void partition(const RCP<PartitioningSolution<Adapter> > &solution) { size_t nObj = adapter->getLocalNumIDs(); ArrayRCP<part_t> partList(new part_t[nObj], 0, nObj, true); size_t nGlobalParts = solution->getTargetGlobalNumberOfParts(); const Teuchos::ParameterEntry *pe = env->getParameters().getEntryPtr("forTestingOnlyFlag"); int forTestingOnlyFlag = pe->getValue<int>(&forTestingOnlyFlag); switch (forTestingOnlyFlag) { case 0: // rank 0 has all objects in part 0 // all other ranks assign to {0, nGlobalParts-1, 0, nGlobalParts-1, ..} if (comm->getRank() == 0) { for (size_t i = 0; i < nObj; i++) partList[i] = 0; } else { for (size_t i = 0; i < nObj; i++) if (i % 2) partList[i] = nGlobalParts - 1; else partList[i] = 0; } break; case 1: // rank 0 has all objects in part 0 // all other ranks assign to {nGlobalParts-1, 0, nGlobalParts-1, 0, ..} if (comm->getRank() == 0) { for (size_t i = 0; i < nObj; i++) partList[i] = 0; } else { for (size_t i = 0; i < nObj; i++) if (i % 2) partList[i] = 0; else partList[i] = nGlobalParts - 1; } break; default: throw std::runtime_error("invalid forTestingOnlyFlag value"); } std::cout << comm->getRank() << " forTestingOnly " << forTestingOnlyFlag << " partList: "; for (size_t i = 0; i < nObj; i++) std::cout << partList[i] << " "; std::cout << std::endl; solution->setParts(partList); }
void AlgPTScotch<Adapter>::partition( const RCP<PartitioningSolution<Adapter> > &solution ) { HELLO; size_t numGlobalParts = solution->getTargetGlobalNumberOfParts(); SCOTCH_Num partnbr=0; TPL_Traits<SCOTCH_Num, size_t>::ASSIGN_TPL_T(partnbr, numGlobalParts, env); #ifdef HAVE_ZOLTAN2_MPI int ierr = 0; int me = problemComm->getRank(); const SCOTCH_Num baseval = 0; // Base value for array indexing. // GraphModel returns GNOs from base 0. SCOTCH_Strat stratstr; // Strategy string // TODO: Set from parameters SCOTCH_stratInit(&stratstr); // Allocate and initialize PTScotch Graph data structure. SCOTCH_Dgraph *gr = SCOTCH_dgraphAlloc(); // Scotch distributed graph ierr = SCOTCH_dgraphInit(gr, mpicomm); env->globalInputAssertion(__FILE__, __LINE__, "SCOTCH_dgraphInit", !ierr, BASIC_ASSERTION, problemComm); // Get vertex info ArrayView<const gno_t> vtxID; ArrayView<StridedData<lno_t, scalar_t> > xyz; ArrayView<StridedData<lno_t, scalar_t> > vwgts; size_t nVtx = model->getVertexList(vtxID, xyz, vwgts); SCOTCH_Num vertlocnbr=0; TPL_Traits<SCOTCH_Num, size_t>::ASSIGN_TPL_T(vertlocnbr, nVtx, env); SCOTCH_Num vertlocmax = vertlocnbr; // Assumes no holes in global nums. // Get edge info ArrayView<const gno_t> edgeIds; ArrayView<const int> procIds; ArrayView<const lno_t> offsets; ArrayView<StridedData<lno_t, scalar_t> > ewgts; size_t nEdge = model->getEdgeList(edgeIds, procIds, offsets, ewgts); SCOTCH_Num edgelocnbr=0; TPL_Traits<SCOTCH_Num, size_t>::ASSIGN_TPL_T(edgelocnbr, nEdge, env); const SCOTCH_Num edgelocsize = edgelocnbr; // Assumes adj array is compact. SCOTCH_Num *vertloctab; // starting adj/vtx TPL_Traits<SCOTCH_Num, lno_t>::ASSIGN_TPL_T_ARRAY(&vertloctab, offsets, env); SCOTCH_Num *edgeloctab; // adjacencies TPL_Traits<SCOTCH_Num, gno_t>::ASSIGN_TPL_T_ARRAY(&edgeloctab, edgeIds, env); // We don't use these arrays, but we need them as arguments to Scotch. SCOTCH_Num *vendloctab = NULL; // Assume consecutive storage for adj SCOTCH_Num *vlblloctab = NULL; // Vertex label array SCOTCH_Num *edgegsttab = NULL; // Array for ghost vertices // Get weight info. SCOTCH_Num *velotab = NULL; // Vertex weights SCOTCH_Num *edlotab = NULL; // Edge weights int nVwgts = model->getNumWeightsPerVertex(); int nEwgts = model->getNumWeightsPerEdge(); if (nVwgts > 1 && me == 0) { std::cerr << "Warning: NumWeightsPerVertex is " << nVwgts << " but Scotch allows only one weight. " << " Zoltan2 will use only the first weight per vertex." << std::endl; } if (nEwgts > 1 && me == 0) { std::cerr << "Warning: NumWeightsPerEdge is " << nEwgts << " but Scotch allows only one weight. " << " Zoltan2 will use only the first weight per edge." << std::endl; } if (nVwgts) { velotab = new SCOTCH_Num[nVtx+1]; // +1 since Scotch wants all procs // to have non-NULL arrays scale_weights(nVtx, vwgts[0], velotab); } if (nEwgts) { edlotab = new SCOTCH_Num[nEdge+1]; // +1 since Scotch wants all procs // to have non-NULL arrays scale_weights(nEdge, ewgts[0], edlotab); } // Build PTScotch distributed data structure ierr = SCOTCH_dgraphBuild(gr, baseval, vertlocnbr, vertlocmax, vertloctab, vendloctab, velotab, vlblloctab, edgelocnbr, edgelocsize, edgeloctab, edgegsttab, edlotab); env->globalInputAssertion(__FILE__, __LINE__, "SCOTCH_dgraphBuild", !ierr, BASIC_ASSERTION, problemComm); // Create array for Scotch to return results in. ArrayRCP<part_t> partList(new part_t[nVtx], 0, nVtx,true); SCOTCH_Num *partloctab = NULL; if (nVtx && (sizeof(SCOTCH_Num) == sizeof(part_t))) { // Can write directly into the solution's memory partloctab = (SCOTCH_Num *) partList.getRawPtr(); } else { // Can't use solution memory directly; will have to copy later. // Note: Scotch does not like NULL arrays, so add 1 to always have non-null. // ParMETIS has this same "feature." See Zoltan bug 4299. partloctab = new SCOTCH_Num[nVtx+1]; } // Get target part sizes float *partsizes = new float[numGlobalParts]; if (!solution->criteriaHasUniformPartSizes(0)) for (size_t i=0; i<numGlobalParts; i++) partsizes[i] = solution->getCriteriaPartSize(0, i); else for (size_t i=0; i<numGlobalParts; i++) partsizes[i] = 1.0 / float(numGlobalParts); // Allocate and initialize PTScotch target architecture data structure SCOTCH_Arch archdat; SCOTCH_archInit(&archdat); SCOTCH_Num velosum = 0; SCOTCH_dgraphSize (gr, &velosum, NULL, NULL, NULL); SCOTCH_Num *goalsizes = new SCOTCH_Num[partnbr]; // TODO: The goalsizes are set as in Zoltan; not sure it is correct there // or here. // It appears velosum is global NUMBER of vertices, not global total // vertex weight. I think we should use the latter. // Fix this when we add vertex weights. for (SCOTCH_Num i = 0; i < partnbr; i++) goalsizes[i] = SCOTCH_Num(ceil(velosum * partsizes[i])); delete [] partsizes; SCOTCH_archCmpltw(&archdat, partnbr, goalsizes); // Call partitioning; result returned in partloctab. ierr = SCOTCH_dgraphMap(gr, &archdat, &stratstr, partloctab); env->globalInputAssertion(__FILE__, __LINE__, "SCOTCH_dgraphMap", !ierr, BASIC_ASSERTION, problemComm); SCOTCH_archExit(&archdat); delete [] goalsizes; // TODO - metrics #ifdef SHOW_ZOLTAN2_SCOTCH_MEMORY int me = env->comm_->getRank(); #endif #ifdef HAVE_SCOTCH_ZOLTAN2_GETMEMORYMAX if (me == 0){ size_t scotchBytes = SCOTCH_getMemoryMax(); std::cout << "Rank " << me << ": Maximum bytes used by Scotch: "; std::cout << scotchBytes << std::endl; } #endif // Clean up PTScotch SCOTCH_dgraphExit(gr); free(gr); SCOTCH_stratExit(&stratstr); // Load answer into the solution. if ((sizeof(SCOTCH_Num) != sizeof(part_t)) || (nVtx == 0)) { for (size_t i = 0; i < nVtx; i++) partList[i] = partloctab[i]; delete [] partloctab; } solution->setParts(partList); env->memory("Zoltan2-Scotch: After creating solution"); // Clean up copies made due to differing data sizes. TPL_Traits<SCOTCH_Num, lno_t>::DELETE_TPL_T_ARRAY(&vertloctab); TPL_Traits<SCOTCH_Num, gno_t>::DELETE_TPL_T_ARRAY(&edgeloctab); if (nVwgts) delete [] velotab; if (nEwgts) delete [] edlotab; #else // DO NOT HAVE_MPI // TODO: Handle serial case with calls to Scotch. // TODO: For now, assign everything to rank 0 and assume only one part. // TODO: Can probably use the code above for loading solution, // TODO: instead of duplicating it here. // TODO // TODO: Actual logic should call Scotch when number of processes == 1. ArrayView<const gno_t> vtxID; ArrayView<StridedData<lno_t, scalar_t> > xyz; ArrayView<StridedData<lno_t, scalar_t> > vwgts; size_t nVtx = model->getVertexList(vtxID, xyz, vwgts); ArrayRCP<part_t> partList(new part_t[nVtx], 0, nVtx, true); for (size_t i = 0; i < nVtx; i++) partList[i] = 0; solution->setParts(partList); #endif // DO NOT HAVE_MPI }
void AlgPTScotch( const RCP<const Environment> &env, // parameters & app comm const RCP<const Comm<int> > &problemComm, // problem comm #ifdef HAVE_ZOLTAN2_MPI MPI_Comm mpicomm, #endif const RCP<GraphModel<typename Adapter::base_adapter_t> > &model, // the graph RCP<PartitioningSolution<Adapter> > &solution ) { HELLO; typedef typename Adapter::lno_t lno_t; typedef typename Adapter::gno_t gno_t; typedef typename Adapter::scalar_t scalar_t; int ierr = 0; size_t numGlobalParts = solution->getTargetGlobalNumberOfParts(); SCOTCH_Num partnbr; SCOTCH_Num_Traits<size_t>::ASSIGN_TO_SCOTCH_NUM(partnbr, numGlobalParts, env); #ifdef HAVE_ZOLTAN2_MPI const SCOTCH_Num baseval = 0; // Base value for array indexing. // GraphModel returns GNOs from base 0. SCOTCH_Strat stratstr; // Strategy string // TODO: Set from parameters SCOTCH_stratInit(&stratstr); // Allocate & initialize PTScotch data structure. SCOTCH_Dgraph *gr = SCOTCH_dgraphAlloc(); // Scotch distributed graph ierr = SCOTCH_dgraphInit(gr, mpicomm); env->globalInputAssertion(__FILE__, __LINE__, "SCOTCH_dgraphInit", !ierr, BASIC_ASSERTION, problemComm); // Get vertex info ArrayView<const gno_t> vtxID; ArrayView<StridedData<lno_t, scalar_t> > xyz; ArrayView<StridedData<lno_t, scalar_t> > vtxWt; size_t nVtx = model->getVertexList(vtxID, xyz, vtxWt); SCOTCH_Num vertlocnbr; SCOTCH_Num_Traits<size_t>::ASSIGN_TO_SCOTCH_NUM(vertlocnbr, nVtx, env); SCOTCH_Num vertlocmax = vertlocnbr; // Assumes no holes in global nums. // Get edge info ArrayView<const gno_t> edgeIds; ArrayView<const int> procIds; ArrayView<const lno_t> offsets; ArrayView<StridedData<lno_t, scalar_t> > ewgts; size_t nEdges = model->getEdgeList(edgeIds, procIds, offsets, ewgts); SCOTCH_Num edgelocnbr; SCOTCH_Num_Traits<size_t>::ASSIGN_TO_SCOTCH_NUM(edgelocnbr, nEdges, env); const SCOTCH_Num edgelocsize = edgelocnbr; // Assumes adj array is compact. SCOTCH_Num *vertloctab; // starting adj/vtx SCOTCH_Num_Traits<lno_t>::ASSIGN_SCOTCH_NUM_ARRAY(&vertloctab, offsets, env); SCOTCH_Num *edgeloctab; // adjacencies SCOTCH_Num_Traits<gno_t>::ASSIGN_SCOTCH_NUM_ARRAY(&edgeloctab, edgeIds, env); // We don't use these arrays, but we need them as arguments to Scotch. SCOTCH_Num *vendloctab = NULL; // Assume consecutive storage for adj SCOTCH_Num *vlblloctab = NULL; // Vertex label array SCOTCH_Num *edgegsttab = NULL; // Array for ghost vertices // Get weight info. // TODO: Actually get the weights; for now, not using weights. SCOTCH_Num *veloloctab = NULL; // Vertex weights SCOTCH_Num *edloloctab = NULL; // Edge weights //TODO int vwtdim = model->getVertexWeightDim(); //TODO int ewtdim = model->getEdgeWeightDim(); //TODO if (vwtdim) veloloctab = new SCOTCH_Num[nVtx]; //TODO if (ewtdim) edloloctab = new SCOTCH_Num[nEdges]; //TODO scale weights to SCOTCH_Nums. // Build PTScotch distributed data structure ierr = SCOTCH_dgraphBuild(gr, baseval, vertlocnbr, vertlocmax, vertloctab, vendloctab, veloloctab, vlblloctab, edgelocnbr, edgelocsize, edgeloctab, edgegsttab, edloloctab); env->globalInputAssertion(__FILE__, __LINE__, "SCOTCH_dgraphBuild", !ierr, BASIC_ASSERTION, problemComm); // Create array for Scotch to return results in. ArrayRCP<partId_t> partList(new partId_t [nVtx], 0, nVtx,true); SCOTCH_Num *partloctab = NULL; if (nVtx && (sizeof(SCOTCH_Num) == sizeof(partId_t))) { // Can write directly into the solution's memory partloctab = (SCOTCH_Num *) partList.getRawPtr(); } else { // Can't use solution memory directly; will have to copy later. // Note: Scotch does not like NULL arrays, so add 1 to always have non-null. // ParMETIS has this same "feature." See Zoltan bug 4299. partloctab = new SCOTCH_Num[nVtx+1]; } // Call partitioning; result returned in partloctab. // TODO: Use SCOTCH_dgraphMap so can include a machine model in partitioning ierr = SCOTCH_dgraphPart(gr, partnbr, &stratstr, partloctab); env->globalInputAssertion(__FILE__, __LINE__, "SCOTCH_dgraphPart", !ierr, BASIC_ASSERTION, problemComm); // TODO - metrics #ifdef SHOW_ZOLTAN2_SCOTCH_MEMORY int me = env->comm_->getRank(); #endif #ifdef HAVE_SCOTCH_ZOLTAN2_GETMEMORYMAX if (me == 0){ size_t scotchBytes = SCOTCH_getMemoryMax(); std::cout << "Rank " << me << ": Maximum bytes used by Scotch: "; std::cout << scotchBytes << std::endl; } #endif // Clean up PTScotch SCOTCH_dgraphExit(gr); delete gr; SCOTCH_stratExit(&stratstr); // Load answer into the solution. if ((sizeof(SCOTCH_Num) != sizeof(partId_t)) || (nVtx == 0)) { for (size_t i = 0; i < nVtx; i++) partList[i] = partloctab[i]; delete [] partloctab; } ArrayRCP<const gno_t> gnos = arcpFromArrayView(vtxID); solution->setParts(gnos, partList, true); env->memory("Zoltan2-Scotch: After creating solution"); //if (me == 0) cout << " done." << endl; // Clean up Zoltan2 //TODO if (vwtdim) delete [] velotab; //TODO if (ewtdim) delete [] edlotab; // Clean up copies made due to differing data sizes. SCOTCH_Num_Traits<lno_t>::DELETE_SCOTCH_NUM_ARRAY(&vertloctab); SCOTCH_Num_Traits<gno_t>::DELETE_SCOTCH_NUM_ARRAY(&edgeloctab); #else // DO NOT HAVE_MPI // TODO: Handle serial case with calls to Scotch. // TODO: For now, assign everything to rank 0 and assume only one part. // TODO: Can probably use the code above for loading solution, // TODO: instead of duplicating it here. // TODO // TODO: Actual logic should call Scotch when number of processes == 1. ArrayView<const gno_t> vtxID; ArrayView<StridedData<lno_t, scalar_t> > xyz; ArrayView<StridedData<lno_t, scalar_t> > vtxWt; size_t nVtx = model->getVertexList(vtxID, xyz, vtxWt); for (size_t i = 0; i < nVtx; i++) partList[i] = 0; #endif // DO NOT HAVE_MPI }
void AlgZoltan<Adapter>::partition( const RCP<PartitioningSolution<Adapter> > &solution ) { HELLO; char paramstr[128]; size_t numGlobalParts = solution->getTargetGlobalNumberOfParts(); sprintf(paramstr, "%lu", numGlobalParts); zz->Set_Param("NUM_GLOBAL_PARTS", paramstr); int wdim = adapter->getNumWeightsPerID(); sprintf(paramstr, "%d", wdim); zz->Set_Param("OBJ_WEIGHT_DIM", paramstr); const Teuchos::ParameterList &pl = env->getParameters(); double tolerance; const Teuchos::ParameterEntry *pe = pl.getEntryPtr("imbalance_tolerance"); if (pe){ char str[30]; tolerance = pe->getValue<double>(&tolerance); sprintf(str, "%f", tolerance); zz->Set_Param("IMBALANCE_TOL", str); } pe = pl.getEntryPtr("partitioning_approach"); if (pe){ std::string approach; approach = pe->getValue<std::string>(&approach); if (approach == "partition") zz->Set_Param("LB_APPROACH", "PARTITION"); else zz->Set_Param("LB_APPROACH", "REPARTITION"); } // Look for zoltan_parameters sublist; pass all zoltan parameters to Zoltan try { const Teuchos::ParameterList &zpl = pl.sublist("zoltan_parameters"); for (ParameterList::ConstIterator iter = zpl.begin(); iter != zpl.end(); iter++) { const std::string &zname = pl.name(iter); // Convert the value to a string to pass to Zoltan std::string zval = pl.entry(iter).getValue(&zval); zz->Set_Param(zname.c_str(), zval.c_str()); } } catch (std::exception &e) { // No zoltan_parameters sublist found; no Zoltan parameters to register } // Get target part sizes int pdim = (wdim > 1 ? wdim : 1); for (int d = 0; d < pdim; d++) { if (!solution->criteriaHasUniformPartSizes(d)) { float *partsizes = new float[numGlobalParts]; int *partidx = new int[numGlobalParts]; int *wgtidx = new int[numGlobalParts]; for (size_t i=0; i<numGlobalParts; i++) partidx[i] = i; for (size_t i=0; i<numGlobalParts; i++) wgtidx[i] = d; for (size_t i=0; i<numGlobalParts; i++) partsizes[i] = solution->getCriteriaPartSize(0, i); zz->LB_Set_Part_Sizes(1, numGlobalParts, partidx, wgtidx, partsizes); delete [] partsizes; delete [] partidx; delete [] wgtidx; } } // Make the call to LB_Partition int changed = 0; int nGidEnt = 1, nLidEnt = 1; int nDummy = -1; // Dummy vars to satisfy arglist ZOLTAN_ID_PTR dGids = NULL, dLids = NULL; int *dProcs = NULL, *dParts = NULL; int nObj = -1; // Output vars with new part info ZOLTAN_ID_PTR oGids = NULL, oLids = NULL; int *oProcs = NULL, *oParts = NULL; zz->Set_Param("RETURN_LISTS", "PARTS"); // required format for Zoltan2; // results in last five arguments int ierr = zz->LB_Partition(changed, nGidEnt, nLidEnt, nDummy, dGids, dLids, dProcs, dParts, nObj, oGids, oLids, oProcs, oParts); env->globalInputAssertion(__FILE__, __LINE__, "Zoltan LB_Partition", (ierr==ZOLTAN_OK || ierr==ZOLTAN_WARN), BASIC_ASSERTION, problemComm); int numObjects=nObj; // The number of objects may be larger than zoltan knows due to copies that // were removed by the hypergraph model if (model!=RCP<const Model<Adapter> >() && dynamic_cast<const HyperGraphModel<Adapter>* >(&(*model)) && !(dynamic_cast<const HyperGraphModel<Adapter>* >(&(*model))->areVertexIDsUnique())) { numObjects=model->getLocalNumObjects(); } // Load answer into the solution. ArrayRCP<part_t> partList(new part_t[numObjects], 0, numObjects, true); for (int i = 0; i < nObj; i++) partList[oLids[i]] = oParts[i]; if (model!=RCP<const Model<Adapter> >() && dynamic_cast<const HyperGraphModel<Adapter>* >(&(*model)) && !(dynamic_cast<const HyperGraphModel<Adapter>* >(&(*model))->areVertexIDsUnique())) { // Setup the part ids for copied entities removed by ownership in // hypergraph model. const HyperGraphModel<Adapter>* mdl = static_cast<const HyperGraphModel<Adapter>* >(&(*model)); typedef typename HyperGraphModel<Adapter>::map_t map_t; Teuchos::RCP<const map_t> mapWithCopies; Teuchos::RCP<const map_t> oneToOneMap; mdl->getVertexMaps(mapWithCopies,oneToOneMap); typedef Tpetra::Vector<scalar_t, lno_t, gno_t> vector_t; vector_t vecWithCopies(mapWithCopies); vector_t oneToOneVec(oneToOneMap); // Set values in oneToOneVec: each entry == rank assert(nObj == lno_t(oneToOneMap->getNodeNumElements())); for (lno_t i = 0; i < nObj; i++) oneToOneVec.replaceLocalValue(i, oParts[i]); // Now import oneToOneVec's values back to vecWithCopies Teuchos::RCP<const Tpetra::Import<lno_t, gno_t> > importer = Tpetra::createImport<lno_t, gno_t>(oneToOneMap, mapWithCopies); vecWithCopies.doImport(oneToOneVec, *importer, Tpetra::REPLACE); // Should see copied vector values when print VEC WITH COPIES lno_t nlocal = lno_t(mapWithCopies->getNodeNumElements()); for (lno_t i = 0; i < nlocal; i++) partList[i] = vecWithCopies.getData()[i]; } solution->setParts(partList); // Clean up zz->LB_Free_Part(&oGids, &oLids, &oProcs, &oParts); }
void AlgPuLP<Adapter>::partition( const RCP<PartitioningSolution<Adapter> > &solution ) { HELLO; size_t numGlobalParts = solution->getTargetGlobalNumberOfParts(); int num_parts = (int)numGlobalParts; //TPL_Traits<int, size_t>::ASSIGN_TPL_T(num_parts, numGlobalParts, env); //#ifdef HAVE_ZOLTAN2_MPI // TODO: XtraPuLP int ierr = 0; //int np = problemComm->getSize(); // Get number of vertices and edges const size_t modelVerts = model->getLocalNumVertices(); const size_t modelEdges = model->getLocalNumEdges(); int num_verts = (int)modelVerts; long num_edges = (long)modelEdges; //TPL_Traits<int, size_t>::ASSIGN_TPL_T(num_verts, modelVerts, env); //TPL_Traits<long, size_t>::ASSIGN_TPL_T(num_edges, modelEdges, env); // Get adjacency list and offset pointers ArrayView<const gno_t> adjs; ArrayView<const lno_t> offsets; ArrayView<StridedData<lno_t, scalar_t> > ewgts; // ignore this for now model->getEdgeList(adjs, offsets, ewgts); // Create PuLP's graph structure int *out_edges; long *out_offsets; TPL_Traits<int, const gno_t>::ASSIGN_TPL_T_ARRAY(&out_edges, adjs); TPL_Traits<long, const lno_t>::ASSIGN_TPL_T_ARRAY(&out_offsets, offsets); pulp_graph_t g = {num_verts, num_edges, out_edges, out_offsets}; // Create array for PuLP to return results in. // Or write directly into solution parts array ArrayRCP<part_t> partList(new part_t[num_verts], 0, num_verts, true); int* parts = NULL; if (num_verts && (sizeof(int) == sizeof(part_t))) { // Can write directly into the solution's memory parts = (int *) partList.getRawPtr(); } else { // Can't use solution memory directly; will have to copy later. parts = new int[num_verts]; } // TODO // Implement vertex and edge weights // TODO // Implement target part sizes // Grab options from parameter list const Teuchos::ParameterList &pl = env->getParameters(); const Teuchos::ParameterEntry *pe; // figure out which parts of the algorithm we're going to run // Default to PuLP with BFS init // PuLP - do_edge_min = false, do_maxcut_min = false // PuLP-M - do_edge_bal = true, do_maxcut_min = false // PuLP-MM - do_edge_bal = true/false, do_maxcut_min = true int do_lp_init = 0; int do_bfs_init = 1; int do_edge_bal = 0; int do_maxcut_min = 0; int verbose_output = 0; // Do label propagation initialization instead of bfs? pe = pl.getEntryPtr("pulp_lp_init"); if (pe) do_lp_init = pe->getValue<int>(&do_lp_init); if (do_lp_init) do_bfs_init = 0; // Now look at additional objective pe = pl.getEntryPtr("pulp_minimize_maxcut"); if (pe) { do_maxcut_min = pe->getValue<int>(&do_maxcut_min); // If we're doing the secondary objective, // set the additional constraint as well if (do_maxcut_min) do_edge_bal = 1; } // Now grab vertex and edge imbalances, defaults at 10% double vert_imbalance = 1.1; double edge_imbalance = 1.1; pe = pl.getEntryPtr("pulp_vert_imbalance"); if (pe) vert_imbalance = pe->getValue<double>(&vert_imbalance); pe = pl.getEntryPtr("pulp_edge_imbalance"); if (pe) { edge_imbalance = pe->getValue<double>(&edge_imbalance); // if manually set edge imbalance, add do_edge_bal flag to true do_edge_bal = 1; } if (vert_imbalance < 1.0) throw std::runtime_error("pulp_vert_imbalance must be '1.0' or greater."); if (edge_imbalance < 1.0) throw std::runtime_error("pulp_edge_imbalance must be '1.0' or greater."); // verbose output? // TODO: fully implement verbose flag throughout PuLP pe = pl.getEntryPtr("pulp_verbose"); if (pe) verbose_output = pe->getValue<int>(&verbose_output); // Create PuLP's partitioning data structure pulp_part_control_t ppc = {vert_imbalance, edge_imbalance, (bool)do_lp_init, (bool)do_bfs_init, (bool)do_edge_bal, (bool)do_maxcut_min, (bool)verbose_output}; if (verbose_output) { printf("n: %i, m: %li, vb: %lf, eb: %lf, p: %i\n", num_verts, num_edges, vert_imbalance, edge_imbalance, num_parts); } // Call partitioning; result returned in parts array ierr = pulp_run(&g, &ppc, parts, num_parts); env->globalInputAssertion(__FILE__, __LINE__, "pulp_run", !ierr, BASIC_ASSERTION, problemComm); // Load answer into the solution if necessary if ((sizeof(int) != sizeof(part_t)) || (num_verts == 0)) { for (int i = 0; i < num_verts; i++) partList[i] = parts[i]; delete [] parts; } solution->setParts(partList); env->memory("Zoltan2-PuLP: After creating solution"); // Clean up copies made due to differing data sizes. TPL_Traits<int, const lno_t>::DELETE_TPL_T_ARRAY(&out_edges); TPL_Traits<long, const gno_t>::DELETE_TPL_T_ARRAY(&out_offsets); //#endif // DO NOT HAVE_MPI }
void AlgZoltan<Adapter>::partition( const RCP<PartitioningSolution<Adapter> > &solution ) { HELLO; char paramstr[128]; size_t numGlobalParts = solution->getTargetGlobalNumberOfParts(); sprintf(paramstr, "%lu", numGlobalParts); zz->Set_Param("NUM_GLOBAL_PARTS", paramstr); int wdim = adapter->getNumWeightsPerID(); sprintf(paramstr, "%d", wdim); zz->Set_Param("OBJ_WEIGHT_DIM", paramstr); const Teuchos::ParameterList &pl = env->getParameters(); double tolerance; const Teuchos::ParameterEntry *pe = pl.getEntryPtr("imbalance_tolerance"); if (pe){ char str[30]; tolerance = pe->getValue<double>(&tolerance); sprintf(str, "%f", tolerance); zz->Set_Param("IMBALANCE_TOL", str); } // Look for zoltan_parameters sublist; pass all zoltan parameters to Zoltan try { const Teuchos::ParameterList &zpl = pl.sublist("zoltan_parameters"); for (ParameterList::ConstIterator iter = zpl.begin(); iter != zpl.end(); iter++) { const std::string &zname = pl.name(iter); // Convert the value to a string to pass to Zoltan std::string &zval = pl.entry(iter).getValue(&zval); zz->Set_Param(zname.c_str(), zval.c_str()); } } catch (std::exception &e) { // No zoltan_parameters sublist found; no Zoltan parameters to register } // Get target part sizes int pdim = (wdim > 1 ? wdim : 1); for (int d = 0; d < pdim; d++) { if (!solution->criteriaHasUniformPartSizes(d)) { float *partsizes = new float[numGlobalParts]; int *partidx = new int[numGlobalParts]; int *wgtidx = new int[numGlobalParts]; for (size_t i=0; i<numGlobalParts; i++) partidx[i] = i; for (size_t i=0; i<numGlobalParts; i++) wgtidx[i] = d; for (size_t i=0; i<numGlobalParts; i++) partsizes[i] = solution->getCriteriaPartSize(0, i); zz->LB_Set_Part_Sizes(1, numGlobalParts, partidx, wgtidx, partsizes); delete [] partsizes; delete [] partidx; delete [] wgtidx; } } // Make the call to LB_Partition int changed = 0; int nGidEnt = 1, nLidEnt = 1; int nDummy = -1; // Dummy vars to satisfy arglist ZOLTAN_ID_PTR dGids = NULL, dLids = NULL; int *dProcs = NULL, *dParts = NULL; int nObj = -1; // Output vars with new part info ZOLTAN_ID_PTR oGids = NULL, oLids = NULL; int *oProcs = NULL, *oParts = NULL; zz->Set_Param("RETURN_LISTS", "PARTS"); // required format for Zoltan2; // results in last five arguments int ierr = zz->LB_Partition(changed, nGidEnt, nLidEnt, nDummy, dGids, dLids, dProcs, dParts, nObj, oGids, oLids, oProcs, oParts); env->globalInputAssertion(__FILE__, __LINE__, "Zoltan LB_Partition", (ierr==ZOLTAN_OK || ierr==ZOLTAN_WARN), BASIC_ASSERTION, problemComm); // Load answer into the solution. ArrayRCP<part_t> partList(new part_t[nObj], 0, nObj, true); for (int i = 0; i < nObj; i++) partList[i] = oParts[oLids[i]]; solution->setParts(partList); // Clean up zz->LB_Free_Part(&oGids, &oLids, &oProcs, &oParts); }