45 #ifndef _ZOLTAN2_ALGPULP_HPP_
46 #define _ZOLTAN2_ALGPULP_HPP_
59 #ifndef HAVE_ZOLTAN2_PULP
65 template <
typename Adapter>
71 const RCP<
const Comm<int> > &,
72 const RCP<const base_adapter_t> &
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>
111 class AlgPuLP :
public Algorithm<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;
121 typedef typename Adapter::userCoord_t userCoord_t;
133 AlgPuLP(
const RCP<const Environment> &env__,
134 const RCP<
const Comm<int> > &problemComm__,
135 const RCP<
const IdentifierAdapter<user_t> > &adapter__) :
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__,
145 const RCP<
const VectorAdapter<user_t> > &adapter__) :
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__,
155 const RCP<
const GraphAdapter<user_t,userCoord_t> > &adapter__) :
156 env(env__), problemComm(problemComm__), adapter(adapter__)
164 AlgPuLP(
const RCP<const Environment> &env__,
165 const RCP<
const Comm<int> > &problemComm__,
166 const RCP<
const MatrixAdapter<user_t,userCoord_t> > &adapter__) :
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__,
194 const RCP<
const MeshAdapter<user_t> > &adapter__) :
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",
249 void partition(
const RCP<PartitioningSolution<Adapter> > &solution);
255 void scale_weights(
size_t n, StridedData<lno_t, scalar_t> &fwgts,
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>
267 void AlgPuLP<Adapter>::buildModel(
modelFlag_t &flags)
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
295 this->model = rcp(
new GraphModel<base_adapter_t>(this->adapter, this->env,
296 this->problemComm, flags));
304 template <
typename Adapter>
306 const RCP<PartitioningSolution<Adapter> > &solution
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>
556 void AlgPuLP<Adapter>::scale_weights(
558 StridedData<typename Adapter::lno_t, typename Adapter::scalar_t> &fwgts,
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
use mesh nodes as vertices
virtual void partition(const RCP< PartitioningSolution< Adapter > > &)
Partitioning method.
fast typical checks for valid arguments
Adapter::base_adapter_t base_adapter_t
static RCP< Teuchos::BoolParameterEntryValidator > getBoolValidator()
Exists to make setting up validators less cluttered.
algorithm requires consecutive ids
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
use nonzeros as graph vertices
Algorithm defines the base class for all algorithms.
static RCP< Teuchos::AnyNumberParameterEntryValidator > getAnyIntValidator()
Exists to make setting up validators less cluttered.
Traits class to handle conversions between gno_t/lno_t and TPL data types (e.g., ParMETIS's idx_t...
use mesh elements as vertices
static void ASSIGN_ARRAY(first_t **a, ArrayView< second_t > &b)
Defines the GraphModel interface.
A gathering of useful namespace methods.
static void DELETE_ARRAY(first_t **a)
model represents graph within only one rank
static void getValidParameters(ParameterList &)
Set up validators specific to this algorithm.
AlgPuLP(const RCP< const Environment > &, const RCP< const Comm< int > > &, const RCP< const base_adapter_t > &)
Zoltan2::BasicUserTypes< zscalar_t, zlno_t, zgno_t > user_t