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;
}
Example #2
0
  int gpartition(const vector< set<int> > &graph, int npartitions, int partition_method, vector<int> &decomp){  
    // If no partitioning method is set, choose a default.
    if(partition_method<0){
      if(npartitions<=8)
        partition_method = 0; // METIS PartGraphRecursive
      else
        partition_method = 1; // METIS PartGraphKway
    }

    int nnodes = graph.size();

    // Compress graph    
    vector<idxtype> xadj(nnodes+1), adjncy;
    int pos=0;
    xadj[0]=1;
    for(int i=0;i<nnodes;i++){
      for(set<int>::iterator jt=graph[i].begin();jt!=graph[i].end();jt++){
        adjncy.push_back(*jt);
        pos++;
      }
      xadj[i+1] = pos+1;
    }
    
    // Partition graph
    decomp.resize(nnodes);
    int wgtflag=0, numflag=1, edgecut=0;
#ifdef PARMETIS_V3
    int options[] = {0};
#else
    idx_t nbc=1;
    idx_t options[METIS_NOPTIONS];
    METIS_SetDefaultOptions(options);
    options[METIS_OPTION_NUMBERING]=1;
#endif
    if(partition_method){
#ifdef PARMETIS_V3
      METIS_PartGraphKway(&nnodes, &(xadj[0]), &(adjncy[0]), NULL, NULL, &wgtflag, 
                          &numflag, &npartitions, options, &edgecut, &(decomp[0]));
#else
      METIS_PartGraphKway(&nnodes,&nbc,&(xadj[0]),&(adjncy[0]), NULL, NULL,NULL,
			  &npartitions, NULL, NULL,options,&edgecut,
			  &(decomp[0]));
#endif
    }else{
#ifdef PARMETIS_V3
      METIS_PartGraphRecursive(&nnodes, &(xadj[0]), &(adjncy[0]), NULL, NULL, &wgtflag, 
                               &numflag, &npartitions, options, &edgecut, &(decomp[0]));
#else
      METIS_PartGraphRecursive(&nnodes,&nbc,&(xadj[0]),&(adjncy[0]), NULL, NULL,NULL,
			  &npartitions, NULL, NULL,options,&edgecut,
			  &(decomp[0]));
#endif
    }
    
    // number from zero
    for(int i=0;i<nnodes;i++)
      decomp[i]--;

    return edgecut;
  }
Example #3
0
void metis_wrapper(int *n, int *xadj, int *adjncy, int *nparts, int *part)
{
#ifndef METIS_VER_MAJOR
/* Metis 4.X (or METISLib in ParaMetis 3.X) */

  int edgecut;
  int wgtflag = 0;
  int numflag = 1;  /* fortran-stype numbering */
  int options[5] = { 0, 3, 1, 1, 0 };  /* default values */

  METIS_PartGraphRecursive(n, xadj, adjncy, NULL, NULL, &wgtflag, &numflag,
                           nparts, options, &edgecut, part);

#elif METIS_VER_MAJOR == 5
/* Metis 5.X */

  int edgecut;
  int ncon = 1;
  int options[METIS_NOPTIONS];

  METIS_SetDefaultOptions(options);
  options[METIS_OPTION_NUMBERING] = 1;  /* fortran-stype numbering */

  METIS_PartGraphRecursive(n, &ncon, xadj, adjncy, NULL, NULL, NULL,
                           nparts, NULL, NULL, options, &edgecut, part);

#else
#error unknown Metis version
#endif
}
Example #4
0
std::vector<bool>balanced_min_cut(const ListGraph&g){
	assert(g.is_valid());

	#ifndef USE_CUT_ORDER
	return {};
	#else

	std::vector<int>out_begin;
	std::vector<int>out_dest;

	build_adj_array(out_begin, out_dest, 
		g.node_count(), g.arc.size(),
		[&](int x){return g.arc[x].source;},
		[&](int x){return g.arc[x].target;}
	);

	std::vector<int>part(g.node_count());

	// Call METIS
	int one = 1, two = 2, ignore, node_count = g.node_count();

	idx_t options[METIS_NOPTIONS];
	METIS_SetDefaultOptions(options);
	options[METIS_OPTION_NUMBERING] = 0;

	options[METIS_OPTION_CONTIG] = 1;
	options[METIS_OPTION_UFACTOR] = 100;

	//options[METIS_OPTION_NCUTS] = 10;

	METIS_PartGraphKway(
		(idx_t*)&node_count,
		(idx_t*)&one,
		(idx_t*)&out_begin[0],
		(idx_t*)&out_dest[0],
		nullptr,
		nullptr,
		nullptr,
		(idx_t*)&two,
		nullptr,
		nullptr,
		options,
		(idx_t*)&ignore,
		(idx_t*)&part[0]
	);

	std::vector<bool>part_ret(g.node_count());
	for(int i=0; i<g.node_count(); ++i)
		part_ret[i] = part[i] == 0;

	return std::move(part_ret);
	#endif
}
Example #5
0
/* Interface for metis k-way partitioning with 64-bit ints */
void MUMPS_CALL
MUMPS_METIS_KWAY_64(MUMPS_INT8 *n,     MUMPS_INT8 *iptr,
                 MUMPS_INT8 *jcn,   MUMPS_INT8 *k,
                 MUMPS_INT8 *part)
/* n     -- the size of the graph to be partitioned
   iptr  -- pointer to the beginning of each node's adjacency list
   jcn   -- jcn[iptr[i]:iptr[i+1]-1] contains the list of neighbors of node i
   k     -- the number of parts
   part  -- part[i] is the part node i belongs to */
/* SELECTIVE I8 FIXME: add an argument *ierr, check it on exit */
 {
#if defined(metis4) || defined(parmetis3)
  MUMPS_INT numflag, edgecut, wgtflag, options[8];
  MUMPS_INT kINT, nINT;
  options[0] = 0;
  /* unweighted partitioning */
  wgtflag    = 0;
  /* Use 1-based fortran numbering */
  numflag    = 1;
  /* n and k are MUMPS_INT */
  nINT=(MUMPS_INT)(*n);
  kINT=(MUMPS_INT)(*k);
/* void METIS_PartGraphKway(int *, idxtype *, idxtype *, idxtype *, idxtype *, int *, int *, int *, int *, int *, idxtype *); */
  METIS_PartGraphKway(&nINT, iptr, jcn,
                      NULL, NULL, &wgtflag,
                      &numflag, &kINT,
                      options, &edgecut,
                      part);
#else /* METIS >= 5 */
  int ierr;
#  if (IDXTYPEWIDTH == 64)
  MUMPS_INT8 ncon, edgecut, options[40];
  ierr=METIS_SetDefaultOptions(options);
  options[0]  = 0;
  /* Use 1-based fortran numbering */
  options[17] = 1;
  ncon        = 1;
     ierr = METIS_PartGraphKway(n, &ncon, iptr, jcn,
     NULL, NULL, NULL,
     k, NULL, NULL, options,
     &edgecut, part);
#  else
     printf("** Error: METIS version >= 4, IDXTYPE WIDTH !=64, but MUMPS_METIS_KWAY_64 was called\n");
     ierr=1;
#  endif
#endif
  return;
 }
Example #6
0
	/*! \brief It set Metis on test
	 *
	 * \param testing set to true to disable the testing
	 *
	 * At the moment disable the seed randomness to keep the result
	 * reproducible
	 *
	 */
	void onTest(bool testing)
	{
		if (testing == false)
			return;

		if (Mg.options == NULL)
		{
			// allocate
			Mg.options = new idx_t[METIS_NOPTIONS];

			// set default options
			METIS_SetDefaultOptions(Mg.options);
		}

		Mg.options[METIS_OPTION_SEED] = 0;
	}
Example #7
0
std::vector<int> MetisMeshPartition(const CMesh* mesh, int nPart)
{
	int vertCount = mesh->vertCount();
	std::vector<int> vPart(vertCount);
	int ncon = 1;
	std::vector<int> xadj, adjncy;
    ZGeom::getMeshGraphCSR(*mesh, xadj, adjncy);
	int objval;
	int options[METIS_NOPTIONS];
	METIS_SetDefaultOptions(options);
	options[METIS_OPTION_CONTIG] = 1;
	options[METIS_OPTION_NUMBERING] = 0;

	METIS_PartGraphKway(&vertCount, &ncon, &xadj[0], &adjncy[0], NULL, NULL, NULL, &nPart, NULL, NULL, NULL, &objval, &vPart[0]);

	return vPart;
}
Example #8
0
int do_metis_kway_partition(network_t *network, options_t *opt, idx_t *part, idx_t mode) {
    int ret = ORCC_OK;
    idx_t ncon = 1;
    idx_t metis_opt[METIS_NOPTIONS];
    idx_t objval;
    adjacency_list *graph, *metis_graph;
    assert(network != NULL);
    assert(opt != NULL);
    assert(part != NULL);

    print_orcc_trace(ORCC_VL_VERBOSE_1, "Applying METIS Kway partition for mapping");

    METIS_SetDefaultOptions(metis_opt);
    metis_opt[METIS_OPTION_OBJTYPE] = mode;
    metis_opt[METIS_OPTION_CONTIG] = 0;  /* 0 or 1 */

    graph = set_graph_from_network(network);
    metis_graph = fix_graph_for_metis(graph);

    ret = METIS_PartGraphKway(&metis_graph->nb_vertices, /* idx_t *nvtxs */
                              &ncon, /*idx_t *ncon*/
                              metis_graph->xadj, /*idx_t *xadj*/
                              metis_graph->adjncy, /*idx_t *adjncy*/
                              metis_graph->vwgt, /*idx_t *vwgt*/
                              NULL, /*idx_t *vsize*/
                              metis_graph->adjwgt, /*idx_t *adjwgt*/
                              &opt->nb_processors, /*idx_t *nparts*/
                              NULL, /*real t *tpwgts*/
                              NULL, /*real t ubvec*/
                              metis_opt, /*idx_t *options*/
                              &objval, /*idx_t *objval*/
                              part); /*idx_t *part*/
    check_metis_error(ret);

    print_orcc_trace(ORCC_VL_VERBOSE_2, "METIS Edgecut : %d", objval);

    delete_graph(graph);
    delete_graph(metis_graph);
    return ret;
}
Example #9
0
/***********************************************************************************
* This function is the entry point of the parallel kmetis algorithm that uses
* coordinates to compute an initial graph distribution.
************************************************************************************/
int ParMETIS_V3_PartGeomKway(idx_t *vtxdist, idx_t *xadj, idx_t *adjncy,
        idx_t *vwgt, idx_t *adjwgt, idx_t *wgtflag, idx_t *numflag, idx_t *ndims, 
	real_t *xyz, idx_t *ncon, idx_t *nparts, real_t *tpwgts, real_t *ubvec, 
	idx_t *options, idx_t *edgecut, idx_t *part, MPI_Comm *comm)
{
  idx_t h, i, j, npes, mype, status, nvtxs, seed, dbglvl;
  idx_t cut, gcut, maxnvtxs;
  idx_t moptions[METIS_NOPTIONS];
  ctrl_t *ctrl;
  graph_t *graph, *mgraph;
  real_t balance;
  size_t curmem;

  /* Check the input parameters and return if an error */
  status = CheckInputsPartGeomKway(vtxdist, xadj, adjncy, vwgt, adjwgt, wgtflag,
                numflag, ndims, xyz, ncon, nparts, tpwgts, ubvec, options, 
                edgecut, part, comm);
  if (GlobalSEMinComm(*comm, status) == 0)
    return METIS_ERROR;

  status = METIS_OK;
  gk_malloc_init();
  curmem = gk_GetCurMemoryUsed();

  /* Setup the ctrl */
  ctrl = SetupCtrl(PARMETIS_OP_GKMETIS, options, *ncon, *nparts, tpwgts, ubvec, *comm);
  npes = ctrl->npes;
  mype = ctrl->mype;

  /* Take care the nparts == 1 case */
  if (*nparts == 1) {
    iset(vtxdist[mype+1]-vtxdist[mype], (*numflag == 0 ? 0 : 1), part);
    *edgecut = 0;
    goto DONE;
  }


  /* Take care of npes == 1 case */
  if (npes == 1) {
    nvtxs = vtxdist[1] - vtxdist[0];  /* subtraction is required when numflag==1 */

    METIS_SetDefaultOptions(moptions);
    moptions[METIS_OPTION_NUMBERING] = *numflag;

    status = METIS_PartGraphKway(&nvtxs, ncon, xadj, adjncy, vwgt, NULL, adjwgt, 
                 nparts, tpwgts, ubvec, moptions, edgecut, part);

    goto DONE;
  }


  /* Setup the graph */
  if (*numflag > 0)
    ChangeNumbering(vtxdist, xadj, adjncy, part, npes, mype, 1);

  graph = SetupGraph(ctrl, *ncon, vtxdist, xadj, vwgt, NULL, adjncy, adjwgt, *wgtflag);
  gk_free((void **)&graph->nvwgt, LTERM); 


  /* Allocate the workspace */
  AllocateWSpace(ctrl, 10*graph->nvtxs);


  /* Compute the initial npes-way partitioning geometric partitioning */
  STARTTIMER(ctrl, ctrl->TotalTmr);

  Coordinate_Partition(ctrl, graph, *ndims, xyz, 1);

  STOPTIMER(ctrl, ctrl->TotalTmr);


  /* Move the graph according to the partitioning */
  STARTTIMER(ctrl, ctrl->MoveTmr);

  ctrl->nparts = npes;
  mgraph = MoveGraph(ctrl, graph);
  ctrl->nparts = *nparts;

  SetupGraph_nvwgts(ctrl, mgraph); /* compute nvwgts for the moved graph */

  if (ctrl->dbglvl&DBG_INFO) {
    CommInterfaceData(ctrl, graph, graph->where, graph->where+graph->nvtxs);
    for (cut=0, i=0; i<graph->nvtxs; i++) {
      for (j=graph->xadj[i]; j<graph->xadj[i+1]; j++) {
        if (graph->where[i] != graph->where[graph->adjncy[j]])
          cut += graph->adjwgt[j];
      }
    }
    gcut     = GlobalSESum(ctrl, cut)/2;
    maxnvtxs = GlobalSEMax(ctrl, mgraph->nvtxs);
    balance  = (real_t)(maxnvtxs)/((real_t)(graph->gnvtxs)/(real_t)(npes));
    rprintf(ctrl, "XYZ Cut: %6"PRIDX" \tBalance: %6.3"PRREAL" [%"PRIDX" %"PRIDX" %"PRIDX"]\n",
       gcut, balance, maxnvtxs, graph->gnvtxs, npes);
  }

  STOPTIMER(ctrl, ctrl->MoveTmr);


  /* Compute the partition of the moved graph */
  STARTTIMER(ctrl, ctrl->TotalTmr);

  ctrl->CoarsenTo = gk_min(vtxdist[npes]+1, 25*(*ncon)*gk_max(npes, *nparts));

  if (vtxdist[npes] < SMALLGRAPH 
      || vtxdist[npes] < npes*20 
      || GlobalSESum(ctrl, mgraph->nedges) == 0) { /* serially */
    IFSET(ctrl->dbglvl, DBG_INFO, 
        rprintf(ctrl, "Partitioning a graph of size %"PRIDX" serially\n", vtxdist[npes]));
    PartitionSmallGraph(ctrl, mgraph);
  }
  else { /* in parallel */
    Global_Partition(ctrl, mgraph);
  }

  ParallelReMapGraph(ctrl, mgraph);

  /* Invert the ordering back to the original graph */
  ctrl->nparts = npes;
  ProjectInfoBack(ctrl, graph, part, mgraph->where);
  ctrl->nparts = *nparts;

  *edgecut = mgraph->mincut;

  STOPTIMER(ctrl, ctrl->TotalTmr);


  /* Print some stats */
  IFSET(ctrl->dbglvl, DBG_TIME, PrintTimingInfo(ctrl));
  IFSET(ctrl->dbglvl, DBG_TIME, gkMPI_Barrier(ctrl->gcomm));
  IFSET(ctrl->dbglvl, DBG_INFO, PrintPostPartInfo(ctrl, mgraph, 0));

  FreeGraph(mgraph);
  FreeInitialGraphAndRemap(graph);

  if (*numflag > 0)
    ChangeNumbering(vtxdist, xadj, adjncy, part, npes, mype, 0);

DONE:
  FreeCtrl(&ctrl);
  if (gk_GetCurMemoryUsed() - curmem > 0) {
    printf("ParMETIS appears to have a memory leak of %zdbytes. Report this.\n",
        (ssize_t)(gk_GetCurMemoryUsed() - curmem));
  }
  gk_malloc_cleanup(0);

  return (int)status;
}
Example #10
0
void FC_FUNC_(oct_metis_setdefaultoptions, OCT_METIS_SETDEFAULTOPTIONS)
     (idx_t *options)
{
  METIS_SetDefaultOptions(options);
}
Example #11
0
/*
 * Assign loop iterations to tiles carving partitions out of /seedLoop/ using
 * the METIS library.
 */
static int* metis(loop_t* seedLoop, int tileSize, map_list* meshMaps,
                  int* nCore, int* nExec, int* nNonExec, int nThreads)
{
  int i;
  int setCore = seedLoop->set->core;
  int setSize = seedLoop->set->size;

  // use the mesh description to find a suitable map for partitioning through METIS
  map_t* map = NULL;
  map_list::const_iterator it, end;
  for (it = meshMaps->begin(), end = meshMaps->end(); it != end; it++) {
    if (set_eq(seedLoop->set, (*it)->inSet) || set_eq(seedLoop->set, (*it)->outSet)) {
      map = *it;
      break;
    }
  }
  if (! map) {
    // unfortunate scenario: the user provided a mesh description, but the loop picked
    // as seed has an iteration space which is not part of the mesh description.
    // will have to revert to chunk partitioning
    return NULL;
  }

  // now partition through METIS:
  // ... mesh geometry
  int nElements = map->inSet->size;
  int nNodes = map->outSet->size;
  int nParts = nElements / tileSize;
  int arity = map->size / nElements;
  // ... data needed for partitioning
  int* indMap = new int[nElements];
  int* indNodesMap = new int[nNodes];
  int* adjncy = map->values;
  int* offsets = new int[nElements+1]();
  for (i = 1; i < nElements+1; i++) {
    offsets[i] = offsets[i-1] + arity;
  }
  // ... options
  int result, objval, ncon = 1;
  int options[METIS_NOPTIONS];
  METIS_SetDefaultOptions(options);
  options[METIS_OPTION_NUMBERING] = 0;
  options[METIS_OPTION_CONTIG] = 1;
  // ... do partition!
  result = (arity == 2) ?
    METIS_PartGraphKway (&nNodes, &ncon, offsets, adjncy, NULL, NULL, NULL,
                         &nParts, NULL, NULL, options, &objval, indMap) :
    METIS_PartMeshNodal (&nElements, &nNodes, offsets, adjncy, NULL, NULL,
                         &nParts, NULL, options, &objval, indMap, indNodesMap);
  ASSERT(result == METIS_OK, "Invalid METIS partitioning");

  // what's the target iteration set ?
  if (set_eq(seedLoop->set, map->inSet)) {
    delete[] indNodesMap;
  }
  else {
    // note: must be set_eq(seedLoop->set, map-outSet)
    delete[] indMap;
    indMap = indNodesMap;
  }
  delete[] offsets;

  // restrict partitions to the core region
  std::fill (indMap + setCore, indMap + setSize, 0);
  std::set<int> partitions (indMap, indMap + setCore);
  // ensure the set of partitions IDs is compact (i.e., if we have a partitioning
  // 0: {0,1,...}, 1: {4,5,...}, 2: {}, 3: {6,10,...} ...
  // we instead want to have
  // 0: {0,1,...}, 1: {4,5,...}, 2: {6,10,...}, ...
  std::map<int, int> mapper;
  std::set<int>::const_iterator sIt, sEnd;
  for (i = 0, sIt = partitions.begin(), sEnd = partitions.end(); sIt != sEnd; sIt++, i++) {
    mapper[*sIt] = i;
  }
  for (i = 0; i < setCore; i++) {
    indMap[i] = mapper[indMap[i]];
  }
  *nCore = partitions.size();

  // partition the exec halo region
  chunk_halo (seedLoop, tileSize, *nCore - 1, indMap, nExec, nNonExec, nThreads);

  return indMap;
}
Example #12
0
File: rbbdf.c Project: tttwwy/LMF
int main(int argc, char *argv[])
{
	idx_t options[METIS_NOPTIONS];
  	bigraph_t *bigraph;
  	idx_t *perm, *iperm;
  	params_t *params;
  	int status, i, j;

  	/* rdiags[i][0] and cdiags[i][0] saves the length of each array
  	 * excluding the first value */
  	idx_t **rdiags, **cdiags;
  	idx_t ndiags;

  	params = parse_cmdline(argc, argv);

  	gk_startcputimer(params->iotimer);
  	bigraph = ReadBiGraph(params);
  	gk_stopcputimer(params->iotimer);

  	if(bigraph == NULL){
  		printf("Input Error : nrows + ncols != nvtxs\n");
  		printf("\n***Metis returned with an error.\n");
  		return -1;
  	}

  	BDFPrintInfo(params, bigraph);

    METIS_SetDefaultOptions(options);
    /*User specific parameters*/
	options[METIS_OPTION_CTYPE]    = params->ctype;
	options[METIS_OPTION_IPTYPE]   = params->iptype;
	options[METIS_OPTION_RTYPE]    = params->rtype;
	options[METIS_OPTION_CCORDER]  = params->ccorder;
	options[METIS_OPTION_SEED]     = params->seed;
	options[METIS_OPTION_DBGLVL]   = params->dbglvl;
	options[METIS_OPTION_DENSITY] = params->density * DIVIDER;
	options[METIS_OPTION_NROWS] = params->nrows;
	options[METIS_OPTION_NCOLS] = params->ncols;
	options[METIS_OPTION_KAPPA] = params->kappa;
	options[METIS_OPTION_NDIAGS] = params->ndiags;

	/*Inner parameters*/
	options[METIS_OPTION_COMPRESS] = params->compress;
	options[METIS_OPTION_UFACTOR]  = params->ufactor;
	options[METIS_OPTION_PFACTOR]  = params->pfactor;
	options[METIS_OPTION_NCUTS] = params->ncuts;
	options[METIS_OPTION_NSEPS]    = params->nseps;
	options[METIS_OPTION_NITER]    = params->niter;
	options[METIS_OPTION_OBJTYPE] = params->objtype;

	perm  = imalloc(bigraph->super->nvtxs, "main: perm");
  	iperm = imalloc(bigraph->super->nvtxs, "main: iperm");

	gk_malloc_init();
	gk_startcputimer(params->parttimer);

	/* Initialize my global paramters */
	gk_clearcputimer(_parttimer);
	gk_clearcputimer(_nztimer);
	_totalcheck = 0;
	_firsthit = 0;
	_maxarea = -1;
	_maxnz = -1;
	_minarea = 700000000000;
	_minnz = 300000000;
	_avgarea = 0;
	_avgnz = 0;
	_maxdense = 0;
	_mindense = 0;

  	/* All the memory that is not allocated in this file should be allocated after
  	 * gk_malloc_init() and be freed before gk_GetCurMemoryUsed().
  	 * Memory that is allocated in this file should be free in the end of main()*/
  	status = METIS_NodeBDF(&bigraph->super->nvtxs, bigraph->super->xadj, bigraph->super->adjncy,
  			bigraph->super->vwgt, bigraph->nrows, bigraph->ncols,
  			options, bigraph->rlabel->label, bigraph->rlabel->ref, bigraph->clabel->label, bigraph->clabel->ref,
  			&rdiags, &cdiags, &ndiags, perm, iperm);

  	gk_stopcputimer(params->parttimer);

	if (gk_GetCurMemoryUsed() != 0)
    	printf("***It seems that Metis did not free all of its memory!\n");
	params->maxmemory = gk_GetMaxMemoryUsed();
	gk_malloc_cleanup(0);

	if (status != METIS_OK) {
		printf("\n***Metis returned with an error.\n");
	}
	else {
		if (! params->nooutput) {
	  		/* Write the permutation */
	  		gk_startcputimer(params->iotimer);
	  		WritePermutation(params->filename, iperm, bigraph->super->nvtxs);
	  		WriteDiags(params->filename, rdiags, cdiags, ndiags);
	  		gk_stopcputimer(params->iotimer);
		}
		BDFReportResults(params, bigraph);
	}

	/* free inner function memory */
	for (i = 0; i < ndiags; i++) {
		free((void*)rdiags[i]);
		free((void*)cdiags[i]);
	}
	free((void*)rdiags);
	free((void*)cdiags);

	/* free memroy allocated in this function */
	FreeBiGraph((ctrl_t*)NULL, &bigraph);
	gk_free((void **)&perm, &iperm, LTERM);
	gk_free((void **)&params->filename, &params->tpwgtsfile, &params->tpwgts,
	  &params->ubvec, &params, LTERM);

	return status;
}
Example #13
0
int
main (int argc, char **argv)
{
  // see Metis documentation (p.20 ff for Metis 5.x)

  /*----------------------------------------------------------------------------*/
  // example graph

  // 0 -- 3
  // |    |
  // 1    4
  // |  / |
  // 2    5

  // number of vertices
  idx_t n_vertex = 6;

  // size of xadj is n_vertex+1.
  // This array stores for every vertex i in xadj[i] the index
  // where the adjacent vertices are found in adjncy[].
  // Looking at the example graph:
  // Neighbors of vertex 0 are found starting at adjncy[0] and ending in adjncy[2-1],
  // i.e. one less than the starting point of the next vertex.
  // Neighbors of vertex 1 are found starting at adjncy[2] and ending in adjncy[4-1],
  // i.e. one less than the starting point of the next vertex.
  // etc.
  idx_t xadj[] = { 0, 2, 4, 6, 8, 11, 12 };

  // number of edges (see below: adjcny stores every edge twice as (u,v) and (v,u))
  idx_t n_edge = 6;

  // size of adjncy is 2 * n_edge (every edge appears twice in undirected graph)
  idx_t adjncy[] = {
    1, 3,	                       // neighbors of vertex 0
    0, 2,			       // neighbors of vertex 1
    1, 4,			       // neighbors of vertex 2
    0, 4,			       // neighbors of vertex 3
    2, 3, 5,			       // neighbors of vertex 4
    4				       // neighbors of vertex 5
  };

  // vertex weights (size of vwgt is n_vertex)
  idx_t vwgt[] = { 20, 30, 80, 60, 100, 90 };

  // edge weights (size of adjwgt is n_edge*2)
  idx_t adjwgt[] = { 10, 20, 10, 10, 10, 30, 20, 10, 30, 10, 10, 10 };

  // the resulting partition:
  // for every vertex i we find in part[i] afterwards the partition number for that vertex
  idx_t part[n_vertex];

  // Metis options (initialized to default values)
  idx_t options[METIS_NOPTIONS];
  METIS_SetDefaultOptions (options);
  // partitioning method: k-way partitioning
  options[METIS_OPTION_PTYPE] = METIS_PTYPE_KWAY;
  // edge cut minimization
  options[METIS_OPTION_OBJTYPE] = METIS_OBJTYPE_CUT;
  // C-style numbering
  options[METIS_OPTION_NUMBERING] = 0;

  // number of balancing constraints
  idx_t ncon = 1;

  // edge cut after partitioning
  idx_t edgecut;




  // !!!!!!!!!! you have to change this !!!!!!!!!!!!
  // number of partitions we want to partition to
  idx_t nparts = 2;
  // !!!!!!!!!! you have to change this !!!!!!!!!!!!



  /*--------------------------------------------------------------------------*/

  // print header and input graph
  printf ("partitioning graph with %ld vertices and %ld edges for %ld partitions\n", (long)n_vertex, (long)n_edge, (long)nparts);
  print_graph (n_vertex, vwgt, xadj, adjncy, adjwgt);


  // call graph partitioning
  double t0 = gettime ();
  int rc = METIS_PartGraphKway (&n_vertex,	// number of vertices
				&ncon,          // number of balancing constraints
				xadj,           // adjacency structure of graph
				adjncy,	        // adjacency structure of graph
				vwgt,           // vertex weights
				NULL,           // only for total communication volume
				adjwgt,	        // edge weights
				&nparts,	// number of partitions wanted
				NULL,           // tpwgts: no desired partition weights
				NULL,           // ubvec: allowed load imbalance
				options,	// special options
				&edgecut,	// objective value (edge cut)
				part     // vector with partition information for each vertex
	  );
  t0 = gettime () - t0;

  // check Metis return value
  switch (rc)
    {
      case METIS_OK:
	break;
      case METIS_ERROR_INPUT:
	printf ("error in Metis input\n");
	exit (1);
      case METIS_ERROR_MEMORY:
	printf ("no more memory in Metis\n");
	exit (1);
      case METIS_ERROR:
	printf ("some error in Metis\n");
	exit (1);
      default:
	printf ("unknown return code ffrom Metis\n");
	exit (1);
    }


  /*--------------------------------------------------------------------------*/
  /* print results */

  // time for partitioning
  printf ("partitioning time: %.9f s\n", t0);
  // print parition
  print_partition (n_vertex, vwgt, xadj, adjncy, adjwgt, part, nparts, edgecut);

  return 0;
}
Example #14
0
void MetisLB::work(LDStats* stats)
{
  /** ========================== INITIALIZATION ============================= */
  ProcArray *parr = new ProcArray(stats);
  ObjGraph *ogr = new ObjGraph(stats);

  /** ============================= STRATEGY ================================ */
  if (_lb_args.debug() >= 2) {
    CkPrintf("[%d] In MetisLB Strategy...\n", CkMyPe());
  }

  // convert ObjGraph to the adjacency structure
  int numVertices = ogr->vertices.size();	// number of vertices
  int numEdges = 0;				// number of edges

  double maxLoad = 0.0;
  int i, j, k, vert;

  /** remove duplicate edges from recvFrom */
  for(i = 0; i < numVertices; i++) {
    for(j = 0; j < ogr->vertices[i].sendToList.size(); j++) {
      vert = ogr->vertices[i].sendToList[j].getNeighborId();
      for(k = 0; k < ogr->vertices[i].recvFromList.size(); k++) {
	if(ogr->vertices[i].recvFromList[k].getNeighborId() == vert) {
	  ogr->vertices[i].sendToList[j].setNumBytes(ogr->vertices[i].sendToList[j].getNumBytes() + ogr->vertices[i].recvFromList[k].getNumBytes());
	  ogr->vertices[i].recvFromList.erase(ogr->vertices[i].recvFromList.begin() + k);
        }
      }
    }
  }

  /** the object load is normalized to an integer between 0 and 256 */
  for(i = 0; i < numVertices; i++) {
    if(ogr->vertices[i].getVertexLoad() > maxLoad)
      maxLoad = ogr->vertices[i].getVertexLoad();
    numEdges = numEdges + ogr->vertices[i].sendToList.size() + ogr->vertices[i].recvFromList.size();
  }

  /* adjacency list */
  idx_t *xadj = new idx_t[numVertices + 1];
  /* id of the neighbors */
  idx_t *adjncy = new idx_t[numEdges];
  /* weights of the vertices */
  idx_t *vwgt = new idx_t[numVertices];
  /* weights of the edges */
  idx_t *adjwgt = new idx_t[numEdges];

  int edgeNum = 0;
  double ratio = 256.0/maxLoad;

  for(i = 0; i < numVertices; i++) {
    xadj[i] = edgeNum;
    vwgt[i] = (int)ceil(ogr->vertices[i].getVertexLoad() * ratio);
    for(j = 0; j < ogr->vertices[i].sendToList.size(); j++) {
      adjncy[edgeNum] = ogr->vertices[i].sendToList[j].getNeighborId();
      adjwgt[edgeNum] = ogr->vertices[i].sendToList[j].getNumBytes();
      edgeNum++;
    }
    for(j = 0; j < ogr->vertices[i].recvFromList.size(); j++) {
      adjncy[edgeNum] = ogr->vertices[i].recvFromList[j].getNeighborId();
      adjwgt[edgeNum] = ogr->vertices[i].recvFromList[j].getNumBytes();
      edgeNum++;
    }
  }
  xadj[i] = edgeNum;
  CkAssert(edgeNum == numEdges);

  idx_t edgecut;		// number of edges cut by the partitioning
  idx_t *pemap;

  idx_t options[METIS_NOPTIONS];
  METIS_SetDefaultOptions(options);
  //options[METIS_OPTION_PTYPE] = METIS_PTYPE_RB;
  // C style numbering
  options[METIS_OPTION_NUMBERING] = 0;

  // number of constrains
  idx_t ncon = 1;
  // number of partitions
  idx_t numPes = parr->procs.size();
  real_t ubvec[ncon];
  // allow 10% imbalance
  ubvec[0] = 1.1;

  // mapping of objs to partitions
  pemap = new idx_t[numVertices];

  // Specifies size of vertices for computing the total communication volume
  idx_t *vsize = NULL;
  // This array of size nparts specifies the desired weight for each partition
  // and setting it to NULL indicates graph should be equally divided among
  // partitions
  real_t *tpwgts = NULL;

  int option = 0;
  if (WEIGHTED == option) {
    // set up the different weights between 0 and 1
    tpwgts = new real_t[numPes];
    for (i = 0; i < numPes; i++) {
      tpwgts[i] = 1.0/(real_t)numPes;
    }
  } else if (MULTI_CONSTRAINT == option) {
    CkAbort("Multiple constraints not implemented.\n");
  }

  // numVertices: num vertices in the graph; ncon: num balancing constrains
  // xadj, adjncy: of size n+1 and adjncy of 2m, adjncy[xadj[i]] through and
  // including adjncy[xadj[i+1]-1];
  // vwgt: weight of the vertices; vsize: amt of data that needs to be sent
  // for ith vertex is vsize[i]
  // adjwght: the weight of edges; numPes: total parts
  // tpwghts: target partition weight, can pass NULL to equally divide
  // ubvec: of size ncon to indicate allowed load imbalance tolerance (> 1.0)
  // options: array of options; edgecut: stores the edgecut; pemap: mapping
  METIS_PartGraphRecursive(&numVertices, &ncon,  xadj, adjncy, vwgt, vsize, adjwgt,
      &numPes, tpwgts, ubvec, options, &edgecut, pemap);

  delete[] xadj;
  delete[] adjncy;
  delete[] vwgt;
  delete[] adjwgt;
  delete[] vsize;
  delete[] tpwgts;

  if (_lb_args.debug() >= 1) {
   CkPrintf("[%d] MetisLB done! \n", CkMyPe());
  }

  for(i = 0; i < numVertices; i++) {
    if(pemap[i] != ogr->vertices[i].getCurrentPe())
      ogr->vertices[i].setNewPe(pemap[i]);
  }

  delete[] pemap;

  /** ============================== CLEANUP ================================ */
  ogr->convertDecisions(stats);
  delete parr;
  delete ogr;
}
Example #15
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 )

}
Example #16
0
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);
}
Example #17
0
idx_t* gpmetis( int argc, char **argv )
/*************************************************************************/
/*! Let the game begin! */
/*************************************************************************/
//int main(int argc, char *argv[])
{
  idx_t i;
  char *curptr, *newptr;
  idx_t options[METIS_NOPTIONS];
  graph_t *graph;
  idx_t *part;
  idx_t objval;
  params_t *params;
  int status=0;

  gk_optind = 0;

  //printf( "argc: %d\n", argc );
  //printf( "gk_optind %d\n", gk_optind );
  fflush( stdout );

    for( i = 0; i < argc; i++ )
    {
        //printf( "%s*\n", argv[ i ] );
    }


  params = parse_cmdline(argc, argv);
  //printf( "gk_optind %d\n", gk_optind );
  //fflush( stdout );
  //return NULL;

  gk_startcputimer(params->iotimer);
  graph = ReadGraph(params);

  ReadTPwgts(params, graph->ncon);
  gk_stopcputimer(params->iotimer);

  /* Check if the graph is contiguous */
  if (params->contig && !IsConnected(graph, 0)) {
    printf("***The input graph is not contiguous.\n"
           "***The specified -contig option will be ignored.\n");
    params->contig = 0;
  }

  /* Get ubvec if supplied */
  if (params->ubvecstr) {
    params->ubvec = rmalloc(graph->ncon, "main");
    curptr = params->ubvecstr;
    for (i=0; i<graph->ncon; i++) {
      params->ubvec[i] = strtoreal(curptr, &newptr);
      if (curptr == newptr)
        errexit("Error parsing entry #%"PRIDX" of ubvec [%s] (possibly missing).\n",
            i, params->ubvecstr);
      curptr = newptr;
    }
  }

  /* Setup iptype */
  if (params->iptype == -1) {
    if (params->ptype == METIS_PTYPE_RB) {
      if (graph->ncon == 1)
        params->iptype = METIS_IPTYPE_GROW;
      else
        params->iptype = METIS_IPTYPE_RANDOM;
    }
  }

  GPPrintInfo(params, graph);

  part = imalloc(graph->nvtxs, "main: part");

  METIS_SetDefaultOptions(options);
  options[METIS_OPTION_OBJTYPE] = params->objtype;
  options[METIS_OPTION_CTYPE]   = params->ctype;
  options[METIS_OPTION_IPTYPE]  = params->iptype;
  options[METIS_OPTION_RTYPE]   = params->rtype;
  options[METIS_OPTION_MINCONN] = params->minconn;
  options[METIS_OPTION_CONTIG]  = params->contig;
  options[METIS_OPTION_SEED]    = params->seed;
  options[METIS_OPTION_NITER]   = params->niter;
  options[METIS_OPTION_NCUTS]   = params->ncuts;
  options[METIS_OPTION_UFACTOR] = params->ufactor;
  options[METIS_OPTION_DBGLVL]  = params->dbglvl;

  gk_malloc_init();
  gk_startcputimer(params->parttimer);

  switch (params->ptype) {
    case METIS_PTYPE_RB:
      status = METIS_PartGraphRecursive(&graph->nvtxs, &graph->ncon, graph->xadj,
                   graph->adjncy, graph->vwgt, graph->vsize, graph->adjwgt,
                   &params->nparts, params->tpwgts, params->ubvec, options,
                   &objval, part);
      break;

    case METIS_PTYPE_KWAY:
      status = METIS_PartGraphKway(&graph->nvtxs, &graph->ncon, graph->xadj,
                   graph->adjncy, graph->vwgt, graph->vsize, graph->adjwgt,
                   &params->nparts, params->tpwgts, params->ubvec, options,
                   &objval, part);
      break;

  }

  gk_stopcputimer(params->parttimer);

  if (gk_GetCurMemoryUsed() != 0)
    printf("***It seems that Metis did not free all of its memory! Report this.\n");
  params->maxmemory = gk_GetMaxMemoryUsed();
  gk_malloc_cleanup(0);


  if (status != METIS_OK) {
    printf("\n***Metis returned with an error.\n");
  }
  else {
    if (!params->nooutput) {
      /* Write the solution */
      gk_startcputimer(params->iotimer);
      WritePartition(params->filename, part, graph->nvtxs, params->nparts);
      gk_stopcputimer(params->iotimer);
    }

    GPReportResults(params, graph, part, objval);
  }

  idx_t *r_part = ( idx_t* ) calloc( graph->nvtxs, sizeof( idx_t ) );

  for( i = 0; i < graph->nvtxs; i++ )
  {
       r_part[ i ] = part[ i ];
  }

  FreeGraph(&graph);
  gk_free((void **)&part, LTERM);
  gk_free((void **)&params->filename, &params->tpwgtsfile, &params->tpwgts,
      &params->ubvecstr, &params->ubvec, &params, LTERM);

  return r_part;
}
void InitKWayPartitioningRB(ctrl_t *ctrl, graph_t *graph)
{
  idx_t i, options[METIS_NOPTIONS], curobj=0;
  idx_t *bestwhere=NULL;
  real_t *ubvec=NULL;
  int status;

  METIS_SetDefaultOptions(options);
  options[METIS_OPTION_NITER]   = 10;
  options[METIS_OPTION_OBJTYPE] = METIS_OBJTYPE_CUT;
  options[METIS_OPTION_NO2HOP]  = ctrl->no2hop;
  options[METIS_OPTION_ONDISK]  = ctrl->ondisk;


  ubvec = rmalloc(graph->ncon, "InitKWayPartitioning: ubvec");
  for (i=0; i<graph->ncon; i++) 
    ubvec[i] = (real_t)pow(ctrl->ubfactors[i], 1.0/log(ctrl->nparts));


  switch (ctrl->objtype) {
    case METIS_OBJTYPE_CUT:
    case METIS_OBJTYPE_VOL:
      options[METIS_OPTION_NCUTS] = ctrl->nIparts;
      status = METIS_PartGraphRecursive(&graph->nvtxs, &graph->ncon, 
                   graph->xadj, graph->adjncy, graph->vwgt, graph->vsize, 
                   graph->adjwgt, &ctrl->nparts, ctrl->tpwgts, ubvec, 
                   options, &curobj, graph->where);

      if (status != METIS_OK)
        gk_errexit(SIGERR, "Failed during initial partitioning\n");

      break;

#ifdef XXX /* This does not seem to help */
    case METIS_OBJTYPE_VOL:
      bestwhere = imalloc(graph->nvtxs, "InitKWayPartitioning: bestwhere");
      options[METIS_OPTION_NCUTS] = 2;

      ntrials = (ctrl->nIparts+1)/2;
      for (i=0; i<ntrials; i++) {
        status = METIS_PartGraphRecursive(&graph->nvtxs, &graph->ncon, 
                     graph->xadj, graph->adjncy, graph->vwgt, graph->vsize, 
                     graph->adjwgt, &ctrl->nparts, ctrl->tpwgts, ubvec, 
                     options, &curobj, graph->where);
        if (status != METIS_OK)
          gk_errexit(SIGERR, "Failed during initial partitioning\n");

        curobj = ComputeVolume(graph, graph->where);

        if (i == 0 || bestobj > curobj) {
          bestobj = curobj;
          if (i < ntrials-1)
            icopy(graph->nvtxs, graph->where, bestwhere);
        }

        if (bestobj == 0)
          break;
      }
      if (bestobj != curobj)
        icopy(graph->nvtxs, bestwhere, graph->where);

      break;
#endif

    default:
      gk_errexit(SIGERR, "Unknown objtype: %d\n", ctrl->objtype);
  }

  gk_free((void **)&ubvec, &bestwhere, LTERM);

}
int MESH_PartitionWithMetis(Mesh_ptr mesh, int nparts, int **part) {

  MEdge_ptr fedge;
  MFace_ptr mf, oppf, rface;
  MRegion_ptr mr, oppr;
  List_ptr fedges, efaces, rfaces, fregions;
  int  i, ncells, ipos;
  int  nv, ne, nf, nr, nfe, nef, nfr, nrf, idx, idx2;
#ifdef METIS_5
  idx_t ngraphvtx, numflag, nedgecut, numparts, ncons;
  idx_t wtflag, metisopts[METIS_NOPTIONS];
  idx_t *vsize, *idxpart;
  idx_t  *xadj, *adjncy, *vwgt, *adjwgt;
  real_t *tpwgts, *ubvec;
#else
  idxtype ngraphvtx, numflag, nedgecut, numparts;
  idxtype  wtflag, metisopts[5] = {0,0,0,0,0};
  idxtype  *xadj, *adjncy, *vwgt, *adjwgt, *idxpart;
#endif
  

  /* First build a nodal graph of the mesh in the format required by
     metis */

  nv = MESH_Num_Vertices(mesh);
  ne = MESH_Num_Edges(mesh);
  nf = MESH_Num_Faces(mesh);
  nr = MESH_Num_Regions(mesh);

  ipos = 0;
  
  if (nr == 0) {
    
    if (nf == 0) {
      fprintf(stderr,"Cannot partition wire meshes\n");
      exit(-1);
    }

#ifdef METIS_5
    xadj = (idx_t *) malloc((nf+1)*sizeof(idx_t));
    adjncy = (idx_t *) malloc(2*ne*sizeof(idx_t));
#else    
    xadj = (idxtype *) malloc((nf+1)*sizeof(idxtype));
    adjncy = (idxtype *) malloc(2*ne*sizeof(idxtype));
#endif
    ncells = nf;

    /* Surface mesh */

    idx = 0; i = 0;
    xadj[i] = ipos;
    while ((mf = MESH_Next_Face(mesh,&idx))) {
      
      fedges = MF_Edges(mf,1,0);
      nfe = List_Num_Entries(fedges);
      
      idx2 = 0;
      while ((fedge = List_Next_Entry(fedges,&idx2))) {
	
	efaces = ME_Faces(fedge);
	nef = List_Num_Entries(efaces);
	
	if (nef == 1) {
	  continue;          /* boundary edge; nothing to do */
	}
	else {
          int j;
          for (j = 0; j < nef; j++) {
            oppf = List_Entry(efaces,j);
            if (oppf != mf) {
              adjncy[ipos] = MF_ID(oppf)-1;
              ipos++;
            }
          }
	}
	
	List_Delete(efaces);
	
      }
      
      List_Delete(fedges);
      
      i++;
      xadj[i] = ipos;
    }

  }
  else {

#ifdef METIS_5
    xadj = (idx_t *) malloc((nr+1)*sizeof(idx_t));
    adjncy = (idx_t *) malloc(2*nf*sizeof(idx_t));
#else
    xadj = (idxtype *) malloc((nr+1)*sizeof(idxtype));
    adjncy = (idxtype *) malloc(2*nf*sizeof(idxtype));
#endif
    ncells = nr;

    /* Volume mesh */

    idx = 0; i = 0;
    xadj[i] = ipos;
    while ((mr = MESH_Next_Region(mesh,&idx))) {
      
      rfaces = MR_Faces(mr);
      nrf = List_Num_Entries(rfaces);
      
      idx2 = 0;
      while ((rface = List_Next_Entry(rfaces,&idx2))) {
	
	fregions = MF_Regions(rface);
	nfr = List_Num_Entries(fregions);
	
	if (nfr > 1) {
	  oppr = List_Entry(fregions,0);
	  if (oppr == mr)
	    oppr = List_Entry(fregions,1);
	  
	  adjncy[ipos] = MR_ID(oppr)-1;
	  ipos++;
	}
        List_Delete(fregions);	
	
      }
      
      List_Delete(rfaces);
      
      i++;
      xadj[i] = ipos;
    }

  }
  


  /* Partition the graph */
  
  wtflag = 0;        /* No weights are specified */
  vwgt = adjwgt = NULL;

  numflag = 0;    /* C style numbering of elements (nodes of the dual graph) */
  ngraphvtx = ncells; /* we want the variable to be of type idxtype or idx_t */
  numparts = nparts;  /* we want the variable to be of type idxtype or idx_t */

#ifdef METIS_5
  idxpart = (idx_t *) malloc(ncells*sizeof(idx_t));

  ncons = 1;  /* Number of constraints */
  vsize = NULL;  
  tpwgts = NULL;
  ubvec = NULL;

  METIS_SetDefaultOptions(metisopts);
  metisopts[METIS_OPTION_NUMBERING] = 0;

  if (nparts <= 8)
    METIS_PartGraphRecursive(&ngraphvtx,&ncons,xadj,adjncy,vwgt,vsize,adjwgt,
			     &numparts,tpwgts,ubvec,metisopts,&nedgecut,
                             idxpart);
  else
    METIS_PartGraphKway(&ngraphvtx,&ncons,xadj,adjncy,vwgt,vsize,adjwgt,
                        &numparts,tpwgts,ubvec,metisopts,&nedgecut,idxpart);

#else

  idxpart = (idxtype *) malloc(ncells*sizeof(idxtype));

  if (nparts <= 8)
    METIS_PartGraphRecursive(&ngraphvtx,xadj,adjncy,vwgt,adjwgt,&wtflag,
			     &numflag,&numparts,metisopts,&nedgecut,idxpart);
  else
    METIS_PartGraphKway(&ngraphvtx,xadj,adjncy,vwgt,adjwgt,&wtflag,&numflag,
			&numparts,metisopts,&nedgecut,idxpart);
#endif

  free(xadj);
  free(adjncy);


  
  *part = (int *) malloc(ncells*sizeof(int));
  for (i = 0; i < ncells; i++)
    (*part)[i] = (int) idxpart[i];

  free(idxpart);
  return 1;

}
Example #20
0
int main()
{

  /* We aim to partition the following mesh into 4 parts:
   *  
   *  0---1---2---3---4
   *  |   |   |   |   |
   *  5---6---7---8---9
   *  |   |   |   |   |
   * 10--11--12--13--14
   *
   */
  const int nVertices = 15;
  const int nNeighs   = 44;
  idx_t xadj [nVertices+1] = { 0, 2, 5, 8, 11, 13, 16, 20, 24, 28, 31, 33, 36, 39, 42, 44 };
  idx_t adjncy [nNeighs] = { 1, 5, 0, 2, 6, 1, 3, 7, 2, 4, 8, 3, 9, 0, 6, 10, 1, 5, 7, 11,
		    2, 6, 8, 12, 3, 7, 9, 13, 4, 8, 14, 5, 11, 6, 10, 12, 7, 11,
		    13, 8, 12, 14, 9, 13 };

  std::cout << "Before Partitioning:" << std::endl;
  std::cout << std::endl;
  std::cout << "0---0---0---0---0" << std::endl;
  std::cout << "|   |   |   |   |" << std::endl;
  std::cout << "0---0---0---0---0" << std::endl;
  std::cout << "|   |   |   |   |" << std::endl;
  std::cout << "0---0---0---0---0" << std::endl;
  std::cout << std::endl;

  // partition the graph using metis
  idx_t nvtxs    = nVertices;         // number of vertices
  idx_t ncon     = 1;                 // number of balancing constraints
  idx_t *vwgt    = NULL;              // vertex weights
  idx_t *vsize   = NULL;              // vertex sizes
  idx_t *adjwgt  = NULL;              // edge weights
  idx_t nparts   = 4;                 // number of partitions
  real_t *tpwgts = NULL;              // target partition weight
  real_t *ubvec  = NULL;              // load balance tolerance for each constraint
  idx_t options[METIS_NOPTIONS];      // array of options
  METIS_SetDefaultOptions( options ); // use defaults
  idx_t objval;                       // edge-cut on return
  std::vector< idx_t > colors( nVertices, 0 ); // ranks
  
  int ierr = METIS_PartGraphRecursive( &nvtxs, &ncon, &xadj[0], &adjncy[0], vwgt, vsize,
				       adjwgt, &nparts, tpwgts, ubvec, options, &objval, &colors[0] );

  if ( ierr != METIS_OK )
    throw std::runtime_error( "METIS graph partitioning failed!" );
    
  std::cout << "After Partitioning:" << std::endl;
  std::cout << std::endl;
  std::cout << colors[0] << "---" << colors[1] << "---" << colors[2] <<
    "---" << colors[3] << "---" << colors[4] << std::endl;
  std::cout << "|   |   |   |   |" << std::endl;
  std::cout << colors[5] << "---" << colors[6] << "---" << colors[7] <<
    "---" << colors[8] << "---" << colors[9] << std::endl;
  std::cout << "|   |   |   |   |" << std::endl;
  std::cout << colors[10] << "---" << colors[11] << "---" << colors[12] <<
    "---" << colors[13] << "---" << colors[14] << std::endl;
  std::cout << std::endl;
  
  return 0;
}
Example #21
0
int generateLevels(std::vector< std::vector<sbfSElement *> >  & selements, std::vector<int> & numTargetByLayers, std::vector<double> &maxImbalance, bool verbouse){

	sbfMesh * mesh = selements[0][0]->mesh();
	if(!mesh) return 1;
	int numRegElems = selements[0].size();
    std::vector <double> facesWeigth;
	std::vector <int> facesOwners;
	std::vector <double> randoms;
	randoms.resize(50);
	for(size_t ct = 0; ct < randoms.size(); ct++) randoms[ct] = ((double)rand())/RAND_MAX;

	facesWeigth.reserve(numRegElems*50);
	facesOwners.reserve(numRegElems*50);

	for(int elemID = 0; elemID < numRegElems; elemID++){//Loop on elements
        sbfElement *elem = mesh->elemPtr(elemID);

		double faceWeigth;
		int facesOwner = elemID;
		std::list<int> inds;
		int count;

		std::vector< std::vector<int> > facesNodesIndexes = elem->facesNodesIndexes();
        for(auto itFace = facesNodesIndexes.begin(); itFace != facesNodesIndexes.end(); itFace++){//Loop on faces
			inds.clear();
            for(auto itIndex = (*itFace).begin(); itIndex != (*itFace).end(); itIndex++)
				inds.push_back(*itIndex);
			inds.sort();
            count = 0; faceWeigth = 0; for(auto it = inds.begin(); it != inds.end(); it++) {faceWeigth += *it*randoms[count++];}
			facesWeigth.push_back(faceWeigth);
			facesOwners.push_back(facesOwner);
		}//Loop on faces

	}//Loop on elements

	quickAssociatedSort<double, int>(&facesWeigth[0], &facesOwners[0], 0, facesWeigth.size()-1);

    if ( verbouse ) std::cout << "sort done" << std::endl;

	for(size_t ctLevel = 0; ctLevel < numTargetByLayers.size(); ctLevel++){//Loop on levels
		int numTargetSE = numTargetByLayers[ctLevel];
		int numSElems = selements[ctLevel].size();

		int vertnbr, edgenbr;
        vertnbr = numSElems;
        edgenbr = 0;

		std::vector< std::list <int> > elemNeibour;
        elemNeibour.resize(vertnbr);

		int founded = 0, unfounded = 0;

		std::vector <double> facesWeigthNextLevel;
		std::vector <int> facesOwnersNextLevel;
		facesWeigthNextLevel.reserve(facesWeigth.size());
		facesOwnersNextLevel.reserve(facesOwners.size());
        auto facesWeigthIt = facesWeigth.begin();
        auto facesOwnersIt = facesOwners.begin();
        auto facesWeigthEndM1 = facesWeigth.end() - 1;
		for(; facesWeigthIt < facesWeigthEndM1; facesWeigthIt++, facesOwnersIt++){
			if(*facesWeigthIt == *(facesWeigthIt+1)){
				//Check if *facesOwnersIt and *(facesOwnersIt+1) are in one SE
				int owner0, owner1;
				owner0 = *facesOwnersIt; owner1 = *(facesOwnersIt+1);
				int ownerSE0 = -1, ownerSE1 = -1;
				bool inSame = false;
				if(ctLevel == 0){ownerSE0 = owner0; ownerSE1 = owner1;}
                else{
					sbfSElement * se = selements[0][owner0];
                    for(size_t ct = 0; ct < ctLevel; ct++) se = se->parent();
					ownerSE0 = se->index();
					se = selements[0][owner1];
                    for(size_t ct = 0; ct < ctLevel; ct++) se = se->parent();
					ownerSE1 = se->index();
                    if(ownerSE0 == ownerSE1) inSame = true;
				}
				if (inSame){ facesWeigthIt++; facesOwnersIt++; continue; }
				elemNeibour[ownerSE1].push_back(ownerSE0);
				elemNeibour[ownerSE0].push_back(ownerSE1);
				facesWeigthNextLevel.push_back(*facesWeigthIt);
				facesWeigthNextLevel.push_back(*facesWeigthIt);
				facesOwnersNextLevel.push_back(*facesOwnersIt);
				facesOwnersNextLevel.push_back(*(facesOwnersIt+1));
				facesWeigthIt++; facesOwnersIt++;
				founded++;
			}
            else unfounded++;
		}

        std::vector<idx_t> verttab, edgetab, edlotab, parttab;
		verttab.resize(vertnbr+1);
        parttab.resize(vertnbr);
		int count = 0;
		verttab[0] = count;
		for(size_t ct = 0; ct < elemNeibour.size(); ct++){
            std::list<int> elemNeibourAll, elemNeibourUnique;
            for(auto it = elemNeibour[ct].begin(); it != elemNeibour[ct].end(); it++)
				elemNeibourAll.push_back(*it);
			elemNeibourAll.sort();
			elemNeibourUnique = elemNeibourAll;
			elemNeibourUnique.unique();
            auto elemNeibourUniqueBegin = elemNeibourUnique.begin();
            auto elemNeibourUniqueEnd = elemNeibourUnique.end();
            auto elemNeibourAllBegin = elemNeibourAll.begin();
            auto elemNeibourAllEnd = elemNeibourAll.end();
            auto itA = elemNeibourAllBegin;
            for(auto itU = elemNeibourUniqueBegin; itU != elemNeibourUniqueEnd; itU++)
			{
                if(static_cast<int>(ct) != *itU){
                    int numAcuarence = 0;
                    while(*itA == *itU && itA != elemNeibourAllEnd){
                        numAcuarence++;
                        itA++;
                    }
                    edgetab.push_back(*itU);
                    edlotab.push_back(numAcuarence);
                    count++;
                    edgenbr++;
                }
			}
			verttab[ct+1] = count;
		}

        idx_t nvtxs = vertnbr, ncon = 1, nparts = numTargetSE, objval;
        idx_t options[METIS_NOPTIONS];
        METIS_SetDefaultOptions(options);
        options[METIS_OPTION_OBJTYPE] = METIS_OBJTYPE_VOL;
        options[METIS_OPTION_NUMBERING] = 0;
        options[METIS_OPTION_NITER] = 600;
        double maxLayerImbalance = maxImbalance.back();
        if( ctLevel < maxImbalance.size() ) maxLayerImbalance = maxImbalance.at(ctLevel);
        options[METIS_OPTION_UFACTOR] = static_cast<int>((maxLayerImbalance-1)*1000);
        options[METIS_OPTION_CONTIG] = 1; //Force contiguous partitions
//        options[METIS_OPTION_DBGLVL] = 1;
        int rez = METIS_PartGraphKway(&nvtxs,
                                      &ncon,
                                      verttab.data(),
                                      edgetab.data(),
                                      /*idx_t *vwgt*/nullptr,
                                      /*idx_t *vsize*/nullptr,
                                      /*idx_t *adjwgt*/nullptr,
                                      &nparts,
                                      /*real_t *tpwgts*/nullptr,
                                      /*real_t *ubvec*/nullptr,
                                      options,
                                      &objval,
                                      parttab.data()
                                      );
        if ( rez != METIS_OK ) throw std::runtime_error("Metis runtime failed :(");

		for(int ct = 0; ct < numSElems; ct++){
			selements[ctLevel][ct]->setParent(selements[ctLevel+1][parttab[ct]]);
            selements[ctLevel+1][parttab[ct]]->addChildren(selements[ctLevel][ct]);
		}

        //Metis solves following problem, but still it should be checked
		//There are SElements with some disconnected clusters of elements.
		//For such SE split them to several SEs

        for(auto seIT = selements[ctLevel+1].begin(); seIT != selements[ctLevel+1].end(); seIT++){//Loop on SElements including new ones
			std::set<int> allElemIndexes;//Indexes of all elements in this SE
			for(int ct = 0; ct < (*seIT)->numSElements(); ct++) allElemIndexes.insert((*seIT)->children(ct)->index());
			std::set<int> inOneSE;
			inOneSE.insert(*(allElemIndexes.begin()));
			bool flagChanges = true;
			while(flagChanges){
				flagChanges = false;
                for(auto it = inOneSE.begin(); it != inOneSE.end(); it++){
                    for(auto itN = elemNeibour[*it].begin(); itN != elemNeibour[*it].end(); itN++){
						if(allElemIndexes.count(*itN) && !inOneSE.count(*itN)){
							inOneSE.insert(*itN);
							flagChanges = true;
						}
					}
				}
			}
			if(allElemIndexes.size() != inOneSE.size()){
				std::set<int> inOtherSE;
				(*seIT)->setChildrens(std::vector<sbfSElement *>{});
				(*seIT)->numSElements();
                for(auto it = inOneSE.begin(); it != inOneSE.end(); it++){
					(*seIT)->addChildren(selements[ctLevel][*it]);
					selements[ctLevel][*it]->setParent(*seIT);
				}
                for(auto it = allElemIndexes.begin(); it != allElemIndexes.end(); it++){
					if(!inOneSE.count(*it))
						inOtherSE.insert(*it);
				}
                sbfSElement *additionalSE = new sbfSElement((*seIT)->mesh(), selements[ctLevel+1].size());
                for(auto it = inOtherSE.begin(); it != inOtherSE.end(); it++){
                    additionalSE->addChildren(selements[ctLevel][*it]);
                    selements[ctLevel][*it]->setParent(additionalSE);
				}
                selements[ctLevel+1].push_back(additionalSE);
                if ( verbouse ) std::cout << "Split disconnected SE to two of sizes: " << inOneSE.size() << ", " << inOtherSE.size() << std::endl;
			}
		}//Loop on SElements including new ones

		facesWeigth = facesWeigthNextLevel;
		facesOwners = facesOwnersNextLevel;

        std::cout << "level " << ctLevel << " done" << std::endl;

        //get statistics
        std::list<int> selems;
        int numAll = 0;
        for(auto se : selements[ctLevel+1]){
            selems.push_back(se->numSElements());
            numAll += se->numSElements();
        }
        if(numAll != numSElems)
            throw std::runtime_error("SElements contain not all elements of previous layer");
        selems.sort();
        selems.reverse();
        if ( verbouse ) { for (auto se : selems ) std::cout << se << "\t"; std::cout << "Imbalance is " << (1.0*selems.front())/selems.back() << std::endl; }
	}//Loop on levels

	return 0;
}
Example #22
0
sparse_matrix* graph_partition(LIST *list , partition_t* partition_info)
{
	graph_t* graph;
	params_t *params;
	idx_t options[METIS_NOPTIONS], status;
	idx_t objval;

	sparse_matrix* matrix = (sparse_matrix*)malloc(sizeof(sparse_matrix));

	graph = ReadGraph(list);

	params = bmalloc(sizeof(*params), "Allocating memory for params");

	METIS_SetDefaultOptions(options);
	METIS_init_params(params, graph->ncon);
	options[METIS_OPTION_OBJTYPE] = params->objtype;
	options[METIS_OPTION_CTYPE]   = params->ctype;
	options[METIS_OPTION_IPTYPE]  = params->iptype;
	options[METIS_OPTION_RTYPE]   = params->rtype;
	options[METIS_OPTION_NO2HOP]  = params->no2hop;
	options[METIS_OPTION_MINCONN] = params->minconn;
	options[METIS_OPTION_CONTIG]  = params->contig;
	options[METIS_OPTION_SEED]    = params->seed;
	options[METIS_OPTION_NITER]   = params->niter;
	options[METIS_OPTION_NCUTS]   = params->ncuts;
	options[METIS_OPTION_UFACTOR] = params->ufactor;
	options[METIS_OPTION_DBGLVL]  = params->dbglvl;

	//print_input_data(graph,params);

	params->tpwgts = NULL;
	params->ubvec = NULL;
	partition_info->partion_table = imalloc(graph->nvtxs, "Allocate memory for part");

	switch (params->ptype) {
	    case METIS_PTYPE_RB:
	      status = METIS_PartGraphRecursive(&graph->nvtxs, &graph->ncon, graph->xadj,
	                   graph->adjncy, graph->vwgt, graph->vsize, graph->adjwgt,
	                   &params->nparts, params->tpwgts, params->ubvec, options,
	                   &objval, partition_info->partion_table);
	      break;

	    case METIS_PTYPE_KWAY:
	      status = METIS_PartGraphKway(&graph->nvtxs, &graph->ncon, graph->xadj,
	                   graph->adjncy, graph->vwgt, graph->vsize, graph->adjwgt,
	                   &params->nparts, params->tpwgts, params->ubvec, options,
	                   &objval, partition_info->partion_table);
	      break;

	}
	if (status != METIS_OK) {
		fprintf(stderr,"\n***Metis returned with an error.***\n");
		return NULL;
	}
    partition_info->size = graph->nvtxs;
    partition_info->noOfParts = params->nparts;
    WritePartition(params->filename, partition_info->partion_table, graph->nvtxs, params->nparts);

	printf("Objval: %d\n",objval);

	matrix->nz = -1;
	matrix->n = graph->nvtxs;
	matrix->p = graph->xadj;
	matrix->i = graph->adjncy;
	matrix->x = NULL;


	return matrix;
}
Example #23
0
void partitionCS( CS *mesh )
{
   /*
      create compressed storage format (CSR) of mesh and METIS it
    */

   CS *self=mesh;

   int nVerts=mesh->nVerts;
   int nEls=mesh->nEls;
   int **e_n=mesh->my_e_n;
   int *epart, *vpart;

   epart=mesh->epart;
   vpart=mesh->vpart;

   idx_t *eptr=malloc( (nEls+1)*sizeof(idx_t) );
   idx_t *eind=malloc( nEls*8*sizeof(idx_t) );
   idx_t *part=malloc( nVerts*sizeof(idx_t) ); // the vert
   idx_t ncon=1;
   real_t *tpwgts=NULL;
   idx_t v_i, nbr_i;
   idx_t num_conn=0;

   idx_t vtxdist=nVerts;
   idx_t elmdist=nEls;

   idx_t ncommonnodes = 4; // for hexahedral

   // fill in element indices
   idx_t num_eind=0;
   idx_t e_i, t_i;
   for( e_i=0; e_i<nEls; e_i++ ) {
      eptr[e_i]=num_eind;
      for(nbr_i=0; nbr_i<8; nbr_i++ ) {
         eind[num_eind] = e_n[e_i][nbr_i];
         num_eind++;
      }
   }
   eptr[e_i]=num_eind;  // the final entry

   idx_t ncommon=4;
   idx_t nparts=4;

   tpwgts = malloc( ncon*nparts*sizeof(real_t) );
   memset( tpwgts, 1, nparts*sizeof(real_t) );
   idx_t options[METIS_NOPTIONS];
   idx_t objval;


   METIS_SetDefaultOptions(options);
   options[METIS_OPTION_OBJTYPE] = METIS_OBJTYPE_CUT;
   for( t_i=0; t_i<ncon*nparts; t_i++ ) {
      tpwgts[t_i]=1.0/(double)nparts;
   }

   int err = METIS_PartMeshDual(
                (idx_t*)&nEls,    // number of elements
                (idx_t*)&nVerts,  // number of verts
                eptr,
                eind,
                NULL, // vwgt
                NULL, // vsize
                &ncommon, // 4
                &nparts,
                NULL, //tpwgts
                NULL, //options....
                &objval,
                (idx_t*)epart,
                (idx_t*)vpart );

   if( err==METIS_OK ) {
      printf("Wow, METIS_OK - the number of edges is %d\n", objval);
   } else {
      printf("METIS is not happy\n");
   }

   free( tpwgts );
   free( eptr );
   free( eind );
   free( part );
}
Example #24
0
vector<vector<Geometry::ElemId>> Volume::getPartitionsIds(
        const size_t nDivisions,
        const vector<pair<Geometry::ElemId,int>> idWgt,
        const Math::Real* taskPower) const {
    // Metis v5 manual:
    // [...] take as input the element-node array of the mesh and
    // compute a k-way partitioning for both its elements and its nodes
    // idWgt contains id and weight pairs.
    vector<vector<Geometry::ElemId>> res;
    res.resize(nDivisions, vector<Geometry::ElemId>());
    // Accounts for the one partition case.
    if (nDivisions == 1) {
        Geometry::ConstElemRGroup physVol = elems();
        physVol.removeMatId(MatId(0));
        const size_t nK = physVol.sizeOf<Geometry::VolR>();
        res[0].resize(nK, Geometry::ElemId(0));
        for (size_t i = 0; i < nK; i++) {
            res[0][i] = (elems())(i)->getId();
        }
        return res;
    }
#ifdef MESH_ALLOW_PARTITIONING
    // Prepares mesh info.
    cout << " - Preparing mesh info... " << flush;
    idx_t ne = elems().sizeOf<Geometry::VolR>();
    idx_t *eptr, *eind;
    eptr = new idx_t[ne+1];
    eind = new idx_t[ne*4];
    size_t counter = 0;
    eptr[0] = counter;
    for (idx_t i = 0; i < ne; i++) {
        const Geometry::VolR* vol = elem_.tet[i];
        for (size_t j = 0; j < vol->numberOfVertices(); j++) {
            eind[counter++] = vol->getVertex(j)->id - 1;
        }
        eptr[i+1] = counter;
    }
    cout << "OK" << endl;
    // Relabels ids, needed by quadratic or linearized meshes.
    cout << " - Relabeling... " << flush;
    DynMatrix<Math::Int> id(ne*4,3);
    for (Math::Int i = 0; i < ne*4; i++) {
        id(i,0) = i;
        id(i,1) = eind[i];
        id(i,2) = 0;
    }
    id.sortRows_omp(1,1);
    Math::Int label = 0;
    for (Math::Int i = 1; i < ne*4; i++) {
        if (id(i,1) == id(i-1,1)) {
            id(i,2) = label;
        } else {
            id(i,2) = ++label;
        }
    }
    id.sortRows_omp(0,0);
    for (Math::Int i = 0; i < ne*4; i++) {
        eind[i] = id(i,2);
    }
    idx_t nn = label+1; // Number of vertices.
    cout << "OK" << endl;
    // Copies weights.
    cout << " - Copying weights... " << flush;
    idx_t *vwgt;
    if (idWgt.size() == 0) {
        vwgt = NULL;
    } else {
        vwgt = new idx_t[ne];
        for (Math::Int e = 0; e < ne; e++) {
            vwgt[e] = idWgt[e].second;
        }
    }
    idx_t *vsize = NULL;
    idx_t nparts = nDivisions;
    idx_t objval;
    idx_t *epart;
    epart = new idx_t[ne];
    idx_t *npart;
    npart = new idx_t[nn];
    cout << "OK" << endl;
    // Computes task computational powers.
    real_t *tpwgts = NULL;
    if (taskPower != NULL) {
        tpwgts = new real_t[nDivisions];
        real_t sum = 0.0;
        for (size_t i = 0; i < nDivisions; i++) {
            tpwgts[i] = taskPower[i];
            sum += tpwgts[i];
        }
        assert(std::abs(sum) - 1.0e-16 < 1.0);
    }
    // METIS options.
    cout << " - Setting Options... " << flush;
    idx_t options[METIS_NOPTIONS];
    Math::Int status;
    status = METIS_SetDefaultOptions(options);
    options[METIS_OPTION_PTYPE] = METIS_PTYPE_KWAY;
    options[METIS_OPTION_OBJTYPE] = METIS_OBJTYPE_CUT;
    options[METIS_OPTION_SEED] = (idx_t) 0;
    //	options[METIS_OPTION_OBJTYPE] = METIS_OBJTYPE_VOL;
    // c numbering. Starts from 0.
    options[METIS_OPTION_NUMBERING] = 0;
    cout << "OK" << endl;
    // Calls METIS partition function for meshes.
    idx_t ncommon = 3; // Number of common vertices per element.
    cout << " - Calling Part Mesh Dual... " << flush;
    status = METIS_PartMeshDual(
            &ne, &nn, eptr, eind, vwgt, vsize, &ncommon, &nparts,
            tpwgts, options, &objval, epart, npart);
    if (status != METIS_OK) {
        throw Error("METIS_PartMeshDual fn failed with error: " + status);
    }
    cout << "OK" << endl;
    // Converts result.
    for (size_t i = 0; i < nDivisions; i++) {
        res[i].reserve(ne);
    }
    for (Math::Int i = 0; i < ne; i++) {
        size_t id = elem_.tet[i]->getId();
        res[epart[i]].push_back(id);
    }
    // Frees memory.
    delete vwgt;
    delete epart;
    delete npart;
    delete eptr;
    delete eind;
    // Returns result.
    return res;
#else
    throw logic_error("Mesh partitioning is not allowed.");
#endif
}
Example #25
0
int main(int argc, char *argv[]) {

	// Allocate stack

	stack st[N];

	// Create shortest paths matrix

	const unsigned seed = atoi(argv[1]);
	st->sp = createsp(seed);

	// Generate random set of drivers

	for (agent i = 0; i < D; i++)
		st->dr[i] = 1;

	memset(st->dr + D, 0, sizeof(agent) * (N - D));
	shuffle(st->dr, N, sizeof(agent));
	memcpy(drg, st->dr, N * sizeof(agent));

	// Initialise n, s, and cs data structures

	st->n[N] = N;

	for (agent i = 0; i < N; i++) {
		X(sg, i) = X(st->s, i) = 1;
		Y(sg, i) = Y(st->s, i) = csg[i] = st->cs[i] = i;
		st->l[i] = st->sp[4 * i * N + 2 * i + 1];
		min += COST(i, st->dr, st->l);
		st->n[st->n[i] = N + i + 1] = i;
	}

	// Initialise c and r bitmasks

	ONES(st->c, E + 1, C);
	CLEAR(st->c, 0);
	ONES(st->r, E + 1, C);
	CLEAR(st->r, 0);

	// Create graph

	#ifdef M
	init(seed);
	memset(st->g, 0, sizeof(edge) * N * N);
	scalefree(st->g, st->a);
	#else
	FILE *f = fopen(argv[2], "r");
	for (agent e = 1; e <= E; e++) {
		agent v1, v2;
		fscanf(f, "%u %u", &v1, &v2);
		createedge(st->g, st->a, v1, v2, e);
	}
	fclose(f);
	#endif

	// Reorder (eventually)

	#ifdef REORDER
	edge go[N * N] = {0};
	agent ao[2 * (E + 1)];
	#ifdef METIS
	idx_t options[METIS_NOPTIONS];
	METIS_SetDefaultOptions(options);
	options[METIS_OPTION_OBJTYPE] = METIS_OBJTYPE_CUT;
	options[METIS_OPTION_SEED] = seed;
	real_t tpwgts[2] = {0.5, 0.5}, ubvec = TOLERANCE;
	agent map[N];
	edge e = 1;
	for (agent i = 0; i < N; i++) map[i] = i;
	reorderedges(st->g, map, N, E, go, ao, &e, tpwgts, &ubvec, options);
	#else
	driversbfs(st->a, st->dr, go, ao);
	#endif
	memcpy(st->g, go, sizeof(edge) * N * N);
	memcpy(st->a, ao, sizeof(agent) * 2 * (E + 1));
	#endif

	#ifdef TREEDOT
	st->dot = fopen(TREEDOT, "w+");
	fprintf(st->dot, "digraph TREE {\n");
	fprintf(st->dot, "\tnode [color = none; shape = plaintext, width = 0.2, height = 0.2];\n");
	#endif

	// Solve

	sol = *st;
	#ifdef LIMIT
	value bou = bound(st);
	#endif
	gettimeofday(&t1, NULL);
	srcfss(st, min);
	gettimeofday(&t2, NULL);

	// Print solution

	#ifdef TREEDOT
	printf("SOLUTION = %zu\n", sol.id);
	fprintf(st->dot, "\t%zu [shape = circle, style = filled, fillcolor = green];\n", sol.id);
	#endif

	#ifdef PK
	FILE *pk = fopen(PK, "w+");
	fprintf(pk, "%u\n%u\n%u\n", N, K, seed);
	printg(st->g, pk);
	printpk(&sol, pk);
	fclose(pk);
	#endif

	#ifdef CSV
	printf("%u,%u,%s,%.2f,%f,%zu\n", N, E, argv[1], 0.01 * min, 
	       (double)(t2.tv_usec - t1.tv_usec) / 1e6 + t2.tv_sec - t1.tv_sec, count);
	#else
	printcs(&sol);
	printf("Visited nodes = %zu\n", count);
	printf("Elapsed time = %f\n", (double)(t2.tv_usec - t1.tv_usec) / 1e6 + t2.tv_sec - t1.tv_sec);
	printf("Solution = %.2f€\n", 0.01 * min);
	#ifdef LIMIT
	printf("Bound = %.2f€\n", 0.01 * bou);
	#endif
	#endif

	// Free data structures

	#ifdef TREEDOT
	fprintf(st->dot, "}");
	fclose(st->dot);
	#endif
	free(st->sp);

	return 0;
}
Example #26
0
int Zoltan_ParMetis(
  ZZ *zz,               /* Zoltan structure */
  float *part_sizes,    /* Input:  Array of size zz->Num_Global_Parts
                           containing the percentage of work to be
                           assigned to each partition.               */
  int *num_imp,         /* number of objects to be imported */
  ZOLTAN_ID_PTR *imp_gids,  /* global ids of objects to be imported */
  ZOLTAN_ID_PTR *imp_lids,  /* local  ids of objects to be imported */
  int **imp_procs,      /* list of processors to import from */
  int **imp_to_part,    /* list of partitions to which imported objects are
                           assigned.  */
  int *num_exp,         /* number of objects to be exported */
  ZOLTAN_ID_PTR *exp_gids,  /* global ids of objects to be exported */
  ZOLTAN_ID_PTR *exp_lids,  /* local  ids of objects to be exported */
  int **exp_procs,      /* list of processors to export to */
  int **exp_to_part     /* list of partitions to which exported objects are
                           assigned. */
)
{
  char *yo = "Zoltan_ParMetis";
  int ierr;
  ZOLTAN_Third_Graph gr;
  ZOLTAN_Third_Geom  *geo = NULL;
  ZOLTAN_Third_Vsize vsp;
  ZOLTAN_Third_Part  prt;
  ZOLTAN_Output_Part part;

  ZOLTAN_ID_PTR global_ids = NULL;
  ZOLTAN_ID_PTR local_ids = NULL;

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

  double pmv3_itr = 0.0;
  realtype itr = 0.0;
  indextype options[MAX_PARMETIS_OPTIONS];
  char alg[MAX_PARAM_STRING_LEN];

#ifdef ZOLTAN_PARMETIS
  MPI_Comm comm = zz->Communicator;/* don't risk letting external packages */
                                   /* change our zz struct.                  */
#endif

  indextype i;
  realtype *imb_tols;
  indextype ncon;
  indextype edgecut;
  indextype wgtflag;
  indextype numflag = 0;
  indextype num_part = zz->LB.Num_Global_Parts; /* passed to ParMETIS. */

  ZOLTAN_TRACE_ENTER(zz, yo);

  Zoltan_Third_Init(&gr, &prt, &vsp, &part,
                    imp_gids, imp_lids, imp_procs, imp_to_part,
                    exp_gids, exp_lids, exp_procs, exp_to_part);

  if (sizeof(realtype) != sizeof(float)) {
    int tmp = zz->LB.Num_Global_Parts * MAX(zz->Obj_Weight_Dim, 1);
    prt.input_part_sizes = (realtype *) ZOLTAN_MALLOC(tmp * sizeof(realtype));

    for (i = 0; i < tmp; i++) 
      prt.input_part_sizes[i] = (realtype) part_sizes[i];

    /* KDD 2/2014:  removed re-scaling part sizes so they sum to one.  
     *              part_sizes are already scaled in Zoltan_LB_Get_Part_Sizes.
     *              plus, the code here was wrong for multiple object weights.
     *              similar scaling code did not exist in the Scotch interface.
     */
    prt.part_sizes = prt.input_part_sizes;
  }
  else
    prt.input_part_sizes = prt.part_sizes = (realtype *) part_sizes;


  ierr = Zoltan_Parmetis_Parse(zz, options, alg, &itr, &pmv3_itr, NULL);
  if ((ierr != ZOLTAN_OK) && (ierr != ZOLTAN_WARN)) {
    Zoltan_Third_Exit(&gr, geo, &prt, &vsp, &part, NULL);
    return (ierr);
  }

  gr.graph_type = 0;

#ifdef ZOLTAN_PARMETIS
  SET_GLOBAL_GRAPH(&gr.graph_type);
  /* Select type of graph, negative because we impose them */
  /* TODO: add a parameter to select the type, shared with Scotch */
/*   if (strcmp (graph_type, "GLOBAL") != 0) { */
/*     gr.graph_type = - LOCAL_GRAPH; */
/*     if (zz->Num_Proc > 1) { */
/*       ZOLTAN_PRINT_ERROR(zz->Proc, yo, "Distributed graph: cannot call METIS, switching to ParMetis"); */
/*       gr.graph_type = - GLOBAL_GRAPH; */
/*       retval = ZOLTAN_WARN; */
/*     } */
/*   } */
#else /* graph is local */
  SET_LOCAL_GRAPH(&gr.graph_type);
#endif /* ZOLTAN_PARMETIS */


  /* Some algorithms use geometry data */
  if (strncmp(alg, "PARTGEOM", 8) == 0){          /* PARTGEOM & PARTGEOMKWAY */
    geo = (ZOLTAN_Third_Geom*) ZOLTAN_MALLOC(sizeof(ZOLTAN_Third_Geom));
    memset (geo, 0, sizeof(ZOLTAN_Third_Geom));
    /* ParMETIS will crash if geometric method and some procs have no nodes. */
    /* Avoid fatal crash by setting scatter to level 2 or higher. */
    gr.scatter_min = 2;
    if (geo == NULL) {
      ZOLTAN_PRINT_ERROR (zz->Proc, yo, "Out of memory.");
      return (ZOLTAN_MEMERR);
    }
    if (strcmp(alg, "PARTGEOM") == 0) {
      gr.get_data = 0;
    }
  }

  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);
  }

  vsp.vsize_malloc = 0;
#ifdef PARMETIS31_ALWAYS_FREES_VSIZE
  if (!strcmp(alg, "ADAPTIVEREPART") && (zz->Num_Proc > 1)) {
    /* ParMETIS will free this memory; use malloc to allocate so
       ZOLTAN_MALLOC counters don't show an error. */
    vsp.vsize_malloc = 1 ;
  }
#endif /* PARMETIS31_ALWAYS_FREES_VSIZE */


  ierr = Zoltan_Preprocess_Graph(zz, &global_ids, &local_ids,  &gr, 
                                 geo, &prt, &vsp);
  if ((ierr != ZOLTAN_OK) && (ierr != ZOLTAN_WARN)) {
    Zoltan_Third_Exit(&gr, geo, &prt, &vsp, &part, NULL);
    return (ierr);
  }

  /* Get object sizes if requested */
  if (options[PMV3_OPT_USE_OBJ_SIZE] &&
      (zz->Get_Obj_Size || zz->Get_Obj_Size_Multi) &&
      (!strcmp(alg, "ADAPTIVEREPART") || gr.final_output))
    gr.showMoveVol = 1;


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

  /* Get ready to call ParMETIS */
  edgecut = -1;
  wgtflag = 2*(gr.obj_wgt_dim>0) + (gr.edge_wgt_dim>0);
  numflag = 0;
  ncon = (gr.obj_wgt_dim > 0 ? gr.obj_wgt_dim : 1);

  if (!prt.part_sizes){
    ZOLTAN_THIRD_ERROR(ZOLTAN_FATAL,"Input parameter part_sizes is NULL.");
  }
  if ((zz->Proc == 0) && (zz->Debug_Level >= ZOLTAN_DEBUG_ALL)) {
    for (i=0; i<num_part; i++){
      indextype j;

      printf("Debug: Size(s) for part " TPL_IDX_SPEC " = ", i);
      for (j=0; j<ncon; j++)
        printf("%f ", prt.part_sizes[i*ncon+j]);
      printf("\n");
    }
  }

  /* if (strcmp(alg, "ADAPTIVEREPART") == 0) */
  for (i = 0; i < num_part*ncon; i++)
    if (prt.part_sizes[i] == 0) 
      ZOLTAN_THIRD_ERROR(ZOLTAN_FATAL, "Zero-sized part(s) requested! "
                            "ParMETIS 3.x will likely fail. Please use a "
                            "different method, or remove the zero-sized "
                            "parts from the problem.");


  /* Set Imbalance Tolerance for each weight component. */
  imb_tols = (realtype *) ZOLTAN_MALLOC(ncon * sizeof(realtype));
  if (!imb_tols){
    /* Not enough memory */
    ZOLTAN_THIRD_ERROR(ZOLTAN_MEMERR, "Out of memory.");
  }
  for (i=0; i<ncon; i++)
    imb_tols[i] = (realtype) (zz->LB.Imbalance_Tol[i]);

  /* Now we can call ParMetis */

  /* Zoltan_Third_Graph_Print(zz, &gr, "Before calling parmetis"); */


#ifdef ZOLTAN_PARMETIS
  if (!IS_LOCAL_GRAPH(gr.graph_type)) { /* May be GLOBAL or NO GRAPH */

    /* First check for ParMetis 3 routines */
    if (strcmp(alg, "PARTKWAY") == 0){
      ZOLTAN_TRACE_DETAIL(zz, yo, "Calling the ParMETIS library "
                                  "ParMETIS_V3_PartKway");
      ParMETIS_V3_PartKway(gr.vtxdist, gr.xadj, gr.adjncy, gr.vwgt, gr.ewgts,
                           &wgtflag, &numflag, &ncon, &num_part, prt.part_sizes,
                           imb_tols, options, &edgecut, prt.part, &comm);
      ZOLTAN_TRACE_DETAIL(zz, yo, "Returned from the ParMETIS library");
    }
    else if (strcmp(alg, "PARTGEOMKWAY") == 0){
      indextype ndims = geo->ndims;
      ZOLTAN_TRACE_DETAIL(zz, yo, "Calling the ParMETIS library "
                                  "ParMETIS_V3_PartGeomKway");
      ParMETIS_V3_PartGeomKway(gr.vtxdist, gr.xadj, gr.adjncy, gr.vwgt,gr.ewgts,
                               &wgtflag, &numflag, &ndims, geo->xyz, &ncon,
                               &num_part, prt.part_sizes,
                               imb_tols, options, &edgecut, prt.part, &comm);
      ZOLTAN_TRACE_DETAIL(zz, yo, "Returned from the ParMETIS library");
    }
    else if (strcmp(alg, "PARTGEOM") == 0){
      indextype ndims = geo->ndims;
      ZOLTAN_TRACE_DETAIL(zz, yo, "Calling the ParMETIS library "
                                  "ParMETIS_V3_PartGeom");
      ParMETIS_V3_PartGeom(gr.vtxdist, &ndims, geo->xyz, prt.part, &comm);
      ZOLTAN_TRACE_DETAIL(zz, yo, "Returned from the ParMETIS library");
    }
    else if (strcmp(alg, "ADAPTIVEREPART") == 0){
      ZOLTAN_TRACE_DETAIL(zz, yo, "Calling the ParMETIS library "
                                  "ParMETIS_V3_AdaptiveRepart");
      ParMETIS_V3_AdaptiveRepart(gr.vtxdist, gr.xadj, gr.adjncy, gr.vwgt,
                                 vsp.vsize, gr.ewgts, &wgtflag, &numflag, &ncon,
                                 &num_part, prt.part_sizes, imb_tols,
                                 &itr, options, &edgecut, prt.part, &comm);
      ZOLTAN_TRACE_DETAIL(zz, yo, "Returned from the ParMETIS library");
    }
    else if (strcmp(alg, "REFINEKWAY") == 0){
      ZOLTAN_TRACE_DETAIL(zz, yo, "Calling the ParMETIS library "
                                  "ParMETIS_V3_RefineKway");
      ParMETIS_V3_RefineKway(gr.vtxdist, gr.xadj, gr.adjncy, gr.vwgt, gr.ewgts,
                             &wgtflag, &numflag, &ncon, &num_part,
                             prt.part_sizes, imb_tols,
                             options, &edgecut, prt.part, &comm);
      ZOLTAN_TRACE_DETAIL(zz, yo, "Returned from the ParMETIS library");
    }
    else {
      /* Sanity check: This should never happen! */
      char msg[256];
      sprintf(msg, "Unknown ParMetis algorithm %s.", alg);
      ZOLTAN_THIRD_ERROR(ZOLTAN_FATAL, msg);
    }
  }
#endif /* ZOLTAN_PARMETIS */
#ifdef ZOLTAN_METIS
  /* TODO: I don't know how to set balance ! */
  if (IS_LOCAL_GRAPH(gr.graph_type)) {
    /* Check for Metis routines */
    if (strcmp(alg, "PARTKWAY") == 0){
      ZOLTAN_TRACE_DETAIL(zz, yo, "Calling the METIS library ");
      /* Use default options for METIS */
#if !defined(METIS_VER_MAJOR) || METIS_VER_MAJOR < 5
      options[0] = 0;
      METIS_WPartGraphKway (gr.vtxdist+1, gr.xadj, gr.adjncy, 
                            gr.vwgt, gr.ewgts, &wgtflag,
                            &numflag, &num_part, prt.part_sizes, 
                            options, &edgecut, prt.part);
#else
      METIS_SetDefaultOptions(options);
      METIS_PartGraphKway (gr.vtxdist+1, &ncon, gr.xadj, gr.adjncy,
                           gr.vwgt, vsp.vsize, gr.ewgts, &num_part,
                           prt.part_sizes, imb_tols, options,
                           &edgecut, prt.part);
#endif

      ZOLTAN_TRACE_DETAIL(zz, yo, "Returned from the METIS library");
    }
    else {
      /* Sanity check: This should never happen! */
      char msg[256];
      sprintf(msg, "Unknown Metis algorithm %s.", alg);
      ZOLTAN_THIRD_ERROR(ZOLTAN_FATAL, msg);
    }
  }
#endif /* ZOLTAN_METIS */


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


  if (gr.final_output) { 
    /* Do final output now because after the data will not be coherent:
       unscatter only unscatter part data, not graph */
    ierr = Zoltan_Postprocess_FinalOutput (zz, &gr, &prt, &vsp, use_timers, itr);
  }
  /* Ignore the timings of Final Ouput */
  if (get_times) times[3] = Zoltan_Time(zz->Timer);

  ierr = Zoltan_Postprocess_Graph(zz, global_ids, local_ids, &gr, 
                                  geo, &prt, &vsp, NULL, &part);

  Zoltan_Third_Export_User(&part, 
                           num_imp, imp_gids, imp_lids, imp_procs, imp_to_part,
                           num_exp, exp_gids, exp_lids, exp_procs, exp_to_part);

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

  if (get_times) Zoltan_Third_DisplayTime(zz, times);

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

  Zoltan_Third_Exit(&gr, geo, &prt, &vsp, NULL, NULL);
  if (imb_tols != NULL) ZOLTAN_FREE(&imb_tols);
  if (geo != NULL) ZOLTAN_FREE(&geo);
  ZOLTAN_FREE(&global_ids);
  ZOLTAN_FREE(&local_ids);

  ZOLTAN_TRACE_EXIT(zz, yo);

  return (ierr);
}
Example #27
0
/*************************************************************************
* This function is the entry point of the initial partition algorithm
* that does recursive bissection.
* This algorithm assembles the graph to all the processors and preceeds
* by parallelizing the recursive bisection step.
**************************************************************************/
void InitPartition(ctrl_t *ctrl, graph_t *graph)
{
  idx_t i, j, ncon, mype, npes, gnvtxs, ngroups;
  idx_t *xadj, *adjncy, *adjwgt, *vwgt;
  idx_t *part, *gwhere0, *gwhere1;
  idx_t *tmpwhere, *tmpvwgt, *tmpxadj, *tmpadjncy, *tmpadjwgt;
  graph_t *agraph;
  idx_t lnparts, fpart, fpe, lnpes; 
  idx_t twoparts=2, moptions[METIS_NOPTIONS], edgecut, max_cut;
  real_t *tpwgts, *tpwgts2, *lbvec, lbsum, min_lbsum, wsum;
  MPI_Comm ipcomm;
  struct {
    double sum;
    int rank;
  } lpesum, gpesum;

  WCOREPUSH;

  ncon = graph->ncon;

  ngroups = gk_max(gk_min(RIP_SPLIT_FACTOR, ctrl->npes), 1);

  IFSET(ctrl->dbglvl, DBG_TIME, gkMPI_Barrier(ctrl->comm));
  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->InitPartTmr));

  lbvec = rwspacemalloc(ctrl, ncon);

  /* assemble the graph to all the processors */
  agraph = AssembleAdaptiveGraph(ctrl, graph);
  gnvtxs = agraph->nvtxs;

  /* make a copy of the graph's structure for later */
  xadj   = icopy(gnvtxs+1, agraph->xadj, iwspacemalloc(ctrl, gnvtxs+1));
  vwgt   = icopy(gnvtxs*ncon, agraph->vwgt, iwspacemalloc(ctrl, gnvtxs*ncon));
  adjncy = icopy(agraph->nedges, agraph->adjncy, iwspacemalloc(ctrl, agraph->nedges));
  adjwgt = icopy(agraph->nedges, agraph->adjwgt, iwspacemalloc(ctrl, agraph->nedges));
  part   = iwspacemalloc(ctrl, gnvtxs);

  /* create different processor groups */
  gkMPI_Comm_split(ctrl->gcomm, ctrl->mype % ngroups, 0, &ipcomm);
  gkMPI_Comm_rank(ipcomm, &mype);
  gkMPI_Comm_size(ipcomm, &npes);


  /* Go into the recursive bisection */
  METIS_SetDefaultOptions(moptions);
  moptions[METIS_OPTION_SEED] = ctrl->sync + (ctrl->mype % ngroups) + 1;

  tpwgts  = ctrl->tpwgts;
  tpwgts2 = rwspacemalloc(ctrl, 2*ncon);

  lnparts = ctrl->nparts;
  fpart = fpe = 0;
  lnpes = npes;
  while (lnpes > 1 && lnparts > 1) {
    /* determine the weights of the two partitions as a function of the 
       weight of the target partition weights */
    for (j=(lnparts>>1), i=0; i<ncon; i++) {
      tpwgts2[i]      = rsum(j, tpwgts+fpart*ncon+i, ncon);
      tpwgts2[ncon+i] = rsum(lnparts-j, tpwgts+(fpart+j)*ncon+i, ncon);
      wsum            = 1.0/(tpwgts2[i] + tpwgts2[ncon+i]);
      tpwgts2[i]      *= wsum;
      tpwgts2[ncon+i] *= wsum;
    }

    METIS_PartGraphRecursive(&agraph->nvtxs, &ncon, agraph->xadj, agraph->adjncy, 
          agraph->vwgt, NULL, agraph->adjwgt, &twoparts, tpwgts2, NULL, moptions, 
          &edgecut, part);

    /* pick one of the branches */
    if (mype < fpe+lnpes/2) {
      KeepPart(ctrl, agraph, part, 0);
      lnpes   = lnpes/2;
      lnparts = lnparts/2;
    }
    else {
      KeepPart(ctrl, agraph, part, 1);
      fpart   = fpart + lnparts/2;
      fpe     = fpe + lnpes/2;
      lnpes   = lnpes - lnpes/2;
      lnparts = lnparts - lnparts/2;
    }
  }

  gwhere0 = iset(gnvtxs, 0, iwspacemalloc(ctrl, gnvtxs));
  gwhere1 = iwspacemalloc(ctrl, gnvtxs);

  if (lnparts == 1) { /* Case npes is greater than or equal to nparts */
    /* Only the first process will assign labels (for the reduction to work) */
    if (mype == fpe) {
      for (i=0; i<agraph->nvtxs; i++) 
        gwhere0[agraph->label[i]] = fpart;
    }
  }
  else { /* Case in which npes is smaller than nparts */
    /* create the normalized tpwgts for the lnparts from ctrl->tpwgts */
    tpwgts = rwspacemalloc(ctrl, lnparts*ncon);
    for (j=0; j<ncon; j++) {
      for (wsum=0.0, i=0; i<lnparts; i++) {
        tpwgts[i*ncon+j] = ctrl->tpwgts[(fpart+i)*ncon+j];
        wsum += tpwgts[i*ncon+j];
      }
      for (wsum=1.0/wsum, i=0; i<lnparts; i++) 
        tpwgts[i*ncon+j] *= wsum;
    }

    METIS_PartGraphKway(&agraph->nvtxs, &ncon, agraph->xadj, agraph->adjncy, 
          agraph->vwgt, NULL, agraph->adjwgt, &lnparts, tpwgts, NULL, moptions, 
          &edgecut, part);

    for (i=0; i<agraph->nvtxs; i++) 
      gwhere0[agraph->label[i]] = fpart + part[i];
  }

  gkMPI_Allreduce((void *)gwhere0, (void *)gwhere1, gnvtxs, IDX_T, MPI_SUM, ipcomm);

  if (ngroups > 1) {
    tmpxadj   = agraph->xadj;
    tmpadjncy = agraph->adjncy;
    tmpadjwgt = agraph->adjwgt;
    tmpvwgt   = agraph->vwgt;
    tmpwhere  = agraph->where;

    agraph->xadj   = xadj;
    agraph->adjncy = adjncy;
    agraph->adjwgt = adjwgt;
    agraph->vwgt   = vwgt;
    agraph->where  = gwhere1;
    agraph->vwgt   = vwgt;
    agraph->nvtxs  = gnvtxs;

    edgecut = ComputeSerialEdgeCut(agraph);
    ComputeSerialBalance(ctrl, agraph, gwhere1, lbvec);
    lbsum = rsum(ncon, lbvec, 1);

    gkMPI_Allreduce((void *)&edgecut, (void *)&max_cut,   1, IDX_T,  MPI_MAX, ctrl->gcomm);
    gkMPI_Allreduce((void *)&lbsum,   (void *)&min_lbsum, 1, REAL_T, MPI_MIN, ctrl->gcomm);

    lpesum.sum = lbsum;
    if (min_lbsum < UNBALANCE_FRACTION*ncon) {
      if (lbsum < UNBALANCE_FRACTION*ncon)
        lpesum.sum = edgecut;
      else
        lpesum.sum = max_cut;
    } 
    lpesum.rank = ctrl->mype;
    
    gkMPI_Allreduce((void *)&lpesum, (void *)&gpesum, 1, MPI_DOUBLE_INT,
        MPI_MINLOC, ctrl->gcomm);
    gkMPI_Bcast((void *)gwhere1, gnvtxs, IDX_T, gpesum.rank, ctrl->gcomm);

    agraph->xadj   = tmpxadj;
    agraph->adjncy = tmpadjncy;
    agraph->adjwgt = tmpadjwgt;
    agraph->vwgt   = tmpvwgt;
    agraph->where  = tmpwhere;
  }

  icopy(graph->nvtxs, gwhere1+graph->vtxdist[ctrl->mype], graph->where);

  FreeGraph(agraph);
  gkMPI_Comm_free(&ipcomm);

  IFSET(ctrl->dbglvl, DBG_TIME, gkMPI_Barrier(ctrl->comm));
  IFSET(ctrl->dbglvl, DBG_TIME, stoptimer(ctrl->InitPartTmr));

  WCOREPOP;
}
Example #28
0
/*************************************************************************
* This function is the entry point of the initial balancing algorithm.
* This algorithm assembles the graph to all the processors and preceeds
* with the balancing step.
**************************************************************************/
void Balance_Partition(ctrl_t *ctrl, graph_t *graph)
{
  idx_t i, j, nvtxs, nedges, ncon;
  idx_t mype, npes, srnpes, srmype; 
  idx_t *vtxdist, *xadj, *adjncy, *adjwgt, *vwgt, *vsize;
  idx_t *part, *lwhere, *home;
  idx_t lnparts, fpart, fpe, lnpes, ngroups;
  idx_t *rcounts, *rdispls;
  idx_t twoparts=2, moptions[METIS_NOPTIONS], edgecut, max_cut;
  idx_t sr_pe, gd_pe, sr, gd, who_wins;
  real_t my_cut, my_totalv, my_cost = -1.0, my_balance = -1.0, wsum;
  real_t rating, max_rating, your_cost = -1.0, your_balance = -1.0;
  real_t lbsum, min_lbsum, *lbvec, *tpwgts, *tpwgts2, buffer[2];
  graph_t *agraph, cgraph;
  ctrl_t *myctrl;
  MPI_Status status;
  MPI_Comm ipcomm, srcomm;
  struct {
    double cost;
    int rank;
  } lpecost, gpecost;

  IFSET(ctrl->dbglvl, DBG_TIME, starttimer(ctrl->InitPartTmr));
  WCOREPUSH;

  vtxdist = graph->vtxdist;
  agraph  = AssembleAdaptiveGraph(ctrl, graph);
  nvtxs   = cgraph.nvtxs  = agraph->nvtxs;
  nedges  = cgraph.nedges = agraph->nedges;
  ncon    = cgraph.ncon   = agraph->ncon;
  xadj    = cgraph.xadj   = icopy(nvtxs+1, agraph->xadj, iwspacemalloc(ctrl, nvtxs+1));
  vwgt    = cgraph.vwgt   = icopy(nvtxs*ncon, agraph->vwgt, iwspacemalloc(ctrl, nvtxs*ncon));
  vsize   = cgraph.vsize  = icopy(nvtxs, agraph->vsize, iwspacemalloc(ctrl, nvtxs));
  adjncy  = cgraph.adjncy = icopy(nedges, agraph->adjncy, iwspacemalloc(ctrl, nedges));
  adjwgt  = cgraph.adjwgt = icopy(nedges, agraph->adjwgt, iwspacemalloc(ctrl, nedges));
  part    = cgraph.where  = agraph->where = iwspacemalloc(ctrl, nvtxs);

  lwhere = iwspacemalloc(ctrl, nvtxs);
  home   = iwspacemalloc(ctrl, nvtxs);
  lbvec  = rwspacemalloc(ctrl, graph->ncon);


  /****************************************/
  /****************************************/
  if (ctrl->ps_relation == PARMETIS_PSR_UNCOUPLED) {
    WCOREPUSH;
    rcounts = iwspacemalloc(ctrl, ctrl->npes);
    rdispls = iwspacemalloc(ctrl, ctrl->npes+1);

    for (i=0; i<ctrl->npes; i++) 
      rdispls[i] = rcounts[i] = vtxdist[i+1]-vtxdist[i];
    MAKECSR(i, ctrl->npes, rdispls);

    gkMPI_Allgatherv((void *)graph->home, graph->nvtxs, IDX_T,
        (void *)part, rcounts, rdispls, IDX_T, ctrl->comm);

    for (i=0; i<agraph->nvtxs; i++)
      home[i] = part[i];

    WCOREPOP;  /* local frees */
  }
  else {
    for (i=0; i<ctrl->npes; i++) {
      for (j=vtxdist[i]; j<vtxdist[i+1]; j++)
        part[j] = home[j] = i;
    }
  }

  /* Ensure that the initial partitioning is legal */
  for (i=0; i<agraph->nvtxs; i++) {
    if (part[i] >= ctrl->nparts)
      part[i] = home[i] = part[i] % ctrl->nparts;
    if (part[i] < 0)
      part[i] = home[i] = (-1*part[i]) % ctrl->nparts;
  }
  /****************************************/
  /****************************************/

  IFSET(ctrl->dbglvl, DBG_REFINEINFO, 
      ComputeSerialBalance(ctrl, agraph, agraph->where, lbvec));
  IFSET(ctrl->dbglvl, DBG_REFINEINFO, 
      rprintf(ctrl, "input cut: %"PRIDX", balance: ", ComputeSerialEdgeCut(agraph)));
  for (i=0; i<agraph->ncon; i++)
    IFSET(ctrl->dbglvl, DBG_REFINEINFO, rprintf(ctrl, "%.3"PRREAL" ", lbvec[i]));
  IFSET(ctrl->dbglvl, DBG_REFINEINFO, rprintf(ctrl, "\n"));

  /****************************************/
  /* Split the processors into two groups */
  /****************************************/
  sr = (ctrl->mype % 2 == 0) ? 1 : 0;
  gd = (ctrl->mype % 2 == 1) ? 1 : 0;

  if (graph->ncon > MAX_NCON_FOR_DIFFUSION || ctrl->npes == 1) {
    sr = 1;
    gd = 0;
  }

  sr_pe = 0;
  gd_pe = 1;

  gkMPI_Comm_split(ctrl->gcomm, sr, 0, &ipcomm);
  gkMPI_Comm_rank(ipcomm, &mype);
  gkMPI_Comm_size(ipcomm, &npes);

  if (sr == 1) { /* Half of the processors do scratch-remap */
    ngroups = gk_max(gk_min(RIP_SPLIT_FACTOR, npes), 1);
    gkMPI_Comm_split(ipcomm, mype % ngroups, 0, &srcomm);
    gkMPI_Comm_rank(srcomm, &srmype);
    gkMPI_Comm_size(srcomm, &srnpes);

    METIS_SetDefaultOptions(moptions);
    moptions[METIS_OPTION_SEED] = ctrl->sync + (mype % ngroups) + 1;

    tpwgts  = ctrl->tpwgts;
    tpwgts2 = rwspacemalloc(ctrl, 2*ncon);

    iset(nvtxs, 0, lwhere);
    lnparts = ctrl->nparts;
    fpart = fpe = 0;
    lnpes = srnpes;
    while (lnpes > 1 && lnparts > 1) {
      PASSERT(ctrl, agraph->nvtxs > 1);
      /* determine the weights of the two partitions as a function of the 
         weight of the target partition weights */
      for (j=(lnparts>>1), i=0; i<ncon; i++) {
        tpwgts2[i]      = rsum(j, tpwgts+fpart*ncon+i, ncon);
        tpwgts2[ncon+i] = rsum(lnparts-j, tpwgts+(fpart+j)*ncon+i, ncon);
        wsum            = 1.0/(tpwgts2[i] + tpwgts2[ncon+i]);
        tpwgts2[i]      *= wsum;
        tpwgts2[ncon+i] *= wsum;
      }

      METIS_PartGraphRecursive(&agraph->nvtxs, &ncon, agraph->xadj, 
            agraph->adjncy, agraph->vwgt, NULL, agraph->adjwgt, 
            &twoparts, tpwgts2, NULL, moptions, &edgecut, part);

      /* pick one of the branches */
      if (srmype < fpe+lnpes/2) {
        KeepPart(ctrl, agraph, part, 0);
        lnpes   = lnpes/2;
        lnparts = lnparts/2;
      }
      else {
        KeepPart(ctrl, agraph, part, 1);
        fpart   = fpart + lnparts/2;
        fpe     = fpe + lnpes/2;
        lnpes   = lnpes - lnpes/2;
        lnparts = lnparts - lnparts/2;
      }
    }

    if (lnparts == 1) { /* Case in which srnpes is greater or equal to nparts */
      /* Only the first process will assign labels (for the reduction to work) */
      if (srmype == fpe) {
        for (i=0; i<agraph->nvtxs; i++) 
          lwhere[agraph->label[i]] = fpart;
      }
    }
    else { /* Case in which srnpes is smaller than nparts */
      /* create the normalized tpwgts for the lnparts from ctrl->tpwgts */
      tpwgts = rwspacemalloc(ctrl, lnparts*ncon);
      for (j=0; j<ncon; j++) {
        for (wsum=0.0, i=0; i<lnparts; i++) {
          tpwgts[i*ncon+j] = ctrl->tpwgts[(fpart+i)*ncon+j];
          wsum += tpwgts[i*ncon+j];
        }
        for (wsum=1.0/wsum, i=0; i<lnparts; i++)
          tpwgts[i*ncon+j] *= wsum;
      }

      METIS_PartGraphKway(&agraph->nvtxs, &ncon, agraph->xadj, agraph->adjncy, 
	    agraph->vwgt, NULL, agraph->adjwgt, &lnparts, tpwgts, NULL, moptions, 
            &edgecut, part);

      for (i=0; i<agraph->nvtxs; i++) 
        lwhere[agraph->label[i]] = fpart + part[i];
    }

    gkMPI_Allreduce((void *)lwhere, (void *)part, nvtxs, IDX_T, MPI_SUM, srcomm);

    edgecut = ComputeSerialEdgeCut(&cgraph);
    ComputeSerialBalance(ctrl, &cgraph, part, lbvec);
    lbsum = rsum(ncon, lbvec, 1);
    gkMPI_Allreduce((void *)&edgecut, (void *)&max_cut, 1, IDX_T, MPI_MAX, ipcomm);
    gkMPI_Allreduce((void *)&lbsum, (void *)&min_lbsum, 1, REAL_T, MPI_MIN, ipcomm);
    lpecost.rank = ctrl->mype;
    lpecost.cost = lbsum;
    if (min_lbsum < UNBALANCE_FRACTION * (real_t)(ncon)) {
      if (lbsum < UNBALANCE_FRACTION * (real_t)(ncon))
        lpecost.cost = (double)edgecut;
      else
        lpecost.cost = (double)max_cut + lbsum;
    }
    gkMPI_Allreduce((void *)&lpecost, (void *)&gpecost, 1, MPI_DOUBLE_INT,
        MPI_MINLOC, ipcomm);

    if (ctrl->mype == gpecost.rank && ctrl->mype != sr_pe) 
      gkMPI_Send((void *)part, nvtxs, IDX_T, sr_pe, 1, ctrl->comm);

    if (ctrl->mype != gpecost.rank && ctrl->mype == sr_pe) 
      gkMPI_Recv((void *)part, nvtxs, IDX_T, gpecost.rank, 1, ctrl->comm, &status);

    if (ctrl->mype == sr_pe) {
      icopy(nvtxs, part, lwhere);
      SerialRemap(ctrl, &cgraph, ctrl->nparts, home, lwhere, part, ctrl->tpwgts);
    }

    gkMPI_Comm_free(&srcomm);
  }