int CLAPS_sparse_lu::factor(int N_, int NNZ, int COLPTR[], int ROWIDX[],
                            double ANZ[], int scale_flag_)
{
    //
    // Input:
    //   N_ = number of equations
    //   NNZ = number of nonzeros in full matrix
    //   ROWIDX[COLPTR[i]:COLPTR[i+1]-1]  = nonzero row numbers for column i
    //   ANZ[   COLPTR[i]:COLPTR[i+1]-1]  = nonzero values in column i
    //   Note: C-style numbering of inputs is assumed (i.e. row and column
    //         numbers are all between 0 and N_-1
    //
    // solver parameters
    //
    DEFBLK = 1;
    int order_opt(2);
    max_small = 4;
    //
    N = N_;
    if (N == 0) return 0;
    if (N <= max_small) {
        int INFO;
        INFO = small_factor(COLPTR, ROWIDX, ANZ);
        return INFO;
    }
    scale_flag = scale_flag_;
    //
    // scale matrix entries if requested
    //
    double *ANZ_SCALED;
    if (scale_flag == 1) {
        int i, j;
        SCALE = new double[N];
        for (i=0; i<N; i++) SCALE[i] = 0;
        for (i=0; i<N; i++) {
            for (j=COLPTR[i]; j<COLPTR[i+1]; j++)
                if (ROWIDX[j] == i) SCALE[i] = sqrt(fabs(ANZ[j]));
            assert (SCALE[i] != 0);
        }
        ANZ_SCALED = new double[NNZ];
        for (i=0; i<N; i++) SCALE[i] = 1/SCALE[i];
        for (i=0; i<N; i++) {
            for (j=COLPTR[i]; j<COLPTR[i+1]; j++) {
                ANZ_SCALED[j] = SCALE[i]*SCALE[ROWIDX[j]]*ANZ[j];
            }
        }
    }
    else {
        ANZ_SCALED = ANZ;
    }
    int NNZA, NADJ, IWMAX, IWSIZE, IFLAG, MAXSUP, NTOT, RWSIZE, LDNS;
    int NNZL, NSUB, NLNZ, TMPSIZ, MAXDEF, ASDEF;
    double ANORM, EPS, TOL;
    int OPTIONS[8];
    //
    OPTIONS[0]=0; // use default values for options
    OPTIONS[1]=0;
    MAXSUP=150;   // maximum supernode size
    NTOT=NNZ;     // total number of nonzeros in matrix
    NADJ=NTOT-N;  // number of nonzeros in full matrix minus those on diagonal
    NNZA=NADJ/2+N;// number of nonzeros in lower triangle including diagonal
    IWMAX=7*N+3;  // dimension for integer working array
    if ((MAXSUP+2*N+1) > IWMAX) IWMAX=MAXSUP+2*N+1;
    if ((3*N+2*MAXSUP) > IWMAX) IWMAX=3*N+2*MAXSUP;

    MAXDEF=10;
    ASDEF=0;
    //  std::cout << "N    = " << N << std::endl;
    //  std::cout << "NTOT = " << NTOT << std::endl;
    //  std::cout << "NADJ = " << NADJ << std::endl;
    //  std::cout << "NNZA = " << NNZA << std::endl;
    int* ADJ = new int[NTOT];
    int* XADJ = new int[N+1];
    LINDX = new int[NTOT];
    PERM = new int[N];
    INVP = new int[N];
    int* IWORK = new int[IWMAX];
    int* COLCNT = new int[N];
    int* SNODE = new int[N];
    XSUPER = new int[N+1];
    XLINDX = new int[N+1];
    XLNZ = new int[N+1];
    DEF = new int[N];
    IPROW = new int[N];
    IPCOL = new int[N];
    //
    // determine adjacency structure of matrix
    // ADJ[XADJ[i]:XADJ[i+1]-1] = dofs adjacent to dof i (but not including
    //                            dof i itself)
    //
    XADJ[0]=0;
    int nnzADJ=0;
    for (int i=0; i<N; i++) {
        for (int j=COLPTR[i]; j<COLPTR[i+1]; j++) {
            int row=ROWIDX[j];
            if (row != i) {
                ADJ[nnzADJ]=row;
                nnzADJ++;
            }
        }
        XADJ[i+1]=nnzADJ;
    }
    //
    // compute L-infinity norm of matrix
    //
    getnrm(N, COLPTR, ROWIDX, ANZ_SCALED, ANORM);
    //
    // convert COLPTR, ROWIDX, XADJ, and ADJ to Fortran numbering
    //
    for (int i=0; i<=N; i++) COLPTR[i]++;
    for (int i=0; i<NNZ; i++) ROWIDX[i]++;
    for (int i=0; i<=N; i++) XADJ[i]++;
    for (int i=0; i<nnzADJ; i++) ADJ[i]++;
    //
    NADJ=XADJ[N]-1;
    for (int i=0; i<=N; i++) XLINDX[i]=XADJ[i];
    for (int i=0; i<nnzADJ; i++) LINDX[i]=ADJ[i];
    //
    // multiple minimum degree ordering
    //
    IWSIZE=4*N;
    if (order_opt == 1) {
        ORDMMD2_F77(N,XLINDX,LINDX,INVP,PERM,IWSIZE,IWORK,NSUB,IFLAG);
        if (IFLAG != 0) {
            std::cout << "error in call to ordmmd2 in CLAPS_sparse_lu::factor" << std::endl;
            std::cout << "ORDMMD2 IFLAG=" << IFLAG << std::endl;
            return -1;
        }
    }
    //
    // Metis ordering
    //
    if (order_opt == 2) {
        int numflag=1;
        std::vector<idx_t> options(METIS_NOPTIONS,0);
        METIS_SetDefaultOptions(&options[0]);

        options[METIS_OPTION_NUMBERING] = numflag;

        METIS_NodeND(&N,XLINDX,LINDX,0,&options[0],PERM,INVP);
    }
    //
    // symbolic factorization initialization
    //
    IWSIZE=7*N+3;
    SFINIT_F77(N,NADJ,XADJ,ADJ,PERM,INVP,MAXSUP,DEFBLK,COLCNT,
               NNZL,NSUB,NSUPER,XSUPER,SNODE,IWSIZE,IWORK,IFLAG);
    if (IFLAG != 0) {
        std::cout << "error in call to sfinit in CLAPS_sparse_lu::factor" << std::endl;
        std::cout << "SFINIT IFLAG=" << IFLAG << std::endl;
        return -1;
    }
    //
    // supernodal symbolic factorization
    //
    IWSIZE=NSUPER+2*N+1;
    if (NSUB>NTOT) {
        delete [] LINDX;
        LINDX = new int[NSUB];
    }
    SYMFCT_F77(N,NADJ,XADJ,ADJ,PERM,INVP,COLCNT,NSUPER,XSUPER,
               SNODE,NSUB,XLINDX,LINDX,XLNZ,IWSIZE,IWORK,IFLAG);
    if (IFLAG != 0) {
        std::cout << "error in call to symfct in CLAPS_sparse_lu::factor" << std::endl;
        std::cout << "SYMFCT IFLAG=" << IFLAG << std::endl;
        return -1;
    }
    //
    // input numerical values into data structures
    //
    NLNZ=XLNZ[N];
    //  std::cout << "number of nonzeros in LU factorization = " << NLNZ << std::endl;
    //  std::cout << "NLNZ = " << NLNZ << std::endl;

    // later, sparsepak will call dgemm on some of the "panels" in this data. We need to have
    // memory on the end of the array to ensure we don't overrun. Without the extra "N", we
    // may not have all of the last column allocated.
    LNZ = new double[NLNZ+N];
    for (int i=0; i<NLNZ; i++) LNZ[i]=0;
    for (int i=0; i<N; i++) DEF[i]=0;
    NDEF=0;
    LBDEF=0;
    inpnv(N,COLPTR,ROWIDX,ANZ_SCALED,PERM,INVP,NSUPER,XSUPER,XLINDX,LINDX,XLNZ,
          LNZ,IWORK);
    if (scale_flag == 1) delete [] ANZ_SCALED;
    //
    // numerical factorization
    //
    BFINIT_F77(NSUPER,XSUPER,SNODE,XLINDX,LINDX,TMPSIZ,RWSIZE);
    if (TMPSIZ < 1) TMPSIZ=1;
    TMPSIZ=2*TMPSIZ;
    double* TMPVEC = new double[TMPSIZ];
    int RWORKdim=N;
    if (RWSIZE > N) RWORKdim=RWSIZE;
    double* RWORK = new double[RWORKdim];
    //  EPS=1e-10;
    EPS = 1e-12;
    //  EPS=DLAMCH('EPS');
    TOL=EPS*ANORM;
    IWSIZE = 3*N + 2*NSUPER;
    BLKLDL_F77(NSUPER,XSUPER,SNODE,XLINDX,LINDX,XLNZ,LNZ,DEFBLK,ASDEF,NDEF,
               LBDEF,DEF,TOL,IPROW,IPCOL,TMPSIZ,TMPVEC,IWSIZE,IWORK,
               RWSIZE,RWORK,IFLAG);
    if (IFLAG != 0) {
        std::cout << "error in call to blkldl in CLAPS_sparse_lu::factor" << std::endl;
        std::cout << "BLKLDL IFLAG=" << IFLAG << std::endl;
        return -1;
    }
    //  if (DEFBLK == 0) {
    //    LBDEF=0;
    //    NDEF=0;
    //  }
    if ((NDEF != 0) && (NDEF <= MAXDEF)) {
        //
        // compute null space
        //
        NS = new double [N*NDEF];
        LDNS=N;
        BLKNS_F77(NSUPER,XSUPER,XLINDX,LINDX,XLNZ,LNZ,DEFBLK,NDEF,LBDEF,
                  DEF,IPCOL,INVP,NS,LDNS,RWORK);
        std::cout << "null space dimension = " << NDEF << std::endl;
        /*
        std::cout << "NS = " << std::endl;
        for (int i=0;i<NDEF;i++) {
          for (int j=0;j<N;j++) std::cout << NS[j+N*i] << " ";
          std::cout << std::endl;
        }
        */
    }
    delete [] ADJ;
    ADJ=0;
    delete [] XADJ;
    XADJ=0;
    delete [] IWORK;
    IWORK=0;
    delete [] COLCNT;
    COLCNT=0;
    delete [] SNODE;
    SNODE=0;
    delete [] TMPVEC;
    TMPVEC=0;
    delete [] RWORK;
    RWORK=0;
    //
    // convert COLPTR and ROWIDX back to C numbering
    //
    for (int i=0; i<=N; i++) COLPTR[i]--;
    for (int i=0; i<NNZ; i++) ROWIDX[i]--;
    return 0;
}
Exemple #2
0
/* Reorder CSR matrix h_csr by ND metis  */
void reorder_nd(csr_t *A, int *perm) {
  int *iperm,n,*ia,*ja;
/*---------------------------------------*/
  n = A->n;
  ia = A->ia;  ja = A->ja;
  Malloc(iperm, n, int);
  int nf = 1;
  int opt = 0;
  METIS_NodeND(&n,ia,ja,&nf,&opt,iperm,perm);
  free(iperm);
}
Ordering *SparseConectivityMtxII :: Get_MetisDiSection()
{
#ifdef _LINK_METIS_
    IntArrayList *order = new IntArrayList(n);
    IntArrayList *perm = new IntArrayList(n);

    int n = N();
    long *adr;
    long *ci;

    GetCmpRows(adr, ci);

    int numflag = 0;
    /*int optionsNodeND[]=
     * {
     *      1,
     *      3,
     *      1,
     *      2,
     *      0,
     *      0,
     *      0,
     *      1
     * };
     *
     * METIS_NodeND(&n,adr,ci,&numflag,optionsNodeND,(int*)order->Items,(int*)perm->Items);
     */

    int optionsEdgeND[] =
    {
        0,
        3,
        1,
        2,
        0,
        0,
        0,
        1
    };

    METIS_NodeND(& n, ( int * ) adr, ( int * ) ci, & numflag, optionsEdgeND, ( int * ) order->Items, ( int * ) perm->Items);

    delete [] adr;
    delete [] ci;

    return new Ordering(perm, order);

#else
    Writeln(" The program was not linked with METIS library, use _LINK_METIS_ directive!");
    return NULL;

#endif
}
Exemple #4
0
/**
 * Establish a fill-reducing permutation for the sparse symmetric
 * matrix of order n represented by the column pointers Tp and row
 * indices Ti.
 *
 * @param n  order of the sparse symmetric matrix
 * @param Tp  column pointers (total length n + 1)
 * @param Ti  row indices (total length Tp[n])
 * @param Perm array of length n to hold the permutation
 * @param iPerm array of length n to hold the inverse permutation
 *
 */
void ssc_metis_order(int n, const int Tp [], const int Ti [],
                     int Perm[], int iPerm[])
{
    int  j, num_flag = 0, options_flag = 0;
    idxtype
    *perm = Calloc(n, idxtype), /* in case idxtype != int */
     *iperm = Calloc(n, idxtype),
      *xadj = Calloc(n+1, idxtype),
       *adj = Calloc(2 * (Tp[n] - n), idxtype);

    /* check row indices for correct range */
    for (j = 0; j < Tp[n]; j++)
        if (Ti[j] < 0 || Ti[j] >= n)
            error(_("row index Ti[%d] = %d is out of range [0,%d]"),
                  j, Ti[j], n - 1);
    /* temporarily use perm to store lengths */
    AZERO(perm, n);
    for (j = 0; j < n; j++) {
        int ip, p2 = Tp[j+1];
        for (ip = Tp[j]; ip < p2; ip++) {
            int i = Ti[ip];
            if (i != j) {
                perm[i]++;
                perm[j]++;
            }
        }
    }
    xadj[0] = 0;
    for (j = 0; j < n; j++) xadj[j+1] = xadj[j] + perm[j];
    /* temporarily use perm to store pointers */
    Memcpy(perm, xadj, n);
    for (j = 0; j < n; j++) {
        int ip, p2 = Tp[j+1];
        for (ip = Tp[j]; ip < p2; ip++) {
            int i = Ti[ip];
            if (i != j) {
                adj[perm[i]] = j;
                adj[perm[j]] = i;
                perm[i]++;
                perm[j]++;
            }
        }
    }
    METIS_NodeND(&n, xadj, adj, &num_flag, &options_flag, perm, iperm);
    for (j = 0; j < n; j++) {
        Perm[j] = (int) perm[j];
        iPerm[j] = (int) iperm[j];
    }
    Free(iperm);
    Free(perm);
    Free(xadj);
    Free(adj);
}
Exemple #5
0
void
get_metis(
	  int_t n,         /* dimension of matrix B */
	  int_t bnz,       /* number of nonzeros in matrix A. */
	  int_t *b_colptr, /* column pointer of size n+1 for matrix B. */
	  int_t *b_rowind, /* row indices of size bnz for matrix B. */
	  int_t *perm_c    /* out - the column permutation vector. */
	  )
{
#define METISOPTIONS 8
    int ct, i, j, nm, numflag = 0; /* C-Style ordering */
    int metis_options[METISOPTIONS];
    int_t *perm, *iperm;

    metis_options[0] = 0; /* Use Defaults for now */
    perm = intMalloc_dist(n);
    iperm = intMalloc_dist(n);

    nm = n;

#ifdef USE_METIS
    /* Call metis */
#undef USEEND
#ifdef USEEND
      METIS_EdgeND(&nm, b_colptr, b_rowind, &numflag, metis_options,
		   perm, iperm);
#else
      METIS_NodeND(&nm, b_colptr, b_rowind, &numflag, metis_options,
		   perm, iperm);
#endif
#endif

      /* Copy the permutation vector into SuperLU data structure. */
      for (i = 0; i < n; ++i) perm_c[i] = iperm[i];

      SUPERLU_FREE(b_colptr);
      SUPERLU_FREE(b_rowind);
      SUPERLU_FREE(perm);
      SUPERLU_FREE(iperm);
}
Exemple #6
0
/*************************************************************************
* This function orders the locally stored graph using MMD. 
* The vertices will be ordered from firstnode onwards.
**************************************************************************/
void LocalNDOrder(CtrlType *ctrl, GraphType *graph, idxtype *order, int firstnode, WorkSpaceType *wspace)
{
  int i, j, nvtxs, firstvtx, lastvtx;
  idxtype *xadj, *adjncy;
  idxtype *perm, *iperm;
  int numflag=0, options[10];

  nvtxs = graph->nvtxs;
  xadj = graph->xadj;
  adjncy = graph->adjncy;

  firstvtx = graph->vtxdist[ctrl->mype];
  lastvtx = graph->vtxdist[ctrl->mype+1];

  /* Relabel the vertices so that they are in local index space */
  for (i=0; i<nvtxs; i++) {
    for (j=xadj[i]; j<xadj[i+1]; j++) {
      ASSERT(ctrl, adjncy[j]>=firstvtx && adjncy[j]<lastvtx);
      adjncy[j] -= firstvtx;
    }
  }

  ASSERT(ctrl, 2*(nvtxs+5) < wspace->maxcore);

  perm = wspace->core;
  iperm = perm + nvtxs + 5;

  options[0] = 0;
  METIS_NodeND(&nvtxs, xadj, adjncy, &numflag, options, perm, iperm);

  for (i=0; i<nvtxs; i++) {
    ASSERT(ctrl, iperm[i]>=0 && iperm[i]<nvtxs);
    order[i] = firstnode+iperm[i];
  }

}
Exemple #7
0
/* ************************************************************************* */
Ordering Ordering::Metis(const MetisIndex& met) {
#ifdef GTSAM_SUPPORT_NESTED_DISSECTION
  gttic(Ordering_METIS);

  vector<idx_t> xadj = met.xadj();
  vector<idx_t> adj = met.adj();
  vector<idx_t> perm, iperm;

  idx_t size = met.nValues();
  for (idx_t i = 0; i < size; i++) {
    perm.push_back(0);
    iperm.push_back(0);
  }

  int outputError;

  outputError = METIS_NodeND(&size, &xadj[0], &adj[0], NULL, NULL, &perm[0],
      &iperm[0]);
  Ordering result;

  if (outputError != METIS_OK) {
    std::cout << "METIS failed during Nested Dissection ordering!\n";
    return result;
  }

  result.resize(size);
  for (size_t j = 0; j < (size_t) size; ++j) {
    // We have to add the minKey value back to obtain the original key in the Values
    result[j] = met.intToKey(perm[j]);
  }
  return result;
#else
  throw runtime_error("GTSAM was built without support for Metis-based "
                      "nested dissection");
#endif
}
Exemple #8
0
void metis_nodend__(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, idxtype *perm, idxtype *iperm)
{
  METIS_NodeND(nvtxs, xadj, adjncy, numflag, options, perm, iperm);
}
Exemple #9
0
void METIS_NODEND(int *nvtxs, idxtype *xadj, idxtype *adjncy, int *numflag, int *options, idxtype *perm, idxtype *iperm)
{
  METIS_NodeND(nvtxs, xadj, adjncy, numflag, options, perm, iperm);
}
Exemple #10
0
int CHOLMOD(metis)
(
    /* ---- input ---- */
    cholmod_sparse *A,	/* matrix to order */
    Int *fset,		/* subset of 0:(A->ncol)-1 */
    size_t fsize,	/* size of fset */
    int postorder,	/* if TRUE, follow with etree or coletree postorder */
    /* ---- output --- */
    Int *Perm,		/* size A->nrow, output permutation */
    /* --------------- */
    cholmod_common *Common
)
{
    double d ;
    Int *Iperm, *Iwork, *Bp, *Bi ;
    idxtype *Mp, *Mi, *Mperm, *Miperm ;
    cholmod_sparse *B ;
    Int i, j, n, nz, p, identity, uncol ;
    int Opt [8], nn, zero = 0 ;
    size_t n1, s ;
    int ok = TRUE ;

    /* ---------------------------------------------------------------------- */
    /* get inputs */
    /* ---------------------------------------------------------------------- */

    RETURN_IF_NULL_COMMON (FALSE) ;
    RETURN_IF_NULL (A, FALSE) ;
    RETURN_IF_NULL (Perm, FALSE) ;
    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
    Common->status = CHOLMOD_OK ;

    /* ---------------------------------------------------------------------- */
    /* quick return */
    /* ---------------------------------------------------------------------- */

    n = A->nrow ;
    if (n == 0)
    {
	return (TRUE) ;
    }
    n1 = ((size_t) n) + 1 ;

    /* ---------------------------------------------------------------------- */
    /* allocate workspace */
    /* ---------------------------------------------------------------------- */

    /* s = 4*n + uncol */
    uncol = (A->stype == 0) ? A->ncol : 0 ;
    s = CHOLMOD(mult_size_t) (n, 4, &ok) ;
    s = CHOLMOD(add_size_t) (s, uncol, &ok) ;
    if (!ok)
    {
	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
	return (FALSE) ;
    }

    CHOLMOD(allocate_work) (n, s, 0, Common) ;
    if (Common->status < CHOLMOD_OK)
    {
	return (FALSE) ;
    }
    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;

    /* ---------------------------------------------------------------------- */
    /* convert the matrix to adjacency list form */
    /* ---------------------------------------------------------------------- */

    /* The input graph for METIS must be symmetric, with both upper and lower
     * parts present, and with no diagonal entries.  The columns need not be
     * sorted.
     * B = A+A', A*A', or A(:,f)*A(:,f)', upper and lower parts present */
    if (A->stype)
    {
	/* Add the upper/lower part to a symmetric lower/upper matrix by
	 * converting to unsymmetric mode */
	/* workspace: Iwork (nrow) */
	B = CHOLMOD(copy) (A, 0, -1, Common) ;
    }
    else
    {
	/* B = A*A' or A(:,f)*A(:,f)', no diagonal */
	/* workspace: Flag (nrow), Iwork (max (nrow,ncol)) */
	B = CHOLMOD(aat) (A, fset, fsize, -1, Common) ;
    }
    ASSERT (CHOLMOD(dump_sparse) (B, "B for NodeND", Common) >= 0) ;
    if (Common->status < CHOLMOD_OK)
    {
	return (FALSE) ;
    }
    ASSERT (B->nrow == A->nrow) ;

    /* ---------------------------------------------------------------------- */
    /* get inputs */
    /* ---------------------------------------------------------------------- */

    Iwork = Common->Iwork ;
    Iperm = Iwork ;		/* size n (i/i/l) */

    Bp = B->p ;
    Bi = B->i ;
    nz = Bp [n] ;

    /* ---------------------------------------------------------------------- */
    /* METIS does not have a SuiteSparse_long integer version */
    /* ---------------------------------------------------------------------- */

#ifdef LONG
    if (sizeof (Int) > sizeof (idxtype) && MAX (n,nz) > INT_MAX / sizeof (int))
    {
	/* CHOLMOD's matrix is too large for METIS */
	CHOLMOD(free_sparse) (&B, Common) ;
	return (FALSE) ;
    }
#endif

    /* B does not include the diagonal, and both upper and lower parts.
     * Common->anz includes the diagonal, and just the lower part of B */
    Common->anz = nz / 2 + n ;

    /* ---------------------------------------------------------------------- */
    /* set control parameters for METIS_NodeND */
    /* ---------------------------------------------------------------------- */

    Opt [0] = 0 ;	/* use defaults */
    Opt [1] = 3 ;	/* matching type */
    Opt [2] = 1 ;	/* init. partitioning algo*/
    Opt [3] = 2 ;	/* refinement algorithm */
    Opt [4] = 0 ;	/* no debug */
    Opt [5] = 1 ;	/* initial compression */
    Opt [6] = 0 ;	/* no dense node removal */
    Opt [7] = 1 ;	/* number of separators @ each step */

    /* ---------------------------------------------------------------------- */
    /* allocate the METIS input arrays, if needed */
    /* ---------------------------------------------------------------------- */

    if (sizeof (Int) == sizeof (idxtype))
    {
	/* This is the typical case. */
	Miperm = (idxtype *) Iperm ;
	Mperm  = (idxtype *) Perm ;
	Mp     = (idxtype *) Bp ;
	Mi     = (idxtype *) Bi ;
    }
    else
    {
	/* allocate graph for METIS only if Int and idxtype differ */
	Miperm = CHOLMOD(malloc) (n,  sizeof (idxtype), Common) ;
	Mperm  = CHOLMOD(malloc) (n,  sizeof (idxtype), Common) ;
	Mp     = CHOLMOD(malloc) (n1, sizeof (idxtype), Common) ;
	Mi     = CHOLMOD(malloc) (nz, sizeof (idxtype), Common) ;
	if (Common->status < CHOLMOD_OK)
	{
	    /* out of memory */
	    CHOLMOD(free_sparse) (&B, Common) ;
	    CHOLMOD(free) (n,  sizeof (idxtype), Miperm, Common) ;
	    CHOLMOD(free) (n,  sizeof (idxtype), Mperm, Common) ;
	    CHOLMOD(free) (n1, sizeof (idxtype), Mp, Common) ;
	    CHOLMOD(free) (nz, sizeof (idxtype), Mi, Common) ;
	    return (FALSE) ;
	}
	for (j = 0 ; j <= n ; j++)
	{
	    Mp [j] = Bp [j] ;
	}
	for (p = 0 ; p < nz ; p++)
	{
	    Mi [p] = Bi [p] ;
	}
    }

    /* ---------------------------------------------------------------------- */
    /* METIS workarounds */
    /* ---------------------------------------------------------------------- */

    identity = FALSE ;
    if (nz == 0)
    {
	/* The matrix has no off-diagonal entries.  METIS_NodeND fails in this
	 * case, so avoid using it.  The best permutation is identity anyway,
	 * so this is an easy fix. */
	identity = TRUE ;
	PRINT1 (("METIS:: no nz\n")) ;
    }
    else if (Common->metis_nswitch > 0)
    {
	/* METIS_NodeND in METIS 4.0.1 gives a seg fault with one matrix of
	 * order n = 3005 and nz = 6,036,025, including the diagonal entries.
	 * The workaround is to return the identity permutation instead of using
	 * METIS for matrices of dimension 3000 or more and with density of 66%
	 * or more - admittedly an uncertain fix, but such matrices are so dense
	 * that any reasonable ordering will do, even identity (n^2 is only 50%
	 * higher than nz in this case).  CHOLMOD's nested dissection method
	 * (cholmod_nested_dissection) has no problems with the same matrix,
	 * even though it too uses METIS_NodeComputeSeparator.  The matrix is
	 * derived from LPnetlib/lpi_cplex1 in the UF sparse matrix collection.
	 * If C is the lpi_cplex matrix (of order 3005-by-5224), A = (C*C')^2
	 * results in the seg fault.  The seg fault also occurs in the stand-
	 * alone onmetis program that comes with METIS.  If a future version of
	 * METIS fixes this problem, then set Common->metis_nswitch to zero.
	 */
	d = ((double) nz) / (((double) n) * ((double) n)) ;
	if (n > (Int) (Common->metis_nswitch) && d > Common->metis_dswitch)
	{
	    identity = TRUE ;
	    PRINT1 (("METIS:: nswitch/dswitch activated\n")) ;
	}
    }

    if (!identity && !metis_memory_ok (n, nz, Common))
    {
	/* METIS might ask for too much memory and thus terminate the program */
	identity = TRUE ;
    }

    /* ---------------------------------------------------------------------- */
    /* find the permutation */
    /* ---------------------------------------------------------------------- */

    if (identity)
    {
	/* no need to do the postorder */
	postorder = FALSE ;
	for (i = 0 ; i < n ; i++)
	{
	    Mperm [i] = i ;
	}
    }
    else
    {
#ifdef DUMP_GRAPH
	/* DUMP_GRAPH */ printf ("Calling METIS_NodeND n "ID" nz "ID""
	"density %g\n", n, nz, ((double) nz) / (((double) n) * ((double) n)));
	dumpgraph (Mp, Mi, n, Common) ;
#endif

	nn = n ;
	METIS_NodeND (&nn, Mp, Mi, &zero, Opt, Mperm, Miperm) ;
	n = nn ;

	PRINT0 (("METIS_NodeND done\n")) ;
    }

    /* ---------------------------------------------------------------------- */
    /* free the METIS input arrays */
    /* ---------------------------------------------------------------------- */

    if (sizeof (Int) != sizeof (idxtype))
    {
	for (i = 0 ; i < n ; i++)
	{
	    Perm [i] = (Int) (Mperm [i]) ;
	}
	CHOLMOD(free) (n,   sizeof (idxtype), Miperm, Common) ;
	CHOLMOD(free) (n,   sizeof (idxtype), Mperm, Common) ;
	CHOLMOD(free) (n+1, sizeof (idxtype), Mp, Common) ;
	CHOLMOD(free) (nz,  sizeof (idxtype), Mi, Common) ;
    }

    CHOLMOD(free_sparse) (&B, Common) ;

    /* ---------------------------------------------------------------------- */
    /* etree or column-etree postordering, using the Cholesky Module */
    /* ---------------------------------------------------------------------- */

    if (postorder)
    {
	Int *Parent, *Post, *NewPerm ;
	Int k ;

	Parent = Iwork + 2*((size_t) n) + uncol ;   /* size n = nrow */
	Post   = Parent + n ;			    /* size n */

	/* workspace: Iwork (2*nrow+uncol), Flag (nrow), Head (nrow+1) */
	CHOLMOD(analyze_ordering) (A, CHOLMOD_METIS, Perm, fset, fsize,
		Parent, Post, NULL, NULL, NULL, Common) ;
	if (Common->status == CHOLMOD_OK)
	{
	    /* combine the METIS permutation with its postordering */
	    NewPerm = Parent ;	    /* use Parent as workspace */
	    for (k = 0 ; k < n ; k++)
	    {
		NewPerm [k] = Perm [Post [k]] ;
	    }
	    for (k = 0 ; k < n ; k++)
	    {
		Perm [k] = NewPerm [k] ;
	    }
	}
    }

    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
    PRINT1 (("cholmod_metis done\n")) ;
    return (Common->status == CHOLMOD_OK) ;
}
Exemple #11
0
/*************************************************************************
* Let the game begin
**************************************************************************/
main(int argc, char *argv[])
{
  int i, options[10];
  idxtype *perm, *iperm;
  GraphType graph;
  char filename[256];
  int numflag = 0, wgtflag;
  timer TOTALTmr, METISTmr, IOTmr, SMBTmr;


  if (argc != 2) {
    printf("Usage: %s <GraphFile>\n",argv[0]);
    exit(0);
  }
    
  strcpy(filename, argv[1]);

  cleartimer(TOTALTmr);
  cleartimer(METISTmr);
  cleartimer(IOTmr);
  cleartimer(SMBTmr);

  starttimer(TOTALTmr);
  starttimer(IOTmr);
  ReadGraph(&graph, filename, &wgtflag);
  if (graph.nvtxs <= 0) {
    printf("Empty graph. Nothing to do.\n");
    exit(0);
  }
  if (graph.ncon != 1) {
    printf("Ordering can only be applied to graphs with one constraint.\n");
    exit(0);
  }
  stoptimer(IOTmr);

  /* Ordering does not use weights! */
  GKfree(&graph.vwgt, &graph.adjwgt, LTERM);

  printf("**********************************************************************\n");
  printf("%s", METISTITLE);
  printf("Graph Information ---------------------------------------------------\n");
  printf("  Name: %s, #Vertices: %d, #Edges: %d\n\n", filename, graph.nvtxs, graph.nedges/2);
  printf("Node-Based Ordering... ----------------------------------------------\n");

  perm = idxmalloc(graph.nvtxs, "main: perm");
  iperm = idxmalloc(graph.nvtxs, "main: iperm");
  options[0] = 0;

  starttimer(METISTmr);
  METIS_NodeND(&graph.nvtxs, graph.xadj, graph.adjncy, &numflag, options, perm, iperm);
  stoptimer(METISTmr);

  starttimer(IOTmr);
  WritePermutation(filename, iperm, graph.nvtxs); 
  stoptimer(IOTmr);

  starttimer(SMBTmr);
  ComputeFillIn(&graph, iperm);
  stoptimer(SMBTmr);

  stoptimer(TOTALTmr);

  printf("\nTiming Information --------------------------------------------------\n");
  printf("  I/O:                     \t %7.3f\n", gettimer(IOTmr));
  printf("  Ordering:                \t %7.3f   (ONMETIS time)\n", gettimer(METISTmr));
  printf("  Symbolic Factorization:  \t %7.3f\n", gettimer(SMBTmr));
  printf("  Total:                   \t %7.3f\n", gettimer(TOTALTmr));
  printf("**********************************************************************\n");


  GKfree(&graph.xadj, &graph.adjncy, &perm, &iperm, LTERM);
}  
Exemple #12
0
static void taucs_ccs_metis(taucs_ccs_matrix * m, int **perm, int **invperm, char *which)
{
#ifndef TAUCS_CONFIG_METIS
	taucs_printf("taucs_ccs_metis: METIS routines not linked.\n");
	*perm = NULL;
	*invperm = NULL;
	return;
#else
	int n, nnz, i, j, ip;
	int *xadj;
	int *adj;
	int num_flag = 0;
	int options_flag[8];
	int *len;
	int *ptr;

	/*
	 * taucs_printf("taucs_ccs_metis: starting (%s)\n",which); 
	 */

	if (!(m->flags & TAUCS_SYMMETRIC) && !(m->flags & TAUCS_HERMITIAN)) {
		taucs_printf("taucs_ccs_treeorder: METIS ordering only works on symmetric matrices.\n");
		*perm = NULL;
		*invperm = NULL;
		return;
	}
	/*
	 * this routine may actually work on UPPER as well 
	 */
	if (!(m->flags & TAUCS_LOWER)) {
		taucs_printf("taucs_ccs_metis: the lower part of the matrix must be represented.\n");
		*perm = NULL;
		*invperm = NULL;
		return;
	}

	n = m->n;
	nnz = (m->colptr)[n];

	*perm = (int *) taucs_malloc(n * sizeof(int));
	*invperm = (int *) taucs_malloc(n * sizeof(int));

	xadj = (int *) taucs_malloc((n + 1) * sizeof(int));
	adj = (int *) taucs_malloc(2 * nnz * sizeof(int));

	if (!(*perm) || !(*invperm) || !xadj || !adj) {
		taucs_free(*perm);
		taucs_free(*invperm);
		taucs_free(xadj);
		taucs_free(adj);
		*perm = *invperm = NULL;
		return;
	}

	ptr = len = *perm;
	for (i = 0; i < n; i++)
		len[i] = 0;

	for (j = 0; j < n; j++) {
		for (ip = (m->colptr)[j]; ip < (m->colptr)[j + 1]; ip++) {
			/*
			 * i = (m->rowind)[ip] - (m->indshift);
			 */
			i = (m->rowind)[ip];
			if (i != j) {
				len[i]++;
				len[j]++;
			}
		}
	}

	xadj[0] = 0;
	for (i = 1; i <= n; i++)
		xadj[i] = xadj[i - 1] + len[i - 1];

	for (i = 0; i < n; i++)
		ptr[i] = xadj[i];

	for (j = 0; j < n; j++) {
		for (ip = (m->colptr)[j]; ip < (m->colptr)[j + 1]; ip++) {
			/*
			 * i = (m->rowind)[ip] - (m->indshift);
			 */
			i = (m->rowind)[ip];
			if (i != j) {
				adj[ptr[i]] = j;
				adj[ptr[j]] = i;
				ptr[i]++;
				ptr[j]++;
			}
		}
	}

	options_flag[0] = 1;				       /* use these options */
	options_flag[1] = 3;				       /* default */
	options_flag[2] = 1;				       /* default */
	options_flag[3] = 1;				       /* two-side refinement */
	options_flag[4] = 0;				       /* no debug */
	options_flag[5] = 1;				       /* default */
	options_flag[6] = 0; 				       /* THIS IS SLOW if non-zero. global nodes */
	options_flag[7] = 3;				       /* number of separators */

	METIS_NodeND(&n, xadj, adj, &num_flag, options_flag, *perm, *invperm);

	taucs_free(xadj);
	taucs_free(adj);
#endif
}
Exemple #13
0
void Cluster::subdivide(unsigned bmin)
{
    const unsigned size(_end - _beg);
    if (size > bmin) {

        idx_t n_rows(static_cast<idx_t>(_l_adj_mat->getNRows()));

        idx_t *xadj(new idx_t[n_rows+1]);
        unsigned const*const original_row_ptr(_l_adj_mat->getRowPtrArray());
        for(idx_t k(0); k<=n_rows; k++) {
            xadj[k] = original_row_ptr[k];
        }

        unsigned nnz(_l_adj_mat->getNNZ());
        idx_t *adjncy(new idx_t[nnz]);
        unsigned const*const original_adjncy(_l_adj_mat->getColIdxArray());
        for(unsigned k(0); k<nnz; k++) {
            adjncy[k] = original_adjncy[k];
        }
//		unsigned nparts = 2;
        idx_t options[METIS_NOPTIONS]; // for METIS
        METIS_SetDefaultOptions(options);
//		options[METIS OPTION PTYPE] = METIS PTYPE RB;
//		options[METIS OPTION OBJTYPE] = METIS OBJTYPE CUT;
//		options[METIS OPTION CTYPE] = METIS CTYPE SHEM;
//		options[] = ;
//		options[] = ;
//		options[] = ;

//		unsigned sepsize(0); // for METIS
        idx_t *vwgt(new idx_t[n_rows + 1]);
//		const unsigned nnz(xadj[n_rows]);
//		unsigned *adjwgt(new unsigned[nnz]);
        for (idx_t k(0); k < n_rows + 1; k++)
            vwgt[k] = 1;
//		for (unsigned k(0); k < nnz; k++)
//			adjwgt[k] = 1;
//		unsigned *part(new unsigned[n_rows + 1]);

        // subdivide the index set into three parts employing METIS
//		METIS_ComputeVertexSeparator(&n_rows, xadj, adjncy, vwgt, &options,
//				&sepsize, part);
        idx_t *loc_op_perm(new idx_t[n_rows]);
        idx_t *loc_po_perm(new idx_t[n_rows]);
        for (idx_t k(0); k<n_rows; k++) {
            loc_op_perm[k] = _g_op_perm[k];
        }
        for (idx_t k(0); k<n_rows; k++) {
            loc_po_perm[k] = _g_po_perm[k];
        }
        METIS_NodeND(&n_rows, xadj, adjncy, vwgt, options, loc_op_perm, loc_po_perm);
        for (idx_t k(0); k<n_rows; k++) {
            _g_op_perm[k] = loc_op_perm[k];
        }
        for (idx_t k(0); k<n_rows; k++) {
            _g_po_perm[k] = loc_po_perm[k];
        }
        delete [] loc_op_perm;
        delete [] loc_po_perm;
        delete [] vwgt;
        delete [] adjncy;
        delete [] xadj;
//		// create and init local permutations
//		unsigned *l_op_perm(new unsigned[size]);
//		unsigned *l_po_perm(new unsigned[size]);
//		for (unsigned i = 0; i < size; ++i)
//			l_op_perm[i] = l_po_perm[i] = i;
//
//		unsigned isep1, isep2;
//		updatePerm(part, isep1, isep2, l_op_perm, l_po_perm);
//		delete[] part;
//
//		// update global permutation
//		unsigned *t_op_perm = new unsigned[size];
//		for (unsigned k = 0; k < size; ++k)
//			t_op_perm[k] = _g_op_perm[_beg + l_op_perm[k]];
//
//		for (unsigned k = _beg; k < _end; ++k) {
//			_g_op_perm[k] = t_op_perm[k - _beg];
//			_g_po_perm[_g_op_perm[k]] = k;
//		}
//		delete[] t_op_perm;
//
//		// next recursion step
//		if ((isep1 >= bmin) && (isep2 - isep1 >= bmin)) {
//			// construct adj matrices for [0, isep1), [isep1,isep2), [isep2, _end)
//			AdjMat *l_adj0(_l_adj_mat->getMat(0, isep1, l_op_perm, l_po_perm));
//			AdjMat *l_adj1(_l_adj_mat->getMat(isep1, isep2, l_op_perm, l_po_perm));
//			AdjMat *l_adj2(_l_adj_mat->getMat(isep2, size, l_op_perm, l_po_perm));
//
//			delete[] l_op_perm;
//			delete[] l_po_perm;
//			delete _l_adj_mat;
//			_l_adj_mat = NULL;
//
//			_n_sons = 3;
//			_sons = new ClusterBase*[_n_sons];
//
//			isep1 += _beg;
//			isep2 += _beg;
//
//			// constructing child nodes for index cluster tree
//			_sons[0] = new Cluster(this, _beg, isep1, _g_op_perm, _g_po_perm, _g_adj_mat, l_adj0);
//			_sons[1] = new Cluster(this, isep1, isep2, _g_op_perm, _g_po_perm, _g_adj_mat, l_adj1);
//			_sons[2] = new Separator(this, isep2, _end, _g_op_perm,	_g_po_perm, _g_adj_mat, l_adj2);
//
//			dynamic_cast<Cluster*>(_sons[0])->subdivide(bmin);
//			dynamic_cast<Cluster*>(_sons[1])->subdivide(bmin);
//
//		} else {
//			delete _l_adj_mat;
//			_l_adj_mat = NULL;
//		} // end if next recursion step
    } // end if ( connected && size () > bmin )

}
int Zoltan_ParMetis_Order(
  ZZ *zz,               /* Zoltan structure */
  int num_obj,          /* Number of (local) objects to order. */
  ZOLTAN_ID_PTR gids,   /* List of global ids (local to this proc) */
                        /* The application must allocate enough space */
  ZOLTAN_ID_PTR lids,   /* List of local ids (local to this proc) */
                        /* The application must allocate enough space */
  ZOLTAN_ID_PTR rank,   /* rank[i] is the rank of gids[i] */
  int *iperm,
  ZOOS *order_opt       /* Ordering options, parsed by Zoltan_Order */
)
{
  static char *yo = "Zoltan_ParMetis_Order";
  int i, n, ierr;
  ZOLTAN_Output_Order ord;
  ZOLTAN_Third_Graph gr;

#ifdef ZOLTAN_PARMETIS
  MPI_Comm comm = zz->Communicator;/* don't want to risk letting external 
                                      packages changing our communicator */
#endif
  indextype numflag = 0;

  int timer_p = 0;
  int get_times = 0;
  int use_timers = 0;
  double times[5];

  ZOLTAN_ID_PTR       l_gids = NULL;
  ZOLTAN_ID_PTR       l_lids = NULL;

  indextype options[MAX_PARMETIS_OPTIONS];
  char alg[MAX_PARAM_STRING_LEN];

  ZOLTAN_TRACE_ENTER(zz, yo);

#ifdef ZOLTAN_PARMETIS
#if TPL_USE_DATATYPE != TPL_METIS_DATATYPES

#ifdef TPL_FLOAT_WEIGHT
  i = 1;
#else
  i = 0;
#endif

  if ((sizeof(indextype) != sizeof(idxtype)) ||
      (sizeof(weighttype) != sizeof(idxtype)) || i){

    ZOLTAN_THIRD_ERROR(ZOLTAN_FATAL,
          "Not supported: Multiple 3rd party libraries with incompatible "
          "data types.");
    return ZOLTAN_FATAL;
  }
#endif
#endif

  memset(&gr, 0, sizeof(ZOLTAN_Third_Graph));
  memset(&ord, 0, sizeof(ZOLTAN_Output_Order));
  memset(times, 0, sizeof(times));

  ord.order_opt = order_opt;

  if (!order_opt){
    /* If for some reason order_opt is NULL, allocate a new ZOOS here. */
    /* This should really never happen. */
    order_opt = (ZOOS *) ZOLTAN_MALLOC(sizeof(ZOOS));
    strcpy(order_opt->method,"PARMETIS");
  }

  ierr = Zoltan_Parmetis_Parse(zz, options, alg, NULL, NULL, &ord);
  /* ParMetis only computes the rank vector */
  order_opt->return_args = RETURN_RANK;

  /* Check that num_obj equals the number of objects on this proc. */
  /* This constraint may be removed in the future. */
  n = zz->Get_Num_Obj(zz->Get_Num_Obj_Data, &ierr);
  if ((ierr!= ZOLTAN_OK) && (ierr!= ZOLTAN_WARN)){
    /* Return error code */
    ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Get_Num_Obj returned error.");
    return(ZOLTAN_FATAL);
  }
  if (n != num_obj){
    /* Currently this is a fatal error. */
    ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Input num_obj does not equal the "
                                     "number of objects.");
    return(ZOLTAN_FATAL);
  }

  /* Do not use weights for ordering */
  gr.obj_wgt_dim = -1;
  gr.edge_wgt_dim = -1;
  gr.num_obj = num_obj;

  /* Check what ordering type is requested */
  if (order_opt){
      SET_GLOBAL_GRAPH(&gr.graph_type); /* GLOBAL by default */

#ifdef ZOLTAN_PARMETIS
      if ((strcmp(order_opt->method, "METIS") == 0))
#endif /* ZOLTAN_PARMETIS */
      SET_LOCAL_GRAPH(&gr.graph_type);
  }
  gr.get_data = 1;

  if (IS_LOCAL_GRAPH(gr.graph_type) && zz->Num_Proc > 1) {
    ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Serial ordering on more than 1 process: "
                                     "set ParMetis instead.");
    return(ZOLTAN_FATAL);
  }

  timer_p = Zoltan_Preprocess_Timer(zz, &use_timers);

    /* Start timer */
  get_times = (zz->Debug_Level >= ZOLTAN_DEBUG_ATIME);
  if (get_times){
    MPI_Barrier(zz->Communicator);
    times[0] = Zoltan_Time(zz->Timer);
  }

  ierr = Zoltan_Preprocess_Graph(zz, &l_gids, &l_lids,  &gr, NULL, NULL, NULL);
  if ((ierr != ZOLTAN_OK) && (ierr != ZOLTAN_WARN)) {
    Zoltan_Third_Exit(&gr, NULL, NULL, NULL, NULL, NULL);
    return (ierr);
  }

  /* Allocate space for separator sizes */

  if (IS_GLOBAL_GRAPH(gr.graph_type)) {
    if (Zoltan_TPL_Order_Init_Tree(&zz->TPL_Order, 2*zz->Num_Proc, zz->Num_Proc) != ZOLTAN_OK) {
      /* Not enough memory */
      Zoltan_Third_Exit(&gr, NULL, NULL, NULL, NULL, &ord);
      ZOLTAN_THIRD_ERROR(ZOLTAN_MEMERR, "Out of memory.");
    }
    ord.sep_sizes = (indextype*)ZOLTAN_MALLOC((2*zz->Num_Proc+1)*sizeof(indextype));
    if (ord.sep_sizes == NULL) {
      Zoltan_Third_Exit(&gr, NULL, NULL, NULL, NULL, &ord);
      ZOLTAN_THIRD_ERROR(ZOLTAN_MEMERR, "Out of memory.");
    }
    memset(ord.sep_sizes, 0, (2*zz->Num_Proc+1)*sizeof(int)); /* It seems parmetis don't initialize correctly */
  }

  /* Allocate space for direct perm */
  ord.rank = (indextype *) ZOLTAN_MALLOC(gr.num_obj*sizeof(indextype));
  if (!ord.rank){
    /* Not enough memory */
    Zoltan_Third_Exit(&gr, NULL, NULL, NULL, NULL, &ord);
    ZOLTAN_THIRD_ERROR(ZOLTAN_MEMERR, "Out of memory.");
  }
  if (IS_LOCAL_GRAPH(gr.graph_type)){
  /* Allocate space for inverse perm */
    ord.iperm = (indextype *) ZOLTAN_MALLOC(gr.num_obj*sizeof(indextype));
    if (!ord.iperm){
      /* Not enough memory */
      Zoltan_Third_Exit(&gr, NULL, NULL, NULL, NULL, &ord);
      ZOLTAN_THIRD_ERROR(ZOLTAN_MEMERR, "Out of memory.");
    }
  }
  else
    ord.iperm = NULL;

  /* Get a time here */
  if (get_times) times[1] = Zoltan_Time(zz->Timer);

#ifdef ZOLTAN_PARMETIS
  if (IS_GLOBAL_GRAPH(gr.graph_type)){
    ZOLTAN_TRACE_DETAIL(zz, yo, "Calling the ParMETIS library");

    ParMETIS_V3_NodeND (gr.vtxdist, gr.xadj, gr.adjncy, 
                        &numflag, options, ord.rank, ord.sep_sizes, &comm);
    ZOLTAN_TRACE_DETAIL(zz, yo, "Returned from the ParMETIS library");

  }
  else
#endif /* ZOLTAN_PARMETIS */
#if defined(ZOLTAN_METIS) || defined(ZOLTAN_PARMETIS)
 if (IS_LOCAL_GRAPH(gr.graph_type)) { /* Be careful : permutation parameters are in the opposite order */
    indextype numobj = gr.num_obj;
    ZOLTAN_TRACE_DETAIL(zz, yo, "Calling the METIS library");
    order_opt->return_args = RETURN_RANK|RETURN_IPERM; /* We provide directly all the permutations */
#if !defined(METIS_VER_MAJOR) || METIS_VER_MAJOR < 5
    options[0] = 0;  /* Use default options for METIS. */
    METIS_NodeND(&numobj, gr.xadj, gr.adjncy, &numflag, options, 
                 ord.iperm, ord.rank);
#else
    METIS_SetDefaultOptions(options);
    METIS_NodeND(&numobj, gr.xadj, gr.adjncy, NULL, options, 
                 ord.iperm, ord.rank); /* NULL is vwgt -- new interface in v4 */
#endif


    ZOLTAN_TRACE_DETAIL(zz, yo, "Returned from the METIS library");
  }
#endif /* ZOLTAN_METIS */

  /* Get a time here */
  if (get_times) times[2] = Zoltan_Time(zz->Timer);

  if (IS_GLOBAL_GRAPH(gr.graph_type)){ /* Update Elimination tree */
    int numbloc;
    int start;
    int leaf;
    int *converttab;
    int levelmax;

    levelmax = mylog2(zz->Num_Proc) + 1;
    converttab = (int*)ZOLTAN_MALLOC(zz->Num_Proc*2*sizeof(int));

    memset(converttab, 0, zz->Num_Proc*2*sizeof(int));
     /* Determine the first node in each separator, store it in zz->TPL_Order.start */
    for (numbloc = 0, start=0, leaf=0; numbloc < zz->Num_Proc /2; numbloc++) {
      int father;

      father = zz->Num_Proc + numbloc;
      converttab[start] = 2*numbloc;
      zz->TPL_Order.leaves[leaf++]=start;
      zz->TPL_Order.ancestor[start] = start + 2;
      converttab[start+1] = 2*numbloc+1;
      zz->TPL_Order.leaves[leaf++]=start+1;
      zz->TPL_Order.ancestor[start+1] = start + 2;
      start+=2;
      do {
        converttab[start] = father;
        if (father %2 == 0) {
          int nextoffset;
          int level;

          level = mylog2(2*zz->Num_Proc - 1 - father);
          nextoffset = (1<<(levelmax-level));
          zz->TPL_Order.ancestor[start] = start+nextoffset;
          start++;
          break;
        }
        else {
          zz->TPL_Order.ancestor[start] = start+1;
          start++;
          father = zz->Num_Proc + father/2;
        }
      } while (father < 2*zz->Num_Proc - 1);
    }

    zz->TPL_Order.start[0] = 0;
    zz->TPL_Order.ancestor [2*zz->Num_Proc - 2] = -1;
    for (numbloc = 1 ; numbloc < 2*zz->Num_Proc ; numbloc++) {
      int oldblock=converttab[numbloc-1];
      zz->TPL_Order.start[numbloc] = zz->TPL_Order.start[numbloc-1] + ord.sep_sizes[oldblock];
    }

    ZOLTAN_FREE(&converttab);
    ZOLTAN_FREE(&ord.sep_sizes);

    zz->TPL_Order.leaves[zz->Num_Proc] = -1;
    zz->TPL_Order.nbr_leaves = zz->Num_Proc;
    zz->TPL_Order.nbr_blocks = 2*zz->Num_Proc-1;
  }
  else { /* No tree */
    zz->TPL_Order.nbr_blocks = 0;
    zz->TPL_Order.start = NULL;
    zz->TPL_Order.ancestor = NULL;
    zz->TPL_Order.leaves = NULL;
  }

  /* Correct because no redistribution */
  memcpy(gids, l_gids, n*zz->Num_GID*sizeof(ZOLTAN_ID_TYPE));
  memcpy(lids, l_lids, n*zz->Num_LID*sizeof(ZOLTAN_ID_TYPE));

  ierr = Zoltan_Postprocess_Graph (zz, l_gids, l_lids, &gr, NULL, NULL, NULL, &ord, NULL);

  ZOLTAN_FREE(&l_gids); 
  ZOLTAN_FREE(&l_lids);

  /* Get a time here */
  if (get_times) times[3] = Zoltan_Time(zz->Timer);

  if (get_times) Zoltan_Third_DisplayTime(zz, times);

  if (use_timers)
    ZOLTAN_TIMER_STOP(zz->ZTime, timer_p, zz->Communicator);

  if (sizeof(indextype) == sizeof(ZOLTAN_ID_TYPE)){
    memcpy(rank, ord.rank, gr.num_obj*sizeof(indextype));
  }
  else{
    for (i=0; i < gr.num_obj; i++){
      rank[i] = (ZOLTAN_ID_TYPE)ord.rank[i];
    }
  }

  if ((ord.iperm != NULL) && (iperm != NULL)){
    if (sizeof(indextype) == sizeof(int)){
      memcpy(iperm, ord.iperm, gr.num_obj*sizeof(indextype));
    }
    else{
      for (i=0; i < gr.num_obj; i++){
        iperm[i] = (int)ord.iperm[i];
      }
    }
  }

  if (ord.iperm != NULL)  ZOLTAN_FREE(&ord.iperm);
  ZOLTAN_FREE(&ord.rank);

  /* Free all other "graph" stuff */
  Zoltan_Third_Exit(&gr, NULL, NULL, NULL, NULL, NULL);

  ZOLTAN_TRACE_EXIT(zz, yo);

  return (ZOLTAN_OK);
}
Exemple #15
0
void
get_metis(
	  int_t n,         /* dimension of matrix B */
	  int_t bnz,       /* number of nonzeros in matrix A. */
	  int_t *b_colptr, /* column pointer of size n+1 for matrix B. */
	  int_t *b_rowind, /* row indices of size bnz for matrix B. */
	  int_t *perm_c    /* out - the column permutation vector. */
	  )
{
    /*#define METISOPTIONS 8*/
#define METISOPTIONS 40
    int_t metis_options[METISOPTIONS];
    int_t ct, i, j, nm, numflag = 0; /* C-Style ordering */
    int_t *perm, *iperm;
    int_t *b_colptr_int, *b_rowind_int;
    extern int check_perm_dist(char *what, int_t n, int_t *perm);

    extern int METIS_NodeND(int_t*, int_t*, int_t*, int_t*, int_t*,
			    int_t*, int_t*);

    metis_options[0] = 0; /* Use Defaults for now */

    perm = (int_t*) SUPERLU_MALLOC(2*n * sizeof(int_t));
    if (!perm) ABORT("SUPERLU_MALLOC fails for perm.");
    iperm = perm + n;
    nm = n;

#if 0
#if defined(_LONGINT)
    /* Metis can only take 32-bit integers */

    if ( !(b_colptr_int = (int*) SUPERLU_MALLOC((n+1) * sizeof(int))) )
	 ABORT("SUPERLU_MALLOC fails for b_colptr_int.");
    for (i = 0; i < n+1; ++i) b_colptr_int[i] = b_colptr[i];
    SUPERLU_FREE(b_colptr);
    
    if ( !(b_rowind_int = (int*) SUPERLU_MALLOC(bnz * sizeof(int))) )
	ABORT("SUPERLU_MALLOC fails for b_rowind_int.");

    for (i = 0; i < bnz; ++i) b_rowind_int[i] = b_rowind[i];
    SUPERLU_FREE(b_rowind);
#else
    b_colptr_int = b_colptr;
    b_rowind_int = b_rowind;
#endif
#endif

    /* Call metis */
#undef USEEND
#ifdef USEEND
    METIS_EdgeND(&nm, b_colptr_int, b_rowind_int, &numflag, metis_options,
		 perm, iperm);
#else

    /* Earlier version 3.x.x */
    /* METIS_NodeND(&nm, b_colptr, b_rowind, &numflag, metis_options,
       perm, iperm);*/

    /* Latest version 4.x.x */
    METIS_NodeND(&nm, b_colptr, b_rowind, NULL, NULL, perm, iperm);

    /*check_perm_dist("metis perm",  n, perm);*/
#endif

    /* Copy the permutation vector into SuperLU data structure. */
    for (i = 0; i < n; ++i) perm_c[i] = iperm[i];

#if 0
    SUPERLU_FREE(b_colptr_int);
    SUPERLU_FREE(b_rowind_int);
#else
    SUPERLU_FREE(b_colptr);
    SUPERLU_FREE(b_rowind);
#endif
    SUPERLU_FREE(perm);
}
static void 
taucs_ccs_metis(taucs_ccs_matrix* m, 
		int** perm, int** invperm,
		char* which)
{
#ifndef TAUCS_CONFIG_METIS
  taucs_printf("taucs_ccs_metis: METIS routines not linked.\n");
  *perm    = NULL;
  *invperm = NULL;
  return;
#else
  int  n,nnz,i,j,ip;
  int* xadj;
  int* adj;
  int  num_flag     = 0;
  int  options_flag = 0;
  int* len;
  int* ptr;

  /* taucs_printf("taucs_ccs_metis: starting (%s)\n",which); */

  if (!(m->flags & TAUCS_SYMMETRIC) && !(m->flags & TAUCS_HERMITIAN)) {
    taucs_printf("taucs_ccs_treeorder: METIS ordering only works on symmetric matrices.\n");
    *perm    = NULL;
    *invperm = NULL;
    return;
  }
  /* this routine may actually work on UPPER as well */
  if (!(m->flags & TAUCS_LOWER)) {
    taucs_printf("taucs_ccs_metis: the lower part of the matrix must be represented.\n");
    *perm    = NULL;
    *invperm = NULL;
    return;
  }

  n   = m->n;
  nnz = (m->colptr)[n];
  
  *perm    = (int*) taucs_malloc(n * sizeof(int));
  *invperm = (int*) taucs_malloc(n * sizeof(int));

  xadj = (int*) taucs_malloc((n+1) * sizeof(int));
  /* Change suggested by Yifan Hu for diagonal matrices */
  /* and for matrices with no diagonal */
  /* adj  = (int*) taucs_malloc(2*(nnz-n) * sizeof(int));*/
  adj  = (int*) taucs_malloc(2* nnz * sizeof(int));

  if (!(*perm) || !(*invperm) || !xadj || !adj) {
    taucs_free(*perm);
    taucs_free(*invperm);
    taucs_free(xadj);
    taucs_free(adj);
    *perm = *invperm = NULL;
    return;
  }

  /* assert(*perm && *invperm && xadj && adj);*/

  ptr = len = *perm;

  for (i=0; i<n; i++) len[i] = 0;

  for (j=0; j<n; j++) {
    for (ip = (m->colptr)[j]; ip < (m->colptr)[j+1]; ip++) {
      /*i = (m->rowind)[ip] - (m->indshift);*/
      i = (m->rowind)[ip];
      if (i != j) {
	len[i] ++;
	len[j] ++;
      }
    }
  }

  xadj[0] = 0;
  for (i=1; i<=n; i++) xadj[i] = xadj[i-1] + len[i-1];
  
  for (i=0; i<n; i++) ptr[i] = xadj[i];

  for (j=0; j<n; j++) {
    for (ip = (m->colptr)[j]; ip < (m->colptr)[j+1]; ip++) {
      /*i = (m->rowind)[ip] - (m->indshift);*/
      i = (m->rowind)[ip];
      if (i != j) {
	adj[ ptr[i] ] = j;
	adj[ ptr[j] ] = i;
	ptr[i] ++;
	ptr[j] ++;
      }
    }
  }

  /* taucs_printf("taucs_ccs_metis: calling metis matrix is %dx%d, nnz=%d\n", */
	     /* n,n,nnz); */

  METIS_NodeND(&n,
	       xadj,adj,
	       &num_flag, &options_flag,
	       *perm,*invperm);

  /* taucs_printf("taucs_ccs_metis: metis returned\n"); */

  /*
  {
    FILE* f;
    f=fopen("p.ijv","w");
    for (i=0; i<n; i++) fprintf(f,"%d\n",last[i]);
    fclose(f);
  }
  */

  taucs_free(xadj);
  taucs_free(adj);
#endif
}