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::offset_t offset_t;
118 typedef typename Adapter::scalar_t
scalar_t;
120 typedef typename Adapter::user_t user_t;
121 typedef typename Adapter::userCoord_t userCoord_t;
133 AlgPuLP(
const RCP<const Environment> &env__,
134 const RCP<
const Comm<int> > &problemComm__,
136 env(env__), problemComm(problemComm__), adapter(adapter__)
138 std::string errStr =
"cannot build GraphModel from IdentifierAdapter, ";
139 errStr +=
"PuLP requires Graph, Matrix, or Mesh Adapter";
140 throw std::runtime_error(errStr);
143 AlgPuLP(
const RCP<const Environment> &env__,
144 const RCP<
const Comm<int> > &problemComm__,
146 env(env__), problemComm(problemComm__), adapter(adapter__)
148 std::string errStr =
"cannot build GraphModel from VectorAdapter, ";
149 errStr +=
"PuLP requires Graph, Matrix, or Mesh Adapter";
150 throw std::runtime_error(errStr);
153 AlgPuLP(
const RCP<const Environment> &env__,
154 const RCP<
const Comm<int> > &problemComm__,
156 env(env__), problemComm(problemComm__), adapter(adapter__)
164 AlgPuLP(
const RCP<const Environment> &env__,
165 const RCP<
const Comm<int> > &problemComm__,
167 env(env__), problemComm(problemComm__), adapter(adapter__)
172 const ParameterList &pl = env->getParameters();
173 const Teuchos::ParameterEntry *pe;
175 std::string defString(
"default");
176 std::string objectOfInterest(defString);
177 pe = pl.getEntryPtr(
"objects_to_partition");
179 objectOfInterest = pe->getValue<std::string>(&objectOfInterest);
181 if (objectOfInterest == defString ||
182 objectOfInterest == std::string(
"matrix_rows") )
184 else if (objectOfInterest == std::string(
"matrix_columns"))
186 else if (objectOfInterest == std::string(
"matrix_nonzeros"))
192 AlgPuLP(
const RCP<const Environment> &env__,
193 const RCP<
const Comm<int> > &problemComm__,
195 env(env__), problemComm(problemComm__), adapter(adapter__)
200 const ParameterList &pl = env->getParameters();
201 const Teuchos::ParameterEntry *pe;
203 std::string defString(
"default");
204 std::string objectOfInterest(defString);
205 pe = pl.getEntryPtr(
"objects_to_partition");
207 objectOfInterest = pe->getValue<std::string>(&objectOfInterest);
209 if (objectOfInterest == defString ||
210 objectOfInterest == std::string(
"mesh_nodes") )
212 else if (objectOfInterest == std::string(
"mesh_elements"))
222 pl.set(
"pulp_vert_imbalance", 1.1,
"vertex imbalance tolerance, ratio of " 223 "maximum load over average load",
226 pl.set(
"pulp_edge_imbalance", 1.1,
"edge imbalance tolerance, ratio of " 227 "maximum load over average load",
231 pl.set(
"pulp_lp_init",
false,
"perform label propagation-based " 235 pl.set(
"pulp_minimize_maxcut",
false,
"perform per-part max cut " 239 pl.set(
"pulp_verbose",
false,
"verbose output",
243 pl.set(
"pulp_do_repart",
false,
"perform repartitioning",
258 const RCP<const Environment> env;
259 const RCP<const Comm<int> > problemComm;
260 const RCP<const base_adapter_t> adapter;
261 RCP<const GraphModel<base_adapter_t> > model;
266 template <
typename Adapter>
269 const ParameterList &pl = env->getParameters();
270 const Teuchos::ParameterEntry *pe;
272 std::string defString(
"default");
273 std::string symParameter(defString);
274 pe = pl.getEntryPtr(
"symmetrize_graph");
276 symParameter = pe->getValue<std::string>(&symParameter);
277 if (symParameter == std::string(
"transpose"))
279 else if (symParameter == std::string(
"bipartite"))
282 bool sgParameter =
false;
283 pe = pl.getEntryPtr(
"subset_graph");
285 sgParameter = pe->getValue(&sgParameter);
291 #ifndef HAVE_ZOLTAN2_MPI 296 this->problemComm, flags));
304 template <
typename Adapter>
311 size_t numGlobalParts = solution->getTargetGlobalNumberOfParts();
313 int num_parts = (int)numGlobalParts;
320 int np = problemComm->getSize();
323 const size_t modelVerts = model->getLocalNumVertices();
324 const size_t modelEdges = model->getLocalNumEdges();
325 int num_verts = (int)modelVerts;
326 long num_edges = (long)modelEdges;
331 ArrayView<const gno_t> vtxIDs;
332 ArrayView<StridedData<lno_t, scalar_t> > vwgts;
333 size_t nVtx = model->getVertexList(vtxIDs, vwgts);
334 int nVwgts = model->getNumWeightsPerVertex();
336 std::cerr <<
"Warning: NumWeightsPerVertex is " << nVwgts
337 <<
" but PuLP allows only one weight. " 338 <<
" Zoltan2 will use only the first weight per vertex." 342 int* vertex_weights = NULL;
343 long vertex_weights_sum = 0;
345 vertex_weights =
new int[nVtx];
346 scale_weights(nVtx, vwgts[0], vertex_weights);
347 for (
int i = 0; i < num_verts; ++i)
348 vertex_weights_sum += vertex_weights[i];
352 ArrayView<const gno_t> adjs;
353 ArrayView<const offset_t> offsets;
354 ArrayView<StridedData<lno_t, scalar_t> > ewgts;
355 size_t nEdge = model->getEdgeList(adjs, offsets, ewgts);
356 int nEwgts = model->getNumWeightsPerEdge();
358 std::cerr <<
"Warning: NumWeightsPerEdge is " << nEwgts
359 <<
" but PuLP allows only one weight. " 360 <<
" Zoltan2 will use only the first weight per edge." 364 int* edge_weights = NULL;
366 edge_weights =
new int[nEdge];
367 scale_weights(nEdge, ewgts[0], edge_weights);
370 #ifndef HAVE_ZOLTAN2_MPI 372 int* out_edges = NULL;
373 long* out_offsets = NULL;
377 pulp_graph_t g = {num_verts, num_edges,
378 out_edges, out_offsets,
379 vertex_weights, edge_weights, vertex_weights_sum};
383 unsigned long* out_edges = NULL;
384 unsigned long* out_offsets = NULL;
388 const size_t modelVertsGlobal = model->getGlobalNumVertices();
389 const size_t modelEdgesGlobal = model->getGlobalNumEdges();
390 unsigned long num_verts_global = (
unsigned long)modelVertsGlobal;
391 unsigned long num_edges_global = (
unsigned long)modelEdgesGlobal;
393 unsigned long* global_ids = NULL;
396 ArrayView<size_t> vtxDist;
397 model->getVertexDist(vtxDist);
398 unsigned long* verts_per_rank =
new unsigned long[np+1];
399 for (
int i = 0; i < np+1; ++i)
400 verts_per_rank[i] = vtxDist[i];
403 create_xtrapulp_dist_graph(&g, num_verts_global, num_edges_global,
404 (
unsigned long)num_verts, (
unsigned long)num_edges,
405 out_edges, out_offsets, global_ids, verts_per_rank,
406 vertex_weights, edge_weights);
412 ArrayRCP<part_t> partList(
new part_t[num_verts], 0, num_verts,
true);
414 if (num_verts && (
sizeof(
int) ==
sizeof(
part_t))) {
416 parts = (
int *) partList.getRawPtr();
420 parts =
new int[num_verts];
427 const Teuchos::ParameterList &pl = env->getParameters();
428 const Teuchos::ParameterEntry *pe;
435 bool do_lp_init =
false;
436 bool do_bfs_init =
true;
437 bool do_edge_bal =
false;
438 bool do_repart =
false;
439 bool do_maxcut_min =
false;
440 bool verbose_output =
false;
443 pe = pl.getEntryPtr(
"pulp_lp_init");
444 if (pe) do_lp_init = pe->getValue(&do_lp_init);
445 if (do_lp_init) do_bfs_init =
false;
448 pe = pl.getEntryPtr(
"pulp_minimize_maxcut");
450 do_maxcut_min = pe->getValue(&do_maxcut_min);
453 if (do_maxcut_min) do_edge_bal =
true;
456 pe = pl.getEntryPtr(
"pulp_do_repart");
458 do_repart = pe->getValue(&do_repart);
468 double vert_imbalance = 1.1;
469 double edge_imbalance = 1.1;
471 pe = pl.getEntryPtr(
"pulp_vert_imbalance");
472 if (pe) vert_imbalance = pe->getValue<
double>(&vert_imbalance);
473 pe = pl.getEntryPtr(
"pulp_edge_imbalance");
475 edge_imbalance = pe->getValue<
double>(&edge_imbalance);
480 if (vert_imbalance < 1.0)
481 throw std::runtime_error(
"pulp_vert_imbalance must be '1.0' or greater.");
482 if (edge_imbalance < 1.0)
483 throw std::runtime_error(
"pulp_edge_imbalance must be '1.0' or greater.");
487 pe = pl.getEntryPtr(
"pulp_verbose");
488 if (pe) verbose_output = pe->getValue(&verbose_output);
491 int pulp_seed = rand();
492 pe = pl.getEntryPtr(
"pulp_seed");
493 if (pe) pulp_seed = pe->getValue(&pulp_seed);
496 pulp_part_control_t ppc = {vert_imbalance, edge_imbalance,
497 do_lp_init, do_bfs_init, do_repart,
498 do_edge_bal, do_maxcut_min,
499 verbose_output, pulp_seed};
502 if (verbose_output) {
503 printf(
"procid: %d, n: %i, m: %li, vb: %f, eb: %f, p: %i\n",
504 problemComm->getRank(),
505 num_verts, num_edges, vert_imbalance, edge_imbalance, num_parts);
509 #ifndef HAVE_ZOLTAN2_MPI 510 ierr = pulp_run(&g, &ppc, parts, num_parts);
512 env->globalInputAssertion(__FILE__, __LINE__,
"pulp_run",
515 ierr = xtrapulp_run(&g, &ppc, parts, num_parts);
516 env->globalInputAssertion(__FILE__, __LINE__,
"xtrapulp_run",
523 if ((
sizeof(
int) !=
sizeof(
part_t)) || (num_verts == 0)) {
524 for (
int i = 0; i < num_verts; i++) partList[i] = parts[i];
528 solution->setParts(partList);
530 env->memory(
"Zoltan2-(Xtra)PuLP: After creating solution");
533 #ifndef HAVE_ZOLTAN2_MPI 555 template <
typename Adapter>
562 const double INT_EPSILON = 1e-5;
563 const double MAX_NUM = 1e9;
566 double sum_wgt = 0.0;
567 double max_wgt = 0.0;
571 for (
size_t i = 0; i < n; i++) {
572 double fw = double(fwgts[i]);
574 int tmp = (int) floor(fw + .5);
575 if (fabs((
double)tmp-fw) > INT_EPSILON) {
580 if (fw > max_wgt) max_wgt = fw;
585 double ltmp[2], gtmp[2];
588 Teuchos::reduceAll<int,double>(*problemComm, Teuchos::REDUCE_SUM, 2,
590 Teuchos::reduceAll<int,double>(*problemComm, Teuchos::REDUCE_MAX, 1,
591 &max_wgt, &gmax_wgt);
599 if (nonint || (max_wgt <= INT_EPSILON) || (sum_wgt > MAX_NUM)) {
601 if (sum_wgt != 0.0) scale = MAX_NUM/sum_wgt;
605 for (
size_t i = 0; i < n; i++)
606 iwgts[i] = (
int) ceil(
double(fwgts[i])*scale);
613 #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