Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-09 08:12:48

0001 // Copyright Louis Dionne 2013
0002 
0003 // Use, modification and distribution is subject to the Boost Software
0004 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy
0005 // at http://www.boost.org/LICENSE_1_0.txt)
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     //! @internal Functor returning all the vertices adjacent to a vertex.
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     //! @internal Functor returning a set of the vertices adjacent to a vertex.
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     //! @internal
0083     //! Return whether a container contains a given value.
0084     //! This is not meant as a general purpose membership testing function; it
0085     //! would have to be more clever about possible optimizations.
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      * @internal
0094      * Algorithm finding all the cycles starting from a given vertex.
0095      *
0096      * The search is only done in the subgraph induced by the starting vertex
0097      * and the vertices with an index higher than the starting vertex.
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         // The one_bit_color_map starts all white, i.e. not blocked.
0117         // Since we make that assumption (I looked at the implementation, but
0118         // I can't find anything that documents this behavior), we're gonna
0119         // assert it in the constructor.
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         // This is used by the constructor to secure the assumption
0134         // documented above.
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         // This is only used in the constructor to make sure the optimization of
0144         // sharing data structures between iterations does not break the code.
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             // Since sharing the data structures between iterations is
0168             // just an optimization, it must always be equivalent to
0169             // constructing new ones in this constructor.
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         //! @internal Return the index of a given vertex.
0177         VertexIndex index_of(Vertex v) const { return get(vim_, v); }
0178 
0179         //! @internal Return whether a vertex `v` is closed to a vertex `u`.
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         //! @internal Close a vertex `v` to a vertex `u`.
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         //! @internal Return whether a given vertex is blocked.
0195         bool is_blocked(Vertex v) const
0196         {
0197             return get(blocked_, v) == blocked_true_color();
0198         }
0199 
0200         //! @internal Block a given vertex.
0201         void block(Vertex v) { put(blocked_, v, blocked_true_color()); }
0202 
0203         //! @internal Unblock a given vertex.
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         //! @internal Main procedure as described in the paper.
0222         bool circuit(Vertex start, Vertex v)
0223         {
0224             bool found_circuit = false;
0225             stack_.push_back(v);
0226             block(v);
0227 
0228             // Truncate the search if any circuits would exceed max_length_.
0229             bool const truncate_search =
0230                 (max_length_ > 0 && stack_.size() >= max_length_);
0231 
0232             // Cache some values that are used more than once in the function.
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                 // Since we're only looking in the subgraph induced by `start`
0243                 // and the vertices with an index higher than `start`, we skip
0244                 // any vertex that does not satisfy that.
0245                 if (index_of(w) < index_of_start)
0246                     continue;
0247 
0248                 // If the last vertex is equal to `start`, we have a circuit.
0249                 else if (w == start)
0250                 {
0251                     // const_cast to ensure the visitor does not modify the
0252                     // stack
0253                     visitor_.cycle(const_cast< Stack const& >(stack_), graph_);
0254                     found_circuit = true;
0255                 }
0256 
0257                 // If required, truncate the search before the subsequent
0258                 // recursive call to circuit().
0259                 else if (truncate_search)
0260                     continue;
0261 
0262                 // If `w` is not blocked, we continue searching further down the
0263                 // same path for a cycle with `w` in it.
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                     // Like above, we skip vertices that are not in the subgraph
0277                     // we're considering.
0278                     if (index_of(w) < index_of_start)
0279                         continue;
0280 
0281                     // If `v` is not closed to `w`, we make it so.
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 /* by value */ 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             // Note1: The sub algorithm may NOT be reused once it has been
0331             // called.
0332 
0333             // Note2: We reuse the Stack and the ClosedMatrix (after clearing
0334             // them) in each iteration to avoid redundant destruction and
0335             // construction. It would be strictly equivalent to have these as
0336             // member variables of the sub algorithm.
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 } // end namespace hawick_circuits_detail
0358 
0359 //! Enumerate all the elementary circuits in a directed multigraph.
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  * Same as `boost::hawick_circuits`, but duplicate circuits caused by parallel
0383  * edges will not be considered. Each circuit will be considered only once.
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 } // end namespace boost
0408 
0409 #endif // !BOOST_GRAPH_HAWICK_CIRCUITS_HPP