strong_components.hpp 13 KB

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