45 #ifndef _ZOLTAN2_ALGPULP_HPP_ 46 #define _ZOLTAN2_ALGPULP_HPP_ 59 #ifndef HAVE_ZOLTAN2_PULP 65 template <
typename Adapter>
70 AlgPuLP(
const RCP<const Environment> &env,
71 const RCP<
const Comm<int> > &problemComm,
72 const RCP<const base_adapter_t> &adapter
75 throw std::runtime_error(
76 "BUILD ERROR: PuLP requested but not compiled into Zoltan2.\n" 77 "Please set CMake flag TPL_ENABLE_PuLP:BOOL=ON.");
94 #ifdef HAVE_ZOLTAN2_PULP 100 #ifndef HAVE_ZOLTAN2_MPI 103 #include "xtrapulp.h" 110 template <
typename Adapter>
115 typedef typename Adapter::lno_t
lno_t;
116 typedef typename Adapter::gno_t
gno_t;
117 typedef typename Adapter::scalar_t
scalar_t;
119 typedef typename Adapter::user_t user_t;
120 typedef typename Adapter::userCoord_t userCoord_t;
132 AlgPuLP(
const RCP<const Environment> &env__,
133 const RCP<
const Comm<int> > &problemComm__,
135 env(env__), problemComm(problemComm__), adapter(adapter__)
137 std::string errStr =
"cannot build GraphModel from IdentifierAdapter, ";
138 errStr +=
"PuLP requires Graph, Matrix, or Mesh Adapter";
139 throw std::runtime_error(errStr);
142 AlgPuLP(
const RCP<const Environment> &env__,
143 const RCP<
const Comm<int> > &problemComm__,
145 env(env__), problemComm(problemComm__), adapter(adapter__)
147 std::string errStr =
"cannot build GraphModel from VectorAdapter, ";
148 errStr +=
"PuLP requires Graph, Matrix, or Mesh Adapter";
149 throw std::runtime_error(errStr);
152 AlgPuLP(
const RCP<const Environment> &env__,
153 const RCP<
const Comm<int> > &problemComm__,
155 env(env__), problemComm(problemComm__), adapter(adapter__)
163 AlgPuLP(
const RCP<const Environment> &env__,
164 const RCP<
const Comm<int> > &problemComm__,
166 env(env__), problemComm(problemComm__), adapter(adapter__)
171 const ParameterList &pl = env->getParameters();
172 const Teuchos::ParameterEntry *pe;
174 std::string defString(
"default");
175 std::string objectOfInterest(defString);
176 pe = pl.getEntryPtr(
"objects_to_partition");
178 objectOfInterest = pe->getValue<std::string>(&objectOfInterest);
180 if (objectOfInterest == defString ||
181 objectOfInterest == std::string(
"matrix_rows") )
183 else if (objectOfInterest == std::string(
"matrix_columns"))
185 else if (objectOfInterest == std::string(
"matrix_nonzeros"))
191 AlgPuLP(
const RCP<const Environment> &env__,
192 const RCP<
const Comm<int> > &problemComm__,
194 env(env__), problemComm(problemComm__), adapter(adapter__)
199 const ParameterList &pl = env->getParameters();
200 const Teuchos::ParameterEntry *pe;
202 std::string defString(
"default");
203 std::string objectOfInterest(defString);
204 pe = pl.getEntryPtr(
"objects_to_partition");
206 objectOfInterest = pe->getValue<std::string>(&objectOfInterest);
208 if (objectOfInterest == defString ||
209 objectOfInterest == std::string(
"mesh_nodes") )
211 else if (objectOfInterest == std::string(
"mesh_elements"))
221 pl.set(
"pulp_vert_imbalance", 1.1,
"vertex imbalance tolerance, ratio of " 222 "maximum load over average load",
225 pl.set(
"pulp_edge_imbalance", 1.1,
"edge imbalance tolerance, ratio of " 226 "maximum load over average load",
230 pl.set(
"pulp_lp_init",
false,
"perform label propagation-based " 234 pl.set(
"pulp_minimize_maxcut",
false,
"perform per-part max cut " 238 pl.set(
"pulp_verbose",
false,
"verbose output",
242 pl.set(
"pulp_do_repart",
false,
"perform repartitioning",
257 const RCP<const Environment> env;
258 const RCP<const Comm<int> > problemComm;
259 const RCP<const base_adapter_t> adapter;
260 RCP<const GraphModel<base_adapter_t> > model;
265 template <
typename Adapter>
268 const ParameterList &pl = env->getParameters();
269 const Teuchos::ParameterEntry *pe;
271 std::string defString(
"default");
272 std::string symParameter(defString);
273 pe = pl.getEntryPtr(
"symmetrize_graph");
275 symParameter = pe->getValue<std::string>(&symParameter);
276 if (symParameter == std::string(
"transpose"))
278 else if (symParameter == std::string(
"bipartite"))
281 bool sgParameter =
false;
282 pe = pl.getEntryPtr(
"subset_graph");
284 sgParameter = pe->getValue(&sgParameter);
290 #ifndef HAVE_ZOLTAN2_MPI 295 this->problemComm, flags));
303 template <
typename Adapter>
310 size_t numGlobalParts = solution->getTargetGlobalNumberOfParts();
312 int num_parts = (int)numGlobalParts;
319 int np = problemComm->getSize();
322 const size_t modelVerts = model->getLocalNumVertices();
323 const size_t modelEdges = model->getLocalNumEdges();
324 int num_verts = (int)modelVerts;
325 long num_edges = (long)modelEdges;
330 ArrayView<const gno_t> vtxIDs;
331 ArrayView<StridedData<lno_t, scalar_t> > vwgts;
332 size_t nVtx = model->getVertexList(vtxIDs, vwgts);
333 int nVwgts = model->getNumWeightsPerVertex();
335 std::cerr <<
"Warning: NumWeightsPerVertex is " << nVwgts
336 <<
" but PuLP allows only one weight. " 337 <<
" Zoltan2 will use only the first weight per vertex." 341 int* vertex_weights = NULL;
342 long vertex_weights_sum = 0;
344 vertex_weights =
new int[nVtx];
345 scale_weights(nVtx, vwgts[0], vertex_weights);
346 for (
int i = 0; i < num_verts; ++i)
347 vertex_weights_sum += vertex_weights[i];
351 ArrayView<const gno_t> adjs;
352 ArrayView<const lno_t> offsets;
353 ArrayView<StridedData<lno_t, scalar_t> > ewgts;
354 size_t nEdge = model->getEdgeList(adjs, offsets, ewgts);
355 int nEwgts = model->getNumWeightsPerEdge();
357 std::cerr <<
"Warning: NumWeightsPerEdge is " << nEwgts
358 <<
" but PuLP allows only one weight. " 359 <<
" Zoltan2 will use only the first weight per edge." 363 int* edge_weights = NULL;
365 edge_weights =
new int[nEdge];
366 scale_weights(nEdge, ewgts[0], edge_weights);
369 #ifndef HAVE_ZOLTAN2_MPI 371 int* out_edges = NULL;
372 long* out_offsets = NULL;
376 pulp_graph_t g = {num_verts, num_edges,
377 out_edges, out_offsets,
378 vertex_weights, edge_weights, vertex_weights_sum};
382 unsigned long* out_edges = NULL;
383 unsigned long* out_offsets = NULL;
387 const size_t modelVertsGlobal = model->getGlobalNumVertices();
388 const size_t modelEdgesGlobal = model->getGlobalNumEdges();
389 unsigned long num_verts_global = (
unsigned long)modelVertsGlobal;
390 unsigned long num_edges_global = (
unsigned long)modelEdgesGlobal;
392 unsigned long* global_ids = NULL;
395 ArrayView<size_t> vtxDist;
396 model->getVertexDist(vtxDist);
397 unsigned long* verts_per_rank =
new unsigned long[np+1];
398 for (
int i = 0; i < np+1; ++i)
399 verts_per_rank[i] = vtxDist[i];
402 create_xtrapulp_dist_graph(&g, num_verts_global, num_edges_global,
403 (
unsigned long)num_verts, (
unsigned long)num_edges,
404 out_edges, out_offsets, global_ids, verts_per_rank,
405 vertex_weights, edge_weights);
411 ArrayRCP<part_t> partList(
new part_t[num_verts], 0, num_verts,
true);
413 if (num_verts && (
sizeof(
int) ==
sizeof(
part_t))) {
415 parts = (
int *) partList.getRawPtr();
419 parts =
new int[num_verts];
426 const Teuchos::ParameterList &pl = env->getParameters();
427 const Teuchos::ParameterEntry *pe;
434 bool do_lp_init =
false;
435 bool do_bfs_init =
true;
436 bool do_edge_bal =
false;
437 bool do_repart =
false;
438 bool do_maxcut_min =
false;
439 bool verbose_output =
false;
442 pe = pl.getEntryPtr(
"pulp_lp_init");
443 if (pe) do_lp_init = pe->getValue(&do_lp_init);
444 if (do_lp_init) do_bfs_init =
false;
447 pe = pl.getEntryPtr(
"pulp_minimize_maxcut");
449 do_maxcut_min = pe->getValue(&do_maxcut_min);
452 if (do_maxcut_min) do_edge_bal =
true;
455 pe = pl.getEntryPtr(
"pulp_do_repart");
457 do_repart = pe->getValue(&do_repart);
467 double vert_imbalance = 1.1;
468 double edge_imbalance = 1.1;
470 pe = pl.getEntryPtr(
"pulp_vert_imbalance");
471 if (pe) vert_imbalance = pe->getValue<
double>(&vert_imbalance);
472 pe = pl.getEntryPtr(
"pulp_edge_imbalance");
474 edge_imbalance = pe->getValue<
double>(&edge_imbalance);
479 if (vert_imbalance < 1.0)
480 throw std::runtime_error(
"pulp_vert_imbalance must be '1.0' or greater.");
481 if (edge_imbalance < 1.0)
482 throw std::runtime_error(
"pulp_edge_imbalance must be '1.0' or greater.");
486 pe = pl.getEntryPtr(
"pulp_verbose");
487 if (pe) verbose_output = pe->getValue(&verbose_output);
490 int pulp_seed = rand();
491 pe = pl.getEntryPtr(
"pulp_seed");
492 if (pe) pulp_seed = pe->getValue(&pulp_seed);
495 pulp_part_control_t ppc = {vert_imbalance, edge_imbalance,
496 do_lp_init, do_bfs_init, do_repart,
497 do_edge_bal, do_maxcut_min,
498 verbose_output, pulp_seed};
501 if (verbose_output) {
502 printf(
"procid: %d, n: %i, m: %li, vb: %f, eb: %f, p: %i\n",
503 problemComm->getRank(),
504 num_verts, num_edges, vert_imbalance, edge_imbalance, num_parts);
508 #ifndef HAVE_ZOLTAN2_MPI 509 ierr = pulp_run(&g, &ppc, parts, num_parts);
511 env->globalInputAssertion(__FILE__, __LINE__,
"pulp_run",
514 ierr = xtrapulp_run(&g, &ppc, parts, num_parts);
515 env->globalInputAssertion(__FILE__, __LINE__,
"xtrapulp_run",
522 if ((
sizeof(
int) !=
sizeof(
part_t)) || (num_verts == 0)) {
523 for (
int i = 0; i < num_verts; i++) partList[i] = parts[i];
527 solution->setParts(partList);
529 env->memory(
"Zoltan2-(Xtra)PuLP: After creating solution");
532 #ifndef HAVE_ZOLTAN2_MPI 554 template <
typename Adapter>
561 const double INT_EPSILON = 1e-5;
562 const double MAX_NUM = 1e9;
565 double sum_wgt = 0.0;
566 double max_wgt = 0.0;
570 for (
size_t i = 0; i < n; i++) {
571 double fw = double(fwgts[i]);
573 int tmp = (int) floor(fw + .5);
574 if (fabs((
double)tmp-fw) > INT_EPSILON) {
579 if (fw > max_wgt) max_wgt = fw;
584 double ltmp[2], gtmp[2];
587 Teuchos::reduceAll<int,double>(*problemComm, Teuchos::REDUCE_SUM, 2,
589 Teuchos::reduceAll<int,double>(*problemComm, Teuchos::REDUCE_MAX, 1,
590 &max_wgt, &gmax_wgt);
598 if (nonint || (max_wgt <= INT_EPSILON) || (sum_wgt > MAX_NUM)) {
600 if (sum_wgt != 0.0) scale = MAX_NUM/sum_wgt;
604 for (
size_t i = 0; i < n; i++)
605 iwgts[i] = (
int) ceil(
double(fwgts[i])*scale);
612 #endif // HAVE_ZOLTAN2_PULP use columns as graph vertices
Zoltan2::BaseAdapter< userTypes_t > base_adapter_t
IdentifierAdapter defines the interface for identifiers.
use mesh nodes as vertices
fast typical checks for valid arguments
MatrixAdapter defines the adapter interface for matrices.
Adapter::base_adapter_t base_adapter_t
GraphAdapter defines the interface for graph-based user data.
static RCP< Teuchos::BoolParameterEntryValidator > getBoolValidator()
Exists to make setting up validators less cluttered.
algorithm requires consecutive ids
MeshAdapter defines the interface for mesh input.
std::bitset< NUM_MODEL_FLAGS > modelFlag_t
model must symmetrize input
model must symmetrize input
Defines the PartitioningSolution class.
static RCP< Teuchos::AnyNumberParameterEntryValidator > getAnyDoubleValidator()
Exists to make setting up validators less cluttered.
sub-steps, each method's entry and exit
SparseMatrixAdapter_t::part_t part_t
use matrix rows as graph vertices
algorithm requires no self edges
Adapter::scalar_t scalar_t
A PartitioningSolution is a solution to a partitioning problem.
use nonzeros as graph vertices
VectorAdapter defines the interface for vector input.
The StridedData class manages lists of weights or coordinates.
Algorithm defines the base class for all algorithms.
static RCP< Teuchos::AnyNumberParameterEntryValidator > getAnyIntValidator()
Exists to make setting up validators less cluttered.
virtual void partition(const RCP< PartitioningSolution< Adapter > > &solution)
Partitioning method.
Traits class to handle conversions between gno_t/lno_t and TPL data types (e.g., ParMETIS's idx_t...
static void getValidParameters(ParameterList &pl)
Set up validators specific to this algorithm.
use mesh elements as vertices
GraphModel defines the interface required for graph models.
static void ASSIGN_ARRAY(first_t **a, ArrayView< second_t > &b)
Defines the GraphModel interface.
AlgPuLP(const RCP< const Environment > &env, const RCP< const Comm< int > > &problemComm, const RCP< const base_adapter_t > &adapter)
A gathering of useful namespace methods.
static void DELETE_ARRAY(first_t **a)
model represents graph within only one rank