|
Blender
V2.59
|
00001 00004 /* 00005 * -- SuperLU routine (version 2.0) -- 00006 * Univ. of California Berkeley, Xerox Palo Alto Research Center, 00007 * and Lawrence Berkeley National Lab. 00008 * November 15, 1997 00009 * 00010 */ 00011 00012 #include "ssp_defs.h" 00013 #include "colamd.h" 00014 00015 extern int genmmd_(int *, int *, int *, int *, int *, int *, int *, 00016 int *, int *, int *, int *, int *); 00017 00018 static void 00019 get_colamd( 00020 const int m, /* number of rows in matrix A. */ 00021 const int n, /* number of columns in matrix A. */ 00022 const int nnz,/* number of nonzeros in matrix A. */ 00023 int *colptr, /* column pointer of size n+1 for matrix A. */ 00024 int *rowind, /* row indices of size nz for matrix A. */ 00025 int *perm_c /* out - the column permutation vector. */ 00026 ) 00027 { 00028 int Alen, *A, i, info, *p; 00029 double *knobs; 00030 00031 Alen = colamd_recommended(nnz, m, n); 00032 00033 if ( !(knobs = (double *) SUPERLU_MALLOC(COLAMD_KNOBS * sizeof(double))) ) 00034 ABORT("Malloc fails for knobs"); 00035 colamd_set_defaults(knobs); 00036 00037 if (!(A = (int *) SUPERLU_MALLOC(Alen * sizeof(int))) ) 00038 ABORT("Malloc fails for A[]"); 00039 if (!(p = (int *) SUPERLU_MALLOC((n+1) * sizeof(int))) ) 00040 ABORT("Malloc fails for p[]"); 00041 for (i = 0; i <= n; ++i) p[i] = colptr[i]; 00042 for (i = 0; i < nnz; ++i) A[i] = rowind[i]; 00043 info = colamd(m, n, Alen, A, p, knobs); 00044 if ( info == FALSE ) ABORT("COLAMD failed"); 00045 00046 for (i = 0; i < n; ++i) perm_c[p[i]] = i; 00047 00048 SUPERLU_FREE(knobs); 00049 SUPERLU_FREE(A); 00050 SUPERLU_FREE(p); 00051 } 00052 00053 static void 00054 getata( 00055 const int m, /* number of rows in matrix A. */ 00056 const int n, /* number of columns in matrix A. */ 00057 const int nz, /* number of nonzeros in matrix A */ 00058 int *colptr, /* column pointer of size n+1 for matrix A. */ 00059 int *rowind, /* row indices of size nz for matrix A. */ 00060 int *atanz, /* out - on exit, returns the actual number of 00061 nonzeros in matrix A'*A. */ 00062 int **ata_colptr, /* out - size n+1 */ 00063 int **ata_rowind /* out - size *atanz */ 00064 ) 00065 /* 00066 * Purpose 00067 * ======= 00068 * 00069 * Form the structure of A'*A. A is an m-by-n matrix in column oriented 00070 * format represented by (colptr, rowind). The output A'*A is in column 00071 * oriented format (symmetrically, also row oriented), represented by 00072 * (ata_colptr, ata_rowind). 00073 * 00074 * This routine is modified from GETATA routine by Tim Davis. 00075 * The complexity of this algorithm is: SUM_{i=1,m} r(i)^2, 00076 * i.e., the sum of the square of the row counts. 00077 * 00078 * Questions 00079 * ========= 00080 * o Do I need to withhold the *dense* rows? 00081 * o How do I know the number of nonzeros in A'*A? 00082 * 00083 */ 00084 { 00085 register int i, j, k, col, num_nz, ti, trow; 00086 int *marker, *b_colptr, *b_rowind; 00087 int *t_colptr, *t_rowind; /* a column oriented form of T = A' */ 00088 00089 if ( !(marker = (int*) SUPERLU_MALLOC((SUPERLU_MAX(m,n)+1)*sizeof(int))) ) 00090 ABORT("SUPERLU_MALLOC fails for marker[]"); 00091 if ( !(t_colptr = (int*) SUPERLU_MALLOC((m+1) * sizeof(int))) ) 00092 ABORT("SUPERLU_MALLOC t_colptr[]"); 00093 if ( !(t_rowind = (int*) SUPERLU_MALLOC(nz * sizeof(int))) ) 00094 ABORT("SUPERLU_MALLOC fails for t_rowind[]"); 00095 00096 00097 /* Get counts of each column of T, and set up column pointers */ 00098 for (i = 0; i < m; ++i) marker[i] = 0; 00099 for (j = 0; j < n; ++j) { 00100 for (i = colptr[j]; i < colptr[j+1]; ++i) 00101 ++marker[rowind[i]]; 00102 } 00103 t_colptr[0] = 0; 00104 for (i = 0; i < m; ++i) { 00105 t_colptr[i+1] = t_colptr[i] + marker[i]; 00106 marker[i] = t_colptr[i]; 00107 } 00108 00109 /* Transpose the matrix from A to T */ 00110 for (j = 0; j < n; ++j) 00111 for (i = colptr[j]; i < colptr[j+1]; ++i) { 00112 col = rowind[i]; 00113 t_rowind[marker[col]] = j; 00114 ++marker[col]; 00115 } 00116 00117 00118 /* ---------------------------------------------------------------- 00119 compute B = T * A, where column j of B is: 00120 00121 Struct (B_*j) = UNION ( Struct (T_*k) ) 00122 A_kj != 0 00123 00124 do not include the diagonal entry 00125 00126 ( Partition A as: A = (A_*1, ..., A_*n) 00127 Then B = T * A = (T * A_*1, ..., T * A_*n), where 00128 T * A_*j = (T_*1, ..., T_*m) * A_*j. ) 00129 ---------------------------------------------------------------- */ 00130 00131 /* Zero the diagonal flag */ 00132 for (i = 0; i < n; ++i) marker[i] = -1; 00133 00134 /* First pass determines number of nonzeros in B */ 00135 num_nz = 0; 00136 for (j = 0; j < n; ++j) { 00137 /* Flag the diagonal so it's not included in the B matrix */ 00138 marker[j] = j; 00139 00140 for (i = colptr[j]; i < colptr[j+1]; ++i) { 00141 /* A_kj is nonzero, add pattern of column T_*k to B_*j */ 00142 k = rowind[i]; 00143 for (ti = t_colptr[k]; ti < t_colptr[k+1]; ++ti) { 00144 trow = t_rowind[ti]; 00145 if ( marker[trow] != j ) { 00146 marker[trow] = j; 00147 num_nz++; 00148 } 00149 } 00150 } 00151 } 00152 *atanz = num_nz; 00153 00154 /* Allocate storage for A'*A */ 00155 if ( !(*ata_colptr = (int*) SUPERLU_MALLOC( (n+1) * sizeof(int)) ) ) 00156 ABORT("SUPERLU_MALLOC fails for ata_colptr[]"); 00157 if ( *atanz ) { 00158 if ( !(*ata_rowind = (int*) SUPERLU_MALLOC( *atanz * sizeof(int)) ) ) 00159 ABORT("SUPERLU_MALLOC fails for ata_rowind[]"); 00160 } 00161 b_colptr = *ata_colptr; /* aliasing */ 00162 b_rowind = *ata_rowind; 00163 00164 /* Zero the diagonal flag */ 00165 for (i = 0; i < n; ++i) marker[i] = -1; 00166 00167 /* Compute each column of B, one at a time */ 00168 num_nz = 0; 00169 for (j = 0; j < n; ++j) { 00170 b_colptr[j] = num_nz; 00171 00172 /* Flag the diagonal so it's not included in the B matrix */ 00173 marker[j] = j; 00174 00175 for (i = colptr[j]; i < colptr[j+1]; ++i) { 00176 /* A_kj is nonzero, add pattern of column T_*k to B_*j */ 00177 k = rowind[i]; 00178 for (ti = t_colptr[k]; ti < t_colptr[k+1]; ++ti) { 00179 trow = t_rowind[ti]; 00180 if ( marker[trow] != j ) { 00181 marker[trow] = j; 00182 b_rowind[num_nz++] = trow; 00183 } 00184 } 00185 } 00186 } 00187 b_colptr[n] = num_nz; 00188 00189 SUPERLU_FREE(marker); 00190 SUPERLU_FREE(t_colptr); 00191 SUPERLU_FREE(t_rowind); 00192 } 00193 00194 00195 static void 00196 at_plus_a( 00197 const int n, /* number of columns in matrix A. */ 00198 const int nz, /* number of nonzeros in matrix A */ 00199 int *colptr, /* column pointer of size n+1 for matrix A. */ 00200 int *rowind, /* row indices of size nz for matrix A. */ 00201 int *bnz, /* out - on exit, returns the actual number of 00202 nonzeros in matrix A'*A. */ 00203 int **b_colptr, /* out - size n+1 */ 00204 int **b_rowind /* out - size *bnz */ 00205 ) 00206 { 00207 /* 00208 * Purpose 00209 * ======= 00210 * 00211 * Form the structure of A'+A. A is an n-by-n matrix in column oriented 00212 * format represented by (colptr, rowind). The output A'+A is in column 00213 * oriented format (symmetrically, also row oriented), represented by 00214 * (b_colptr, b_rowind). 00215 * 00216 */ 00217 register int i, j, k, col, num_nz; 00218 int *t_colptr, *t_rowind; /* a column oriented form of T = A' */ 00219 int *marker; 00220 00221 if ( !(marker = (int*) SUPERLU_MALLOC( n * sizeof(int)) ) ) 00222 ABORT("SUPERLU_MALLOC fails for marker[]"); 00223 if ( !(t_colptr = (int*) SUPERLU_MALLOC( (n+1) * sizeof(int)) ) ) 00224 ABORT("SUPERLU_MALLOC fails for t_colptr[]"); 00225 if ( !(t_rowind = (int*) SUPERLU_MALLOC( nz * sizeof(int)) ) ) 00226 ABORT("SUPERLU_MALLOC fails t_rowind[]"); 00227 00228 00229 /* Get counts of each column of T, and set up column pointers */ 00230 for (i = 0; i < n; ++i) marker[i] = 0; 00231 for (j = 0; j < n; ++j) { 00232 for (i = colptr[j]; i < colptr[j+1]; ++i) 00233 ++marker[rowind[i]]; 00234 } 00235 t_colptr[0] = 0; 00236 for (i = 0; i < n; ++i) { 00237 t_colptr[i+1] = t_colptr[i] + marker[i]; 00238 marker[i] = t_colptr[i]; 00239 } 00240 00241 /* Transpose the matrix from A to T */ 00242 for (j = 0; j < n; ++j) 00243 for (i = colptr[j]; i < colptr[j+1]; ++i) { 00244 col = rowind[i]; 00245 t_rowind[marker[col]] = j; 00246 ++marker[col]; 00247 } 00248 00249 00250 /* ---------------------------------------------------------------- 00251 compute B = A + T, where column j of B is: 00252 00253 Struct (B_*j) = Struct (A_*k) UNION Struct (T_*k) 00254 00255 do not include the diagonal entry 00256 ---------------------------------------------------------------- */ 00257 00258 /* Zero the diagonal flag */ 00259 for (i = 0; i < n; ++i) marker[i] = -1; 00260 00261 /* First pass determines number of nonzeros in B */ 00262 num_nz = 0; 00263 for (j = 0; j < n; ++j) { 00264 /* Flag the diagonal so it's not included in the B matrix */ 00265 marker[j] = j; 00266 00267 /* Add pattern of column A_*k to B_*j */ 00268 for (i = colptr[j]; i < colptr[j+1]; ++i) { 00269 k = rowind[i]; 00270 if ( marker[k] != j ) { 00271 marker[k] = j; 00272 ++num_nz; 00273 } 00274 } 00275 00276 /* Add pattern of column T_*k to B_*j */ 00277 for (i = t_colptr[j]; i < t_colptr[j+1]; ++i) { 00278 k = t_rowind[i]; 00279 if ( marker[k] != j ) { 00280 marker[k] = j; 00281 ++num_nz; 00282 } 00283 } 00284 } 00285 *bnz = num_nz; 00286 00287 /* Allocate storage for A+A' */ 00288 if ( !(*b_colptr = (int*) SUPERLU_MALLOC( (n+1) * sizeof(int)) ) ) 00289 ABORT("SUPERLU_MALLOC fails for b_colptr[]"); 00290 if ( *bnz) { 00291 if ( !(*b_rowind = (int*) SUPERLU_MALLOC( *bnz * sizeof(int)) ) ) 00292 ABORT("SUPERLU_MALLOC fails for b_rowind[]"); 00293 } 00294 00295 /* Zero the diagonal flag */ 00296 for (i = 0; i < n; ++i) marker[i] = -1; 00297 00298 /* Compute each column of B, one at a time */ 00299 num_nz = 0; 00300 for (j = 0; j < n; ++j) { 00301 (*b_colptr)[j] = num_nz; 00302 00303 /* Flag the diagonal so it's not included in the B matrix */ 00304 marker[j] = j; 00305 00306 /* Add pattern of column A_*k to B_*j */ 00307 for (i = colptr[j]; i < colptr[j+1]; ++i) { 00308 k = rowind[i]; 00309 if ( marker[k] != j ) { 00310 marker[k] = j; 00311 (*b_rowind)[num_nz++] = k; 00312 } 00313 } 00314 00315 /* Add pattern of column T_*k to B_*j */ 00316 for (i = t_colptr[j]; i < t_colptr[j+1]; ++i) { 00317 k = t_rowind[i]; 00318 if ( marker[k] != j ) { 00319 marker[k] = j; 00320 (*b_rowind)[num_nz++] = k; 00321 } 00322 } 00323 } 00324 (*b_colptr)[n] = num_nz; 00325 00326 SUPERLU_FREE(marker); 00327 SUPERLU_FREE(t_colptr); 00328 SUPERLU_FREE(t_rowind); 00329 } 00330 00331 void 00332 get_perm_c(int ispec, SuperMatrix *A, int *perm_c) 00333 /* 00334 * Purpose 00335 * ======= 00336 * 00337 * GET_PERM_C obtains a permutation matrix Pc, by applying the multiple 00338 * minimum degree ordering code by Joseph Liu to matrix A'*A or A+A'. 00339 * or using approximate minimum degree column ordering by Davis et. al. 00340 * The LU factorization of A*Pc tends to have less fill than the LU 00341 * factorization of A. 00342 * 00343 * Arguments 00344 * ========= 00345 * 00346 * ispec (input) int 00347 * Specifies the type of column ordering to reduce fill: 00348 * = 1: minimum degree on the structure of A^T * A 00349 * = 2: minimum degree on the structure of A^T + A 00350 * = 3: approximate minimum degree for unsymmetric matrices 00351 * If ispec == 0, the natural ordering (i.e., Pc = I) is returned. 00352 * 00353 * A (input) SuperMatrix* 00354 * Matrix A in A*X=B, of dimension (A->nrow, A->ncol). The number 00355 * of the linear equations is A->nrow. Currently, the type of A 00356 * can be: Stype = NC; Dtype = _D; Mtype = GE. In the future, 00357 * more general A can be handled. 00358 * 00359 * perm_c (output) int* 00360 * Column permutation vector of size A->ncol, which defines the 00361 * permutation matrix Pc; perm_c[i] = j means column i of A is 00362 * in position j in A*Pc. 00363 * 00364 */ 00365 { 00366 NCformat *Astore = A->Store; 00367 int m, n, bnz, *b_colptr, i; 00368 int delta, maxint, nofsub, *invp; 00369 int *b_rowind, *dhead, *qsize, *llist, *marker; 00370 double t, SuperLU_timer_(); 00371 00372 /* make gcc happy */ 00373 b_rowind=NULL; 00374 b_colptr=NULL; 00375 00376 m = A->nrow; 00377 n = A->ncol; 00378 00379 t = SuperLU_timer_(); 00380 switch ( ispec ) { 00381 case 0: /* Natural ordering */ 00382 for (i = 0; i < n; ++i) perm_c[i] = i; 00383 #if ( PRNTlevel>=1 ) 00384 printf("Use natural column ordering.\n"); 00385 #endif 00386 return; 00387 case 1: /* Minimum degree ordering on A'*A */ 00388 getata(m, n, Astore->nnz, Astore->colptr, Astore->rowind, 00389 &bnz, &b_colptr, &b_rowind); 00390 #if ( PRNTlevel>=1 ) 00391 printf("Use minimum degree ordering on A'*A.\n"); 00392 #endif 00393 t = SuperLU_timer_() - t; 00394 /*printf("Form A'*A time = %8.3f\n", t);*/ 00395 break; 00396 case 2: /* Minimum degree ordering on A'+A */ 00397 if ( m != n ) ABORT("Matrix is not square"); 00398 at_plus_a(n, Astore->nnz, Astore->colptr, Astore->rowind, 00399 &bnz, &b_colptr, &b_rowind); 00400 #if ( PRNTlevel>=1 ) 00401 printf("Use minimum degree ordering on A'+A.\n"); 00402 #endif 00403 t = SuperLU_timer_() - t; 00404 /*printf("Form A'+A time = %8.3f\n", t);*/ 00405 break; 00406 case 3: /* Approximate minimum degree column ordering. */ 00407 get_colamd(m, n, Astore->nnz, Astore->colptr, Astore->rowind, 00408 perm_c); 00409 #if ( PRNTlevel>=1 ) 00410 printf(".. Use approximate minimum degree column ordering.\n"); 00411 #endif 00412 return; 00413 default: 00414 ABORT("Invalid ISPEC"); 00415 return; 00416 } 00417 00418 if ( bnz != 0 ) { 00419 t = SuperLU_timer_(); 00420 00421 /* Initialize and allocate storage for GENMMD. */ 00422 delta = 1; /* DELTA is a parameter to allow the choice of nodes 00423 whose degree <= min-degree + DELTA. */ 00424 maxint = 2147483647; /* 2**31 - 1 */ 00425 invp = (int *) SUPERLU_MALLOC((n+delta)*sizeof(int)); 00426 if ( !invp ) ABORT("SUPERLU_MALLOC fails for invp."); 00427 dhead = (int *) SUPERLU_MALLOC((n+delta)*sizeof(int)); 00428 if ( !dhead ) ABORT("SUPERLU_MALLOC fails for dhead."); 00429 qsize = (int *) SUPERLU_MALLOC((n+delta)*sizeof(int)); 00430 if ( !qsize ) ABORT("SUPERLU_MALLOC fails for qsize."); 00431 llist = (int *) SUPERLU_MALLOC(n*sizeof(int)); 00432 if ( !llist ) ABORT("SUPERLU_MALLOC fails for llist."); 00433 marker = (int *) SUPERLU_MALLOC(n*sizeof(int)); 00434 if ( !marker ) ABORT("SUPERLU_MALLOC fails for marker."); 00435 00436 /* Transform adjacency list into 1-based indexing required by GENMMD.*/ 00437 for (i = 0; i <= n; ++i) ++b_colptr[i]; 00438 for (i = 0; i < bnz; ++i) ++b_rowind[i]; 00439 00440 genmmd_(&n, b_colptr, b_rowind, perm_c, invp, &delta, dhead, 00441 qsize, llist, marker, &maxint, &nofsub); 00442 00443 /* Transform perm_c into 0-based indexing. */ 00444 for (i = 0; i < n; ++i) --perm_c[i]; 00445 00446 SUPERLU_FREE(b_colptr); 00447 SUPERLU_FREE(b_rowind); 00448 SUPERLU_FREE(invp); 00449 SUPERLU_FREE(dhead); 00450 SUPERLU_FREE(qsize); 00451 SUPERLU_FREE(llist); 00452 SUPERLU_FREE(marker); 00453 00454 t = SuperLU_timer_() - t; 00455 /* printf("call GENMMD time = %8.3f\n", t);*/ 00456 00457 } else { /* Empty adjacency structure */ 00458 for (i = 0; i < n; ++i) perm_c[i] = i; 00459 } 00460 00461 }