123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387 |
- // Copyright Louis Dionne 2013
- // Use, modification and distribution is subject to the Boost Software
- // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy
- // at http://www.boost.org/LICENSE_1_0.txt)
- #ifndef BOOST_GRAPH_HAWICK_CIRCUITS_HPP
- #define BOOST_GRAPH_HAWICK_CIRCUITS_HPP
- #include <algorithm>
- #include <boost/assert.hpp>
- #include <boost/foreach.hpp>
- #include <boost/graph/graph_traits.hpp>
- #include <boost/graph/one_bit_color_map.hpp>
- #include <boost/graph/properties.hpp>
- #include <boost/move/utility.hpp>
- #include <boost/property_map/property_map.hpp>
- #include <boost/range/begin.hpp>
- #include <boost/range/end.hpp>
- #include <boost/range/iterator.hpp>
- #include <boost/tuple/tuple.hpp> // for boost::tie
- #include <boost/type_traits/remove_reference.hpp>
- #include <boost/utility/result_of.hpp>
- #include <set>
- #include <utility> // for std::pair
- #include <vector>
- namespace boost
- {
- namespace hawick_circuits_detail
- {
- //! @internal Functor returning all the vertices adjacent to a vertex.
- struct get_all_adjacent_vertices
- {
- template < typename Sig > struct result;
- template < typename This, typename Vertex, typename Graph >
- struct result< This(Vertex, Graph) >
- {
- private:
- typedef typename remove_reference< Graph >::type RawGraph;
- typedef graph_traits< RawGraph > Traits;
- typedef typename Traits::adjacency_iterator AdjacencyIterator;
- public:
- typedef std::pair< AdjacencyIterator, AdjacencyIterator > type;
- };
- template < typename Vertex, typename Graph >
- typename result< get_all_adjacent_vertices(
- BOOST_FWD_REF(Vertex), BOOST_FWD_REF(Graph)) >::type
- operator()(BOOST_FWD_REF(Vertex) v, BOOST_FWD_REF(Graph) g) const
- {
- return adjacent_vertices(
- boost::forward< Vertex >(v), boost::forward< Graph >(g));
- }
- };
- //! @internal Functor returning a set of the vertices adjacent to a vertex.
- struct get_unique_adjacent_vertices
- {
- template < typename Sig > struct result;
- template < typename This, typename Vertex, typename Graph >
- struct result< This(Vertex, Graph) >
- {
- typedef std::set< typename remove_reference< Vertex >::type > type;
- };
- template < typename Vertex, typename Graph >
- typename result< get_unique_adjacent_vertices(
- Vertex, Graph const&) >::type
- operator()(Vertex v, Graph const& g) const
- {
- typedef typename result< get_unique_adjacent_vertices(
- Vertex, Graph const&) >::type Set;
- return Set(
- adjacent_vertices(v, g).first, adjacent_vertices(v, g).second);
- }
- };
- //! @internal
- //! Return whether a container contains a given value.
- //! This is not meant as a general purpose membership testing function; it
- //! would have to be more clever about possible optimizations.
- template < typename Container, typename Value >
- bool contains(Container const& c, Value const& v)
- {
- return std::find(boost::begin(c), boost::end(c), v) != boost::end(c);
- }
- /*!
- * @internal
- * Algorithm finding all the cycles starting from a given vertex.
- *
- * The search is only done in the subgraph induced by the starting vertex
- * and the vertices with an index higher than the starting vertex.
- */
- template < typename Graph, typename Visitor, typename VertexIndexMap,
- typename Stack, typename ClosedMatrix, typename GetAdjacentVertices >
- struct hawick_circuits_from
- {
- private:
- typedef graph_traits< Graph > Traits;
- typedef typename Traits::vertex_descriptor Vertex;
- typedef typename Traits::edge_descriptor Edge;
- typedef typename Traits::vertices_size_type VerticesSize;
- typedef
- typename property_traits< VertexIndexMap >::value_type VertexIndex;
- typedef typename result_of< GetAdjacentVertices(
- Vertex, Graph const&) >::type AdjacentVertices;
- typedef typename range_iterator< AdjacentVertices const >::type
- AdjacencyIterator;
- // The one_bit_color_map starts all white, i.e. not blocked.
- // Since we make that assumption (I looked at the implementation, but
- // I can't find anything that documents this behavior), we're gonna
- // assert it in the constructor.
- typedef one_bit_color_map< VertexIndexMap > BlockedMap;
- typedef typename property_traits< BlockedMap >::value_type BlockedColor;
- static BlockedColor blocked_false_color()
- {
- return color_traits< BlockedColor >::white();
- }
- static BlockedColor blocked_true_color()
- {
- return color_traits< BlockedColor >::black();
- }
- // This is used by the constructor to secure the assumption
- // documented above.
- bool blocked_map_starts_all_unblocked() const
- {
- BOOST_FOREACH (Vertex v, vertices(graph_))
- if (is_blocked(v))
- return false;
- return true;
- }
- // This is only used in the constructor to make sure the optimization of
- // sharing data structures between iterations does not break the code.
- bool all_closed_rows_are_empty() const
- {
- BOOST_FOREACH (typename ClosedMatrix::reference row, closed_)
- if (!row.empty())
- return false;
- return true;
- }
- public:
- hawick_circuits_from(Graph const& graph, Visitor& visitor,
- VertexIndexMap const& vim, Stack& stack, ClosedMatrix& closed,
- VerticesSize n_vertices)
- : graph_(graph)
- , visitor_(visitor)
- , vim_(vim)
- , stack_(stack)
- , closed_(closed)
- , blocked_(n_vertices, vim_)
- {
- BOOST_ASSERT(blocked_map_starts_all_unblocked());
- // Since sharing the data structures between iterations is
- // just an optimization, it must always be equivalent to
- // constructing new ones in this constructor.
- BOOST_ASSERT(stack_.empty());
- BOOST_ASSERT(closed_.size() == n_vertices);
- BOOST_ASSERT(all_closed_rows_are_empty());
- }
- private:
- //! @internal Return the index of a given vertex.
- VertexIndex index_of(Vertex v) const { return get(vim_, v); }
- //! @internal Return whether a vertex `v` is closed to a vertex `u`.
- bool is_closed_to(Vertex u, Vertex v) const
- {
- typedef typename ClosedMatrix::const_reference VertexList;
- VertexList closed_to_u = closed_[index_of(u)];
- return contains(closed_to_u, v);
- }
- //! @internal Close a vertex `v` to a vertex `u`.
- void close_to(Vertex u, Vertex v)
- {
- BOOST_ASSERT(!is_closed_to(u, v));
- closed_[index_of(u)].push_back(v);
- }
- //! @internal Return whether a given vertex is blocked.
- bool is_blocked(Vertex v) const
- {
- return get(blocked_, v) == blocked_true_color();
- }
- //! @internal Block a given vertex.
- void block(Vertex v) { put(blocked_, v, blocked_true_color()); }
- //! @internal Unblock a given vertex.
- void unblock(Vertex u)
- {
- typedef typename ClosedMatrix::reference VertexList;
- put(blocked_, u, blocked_false_color());
- VertexList closed_to_u = closed_[index_of(u)];
- while (!closed_to_u.empty())
- {
- Vertex const w = closed_to_u.back();
- closed_to_u.pop_back();
- if (is_blocked(w))
- unblock(w);
- }
- BOOST_ASSERT(closed_to_u.empty());
- }
- //! @internal Main procedure as described in the paper.
- bool circuit(Vertex start, Vertex v)
- {
- bool found_circuit = false;
- stack_.push_back(v);
- block(v);
- // Cache some values that are used more than once in the function.
- VertexIndex const index_of_start = index_of(start);
- AdjacentVertices const adj_vertices
- = GetAdjacentVertices()(v, graph_);
- AdjacencyIterator const w_end = boost::end(adj_vertices);
- for (AdjacencyIterator w_it = boost::begin(adj_vertices);
- w_it != w_end; ++w_it)
- {
- Vertex const w = *w_it;
- // Since we're only looking in the subgraph induced by `start`
- // and the vertices with an index higher than `start`, we skip
- // any vertex that does not satisfy that.
- if (index_of(w) < index_of_start)
- continue;
- // If the last vertex is equal to `start`, we have a circuit.
- else if (w == start)
- {
- // const_cast to ensure the visitor does not modify the
- // stack
- visitor_.cycle(const_cast< Stack const& >(stack_), graph_);
- found_circuit = true;
- }
- // If `w` is not blocked, we continue searching further down the
- // same path for a cycle with `w` in it.
- else if (!is_blocked(w) && circuit(start, w))
- found_circuit = true;
- }
- if (found_circuit)
- unblock(v);
- else
- for (AdjacencyIterator w_it = boost::begin(adj_vertices);
- w_it != w_end; ++w_it)
- {
- Vertex const w = *w_it;
- // Like above, we skip vertices that are not in the subgraph
- // we're considering.
- if (index_of(w) < index_of_start)
- continue;
- // If `v` is not closed to `w`, we make it so.
- if (!is_closed_to(w, v))
- close_to(w, v);
- }
- BOOST_ASSERT(v == stack_.back());
- stack_.pop_back();
- return found_circuit;
- }
- public:
- void operator()(Vertex start) { circuit(start, start); }
- private:
- Graph const& graph_;
- Visitor& visitor_;
- VertexIndexMap const& vim_;
- Stack& stack_;
- ClosedMatrix& closed_;
- BlockedMap blocked_;
- };
- template < typename GetAdjacentVertices, typename Graph, typename Visitor,
- typename VertexIndexMap >
- void call_hawick_circuits(Graph const& graph,
- Visitor /* by value */ visitor, VertexIndexMap const& vertex_index_map)
- {
- typedef graph_traits< Graph > Traits;
- typedef typename Traits::vertex_descriptor Vertex;
- typedef typename Traits::vertices_size_type VerticesSize;
- typedef typename Traits::vertex_iterator VertexIterator;
- typedef std::vector< Vertex > Stack;
- typedef std::vector< std::vector< Vertex > > ClosedMatrix;
- typedef hawick_circuits_from< Graph, Visitor, VertexIndexMap, Stack,
- ClosedMatrix, GetAdjacentVertices >
- SubAlgorithm;
- VerticesSize const n_vertices = num_vertices(graph);
- Stack stack;
- stack.reserve(n_vertices);
- ClosedMatrix closed(n_vertices);
- VertexIterator start, last;
- for (boost::tie(start, last) = vertices(graph); start != last; ++start)
- {
- // Note1: The sub algorithm may NOT be reused once it has been
- // called.
- // Note2: We reuse the Stack and the ClosedMatrix (after clearing
- // them) in each iteration to avoid redundant destruction and
- // construction. It would be strictly equivalent to have these as
- // member variables of the sub algorithm.
- SubAlgorithm sub_algo(
- graph, visitor, vertex_index_map, stack, closed, n_vertices);
- sub_algo(*start);
- stack.clear();
- typename ClosedMatrix::iterator row, last_row = closed.end();
- for (row = closed.begin(); row != last_row; ++row)
- row->clear();
- }
- }
- template < typename GetAdjacentVertices, typename Graph, typename Visitor >
- void call_hawick_circuits(
- Graph const& graph, BOOST_FWD_REF(Visitor) visitor)
- {
- call_hawick_circuits< GetAdjacentVertices >(graph,
- boost::forward< Visitor >(visitor), get(vertex_index, graph));
- }
- } // end namespace hawick_circuits_detail
- //! Enumerate all the elementary circuits in a directed multigraph.
- template < typename Graph, typename Visitor, typename VertexIndexMap >
- void hawick_circuits(BOOST_FWD_REF(Graph) graph, BOOST_FWD_REF(Visitor) visitor,
- BOOST_FWD_REF(VertexIndexMap) vertex_index_map)
- {
- hawick_circuits_detail::call_hawick_circuits<
- hawick_circuits_detail::get_all_adjacent_vertices >(
- boost::forward< Graph >(graph), boost::forward< Visitor >(visitor),
- boost::forward< VertexIndexMap >(vertex_index_map));
- }
- template < typename Graph, typename Visitor >
- void hawick_circuits(BOOST_FWD_REF(Graph) graph, BOOST_FWD_REF(Visitor) visitor)
- {
- hawick_circuits_detail::call_hawick_circuits<
- hawick_circuits_detail::get_all_adjacent_vertices >(
- boost::forward< Graph >(graph), boost::forward< Visitor >(visitor));
- }
- /*!
- * Same as `boost::hawick_circuits`, but duplicate circuits caused by parallel
- * edges will not be considered. Each circuit will be considered only once.
- */
- template < typename Graph, typename Visitor, typename VertexIndexMap >
- void hawick_unique_circuits(BOOST_FWD_REF(Graph) graph,
- BOOST_FWD_REF(Visitor) visitor,
- BOOST_FWD_REF(VertexIndexMap) vertex_index_map)
- {
- hawick_circuits_detail::call_hawick_circuits<
- hawick_circuits_detail::get_unique_adjacent_vertices >(
- boost::forward< Graph >(graph), boost::forward< Visitor >(visitor),
- boost::forward< VertexIndexMap >(vertex_index_map));
- }
- template < typename Graph, typename Visitor >
- void hawick_unique_circuits(
- BOOST_FWD_REF(Graph) graph, BOOST_FWD_REF(Visitor) visitor)
- {
- hawick_circuits_detail::call_hawick_circuits<
- hawick_circuits_detail::get_unique_adjacent_vertices >(
- boost::forward< Graph >(graph), boost::forward< Visitor >(visitor));
- }
- } // end namespace boost
- #endif // !BOOST_GRAPH_HAWICK_CIRCUITS_HPP
|