use std::fmt::Debug;
use std::ops::{Div, Mul, Sub};
use conv::{ConvUtil, ValueFrom};
use crate::prelude::Matrix;
use itertools::Itertools;
pub trait LUDecompose {
fn lu_decompose(&self) -> Option<(Self, Self)> where Self: Sized;
}
impl<const T: usize, L: Copy + Debug> LUDecompose for Matrix<T, T, L> where L: ValueFrom<isize> + Div<Output=L> + Mul<Output=L> + Sub<Output=L> + PartialEq {
fn lu_decompose(&self) -> Option<(Self, Self)> {
let mut upper = self.clone();
let mut lower = Self::empty();
for r in 0..T {
let scale = upper[(r, r)];
if scale == 0.value_as().unwrap() {
return None
}
for i in r..T {
lower[(i, r)] = upper[(i, r)]
}
for i in 0..T {
upper[(r, i)] = upper[(r, i)] / scale
}
for lower in r + 1..T {
let second_scale = upper[(lower, r)];
for col in r..T {
upper[(lower, col)] = upper[(lower, col)] - second_scale * upper[(r, col)]
}
}
}
Some((lower, upper))
}
}
pub trait PLUDecompose {
fn plu_decompose(&self) -> Option<(Self, Self, Self)> where Self: Sized;
}
impl<const T: usize, L: Copy + Debug> PLUDecompose for Matrix<T, T, L> where L: ValueFrom<isize> + Div<Output=L> + Mul<Output=L> + Sub<Output=L> + PartialEq {
fn plu_decompose(&self) -> Option<(Self, Self, Self)> {
for i in (0..T).permutations(T) {
let mut p_data = [[0.value_as::<L>().unwrap(); T]; T];
for (n, j) in i.iter().enumerate() {
p_data[n] = self.0[*j].clone()
}
if let Some((l, u)) = Matrix::new(p_data).lu_decompose() {
let mut permutation = Matrix::<T, T, L>::empty();
for (n, j) in i.iter().enumerate() {
permutation.0[n][*j] = 1.value_as().unwrap()
}
return Some((permutation, l, u))
}
}
None
}
}
#[doc(alias="Diagonalize")]
pub trait Diagonalise {
fn diagonalise(&self) -> Option<(Self, Self, Self)> where Self: Sized;
}