Zoltan2
Zoltan2_PartitioningProblem.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 
50 #ifndef _ZOLTAN2_PARTITIONINGPROBLEM_HPP_
51 #define _ZOLTAN2_PARTITIONINGPROBLEM_HPP_
52 
53 #include <Zoltan2_Problem.hpp>
57 #include <Zoltan2_GraphModel.hpp>
62 #ifdef ZOLTAN2_TASKMAPPING_MOVE
63 #include <Zoltan2_TaskMapping.hpp>
64 #endif
65 
66 #ifndef _WIN32
67 #include <unistd.h>
68 #else
69 #include <process.h>
70 #define NOMINMAX
71 #include <windows.h>
72 #endif
73 
74 #ifdef HAVE_ZOLTAN2_OVIS
75 #include <ovis.h>
76 #endif
77 
78 namespace Zoltan2{
79 
103 template<typename Adapter>
104 class PartitioningProblem : public Problem<Adapter>
105 {
106 public:
107 
108  typedef typename Adapter::scalar_t scalar_t;
109  typedef typename Adapter::gno_t gno_t;
110  typedef typename Adapter::lno_t lno_t;
111  typedef typename Adapter::part_t part_t;
112  typedef typename Adapter::user_t user_t;
114 
116  PartitioningProblem(Adapter *A, ParameterList *p,
117  const RCP<const Teuchos::Comm<int> > &comm):
118  Problem<Adapter>(A,p,comm),
119  solution_(),
120  inputType_(InvalidAdapterType),
121  graphFlags_(), idFlags_(), coordFlags_(),
122  algName_(), numberOfWeights_(), partIds_(), partSizes_(),
123  numberOfCriteria_(), levelNumberParts_(), hierarchical_(false)
124  {
125  for(int i=0;i<MAX_NUM_MODEL_TYPES;i++) modelAvail_[i]=false;
126  initializeProblem();
127  }
128 
129 #ifdef HAVE_ZOLTAN2_MPI
130 
132  PartitioningProblem(Adapter *A, ParameterList *p, MPI_Comm mpicomm):
133  PartitioningProblem(A, p,
134  rcp<const Comm<int> >(new Teuchos::MpiComm<int>(
135  Teuchos::opaqueWrapper(mpicomm))))
136  {}
137 #endif
138 
140  PartitioningProblem(Adapter *A, ParameterList *p):
141  PartitioningProblem(A, p, Tpetra::getDefaultComm())
142  {}
143 
147 
149  //
150  // \param updateInputData If true this indicates that either
151  // this is the first attempt at solution, or that we
152  // are computing a new solution and the input data has
153  // changed since the previous solution was computed.
154  // By input data we mean coordinates, topology, or weights.
155  // If false, this indicates that we are computing a
156  // new solution using the same input data was used for
157  // the previous solution, even though the parameters
158  // may have been changed.
159  //
160  // For the sake of performance, we ask the caller to set \c updateInputData
161  // to false if he/she is computing a new solution using the same input data,
162  // but different problem parameters, than that which was used to compute
163  // the most recent solution.
164 
165  void solve(bool updateInputData=true);
166 
168  //
169  // \return a reference to the solution to the most recent solve().
170 
172  return *(solution_.getRawPtr());
173  };
174 
213  void setPartSizes(int len, part_t *partIds, scalar_t *partSizes,
214  bool makeCopy=true)
215  {
216  setPartSizesForCriteria(0, len, partIds, partSizes, makeCopy);
217  }
218 
253  void setPartSizesForCriteria(int criteria, int len, part_t *partIds,
254  scalar_t *partSizes, bool makeCopy=true) ;
255 /*
256  void setMachine(MachineRepresentation<typename Adapter::base_adapter_t::scalar_t> *machine);
257 */
258 
261  static void getValidParameters(ParameterList & pl)
262  {
269 
270  // This set up does not use tuple because we didn't have constructors
271  // that took that many elements - Tuple will need to be modified and I
272  // didn't want to have low level changes with this particular refactor
273  // TO DO: Add more Tuple constructors and then redo this code to be
274  // Teuchos::tuple<std::string> algorithm_names( "rcb", "multijagged" ... );
275  Array<std::string> algorithm_names(19);
276  algorithm_names[0] = "rcb";
277  algorithm_names[1] = "multijagged";
278  algorithm_names[2] = "rib";
279  algorithm_names[3] = "hsfc";
280  algorithm_names[4] = "patoh";
281  algorithm_names[5] = "phg";
282  algorithm_names[6] = "metis";
283  algorithm_names[7] = "parmetis";
284  algorithm_names[8] = "quotient";
285  algorithm_names[9] = "pulp";
286  algorithm_names[10] = "parma";
287  algorithm_names[11] = "scotch";
288  algorithm_names[12] = "ptscotch";
289  algorithm_names[13] = "block";
290  algorithm_names[14] = "cyclic";
291  algorithm_names[15] = "sarma";
292  algorithm_names[16] = "random";
293  algorithm_names[17] = "zoltan";
294  algorithm_names[18] = "forTestingOnly";
295  RCP<Teuchos::StringValidator> algorithm_Validator = Teuchos::rcp(
296  new Teuchos::StringValidator( algorithm_names ));
297  pl.set("algorithm", "random", "partitioning algorithm",
298  algorithm_Validator);
299 
300  // bool parameter
301  pl.set("keep_partition_tree", false, "If true, will keep partition tree",
303 
304  // bool parameter
305  pl.set("rectilinear", false, "If true, then when a cut is made, all of the "
306  "dots located on the cut are moved to the same side of the cut. The "
307  "resulting regions are then rectilinear. The resulting load balance may "
308  "not be as good as when the group of dots is split by the cut. ",
310 
311  RCP<Teuchos::StringValidator> partitioning_objective_Validator =
312  Teuchos::rcp( new Teuchos::StringValidator(
313  Teuchos::tuple<std::string>( "balance_object_count",
314  "balance_object_weight", "multicriteria_minimize_total_weight",
315  "multicriteria_minimize_maximum_weight",
316  "multicriteria_balance_total_maximum", "minimize_cut_edge_count",
317  "minimize_cut_edge_weight", "minimize_neighboring_parts",
318  "minimize_boundary_vertices" )));
319  pl.set("partitioning_objective", "balance_object_weight",
320  "objective of partitioning", partitioning_objective_Validator);
321 
322  pl.set("imbalance_tolerance", 1.1, "imbalance tolerance, ratio of "
323  "maximum load over average load", Environment::getAnyDoubleValidator());
324 
325  // num_global_parts >= 1
326  RCP<Teuchos::EnhancedNumberValidator<int>> num_global_parts_Validator =
327  Teuchos::rcp( new Teuchos::EnhancedNumberValidator<int>(
328  1, Teuchos::EnhancedNumberTraits<int>::max()) ); // no maximum
329  pl.set("num_global_parts", 1, "global number of parts to compute "
330  "(0 means use the number of processes)", num_global_parts_Validator);
331 
332  // num_local_parts >= 0
333  RCP<Teuchos::EnhancedNumberValidator<int>> num_local_parts_Validator =
334  Teuchos::rcp( new Teuchos::EnhancedNumberValidator<int>(
335  0, Teuchos::EnhancedNumberTraits<int>::max()) ); // no maximum
336  pl.set("num_local_parts", 0, "number of parts to compute for this "
337  "process (num_global_parts == sum of all num_local_parts)",
338  num_local_parts_Validator);
339 
340  RCP<Teuchos::StringValidator> partitioning_approach_Validator =
341  Teuchos::rcp( new Teuchos::StringValidator(
342  Teuchos::tuple<std::string>( "partition", "repartition",
343  "maximize_overlap" )));
344  pl.set("partitioning_approach", "partition", "Partition from scratch, "
345  "partition incrementally from current partition, of partition from "
346  "scratch but maximize overlap with the current partition",
347  partitioning_approach_Validator);
348 
349  RCP<Teuchos::StringValidator> objects_to_partition_Validator =
350  Teuchos::rcp( new Teuchos::StringValidator(
351  Teuchos::tuple<std::string>( "matrix_rows", "matrix_columns",
352  "matrix_nonzeros", "mesh_elements", "mesh_nodes", "graph_edges",
353  "graph_vertices", "coordinates", "identifiers" )));
354  pl.set("objects_to_partition", "graph_vertices", "Objects to be partitioned",
355  objects_to_partition_Validator);
356 
357  RCP<Teuchos::StringValidator> model_Validator = Teuchos::rcp(
358  new Teuchos::StringValidator(
359  Teuchos::tuple<std::string>( "hypergraph", "graph",
360  "geometry", "ids" )));
361  pl.set("model", "graph", "This is a low level parameter. Normally the "
362  "library will choose a computational model based on the algorithm or "
363  "objective specified by the user.", model_Validator);
364 
365  // bool parameter
366  pl.set("remap_parts", false, "remap part numbers to minimize migration "
367  "between old and new partitions", Environment::getBoolValidator() );
368 
369  pl.set("mapping_type", -1, "Mapping of solution to the processors. -1 No"
370  " Mapping, 0 coordinate mapping.", Environment::getAnyIntValidator());
371 
372  RCP<Teuchos::EnhancedNumberValidator<int>> ghost_layers_Validator =
373  Teuchos::rcp( new Teuchos::EnhancedNumberValidator<int>(1, 10, 1, 0) );
374  pl.set("ghost_layers", 2, "number of layers for ghosting used in "
375  "hypergraph ghost method", ghost_layers_Validator);
376  }
377 
378 private:
379  void initializeProblem();
380 
381  void createPartitioningProblem(bool newData);
382 
383  RCP<PartitioningSolution<Adapter> > solution_;
384 #ifdef ZOLTAN2_TASKMAPPING_MOVE
385  RCP<MachineRepresentation<scalar_t,part_t> > machine_;
386 #endif
387 
388  BaseAdapterType inputType_;
389 
390  //ModelType modelType_;
391  bool modelAvail_[MAX_NUM_MODEL_TYPES];
392 
393  modelFlag_t graphFlags_;
394  modelFlag_t idFlags_;
395  modelFlag_t coordFlags_;
396  std::string algName_;
397 
398  int numberOfWeights_;
399 
400  // Suppose Array<part_t> partIds = partIds_[w]. If partIds.size() > 0
401  // then the user supplied part sizes for weight index "w", and the sizes
402  // corresponding to the Ids in partIds are partSizes[w].
403  //
404  // If numberOfWeights_ >= 0, then there is an Id and Sizes array for
405  // for each weight. Otherwise the user did not supply object weights,
406  // but they can still specify part sizes.
407  // So numberOfCriteria_ is numberOfWeights_ or one, whichever is greater.
408 
409  ArrayRCP<ArrayRCP<part_t> > partIds_;
410  ArrayRCP<ArrayRCP<scalar_t> > partSizes_;
411  int numberOfCriteria_;
412 
413  // Number of parts to be computed at each level in hierarchical partitioning.
414 
415  ArrayRCP<int> levelNumberParts_;
416  bool hierarchical_;
417 };
419 
420 /*
421 template <typename Adapter>
422 void PartitioningProblem<Adapter>::setMachine(MachineRepresentation<typename Adapter::base_adapter_t::scalar_t> *machine){
423  this->machine_ = RCP<MachineRepresentation<typename Adapter::base_adapter_t::scalar_t> > (machine, false);
424 }
425 */
426 
427 
428 template <typename Adapter>
429  void PartitioningProblem<Adapter>::initializeProblem()
430 {
431  HELLO;
432 
433  this->env_->debug(DETAILED_STATUS, "PartitioningProblem::initializeProblem");
434 
435  if (getenv("DEBUGME")){
436 #ifndef _WIN32
437  std::cout << getpid() << std::endl;
438  sleep(15);
439 #else
440  std::cout << _getpid() << std::endl;
441  Sleep(15000);
442 #endif
443  }
444 
445 #ifdef HAVE_ZOLTAN2_OVIS
446  ovis_enabled(this->comm_->getRank());
447 #endif
448 
449  // Create a copy of the user's communicator.
450 
451 #ifdef ZOLTAN2_TASKMAPPING_MOVE
452  machine_ = RCP<MachineRepresentation<scalar_t,part_t> >(
453  new MachineRepresentation<scalar_t,part_t>(*(this->comm_)));
454 #endif
455 
456  // Number of criteria is number of user supplied weights if non-zero.
457  // Otherwise it is 1 and uniform weight is implied.
458 
459  numberOfWeights_ = this->inputAdapter_->getNumWeightsPerID();
460 
461  numberOfCriteria_ = (numberOfWeights_ > 1) ? numberOfWeights_ : 1;
462 
463  inputType_ = this->inputAdapter_->adapterType();
464 
465  // The Caller can specify part sizes in setPartSizes(). If he/she
466  // does not, the part size arrays are empty.
467 
468  ArrayRCP<part_t> *noIds = new ArrayRCP<part_t> [numberOfCriteria_];
469  ArrayRCP<scalar_t> *noSizes = new ArrayRCP<scalar_t> [numberOfCriteria_];
470 
471  partIds_ = arcp(noIds, 0, numberOfCriteria_, true);
472  partSizes_ = arcp(noSizes, 0, numberOfCriteria_, true);
473 
474  if (this->env_->getDebugLevel() >= DETAILED_STATUS){
475  std::ostringstream msg;
476  msg << this->comm_->getSize() << " procs,"
477  << numberOfWeights_ << " user-defined weights\n";
478  this->env_->debug(DETAILED_STATUS, msg.str());
479  }
480 
481  this->env_->memory("After initializeProblem");
482 }
483 
484 template <typename Adapter>
486  int criteria, int len, part_t *partIds, scalar_t *partSizes, bool makeCopy)
487 {
488  this->env_->localInputAssertion(__FILE__, __LINE__, "invalid length",
489  len>= 0, BASIC_ASSERTION);
490 
491  this->env_->localInputAssertion(__FILE__, __LINE__, "invalid criteria",
492  criteria >= 0 && criteria < numberOfCriteria_, BASIC_ASSERTION);
493 
494  if (len == 0){
495  partIds_[criteria] = ArrayRCP<part_t>();
496  partSizes_[criteria] = ArrayRCP<scalar_t>();
497  return;
498  }
499 
500  this->env_->localInputAssertion(__FILE__, __LINE__, "invalid arrays",
501  partIds && partSizes, BASIC_ASSERTION);
502 
503  // The global validity of the partIds and partSizes arrays is performed
504  // by the PartitioningSolution, which computes global part distribution and
505  // part sizes.
506 
507  part_t *z2_partIds = NULL;
508  scalar_t *z2_partSizes = NULL;
509  bool own_memory = false;
510 
511  if (makeCopy){
512  z2_partIds = new part_t [len];
513  z2_partSizes = new scalar_t [len];
514  this->env_->localMemoryAssertion(__FILE__, __LINE__, len, z2_partSizes);
515  memcpy(z2_partIds, partIds, len * sizeof(part_t));
516  memcpy(z2_partSizes, partSizes, len * sizeof(scalar_t));
517  own_memory=true;
518  }
519  else{
520  z2_partIds = partIds;
521  z2_partSizes = partSizes;
522  }
523 
524  partIds_[criteria] = arcp(z2_partIds, 0, len, own_memory);
525  partSizes_[criteria] = arcp(z2_partSizes, 0, len, own_memory);
526 }
527 
528 template <typename Adapter>
529 void PartitioningProblem<Adapter>::solve(bool updateInputData)
530 {
531  this->env_->debug(DETAILED_STATUS, "Entering solve");
532 
533  // Create the computational model.
534 
535  this->env_->timerStart(MACRO_TIMERS, "create problem");
536 
537  createPartitioningProblem(updateInputData);
538 
539  this->env_->timerStop(MACRO_TIMERS, "create problem");
540 
541  // TODO: If hierarchical_
542 
543  // Create the solution. The algorithm will query the Solution
544  // for part and weight information. The algorithm will
545  // update the solution with part assignments and quality metrics.
546 
547  // Create the algorithm
548  try {
549  if (algName_ == std::string("multijagged")) {
550  this->algorithm_ = rcp(new Zoltan2_AlgMJ<Adapter>(this->envConst_,
551  this->comm_,
552  this->coordinateModel_));
553  }
554  else if (algName_ == std::string("zoltan")) {
555  this->algorithm_ = rcp(new AlgZoltan<Adapter>(this->envConst_,
556  this->comm_,
557  this->baseInputAdapter_));
558  }
559  else if (algName_ == std::string("parma")) {
560  this->algorithm_ = rcp(new AlgParMA<Adapter>(this->envConst_,
561  this->comm_,
562  this->baseInputAdapter_));
563  }
564  else if (algName_ == std::string("scotch")) {
565  this->algorithm_ = rcp(new AlgPTScotch<Adapter>(this->envConst_,
566  this->comm_,
567  this->baseInputAdapter_));
568  }
569  else if (algName_ == std::string("parmetis")) {
570  using model_t = GraphModel<base_adapter_t>;
571  this->algorithm_ = rcp(new AlgParMETIS<Adapter, model_t>(this->envConst_,
572  this->comm_,
573  this->graphModel_));
574  }
575  else if (algName_ == std::string("quotient")) {
576  this->algorithm_ = rcp(new AlgQuotient<Adapter>(this->envConst_,
577  this->comm_,
578  this->baseInputAdapter_));
579  //"parmetis")); // The default alg. to use inside Quotient
580  } // is ParMETIS for now.
581  else if (algName_ == std::string("pulp")) {
582  this->algorithm_ = rcp(new AlgPuLP<Adapter>(this->envConst_,
583  this->comm_,
584  this->baseInputAdapter_));
585  }
586  else if (algName_ == std::string("block")) {
587  this->algorithm_ = rcp(new AlgBlock<Adapter>(this->envConst_,
588  this->comm_, this->identifierModel_));
589  }
590  else if (algName_ == std::string("phg") ||
591  algName_ == std::string("patoh")) {
592  // phg and patoh provided through Zoltan
593  Teuchos::ParameterList &pl = this->env_->getParametersNonConst();
594  Teuchos::ParameterList &zparams = pl.sublist("zoltan_parameters",false);
595  if (numberOfWeights_ > 0) {
596  char strval[20];
597  sprintf(strval, "%d", numberOfWeights_);
598  zparams.set("OBJ_WEIGHT_DIM", strval);
599  }
600  zparams.set("LB_METHOD", algName_.c_str());
601  zparams.set("LB_APPROACH", "PARTITION");
602  algName_ = std::string("zoltan");
603 
604  this->algorithm_ = rcp(new AlgZoltan<Adapter>(this->envConst_,
605  this->comm_,
606  this->baseInputAdapter_));
607  }
608  else if (algName_ == std::string("sarma")) {
609  this->algorithm_ = rcp(new AlgSarma<Adapter>(this->envConst_,
610  this->comm_,
611  this->baseInputAdapter_));
612  }
613  else if (algName_ == std::string("forTestingOnly")) {
614  this->algorithm_ = rcp(new AlgForTestingOnly<Adapter>(this->envConst_,
615  this->comm_,
616  this->baseInputAdapter_));
617  }
618  // else if (algName_ == std::string("rcb")) {
619  // this->algorithm_ = rcp(new AlgRCB<Adapter>(this->envConst_,this->comm_,
620  // this->coordinateModel_));
621  // }
622  else {
623  throw std::logic_error("partitioning algorithm not supported");
624  }
625  }
627 
628  // Create the solution
629  this->env_->timerStart(MACRO_TIMERS, "create solution");
630  PartitioningSolution<Adapter> *soln = NULL;
631 
632  try{
634  this->envConst_, this->comm_, numberOfWeights_,
635  partIds_.view(0, numberOfCriteria_),
636  partSizes_.view(0, numberOfCriteria_), this->algorithm_);
637  }
639 
640  solution_ = rcp(soln);
641 
642  this->env_->timerStop(MACRO_TIMERS, "create solution");
643  this->env_->memory("After creating Solution");
644 
645  // Call the algorithm
646 
647  try {
648  this->algorithm_->partition(solution_);
649  }
651 
652  //if mapping is requested
653  const Teuchos::ParameterEntry *pe = this->envConst_->getParameters().getEntryPtr("mapping_type");
654  int mapping_type = -1;
655  if (pe){
656  mapping_type = pe->getValue(&mapping_type);
657  }
658  //if mapping is 0 -- coordinate mapping
659 
660 #if ZOLTAN2_TASKMAPPING_MOVE
661  if (mapping_type == 0){
662 
663  //part_t *task_communication_xadj = NULL, *task_communication_adj = NULL;
664 
667  this->comm_.getRawPtr(),
668  machine_.getRawPtr(),
669  this->coordinateModel_.getRawPtr(),
670  solution_.getRawPtr(),
671  this->envConst_.getRawPtr()
672  //,task_communication_xadj,
673  //task_communication_adj
674  );
675 
676  // KDD For now, we would need to re-map the part numbers in the solution.
677  // KDD I suspect we'll later need to distinguish between part numbers and
678  // KDD process numbers to provide separation between partitioning and
679  // KDD mapping. For example, does this approach here assume #parts == #procs?
680  // KDD If we map k tasks to p processes with k > p, do we effectively reduce
681  // KDD the number of tasks (parts) in the solution?
682 
683 #ifdef KDD_READY
684  const part_t *oldParts = solution_->getPartListView();
685  size_t nLocal = ia->getNumLocalIds();
686  for (size_t i = 0; i < nLocal; i++) {
687  // kind of cheating since oldParts is a view; probably want an interface in solution
688  // for resetting the PartList rather than hacking in like this.
689  oldParts[i] = ctm->getAssignedProcForTask(oldParts[i]);
690  }
691 #endif
692 
693  //for now just delete the object.
694  delete ctm;
695  }
696 #endif
697 
698  else if (mapping_type == 1){
699  //if mapping is 1 -- graph mapping
700  }
701 
702  this->env_->debug(DETAILED_STATUS, "Exiting solve");
703 }
704 
705 template <typename Adapter>
707 {
708  this->env_->debug(DETAILED_STATUS,
709  "PartitioningProblem::createPartitioningProblem");
710 
711  using Teuchos::ParameterList;
712 
713  // A Problem object may be reused. The input data may have changed and
714  // new parameters or part sizes may have been set.
715  //
716  // Save these values in order to determine if we need to create a new model.
717 
718  //ModelType previousModel = modelType_;
719  bool prevModelAvail[MAX_NUM_MODEL_TYPES];
720  for(int i=0;i<MAX_NUM_MODEL_TYPES;i++)
721  {
722  prevModelAvail[i] = modelAvail_[i];
723  }
724 
725 
726  modelFlag_t previousGraphModelFlags = graphFlags_;
727  modelFlag_t previousIdentifierModelFlags = idFlags_;
728  modelFlag_t previousCoordinateModelFlags = coordFlags_;
729 
730  //modelType_ = InvalidModel;
731  for(int i=0;i<MAX_NUM_MODEL_TYPES;i++)
732  {
733  modelAvail_[i] = false;
734  }
735 
736  graphFlags_.reset();
737  idFlags_.reset();
738  coordFlags_.reset();
739 
741  // It's possible at this point that the Problem may want to
742  // add problem parameters to the parameter list in the Environment.
743  //
744  // Since the parameters in the Environment have already been
745  // validated in its constructor, a new Environment must be created:
747  // Teuchos::RCP<const Teuchos::Comm<int> > oldComm = this->env_->comm_;
748  // const ParameterList &oldParams = this->env_->getUnvalidatedParameters();
749  //
750  // ParameterList newParams = oldParams;
751  // newParams.set("new_parameter", "new_value");
752  //
753  // ParameterList &newPartParams = newParams.sublist("partitioning");
754  // newPartParams.set("new_partitioning_parameter", "its_value");
755  //
756  // this->env_ = rcp(new Environment(newParams, oldComm));
758 
759  this->env_->debug(DETAILED_STATUS, " parameters");
760  Environment &env = *(this->env_);
761  ParameterList &pl = env.getParametersNonConst();
762 
763  std::string defString("default");
764 
765  // Did the user specify a computational model?
766 
767  std::string model(defString);
768  const Teuchos::ParameterEntry *pe = pl.getEntryPtr("model");
769  if (pe)
770  model = pe->getValue<std::string>(&model);
771 
772  // Did the user specify an algorithm?
773 
774  std::string algorithm(defString);
775  pe = pl.getEntryPtr("algorithm");
776  if (pe)
777  algorithm = pe->getValue<std::string>(&algorithm);
778 
779  // Possible algorithm requirements that must be conveyed to the model:
780 
781  bool needConsecutiveGlobalIds = false;
782  bool removeSelfEdges= false;
783 
785  // Determine algorithm, model, and algorithm requirements. This
786  // is a first pass. Feel free to change this and add to it.
787 
788  if (algorithm != defString)
789  {
790 
791  // Figure out the model required by the algorithm
792  if (algorithm == std::string("block") ||
793  algorithm == std::string("random") ||
794  algorithm == std::string("cyclic") ){
795 
796  //modelType_ = IdentifierModelType;
797  modelAvail_[IdentifierModelType] = true;
798 
799  algName_ = algorithm;
800  }
801  else if (algorithm == std::string("zoltan") ||
802  algorithm == std::string("parma") ||
803  algorithm == std::string("forTestingOnly"))
804  {
805  algName_ = algorithm;
806  }
807  else if (algorithm == std::string("rcb") ||
808  algorithm == std::string("rib") ||
809  algorithm == std::string("hsfc"))
810  {
811  // rcb, rib, hsfc provided through Zoltan
812  Teuchos::ParameterList &zparams = pl.sublist("zoltan_parameters",false);
813  zparams.set("LB_METHOD", algorithm);
814  if (numberOfWeights_ > 0) {
815  char strval[20];
816  sprintf(strval, "%d", numberOfWeights_);
817  zparams.set("OBJ_WEIGHT_DIM", strval);
818  }
819  algName_ = std::string("zoltan");
820  }
821  else if (algorithm == std::string("multijagged"))
822  {
823  //modelType_ = CoordinateModelType;
824  modelAvail_[CoordinateModelType]=true;
825 
826  algName_ = algorithm;
827  }
828  else if (algorithm == std::string("metis") ||
829  algorithm == std::string("parmetis"))
830  {
831 
832  //modelType_ = GraphModelType;
833  modelAvail_[GraphModelType]=true;
834  algName_ = algorithm;
835  removeSelfEdges = true;
836  needConsecutiveGlobalIds = true;
837  }
838  else if (algorithm == std::string("quotient"))
839  {
840  algName_ = algorithm;
841  }
842  else if (algorithm == std::string("scotch") ||
843  algorithm == std::string("ptscotch")) // BDD: Don't construct graph for scotch here
844  {
845  algName_ = algorithm;
846  }
847  else if (algorithm == std::string("pulp"))
848  {
849  algName_ = algorithm;
850  }
851  else if (algorithm == std::string("sarma"))
852  {
853  algName_ = algorithm;
854  }
855  else if (algorithm == std::string("patoh") ||
856  algorithm == std::string("phg"))
857  {
858  // if ((modelType_ != GraphModelType) &&
859  // (modelType_ != HypergraphModelType) )
860  if ((modelAvail_[GraphModelType]==false) &&
861  (modelAvail_[HypergraphModelType]==false) )
862  {
863  //modelType_ = HypergraphModelType;
864  modelAvail_[HypergraphModelType]=true;
865  }
866  algName_ = algorithm;
867  }
868  else
869  {
870  // Parameter list should ensure this does not happen.
871  throw std::logic_error("parameter list algorithm is invalid");
872  }
873  }
874  else if (model != defString)
875  {
876  // Figure out the algorithm suggested by the model.
877  if (model == std::string("hypergraph"))
878  {
879  //modelType_ = HypergraphModelType;
880  modelAvail_[HypergraphModelType]=true;
881 
882  algName_ = std::string("phg");
883  }
884  else if (model == std::string("graph"))
885  {
886  //modelType_ = GraphModelType;
887  modelAvail_[GraphModelType]=true;
888 
889 #ifdef HAVE_ZOLTAN2_SCOTCH
890  modelAvail_[GraphModelType]=false; // graph constructed by AlgPTScotch
891  if (this->comm_->getSize() > 1)
892  algName_ = std::string("ptscotch");
893  else
894  algName_ = std::string("scotch");
895 #else
896 #ifdef HAVE_ZOLTAN2_PARMETIS
897  if (this->comm_->getSize() > 1)
898  algName_ = std::string("parmetis");
899  else
900  algName_ = std::string("metis");
901  removeSelfEdges = true;
902  needConsecutiveGlobalIds = true;
903 #else
904 #ifdef HAVE_ZOLTAN2_PULP
905  // TODO: XtraPuLP
906  //if (this->comm_->getSize() > 1)
907  // algName_ = std::string("xtrapulp");
908  //else
909  algName_ = std::string("pulp");
910 #else
911  algName_ = std::string("phg");
912 #endif
913 #endif
914 #endif
915  }
916  else if (model == std::string("geometry"))
917  {
918  //modelType_ = CoordinateModelType;
919  modelAvail_[CoordinateModelType]=true;
920 
921  algName_ = std::string("multijagged");
922  }
923  else if (model == std::string("ids"))
924  {
925  //modelType_ = IdentifierModelType;
926  modelAvail_[IdentifierModelType]=true;
927 
928  algName_ = std::string("block");
929  }
930  else
931  {
932  // Parameter list should ensure this does not happen.
933  env.localBugAssertion(__FILE__, __LINE__,
934  "parameter list model type is invalid", 1, BASIC_ASSERTION);
935  }
936  }
937  else
938  {
939  // Determine an algorithm and model suggested by the input type.
940  // TODO: this is a good time to use the time vs. quality parameter
941  // in choosing an algorithm, and setting some parameters
942 
943  if (inputType_ == MatrixAdapterType)
944  {
945  //modelType_ = HypergraphModelType;
946  modelAvail_[HypergraphModelType]=true;
947 
948  algName_ = std::string("phg");
949  }
950  else if (inputType_ == GraphAdapterType ||
951  inputType_ == MeshAdapterType)
952  {
953  //modelType_ = GraphModelType;
954  modelAvail_[GraphModelType]=true;
955 
956  algName_ = std::string("phg");
957  }
958  else if (inputType_ == VectorAdapterType)
959  {
960  //modelType_ = CoordinateModelType;
961  modelAvail_[CoordinateModelType]=true;
962 
963  algName_ = std::string("multijagged");
964  }
965  else if (inputType_ == IdentifierAdapterType)
966  {
967  //modelType_ = IdentifierModelType;
968  modelAvail_[IdentifierModelType]=true;
969 
970  algName_ = std::string("block");
971  }
972  else{
973  // This should never happen
974  throw std::logic_error("input type is invalid");
975  }
976  }
977 
978  // Hierarchical partitioning?
979 
980  Array<int> valueList;
981  pe = pl.getEntryPtr("topology");
982 
983  if (pe){
984  valueList = pe->getValue<Array<int> >(&valueList);
985 
986  if (!Zoltan2::noValuesAreInRangeList<int>(valueList)){
987  int *n = new int [valueList.size() + 1];
988  levelNumberParts_ = arcp(n, 0, valueList.size() + 1, true);
989  int procsPerNode = 1;
990  for (int i=0; i < valueList.size(); i++){
991  levelNumberParts_[i+1] = valueList[i];
992  procsPerNode *= valueList[i];
993  }
994  // Number of parts in the first level
995  levelNumberParts_[0] = env.numProcs_ / procsPerNode;
996 
997  if (env.numProcs_ % procsPerNode > 0)
998  levelNumberParts_[0]++;
999  }
1000  }
1001  else{
1002  levelNumberParts_.clear();
1003  }
1004 
1005  hierarchical_ = levelNumberParts_.size() > 0;
1006 
1007  // Object to be partitioned? (rows, columns, etc)
1008 
1009  std::string objectOfInterest(defString);
1010  pe = pl.getEntryPtr("objects_to_partition");
1011  if (pe)
1012  objectOfInterest = pe->getValue<std::string>(&objectOfInterest);
1013 
1015  // Set model creation flags, if any.
1016 
1017  this->env_->debug(DETAILED_STATUS, " models");
1018  // if (modelType_ == GraphModelType)
1019  if (modelAvail_[GraphModelType]==true)
1020  {
1021 
1022  // Any parameters in the graph sublist?
1023 
1024  std::string symParameter(defString);
1025  pe = pl.getEntryPtr("symmetrize_graph");
1026  if (pe){
1027  symParameter = pe->getValue<std::string>(&symParameter);
1028  if (symParameter == std::string("transpose"))
1029  graphFlags_.set(SYMMETRIZE_INPUT_TRANSPOSE);
1030  else if (symParameter == std::string("bipartite"))
1031  graphFlags_.set(SYMMETRIZE_INPUT_BIPARTITE);
1032  }
1033 
1034  bool sgParameter = false;
1035  pe = pl.getEntryPtr("subset_graph");
1036  if (pe)
1037  sgParameter = pe->getValue(&sgParameter);
1038 
1039  if (sgParameter == 1)
1040  graphFlags_.set(BUILD_SUBSET_GRAPH);
1041 
1042  // Any special behaviors required by the algorithm?
1043 
1044  if (removeSelfEdges)
1045  graphFlags_.set(REMOVE_SELF_EDGES);
1046 
1047  if (needConsecutiveGlobalIds)
1048  graphFlags_.set(GENERATE_CONSECUTIVE_IDS);
1049 
1050  // How does user input map to vertices and edges?
1051 
1052  if (inputType_ == MatrixAdapterType){
1053  if (objectOfInterest == defString ||
1054  objectOfInterest == std::string("matrix_rows") )
1055  graphFlags_.set(VERTICES_ARE_MATRIX_ROWS);
1056  else if (objectOfInterest == std::string("matrix_columns"))
1057  graphFlags_.set(VERTICES_ARE_MATRIX_COLUMNS);
1058  else if (objectOfInterest == std::string("matrix_nonzeros"))
1059  graphFlags_.set(VERTICES_ARE_MATRIX_NONZEROS);
1060  }
1061 
1062  else if (inputType_ == MeshAdapterType){
1063  if (objectOfInterest == defString ||
1064  objectOfInterest == std::string("mesh_nodes") )
1065  graphFlags_.set(VERTICES_ARE_MESH_NODES);
1066  else if (objectOfInterest == std::string("mesh_elements"))
1067  graphFlags_.set(VERTICES_ARE_MESH_ELEMENTS);
1068  }
1069  }
1070  //MMW is it ok to remove else?
1071  // else if (modelType_ == IdentifierModelType)
1072  if (modelAvail_[IdentifierModelType]==true)
1073  {
1074 
1075  // Any special behaviors required by the algorithm?
1076 
1077  }
1078  // else if (modelType_ == CoordinateModelType)
1079  if (modelAvail_[CoordinateModelType]==true)
1080  {
1081 
1082  // Any special behaviors required by the algorithm?
1083 
1084  }
1085 
1086 
1087  if (newData ||
1088  (modelAvail_[GraphModelType]!=prevModelAvail[GraphModelType]) ||
1089  (modelAvail_[HypergraphModelType]!=prevModelAvail[HypergraphModelType])||
1090  (modelAvail_[CoordinateModelType]!=prevModelAvail[CoordinateModelType])||
1091  (modelAvail_[IdentifierModelType]!=prevModelAvail[IdentifierModelType])||
1092  // (modelType_ != previousModel) ||
1093  (graphFlags_ != previousGraphModelFlags) ||
1094  (coordFlags_ != previousCoordinateModelFlags) ||
1095  (idFlags_ != previousIdentifierModelFlags))
1096  {
1097  // Create the computational model.
1098  // Models are instantiated for base input adapter types (mesh,
1099  // matrix, graph, and so on). We pass a pointer to the input
1100  // adapter, cast as the base input type.
1101 
1102  //KDD Not sure why this shadow declaration is needed
1103  //KDD Comment out for now; revisit later if problems.
1104  //KDD const Teuchos::ParameterList pl = this->envConst_->getParameters();
1105  //bool exceptionThrow = true;
1106 
1107  if(modelAvail_[GraphModelType]==true)
1108  {
1109  this->env_->debug(DETAILED_STATUS, " building graph model");
1110  this->graphModel_ = rcp(new GraphModel<base_adapter_t>(
1111  this->baseInputAdapter_, this->envConst_, this->comm_,
1112  graphFlags_));
1113 
1114  this->baseModel_ = rcp_implicit_cast<const Model<base_adapter_t> >(
1115  this->graphModel_);
1116  }
1117  if(modelAvail_[HypergraphModelType]==true)
1118  {
1119  //KDD USING ZOLTAN FOR HYPERGRAPH FOR NOW
1120  //KDD std::cout << "Hypergraph model not implemented yet..." << std::endl;
1121  }
1122 
1123  if(modelAvail_[CoordinateModelType]==true)
1124  {
1125  this->env_->debug(DETAILED_STATUS, " building coordinate model");
1126  this->coordinateModel_ = rcp(new CoordinateModel<base_adapter_t>(
1127  this->baseInputAdapter_, this->envConst_, this->comm_,
1128  coordFlags_));
1129 
1130  this->baseModel_ = rcp_implicit_cast<const Model<base_adapter_t> >(
1131  this->coordinateModel_);
1132  }
1133 
1134  if(modelAvail_[IdentifierModelType]==true)
1135  {
1136  this->env_->debug(DETAILED_STATUS, " building identifier model");
1137  this->identifierModel_ = rcp(new IdentifierModel<base_adapter_t>(
1138  this->baseInputAdapter_, this->envConst_, this->comm_,
1139  idFlags_));
1140 
1141  this->baseModel_ = rcp_implicit_cast<const Model<base_adapter_t> >(
1142  this->identifierModel_);
1143  }
1144 
1145  this->env_->memory("After creating Model");
1146  this->env_->debug(DETAILED_STATUS, "createPartitioningProblem done");
1147  }
1148 }
1149 
1150 } // namespace Zoltan2
1151 #endif
use columns as graph vertices
Serial greedy first-fit graph coloring (local graph only)
#define HELLO
Zoltan2::BaseAdapter< userTypes_t > base_adapter_t
Created by mbenlioglu on Aug 31, 2020.
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
fast typical checks for valid arguments
#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:18
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.
SparseMatrixAdapter_t::part_t part_t
use matrix rows as graph vertices
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.
BaseAdapterType
An enum to identify general types of adapters.
identifier data, just a list of IDs
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:17
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.
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:74