1use crate::internal_prelude_sp::*;
3use crate::{assert, debug_assert};
4#[inline]
5fn post_tree<'n, I: Index>(
6 root: Idx<'n, usize>,
7 k: usize,
8 child: &mut Array<'n, MaybeIdx<'n, I>>,
9 sibling: &Array<'n, MaybeIdx<'n, I>>,
10 order: &mut Array<'n, I::Signed>,
11 stack: &mut Array<'n, I::Signed>,
12) -> usize {
13 let N = child.len();
14 let I = I::Signed::truncate;
15 let mut top = 1usize;
16 stack[N.check(0)] = I(*root);
17 let mut k = k;
18 while top > 0 {
19 let i = N.check(stack[N.check(top - 1)].zx());
20 if let Some(child_) = child[i].idx() {
21 let mut f = child_.zx();
22 loop {
23 top += 1;
24 if let Some(new_f) = sibling[f].idx() {
25 f = new_f.zx();
26 } else {
27 break;
28 }
29 }
30 let mut t = top;
31 let mut f = child_.zx();
32 loop {
33 t -= 1;
34 stack[N.check(t)] = I(*f);
35 if let Some(new_f) = sibling[f].idx() {
36 f = new_f.zx();
37 } else {
38 break;
39 }
40 }
41 child[i] = MaybeIdx::none();
42 } else {
43 top -= 1;
44 order[i] = I(k);
45 k += 1;
46 }
47 }
48 k
49}
50#[inline]
51fn postorder<'n, 'out, I: Index>(
52 order: &'out mut Array<'n, I::Signed>,
53 etree: &Array<'n, MaybeIdx<'n, I>>,
54 nv: &Array<'n, I::Signed>,
55 f_size: &Array<'n, I::Signed>,
56 stack: &mut MemStack,
57) {
58 let N = order.len();
59 let n = *N;
60 if n == 0 {
61 return;
62 }
63 let I = I::Signed::truncate;
64 let zero = I(0);
65 let none = I(NONE);
66 let (ref mut child, stack) =
67 stack.collect(repeat_n!(MaybeIdx::<'_, I>::none(), n));
68 let (ref mut sibling, stack) =
69 stack.collect(repeat_n!(MaybeIdx::<'_, I>::none(), n));
70 let (ref mut stack, _) = stack.collect(repeat_n!(I(0), n));
71 let child = Array::from_mut(child, N);
72 let sibling = Array::from_mut(sibling, N);
73 let stack = Array::from_mut(stack, N);
74 for j in N.indices().rev() {
75 if nv[j] > zero {
76 if let Some(parent) = etree[j].idx() {
77 let parent = parent.zx();
78 sibling[j] = child[parent];
79 child[parent] = MaybeIdx::from_index(j.truncate());
80 }
81 }
82 }
83 for i in N.indices() {
84 if nv[i] > zero {
85 if let Some(child_) = child[i].idx() {
86 let child_ = child_.zx();
87 let mut fprev = MaybeIdx::<'n>::none();
88 let mut bigfprev = MaybeIdx::<'n>::none();
89 let mut bigf = MaybeIdx::<'n>::none();
90 let mut maxfrsize = none;
91 let mut f = MaybeIdx::from_index(child_);
92 while let Some(f_) = f.idx() {
93 let frsize = f_size[f_];
94 if frsize >= maxfrsize {
95 maxfrsize = frsize;
96 bigfprev = fprev;
97 bigf = f;
98 }
99 fprev = f;
100 f = sibling[f_].sx();
101 }
102 let bigf = bigf.idx().unwrap();
103 let fnext = sibling[bigf];
104 if let Some(fnext) = fnext.idx() {
105 if let Some(bigfprev) = bigfprev.idx() {
106 sibling[bigfprev] = MaybeIdx::from_index(fnext);
107 } else {
108 child[i] = MaybeIdx::from_index(fnext);
109 }
110 let fprev = fprev.idx().unwrap();
111 sibling[bigf] = MaybeIdx::none();
112 sibling[fprev] = MaybeIdx::from_index(bigf.truncate());
113 }
114 }
115 }
116 }
117 order.as_mut().fill(none);
118 let mut k = 0usize;
119 for i in N.indices() {
120 if etree[i].idx().is_none() && nv[i] > zero {
121 k = post_tree(i, k, child, sibling, order, stack);
122 }
123 }
124}
125#[inline(always)]
126fn flip<I: SignedIndex>(i: I) -> I {
127 -I::truncate(2) - i
128}
129#[inline]
130fn clear_flag<I: SignedIndex>(wflg: I, wbig: I, w: &mut [I]) -> I {
131 let I = I::truncate;
132 let zero = I(0);
133 let one = I(1);
134 if wflg < I(2) || wflg >= wbig {
135 for x in w {
136 if *x != zero {
137 *x = one;
138 }
139 }
140 return I(2);
141 }
142 wflg
143}
144#[allow(clippy::comparison_chain)]
145fn amd_2<I: Index>(
146 pe: &mut [I::Signed],
147 iw: &mut [I::Signed],
148 len: &mut [I::Signed],
149 pfree: usize,
150 next: &mut [I::Signed],
151 last: &mut [I::Signed],
152 control: Control,
153 stack: &mut MemStack,
154) -> FlopCount {
155 let n = pe.len();
156 assert!(n < I::Signed::MAX.zx());
157 let mut pfree = pfree;
158 let iwlen = iw.len();
159 let I = I::Signed::truncate;
160 let none = I(NONE);
161 let zero = I(0);
162 let one = I(1);
163 let alpha = control.dense;
164 let aggressive = control.aggressive;
165 let mut mindeg = 0usize;
166 let mut ncmpa = 0usize;
167 let mut lemax = 0usize;
168 let mut ndiv = 0.0;
169 let mut nms_lu = 0.0;
170 let mut nms_ldl = 0.0;
171 let mut nel = 0usize;
172 let mut me = none;
173 let dense = if alpha < 0.0 {
174 n - 2
175 } else {
176 (alpha * ComplexFieldExt::sqrt(&(n as f64))) as usize
177 };
178 let dense = Ord::max(dense, 16);
179 let dense = Ord::min(dense, n);
180 let (mut w, stack) = stack.collect(repeat_n!(one, n));
181 let (mut nv, stack) = stack.collect(repeat_n!(one, n));
182 let (mut elen, stack) = stack.collect(repeat_n!(zero, n));
183 let nv = &mut *nv;
184 let elen = &mut *elen;
185 let w = &mut *w;
186 let wbig = I::Signed::MAX - I(n);
187 let mut wflg = I(0);
188 let mut ndense = zero;
189 {
190 let (mut head, stack) = stack.collect(repeat_n!(none, n));
191 let (mut degree, _) = stack.collect(repeat_n!(none, n));
192 let head = &mut *head;
193 let degree = &mut *degree;
194 last.fill(none);
195 head.fill(none);
196 next.fill(none);
197 degree.copy_from_slice(len);
198 for i in 0..n {
199 let deg = degree[i].zx();
200 if deg == 0 {
201 elen[i] = flip(one);
202 nel += 1;
203 pe[i] = none;
204 w[i] = zero;
205 } else if deg > dense {
206 ndense += one;
207 nv[i] = zero;
208 elen[i] = none;
209 pe[i] = none;
210 nel += 1;
211 } else {
212 let inext = head[deg];
213 if inext != none {
214 last[inext.zx()] = I(i);
215 }
216 next[i] = inext;
217 head[deg] = I(i);
218 }
219 }
220 while nel < n {
221 let mut deg = mindeg;
222 while deg < n {
223 me = head[deg];
224 if me != none {
225 break;
226 }
227 deg += 1;
228 }
229 mindeg = deg;
230 let me = me.zx();
231 let inext = next[me];
232 if inext != none {
233 last[inext.zx()] = none;
234 }
235 head[deg] = inext;
236 let elenme = elen[me];
237 let mut nvpiv = nv[me];
238 nel += nvpiv.zx();
239 nv[me] = -nvpiv;
240 let mut degme = 0usize;
241 let mut pme1;
242 let mut pme2;
243 if elenme == zero {
244 pme1 = pe[me];
245 pme2 = pme1 - one;
246 for p in pme1.zx()..(pme1 + len[me]).zx() {
247 let i = iw[p].zx();
248 let nvi = nv[i];
249 if nvi > zero {
250 degme += nvi.zx();
251 nv[i] = -nvi;
252 pme2 += one;
253 iw[pme2.zx()] = I(i);
254 let ilast = last[i];
255 let inext = next[i];
256 if inext != none {
257 last[inext.zx()] = ilast;
258 }
259 if ilast != none {
260 next[ilast.zx()] = inext;
261 } else {
262 head[degree[i].zx()] = inext;
263 }
264 }
265 }
266 } else {
267 let mut p = pe[me].zx();
268 pme1 = I(pfree);
269 let slenme = (len[me] - elenme).zx();
270 for knt1 in 1..elenme.zx() + 2 {
271 let e;
272 let mut pj;
273 let ln;
274 if I(knt1) > elenme {
275 e = me;
276 pj = I(p);
277 ln = slenme;
278 } else {
279 e = iw[p].zx();
280 p += 1;
281 pj = pe[e];
282 ln = len[e].zx();
283 }
284 for knt2 in 1..ln + 1 {
285 let i = iw[pj.zx()].zx();
286 pj += one;
287 let nvi = nv[i];
288 if nvi > zero {
289 if pfree >= iwlen {
290 pe[me] = I(p);
291 len[me] -= I(knt1);
292 if len[me] == zero {
293 pe[me] = none;
294 }
295 pe[e] = pj;
296 len[e] = I(ln - knt2);
297 if len[e] == zero {
298 pe[e] = none;
299 }
300 ncmpa += 1;
301 for (j, pe) in pe.iter_mut().enumerate() {
302 let pn = *pe;
303 if pn >= zero {
304 let pn = pn.zx();
305 *pe = iw[pn];
306 iw[pn] = flip(I(j));
307 }
308 }
309 let mut psrc = 0usize;
310 let mut pdst = 0usize;
311 let pend = pme1.zx();
312 while psrc < pend {
313 let j = flip(iw[psrc]);
314 psrc += 1;
315 if j >= zero {
316 let j = j.zx();
317 iw[pdst] = pe[j];
318 pe[j] = I(pdst);
319 pdst += 1;
320 let lenj = len[j].zx();
321 if lenj > 0 {
322 iw.copy_within(
323 psrc..psrc + lenj - 1,
324 pdst,
325 );
326 psrc += lenj - 1;
327 pdst += lenj - 1;
328 }
329 }
330 }
331 let p1 = pdst;
332 iw.copy_within(pme1.zx()..pfree, pdst);
333 pdst += pfree - pme1.zx();
334 pme1 = I(p1);
335 pfree = pdst;
336 pj = pe[e];
337 p = pe[me].zx();
338 }
339 degme += nvi.zx();
340 nv[i] = -nvi;
341 iw[pfree] = I(i);
342 pfree += 1;
343 let ilast = last[i];
344 let inext = next[i];
345 if inext != none {
346 last[inext.zx()] = ilast;
347 }
348 if ilast != none {
349 next[ilast.zx()] = inext;
350 } else {
351 head[degree[i].zx()] = inext;
352 }
353 }
354 }
355 if e != me {
356 pe[e] = flip(I(me));
357 w[e] = zero;
358 }
359 }
360 pme2 = I(pfree - 1);
361 }
362 degree[me] = I(degme);
363 pe[me] = pme1;
364 len[me] = pme2 - pme1 + one;
365 elen[me] = flip(nvpiv + I(degme));
366 wflg = clear_flag(wflg, wbig, w);
367 assert!(pme1 >= zero);
368 for pme in pme1.zx()..(pme2 + one).zx() {
369 let i = iw[pme].zx();
370 let eln = elen[i];
371 if eln > zero {
372 let nvi = -nv[i];
373 let wnvi = wflg - nvi;
374 for iw in iw[pe[i].zx()..][..eln.zx()].iter() {
375 let e = iw.zx();
376 let mut we = w[e];
377 if we >= wflg {
378 we -= nvi;
379 } else if we != zero {
380 we = degree[e] + wnvi;
381 }
382 w[e] = we;
383 }
384 }
385 }
386 for pme in pme1.zx()..(pme2 + one).zx() {
387 let i = iw[pme].zx();
388 let p1 = pe[i].zx();
389 let p2 = p1 + elen[i].zx();
390 let mut pn = p1;
391 let mut hash = 0usize;
392 deg = 0usize;
393 if aggressive {
394 for p in p1..p2 {
395 let e = iw[p].zx();
396 let we = w[e];
397 if we != zero {
398 let dext = we - wflg;
399 if dext > zero {
400 deg += dext.zx();
401 iw[pn] = I(e);
402 pn += 1;
403 hash = hash.wrapping_add(e);
404 } else {
405 pe[e] = flip(I(me));
406 w[e] = zero;
407 }
408 }
409 }
410 } else {
411 for p in p1..p2 {
412 let e = iw[p].zx();
413 let we = w[e];
414 if we != zero {
415 let dext = (we - wflg).zx();
416 deg += dext;
417 iw[pn] = I(e);
418 pn += 1;
419 hash = hash.wrapping_add(e);
420 }
421 }
422 }
423 elen[i] = I(pn - p1 + 1);
424 let p3 = pn;
425 let p4 = p1 + len[i].zx();
426 for p in p2..p4 {
427 let j = iw[p].zx();
428 let nvj = nv[j];
429 if nvj > zero {
430 deg += nvj.zx();
431 iw[pn] = I(j);
432 pn += 1;
433 hash = hash.wrapping_add(j);
434 }
435 }
436 if elen[i] == one && p3 == pn {
437 pe[i] = flip(I(me));
438 let nvi = -nv[i];
439 assert!(nvi >= zero);
440 degme -= nvi.zx();
441 nvpiv += nvi;
442 nel += nvi.zx();
443 nv[i] = zero;
444 elen[i] = none;
445 } else {
446 degree[i] = Ord::min(degree[i], I(deg));
447 iw[pn] = iw[p3];
448 iw[p3] = iw[p1];
449 iw[p1] = I(me);
450 len[i] = I(pn - p1 + 1);
451 hash %= n;
452 let j = head[hash];
453 if j <= none {
454 next[i] = flip(j);
455 head[hash] = flip(I(i));
456 } else {
457 next[i] = last[j.zx()];
458 last[j.zx()] = I(i);
459 }
460 last[i] = I(hash);
461 }
462 }
463 degree[me] = I(degme);
464 lemax = Ord::max(lemax, degme);
465 wflg += I(lemax);
466 wflg = clear_flag(wflg, wbig, w);
467 for pme in pme1.zx()..(pme2 + one).zx() {
468 let mut i = iw[pme].zx();
469 if nv[i] < zero {
470 let hash = last[i].zx();
471 let j = head[hash];
472 if j == none {
473 i = NONE;
474 } else if j < none {
475 i = flip(j).zx();
476 head[hash] = none;
477 } else {
478 i = last[j.zx()].sx();
479 last[j.zx()] = none;
480 }
481 while i != NONE && next[i] != none {
482 let ln = len[i];
483 let eln = elen[i];
484 for p in (pe[i] + one).zx()..(pe[i] + ln).zx() {
485 w[iw[p].zx()] = wflg;
486 }
487 let mut jlast = i;
488 let mut j = next[i].sx();
489 while j != NONE {
490 let mut ok = len[j] == ln && elen[j] == eln;
491 if ok {
492 for p in (pe[j] + one).zx()..(pe[j] + ln).zx() {
493 if w[iw[p].zx()] != wflg {
494 ok = false;
495 break;
496 }
497 }
498 }
499 if ok {
500 pe[j] = flip(I(i));
501 nv[i] += nv[j];
502 nv[j] = zero;
503 elen[j] = none;
504 j = next[j].sx();
505 next[jlast] = I(j);
506 } else {
507 jlast = j;
508 j = next[j].sx();
509 }
510 }
511 wflg += one;
512 i = next[i].sx();
513 }
514 }
515 }
516 let mut p = pme1.zx();
517 let nleft = n - nel;
518 for pme in pme1.zx()..(pme2 + one).zx() {
519 let i = iw[pme].zx();
520 let nvi = -nv[i];
521 if nvi > zero {
522 nv[i] = nvi;
523 deg = degree[i].zx() + degme - nvi.zx();
524 deg = Ord::min(deg, nleft - nvi.zx());
525 let inext = head[deg];
526 if inext != none {
527 last[inext.zx()] = I(i);
528 }
529 next[i] = inext;
530 last[i] = none;
531 head[deg] = I(i);
532 mindeg = Ord::min(mindeg, deg);
533 degree[i] = I(deg);
534 iw[p] = I(i);
535 p += 1;
536 }
537 }
538 nv[me] = nvpiv;
539 len[me] = I(p) - pme1;
540 if len[me] == zero {
541 pe[me] = none;
542 w[me] = zero;
543 }
544 if elenme != zero {
545 pfree = p;
546 }
547 {
548 let f = nvpiv.sx() as isize as f64;
549 let r = degme as f64 + ndense.sx() as isize as f64;
550 let lnzme = f * r + (f - 1.0) * f / 2.0;
551 ndiv += lnzme;
552 let s = f * r * r
553 + r * (f - 1.0) * f
554 + (f - 1.0) * f * (2.0 * f - 1.0) / 6.0;
555 nms_lu += s;
556 nms_ldl += (s + lnzme) / 2.0;
557 }
558 }
559 {
560 let f = ndense.sx() as isize as f64;
561 let lnzme = (f - 1.0) * f / 2.0;
562 ndiv += lnzme;
563 let s = (f - 1.0) * f * (2.0 * f - 1.0) / 6.0;
564 nms_lu += s;
565 nms_ldl += (s + lnzme) / 2.0;
566 }
567 for pe in pe.iter_mut() {
568 *pe = flip(*pe);
569 }
570 for elen in elen.iter_mut() {
571 *elen = flip(*elen);
572 }
573 for i in 0..n {
574 if nv[i] == zero {
575 let mut j = pe[i].sx();
576 if j == NONE {
577 continue;
578 }
579 while nv[j] == zero {
580 j = pe[j].zx();
581 }
582 let e = I(j);
583 let mut j = i;
584 while nv[j] == zero {
585 let jnext = pe[j];
586 pe[j] = e;
587 j = jnext.zx();
588 }
589 }
590 }
591 }
592 with_dim!(N, n);
593 postorder(
594 Array::from_mut(w, N),
595 Array::from_ref(MaybeIdx::<'_, I>::from_slice_ref_checked(pe, N), N),
596 Array::from_ref(nv, N),
597 Array::from_ref(elen, N),
598 stack,
599 );
600 let (ref mut head, _) = stack.collect(repeat_n!(none, n));
601 next.fill(none);
602 for (e, &k) in w.iter().enumerate() {
603 if k != none {
604 head[k.zx()] = I(e);
605 }
606 }
607 nel = 0;
608 for &e in head.iter() {
609 if e == none {
610 break;
611 }
612 let e = e.zx();
613 next[e] = I(nel);
614 nel += nv[e].zx();
615 }
616 assert!(nel == n - ndense.zx());
617 for i in 0..n {
618 if nv[i] == zero {
619 let e = pe[i];
620 if e != none {
621 let e = e.zx();
622 next[i] = next[e];
623 next[e] += one;
624 } else {
625 next[i] = I(nel);
626 nel += 1;
627 }
628 }
629 }
630 assert!(nel == n);
631 for i in 0..n {
632 last[next[i].zx()] = I(i);
633 }
634 let _ = ncmpa;
635 FlopCount {
636 n_div: ndiv,
637 n_mult_subs_ldl: nms_ldl,
638 n_mult_subs_lu: nms_lu,
639 }
640}
641#[allow(clippy::comparison_chain)]
642fn amd_1<I: Index>(
643 perm: &mut [I::Signed],
644 perm_inv: &mut [I::Signed],
645 A: SymbolicSparseColMatRef<'_, I>,
646 len: &mut [I::Signed],
647 iwlen: usize,
648 control: Control,
649 stack: &mut MemStack,
650) -> FlopCount {
651 let n = perm.len();
652 let I = I::Signed::truncate;
653 let zero = I(0);
654 let one = I(1);
655 let (p_e, stack) = unsafe { stack.make_raw::<I::Signed>(n) };
656 let (s_p, stack) = unsafe { stack.make_raw::<I::Signed>(n) };
657 let (i_w, stack) = unsafe { stack.make_raw::<I::Signed>(iwlen) };
658 let mut pfree = zero;
659 for j in 0..n {
660 p_e[j] = pfree;
661 s_p[j] = pfree;
662 pfree += len[j];
663 }
664 let pfree = pfree.zx();
665 assert!(iwlen >= pfree + n);
666 {
667 with_dim!(N, n);
668 let (t_p, _) = unsafe { stack.make_raw::<I::Signed>(n) };
669 let A = A.as_shape(N, N);
670 let s_p = Array::from_mut(s_p, N);
671 let t_p = Array::from_mut(t_p, N);
672 for k in N.indices() {
673 let mut seen = zero;
674 let mut j_prev = usize::MAX;
675 for j in A.row_idx_of_col(k) {
676 if j_prev == *j {
677 j_prev = *j;
678 continue;
679 }
680 j_prev = *j;
681 if j < k {
682 i_w[s_p[j].zx()] = I(*k);
683 s_p[j] += one;
684 i_w[s_p[k].zx()] = I(*j);
685 s_p[k] += one;
686 seen += one;
687 } else {
688 if j == k {
689 seen += one;
690 }
691 break;
692 }
693 let mut seen_j = zero;
694 let mut i_prev = usize::MAX;
695 for i in &A.row_idx_of_col_raw(j)[t_p[j].zx()..] {
696 if i_prev == *i.zx() {
697 i_prev = *i.zx();
698 continue;
699 }
700 i_prev = *i.zx();
701 let i = i.zx();
702 if i < k {
703 i_w[s_p[i].zx()] = I(*j);
704 s_p[i] += one;
705 i_w[s_p[j].zx()] = I(*i);
706 s_p[j] += one;
707 seen_j += one;
708 } else {
709 if i == k {
710 seen_j += one;
711 }
712 break;
713 }
714 }
715 t_p[j] += seen_j;
716 }
717 t_p[k] = seen;
718 }
719 for j in N.indices() {
720 let mut i_prev = usize::MAX;
721 for i in &A.row_idx_of_col_raw(j)[t_p[j].zx()..] {
722 if i_prev == *i.zx() {
723 i_prev = *i.zx();
724 continue;
725 }
726 i_prev = *i.zx();
727 let i = i.zx();
728 i_w[s_p[i].zx()] = I(*j);
729 s_p[i] += one;
730 i_w[s_p[j].zx()] = I(*i);
731 s_p[j] += one;
732 }
733 }
734 }
735 debug_assert!(s_p[n - 1] == I(pfree));
736 amd_2::<I>(p_e, i_w, len, pfree, perm_inv, perm, control, stack)
737}
738fn preprocess<'out, I: Index>(
739 new_col_ptr: &'out mut [I],
740 new_row_idx: &'out mut [I],
741 A: SymbolicSparseColMatRef<'_, I>,
742 stack: &mut MemStack,
743) -> SymbolicSparseColMatRef<'out, I> {
744 let n = A.nrows();
745 with_dim!(N, n);
746 let I = I::Signed::truncate;
747 let zero = I(0);
748 let one = I(1);
749 let (ref mut w, stack) = stack.collect(repeat_n!(I(0), n));
750 let (ref mut flag, _) = stack.collect(repeat_n!(I(NONE), n));
751 let w = Array::from_mut(w, N);
752 let flag = Array::from_mut(flag, N);
753 let A = A.as_shape(N, N);
754 for j in N.indices() {
755 let j_ = I(*j);
756 for i in A.row_idx_of_col(j) {
757 if flag[i] != j_ {
758 w[i] += one;
759 flag[i] = j_;
760 }
761 }
762 }
763 new_col_ptr[0] = I::from_signed(zero);
764 for (i, [r, r_next]) in iter::zip(
765 N.indices(),
766 windows2(Cell::as_slice_of_cells(Cell::from_mut(new_col_ptr))),
767 ) {
768 r_next.set(r.get() + I::from_signed(w[i]));
769 }
770 w.as_mut()
771 .copy_from_slice(bytemuck::cast_slice(&new_col_ptr[..n]));
772 flag.as_mut().fill(I(NONE));
773 for j in N.indices() {
774 let j_ = I(*j);
775 for i in A.row_idx_of_col(j) {
776 if flag[i] != j_ {
777 new_row_idx[w[i].zx()] = I::from_signed(j_);
778 w[i] += one;
779 flag[i] = j_;
780 }
781 }
782 }
783 unsafe {
784 SymbolicSparseColMatRef::new_unchecked(
785 n,
786 n,
787 &*new_col_ptr,
788 None,
789 &new_row_idx[..new_col_ptr[n].zx()],
790 )
791 }
792}
793#[allow(clippy::comparison_chain)]
794fn aat<I: Index>(
795 len: &mut [I::Signed],
796 A: SymbolicSparseColMatRef<'_, I>,
797 stack: &mut MemStack,
798) -> Result<usize, FaerError> {
799 {
800 with_dim!(N, A.nrows());
801 let I = I::Signed::truncate;
802 let zero = I(0);
803 let one = I(1);
804 let A = A.as_shape(N, N);
805 let n = *N;
806 let t_p = &mut *unsafe { stack.make_raw::<I::Signed>(n).0 };
807 let len = Array::from_mut(len, N);
808 let t_p = Array::from_mut(t_p, N);
809 for k in N.indices() {
810 let mut seen = zero;
811 let mut j_prev = usize::MAX;
812 for j in A.row_idx_of_col(k) {
813 if j_prev == *j {
814 j_prev = *j;
815 continue;
816 }
817 j_prev = *j;
818 if j < k {
819 seen += one;
820 len[j] += one;
821 len[k] += one;
822 } else {
823 if j == k {
824 seen += one;
825 }
826 break;
827 }
828 let mut seen_j = zero;
829 let mut i_prev = usize::MAX;
830 for i in &A.row_idx_of_col_raw(j)[t_p[j].zx()..] {
831 if i_prev == *i.zx() {
832 i_prev = *i.zx();
833 continue;
834 }
835 i_prev = *i.zx();
836 let i = i.zx();
837 if i < k {
838 len[i] += one;
839 len[j] += one;
840 seen_j += one;
841 } else {
842 if i == k {
843 seen_j += one;
844 }
845 break;
846 }
847 }
848 t_p[j] += seen_j;
849 }
850 t_p[k] = seen;
851 }
852 for j in N.indices() {
853 let mut i_prev = usize::MAX;
854 for i in &A.row_idx_of_col_raw(j)[t_p[j].zx()..] {
855 if i_prev == *i.zx() {
856 i_prev = *i.zx();
857 continue;
858 }
859 i_prev = *i.zx();
860 len[i.zx()] += one;
861 len[j] += one;
862 }
863 }
864 }
865 let nzaat = I::Signed::sum_nonnegative(len).map(I::from_signed);
866 nzaat.ok_or(FaerError::IndexOverflow).map(I::zx)
867}
868pub fn order_scratch<I: Index>(n: usize, nnz_upper: usize) -> StackReq {
871 let n_scratch = StackReq::new::<I>(n);
872 let nzaat = nnz_upper.checked_mul(2).unwrap_or(usize::MAX);
873 StackReq::all_of(&[
874 n_scratch,
875 StackReq::new::<I>(nzaat.checked_add(nzaat / 5).unwrap_or(usize::MAX)),
876 n_scratch,
877 n_scratch,
878 n_scratch,
879 n_scratch,
880 n_scratch,
881 n_scratch,
882 n_scratch,
883 n_scratch,
884 n_scratch,
885 n_scratch,
886 ])
887}
888pub fn order_maybe_unsorted_scratch<I: Index>(
891 n: usize,
892 nnz_upper: usize,
893) -> StackReq {
894 StackReq::all_of(&[
895 order_scratch::<I>(n, nnz_upper),
896 StackReq::new::<I>(n + 1),
897 StackReq::new::<I>(nnz_upper),
898 ])
899}
900pub fn order<I: Index>(
904 perm: &mut [I],
905 perm_inv: &mut [I],
906 A: SymbolicSparseColMatRef<'_, I>,
907 control: Control,
908 stack: &mut MemStack,
909) -> Result<FlopCount, FaerError> {
910 let n = perm.len();
911 if n == 0 {
912 return Ok(FlopCount {
913 n_div: 0.0,
914 n_mult_subs_ldl: 0.0,
915 n_mult_subs_lu: 0.0,
916 });
917 }
918 let (ref mut len, stack) =
919 stack.collect(repeat_n!(I::Signed::truncate(0), n));
920 let nzaat = aat(len, A, stack)?;
921 let iwlen = nzaat
922 .checked_add(nzaat / 5)
923 .and_then(|x| x.checked_add(n))
924 .ok_or(FaerError::IndexOverflow)?;
925 Ok(amd_1::<I>(
926 bytemuck::cast_slice_mut(perm),
927 bytemuck::cast_slice_mut(perm_inv),
928 A,
929 len,
930 iwlen,
931 control,
932 stack,
933 ))
934}
935pub fn order_maybe_unsorted<I: Index>(
942 perm: &mut [I],
943 perm_inv: &mut [I],
944 A: SymbolicSparseColMatRef<'_, I>,
945 control: Control,
946 stack: &mut MemStack,
947) -> Result<FlopCount, FaerError> {
948 let n = perm.len();
949 if n == 0 {
950 return Ok(FlopCount {
951 n_div: 0.0,
952 n_mult_subs_ldl: 0.0,
953 n_mult_subs_lu: 0.0,
954 });
955 }
956 let nnz = A.compute_nnz();
957 let (new_col_ptr, stack) = unsafe { stack.make_raw::<I>(n + 1) };
958 let (new_row_idx, stack) = unsafe { stack.make_raw::<I>(nnz) };
959 let A = preprocess(new_col_ptr, new_row_idx, A, stack);
960 order(perm, perm_inv, A, control, stack)
961}
962#[derive(Debug, Copy, Clone, PartialEq)]
964pub struct Control {
965 pub dense: f64,
967 pub aggressive: bool,
969}
970impl Default for Control {
971 #[inline]
972 fn default() -> Self {
973 Self {
974 dense: 10.0,
975 aggressive: true,
976 }
977 }
978}
979#[derive(Default, Debug, Copy, Clone, PartialEq)]
982pub struct FlopCount {
983 pub n_div: f64,
985 pub n_mult_subs_ldl: f64,
987 pub n_mult_subs_lu: f64,
989}
990
991#[cfg(test)]
992mod tests {
993 use super::*;
994 use alloc::alloc::Layout;
995 use core::slice;
996 use std::alloc::System;
997
998 struct GlobalAlloc;
999 #[global_allocator]
1000 static GLOBAL_ALLOC: GlobalAlloc = GlobalAlloc;
1001 unsafe impl core::alloc::GlobalAlloc for GlobalAlloc {
1002 unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
1003 let result = unsafe { System.alloc(layout) };
1004 unsafe {
1006 slice::from_raw_parts_mut(result, layout.size()).fill(0x7F)
1007 };
1008 result
1009 }
1010
1011 unsafe fn realloc(
1012 &self,
1013 ptr: *mut u8,
1014 layout: Layout,
1015 new_size: usize,
1016 ) -> *mut u8 {
1017 unsafe { System.realloc(ptr, layout, new_size) }
1018 }
1019
1020 unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
1021 unsafe { System.dealloc(ptr, layout) }
1022 }
1023 }
1024
1025 #[test]
1026 fn test_gh_258() {
1027 use faer::Side;
1028 use faer::sparse::linalg::cholesky::{
1029 SymmetricOrdering, factorize_symbolic_cholesky,
1030 };
1031 use faer::sparse::{SparseColMat, Triplet};
1032 use std::fs::read_to_string;
1033
1034 let data =
1035 read_to_string("test_data/sparse_cholesky/gh_258.txt").unwrap();
1036 let mut triplets = Vec::<Triplet<u32, u32, f64>>::new();
1037 for line in data.lines() {
1038 let [i, j, a] = Vec::from_iter(line.split(" ")).try_into().unwrap();
1039 triplets.push(Triplet::new(
1040 i.parse().unwrap(),
1041 j.parse().unwrap(),
1042 a.parse().unwrap(),
1043 ));
1044 }
1045 let mat =
1046 SparseColMat::try_new_from_triplets(52, 52, &triplets).unwrap();
1047 _ = factorize_symbolic_cholesky(
1048 mat.symbolic(),
1049 Side::Lower,
1050 SymmetricOrdering::Amd,
1051 <_>::default(),
1052 );
1053 }
1054}