graph_dfs.cc 4.86 KB
Newer Older
Tiago Peixoto's avatar
Tiago Peixoto committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

#include "graph_filtering.hh"
#include "graph_python_interface.hh"

#include <boost/python.hpp>
#include <boost/graph/depth_first_search.hpp>
#include <boost/graph/undirected_dfs.hpp>

#include "graph.hh"
#include "graph_selectors.hh"
#include "graph_util.hh"

19 20
#include "coroutine.hh"
#include "graph_python_interface.hh"
21

Tiago Peixoto's avatar
Tiago Peixoto committed
22 23 24 25 26 27 28 29
using namespace std;
using namespace boost;
using namespace graph_tool;


class DFSVisitorWrapper
{
public:
30
    DFSVisitorWrapper(GraphInterface& gi, python::object vis)
Tiago Peixoto's avatar
Tiago Peixoto committed
31 32 33 34
        : _gi(gi), _vis(vis) {}


    template <class Vertex, class Graph>
35
    void initialize_vertex(Vertex u, Graph& g)
Tiago Peixoto's avatar
Tiago Peixoto committed
36
    {
37
        auto gp = retrieve_graph_view<Graph>(_gi, g);
38
        _vis.attr("initialize_vertex")(PythonVertex<Graph>(gp, u));
Tiago Peixoto's avatar
Tiago Peixoto committed
39 40
    }
    template <class Vertex, class Graph>
41
    void start_vertex(Vertex u, Graph& g)
Tiago Peixoto's avatar
Tiago Peixoto committed
42
    {
43
        auto gp = retrieve_graph_view<Graph>(_gi, g);
44
        _vis.attr("start_vertex")(PythonVertex<Graph>(gp, u));
Tiago Peixoto's avatar
Tiago Peixoto committed
45 46
    }
    template <class Vertex, class Graph>
47
    void discover_vertex(Vertex u, Graph& g)
Tiago Peixoto's avatar
Tiago Peixoto committed
48
    {
49
        auto gp = retrieve_graph_view<Graph>(_gi, g);
50
        _vis.attr("discover_vertex")(PythonVertex<Graph>(gp, u));
Tiago Peixoto's avatar
Tiago Peixoto committed
51 52 53
    }

    template <class Edge, class Graph>
54
    void examine_edge(Edge e, Graph& g)
Tiago Peixoto's avatar
Tiago Peixoto committed
55
    {
56
        auto gp = retrieve_graph_view<Graph>(_gi, g);
57
        _vis.attr("examine_edge")(PythonEdge<Graph>(gp, e));
Tiago Peixoto's avatar
Tiago Peixoto committed
58 59 60
    }

    template <class Edge, class Graph>
61
    void tree_edge(Edge e, Graph& g)
Tiago Peixoto's avatar
Tiago Peixoto committed
62
    {
63
        auto gp = retrieve_graph_view<Graph>(_gi, g);
64
        _vis.attr("tree_edge")(PythonEdge<Graph>(gp, e));
Tiago Peixoto's avatar
Tiago Peixoto committed
65 66 67
    }

    template <class Edge, class Graph>
68
    void back_edge(Edge e, Graph& g)
Tiago Peixoto's avatar
Tiago Peixoto committed
69
    {
70
        auto gp = retrieve_graph_view<Graph>(_gi, g);
71
        _vis.attr("back_edge")(PythonEdge<Graph>(gp, e));
Tiago Peixoto's avatar
Tiago Peixoto committed
72 73 74
    }

    template <class Edge, class Graph>
75
    void forward_or_cross_edge(Edge e, Graph& g)
Tiago Peixoto's avatar
Tiago Peixoto committed
76
    {
77
        auto gp = retrieve_graph_view<Graph>(_gi, g);
78
        _vis.attr("forward_or_cross_edge")(PythonEdge<Graph>(gp, e));
Tiago Peixoto's avatar
Tiago Peixoto committed
79 80 81
    }

    template <class Vertex, class Graph>
82
    void finish_vertex(Vertex u, Graph& g)
Tiago Peixoto's avatar
Tiago Peixoto committed
83
    {
84
        auto gp = retrieve_graph_view<Graph>(_gi, g);
85
        _vis.attr("finish_vertex")(PythonVertex<Graph>(gp, u));
Tiago Peixoto's avatar
Tiago Peixoto committed
86 87 88
    }

private:
89 90
    GraphInterface& _gi;
    python::object _vis;
Tiago Peixoto's avatar
Tiago Peixoto committed
91 92
};

93
void dfs_search(GraphInterface& gi, size_t s, python::object vis)
Tiago Peixoto's avatar
Tiago Peixoto committed
94
{
95 96 97 98 99 100 101 102 103 104 105 106 107 108
    run_action<graph_tool::all_graph_views, mpl::true_>()
        (gi,
         [&](auto &g)
         {
             typedef typename std::remove_reference<decltype(g)>::type g_t;
             typename vprop_map_t<default_color_type>::type
                 color(get(vertex_index_t(), g));
             auto visw = DFSVisitorWrapper(gi, vis);
             auto v = vertex(s, g);
             if (v == graph_traits<g_t>::null_vertex())
                 depth_first_search(g, visw, color);
             else
                 depth_first_visit(g, v, visw, color);
         })();
Tiago Peixoto's avatar
Tiago Peixoto committed
109 110
}

111
#ifdef HAVE_BOOST_COROUTINE
112 113 114 115 116 117 118 119 120 121 122

class DFSGeneratorVisitor : public dfs_visitor<>
{
public:
    DFSGeneratorVisitor(GraphInterface& gi,
                        coro_t::push_type& yield)
        : _gi(gi), _yield(yield) {}

    template <class Edge, class Graph>
    void tree_edge(const Edge& e, Graph& g)
    {
123
        auto gp = retrieve_graph_view<Graph>(_gi, g);
124 125 126 127 128 129 130 131
        _yield(boost::python::object(PythonEdge<Graph>(gp, e)));
    }

private:
    GraphInterface& _gi;
    coro_t::push_type& _yield;
};

132 133 134
#endif // HAVE_BOOST_COROUTINE


135 136
boost::python::object dfs_search_generator(GraphInterface& g, size_t s)
{
Tiago Peixoto's avatar
Tiago Peixoto committed
137
#ifdef HAVE_BOOST_COROUTINE
138 139 140
    auto dispatch = [&](auto& yield)
        {
            DFSGeneratorVisitor vis(g, yield);
141
            run_action<graph_tool::all_graph_views,mpl::true_>()
142 143 144 145 146 147 148 149 150 151 152 153
                (g,
                 [&](auto &g)
                 {
                     typedef typename std::remove_reference<decltype(g)>::type g_t;
                     typename vprop_map_t<default_color_type>::type
                         color(get(vertex_index_t(), g));
                     auto v = vertex(s, g);
                     if (v == graph_traits<g_t>::null_vertex())
                         depth_first_search(g, vis, color);
                     else
                         depth_first_visit(g, v, vis, color);
                 })();
154
        };
155
    return boost::python::object(CoroGenerator(dispatch));
Tiago Peixoto's avatar
Tiago Peixoto committed
156
#else
157
    throw GraphException("This functionality is not available because boost::coroutine was not found at compile-time");
Tiago Peixoto's avatar
Tiago Peixoto committed
158
#endif
159 160
}

Tiago Peixoto's avatar
Tiago Peixoto committed
161 162 163 164
void export_dfs()
{
    using namespace boost::python;
    def("dfs_search", &dfs_search);
165
    def("dfs_search_generator", &dfs_search_generator);
Tiago Peixoto's avatar
Tiago Peixoto committed
166
}