FEAT 3
Finite Element Analysis Toolbox
Loading...
Searching...
No Matches
cuthill_mckee.cpp
1// FEAT3: Finite Element Analysis Toolbox, Version 3
2// Copyright (C) 2010 by Stefan Turek & the FEAT group
3// FEAT3 is released under the GNU General Public License version 3,
4// see the file 'copyright.txt' in the top level directory for details.
5
6// includes, FEAT
7#include <kernel/adjacency/cuthill_mckee.hpp>
8#include <kernel/adjacency/graph.hpp>
10
11namespace FEAT
12{
13 namespace Adjacency
14 {
16 const Graph& graph,
17 bool reverse,
20 {
21 std::vector<Index> layers;
22 return compute(layers, graph, reverse, r_type, s_type);
23 }
24
26 std::vector<Index>& layers,
27 const Graph& graph,
28 bool reverse,
31 {
32 layers.reserve(graph.get_num_nodes_domain() + Index(1));
33
34 // get the number of nodes
35 Index num_nodes = graph.get_num_nodes_domain();
36
37 // get the graph's data
38 const Index* domain_ptr = graph.get_domain_ptr();
39 const Index* image_idx = graph.get_image_idx();
40
41 // a vector which keeps track of which nodes have already been processed
42 std::vector<bool> node_mask(num_nodes, false);
43
44 // a vector storing the degree of each node
45 std::vector<Index> node_degree(num_nodes);
46 for(Index j(0); j < num_nodes; ++j)
47 {
48 node_degree[j] = graph.degree(j);
49 }
50
51 // auxiliary variables
52 Index lvl1 = 0;
53 Index lvl2 = 0;
54 Index lvl3 = 0;
55
56 // push first layer start
57 layers.push_back(lvl1);
58
59 // create permutation
60 Permutation perm(graph.get_num_nodes_domain());
61 Index* permutation = perm.get_perm_pos();
62
63 while(lvl2 < num_nodes)
64 {
65 // initialize root
66 Index root = num_nodes + 1;
67
68 // get the root node
69 switch(r_type)
70 {
71
72 // default: choose the first node possible
74 for(Index j(0); j < num_nodes; ++j)
75 {
76 // check if the node is unmarked
77 if(!node_mask[j])
78 {
79 root = j;
80 break;
81 }
82 }
83 break;
84
85 // choose the node of minimum degree
87 {
88 Index min = num_nodes + 1;
89 for(Index j(0); j < num_nodes; ++j)
90 {
91 if((node_degree[j] < min) && !node_mask[j])
92 {
93 root = j;
94 min = node_degree[j];
95 }
96 }
97 }
98 break;
99
100 // choose the node of maximum degree
102 {
103 Index max = 0;
104 for(Index j(0); j < num_nodes; ++j)
105 {
106 if((node_degree[j] > max) && !node_mask[j])
107 {
108 root = j;
109 max = node_degree[j];
110 }
111 }
112 break;
113 }
114
115 // else: error
116 default:
117 XABORTM("Invalid RootType::type parameter!");
118 }
119
120 // if something very odd has happened
121 XASSERTM(root < num_nodes, "No root node found!");
122
123 // initialize the first level of the root node
124 ++lvl1;
125 lvl2 = lvl1;
126 lvl3 = lvl1;
127
128 // add the root into the permutation array
129 const Index lvl_root = lvl1;
130 permutation[lvl1 - 1] = root;
131 node_mask[root] = 1;
132
133 // push the root into the next layer
134 const Index lay_root_pos = Index(layers.size());
135 layers.push_back(lvl1);
136
137 // loop through the adjacency levels of the root
138 while(lvl2 < num_nodes)
139 {
140 // loop through all nodes in the current level
141 for(Index i(lvl1 - 1); i < lvl2 ; ++i)
142 {
143 // get the node's index
144 Index n = permutation[i];
145
146 // Go through all nodes which are adjacent to node n
147 for(Index j(domain_ptr[n]); j < domain_ptr[n+1] ; ++j)
148 {
149 // Get the index of the adjacent node
150 Index k = image_idx[j];
151
152 // has this node been processed?
153 if(!node_mask[k])
154 {
155 ++lvl3;
156 permutation[lvl3 - 1] = k;
157 node_mask[k] = true;
158 }
159 } //j loop
160 } // i loop
161
162 if(lvl3 <= lvl2)
163 {
164 break;
165 }
166
167 // sorting
168 switch(s_type)
169 {
170 // default: do nothing
172 break;
173
174 // descending order
175 case SortType::desc:
176
177 // if there is nothing to do
178 if(lvl2 + 1 >= lvl3)
179 {
180 break;
181 }
182
183 // sorting algorithm: linear insertion
184 for(Index i(lvl2); i < lvl3; ++i)
185 {
186 Index x = node_degree[permutation[i]];
187 Index y = permutation[i];
188 Index k(i);
189 for(; (k > lvl2) && (x > node_degree[permutation[k-1]]); --k)
190 {
191 permutation[k] = permutation[k-1];
192 }
193 permutation[k] = y;
194 }
195 break;
196
197 // ascending order
198 case SortType::asc:
199
200 // if there is nothing to do
201 if(lvl2 + 1 >= lvl3)
202 {
203 break;
204 }
205
206 // sorting algorithm: linear insertion
207 for(Index i(lvl2); i < lvl3; ++i)
208 {
209 Index x = node_degree[permutation[i]];
210 Index y = permutation[i];
211 Index k(i);
212 for(; (k > lvl2) && (x < node_degree[permutation[k-1]]); --k)
213 {
214 permutation[k] = permutation[k-1];
215 }
216 permutation[k] = y;
217 }
218 break;
219
220 // else: error
221 default:
222 XABORTM("Invalid run_type parameter!");
223 }
224
225 // push next layer
226 layers.push_back(lvl3);
227
228 // get to the next adjacency level
229 lvl1 = lvl2+1;
230 lvl2 = lvl3;
231
232 } //while(lvl2 < num_nodes)
233
234 // reverse?
235 if(reverse)
236 {
237 for(Index ind(lvl_root - 1), jnd(lvl2 - 1); ind < jnd; ++ind, --jnd)
238 {
239 std::swap(permutation[ind], permutation[jnd]);
240 }
241
242 // reverse layers
243 const Index lay_back = Index(layers.size()) - 1u;
244 for(Index k(lay_back); k >= lay_root_pos; --k)
245 {
246 // compute layer sizes from offsets
247 layers.at(k) -= layers.at(k-1u);
248 }
249 for(Index k(lay_root_pos), l(lay_back); k < l; ++k, --l)
250 {
251 // reverse layer sizes
252 std::swap(layers.at(k), layers.at(l));
253 }
254 for(Index k(lay_root_pos); k <= lay_back; ++k)
255 {
256 // compute layer offsets from sizes
257 layers.at(k) += layers.at(k-1u);
258 }
259 }
260
261 } //while(lvl2 < num_nodes) (the separability loop)
262
263 // push the final layer terminator
264 layers.push_back(num_nodes);
265
266 // compute swap array
267 perm.calc_swap_from_perm();
268
269 // return permutation
270 return perm;
271 }
272 } // namespace Adjacency
273} // namespace FEAT
#define XABORTM(msg)
Abortion macro definition with custom message.
Definition: assertion.hpp:192
#define XASSERTM(expr, msg)
Assertion macro definition with custom message.
Definition: assertion.hpp:263
RootType
Root type enumeration.
static Permutation compute(std::vector< Index > &layers, const Graph &graph, bool reverse=false, CuthillMcKee::RootType r_type=RootType::standard, CuthillMcKee::SortType t_type=SortType::standard)
Cuthill-McKee permutation computation function.
SortType
Sort type enumeration.
Adjacency Graph implementation.
Definition: graph.hpp:34
Index * get_domain_ptr()
Returns the domain pointer array.
Definition: graph.hpp:359
Index * get_image_idx()
Returns the image node index array.
Definition: graph.hpp:374
Index degree(Index domain_node) const
Returns the degree of a domain node.
Definition: graph.hpp:333
Index * get_perm_pos()
returns the permute-position array
void calc_swap_from_perm()
Computes the swap-position vector from the permutation-position vector.
FEAT namespace.
Definition: adjactor.hpp:12
std::uint64_t Index
Index data type.