Blender  V2.59
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 
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 }