src/colamd/colamd.c
author Alpar Juttner <alpar@cs.elte.hu>
Mon, 06 Dec 2010 13:09:21 +0100
changeset 1 c445c931472f
permissions -rw-r--r--
Import glpk-4.45

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