Chris@16
|
1 //
|
Chris@16
|
2 //=======================================================================
|
Chris@16
|
3 // Copyright 1997, 1998, 1999, 2000 University of Notre Dame.
|
Chris@16
|
4 // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek
|
Chris@16
|
5 //
|
Chris@16
|
6 // Distributed under the Boost Software License, Version 1.0. (See
|
Chris@16
|
7 // accompanying file LICENSE_1_0.txt or copy at
|
Chris@16
|
8 // http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
9 //=======================================================================
|
Chris@16
|
10 //
|
Chris@16
|
11
|
Chris@16
|
12 #ifndef BOOST_GRAPH_STRONG_COMPONENTS_HPP
|
Chris@16
|
13 #define BOOST_GRAPH_STRONG_COMPONENTS_HPP
|
Chris@16
|
14
|
Chris@16
|
15 #include <stack>
|
Chris@16
|
16 #include <boost/config.hpp>
|
Chris@16
|
17 #include <boost/graph/depth_first_search.hpp>
|
Chris@16
|
18 #include <boost/type_traits/conversion_traits.hpp>
|
Chris@16
|
19 #include <boost/static_assert.hpp>
|
Chris@16
|
20 #include <boost/graph/overloading.hpp>
|
Chris@16
|
21 #include <boost/concept/assert.hpp>
|
Chris@16
|
22
|
Chris@16
|
23 namespace boost {
|
Chris@16
|
24
|
Chris@16
|
25 //==========================================================================
|
Chris@16
|
26 // This is Tarjan's algorithm for strongly connected components
|
Chris@16
|
27 // from his paper "Depth first search and linear graph algorithms".
|
Chris@16
|
28 // It calculates the components in a single application of DFS.
|
Chris@16
|
29 // We implement the algorithm as a dfs-visitor.
|
Chris@16
|
30
|
Chris@16
|
31 namespace detail {
|
Chris@16
|
32
|
Chris@16
|
33 template <typename ComponentMap, typename RootMap, typename DiscoverTime,
|
Chris@16
|
34 typename Stack>
|
Chris@16
|
35 class tarjan_scc_visitor : public dfs_visitor<>
|
Chris@16
|
36 {
|
Chris@16
|
37 typedef typename property_traits<ComponentMap>::value_type comp_type;
|
Chris@16
|
38 typedef typename property_traits<DiscoverTime>::value_type time_type;
|
Chris@16
|
39 public:
|
Chris@16
|
40 tarjan_scc_visitor(ComponentMap comp_map, RootMap r, DiscoverTime d,
|
Chris@16
|
41 comp_type& c_, Stack& s_)
|
Chris@16
|
42 : c(c_), comp(comp_map), root(r), discover_time(d),
|
Chris@16
|
43 dfs_time(time_type()), s(s_) { }
|
Chris@16
|
44
|
Chris@16
|
45 template <typename Graph>
|
Chris@16
|
46 void discover_vertex(typename graph_traits<Graph>::vertex_descriptor v,
|
Chris@16
|
47 const Graph&) {
|
Chris@16
|
48 put(root, v, v);
|
Chris@16
|
49 put(comp, v, (std::numeric_limits<comp_type>::max)());
|
Chris@16
|
50 put(discover_time, v, dfs_time++);
|
Chris@16
|
51 s.push(v);
|
Chris@16
|
52 }
|
Chris@16
|
53 template <typename Graph>
|
Chris@16
|
54 void finish_vertex(typename graph_traits<Graph>::vertex_descriptor v,
|
Chris@16
|
55 const Graph& g) {
|
Chris@16
|
56 typename graph_traits<Graph>::vertex_descriptor w;
|
Chris@16
|
57 typename graph_traits<Graph>::out_edge_iterator ei, ei_end;
|
Chris@16
|
58 for (boost::tie(ei, ei_end) = out_edges(v, g); ei != ei_end; ++ei) {
|
Chris@16
|
59 w = target(*ei, g);
|
Chris@16
|
60 if (get(comp, w) == (std::numeric_limits<comp_type>::max)())
|
Chris@16
|
61 put(root, v, this->min_discover_time(get(root,v), get(root,w)));
|
Chris@16
|
62 }
|
Chris@16
|
63 if (get(root, v) == v) {
|
Chris@16
|
64 do {
|
Chris@16
|
65 w = s.top(); s.pop();
|
Chris@16
|
66 put(comp, w, c);
|
Chris@16
|
67 } while (w != v);
|
Chris@16
|
68 ++c;
|
Chris@16
|
69 }
|
Chris@16
|
70 }
|
Chris@16
|
71 private:
|
Chris@16
|
72 template <typename Vertex>
|
Chris@16
|
73 Vertex min_discover_time(Vertex u, Vertex v) {
|
Chris@16
|
74 return get(discover_time, u) < get(discover_time,v) ? u : v;
|
Chris@16
|
75 }
|
Chris@16
|
76
|
Chris@16
|
77 comp_type& c;
|
Chris@16
|
78 ComponentMap comp;
|
Chris@16
|
79 RootMap root;
|
Chris@16
|
80 DiscoverTime discover_time;
|
Chris@16
|
81 time_type dfs_time;
|
Chris@16
|
82 Stack& s;
|
Chris@16
|
83 };
|
Chris@16
|
84
|
Chris@16
|
85 template <class Graph, class ComponentMap, class RootMap,
|
Chris@16
|
86 class DiscoverTime, class P, class T, class R>
|
Chris@16
|
87 typename property_traits<ComponentMap>::value_type
|
Chris@16
|
88 strong_components_impl
|
Chris@16
|
89 (const Graph& g, // Input
|
Chris@16
|
90 ComponentMap comp, // Output
|
Chris@16
|
91 // Internal record keeping
|
Chris@16
|
92 RootMap root,
|
Chris@16
|
93 DiscoverTime discover_time,
|
Chris@16
|
94 const bgl_named_params<P, T, R>& params)
|
Chris@16
|
95 {
|
Chris@16
|
96 typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
|
Chris@16
|
97 BOOST_CONCEPT_ASSERT(( ReadWritePropertyMapConcept<ComponentMap, Vertex> ));
|
Chris@16
|
98 BOOST_CONCEPT_ASSERT(( ReadWritePropertyMapConcept<RootMap, Vertex> ));
|
Chris@16
|
99 typedef typename property_traits<RootMap>::value_type RootV;
|
Chris@16
|
100 BOOST_CONCEPT_ASSERT(( ConvertibleConcept<RootV, Vertex> ));
|
Chris@16
|
101 BOOST_CONCEPT_ASSERT(( ReadWritePropertyMapConcept<DiscoverTime, Vertex> ));
|
Chris@16
|
102
|
Chris@16
|
103 typename property_traits<ComponentMap>::value_type total = 0;
|
Chris@16
|
104
|
Chris@16
|
105 std::stack<Vertex> s;
|
Chris@16
|
106 detail::tarjan_scc_visitor<ComponentMap, RootMap, DiscoverTime,
|
Chris@16
|
107 std::stack<Vertex> >
|
Chris@16
|
108 vis(comp, root, discover_time, total, s);
|
Chris@16
|
109 depth_first_search(g, params.visitor(vis));
|
Chris@16
|
110 return total;
|
Chris@16
|
111 }
|
Chris@16
|
112
|
Chris@16
|
113 //-------------------------------------------------------------------------
|
Chris@16
|
114 // The dispatch functions handle the defaults for the rank and discover
|
Chris@16
|
115 // time property maps.
|
Chris@16
|
116 // dispatch with class specialization to avoid VC++ bug
|
Chris@16
|
117
|
Chris@16
|
118 template <class DiscoverTimeMap>
|
Chris@16
|
119 struct strong_comp_dispatch2 {
|
Chris@16
|
120 template <class Graph, class ComponentMap, class RootMap, class P, class T, class R>
|
Chris@16
|
121 inline static typename property_traits<ComponentMap>::value_type
|
Chris@16
|
122 apply(const Graph& g,
|
Chris@16
|
123 ComponentMap comp,
|
Chris@16
|
124 RootMap r_map,
|
Chris@16
|
125 const bgl_named_params<P, T, R>& params,
|
Chris@16
|
126 DiscoverTimeMap time_map)
|
Chris@16
|
127 {
|
Chris@16
|
128 return strong_components_impl(g, comp, r_map, time_map, params);
|
Chris@16
|
129 }
|
Chris@16
|
130 };
|
Chris@16
|
131
|
Chris@16
|
132
|
Chris@16
|
133 template <>
|
Chris@16
|
134 struct strong_comp_dispatch2<param_not_found> {
|
Chris@16
|
135 template <class Graph, class ComponentMap, class RootMap,
|
Chris@16
|
136 class P, class T, class R>
|
Chris@16
|
137 inline static typename property_traits<ComponentMap>::value_type
|
Chris@16
|
138 apply(const Graph& g,
|
Chris@16
|
139 ComponentMap comp,
|
Chris@16
|
140 RootMap r_map,
|
Chris@16
|
141 const bgl_named_params<P, T, R>& params,
|
Chris@16
|
142 param_not_found)
|
Chris@16
|
143 {
|
Chris@16
|
144 typedef typename graph_traits<Graph>::vertices_size_type size_type;
|
Chris@16
|
145 size_type n = num_vertices(g) > 0 ? num_vertices(g) : 1;
|
Chris@16
|
146 std::vector<size_type> time_vec(n);
|
Chris@16
|
147 return strong_components_impl
|
Chris@16
|
148 (g, comp, r_map,
|
Chris@16
|
149 make_iterator_property_map(time_vec.begin(), choose_const_pmap
|
Chris@16
|
150 (get_param(params, vertex_index),
|
Chris@16
|
151 g, vertex_index), time_vec[0]),
|
Chris@16
|
152 params);
|
Chris@16
|
153 }
|
Chris@16
|
154 };
|
Chris@16
|
155
|
Chris@16
|
156 template <class Graph, class ComponentMap, class RootMap,
|
Chris@16
|
157 class P, class T, class R, class DiscoverTimeMap>
|
Chris@16
|
158 inline typename property_traits<ComponentMap>::value_type
|
Chris@16
|
159 scc_helper2(const Graph& g,
|
Chris@16
|
160 ComponentMap comp,
|
Chris@16
|
161 RootMap r_map,
|
Chris@16
|
162 const bgl_named_params<P, T, R>& params,
|
Chris@16
|
163 DiscoverTimeMap time_map)
|
Chris@16
|
164 {
|
Chris@16
|
165 return strong_comp_dispatch2<DiscoverTimeMap>::apply(g, comp, r_map, params, time_map);
|
Chris@16
|
166 }
|
Chris@16
|
167
|
Chris@16
|
168 template <class RootMap>
|
Chris@16
|
169 struct strong_comp_dispatch1 {
|
Chris@16
|
170
|
Chris@16
|
171 template <class Graph, class ComponentMap, class P, class T, class R>
|
Chris@16
|
172 inline static typename property_traits<ComponentMap>::value_type
|
Chris@16
|
173 apply(const Graph& g,
|
Chris@16
|
174 ComponentMap comp,
|
Chris@16
|
175 const bgl_named_params<P, T, R>& params,
|
Chris@16
|
176 RootMap r_map)
|
Chris@16
|
177 {
|
Chris@16
|
178 return scc_helper2(g, comp, r_map, params, get_param(params, vertex_discover_time));
|
Chris@16
|
179 }
|
Chris@16
|
180 };
|
Chris@16
|
181 template <>
|
Chris@16
|
182 struct strong_comp_dispatch1<param_not_found> {
|
Chris@16
|
183
|
Chris@16
|
184 template <class Graph, class ComponentMap,
|
Chris@16
|
185 class P, class T, class R>
|
Chris@16
|
186 inline static typename property_traits<ComponentMap>::value_type
|
Chris@16
|
187 apply(const Graph& g,
|
Chris@16
|
188 ComponentMap comp,
|
Chris@16
|
189 const bgl_named_params<P, T, R>& params,
|
Chris@16
|
190 param_not_found)
|
Chris@16
|
191 {
|
Chris@16
|
192 typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
|
Chris@16
|
193 typename std::vector<Vertex>::size_type
|
Chris@16
|
194 n = num_vertices(g) > 0 ? num_vertices(g) : 1;
|
Chris@16
|
195 std::vector<Vertex> root_vec(n);
|
Chris@16
|
196 return scc_helper2
|
Chris@16
|
197 (g, comp,
|
Chris@16
|
198 make_iterator_property_map(root_vec.begin(), choose_const_pmap
|
Chris@16
|
199 (get_param(params, vertex_index),
|
Chris@16
|
200 g, vertex_index), root_vec[0]),
|
Chris@16
|
201 params,
|
Chris@16
|
202 get_param(params, vertex_discover_time));
|
Chris@16
|
203 }
|
Chris@16
|
204 };
|
Chris@16
|
205
|
Chris@16
|
206 template <class Graph, class ComponentMap, class RootMap,
|
Chris@16
|
207 class P, class T, class R>
|
Chris@16
|
208 inline typename property_traits<ComponentMap>::value_type
|
Chris@16
|
209 scc_helper1(const Graph& g,
|
Chris@16
|
210 ComponentMap comp,
|
Chris@16
|
211 const bgl_named_params<P, T, R>& params,
|
Chris@16
|
212 RootMap r_map)
|
Chris@16
|
213 {
|
Chris@16
|
214 return detail::strong_comp_dispatch1<RootMap>::apply(g, comp, params,
|
Chris@16
|
215 r_map);
|
Chris@16
|
216 }
|
Chris@16
|
217
|
Chris@16
|
218 } // namespace detail
|
Chris@16
|
219
|
Chris@16
|
220 template <class Graph, class ComponentMap,
|
Chris@16
|
221 class P, class T, class R>
|
Chris@16
|
222 inline typename property_traits<ComponentMap>::value_type
|
Chris@16
|
223 strong_components(const Graph& g, ComponentMap comp,
|
Chris@16
|
224 const bgl_named_params<P, T, R>& params
|
Chris@16
|
225 BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph, vertex_list_graph_tag))
|
Chris@16
|
226 {
|
Chris@16
|
227 typedef typename graph_traits<Graph>::directed_category DirCat;
|
Chris@16
|
228 BOOST_STATIC_ASSERT((is_convertible<DirCat*, directed_tag*>::value == true));
|
Chris@16
|
229 return detail::scc_helper1(g, comp, params,
|
Chris@16
|
230 get_param(params, vertex_root_t()));
|
Chris@16
|
231 }
|
Chris@16
|
232
|
Chris@16
|
233 template <class Graph, class ComponentMap>
|
Chris@16
|
234 inline typename property_traits<ComponentMap>::value_type
|
Chris@16
|
235 strong_components(const Graph& g, ComponentMap comp
|
Chris@16
|
236 BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph, vertex_list_graph_tag))
|
Chris@16
|
237 {
|
Chris@16
|
238 typedef typename graph_traits<Graph>::directed_category DirCat;
|
Chris@16
|
239 BOOST_STATIC_ASSERT((is_convertible<DirCat*, directed_tag*>::value == true));
|
Chris@16
|
240 bgl_named_params<int, int> params(0);
|
Chris@16
|
241 return strong_components(g, comp, params);
|
Chris@16
|
242 }
|
Chris@16
|
243
|
Chris@16
|
244 template <typename Graph, typename ComponentMap, typename ComponentLists>
|
Chris@16
|
245 void build_component_lists
|
Chris@16
|
246 (const Graph& g,
|
Chris@16
|
247 typename graph_traits<Graph>::vertices_size_type num_scc,
|
Chris@16
|
248 ComponentMap component_number,
|
Chris@16
|
249 ComponentLists& components)
|
Chris@16
|
250 {
|
Chris@16
|
251 components.resize(num_scc);
|
Chris@16
|
252 typename graph_traits<Graph>::vertex_iterator vi, vi_end;
|
Chris@16
|
253 for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)
|
Chris@16
|
254 components[component_number[*vi]].push_back(*vi);
|
Chris@16
|
255 }
|
Chris@16
|
256
|
Chris@16
|
257
|
Chris@16
|
258 } // namespace boost
|
Chris@16
|
259
|
Chris@16
|
260 #include <queue>
|
Chris@16
|
261 #include <vector>
|
Chris@16
|
262 #include <boost/graph/transpose_graph.hpp>
|
Chris@16
|
263 #include <boost/pending/indirect_cmp.hpp>
|
Chris@16
|
264 #include <boost/graph/connected_components.hpp> // for components_recorder
|
Chris@16
|
265
|
Chris@16
|
266 namespace boost {
|
Chris@16
|
267
|
Chris@16
|
268 //==========================================================================
|
Chris@16
|
269 // This is the version of strongly connected components from
|
Chris@16
|
270 // "Intro. to Algorithms" by Cormen, Leiserson, Rivest, which was
|
Chris@16
|
271 // adapted from "Data Structure and Algorithms" by Aho, Hopcroft,
|
Chris@16
|
272 // and Ullman, who credit the algorithm to S.R. Kosaraju and M. Sharir.
|
Chris@16
|
273 // The algorithm is based on computing DFS forests the graph
|
Chris@16
|
274 // and its transpose.
|
Chris@16
|
275
|
Chris@16
|
276 // This algorithm is slower than Tarjan's by a constant factor, uses
|
Chris@16
|
277 // more memory, and puts more requirements on the graph type.
|
Chris@16
|
278
|
Chris@16
|
279 template <class Graph, class DFSVisitor, class ComponentsMap,
|
Chris@16
|
280 class DiscoverTime, class FinishTime,
|
Chris@16
|
281 class ColorMap>
|
Chris@16
|
282 typename property_traits<ComponentsMap>::value_type
|
Chris@16
|
283 kosaraju_strong_components(Graph& G, ComponentsMap c,
|
Chris@16
|
284 FinishTime finish_time, ColorMap color)
|
Chris@16
|
285 {
|
Chris@16
|
286 BOOST_CONCEPT_ASSERT(( MutableGraphConcept<Graph> ));
|
Chris@16
|
287 // ...
|
Chris@16
|
288
|
Chris@16
|
289 typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
|
Chris@16
|
290 typedef typename property_traits<ColorMap>::value_type ColorValue;
|
Chris@16
|
291 typedef color_traits<ColorValue> Color;
|
Chris@16
|
292 typename property_traits<FinishTime>::value_type time = 0;
|
Chris@16
|
293 depth_first_search
|
Chris@16
|
294 (G, make_dfs_visitor(stamp_times(finish_time, time, on_finish_vertex())),
|
Chris@16
|
295 color);
|
Chris@16
|
296
|
Chris@16
|
297 Graph G_T(num_vertices(G));
|
Chris@16
|
298 transpose_graph(G, G_T);
|
Chris@16
|
299
|
Chris@16
|
300 typedef typename property_traits<ComponentsMap>::value_type count_type;
|
Chris@16
|
301
|
Chris@16
|
302 count_type c_count(0);
|
Chris@16
|
303 detail::components_recorder<ComponentsMap>
|
Chris@16
|
304 vis(c, c_count);
|
Chris@16
|
305
|
Chris@16
|
306 // initialize G_T
|
Chris@16
|
307 typename graph_traits<Graph>::vertex_iterator ui, ui_end;
|
Chris@16
|
308 for (boost::tie(ui, ui_end) = vertices(G_T); ui != ui_end; ++ui)
|
Chris@16
|
309 put(color, *ui, Color::white());
|
Chris@16
|
310
|
Chris@16
|
311 typedef typename property_traits<FinishTime>::value_type D;
|
Chris@16
|
312 typedef indirect_cmp< FinishTime, std::less<D> > Compare;
|
Chris@16
|
313
|
Chris@16
|
314 Compare fl(finish_time);
|
Chris@16
|
315 std::priority_queue<Vertex, std::vector<Vertex>, Compare > Q(fl);
|
Chris@16
|
316
|
Chris@16
|
317 typename graph_traits<Graph>::vertex_iterator i, j, iend, jend;
|
Chris@16
|
318 boost::tie(i, iend) = vertices(G_T);
|
Chris@16
|
319 boost::tie(j, jend) = vertices(G);
|
Chris@16
|
320 for ( ; i != iend; ++i, ++j) {
|
Chris@16
|
321 put(finish_time, *i, get(finish_time, *j));
|
Chris@16
|
322 Q.push(*i);
|
Chris@16
|
323 }
|
Chris@16
|
324
|
Chris@16
|
325 while ( !Q.empty() ) {
|
Chris@16
|
326 Vertex u = Q.top();
|
Chris@16
|
327 Q.pop();
|
Chris@16
|
328 if (get(color, u) == Color::white()) {
|
Chris@16
|
329 depth_first_visit(G_T, u, vis, color);
|
Chris@16
|
330 ++c_count;
|
Chris@16
|
331 }
|
Chris@16
|
332 }
|
Chris@16
|
333 return c_count;
|
Chris@16
|
334 }
|
Chris@16
|
335
|
Chris@16
|
336 } // namespace boost
|
Chris@16
|
337
|
Chris@16
|
338 #ifdef BOOST_GRAPH_USE_MPI
|
Chris@16
|
339 # include <boost/graph/distributed/strong_components.hpp>
|
Chris@16
|
340 #endif
|
Chris@16
|
341
|
Chris@16
|
342 #endif // BOOST_GRAPH_STRONG_COMPONENTS_HPP
|