faer_precond/ic0/
numeric.rs1use faer::sparse::SparseColMatRef;
4use faer_traits::math_utils::{conj, copy, from_real, mul, real, recip, sqrt, sub, zero};
5use faer_traits::{ComplexField, Index};
6
7use super::Ic0Error;
8use super::symbolic::SymbolicIc0;
9
10#[derive(Debug, Clone)]
17pub struct Ic0<I, T> {
18 pub(crate) symbolic: SymbolicIc0<I>,
19 pub(crate) l_values: Vec<T>,
20 pub(crate) workspace_w: Vec<T>,
21 pub(crate) workspace_marker: Vec<usize>,
22}
23
24impl<I: Index, T: ComplexField> Ic0<I, T> {
25 pub fn new_with_symbolic(symbolic: SymbolicIc0<I>) -> Self {
30 let n = symbolic.dim;
31 let l_nnz = symbolic.l_nnz();
32 let l_values = (0..l_nnz).map(|_| zero::<T>()).collect();
33 let workspace_w = (0..n).map(|_| zero::<T>()).collect();
34 let workspace_marker = vec![usize::MAX; n];
35 Self {
36 symbolic,
37 l_values,
38 workspace_w,
39 workspace_marker,
40 }
41 }
42
43 pub fn try_new(a: SparseColMatRef<'_, I, T>) -> Result<Self, Ic0Error> {
49 let symbolic = SymbolicIc0::try_new(a.symbolic())?;
50 let mut me = Self::new_with_symbolic(symbolic);
51 me.refactorize(a)?;
52 Ok(me)
53 }
54
55 #[inline]
57 pub fn dim(&self) -> usize {
58 self.symbolic.dim
59 }
60
61 #[inline]
63 pub fn symbolic(&self) -> &SymbolicIc0<I> {
64 &self.symbolic
65 }
66
67 pub fn refactorize(&mut self, a: SparseColMatRef<'_, I, T>) -> Result<(), Ic0Error> {
80 let n = self.symbolic.dim;
81 if a.nrows() != n || a.ncols() != n {
82 return Err(Ic0Error::PatternMismatch);
83 }
84 let a_sym = a.symbolic();
85
86 for j in 0..n {
88 let a_row_idx = a_sym.row_idx_of_col_raw(j);
89 let a_col_len = a_row_idx.len();
90 let d = self.symbolic.diag_pos[j];
91 if d >= a_col_len || a_row_idx[d].zx() != j {
92 return Err(Ic0Error::PatternMismatch);
93 }
94 let l_start = self.symbolic.l_col_ptr[j].zx();
95 let l_end = self.symbolic.l_col_ptr[j + 1].zx();
96 if l_end - l_start != a_col_len - d {
97 return Err(Ic0Error::PatternMismatch);
98 }
99
100 let a_val = a.val_of_col(j);
101 for (dst, val) in self.l_values[l_start..l_end]
102 .iter_mut()
103 .zip(a_val[d..].iter())
104 {
105 *dst = copy(val);
106 }
107 }
108
109 let symbolic = &self.symbolic;
111 let w = self.workspace_w.as_mut_slice();
112 let marker = self.workspace_marker.as_mut_slice();
113 let l_values = self.l_values.as_mut_slice();
114
115 for j in 0..n {
116 let l_start = symbolic.l_col_ptr[j].zx();
117 let l_end = symbolic.l_col_ptr[j + 1].zx();
118
119 for (raw_row, val) in symbolic.l_row_idx[l_start..l_end]
121 .iter()
122 .zip(l_values[l_start..l_end].iter())
123 {
124 let i = raw_row.zx();
125 marker[i] = j;
126 w[i] = copy(val);
127 }
128
129 let rcp_start = symbolic.row_col_ptr[j];
133 let rcp_end = symbolic.row_col_ptr[j + 1];
134 for (raw_k, &l_jk_pos) in symbolic.row_col_idx[rcp_start..rcp_end]
135 .iter()
136 .zip(symbolic.row_lpos[rcp_start..rcp_end].iter())
137 {
138 let k = raw_k.zx();
139 let lk_end = symbolic.l_col_ptr[k + 1].zx();
140 let conj_l_jk = conj(&l_values[l_jk_pos]);
141 for (raw_row, lv) in symbolic.l_row_idx[l_jk_pos..lk_end]
144 .iter()
145 .zip(l_values[l_jk_pos..lk_end].iter())
146 {
147 let i = raw_row.zx();
148 if marker[i] == j {
149 let upd = mul(lv, &conj_l_jk);
150 w[i] = sub(&w[i], &upd);
151 }
152 }
153 }
154
155 let pivot_real = real(&w[j]);
158 if pivot_real.partial_cmp(&zero::<T::Real>()) != Some(core::cmp::Ordering::Greater) {
159 return Err(Ic0Error::NotPositiveDefinite { col: j });
160 }
161 let pivot_root = sqrt::<T::Real>(&pivot_real);
162 let pivot = from_real::<T>(&pivot_root);
163 let pivot_inv = recip(&pivot);
164
165 l_values[l_start] = pivot;
168 for (raw_row, dst) in symbolic.l_row_idx[l_start + 1..l_end]
169 .iter()
170 .zip(l_values[l_start + 1..l_end].iter_mut())
171 {
172 let i = raw_row.zx();
173 *dst = mul(&w[i], &pivot_inv);
174 }
175 }
176
177 Ok(())
178 }
179
180 #[inline]
184 pub fn l_view(&self) -> SparseColMatRef<'_, I, T> {
185 let symbolic = unsafe {
186 faer::sparse::SymbolicSparseColMatRef::<'_, I>::new_unchecked(
187 self.symbolic.dim,
188 self.symbolic.dim,
189 &self.symbolic.l_col_ptr,
190 None,
191 &self.symbolic.l_row_idx,
192 )
193 };
194 SparseColMatRef::new(symbolic, &self.l_values)
195 }
196}