Zoltan2
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
Zoltan2_AlgND.hpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // Zoltan2: A package of combinatorial algorithms for scientific computing
4 //
5 // Copyright 2012 NTESS and the Zoltan2 contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 //MMW need to specify that this requires Zoltan
11 
12 #ifndef _ZOLTAN2_ALGND_HPP_
13 #define _ZOLTAN2_ALGND_HPP_
14 
17 #include <Zoltan2_Algorithm.hpp>
18 #include <Zoltan2_AlgZoltan.hpp>
19 
21 
22 #include <sstream>
23 #include <string>
24 #include <bitset>
25 
30 namespace Zoltan2
31 {
32 
34 
45  template <typename Adapter>
47  class AlgND : public Algorithm<Adapter>
48  {
49 
50  private:
51  typedef typename Adapter::part_t part_t;
52 
53  typedef typename Adapter::lno_t lno_t;
54  typedef typename Adapter::gno_t gno_t;
55 
56  const RCP<const Environment> mEnv;
57  const RCP<const Comm<int>> mProblemComm;
58 
59  std::string mPartitionMethod;
60 
61  const RCP<const typename Adapter::base_adapter_t> mBaseInputAdapter;
62  modelFlag_t graphFlags;
63 
64  void getBoundLayer(part_t levelIndx, const std::vector<part_t> &partMap,
65  const part_t *parts, const std::set<lno_t> &excVerts,
66  lno_t &bigraphNumS, lno_t &bigraphNumT, lno_t &bigraphNumE,
67  std::vector<lno_t> &bigraphCRSRowPtr, std::vector<lno_t> &bigraphCRSCols,
68  std::vector<lno_t> &bigraphVMapU, std::vector<lno_t> &bigraphVMapV,
69  const RCP<const GraphModel<Adapter>> &graphModel);
70 
71  void buildPartTree(part_t level, std::vector<part_t> &levIndx,
72  part_t startV, const std::vector<part_t> &permPartNums,
73  const std::vector<part_t> &splitRangeBeg,
74  const std::vector<part_t> &splitRangeEnd,
75  const std::vector<part_t> &treeVertParents,
76  std::vector<part_t> &sepLevels, std::vector<std::set<part_t>> &sepParts1,
77  std::vector<std::set<part_t>> &sepParts2, part_t &maxLev,
78  part_t &sepTreeIndx, part_t *sepTreeView,
79  std::vector<std::pair<part_t, part_t>> &treeIndxToSepLev);
80 
81  void fillSolutionIperm(const RCP<const GraphModel<Adapter>> &graphModel,
82  const part_t *parts, const std::set<lno_t> &sepVerts,
83  const std::vector<std::vector<std::set<lno_t>>> &sepVertsByLevel,
84  const std::vector<std::pair<part_t, part_t>> &treeIndxToSepLev,
85  lno_t *ipermView, lno_t *sepRangeView);
86 
87  void getIdsOfPart(const RCP<const GraphModel<Adapter>> &graphModel, const part_t *parts,
88  part_t targetPart, const std::set<lno_t> &idsToExcl, std::set<lno_t> &outIds);
89 
90  public:
91  // Constructor
92  AlgND(const RCP<const Environment> &env_,
93  const RCP<const Comm<int>> &problemComm_,
94  const RCP<const typename Adapter::base_adapter_t> &baseInputAdapter_,
95  const modelFlag_t &graphFlags_)
96  : mEnv(env_), mProblemComm(problemComm_), mPartitionMethod("rcb"),
97  mBaseInputAdapter(baseInputAdapter_), graphFlags(graphFlags_)
98  {
99 #ifndef INCLUDE_ZOLTAN2_EXPERIMENTAL
100  Z2_THROW_EXPERIMENTAL("Zoltan2 AlgND is strictly experimental software ")
101 #endif
102 
103  if (mProblemComm->getSize() != 1)
104  {
105  Z2_THROW_SERIAL("Zoltan2 AlgND is strictly serial!");
106  }
107 
108  const Teuchos::ParameterList &pl = mEnv->getParameters();
109  const Teuchos::ParameterEntry *pe;
110 
111  pe = pl.getEntryPtr("edge_separator_method");
112 
113  if (pe)
114  {
115  mPartitionMethod = pe->getValue<std::string>(&mPartitionMethod);
116  }
117  }
118 
119  // Ordering method
120  int localOrder(const RCP<LocalOrderingSolution<lno_t>> &solution_);
121  int globalOrder(const RCP<GlobalOrderingSolution<gno_t>> &solution_);
122 
125  static void getValidParameters(ParameterList &pl)
126  {
127 
128  RCP<Teuchos::StringValidator> es_method_Validator =
129  Teuchos::rcp(new Teuchos::StringValidator(Teuchos::tuple<std::string>("rcb", "phg")));
130 
131  pl.set("edge_separator_method", "rcb", "ND ordering - Edge separator method", es_method_Validator);
132  }
133  };
135 
138  template <typename Adapter>
140  const RCP<GlobalOrderingSolution<gno_t>> &solution_)
141  {
142  throw std::logic_error("AlgND does not support global ordering.");
143  }
144 
146 
149  template <typename Adapter>
151  {
152  mEnv->debug(DETAILED_STATUS, std::string("Entering AlgND"));
153 
155  // First, let's partition with RCB using Zoltan. Eventually, we will change
156  // to give an option to use PHG
158 
160  // Create parameter list for partitioning environment
162  Teuchos::ParameterList partParams;
163 
164  part_t numParts = mEnv->getParameters().template get<part_t>("num_global_parts");
165 
166  partParams.set("num_global_parts", numParts);
167 
168  // Keeping partitioning tree
169  partParams.set("keep_partition_tree", true);
170 
171  // Set Zoltan parameter lists
172  Teuchos::ParameterList &zparams = partParams.sublist("zoltan_parameters", false);
173  zparams.set("LB_METHOD", mPartitionMethod);
175 
177  //Create new environment with parameters for partitioning
179  const RCP<const Environment> partEnv = rcp(new Zoltan2::Environment(partParams, this->mEnv->comm_));
181 
182  int nUserWts = 0;
183 
184  RCP<AlgZoltan<Adapter>> algZoltan = rcp(new AlgZoltan<Adapter>(partEnv, mProblemComm, this->mBaseInputAdapter));
185 
186  RCP<PartitioningSolution<Adapter>> partSoln;
187  partSoln =
188  RCP<PartitioningSolution<Adapter>>(new PartitioningSolution<Adapter>(partEnv, mProblemComm, nUserWts, algZoltan));
189 
190  algZoltan->partition(partSoln);
191 
192  size_t numGlobalParts = partSoln->getTargetGlobalNumberOfParts();
193 
194  const part_t *parts = partSoln->getPartListView();
195 
196  // size_t numVerts = mGraphModel->getLocalNumVertices();
197  // for(size_t i=0; i< numVerts; i++)
198  // {
199  // std::cout << "part[" << i << "] = " << parts[i] <<std::endl;
200  // }
202 
204  // Obtain partitioning tree info from solution
206 
207  // Need to guarantee partitioning tree is binary
208  assert(partSoln->isPartitioningTreeBinary() == true);
209 
211  // Get partitioning tree from solution
213  part_t numTreeVerts = 0;
214  std::vector<part_t> permPartNums; // peritab in Scotch
215 
216  std::vector<part_t> splitRangeBeg;
217  std::vector<part_t> splitRangeEnd;
218  std::vector<part_t> treeVertParents;
219 
220  partSoln->getPartitionTree(numTreeVerts, permPartNums, splitRangeBeg,
221  splitRangeEnd, treeVertParents);
223 
225  // Grab part numbers that are to be split by the separators
226  //
227  // Each separator i is represented by 1 integer and two sets of part_t's in the
228  // the following 3 structure:
229  //
230  // sepLevels[i] - level of separator
231  // sepParts1[i] - 1st set of parts on one side of separator
232  // sepParts2[i] - 2nd set of parts on other side of separator
233  //
235  std::vector<part_t> levInds;
236 
237  std::vector<part_t> sepLevels;
238  std::vector<std::set<part_t>> sepParts1;
239  std::vector<std::set<part_t>> sepParts2;
240 
241  std::vector<std::pair<part_t, part_t>> treeIndxToSepLev(treeVertParents.size());
242 
243  part_t maxLevel = 0;
244 
245  //View of separator tree structure of solution
246  part_t *sepTreeView = solution_->getSeparatorTreeView();
247 
248  part_t sepTreeIndx = treeVertParents.size() - 1;
249 
250  sepTreeView[sepTreeIndx] = -1;
251 
252  buildPartTree(0, levInds, numTreeVerts, permPartNums, splitRangeBeg, splitRangeEnd, treeVertParents,
253  sepLevels, sepParts1, sepParts2, maxLevel, sepTreeIndx, sepTreeView, treeIndxToSepLev);
254 
255  solution_->setHaveSeparatorTree(true);
256 
257  // std::cout << "sepTreeView: ";
258  // for(part_t i=0; i<treeVertParents.size(); i++)
259  // {
260  // std::cout << sepTreeView[i] << " ";
261  // }
262  // std::cout << std::endl;
263 
264  // std::cout << "treeIndxToSepLev:" << std::endl;
265  // for(part_t i=0; i<treeVertParents.size(); i++)
266  // {
267  // std::cout << treeIndxToSepLev[i].first << " " << treeIndxToSepLev[i].second <<std::endl;
268  // }
269 
270  part_t numSeparators = sepLevels.size();
273 
275  // Create a map that maps each part number to a new number based on
276  // the level of the hiearchy of the separator tree. This allows us
277  // to easily identify the boundary value vertices
279  part_t numLevels = maxLevel + 1;
280 
281  std::vector<std::vector<part_t>> partLevelMap(numLevels, std::vector<part_t>(numGlobalParts));
282 
283  std::vector<part_t> sepsInLev(numLevels, 0);
284 
285  const auto graphModel = rcp(new GraphModel<Adapter>(mBaseInputAdapter, mEnv, mProblemComm, graphFlags));
286 
287  for (part_t i = 0; i < numSeparators; i++)
288  {
289  part_t level = sepLevels[i];
290 
291  for (typename std::set<part_t>::const_iterator iter = sepParts1[i].begin();
292  iter != sepParts1[i].end(); ++iter)
293  {
294  partLevelMap[level][*iter] = 2 * sepsInLev[level];
295  }
296 
297  for (typename std::set<part_t>::const_iterator iter = sepParts2[i].begin();
298  iter != sepParts2[i].end(); ++iter)
299  {
300  partLevelMap[level][*iter] = 2 * sepsInLev[level] + 1;
301  }
302 
303  sepsInLev[level]++;
304  }
306 
307  // Set of separator vertices. Used to keep track of what vertices are
308  // already in previous calculated separators. These vertices should be
309  // excluded from future separator calculations
310  std::set<lno_t> sepVerts;
311  std::vector<std::vector<std::set<lno_t>>> sepVertsByLevel(numLevels);
312 
314  // Loop over each cut
315  // 1. Build boundary layer between parts
316  // 2. Build vertex separator from boundary layer
318  for (part_t level = 0; level < numLevels; level++)
319  {
320  sepVertsByLevel[level].resize(sepsInLev[level]);
321 
322  for (part_t levIndx = 0; levIndx < sepsInLev[level]; levIndx++)
323  {
324 
326  // Build boundary layer between parts (edge separator)
328  lno_t bigraphNumU = 0, bigraphNumV = 0;
329  lno_t bigraphNumE = 0; // Should probably be size_t, but making lno_t for Matcher
330  std::vector<lno_t> bigraphVMapU;
331  std::vector<lno_t> bigraphVMapV;
332 
333  std::vector<lno_t> bigraphCRSRowPtr;
334  std::vector<lno_t> bigraphCRSCols;
335 
336  getBoundLayer(levIndx, partLevelMap[level], parts, sepVerts,
337  bigraphNumU, bigraphNumV, bigraphNumE,
338  bigraphCRSRowPtr, bigraphCRSCols,
339  bigraphVMapU, bigraphVMapV, graphModel);
340 
341  // std::cout << "Bipartite graph: " << bigraphNumU << " " << bigraphNumV << " "
342  // << bigraphNumE << std::endl;
343 
344  // for (size_t i=0;i<bigraphVMapU.size();i++)
345  // {
346  // std::cout << "boundVertU: " << bigraphVMapU[i] << std::endl;
347  // }
348 
349  // for (size_t i=0;i<bigraphVMapV.size();i++)
350  // {
351  // std::cout << "boundVertV: " << bigraphVMapV[i] << std::endl;
352  // }
353 
354  // for (lno_t rownum=0;rownum<bigraphNumU;rownum++)
355  // {
356 
357  // for (lno_t eIdx=bigraphCRSRowPtr[rownum];eIdx<bigraphCRSRowPtr[rownum+1];eIdx++)
358  // {
359  // std::cout << "bipartite E: " << bigraphVMapU[rownum] << ", " << bigraphVMapV[ bigraphCRSCols[eIdx]]
360  // << " ( " << rownum << "," << bigraphCRSCols[eIdx] << " )" << std::endl;
361  // }
362 
363  // }
365 
367  // Calculate bipartite matching from boundary layer
369  if (bigraphNumU > 0)
370  {
371  assert(bigraphNumV > 0);
372 
373  Matcher<lno_t> bpMatch(bigraphCRSRowPtr.data(), bigraphCRSCols.data(), bigraphNumU, bigraphNumV, bigraphNumE);
374  bpMatch.match();
375 
376  const std::vector<lno_t> &vertUMatches = bpMatch.getVertexUMatches();
377  const std::vector<lno_t> &vertVMatches = bpMatch.getVertexVMatches();
379 
381  // Calculate vertex cover (which is vertex separator) from matching
383  std::vector<lno_t> VC;
384 
385  bpMatch.getVCfromMatching(bigraphCRSRowPtr, bigraphCRSCols, vertUMatches, vertVMatches,
386  bigraphVMapU, bigraphVMapV, VC);
387 
388  for (size_t i = 0; i < VC.size(); i++)
389  {
390  sepVerts.insert(VC[i]);
391 
392  sepVertsByLevel[level][levIndx].insert(VC[i]);
393  // std::cout << "VC: " << VC[i] << std::endl;
394  }
396  }
397  }
398  }
400 
402  // Fill solution structures: invperm and separatorRange
404  bool inverse = true;
405  lno_t *ipermView = solution_->getPermutationView(inverse);
406  lno_t *sepRangeView = solution_->getSeparatorRangeView();
407 
408  fillSolutionIperm(graphModel, parts, sepVerts, sepVertsByLevel, treeIndxToSepLev, ipermView, sepRangeView);
409 
410  solution_->setHaveInverse(true);
411  solution_->setHaveSeparatorRange(true);
413 
415  // Output separators
417  std::cout << "Separators: " << std::endl;
418 
419  part_t nLevels = sepVertsByLevel.size();
420  for (part_t level = 0; level < nLevels; level++)
421  {
422  //sepVertsByLevel[level].resize(sepsInLev[level]);
423  part_t nSepsOnLev = sepVertsByLevel[level].size();
424 
425  for (part_t levIndx = 0; levIndx < nSepsOnLev; levIndx++)
426  {
427  std::cout << " Separator " << level << " " << levIndx << ": ";
428 
429  typename std::set<lno_t>::const_iterator iterS;
430  for (iterS = sepVertsByLevel[level][levIndx].begin(); iterS != sepVertsByLevel[level][levIndx].end(); ++iterS)
431  {
432  std::cout << *iterS << " ";
433  }
434  std::cout << std::endl;
435  }
436  }
438 
439  // std::cout << "iPerm: ";
440  // for(part_t i=0; i<numVerts; i++)
441  // {
442  // std::cout << ipermView[i] << " ";
443  // }
444  // std::cout << std::endl;
445 
446  // std::cout << "sepRange: ";
447  // for(part_t i=0; i<treeVertParents.size()+1; i++)
448  // {
449  // std::cout << sepRangeView[i] << " ";
450  // }
451  // std::cout << std::endl;
452 
454 
456 
457  mEnv->debug(DETAILED_STATUS, std::string("Exiting AlgND"));
458  return 0;
459  }
461 
463  // Create boundary layer of vertices between 2 partitions
464  //
465  // Could improve the efficiency here by first creating a boundary layer graph
466  // between all parts
468  template <typename Adapter>
469  void AlgND<Adapter>::getBoundLayer(part_t levelIndx, const std::vector<part_t> &partMap,
470  const part_t *parts,
471  const std::set<lno_t> &excVerts,
472  lno_t &bigraphNumS, lno_t &bigraphNumT, lno_t &bigraphNumE,
473  std::vector<lno_t> &bigraphCRSRowPtr, std::vector<lno_t> &bigraphCRSCols,
474  std::vector<lno_t> &bigraphVMapS, std::vector<lno_t> &bigraphVMapT,
475  const RCP<const GraphModel<Adapter>> &graphModel)
476  {
477  typedef typename Adapter::offset_t offset_t; // offset_t
479 
480  lno_t numVerts = graphModel->getLocalNumVertices();
481 
482  //Teuchos ArrayView
483  // Original -- ArrayView< const lno_t > eIDs;
484  ArrayView<const gno_t> eIDs;
485  ArrayView<const offset_t> vOffsets;
486  ArrayView<input_t> wgts;
487 
488  // MMW:
489  // For some reason getLocalEdgeList seems to be returning empty eIDs
490  // getEdgeList expects eIDs to be an array of gno_t
491  // I wanted eIDs to be lno_t since this ordering is computed on a single node and
492  // it seems unnecessary to use the potentially larger gno_t.
493  // The problem might be that the partitioning is being calculated on the gno_t.
494  // Perhaps a solution would be set gno_t = lno_t in the partitioning.
495  // For now, I'll leave this since the edgelist is unlikely to be prohibitively big
496 
497  graphModel->getEdgeList(eIDs, vOffsets, wgts);
498 
499  // original
500  // ( (GraphModel<typename Adapter::base_adapter_t>) *mGraphModel).getEdgeList(eIDs, vOffsets, wgts);
501 
502  std::map<lno_t, std::set<lno_t>> bigraphEs;
503  std::set<lno_t> vSetS;
504  std::set<lno_t> vSetT;
505 
506  bigraphNumE = 0;
507 
508  for (lno_t v1 = 0; v1 < numVerts; v1++)
509  {
510 
511  part_t vpart1 = partMap[parts[v1]];
512 
513  bool correctBL = (vpart1 >= 2 * levelIndx && vpart1 < 2 * (levelIndx + 1));
514 
515  // if vertex is not in the correct range of parts, it cannot be a member of
516  // this boundary layer
517  if (!correctBL)
518  {
519  continue;
520  }
521 
522  // Ignore vertices that belong to set of vertices to exclude
523  if (excVerts.find(v1) != excVerts.end())
524  {
525  continue;
526  }
527 
528  //Loop over edges connected to v1
529  //MMW figure out how to get this from Zoltan2
530  for (offset_t j = vOffsets[v1]; j < vOffsets[v1 + 1]; j++)
531  {
532 
533  lno_t v2 = eIDs[j];
534 
535  part_t vpart2 = partMap[parts[v2]];
536 
537  correctBL = (vpart2 >= 2 * levelIndx && vpart2 < 2 * (levelIndx + 1));
538 
539  // if vertex is not in the correct range of parts, it cannot be a member of
540  // this boundary layer
541  if (!correctBL)
542  {
543  continue;
544  }
545 
546  // Ignore vertices that belong to set of vertices to exclude
547  if (excVerts.find(v2) != excVerts.end())
548  {
549  continue;
550  }
551 
552  if (vpart1 != vpart2)
553  {
554  // Vertex added to 1st set of boundary vertices
555  if (vpart1 < vpart2)
556  {
557  vSetS.insert(v1);
558 
559  // v1, v2
560  if (bigraphEs.find(v1) == bigraphEs.end())
561  {
562  bigraphEs[v1] = std::set<lno_t>();
563  }
564  bigraphEs[v1].insert(v2);
565  bigraphNumE++;
566  }
567  // Vertex added to 2nd set of boundary vertices
568  else
569  {
570  vSetT.insert(v1);
571  }
572  }
573  }
574  }
575 
577  // Set size of two vertex sets for bipartite graph
579  bigraphNumS = vSetS.size();
580  bigraphNumT = vSetT.size();
582 
585 
586  bigraphVMapS.resize(bigraphNumS);
587 
588  std::map<lno_t, lno_t> glob2LocTMap;
589 
590  lno_t indx = 0;
591  for (typename std::set<lno_t>::const_iterator iter = vSetS.begin(); iter != vSetS.end(); ++iter)
592  {
593  bigraphVMapS[indx] = *iter;
594  indx++;
595  }
596 
597  bigraphVMapT.resize(bigraphNumT);
598  indx = 0;
599  for (typename std::set<lno_t>::const_iterator iter = vSetT.begin(); iter != vSetT.end(); ++iter)
600  {
601  bigraphVMapT[indx] = *iter;
602  glob2LocTMap[*iter] = indx;
603  indx++;
604  }
606 
608  // Set sizes for bipartite graph data structures
610  bigraphCRSRowPtr.resize(bigraphNumS + 1);
611  bigraphCRSCols.resize(bigraphNumE);
613 
615  // Copy bipartite graph edges into CRS format
617  bigraphCRSRowPtr[0] = 0;
618 
619  lno_t rownum = 0;
620  size_t nzIndx = 0;
621  typename std::map<lno_t, std::set<lno_t>>::const_iterator iterM;
622  for (iterM = bigraphEs.begin(); iterM != bigraphEs.end(); ++iterM)
623  {
624  bigraphCRSRowPtr[rownum + 1] = bigraphCRSRowPtr[rownum] + (*iterM).second.size();
625 
626  for (typename std::set<lno_t>::const_iterator iter = (*iterM).second.begin(); iter != (*iterM).second.end(); ++iter)
627  {
628  bigraphCRSCols[nzIndx] = glob2LocTMap[(*iter)];
629 
630  nzIndx++;
631  }
632 
633  rownum++;
634  }
636  }
638 
641  template <typename Adapter>
642  void AlgND<Adapter>::
643  buildPartTree(part_t level, std::vector<part_t> &levIndx,
644  part_t startV,
645  const std::vector<part_t> &permPartNums,
646  const std::vector<part_t> &splitRangeBeg,
647  const std::vector<part_t> &splitRangeEnd,
648  const std::vector<part_t> &treeVertParents,
649  std::vector<part_t> &sepLevels,
650  std::vector<std::set<part_t>> &sepParts1, std::vector<std::set<part_t>> &sepParts2,
651  part_t &maxLev, part_t &gIndx,
652  part_t *sepTreeView, std::vector<std::pair<part_t, part_t>> &treeIndxToSepLev)
653  {
654  // Insert information for this separator
655  maxLev = level;
656  part_t tmpMaxLev = maxLev;
657 
659  // Search for indices that have parent startV
661  typename std::vector<part_t>::const_iterator iter;
662  std::vector<part_t> inds;
663  part_t ind = 0;
664  for (iter = treeVertParents.begin(); iter != treeVertParents.end(); ++iter)
665  {
666  if (*iter == startV)
667  {
668  inds.push_back(ind);
669  }
670  ind++;
671  }
673 
675  // If startV has children, this will correspond to a separator. Construct
676  // appropriate data structure and then recurse
678  assert(inds.size() == 2 || inds.size() == 0);
679 
680  // If startV has children
681  if (inds.size() == 2)
682  {
683 
684  if ((part_t)levIndx.size() < level + 1)
685  {
686  levIndx.push_back(0);
687  }
688  else
689  {
690  levIndx[level]++;
691  }
692 
693  // std::cout << "gIndx " << gIndx << ": separator " << level << " " << levIndx[level] << std::endl;
694 
695  treeIndxToSepLev[gIndx].first = level;
696  treeIndxToSepLev[gIndx].second = levIndx[level];
697 
698  part_t v0 = inds[0];
699  part_t v1 = inds[1];
700 
701  sepLevels.push_back(level);
702 
703  sepParts1.push_back(std::set<part_t>());
704  typename std::vector<std::set<part_t>>::iterator setIter = sepParts1.end();
705  setIter--; // set iterator to point to new set
706 
707  for (part_t k = splitRangeBeg[v0]; k < splitRangeEnd[v0]; k++)
708  {
709  (*setIter).insert(permPartNums[k]);
710  }
711 
712  sepParts2.push_back(std::set<part_t>());
713  setIter = sepParts2.end();
714  setIter--; // set iterator to point to new set
715 
716  for (part_t k = splitRangeBeg[v1]; k < splitRangeEnd[v1]; k++)
717  {
718  (*setIter).insert(permPartNums[k]);
719  }
720 
721  part_t parentNode = gIndx;
722  gIndx--;
723  sepTreeView[gIndx] = parentNode;
724 
725  // Recursively call function on children
726  buildPartTree(level + 1, levIndx, v0,
727  permPartNums, splitRangeBeg, splitRangeEnd, treeVertParents,
728  sepLevels, sepParts1, sepParts2,
729  tmpMaxLev,
730  gIndx, sepTreeView, treeIndxToSepLev);
731  if (tmpMaxLev > maxLev)
732  {
733  maxLev = tmpMaxLev;
734  }
735 
736  gIndx--;
737  sepTreeView[gIndx] = parentNode;
738 
739  buildPartTree(level + 1, levIndx, v1,
740  permPartNums, splitRangeBeg, splitRangeEnd, treeVertParents,
741  sepLevels, sepParts1, sepParts2,
742  tmpMaxLev,
743  gIndx, sepTreeView, treeIndxToSepLev);
744  if (tmpMaxLev > maxLev)
745  {
746  maxLev = tmpMaxLev;
747  }
748  }
749  else // no children, so this is not a separator
750  {
751  // std::cout << "gIndx " << gIndx << " leaf: " << permPartNums[splitRangeBeg[startV]] << std::endl;
752  treeIndxToSepLev[gIndx].first = -1;
753  treeIndxToSepLev[gIndx].second = permPartNums[splitRangeBeg[startV]];
754 
755  maxLev--;
756  }
758  }
759 
761 
764  template <typename Adapter>
765  void AlgND<Adapter>::
766  fillSolutionIperm(const RCP<const GraphModel<Adapter>> &graphModel,
767  const part_t *parts, const std::set<lno_t> &sepVerts,
768  const std::vector<std::vector<std::set<lno_t>>> &sepVertsByLevel,
769  const std::vector<std::pair<part_t, part_t>> &treeIndxToSepLev,
770  lno_t *ipermView, lno_t *sepRangeView)
771  {
772  lno_t permIndx = 0;
773  lno_t sepRangeIndx = 0;
774  sepRangeView[sepRangeIndx] = 0;
775 
776  for (size_t i = 0; i < treeIndxToSepLev.size(); i++)
777  {
778  part_t lev = treeIndxToSepLev[i].first;
780  // Leaf node of separator tree
782  if (lev == -1)
783  {
784  std::set<lno_t> idSet;
785  getIdsOfPart(graphModel, parts, treeIndxToSepLev[i].second, sepVerts, idSet);
786 
787  for (typename std::set<lno_t>::const_iterator setIter = idSet.begin(); setIter != idSet.end();
788  ++setIter)
789  {
790  ipermView[permIndx] = *setIter;
791  permIndx++;
792  }
793  sepRangeView[sepRangeIndx + 1] = sepRangeView[sepRangeIndx] + idSet.size();
794  sepRangeIndx++;
795  }
798  // Internal "separator node" of separator tree
800  else
801  {
802  const std::set<lno_t> &idSet = sepVertsByLevel[lev][treeIndxToSepLev[i].second];
803 
804  for (typename std::set<lno_t>::const_iterator setIter = idSet.begin();
805  setIter != idSet.end(); ++setIter)
806  {
807  ipermView[permIndx] = *setIter;
808  permIndx++;
809  }
810  sepRangeView[sepRangeIndx + 1] = sepRangeView[sepRangeIndx] + idSet.size();
811  sepRangeIndx++;
812  }
814  }
815  }
817 
820  template <typename Adapter>
821  void AlgND<Adapter>::
822  getIdsOfPart(const RCP<const GraphModel<Adapter>> &graphModel, const part_t *parts,
823  part_t targetPart, const std::set<lno_t> &idsToExcl, std::set<lno_t> &outIds)
824  {
825  size_t numVerts = graphModel->getLocalNumVertices();
826 
827  for (size_t i = 0; i < numVerts; i++)
828  {
829  if (parts[i] == targetPart && idsToExcl.find(i) == idsToExcl.end())
830  {
831  outIds.insert(i);
832  }
833  }
834  }
836 
837 } // namespace Zoltan2
838 
839 #endif
#define Z2_THROW_SERIAL(mystr)
Throw an error when code is run on more than one processor.
LO match()
Computes the maximum cardinality matching.
lno_t size() const
Return the length of the strided array.
interface to the Zoltan package
std::bitset< NUM_MODEL_FLAGS > modelFlag_t
AlgND(const RCP< const Environment > &env_, const RCP< const Comm< int >> &problemComm_, const RCP< const typename Adapter::base_adapter_t > &baseInputAdapter_, const modelFlag_t &graphFlags_)
map_t::global_ordinal_type gno_t
Definition: mapRemotes.cpp:27
Defines the PartitioningSolution class.
An implementation of the Matcher interface that operates on Epetra matrices and Graphs.
sub-steps, each method&#39;s entry and exit
static void getValidParameters(ParameterList &pl)
Set up validators specific to this algorithm.
SparseMatrixAdapter_t::part_t part_t
Defines the IdentifierModel interface.
A PartitioningSolution is a solution to a partitioning problem.
The StridedData class manages lists of weights or coordinates.
Algorithm defines the base class for all algorithms.
map_t::local_ordinal_type lno_t
Definition: mapRemotes.cpp:26
The user parameters, debug, timing and memory profiling output objects, and error checking methods...
#define Z2_THROW_EXPERIMENTAL(mystr)
Throw an error when experimental code is requested but not compiled.
GraphModel defines the interface required for graph models.
int globalOrder(const RCP< GlobalOrderingSolution< gno_t >> &solution_)
int localOrder(const RCP< LocalOrderingSolution< lno_t >> &solution_)