File indexing completed on 2025-07-09 08:12:48
0001
0002
0003
0004
0005
0006
0007 #ifndef BOOST_GRAPH_HAWICK_CIRCUITS_HPP
0008 #define BOOST_GRAPH_HAWICK_CIRCUITS_HPP
0009
0010 #include <algorithm>
0011 #include <boost/assert.hpp>
0012 #include <boost/foreach.hpp>
0013 #include <boost/graph/graph_traits.hpp>
0014 #include <boost/graph/one_bit_color_map.hpp>
0015 #include <boost/graph/properties.hpp>
0016 #include <boost/move/utility.hpp>
0017 #include <boost/property_map/property_map.hpp>
0018 #include <boost/range/begin.hpp>
0019 #include <boost/range/end.hpp>
0020 #include <boost/range/iterator.hpp>
0021 #include <boost/tuple/tuple.hpp> // for boost::tie
0022 #include <boost/type_traits/remove_reference.hpp>
0023 #include <boost/utility/result_of.hpp>
0024 #include <set>
0025 #include <utility> // for std::pair
0026 #include <vector>
0027
0028 namespace boost
0029 {
0030 namespace hawick_circuits_detail
0031 {
0032
0033 struct get_all_adjacent_vertices
0034 {
0035 template < typename Sig > struct result;
0036
0037 template < typename This, typename Vertex, typename Graph >
0038 struct result< This(Vertex, Graph) >
0039 {
0040 private:
0041 typedef typename remove_reference< Graph >::type RawGraph;
0042 typedef graph_traits< RawGraph > Traits;
0043 typedef typename Traits::adjacency_iterator AdjacencyIterator;
0044
0045 public:
0046 typedef std::pair< AdjacencyIterator, AdjacencyIterator > type;
0047 };
0048
0049 template < typename Vertex, typename Graph >
0050 typename result< get_all_adjacent_vertices(
0051 BOOST_FWD_REF(Vertex), BOOST_FWD_REF(Graph)) >::type
0052 operator()(BOOST_FWD_REF(Vertex) v, BOOST_FWD_REF(Graph) g) const
0053 {
0054 return adjacent_vertices(
0055 boost::forward< Vertex >(v), boost::forward< Graph >(g));
0056 }
0057 };
0058
0059
0060 struct get_unique_adjacent_vertices
0061 {
0062 template < typename Sig > struct result;
0063
0064 template < typename This, typename Vertex, typename Graph >
0065 struct result< This(Vertex, Graph) >
0066 {
0067 typedef std::set< typename remove_reference< Vertex >::type > type;
0068 };
0069
0070 template < typename Vertex, typename Graph >
0071 typename result< get_unique_adjacent_vertices(
0072 Vertex, Graph const&) >::type
0073 operator()(Vertex v, Graph const& g) const
0074 {
0075 typedef typename result< get_unique_adjacent_vertices(
0076 Vertex, Graph const&) >::type Set;
0077 return Set(
0078 adjacent_vertices(v, g).first, adjacent_vertices(v, g).second);
0079 }
0080 };
0081
0082
0083
0084
0085
0086 template < typename Container, typename Value >
0087 bool contains(Container const& c, Value const& v)
0088 {
0089 return std::find(boost::begin(c), boost::end(c), v) != boost::end(c);
0090 }
0091
0092
0093
0094
0095
0096
0097
0098
0099 template < typename Graph, typename Visitor, typename VertexIndexMap,
0100 typename Stack, typename ClosedMatrix, typename GetAdjacentVertices >
0101 struct hawick_circuits_from
0102 {
0103 private:
0104 typedef graph_traits< Graph > Traits;
0105 typedef typename Traits::vertex_descriptor Vertex;
0106 typedef typename Traits::edge_descriptor Edge;
0107 typedef typename Traits::vertices_size_type VerticesSize;
0108 typedef
0109 typename property_traits< VertexIndexMap >::value_type VertexIndex;
0110
0111 typedef typename result_of< GetAdjacentVertices(
0112 Vertex, Graph const&) >::type AdjacentVertices;
0113 typedef typename range_iterator< AdjacentVertices const >::type
0114 AdjacencyIterator;
0115
0116
0117
0118
0119
0120 typedef one_bit_color_map< VertexIndexMap > BlockedMap;
0121 typedef typename property_traits< BlockedMap >::value_type BlockedColor;
0122
0123 static BlockedColor blocked_false_color()
0124 {
0125 return color_traits< BlockedColor >::white();
0126 }
0127
0128 static BlockedColor blocked_true_color()
0129 {
0130 return color_traits< BlockedColor >::black();
0131 }
0132
0133
0134
0135 bool blocked_map_starts_all_unblocked() const
0136 {
0137 BOOST_FOREACH (Vertex v, vertices(graph_))
0138 if (is_blocked(v))
0139 return false;
0140 return true;
0141 }
0142
0143
0144
0145 bool all_closed_rows_are_empty() const
0146 {
0147 BOOST_FOREACH (typename ClosedMatrix::reference row, closed_)
0148 if (!row.empty())
0149 return false;
0150 return true;
0151 }
0152
0153 public:
0154 hawick_circuits_from(Graph const& graph, Visitor& visitor,
0155 VertexIndexMap const& vim, Stack& stack, ClosedMatrix& closed,
0156 VerticesSize n_vertices, unsigned int max_length)
0157 : graph_(graph)
0158 , visitor_(visitor)
0159 , vim_(vim)
0160 , stack_(stack)
0161 , closed_(closed)
0162 , blocked_(n_vertices, vim_)
0163 , max_length_(max_length)
0164 {
0165 BOOST_ASSERT(blocked_map_starts_all_unblocked());
0166
0167
0168
0169
0170 BOOST_ASSERT(stack_.empty());
0171 BOOST_ASSERT(closed_.size() == n_vertices);
0172 BOOST_ASSERT(all_closed_rows_are_empty());
0173 }
0174
0175 private:
0176
0177 VertexIndex index_of(Vertex v) const { return get(vim_, v); }
0178
0179
0180 bool is_closed_to(Vertex u, Vertex v) const
0181 {
0182 typedef typename ClosedMatrix::const_reference VertexList;
0183 VertexList closed_to_u = closed_[index_of(u)];
0184 return contains(closed_to_u, v);
0185 }
0186
0187
0188 void close_to(Vertex u, Vertex v)
0189 {
0190 BOOST_ASSERT(!is_closed_to(u, v));
0191 closed_[index_of(u)].push_back(v);
0192 }
0193
0194
0195 bool is_blocked(Vertex v) const
0196 {
0197 return get(blocked_, v) == blocked_true_color();
0198 }
0199
0200
0201 void block(Vertex v) { put(blocked_, v, blocked_true_color()); }
0202
0203
0204 void unblock(Vertex u)
0205 {
0206 typedef typename ClosedMatrix::reference VertexList;
0207
0208 put(blocked_, u, blocked_false_color());
0209 VertexList closed_to_u = closed_[index_of(u)];
0210
0211 while (!closed_to_u.empty())
0212 {
0213 Vertex const w = closed_to_u.back();
0214 closed_to_u.pop_back();
0215 if (is_blocked(w))
0216 unblock(w);
0217 }
0218 BOOST_ASSERT(closed_to_u.empty());
0219 }
0220
0221
0222 bool circuit(Vertex start, Vertex v)
0223 {
0224 bool found_circuit = false;
0225 stack_.push_back(v);
0226 block(v);
0227
0228
0229 bool const truncate_search =
0230 (max_length_ > 0 && stack_.size() >= max_length_);
0231
0232
0233 VertexIndex const index_of_start = index_of(start);
0234 AdjacentVertices const adj_vertices
0235 = GetAdjacentVertices()(v, graph_);
0236 AdjacencyIterator const w_end = boost::end(adj_vertices);
0237
0238 for (AdjacencyIterator w_it = boost::begin(adj_vertices);
0239 w_it != w_end; ++w_it)
0240 {
0241 Vertex const w = *w_it;
0242
0243
0244
0245 if (index_of(w) < index_of_start)
0246 continue;
0247
0248
0249 else if (w == start)
0250 {
0251
0252
0253 visitor_.cycle(const_cast< Stack const& >(stack_), graph_);
0254 found_circuit = true;
0255 }
0256
0257
0258
0259 else if (truncate_search)
0260 continue;
0261
0262
0263
0264 else if (!is_blocked(w) && circuit(start, w))
0265 found_circuit = true;
0266 }
0267
0268 bool const finish_circuit = (found_circuit || truncate_search);
0269 if (finish_circuit)
0270 unblock(v);
0271 else
0272 for (AdjacencyIterator w_it = boost::begin(adj_vertices);
0273 w_it != w_end; ++w_it)
0274 {
0275 Vertex const w = *w_it;
0276
0277
0278 if (index_of(w) < index_of_start)
0279 continue;
0280
0281
0282 if (!is_closed_to(w, v))
0283 close_to(w, v);
0284 }
0285
0286 BOOST_ASSERT(v == stack_.back());
0287 stack_.pop_back();
0288 return finish_circuit;
0289 }
0290
0291 public:
0292 void operator()(Vertex start) { circuit(start, start); }
0293
0294 private:
0295 Graph const& graph_;
0296 Visitor& visitor_;
0297 VertexIndexMap const& vim_;
0298 Stack& stack_;
0299 ClosedMatrix& closed_;
0300 BlockedMap blocked_;
0301 unsigned int max_length_;
0302 };
0303
0304 template < typename GetAdjacentVertices, typename Graph, typename Visitor,
0305 typename VertexIndexMap >
0306 void call_hawick_circuits(Graph const& graph,
0307 Visitor visitor, VertexIndexMap const& vertex_index_map,
0308 unsigned int max_length)
0309 {
0310 typedef graph_traits< Graph > Traits;
0311 typedef typename Traits::vertex_descriptor Vertex;
0312 typedef typename Traits::vertices_size_type VerticesSize;
0313 typedef typename Traits::vertex_iterator VertexIterator;
0314
0315 typedef std::vector< Vertex > Stack;
0316 typedef std::vector< std::vector< Vertex > > ClosedMatrix;
0317
0318 typedef hawick_circuits_from< Graph, Visitor, VertexIndexMap, Stack,
0319 ClosedMatrix, GetAdjacentVertices >
0320 SubAlgorithm;
0321
0322 VerticesSize const n_vertices = num_vertices(graph);
0323 Stack stack;
0324 stack.reserve(n_vertices);
0325 ClosedMatrix closed(n_vertices);
0326
0327 VertexIterator start, last;
0328 for (boost::tie(start, last) = vertices(graph); start != last; ++start)
0329 {
0330
0331
0332
0333
0334
0335
0336
0337 SubAlgorithm sub_algo(
0338 graph, visitor, vertex_index_map, stack, closed, n_vertices,
0339 max_length);
0340 sub_algo(*start);
0341 stack.clear();
0342 typename ClosedMatrix::iterator row, last_row = closed.end();
0343 for (row = closed.begin(); row != last_row; ++row)
0344 row->clear();
0345 }
0346 }
0347
0348 template < typename GetAdjacentVertices, typename Graph, typename Visitor >
0349 void call_hawick_circuits(
0350 Graph const& graph, BOOST_FWD_REF(Visitor) visitor,
0351 unsigned int max_length)
0352 {
0353 call_hawick_circuits< GetAdjacentVertices >(graph,
0354 boost::forward< Visitor >(visitor), get(vertex_index, graph),
0355 max_length);
0356 }
0357 }
0358
0359
0360 template < typename Graph, typename Visitor, typename VertexIndexMap >
0361 void hawick_circuits(BOOST_FWD_REF(Graph) graph, BOOST_FWD_REF(Visitor) visitor,
0362 BOOST_FWD_REF(VertexIndexMap) vertex_index_map,
0363 unsigned int max_length = 0)
0364 {
0365 hawick_circuits_detail::call_hawick_circuits<
0366 hawick_circuits_detail::get_all_adjacent_vertices >(
0367 boost::forward< Graph >(graph), boost::forward< Visitor >(visitor),
0368 boost::forward< VertexIndexMap >(vertex_index_map), max_length);
0369 }
0370
0371 template < typename Graph, typename Visitor >
0372 void hawick_circuits(BOOST_FWD_REF(Graph) graph, BOOST_FWD_REF(Visitor) visitor,
0373 unsigned int max_length = 0)
0374 {
0375 hawick_circuits_detail::call_hawick_circuits<
0376 hawick_circuits_detail::get_all_adjacent_vertices >(
0377 boost::forward< Graph >(graph), boost::forward< Visitor >(visitor),
0378 max_length);
0379 }
0380
0381
0382
0383
0384
0385 template < typename Graph, typename Visitor, typename VertexIndexMap >
0386 void hawick_unique_circuits(BOOST_FWD_REF(Graph) graph,
0387 BOOST_FWD_REF(Visitor) visitor,
0388 BOOST_FWD_REF(VertexIndexMap) vertex_index_map,
0389 unsigned int max_length = 0)
0390 {
0391 hawick_circuits_detail::call_hawick_circuits<
0392 hawick_circuits_detail::get_unique_adjacent_vertices >(
0393 boost::forward< Graph >(graph), boost::forward< Visitor >(visitor),
0394 boost::forward< VertexIndexMap >(vertex_index_map), max_length);
0395 }
0396
0397 template < typename Graph, typename Visitor >
0398 void hawick_unique_circuits(
0399 BOOST_FWD_REF(Graph) graph, BOOST_FWD_REF(Visitor) visitor,
0400 unsigned int max_length = 0)
0401 {
0402 hawick_circuits_detail::call_hawick_circuits<
0403 hawick_circuits_detail::get_unique_adjacent_vertices >(
0404 boost::forward< Graph >(graph), boost::forward< Visitor >(visitor),
0405 max_length);
0406 }
0407 }
0408
0409 #endif