extern crate core;
use index::MatrixIndex;
use itertools::Itertools;
use num_traits::{Bounded, One, Zero};
use std::cmp::min;
use std::fmt::Debug;
use std::iter::{zip, Flatten};
use std::ops::{Index, IndexMut};
pub mod decompose;
pub mod index;
mod math;
mod ops;
mod swizzle;
mod util;
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Matrix<T, const M: usize, const N: usize>
where
T: Copy,
{
data: [[T; N]; M], }
pub type Vector<T, const N: usize> = Matrix<T, N, 1>;
impl<T: Copy + Default, const M: usize, const N: usize> Default for Matrix<T, M, N> {
fn default() -> Self {
Matrix::fill(T::default())
}
}
impl<T: Copy + Zero, const M: usize, const N: usize> Zero for Matrix<T, M, N> {
fn zero() -> Self {
Matrix::fill(T::zero())
}
fn is_zero(&self) -> bool {
self.elements().all(|e| e.is_zero())
}
}
impl<T: Copy + One, const M: usize, const N: usize> One for Matrix<T, M, N> {
fn one() -> Self {
Matrix::fill(T::one())
}
}
impl<T: Copy + Bounded, const N: usize, const M: usize> Bounded for Matrix<T, N, M> {
fn min_value() -> Self {
Self::fill(T::min_value())
}
fn max_value() -> Self {
Self::fill(T::max_value())
}
}
impl<T: Copy + Zero + One, const N: usize> Matrix<T, N, N> {
#[must_use]
pub fn identity() -> Self {
let mut result = Self::zero();
for i in 0..N {
result[(i, i)] = T::one();
}
return result;
}
}
impl<T: Copy, const M: usize, const N: usize> Matrix<T, M, N> {
#[must_use]
pub fn mat(data: [[T; N]; M]) -> Self {
assert!(M > 0, "Matrix must have at least 1 row");
assert!(N > 0, "Matrix must have at least 1 column");
Matrix::<T, M, N> { data }
}
#[must_use]
pub fn fill(scalar: T) -> Matrix<T, M, N> {
assert!(M > 0, "Matrix must have at least 1 row");
assert!(N > 0, "Matrix must have at least 1 column");
Matrix::<T, M, N> {
data: [[scalar; N]; M],
}
}
#[must_use]
pub fn from_rows<I>(iter: I) -> Self
where
I: IntoIterator<Item = Vector<T, N>>,
Self: Default,
{
let mut result = Self::default();
for (m, row) in iter.into_iter().enumerate().take(M) {
result.set_row(m, &row)
}
result
}
#[must_use]
pub fn from_cols<I>(iter: I) -> Self
where
I: IntoIterator<Item = Vector<T, M>>,
Self: Default,
{
let mut result = Self::default();
for (n, col) in iter.into_iter().enumerate().take(N) {
result.set_col(n, &col)
}
result
}
}
impl<T: Copy, const N: usize> Vector<T, N> {
pub fn vec(data: [T; N]) -> Self {
assert!(N > 0, "Vector must have at least 1 element");
return Vector::<T, N> {
data: data.map(|e| [e]),
};
}
}
impl<T: Copy, const M: usize, const N: usize> Matrix<T, M, N> {
#[must_use]
pub fn elements<'s>(&'s self) -> impl Iterator<Item = &'s T> + 's {
self.data.iter().flatten()
}
#[must_use]
pub fn elements_mut<'s>(&'s mut self) -> impl Iterator<Item = &'s mut T> + 's {
self.data.iter_mut().flatten()
}
#[must_use]
pub fn diagonals<'s>(&'s self) -> impl Iterator<Item = &'s T> + 's {
(0..min(N, M)).map(|n| &self[(n, n)])
}
#[must_use]
pub fn subdiagonals<'s>(&'s self) -> impl Iterator<Item = &'s T> + 's {
(0..min(N, M - 1)).map(|n| &self[(n + 1, n)])
}
#[inline]
#[must_use]
pub fn get(&self, index: impl MatrixIndex) -> Option<&T> {
let (m, n) = index.to_2d(M, N)?;
Some(&self.data[m][n])
}
#[inline]
#[must_use]
pub fn get_mut(&mut self, index: impl MatrixIndex) -> Option<&mut T> {
let (m, n) = index.to_2d(M, N)?;
Some(&mut self.data[m][n])
}
#[inline]
#[must_use]
pub fn row(&self, m: usize) -> Vector<T, N> {
assert!(
m < M,
"Row index {} out of bounds for {}×{} matrix",
m,
M,
N
);
Vector::<T, N>::vec(self.data[m])
}
#[inline]
pub fn set_row(&mut self, m: usize, val: &Vector<T, N>) {
assert!(
m < M,
"Row index {} out of bounds for {}×{} matrix",
m,
M,
N
);
for n in 0..N {
self.data[m][n] = val.data[n][0];
}
}
#[inline]
#[must_use]
pub fn col(&self, n: usize) -> Vector<T, M> {
assert!(
n < N,
"Column index {} out of bounds for {}×{} matrix",
n,
M,
N
);
Vector::<T, M>::vec(self.data.map(|r| r[n]))
}
#[inline]
pub fn set_col(&mut self, n: usize, val: &Vector<T, M>) {
assert!(
n < N,
"Column index {} out of bounds for {}×{} matrix",
n,
M,
N
);
for m in 0..M {
self.data[m][n] = val.data[m][0];
}
}
#[must_use]
pub fn rows<'a>(&'a self) -> impl Iterator<Item = Vector<T, N>> + 'a {
(0..M).map(|m| self.row(m))
}
#[must_use]
pub fn cols<'a>(&'a self) -> impl Iterator<Item = Vector<T, M>> + 'a {
(0..N).map(|n| self.col(n))
}
pub fn pivot_row(&mut self, m1: usize, m2: usize) {
let tmp = self.row(m2);
self.set_row(m2, &self.row(m1));
self.set_row(m1, &tmp);
}
pub fn pivot_col(&mut self, n1: usize, n2: usize) {
let tmp = self.col(n2);
self.set_col(n2, &self.col(n1));
self.set_col(n1, &tmp);
}
#[must_use]
pub fn permute_rows<const P: usize>(&self, ms: &Vector<usize, P>) -> Matrix<T, P, N>
where
T: Default,
{
Matrix::<T, P, N>::from_rows(ms.elements().map(|&m| self.row(m)))
}
#[must_use]
pub fn permute_cols<const P: usize>(&self, ns: &Vector<usize, P>) -> Matrix<T, M, P>
where
T: Default,
{
Matrix::<T, M, P>::from_cols(ns.elements().map(|&n| self.col(n)))
}
pub fn transpose(&self) -> Matrix<T, N, M>
where
Matrix<T, N, M>: Default,
{
Matrix::<T, N, M>::from_rows(self.cols())
}
}
impl<I, T, const M: usize, const N: usize> Index<I> for Matrix<T, M, N>
where
I: MatrixIndex,
T: Copy,
{
type Output = T;
#[inline(always)]
fn index(&self, index: I) -> &Self::Output {
self.get(index).expect(&*format!(
"index {:?} out of range for {}×{} Matrix",
index, M, N
))
}
}
impl<I, T, const M: usize, const N: usize> IndexMut<I> for Matrix<T, M, N>
where
I: MatrixIndex,
T: Copy,
{
#[inline(always)]
fn index_mut(&mut self, index: I) -> &mut Self::Output {
self.get_mut(index).expect(&*format!(
"index {:?} out of range for {}×{} Matrix",
index, M, N
))
}
}
impl<T: Copy, const M: usize, const N: usize> From<[[T; N]; M]> for Matrix<T, M, N> {
fn from(data: [[T; N]; M]) -> Self {
Self::mat(data)
}
}
impl<T: Copy, const M: usize> From<[T; M]> for Vector<T, M> {
fn from(data: [T; M]) -> Self {
Self::vec(data)
}
}
impl<T: Copy, const M: usize, const N: usize> From<T> for Matrix<T, M, N> {
fn from(scalar: T) -> Self {
Self::fill(scalar)
}
}
impl<T: Copy + Debug, const M: usize, const N: usize> Into<[[T; N]; M]> for Matrix<T, M, N> {
fn into(self) -> [[T; N]; M] {
self.rows()
.map(|row| row.into())
.collect_vec()
.try_into()
.unwrap()
}
}
impl<T: Copy + Debug, const M: usize> Into<[T; M]> for Vector<T, M> {
fn into(self) -> [T; M] {
self.elements().cloned().collect_vec().try_into().unwrap()
}
}
impl<T: Copy, const M: usize, const N: usize> IntoIterator for Matrix<T, M, N> {
type Item = T;
type IntoIter = Flatten<std::array::IntoIter<[T; N], M>>;
fn into_iter(self) -> Self::IntoIter {
self.data.into_iter().flatten()
}
}
impl<T: Copy, 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
}
}