Amesos Package Browser (Single Doxygen Collection)  Development
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
amesos_camd_l2.c
Go to the documentation of this file.
1 /* ========================================================================= */
2 /* === CAMD_2 ============================================================== */
3 /* ========================================================================= */
4 
5 /* ------------------------------------------------------------------------- */
6 /* CAMD, Copyright (c) Timothy A. Davis, Yanqing Chen, */
7 /* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */
8 /* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */
9 /* web: http://www.cise.ufl.edu/research/sparse/camd */
10 /* ------------------------------------------------------------------------- */
11 
12 /* CAMD_2: performs the CAMD ordering on a symmetric sparse matrix A, followed
13  * by a postordering (via depth-first search) of the assembly tree using the
14  * CAMD_postorder routine.
15  */
16 
17 /* ========================================================================= */
18 /* === Macros and definitions ============================================== */
19 /* ========================================================================= */
20 
21 /* True if node i is in the current Constraint Set */
22 #define IsInCurrentSet(C,i,curC) ((C == NULL) ? 1 : (C [i] == curC))
23 
24 /* True if i and j are in the same Constraint Set */
25 #define InSameConstraintSet(C,i,j) ((C == NULL) ? 1 : (C [i] == C [j]))
26 
27 /* This file should make the long int version of CAMD */
28 #define DLONG 1
29 
30 #include "amesos_camd_internal.h"
31 
32 /* ========================================================================= */
33 /* === clear_flag ========================================================== */
34 /* ========================================================================= */
35 
36 static Int amesos_clear_flag (Int wflg, Int wbig, Int W [ ], Int n)
37 {
38  Int x ;
39  if (wflg < 2 || wflg >= wbig)
40  {
41  for (x = 0 ; x < n ; x++)
42  {
43  if (W [x] != 0) W [x] = 1 ;
44  }
45  wflg = 2 ;
46  }
47  /* at this point, W [0..n-1] < wflg holds */
48  return (wflg) ;
49 }
50 
51 
52 /* ========================================================================= */
53 /* === CAMD_2 ============================================================== */
54 /* ========================================================================= */
55 
56 GLOBAL void CAMD_2
57 (
58  Int n, /* A is n-by-n, where n > 0 */
59  Int Pe [ ], /* Pe [0..n-1]: index in Iw of row i on input */
60  Int Iw [ ], /* workspace of size iwlen. Iw [0..pfree-1]
61  * holds the matrix on input */
62  Int Len [ ], /* Len [0..n-1]: length for row/column i on input */
63  Int iwlen, /* length of Iw. iwlen >= pfree + n */
64  Int pfree, /* Iw [pfree ... iwlen-1] is empty on input */
65 
66  /* 7 size-n or size-n+1 workspaces, not defined on input: */
67  Int Nv [ ], /* size n, the size of each supernode on output */
68  Int Next [ ], /* size n, the output inverse permutation */
69  Int Last [ ], /* size n, the output permutation */
70  Int Head [ ], /* size n+1 (Note: it was size n in AMD) */
71  Int Elen [ ], /* size n, the size columns of L for each supernode */
72  Int Degree [ ], /* size n */
73  Int W [ ], /* size n+1 (Note: it was size n in AMD) */
74 
75  /* control parameters and output statistics */
76  double Control [ ], /* array of size CAMD_CONTROL */
77  double Info [ ], /* array of size CAMD_INFO */
78 
79  /* input, not modified: */
80  const Int C [ ], /* size n, C [i] is the constraint set of node i */
81 
82  /* size-n workspace, not defined on input or output: */
83  Int BucketSet [ ] /* size n */
84 )
85 {
86 
87 /*
88  * Given a representation of the nonzero pattern of a symmetric matrix, A,
89  * (excluding the diagonal) perform an approximate minimum (UMFPACK/MA38-style)
90  * degree ordering to compute a pivot order such that the introduction of
91  * nonzeros (fill-in) in the Cholesky factors A = LL' is kept low. At each
92  * step, the pivot selected is the one with the minimum UMFAPACK/MA38-style
93  * upper-bound on the external degree. This routine can optionally perform
94  * aggresive absorption (as done by MC47B in the Harwell Subroutine
95  * Library).
96  *
97  * The approximate degree algorithm implemented here is the symmetric analog of
98  * the degree update algorithm in MA38 and UMFPACK (the Unsymmetric-pattern
99  * MultiFrontal PACKage, both by Davis and Duff). The routine is based on the
100  * MA27 minimum degree ordering algorithm by Iain Duff and John Reid.
101  *
102  * This routine is a translation of the original AMDBAR and MC47B routines,
103  * in Fortran, with the following modifications:
104  *
105  * (1) dense rows/columns are removed prior to ordering the matrix, and placed
106  * last in the output order. The presence of a dense row/column can
107  * increase the ordering time by up to O(n^2), unless they are removed
108  * prior to ordering.
109  *
110  * (2) the minimum degree ordering is followed by a postordering (depth-first
111  * search) of the assembly tree. Note that mass elimination (discussed
112  * below) combined with the approximate degree update can lead to the mass
113  * elimination of nodes with lower exact degree than the current pivot
114  * element. No additional fill-in is caused in the representation of the
115  * Schur complement. The mass-eliminated nodes merge with the current
116  * pivot element. They are ordered prior to the current pivot element.
117  * Because they can have lower exact degree than the current element, the
118  * merger of two or more of these nodes in the current pivot element can
119  * lead to a single element that is not a "fundamental supernode". The
120  * diagonal block can have zeros in it. Thus, the assembly tree used here
121  * is not guaranteed to be the precise supernodal elemination tree (with
122  * "funadmental" supernodes), and the postordering performed by this
123  * routine is not guaranteed to be a precise postordering of the
124  * elimination tree.
125  *
126  * (3) input parameters are added, to control aggressive absorption and the
127  * detection of "dense" rows/columns of A.
128  *
129  * (4) additional statistical information is returned, such as the number of
130  * nonzeros in L, and the flop counts for subsequent LDL' and LU
131  * factorizations. These are slight upper bounds, because of the mass
132  * elimination issue discussed above.
133  *
134  * (5) additional routines are added to interface this routine to MATLAB
135  * to provide a simple C-callable user-interface, to check inputs for
136  * errors, compute the symmetry of the pattern of A and the number of
137  * nonzeros in each row/column of A+A', to compute the pattern of A+A',
138  * to perform the assembly tree postordering, and to provide debugging
139  * ouput. Many of these functions are also provided by the Fortran
140  * Harwell Subroutine Library routine MC47A.
141  *
142  * (6) both "int" and "long" versions are provided. In the descriptions below
143  * and integer is and "int" or "long", depending on which version is
144  * being used.
145 
146  **********************************************************************
147  ***** CAUTION: ARGUMENTS ARE NOT CHECKED FOR ERRORS ON INPUT. ******
148  **********************************************************************
149  ** If you want error checking, a more versatile input format, and a **
150  ** simpler user interface, use camd_order or camd_l_order instead. **
151  ** This routine is not meant to be user-callable. **
152  **********************************************************************
153 
154  * ----------------------------------------------------------------------------
155  * References:
156  * ----------------------------------------------------------------------------
157  *
158  * [1] Timothy A. Davis and Iain Duff, "An unsymmetric-pattern multifrontal
159  * method for sparse LU factorization", SIAM J. Matrix Analysis and
160  * Applications, vol. 18, no. 1, pp. 140-158. Discusses UMFPACK / MA38,
161  * which first introduced the approximate minimum degree used by this
162  * routine.
163  *
164  * [2] Patrick Amestoy, Timothy A. Davis, and Iain S. Duff, "An approximate
165  * minimum degree ordering algorithm," SIAM J. Matrix Analysis and
166  * Applications, vol. 17, no. 4, pp. 886-905, 1996. Discusses AMDBAR and
167  * MC47B, which are the Fortran versions of this routine.
168  *
169  * [3] Alan George and Joseph Liu, "The evolution of the minimum degree
170  * ordering algorithm," SIAM Review, vol. 31, no. 1, pp. 1-19, 1989.
171  * We list below the features mentioned in that paper that this code
172  * includes:
173  *
174  * mass elimination:
175  * Yes. MA27 relied on supervariable detection for mass elimination.
176  *
177  * indistinguishable nodes:
178  * Yes (we call these "supervariables"). This was also in the MA27
179  * code - although we modified the method of detecting them (the
180  * previous hash was the true degree, which we no longer keep track
181  * of). A supervariable is a set of rows with identical nonzero
182  * pattern. All variables in a supervariable are eliminated together.
183  * Each supervariable has as its numerical name that of one of its
184  * variables (its principal variable).
185  *
186  * quotient graph representation:
187  * Yes. We use the term "element" for the cliques formed during
188  * elimination. This was also in the MA27 code. The algorithm can
189  * operate in place, but it will work more efficiently if given some
190  * "elbow room."
191  *
192  * element absorption:
193  * Yes. This was also in the MA27 code.
194  *
195  * external degree:
196  * Yes. The MA27 code was based on the true degree.
197  *
198  * incomplete degree update and multiple elimination:
199  * No. This was not in MA27, either. Our method of degree update
200  * within MC47B is element-based, not variable-based. It is thus
201  * not well-suited for use with incomplete degree update or multiple
202  * elimination.
203  *
204  * AMD Authors, and Copyright (C) 2004 by:
205  * Timothy A. Davis, Patrick Amestoy, Iain S. Duff, John K. Reid.
206  * Modifications for CAMD authored by Davis and Yanqing "Morris" Chen.
207  *
208  * Acknowledgements: This work (and the UMFPACK package) was supported by the
209  * National Science Foundation (ASC-9111263, DMS-9223088, and CCR-0203270).
210  * The UMFPACK/MA38 approximate degree update algorithm, the unsymmetric analog
211  * which forms the basis of CAMD, was developed while Tim Davis was supported by
212  * CERFACS (Toulouse, France) in a post-doctoral position. This C version, and
213  * the etree postorder, were written while Tim Davis was on sabbatical at
214  * Stanford University and Lawrence Berkeley National Laboratory.
215  * Ordering constraints were added with support from Sandia National Labs (DOE).
216 
217  * ----------------------------------------------------------------------------
218  * INPUT ARGUMENTS (unaltered):
219  * ----------------------------------------------------------------------------
220 
221  * n: The matrix order. Restriction: n >= 1.
222  *
223  * iwlen: The size of the Iw array. On input, the matrix is stored in
224  * Iw [0..pfree-1]. However, Iw [0..iwlen-1] should be slightly larger
225  * than what is required to hold the matrix, at least iwlen >= pfree + n.
226  * Otherwise, excessive compressions will take place. The recommended
227  * value of iwlen is 1.2 * pfree + n, which is the value used in the
228  * user-callable interface to this routine (camd_order.c). The algorithm
229  * will not run at all if iwlen < pfree. Restriction: iwlen >= pfree + n.
230  * Note that this is slightly more restrictive than the actual minimum
231  * (iwlen >= pfree), but CAMD_2 will be very slow with no elbow room.
232  * Thus, this routine enforces a bare minimum elbow room of size n.
233  *
234  * pfree: On input the tail end of the array, Iw [pfree..iwlen-1], is empty,
235  * and the matrix is stored in Iw [0..pfree-1]. During execution,
236  * additional data is placed in Iw, and pfree is modified so that
237  * Iw [pfree..iwlen-1] is always the unused part of Iw.
238  *
239  * Control: A double array of size CAMD_CONTROL containing input parameters
240  * that affect how the ordering is computed. If NULL, then default
241  * settings are used.
242  *
243  * Control [CAMD_DENSE] is used to determine whether or not a given input
244  * row is "dense". A row is "dense" if the number of entries in the row
245  * exceeds Control [CAMD_DENSE] times sqrt (n), except that rows with 16 or
246  * fewer entries are never considered "dense". To turn off the detection
247  * of dense rows, set Control [CAMD_DENSE] to a negative number, or to a
248  * number larger than sqrt (n). The default value of Control [CAMD_DENSE]
249  * is CAMD_DEFAULT_DENSE, which is defined in camd.h as 10.
250  *
251  * Control [CAMD_AGGRESSIVE] is used to determine whether or not aggressive
252  * absorption is to be performed. If nonzero, then aggressive absorption
253  * is performed (this is the default).
254  *
255  * C: defines the ordering constraints. s = C [j] gives the constraint set s
256  * that contains the row/column j (Restriction: 0 <= s < n).
257  * In the output row permutation, all rows in set 0 appear first, followed
258  * by all rows in set 1, and so on. If NULL, all rows are treated as if
259  * they were in a single constraint set, and you will obtain a similar
260  * ordering as AMD (slightly different because of the different
261  * postordering used).
262 
263  * ----------------------------------------------------------------------------
264  * INPUT/OUPUT ARGUMENTS:
265  * ----------------------------------------------------------------------------
266  *
267  * Pe: An integer array of size n. On input, Pe [i] is the index in Iw of
268  * the start of row i. Pe [i] is ignored if row i has no off-diagonal
269  * entries. Thus Pe [i] must be in the range 0 to pfree-1 for non-empty
270  * rows.
271  *
272  * During execution, it is used for both supervariables and elements:
273  *
274  * Principal supervariable i: index into Iw of the description of
275  * supervariable i. A supervariable represents one or more rows of
276  * the matrix with identical nonzero pattern. In this case,
277  * Pe [i] >= 0.
278  *
279  * Non-principal supervariable i: if i has been absorbed into another
280  * supervariable j, then Pe [i] = FLIP (j), where FLIP (j) is defined
281  * as (-(j)-2). Row j has the same pattern as row i. Note that j
282  * might later be absorbed into another supervariable j2, in which
283  * case Pe [i] is still FLIP (j), and Pe [j] = FLIP (j2) which is
284  * < EMPTY, where EMPTY is defined as (-1) in camd_internal.h.
285  *
286  * Unabsorbed element e: the index into Iw of the description of element
287  * e, if e has not yet been absorbed by a subsequent element. Element
288  * e is created when the supervariable of the same name is selected as
289  * the pivot. In this case, Pe [i] >= 0.
290  *
291  * Absorbed element e: if element e is absorbed into element e2, then
292  * Pe [e] = FLIP (e2). This occurs when the pattern of e (which we
293  * refer to as Le) is found to be a subset of the pattern of e2 (that
294  * is, Le2). In this case, Pe [i] < EMPTY. If element e is "null"
295  * (it has no nonzeros outside its pivot block), then Pe [e] = EMPTY,
296  * and e is the root of an assembly subtree (or the whole tree if
297  * there is just one such root).
298  *
299  * Dense or empty variable i: if i is "dense" or empty (with zero degree),
300  * then Pe [i] = FLIP (n).
301  *
302  * On output, Pe holds the assembly tree/forest, which implicitly
303  * represents a pivot order with identical fill-in as the actual order
304  * (via a depth-first search of the tree), as follows. If Nv [i] > 0,
305  * then i represents a node in the assembly tree, and the parent of i is
306  * Pe [i], or EMPTY if i is a root. If Nv [i] = 0, then (i, Pe [i])
307  * represents an edge in a subtree, the root of which is a node in the
308  * assembly tree. Note that i refers to a row/column in the original
309  * matrix, not the permuted matrix.
310  *
311  * Info: A double array of size CAMD_INFO. If present, (that is, not NULL),
312  * then statistics about the ordering are returned in the Info array.
313  * See camd.h for a description.
314 
315  * ----------------------------------------------------------------------------
316  * INPUT/MODIFIED (undefined on output):
317  * ----------------------------------------------------------------------------
318  *
319  * Len: An integer array of size n. On input, Len [i] holds the number of
320  * entries in row i of the matrix, excluding the diagonal. The contents
321  * of Len are undefined on output. Len also works as a temporary
322  * workspace in post ordering with dense nodes detected.
323  *
324  * Iw: An integer array of size iwlen. On input, Iw [0..pfree-1] holds the
325  * description of each row i in the matrix. The matrix must be symmetric,
326  * and both upper and lower triangular parts must be present. The
327  * diagonal must not be present. Row i is held as follows:
328  *
329  * Len [i]: the length of the row i data structure in the Iw array.
330  * Iw [Pe [i] ... Pe [i] + Len [i] - 1]:
331  * the list of column indices for nonzeros in row i (simple
332  * supervariables), excluding the diagonal. All supervariables
333  * start with one row/column each (supervariable i is just row i).
334  * If Len [i] is zero on input, then Pe [i] is ignored on input.
335  *
336  * Note that the rows need not be in any particular order, and there
337  * may be empty space between the rows.
338  *
339  * During execution, the supervariable i experiences fill-in. This is
340  * represented by placing in i a list of the elements that cause fill-in
341  * in supervariable i:
342  *
343  * Len [i]: the length of supervariable i in the Iw array.
344  * Iw [Pe [i] ... Pe [i] + Elen [i] - 1]:
345  * the list of elements that contain i. This list is kept short
346  * by removing absorbed elements.
347  * Iw [Pe [i] + Elen [i] ... Pe [i] + Len [i] - 1]:
348  * the list of supervariables in i. This list is kept short by
349  * removing nonprincipal variables, and any entry j that is also
350  * contained in at least one of the elements (j in Le) in the list
351  * for i (e in row i).
352  *
353  * When supervariable i is selected as pivot, we create an element e of
354  * the same name (e=i):
355  *
356  * Len [e]: the length of element e in the Iw array.
357  * Iw [Pe [e] ... Pe [e] + Len [e] - 1]:
358  * the list of supervariables in element e.
359  *
360  * An element represents the fill-in that occurs when supervariable i is
361  * selected as pivot (which represents the selection of row i and all
362  * non-principal variables whose principal variable is i). We use the
363  * term Le to denote the set of all supervariables in element e. Absorbed
364  * supervariables and elements are pruned from these lists when
365  * computationally convenient.
366  *
367  * CAUTION: THE INPUT MATRIX IS OVERWRITTEN DURING COMPUTATION.
368  * The contents of Iw are undefined on output.
369 
370  * ----------------------------------------------------------------------------
371  * OUTPUT (need not be set on input):
372  * ----------------------------------------------------------------------------
373  *
374  *
375  * Nv: An integer array of size n. During execution, ABS (Nv [i]) is equal to
376  * the number of rows that are represented by the principal supervariable
377  * i. If i is a nonprincipal or dense variable, then Nv [i] = 0.
378  * Initially, Nv [i] = 1 for all i. Nv [i] < 0 signifies that i is a
379  * principal variable in the pattern Lme of the current pivot element me.
380  * After element me is constructed, Nv [i] is set back to a positive
381  * value.
382  *
383  * On output, Nv [i] holds the number of pivots represented by super
384  * row/column i of the original matrix, or Nv [i] = 0 for non-principal
385  * rows/columns. Note that i refers to a row/column in the original
386  * matrix, not the permuted matrix.
387  *
388  * Nv also works as a temporary workspace in initializing the BucketSet
389  * array.
390  *
391  * Elen: An integer array of size n. See the description of Iw above. At the
392  * start of execution, Elen [i] is set to zero for all rows i. During
393  * execution, Elen [i] is the number of elements in the list for
394  * supervariable i. When e becomes an element, Elen [e] = FLIP (esize) is
395  * set, where esize is the size of the element (the number of pivots, plus
396  * the number of nonpivotal entries). Thus Elen [e] < EMPTY.
397  * Elen (i) = EMPTY set when variable i becomes nonprincipal.
398  *
399  * For variables, Elen (i) >= EMPTY holds until just before the
400  * postordering and permutation vectors are computed. For elements,
401  * Elen [e] < EMPTY holds.
402  *
403  * On output, Elen [i] is the degree of the row/column in the Cholesky
404  * factorization of the permuted matrix, corresponding to the original row
405  * i, if i is a super row/column. It is equal to EMPTY if i is
406  * non-principal. Note that i refers to a row/column in the original
407  * matrix, not the permuted matrix.
408  *
409  * Note that the contents of Elen on output differ from the Fortran
410  * version (Elen holds the inverse permutation in the Fortran version,
411  * which is instead returned in the Next array in this C version,
412  * described below).
413  *
414  * Last: In a degree list, Last [i] is the supervariable preceding i, or EMPTY
415  * if i is the head of the list. In a hash bucket, Last [i] is the hash
416  * key for i.
417  *
418  * Last [Head [hash]] is also used as the head of a hash bucket if
419  * Head [hash] contains a degree list (see the description of Head,
420  * below).
421  *
422  * On output, Last [0..n-1] holds the permutation. That is, if
423  * i = Last [k], then row i is the kth pivot row (where k ranges from 0 to
424  * n-1). Row Last [k] of A is the kth row in the permuted matrix, PAP'.
425  *
426  * Next: Next [i] is the supervariable following i in a link list, or EMPTY if
427  * i is the last in the list. Used for two kinds of lists: degree lists
428  * and hash buckets (a supervariable can be in only one kind of list at a
429  * time).
430  *
431  * On output Next [0..n-1] holds the inverse permutation. That is, if
432  * k = Next [i], then row i is the kth pivot row. Row i of A appears as
433  * the (Next[i])-th row in the permuted matrix, PAP'.
434  *
435  * Note that the contents of Next on output differ from the Fortran
436  * version (Next is undefined on output in the Fortran version).
437 
438  * ----------------------------------------------------------------------------
439  * LOCAL WORKSPACE (not input or output - used only during execution):
440  * ----------------------------------------------------------------------------
441  *
442  * Degree: An integer array of size n. If i is a supervariable, then
443  * Degree [i] holds the current approximation of the external degree of
444  * row i (an upper bound). The external degree is the number of nonzeros
445  * in row i, minus ABS (Nv [i]), the diagonal part. The bound is equal to
446  * the exact external degree if Elen [i] is less than or equal to two.
447  *
448  * We also use the term "external degree" for elements e to refer to
449  * |Le \ Lme|. If e is an element, then Degree [e] is |Le|, which is the
450  * degree of the off-diagonal part of the element e (not including the
451  * diagonal part).
452  *
453  * Head: An integer array of size n. Head is used for degree lists.
454  * Head [deg] is the first supervariable in a degree list. All
455  * supervariables i in a degree list Head [deg] have the same approximate
456  * degree, namely, deg = Degree [i]. If the list Head [deg] is empty then
457  * Head [deg] = EMPTY.
458  *
459  * During supervariable detection Head [hash] also serves as a pointer to
460  * a hash bucket. If Head [hash] >= 0, there is a degree list of degree
461  * hash. The hash bucket head pointer is Last [Head [hash]]. If
462  * Head [hash] = EMPTY, then the degree list and hash bucket are both
463  * empty. If Head [hash] < EMPTY, then the degree list is empty, and
464  * FLIP (Head [hash]) is the head of the hash bucket. After supervariable
465  * detection is complete, all hash buckets are empty, and the
466  * (Last [Head [hash]] = EMPTY) condition is restored for the non-empty
467  * degree lists.
468  *
469  * Head also workes as a temporary workspace in post ordering with dense
470  * nodes detected.
471  *
472  * W: An integer array of size n. The flag array W determines the status of
473  * elements and variables, and the external degree of elements.
474  *
475  * for elements:
476  * if W [e] = 0, then the element e is absorbed.
477  * if W [e] >= wflg, then W [e] - wflg is the size of the set
478  * |Le \ Lme|, in terms of nonzeros (the sum of ABS (Nv [i]) for
479  * each principal variable i that is both in the pattern of
480  * element e and NOT in the pattern of the current pivot element,
481  * me).
482  * if wflg > W [e] > 0, then e is not absorbed and has not yet been
483  * seen in the scan of the element lists in the computation of
484  * |Le\Lme| in Scan 1 below.
485  *
486  * for variables:
487  * during supervariable detection, if W [j] != wflg then j is
488  * not in the pattern of variable i.
489  *
490  * The W array is initialized by setting W [i] = 1 for all i, and by
491  * setting wflg = 2. It is reinitialized if wflg becomes too large (to
492  * ensure that wflg+n does not cause integer overflow).
493  *
494  * BucketSet: An integer array of size n.
495  * During execution it stores the rows that sorted in the ascending order
496  * based on C []. For instance: if C[]={0,2,1,0,1,0,2,1}, the
497  * Bucketset will be {0,3,5,2,4,7,1,6}.
498  * The elements in Bucketset are then modified, to maintain the order of
499  * roots (Pe[i]=-1) in each Constraint Set.
500 
501  * ----------------------------------------------------------------------------
502  * LOCAL INTEGERS:
503  * ----------------------------------------------------------------------------
504  */
505 
506  Int deg, degme, dext, lemax, e, elenme, eln, i, ilast, inext, j,
507  jlast, k, knt1, knt2, knt3, lenj, ln, me, mindeg, nel, nleft,
508  nvi, nvj, nvpiv, slenme, wbig, we, wflg, wnvi, ok, ndense, ncmpa, nnull,
509  dense, aggressive ;
510 
511  unsigned Int hash ; /* unsigned, so that hash % n is well defined.*/
512 
513 /*
514  * deg: the degree of a variable or element
515  * degme: size, |Lme|, of the current element, me (= Degree [me])
516  * dext: external degree, |Le \ Lme|, of some element e
517  * lemax: largest |Le| seen so far (called dmax in Fortran version)
518  * e: an element
519  * elenme: the length, Elen [me], of element list of pivotal variable
520  * eln: the length, Elen [...], of an element list
521  * hash: the computed value of the hash function
522  * i: a supervariable
523  * ilast: the entry in a link list preceding i
524  * inext: the entry in a link list following i
525  * j: a supervariable
526  * jlast: the entry in a link list preceding j
527  * k: the pivot order of an element or variable
528  * knt1: loop counter used during element construction
529  * knt2: loop counter used during element construction
530  * knt3: loop counter used during compression
531  * lenj: Len [j]
532  * ln: length of a supervariable list
533  * me: current supervariable being eliminated, and the current
534  * element created by eliminating that supervariable
535  * mindeg: current minimum degree
536  * nel: number of pivots selected so far
537  * nleft: n - nel, the number of nonpivotal rows/columns remaining
538  * nvi: the number of variables in a supervariable i (= Nv [i])
539  * nvj: the number of variables in a supervariable j (= Nv [j])
540  * nvpiv: number of pivots in current element
541  * slenme: number of variables in variable list of pivotal variable
542  * wbig: = INT_MAX - n for the "int" version, LONG_MAX - n for the
543  * "long" version. wflg is not allowed to be >= wbig.
544  * we: W [e]
545  * wflg: used for flagging the W array. See description of Iw.
546  * wnvi: wflg - Nv [i]
547  * x: either a supervariable or an element
548  *
549  * ok: true if supervariable j can be absorbed into i
550  * ndense: number of "dense" rows/columns
551  * nnull: number of empty rows/columns
552  * dense: rows/columns with initial degree > dense are considered "dense"
553  * aggressive: true if aggressive absorption is being performed
554  * ncmpa: number of garbage collections
555 
556  * ----------------------------------------------------------------------------
557  * LOCAL DOUBLES, used for statistical output only (except for alpha):
558  * ----------------------------------------------------------------------------
559  */
560 
561  double f, r, ndiv, s, nms_lu, nms_ldl, dmax, alpha, lnz, lnzme ;
562 
563 /*
564  * f: nvpiv
565  * r: degme + nvpiv
566  * ndiv: number of divisions for LU or LDL' factorizations
567  * s: number of multiply-subtract pairs for LU factorization, for the
568  * current element me
569  * nms_lu number of multiply-subtract pairs for LU factorization
570  * nms_ldl number of multiply-subtract pairs for LDL' factorization
571  * dmax: the largest number of entries in any column of L, including the
572  * diagonal
573  * alpha: "dense" degree ratio
574  * lnz: the number of nonzeros in L (excluding the diagonal)
575  * lnzme: the number of nonzeros in L (excl. the diagonal) for the
576  * current element me
577 
578  * ----------------------------------------------------------------------------
579  * LOCAL "POINTERS" (indices into the Iw array)
580  * ----------------------------------------------------------------------------
581 */
582 
583  Int p, p1, p2, p3, p4, pdst, pend, pj, pme, pme1, pme2, pn, psrc ;
584 
585 /*
586  * Any parameter (Pe [...] or pfree) or local variable starting with "p" (for
587  * Pointer) is an index into Iw, and all indices into Iw use variables starting
588  * with "p." The only exception to this rule is the iwlen input argument.
589  *
590  * p: pointer into lots of things
591  * p1: Pe [i] for some variable i (start of element list)
592  * p2: Pe [i] + Elen [i] - 1 for some variable i
593  * p3: index of first supervariable in clean list
594  * p4:
595  * pdst: destination pointer, for compression
596  * pend: end of memory to compress
597  * pj: pointer into an element or variable
598  * pme: pointer into the current element (pme1...pme2)
599  * pme1: the current element, me, is stored in Iw [pme1...pme2]
600  * pme2: the end of the current element
601  * pn: pointer into a "clean" variable, also used to compress
602  * psrc: source pointer, for compression
603 */
604 
605  Int curC, pBucket, pBucket2, degreeListCounter, c, cmax = 0,
606  ndense_or_null ;
607  Int *Bucket, *Perm ;
608 
609 /*
610  * curC: the current Constraint Set being ordered
611  * pBucket: pointer into Bucketset[] when building the degreelist for each
612  * Constraint Set
613  * pBucket2: pointer into Bucketset[] to tell the post ordering where to stop
614  * degreeListCounter: number of elements remaining in the
615  * degreelist of current Constraint Set
616  * Bucket: used to construct BucketSet
617  * Perm: permutation
618  */
619 
620 /* ========================================================================= */
621 /* INITIALIZATIONS */
622 /* ========================================================================= */
623 
624  /* Note that this restriction on iwlen is slightly more restrictive than
625  * what is actually required in CAMD_2. CAMD_2 can operate with no elbow
626  * room at all, but it will be slow. For better performance, at least
627  * size-n elbow room is enforced. */
628  ASSERT (iwlen >= pfree + n) ;
629  ASSERT (n > 0) ;
630 
631  /* initialize output statistics */
632  lnz = 0 ;
633  ndiv = 0 ;
634  nms_lu = 0 ;
635  nms_ldl = 0 ;
636  dmax = 1 ;
637  me = EMPTY ;
638 
639  mindeg = 0 ;
640  ncmpa = 0 ;
641  nel = 0 ;
642  lemax = 0 ;
643  curC = 0 ;
644 
645 /* camd work initBucketSet using CountingSort
646  * BucketSort the index Array BucketSet According to Contrains Array C, Using
647  * Nv[] as a temporary workspace
648  * Input: Index Array from 0 to n.(index of rows)
649  * Output: Index Array sorted according to C. worked as a bucket set.
650  *
651  * All the value in C must be 0 <= C[i] <= n-1
652  * For instance: if C[]={0,2,1,0,1,0,2,1}, the output Bucketset should be
653  * {0,3,5,2,4,7,1,6}
654  */
655 
656 
657 /* CountingSort BucketSet[] based on C[], It is O(n) linear time */
658 
659  if (C == NULL)
660  {
661  /* store everything in bucket without changing order */
662  for (j = 0 ; j < n ; j++)
663  {
664  BucketSet [j] = j ;
665  }
666  }
667  else
668  {
669 
670  Bucket = Nv ;
671  for (i = 0 ; i < n ; i++)
672  {
673  Bucket [i] = 0 ;
674  }
675  cmax = C [0] ;
676  for (j = 0 ; j < n ; j++)
677  {
678  c = C [j] ;
679  CAMD_DEBUG1 (("C [%d] = "ID"\n", j, c)) ;
680  Bucket [c]++ ;
681  cmax = MAX (cmax, c) ;
682  ASSERT (c >= 0 && c < n) ;
683  }
684  CAMD_DEBUG1 (("Max constraint set: "ID"\n", cmax)) ;
685  for (i = 1 ; i < n ; i++)
686  {
687  Bucket [i] += Bucket [i-1] ;
688  }
689  for (j = n-1 ; j >= 0 ; j--)
690  {
691  BucketSet [--Bucket [C [j]]] = j ;
692  }
693 
694 #ifndef NDEBUG
695  CAMD_DEBUG3 (("\nConstraint Set "ID" :", C [BucketSet [0]]));
696  for (i = 0 ; i < n ; i++)
697  {
698  CAMD_DEBUG3 ((ID" ", BucketSet [i])) ;
699  if (i == n-1)
700  {
701  CAMD_DEBUG3 (("\n")) ;
702  break ;
703  }
704  if (C [BucketSet [i+1]] != C [BucketSet [i]])
705  {
706  CAMD_DEBUG3 (("\nConstraint Set "ID" :", C [BucketSet [i+1]])) ;
707  }
708  }
709 #endif
710  }
711 
712  /* get control parameters */
713  if (Control != (double *) NULL)
714  {
715  alpha = Control [CAMD_DENSE] ;
716  aggressive = (Control [CAMD_AGGRESSIVE] != 0) ;
717  }
718  else
719  {
720  alpha = CAMD_DEFAULT_DENSE ;
721  aggressive = CAMD_DEFAULT_AGGRESSIVE ;
722  }
723  /* Note: if alpha is NaN, this is undefined: */
724  if (alpha < 0)
725  {
726  /* only remove completely dense rows/columns */
727  dense = n-2 ;
728  }
729  else
730  {
731  dense = alpha * sqrt ((double) n) ;
732  }
733  dense = MAX (16, dense) ;
734  dense = MIN (n, dense) ;
735  CAMD_DEBUG1 (("\n\nCAMD (debug), alpha %g, aggr. "ID"\n",
736  alpha, aggressive)) ;
737 
738  for (i = 0 ; i < n ; i++)
739  {
740  Last [i] = EMPTY ;
741  Head [i] = EMPTY ;
742  Next [i] = EMPTY ;
743  /* if separate Hhead array is used for hash buckets: *
744  Hhead [i] = EMPTY ;
745  */
746  Nv [i] = 1 ;
747  W [i] = 1 ;
748  Elen [i] = 0 ;
749  Degree [i] = Len [i] ;
750  }
751  Head [n] = EMPTY ;
752 
753  /* initialize wflg */
754  wbig = Int_MAX - n ;
755  wflg = amesos_clear_flag (0, wbig, W, n) ;
756 
757  /* --------------------------------------------------------------------- */
758  /* eliminate dense and empty rows */
759  /* --------------------------------------------------------------------- */
760 
761  ndense = 0 ;
762  nnull = 0 ;
763 
764  for (j = 0 ; j < n ; j++)
765  {
766  i = BucketSet [j] ;
767  deg = Degree [i] ;
768  ASSERT (deg >= 0 && deg < n) ;
769  if (deg > dense || deg == 0)
770  {
771 
772  /* -------------------------------------------------------------
773  * Dense or empty variables are treated as non-principal variables
774  * represented by node n. That is, i is absorbed into n, just like
775  * j is absorbed into i in supervariable detection (see "found it!"
776  * comment, below).
777  * ------------------------------------------------------------- */
778 
779  if (deg > dense)
780  {
781  CAMD_DEBUG1 (("Dense node "ID" degree "ID" bucket "ID"\n",
782  i, deg, j)) ;
783  ndense++ ;
784  }
785  else
786  {
787  CAMD_DEBUG1 (("Empty node "ID" degree "ID" bucket "ID"\n",
788  i, deg, j)) ;
789  nnull++ ;
790  }
791  Pe [i] = FLIP (n) ;
792  Nv [i] = 0 ; /* do not postorder this node */
793  Elen [i] = EMPTY ;
794  nel++ ;
795  }
796  }
797 
798  ndense_or_null = ndense + nnull ;
799 
800  pBucket = 0 ;
801  degreeListCounter = 0 ;
802  pBucket2 = 0 ;
803 
804 /* ========================================================================= */
805 /* WHILE (selecting pivots) DO */
806 /* ========================================================================= */
807 
808  while (nel < n)
809  {
810 
811  /* ------------------------------------------------------------------ */
812  /* if empty, fill the degree list with next non-empty constraint set */
813  /* ------------------------------------------------------------------ */
814 
815  while (degreeListCounter == 0)
816  {
817  mindeg = n ;
818  /* determine the new constraint set */
819  curC = (C == NULL) ? 0 : C [BucketSet [pBucket]] ;
820  for ( ; pBucket < n ; pBucket++)
821  {
822  /* add i to the degree list, unless it's dead or not in curC */
823  i = BucketSet [pBucket] ;
824  if (!IsInCurrentSet (C, i, curC)) break ;
825  deg = Degree [i] ;
826  ASSERT (deg >= 0 && deg < n) ;
827  if (Pe [i] >= 0)
828  {
829 
830  /* ------------------------------------------------------
831  * place i in the degree list corresponding to its degree
832  * ------------------------------------------------------ */
833 
834  inext = Head [deg] ;
835  ASSERT (inext >= EMPTY && inext < n) ;
836  if (inext != EMPTY) Last [inext] = i ;
837  Next [i] = inext ;
838  Head [deg] = i ;
839  degreeListCounter++ ;
840  Last [i] = EMPTY ;
841  mindeg = MIN (mindeg, deg) ;
842  }
843  }
844  }
845 
846 #ifndef NDEBUG
847  CAMD_DEBUG1 (("\n======Nel "ID"\n", nel)) ;
848  if (CAMD_debug >= 2)
849  {
850  CAMD_dump (n, Pe, Iw, Len, iwlen, pfree, Nv, Next,
851  Last, Head, Elen, Degree, W, nel, BucketSet, C, curC) ;
852  }
853 #endif
854 
855 /* ========================================================================= */
856 /* GET PIVOT OF MINIMUM DEGREE */
857 /* ========================================================================= */
858 
859  /* ----------------------------------------------------------------- */
860  /* find next supervariable for elimination */
861  /* ----------------------------------------------------------------- */
862 
863  ASSERT (mindeg >= 0 && mindeg < n) ;
864  for (deg = mindeg ; deg < n ; deg++)
865  {
866  me = Head [deg] ;
867  if (me != EMPTY) break ;
868  }
869  mindeg = deg ;
870  ASSERT (me >= 0 && me < n) ;
871  CAMD_DEBUG1 (("=================me: "ID"\n", me)) ;
872 
873  /* ----------------------------------------------------------------- */
874  /* remove chosen variable from link list */
875  /* ----------------------------------------------------------------- */
876 
877  inext = Next [me] ;
878  ASSERT (inext >= EMPTY && inext < n) ;
879  if (inext != EMPTY) Last [inext] = EMPTY ;
880  Head [deg] = inext ;
881  degreeListCounter-- ;
882 
883  /* ----------------------------------------------------------------- */
884  /* me represents the elimination of pivots nel to nel+Nv[me]-1. */
885  /* place me itself as the first in this set. */
886  /* ----------------------------------------------------------------- */
887 
888  elenme = Elen [me] ;
889  nvpiv = Nv [me] ;
890  ASSERT (nvpiv > 0) ;
891  nel += nvpiv ;
892  CAMD_DEBUG1 (("nvpiv is initially "ID"\n", nvpiv)) ;
893 
894 /* ========================================================================= */
895 /* CONSTRUCT NEW ELEMENT */
896 /* ========================================================================= */
897 
898  /* -----------------------------------------------------------------
899  * At this point, me is the pivotal supervariable. It will be
900  * converted into the current element. Scan list of the pivotal
901  * supervariable, me, setting tree pointers and constructing new list
902  * of supervariables for the new element, me. p is a pointer to the
903  * current position in the old list.
904  * ----------------------------------------------------------------- */
905 
906  /* flag the variable "me" as being in Lme by negating Nv [me] */
907  Nv [me] = -nvpiv ;
908  degme = 0 ;
909  ASSERT (Pe [me] >= 0 && Pe [me] < iwlen) ;
910 
911  if (elenme == 0)
912  {
913 
914  /* ------------------------------------------------------------- */
915  /* construct the new element in place */
916  /* ------------------------------------------------------------- */
917 
918  pme1 = Pe [me] ;
919  pme2 = pme1 - 1 ;
920 
921  for (p = pme1 ; p <= pme1 + Len [me] - 1 ; p++)
922  {
923  i = Iw [p] ;
924  ASSERT (i >= 0 && i < n && Nv [i] >= 0) ;
925  nvi = Nv [i] ;
926  if (nvi > 0)
927  {
928 
929  /* ----------------------------------------------------- */
930  /* i is a principal variable not yet placed in Lme. */
931  /* store i in new list */
932  /* ----------------------------------------------------- */
933 
934  /* flag i as being in Lme by negating Nv [i] */
935  degme += nvi ;
936  Nv [i] = -nvi ;
937  Iw [++pme2] = i ;
938 
939  /* ----------------------------------------------------- */
940  /* remove variable i from degree list. */
941  /* ----------------------------------------------------- */
942 
943  if (IsInCurrentSet (C, i, curC))
944  {
945  ilast = Last [i] ;
946  inext = Next [i] ;
947  ASSERT (ilast >= EMPTY && ilast < n) ;
948  ASSERT (inext >= EMPTY && inext < n) ;
949  if (inext != EMPTY) Last [inext] = ilast ;
950  if (ilast != EMPTY)
951  {
952  Next [ilast] = inext ;
953  }
954  else
955  {
956  /* i is at the head of the degree list */
957  ASSERT (Degree [i] >= 0 && Degree [i] < n) ;
958  Head [Degree [i]] = inext ;
959  }
960  degreeListCounter-- ;
961  }
962  }
963  }
964  }
965  else
966  {
967 
968  /* ------------------------------------------------------------- */
969  /* construct the new element in empty space, Iw [pfree ...] */
970  /* ------------------------------------------------------------- */
971 
972  p = Pe [me] ;
973  pme1 = pfree ;
974  slenme = Len [me] - elenme ;
975 
976  for (knt1 = 1 ; knt1 <= elenme + 1 ; knt1++)
977  {
978 
979  if (knt1 > elenme)
980  {
981  /* search the supervariables in me. */
982  e = me ;
983  pj = p ;
984  ln = slenme ;
985  CAMD_DEBUG2 (("Search sv: "ID" "ID" "ID"\n", me,pj,ln)) ;
986  }
987  else
988  {
989  /* search the elements in me. */
990  e = Iw [p++] ;
991  ASSERT (e >= 0 && e < n) ;
992  pj = Pe [e] ;
993  ln = Len [e] ;
994  CAMD_DEBUG2 (("Search element e "ID" in me "ID"\n", e,me)) ;
995  ASSERT (Elen [e] < EMPTY && W [e] > 0 && pj >= 0) ;
996  }
997  ASSERT (ln >= 0 && (ln == 0 || (pj >= 0 && pj < iwlen))) ;
998 
999  /* ---------------------------------------------------------
1000  * search for different supervariables and add them to the
1001  * new list, compressing when necessary. this loop is
1002  * executed once for each element in the list and once for
1003  * all the supervariables in the list.
1004  * --------------------------------------------------------- */
1005 
1006  for (knt2 = 1 ; knt2 <= ln ; knt2++)
1007  {
1008  i = Iw [pj++] ;
1009  ASSERT (i >= 0 && i < n && (i == me || Elen [i] >= EMPTY));
1010  nvi = Nv [i] ;
1011  CAMD_DEBUG2 ((": "ID" "ID" "ID" "ID"\n",
1012  i, Elen [i], Nv [i], wflg)) ;
1013 
1014  if (nvi > 0)
1015  {
1016 
1017  /* ------------------------------------------------- */
1018  /* compress Iw, if necessary */
1019  /* ------------------------------------------------- */
1020 
1021  if (pfree >= iwlen)
1022  {
1023 
1024  CAMD_DEBUG1 (("GARBAGE COLLECTION\n")) ;
1025 
1026  /* prepare for compressing Iw by adjusting pointers
1027  * and lengths so that the lists being searched in
1028  * the inner and outer loops contain only the
1029  * remaining entries. */
1030 
1031  Pe [me] = p ;
1032  Len [me] -= knt1 ;
1033  /* check if nothing left of supervariable me */
1034  if (Len [me] == 0) Pe [me] = EMPTY ;
1035  Pe [e] = pj ;
1036  Len [e] = ln - knt2 ;
1037  /* nothing left of element e */
1038  if (Len [e] == 0) Pe [e] = EMPTY ;
1039 
1040  ncmpa++ ; /* one more garbage collection */
1041 
1042  /* store first entry of each object in Pe */
1043  /* FLIP the first entry in each object */
1044  for (j = 0 ; j < n ; j++)
1045  {
1046  pn = Pe [j] ;
1047  if (pn >= 0)
1048  {
1049  ASSERT (pn >= 0 && pn < iwlen) ;
1050  Pe [j] = Iw [pn] ;
1051  Iw [pn] = FLIP (j) ;
1052  }
1053  }
1054 
1055  /* psrc/pdst point to source/destination */
1056  psrc = 0 ;
1057  pdst = 0 ;
1058  pend = pme1 - 1 ;
1059 
1060  while (psrc <= pend)
1061  {
1062  /* search for next FLIP'd entry */
1063  j = FLIP (Iw [psrc++]) ;
1064  if (j >= 0)
1065  {
1066  CAMD_DEBUG2 (("Got object j: "ID"\n", j)) ;
1067  Iw [pdst] = Pe [j] ;
1068  Pe [j] = pdst++ ;
1069  lenj = Len [j] ;
1070  /* copy from source to destination */
1071  for (knt3 = 0 ; knt3 <= lenj - 2 ; knt3++)
1072  {
1073  Iw [pdst++] = Iw [psrc++] ;
1074  }
1075  }
1076  }
1077 
1078  /* move the new partially-constructed element */
1079  p1 = pdst ;
1080  for (psrc = pme1 ; psrc <= pfree-1 ; psrc++)
1081  {
1082  Iw [pdst++] = Iw [psrc] ;
1083  }
1084  pme1 = p1 ;
1085  pfree = pdst ;
1086  pj = Pe [e] ;
1087  p = Pe [me] ;
1088 
1089  }
1090 
1091  /* ------------------------------------------------- */
1092  /* i is a principal variable not yet placed in Lme */
1093  /* store i in new list */
1094  /* ------------------------------------------------- */
1095 
1096  /* flag i as being in Lme by negating Nv [i] */
1097  degme += nvi ;
1098  Nv [i] = -nvi ;
1099  Iw [pfree++] = i ;
1100  CAMD_DEBUG2 ((" s: "ID" nv "ID"\n", i, Nv [i]));
1101 
1102  /* ------------------------------------------------- */
1103  /* remove variable i from degree link list */
1104  /* ------------------------------------------------- */
1105 
1106  if (IsInCurrentSet (C, i, curC))
1107  {
1108  ilast = Last [i] ;
1109  inext = Next [i] ;
1110  ASSERT (ilast >= EMPTY && ilast < n) ;
1111  ASSERT (inext >= EMPTY && inext < n) ;
1112  if (inext != EMPTY) Last [inext] = ilast ;
1113  if (ilast != EMPTY)
1114  {
1115  Next [ilast] = inext ;
1116  }
1117  else
1118  {
1119  /* i is at the head of the degree list */
1120  ASSERT (Degree [i] >= 0 && Degree [i] < n) ;
1121  Head [Degree [i]] = inext ;
1122  }
1123  degreeListCounter-- ;
1124  }
1125  }
1126  }
1127 
1128  if (e != me)
1129  {
1130  if (IsInCurrentSet (C, e, curC))
1131  {
1132  /* absorb element here if in same bucket */
1133  /* set tree pointer and flag to indicate element e is
1134  * absorbed into new element me (the parent of e is me)
1135  */
1136  CAMD_DEBUG1 ((" Element "ID" => "ID"\n", e, me)) ;
1137  Pe [e] = FLIP (me) ;
1138  W [e] = 0 ;
1139  }
1140  else
1141  {
1142  /* make element a root; kill it if not in same bucket */
1143  CAMD_DEBUG1 (("2 Element "ID" => "ID"\n", e, me)) ;
1144  Pe [e] = EMPTY ;
1145  W [e] = 0 ;
1146  }
1147  }
1148  }
1149 
1150  pme2 = pfree - 1 ;
1151  }
1152 
1153  /* ----------------------------------------------------------------- */
1154  /* me has now been converted into an element in Iw [pme1..pme2] */
1155  /* ----------------------------------------------------------------- */
1156 
1157  /* degme holds the external degree of new element */
1158  Degree [me] = degme ;
1159  Pe [me] = pme1 ;
1160  Len [me] = pme2 - pme1 + 1 ;
1161  ASSERT (Pe [me] >= 0 && Pe [me] < iwlen) ;
1162 
1163  Elen [me] = FLIP (nvpiv + degme) ;
1164  /* FLIP (Elen (me)) is now the degree of pivot (including
1165  * diagonal part). */
1166 
1167 #ifndef NDEBUG
1168  CAMD_DEBUG2 (("New element structure: length= "ID"\n", pme2-pme1+1)) ;
1169  for (pme = pme1 ; pme <= pme2 ; pme++) CAMD_DEBUG3 ((" "ID"", Iw[pme]));
1170  CAMD_DEBUG3 (("\n")) ;
1171 #endif
1172 
1173  /* ----------------------------------------------------------------- */
1174  /* make sure that wflg is not too large. */
1175  /* ----------------------------------------------------------------- */
1176 
1177  /* With the current value of wflg, wflg+n must not cause integer
1178  * overflow */
1179 
1180  wflg = amesos_clear_flag (wflg, wbig, W, n) ;
1181 
1182 /* ========================================================================= */
1183 /* COMPUTE (W [e] - wflg) = |Le\Lme| FOR ALL ELEMENTS */
1184 /* ========================================================================= */
1185 
1186  /* -----------------------------------------------------------------
1187  * Scan 1: compute the external degrees of previous elements with
1188  * respect to the current element. That is:
1189  * (W [e] - wflg) = |Le \ Lme|
1190  * for each element e that appears in any supervariable in Lme. The
1191  * notation Le refers to the pattern (list of supervariables) of a
1192  * previous element e, where e is not yet absorbed, stored in
1193  * Iw [Pe [e] + 1 ... Pe [e] + Len [e]]. The notation Lme
1194  * refers to the pattern of the current element (stored in
1195  * Iw [pme1..pme2]). If aggressive absorption is enabled, and
1196  * (W [e] - wflg) becomes zero, then the element e will be absorbed
1197  * in Scan 2.
1198  * ----------------------------------------------------------------- */
1199 
1200  CAMD_DEBUG2 (("me: ")) ;
1201  for (pme = pme1 ; pme <= pme2 ; pme++)
1202  {
1203  i = Iw [pme] ;
1204  ASSERT (i >= 0 && i < n) ;
1205  eln = Elen [i] ;
1206  CAMD_DEBUG3 ((""ID" Elen "ID": \n", i, eln)) ;
1207  if (eln > 0)
1208  {
1209  /* note that Nv [i] has been negated to denote i in Lme: */
1210  nvi = -Nv [i] ;
1211  ASSERT (nvi > 0 && Pe [i] >= 0 && Pe [i] < iwlen) ;
1212  wnvi = wflg - nvi ;
1213  for (p = Pe [i] ; p <= Pe [i] + eln - 1 ; p++)
1214  {
1215  e = Iw [p] ;
1216  ASSERT (e >= 0 && e < n) ;
1217  we = W [e] ;
1218  CAMD_DEBUG4 ((" e "ID" we "ID" ", e, we)) ;
1219  if (we >= wflg)
1220  {
1221  /* unabsorbed element e has been seen in this loop */
1222  CAMD_DEBUG4 ((" unabsorbed, first time seen")) ;
1223  we -= nvi ;
1224  }
1225  else if (we != 0)
1226  {
1227  /* e is an unabsorbed element */
1228  /* this is the first we have seen e in all of Scan 1 */
1229  CAMD_DEBUG4 ((" unabsorbed")) ;
1230  we = Degree [e] + wnvi ;
1231  }
1232  CAMD_DEBUG4 (("\n")) ;
1233  W [e] = we ;
1234  }
1235  }
1236  }
1237  CAMD_DEBUG2 (("\n")) ;
1238 
1239 /* ========================================================================= */
1240 /* DEGREE UPDATE AND ELEMENT ABSORPTION */
1241 /* ========================================================================= */
1242 
1243  /* -----------------------------------------------------------------
1244  * Scan 2: for each i in Lme, sum up the degree of Lme (which is
1245  * degme), plus the sum of the external degrees of each Le for the
1246  * elements e appearing within i, plus the supervariables in i.
1247  * Place i in hash list.
1248  * ----------------------------------------------------------------- */
1249 
1250  for (pme = pme1 ; pme <= pme2 ; pme++)
1251  {
1252  i = Iw [pme] ;
1253  ASSERT (i >= 0 && i < n && Nv [i] < 0 && Elen [i] >= 0) ;
1254  CAMD_DEBUG2 (("Updating: i "ID" "ID" "ID"\n", i, Elen[i], Len [i]));
1255  p1 = Pe [i] ;
1256  p2 = p1 + Elen [i] - 1 ;
1257  pn = p1 ;
1258  hash = 0 ;
1259  deg = 0 ;
1260  ASSERT (p1 >= 0 && p1 < iwlen && p2 >= -1 && p2 < iwlen) ;
1261 
1262  /* ------------------------------------------------------------- */
1263  /* scan the element list associated with supervariable i */
1264  /* ------------------------------------------------------------- */
1265 
1266  /* UMFPACK/MA38-style approximate degree: */
1267  if (aggressive)
1268  {
1269  for (p = p1 ; p <= p2 ; p++)
1270  {
1271  e = Iw [p] ;
1272  ASSERT (e >= 0 && e < n) ;
1273  we = W [e] ;
1274  if (we != 0)
1275  {
1276  /* e is an unabsorbed element */
1277  /* dext = | Le \ Lme | */
1278  dext = we - wflg ;
1279  if (dext > 0)
1280  {
1281  deg += dext ;
1282  Iw [pn++] = e ;
1283  hash += e ;
1284  CAMD_DEBUG4 ((" e: "ID" hash = "ID"\n",e,hash)) ;
1285  }
1286  else
1287  {
1288  if (IsInCurrentSet (C, e, curC))
1289  {
1290  /* external degree of e is zero and if
1291  * C[e] = curC; absorb e into me */
1292  CAMD_DEBUG1 ((" Element "ID" =>"ID" (aggr)\n",
1293  e, me)) ;
1294  ASSERT (dext == 0) ;
1295  Pe [e] = FLIP (me) ;
1296  W [e] = 0 ;
1297  }
1298  else
1299  {
1300  /* make element a root; kill it if not in same
1301  * bucket */
1302  CAMD_DEBUG1 (("2 Element "ID" =>"ID" (aggr)\n",
1303  e, me)) ;
1304  ASSERT (dext == 0) ;
1305  Pe [e] = EMPTY ;
1306  W [e] = 0 ;
1307  }
1308  }
1309  }
1310  }
1311  }
1312  else
1313  {
1314  for (p = p1 ; p <= p2 ; p++)
1315  {
1316  e = Iw [p] ;
1317  ASSERT (e >= 0 && e < n) ;
1318  we = W [e] ;
1319  if (we != 0)
1320  {
1321  /* e is an unabsorbed element */
1322  dext = we - wflg ;
1323  ASSERT (dext >= 0) ;
1324  deg += dext ;
1325  Iw [pn++] = e ;
1326  hash += e ;
1327  CAMD_DEBUG4 ((" e: "ID" hash = "ID"\n",e,hash)) ;
1328  }
1329  }
1330  }
1331 
1332  /* count the number of elements in i (including me): */
1333  Elen [i] = pn - p1 + 1 ;
1334 
1335  /* ------------------------------------------------------------- */
1336  /* scan the supervariables in the list associated with i */
1337  /* ------------------------------------------------------------- */
1338 
1339  /* The bulk of the CAMD run time is typically spent in this loop,
1340  * particularly if the matrix has many dense rows that are not
1341  * removed prior to ordering. */
1342  p3 = pn ;
1343  p4 = p1 + Len [i] ;
1344  for (p = p2 + 1 ; p < p4 ; p++)
1345  {
1346  j = Iw [p] ;
1347  ASSERT (j >= 0 && j < n) ;
1348  nvj = Nv [j] ;
1349  if (nvj > 0)
1350  {
1351  /* j is unabsorbed, and not in Lme. */
1352  /* add to degree and add to new list */
1353  deg += nvj ;
1354  Iw [pn++] = j ;
1355  hash += j ;
1356  CAMD_DEBUG4 ((" s: "ID" hash "ID" Nv[j]= "ID"\n",
1357  j, hash, nvj)) ;
1358  }
1359  }
1360 
1361  /* ------------------------------------------------------------- */
1362  /* update the degree and check for mass elimination */
1363  /* ------------------------------------------------------------- */
1364 
1365  /* with aggressive absorption, deg==0 is identical to the
1366  * Elen [i] == 1 && p3 == pn test, below. */
1367  ASSERT (IMPLIES (aggressive, (deg==0) == (Elen[i]==1 && p3==pn))) ;
1368 
1369  if (Elen [i] == 1 && p3 == pn && IsInCurrentSet (C, i, curC))
1370  {
1371 
1372  /* --------------------------------------------------------- */
1373  /* mass elimination */
1374  /* --------------------------------------------------------- */
1375 
1376  /* There is nothing left of this node except for an edge to
1377  * the current pivot element. Elen [i] is 1, and there are
1378  * no variables adjacent to node i. Absorb i into the
1379  * current pivot element, me. Note that if there are two or
1380  * more mass eliminations, fillin due to mass elimination is
1381  * possible within the nvpiv-by-nvpiv pivot block. It is this
1382  * step that causes CAMD's analysis to be an upper bound.
1383  *
1384  * The reason is that the selected pivot has a lower
1385  * approximate degree than the true degree of the two mass
1386  * eliminated nodes. There is no edge between the two mass
1387  * eliminated nodes. They are merged with the current pivot
1388  * anyway.
1389  *
1390  * No fillin occurs in the Schur complement, in any case,
1391  * and this effect does not decrease the quality of the
1392  * ordering itself, just the quality of the nonzero and
1393  * flop count analysis. It also means that the post-ordering
1394  * is not an exact elimination tree post-ordering. */
1395 
1396  CAMD_DEBUG1 ((" MASS i "ID" => parent e "ID"\n", i, me)) ;
1397  Pe [i] = FLIP (me) ;
1398  nvi = -Nv [i] ;
1399  degme -= nvi ;
1400  nvpiv += nvi ;
1401  nel += nvi ;
1402  Nv [i] = 0 ;
1403  Elen [i] = EMPTY ;
1404 
1405  }
1406  else
1407  {
1408 
1409  /* --------------------------------------------------------- */
1410  /* update the upper-bound degree of i */
1411  /* --------------------------------------------------------- */
1412 
1413  /* the following degree does not yet include the size
1414  * of the current element, which is added later: */
1415 
1416  Degree [i] = MIN (Degree [i], deg) ;
1417 
1418  /* --------------------------------------------------------- */
1419  /* add me to the list for i */
1420  /* --------------------------------------------------------- */
1421 
1422  /* move first supervariable to end of list */
1423  Iw [pn] = Iw [p3] ;
1424  /* move first element to end of element part of list */
1425  Iw [p3] = Iw [p1] ;
1426  /* add new element, me, to front of list. */
1427  Iw [p1] = me ;
1428  /* store the new length of the list in Len [i] */
1429  Len [i] = pn - p1 + 1 ;
1430 
1431  /* --------------------------------------------------------- */
1432  /* place in hash bucket. Save hash key of i in Last [i]. */
1433  /* --------------------------------------------------------- */
1434 
1435  /* NOTE: this can fail if hash is negative, because the ANSI C
1436  * standard does not define a % b when a and/or b are negative.
1437  * That's why hash is defined as an unsigned Int, to avoid this
1438  * problem. */
1439  hash = hash % n ;
1440  ASSERT (((Int) hash) >= 0 && ((Int) hash) < n) ;
1441 
1442  /* if the Hhead array is not used: */
1443  j = Head [hash] ;
1444  if (j <= EMPTY)
1445  {
1446  /* degree list is empty, hash head is FLIP (j) */
1447  Next [i] = FLIP (j) ;
1448  Head [hash] = FLIP (i) ;
1449  }
1450  else
1451  {
1452  /* degree list is not empty, use Last [Head [hash]] as
1453  * hash head. */
1454  Next [i] = Last [j] ;
1455  Last [j] = i ;
1456  }
1457 
1458  /* if a separate Hhead array is used: *
1459  Next [i] = Hhead [hash] ;
1460  Hhead [hash] = i ;
1461  */
1462 
1463  CAMD_DEBUG4 ((" s: "ID" hash "ID" \n", i, hash)) ;
1464  Last [i] = hash ;
1465  }
1466  }
1467 
1468  Degree [me] = degme ;
1469 
1470  /* ----------------------------------------------------------------- */
1471  /* Clear the counter array, W [...], by incrementing wflg. */
1472  /* ----------------------------------------------------------------- */
1473 
1474  /* make sure that wflg+n does not cause integer overflow */
1475  lemax = MAX (lemax, degme) ;
1476  wflg += lemax ;
1477  wflg = amesos_clear_flag (wflg, wbig, W, n) ;
1478  /* at this point, W [0..n-1] < wflg holds */
1479 
1480 /* ========================================================================= */
1481 /* SUPERVARIABLE DETECTION */
1482 /* ========================================================================= */
1483 
1484  CAMD_DEBUG1 (("Detecting supervariables:\n")) ;
1485  for (pme = pme1 ; pme <= pme2 ; pme++)
1486  {
1487  i = Iw [pme] ;
1488  ASSERT (i >= 0 && i < n) ;
1489  CAMD_DEBUG2 (("Consider i "ID" nv "ID"\n", i, Nv [i])) ;
1490  if (Nv [i] < 0)
1491  {
1492  /* i is a principal variable in Lme */
1493 
1494  /* ---------------------------------------------------------
1495  * examine all hash buckets with 2 or more variables. We do
1496  * this by examing all unique hash keys for supervariables in
1497  * the pattern Lme of the current element, me
1498  * --------------------------------------------------------- */
1499 
1500  CAMD_DEBUG2 (("Last: "ID"\n", Last [i])) ;
1501 
1502  /* let i = head of hash bucket, and empty the hash bucket */
1503  ASSERT (Last [i] >= 0 && Last [i] < n) ;
1504  hash = Last [i] ;
1505 
1506  /* if Hhead array is not used: */
1507  j = Head [hash] ;
1508  if (j == EMPTY)
1509  {
1510  /* hash bucket and degree list are both empty */
1511  i = EMPTY ;
1512  }
1513  else if (j < EMPTY)
1514  {
1515  /* degree list is empty */
1516  i = FLIP (j) ;
1517  Head [hash] = EMPTY ;
1518  }
1519  else
1520  {
1521  /* degree list is not empty, restore Last [j] of head j */
1522  i = Last [j] ;
1523  Last [j] = EMPTY ;
1524  }
1525 
1526  /* if separate Hhead array is used: *
1527  i = Hhead [hash] ;
1528  Hhead [hash] = EMPTY ;
1529  */
1530 
1531  ASSERT (i >= EMPTY && i < n) ;
1532  CAMD_DEBUG2 (("----i "ID" hash "ID"\n", i, hash)) ;
1533 
1534  while (i != EMPTY && Next [i] != EMPTY)
1535  {
1536 
1537  /* -----------------------------------------------------
1538  * this bucket has one or more variables following i.
1539  * scan all of them to see if i can absorb any entries
1540  * that follow i in hash bucket. Scatter i into w.
1541  * ----------------------------------------------------- */
1542 
1543  ln = Len [i] ;
1544  eln = Elen [i] ;
1545  ASSERT (ln >= 0 && eln >= 0) ;
1546  ASSERT (Pe [i] >= 0 && Pe [i] < iwlen) ;
1547  /* do not flag the first element in the list (me) */
1548  for (p = Pe [i] + 1 ; p <= Pe [i] + ln - 1 ; p++)
1549  {
1550  ASSERT (Iw [p] >= 0 && Iw [p] < n) ;
1551  W [Iw [p]] = wflg ;
1552  }
1553 
1554  /* ----------------------------------------------------- */
1555  /* scan every other entry j following i in bucket */
1556  /* ----------------------------------------------------- */
1557 
1558  jlast = i ;
1559  j = Next [i] ;
1560  ASSERT (j >= EMPTY && j < n) ;
1561 
1562  while (j != EMPTY)
1563  {
1564  /* ------------------------------------------------- */
1565  /* check if j and i have identical nonzero pattern */
1566  /* ------------------------------------------------- */
1567 
1568  CAMD_DEBUG3 (("compare i "ID" and j "ID"\n", i,j)) ;
1569 
1570  /* check if i and j have the same Len and Elen */
1571  /* and are in the same bucket */
1572  ASSERT (Len [j] >= 0 && Elen [j] >= 0) ;
1573  ASSERT (Pe [j] >= 0 && Pe [j] < iwlen) ;
1574  ok = (Len [j] == ln) && (Elen [j] == eln) ;
1575  ok = ok && InSameConstraintSet (C,i,j) ;
1576 
1577  /* skip the first element in the list (me) */
1578  for (p = Pe [j] + 1 ; ok && p <= Pe [j] + ln - 1 ; p++)
1579  {
1580  ASSERT (Iw [p] >= 0 && Iw [p] < n) ;
1581  if (W [Iw [p]] != wflg) ok = 0 ;
1582  }
1583  if (ok)
1584  {
1585  /* --------------------------------------------- */
1586  /* found it! j can be absorbed into i */
1587  /* --------------------------------------------- */
1588 
1589  CAMD_DEBUG1 (("found it! j "ID" => i "ID"\n", j,i));
1590  Pe [j] = FLIP (i) ;
1591  /* both Nv [i] and Nv [j] are negated since they */
1592  /* are in Lme, and the absolute values of each */
1593  /* are the number of variables in i and j: */
1594  Nv [i] += Nv [j] ;
1595  Nv [j] = 0 ;
1596  Elen [j] = EMPTY ;
1597  /* delete j from hash bucket */
1598  ASSERT (j != Next [j]) ;
1599  j = Next [j] ;
1600  Next [jlast] = j ;
1601 
1602  }
1603  else
1604  {
1605  /* j cannot be absorbed into i */
1606  jlast = j ;
1607  ASSERT (j != Next [j]) ;
1608  j = Next [j] ;
1609  }
1610  ASSERT (j >= EMPTY && j < n) ;
1611  }
1612 
1613  /* -----------------------------------------------------
1614  * no more variables can be absorbed into i
1615  * go to next i in bucket and clear flag array
1616  * ----------------------------------------------------- */
1617 
1618  wflg++ ;
1619  i = Next [i] ;
1620  ASSERT (i >= EMPTY && i < n) ;
1621 
1622  }
1623  }
1624  }
1625  CAMD_DEBUG2 (("detect done\n")) ;
1626 
1627 /* ========================================================================= */
1628 /* RESTORE DEGREE LISTS AND REMOVE NONPRINCIPAL SUPERVARIABLES FROM ELEMENT */
1629 /* ========================================================================= */
1630 
1631  p = pme1 ;
1632  nleft = n - nel ;
1633  for (pme = pme1 ; pme <= pme2 ; pme++)
1634  {
1635  i = Iw [pme] ;
1636  ASSERT (i >= 0 && i < n) ;
1637  nvi = -Nv [i] ;
1638  CAMD_DEBUG3 (("Restore i "ID" "ID"\n", i, nvi)) ;
1639  if (nvi > 0)
1640  {
1641  /* i is a principal variable in Lme */
1642  /* restore Nv [i] to signify that i is principal */
1643  Nv [i] = nvi ;
1644 
1645  /* --------------------------------------------------------- */
1646  /* compute the external degree (add size of current element) */
1647  /* --------------------------------------------------------- */
1648 
1649  deg = Degree [i] + degme - nvi ;
1650  deg = MIN (deg, nleft - nvi) ;
1651  ASSERT (deg >= 0 && deg < n) ;
1652 
1653  /* --------------------------------------------------------- */
1654  /* place the supervariable at the head of the degree list */
1655  /* --------------------------------------------------------- */
1656 
1657  if (IsInCurrentSet (C, i, curC))
1658  {
1659  inext = Head [deg] ;
1660  ASSERT (inext >= EMPTY && inext < n) ;
1661  if (inext != EMPTY) Last [inext] = i ;
1662  Next [i] = inext ;
1663  Last [i] = EMPTY ;
1664  Head [deg] = i ;
1665  degreeListCounter++ ;
1666  }
1667 
1668  /* --------------------------------------------------------- */
1669  /* save the new degree, and find the minimum degree */
1670  /* --------------------------------------------------------- */
1671 
1672  mindeg = MIN (mindeg, deg) ;
1673  Degree [i] = deg ;
1674 
1675  /* --------------------------------------------------------- */
1676  /* place the supervariable in the element pattern */
1677  /* --------------------------------------------------------- */
1678 
1679  Iw [p++] = i ;
1680  }
1681  }
1682  CAMD_DEBUG2 (("restore done\n")) ;
1683 
1684 /* ========================================================================= */
1685 /* FINALIZE THE NEW ELEMENT */
1686 /* ========================================================================= */
1687 
1688  CAMD_DEBUG2 (("ME = "ID" DONE\n", me)) ;
1689  Nv [me] = nvpiv ;
1690  /* save the length of the list for the new element me */
1691  Len [me] = p - pme1 ;
1692  if (Len [me] == 0)
1693  {
1694  /* there is nothing left of the current pivot element */
1695  /* it is a root of the assembly tree */
1696  Pe [me] = EMPTY ;
1697  W [me] = 0 ;
1698  }
1699  if (elenme != 0)
1700  {
1701  /* element was not constructed in place: deallocate part of */
1702  /* it since newly nonprincipal variables may have been removed */
1703  pfree = p ;
1704  }
1705 
1706  /* Store the element back into BucketSet. This is the way to maintain
1707  * the order of roots (Pe[i]=-1) in each Constraint Set. */
1708  BucketSet [pBucket2++] = me ;
1709 
1710  /* The new element has nvpiv pivots and the size of the contribution
1711  * block for a multifrontal method is degme-by-degme, not including
1712  * the "dense" rows/columns. If the "dense" rows/columns are included,
1713  * the frontal matrix is no larger than
1714  * (degme+ndense)-by-(degme+ndense).
1715  */
1716 
1717  if (Info != (double *) NULL)
1718  {
1719  f = nvpiv ;
1720  r = degme + ndense ;
1721  dmax = MAX (dmax, f + r) ;
1722 
1723  /* number of nonzeros in L (excluding the diagonal) */
1724  lnzme = f*r + (f-1)*f/2 ;
1725  lnz += lnzme ;
1726 
1727  /* number of divide operations for LDL' and for LU */
1728  ndiv += lnzme ;
1729 
1730  /* number of multiply-subtract pairs for LU */
1731  s = f*r*r + r*(f-1)*f + (f-1)*f*(2*f-1)/6 ;
1732  nms_lu += s ;
1733 
1734  /* number of multiply-subtract pairs for LDL' */
1735  nms_ldl += (s + lnzme)/2 ;
1736  }
1737 
1738 #ifndef NDEBUG
1739  CAMD_DEBUG2 (("finalize done nel "ID" n "ID"\n ::::\n", nel, n)) ;
1740  for (pme = Pe [me] ; pme <= Pe [me] + Len [me] - 1 ; pme++)
1741  {
1742  CAMD_DEBUG3 ((" "ID"", Iw [pme])) ;
1743  }
1744  CAMD_DEBUG3 (("\n")) ;
1745 #endif
1746 
1747  }
1748 
1749 /* ========================================================================= */
1750 /* DONE SELECTING PIVOTS */
1751 /* ========================================================================= */
1752 
1753  if (Info != (double *) NULL)
1754  {
1755 
1756  /* count the work to factorize the ndense-by-ndense submatrix */
1757  f = ndense ;
1758  dmax = MAX (dmax, (double) ndense) ;
1759 
1760  /* number of nonzeros in L (excluding the diagonal) */
1761  lnzme = (f-1)*f/2 ;
1762  lnz += lnzme ;
1763 
1764  /* number of divide operations for LDL' and for LU */
1765  ndiv += lnzme ;
1766 
1767  /* number of multiply-subtract pairs for LU */
1768  s = (f-1)*f*(2*f-1)/6 ;
1769  nms_lu += s ;
1770 
1771  /* number of multiply-subtract pairs for LDL' */
1772  nms_ldl += (s + lnzme)/2 ;
1773 
1774  /* number of nz's in L (excl. diagonal) */
1775  Info [CAMD_LNZ] = lnz ;
1776 
1777  /* number of divide ops for LU and LDL' */
1778  Info [CAMD_NDIV] = ndiv ;
1779 
1780  /* number of multiply-subtract pairs for LDL' */
1781  Info [CAMD_NMULTSUBS_LDL] = nms_ldl ;
1782 
1783  /* number of multiply-subtract pairs for LU */
1784  Info [CAMD_NMULTSUBS_LU] = nms_lu ;
1785 
1786  /* number of "dense" rows/columns */
1787  Info [CAMD_NDENSE] = ndense ;
1788 
1789  /* largest front is dmax-by-dmax */
1790  Info [CAMD_DMAX] = dmax ;
1791 
1792  /* number of garbage collections in CAMD */
1793  Info [CAMD_NCMPA] = ncmpa ;
1794 
1795  /* successful ordering */
1796  Info [CAMD_STATUS] = CAMD_OK ;
1797  }
1798 
1799 /* ========================================================================= */
1800 /* POST-ORDERING */
1801 /* ========================================================================= */
1802 
1803 /* -------------------------------------------------------------------------
1804  * Variables at this point:
1805  *
1806  * Pe: holds the elimination tree. The parent of j is FLIP (Pe [j]),
1807  * or EMPTY if j is a root. The tree holds both elements and
1808  * non-principal (unordered) variables absorbed into them.
1809  * Dense and empty variables are non-principal and unordered. They are
1810  * all represented by the fictitious node n (that is, Pe [i] = FLIP (n)
1811  * and Elen [i] = EMPTY if i is a dense or empty node).
1812  *
1813  * Elen: holds the size of each element, including the diagonal part.
1814  * FLIP (Elen [e]) > 0 if e is an element. For unordered
1815  * variables i, Elen [i] is EMPTY.
1816  *
1817  * Nv: Nv [e] > 0 is the number of pivots represented by the element e.
1818  * For unordered variables i, Nv [i] is zero.
1819  *
1820  * BucketSet: BucketSet [0.....pBucket2] holds all
1821  * the elements that removed during the elimination, in eliminated order.
1822  *
1823  *
1824  * Contents no longer needed:
1825  * W, Iw, Len, Degree, Head, Next, Last.
1826  *
1827  * The matrix itself has been destroyed.
1828  *
1829  * n: the size of the matrix.
1830  * ndense: the number of "dense" nodes.
1831  * nnull: the number of empty nodes (zero degree)
1832  * No other scalars needed (pfree, iwlen, etc.)
1833  * ------------------------------------------------------------------------- */
1834 
1835 
1836  /* restore Pe */
1837  for (i = 0 ; i < n ; i++)
1838  {
1839  Pe [i] = FLIP (Pe [i]) ;
1840  }
1841 
1842  /* restore Elen, for output information only */
1843  for (i = 0 ; i < n ; i++)
1844  {
1845  Elen [i] = FLIP (Elen [i]) ;
1846  }
1847 
1848  /* Now, Pe [j] is the parent of j, or EMPTY if j is a root.
1849  * Pe [j] = n if j is a dense/empty node */
1850 
1851  /* place all variables in the list of children of their parents */
1852  for (j = n-1 ; j >= 0 ; j--)
1853  {
1854  if (Nv [j] > 0) continue ; /* skip if j is an element */
1855  ASSERT (Pe [j] >= 0 && Pe [j] <= n) ;
1856  Next [j] = Head [Pe [j]] ; /* place j in list of its parent */
1857  Head [Pe [j]] = j ;
1858  }
1859 
1860  /* place all elements in the list of children of their parents */
1861  for (e = n-1 ; e >= 0 ; e--)
1862  {
1863  if (Nv [e] <= 0) continue ; /* skip if e is a variable */
1864  if (Pe [e] == EMPTY) continue ; /* skip if e is a root */
1865  Next [e] = Head [Pe [e]] ; /* place e in list of its parent */
1866  Head [Pe [e]] = e ;
1867  }
1868 
1869  /* determine where to put the postordering permutation */
1870  if (C != NULL && ndense_or_null > 0)
1871  {
1872  /* Perm needs to be computed in a temporary workspace, and then
1873  * transformed and copied into the output permutation, in Last */
1874  Perm = Degree ;
1875  }
1876  else
1877  {
1878  /* the postorder computes the permutation directly, in Last */
1879  Perm = Last ;
1880  }
1881 
1882  /* postorder the elements and their descendants (both elements and
1883  * variables), but not (yet) the dense/empty nodes */
1884  for (k = 0 , i = 0 ; i < pBucket2 ; i++)
1885  {
1886  j = BucketSet [i] ;
1887  ASSERT (j >= 0 && j < n) ;
1888  if (Pe [j] == EMPTY)
1889  {
1890  k = CAMD_postorder (j, k, n, Head, Next, Perm, W) ;
1891  }
1892  }
1893 
1894  /* Perm [0..k-1] now contains a list of the nonempty/nondense nodes,
1895  * ordered via minimum degree and following the constraints. */
1896 
1897  CAMD_DEBUG1 (("before dense/empty, k = "ID"\n", k)) ;
1898  fflush (stdout) ;
1899  ASSERT (k + ndense_or_null == n) ;
1900 
1901  if (ndense_or_null > 0)
1902  {
1903  if (C == NULL)
1904  {
1905  /* postorder the dense/empty nodes (the parent of all these is n) */
1906  CAMD_postorder (n, k, n, Head, Next, Perm, W) ;
1907  }
1908  else
1909  {
1910  /* dense (or empty) nodes exist, AND C also exists. The dense/empty
1911  * nodes are a link list whose head is Head[n], and Next[i] gives the
1912  * next node after i in the list. They need to be sorted by their
1913  * constraints, and then merged with Perm [0..k-1].*/
1914 
1915  /* count how many dense/empty nodes are in each constraint set */
1916 
1917  Bucket = W ; /* use W as workspace (it has size n+1) */
1918 
1919  /* count the number of dense/empty nodes in each constraint set */
1920  for (c = 0 ; c <= cmax ; c++)
1921  {
1922  Bucket [c] = 0 ;
1923  }
1924  i = 0 ;
1925  for (j = Head [n] ; j != EMPTY ; j = Next [j])
1926  {
1927  CAMD_DEBUG1 (("Dense/empty node: "ID" : "ID" "ID"\n", j,
1928  Pe [j], Elen [j])) ;
1929  fflush (stdout) ;
1930  ASSERT (Pe [j] == n && Elen [j] == EMPTY) ;
1931  i++ ;
1932  Bucket [C [j]]++ ;
1933  }
1934  ASSERT (i == ndense_or_null) ;
1935 
1936  /* find the cumulative sum of Bucket */
1937  knt1 = 0 ;
1938  for (c = 0 ; c <= cmax ; c++)
1939  {
1940  i = Bucket [c] ;
1941  Bucket [c] = knt1 ;
1942  knt1 += i ;
1943  }
1944  CAMD_DEBUG1 (("knt1 "ID" dense/empty "ID"\n", knt1, ndense_or_null));
1945  ASSERT (knt1 == ndense_or_null) ;
1946 
1947  /* place dense/empty nodes in BucketSet, in constraint order,
1948  * ties in natural order */
1949  for (j = Head [n] ; j != EMPTY ; j = Next [j])
1950  {
1951  BucketSet [Bucket [C [j]]++] = j ;
1952  }
1953 
1954 #ifndef NDEBUG
1955  /* each set is in monotonically increasing order of constraints */
1956  for (i = 1 ; i < k ; i++)
1957  {
1958  ASSERT (C [Perm [i]] >= C [Perm [i-1]]) ;
1959  }
1960  for (i = 1 ; i < ndense_or_null ; i++)
1961  {
1962  /* in order of constraints, with ties in natural order */
1963  ASSERT (
1964  (C [BucketSet [i]] > C [BucketSet [i-1]]) ||
1965  (C [BucketSet [i]] == C [BucketSet [i-1]]
1966  && (BucketSet [i] > BucketSet [i-1]))) ;
1967  }
1968 #endif
1969 
1970  /* merge Perm [0..k-1] and BucketSet [0..ndense+nnull] */
1971  p1 = 0 ;
1972  p2 = 0 ;
1973  p3 = 0 ;
1974  while (p1 < k && p2 < ndense_or_null)
1975  {
1976  /* place the dense/empty nodes at the end of each constraint
1977  * set, after the non-dense/non-empty nodes in the same set */
1978  if (C [Perm [p1]] <= C [BucketSet [p2]])
1979  {
1980  /* non-dense/non-empty node */
1981  Last [p3++] = Perm [p1++] ;
1982  }
1983  else
1984  {
1985  /* dense/empty node */
1986  Last [p3++] = BucketSet [p2++] ;
1987  }
1988  }
1989  /* wrap up; either Perm[0..k-1] or BucketSet[ ] is used up */
1990  while (p1 < k)
1991  {
1992  Last [p3++] = Perm [p1++] ;
1993  }
1994  while (p2 < ndense_or_null)
1995  {
1996  Last [p3++] = BucketSet [p2++] ;
1997  }
1998  }
1999  }
2000 
2001 #ifndef NDEBUG
2002  CAMD_DEBUG1 (("\nFinal constrained ordering:\n")) ;
2003  i = 0 ;
2004  CAMD_DEBUG1 (("Last ["ID"] = "ID", C["ID"] = "ID"\n", i, Last [i],
2005  Last [i], C [Last [i]])) ;
2006  for (i = 1 ; i < n ; i++)
2007  {
2008  CAMD_DEBUG1 (("Last ["ID"] = "ID", C["ID"] = "ID"\n", i, Last [i],
2009  Last [i], C [Last [i]])) ;
2010 
2011  /* This is the critical assertion. It states that the permutation
2012  * satisfies the constraints. */
2013  ASSERT (C [Last [i]] >= C [Last [i-1]]) ;
2014  }
2015 #endif
2016 }
#define CAMD_dump
#define CAMD_DMAX
Definition: amesos_camd.h:376
#define CAMD_postorder
#define CAMD_debug
void f()
#define CAMD_DENSE
Definition: amesos_camd.h:355
#define EMPTY
#define CAMD_STATUS
Definition: amesos_camd.h:363
#define GLOBAL
#define CAMD_NCMPA
Definition: amesos_camd.h:371
#define Int
#define CAMD_AGGRESSIVE
Definition: amesos_camd.h:356
#define CAMD_LNZ
Definition: amesos_camd.h:372
static Int amesos_clear_flag(Int wflg, Int wbig, Int W[], Int n)
#define CAMD_NMULTSUBS_LDL
Definition: amesos_camd.h:374
#define CAMD_DEBUG3(params)
#define MAX(a, b)
#define NULL
#define ASSERT(expression)
#define FLIP(i)
#define ID
#define CAMD_NDENSE
Definition: amesos_camd.h:369
#define InSameConstraintSet(C, i, j)
#define CAMD_DEBUG1(params)
#define CAMD_NDIV
Definition: amesos_camd.h:373
GLOBAL void CAMD_2(Int n, Int Pe[], Int Iw[], Int Len[], Int iwlen, Int pfree, Int Nv[], Int Next[], Int Last[], Int Head[], Int Elen[], Int Degree[], Int W[], double Control[], double Info[], const Int C[], Int BucketSet[])
#define Int_MAX
#define CAMD_NMULTSUBS_LU
Definition: amesos_camd.h:375
#define CAMD_DEBUG4(params)
#define MIN(a, b)
#define CAMD_OK
Definition: amesos_camd.h:382
#define CAMD_DEFAULT_AGGRESSIVE
Definition: amesos_camd.h:360
#define IsInCurrentSet(C, i, curC)
#define IMPLIES(p, q)
#define CAMD_DEBUG2(params)
#define CAMD_DEFAULT_DENSE
Definition: amesos_camd.h:359