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>
62#ifdef ZOLTAN2_TASKMAPPING_MOVE
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
78namespace Zoltan2{
79
103template<typename Adapter>
104class PartitioningProblem : public Problem<Adapter>
105{
106public:
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):
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
378private:
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/*
421template <typename Adapter>
422void 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
428template <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
484template <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
528template <typename Adapter>
529void 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");
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
705template <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