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