kusano 7d535a
/*! @file sp_preorder.c
kusano 7d535a
 * \brief Permute and performs functions on columns of orginal matrix
kusano 7d535a
 */
kusano 7d535a
#include "slu_ddefs.h"
kusano 7d535a
kusano 7d535a
kusano 7d535a
/*! \brief
kusano 7d535a
 *
kusano 7d535a
 * 
kusano 7d535a
 * Purpose
kusano 7d535a
 * =======
kusano 7d535a
 *
kusano 7d535a
 * sp_preorder() permutes the columns of the original matrix. It performs
kusano 7d535a
 * the following steps:
kusano 7d535a
 *
kusano 7d535a
 *    1. Apply column permutation perm_c[] to A's column pointers to form AC;
kusano 7d535a
 *
kusano 7d535a
 *    2. If options->Fact = DOFACT, then
kusano 7d535a
 *       (1) Compute column elimination tree etree[] of AC'AC;
kusano 7d535a
 *       (2) Post order etree[] to get a postordered elimination tree etree[],
kusano 7d535a
 *           and a postorder permutation post[];
kusano 7d535a
 *       (3) Apply post[] permutation to columns of AC;
kusano 7d535a
 *       (4) Overwrite perm_c[] with the product perm_c * post.
kusano 7d535a
 *
kusano 7d535a
 * Arguments
kusano 7d535a
 * =========
kusano 7d535a
 *
kusano 7d535a
 * options (input) superlu_options_t*
kusano 7d535a
 *         Specifies whether or not the elimination tree will be re-used.
kusano 7d535a
 *         If options->Fact == DOFACT, this means first time factor A, 
kusano 7d535a
 *         etree is computed, postered, and output.
kusano 7d535a
 *         Otherwise, re-factor A, etree is input, unchanged on exit.
kusano 7d535a
 *
kusano 7d535a
 * A       (input) SuperMatrix*
kusano 7d535a
 *         Matrix A in A*X=B, of dimension (A->nrow, A->ncol). The number
kusano 7d535a
 *         of the linear equations is A->nrow. Currently, the type of A can be:
kusano 7d535a
 *         Stype = NC or SLU_NCP; Mtype = SLU_GE.
kusano 7d535a
 *         In the future, more general A may be handled.
kusano 7d535a
 *
kusano 7d535a
 * perm_c  (input/output) int*
kusano 7d535a
 *	   Column permutation vector of size A->ncol, which defines the 
kusano 7d535a
 *         permutation matrix Pc; perm_c[i] = j means column i of A is 
kusano 7d535a
 *         in position j in A*Pc.
kusano 7d535a
 *         If options->Fact == DOFACT, perm_c is both input and output.
kusano 7d535a
 *         On output, it is changed according to a postorder of etree.
kusano 7d535a
 *         Otherwise, perm_c is input.
kusano 7d535a
 *
kusano 7d535a
 * etree   (input/output) int*
kusano 7d535a
 *         Elimination tree of Pc'*A'*A*Pc, dimension A->ncol.
kusano 7d535a
 *         If options->Fact == DOFACT, etree is an output argument,
kusano 7d535a
 *         otherwise it is an input argument.
kusano 7d535a
 *         Note: etree is a vector of parent pointers for a forest whose
kusano 7d535a
 *         vertices are the integers 0 to A->ncol-1; etree[root]==A->ncol.
kusano 7d535a
 *
kusano 7d535a
 * AC      (output) SuperMatrix*
kusano 7d535a
 *         The resulting matrix after applied the column permutation
kusano 7d535a
 *         perm_c[] to matrix A. The type of AC can be:
kusano 7d535a
 *         Stype = SLU_NCP; Dtype = A->Dtype; Mtype = SLU_GE.
kusano 7d535a
 * 
kusano 7d535a
 */
kusano 7d535a
void
kusano 7d535a
sp_preorder(superlu_options_t *options,  SuperMatrix *A, int *perm_c, 
kusano 7d535a
	    int *etree, SuperMatrix *AC)
kusano 7d535a
{
kusano 7d535a
    NCformat  *Astore;
kusano 7d535a
    NCPformat *ACstore;
kusano 7d535a
    int       *iwork, *post;
kusano 7d535a
    register  int n, i;
kusano 7d535a
kusano 7d535a
    n = A->ncol;
kusano 7d535a
    
kusano 7d535a
    /* Apply column permutation perm_c to A's column pointers so to
kusano 7d535a
       obtain NCP format in AC = A*Pc.  */
kusano 7d535a
    AC->Stype       = SLU_NCP;
kusano 7d535a
    AC->Dtype       = A->Dtype;
kusano 7d535a
    AC->Mtype       = A->Mtype;
kusano 7d535a
    AC->nrow        = A->nrow;
kusano 7d535a
    AC->ncol        = A->ncol;
kusano 7d535a
    Astore          = A->Store;
kusano 7d535a
    ACstore = AC->Store = (void *) SUPERLU_MALLOC( sizeof(NCPformat) );
kusano 7d535a
    if ( !ACstore ) ABORT("SUPERLU_MALLOC fails for ACstore");
kusano 7d535a
    ACstore->nnz    = Astore->nnz;
kusano 7d535a
    ACstore->nzval  = Astore->nzval;
kusano 7d535a
    ACstore->rowind = Astore->rowind;
kusano 7d535a
    ACstore->colbeg = (int*) SUPERLU_MALLOC(n*sizeof(int));
kusano 7d535a
    if ( !(ACstore->colbeg) ) ABORT("SUPERLU_MALLOC fails for ACstore->colbeg");
kusano 7d535a
    ACstore->colend = (int*) SUPERLU_MALLOC(n*sizeof(int));
kusano 7d535a
    if ( !(ACstore->colend) ) ABORT("SUPERLU_MALLOC fails for ACstore->colend");
kusano 7d535a
kusano 7d535a
#ifdef DEBUG
kusano 7d535a
    print_int_vec("pre_order:", n, perm_c);
kusano 7d535a
    check_perm("Initial perm_c", n, perm_c);
kusano 7d535a
#endif      
kusano 7d535a
kusano 7d535a
    for (i = 0; i < n; i++) {
kusano 7d535a
	ACstore->colbeg[perm_c[i]] = Astore->colptr[i]; 
kusano 7d535a
	ACstore->colend[perm_c[i]] = Astore->colptr[i+1];
kusano 7d535a
    }
kusano 7d535a
	
kusano 7d535a
    if ( options->Fact == DOFACT ) {
kusano 7d535a
#undef ETREE_ATplusA
kusano 7d535a
#ifdef ETREE_ATplusA
kusano 7d535a
        /*--------------------------------------------
kusano 7d535a
	  COMPUTE THE ETREE OF Pc*(A'+A)*Pc'.
kusano 7d535a
	  --------------------------------------------*/
kusano 7d535a
        int *b_colptr, *b_rowind, bnz, j;
kusano 7d535a
	int *c_colbeg, *c_colend;
kusano 7d535a
kusano 7d535a
        /*printf("Use etree(A'+A)\n");*/
kusano 7d535a
kusano 7d535a
	/* Form B = A + A'. */
kusano 7d535a
	at_plus_a(n, Astore->nnz, Astore->colptr, Astore->rowind,
kusano 7d535a
		  &bnz, &b_colptr, &b_rowind);
kusano 7d535a
kusano 7d535a
	/* Form C = Pc*B*Pc'. */
kusano 7d535a
	c_colbeg = (int*) SUPERLU_MALLOC(2*n*sizeof(int));
kusano 7d535a
	c_colend = c_colbeg + n;
kusano 7d535a
	if (!c_colbeg ) ABORT("SUPERLU_MALLOC fails for c_colbeg/c_colend");
kusano 7d535a
	for (i = 0; i < n; i++) {
kusano 7d535a
	    c_colbeg[perm_c[i]] = b_colptr[i]; 
kusano 7d535a
  	    c_colend[perm_c[i]] = b_colptr[i+1];
kusano 7d535a
	}
kusano 7d535a
	for (j = 0; j < n; ++j) {
kusano 7d535a
	    for (i = c_colbeg[j]; i < c_colend[j]; ++i) {
kusano 7d535a
	        b_rowind[i] = perm_c[b_rowind[i]];
kusano 7d535a
	    }
kusano 7d535a
	}
kusano 7d535a
kusano 7d535a
	/* Compute etree of C. */
kusano 7d535a
	sp_symetree(c_colbeg, c_colend, b_rowind, n, etree);
kusano 7d535a
kusano 7d535a
	SUPERLU_FREE(b_colptr);
kusano 7d535a
	if ( bnz ) SUPERLU_FREE(b_rowind);
kusano 7d535a
	SUPERLU_FREE(c_colbeg);
kusano 7d535a
	
kusano 7d535a
#else
kusano 7d535a
        /*--------------------------------------------
kusano 7d535a
	  COMPUTE THE COLUMN ELIMINATION TREE.
kusano 7d535a
	  --------------------------------------------*/
kusano 7d535a
	sp_coletree(ACstore->colbeg, ACstore->colend, ACstore->rowind,
kusano 7d535a
		    A->nrow, A->ncol, etree);
kusano 7d535a
#endif
kusano 7d535a
#ifdef DEBUG	
kusano 7d535a
	print_int_vec("etree:", n, etree);
kusano 7d535a
#endif	
kusano 7d535a
	
kusano 7d535a
	/* In symmetric mode, do not do postorder here. */
kusano 7d535a
	if ( options->SymmetricMode == NO ) {
kusano 7d535a
	    /* Post order etree */
kusano 7d535a
	    post = (int *) TreePostorder(n, etree);
kusano 7d535a
	    /* for (i = 0; i < n+1; ++i) inv_post[post[i]] = i;
kusano 7d535a
	       iwork = post; */
kusano 7d535a
kusano 7d535a
#ifdef DEBUG
kusano 7d535a
	    print_int_vec("post:", n+1, post);
kusano 7d535a
	    check_perm("post", n, post);	
kusano 7d535a
#endif	
kusano 7d535a
	    iwork = (int*) SUPERLU_MALLOC((n+1)*sizeof(int)); 
kusano 7d535a
	    if ( !iwork ) ABORT("SUPERLU_MALLOC fails for iwork[]");
kusano 7d535a
kusano 7d535a
	    /* Renumber etree in postorder */
kusano 7d535a
	    for (i = 0; i < n; ++i) iwork[post[i]] = post[etree[i]];
kusano 7d535a
	    for (i = 0; i < n; ++i) etree[i] = iwork[i];
kusano 7d535a
kusano 7d535a
#ifdef DEBUG	
kusano 7d535a
	    print_int_vec("postorder etree:", n, etree);
kusano 7d535a
#endif
kusano 7d535a
	
kusano 7d535a
	    /* Postmultiply A*Pc by post[] */
kusano 7d535a
	    for (i = 0; i < n; ++i) iwork[post[i]] = ACstore->colbeg[i];
kusano 7d535a
	    for (i = 0; i < n; ++i) ACstore->colbeg[i] = iwork[i];
kusano 7d535a
	    for (i = 0; i < n; ++i) iwork[post[i]] = ACstore->colend[i];
kusano 7d535a
	    for (i = 0; i < n; ++i) ACstore->colend[i] = iwork[i];
kusano 7d535a
kusano 7d535a
	    for (i = 0; i < n; ++i)
kusano 7d535a
	        iwork[i] = post[perm_c[i]];  /* product of perm_c and post */
kusano 7d535a
	    for (i = 0; i < n; ++i) perm_c[i] = iwork[i];
kusano 7d535a
kusano 7d535a
#ifdef DEBUG
kusano 7d535a
	    print_int_vec("Pc*post:", n, perm_c);
kusano 7d535a
	    check_perm("final perm_c", n, perm_c);	
kusano 7d535a
#endif
kusano 7d535a
	    SUPERLU_FREE (post);
kusano 7d535a
	    SUPERLU_FREE (iwork);
kusano 7d535a
	} /* end postordering */
kusano 7d535a
kusano 7d535a
    } /* if options->Fact == DOFACT ... */
kusano 7d535a
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
int check_perm(char *what, int n, int *perm)
kusano 7d535a
{
kusano 7d535a
    register int i;
kusano 7d535a
    int          *marker;
kusano 7d535a
    marker = (int *) calloc(n, sizeof(int));
kusano 7d535a
kusano 7d535a
    for (i = 0; i < n; ++i) {
kusano 7d535a
	if ( marker[perm[i]] == 1 || perm[i] >= n ) {
kusano 7d535a
	    printf("%s: Not a valid PERM[%d] = %d\n", what, i, perm[i]);
kusano 7d535a
	    ABORT("check_perm");
kusano 7d535a
	} else {
kusano 7d535a
	    marker[perm[i]] = 1;
kusano 7d535a
	}
kusano 7d535a
    }
kusano 7d535a
kusano 7d535a
    SUPERLU_FREE(marker);
kusano 7d535a
    return 0;
kusano 7d535a
}