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; }
/* 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 }
/** * 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); }
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); }
/************************************************************************* * 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]; } }
/* ************************************************************************* */ 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 }
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); }
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); }
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) ; }
/************************************************************************* * 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); }
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 }
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); }
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 }