polymath 0.3.1

Make math in Rust more powerful! (New math datatypes, traits, functions, etc...)
Documentation
#![allow(dead_code)]

mod matrix_impl;

use std::ops::{
    Add,
    Sub,
    Mul,
    Div,
    Rem,
};
use std::fmt;
use matrix_impl::*;
use super::super::{PolymathError, PolymathErrorKind};

#[derive(PartialEq, Eq, Clone)]
/// Matrix
///
/// # Examples:
/// ```rust
/// use polymath::prelude::*;
///
/// fn main() {
///     let a: Matrix<f64> = Matrix::new((2, 4), 0.0); // Matrix { 2 rows, 4 columns, elements set to 0.0 }
///     let b: f64 = 5.0;
///     let c: Matrix<f64> = a.clone() + b; // Adds 5 to every element in the Matrix.
///
///     assert!(c - b == a);
/// }
/// ```
pub struct Matrix<T: Clone> {
    pub rows: usize,
    pub columns: usize,
    data: Vec<T>,
}

impl<T: Clone> Matrix<T> {
    /// Create a new matrix
    ///
    /// # Examples:
    /// ```rust
    /// use polymath::prelude::*;
    ///
    /// fn main() {
    ///     // New Matrix: { 2 rows, 4 columns, elements set to 0.0 }
    ///     let matrix: Matrix<f64> = Matrix::new((2, 4), 0.0);
    /// }
    /// ```
    pub fn new(shape: (usize, usize), element_default: T) -> Self {
        let mut data: Vec<T> = Vec::with_capacity(shape.0 * shape.1);
        data.resize(shape.0 * shape.1, element_default);

        return Self::from_vec(shape, data).unwrap();
    }

    /// Create a new matrix with pre-existing data
    ///
    /// # Examples:
    /// ```rust
    /// use polymath::prelude::*;
    ///
    /// fn main() {
    ///     let rows: usize = 2;
    ///     let columns: usize = 2;
    ///
    ///     // Making a new vector the size of the matrix, and setting each element to 5.
    ///     let mut data: Vec<u8> = Vec::with_capacity(rows * columns);
    ///     data.resize(rows * columns, 5);
    ///
    ///     // New Matrix: { rows, columns, using data vector }
    ///     let matrix: Matrix<u8> = Matrix::from_vec((rows, columns), data).unwrap();
    /// }
    /// ```
    pub fn from_vec(shape: (usize, usize), data: Vec<T>) -> Option<Self> {
        if data.len() != (shape.0 * shape.1) {
            return None;
        }

        return Some(Self {
            rows: shape.0,
            columns: shape.1,
            data,
        });
    }

    pub fn from_2d_vec(data: Vec<Vec<T>>) -> Option<Self> {
        if data.len() == 0 {
            return None;
        }

        if data[0].len() == 0 {
            return None;
        }

        for i in data.iter() {
            if i.len() != data[0].len() {
                return None;
            }
        }

        let rows = data.len();
        let columns = data[0].len();

        let mut line_data: Vec<T> = Vec::new();

        for i in data.into_iter() {
            for j in i.into_iter() {
                line_data.push(j);
            }
        }

        return Self::from_vec((rows, columns), line_data);
    }

    /// Get the length of the matrix's underlying vector (recommended to use matrix.len() instead)
    pub fn vec_len(&self) -> usize {
        return self.data.len();
    }

    /// Get the length of the matrix in elements (rows * columns)
    pub fn len(&self) -> usize {
        return self.rows * self.columns;
    }

    /// Get the length of the matrix ((rows, columns))
    pub fn len_rc(&self) -> (usize, usize) {
        return (self.rows, self.columns);
    }

    /// Get a value in the matrix's underlying vector (linear)
    pub fn get_linear(&self, index: usize) -> Option<T> {
        if self.data.len() <= index {
            return None;
        }

        return Some(self.data[index].clone());
    }

    /// Get a value in the matrix by 2d coordinates (x0 y0 is top left corner)
    pub fn get(&self, pos: (usize, usize)) -> Option<T> {
        return self.get_linear(self.linearize(pos));
    }

    /// Set a value in the matrix's underlying vector (linear)
    pub fn set_linear(&mut self, index: usize, value: T) -> Result<(), PolymathError> {
        if self.data.len() <= index {
            return Err(PolymathError::new(PolymathErrorKind::OutOfBounds, "Index out of bounds!"));
        }

        self.data[index] = value;

        return Ok(());
    }

    /// Set a value in the matrix by 2d coordinates (x0 y0 is top left corner)
    pub fn set(&mut self, pos: (usize, usize), value: T) -> Result<(), PolymathError> {
        return self.set_linear(self.linearize(pos), value);
    }

    /// (Row, Column) -> Index
    pub fn linearize(&self, pos: (usize, usize)) -> usize {
        return pos.0 * self.columns + pos.1;
    }

    /// Index -> (Row, Column)
    pub fn delinearize(&self, index: usize) -> (usize, usize) {
        let row = index / self.columns;
        let column = index % self.columns;

        return (row, column);
    }
}

impl_matrix_type!(usize);
impl_matrix_type!(u8);
impl_matrix_type!(u16);
impl_matrix_type!(u32);
impl_matrix_type!(u64);
impl_matrix_type!(isize);
impl_matrix_type!(i8);
impl_matrix_type!(i16);
impl_matrix_type!(i32);
impl_matrix_type!(i64);
impl_matrix_type!(f32);
impl_matrix_type!(f64);