conspire/math/sparse/matrix/amd/
mod.rs1#[cfg(test)]
2mod test;
3
4use super::CscMatrix;
5
6const NONE: isize = -1;
7
8fn flip(i: isize) -> isize {
9 -i - 2
10}
11
12fn wclear(mark: isize, lemax: isize, w: &mut [isize], n: usize) -> isize {
13 if mark < 2 || mark + lemax < 0 {
14 w[..n].iter_mut().for_each(|w_i| {
15 if *w_i != 0 {
16 *w_i = 1
17 }
18 });
19 2
20 } else {
21 mark
22 }
23}
24
25fn tdfs(
26 root: isize,
27 mut count: usize,
28 head: &mut [isize],
29 next: &[isize],
30 post: &mut [isize],
31 stack: &mut [isize],
32) -> usize {
33 let mut top = 0_isize;
34 stack[0] = root;
35 while top >= 0 {
36 let p = stack[top as usize];
37 let i = head[p as usize];
38 if i == NONE {
39 top -= 1;
40 post[count] = p;
41 count += 1;
42 } else {
43 head[p as usize] = next[i as usize];
44 top += 1;
45 stack[top as usize] = i;
46 }
47 }
48 count
49}
50
51impl CscMatrix {
52 pub fn amd(&self) -> Vec<usize> {
54 let n = self.height();
55 assert_eq!(n, self.width());
56 if n == 0 {
57 return Vec::new();
58 }
59 let transpose = self.transpose();
60 let mut cp = vec![0_isize; n + 1];
61 let mut ci = Vec::<isize>::new();
62 let mut len = vec![0_isize; n + 1];
63 (0..n).for_each(|j| {
64 cp[j] = ci.len() as isize;
65 let mut a = self.column(j).map(|(i, _)| i).peekable();
66 let mut b = transpose.column(j).map(|(i, _)| i).peekable();
67 loop {
68 let i = match (a.peek(), b.peek()) {
69 (Some(&x), Some(&y)) => {
70 if x <= y {
71 if x == y {
72 b.next();
73 }
74 a.next();
75 x
76 } else {
77 b.next();
78 y
79 }
80 }
81 (Some(&x), None) => {
82 a.next();
83 x
84 }
85 (None, Some(&y)) => {
86 b.next();
87 y
88 }
89 (None, None) => break,
90 };
91 if i != j {
92 ci.push(i as isize);
93 }
94 }
95 len[j] = ci.len() as isize - cp[j];
96 });
97 let mut cnz = ci.len() as isize;
98 let nzmax = cnz + cnz / 5 + 2 * n as isize;
99 ci.resize(nzmax as usize, 0);
100 let dense = 16
101 .max((10.0 * (n as f64).sqrt()) as isize)
102 .min(n as isize - 2);
103 let mut nv = vec![1_isize; n + 1];
104 let mut w = vec![1_isize; n + 1];
105 let mut elen = vec![0_isize; n + 1];
106 let mut degree = len.clone();
107 let mut head = vec![NONE; n + 1];
108 let mut next = vec![NONE; n + 1];
109 let mut last = vec![NONE; n + 1];
110 let mut hhead = vec![NONE; n + 1];
111 cp[n] = NONE;
112 elen[n] = -2;
113 w[n] = 0;
114 let mut nel = 0_isize;
115 let mut mindeg = 0_usize;
116 let mut lemax = 0_isize;
117 let mut mark = wclear(0, 0, &mut w, n);
118 (0..n).for_each(|i| {
119 let d = degree[i];
120 if d == 0 {
121 elen[i] = -2;
122 nel += 1;
123 cp[i] = NONE;
124 w[i] = 0;
125 } else if d > dense {
126 nv[i] = 0;
127 elen[i] = NONE;
128 nel += 1;
129 cp[i] = flip(n as isize);
130 nv[n] += 1;
131 } else {
132 if head[d as usize] != NONE {
133 last[head[d as usize] as usize] = i as isize;
134 }
135 next[i] = head[d as usize];
136 head[d as usize] = i as isize;
137 }
138 });
139 while nel < n as isize {
140 let mut pivot = NONE;
141 while mindeg < n {
142 pivot = head[mindeg];
143 if pivot != NONE {
144 break;
145 }
146 mindeg += 1;
147 }
148 let k = pivot as usize;
149 if next[k] != NONE {
150 last[next[k] as usize] = NONE;
151 }
152 head[mindeg] = next[k];
153 let elenk = elen[k];
154 let mut nvk = nv[k];
155 nel += nvk;
156 if elenk > 0 && cnz + mindeg as isize >= nzmax {
157 (0..n).for_each(|j| {
158 let p = cp[j];
159 if p >= 0 {
160 cp[j] = ci[p as usize];
161 ci[p as usize] = flip(j as isize);
162 }
163 });
164 let mut q = 0_usize;
165 let mut p = 0_usize;
166 while (p as isize) < cnz {
167 let j = flip(ci[p]);
168 p += 1;
169 if j >= 0 {
170 let j = j as usize;
171 ci[q] = cp[j];
172 cp[j] = q as isize;
173 q += 1;
174 (0..len[j] - 1).for_each(|_| {
175 ci[q] = ci[p];
176 q += 1;
177 p += 1;
178 });
179 }
180 }
181 cnz = q as isize;
182 }
183 let mut dk = 0_isize;
184 nv[k] = -nvk;
185 let mut p = cp[k];
186 let pk1 = if elenk == 0 { p } else { cnz };
187 let mut pk2 = pk1;
188 for k1 in 1..=(elenk + 1) {
189 let (e, mut pj, ln) = if k1 > elenk {
190 (k, p, len[k] - elenk)
191 } else {
192 let e = ci[p as usize] as usize;
193 p += 1;
194 (e, cp[e], len[e])
195 };
196 (0..ln).for_each(|_| {
197 let i = ci[pj as usize] as usize;
198 pj += 1;
199 let nvi = nv[i];
200 if nvi > 0 {
201 dk += nvi;
202 nv[i] = -nvi;
203 ci[pk2 as usize] = i as isize;
204 pk2 += 1;
205 if next[i] != NONE {
206 last[next[i] as usize] = last[i];
207 }
208 if last[i] != NONE {
209 next[last[i] as usize] = next[i];
210 } else {
211 head[degree[i] as usize] = next[i];
212 }
213 }
214 });
215 if e != k {
216 cp[e] = flip(k as isize);
217 w[e] = 0;
218 }
219 }
220 if elenk != 0 {
221 cnz = pk2;
222 }
223 degree[k] = dk;
224 cp[k] = pk1;
225 len[k] = pk2 - pk1;
226 elen[k] = -2;
227 mark = wclear(mark, lemax, &mut w, n);
228 (pk1..pk2).for_each(|pk| {
229 let i = ci[pk as usize] as usize;
230 let eln = elen[i];
231 if eln > 0 {
232 let nvi = -nv[i];
233 let wnvi = mark - nvi;
234 (cp[i]..cp[i] + eln).for_each(|p| {
235 let e = ci[p as usize] as usize;
236 if w[e] >= mark {
237 w[e] -= nvi;
238 } else if w[e] != 0 {
239 w[e] = degree[e] + wnvi;
240 }
241 });
242 }
243 });
244 (pk1..pk2).for_each(|pk| {
245 let i = ci[pk as usize] as usize;
246 let p1 = cp[i];
247 let p2 = p1 + elen[i];
248 let mut pn = p1;
249 let mut hash = 0_usize;
250 let mut d = 0_isize;
251 (p1..p2).for_each(|p| {
252 let e = ci[p as usize] as usize;
253 if w[e] != 0 {
254 let dext = w[e] - mark;
255 if dext > 0 {
256 d += dext;
257 ci[pn as usize] = e as isize;
258 pn += 1;
259 hash += e;
260 } else {
261 cp[e] = flip(k as isize);
262 w[e] = 0;
263 }
264 }
265 });
266 elen[i] = pn - p1 + 1;
267 let p3 = pn;
268 let p4 = p1 + len[i];
269 (p2..p4).for_each(|p| {
270 let j = ci[p as usize] as usize;
271 let nvj = nv[j];
272 if nvj > 0 {
273 d += nvj;
274 ci[pn as usize] = j as isize;
275 pn += 1;
276 hash += j;
277 }
278 });
279 if d == 0 {
280 cp[i] = flip(k as isize);
281 let nvi = -nv[i];
282 dk -= nvi;
283 nvk += nvi;
284 nel += nvi;
285 nv[i] = 0;
286 elen[i] = NONE;
287 } else {
288 degree[i] = degree[i].min(d);
289 ci[pn as usize] = ci[p3 as usize];
290 ci[p3 as usize] = ci[p1 as usize];
291 ci[p1 as usize] = k as isize;
292 len[i] = pn - p1 + 1;
293 let hash = hash % n;
294 next[i] = hhead[hash];
295 hhead[hash] = i as isize;
296 last[i] = hash as isize;
297 }
298 });
299 degree[k] = dk;
300 lemax = lemax.max(dk);
301 mark = wclear(mark + lemax, lemax, &mut w, n);
302 (pk1..pk2).for_each(|pk| {
303 let i = ci[pk as usize] as usize;
304 if nv[i] < 0 {
305 let hash = last[i] as usize;
306 let mut i = hhead[hash];
307 hhead[hash] = NONE;
308 while i != NONE && next[i as usize] != NONE {
309 let iu = i as usize;
310 let ln = len[iu];
311 let eln = elen[iu];
312 (cp[iu] + 1..cp[iu] + ln).for_each(|p| w[ci[p as usize] as usize] = mark);
313 let mut jlast = iu;
314 let mut j = next[iu];
315 while j != NONE {
316 let ju = j as usize;
317 let mut ok = len[ju] == ln && elen[ju] == eln;
318 let mut p = cp[ju] + 1;
319 while ok && p < cp[ju] + ln {
320 if w[ci[p as usize] as usize] != mark {
321 ok = false;
322 }
323 p += 1;
324 }
325 if ok {
326 cp[ju] = flip(i);
327 nv[iu] += nv[ju];
328 nv[ju] = 0;
329 elen[ju] = NONE;
330 j = next[ju];
331 next[jlast] = j;
332 } else {
333 jlast = ju;
334 j = next[ju];
335 }
336 }
337 i = next[iu];
338 mark += 1;
339 }
340 }
341 });
342 let mut p = pk1;
343 (pk1..pk2).for_each(|pk| {
344 let i = ci[pk as usize] as usize;
345 let nvi = -nv[i];
346 if nvi > 0 {
347 nv[i] = nvi;
348 let d = (degree[i] + dk - nvi).min(n as isize - nel - nvi);
349 if head[d as usize] != NONE {
350 last[head[d as usize] as usize] = i as isize;
351 }
352 next[i] = head[d as usize];
353 last[i] = NONE;
354 head[d as usize] = i as isize;
355 mindeg = mindeg.min(d as usize);
356 degree[i] = d;
357 ci[p as usize] = i as isize;
358 p += 1;
359 }
360 });
361 nv[k] = nvk;
362 len[k] = p - pk1;
363 if len[k] == 0 {
364 cp[k] = NONE;
365 w[k] = 0;
366 }
367 if elenk != 0 {
368 cnz = p;
369 }
370 }
371 (0..=n).for_each(|i| cp[i] = flip(cp[i]));
372 head.iter_mut().for_each(|head_i| *head_i = NONE);
373 (0..n).rev().for_each(|j| {
374 if nv[j] <= 0 {
375 next[j] = head[cp[j] as usize];
376 head[cp[j] as usize] = j as isize;
377 }
378 });
379 (0..=n).rev().for_each(|e| {
380 if nv[e] > 0 && cp[e] != NONE {
381 next[e] = head[cp[e] as usize];
382 head[cp[e] as usize] = e as isize;
383 }
384 });
385 let mut post = vec![0_isize; n + 1];
386 let mut stack = vec![0_isize; n + 1];
387 let mut count = 0_usize;
388 (0..=n).for_each(|i| {
389 if cp[i] == NONE {
390 count = tdfs(i as isize, count, &mut head, &next, &mut post, &mut stack);
391 }
392 });
393 post.into_iter()
394 .filter(|&i| i != n as isize)
395 .map(|i| i as usize)
396 .collect()
397 }
398}