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