annotate DEPENDENCIES/generic/include/boost/graph/hawick_circuits.hpp @ 125:34e428693f5d vext

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