depth_first_search.hpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. //=======================================================================
  2. // Copyright 1997, 1998, 1999, 2000 University of Notre Dame.
  3. // Copyright 2003 Bruce Barr
  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. // Nonrecursive implementation of depth_first_visit_impl submitted by
  11. // Bruce Barr, schmoost <at> yahoo.com, May/June 2003.
  12. #ifndef BOOST_GRAPH_RECURSIVE_DFS_HPP
  13. #define BOOST_GRAPH_RECURSIVE_DFS_HPP
  14. #include <boost/config.hpp>
  15. #include <boost/graph/graph_traits.hpp>
  16. #include <boost/graph/graph_concepts.hpp>
  17. #include <boost/graph/properties.hpp>
  18. #include <boost/graph/visitors.hpp>
  19. #include <boost/graph/named_function_params.hpp>
  20. #include <boost/ref.hpp>
  21. #include <boost/implicit_cast.hpp>
  22. #include <boost/optional.hpp>
  23. #include <boost/parameter.hpp>
  24. #include <boost/concept/assert.hpp>
  25. #include <boost/tti/has_member_function.hpp>
  26. #include <vector>
  27. #include <utility>
  28. namespace boost {
  29. template <class Visitor, class Graph>
  30. class DFSVisitorConcept {
  31. public:
  32. void constraints() {
  33. BOOST_CONCEPT_ASSERT(( CopyConstructibleConcept<Visitor> ));
  34. vis.initialize_vertex(u, g);
  35. vis.start_vertex(u, g);
  36. vis.discover_vertex(u, g);
  37. vis.examine_edge(e, g);
  38. vis.tree_edge(e, g);
  39. vis.back_edge(e, g);
  40. vis.forward_or_cross_edge(e, g);
  41. // vis.finish_edge(e, g); // Optional for user
  42. vis.finish_vertex(u, g);
  43. }
  44. private:
  45. Visitor vis;
  46. Graph g;
  47. typename graph_traits<Graph>::vertex_descriptor u;
  48. typename graph_traits<Graph>::edge_descriptor e;
  49. };
  50. namespace detail {
  51. struct nontruth2 {
  52. template<class T, class T2>
  53. bool operator()(const T&, const T2&) const { return false; }
  54. };
  55. BOOST_TTI_HAS_MEMBER_FUNCTION(finish_edge)
  56. template <bool IsCallable> struct do_call_finish_edge {
  57. template <typename E, typename G, typename Vis>
  58. static void call_finish_edge(Vis& vis, E e, const G& g) {
  59. vis.finish_edge(e, g);
  60. }
  61. };
  62. template <> struct do_call_finish_edge<false> {
  63. template <typename E, typename G, typename Vis>
  64. static void call_finish_edge(Vis&, E, const G&) {}
  65. };
  66. template <typename E, typename G, typename Vis>
  67. void call_finish_edge(Vis& vis, E e, const G& g) { // Only call if method exists
  68. #if ((defined(__GNUC__) && (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9))) || \
  69. defined(__clang__) || \
  70. (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1200)))
  71. do_call_finish_edge<
  72. has_member_function_finish_edge<Vis, void,
  73. boost::mpl::vector<E, const G&> >::value>::call_finish_edge(vis, e, g);
  74. #else
  75. do_call_finish_edge<has_member_function_finish_edge<Vis, void>::value>::call_finish_edge(vis, e, g);
  76. #endif
  77. }
  78. // Define BOOST_RECURSIVE_DFS to use older, recursive version.
  79. // It is retained for a while in order to perform performance
  80. // comparison.
  81. #ifndef BOOST_RECURSIVE_DFS
  82. // If the vertex u and the iterators ei and ei_end are thought of as the
  83. // context of the algorithm, each push and pop from the stack could
  84. // be thought of as a context shift.
  85. // Each pass through "while (ei != ei_end)" may refer to the out-edges of
  86. // an entirely different vertex, because the context of the algorithm
  87. // shifts every time a white adjacent vertex is discovered.
  88. // The corresponding context shift back from the adjacent vertex occurs
  89. // after all of its out-edges have been examined.
  90. //
  91. // See http://lists.boost.org/MailArchives/boost/msg48752.php for FAQ.
  92. template <class IncidenceGraph, class DFSVisitor, class ColorMap,
  93. class TerminatorFunc>
  94. void depth_first_visit_impl
  95. (const IncidenceGraph& g,
  96. typename graph_traits<IncidenceGraph>::vertex_descriptor u,
  97. DFSVisitor& vis,
  98. ColorMap color, TerminatorFunc func = TerminatorFunc())
  99. {
  100. BOOST_CONCEPT_ASSERT(( IncidenceGraphConcept<IncidenceGraph> ));
  101. BOOST_CONCEPT_ASSERT(( DFSVisitorConcept<DFSVisitor, IncidenceGraph> ));
  102. typedef typename graph_traits<IncidenceGraph>::vertex_descriptor Vertex;
  103. typedef typename graph_traits<IncidenceGraph>::edge_descriptor Edge;
  104. BOOST_CONCEPT_ASSERT(( ReadWritePropertyMapConcept<ColorMap, Vertex> ));
  105. typedef typename property_traits<ColorMap>::value_type ColorValue;
  106. BOOST_CONCEPT_ASSERT(( ColorValueConcept<ColorValue> ));
  107. typedef color_traits<ColorValue> Color;
  108. typedef typename graph_traits<IncidenceGraph>::out_edge_iterator Iter;
  109. typedef std::pair<Vertex, std::pair<boost::optional<Edge>, std::pair<Iter, Iter> > > VertexInfo;
  110. boost::optional<Edge> src_e;
  111. Iter ei, ei_end;
  112. std::vector<VertexInfo> stack;
  113. // Possible optimization for vector
  114. //stack.reserve(num_vertices(g));
  115. put(color, u, Color::gray());
  116. vis.discover_vertex(u, g);
  117. boost::tie(ei, ei_end) = out_edges(u, g);
  118. if (func(u, g)) {
  119. // If this vertex terminates the search, we push empty range
  120. stack.push_back(std::make_pair(u, std::make_pair(boost::optional<Edge>(), std::make_pair(ei_end, ei_end))));
  121. } else {
  122. stack.push_back(std::make_pair(u, std::make_pair(boost::optional<Edge>(), std::make_pair(ei, ei_end))));
  123. }
  124. while (!stack.empty()) {
  125. VertexInfo& back = stack.back();
  126. u = back.first;
  127. src_e = back.second.first;
  128. boost::tie(ei, ei_end) = back.second.second;
  129. stack.pop_back();
  130. // finish_edge has to be called here, not after the
  131. // loop. Think of the pop as the return from a recursive call.
  132. if (src_e) {
  133. call_finish_edge(vis, src_e.get(), g);
  134. }
  135. while (ei != ei_end) {
  136. Vertex v = target(*ei, g);
  137. vis.examine_edge(*ei, g);
  138. ColorValue v_color = get(color, v);
  139. if (v_color == Color::white()) {
  140. vis.tree_edge(*ei, g);
  141. src_e = *ei;
  142. stack.push_back(std::make_pair(u, std::make_pair(src_e, std::make_pair(++ei, ei_end))));
  143. u = v;
  144. put(color, u, Color::gray());
  145. vis.discover_vertex(u, g);
  146. boost::tie(ei, ei_end) = out_edges(u, g);
  147. if (func(u, g)) {
  148. ei = ei_end;
  149. }
  150. } else {
  151. if (v_color == Color::gray()) {
  152. vis.back_edge(*ei, g);
  153. } else {
  154. vis.forward_or_cross_edge(*ei, g);
  155. }
  156. call_finish_edge(vis, *ei, g);
  157. ++ei;
  158. }
  159. }
  160. put(color, u, Color::black());
  161. vis.finish_vertex(u, g);
  162. }
  163. }
  164. #else // BOOST_RECURSIVE_DFS is defined
  165. template <class IncidenceGraph, class DFSVisitor, class ColorMap,
  166. class TerminatorFunc>
  167. void depth_first_visit_impl
  168. (const IncidenceGraph& g,
  169. typename graph_traits<IncidenceGraph>::vertex_descriptor u,
  170. DFSVisitor& vis, // pass-by-reference here, important!
  171. ColorMap color, TerminatorFunc func)
  172. {
  173. BOOST_CONCEPT_ASSERT(( IncidenceGraphConcept<IncidenceGraph> ));
  174. BOOST_CONCEPT_ASSERT(( DFSVisitorConcept<DFSVisitor, IncidenceGraph> ));
  175. typedef typename graph_traits<IncidenceGraph>::vertex_descriptor Vertex;
  176. BOOST_CONCEPT_ASSERT(( ReadWritePropertyMapConcept<ColorMap, Vertex> ));
  177. typedef typename property_traits<ColorMap>::value_type ColorValue;
  178. BOOST_CONCEPT_ASSERT(( ColorValueConcept<ColorValue> ));
  179. typedef color_traits<ColorValue> Color;
  180. typename graph_traits<IncidenceGraph>::out_edge_iterator ei, ei_end;
  181. put(color, u, Color::gray()); vis.discover_vertex(u, g);
  182. if (!func(u, g))
  183. for (boost::tie(ei, ei_end) = out_edges(u, g); ei != ei_end; ++ei) {
  184. Vertex v = target(*ei, g); vis.examine_edge(*ei, g);
  185. ColorValue v_color = get(color, v);
  186. if (v_color == Color::white()) { vis.tree_edge(*ei, g);
  187. depth_first_visit_impl(g, v, vis, color, func);
  188. } else if (v_color == Color::gray()) vis.back_edge(*ei, g);
  189. else vis.forward_or_cross_edge(*ei, g);
  190. call_finish_edge(vis, *ei, g);
  191. }
  192. put(color, u, Color::black()); vis.finish_vertex(u, g);
  193. }
  194. #endif
  195. } // namespace detail
  196. template <class VertexListGraph, class DFSVisitor, class ColorMap>
  197. void
  198. depth_first_search(const VertexListGraph& g, DFSVisitor vis, ColorMap color,
  199. typename graph_traits<VertexListGraph>::vertex_descriptor start_vertex)
  200. {
  201. typedef typename graph_traits<VertexListGraph>::vertex_descriptor Vertex;
  202. BOOST_CONCEPT_ASSERT(( DFSVisitorConcept<DFSVisitor, VertexListGraph> ));
  203. typedef typename property_traits<ColorMap>::value_type ColorValue;
  204. typedef color_traits<ColorValue> Color;
  205. typename graph_traits<VertexListGraph>::vertex_iterator ui, ui_end;
  206. for (boost::tie(ui, ui_end) = vertices(g); ui != ui_end; ++ui) {
  207. Vertex u = implicit_cast<Vertex>(*ui);
  208. put(color, u, Color::white()); vis.initialize_vertex(u, g);
  209. }
  210. if (start_vertex != detail::get_default_starting_vertex(g)){ vis.start_vertex(start_vertex, g);
  211. detail::depth_first_visit_impl(g, start_vertex, vis, color,
  212. detail::nontruth2());
  213. }
  214. for (boost::tie(ui, ui_end) = vertices(g); ui != ui_end; ++ui) {
  215. Vertex u = implicit_cast<Vertex>(*ui);
  216. ColorValue u_color = get(color, u);
  217. if (u_color == Color::white()) { vis.start_vertex(u, g);
  218. detail::depth_first_visit_impl(g, u, vis, color, detail::nontruth2());
  219. }
  220. }
  221. }
  222. template <class VertexListGraph, class DFSVisitor, class ColorMap>
  223. void
  224. depth_first_search(const VertexListGraph& g, DFSVisitor vis, ColorMap color)
  225. {
  226. typedef typename boost::graph_traits<VertexListGraph>::vertex_iterator vi;
  227. std::pair<vi, vi> verts = vertices(g);
  228. if (verts.first == verts.second)
  229. return;
  230. depth_first_search(g, vis, color, detail::get_default_starting_vertex(g));
  231. }
  232. template <class Visitors = null_visitor>
  233. class dfs_visitor {
  234. public:
  235. dfs_visitor() { }
  236. dfs_visitor(Visitors vis) : m_vis(vis) { }
  237. template <class Vertex, class Graph>
  238. void initialize_vertex(Vertex u, const Graph& g) {
  239. invoke_visitors(m_vis, u, g, ::boost::on_initialize_vertex());
  240. }
  241. template <class Vertex, class Graph>
  242. void start_vertex(Vertex u, const Graph& g) {
  243. invoke_visitors(m_vis, u, g, ::boost::on_start_vertex());
  244. }
  245. template <class Vertex, class Graph>
  246. void discover_vertex(Vertex u, const Graph& g) {
  247. invoke_visitors(m_vis, u, g, ::boost::on_discover_vertex());
  248. }
  249. template <class Edge, class Graph>
  250. void examine_edge(Edge u, const Graph& g) {
  251. invoke_visitors(m_vis, u, g, ::boost::on_examine_edge());
  252. }
  253. template <class Edge, class Graph>
  254. void tree_edge(Edge u, const Graph& g) {
  255. invoke_visitors(m_vis, u, g, ::boost::on_tree_edge());
  256. }
  257. template <class Edge, class Graph>
  258. void back_edge(Edge u, const Graph& g) {
  259. invoke_visitors(m_vis, u, g, ::boost::on_back_edge());
  260. }
  261. template <class Edge, class Graph>
  262. void forward_or_cross_edge(Edge u, const Graph& g) {
  263. invoke_visitors(m_vis, u, g, ::boost::on_forward_or_cross_edge());
  264. }
  265. template <class Edge, class Graph>
  266. void finish_edge(Edge u, const Graph& g) {
  267. invoke_visitors(m_vis, u, g, ::boost::on_finish_edge());
  268. }
  269. template <class Vertex, class Graph>
  270. void finish_vertex(Vertex u, const Graph& g) {
  271. invoke_visitors(m_vis, u, g, ::boost::on_finish_vertex());
  272. }
  273. BOOST_GRAPH_EVENT_STUB(on_initialize_vertex,dfs)
  274. BOOST_GRAPH_EVENT_STUB(on_start_vertex,dfs)
  275. BOOST_GRAPH_EVENT_STUB(on_discover_vertex,dfs)
  276. BOOST_GRAPH_EVENT_STUB(on_examine_edge,dfs)
  277. BOOST_GRAPH_EVENT_STUB(on_tree_edge,dfs)
  278. BOOST_GRAPH_EVENT_STUB(on_back_edge,dfs)
  279. BOOST_GRAPH_EVENT_STUB(on_forward_or_cross_edge,dfs)
  280. BOOST_GRAPH_EVENT_STUB(on_finish_edge,dfs)
  281. BOOST_GRAPH_EVENT_STUB(on_finish_vertex,dfs)
  282. protected:
  283. Visitors m_vis;
  284. };
  285. template <class Visitors>
  286. dfs_visitor<Visitors>
  287. make_dfs_visitor(Visitors vis) {
  288. return dfs_visitor<Visitors>(vis);
  289. }
  290. typedef dfs_visitor<> default_dfs_visitor;
  291. // Boost.Parameter named parameter variant
  292. namespace graph {
  293. namespace detail {
  294. template <typename Graph>
  295. struct depth_first_search_impl {
  296. typedef void result_type;
  297. template <typename ArgPack>
  298. void operator()(const Graph& g, const ArgPack& arg_pack) const {
  299. using namespace boost::graph::keywords;
  300. boost::depth_first_search(g,
  301. arg_pack[_visitor | make_dfs_visitor(null_visitor())],
  302. boost::detail::make_color_map_from_arg_pack(g, arg_pack),
  303. arg_pack[_root_vertex || boost::detail::get_default_starting_vertex_t<Graph>(g)]);
  304. }
  305. };
  306. }
  307. BOOST_GRAPH_MAKE_FORWARDING_FUNCTION(depth_first_search, 1, 4)
  308. }
  309. BOOST_GRAPH_MAKE_OLD_STYLE_PARAMETER_FUNCTION(depth_first_search, 1)
  310. template <class IncidenceGraph, class DFSVisitor, class ColorMap>
  311. void depth_first_visit
  312. (const IncidenceGraph& g,
  313. typename graph_traits<IncidenceGraph>::vertex_descriptor u,
  314. DFSVisitor vis, ColorMap color)
  315. {
  316. vis.start_vertex(u, g);
  317. detail::depth_first_visit_impl(g, u, vis, color, detail::nontruth2());
  318. }
  319. template <class IncidenceGraph, class DFSVisitor, class ColorMap,
  320. class TerminatorFunc>
  321. void depth_first_visit
  322. (const IncidenceGraph& g,
  323. typename graph_traits<IncidenceGraph>::vertex_descriptor u,
  324. DFSVisitor vis, ColorMap color, TerminatorFunc func = TerminatorFunc())
  325. {
  326. vis.start_vertex(u, g);
  327. detail::depth_first_visit_impl(g, u, vis, color, func);
  328. }
  329. } // namespace boost
  330. #ifdef BOOST_GRAPH_USE_MPI
  331. # include <boost/graph/distributed/depth_first_search.hpp>
  332. #endif
  333. #endif