strong_components.hpp 13 KB

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