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 
68 //void buildPartTree(int level, int leftPart, int splitPart, int rightPart, std::vector<int> &partTree);
69 
70 
71 namespace Zoltan2
72 {
73 
75 
86 template <typename Adapter>
88 class AlgND : public Algorithm<typename Adapter::base_adapter_t>
89 //class AlgND : public Algorithm<Adapter>
90 {
91 
92 private:
93 
94  typedef typename Adapter::part_t part_t;
95 
96  typedef typename Adapter::lno_t lno_t;
97  typedef typename Adapter::gno_t gno_t;
98 
99 
100  const RCP<const Environment> mEnv;
101  const RCP<const Comm<int> > mProblemComm;
102 
103  // const RCP<const GraphModel<Adapter> > mGraphModel;
104  const RCP<GraphModel<typename Adapter::base_adapter_t> > mGraphModel;
105  // const RCP<const CoordinateModel<Adapter> > mIds;
106  const RCP<CoordinateModel<typename Adapter::base_adapter_t> > mIds;
107 
108  //const RCP<const Adapter> mBaseInputAdapter;
109  //const RCP<const Adapter> mInputAdapter;
110  const RCP<const typename Adapter::base_adapter_t> mBaseInputAdapter;
111 
112  void getBoundLayer(int levelIndx, const std::vector<part_t> &partMap,
113  const part_t * parts,
114  const std::set<int> &excVerts,
115  int &bigraphNumS, int &bigraphNumT, int &bigraphNumE,
116  std::vector<int> &bigraphCRSRowPtr, std::vector<int> &bigraphCRSCols,
117  std::vector<int> &bigraphVMapU, std::vector<int> &bigraphVMapV);
118 
119 void buildPartTree(int level, int leftPart, int splitPart, int rightPart, std::vector<int> &partTree);
120 
121 
122 public:
123  // Constructor
124  AlgND(const RCP<const Environment> &env_,
125  const RCP<const Comm<int> > &problemComm_,
128  const RCP<const typename Adapter::base_adapter_t> baseInputAdapter_
129  )
130  :mEnv(env_), mProblemComm(problemComm_), mGraphModel(gModel_),
131  mIds(cModel_), mBaseInputAdapter(baseInputAdapter_)
132  {
133 #ifndef INCLUDE_ZOLTAN2_EXPERIMENTAL
134  Z2_THROW_EXPERIMENTAL("Zoltan2 AlgND is strictly experimental software ")
135 #endif
136 
137 #ifndef INCLUDE_ZOLTAN2_EXPERIMENTAL_WOLF
138  Z2_THROW_EXPERIMENTAL_WOLF("Zoltan2 algND is strictly experimental software ")
139 #endif
140 
141  if(mProblemComm->getSize()!=1)
142  {
143  Z2_THROW_SERIAL("Zoltan2 AlgND is strictly serial!");
144  }
145 
146  }
147 
148  // Ordering method
149  int localOrder(const RCP<LocalOrderingSolution<lno_t> > &solution_);
150  int globalOrder(const RCP<GlobalOrderingSolution<gno_t> > &solution_);
151 
152 };
154 
157 template <typename Adapter>
159  const RCP<GlobalOrderingSolution<gno_t> > &solution_)
160 {
161  throw std::logic_error("AlgND does not support global ordering.");
162 }
163 
165 
166 
169 template <typename Adapter>
171 {
172  typedef typename Adapter::lno_t lno_t; // local ids
173  // typedef typename Adapter::gno_t gno_t; // global ids
174  // typedef typename Adapter::scalar_t scalar_t; // scalars
175 
176  mEnv->debug(DETAILED_STATUS, std::string("Entering AlgND"));
177 
179  // First, let's partition with RCB using Zoltan. Eventually, we will change this
180  // to use PHG
182 
183  RCP<PartitioningSolution<Adapter> > partSoln;
184  int nUserWts=0;
185 
186  partSoln =
187  RCP<PartitioningSolution<Adapter> > (new PartitioningSolution<Adapter>(this->mEnv, mProblemComm, nUserWts));
188 
189  AlgZoltan<Adapter> algZoltan(this->mEnv, mProblemComm, this->mBaseInputAdapter);
190 
191  algZoltan.partition(partSoln);
192 
193  size_t numGlobalParts = partSoln->getTargetGlobalNumberOfParts();
194 
195  const part_t *parts = partSoln->getPartListView();
197 
199  // Build up tree that represents partitioning subproblems, which will
200  // be used for determining separators at each level
201  // -- for now, this is built up artificially
202  // -- eventually this will be obtained from PHG output
203  //
204  // Each separator i is represented by 4 integers/part_t? in the partTree
205  // structure: partTree[4*i], partTree[4*i+1], partTree[4*i+2], partTree[4*i+3]
206  // These 4 integers are level of separator, smallest part in 1st half of separator,
207  // smallest part in 2nd half of separator, largest part in 2nd half of separator + 1
209  // change int to something, part_t?
210 
211  std::vector<int> partTree;
212 
213  buildPartTree( 0, 0, (numGlobalParts-1)/2 + 1, numGlobalParts, partTree);
214  unsigned int numSeparators = partTree.size() / 4;
215 
216  for(unsigned int i=0;i<partTree.size(); i++)
217  {
218  std::cout << "partTree: " << partTree[i] << std::endl;
219  }
220  std::cout << "NumSeparators: " << numSeparators << std::endl;
221 
223 
224 
226  // Create a map that maps each part number to a new number based on
227  // the level of the hiearchy of the separator tree. This allows us
228  // to easily identify the boundary value vertices
230  int numLevels = partTree[4*(numSeparators-1)]+1;
231 
232  std::vector<std::vector<int> > partLevelMap(numLevels,std::vector<int>(numGlobalParts));
233 
234  std::vector<int> sepsInLev(numLevels,0);
235 
236  for(unsigned int i=0;i<numSeparators;i++)
237  {
238  int level = partTree[4*i];
239  int leftPart = partTree[4*i+1];
240  int splitPart = partTree[4*i+2];
241  int rightPart = partTree[4*i+3];
242 
243  for(int part=leftPart; part<splitPart; part++)
244  {
245  partLevelMap[level][part] = 2*sepsInLev[level];
246  }
247 
248  for(int part=splitPart; part<rightPart; part++)
249  {
250  partLevelMap[level][part] = 2*sepsInLev[level]+1;
251  }
252 
253  sepsInLev[level]++;
254  }
255 
256  std::cout << "partLevelMap[0][0] = " << partLevelMap[0][0] << std::endl;
257  std::cout << "partLevelMap[0][1] = " << partLevelMap[0][1] << std::endl;
258 
259  std::cout << "HERE7" << std::endl;
260 
262 
263  // Set of separator vertices. Used to keep track of what vertices are
264  // already in previous calculated separators. These vertices should be
265  // excluded from future separator calculations
266  std::set<lno_t> sepVerts;
267  std::vector<std::vector< std::set<lno_t> > > sepVertsByLevel(numLevels);
268 
270  // Loop over each cut
271  // 1. Build boundary layer between parts
272  // 2. Build vertex separator from boundary layer
274  std::cout << "HERE8" << std::endl;
275 
276  for(unsigned int level=0;level<numLevels;level++)
277  {
278  sepVertsByLevel[level].resize(sepsInLev[level]);
279 
280  for(unsigned int levIndx=0;levIndx<sepsInLev[level];levIndx++)
281  {
283  // Build boundary layer between parts (edge separator)
285  std::cout << "HERE9" << std::endl;
286 
287  int bigraphNumU=0, bigraphNumV=0, bigraphNumE=0;
288  std::vector<int> bigraphVMapU;
289  std::vector<int> bigraphVMapV;
290 
291  std::vector<int> bigraphCRSRowPtr;
292  std::vector<int> bigraphCRSCols;
293 
294 
295  getBoundLayer(levIndx, partLevelMap[level], parts, sepVerts,
296  bigraphNumU,bigraphNumV,bigraphNumE,
297  bigraphCRSRowPtr, bigraphCRSCols,
298  bigraphVMapU,bigraphVMapV);
299 
300  std::cout << "Bipartite graph: " << bigraphNumU << " " << bigraphNumV << " "
301  << bigraphNumE << std::endl;
302 
303  for (unsigned int i=0;i<bigraphVMapU.size();i++)
304  {
305  std::cout << "boundVertU: " << bigraphVMapU[i] << std::endl;
306  }
307 
308  for (unsigned int i=0;i<bigraphVMapV.size();i++)
309  {
310  std::cout << "boundVertV: " << bigraphVMapV[i] << std::endl;
311  }
312 
313 
314 
315  for (int rownum=0;rownum<bigraphNumU;rownum++)
316  {
317 
318  for (int eIdx=bigraphCRSRowPtr[rownum];eIdx<bigraphCRSRowPtr[rownum+1];eIdx++)
319  {
320  std::cout << "bipartite E: " << bigraphVMapU[rownum] << ", " << bigraphVMapV[ bigraphCRSCols[eIdx]]
321  << " ( " << rownum << "," << bigraphCRSCols[eIdx] << " )" << std::endl;
322  }
323 
324  }
325  std::cout << "HERE10" << std::endl;
327 
329  // Calculate bipartite matching from boundary layer
331  if (bigraphNumU > 0)
332  {
333  assert(bigraphNumV>0);
334 
335  Matcher<lno_t> bpMatch(bigraphCRSRowPtr.data(), bigraphCRSCols.data(), bigraphNumU, bigraphNumV, bigraphNumE);
336  bpMatch.match();
337 
338  const std::vector<int> &vertUMatches = bpMatch.getVertexUMatches();
339  const std::vector<int> &vertVMatches = bpMatch.getVertexVMatches();
341 
343  // Calculate vertex cover (which is vertex separator) from matching
345  std::vector<int> VC;
346 
347  bpMatch.getVCfromMatching(bigraphCRSRowPtr,bigraphCRSCols,vertUMatches,vertVMatches,
348  bigraphVMapU,bigraphVMapV,VC);
349 
350  for(unsigned int i=0;i<VC.size();i++)
351  {
352  sepVerts.insert(VC[i]);
353 
354  sepVertsByLevel[level][levIndx].insert(VC[i]);
355  std::cout << "VC: " << VC[i] << std::endl;
356  }
358  }
359 
360  //TODO: Copy data into separator structures?
361 
362 
363  }
364  }
365 
367  // Output separators
369  std::cout << "Separators: " << std::endl;
370  for(unsigned int level=0;level<sepVertsByLevel.size();level++)
371  {
372  sepVertsByLevel[level].resize(sepsInLev[level]);
373 
374  for(unsigned int levIndx=0;levIndx<sepVertsByLevel[level].size();levIndx++)
375  {
376  std::cout << " Separator " << level << " " << levIndx << ": ";
377 
378 
379 
380 
381  typename std::set<lno_t>::const_iterator iterS;
382  for (iterS=sepVertsByLevel[level][levIndx].begin();iterS!=sepVertsByLevel[level][levIndx].end();++iterS)
383  {
384  std::cout << *iterS << " ";
385  }
386  std::cout << std::endl;
387 
388 
389  }
390  }
392 
393 
394 
395 
396  std::cout << "HERE20" << std::endl;
397 
399 
400  // //TODO: calculate vertex separator for each layer,
401  // //TODO: using vertex separators, compute new ordering and store in solution
402  // //TODO: move to ordering directory
403 
404  mEnv->debug(DETAILED_STATUS, std::string("Exiting AlgND"));
405  return 0;
406 }
408 
410 // Create boundary layer of vertices between 2 partitions
411 //
412 // Could improve the efficiency here by first creating a boundary layer graph
413 // between all parts
415 template <typename Adapter>
416 void AlgND<Adapter>::getBoundLayer(int levelIndx, const std::vector<part_t> &partMap,
417  const part_t * parts,
418  const std::set<int> &excVerts,
419  int &bigraphNumS, int &bigraphNumT, int &bigraphNumE,
420  std::vector<int> &bigraphCRSRowPtr, std::vector<int> &bigraphCRSCols,
421  std::vector<int> &bigraphVMapS, std::vector<int> &bigraphVMapT)
422 {
423  std::cout << "HI1" << std::endl;
424 
425  typedef typename Adapter::lno_t lno_t; // local ids
426  typedef typename Adapter::scalar_t scalar_t; // scalars
427  typedef StridedData<lno_t, scalar_t> input_t;
428 
429  int numVerts = mGraphModel->getLocalNumVertices();
430 
431  //Teuchos ArrayView
432  ArrayView< const lno_t > eIDs;
433  ArrayView< const lno_t > vOffsets;
434  ArrayView< input_t > wgts;
435 
436  // For some reason getLocalEdgeList seems to be returning empty eIDs
437  //size_t numEdges = ( (GraphModel<typename Adapter::base_adapter_t>) *mGraphModel).getLocalEdgeList(eIDs, vOffsets, wgts);
438 
439  //size_t numEdges = ( (GraphModel<typename Adapter::base_adapter_t>) *mGraphModel).getEdgeList(eIDs, vOffsets, wgts);
440  ( (GraphModel<typename Adapter::base_adapter_t>) *mGraphModel).getEdgeList(eIDs, vOffsets, wgts);
441 
442 
443  std::map<int,std::set<int> > bigraphEs;
444  std::set<int> vSetS;
445  std::set<int> vSetT;
446 
447  bigraphNumE=0;
448 
449  for(int v1=0;v1<numVerts;v1++)
450  {
451 
452  part_t vpart1 = partMap[parts[v1]];
453 
454  bool correctBL = (vpart1 >= 2*levelIndx && vpart1 < 2*(levelIndx+1) );
455 
456  // if vertex is not in the correct range of parts, it cannot be a member of
457  // this boundary layer
458  if(!correctBL)
459  {
460  continue;
461  }
462 
463  // Ignore vertices that belong to set of vertices to exclude
464  if(excVerts.find(v1)!=excVerts.end())
465  {
466  continue;
467  }
468 
469  //Loop over edges connected to v1
470  //MMW figure out how to get this from Zoltan2
471  for(int j=vOffsets[v1];j<vOffsets[v1+1];j++)
472  {
473 
474  int v2 = eIDs[j];
475 
476  part_t vpart2 = partMap[parts[v2]];
477 
478  correctBL = (vpart2 >= 2*levelIndx && vpart2 < 2*(levelIndx+1) );
479 
480  // if vertex is not in the correct range of parts, it cannot be a member of
481  // this boundary layer
482  if(!correctBL)
483  {
484  continue;
485  }
486 
487  // Ignore vertices that belong to set of vertices to exclude
488  if(excVerts.find(v2)!=excVerts.end())
489  {
490  continue;
491  }
492 
493  if ( vpart1 != vpart2 )
494  {
495  // Vertex added to 1st set of boundary vertices
496  if(vpart1<vpart2)
497  {
498  vSetS.insert(v1);
499 
500  // v1, v2
501  if(bigraphEs.find(v1)==bigraphEs.end())
502  {
503  bigraphEs[v1] = std::set<int>();
504  }
505  bigraphEs[v1].insert(v2);
506  bigraphNumE++;
507 
508  }
509  // Vertex added to 2nd set of boundary vertices
510  else
511  {
512  vSetT.insert(v1);
513  }
514  }
515 
516  }
517  }
518 
520  // Set size of two vertex sets for bipartite graph
522  bigraphNumS = vSetS.size();
523  bigraphNumT = vSetT.size();
525 
528 
529  bigraphVMapS.resize(bigraphNumS);
530 
531  std::map<int,int> glob2LocTMap;
532 
533  unsigned int indx=0;
534  for(std::set<int>::const_iterator iter=vSetS.begin(); iter!=vSetS.end(); ++iter)
535  {
536  bigraphVMapS[indx] = *iter;
537  indx++;
538  }
539 
540 
541  bigraphVMapT.resize(bigraphNumT);
542  indx=0;
543  for(std::set<int>::const_iterator iter=vSetT.begin();iter!=vSetT.end();++iter)
544  {
545  bigraphVMapT[indx] = *iter;
546  glob2LocTMap[*iter]=indx;
547  indx++;
548  }
550 
551 
553  // Set sizes for bipartite graph data structures
555  bigraphCRSRowPtr.resize(bigraphNumS+1);
556  bigraphCRSCols.resize(bigraphNumE);
558 
560  // Copy bipartite graph edges into CRS format
562  bigraphCRSRowPtr[0]=0;
563 
564  unsigned int rownum=0;
565  unsigned int nzIndx=0;
566  std::map<int,std::set<int> >::const_iterator iterM;
567  for (iterM=bigraphEs.begin();iterM!=bigraphEs.end();++iterM)
568  {
569  bigraphCRSRowPtr[rownum+1] = bigraphCRSRowPtr[rownum] + (*iterM).second.size();
570 
571  for(std::set<int>::const_iterator iter=(*iterM).second.begin(); iter!=(*iterM).second.end(); ++iter)
572  {
573  bigraphCRSCols[nzIndx] = glob2LocTMap[(*iter)];
574 
575  nzIndx++;
576  }
577 
578  rownum++;
579  }
581 
582 }
584 
585 
586 
587 template <typename Adapter>
588 void AlgND<Adapter>::
589 buildPartTree(int level, int leftPart, int splitPart, int rightPart, std::vector<int> &partTree)
590 {
591  // Insert information for this separator
592  partTree.push_back(level);
593  partTree.push_back(leftPart);
594  partTree.push_back(splitPart);
595  partTree.push_back(rightPart);
596 
597  // Recurse down left side of tree
598  if(splitPart-leftPart > 1)
599  {
600  int newSplit = leftPart+(splitPart-leftPart-1)/2 + 1;
601  buildPartTree(level+1,leftPart,newSplit,splitPart,partTree);
602  }
603 
604  // Recurse down right side of tree
605  if(rightPart-splitPart>1)
606  {
607  int newSplit = splitPart+(rightPart-splitPart-1)/2 + 1;
608  buildPartTree(level+1,splitPart,newSplit,rightPart,partTree);
609  }
610 }
611 
612 
613 
614 } // namespace Zoltan2
615 
616 
617 
618 
619 
620 #endif
#define Z2_THROW_SERIAL(mystr)
Throw an error when code is run on more than one processor.
#define Z2_THROW_EXPERIMENTAL_WOLF(mystr)
Throw an error when wolf experimental code is requested but not compiled.
LO match()
Computes the maximum cardinality matching.
interface to the Zoltan package
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
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.
void partition(const RCP< PartitioningSolution< Adapter > > &solution)
Partitioning method.
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.
#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.