Beispiel #1
0
/*! \brief
 *
 * <pre>
 * Purpose
 * =======
 *
 * sp_preorder() permutes the columns of the original matrix. It performs
 * the following steps:
 *
 *    1. Apply column permutation perm_c[] to A's column pointers to form AC;
 *
 *    2. If options->Fact = DOFACT, then
 *       (1) Compute column elimination tree etree[] of AC'AC;
 *       (2) Post order etree[] to get a postordered elimination tree etree[],
 *           and a postorder permutation post[];
 *       (3) Apply post[] permutation to columns of AC;
 *       (4) Overwrite perm_c[] with the product perm_c * post.
 *
 * Arguments
 * =========
 *
 * options (input) superlu_options_t*
 *         Specifies whether or not the elimination tree will be re-used.
 *         If options->Fact == DOFACT, this means first time factor A, 
 *         etree is computed, postered, and output.
 *         Otherwise, re-factor A, etree is input, unchanged on exit.
 *
 * A       (input) SuperMatrix*
 *         Matrix A in A*X=B, of dimension (A->nrow, A->ncol). The number
 *         of the linear equations is A->nrow. Currently, the type of A can be:
 *         Stype = NC or SLU_NCP; Mtype = SLU_GE.
 *         In the future, more general A may be handled.
 *
 * perm_c  (input/output) int*
 *	   Column permutation vector of size A->ncol, which defines the 
 *         permutation matrix Pc; perm_c[i] = j means column i of A is 
 *         in position j in A*Pc.
 *         If options->Fact == DOFACT, perm_c is both input and output.
 *         On output, it is changed according to a postorder of etree.
 *         Otherwise, perm_c is input.
 *
 * etree   (input/output) int*
 *         Elimination tree of Pc'*A'*A*Pc, dimension A->ncol.
 *         If options->Fact == DOFACT, etree is an output argument,
 *         otherwise it is an input argument.
 *         Note: etree is a vector of parent pointers for a forest whose
 *         vertices are the integers 0 to A->ncol-1; etree[root]==A->ncol.
 *
 * AC      (output) SuperMatrix*
 *         The resulting matrix after applied the column permutation
 *         perm_c[] to matrix A. The type of AC can be:
 *         Stype = SLU_NCP; Dtype = A->Dtype; Mtype = SLU_GE.
 * </pre>
 */
void
sp_preorder(superlu_options_t *options,  SuperMatrix *A, int *perm_c, 
	    int *etree, SuperMatrix *AC)
{
    NCformat  *Astore;
    NCPformat *ACstore;
    int       *iwork, *post;
    register  int n, i;

    n = A->ncol;
    
    /* Apply column permutation perm_c to A's column pointers so to
       obtain NCP format in AC = A*Pc.  */
    AC->Stype       = SLU_NCP;
    AC->Dtype       = A->Dtype;
    AC->Mtype       = A->Mtype;
    AC->nrow        = A->nrow;
    AC->ncol        = A->ncol;
    Astore          = A->Store;
    ACstore = AC->Store = (void *) SUPERLU_MALLOC( sizeof(NCPformat) );
    if ( !ACstore ) ABORT("SUPERLU_MALLOC fails for ACstore");
    ACstore->nnz    = Astore->nnz;
    ACstore->nzval  = Astore->nzval;
    ACstore->rowind = Astore->rowind;
    ACstore->colbeg = (int*) SUPERLU_MALLOC(n*sizeof(int));
    if ( !(ACstore->colbeg) ) ABORT("SUPERLU_MALLOC fails for ACstore->colbeg");
    ACstore->colend = (int*) SUPERLU_MALLOC(n*sizeof(int));
    if ( !(ACstore->colend) ) ABORT("SUPERLU_MALLOC fails for ACstore->colend");

#ifdef DEBUG
    print_int_vec("pre_order:", n, perm_c);
    check_perm("Initial perm_c", n, perm_c);
#endif      

    for (i = 0; i < n; i++) {
	ACstore->colbeg[perm_c[i]] = Astore->colptr[i]; 
	ACstore->colend[perm_c[i]] = Astore->colptr[i+1];
    }
	
    if ( options->Fact == DOFACT ) {
#undef ETREE_ATplusA
#ifdef ETREE_ATplusA
        /*--------------------------------------------
	  COMPUTE THE ETREE OF Pc*(A'+A)*Pc'.
	  --------------------------------------------*/
        int *b_colptr, *b_rowind, bnz, j;
	int *c_colbeg, *c_colend;

        /*printf("Use etree(A'+A)\n");*/

	/* Form B = A + A'. */
	at_plus_a(n, Astore->nnz, Astore->colptr, Astore->rowind,
		  &bnz, &b_colptr, &b_rowind);

	/* Form C = Pc*B*Pc'. */
	c_colbeg = (int*) SUPERLU_MALLOC(2*n*sizeof(int));
	c_colend = c_colbeg + n;
	if (!c_colbeg ) ABORT("SUPERLU_MALLOC fails for c_colbeg/c_colend");
	for (i = 0; i < n; i++) {
	    c_colbeg[perm_c[i]] = b_colptr[i]; 
  	    c_colend[perm_c[i]] = b_colptr[i+1];
	}
	for (j = 0; j < n; ++j) {
	    for (i = c_colbeg[j]; i < c_colend[j]; ++i) {
	        b_rowind[i] = perm_c[b_rowind[i]];
	    }
	}

	/* Compute etree of C. */
	sp_symetree(c_colbeg, c_colend, b_rowind, n, etree);

	SUPERLU_FREE(b_colptr);
	if ( bnz ) SUPERLU_FREE(b_rowind);
	SUPERLU_FREE(c_colbeg);
	
#else
        /*--------------------------------------------
	  COMPUTE THE COLUMN ELIMINATION TREE.
	  --------------------------------------------*/
	sp_coletree(ACstore->colbeg, ACstore->colend, ACstore->rowind,
		    A->nrow, A->ncol, etree);
#endif
#ifdef DEBUG	
	print_int_vec("etree:", n, etree);
#endif	
	
	/* In symmetric mode, do not do postorder here. */
	if ( options->SymmetricMode == NO ) {
	    /* Post order etree */
	    post = (int *) TreePostorder(n, etree);
	    /* for (i = 0; i < n+1; ++i) inv_post[post[i]] = i;
	       iwork = post; */

#ifdef DEBUG
	    print_int_vec("post:", n+1, post);
	    check_perm("post", n, post);	
#endif	
	    iwork = (int*) SUPERLU_MALLOC((n+1)*sizeof(int)); 
	    if ( !iwork ) ABORT("SUPERLU_MALLOC fails for iwork[]");

	    /* Renumber etree in postorder */
	    for (i = 0; i < n; ++i) iwork[post[i]] = post[etree[i]];
	    for (i = 0; i < n; ++i) etree[i] = iwork[i];

#ifdef DEBUG	
	    print_int_vec("postorder etree:", n, etree);
#endif
	
	    /* Postmultiply A*Pc by post[] */
	    for (i = 0; i < n; ++i) iwork[post[i]] = ACstore->colbeg[i];
	    for (i = 0; i < n; ++i) ACstore->colbeg[i] = iwork[i];
	    for (i = 0; i < n; ++i) iwork[post[i]] = ACstore->colend[i];
	    for (i = 0; i < n; ++i) ACstore->colend[i] = iwork[i];

	    for (i = 0; i < n; ++i)
	        iwork[i] = post[perm_c[i]];  /* product of perm_c and post */
	    for (i = 0; i < n; ++i) perm_c[i] = iwork[i];

#ifdef DEBUG
	    print_int_vec("Pc*post:", n, perm_c);
	    check_perm("final perm_c", n, perm_c);	
#endif
	    SUPERLU_FREE (post);
	    SUPERLU_FREE (iwork);
	} /* end postordering */

    } /* if options->Fact == DOFACT ... */

}
Beispiel #2
0
void
get_perm_c(int ispec, SuperMatrix *A, int *perm_c)
/*
 * Purpose
 * =======
 *
 * GET_PERM_C obtains a permutation matrix Pc, by applying the multiple
 * minimum degree ordering code by Joseph Liu to matrix A'*A or A+A'.
 * or using approximate minimum degree column ordering by Davis et. al.
 * The LU factorization of A*Pc tends to have less fill than the LU 
 * factorization of A.
 *
 * Arguments
 * =========
 *
 * ispec   (input) int
 *         Specifies the type of column ordering to reduce fill:
 *         = 1: minimum degree on the structure of A^T * A
 *         = 2: minimum degree on the structure of A^T + A
 *         = 3: approximate minimum degree for unsymmetric matrices
 *         If ispec == 0, the natural ordering (i.e., Pc = I) is returned.
 * 
 * A       (input) SuperMatrix*
 *         Matrix A in A*X=B, of dimension (A->nrow, A->ncol). The number
 *         of the linear equations is A->nrow. Currently, the type of A 
 *         can be: Stype = NC; Dtype = _D; Mtype = GE. In the future,
 *         more general A can be handled.
 *
 * perm_c  (output) int*
 *	   Column permutation vector of size A->ncol, which defines the 
 *         permutation matrix Pc; perm_c[i] = j means column i of A is 
 *         in position j in A*Pc.
 *
 */
{
    NCformat *Astore = A->Store;
    int m, n, bnz = 0, *b_colptr, i;
    int delta, maxint, nofsub, *invp;
    int *b_rowind, *dhead, *qsize, *llist, *marker;
    double t, SuperLU_timer_();
    
    m = A->nrow;
    n = A->ncol;

    t = SuperLU_timer_();
    switch ( ispec ) {
        case 0: /* Natural ordering */
	      for (i = 0; i < n; ++i) perm_c[i] = i;
#if ( PRNTlevel>=1 )
	      printf("Use natural column ordering.\n");
#endif
	      return;
        case 1: /* Minimum degree ordering on A'*A */
	      getata(m, n, Astore->nnz, Astore->colptr, Astore->rowind,
		     &bnz, &b_colptr, &b_rowind);
#if ( PRNTlevel>=1 )
	      printf("Use minimum degree ordering on A'*A.\n");
#endif
	      t = SuperLU_timer_() - t;
	      /*printf("Form A'*A time = %8.3f\n", t);*/
	      break;
        case 2: /* Minimum degree ordering on A'+A */
	      if ( m != n ) ABORT("Matrix is not square");
	      at_plus_a(n, Astore->nnz, Astore->colptr, Astore->rowind,
			&bnz, &b_colptr, &b_rowind);
#if ( PRNTlevel>=1 )
	      printf("Use minimum degree ordering on A'+A.\n");
#endif
	      t = SuperLU_timer_() - t;
	      /*printf("Form A'+A time = %8.3f\n", t);*/
	      break;
        case 3: /* Approximate minimum degree column ordering. */
	      get_colamd(m, n, Astore->nnz, Astore->colptr, Astore->rowind,
			 perm_c);
#if ( PRNTlevel>=1 )
	      printf(".. Use approximate minimum degree column ordering.\n");
#endif
	      return; 
        default:
	      ABORT("Invalid ISPEC");
    }

    if ( bnz != 0 ) {
	t = SuperLU_timer_();

	/* Initialize and allocate storage for GENMMD. */
	delta = 1; /* DELTA is a parameter to allow the choice of nodes
		      whose degree <= min-degree + DELTA. */
	maxint = 2147483647; /* 2**31 - 1 */
	invp = (int *) SUPERLU_MALLOC((n+delta)*sizeof(int));
	if ( !invp ) ABORT("SUPERLU_MALLOC fails for invp.");
	dhead = (int *) SUPERLU_MALLOC((n+delta)*sizeof(int));
	if ( !dhead ) ABORT("SUPERLU_MALLOC fails for dhead.");
	qsize = (int *) SUPERLU_MALLOC((n+delta)*sizeof(int));
	if ( !qsize ) ABORT("SUPERLU_MALLOC fails for qsize.");
	llist = (int *) SUPERLU_MALLOC(n*sizeof(int));
	if ( !llist ) ABORT("SUPERLU_MALLOC fails for llist.");
	marker = (int *) SUPERLU_MALLOC(n*sizeof(int));
	if ( !marker ) ABORT("SUPERLU_MALLOC fails for marker.");

	/* Transform adjacency list into 1-based indexing required by GENMMD.*/
	for (i = 0; i <= n; ++i) ++b_colptr[i];
	for (i = 0; i < bnz; ++i) ++b_rowind[i];
	
	genmmd_(&n, b_colptr, b_rowind, perm_c, invp, &delta, dhead, 
		qsize, llist, marker, &maxint, &nofsub);

	/* Transform perm_c into 0-based indexing. */
	for (i = 0; i < n; ++i) --perm_c[i];

	SUPERLU_FREE(invp);
	SUPERLU_FREE(dhead);
	SUPERLU_FREE(qsize);
	SUPERLU_FREE(llist);
	SUPERLU_FREE(marker);
	SUPERLU_FREE(b_rowind);

	t = SuperLU_timer_() - t;
	/*  printf("call GENMMD time = %8.3f\n", t);*/

    } else { /* Empty adjacency structure */
	for (i = 0; i < n; ++i) perm_c[i] = i;
    }

    SUPERLU_FREE(b_colptr);
}
Beispiel #3
0
void
sp_colorder(SuperMatrix *A, int *perm_c, superlumt_options_t *options,
	    SuperMatrix *AC)
{
/*
 * -- SuperLU MT routine (version 2.0) --
 * Lawrence Berkeley National Lab, Univ. of California Berkeley,
 * and Xerox Palo Alto Research Center.
 * September 10, 2007
 *
 *
 * Purpose
 * =======
 *
 * sp_colorder() permutes the columns of the original matrix A into AC. 
 * It performs the following steps:
 *
 *    1. Apply column permutation perm_c[] to A's column pointers to form AC;
 *
 *    2. If options->refact = NO, then
 *       (1) Allocate etree[], and compute column etree etree[] of AC'AC;
 *       (2) Post order etree[] to get a postordered elimination tree etree[],
 *           and a postorder permutation post[];
 *       (3) Apply post[] permutation to columns of AC;
 *       (4) Overwrite perm_c[] with the product perm_c * post.
 *       (5) Allocate storage, and compute the column count (colcnt_h) and the
 *           supernode partition (part_super_h) for the Householder matrix H.
 *
 * Arguments
 * =========
 *
 * A      (input) SuperMatrix*
 *        Matrix A in A*X=B, of dimension (A->nrow, A->ncol). The number
 *        of the linear equations is A->nrow. Currently, the type of A can be:
 *        Stype = NC or NCP; Dtype = _D; Mtype = GE.
 *
 * perm_c (input/output) int*
 *	  Column permutation vector of size A->ncol, which defines the 
 *        permutation matrix Pc; perm_c[i] = j means column i of A is 
 *        in position j in A*Pc.
 *
 * options (input/output) superlumt_options_t*
 *        If options->refact = YES, then options is an
 *        input argument. The arrays etree[], colcnt_h[] and part_super_h[]
 *        are available from a previous factor and will be re-used.
 *        If options->refact = NO, then options is an output argument. 
 *
 * AC     (output) SuperMatrix*
 *        The resulting matrix after applied the column permutation
 *        perm_c[] to matrix A. The type of AC can be:
 *        Stype = NCP; Dtype = _D; Mtype = GE.
 *
 */

    NCformat  *Astore;
    NCPformat *ACstore;
    int i, n, nnz, nlnz;
    yes_no_t  refact = options->refact;
    int *etree;
    int *colcnt_h;
    int *part_super_h;
    int *iwork, *post, *iperm;
    int *invp;
    int *part_super_ata;

    extern void at_plus_a(const int, const int,	int *, int *,
			  int *, int **, int **, int);

    n     = A->ncol;
    iwork = intMalloc(n+1);
    part_super_ata = intMalloc(n);
    
    /* Apply column permutation perm_c to A's column pointers so to
       obtain NCP format in AC = A*Pc.  */
    AC->Stype       = SLU_NCP;
    AC->Dtype       = A->Dtype;
    AC->Mtype       = A->Mtype;
    AC->nrow        = A->nrow;
    AC->ncol        = A->ncol;
    Astore          = A->Store;
    ACstore = AC->Store = (void *) malloc( sizeof(NCPformat) );
    ACstore->nnz    = Astore->nnz;
    ACstore->nzval  = Astore->nzval;
    ACstore->rowind = Astore->rowind;
    ACstore->colbeg = intMalloc(n);
    ACstore->colend = intMalloc(n);
    nnz             = Astore->nnz;

#ifdef CHK_COLORDER
    print_int_vec("pre_order:", n, perm_c);
    dcheck_perm("Initial perm_c", n, perm_c);
#endif      

    for (i = 0; i < n; i++) {
	ACstore->colbeg[perm_c[i]] = Astore->colptr[i]; 
	ACstore->colend[perm_c[i]] = Astore->colptr[i+1];
    }
	
    if ( refact == NO ) {
	int *b_colptr, *b_rowind, bnz, j;
	
	options->etree = etree = intMalloc(n);
	options->colcnt_h = colcnt_h = intMalloc(n);
	options->part_super_h = part_super_h = intMalloc(n);
	
	if ( options->SymmetricMode ) {
	    /* Compute the etree of C = Pc*(A'+A)*Pc'. */
	    int *c_colbeg, *c_colend;

	    /* Form B = A + A'. */
	    at_plus_a(n, Astore->nnz, Astore->colptr, Astore->rowind,
		      &bnz, &b_colptr, &b_rowind, 1);
	    
	    /* Form C = Pc*B*Pc'. */
	    c_colbeg = (int_t*) intMalloc(n);
	    c_colend = (int_t*) intMalloc(n);
	    if (!(c_colbeg) || !(c_colend) )
		SUPERLU_ABORT("SUPERLU_MALLOC fails for c_colbeg/c_colend");
	    for (i = 0; i < n; i++) {
		c_colbeg[perm_c[i]] = b_colptr[i]; 
		c_colend[perm_c[i]] = b_colptr[i+1];
	    }
	    for (j = 0; j < n; ++j) {
		for (i = c_colbeg[j]; i < c_colend[j]; ++i) {
		    b_rowind[i] = perm_c[b_rowind[i]];
		}
		iwork[perm_c[j]] = j; /* inverse perm_c */
	    }

	    /* Compute etree of C. */
	    sp_symetree(c_colbeg, c_colend, b_rowind, n, etree);

	    /* Restore B to be A+A', without column permutation */
	    for (i = 0; i < bnz; ++i)
		b_rowind[i] = iwork[b_rowind[i]];

	    SUPERLU_FREE(c_colbeg);
	    SUPERLU_FREE(c_colend);
	    
	} else {
	    /* Compute the column elimination tree. */
	    sp_coletree(ACstore->colbeg, ACstore->colend, ACstore->rowind,
			A->nrow, A->ncol, etree);
	}

#ifdef CHK_COLORDER	
	print_int_vec("etree:", n, etree);
#endif	

	/* Post order etree. */
	post = (int *) TreePostorder(n, etree);
	invp  = intMalloc(n);
	for (i = 0; i < n; ++i) invp[post[i]] = i;

#ifdef CHK_COLORDER
	print_int_vec("post:", n+1, post);
	dcheck_perm("post", n, post);	
#endif	

	/* Renumber etree in postorder. */
	for (i = 0; i < n; ++i) iwork[post[i]] = post[etree[i]];
	for (i = 0; i < n; ++i) etree[i] = iwork[i];

#ifdef CHK_COLORDER	
	print_int_vec("postorder etree:", n, etree);
#endif

	/* Postmultiply A*Pc by post[]. */
	for (i = 0; i < n; ++i) iwork[post[i]] = ACstore->colbeg[i];
	for (i = 0; i < n; ++i) ACstore->colbeg[i] = iwork[i];
	for (i = 0; i < n; ++i) iwork[post[i]] = ACstore->colend[i];
	for (i = 0; i < n; ++i) ACstore->colend[i] = iwork[i];

	for (i = 0; i < n; ++i)
	    iwork[i] = post[perm_c[i]];  /* product of perm_c and post */
	for (i = 0; i < n; ++i) perm_c[i] = iwork[i];
	for (i = 0; i < n; ++i) invp[perm_c[i]] = i; /* inverse of perm_c */

	iperm = post; /* alias to the same address */

#ifdef ZFD_PERM
	/* Permute the rows of AC to have zero-free diagonal. */
	printf("** Permute the rows to have zero-free diagonal....\n");
	for (i = 0; i < n; ++i)
	    iwork[i] = ACstore->colend[i] - ACstore->colbeg[i];
	zfdperm(n, nnz, ACstore->rowind, ACstore->colbeg, iwork, iperm);
#else
	for (i = 0; i < n; ++i) iperm[i] = i;
#endif	

	/* NOTE: iperm is returned as column permutation so that
	 * the diagonal is nonzero. Since a symmetric permutation
	 * preserves the diagonal, we can do the following:
	 *     P'(AP')P = P'A
	 * That is, we apply the inverse of iperm to rows of A
	 * to get zero-free diagonal. But since iperm is defined
	 * in MC21A inversely as our definition of permutation,
	 * so it is indeed an inverse for our purpose. We can
	 * apply it directly.
	 */

	if ( options->SymmetricMode ) {
	    /* Determine column count in the Cholesky factor of B = A+A' */
#if 0
	    cholnzcnt(n, Astore->colptr, Astore->rowind,
		      invp, perm_c, etree, colcnt_h, &nlnz, part_super_h);
#else
	    cholnzcnt(n, b_colptr, b_rowind,
		      invp, perm_c, etree, colcnt_h, &nlnz, part_super_h);
#endif
#if ( PRNTlevel>=1 ) 
	    printf(".. bnz %d\n", bnz);
#endif

	    SUPERLU_FREE(b_colptr);
	    if ( bnz ) SUPERLU_FREE(b_rowind);

	} else {
	    /* Determine the row and column counts in the QR factor. */
	    qrnzcnt(n, nnz, Astore->colptr, Astore->rowind, iperm,
		    invp, perm_c, etree, colcnt_h, &nlnz,
		    part_super_ata, part_super_h);
	}

#if ( PRNTlevel>=2 )
	dCheckZeroDiagonal(n, ACstore->rowind, ACstore->colbeg,
			   ACstore->colend, perm_c);
	print_int_vec("colcnt", n, colcnt_h);
	dPrintSuperPart("Hpart", n, part_super_h);
	print_int_vec("iperm", n, iperm);
#endif	
	
#ifdef CHK_COLORDER
	print_int_vec("Pc*post:", n, perm_c);
	dcheck_perm("final perm_c", n, perm_c);	
#endif

	SUPERLU_FREE (post);
	SUPERLU_FREE (invp);

    } /* if refact == NO */

    SUPERLU_FREE (iwork);
    SUPERLU_FREE (part_super_ata);
}