diff --git a/Cargo.toml b/Cargo.toml index 2efb020..fe8c8ce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,3 +6,4 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +generic_parameterize = "0.1.0" diff --git a/src/index.rs b/src/index.rs index c63c05a..079d60a 100644 --- a/src/index.rs +++ b/src/index.rs @@ -1,4 +1,6 @@ -pub trait Index2D: Copy { +use std::fmt::Debug; + +pub trait Index2D: Copy + Debug { fn to_1d(self, height: usize, width: usize) -> Option { let (r, c) = self.to_2d(height, width)?; Some(r * width + c) diff --git a/src/lib.rs b/src/lib.rs index f723672..83c6a21 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,7 @@ +extern crate core; + pub mod index; -mod matrix; mod macros; +mod matrix; + +pub use matrix::{Matrix, Scalar, Vector}; diff --git a/src/macros/ops.rs b/src/macros/ops.rs index 38c4410..434ff88 100644 --- a/src/macros/ops.rs +++ b/src/macros/ops.rs @@ -2,137 +2,141 @@ #[doc(hidden)] #[macro_export] macro_rules! impl_matrix_op { - (neg, $f:expr) => { - $crate::_impl_op_m_internal_ex!(Neg, neg, $f); + (neg) => { + $crate::_impl_op_m_internal_ex!(Neg, neg); }; - (!, $f:expr) => { - $crate::_impl_op_m_internal_ex!(Not, not, $f); + (!) => { + $crate::_impl_op_m_internal_ex!(Not, not); }; - (+, $f:expr) => { - $crate::_impl_op_mm_internal_ex!(Add, add, $f); - $crate::_impl_opassign_mm_internal_ex!(Add, AddAssign, add_assign, $f); + (+) => { + $crate::_impl_op_mm_internal_ex!(Add, add); + $crate::_impl_opassign_mm_internal_ex!(AddAssign, add_assign); }; - (-, $f:expr) => { - $crate::_impl_op_mm_internal_ex!(Sub, sub, $f); - $crate::_impl_opassign_mm_internal_ex!(Sub, SubAssign, sub_assign, $f); + (-) => { + $crate::_impl_op_mm_internal_ex!(Sub, sub); + $crate::_impl_opassign_mm_internal_ex!(SubAssign, sub_assign); }; - (*, $f:expr) => { - $crate::_impl_op_mm_internal_ex!(Mul, mul, $f); - $crate::_impl_op_ms_internal_ex!(Mul, mul, $f); - $crate::_impl_opassign_mm_internal_ex!(Mul, MulAssign, mul_assign, $f); - $crate::_impl_opassign_ms_internal_ex!(Mul, MulAssign, mul_assign, $f); + (*) => { + $crate::_impl_op_mm_internal_ex!(Mul, mul); + $crate::_impl_op_ms_internal_ex!(Mul, mul); + $crate::_impl_opassign_mm_internal_ex!(MulAssign, mul_assign); + $crate::_impl_opassign_ms_internal_ex!(MulAssign, mul_assign); }; - (/, $f:expr) => { - $crate::_impl_op_mm_internal_ex!(Div, div, $f); - $crate::_impl_op_ms_internal_ex!(Div, div, $f); - $crate::_impl_opassign_mm_internal_ex!(Div, DivAssign, div_assign, $f); - $crate::_impl_opassign_ms_internal_ex!(Div, DivAssign, div_assign, $f); + (/) => { + $crate::_impl_op_mm_internal_ex!(Div, div); + $crate::_impl_op_ms_internal_ex!(Div, div); + $crate::_impl_opassign_mm_internal_ex!(DivAssign, div_assign); + $crate::_impl_opassign_ms_internal_ex!(DivAssign, div_assign); }; - (%, $f:expr) => { - $crate::_impl_op_mm_internal_ex!(Rem, rem, $f); - $crate::_impl_op_ms_internal_ex!(Rem, rem, $f); - $crate::_impl_opassign_mm_internal_ex!(Rem, RemAssign, rem_assign, $f); - $crate::_impl_opassign_ms_internal_ex!(Rem, RemAssign, rem_assign, $f); + (%) => { + $crate::_impl_op_mm_internal_ex!(Rem, rem); + $crate::_impl_op_ms_internal_ex!(Rem, rem); + $crate::_impl_opassign_mm_internal_ex!(RemAssign, rem_assign); + $crate::_impl_opassign_ms_internal_ex!(RemAssign, rem_assign); }; - (&, $f:expr) => { - $crate::_impl_op_mm_internal_ex!(BitAnd, bitand, $f); - $crate::_impl_opassign_mm_internal_ex!(BitAnd, BitAndAssign, bitand_assign, $f); + (&) => { + $crate::_impl_op_mm_internal_ex!(BitAnd, bitand); + $crate::_impl_opassign_mm_internal_ex!(BitAndAssign, bitand_assign); }; - (|, $f:expr) => { - $crate::_impl_op_mm_internal_ex!(BitOr, bitor, $f); - $crate::_impl_opassign_mm_internal_ex!(BitOr, BitOrAssign, bitor_assign, $f); + (|) => { + $crate::_impl_op_mm_internal_ex!(BitOr, bitor); + $crate::_impl_opassign_mm_internal_ex!(BitOrAssign, bitor_assign); }; - (^, $f:expr) => { - $crate::_impl_op_mm_internal_ex!(BitXor, bitxor, $f); - $crate::_impl_opassign_mm_internal_ex!(BitXor, BitXorAssign, bitxor_assign, $f); + (^) => { + $crate::_impl_op_mm_internal_ex!(BitXor, bitxor); + $crate::_impl_opassign_mm_internal_ex!(BitXorAssign, bitxor_assign); }; - (<<, $f:expr) => { - $crate::_impl_op_ms_internal_ex!(Shl, shl, $f); - $crate::_impl_opassign_mm_internal_ex!(Shl, ShlAssign, shl_assign, $f); + (<<) => { + $crate::_impl_op_ms_internal_ex!(Shl, shl); + $crate::_impl_opassign_ms_internal_ex!(ShlAssign, shl_assign); }; - (>>, $f:expr) => { - $crate::_impl_op_ms_internal_ex!(Shr, shr, $f); - $crate::_impl_opassign_mm_internal_ex!(Shr, ShrAssign, shr_assign, $f); - }; -} - -#[doc(hidden)] -#[macro_export] -macro_rules! impl_op_ms { - (*, $f:expr) => { - _impl_op_ms_internal!(Mul, mul, $f); - }; - (/, $f:expr) => { - _impl_op_ms_internal!(Div, div, $f); - }; - (%, $f:expr) => { - _impl_op_ms_internal!(Rem, rem, $f); - }; - (<<, $f:expr) => { - _impl_op_ms_internal!(Shl, shl, $f); - }; - (>>, $f:expr) => { - _impl_op_ms_internal!(Shr, shr, $d); + (>>) => { + $crate::_impl_op_ms_internal_ex!(Shr, shr); + $crate::_impl_opassign_ms_internal_ex!(ShrAssign, shr_assign); }; } #[macro_export] macro_rules! _impl_op_m_internal_ex { - ($ops_trait:ident, $ops_fn:ident, $f:expr) => { - $crate::_impl_op_m_internal!($ops_trait, $ops_fn, Matrix, Matrix, $f); - $crate::_impl_op_m_internal!($ops_trait, $ops_fn, &Matrix, Matrix, $f); + ($ops_trait:ident, $ops_fn:ident) => { + $crate::_impl_op_m_internal!($ops_trait, $ops_fn, Matrix, Matrix); + $crate::_impl_op_m_internal!($ops_trait, $ops_fn, &Matrix, Matrix); } } #[macro_export] macro_rules! _impl_op_mm_internal_ex { - ($ops_trait:ident, $ops_fn:ident, $f:expr) => { - $crate::_impl_op_mm_internal!($ops_trait, $ops_fn, Matrix, Matrix, Matrix, $f); - $crate::_impl_op_mm_internal!($ops_trait, $ops_fn, &Matrix, Matrix, Matrix, $f); - $crate::_impl_op_mm_internal!($ops_trait, $ops_fn, Matrix, &Matrix, Matrix, $f); - $crate::_impl_op_mm_internal!($ops_trait, $ops_fn, &Matrix, &Matrix, Matrix, $f); + ($ops_trait:ident, $ops_fn:ident) => { + $crate::_impl_op_mm_internal!($ops_trait, $ops_fn, Matrix, Matrix, Matrix); + $crate::_impl_op_mm_internal!($ops_trait, $ops_fn, &Matrix, Matrix, Matrix); + $crate::_impl_op_mm_internal!($ops_trait, $ops_fn, Matrix, &Matrix, Matrix); + $crate::_impl_op_mm_internal!($ops_trait, $ops_fn, &Matrix, &Matrix, Matrix); } } #[macro_export] macro_rules! _impl_opassign_mm_internal_ex { - ($ops_super:ident, $ops_trait:ident, $ops_fn:ident, $f:expr) => { - $crate::_impl_opassign_mm_internal!($ops_super, $ops_trait, $ops_fn, Matrix, Matrix, Matrix, $f); - $crate::_impl_opassign_mm_internal!($ops_super, $ops_trait, $ops_fn, Matrix, &Matrix, Matrix, $f); + ($ops_trait:ident, $ops_fn:ident) => { + $crate::_impl_opassign_mm_internal!($ops_trait, $ops_fn, Matrix, Matrix, Matrix); + $crate::_impl_opassign_mm_internal!($ops_trait, $ops_fn, Matrix, &Matrix, Matrix); } } #[macro_export] macro_rules! _impl_op_ms_internal_ex { - ($ops_trait:ident, $ops_fn:ident, $f:expr) => { - $crate::_impl_op_ms_internal!($ops_trait, $ops_fn, Matrix, R, Matrix, $f); - $crate::_impl_op_ms_internal!($ops_trait, $ops_fn, &Matrix, R, Matrix, $f); + ($ops_trait:ident, $ops_fn:ident) => { + $crate::_impl_op_ms_internal!($ops_trait, $ops_fn, Matrix, R, Matrix); + $crate::_impl_op_ms_internal!($ops_trait, $ops_fn, &Matrix, R, Matrix); } } #[macro_export] macro_rules! _impl_opassign_ms_internal_ex { - ($ops_super:ident, $ops_trait:ident, $ops_fn:ident, $f:expr) => { - $crate::_impl_opassign_ms_internal!($ops_super, $ops_trait, $ops_fn, Matrix, R, Matrix, $f); + ($ops_trait:ident, $ops_fn:ident) => { + $crate::_impl_opassign_ms_internal!($ops_trait, $ops_fn, Matrix, R, Matrix); } } +#[macro_export] +macro_rules! _impl_op_m_internal { + ($ops_trait:ident, $ops_fn:ident, $lhs:ty, $out:ty) => { + impl ::std::ops::$ops_trait for $lhs + where + L: ::std::ops::$ops_trait + Scalar, + { + type Output = $out; + + #[inline(always)] + fn $ops_fn(self) -> Self::Output { + let mut result = self.clone(); + for m in 0..M { + for n in 0..N { + result.data[m][n] = self.data[m][n].$ops_fn(); + } + } + result + } + } + }; +} + #[macro_export] macro_rules! _impl_op_mm_internal { - ($ops_trait:ident, $ops_fn:ident, $lhs:ty, $rhs:ty, $out:ty, $f:expr) => { + ($ops_trait:ident, $ops_fn:ident, $lhs:ty, $rhs:ty, $out:ty) => { impl ::std::ops::$ops_trait<$rhs> for $lhs where - L: ::std::ops::$ops_trait, - L: Scalar, + L: ::std::ops::$ops_trait + Scalar, R: Scalar, { type Output = $out; - fn $ops_fn(self, rhs_i: $rhs) -> Self::Output { + #[inline(always)] + fn $ops_fn(self, other: $rhs) -> Self::Output { let mut result = self.clone(); - let op = $f; - for (l, r) in zip(result.elements_mut(), rhs_i.elements()) { - *l = op(*l, *r); + for m in 0..M { + for n in 0..N { + result.data[m][n] = self.data[m][n].$ops_fn(other.data[m][n]); + } } result } @@ -142,62 +146,41 @@ macro_rules! _impl_op_mm_internal { #[macro_export] macro_rules! _impl_opassign_mm_internal { - ($ops_super:ident, $ops_trait:ident, $ops_fn:ident, $lhs:ty, $rhs:ty, $out:ty, $f:expr) => { + ($ops_trait:ident, $ops_fn:ident, $lhs:ty, $rhs:ty, $out:ty) => { impl ::std::ops::$ops_trait<$rhs> for $lhs where - L: ::std::ops::$ops_trait, - L: ::std::ops::$ops_super, - L: Scalar, + L: ::std::ops::$ops_trait + Scalar, R: Scalar, { - fn $ops_fn(&mut self, rhs_i: $rhs) { - let op = $f; - for (l, r) in zip(self.elements_mut(), rhs_i.elements()) { - *l = op(*l, *r); + #[inline(always)] + fn $ops_fn(&mut self, other: $rhs) { + for m in 0..M { + for n in 0..N { + self.data[m][n].$ops_fn(other.data[m][n]); + } } } } }; } -#[macro_export] -macro_rules! _impl_op_m_internal { - ($ops_trait:ident, $ops_fn:ident, $lhs:ty, $out:ty, $f:expr) => { - impl ::std::ops::$ops_trait for $lhs - where - L: ::std::ops::$ops_trait, - L: Scalar, - { - type Output = $out; - - fn $ops_fn(self) -> Self::Output { - let mut result = self.clone(); - let op = $f; - for l in result.elements_mut() { - *l = op(*l); - } - result - } - } - }; -} - #[macro_export] macro_rules! _impl_op_ms_internal { - ($ops_trait:ident, $ops_fn:ident, $lhs:ty, $rhs:ty, $out:ty, $f:expr) => { + ($ops_trait:ident, $ops_fn:ident, $lhs:ty, $rhs:ty, $out:ty) => { impl ::std::ops::$ops_trait<$rhs> for $lhs where - L: ::std::ops::$ops_trait, - L: Scalar, + L: ::std::ops::$ops_trait + Scalar, R: Scalar, { type Output = $out; - fn $ops_fn(self, r: $rhs) -> Self::Output { + #[inline(always)] + fn $ops_fn(self, other: $rhs) -> Self::Output { let mut result = self.clone(); - let op = $f; - for l in result.elements_mut() { - *l = op(*l, r); + for m in 0..M { + for n in 0..N { + result.data[m][n] = self.data[m][n].$ops_fn(other); + } } result } @@ -207,18 +190,18 @@ macro_rules! _impl_op_ms_internal { #[macro_export] macro_rules! _impl_opassign_ms_internal { - ($ops_super:ident, $ops_trait:ident, $ops_fn:ident, $lhs:ty, $rhs:ty, $out:ty, $f:expr) => { + ($ops_trait:ident, $ops_fn:ident, $lhs:ty, $rhs:ty, $out:ty) => { impl ::std::ops::$ops_trait<$rhs> for $lhs where - L: ::std::ops::$ops_trait, - L: ::std::ops::$ops_super, - L: Scalar, + L: ::std::ops::$ops_trait + Scalar, R: Scalar, { + #[inline(always)] fn $ops_fn(&mut self, r: $rhs) { - let op = $f; - for l in self.elements_mut() { - *l = op(*l, r); + for m in 0..M { + for n in 0..N { + self.data[m][n].$ops_fn(r); + } } } } diff --git a/src/matrix.rs b/src/matrix.rs index 6d20e02..7c78fb3 100644 --- a/src/matrix.rs +++ b/src/matrix.rs @@ -1,92 +1,197 @@ use crate::impl_matrix_op; use crate::index::Index2D; -use std::iter::{zip, Enumerate, Flatten}; -use std::ops::{Add, Deref, DerefMut, Index, IndexMut, Range}; -use std::option::IntoIter; +use std::fmt::Debug; +use std::iter::{zip, Flatten, Product, Sum}; +use std::ops::{AddAssign, Deref, DerefMut, Index, IndexMut, MulAssign}; -pub trait Get2D { - type Scalar: Sized + Copy; - const HEIGHT: usize; - const WIDTH: usize; - - fn get(&self, i: I) -> Option<&Self::Scalar>; -} - -pub trait Get2DMut: Get2D { - fn get_mut(&mut self, i: I) -> Option<&mut Self::Scalar>; -} - -trait Scalar: Copy + 'static {} +/// A Scalar that a [Matrix] can be made up of. +/// +/// This trait has no associated functions and can be implemented on any type that is [Default] and +/// [Copy] and has a static lifetime. +pub trait Scalar: Default + Copy + 'static {} macro_rules! multi_impl { ($name:ident for $($t:ty),*) => ($( impl $name for $t {} )*) } -multi_impl!(Scalar for i8, i16, i32, i64, isize, u8, u16, u32, u64, usize, f32, f64); -impl Scalar for &'static T where T: Scalar {} +multi_impl!(Scalar for i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize, f32, f64); +impl Scalar for &'static T +where + T: Scalar, + &'static T: Default, +{ +} -#[derive(Debug, Copy, Clone)] -struct Matrix +/// A 2D array of values which can be operated upon. +/// +/// Matrices have a fixed size known at compile time, and must be made up of types that implement +/// the [Scalar] trait. +#[derive(Debug, Copy, Clone, PartialEq)] +pub struct Matrix where T: Scalar, { data: [[T; N]; M], } -type Vector = Matrix; +/// An alias for a [Matrix] with a single column +pub type Vector = Matrix; impl Matrix { - fn new(data: [[T; N]; M]) -> Self { - return Matrix:: { data }; + /// Generate a new matrix from a 2D Array + /// + /// # Arguments + /// + /// * `data`: A 2D array of elements to copy into the new matrix + /// + /// returns: Matrix + /// + /// # Examples + /// + /// ``` + /// # use vector_victor::Matrix; + /// let a = Matrix::new([[1,2,3,4];4]); + /// ``` + #[must_use] + pub fn new(data: [[T; N]; M]) -> Self { + Matrix:: { data } } - fn from_rows(iter: &I) -> Self + /// Generate a new matrix from a single scalar + /// + /// # Arguments + /// + /// * `scalar`: Scalar value to copy into the new matrix. + /// + /// returns: Matrix + /// + /// # Examples + /// + /// ``` + /// # use vector_victor::Matrix; + /// let my_matrix = Matrix::::fill(5); + /// // is equivalent to + /// assert_eq!(my_matrix, Matrix::new([[5;4];4])) + /// ``` + #[must_use] + pub fn fill(scalar: T) -> Matrix { + Matrix:: { + data: [[scalar; N]; M], + } + } + + /// Create a matrix from an iterator of vectors + /// + /// # Arguments + /// + /// * `iter`: iterator of vectors to copy into rows + /// + /// returns: Matrix + /// + /// # Examples + /// + /// ``` + /// # use vector_victor::Matrix; + /// let my_matrix = Matrix::new([[1,2,3],[4,5,6]]); + /// let transpose : Matrix<_,3,2>= Matrix::from_rows(my_matrix.cols()); + /// assert_eq!(transpose, Matrix::new([[1,4],[2,5],[3,6]])) + /// ``` + #[must_use] + pub fn from_rows(iter: I) -> Self where Self: Default, - I: Iterator> + Copy, + I: IntoIterator>, { let mut result = Self::default(); - for (m, row) in iter.enumerate().filter(|(m, _)| *m <= M) { + for (m, row) in iter.into_iter().enumerate().take(M) { result.set_row(m, &row) } result } - fn from_cols(iter: &I) -> Self + /// Create a matrix from an iterator of vectors + /// + /// # Arguments + /// + /// * `iter`: iterator of vectors to copy into columns + /// + /// returns: Matrix + /// + /// # Examples + /// + /// ``` + /// # use vector_victor::Matrix; + /// let my_matrix = Matrix::new([[1,2,3],[4,5,6]]); + /// let transpose : Matrix<_,3,2>= Matrix::from_cols(my_matrix.rows()); + /// assert_eq!(transpose, Matrix::new([[1,4],[2,5],[3,6]])) + /// ``` + #[must_use] + pub fn from_cols(iter: I) -> Self where Self: Default, - I: Iterator> + Copy, + I: IntoIterator>, { let mut result = Self::default(); - for (n, col) in iter.enumerate().filter(|(n, _)| *n <= N) { + for (n, col) in iter.into_iter().enumerate().take(N) { result.set_col(n, &col) } result } - fn elements<'a>(&'a self) -> impl Iterator + 'a { + /// Returns an iterator over the elements of the matrix in row-major order. + /// + /// # Examples + /// ``` + /// # use vector_victor::Matrix; + /// let my_matrix = Matrix::new([[1,2],[3,4]]); + /// assert!(vec![1,2,3,4].iter().eq(my_matrix.elements())) + /// ``` + #[must_use] + pub fn elements<'a>(&'a self) -> impl Iterator + 'a { self.data.iter().flatten() } - fn elements_mut<'a>(&'a mut self) -> impl Iterator + 'a { + /// Returns a mutable iterator over the elements of the matrix in row-major order. + #[must_use] + pub fn elements_mut<'a>(&'a mut self) -> impl Iterator + 'a { self.data.iter_mut().flatten() } - fn get(&self, index: impl Index2D) -> Option<&T> { + /// Returns a reference to the element at that position in the matrix or `None` if out of bounds. + /// + /// # Examples + /// + /// ``` + /// # use vector_victor::Matrix; + /// let my_matrix = Matrix::new([[1,2],[3,4]]); + /// + /// // element at index 2 is the same as the element at (row 1, column 0). + /// assert_eq!(my_matrix.get(2), my_matrix.get((1,0))); + /// // index 4 is out of range, so get(4) returns None. + /// assert_eq!(my_matrix.get(4), None); + /// ``` + #[inline] + #[must_use] + pub fn get(&self, index: impl Index2D) -> Option<&T> { let (m, n) = index.to_2d(M, N)?; Some(&self.data[m][n]) } - fn get_mut(&mut self, index: impl Index2D) -> Option<&mut T> { + #[inline] + #[must_use] + pub fn get_mut(&mut self, index: impl Index2D) -> Option<&mut T> { let (m, n) = index.to_2d(M, N)?; Some(&mut self.data[m][n]) } - fn row(&self, m: usize) -> Option> { + #[inline] + #[must_use] + pub fn row(&self, m: usize) -> Option> { if m < M { - Some(Vector::::new_vector(self.data[m])) + Some(Vector::::vec(self.data[m])) } else { None } } - fn set_row(&mut self, m: usize, val: &Vector) { + #[inline] + pub fn set_row(&mut self, m: usize, val: &Vector) { assert!( m < M, "Row index {} out of bounds for {}x{} matrix", @@ -99,15 +204,18 @@ impl Matrix { } } - fn col(&self, n: usize) -> Option> { + #[inline] + #[must_use] + pub fn col(&self, n: usize) -> Option> { if n < N { - Some(Vector::::new_vector(self.data.map(|r| r[n]))) + Some(Vector::::vec(self.data.map(|r| r[n]))) } else { None } } - fn set_col(&mut self, n: usize, val: &Vector) { + #[inline] + pub fn set_col(&mut self, n: usize, val: &Vector) { assert!( n < N, "Column index {} out of bounds for {}x{} matrix", @@ -121,37 +229,100 @@ impl Matrix { } } - fn rows<'a>(&'a self) -> impl Iterator> + 'a { + #[must_use] + pub fn rows<'a>(&'a self) -> impl Iterator> + 'a { (0..M).map(|m| self.row(m).expect("invalid row reached while iterating")) } - fn cols<'a>(&'a self) -> impl Iterator> + 'a { + #[must_use] + pub fn cols<'a>(&'a self) -> impl Iterator> + 'a { (0..N).map(|n| self.col(n).expect("invalid column reached while iterating")) } } -// constructor for column vectors -impl Vector { - fn new_vector(data: [T; N]) -> Self { - return Vector:: { - data: data.map(|e| [e]), +// 1D vector implementations +impl Matrix { + /// Create a vector from a 1D array. + /// Note that vectors are always column vectors unless explicitly instantiated as row vectors + /// + /// # Arguments + /// + /// * `data`: A 1D array of elements to copy into the new vector + /// + /// returns: Matrix + /// + /// # Examples + /// + /// ``` + /// # use vector_victor::{Matrix, Vector}; + /// let my_vector = Vector::vec([1,2,3,4]); + /// // is equivalent to + /// assert_eq!(my_vector, Matrix::new([[1],[2],[3],[4]])); + /// ``` + pub fn vec(data: [T; M]) -> Self { + return Matrix:: { + data: data.map(|e| [e; 1]), }; } } -// default constructor -impl Default for Matrix +// Index +impl Index for Matrix where - [[T; N]; M]: Default, + I: Index2D, T: Scalar, { + type Output = T; + + fn index(&self, index: I) -> &Self::Output { + self.get(index).expect(&*format!( + "index {:?} out of range for {}x{} Matrix", + index, M, N + )) + } +} + +// IndexMut +impl IndexMut for Matrix +where + I: Index2D, + T: Scalar, +{ + fn index_mut(&mut self, index: I) -> &mut Self::Output { + self.get_mut(index).expect(&*format!( + "index {:?} out of range for {}x{} Matrix", + index, M, N + )) + } +} + +// Default +impl Default for Matrix { fn default() -> Self { Matrix { - data: Default::default(), + data: [[T::default(); N]; M], } } } +impl From<[[T; N]; M]> for Matrix { + fn from(data: [[T; N]; M]) -> Self { + Self::new(data) + } +} + +impl From<[T; M]> for Vector { + fn from(data: [T; M]) -> Self { + Self::vec(data) + } +} + +impl From for Matrix { + fn from(scalar: T) -> Self { + Self::fill(scalar) + } +} + // deref 1x1 matrices to a scalar automatically impl Deref for Matrix { type Target = T; @@ -168,6 +339,7 @@ impl DerefMut for Matrix { } } +// IntoIter impl IntoIterator for Matrix { type Item = T; type IntoIter = Flatten>; @@ -177,15 +349,53 @@ impl IntoIterator for Matrix } } -impl_matrix_op!(neg, |l: L| { -l }); -impl_matrix_op!(!, |l: L| { !l }); -impl_matrix_op!(+, |l,r| {l + r}); -impl_matrix_op!(-, |l,r| {l - r}); -impl_matrix_op!(*, |l,r| {l * r}); -impl_matrix_op!(/, |l,r| {l / r}); -impl_matrix_op!(%, |l,r| {l % r}); -impl_matrix_op!(&, |l,r| {l & r}); -impl_matrix_op!(|, |l,r| {l | r}); -impl_matrix_op!(^, |l,r| {l ^ r}); -impl_matrix_op!(<<, |l,r| {l << r}); -impl_matrix_op!(>>, |l,r| {l >> r}); +// FromIterator +impl FromIterator for Matrix +where + Self: Default, +{ + fn from_iter>(iter: I) -> Self { + let mut result: Self = Default::default(); + for (l, r) in zip(result.elements_mut(), iter) { + *l = r; + } + result + } +} + +impl Sum for Matrix { + fn sum>(iter: I) -> Self { + let mut sum = Self::default(); + + for m in iter { + sum += m; + } + + sum + } +} + +impl Product for Matrix { + fn product>(iter: I) -> Self { + let mut prod = Self::default(); + + for m in iter { + prod *= m; + } + + prod + } +} + +impl_matrix_op!(neg); +impl_matrix_op!(!); +impl_matrix_op!(+); +impl_matrix_op!(-); +impl_matrix_op!(*); +impl_matrix_op!(/); +impl_matrix_op!(%); +impl_matrix_op!(&); +impl_matrix_op!(|); +impl_matrix_op!(^); +impl_matrix_op!(<<); +impl_matrix_op!(>>); diff --git a/tests/ops.rs b/tests/ops.rs new file mode 100644 index 0000000..0afb902 --- /dev/null +++ b/tests/ops.rs @@ -0,0 +1,18 @@ +use generic_parameterize::parameterize; +use std::fmt::Debug; +use std::ops; +use vector_victor::{Matrix, Scalar}; + +#[parameterize(S = (i32, f32, u32), M = [1,4], N = [1,4])] +#[test] +fn test_add + PartialEq + Debug, const M: usize, const N: usize>() +where + Matrix: ops::Add>, +{ + let a = Matrix::::fill(S::from(1)); + let b = Matrix::::fill(S::from(3)); + let c: Matrix = a + b; + for (i, ci) in c.elements().enumerate() { + assert_eq!(*ci, S::from(4)); + } +}