Zoltan2
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
Zoltan2_AlgPuLP.hpp
Go to the documentation of this file.
1 // @HEADER
2 //
3 // ***********************************************************************
4 //
5 // Zoltan2: A package of combinatorial algorithms for scientific computing
6 // Copyright 2012 Sandia Corporation
7 //
8 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
9 // the U.S. Government retains certain rights in this software.
10 //
11 // Redistribution and use in source and binary forms, with or without
12 // modification, are permitted provided that the following conditions are
13 // met:
14 //
15 // 1. Redistributions of source code must retain the above copyright
16 // notice, this list of conditions and the following disclaimer.
17 //
18 // 2. Redistributions in binary form must reproduce the above copyright
19 // notice, this list of conditions and the following disclaimer in the
20 // documentation and/or other materials provided with the distribution.
21 //
22 // 3. Neither the name of the Corporation nor the names of the
23 // contributors may be used to endorse or promote products derived from
24 // this software without specific prior written permission.
25 //
26 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 //
38 // Questions? Contact Karen Devine (kddevin@sandia.gov)
39 // Erik Boman (egboman@sandia.gov)
40 // Siva Rajamanickam (srajama@sandia.gov)
41 //
42 // ***********************************************************************
43 //
44 // @HEADER
45 #ifndef _ZOLTAN2_ALGPULP_HPP_
46 #define _ZOLTAN2_ALGPULP_HPP_
47 
48 #include <Zoltan2_GraphModel.hpp>
49 #include <Zoltan2_Algorithm.hpp>
51 #include <Zoltan2_Util.hpp>
52 #include <Zoltan2_TPLTraits.hpp>
53 
57 
59 #ifndef HAVE_ZOLTAN2_PULP
60 
61 namespace Zoltan2 {
62 // Error handling for when PuLP is requested
63 // but Zoltan2 not built with PuLP.
64 
65 template <typename Adapter>
66 class AlgPuLP : public Algorithm<Adapter>
67 {
68 public:
70  AlgPuLP(const RCP<const Environment> &/* env */,
71  const RCP<const Comm<int> > &/* problemComm */,
72  const RCP<const base_adapter_t> &/* adapter */
73  )
74  {
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.");
78  }
79 
82  static void getValidParameters(ParameterList & /* pl */)
83  {
84  // No parameters needed in this error-handling version of AlgPuLP
85  }
86 };
87 
88 }
89 #endif
90 
93 
94 #ifdef HAVE_ZOLTAN2_PULP
95 
96 namespace Zoltan2 {
97 
98 extern "C" {
99 // TODO: XtraPuLP
100 #ifndef HAVE_ZOLTAN2_MPI
101 #include "pulp.h"
102 #else
103 #include "xtrapulp.h"
104 #endif
105 }
106 
107 
108 
109 
110 template <typename Adapter>
111 class AlgPuLP : public Algorithm<Adapter>
112 {
113 public:
114  typedef typename Adapter::base_adapter_t base_adapter_t;
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;
119  typedef typename Adapter::part_t part_t;
120  typedef typename Adapter::user_t user_t;
121  typedef typename Adapter::userCoord_t userCoord_t;
122 
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__)
137  {
138  std::string errStr = "cannot build GraphModel from IdentifierAdapter, ";
139  errStr += "PuLP requires Graph, Matrix, or Mesh Adapter";
140  throw std::runtime_error(errStr);
141  }
142 
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__)
147  {
148  std::string errStr = "cannot build GraphModel from VectorAdapter, ";
149  errStr += "PuLP requires Graph, Matrix, or Mesh Adapter";
150  throw std::runtime_error(errStr);
151  }
152 
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__)
157  {
158  modelFlag_t flags;
159  flags.reset();
160 
161  buildModel(flags);
162  }
163 
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__)
168  {
169  modelFlag_t flags;
170  flags.reset();
171 
172  const ParameterList &pl = env->getParameters();
173  const Teuchos::ParameterEntry *pe;
174 
175  std::string defString("default");
176  std::string objectOfInterest(defString);
177  pe = pl.getEntryPtr("objects_to_partition");
178  if (pe)
179  objectOfInterest = pe->getValue<std::string>(&objectOfInterest);
180 
181  if (objectOfInterest == defString ||
182  objectOfInterest == std::string("matrix_rows") )
183  flags.set(VERTICES_ARE_MATRIX_ROWS);
184  else if (objectOfInterest == std::string("matrix_columns"))
185  flags.set(VERTICES_ARE_MATRIX_COLUMNS);
186  else if (objectOfInterest == std::string("matrix_nonzeros"))
187  flags.set(VERTICES_ARE_MATRIX_NONZEROS);
188 
189  buildModel(flags);
190  }
191 
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__)
196  {
197  modelFlag_t flags;
198  flags.reset();
199 
200  const ParameterList &pl = env->getParameters();
201  const Teuchos::ParameterEntry *pe;
202 
203  std::string defString("default");
204  std::string objectOfInterest(defString);
205  pe = pl.getEntryPtr("objects_to_partition");
206  if (pe)
207  objectOfInterest = pe->getValue<std::string>(&objectOfInterest);
208 
209  if (objectOfInterest == defString ||
210  objectOfInterest == std::string("mesh_nodes") )
211  flags.set(VERTICES_ARE_MESH_NODES);
212  else if (objectOfInterest == std::string("mesh_elements"))
213  flags.set(VERTICES_ARE_MESH_ELEMENTS);
214 
215  buildModel(flags);
216  }
217 
220  static void getValidParameters(ParameterList & pl)
221  {
222  pl.set("pulp_vert_imbalance", 1.1, "vertex imbalance tolerance, ratio of "
223  "maximum load over average load",
225 
226  pl.set("pulp_edge_imbalance", 1.1, "edge imbalance tolerance, ratio of "
227  "maximum load over average load",
229 
230  // bool parameter
231  pl.set("pulp_lp_init", false, "perform label propagation-based "
232  "initialization", Environment::getBoolValidator() );
233 
234  // bool parameter
235  pl.set("pulp_minimize_maxcut", false, "perform per-part max cut "
236  "minimization", Environment::getBoolValidator() );
237 
238  // bool parameter
239  pl.set("pulp_verbose", false, "verbose output",
241 
242  // bool parameter
243  pl.set("pulp_do_repart", false, "perform repartitioning",
245 
246  pl.set("pulp_seed", 0, "set pulp seed", Environment::getAnyIntValidator());
247  }
248 
249  void partition(const RCP<PartitioningSolution<Adapter> > &solution);
250 
251 private:
252 
253  void buildModel(modelFlag_t &flags);
254 
255  void scale_weights(size_t n, StridedData<lno_t, scalar_t> &fwgts,
256  int *iwgts);
257 
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;
262 };
263 
264 
266 template <typename Adapter>
267 void AlgPuLP<Adapter>::buildModel(modelFlag_t &flags)
268 {
269  const ParameterList &pl = env->getParameters();
270  const Teuchos::ParameterEntry *pe;
271 
272  std::string defString("default");
273  std::string symParameter(defString);
274  pe = pl.getEntryPtr("symmetrize_graph");
275  if (pe){
276  symParameter = pe->getValue<std::string>(&symParameter);
277  if (symParameter == std::string("transpose"))
278  flags.set(SYMMETRIZE_INPUT_TRANSPOSE);
279  else if (symParameter == std::string("bipartite"))
280  flags.set(SYMMETRIZE_INPUT_BIPARTITE); }
281 
282  bool sgParameter = false;
283  pe = pl.getEntryPtr("subset_graph");
284  if (pe)
285  sgParameter = pe->getValue(&sgParameter);
286  if (sgParameter)
287  flags.set(BUILD_SUBSET_GRAPH);
288 
289  flags.set(REMOVE_SELF_EDGES);
290  flags.set(GENERATE_CONSECUTIVE_IDS);
291 #ifndef HAVE_ZOLTAN2_MPI
292  flags.set(BUILD_LOCAL_GRAPH);
293 #endif
294  this->env->debug(DETAILED_STATUS, " building graph model");
295  this->model = rcp(new GraphModel<base_adapter_t>(this->adapter, this->env,
296  this->problemComm, flags));
297  this->env->debug(DETAILED_STATUS, " graph model built");
298 }
299 
300 /*
301 NOTE:
302  Assumes installed PuLP library is version pulp-0.2
303 */
304 template <typename Adapter>
306  const RCP<PartitioningSolution<Adapter> > &solution
307 )
308 {
309  HELLO;
310 
311  size_t numGlobalParts = solution->getTargetGlobalNumberOfParts();
312 
313  int num_parts = (int)numGlobalParts;
314  //TPL_Traits<int, size_t>::ASSIGN(num_parts, numGlobalParts, env);
315 
316  //#ifdef HAVE_ZOLTAN2_MPI
317  // TODO: XtraPuLP
318 
319  int ierr = 0;
320  int np = problemComm->getSize();
321 
322  // Get number of vertices and edges
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;
327  //TPL_Traits<int, size_t>::ASSIGN(num_verts, modelVerts, env);
328  //TPL_Traits<long, size_t>::ASSIGN(num_edges, modelEdges, env);
329 
330  // Get vertex info
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();
335  if (nVwgts > 1) {
336  std::cerr << "Warning: NumWeightsPerVertex is " << nVwgts
337  << " but PuLP allows only one weight. "
338  << " Zoltan2 will use only the first weight per vertex."
339  << std::endl;
340  }
341 
342  int* vertex_weights = NULL;
343  long vertex_weights_sum = 0;
344  if (nVwgts) {
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];
349  }
350 
351  // Get edge info
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();
357  if (nEwgts > 1) {
358  std::cerr << "Warning: NumWeightsPerEdge is " << nEwgts
359  << " but PuLP allows only one weight. "
360  << " Zoltan2 will use only the first weight per edge."
361  << std::endl;
362  }
363 
364  int* edge_weights = NULL;
365  if (nEwgts) {
366  edge_weights = new int[nEdge];
367  scale_weights(nEdge, ewgts[0], edge_weights);
368  }
369 
370 #ifndef HAVE_ZOLTAN2_MPI
371  // Create PuLP's graph structure
372  int* out_edges = NULL;
373  long* out_offsets = NULL;
375  TPL_Traits<long, const offset_t>::ASSIGN_ARRAY(&out_offsets, offsets);
376 
377  pulp_graph_t g = {num_verts, num_edges,
378  out_edges, out_offsets,
379  vertex_weights, edge_weights, vertex_weights_sum};
380 
381 #else
382  // Create XtraPuLP's graph structure
383  unsigned long* out_edges = NULL;
384  unsigned long* out_offsets = NULL;
387 
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;
392 
393  unsigned long* global_ids = NULL;
395 
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];
401 
402  dist_graph_t g;
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);
407 #endif
408 
409 
410  // Create array for PuLP to return results in.
411  // Or write directly into solution parts array
412  ArrayRCP<part_t> partList(new part_t[num_verts], 0, num_verts, true);
413  int* parts = NULL;
414  if (num_verts && (sizeof(int) == sizeof(part_t))) {
415  // Can write directly into the solution's memory
416  parts = (int *) partList.getRawPtr();
417  }
418  else {
419  // Can't use solution memory directly; will have to copy later.
420  parts = new int[num_verts];
421  }
422 
423  // TODO
424  // Implement target part sizes
425 
426  // Grab options from parameter list
427  const Teuchos::ParameterList &pl = env->getParameters();
428  const Teuchos::ParameterEntry *pe;
429 
430  // figure out which parts of the algorithm we're going to run
431  // Default to PuLP with BFS init
432  // PuLP - do_edge_min = false, do_maxcut_min = false
433  // PuLP-M - do_edge_bal = true, do_maxcut_min = false
434  // PuLP-MM - do_edge_bal = true/false, do_maxcut_min = true
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;
441 
442  // Do label propagation initialization instead of bfs?
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;
446 
447  // Now look at additional objective
448  pe = pl.getEntryPtr("pulp_minimize_maxcut");
449  if (pe) {
450  do_maxcut_min = pe->getValue(&do_maxcut_min);
451  // If we're doing the secondary objective,
452  // set the additional constraint as well
453  if (do_maxcut_min) do_edge_bal = true;
454  }
455 
456  pe = pl.getEntryPtr("pulp_do_repart");
457  if (pe) {
458  do_repart = pe->getValue(&do_repart);
459  // Do repartitioning with input parts
460  do_bfs_init = false;
461  do_lp_init = false;
462  // TODO: read in current parts
463  // for (int i = 0; i < num_verts; ++i)
464  // parts[i] = something;
465  }
466 
467  // Now grab vertex and edge imbalances, defaults at 10%
468  double vert_imbalance = 1.1;
469  double edge_imbalance = 1.1;
470 
471  pe = pl.getEntryPtr("pulp_vert_imbalance");
472  if (pe) vert_imbalance = pe->getValue<double>(&vert_imbalance);
473  pe = pl.getEntryPtr("pulp_edge_imbalance");
474  if (pe) {
475  edge_imbalance = pe->getValue<double>(&edge_imbalance);
476  // if manually set edge imbalance, add do_edge_bal flag to true
477  do_edge_bal = 1;
478  }
479 
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.");
484 
485  // verbose output?
486  // TODO: fully implement verbose flag throughout PuLP
487  pe = pl.getEntryPtr("pulp_verbose");
488  if (pe) verbose_output = pe->getValue(&verbose_output);
489 
490  // using pulp seed?
491  int pulp_seed = rand();
492  pe = pl.getEntryPtr("pulp_seed");
493  if (pe) pulp_seed = pe->getValue(&pulp_seed);
494 
495  // Create PuLP's partitioning data structure
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};
500 
501 
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);
506  }
507 
508  // Call partitioning; result returned in parts array
509 #ifndef HAVE_ZOLTAN2_MPI
510  ierr = pulp_run(&g, &ppc, parts, num_parts);
511 
512  env->globalInputAssertion(__FILE__, __LINE__, "pulp_run",
513  !ierr, BASIC_ASSERTION, problemComm);
514 #else
515  ierr = xtrapulp_run(&g, &ppc, parts, num_parts);
516  env->globalInputAssertion(__FILE__, __LINE__, "xtrapulp_run",
517  !ierr, BASIC_ASSERTION, problemComm);
518 #endif
519 
520 
521 
522  // Load answer into the solution if necessary
523  if ((sizeof(int) != sizeof(part_t)) || (num_verts == 0)) {
524  for (int i = 0; i < num_verts; i++) partList[i] = parts[i];
525  delete [] parts;
526  }
527 
528  solution->setParts(partList);
529 
530  env->memory("Zoltan2-(Xtra)PuLP: After creating solution");
531 
532  // Clean up copies made due to differing data sizes.
533 #ifndef HAVE_ZOLTAN2_MPI
536 #else
540 #endif
541 
542 
543 //#endif // DO NOT HAVE_MPI
544 }
545 
547 // Scale and round scalar_t weights (typically float or double) to
548 // PuLP int
549 // subject to sum(weights) <= max_wgt_sum.
550 // Scale only if deemed necessary.
551 //
552 // Note that we use ceil() instead of round() to avoid
553 // rounding to zero weights.
554 // Based on Zoltan's scale_round_weights, mode 1
555 template <typename Adapter>
556 void AlgPuLP<Adapter>::scale_weights(
557  size_t n,
558  StridedData<typename Adapter::lno_t, typename Adapter::scalar_t> &fwgts,
559  int *iwgts
560 )
561 {
562  const double INT_EPSILON = 1e-5;
563  const double MAX_NUM = 1e9;
564 
565  int nonint = 0;
566  double sum_wgt = 0.0;
567  double max_wgt = 0.0;
568 
569  // Compute local sums of the weights
570  // Check whether all weights are integers
571  for (size_t i = 0; i < n; i++) {
572  double fw = double(fwgts[i]);
573  if (!nonint){
574  int tmp = (int) floor(fw + .5); /* Nearest int */
575  if (fabs((double)tmp-fw) > INT_EPSILON) {
576  nonint = 1;
577  }
578  }
579  sum_wgt += fw;
580  if (fw > max_wgt) max_wgt = fw;
581  }
582 
583  // Get agreement across processors
584  double gmax_wgt;
585  double ltmp[2], gtmp[2];
586  ltmp[0] = nonint;
587  ltmp[1] = sum_wgt;
588  Teuchos::reduceAll<int,double>(*problemComm, Teuchos::REDUCE_SUM, 2,
589  ltmp, gtmp);
590  Teuchos::reduceAll<int,double>(*problemComm, Teuchos::REDUCE_MAX, 1,
591  &max_wgt, &gmax_wgt);
592  nonint = gtmp[0];
593  sum_wgt = gtmp[1];
594  max_wgt = gmax_wgt;
595 
596  // Scaling needed if weights are not integers or weights'
597  // range is not sufficient
598  double scale = 1.0;
599  if (nonint || (max_wgt <= INT_EPSILON) || (sum_wgt > MAX_NUM)) {
600  /* Calculate scale factor */
601  if (sum_wgt != 0.0) scale = MAX_NUM/sum_wgt;
602  }
603 
604  /* Convert weights to positive integers using the computed scale factor */
605  for (size_t i = 0; i < n; i++)
606  iwgts[i] = (int) ceil(double(fwgts[i])*scale);
607 
608 }
609 
610 
611 } // namespace Zoltan2
612 
613 #endif // HAVE_ZOLTAN2_PULP
614 
616 
617 
618 #endif
619 
620 
621 
622 
623 
624 
use columns as graph vertices
#define HELLO
Zoltan2::BaseAdapter< userTypes_t > base_adapter_t
ignore invalid neighbors
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&#39;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
Adapter::part_t part_t
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&#39;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
Definition: Metric.cpp:74