1use super::*;
2use crate::assert;
3use crate::internal_prelude::*;
4#[track_caller]
11pub fn binary_op<I: Index, T, LhsT, RhsT>(
12 lhs: SparseColMatRef<'_, I, LhsT>,
13 rhs: SparseColMatRef<'_, I, RhsT>,
14 f: impl FnMut(Option<&LhsT>, Option<&RhsT>) -> T,
15) -> Result<SparseColMat<I, T>, FaerError> {
16 assert!(lhs.nrows() == rhs.nrows());
17 assert!(lhs.ncols() == rhs.ncols());
18 let mut f = f;
19 let m = lhs.nrows();
20 let n = lhs.ncols();
21 let mut col_ptr = try_zeroed::<I>(n + 1)?;
22 let mut nnz = 0usize;
23 for j in 0..n {
24 let lhs = lhs.row_idx_of_col_raw(j);
25 let rhs = rhs.row_idx_of_col_raw(j);
26 let mut lhs_pos = 0usize;
27 let mut rhs_pos = 0usize;
28 while lhs_pos < lhs.len() && rhs_pos < rhs.len() {
29 let lhs = lhs[lhs_pos];
30 let rhs = rhs[rhs_pos];
31 lhs_pos += (lhs <= rhs) as usize;
32 rhs_pos += (rhs <= lhs) as usize;
33 nnz += 1;
34 }
35 nnz += lhs.len() - lhs_pos;
36 nnz += rhs.len() - rhs_pos;
37 col_ptr[j + 1] = I::truncate(nnz);
38 }
39 if nnz > I::Signed::MAX.zx() {
40 return Err(FaerError::IndexOverflow);
41 }
42 let mut row_idx = try_zeroed(nnz)?;
43 let mut values = alloc::vec::Vec::new();
44 values
45 .try_reserve_exact(nnz)
46 .map_err(|_| FaerError::OutOfMemory)?;
47 let mut nnz = 0usize;
48 for j in 0..n {
49 let lhs_values = lhs.val_of_col(j);
50 let rhs_values = rhs.val_of_col(j);
51 let lhs = lhs.row_idx_of_col_raw(j);
52 let rhs = rhs.row_idx_of_col_raw(j);
53 let mut lhs_pos = 0usize;
54 let mut rhs_pos = 0usize;
55 while lhs_pos < lhs.len() && rhs_pos < rhs.len() {
56 let lhs = lhs[lhs_pos];
57 let rhs = rhs[rhs_pos];
58 match lhs.cmp(&rhs) {
59 core::cmp::Ordering::Less => {
60 row_idx[nnz] = lhs;
61 values.push(f(Some(&lhs_values[lhs_pos]), None));
62 },
63 core::cmp::Ordering::Equal => {
64 row_idx[nnz] = lhs;
65 values.push(f(
66 Some(&lhs_values[lhs_pos]),
67 Some(&rhs_values[rhs_pos]),
68 ));
69 },
70 core::cmp::Ordering::Greater => {
71 row_idx[nnz] = rhs;
72 values.push(f(None, Some(&rhs_values[rhs_pos])));
73 },
74 }
75 lhs_pos += (lhs <= rhs) as usize;
76 rhs_pos += (rhs <= lhs) as usize;
77 nnz += 1;
78 }
79 row_idx[nnz..nnz + lhs.len() - lhs_pos]
80 .copy_from_slice(&lhs[lhs_pos..]);
81 for src in &lhs_values[lhs_pos..lhs.len()] {
82 values.push(f(Some(src), None));
83 }
84 nnz += lhs.len() - lhs_pos;
85 row_idx[nnz..nnz + rhs.len() - rhs_pos]
86 .copy_from_slice(&rhs[rhs_pos..]);
87 for src in &rhs_values[rhs_pos..rhs.len()] {
88 values.push(f(None, Some(src)));
89 }
90 nnz += rhs.len() - rhs_pos;
91 }
92 Ok(SparseColMat::<I, T>::new(
93 SymbolicSparseColMat::<I>::new_checked(m, n, col_ptr, None, row_idx),
94 values,
95 ))
96}
97#[track_caller]
105pub fn binary_op_assign_into<I: Index, T, SrcT>(
106 dst: SparseColMatMut<'_, I, T>,
107 src: SparseColMatRef<'_, I, SrcT>,
108 f: impl FnMut(&mut T, Option<&SrcT>),
109) {
110 {
111 assert!(dst.nrows() == src.nrows());
112 assert!(dst.ncols() == src.ncols());
113 let n = dst.ncols();
114 let mut dst = dst;
115 let mut f = f;
116 for j in 0..n {
117 let (dst, dst_val) = dst.rb_mut().parts_mut();
118 let dst_val = &mut dst_val[dst.col_range(j)];
119 let src_val = src.val_of_col(j);
120 let dst = dst.row_idx_of_col_raw(j);
121 let src = src.row_idx_of_col_raw(j);
122 let mut dst_pos = 0usize;
123 let mut src_pos = 0usize;
124 while src_pos < src.len() {
125 let src = src[src_pos];
126 if dst[dst_pos] < src {
127 f(&mut dst_val[dst_pos], None);
128 dst_pos += 1;
129 continue;
130 }
131 assert!(dst[dst_pos] == src);
132 f(&mut dst_val[dst_pos], Some(&src_val[src_pos]));
133 src_pos += 1;
134 dst_pos += 1;
135 }
136 while dst_pos < dst.len() {
137 f(&mut dst_val[dst_pos], None);
138 dst_pos += 1;
139 }
140 }
141 }
142}
143#[track_caller]
151pub fn ternary_op_assign_into<I: Index, T, LhsT, RhsT>(
152 dst: SparseColMatMut<'_, I, T>,
153 lhs: SparseColMatRef<'_, I, LhsT>,
154 rhs: SparseColMatRef<'_, I, RhsT>,
155 f: impl FnMut(&mut T, Option<&LhsT>, Option<&RhsT>),
156) {
157 {
158 assert!(dst.nrows() == lhs.nrows());
159 assert!(dst.ncols() == lhs.ncols());
160 assert!(dst.nrows() == rhs.nrows());
161 assert!(dst.ncols() == rhs.ncols());
162 let n = dst.ncols();
163 let mut dst = dst;
164 let mut f = f;
165 for j in 0..n {
166 let (dst, dst_val) = dst.rb_mut().parts_mut();
167 let dst_val = &mut dst_val[dst.col_range(j)];
168 let lhs_val = lhs.val_of_col(j);
169 let rhs_val = rhs.val_of_col(j);
170 let dst = dst.row_idx_of_col_raw(j);
171 let rhs = rhs.row_idx_of_col_raw(j);
172 let lhs = lhs.row_idx_of_col_raw(j);
173 let mut dst_pos = 0usize;
174 let mut lhs_pos = 0usize;
175 let mut rhs_pos = 0usize;
176 while lhs_pos < lhs.len() && rhs_pos < rhs.len() {
177 let lhs = lhs[lhs_pos];
178 let rhs = rhs[rhs_pos];
179 if dst[dst_pos] < Ord::min(lhs, rhs) {
180 f(&mut dst_val[dst_pos], None, None);
181 dst_pos += 1;
182 continue;
183 }
184 assert!(dst[dst_pos] == Ord::min(lhs, rhs));
185 match lhs.cmp(&rhs) {
186 core::cmp::Ordering::Less => {
187 f(&mut dst_val[dst_pos], Some(&lhs_val[lhs_pos]), None);
188 },
189 core::cmp::Ordering::Equal => {
190 f(
191 &mut dst_val[dst_pos],
192 Some(&lhs_val[lhs_pos]),
193 Some(&rhs_val[rhs_pos]),
194 );
195 },
196 core::cmp::Ordering::Greater => {
197 f(&mut dst_val[dst_pos], None, Some(&rhs_val[rhs_pos]));
198 },
199 }
200 lhs_pos += (lhs <= rhs) as usize;
201 rhs_pos += (rhs <= lhs) as usize;
202 dst_pos += 1;
203 }
204 while lhs_pos < lhs.len() {
205 let lhs = lhs[lhs_pos];
206 if dst[dst_pos] < lhs {
207 f(&mut dst_val[dst_pos], None, None);
208 dst_pos += 1;
209 continue;
210 }
211 f(&mut dst_val[dst_pos], Some(&lhs_val[lhs_pos]), None);
212 lhs_pos += 1;
213 dst_pos += 1;
214 }
215 while rhs_pos < rhs.len() {
216 let rhs = rhs[rhs_pos];
217 if dst[dst_pos] < rhs {
218 f(&mut dst_val[dst_pos], None, None);
219 dst_pos += 1;
220 continue;
221 }
222 f(&mut dst_val[dst_pos], None, Some(&rhs_val[rhs_pos]));
223 rhs_pos += 1;
224 dst_pos += 1;
225 }
226 while rhs_pos < rhs.len() {
227 let rhs = rhs[rhs_pos];
228 dst_pos += dst[dst_pos..].binary_search(&rhs).unwrap();
229 f(&mut dst_val[dst_pos], None, Some(&rhs_val[rhs_pos]));
230 rhs_pos += 1;
231 }
232 }
233 }
234}
235#[track_caller]
241#[inline]
242pub fn union_symbolic<I: Index>(
243 lhs: SymbolicSparseColMatRef<'_, I>,
244 rhs: SymbolicSparseColMatRef<'_, I>,
245) -> Result<SymbolicSparseColMat<I>, FaerError> {
246 Ok(binary_op(
247 SparseColMatRef::<I, Symbolic>::new(
248 lhs,
249 Symbolic::materialize(lhs.compute_nnz()),
250 ),
251 SparseColMatRef::<I, Symbolic>::new(
252 rhs,
253 Symbolic::materialize(rhs.compute_nnz()),
254 ),
255 #[inline(always)]
256 |_, _| Symbolic,
257 )?
258 .into_parts()
259 .0)
260}
261#[track_caller]
266#[inline]
267pub fn add<
268 I: Index,
269 T: ComplexField,
270 LhsT: Conjugate<Canonical = T>,
271 RhsT: Conjugate<Canonical = T>,
272>(
273 lhs: SparseColMatRef<'_, I, LhsT>,
274 rhs: SparseColMatRef<'_, I, RhsT>,
275) -> Result<SparseColMat<I, T>, FaerError> {
276 binary_op(lhs, rhs, |lhs, rhs| {
277 match (lhs.map(Conj::apply), rhs.map(Conj::apply)) {
278 (None, None) => zero(),
279 (None, Some(rhs)) => rhs,
280 (Some(lhs), None) => lhs,
281 (Some(lhs), Some(rhs)) => lhs + rhs,
282 }
283 })
284}
285#[track_caller]
290#[inline]
291pub fn sub<
292 I: Index,
293 T: ComplexField,
294 LhsT: Conjugate<Canonical = T>,
295 RhsT: Conjugate<Canonical = T>,
296>(
297 lhs: SparseColMatRef<'_, I, LhsT>,
298 rhs: SparseColMatRef<'_, I, RhsT>,
299) -> Result<SparseColMat<I, T>, FaerError> {
300 binary_op(lhs, rhs, |lhs, rhs| {
301 match (lhs.map(Conj::apply), rhs.map(Conj::apply)) {
302 (None, None) => zero(),
303 (None, Some(rhs)) => -rhs,
304 (Some(lhs), None) => lhs,
305 (Some(lhs), Some(rhs)) => lhs - rhs,
306 }
307 })
308}
309pub fn add_assign<I: Index, T: ComplexField, RhsT: Conjugate<Canonical = T>>(
316 dst: SparseColMatMut<'_, I, T>,
317 rhs: SparseColMatRef<'_, I, RhsT>,
318) {
319 binary_op_assign_into(dst, rhs, |dst, rhs| {
320 *dst += match rhs {
321 Some(rhs) => Conj::apply(rhs),
322 None => zero(),
323 }
324 })
325}
326pub fn sub_assign<I: Index, T: ComplexField, RhsT: Conjugate<Canonical = T>>(
333 dst: SparseColMatMut<'_, I, T>,
334 rhs: SparseColMatRef<'_, I, RhsT>,
335) {
336 binary_op_assign_into(dst, rhs, |dst, rhs| {
337 *dst -= match rhs {
338 Some(rhs) => Conj::apply(rhs),
339 None => zero(),
340 }
341 })
342}
343#[track_caller]
350#[inline]
351pub fn add_into<
352 I: Index,
353 T: ComplexField,
354 LhsT: Conjugate<Canonical = T>,
355 RhsT: Conjugate<Canonical = T>,
356>(
357 dst: SparseColMatMut<'_, I, T>,
358 lhs: SparseColMatRef<'_, I, LhsT>,
359 rhs: SparseColMatRef<'_, I, RhsT>,
360) {
361 ternary_op_assign_into(dst, lhs, rhs, |dst, lhs, rhs| {
362 *dst = match (lhs.map(Conj::apply), rhs.map(Conj::apply)) {
363 (None, None) => zero(),
364 (None, Some(rhs)) => rhs,
365 (Some(lhs), None) => lhs,
366 (Some(lhs), Some(rhs)) => lhs + rhs,
367 };
368 })
369}
370#[track_caller]
377#[inline]
378pub fn sub_into<
379 I: Index,
380 T: ComplexField,
381 LhsT: Conjugate<Canonical = T>,
382 RhsT: Conjugate<Canonical = T>,
383>(
384 dst: SparseColMatMut<'_, I, T>,
385 lhs: SparseColMatRef<'_, I, LhsT>,
386 rhs: SparseColMatRef<'_, I, RhsT>,
387) {
388 ternary_op_assign_into(dst, lhs, rhs, |dst, lhs, rhs| {
389 *dst = match (lhs.map(Conj::apply), rhs.map(Conj::apply)) {
390 (None, None) => zero(),
391 (None, Some(rhs)) => -rhs,
392 (Some(lhs), None) => lhs,
393 (Some(lhs), Some(rhs)) => lhs - rhs,
394 };
395 })
396}