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