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