lemon-project-template-glpk

comparison deps/glpk/src/colamd/colamd.c @ 9:33de93886c88

Import GLPK 4.47
author Alpar Juttner <alpar@cs.elte.hu>
date Sun, 06 Nov 2011 20:59:10 +0100
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:2bdb0990ba18
1 /* ========================================================================== */
2 /* === colamd/symamd - a sparse matrix column ordering algorithm ============ */
3 /* ========================================================================== */
4
5 /* COLAMD / SYMAMD
6
7 colamd: an approximate minimum degree column ordering algorithm,
8 for LU factorization of symmetric or unsymmetric matrices,
9 QR factorization, least squares, interior point methods for
10 linear programming problems, and other related problems.
11
12 symamd: an approximate minimum degree ordering algorithm for Cholesky
13 factorization of symmetric matrices.
14
15 Purpose:
16
17 Colamd computes a permutation Q such that the Cholesky factorization of
18 (AQ)'(AQ) has less fill-in and requires fewer floating point operations
19 than A'A. This also provides a good ordering for sparse partial
20 pivoting methods, P(AQ) = LU, where Q is computed prior to numerical
21 factorization, and P is computed during numerical factorization via
22 conventional partial pivoting with row interchanges. Colamd is the
23 column ordering method used in SuperLU, part of the ScaLAPACK library.
24 It is also available as built-in function in MATLAB Version 6,
25 available from MathWorks, Inc. (http://www.mathworks.com). This
26 routine can be used in place of colmmd in MATLAB.
27
28 Symamd computes a permutation P of a symmetric matrix A such that the
29 Cholesky factorization of PAP' has less fill-in and requires fewer
30 floating point operations than A. Symamd constructs a matrix M such
31 that M'M has the same nonzero pattern of A, and then orders the columns
32 of M using colmmd. The column ordering of M is then returned as the
33 row and column ordering P of A.
34
35 Authors:
36
37 The authors of the code itself are Stefan I. Larimore and Timothy A.
38 Davis (davis at cise.ufl.edu), University of Florida. The algorithm was
39 developed in collaboration with John Gilbert, Xerox PARC, and Esmond
40 Ng, Oak Ridge National Laboratory.
41
42 Acknowledgements:
43
44 This work was supported by the National Science Foundation, under
45 grants DMS-9504974 and DMS-9803599.
46
47 Copyright and License:
48
49 Copyright (c) 1998-2007, Timothy A. Davis, All Rights Reserved.
50 COLAMD is also available under alternate licenses, contact T. Davis
51 for details.
52
53 This library is free software; you can redistribute it and/or
54 modify it under the terms of the GNU Lesser General Public
55 License as published by the Free Software Foundation; either
56 version 2.1 of the License, or (at your option) any later version.
57
58 This library is distributed in the hope that it will be useful,
59 but WITHOUT ANY WARRANTY; without even the implied warranty of
60 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
61 Lesser General Public License for more details.
62
63 You should have received a copy of the GNU Lesser General Public
64 License along with this library; if not, write to the Free Software
65 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
66 USA
67
68 Permission is hereby granted to use or copy this program under the
69 terms of the GNU LGPL, provided that the Copyright, this License,
70 and the Availability of the original version is retained on all copies.
71 User documentation of any code that uses this code or any modified
72 version of this code must cite the Copyright, this License, the
73 Availability note, and "Used by permission." Permission to modify
74 the code and to distribute modified code is granted, provided the
75 Copyright, this License, and the Availability note are retained,
76 and a notice that the code was modified is included.
77
78 Availability:
79
80 The colamd/symamd library is available at
81
82 http://www.cise.ufl.edu/research/sparse/colamd/
83
84 This is the http://www.cise.ufl.edu/research/sparse/colamd/colamd.c
85 file. It requires the colamd.h file. It is required by the colamdmex.c
86 and symamdmex.c files, for the MATLAB interface to colamd and symamd.
87 Appears as ACM Algorithm 836.
88
89 See the ChangeLog file for changes since Version 1.0.
90
91 References:
92
93 T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, An approximate column
94 minimum degree ordering algorithm, ACM Transactions on Mathematical
95 Software, vol. 30, no. 3., pp. 353-376, 2004.
96
97 T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, Algorithm 836: COLAMD,
98 an approximate column minimum degree ordering algorithm, ACM
99 Transactions on Mathematical Software, vol. 30, no. 3., pp. 377-380,
100 2004.
101
102 */
103
104 /* ========================================================================== */
105 /* === Description of user-callable routines ================================ */
106 /* ========================================================================== */
107
108 /* COLAMD includes both int and UF_long versions of all its routines. The
109 * description below is for the int version. For UF_long, all int arguments
110 * become UF_long. UF_long is normally defined as long, except for WIN64.
111
112 ----------------------------------------------------------------------------
113 colamd_recommended:
114 ----------------------------------------------------------------------------
115
116 C syntax:
117
118 #include "colamd.h"
119 size_t colamd_recommended (int nnz, int n_row, int n_col) ;
120 size_t colamd_l_recommended (UF_long nnz, UF_long n_row,
121 UF_long n_col) ;
122
123 Purpose:
124
125 Returns recommended value of Alen for use by colamd. Returns 0
126 if any input argument is negative. The use of this routine
127 is optional. Not needed for symamd, which dynamically allocates
128 its own memory.
129
130 Note that in v2.4 and earlier, these routines returned int or long.
131 They now return a value of type size_t.
132
133 Arguments (all input arguments):
134
135 int nnz ; Number of nonzeros in the matrix A. This must
136 be the same value as p [n_col] in the call to
137 colamd - otherwise you will get a wrong value
138 of the recommended memory to use.
139
140 int n_row ; Number of rows in the matrix A.
141
142 int n_col ; Number of columns in the matrix A.
143
144 ----------------------------------------------------------------------------
145 colamd_set_defaults:
146 ----------------------------------------------------------------------------
147
148 C syntax:
149
150 #include "colamd.h"
151 colamd_set_defaults (double knobs [COLAMD_KNOBS]) ;
152 colamd_l_set_defaults (double knobs [COLAMD_KNOBS]) ;
153
154 Purpose:
155
156 Sets the default parameters. The use of this routine is optional.
157
158 Arguments:
159
160 double knobs [COLAMD_KNOBS] ; Output only.
161
162 NOTE: the meaning of the dense row/col knobs has changed in v2.4
163
164 knobs [0] and knobs [1] control dense row and col detection:
165
166 Colamd: rows with more than
167 max (16, knobs [COLAMD_DENSE_ROW] * sqrt (n_col))
168 entries are removed prior to ordering. Columns with more than
169 max (16, knobs [COLAMD_DENSE_COL] * sqrt (MIN (n_row,n_col)))
170 entries are removed prior to
171 ordering, and placed last in the output column ordering.
172
173 Symamd: uses only knobs [COLAMD_DENSE_ROW], which is knobs [0].
174 Rows and columns with more than
175 max (16, knobs [COLAMD_DENSE_ROW] * sqrt (n))
176 entries are removed prior to ordering, and placed last in the
177 output ordering.
178
179 COLAMD_DENSE_ROW and COLAMD_DENSE_COL are defined as 0 and 1,
180 respectively, in colamd.h. Default values of these two knobs
181 are both 10. Currently, only knobs [0] and knobs [1] are
182 used, but future versions may use more knobs. If so, they will
183 be properly set to their defaults by the future version of
184 colamd_set_defaults, so that the code that calls colamd will
185 not need to change, assuming that you either use
186 colamd_set_defaults, or pass a (double *) NULL pointer as the
187 knobs array to colamd or symamd.
188
189 knobs [2]: aggressive absorption
190
191 knobs [COLAMD_AGGRESSIVE] controls whether or not to do
192 aggressive absorption during the ordering. Default is TRUE.
193
194
195 ----------------------------------------------------------------------------
196 colamd:
197 ----------------------------------------------------------------------------
198
199 C syntax:
200
201 #include "colamd.h"
202 int colamd (int n_row, int n_col, int Alen, int *A, int *p,
203 double knobs [COLAMD_KNOBS], int stats [COLAMD_STATS]) ;
204 UF_long colamd_l (UF_long n_row, UF_long n_col, UF_long Alen,
205 UF_long *A, UF_long *p, double knobs [COLAMD_KNOBS],
206 UF_long stats [COLAMD_STATS]) ;
207
208 Purpose:
209
210 Computes a column ordering (Q) of A such that P(AQ)=LU or
211 (AQ)'AQ=LL' have less fill-in and require fewer floating point
212 operations than factorizing the unpermuted matrix A or A'A,
213 respectively.
214
215 Returns:
216
217 TRUE (1) if successful, FALSE (0) otherwise.
218
219 Arguments:
220
221 int n_row ; Input argument.
222
223 Number of rows in the matrix A.
224 Restriction: n_row >= 0.
225 Colamd returns FALSE if n_row is negative.
226
227 int n_col ; Input argument.
228
229 Number of columns in the matrix A.
230 Restriction: n_col >= 0.
231 Colamd returns FALSE if n_col is negative.
232
233 int Alen ; Input argument.
234
235 Restriction (see note):
236 Alen >= 2*nnz + 6*(n_col+1) + 4*(n_row+1) + n_col
237 Colamd returns FALSE if these conditions are not met.
238
239 Note: this restriction makes an modest assumption regarding
240 the size of the two typedef's structures in colamd.h.
241 We do, however, guarantee that
242
243 Alen >= colamd_recommended (nnz, n_row, n_col)
244
245 will be sufficient. Note: the macro version does not check
246 for integer overflow, and thus is not recommended. Use
247 the colamd_recommended routine instead.
248
249 int A [Alen] ; Input argument, undefined on output.
250
251 A is an integer array of size Alen. Alen must be at least as
252 large as the bare minimum value given above, but this is very
253 low, and can result in excessive run time. For best
254 performance, we recommend that Alen be greater than or equal to
255 colamd_recommended (nnz, n_row, n_col), which adds
256 nnz/5 to the bare minimum value given above.
257
258 On input, the row indices of the entries in column c of the
259 matrix are held in A [(p [c]) ... (p [c+1]-1)]. The row indices
260 in a given column c need not be in ascending order, and
261 duplicate row indices may be be present. However, colamd will
262 work a little faster if both of these conditions are met
263 (Colamd puts the matrix into this format, if it finds that the
264 the conditions are not met).
265
266 The matrix is 0-based. That is, rows are in the range 0 to
267 n_row-1, and columns are in the range 0 to n_col-1. Colamd
268 returns FALSE if any row index is out of range.
269
270 The contents of A are modified during ordering, and are
271 undefined on output.
272
273 int p [n_col+1] ; Both input and output argument.
274
275 p is an integer array of size n_col+1. On input, it holds the
276 "pointers" for the column form of the matrix A. Column c of
277 the matrix A is held in A [(p [c]) ... (p [c+1]-1)]. The first
278 entry, p [0], must be zero, and p [c] <= p [c+1] must hold
279 for all c in the range 0 to n_col-1. The value p [n_col] is
280 thus the total number of entries in the pattern of the matrix A.
281 Colamd returns FALSE if these conditions are not met.
282
283 On output, if colamd returns TRUE, the array p holds the column
284 permutation (Q, for P(AQ)=LU or (AQ)'(AQ)=LL'), where p [0] is
285 the first column index in the new ordering, and p [n_col-1] is
286 the last. That is, p [k] = j means that column j of A is the
287 kth pivot column, in AQ, where k is in the range 0 to n_col-1
288 (p [0] = j means that column j of A is the first column in AQ).
289
290 If colamd returns FALSE, then no permutation is returned, and
291 p is undefined on output.
292
293 double knobs [COLAMD_KNOBS] ; Input argument.
294
295 See colamd_set_defaults for a description.
296
297 int stats [COLAMD_STATS] ; Output argument.
298
299 Statistics on the ordering, and error status.
300 See colamd.h for related definitions.
301 Colamd returns FALSE if stats is not present.
302
303 stats [0]: number of dense or empty rows ignored.
304
305 stats [1]: number of dense or empty columns ignored (and
306 ordered last in the output permutation p)
307 Note that a row can become "empty" if it
308 contains only "dense" and/or "empty" columns,
309 and similarly a column can become "empty" if it
310 only contains "dense" and/or "empty" rows.
311
312 stats [2]: number of garbage collections performed.
313 This can be excessively high if Alen is close
314 to the minimum required value.
315
316 stats [3]: status code. < 0 is an error code.
317 > 1 is a warning or notice.
318
319 0 OK. Each column of the input matrix contained
320 row indices in increasing order, with no
321 duplicates.
322
323 1 OK, but columns of input matrix were jumbled
324 (unsorted columns or duplicate entries). Colamd
325 had to do some extra work to sort the matrix
326 first and remove duplicate entries, but it
327 still was able to return a valid permutation
328 (return value of colamd was TRUE).
329
330 stats [4]: highest numbered column that
331 is unsorted or has duplicate
332 entries.
333 stats [5]: last seen duplicate or
334 unsorted row index.
335 stats [6]: number of duplicate or
336 unsorted row indices.
337
338 -1 A is a null pointer
339
340 -2 p is a null pointer
341
342 -3 n_row is negative
343
344 stats [4]: n_row
345
346 -4 n_col is negative
347
348 stats [4]: n_col
349
350 -5 number of nonzeros in matrix is negative
351
352 stats [4]: number of nonzeros, p [n_col]
353
354 -6 p [0] is nonzero
355
356 stats [4]: p [0]
357
358 -7 A is too small
359
360 stats [4]: required size
361 stats [5]: actual size (Alen)
362
363 -8 a column has a negative number of entries
364
365 stats [4]: column with < 0 entries
366 stats [5]: number of entries in col
367
368 -9 a row index is out of bounds
369
370 stats [4]: column with bad row index
371 stats [5]: bad row index
372 stats [6]: n_row, # of rows of matrx
373
374 -10 (unused; see symamd.c)
375
376 -999 (unused; see symamd.c)
377
378 Future versions may return more statistics in the stats array.
379
380 Example:
381
382 See http://www.cise.ufl.edu/research/sparse/colamd/example.c
383 for a complete example.
384
385 To order the columns of a 5-by-4 matrix with 11 nonzero entries in
386 the following nonzero pattern
387
388 x 0 x 0
389 x 0 x x
390 0 x x 0
391 0 0 x x
392 x x 0 0
393
394 with default knobs and no output statistics, do the following:
395
396 #include "colamd.h"
397 #define ALEN 100
398 int A [ALEN] = {0, 1, 4, 2, 4, 0, 1, 2, 3, 1, 3} ;
399 int p [ ] = {0, 3, 5, 9, 11} ;
400 int stats [COLAMD_STATS] ;
401 colamd (5, 4, ALEN, A, p, (double *) NULL, stats) ;
402
403 The permutation is returned in the array p, and A is destroyed.
404
405 ----------------------------------------------------------------------------
406 symamd:
407 ----------------------------------------------------------------------------
408
409 C syntax:
410
411 #include "colamd.h"
412 int symamd (int n, int *A, int *p, int *perm,
413 double knobs [COLAMD_KNOBS], int stats [COLAMD_STATS],
414 void (*allocate) (size_t, size_t), void (*release) (void *)) ;
415 UF_long symamd_l (UF_long n, UF_long *A, UF_long *p, UF_long *perm,
416 double knobs [COLAMD_KNOBS], UF_long stats [COLAMD_STATS],
417 void (*allocate) (size_t, size_t), void (*release) (void *)) ;
418
419 Purpose:
420
421 The symamd routine computes an ordering P of a symmetric sparse
422 matrix A such that the Cholesky factorization PAP' = LL' remains
423 sparse. It is based on a column ordering of a matrix M constructed
424 so that the nonzero pattern of M'M is the same as A. The matrix A
425 is assumed to be symmetric; only the strictly lower triangular part
426 is accessed. You must pass your selected memory allocator (usually
427 calloc/free or mxCalloc/mxFree) to symamd, for it to allocate
428 memory for the temporary matrix M.
429
430 Returns:
431
432 TRUE (1) if successful, FALSE (0) otherwise.
433
434 Arguments:
435
436 int n ; Input argument.
437
438 Number of rows and columns in the symmetrix matrix A.
439 Restriction: n >= 0.
440 Symamd returns FALSE if n is negative.
441
442 int A [nnz] ; Input argument.
443
444 A is an integer array of size nnz, where nnz = p [n].
445
446 The row indices of the entries in column c of the matrix are
447 held in A [(p [c]) ... (p [c+1]-1)]. The row indices in a
448 given column c need not be in ascending order, and duplicate
449 row indices may be present. However, symamd will run faster
450 if the columns are in sorted order with no duplicate entries.
451
452 The matrix is 0-based. That is, rows are in the range 0 to
453 n-1, and columns are in the range 0 to n-1. Symamd
454 returns FALSE if any row index is out of range.
455
456 The contents of A are not modified.
457
458 int p [n+1] ; Input argument.
459
460 p is an integer array of size n+1. On input, it holds the
461 "pointers" for the column form of the matrix A. Column c of
462 the matrix A is held in A [(p [c]) ... (p [c+1]-1)]. The first
463 entry, p [0], must be zero, and p [c] <= p [c+1] must hold
464 for all c in the range 0 to n-1. The value p [n] is
465 thus the total number of entries in the pattern of the matrix A.
466 Symamd returns FALSE if these conditions are not met.
467
468 The contents of p are not modified.
469
470 int perm [n+1] ; Output argument.
471
472 On output, if symamd returns TRUE, the array perm holds the
473 permutation P, where perm [0] is the first index in the new
474 ordering, and perm [n-1] is the last. That is, perm [k] = j
475 means that row and column j of A is the kth column in PAP',
476 where k is in the range 0 to n-1 (perm [0] = j means
477 that row and column j of A are the first row and column in
478 PAP'). The array is used as a workspace during the ordering,
479 which is why it must be of length n+1, not just n.
480
481 double knobs [COLAMD_KNOBS] ; Input argument.
482
483 See colamd_set_defaults for a description.
484
485 int stats [COLAMD_STATS] ; Output argument.
486
487 Statistics on the ordering, and error status.
488 See colamd.h for related definitions.
489 Symamd returns FALSE if stats is not present.
490
491 stats [0]: number of dense or empty row and columns ignored
492 (and ordered last in the output permutation
493 perm). Note that a row/column can become
494 "empty" if it contains only "dense" and/or
495 "empty" columns/rows.
496
497 stats [1]: (same as stats [0])
498
499 stats [2]: number of garbage collections performed.
500
501 stats [3]: status code. < 0 is an error code.
502 > 1 is a warning or notice.
503
504 0 OK. Each column of the input matrix contained
505 row indices in increasing order, with no
506 duplicates.
507
508 1 OK, but columns of input matrix were jumbled
509 (unsorted columns or duplicate entries). Symamd
510 had to do some extra work to sort the matrix
511 first and remove duplicate entries, but it
512 still was able to return a valid permutation
513 (return value of symamd was TRUE).
514
515 stats [4]: highest numbered column that
516 is unsorted or has duplicate
517 entries.
518 stats [5]: last seen duplicate or
519 unsorted row index.
520 stats [6]: number of duplicate or
521 unsorted row indices.
522
523 -1 A is a null pointer
524
525 -2 p is a null pointer
526
527 -3 (unused, see colamd.c)
528
529 -4 n is negative
530
531 stats [4]: n
532
533 -5 number of nonzeros in matrix is negative
534
535 stats [4]: # of nonzeros (p [n]).
536
537 -6 p [0] is nonzero
538
539 stats [4]: p [0]
540
541 -7 (unused)
542
543 -8 a column has a negative number of entries
544
545 stats [4]: column with < 0 entries
546 stats [5]: number of entries in col
547
548 -9 a row index is out of bounds
549
550 stats [4]: column with bad row index
551 stats [5]: bad row index
552 stats [6]: n_row, # of rows of matrx
553
554 -10 out of memory (unable to allocate temporary
555 workspace for M or count arrays using the
556 "allocate" routine passed into symamd).
557
558 Future versions may return more statistics in the stats array.
559
560 void * (*allocate) (size_t, size_t)
561
562 A pointer to a function providing memory allocation. The
563 allocated memory must be returned initialized to zero. For a
564 C application, this argument should normally be a pointer to
565 calloc. For a MATLAB mexFunction, the routine mxCalloc is
566 passed instead.
567
568 void (*release) (size_t, size_t)
569
570 A pointer to a function that frees memory allocated by the
571 memory allocation routine above. For a C application, this
572 argument should normally be a pointer to free. For a MATLAB
573 mexFunction, the routine mxFree is passed instead.
574
575
576 ----------------------------------------------------------------------------
577 colamd_report:
578 ----------------------------------------------------------------------------
579
580 C syntax:
581
582 #include "colamd.h"
583 colamd_report (int stats [COLAMD_STATS]) ;
584 colamd_l_report (UF_long stats [COLAMD_STATS]) ;
585
586 Purpose:
587
588 Prints the error status and statistics recorded in the stats
589 array on the standard error output (for a standard C routine)
590 or on the MATLAB output (for a mexFunction).
591
592 Arguments:
593
594 int stats [COLAMD_STATS] ; Input only. Statistics from colamd.
595
596
597 ----------------------------------------------------------------------------
598 symamd_report:
599 ----------------------------------------------------------------------------
600
601 C syntax:
602
603 #include "colamd.h"
604 symamd_report (int stats [COLAMD_STATS]) ;
605 symamd_l_report (UF_long stats [COLAMD_STATS]) ;
606
607 Purpose:
608
609 Prints the error status and statistics recorded in the stats
610 array on the standard error output (for a standard C routine)
611 or on the MATLAB output (for a mexFunction).
612
613 Arguments:
614
615 int stats [COLAMD_STATS] ; Input only. Statistics from symamd.
616
617
618 */
619
620 /* ========================================================================== */
621 /* === Scaffolding code definitions ======================================== */
622 /* ========================================================================== */
623
624 /* Ensure that debugging is turned off: */
625 #ifndef NDEBUG
626 #define NDEBUG
627 #endif
628
629 /* turn on debugging by uncommenting the following line
630 #undef NDEBUG
631 */
632
633 /*
634 Our "scaffolding code" philosophy: In our opinion, well-written library
635 code should keep its "debugging" code, and just normally have it turned off
636 by the compiler so as not to interfere with performance. This serves
637 several purposes:
638
639 (1) assertions act as comments to the reader, telling you what the code
640 expects at that point. All assertions will always be true (unless
641 there really is a bug, of course).
642
643 (2) leaving in the scaffolding code assists anyone who would like to modify
644 the code, or understand the algorithm (by reading the debugging output,
645 one can get a glimpse into what the code is doing).
646
647 (3) (gasp!) for actually finding bugs. This code has been heavily tested
648 and "should" be fully functional and bug-free ... but you never know...
649
650 The code will become outrageously slow when debugging is
651 enabled. To control the level of debugging output, set an environment
652 variable D to 0 (little), 1 (some), 2, 3, or 4 (lots). When debugging,
653 you should see the following message on the standard output:
654
655 colamd: debug version, D = 1 (THIS WILL BE SLOW!)
656
657 or a similar message for symamd. If you don't, then debugging has not
658 been enabled.
659
660 */
661
662 /* ========================================================================== */
663 /* === Include files ======================================================== */
664 /* ========================================================================== */
665
666 #include "colamd.h"
667
668 #if 0 /* by mao */
669 #include <limits.h>
670 #include <math.h>
671
672 #ifdef MATLAB_MEX_FILE
673 #include "mex.h"
674 #include "matrix.h"
675 #endif /* MATLAB_MEX_FILE */
676
677 #if !defined (NPRINT) || !defined (NDEBUG)
678 #include <stdio.h>
679 #endif
680
681 #ifndef NULL
682 #define NULL ((void *) 0)
683 #endif
684 #endif
685
686 /* ========================================================================== */
687 /* === int or UF_long ======================================================= */
688 /* ========================================================================== */
689
690 #if 0 /* by mao */
691 /* define UF_long */
692 #include "UFconfig.h"
693 #endif
694
695 #ifdef DLONG
696
697 #define Int UF_long
698 #define ID UF_long_id
699 #define Int_MAX UF_long_max
700
701 #define COLAMD_recommended colamd_l_recommended
702 #define COLAMD_set_defaults colamd_l_set_defaults
703 #define COLAMD_MAIN colamd_l
704 #define SYMAMD_MAIN symamd_l
705 #define COLAMD_report colamd_l_report
706 #define SYMAMD_report symamd_l_report
707
708 #else
709
710 #define Int int
711 #define ID "%d"
712 #define Int_MAX INT_MAX
713
714 #define COLAMD_recommended colamd_recommended
715 #define COLAMD_set_defaults colamd_set_defaults
716 #define COLAMD_MAIN colamd
717 #define SYMAMD_MAIN symamd
718 #define COLAMD_report colamd_report
719 #define SYMAMD_report symamd_report
720
721 #endif
722
723 /* ========================================================================== */
724 /* === Row and Column structures ============================================ */
725 /* ========================================================================== */
726
727 /* User code that makes use of the colamd/symamd routines need not directly */
728 /* reference these structures. They are used only for colamd_recommended. */
729
730 typedef struct Colamd_Col_struct
731 {
732 Int start ; /* index for A of first row in this column, or DEAD */
733 /* if column is dead */
734 Int length ; /* number of rows in this column */
735 union
736 {
737 Int thickness ; /* number of original columns represented by this */
738 /* col, if the column is alive */
739 Int parent ; /* parent in parent tree super-column structure, if */
740 /* the column is dead */
741 } shared1 ;
742 union
743 {
744 Int score ; /* the score used to maintain heap, if col is alive */
745 Int order ; /* pivot ordering of this column, if col is dead */
746 } shared2 ;
747 union
748 {
749 Int headhash ; /* head of a hash bucket, if col is at the head of */
750 /* a degree list */
751 Int hash ; /* hash value, if col is not in a degree list */
752 Int prev ; /* previous column in degree list, if col is in a */
753 /* degree list (but not at the head of a degree list) */
754 } shared3 ;
755 union
756 {
757 Int degree_next ; /* next column, if col is in a degree list */
758 Int hash_next ; /* next column, if col is in a hash list */
759 } shared4 ;
760
761 } Colamd_Col ;
762
763 typedef struct Colamd_Row_struct
764 {
765 Int start ; /* index for A of first col in this row */
766 Int length ; /* number of principal columns in this row */
767 union
768 {
769 Int degree ; /* number of principal & non-principal columns in row */
770 Int p ; /* used as a row pointer in init_rows_cols () */
771 } shared1 ;
772 union
773 {
774 Int mark ; /* for computing set differences and marking dead rows*/
775 Int first_column ;/* first column in row (used in garbage collection) */
776 } shared2 ;
777
778 } Colamd_Row ;
779
780 /* ========================================================================== */
781 /* === Definitions ========================================================== */
782 /* ========================================================================== */
783
784 /* Routines are either PUBLIC (user-callable) or PRIVATE (not user-callable) */
785 #define PUBLIC
786 #define PRIVATE static
787
788 #define DENSE_DEGREE(alpha,n) \
789 ((Int) MAX (16.0, (alpha) * sqrt ((double) (n))))
790
791 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
792 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
793
794 #define ONES_COMPLEMENT(r) (-(r)-1)
795
796 /* -------------------------------------------------------------------------- */
797 /* Change for version 2.1: define TRUE and FALSE only if not yet defined */
798 /* -------------------------------------------------------------------------- */
799
800 #ifndef TRUE
801 #define TRUE (1)
802 #endif
803
804 #ifndef FALSE
805 #define FALSE (0)
806 #endif
807
808 /* -------------------------------------------------------------------------- */
809
810 #define EMPTY (-1)
811
812 /* Row and column status */
813 #define ALIVE (0)
814 #define DEAD (-1)
815
816 /* Column status */
817 #define DEAD_PRINCIPAL (-1)
818 #define DEAD_NON_PRINCIPAL (-2)
819
820 /* Macros for row and column status update and checking. */
821 #define ROW_IS_DEAD(r) ROW_IS_MARKED_DEAD (Row[r].shared2.mark)
822 #define ROW_IS_MARKED_DEAD(row_mark) (row_mark < ALIVE)
823 #define ROW_IS_ALIVE(r) (Row [r].shared2.mark >= ALIVE)
824 #define COL_IS_DEAD(c) (Col [c].start < ALIVE)
825 #define COL_IS_ALIVE(c) (Col [c].start >= ALIVE)
826 #define COL_IS_DEAD_PRINCIPAL(c) (Col [c].start == DEAD_PRINCIPAL)
827 #define KILL_ROW(r) { Row [r].shared2.mark = DEAD ; }
828 #define KILL_PRINCIPAL_COL(c) { Col [c].start = DEAD_PRINCIPAL ; }
829 #define KILL_NON_PRINCIPAL_COL(c) { Col [c].start = DEAD_NON_PRINCIPAL ; }
830
831 /* ========================================================================== */
832 /* === Colamd reporting mechanism =========================================== */
833 /* ========================================================================== */
834
835 #if defined (MATLAB_MEX_FILE) || defined (MATHWORKS)
836 /* In MATLAB, matrices are 1-based to the user, but 0-based internally */
837 #define INDEX(i) ((i)+1)
838 #else
839 /* In C, matrices are 0-based and indices are reported as such in *_report */
840 #define INDEX(i) (i)
841 #endif
842
843 /* All output goes through the PRINTF macro. */
844 #define PRINTF(params) { if (colamd_printf != NULL) (void) colamd_printf params ; }
845
846 /* ========================================================================== */
847 /* === Prototypes of PRIVATE routines ======================================= */
848 /* ========================================================================== */
849
850 PRIVATE Int init_rows_cols
851 (
852 Int n_row,
853 Int n_col,
854 Colamd_Row Row [],
855 Colamd_Col Col [],
856 Int A [],
857 Int p [],
858 Int stats [COLAMD_STATS]
859 ) ;
860
861 PRIVATE void init_scoring
862 (
863 Int n_row,
864 Int n_col,
865 Colamd_Row Row [],
866 Colamd_Col Col [],
867 Int A [],
868 Int head [],
869 double knobs [COLAMD_KNOBS],
870 Int *p_n_row2,
871 Int *p_n_col2,
872 Int *p_max_deg
873 ) ;
874
875 PRIVATE Int find_ordering
876 (
877 Int n_row,
878 Int n_col,
879 Int Alen,
880 Colamd_Row Row [],
881 Colamd_Col Col [],
882 Int A [],
883 Int head [],
884 Int n_col2,
885 Int max_deg,
886 Int pfree,
887 Int aggressive
888 ) ;
889
890 PRIVATE void order_children
891 (
892 Int n_col,
893 Colamd_Col Col [],
894 Int p []
895 ) ;
896
897 PRIVATE void detect_super_cols
898 (
899
900 #ifndef NDEBUG
901 Int n_col,
902 Colamd_Row Row [],
903 #endif /* NDEBUG */
904
905 Colamd_Col Col [],
906 Int A [],
907 Int head [],
908 Int row_start,
909 Int row_length
910 ) ;
911
912 PRIVATE Int garbage_collection
913 (
914 Int n_row,
915 Int n_col,
916 Colamd_Row Row [],
917 Colamd_Col Col [],
918 Int A [],
919 Int *pfree
920 ) ;
921
922 PRIVATE Int clear_mark
923 (
924 Int tag_mark,
925 Int max_mark,
926 Int n_row,
927 Colamd_Row Row []
928 ) ;
929
930 PRIVATE void print_report
931 (
932 char *method,
933 Int stats [COLAMD_STATS]
934 ) ;
935
936 /* ========================================================================== */
937 /* === Debugging prototypes and definitions ================================= */
938 /* ========================================================================== */
939
940 #ifndef NDEBUG
941
942 #if 0 /* by mao */
943 #include <assert.h>
944 #endif
945
946 /* colamd_debug is the *ONLY* global variable, and is only */
947 /* present when debugging */
948
949 PRIVATE Int colamd_debug = 0 ; /* debug print level */
950
951 #define DEBUG0(params) { PRINTF (params) ; }
952 #define DEBUG1(params) { if (colamd_debug >= 1) PRINTF (params) ; }
953 #define DEBUG2(params) { if (colamd_debug >= 2) PRINTF (params) ; }
954 #define DEBUG3(params) { if (colamd_debug >= 3) PRINTF (params) ; }
955 #define DEBUG4(params) { if (colamd_debug >= 4) PRINTF (params) ; }
956
957 #if 0 /* by mao */
958 #ifdef MATLAB_MEX_FILE
959 #define ASSERT(expression) (mxAssert ((expression), ""))
960 #else
961 #define ASSERT(expression) (assert (expression))
962 #endif /* MATLAB_MEX_FILE */
963 #else
964 #define ASSERT xassert
965 #endif
966
967 PRIVATE void colamd_get_debug /* gets the debug print level from getenv */
968 (
969 char *method
970 ) ;
971
972 PRIVATE void debug_deg_lists
973 (
974 Int n_row,
975 Int n_col,
976 Colamd_Row Row [],
977 Colamd_Col Col [],
978 Int head [],
979 Int min_score,
980 Int should,
981 Int max_deg
982 ) ;
983
984 PRIVATE void debug_mark
985 (
986 Int n_row,
987 Colamd_Row Row [],
988 Int tag_mark,
989 Int max_mark
990 ) ;
991
992 PRIVATE void debug_matrix
993 (
994 Int n_row,
995 Int n_col,
996 Colamd_Row Row [],
997 Colamd_Col Col [],
998 Int A []
999 ) ;
1000
1001 PRIVATE void debug_structures
1002 (
1003 Int n_row,
1004 Int n_col,
1005 Colamd_Row Row [],
1006 Colamd_Col Col [],
1007 Int A [],
1008 Int n_col2
1009 ) ;
1010
1011 #else /* NDEBUG */
1012
1013 /* === No debugging ========================================================= */
1014
1015 #define DEBUG0(params) ;
1016 #define DEBUG1(params) ;
1017 #define DEBUG2(params) ;
1018 #define DEBUG3(params) ;
1019 #define DEBUG4(params) ;
1020
1021 #define ASSERT(expression)
1022
1023 #endif /* NDEBUG */
1024
1025 /* ========================================================================== */
1026 /* === USER-CALLABLE ROUTINES: ============================================== */
1027 /* ========================================================================== */
1028
1029 /* ========================================================================== */
1030 /* === colamd_recommended =================================================== */
1031 /* ========================================================================== */
1032
1033 /*
1034 The colamd_recommended routine returns the suggested size for Alen. This
1035 value has been determined to provide good balance between the number of
1036 garbage collections and the memory requirements for colamd. If any
1037 argument is negative, or if integer overflow occurs, a 0 is returned as an
1038 error condition. 2*nnz space is required for the row and column
1039 indices of the matrix. COLAMD_C (n_col) + COLAMD_R (n_row) space is
1040 required for the Col and Row arrays, respectively, which are internal to
1041 colamd (roughly 6*n_col + 4*n_row). An additional n_col space is the
1042 minimal amount of "elbow room", and nnz/5 more space is recommended for
1043 run time efficiency.
1044
1045 Alen is approximately 2.2*nnz + 7*n_col + 4*n_row + 10.
1046
1047 This function is not needed when using symamd.
1048 */
1049
1050 /* add two values of type size_t, and check for integer overflow */
1051 static size_t t_add (size_t a, size_t b, int *ok)
1052 {
1053 (*ok) = (*ok) && ((a + b) >= MAX (a,b)) ;
1054 return ((*ok) ? (a + b) : 0) ;
1055 }
1056
1057 /* compute a*k where k is a small integer, and check for integer overflow */
1058 static size_t t_mult (size_t a, size_t k, int *ok)
1059 {
1060 size_t i, s = 0 ;
1061 for (i = 0 ; i < k ; i++)
1062 {
1063 s = t_add (s, a, ok) ;
1064 }
1065 return (s) ;
1066 }
1067
1068 /* size of the Col and Row structures */
1069 #define COLAMD_C(n_col,ok) \
1070 ((t_mult (t_add (n_col, 1, ok), sizeof (Colamd_Col), ok) / sizeof (Int)))
1071
1072 #define COLAMD_R(n_row,ok) \
1073 ((t_mult (t_add (n_row, 1, ok), sizeof (Colamd_Row), ok) / sizeof (Int)))
1074
1075
1076 PUBLIC size_t COLAMD_recommended /* returns recommended value of Alen. */
1077 (
1078 /* === Parameters ======================================================= */
1079
1080 Int nnz, /* number of nonzeros in A */
1081 Int n_row, /* number of rows in A */
1082 Int n_col /* number of columns in A */
1083 )
1084 {
1085 size_t s, c, r ;
1086 int ok = TRUE ;
1087 if (nnz < 0 || n_row < 0 || n_col < 0)
1088 {
1089 return (0) ;
1090 }
1091 s = t_mult (nnz, 2, &ok) ; /* 2*nnz */
1092 c = COLAMD_C (n_col, &ok) ; /* size of column structures */
1093 r = COLAMD_R (n_row, &ok) ; /* size of row structures */
1094 s = t_add (s, c, &ok) ;
1095 s = t_add (s, r, &ok) ;
1096 s = t_add (s, n_col, &ok) ; /* elbow room */
1097 s = t_add (s, nnz/5, &ok) ; /* elbow room */
1098 ok = ok && (s < Int_MAX) ;
1099 return (ok ? s : 0) ;
1100 }
1101
1102
1103 /* ========================================================================== */
1104 /* === colamd_set_defaults ================================================== */
1105 /* ========================================================================== */
1106
1107 /*
1108 The colamd_set_defaults routine sets the default values of the user-
1109 controllable parameters for colamd and symamd:
1110
1111 Colamd: rows with more than max (16, knobs [0] * sqrt (n_col))
1112 entries are removed prior to ordering. Columns with more than
1113 max (16, knobs [1] * sqrt (MIN (n_row,n_col))) entries are removed
1114 prior to ordering, and placed last in the output column ordering.
1115
1116 Symamd: Rows and columns with more than max (16, knobs [0] * sqrt (n))
1117 entries are removed prior to ordering, and placed last in the
1118 output ordering.
1119
1120 knobs [0] dense row control
1121
1122 knobs [1] dense column control
1123
1124 knobs [2] if nonzero, do aggresive absorption
1125
1126 knobs [3..19] unused, but future versions might use this
1127
1128 */
1129
1130 PUBLIC void COLAMD_set_defaults
1131 (
1132 /* === Parameters ======================================================= */
1133
1134 double knobs [COLAMD_KNOBS] /* knob array */
1135 )
1136 {
1137 /* === Local variables ================================================== */
1138
1139 Int i ;
1140
1141 if (!knobs)
1142 {
1143 return ; /* no knobs to initialize */
1144 }
1145 for (i = 0 ; i < COLAMD_KNOBS ; i++)
1146 {
1147 knobs [i] = 0 ;
1148 }
1149 knobs [COLAMD_DENSE_ROW] = 10 ;
1150 knobs [COLAMD_DENSE_COL] = 10 ;
1151 knobs [COLAMD_AGGRESSIVE] = TRUE ; /* default: do aggressive absorption*/
1152 }
1153
1154
1155 /* ========================================================================== */
1156 /* === symamd =============================================================== */
1157 /* ========================================================================== */
1158
1159 PUBLIC Int SYMAMD_MAIN /* return TRUE if OK, FALSE otherwise */
1160 (
1161 /* === Parameters ======================================================= */
1162
1163 Int n, /* number of rows and columns of A */
1164 Int A [], /* row indices of A */
1165 Int p [], /* column pointers of A */
1166 Int perm [], /* output permutation, size n+1 */
1167 double knobs [COLAMD_KNOBS], /* parameters (uses defaults if NULL) */
1168 Int stats [COLAMD_STATS], /* output statistics and error codes */
1169 void * (*allocate) (size_t, size_t),
1170 /* pointer to calloc (ANSI C) or */
1171 /* mxCalloc (for MATLAB mexFunction) */
1172 void (*release) (void *)
1173 /* pointer to free (ANSI C) or */
1174 /* mxFree (for MATLAB mexFunction) */
1175 )
1176 {
1177 /* === Local variables ================================================== */
1178
1179 Int *count ; /* length of each column of M, and col pointer*/
1180 Int *mark ; /* mark array for finding duplicate entries */
1181 Int *M ; /* row indices of matrix M */
1182 size_t Mlen ; /* length of M */
1183 Int n_row ; /* number of rows in M */
1184 Int nnz ; /* number of entries in A */
1185 Int i ; /* row index of A */
1186 Int j ; /* column index of A */
1187 Int k ; /* row index of M */
1188 Int mnz ; /* number of nonzeros in M */
1189 Int pp ; /* index into a column of A */
1190 Int last_row ; /* last row seen in the current column */
1191 Int length ; /* number of nonzeros in a column */
1192
1193 double cknobs [COLAMD_KNOBS] ; /* knobs for colamd */
1194 double default_knobs [COLAMD_KNOBS] ; /* default knobs for colamd */
1195
1196 #ifndef NDEBUG
1197 colamd_get_debug ("symamd") ;
1198 #endif /* NDEBUG */
1199
1200 /* === Check the input arguments ======================================== */
1201
1202 if (!stats)
1203 {
1204 DEBUG0 (("symamd: stats not present\n")) ;
1205 return (FALSE) ;
1206 }
1207 for (i = 0 ; i < COLAMD_STATS ; i++)
1208 {
1209 stats [i] = 0 ;
1210 }
1211 stats [COLAMD_STATUS] = COLAMD_OK ;
1212 stats [COLAMD_INFO1] = -1 ;
1213 stats [COLAMD_INFO2] = -1 ;
1214
1215 if (!A)
1216 {
1217 stats [COLAMD_STATUS] = COLAMD_ERROR_A_not_present ;
1218 DEBUG0 (("symamd: A not present\n")) ;
1219 return (FALSE) ;
1220 }
1221
1222 if (!p) /* p is not present */
1223 {
1224 stats [COLAMD_STATUS] = COLAMD_ERROR_p_not_present ;
1225 DEBUG0 (("symamd: p not present\n")) ;
1226 return (FALSE) ;
1227 }
1228
1229 if (n < 0) /* n must be >= 0 */
1230 {
1231 stats [COLAMD_STATUS] = COLAMD_ERROR_ncol_negative ;
1232 stats [COLAMD_INFO1] = n ;
1233 DEBUG0 (("symamd: n negative %d\n", n)) ;
1234 return (FALSE) ;
1235 }
1236
1237 nnz = p [n] ;
1238 if (nnz < 0) /* nnz must be >= 0 */
1239 {
1240 stats [COLAMD_STATUS] = COLAMD_ERROR_nnz_negative ;
1241 stats [COLAMD_INFO1] = nnz ;
1242 DEBUG0 (("symamd: number of entries negative %d\n", nnz)) ;
1243 return (FALSE) ;
1244 }
1245
1246 if (p [0] != 0)
1247 {
1248 stats [COLAMD_STATUS] = COLAMD_ERROR_p0_nonzero ;
1249 stats [COLAMD_INFO1] = p [0] ;
1250 DEBUG0 (("symamd: p[0] not zero %d\n", p [0])) ;
1251 return (FALSE) ;
1252 }
1253
1254 /* === If no knobs, set default knobs =================================== */
1255
1256 if (!knobs)
1257 {
1258 COLAMD_set_defaults (default_knobs) ;
1259 knobs = default_knobs ;
1260 }
1261
1262 /* === Allocate count and mark ========================================== */
1263
1264 count = (Int *) ((*allocate) (n+1, sizeof (Int))) ;
1265 if (!count)
1266 {
1267 stats [COLAMD_STATUS] = COLAMD_ERROR_out_of_memory ;
1268 DEBUG0 (("symamd: allocate count (size %d) failed\n", n+1)) ;
1269 return (FALSE) ;
1270 }
1271
1272 mark = (Int *) ((*allocate) (n+1, sizeof (Int))) ;
1273 if (!mark)
1274 {
1275 stats [COLAMD_STATUS] = COLAMD_ERROR_out_of_memory ;
1276 (*release) ((void *) count) ;
1277 DEBUG0 (("symamd: allocate mark (size %d) failed\n", n+1)) ;
1278 return (FALSE) ;
1279 }
1280
1281 /* === Compute column counts of M, check if A is valid ================== */
1282
1283 stats [COLAMD_INFO3] = 0 ; /* number of duplicate or unsorted row indices*/
1284
1285 for (i = 0 ; i < n ; i++)
1286 {
1287 mark [i] = -1 ;
1288 }
1289
1290 for (j = 0 ; j < n ; j++)
1291 {
1292 last_row = -1 ;
1293
1294 length = p [j+1] - p [j] ;
1295 if (length < 0)
1296 {
1297 /* column pointers must be non-decreasing */
1298 stats [COLAMD_STATUS] = COLAMD_ERROR_col_length_negative ;
1299 stats [COLAMD_INFO1] = j ;
1300 stats [COLAMD_INFO2] = length ;
1301 (*release) ((void *) count) ;
1302 (*release) ((void *) mark) ;
1303 DEBUG0 (("symamd: col %d negative length %d\n", j, length)) ;
1304 return (FALSE) ;
1305 }
1306
1307 for (pp = p [j] ; pp < p [j+1] ; pp++)
1308 {
1309 i = A [pp] ;
1310 if (i < 0 || i >= n)
1311 {
1312 /* row index i, in column j, is out of bounds */
1313 stats [COLAMD_STATUS] = COLAMD_ERROR_row_index_out_of_bounds ;
1314 stats [COLAMD_INFO1] = j ;
1315 stats [COLAMD_INFO2] = i ;
1316 stats [COLAMD_INFO3] = n ;
1317 (*release) ((void *) count) ;
1318 (*release) ((void *) mark) ;
1319 DEBUG0 (("symamd: row %d col %d out of bounds\n", i, j)) ;
1320 return (FALSE) ;
1321 }
1322
1323 if (i <= last_row || mark [i] == j)
1324 {
1325 /* row index is unsorted or repeated (or both), thus col */
1326 /* is jumbled. This is a notice, not an error condition. */
1327 stats [COLAMD_STATUS] = COLAMD_OK_BUT_JUMBLED ;
1328 stats [COLAMD_INFO1] = j ;
1329 stats [COLAMD_INFO2] = i ;
1330 (stats [COLAMD_INFO3]) ++ ;
1331 DEBUG1 (("symamd: row %d col %d unsorted/duplicate\n", i, j)) ;
1332 }
1333
1334 if (i > j && mark [i] != j)
1335 {
1336 /* row k of M will contain column indices i and j */
1337 count [i]++ ;
1338 count [j]++ ;
1339 }
1340
1341 /* mark the row as having been seen in this column */
1342 mark [i] = j ;
1343
1344 last_row = i ;
1345 }
1346 }
1347
1348 /* v2.4: removed free(mark) */
1349
1350 /* === Compute column pointers of M ===================================== */
1351
1352 /* use output permutation, perm, for column pointers of M */
1353 perm [0] = 0 ;
1354 for (j = 1 ; j <= n ; j++)
1355 {
1356 perm [j] = perm [j-1] + count [j-1] ;
1357 }
1358 for (j = 0 ; j < n ; j++)
1359 {
1360 count [j] = perm [j] ;
1361 }
1362
1363 /* === Construct M ====================================================== */
1364
1365 mnz = perm [n] ;
1366 n_row = mnz / 2 ;
1367 Mlen = COLAMD_recommended (mnz, n_row, n) ;
1368 M = (Int *) ((*allocate) (Mlen, sizeof (Int))) ;
1369 DEBUG0 (("symamd: M is %d-by-%d with %d entries, Mlen = %g\n",
1370 n_row, n, mnz, (double) Mlen)) ;
1371
1372 if (!M)
1373 {
1374 stats [COLAMD_STATUS] = COLAMD_ERROR_out_of_memory ;
1375 (*release) ((void *) count) ;
1376 (*release) ((void *) mark) ;
1377 DEBUG0 (("symamd: allocate M (size %g) failed\n", (double) Mlen)) ;
1378 return (FALSE) ;
1379 }
1380
1381 k = 0 ;
1382
1383 if (stats [COLAMD_STATUS] == COLAMD_OK)
1384 {
1385 /* Matrix is OK */
1386 for (j = 0 ; j < n ; j++)
1387 {
1388 ASSERT (p [j+1] - p [j] >= 0) ;
1389 for (pp = p [j] ; pp < p [j+1] ; pp++)
1390 {
1391 i = A [pp] ;
1392 ASSERT (i >= 0 && i < n) ;
1393 if (i > j)
1394 {
1395 /* row k of M contains column indices i and j */
1396 M [count [i]++] = k ;
1397 M [count [j]++] = k ;
1398 k++ ;
1399 }
1400 }
1401 }
1402 }
1403 else
1404 {
1405 /* Matrix is jumbled. Do not add duplicates to M. Unsorted cols OK. */
1406 DEBUG0 (("symamd: Duplicates in A.\n")) ;
1407 for (i = 0 ; i < n ; i++)
1408 {
1409 mark [i] = -1 ;
1410 }
1411 for (j = 0 ; j < n ; j++)
1412 {
1413 ASSERT (p [j+1] - p [j] >= 0) ;
1414 for (pp = p [j] ; pp < p [j+1] ; pp++)
1415 {
1416 i = A [pp] ;
1417 ASSERT (i >= 0 && i < n) ;
1418 if (i > j && mark [i] != j)
1419 {
1420 /* row k of M contains column indices i and j */
1421 M [count [i]++] = k ;
1422 M [count [j]++] = k ;
1423 k++ ;
1424 mark [i] = j ;
1425 }
1426 }
1427 }
1428 /* v2.4: free(mark) moved below */
1429 }
1430
1431 /* count and mark no longer needed */
1432 (*release) ((void *) count) ;
1433 (*release) ((void *) mark) ; /* v2.4: free (mark) moved here */
1434 ASSERT (k == n_row) ;
1435
1436 /* === Adjust the knobs for M =========================================== */
1437
1438 for (i = 0 ; i < COLAMD_KNOBS ; i++)
1439 {
1440 cknobs [i] = knobs [i] ;
1441 }
1442
1443 /* there are no dense rows in M */
1444 cknobs [COLAMD_DENSE_ROW] = -1 ;
1445 cknobs [COLAMD_DENSE_COL] = knobs [COLAMD_DENSE_ROW] ;
1446
1447 /* === Order the columns of M =========================================== */
1448
1449 /* v2.4: colamd cannot fail here, so the error check is removed */
1450 (void) COLAMD_MAIN (n_row, n, (Int) Mlen, M, perm, cknobs, stats) ;
1451
1452 /* Note that the output permutation is now in perm */
1453
1454 /* === get the statistics for symamd from colamd ======================== */
1455
1456 /* a dense column in colamd means a dense row and col in symamd */
1457 stats [COLAMD_DENSE_ROW] = stats [COLAMD_DENSE_COL] ;
1458
1459 /* === Free M =========================================================== */
1460
1461 (*release) ((void *) M) ;
1462 DEBUG0 (("symamd: done.\n")) ;
1463 return (TRUE) ;
1464
1465 }
1466
1467 /* ========================================================================== */
1468 /* === colamd =============================================================== */
1469 /* ========================================================================== */
1470
1471 /*
1472 The colamd routine computes a column ordering Q of a sparse matrix
1473 A such that the LU factorization P(AQ) = LU remains sparse, where P is
1474 selected via partial pivoting. The routine can also be viewed as
1475 providing a permutation Q such that the Cholesky factorization
1476 (AQ)'(AQ) = LL' remains sparse.
1477 */
1478
1479 PUBLIC Int COLAMD_MAIN /* returns TRUE if successful, FALSE otherwise*/
1480 (
1481 /* === Parameters ======================================================= */
1482
1483 Int n_row, /* number of rows in A */
1484 Int n_col, /* number of columns in A */
1485 Int Alen, /* length of A */
1486 Int A [], /* row indices of A */
1487 Int p [], /* pointers to columns in A */
1488 double knobs [COLAMD_KNOBS],/* parameters (uses defaults if NULL) */
1489 Int stats [COLAMD_STATS] /* output statistics and error codes */
1490 )
1491 {
1492 /* === Local variables ================================================== */
1493
1494 Int i ; /* loop index */
1495 Int nnz ; /* nonzeros in A */
1496 size_t Row_size ; /* size of Row [], in integers */
1497 size_t Col_size ; /* size of Col [], in integers */
1498 size_t need ; /* minimum required length of A */
1499 Colamd_Row *Row ; /* pointer into A of Row [0..n_row] array */
1500 Colamd_Col *Col ; /* pointer into A of Col [0..n_col] array */
1501 Int n_col2 ; /* number of non-dense, non-empty columns */
1502 Int n_row2 ; /* number of non-dense, non-empty rows */
1503 Int ngarbage ; /* number of garbage collections performed */
1504 Int max_deg ; /* maximum row degree */
1505 double default_knobs [COLAMD_KNOBS] ; /* default knobs array */
1506 Int aggressive ; /* do aggressive absorption */
1507 int ok ;
1508
1509 #ifndef NDEBUG
1510 colamd_get_debug ("colamd") ;
1511 #endif /* NDEBUG */
1512
1513 /* === Check the input arguments ======================================== */
1514
1515 if (!stats)
1516 {
1517 DEBUG0 (("colamd: stats not present\n")) ;
1518 return (FALSE) ;
1519 }
1520 for (i = 0 ; i < COLAMD_STATS ; i++)
1521 {
1522 stats [i] = 0 ;
1523 }
1524 stats [COLAMD_STATUS] = COLAMD_OK ;
1525 stats [COLAMD_INFO1] = -1 ;
1526 stats [COLAMD_INFO2] = -1 ;
1527
1528 if (!A) /* A is not present */
1529 {
1530 stats [COLAMD_STATUS] = COLAMD_ERROR_A_not_present ;
1531 DEBUG0 (("colamd: A not present\n")) ;
1532 return (FALSE) ;
1533 }
1534
1535 if (!p) /* p is not present */
1536 {
1537 stats [COLAMD_STATUS] = COLAMD_ERROR_p_not_present ;
1538 DEBUG0 (("colamd: p not present\n")) ;
1539 return (FALSE) ;
1540 }
1541
1542 if (n_row < 0) /* n_row must be >= 0 */
1543 {
1544 stats [COLAMD_STATUS] = COLAMD_ERROR_nrow_negative ;
1545 stats [COLAMD_INFO1] = n_row ;
1546 DEBUG0 (("colamd: nrow negative %d\n", n_row)) ;
1547 return (FALSE) ;
1548 }
1549
1550 if (n_col < 0) /* n_col must be >= 0 */
1551 {
1552 stats [COLAMD_STATUS] = COLAMD_ERROR_ncol_negative ;
1553 stats [COLAMD_INFO1] = n_col ;
1554 DEBUG0 (("colamd: ncol negative %d\n", n_col)) ;
1555 return (FALSE) ;
1556 }
1557
1558 nnz = p [n_col] ;
1559 if (nnz < 0) /* nnz must be >= 0 */
1560 {
1561 stats [COLAMD_STATUS] = COLAMD_ERROR_nnz_negative ;
1562 stats [COLAMD_INFO1] = nnz ;
1563 DEBUG0 (("colamd: number of entries negative %d\n", nnz)) ;
1564 return (FALSE) ;
1565 }
1566
1567 if (p [0] != 0)
1568 {
1569 stats [COLAMD_STATUS] = COLAMD_ERROR_p0_nonzero ;
1570 stats [COLAMD_INFO1] = p [0] ;
1571 DEBUG0 (("colamd: p[0] not zero %d\n", p [0])) ;
1572 return (FALSE) ;
1573 }
1574
1575 /* === If no knobs, set default knobs =================================== */
1576
1577 if (!knobs)
1578 {
1579 COLAMD_set_defaults (default_knobs) ;
1580 knobs = default_knobs ;
1581 }
1582
1583 aggressive = (knobs [COLAMD_AGGRESSIVE] != FALSE) ;
1584
1585 /* === Allocate the Row and Col arrays from array A ===================== */
1586
1587 ok = TRUE ;
1588 Col_size = COLAMD_C (n_col, &ok) ; /* size of Col array of structs */
1589 Row_size = COLAMD_R (n_row, &ok) ; /* size of Row array of structs */
1590
1591 /* need = 2*nnz + n_col + Col_size + Row_size ; */
1592 need = t_mult (nnz, 2, &ok) ;
1593 need = t_add (need, n_col, &ok) ;
1594 need = t_add (need, Col_size, &ok) ;
1595 need = t_add (need, Row_size, &ok) ;
1596
1597 if (!ok || need > (size_t) Alen || need > Int_MAX)
1598 {
1599 /* not enough space in array A to perform the ordering */
1600 stats [COLAMD_STATUS] = COLAMD_ERROR_A_too_small ;
1601 stats [COLAMD_INFO1] = need ;
1602 stats [COLAMD_INFO2] = Alen ;
1603 DEBUG0 (("colamd: Need Alen >= %d, given only Alen = %d\n", need,Alen));
1604 return (FALSE) ;
1605 }
1606
1607 Alen -= Col_size + Row_size ;
1608 Col = (Colamd_Col *) &A [Alen] ;
1609 Row = (Colamd_Row *) &A [Alen + Col_size] ;
1610
1611 /* === Construct the row and column data structures ===================== */
1612
1613 if (!init_rows_cols (n_row, n_col, Row, Col, A, p, stats))
1614 {
1615 /* input matrix is invalid */
1616 DEBUG0 (("colamd: Matrix invalid\n")) ;
1617 return (FALSE) ;
1618 }
1619
1620 /* === Initialize scores, kill dense rows/columns ======================= */
1621
1622 init_scoring (n_row, n_col, Row, Col, A, p, knobs,
1623 &n_row2, &n_col2, &max_deg) ;
1624
1625 /* === Order the supercolumns =========================================== */
1626
1627 ngarbage = find_ordering (n_row, n_col, Alen, Row, Col, A, p,
1628 n_col2, max_deg, 2*nnz, aggressive) ;
1629
1630 /* === Order the non-principal columns ================================== */
1631
1632 order_children (n_col, Col, p) ;
1633
1634 /* === Return statistics in stats ======================================= */
1635
1636 stats [COLAMD_DENSE_ROW] = n_row - n_row2 ;
1637 stats [COLAMD_DENSE_COL] = n_col - n_col2 ;
1638 stats [COLAMD_DEFRAG_COUNT] = ngarbage ;
1639 DEBUG0 (("colamd: done.\n")) ;
1640 return (TRUE) ;
1641 }
1642
1643
1644 /* ========================================================================== */
1645 /* === colamd_report ======================================================== */
1646 /* ========================================================================== */
1647
1648 PUBLIC void COLAMD_report
1649 (
1650 Int stats [COLAMD_STATS]
1651 )
1652 {
1653 print_report ("colamd", stats) ;
1654 }
1655
1656
1657 /* ========================================================================== */
1658 /* === symamd_report ======================================================== */
1659 /* ========================================================================== */
1660
1661 PUBLIC void SYMAMD_report
1662 (
1663 Int stats [COLAMD_STATS]
1664 )
1665 {
1666 print_report ("symamd", stats) ;
1667 }
1668
1669
1670
1671 /* ========================================================================== */
1672 /* === NON-USER-CALLABLE ROUTINES: ========================================== */
1673 /* ========================================================================== */
1674
1675 /* There are no user-callable routines beyond this point in the file */
1676
1677
1678 /* ========================================================================== */
1679 /* === init_rows_cols ======================================================= */
1680 /* ========================================================================== */
1681
1682 /*
1683 Takes the column form of the matrix in A and creates the row form of the
1684 matrix. Also, row and column attributes are stored in the Col and Row
1685 structs. If the columns are un-sorted or contain duplicate row indices,
1686 this routine will also sort and remove duplicate row indices from the
1687 column form of the matrix. Returns FALSE if the matrix is invalid,
1688 TRUE otherwise. Not user-callable.
1689 */
1690
1691 PRIVATE Int init_rows_cols /* returns TRUE if OK, or FALSE otherwise */
1692 (
1693 /* === Parameters ======================================================= */
1694
1695 Int n_row, /* number of rows of A */
1696 Int n_col, /* number of columns of A */
1697 Colamd_Row Row [], /* of size n_row+1 */
1698 Colamd_Col Col [], /* of size n_col+1 */
1699 Int A [], /* row indices of A, of size Alen */
1700 Int p [], /* pointers to columns in A, of size n_col+1 */
1701 Int stats [COLAMD_STATS] /* colamd statistics */
1702 )
1703 {
1704 /* === Local variables ================================================== */
1705
1706 Int col ; /* a column index */
1707 Int row ; /* a row index */
1708 Int *cp ; /* a column pointer */
1709 Int *cp_end ; /* a pointer to the end of a column */
1710 Int *rp ; /* a row pointer */
1711 Int *rp_end ; /* a pointer to the end of a row */
1712 Int last_row ; /* previous row */
1713
1714 /* === Initialize columns, and check column pointers ==================== */
1715
1716 for (col = 0 ; col < n_col ; col++)
1717 {
1718 Col [col].start = p [col] ;
1719 Col [col].length = p [col+1] - p [col] ;
1720
1721 if (Col [col].length < 0)
1722 {
1723 /* column pointers must be non-decreasing */
1724 stats [COLAMD_STATUS] = COLAMD_ERROR_col_length_negative ;
1725 stats [COLAMD_INFO1] = col ;
1726 stats [COLAMD_INFO2] = Col [col].length ;
1727 DEBUG0 (("colamd: col %d length %d < 0\n", col, Col [col].length)) ;
1728 return (FALSE) ;
1729 }
1730
1731 Col [col].shared1.thickness = 1 ;
1732 Col [col].shared2.score = 0 ;
1733 Col [col].shared3.prev = EMPTY ;
1734 Col [col].shared4.degree_next = EMPTY ;
1735 }
1736
1737 /* p [0..n_col] no longer needed, used as "head" in subsequent routines */
1738
1739 /* === Scan columns, compute row degrees, and check row indices ========= */
1740
1741 stats [COLAMD_INFO3] = 0 ; /* number of duplicate or unsorted row indices*/
1742
1743 for (row = 0 ; row < n_row ; row++)
1744 {
1745 Row [row].length = 0 ;
1746 Row [row].shared2.mark = -1 ;
1747 }
1748
1749 for (col = 0 ; col < n_col ; col++)
1750 {
1751 last_row = -1 ;
1752
1753 cp = &A [p [col]] ;
1754 cp_end = &A [p [col+1]] ;
1755
1756 while (cp < cp_end)
1757 {
1758 row = *cp++ ;
1759
1760 /* make sure row indices within range */
1761 if (row < 0 || row >= n_row)
1762 {
1763 stats [COLAMD_STATUS] = COLAMD_ERROR_row_index_out_of_bounds ;
1764 stats [COLAMD_INFO1] = col ;
1765 stats [COLAMD_INFO2] = row ;
1766 stats [COLAMD_INFO3] = n_row ;
1767 DEBUG0 (("colamd: row %d col %d out of bounds\n", row, col)) ;
1768 return (FALSE) ;
1769 }
1770
1771 if (row <= last_row || Row [row].shared2.mark == col)
1772 {
1773 /* row index are unsorted or repeated (or both), thus col */
1774 /* is jumbled. This is a notice, not an error condition. */
1775 stats [COLAMD_STATUS] = COLAMD_OK_BUT_JUMBLED ;
1776 stats [COLAMD_INFO1] = col ;
1777 stats [COLAMD_INFO2] = row ;
1778 (stats [COLAMD_INFO3]) ++ ;
1779 DEBUG1 (("colamd: row %d col %d unsorted/duplicate\n",row,col));
1780 }
1781
1782 if (Row [row].shared2.mark != col)
1783 {
1784 Row [row].length++ ;
1785 }
1786 else
1787 {
1788 /* this is a repeated entry in the column, */
1789 /* it will be removed */
1790 Col [col].length-- ;
1791 }
1792
1793 /* mark the row as having been seen in this column */
1794 Row [row].shared2.mark = col ;
1795
1796 last_row = row ;
1797 }
1798 }
1799
1800 /* === Compute row pointers ============================================= */
1801
1802 /* row form of the matrix starts directly after the column */
1803 /* form of matrix in A */
1804 Row [0].start = p [n_col] ;
1805 Row [0].shared1.p = Row [0].start ;
1806 Row [0].shared2.mark = -1 ;
1807 for (row = 1 ; row < n_row ; row++)
1808 {
1809 Row [row].start = Row [row-1].start + Row [row-1].length ;
1810 Row [row].shared1.p = Row [row].start ;
1811 Row [row].shared2.mark = -1 ;
1812 }
1813
1814 /* === Create row form ================================================== */
1815
1816 if (stats [COLAMD_STATUS] == COLAMD_OK_BUT_JUMBLED)
1817 {
1818 /* if cols jumbled, watch for repeated row indices */
1819 for (col = 0 ; col < n_col ; col++)
1820 {
1821 cp = &A [p [col]] ;
1822 cp_end = &A [p [col+1]] ;
1823 while (cp < cp_end)
1824 {
1825 row = *cp++ ;
1826 if (Row [row].shared2.mark != col)
1827 {
1828 A [(Row [row].shared1.p)++] = col ;
1829 Row [row].shared2.mark = col ;
1830 }
1831 }
1832 }
1833 }
1834 else
1835 {
1836 /* if cols not jumbled, we don't need the mark (this is faster) */
1837 for (col = 0 ; col < n_col ; col++)
1838 {
1839 cp = &A [p [col]] ;
1840 cp_end = &A [p [col+1]] ;
1841 while (cp < cp_end)
1842 {
1843 A [(Row [*cp++].shared1.p)++] = col ;
1844 }
1845 }
1846 }
1847
1848 /* === Clear the row marks and set row degrees ========================== */
1849
1850 for (row = 0 ; row < n_row ; row++)
1851 {
1852 Row [row].shared2.mark = 0 ;
1853 Row [row].shared1.degree = Row [row].length ;
1854 }
1855
1856 /* === See if we need to re-create columns ============================== */
1857
1858 if (stats [COLAMD_STATUS] == COLAMD_OK_BUT_JUMBLED)
1859 {
1860 DEBUG0 (("colamd: reconstructing column form, matrix jumbled\n")) ;
1861
1862 #ifndef NDEBUG
1863 /* make sure column lengths are correct */
1864 for (col = 0 ; col < n_col ; col++)
1865 {
1866 p [col] = Col [col].length ;
1867 }
1868 for (row = 0 ; row < n_row ; row++)
1869 {
1870 rp = &A [Row [row].start] ;
1871 rp_end = rp + Row [row].length ;
1872 while (rp < rp_end)
1873 {
1874 p [*rp++]-- ;
1875 }
1876 }
1877 for (col = 0 ; col < n_col ; col++)
1878 {
1879 ASSERT (p [col] == 0) ;
1880 }
1881 /* now p is all zero (different than when debugging is turned off) */
1882 #endif /* NDEBUG */
1883
1884 /* === Compute col pointers ========================================= */
1885
1886 /* col form of the matrix starts at A [0]. */
1887 /* Note, we may have a gap between the col form and the row */
1888 /* form if there were duplicate entries, if so, it will be */
1889 /* removed upon the first garbage collection */
1890 Col [0].start = 0 ;
1891 p [0] = Col [0].start ;
1892 for (col = 1 ; col < n_col ; col++)
1893 {
1894 /* note that the lengths here are for pruned columns, i.e. */
1895 /* no duplicate row indices will exist for these columns */
1896 Col [col].start = Col [col-1].start + Col [col-1].length ;
1897 p [col] = Col [col].start ;
1898 }
1899
1900 /* === Re-create col form =========================================== */
1901
1902 for (row = 0 ; row < n_row ; row++)
1903 {
1904 rp = &A [Row [row].start] ;
1905 rp_end = rp + Row [row].length ;
1906 while (rp < rp_end)
1907 {
1908 A [(p [*rp++])++] = row ;
1909 }
1910 }
1911 }
1912
1913 /* === Done. Matrix is not (or no longer) jumbled ====================== */
1914
1915 return (TRUE) ;
1916 }
1917
1918
1919 /* ========================================================================== */
1920 /* === init_scoring ========================================================= */
1921 /* ========================================================================== */
1922
1923 /*
1924 Kills dense or empty columns and rows, calculates an initial score for
1925 each column, and places all columns in the degree lists. Not user-callable.
1926 */
1927
1928 PRIVATE void init_scoring
1929 (
1930 /* === Parameters ======================================================= */
1931
1932 Int n_row, /* number of rows of A */
1933 Int n_col, /* number of columns of A */
1934 Colamd_Row Row [], /* of size n_row+1 */
1935 Colamd_Col Col [], /* of size n_col+1 */
1936 Int A [], /* column form and row form of A */
1937 Int head [], /* of size n_col+1 */
1938 double knobs [COLAMD_KNOBS],/* parameters */
1939 Int *p_n_row2, /* number of non-dense, non-empty rows */
1940 Int *p_n_col2, /* number of non-dense, non-empty columns */
1941 Int *p_max_deg /* maximum row degree */
1942 )
1943 {
1944 /* === Local variables ================================================== */
1945
1946 Int c ; /* a column index */
1947 Int r, row ; /* a row index */
1948 Int *cp ; /* a column pointer */
1949 Int deg ; /* degree of a row or column */
1950 Int *cp_end ; /* a pointer to the end of a column */
1951 Int *new_cp ; /* new column pointer */
1952 Int col_length ; /* length of pruned column */
1953 Int score ; /* current column score */
1954 Int n_col2 ; /* number of non-dense, non-empty columns */
1955 Int n_row2 ; /* number of non-dense, non-empty rows */
1956 Int dense_row_count ; /* remove rows with more entries than this */
1957 Int dense_col_count ; /* remove cols with more entries than this */
1958 Int min_score ; /* smallest column score */
1959 Int max_deg ; /* maximum row degree */
1960 Int next_col ; /* Used to add to degree list.*/
1961
1962 #ifndef NDEBUG
1963 Int debug_count ; /* debug only. */
1964 #endif /* NDEBUG */
1965
1966 /* === Extract knobs ==================================================== */
1967
1968 /* Note: if knobs contains a NaN, this is undefined: */
1969 if (knobs [COLAMD_DENSE_ROW] < 0)
1970 {
1971 /* only remove completely dense rows */
1972 dense_row_count = n_col-1 ;
1973 }
1974 else
1975 {
1976 dense_row_count = DENSE_DEGREE (knobs [COLAMD_DENSE_ROW], n_col) ;
1977 }
1978 if (knobs [COLAMD_DENSE_COL] < 0)
1979 {
1980 /* only remove completely dense columns */
1981 dense_col_count = n_row-1 ;
1982 }
1983 else
1984 {
1985 dense_col_count =
1986 DENSE_DEGREE (knobs [COLAMD_DENSE_COL], MIN (n_row, n_col)) ;
1987 }
1988
1989 DEBUG1 (("colamd: densecount: %d %d\n", dense_row_count, dense_col_count)) ;
1990 max_deg = 0 ;
1991 n_col2 = n_col ;
1992 n_row2 = n_row ;
1993
1994 /* === Kill empty columns =============================================== */
1995
1996 /* Put the empty columns at the end in their natural order, so that LU */
1997 /* factorization can proceed as far as possible. */
1998 for (c = n_col-1 ; c >= 0 ; c--)
1999 {
2000 deg = Col [c].length ;
2001 if (deg == 0)
2002 {
2003 /* this is a empty column, kill and order it last */
2004 Col [c].shared2.order = --n_col2 ;
2005 KILL_PRINCIPAL_COL (c) ;
2006 }
2007 }
2008 DEBUG1 (("colamd: null columns killed: %d\n", n_col - n_col2)) ;
2009
2010 /* === Kill dense columns =============================================== */
2011
2012 /* Put the dense columns at the end, in their natural order */
2013 for (c = n_col-1 ; c >= 0 ; c--)
2014 {
2015 /* skip any dead columns */
2016 if (COL_IS_DEAD (c))
2017 {
2018 continue ;
2019 }
2020 deg = Col [c].length ;
2021 if (deg > dense_col_count)
2022 {
2023 /* this is a dense column, kill and order it last */
2024 Col [c].shared2.order = --n_col2 ;
2025 /* decrement the row degrees */
2026 cp = &A [Col [c].start] ;
2027 cp_end = cp + Col [c].length ;
2028 while (cp < cp_end)
2029 {
2030 Row [*cp++].shared1.degree-- ;
2031 }
2032 KILL_PRINCIPAL_COL (c) ;
2033 }
2034 }
2035 DEBUG1 (("colamd: Dense and null columns killed: %d\n", n_col - n_col2)) ;
2036
2037 /* === Kill dense and empty rows ======================================== */
2038
2039 for (r = 0 ; r < n_row ; r++)
2040 {
2041 deg = Row [r].shared1.degree ;
2042 ASSERT (deg >= 0 && deg <= n_col) ;
2043 if (deg > dense_row_count || deg == 0)
2044 {
2045 /* kill a dense or empty row */
2046 KILL_ROW (r) ;
2047 --n_row2 ;
2048 }
2049 else
2050 {
2051 /* keep track of max degree of remaining rows */
2052 max_deg = MAX (max_deg, deg) ;
2053 }
2054 }
2055 DEBUG1 (("colamd: Dense and null rows killed: %d\n", n_row - n_row2)) ;
2056
2057 /* === Compute initial column scores ==================================== */
2058
2059 /* At this point the row degrees are accurate. They reflect the number */
2060 /* of "live" (non-dense) columns in each row. No empty rows exist. */
2061 /* Some "live" columns may contain only dead rows, however. These are */
2062 /* pruned in the code below. */
2063
2064 /* now find the initial matlab score for each column */
2065 for (c = n_col-1 ; c >= 0 ; c--)
2066 {
2067 /* skip dead column */
2068 if (COL_IS_DEAD (c))
2069 {
2070 continue ;
2071 }
2072 score = 0 ;
2073 cp = &A [Col [c].start] ;
2074 new_cp = cp ;
2075 cp_end = cp + Col [c].length ;
2076 while (cp < cp_end)
2077 {
2078 /* get a row */
2079 row = *cp++ ;
2080 /* skip if dead */
2081 if (ROW_IS_DEAD (row))
2082 {
2083 continue ;
2084 }
2085 /* compact the column */
2086 *new_cp++ = row ;
2087 /* add row's external degree */
2088 score += Row [row].shared1.degree - 1 ;
2089 /* guard against integer overflow */
2090 score = MIN (score, n_col) ;
2091 }
2092 /* determine pruned column length */
2093 col_length = (Int) (new_cp - &A [Col [c].start]) ;
2094 if (col_length == 0)
2095 {
2096 /* a newly-made null column (all rows in this col are "dense" */
2097 /* and have already been killed) */
2098 DEBUG2 (("Newly null killed: %d\n", c)) ;
2099 Col [c].shared2.order = --n_col2 ;
2100 KILL_PRINCIPAL_COL (c) ;
2101 }
2102 else
2103 {
2104 /* set column length and set score */
2105 ASSERT (score >= 0) ;
2106 ASSERT (score <= n_col) ;
2107 Col [c].length = col_length ;
2108 Col [c].shared2.score = score ;
2109 }
2110 }
2111 DEBUG1 (("colamd: Dense, null, and newly-null columns killed: %d\n",
2112 n_col-n_col2)) ;
2113
2114 /* At this point, all empty rows and columns are dead. All live columns */
2115 /* are "clean" (containing no dead rows) and simplicial (no supercolumns */
2116 /* yet). Rows may contain dead columns, but all live rows contain at */
2117 /* least one live column. */
2118
2119 #ifndef NDEBUG
2120 debug_structures (n_row, n_col, Row, Col, A, n_col2) ;
2121 #endif /* NDEBUG */
2122
2123 /* === Initialize degree lists ========================================== */
2124
2125 #ifndef NDEBUG
2126 debug_count = 0 ;
2127 #endif /* NDEBUG */
2128
2129 /* clear the hash buckets */
2130 for (c = 0 ; c <= n_col ; c++)
2131 {
2132 head [c] = EMPTY ;
2133 }
2134 min_score = n_col ;
2135 /* place in reverse order, so low column indices are at the front */
2136 /* of the lists. This is to encourage natural tie-breaking */
2137 for (c = n_col-1 ; c >= 0 ; c--)
2138 {
2139 /* only add principal columns to degree lists */
2140 if (COL_IS_ALIVE (c))
2141 {
2142 DEBUG4 (("place %d score %d minscore %d ncol %d\n",
2143 c, Col [c].shared2.score, min_score, n_col)) ;
2144
2145 /* === Add columns score to DList =============================== */
2146
2147 score = Col [c].shared2.score ;
2148
2149 ASSERT (min_score >= 0) ;
2150 ASSERT (min_score <= n_col) ;
2151 ASSERT (score >= 0) ;
2152 ASSERT (score <= n_col) ;
2153 ASSERT (head [score] >= EMPTY) ;
2154
2155 /* now add this column to dList at proper score location */
2156 next_col = head [score] ;
2157 Col [c].shared3.prev = EMPTY ;
2158 Col [c].shared4.degree_next = next_col ;
2159
2160 /* if there already was a column with the same score, set its */
2161 /* previous pointer to this new column */
2162 if (next_col != EMPTY)
2163 {
2164 Col [next_col].shared3.prev = c ;
2165 }
2166 head [score] = c ;
2167
2168 /* see if this score is less than current min */
2169 min_score = MIN (min_score, score) ;
2170
2171 #ifndef NDEBUG
2172 debug_count++ ;
2173 #endif /* NDEBUG */
2174
2175 }
2176 }
2177
2178 #ifndef NDEBUG
2179 DEBUG1 (("colamd: Live cols %d out of %d, non-princ: %d\n",
2180 debug_count, n_col, n_col-debug_count)) ;
2181 ASSERT (debug_count == n_col2) ;
2182 debug_deg_lists (n_row, n_col, Row, Col, head, min_score, n_col2, max_deg) ;
2183 #endif /* NDEBUG */
2184
2185 /* === Return number of remaining columns, and max row degree =========== */
2186
2187 *p_n_col2 = n_col2 ;
2188 *p_n_row2 = n_row2 ;
2189 *p_max_deg = max_deg ;
2190 }
2191
2192
2193 /* ========================================================================== */
2194 /* === find_ordering ======================================================== */
2195 /* ========================================================================== */
2196
2197 /*
2198 Order the principal columns of the supercolumn form of the matrix
2199 (no supercolumns on input). Uses a minimum approximate column minimum
2200 degree ordering method. Not user-callable.
2201 */
2202
2203 PRIVATE Int find_ordering /* return the number of garbage collections */
2204 (
2205 /* === Parameters ======================================================= */
2206
2207 Int n_row, /* number of rows of A */
2208 Int n_col, /* number of columns of A */
2209 Int Alen, /* size of A, 2*nnz + n_col or larger */
2210 Colamd_Row Row [], /* of size n_row+1 */
2211 Colamd_Col Col [], /* of size n_col+1 */
2212 Int A [], /* column form and row form of A */
2213 Int head [], /* of size n_col+1 */
2214 Int n_col2, /* Remaining columns to order */
2215 Int max_deg, /* Maximum row degree */
2216 Int pfree, /* index of first free slot (2*nnz on entry) */
2217 Int aggressive
2218 )
2219 {
2220 /* === Local variables ================================================== */
2221
2222 Int k ; /* current pivot ordering step */
2223 Int pivot_col ; /* current pivot column */
2224 Int *cp ; /* a column pointer */
2225 Int *rp ; /* a row pointer */
2226 Int pivot_row ; /* current pivot row */
2227 Int *new_cp ; /* modified column pointer */
2228 Int *new_rp ; /* modified row pointer */
2229 Int pivot_row_start ; /* pointer to start of pivot row */
2230 Int pivot_row_degree ; /* number of columns in pivot row */
2231 Int pivot_row_length ; /* number of supercolumns in pivot row */
2232 Int pivot_col_score ; /* score of pivot column */
2233 Int needed_memory ; /* free space needed for pivot row */
2234 Int *cp_end ; /* pointer to the end of a column */
2235 Int *rp_end ; /* pointer to the end of a row */
2236 Int row ; /* a row index */
2237 Int col ; /* a column index */
2238 Int max_score ; /* maximum possible score */
2239 Int cur_score ; /* score of current column */
2240 unsigned Int hash ; /* hash value for supernode detection */
2241 Int head_column ; /* head of hash bucket */
2242 Int first_col ; /* first column in hash bucket */
2243 Int tag_mark ; /* marker value for mark array */
2244 Int row_mark ; /* Row [row].shared2.mark */
2245 Int set_difference ; /* set difference size of row with pivot row */
2246 Int min_score ; /* smallest column score */
2247 Int col_thickness ; /* "thickness" (no. of columns in a supercol) */
2248 Int max_mark ; /* maximum value of tag_mark */
2249 Int pivot_col_thickness ; /* number of columns represented by pivot col */
2250 Int prev_col ; /* Used by Dlist operations. */
2251 Int next_col ; /* Used by Dlist operations. */
2252 Int ngarbage ; /* number of garbage collections performed */
2253
2254 #ifndef NDEBUG
2255 Int debug_d ; /* debug loop counter */
2256 Int debug_step = 0 ; /* debug loop counter */
2257 #endif /* NDEBUG */
2258
2259 /* === Initialization and clear mark ==================================== */
2260
2261 max_mark = INT_MAX - n_col ; /* INT_MAX defined in <limits.h> */
2262 tag_mark = clear_mark (0, max_mark, n_row, Row) ;
2263 min_score = 0 ;
2264 ngarbage = 0 ;
2265 DEBUG1 (("colamd: Ordering, n_col2=%d\n", n_col2)) ;
2266
2267 /* === Order the columns ================================================ */
2268
2269 for (k = 0 ; k < n_col2 ; /* 'k' is incremented below */)
2270 {
2271
2272 #ifndef NDEBUG
2273 if (debug_step % 100 == 0)
2274 {
2275 DEBUG2 (("\n... Step k: %d out of n_col2: %d\n", k, n_col2)) ;
2276 }
2277 else
2278 {
2279 DEBUG3 (("\n----------Step k: %d out of n_col2: %d\n", k, n_col2)) ;
2280 }
2281 debug_step++ ;
2282 debug_deg_lists (n_row, n_col, Row, Col, head,
2283 min_score, n_col2-k, max_deg) ;
2284 debug_matrix (n_row, n_col, Row, Col, A) ;
2285 #endif /* NDEBUG */
2286
2287 /* === Select pivot column, and order it ============================ */
2288
2289 /* make sure degree list isn't empty */
2290 ASSERT (min_score >= 0) ;
2291 ASSERT (min_score <= n_col) ;
2292 ASSERT (head [min_score] >= EMPTY) ;
2293
2294 #ifndef NDEBUG
2295 for (debug_d = 0 ; debug_d < min_score ; debug_d++)
2296 {
2297 ASSERT (head [debug_d] == EMPTY) ;
2298 }
2299 #endif /* NDEBUG */
2300
2301 /* get pivot column from head of minimum degree list */
2302 while (head [min_score] == EMPTY && min_score < n_col)
2303 {
2304 min_score++ ;
2305 }
2306 pivot_col = head [min_score] ;
2307 ASSERT (pivot_col >= 0 && pivot_col <= n_col) ;
2308 next_col = Col [pivot_col].shared4.degree_next ;
2309 head [min_score] = next_col ;
2310 if (next_col != EMPTY)
2311 {
2312 Col [next_col].shared3.prev = EMPTY ;
2313 }
2314
2315 ASSERT (COL_IS_ALIVE (pivot_col)) ;
2316
2317 /* remember score for defrag check */
2318 pivot_col_score = Col [pivot_col].shared2.score ;
2319
2320 /* the pivot column is the kth column in the pivot order */
2321 Col [pivot_col].shared2.order = k ;
2322
2323 /* increment order count by column thickness */
2324 pivot_col_thickness = Col [pivot_col].shared1.thickness ;
2325 k += pivot_col_thickness ;
2326 ASSERT (pivot_col_thickness > 0) ;
2327 DEBUG3 (("Pivot col: %d thick %d\n", pivot_col, pivot_col_thickness)) ;
2328
2329 /* === Garbage_collection, if necessary ============================= */
2330
2331 needed_memory = MIN (pivot_col_score, n_col - k) ;
2332 if (pfree + needed_memory >= Alen)
2333 {
2334 pfree = garbage_collection (n_row, n_col, Row, Col, A, &A [pfree]) ;
2335 ngarbage++ ;
2336 /* after garbage collection we will have enough */
2337 ASSERT (pfree + needed_memory < Alen) ;
2338 /* garbage collection has wiped out the Row[].shared2.mark array */
2339 tag_mark = clear_mark (0, max_mark, n_row, Row) ;
2340
2341 #ifndef NDEBUG
2342 debug_matrix (n_row, n_col, Row, Col, A) ;
2343 #endif /* NDEBUG */
2344 }
2345
2346 /* === Compute pivot row pattern ==================================== */
2347
2348 /* get starting location for this new merged row */
2349 pivot_row_start = pfree ;
2350
2351 /* initialize new row counts to zero */
2352 pivot_row_degree = 0 ;
2353
2354 /* tag pivot column as having been visited so it isn't included */
2355 /* in merged pivot row */
2356 Col [pivot_col].shared1.thickness = -pivot_col_thickness ;
2357
2358 /* pivot row is the union of all rows in the pivot column pattern */
2359 cp = &A [Col [pivot_col].start] ;
2360 cp_end = cp + Col [pivot_col].length ;
2361 while (cp < cp_end)
2362 {
2363 /* get a row */
2364 row = *cp++ ;
2365 DEBUG4 (("Pivot col pattern %d %d\n", ROW_IS_ALIVE (row), row)) ;
2366 /* skip if row is dead */
2367 if (ROW_IS_ALIVE (row))
2368 {
2369 rp = &A [Row [row].start] ;
2370 rp_end = rp + Row [row].length ;
2371 while (rp < rp_end)
2372 {
2373 /* get a column */
2374 col = *rp++ ;
2375 /* add the column, if alive and untagged */
2376 col_thickness = Col [col].shared1.thickness ;
2377 if (col_thickness > 0 && COL_IS_ALIVE (col))
2378 {
2379 /* tag column in pivot row */
2380 Col [col].shared1.thickness = -col_thickness ;
2381 ASSERT (pfree < Alen) ;
2382 /* place column in pivot row */
2383 A [pfree++] = col ;
2384 pivot_row_degree += col_thickness ;
2385 }
2386 }
2387 }
2388 }
2389
2390 /* clear tag on pivot column */
2391 Col [pivot_col].shared1.thickness = pivot_col_thickness ;
2392 max_deg = MAX (max_deg, pivot_row_degree) ;
2393
2394 #ifndef NDEBUG
2395 DEBUG3 (("check2\n")) ;
2396 debug_mark (n_row, Row, tag_mark, max_mark) ;
2397 #endif /* NDEBUG */
2398
2399 /* === Kill all rows used to construct pivot row ==================== */
2400
2401 /* also kill pivot row, temporarily */
2402 cp = &A [Col [pivot_col].start] ;
2403 cp_end = cp + Col [pivot_col].length ;
2404 while (cp < cp_end)
2405 {
2406 /* may be killing an already dead row */
2407 row = *cp++ ;
2408 DEBUG3 (("Kill row in pivot col: %d\n", row)) ;
2409 KILL_ROW (row) ;
2410 }
2411
2412 /* === Select a row index to use as the new pivot row =============== */
2413
2414 pivot_row_length = pfree - pivot_row_start ;
2415 if (pivot_row_length > 0)
2416 {
2417 /* pick the "pivot" row arbitrarily (first row in col) */
2418 pivot_row = A [Col [pivot_col].start] ;
2419 DEBUG3 (("Pivotal row is %d\n", pivot_row)) ;
2420 }
2421 else
2422 {
2423 /* there is no pivot row, since it is of zero length */
2424 pivot_row = EMPTY ;
2425 ASSERT (pivot_row_length == 0) ;
2426 }
2427 ASSERT (Col [pivot_col].length > 0 || pivot_row_length == 0) ;
2428
2429 /* === Approximate degree computation =============================== */
2430
2431 /* Here begins the computation of the approximate degree. The column */
2432 /* score is the sum of the pivot row "length", plus the size of the */
2433 /* set differences of each row in the column minus the pattern of the */
2434 /* pivot row itself. The column ("thickness") itself is also */
2435 /* excluded from the column score (we thus use an approximate */
2436 /* external degree). */
2437
2438 /* The time taken by the following code (compute set differences, and */
2439 /* add them up) is proportional to the size of the data structure */
2440 /* being scanned - that is, the sum of the sizes of each column in */
2441 /* the pivot row. Thus, the amortized time to compute a column score */
2442 /* is proportional to the size of that column (where size, in this */
2443 /* context, is the column "length", or the number of row indices */
2444 /* in that column). The number of row indices in a column is */
2445 /* monotonically non-decreasing, from the length of the original */
2446 /* column on input to colamd. */
2447
2448 /* === Compute set differences ====================================== */
2449
2450 DEBUG3 (("** Computing set differences phase. **\n")) ;
2451
2452 /* pivot row is currently dead - it will be revived later. */
2453
2454 DEBUG3 (("Pivot row: ")) ;
2455 /* for each column in pivot row */
2456 rp = &A [pivot_row_start] ;
2457 rp_end = rp + pivot_row_length ;
2458 while (rp < rp_end)
2459 {
2460 col = *rp++ ;
2461 ASSERT (COL_IS_ALIVE (col) && col != pivot_col) ;
2462 DEBUG3 (("Col: %d\n", col)) ;
2463
2464 /* clear tags used to construct pivot row pattern */
2465 col_thickness = -Col [col].shared1.thickness ;
2466 ASSERT (col_thickness > 0) ;
2467 Col [col].shared1.thickness = col_thickness ;
2468
2469 /* === Remove column from degree list =========================== */
2470
2471 cur_score = Col [col].shared2.score ;
2472 prev_col = Col [col].shared3.prev ;
2473 next_col = Col [col].shared4.degree_next ;
2474 ASSERT (cur_score >= 0) ;
2475 ASSERT (cur_score <= n_col) ;
2476 ASSERT (cur_score >= EMPTY) ;
2477 if (prev_col == EMPTY)
2478 {
2479 head [cur_score] = next_col ;
2480 }
2481 else
2482 {
2483 Col [prev_col].shared4.degree_next = next_col ;
2484 }
2485 if (next_col != EMPTY)
2486 {
2487 Col [next_col].shared3.prev = prev_col ;
2488 }
2489
2490 /* === Scan the column ========================================== */
2491
2492 cp = &A [Col [col].start] ;
2493 cp_end = cp + Col [col].length ;
2494 while (cp < cp_end)
2495 {
2496 /* get a row */
2497 row = *cp++ ;
2498 row_mark = Row [row].shared2.mark ;
2499 /* skip if dead */
2500 if (ROW_IS_MARKED_DEAD (row_mark))
2501 {
2502 continue ;
2503 }
2504 ASSERT (row != pivot_row) ;
2505 set_difference = row_mark - tag_mark ;
2506 /* check if the row has been seen yet */
2507 if (set_difference < 0)
2508 {
2509 ASSERT (Row [row].shared1.degree <= max_deg) ;
2510 set_difference = Row [row].shared1.degree ;
2511 }
2512 /* subtract column thickness from this row's set difference */
2513 set_difference -= col_thickness ;
2514 ASSERT (set_difference >= 0) ;
2515 /* absorb this row if the set difference becomes zero */
2516 if (set_difference == 0 && aggressive)
2517 {
2518 DEBUG3 (("aggressive absorption. Row: %d\n", row)) ;
2519 KILL_ROW (row) ;
2520 }
2521 else
2522 {
2523 /* save the new mark */
2524 Row [row].shared2.mark = set_difference + tag_mark ;
2525 }
2526 }
2527 }
2528
2529 #ifndef NDEBUG
2530 debug_deg_lists (n_row, n_col, Row, Col, head,
2531 min_score, n_col2-k-pivot_row_degree, max_deg) ;
2532 #endif /* NDEBUG */
2533
2534 /* === Add up set differences for each column ======================= */
2535
2536 DEBUG3 (("** Adding set differences phase. **\n")) ;
2537
2538 /* for each column in pivot row */
2539 rp = &A [pivot_row_start] ;
2540 rp_end = rp + pivot_row_length ;
2541 while (rp < rp_end)
2542 {
2543 /* get a column */
2544 col = *rp++ ;
2545 ASSERT (COL_IS_ALIVE (col) && col != pivot_col) ;
2546 hash = 0 ;
2547 cur_score = 0 ;
2548 cp = &A [Col [col].start] ;
2549 /* compact the column */
2550 new_cp = cp ;
2551 cp_end = cp + Col [col].length ;
2552
2553 DEBUG4 (("Adding set diffs for Col: %d.\n", col)) ;
2554
2555 while (cp < cp_end)
2556 {
2557 /* get a row */
2558 row = *cp++ ;
2559 ASSERT(row >= 0 && row < n_row) ;
2560 row_mark = Row [row].shared2.mark ;
2561 /* skip if dead */
2562 if (ROW_IS_MARKED_DEAD (row_mark))
2563 {
2564 DEBUG4 ((" Row %d, dead\n", row)) ;
2565 continue ;
2566 }
2567 DEBUG4 ((" Row %d, set diff %d\n", row, row_mark-tag_mark));
2568 ASSERT (row_mark >= tag_mark) ;
2569 /* compact the column */
2570 *new_cp++ = row ;
2571 /* compute hash function */
2572 hash += row ;
2573 /* add set difference */
2574 cur_score += row_mark - tag_mark ;
2575 /* integer overflow... */
2576 cur_score = MIN (cur_score, n_col) ;
2577 }
2578
2579 /* recompute the column's length */
2580 Col [col].length = (Int) (new_cp - &A [Col [col].start]) ;
2581
2582 /* === Further mass elimination ================================= */
2583
2584 if (Col [col].length == 0)
2585 {
2586 DEBUG4 (("further mass elimination. Col: %d\n", col)) ;
2587 /* nothing left but the pivot row in this column */
2588 KILL_PRINCIPAL_COL (col) ;
2589 pivot_row_degree -= Col [col].shared1.thickness ;
2590 ASSERT (pivot_row_degree >= 0) ;
2591 /* order it */
2592 Col [col].shared2.order = k ;
2593 /* increment order count by column thickness */
2594 k += Col [col].shared1.thickness ;
2595 }
2596 else
2597 {
2598 /* === Prepare for supercolumn detection ==================== */
2599
2600 DEBUG4 (("Preparing supercol detection for Col: %d.\n", col)) ;
2601
2602 /* save score so far */
2603 Col [col].shared2.score = cur_score ;
2604
2605 /* add column to hash table, for supercolumn detection */
2606 hash %= n_col + 1 ;
2607
2608 DEBUG4 ((" Hash = %d, n_col = %d.\n", hash, n_col)) ;
2609 ASSERT (((Int) hash) <= n_col) ;
2610
2611 head_column = head [hash] ;
2612 if (head_column > EMPTY)
2613 {
2614 /* degree list "hash" is non-empty, use prev (shared3) of */
2615 /* first column in degree list as head of hash bucket */
2616 first_col = Col [head_column].shared3.headhash ;
2617 Col [head_column].shared3.headhash = col ;
2618 }
2619 else
2620 {
2621 /* degree list "hash" is empty, use head as hash bucket */
2622 first_col = - (head_column + 2) ;
2623 head [hash] = - (col + 2) ;
2624 }
2625 Col [col].shared4.hash_next = first_col ;
2626
2627 /* save hash function in Col [col].shared3.hash */
2628 Col [col].shared3.hash = (Int) hash ;
2629 ASSERT (COL_IS_ALIVE (col)) ;
2630 }
2631 }
2632
2633 /* The approximate external column degree is now computed. */
2634
2635 /* === Supercolumn detection ======================================== */
2636
2637 DEBUG3 (("** Supercolumn detection phase. **\n")) ;
2638
2639 detect_super_cols (
2640
2641 #ifndef NDEBUG
2642 n_col, Row,
2643 #endif /* NDEBUG */
2644
2645 Col, A, head, pivot_row_start, pivot_row_length) ;
2646
2647 /* === Kill the pivotal column ====================================== */
2648
2649 KILL_PRINCIPAL_COL (pivot_col) ;
2650
2651 /* === Clear mark =================================================== */
2652
2653 tag_mark = clear_mark (tag_mark+max_deg+1, max_mark, n_row, Row) ;
2654
2655 #ifndef NDEBUG
2656 DEBUG3 (("check3\n")) ;
2657 debug_mark (n_row, Row, tag_mark, max_mark) ;
2658 #endif /* NDEBUG */
2659
2660 /* === Finalize the new pivot row, and column scores ================ */
2661
2662 DEBUG3 (("** Finalize scores phase. **\n")) ;
2663
2664 /* for each column in pivot row */
2665 rp = &A [pivot_row_start] ;
2666 /* compact the pivot row */
2667 new_rp = rp ;
2668 rp_end = rp + pivot_row_length ;
2669 while (rp < rp_end)
2670 {
2671 col = *rp++ ;
2672 /* skip dead columns */
2673 if (COL_IS_DEAD (col))
2674 {
2675 continue ;
2676 }
2677 *new_rp++ = col ;
2678 /* add new pivot row to column */
2679 A [Col [col].start + (Col [col].length++)] = pivot_row ;
2680
2681 /* retrieve score so far and add on pivot row's degree. */
2682 /* (we wait until here for this in case the pivot */
2683 /* row's degree was reduced due to mass elimination). */
2684 cur_score = Col [col].shared2.score + pivot_row_degree ;
2685
2686 /* calculate the max possible score as the number of */
2687 /* external columns minus the 'k' value minus the */
2688 /* columns thickness */
2689 max_score = n_col - k - Col [col].shared1.thickness ;
2690
2691 /* make the score the external degree of the union-of-rows */
2692 cur_score -= Col [col].shared1.thickness ;
2693
2694 /* make sure score is less or equal than the max score */
2695 cur_score = MIN (cur_score, max_score) ;
2696 ASSERT (cur_score >= 0) ;
2697
2698 /* store updated score */
2699 Col [col].shared2.score = cur_score ;
2700
2701 /* === Place column back in degree list ========================= */
2702
2703 ASSERT (min_score >= 0) ;
2704 ASSERT (min_score <= n_col) ;
2705 ASSERT (cur_score >= 0) ;
2706 ASSERT (cur_score <= n_col) ;
2707 ASSERT (head [cur_score] >= EMPTY) ;
2708 next_col = head [cur_score] ;
2709 Col [col].shared4.degree_next = next_col ;
2710 Col [col].shared3.prev = EMPTY ;
2711 if (next_col != EMPTY)
2712 {
2713 Col [next_col].shared3.prev = col ;
2714 }
2715 head [cur_score] = col ;
2716
2717 /* see if this score is less than current min */
2718 min_score = MIN (min_score, cur_score) ;
2719
2720 }
2721
2722 #ifndef NDEBUG
2723 debug_deg_lists (n_row, n_col, Row, Col, head,
2724 min_score, n_col2-k, max_deg) ;
2725 #endif /* NDEBUG */
2726
2727 /* === Resurrect the new pivot row ================================== */
2728
2729 if (pivot_row_degree > 0)
2730 {
2731 /* update pivot row length to reflect any cols that were killed */
2732 /* during super-col detection and mass elimination */
2733 Row [pivot_row].start = pivot_row_start ;
2734 Row [pivot_row].length = (Int) (new_rp - &A[pivot_row_start]) ;
2735 ASSERT (Row [pivot_row].length > 0) ;
2736 Row [pivot_row].shared1.degree = pivot_row_degree ;
2737 Row [pivot_row].shared2.mark = 0 ;
2738 /* pivot row is no longer dead */
2739
2740 DEBUG1 (("Resurrect Pivot_row %d deg: %d\n",
2741 pivot_row, pivot_row_degree)) ;
2742 }
2743 }
2744
2745 /* === All principal columns have now been ordered ====================== */
2746
2747 return (ngarbage) ;
2748 }
2749
2750
2751 /* ========================================================================== */
2752 /* === order_children ======================================================= */
2753 /* ========================================================================== */
2754
2755 /*
2756 The find_ordering routine has ordered all of the principal columns (the
2757 representatives of the supercolumns). The non-principal columns have not
2758 yet been ordered. This routine orders those columns by walking up the
2759 parent tree (a column is a child of the column which absorbed it). The
2760 final permutation vector is then placed in p [0 ... n_col-1], with p [0]
2761 being the first column, and p [n_col-1] being the last. It doesn't look
2762 like it at first glance, but be assured that this routine takes time linear
2763 in the number of columns. Although not immediately obvious, the time
2764 taken by this routine is O (n_col), that is, linear in the number of
2765 columns. Not user-callable.
2766 */
2767
2768 PRIVATE void order_children
2769 (
2770 /* === Parameters ======================================================= */
2771
2772 Int n_col, /* number of columns of A */
2773 Colamd_Col Col [], /* of size n_col+1 */
2774 Int p [] /* p [0 ... n_col-1] is the column permutation*/
2775 )
2776 {
2777 /* === Local variables ================================================== */
2778
2779 Int i ; /* loop counter for all columns */
2780 Int c ; /* column index */
2781 Int parent ; /* index of column's parent */
2782 Int order ; /* column's order */
2783
2784 /* === Order each non-principal column ================================== */
2785
2786 for (i = 0 ; i < n_col ; i++)
2787 {
2788 /* find an un-ordered non-principal column */
2789 ASSERT (COL_IS_DEAD (i)) ;
2790 if (!COL_IS_DEAD_PRINCIPAL (i) && Col [i].shared2.order == EMPTY)
2791 {
2792 parent = i ;
2793 /* once found, find its principal parent */
2794 do
2795 {
2796 parent = Col [parent].shared1.parent ;
2797 } while (!COL_IS_DEAD_PRINCIPAL (parent)) ;
2798
2799 /* now, order all un-ordered non-principal columns along path */
2800 /* to this parent. collapse tree at the same time */
2801 c = i ;
2802 /* get order of parent */
2803 order = Col [parent].shared2.order ;
2804
2805 do
2806 {
2807 ASSERT (Col [c].shared2.order == EMPTY) ;
2808
2809 /* order this column */
2810 Col [c].shared2.order = order++ ;
2811 /* collaps tree */
2812 Col [c].shared1.parent = parent ;
2813
2814 /* get immediate parent of this column */
2815 c = Col [c].shared1.parent ;
2816
2817 /* continue until we hit an ordered column. There are */
2818 /* guarranteed not to be anymore unordered columns */
2819 /* above an ordered column */
2820 } while (Col [c].shared2.order == EMPTY) ;
2821
2822 /* re-order the super_col parent to largest order for this group */
2823 Col [parent].shared2.order = order ;
2824 }
2825 }
2826
2827 /* === Generate the permutation ========================================= */
2828
2829 for (c = 0 ; c < n_col ; c++)
2830 {
2831 p [Col [c].shared2.order] = c ;
2832 }
2833 }
2834
2835
2836 /* ========================================================================== */
2837 /* === detect_super_cols ==================================================== */
2838 /* ========================================================================== */
2839
2840 /*
2841 Detects supercolumns by finding matches between columns in the hash buckets.
2842 Check amongst columns in the set A [row_start ... row_start + row_length-1].
2843 The columns under consideration are currently *not* in the degree lists,
2844 and have already been placed in the hash buckets.
2845
2846 The hash bucket for columns whose hash function is equal to h is stored
2847 as follows:
2848
2849 if head [h] is >= 0, then head [h] contains a degree list, so:
2850
2851 head [h] is the first column in degree bucket h.
2852 Col [head [h]].headhash gives the first column in hash bucket h.
2853
2854 otherwise, the degree list is empty, and:
2855
2856 -(head [h] + 2) is the first column in hash bucket h.
2857
2858 For a column c in a hash bucket, Col [c].shared3.prev is NOT a "previous
2859 column" pointer. Col [c].shared3.hash is used instead as the hash number
2860 for that column. The value of Col [c].shared4.hash_next is the next column
2861 in the same hash bucket.
2862
2863 Assuming no, or "few" hash collisions, the time taken by this routine is
2864 linear in the sum of the sizes (lengths) of each column whose score has
2865 just been computed in the approximate degree computation.
2866 Not user-callable.
2867 */
2868
2869 PRIVATE void detect_super_cols
2870 (
2871 /* === Parameters ======================================================= */
2872
2873 #ifndef NDEBUG
2874 /* these two parameters are only needed when debugging is enabled: */
2875 Int n_col, /* number of columns of A */
2876 Colamd_Row Row [], /* of size n_row+1 */
2877 #endif /* NDEBUG */
2878
2879 Colamd_Col Col [], /* of size n_col+1 */
2880 Int A [], /* row indices of A */
2881 Int head [], /* head of degree lists and hash buckets */
2882 Int row_start, /* pointer to set of columns to check */
2883 Int row_length /* number of columns to check */
2884 )
2885 {
2886 /* === Local variables ================================================== */
2887
2888 Int hash ; /* hash value for a column */
2889 Int *rp ; /* pointer to a row */
2890 Int c ; /* a column index */
2891 Int super_c ; /* column index of the column to absorb into */
2892 Int *cp1 ; /* column pointer for column super_c */
2893 Int *cp2 ; /* column pointer for column c */
2894 Int length ; /* length of column super_c */
2895 Int prev_c ; /* column preceding c in hash bucket */
2896 Int i ; /* loop counter */
2897 Int *rp_end ; /* pointer to the end of the row */
2898 Int col ; /* a column index in the row to check */
2899 Int head_column ; /* first column in hash bucket or degree list */
2900 Int first_col ; /* first column in hash bucket */
2901
2902 /* === Consider each column in the row ================================== */
2903
2904 rp = &A [row_start] ;
2905 rp_end = rp + row_length ;
2906 while (rp < rp_end)
2907 {
2908 col = *rp++ ;
2909 if (COL_IS_DEAD (col))
2910 {
2911 continue ;
2912 }
2913
2914 /* get hash number for this column */
2915 hash = Col [col].shared3.hash ;
2916 ASSERT (hash <= n_col) ;
2917
2918 /* === Get the first column in this hash bucket ===================== */
2919
2920 head_column = head [hash] ;
2921 if (head_column > EMPTY)
2922 {
2923 first_col = Col [head_column].shared3.headhash ;
2924 }
2925 else
2926 {
2927 first_col = - (head_column + 2) ;
2928 }
2929
2930 /* === Consider each column in the hash bucket ====================== */
2931
2932 for (super_c = first_col ; super_c != EMPTY ;
2933 super_c = Col [super_c].shared4.hash_next)
2934 {
2935 ASSERT (COL_IS_ALIVE (super_c)) ;
2936 ASSERT (Col [super_c].shared3.hash == hash) ;
2937 length = Col [super_c].length ;
2938
2939 /* prev_c is the column preceding column c in the hash bucket */
2940 prev_c = super_c ;
2941
2942 /* === Compare super_c with all columns after it ================ */
2943
2944 for (c = Col [super_c].shared4.hash_next ;
2945 c != EMPTY ; c = Col [c].shared4.hash_next)
2946 {
2947 ASSERT (c != super_c) ;
2948 ASSERT (COL_IS_ALIVE (c)) ;
2949 ASSERT (Col [c].shared3.hash == hash) ;
2950
2951 /* not identical if lengths or scores are different */
2952 if (Col [c].length != length ||
2953 Col [c].shared2.score != Col [super_c].shared2.score)
2954 {
2955 prev_c = c ;
2956 continue ;
2957 }
2958
2959 /* compare the two columns */
2960 cp1 = &A [Col [super_c].start] ;
2961 cp2 = &A [Col [c].start] ;
2962
2963 for (i = 0 ; i < length ; i++)
2964 {
2965 /* the columns are "clean" (no dead rows) */
2966 ASSERT (ROW_IS_ALIVE (*cp1)) ;
2967 ASSERT (ROW_IS_ALIVE (*cp2)) ;
2968 /* row indices will same order for both supercols, */
2969 /* no gather scatter nessasary */
2970 if (*cp1++ != *cp2++)
2971 {
2972 break ;
2973 }
2974 }
2975
2976 /* the two columns are different if the for-loop "broke" */
2977 if (i != length)
2978 {
2979 prev_c = c ;
2980 continue ;
2981 }
2982
2983 /* === Got it! two columns are identical =================== */
2984
2985 ASSERT (Col [c].shared2.score == Col [super_c].shared2.score) ;
2986
2987 Col [super_c].shared1.thickness += Col [c].shared1.thickness ;
2988 Col [c].shared1.parent = super_c ;
2989 KILL_NON_PRINCIPAL_COL (c) ;
2990 /* order c later, in order_children() */
2991 Col [c].shared2.order = EMPTY ;
2992 /* remove c from hash bucket */
2993 Col [prev_c].shared4.hash_next = Col [c].shared4.hash_next ;
2994 }
2995 }
2996
2997 /* === Empty this hash bucket ======================================= */
2998
2999 if (head_column > EMPTY)
3000 {
3001 /* corresponding degree list "hash" is not empty */
3002 Col [head_column].shared3.headhash = EMPTY ;
3003 }
3004 else
3005 {
3006 /* corresponding degree list "hash" is empty */
3007 head [hash] = EMPTY ;
3008 }
3009 }
3010 }
3011
3012
3013 /* ========================================================================== */
3014 /* === garbage_collection =================================================== */
3015 /* ========================================================================== */
3016
3017 /*
3018 Defragments and compacts columns and rows in the workspace A. Used when
3019 all avaliable memory has been used while performing row merging. Returns
3020 the index of the first free position in A, after garbage collection. The
3021 time taken by this routine is linear is the size of the array A, which is
3022 itself linear in the number of nonzeros in the input matrix.
3023 Not user-callable.
3024 */
3025
3026 PRIVATE Int garbage_collection /* returns the new value of pfree */
3027 (
3028 /* === Parameters ======================================================= */
3029
3030 Int n_row, /* number of rows */
3031 Int n_col, /* number of columns */
3032 Colamd_Row Row [], /* row info */
3033 Colamd_Col Col [], /* column info */
3034 Int A [], /* A [0 ... Alen-1] holds the matrix */
3035 Int *pfree /* &A [0] ... pfree is in use */
3036 )
3037 {
3038 /* === Local variables ================================================== */
3039
3040 Int *psrc ; /* source pointer */
3041 Int *pdest ; /* destination pointer */
3042 Int j ; /* counter */
3043 Int r ; /* a row index */
3044 Int c ; /* a column index */
3045 Int length ; /* length of a row or column */
3046
3047 #ifndef NDEBUG
3048 Int debug_rows ;
3049 DEBUG2 (("Defrag..\n")) ;
3050 for (psrc = &A[0] ; psrc < pfree ; psrc++) ASSERT (*psrc >= 0) ;
3051 debug_rows = 0 ;
3052 #endif /* NDEBUG */
3053
3054 /* === Defragment the columns =========================================== */
3055
3056 pdest = &A[0] ;
3057 for (c = 0 ; c < n_col ; c++)
3058 {
3059 if (COL_IS_ALIVE (c))
3060 {
3061 psrc = &A [Col [c].start] ;
3062
3063 /* move and compact the column */
3064 ASSERT (pdest <= psrc) ;
3065 Col [c].start = (Int) (pdest - &A [0]) ;
3066 length = Col [c].length ;
3067 for (j = 0 ; j < length ; j++)
3068 {
3069 r = *psrc++ ;
3070 if (ROW_IS_ALIVE (r))
3071 {
3072 *pdest++ = r ;
3073 }
3074 }
3075 Col [c].length = (Int) (pdest - &A [Col [c].start]) ;
3076 }
3077 }
3078
3079 /* === Prepare to defragment the rows =================================== */
3080
3081 for (r = 0 ; r < n_row ; r++)
3082 {
3083 if (ROW_IS_DEAD (r) || (Row [r].length == 0))
3084 {
3085 /* This row is already dead, or is of zero length. Cannot compact
3086 * a row of zero length, so kill it. NOTE: in the current version,
3087 * there are no zero-length live rows. Kill the row (for the first
3088 * time, or again) just to be safe. */
3089 KILL_ROW (r) ;
3090 }
3091 else
3092 {
3093 /* save first column index in Row [r].shared2.first_column */
3094 psrc = &A [Row [r].start] ;
3095 Row [r].shared2.first_column = *psrc ;
3096 ASSERT (ROW_IS_ALIVE (r)) ;
3097 /* flag the start of the row with the one's complement of row */
3098 *psrc = ONES_COMPLEMENT (r) ;
3099 #ifndef NDEBUG
3100 debug_rows++ ;
3101 #endif /* NDEBUG */
3102 }
3103 }
3104
3105 /* === Defragment the rows ============================================== */
3106
3107 psrc = pdest ;
3108 while (psrc < pfree)
3109 {
3110 /* find a negative number ... the start of a row */
3111 if (*psrc++ < 0)
3112 {
3113 psrc-- ;
3114 /* get the row index */
3115 r = ONES_COMPLEMENT (*psrc) ;
3116 ASSERT (r >= 0 && r < n_row) ;
3117 /* restore first column index */
3118 *psrc = Row [r].shared2.first_column ;
3119 ASSERT (ROW_IS_ALIVE (r)) ;
3120 ASSERT (Row [r].length > 0) ;
3121 /* move and compact the row */
3122 ASSERT (pdest <= psrc) ;
3123 Row [r].start = (Int) (pdest - &A [0]) ;
3124 length = Row [r].length ;
3125 for (j = 0 ; j < length ; j++)
3126 {
3127 c = *psrc++ ;
3128 if (COL_IS_ALIVE (c))
3129 {
3130 *pdest++ = c ;
3131 }
3132 }
3133 Row [r].length = (Int) (pdest - &A [Row [r].start]) ;
3134 ASSERT (Row [r].length > 0) ;
3135 #ifndef NDEBUG
3136 debug_rows-- ;
3137 #endif /* NDEBUG */
3138 }
3139 }
3140 /* ensure we found all the rows */
3141 ASSERT (debug_rows == 0) ;
3142
3143 /* === Return the new value of pfree ==================================== */
3144
3145 return ((Int) (pdest - &A [0])) ;
3146 }
3147
3148
3149 /* ========================================================================== */
3150 /* === clear_mark =========================================================== */
3151 /* ========================================================================== */
3152
3153 /*
3154 Clears the Row [].shared2.mark array, and returns the new tag_mark.
3155 Return value is the new tag_mark. Not user-callable.
3156 */
3157
3158 PRIVATE Int clear_mark /* return the new value for tag_mark */
3159 (
3160 /* === Parameters ======================================================= */
3161
3162 Int tag_mark, /* new value of tag_mark */
3163 Int max_mark, /* max allowed value of tag_mark */
3164
3165 Int n_row, /* number of rows in A */
3166 Colamd_Row Row [] /* Row [0 ... n_row-1].shared2.mark is set to zero */
3167 )
3168 {
3169 /* === Local variables ================================================== */
3170
3171 Int r ;
3172
3173 if (tag_mark <= 0 || tag_mark >= max_mark)
3174 {
3175 for (r = 0 ; r < n_row ; r++)
3176 {
3177 if (ROW_IS_ALIVE (r))
3178 {
3179 Row [r].shared2.mark = 0 ;
3180 }
3181 }
3182 tag_mark = 1 ;
3183 }
3184
3185 return (tag_mark) ;
3186 }
3187
3188
3189 /* ========================================================================== */
3190 /* === print_report ========================================================= */
3191 /* ========================================================================== */
3192
3193 PRIVATE void print_report
3194 (
3195 char *method,
3196 Int stats [COLAMD_STATS]
3197 )
3198 {
3199
3200 Int i1, i2, i3 ;
3201
3202 PRINTF (("\n%s version %d.%d, %s: ", method,
3203 COLAMD_MAIN_VERSION, COLAMD_SUB_VERSION, COLAMD_DATE)) ;
3204
3205 if (!stats)
3206 {
3207 PRINTF (("No statistics available.\n")) ;
3208 return ;
3209 }
3210
3211 i1 = stats [COLAMD_INFO1] ;
3212 i2 = stats [COLAMD_INFO2] ;
3213 i3 = stats [COLAMD_INFO3] ;
3214
3215 if (stats [COLAMD_STATUS] >= 0)
3216 {
3217 PRINTF (("OK. ")) ;
3218 }
3219 else
3220 {
3221 PRINTF (("ERROR. ")) ;
3222 }
3223
3224 switch (stats [COLAMD_STATUS])
3225 {
3226
3227 case COLAMD_OK_BUT_JUMBLED:
3228
3229 PRINTF(("Matrix has unsorted or duplicate row indices.\n")) ;
3230
3231 PRINTF(("%s: number of duplicate or out-of-order row indices: %d\n",
3232 method, i3)) ;
3233
3234 PRINTF(("%s: last seen duplicate or out-of-order row index: %d\n",
3235 method, INDEX (i2))) ;
3236
3237 PRINTF(("%s: last seen in column: %d",
3238 method, INDEX (i1))) ;
3239
3240 /* no break - fall through to next case instead */
3241
3242 case COLAMD_OK:
3243
3244 PRINTF(("\n")) ;
3245
3246 PRINTF(("%s: number of dense or empty rows ignored: %d\n",
3247 method, stats [COLAMD_DENSE_ROW])) ;
3248
3249 PRINTF(("%s: number of dense or empty columns ignored: %d\n",
3250 method, stats [COLAMD_DENSE_COL])) ;
3251
3252 PRINTF(("%s: number of garbage collections performed: %d\n",
3253 method, stats [COLAMD_DEFRAG_COUNT])) ;
3254 break ;
3255
3256 case COLAMD_ERROR_A_not_present:
3257
3258 PRINTF(("Array A (row indices of matrix) not present.\n")) ;
3259 break ;
3260
3261 case COLAMD_ERROR_p_not_present:
3262
3263 PRINTF(("Array p (column pointers for matrix) not present.\n")) ;
3264 break ;
3265
3266 case COLAMD_ERROR_nrow_negative:
3267
3268 PRINTF(("Invalid number of rows (%d).\n", i1)) ;
3269 break ;
3270
3271 case COLAMD_ERROR_ncol_negative:
3272
3273 PRINTF(("Invalid number of columns (%d).\n", i1)) ;
3274 break ;
3275
3276 case COLAMD_ERROR_nnz_negative:
3277
3278 PRINTF(("Invalid number of nonzero entries (%d).\n", i1)) ;
3279 break ;
3280
3281 case COLAMD_ERROR_p0_nonzero:
3282
3283 PRINTF(("Invalid column pointer, p [0] = %d, must be zero.\n", i1));
3284 break ;
3285
3286 case COLAMD_ERROR_A_too_small:
3287
3288 PRINTF(("Array A too small.\n")) ;
3289 PRINTF((" Need Alen >= %d, but given only Alen = %d.\n",
3290 i1, i2)) ;
3291 break ;
3292
3293 case COLAMD_ERROR_col_length_negative:
3294
3295 PRINTF
3296 (("Column %d has a negative number of nonzero entries (%d).\n",
3297 INDEX (i1), i2)) ;
3298 break ;
3299
3300 case COLAMD_ERROR_row_index_out_of_bounds:
3301
3302 PRINTF
3303 (("Row index (row %d) out of bounds (%d to %d) in column %d.\n",
3304 INDEX (i2), INDEX (0), INDEX (i3-1), INDEX (i1))) ;
3305 break ;
3306
3307 case COLAMD_ERROR_out_of_memory:
3308
3309 PRINTF(("Out of memory.\n")) ;
3310 break ;
3311
3312 /* v2.4: internal-error case deleted */
3313 }
3314 }
3315
3316
3317
3318
3319 /* ========================================================================== */
3320 /* === colamd debugging routines ============================================ */
3321 /* ========================================================================== */
3322
3323 /* When debugging is disabled, the remainder of this file is ignored. */
3324
3325 #ifndef NDEBUG
3326
3327
3328 /* ========================================================================== */
3329 /* === debug_structures ===================================================== */
3330 /* ========================================================================== */
3331
3332 /*
3333 At this point, all empty rows and columns are dead. All live columns
3334 are "clean" (containing no dead rows) and simplicial (no supercolumns
3335 yet). Rows may contain dead columns, but all live rows contain at
3336 least one live column.
3337 */
3338
3339 PRIVATE void debug_structures
3340 (
3341 /* === Parameters ======================================================= */
3342
3343 Int n_row,
3344 Int n_col,
3345 Colamd_Row Row [],
3346 Colamd_Col Col [],
3347 Int A [],
3348 Int n_col2
3349 )
3350 {
3351 /* === Local variables ================================================== */
3352
3353 Int i ;
3354 Int c ;
3355 Int *cp ;
3356 Int *cp_end ;
3357 Int len ;
3358 Int score ;
3359 Int r ;
3360 Int *rp ;
3361 Int *rp_end ;
3362 Int deg ;
3363
3364 /* === Check A, Row, and Col ============================================ */
3365
3366 for (c = 0 ; c < n_col ; c++)
3367 {
3368 if (COL_IS_ALIVE (c))
3369 {
3370 len = Col [c].length ;
3371 score = Col [c].shared2.score ;
3372 DEBUG4 (("initial live col %5d %5d %5d\n", c, len, score)) ;
3373 ASSERT (len > 0) ;
3374 ASSERT (score >= 0) ;
3375 ASSERT (Col [c].shared1.thickness == 1) ;
3376 cp = &A [Col [c].start] ;
3377 cp_end = cp + len ;
3378 while (cp < cp_end)
3379 {
3380 r = *cp++ ;
3381 ASSERT (ROW_IS_ALIVE (r)) ;
3382 }
3383 }
3384 else
3385 {
3386 i = Col [c].shared2.order ;
3387 ASSERT (i >= n_col2 && i < n_col) ;
3388 }
3389 }
3390
3391 for (r = 0 ; r < n_row ; r++)
3392 {
3393 if (ROW_IS_ALIVE (r))
3394 {
3395 i = 0 ;
3396 len = Row [r].length ;
3397 deg = Row [r].shared1.degree ;
3398 ASSERT (len > 0) ;
3399 ASSERT (deg > 0) ;
3400 rp = &A [Row [r].start] ;
3401 rp_end = rp + len ;
3402 while (rp < rp_end)
3403 {
3404 c = *rp++ ;
3405 if (COL_IS_ALIVE (c))
3406 {
3407 i++ ;
3408 }
3409 }
3410 ASSERT (i > 0) ;
3411 }
3412 }
3413 }
3414
3415
3416 /* ========================================================================== */
3417 /* === debug_deg_lists ====================================================== */
3418 /* ========================================================================== */
3419
3420 /*
3421 Prints the contents of the degree lists. Counts the number of columns
3422 in the degree list and compares it to the total it should have. Also
3423 checks the row degrees.
3424 */
3425
3426 PRIVATE void debug_deg_lists
3427 (
3428 /* === Parameters ======================================================= */
3429
3430 Int n_row,
3431 Int n_col,
3432 Colamd_Row Row [],
3433 Colamd_Col Col [],
3434 Int head [],
3435 Int min_score,
3436 Int should,
3437 Int max_deg
3438 )
3439 {
3440 /* === Local variables ================================================== */
3441
3442 Int deg ;
3443 Int col ;
3444 Int have ;
3445 Int row ;
3446
3447 /* === Check the degree lists =========================================== */
3448
3449 if (n_col > 10000 && colamd_debug <= 0)
3450 {
3451 return ;
3452 }
3453 have = 0 ;
3454 DEBUG4 (("Degree lists: %d\n", min_score)) ;
3455 for (deg = 0 ; deg <= n_col ; deg++)
3456 {
3457 col = head [deg] ;
3458 if (col == EMPTY)
3459 {
3460 continue ;
3461 }
3462 DEBUG4 (("%d:", deg)) ;
3463 while (col != EMPTY)
3464 {
3465 DEBUG4 ((" %d", col)) ;
3466 have += Col [col].shared1.thickness ;
3467 ASSERT (COL_IS_ALIVE (col)) ;
3468 col = Col [col].shared4.degree_next ;
3469 }
3470 DEBUG4 (("\n")) ;
3471 }
3472 DEBUG4 (("should %d have %d\n", should, have)) ;
3473 ASSERT (should == have) ;
3474
3475 /* === Check the row degrees ============================================ */
3476
3477 if (n_row > 10000 && colamd_debug <= 0)
3478 {
3479 return ;
3480 }
3481 for (row = 0 ; row < n_row ; row++)
3482 {
3483 if (ROW_IS_ALIVE (row))
3484 {
3485 ASSERT (Row [row].shared1.degree <= max_deg) ;
3486 }
3487 }
3488 }
3489
3490
3491 /* ========================================================================== */
3492 /* === debug_mark =========================================================== */
3493 /* ========================================================================== */
3494
3495 /*
3496 Ensures that the tag_mark is less that the maximum and also ensures that
3497 each entry in the mark array is less than the tag mark.
3498 */
3499
3500 PRIVATE void debug_mark
3501 (
3502 /* === Parameters ======================================================= */
3503
3504 Int n_row,
3505 Colamd_Row Row [],
3506 Int tag_mark,
3507 Int max_mark
3508 )
3509 {
3510 /* === Local variables ================================================== */
3511
3512 Int r ;
3513
3514 /* === Check the Row marks ============================================== */
3515
3516 ASSERT (tag_mark > 0 && tag_mark <= max_mark) ;
3517 if (n_row > 10000 && colamd_debug <= 0)
3518 {
3519 return ;
3520 }
3521 for (r = 0 ; r < n_row ; r++)
3522 {
3523 ASSERT (Row [r].shared2.mark < tag_mark) ;
3524 }
3525 }
3526
3527
3528 /* ========================================================================== */
3529 /* === debug_matrix ========================================================= */
3530 /* ========================================================================== */
3531
3532 /*
3533 Prints out the contents of the columns and the rows.
3534 */
3535
3536 PRIVATE void debug_matrix
3537 (
3538 /* === Parameters ======================================================= */
3539
3540 Int n_row,
3541 Int n_col,
3542 Colamd_Row Row [],
3543 Colamd_Col Col [],
3544 Int A []
3545 )
3546 {
3547 /* === Local variables ================================================== */
3548
3549 Int r ;
3550 Int c ;
3551 Int *rp ;
3552 Int *rp_end ;
3553 Int *cp ;
3554 Int *cp_end ;
3555
3556 /* === Dump the rows and columns of the matrix ========================== */
3557
3558 if (colamd_debug < 3)
3559 {
3560 return ;
3561 }
3562 DEBUG3 (("DUMP MATRIX:\n")) ;
3563 for (r = 0 ; r < n_row ; r++)
3564 {
3565 DEBUG3 (("Row %d alive? %d\n", r, ROW_IS_ALIVE (r))) ;
3566 if (ROW_IS_DEAD (r))
3567 {
3568 continue ;
3569 }
3570 DEBUG3 (("start %d length %d degree %d\n",
3571 Row [r].start, Row [r].length, Row [r].shared1.degree)) ;
3572 rp = &A [Row [r].start] ;
3573 rp_end = rp + Row [r].length ;
3574 while (rp < rp_end)
3575 {
3576 c = *rp++ ;
3577 DEBUG4 ((" %d col %d\n", COL_IS_ALIVE (c), c)) ;
3578 }
3579 }
3580
3581 for (c = 0 ; c < n_col ; c++)
3582 {
3583 DEBUG3 (("Col %d alive? %d\n", c, COL_IS_ALIVE (c))) ;
3584 if (COL_IS_DEAD (c))
3585 {
3586 continue ;
3587 }
3588 DEBUG3 (("start %d length %d shared1 %d shared2 %d\n",
3589 Col [c].start, Col [c].length,
3590 Col [c].shared1.thickness, Col [c].shared2.score)) ;
3591 cp = &A [Col [c].start] ;
3592 cp_end = cp + Col [c].length ;
3593 while (cp < cp_end)
3594 {
3595 r = *cp++ ;
3596 DEBUG4 ((" %d row %d\n", ROW_IS_ALIVE (r), r)) ;
3597 }
3598 }
3599 }
3600
3601 PRIVATE void colamd_get_debug
3602 (
3603 char *method
3604 )
3605 {
3606 FILE *f ;
3607 colamd_debug = 0 ; /* no debug printing */
3608 f = fopen ("debug", "r") ;
3609 if (f == (FILE *) NULL)
3610 {
3611 colamd_debug = 0 ;
3612 }
3613 else
3614 {
3615 fscanf (f, "%d", &colamd_debug) ;
3616 fclose (f) ;
3617 }
3618 DEBUG0 (("%s: debug version, D = %d (THIS WILL BE SLOW!)\n",
3619 method, colamd_debug)) ;
3620 }
3621
3622 #endif /* NDEBUG */