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
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[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> {
|
fn to_1d(self, height: usize, width: usize) -> Option<usize> {
|
||||||
let (r, c) = self.to_2d(height, width)?;
|
let (r, c) = self.to_2d(height, width)?;
|
||||||
Some(r * width + c)
|
Some(r * width + c)
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
extern crate core;
|
||||||
|
|
||||||
pub mod index;
|
pub mod index;
|
||||||
mod matrix;
|
|
||||||
mod macros;
|
mod macros;
|
||||||
|
mod matrix;
|
||||||
|
|
||||||
|
pub use matrix::{Matrix, Scalar, Vector};
|
||||||
|
@ -2,137 +2,141 @@
|
|||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! impl_matrix_op {
|
macro_rules! impl_matrix_op {
|
||||||
(neg, $f:expr) => {
|
(neg) => {
|
||||||
$crate::_impl_op_m_internal_ex!(Neg, neg, $f);
|
$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_op_mm_internal_ex!(Add, add);
|
||||||
$crate::_impl_opassign_mm_internal_ex!(Add, AddAssign, add_assign, $f);
|
$crate::_impl_opassign_mm_internal_ex!(AddAssign, add_assign);
|
||||||
};
|
};
|
||||||
(-, $f:expr) => {
|
(-) => {
|
||||||
$crate::_impl_op_mm_internal_ex!(Sub, sub, $f);
|
$crate::_impl_op_mm_internal_ex!(Sub, sub);
|
||||||
$crate::_impl_opassign_mm_internal_ex!(Sub, SubAssign, sub_assign, $f);
|
$crate::_impl_opassign_mm_internal_ex!(SubAssign, sub_assign);
|
||||||
};
|
};
|
||||||
(*, $f:expr) => {
|
(*) => {
|
||||||
$crate::_impl_op_mm_internal_ex!(Mul, mul, $f);
|
$crate::_impl_op_mm_internal_ex!(Mul, mul);
|
||||||
$crate::_impl_op_ms_internal_ex!(Mul, mul, $f);
|
$crate::_impl_op_ms_internal_ex!(Mul, mul);
|
||||||
$crate::_impl_opassign_mm_internal_ex!(Mul, MulAssign, mul_assign, $f);
|
$crate::_impl_opassign_mm_internal_ex!(MulAssign, mul_assign);
|
||||||
$crate::_impl_opassign_ms_internal_ex!(Mul, MulAssign, mul_assign, $f);
|
$crate::_impl_opassign_ms_internal_ex!(MulAssign, mul_assign);
|
||||||
};
|
};
|
||||||
(/, $f:expr) => {
|
(/) => {
|
||||||
$crate::_impl_op_mm_internal_ex!(Div, div, $f);
|
$crate::_impl_op_mm_internal_ex!(Div, div);
|
||||||
$crate::_impl_op_ms_internal_ex!(Div, div, $f);
|
$crate::_impl_op_ms_internal_ex!(Div, div);
|
||||||
$crate::_impl_opassign_mm_internal_ex!(Div, DivAssign, div_assign, $f);
|
$crate::_impl_opassign_mm_internal_ex!(DivAssign, div_assign);
|
||||||
$crate::_impl_opassign_ms_internal_ex!(Div, DivAssign, div_assign, $f);
|
$crate::_impl_opassign_ms_internal_ex!(DivAssign, div_assign);
|
||||||
};
|
};
|
||||||
(%, $f:expr) => {
|
(%) => {
|
||||||
$crate::_impl_op_mm_internal_ex!(Rem, rem, $f);
|
$crate::_impl_op_mm_internal_ex!(Rem, rem);
|
||||||
$crate::_impl_op_ms_internal_ex!(Rem, rem, $f);
|
$crate::_impl_op_ms_internal_ex!(Rem, rem);
|
||||||
$crate::_impl_opassign_mm_internal_ex!(Rem, RemAssign, rem_assign, $f);
|
$crate::_impl_opassign_mm_internal_ex!(RemAssign, rem_assign);
|
||||||
$crate::_impl_opassign_ms_internal_ex!(Rem, RemAssign, rem_assign, $f);
|
$crate::_impl_opassign_ms_internal_ex!(RemAssign, rem_assign);
|
||||||
};
|
};
|
||||||
(&, $f:expr) => {
|
(&) => {
|
||||||
$crate::_impl_op_mm_internal_ex!(BitAnd, bitand, $f);
|
$crate::_impl_op_mm_internal_ex!(BitAnd, bitand);
|
||||||
$crate::_impl_opassign_mm_internal_ex!(BitAnd, BitAndAssign, bitand_assign, $f);
|
$crate::_impl_opassign_mm_internal_ex!(BitAndAssign, bitand_assign);
|
||||||
};
|
};
|
||||||
(|, $f:expr) => {
|
(|) => {
|
||||||
$crate::_impl_op_mm_internal_ex!(BitOr, bitor, $f);
|
$crate::_impl_op_mm_internal_ex!(BitOr, bitor);
|
||||||
$crate::_impl_opassign_mm_internal_ex!(BitOr, BitOrAssign, bitor_assign, $f);
|
$crate::_impl_opassign_mm_internal_ex!(BitOrAssign, bitor_assign);
|
||||||
};
|
};
|
||||||
(^, $f:expr) => {
|
(^) => {
|
||||||
$crate::_impl_op_mm_internal_ex!(BitXor, bitxor, $f);
|
$crate::_impl_op_mm_internal_ex!(BitXor, bitxor);
|
||||||
$crate::_impl_opassign_mm_internal_ex!(BitXor, BitXorAssign, bitxor_assign, $f);
|
$crate::_impl_opassign_mm_internal_ex!(BitXorAssign, bitxor_assign);
|
||||||
};
|
};
|
||||||
(<<, $f:expr) => {
|
(<<) => {
|
||||||
$crate::_impl_op_ms_internal_ex!(Shl, shl, $f);
|
$crate::_impl_op_ms_internal_ex!(Shl, shl);
|
||||||
$crate::_impl_opassign_mm_internal_ex!(Shl, ShlAssign, shl_assign, $f);
|
$crate::_impl_opassign_ms_internal_ex!(ShlAssign, shl_assign);
|
||||||
};
|
};
|
||||||
(>>, $f:expr) => {
|
(>>) => {
|
||||||
$crate::_impl_op_ms_internal_ex!(Shr, shr, $f);
|
$crate::_impl_op_ms_internal_ex!(Shr, shr);
|
||||||
$crate::_impl_opassign_mm_internal_ex!(Shr, ShrAssign, shr_assign, $f);
|
$crate::_impl_opassign_ms_internal_ex!(ShrAssign, shr_assign);
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[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);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! _impl_op_m_internal_ex {
|
macro_rules! _impl_op_m_internal_ex {
|
||||||
($ops_trait:ident, $ops_fn:ident, $f:expr) => {
|
($ops_trait:ident, $ops_fn:ident) => {
|
||||||
$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>);
|
||||||
$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>);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! _impl_op_mm_internal_ex {
|
macro_rules! _impl_op_mm_internal_ex {
|
||||||
($ops_trait:ident, $ops_fn:ident, $f:expr) => {
|
($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>, $f);
|
$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>, $f);
|
$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>, $f);
|
$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>, $f);
|
$crate::_impl_op_mm_internal!($ops_trait, $ops_fn, &Matrix<L,M,N>, &Matrix<R,M,N>, Matrix<L,M,N>);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! _impl_opassign_mm_internal_ex {
|
macro_rules! _impl_opassign_mm_internal_ex {
|
||||||
($ops_super:ident, $ops_trait:ident, $ops_fn:ident, $f:expr) => {
|
($ops_trait:ident, $ops_fn:ident) => {
|
||||||
$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_trait, $ops_fn, Matrix<L,M,N>, Matrix<R,M,N>, Matrix<L,M,N>);
|
||||||
$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_trait, $ops_fn, Matrix<L,M,N>, &Matrix<R,M,N>, Matrix<L,M,N>);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! _impl_op_ms_internal_ex {
|
macro_rules! _impl_op_ms_internal_ex {
|
||||||
($ops_trait:ident, $ops_fn:ident, $f:expr) => {
|
($ops_trait:ident, $ops_fn:ident) => {
|
||||||
$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>);
|
||||||
$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>);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! _impl_opassign_ms_internal_ex {
|
macro_rules! _impl_opassign_ms_internal_ex {
|
||||||
($ops_super:ident, $ops_trait:ident, $ops_fn:ident, $f:expr) => {
|
($ops_trait:ident, $ops_fn:ident) => {
|
||||||
$crate::_impl_opassign_ms_internal!($ops_super, $ops_trait, $ops_fn, Matrix<L,M,N>, R, Matrix<L,M,N>, $f);
|
$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_export]
|
||||||
macro_rules! _impl_op_mm_internal {
|
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
|
impl<L, R, const M: usize, const N: usize> ::std::ops::$ops_trait<$rhs> for $lhs
|
||||||
where
|
where
|
||||||
L: ::std::ops::$ops_trait<R, Output = L>,
|
L: ::std::ops::$ops_trait<R, Output = L> + Scalar,
|
||||||
L: Scalar,
|
|
||||||
R: Scalar,
|
R: Scalar,
|
||||||
{
|
{
|
||||||
type Output = $out;
|
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 mut result = self.clone();
|
||||||
let op = $f;
|
for m in 0..M {
|
||||||
for (l, r) in zip(result.elements_mut(), rhs_i.elements()) {
|
for n in 0..N {
|
||||||
*l = op(*l, *r);
|
result.data[m][n] = self.data[m][n].$ops_fn(other.data[m][n]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
@ -142,62 +146,41 @@ macro_rules! _impl_op_mm_internal {
|
|||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! _impl_opassign_mm_internal {
|
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
|
impl<L, R, const M: usize, const N: usize> ::std::ops::$ops_trait<$rhs> for $lhs
|
||||||
where
|
where
|
||||||
L: ::std::ops::$ops_trait<R>,
|
L: ::std::ops::$ops_trait<R> + Scalar,
|
||||||
L: ::std::ops::$ops_super<R, Output = L>,
|
|
||||||
L: Scalar,
|
|
||||||
R: Scalar,
|
R: Scalar,
|
||||||
{
|
{
|
||||||
fn $ops_fn(&mut self, rhs_i: $rhs) {
|
#[inline(always)]
|
||||||
let op = $f;
|
fn $ops_fn(&mut self, other: $rhs) {
|
||||||
for (l, r) in zip(self.elements_mut(), rhs_i.elements()) {
|
for m in 0..M {
|
||||||
*l = op(*l, *r);
|
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_export]
|
||||||
macro_rules! _impl_op_ms_internal {
|
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
|
impl<L, R, const M: usize, const N: usize> ::std::ops::$ops_trait<$rhs> for $lhs
|
||||||
where
|
where
|
||||||
L: ::std::ops::$ops_trait<R, Output = L>,
|
L: ::std::ops::$ops_trait<R, Output = L> + Scalar,
|
||||||
L: Scalar,
|
|
||||||
R: Scalar,
|
R: Scalar,
|
||||||
{
|
{
|
||||||
type Output = $out;
|
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 mut result = self.clone();
|
||||||
let op = $f;
|
for m in 0..M {
|
||||||
for l in result.elements_mut() {
|
for n in 0..N {
|
||||||
*l = op(*l, r);
|
result.data[m][n] = self.data[m][n].$ops_fn(other);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
@ -207,18 +190,18 @@ macro_rules! _impl_op_ms_internal {
|
|||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! _impl_opassign_ms_internal {
|
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
|
impl<L, R, const M: usize, const N: usize> ::std::ops::$ops_trait<$rhs> for $lhs
|
||||||
where
|
where
|
||||||
L: ::std::ops::$ops_trait<R>,
|
L: ::std::ops::$ops_trait<R> + Scalar,
|
||||||
L: ::std::ops::$ops_super<R, Output = L>,
|
|
||||||
L: Scalar,
|
|
||||||
R: Scalar,
|
R: Scalar,
|
||||||
{
|
{
|
||||||
|
#[inline(always)]
|
||||||
fn $ops_fn(&mut self, r: $rhs) {
|
fn $ops_fn(&mut self, r: $rhs) {
|
||||||
let op = $f;
|
for m in 0..M {
|
||||||
for l in self.elements_mut() {
|
for n in 0..N {
|
||||||
*l = op(*l, r);
|
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::impl_matrix_op;
|
||||||
use crate::index::Index2D;
|
use crate::index::Index2D;
|
||||||
use std::iter::{zip, Enumerate, Flatten};
|
use std::fmt::Debug;
|
||||||
use std::ops::{Add, Deref, DerefMut, Index, IndexMut, Range};
|
use std::iter::{zip, Flatten, Product, Sum};
|
||||||
use std::option::IntoIter;
|
use std::ops::{AddAssign, Deref, DerefMut, Index, IndexMut, MulAssign};
|
||||||
|
|
||||||
pub trait Get2D {
|
/// A Scalar that a [Matrix] can be made up of.
|
||||||
type Scalar: Sized + Copy;
|
///
|
||||||
const HEIGHT: usize;
|
/// This trait has no associated functions and can be implemented on any type that is [Default] and
|
||||||
const WIDTH: usize;
|
/// [Copy] and has a static lifetime.
|
||||||
|
pub trait Scalar: Default + Copy + 'static {}
|
||||||
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 {}
|
|
||||||
macro_rules! multi_impl { ($name:ident for $($t:ty),*) => ($( impl $name for $t {} )*) }
|
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);
|
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 {}
|
impl<T> Scalar for &'static T
|
||||||
|
where
|
||||||
|
T: Scalar,
|
||||||
|
&'static T: Default,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
/// A 2D array of values which can be operated upon.
|
||||||
struct Matrix<T, const M: usize, const N: usize>
|
///
|
||||||
|
/// 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
|
where
|
||||||
T: Scalar,
|
T: Scalar,
|
||||||
{
|
{
|
||||||
data: [[T; N]; M],
|
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> {
|
impl<T: Scalar, const M: usize, const N: usize> Matrix<T, M, N> {
|
||||||
fn new(data: [[T; N]; M]) -> Self {
|
/// Generate a new matrix from a 2D Array
|
||||||
return Matrix::<T, M, N> { data };
|
///
|
||||||
|
/// # 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
|
where
|
||||||
Self: Default,
|
Self: Default,
|
||||||
I: Iterator<Item = Vector<T, N>> + Copy,
|
I: IntoIterator<Item = Vector<T, N>>,
|
||||||
{
|
{
|
||||||
let mut result = Self::default();
|
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.set_row(m, &row)
|
||||||
}
|
}
|
||||||
result
|
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
|
where
|
||||||
Self: Default,
|
Self: Default,
|
||||||
I: Iterator<Item = Vector<T, M>> + Copy,
|
I: IntoIterator<Item = Vector<T, M>>,
|
||||||
{
|
{
|
||||||
let mut result = Self::default();
|
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.set_col(n, &col)
|
||||||
}
|
}
|
||||||
result
|
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()
|
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()
|
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)?;
|
let (m, n) = index.to_2d(M, N)?;
|
||||||
Some(&self.data[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)?;
|
let (m, n) = index.to_2d(M, N)?;
|
||||||
Some(&mut self.data[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 {
|
if m < M {
|
||||||
Some(Vector::<T, N>::new_vector(self.data[m]))
|
Some(Vector::<T, N>::vec(self.data[m]))
|
||||||
} else {
|
} else {
|
||||||
None
|
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!(
|
assert!(
|
||||||
m < M,
|
m < M,
|
||||||
"Row index {} out of bounds for {}x{} matrix",
|
"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 {
|
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 {
|
} else {
|
||||||
None
|
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!(
|
assert!(
|
||||||
n < N,
|
n < N,
|
||||||
"Column index {} out of bounds for {}x{} matrix",
|
"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"))
|
(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"))
|
(0..N).map(|n| self.col(n).expect("invalid column reached while iterating"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// constructor for column vectors
|
// 1D vector implementations
|
||||||
impl<T: Scalar, const N: usize> Vector<T, N> {
|
impl<T: Scalar, const M: usize> Matrix<T, M, 1> {
|
||||||
fn new_vector(data: [T; N]) -> Self {
|
/// Create a vector from a 1D array.
|
||||||
return Vector::<T, N> {
|
/// Note that vectors are always column vectors unless explicitly instantiated as row vectors
|
||||||
data: data.map(|e| [e]),
|
///
|
||||||
|
/// # 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
|
// Index
|
||||||
impl<T, const M: usize, const N: usize> Default for Matrix<T, M, N>
|
impl<I, T, const M: usize, const N: usize> Index<I> for Matrix<T, M, N>
|
||||||
where
|
where
|
||||||
[[T; N]; M]: Default,
|
I: Index2D,
|
||||||
T: Scalar,
|
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 {
|
fn default() -> Self {
|
||||||
Matrix {
|
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
|
// deref 1x1 matrices to a scalar automatically
|
||||||
impl<T: Scalar> Deref for Matrix<T, 1, 1> {
|
impl<T: Scalar> Deref for Matrix<T, 1, 1> {
|
||||||
type Target = T;
|
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> {
|
impl<T: Scalar, const M: usize, const N: usize> IntoIterator for Matrix<T, M, N> {
|
||||||
type Item = T;
|
type Item = T;
|
||||||
type IntoIter = Flatten<std::array::IntoIter<[T; N], M>>;
|
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 });
|
// FromIterator
|
||||||
impl_matrix_op!(!, |l: L| { !l });
|
impl<T: Scalar, const M: usize, const N: usize> FromIterator<T> for Matrix<T, M, N>
|
||||||
impl_matrix_op!(+, |l,r| {l + r});
|
where
|
||||||
impl_matrix_op!(-, |l,r| {l - r});
|
Self: Default,
|
||||||
impl_matrix_op!(*, |l,r| {l * r});
|
{
|
||||||
impl_matrix_op!(/, |l,r| {l / r});
|
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
|
||||||
impl_matrix_op!(%, |l,r| {l % r});
|
let mut result: Self = Default::default();
|
||||||
impl_matrix_op!(&, |l,r| {l & r});
|
for (l, r) in zip(result.elements_mut(), iter) {
|
||||||
impl_matrix_op!(|, |l,r| {l | r});
|
*l = r;
|
||||||
impl_matrix_op!(^, |l,r| {l ^ r});
|
}
|
||||||
impl_matrix_op!(<<, |l,r| {l << r});
|
result
|
||||||
impl_matrix_op!(>>, |l,r| {l >> r});
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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