faer_precond/iluk/
numeric.rs1use faer::sparse::{SparseColMatRef, SymbolicSparseColMatRef};
9use faer_traits::math_utils::{abs2, copy, mul, one, recip, sub, zero};
10use faer_traits::{ComplexField, Index};
11
12use super::IlukError;
13use super::symbolic::SymbolicIluk;
14
15#[derive(Debug, Clone)]
21pub struct Iluk<I, T> {
22 pub(crate) symbolic: SymbolicIluk<I>,
23 pub(crate) l_values: Vec<T>,
24 pub(crate) u_values: Vec<T>,
25 pub(crate) workspace_w: Vec<T>,
26 pub(crate) workspace_marker: Vec<usize>,
27}
28
29impl<I: Index, T: ComplexField> Iluk<I, T> {
30 pub fn new_with_symbolic(symbolic: SymbolicIluk<I>) -> Self {
32 let n = symbolic.dim;
33 let l_values = (0..symbolic.l_nnz()).map(|_| zero::<T>()).collect();
34 let u_values = (0..symbolic.u_nnz()).map(|_| zero::<T>()).collect();
35 let workspace_w = (0..n).map(|_| zero::<T>()).collect();
36 let workspace_marker = vec![usize::MAX; n];
37 Self {
38 symbolic,
39 l_values,
40 u_values,
41 workspace_w,
42 workspace_marker,
43 }
44 }
45
46 pub fn try_new(a: SparseColMatRef<'_, I, T>, level: usize) -> Result<Self, IlukError> {
48 let symbolic = SymbolicIluk::try_new(a.symbolic(), level)?;
49 let mut me = Self::new_with_symbolic(symbolic);
50 me.refactorize(a)?;
51 Ok(me)
52 }
53
54 #[inline]
56 pub fn dim(&self) -> usize {
57 self.symbolic.dim
58 }
59
60 #[inline]
62 pub fn symbolic(&self) -> &SymbolicIluk<I> {
63 &self.symbolic
64 }
65
66 pub fn refactorize(&mut self, a: SparseColMatRef<'_, I, T>) -> Result<(), IlukError> {
76 let n = self.symbolic.dim;
77 if a.nrows() != n || a.ncols() != n {
78 return Err(IlukError::PatternMismatch);
79 }
80
81 let symbolic = &self.symbolic;
82 let w = self.workspace_w.as_mut_slice();
83 let marker = self.workspace_marker.as_mut_slice();
84 let l_values = self.l_values.as_mut_slice();
85 let u_values = self.u_values.as_mut_slice();
86
87 for j in 0..n {
88 let u_start = symbolic.u_col_ptr[j].zx();
89 let u_end = symbolic.u_col_ptr[j + 1].zx();
90 let l_start = symbolic.l_col_ptr[j].zx();
91 let l_end = symbolic.l_col_ptr[j + 1].zx();
92
93 for raw in &symbolic.u_row_idx[u_start..u_end] {
95 let i = raw.zx();
96 marker[i] = j;
97 w[i] = zero::<T>();
98 }
99 for raw in &symbolic.l_row_idx[l_start..l_end] {
100 let i = raw.zx();
101 marker[i] = j;
102 w[i] = zero::<T>();
103 }
104 let a_rows = a.symbolic().row_idx_of_col_raw(j);
106 let a_vals = a.val_of_col(j);
107 for (raw, val) in a_rows.iter().zip(a_vals.iter()) {
108 let i = raw.zx();
109 if marker[i] == j {
110 w[i] = copy(val);
111 }
112 }
113
114 for raw_p in &symbolic.u_row_idx[u_start..u_end - 1] {
117 let p = raw_p.zx();
118 let u_pj = copy(&w[p]);
119 let lp_start = symbolic.l_col_ptr[p].zx();
120 let lp_end = symbolic.l_col_ptr[p + 1].zx();
121 for (raw_row, lv) in symbolic.l_row_idx[lp_start + 1..lp_end]
122 .iter()
123 .zip(l_values[lp_start + 1..lp_end].iter())
124 {
125 let i = raw_row.zx();
126 if marker[i] == j {
127 let upd = mul(lv, &u_pj);
128 w[i] = sub(&w[i], &upd);
129 }
130 }
131 }
132
133 for (raw_row, dst) in symbolic.u_row_idx[u_start..u_end]
135 .iter()
136 .zip(u_values[u_start..u_end].iter_mut())
137 {
138 let i = raw_row.zx();
139 *dst = copy(&w[i]);
140 }
141
142 let pivot = copy(&u_values[u_end - 1]);
143 if abs2(&pivot) == zero::<T::Real>() {
144 return Err(IlukError::ZeroPivot { col: j });
145 }
146 let pivot_inv = recip(&pivot);
147
148 l_values[l_start] = one::<T>();
150 for (raw_row, dst) in symbolic.l_row_idx[l_start + 1..l_end]
151 .iter()
152 .zip(l_values[l_start + 1..l_end].iter_mut())
153 {
154 let i = raw_row.zx();
155 *dst = mul(&w[i], &pivot_inv);
156 }
157 }
158
159 Ok(())
160 }
161
162 #[inline]
164 pub fn l_view(&self) -> SparseColMatRef<'_, I, T> {
165 let symbolic = unsafe {
166 SymbolicSparseColMatRef::<'_, I>::new_unchecked(
167 self.symbolic.dim,
168 self.symbolic.dim,
169 &self.symbolic.l_col_ptr,
170 None,
171 &self.symbolic.l_row_idx,
172 )
173 };
174 SparseColMatRef::new(symbolic, &self.l_values)
175 }
176
177 #[inline]
179 pub fn u_view(&self) -> SparseColMatRef<'_, I, T> {
180 let symbolic = unsafe {
181 SymbolicSparseColMatRef::<'_, I>::new_unchecked(
182 self.symbolic.dim,
183 self.symbolic.dim,
184 &self.symbolic.u_col_ptr,
185 None,
186 &self.symbolic.u_row_idx,
187 )
188 };
189 SparseColMatRef::new(symbolic, &self.u_values)
190 }
191}