File indexing completed on 2025-10-31 08:41:49
0001 
0002 
0003 
0004 
0005 
0006 
0007 #ifndef BOOST_GRAPH_CYCLE_HPP
0008 #define BOOST_GRAPH_CYCLE_HPP
0009 
0010 #include <vector>
0011 
0012 #include <boost/config.hpp>
0013 #include <boost/graph/graph_concepts.hpp>
0014 #include <boost/graph/graph_traits.hpp>
0015 #include <boost/graph/properties.hpp>
0016 #include <boost/concept/assert.hpp>
0017 
0018 #include <boost/concept/detail/concept_def.hpp>
0019 namespace boost
0020 {
0021 namespace concepts
0022 {
0023     BOOST_concept(CycleVisitor, (Visitor)(Path)(Graph))
0024     {
0025         BOOST_CONCEPT_USAGE(CycleVisitor) { vis.cycle(p, g); }
0026 
0027     private:
0028         Visitor vis;
0029         Graph g;
0030         Path p;
0031     };
0032 } 
0033 using concepts::CycleVisitorConcept;
0034 } 
0035 #include <boost/concept/detail/concept_undef.hpp>
0036 
0037 namespace boost
0038 {
0039 
0040 
0041 
0042 
0043 
0044 
0045 
0046 
0047 
0048 
0049 
0050 
0051 
0052 
0053 
0054 
0055 
0056 
0057 
0058 
0059 
0060 
0061 
0062 
0063 
0064 
0065 
0066 
0067 
0068 
0069 
0070 
0071 
0072 
0073 
0074 
0075 
0076 
0077 
0078 
0079 
0080 
0081 
0082 struct cycle_visitor
0083 {
0084     template < typename Path, typename Graph >
0085     inline void cycle(const Path& p, const Graph& g)
0086     {
0087     }
0088 };
0089 
0090 
0091 
0092 
0093 
0094 struct min_max_cycle_visitor
0095 {
0096     min_max_cycle_visitor(std::size_t& min_, std::size_t& max_)
0097     : minimum(min_), maximum(max_)
0098     {
0099     }
0100 
0101     template < typename Path, typename Graph >
0102     inline void cycle(const Path& p, const Graph& g)
0103     {
0104         BOOST_USING_STD_MIN();
0105         BOOST_USING_STD_MAX();
0106         std::size_t len = p.size();
0107         minimum = min BOOST_PREVENT_MACRO_SUBSTITUTION(minimum, len);
0108         maximum = max BOOST_PREVENT_MACRO_SUBSTITUTION(maximum, len);
0109     }
0110     std::size_t& minimum;
0111     std::size_t& maximum;
0112 };
0113 
0114 inline min_max_cycle_visitor find_min_max_cycle(
0115     std::size_t& min_, std::size_t& max_)
0116 {
0117     return min_max_cycle_visitor(min_, max_);
0118 }
0119 
0120 namespace detail
0121 {
0122     template < typename Graph, typename Path >
0123     inline bool is_vertex_in_path(const Graph&,
0124         typename graph_traits< Graph >::vertex_descriptor v, const Path& p)
0125     {
0126         return (std::find(p.begin(), p.end(), v) != p.end());
0127     }
0128 
0129     template < typename Graph, typename ClosedMatrix >
0130     inline bool is_path_closed(const Graph& g,
0131         typename graph_traits< Graph >::vertex_descriptor u,
0132         typename graph_traits< Graph >::vertex_descriptor v,
0133         const ClosedMatrix& closed)
0134     {
0135         
0136         
0137         typedef typename ClosedMatrix::const_reference Row;
0138         Row r = closed[get(vertex_index, g, u)];
0139         if (find(r.begin(), r.end(), v) != r.end())
0140         {
0141             return true;
0142         }
0143         return false;
0144     }
0145 
0146     template < typename Graph, typename Path, typename ClosedMatrix >
0147     inline bool can_extend_path(const Graph& g,
0148         typename graph_traits< Graph >::edge_descriptor e, const Path& p,
0149         const ClosedMatrix& m)
0150     {
0151         BOOST_CONCEPT_ASSERT((IncidenceGraphConcept< Graph >));
0152         BOOST_CONCEPT_ASSERT((VertexIndexGraphConcept< Graph >));
0153         typedef typename graph_traits< Graph >::vertex_descriptor Vertex;
0154 
0155         
0156         Vertex u = source(e, g), v = target(e, g);
0157 
0158         
0159         
0160         
0161         
0162         
0163 
0164         bool indices
0165             = get(vertex_index, g, p.front()) < get(vertex_index, g, v);
0166         bool path = !is_vertex_in_path(g, v, p);
0167         bool closed = !is_path_closed(g, u, v, m);
0168         return indices && path && closed;
0169     }
0170 
0171     template < typename Graph, typename Path >
0172     inline bool can_wrap_path(const Graph& g, const Path& p)
0173     {
0174         BOOST_CONCEPT_ASSERT((IncidenceGraphConcept< Graph >));
0175         typedef typename graph_traits< Graph >::vertex_descriptor Vertex;
0176         typedef typename graph_traits< Graph >::out_edge_iterator OutIterator;
0177 
0178         
0179         
0180         
0181         
0182         Vertex u = p.back(), v = p.front();
0183         OutIterator i, end;
0184         for (boost::tie(i, end) = out_edges(u, g); i != end; ++i)
0185         {
0186             if ((target(*i, g) == v))
0187             {
0188                 return true;
0189             }
0190         }
0191         return false;
0192     }
0193 
0194     template < typename Graph, typename Path, typename ClosedMatrix >
0195     inline typename graph_traits< Graph >::vertex_descriptor extend_path(
0196         const Graph& g, Path& p, ClosedMatrix& closed)
0197     {
0198         BOOST_CONCEPT_ASSERT((IncidenceGraphConcept< Graph >));
0199         typedef typename graph_traits< Graph >::vertex_descriptor Vertex;
0200         typedef typename graph_traits< Graph >::out_edge_iterator OutIterator;
0201 
0202         
0203         Vertex u = p.back();
0204         Vertex ret = graph_traits< Graph >::null_vertex();
0205 
0206         
0207         OutIterator i, end;
0208         for (boost::tie(i, end) = out_edges(u, g); i != end; ++i)
0209         {
0210             Vertex v = target(*i, g);
0211 
0212             
0213             
0214             if (can_extend_path(g, *i, p, closed))
0215             {
0216                 p.push_back(v); 
0217                 ret = v;
0218                 break;
0219             }
0220         }
0221         return ret;
0222     }
0223 
0224     template < typename Graph, typename Path, typename ClosedMatrix >
0225     inline bool exhaust_paths(const Graph& g, Path& p, ClosedMatrix& closed)
0226     {
0227         BOOST_CONCEPT_ASSERT((GraphConcept< Graph >));
0228         typedef typename graph_traits< Graph >::vertex_descriptor Vertex;
0229 
0230         
0231         
0232         
0233         if (p.size() > 1)
0234         {
0235             
0236             
0237             Vertex last, prev;
0238             last = p.back();
0239             p.pop_back();
0240             prev = p.back();
0241 
0242             
0243             
0244             
0245             closed[get(vertex_index, g, last)].clear();
0246             closed[get(vertex_index, g, prev)].push_back(last);
0247             return true;
0248         }
0249         else
0250         {
0251             return false;
0252         }
0253     }
0254 
0255     template < typename Graph, typename Visitor >
0256     inline void all_cycles_from_vertex(const Graph& g,
0257         typename graph_traits< Graph >::vertex_descriptor v, Visitor vis,
0258         std::size_t minlen, std::size_t maxlen)
0259     {
0260         BOOST_CONCEPT_ASSERT((VertexListGraphConcept< Graph >));
0261         typedef typename graph_traits< Graph >::vertex_descriptor Vertex;
0262         typedef std::vector< Vertex > Path;
0263         BOOST_CONCEPT_ASSERT((CycleVisitorConcept< Visitor, Path, Graph >));
0264         typedef std::vector< Vertex > VertexList;
0265         typedef std::vector< VertexList > ClosedMatrix;
0266 
0267         Path p;
0268         ClosedMatrix closed(num_vertices(g), VertexList());
0269         Vertex null = graph_traits< Graph >::null_vertex();
0270 
0271         
0272         p.push_back(v);
0273 
0274         while (1)
0275         {
0276             
0277             
0278             Vertex j = null;
0279             while (((j = detail::extend_path(g, p, closed)) != null)
0280                 && (p.size() < maxlen))
0281                 ; 
0282 
0283             
0284             
0285             
0286             if (detail::can_wrap_path(g, p) && p.size() >= minlen)
0287             {
0288                 vis.cycle(p, g);
0289             }
0290 
0291             if (!detail::exhaust_paths(g, p, closed))
0292             {
0293                 break;
0294             }
0295         }
0296     }
0297 
0298     
0299     
0300     template < typename D > struct min_cycles
0301     {
0302         enum
0303         {
0304             value = 2
0305         };
0306     };
0307     template <> struct min_cycles< undirected_tag >
0308     {
0309         enum
0310         {
0311             value = 3
0312         };
0313     };
0314 } 
0315 
0316 template < typename Graph, typename Visitor >
0317 inline void tiernan_all_cycles(
0318     const Graph& g, Visitor vis, std::size_t minlen, std::size_t maxlen)
0319 {
0320     BOOST_CONCEPT_ASSERT((VertexListGraphConcept< Graph >));
0321     typedef typename graph_traits< Graph >::vertex_iterator VertexIterator;
0322 
0323     VertexIterator i, end;
0324     for (boost::tie(i, end) = vertices(g); i != end; ++i)
0325     {
0326         detail::all_cycles_from_vertex(g, *i, vis, minlen, maxlen);
0327     }
0328 }
0329 
0330 template < typename Graph, typename Visitor >
0331 inline void tiernan_all_cycles(const Graph& g, Visitor vis, std::size_t maxlen)
0332 {
0333     typedef typename graph_traits< Graph >::directed_category Dir;
0334     tiernan_all_cycles(g, vis, detail::min_cycles< Dir >::value, maxlen);
0335 }
0336 
0337 template < typename Graph, typename Visitor >
0338 inline void tiernan_all_cycles(const Graph& g, Visitor vis)
0339 {
0340     typedef typename graph_traits< Graph >::directed_category Dir;
0341     tiernan_all_cycles(g, vis, detail::min_cycles< Dir >::value,
0342         (std::numeric_limits< std::size_t >::max)());
0343 }
0344 
0345 template < typename Graph >
0346 inline std::pair< std::size_t, std::size_t > tiernan_girth_and_circumference(
0347     const Graph& g)
0348 {
0349     std::size_t min_ = (std::numeric_limits< std::size_t >::max)(), max_ = 0;
0350     tiernan_all_cycles(g, find_min_max_cycle(min_, max_));
0351 
0352     
0353     if (max_ == 0)
0354         max_ = min_;
0355 
0356     return std::make_pair(min_, max_);
0357 }
0358 
0359 template < typename Graph > inline std::size_t tiernan_girth(const Graph& g)
0360 {
0361     return tiernan_girth_and_circumference(g).first;
0362 }
0363 
0364 template < typename Graph >
0365 inline std::size_t tiernan_circumference(const Graph& g)
0366 {
0367     return tiernan_girth_and_circumference(g).second;
0368 }
0369 
0370 } 
0371 
0372 #endif