Zoltan2
Zoltan2_AlgND.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 
46 //MMW need to specify that this requires Zoltan
47 
48 #ifndef _ZOLTAN2_ALGND_HPP_
49 #define _ZOLTAN2_ALGND_HPP_
50 
53 #include <Zoltan2_Algorithm.hpp>
54 #include <Zoltan2_AlgZoltan.hpp>
55 
57 
58 
59 #include <sstream>
60 #include <string>
61 #include <bitset>
62 
67 namespace Zoltan2
68 {
69 
70 
72 
83 template <typename Adapter>
85 class AlgND : public Algorithm<typename Adapter::base_adapter_t>
86 {
87 
88 private:
89 
90  typedef typename Adapter::part_t part_t;
91 
92  typedef typename Adapter::lno_t lno_t;
93  typedef typename Adapter::gno_t gno_t;
94 
95 
96  const RCP<const Environment> mEnv;
97  const RCP<const Comm<int> > mProblemComm;
98 
99  std::string mPartitionMethod;
100 
101  const RCP<GraphModel<typename Adapter::base_adapter_t> > mGraphModel;
102  const RCP<const typename Adapter::base_adapter_t> mBaseInputAdapter;
103 
104  void getBoundLayer(part_t levelIndx, const std::vector<part_t> &partMap,
105  const part_t * parts,
106  const std::set<lno_t> &excVerts,
107  lno_t &bigraphNumS, lno_t &bigraphNumT, lno_t &bigraphNumE,
108  std::vector<lno_t> &bigraphCRSRowPtr, std::vector<lno_t> &bigraphCRSCols,
109  std::vector<lno_t> &bigraphVMapU, std::vector<lno_t> &bigraphVMapV);
110 
111  void buildPartTree(part_t level, std::vector<part_t> &levIndx,
112  part_t startV,
113  const std::vector<part_t> &permPartNums,
114  const std::vector<part_t> &splitRangeBeg,
115  const std::vector<part_t> &splitRangeEnd,
116  const std::vector<part_t> &treeVertParents,
117  std::vector<part_t> &sepLevels,
118  std::vector<std::set<part_t> > &sepParts1, std::vector<std::set<part_t> > &sepParts2,
119  part_t &maxLev,
120  part_t &sepTreeIndx,
121  part_t *sepTreeView, std::vector<std::pair<part_t,part_t> > &treeIndxToSepLev);
122 
123  void fillSolutionIperm(const part_t *parts, const std::set<lno_t> &sepVerts,
124  const std::vector<std::vector< std::set<lno_t> > > & sepVertsByLevel,
125  const std::vector<std::pair<part_t,part_t> > &treeIndxToSepLev,
126  lno_t * ipermView, lno_t *sepRangeView);
127 
128  void getIdsOfPart(const part_t *parts, part_t targetPart,const std::set<lno_t> &idsToExcl,
129  std::set<lno_t> &outIds);
130 
131 
132 public:
133  // Constructor
134  AlgND(const RCP<const Environment> &env_,
135  const RCP<const Comm<int> > &problemComm_,
138  const RCP<const typename Adapter::base_adapter_t> baseInputAdapter_
139  )
140  :mEnv(env_), mProblemComm(problemComm_), mPartitionMethod("rcb"),
141  mGraphModel(gModel_),
142  mBaseInputAdapter(baseInputAdapter_)
143  {
144 #ifndef INCLUDE_ZOLTAN2_EXPERIMENTAL
145  Z2_THROW_EXPERIMENTAL("Zoltan2 AlgND is strictly experimental software ")
146 #endif
147 
148  if(mProblemComm->getSize()!=1)
149  {
150  Z2_THROW_SERIAL("Zoltan2 AlgND is strictly serial!");
151  }
152 
153 
154  const Teuchos::ParameterList &pl = mEnv->getParameters();
155  const Teuchos::ParameterEntry *pe;
156 
157 
158  pe = pl.getEntryPtr("edge_separator_method");
159 
160  if (pe)
161  {
162  mPartitionMethod = pe->getValue<std::string>(&mPartitionMethod);
163  }
164 
165  }
166 
167  // Ordering method
168  int localOrder(const RCP<LocalOrderingSolution<lno_t> > &solution_);
169  int globalOrder(const RCP<GlobalOrderingSolution<gno_t> > &solution_);
170 
173  static void getValidParameters(ParameterList & pl)
174  {
175 
176  RCP<Teuchos::StringValidator> es_method_Validator =
177  Teuchos::rcp( new Teuchos::StringValidator(Teuchos::tuple<std::string>( "rcb", "phg")));
178 
179  pl.set("edge_separator_method", "rcb", "ND ordering - Edge separator method", es_method_Validator);
180  }
181 
182 };
184 
187 template <typename Adapter>
189  const RCP<GlobalOrderingSolution<gno_t> > &solution_)
190 {
191  throw std::logic_error("AlgND does not support global ordering.");
192 }
193 
195 
196 
199 template <typename Adapter>
201 {
202  mEnv->debug(DETAILED_STATUS, std::string("Entering AlgND"));
203 
205  // First, let's partition with RCB using Zoltan. Eventually, we will change
206  // to give an option to use PHG
208 
210  // Create parameter list for partitioning environment
212  Teuchos::ParameterList partParams;
213 
214  part_t numParts = mEnv->getParameters().template get<part_t>("num_global_parts");
215 
216  partParams.set("num_global_parts", numParts);
217 
218  // Keeping partitioning tree
219  partParams.set("keep_partition_tree", true);
220 
221 
222  // Set Zoltan parameter lists
223  Teuchos::ParameterList &zparams = partParams.sublist("zoltan_parameters",false);
224  zparams.set("LB_METHOD", mPartitionMethod);
226 
228  //Create new environment with parameters for partitioning
230  const RCP<const Environment> partEnv = rcp(new Zoltan2::Environment(partParams,this->mEnv->comm_));
232 
233  int nUserWts=0;
234 
235  RCP<AlgZoltan<Adapter> > algZoltan = rcp(new AlgZoltan<Adapter>(partEnv, mProblemComm, this->mBaseInputAdapter));
236 
237  RCP<PartitioningSolution<Adapter> > partSoln;
238  partSoln =
239  RCP<PartitioningSolution<Adapter> > (new PartitioningSolution<Adapter>(partEnv, mProblemComm, nUserWts,algZoltan));
240 
241 
242  algZoltan->partition(partSoln);
243 
244  size_t numGlobalParts = partSoln->getTargetGlobalNumberOfParts();
245 
246  const part_t *parts = partSoln->getPartListView();
247 
248  // size_t numVerts = mGraphModel->getLocalNumVertices();
249  // for(size_t i=0; i< numVerts; i++)
250  // {
251  // std::cout << "part[" << i << "] = " << parts[i] <<std::endl;
252  // }
254 
256  // Obtain partitioning tree info from solution
258 
259  // Need to guarantee partitioning tree is binary
260  assert(partSoln->isPartitioningTreeBinary()==true);
261 
263  // Get partitioning tree from solution
265  part_t numTreeVerts = 0;
266  std::vector<part_t> permPartNums; // peritab in Scotch
267 
268  std::vector<part_t> splitRangeBeg;
269  std::vector<part_t> splitRangeEnd;
270  std::vector<part_t> treeVertParents;
271 
272  partSoln->getPartitionTree(numTreeVerts,permPartNums,splitRangeBeg,
273  splitRangeEnd,treeVertParents);
275 
277  // Grab part numbers that are to be split by the separators
278  //
279  // Each separator i is represented by 1 integer and two sets of part_t's in the
280  // the following 3 structure:
281  //
282  // sepLevels[i] - level of separator
283  // sepParts1[i] - 1st set of parts on one side of separator
284  // sepParts2[i] - 2nd set of parts on other side of separator
285  //
287  std::vector<part_t> levInds;
288 
289  std::vector<part_t> sepLevels;
290  std::vector<std::set<part_t> > sepParts1;
291  std::vector<std::set<part_t> > sepParts2;
292 
293  std::vector<std::pair<part_t,part_t> > treeIndxToSepLev(treeVertParents.size());
294 
295  part_t maxLevel = 0;
296 
297  //View of separator tree structure of solution
298  part_t *sepTreeView = solution_->getSeparatorTreeView();
299 
300  part_t sepTreeIndx= treeVertParents.size()-1;
301 
302  sepTreeView[sepTreeIndx]=-1;
303 
304  buildPartTree(0, levInds, numTreeVerts, permPartNums, splitRangeBeg, splitRangeEnd, treeVertParents,
305  sepLevels, sepParts1, sepParts2, maxLevel, sepTreeIndx,sepTreeView,treeIndxToSepLev);
306 
307  solution_->setHaveSeparatorTree(true);
308 
309  // std::cout << "sepTreeView: ";
310  // for(part_t i=0; i<treeVertParents.size(); i++)
311  // {
312  // std::cout << sepTreeView[i] << " ";
313  // }
314  // std::cout << std::endl;
315 
316 
317  // std::cout << "treeIndxToSepLev:" << std::endl;
318  // for(part_t i=0; i<treeVertParents.size(); i++)
319  // {
320  // std::cout << treeIndxToSepLev[i].first << " " << treeIndxToSepLev[i].second <<std::endl;
321  // }
322 
323  part_t numSeparators = sepLevels.size();
326 
328  // Create a map that maps each part number to a new number based on
329  // the level of the hiearchy of the separator tree. This allows us
330  // to easily identify the boundary value vertices
332  part_t numLevels = maxLevel+1;
333 
334  std::vector<std::vector<part_t> > partLevelMap(numLevels,std::vector<part_t>(numGlobalParts));
335 
336  std::vector<part_t> sepsInLev(numLevels,0);
337 
338  for(part_t i=0;i<numSeparators;i++)
339  {
340  part_t level = sepLevels[i];
341 
342  for(typename std::set<part_t>::const_iterator iter = sepParts1[i].begin();
343  iter!=sepParts1[i].end();++iter)
344  {
345  partLevelMap[level][*iter] = 2*sepsInLev[level];
346  }
347 
348 
349  for(typename std::set<part_t>::const_iterator iter = sepParts2[i].begin();
350  iter!=sepParts2[i].end();++iter)
351  {
352  partLevelMap[level][*iter] = 2*sepsInLev[level]+1;
353  }
354 
355  sepsInLev[level]++;
356  }
358 
359  // Set of separator vertices. Used to keep track of what vertices are
360  // already in previous calculated separators. These vertices should be
361  // excluded from future separator calculations
362  std::set<lno_t> sepVerts;
363  std::vector<std::vector< std::set<lno_t> > > sepVertsByLevel(numLevels);
364 
366  // Loop over each cut
367  // 1. Build boundary layer between parts
368  // 2. Build vertex separator from boundary layer
370  for(part_t level=0;level<numLevels;level++)
371  {
372  sepVertsByLevel[level].resize(sepsInLev[level]);
373 
374  for(part_t levIndx=0;levIndx<sepsInLev[level];levIndx++)
375  {
376 
378  // Build boundary layer between parts (edge separator)
380  lno_t bigraphNumU=0, bigraphNumV=0;
381  lno_t bigraphNumE=0; // Should probably be size_t, but making lno_t for Matcher
382  std::vector<lno_t> bigraphVMapU;
383  std::vector<lno_t> bigraphVMapV;
384 
385  std::vector<lno_t> bigraphCRSRowPtr;
386  std::vector<lno_t> bigraphCRSCols;
387 
388 
389  getBoundLayer(levIndx, partLevelMap[level], parts, sepVerts,
390  bigraphNumU,bigraphNumV,bigraphNumE,
391  bigraphCRSRowPtr, bigraphCRSCols,
392  bigraphVMapU,bigraphVMapV);
393 
394  // std::cout << "Bipartite graph: " << bigraphNumU << " " << bigraphNumV << " "
395  // << bigraphNumE << std::endl;
396 
397  // for (size_t i=0;i<bigraphVMapU.size();i++)
398  // {
399  // std::cout << "boundVertU: " << bigraphVMapU[i] << std::endl;
400  // }
401 
402  // for (size_t i=0;i<bigraphVMapV.size();i++)
403  // {
404  // std::cout << "boundVertV: " << bigraphVMapV[i] << std::endl;
405  // }
406 
407 
408 
409  // for (lno_t rownum=0;rownum<bigraphNumU;rownum++)
410  // {
411 
412  // for (lno_t eIdx=bigraphCRSRowPtr[rownum];eIdx<bigraphCRSRowPtr[rownum+1];eIdx++)
413  // {
414  // std::cout << "bipartite E: " << bigraphVMapU[rownum] << ", " << bigraphVMapV[ bigraphCRSCols[eIdx]]
415  // << " ( " << rownum << "," << bigraphCRSCols[eIdx] << " )" << std::endl;
416  // }
417 
418  // }
420 
422  // Calculate bipartite matching from boundary layer
424  if (bigraphNumU > 0)
425  {
426  assert(bigraphNumV>0);
427 
428  Matcher<lno_t> bpMatch(bigraphCRSRowPtr.data(), bigraphCRSCols.data(), bigraphNumU, bigraphNumV, bigraphNumE);
429  bpMatch.match();
430 
431  const std::vector<lno_t> &vertUMatches = bpMatch.getVertexUMatches();
432  const std::vector<lno_t> &vertVMatches = bpMatch.getVertexVMatches();
434 
436  // Calculate vertex cover (which is vertex separator) from matching
438  std::vector<lno_t> VC;
439 
440  bpMatch.getVCfromMatching(bigraphCRSRowPtr,bigraphCRSCols,vertUMatches,vertVMatches,
441  bigraphVMapU,bigraphVMapV,VC);
442 
443  for(size_t i=0;i<VC.size();i++)
444  {
445  sepVerts.insert(VC[i]);
446 
447  sepVertsByLevel[level][levIndx].insert(VC[i]);
448  // std::cout << "VC: " << VC[i] << std::endl;
449  }
451  }
452  }
453  }
455 
457  // Fill solution structures: invperm and separatorRange
459  bool inverse=true;
460  lno_t *ipermView = solution_->getPermutationView(inverse);
461  lno_t *sepRangeView = solution_->getSeparatorRangeView();
462 
463  fillSolutionIperm(parts, sepVerts,sepVertsByLevel,treeIndxToSepLev,ipermView, sepRangeView);
464 
465  solution_->setHaveInverse(true);
466  solution_->setHaveSeparatorRange(true);
468 
470  // Output separators
472  std::cout << "Separators: " << std::endl;
473 
474  part_t nLevels = sepVertsByLevel.size();
475  for(part_t level=0;level<nLevels;level++)
476  {
477  //sepVertsByLevel[level].resize(sepsInLev[level]);
478  part_t nSepsOnLev = sepVertsByLevel[level].size();
479 
480  for(part_t levIndx=0;levIndx<nSepsOnLev;levIndx++)
481  {
482  std::cout << " Separator " << level << " " << levIndx << ": ";
483 
484  typename std::set<lno_t>::const_iterator iterS;
485  for (iterS=sepVertsByLevel[level][levIndx].begin();iterS!=sepVertsByLevel[level][levIndx].end();++iterS)
486  {
487  std::cout << *iterS << " ";
488  }
489  std::cout << std::endl;
490  }
491  }
493 
494 
495  // std::cout << "iPerm: ";
496  // for(part_t i=0; i<numVerts; i++)
497  // {
498  // std::cout << ipermView[i] << " ";
499  // }
500  // std::cout << std::endl;
501 
502  // std::cout << "sepRange: ";
503  // for(part_t i=0; i<treeVertParents.size()+1; i++)
504  // {
505  // std::cout << sepRangeView[i] << " ";
506  // }
507  // std::cout << std::endl;
508 
510 
511 
513 
514  mEnv->debug(DETAILED_STATUS, std::string("Exiting AlgND"));
515  return 0;
516 }
518 
520 // Create boundary layer of vertices between 2 partitions
521 //
522 // Could improve the efficiency here by first creating a boundary layer graph
523 // between all parts
525 template <typename Adapter>
526 void AlgND<Adapter>::getBoundLayer(part_t levelIndx, const std::vector<part_t> &partMap,
527  const part_t * parts,
528  const std::set<lno_t> &excVerts,
529  lno_t &bigraphNumS, lno_t &bigraphNumT, lno_t &bigraphNumE,
530  std::vector<lno_t> &bigraphCRSRowPtr, std::vector<lno_t> &bigraphCRSCols,
531  std::vector<lno_t> &bigraphVMapS, std::vector<lno_t> &bigraphVMapT)
532 {
533  typedef typename Adapter::offset_t offset_t; // offset_t
535 
536  lno_t numVerts = mGraphModel->getLocalNumVertices();
537 
538  //Teuchos ArrayView
539  // Original -- ArrayView< const lno_t > eIDs;
540  ArrayView< const gno_t > eIDs;
541  ArrayView< const offset_t > vOffsets;
542  ArrayView< input_t > wgts;
543 
544  // MMW:
545  // For some reason getLocalEdgeList seems to be returning empty eIDs
546  // getEdgeList expects eIDs to be an array of gno_t
547  // I wanted eIDs to be lno_t since this ordering is computed on a single node and
548  // it seems unnecessary to use the potentially larger gno_t.
549  // The problem might be that the partitioning is being calculated on the gno_t.
550  // Perhaps a solution would be set gno_t = lno_t in the partitioning.
551  // For now, I'll leave this since the edgelist is unlikely to be prohibitively big
552 
553 
554  mGraphModel->getEdgeList(eIDs, vOffsets, wgts);
555 
556  // original
557  // ( (GraphModel<typename Adapter::base_adapter_t>) *mGraphModel).getEdgeList(eIDs, vOffsets, wgts);
558 
559 
560  std::map<lno_t,std::set<lno_t> > bigraphEs;
561  std::set<lno_t> vSetS;
562  std::set<lno_t> vSetT;
563 
564  bigraphNumE=0;
565 
566  for(lno_t v1=0;v1<numVerts;v1++)
567  {
568 
569  part_t vpart1 = partMap[parts[v1]];
570 
571  bool correctBL = (vpart1 >= 2*levelIndx && vpart1 < 2*(levelIndx+1) );
572 
573  // if vertex is not in the correct range of parts, it cannot be a member of
574  // this boundary layer
575  if(!correctBL)
576  {
577  continue;
578  }
579 
580  // Ignore vertices that belong to set of vertices to exclude
581  if(excVerts.find(v1)!=excVerts.end())
582  {
583  continue;
584  }
585 
586  //Loop over edges connected to v1
587  //MMW figure out how to get this from Zoltan2
588  for(offset_t j=vOffsets[v1];j<vOffsets[v1+1];j++)
589  {
590 
591  lno_t v2 = eIDs[j];
592 
593  part_t vpart2 = partMap[parts[v2]];
594 
595  correctBL = (vpart2 >= 2*levelIndx && vpart2 < 2*(levelIndx+1) );
596 
597  // if vertex is not in the correct range of parts, it cannot be a member of
598  // this boundary layer
599  if(!correctBL)
600  {
601  continue;
602  }
603 
604  // Ignore vertices that belong to set of vertices to exclude
605  if(excVerts.find(v2)!=excVerts.end())
606  {
607  continue;
608  }
609 
610  if ( vpart1 != vpart2 )
611  {
612  // Vertex added to 1st set of boundary vertices
613  if(vpart1<vpart2)
614  {
615  vSetS.insert(v1);
616 
617  // v1, v2
618  if(bigraphEs.find(v1)==bigraphEs.end())
619  {
620  bigraphEs[v1] = std::set<lno_t>();
621  }
622  bigraphEs[v1].insert(v2);
623  bigraphNumE++;
624 
625  }
626  // Vertex added to 2nd set of boundary vertices
627  else
628  {
629  vSetT.insert(v1);
630  }
631  }
632 
633  }
634  }
635 
637  // Set size of two vertex sets for bipartite graph
639  bigraphNumS = vSetS.size();
640  bigraphNumT = vSetT.size();
642 
645 
646  bigraphVMapS.resize(bigraphNumS);
647 
648  std::map<lno_t,lno_t> glob2LocTMap;
649 
650  lno_t indx=0;
651  for(typename std::set<lno_t>::const_iterator iter=vSetS.begin(); iter!=vSetS.end(); ++iter)
652  {
653  bigraphVMapS[indx] = *iter;
654  indx++;
655  }
656 
657 
658  bigraphVMapT.resize(bigraphNumT);
659  indx=0;
660  for(typename std::set<lno_t>::const_iterator iter=vSetT.begin();iter!=vSetT.end();++iter)
661  {
662  bigraphVMapT[indx] = *iter;
663  glob2LocTMap[*iter]=indx;
664  indx++;
665  }
667 
668 
670  // Set sizes for bipartite graph data structures
672  bigraphCRSRowPtr.resize(bigraphNumS+1);
673  bigraphCRSCols.resize(bigraphNumE);
675 
677  // Copy bipartite graph edges into CRS format
679  bigraphCRSRowPtr[0]=0;
680 
681  lno_t rownum=0;
682  size_t nzIndx=0;
683  typename std::map<lno_t,std::set<lno_t> >::const_iterator iterM;
684  for (iterM=bigraphEs.begin();iterM!=bigraphEs.end();++iterM)
685  {
686  bigraphCRSRowPtr[rownum+1] = bigraphCRSRowPtr[rownum] + (*iterM).second.size();
687 
688  for(typename std::set<lno_t>::const_iterator iter=(*iterM).second.begin(); iter!=(*iterM).second.end(); ++iter)
689  {
690  bigraphCRSCols[nzIndx] = glob2LocTMap[(*iter)];
691 
692  nzIndx++;
693  }
694 
695  rownum++;
696  }
698 
699 }
701 
704 template <typename Adapter>
705 void AlgND<Adapter>::
706 buildPartTree(part_t level, std::vector<part_t> &levIndx,
707  part_t startV,
708  const std::vector<part_t> &permPartNums,
709  const std::vector<part_t> &splitRangeBeg,
710  const std::vector<part_t> &splitRangeEnd,
711  const std::vector<part_t> &treeVertParents,
712  std::vector<part_t> &sepLevels,
713  std::vector<std::set<part_t> > &sepParts1, std::vector<std::set<part_t> > &sepParts2,
714  part_t &maxLev, part_t &gIndx,
715  part_t *sepTreeView,std::vector<std::pair<part_t,part_t> > &treeIndxToSepLev)
716 {
717  // Insert information for this separator
718  maxLev=level;
719  part_t tmpMaxLev=maxLev;
720 
722  // Search for indices that have parent startV
724  typename std::vector<part_t>::const_iterator iter;
725  std::vector<part_t> inds;
726  part_t ind=0;
727  for(iter=treeVertParents.begin(); iter!=treeVertParents.end(); ++iter)
728  {
729  if(*iter == startV)
730  {
731  inds.push_back(ind);
732  }
733  ind++;
734  }
736 
738  // If startV has children, this will correspond to a separator. Construct
739  // appropriate data structure and then recurse
741  assert(inds.size()==2 || inds.size()==0);
742 
743  // If startV has children
744  if(inds.size()==2)
745  {
746 
747 
748  if((part_t)levIndx.size() < level+1)
749  {
750  levIndx.push_back(0);
751  }
752  else
753  {
754  levIndx[level]++;
755  }
756 
757  // std::cout << "gIndx " << gIndx << ": separator " << level << " " << levIndx[level] << std::endl;
758 
759  treeIndxToSepLev[gIndx].first = level;
760  treeIndxToSepLev[gIndx].second = levIndx[level];
761 
762  part_t v0 = inds[0];
763  part_t v1 = inds[1];
764 
765  sepLevels.push_back(level);
766 
767  sepParts1.push_back(std::set<part_t>());
768  typename std::vector<std::set<part_t> >::iterator setIter = sepParts1.end();
769  setIter--; // set iterator to point to new set
770 
771  for(part_t k=splitRangeBeg[v0]; k<splitRangeEnd[v0]; k++)
772  {
773  (*setIter).insert(permPartNums[k]);
774  }
775 
776 
777  sepParts2.push_back(std::set<part_t>());
778  setIter = sepParts2.end();
779  setIter--; // set iterator to point to new set
780 
781  for(part_t k=splitRangeBeg[v1]; k<splitRangeEnd[v1]; k++)
782  {
783  (*setIter).insert(permPartNums[k]);
784  }
785 
786  part_t parentNode = gIndx;
787  gIndx--;
788  sepTreeView[gIndx] = parentNode;
789 
790  // Recursively call function on children
791  buildPartTree(level+1, levIndx,v0,
792  permPartNums, splitRangeBeg, splitRangeEnd, treeVertParents,
793  sepLevels, sepParts1, sepParts2,
794  tmpMaxLev,
795  gIndx,sepTreeView,treeIndxToSepLev);
796  if(tmpMaxLev>maxLev)
797  {
798  maxLev = tmpMaxLev;
799  }
800 
801 
802  gIndx--;
803  sepTreeView[gIndx] = parentNode;
804 
805  buildPartTree(level+1, levIndx, v1,
806  permPartNums, splitRangeBeg, splitRangeEnd, treeVertParents,
807  sepLevels, sepParts1, sepParts2,
808  tmpMaxLev,
809  gIndx, sepTreeView,treeIndxToSepLev);
810  if(tmpMaxLev>maxLev)
811  {
812  maxLev = tmpMaxLev;
813  }
814 
815 
816  }
817  else // no children, so this is not a separator
818  {
819  // std::cout << "gIndx " << gIndx << " leaf: " << permPartNums[splitRangeBeg[startV]] << std::endl;
820  treeIndxToSepLev[gIndx].first = -1;
821  treeIndxToSepLev[gIndx].second = permPartNums[splitRangeBeg[startV]];
822 
823  maxLev--;
824  }
826 
827 
828 }
829 
831 
834 template <typename Adapter>
835 void AlgND<Adapter>::
836 fillSolutionIperm(const part_t *parts, const std::set<lno_t> &sepVerts,
837  const std::vector<std::vector< std::set<lno_t> > > & sepVertsByLevel,
838  const std::vector<std::pair<part_t,part_t> > &treeIndxToSepLev,
839  lno_t * ipermView, lno_t *sepRangeView)
840 {
841  lno_t permIndx=0;
842  lno_t sepRangeIndx=0;
843  sepRangeView[sepRangeIndx] = 0;
844 
845  for(size_t i=0; i<treeIndxToSepLev.size();i++)
846  {
847  part_t lev = treeIndxToSepLev[i].first;
849  // Leaf node of separator tree
851  if(lev==-1)
852  {
853  std::set<lno_t> idSet;
854  getIdsOfPart(parts,treeIndxToSepLev[i].second,sepVerts,idSet);
855 
856  for(typename std::set<lno_t>::const_iterator setIter=idSet.begin(); setIter != idSet.end();
857  ++setIter)
858  {
859  ipermView[permIndx]=*setIter;
860  permIndx++;
861  }
862  sepRangeView[sepRangeIndx+1]=sepRangeView[sepRangeIndx]+idSet.size();
863  sepRangeIndx++;
864 
865  }
868  // Internal "separator node" of separator tree
870  else
871  {
872  const std::set<lno_t> &idSet = sepVertsByLevel[lev][treeIndxToSepLev[i].second];
873 
874  for(typename std::set<lno_t>::const_iterator setIter=idSet.begin();
875  setIter != idSet.end(); ++setIter)
876  {
877  ipermView[permIndx]=*setIter;
878  permIndx++;
879  }
880  sepRangeView[sepRangeIndx+1]=sepRangeView[sepRangeIndx]+idSet.size();
881  sepRangeIndx++;
882 
883  }
885 
886  }
887 }
889 
890 
893 template <typename Adapter>
894 void AlgND<Adapter>::
895 getIdsOfPart(const part_t *parts, part_t targetPart,const std::set<lno_t> &idsToExcl,
896  std::set<lno_t> &outIds)
897 {
898  size_t numVerts = mGraphModel->getLocalNumVertices();
899 
900  for(size_t i=0; i<numVerts; i++)
901  {
902  if(parts[i]==targetPart && idsToExcl.find(i)==idsToExcl.end())
903  {
904  outIds.insert(i);
905  }
906  }
907 
908 }
910 
911 
912 } // namespace Zoltan2
913 
914 
915 
916 
917 
918 #endif
Created by mbenlioglu on Aug 31, 2020.
#define Z2_THROW_SERIAL(mystr)
Throw an error when code is run on more than one processor.
LO match()
Computes the maximum cardinality matching.
interface to the Zoltan package
map_t::global_ordinal_type gno_t
Definition: mapRemotes.cpp:18
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
int globalOrder(const RCP< GlobalOrderingSolution< gno_t > > &solution_)
Ordering method.
SparseMatrixAdapter_t::part_t part_t
This class provides geometric coordinates with optional weights to the Zoltan2 algorithm.
Defines the IdentifierModel interface.
A PartitioningSolution is a solution to a partitioning problem.
The StridedData class manages lists of weights or coordinates.
lno_t size() const
Return the length of the strided array.
Algorithm defines the base class for all algorithms.
map_t::local_ordinal_type lno_t
Definition: mapRemotes.cpp:17
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.
AlgND(const RCP< const Environment > &env_, const RCP< const Comm< int > > &problemComm_, const RCP< GraphModel< typename Adapter::base_adapter_t > > &gModel_, const RCP< CoordinateModel< typename Adapter::base_adapter_t > > &cModel_, const RCP< const typename Adapter::base_adapter_t > baseInputAdapter_)
int localOrder(const RCP< LocalOrderingSolution< lno_t > > &solution_)
Ordering method.