graph_python_interface.cc 25.7 KB
Newer Older
1
2
// graph-tool -- a general graph modification and manipulation thingy
//
Tiago Peixoto's avatar
Tiago Peixoto committed
3
// Copyright (C) 2006-2017 Tiago de Paula Peixoto <tiago@skewed.de>
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// 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/>.

18
19
#include "graph_filtering.hh"
#include "graph.hh"
20
#include "graph_util.hh"
21
22
#include "graph_python_interface.hh"

23
#include <boost/python.hpp>
24
#include <boost/python/stl_iterator.hpp>
25
#include <set>
26

27

28
29
30
31
using namespace std;
using namespace boost;
using namespace graph_tool;

32
33
34
namespace graph_tool
{

35
36
37
struct get_vertex_iterator
{
    template <class Graph>
38
    void operator()(Graph& g, GraphInterface& gi,
39
40
                    python::object& iter) const
    {
41
        auto gp = retrieve_graph_view<Graph>(gi, g);
42
        typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
43
44
        iter = python::object(PythonIterator<Graph, PythonVertex<Graph>,
                                             vertex_iterator>(gp, vertices(g)));
45
46
47
    }
};

48
python::object get_vertices(GraphInterface& gi)
49
50
{
    python::object iter;
51
    run_action<>()(gi, std::bind(get_vertex_iterator(),
52
                                 std::placeholders::_1,
53
                                 std::ref(gi),
Tiago Peixoto's avatar
Tiago Peixoto committed
54
                                 std::ref(iter)))();
55
56
57
    return iter;
}

58
59
60
struct get_vertex_soft
{
    template <class Graph>
61
    void operator()(Graph& g, GraphInterface& gi, size_t i, python::object& v) const
62
    {
63
        auto gp = retrieve_graph_view<Graph>(gi, g);
64
65
66
67
68
        if (i < num_vertices(g))
            v = python::object(PythonVertex<Graph>(gp, vertex(i, g)));
        else
            v = python::object(PythonVertex<Graph>(gp,
                                                   graph_traits<Graph>::null_vertex()));
69
70
71
72
73
74
    }
};

struct get_vertex_hard
{
    template <class Graph>
75
    void operator()(Graph& g, GraphInterface& gi, size_t i, python::object& v) const
76
    {
77
        auto gp = retrieve_graph_view<Graph>(gi, g);
78
        size_t c = 0;
79
        for (auto vi : vertices_range(g))
80
81
        {
            if (c == i)
82
            {
83
                v = python::object(PythonVertex<Graph>(gp, vi));
84
85
                return;
            }
86
87
            ++c;
        }
88
89
        v = python::object(PythonVertex<Graph>(gp,
                                               graph_traits<Graph>::null_vertex()));
90
91
92
    }
};

93
python::object get_vertex(GraphInterface& gi, size_t i, bool use_index)
94
95
{
    python::object v;
96
    if (!use_index)
97
        run_action<>()(gi,
98
                       std::bind(get_vertex_hard(), std::placeholders::_1,
99
                                 std::ref(gi), i, std::ref(v)))();
100
    else
101
        run_action<>()(gi,
102
                       std::bind(get_vertex_soft(), std::placeholders::_1,
103
                                 std::ref(gi), i, std::ref(v)))();
104
105
106
    return v;
}

107
108
109
struct get_edge_iterator
{
    template <class Graph>
110
    void operator()(Graph& g, GraphInterface& gi, python::object& iter)
111
        const
112
    {
113
        auto gp = retrieve_graph_view<Graph>(gi, g);
114
        typedef typename graph_traits<Graph>::edge_iterator edge_iterator;
115
116
        iter = python::object(PythonIterator<Graph, PythonEdge<Graph>,
                                             edge_iterator>(gp, edges(g)));
117
118
119
    }
};

120
python::object get_edges(GraphInterface& gi)
121
122
{
    python::object iter;
123
    run_action<>()(gi, std::bind(get_edge_iterator(), std::placeholders::_1,
124
                                 std::ref(gi), std::ref(iter)))();
125
126
127
    return iter;
}

128
struct add_new_vertex
129
{
130
131
132
    template <class Graph>
    void operator()(Graph& g, GraphInterface& gi, size_t n,
                    python::object& new_v) const
133
    {
134
        auto gp = retrieve_graph_view<Graph>(gi, g);
135
        if (n != 1)
136
137
138
139
140
141
142
143
144
        {
            for (size_t i = 0; i < n; ++i)
                add_vertex(g);
            new_v = python::object();
        }
        else
        {
            new_v = python::object(PythonVertex<Graph>(gp, add_vertex(g)));
        }
145
    }
146
147
148
149
150
151
};


python::object add_vertex(GraphInterface& gi, size_t n)
{
    python::object v;
152
    run_action<>()(gi, std::bind(add_new_vertex(), std::placeholders::_1,
153
154
                                 std::ref(gi), n, std::ref(v)))();
    return v;
155
156
157
}


158
void remove_vertex_array(GraphInterface& gi, const python::object& oindex, bool fast)
159
{
160
    boost::multi_array_ref<int64_t,1> index = get_array<int64_t,1>(oindex);
161
    auto& g = gi.get_graph();
162
    if (fast)
163
164
165
166
    {
        for (auto v : index)
            remove_vertex_fast(vertex(v, g), g);
    }
167
    else
168
169
170
171
    {
        for (auto v : index)
            remove_vertex(vertex(v, g), g);
    }
172
173
}

174
175
void remove_vertex(GraphInterface& gi, size_t v, bool fast)
{
176
    auto& g = gi.get_graph();
177
178
179
180
181
182
183
184
185
186
    if (fast)
    {
        remove_vertex_fast(vertex(v, g), g);
    }
    else
    {
        remove_vertex(vertex(v, g), g);
    }
}

187
188
189
190
191
192
193
194
195
196
197
struct do_clear_vertex
{
    template <class Graph>
    void operator()(Graph& g, size_t v) const
    {
        clear_vertex(vertex(v, g), g);
    }
};

void clear_vertex(GraphInterface& gi, size_t v)
{
198
    run_action<>()(gi, std::bind(do_clear_vertex(), std::placeholders::_1, v))();
199
}
200

201
202
struct add_new_edge
{
203
204
205
    template <class Graph>
    void operator()(Graph& g, GraphInterface& gi, size_t s, size_t t,
                    python::object& new_e) const
206
    {
207
        auto gp = retrieve_graph_view<Graph>(gi, g);
208
209
        auto e = add_edge(vertex(s, g), vertex(t, g), g).first;
        new_e = python::object(PythonEdge<Graph>(gp, e));
210
211
212
    }
};

213
python::object add_edge(GraphInterface& gi, size_t s, size_t t)
214
215
{
    python::object new_e;
216
    run_action<>()(gi, std::bind(add_new_edge(), std::placeholders::_1, std::ref(gi),
217
                                 s, t, std::ref(new_e)))();
218
219
220
    return new_e;
}

Tiago Peixoto's avatar
Tiago Peixoto committed
221
void remove_edge(GraphInterface& gi, EdgeBase& e)
222
{
Tiago Peixoto's avatar
Tiago Peixoto committed
223
224
225
226
    e.check_valid();
    auto edge = e.get_descriptor();
    run_action<>()(gi, [&](auto& g) { remove_edge(edge, g); })();
    e.invalidate();
227
228
}

229
230
231
struct get_edge_dispatch
{
    template <class Graph>
232
    void operator()(Graph& g, GraphInterface& gi, size_t s, size_t t,
233
234
                    bool all_edges, boost::python::list& es) const
    {
235
        auto gp = retrieve_graph_view<Graph>(gi, g);
236
        size_t k_t = graph_tool::is_directed(g) ?
237
238
            in_degreeS()(t, g) : out_degree(t, g);
        if (out_degree(s, g) <= k_t)
239
        {
240
            for (auto e : out_edges_range(vertex(s, g), g))
241
            {
242
243
244
245
246
247
248
249
250
251
252
253
                if (target(e, g) == vertex(t, g))
                {
                    es.append(PythonEdge<Graph>(gp, e));
                    if (!all_edges)
                        break;
                }
            }
        }
        else
        {
            for (auto e : in_or_out_edges_range(vertex(t, g), g))
            {
254
                auto w = graph_tool::is_directed(g) ?
255
256
257
                    source(e, g) : target(e, g);
                if (w == vertex(s, g))
                {
258
                    if (!graph_tool::is_directed(g) && e.s != s)
259
                        std::swap(e.s, e.t);
260
261
262
263
                    es.append(PythonEdge<Graph>(gp, e));
                    if (!all_edges)
                        break;
                }
264
265
266
267
268
            }
        }
    }
};

269
python::object get_edge(GraphInterface& gi, size_t s, size_t t, bool all_edges)
270
271
{
    python::list es;
272
    run_action<>()(gi, std::bind(get_edge_dispatch(), std::placeholders::_1,
273
274
                                 std::ref(gi), s, t, all_edges,
                                 std::ref(es)))();
275
276
277
278
    return es;
}


279
280
struct get_degree_map
{
281
282
    template <class Graph, class DegS, class Weight>
    void operator()(const Graph& g, python::object& odeg_map, DegS deg, Weight weight) const
283
    {
284
        typedef typename detail::get_weight_type<Weight>::type weight_t;
Tiago Peixoto's avatar
Tiago Peixoto committed
285
        typedef typename mpl::if_<std::is_same<weight_t, size_t>, int32_t, weight_t>::type deg_t;
286

287
        typedef typename vprop_map_t<deg_t>::type map_t;
288
289
290
291

        map_t cdeg_map(get(vertex_index, g));
        typename map_t::unchecked_t deg_map = cdeg_map.get_unchecked(num_vertices(g));

Tiago Peixoto's avatar
Tiago Peixoto committed
292
293
294
295
296
297
        parallel_vertex_loop
            (g,
             [&](auto v)
             {
                 deg_map[v] = deg(v, g, weight);
             });
298
299

        odeg_map = python::object(PythonPropertyMap<map_t>(cdeg_map));
300
301
302
    }
};

303
python::object GraphInterface::degree_map(string deg, boost::any weight) const
304
305
{

306
307
    python::object deg_map;

308
309
    typedef mpl::push_back<edge_scalar_properties,
                           detail::no_weightS>::type weight_t;
310
311
    if (weight.empty())
        weight = detail::no_weightS();
312
313

    if (deg == "in")
314
        run_action<>()(const_cast<GraphInterface&>(*this),
315
316
                       std::bind(get_degree_map(), std::placeholders::_1,
                                 std::ref(deg_map), in_degreeS(), std::placeholders::_2), weight_t())
317
            (weight);
318
    else if (deg == "out")
319
        run_action<>()(const_cast<GraphInterface&>(*this),
320
321
                       std::bind(get_degree_map(), std::placeholders::_1,
                                 std::ref(deg_map), out_degreeS(), std::placeholders::_2), weight_t())
322
            (weight);
323
    else if (deg == "total")
324
        run_action<>()(const_cast<GraphInterface&>(*this),
325
326
                       std::bind(get_degree_map(), std::placeholders::_1,
                                 std::ref(deg_map), total_degreeS(), std::placeholders::_2), weight_t())
327
328
            (weight);
    return deg_map;
329
330
}

331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
python::object get_vertex_list(GraphInterface& gi)
{
    std::vector<size_t> vlist;
    vlist.reserve(gi.get_num_vertices());
    run_action<>()(gi,
                   [&](auto& g)
                   {
                       for (auto v: vertices_range(g))
                           vlist.push_back(v);
                   })();
    return wrap_vector_owned(vlist);
}

python::object get_edge_list(GraphInterface& gi)
{
    std::vector<size_t> elist;
    run_action<>()(gi,
                   [&](auto& g)
                   {
                       auto edge_index = get(edge_index_t(), g);
                       for (auto e: edges_range(g))
                       {
                           elist.push_back(source(e, g));
                           elist.push_back(target(e, g));
                           elist.push_back(edge_index[e]);
                       }
                   })();
    return wrap_vector_owned(elist);
}

python::object get_out_edge_list(GraphInterface& gi, size_t v)
{
    std::vector<size_t> elist;
    run_action<>()(gi,
                   [&](auto& g)
                   {
                       if (!is_valid_vertex(v, g))
                           throw ValueException("invalid vertex: " +
                                                lexical_cast<string>(v));
                       auto edge_index = get(edge_index_t(), g);
                       elist.reserve(3 * out_degree(v, g));
                       for (auto e: out_edges_range(v, g))
                       {
                           elist.push_back(source(e, g));
                           elist.push_back(target(e, g));
                           elist.push_back(edge_index[e]);
                       }
                   })();
    return wrap_vector_owned(elist);
}

python::object get_in_edge_list(GraphInterface& gi, size_t v)
{
    std::vector<size_t> elist;
    run_action<>()(gi,
                   [&](auto& g)
                   {
                       if (!is_valid_vertex(v, g))
                           throw ValueException("invalid vertex: " +
                                                lexical_cast<string>(v));
                       auto edge_index = get(edge_index_t(), g);
                       elist.reserve(3 * in_degree(v, g));
                       for (auto e: in_edges_range(v, g))
                       {
                           elist.push_back(source(e, g));
                           elist.push_back(target(e, g));
                           elist.push_back(edge_index[e]);
                       }
                   })();
    return wrap_vector_owned(elist);
}

403
python::object get_out_neighbors_list(GraphInterface& gi, size_t v)
404
405
406
407
408
409
410
411
412
{
    std::vector<size_t> vlist;
    run_action<>()(gi,
                   [&](auto& g)
                   {
                       if (!is_valid_vertex(v, g))
                           throw ValueException("invalid vertex: " +
                                                lexical_cast<string>(v));
                       vlist.reserve(out_degree(v, g));
413
                       for (auto u: out_neighbors_range(v, g))
414
415
416
417
418
                           vlist.push_back(u);
                   })();
    return wrap_vector_owned(vlist);
}

419
python::object get_in_neighbors_list(GraphInterface& gi, size_t v)
420
421
422
423
424
425
426
427
428
{
    std::vector<size_t> vlist;
    run_action<>()(gi,
                   [&](auto& g)
                   {
                       if (!is_valid_vertex(v, g))
                           throw ValueException("invalid vertex: " +
                                                lexical_cast<string>(v));
                       vlist.reserve(in_degree(v, g));
429
                       for (auto u: in_neighbors_range(v, g))
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
                           vlist.push_back(u);
                   })();
    return wrap_vector_owned(vlist);
}

python::object get_degree_list(GraphInterface& gi, python::object ovlist,
                               boost::any eprop, bool out)
{
    python::object ret;
    auto vlist = get_array<uint64_t,1>(ovlist);

    typedef UnityPropertyMap<size_t,
                             graph_traits<GraphInterface::multigraph_t>::edge_descriptor>
        empty_t;
    if (eprop.empty())
    {
        eprop = empty_t();
    }
    else
    {
        if (!belongs<edge_scalar_properties>()(eprop))
            throw ValueException("edge weight property map must be of scalar type");
    }

    typedef mpl::push_back<edge_scalar_properties,
                           empty_t>::type eprops_t;

    auto get_degs = [&](auto deg)
        {
            run_action<>()(gi,
                           [&](auto& g, auto& ew)
                           {
                               typedef typename std::remove_reference
                                   <decltype(ew)>::type::value_type val_t;
                               std::vector<val_t> dlist;
                               dlist.reserve(vlist.size());
                               for (auto v : vlist)
                               {
                                   if (!is_valid_vertex(v, g))
                                       throw ValueException("invalid vertex: " +
                                                            lexical_cast<string>(v));
                                   dlist.push_back(val_t(deg(v, g, ew)));
                               }
                               ret = wrap_vector_owned(dlist);
                           }, eprops_t())(eprop);
        };

    if (out)
        get_degs(out_degreeS());
    else
        get_degs(in_degreeS());

    return ret;
}

485
486
487
488
489
//
// Below are the functions with will properly register all the types to python,
// for every filter, type, etc.
//

490
491
492
// this will register all the Vertex/Edge classes to python
struct export_python_interface
{
493
494
495
    template <class Graph, class GraphViews>
    void operator()(Graph* gp, python::list vclasses,
                    python::list eclasses, GraphViews) const
496
497
    {
        using namespace boost::python;
498

499
500
        class_<PythonVertex<Graph>, bases<VertexBase>> vclass("Vertex", no_init);
        vclass
501
            .def("__in_degree", &PythonVertex<Graph>::get_in_degree,
502
                 "Return the in-degree.")
503
            .def("__weighted_in_degree", &PythonVertex<Graph>::get_weighted_in_degree,
504
                 "Return the weighted in-degree.")
505
            .def("__out_degree", &PythonVertex<Graph>::get_out_degree,
506
                 "Return the out-degree.")
507
            .def("__weighted_out_degree", &PythonVertex<Graph>::get_weighted_out_degree,
508
                 "Return the weighted out-degree.")
509
            .def("in_edges", &PythonVertex<Graph>::in_edges,
510
                 "Return an iterator over the in-edges.")
511
            .def("out_edges", &PythonVertex<Graph>::out_edges,
512
                 "Return an iterator over the out-edges.")
513
            .def("is_valid", &PythonVertex<Graph>::is_valid,
514
                 "Return whether the vertex is valid.")
515
516
517
518
519
            .def("graph_ptr", &PythonVertex<Graph>::get_graph_ptr)
            .def("graph_type", &PythonVertex<Graph>::get_graph_type)
            .def("__str__", &PythonVertex<Graph>::get_string)
            .def("__int__", &PythonVertex<Graph>::get_index)
            .def("__hash__", &PythonVertex<Graph>::get_hash);
520
521
522
523
524

        vclasses.append(vclass);

        class_<PythonEdge<Graph>, bases<EdgeBase>> eclass("Edge", no_init);
        eclass
525
            .def("source", &PythonEdge<Graph>::get_source,
526
                 "Return the source vertex.")
527
            .def("target", &PythonEdge<Graph>::get_target,
528
                 "Return the target vertex.")
529
            .def("is_valid", &PythonEdge<Graph>::is_valid,
530
                 "Return whether the edge is valid.")
531
532
            .def("graph_ptr", &PythonEdge<Graph>::get_graph_ptr)
            .def("graph_type", &PythonEdge<Graph>::get_graph_type)
533
534
            .def("__str__", &PythonEdge<Graph>::get_string)
            .def("__hash__", &PythonEdge<Graph>::get_hash);
535

536
537
538
539
540
541
        boost::mpl::for_each<GraphViews>(std::bind(export_python_interface(),
                                                   gp, std::placeholders::_1,
                                                   std::ref(eclass)));

        eclasses.append(eclass);

542
        typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
543
544
545
546
        class_<PythonIterator<Graph, PythonVertex<Graph>, vertex_iterator> >
            ("VertexIterator", no_init)
            .def("__iter__", objects::identity_function())
            .def("__next__", &PythonIterator<Graph, PythonVertex<Graph>,
547
                                             vertex_iterator>::next)
548
            .def("next", &PythonIterator<Graph, PythonVertex<Graph>,
549
                                         vertex_iterator>::next);
550

551
        typedef typename graph_traits<Graph>::edge_iterator edge_iterator;
552
        class_<PythonIterator<Graph, PythonEdge<Graph>,
553
554
                              edge_iterator> >("EdgeIterator", no_init)
            .def("__iter__", objects::identity_function())
555
            .def("__next__", &PythonIterator<Graph, PythonEdge<Graph>,
556
                                             edge_iterator>::next)
557
            .def("next", &PythonIterator<Graph, PythonEdge<Graph>,
558
                                         edge_iterator>::next);
559
560
561

        typedef typename graph_traits<Graph>::out_edge_iterator
            out_edge_iterator;
562
        class_<PythonIterator<Graph, PythonEdge<Graph>,
563
564
                              out_edge_iterator> >("OutEdgeIterator", no_init)
            .def("__iter__", objects::identity_function())
565
            .def("__next__", &PythonIterator<Graph, PythonEdge<Graph>,
566
                                             out_edge_iterator>::next)
567
            .def("next", &PythonIterator<Graph, PythonEdge<Graph>,
568
                                         out_edge_iterator>::next);
569
570
571

        typedef typename graph_traits<Graph>::directed_category
            directed_category;
Tiago Peixoto's avatar
Tiago Peixoto committed
572
573
        typedef typename std::is_convertible<directed_category,
                                             boost::directed_tag>::type is_directed;
574
575
576
        if (is_directed::value)
        {
            typedef typename in_edge_iteratorS<Graph>::type in_edge_iterator;
577
            class_<PythonIterator<Graph, PythonEdge<Graph>,
578
579
                                  in_edge_iterator> >("InEdgeIterator", no_init)
                .def("__iter__", objects::identity_function())
580
                .def("__next__", &PythonIterator<Graph, PythonEdge<Graph>,
581
                                                 in_edge_iterator>::next)
582
                .def("next", &PythonIterator<Graph, PythonEdge<Graph>,
583
                                             in_edge_iterator>::next);
584
585
        }
    }
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622

    template <class Graph, class OGraph, class Eclass>
    void operator()(Graph*, OGraph*, Eclass& eclass) const
    {
        std::function<bool(const PythonEdge<Graph>&,
                           const PythonEdge<OGraph>&)> eq =
            [] (const PythonEdge<Graph>& e1,
                const PythonEdge<OGraph>& e2) -> bool { return e1 == e2; };
        std::function<bool(const PythonEdge<Graph>& e1,
                           const PythonEdge<OGraph>&)> ne =
            [] (const PythonEdge<Graph>& e1,
                const PythonEdge<OGraph>& e2) -> bool { return e1 != e2; };
        std::function<bool(const PythonEdge<Graph>&,
                           const PythonEdge<OGraph>&)> gt =
            [] (const PythonEdge<Graph>& e1,
                const PythonEdge<OGraph>& e2) -> bool { return e1 > e2; };
        std::function<bool(const PythonEdge<Graph>&,
                           const PythonEdge<OGraph>&)> lt =
            [] (const PythonEdge<Graph>& e1,
                const PythonEdge<OGraph>& e2) -> bool { return e1 < e2; };
        std::function<bool(const PythonEdge<Graph>&,
                           const PythonEdge<OGraph>&)> ge =
            [] (const PythonEdge<Graph>& e1,
                const PythonEdge<OGraph>& e2) -> bool { return e1 >= e2; };
        std::function<bool(const PythonEdge<Graph>&,
                           const PythonEdge<OGraph>&)> le =
            [] (const PythonEdge<Graph>& e1,
                const PythonEdge<OGraph>& e2) -> bool { return e1 <= e2; };

        eclass
            .def("__eq__", eq)
            .def("__ne__", ne)
            .def("__lt__", lt)
            .def("__gt__", gt)
            .def("__le__", le)
            .def("__ge__", ge);
    }
623
624
};

625
626
627
628
PythonPropertyMap<GraphInterface::vertex_index_map_t>
get_vertex_index(GraphInterface& g)
{
    return PythonPropertyMap<GraphInterface::vertex_index_map_t>
629
        (g.get_vertex_index());
630
631
632
}

PythonPropertyMap<GraphInterface::edge_index_map_t>
633
do_get_edge_index(GraphInterface& g)
634
635
{
    return PythonPropertyMap<GraphInterface::edge_index_map_t>
636
        (g.get_edge_index());
637
638
}

639
void do_add_edge_list(GraphInterface& gi, python::object aedge_list,
640
                      python::object eprops);
641
642

void do_add_edge_list_hashed(GraphInterface& gi, python::object aedge_list,
643
                             boost::any& vertex_map, bool is_str,
644
                             python::object eprops);
645
646

void do_add_edge_list_iter(GraphInterface& gi, python::object edge_list,
647
                           python::object eprops);
648

649
650
} // namespace graph_tool

651
652
// register everything

653
654
void export_python_properties();

655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
python::list* _vlist(0);
python::list* _elist(0);

python::list get_vlist()
{
    if (_vlist == nullptr)
        _vlist = new python::list();
    return *_vlist;
}

python::list get_elist()
{
    if (_elist == nullptr)
        _elist = new python::list();
    return *_elist;
}

672
void export_python_interface()
673
{
674
675
    using namespace boost::python;

676
    class_<VertexBase>("VertexBase", no_init);
Tiago Peixoto's avatar
Tiago Peixoto committed
677
    class_<EdgeBase, boost::noncopyable>("EdgeBase", no_init);
678

679
    typedef boost::mpl::transform<graph_tool::all_graph_views,
680
                                  boost::mpl::quote1<std::add_const> >::type const_graph_views;
681
    typedef boost::mpl::transform<graph_tool::all_graph_views,
682
683
684
685
                                  boost::mpl::quote1<std::add_pointer> >::type all_graph_views;
    typedef boost::mpl::transform<const_graph_views,
                                  boost::mpl::quote1<std::add_pointer> >::type all_const_graph_views;
    typedef boost::mpl::joint_view<all_graph_views, all_const_graph_views>::type graph_views;
Tiago Peixoto's avatar
Tiago Peixoto committed
686
    boost::mpl::for_each<graph_views>(std::bind(graph_tool::export_python_interface(),
687
                                                std::placeholders::_1, get_vlist(),
688
                                                get_elist(), graph_views()));
689
    export_python_properties();
690
691
692
693
694
695
    def("new_vertex_property",
        &new_property<GraphInterface::vertex_index_map_t>);
    def("new_edge_property", &new_property<GraphInterface::edge_index_map_t>);
    def("new_graph_property",
        &new_property<ConstantPropertyMap<size_t,graph_property_tag> >);

696
697
698
699
700
701
    def("get_vertex", get_vertex);
    def("get_vertices", get_vertices);
    def("get_edges", get_edges);
    def("add_vertex", graph_tool::add_vertex);
    def("add_edge", graph_tool::add_edge);
    def("remove_vertex", graph_tool::remove_vertex);
702
    def("remove_vertex_array", graph_tool::remove_vertex_array);
703
    def("clear_vertex", graph_tool::clear_vertex);
704
    def("remove_edge", graph_tool::remove_edge);
705
    def("add_edge_list", graph_tool::do_add_edge_list);
706
    def("add_edge_list_hashed", graph_tool::do_add_edge_list_hashed);
707
    def("add_edge_list_iter", graph_tool::do_add_edge_list_iter);
708
    def("get_edge", get_edge);
709

710
711
712
713
    def("get_vertex_list", get_vertex_list);
    def("get_edge_list", get_edge_list);
    def("get_out_edge_list", get_out_edge_list);
    def("get_in_edge_list", get_in_edge_list);
714
715
    def("get_out_neighbors_list", get_out_neighbors_list);
    def("get_in_neighbors_list", get_in_neighbors_list);
716
717
    def("get_degree_list", get_degree_list);

718
    def("get_vertex_index", get_vertex_index);
719
    def("get_edge_index", do_get_edge_index);
720
721
722

    def("get_vlist", get_vlist);
    def("get_elist", get_elist);
723
724
725
726
727
728
729

#ifdef HAVE_BOOST_COROUTINE
    class_<CoroGenerator>("CoroGenerator", no_init)
        .def("__iter__", objects::identity_function())
        .def("next", &CoroGenerator::next)
        .def("__next__", &CoroGenerator::next);
#endif
730
}