22#ifndef EIGEN_SPARSE_AMD_H
23#define EIGEN_SPARSE_AMD_H
26#include "./InternalHeaderCheck.h"
33inline T amd_flip(
const T& i) {
38template <
typename StorageIndex>
39static StorageIndex cs_wclear(StorageIndex mark, StorageIndex lemax, StorageIndex* w, StorageIndex n) {
41 if (mark < 2 || (mark + lemax < 0)) {
42 for (k = 0; k < n; k++)
43 if (w[k] != 0) w[k] = 1;
50template <
typename StorageIndex>
51StorageIndex cs_tdfs(StorageIndex j, StorageIndex k, StorageIndex* head,
const StorageIndex* next, StorageIndex* post,
52 StorageIndex* stack) {
53 StorageIndex i, p, top = 0;
54 if (!head || !next || !post || !stack)
return (-1);
80template <
typename Scalar,
typename StorageIndex>
81void minimum_degree_ordering(SparseMatrix<Scalar, ColMajor, StorageIndex>& C,
82 PermutationMatrix<Dynamic, Dynamic, StorageIndex>& perm) {
85 StorageIndex d, dk, dext, lemax = 0, e, elenk, eln, i, j, k, k1, k2, k3, jlast, ln, dense, nzmax, mindeg = 0, nvi,
86 nvj, nvk, mark, wnvi, ok, nel = 0, p, p1, p2, p3, p4, pj, pk, pk1, pk2, pn, q, t, h;
88 StorageIndex n = StorageIndex(C.cols());
89 dense = std::max<StorageIndex>(16, StorageIndex(10 * sqrt(
double(n))));
90 dense = (std::min)(n - 2, dense);
92 StorageIndex cnz = StorageIndex(C.nonZeros());
94 t = cnz + cnz / 5 + 2 * n;
98 ei_declare_aligned_stack_constructed_variable(StorageIndex, W, 8 * (n + 1), 0);
99 StorageIndex* len = W;
100 StorageIndex* nv = W + (n + 1);
101 StorageIndex* next = W + 2 * (n + 1);
102 StorageIndex* head = W + 3 * (n + 1);
103 StorageIndex* elen = W + 4 * (n + 1);
104 StorageIndex* degree = W + 5 * (n + 1);
105 StorageIndex* w = W + 6 * (n + 1);
106 StorageIndex* hhead = W + 7 * (n + 1);
107 StorageIndex* last = perm.indices().data();
110 StorageIndex* Cp = C.outerIndexPtr();
111 StorageIndex* Ci = C.innerIndexPtr();
112 for (k = 0; k < n; k++) len[k] = Cp[k + 1] - Cp[k];
116 for (i = 0; i <= n; i++) {
126 mark = internal::cs_wclear<StorageIndex>(0, 0, w, n);
129 for (i = 0; i < n; i++) {
130 bool has_diag =
false;
131 for (p = Cp[i]; p < Cp[i + 1]; ++p)
138 if (d == 1 && has_diag)
144 }
else if (d > dense || !has_diag)
152 if (head[d] != -1) last[head[d]] = i;
165 for (k = -1; mindeg < n && (k = head[mindeg]) == -1; mindeg++) {
167 if (next[k] != -1) last[next[k]] = -1;
168 head[mindeg] = next[k];
174 if (elenk > 0 && cnz + mindeg >= nzmax) {
175 for (j = 0; j < n; j++) {
176 if ((p = Cp[j]) >= 0)
182 for (q = 0, p = 0; p < cnz;)
184 if ((j = amd_flip(Ci[p++])) >= 0)
188 for (k3 = 0; k3 < len[j] - 1; k3++) Ci[q++] = Ci[p++];
198 pk1 = (elenk == 0) ? p : cnz;
200 for (k1 = 1; k1 <= elenk + 1; k1++) {
210 for (k2 = 1; k2 <= ln; k2++) {
212 if ((nvi = nv[i]) <= 0)
continue;
216 if (next[i] != -1) last[next[i]] = last[i];
219 next[last[i]] = next[i];
221 head[degree[i]] = next[i];
229 if (elenk != 0) cnz = pk2;
236 mark = internal::cs_wclear<StorageIndex>(mark, lemax, w, n);
237 for (pk = pk1; pk < pk2; pk++)
240 if ((eln = elen[i]) <= 0)
continue;
243 for (p = Cp[i]; p <= Cp[i] + eln - 1; p++)
248 }
else if (w[e] != 0)
250 w[e] = degree[e] + wnvi;
256 for (pk = pk1; pk < pk2; pk++)
260 p2 = p1 + elen[i] - 1;
262 for (h = 0, d = 0, p = p1; p <= p2; p++)
278 elen[i] = pn - p1 + 1;
281 for (p = p2 + 1; p < p4; p++)
284 if ((nvj = nv[j]) <= 0)
continue;
299 degree[i] = std::min<StorageIndex>(degree[i], d);
303 len[i] = pn - p1 + 1;
311 lemax = std::max<StorageIndex>(lemax, dk);
312 mark = internal::cs_wclear<StorageIndex>(mark + lemax, lemax, w, n);
315 for (pk = pk1; pk < pk2; pk++) {
317 if (nv[i] >= 0)
continue;
321 for (; i != -1 && next[i] != -1; i = next[i], mark++) {
324 for (p = Cp[i] + 1; p <= Cp[i] + ln - 1; p++) w[Ci[p]] = mark;
326 for (j = next[i]; j != -1;)
328 ok = (len[j] == ln) && (elen[j] == eln);
329 for (p = Cp[j] + 1; ok && p <= Cp[j] + ln - 1; p++) {
330 if (w[Ci[p]] != mark) ok = 0;
349 for (p = pk1, pk = pk1; pk < pk2; pk++)
352 if ((nvi = -nv[i]) <= 0)
continue;
354 d = degree[i] + dk - nvi;
355 d = std::min<StorageIndex>(d, n - nel - nvi);
356 if (head[d] != -1) last[head[d]] = i;
360 mindeg = std::min<StorageIndex>(mindeg, d);
365 if ((len[k] = p - pk1) == 0)
370 if (elenk != 0) cnz = p;
374 for (i = 0; i < n; i++) Cp[i] = amd_flip(Cp[i]);
375 for (j = 0; j <= n; j++) head[j] = -1;
376 for (j = n; j >= 0; j--)
378 if (nv[j] > 0)
continue;
379 next[j] = head[Cp[j]];
382 for (e = n; e >= 0; e--)
384 if (nv[e] <= 0)
continue;
386 next[e] = head[Cp[e]];
390 for (k = 0, i = 0; i <= n; i++)
392 if (Cp[i] == -1) k = internal::cs_tdfs<StorageIndex>(i, k, head, next, perm.indices().data(), w);
395 perm.indices().conservativeResize(n);