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