1c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// This file is part of Eigen, a lightweight C++ template library
2c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// for linear algebra.
3c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath//
4c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// Copyright (C) 2010 Gael Guennebaud <gael.guennebaud@inria.fr>
5c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath//
6c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// This Source Code Form is subject to the terms of the Mozilla
7c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// Public License v. 2.0. If a copy of the MPL was not distributed
8c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
9c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
10c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath/*
11c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
12c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan KamathNOTE: this routine has been adapted from the CSparse library:
13c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
14c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan KamathCopyright (c) 2006, Timothy A. Davis.
15c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathhttp://www.cise.ufl.edu/research/sparse/CSparse
16c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
17c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan KamathCSparse is free software; you can redistribute it and/or
18c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathmodify it under the terms of the GNU Lesser General Public
19c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan KamathLicense as published by the Free Software Foundation; either
20c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathversion 2.1 of the License, or (at your option) any later version.
21c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
22c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan KamathCSparse is distributed in the hope that it will be useful,
23c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathbut WITHOUT ANY WARRANTY; without even the implied warranty of
24c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan KamathMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan KamathLesser General Public License for more details.
26c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
27c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan KamathYou should have received a copy of the GNU Lesser General Public
28c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan KamathLicense along with this Module; if not, write to the Free Software
29c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan KamathFoundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
30c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
31c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath*/
32c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
33c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#include "../Core/util/NonMPL2.h"
34c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
35c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#ifndef EIGEN_SPARSE_AMD_H
36c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#define EIGEN_SPARSE_AMD_H
37c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
38c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathnamespace Eigen {
39c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
40c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathnamespace internal {
41c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
42c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathtemplate<typename T> inline T amd_flip(const T& i) { return -i-2; }
43c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathtemplate<typename T> inline T amd_unflip(const T& i) { return i<0 ? amd_flip(i) : i; }
44c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathtemplate<typename T0, typename T1> inline bool amd_marked(const T0* w, const T1& j) { return w[j]<0; }
45c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathtemplate<typename T0, typename T1> inline void amd_mark(const T0* w, const T1& j) { return w[j] = amd_flip(w[j]); }
46c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
47c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath/* clear w */
48c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathtemplate<typename Index>
49c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathstatic int cs_wclear (Index mark, Index lemax, Index *w, Index n)
50c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath{
51c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  Index k;
52c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  if(mark < 2 || (mark + lemax < 0))
53c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  {
54c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    for(k = 0; k < n; k++)
55c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      if(w[k] != 0)
56c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        w[k] = 1;
57c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    mark = 2;
58c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  }
59c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  return (mark);     /* at this point, w[0..n-1] < mark holds */
60c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath}
61c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
62c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath/* depth-first search and postorder of a tree rooted at node j */
63c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathtemplate<typename Index>
64c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan KamathIndex cs_tdfs(Index j, Index k, Index *head, const Index *next, Index *post, Index *stack)
65c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath{
66c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  int i, p, top = 0;
67c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  if(!head || !next || !post || !stack) return (-1);    /* check inputs */
68c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  stack[0] = j;                 /* place j on the stack */
69c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  while (top >= 0)                /* while (stack is not empty) */
70c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  {
71c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    p = stack[top];           /* p = top of stack */
72c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    i = head[p];              /* i = youngest child of p */
73c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    if(i == -1)
74c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    {
75c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      top--;                 /* p has no unordered children left */
76c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      post[k++] = p;        /* node p is the kth postordered node */
77c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    }
78c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    else
79c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    {
80c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      head[p] = next[i];   /* remove i from children of p */
81c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      stack[++top] = i;     /* start dfs on child node i */
82c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    }
83c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  }
84c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  return k;
85c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath}
86c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
87c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
88c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath/** \internal
89c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  * Approximate minimum degree ordering algorithm.
90c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  * \returns the permutation P reducing the fill-in of the input matrix \a C
91c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  * The input matrix \a C must be a selfadjoint compressed column major SparseMatrix object. Both the upper and lower parts have to be stored, but the diagonal entries are optional.
92c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  * On exit the values of C are destroyed */
93c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathtemplate<typename Scalar, typename Index>
94c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamathvoid minimum_degree_ordering(SparseMatrix<Scalar,ColMajor,Index>& C, PermutationMatrix<Dynamic,Dynamic,Index>& perm)
95c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath{
96c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  using std::sqrt;
97c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  typedef SparseMatrix<Scalar,ColMajor,Index> CCS;
98c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
99c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  int d, dk, dext, lemax = 0, e, elenk, eln, i, j, k, k1,
100c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      k2, k3, jlast, ln, dense, nzmax, mindeg = 0, nvi, nvj, nvk, mark, wnvi,
101c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      ok, nel = 0, p, p1, p2, p3, p4, pj, pk, pk1, pk2, pn, q, t;
102c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  unsigned int h;
103c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
104c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  Index n = C.cols();
105c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  dense = std::max<Index> (16, Index(10 * sqrt(double(n))));   /* find dense threshold */
106c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  dense = std::min<Index> (n-2, dense);
107c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
108c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  Index cnz = C.nonZeros();
109c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  perm.resize(n+1);
110c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  t = cnz + cnz/5 + 2*n;                 /* add elbow room to C */
111c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  C.resizeNonZeros(t);
112c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
113c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  Index* W       = new Index[8*(n+1)]; /* get workspace */
114c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  Index* len     = W;
115c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  Index* nv      = W +   (n+1);
116c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  Index* next    = W + 2*(n+1);
117c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  Index* head    = W + 3*(n+1);
118c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  Index* elen    = W + 4*(n+1);
119c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  Index* degree  = W + 5*(n+1);
120c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  Index* w       = W + 6*(n+1);
121c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  Index* hhead   = W + 7*(n+1);
122c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  Index* last    = perm.indices().data();                              /* use P as workspace for last */
123c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
124c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  /* --- Initialize quotient graph ---------------------------------------- */
125c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  Index* Cp = C.outerIndexPtr();
126c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  Index* Ci = C.innerIndexPtr();
127c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  for(k = 0; k < n; k++)
128c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    len[k] = Cp[k+1] - Cp[k];
129c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  len[n] = 0;
130c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  nzmax = t;
131c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
132c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  for(i = 0; i <= n; i++)
133c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  {
134c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    head[i]   = -1;                     // degree list i is empty
135c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    last[i]   = -1;
136c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    next[i]   = -1;
137c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    hhead[i]  = -1;                     // hash list i is empty
138c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    nv[i]     = 1;                      // node i is just one node
139c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    w[i]      = 1;                      // node i is alive
140c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    elen[i]   = 0;                      // Ek of node i is empty
141c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    degree[i] = len[i];                 // degree of node i
142c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  }
143c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  mark = internal::cs_wclear<Index>(0, 0, w, n);         /* clear w */
144c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  elen[n] = -2;                         /* n is a dead element */
145c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  Cp[n] = -1;                           /* n is a root of assembly tree */
146c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  w[n] = 0;                             /* n is a dead element */
147c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
148c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  /* --- Initialize degree lists ------------------------------------------ */
149c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  for(i = 0; i < n; i++)
150c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  {
151c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    d = degree[i];
152c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    if(d == 0)                         /* node i is empty */
153c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    {
154c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      elen[i] = -2;                 /* element i is dead */
155c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      nel++;
156c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      Cp[i] = -1;                   /* i is a root of assembly tree */
157c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      w[i] = 0;
158c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    }
159c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    else if(d > dense)                 /* node i is dense */
160c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    {
161c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      nv[i] = 0;                    /* absorb i into element n */
162c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      elen[i] = -1;                 /* node i is dead */
163c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      nel++;
164c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      Cp[i] = amd_flip (n);
165c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      nv[n]++;
166c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    }
167c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    else
168c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    {
169c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      if(head[d] != -1) last[head[d]] = i;
170c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      next[i] = head[d];           /* put node i in degree list d */
171c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      head[d] = i;
172c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    }
173c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  }
174c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
175c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  while (nel < n)                         /* while (selecting pivots) do */
176c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  {
177c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    /* --- Select node of minimum approximate degree -------------------- */
178c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    for(k = -1; mindeg < n && (k = head[mindeg]) == -1; mindeg++) {}
179c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    if(next[k] != -1) last[next[k]] = -1;
180c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    head[mindeg] = next[k];          /* remove k from degree list */
181c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    elenk = elen[k];                  /* elenk = |Ek| */
182c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    nvk = nv[k];                      /* # of nodes k represents */
183c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    nel += nvk;                        /* nv[k] nodes of A eliminated */
184c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
185c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    /* --- Garbage collection ------------------------------------------- */
186c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    if(elenk > 0 && cnz + mindeg >= nzmax)
187c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    {
188c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      for(j = 0; j < n; j++)
189c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      {
190c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        if((p = Cp[j]) >= 0)      /* j is a live node or element */
191c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        {
192c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          Cp[j] = Ci[p];          /* save first entry of object */
193c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          Ci[p] = amd_flip (j);    /* first entry is now amd_flip(j) */
194c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        }
195c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      }
196c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      for(q = 0, p = 0; p < cnz; ) /* scan all of memory */
197c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      {
198c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        if((j = amd_flip (Ci[p++])) >= 0)  /* found object j */
199c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        {
200c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          Ci[q] = Cp[j];       /* restore first entry of object */
201c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          Cp[j] = q++;          /* new pointer to object j */
202c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          for(k3 = 0; k3 < len[j]-1; k3++) Ci[q++] = Ci[p++];
203c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        }
204c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      }
205c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      cnz = q;                       /* Ci[cnz...nzmax-1] now free */
206c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    }
207c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
208c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    /* --- Construct new element ---------------------------------------- */
209c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    dk = 0;
210c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    nv[k] = -nvk;                     /* flag k as in Lk */
211c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    p = Cp[k];
212c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    pk1 = (elenk == 0) ? p : cnz;      /* do in place if elen[k] == 0 */
213c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    pk2 = pk1;
214c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    for(k1 = 1; k1 <= elenk + 1; k1++)
215c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    {
216c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      if(k1 > elenk)
217c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      {
218c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        e = k;                     /* search the nodes in k */
219c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        pj = p;                    /* list of nodes starts at Ci[pj]*/
220c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        ln = len[k] - elenk;      /* length of list of nodes in k */
221c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      }
222c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      else
223c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      {
224c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        e = Ci[p++];              /* search the nodes in e */
225c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        pj = Cp[e];
226c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        ln = len[e];              /* length of list of nodes in e */
227c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      }
228c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      for(k2 = 1; k2 <= ln; k2++)
229c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      {
230c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        i = Ci[pj++];
231c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        if((nvi = nv[i]) <= 0) continue; /* node i dead, or seen */
232c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        dk += nvi;                 /* degree[Lk] += size of node i */
233c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        nv[i] = -nvi;             /* negate nv[i] to denote i in Lk*/
234c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        Ci[pk2++] = i;            /* place i in Lk */
235c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        if(next[i] != -1) last[next[i]] = last[i];
236c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        if(last[i] != -1)         /* remove i from degree list */
237c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        {
238c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          next[last[i]] = next[i];
239c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        }
240c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        else
241c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        {
242c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          head[degree[i]] = next[i];
243c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        }
244c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      }
245c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      if(e != k)
246c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      {
247c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        Cp[e] = amd_flip (k);      /* absorb e into k */
248c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        w[e] = 0;                 /* e is now a dead element */
249c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      }
250c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    }
251c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    if(elenk != 0) cnz = pk2;         /* Ci[cnz...nzmax] is free */
252c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    degree[k] = dk;                   /* external degree of k - |Lk\i| */
253c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    Cp[k] = pk1;                      /* element k is in Ci[pk1..pk2-1] */
254c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    len[k] = pk2 - pk1;
255c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    elen[k] = -2;                     /* k is now an element */
256c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
257c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    /* --- Find set differences ----------------------------------------- */
258c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    mark = internal::cs_wclear<Index>(mark, lemax, w, n);  /* clear w if necessary */
259c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    for(pk = pk1; pk < pk2; pk++)    /* scan 1: find |Le\Lk| */
260c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    {
261c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      i = Ci[pk];
262c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      if((eln = elen[i]) <= 0) continue;/* skip if elen[i] empty */
263c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      nvi = -nv[i];                      /* nv[i] was negated */
264c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      wnvi = mark - nvi;
265c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      for(p = Cp[i]; p <= Cp[i] + eln - 1; p++)  /* scan Ei */
266c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      {
267c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        e = Ci[p];
268c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        if(w[e] >= mark)
269c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        {
270c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          w[e] -= nvi;          /* decrement |Le\Lk| */
271c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        }
272c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        else if(w[e] != 0)        /* ensure e is a live element */
273c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        {
274c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          w[e] = degree[e] + wnvi; /* 1st time e seen in scan 1 */
275c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        }
276c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      }
277c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    }
278c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
279c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    /* --- Degree update ------------------------------------------------ */
280c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    for(pk = pk1; pk < pk2; pk++)    /* scan2: degree update */
281c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    {
282c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      i = Ci[pk];                   /* consider node i in Lk */
283c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      p1 = Cp[i];
284c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      p2 = p1 + elen[i] - 1;
285c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      pn = p1;
286c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      for(h = 0, d = 0, p = p1; p <= p2; p++)    /* scan Ei */
287c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      {
288c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        e = Ci[p];
289c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        if(w[e] != 0)             /* e is an unabsorbed element */
290c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        {
291c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          dext = w[e] - mark;   /* dext = |Le\Lk| */
292c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          if(dext > 0)
293c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          {
294c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath            d += dext;         /* sum up the set differences */
295c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath            Ci[pn++] = e;     /* keep e in Ei */
296c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath            h += e;            /* compute the hash of node i */
297c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          }
298c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          else
299c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          {
300c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath            Cp[e] = amd_flip (k);  /* aggressive absorb. e->k */
301c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath            w[e] = 0;             /* e is a dead element */
302c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          }
303c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        }
304c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      }
305c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      elen[i] = pn - p1 + 1;        /* elen[i] = |Ei| */
306c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      p3 = pn;
307c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      p4 = p1 + len[i];
308c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      for(p = p2 + 1; p < p4; p++) /* prune edges in Ai */
309c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      {
310c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        j = Ci[p];
311c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        if((nvj = nv[j]) <= 0) continue; /* node j dead or in Lk */
312c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        d += nvj;                  /* degree(i) += |j| */
313c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        Ci[pn++] = j;             /* place j in node list of i */
314c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        h += j;                    /* compute hash for node i */
315c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      }
316c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      if(d == 0)                     /* check for mass elimination */
317c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      {
318c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        Cp[i] = amd_flip (k);      /* absorb i into k */
319c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        nvi = -nv[i];
320c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        dk -= nvi;                 /* |Lk| -= |i| */
321c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        nvk += nvi;                /* |k| += nv[i] */
322c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        nel += nvi;
323c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        nv[i] = 0;
324c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        elen[i] = -1;             /* node i is dead */
325c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      }
326c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      else
327c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      {
328c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        degree[i] = std::min<Index> (degree[i], d);   /* update degree(i) */
329c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        Ci[pn] = Ci[p3];         /* move first node to end */
330c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        Ci[p3] = Ci[p1];         /* move 1st el. to end of Ei */
331c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        Ci[p1] = k;               /* add k as 1st element in of Ei */
332c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        len[i] = pn - p1 + 1;     /* new len of adj. list of node i */
333c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        h %= n;                    /* finalize hash of i */
334c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        next[i] = hhead[h];      /* place i in hash bucket */
335c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        hhead[h] = i;
336c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        last[i] = h;              /* save hash of i in last[i] */
337c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      }
338c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    }                                   /* scan2 is done */
339c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    degree[k] = dk;                   /* finalize |Lk| */
340c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    lemax = std::max<Index>(lemax, dk);
341c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    mark = internal::cs_wclear<Index>(mark+lemax, lemax, w, n);    /* clear w */
342c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
343c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    /* --- Supernode detection ------------------------------------------ */
344c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    for(pk = pk1; pk < pk2; pk++)
345c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    {
346c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      i = Ci[pk];
347c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      if(nv[i] >= 0) continue;         /* skip if i is dead */
348c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      h = last[i];                      /* scan hash bucket of node i */
349c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      i = hhead[h];
350c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      hhead[h] = -1;                    /* hash bucket will be empty */
351c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      for(; i != -1 && next[i] != -1; i = next[i], mark++)
352c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      {
353c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        ln = len[i];
354c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        eln = elen[i];
355c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        for(p = Cp[i]+1; p <= Cp[i] + ln-1; p++) w[Ci[p]] = mark;
356c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        jlast = i;
357c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        for(j = next[i]; j != -1; ) /* compare i with all j */
358c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        {
359c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          ok = (len[j] == ln) && (elen[j] == eln);
360c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          for(p = Cp[j] + 1; ok && p <= Cp[j] + ln - 1; p++)
361c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          {
362c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath            if(w[Ci[p]] != mark) ok = 0;    /* compare i and j*/
363c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          }
364c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          if(ok)                     /* i and j are identical */
365c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          {
366c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath            Cp[j] = amd_flip (i);  /* absorb j into i */
367c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath            nv[i] += nv[j];
368c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath            nv[j] = 0;
369c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath            elen[j] = -1;         /* node j is dead */
370c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath            j = next[j];          /* delete j from hash bucket */
371c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath            next[jlast] = j;
372c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          }
373c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          else
374c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          {
375c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath            jlast = j;             /* j and i are different */
376c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath            j = next[j];
377c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath          }
378c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath        }
379c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      }
380c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    }
381c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
382c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    /* --- Finalize new element------------------------------------------ */
383c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    for(p = pk1, pk = pk1; pk < pk2; pk++)   /* finalize Lk */
384c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    {
385c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      i = Ci[pk];
386c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      if((nvi = -nv[i]) <= 0) continue;/* skip if i is dead */
387c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      nv[i] = nvi;                      /* restore nv[i] */
388c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      d = degree[i] + dk - nvi;         /* compute external degree(i) */
389c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      d = std::min<Index> (d, n - nel - nvi);
390c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      if(head[d] != -1) last[head[d]] = i;
391c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      next[i] = head[d];               /* put i back in degree list */
392c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      last[i] = -1;
393c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      head[d] = i;
394c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      mindeg = std::min<Index> (mindeg, d);       /* find new minimum degree */
395c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      degree[i] = d;
396c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      Ci[p++] = i;                      /* place i in Lk */
397c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    }
398c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    nv[k] = nvk;                      /* # nodes absorbed into k */
399c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    if((len[k] = p-pk1) == 0)         /* length of adj list of element k*/
400c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    {
401c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      Cp[k] = -1;                   /* k is a root of the tree */
402c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      w[k] = 0;                     /* k is now a dead element */
403c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    }
404c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    if(elenk != 0) cnz = p;           /* free unused space in Lk */
405c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  }
406c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
407c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  /* --- Postordering ----------------------------------------------------- */
408c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  for(i = 0; i < n; i++) Cp[i] = amd_flip (Cp[i]);/* fix assembly tree */
409c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  for(j = 0; j <= n; j++) head[j] = -1;
410c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  for(j = n; j >= 0; j--)              /* place unordered nodes in lists */
411c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  {
412c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    if(nv[j] > 0) continue;          /* skip if j is an element */
413c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    next[j] = head[Cp[j]];          /* place j in list of its parent */
414c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    head[Cp[j]] = j;
415c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  }
416c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  for(e = n; e >= 0; e--)              /* place elements in lists */
417c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  {
418c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    if(nv[e] <= 0) continue;         /* skip unless e is an element */
419c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    if(Cp[e] != -1)
420c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    {
421c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      next[e] = head[Cp[e]];      /* place e in list of its parent */
422c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath      head[Cp[e]] = e;
423c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    }
424c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  }
425c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  for(k = 0, i = 0; i <= n; i++)       /* postorder the assembly tree */
426c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  {
427c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath    if(Cp[i] == -1) k = internal::cs_tdfs<Index>(i, k, head, next, perm.indices().data(), w);
428c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  }
429c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
430c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  perm.indices().conservativeResize(n);
431c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
432c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath  delete[] W;
433c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath}
434c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
435c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath} // namespace internal
436c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
437c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath} // end namespace Eigen
438c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath
439c981c48f5bc9aefeffc0bcb0cc3934c2fae179ddNarayan Kamath#endif // EIGEN_SPARSE_AMD_H
440