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