linear_isomorphic 0.3.3

A set of traits to astract over linear-like types.
Documentation
//! Set of traits to abstract over linear algebra types.
//!
//! Provides an abstraction over vector-like types. This makes it easier to
//! implement generic math algorithms.
//!
//! # Example
//! ```
//! use linear_isomorphic::*;
//!
//! pub fn point_segment_distance<Vec>(start: &Vec, end: &Vec, point: &Vec) -> f32
//! where
//!     Vec: VectorSpace<Scalar = f32>,
//! {
//!     let dir = end.clone() - start.clone();
//!     let t = (point.clone() - start.clone()).dot(&dir) / dir.norm_squared();
//!
//!     let t = t.clamp(0.0, 1.0);
//!
//!     let closest = start.clone() + dir * t;
//!
//!     (closest - point.clone()).norm()
//! }
//! ```

use std::fmt::{Debug, Display};
use std::iter::IntoIterator;
use std::ops::{
    Add,
    AddAssign,
    Div,
    DivAssign,
    Index,
    IndexMut,
    Mul,
    MulAssign,
    Neg,
    Sub,
    SubAssign,
};

use num::Float;

pub mod prelude
{
    pub use crate::ArithmeticType;
    pub use crate::InnerSpace;
    pub use crate::RealField;
    pub use crate::VectorSpace;
}

/// Trait representing a type isomorphic to a lin alg vector in the most basic
/// sense. That is, it supports addition and scalar multiplication. Useful to
/// write functions that work on arithmetic types.
pub trait ArithmeticType<S>:
    Mul<S, Output = Self>
    + AddAssign<Self>
    + SubAssign<Self>
    + Add<Output = Self>
    + Sub<Output = Self>
    + Neg<Output = Self>
    + Clone
    + Sized
where
    S: RealField + Mul<Self, Output = Self>,
{
}

impl<T, S> ArithmeticType<S> for T
where
    T: Mul<S, Output = Self>
        + AddAssign<Self>
        + SubAssign<Self>
        + Add<Output = Self>
        + Sub<Output = Self>
        + Neg<Output = Self>
        + Clone
        + Sized,
    S: RealField + Mul<Self, Output = Self>,
{
}

/// Trait representing a type which can be multiplied by, i.e. a scalar.
pub trait RealField:
    Display
    + Debug
    + Default
    + Add
    + Sub
    + Mul
    + Div
    + AddAssign
    + DivAssign
    + SubAssign
    + MulAssign
    + Float
    + 'static
{
    fn clamp(&self, min: Self, high: Self) -> Self
    {
        if *self < min
        {
            min
        }
        else if *self > high
        {
            high
        }
        else
        {
            self.clone()
        }
    }
}

impl<T> RealField for T where
    T: Display
        + Debug
        + Default
        + Add
        + Sub
        + Mul
        + Div
        + AddAssign
        + DivAssign
        + SubAssign
        + MulAssign
        + Float
        + 'static
{
}


pub trait VMul<S> {}
impl<V, S> VMul<S> for V where S: Mul<V, Output = V> + RealField  {}

/// Extension of the `ArithmeticType` trait. It also demands that the type is
/// indexable and can be default initialised (default initialisation is assumed
/// to be equivalent to the 0 vector).
/// Additionally, provides methods common to vectors.
pub trait VectorSpace:
    ArithmeticType<Self::Scalar>
    + Index<usize, Output = Self::Scalar>
    + IndexMut<usize, Output = Self::Scalar>
    + Default
    + VMul<Self::Scalar>
{
    type Scalar: RealField + Mul<Self, Output = Self>;

    /// Compute the cross-product of two vectors. Call only if both vectors are
    /// three-dimensional.
    fn cross(&self, other: &Self) -> Self;

    /// Set a portion of this vector to some values.
    fn set_subset(&mut self, values: &[Self::Scalar])
    {
        for (i, v) in values.iter().enumerate()
        {
            self[i] = v.clone()
        }
    }
}

/// Blank implementation for a type that is isomorphic to a vector and can be
/// represented in contiguous memory.
impl<V, S> VectorSpace for V
where
    V: ArithmeticType<S>
        + Index<usize, Output = S>
        + IndexMut<usize, Output = S>
        + Default,
    S: RealField + Mul<Self, Output = Self>,
{
    type Scalar = S;

    /// Assumes a 3-dimensional vector.
    fn cross(&self, other: &Self) -> Self
    {
        let mut result = self.clone() * S::from(0.0).unwrap();
        result[0] = self[1] * other[2] - self[2] * other[1];
        result[1] = self[2] * other[0] - self[0] * other[2];
        result[2] = self[0] * other[1] - self[1] * other[0];

        result
    }
}

pub trait RefIterable<I> {
    type Iter<'a>: Iterator<Item = &'a I>
    where
        Self: 'a,
        I: 'a;
    fn iter<'a>(&'a self) -> Self::Iter<'a>
    where
        I: 'a;
}

impl<T, I> RefIterable<I> for T
where
        for<'a> &'a T: IntoIterator<Item = &'a I>,
{
    type Iter<'a>
    = <&'a Self as IntoIterator>::IntoIter
    where
        Self: 'a,
        I: 'a;
    fn iter<'a>(&'a self) -> Self::Iter<'a>
    where
        I: 'a,
    {
        IntoIterator::into_iter(self)
    }
}

pub trait InnerSpace<S>: VectorSpace<Scalar = S> + RefIterable<S>
where
    S: RealField + Display + Debug,
{
    /// Get a unit vector in the same direction as this one. Can produce
    /// NAN's.
    fn normalized(&self) -> Self;
    /// Get the current norm/length of this vector.
    fn norm(&self) -> Self::Scalar;
    /// Get the squared norm of the vector, this is faster than getting the norm
    /// in most cases.
    fn norm_squared(&self) -> Self::Scalar;
    /// The inner product of this space.
    fn dot(&self, other: &Self) -> S;
    /// Construct a new vector by applying f to the entries of this vector.
    fn map(&self, f: impl FnMut(S) -> S) -> Self;
    /// Construct a new vector from a scalar (this is inefficient due to type
    /// constraints at the moment).
    fn from_scalar(s: S) -> Self;
}

impl<V, S> InnerSpace<S> for V
where
    V: VectorSpace<Scalar = S> + RefIterable<S>,
    S: RealField,
{
    fn normalized(&self) -> Self { self.clone() * (S::from(1.0).unwrap() / self.norm()) }

    fn norm(&self) -> S { self.norm_squared().sqrt() }

    fn norm_squared(&self) -> S { self.dot(&self) }

    fn dot(&self, other: &Self) -> S
    {
        let mut result = S::from(0.0).unwrap();
        for (v, w) in self.iter().zip(other.iter())
        {
            result += v.clone() * w.clone();
        }

        result
    }

    fn map(&self, mut f: impl FnMut(S) -> S) -> Self
    {
        let mut result = self.clone();
        for (i, v) in self.iter().enumerate()
        {
            result[i] = f(v.clone());
        }

        result
    }

    fn from_scalar(s: S) -> Self
    {
        let mut result = V::default();
        for (i, _) in V::default().iter().enumerate()
        {
            result[i] = s;
        }

        result
    }
}