use crate::mat::SMatrix;
use num_traits::cast::ToPrimitive;
use num_traits::identities::{One, Zero};
use num_traits::sign::Signed;
use std::ops::{Add, Mul, Sub};
impl<T, const M: usize, const N: usize> SMatrix<T, M, N>
where
T: Copy,
{
pub fn new(init: T) -> SMatrix<T, M, N> {
if M > 0 && N > 0 {
SMatrix::<T, M, N> {
data: [[init; N]; M],
}
} else {
panic!("NOOO")
}
}
pub fn row_count(&self) -> usize {
M
}
pub fn col_count(&self) -> usize {
N
}
pub fn is_square(&self) -> bool {
M == N
}
pub fn transpose(&self) -> SMatrix<T, N, M>
where
T: Zero,
{
let mut res: SMatrix<T, N, M> = SMatrix::new(T::zero());
for i in 0..M {
for j in 0..N {
res[j][i] = self[i][j];
}
}
res
}
}
impl<T, const N: usize> SMatrix<T, N, N>
where
T: Sub<Output = T> + Add<Output = T> + Mul<Output = T> + ToPrimitive,
{
pub fn lupdecompose(&self) -> Option<(SMatrix<f64, N, N>, Vec<usize>)>
where
T: Signed,
{
let mut a: SMatrix<f64, N, N> = SMatrix::new(f64::default());
for rs in a.iter_mut() {
for es in rs.iter_mut() {
*es = es.to_f64().unwrap();
}
}
let dim = N;
let mut imax: usize;
let mut max_a: f64;
let mut p: Vec<usize> = (0..=dim).collect();
for i in 0..dim {
max_a = f64::default();
imax = i;
for k in i..dim {
if a[i][k].abs() > max_a {
max_a = a[i][k].abs();
imax = k;
}
}
if max_a < 0.000001 {
return None;
}
if imax != i {
let j = p[i];
p[i] = p[imax];
p[imax] = j;
let mut t_ij: SMatrix<f64, N, N> = SMatrix::one();
t_ij[i][i] = f64::zero();
t_ij[imax][imax] = f64::zero();
t_ij[i][imax] = f64::one();
t_ij[imax][i] = f64::one();
a = a * t_ij;
p[dim] += 1;
}
for j in (i + 1)..dim {
a[j][i] = a[j][i] / a[i][i];
for k in (i + 1)..dim {
a[j][k] = a[j][k] - a[j][i] * a[i][k];
}
}
}
Some((a, p))
}
fn det_approx(&self) -> f64
where
T: Signed,
{
if let Some((mat, p)) = self.lupdecompose() {
let mut det = mat[0][0];
for i in 1..N {
det = det * mat[i][i];
}
if (p[N] - N) % 2 == 0 {
det
} else {
-det
}
} else {
f64::zero()
}
}
pub fn det(&self) -> f64
where
T: Copy + Signed,
{
if N < 4 {
match {
if N == 1 {
self[0][0].to_f64()
} else if N == 2 {
{ self[0][0] * self[1][1] - self[0][1] * self[1][0] }.to_f64()
} else if N == 3 {
{
self[0][0] * self[1][1] * self[2][2]
+ self[1][0] * self[2][1] * self[0][2]
+ self[2][0] * self[0][1] * self[1][2]
- self[0][2] * self[1][1] * self[2][0]
- self[0][1] * self[1][0] * self[2][2]
- self[0][0] * self[1][2] * self[2][1]
}
.to_f64()
} else {
Some(f64::default())
}
} {
Some(n) => n,
None => f64::default(),
}
} else {
self.det_approx()
}
}
pub fn diag(init: T) -> SMatrix<T, N, N>
where
T: Copy + One + Zero,
{
SMatrix::<T, N, N>::one() * init
}
pub fn diag_with(entries: &[T]) -> SMatrix<T, N, N>
where
T: One + Copy + Zero,
{
if entries.len() > N || entries.len() < N {
panic!("Input slice does not have the correct length.");
}
let mut res: SMatrix<T, N, N> = SMatrix::one();
for i in 0..N {
res[i][i] = entries[i];
}
res
}
}