use crate::algebra::abstr::{AbsDiffEq, RelativeEq};
use crate::algebra::abstr::{Field, Scalar};
use crate::algebra::linear::matrix::substitute::SubstituteBackward;
use crate::algebra::linear::{
matrix::{General, UpperTriangular},
vector::Vector,
};
use crate::relative_eq;
impl<T> SubstituteBackward<Vector<T>> for UpperTriangular<T>
where
T: Field + Scalar + AbsDiffEq<Epsilon = T> + RelativeEq,
{
fn substitute_backward(&self, mut c: Vector<T>) -> Result<Vector<T>, ()> {
let rows = self.matrix.nrows();
for k in (0..rows).rev() {
for l in (k + 1..rows).rev() {
c[k] = c[k] - self[[k, l]] * c[l];
}
let div = c[k] / self[[k, k]];
if div.to_f64().is_finite() {
c[k] = div;
} else if !relative_eq!(c[k], T::from_f64(0.000000000001) * T::default_epsilon()) {
return Err(());
} else {
c[k] = T::one();
}
}
Ok(c)
}
}
impl<T> SubstituteBackward<General<T>> for UpperTriangular<T>
where
T: Field + Scalar,
{
fn substitute_backward(&self, mut c: General<T>) -> Result<General<T>, ()> {
let (rows, cols) = c.dim();
for j in 0..cols {
for k in (0..rows).rev() {
for i in (k + 1..rows).rev() {
c[[k, j]] = c[[k, j]] - c[[i, j]] * self[[k, i]];
}
c[[k, j]] /= self[[k, k]];
}
}
Ok(c)
}
}