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 */ |
---|