use core::ops::{Add, AddAssign, Index, IndexMut, Mul, Neg, Sub, SubAssign};
use crate::linear_algebra::Vector;
use crate::scalar::Numeric;
use crate::utils::error_codes::CalcError;
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq)]
#[must_use]
pub struct Matrix<const ROWS: usize, const COLS: usize, T = f64> {
data: [[T; COLS]; ROWS],
}
impl<const ROWS: usize, const COLS: usize, T> Matrix<ROWS, COLS, T> {
#[inline]
pub const fn new(data: [[T; COLS]; ROWS]) -> Self {
Matrix { data }
}
#[inline]
pub fn from_fn(mut f: impl FnMut(usize, usize) -> T) -> Self {
Matrix {
data: core::array::from_fn(|r| core::array::from_fn(|c| f(r, c))),
}
}
#[inline]
#[must_use]
pub const fn as_slice_rows(&self) -> &[[T; COLS]; ROWS] {
&self.data
}
#[inline]
#[must_use]
pub fn into_array(self) -> [[T; COLS]; ROWS] {
self.data
}
}
impl<const ROWS: usize, const COLS: usize, T: Copy> Matrix<ROWS, COLS, T> {
#[inline]
#[must_use]
pub fn try_from_row_slice(slice: &[T]) -> Option<Self> {
(slice.len() == ROWS * COLS).then(|| Self::from_fn(|r, c| slice[r * COLS + c]))
}
#[inline]
pub fn row(&self, r: usize) -> Vector<COLS, T> {
Vector::new(self.data[r])
}
#[inline]
pub fn column(&self, c: usize) -> Vector<ROWS, T> {
Vector::from_fn(|r| self.data[r][c])
}
}
impl<const ROWS: usize, const COLS: usize, T: Numeric> Matrix<ROWS, COLS, T> {
#[inline]
pub fn zeros() -> Self {
Matrix::from_fn(|_, _| T::ZERO)
}
#[inline]
pub fn scale(self, scalar: T) -> Self {
Matrix::from_fn(|r, c| self[(r, c)] * scalar)
}
#[inline]
pub fn transpose(self) -> Matrix<COLS, ROWS, T> {
Matrix::from_fn(|r, c| self[(c, r)])
}
}
impl<const N: usize, T: Numeric> Matrix<N, N, T> {
#[inline]
pub fn identity() -> Self {
Matrix::from_fn(|r, c| if r == c { T::ONE } else { T::ZERO })
}
}
impl<const ROWS: usize, const COLS: usize, T> From<[[T; COLS]; ROWS]> for Matrix<ROWS, COLS, T> {
#[inline]
fn from(data: [[T; COLS]; ROWS]) -> Self {
Matrix { data }
}
}
impl<const ROWS: usize, const COLS: usize, T> Index<(usize, usize)> for Matrix<ROWS, COLS, T> {
type Output = T;
#[inline]
fn index(&self, (row, col): (usize, usize)) -> &T {
&self.data[row][col]
}
}
impl<const ROWS: usize, const COLS: usize, T> IndexMut<(usize, usize)> for Matrix<ROWS, COLS, T> {
#[inline]
fn index_mut(&mut self, (row, col): (usize, usize)) -> &mut T {
&mut self.data[row][col]
}
}
impl<const ROWS: usize, const COLS: usize, T: Numeric> Add for Matrix<ROWS, COLS, T> {
type Output = Self;
#[inline]
fn add(self, rhs: Self) -> Self {
Matrix::from_fn(|r, c| self[(r, c)] + rhs[(r, c)])
}
}
impl<const ROWS: usize, const COLS: usize, T: Numeric> AddAssign for Matrix<ROWS, COLS, T> {
#[inline]
fn add_assign(&mut self, rhs: Self) {
for (row, rhs_row) in self.data.iter_mut().zip(&rhs.data) {
for (a, &b) in row.iter_mut().zip(rhs_row) {
*a += b;
}
}
}
}
impl<const ROWS: usize, const COLS: usize, T: Numeric> Sub for Matrix<ROWS, COLS, T> {
type Output = Self;
#[inline]
fn sub(self, rhs: Self) -> Self {
Matrix::from_fn(|r, c| self[(r, c)] - rhs[(r, c)])
}
}
impl<const ROWS: usize, const COLS: usize, T: Numeric> SubAssign for Matrix<ROWS, COLS, T> {
#[inline]
fn sub_assign(&mut self, rhs: Self) {
for (row, rhs_row) in self.data.iter_mut().zip(&rhs.data) {
for (a, &b) in row.iter_mut().zip(rhs_row) {
*a -= b;
}
}
}
}
impl<const ROWS: usize, const COLS: usize, T: Numeric> Neg for Matrix<ROWS, COLS, T> {
type Output = Self;
#[inline]
fn neg(self) -> Self {
Matrix::from_fn(|r, c| -self[(r, c)])
}
}
impl<const ROWS: usize, const COLS: usize, T: Numeric> Mul<T> for Matrix<ROWS, COLS, T> {
type Output = Self;
#[inline]
fn mul(self, scalar: T) -> Self {
self.scale(scalar)
}
}
impl<const ROWS: usize, const COLS: usize, const C2: usize, T: Numeric> Mul<Matrix<COLS, C2, T>>
for Matrix<ROWS, COLS, T>
{
type Output = Matrix<ROWS, C2, T>;
#[inline]
fn mul(self, rhs: Matrix<COLS, C2, T>) -> Matrix<ROWS, C2, T> {
Matrix::from_fn(|r, c| {
let mut acc = T::ZERO;
for k in 0..COLS {
acc += self[(r, k)] * rhs[(k, c)];
}
acc
})
}
}
impl<const ROWS: usize, const COLS: usize, T: Numeric> Mul<Vector<COLS, T>>
for Matrix<ROWS, COLS, T>
{
type Output = Vector<ROWS, T>;
#[inline]
fn mul(self, rhs: Vector<COLS, T>) -> Vector<ROWS, T> {
Vector::from_fn(|r| self.row(r).dot(rhs))
}
}
impl<T: Numeric> Matrix<2, 2, T> {
#[inline]
#[must_use]
pub fn determinant(self) -> T {
self[(0, 0)] * self[(1, 1)] - self[(0, 1)] * self[(1, 0)]
}
#[inline]
pub fn inverse(self) -> Result<Self, CalcError> {
let det = self.determinant();
if det == T::ZERO {
return Err(CalcError::SingularMatrix);
}
let inv = T::ONE / det;
let m = self;
Ok(Matrix::new([
[m[(1, 1)] * inv, -m[(0, 1)] * inv],
[-m[(1, 0)] * inv, m[(0, 0)] * inv],
]))
}
}
impl<T: Numeric> Matrix<3, 3, T> {
#[inline]
#[must_use]
pub fn determinant(self) -> T {
let m = self;
m[(0, 0)] * (m[(1, 1)] * m[(2, 2)] - m[(1, 2)] * m[(2, 1)])
- m[(0, 1)] * (m[(1, 0)] * m[(2, 2)] - m[(1, 2)] * m[(2, 0)])
+ m[(0, 2)] * (m[(1, 0)] * m[(2, 1)] - m[(1, 1)] * m[(2, 0)])
}
#[inline]
pub fn inverse(self) -> Result<Self, CalcError> {
let det = self.determinant();
if det == T::ZERO {
return Err(CalcError::SingularMatrix);
}
let inv = T::ONE / det;
let m = self;
Ok(Matrix::new([
[
(m[(1, 1)] * m[(2, 2)] - m[(1, 2)] * m[(2, 1)]) * inv,
(m[(0, 2)] * m[(2, 1)] - m[(0, 1)] * m[(2, 2)]) * inv,
(m[(0, 1)] * m[(1, 2)] - m[(0, 2)] * m[(1, 1)]) * inv,
],
[
(m[(1, 2)] * m[(2, 0)] - m[(1, 0)] * m[(2, 2)]) * inv,
(m[(0, 0)] * m[(2, 2)] - m[(0, 2)] * m[(2, 0)]) * inv,
(m[(0, 2)] * m[(1, 0)] - m[(0, 0)] * m[(1, 2)]) * inv,
],
[
(m[(1, 0)] * m[(2, 1)] - m[(1, 1)] * m[(2, 0)]) * inv,
(m[(0, 1)] * m[(2, 0)] - m[(0, 0)] * m[(2, 1)]) * inv,
(m[(0, 0)] * m[(1, 1)] - m[(0, 1)] * m[(1, 0)]) * inv,
],
]))
}
}
impl<T: Numeric> Matrix<4, 4, T> {
#[inline]
fn row_pair_minors(self) -> ([T; 6], [T; 6]) {
let m = self;
let s = [
m[(0, 0)] * m[(1, 1)] - m[(0, 1)] * m[(1, 0)],
m[(0, 0)] * m[(1, 2)] - m[(0, 2)] * m[(1, 0)],
m[(0, 0)] * m[(1, 3)] - m[(0, 3)] * m[(1, 0)],
m[(0, 1)] * m[(1, 2)] - m[(0, 2)] * m[(1, 1)],
m[(0, 1)] * m[(1, 3)] - m[(0, 3)] * m[(1, 1)],
m[(0, 2)] * m[(1, 3)] - m[(0, 3)] * m[(1, 2)],
];
let c = [
m[(2, 0)] * m[(3, 1)] - m[(2, 1)] * m[(3, 0)],
m[(2, 0)] * m[(3, 2)] - m[(2, 2)] * m[(3, 0)],
m[(2, 0)] * m[(3, 3)] - m[(2, 3)] * m[(3, 0)],
m[(2, 1)] * m[(3, 2)] - m[(2, 2)] * m[(3, 1)],
m[(2, 1)] * m[(3, 3)] - m[(2, 3)] * m[(3, 1)],
m[(2, 2)] * m[(3, 3)] - m[(2, 3)] * m[(3, 2)],
];
(s, c)
}
#[inline]
#[must_use]
pub fn determinant(self) -> T {
let (s, c) = self.row_pair_minors();
s[0] * c[5] - s[1] * c[4] + s[2] * c[3] + s[3] * c[2] - s[4] * c[1] + s[5] * c[0]
}
#[inline]
pub fn inverse(self) -> Result<Self, CalcError> {
let (s, c) = self.row_pair_minors();
let det = s[0] * c[5] - s[1] * c[4] + s[2] * c[3] + s[3] * c[2] - s[4] * c[1] + s[5] * c[0];
if det == T::ZERO {
return Err(CalcError::SingularMatrix);
}
let inv = T::ONE / det;
let m = self;
Ok(Matrix::new([
[
(m[(1, 1)] * c[5] - m[(1, 2)] * c[4] + m[(1, 3)] * c[3]) * inv,
(-m[(0, 1)] * c[5] + m[(0, 2)] * c[4] - m[(0, 3)] * c[3]) * inv,
(m[(3, 1)] * s[5] - m[(3, 2)] * s[4] + m[(3, 3)] * s[3]) * inv,
(-m[(2, 1)] * s[5] + m[(2, 2)] * s[4] - m[(2, 3)] * s[3]) * inv,
],
[
(-m[(1, 0)] * c[5] + m[(1, 2)] * c[2] - m[(1, 3)] * c[1]) * inv,
(m[(0, 0)] * c[5] - m[(0, 2)] * c[2] + m[(0, 3)] * c[1]) * inv,
(-m[(3, 0)] * s[5] + m[(3, 2)] * s[2] - m[(3, 3)] * s[1]) * inv,
(m[(2, 0)] * s[5] - m[(2, 2)] * s[2] + m[(2, 3)] * s[1]) * inv,
],
[
(m[(1, 0)] * c[4] - m[(1, 1)] * c[2] + m[(1, 3)] * c[0]) * inv,
(-m[(0, 0)] * c[4] + m[(0, 1)] * c[2] - m[(0, 3)] * c[0]) * inv,
(m[(3, 0)] * s[4] - m[(3, 1)] * s[2] + m[(3, 3)] * s[0]) * inv,
(-m[(2, 0)] * s[4] + m[(2, 1)] * s[2] - m[(2, 3)] * s[0]) * inv,
],
[
(-m[(1, 0)] * c[3] + m[(1, 1)] * c[1] - m[(1, 2)] * c[0]) * inv,
(m[(0, 0)] * c[3] - m[(0, 1)] * c[1] + m[(0, 2)] * c[0]) * inv,
(-m[(3, 0)] * s[3] + m[(3, 1)] * s[1] - m[(3, 2)] * s[0]) * inv,
(m[(2, 0)] * s[3] - m[(2, 1)] * s[1] + m[(2, 2)] * s[0]) * inv,
],
]))
}
}