#![allow(non_snake_case)]
use super::DenseMatrixSym2;
use crate::algebra::*;
impl<T> DenseMatrixSym2<T>
where
T: FloatT,
{
pub fn cholesky_2x2_explicit_factor(
&mut self,
A: &DenseMatrixSym2<T>,
) -> Result<(), DenseFactorizationError> {
let L = self;
let t = A[(0, 0)];
if t <= T::zero() {
return Err(DenseFactorizationError::Cholesky(1));
}
L[(0, 0)] = t.sqrt();
L[(1, 0)] = A[(1, 0)] / L[(0, 0)];
let t = A[(1, 1)] - L[(1, 0)] * L[(1, 0)];
if t <= T::zero() {
return Err(DenseFactorizationError::Cholesky(2));
}
L[(1, 1)] = t.sqrt();
Ok(())
}
pub fn cholesky_2x2_explicit_solve(&self, x: &mut [T], b: &[T]) {
let L = self;
let c0 = b[0] / L[(0, 0)];
let c1 = (b[1] - L[(1, 0)] * c0) / L[(1, 1)];
x[1] = c1 / L[(1, 1)];
x[0] = (c0 - L[(1, 0)] * x[1]) / L[(0, 0)];
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::algebra::*;
#[test]
fn test_cholesky_2x2() {
let As = DenseMatrixSym2 {
data: [4.0, -2.0, 6.0],
};
let xtrue = vec![1.0, 2.0];
let mut b = vec![0.0; 3];
As.mul(&mut b, &xtrue);
let mut L = DenseMatrixSym2::zeros();
L.cholesky_2x2_explicit_factor(&As).unwrap();
let mut Lfull: Matrix<f64> = L.clone().into();
Lfull[(0, 1)] = 0.0;
let mut M = Matrix::zeros((2, 2));
M.mul(&Lfull, &Lfull.t(), 1.0, 0.0);
let mut xsolve = vec![0.0; 2];
L.cholesky_2x2_explicit_solve(&mut xsolve, &b);
assert!(xsolve.norm_inf_diff(&xtrue) < 1e-10);
}
}