hawick_circuits.hpp 13 KB

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