Amesos Package Browser (Single Doxygen Collection)  Development
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
amesos_ccolamd.c
Go to the documentation of this file.
1 /* ========================================================================== */
2 /* === CCOLAMD/CSYMAMD - a constrained column ordering algorithm ============ */
3 /* ========================================================================== */
4 
5 /* ----------------------------------------------------------------------------
6  * CCOLAMD, Copyright (C) Univ. of Florida. Authors: Timothy A. Davis,
7  * Sivasankaran Rajamanickam, and Stefan Larimore
8  * See License.txt for the Version 2.1 of the GNU Lesser General Public License
9  * http://www.cise.ufl.edu/research/sparse
10  * -------------------------------------------------------------------------- */
11 
12 /*
13  * ccolamd: a constrained approximate minimum degree column ordering
14  * algorithm, LU factorization of symmetric or unsymmetric matrices,
15  * QR factorization, least squares, interior point methods for
16  * linear programming problems, and other related problems.
17  *
18  * csymamd: a constrained approximate minimum degree ordering algorithm for
19  * Cholesky factorization of symmetric matrices.
20  *
21  * Purpose:
22  *
23  * CCOLAMD computes a permutation Q such that the Cholesky factorization of
24  * (AQ)'(AQ) has less fill-in and requires fewer floating point operations
25  * than A'A. This also provides a good ordering for sparse partial
26  * pivoting methods, P(AQ) = LU, where Q is computed prior to numerical
27  * factorization, and P is computed during numerical factorization via
28  * conventional partial pivoting with row interchanges. CCOLAMD is an
29  * extension of COLAMD, available as built-in function in MATLAB Version 6,
30  * available from MathWorks, Inc. (http://www.mathworks.com). This
31  * routine can be used in place of COLAMD in MATLAB.
32  *
33  * CSYMAMD computes a permutation P of a symmetric matrix A such that the
34  * Cholesky factorization of PAP' has less fill-in and requires fewer
35  * floating point operations than A. CSYMAMD constructs a matrix M such
36  * that M'M has the same nonzero pattern of A, and then orders the columns
37  * of M using colmmd. The column ordering of M is then returned as the
38  * row and column ordering P of A. CSYMAMD is an extension of SYMAMD.
39  *
40  * Authors:
41  *
42  * Timothy A. Davis and S. Rajamanickam wrote CCOLAMD, based directly on
43  * COLAMD by Stefan I. Larimore and Timothy A. Davis, University of
44  * Florida. The algorithm was developed in collaboration with John
45  * Gilbert, (UCSB, then at Xerox PARC), and Esmond Ng, (Lawrence Berkeley
46  * National Lab, then at Oak Ridge National Laboratory).
47  *
48  * Acknowledgements:
49  *
50  * This work was supported by the National Science Foundation, under
51  * grants DMS-9504974 and DMS-9803599, CCR-0203270, and a grant from the
52  * Sandia National Laboratory (Dept. of Energy).
53  *
54  * Copyright and License:
55  *
56  * Copyright (c) 1998-2005 by the University of Florida.
57  * All Rights Reserved.
58  * COLAMD is also available under alternate licenses, contact T. Davis
59  * for details.
60  *
61  * This library is free software; you can redistribute it and/or
62  * modify it under the terms of the GNU Lesser General Public
63  * License as published by the Free Software Foundation; either
64  * version 2.1 of the License, or (at your option) any later version.
65  *
66  * This library is distributed in the hope that it will be useful,
67  * but WITHOUT ANY WARRANTY; without even the implied warranty of
68  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
69  * Lesser General Public License for more details.
70  *
71  * You should have received a copy of the GNU Lesser General Public
72  * License along with this library; if not, write to the Free Software
73  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
74  * USA
75  *
76  * Permission is hereby granted to use or copy this program under the
77  * terms of the GNU LGPL, provided that the Copyright, this License,
78  * and the Availability of the original version is retained on all copies.
79  * User documentation of any code that uses this code or any modified
80  * version of this code must cite the Copyright, this License, the
81  * Availability note, and "Used by permission." Permission to modify
82  * the code and to distribute modified code is granted, provided the
83  * Copyright, this License, and the Availability note are retained,
84  * and a notice that the code was modified is included.
85  *
86  * Availability:
87  *
88  * The CCOLAMD/CSYMAMD library is available at
89  *
90  * http://www.cise.ufl.edu/research/sparse/ccolamd/
91  *
92  * This is the http://www.cise.ufl.edu/research/sparse/ccolamd/ccolamd.c
93  * file.
94  *
95  * See the ChangeLog file for changes since Version 1.0.
96  */
97 
98 /* ========================================================================== */
99 /* === Description of user-callable routines ================================ */
100 /* ========================================================================== */
101 
102 /* CCOLAMD includes both int and UF_long versions of all its routines. The
103  * description below is for the int version. For UF_long, all int arguments
104  * become UF_long integers. UF_long is normally defined as long, except for
105  * WIN64 */
106 
107 /* ----------------------------------------------------------------------------
108  * ccolamd_recommended:
109  * ----------------------------------------------------------------------------
110  *
111  * C syntax:
112  *
113  * #include "ccolamd.h"
114  * size_t ccolamd_recommended (int nnz, int n_row, int n_col) ;
115  * size_t ccolamd_l_recommended (UF_long nnz, UF_long n_row,
116  * UF_long n_col) ;
117  *
118  * Purpose:
119  *
120  * Returns recommended value of Alen for use by ccolamd. Returns 0
121  * if any input argument is negative. The use of this routine
122  * is optional. Not needed for csymamd, which dynamically allocates
123  * its own memory.
124  *
125  * Arguments (all input arguments):
126  *
127  * int nnz ; Number of nonzeros in the matrix A. This must
128  * be the same value as p [n_col] in the call to
129  * ccolamd - otherwise you will get a wrong value
130  * of the recommended memory to use.
131  *
132  * int n_row ; Number of rows in the matrix A.
133  *
134  * int n_col ; Number of columns in the matrix A.
135  *
136  * ----------------------------------------------------------------------------
137  * ccolamd_set_defaults:
138  * ----------------------------------------------------------------------------
139  *
140  * C syntax:
141  *
142  * #include "ccolamd.h"
143  * ccolamd_set_defaults (double knobs [CCOLAMD_KNOBS]) ;
144  * ccolamd_l_set_defaults (double knobs [CCOLAMD_KNOBS]) ;
145  *
146  * Purpose:
147  *
148  * Sets the default parameters. The use of this routine is optional.
149  * Passing a (double *) NULL pointer for the knobs results in the
150  * default parameter settings.
151  *
152  * Arguments:
153  *
154  * double knobs [CCOLAMD_KNOBS] ; Output only.
155  *
156  * knobs [0] and knobs [1] behave differently than they did in COLAMD.
157  * The other knobs are new to CCOLAMD.
158  *
159  * knobs [0]: dense row control
160  *
161  * For CCOLAMD, rows with more than
162  * max (16, knobs [CCOLAMD_DENSE_ROW] * sqrt (n_col))
163  * entries are removed prior to ordering.
164  *
165  * For CSYMAMD, rows and columns with more than
166  * max (16, knobs [CCOLAMD_DENSE_ROW] * sqrt (n))
167  * entries are removed prior to ordering, and placed last in the
168  * output ordering (subject to the constraints).
169  *
170  * If negative, only completely dense rows are removed. If you
171  * intend to use CCOLAMD for a Cholesky factorization of A*A', set
172  * knobs [CCOLAMD_DENSE_ROW] to -1, which is more appropriate for
173  * that case.
174  *
175  * Default: 10.
176  *
177  * knobs [1]: dense column control
178  *
179  * For CCOLAMD, columns with more than
180  * max (16, knobs [CCOLAMD_DENSE_COL] * sqrt (MIN (n_row,n_col)))
181  * entries are removed prior to ordering, and placed last in the
182  * output column ordering (subject to the constraints).
183  * Not used by CSYMAMD. If negative, only completely dense
184  * columns are removed. Default: 10.
185  *
186  * knobs [2]: aggressive absorption
187  *
188  * knobs [CCOLAMD_AGGRESSIVE] controls whether or not to do
189  * aggressive absorption during the ordering. Default is TRUE
190  * (nonzero). If zero, no aggressive absorption is performed.
191  *
192  * knobs [3]: optimize ordering for LU or Cholesky
193  *
194  * knobs [CCOLAMD_LU] controls an option that optimizes the
195  * ordering for the LU of A or the Cholesky factorization of A'A.
196  * If TRUE (nonzero), an ordering optimized for LU is performed.
197  * If FALSE (zero), an ordering for Cholesky is performed.
198  * Default is FALSE. CSYMAMD ignores this parameter; it always
199  * orders for Cholesky.
200  *
201  * ----------------------------------------------------------------------------
202  * ccolamd:
203  * ----------------------------------------------------------------------------
204  *
205  * C syntax:
206  *
207  * #include "ccolamd.h"
208  * int ccolamd (int n_row, int n_col, int Alen, int *A, int *p,
209  * double knobs [CCOLAMD_KNOBS], int stats [CCOLAMD_STATS],
210  * int *cmember) ;
211  *
212  * UF_long ccolamd_l (UF_long n_row, UF_long n_col, UF_long Alen,
213  * UF_long *A, UF_long *p, double knobs [CCOLAMD_KNOBS],
214  * UF_long stats [CCOLAMD_STATS], UF_long *cmember) ;
215  *
216  * Purpose:
217  *
218  * Computes a column ordering (Q) of A such that P(AQ)=LU or
219  * (AQ)'AQ=LL' have less fill-in and require fewer floating point
220  * operations than factorizing the unpermuted matrix A or A'A,
221  * respectively.
222  *
223  * Returns:
224  *
225  * TRUE (1) if successful, FALSE (0) otherwise.
226  *
227  * Arguments (for int version):
228  *
229  * int n_row ; Input argument.
230  *
231  * Number of rows in the matrix A.
232  * Restriction: n_row >= 0.
233  * ccolamd returns FALSE if n_row is negative.
234  *
235  * int n_col ; Input argument.
236  *
237  * Number of columns in the matrix A.
238  * Restriction: n_col >= 0.
239  * ccolamd returns FALSE if n_col is negative.
240  *
241  * int Alen ; Input argument.
242  *
243  * Restriction (see note):
244  * Alen >= MAX (2*nnz, 4*n_col) + 17*n_col + 7*n_row + 7, where
245  * nnz = p [n_col]. ccolamd returns FALSE if this condition is
246  * not met. We recommend about nnz/5 more space for better
247  * efficiency. This restriction makes an modest assumption
248  * regarding the size of two typedef'd structures in ccolamd.h.
249  * We do, however, guarantee that
250  *
251  * Alen >= ccolamd_recommended (nnz, n_row, n_col)
252  *
253  * will work efficiently.
254  *
255  * int A [Alen] ; Input argument, undefined on output.
256  *
257  * A is an integer array of size Alen. Alen must be at least as
258  * large as the bare minimum value given above, but this is very
259  * low, and can result in excessive run time. For best
260  * performance, we recommend that Alen be greater than or equal to
261  * ccolamd_recommended (nnz, n_row, n_col), which adds
262  * nnz/5 to the bare minimum value given above.
263  *
264  * On input, the row indices of the entries in column c of the
265  * matrix are held in A [(p [c]) ... (p [c+1]-1)]. The row indices
266  * in a given column c need not be in ascending order, and
267  * duplicate row indices may be be present. However, ccolamd will
268  * work a little faster if both of these conditions are met
269  * (ccolamd puts the matrix into this format, if it finds that the
270  * the conditions are not met).
271  *
272  * The matrix is 0-based. That is, rows are in the range 0 to
273  * n_row-1, and columns are in the range 0 to n_col-1. ccolamd
274  * returns FALSE if any row index is out of range.
275  *
276  * The contents of A are modified during ordering, and are
277  * undefined on output.
278  *
279  * int p [n_col+1] ; Both input and output argument.
280  *
281  * p is an integer array of size n_col+1. On input, it holds the
282  * "pointers" for the column form of the matrix A. Column c of
283  * the matrix A is held in A [(p [c]) ... (p [c+1]-1)]. The first
284  * entry, p [0], must be zero, and p [c] <= p [c+1] must hold
285  * for all c in the range 0 to n_col-1. The value nnz = p [n_col]
286  * is thus the total number of entries in the pattern of the
287  * matrix A. ccolamd returns FALSE if these conditions are not
288  * met.
289  *
290  * On output, if ccolamd returns TRUE, the array p holds the column
291  * permutation (Q, for P(AQ)=LU or (AQ)'(AQ)=LL'), where p [0] is
292  * the first column index in the new ordering, and p [n_col-1] is
293  * the last. That is, p [k] = j means that column j of A is the
294  * kth pivot column, in AQ, where k is in the range 0 to n_col-1
295  * (p [0] = j means that column j of A is the first column in AQ).
296  *
297  * If ccolamd returns FALSE, then no permutation is returned, and
298  * p is undefined on output.
299  *
300  * double knobs [CCOLAMD_KNOBS] ; Input argument.
301  *
302  * See ccolamd_set_defaults for a description.
303  *
304  * int stats [CCOLAMD_STATS] ; Output argument.
305  *
306  * Statistics on the ordering, and error status.
307  * See ccolamd.h for related definitions.
308  * ccolamd returns FALSE if stats is not present.
309  *
310  * stats [0]: number of dense or empty rows ignored.
311  *
312  * stats [1]: number of dense or empty columns ignored (and
313  * ordered last in the output permutation p, subject to the
314  * constraints). Note that a row can become "empty" if it
315  * contains only "dense" and/or "empty" columns, and similarly
316  * a column can become "empty" if it only contains "dense"
317  * and/or "empty" rows.
318  *
319  * stats [2]: number of garbage collections performed. This can
320  * be excessively high if Alen is close to the minimum
321  * required value.
322  *
323  * stats [3]: status code. < 0 is an error code.
324  * > 1 is a warning or notice.
325  *
326  * 0 OK. Each column of the input matrix contained row
327  * indices in increasing order, with no duplicates.
328  *
329  * 1 OK, but columns of input matrix were jumbled (unsorted
330  * columns or duplicate entries). CCOLAMD had to do some
331  * extra work to sort the matrix first and remove
332  * duplicate entries, but it still was able to return a
333  * valid permutation (return value of ccolamd was TRUE).
334  *
335  * stats [4]: highest column index of jumbled columns
336  * stats [5]: last seen duplicate or unsorted row index
337  * stats [6]: number of duplicate or unsorted row indices
338  *
339  * -1 A is a null pointer
340  *
341  * -2 p is a null pointer
342  *
343  * -3 n_row is negative. stats [4]: n_row
344  *
345  * -4 n_col is negative. stats [4]: n_col
346  *
347  * -5 number of nonzeros in matrix is negative
348  *
349  * stats [4]: number of nonzeros, p [n_col]
350  *
351  * -6 p [0] is nonzero
352  *
353  * stats [4]: p [0]
354  *
355  * -7 A is too small
356  *
357  * stats [4]: required size
358  * stats [5]: actual size (Alen)
359  *
360  * -8 a column has a negative number of entries
361  *
362  * stats [4]: column with < 0 entries
363  * stats [5]: number of entries in col
364  *
365  * -9 a row index is out of bounds
366  *
367  * stats [4]: column with bad row index
368  * stats [5]: bad row index
369  * stats [6]: n_row, # of rows of matrx
370  *
371  * -10 (unused; see csymamd)
372  *
373  * int cmember [n_col] ; Input argument.
374  *
375  * cmember is new to CCOLAMD. It did not appear in COLAMD.
376  * It places contraints on the output ordering. s = cmember [j]
377  * gives the constraint set s that contains the column j
378  * (Restriction: 0 <= s < n_col). In the output column
379  * permutation, all columns in set 0 appear first, followed by
380  * all columns in set 1, and so on. If NULL, all columns are
381  * treated as if they were in a single constraint set, and you
382  * will obtain the same ordering as COLAMD (with one exception:
383  * the dense row/column threshold and other default knobs in
384  * CCOLAMD and COLAMD are different).
385  *
386  * Example:
387  *
388  * See
389  * http://www.cise.ufl.edu/research/sparse/ccolamd/ccolamd_example.c
390  * for a complete example.
391  *
392  * To order the columns of a 5-by-4 matrix with 11 nonzero entries in
393  * the following nonzero pattern
394  *
395  * x 0 x 0
396  * x 0 x x
397  * 0 x x 0
398  * 0 0 x x
399  * x x 0 0
400  *
401  * with default knobs, no output statistics, and no ordering
402  * constraints, do the following:
403  *
404  * #include "ccolamd.h"
405  * #define ALEN 144
406  * int A [ALEN] = {0, 1, 4, 2, 4, 0, 1, 2, 3, 1, 3} ;
407  * int p [ ] = {0, 3, 5, 9, 11} ;
408  * int stats [CCOLAMD_STATS] ;
409  * ccolamd (5, 4, ALEN, A, p, (double *) NULL, stats, NULL) ;
410  *
411  * The permutation is returned in the array p, and A is destroyed.
412  *
413  * ----------------------------------------------------------------------------
414  * csymamd:
415  * ----------------------------------------------------------------------------
416  *
417  * C syntax:
418  *
419  * #include "ccolamd.h"
420  *
421  * int csymamd (int n, int *A, int *p, int *perm,
422  * double knobs [CCOLAMD_KNOBS], int stats [CCOLAMD_STATS],
423  * void (*allocate) (size_t, size_t), void (*release) (void *),
424  * int *cmember, int stype) ;
425  *
426  * UF_long csymamd_l (UF_long n, UF_long *A, UF_long *p, UF_long *perm,
427  * double knobs [CCOLAMD_KNOBS], UF_long stats [CCOLAMD_STATS],
428  * void (*allocate) (size_t, size_t), void (*release) (void *),
429  * UF_long *cmember, UF_long stype) ;
430  *
431  * Purpose:
432  *
433  * The csymamd routine computes an ordering P of a symmetric sparse
434  * matrix A such that the Cholesky factorization PAP' = LL' remains
435  * sparse. It is based on a column ordering of a matrix M constructed
436  * so that the nonzero pattern of M'M is the same as A. Either the
437  * lower or upper triangular part of A can be used, or the pattern
438  * A+A' can be used. You must pass your selected memory allocator
439  * (usually calloc/free or mxCalloc/mxFree) to csymamd, for it to
440  * allocate memory for the temporary matrix M.
441  *
442  * Returns:
443  *
444  * TRUE (1) if successful, FALSE (0) otherwise.
445  *
446  * Arguments:
447  *
448  * int n ; Input argument.
449  *
450  * Number of rows and columns in the symmetrix matrix A.
451  * Restriction: n >= 0.
452  * csymamd returns FALSE if n is negative.
453  *
454  * int A [nnz] ; Input argument.
455  *
456  * A is an integer array of size nnz, where nnz = p [n].
457  *
458  * The row indices of the entries in column c of the matrix are
459  * held in A [(p [c]) ... (p [c+1]-1)]. The row indices in a
460  * given column c need not be in ascending order, and duplicate
461  * row indices may be present. However, csymamd will run faster
462  * if the columns are in sorted order with no duplicate entries.
463  *
464  * The matrix is 0-based. That is, rows are in the range 0 to
465  * n-1, and columns are in the range 0 to n-1. csymamd
466  * returns FALSE if any row index is out of range.
467  *
468  * The contents of A are not modified.
469  *
470  * int p [n+1] ; Input argument.
471  *
472  * p is an integer array of size n+1. On input, it holds the
473  * "pointers" for the column form of the matrix A. Column c of
474  * the matrix A is held in A [(p [c]) ... (p [c+1]-1)]. The first
475  * entry, p [0], must be zero, and p [c] <= p [c+1] must hold
476  * for all c in the range 0 to n-1. The value p [n] is
477  * thus the total number of entries in the pattern of the matrix A.
478  * csymamd returns FALSE if these conditions are not met.
479  *
480  * The contents of p are not modified.
481  *
482  * int perm [n+1] ; Output argument.
483  *
484  * On output, if csymamd returns TRUE, the array perm holds the
485  * permutation P, where perm [0] is the first index in the new
486  * ordering, and perm [n-1] is the last. That is, perm [k] = j
487  * means that row and column j of A is the kth column in PAP',
488  * where k is in the range 0 to n-1 (perm [0] = j means
489  * that row and column j of A are the first row and column in
490  * PAP'). The array is used as a workspace during the ordering,
491  * which is why it must be of length n+1, not just n.
492  *
493  * double knobs [CCOLAMD_KNOBS] ; Input argument.
494  *
495  * See colamd_set_defaults for a description.
496  *
497  * int stats [CCOLAMD_STATS] ; Output argument.
498  *
499  * Statistics on the ordering, and error status.
500  * See ccolamd.h for related definitions.
501  * csymand returns FALSE if stats is not present.
502  *
503  * stats [0]: number of dense or empty row and columns ignored
504  * (and ordered last in the output permutation perm, subject
505  * to the constraints). Note that a row/column can become
506  * "empty" if it contains only "dense" and/or "empty"
507  * columns/rows.
508  *
509  * stats [1]: (same as stats [0])
510  *
511  * stats [2]: number of garbage collections performed.
512  *
513  * stats [3]: status code. < 0 is an error code.
514  * > 1 is a warning or notice.
515  *
516  * 0 to -9: same as ccolamd, with n replacing n_col and n_row,
517  * and -3 and -7 are unused.
518  *
519  * -10 out of memory (unable to allocate temporary workspace
520  * for M or count arrays using the "allocate" routine
521  * passed into csymamd).
522  *
523  * void * (*allocate) (size_t, size_t)
524  *
525  * A pointer to a function providing memory allocation. The
526  * allocated memory must be returned initialized to zero. For a
527  * C application, this argument should normally be a pointer to
528  * calloc. For a MATLAB mexFunction, the routine mxCalloc is
529  * passed instead.
530  *
531  * void (*release) (size_t, size_t)
532  *
533  * A pointer to a function that frees memory allocated by the
534  * memory allocation routine above. For a C application, this
535  * argument should normally be a pointer to free. For a MATLAB
536  * mexFunction, the routine mxFree is passed instead.
537  *
538  * int cmember [n] ; Input argument.
539  *
540  * Same as ccolamd, except that cmember is of size n, and it places
541  * contraints symmetrically, on both the row and column ordering.
542  * Entries in cmember must be in the range 0 to n-1.
543  *
544  * int stype ; Input argument.
545  *
546  * If stype < 0, then only the strictly lower triangular part of
547  * A is accessed. The upper triangular part is assumed to be the
548  * transpose of the lower triangular part. This is the same as
549  * SYMAMD, which did not have an stype parameter.
550  *
551  * If stype > 0, only the strictly upper triangular part of A is
552  * accessed. The lower triangular part is assumed to be the
553  * transpose of the upper triangular part.
554  *
555  * If stype == 0, then the nonzero pattern of A+A' is ordered.
556  *
557  * ----------------------------------------------------------------------------
558  * ccolamd_report:
559  * ----------------------------------------------------------------------------
560  *
561  * C syntax:
562  *
563  * #include "ccolamd.h"
564  * ccolamd_report (int stats [CCOLAMD_STATS]) ;
565  * ccolamd_l_report (UF_long stats [CCOLAMD_STATS]) ;
566  *
567  * Purpose:
568  *
569  * Prints the error status and statistics recorded in the stats
570  * array on the standard error output (for a standard C routine)
571  * or on the MATLAB output (for a mexFunction).
572  *
573  * Arguments:
574  *
575  * int stats [CCOLAMD_STATS] ; Input only. Statistics from ccolamd.
576  *
577  *
578  * ----------------------------------------------------------------------------
579  * csymamd_report:
580  * ----------------------------------------------------------------------------
581  *
582  * C syntax:
583  *
584  * #include "ccolamd.h"
585  * csymamd_report (int stats [CCOLAMD_STATS]) ;
586  * csymamd_l_report (UF_long stats [CCOLAMD_STATS]) ;
587  *
588  * Purpose:
589  *
590  * Prints the error status and statistics recorded in the stats
591  * array on the standard error output (for a standard C routine)
592  * or on the MATLAB output (for a mexFunction).
593  *
594  * Arguments:
595  *
596  * int stats [CCOLAMD_STATS] ; Input only. Statistics from csymamd.
597  *
598  */
599 
600 
601 /* ========================================================================== */
602 /* === Scaffolding code definitions ======================================== */
603 /* ========================================================================== */
604 
605 /* Ensure that debugging is turned off: */
606 #ifndef NDEBUG
607 #define NDEBUG
608 #endif
609 
610 /* turn on debugging by uncommenting the following line
611  #undef NDEBUG
612  */
613 
614 /* ========================================================================== */
615 /* === Include files ======================================================== */
616 /* ========================================================================== */
617 
618 #include "amesos_ccolamd.h"
619 
620 #include <stdlib.h>
621 #include <math.h>
622 #include <limits.h>
623 
624 #ifdef MATLAB_MEX_FILE
625 #include "mex.h"
626 #include "matrix.h"
627 #endif
628 
629 #if !defined (NPRINT) || !defined (NDEBUG)
630 #include <stdio.h>
631 #endif
632 
633 #ifndef NULL
634 #define NULL ((void *) 0)
635 #endif
636 
637 /* ========================================================================== */
638 /* === int or UF_long ======================================================= */
639 /* ========================================================================== */
640 
641 /* define UF_long */
642 #include "amesos_UFconfig.h"
643 
644 #ifdef DLONG
645 
646 #define Int UF_long
647 #define ID UF_long_id
648 #define Int_MAX UF_long_max
649 
650 #define CCOLAMD_recommended amesos_ccolamd_l_recommended
651 #define CCOLAMD_set_defaults amesos_ccolamd_l_set_defaults
652 #define CCOLAMD_2 amesos_ccolamd2_l
653 #define CCOLAMD_MAIN amesos_ccolamd_l
654 #define CCOLAMD_apply_order amesos_ccolamd_l_apply_order
655 #define CCOLAMD_postorder amesos_ccolamd_l_postorder
656 #define CCOLAMD_post_tree amesos_ccolamd_l_post_tree
657 #define CCOLAMD_fsize amesos_ccolamd_l_fsize
658 #define CSYMAMD_MAIN amesos_csymamd_l
659 #define CCOLAMD_report amesos_ccolamd_l_report
660 #define CSYMAMD_report amesos_csymamd_l_report
661 
662 #else
663 
664 #define Int int
665 #define ID "%d"
666 #define Int_MAX INT_MAX
667 
668 #define CCOLAMD_recommended amesos_ccolamd_recommended
669 #define CCOLAMD_set_defaults amesos_ccolamd_set_defaults
670 #define CCOLAMD_2 amesos_ccolamd2
671 #define CCOLAMD_MAIN amesos_ccolamd
672 #define CCOLAMD_apply_order amesos_ccolamd_apply_order
673 #define CCOLAMD_postorder amesos_ccolamd_postorder
674 #define CCOLAMD_post_tree amesos_ccolamd_post_tree
675 #define CCOLAMD_fsize amesos_ccolamd_fsize
676 #define CSYMAMD_MAIN amesos_csymamd
677 #define CCOLAMD_report amesos_ccolamd_report
678 #define CSYMAMD_report amesos_csymamd_report
679 
680 #endif
681 
682 /* ========================================================================== */
683 /* === Row and Column structures ============================================ */
684 /* ========================================================================== */
685 
686 typedef struct CColamd_Col_struct
687 {
688  /* size of this struct is 8 integers if no padding occurs */
689 
690  Int start ; /* index for A of first row in this column, or DEAD */
691  /* if column is dead */
692  Int length ; /* number of rows in this column */
693  union
694  {
695  Int thickness ; /* number of original columns represented by this */
696  /* col, if the column is alive */
697  Int parent ; /* parent in parent tree super-column structure, if */
698  /* the column is dead */
699  } shared1 ;
700  union
701  {
704  } shared2 ;
705  union
706  {
707  Int headhash ; /* head of a hash bucket, if col is at the head of */
708  /* a degree list */
709  Int hash ; /* hash value, if col is not in a degree list */
710  Int prev ; /* previous column in degree list, if col is in a */
711  /* degree list (but not at the head of a degree list) */
712  } shared3 ;
713  union
714  {
715  Int degree_next ; /* next column, if col is in a degree list */
716  Int hash_next ; /* next column, if col is in a hash list */
717  } shared4 ;
718 
719  Int nextcol ; /* next column in this supercolumn */
720  Int lastcol ; /* last column in this supercolumn */
721 
722 } CColamd_Col ;
723 
724 
725 typedef struct CColamd_Row_struct
726 {
727  /* size of this struct is 6 integers if no padding occurs */
728 
729  Int start ; /* index for A of first col in this row */
730  Int length ; /* number of principal columns in this row */
731  union
732  {
733  Int degree ; /* number of principal & non-principal columns in row */
734  Int p ; /* used as a row pointer in init_rows_cols () */
735  } shared1 ;
736  union
737  {
738  Int mark ; /* for computing set differences and marking dead rows*/
739  Int first_column ;/* first column in row (used in garbage collection) */
740  } shared2 ;
741 
742  Int thickness ; /* number of original rows represented by this row */
743  /* that are not yet pivotal */
744  Int front ; /* -1 if an original row */
745  /* k if this row represents the kth frontal matrix */
746  /* where k goes from 0 to at most n_col-1 */
747 
748 } CColamd_Row ;
749 
750 /* ========================================================================== */
751 /* === basic definitions ==================================================== */
752 /* ========================================================================== */
753 
754 #define EMPTY (-1)
755 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
756 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
757 
758 /* Routines are either PUBLIC (user-callable) or PRIVATE (not user-callable) */
759 #define GLOBAL
760 #define PUBLIC
761 #define PRIVATE static
762 
763 #define DENSE_DEGREE(alpha,n) \
764  ((Int) MAX (16.0, (alpha) * sqrt ((double) (n))))
765 
766 #define CMEMBER(c) ((cmember == (Int *) NULL) ? (0) : (cmember [c]))
767 
768 /* True if x is NaN */
769 #define SCALAR_IS_NAN(x) ((x) != (x))
770 
771 /* true if an integer (stored in double x) would overflow (or if x is NaN) */
772 #define INT_OVERFLOW(x) ((!((x) * (1.0+1e-8) <= (double) Int_MAX)) \
773  || SCALAR_IS_NAN (x))
774 
775 #define ONES_COMPLEMENT(r) (-(r)-1)
776 #undef TRUE
777 #undef FALSE
778 #define TRUE (1)
779 #define FALSE (0)
780 
781 /* Row and column status */
782 #define ALIVE (0)
783 #define DEAD (-1)
784 
785 /* Column status */
786 #define DEAD_PRINCIPAL (-1)
787 #define DEAD_NON_PRINCIPAL (-2)
788 
789 /* Macros for row and column status update and checking. */
790 #define ROW_IS_DEAD(r) ROW_IS_MARKED_DEAD (Row[r].shared2.mark)
791 #define ROW_IS_MARKED_DEAD(row_mark) (row_mark < ALIVE)
792 #define ROW_IS_ALIVE(r) (Row [r].shared2.mark >= ALIVE)
793 #define COL_IS_DEAD(c) (Col [c].start < ALIVE)
794 #define COL_IS_ALIVE(c) (Col [c].start >= ALIVE)
795 #define COL_IS_DEAD_PRINCIPAL(c) (Col [c].start == DEAD_PRINCIPAL)
796 #define KILL_ROW(r) { Row [r].shared2.mark = DEAD ; }
797 #define KILL_PRINCIPAL_COL(c) { Col [c].start = DEAD_PRINCIPAL ; }
798 #define KILL_NON_PRINCIPAL_COL(c) { Col [c].start = DEAD_NON_PRINCIPAL ; }
799 
800 
801 /* ========================================================================== */
802 /* === ccolamd reporting mechanism ========================================== */
803 /* ========================================================================== */
804 
805 #if defined (MATLAB_MEX_FILE) || defined (MATHWORKS)
806 /* In MATLAB, matrices are 1-based to the user, but 0-based internally */
807 #define INDEX(i) ((i)+1)
808 #else
809 /* In C, matrices are 0-based and indices are reported as such in *_report */
810 #define INDEX(i) (i)
811 #endif
812 
813 /* All output goes through the PRINTF macro. */
814 #define PRINTF(params) { if (amesos_ccolamd_printf != NULL) (void) amesos_ccolamd_printf params ; }
815 
816 
817 /* ========================================================================== */
818 /* === Debugging prototypes and definitions ================================= */
819 /* ========================================================================== */
820 
821 #ifndef NDEBUG
822 
823 #include <assert.h>
824 
825 /* debug print level, present only when debugging */
826 PRIVATE Int ccolamd_debug ;
827 
828 /* debug print statements */
829 #define DEBUG0(params) { PRINTF (params) ; }
830 #define DEBUG1(params) { if (ccolamd_debug >= 1) PRINTF (params) ; }
831 #define DEBUG2(params) { if (ccolamd_debug >= 2) PRINTF (params) ; }
832 #define DEBUG3(params) { if (ccolamd_debug >= 3) PRINTF (params) ; }
833 #define DEBUG4(params) { if (ccolamd_debug >= 4) PRINTF (params) ; }
834 
835 #ifdef MATLAB_MEX_FILE
836 #define ASSERT(expression) (mxAssert ((expression), ""))
837 #else
838 #define ASSERT(expression) (assert (expression))
839 #endif
840 
841 PRIVATE void ccolamd_get_debug
842 (
843  char *method
844 ) ;
845 
846 PRIVATE void debug_mark
847 (
848  Int n_row,
849  CColamd_Row Row [],
850  Int tag_mark,
851  Int max_mark
852 ) ;
853 
854 PRIVATE void debug_matrix
855 (
856  Int n_row,
857  Int n_col,
858  CColamd_Row Row [],
859  CColamd_Col Col [],
860  Int A []
861 ) ;
862 
863 PRIVATE void debug_structures
864 (
865  Int n_row,
866  Int n_col,
867  CColamd_Row Row [],
868  CColamd_Col Col [],
869  Int A [],
870  Int in_cset [],
871  Int cset_start []
872 ) ;
873 
874 PRIVATE void dump_super
875 (
876  Int super_c,
877  CColamd_Col Col [],
878  Int n_col
879 ) ;
880 
881 PRIVATE void debug_deg_lists
882 (
883  Int n_row,
884  Int n_col,
885  CColamd_Row Row [ ],
886  CColamd_Col Col [ ],
887  Int head [ ],
888  Int min_score,
889  Int should,
890  Int max_deg
891 ) ;
892 
893 #else
894 
895 /* === No debugging ========================================================= */
896 
897 #define DEBUG0(params) ;
898 #define DEBUG1(params) ;
899 #define DEBUG2(params) ;
900 #define DEBUG3(params) ;
901 #define DEBUG4(params) ;
902 
903 #define ASSERT(expression)
904 
905 #endif
906 
907 /* ========================================================================== */
908 /* === Prototypes of PRIVATE routines ======================================= */
909 /* ========================================================================== */
910 
912 (
913  Int n_row,
914  Int n_col,
915  CColamd_Row Row [ ],
916  CColamd_Col Col [ ],
917  Int A [ ],
918  Int p [ ],
919  Int stats [CCOLAMD_STATS]
920 ) ;
921 
923 (
924  Int n_row,
925  Int n_col,
926  CColamd_Row Row [ ],
927  CColamd_Col Col [ ],
928  Int A [ ],
929  Int head [ ],
930  double knobs [CCOLAMD_KNOBS],
931  Int *p_n_row2,
932  Int *p_n_col2,
933  Int *p_max_deg,
934  Int cmember [ ],
935  Int n_cset,
936  Int cset_start [ ],
937  Int dead_cols [ ],
938  Int *p_ndense_row, /* number of dense rows */
939  Int *p_nempty_row, /* number of original empty rows */
940  Int *p_nnewlyempty_row, /* number of newly empty rows */
941  Int *p_ndense_col, /* number of dense cols (excl "empty" cols) */
942  Int *p_nempty_col, /* number of original empty cols */
943  Int *p_nnewlyempty_col /* number of newly empty cols */
944 ) ;
945 
947 (
948  Int n_row,
949  Int n_col,
950  Int Alen,
951  CColamd_Row Row [ ],
952  CColamd_Col Col [ ],
953  Int A [ ],
954  Int head [ ],
955 #ifndef NDEBUG
956  Int n_col2,
957 #endif
958  Int max_deg,
959  Int pfree,
960  Int cset [ ],
961  Int cset_start [ ],
962 #ifndef NDEBUG
963  Int n_cset,
964 #endif
965  Int cmember [ ],
966  Int Front_npivcol [ ],
967  Int Front_nrows [ ],
968  Int Front_ncols [ ],
969  Int Front_parent [ ],
970  Int Front_cols [ ],
971  Int *p_nfr,
972  Int aggressive,
973  Int InFront [ ],
974  Int order_for_lu
975 ) ;
976 
978 (
979 #ifndef NDEBUG
980  Int n_col,
981  CColamd_Row Row [ ],
982 #endif
983  CColamd_Col Col [ ],
984  Int A [ ],
985  Int head [ ],
986  Int row_start,
987  Int row_length,
988  Int in_set [ ]
989 ) ;
990 
992 (
993  Int n_row,
994  Int n_col,
995  CColamd_Row Row [ ],
996  CColamd_Col Col [ ],
997  Int A [ ],
998  Int *pfree
999 ) ;
1000 
1002 (
1003  Int tag_mark,
1004  Int max_mark,
1005  Int n_row,
1006  CColamd_Row Row [ ]
1007 ) ;
1008 
1009 PRIVATE void print_report
1010 (
1011  char *method,
1012  Int stats [CCOLAMD_STATS]
1013 ) ;
1014 
1015 
1016 /* ========================================================================== */
1017 /* === USER-CALLABLE ROUTINES: ============================================== */
1018 /* ========================================================================== */
1019 
1020 
1021 /* ========================================================================== */
1022 /* === ccolamd_recommended ================================================== */
1023 /* ========================================================================== */
1024 
1025 /*
1026  * The ccolamd_recommended routine returns the suggested size for Alen. This
1027  * value has been determined to provide good balance between the number of
1028  * garbage collections and the memory requirements for ccolamd. If any
1029  * argument is negative, or if integer overflow occurs, a 0 is returned as
1030  * an error condition.
1031  *
1032  * 2*nnz space is required for the row and column indices of the matrix
1033  * (or 4*n_col, which ever is larger).
1034  *
1035  * CCOLAMD_C (n_col) + CCOLAMD_R (n_row) space is required for the Col and Row
1036  * arrays, respectively, which are internal to ccolamd. This is equal to
1037  * 8*n_col + 6*n_row if the structures are not padded.
1038  *
1039  * An additional n_col space is the minimal amount of "elbow room",
1040  * and nnz/5 more space is recommended for run time efficiency.
1041  *
1042  * The remaining (((3 * n_col) + 1) + 5 * (n_col + 1) + n_row) space is
1043  * for other workspace used in ccolamd which did not appear in colamd.
1044  */
1045 
1046 /* add two values of type size_t, and check for integer overflow */
1047 static size_t t_add (size_t a, size_t b, int *ok)
1048 {
1049  (*ok) = (*ok) && ((a + b) >= MAX (a,b)) ;
1050  return ((*ok) ? (a + b) : 0) ;
1051 }
1052 
1053 /* compute a*k where k is a small integer, and check for integer overflow */
1054 static size_t t_mult (size_t a, size_t k, int *ok)
1055 {
1056  size_t i, s = 0 ;
1057  for (i = 0 ; i < k ; i++)
1058  {
1059  s = t_add (s, a, ok) ;
1060  }
1061  return (s) ;
1062 }
1063 
1064 /* size of the Col and Row structures */
1065 #define CCOLAMD_C(n_col,ok) \
1066  ((t_mult (t_add (n_col, 1, ok), sizeof (CColamd_Col), ok) / sizeof (Int)))
1067 
1068 #define CCOLAMD_R(n_row,ok) \
1069  ((t_mult (t_add (n_row, 1, ok), sizeof (CColamd_Row), ok) / sizeof (Int)))
1070 
1071 /*
1072 #define CCOLAMD_RECOMMENDED(nnz, n_row, n_col) \
1073  MAX (2 * nnz, 4 * n_col) + \
1074  CCOLAMD_C (n_col) + CCOLAMD_R (n_row) + n_col + (nnz / 5) \
1075  + ((3 * n_col) + 1) + 5 * (n_col + 1) + n_row
1076  */
1077 
1078 static size_t ccolamd_need (Int nnz, Int n_row, Int n_col, int *ok)
1079 {
1080 
1081  /* ccolamd_need, compute the following, and check for integer overflow:
1082  need = MAX (2*nnz, 4*n_col) + n_col +
1083  Col_size + Row_size +
1084  (3*n_col+1) + (5*(n_col+1)) + n_row ;
1085  */
1086  size_t s, c, r, t ;
1087 
1088  /* MAX (2*nnz, 4*n_col) */
1089  s = t_mult (nnz, 2, ok) ; /* 2*nnz */
1090  t = t_mult (n_col, 4, ok) ; /* 4*n_col */
1091  s = MAX (s,t) ;
1092 
1093  s = t_add (s, n_col, ok) ; /* bare minimum elbow room */
1094 
1095  /* Col and Row arrays */
1096  c = CCOLAMD_C (n_col, ok) ; /* size of column structures */
1097  r = CCOLAMD_R (n_row, ok) ; /* size of row structures */
1098  s = t_add (s, c, ok) ;
1099  s = t_add (s, r, ok) ;
1100 
1101  c = t_mult (n_col, 3, ok) ; /* 3*n_col + 1 */
1102  c = t_add (c, 1, ok) ;
1103  s = t_add (s, c, ok) ;
1104 
1105  c = t_add (n_col, 1, ok) ; /* 5 * (n_col + 1) */
1106  c = t_mult (c, 5, ok) ;
1107  s = t_add (s, c, ok) ;
1108 
1109  s = t_add (s, n_row, ok) ; /* n_row */
1110 
1111  return (ok ? s : 0) ;
1112 }
1113 
1114 PUBLIC size_t CCOLAMD_recommended /* returns recommended value of Alen. */
1116  /* === Parameters ======================================================= */
1117 
1118  Int nnz, /* number of nonzeros in A */
1119  Int n_row, /* number of rows in A */
1120  Int n_col /* number of columns in A */
1121 )
1122 {
1123  size_t s ;
1124  int ok = TRUE ;
1125  if (nnz < 0 || n_row < 0 || n_col < 0)
1126  {
1127  return (0) ;
1128  }
1129  s = ccolamd_need (nnz, n_row, n_col, &ok) ; /* bare minimum needed */
1130  s = t_add (s, nnz/5, &ok) ; /* extra elbow room */
1131  ok = ok && (s < Int_MAX) ;
1132  return (ok ? s : 0) ;
1133 }
1134 
1135 
1136 /* ========================================================================== */
1137 /* === ccolamd_set_defaults ================================================= */
1138 /* ========================================================================== */
1139 
1140 /*
1141  * The ccolamd_set_defaults routine sets the default values of the user-
1142  * controllable parameters for ccolamd.
1143  */
1144 
1147  /* === Parameters ======================================================= */
1148 
1149  double knobs [CCOLAMD_KNOBS] /* knob array */
1150 )
1151 {
1152  /* === Local variables ================================================== */
1153 
1154  Int i ;
1155 
1156  if (!knobs)
1157  {
1158  return ; /* no knobs to initialize */
1159  }
1160  for (i = 0 ; i < CCOLAMD_KNOBS ; i++)
1161  {
1162  knobs [i] = 0 ;
1163  }
1164  knobs [CCOLAMD_DENSE_ROW] = 10 ;
1165  knobs [CCOLAMD_DENSE_COL] = 10 ;
1166  knobs [CCOLAMD_AGGRESSIVE] = TRUE ; /* default: do aggressive absorption*/
1167  knobs [CCOLAMD_LU] = FALSE ; /* default: order for Cholesky */
1168 }
1169 
1170 
1171 /* ========================================================================== */
1172 /* === symamd =============================================================== */
1173 /* ========================================================================== */
1174 
1175 PUBLIC Int CSYMAMD_MAIN /* return TRUE if OK, FALSE otherwise */
1177  /* === Parameters ======================================================= */
1178 
1179  Int n, /* number of rows and columns of A */
1180  Int A [ ], /* row indices of A */
1181  Int p [ ], /* column pointers of A */
1182  Int perm [ ], /* output permutation, size n+1 */
1183  double knobs [CCOLAMD_KNOBS], /* parameters (uses defaults if NULL) */
1184  Int stats [CCOLAMD_STATS], /* output statistics and error codes */
1185  void * (*allocate) (size_t, size_t),/* pointer to calloc (ANSI C) or */
1186  /* mxCalloc (for MATLAB mexFunction) */
1187  void (*release) (void *), /* pointer to free (ANSI C) or */
1188  /* mxFree (for MATLAB mexFunction) */
1189  Int cmember [ ], /* constraint set */
1190  Int stype /* stype of A */
1191 )
1192 {
1193  /* === Local variables ================================================== */
1194 
1195  double cknobs [CCOLAMD_KNOBS] ;
1196  double default_knobs [CCOLAMD_KNOBS] ;
1197 
1198  Int *count ; /* length of each column of M, and col pointer*/
1199  Int *mark ; /* mark array for finding duplicate entries */
1200  Int *M ; /* row indices of matrix M */
1201  size_t Mlen ; /* length of M */
1202  Int n_row ; /* number of rows in M */
1203  Int nnz ; /* number of entries in A */
1204  Int i ; /* row index of A */
1205  Int j ; /* column index of A */
1206  Int k ; /* row index of M */
1207  Int mnz ; /* number of nonzeros in M */
1208  Int pp ; /* index into a column of A */
1209  Int last_row ; /* last row seen in the current column */
1210  Int length ; /* number of nonzeros in a column */
1211  Int both ; /* TRUE if ordering A+A' */
1212  Int upper ; /* TRUE if ordering triu(A)+triu(A)' */
1213  Int lower ; /* TRUE if ordering tril(A)+tril(A)' */
1214 
1215 #ifndef NDEBUG
1216  ccolamd_get_debug ("csymamd") ;
1217 #endif
1218 
1219  both = (stype == 0) ;
1220  upper = (stype > 0) ;
1221  lower = (stype < 0) ;
1222 
1223  /* === Check the input arguments ======================================== */
1224 
1225  if (!stats)
1226  {
1227  DEBUG1 (("csymamd: stats not present\n")) ;
1228  return (FALSE) ;
1229  }
1230  for (i = 0 ; i < CCOLAMD_STATS ; i++)
1231  {
1232  stats [i] = 0 ;
1233  }
1234  stats [CCOLAMD_STATUS] = CCOLAMD_OK ;
1235  stats [CCOLAMD_INFO1] = -1 ;
1236  stats [CCOLAMD_INFO2] = -1 ;
1237 
1238  if (!A)
1239  {
1241  DEBUG1 (("csymamd: A not present\n")) ;
1242  return (FALSE) ;
1243  }
1244 
1245  if (!p) /* p is not present */
1246  {
1248  DEBUG1 (("csymamd: p not present\n")) ;
1249  return (FALSE) ;
1250  }
1251 
1252  if (n < 0) /* n must be >= 0 */
1253  {
1255  stats [CCOLAMD_INFO1] = n ;
1256  DEBUG1 (("csymamd: n negative "ID" \n", n)) ;
1257  return (FALSE) ;
1258  }
1259 
1260  nnz = p [n] ;
1261  if (nnz < 0) /* nnz must be >= 0 */
1262  {
1264  stats [CCOLAMD_INFO1] = nnz ;
1265  DEBUG1 (("csymamd: number of entries negative "ID" \n", nnz)) ;
1266  return (FALSE) ;
1267  }
1268 
1269  if (p [0] != 0)
1270  {
1272  stats [CCOLAMD_INFO1] = p [0] ;
1273  DEBUG1 (("csymamd: p[0] not zero "ID"\n", p [0])) ;
1274  return (FALSE) ;
1275  }
1276 
1277  /* === If no knobs, set default knobs =================================== */
1278 
1279  if (!knobs)
1280  {
1281  CCOLAMD_set_defaults (default_knobs) ;
1282  knobs = default_knobs ;
1283  }
1284 
1285  /* === Allocate count and mark ========================================== */
1286 
1287  count = (Int *) ((*allocate) (n+1, sizeof (Int))) ;
1288  if (!count)
1289  {
1291  DEBUG1 (("csymamd: allocate count (size "ID") failed\n", n+1)) ;
1292  return (FALSE) ;
1293  }
1294 
1295  mark = (Int *) ((*allocate) (n+1, sizeof (Int))) ;
1296  if (!mark)
1297  {
1299  (*release) ((void *) count) ;
1300  DEBUG1 (("csymamd: allocate mark (size "ID") failed\n", n+1)) ;
1301  return (FALSE) ;
1302  }
1303 
1304  /* === Compute column counts of M, check if A is valid ================== */
1305 
1306  stats [CCOLAMD_INFO3] = 0 ; /* number of duplicate or unsorted row indices*/
1307 
1308  for (i = 0 ; i < n ; i++)
1309  {
1310  mark [i] = -1 ;
1311  }
1312  for (j = 0 ; j < n ; j++)
1313  {
1314  last_row = -1 ;
1315 
1316  length = p [j+1] - p [j] ;
1317  if (length < 0)
1318  {
1319  /* column pointers must be non-decreasing */
1321  stats [CCOLAMD_INFO1] = j ;
1322  stats [CCOLAMD_INFO2] = length ;
1323  (*release) ((void *) count) ;
1324  (*release) ((void *) mark) ;
1325  DEBUG1 (("csymamd: col "ID" negative length "ID"\n", j, length)) ;
1326  return (FALSE) ;
1327  }
1328 
1329  for (pp = p [j] ; pp < p [j+1] ; pp++)
1330  {
1331  i = A [pp] ;
1332  if (i < 0 || i >= n)
1333  {
1334  /* row index i, in column j, is out of bounds */
1336  stats [CCOLAMD_INFO1] = j ;
1337  stats [CCOLAMD_INFO2] = i ;
1338  stats [CCOLAMD_INFO3] = n ;
1339  (*release) ((void *) count) ;
1340  (*release) ((void *) mark) ;
1341  DEBUG1 (("csymamd: row "ID" col "ID" out of bounds\n", i, j)) ;
1342  return (FALSE) ;
1343  }
1344 
1345  if (i <= last_row || mark [i] == j)
1346  {
1347  /* row index is unsorted or repeated (or both), thus col */
1348  /* is jumbled. This is a notice, not an error condition. */
1350  stats [CCOLAMD_INFO1] = j ;
1351  stats [CCOLAMD_INFO2] = i ;
1352  (stats [CCOLAMD_INFO3]) ++ ;
1353  DEBUG1 (("csymamd: row "ID" col "ID" unsorted/dupl.\n", i, j)) ;
1354  }
1355 
1356  if (mark [i] != j)
1357  {
1358  if ((both && i != j) || (lower && i > j) || (upper && i < j))
1359  {
1360  /* row k of M will contain column indices i and j */
1361  count [i]++ ;
1362  count [j]++ ;
1363  }
1364  }
1365 
1366  /* mark the row as having been seen in this column */
1367  mark [i] = j ;
1368 
1369  last_row = i ;
1370  }
1371  }
1372 
1373  /* === Compute column pointers of M ===================================== */
1374 
1375  /* use output permutation, perm, for column pointers of M */
1376  perm [0] = 0 ;
1377  for (j = 1 ; j <= n ; j++)
1378  {
1379  perm [j] = perm [j-1] + count [j-1] ;
1380  }
1381  for (j = 0 ; j < n ; j++)
1382  {
1383  count [j] = perm [j] ;
1384  }
1385 
1386  /* === Construct M ====================================================== */
1387 
1388  mnz = perm [n] ;
1389  n_row = mnz / 2 ;
1390  Mlen = CCOLAMD_recommended (mnz, n_row, n) ;
1391  M = (Int *) ((*allocate) (Mlen, sizeof (Int))) ;
1392  DEBUG1 (("csymamd: M is "ID"-by-"ID" with "ID" entries, Mlen = %g\n",
1393  n_row, n, mnz, (double) Mlen)) ;
1394 
1395  if (!M)
1396  {
1398  (*release) ((void *) count) ;
1399  (*release) ((void *) mark) ;
1400  DEBUG1 (("csymamd: allocate M (size %g) failed\n", (double) Mlen)) ;
1401  return (FALSE) ;
1402  }
1403 
1404  k = 0 ;
1405 
1406  if (stats [CCOLAMD_STATUS] == CCOLAMD_OK)
1407  {
1408  /* Matrix is OK */
1409  for (j = 0 ; j < n ; j++)
1410  {
1411  ASSERT (p [j+1] - p [j] >= 0) ;
1412  for (pp = p [j] ; pp < p [j+1] ; pp++)
1413  {
1414  i = A [pp] ;
1415  ASSERT (i >= 0 && i < n) ;
1416  if ((both && i != j) || (lower && i > j) || (upper && i < j))
1417  {
1418  /* row k of M contains column indices i and j */
1419  M [count [i]++] = k ;
1420  M [count [j]++] = k ;
1421  k++ ;
1422  }
1423  }
1424  }
1425  }
1426  else
1427  {
1428  /* Matrix is jumbled. Do not add duplicates to M. Unsorted cols OK. */
1429  DEBUG1 (("csymamd: Duplicates in A.\n")) ;
1430  for (i = 0 ; i < n ; i++)
1431  {
1432  mark [i] = -1 ;
1433  }
1434  for (j = 0 ; j < n ; j++)
1435  {
1436  ASSERT (p [j+1] - p [j] >= 0) ;
1437  for (pp = p [j] ; pp < p [j+1] ; pp++)
1438  {
1439  i = A [pp] ;
1440  ASSERT (i >= 0 && i < n) ;
1441  if (mark [i] != j)
1442  {
1443  if ((both && i != j) || (lower && i > j) || (upper && i<j))
1444  {
1445  /* row k of M contains column indices i and j */
1446  M [count [i]++] = k ;
1447  M [count [j]++] = k ;
1448  k++ ;
1449  mark [i] = j ;
1450  }
1451  }
1452  }
1453  }
1454  }
1455 
1456  /* count and mark no longer needed */
1457  (*release) ((void *) mark) ;
1458  (*release) ((void *) count) ;
1459  ASSERT (k == n_row) ;
1460 
1461  /* === Adjust the knobs for M =========================================== */
1462 
1463  for (i = 0 ; i < CCOLAMD_KNOBS ; i++)
1464  {
1465  cknobs [i] = knobs [i] ;
1466  }
1467 
1468  /* there are no dense rows in M */
1469  cknobs [CCOLAMD_DENSE_ROW] = -1 ;
1470  cknobs [CCOLAMD_DENSE_COL] = knobs [CCOLAMD_DENSE_ROW] ;
1471 
1472  /* ensure CCSYMAMD orders for Cholesky, not LU */
1473  cknobs [CCOLAMD_LU] = FALSE ;
1474 
1475  /* === Order the columns of M =========================================== */
1476 
1477  (void) CCOLAMD_2 (n_row, n, (Int) Mlen, M, perm, cknobs, stats,
1478  (Int *) NULL, (Int *) NULL, (Int *) NULL, (Int *) NULL,
1479  (Int *) NULL, (Int *) NULL, (Int *) NULL, cmember) ;
1480 
1481  /* === adjust statistics ================================================ */
1482 
1483  /* a dense column in ccolamd means a dense row and col in csymamd */
1484  stats [CCOLAMD_DENSE_ROW] = stats [CCOLAMD_DENSE_COL] ;
1485 
1486  /* === Free M =========================================================== */
1487 
1488  (*release) ((void *) M) ;
1489  DEBUG1 (("csymamd: done.\n")) ;
1490  return (TRUE) ;
1491 }
1492 
1493 
1494 /* ========================================================================== */
1495 /* === ccolamd ============================================================== */
1496 /* ========================================================================== */
1497 
1498 /*
1499  * The colamd routine computes a column ordering Q of a sparse matrix
1500  * A such that the LU factorization P(AQ) = LU remains sparse, where P is
1501  * selected via partial pivoting. The routine can also be viewed as
1502  * providing a permutation Q such that the Cholesky factorization
1503  * (AQ)'(AQ) = LL' remains sparse.
1504  */
1505 
1508  /* === Parameters ======================================================= */
1509 
1510  Int n_row, /* number of rows in A */
1511  Int n_col, /* number of columns in A */
1512  Int Alen, /* length of A */
1513  Int A [ ], /* row indices of A */
1514  Int p [ ], /* pointers to columns in A */
1515  double knobs [CCOLAMD_KNOBS],/* parameters (uses defaults if NULL) */
1516  Int stats [CCOLAMD_STATS], /* output statistics and error codes */
1517  Int cmember [ ] /* constraint set of A */
1518 )
1519 {
1520  return (CCOLAMD_2 (n_row, n_col, Alen, A, p, knobs, stats,
1521  (Int *) NULL, (Int *) NULL, (Int *) NULL, (Int *) NULL,
1522  (Int *) NULL, (Int *) NULL, (Int *) NULL, cmember)) ;
1523 }
1524 
1525 
1526 /* ========================================================================== */
1527 /* === ccolamd2 ============================================================= */
1528 /* ========================================================================== */
1529 
1530 /* Identical to ccolamd, except that additional information about each frontal
1531  * matrix is returned to the caller. Not intended to be directly called by
1532  * the user.
1533  */
1534 
1535 PUBLIC Int CCOLAMD_2 /* returns TRUE if successful, FALSE otherwise */
1537  /* === Parameters ======================================================= */
1538 
1539  Int n_row, /* number of rows in A */
1540  Int n_col, /* number of columns in A */
1541  Int Alen, /* length of A */
1542  Int A [ ], /* row indices of A */
1543  Int p [ ], /* pointers to columns in A */
1544  double knobs [CCOLAMD_KNOBS],/* parameters (uses defaults if NULL) */
1545  Int stats [CCOLAMD_STATS], /* output statistics and error codes */
1546 
1547  /* each Front array is of size n_col+1. */
1548  Int Front_npivcol [ ], /* # pivot cols in each front */
1549  Int Front_nrows [ ], /* # of rows in each front (incl. pivot rows) */
1550  Int Front_ncols [ ], /* # of cols in each front (incl. pivot cols) */
1551  Int Front_parent [ ], /* parent of each front */
1552  Int Front_cols [ ], /* link list of pivot columns for each front */
1553  Int *p_nfr, /* total number of frontal matrices */
1554  Int InFront [ ], /* InFront [row] = f if the original row was
1555  * absorbed into front f. EMPTY if the row was
1556  * empty, dense, or not absorbed. This array
1557  * has size n_row+1 */
1558  Int cmember [ ] /* constraint set of A */
1559 )
1560 {
1561  /* === Local variables ================================================== */
1562 
1563  Int i ; /* loop index */
1564  Int nnz ; /* nonzeros in A */
1565  size_t Row_size ; /* size of Row [ ], in integers */
1566  size_t Col_size ; /* size of Col [ ], in integers */
1567  size_t need ; /* minimum required length of A */
1568  CColamd_Row *Row ; /* pointer into A of Row [0..n_row] array */
1569  CColamd_Col *Col ; /* pointer into A of Col [0..n_col] array */
1570  Int n_col2 ; /* number of non-dense, non-empty columns */
1571  Int n_row2 ; /* number of non-dense, non-empty rows */
1572  Int ngarbage ; /* number of garbage collections performed */
1573  Int max_deg ; /* maximum row degree */
1574  double default_knobs [CCOLAMD_KNOBS] ; /* default knobs array */
1575 
1576  Int n_cset ; /* number of constraint sets */
1577  Int *cset ; /* cset of A */
1578  Int *cset_start ; /* pointer into cset */
1579  Int *temp_cstart ; /* temp pointer to start of cset */
1580  Int *csize ; /* temp pointer to cset size */
1581  Int ap ; /* column index */
1582  Int order_for_lu ; /* TRUE: order for LU, FALSE: for Cholesky */
1583 
1584  Int ndense_row, nempty_row, parent, ndense_col,
1585  nempty_col, k, col, nfr, *Front_child, *Front_sibling, *Front_stack,
1586  *Front_order, *Front_size ;
1587  Int nnewlyempty_col, nnewlyempty_row ;
1588  Int aggressive ;
1589  Int row ;
1590  Int *dead_cols ;
1591  Int set1 ;
1592  Int set2 ;
1593  Int cs ;
1594 
1595  int ok ;
1596 
1597 #ifndef NDEBUG
1598  ccolamd_get_debug ("ccolamd") ;
1599 #endif
1600 
1601  /* === Check the input arguments ======================================== */
1602 
1603  if (!stats)
1604  {
1605  DEBUG1 (("ccolamd: stats not present\n")) ;
1606  return (FALSE) ;
1607  }
1608  for (i = 0 ; i < CCOLAMD_STATS ; i++)
1609  {
1610  stats [i] = 0 ;
1611  }
1612  stats [CCOLAMD_STATUS] = CCOLAMD_OK ;
1613  stats [CCOLAMD_INFO1] = -1 ;
1614  stats [CCOLAMD_INFO2] = -1 ;
1615 
1616  if (!A) /* A is not present */
1617  {
1619  DEBUG1 (("ccolamd: A not present\n")) ;
1620  return (FALSE) ;
1621  }
1622 
1623  if (!p) /* p is not present */
1624  {
1626  DEBUG1 (("ccolamd: p not present\n")) ;
1627  return (FALSE) ;
1628  }
1629 
1630  if (n_row < 0) /* n_row must be >= 0 */
1631  {
1633  stats [CCOLAMD_INFO1] = n_row ;
1634  DEBUG1 (("ccolamd: nrow negative "ID"\n", n_row)) ;
1635  return (FALSE) ;
1636  }
1637 
1638  if (n_col < 0) /* n_col must be >= 0 */
1639  {
1641  stats [CCOLAMD_INFO1] = n_col ;
1642  DEBUG1 (("ccolamd: ncol negative "ID"\n", n_col)) ;
1643  return (FALSE) ;
1644  }
1645 
1646  nnz = p [n_col] ;
1647  if (nnz < 0) /* nnz must be >= 0 */
1648  {
1650  stats [CCOLAMD_INFO1] = nnz ;
1651  DEBUG1 (("ccolamd: number of entries negative "ID"\n", nnz)) ;
1652  return (FALSE) ;
1653  }
1654 
1655  if (p [0] != 0)
1656  {
1658  stats [CCOLAMD_INFO1] = p [0] ;
1659  DEBUG1 (("ccolamd: p[0] not zero "ID"\n", p [0])) ;
1660  return (FALSE) ;
1661  }
1662 
1663  /* === If no knobs, set default knobs =================================== */
1664 
1665  if (!knobs)
1666  {
1667  CCOLAMD_set_defaults (default_knobs) ;
1668  knobs = default_knobs ;
1669  }
1670 
1671  aggressive = (knobs [CCOLAMD_AGGRESSIVE] != FALSE) ;
1672  order_for_lu = (knobs [CCOLAMD_LU] != FALSE) ;
1673 
1674  /* === Allocate workspace from array A ================================== */
1675 
1676  ok = TRUE ;
1677  Col_size = CCOLAMD_C (n_col, &ok) ;
1678  Row_size = CCOLAMD_R (n_row, &ok) ;
1679 
1680  /* min size of A is 2nnz+ncol. cset and cset_start are of size 2ncol+1 */
1681  /* Each of the 5 fronts is of size n_col + 1. InFront is of size nrow. */
1682 
1683  /*
1684  need = MAX (2*nnz, 4*n_col) + n_col +
1685  Col_size + Row_size +
1686  (3*n_col+1) + (5*(n_col+1)) + n_row ;
1687  */
1688  need = ccolamd_need (nnz, n_row, n_col, &ok) ;
1689 
1690  if (!ok || need > (size_t) Alen || need > Int_MAX)
1691  {
1692  /* not enough space in array A to perform the ordering */
1694  stats [CCOLAMD_INFO1] = need ;
1695  stats [CCOLAMD_INFO2] = Alen ;
1696  DEBUG1 (("ccolamd: Need Alen >= "ID", given "ID"\n", need, Alen)) ;
1697  return (FALSE) ;
1698  }
1699 
1700  /* since integer overflow has been check, the following cannot overflow: */
1701  Alen -= Col_size + Row_size + (3*n_col + 1) + 5*(n_col+1) + n_row ;
1702 
1703  /* Size of A is now Alen >= MAX (2*nnz, 4*n_col) + n_col. The ordering
1704  * requires Alen >= 2*nnz + n_col, and the postorder requires
1705  * Alen >= 5*n_col. */
1706 
1707  ap = Alen ;
1708 
1709  /* Front array workspace: 5*(n_col+1) + n_row */
1710  if (!Front_npivcol || !Front_nrows || !Front_ncols || !Front_parent ||
1711  !Front_cols || !Front_cols || !InFront)
1712  {
1713  Front_npivcol = &A [ap] ; ap += (n_col + 1) ;
1714  Front_nrows = &A [ap] ; ap += (n_col + 1) ;
1715  Front_ncols = &A [ap] ; ap += (n_col + 1) ;
1716  Front_parent = &A [ap] ; ap += (n_col + 1) ;
1717  Front_cols = &A [ap] ; ap += (n_col + 1) ;
1718  InFront = &A [ap] ; ap += (n_row) ;
1719  }
1720  else
1721  {
1722  /* Fronts are present. Leave the additional space as elbow room. */
1723  ap += 5*(n_col+1) + n_row ;
1724  ap = Alen ;
1725  }
1726 
1727  /* Workspace for cset management: 3*n_col+1 */
1728  /* cset_start is of size n_col + 1 */
1729  cset_start = &A [ap] ;
1730  ap += n_col + 1 ;
1731 
1732  /* dead_col is of size n_col */
1733  dead_cols = &A [ap] ;
1734  ap += n_col ;
1735 
1736  /* cset is of size n_col */
1737  cset = &A [ap] ;
1738  ap += n_col ;
1739 
1740  /* Col is of size Col_size. The space is shared by temp_cstart and csize */
1741  Col = (CColamd_Col *) &A [ap] ;
1742  temp_cstart = (Int *) Col ; /* [ temp_cstart is of size n_col+1 */
1743  csize = temp_cstart + (n_col+1) ; /* csize is of size n_col+1 */
1744  ap += Col_size ;
1745  ASSERT (Col_size >= 2*n_col+1) ;
1746 
1747  /* Row is of size Row_size */
1748  Row = (CColamd_Row *) &A [ap] ;
1749  ap += Row_size ;
1750 
1751  /* Initialize csize & dead_cols to zero */
1752  for (i = 0 ; i < n_col ; i++)
1753  {
1754  csize [i] = 0 ;
1755  dead_cols [i] = 0 ;
1756  }
1757 
1758  /* === Construct the constraint set ===================================== */
1759 
1760  if (n_col == 0)
1761  {
1762  n_cset = 0 ;
1763  }
1764  else if (cmember == (Int *) NULL)
1765  {
1766  /* no constraint set; all columns belong to set zero */
1767  n_cset = 1 ;
1768  csize [0] = n_col ;
1769  DEBUG1 (("no cmember present\n")) ;
1770  }
1771  else
1772  {
1773  n_cset = 0 ;
1774  for (i = 0 ; i < n_col ; i++)
1775  {
1776  if (cmember [i] < 0 || cmember [i] > n_col)
1777  {
1779  DEBUG1 (("ccolamd: malformed cmember \n")) ;
1780  return (FALSE) ;
1781  }
1782  n_cset = MAX (n_cset, cmember [i]) ;
1783  csize [cmember [i]]++ ;
1784  }
1785  /* cset is zero based */
1786  n_cset++ ;
1787  }
1788 
1789  ASSERT ((n_cset >= 0) && (n_cset <= n_col)) ;
1790 
1791  cset_start [0] = temp_cstart [0] = 0 ;
1792  for (i = 1 ; i <= n_cset ; i++)
1793  {
1794  cset_start [i] = cset_start [i-1] + csize [i-1] ;
1795  DEBUG4 ((" cset_start ["ID"] = "ID" \n", i , cset_start [i])) ;
1796  temp_cstart [i] = cset_start [i] ;
1797  }
1798 
1799  /* do in reverse order to encourage natural tie-breaking */
1800  if (cmember == (Int *) NULL)
1801  {
1802  for (i = n_col-1 ; i >= 0 ; i--)
1803  {
1804  cset [temp_cstart [0]++] = i ;
1805  }
1806  }
1807  else
1808  {
1809  for (i = n_col-1 ; i >= 0 ; i--)
1810  {
1811  cset [temp_cstart [cmember [i]]++] = i ;
1812  }
1813  }
1814 
1815  /* ] temp_cstart and csize are no longer used */
1816 
1817  /* === Construct the row and column data structures ===================== */
1818 
1819  if (!init_rows_cols (n_row, n_col, Row, Col, A, p, stats))
1820  {
1821  /* input matrix is invalid */
1822  DEBUG1 (("ccolamd: Matrix invalid\n")) ;
1823  return (FALSE) ;
1824  }
1825 
1826  /* === Initialize front info ============================================ */
1827 
1828  for (col = 0 ; col < n_col ; col++)
1829  {
1830  Front_npivcol [col] = 0 ;
1831  Front_nrows [col] = 0 ;
1832  Front_ncols [col] = 0 ;
1833  Front_parent [col] = EMPTY ;
1834  Front_cols [col] = EMPTY ;
1835  }
1836 
1837  /* === Initialize scores, kill dense rows/columns ======================= */
1838 
1839  init_scoring (n_row, n_col, Row, Col, A, p, knobs,
1840  &n_row2, &n_col2, &max_deg, cmember, n_cset, cset_start, dead_cols,
1841  &ndense_row, &nempty_row, &nnewlyempty_row,
1842  &ndense_col, &nempty_col, &nnewlyempty_col) ;
1843 
1844  ASSERT (n_row2 == n_row - nempty_row - nnewlyempty_row - ndense_row) ;
1845  ASSERT (n_col2 == n_col - nempty_col - nnewlyempty_col - ndense_col) ;
1846  DEBUG1 (("# dense rows "ID" cols "ID"\n", ndense_row, ndense_col)) ;
1847 
1848  /* === Order the supercolumns =========================================== */
1849 
1850  ngarbage = find_ordering (n_row, n_col, Alen, Row, Col, A, p,
1851 #ifndef NDEBUG
1852  n_col2,
1853 #endif
1854  max_deg, 2*nnz, cset, cset_start,
1855 #ifndef NDEBUG
1856  n_cset,
1857 #endif
1858  cmember, Front_npivcol, Front_nrows, Front_ncols, Front_parent,
1859  Front_cols, &nfr, aggressive, InFront, order_for_lu) ;
1860 
1861  ASSERT (Alen >= 5*n_col) ;
1862 
1863  /* === Postorder ======================================================== */
1864 
1865  /* A is no longer needed, so use A [0..5*nfr-1] as workspace [ [ */
1866  /* This step requires Alen >= 5*n_col */
1867  Front_child = A ;
1868  Front_sibling = Front_child + nfr ;
1869  Front_stack = Front_sibling + nfr ;
1870  Front_order = Front_stack + nfr ;
1871  Front_size = Front_order + nfr ;
1872 
1873  CCOLAMD_fsize (nfr, Front_size, Front_nrows, Front_ncols,
1874  Front_parent, Front_npivcol) ;
1875 
1876  CCOLAMD_postorder (nfr, Front_parent, Front_npivcol, Front_size,
1877  Front_order, Front_child, Front_sibling, Front_stack, Front_cols,
1878  cmember) ;
1879 
1880  /* Front_size, Front_stack, Front_child, Front_sibling no longer needed ] */
1881 
1882  /* use A [0..nfr-1] as workspace */
1883  CCOLAMD_apply_order (Front_npivcol, Front_order, A, nfr, nfr) ;
1884  CCOLAMD_apply_order (Front_nrows, Front_order, A, nfr, nfr) ;
1885  CCOLAMD_apply_order (Front_ncols, Front_order, A, nfr, nfr) ;
1886  CCOLAMD_apply_order (Front_parent, Front_order, A, nfr, nfr) ;
1887  CCOLAMD_apply_order (Front_cols, Front_order, A, nfr, nfr) ;
1888 
1889  /* fix the parent to refer to the new numbering */
1890  for (i = 0 ; i < nfr ; i++)
1891  {
1892  parent = Front_parent [i] ;
1893  if (parent != EMPTY)
1894  {
1895  Front_parent [i] = Front_order [parent] ;
1896  }
1897  }
1898 
1899  /* fix InFront to refer to the new numbering */
1900  for (row = 0 ; row < n_row ; row++)
1901  {
1902  i = InFront [row] ;
1903  ASSERT (i >= EMPTY && i < nfr) ;
1904  if (i != EMPTY)
1905  {
1906  InFront [row] = Front_order [i] ;
1907  }
1908  }
1909 
1910  /* Front_order longer needed ] */
1911 
1912  /* === Order the columns in the fronts ================================== */
1913 
1914  /* use A [0..n_col-1] as inverse permutation */
1915  for (i = 0 ; i < n_col ; i++)
1916  {
1917  A [i] = EMPTY ;
1918  }
1919 
1920  k = 0 ;
1921  set1 = 0 ;
1922  for (i = 0 ; i < nfr ; i++)
1923  {
1924  ASSERT (Front_npivcol [i] > 0) ;
1925 
1926  set2 = CMEMBER (Front_cols [i]) ;
1927  while (set1 < set2)
1928  {
1929  k += dead_cols [set1] ;
1930  DEBUG3 (("Skip null/dense columns of set "ID"\n",set1)) ;
1931  set1++ ;
1932  }
1933  set1 = set2 ;
1934 
1935  for (col = Front_cols [i] ; col != EMPTY ; col = Col [col].nextcol)
1936  {
1937  ASSERT (col >= 0 && col < n_col) ;
1938  DEBUG1 (("ccolamd output ordering: k "ID" col "ID"\n", k, col)) ;
1939  p [k] = col ;
1940  ASSERT (A [col] == EMPTY) ;
1941 
1942  cs = CMEMBER (col) ;
1943  ASSERT (k >= cset_start [cs] && k < cset_start [cs+1]) ;
1944 
1945  A [col] = k ;
1946  k++ ;
1947  }
1948  }
1949 
1950  /* === Order the "dense" and null columns =============================== */
1951 
1952  if (n_col2 < n_col)
1953  {
1954  for (col = 0 ; col < n_col ; col++)
1955  {
1956  if (A [col] == EMPTY)
1957  {
1958  k = Col [col].shared2.order ;
1959  cs = CMEMBER (col) ;
1960 #ifndef NDEBUG
1961  dead_cols [cs]-- ;
1962 #endif
1963  ASSERT (k >= cset_start [cs] && k < cset_start [cs+1]) ;
1964  DEBUG1 (("ccolamd output ordering: k "ID" col "ID
1965  " (dense or null col)\n", k, col)) ;
1966  p [k] = col ;
1967  A [col] = k ;
1968  }
1969  }
1970  }
1971 
1972 #ifndef NDEBUG
1973  for (i = 0 ; i < n_cset ; i++)
1974  {
1975  ASSERT (dead_cols [i] == 0) ;
1976  }
1977 #endif
1978 
1979  /* === Return statistics in stats ======================================= */
1980 
1981  stats [CCOLAMD_DENSE_ROW] = ndense_row ;
1982  stats [CCOLAMD_DENSE_COL] = nempty_row ;
1983  stats [CCOLAMD_NEWLY_EMPTY_ROW] = nnewlyempty_row ;
1984  stats [CCOLAMD_DENSE_COL] = ndense_col ;
1985  stats [CCOLAMD_EMPTY_COL] = nempty_col ;
1986  stats [CCOLAMD_NEWLY_EMPTY_COL] = nnewlyempty_col ;
1987  ASSERT (ndense_col + nempty_col + nnewlyempty_col == n_col - n_col2) ;
1988  if (p_nfr)
1989  {
1990  *p_nfr = nfr ;
1991  }
1992  stats [CCOLAMD_DEFRAG_COUNT] = ngarbage ;
1993  DEBUG1 (("ccolamd: done.\n")) ;
1994  return (TRUE) ;
1995 }
1996 
1997 
1998 /* ========================================================================== */
1999 /* === colamd_report ======================================================== */
2000 /* ========================================================================== */
2001 
2004  Int stats [CCOLAMD_STATS]
2005 )
2006 {
2007  print_report ("ccolamd", stats) ;
2008 }
2009 
2010 
2011 /* ========================================================================== */
2012 /* === symamd_report ======================================================== */
2013 /* ========================================================================== */
2014 
2017  Int stats [CCOLAMD_STATS]
2018 )
2019 {
2020  print_report ("csymamd", stats) ;
2021 }
2022 
2023 
2024 /* ========================================================================== */
2025 /* === NON-USER-CALLABLE ROUTINES: ========================================== */
2026 /* ========================================================================== */
2027 
2028 /* There are no user-callable routines beyond this point in the file */
2029 
2030 
2031 /* ========================================================================== */
2032 /* === init_rows_cols ======================================================= */
2033 /* ========================================================================== */
2034 
2035 /*
2036  Takes the column form of the matrix in A and creates the row form of the
2037  matrix. Also, row and column attributes are stored in the Col and Row
2038  structs. If the columns are un-sorted or contain duplicate row indices,
2039  this routine will also sort and remove duplicate row indices from the
2040  column form of the matrix. Returns FALSE if the matrix is invalid,
2041  TRUE otherwise. Not user-callable.
2042 */
2043 
2044 PRIVATE Int init_rows_cols /* returns TRUE if OK, or FALSE otherwise */
2046  /* === Parameters ======================================================= */
2047 
2048  Int n_row, /* number of rows of A */
2049  Int n_col, /* number of columns of A */
2050  CColamd_Row Row [ ], /* of size n_row+1 */
2051  CColamd_Col Col [ ], /* of size n_col+1 */
2052  Int A [ ], /* row indices of A, of size Alen */
2053  Int p [ ], /* pointers to columns in A, of size n_col+1 */
2054  Int stats [CCOLAMD_STATS] /* colamd statistics */
2055 )
2056 {
2057  /* === Local variables ================================================== */
2058 
2059  Int col ; /* a column index */
2060  Int row ; /* a row index */
2061  Int *cp ; /* a column pointer */
2062  Int *cp_end ; /* a pointer to the end of a column */
2063  Int *rp ; /* a row pointer */
2064  Int *rp_end ; /* a pointer to the end of a row */
2065  Int last_row ; /* previous row */
2066 
2067  /* === Initialize columns, and check column pointers ==================== */
2068 
2069  for (col = 0 ; col < n_col ; col++)
2070  {
2071  Col [col].start = p [col] ;
2072  Col [col].length = p [col+1] - p [col] ;
2073 
2074  if (Col [col].length < 0)
2075  {
2076  /* column pointers must be non-decreasing */
2078  stats [CCOLAMD_INFO1] = col ;
2079  stats [CCOLAMD_INFO2] = Col [col].length ;
2080  DEBUG1 (("ccolamd: col "ID" length "ID" < 0\n",
2081  col, Col [col].length)) ;
2082  return (FALSE) ;
2083  }
2084 
2085  Col [col].shared1.thickness = 1 ;
2086  Col [col].shared2.score = 0 ;
2087  Col [col].shared3.prev = EMPTY ;
2088  Col [col].shared4.degree_next = EMPTY ;
2089  Col [col].nextcol = EMPTY ;
2090  Col [col].lastcol = col ;
2091  }
2092 
2093  /* p [0..n_col] no longer needed, used as "head" in subsequent routines */
2094 
2095  /* === Scan columns, compute row degrees, and check row indices ========= */
2096 
2097  stats [CCOLAMD_INFO3] = 0 ; /* number of duplicate or unsorted row indices*/
2098 
2099  for (row = 0 ; row < n_row ; row++)
2100  {
2101  Row [row].length = 0 ;
2102  Row [row].shared2.mark = -1 ;
2103  Row [row].thickness = 1 ;
2104  Row [row].front = EMPTY ;
2105  }
2106 
2107  for (col = 0 ; col < n_col ; col++)
2108  {
2109  DEBUG1 (("\nCcolamd input column "ID":\n", col)) ;
2110  last_row = -1 ;
2111 
2112  cp = &A [p [col]] ;
2113  cp_end = &A [p [col+1]] ;
2114 
2115  while (cp < cp_end)
2116  {
2117  row = *cp++ ;
2118  DEBUG1 (("row: "ID"\n", row)) ;
2119 
2120  /* make sure row indices within range */
2121  if (row < 0 || row >= n_row)
2122  {
2124  stats [CCOLAMD_INFO1] = col ;
2125  stats [CCOLAMD_INFO2] = row ;
2126  stats [CCOLAMD_INFO3] = n_row ;
2127  DEBUG1 (("row "ID" col "ID" out of bounds\n", row, col)) ;
2128  return (FALSE) ;
2129  }
2130 
2131  if (row <= last_row || Row [row].shared2.mark == col)
2132  {
2133  /* row index are unsorted or repeated (or both), thus col */
2134  /* is jumbled. This is a notice, not an error condition. */
2136  stats [CCOLAMD_INFO1] = col ;
2137  stats [CCOLAMD_INFO2] = row ;
2138  (stats [CCOLAMD_INFO3]) ++ ;
2139  DEBUG1 (("row "ID" col "ID" unsorted/duplicate\n", row, col)) ;
2140  }
2141 
2142  if (Row [row].shared2.mark != col)
2143  {
2144  Row [row].length++ ;
2145  }
2146  else
2147  {
2148  /* this is a repeated entry in the column, */
2149  /* it will be removed */
2150  Col [col].length-- ;
2151  }
2152 
2153  /* mark the row as having been seen in this column */
2154  Row [row].shared2.mark = col ;
2155 
2156  last_row = row ;
2157  }
2158  }
2159 
2160  /* === Compute row pointers ============================================= */
2161 
2162  /* row form of the matrix starts directly after the column */
2163  /* form of matrix in A */
2164  Row [0].start = p [n_col] ;
2165  Row [0].shared1.p = Row [0].start ;
2166  Row [0].shared2.mark = -1 ;
2167  for (row = 1 ; row < n_row ; row++)
2168  {
2169  Row [row].start = Row [row-1].start + Row [row-1].length ;
2170  Row [row].shared1.p = Row [row].start ;
2171  Row [row].shared2.mark = -1 ;
2172  }
2173 
2174  /* === Create row form ================================================== */
2175 
2176  if (stats [CCOLAMD_STATUS] == CCOLAMD_OK_BUT_JUMBLED)
2177  {
2178  /* if cols jumbled, watch for repeated row indices */
2179  for (col = 0 ; col < n_col ; col++)
2180  {
2181  cp = &A [p [col]] ;
2182  cp_end = &A [p [col+1]] ;
2183  while (cp < cp_end)
2184  {
2185  row = *cp++ ;
2186  if (Row [row].shared2.mark != col)
2187  {
2188  A [(Row [row].shared1.p)++] = col ;
2189  Row [row].shared2.mark = col ;
2190  }
2191  }
2192  }
2193  }
2194  else
2195  {
2196  /* if cols not jumbled, we don't need the mark (this is faster) */
2197  for (col = 0 ; col < n_col ; col++)
2198  {
2199  cp = &A [p [col]] ;
2200  cp_end = &A [p [col+1]] ;
2201  while (cp < cp_end)
2202  {
2203  A [(Row [*cp++].shared1.p)++] = col ;
2204  }
2205  }
2206  }
2207 
2208  /* === Clear the row marks and set row degrees ========================== */
2209 
2210  for (row = 0 ; row < n_row ; row++)
2211  {
2212  Row [row].shared2.mark = 0 ;
2213  Row [row].shared1.degree = Row [row].length ;
2214  }
2215 
2216  /* === See if we need to re-create columns ============================== */
2217 
2218  if (stats [CCOLAMD_STATUS] == CCOLAMD_OK_BUT_JUMBLED)
2219  {
2220  DEBUG1 (("ccolamd: reconstructing column form, matrix jumbled\n")) ;
2221 
2222 #ifndef NDEBUG
2223  /* make sure column lengths are correct */
2224  for (col = 0 ; col < n_col ; col++)
2225  {
2226  p [col] = Col [col].length ;
2227  }
2228  for (row = 0 ; row < n_row ; row++)
2229  {
2230  rp = &A [Row [row].start] ;
2231  rp_end = rp + Row [row].length ;
2232  while (rp < rp_end)
2233  {
2234  p [*rp++]-- ;
2235  }
2236  }
2237  for (col = 0 ; col < n_col ; col++)
2238  {
2239  ASSERT (p [col] == 0) ;
2240  }
2241  /* now p is all zero (different than when debugging is turned off) */
2242 #endif
2243 
2244  /* === Compute col pointers ========================================= */
2245 
2246  /* col form of the matrix starts at A [0]. */
2247  /* Note, we may have a gap between the col form and the row */
2248  /* form if there were duplicate entries, if so, it will be */
2249  /* removed upon the first garbage collection */
2250  Col [0].start = 0 ;
2251  p [0] = Col [0].start ;
2252  for (col = 1 ; col < n_col ; col++)
2253  {
2254  /* note that the lengths here are for pruned columns, i.e. */
2255  /* no duplicate row indices will exist for these columns */
2256  Col [col].start = Col [col-1].start + Col [col-1].length ;
2257  p [col] = Col [col].start ;
2258  }
2259 
2260  /* === Re-create col form =========================================== */
2261 
2262  for (row = 0 ; row < n_row ; row++)
2263  {
2264  rp = &A [Row [row].start] ;
2265  rp_end = rp + Row [row].length ;
2266  while (rp < rp_end)
2267  {
2268  A [(p [*rp++])++] = row ;
2269  }
2270  }
2271  }
2272 
2273  /* === Done. Matrix is not (or no longer) jumbled ====================== */
2274 
2275 
2276  return (TRUE) ;
2277 }
2278 
2279 
2280 /* ========================================================================== */
2281 /* === init_scoring ========================================================= */
2282 /* ========================================================================== */
2283 
2284 /*
2285  Kills dense or empty columns and rows, calculates an initial score for
2286  each column, and places all columns in the degree lists. Not user-callable.
2287 */
2288 
2289 PRIVATE void init_scoring
2291  /* === Parameters ======================================================= */
2292 
2293  Int n_row, /* number of rows of A */
2294  Int n_col, /* number of columns of A */
2295  CColamd_Row Row [ ], /* of size n_row+1 */
2296  CColamd_Col Col [ ], /* of size n_col+1 */
2297  Int A [ ], /* column form and row form of A */
2298  Int head [ ], /* of size n_col+1 */
2299  double knobs [CCOLAMD_KNOBS],/* parameters */
2300  Int *p_n_row2, /* number of non-dense, non-empty rows */
2301  Int *p_n_col2, /* number of non-dense, non-empty columns */
2302  Int *p_max_deg, /* maximum row degree */
2303  Int cmember [ ],
2304  Int n_cset,
2305  Int cset_start [ ],
2306  Int dead_cols [ ],
2307  Int *p_ndense_row, /* number of dense rows */
2308  Int *p_nempty_row, /* number of original empty rows */
2309  Int *p_nnewlyempty_row, /* number of newly empty rows */
2310  Int *p_ndense_col, /* number of dense cols (excl "empty" cols) */
2311  Int *p_nempty_col, /* number of original empty cols */
2312  Int *p_nnewlyempty_col /* number of newly empty cols */
2313 )
2314 {
2315 /* === Local variables ================================================== */
2316 
2317  Int c ; /* a column index */
2318  Int r, row ; /* a row index */
2319  Int *cp ; /* a column pointer */
2320  Int deg ; /* degree of a row or column */
2321  Int *cp_end ; /* a pointer to the end of a column */
2322  Int *new_cp ; /* new column pointer */
2323  Int col_length ; /* length of pruned column */
2324  Int score ; /* current column score */
2325  Int n_col2 ; /* number of non-dense, non-empty columns */
2326  Int n_row2 ; /* number of non-dense, non-empty rows */
2327  Int dense_row_count ; /* remove rows with more entries than this */
2328  Int dense_col_count ; /* remove cols with more entries than this */
2329  Int max_deg ; /* maximum row degree */
2330  Int s ; /* a cset index */
2331  Int ndense_row ; /* number of dense rows */
2332  Int nempty_row ; /* number of empty rows */
2333  Int nnewlyempty_row ; /* number of newly empty rows */
2334  Int ndense_col ; /* number of dense cols (excl "empty" cols) */
2335  Int nempty_col ; /* number of original empty cols */
2336  Int nnewlyempty_col ; /* number of newly empty cols */
2337  Int ne ;
2338 
2339 #ifndef NDEBUG
2340  Int debug_count ; /* debug only. */
2341 #endif
2342 
2343  /* === Extract knobs ==================================================== */
2344 
2345  /* Note: if knobs contains a NaN, this is undefined: */
2346  if (knobs [CCOLAMD_DENSE_ROW] < 0)
2347  {
2348  /* only remove completely dense rows */
2349  dense_row_count = n_col-1 ;
2350  }
2351  else
2352  {
2353  dense_row_count = DENSE_DEGREE (knobs [CCOLAMD_DENSE_ROW], n_col) ;
2354  }
2355  if (knobs [CCOLAMD_DENSE_COL] < 0)
2356  {
2357  /* only remove completely dense columns */
2358  dense_col_count = n_row-1 ;
2359  }
2360  else
2361  {
2362  dense_col_count =
2363  DENSE_DEGREE (knobs [CCOLAMD_DENSE_COL], MIN (n_row, n_col)) ;
2364  }
2365 
2366  DEBUG1 (("densecount: "ID" "ID"\n", dense_row_count, dense_col_count)) ;
2367  max_deg = 0 ;
2368 
2369  n_col2 = n_col ;
2370  n_row2 = n_row ;
2371 
2372  /* Set the head array for bookkeeping of dense and empty columns. */
2373  /* This will be used as hash buckets later. */
2374  for (s = 0 ; s < n_cset ; s++)
2375  {
2376  head [s] = cset_start [s+1] ;
2377  }
2378 
2379  ndense_col = 0 ;
2380  nempty_col = 0 ;
2381  nnewlyempty_col = 0 ;
2382  ndense_row = 0 ;
2383  nempty_row = 0 ;
2384  nnewlyempty_row = 0 ;
2385 
2386  /* === Kill empty columns =============================================== */
2387 
2388  /* Put the empty columns at the end in their natural order, so that LU */
2389  /* factorization can proceed as far as possible. */
2390  for (c = n_col-1 ; c >= 0 ; c--)
2391  {
2392  deg = Col [c].length ;
2393  if (deg == 0)
2394  {
2395  /* this is a empty column, kill and order it last of its cset */
2396  Col [c].shared2.order = --head [CMEMBER (c)] ;
2397  --n_col2 ;
2398  dead_cols [CMEMBER (c)] ++ ;
2399  nempty_col++ ;
2400  KILL_PRINCIPAL_COL (c) ;
2401  }
2402  }
2403  DEBUG1 (("ccolamd: null columns killed: "ID"\n", n_col - n_col2)) ;
2404 
2405  /* === Kill dense columns =============================================== */
2406 
2407  /* Put the dense columns at the end, in their natural order */
2408  for (c = n_col-1 ; c >= 0 ; c--)
2409  {
2410  /* skip any dead columns */
2411  if (COL_IS_DEAD (c))
2412  {
2413  continue ;
2414  }
2415  deg = Col [c].length ;
2416  if (deg > dense_col_count)
2417  {
2418  /* this is a dense column, kill and order it last of its cset */
2419  Col [c].shared2.order = --head [CMEMBER (c)] ;
2420  --n_col2 ;
2421  dead_cols [CMEMBER (c)] ++ ;
2422  ndense_col++ ;
2423  /* decrement the row degrees */
2424  cp = &A [Col [c].start] ;
2425  cp_end = cp + Col [c].length ;
2426  while (cp < cp_end)
2427  {
2428  Row [*cp++].shared1.degree-- ;
2429  }
2430  KILL_PRINCIPAL_COL (c) ;
2431  }
2432  }
2433  DEBUG1 (("Dense and null columns killed: "ID"\n", n_col - n_col2)) ;
2434 
2435  /* === Kill dense and empty rows ======================================== */
2436 
2437  /* Note that there can now be empty rows, since dense columns have
2438  * been deleted. These are "newly" empty rows. */
2439 
2440  ne = 0 ;
2441  for (r = 0 ; r < n_row ; r++)
2442  {
2443  deg = Row [r].shared1.degree ;
2444  ASSERT (deg >= 0 && deg <= n_col) ;
2445  if (deg > dense_row_count)
2446  {
2447  /* There is at least one dense row. Continue ordering, but */
2448  /* symbolic factorization will be redone after ccolamd is done.*/
2449  ndense_row++ ;
2450  }
2451  if (deg == 0)
2452  {
2453  /* this is a newly empty row, or original empty row */
2454  ne++ ;
2455  }
2456  if (deg > dense_row_count || deg == 0)
2457  {
2458  /* kill a dense or empty row */
2459  KILL_ROW (r) ;
2460  Row [r].thickness = 0 ;
2461  --n_row2 ;
2462  }
2463  else
2464  {
2465  /* keep track of max degree of remaining rows */
2466  max_deg = MAX (max_deg, deg) ;
2467  }
2468  }
2469  nnewlyempty_row = ne - nempty_row ;
2470  DEBUG1 (("ccolamd: Dense and null rows killed: "ID"\n", n_row - n_row2)) ;
2471 
2472  /* === Compute initial column scores ==================================== */
2473 
2474  /* At this point the row degrees are accurate. They reflect the number */
2475  /* of "live" (non-dense) columns in each row. No empty rows exist. */
2476  /* Some "live" columns may contain only dead rows, however. These are */
2477  /* pruned in the code below. */
2478 
2479  /* now find the initial COLMMD score for each column */
2480  for (c = n_col-1 ; c >= 0 ; c--)
2481  {
2482  /* skip dead column */
2483  if (COL_IS_DEAD (c))
2484  {
2485  continue ;
2486  }
2487  score = 0 ;
2488  cp = &A [Col [c].start] ;
2489  new_cp = cp ;
2490  cp_end = cp + Col [c].length ;
2491  while (cp < cp_end)
2492  {
2493  /* get a row */
2494  row = *cp++ ;
2495  /* skip if dead */
2496  if (ROW_IS_DEAD (row))
2497  {
2498  continue ;
2499  }
2500  /* compact the column */
2501  *new_cp++ = row ;
2502  /* add row's external degree */
2503  score += Row [row].shared1.degree - 1 ;
2504  /* guard against integer overflow */
2505  score = MIN (score, n_col) ;
2506  }
2507  /* determine pruned column length */
2508  col_length = (Int) (new_cp - &A [Col [c].start]) ;
2509  if (col_length == 0)
2510  {
2511  /* a newly-made null column (all rows in this col are "dense" */
2512  /* and have already been killed) */
2513  DEBUG1 (("Newly null killed: "ID"\n", c)) ;
2514  Col [c].shared2.order = -- head [CMEMBER (c)] ;
2515  --n_col2 ;
2516  dead_cols [CMEMBER (c)] ++ ;
2517  nnewlyempty_col++ ;
2518  KILL_PRINCIPAL_COL (c) ;
2519  }
2520  else
2521  {
2522  /* set column length and set score */
2523  ASSERT (score >= 0) ;
2524  ASSERT (score <= n_col) ;
2525  Col [c].length = col_length ;
2526  Col [c].shared2.score = score ;
2527  }
2528  }
2529  DEBUG1 (("ccolamd: Dense, null, and newly-null columns killed: "ID"\n",
2530  n_col-n_col2)) ;
2531 
2532  /* At this point, all empty rows and columns are dead. All live columns */
2533  /* are "clean" (containing no dead rows) and simplicial (no supercolumns */
2534  /* yet). Rows may contain dead columns, but all live rows contain at */
2535  /* least one live column. */
2536 
2537 #ifndef NDEBUG
2538  debug_count = 0 ;
2539 #endif
2540 
2541  /* clear the hash buckets */
2542  for (c = 0 ; c <= n_col ; c++)
2543  {
2544  head [c] = EMPTY ;
2545  }
2546 
2547 #ifndef NDEBUG
2548  debug_structures (n_row, n_col, Row, Col, A, cmember, cset_start) ;
2549 #endif
2550 
2551  /* === Return number of remaining columns, and max row degree =========== */
2552 
2553  *p_n_col2 = n_col2 ;
2554  *p_n_row2 = n_row2 ;
2555  *p_max_deg = max_deg ;
2556  *p_ndense_row = ndense_row ;
2557  *p_nempty_row = nempty_row ; /* original empty rows */
2558  *p_nnewlyempty_row = nnewlyempty_row ;
2559  *p_ndense_col = ndense_col ;
2560  *p_nempty_col = nempty_col ; /* original empty cols */
2561  *p_nnewlyempty_col = nnewlyempty_col ;
2562 }
2563 
2564 
2565 /* ========================================================================== */
2566 /* === find_ordering ======================================================== */
2567 /* ========================================================================== */
2568 
2569 /*
2570  * Order the principal columns of the supercolumn form of the matrix
2571  * (no supercolumns on input). Uses a minimum approximate column minimum
2572  * degree ordering method. Not user-callable.
2573  */
2574 
2575 PRIVATE Int find_ordering /* return the number of garbage collections */
2577  /* === Parameters ======================================================= */
2578 
2579  Int n_row, /* number of rows of A */
2580  Int n_col, /* number of columns of A */
2581  Int Alen, /* size of A, 2*nnz + n_col or larger */
2582  CColamd_Row Row [ ], /* of size n_row+1 */
2583  CColamd_Col Col [ ], /* of size n_col+1 */
2584  Int A [ ], /* column form and row form of A */
2585  Int head [ ], /* of size n_col+1 */
2586 #ifndef NDEBUG
2587  Int n_col2, /* Remaining columns to order */
2588 #endif
2589  Int max_deg, /* Maximum row degree */
2590  Int pfree, /* index of first free slot (2*nnz on entry) */
2591  Int cset [ ], /* constraint set of A */
2592  Int cset_start [ ], /* pointer to the start of every cset */
2593 #ifndef NDEBUG
2594  Int n_cset, /* number of csets */
2595 #endif
2596  Int cmember [ ], /* col -> cset mapping */
2597  Int Front_npivcol [ ],
2598  Int Front_nrows [ ],
2599  Int Front_ncols [ ],
2600  Int Front_parent [ ],
2601  Int Front_cols [ ],
2602  Int *p_nfr, /* number of fronts */
2603  Int aggressive,
2604  Int InFront [ ],
2605  Int order_for_lu
2606 )
2607 {
2608  /* === Local variables ================================================== */
2609 
2610  Int k ; /* current pivot ordering step */
2611  Int pivot_col ; /* current pivot column */
2612  Int *cp ; /* a column pointer */
2613  Int *rp ; /* a row pointer */
2614  Int pivot_row ; /* current pivot row */
2615  Int *new_cp ; /* modified column pointer */
2616  Int *new_rp ; /* modified row pointer */
2617  Int pivot_row_start ; /* pointer to start of pivot row */
2618  Int pivot_row_degree ; /* number of columns in pivot row */
2619  Int pivot_row_length ; /* number of supercolumns in pivot row */
2620  Int pivot_col_score ; /* score of pivot column */
2621  Int needed_memory ; /* free space needed for pivot row */
2622  Int *cp_end ; /* pointer to the end of a column */
2623  Int *rp_end ; /* pointer to the end of a row */
2624  Int row ; /* a row index */
2625  Int col ; /* a column index */
2626  Int max_score ; /* maximum possible score */
2627  Int cur_score ; /* score of current column */
2628  unsigned Int hash ; /* hash value for supernode detection */
2629  Int head_column ; /* head of hash bucket */
2630  Int first_col ; /* first column in hash bucket */
2631  Int tag_mark ; /* marker value for mark array */
2632  Int row_mark ; /* Row [row].shared2.mark */
2633  Int set_difference ; /* set difference size of row with pivot row */
2634  Int min_score ; /* smallest column score */
2635  Int col_thickness ; /* "thickness" (no. of columns in a supercol) */
2636  Int max_mark ; /* maximum value of tag_mark */
2637  Int pivot_col_thickness ; /* number of columns represented by pivot col */
2638  Int prev_col ; /* Used by Dlist operations. */
2639  Int next_col ; /* Used by Dlist operations. */
2640  Int ngarbage ; /* number of garbage collections performed */
2641  Int current_set ; /* consraint set that is being ordered */
2642  Int score ; /* score of a column */
2643  Int colstart ; /* pointer to first column in current cset */
2644  Int colend ; /* pointer to last column in current cset */
2645  Int deadcol ; /* number of dense & null columns in a cset */
2646 
2647 #ifndef NDEBUG
2648  Int debug_d ; /* debug loop counter */
2649  Int debug_step = 0 ; /* debug loop counter */
2650  Int cols_thickness = 0 ; /* the thickness of the columns in current */
2651  /* cset degreelist and in pivot row pattern. */
2652 #endif
2653 
2654  Int pivot_row_thickness ; /* number of rows represented by pivot row */
2655  Int nfr = 0 ; /* number of fronts */
2656  Int child ;
2657 
2658  /* === Initialization and clear mark ==================================== */
2659 
2660  max_mark = Int_MAX - n_col ; /* Int_MAX defined in <limits.h> */
2661  tag_mark = clear_mark (0, max_mark, n_row, Row) ;
2662  min_score = 0 ;
2663  ngarbage = 0 ;
2664  current_set = -1 ;
2665  deadcol = 0 ;
2666  DEBUG1 (("ccolamd: Ordering, n_col2="ID"\n", n_col2)) ;
2667 
2668  for (row = 0 ; row < n_row ; row++)
2669  {
2670  InFront [row] = EMPTY ;
2671  }
2672 
2673  /* === Order the columns ================================================ */
2674 
2675  for (k = 0 ; k < n_col ; /* 'k' is incremented below */)
2676  {
2677 
2678  /* make sure degree list isn't empty */
2679  ASSERT (min_score >= 0) ;
2680  ASSERT (min_score <= n_col) ;
2681  ASSERT (head [min_score] >= EMPTY) ;
2682 
2683 #ifndef NDEBUG
2684  for (debug_d = 0 ; debug_d < min_score ; debug_d++)
2685  {
2686  ASSERT (head [debug_d] == EMPTY) ;
2687  }
2688 #endif
2689 
2690  /* Initialize the degree list with columns from next non-empty cset */
2691 
2692  while ((k+deadcol) == cset_start [current_set+1])
2693  {
2694  current_set++ ;
2695  DEBUG1 (("\n\n\n============ CSET: "ID"\n", current_set)) ;
2696  k += deadcol ; /* jump to start of next cset */
2697  deadcol = 0 ; /* reset dead column count */
2698 
2699  ASSERT ((current_set == n_cset) == (k == n_col)) ;
2700 
2701  /* return if all columns are ordered. */
2702  if (k == n_col)
2703  {
2704  *p_nfr = nfr ;
2705  return (ngarbage) ;
2706  }
2707 
2708 #ifndef NDEBUG
2709  for (col = 0 ; col <= n_col ; col++)
2710  {
2711  ASSERT (head [col] == EMPTY) ;
2712  }
2713 #endif
2714 
2715  min_score = n_col ;
2716  colstart = cset_start [current_set] ;
2717  colend = cset_start [current_set+1] ;
2718 
2719  while (colstart < colend)
2720  {
2721  col = cset [colstart++] ;
2722 
2723  if (COL_IS_DEAD(col))
2724  {
2725  DEBUG1 (("Column "ID" is dead\n", col)) ;
2726  /* count dense and null columns */
2727  if (Col [col].shared2.order != EMPTY)
2728  {
2729  deadcol++ ;
2730  }
2731  continue ;
2732  }
2733 
2734  /* only add principal columns in current set to degree lists */
2735  ASSERT (CMEMBER (col) == current_set) ;
2736 
2737  score = Col [col].shared2.score ;
2738  DEBUG1 (("Column "ID" is alive, score "ID"\n", col, score)) ;
2739 
2740  ASSERT (min_score >= 0) ;
2741  ASSERT (min_score <= n_col) ;
2742  ASSERT (score >= 0) ;
2743  ASSERT (score <= n_col) ;
2744  ASSERT (head [score] >= EMPTY) ;
2745 
2746  /* now add this column to dList at proper score location */
2747  next_col = head [score] ;
2748  Col [col].shared3.prev = EMPTY ;
2749  Col [col].shared4.degree_next = next_col ;
2750 
2751  /* if there already was a column with the same score, set its */
2752  /* previous pointer to this new column */
2753  if (next_col != EMPTY)
2754  {
2755  Col [next_col].shared3.prev = col ;
2756  }
2757  head [score] = col ;
2758 
2759  /* see if this score is less than current min */
2760  min_score = MIN (min_score, score) ;
2761  }
2762 
2763 #ifndef NDEBUG
2764  DEBUG1 (("degree lists initialized \n")) ;
2765  debug_deg_lists (n_row, n_col, Row, Col, head, min_score,
2766  ((cset_start [current_set+1]-cset_start [current_set])-deadcol),
2767  max_deg) ;
2768 #endif
2769  }
2770 
2771 #ifndef NDEBUG
2772  if (debug_step % 100 == 0)
2773  {
2774  DEBUG2 (("\n... Step k: "ID" out of n_col2: "ID"\n", k, n_col2)) ;
2775  }
2776  else
2777  {
2778  DEBUG3 (("\n------Step k: "ID" out of n_col2: "ID"\n", k, n_col2)) ;
2779  }
2780  debug_step++ ;
2781  DEBUG1 (("start of step k="ID": ", k)) ;
2782  debug_deg_lists (n_row, n_col, Row, Col, head,
2783  min_score, cset_start [current_set+1]-(k+deadcol), max_deg) ;
2784  debug_matrix (n_row, n_col, Row, Col, A) ;
2785 #endif
2786 
2787  /* === Select pivot column, and order it ============================ */
2788 
2789  while (head [min_score] == EMPTY && min_score < n_col)
2790  {
2791  min_score++ ;
2792  }
2793 
2794  pivot_col = head [min_score] ;
2795 
2796  ASSERT (pivot_col >= 0 && pivot_col <= n_col) ;
2797  next_col = Col [pivot_col].shared4.degree_next ;
2798  head [min_score] = next_col ;
2799  if (next_col != EMPTY)
2800  {
2801  Col [next_col].shared3.prev = EMPTY ;
2802  }
2803 
2804  ASSERT (COL_IS_ALIVE (pivot_col)) ;
2805 
2806  /* remember score for defrag check */
2807  pivot_col_score = Col [pivot_col].shared2.score ;
2808 
2809  /* the pivot column is the kth column in the pivot order */
2810  Col [pivot_col].shared2.order = k ;
2811 
2812  /* increment order count by column thickness */
2813  pivot_col_thickness = Col [pivot_col].shared1.thickness ;
2814  k += pivot_col_thickness ;
2815  ASSERT (pivot_col_thickness > 0) ;
2816  DEBUG3 (("Pivot col: "ID" thick "ID"\n", pivot_col,
2817  pivot_col_thickness)) ;
2818 
2819  /* === Garbage_collection, if necessary ============================= */
2820 
2821  needed_memory = MIN (pivot_col_score, n_col - k) ;
2822  if (pfree + needed_memory >= Alen)
2823  {
2824  pfree = garbage_collection (n_row, n_col, Row, Col, A, &A [pfree]) ;
2825  ngarbage++ ;
2826  /* after garbage collection we will have enough */
2827  ASSERT (pfree + needed_memory < Alen) ;
2828  /* garbage collection has wiped out Row [ ].shared2.mark array */
2829  tag_mark = clear_mark (0, max_mark, n_row, Row) ;
2830 
2831 #ifndef NDEBUG
2832  debug_matrix (n_row, n_col, Row, Col, A) ;
2833 #endif
2834  }
2835 
2836  /* === Compute pivot row pattern ==================================== */
2837 
2838  /* get starting location for this new merged row */
2839  pivot_row_start = pfree ;
2840 
2841  /* initialize new row counts to zero */
2842  pivot_row_degree = 0 ;
2843  pivot_row_thickness = 0 ;
2844 
2845  /* tag pivot column as having been visited so it isn't included */
2846  /* in merged pivot row */
2847  Col [pivot_col].shared1.thickness = -pivot_col_thickness ;
2848 
2849  /* pivot row is the union of all rows in the pivot column pattern */
2850  cp = &A [Col [pivot_col].start] ;
2851  cp_end = cp + Col [pivot_col].length ;
2852  while (cp < cp_end)
2853  {
2854  /* get a row */
2855  row = *cp++ ;
2856  ASSERT (row >= 0 && row < n_row) ;
2857  DEBUG4 (("Pivcol pattern "ID" "ID"\n", ROW_IS_ALIVE (row), row)) ;
2858  /* skip if row is dead */
2859  if (ROW_IS_ALIVE (row))
2860  {
2861  /* sum the thicknesses of all the rows */
2862  pivot_row_thickness += Row [row].thickness ;
2863 
2864  rp = &A [Row [row].start] ;
2865  rp_end = rp + Row [row].length ;
2866  while (rp < rp_end)
2867  {
2868  /* get a column */
2869  col = *rp++ ;
2870  /* add the column, if alive and untagged */
2871  col_thickness = Col [col].shared1.thickness ;
2872  if (col_thickness > 0 && COL_IS_ALIVE (col))
2873  {
2874  /* tag column in pivot row */
2875  Col [col].shared1.thickness = -col_thickness ;
2876  ASSERT (pfree < Alen) ;
2877  /* place column in pivot row */
2878  A [pfree++] = col ;
2879  pivot_row_degree += col_thickness ;
2880  DEBUG4 (("\t\t\tNew live col in pivrow: "ID"\n",col)) ;
2881  }
2882 #ifndef NDEBUG
2883  if (col_thickness < 0 && COL_IS_ALIVE (col))
2884  {
2885  DEBUG4 (("\t\t\tOld live col in pivrow: "ID"\n",col)) ;
2886  }
2887 #endif
2888  }
2889  }
2890  }
2891 
2892  /* pivot_row_thickness is the number of rows in frontal matrix */
2893  /* including both pivotal rows and nonpivotal rows */
2894 
2895  /* clear tag on pivot column */
2896  Col [pivot_col].shared1.thickness = pivot_col_thickness ;
2897  max_deg = MAX (max_deg, pivot_row_degree) ;
2898 
2899 #ifndef NDEBUG
2900  DEBUG3 (("check2\n")) ;
2901  debug_mark (n_row, Row, tag_mark, max_mark) ;
2902 #endif
2903 
2904  /* === Kill all rows used to construct pivot row ==================== */
2905 
2906  /* also kill pivot row, temporarily */
2907  cp = &A [Col [pivot_col].start] ;
2908  cp_end = cp + Col [pivot_col].length ;
2909  while (cp < cp_end)
2910  {
2911  /* may be killing an already dead row */
2912  row = *cp++ ;
2913  DEBUG3 (("Kill row in pivot col: "ID"\n", row)) ;
2914  ASSERT (row >= 0 && row < n_row) ;
2915  if (ROW_IS_ALIVE (row))
2916  {
2917  if (Row [row].front != EMPTY)
2918  {
2919  /* This row represents a frontal matrix. */
2920  /* Row [row].front is a child of current front */
2921  child = Row [row].front ;
2922  Front_parent [child] = nfr ;
2923  DEBUG1 (("Front "ID" => front "ID", normal\n", child, nfr));
2924  }
2925  else
2926  {
2927  /* This is an original row. Keep track of which front
2928  * is its parent in the row-merge tree. */
2929  InFront [row] = nfr ;
2930  DEBUG1 (("Row "ID" => front "ID", normal\n", row, nfr)) ;
2931  }
2932  }
2933 
2934  KILL_ROW (row) ;
2935  Row [row].thickness = 0 ;
2936  }
2937 
2938  /* === Select a row index to use as the new pivot row =============== */
2939 
2940  pivot_row_length = pfree - pivot_row_start ;
2941  if (pivot_row_length > 0)
2942  {
2943  /* pick the "pivot" row arbitrarily (first row in col) */
2944  pivot_row = A [Col [pivot_col].start] ;
2945  DEBUG3 (("Pivotal row is "ID"\n", pivot_row)) ;
2946  }
2947  else
2948  {
2949  /* there is no pivot row, since it is of zero length */
2950  pivot_row = EMPTY ;
2951  ASSERT (pivot_row_length == 0) ;
2952  }
2953  ASSERT (Col [pivot_col].length > 0 || pivot_row_length == 0) ;
2954 
2955  /* === Approximate degree computation =============================== */
2956 
2957  /* Here begins the computation of the approximate degree. The column */
2958  /* score is the sum of the pivot row "length", plus the size of the */
2959  /* set differences of each row in the column minus the pattern of the */
2960  /* pivot row itself. The column ("thickness") itself is also */
2961  /* excluded from the column score (we thus use an approximate */
2962  /* external degree). */
2963 
2964  /* The time taken by the following code (compute set differences, and */
2965  /* add them up) is proportional to the size of the data structure */
2966  /* being scanned - that is, the sum of the sizes of each column in */
2967  /* the pivot row. Thus, the amortized time to compute a column score */
2968  /* is proportional to the size of that column (where size, in this */
2969  /* context, is the column "length", or the number of row indices */
2970  /* in that column). The number of row indices in a column is */
2971  /* monotonically non-decreasing, from the length of the original */
2972  /* column on input to colamd. */
2973 
2974  /* === Compute set differences ====================================== */
2975 
2976  DEBUG3 (("** Computing set differences phase. **\n")) ;
2977 
2978  /* pivot row is currently dead - it will be revived later. */
2979 
2980  DEBUG3 (("Pivot row: ")) ;
2981  /* for each column in pivot row */
2982  rp = &A [pivot_row_start] ;
2983  rp_end = rp + pivot_row_length ;
2984  while (rp < rp_end)
2985  {
2986  col = *rp++ ;
2987  ASSERT (COL_IS_ALIVE (col) && col != pivot_col) ;
2988  DEBUG3 (("Col: "ID"\n", col)) ;
2989 
2990  /* clear tags used to construct pivot row pattern */
2991  col_thickness = -Col [col].shared1.thickness ;
2992  ASSERT (col_thickness > 0) ;
2993  Col [col].shared1.thickness = col_thickness ;
2994 
2995  /* === Remove column from degree list =========================== */
2996 
2997  /* only columns in current_set will be in degree list */
2998  if (CMEMBER (col) == current_set)
2999  {
3000 #ifndef NDEBUG
3001  cols_thickness += col_thickness ;
3002 #endif
3003  cur_score = Col [col].shared2.score ;
3004  prev_col = Col [col].shared3.prev ;
3005  next_col = Col [col].shared4.degree_next ;
3006  DEBUG3 ((" cur_score "ID" prev_col "ID" next_col "ID"\n",
3007  cur_score, prev_col, next_col)) ;
3008  ASSERT (cur_score >= 0) ;
3009  ASSERT (cur_score <= n_col) ;
3010  ASSERT (cur_score >= EMPTY) ;
3011  if (prev_col == EMPTY)
3012  {
3013  head [cur_score] = next_col ;
3014  }
3015  else
3016  {
3017  Col [prev_col].shared4.degree_next = next_col ;
3018  }
3019  if (next_col != EMPTY)
3020  {
3021  Col [next_col].shared3.prev = prev_col ;
3022  }
3023  }
3024 
3025  /* === Scan the column ========================================== */
3026 
3027  cp = &A [Col [col].start] ;
3028  cp_end = cp + Col [col].length ;
3029  while (cp < cp_end)
3030  {
3031  /* get a row */
3032  row = *cp++ ;
3033  row_mark = Row [row].shared2.mark ;
3034  /* skip if dead */
3035  if (ROW_IS_MARKED_DEAD (row_mark))
3036  {
3037  continue ;
3038  }
3039  ASSERT (row != pivot_row) ;
3040  set_difference = row_mark - tag_mark ;
3041  /* check if the row has been seen yet */
3042  if (set_difference < 0)
3043  {
3044  ASSERT (Row [row].shared1.degree <= max_deg) ;
3045  set_difference = Row [row].shared1.degree ;
3046  }
3047  /* subtract column thickness from this row's set difference */
3048  set_difference -= col_thickness ;
3049  ASSERT (set_difference >= 0) ;
3050  /* absorb this row if the set difference becomes zero */
3051  if (set_difference == 0 && aggressive)
3052  {
3053  DEBUG3 (("aggressive absorption. Row: "ID"\n", row)) ;
3054 
3055  if (Row [row].front != EMPTY)
3056  {
3057  /* Row [row].front is a child of current front. */
3058  child = Row [row].front ;
3059  Front_parent [child] = nfr ;
3060  DEBUG1 (("Front "ID" => front "ID", aggressive\n",
3061  child, nfr)) ;
3062  }
3063  else
3064  {
3065  /* this is an original row. Keep track of which front
3066  * assembles it, for the row-merge tree */
3067  InFront [row] = nfr ;
3068  DEBUG1 (("Row "ID" => front "ID", aggressive\n",
3069  row, nfr)) ;
3070  }
3071 
3072  KILL_ROW (row) ;
3073 
3074  /* sum the thicknesses of all the rows */
3075  pivot_row_thickness += Row [row].thickness ;
3076  Row [row].thickness = 0 ;
3077  }
3078  else
3079  {
3080  /* save the new mark */
3081  Row [row].shared2.mark = set_difference + tag_mark ;
3082  }
3083  }
3084  }
3085 
3086 #ifndef NDEBUG
3087  debug_deg_lists (n_row, n_col, Row, Col, head, min_score,
3088  cset_start [current_set+1]-(k+deadcol)-(cols_thickness),
3089  max_deg) ;
3090  cols_thickness = 0 ;
3091 #endif
3092 
3093  /* === Add up set differences for each column ======================= */
3094 
3095  DEBUG3 (("** Adding set differences phase. **\n")) ;
3096 
3097  /* for each column in pivot row */
3098  rp = &A [pivot_row_start] ;
3099  rp_end = rp + pivot_row_length ;
3100  while (rp < rp_end)
3101  {
3102  /* get a column */
3103  col = *rp++ ;
3104  ASSERT (COL_IS_ALIVE (col) && col != pivot_col) ;
3105  hash = 0 ;
3106  cur_score = 0 ;
3107  cp = &A [Col [col].start] ;
3108  /* compact the column */
3109  new_cp = cp ;
3110  cp_end = cp + Col [col].length ;
3111 
3112  DEBUG4 (("Adding set diffs for Col: "ID".\n", col)) ;
3113 
3114  while (cp < cp_end)
3115  {
3116  /* get a row */
3117  row = *cp++ ;
3118  ASSERT (row >= 0 && row < n_row) ;
3119  row_mark = Row [row].shared2.mark ;
3120  /* skip if dead */
3121  if (ROW_IS_MARKED_DEAD (row_mark))
3122  {
3123  DEBUG4 ((" Row "ID", dead\n", row)) ;
3124  continue ;
3125  }
3126  DEBUG4 ((" Row "ID", set diff "ID"\n", row, row_mark-tag_mark));
3127  ASSERT (row_mark >= tag_mark) ;
3128  /* compact the column */
3129  *new_cp++ = row ;
3130  /* compute hash function */
3131  hash += row ;
3132  /* add set difference */
3133  cur_score += row_mark - tag_mark ;
3134  /* integer overflow... */
3135  cur_score = MIN (cur_score, n_col) ;
3136  }
3137 
3138  /* recompute the column's length */
3139  Col [col].length = (Int) (new_cp - &A [Col [col].start]) ;
3140 
3141  /* === Further mass elimination ================================= */
3142 
3143  if (Col [col].length == 0 && CMEMBER (col) == current_set)
3144  {
3145  DEBUG4 (("further mass elimination. Col: "ID"\n", col)) ;
3146  /* nothing left but the pivot row in this column */
3147  KILL_PRINCIPAL_COL (col) ;
3148  pivot_row_degree -= Col [col].shared1.thickness ;
3149  ASSERT (pivot_row_degree >= 0) ;
3150  /* order it */
3151  Col [col].shared2.order = k ;
3152  /* increment order count by column thickness */
3153  k += Col [col].shared1.thickness ;
3154  pivot_col_thickness += Col [col].shared1.thickness ;
3155  /* add to column list of front */
3156 #ifndef NDEBUG
3157  DEBUG1 (("Mass")) ;
3158  dump_super (col, Col, n_col) ;
3159 #endif
3160  Col [Col [col].lastcol].nextcol = Front_cols [nfr] ;
3161  Front_cols [nfr] = col ;
3162  }
3163  else
3164  {
3165  /* === Prepare for supercolumn detection ==================== */
3166 
3167  DEBUG4 (("Preparing supercol detection for Col: "ID".\n", col));
3168 
3169  /* save score so far */
3170  Col [col].shared2.score = cur_score ;
3171 
3172  /* add column to hash table, for supercolumn detection */
3173  hash %= n_col + 1 ;
3174 
3175  DEBUG4 ((" Hash = "ID", n_col = "ID".\n", hash, n_col)) ;
3176  ASSERT (((Int) hash) <= n_col) ;
3177 
3178  head_column = head [hash] ;
3179  if (head_column > EMPTY)
3180  {
3181  /* degree list "hash" is non-empty, use prev (shared3) of */
3182  /* first column in degree list as head of hash bucket */
3183  first_col = Col [head_column].shared3.headhash ;
3184  Col [head_column].shared3.headhash = col ;
3185  }
3186  else
3187  {
3188  /* degree list "hash" is empty, use head as hash bucket */
3189  first_col = - (head_column + 2) ;
3190  head [hash] = - (col + 2) ;
3191  }
3192  Col [col].shared4.hash_next = first_col ;
3193 
3194  /* save hash function in Col [col].shared3.hash */
3195  Col [col].shared3.hash = (Int) hash ;
3196  ASSERT (COL_IS_ALIVE (col)) ;
3197  }
3198  }
3199 
3200  /* The approximate external column degree is now computed. */
3201 
3202  /* === Supercolumn detection ======================================== */
3203 
3204  DEBUG3 (("** Supercolumn detection phase. **\n")) ;
3205 
3207 #ifndef NDEBUG
3208  n_col, Row,
3209 #endif
3210  Col, A, head, pivot_row_start, pivot_row_length, cmember) ;
3211 
3212  /* === Kill the pivotal column ====================================== */
3213 
3214  DEBUG1 ((" KILLING column detect supercols "ID" \n", pivot_col)) ;
3215  KILL_PRINCIPAL_COL (pivot_col) ;
3216 
3217  /* add columns to column list of front */
3218 #ifndef NDEBUG
3219  DEBUG1 (("Pivot")) ;
3220  dump_super (pivot_col, Col, n_col) ;
3221 #endif
3222  Col [Col [pivot_col].lastcol].nextcol = Front_cols [nfr] ;
3223  Front_cols [nfr] = pivot_col ;
3224 
3225  /* === Clear mark =================================================== */
3226 
3227  tag_mark = clear_mark (tag_mark+max_deg+1, max_mark, n_row, Row) ;
3228 
3229 #ifndef NDEBUG
3230  DEBUG3 (("check3\n")) ;
3231  debug_mark (n_row, Row, tag_mark, max_mark) ;
3232 #endif
3233 
3234  /* === Finalize the new pivot row, and column scores ================ */
3235 
3236  DEBUG3 (("** Finalize scores phase. **\n")) ;
3237 
3238  /* for each column in pivot row */
3239  rp = &A [pivot_row_start] ;
3240  /* compact the pivot row */
3241  new_rp = rp ;
3242  rp_end = rp + pivot_row_length ;
3243  while (rp < rp_end)
3244  {
3245  col = *rp++ ;
3246  /* skip dead columns */
3247  if (COL_IS_DEAD (col))
3248  {
3249  continue ;
3250  }
3251  *new_rp++ = col ;
3252  /* add new pivot row to column */
3253  A [Col [col].start + (Col [col].length++)] = pivot_row ;
3254 
3255  /* retrieve score so far and add on pivot row's degree. */
3256  /* (we wait until here for this in case the pivot */
3257  /* row's degree was reduced due to mass elimination). */
3258  cur_score = Col [col].shared2.score + pivot_row_degree ;
3259 
3260  /* calculate the max possible score as the number of */
3261  /* external columns minus the 'k' value minus the */
3262  /* columns thickness */
3263  max_score = n_col - k - Col [col].shared1.thickness ;
3264 
3265  /* make the score the external degree of the union-of-rows */
3266  cur_score -= Col [col].shared1.thickness ;
3267 
3268  /* make sure score is less or equal than the max score */
3269  cur_score = MIN (cur_score, max_score) ;
3270  ASSERT (cur_score >= 0) ;
3271 
3272  /* store updated score */
3273  Col [col].shared2.score = cur_score ;
3274 
3275  /* === Place column back in degree list ========================= */
3276 
3277  if (CMEMBER (col) == current_set)
3278  {
3279  ASSERT (min_score >= 0) ;
3280  ASSERT (min_score <= n_col) ;
3281  ASSERT (cur_score >= 0) ;
3282  ASSERT (cur_score <= n_col) ;
3283  ASSERT (head [cur_score] >= EMPTY) ;
3284  next_col = head [cur_score] ;
3285  Col [col].shared4.degree_next = next_col ;
3286  Col [col].shared3.prev = EMPTY ;
3287  if (next_col != EMPTY)
3288  {
3289  Col [next_col].shared3.prev = col ;
3290  }
3291  head [cur_score] = col ;
3292  /* see if this score is less than current min */
3293  min_score = MIN (min_score, cur_score) ;
3294  }
3295  else
3296  {
3297  Col [col].shared4.degree_next = EMPTY ;
3298  Col [col].shared3.prev = EMPTY ;
3299  }
3300  }
3301 
3302 #ifndef NDEBUG
3303  debug_deg_lists (n_row, n_col, Row, Col, head,
3304  min_score, cset_start [current_set+1]-(k+deadcol), max_deg) ;
3305 #endif
3306 
3307  /* frontal matrix can have more pivot cols than pivot rows for */
3308  /* singular matrices. */
3309 
3310  /* number of candidate pivot columns */
3311  Front_npivcol [nfr] = pivot_col_thickness ;
3312 
3313  /* all rows (not just size of contrib. block) */
3314  Front_nrows [nfr] = pivot_row_thickness ;
3315 
3316  /* all cols */
3317  Front_ncols [nfr] = pivot_col_thickness + pivot_row_degree ;
3318 
3319  Front_parent [nfr] = EMPTY ;
3320 
3321  pivot_row_thickness -= pivot_col_thickness ;
3322  DEBUG1 (("Front "ID" Pivot_row_thickness after pivot cols elim: "ID"\n",
3323  nfr, pivot_row_thickness)) ;
3324  pivot_row_thickness = MAX (0, pivot_row_thickness) ;
3325 
3326  /* === Resurrect the new pivot row ================================== */
3327 
3328  if ((pivot_row_degree > 0 && pivot_row_thickness > 0 && (order_for_lu))
3329  || (pivot_row_degree > 0 && (!order_for_lu)))
3330  {
3331  /* update pivot row length to reflect any cols that were killed */
3332  /* during super-col detection and mass elimination */
3333  Row [pivot_row].start = pivot_row_start ;
3334  Row [pivot_row].length = (Int) (new_rp - &A[pivot_row_start]) ;
3335  Row [pivot_row].shared1.degree = pivot_row_degree ;
3336  Row [pivot_row].shared2.mark = 0 ;
3337  Row [pivot_row].thickness = pivot_row_thickness ;
3338  Row [pivot_row].front = nfr ;
3339  /* pivot row is no longer dead */
3340  DEBUG1 (("Resurrect Pivot_row "ID" deg: "ID"\n",
3341  pivot_row, pivot_row_degree)) ;
3342  }
3343 
3344 #ifndef NDEBUG
3345  DEBUG1 (("Front "ID" : "ID" "ID" "ID" ", nfr,
3346  Front_npivcol [nfr], Front_nrows [nfr], Front_ncols [nfr])) ;
3347  DEBUG1 ((" cols:[ ")) ;
3348  debug_d = 0 ;
3349  for (col = Front_cols [nfr] ; col != EMPTY ; col = Col [col].nextcol)
3350  {
3351  DEBUG1 ((" "ID, col)) ;
3352  ASSERT (col >= 0 && col < n_col) ;
3353  ASSERT (COL_IS_DEAD (col)) ;
3354  debug_d++ ;
3355  ASSERT (debug_d <= pivot_col_thickness) ;
3356  }
3357  ASSERT (debug_d == pivot_col_thickness) ;
3358  DEBUG1 ((" ]\n ")) ;
3359 #endif
3360  nfr++ ; /* one more front */
3361  }
3362 
3363  /* === All principal columns have now been ordered ====================== */
3364 
3365  *p_nfr = nfr ;
3366  return (ngarbage) ;
3367 }
3368 
3369 
3370 /* ========================================================================== */
3371 /* === detect_super_cols ==================================================== */
3372 /* ========================================================================== */
3373 
3374 /*
3375  * Detects supercolumns by finding matches between columns in the hash buckets.
3376  * Check amongst columns in the set A [row_start ... row_start + row_length-1].
3377  * The columns under consideration are currently *not* in the degree lists,
3378  * and have already been placed in the hash buckets.
3379  *
3380  * The hash bucket for columns whose hash function is equal to h is stored
3381  * as follows:
3382  *
3383  * if head [h] is >= 0, then head [h] contains a degree list, so:
3384  *
3385  * head [h] is the first column in degree bucket h.
3386  * Col [head [h]].headhash gives the first column in hash bucket h.
3387  *
3388  * otherwise, the degree list is empty, and:
3389  *
3390  * -(head [h] + 2) is the first column in hash bucket h.
3391  *
3392  * For a column c in a hash bucket, Col [c].shared3.prev is NOT a "previous
3393  * column" pointer. Col [c].shared3.hash is used instead as the hash number
3394  * for that column. The value of Col [c].shared4.hash_next is the next column
3395  * in the same hash bucket.
3396  *
3397  * Assuming no, or "few" hash collisions, the time taken by this routine is
3398  * linear in the sum of the sizes (lengths) of each column whose score has
3399  * just been computed in the approximate degree computation.
3400  * Not user-callable.
3401  */
3402 
3405  /* === Parameters ======================================================= */
3406 
3407 #ifndef NDEBUG
3408  /* these two parameters are only needed when debugging is enabled: */
3409  Int n_col, /* number of columns of A */
3410  CColamd_Row Row [ ], /* of size n_row+1 */
3411 #endif
3412 
3413  CColamd_Col Col [ ], /* of size n_col+1 */
3414  Int A [ ], /* row indices of A */
3415  Int head [ ], /* head of degree lists and hash buckets */
3416  Int row_start, /* pointer to set of columns to check */
3417  Int row_length, /* number of columns to check */
3418  Int cmember [ ] /* col -> cset mapping */
3419 )
3420 {
3421  /* === Local variables ================================================== */
3422 
3423  Int hash ; /* hash value for a column */
3424  Int *rp ; /* pointer to a row */
3425  Int c ; /* a column index */
3426  Int super_c ; /* column index of the column to absorb into */
3427  Int *cp1 ; /* column pointer for column super_c */
3428  Int *cp2 ; /* column pointer for column c */
3429  Int length ; /* length of column super_c */
3430  Int prev_c ; /* column preceding c in hash bucket */
3431  Int i ; /* loop counter */
3432  Int *rp_end ; /* pointer to the end of the row */
3433  Int col ; /* a column index in the row to check */
3434  Int head_column ; /* first column in hash bucket or degree list */
3435  Int first_col ; /* first column in hash bucket */
3436 
3437  /* === Consider each column in the row ================================== */
3438 
3439  rp = &A [row_start] ;
3440  rp_end = rp + row_length ;
3441  while (rp < rp_end)
3442  {
3443  col = *rp++ ;
3444  if (COL_IS_DEAD (col))
3445  {
3446  continue ;
3447  }
3448 
3449  /* get hash number for this column */
3450  hash = Col [col].shared3.hash ;
3451  ASSERT (hash <= n_col) ;
3452 
3453  /* === Get the first column in this hash bucket ===================== */
3454 
3455  head_column = head [hash] ;
3456  if (head_column > EMPTY)
3457  {
3458  first_col = Col [head_column].shared3.headhash ;
3459  }
3460  else
3461  {
3462  first_col = - (head_column + 2) ;
3463  }
3464 
3465  /* === Consider each column in the hash bucket ====================== */
3466 
3467  for (super_c = first_col ; super_c != EMPTY ;
3468  super_c = Col [super_c].shared4.hash_next)
3469  {
3470  ASSERT (COL_IS_ALIVE (super_c)) ;
3471  ASSERT (Col [super_c].shared3.hash == hash) ;
3472  length = Col [super_c].length ;
3473 
3474  /* prev_c is the column preceding column c in the hash bucket */
3475  prev_c = super_c ;
3476 
3477  /* === Compare super_c with all columns after it ================ */
3478 
3479  for (c = Col [super_c].shared4.hash_next ;
3480  c != EMPTY ; c = Col [c].shared4.hash_next)
3481  {
3482  ASSERT (c != super_c) ;
3483  ASSERT (COL_IS_ALIVE (c)) ;
3484  ASSERT (Col [c].shared3.hash == hash) ;
3485 
3486  /* not identical if lengths or scores are different, */
3487  /* or if in different constraint sets */
3488  if (Col [c].length != length ||
3489  Col [c].shared2.score != Col [super_c].shared2.score
3490  || CMEMBER (c) != CMEMBER (super_c))
3491  {
3492  prev_c = c ;
3493  continue ;
3494  }
3495 
3496  /* compare the two columns */
3497  cp1 = &A [Col [super_c].start] ;
3498  cp2 = &A [Col [c].start] ;
3499 
3500  for (i = 0 ; i < length ; i++)
3501  {
3502  /* the columns are "clean" (no dead rows) */
3503  ASSERT (ROW_IS_ALIVE (*cp1)) ;
3504  ASSERT (ROW_IS_ALIVE (*cp2)) ;
3505  /* row indices will same order for both supercols, */
3506  /* no gather scatter nessasary */
3507  if (*cp1++ != *cp2++)
3508  {
3509  break ;
3510  }
3511  }
3512 
3513  /* the two columns are different if the for-loop "broke" */
3514  /* super columns should belong to the same constraint set */
3515  if (i != length)
3516  {
3517  prev_c = c ;
3518  continue ;
3519  }
3520 
3521  /* === Got it! two columns are identical =================== */
3522 
3523  ASSERT (Col [c].shared2.score == Col [super_c].shared2.score) ;
3524 
3525  Col [super_c].shared1.thickness += Col [c].shared1.thickness ;
3526  Col [c].shared1.parent = super_c ;
3528  /* order c later, in order_children() */
3529  Col [c].shared2.order = EMPTY ;
3530  /* remove c from hash bucket */
3531  Col [prev_c].shared4.hash_next = Col [c].shared4.hash_next ;
3532 
3533  /* add c to end of list of super_c */
3534  ASSERT (Col [super_c].lastcol >= 0) ;
3535  ASSERT (Col [super_c].lastcol < n_col) ;
3536  Col [Col [super_c].lastcol].nextcol = c ;
3537  Col [super_c].lastcol = Col [c].lastcol ;
3538 #ifndef NDEBUG
3539  /* dump the supercolumn */
3540  DEBUG1 (("Super")) ;
3541  dump_super (super_c, Col, n_col) ;
3542 #endif
3543  }
3544  }
3545 
3546  /* === Empty this hash bucket ======================================= */
3547 
3548  if (head_column > EMPTY)
3549  {
3550  /* corresponding degree list "hash" is not empty */
3551  Col [head_column].shared3.headhash = EMPTY ;
3552  }
3553  else
3554  {
3555  /* corresponding degree list "hash" is empty */
3556  head [hash] = EMPTY ;
3557  }
3558  }
3559 }
3560 
3561 
3562 /* ========================================================================== */
3563 /* === garbage_collection =================================================== */
3564 /* ========================================================================== */
3565 
3566 /*
3567  * Defragments and compacts columns and rows in the workspace A. Used when
3568  * all avaliable memory has been used while performing row merging. Returns
3569  * the index of the first free position in A, after garbage collection. The
3570  * time taken by this routine is linear is the size of the array A, which is
3571  * itself linear in the number of nonzeros in the input matrix.
3572  * Not user-callable.
3573  */
3574 
3575 PRIVATE Int garbage_collection /* returns the new value of pfree */
3577  /* === Parameters ======================================================= */
3578 
3579  Int n_row, /* number of rows */
3580  Int n_col, /* number of columns */
3581  CColamd_Row Row [ ], /* row info */
3582  CColamd_Col Col [ ], /* column info */
3583  Int A [ ], /* A [0 ... Alen-1] holds the matrix */
3584  Int *pfree /* &A [0] ... pfree is in use */
3585 )
3586 {
3587  /* === Local variables ================================================== */
3588 
3589  Int *psrc ; /* source pointer */
3590  Int *pdest ; /* destination pointer */
3591  Int j ; /* counter */
3592  Int r ; /* a row index */
3593  Int c ; /* a column index */
3594  Int length ; /* length of a row or column */
3595 
3596 #ifndef NDEBUG
3597  Int debug_rows ;
3598  DEBUG2 (("Defrag..\n")) ;
3599  for (psrc = &A[0] ; psrc < pfree ; psrc++) ASSERT (*psrc >= 0) ;
3600  debug_rows = 0 ;
3601 #endif
3602 
3603  /* === Defragment the columns =========================================== */
3604 
3605  pdest = &A[0] ;
3606  for (c = 0 ; c < n_col ; c++)
3607  {
3608  if (COL_IS_ALIVE (c))
3609  {
3610  psrc = &A [Col [c].start] ;
3611 
3612  /* move and compact the column */
3613  ASSERT (pdest <= psrc) ;
3614  Col [c].start = (Int) (pdest - &A [0]) ;
3615  length = Col [c].length ;
3616  for (j = 0 ; j < length ; j++)
3617  {
3618  r = *psrc++ ;
3619  if (ROW_IS_ALIVE (r))
3620  {
3621  *pdest++ = r ;
3622  }
3623  }
3624  Col [c].length = (Int) (pdest - &A [Col [c].start]) ;
3625  }
3626  }
3627 
3628  /* === Prepare to defragment the rows =================================== */
3629 
3630  for (r = 0 ; r < n_row ; r++)
3631  {
3632  if (ROW_IS_DEAD (r) || (Row [r].length == 0))
3633  {
3634  /* This row is already dead, or is of zero length. Cannot compact
3635  * a row of zero length, so kill it. NOTE: in the current version,
3636  * there are no zero-length live rows. Kill the row (for the first
3637  * time, or again) just to be safe. */
3638  KILL_ROW (r) ;
3639  }
3640  else
3641  {
3642  /* save first column index in Row [r].shared2.first_column */
3643  psrc = &A [Row [r].start] ;
3644  Row [r].shared2.first_column = *psrc ;
3645  ASSERT (ROW_IS_ALIVE (r)) ;
3646  /* flag the start of the row with the one's complement of row */
3647  *psrc = ONES_COMPLEMENT (r) ;
3648 #ifndef NDEBUG
3649  debug_rows++ ;
3650 #endif
3651  }
3652  }
3653 
3654  /* === Defragment the rows ============================================== */
3655 
3656  psrc = pdest ;
3657  while (psrc < pfree)
3658  {
3659  /* find a negative number ... the start of a row */
3660  if (*psrc++ < 0)
3661  {
3662  psrc-- ;
3663  /* get the row index */
3664  r = ONES_COMPLEMENT (*psrc) ;
3665  ASSERT (r >= 0 && r < n_row) ;
3666  /* restore first column index */
3667  *psrc = Row [r].shared2.first_column ;
3668  ASSERT (ROW_IS_ALIVE (r)) ;
3669 
3670  /* move and compact the row */
3671  ASSERT (pdest <= psrc) ;
3672  Row [r].start = (Int) (pdest - &A [0]) ;
3673  length = Row [r].length ;
3674  for (j = 0 ; j < length ; j++)
3675  {
3676  c = *psrc++ ;
3677  if (COL_IS_ALIVE (c))
3678  {
3679  *pdest++ = c ;
3680  }
3681  }
3682  Row [r].length = (Int) (pdest - &A [Row [r].start]) ;
3683 #ifndef NDEBUG
3684  debug_rows-- ;
3685 #endif
3686  }
3687  }
3688 
3689  /* ensure we found all the rows */
3690  ASSERT (debug_rows == 0) ;
3691 
3692  /* === Return the new value of pfree ==================================== */
3693 
3694  return ((Int) (pdest - &A [0])) ;
3695 }
3696 
3697 
3698 /* ========================================================================== */
3699 /* === clear_mark =========================================================== */
3700 /* ========================================================================== */
3701 
3702 /*
3703  * Clears the Row [ ].shared2.mark array, and returns the new tag_mark.
3704  * Return value is the new tag_mark. Not user-callable.
3705  */
3706 
3707 PRIVATE Int clear_mark /* return the new value for tag_mark */
3709  /* === Parameters ======================================================= */
3710 
3711  Int tag_mark, /* new value of tag_mark */
3712  Int max_mark, /* max allowed value of tag_mark */
3713 
3714  Int n_row, /* number of rows in A */
3715  CColamd_Row Row [ ] /* Row [0 ... n_row-1].shared2.mark is set to zero */
3716 )
3717 {
3718  /* === Local variables ================================================== */
3719 
3720  Int r ;
3721 
3722  if (tag_mark <= 0 || tag_mark >= max_mark)
3723  {
3724  for (r = 0 ; r < n_row ; r++)
3725  {
3726  if (ROW_IS_ALIVE (r))
3727  {
3728  Row [r].shared2.mark = 0 ;
3729  }
3730  }
3731  tag_mark = 1 ;
3732  }
3733 
3734  return (tag_mark) ;
3735 }
3736 
3737 
3738 /* ========================================================================== */
3739 /* === print_report ========================================================= */
3740 /* ========================================================================== */
3741 
3742 /* No printing occurs if NPRINT is defined at compile time. */
3743 
3744 PRIVATE void print_report
3746  char *method,
3747  Int stats [CCOLAMD_STATS]
3748 )
3749 {
3750 
3751  Int i1, i2, i3 ;
3752 
3753  PRINTF (("\n%s version %d.%d, %s: ", method,
3755 
3756  if (!stats)
3757  {
3758  PRINTF (("No statistics available.\n")) ;
3759  return ;
3760  }
3761 
3762  i1 = stats [CCOLAMD_INFO1] ;
3763  i2 = stats [CCOLAMD_INFO2] ;
3764  i3 = stats [CCOLAMD_INFO3] ;
3765 
3766  if (stats [CCOLAMD_STATUS] >= 0)
3767  {
3768  PRINTF(("OK. ")) ;
3769  }
3770  else
3771  {
3772  PRINTF(("ERROR. ")) ;
3773  }
3774 
3775  switch (stats [CCOLAMD_STATUS])
3776  {
3777 
3779 
3780  PRINTF(("Matrix has unsorted or duplicate row indices.\n")) ;
3781 
3782  PRINTF(("%s: duplicate or out-of-order row indices: "ID"\n",
3783  method, i3)) ;
3784 
3785  PRINTF(("%s: last seen duplicate or out-of-order row: "ID"\n",
3786  method, INDEX (i2))) ;
3787 
3788  PRINTF(("%s: last seen in column: "ID"",
3789  method, INDEX (i1))) ;
3790 
3791  /* no break - fall through to next case instead */
3792 
3793  case CCOLAMD_OK:
3794 
3795  PRINTF(("\n")) ;
3796 
3797  PRINTF(("%s: number of dense or empty rows ignored: "ID"\n",
3798  method, stats [CCOLAMD_DENSE_ROW])) ;
3799 
3800  PRINTF(("%s: number of dense or empty columns ignored: "ID"\n",
3801  method, stats [CCOLAMD_DENSE_COL])) ;
3802 
3803  PRINTF(("%s: number of garbage collections performed: "ID"\n",
3804  method, stats [CCOLAMD_DEFRAG_COUNT])) ;
3805  break ;
3806 
3808 
3809  PRINTF(("Array A (row indices of matrix) not present.\n")) ;
3810  break ;
3811 
3813 
3814  PRINTF(("Array p (column pointers for matrix) not present.\n")) ;
3815  break ;
3816 
3818 
3819  PRINTF(("Invalid number of rows ("ID").\n", i1)) ;
3820  break ;
3821 
3823 
3824  PRINTF(("Invalid number of columns ("ID").\n", i1)) ;
3825  break ;
3826 
3828 
3829  PRINTF(("Invalid number of nonzero entries ("ID").\n", i1)) ;
3830  break ;
3831 
3833 
3834  PRINTF(("Invalid column pointer, p [0] = "ID", must be 0.\n", i1)) ;
3835  break ;
3836 
3838 
3839  PRINTF(("Array A too small.\n")) ;
3840  PRINTF((" Need Alen >= "ID", but given only Alen = "ID".\n",
3841  i1, i2)) ;
3842  break ;
3843 
3845 
3846  PRINTF(("Column "ID" has a negative number of entries ("ID").\n",
3847  INDEX (i1), i2)) ;
3848  break ;
3849 
3851 
3852  PRINTF(("Row index (row "ID") out of bounds ("ID" to "ID") in"
3853  "column "ID".\n", INDEX (i2), INDEX (0), INDEX (i3-1),
3854  INDEX (i1))) ;
3855  break ;
3856 
3858 
3859  PRINTF(("Out of memory.\n")) ;
3860  break ;
3861 
3863 
3864  PRINTF(("cmember invalid\n")) ;
3865  break ;
3866  }
3867 }
3868 
3869 
3870 /* ========================================================================= */
3871 /* === "Expert" routines =================================================== */
3872 /* ========================================================================= */
3873 
3874 /* The following routines are visible outside this routine, but are not meant
3875  * to be called by the user. They are meant for a future version of UMFPACK,
3876  * to replace UMFPACK internal routines with a similar name.
3877  */
3878 
3879 
3880 /* ========================================================================== */
3881 /* === CCOLAMD_apply_order ================================================== */
3882 /* ========================================================================== */
3883 
3884 /*
3885  * Apply post-ordering of supernodal elimination tree.
3886  */
3887 
3890  Int Front [ ], /* of size nn on input, size nfr on output */
3891  const Int Order [ ], /* Order [i] = k, i in the range 0..nn-1,
3892  * and k in the range 0..nfr-1, means that node
3893  * i is the kth node in the postordered tree. */
3894  Int Temp [ ], /* workspace of size nfr */
3895  Int nn, /* nodes are numbered in the range 0..nn-1 */
3896  Int nfr /* the number of nodes actually in use */
3897 )
3898 {
3899  Int i, k ;
3900  for (i = 0 ; i < nn ; i++)
3901  {
3902  k = Order [i] ;
3903  ASSERT (k >= EMPTY && k < nfr) ;
3904  if (k != EMPTY)
3905  {
3906  Temp [k] = Front [i] ;
3907  }
3908  }
3909 
3910  for (k = 0 ; k < nfr ; k++)
3911  {
3912  Front [k] = Temp [k] ;
3913  }
3914 }
3915 
3916 
3917 /* ========================================================================== */
3918 /* === CCOLAMD_fsize ======================================================== */
3919 /* ========================================================================== */
3920 
3921 /* Determine the largest frontal matrix size for each subtree.
3922  * Only required to sort the children of each
3923  * node prior to postordering the column elimination tree. */
3924 
3925 GLOBAL void CCOLAMD_fsize
3927  Int nn,
3928  Int Fsize [ ],
3929  Int Fnrows [ ],
3930  Int Fncols [ ],
3931  Int Parent [ ],
3932  Int Npiv [ ]
3933 )
3934 {
3935  double dr, dc ;
3936  Int j, parent, frsize, r, c ;
3937 
3938  for (j = 0 ; j < nn ; j++)
3939  {
3940  Fsize [j] = EMPTY ;
3941  }
3942 
3943  /* ---------------------------------------------------------------------- */
3944  /* find max front size for tree rooted at node j, for each front j */
3945  /* ---------------------------------------------------------------------- */
3946 
3947  DEBUG1 (("\n\n========================================FRONTS:\n")) ;
3948  for (j = 0 ; j < nn ; j++)
3949  {
3950  if (Npiv [j] > 0)
3951  {
3952  /* this is a frontal matrix */
3953  parent = Parent [j] ;
3954  r = Fnrows [j] ;
3955  c = Fncols [j] ;
3956  /* avoid integer overflow */
3957  dr = (double) r ;
3958  dc = (double) c ;
3959  frsize = (INT_OVERFLOW (dr * dc)) ? Int_MAX : (r * c) ;
3960  DEBUG1 ((""ID" : npiv "ID" size "ID" parent "ID" ",
3961  j, Npiv [j], frsize, parent)) ;
3962  Fsize [j] = MAX (Fsize [j], frsize) ;
3963  DEBUG1 (("Fsize [j = "ID"] = "ID"\n", j, Fsize [j])) ;
3964  if (parent != EMPTY)
3965  {
3966  /* find the maximum frontsize of self and children */
3967  ASSERT (Npiv [parent] > 0) ;
3968  ASSERT (parent > j) ;
3969  Fsize [parent] = MAX (Fsize [parent], Fsize [j]) ;
3970  DEBUG1 (("Fsize [parent = "ID"] = "ID"\n",
3971  parent, Fsize [parent]));
3972  }
3973  }
3974  }
3975  DEBUG1 (("fsize done\n")) ;
3976 }
3977 
3978 
3979 /* ========================================================================= */
3980 /* === CCOLAMD_postorder =================================================== */
3981 /* ========================================================================= */
3982 
3983 /* Perform a postordering (via depth-first search) of an assembly tree. */
3984 
3987  /* inputs, not modified on output: */
3988  Int nn, /* nodes are in the range 0..nn-1 */
3989  Int Parent [ ], /* Parent [j] is the parent of j, or EMPTY if root */
3990  Int Nv [ ], /* Nv [j] > 0 number of pivots represented by node j,
3991  * or zero if j is not a node. */
3992  Int Fsize [ ], /* Fsize [j]: size of node j */
3993 
3994  /* output, not defined on input: */
3995  Int Order [ ], /* output post-order */
3996 
3997  /* workspaces of size nn: */
3998  Int Child [ ],
3999  Int Sibling [ ],
4000  Int Stack [ ],
4001  Int Front_cols [ ],
4002 
4003  /* input, not modified on output: */
4004  Int cmember [ ]
4005 )
4006 {
4007  Int i, j, k, parent, frsize, f, fprev, maxfrsize, bigfprev, bigf, fnext ;
4008 
4009  for (j = 0 ; j < nn ; j++)
4010  {
4011  Child [j] = EMPTY ;
4012  Sibling [j] = EMPTY ;
4013  }
4014 
4015  /* --------------------------------------------------------------------- */
4016  /* place the children in link lists - bigger elements tend to be last */
4017  /* --------------------------------------------------------------------- */
4018 
4019  for (j = nn-1 ; j >= 0 ; j--)
4020  {
4021  if (Nv [j] > 0)
4022  {
4023  /* this is an element */
4024  parent = Parent [j] ;
4025  if (parent != EMPTY)
4026  {
4027  /* place the element in link list of the children its parent */
4028  /* bigger elements will tend to be at the end of the list */
4029  Sibling [j] = Child [parent] ;
4030  if (CMEMBER (Front_cols[parent]) == CMEMBER (Front_cols[j]))
4031  {
4032  Child [parent] = j ;
4033  }
4034  }
4035  }
4036  }
4037 
4038 #ifndef NDEBUG
4039  {
4040  Int nels, ff, nchild ;
4041  DEBUG1 (("\n\n================================ ccolamd_postorder:\n"));
4042  nels = 0 ;
4043  for (j = 0 ; j < nn ; j++)
4044  {
4045  if (Nv [j] > 0)
4046  {
4047  DEBUG1 ((""ID" : nels "ID" npiv "ID" size "ID
4048  " parent "ID" maxfr "ID"\n", j, nels,
4049  Nv [j], Fsize [j], Parent [j], Fsize [j])) ;
4050  /* this is an element */
4051  /* dump the link list of children */
4052  nchild = 0 ;
4053  DEBUG1 ((" Children: ")) ;
4054  for (ff = Child [j] ; ff != EMPTY ; ff = Sibling [ff])
4055  {
4056  DEBUG1 ((ID" ", ff)) ;
4057  nchild++ ;
4058  ASSERT (nchild < nn) ;
4059  }
4060  DEBUG1 (("\n")) ;
4061  parent = Parent [j] ;
4062  nels++ ;
4063  }
4064  }
4065  }
4066 #endif
4067 
4068  /* --------------------------------------------------------------------- */
4069  /* place the largest child last in the list of children for each node */
4070  /* --------------------------------------------------------------------- */
4071 
4072  for (i = 0 ; i < nn ; i++)
4073  {
4074  if (Nv [i] > 0 && Child [i] != EMPTY)
4075  {
4076 
4077 #ifndef NDEBUG
4078  Int nchild ;
4079  DEBUG1 (("Before partial sort, element "ID"\n", i)) ;
4080  nchild = 0 ;
4081  for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
4082  {
4083  DEBUG1 ((" f: "ID" size: "ID"\n", f, Fsize [f])) ;
4084  nchild++ ;
4085  }
4086 #endif
4087 
4088  /* find the biggest element in the child list */
4089  fprev = EMPTY ;
4090  maxfrsize = EMPTY ;
4091  bigfprev = EMPTY ;
4092  bigf = EMPTY ;
4093  for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
4094  {
4095  frsize = Fsize [f] ;
4096  if (frsize >= maxfrsize)
4097  {
4098  /* this is the biggest seen so far */
4099  maxfrsize = frsize ;
4100  bigfprev = fprev ;
4101  bigf = f ;
4102  }
4103  fprev = f ;
4104  }
4105 
4106  fnext = Sibling [bigf] ;
4107 
4108  DEBUG1 (("bigf "ID" maxfrsize "ID" bigfprev "ID" fnext "ID
4109  " fprev " ID"\n", bigf, maxfrsize, bigfprev, fnext, fprev)) ;
4110 
4111  if (fnext != EMPTY)
4112  {
4113  /* if fnext is EMPTY then bigf is already at the end of list */
4114 
4115  if (bigfprev == EMPTY)
4116  {
4117  /* delete bigf from the element of the list */
4118  Child [i] = fnext ;
4119  }
4120  else
4121  {
4122  /* delete bigf from the middle of the list */
4123  Sibling [bigfprev] = fnext ;
4124  }
4125 
4126  /* put bigf at the end of the list */
4127  Sibling [bigf] = EMPTY ;
4128  Sibling [fprev] = bigf ;
4129  }
4130 
4131 #ifndef NDEBUG
4132  DEBUG1 (("After partial sort, element "ID"\n", i)) ;
4133  for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
4134  {
4135  DEBUG1 ((" "ID" "ID"\n", f, Fsize [f])) ;
4136  nchild-- ;
4137  }
4138 #endif
4139  }
4140  }
4141 
4142  /* --------------------------------------------------------------------- */
4143  /* postorder the assembly tree */
4144  /* --------------------------------------------------------------------- */
4145 
4146  for (i = 0 ; i < nn ; i++)
4147  {
4148  Order [i] = EMPTY ;
4149  }
4150 
4151  k = 0 ;
4152 
4153  for (i = 0 ; i < nn ; i++)
4154  {
4155  if ((Parent [i] == EMPTY
4156  || (CMEMBER (Front_cols [Parent [i]]) != CMEMBER (Front_cols [i])))
4157  && Nv [i] > 0)
4158  {
4159  DEBUG1 (("Root of assembly tree "ID"\n", i)) ;
4160  k = CCOLAMD_post_tree (i, k, Child, Sibling, Order, Stack) ;
4161  }
4162  }
4163 }
4164 
4165 
4166 /* ========================================================================= */
4167 /* === CCOLAMD_post_tree =================================================== */
4168 /* ========================================================================= */
4169 
4170 /* Post-ordering of a supernodal column elimination tree. */
4171 
4174  Int root, /* root of the tree */
4175  Int k, /* start numbering at k */
4176  Int Child [ ], /* input argument of size nn, undefined on
4177  * output. Child [i] is the head of a link
4178  * list of all nodes that are children of node
4179  * i in the tree. */
4180  const Int Sibling [ ], /* input argument of size nn, not modified.
4181  * If f is a node in the link list of the
4182  * children of node i, then Sibling [f] is the
4183  * next child of node i.
4184  */
4185  Int Order [ ], /* output order, of size nn. Order [i] = k
4186  * if node i is the kth node of the reordered
4187  * tree. */
4188  Int Stack [ ] /* workspace of size nn */
4189 )
4190 {
4191  Int f, head, h, i ;
4192 
4193 #if 0
4194  /* --------------------------------------------------------------------- */
4195  /* recursive version (Stack [ ] is not used): */
4196  /* --------------------------------------------------------------------- */
4197 
4198  /* this is simple, but can cause stack overflow if nn is large */
4199  i = root ;
4200  for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
4201  {
4202  k = CCOLAMD_post_tree (f, k, Child, Sibling, Order, Stack, nn) ;
4203  }
4204  Order [i] = k++ ;
4205  return (k) ;
4206 #endif
4207 
4208  /* --------------------------------------------------------------------- */
4209  /* non-recursive version, using an explicit stack */
4210  /* --------------------------------------------------------------------- */
4211 
4212  /* push root on the stack */
4213  head = 0 ;
4214  Stack [0] = root ;
4215 
4216  while (head >= 0)
4217  {
4218  /* get head of stack */
4219  i = Stack [head] ;
4220  DEBUG1 (("head of stack "ID" \n", i)) ;
4221 
4222  if (Child [i] != EMPTY)
4223  {
4224  /* the children of i are not yet ordered */
4225  /* push each child onto the stack in reverse order */
4226  /* so that small ones at the head of the list get popped first */
4227  /* and the biggest one at the end of the list gets popped last */
4228  for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
4229  {
4230  head++ ;
4231  }
4232  h = head ;
4233  for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
4234  {
4235  ASSERT (h > 0) ;
4236  Stack [h--] = f ;
4237  DEBUG1 (("push "ID" on stack\n", f)) ;
4238  }
4239  ASSERT (Stack [h] == i) ;
4240 
4241  /* delete child list so that i gets ordered next time we see it */
4242  Child [i] = EMPTY ;
4243  }
4244  else
4245  {
4246  /* the children of i (if there were any) are already ordered */
4247  /* remove i from the stack and order it. Front i is kth front */
4248  head-- ;
4249  DEBUG1 (("pop "ID" order "ID"\n", i, k)) ;
4250  Order [i] = k++ ;
4251  }
4252 
4253 #ifndef NDEBUG
4254  DEBUG1 (("\nStack:")) ;
4255  for (h = head ; h >= 0 ; h--)
4256  {
4257  Int j = Stack [h] ;
4258  DEBUG1 ((" "ID, j)) ;
4259  }
4260  DEBUG1 (("\n\n")) ;
4261 #endif
4262 
4263  }
4264  return (k) ;
4265 }
4266 
4267 
4268 
4269 /* ========================================================================== */
4270 /* === CCOLAMD debugging routines =========================================== */
4271 /* ========================================================================== */
4272 
4273 /* When debugging is disabled, the remainder of this file is ignored. */
4274 
4275 #ifndef NDEBUG
4276 
4277 
4278 /* ========================================================================== */
4279 /* === debug_structures ===================================================== */
4280 /* ========================================================================== */
4281 
4282 /*
4283  * At this point, all empty rows and columns are dead. All live columns
4284  * are "clean" (containing no dead rows) and simplicial (no supercolumns
4285  * yet). Rows may contain dead columns, but all live rows contain at
4286  * least one live column.
4287  */
4288 
4289 PRIVATE void debug_structures
4290 (
4291  /* === Parameters ======================================================= */
4292 
4293  Int n_row,
4294  Int n_col,
4295  CColamd_Row Row [ ],
4296  CColamd_Col Col [ ],
4297  Int A [ ],
4298  Int cmember [ ],
4299  Int cset_start [ ]
4300 )
4301 {
4302  /* === Local variables ================================================== */
4303 
4304  Int i ;
4305  Int c ;
4306  Int *cp ;
4307  Int *cp_end ;
4308  Int len ;
4309  Int score ;
4310  Int r ;
4311  Int *rp ;
4312  Int *rp_end ;
4313  Int deg ;
4314  Int cs ;
4315 
4316  /* === Check A, Row, and Col ============================================ */
4317 
4318  for (c = 0 ; c < n_col ; c++)
4319  {
4320  if (COL_IS_ALIVE (c))
4321  {
4322  len = Col [c].length ;
4323  score = Col [c].shared2.score ;
4324  DEBUG4 (("initial live col %5d %5d %5d\n", c, len, score)) ;
4325  ASSERT (len > 0) ;
4326  ASSERT (score >= 0) ;
4327  ASSERT (Col [c].shared1.thickness == 1) ;
4328  cp = &A [Col [c].start] ;
4329  cp_end = cp + len ;
4330  while (cp < cp_end)
4331  {
4332  r = *cp++ ;
4333  ASSERT (ROW_IS_ALIVE (r)) ;
4334  }
4335  }
4336  else
4337  {
4338  i = Col [c].shared2.order ;
4339  cs = CMEMBER (c) ;
4340  ASSERT (i >= cset_start [cs] && i < cset_start [cs+1]) ;
4341  }
4342  }
4343 
4344  for (r = 0 ; r < n_row ; r++)
4345  {
4346  if (ROW_IS_ALIVE (r))
4347  {
4348  i = 0 ;
4349  len = Row [r].length ;
4350  deg = Row [r].shared1.degree ;
4351  ASSERT (len > 0) ;
4352  ASSERT (deg > 0) ;
4353  rp = &A [Row [r].start] ;
4354  rp_end = rp + len ;
4355  while (rp < rp_end)
4356  {
4357  c = *rp++ ;
4358  if (COL_IS_ALIVE (c))
4359  {
4360  i++ ;
4361  }
4362  }
4363  ASSERT (i > 0) ;
4364  }
4365  }
4366 }
4367 
4368 
4369 /* ========================================================================== */
4370 /* === debug_deg_lists ====================================================== */
4371 /* ========================================================================== */
4372 
4373 /*
4374  * Prints the contents of the degree lists. Counts the number of columns
4375  * in the degree list and compares it to the total it should have. Also
4376  * checks the row degrees.
4377  */
4378 
4379 PRIVATE void debug_deg_lists
4380 (
4381  /* === Parameters ======================================================= */
4382 
4383  Int n_row,
4384  Int n_col,
4385  CColamd_Row Row [ ],
4386  CColamd_Col Col [ ],
4387  Int head [ ],
4388  Int min_score,
4389  Int should,
4390  Int max_deg
4391 )
4392 
4393 {
4394  /* === Local variables ================================================== */
4395 
4396  Int deg ;
4397  Int col ;
4398  Int have ;
4399  Int row ;
4400 
4401  /* === Check the degree lists =========================================== */
4402 
4403  if (n_col > 10000 && ccolamd_debug <= 0)
4404  {
4405  return ;
4406  }
4407  have = 0 ;
4408  DEBUG4 (("Degree lists: "ID"\n", min_score)) ;
4409  for (deg = 0 ; deg <= n_col ; deg++)
4410  {
4411  col = head [deg] ;
4412  if (col == EMPTY)
4413  {
4414  continue ;
4415  }
4416  DEBUG4 (("%d:", deg)) ;
4417  ASSERT (Col [col].shared3.prev == EMPTY) ;
4418  while (col != EMPTY)
4419  {
4420  DEBUG4 ((" "ID"", col)) ;
4421  have += Col [col].shared1.thickness ;
4422  ASSERT (COL_IS_ALIVE (col)) ;
4423  col = Col [col].shared4.degree_next ;
4424  }
4425  DEBUG4 (("\n")) ;
4426  }
4427  DEBUG4 (("should "ID" have "ID"\n", should, have)) ;
4428  ASSERT (should == have) ;
4429 
4430  /* === Check the row degrees ============================================ */
4431 
4432  if (n_row > 10000 && ccolamd_debug <= 0)
4433  {
4434  return ;
4435  }
4436  for (row = 0 ; row < n_row ; row++)
4437  {
4438  if (ROW_IS_ALIVE (row))
4439  {
4440  ASSERT (Row [row].shared1.degree <= max_deg) ;
4441  }
4442  }
4443 }
4444 
4445 
4446 /* ========================================================================== */
4447 /* === debug_mark =========================================================== */
4448 /* ========================================================================== */
4449 
4450 /*
4451  * Ensures that the tag_mark is less that the maximum and also ensures that
4452  * each entry in the mark array is less than the tag mark.
4453  */
4454 
4455 PRIVATE void debug_mark
4456 (
4457  /* === Parameters ======================================================= */
4458 
4459  Int n_row,
4460  CColamd_Row Row [ ],
4461  Int tag_mark,
4462  Int max_mark
4463 )
4464 {
4465  /* === Local variables ================================================== */
4466 
4467  Int r ;
4468 
4469  /* === Check the Row marks ============================================== */
4470 
4471  ASSERT (tag_mark > 0 && tag_mark <= max_mark) ;
4472  if (n_row > 10000 && ccolamd_debug <= 0)
4473  {
4474  return ;
4475  }
4476  for (r = 0 ; r < n_row ; r++)
4477  {
4478  ASSERT (Row [r].shared2.mark < tag_mark) ;
4479  }
4480 }
4481 
4482 
4483 /* ========================================================================== */
4484 /* === debug_matrix ========================================================= */
4485 /* ========================================================================== */
4486 
4487 /* Prints out the contents of the columns and the rows. */
4488 
4489 PRIVATE void debug_matrix
4490 (
4491  /* === Parameters ======================================================= */
4492 
4493  Int n_row,
4494  Int n_col,
4495  CColamd_Row Row [ ],
4496  CColamd_Col Col [ ],
4497  Int A [ ]
4498 )
4499 {
4500  /* === Local variables ================================================== */
4501 
4502  Int r ;
4503  Int c ;
4504  Int *rp ;
4505  Int *rp_end ;
4506  Int *cp ;
4507  Int *cp_end ;
4508 
4509  /* === Dump the rows and columns of the matrix ========================== */
4510 
4511  if (ccolamd_debug < 3)
4512  {
4513  return ;
4514  }
4515  DEBUG3 (("DUMP MATRIX:\n")) ;
4516  for (r = 0 ; r < n_row ; r++)
4517  {
4518  DEBUG3 (("Row "ID" alive? "ID"\n", r, ROW_IS_ALIVE (r))) ;
4519  if (ROW_IS_DEAD (r))
4520  {
4521  continue ;
4522  }
4523 
4524  DEBUG3 (("start "ID" length "ID" degree "ID"\nthickness "ID"\n",
4525  Row [r].start, Row [r].length, Row [r].shared1.degree,
4526  Row [r].thickness)) ;
4527 
4528  rp = &A [Row [r].start] ;
4529  rp_end = rp + Row [r].length ;
4530  while (rp < rp_end)
4531  {
4532  c = *rp++ ;
4533  DEBUG4 ((" "ID" col "ID"\n", COL_IS_ALIVE (c), c)) ;
4534  }
4535  }
4536 
4537  for (c = 0 ; c < n_col ; c++)
4538  {
4539  DEBUG3 (("Col "ID" alive? "ID"\n", c, COL_IS_ALIVE (c))) ;
4540  if (COL_IS_DEAD (c))
4541  {
4542  continue ;
4543  }
4544  DEBUG3 (("start "ID" length "ID" shared1 "ID" shared2 "ID"\n",
4545  Col [c].start, Col [c].length,
4546  Col [c].shared1.thickness, Col [c].shared2.score)) ;
4547  cp = &A [Col [c].start] ;
4548  cp_end = cp + Col [c].length ;
4549  while (cp < cp_end)
4550  {
4551  r = *cp++ ;
4552  DEBUG4 ((" "ID" row "ID"\n", ROW_IS_ALIVE (r), r)) ;
4553  }
4554  }
4555 }
4556 
4557 
4558 /* ========================================================================== */
4559 /* === dump_super =========================================================== */
4560 /* ========================================================================== */
4561 
4562 PRIVATE void dump_super
4563 (
4564  Int super_c,
4565  CColamd_Col Col [ ],
4566  Int n_col
4567 )
4568 {
4569  Int col, ncols ;
4570 
4571  DEBUG1 ((" =[ ")) ;
4572  ncols = 0 ;
4573  for (col = super_c ; col != EMPTY ; col = Col [col].nextcol)
4574  {
4575  DEBUG1 ((" "ID, col)) ;
4576  ASSERT (col >= 0 && col < n_col) ;
4577  if (col != super_c)
4578  {
4579  ASSERT (COL_IS_DEAD (col)) ;
4580  }
4581  if (Col [col].nextcol == EMPTY)
4582  {
4583  ASSERT (col == Col [super_c].lastcol) ;
4584  }
4585  ncols++ ;
4586  ASSERT (ncols <= Col [super_c].shared1.thickness) ;
4587  }
4588  ASSERT (ncols == Col [super_c].shared1.thickness) ;
4589  DEBUG1 (("]\n")) ;
4590 }
4591 
4592 
4593 /* ========================================================================== */
4594 /* === ccolamd_get_debug ==================================================== */
4595 /* ========================================================================== */
4596 
4597 PRIVATE void ccolamd_get_debug
4598 (
4599  char *method
4600 )
4601 {
4602  FILE *debug_file ;
4603  ccolamd_debug = 0 ; /* no debug printing */
4604 
4605  /* Read debug info from the debug file. */
4606  debug_file = fopen ("debug", "r") ;
4607  if (debug_file)
4608  {
4609  (void) fscanf (debug_file, ""ID"", &ccolamd_debug) ;
4610  (void) fclose (debug_file) ;
4611  }
4612 
4613  DEBUG0 ((":")) ;
4614  DEBUG1 (("%s: debug version, D = "ID" (THIS WILL BE SLOW!)\n",
4615  method, ccolamd_debug)) ;
4616  DEBUG1 ((" Debug printing level: "ID"\n", ccolamd_debug)) ;
4617 }
4618 
4619 #endif
#define CCOLAMD_INFO2
#define CCOLAMD_STATUS
static size_t ccolamd_need(Int nnz, Int n_row, Int n_col, int *ok)
union CColamd_Col_struct::@0 shared1
void f()
#define CCOLAMD_recommended
#define CCOLAMD_apply_order
#define CCOLAMD_ERROR_ncol_negative
#define CCOLAMD_fsize
UF_long CHOLMOD() nnz(cholmod_sparse *A, cholmod_common *Common)
#define CCOLAMD_ERROR_p_not_present
#define NDEBUG
PRIVATE Int garbage_collection(Int n_row, Int n_col, CColamd_Row Row[], CColamd_Col Col[], Int A[], Int *pfree)
#define CCOLAMD_DEFRAG_COUNT
#define CCOLAMD_NEWLY_EMPTY_ROW
#define CCOLAMD_OK_BUT_JUMBLED
#define DEBUG3(params)
#define CCOLAMD_AGGRESSIVE
PRIVATE Int clear_mark(Int tag_mark, Int max_mark, Int n_row, CColamd_Row Row[])
#define Int
#define CCOLAMD_ERROR_nnz_negative
union CColamd_Row_struct::@5 shared2
static size_t t_add(size_t a, size_t b, int *ok)
#define COL_IS_ALIVE(c)
static size_t t_mult(size_t a, size_t k, int *ok)
PRIVATE void init_scoring(Int n_row, Int n_col, CColamd_Row Row[], CColamd_Col Col[], Int A[], Int head[], double knobs[CCOLAMD_KNOBS], Int *p_n_row2, Int *p_n_col2, Int *p_max_deg, Int cmember[], Int n_cset, Int cset_start[], Int dead_cols[], Int *p_ndense_row, Int *p_nempty_row, Int *p_nnewlyempty_row, Int *p_ndense_col, Int *p_nempty_col, Int *p_nnewlyempty_col)
#define CCOLAMD_DATE
#define KILL_NON_PRINCIPAL_COL(c)
#define CCOLAMD_OK
#define CCOLAMD_ERROR_invalid_cmember
#define CCOLAMD_ERROR_nrow_negative
#define PUBLIC
#define ONES_COMPLEMENT(r)
#define CCOLAMD_NEWLY_EMPTY_COL
union CColamd_Col_struct::@3 shared4
#define CCOLAMD_EMPTY_COL
#define CCOLAMD_postorder
PRIVATE Int init_rows_cols(Int n_row, Int n_col, CColamd_Row Row[], CColamd_Col Col[], Int A[], Int p[], Int stats[CCOLAMD_STATS])
#define DEBUG1(params)
#define PRINTF(params)
union CColamd_Col_struct::@1 shared2
#define CCOLAMD_ERROR_A_not_present
#define CCOLAMD_MAIN
#define CCOLAMD_ERROR_col_length_negative
#define CCOLAMD_MAIN_VERSION
#define CCOLAMD_KNOBS
#define CCOLAMD_post_tree
#define CCOLAMD_INFO3
#define DENSE_DEGREE(alpha, n)
int CHOLMOD() start(cholmod_common *Common)
#define DEBUG2(params)
#define CCOLAMD_2
#define DEBUG4(params)
#define CCOLAMD_R(n_row, ok)
#define TRUE
#define CCOLAMD_DENSE_ROW
PRIVATE void detect_super_cols(CColamd_Col Col[], Int A[], Int head[], Int row_start, Int row_length, Int in_set[])
PRIVATE Int find_ordering(Int n_row, Int n_col, Int Alen, CColamd_Row Row[], CColamd_Col Col[], Int A[], Int head[], Int max_deg, Int pfree, Int cset[], Int cset_start[], Int cmember[], Int Front_npivcol[], Int Front_nrows[], Int Front_ncols[], Int Front_parent[], Int Front_cols[], Int *p_nfr, Int aggressive, Int InFront[], Int order_for_lu)
#define CCOLAMD_INFO1
#define EMPTY
#define CCOLAMD_set_defaults
#define DEBUG0(params)
#define CCOLAMD_report
#define CCOLAMD_LU
#define INT_OVERFLOW(x)
void CHOLMOD() dump_super(UF_long s, Int *Super, Int *Lpi, Int *Ls, Int *Lpx, double *Lx, int xentry, cholmod_common *Common)
#define ROW_IS_ALIVE(r)
#define CCOLAMD_SUB_VERSION
#define KILL_PRINCIPAL_COL(c)
#define CMEMBER(c)
union CColamd_Col_struct::@2 shared3
#define CCOLAMD_C(n_col, ok)
#define PRIVATE
#define CSYMAMD_report
#define MAX(a, b)
struct CColamd_Col_struct CColamd_Col
#define KILL_ROW(r)
#define INDEX(i)
#define ROW_IS_MARKED_DEAD(row_mark)
#define FALSE
struct CColamd_Row_struct CColamd_Row
#define ID
#define COL_IS_DEAD(c)
#define ASSERT(expression)
#define NULL
#define CCOLAMD_ERROR_row_index_out_of_bounds
#define MIN(a, b)
union CColamd_Row_struct::@4 shared1
#define CCOLAMD_ERROR_p0_nonzero
#define CCOLAMD_ERROR_A_too_small
#define GLOBAL
#define CSYMAMD_MAIN
int n
#define CCOLAMD_STATS
#define CCOLAMD_ERROR_out_of_memory
PRIVATE void print_report(char *method, Int stats[CCOLAMD_STATS])
#define Int_MAX
#define ROW_IS_DEAD(r)
#define CCOLAMD_DENSE_COL