src/amd/amd_2.c
author Alpar Juttner <alpar@cs.elte.hu>
Sun, 05 Dec 2010 17:35:23 +0100
changeset 2 4c8956a7bdf4
permissions -rw-r--r--
Set up CMAKE build environment
alpar@1
     1
/* ========================================================================= */
alpar@1
     2
/* === AMD_2 =============================================================== */
alpar@1
     3
/* ========================================================================= */
alpar@1
     4
alpar@1
     5
/* ------------------------------------------------------------------------- */
alpar@1
     6
/* AMD, Copyright (c) Timothy A. Davis,                                      */
alpar@1
     7
/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
alpar@1
     8
/* email: davis at cise.ufl.edu    CISE Department, Univ. of Florida.        */
alpar@1
     9
/* web: http://www.cise.ufl.edu/research/sparse/amd                          */
alpar@1
    10
/* ------------------------------------------------------------------------- */
alpar@1
    11
alpar@1
    12
/* AMD_2:  performs the AMD ordering on a symmetric sparse matrix A, followed
alpar@1
    13
 * by a postordering (via depth-first search) of the assembly tree using the
alpar@1
    14
 * AMD_postorder routine.
alpar@1
    15
 */
alpar@1
    16
alpar@1
    17
#include "amd_internal.h"
alpar@1
    18
alpar@1
    19
/* ========================================================================= */
alpar@1
    20
/* === clear_flag ========================================================== */
alpar@1
    21
/* ========================================================================= */
alpar@1
    22
alpar@1
    23
static Int clear_flag (Int wflg, Int wbig, Int W [ ], Int n)
alpar@1
    24
{
alpar@1
    25
    Int x ;
alpar@1
    26
    if (wflg < 2 || wflg >= wbig)
alpar@1
    27
    {
alpar@1
    28
        for (x = 0 ; x < n ; x++)
alpar@1
    29
        {
alpar@1
    30
            if (W [x] != 0) W [x] = 1 ;
alpar@1
    31
        }
alpar@1
    32
        wflg = 2 ;
alpar@1
    33
    }
alpar@1
    34
    /*  at this point, W [0..n-1] < wflg holds */
alpar@1
    35
    return (wflg) ;
alpar@1
    36
}
alpar@1
    37
alpar@1
    38
alpar@1
    39
/* ========================================================================= */
alpar@1
    40
/* === AMD_2 =============================================================== */
alpar@1
    41
/* ========================================================================= */
alpar@1
    42
alpar@1
    43
GLOBAL void AMD_2
alpar@1
    44
(
alpar@1
    45
    Int n,              /* A is n-by-n, where n > 0 */
alpar@1
    46
    Int Pe [ ],         /* Pe [0..n-1]: index in Iw of row i on input */
alpar@1
    47
    Int Iw [ ],         /* workspace of size iwlen. Iw [0..pfree-1]
alpar@1
    48
                         * holds the matrix on input */
alpar@1
    49
    Int Len [ ],        /* Len [0..n-1]: length for row/column i on input */
alpar@1
    50
    Int iwlen,          /* length of Iw. iwlen >= pfree + n */
alpar@1
    51
    Int pfree,          /* Iw [pfree ... iwlen-1] is empty on input */
alpar@1
    52
alpar@1
    53
    /* 7 size-n workspaces, not defined on input: */
alpar@1
    54
    Int Nv [ ],         /* the size of each supernode on output */
alpar@1
    55
    Int Next [ ],       /* the output inverse permutation */
alpar@1
    56
    Int Last [ ],       /* the output permutation */
alpar@1
    57
    Int Head [ ],
alpar@1
    58
    Int Elen [ ],       /* the size columns of L for each supernode */
alpar@1
    59
    Int Degree [ ],
alpar@1
    60
    Int W [ ],
alpar@1
    61
alpar@1
    62
    /* control parameters and output statistics */
alpar@1
    63
    double Control [ ], /* array of size AMD_CONTROL */
alpar@1
    64
    double Info [ ]     /* array of size AMD_INFO */
alpar@1
    65
)
alpar@1
    66
{
alpar@1
    67
alpar@1
    68
/*
alpar@1
    69
 * Given a representation of the nonzero pattern of a symmetric matrix, A,
alpar@1
    70
 * (excluding the diagonal) perform an approximate minimum (UMFPACK/MA38-style)
alpar@1
    71
 * degree ordering to compute a pivot order such that the introduction of
alpar@1
    72
 * nonzeros (fill-in) in the Cholesky factors A = LL' is kept low.  At each
alpar@1
    73
 * step, the pivot selected is the one with the minimum UMFAPACK/MA38-style
alpar@1
    74
 * upper-bound on the external degree.  This routine can optionally perform
alpar@1
    75
 * aggresive absorption (as done by MC47B in the Harwell Subroutine
alpar@1
    76
 * Library).
alpar@1
    77
 *
alpar@1
    78
 * The approximate degree algorithm implemented here is the symmetric analog of
alpar@1
    79
 * the degree update algorithm in MA38 and UMFPACK (the Unsymmetric-pattern
alpar@1
    80
 * MultiFrontal PACKage, both by Davis and Duff).  The routine is based on the
alpar@1
    81
 * MA27 minimum degree ordering algorithm by Iain Duff and John Reid.
alpar@1
    82
 *
alpar@1
    83
 * This routine is a translation of the original AMDBAR and MC47B routines,
alpar@1
    84
 * in Fortran, with the following modifications:
alpar@1
    85
 *
alpar@1
    86
 * (1) dense rows/columns are removed prior to ordering the matrix, and placed
alpar@1
    87
 *      last in the output order.  The presence of a dense row/column can
alpar@1
    88
 *      increase the ordering time by up to O(n^2), unless they are removed
alpar@1
    89
 *      prior to ordering.
alpar@1
    90
 *
alpar@1
    91
 * (2) the minimum degree ordering is followed by a postordering (depth-first
alpar@1
    92
 *      search) of the assembly tree.  Note that mass elimination (discussed
alpar@1
    93
 *      below) combined with the approximate degree update can lead to the mass
alpar@1
    94
 *      elimination of nodes with lower exact degree than the current pivot
alpar@1
    95
 *      element.  No additional fill-in is caused in the representation of the
alpar@1
    96
 *      Schur complement.  The mass-eliminated nodes merge with the current
alpar@1
    97
 *      pivot element.  They are ordered prior to the current pivot element.
alpar@1
    98
 *      Because they can have lower exact degree than the current element, the
alpar@1
    99
 *      merger of two or more of these nodes in the current pivot element can
alpar@1
   100
 *      lead to a single element that is not a "fundamental supernode".  The
alpar@1
   101
 *      diagonal block can have zeros in it.  Thus, the assembly tree used here
alpar@1
   102
 *      is not guaranteed to be the precise supernodal elemination tree (with
alpar@1
   103
 *      "funadmental" supernodes), and the postordering performed by this
alpar@1
   104
 *      routine is not guaranteed to be a precise postordering of the
alpar@1
   105
 *      elimination tree.
alpar@1
   106
 *
alpar@1
   107
 * (3) input parameters are added, to control aggressive absorption and the
alpar@1
   108
 *      detection of "dense" rows/columns of A.
alpar@1
   109
 *
alpar@1
   110
 * (4) additional statistical information is returned, such as the number of
alpar@1
   111
 *      nonzeros in L, and the flop counts for subsequent LDL' and LU
alpar@1
   112
 *      factorizations.  These are slight upper bounds, because of the mass
alpar@1
   113
 *      elimination issue discussed above.
alpar@1
   114
 *
alpar@1
   115
 * (5) additional routines are added to interface this routine to MATLAB
alpar@1
   116
 *      to provide a simple C-callable user-interface, to check inputs for
alpar@1
   117
 *      errors, compute the symmetry of the pattern of A and the number of
alpar@1
   118
 *      nonzeros in each row/column of A+A', to compute the pattern of A+A',
alpar@1
   119
 *      to perform the assembly tree postordering, and to provide debugging
alpar@1
   120
 *      ouput.  Many of these functions are also provided by the Fortran
alpar@1
   121
 *      Harwell Subroutine Library routine MC47A.
alpar@1
   122
 *
alpar@1
   123
 * (6) both int and UF_long versions are provided.  In the descriptions below
alpar@1
   124
 *      and integer is and int or UF_long depending on which version is
alpar@1
   125
 *      being used.
alpar@1
   126
alpar@1
   127
 **********************************************************************
alpar@1
   128
 ***** CAUTION:  ARGUMENTS ARE NOT CHECKED FOR ERRORS ON INPUT.  ******
alpar@1
   129
 **********************************************************************
alpar@1
   130
 ** If you want error checking, a more versatile input format, and a **
alpar@1
   131
 ** simpler user interface, use amd_order or amd_l_order instead.    **
alpar@1
   132
 ** This routine is not meant to be user-callable.                   **
alpar@1
   133
 **********************************************************************
alpar@1
   134
alpar@1
   135
 * ----------------------------------------------------------------------------
alpar@1
   136
 * References:
alpar@1
   137
 * ----------------------------------------------------------------------------
alpar@1
   138
 *
alpar@1
   139
 *  [1] Timothy A. Davis and Iain Duff, "An unsymmetric-pattern multifrontal
alpar@1
   140
 *      method for sparse LU factorization", SIAM J. Matrix Analysis and
alpar@1
   141
 *      Applications, vol. 18, no. 1, pp. 140-158.  Discusses UMFPACK / MA38,
alpar@1
   142
 *      which first introduced the approximate minimum degree used by this
alpar@1
   143
 *      routine.
alpar@1
   144
 *
alpar@1
   145
 *  [2] Patrick Amestoy, Timothy A. Davis, and Iain S. Duff, "An approximate
alpar@1
   146
 *      minimum degree ordering algorithm," SIAM J. Matrix Analysis and
alpar@1
   147
 *      Applications, vol. 17, no. 4, pp. 886-905, 1996.  Discusses AMDBAR and
alpar@1
   148
 *      MC47B, which are the Fortran versions of this routine.
alpar@1
   149
 *
alpar@1
   150
 *  [3] Alan George and Joseph Liu, "The evolution of the minimum degree
alpar@1
   151
 *      ordering algorithm," SIAM Review, vol. 31, no. 1, pp. 1-19, 1989.
alpar@1
   152
 *      We list below the features mentioned in that paper that this code
alpar@1
   153
 *      includes:
alpar@1
   154
 *
alpar@1
   155
 *      mass elimination:
alpar@1
   156
 *          Yes.  MA27 relied on supervariable detection for mass elimination.
alpar@1
   157
 *
alpar@1
   158
 *      indistinguishable nodes:
alpar@1
   159
 *          Yes (we call these "supervariables").  This was also in the MA27
alpar@1
   160
 *          code - although we modified the method of detecting them (the
alpar@1
   161
 *          previous hash was the true degree, which we no longer keep track
alpar@1
   162
 *          of).  A supervariable is a set of rows with identical nonzero
alpar@1
   163
 *          pattern.  All variables in a supervariable are eliminated together.
alpar@1
   164
 *          Each supervariable has as its numerical name that of one of its
alpar@1
   165
 *          variables (its principal variable).
alpar@1
   166
 *
alpar@1
   167
 *      quotient graph representation:
alpar@1
   168
 *          Yes.  We use the term "element" for the cliques formed during
alpar@1
   169
 *          elimination.  This was also in the MA27 code.  The algorithm can
alpar@1
   170
 *          operate in place, but it will work more efficiently if given some
alpar@1
   171
 *          "elbow room."
alpar@1
   172
 *
alpar@1
   173
 *      element absorption:
alpar@1
   174
 *          Yes.  This was also in the MA27 code.
alpar@1
   175
 *
alpar@1
   176
 *      external degree:
alpar@1
   177
 *          Yes.  The MA27 code was based on the true degree.
alpar@1
   178
 *
alpar@1
   179
 *      incomplete degree update and multiple elimination:
alpar@1
   180
 *          No.  This was not in MA27, either.  Our method of degree update
alpar@1
   181
 *          within MC47B is element-based, not variable-based.  It is thus
alpar@1
   182
 *          not well-suited for use with incomplete degree update or multiple
alpar@1
   183
 *          elimination.
alpar@1
   184
 *
alpar@1
   185
 * Authors, and Copyright (C) 2004 by:
alpar@1
   186
 * Timothy A. Davis, Patrick Amestoy, Iain S. Duff, John K. Reid.
alpar@1
   187
 *
alpar@1
   188
 * Acknowledgements: This work (and the UMFPACK package) was supported by the
alpar@1
   189
 * National Science Foundation (ASC-9111263, DMS-9223088, and CCR-0203270).
alpar@1
   190
 * The UMFPACK/MA38 approximate degree update algorithm, the unsymmetric analog
alpar@1
   191
 * which forms the basis of AMD, was developed while Tim Davis was supported by
alpar@1
   192
 * CERFACS (Toulouse, France) in a post-doctoral position.  This C version, and
alpar@1
   193
 * the etree postorder, were written while Tim Davis was on sabbatical at
alpar@1
   194
 * Stanford University and Lawrence Berkeley National Laboratory.
alpar@1
   195
alpar@1
   196
 * ----------------------------------------------------------------------------
alpar@1
   197
 * INPUT ARGUMENTS (unaltered):
alpar@1
   198
 * ----------------------------------------------------------------------------
alpar@1
   199
alpar@1
   200
 * n:  The matrix order.  Restriction:  n >= 1.
alpar@1
   201
 *
alpar@1
   202
 * iwlen:  The size of the Iw array.  On input, the matrix is stored in
alpar@1
   203
 *      Iw [0..pfree-1].  However, Iw [0..iwlen-1] should be slightly larger
alpar@1
   204
 *      than what is required to hold the matrix, at least iwlen >= pfree + n.
alpar@1
   205
 *      Otherwise, excessive compressions will take place.  The recommended
alpar@1
   206
 *      value of iwlen is 1.2 * pfree + n, which is the value used in the
alpar@1
   207
 *      user-callable interface to this routine (amd_order.c).  The algorithm
alpar@1
   208
 *      will not run at all if iwlen < pfree.  Restriction: iwlen >= pfree + n.
alpar@1
   209
 *      Note that this is slightly more restrictive than the actual minimum
alpar@1
   210
 *      (iwlen >= pfree), but AMD_2 will be very slow with no elbow room.
alpar@1
   211
 *      Thus, this routine enforces a bare minimum elbow room of size n.
alpar@1
   212
 *
alpar@1
   213
 * pfree: On input the tail end of the array, Iw [pfree..iwlen-1], is empty,
alpar@1
   214
 *      and the matrix is stored in Iw [0..pfree-1].  During execution,
alpar@1
   215
 *      additional data is placed in Iw, and pfree is modified so that
alpar@1
   216
 *      Iw [pfree..iwlen-1] is always the unused part of Iw.
alpar@1
   217
 *
alpar@1
   218
 * Control:  A double array of size AMD_CONTROL containing input parameters
alpar@1
   219
 *      that affect how the ordering is computed.  If NULL, then default
alpar@1
   220
 *      settings are used.
alpar@1
   221
 *
alpar@1
   222
 *      Control [AMD_DENSE] is used to determine whether or not a given input
alpar@1
   223
 *      row is "dense".  A row is "dense" if the number of entries in the row
alpar@1
   224
 *      exceeds Control [AMD_DENSE] times sqrt (n), except that rows with 16 or
alpar@1
   225
 *      fewer entries are never considered "dense".  To turn off the detection
alpar@1
   226
 *      of dense rows, set Control [AMD_DENSE] to a negative number, or to a
alpar@1
   227
 *      number larger than sqrt (n).  The default value of Control [AMD_DENSE]
alpar@1
   228
 *      is AMD_DEFAULT_DENSE, which is defined in amd.h as 10.
alpar@1
   229
 *
alpar@1
   230
 *      Control [AMD_AGGRESSIVE] is used to determine whether or not aggressive
alpar@1
   231
 *      absorption is to be performed.  If nonzero, then aggressive absorption
alpar@1
   232
 *      is performed (this is the default).
alpar@1
   233
alpar@1
   234
 * ----------------------------------------------------------------------------
alpar@1
   235
 * INPUT/OUPUT ARGUMENTS:
alpar@1
   236
 * ----------------------------------------------------------------------------
alpar@1
   237
 *
alpar@1
   238
 * Pe:  An integer array of size n.  On input, Pe [i] is the index in Iw of
alpar@1
   239
 *      the start of row i.  Pe [i] is ignored if row i has no off-diagonal
alpar@1
   240
 *      entries.  Thus Pe [i] must be in the range 0 to pfree-1 for non-empty
alpar@1
   241
 *      rows.
alpar@1
   242
 *
alpar@1
   243
 *      During execution, it is used for both supervariables and elements:
alpar@1
   244
 *
alpar@1
   245
 *      Principal supervariable i:  index into Iw of the description of
alpar@1
   246
 *          supervariable i.  A supervariable represents one or more rows of
alpar@1
   247
 *          the matrix with identical nonzero pattern.  In this case,
alpar@1
   248
 *          Pe [i] >= 0.
alpar@1
   249
 *
alpar@1
   250
 *      Non-principal supervariable i:  if i has been absorbed into another
alpar@1
   251
 *          supervariable j, then Pe [i] = FLIP (j), where FLIP (j) is defined
alpar@1
   252
 *          as (-(j)-2).  Row j has the same pattern as row i.  Note that j
alpar@1
   253
 *          might later be absorbed into another supervariable j2, in which
alpar@1
   254
 *          case Pe [i] is still FLIP (j), and Pe [j] = FLIP (j2) which is
alpar@1
   255
 *          < EMPTY, where EMPTY is defined as (-1) in amd_internal.h.
alpar@1
   256
 *
alpar@1
   257
 *      Unabsorbed element e:  the index into Iw of the description of element
alpar@1
   258
 *          e, if e has not yet been absorbed by a subsequent element.  Element
alpar@1
   259
 *          e is created when the supervariable of the same name is selected as
alpar@1
   260
 *          the pivot.  In this case, Pe [i] >= 0.
alpar@1
   261
 *
alpar@1
   262
 *      Absorbed element e:  if element e is absorbed into element e2, then
alpar@1
   263
 *          Pe [e] = FLIP (e2).  This occurs when the pattern of e (which we
alpar@1
   264
 *          refer to as Le) is found to be a subset of the pattern of e2 (that
alpar@1
   265
 *          is, Le2).  In this case, Pe [i] < EMPTY.  If element e is "null"
alpar@1
   266
 *          (it has no nonzeros outside its pivot block), then Pe [e] = EMPTY,
alpar@1
   267
 *          and e is the root of an assembly subtree (or the whole tree if
alpar@1
   268
 *          there is just one such root).
alpar@1
   269
 *
alpar@1
   270
 *      Dense variable i:  if i is "dense", then Pe [i] = EMPTY.
alpar@1
   271
 *
alpar@1
   272
 *      On output, Pe holds the assembly tree/forest, which implicitly
alpar@1
   273
 *      represents a pivot order with identical fill-in as the actual order
alpar@1
   274
 *      (via a depth-first search of the tree), as follows.  If Nv [i] > 0,
alpar@1
   275
 *      then i represents a node in the assembly tree, and the parent of i is
alpar@1
   276
 *      Pe [i], or EMPTY if i is a root.  If Nv [i] = 0, then (i, Pe [i])
alpar@1
   277
 *      represents an edge in a subtree, the root of which is a node in the
alpar@1
   278
 *      assembly tree.  Note that i refers to a row/column in the original
alpar@1
   279
 *      matrix, not the permuted matrix.
alpar@1
   280
 *
alpar@1
   281
 * Info:  A double array of size AMD_INFO.  If present, (that is, not NULL),
alpar@1
   282
 *      then statistics about the ordering are returned in the Info array.
alpar@1
   283
 *      See amd.h for a description.
alpar@1
   284
alpar@1
   285
 * ----------------------------------------------------------------------------
alpar@1
   286
 * INPUT/MODIFIED (undefined on output):
alpar@1
   287
 * ----------------------------------------------------------------------------
alpar@1
   288
 *
alpar@1
   289
 * Len:  An integer array of size n.  On input, Len [i] holds the number of
alpar@1
   290
 *      entries in row i of the matrix, excluding the diagonal.  The contents
alpar@1
   291
 *      of Len are undefined on output.
alpar@1
   292
 *
alpar@1
   293
 * Iw:  An integer array of size iwlen.  On input, Iw [0..pfree-1] holds the
alpar@1
   294
 *      description of each row i in the matrix.  The matrix must be symmetric,
alpar@1
   295
 *      and both upper and lower triangular parts must be present.  The
alpar@1
   296
 *      diagonal must not be present.  Row i is held as follows:
alpar@1
   297
 *
alpar@1
   298
 *          Len [i]:  the length of the row i data structure in the Iw array.
alpar@1
   299
 *          Iw [Pe [i] ... Pe [i] + Len [i] - 1]:
alpar@1
   300
 *              the list of column indices for nonzeros in row i (simple
alpar@1
   301
 *              supervariables), excluding the diagonal.  All supervariables
alpar@1
   302
 *              start with one row/column each (supervariable i is just row i).
alpar@1
   303
 *              If Len [i] is zero on input, then Pe [i] is ignored on input.
alpar@1
   304
 *
alpar@1
   305
 *          Note that the rows need not be in any particular order, and there
alpar@1
   306
 *          may be empty space between the rows.
alpar@1
   307
 *
alpar@1
   308
 *      During execution, the supervariable i experiences fill-in.  This is
alpar@1
   309
 *      represented by placing in i a list of the elements that cause fill-in
alpar@1
   310
 *      in supervariable i:
alpar@1
   311
 *
alpar@1
   312
 *          Len [i]:  the length of supervariable i in the Iw array.
alpar@1
   313
 *          Iw [Pe [i] ... Pe [i] + Elen [i] - 1]:
alpar@1
   314
 *              the list of elements that contain i.  This list is kept short
alpar@1
   315
 *              by removing absorbed elements.
alpar@1
   316
 *          Iw [Pe [i] + Elen [i] ... Pe [i] + Len [i] - 1]:
alpar@1
   317
 *              the list of supervariables in i.  This list is kept short by
alpar@1
   318
 *              removing nonprincipal variables, and any entry j that is also
alpar@1
   319
 *              contained in at least one of the elements (j in Le) in the list
alpar@1
   320
 *              for i (e in row i).
alpar@1
   321
 *
alpar@1
   322
 *      When supervariable i is selected as pivot, we create an element e of
alpar@1
   323
 *      the same name (e=i):
alpar@1
   324
 *
alpar@1
   325
 *          Len [e]:  the length of element e in the Iw array.
alpar@1
   326
 *          Iw [Pe [e] ... Pe [e] + Len [e] - 1]:
alpar@1
   327
 *              the list of supervariables in element e.
alpar@1
   328
 *
alpar@1
   329
 *      An element represents the fill-in that occurs when supervariable i is
alpar@1
   330
 *      selected as pivot (which represents the selection of row i and all
alpar@1
   331
 *      non-principal variables whose principal variable is i).  We use the
alpar@1
   332
 *      term Le to denote the set of all supervariables in element e.  Absorbed
alpar@1
   333
 *      supervariables and elements are pruned from these lists when
alpar@1
   334
 *      computationally convenient.
alpar@1
   335
 *
alpar@1
   336
 *  CAUTION:  THE INPUT MATRIX IS OVERWRITTEN DURING COMPUTATION.
alpar@1
   337
 *  The contents of Iw are undefined on output.
alpar@1
   338
alpar@1
   339
 * ----------------------------------------------------------------------------
alpar@1
   340
 * OUTPUT (need not be set on input):
alpar@1
   341
 * ----------------------------------------------------------------------------
alpar@1
   342
 *
alpar@1
   343
 * Nv:  An integer array of size n.  During execution, ABS (Nv [i]) is equal to
alpar@1
   344
 *      the number of rows that are represented by the principal supervariable
alpar@1
   345
 *      i.  If i is a nonprincipal or dense variable, then Nv [i] = 0.
alpar@1
   346
 *      Initially, Nv [i] = 1 for all i.  Nv [i] < 0 signifies that i is a
alpar@1
   347
 *      principal variable in the pattern Lme of the current pivot element me.
alpar@1
   348
 *      After element me is constructed, Nv [i] is set back to a positive
alpar@1
   349
 *      value.
alpar@1
   350
 *
alpar@1
   351
 *      On output, Nv [i] holds the number of pivots represented by super
alpar@1
   352
 *      row/column i of the original matrix, or Nv [i] = 0 for non-principal
alpar@1
   353
 *      rows/columns.  Note that i refers to a row/column in the original
alpar@1
   354
 *      matrix, not the permuted matrix.
alpar@1
   355
 *
alpar@1
   356
 * Elen:  An integer array of size n.  See the description of Iw above.  At the
alpar@1
   357
 *      start of execution, Elen [i] is set to zero for all rows i.  During
alpar@1
   358
 *      execution, Elen [i] is the number of elements in the list for
alpar@1
   359
 *      supervariable i.  When e becomes an element, Elen [e] = FLIP (esize) is
alpar@1
   360
 *      set, where esize is the size of the element (the number of pivots, plus
alpar@1
   361
 *      the number of nonpivotal entries).  Thus Elen [e] < EMPTY.
alpar@1
   362
 *      Elen (i) = EMPTY set when variable i becomes nonprincipal.
alpar@1
   363
 *
alpar@1
   364
 *      For variables, Elen (i) >= EMPTY holds until just before the
alpar@1
   365
 *      postordering and permutation vectors are computed.  For elements,
alpar@1
   366
 *      Elen [e] < EMPTY holds.
alpar@1
   367
 *
alpar@1
   368
 *      On output, Elen [i] is the degree of the row/column in the Cholesky
alpar@1
   369
 *      factorization of the permuted matrix, corresponding to the original row
alpar@1
   370
 *      i, if i is a super row/column.  It is equal to EMPTY if i is
alpar@1
   371
 *      non-principal.  Note that i refers to a row/column in the original
alpar@1
   372
 *      matrix, not the permuted matrix.
alpar@1
   373
 *
alpar@1
   374
 *      Note that the contents of Elen on output differ from the Fortran
alpar@1
   375
 *      version (Elen holds the inverse permutation in the Fortran version,
alpar@1
   376
 *      which is instead returned in the Next array in this C version,
alpar@1
   377
 *      described below).
alpar@1
   378
 *
alpar@1
   379
 * Last: In a degree list, Last [i] is the supervariable preceding i, or EMPTY
alpar@1
   380
 *      if i is the head of the list.  In a hash bucket, Last [i] is the hash
alpar@1
   381
 *      key for i.
alpar@1
   382
 *
alpar@1
   383
 *      Last [Head [hash]] is also used as the head of a hash bucket if
alpar@1
   384
 *      Head [hash] contains a degree list (see the description of Head,
alpar@1
   385
 *      below).
alpar@1
   386
 *
alpar@1
   387
 *      On output, Last [0..n-1] holds the permutation.  That is, if
alpar@1
   388
 *      i = Last [k], then row i is the kth pivot row (where k ranges from 0 to
alpar@1
   389
 *      n-1).  Row Last [k] of A is the kth row in the permuted matrix, PAP'.
alpar@1
   390
 *
alpar@1
   391
 * Next: Next [i] is the supervariable following i in a link list, or EMPTY if
alpar@1
   392
 *      i is the last in the list.  Used for two kinds of lists:  degree lists
alpar@1
   393
 *      and hash buckets (a supervariable can be in only one kind of list at a
alpar@1
   394
 *      time).
alpar@1
   395
 *
alpar@1
   396
 *      On output Next [0..n-1] holds the inverse permutation.  That is, if
alpar@1
   397
 *      k = Next [i], then row i is the kth pivot row. Row i of A appears as
alpar@1
   398
 *      the (Next[i])-th row in the permuted matrix, PAP'.
alpar@1
   399
 *
alpar@1
   400
 *      Note that the contents of Next on output differ from the Fortran
alpar@1
   401
 *      version (Next is undefined on output in the Fortran version).
alpar@1
   402
alpar@1
   403
 * ----------------------------------------------------------------------------
alpar@1
   404
 * LOCAL WORKSPACE (not input or output - used only during execution):
alpar@1
   405
 * ----------------------------------------------------------------------------
alpar@1
   406
 *
alpar@1
   407
 * Degree:  An integer array of size n.  If i is a supervariable, then
alpar@1
   408
 *      Degree [i] holds the current approximation of the external degree of
alpar@1
   409
 *      row i (an upper bound).  The external degree is the number of nonzeros
alpar@1
   410
 *      in row i, minus ABS (Nv [i]), the diagonal part.  The bound is equal to
alpar@1
   411
 *      the exact external degree if Elen [i] is less than or equal to two.
alpar@1
   412
 *
alpar@1
   413
 *      We also use the term "external degree" for elements e to refer to
alpar@1
   414
 *      |Le \ Lme|.  If e is an element, then Degree [e] is |Le|, which is the
alpar@1
   415
 *      degree of the off-diagonal part of the element e (not including the
alpar@1
   416
 *      diagonal part).
alpar@1
   417
 *
alpar@1
   418
 * Head:   An integer array of size n.  Head is used for degree lists.
alpar@1
   419
 *      Head [deg] is the first supervariable in a degree list.  All
alpar@1
   420
 *      supervariables i in a degree list Head [deg] have the same approximate
alpar@1
   421
 *      degree, namely, deg = Degree [i].  If the list Head [deg] is empty then
alpar@1
   422
 *      Head [deg] = EMPTY.
alpar@1
   423
 *
alpar@1
   424
 *      During supervariable detection Head [hash] also serves as a pointer to
alpar@1
   425
 *      a hash bucket.  If Head [hash] >= 0, there is a degree list of degree
alpar@1
   426
 *      hash.  The hash bucket head pointer is Last [Head [hash]].  If
alpar@1
   427
 *      Head [hash] = EMPTY, then the degree list and hash bucket are both
alpar@1
   428
 *      empty.  If Head [hash] < EMPTY, then the degree list is empty, and
alpar@1
   429
 *      FLIP (Head [hash]) is the head of the hash bucket.  After supervariable
alpar@1
   430
 *      detection is complete, all hash buckets are empty, and the
alpar@1
   431
 *      (Last [Head [hash]] = EMPTY) condition is restored for the non-empty
alpar@1
   432
 *      degree lists.
alpar@1
   433
 *
alpar@1
   434
 * W:  An integer array of size n.  The flag array W determines the status of
alpar@1
   435
 *      elements and variables, and the external degree of elements.
alpar@1
   436
 *
alpar@1
   437
 *      for elements:
alpar@1
   438
 *          if W [e] = 0, then the element e is absorbed.
alpar@1
   439
 *          if W [e] >= wflg, then W [e] - wflg is the size of the set
alpar@1
   440
 *              |Le \ Lme|, in terms of nonzeros (the sum of ABS (Nv [i]) for
alpar@1
   441
 *              each principal variable i that is both in the pattern of
alpar@1
   442
 *              element e and NOT in the pattern of the current pivot element,
alpar@1
   443
 *              me).
alpar@1
   444
 *          if wflg > W [e] > 0, then e is not absorbed and has not yet been
alpar@1
   445
 *              seen in the scan of the element lists in the computation of
alpar@1
   446
 *              |Le\Lme| in Scan 1 below.
alpar@1
   447
 *
alpar@1
   448
 *      for variables:
alpar@1
   449
 *          during supervariable detection, if W [j] != wflg then j is
alpar@1
   450
 *          not in the pattern of variable i.
alpar@1
   451
 *
alpar@1
   452
 *      The W array is initialized by setting W [i] = 1 for all i, and by
alpar@1
   453
 *      setting wflg = 2.  It is reinitialized if wflg becomes too large (to
alpar@1
   454
 *      ensure that wflg+n does not cause integer overflow).
alpar@1
   455
alpar@1
   456
 * ----------------------------------------------------------------------------
alpar@1
   457
 * LOCAL INTEGERS:
alpar@1
   458
 * ----------------------------------------------------------------------------
alpar@1
   459
 */
alpar@1
   460
alpar@1
   461
    Int deg, degme, dext, lemax, e, elenme, eln, i, ilast, inext, j,
alpar@1
   462
        jlast, jnext, k, knt1, knt2, knt3, lenj, ln, me, mindeg, nel, nleft,
alpar@1
   463
        nvi, nvj, nvpiv, slenme, wbig, we, wflg, wnvi, ok, ndense, ncmpa,
alpar@1
   464
        dense, aggressive ;
alpar@1
   465
alpar@1
   466
    unsigned Int hash ;     /* unsigned, so that hash % n is well defined.*/
alpar@1
   467
alpar@1
   468
/*
alpar@1
   469
 * deg:         the degree of a variable or element
alpar@1
   470
 * degme:       size, |Lme|, of the current element, me (= Degree [me])
alpar@1
   471
 * dext:        external degree, |Le \ Lme|, of some element e
alpar@1
   472
 * lemax:       largest |Le| seen so far (called dmax in Fortran version)
alpar@1
   473
 * e:           an element
alpar@1
   474
 * elenme:      the length, Elen [me], of element list of pivotal variable
alpar@1
   475
 * eln:         the length, Elen [...], of an element list
alpar@1
   476
 * hash:        the computed value of the hash function
alpar@1
   477
 * i:           a supervariable
alpar@1
   478
 * ilast:       the entry in a link list preceding i
alpar@1
   479
 * inext:       the entry in a link list following i
alpar@1
   480
 * j:           a supervariable
alpar@1
   481
 * jlast:       the entry in a link list preceding j
alpar@1
   482
 * jnext:       the entry in a link list, or path, following j
alpar@1
   483
 * k:           the pivot order of an element or variable
alpar@1
   484
 * knt1:        loop counter used during element construction
alpar@1
   485
 * knt2:        loop counter used during element construction
alpar@1
   486
 * knt3:        loop counter used during compression
alpar@1
   487
 * lenj:        Len [j]
alpar@1
   488
 * ln:          length of a supervariable list
alpar@1
   489
 * me:          current supervariable being eliminated, and the current
alpar@1
   490
 *                  element created by eliminating that supervariable
alpar@1
   491
 * mindeg:      current minimum degree
alpar@1
   492
 * nel:         number of pivots selected so far
alpar@1
   493
 * nleft:       n - nel, the number of nonpivotal rows/columns remaining
alpar@1
   494
 * nvi:         the number of variables in a supervariable i (= Nv [i])
alpar@1
   495
 * nvj:         the number of variables in a supervariable j (= Nv [j])
alpar@1
   496
 * nvpiv:       number of pivots in current element
alpar@1
   497
 * slenme:      number of variables in variable list of pivotal variable
alpar@1
   498
 * wbig:        = INT_MAX - n for the int version, UF_long_max - n for the
alpar@1
   499
 *                  UF_long version.  wflg is not allowed to be >= wbig.
alpar@1
   500
 * we:          W [e]
alpar@1
   501
 * wflg:        used for flagging the W array.  See description of Iw.
alpar@1
   502
 * wnvi:        wflg - Nv [i]
alpar@1
   503
 * x:           either a supervariable or an element
alpar@1
   504
 *
alpar@1
   505
 * ok:          true if supervariable j can be absorbed into i
alpar@1
   506
 * ndense:      number of "dense" rows/columns
alpar@1
   507
 * dense:       rows/columns with initial degree > dense are considered "dense"
alpar@1
   508
 * aggressive:  true if aggressive absorption is being performed
alpar@1
   509
 * ncmpa:       number of garbage collections
alpar@1
   510
alpar@1
   511
 * ----------------------------------------------------------------------------
alpar@1
   512
 * LOCAL DOUBLES, used for statistical output only (except for alpha):
alpar@1
   513
 * ----------------------------------------------------------------------------
alpar@1
   514
 */
alpar@1
   515
alpar@1
   516
    double f, r, ndiv, s, nms_lu, nms_ldl, dmax, alpha, lnz, lnzme ;
alpar@1
   517
alpar@1
   518
/*
alpar@1
   519
 * f:           nvpiv
alpar@1
   520
 * r:           degme + nvpiv
alpar@1
   521
 * ndiv:        number of divisions for LU or LDL' factorizations
alpar@1
   522
 * s:           number of multiply-subtract pairs for LU factorization, for the
alpar@1
   523
 *                  current element me
alpar@1
   524
 * nms_lu       number of multiply-subtract pairs for LU factorization
alpar@1
   525
 * nms_ldl      number of multiply-subtract pairs for LDL' factorization
alpar@1
   526
 * dmax:        the largest number of entries in any column of L, including the
alpar@1
   527
 *                  diagonal
alpar@1
   528
 * alpha:       "dense" degree ratio
alpar@1
   529
 * lnz:         the number of nonzeros in L (excluding the diagonal)
alpar@1
   530
 * lnzme:       the number of nonzeros in L (excl. the diagonal) for the
alpar@1
   531
 *                  current element me
alpar@1
   532
alpar@1
   533
 * ----------------------------------------------------------------------------
alpar@1
   534
 * LOCAL "POINTERS" (indices into the Iw array)
alpar@1
   535
 * ----------------------------------------------------------------------------
alpar@1
   536
*/
alpar@1
   537
alpar@1
   538
    Int p, p1, p2, p3, p4, pdst, pend, pj, pme, pme1, pme2, pn, psrc ;
alpar@1
   539
alpar@1
   540
/*
alpar@1
   541
 * Any parameter (Pe [...] or pfree) or local variable starting with "p" (for
alpar@1
   542
 * Pointer) is an index into Iw, and all indices into Iw use variables starting
alpar@1
   543
 * with "p."  The only exception to this rule is the iwlen input argument.
alpar@1
   544
 *
alpar@1
   545
 * p:           pointer into lots of things
alpar@1
   546
 * p1:          Pe [i] for some variable i (start of element list)
alpar@1
   547
 * p2:          Pe [i] + Elen [i] -  1 for some variable i
alpar@1
   548
 * p3:          index of first supervariable in clean list
alpar@1
   549
 * p4:          
alpar@1
   550
 * pdst:        destination pointer, for compression
alpar@1
   551
 * pend:        end of memory to compress
alpar@1
   552
 * pj:          pointer into an element or variable
alpar@1
   553
 * pme:         pointer into the current element (pme1...pme2)
alpar@1
   554
 * pme1:        the current element, me, is stored in Iw [pme1...pme2]
alpar@1
   555
 * pme2:        the end of the current element
alpar@1
   556
 * pn:          pointer into a "clean" variable, also used to compress
alpar@1
   557
 * psrc:        source pointer, for compression
alpar@1
   558
*/
alpar@1
   559
alpar@1
   560
/* ========================================================================= */
alpar@1
   561
/*  INITIALIZATIONS */
alpar@1
   562
/* ========================================================================= */
alpar@1
   563
alpar@1
   564
    /* Note that this restriction on iwlen is slightly more restrictive than
alpar@1
   565
     * what is actually required in AMD_2.  AMD_2 can operate with no elbow
alpar@1
   566
     * room at all, but it will be slow.  For better performance, at least
alpar@1
   567
     * size-n elbow room is enforced. */
alpar@1
   568
    ASSERT (iwlen >= pfree + n) ;
alpar@1
   569
    ASSERT (n > 0) ;
alpar@1
   570
alpar@1
   571
    /* initialize output statistics */
alpar@1
   572
    lnz = 0 ;
alpar@1
   573
    ndiv = 0 ;
alpar@1
   574
    nms_lu = 0 ;
alpar@1
   575
    nms_ldl = 0 ;
alpar@1
   576
    dmax = 1 ;
alpar@1
   577
    me = EMPTY ;
alpar@1
   578
alpar@1
   579
    mindeg = 0 ;
alpar@1
   580
    ncmpa = 0 ;
alpar@1
   581
    nel = 0 ;
alpar@1
   582
    lemax = 0 ;
alpar@1
   583
alpar@1
   584
    /* get control parameters */
alpar@1
   585
    if (Control != (double *) NULL)
alpar@1
   586
    {
alpar@1
   587
        alpha = Control [AMD_DENSE] ;
alpar@1
   588
        aggressive = (Control [AMD_AGGRESSIVE] != 0) ;
alpar@1
   589
    }
alpar@1
   590
    else
alpar@1
   591
    {
alpar@1
   592
        alpha = AMD_DEFAULT_DENSE ;
alpar@1
   593
        aggressive = AMD_DEFAULT_AGGRESSIVE ;
alpar@1
   594
    }
alpar@1
   595
    /* Note: if alpha is NaN, this is undefined: */
alpar@1
   596
    if (alpha < 0)
alpar@1
   597
    {
alpar@1
   598
        /* only remove completely dense rows/columns */
alpar@1
   599
        dense = n-2 ;
alpar@1
   600
    }
alpar@1
   601
    else
alpar@1
   602
    {
alpar@1
   603
        dense = alpha * sqrt ((double) n) ;
alpar@1
   604
    }
alpar@1
   605
    dense = MAX (16, dense) ;
alpar@1
   606
    dense = MIN (n,  dense) ;
alpar@1
   607
    AMD_DEBUG1 (("\n\nAMD (debug), alpha %g, aggr. "ID"\n",
alpar@1
   608
        alpha, aggressive)) ;
alpar@1
   609
alpar@1
   610
    for (i = 0 ; i < n ; i++)
alpar@1
   611
    {
alpar@1
   612
        Last [i] = EMPTY ;
alpar@1
   613
        Head [i] = EMPTY ;
alpar@1
   614
        Next [i] = EMPTY ;
alpar@1
   615
        /* if separate Hhead array is used for hash buckets: *
alpar@1
   616
        Hhead [i] = EMPTY ;
alpar@1
   617
        */
alpar@1
   618
        Nv [i] = 1 ;
alpar@1
   619
        W [i] = 1 ;
alpar@1
   620
        Elen [i] = 0 ;
alpar@1
   621
        Degree [i] = Len [i] ;
alpar@1
   622
    }
alpar@1
   623
alpar@1
   624
#ifndef NDEBUG
alpar@1
   625
    AMD_DEBUG1 (("\n======Nel "ID" initial\n", nel)) ;
alpar@1
   626
    AMD_dump (n, Pe, Iw, Len, iwlen, pfree, Nv, Next, Last,
alpar@1
   627
                Head, Elen, Degree, W, -1) ;
alpar@1
   628
#endif
alpar@1
   629
alpar@1
   630
    /* initialize wflg */
alpar@1
   631
    wbig = Int_MAX - n ;
alpar@1
   632
    wflg = clear_flag (0, wbig, W, n) ;
alpar@1
   633
alpar@1
   634
    /* --------------------------------------------------------------------- */
alpar@1
   635
    /* initialize degree lists and eliminate dense and empty rows */
alpar@1
   636
    /* --------------------------------------------------------------------- */
alpar@1
   637
alpar@1
   638
    ndense = 0 ;
alpar@1
   639
alpar@1
   640
    for (i = 0 ; i < n ; i++)
alpar@1
   641
    {
alpar@1
   642
        deg = Degree [i] ;
alpar@1
   643
        ASSERT (deg >= 0 && deg < n) ;
alpar@1
   644
        if (deg == 0)
alpar@1
   645
        {
alpar@1
   646
alpar@1
   647
            /* -------------------------------------------------------------
alpar@1
   648
             * we have a variable that can be eliminated at once because
alpar@1
   649
             * there is no off-diagonal non-zero in its row.  Note that
alpar@1
   650
             * Nv [i] = 1 for an empty variable i.  It is treated just
alpar@1
   651
             * the same as an eliminated element i.
alpar@1
   652
             * ------------------------------------------------------------- */
alpar@1
   653
alpar@1
   654
            Elen [i] = FLIP (1) ;
alpar@1
   655
            nel++ ;
alpar@1
   656
            Pe [i] = EMPTY ;
alpar@1
   657
            W [i] = 0 ;
alpar@1
   658
alpar@1
   659
        }
alpar@1
   660
        else if (deg > dense)
alpar@1
   661
        {
alpar@1
   662
alpar@1
   663
            /* -------------------------------------------------------------
alpar@1
   664
             * Dense variables are not treated as elements, but as unordered,
alpar@1
   665
             * non-principal variables that have no parent.  They do not take
alpar@1
   666
             * part in the postorder, since Nv [i] = 0.  Note that the Fortran
alpar@1
   667
             * version does not have this option.
alpar@1
   668
             * ------------------------------------------------------------- */
alpar@1
   669
alpar@1
   670
            AMD_DEBUG1 (("Dense node "ID" degree "ID"\n", i, deg)) ;
alpar@1
   671
            ndense++ ;
alpar@1
   672
            Nv [i] = 0 ;                /* do not postorder this node */
alpar@1
   673
            Elen [i] = EMPTY ;
alpar@1
   674
            nel++ ;
alpar@1
   675
            Pe [i] = EMPTY ;
alpar@1
   676
alpar@1
   677
        }
alpar@1
   678
        else
alpar@1
   679
        {
alpar@1
   680
alpar@1
   681
            /* -------------------------------------------------------------
alpar@1
   682
             * place i in the degree list corresponding to its degree
alpar@1
   683
             * ------------------------------------------------------------- */
alpar@1
   684
alpar@1
   685
            inext = Head [deg] ;
alpar@1
   686
            ASSERT (inext >= EMPTY && inext < n) ;
alpar@1
   687
            if (inext != EMPTY) Last [inext] = i ;
alpar@1
   688
            Next [i] = inext ;
alpar@1
   689
            Head [deg] = i ;
alpar@1
   690
alpar@1
   691
        }
alpar@1
   692
    }
alpar@1
   693
alpar@1
   694
/* ========================================================================= */
alpar@1
   695
/* WHILE (selecting pivots) DO */
alpar@1
   696
/* ========================================================================= */
alpar@1
   697
alpar@1
   698
    while (nel < n)
alpar@1
   699
    {
alpar@1
   700
alpar@1
   701
#ifndef NDEBUG
alpar@1
   702
        AMD_DEBUG1 (("\n======Nel "ID"\n", nel)) ;
alpar@1
   703
        if (AMD_debug >= 2)
alpar@1
   704
        {
alpar@1
   705
            AMD_dump (n, Pe, Iw, Len, iwlen, pfree, Nv, Next,
alpar@1
   706
                    Last, Head, Elen, Degree, W, nel) ;
alpar@1
   707
        }
alpar@1
   708
#endif
alpar@1
   709
alpar@1
   710
/* ========================================================================= */
alpar@1
   711
/* GET PIVOT OF MINIMUM DEGREE */
alpar@1
   712
/* ========================================================================= */
alpar@1
   713
alpar@1
   714
        /* ----------------------------------------------------------------- */
alpar@1
   715
        /* find next supervariable for elimination */
alpar@1
   716
        /* ----------------------------------------------------------------- */
alpar@1
   717
alpar@1
   718
        ASSERT (mindeg >= 0 && mindeg < n) ;
alpar@1
   719
        for (deg = mindeg ; deg < n ; deg++)
alpar@1
   720
        {
alpar@1
   721
            me = Head [deg] ;
alpar@1
   722
            if (me != EMPTY) break ;
alpar@1
   723
        }
alpar@1
   724
        mindeg = deg ;
alpar@1
   725
        ASSERT (me >= 0 && me < n) ;
alpar@1
   726
        AMD_DEBUG1 (("=================me: "ID"\n", me)) ;
alpar@1
   727
alpar@1
   728
        /* ----------------------------------------------------------------- */
alpar@1
   729
        /* remove chosen variable from link list */
alpar@1
   730
        /* ----------------------------------------------------------------- */
alpar@1
   731
alpar@1
   732
        inext = Next [me] ;
alpar@1
   733
        ASSERT (inext >= EMPTY && inext < n) ;
alpar@1
   734
        if (inext != EMPTY) Last [inext] = EMPTY ;
alpar@1
   735
        Head [deg] = inext ;
alpar@1
   736
alpar@1
   737
        /* ----------------------------------------------------------------- */
alpar@1
   738
        /* me represents the elimination of pivots nel to nel+Nv[me]-1. */
alpar@1
   739
        /* place me itself as the first in this set. */
alpar@1
   740
        /* ----------------------------------------------------------------- */
alpar@1
   741
alpar@1
   742
        elenme = Elen [me] ;
alpar@1
   743
        nvpiv = Nv [me] ;
alpar@1
   744
        ASSERT (nvpiv > 0) ;
alpar@1
   745
        nel += nvpiv ;
alpar@1
   746
alpar@1
   747
/* ========================================================================= */
alpar@1
   748
/* CONSTRUCT NEW ELEMENT */
alpar@1
   749
/* ========================================================================= */
alpar@1
   750
alpar@1
   751
        /* -----------------------------------------------------------------
alpar@1
   752
         * At this point, me is the pivotal supervariable.  It will be
alpar@1
   753
         * converted into the current element.  Scan list of the pivotal
alpar@1
   754
         * supervariable, me, setting tree pointers and constructing new list
alpar@1
   755
         * of supervariables for the new element, me.  p is a pointer to the
alpar@1
   756
         * current position in the old list.
alpar@1
   757
         * ----------------------------------------------------------------- */
alpar@1
   758
alpar@1
   759
        /* flag the variable "me" as being in Lme by negating Nv [me] */
alpar@1
   760
        Nv [me] = -nvpiv ;
alpar@1
   761
        degme = 0 ;
alpar@1
   762
        ASSERT (Pe [me] >= 0 && Pe [me] < iwlen) ;
alpar@1
   763
alpar@1
   764
        if (elenme == 0)
alpar@1
   765
        {
alpar@1
   766
alpar@1
   767
            /* ------------------------------------------------------------- */
alpar@1
   768
            /* construct the new element in place */
alpar@1
   769
            /* ------------------------------------------------------------- */
alpar@1
   770
alpar@1
   771
            pme1 = Pe [me] ;
alpar@1
   772
            pme2 = pme1 - 1 ;
alpar@1
   773
alpar@1
   774
            for (p = pme1 ; p <= pme1 + Len [me] - 1 ; p++)
alpar@1
   775
            {
alpar@1
   776
                i = Iw [p] ;
alpar@1
   777
                ASSERT (i >= 0 && i < n && Nv [i] >= 0) ;
alpar@1
   778
                nvi = Nv [i] ;
alpar@1
   779
                if (nvi > 0)
alpar@1
   780
                {
alpar@1
   781
alpar@1
   782
                    /* ----------------------------------------------------- */
alpar@1
   783
                    /* i is a principal variable not yet placed in Lme. */
alpar@1
   784
                    /* store i in new list */
alpar@1
   785
                    /* ----------------------------------------------------- */
alpar@1
   786
alpar@1
   787
                    /* flag i as being in Lme by negating Nv [i] */
alpar@1
   788
                    degme += nvi ;
alpar@1
   789
                    Nv [i] = -nvi ;
alpar@1
   790
                    Iw [++pme2] = i ;
alpar@1
   791
alpar@1
   792
                    /* ----------------------------------------------------- */
alpar@1
   793
                    /* remove variable i from degree list. */
alpar@1
   794
                    /* ----------------------------------------------------- */
alpar@1
   795
alpar@1
   796
                    ilast = Last [i] ;
alpar@1
   797
                    inext = Next [i] ;
alpar@1
   798
                    ASSERT (ilast >= EMPTY && ilast < n) ;
alpar@1
   799
                    ASSERT (inext >= EMPTY && inext < n) ;
alpar@1
   800
                    if (inext != EMPTY) Last [inext] = ilast ;
alpar@1
   801
                    if (ilast != EMPTY)
alpar@1
   802
                    {
alpar@1
   803
                        Next [ilast] = inext ;
alpar@1
   804
                    }
alpar@1
   805
                    else
alpar@1
   806
                    {
alpar@1
   807
                        /* i is at the head of the degree list */
alpar@1
   808
                        ASSERT (Degree [i] >= 0 && Degree [i] < n) ;
alpar@1
   809
                        Head [Degree [i]] = inext ;
alpar@1
   810
                    }
alpar@1
   811
                }
alpar@1
   812
            }
alpar@1
   813
        }
alpar@1
   814
        else
alpar@1
   815
        {
alpar@1
   816
alpar@1
   817
            /* ------------------------------------------------------------- */
alpar@1
   818
            /* construct the new element in empty space, Iw [pfree ...] */
alpar@1
   819
            /* ------------------------------------------------------------- */
alpar@1
   820
alpar@1
   821
            p = Pe [me] ;
alpar@1
   822
            pme1 = pfree ;
alpar@1
   823
            slenme = Len [me] - elenme ;
alpar@1
   824
alpar@1
   825
            for (knt1 = 1 ; knt1 <= elenme + 1 ; knt1++)
alpar@1
   826
            {
alpar@1
   827
alpar@1
   828
                if (knt1 > elenme)
alpar@1
   829
                {
alpar@1
   830
                    /* search the supervariables in me. */
alpar@1
   831
                    e = me ;
alpar@1
   832
                    pj = p ;
alpar@1
   833
                    ln = slenme ;
alpar@1
   834
                    AMD_DEBUG2 (("Search sv: "ID" "ID" "ID"\n", me,pj,ln)) ;
alpar@1
   835
                }
alpar@1
   836
                else
alpar@1
   837
                {
alpar@1
   838
                    /* search the elements in me. */
alpar@1
   839
                    e = Iw [p++] ;
alpar@1
   840
                    ASSERT (e >= 0 && e < n) ;
alpar@1
   841
                    pj = Pe [e] ;
alpar@1
   842
                    ln = Len [e] ;
alpar@1
   843
                    AMD_DEBUG2 (("Search element e "ID" in me "ID"\n", e,me)) ;
alpar@1
   844
                    ASSERT (Elen [e] < EMPTY && W [e] > 0 && pj >= 0) ;
alpar@1
   845
                }
alpar@1
   846
                ASSERT (ln >= 0 && (ln == 0 || (pj >= 0 && pj < iwlen))) ;
alpar@1
   847
alpar@1
   848
                /* ---------------------------------------------------------
alpar@1
   849
                 * search for different supervariables and add them to the
alpar@1
   850
                 * new list, compressing when necessary. this loop is
alpar@1
   851
                 * executed once for each element in the list and once for
alpar@1
   852
                 * all the supervariables in the list.
alpar@1
   853
                 * --------------------------------------------------------- */
alpar@1
   854
alpar@1
   855
                for (knt2 = 1 ; knt2 <= ln ; knt2++)
alpar@1
   856
                {
alpar@1
   857
                    i = Iw [pj++] ;
alpar@1
   858
                    ASSERT (i >= 0 && i < n && (i == me || Elen [i] >= EMPTY));
alpar@1
   859
                    nvi = Nv [i] ;
alpar@1
   860
                    AMD_DEBUG2 ((": "ID" "ID" "ID" "ID"\n",
alpar@1
   861
                                i, Elen [i], Nv [i], wflg)) ;
alpar@1
   862
alpar@1
   863
                    if (nvi > 0)
alpar@1
   864
                    {
alpar@1
   865
alpar@1
   866
                        /* ------------------------------------------------- */
alpar@1
   867
                        /* compress Iw, if necessary */
alpar@1
   868
                        /* ------------------------------------------------- */
alpar@1
   869
alpar@1
   870
                        if (pfree >= iwlen)
alpar@1
   871
                        {
alpar@1
   872
alpar@1
   873
                            AMD_DEBUG1 (("GARBAGE COLLECTION\n")) ;
alpar@1
   874
alpar@1
   875
                            /* prepare for compressing Iw by adjusting pointers
alpar@1
   876
                             * and lengths so that the lists being searched in
alpar@1
   877
                             * the inner and outer loops contain only the
alpar@1
   878
                             * remaining entries. */
alpar@1
   879
alpar@1
   880
                            Pe [me] = p ;
alpar@1
   881
                            Len [me] -= knt1 ;
alpar@1
   882
                            /* check if nothing left of supervariable me */
alpar@1
   883
                            if (Len [me] == 0) Pe [me] = EMPTY ;
alpar@1
   884
                            Pe [e] = pj ;
alpar@1
   885
                            Len [e] = ln - knt2 ;
alpar@1
   886
                            /* nothing left of element e */
alpar@1
   887
                            if (Len [e] == 0) Pe [e] = EMPTY ;
alpar@1
   888
alpar@1
   889
                            ncmpa++ ;   /* one more garbage collection */
alpar@1
   890
alpar@1
   891
                            /* store first entry of each object in Pe */
alpar@1
   892
                            /* FLIP the first entry in each object */
alpar@1
   893
                            for (j = 0 ; j < n ; j++)
alpar@1
   894
                            {
alpar@1
   895
                                pn = Pe [j] ;
alpar@1
   896
                                if (pn >= 0)
alpar@1
   897
                                {
alpar@1
   898
                                    ASSERT (pn >= 0 && pn < iwlen) ;
alpar@1
   899
                                    Pe [j] = Iw [pn] ;
alpar@1
   900
                                    Iw [pn] = FLIP (j) ;
alpar@1
   901
                                }
alpar@1
   902
                            }
alpar@1
   903
alpar@1
   904
                            /* psrc/pdst point to source/destination */
alpar@1
   905
                            psrc = 0 ;
alpar@1
   906
                            pdst = 0 ;
alpar@1
   907
                            pend = pme1 - 1 ;
alpar@1
   908
alpar@1
   909
                            while (psrc <= pend)
alpar@1
   910
                            {
alpar@1
   911
                                /* search for next FLIP'd entry */
alpar@1
   912
                                j = FLIP (Iw [psrc++]) ;
alpar@1
   913
                                if (j >= 0)
alpar@1
   914
                                {
alpar@1
   915
                                    AMD_DEBUG2 (("Got object j: "ID"\n", j)) ;
alpar@1
   916
                                    Iw [pdst] = Pe [j] ;
alpar@1
   917
                                    Pe [j] = pdst++ ;
alpar@1
   918
                                    lenj = Len [j] ;
alpar@1
   919
                                    /* copy from source to destination */
alpar@1
   920
                                    for (knt3 = 0 ; knt3 <= lenj - 2 ; knt3++)
alpar@1
   921
                                    {
alpar@1
   922
                                        Iw [pdst++] = Iw [psrc++] ;
alpar@1
   923
                                    }
alpar@1
   924
                                }
alpar@1
   925
                            }
alpar@1
   926
alpar@1
   927
                            /* move the new partially-constructed element */
alpar@1
   928
                            p1 = pdst ;
alpar@1
   929
                            for (psrc = pme1 ; psrc <= pfree-1 ; psrc++)
alpar@1
   930
                            {
alpar@1
   931
                                Iw [pdst++] = Iw [psrc] ;
alpar@1
   932
                            }
alpar@1
   933
                            pme1 = p1 ;
alpar@1
   934
                            pfree = pdst ;
alpar@1
   935
                            pj = Pe [e] ;
alpar@1
   936
                            p = Pe [me] ;
alpar@1
   937
alpar@1
   938
                        }
alpar@1
   939
alpar@1
   940
                        /* ------------------------------------------------- */
alpar@1
   941
                        /* i is a principal variable not yet placed in Lme */
alpar@1
   942
                        /* store i in new list */
alpar@1
   943
                        /* ------------------------------------------------- */
alpar@1
   944
alpar@1
   945
                        /* flag i as being in Lme by negating Nv [i] */
alpar@1
   946
                        degme += nvi ;
alpar@1
   947
                        Nv [i] = -nvi ;
alpar@1
   948
                        Iw [pfree++] = i ;
alpar@1
   949
                        AMD_DEBUG2 (("     s: "ID"     nv "ID"\n", i, Nv [i]));
alpar@1
   950
alpar@1
   951
                        /* ------------------------------------------------- */
alpar@1
   952
                        /* remove variable i from degree link list */
alpar@1
   953
                        /* ------------------------------------------------- */
alpar@1
   954
alpar@1
   955
                        ilast = Last [i] ;
alpar@1
   956
                        inext = Next [i] ;
alpar@1
   957
                        ASSERT (ilast >= EMPTY && ilast < n) ;
alpar@1
   958
                        ASSERT (inext >= EMPTY && inext < n) ;
alpar@1
   959
                        if (inext != EMPTY) Last [inext] = ilast ;
alpar@1
   960
                        if (ilast != EMPTY)
alpar@1
   961
                        {
alpar@1
   962
                            Next [ilast] = inext ;
alpar@1
   963
                        }
alpar@1
   964
                        else
alpar@1
   965
                        {
alpar@1
   966
                            /* i is at the head of the degree list */
alpar@1
   967
                            ASSERT (Degree [i] >= 0 && Degree [i] < n) ;
alpar@1
   968
                            Head [Degree [i]] = inext ;
alpar@1
   969
                        }
alpar@1
   970
                    }
alpar@1
   971
                }
alpar@1
   972
alpar@1
   973
                if (e != me)
alpar@1
   974
                {
alpar@1
   975
                    /* set tree pointer and flag to indicate element e is
alpar@1
   976
                     * absorbed into new element me (the parent of e is me) */
alpar@1
   977
                    AMD_DEBUG1 ((" Element "ID" => "ID"\n", e, me)) ;
alpar@1
   978
                    Pe [e] = FLIP (me) ;
alpar@1
   979
                    W [e] = 0 ;
alpar@1
   980
                }
alpar@1
   981
            }
alpar@1
   982
alpar@1
   983
            pme2 = pfree - 1 ;
alpar@1
   984
        }
alpar@1
   985
alpar@1
   986
        /* ----------------------------------------------------------------- */
alpar@1
   987
        /* me has now been converted into an element in Iw [pme1..pme2] */
alpar@1
   988
        /* ----------------------------------------------------------------- */
alpar@1
   989
alpar@1
   990
        /* degme holds the external degree of new element */
alpar@1
   991
        Degree [me] = degme ;
alpar@1
   992
        Pe [me] = pme1 ;
alpar@1
   993
        Len [me] = pme2 - pme1 + 1 ;
alpar@1
   994
        ASSERT (Pe [me] >= 0 && Pe [me] < iwlen) ;
alpar@1
   995
alpar@1
   996
        Elen [me] = FLIP (nvpiv + degme) ;
alpar@1
   997
        /* FLIP (Elen (me)) is now the degree of pivot (including
alpar@1
   998
         * diagonal part). */
alpar@1
   999
alpar@1
  1000
#ifndef NDEBUG
alpar@1
  1001
        AMD_DEBUG2 (("New element structure: length= "ID"\n", pme2-pme1+1)) ;
alpar@1
  1002
        for (pme = pme1 ; pme <= pme2 ; pme++) AMD_DEBUG3 ((" "ID"", Iw[pme]));
alpar@1
  1003
        AMD_DEBUG3 (("\n")) ;
alpar@1
  1004
#endif
alpar@1
  1005
alpar@1
  1006
        /* ----------------------------------------------------------------- */
alpar@1
  1007
        /* make sure that wflg is not too large. */
alpar@1
  1008
        /* ----------------------------------------------------------------- */
alpar@1
  1009
alpar@1
  1010
        /* With the current value of wflg, wflg+n must not cause integer
alpar@1
  1011
         * overflow */
alpar@1
  1012
alpar@1
  1013
        wflg = clear_flag (wflg, wbig, W, n) ;
alpar@1
  1014
alpar@1
  1015
/* ========================================================================= */
alpar@1
  1016
/* COMPUTE (W [e] - wflg) = |Le\Lme| FOR ALL ELEMENTS */
alpar@1
  1017
/* ========================================================================= */
alpar@1
  1018
alpar@1
  1019
        /* -----------------------------------------------------------------
alpar@1
  1020
         * Scan 1:  compute the external degrees of previous elements with
alpar@1
  1021
         * respect to the current element.  That is:
alpar@1
  1022
         *       (W [e] - wflg) = |Le \ Lme|
alpar@1
  1023
         * for each element e that appears in any supervariable in Lme.  The
alpar@1
  1024
         * notation Le refers to the pattern (list of supervariables) of a
alpar@1
  1025
         * previous element e, where e is not yet absorbed, stored in
alpar@1
  1026
         * Iw [Pe [e] + 1 ... Pe [e] + Len [e]].  The notation Lme
alpar@1
  1027
         * refers to the pattern of the current element (stored in
alpar@1
  1028
         * Iw [pme1..pme2]).   If aggressive absorption is enabled, and
alpar@1
  1029
         * (W [e] - wflg) becomes zero, then the element e will be absorbed
alpar@1
  1030
         * in Scan 2.
alpar@1
  1031
         * ----------------------------------------------------------------- */
alpar@1
  1032
alpar@1
  1033
        AMD_DEBUG2 (("me: ")) ;
alpar@1
  1034
        for (pme = pme1 ; pme <= pme2 ; pme++)
alpar@1
  1035
        {
alpar@1
  1036
            i = Iw [pme] ;
alpar@1
  1037
            ASSERT (i >= 0 && i < n) ;
alpar@1
  1038
            eln = Elen [i] ;
alpar@1
  1039
            AMD_DEBUG3 ((""ID" Elen "ID": \n", i, eln)) ;
alpar@1
  1040
            if (eln > 0)
alpar@1
  1041
            {
alpar@1
  1042
                /* note that Nv [i] has been negated to denote i in Lme: */
alpar@1
  1043
                nvi = -Nv [i] ;
alpar@1
  1044
                ASSERT (nvi > 0 && Pe [i] >= 0 && Pe [i] < iwlen) ;
alpar@1
  1045
                wnvi = wflg - nvi ;
alpar@1
  1046
                for (p = Pe [i] ; p <= Pe [i] + eln - 1 ; p++)
alpar@1
  1047
                {
alpar@1
  1048
                    e = Iw [p] ;
alpar@1
  1049
                    ASSERT (e >= 0 && e < n) ;
alpar@1
  1050
                    we = W [e] ;
alpar@1
  1051
                    AMD_DEBUG4 (("    e "ID" we "ID" ", e, we)) ;
alpar@1
  1052
                    if (we >= wflg)
alpar@1
  1053
                    {
alpar@1
  1054
                        /* unabsorbed element e has been seen in this loop */
alpar@1
  1055
                        AMD_DEBUG4 (("    unabsorbed, first time seen")) ;
alpar@1
  1056
                        we -= nvi ;
alpar@1
  1057
                    }
alpar@1
  1058
                    else if (we != 0)
alpar@1
  1059
                    {
alpar@1
  1060
                        /* e is an unabsorbed element */
alpar@1
  1061
                        /* this is the first we have seen e in all of Scan 1 */
alpar@1
  1062
                        AMD_DEBUG4 (("    unabsorbed")) ;
alpar@1
  1063
                        we = Degree [e] + wnvi ;
alpar@1
  1064
                    }
alpar@1
  1065
                    AMD_DEBUG4 (("\n")) ;
alpar@1
  1066
                    W [e] = we ;
alpar@1
  1067
                }
alpar@1
  1068
            }
alpar@1
  1069
        }
alpar@1
  1070
        AMD_DEBUG2 (("\n")) ;
alpar@1
  1071
alpar@1
  1072
/* ========================================================================= */
alpar@1
  1073
/* DEGREE UPDATE AND ELEMENT ABSORPTION */
alpar@1
  1074
/* ========================================================================= */
alpar@1
  1075
alpar@1
  1076
        /* -----------------------------------------------------------------
alpar@1
  1077
         * Scan 2:  for each i in Lme, sum up the degree of Lme (which is
alpar@1
  1078
         * degme), plus the sum of the external degrees of each Le for the
alpar@1
  1079
         * elements e appearing within i, plus the supervariables in i.
alpar@1
  1080
         * Place i in hash list.
alpar@1
  1081
         * ----------------------------------------------------------------- */
alpar@1
  1082
alpar@1
  1083
        for (pme = pme1 ; pme <= pme2 ; pme++)
alpar@1
  1084
        {
alpar@1
  1085
            i = Iw [pme] ;
alpar@1
  1086
            ASSERT (i >= 0 && i < n && Nv [i] < 0 && Elen [i] >= 0) ;
alpar@1
  1087
            AMD_DEBUG2 (("Updating: i "ID" "ID" "ID"\n", i, Elen[i], Len [i]));
alpar@1
  1088
            p1 = Pe [i] ;
alpar@1
  1089
            p2 = p1 + Elen [i] - 1 ;
alpar@1
  1090
            pn = p1 ;
alpar@1
  1091
            hash = 0 ;
alpar@1
  1092
            deg = 0 ;
alpar@1
  1093
            ASSERT (p1 >= 0 && p1 < iwlen && p2 >= -1 && p2 < iwlen) ;
alpar@1
  1094
alpar@1
  1095
            /* ------------------------------------------------------------- */
alpar@1
  1096
            /* scan the element list associated with supervariable i */
alpar@1
  1097
            /* ------------------------------------------------------------- */
alpar@1
  1098
alpar@1
  1099
            /* UMFPACK/MA38-style approximate degree: */
alpar@1
  1100
            if (aggressive)
alpar@1
  1101
            {
alpar@1
  1102
                for (p = p1 ; p <= p2 ; p++)
alpar@1
  1103
                {
alpar@1
  1104
                    e = Iw [p] ;
alpar@1
  1105
                    ASSERT (e >= 0 && e < n) ;
alpar@1
  1106
                    we = W [e] ;
alpar@1
  1107
                    if (we != 0)
alpar@1
  1108
                    {
alpar@1
  1109
                        /* e is an unabsorbed element */
alpar@1
  1110
                        /* dext = | Le \ Lme | */
alpar@1
  1111
                        dext = we - wflg ;
alpar@1
  1112
                        if (dext > 0)
alpar@1
  1113
                        {
alpar@1
  1114
                            deg += dext ;
alpar@1
  1115
                            Iw [pn++] = e ;
alpar@1
  1116
                            hash += e ;
alpar@1
  1117
                            AMD_DEBUG4 ((" e: "ID" hash = "ID"\n",e,hash)) ;
alpar@1
  1118
                        }
alpar@1
  1119
                        else
alpar@1
  1120
                        {
alpar@1
  1121
                            /* external degree of e is zero, absorb e into me*/
alpar@1
  1122
                            AMD_DEBUG1 ((" Element "ID" =>"ID" (aggressive)\n",
alpar@1
  1123
                                e, me)) ;
alpar@1
  1124
                            ASSERT (dext == 0) ;
alpar@1
  1125
                            Pe [e] = FLIP (me) ;
alpar@1
  1126
                            W [e] = 0 ;
alpar@1
  1127
                        }
alpar@1
  1128
                    }
alpar@1
  1129
                }
alpar@1
  1130
            }
alpar@1
  1131
            else
alpar@1
  1132
            {
alpar@1
  1133
                for (p = p1 ; p <= p2 ; p++)
alpar@1
  1134
                {
alpar@1
  1135
                    e = Iw [p] ;
alpar@1
  1136
                    ASSERT (e >= 0 && e < n) ;
alpar@1
  1137
                    we = W [e] ;
alpar@1
  1138
                    if (we != 0)
alpar@1
  1139
                    {
alpar@1
  1140
                        /* e is an unabsorbed element */
alpar@1
  1141
                        dext = we - wflg ;
alpar@1
  1142
                        ASSERT (dext >= 0) ;
alpar@1
  1143
                        deg += dext ;
alpar@1
  1144
                        Iw [pn++] = e ;
alpar@1
  1145
                        hash += e ;
alpar@1
  1146
                        AMD_DEBUG4 (("  e: "ID" hash = "ID"\n",e,hash)) ;
alpar@1
  1147
                    }
alpar@1
  1148
                }
alpar@1
  1149
            }
alpar@1
  1150
alpar@1
  1151
            /* count the number of elements in i (including me): */
alpar@1
  1152
            Elen [i] = pn - p1 + 1 ;
alpar@1
  1153
alpar@1
  1154
            /* ------------------------------------------------------------- */
alpar@1
  1155
            /* scan the supervariables in the list associated with i */
alpar@1
  1156
            /* ------------------------------------------------------------- */
alpar@1
  1157
alpar@1
  1158
            /* The bulk of the AMD run time is typically spent in this loop,
alpar@1
  1159
             * particularly if the matrix has many dense rows that are not
alpar@1
  1160
             * removed prior to ordering. */
alpar@1
  1161
            p3 = pn ;
alpar@1
  1162
            p4 = p1 + Len [i] ;
alpar@1
  1163
            for (p = p2 + 1 ; p < p4 ; p++)
alpar@1
  1164
            {
alpar@1
  1165
                j = Iw [p] ;
alpar@1
  1166
                ASSERT (j >= 0 && j < n) ;
alpar@1
  1167
                nvj = Nv [j] ;
alpar@1
  1168
                if (nvj > 0)
alpar@1
  1169
                {
alpar@1
  1170
                    /* j is unabsorbed, and not in Lme. */
alpar@1
  1171
                    /* add to degree and add to new list */
alpar@1
  1172
                    deg += nvj ;
alpar@1
  1173
                    Iw [pn++] = j ;
alpar@1
  1174
                    hash += j ;
alpar@1
  1175
                    AMD_DEBUG4 (("  s: "ID" hash "ID" Nv[j]= "ID"\n",
alpar@1
  1176
                                j, hash, nvj)) ;
alpar@1
  1177
                }
alpar@1
  1178
            }
alpar@1
  1179
alpar@1
  1180
            /* ------------------------------------------------------------- */
alpar@1
  1181
            /* update the degree and check for mass elimination */
alpar@1
  1182
            /* ------------------------------------------------------------- */
alpar@1
  1183
alpar@1
  1184
            /* with aggressive absorption, deg==0 is identical to the
alpar@1
  1185
             * Elen [i] == 1 && p3 == pn test, below. */
alpar@1
  1186
            ASSERT (IMPLIES (aggressive, (deg==0) == (Elen[i]==1 && p3==pn))) ;
alpar@1
  1187
alpar@1
  1188
            if (Elen [i] == 1 && p3 == pn)
alpar@1
  1189
            {
alpar@1
  1190
alpar@1
  1191
                /* --------------------------------------------------------- */
alpar@1
  1192
                /* mass elimination */
alpar@1
  1193
                /* --------------------------------------------------------- */
alpar@1
  1194
alpar@1
  1195
                /* There is nothing left of this node except for an edge to
alpar@1
  1196
                 * the current pivot element.  Elen [i] is 1, and there are
alpar@1
  1197
                 * no variables adjacent to node i.  Absorb i into the
alpar@1
  1198
                 * current pivot element, me.  Note that if there are two or
alpar@1
  1199
                 * more mass eliminations, fillin due to mass elimination is
alpar@1
  1200
                 * possible within the nvpiv-by-nvpiv pivot block.  It is this
alpar@1
  1201
                 * step that causes AMD's analysis to be an upper bound.
alpar@1
  1202
                 *
alpar@1
  1203
                 * The reason is that the selected pivot has a lower
alpar@1
  1204
                 * approximate degree than the true degree of the two mass
alpar@1
  1205
                 * eliminated nodes.  There is no edge between the two mass
alpar@1
  1206
                 * eliminated nodes.  They are merged with the current pivot
alpar@1
  1207
                 * anyway.
alpar@1
  1208
                 *
alpar@1
  1209
                 * No fillin occurs in the Schur complement, in any case,
alpar@1
  1210
                 * and this effect does not decrease the quality of the
alpar@1
  1211
                 * ordering itself, just the quality of the nonzero and
alpar@1
  1212
                 * flop count analysis.  It also means that the post-ordering
alpar@1
  1213
                 * is not an exact elimination tree post-ordering. */
alpar@1
  1214
alpar@1
  1215
                AMD_DEBUG1 (("  MASS i "ID" => parent e "ID"\n", i, me)) ;
alpar@1
  1216
                Pe [i] = FLIP (me) ;
alpar@1
  1217
                nvi = -Nv [i] ;
alpar@1
  1218
                degme -= nvi ;
alpar@1
  1219
                nvpiv += nvi ;
alpar@1
  1220
                nel += nvi ;
alpar@1
  1221
                Nv [i] = 0 ;
alpar@1
  1222
                Elen [i] = EMPTY ;
alpar@1
  1223
alpar@1
  1224
            }
alpar@1
  1225
            else
alpar@1
  1226
            {
alpar@1
  1227
alpar@1
  1228
                /* --------------------------------------------------------- */
alpar@1
  1229
                /* update the upper-bound degree of i */
alpar@1
  1230
                /* --------------------------------------------------------- */
alpar@1
  1231
alpar@1
  1232
                /* the following degree does not yet include the size
alpar@1
  1233
                 * of the current element, which is added later: */
alpar@1
  1234
alpar@1
  1235
                Degree [i] = MIN (Degree [i], deg) ;
alpar@1
  1236
alpar@1
  1237
                /* --------------------------------------------------------- */
alpar@1
  1238
                /* add me to the list for i */
alpar@1
  1239
                /* --------------------------------------------------------- */
alpar@1
  1240
alpar@1
  1241
                /* move first supervariable to end of list */
alpar@1
  1242
                Iw [pn] = Iw [p3] ;
alpar@1
  1243
                /* move first element to end of element part of list */
alpar@1
  1244
                Iw [p3] = Iw [p1] ;
alpar@1
  1245
                /* add new element, me, to front of list. */
alpar@1
  1246
                Iw [p1] = me ;
alpar@1
  1247
                /* store the new length of the list in Len [i] */
alpar@1
  1248
                Len [i] = pn - p1 + 1 ;
alpar@1
  1249
alpar@1
  1250
                /* --------------------------------------------------------- */
alpar@1
  1251
                /* place in hash bucket.  Save hash key of i in Last [i]. */
alpar@1
  1252
                /* --------------------------------------------------------- */
alpar@1
  1253
alpar@1
  1254
                /* NOTE: this can fail if hash is negative, because the ANSI C
alpar@1
  1255
                 * standard does not define a % b when a and/or b are negative.
alpar@1
  1256
                 * That's why hash is defined as an unsigned Int, to avoid this
alpar@1
  1257
                 * problem. */
alpar@1
  1258
                hash = hash % n ;
alpar@1
  1259
                ASSERT (((Int) hash) >= 0 && ((Int) hash) < n) ;
alpar@1
  1260
alpar@1
  1261
                /* if the Hhead array is not used: */
alpar@1
  1262
                j = Head [hash] ;
alpar@1
  1263
                if (j <= EMPTY)
alpar@1
  1264
                {
alpar@1
  1265
                    /* degree list is empty, hash head is FLIP (j) */
alpar@1
  1266
                    Next [i] = FLIP (j) ;
alpar@1
  1267
                    Head [hash] = FLIP (i) ;
alpar@1
  1268
                }
alpar@1
  1269
                else
alpar@1
  1270
                {
alpar@1
  1271
                    /* degree list is not empty, use Last [Head [hash]] as
alpar@1
  1272
                     * hash head. */
alpar@1
  1273
                    Next [i] = Last [j] ;
alpar@1
  1274
                    Last [j] = i ;
alpar@1
  1275
                }
alpar@1
  1276
alpar@1
  1277
                /* if a separate Hhead array is used: *
alpar@1
  1278
                Next [i] = Hhead [hash] ;
alpar@1
  1279
                Hhead [hash] = i ;
alpar@1
  1280
                */
alpar@1
  1281
alpar@1
  1282
                Last [i] = hash ;
alpar@1
  1283
            }
alpar@1
  1284
        }
alpar@1
  1285
alpar@1
  1286
        Degree [me] = degme ;
alpar@1
  1287
alpar@1
  1288
        /* ----------------------------------------------------------------- */
alpar@1
  1289
        /* Clear the counter array, W [...], by incrementing wflg. */
alpar@1
  1290
        /* ----------------------------------------------------------------- */
alpar@1
  1291
alpar@1
  1292
        /* make sure that wflg+n does not cause integer overflow */
alpar@1
  1293
        lemax =  MAX (lemax, degme) ;
alpar@1
  1294
        wflg += lemax ;
alpar@1
  1295
        wflg = clear_flag (wflg, wbig, W, n) ;
alpar@1
  1296
        /*  at this point, W [0..n-1] < wflg holds */
alpar@1
  1297
alpar@1
  1298
/* ========================================================================= */
alpar@1
  1299
/* SUPERVARIABLE DETECTION */
alpar@1
  1300
/* ========================================================================= */
alpar@1
  1301
alpar@1
  1302
        AMD_DEBUG1 (("Detecting supervariables:\n")) ;
alpar@1
  1303
        for (pme = pme1 ; pme <= pme2 ; pme++)
alpar@1
  1304
        {
alpar@1
  1305
            i = Iw [pme] ;
alpar@1
  1306
            ASSERT (i >= 0 && i < n) ;
alpar@1
  1307
            AMD_DEBUG2 (("Consider i "ID" nv "ID"\n", i, Nv [i])) ;
alpar@1
  1308
            if (Nv [i] < 0)
alpar@1
  1309
            {
alpar@1
  1310
                /* i is a principal variable in Lme */
alpar@1
  1311
alpar@1
  1312
                /* ---------------------------------------------------------
alpar@1
  1313
                 * examine all hash buckets with 2 or more variables.  We do
alpar@1
  1314
                 * this by examing all unique hash keys for supervariables in
alpar@1
  1315
                 * the pattern Lme of the current element, me
alpar@1
  1316
                 * --------------------------------------------------------- */
alpar@1
  1317
alpar@1
  1318
                /* let i = head of hash bucket, and empty the hash bucket */
alpar@1
  1319
                ASSERT (Last [i] >= 0 && Last [i] < n) ;
alpar@1
  1320
                hash = Last [i] ;
alpar@1
  1321
alpar@1
  1322
                /* if Hhead array is not used: */
alpar@1
  1323
                j = Head [hash] ;
alpar@1
  1324
                if (j == EMPTY)
alpar@1
  1325
                {
alpar@1
  1326
                    /* hash bucket and degree list are both empty */
alpar@1
  1327
                    i = EMPTY ;
alpar@1
  1328
                }
alpar@1
  1329
                else if (j < EMPTY)
alpar@1
  1330
                {
alpar@1
  1331
                    /* degree list is empty */
alpar@1
  1332
                    i = FLIP (j) ;
alpar@1
  1333
                    Head [hash] = EMPTY ;
alpar@1
  1334
                }
alpar@1
  1335
                else
alpar@1
  1336
                {
alpar@1
  1337
                    /* degree list is not empty, restore Last [j] of head j */
alpar@1
  1338
                    i = Last [j] ;
alpar@1
  1339
                    Last [j] = EMPTY ;
alpar@1
  1340
                }
alpar@1
  1341
alpar@1
  1342
                /* if separate Hhead array is used: *
alpar@1
  1343
                i = Hhead [hash] ;
alpar@1
  1344
                Hhead [hash] = EMPTY ;
alpar@1
  1345
                */
alpar@1
  1346
alpar@1
  1347
                ASSERT (i >= EMPTY && i < n) ;
alpar@1
  1348
                AMD_DEBUG2 (("----i "ID" hash "ID"\n", i, hash)) ;
alpar@1
  1349
alpar@1
  1350
                while (i != EMPTY && Next [i] != EMPTY)
alpar@1
  1351
                {
alpar@1
  1352
alpar@1
  1353
                    /* -----------------------------------------------------
alpar@1
  1354
                     * this bucket has one or more variables following i.
alpar@1
  1355
                     * scan all of them to see if i can absorb any entries
alpar@1
  1356
                     * that follow i in hash bucket.  Scatter i into w.
alpar@1
  1357
                     * ----------------------------------------------------- */
alpar@1
  1358
alpar@1
  1359
                    ln = Len [i] ;
alpar@1
  1360
                    eln = Elen [i] ;
alpar@1
  1361
                    ASSERT (ln >= 0 && eln >= 0) ;
alpar@1
  1362
                    ASSERT (Pe [i] >= 0 && Pe [i] < iwlen) ;
alpar@1
  1363
                    /* do not flag the first element in the list (me) */
alpar@1
  1364
                    for (p = Pe [i] + 1 ; p <= Pe [i] + ln - 1 ; p++)
alpar@1
  1365
                    {
alpar@1
  1366
                        ASSERT (Iw [p] >= 0 && Iw [p] < n) ;
alpar@1
  1367
                        W [Iw [p]] = wflg ;
alpar@1
  1368
                    }
alpar@1
  1369
alpar@1
  1370
                    /* ----------------------------------------------------- */
alpar@1
  1371
                    /* scan every other entry j following i in bucket */
alpar@1
  1372
                    /* ----------------------------------------------------- */
alpar@1
  1373
alpar@1
  1374
                    jlast = i ;
alpar@1
  1375
                    j = Next [i] ;
alpar@1
  1376
                    ASSERT (j >= EMPTY && j < n) ;
alpar@1
  1377
alpar@1
  1378
                    while (j != EMPTY)
alpar@1
  1379
                    {
alpar@1
  1380
                        /* ------------------------------------------------- */
alpar@1
  1381
                        /* check if j and i have identical nonzero pattern */
alpar@1
  1382
                        /* ------------------------------------------------- */
alpar@1
  1383
alpar@1
  1384
                        AMD_DEBUG3 (("compare i "ID" and j "ID"\n", i,j)) ;
alpar@1
  1385
alpar@1
  1386
                        /* check if i and j have the same Len and Elen */
alpar@1
  1387
                        ASSERT (Len [j] >= 0 && Elen [j] >= 0) ;
alpar@1
  1388
                        ASSERT (Pe [j] >= 0 && Pe [j] < iwlen) ;
alpar@1
  1389
                        ok = (Len [j] == ln) && (Elen [j] == eln) ;
alpar@1
  1390
                        /* skip the first element in the list (me) */
alpar@1
  1391
                        for (p = Pe [j] + 1 ; ok && p <= Pe [j] + ln - 1 ; p++)
alpar@1
  1392
                        {
alpar@1
  1393
                            ASSERT (Iw [p] >= 0 && Iw [p] < n) ;
alpar@1
  1394
                            if (W [Iw [p]] != wflg) ok = 0 ;
alpar@1
  1395
                        }
alpar@1
  1396
                        if (ok)
alpar@1
  1397
                        {
alpar@1
  1398
                            /* --------------------------------------------- */
alpar@1
  1399
                            /* found it!  j can be absorbed into i */
alpar@1
  1400
                            /* --------------------------------------------- */
alpar@1
  1401
alpar@1
  1402
                            AMD_DEBUG1 (("found it! j "ID" => i "ID"\n", j,i));
alpar@1
  1403
                            Pe [j] = FLIP (i) ;
alpar@1
  1404
                            /* both Nv [i] and Nv [j] are negated since they */
alpar@1
  1405
                            /* are in Lme, and the absolute values of each */
alpar@1
  1406
                            /* are the number of variables in i and j: */
alpar@1
  1407
                            Nv [i] += Nv [j] ;
alpar@1
  1408
                            Nv [j] = 0 ;
alpar@1
  1409
                            Elen [j] = EMPTY ;
alpar@1
  1410
                            /* delete j from hash bucket */
alpar@1
  1411
                            ASSERT (j != Next [j]) ;
alpar@1
  1412
                            j = Next [j] ;
alpar@1
  1413
                            Next [jlast] = j ;
alpar@1
  1414
alpar@1
  1415
                        }
alpar@1
  1416
                        else
alpar@1
  1417
                        {
alpar@1
  1418
                            /* j cannot be absorbed into i */
alpar@1
  1419
                            jlast = j ;
alpar@1
  1420
                            ASSERT (j != Next [j]) ;
alpar@1
  1421
                            j = Next [j] ;
alpar@1
  1422
                        }
alpar@1
  1423
                        ASSERT (j >= EMPTY && j < n) ;
alpar@1
  1424
                    }
alpar@1
  1425
alpar@1
  1426
                    /* -----------------------------------------------------
alpar@1
  1427
                     * no more variables can be absorbed into i
alpar@1
  1428
                     * go to next i in bucket and clear flag array
alpar@1
  1429
                     * ----------------------------------------------------- */
alpar@1
  1430
alpar@1
  1431
                    wflg++ ;
alpar@1
  1432
                    i = Next [i] ;
alpar@1
  1433
                    ASSERT (i >= EMPTY && i < n) ;
alpar@1
  1434
alpar@1
  1435
                }
alpar@1
  1436
            }
alpar@1
  1437
        }
alpar@1
  1438
        AMD_DEBUG2 (("detect done\n")) ;
alpar@1
  1439
alpar@1
  1440
/* ========================================================================= */
alpar@1
  1441
/* RESTORE DEGREE LISTS AND REMOVE NONPRINCIPAL SUPERVARIABLES FROM ELEMENT */
alpar@1
  1442
/* ========================================================================= */
alpar@1
  1443
alpar@1
  1444
        p = pme1 ;
alpar@1
  1445
        nleft = n - nel ;
alpar@1
  1446
        for (pme = pme1 ; pme <= pme2 ; pme++)
alpar@1
  1447
        {
alpar@1
  1448
            i = Iw [pme] ;
alpar@1
  1449
            ASSERT (i >= 0 && i < n) ;
alpar@1
  1450
            nvi = -Nv [i] ;
alpar@1
  1451
            AMD_DEBUG3 (("Restore i "ID" "ID"\n", i, nvi)) ;
alpar@1
  1452
            if (nvi > 0)
alpar@1
  1453
            {
alpar@1
  1454
                /* i is a principal variable in Lme */
alpar@1
  1455
                /* restore Nv [i] to signify that i is principal */
alpar@1
  1456
                Nv [i] = nvi ;
alpar@1
  1457
alpar@1
  1458
                /* --------------------------------------------------------- */
alpar@1
  1459
                /* compute the external degree (add size of current element) */
alpar@1
  1460
                /* --------------------------------------------------------- */
alpar@1
  1461
alpar@1
  1462
                deg = Degree [i] + degme - nvi ;
alpar@1
  1463
                deg = MIN (deg, nleft - nvi) ;
alpar@1
  1464
                ASSERT (IMPLIES (aggressive, deg > 0) && deg >= 0 && deg < n) ;
alpar@1
  1465
alpar@1
  1466
                /* --------------------------------------------------------- */
alpar@1
  1467
                /* place the supervariable at the head of the degree list */
alpar@1
  1468
                /* --------------------------------------------------------- */
alpar@1
  1469
alpar@1
  1470
                inext = Head [deg] ;
alpar@1
  1471
                ASSERT (inext >= EMPTY && inext < n) ;
alpar@1
  1472
                if (inext != EMPTY) Last [inext] = i ;
alpar@1
  1473
                Next [i] = inext ;
alpar@1
  1474
                Last [i] = EMPTY ;
alpar@1
  1475
                Head [deg] = i ;
alpar@1
  1476
alpar@1
  1477
                /* --------------------------------------------------------- */
alpar@1
  1478
                /* save the new degree, and find the minimum degree */
alpar@1
  1479
                /* --------------------------------------------------------- */
alpar@1
  1480
alpar@1
  1481
                mindeg = MIN (mindeg, deg) ;
alpar@1
  1482
                Degree [i] = deg ;
alpar@1
  1483
alpar@1
  1484
                /* --------------------------------------------------------- */
alpar@1
  1485
                /* place the supervariable in the element pattern */
alpar@1
  1486
                /* --------------------------------------------------------- */
alpar@1
  1487
alpar@1
  1488
                Iw [p++] = i ;
alpar@1
  1489
alpar@1
  1490
            }
alpar@1
  1491
        }
alpar@1
  1492
        AMD_DEBUG2 (("restore done\n")) ;
alpar@1
  1493
alpar@1
  1494
/* ========================================================================= */
alpar@1
  1495
/* FINALIZE THE NEW ELEMENT */
alpar@1
  1496
/* ========================================================================= */
alpar@1
  1497
alpar@1
  1498
        AMD_DEBUG2 (("ME = "ID" DONE\n", me)) ;
alpar@1
  1499
        Nv [me] = nvpiv ;
alpar@1
  1500
        /* save the length of the list for the new element me */
alpar@1
  1501
        Len [me] = p - pme1 ;
alpar@1
  1502
        if (Len [me] == 0)
alpar@1
  1503
        {
alpar@1
  1504
            /* there is nothing left of the current pivot element */
alpar@1
  1505
            /* it is a root of the assembly tree */
alpar@1
  1506
            Pe [me] = EMPTY ;
alpar@1
  1507
            W [me] = 0 ;
alpar@1
  1508
        }
alpar@1
  1509
        if (elenme != 0)
alpar@1
  1510
        {
alpar@1
  1511
            /* element was not constructed in place: deallocate part of */
alpar@1
  1512
            /* it since newly nonprincipal variables may have been removed */
alpar@1
  1513
            pfree = p ;
alpar@1
  1514
        }
alpar@1
  1515
alpar@1
  1516
        /* The new element has nvpiv pivots and the size of the contribution
alpar@1
  1517
         * block for a multifrontal method is degme-by-degme, not including
alpar@1
  1518
         * the "dense" rows/columns.  If the "dense" rows/columns are included,
alpar@1
  1519
         * the frontal matrix is no larger than
alpar@1
  1520
         * (degme+ndense)-by-(degme+ndense).
alpar@1
  1521
         */
alpar@1
  1522
alpar@1
  1523
        if (Info != (double *) NULL)
alpar@1
  1524
        {
alpar@1
  1525
            f = nvpiv ;
alpar@1
  1526
            r = degme + ndense ;
alpar@1
  1527
            dmax = MAX (dmax, f + r) ;
alpar@1
  1528
alpar@1
  1529
            /* number of nonzeros in L (excluding the diagonal) */
alpar@1
  1530
            lnzme = f*r + (f-1)*f/2 ;
alpar@1
  1531
            lnz += lnzme ;
alpar@1
  1532
alpar@1
  1533
            /* number of divide operations for LDL' and for LU */
alpar@1
  1534
            ndiv += lnzme ;
alpar@1
  1535
alpar@1
  1536
            /* number of multiply-subtract pairs for LU */
alpar@1
  1537
            s = f*r*r + r*(f-1)*f + (f-1)*f*(2*f-1)/6 ;
alpar@1
  1538
            nms_lu += s ;
alpar@1
  1539
alpar@1
  1540
            /* number of multiply-subtract pairs for LDL' */
alpar@1
  1541
            nms_ldl += (s + lnzme)/2 ;
alpar@1
  1542
        }
alpar@1
  1543
alpar@1
  1544
#ifndef NDEBUG
alpar@1
  1545
        AMD_DEBUG2 (("finalize done nel "ID" n "ID"\n   ::::\n", nel, n)) ;
alpar@1
  1546
        for (pme = Pe [me] ; pme <= Pe [me] + Len [me] - 1 ; pme++)
alpar@1
  1547
        {
alpar@1
  1548
              AMD_DEBUG3 ((" "ID"", Iw [pme])) ;
alpar@1
  1549
        }
alpar@1
  1550
        AMD_DEBUG3 (("\n")) ;
alpar@1
  1551
#endif
alpar@1
  1552
alpar@1
  1553
    }
alpar@1
  1554
alpar@1
  1555
/* ========================================================================= */
alpar@1
  1556
/* DONE SELECTING PIVOTS */
alpar@1
  1557
/* ========================================================================= */
alpar@1
  1558
alpar@1
  1559
    if (Info != (double *) NULL)
alpar@1
  1560
    {
alpar@1
  1561
alpar@1
  1562
        /* count the work to factorize the ndense-by-ndense submatrix */
alpar@1
  1563
        f = ndense ;
alpar@1
  1564
        dmax = MAX (dmax, (double) ndense) ;
alpar@1
  1565
alpar@1
  1566
        /* number of nonzeros in L (excluding the diagonal) */
alpar@1
  1567
        lnzme = (f-1)*f/2 ;
alpar@1
  1568
        lnz += lnzme ;
alpar@1
  1569
alpar@1
  1570
        /* number of divide operations for LDL' and for LU */
alpar@1
  1571
        ndiv += lnzme ;
alpar@1
  1572
alpar@1
  1573
        /* number of multiply-subtract pairs for LU */
alpar@1
  1574
        s = (f-1)*f*(2*f-1)/6 ;
alpar@1
  1575
        nms_lu += s ;
alpar@1
  1576
alpar@1
  1577
        /* number of multiply-subtract pairs for LDL' */
alpar@1
  1578
        nms_ldl += (s + lnzme)/2 ;
alpar@1
  1579
alpar@1
  1580
        /* number of nz's in L (excl. diagonal) */
alpar@1
  1581
        Info [AMD_LNZ] = lnz ;
alpar@1
  1582
alpar@1
  1583
        /* number of divide ops for LU and LDL' */
alpar@1
  1584
        Info [AMD_NDIV] = ndiv ;
alpar@1
  1585
alpar@1
  1586
        /* number of multiply-subtract pairs for LDL' */
alpar@1
  1587
        Info [AMD_NMULTSUBS_LDL] = nms_ldl ;
alpar@1
  1588
alpar@1
  1589
        /* number of multiply-subtract pairs for LU */
alpar@1
  1590
        Info [AMD_NMULTSUBS_LU] = nms_lu ;
alpar@1
  1591
alpar@1
  1592
        /* number of "dense" rows/columns */
alpar@1
  1593
        Info [AMD_NDENSE] = ndense ;
alpar@1
  1594
alpar@1
  1595
        /* largest front is dmax-by-dmax */
alpar@1
  1596
        Info [AMD_DMAX] = dmax ;
alpar@1
  1597
alpar@1
  1598
        /* number of garbage collections in AMD */
alpar@1
  1599
        Info [AMD_NCMPA] = ncmpa ;
alpar@1
  1600
alpar@1
  1601
        /* successful ordering */
alpar@1
  1602
        Info [AMD_STATUS] = AMD_OK ;
alpar@1
  1603
    }
alpar@1
  1604
alpar@1
  1605
/* ========================================================================= */
alpar@1
  1606
/* POST-ORDERING */
alpar@1
  1607
/* ========================================================================= */
alpar@1
  1608
alpar@1
  1609
/* -------------------------------------------------------------------------
alpar@1
  1610
 * Variables at this point:
alpar@1
  1611
 *
alpar@1
  1612
 * Pe: holds the elimination tree.  The parent of j is FLIP (Pe [j]),
alpar@1
  1613
 *      or EMPTY if j is a root.  The tree holds both elements and
alpar@1
  1614
 *      non-principal (unordered) variables absorbed into them.
alpar@1
  1615
 *      Dense variables are non-principal and unordered.
alpar@1
  1616
 *
alpar@1
  1617
 * Elen: holds the size of each element, including the diagonal part.
alpar@1
  1618
 *      FLIP (Elen [e]) > 0 if e is an element.  For unordered
alpar@1
  1619
 *      variables i, Elen [i] is EMPTY.
alpar@1
  1620
 *
alpar@1
  1621
 * Nv: Nv [e] > 0 is the number of pivots represented by the element e.
alpar@1
  1622
 *      For unordered variables i, Nv [i] is zero.
alpar@1
  1623
 *
alpar@1
  1624
 * Contents no longer needed:
alpar@1
  1625
 *      W, Iw, Len, Degree, Head, Next, Last.
alpar@1
  1626
 *
alpar@1
  1627
 * The matrix itself has been destroyed.
alpar@1
  1628
 *
alpar@1
  1629
 * n: the size of the matrix.
alpar@1
  1630
 * No other scalars needed (pfree, iwlen, etc.)
alpar@1
  1631
 * ------------------------------------------------------------------------- */
alpar@1
  1632
alpar@1
  1633
    /* restore Pe */
alpar@1
  1634
    for (i = 0 ; i < n ; i++)
alpar@1
  1635
    {
alpar@1
  1636
        Pe [i] = FLIP (Pe [i]) ;
alpar@1
  1637
    }
alpar@1
  1638
alpar@1
  1639
    /* restore Elen, for output information, and for postordering */
alpar@1
  1640
    for (i = 0 ; i < n ; i++)
alpar@1
  1641
    {
alpar@1
  1642
        Elen [i] = FLIP (Elen [i]) ;
alpar@1
  1643
    }
alpar@1
  1644
alpar@1
  1645
/* Now the parent of j is Pe [j], or EMPTY if j is a root.  Elen [e] > 0
alpar@1
  1646
 * is the size of element e.  Elen [i] is EMPTY for unordered variable i. */
alpar@1
  1647
alpar@1
  1648
#ifndef NDEBUG
alpar@1
  1649
    AMD_DEBUG2 (("\nTree:\n")) ;
alpar@1
  1650
    for (i = 0 ; i < n ; i++)
alpar@1
  1651
    {
alpar@1
  1652
        AMD_DEBUG2 ((" "ID" parent: "ID"   ", i, Pe [i])) ;
alpar@1
  1653
        ASSERT (Pe [i] >= EMPTY && Pe [i] < n) ;
alpar@1
  1654
        if (Nv [i] > 0)
alpar@1
  1655
        {
alpar@1
  1656
            /* this is an element */
alpar@1
  1657
            e = i ;
alpar@1
  1658
            AMD_DEBUG2 ((" element, size is "ID"\n", Elen [i])) ;
alpar@1
  1659
            ASSERT (Elen [e] > 0) ;
alpar@1
  1660
        }
alpar@1
  1661
        AMD_DEBUG2 (("\n")) ;
alpar@1
  1662
    }
alpar@1
  1663
    AMD_DEBUG2 (("\nelements:\n")) ;
alpar@1
  1664
    for (e = 0 ; e < n ; e++)
alpar@1
  1665
    {
alpar@1
  1666
        if (Nv [e] > 0)
alpar@1
  1667
        {
alpar@1
  1668
            AMD_DEBUG3 (("Element e= "ID" size "ID" nv "ID" \n", e,
alpar@1
  1669
                Elen [e], Nv [e])) ;
alpar@1
  1670
        }
alpar@1
  1671
    }
alpar@1
  1672
    AMD_DEBUG2 (("\nvariables:\n")) ;
alpar@1
  1673
    for (i = 0 ; i < n ; i++)
alpar@1
  1674
    {
alpar@1
  1675
        Int cnt ;
alpar@1
  1676
        if (Nv [i] == 0)
alpar@1
  1677
        {
alpar@1
  1678
            AMD_DEBUG3 (("i unordered: "ID"\n", i)) ;
alpar@1
  1679
            j = Pe [i] ;
alpar@1
  1680
            cnt = 0 ;
alpar@1
  1681
            AMD_DEBUG3 (("  j: "ID"\n", j)) ;
alpar@1
  1682
            if (j == EMPTY)
alpar@1
  1683
            {
alpar@1
  1684
                AMD_DEBUG3 (("  i is a dense variable\n")) ;
alpar@1
  1685
            }
alpar@1
  1686
            else
alpar@1
  1687
            {
alpar@1
  1688
                ASSERT (j >= 0 && j < n) ;
alpar@1
  1689
                while (Nv [j] == 0)
alpar@1
  1690
                {
alpar@1
  1691
                    AMD_DEBUG3 (("      j : "ID"\n", j)) ;
alpar@1
  1692
                    j = Pe [j] ;
alpar@1
  1693
                    AMD_DEBUG3 (("      j:: "ID"\n", j)) ;
alpar@1
  1694
                    cnt++ ;
alpar@1
  1695
                    if (cnt > n) break ;
alpar@1
  1696
                }
alpar@1
  1697
                e = j ;
alpar@1
  1698
                AMD_DEBUG3 (("  got to e: "ID"\n", e)) ;
alpar@1
  1699
            }
alpar@1
  1700
        }
alpar@1
  1701
    }
alpar@1
  1702
#endif
alpar@1
  1703
alpar@1
  1704
/* ========================================================================= */
alpar@1
  1705
/* compress the paths of the variables */
alpar@1
  1706
/* ========================================================================= */
alpar@1
  1707
alpar@1
  1708
    for (i = 0 ; i < n ; i++)
alpar@1
  1709
    {
alpar@1
  1710
        if (Nv [i] == 0)
alpar@1
  1711
        {
alpar@1
  1712
alpar@1
  1713
            /* -------------------------------------------------------------
alpar@1
  1714
             * i is an un-ordered row.  Traverse the tree from i until
alpar@1
  1715
             * reaching an element, e.  The element, e, was the principal
alpar@1
  1716
             * supervariable of i and all nodes in the path from i to when e
alpar@1
  1717
             * was selected as pivot.
alpar@1
  1718
             * ------------------------------------------------------------- */
alpar@1
  1719
alpar@1
  1720
            AMD_DEBUG1 (("Path compression, i unordered: "ID"\n", i)) ;
alpar@1
  1721
            j = Pe [i] ;
alpar@1
  1722
            ASSERT (j >= EMPTY && j < n) ;
alpar@1
  1723
            AMD_DEBUG3 (("      j: "ID"\n", j)) ;
alpar@1
  1724
            if (j == EMPTY)
alpar@1
  1725
            {
alpar@1
  1726
                /* Skip a dense variable.  It has no parent. */
alpar@1
  1727
                AMD_DEBUG3 (("      i is a dense variable\n")) ;
alpar@1
  1728
                continue ;
alpar@1
  1729
            }
alpar@1
  1730
alpar@1
  1731
            /* while (j is a variable) */
alpar@1
  1732
            while (Nv [j] == 0)
alpar@1
  1733
            {
alpar@1
  1734
                AMD_DEBUG3 (("          j : "ID"\n", j)) ;
alpar@1
  1735
                j = Pe [j] ;
alpar@1
  1736
                AMD_DEBUG3 (("          j:: "ID"\n", j)) ;
alpar@1
  1737
                ASSERT (j >= 0 && j < n) ;
alpar@1
  1738
            }
alpar@1
  1739
            /* got to an element e */
alpar@1
  1740
            e = j ;
alpar@1
  1741
            AMD_DEBUG3 (("got to e: "ID"\n", e)) ;
alpar@1
  1742
alpar@1
  1743
            /* -------------------------------------------------------------
alpar@1
  1744
             * traverse the path again from i to e, and compress the path
alpar@1
  1745
             * (all nodes point to e).  Path compression allows this code to
alpar@1
  1746
             * compute in O(n) time.
alpar@1
  1747
             * ------------------------------------------------------------- */
alpar@1
  1748
alpar@1
  1749
            j = i ;
alpar@1
  1750
            /* while (j is a variable) */
alpar@1
  1751
            while (Nv [j] == 0)
alpar@1
  1752
            {
alpar@1
  1753
                jnext = Pe [j] ;
alpar@1
  1754
                AMD_DEBUG3 (("j "ID" jnext "ID"\n", j, jnext)) ;
alpar@1
  1755
                Pe [j] = e ;
alpar@1
  1756
                j = jnext ;
alpar@1
  1757
                ASSERT (j >= 0 && j < n) ;
alpar@1
  1758
            }
alpar@1
  1759
        }
alpar@1
  1760
    }
alpar@1
  1761
alpar@1
  1762
/* ========================================================================= */
alpar@1
  1763
/* postorder the assembly tree */
alpar@1
  1764
/* ========================================================================= */
alpar@1
  1765
alpar@1
  1766
    AMD_postorder (n, Pe, Nv, Elen,
alpar@1
  1767
        W,                      /* output order */
alpar@1
  1768
        Head, Next, Last) ;     /* workspace */
alpar@1
  1769
alpar@1
  1770
/* ========================================================================= */
alpar@1
  1771
/* compute output permutation and inverse permutation */
alpar@1
  1772
/* ========================================================================= */
alpar@1
  1773
alpar@1
  1774
    /* W [e] = k means that element e is the kth element in the new
alpar@1
  1775
     * order.  e is in the range 0 to n-1, and k is in the range 0 to
alpar@1
  1776
     * the number of elements.  Use Head for inverse order. */
alpar@1
  1777
alpar@1
  1778
    for (k = 0 ; k < n ; k++)
alpar@1
  1779
    {
alpar@1
  1780
        Head [k] = EMPTY ;
alpar@1
  1781
        Next [k] = EMPTY ;
alpar@1
  1782
    }
alpar@1
  1783
    for (e = 0 ; e < n ; e++)
alpar@1
  1784
    {
alpar@1
  1785
        k = W [e] ;
alpar@1
  1786
        ASSERT ((k == EMPTY) == (Nv [e] == 0)) ;
alpar@1
  1787
        if (k != EMPTY)
alpar@1
  1788
        {
alpar@1
  1789
            ASSERT (k >= 0 && k < n) ;
alpar@1
  1790
            Head [k] = e ;
alpar@1
  1791
        }
alpar@1
  1792
    }
alpar@1
  1793
alpar@1
  1794
    /* construct output inverse permutation in Next,
alpar@1
  1795
     * and permutation in Last */
alpar@1
  1796
    nel = 0 ;
alpar@1
  1797
    for (k = 0 ; k < n ; k++)
alpar@1
  1798
    {
alpar@1
  1799
        e = Head [k] ;
alpar@1
  1800
        if (e == EMPTY) break ;
alpar@1
  1801
        ASSERT (e >= 0 && e < n && Nv [e] > 0) ;
alpar@1
  1802
        Next [e] = nel ;
alpar@1
  1803
        nel += Nv [e] ;
alpar@1
  1804
    }
alpar@1
  1805
    ASSERT (nel == n - ndense) ;
alpar@1
  1806
alpar@1
  1807
    /* order non-principal variables (dense, & those merged into supervar's) */
alpar@1
  1808
    for (i = 0 ; i < n ; i++)
alpar@1
  1809
    {
alpar@1
  1810
        if (Nv [i] == 0)
alpar@1
  1811
        {
alpar@1
  1812
            e = Pe [i] ;
alpar@1
  1813
            ASSERT (e >= EMPTY && e < n) ;
alpar@1
  1814
            if (e != EMPTY)
alpar@1
  1815
            {
alpar@1
  1816
                /* This is an unordered variable that was merged
alpar@1
  1817
                 * into element e via supernode detection or mass
alpar@1
  1818
                 * elimination of i when e became the pivot element.
alpar@1
  1819
                 * Place i in order just before e. */
alpar@1
  1820
                ASSERT (Next [i] == EMPTY && Nv [e] > 0) ;
alpar@1
  1821
                Next [i] = Next [e] ;
alpar@1
  1822
                Next [e]++ ;
alpar@1
  1823
            }
alpar@1
  1824
            else
alpar@1
  1825
            {
alpar@1
  1826
                /* This is a dense unordered variable, with no parent.
alpar@1
  1827
                 * Place it last in the output order. */
alpar@1
  1828
                Next [i] = nel++ ;
alpar@1
  1829
            }
alpar@1
  1830
        }
alpar@1
  1831
    }
alpar@1
  1832
    ASSERT (nel == n) ;
alpar@1
  1833
alpar@1
  1834
    AMD_DEBUG2 (("\n\nPerm:\n")) ;
alpar@1
  1835
    for (i = 0 ; i < n ; i++)
alpar@1
  1836
    {
alpar@1
  1837
        k = Next [i] ;
alpar@1
  1838
        ASSERT (k >= 0 && k < n) ;
alpar@1
  1839
        Last [k] = i ;
alpar@1
  1840
        AMD_DEBUG2 (("   perm ["ID"] = "ID"\n", k, i)) ;
alpar@1
  1841
    }
alpar@1
  1842
}