puffpastry 0.1.0

basic rust neural network framework
Documentation
use std::fmt::Debug;
use std::ops::{Add, Div, Mul, Sub};

pub trait ValidNumber<T>:
    Copy
    + Add<T, Output = T>
    + Mul<T, Output = T>
    + Sub<T, Output = T>
    + Div<T, Output = T>
    + From<f64>
    + Into<f64>
    + Debug
    + PartialOrd
{
}

impl<T> ValidNumber<T> for T where
    T: Copy
        + Add<T, Output = T>
        + Mul<T, Output = T>
        + Sub<T, Output = T>
        + Div<T, Output = T>
        + From<f64>
        + Into<f64>
        + Debug
        + PartialOrd
{
}

pub trait AddVec<T> {
    fn add_vec(&self, other: &Vec<T>) -> Vec<T>;
}

impl<T: ValidNumber<T>> AddVec<T> for Vec<T> {
    fn add_vec(&self, other: &Vec<T>) -> Vec<T> {
        self.iter()
            .zip(other.iter())
            .map(|(x, y)| *x + *y)
            .collect()
    }
}

pub trait ElementwiseMatrixMultiply<T> {
    fn elementwise_multiply(&self, other: &Vec<Vec<T>>) -> Vec<Vec<T>>;
}

impl<T: ValidNumber<T>> ElementwiseMatrixMultiply<T> for Vec<Vec<T>> {
    fn elementwise_multiply(&self, other: &Vec<Vec<T>>) -> Vec<Vec<T>> {
        let mut out = vec![vec![T::from(0.0); self[0].len()]; self.len()];

        for row in 0..out.len() {
            for col in 0..out[row].len() {
                out[row][col] = self[row][col] * other[row][col];
            }
        }

        out
    }
}

pub trait DotProduct<T> {
    fn dot_product(&self, right: &Vec<T>) -> T;
}

impl<T: ValidNumber<T>> DotProduct<T> for Vec<T> {
    fn dot_product(&self, right: &Vec<T>) -> T {
        self.iter()
            .zip(right.iter())
            .fold(T::from(0.0), |acc, (x, y)| acc + (*x) * (*y))
    }
}

pub trait Transpose<T> {
    fn transposed(&self) -> Vec<Vec<T>>;
}

impl<T: ValidNumber<T>> Transpose<T> for Vec<Vec<T>> {
    fn transposed(&self) -> Vec<Vec<T>> {
        let mut out = vec![vec![self[0][0]; self.len()]; self[0].len()];

        for row in 0..self.len() {
            for col in 0..self[row].len() {
                out[col][row] = self[row][col];
            }
        }

        out
    }
}

pub trait MatrixMultiply<T> {
    fn matrix_multiply(&self, other: &Vec<Vec<T>>) -> Vec<Vec<T>>;
}

impl<T: ValidNumber<T>> MatrixMultiply<T> for Vec<Vec<T>> {
    fn matrix_multiply(&self, other: &Vec<Vec<T>>) -> Vec<Vec<T>> {
        let mut out: Vec<Vec<T>> = vec![vec![other[0][0]; other[0].len()]; self.len()];
        let other = other.transposed();

        for row in 0..out.len() {
            for col in 0..out[0].len() {
                out[row][col] = self[row].dot_product(&other[col]);
            }
        }

        out
    }
}

mod test {
    use super::*;

    #[test]
    fn mat_mul_test_1() {
        let mat1 = vec![vec![1.0, 0.0], vec![0.0, 1.0]];
        let mat2 = vec![vec![1.0], vec![2.0]];
        let res = mat1.matrix_multiply(&mat2);

        assert_eq!(res, mat2);
    }

    #[test]
    fn mat_mul_test_2() {
        let mat1 = vec![
            vec![1.0, 2.0, 3.0],
            vec![4.0, 5.0, 6.0],
            vec![7.0, 8.0, 9.0],
        ];
        let mat2 = vec![vec![1.0], vec![2.0], vec![3.0]];
        let res = mat1.matrix_multiply(&mat2);
        let truth = vec![vec![14.0], vec![32.0], vec![50.0]];
    }

    #[test]
    fn row_transpose_test() {
        let input = vec![1.0, 2.0, 3.0];
        let res = vec![input.clone()].transposed().transposed();

        assert_eq!(vec![input], res)
    }

    #[test]
    fn elem_mult_test() {
        let mat1 = vec![vec![1.0, 2.0, 3.0]];
        let mat2 = vec![vec![3.0, 2.0, 1.0]];

        let res = mat1.transposed().elementwise_multiply(&mat2.transposed());

        assert_eq!(res, vec![vec![3.0, 4.0, 3.0]].transposed());
    }
}