strong_components.hpp 13 KB

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