depth_first_search.hpp 15 KB

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