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