use core::f32;
use std::{
fmt::{Debug, Display, Formatter, Result},
ops::{Mul, MulAssign},
};
use crate::base::Vector;
#[repr(transparent)]
#[derive(Copy, Clone, PartialEq)]
pub struct Matrix {
rows: [Vector; 4],
}
impl Debug for Matrix {
#[inline(always)]
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
write!(
f,
"{}, {}, {}, {}",
self.get_row(0),
self.get_row(1),
self.get_row(2),
self.get_row(3)
)
}
}
impl Default for Matrix {
#[inline(always)]
fn default() -> Self { Matrix::identity() }
}
impl Display for Matrix {
#[inline(always)]
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
write!(
f,
"{}, {}, {}, {}",
self.get_row(0),
self.get_row(1),
self.get_row(2),
self.get_row(3)
)
}
}
impl Mul for Matrix {
type Output = Self;
#[inline(always)]
fn mul(self, rhs: Self) -> Self {
let mut rows = [Vector::default(); 4];
for i in 0..4 {
rows[i] = rhs.rows[0] * self.rows[i].shuffle::<0, 0, 0, 0>()
+ rhs.rows[1] * self.rows[i].shuffle::<1, 1, 1, 1>()
+ rhs.rows[2] * self.rows[i].shuffle::<2, 2, 2, 2>()
+ rhs.rows[3] * self.rows[i].shuffle::<3, 3, 3, 3>()
}
Self { rows }
}
}
impl MulAssign for Matrix {
#[inline(always)]
fn mul_assign(&mut self, rhs: Self) { *self = *self * rhs; }
}
impl Matrix {
#[inline(always)]
pub fn rows(rows: [[f32; 4]; 4]) -> Self {
Self {
rows: [
Vector::new(rows[0][0], rows[0][1], rows[0][2], rows[0][3]),
Vector::new(rows[1][0], rows[1][1], rows[1][2], rows[1][3]),
Vector::new(rows[2][0], rows[2][1], rows[2][2], rows[2][3]),
Vector::new(rows[3][0], rows[3][1], rows[3][2], rows[3][3]),
],
}
}
#[inline(always)]
pub fn row_vectors(rows: [Vector; 4]) -> Self { Self { rows } }
#[inline(always)]
pub fn identity() -> Self {
Self {
rows: [
Vector::new(1f32, 0f32, 0f32, 0f32),
Vector::new(0f32, 1f32, 0f32, 0f32),
Vector::new(0f32, 0f32, 1f32, 0f32),
Vector::new(0f32, 0f32, 0f32, 1f32),
],
}
}
#[inline(always)]
pub fn transpose(&self) -> Matrix {
let temp = [
Vector::shuffle_merge::<0, 1, 0, 1>(self.rows[0], self.rows[1]),
Vector::shuffle_merge::<2, 3, 2, 3>(self.rows[0], self.rows[1]),
Vector::shuffle_merge::<0, 1, 0, 1>(self.rows[2], self.rows[3]),
Vector::shuffle_merge::<2, 3, 2, 3>(self.rows[2], self.rows[3]),
];
Self {
rows: [
Vector::shuffle_merge::<0, 2, 0, 2>(temp[0], temp[2]),
Vector::shuffle_merge::<1, 3, 1, 3>(temp[0], temp[2]),
Vector::shuffle_merge::<0, 2, 0, 2>(temp[1], temp[3]),
Vector::shuffle_merge::<1, 3, 1, 3>(temp[1], temp[3]),
],
}
}
#[inline(always)]
pub fn det(&self) -> f32 {
let a = Vector::shuffle_merge::<0, 1, 0, 1>(self.rows[0], self.rows[1]);
let c = Vector::shuffle_merge::<2, 3, 2, 3>(self.rows[0], self.rows[1]);
let b = Vector::shuffle_merge::<0, 1, 0, 1>(self.rows[2], self.rows[3]);
let d = Vector::shuffle_merge::<2, 3, 2, 3>(self.rows[2], self.rows[3]);
let det_sub = Vector::shuffle_merge::<0, 2, 0, 2>(self.rows[0], self.rows[2])
* Vector::shuffle_merge::<1, 3, 1, 3>(self.rows[1], self.rows[3])
- Vector::shuffle_merge::<1, 3, 1, 3>(self.rows[0], self.rows[2])
* Vector::shuffle_merge::<0, 2, 0, 2>(self.rows[1], self.rows[3]);
let det_a = det_sub.shuffle::<0, 0, 0, 0>();
let det_c = det_sub.shuffle::<1, 1, 1, 1>();
let det_b = det_sub.shuffle::<2, 2, 2, 2>();
let det_d = det_sub.shuffle::<3, 3, 3, 3>();
let d_c = mat2_adj_mul(d, c);
let a_b = mat2_adj_mul(a, b);
let tr = a_b * d_c.shuffle::<0, 2, 1, 3>();
let tr = tr.hsum();
((det_a * det_d + det_b * det_c) - Vector::new(tr, tr, tr, tr)).x()
}
#[inline(always)]
pub fn inverse(&self) -> Matrix {
let a = Vector::shuffle_merge::<0, 1, 0, 1>(self.rows[0], self.rows[1]);
let c = Vector::shuffle_merge::<2, 3, 2, 3>(self.rows[0], self.rows[1]);
let b = Vector::shuffle_merge::<0, 1, 0, 1>(self.rows[2], self.rows[3]);
let d = Vector::shuffle_merge::<2, 3, 2, 3>(self.rows[2], self.rows[3]);
let det_sub = Vector::shuffle_merge::<0, 2, 0, 2>(self.rows[0], self.rows[2])
* Vector::shuffle_merge::<1, 3, 1, 3>(self.rows[1], self.rows[3])
- Vector::shuffle_merge::<1, 3, 1, 3>(self.rows[0], self.rows[2])
* Vector::shuffle_merge::<0, 2, 0, 2>(self.rows[1], self.rows[3]);
let det_a = det_sub.shuffle::<0, 0, 0, 0>();
let det_c = det_sub.shuffle::<1, 1, 1, 1>();
let det_b = det_sub.shuffle::<2, 2, 2, 2>();
let det_d = det_sub.shuffle::<3, 3, 3, 3>();
let d_c = mat2_adj_mul(d, c);
let a_b = mat2_adj_mul(a, b);
let x_ = det_d * a - mat2_mul(b, d_c);
let w_ = det_a * d - mat2_mul(c, a_b);
let y_ = det_b * c - mat2_mul_adj(d, a_b);
let z_ = det_c * b - mat2_mul_adj(a, d_c);
let tr = a_b * d_c.shuffle::<0, 2, 1, 3>();
let tr = tr.hsum();
let det_m = (det_a * det_d + det_b * det_c) - Vector::new(tr, tr, tr, tr);
let r_det_m = Vector::new(1f32, -1f32, -1f32, 1f32) / det_m;
let x = x_ * r_det_m;
let y = y_ * r_det_m;
let z = z_ * r_det_m;
let w = w_ * r_det_m;
Self {
rows: [
Vector::shuffle_merge::<3, 1, 3, 1>(x, z),
Vector::shuffle_merge::<2, 0, 2, 0>(x, z),
Vector::shuffle_merge::<3, 1, 3, 1>(y, w),
Vector::shuffle_merge::<2, 0, 2, 0>(y, w),
],
}
}
#[inline(always)]
pub fn get_row(&self, idx: u8) -> Vector { self.rows[idx as usize] }
#[inline(always)]
pub fn get_column(&self, idx: u8) -> Vector {
Vector::new(
self.rows[0].get(idx),
self.rows[1].get(idx),
self.rows[2].get(idx),
self.rows[3].get(idx),
)
}
}
#[inline(always)]
fn mat2_mul(vec1: Vector, vec2: Vector) -> Vector {
vec1 * vec2.shuffle::<0, 0, 3, 3>() + vec1.shuffle::<2, 3, 0, 1>() + vec2.shuffle::<1, 1, 2, 2>()
}
#[inline(always)]
fn mat2_adj_mul(vec1: Vector, vec2: Vector) -> Vector {
vec1.shuffle::<3, 0, 3, 0>() * vec2 - vec1.shuffle::<2, 1, 2, 1>() * vec2.shuffle::<1, 0, 3, 2>()
}
#[inline(always)]
fn mat2_mul_adj(vec1: Vector, vec2: Vector) -> Vector {
vec1 * vec2.shuffle::<3, 3, 0, 0>() - vec1.shuffle::<2, 3, 0, 1>() * vec2.shuffle::<1, 1, 2, 2>()
}
mod tests {
#[allow(unused_imports)] use super::*;
#[test]
fn multiply() {
let mat = Matrix::rows([
[1f32, 2f32, 3f32, 4f32],
[5f32, 6f32, 7f32, 8f32],
[9f32, 10f32, 11f32, 12f32],
[13f32, 14f32, 15f32, 16f32],
]);
assert_eq!(
mat * mat,
Matrix::rows([
[90f32, 100f32, 110f32, 120f32],
[202f32, 228f32, 254f32, 280f32],
[314f32, 356f32, 398f32, 440f32],
[426f32, 484f32, 542f32, 600f32],
])
);
}
#[test]
fn transpose() {
assert_eq!(
Matrix::rows([
[1f32, 2f32, 3f32, 4f32],
[5f32, 6f32, 7f32, 8f32],
[9f32, 10f32, 11f32, 12f32],
[13f32, 14f32, 15f32, 16f32],
])
.transpose(),
Matrix::rows([
[1f32, 5f32, 9f32, 13f32],
[2f32, 6f32, 10f32, 14f32],
[3f32, 7f32, 11f32, 15f32],
[4f32, 8f32, 12f32, 16f32],
])
)
}
#[test]
fn inverse() {
let mat = Matrix::rows([
[2f32, 0f32, 0f32, 0f32],
[0f32, 2f32, 0f32, 0f32],
[0f32, 0f32, 2f32, 0f32],
[0f32, 0f32, 0f32, 1f32],
]);
assert_eq!(mat * mat.inverse(), Matrix::default())
}
}