diff --git a/src/linalg/cholesky.rs b/src/linalg/cholesky.rs index 0b6e6db5..606434e9 100644 --- a/src/linalg/cholesky.rs +++ b/src/linalg/cholesky.rs @@ -6,28 +6,25 @@ use alga::general::ComplexField; use crate::allocator::Allocator; use crate::base::{DefaultAllocator, Matrix, MatrixMN, MatrixN, SquareMatrix}; use crate::constraint::{SameNumberOfRows, ShapeConstraint}; -use crate::dimension::{Dim, DimSub, Dynamic}; +use crate::dimension::{Dim, DimSub, Dynamic, U1}; use crate::storage::{Storage, StorageMut}; /// The Cholesky decomposition of a symmetric-definite-positive matrix. #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[cfg_attr( feature = "serde-serialize", - serde(bound( - serialize = "DefaultAllocator: Allocator, - MatrixN: Serialize" - )) + serde(bound(serialize = "DefaultAllocator: Allocator, + MatrixN: Serialize")) )] #[cfg_attr( feature = "serde-serialize", - serde(bound( - deserialize = "DefaultAllocator: Allocator, - MatrixN: Deserialize<'de>" - )) + serde(bound(deserialize = "DefaultAllocator: Allocator, + MatrixN: Deserialize<'de>")) )] #[derive(Clone, Debug)] pub struct Cholesky -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { chol: MatrixN, } @@ -36,10 +33,12 @@ impl Copy for Cholesky where DefaultAllocator: Allocator, MatrixN: Copy, -{} +{ +} impl> Cholesky -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { /// Attempts to compute the Cholesky decomposition of `matrix`. /// @@ -129,7 +128,7 @@ where DefaultAllocator: Allocator /// `x` the unknown. pub fn solve(&self, b: &Matrix) -> MatrixMN where - S2: StorageMut, + S2: Storage, DefaultAllocator: Allocator, ShapeConstraint: SameNumberOfRows, { @@ -146,10 +145,41 @@ where DefaultAllocator: Allocator self.solve_mut(&mut res); res } + + /// Performs a rank one update of the current decomposition. + /// If `M = L * L^T` before the rank one update, then after it we have `L*L^T = M + sigma * v*v^T` where v must be a vector of same dimension. + /// TODO rewrite comment (current version is taken verbatim from eigen) + /// TODO insures that code is correct for complex numbers, eigen uses abs2 and conj + /// https://eigen.tuxfamily.org/dox/LLT_8h_source.html + pub fn rank_one_update(&mut self, x: &Matrix, sigma: N) + where + S2: Storage, + DefaultAllocator: Allocator, + ShapeConstraint: SameNumberOfRows, + { + let n = x.nrows(); + let mut temp = x.clone_owned(); + for k in 0..n { + let lkk = self.chol[(k, k)]; // TODO unsafe { *matrix.get_unchecked((j, j)) } + let xk = temp[k]; + let r = (lkk * lkk + sigma * xk * xk).sqrt(); + let c = r / lkk; + let s = xk / lkk; + self.chol[(k, k)] = r; + // Update the terms of L + if k < n { + for k2 in (k + 1)..n { + self.chol[(k2, k)] = (self.chol[(k2, k)] + sigma * s * temp[k2]) / c; + temp[k2] = c * temp[k2] - s * self.chol[(k2, k)]; + } + } + } + } } impl, S: Storage> SquareMatrix -where DefaultAllocator: Allocator +where + DefaultAllocator: Allocator, { /// Attempts to compute the Cholesky decomposition of this matrix. ///