Zoltan2
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
Zoltan2_AlgRCM.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 #ifndef _ZOLTAN2_ALGRCM_HPP_
11 #define _ZOLTAN2_ALGRCM_HPP_
12 
13 #include <Zoltan2_Algorithm.hpp>
14 #include <Zoltan2_GraphModel.hpp>
16 #include <Zoltan2_Sort.hpp>
17 #include <queue>
18 
19 
23 
24 
25 namespace Zoltan2{
26 
27 template <typename Adapter>
28 class AlgRCM : public Algorithm<Adapter>
29 {
30  private:
31 
32  const RCP<const typename Adapter::base_adapter_t> adapter;
33  const RCP<Teuchos::ParameterList> pl;
34  const RCP<const Teuchos::Comm<int> > comm;
35  RCP<const Environment> env;
36  modelFlag_t graphFlags;
37 
38  public:
39 
40  typedef typename Adapter::lno_t lno_t;
41  typedef typename Adapter::gno_t gno_t;
42  typedef typename Adapter::offset_t offset_t;
43  typedef typename Adapter::scalar_t scalar_t;
44 
46  const RCP<const typename Adapter::base_adapter_t> &adapter__,
47  const RCP<Teuchos::ParameterList> &pl__,
48  const RCP<const Teuchos::Comm<int> > &comm__,
49  RCP<const Environment> &env__,
50  const modelFlag_t &graphFlags__
51  ) : adapter(adapter__), pl(pl__), comm(comm__), env(env__), graphFlags(graphFlags__)
52  {
53  }
54 
55  int globalOrder(const RCP<GlobalOrderingSolution<gno_t> > &/* solution */)
56  {
57  throw std::logic_error("AlgRCM does not yet support global ordering.");
58  }
59 
60  int localOrder(const RCP<LocalOrderingSolution<lno_t> > &solution)
61  {
62  int ierr= 0;
63 
64  HELLO;
65 
66  // Get local graph.
67  ArrayView<const gno_t> edgeIds;
68  ArrayView<const offset_t> offsets;
69  ArrayView<StridedData<lno_t, scalar_t> > wgts;
70 
71  const auto model = rcp(new GraphModel<Adapter>(adapter, env, comm, graphFlags));
72  const size_t nVtx = model->getLocalNumVertices();
73  model->getEdgeList(edgeIds, offsets, wgts);
74  const int numWeightsPerEdge = model->getNumWeightsPerEdge();
75  if (numWeightsPerEdge > 1){
76  throw std::runtime_error("Multiple weights not supported.");
77  }
78 
79 #if 0
80  // Debug
81  cout << "Debug: Local graph from getLocalEdgeList" << endl;
82  cout << "rank " << comm->getRank() << ": nVtx= " << nVtx << endl;
83  cout << "rank " << comm->getRank() << ": edgeIds: " << edgeIds << endl;
84  cout << "rank " << comm->getRank() << ": offsets: " << offsets << endl;
85 #endif
86 
87  // RCM constructs invPerm, not perm
88  const ArrayRCP<lno_t> invPerm = solution->getPermutationRCP(true);
89  const ArrayRCP<lno_t> tmpPerm(invPerm.size()); //temporary array used in reversing order
90 
91  // Check if there are actually edges to reorder.
92  // If there are not, then just use the natural ordering.
93  if (offsets[nVtx] == 0) {
94  for (size_t i = 0; i < nVtx; ++i) {
95  invPerm[i] = i;
96  }
97  solution->setHaveInverse(true);
98  return 0;
99  }
100 
101  // Set the label of each vertex to invalid.
102  Tpetra::global_size_t INVALID = Teuchos::OrdinalTraits<Tpetra::global_size_t>::invalid();
103  for (size_t i = 0; i < nVtx; ++i) {
104  invPerm[i] = INVALID;
105  }
106 
107  // Loop over all connected components.
108  // Do BFS within each component.
109  gno_t root = 0;
110  std::queue<gno_t> Q;
111  size_t count = 0; // CM label, reversed later
112  size_t next = 0; // next unmarked vertex
113  Teuchos::Array<std::pair<gno_t, offset_t> > children; // children and their degrees
114 
115  while (count < nVtx) {
116 
117  // Find suitable root vertex for this component.
118  // First find an unmarked vertex, use to find root in next component.
119  while ((next < nVtx) && (static_cast<Tpetra::global_size_t>(invPerm[next]) != INVALID)) next++;
120 
121  // Select root method. Pseudoperipheral usually gives the best
122  // ordering, but the user may choose a faster method.
123  std::string root_method = pl->get("root_method", "pseudoperipheral");
124  if (root_method == std::string("first"))
125  root = next;
126  else if (root_method == std::string("smallest_degree"))
127  root = findSmallestDegree(next, nVtx, edgeIds, offsets);
128  else if (root_method == std::string("pseudoperipheral"))
129  root = findPseudoPeripheral(next, nVtx, edgeIds, offsets);
130  else {
131  // This should never happen if pl was validated.
132  throw std::runtime_error("invalid root_method");
133  }
134 
135  // Label connected component starting at root
136  Q.push(root);
137  //cout << "Debug: invPerm[" << root << "] = " << count << endl;
138  invPerm[root] = count++;
139  tmpPerm[invPerm[root]] = root;
140 
141  while (Q.size()){
142  // Get a vertex from the queue
143  gno_t v = Q.front();
144  Q.pop();
145  //cout << "Debug: v= " << v << ", offsets[v] = " << offsets[v] << endl;
146 
147  // Add unmarked children to list of pairs, to be added to queue.
148  children.resize(0);
149  for (offset_t ptr = offsets[v]; ptr < offsets[v+1]; ++ptr){
150  gno_t child = edgeIds[ptr];
151  if (static_cast<Tpetra::global_size_t>(invPerm[child]) == INVALID){
152  // Not visited yet; add child to list of pairs.
153  std::pair<gno_t,offset_t> newchild;
154  newchild.first = child;
155  newchild.second = offsets[child+1] - offsets[child];
156  children.push_back(newchild);
157  }
158  }
159  // Sort children by increasing degree
160  // TODO: If edge weights, sort children by decreasing weight,
162  zort.sort(children);
163 
164  typename Teuchos::Array<std::pair<gno_t,offset_t> >::iterator it = children.begin ();
165  for ( ; it != children.end(); ++it){
166  // Push children on the queue in sorted order.
167  gno_t child = it->first;
168  invPerm[child] = count++; // Label as we push on Q
169  tmpPerm[invPerm[child]] = child;
170  Q.push(child);
171  //cout << "Debug: invPerm[" << child << "] = " << count << endl;
172  }
173  }
174  }
175 
176  // Old row tmpPerm[i] is now the new row i.
177 
178  // Reverse labels for RCM.
179  bool reverse = true; // TODO: Make parameter
180  if (reverse) {
181  lno_t temp;
182  for (size_t i=0; i < nVtx/2; ++i) {
183  // This effectively does the work of two loops:
184  // 1) for (i=1; i< nVtx/2; ++i)
185  // swap of tmpPerm[i] and tmpPerm[nVtx-1-i]
186  // 2) for (i=0; i < nVtx; ++i)
187  // invPerm[tmpPerm[i]] = i;
188  temp = tmpPerm[i];
189  invPerm[tmpPerm[nVtx-1-i]] = i;
190  invPerm[temp] = nVtx-1-i;
191  }
192 
193  }
194 
195  solution->setHaveInverse(true);
196  return ierr;
197  }
198 
199  private:
200  // Find a smallest degree vertex in component containing v
201  gno_t findSmallestDegree(
202  gno_t v,
203  lno_t nVtx,
204  ArrayView<const gno_t> edgeIds,
205  ArrayView<const offset_t> offsets)
206  {
207  std::queue<gno_t> Q;
208  Teuchos::Array<bool> mark(nVtx);
209 
210  // Do BFS and compute smallest degree as we go
211  offset_t smallestDegree = nVtx;
212  gno_t smallestVertex = 0;
213 
214  // Clear mark array - nothing marked yet
215  for (int i=0; i<nVtx; i++)
216  mark[i] = false;
217 
218  // Start from v
219  Q.push(v);
220  while (Q.size()){
221  // Get first vertex from the queue
222  v = Q.front();
223  Q.pop();
224  // Check degree of v
225  offset_t deg = offsets[v+1] - offsets[v];
226  if (deg < smallestDegree){
227  smallestDegree = deg;
228  smallestVertex = v;
229  }
230  // Add unmarked children to queue
231  for (offset_t ptr = offsets[v]; ptr < offsets[v+1]; ++ptr){
232  gno_t child = edgeIds[ptr];
233  if (!mark[child]){
234  mark[child] = true;
235  Q.push(child);
236  }
237  }
238  }
239  return smallestVertex;
240  }
241 
242  // Find a pseudoperipheral vertex in component containing v
243  gno_t findPseudoPeripheral(
244  gno_t v,
245  lno_t nVtx,
246  ArrayView<const gno_t> edgeIds,
247  ArrayView<const offset_t> offsets)
248  {
249  std::queue<gno_t> Q;
250  Teuchos::Array<bool> mark(nVtx);
251 
252  // Do BFS a couple times, pick vertex last visited (furthest away)
253  const int numBFS = 2;
254  for (int bfs=0; bfs<numBFS; bfs++){
255  // Clear mark array - nothing marked yet
256  for (int i=0; i<nVtx; i++)
257  mark[i] = false;
258  // Start from v
259  Q.push(v);
260  while (Q.size()){
261  // Get first vertex from the queue
262  v = Q.front();
263  Q.pop();
264  // Add unmarked children to queue
265  for (offset_t ptr = offsets[v]; ptr < offsets[v+1]; ++ptr){
266  gno_t child = edgeIds[ptr];
267  if (!mark[child]){
268  mark[child] = true;
269  Q.push(child);
270  }
271  }
272  }
273  }
274  return v;
275  }
276 
277 };
278 }
279 #endif
#define HELLO
#define INVALID(STR)
int localOrder(const RCP< LocalOrderingSolution< lno_t > > &solution)
Ordering method.
AlgRCM(const RCP< const typename Adapter::base_adapter_t > &adapter__, const RCP< Teuchos::ParameterList > &pl__, const RCP< const Teuchos::Comm< int > > &comm__, RCP< const Environment > &env__, const modelFlag_t &graphFlags__)
std::bitset< NUM_MODEL_FLAGS > modelFlag_t
map_t::global_ordinal_type gno_t
Definition: mapRemotes.cpp:27
Defines the OrderingSolution class.
Adapter::offset_t offset_t
tuple root
Definition: validXML.py:24
Algorithm defines the base class for all algorithms.
map_t::local_ordinal_type lno_t
Definition: mapRemotes.cpp:26
int globalOrder(const RCP< GlobalOrderingSolution< gno_t > > &)
Ordering method.
Sort vector of pairs (key, value) by value.
Adapter::scalar_t scalar_t
GraphModel defines the interface required for graph models.
Tpetra::global_size_t global_size_t
Defines the GraphModel interface.
Adapter::lno_t lno_t
void sort(Teuchos::Array< std::pair< key_t, value_t > > &listofPairs, bool inc=true)
Adapter::gno_t gno_t