Expand API and start adding tests

master
Andrew Cassidy 2 years ago
parent 2bb625bdaf
commit e928ed6926

@ -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"

@ -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<usize> {
let (r, c) = self.to_2d(height, width)?;
Some(r * width + c)

@ -1,3 +1,7 @@
extern crate core;
pub mod index;
mod matrix;
mod macros;
mod matrix;
pub use matrix::{Matrix, Scalar, Vector};

@ -2,137 +2,117 @@
#[doc(hidden)]
#[macro_export]
macro_rules! impl_matrix_op {
(neg, $f:expr) => {
$crate::_impl_op_m_internal_ex!(Neg, neg, $f);
};
(!, $f:expr) => {
$crate::_impl_op_m_internal_ex!(Not, not, $f);
};
(+, $f:expr) => {
$crate::_impl_op_mm_internal_ex!(Add, add, $f);
$crate::_impl_opassign_mm_internal_ex!(Add, AddAssign, add_assign, $f);
};
(-, $f:expr) => {
$crate::_impl_op_mm_internal_ex!(Sub, sub, $f);
$crate::_impl_opassign_mm_internal_ex!(Sub, SubAssign, sub_assign, $f);
};
(*, $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);
};
(/, $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);
};
(%, $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);
};
(&, $f:expr) => {
$crate::_impl_op_mm_internal_ex!(BitAnd, bitand, $f);
$crate::_impl_opassign_mm_internal_ex!(BitAnd, BitAndAssign, bitand_assign, $f);
};
(|, $f:expr) => {
$crate::_impl_op_mm_internal_ex!(BitOr, bitor, $f);
$crate::_impl_opassign_mm_internal_ex!(BitOr, BitOrAssign, bitor_assign, $f);
};
(^, $f:expr) => {
$crate::_impl_op_mm_internal_ex!(BitXor, bitxor, $f);
$crate::_impl_opassign_mm_internal_ex!(BitXor, BitXorAssign, bitxor_assign, $f);
};
(<<, $f:expr) => {
$crate::_impl_op_ms_internal_ex!(Shl, shl, $f);
$crate::_impl_opassign_mm_internal_ex!(Shl, ShlAssign, shl_assign, $f);
};
(>>, $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);
(neg) => {
$crate::_impl_op_m_internal_ex!(Neg, neg);
};
(!) => {
$crate::_impl_op_m_internal_ex!(Not, not);
};
(+) => {
$crate::_impl_op_mm_internal_ex!(Add, add);
$crate::_impl_opassign_mm_internal_ex!(AddAssign, add_assign);
};
(-) => {
$crate::_impl_op_mm_internal_ex!(Sub, sub);
$crate::_impl_opassign_mm_internal_ex!(SubAssign, sub_assign);
};
(*) => {
$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);
};
(/) => {
$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);
};
(%) => {
$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);
};
(&) => {
$crate::_impl_op_mm_internal_ex!(BitAnd, bitand);
$crate::_impl_opassign_mm_internal_ex!(BitAndAssign, bitand_assign);
};
(|) => {
$crate::_impl_op_mm_internal_ex!(BitOr, bitor);
$crate::_impl_opassign_mm_internal_ex!(BitOrAssign, bitor_assign);
};
(^) => {
$crate::_impl_op_mm_internal_ex!(BitXor, bitxor);
$crate::_impl_opassign_mm_internal_ex!(BitXorAssign, bitxor_assign);
};
(<<) => {
$crate::_impl_op_ms_internal_ex!(Shl, shl);
$crate::_impl_opassign_ms_internal_ex!(ShlAssign, shl_assign);
};
(>>) => {
$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<L,M,N>, Matrix<L,M,N>, $f);
$crate::_impl_op_m_internal!($ops_trait, $ops_fn, &Matrix<L,M,N>, Matrix<L,M,N>, $f);
($ops_trait:ident, $ops_fn:ident) => {
$crate::_impl_op_m_internal!($ops_trait, $ops_fn, Matrix<L,M,N>, Matrix<L,M,N>);
$crate::_impl_op_m_internal!($ops_trait, $ops_fn, &Matrix<L,M,N>, Matrix<L,M,N>);
}
}
#[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<L,M,N>, Matrix<R,M,N>, Matrix<L,M,N>, $f);
$crate::_impl_op_mm_internal!($ops_trait, $ops_fn, &Matrix<L,M,N>, Matrix<R,M,N>, Matrix<L,M,N>, $f);
$crate::_impl_op_mm_internal!($ops_trait, $ops_fn, Matrix<L,M,N>, &Matrix<R,M,N>, Matrix<L,M,N>, $f);
$crate::_impl_op_mm_internal!($ops_trait, $ops_fn, &Matrix<L,M,N>, &Matrix<R,M,N>, Matrix<L,M,N>, $f);
($ops_trait:ident, $ops_fn:ident) => {
$crate::_impl_op_mm_internal!($ops_trait, $ops_fn, Matrix<L,M,N>, Matrix<R,M,N>, Matrix<L,M,N>);
$crate::_impl_op_mm_internal!($ops_trait, $ops_fn, &Matrix<L,M,N>, Matrix<R,M,N>, Matrix<L,M,N>);
$crate::_impl_op_mm_internal!($ops_trait, $ops_fn, Matrix<L,M,N>, &Matrix<R,M,N>, Matrix<L,M,N>);
$crate::_impl_op_mm_internal!($ops_trait, $ops_fn, &Matrix<L,M,N>, &Matrix<R,M,N>, Matrix<L,M,N>);
}
}
#[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<L,M,N>, Matrix<R,M,N>, Matrix<L,M,N>, $f);
$crate::_impl_opassign_mm_internal!($ops_super, $ops_trait, $ops_fn, Matrix<L,M,N>, &Matrix<R,M,N>, Matrix<L,M,N>, $f);
($ops_trait:ident, $ops_fn:ident) => {
$crate::_impl_opassign_mm_internal!($ops_trait, $ops_fn, Matrix<L,M,N>, Matrix<R,M,N>, Matrix<L,M,N>);
$crate::_impl_opassign_mm_internal!($ops_trait, $ops_fn, Matrix<L,M,N>, &Matrix<R,M,N>, Matrix<L,M,N>);
}
}
#[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<L,M,N>, R, Matrix<L,M,N>, $f);
$crate::_impl_op_ms_internal!($ops_trait, $ops_fn, &Matrix<L,M,N>, R, Matrix<L,M,N>, $f);
($ops_trait:ident, $ops_fn:ident) => {
$crate::_impl_op_ms_internal!($ops_trait, $ops_fn, Matrix<L,M,N>, R, Matrix<L,M,N>);
$crate::_impl_op_ms_internal!($ops_trait, $ops_fn, &Matrix<L,M,N>, R, Matrix<L,M,N>);
}
}
#[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<L,M,N>, R, Matrix<L,M,N>, $f);
($ops_trait:ident, $ops_fn:ident) => {
$crate::_impl_opassign_ms_internal!($ops_trait, $ops_fn, Matrix<L,M,N>, R, Matrix<L,M,N>);
}
}
#[macro_export]
macro_rules! _impl_op_mm_internal {
($ops_trait:ident, $ops_fn:ident, $lhs:ty, $rhs:ty, $out:ty, $f:expr) => {
impl<L, R, const M: usize, const N: usize> ::std::ops::$ops_trait<$rhs> for $lhs
macro_rules! _impl_op_m_internal {
($ops_trait:ident, $ops_fn:ident, $lhs:ty, $out:ty) => {
impl<L, const M: usize, const N: usize> ::std::ops::$ops_trait for $lhs
where
L: ::std::ops::$ops_trait<R, Output = L>,
L: Scalar,
R: Scalar,
L: ::std::ops::$ops_trait<Output = L> + Scalar,
{
type Output = $out;
fn $ops_fn(self, rhs_i: $rhs) -> Self::Output {
#[inline(always)]
fn $ops_fn(self) -> 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();
}
}
result
}
@ -141,42 +121,44 @@ 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) => {
macro_rules! _impl_op_mm_internal {
($ops_trait:ident, $ops_fn:ident, $lhs:ty, $rhs:ty, $out:ty) => {
impl<L, R, const M: usize, const N: usize> ::std::ops::$ops_trait<$rhs> for $lhs
where
L: ::std::ops::$ops_trait<R>,
L: ::std::ops::$ops_super<R, Output = L>,
L: Scalar,
L: ::std::ops::$ops_trait<R, Output = L> + 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);
type Output = $out;
#[inline(always)]
fn $ops_fn(self, other: $rhs) -> 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(other.data[m][n]);
}
}
result
}
}
};
}
#[macro_export]
macro_rules! _impl_op_m_internal {
($ops_trait:ident, $ops_fn:ident, $lhs:ty, $out:ty, $f:expr) => {
impl<L, const M: usize, const N: usize> ::std::ops::$ops_trait for $lhs
macro_rules! _impl_opassign_mm_internal {
($ops_trait:ident, $ops_fn:ident, $lhs:ty, $rhs:ty, $out:ty) => {
impl<L, R, const M: usize, const N: usize> ::std::ops::$ops_trait<$rhs> for $lhs
where
L: ::std::ops::$ops_trait<Output = L>,
L: Scalar,
L: ::std::ops::$ops_trait<R> + Scalar,
R: 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);
#[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]);
}
}
result
}
}
};
@ -184,20 +166,21 @@ macro_rules! _impl_op_m_internal {
#[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<L, R, const M: usize, const N: usize> ::std::ops::$ops_trait<$rhs> for $lhs
where
L: ::std::ops::$ops_trait<R, Output = L>,
L: Scalar,
L: ::std::ops::$ops_trait<R, Output = L> + 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<L, R, const M: usize, const N: usize> ::std::ops::$ops_trait<$rhs> for $lhs
where
L: ::std::ops::$ops_trait<R>,
L: ::std::ops::$ops_super<R, Output = L>,
L: Scalar,
L: ::std::ops::$ops_trait<R> + 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);
}
}
}
}

@ -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<I: Index2D>(&self, i: I) -> Option<&Self::Scalar>;
}
pub trait Get2DMut: Get2D {
fn get_mut<I: Index2D>(&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<T> 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<T> Scalar for &'static T
where
T: Scalar,
&'static T: Default,
{
}
#[derive(Debug, Copy, Clone)]
struct Matrix<T, const M: usize, const N: usize>
/// 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<T, const M: usize, const N: usize>
where
T: Scalar,
{
data: [[T; N]; M],
}
type Vector<T, const N: usize> = Matrix<T, N, 1>;
/// An alias for a [Matrix] with a single column
pub type Vector<T, const N: usize> = Matrix<T, N, 1>;
impl<T: Scalar, const M: usize, const N: usize> Matrix<T, M, N> {
fn new(data: [[T; N]; M]) -> Self {
return Matrix::<T, M, N> { data };
/// Generate a new matrix from a 2D Array
///
/// # Arguments
///
/// * `data`: A 2D array of elements to copy into the new matrix
///
/// returns: Matrix<T, M, N>
///
/// # 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::<T, M, N> { data }
}
/// Generate a new matrix from a single scalar
///
/// # Arguments
///
/// * `scalar`: Scalar value to copy into the new matrix.
///
/// returns: Matrix<T, M, N>
///
/// # Examples
///
/// ```
/// # use vector_victor::Matrix;
/// let my_matrix = Matrix::<i32,4,4>::fill(5);
/// // is equivalent to
/// assert_eq!(my_matrix, Matrix::new([[5;4];4]))
/// ```
#[must_use]
pub fn fill(scalar: T) -> Matrix<T, M, N> {
Matrix::<T, M, N> {
data: [[scalar; N]; M],
}
}
fn from_rows<I>(iter: &I) -> Self
/// Create a matrix from an iterator of vectors
///
/// # Arguments
///
/// * `iter`: iterator of vectors to copy into rows
///
/// returns: Matrix<T, M, N>
///
/// # 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<I>(iter: I) -> Self
where
Self: Default,
I: Iterator<Item = Vector<T, N>> + Copy,
I: IntoIterator<Item = Vector<T, N>>,
{
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<I>(iter: &I) -> Self
/// Create a matrix from an iterator of vectors
///
/// # Arguments
///
/// * `iter`: iterator of vectors to copy into columns
///
/// returns: Matrix<T, M, N>
///
/// # 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<I>(iter: I) -> Self
where
Self: Default,
I: Iterator<Item = Vector<T, M>> + Copy,
I: IntoIterator<Item = Vector<T, M>>,
{
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<Item = &T> + '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<Item = &T> + 'a {
self.data.iter().flatten()
}
fn elements_mut<'a>(&'a mut self) -> impl Iterator<Item = &mut T> + '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<Item = &mut T> + '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<Vector<T, N>> {
#[inline]
#[must_use]
pub fn row(&self, m: usize) -> Option<Vector<T, N>> {
if m < M {
Some(Vector::<T, N>::new_vector(self.data[m]))
Some(Vector::<T, N>::vec(self.data[m]))
} else {
None
}
}
fn set_row(&mut self, m: usize, val: &Vector<T, N>) {
#[inline]
pub fn set_row(&mut self, m: usize, val: &Vector<T, N>) {
assert!(
m < M,
"Row index {} out of bounds for {}x{} matrix",
@ -99,15 +204,18 @@ impl<T: Scalar, const M: usize, const N: usize> Matrix<T, M, N> {
}
}
fn col(&self, n: usize) -> Option<Vector<T, M>> {
#[inline]
#[must_use]
pub fn col(&self, n: usize) -> Option<Vector<T, M>> {
if n < N {
Some(Vector::<T, M>::new_vector(self.data.map(|r| r[n])))
Some(Vector::<T, M>::vec(self.data.map(|r| r[n])))
} else {
None
}
}
fn set_col(&mut self, n: usize, val: &Vector<T, M>) {
#[inline]
pub fn set_col(&mut self, n: usize, val: &Vector<T, M>) {
assert!(
n < N,
"Column index {} out of bounds for {}x{} matrix",
@ -121,37 +229,100 @@ impl<T: Scalar, const M: usize, const N: usize> Matrix<T, M, N> {
}
}
fn rows<'a>(&'a self) -> impl Iterator<Item = Vector<T, N>> + 'a {
#[must_use]
pub fn rows<'a>(&'a self) -> impl Iterator<Item = Vector<T, N>> + 'a {
(0..M).map(|m| self.row(m).expect("invalid row reached while iterating"))
}
fn cols<'a>(&'a self) -> impl Iterator<Item = Vector<T, M>> + 'a {
#[must_use]
pub fn cols<'a>(&'a self) -> impl Iterator<Item = Vector<T, M>> + 'a {
(0..N).map(|n| self.col(n).expect("invalid column reached while iterating"))
}
}
// constructor for column vectors
impl<T: Scalar, const N: usize> Vector<T, N> {
fn new_vector(data: [T; N]) -> Self {
return Vector::<T, N> {
data: data.map(|e| [e]),
// 1D vector implementations
impl<T: Scalar, const M: usize> Matrix<T, M, 1> {
/// 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<T, { M }, 1>
///
/// # 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::<T, M, 1> {
data: data.map(|e| [e; 1]),
};
}
}
// default constructor
impl<T, const M: usize, const N: usize> Default for Matrix<T, M, N>
// Index
impl<I, T, const M: usize, const N: usize> Index<I> for Matrix<T, M, N>
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<I, T, const M: usize, const N: usize> IndexMut<I> for Matrix<T, M, N>
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<T: Scalar, const M: usize, const N: usize> Default for Matrix<T, M, N> {
fn default() -> Self {
Matrix {
data: Default::default(),
data: [[T::default(); N]; M],
}
}
}
impl<T: Scalar, const M: usize, const N: usize> From<[[T; N]; M]> for Matrix<T, M, N> {
fn from(data: [[T; N]; M]) -> Self {
Self::new(data)
}
}
impl<T: Scalar, const M: usize> From<[T; M]> for Vector<T, M> {
fn from(data: [T; M]) -> Self {
Self::vec(data)
}
}
impl<T: Scalar, const M: usize, const N: usize> From<T> for Matrix<T, M, N> {
fn from(scalar: T) -> Self {
Self::fill(scalar)
}
}
// deref 1x1 matrices to a scalar automatically
impl<T: Scalar> Deref for Matrix<T, 1, 1> {
type Target = T;
@ -168,6 +339,7 @@ impl<T: Scalar> DerefMut for Matrix<T, 1, 1> {
}
}
// IntoIter
impl<T: Scalar, const M: usize, const N: usize> IntoIterator for Matrix<T, M, N> {
type Item = T;
type IntoIter = Flatten<std::array::IntoIter<[T; N], M>>;
@ -177,15 +349,53 @@ impl<T: Scalar, const M: usize, const N: usize> IntoIterator for Matrix<T, M, N>
}
}
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<T: Scalar, const M: usize, const N: usize> FromIterator<T> for Matrix<T, M, N>
where
Self: Default,
{
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
let mut result: Self = Default::default();
for (l, r) in zip(result.elements_mut(), iter) {
*l = r;
}
result
}
}
impl<T: Scalar + AddAssign, const M: usize, const N: usize> Sum for Matrix<T, M, N> {
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
let mut sum = Self::default();
for m in iter {
sum += m;
}
sum
}
}
impl<T: Scalar + MulAssign, const M: usize, const N: usize> Product for Matrix<T, M, N> {
fn product<I: Iterator<Item = Self>>(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!(>>);

@ -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<S: Scalar + From<u16> + PartialEq + Debug, const M: usize, const N: usize>()
where
Matrix<S, M, N>: ops::Add<Output = Matrix<S, M, N>>,
{
let a = Matrix::<S, M, N>::fill(S::from(1));
let b = Matrix::<S, M, N>::fill(S::from(3));
let c: Matrix<S, M, N> = a + b;
for (i, ci) in c.elements().enumerate() {
assert_eq!(*ci, S::from(4));
}
}
Loading…
Cancel
Save