use crate::error::IError;
use crate::error::IResult;
use crate::matrix::Matrix;
use crate::num::number::Fractional;
use crate::num::number::Number;
use crate::utils::predicate::is_upper_triangle_matrix;
use crate::vector::euclid_norm;
use crate::vector::identity_vector_column;
use crate::vector::times_d;
use crate::vector::times_v;
use crate::vector::ColumnVector;
pub fn plu_decomposition<T>(mat: Matrix<T>) -> IResult<(Matrix<T>, Matrix<T>, Matrix<T>)>
where
T: Number,
{
let eliminates = mat.row_eliminate()?;
if eliminates.2.get_diag()?.iter().any(|e| e.is_zero()) {
Err(IError::SingularMatrix)
} else {
let (p, l, _, _) = eliminates.0.times(eliminates.1)?.row_eliminate()?;
Ok((p, l, eliminates.2))
}
}
pub fn qr_decomposition<T>(mat: Matrix<T>) -> IResult<(Matrix<T>, Matrix<T>)>
where
T: Fractional + std::cmp::PartialOrd,
{
let mrow = mat.row();
let mcol = mat.column();
let mut q = Matrix::eyes(mrow, mrow)?;
let mut r = mat.clone();
let two = T::one() + T::one();
for index in 1..=mcol.min(mrow) {
let mut an = r.get_col(index)?.map(&mut |e| e.clone())?;
let ann = r.get_element(index, index)?.clone();
for row in 1..=((index - 1).min(mrow)) {
an.set_element(row, 1, T::zero())?;
}
let an_norm = euclid_norm(an.clone())?;
let vn = an.clone().plus(
identity_vector_column(mrow, index)?
.muls(an_norm.clone())?
.muls(if ann < T::zero() { -T::one() } else { T::one() })?,
)?;
let hn = Matrix::eyes(mrow, mrow)?.subtract(
times_v(vn.clone(), vn.conjugate_transpose()?)?
.muls(two.clone().ndiv(times_d(vn.conjugate_transpose()?, vn)?)?)?,
)?;
q = hn.clone().times(q)?;
r = hn.times(r)?;
if is_upper_triangle_matrix(&r) {
break;
}
}
Ok((q, r))
}
pub fn qr_decomposition_reduced<T>(mat: Matrix<T>) -> IResult<(Matrix<T>, Matrix<T>)>
where
T: Clone + Fractional + std::cmp::PartialOrd,
{
let (q, r) = qr_decomposition(mat)?;
let mut reduced_r = Matrix::zeros(r.rank()?, r.column())?;
let mut reduced_q = Matrix::zeros(reduced_r.row(), q.column())?;
for row in 1..=reduced_r.row() {
for col in 1..=reduced_r.column() {
reduced_r.set_element(row, col, r.get_element(row, col)?.clone())?;
}
for col in 1..=reduced_q.column() {
reduced_q.set_element(row, col, q.get_element(row, col)?.clone())?;
}
}
Ok((reduced_q, reduced_r))
}
pub fn qr_decomposition_gs<T>(mat: Matrix<T>) -> IResult<(Matrix<T>, Matrix<T>)>
where
T: Fractional,
{
let mrow = mat.row();
let mcol = mat.column();
let mut an = Vec::with_capacity(mcol);
for col in 1..=mcol {
an.push(mat.get_col(col)?);
}
let mut un: Vec<ColumnVector<T>> = Vec::with_capacity(mcol);
let mut en: Vec<ColumnVector<T>> = Vec::with_capacity(mcol);
for col in 1..=mcol {
let ai = match an.get(col - 1) {
Some(element) => Ok(element),
None => Err(IError::Message(format!(
"read index {} out of boundary",
col
))),
}?
.clone()
.map(&mut |e| e.clone())?;
let mut ui = ai.clone();
for index in 1..=(col - 1) {
let ek = match en.get(index - 1) {
Some(element) => Ok(element),
None => Err(IError::Message(format!(
"read index {} out of boundary",
index
))),
}?
.clone()
.map(&mut |e| e.clone())?;
ui = ui.subtract(
ek.clone()
.muls(times_d(ai.clone().conjugate_transpose()?, ek)?)?,
)?;
}
un.push(ui.clone());
let norm = euclid_norm(ui.clone())?;
let ei = ui.divs(norm)?;
en.push(ei);
}
let mut q = Matrix::zeros(mrow, mcol)?;
let mut r = Matrix::zeros(mcol, mcol)?;
for row in 1..=mrow {
for col in 1..=mcol {
let ei = match en.get(col - 1) {
Some(element) => Ok(element),
None => Err(IError::Message(format!(
"read index {} out of boundary",
col
))),
}?
.clone();
q.set_element(row, col, ei.get_element(row, 1)?.clone().clone())?;
}
}
for col1 in 1..=mcol {
let ei = match en.get(col1 - 1) {
Some(element) => Ok(element),
None => Err(IError::Message(format!(
"read index {} out of boundary",
col1
))),
}?
.clone()
.map(&mut |e| e.clone())?;
for col2 in col1..=mcol {
let ai = match an.get(col2 - 1) {
Some(element) => Ok(element),
None => Err(IError::Message(format!(
"read index {} out of boundary",
col2
))),
}?
.clone()
.map(&mut |e| e.clone())?;
r.set_element(col1, col2, times_d(ai.conjugate_transpose()?, ei.clone())?)?;
}
}
Ok((q, r))
}