lemon-project-template-glpk
diff deps/glpk/src/amd/amd_2.c @ 9:33de93886c88
Import GLPK 4.47
author | Alpar Juttner <alpar@cs.elte.hu> |
---|---|
date | Sun, 06 Nov 2011 20:59:10 +0100 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/deps/glpk/src/amd/amd_2.c Sun Nov 06 20:59:10 2011 +0100 1.3 @@ -0,0 +1,1842 @@ 1.4 +/* ========================================================================= */ 1.5 +/* === AMD_2 =============================================================== */ 1.6 +/* ========================================================================= */ 1.7 + 1.8 +/* ------------------------------------------------------------------------- */ 1.9 +/* AMD, Copyright (c) Timothy A. Davis, */ 1.10 +/* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ 1.11 +/* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */ 1.12 +/* web: http://www.cise.ufl.edu/research/sparse/amd */ 1.13 +/* ------------------------------------------------------------------------- */ 1.14 + 1.15 +/* AMD_2: performs the AMD ordering on a symmetric sparse matrix A, followed 1.16 + * by a postordering (via depth-first search) of the assembly tree using the 1.17 + * AMD_postorder routine. 1.18 + */ 1.19 + 1.20 +#include "amd_internal.h" 1.21 + 1.22 +/* ========================================================================= */ 1.23 +/* === clear_flag ========================================================== */ 1.24 +/* ========================================================================= */ 1.25 + 1.26 +static Int clear_flag (Int wflg, Int wbig, Int W [ ], Int n) 1.27 +{ 1.28 + Int x ; 1.29 + if (wflg < 2 || wflg >= wbig) 1.30 + { 1.31 + for (x = 0 ; x < n ; x++) 1.32 + { 1.33 + if (W [x] != 0) W [x] = 1 ; 1.34 + } 1.35 + wflg = 2 ; 1.36 + } 1.37 + /* at this point, W [0..n-1] < wflg holds */ 1.38 + return (wflg) ; 1.39 +} 1.40 + 1.41 + 1.42 +/* ========================================================================= */ 1.43 +/* === AMD_2 =============================================================== */ 1.44 +/* ========================================================================= */ 1.45 + 1.46 +GLOBAL void AMD_2 1.47 +( 1.48 + Int n, /* A is n-by-n, where n > 0 */ 1.49 + Int Pe [ ], /* Pe [0..n-1]: index in Iw of row i on input */ 1.50 + Int Iw [ ], /* workspace of size iwlen. Iw [0..pfree-1] 1.51 + * holds the matrix on input */ 1.52 + Int Len [ ], /* Len [0..n-1]: length for row/column i on input */ 1.53 + Int iwlen, /* length of Iw. iwlen >= pfree + n */ 1.54 + Int pfree, /* Iw [pfree ... iwlen-1] is empty on input */ 1.55 + 1.56 + /* 7 size-n workspaces, not defined on input: */ 1.57 + Int Nv [ ], /* the size of each supernode on output */ 1.58 + Int Next [ ], /* the output inverse permutation */ 1.59 + Int Last [ ], /* the output permutation */ 1.60 + Int Head [ ], 1.61 + Int Elen [ ], /* the size columns of L for each supernode */ 1.62 + Int Degree [ ], 1.63 + Int W [ ], 1.64 + 1.65 + /* control parameters and output statistics */ 1.66 + double Control [ ], /* array of size AMD_CONTROL */ 1.67 + double Info [ ] /* array of size AMD_INFO */ 1.68 +) 1.69 +{ 1.70 + 1.71 +/* 1.72 + * Given a representation of the nonzero pattern of a symmetric matrix, A, 1.73 + * (excluding the diagonal) perform an approximate minimum (UMFPACK/MA38-style) 1.74 + * degree ordering to compute a pivot order such that the introduction of 1.75 + * nonzeros (fill-in) in the Cholesky factors A = LL' is kept low. At each 1.76 + * step, the pivot selected is the one with the minimum UMFAPACK/MA38-style 1.77 + * upper-bound on the external degree. This routine can optionally perform 1.78 + * aggresive absorption (as done by MC47B in the Harwell Subroutine 1.79 + * Library). 1.80 + * 1.81 + * The approximate degree algorithm implemented here is the symmetric analog of 1.82 + * the degree update algorithm in MA38 and UMFPACK (the Unsymmetric-pattern 1.83 + * MultiFrontal PACKage, both by Davis and Duff). The routine is based on the 1.84 + * MA27 minimum degree ordering algorithm by Iain Duff and John Reid. 1.85 + * 1.86 + * This routine is a translation of the original AMDBAR and MC47B routines, 1.87 + * in Fortran, with the following modifications: 1.88 + * 1.89 + * (1) dense rows/columns are removed prior to ordering the matrix, and placed 1.90 + * last in the output order. The presence of a dense row/column can 1.91 + * increase the ordering time by up to O(n^2), unless they are removed 1.92 + * prior to ordering. 1.93 + * 1.94 + * (2) the minimum degree ordering is followed by a postordering (depth-first 1.95 + * search) of the assembly tree. Note that mass elimination (discussed 1.96 + * below) combined with the approximate degree update can lead to the mass 1.97 + * elimination of nodes with lower exact degree than the current pivot 1.98 + * element. No additional fill-in is caused in the representation of the 1.99 + * Schur complement. The mass-eliminated nodes merge with the current 1.100 + * pivot element. They are ordered prior to the current pivot element. 1.101 + * Because they can have lower exact degree than the current element, the 1.102 + * merger of two or more of these nodes in the current pivot element can 1.103 + * lead to a single element that is not a "fundamental supernode". The 1.104 + * diagonal block can have zeros in it. Thus, the assembly tree used here 1.105 + * is not guaranteed to be the precise supernodal elemination tree (with 1.106 + * "funadmental" supernodes), and the postordering performed by this 1.107 + * routine is not guaranteed to be a precise postordering of the 1.108 + * elimination tree. 1.109 + * 1.110 + * (3) input parameters are added, to control aggressive absorption and the 1.111 + * detection of "dense" rows/columns of A. 1.112 + * 1.113 + * (4) additional statistical information is returned, such as the number of 1.114 + * nonzeros in L, and the flop counts for subsequent LDL' and LU 1.115 + * factorizations. These are slight upper bounds, because of the mass 1.116 + * elimination issue discussed above. 1.117 + * 1.118 + * (5) additional routines are added to interface this routine to MATLAB 1.119 + * to provide a simple C-callable user-interface, to check inputs for 1.120 + * errors, compute the symmetry of the pattern of A and the number of 1.121 + * nonzeros in each row/column of A+A', to compute the pattern of A+A', 1.122 + * to perform the assembly tree postordering, and to provide debugging 1.123 + * ouput. Many of these functions are also provided by the Fortran 1.124 + * Harwell Subroutine Library routine MC47A. 1.125 + * 1.126 + * (6) both int and UF_long versions are provided. In the descriptions below 1.127 + * and integer is and int or UF_long depending on which version is 1.128 + * being used. 1.129 + 1.130 + ********************************************************************** 1.131 + ***** CAUTION: ARGUMENTS ARE NOT CHECKED FOR ERRORS ON INPUT. ****** 1.132 + ********************************************************************** 1.133 + ** If you want error checking, a more versatile input format, and a ** 1.134 + ** simpler user interface, use amd_order or amd_l_order instead. ** 1.135 + ** This routine is not meant to be user-callable. ** 1.136 + ********************************************************************** 1.137 + 1.138 + * ---------------------------------------------------------------------------- 1.139 + * References: 1.140 + * ---------------------------------------------------------------------------- 1.141 + * 1.142 + * [1] Timothy A. Davis and Iain Duff, "An unsymmetric-pattern multifrontal 1.143 + * method for sparse LU factorization", SIAM J. Matrix Analysis and 1.144 + * Applications, vol. 18, no. 1, pp. 140-158. Discusses UMFPACK / MA38, 1.145 + * which first introduced the approximate minimum degree used by this 1.146 + * routine. 1.147 + * 1.148 + * [2] Patrick Amestoy, Timothy A. Davis, and Iain S. Duff, "An approximate 1.149 + * minimum degree ordering algorithm," SIAM J. Matrix Analysis and 1.150 + * Applications, vol. 17, no. 4, pp. 886-905, 1996. Discusses AMDBAR and 1.151 + * MC47B, which are the Fortran versions of this routine. 1.152 + * 1.153 + * [3] Alan George and Joseph Liu, "The evolution of the minimum degree 1.154 + * ordering algorithm," SIAM Review, vol. 31, no. 1, pp. 1-19, 1989. 1.155 + * We list below the features mentioned in that paper that this code 1.156 + * includes: 1.157 + * 1.158 + * mass elimination: 1.159 + * Yes. MA27 relied on supervariable detection for mass elimination. 1.160 + * 1.161 + * indistinguishable nodes: 1.162 + * Yes (we call these "supervariables"). This was also in the MA27 1.163 + * code - although we modified the method of detecting them (the 1.164 + * previous hash was the true degree, which we no longer keep track 1.165 + * of). A supervariable is a set of rows with identical nonzero 1.166 + * pattern. All variables in a supervariable are eliminated together. 1.167 + * Each supervariable has as its numerical name that of one of its 1.168 + * variables (its principal variable). 1.169 + * 1.170 + * quotient graph representation: 1.171 + * Yes. We use the term "element" for the cliques formed during 1.172 + * elimination. This was also in the MA27 code. The algorithm can 1.173 + * operate in place, but it will work more efficiently if given some 1.174 + * "elbow room." 1.175 + * 1.176 + * element absorption: 1.177 + * Yes. This was also in the MA27 code. 1.178 + * 1.179 + * external degree: 1.180 + * Yes. The MA27 code was based on the true degree. 1.181 + * 1.182 + * incomplete degree update and multiple elimination: 1.183 + * No. This was not in MA27, either. Our method of degree update 1.184 + * within MC47B is element-based, not variable-based. It is thus 1.185 + * not well-suited for use with incomplete degree update or multiple 1.186 + * elimination. 1.187 + * 1.188 + * Authors, and Copyright (C) 2004 by: 1.189 + * Timothy A. Davis, Patrick Amestoy, Iain S. Duff, John K. Reid. 1.190 + * 1.191 + * Acknowledgements: This work (and the UMFPACK package) was supported by the 1.192 + * National Science Foundation (ASC-9111263, DMS-9223088, and CCR-0203270). 1.193 + * The UMFPACK/MA38 approximate degree update algorithm, the unsymmetric analog 1.194 + * which forms the basis of AMD, was developed while Tim Davis was supported by 1.195 + * CERFACS (Toulouse, France) in a post-doctoral position. This C version, and 1.196 + * the etree postorder, were written while Tim Davis was on sabbatical at 1.197 + * Stanford University and Lawrence Berkeley National Laboratory. 1.198 + 1.199 + * ---------------------------------------------------------------------------- 1.200 + * INPUT ARGUMENTS (unaltered): 1.201 + * ---------------------------------------------------------------------------- 1.202 + 1.203 + * n: The matrix order. Restriction: n >= 1. 1.204 + * 1.205 + * iwlen: The size of the Iw array. On input, the matrix is stored in 1.206 + * Iw [0..pfree-1]. However, Iw [0..iwlen-1] should be slightly larger 1.207 + * than what is required to hold the matrix, at least iwlen >= pfree + n. 1.208 + * Otherwise, excessive compressions will take place. The recommended 1.209 + * value of iwlen is 1.2 * pfree + n, which is the value used in the 1.210 + * user-callable interface to this routine (amd_order.c). The algorithm 1.211 + * will not run at all if iwlen < pfree. Restriction: iwlen >= pfree + n. 1.212 + * Note that this is slightly more restrictive than the actual minimum 1.213 + * (iwlen >= pfree), but AMD_2 will be very slow with no elbow room. 1.214 + * Thus, this routine enforces a bare minimum elbow room of size n. 1.215 + * 1.216 + * pfree: On input the tail end of the array, Iw [pfree..iwlen-1], is empty, 1.217 + * and the matrix is stored in Iw [0..pfree-1]. During execution, 1.218 + * additional data is placed in Iw, and pfree is modified so that 1.219 + * Iw [pfree..iwlen-1] is always the unused part of Iw. 1.220 + * 1.221 + * Control: A double array of size AMD_CONTROL containing input parameters 1.222 + * that affect how the ordering is computed. If NULL, then default 1.223 + * settings are used. 1.224 + * 1.225 + * Control [AMD_DENSE] is used to determine whether or not a given input 1.226 + * row is "dense". A row is "dense" if the number of entries in the row 1.227 + * exceeds Control [AMD_DENSE] times sqrt (n), except that rows with 16 or 1.228 + * fewer entries are never considered "dense". To turn off the detection 1.229 + * of dense rows, set Control [AMD_DENSE] to a negative number, or to a 1.230 + * number larger than sqrt (n). The default value of Control [AMD_DENSE] 1.231 + * is AMD_DEFAULT_DENSE, which is defined in amd.h as 10. 1.232 + * 1.233 + * Control [AMD_AGGRESSIVE] is used to determine whether or not aggressive 1.234 + * absorption is to be performed. If nonzero, then aggressive absorption 1.235 + * is performed (this is the default). 1.236 + 1.237 + * ---------------------------------------------------------------------------- 1.238 + * INPUT/OUPUT ARGUMENTS: 1.239 + * ---------------------------------------------------------------------------- 1.240 + * 1.241 + * Pe: An integer array of size n. On input, Pe [i] is the index in Iw of 1.242 + * the start of row i. Pe [i] is ignored if row i has no off-diagonal 1.243 + * entries. Thus Pe [i] must be in the range 0 to pfree-1 for non-empty 1.244 + * rows. 1.245 + * 1.246 + * During execution, it is used for both supervariables and elements: 1.247 + * 1.248 + * Principal supervariable i: index into Iw of the description of 1.249 + * supervariable i. A supervariable represents one or more rows of 1.250 + * the matrix with identical nonzero pattern. In this case, 1.251 + * Pe [i] >= 0. 1.252 + * 1.253 + * Non-principal supervariable i: if i has been absorbed into another 1.254 + * supervariable j, then Pe [i] = FLIP (j), where FLIP (j) is defined 1.255 + * as (-(j)-2). Row j has the same pattern as row i. Note that j 1.256 + * might later be absorbed into another supervariable j2, in which 1.257 + * case Pe [i] is still FLIP (j), and Pe [j] = FLIP (j2) which is 1.258 + * < EMPTY, where EMPTY is defined as (-1) in amd_internal.h. 1.259 + * 1.260 + * Unabsorbed element e: the index into Iw of the description of element 1.261 + * e, if e has not yet been absorbed by a subsequent element. Element 1.262 + * e is created when the supervariable of the same name is selected as 1.263 + * the pivot. In this case, Pe [i] >= 0. 1.264 + * 1.265 + * Absorbed element e: if element e is absorbed into element e2, then 1.266 + * Pe [e] = FLIP (e2). This occurs when the pattern of e (which we 1.267 + * refer to as Le) is found to be a subset of the pattern of e2 (that 1.268 + * is, Le2). In this case, Pe [i] < EMPTY. If element e is "null" 1.269 + * (it has no nonzeros outside its pivot block), then Pe [e] = EMPTY, 1.270 + * and e is the root of an assembly subtree (or the whole tree if 1.271 + * there is just one such root). 1.272 + * 1.273 + * Dense variable i: if i is "dense", then Pe [i] = EMPTY. 1.274 + * 1.275 + * On output, Pe holds the assembly tree/forest, which implicitly 1.276 + * represents a pivot order with identical fill-in as the actual order 1.277 + * (via a depth-first search of the tree), as follows. If Nv [i] > 0, 1.278 + * then i represents a node in the assembly tree, and the parent of i is 1.279 + * Pe [i], or EMPTY if i is a root. If Nv [i] = 0, then (i, Pe [i]) 1.280 + * represents an edge in a subtree, the root of which is a node in the 1.281 + * assembly tree. Note that i refers to a row/column in the original 1.282 + * matrix, not the permuted matrix. 1.283 + * 1.284 + * Info: A double array of size AMD_INFO. If present, (that is, not NULL), 1.285 + * then statistics about the ordering are returned in the Info array. 1.286 + * See amd.h for a description. 1.287 + 1.288 + * ---------------------------------------------------------------------------- 1.289 + * INPUT/MODIFIED (undefined on output): 1.290 + * ---------------------------------------------------------------------------- 1.291 + * 1.292 + * Len: An integer array of size n. On input, Len [i] holds the number of 1.293 + * entries in row i of the matrix, excluding the diagonal. The contents 1.294 + * of Len are undefined on output. 1.295 + * 1.296 + * Iw: An integer array of size iwlen. On input, Iw [0..pfree-1] holds the 1.297 + * description of each row i in the matrix. The matrix must be symmetric, 1.298 + * and both upper and lower triangular parts must be present. The 1.299 + * diagonal must not be present. Row i is held as follows: 1.300 + * 1.301 + * Len [i]: the length of the row i data structure in the Iw array. 1.302 + * Iw [Pe [i] ... Pe [i] + Len [i] - 1]: 1.303 + * the list of column indices for nonzeros in row i (simple 1.304 + * supervariables), excluding the diagonal. All supervariables 1.305 + * start with one row/column each (supervariable i is just row i). 1.306 + * If Len [i] is zero on input, then Pe [i] is ignored on input. 1.307 + * 1.308 + * Note that the rows need not be in any particular order, and there 1.309 + * may be empty space between the rows. 1.310 + * 1.311 + * During execution, the supervariable i experiences fill-in. This is 1.312 + * represented by placing in i a list of the elements that cause fill-in 1.313 + * in supervariable i: 1.314 + * 1.315 + * Len [i]: the length of supervariable i in the Iw array. 1.316 + * Iw [Pe [i] ... Pe [i] + Elen [i] - 1]: 1.317 + * the list of elements that contain i. This list is kept short 1.318 + * by removing absorbed elements. 1.319 + * Iw [Pe [i] + Elen [i] ... Pe [i] + Len [i] - 1]: 1.320 + * the list of supervariables in i. This list is kept short by 1.321 + * removing nonprincipal variables, and any entry j that is also 1.322 + * contained in at least one of the elements (j in Le) in the list 1.323 + * for i (e in row i). 1.324 + * 1.325 + * When supervariable i is selected as pivot, we create an element e of 1.326 + * the same name (e=i): 1.327 + * 1.328 + * Len [e]: the length of element e in the Iw array. 1.329 + * Iw [Pe [e] ... Pe [e] + Len [e] - 1]: 1.330 + * the list of supervariables in element e. 1.331 + * 1.332 + * An element represents the fill-in that occurs when supervariable i is 1.333 + * selected as pivot (which represents the selection of row i and all 1.334 + * non-principal variables whose principal variable is i). We use the 1.335 + * term Le to denote the set of all supervariables in element e. Absorbed 1.336 + * supervariables and elements are pruned from these lists when 1.337 + * computationally convenient. 1.338 + * 1.339 + * CAUTION: THE INPUT MATRIX IS OVERWRITTEN DURING COMPUTATION. 1.340 + * The contents of Iw are undefined on output. 1.341 + 1.342 + * ---------------------------------------------------------------------------- 1.343 + * OUTPUT (need not be set on input): 1.344 + * ---------------------------------------------------------------------------- 1.345 + * 1.346 + * Nv: An integer array of size n. During execution, ABS (Nv [i]) is equal to 1.347 + * the number of rows that are represented by the principal supervariable 1.348 + * i. If i is a nonprincipal or dense variable, then Nv [i] = 0. 1.349 + * Initially, Nv [i] = 1 for all i. Nv [i] < 0 signifies that i is a 1.350 + * principal variable in the pattern Lme of the current pivot element me. 1.351 + * After element me is constructed, Nv [i] is set back to a positive 1.352 + * value. 1.353 + * 1.354 + * On output, Nv [i] holds the number of pivots represented by super 1.355 + * row/column i of the original matrix, or Nv [i] = 0 for non-principal 1.356 + * rows/columns. Note that i refers to a row/column in the original 1.357 + * matrix, not the permuted matrix. 1.358 + * 1.359 + * Elen: An integer array of size n. See the description of Iw above. At the 1.360 + * start of execution, Elen [i] is set to zero for all rows i. During 1.361 + * execution, Elen [i] is the number of elements in the list for 1.362 + * supervariable i. When e becomes an element, Elen [e] = FLIP (esize) is 1.363 + * set, where esize is the size of the element (the number of pivots, plus 1.364 + * the number of nonpivotal entries). Thus Elen [e] < EMPTY. 1.365 + * Elen (i) = EMPTY set when variable i becomes nonprincipal. 1.366 + * 1.367 + * For variables, Elen (i) >= EMPTY holds until just before the 1.368 + * postordering and permutation vectors are computed. For elements, 1.369 + * Elen [e] < EMPTY holds. 1.370 + * 1.371 + * On output, Elen [i] is the degree of the row/column in the Cholesky 1.372 + * factorization of the permuted matrix, corresponding to the original row 1.373 + * i, if i is a super row/column. It is equal to EMPTY if i is 1.374 + * non-principal. Note that i refers to a row/column in the original 1.375 + * matrix, not the permuted matrix. 1.376 + * 1.377 + * Note that the contents of Elen on output differ from the Fortran 1.378 + * version (Elen holds the inverse permutation in the Fortran version, 1.379 + * which is instead returned in the Next array in this C version, 1.380 + * described below). 1.381 + * 1.382 + * Last: In a degree list, Last [i] is the supervariable preceding i, or EMPTY 1.383 + * if i is the head of the list. In a hash bucket, Last [i] is the hash 1.384 + * key for i. 1.385 + * 1.386 + * Last [Head [hash]] is also used as the head of a hash bucket if 1.387 + * Head [hash] contains a degree list (see the description of Head, 1.388 + * below). 1.389 + * 1.390 + * On output, Last [0..n-1] holds the permutation. That is, if 1.391 + * i = Last [k], then row i is the kth pivot row (where k ranges from 0 to 1.392 + * n-1). Row Last [k] of A is the kth row in the permuted matrix, PAP'. 1.393 + * 1.394 + * Next: Next [i] is the supervariable following i in a link list, or EMPTY if 1.395 + * i is the last in the list. Used for two kinds of lists: degree lists 1.396 + * and hash buckets (a supervariable can be in only one kind of list at a 1.397 + * time). 1.398 + * 1.399 + * On output Next [0..n-1] holds the inverse permutation. That is, if 1.400 + * k = Next [i], then row i is the kth pivot row. Row i of A appears as 1.401 + * the (Next[i])-th row in the permuted matrix, PAP'. 1.402 + * 1.403 + * Note that the contents of Next on output differ from the Fortran 1.404 + * version (Next is undefined on output in the Fortran version). 1.405 + 1.406 + * ---------------------------------------------------------------------------- 1.407 + * LOCAL WORKSPACE (not input or output - used only during execution): 1.408 + * ---------------------------------------------------------------------------- 1.409 + * 1.410 + * Degree: An integer array of size n. If i is a supervariable, then 1.411 + * Degree [i] holds the current approximation of the external degree of 1.412 + * row i (an upper bound). The external degree is the number of nonzeros 1.413 + * in row i, minus ABS (Nv [i]), the diagonal part. The bound is equal to 1.414 + * the exact external degree if Elen [i] is less than or equal to two. 1.415 + * 1.416 + * We also use the term "external degree" for elements e to refer to 1.417 + * |Le \ Lme|. If e is an element, then Degree [e] is |Le|, which is the 1.418 + * degree of the off-diagonal part of the element e (not including the 1.419 + * diagonal part). 1.420 + * 1.421 + * Head: An integer array of size n. Head is used for degree lists. 1.422 + * Head [deg] is the first supervariable in a degree list. All 1.423 + * supervariables i in a degree list Head [deg] have the same approximate 1.424 + * degree, namely, deg = Degree [i]. If the list Head [deg] is empty then 1.425 + * Head [deg] = EMPTY. 1.426 + * 1.427 + * During supervariable detection Head [hash] also serves as a pointer to 1.428 + * a hash bucket. If Head [hash] >= 0, there is a degree list of degree 1.429 + * hash. The hash bucket head pointer is Last [Head [hash]]. If 1.430 + * Head [hash] = EMPTY, then the degree list and hash bucket are both 1.431 + * empty. If Head [hash] < EMPTY, then the degree list is empty, and 1.432 + * FLIP (Head [hash]) is the head of the hash bucket. After supervariable 1.433 + * detection is complete, all hash buckets are empty, and the 1.434 + * (Last [Head [hash]] = EMPTY) condition is restored for the non-empty 1.435 + * degree lists. 1.436 + * 1.437 + * W: An integer array of size n. The flag array W determines the status of 1.438 + * elements and variables, and the external degree of elements. 1.439 + * 1.440 + * for elements: 1.441 + * if W [e] = 0, then the element e is absorbed. 1.442 + * if W [e] >= wflg, then W [e] - wflg is the size of the set 1.443 + * |Le \ Lme|, in terms of nonzeros (the sum of ABS (Nv [i]) for 1.444 + * each principal variable i that is both in the pattern of 1.445 + * element e and NOT in the pattern of the current pivot element, 1.446 + * me). 1.447 + * if wflg > W [e] > 0, then e is not absorbed and has not yet been 1.448 + * seen in the scan of the element lists in the computation of 1.449 + * |Le\Lme| in Scan 1 below. 1.450 + * 1.451 + * for variables: 1.452 + * during supervariable detection, if W [j] != wflg then j is 1.453 + * not in the pattern of variable i. 1.454 + * 1.455 + * The W array is initialized by setting W [i] = 1 for all i, and by 1.456 + * setting wflg = 2. It is reinitialized if wflg becomes too large (to 1.457 + * ensure that wflg+n does not cause integer overflow). 1.458 + 1.459 + * ---------------------------------------------------------------------------- 1.460 + * LOCAL INTEGERS: 1.461 + * ---------------------------------------------------------------------------- 1.462 + */ 1.463 + 1.464 + Int deg, degme, dext, lemax, e, elenme, eln, i, ilast, inext, j, 1.465 + jlast, jnext, k, knt1, knt2, knt3, lenj, ln, me, mindeg, nel, nleft, 1.466 + nvi, nvj, nvpiv, slenme, wbig, we, wflg, wnvi, ok, ndense, ncmpa, 1.467 + dense, aggressive ; 1.468 + 1.469 + unsigned Int hash ; /* unsigned, so that hash % n is well defined.*/ 1.470 + 1.471 +/* 1.472 + * deg: the degree of a variable or element 1.473 + * degme: size, |Lme|, of the current element, me (= Degree [me]) 1.474 + * dext: external degree, |Le \ Lme|, of some element e 1.475 + * lemax: largest |Le| seen so far (called dmax in Fortran version) 1.476 + * e: an element 1.477 + * elenme: the length, Elen [me], of element list of pivotal variable 1.478 + * eln: the length, Elen [...], of an element list 1.479 + * hash: the computed value of the hash function 1.480 + * i: a supervariable 1.481 + * ilast: the entry in a link list preceding i 1.482 + * inext: the entry in a link list following i 1.483 + * j: a supervariable 1.484 + * jlast: the entry in a link list preceding j 1.485 + * jnext: the entry in a link list, or path, following j 1.486 + * k: the pivot order of an element or variable 1.487 + * knt1: loop counter used during element construction 1.488 + * knt2: loop counter used during element construction 1.489 + * knt3: loop counter used during compression 1.490 + * lenj: Len [j] 1.491 + * ln: length of a supervariable list 1.492 + * me: current supervariable being eliminated, and the current 1.493 + * element created by eliminating that supervariable 1.494 + * mindeg: current minimum degree 1.495 + * nel: number of pivots selected so far 1.496 + * nleft: n - nel, the number of nonpivotal rows/columns remaining 1.497 + * nvi: the number of variables in a supervariable i (= Nv [i]) 1.498 + * nvj: the number of variables in a supervariable j (= Nv [j]) 1.499 + * nvpiv: number of pivots in current element 1.500 + * slenme: number of variables in variable list of pivotal variable 1.501 + * wbig: = INT_MAX - n for the int version, UF_long_max - n for the 1.502 + * UF_long version. wflg is not allowed to be >= wbig. 1.503 + * we: W [e] 1.504 + * wflg: used for flagging the W array. See description of Iw. 1.505 + * wnvi: wflg - Nv [i] 1.506 + * x: either a supervariable or an element 1.507 + * 1.508 + * ok: true if supervariable j can be absorbed into i 1.509 + * ndense: number of "dense" rows/columns 1.510 + * dense: rows/columns with initial degree > dense are considered "dense" 1.511 + * aggressive: true if aggressive absorption is being performed 1.512 + * ncmpa: number of garbage collections 1.513 + 1.514 + * ---------------------------------------------------------------------------- 1.515 + * LOCAL DOUBLES, used for statistical output only (except for alpha): 1.516 + * ---------------------------------------------------------------------------- 1.517 + */ 1.518 + 1.519 + double f, r, ndiv, s, nms_lu, nms_ldl, dmax, alpha, lnz, lnzme ; 1.520 + 1.521 +/* 1.522 + * f: nvpiv 1.523 + * r: degme + nvpiv 1.524 + * ndiv: number of divisions for LU or LDL' factorizations 1.525 + * s: number of multiply-subtract pairs for LU factorization, for the 1.526 + * current element me 1.527 + * nms_lu number of multiply-subtract pairs for LU factorization 1.528 + * nms_ldl number of multiply-subtract pairs for LDL' factorization 1.529 + * dmax: the largest number of entries in any column of L, including the 1.530 + * diagonal 1.531 + * alpha: "dense" degree ratio 1.532 + * lnz: the number of nonzeros in L (excluding the diagonal) 1.533 + * lnzme: the number of nonzeros in L (excl. the diagonal) for the 1.534 + * current element me 1.535 + 1.536 + * ---------------------------------------------------------------------------- 1.537 + * LOCAL "POINTERS" (indices into the Iw array) 1.538 + * ---------------------------------------------------------------------------- 1.539 +*/ 1.540 + 1.541 + Int p, p1, p2, p3, p4, pdst, pend, pj, pme, pme1, pme2, pn, psrc ; 1.542 + 1.543 +/* 1.544 + * Any parameter (Pe [...] or pfree) or local variable starting with "p" (for 1.545 + * Pointer) is an index into Iw, and all indices into Iw use variables starting 1.546 + * with "p." The only exception to this rule is the iwlen input argument. 1.547 + * 1.548 + * p: pointer into lots of things 1.549 + * p1: Pe [i] for some variable i (start of element list) 1.550 + * p2: Pe [i] + Elen [i] - 1 for some variable i 1.551 + * p3: index of first supervariable in clean list 1.552 + * p4: 1.553 + * pdst: destination pointer, for compression 1.554 + * pend: end of memory to compress 1.555 + * pj: pointer into an element or variable 1.556 + * pme: pointer into the current element (pme1...pme2) 1.557 + * pme1: the current element, me, is stored in Iw [pme1...pme2] 1.558 + * pme2: the end of the current element 1.559 + * pn: pointer into a "clean" variable, also used to compress 1.560 + * psrc: source pointer, for compression 1.561 +*/ 1.562 + 1.563 +/* ========================================================================= */ 1.564 +/* INITIALIZATIONS */ 1.565 +/* ========================================================================= */ 1.566 + 1.567 + /* Note that this restriction on iwlen is slightly more restrictive than 1.568 + * what is actually required in AMD_2. AMD_2 can operate with no elbow 1.569 + * room at all, but it will be slow. For better performance, at least 1.570 + * size-n elbow room is enforced. */ 1.571 + ASSERT (iwlen >= pfree + n) ; 1.572 + ASSERT (n > 0) ; 1.573 + 1.574 + /* initialize output statistics */ 1.575 + lnz = 0 ; 1.576 + ndiv = 0 ; 1.577 + nms_lu = 0 ; 1.578 + nms_ldl = 0 ; 1.579 + dmax = 1 ; 1.580 + me = EMPTY ; 1.581 + 1.582 + mindeg = 0 ; 1.583 + ncmpa = 0 ; 1.584 + nel = 0 ; 1.585 + lemax = 0 ; 1.586 + 1.587 + /* get control parameters */ 1.588 + if (Control != (double *) NULL) 1.589 + { 1.590 + alpha = Control [AMD_DENSE] ; 1.591 + aggressive = (Control [AMD_AGGRESSIVE] != 0) ; 1.592 + } 1.593 + else 1.594 + { 1.595 + alpha = AMD_DEFAULT_DENSE ; 1.596 + aggressive = AMD_DEFAULT_AGGRESSIVE ; 1.597 + } 1.598 + /* Note: if alpha is NaN, this is undefined: */ 1.599 + if (alpha < 0) 1.600 + { 1.601 + /* only remove completely dense rows/columns */ 1.602 + dense = n-2 ; 1.603 + } 1.604 + else 1.605 + { 1.606 + dense = alpha * sqrt ((double) n) ; 1.607 + } 1.608 + dense = MAX (16, dense) ; 1.609 + dense = MIN (n, dense) ; 1.610 + AMD_DEBUG1 (("\n\nAMD (debug), alpha %g, aggr. "ID"\n", 1.611 + alpha, aggressive)) ; 1.612 + 1.613 + for (i = 0 ; i < n ; i++) 1.614 + { 1.615 + Last [i] = EMPTY ; 1.616 + Head [i] = EMPTY ; 1.617 + Next [i] = EMPTY ; 1.618 + /* if separate Hhead array is used for hash buckets: * 1.619 + Hhead [i] = EMPTY ; 1.620 + */ 1.621 + Nv [i] = 1 ; 1.622 + W [i] = 1 ; 1.623 + Elen [i] = 0 ; 1.624 + Degree [i] = Len [i] ; 1.625 + } 1.626 + 1.627 +#ifndef NDEBUG 1.628 + AMD_DEBUG1 (("\n======Nel "ID" initial\n", nel)) ; 1.629 + AMD_dump (n, Pe, Iw, Len, iwlen, pfree, Nv, Next, Last, 1.630 + Head, Elen, Degree, W, -1) ; 1.631 +#endif 1.632 + 1.633 + /* initialize wflg */ 1.634 + wbig = Int_MAX - n ; 1.635 + wflg = clear_flag (0, wbig, W, n) ; 1.636 + 1.637 + /* --------------------------------------------------------------------- */ 1.638 + /* initialize degree lists and eliminate dense and empty rows */ 1.639 + /* --------------------------------------------------------------------- */ 1.640 + 1.641 + ndense = 0 ; 1.642 + 1.643 + for (i = 0 ; i < n ; i++) 1.644 + { 1.645 + deg = Degree [i] ; 1.646 + ASSERT (deg >= 0 && deg < n) ; 1.647 + if (deg == 0) 1.648 + { 1.649 + 1.650 + /* ------------------------------------------------------------- 1.651 + * we have a variable that can be eliminated at once because 1.652 + * there is no off-diagonal non-zero in its row. Note that 1.653 + * Nv [i] = 1 for an empty variable i. It is treated just 1.654 + * the same as an eliminated element i. 1.655 + * ------------------------------------------------------------- */ 1.656 + 1.657 + Elen [i] = FLIP (1) ; 1.658 + nel++ ; 1.659 + Pe [i] = EMPTY ; 1.660 + W [i] = 0 ; 1.661 + 1.662 + } 1.663 + else if (deg > dense) 1.664 + { 1.665 + 1.666 + /* ------------------------------------------------------------- 1.667 + * Dense variables are not treated as elements, but as unordered, 1.668 + * non-principal variables that have no parent. They do not take 1.669 + * part in the postorder, since Nv [i] = 0. Note that the Fortran 1.670 + * version does not have this option. 1.671 + * ------------------------------------------------------------- */ 1.672 + 1.673 + AMD_DEBUG1 (("Dense node "ID" degree "ID"\n", i, deg)) ; 1.674 + ndense++ ; 1.675 + Nv [i] = 0 ; /* do not postorder this node */ 1.676 + Elen [i] = EMPTY ; 1.677 + nel++ ; 1.678 + Pe [i] = EMPTY ; 1.679 + 1.680 + } 1.681 + else 1.682 + { 1.683 + 1.684 + /* ------------------------------------------------------------- 1.685 + * place i in the degree list corresponding to its degree 1.686 + * ------------------------------------------------------------- */ 1.687 + 1.688 + inext = Head [deg] ; 1.689 + ASSERT (inext >= EMPTY && inext < n) ; 1.690 + if (inext != EMPTY) Last [inext] = i ; 1.691 + Next [i] = inext ; 1.692 + Head [deg] = i ; 1.693 + 1.694 + } 1.695 + } 1.696 + 1.697 +/* ========================================================================= */ 1.698 +/* WHILE (selecting pivots) DO */ 1.699 +/* ========================================================================= */ 1.700 + 1.701 + while (nel < n) 1.702 + { 1.703 + 1.704 +#ifndef NDEBUG 1.705 + AMD_DEBUG1 (("\n======Nel "ID"\n", nel)) ; 1.706 + if (AMD_debug >= 2) 1.707 + { 1.708 + AMD_dump (n, Pe, Iw, Len, iwlen, pfree, Nv, Next, 1.709 + Last, Head, Elen, Degree, W, nel) ; 1.710 + } 1.711 +#endif 1.712 + 1.713 +/* ========================================================================= */ 1.714 +/* GET PIVOT OF MINIMUM DEGREE */ 1.715 +/* ========================================================================= */ 1.716 + 1.717 + /* ----------------------------------------------------------------- */ 1.718 + /* find next supervariable for elimination */ 1.719 + /* ----------------------------------------------------------------- */ 1.720 + 1.721 + ASSERT (mindeg >= 0 && mindeg < n) ; 1.722 + for (deg = mindeg ; deg < n ; deg++) 1.723 + { 1.724 + me = Head [deg] ; 1.725 + if (me != EMPTY) break ; 1.726 + } 1.727 + mindeg = deg ; 1.728 + ASSERT (me >= 0 && me < n) ; 1.729 + AMD_DEBUG1 (("=================me: "ID"\n", me)) ; 1.730 + 1.731 + /* ----------------------------------------------------------------- */ 1.732 + /* remove chosen variable from link list */ 1.733 + /* ----------------------------------------------------------------- */ 1.734 + 1.735 + inext = Next [me] ; 1.736 + ASSERT (inext >= EMPTY && inext < n) ; 1.737 + if (inext != EMPTY) Last [inext] = EMPTY ; 1.738 + Head [deg] = inext ; 1.739 + 1.740 + /* ----------------------------------------------------------------- */ 1.741 + /* me represents the elimination of pivots nel to nel+Nv[me]-1. */ 1.742 + /* place me itself as the first in this set. */ 1.743 + /* ----------------------------------------------------------------- */ 1.744 + 1.745 + elenme = Elen [me] ; 1.746 + nvpiv = Nv [me] ; 1.747 + ASSERT (nvpiv > 0) ; 1.748 + nel += nvpiv ; 1.749 + 1.750 +/* ========================================================================= */ 1.751 +/* CONSTRUCT NEW ELEMENT */ 1.752 +/* ========================================================================= */ 1.753 + 1.754 + /* ----------------------------------------------------------------- 1.755 + * At this point, me is the pivotal supervariable. It will be 1.756 + * converted into the current element. Scan list of the pivotal 1.757 + * supervariable, me, setting tree pointers and constructing new list 1.758 + * of supervariables for the new element, me. p is a pointer to the 1.759 + * current position in the old list. 1.760 + * ----------------------------------------------------------------- */ 1.761 + 1.762 + /* flag the variable "me" as being in Lme by negating Nv [me] */ 1.763 + Nv [me] = -nvpiv ; 1.764 + degme = 0 ; 1.765 + ASSERT (Pe [me] >= 0 && Pe [me] < iwlen) ; 1.766 + 1.767 + if (elenme == 0) 1.768 + { 1.769 + 1.770 + /* ------------------------------------------------------------- */ 1.771 + /* construct the new element in place */ 1.772 + /* ------------------------------------------------------------- */ 1.773 + 1.774 + pme1 = Pe [me] ; 1.775 + pme2 = pme1 - 1 ; 1.776 + 1.777 + for (p = pme1 ; p <= pme1 + Len [me] - 1 ; p++) 1.778 + { 1.779 + i = Iw [p] ; 1.780 + ASSERT (i >= 0 && i < n && Nv [i] >= 0) ; 1.781 + nvi = Nv [i] ; 1.782 + if (nvi > 0) 1.783 + { 1.784 + 1.785 + /* ----------------------------------------------------- */ 1.786 + /* i is a principal variable not yet placed in Lme. */ 1.787 + /* store i in new list */ 1.788 + /* ----------------------------------------------------- */ 1.789 + 1.790 + /* flag i as being in Lme by negating Nv [i] */ 1.791 + degme += nvi ; 1.792 + Nv [i] = -nvi ; 1.793 + Iw [++pme2] = i ; 1.794 + 1.795 + /* ----------------------------------------------------- */ 1.796 + /* remove variable i from degree list. */ 1.797 + /* ----------------------------------------------------- */ 1.798 + 1.799 + ilast = Last [i] ; 1.800 + inext = Next [i] ; 1.801 + ASSERT (ilast >= EMPTY && ilast < n) ; 1.802 + ASSERT (inext >= EMPTY && inext < n) ; 1.803 + if (inext != EMPTY) Last [inext] = ilast ; 1.804 + if (ilast != EMPTY) 1.805 + { 1.806 + Next [ilast] = inext ; 1.807 + } 1.808 + else 1.809 + { 1.810 + /* i is at the head of the degree list */ 1.811 + ASSERT (Degree [i] >= 0 && Degree [i] < n) ; 1.812 + Head [Degree [i]] = inext ; 1.813 + } 1.814 + } 1.815 + } 1.816 + } 1.817 + else 1.818 + { 1.819 + 1.820 + /* ------------------------------------------------------------- */ 1.821 + /* construct the new element in empty space, Iw [pfree ...] */ 1.822 + /* ------------------------------------------------------------- */ 1.823 + 1.824 + p = Pe [me] ; 1.825 + pme1 = pfree ; 1.826 + slenme = Len [me] - elenme ; 1.827 + 1.828 + for (knt1 = 1 ; knt1 <= elenme + 1 ; knt1++) 1.829 + { 1.830 + 1.831 + if (knt1 > elenme) 1.832 + { 1.833 + /* search the supervariables in me. */ 1.834 + e = me ; 1.835 + pj = p ; 1.836 + ln = slenme ; 1.837 + AMD_DEBUG2 (("Search sv: "ID" "ID" "ID"\n", me,pj,ln)) ; 1.838 + } 1.839 + else 1.840 + { 1.841 + /* search the elements in me. */ 1.842 + e = Iw [p++] ; 1.843 + ASSERT (e >= 0 && e < n) ; 1.844 + pj = Pe [e] ; 1.845 + ln = Len [e] ; 1.846 + AMD_DEBUG2 (("Search element e "ID" in me "ID"\n", e,me)) ; 1.847 + ASSERT (Elen [e] < EMPTY && W [e] > 0 && pj >= 0) ; 1.848 + } 1.849 + ASSERT (ln >= 0 && (ln == 0 || (pj >= 0 && pj < iwlen))) ; 1.850 + 1.851 + /* --------------------------------------------------------- 1.852 + * search for different supervariables and add them to the 1.853 + * new list, compressing when necessary. this loop is 1.854 + * executed once for each element in the list and once for 1.855 + * all the supervariables in the list. 1.856 + * --------------------------------------------------------- */ 1.857 + 1.858 + for (knt2 = 1 ; knt2 <= ln ; knt2++) 1.859 + { 1.860 + i = Iw [pj++] ; 1.861 + ASSERT (i >= 0 && i < n && (i == me || Elen [i] >= EMPTY)); 1.862 + nvi = Nv [i] ; 1.863 + AMD_DEBUG2 ((": "ID" "ID" "ID" "ID"\n", 1.864 + i, Elen [i], Nv [i], wflg)) ; 1.865 + 1.866 + if (nvi > 0) 1.867 + { 1.868 + 1.869 + /* ------------------------------------------------- */ 1.870 + /* compress Iw, if necessary */ 1.871 + /* ------------------------------------------------- */ 1.872 + 1.873 + if (pfree >= iwlen) 1.874 + { 1.875 + 1.876 + AMD_DEBUG1 (("GARBAGE COLLECTION\n")) ; 1.877 + 1.878 + /* prepare for compressing Iw by adjusting pointers 1.879 + * and lengths so that the lists being searched in 1.880 + * the inner and outer loops contain only the 1.881 + * remaining entries. */ 1.882 + 1.883 + Pe [me] = p ; 1.884 + Len [me] -= knt1 ; 1.885 + /* check if nothing left of supervariable me */ 1.886 + if (Len [me] == 0) Pe [me] = EMPTY ; 1.887 + Pe [e] = pj ; 1.888 + Len [e] = ln - knt2 ; 1.889 + /* nothing left of element e */ 1.890 + if (Len [e] == 0) Pe [e] = EMPTY ; 1.891 + 1.892 + ncmpa++ ; /* one more garbage collection */ 1.893 + 1.894 + /* store first entry of each object in Pe */ 1.895 + /* FLIP the first entry in each object */ 1.896 + for (j = 0 ; j < n ; j++) 1.897 + { 1.898 + pn = Pe [j] ; 1.899 + if (pn >= 0) 1.900 + { 1.901 + ASSERT (pn >= 0 && pn < iwlen) ; 1.902 + Pe [j] = Iw [pn] ; 1.903 + Iw [pn] = FLIP (j) ; 1.904 + } 1.905 + } 1.906 + 1.907 + /* psrc/pdst point to source/destination */ 1.908 + psrc = 0 ; 1.909 + pdst = 0 ; 1.910 + pend = pme1 - 1 ; 1.911 + 1.912 + while (psrc <= pend) 1.913 + { 1.914 + /* search for next FLIP'd entry */ 1.915 + j = FLIP (Iw [psrc++]) ; 1.916 + if (j >= 0) 1.917 + { 1.918 + AMD_DEBUG2 (("Got object j: "ID"\n", j)) ; 1.919 + Iw [pdst] = Pe [j] ; 1.920 + Pe [j] = pdst++ ; 1.921 + lenj = Len [j] ; 1.922 + /* copy from source to destination */ 1.923 + for (knt3 = 0 ; knt3 <= lenj - 2 ; knt3++) 1.924 + { 1.925 + Iw [pdst++] = Iw [psrc++] ; 1.926 + } 1.927 + } 1.928 + } 1.929 + 1.930 + /* move the new partially-constructed element */ 1.931 + p1 = pdst ; 1.932 + for (psrc = pme1 ; psrc <= pfree-1 ; psrc++) 1.933 + { 1.934 + Iw [pdst++] = Iw [psrc] ; 1.935 + } 1.936 + pme1 = p1 ; 1.937 + pfree = pdst ; 1.938 + pj = Pe [e] ; 1.939 + p = Pe [me] ; 1.940 + 1.941 + } 1.942 + 1.943 + /* ------------------------------------------------- */ 1.944 + /* i is a principal variable not yet placed in Lme */ 1.945 + /* store i in new list */ 1.946 + /* ------------------------------------------------- */ 1.947 + 1.948 + /* flag i as being in Lme by negating Nv [i] */ 1.949 + degme += nvi ; 1.950 + Nv [i] = -nvi ; 1.951 + Iw [pfree++] = i ; 1.952 + AMD_DEBUG2 ((" s: "ID" nv "ID"\n", i, Nv [i])); 1.953 + 1.954 + /* ------------------------------------------------- */ 1.955 + /* remove variable i from degree link list */ 1.956 + /* ------------------------------------------------- */ 1.957 + 1.958 + ilast = Last [i] ; 1.959 + inext = Next [i] ; 1.960 + ASSERT (ilast >= EMPTY && ilast < n) ; 1.961 + ASSERT (inext >= EMPTY && inext < n) ; 1.962 + if (inext != EMPTY) Last [inext] = ilast ; 1.963 + if (ilast != EMPTY) 1.964 + { 1.965 + Next [ilast] = inext ; 1.966 + } 1.967 + else 1.968 + { 1.969 + /* i is at the head of the degree list */ 1.970 + ASSERT (Degree [i] >= 0 && Degree [i] < n) ; 1.971 + Head [Degree [i]] = inext ; 1.972 + } 1.973 + } 1.974 + } 1.975 + 1.976 + if (e != me) 1.977 + { 1.978 + /* set tree pointer and flag to indicate element e is 1.979 + * absorbed into new element me (the parent of e is me) */ 1.980 + AMD_DEBUG1 ((" Element "ID" => "ID"\n", e, me)) ; 1.981 + Pe [e] = FLIP (me) ; 1.982 + W [e] = 0 ; 1.983 + } 1.984 + } 1.985 + 1.986 + pme2 = pfree - 1 ; 1.987 + } 1.988 + 1.989 + /* ----------------------------------------------------------------- */ 1.990 + /* me has now been converted into an element in Iw [pme1..pme2] */ 1.991 + /* ----------------------------------------------------------------- */ 1.992 + 1.993 + /* degme holds the external degree of new element */ 1.994 + Degree [me] = degme ; 1.995 + Pe [me] = pme1 ; 1.996 + Len [me] = pme2 - pme1 + 1 ; 1.997 + ASSERT (Pe [me] >= 0 && Pe [me] < iwlen) ; 1.998 + 1.999 + Elen [me] = FLIP (nvpiv + degme) ; 1.1000 + /* FLIP (Elen (me)) is now the degree of pivot (including 1.1001 + * diagonal part). */ 1.1002 + 1.1003 +#ifndef NDEBUG 1.1004 + AMD_DEBUG2 (("New element structure: length= "ID"\n", pme2-pme1+1)) ; 1.1005 + for (pme = pme1 ; pme <= pme2 ; pme++) AMD_DEBUG3 ((" "ID"", Iw[pme])); 1.1006 + AMD_DEBUG3 (("\n")) ; 1.1007 +#endif 1.1008 + 1.1009 + /* ----------------------------------------------------------------- */ 1.1010 + /* make sure that wflg is not too large. */ 1.1011 + /* ----------------------------------------------------------------- */ 1.1012 + 1.1013 + /* With the current value of wflg, wflg+n must not cause integer 1.1014 + * overflow */ 1.1015 + 1.1016 + wflg = clear_flag (wflg, wbig, W, n) ; 1.1017 + 1.1018 +/* ========================================================================= */ 1.1019 +/* COMPUTE (W [e] - wflg) = |Le\Lme| FOR ALL ELEMENTS */ 1.1020 +/* ========================================================================= */ 1.1021 + 1.1022 + /* ----------------------------------------------------------------- 1.1023 + * Scan 1: compute the external degrees of previous elements with 1.1024 + * respect to the current element. That is: 1.1025 + * (W [e] - wflg) = |Le \ Lme| 1.1026 + * for each element e that appears in any supervariable in Lme. The 1.1027 + * notation Le refers to the pattern (list of supervariables) of a 1.1028 + * previous element e, where e is not yet absorbed, stored in 1.1029 + * Iw [Pe [e] + 1 ... Pe [e] + Len [e]]. The notation Lme 1.1030 + * refers to the pattern of the current element (stored in 1.1031 + * Iw [pme1..pme2]). If aggressive absorption is enabled, and 1.1032 + * (W [e] - wflg) becomes zero, then the element e will be absorbed 1.1033 + * in Scan 2. 1.1034 + * ----------------------------------------------------------------- */ 1.1035 + 1.1036 + AMD_DEBUG2 (("me: ")) ; 1.1037 + for (pme = pme1 ; pme <= pme2 ; pme++) 1.1038 + { 1.1039 + i = Iw [pme] ; 1.1040 + ASSERT (i >= 0 && i < n) ; 1.1041 + eln = Elen [i] ; 1.1042 + AMD_DEBUG3 ((""ID" Elen "ID": \n", i, eln)) ; 1.1043 + if (eln > 0) 1.1044 + { 1.1045 + /* note that Nv [i] has been negated to denote i in Lme: */ 1.1046 + nvi = -Nv [i] ; 1.1047 + ASSERT (nvi > 0 && Pe [i] >= 0 && Pe [i] < iwlen) ; 1.1048 + wnvi = wflg - nvi ; 1.1049 + for (p = Pe [i] ; p <= Pe [i] + eln - 1 ; p++) 1.1050 + { 1.1051 + e = Iw [p] ; 1.1052 + ASSERT (e >= 0 && e < n) ; 1.1053 + we = W [e] ; 1.1054 + AMD_DEBUG4 ((" e "ID" we "ID" ", e, we)) ; 1.1055 + if (we >= wflg) 1.1056 + { 1.1057 + /* unabsorbed element e has been seen in this loop */ 1.1058 + AMD_DEBUG4 ((" unabsorbed, first time seen")) ; 1.1059 + we -= nvi ; 1.1060 + } 1.1061 + else if (we != 0) 1.1062 + { 1.1063 + /* e is an unabsorbed element */ 1.1064 + /* this is the first we have seen e in all of Scan 1 */ 1.1065 + AMD_DEBUG4 ((" unabsorbed")) ; 1.1066 + we = Degree [e] + wnvi ; 1.1067 + } 1.1068 + AMD_DEBUG4 (("\n")) ; 1.1069 + W [e] = we ; 1.1070 + } 1.1071 + } 1.1072 + } 1.1073 + AMD_DEBUG2 (("\n")) ; 1.1074 + 1.1075 +/* ========================================================================= */ 1.1076 +/* DEGREE UPDATE AND ELEMENT ABSORPTION */ 1.1077 +/* ========================================================================= */ 1.1078 + 1.1079 + /* ----------------------------------------------------------------- 1.1080 + * Scan 2: for each i in Lme, sum up the degree of Lme (which is 1.1081 + * degme), plus the sum of the external degrees of each Le for the 1.1082 + * elements e appearing within i, plus the supervariables in i. 1.1083 + * Place i in hash list. 1.1084 + * ----------------------------------------------------------------- */ 1.1085 + 1.1086 + for (pme = pme1 ; pme <= pme2 ; pme++) 1.1087 + { 1.1088 + i = Iw [pme] ; 1.1089 + ASSERT (i >= 0 && i < n && Nv [i] < 0 && Elen [i] >= 0) ; 1.1090 + AMD_DEBUG2 (("Updating: i "ID" "ID" "ID"\n", i, Elen[i], Len [i])); 1.1091 + p1 = Pe [i] ; 1.1092 + p2 = p1 + Elen [i] - 1 ; 1.1093 + pn = p1 ; 1.1094 + hash = 0 ; 1.1095 + deg = 0 ; 1.1096 + ASSERT (p1 >= 0 && p1 < iwlen && p2 >= -1 && p2 < iwlen) ; 1.1097 + 1.1098 + /* ------------------------------------------------------------- */ 1.1099 + /* scan the element list associated with supervariable i */ 1.1100 + /* ------------------------------------------------------------- */ 1.1101 + 1.1102 + /* UMFPACK/MA38-style approximate degree: */ 1.1103 + if (aggressive) 1.1104 + { 1.1105 + for (p = p1 ; p <= p2 ; p++) 1.1106 + { 1.1107 + e = Iw [p] ; 1.1108 + ASSERT (e >= 0 && e < n) ; 1.1109 + we = W [e] ; 1.1110 + if (we != 0) 1.1111 + { 1.1112 + /* e is an unabsorbed element */ 1.1113 + /* dext = | Le \ Lme | */ 1.1114 + dext = we - wflg ; 1.1115 + if (dext > 0) 1.1116 + { 1.1117 + deg += dext ; 1.1118 + Iw [pn++] = e ; 1.1119 + hash += e ; 1.1120 + AMD_DEBUG4 ((" e: "ID" hash = "ID"\n",e,hash)) ; 1.1121 + } 1.1122 + else 1.1123 + { 1.1124 + /* external degree of e is zero, absorb e into me*/ 1.1125 + AMD_DEBUG1 ((" Element "ID" =>"ID" (aggressive)\n", 1.1126 + e, me)) ; 1.1127 + ASSERT (dext == 0) ; 1.1128 + Pe [e] = FLIP (me) ; 1.1129 + W [e] = 0 ; 1.1130 + } 1.1131 + } 1.1132 + } 1.1133 + } 1.1134 + else 1.1135 + { 1.1136 + for (p = p1 ; p <= p2 ; p++) 1.1137 + { 1.1138 + e = Iw [p] ; 1.1139 + ASSERT (e >= 0 && e < n) ; 1.1140 + we = W [e] ; 1.1141 + if (we != 0) 1.1142 + { 1.1143 + /* e is an unabsorbed element */ 1.1144 + dext = we - wflg ; 1.1145 + ASSERT (dext >= 0) ; 1.1146 + deg += dext ; 1.1147 + Iw [pn++] = e ; 1.1148 + hash += e ; 1.1149 + AMD_DEBUG4 ((" e: "ID" hash = "ID"\n",e,hash)) ; 1.1150 + } 1.1151 + } 1.1152 + } 1.1153 + 1.1154 + /* count the number of elements in i (including me): */ 1.1155 + Elen [i] = pn - p1 + 1 ; 1.1156 + 1.1157 + /* ------------------------------------------------------------- */ 1.1158 + /* scan the supervariables in the list associated with i */ 1.1159 + /* ------------------------------------------------------------- */ 1.1160 + 1.1161 + /* The bulk of the AMD run time is typically spent in this loop, 1.1162 + * particularly if the matrix has many dense rows that are not 1.1163 + * removed prior to ordering. */ 1.1164 + p3 = pn ; 1.1165 + p4 = p1 + Len [i] ; 1.1166 + for (p = p2 + 1 ; p < p4 ; p++) 1.1167 + { 1.1168 + j = Iw [p] ; 1.1169 + ASSERT (j >= 0 && j < n) ; 1.1170 + nvj = Nv [j] ; 1.1171 + if (nvj > 0) 1.1172 + { 1.1173 + /* j is unabsorbed, and not in Lme. */ 1.1174 + /* add to degree and add to new list */ 1.1175 + deg += nvj ; 1.1176 + Iw [pn++] = j ; 1.1177 + hash += j ; 1.1178 + AMD_DEBUG4 ((" s: "ID" hash "ID" Nv[j]= "ID"\n", 1.1179 + j, hash, nvj)) ; 1.1180 + } 1.1181 + } 1.1182 + 1.1183 + /* ------------------------------------------------------------- */ 1.1184 + /* update the degree and check for mass elimination */ 1.1185 + /* ------------------------------------------------------------- */ 1.1186 + 1.1187 + /* with aggressive absorption, deg==0 is identical to the 1.1188 + * Elen [i] == 1 && p3 == pn test, below. */ 1.1189 + ASSERT (IMPLIES (aggressive, (deg==0) == (Elen[i]==1 && p3==pn))) ; 1.1190 + 1.1191 + if (Elen [i] == 1 && p3 == pn) 1.1192 + { 1.1193 + 1.1194 + /* --------------------------------------------------------- */ 1.1195 + /* mass elimination */ 1.1196 + /* --------------------------------------------------------- */ 1.1197 + 1.1198 + /* There is nothing left of this node except for an edge to 1.1199 + * the current pivot element. Elen [i] is 1, and there are 1.1200 + * no variables adjacent to node i. Absorb i into the 1.1201 + * current pivot element, me. Note that if there are two or 1.1202 + * more mass eliminations, fillin due to mass elimination is 1.1203 + * possible within the nvpiv-by-nvpiv pivot block. It is this 1.1204 + * step that causes AMD's analysis to be an upper bound. 1.1205 + * 1.1206 + * The reason is that the selected pivot has a lower 1.1207 + * approximate degree than the true degree of the two mass 1.1208 + * eliminated nodes. There is no edge between the two mass 1.1209 + * eliminated nodes. They are merged with the current pivot 1.1210 + * anyway. 1.1211 + * 1.1212 + * No fillin occurs in the Schur complement, in any case, 1.1213 + * and this effect does not decrease the quality of the 1.1214 + * ordering itself, just the quality of the nonzero and 1.1215 + * flop count analysis. It also means that the post-ordering 1.1216 + * is not an exact elimination tree post-ordering. */ 1.1217 + 1.1218 + AMD_DEBUG1 ((" MASS i "ID" => parent e "ID"\n", i, me)) ; 1.1219 + Pe [i] = FLIP (me) ; 1.1220 + nvi = -Nv [i] ; 1.1221 + degme -= nvi ; 1.1222 + nvpiv += nvi ; 1.1223 + nel += nvi ; 1.1224 + Nv [i] = 0 ; 1.1225 + Elen [i] = EMPTY ; 1.1226 + 1.1227 + } 1.1228 + else 1.1229 + { 1.1230 + 1.1231 + /* --------------------------------------------------------- */ 1.1232 + /* update the upper-bound degree of i */ 1.1233 + /* --------------------------------------------------------- */ 1.1234 + 1.1235 + /* the following degree does not yet include the size 1.1236 + * of the current element, which is added later: */ 1.1237 + 1.1238 + Degree [i] = MIN (Degree [i], deg) ; 1.1239 + 1.1240 + /* --------------------------------------------------------- */ 1.1241 + /* add me to the list for i */ 1.1242 + /* --------------------------------------------------------- */ 1.1243 + 1.1244 + /* move first supervariable to end of list */ 1.1245 + Iw [pn] = Iw [p3] ; 1.1246 + /* move first element to end of element part of list */ 1.1247 + Iw [p3] = Iw [p1] ; 1.1248 + /* add new element, me, to front of list. */ 1.1249 + Iw [p1] = me ; 1.1250 + /* store the new length of the list in Len [i] */ 1.1251 + Len [i] = pn - p1 + 1 ; 1.1252 + 1.1253 + /* --------------------------------------------------------- */ 1.1254 + /* place in hash bucket. Save hash key of i in Last [i]. */ 1.1255 + /* --------------------------------------------------------- */ 1.1256 + 1.1257 + /* NOTE: this can fail if hash is negative, because the ANSI C 1.1258 + * standard does not define a % b when a and/or b are negative. 1.1259 + * That's why hash is defined as an unsigned Int, to avoid this 1.1260 + * problem. */ 1.1261 + hash = hash % n ; 1.1262 + ASSERT (((Int) hash) >= 0 && ((Int) hash) < n) ; 1.1263 + 1.1264 + /* if the Hhead array is not used: */ 1.1265 + j = Head [hash] ; 1.1266 + if (j <= EMPTY) 1.1267 + { 1.1268 + /* degree list is empty, hash head is FLIP (j) */ 1.1269 + Next [i] = FLIP (j) ; 1.1270 + Head [hash] = FLIP (i) ; 1.1271 + } 1.1272 + else 1.1273 + { 1.1274 + /* degree list is not empty, use Last [Head [hash]] as 1.1275 + * hash head. */ 1.1276 + Next [i] = Last [j] ; 1.1277 + Last [j] = i ; 1.1278 + } 1.1279 + 1.1280 + /* if a separate Hhead array is used: * 1.1281 + Next [i] = Hhead [hash] ; 1.1282 + Hhead [hash] = i ; 1.1283 + */ 1.1284 + 1.1285 + Last [i] = hash ; 1.1286 + } 1.1287 + } 1.1288 + 1.1289 + Degree [me] = degme ; 1.1290 + 1.1291 + /* ----------------------------------------------------------------- */ 1.1292 + /* Clear the counter array, W [...], by incrementing wflg. */ 1.1293 + /* ----------------------------------------------------------------- */ 1.1294 + 1.1295 + /* make sure that wflg+n does not cause integer overflow */ 1.1296 + lemax = MAX (lemax, degme) ; 1.1297 + wflg += lemax ; 1.1298 + wflg = clear_flag (wflg, wbig, W, n) ; 1.1299 + /* at this point, W [0..n-1] < wflg holds */ 1.1300 + 1.1301 +/* ========================================================================= */ 1.1302 +/* SUPERVARIABLE DETECTION */ 1.1303 +/* ========================================================================= */ 1.1304 + 1.1305 + AMD_DEBUG1 (("Detecting supervariables:\n")) ; 1.1306 + for (pme = pme1 ; pme <= pme2 ; pme++) 1.1307 + { 1.1308 + i = Iw [pme] ; 1.1309 + ASSERT (i >= 0 && i < n) ; 1.1310 + AMD_DEBUG2 (("Consider i "ID" nv "ID"\n", i, Nv [i])) ; 1.1311 + if (Nv [i] < 0) 1.1312 + { 1.1313 + /* i is a principal variable in Lme */ 1.1314 + 1.1315 + /* --------------------------------------------------------- 1.1316 + * examine all hash buckets with 2 or more variables. We do 1.1317 + * this by examing all unique hash keys for supervariables in 1.1318 + * the pattern Lme of the current element, me 1.1319 + * --------------------------------------------------------- */ 1.1320 + 1.1321 + /* let i = head of hash bucket, and empty the hash bucket */ 1.1322 + ASSERT (Last [i] >= 0 && Last [i] < n) ; 1.1323 + hash = Last [i] ; 1.1324 + 1.1325 + /* if Hhead array is not used: */ 1.1326 + j = Head [hash] ; 1.1327 + if (j == EMPTY) 1.1328 + { 1.1329 + /* hash bucket and degree list are both empty */ 1.1330 + i = EMPTY ; 1.1331 + } 1.1332 + else if (j < EMPTY) 1.1333 + { 1.1334 + /* degree list is empty */ 1.1335 + i = FLIP (j) ; 1.1336 + Head [hash] = EMPTY ; 1.1337 + } 1.1338 + else 1.1339 + { 1.1340 + /* degree list is not empty, restore Last [j] of head j */ 1.1341 + i = Last [j] ; 1.1342 + Last [j] = EMPTY ; 1.1343 + } 1.1344 + 1.1345 + /* if separate Hhead array is used: * 1.1346 + i = Hhead [hash] ; 1.1347 + Hhead [hash] = EMPTY ; 1.1348 + */ 1.1349 + 1.1350 + ASSERT (i >= EMPTY && i < n) ; 1.1351 + AMD_DEBUG2 (("----i "ID" hash "ID"\n", i, hash)) ; 1.1352 + 1.1353 + while (i != EMPTY && Next [i] != EMPTY) 1.1354 + { 1.1355 + 1.1356 + /* ----------------------------------------------------- 1.1357 + * this bucket has one or more variables following i. 1.1358 + * scan all of them to see if i can absorb any entries 1.1359 + * that follow i in hash bucket. Scatter i into w. 1.1360 + * ----------------------------------------------------- */ 1.1361 + 1.1362 + ln = Len [i] ; 1.1363 + eln = Elen [i] ; 1.1364 + ASSERT (ln >= 0 && eln >= 0) ; 1.1365 + ASSERT (Pe [i] >= 0 && Pe [i] < iwlen) ; 1.1366 + /* do not flag the first element in the list (me) */ 1.1367 + for (p = Pe [i] + 1 ; p <= Pe [i] + ln - 1 ; p++) 1.1368 + { 1.1369 + ASSERT (Iw [p] >= 0 && Iw [p] < n) ; 1.1370 + W [Iw [p]] = wflg ; 1.1371 + } 1.1372 + 1.1373 + /* ----------------------------------------------------- */ 1.1374 + /* scan every other entry j following i in bucket */ 1.1375 + /* ----------------------------------------------------- */ 1.1376 + 1.1377 + jlast = i ; 1.1378 + j = Next [i] ; 1.1379 + ASSERT (j >= EMPTY && j < n) ; 1.1380 + 1.1381 + while (j != EMPTY) 1.1382 + { 1.1383 + /* ------------------------------------------------- */ 1.1384 + /* check if j and i have identical nonzero pattern */ 1.1385 + /* ------------------------------------------------- */ 1.1386 + 1.1387 + AMD_DEBUG3 (("compare i "ID" and j "ID"\n", i,j)) ; 1.1388 + 1.1389 + /* check if i and j have the same Len and Elen */ 1.1390 + ASSERT (Len [j] >= 0 && Elen [j] >= 0) ; 1.1391 + ASSERT (Pe [j] >= 0 && Pe [j] < iwlen) ; 1.1392 + ok = (Len [j] == ln) && (Elen [j] == eln) ; 1.1393 + /* skip the first element in the list (me) */ 1.1394 + for (p = Pe [j] + 1 ; ok && p <= Pe [j] + ln - 1 ; p++) 1.1395 + { 1.1396 + ASSERT (Iw [p] >= 0 && Iw [p] < n) ; 1.1397 + if (W [Iw [p]] != wflg) ok = 0 ; 1.1398 + } 1.1399 + if (ok) 1.1400 + { 1.1401 + /* --------------------------------------------- */ 1.1402 + /* found it! j can be absorbed into i */ 1.1403 + /* --------------------------------------------- */ 1.1404 + 1.1405 + AMD_DEBUG1 (("found it! j "ID" => i "ID"\n", j,i)); 1.1406 + Pe [j] = FLIP (i) ; 1.1407 + /* both Nv [i] and Nv [j] are negated since they */ 1.1408 + /* are in Lme, and the absolute values of each */ 1.1409 + /* are the number of variables in i and j: */ 1.1410 + Nv [i] += Nv [j] ; 1.1411 + Nv [j] = 0 ; 1.1412 + Elen [j] = EMPTY ; 1.1413 + /* delete j from hash bucket */ 1.1414 + ASSERT (j != Next [j]) ; 1.1415 + j = Next [j] ; 1.1416 + Next [jlast] = j ; 1.1417 + 1.1418 + } 1.1419 + else 1.1420 + { 1.1421 + /* j cannot be absorbed into i */ 1.1422 + jlast = j ; 1.1423 + ASSERT (j != Next [j]) ; 1.1424 + j = Next [j] ; 1.1425 + } 1.1426 + ASSERT (j >= EMPTY && j < n) ; 1.1427 + } 1.1428 + 1.1429 + /* ----------------------------------------------------- 1.1430 + * no more variables can be absorbed into i 1.1431 + * go to next i in bucket and clear flag array 1.1432 + * ----------------------------------------------------- */ 1.1433 + 1.1434 + wflg++ ; 1.1435 + i = Next [i] ; 1.1436 + ASSERT (i >= EMPTY && i < n) ; 1.1437 + 1.1438 + } 1.1439 + } 1.1440 + } 1.1441 + AMD_DEBUG2 (("detect done\n")) ; 1.1442 + 1.1443 +/* ========================================================================= */ 1.1444 +/* RESTORE DEGREE LISTS AND REMOVE NONPRINCIPAL SUPERVARIABLES FROM ELEMENT */ 1.1445 +/* ========================================================================= */ 1.1446 + 1.1447 + p = pme1 ; 1.1448 + nleft = n - nel ; 1.1449 + for (pme = pme1 ; pme <= pme2 ; pme++) 1.1450 + { 1.1451 + i = Iw [pme] ; 1.1452 + ASSERT (i >= 0 && i < n) ; 1.1453 + nvi = -Nv [i] ; 1.1454 + AMD_DEBUG3 (("Restore i "ID" "ID"\n", i, nvi)) ; 1.1455 + if (nvi > 0) 1.1456 + { 1.1457 + /* i is a principal variable in Lme */ 1.1458 + /* restore Nv [i] to signify that i is principal */ 1.1459 + Nv [i] = nvi ; 1.1460 + 1.1461 + /* --------------------------------------------------------- */ 1.1462 + /* compute the external degree (add size of current element) */ 1.1463 + /* --------------------------------------------------------- */ 1.1464 + 1.1465 + deg = Degree [i] + degme - nvi ; 1.1466 + deg = MIN (deg, nleft - nvi) ; 1.1467 + ASSERT (IMPLIES (aggressive, deg > 0) && deg >= 0 && deg < n) ; 1.1468 + 1.1469 + /* --------------------------------------------------------- */ 1.1470 + /* place the supervariable at the head of the degree list */ 1.1471 + /* --------------------------------------------------------- */ 1.1472 + 1.1473 + inext = Head [deg] ; 1.1474 + ASSERT (inext >= EMPTY && inext < n) ; 1.1475 + if (inext != EMPTY) Last [inext] = i ; 1.1476 + Next [i] = inext ; 1.1477 + Last [i] = EMPTY ; 1.1478 + Head [deg] = i ; 1.1479 + 1.1480 + /* --------------------------------------------------------- */ 1.1481 + /* save the new degree, and find the minimum degree */ 1.1482 + /* --------------------------------------------------------- */ 1.1483 + 1.1484 + mindeg = MIN (mindeg, deg) ; 1.1485 + Degree [i] = deg ; 1.1486 + 1.1487 + /* --------------------------------------------------------- */ 1.1488 + /* place the supervariable in the element pattern */ 1.1489 + /* --------------------------------------------------------- */ 1.1490 + 1.1491 + Iw [p++] = i ; 1.1492 + 1.1493 + } 1.1494 + } 1.1495 + AMD_DEBUG2 (("restore done\n")) ; 1.1496 + 1.1497 +/* ========================================================================= */ 1.1498 +/* FINALIZE THE NEW ELEMENT */ 1.1499 +/* ========================================================================= */ 1.1500 + 1.1501 + AMD_DEBUG2 (("ME = "ID" DONE\n", me)) ; 1.1502 + Nv [me] = nvpiv ; 1.1503 + /* save the length of the list for the new element me */ 1.1504 + Len [me] = p - pme1 ; 1.1505 + if (Len [me] == 0) 1.1506 + { 1.1507 + /* there is nothing left of the current pivot element */ 1.1508 + /* it is a root of the assembly tree */ 1.1509 + Pe [me] = EMPTY ; 1.1510 + W [me] = 0 ; 1.1511 + } 1.1512 + if (elenme != 0) 1.1513 + { 1.1514 + /* element was not constructed in place: deallocate part of */ 1.1515 + /* it since newly nonprincipal variables may have been removed */ 1.1516 + pfree = p ; 1.1517 + } 1.1518 + 1.1519 + /* The new element has nvpiv pivots and the size of the contribution 1.1520 + * block for a multifrontal method is degme-by-degme, not including 1.1521 + * the "dense" rows/columns. If the "dense" rows/columns are included, 1.1522 + * the frontal matrix is no larger than 1.1523 + * (degme+ndense)-by-(degme+ndense). 1.1524 + */ 1.1525 + 1.1526 + if (Info != (double *) NULL) 1.1527 + { 1.1528 + f = nvpiv ; 1.1529 + r = degme + ndense ; 1.1530 + dmax = MAX (dmax, f + r) ; 1.1531 + 1.1532 + /* number of nonzeros in L (excluding the diagonal) */ 1.1533 + lnzme = f*r + (f-1)*f/2 ; 1.1534 + lnz += lnzme ; 1.1535 + 1.1536 + /* number of divide operations for LDL' and for LU */ 1.1537 + ndiv += lnzme ; 1.1538 + 1.1539 + /* number of multiply-subtract pairs for LU */ 1.1540 + s = f*r*r + r*(f-1)*f + (f-1)*f*(2*f-1)/6 ; 1.1541 + nms_lu += s ; 1.1542 + 1.1543 + /* number of multiply-subtract pairs for LDL' */ 1.1544 + nms_ldl += (s + lnzme)/2 ; 1.1545 + } 1.1546 + 1.1547 +#ifndef NDEBUG 1.1548 + AMD_DEBUG2 (("finalize done nel "ID" n "ID"\n ::::\n", nel, n)) ; 1.1549 + for (pme = Pe [me] ; pme <= Pe [me] + Len [me] - 1 ; pme++) 1.1550 + { 1.1551 + AMD_DEBUG3 ((" "ID"", Iw [pme])) ; 1.1552 + } 1.1553 + AMD_DEBUG3 (("\n")) ; 1.1554 +#endif 1.1555 + 1.1556 + } 1.1557 + 1.1558 +/* ========================================================================= */ 1.1559 +/* DONE SELECTING PIVOTS */ 1.1560 +/* ========================================================================= */ 1.1561 + 1.1562 + if (Info != (double *) NULL) 1.1563 + { 1.1564 + 1.1565 + /* count the work to factorize the ndense-by-ndense submatrix */ 1.1566 + f = ndense ; 1.1567 + dmax = MAX (dmax, (double) ndense) ; 1.1568 + 1.1569 + /* number of nonzeros in L (excluding the diagonal) */ 1.1570 + lnzme = (f-1)*f/2 ; 1.1571 + lnz += lnzme ; 1.1572 + 1.1573 + /* number of divide operations for LDL' and for LU */ 1.1574 + ndiv += lnzme ; 1.1575 + 1.1576 + /* number of multiply-subtract pairs for LU */ 1.1577 + s = (f-1)*f*(2*f-1)/6 ; 1.1578 + nms_lu += s ; 1.1579 + 1.1580 + /* number of multiply-subtract pairs for LDL' */ 1.1581 + nms_ldl += (s + lnzme)/2 ; 1.1582 + 1.1583 + /* number of nz's in L (excl. diagonal) */ 1.1584 + Info [AMD_LNZ] = lnz ; 1.1585 + 1.1586 + /* number of divide ops for LU and LDL' */ 1.1587 + Info [AMD_NDIV] = ndiv ; 1.1588 + 1.1589 + /* number of multiply-subtract pairs for LDL' */ 1.1590 + Info [AMD_NMULTSUBS_LDL] = nms_ldl ; 1.1591 + 1.1592 + /* number of multiply-subtract pairs for LU */ 1.1593 + Info [AMD_NMULTSUBS_LU] = nms_lu ; 1.1594 + 1.1595 + /* number of "dense" rows/columns */ 1.1596 + Info [AMD_NDENSE] = ndense ; 1.1597 + 1.1598 + /* largest front is dmax-by-dmax */ 1.1599 + Info [AMD_DMAX] = dmax ; 1.1600 + 1.1601 + /* number of garbage collections in AMD */ 1.1602 + Info [AMD_NCMPA] = ncmpa ; 1.1603 + 1.1604 + /* successful ordering */ 1.1605 + Info [AMD_STATUS] = AMD_OK ; 1.1606 + } 1.1607 + 1.1608 +/* ========================================================================= */ 1.1609 +/* POST-ORDERING */ 1.1610 +/* ========================================================================= */ 1.1611 + 1.1612 +/* ------------------------------------------------------------------------- 1.1613 + * Variables at this point: 1.1614 + * 1.1615 + * Pe: holds the elimination tree. The parent of j is FLIP (Pe [j]), 1.1616 + * or EMPTY if j is a root. The tree holds both elements and 1.1617 + * non-principal (unordered) variables absorbed into them. 1.1618 + * Dense variables are non-principal and unordered. 1.1619 + * 1.1620 + * Elen: holds the size of each element, including the diagonal part. 1.1621 + * FLIP (Elen [e]) > 0 if e is an element. For unordered 1.1622 + * variables i, Elen [i] is EMPTY. 1.1623 + * 1.1624 + * Nv: Nv [e] > 0 is the number of pivots represented by the element e. 1.1625 + * For unordered variables i, Nv [i] is zero. 1.1626 + * 1.1627 + * Contents no longer needed: 1.1628 + * W, Iw, Len, Degree, Head, Next, Last. 1.1629 + * 1.1630 + * The matrix itself has been destroyed. 1.1631 + * 1.1632 + * n: the size of the matrix. 1.1633 + * No other scalars needed (pfree, iwlen, etc.) 1.1634 + * ------------------------------------------------------------------------- */ 1.1635 + 1.1636 + /* restore Pe */ 1.1637 + for (i = 0 ; i < n ; i++) 1.1638 + { 1.1639 + Pe [i] = FLIP (Pe [i]) ; 1.1640 + } 1.1641 + 1.1642 + /* restore Elen, for output information, and for postordering */ 1.1643 + for (i = 0 ; i < n ; i++) 1.1644 + { 1.1645 + Elen [i] = FLIP (Elen [i]) ; 1.1646 + } 1.1647 + 1.1648 +/* Now the parent of j is Pe [j], or EMPTY if j is a root. Elen [e] > 0 1.1649 + * is the size of element e. Elen [i] is EMPTY for unordered variable i. */ 1.1650 + 1.1651 +#ifndef NDEBUG 1.1652 + AMD_DEBUG2 (("\nTree:\n")) ; 1.1653 + for (i = 0 ; i < n ; i++) 1.1654 + { 1.1655 + AMD_DEBUG2 ((" "ID" parent: "ID" ", i, Pe [i])) ; 1.1656 + ASSERT (Pe [i] >= EMPTY && Pe [i] < n) ; 1.1657 + if (Nv [i] > 0) 1.1658 + { 1.1659 + /* this is an element */ 1.1660 + e = i ; 1.1661 + AMD_DEBUG2 ((" element, size is "ID"\n", Elen [i])) ; 1.1662 + ASSERT (Elen [e] > 0) ; 1.1663 + } 1.1664 + AMD_DEBUG2 (("\n")) ; 1.1665 + } 1.1666 + AMD_DEBUG2 (("\nelements:\n")) ; 1.1667 + for (e = 0 ; e < n ; e++) 1.1668 + { 1.1669 + if (Nv [e] > 0) 1.1670 + { 1.1671 + AMD_DEBUG3 (("Element e= "ID" size "ID" nv "ID" \n", e, 1.1672 + Elen [e], Nv [e])) ; 1.1673 + } 1.1674 + } 1.1675 + AMD_DEBUG2 (("\nvariables:\n")) ; 1.1676 + for (i = 0 ; i < n ; i++) 1.1677 + { 1.1678 + Int cnt ; 1.1679 + if (Nv [i] == 0) 1.1680 + { 1.1681 + AMD_DEBUG3 (("i unordered: "ID"\n", i)) ; 1.1682 + j = Pe [i] ; 1.1683 + cnt = 0 ; 1.1684 + AMD_DEBUG3 ((" j: "ID"\n", j)) ; 1.1685 + if (j == EMPTY) 1.1686 + { 1.1687 + AMD_DEBUG3 ((" i is a dense variable\n")) ; 1.1688 + } 1.1689 + else 1.1690 + { 1.1691 + ASSERT (j >= 0 && j < n) ; 1.1692 + while (Nv [j] == 0) 1.1693 + { 1.1694 + AMD_DEBUG3 ((" j : "ID"\n", j)) ; 1.1695 + j = Pe [j] ; 1.1696 + AMD_DEBUG3 ((" j:: "ID"\n", j)) ; 1.1697 + cnt++ ; 1.1698 + if (cnt > n) break ; 1.1699 + } 1.1700 + e = j ; 1.1701 + AMD_DEBUG3 ((" got to e: "ID"\n", e)) ; 1.1702 + } 1.1703 + } 1.1704 + } 1.1705 +#endif 1.1706 + 1.1707 +/* ========================================================================= */ 1.1708 +/* compress the paths of the variables */ 1.1709 +/* ========================================================================= */ 1.1710 + 1.1711 + for (i = 0 ; i < n ; i++) 1.1712 + { 1.1713 + if (Nv [i] == 0) 1.1714 + { 1.1715 + 1.1716 + /* ------------------------------------------------------------- 1.1717 + * i is an un-ordered row. Traverse the tree from i until 1.1718 + * reaching an element, e. The element, e, was the principal 1.1719 + * supervariable of i and all nodes in the path from i to when e 1.1720 + * was selected as pivot. 1.1721 + * ------------------------------------------------------------- */ 1.1722 + 1.1723 + AMD_DEBUG1 (("Path compression, i unordered: "ID"\n", i)) ; 1.1724 + j = Pe [i] ; 1.1725 + ASSERT (j >= EMPTY && j < n) ; 1.1726 + AMD_DEBUG3 ((" j: "ID"\n", j)) ; 1.1727 + if (j == EMPTY) 1.1728 + { 1.1729 + /* Skip a dense variable. It has no parent. */ 1.1730 + AMD_DEBUG3 ((" i is a dense variable\n")) ; 1.1731 + continue ; 1.1732 + } 1.1733 + 1.1734 + /* while (j is a variable) */ 1.1735 + while (Nv [j] == 0) 1.1736 + { 1.1737 + AMD_DEBUG3 ((" j : "ID"\n", j)) ; 1.1738 + j = Pe [j] ; 1.1739 + AMD_DEBUG3 ((" j:: "ID"\n", j)) ; 1.1740 + ASSERT (j >= 0 && j < n) ; 1.1741 + } 1.1742 + /* got to an element e */ 1.1743 + e = j ; 1.1744 + AMD_DEBUG3 (("got to e: "ID"\n", e)) ; 1.1745 + 1.1746 + /* ------------------------------------------------------------- 1.1747 + * traverse the path again from i to e, and compress the path 1.1748 + * (all nodes point to e). Path compression allows this code to 1.1749 + * compute in O(n) time. 1.1750 + * ------------------------------------------------------------- */ 1.1751 + 1.1752 + j = i ; 1.1753 + /* while (j is a variable) */ 1.1754 + while (Nv [j] == 0) 1.1755 + { 1.1756 + jnext = Pe [j] ; 1.1757 + AMD_DEBUG3 (("j "ID" jnext "ID"\n", j, jnext)) ; 1.1758 + Pe [j] = e ; 1.1759 + j = jnext ; 1.1760 + ASSERT (j >= 0 && j < n) ; 1.1761 + } 1.1762 + } 1.1763 + } 1.1764 + 1.1765 +/* ========================================================================= */ 1.1766 +/* postorder the assembly tree */ 1.1767 +/* ========================================================================= */ 1.1768 + 1.1769 + AMD_postorder (n, Pe, Nv, Elen, 1.1770 + W, /* output order */ 1.1771 + Head, Next, Last) ; /* workspace */ 1.1772 + 1.1773 +/* ========================================================================= */ 1.1774 +/* compute output permutation and inverse permutation */ 1.1775 +/* ========================================================================= */ 1.1776 + 1.1777 + /* W [e] = k means that element e is the kth element in the new 1.1778 + * order. e is in the range 0 to n-1, and k is in the range 0 to 1.1779 + * the number of elements. Use Head for inverse order. */ 1.1780 + 1.1781 + for (k = 0 ; k < n ; k++) 1.1782 + { 1.1783 + Head [k] = EMPTY ; 1.1784 + Next [k] = EMPTY ; 1.1785 + } 1.1786 + for (e = 0 ; e < n ; e++) 1.1787 + { 1.1788 + k = W [e] ; 1.1789 + ASSERT ((k == EMPTY) == (Nv [e] == 0)) ; 1.1790 + if (k != EMPTY) 1.1791 + { 1.1792 + ASSERT (k >= 0 && k < n) ; 1.1793 + Head [k] = e ; 1.1794 + } 1.1795 + } 1.1796 + 1.1797 + /* construct output inverse permutation in Next, 1.1798 + * and permutation in Last */ 1.1799 + nel = 0 ; 1.1800 + for (k = 0 ; k < n ; k++) 1.1801 + { 1.1802 + e = Head [k] ; 1.1803 + if (e == EMPTY) break ; 1.1804 + ASSERT (e >= 0 && e < n && Nv [e] > 0) ; 1.1805 + Next [e] = nel ; 1.1806 + nel += Nv [e] ; 1.1807 + } 1.1808 + ASSERT (nel == n - ndense) ; 1.1809 + 1.1810 + /* order non-principal variables (dense, & those merged into supervar's) */ 1.1811 + for (i = 0 ; i < n ; i++) 1.1812 + { 1.1813 + if (Nv [i] == 0) 1.1814 + { 1.1815 + e = Pe [i] ; 1.1816 + ASSERT (e >= EMPTY && e < n) ; 1.1817 + if (e != EMPTY) 1.1818 + { 1.1819 + /* This is an unordered variable that was merged 1.1820 + * into element e via supernode detection or mass 1.1821 + * elimination of i when e became the pivot element. 1.1822 + * Place i in order just before e. */ 1.1823 + ASSERT (Next [i] == EMPTY && Nv [e] > 0) ; 1.1824 + Next [i] = Next [e] ; 1.1825 + Next [e]++ ; 1.1826 + } 1.1827 + else 1.1828 + { 1.1829 + /* This is a dense unordered variable, with no parent. 1.1830 + * Place it last in the output order. */ 1.1831 + Next [i] = nel++ ; 1.1832 + } 1.1833 + } 1.1834 + } 1.1835 + ASSERT (nel == n) ; 1.1836 + 1.1837 + AMD_DEBUG2 (("\n\nPerm:\n")) ; 1.1838 + for (i = 0 ; i < n ; i++) 1.1839 + { 1.1840 + k = Next [i] ; 1.1841 + ASSERT (k >= 0 && k < n) ; 1.1842 + Last [k] = i ; 1.1843 + AMD_DEBUG2 ((" perm ["ID"] = "ID"\n", k, i)) ; 1.1844 + } 1.1845 +}