mirror of
https://github.com/drewcassidy/vector-victor.git
synced 2024-09-01 14:58:35 +00:00
Expand API and start adding tests
This commit is contained in:
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,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<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_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<Output = L> + 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<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, 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<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,
|
||||
{
|
||||
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<L, const M: usize, const N: usize> ::std::ops::$ops_trait for $lhs
|
||||
where
|
||||
L: ::std::ops::$ops_trait<Output = L>,
|
||||
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<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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
334
src/matrix.rs
334
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<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 }
|
||||
}
|
||||
|
||||
fn from_rows<I>(iter: &I) -> Self
|
||||
/// 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],
|
||||
}
|
||||
}
|
||||
|
||||
/// 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!(>>);
|
||||
|
18
tests/ops.rs
Normal file
18
tests/ops.rs
Normal file
@ -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…
Reference in New Issue
Block a user