hawick_circuits.hpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. // Copyright Louis Dionne 2013
  2. // Use, modification and distribution is subject to the Boost Software
  3. // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy
  4. // at http://www.boost.org/LICENSE_1_0.txt)
  5. #ifndef BOOST_GRAPH_HAWICK_CIRCUITS_HPP
  6. #define BOOST_GRAPH_HAWICK_CIRCUITS_HPP
  7. #include <algorithm>
  8. #include <boost/assert.hpp>
  9. #include <boost/foreach.hpp>
  10. #include <boost/graph/graph_traits.hpp>
  11. #include <boost/graph/one_bit_color_map.hpp>
  12. #include <boost/graph/properties.hpp>
  13. #include <boost/move/utility.hpp>
  14. #include <boost/property_map/property_map.hpp>
  15. #include <boost/range/begin.hpp>
  16. #include <boost/range/end.hpp>
  17. #include <boost/range/iterator.hpp>
  18. #include <boost/tuple/tuple.hpp> // for boost::tie
  19. #include <boost/type_traits/remove_reference.hpp>
  20. #include <boost/utility/result_of.hpp>
  21. #include <set>
  22. #include <utility> // for std::pair
  23. #include <vector>
  24. namespace boost
  25. {
  26. namespace hawick_circuits_detail
  27. {
  28. //! @internal Functor returning all the vertices adjacent to a vertex.
  29. struct get_all_adjacent_vertices
  30. {
  31. template < typename Sig > struct result;
  32. template < typename This, typename Vertex, typename Graph >
  33. struct result< This(Vertex, Graph) >
  34. {
  35. private:
  36. typedef typename remove_reference< Graph >::type RawGraph;
  37. typedef graph_traits< RawGraph > Traits;
  38. typedef typename Traits::adjacency_iterator AdjacencyIterator;
  39. public:
  40. typedef std::pair< AdjacencyIterator, AdjacencyIterator > type;
  41. };
  42. template < typename Vertex, typename Graph >
  43. typename result< get_all_adjacent_vertices(
  44. BOOST_FWD_REF(Vertex), BOOST_FWD_REF(Graph)) >::type
  45. operator()(BOOST_FWD_REF(Vertex) v, BOOST_FWD_REF(Graph) g) const
  46. {
  47. return adjacent_vertices(
  48. boost::forward< Vertex >(v), boost::forward< Graph >(g));
  49. }
  50. };
  51. //! @internal Functor returning a set of the vertices adjacent to a vertex.
  52. struct get_unique_adjacent_vertices
  53. {
  54. template < typename Sig > struct result;
  55. template < typename This, typename Vertex, typename Graph >
  56. struct result< This(Vertex, Graph) >
  57. {
  58. typedef std::set< typename remove_reference< Vertex >::type > type;
  59. };
  60. template < typename Vertex, typename Graph >
  61. typename result< get_unique_adjacent_vertices(
  62. Vertex, Graph const&) >::type
  63. operator()(Vertex v, Graph const& g) const
  64. {
  65. typedef typename result< get_unique_adjacent_vertices(
  66. Vertex, Graph const&) >::type Set;
  67. return Set(
  68. adjacent_vertices(v, g).first, adjacent_vertices(v, g).second);
  69. }
  70. };
  71. //! @internal
  72. //! Return whether a container contains a given value.
  73. //! This is not meant as a general purpose membership testing function; it
  74. //! would have to be more clever about possible optimizations.
  75. template < typename Container, typename Value >
  76. bool contains(Container const& c, Value const& v)
  77. {
  78. return std::find(boost::begin(c), boost::end(c), v) != boost::end(c);
  79. }
  80. /*!
  81. * @internal
  82. * Algorithm finding all the cycles starting from a given vertex.
  83. *
  84. * The search is only done in the subgraph induced by the starting vertex
  85. * and the vertices with an index higher than the starting vertex.
  86. */
  87. template < typename Graph, typename Visitor, typename VertexIndexMap,
  88. typename Stack, typename ClosedMatrix, typename GetAdjacentVertices >
  89. struct hawick_circuits_from
  90. {
  91. private:
  92. typedef graph_traits< Graph > Traits;
  93. typedef typename Traits::vertex_descriptor Vertex;
  94. typedef typename Traits::edge_descriptor Edge;
  95. typedef typename Traits::vertices_size_type VerticesSize;
  96. typedef
  97. typename property_traits< VertexIndexMap >::value_type VertexIndex;
  98. typedef typename result_of< GetAdjacentVertices(
  99. Vertex, Graph const&) >::type AdjacentVertices;
  100. typedef typename range_iterator< AdjacentVertices const >::type
  101. AdjacencyIterator;
  102. // The one_bit_color_map starts all white, i.e. not blocked.
  103. // Since we make that assumption (I looked at the implementation, but
  104. // I can't find anything that documents this behavior), we're gonna
  105. // assert it in the constructor.
  106. typedef one_bit_color_map< VertexIndexMap > BlockedMap;
  107. typedef typename property_traits< BlockedMap >::value_type BlockedColor;
  108. static BlockedColor blocked_false_color()
  109. {
  110. return color_traits< BlockedColor >::white();
  111. }
  112. static BlockedColor blocked_true_color()
  113. {
  114. return color_traits< BlockedColor >::black();
  115. }
  116. // This is used by the constructor to secure the assumption
  117. // documented above.
  118. bool blocked_map_starts_all_unblocked() const
  119. {
  120. BOOST_FOREACH (Vertex v, vertices(graph_))
  121. if (is_blocked(v))
  122. return false;
  123. return true;
  124. }
  125. // This is only used in the constructor to make sure the optimization of
  126. // sharing data structures between iterations does not break the code.
  127. bool all_closed_rows_are_empty() const
  128. {
  129. BOOST_FOREACH (typename ClosedMatrix::reference row, closed_)
  130. if (!row.empty())
  131. return false;
  132. return true;
  133. }
  134. public:
  135. hawick_circuits_from(Graph const& graph, Visitor& visitor,
  136. VertexIndexMap const& vim, Stack& stack, ClosedMatrix& closed,
  137. VerticesSize n_vertices, unsigned int max_length)
  138. : graph_(graph)
  139. , visitor_(visitor)
  140. , vim_(vim)
  141. , stack_(stack)
  142. , closed_(closed)
  143. , blocked_(n_vertices, vim_)
  144. , max_length_(max_length)
  145. {
  146. BOOST_ASSERT(blocked_map_starts_all_unblocked());
  147. // Since sharing the data structures between iterations is
  148. // just an optimization, it must always be equivalent to
  149. // constructing new ones in this constructor.
  150. BOOST_ASSERT(stack_.empty());
  151. BOOST_ASSERT(closed_.size() == n_vertices);
  152. BOOST_ASSERT(all_closed_rows_are_empty());
  153. }
  154. private:
  155. //! @internal Return the index of a given vertex.
  156. VertexIndex index_of(Vertex v) const { return get(vim_, v); }
  157. //! @internal Return whether a vertex `v` is closed to a vertex `u`.
  158. bool is_closed_to(Vertex u, Vertex v) const
  159. {
  160. typedef typename ClosedMatrix::const_reference VertexList;
  161. VertexList closed_to_u = closed_[index_of(u)];
  162. return contains(closed_to_u, v);
  163. }
  164. //! @internal Close a vertex `v` to a vertex `u`.
  165. void close_to(Vertex u, Vertex v)
  166. {
  167. BOOST_ASSERT(!is_closed_to(u, v));
  168. closed_[index_of(u)].push_back(v);
  169. }
  170. //! @internal Return whether a given vertex is blocked.
  171. bool is_blocked(Vertex v) const
  172. {
  173. return get(blocked_, v) == blocked_true_color();
  174. }
  175. //! @internal Block a given vertex.
  176. void block(Vertex v) { put(blocked_, v, blocked_true_color()); }
  177. //! @internal Unblock a given vertex.
  178. void unblock(Vertex u)
  179. {
  180. typedef typename ClosedMatrix::reference VertexList;
  181. put(blocked_, u, blocked_false_color());
  182. VertexList closed_to_u = closed_[index_of(u)];
  183. while (!closed_to_u.empty())
  184. {
  185. Vertex const w = closed_to_u.back();
  186. closed_to_u.pop_back();
  187. if (is_blocked(w))
  188. unblock(w);
  189. }
  190. BOOST_ASSERT(closed_to_u.empty());
  191. }
  192. //! @internal Main procedure as described in the paper.
  193. bool circuit(Vertex start, Vertex v)
  194. {
  195. bool found_circuit = false;
  196. stack_.push_back(v);
  197. block(v);
  198. // Truncate the search if any circuits would exceed max_length_.
  199. bool const truncate_search =
  200. (max_length_ > 0 && stack_.size() >= max_length_);
  201. // Cache some values that are used more than once in the function.
  202. VertexIndex const index_of_start = index_of(start);
  203. AdjacentVertices const adj_vertices
  204. = GetAdjacentVertices()(v, graph_);
  205. AdjacencyIterator const w_end = boost::end(adj_vertices);
  206. for (AdjacencyIterator w_it = boost::begin(adj_vertices);
  207. w_it != w_end; ++w_it)
  208. {
  209. Vertex const w = *w_it;
  210. // Since we're only looking in the subgraph induced by `start`
  211. // and the vertices with an index higher than `start`, we skip
  212. // any vertex that does not satisfy that.
  213. if (index_of(w) < index_of_start)
  214. continue;
  215. // If the last vertex is equal to `start`, we have a circuit.
  216. else if (w == start)
  217. {
  218. // const_cast to ensure the visitor does not modify the
  219. // stack
  220. visitor_.cycle(const_cast< Stack const& >(stack_), graph_);
  221. found_circuit = true;
  222. }
  223. // If required, truncate the search before the subsequent
  224. // recursive call to circuit().
  225. else if (truncate_search)
  226. continue;
  227. // If `w` is not blocked, we continue searching further down the
  228. // same path for a cycle with `w` in it.
  229. else if (!is_blocked(w) && circuit(start, w))
  230. found_circuit = true;
  231. }
  232. bool const finish_circuit = (found_circuit || truncate_search);
  233. if (finish_circuit)
  234. unblock(v);
  235. else
  236. for (AdjacencyIterator w_it = boost::begin(adj_vertices);
  237. w_it != w_end; ++w_it)
  238. {
  239. Vertex const w = *w_it;
  240. // Like above, we skip vertices that are not in the subgraph
  241. // we're considering.
  242. if (index_of(w) < index_of_start)
  243. continue;
  244. // If `v` is not closed to `w`, we make it so.
  245. if (!is_closed_to(w, v))
  246. close_to(w, v);
  247. }
  248. BOOST_ASSERT(v == stack_.back());
  249. stack_.pop_back();
  250. return finish_circuit;
  251. }
  252. public:
  253. void operator()(Vertex start) { circuit(start, start); }
  254. private:
  255. Graph const& graph_;
  256. Visitor& visitor_;
  257. VertexIndexMap const& vim_;
  258. Stack& stack_;
  259. ClosedMatrix& closed_;
  260. BlockedMap blocked_;
  261. unsigned int max_length_;
  262. };
  263. template < typename GetAdjacentVertices, typename Graph, typename Visitor,
  264. typename VertexIndexMap >
  265. void call_hawick_circuits(Graph const& graph,
  266. Visitor /* by value */ visitor, VertexIndexMap const& vertex_index_map,
  267. unsigned int max_length)
  268. {
  269. typedef graph_traits< Graph > Traits;
  270. typedef typename Traits::vertex_descriptor Vertex;
  271. typedef typename Traits::vertices_size_type VerticesSize;
  272. typedef typename Traits::vertex_iterator VertexIterator;
  273. typedef std::vector< Vertex > Stack;
  274. typedef std::vector< std::vector< Vertex > > ClosedMatrix;
  275. typedef hawick_circuits_from< Graph, Visitor, VertexIndexMap, Stack,
  276. ClosedMatrix, GetAdjacentVertices >
  277. SubAlgorithm;
  278. VerticesSize const n_vertices = num_vertices(graph);
  279. Stack stack;
  280. stack.reserve(n_vertices);
  281. ClosedMatrix closed(n_vertices);
  282. VertexIterator start, last;
  283. for (boost::tie(start, last) = vertices(graph); start != last; ++start)
  284. {
  285. // Note1: The sub algorithm may NOT be reused once it has been
  286. // called.
  287. // Note2: We reuse the Stack and the ClosedMatrix (after clearing
  288. // them) in each iteration to avoid redundant destruction and
  289. // construction. It would be strictly equivalent to have these as
  290. // member variables of the sub algorithm.
  291. SubAlgorithm sub_algo(
  292. graph, visitor, vertex_index_map, stack, closed, n_vertices,
  293. max_length);
  294. sub_algo(*start);
  295. stack.clear();
  296. typename ClosedMatrix::iterator row, last_row = closed.end();
  297. for (row = closed.begin(); row != last_row; ++row)
  298. row->clear();
  299. }
  300. }
  301. template < typename GetAdjacentVertices, typename Graph, typename Visitor >
  302. void call_hawick_circuits(
  303. Graph const& graph, BOOST_FWD_REF(Visitor) visitor,
  304. unsigned int max_length)
  305. {
  306. call_hawick_circuits< GetAdjacentVertices >(graph,
  307. boost::forward< Visitor >(visitor), get(vertex_index, graph),
  308. max_length);
  309. }
  310. } // end namespace hawick_circuits_detail
  311. //! Enumerate all the elementary circuits in a directed multigraph.
  312. template < typename Graph, typename Visitor, typename VertexIndexMap >
  313. void hawick_circuits(BOOST_FWD_REF(Graph) graph, BOOST_FWD_REF(Visitor) visitor,
  314. BOOST_FWD_REF(VertexIndexMap) vertex_index_map,
  315. unsigned int max_length = 0)
  316. {
  317. hawick_circuits_detail::call_hawick_circuits<
  318. hawick_circuits_detail::get_all_adjacent_vertices >(
  319. boost::forward< Graph >(graph), boost::forward< Visitor >(visitor),
  320. boost::forward< VertexIndexMap >(vertex_index_map), max_length);
  321. }
  322. template < typename Graph, typename Visitor >
  323. void hawick_circuits(BOOST_FWD_REF(Graph) graph, BOOST_FWD_REF(Visitor) visitor,
  324. unsigned int max_length = 0)
  325. {
  326. hawick_circuits_detail::call_hawick_circuits<
  327. hawick_circuits_detail::get_all_adjacent_vertices >(
  328. boost::forward< Graph >(graph), boost::forward< Visitor >(visitor),
  329. max_length);
  330. }
  331. /*!
  332. * Same as `boost::hawick_circuits`, but duplicate circuits caused by parallel
  333. * edges will not be considered. Each circuit will be considered only once.
  334. */
  335. template < typename Graph, typename Visitor, typename VertexIndexMap >
  336. void hawick_unique_circuits(BOOST_FWD_REF(Graph) graph,
  337. BOOST_FWD_REF(Visitor) visitor,
  338. BOOST_FWD_REF(VertexIndexMap) vertex_index_map,
  339. unsigned int max_length = 0)
  340. {
  341. hawick_circuits_detail::call_hawick_circuits<
  342. hawick_circuits_detail::get_unique_adjacent_vertices >(
  343. boost::forward< Graph >(graph), boost::forward< Visitor >(visitor),
  344. boost::forward< VertexIndexMap >(vertex_index_map), max_length);
  345. }
  346. template < typename Graph, typename Visitor >
  347. void hawick_unique_circuits(
  348. BOOST_FWD_REF(Graph) graph, BOOST_FWD_REF(Visitor) visitor,
  349. unsigned int max_length = 0)
  350. {
  351. hawick_circuits_detail::call_hawick_circuits<
  352. hawick_circuits_detail::get_unique_adjacent_vertices >(
  353. boost::forward< Graph >(graph), boost::forward< Visitor >(visitor),
  354. max_length);
  355. }
  356. } // end namespace boost
  357. #endif // !BOOST_GRAPH_HAWICK_CIRCUITS_HPP