diff DEPENDENCIES/generic/include/boost/graph/hawick_circuits.hpp @ 16:2665513ce2d3

Add boost headers
author Chris Cannam
date Tue, 05 Aug 2014 11:11:38 +0100
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DEPENDENCIES/generic/include/boost/graph/hawick_circuits.hpp	Tue Aug 05 11:11:38 2014 +0100
@@ -0,0 +1,381 @@
+// 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