crying 0.0.1

linear algebra utility library with generic matrix and vector types
Documentation
use num_traits::identities;
use rand::{self, RngCore};
use std::{convert, ops};

use crate::scalar::{RandFloat, Scalar, ScalarFloat};

// Gector
#[derive(Clone, Copy, Debug)]
pub struct Gec<S: Scalar, const DIM: usize>(pub [S; DIM]);

impl<S: Scalar, const DIM: usize> Gec<S,DIM> {
    pub fn scale(mut self, by: S) -> Self {
        for i in 0..DIM {
            self[i] *= by;
        }
        self
    }
}

// Indexing
impl<S: Scalar, const DIM: usize> ops::Index<usize> for Gec<S, DIM> {
    type Output = S;
    fn index<'a>(&'a self, i: usize) -> &'a S {
        &self.0[i]
    }
}
impl<T: Scalar, const DIM: usize> ops::IndexMut<usize> for Gec<T, DIM> {
    fn index_mut<'a>(&'a mut self, i: usize) -> &'a mut T {
        &mut self.0[i]
    }
}

// arithmetic+assignment
impl<T: Scalar + ops::AddAssign, const DIM: usize> ops::AddAssign for Gec<T, DIM> {
    fn add_assign(&mut self, rhs: Self) {
        for n in 0..DIM {
            self.0[n] += rhs.0[n];
        }
    }
}
impl<S: Scalar + ops::SubAssign, const DIM: usize> ops::SubAssign for Gec<S, DIM> {
    fn sub_assign(&mut self, rhs: Self) {
        for n in 0..DIM {
            self.0[n] -= rhs.0[n];
        }
    }
}
impl<T: Scalar + ops::MulAssign, const DIM: usize> ops::MulAssign for Gec<T, DIM> {
    fn mul_assign(&mut self, rhs: Self) {
        for n in 0..DIM {
            self.0[n] *= rhs.0[n];
        }
    }
}
impl<S: Scalar + ops::DivAssign, const DIM: usize> ops::DivAssign for Gec<S, DIM> {
    fn div_assign(&mut self, rhs: Self) {
        for n in 0..DIM {
            self.0[n] *= rhs.0[n];
        }
    }
}

// arithmetic
impl<S: Scalar, const DIM: usize> ops::Add<&Gec<S, DIM>> for Gec<S, DIM> {
    type Output = Gec<S,DIM>;
    fn add(mut self, rhs: &Gec<S, DIM>) -> Self::Output {
        self += rhs;
        self
    }
}
impl<S: Scalar, const DIM: usize> ops::Add<Gec<S, DIM>> for Gec<S, DIM> {
    type Output = Gec<S,DIM>;
    fn add(self, rhs: Gec<S, DIM>) -> Self::Output {
        self + &rhs
    }
}
impl<S: Scalar, const DIM: usize> ops::Add<Gec<S, DIM>> for &Gec<S, DIM> {
    type Output = Gec<S,DIM>;
    fn add(self, rhs: Gec<S, DIM>) -> Self::Output {
        rhs + self
    }
}

impl<S: Scalar, const DIM: usize> ops::Sub<&Gec<S, DIM>> for Gec<S, DIM> {
    type Output = Gec<S,DIM>;
    fn sub(mut self, rhs: &Gec<S, DIM>) -> Self::Output {
        self -= rhs;
        self
    }
}
impl<S: Scalar, const DIM: usize> ops::Sub<Gec<S, DIM>> for Gec<S, DIM> {
    type Output = Gec<S,DIM>;
    fn sub(self, rhs: Gec<S, DIM>) -> Self::Output {
        self - &rhs
    }
}
impl<S: Scalar, const DIM: usize> ops::Sub<Gec<S, DIM>> for &Gec<S, DIM> {
    type Output = Gec<S,DIM>;
    fn sub(self, mut rhs: Gec<S, DIM>) -> Self::Output {
        for i in 0..DIM {
            rhs[i] = self[i] - rhs[i];
        }
        rhs
    }
}

impl<S: Scalar, const DIM: usize> ops::Mul<&Gec<S, DIM>> for Gec<S, DIM> {
    type Output = Gec<S,DIM>;
    fn mul(mut self, rhs: &Gec<S, DIM>) -> Self::Output {
        self *= rhs;
        self
    }
}
impl<S: Scalar, const DIM: usize> ops::Mul<Gec<S, DIM>> for Gec<S, DIM> {
    type Output = Gec<S,DIM>;
    fn mul(self, rhs: Gec<S, DIM>) -> Self::Output {
        self * &rhs
    }
}
impl<S: Scalar, const DIM: usize> ops::Mul<Gec<S, DIM>> for &Gec<S, DIM> {
    type Output = Gec<S, DIM>;
    fn mul(self, rhs: Gec<S, DIM>) -> Self::Output {
        rhs * self
    }
}

impl<S: Scalar, const DIM: usize> ops::Div<&Gec<S, DIM>> for Gec<S, DIM> {
    type Output = Gec<S,DIM>;
    fn div(mut self, rhs: &Gec<S, DIM>) -> Self::Output {
        self /= rhs;
        self
    }
}
impl<S: Scalar, const DIM: usize> ops::Neg for Gec<S, DIM> {
    type Output = Self;
    fn neg(mut self) -> Self::Output {
        for i in 0..DIM {
            self[i] = <S as Scalar>::zero() - self[i];
        }
        self
    }
}

impl<S: Scalar + ops::AddAssign, const DIM: usize> ops::AddAssign<&Gec<S, DIM>> for Gec<S, DIM> {
    fn add_assign(&mut self, rhs: &Gec<S, DIM>) {
        for n in 0..DIM {
            self.0[n] += rhs.0[n];
        }
    }
}
impl<S: Scalar + ops::SubAssign, const DIM: usize> ops::SubAssign<&Gec<S, DIM>> for Gec<S, DIM> {
    fn sub_assign(&mut self, rhs: &Gec<S, DIM>) {
        for n in 0..DIM {
            self.0[n] -= rhs.0[n];
        }
    }
}
impl<S: Scalar + ops::MulAssign, const DIM: usize> ops::MulAssign<&Gec<S, DIM>> for Gec<S, DIM> {
    fn mul_assign(&mut self, rhs: &Gec<S, DIM>) {
        for n in 0..DIM {
            self.0[n] *= rhs.0[n];
        }
    }
}
impl<S: Scalar + ops::DivAssign, const DIM: usize> ops::DivAssign<&Gec<S, DIM>> for Gec<S, DIM> {
    fn div_assign(&mut self, rhs: &Gec<S, DIM>) {
        for n in 0..DIM {
            self.0[n] /= rhs.0[n];
        }
    }
}


// scalar by vector multiplication/division
impl<const DIM: usize> ops::Mul<Gec<f32, DIM>> for f32 {
    type Output = Gec<f32, DIM>;
    fn mul(self, rhs: Gec<f32, DIM>) -> Self::Output {
        rhs.scale(self)
    }
}
impl<const DIM: usize> ops::Mul<Gec<f64, DIM>> for f64 {
    type Output = Gec<f64, DIM>;
    fn mul(self, rhs: Gec<f64, DIM>) -> Self::Output {
        rhs.scale(self)
    }
}
// TODO: same thing for int types... (use a macro?)

// converting between Gecs and arrays
impl<S: Scalar, const DIM: usize> convert::From<[S; DIM]> for Gec<S, DIM> {
    fn from(value: [S; DIM]) -> Self {
        Self(value)
    }
}

// things that work for all types of scalars
impl<S: Scalar, const DIM: usize> Gec<S, DIM> {
    pub fn zero() -> Self {
        Gec([identities::zero(); DIM])
    }
    pub fn ones() -> Self {
        Gec([identities::one(); DIM])
    }
    pub fn dot(self, other: Self) -> S {
        self.0
            .iter()
            .zip(other.0.iter())
            .fold(identities::zero(), |acc, (&l, &r)| acc + l * r)
    }
    pub fn length_squared(self) -> S {
        self.dot(self)
    }
}

// floating-point operations
impl<S: ScalarFloat, const DIM: usize> Gec<S, DIM> {
    pub fn length(self) -> S {
        self.length_squared().sqrt()
    }
    pub fn to_unit(self) -> Self {
        self.scale(<S as Scalar>::one() / self.length())
    }
}

impl<S: RandFloat, const DIM: usize> Gec<S, DIM> {
    // sample randomly for each coordinate in [0, 1)
    pub fn random<R: RngCore + ?Sized>(r: &mut R) -> Self {
        let mut arr: [S; DIM] = [identities::zero(); DIM];
        for x in &mut arr[..] {
            *x = S::sample01(r);
        }
        Self::from(arr)
    }
    pub fn random_openclosed<R: RngCore + ?Sized>(r: &mut R) -> Self {
        let mut arr: [S; DIM] = [identities::zero(); DIM];
        for x in &mut arr[..] {
            *x = S::sample01_openclosed(r);
        }
        Self::from(arr)
    }

    pub fn random_unit<R: RngCore + ?Sized>(rng: &mut R) -> Self {
        let v = Self::random(rng);
        v.scale(<S as Scalar>::one() / v.length())
    }

    /// unit vector with angle < pi relative to the provided normal direction
    pub fn random_on_hemisphere<R: RngCore + ?Sized>(rng: &mut R, normal: Self) -> Self {
        let attempt = Self::random_unit(rng);
        if attempt.dot(normal) > <S as Scalar>::one() {
            attempt
        } else {
            -attempt
        }
    }

    // Gets a vector of length < 1 with last coordinate 0, i.e. a random
    // element of a (DIM-1) dimensional unit hyperdisk
    pub fn random_in_unit_disk<R: RngCore + ?Sized>(rng: &mut R) -> Self {
        loop {
            // TODO: don't generate the unnecessary extra random number
            let mut v = Self::random(rng);
            v[DIM - 1] = <S as Scalar>::zero();
            if v.length_squared() < <S as Scalar>::one() {
                break v;
            }
        }
    }
}

// 3D vectors
impl<S: Scalar> Gec<S, 3> {
    pub fn cross(self, other: Self) -> Self {
        Self::from([
            self[1] * other[2] - self[2] * other[1],
            self[2] * other[0] - self[0] * other[2],
            self[0] * other[1] - self[1] * other[0],
        ])
    }

    pub fn to_homogeneous(&self) -> Gec<S, 4> {
        Gec::from([self[0], self[1], self[2], identities::one()])
    }
}