Zoltan2
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
Zoltan2_PartitioningProblem.hpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // Zoltan2: A package of combinatorial algorithms for scientific computing
4 //
5 // Copyright 2012 NTESS and the Zoltan2 contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
14 #ifndef _ZOLTAN2_PARTITIONINGPROBLEM_HPP_
15 #define _ZOLTAN2_PARTITIONINGPROBLEM_HPP_
16 
17 #include <Zoltan2_Problem.hpp>
21 #include <Zoltan2_GraphModel.hpp>
26 #ifdef ZOLTAN2_TASKMAPPING_MOVE
27 #include <Zoltan2_TaskMapping.hpp>
28 #endif
29 
30 #ifndef _WIN32
31 #include <unistd.h>
32 #else
33 #include <process.h>
34 #define NOMINMAX
35 #include <windows.h>
36 #endif
37 
38 #ifdef HAVE_ZOLTAN2_OVIS
39 #include <ovis.h>
40 #endif
41 
42 namespace Zoltan2{
43 
67 template<typename Adapter>
68 class PartitioningProblem : public Problem<Adapter>
69 {
70 public:
71 
72  typedef typename Adapter::scalar_t scalar_t;
73  typedef typename Adapter::gno_t gno_t;
74  typedef typename Adapter::lno_t lno_t;
75  typedef typename Adapter::part_t part_t;
76  typedef typename Adapter::user_t user_t;
78 
80  PartitioningProblem(Adapter *A, ParameterList *p,
81  const RCP<const Teuchos::Comm<int> > &comm):
82  Problem<Adapter>(A,p,comm),
83  solution_(),
88  {
90  }
91 
92 #ifdef HAVE_ZOLTAN2_MPI
93 
95  PartitioningProblem(Adapter *A, ParameterList *p, MPI_Comm mpicomm):
97  rcp<const Comm<int> >(new Teuchos::MpiComm<int>(
98  Teuchos::opaqueWrapper(mpicomm))))
99  {}
100 #endif
101 
103  PartitioningProblem(Adapter *A, ParameterList *p):
104  PartitioningProblem(A, p, Tpetra::getDefaultComm())
105  {}
106 
110 
112  //
113  // \param updateInputData If true this indicates that either
114  // this is the first attempt at solution, or that we
115  // are computing a new solution and the input data has
116  // changed since the previous solution was computed.
117  // By input data we mean coordinates, topology, or weights.
118  // If false, this indicates that we are computing a
119  // new solution using the same input data was used for
120  // the previous solution, even though the parameters
121  // may have been changed.
122  //
123  // For the sake of performance, we ask the caller to set \c updateInputData
124  // to false if he/she is computing a new solution using the same input data,
125  // but different problem parameters, than that which was used to compute
126  // the most recent solution.
127 
128  void solve(bool updateInputData=true);
129 
131  //
132  // \return a reference to the solution to the most recent solve().
133 
135  return *(solution_.getRawPtr());
136  };
137 
176  void setPartSizes(int len, part_t *partIds, scalar_t *partSizes,
177  bool makeCopy=true)
178  {
179  setPartSizesForCriteria(0, len, partIds, partSizes, makeCopy);
180  }
181 
216  void setPartSizesForCriteria(int criteria, int len, part_t *partIds,
217  scalar_t *partSizes, bool makeCopy=true) ;
218 /*
219  void setMachine(MachineRepresentation<typename Adapter::base_adapter_t::scalar_t> *machine);
220 */
221 
224  static void getValidParameters(ParameterList & pl)
225  {
227 
229 
234 
235  // This set up does not use tuple because we didn't have constructors
236  // that took that many elements - Tuple will need to be modified and I
237  // didn't want to have low level changes with this particular refactor
238  // TO DO: Add more Tuple constructors and then redo this code to be
239  // Teuchos::tuple<std::string> algorithm_names( "rcb", "multijagged" ... );
240  Array<std::string> algorithm_names(19);
241  algorithm_names[0] = "rcb";
242  algorithm_names[1] = "multijagged";
243  algorithm_names[2] = "rib";
244  algorithm_names[3] = "hsfc";
245  algorithm_names[4] = "patoh";
246  algorithm_names[5] = "phg";
247  algorithm_names[6] = "metis";
248  algorithm_names[7] = "parmetis";
249  algorithm_names[8] = "quotient";
250  algorithm_names[9] = "pulp";
251  algorithm_names[10] = "parma";
252  algorithm_names[11] = "scotch";
253  algorithm_names[12] = "ptscotch";
254  algorithm_names[13] = "block";
255  algorithm_names[14] = "cyclic";
256  algorithm_names[15] = "sarma";
257  algorithm_names[16] = "random";
258  algorithm_names[17] = "zoltan";
259  algorithm_names[18] = "forTestingOnly";
260  RCP<Teuchos::StringValidator> algorithm_Validator = Teuchos::rcp(
261  new Teuchos::StringValidator( algorithm_names ));
262  pl.set("algorithm", "random", "partitioning algorithm",
263  algorithm_Validator);
264 
265  // bool parameter
266  pl.set("keep_partition_tree", false, "If true, will keep partition tree",
268 
269  // bool parameter
270  pl.set("rectilinear", false, "If true, then when a cut is made, all of the "
271  "dots located on the cut are moved to the same side of the cut. The "
272  "resulting regions are then rectilinear. The resulting load balance may "
273  "not be as good as when the group of dots is split by the cut. ",
275 
276  RCP<Teuchos::StringValidator> partitioning_objective_Validator =
277  Teuchos::rcp( new Teuchos::StringValidator(
278  Teuchos::tuple<std::string>( "balance_object_count",
279  "balance_object_weight", "multicriteria_minimize_total_weight",
280  "multicriteria_minimize_maximum_weight",
281  "multicriteria_balance_total_maximum", "minimize_cut_edge_count",
282  "minimize_cut_edge_weight", "minimize_neighboring_parts",
283  "minimize_boundary_vertices" )));
284  pl.set("partitioning_objective", "balance_object_weight",
285  "objective of partitioning", partitioning_objective_Validator);
286 
287  pl.set("imbalance_tolerance", 1.1, "imbalance tolerance, ratio of "
288  "maximum load over average load", Environment::getAnyDoubleValidator());
289 
290  // num_global_parts >= 1
291  RCP<Teuchos::EnhancedNumberValidator<int>> num_global_parts_Validator =
292  Teuchos::rcp( new Teuchos::EnhancedNumberValidator<int>(
293  1, Teuchos::EnhancedNumberTraits<int>::max()) ); // no maximum
294  pl.set("num_global_parts", 1, "global number of parts to compute "
295  "(0 means use the number of processes)", num_global_parts_Validator);
296 
297  // num_local_parts >= 0
298  RCP<Teuchos::EnhancedNumberValidator<int>> num_local_parts_Validator =
299  Teuchos::rcp( new Teuchos::EnhancedNumberValidator<int>(
300  0, Teuchos::EnhancedNumberTraits<int>::max()) ); // no maximum
301  pl.set("num_local_parts", 0, "number of parts to compute for this "
302  "process (num_global_parts == sum of all num_local_parts)",
303  num_local_parts_Validator);
304 
305  RCP<Teuchos::StringValidator> partitioning_approach_Validator =
306  Teuchos::rcp( new Teuchos::StringValidator(
307  Teuchos::tuple<std::string>( "partition", "repartition",
308  "maximize_overlap" )));
309  pl.set("partitioning_approach", "partition", "Partition from scratch, "
310  "partition incrementally from current partition, of partition from "
311  "scratch but maximize overlap with the current partition",
312  partitioning_approach_Validator);
313 
314  RCP<Teuchos::StringValidator> objects_to_partition_Validator =
315  Teuchos::rcp( new Teuchos::StringValidator(
316  Teuchos::tuple<std::string>( "matrix_rows", "matrix_columns",
317  "matrix_nonzeros", "mesh_elements", "mesh_nodes", "graph_edges",
318  "graph_vertices", "coordinates", "identifiers" )));
319  pl.set("objects_to_partition", "graph_vertices", "Objects to be partitioned",
320  objects_to_partition_Validator);
321 
322  RCP<Teuchos::StringValidator> model_Validator = Teuchos::rcp(
323  new Teuchos::StringValidator(
324  Teuchos::tuple<std::string>( "hypergraph", "graph",
325  "geometry", "ids" )));
326  pl.set("model", "graph", "This is a low level parameter. Normally the "
327  "library will choose a computational model based on the algorithm or "
328  "objective specified by the user.", model_Validator);
329 
330  // bool parameter
331  pl.set("remap_parts", false, "remap part numbers to minimize migration "
332  "between old and new partitions", Environment::getBoolValidator() );
333 
334  pl.set("mapping_type", -1, "Mapping of solution to the processors. -1 No"
335  " Mapping, 0 coordinate mapping.", Environment::getAnyIntValidator());
336 
337  RCP<Teuchos::EnhancedNumberValidator<int>> ghost_layers_Validator =
338  Teuchos::rcp( new Teuchos::EnhancedNumberValidator<int>(1, 10, 1, 0) );
339  pl.set("ghost_layers", 2, "number of layers for ghosting used in "
340  "hypergraph ghost method", ghost_layers_Validator);
341  }
342 
343 protected:
344  void initializeProblem();
345  virtual void processAlgorithmName(const std::string& algorithm, const std::string& defString, const std::string& model,
346  Environment &env, bool& removeSelfEdges, bool &isGraphType, bool& needConsecutiveGlobalIds);
347 
348  void createPartitioningProblem(bool newData);
349  virtual void createAlgorithm();
350 
351  RCP<PartitioningSolution<Adapter> > solution_;
352 #ifdef ZOLTAN2_TASKMAPPING_MOVE
353  RCP<MachineRepresentation<scalar_t,part_t> > machine_;
354 #endif
355 
357 
361  std::string algName_;
362 
364 
365  // Suppose Array<part_t> partIds = partIds_[w]. If partIds.size() > 0
366  // then the user supplied part sizes for weight index "w", and the sizes
367  // corresponding to the Ids in partIds are partSizes[w].
368  //
369  // If numberOfWeights_ >= 0, then there is an Id and Sizes array for
370  // for each weight. Otherwise the user did not supply object weights,
371  // but they can still specify part sizes.
372  // So numberOfCriteria_ is numberOfWeights_ or one, whichever is greater.
373 
374  ArrayRCP<ArrayRCP<part_t> > partIds_;
375  ArrayRCP<ArrayRCP<scalar_t> > partSizes_;
377 
378  // Number of parts to be computed at each level in hierarchical partitioning.
379 
380  ArrayRCP<int> levelNumberParts_;
382 };
384 
385 /*
386 template <typename Adapter>
387 void PartitioningProblem<Adapter>::setMachine(MachineRepresentation<typename Adapter::base_adapter_t::scalar_t> *machine){
388  this->machine_ = RCP<MachineRepresentation<typename Adapter::base_adapter_t::scalar_t> > (machine, false);
389 }
390 */
391 
392 
393 template <typename Adapter>
395 {
396  HELLO;
397 
398  this->env_->debug(DETAILED_STATUS, "PartitioningProblem::initializeProblem");
399 
400  if (getenv("DEBUGME")){
401 #ifndef _WIN32
402  std::cout << getpid() << std::endl;
403  sleep(15);
404 #else
405  std::cout << _getpid() << std::endl;
406  Sleep(15000);
407 #endif
408  }
409 
410 #ifdef HAVE_ZOLTAN2_OVIS
411  ovis_enabled(this->comm_->getRank());
412 #endif
413 
414  // Create a copy of the user's communicator.
415 
416 #ifdef ZOLTAN2_TASKMAPPING_MOVE
417  machine_ = RCP<MachineRepresentation<scalar_t,part_t> >(
418  new MachineRepresentation<scalar_t,part_t>(*(this->comm_)));
419 #endif
420 
421  // Number of criteria is number of user supplied weights if non-zero.
422  // Otherwise it is 1 and uniform weight is implied.
423 
424  numberOfWeights_ = this->inputAdapter_->getNumWeightsPerID();
425 
426  numberOfCriteria_ = (numberOfWeights_ > 1) ? numberOfWeights_ : 1;
427 
428  inputType_ = this->inputAdapter_->adapterType();
429 
430  // The Caller can specify part sizes in setPartSizes(). If he/she
431  // does not, the part size arrays are empty.
432 
433  ArrayRCP<part_t> *noIds = new ArrayRCP<part_t> [numberOfCriteria_];
434  ArrayRCP<scalar_t> *noSizes = new ArrayRCP<scalar_t> [numberOfCriteria_];
435 
436  partIds_ = arcp(noIds, 0, numberOfCriteria_, true);
437  partSizes_ = arcp(noSizes, 0, numberOfCriteria_, true);
438 
439  if (this->env_->getDebugLevel() >= DETAILED_STATUS){
440  std::ostringstream msg;
441  msg << this->comm_->getSize() << " procs,"
442  << numberOfWeights_ << " user-defined weights\n";
443  this->env_->debug(DETAILED_STATUS, msg.str());
444  }
445 
446  this->env_->memory("After initializeProblem");
447 }
448 
449 template <typename Adapter>
451  int criteria, int len, part_t *partIds, scalar_t *partSizes, bool makeCopy)
452 {
453  this->env_->localInputAssertion(__FILE__, __LINE__, "invalid length",
454  len>= 0, BASIC_ASSERTION);
455 
456  this->env_->localInputAssertion(__FILE__, __LINE__, "invalid criteria",
457  criteria >= 0 && criteria < numberOfCriteria_, BASIC_ASSERTION);
458 
459  if (len == 0){
460  partIds_[criteria] = ArrayRCP<part_t>();
461  partSizes_[criteria] = ArrayRCP<scalar_t>();
462  return;
463  }
464 
465  this->env_->localInputAssertion(__FILE__, __LINE__, "invalid arrays",
466  partIds && partSizes, BASIC_ASSERTION);
467 
468  // The global validity of the partIds and partSizes arrays is performed
469  // by the PartitioningSolution, which computes global part distribution and
470  // part sizes.
471 
472  part_t *z2_partIds = NULL;
473  scalar_t *z2_partSizes = NULL;
474  bool own_memory = false;
475 
476  if (makeCopy){
477  z2_partIds = new part_t [len];
478  z2_partSizes = new scalar_t [len];
479  this->env_->localMemoryAssertion(__FILE__, __LINE__, len, z2_partSizes);
480  memcpy(z2_partIds, partIds, len * sizeof(part_t));
481  memcpy(z2_partSizes, partSizes, len * sizeof(scalar_t));
482  own_memory=true;
483  }
484  else{
485  z2_partIds = partIds;
486  z2_partSizes = partSizes;
487  }
488 
489  partIds_[criteria] = arcp(z2_partIds, 0, len, own_memory);
490  partSizes_[criteria] = arcp(z2_partSizes, 0, len, own_memory);
491 }
492 
493  template <typename Adapter>
495  {
496  // Create the algorithm
497  if (algName_ == std::string("multijagged")) {
498  this->algorithm_ = rcp(new Zoltan2_AlgMJ<Adapter>(this->envConst_,
499  this->comm_,
500  this->baseInputAdapter_));
501  }
502  else if (algName_ == std::string("zoltan")) {
503  this->algorithm_ = rcp(new AlgZoltan<Adapter>(this->envConst_,
504  this->comm_,
505  this->baseInputAdapter_));
506  }
507  else if (algName_ == std::string("parma")) {
508  this->algorithm_ = rcp(new AlgParMA<Adapter>(this->envConst_,
509  this->comm_,
510  this->baseInputAdapter_));
511  }
512  else if (algName_ == std::string("scotch")) {
513  this->algorithm_ = rcp(new AlgPTScotch<Adapter>(this->envConst_,
514  this->comm_,
515  this->baseInputAdapter_));
516  }
517  else if (algName_ == std::string("parmetis")) {
518  using model_t = GraphModel<base_adapter_t>;
519  this->algorithm_ = rcp(new AlgParMETIS<Adapter, model_t>(this->envConst_,
520  this->comm_,
521  this->baseInputAdapter_,
522  this->graphFlags_));
523  }
524  else if (algName_ == std::string("quotient")) {
525  this->algorithm_ = rcp(new AlgQuotient<Adapter>(this->envConst_,
526  this->comm_,
527  this->baseInputAdapter_,
528  this->graphFlags_));
529  //"parmetis")); // The default alg. to use inside Quotient
530  } // is ParMETIS for now.
531  else if (algName_ == std::string("pulp")) {
532  this->algorithm_ = rcp(new AlgPuLP<Adapter>(this->envConst_,
533  this->comm_,
534  this->baseInputAdapter_));
535  }
536  else if (algName_ == std::string("block")) {
537  this->algorithm_ = rcp(new AlgBlock<Adapter>(this->envConst_,
538  this->comm_, this->baseInputAdapter_));
539  }
540  else if (algName_ == std::string("phg") ||
541  algName_ == std::string("patoh")) {
542  // phg and patoh provided through Zoltan
543  Teuchos::ParameterList &pl = this->env_->getParametersNonConst();
544  Teuchos::ParameterList &zparams = pl.sublist("zoltan_parameters",false);
545  if (numberOfWeights_ > 0) {
546  char strval[20];
547  sprintf(strval, "%d", numberOfWeights_);
548  zparams.set("OBJ_WEIGHT_DIM", strval);
549  }
550  zparams.set("LB_METHOD", algName_.c_str());
551  zparams.set("LB_APPROACH", "PARTITION");
552  algName_ = std::string("zoltan");
553 
554  this->algorithm_ = rcp(new AlgZoltan<Adapter>(this->envConst_,
555  this->comm_,
556  this->baseInputAdapter_));
557  }
558  else if (algName_ == std::string("sarma")) {
559  this->algorithm_ = rcp(new AlgSarma<Adapter>(this->envConst_,
560  this->comm_,
561  this->baseInputAdapter_));
562  }
563  else if (algName_ == std::string("forTestingOnly")) {
564  this->algorithm_ = rcp(new AlgForTestingOnly<Adapter>(this->envConst_,
565  this->comm_,
566  this->baseInputAdapter_));
567  }
568  // else if (algName_ == std::string("rcb")) {
569  // this->algorithm_ = rcp(new AlgRCB<Adapter>(this->envConst_,this->comm_,
570  // this->coordinateModel_));
571  // }
572  else {
573  throw std::logic_error("partitioning algorithm not supported");
574  }
575  }
576 
577 template <typename Adapter>
578 void PartitioningProblem<Adapter>::solve(bool updateInputData)
579 {
580  this->env_->debug(DETAILED_STATUS, "Entering solve");
581 
582  // Create the computational model.
583 
584  this->env_->timerStart(MACRO_TIMERS, "create problem");
585 
586  createPartitioningProblem(updateInputData);
587 
588  this->env_->timerStop(MACRO_TIMERS, "create problem");
589 
590  // TODO: If hierarchical_
591 
592  // Create the solution. The algorithm will query the Solution
593  // for part and weight information. The algorithm will
594  // update the solution with part assignments and quality metrics.
595 
596  // Create the algorithm
597  try {
598  this->createAlgorithm();
599  }
601  // Create the solution
602  this->env_->timerStart(MACRO_TIMERS, "create solution");
603  PartitioningSolution<Adapter> *soln = NULL;
604 
605  try{
607  this->envConst_, this->comm_, numberOfWeights_,
608  partIds_.view(0, numberOfCriteria_),
609  partSizes_.view(0, numberOfCriteria_), this->algorithm_);
610  }
612 
613  solution_ = rcp(soln);
614 
615  this->env_->timerStop(MACRO_TIMERS, "create solution");
616  this->env_->memory("After creating Solution");
617 
618  // Call the algorithm
619 
620  try {
621  this->algorithm_->partition(solution_);
622  }
624 
625  //if mapping is requested
626  const Teuchos::ParameterEntry *pe = this->envConst_->getParameters().getEntryPtr("mapping_type");
627  int mapping_type = -1;
628  if (pe){
629  mapping_type = pe->getValue(&mapping_type);
630  }
631  //if mapping is 0 -- coordinate mapping
632 
633 #if ZOLTAN2_TASKMAPPING_MOVE
634  if (mapping_type == 0){
635 
636  //part_t *task_communication_xadj = NULL, *task_communication_adj = NULL;
637 
640  this->comm_.getRawPtr(),
641  machine_.getRawPtr(),
642  this->baseInputAdapter_.getRawPtr(),
643  solution_.getRawPtr(),
644  this->envConst_.getRawPtr()
645  //,task_communication_xadj,
646  //task_communication_adj
647  );
648 
649  // KDD For now, we would need to re-map the part numbers in the solution.
650  // KDD I suspect we'll later need to distinguish between part numbers and
651  // KDD process numbers to provide separation between partitioning and
652  // KDD mapping. For example, does this approach here assume #parts == #procs?
653  // KDD If we map k tasks to p processes with k > p, do we effectively reduce
654  // KDD the number of tasks (parts) in the solution?
655 
656 #ifdef KDD_READY
657  const part_t *oldParts = solution_->getPartListView();
658  size_t nLocal = ia->getNumLocalIds();
659  for (size_t i = 0; i < nLocal; i++) {
660  // kind of cheating since oldParts is a view; probably want an interface in solution
661  // for resetting the PartList rather than hacking in like this.
662  oldParts[i] = ctm->getAssignedProcForTask(oldParts[i]);
663  }
664 #endif
665 
666  //for now just delete the object.
667  delete ctm;
668  }
669 #endif
670 
671  else if (mapping_type == 1){
672  //if mapping is 1 -- graph mapping
673  }
674 
675  this->env_->debug(DETAILED_STATUS, "Exiting solve");
676 }
677 
678 template <typename Adapter>
680  const std::string &algorithm, const std::string &defString,
681  const std::string &model, Environment &env, bool &removeSelfEdges,
682  bool &isGraphType, bool &needConsecutiveGlobalIds) {
683  ParameterList &pl = env.getParametersNonConst();
684 
685  if (algorithm != defString) {
686  if (algorithm == std::string("block") ||
687  algorithm == std::string("random") ||
688  algorithm == std::string("cyclic") ||
689  algorithm == std::string("zoltan") ||
690  algorithm == std::string("parma") ||
691  algorithm == std::string("forTestingOnly") ||
692  algorithm == std::string("quotient") ||
693  algorithm == std::string("scotch") ||
694  algorithm == std::string("ptscotch") ||
695  algorithm == std::string("pulp") || algorithm == std::string("sarma") ||
696  algorithm == std::string("patoh") || algorithm == std::string("phg") ||
697  algorithm == std::string("multijagged")) {
698  algName_ = algorithm;
699  } else if (algorithm == std::string("rcb") ||
700  algorithm == std::string("rib") ||
701  algorithm == std::string("hsfc")) {
702  // rcb, rib, hsfc provided through Zoltan
703  Teuchos::ParameterList &zparams = pl.sublist("zoltan_parameters", false);
704  zparams.set("LB_METHOD", algorithm);
705  if (numberOfWeights_ > 0) {
706  char strval[20];
707  sprintf(strval, "%d", numberOfWeights_);
708  zparams.set("OBJ_WEIGHT_DIM", strval);
709  }
710  algName_ = std::string("zoltan");
711  } else if (algorithm == std::string("metis") ||
712  algorithm == std::string("parmetis")) {
713  algName_ = algorithm;
714  removeSelfEdges = true;
715  needConsecutiveGlobalIds = true;
716  isGraphType = true;
717  } else {
718  // Parameter list should ensure this does not happen.
719  throw std::logic_error("parameter list algorithm is invalid");
720  }
721  } else if (model != defString) {
722  // Figure out the algorithm suggested by the model.
723  if (model == std::string("hypergraph")) {
724  algName_ = std::string("phg");
725  } else if (model == std::string("graph")) {
726 #ifdef HAVE_ZOLTAN2_SCOTCH
727  if (this->comm_->getSize() > 1)
728  algName_ = std::string("ptscotch");
729  else
730  algName_ = std::string("scotch");
731 #else
732 #ifdef HAVE_ZOLTAN2_PARMETIS
733  if (this->comm_->getSize() > 1)
734  algName_ = std::string("parmetis");
735  else
736  algName_ = std::string("metis");
737  removeSelfEdges = true;
738  needConsecutiveGlobalIds = true;
739  isGraphType = true;
740 #else
741 #ifdef HAVE_ZOLTAN2_PULP
742  // TODO: XtraPuLP
743  // if (this->comm_->getSize() > 1)
744  // algName_ = std::string("xtrapulp");
745  // else
746  algName_ = std::string("pulp");
747 #else
748  algName_ = std::string("phg");
749 #endif
750 #endif
751 #endif
752  } else if (model == std::string("geometry")) {
753  algName_ = std::string("multijagged");
754  } else if (model == std::string("ids")) {
755  algName_ = std::string("block");
756  } else {
757  // Parameter list should ensure this does not happen.
758  env.localBugAssertion(__FILE__, __LINE__,
759  "parameter list model type is invalid", 1,
761  }
762  } else {
763  // Determine an algorithm and model suggested by the input type.
764  // TODO: this is a good time to use the time vs. quality parameter
765  // in choosing an algorithm, and setting some parameters
766 
767  if (inputType_ == MatrixAdapterType) {
768  algName_ = std::string("phg");
769  } else if (inputType_ == GraphAdapterType ||
770  inputType_ == MeshAdapterType) {
771  algName_ = std::string("phg");
772  } else if (inputType_ == VectorAdapterType) {
773  algName_ = std::string("multijagged");
774  } else if (inputType_ == IdentifierAdapterType) {
775  algName_ = std::string("block");
776  } else {
777  // This should never happen
778  throw std::logic_error("input type is invalid");
779  }
780  }
781 }
782 
783 template <typename Adapter>
785 {
786  this->env_->debug(DETAILED_STATUS,
787  "PartitioningProblem::createPartitioningProblem");
788 
789  using Teuchos::ParameterList;
790 
791  graphFlags_.reset();
792  idFlags_.reset();
793  coordFlags_.reset();
794 
796  // It's possible at this point that the Problem may want to
797  // add problem parameters to the parameter list in the Environment.
798  //
799  // Since the parameters in the Environment have already been
800  // validated in its constructor, a new Environment must be created:
802  // Teuchos::RCP<const Teuchos::Comm<int> > oldComm = this->env_->comm_;
803  // const ParameterList &oldParams = this->env_->getUnvalidatedParameters();
804  //
805  // ParameterList newParams = oldParams;
806  // newParams.set("new_parameter", "new_value");
807  //
808  // ParameterList &newPartParams = newParams.sublist("partitioning");
809  // newPartParams.set("new_partitioning_parameter", "its_value");
810  //
811  // this->env_ = rcp(new Environment(newParams, oldComm));
813 
814  this->env_->debug(DETAILED_STATUS, " parameters");
815  Environment &env = *(this->env_);
816  ParameterList &pl = env.getParametersNonConst();
817 
818  std::string defString("default");
819 
820  // Did the user specify a computational model?
821 
822  std::string model(defString);
823  const Teuchos::ParameterEntry *pe = pl.getEntryPtr("model");
824  if (pe)
825  model = pe->getValue<std::string>(&model);
826 
827  // Did the user specify an algorithm?
828 
829  std::string algorithm(defString);
830  pe = pl.getEntryPtr("algorithm");
831  if (pe)
832  algorithm = pe->getValue<std::string>(&algorithm);
833 
834  // Possible algorithm requirements that must be conveyed to the model:
835 
836  bool needConsecutiveGlobalIds = false;
837  bool removeSelfEdges= false;
838  bool isGraphModel = false;
839 
841  // Determine algorithm, model, and algorithm requirements. This
842  // is a first pass. Feel free to change this and add to it.
843 
844  this->processAlgorithmName(algorithm, defString, model, env, removeSelfEdges,
845  isGraphModel, needConsecutiveGlobalIds);
846 
847  // Hierarchical partitioning?
848 
849  Array<int> valueList;
850  pe = pl.getEntryPtr("topology");
851 
852  if (pe){
853  valueList = pe->getValue<Array<int> >(&valueList);
854 
855  if (!Zoltan2::noValuesAreInRangeList<int>(valueList)){
856  int *n = new int [valueList.size() + 1];
857  levelNumberParts_ = arcp(n, 0, valueList.size() + 1, true);
858  int procsPerNode = 1;
859  for (int i=0; i < valueList.size(); i++){
860  levelNumberParts_[i+1] = valueList[i];
861  procsPerNode *= valueList[i];
862  }
863  // Number of parts in the first level
864  levelNumberParts_[0] = env.numProcs_ / procsPerNode;
865 
866  if (env.numProcs_ % procsPerNode > 0)
867  levelNumberParts_[0]++;
868  }
869  }
870  else{
871  levelNumberParts_.clear();
872  }
873 
874  hierarchical_ = levelNumberParts_.size() > 0;
875 
876  // Object to be partitioned? (rows, columns, etc)
877 
878  std::string objectOfInterest(defString);
879  pe = pl.getEntryPtr("objects_to_partition");
880  if (pe)
881  objectOfInterest = pe->getValue<std::string>(&objectOfInterest);
882 
884  // Set model creation flags, if any.
885 
886  this->env_->debug(DETAILED_STATUS, " models");
887 
888  if (isGraphModel == true)
889  {
890 
891  // Any parameters in the graph sublist?
892 
893  std::string symParameter(defString);
894  pe = pl.getEntryPtr("symmetrize_graph");
895  if (pe){
896  symParameter = pe->getValue<std::string>(&symParameter);
897  if (symParameter == std::string("transpose"))
898  graphFlags_.set(SYMMETRIZE_INPUT_TRANSPOSE);
899  else if (symParameter == std::string("bipartite"))
900  graphFlags_.set(SYMMETRIZE_INPUT_BIPARTITE);
901  }
902 
903  bool sgParameter = false;
904  pe = pl.getEntryPtr("subset_graph");
905  if (pe)
906  sgParameter = pe->getValue(&sgParameter);
907 
908  if (sgParameter == 1)
909  graphFlags_.set(BUILD_SUBSET_GRAPH);
910 
911  // Any special behaviors required by the algorithm?
912 
913  if (removeSelfEdges)
914  graphFlags_.set(REMOVE_SELF_EDGES);
915 
916  if (needConsecutiveGlobalIds)
917  graphFlags_.set(GENERATE_CONSECUTIVE_IDS);
918 
919  // How does user input map to vertices and edges?
920 
921  if (inputType_ == MatrixAdapterType){
922  if (objectOfInterest == defString ||
923  objectOfInterest == std::string("matrix_rows") )
924  graphFlags_.set(VERTICES_ARE_MATRIX_ROWS);
925  else if (objectOfInterest == std::string("matrix_columns"))
926  graphFlags_.set(VERTICES_ARE_MATRIX_COLUMNS);
927  else if (objectOfInterest == std::string("matrix_nonzeros"))
928  graphFlags_.set(VERTICES_ARE_MATRIX_NONZEROS);
929  }
930 
931  else if (inputType_ == MeshAdapterType){
932  if (objectOfInterest == defString ||
933  objectOfInterest == std::string("mesh_nodes") )
934  graphFlags_.set(VERTICES_ARE_MESH_NODES);
935  else if (objectOfInterest == std::string("mesh_elements"))
936  graphFlags_.set(VERTICES_ARE_MESH_ELEMENTS);
937  }
938  }
939 }
940 
941 } // namespace Zoltan2
942 #endif
use columns as graph vertices
Serial greedy first-fit graph coloring (local graph only)
#define HELLO
Zoltan2::BaseAdapter< userTypes_t > base_adapter_t
Time an algorithm (or other entity) as a whole.
ignore invalid neighbors
void setPartSizes(int len, part_t *partIds, scalar_t *partSizes, bool makeCopy=true)
Set or reset relative sizes for the parts that Zoltan2 will create.
use mesh nodes as vertices
ArrayRCP< ArrayRCP< part_t > > partIds_
fast typical checks for valid arguments
ArrayRCP< ArrayRCP< scalar_t > > partSizes_
#define Z2_FORWARD_EXCEPTIONS
Forward an exception back through call stack.
static void getValidParameters(ParameterList &pl)
Set up validators specific to this algorithm.
static RCP< Teuchos::BoolParameterEntryValidator > getBoolValidator()
Exists to make setting up validators less cluttered.
algorithm requires consecutive ids
std::bitset< NUM_MODEL_FLAGS > modelFlag_t
PartitioningProblem(Adapter *A, ParameterList *p)
Constructor where communicator is the Teuchos default.
model must symmetrize input
map_t::global_ordinal_type gno_t
Definition: mapRemotes.cpp:27
model must symmetrize input
PartitioningProblem(Adapter *A, ParameterList *p, const RCP< const Teuchos::Comm< int > > &comm)
Constructor where Teuchos communicator is specified.
Defines the PartitioningSolution class.
static RCP< Teuchos::AnyNumberParameterEntryValidator > getAnyDoubleValidator()
Exists to make setting up validators less cluttered.
part_t getAssignedProcForTask(part_t taskId)
getAssignedProcForTask function, returns the assigned processor id for the given task ...
sub-steps, each method&#39;s entry and exit
static void getValidParameters(ParameterList &pl)
Set up validators specific to this Problem.
void setPartSizesForCriteria(int criteria, int len, part_t *partIds, scalar_t *partSizes, bool makeCopy=true)
Set or reset the relative sizes (per weight) for the parts that Zoltan2 will create.
int numProcs_
number of processes (relative to comm_)
SparseMatrixAdapter_t::part_t part_t
use matrix rows as graph vertices
Teuchos::ParameterList & getParametersNonConst()
Returns a reference to a non-const copy of the parameters.
algorithm requires no self edges
Defines the IdentifierModel interface.
A PartitioningSolution is a solution to a partitioning problem.
use nonzeros as graph vertices
Defines the EvaluatePartition class.
virtual void processAlgorithmName(const std::string &algorithm, const std::string &defString, const std::string &model, Environment &env, bool &removeSelfEdges, bool &isGraphType, bool &needConsecutiveGlobalIds)
BaseAdapterType
An enum to identify general types of adapters.
identifier data, just a list of IDs
void localBugAssertion(const char *file, int lineNum, const char *msg, bool ok, AssertionLevel level) const
Test for valid library behavior on local process only.
Problem base class from which other classes (PartitioningProblem, ColoringProblem, OrderingProblem, MatchingProblem, etc.) derive.
Defines the Problem base class.
map_t::local_ordinal_type lno_t
Definition: mapRemotes.cpp:26
RCP< PartitioningSolution< Adapter > > solution_
The user parameters, debug, timing and memory profiling output objects, and error checking methods...
static RCP< Teuchos::AnyNumberParameterEntryValidator > getAnyIntValidator()
Exists to make setting up validators less cluttered.
static void getValidParameters(ParameterList &pl)
Set up validators specific to this algorithm.
MachineRepresentation Class Base class for representing machine coordinates, networks, etc.
Define IntegerRangeList validator.
const PartitioningSolution< Adapter > & getSolution()
Get the solution to the problem.
PartitioningProblem sets up partitioning problems for the user.
use mesh elements as vertices
GraphModel defines the interface required for graph models.
Defines the GraphModel interface.
static void getValidParameters(ParameterList &pl)
Set up validators specific to this algorithm.
static void getValidParameters(ParameterList &pl)
Set up validators specific to this algorithm.
static void getValidParameters(ParameterList &)
Set up validators specific to this algorithm.
void solve(bool updateInputData=true)
Direct the problem to create a solution.
Multi Jagged coordinate partitioning algorithm.
static void getValidParameters(ParameterList &pl)
Set up validators specific to this algorithm.
Zoltan2::BasicUserTypes< zscalar_t, zlno_t, zgno_t > user_t
Definition: Metric.cpp:39