Blender V2.61 - r43446

get_perm_c.c

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