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
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
Zoltan2::BasicUserTypes< zscalar_t, zlno_t, zgno_t > user_t
Definition: Metric.cpp:74
Serial greedy first-fit graph coloring (local graph only)
Defines the EvaluatePartition class.
#define Z2_FORWARD_EXCEPTIONS
Forward an exception back through call stack.
Defines the GraphModel interface.
Defines the IdentifierModel interface.
Define IntegerRangeList validator.
Defines the PartitioningSolution class.
Defines the Problem base class.
#define HELLO
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.
static void getValidParameters(ParameterList &pl)
Set up validators specific to this algorithm.
static void getValidParameters(ParameterList &pl)
Set up validators specific to this algorithm.
part_t getAssignedProcForTask(part_t taskId)
getAssignedProcForTask function, returns the assigned processor id for the given task
static RCP< Teuchos::BoolParameterEntryValidator > getBoolValidator()
Exists to make setting up validators less cluttered.
static RCP< Teuchos::AnyNumberParameterEntryValidator > getAnyDoubleValidator()
Exists to make setting up validators less cluttered.
static RCP< Teuchos::AnyNumberParameterEntryValidator > getAnyIntValidator()
Exists to make setting up validators less cluttered.
GraphModel defines the interface required for graph models.
PartitioningProblem sets up partitioning problems for the user.
static void getValidParameters(ParameterList &pl)
Set up validators specific to this Problem.
const PartitioningSolution< Adapter > & getSolution()
Get the solution to the 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.
PartitioningProblem(Adapter *A, ParameterList *p, const RCP< const Teuchos::Comm< int > > &comm)
Constructor where Teuchos communicator is specified.
void solve(bool updateInputData=true)
Direct the problem to create a solution.
PartitioningProblem(Adapter *A, ParameterList *p)
Constructor where communicator is the Teuchos default.
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.
A PartitioningSolution is a solution to a partitioning problem.
Problem base class from which other classes (PartitioningProblem, ColoringProblem,...
Multi Jagged coordinate partitioning algorithm.
static void getValidParameters(ParameterList &pl)
Set up validators specific to this algorithm.
map_t::local_ordinal_type lno_t
Definition: mapRemotes.cpp:17
map_t::global_ordinal_type gno_t
Definition: mapRemotes.cpp:18
Zoltan2::BaseAdapter< userTypes_t > base_adapter_t
Created by mbenlioglu on Aug 31, 2020.
std::bitset< NUM_MODEL_FLAGS > modelFlag_t
@ IdentifierModelType
@ MAX_NUM_MODEL_TYPES
@ HypergraphModelType
@ CoordinateModelType
@ MACRO_TIMERS
Time an algorithm (or other entity) as a whole.
@ DETAILED_STATUS
sub-steps, each method's entry and exit
@ BASIC_ASSERTION
fast typical checks for valid arguments
BaseAdapterType
An enum to identify general types of adapters.
@ VectorAdapterType
vector data
@ InvalidAdapterType
unused value
@ GraphAdapterType
graph data
@ MatrixAdapterType
matrix data
@ MeshAdapterType
mesh data
@ IdentifierAdapterType
identifier data, just a list of IDs
@ VERTICES_ARE_MATRIX_ROWS
use matrix rows as graph vertices
@ VERTICES_ARE_MESH_ELEMENTS
use mesh elements as vertices
@ BUILD_SUBSET_GRAPH
ignore invalid neighbors
@ GENERATE_CONSECUTIVE_IDS
algorithm requires consecutive ids
@ SYMMETRIZE_INPUT_TRANSPOSE
model must symmetrize input
@ SYMMETRIZE_INPUT_BIPARTITE
model must symmetrize input
@ REMOVE_SELF_EDGES
algorithm requires no self edges
@ VERTICES_ARE_MESH_NODES
use mesh nodes as vertices
@ VERTICES_ARE_MATRIX_COLUMNS
use columns as graph vertices
@ VERTICES_ARE_MATRIX_NONZEROS
use nonzeros as graph vertices
SparseMatrixAdapter_t::part_t part_t