1 //
2 //=======================================================================
3 // Copyright 2002 Marc Wintermantel (wintermantel@even-ag.ch)
4 // ETH Zurich, Center of Structure Technologies
5 // (https://web.archive.org/web/20050307090307/http://www.structures.ethz.ch/)
6 //
7 // Distributed under the Boost Software License, Version 1.0. (See
8 // accompanying file LICENSE_1_0.txt or copy at
9 // http://www.boost.org/LICENSE_1_0.txt)
10 //=======================================================================
11 //
12
13 #ifndef BOOST_GRAPH_SLOAN_HPP
14 #define BOOST_GRAPH_SLOAN_HPP
15
16 #define WEIGHT1 1 // default weight for the distance in the Sloan algorithm
17 #define WEIGHT2 2 // default weight for the degree in the Sloan algorithm
18
19 #include <boost/config.hpp>
20 #include <vector>
21 #include <queue>
22 #include <algorithm>
23 #include <limits>
24 #include <boost/pending/queue.hpp>
25 #include <boost/graph/graph_traits.hpp>
26 #include <boost/graph/breadth_first_search.hpp>
27 #include <boost/graph/properties.hpp>
28 #include <boost/pending/indirect_cmp.hpp>
29 #include <boost/property_map/property_map.hpp>
30 #include <boost/graph/visitors.hpp>
31 #include <boost/graph/adjacency_list.hpp>
32 #include <boost/graph/cuthill_mckee_ordering.hpp>
33
34 ////////////////////////////////////////////////////////////
35 //
36 // Sloan-Algorithm for graph reordering
37 //(optimzes profile and wavefront, not primiraly bandwidth
38 //
39 ////////////////////////////////////////////////////////////
40
41 namespace boost
42 {
43
44 /////////////////////////////////////////////////////////////////////////
45 // Function that returns the maximum depth of
46 // a rooted level strucutre (RLS)
47 //
48 /////////////////////////////////////////////////////////////////////////
RLS_depth(Distance & d)49 template < class Distance > typename Distance::value_type RLS_depth(Distance& d)
50 {
51 typename Distance::value_type h_s = 0;
52 typename Distance::iterator iter;
53
54 for (iter = d.begin(); iter != d.end(); ++iter)
55 {
56 if (*iter > h_s)
57 {
58 h_s = *iter;
59 }
60 }
61
62 return h_s;
63 }
64
65 /////////////////////////////////////////////////////////////////////////
66 // Function that returns the width of the largest level of
67 // a rooted level strucutre (RLS)
68 //
69 /////////////////////////////////////////////////////////////////////////
70 template < class Distance, class my_int >
RLS_max_width(Distance & d,my_int depth)71 typename Distance::value_type RLS_max_width(Distance& d, my_int depth)
72 {
73
74 typedef typename Distance::value_type Degree;
75
76 // Searching for the maximum width of a level
77 std::vector< Degree > dummy_width(depth + 1, 0);
78 typename std::vector< Degree >::iterator my_it;
79 typename Distance::iterator iter;
80 Degree w_max = 0;
81
82 for (iter = d.begin(); iter != d.end(); ++iter)
83 {
84 dummy_width[*iter]++;
85 }
86
87 for (my_it = dummy_width.begin(); my_it != dummy_width.end(); ++my_it)
88 {
89 if (*my_it > w_max)
90 w_max = *my_it;
91 }
92
93 return w_max;
94 }
95
96 /////////////////////////////////////////////////////////////////////////
97 // Function for finding a good starting node for Sloan algorithm
98 //
99 // This is to find a good starting node. "good" is in the sense
100 // of the ordering generated.
101 /////////////////////////////////////////////////////////////////////////
102 template < class Graph, class ColorMap, class DegreeMap >
sloan_start_end_vertices(Graph & G,typename graph_traits<Graph>::vertex_descriptor & s,ColorMap color,DegreeMap degree)103 typename graph_traits< Graph >::vertex_descriptor sloan_start_end_vertices(
104 Graph& G, typename graph_traits< Graph >::vertex_descriptor& s,
105 ColorMap color, DegreeMap degree)
106 {
107 typedef typename property_traits< DegreeMap >::value_type Degree;
108 typedef typename graph_traits< Graph >::vertex_descriptor Vertex;
109 typedef typename std::vector<
110 typename graph_traits< Graph >::vertices_size_type >::iterator vec_iter;
111 typedef typename graph_traits< Graph >::vertices_size_type size_type;
112
113 typedef typename property_map< Graph, vertex_index_t >::const_type VertexID;
114
115 s = *(vertices(G).first);
116 Vertex e = s;
117 Vertex i;
118 Degree my_degree = get(degree, s);
119 Degree dummy, h_i, h_s, w_i, w_e;
120 bool new_start = true;
121 Degree maximum_degree = 0;
122
123 // Creating a std-vector for storing the distance from the start vertex in
124 // dist
125 std::vector< typename graph_traits< Graph >::vertices_size_type > dist(
126 num_vertices(G), 0);
127
128 // Wrap a property_map_iterator around the std::iterator
129 boost::iterator_property_map< vec_iter, VertexID, size_type, size_type& >
130 dist_pmap(dist.begin(), get(vertex_index, G));
131
132 // Creating a property_map for the indices of a vertex
133 typename property_map< Graph, vertex_index_t >::type index_map
134 = get(vertex_index, G);
135
136 // Creating a priority queue
137 typedef indirect_cmp< DegreeMap, std::greater< Degree > > Compare;
138 Compare comp(degree);
139 std::priority_queue< Vertex, std::vector< Vertex >, Compare > degree_queue(
140 comp);
141
142 // step 1
143 // Scan for the vertex with the smallest degree and the maximum degree
144 typename graph_traits< Graph >::vertex_iterator ui, ui_end;
145 for (boost::tie(ui, ui_end) = vertices(G); ui != ui_end; ++ui)
146 {
147 dummy = get(degree, *ui);
148
149 if (dummy < my_degree)
150 {
151 my_degree = dummy;
152 s = *ui;
153 }
154
155 if (dummy > maximum_degree)
156 {
157 maximum_degree = dummy;
158 }
159 }
160 // end 1
161
162 do
163 {
164 new_start = false; // Setting the loop repetition status to false
165
166 // step 2
167 // initialize the the disance std-vector with 0
168 for (typename std::vector< typename graph_traits<
169 Graph >::vertices_size_type >::iterator iter
170 = dist.begin();
171 iter != dist.end(); ++iter)
172 *iter = 0;
173
174 // generating the RLS (rooted level structure)
175 breadth_first_search(G, s,
176 visitor(
177 make_bfs_visitor(record_distances(dist_pmap, on_tree_edge()))));
178
179 // end 2
180
181 // step 3
182 // calculating the depth of the RLS
183 h_s = RLS_depth(dist);
184
185 // step 4
186 // pushing one node of each degree in an ascending manner into
187 // degree_queue
188 std::vector< bool > shrink_trace(maximum_degree, false);
189 for (boost::tie(ui, ui_end) = vertices(G); ui != ui_end; ++ui)
190 {
191 dummy = get(degree, *ui);
192
193 if ((dist[index_map[*ui]] == h_s) && (!shrink_trace[dummy]))
194 {
195 degree_queue.push(*ui);
196 shrink_trace[dummy] = true;
197 }
198 }
199
200 // end 3 & 4
201
202 // step 5
203 // Initializing w
204 w_e = (std::numeric_limits< Degree >::max)();
205 // end 5
206
207 // step 6
208 // Testing for termination
209 while (!degree_queue.empty())
210 {
211 i = degree_queue.top(); // getting the node with the lowest degree
212 // from the degree queue
213 degree_queue.pop(); // ereasing the node with the lowest degree from
214 // the degree queue
215
216 // generating a RLS
217 for (typename std::vector< typename graph_traits<
218 Graph >::vertices_size_type >::iterator iter
219 = dist.begin();
220 iter != dist.end(); ++iter)
221 *iter = 0;
222
223 breadth_first_search(G, i,
224 boost::visitor(make_bfs_visitor(
225 record_distances(dist_pmap, on_tree_edge()))));
226
227 // Calculating depth and width of the rooted level
228 h_i = RLS_depth(dist);
229 w_i = RLS_max_width(dist, h_i);
230
231 // Testing for termination
232 if ((h_i > h_s) && (w_i < w_e))
233 {
234 h_s = h_i;
235 s = i;
236 while (!degree_queue.empty())
237 degree_queue.pop();
238 new_start = true;
239 }
240 else if (w_i < w_e)
241 {
242 w_e = w_i;
243 e = i;
244 }
245 }
246 // end 6
247
248 } while (new_start);
249
250 return e;
251 }
252
253 //////////////////////////////////////////////////////////////////////////
254 // Sloan algorithm with a given starting Vertex.
255 //
256 // This algorithm requires user to provide a starting vertex to
257 // compute Sloan ordering.
258 //////////////////////////////////////////////////////////////////////////
259 template < class Graph, class OutputIterator, class ColorMap, class DegreeMap,
260 class PriorityMap, class Weight >
261 OutputIterator sloan_ordering(Graph& g,
262 typename graph_traits< Graph >::vertex_descriptor s,
263 typename graph_traits< Graph >::vertex_descriptor e,
264 OutputIterator permutation, ColorMap color, DegreeMap degree,
265 PriorityMap priority, Weight W1, Weight W2)
266 {
267 // typedef typename property_traits<DegreeMap>::value_type Degree;
268 typedef typename property_traits< PriorityMap >::value_type Degree;
269 typedef typename property_traits< ColorMap >::value_type ColorValue;
270 typedef color_traits< ColorValue > Color;
271 typedef typename graph_traits< Graph >::vertex_descriptor Vertex;
272 typedef typename std::vector<
273 typename graph_traits< Graph >::vertices_size_type >::iterator vec_iter;
274 typedef typename graph_traits< Graph >::vertices_size_type size_type;
275
276 typedef typename property_map< Graph, vertex_index_t >::const_type VertexID;
277
278 // Creating a std-vector for storing the distance from the end vertex in it
279 typename std::vector< typename graph_traits< Graph >::vertices_size_type >
280 dist(num_vertices(g), 0);
281
282 // Wrap a property_map_iterator around the std::iterator
283 boost::iterator_property_map< vec_iter, VertexID, size_type, size_type& >
284 dist_pmap(dist.begin(), get(vertex_index, g));
285
286 breadth_first_search(g, e,
287 visitor(make_bfs_visitor(record_distances(dist_pmap, on_tree_edge()))));
288
289 // Creating a property_map for the indices of a vertex
290 typename property_map< Graph, vertex_index_t >::type index_map
291 = get(vertex_index, g);
292
293 // Sets the color and priority to their initial status
294 Degree cdeg;
295 typename graph_traits< Graph >::vertex_iterator ui, ui_end;
296 for (boost::tie(ui, ui_end) = vertices(g); ui != ui_end; ++ui)
297 {
298 put(color, *ui, Color::white());
299 cdeg = get(degree, *ui) + 1;
300 put(priority, *ui, W1 * dist[index_map[*ui]] - W2 * cdeg);
301 }
302
303 // Priority list
304 typedef indirect_cmp< PriorityMap, std::greater< Degree > > Compare;
305 Compare comp(priority);
306 std::list< Vertex > priority_list;
307
308 // Some more declarations
309 typename graph_traits< Graph >::out_edge_iterator ei, ei_end, ei2, ei2_end;
310 Vertex u, v, w;
311
312 put(color, s,
313 Color::green()); // Sets the color of the starting vertex to gray
314 priority_list.push_front(s); // Puts s into the priority_list
315
316 while (!priority_list.empty())
317 {
318 priority_list.sort(comp); // Orders the elements in the priority list in
319 // an ascending manner
320
321 u = priority_list
322 .front(); // Accesses the last element in the priority list
323 priority_list
324 .pop_front(); // Removes the last element in the priority list
325
326 if (get(color, u) == Color::green())
327 {
328 // for-loop over all out-edges of vertex u
329 for (boost::tie(ei, ei_end) = out_edges(u, g); ei != ei_end; ++ei)
330 {
331 v = target(*ei, g);
332
333 put(priority, v, get(priority, v) + W2); // updates the priority
334
335 if (get(color, v)
336 == Color::white()) // test if the vertex is inactive
337 {
338 put(color, v,
339 Color::green()); // giving the vertex a preactive status
340 priority_list.push_front(
341 v); // writing the vertex in the priority_queue
342 }
343 }
344 }
345
346 // Here starts step 8
347 *permutation++
348 = u; // Puts u to the first position in the permutation-vector
349 put(color, u, Color::black()); // Gives u an inactive status
350
351 // for loop over all the adjacent vertices of u
352 for (boost::tie(ei, ei_end) = out_edges(u, g); ei != ei_end; ++ei)
353 {
354
355 v = target(*ei, g);
356
357 if (get(color, v) == Color::green())
358 { // tests if the vertex is inactive
359
360 put(color, v,
361 Color::red()); // giving the vertex an active status
362 put(priority, v, get(priority, v) + W2); // updates the priority
363
364 // for loop over alll adjacent vertices of v
365 for (boost::tie(ei2, ei2_end) = out_edges(v, g); ei2 != ei2_end;
366 ++ei2)
367 {
368 w = target(*ei2, g);
369
370 if (get(color, w) != Color::black())
371 { // tests if vertex is postactive
372
373 put(priority, w,
374 get(priority, w) + W2); // updates the priority
375
376 if (get(color, w) == Color::white())
377 {
378
379 put(color, w, Color::green()); // gives the vertex a
380 // preactive status
381 priority_list.push_front(
382 w); // puts the vertex into the priority queue
383
384 } // end if
385
386 } // end if
387
388 } // end for
389
390 } // end if
391
392 } // end for
393
394 } // end while
395
396 return permutation;
397 }
398
399 /////////////////////////////////////////////////////////////////////////////////////////
400 // Same algorithm as before, but without the weights given (taking default
401 // weights
402 template < class Graph, class OutputIterator, class ColorMap, class DegreeMap,
403 class PriorityMap >
404 OutputIterator sloan_ordering(Graph& g,
405 typename graph_traits< Graph >::vertex_descriptor s,
406 typename graph_traits< Graph >::vertex_descriptor e,
407 OutputIterator permutation, ColorMap color, DegreeMap degree,
408 PriorityMap priority)
409 {
410 return sloan_ordering(
411 g, s, e, permutation, color, degree, priority, WEIGHT1, WEIGHT2);
412 }
413
414 //////////////////////////////////////////////////////////////////////////
415 // Sloan algorithm without a given starting Vertex.
416 //
417 // This algorithm finds a good starting vertex itself to
418 // compute Sloan-ordering.
419 //////////////////////////////////////////////////////////////////////////
420
421 template < class Graph, class OutputIterator, class Color, class Degree,
422 class Priority, class Weight >
sloan_ordering(Graph & G,OutputIterator permutation,Color color,Degree degree,Priority priority,Weight W1,Weight W2)423 inline OutputIterator sloan_ordering(Graph& G, OutputIterator permutation,
424 Color color, Degree degree, Priority priority, Weight W1, Weight W2)
425 {
426 typedef typename boost::graph_traits< Graph >::vertex_descriptor Vertex;
427
428 Vertex s, e;
429 e = sloan_start_end_vertices(G, s, color, degree);
430
431 return sloan_ordering(
432 G, s, e, permutation, color, degree, priority, W1, W2);
433 }
434
435 /////////////////////////////////////////////////////////////////////////////////////////
436 // Same as before, but without given weights (default weights are taken instead)
437 template < class Graph, class OutputIterator, class Color, class Degree,
438 class Priority >
sloan_ordering(Graph & G,OutputIterator permutation,Color color,Degree degree,Priority priority)439 inline OutputIterator sloan_ordering(Graph& G, OutputIterator permutation,
440 Color color, Degree degree, Priority priority)
441 {
442 return sloan_ordering(
443 G, permutation, color, degree, priority, WEIGHT1, WEIGHT2);
444 }
445
446 } // namespace boost
447
448 #endif // BOOST_GRAPH_SLOAN_HPP
449