use crate::core::Expression;
use crate::matrices::types::*;
use crate::matrices::unified::Matrix;
use crate::simplify::Simplify;
impl Matrix {
pub fn lu_decomposition(&self) -> Option<LUDecomposition> {
let (rows, cols) = self.dimensions();
if rows != cols {
return None; }
match self {
Matrix::Identity(data) => Some(LUDecomposition {
l: Matrix::identity(data.size),
u: Matrix::identity(data.size),
p: Some(Matrix::identity(data.size)),
}),
Matrix::Zero(_) => Some(LUDecomposition {
l: Matrix::identity(rows),
u: Matrix::zero(rows, cols),
p: Some(Matrix::identity(rows)),
}),
Matrix::Diagonal(_) => Some(LUDecomposition {
l: Matrix::identity(rows),
u: self.clone(),
p: Some(Matrix::identity(rows)),
}),
Matrix::UpperTriangular(_) => Some(LUDecomposition {
l: Matrix::identity(rows),
u: self.clone(),
p: Some(Matrix::identity(rows)),
}),
_ => {
self.general_lu_decomposition()
}
}
}
fn general_lu_decomposition(&self) -> Option<LUDecomposition> {
let (n, _) = self.dimensions();
let mut a = self.to_dense_matrix();
let mut p = Matrix::identity(n);
for k in 0..n {
let mut pivot_row = k;
for i in (k + 1)..n {
let current_elem = a.get_element(i, k);
let pivot_elem = a.get_element(pivot_row, k);
if !current_elem.is_zero() && pivot_elem.is_zero() {
pivot_row = i;
}
}
if pivot_row != k {
a = a.swap_rows(k, pivot_row);
p = p.swap_rows(k, pivot_row);
}
let pivot = a.get_element(k, k);
if pivot.is_zero() {
continue; }
for i in (k + 1)..n {
let factor = Expression::mul(vec![
a.get_element(i, k),
Expression::pow(pivot.clone(), Expression::integer(-1)),
])
.simplify();
a = a.set_element(i, k, &factor);
for j in (k + 1)..n {
let old_val = a.get_element(i, j);
let pivot_val = a.get_element(k, j);
let new_val = Expression::add(vec![
old_val,
Expression::mul(vec![Expression::integer(-1), factor.clone(), pivot_val]),
])
.simplify();
a = a.set_element(i, j, &new_val);
}
}
}
let mut l_elements = Vec::new();
let mut u_elements = Vec::new();
for i in 0..n {
let mut l_row = Vec::new();
let mut u_row = Vec::new();
for j in 0..n {
if i > j {
l_row.push(a.get_element(i, j));
u_row.push(Expression::integer(0));
} else if i == j {
l_row.push(Expression::integer(1));
u_row.push(a.get_element(i, j));
} else {
l_row.push(Expression::integer(0));
u_row.push(a.get_element(i, j));
}
}
l_elements.push(l_row);
u_elements.push(u_row);
}
Some(LUDecomposition {
l: Matrix::dense(l_elements),
u: Matrix::dense(u_elements),
p: Some(p),
})
}
}