graph_bind.cc 18.7 KB
Newer Older
Tiago Peixoto's avatar
Tiago Peixoto committed
1
2
// graph-tool -- a general graph modification and manipulation thingy
//
Tiago Peixoto's avatar
Tiago Peixoto committed
3
// Copyright (C) 2006-2015 Tiago de Paula Peixoto <tiago@skewed.de>
Tiago Peixoto's avatar
Tiago Peixoto committed
4
5
6
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
Tiago Peixoto's avatar
Tiago Peixoto committed
7
// as published by the Free Software Foundation; either version 3
Tiago Peixoto's avatar
Tiago Peixoto committed
8
9
10
11
12
13
14
15
// 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
16
17
// along with this program. If not, see <http://www.gnu.org/licenses/>.

18
19
#include "graph.hh"
#include "graph_util.hh"
20

21
#define NUMPY_EXPORT
22
23
#include "numpy_bind.hh"

Tiago Peixoto's avatar
Tiago Peixoto committed
24
#include "graph_python_interface.hh"
Tiago Peixoto's avatar
Tiago Peixoto committed
25

26
27
#include "random.hh"

Tiago Peixoto's avatar
Tiago Peixoto committed
28
29
#ifdef HAVE_SCIPY // integration with scipy weave
#include "weave/scxx/object.h"
30
31
32
33
#include "weave/scxx/list.h"
#include "weave/scxx/tuple.h"
#include "weave/scxx/dict.h"
#include "weave/scxx/str.h"
Tiago Peixoto's avatar
Tiago Peixoto committed
34
35
#endif

Tiago Peixoto's avatar
Tiago Peixoto committed
36
37
#include <boost/python.hpp>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
38
#include <boost/python/stl_iterator.hpp>
Tiago Peixoto's avatar
Tiago Peixoto committed
39
40
#include "bytesobject.h"

Tiago Peixoto's avatar
Tiago Peixoto committed
41
42
43
44
45
using namespace std;
using namespace graph_tool;
using namespace boost;
using namespace boost::python;

46
struct LibInfo
Tiago Peixoto's avatar
Tiago Peixoto committed
47
{
48
49
50
51
52
53
    string GetName()      const {return PACKAGE_NAME;}
    string GetAuthor()    const {return AUTHOR;}
    string GetCopyright() const {return COPYRIGHT;}
    string GetVersion()   const {return VERSION " (commit " GIT_COMMIT
                                        ", " GIT_COMMIT_DATE ")";}
    string GetLicense()   const {return "GPL version 3 or above";}
Tiago Peixoto's avatar
Tiago Peixoto committed
54
    string GetCXXFLAGS()  const {return CPPFLAGS " " CXXFLAGS " " LDFLAGS;}
55
56
    string GetInstallPrefix() const {return INSTALL_PREFIX;}
    string GetPythonDir() const {return PYTHON_DIR;}
Tiago Peixoto's avatar
Tiago Peixoto committed
57
58
59
60
61
62
    string GetGCCVersion() const
    {
        stringstream s;
        s << __GNUC__ << "." << __GNUC_MINOR__ << "." <<  __GNUC_PATCHLEVEL__;
        return s.str();
    }
Tiago Peixoto's avatar
Tiago Peixoto committed
63
64
};

65

66
67
template <class ValueType>
struct vector_from_list
Tiago Peixoto's avatar
Tiago Peixoto committed
68
{
69
    vector_from_list()
Tiago Peixoto's avatar
Tiago Peixoto committed
70
    {
Tiago Peixoto's avatar
Tiago Peixoto committed
71
         boost::python::converter::registry::push_back
72
            (&convertible, &construct,
73
             boost::python::type_id<vector<ValueType> >());
Tiago Peixoto's avatar
Tiago Peixoto committed
74
75
76
77
    }

    static void* convertible(PyObject* obj_ptr)
    {
78
        // can't verify without potentially exhausting an iterator
79
        return obj_ptr;
Tiago Peixoto's avatar
Tiago Peixoto committed
80
81
    }

82
    static void construct(PyObject* obj_ptr,
Tiago Peixoto's avatar
Tiago Peixoto committed
83
                          boost::python::converter::rvalue_from_python_stage1_data* data)
84
    {
85
86
        python::handle<> x(python::borrowed(obj_ptr));
        python::object o(x);
87
        vector<ValueType> value;
88
89
90
        python::stl_input_iterator<ValueType> iter(o), end;
        for (; iter != end; ++iter)
            value.push_back(*iter);
91
        void* storage =
92
            ( (boost::python::converter::rvalue_from_python_storage
93
94
               <vector<ValueType> >*) data)->storage.bytes;
        new (storage) vector<ValueType>(value);
95
        data->convertible = storage;
Tiago Peixoto's avatar
Tiago Peixoto committed
96
97
98
    }
};

99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
template <class ValueType>
bool vector_equal_compare(const vector<ValueType>& v1,
                          const vector<ValueType>& v2)
{
    if (v1.size() != v2.size())
        return false;
    for (size_t i = 0; i < v1.size(); ++i)
    {
        if (v1[i] != v2[i])
            return false;
    }
    return true;
}

template <class ValueType>
bool vector_nequal_compare(const vector<ValueType>& v1,
                           const vector<ValueType>& v2)
{
    return !vector_equal_compare(v1,v2);
}

120
struct export_vector_types
Tiago Peixoto's avatar
Tiago Peixoto committed
121
{
122
    template <class ValueType>
123
    void operator()(ValueType, std::string type_name = "") const
Tiago Peixoto's avatar
Tiago Peixoto committed
124
    {
125
        if (type_name.empty())
126
127
            type_name = get_type_name<>()(typeid(ValueType));
        std::replace(type_name.begin(), type_name.end(), ' ', '_');
128
        string name = "Vector_" + type_name;
129
        class_<vector<ValueType> > vc(name.c_str());
130
        std::function<size_t(const vector<ValueType>&)> hasher =
131
132
133
134
135
136
137
138
139
140
            [] (const vector<ValueType>& v) -> size_t
            { return std::hash<vector<ValueType>>()(v); };
        std::function<void(vector<ValueType>&, size_t size)> resize =
            [] (vector<ValueType>& v, size_t n) { v.resize(n); };
        std::function<void(vector<ValueType>&, size_t n)> reserve =
            [] (vector<ValueType>& v, size_t n) { v.reserve(n); };
        std::function<void(vector<ValueType>&)> shrink_to_fit =
            [] (vector<ValueType>& v) { v.shrink_to_fit(); };
        std::function<bool(vector<ValueType>&)> empty =
            [] (vector<ValueType>& v) -> bool { return v.empty(); };
141
        vc.def(vector_indexing_suite<vector<ValueType> >())
142
            .def("__eq__", &vector_equal_compare<ValueType>)
143
            .def("__ne__", &vector_nequal_compare<ValueType>)
144
145
146
147
            .def("__hash__", hasher)
            .def("resize", resize)
            .def("shrink_to_fit", shrink_to_fit)
            .def("empty", empty);
Tiago Peixoto's avatar
Tiago Peixoto committed
148
        wrap_array(vc, typename boost::mpl::has_key<numpy_types,ValueType>::type());
149
        vector_from_list<ValueType>();
Tiago Peixoto's avatar
Tiago Peixoto committed
150
    }
151
152

    template <class ValueType>
Tiago Peixoto's avatar
Tiago Peixoto committed
153
    void wrap_array(class_<vector<ValueType> >& vc, boost::mpl::true_) const
154
155
156
157
158
    {
        vc.def("get_array", &wrap_vector_not_owned<ValueType>);
    }

    template <class ValueType>
159
    void wrap_array(class_<vector<ValueType> >&, boost::mpl::false_) const
160
161
    {
    }
162
};
Tiago Peixoto's avatar
Tiago Peixoto committed
163

164
165
// exception translation
template <class Exception>
Tiago Peixoto's avatar
Tiago Peixoto committed
166
void graph_exception_translator(const Exception& e)
167
{
Tiago Peixoto's avatar
Tiago Peixoto committed
168
    PyObject* error;
Tiago Peixoto's avatar
Tiago Peixoto committed
169
    if (std::is_same<Exception, GraphException>::value)
Tiago Peixoto's avatar
Tiago Peixoto committed
170
        error = PyExc_RuntimeError;
Tiago Peixoto's avatar
Tiago Peixoto committed
171
    if (std::is_same<Exception, IOException>::value)
Tiago Peixoto's avatar
Tiago Peixoto committed
172
        error = PyExc_IOError;
Tiago Peixoto's avatar
Tiago Peixoto committed
173
    if (std::is_same<Exception, ValueException>::value)
Tiago Peixoto's avatar
Tiago Peixoto committed
174
175
        error = PyExc_ValueError;
    PyErr_SetString(error, e.what());
176
}
Tiago Peixoto's avatar
Tiago Peixoto committed
177

178
179
180
181
void raise_error(const string& msg)
{
    throw GraphException(msg);
}
Tiago Peixoto's avatar
Tiago Peixoto committed
182

183
184
template <class T1, class T2>
struct pair_to_tuple
Tiago Peixoto's avatar
Tiago Peixoto committed
185
{
186
    static PyObject* convert(const pair<T1,T2>& p)
Tiago Peixoto's avatar
Tiago Peixoto committed
187
    {
188
189
        boost::python::tuple t = boost::python::make_tuple(p.first,p.second);
        return incref(t.ptr());
Tiago Peixoto's avatar
Tiago Peixoto committed
190
191
192
    }
};

193
194
195
196
197
198
199
200
201
202
203
204
205
template <class T1, class T2>
struct pair_from_tuple
{
    pair_from_tuple()
    {
        converter::registry::push_back(&convertible, &construct,
                                       boost::python::type_id<pair<T1,T2> >());
    }

    static void* convertible(PyObject* obj_ptr)
    {
        handle<> x(borrowed(obj_ptr));
        object o(x);
Tiago Peixoto's avatar
Tiago Peixoto committed
206
        if (boost::python::len(o) < 2)
207
            return 0;
208
209
210
211
212
213
214
215
216
217
218
219
220
        extract<T1> first(o[0]);
        extract<T2> second(o[1]);
        if (!first.check() || !second.check())
            return 0;
        return obj_ptr;
    }

    static void construct(PyObject* obj_ptr,
                          converter::rvalue_from_python_stage1_data* data)
    {
        handle<> x(borrowed(obj_ptr));
        object o(x);
        pair<T1,T2> value;
221
222
        value.first = extract<T1>(o[0])();
        value.second = extract<T2>(o[1])();
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
        void* storage =
            ( (boost::python::converter::rvalue_from_python_storage
               <pair<T1,T2> >*) data)->storage.bytes;
        new (storage) pair<T1,T2>(value);
        data->convertible = storage;
    }
};

template <class ValueType>
struct variant_from_python
{
    variant_from_python()
    {
        converter::registry::push_back
            (&convertible, &construct,
             boost::python::type_id<GraphInterface::deg_t>());
    }

    static void* convertible(PyObject* obj_ptr)
    {
        handle<> x(borrowed(obj_ptr));
        object o(x);
        extract<ValueType> str(o);
        if (!str.check())
            return 0;
        return obj_ptr;
    }

    static void construct(PyObject* obj_ptr,
                          converter::rvalue_from_python_stage1_data* data)
    {
        handle<> x(borrowed(obj_ptr));
        object o(x);
256
        ValueType value = extract<ValueType>(o)();
257
258
259
260
261
262
263
264
265
        GraphInterface::deg_t deg = value;
        void* storage =
            ( (boost::python::converter::rvalue_from_python_storage
               <GraphInterface::deg_t>*) data)->storage.bytes;
        new (storage) GraphInterface::deg_t(deg);
        data->convertible = storage;
    }
};

Tiago Peixoto's avatar
Tiago Peixoto committed
266
267
// scipy weave integration
#ifdef HAVE_SCIPY
268
template <class ScxxType>
Tiago Peixoto's avatar
Tiago Peixoto committed
269
270
struct scxx_to_python
{
271
    static PyObject* convert(const ScxxType& o)
Tiago Peixoto's avatar
Tiago Peixoto committed
272
273
274
275
276
277
    {
        return incref((PyObject*)(o));
    }
};
#endif

278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
template <class T>
struct integer_from_convertible
{
    integer_from_convertible()
    {
        converter::registry::push_back(&convertible, &construct,
                                       boost::python::type_id<T>());
    }

    static void* convertible(PyObject* obj_ptr)
    {
        if (PyObject_HasAttrString(obj_ptr, "__int__"))
            return obj_ptr;
        return 0;
    }

    static void construct(PyObject* obj_ptr,
                          converter::rvalue_from_python_stage1_data* data)
    {
        handle<> x(borrowed(obj_ptr));
        object o(x);
299
        T value = extract<T>(o.attr("__int__")())();
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
        void* storage =
            ( (boost::python::converter::rvalue_from_python_storage<T>*) data)->storage.bytes;
        new (storage) T(value);
        data->convertible = storage;
    }
};

template <class T>
struct float_from_convertible
{
    float_from_convertible()
    {
        converter::registry::push_back(&convertible, &construct,
                                       boost::python::type_id<T>());
    }

    static void* convertible(PyObject* obj_ptr)
    {
        if (PyObject_HasAttrString(obj_ptr, "__float__"))
            return obj_ptr;
        return 0;
    }

    static void construct(PyObject* obj_ptr,
                          converter::rvalue_from_python_stage1_data* data)
    {
        handle<> x(borrowed(obj_ptr));
        object o(x);
328
        T value = extract<T>(o.attr("__float__")())();
329
330
331
332
333
334
335
336
        void* storage =
            ( (boost::python::converter::rvalue_from_python_storage<T>*) data)->storage.bytes;
        new (storage) T(value);
        data->convertible = storage;
    }
};


337
338
339
340
341
342
343
// persistent python object IO
namespace graph_tool
{
extern python::object object_pickler;
extern python::object object_unpickler;
}

Tiago Peixoto's avatar
Tiago Peixoto committed
344
void set_pickler(boost::python::object o)
345
346
347
348
{
    graph_tool::object_pickler = o;
}

Tiago Peixoto's avatar
Tiago Peixoto committed
349
void set_unpickler(boost::python::object o)
350
351
352
353
{
    graph_tool::object_unpickler = o;
}

Tiago Peixoto's avatar
Tiago Peixoto committed
354
boost::python::list get_property_types()
Tiago Peixoto's avatar
Tiago Peixoto committed
355
{
Tiago Peixoto's avatar
Tiago Peixoto committed
356
357
    boost::python::list plist;
    for (int i = 0; i < boost::mpl::size<value_types>::value; ++i)
Tiago Peixoto's avatar
Tiago Peixoto committed
358
359
360
361
        plist.append(string(type_names[i]));
    return plist;
}

Tiago Peixoto's avatar
Tiago Peixoto committed
362
363
struct graph_type_name
{
Tiago Peixoto's avatar
Tiago Peixoto committed
364
    typedef void result_type;
Tiago Peixoto's avatar
Tiago Peixoto committed
365
    template <class Graph>
366
    void operator()(const Graph&, string& name) const
Tiago Peixoto's avatar
Tiago Peixoto committed
367
    {
Tiago Peixoto's avatar
Tiago Peixoto committed
368
        using boost::python::detail::gcc_demangle;
Tiago Peixoto's avatar
Tiago Peixoto committed
369
370
371
372
373
374
375
        name = string(gcc_demangle(typeid(Graph).name()));
    }
};

string get_graph_type(GraphInterface& g)
{
    string name;
Tiago Peixoto's avatar
Tiago Peixoto committed
376
377
    run_action<>()(g, std::bind(graph_type_name(), std::placeholders::_1,
                                std::ref(name)))();
Tiago Peixoto's avatar
Tiago Peixoto committed
378
379
380
    return name;
}

381
382
383
384
385
386
387
// numpy array interface weirdness
void* do_import_array()
{
    import_array1(NULL);
    return NULL;
}

388
389
390
391
void ungroup_vector_property(GraphInterface& g, boost::any vector_prop,
                             boost::any prop, size_t pos, bool edge);
void group_vector_property(GraphInterface& g, boost::any vector_prop,
                           boost::any prop, size_t pos, bool edge);
392
393
394
void property_map_values(GraphInterface& g, boost::any src_prop,
                         boost::any tgt_prop, boost::python::object mapper,
                         bool edge);
395
void infect_vertex_property(GraphInterface& gi, boost::any prop,
Tiago Peixoto's avatar
Tiago Peixoto committed
396
                            boost::python::object val);
397
398
void edge_endpoint(GraphInterface& gi, boost::any prop,
                   boost::any eprop, std::string endpoint);
399
400
void out_edges_op(GraphInterface& gi, boost::any eprop, boost::any vprop,
                  std::string op);
401
402
void mark_edges(GraphInterface& gi, boost::any prop);

Tiago Peixoto's avatar
Tiago Peixoto committed
403
404
405
406
void perfect_ehash(GraphInterface& gi, boost::any prop, boost::any hprop,
                   boost::any& dict);
void perfect_vhash(GraphInterface& gi, boost::any prop, boost::any hprop,
                   boost::any& dict);
407
408
409
410
void set_vertex_property(GraphInterface& gi, boost::any prop,
                         boost::python::object val);
void set_edge_property(GraphInterface& gi, boost::any prop,
                       boost::python::object val);
Tiago Peixoto's avatar
Tiago Peixoto committed
411
412


413
void export_python_interface();
414

415
416
void export_openmp();

417
BOOST_PYTHON_MODULE(libgraph_tool_core)
Tiago Peixoto's avatar
Tiago Peixoto committed
418
{
Tiago Peixoto's avatar
Tiago Peixoto committed
419
420
    using namespace boost::python;

421
    // numpy
422
    do_import_array();
423
    export_python_interface();
Tiago Peixoto's avatar
Tiago Peixoto committed
424

425
426
427
428
    // random numbers
    class_<rng_t>("rng_t");
    def("get_rng", get_rng);

Tiago Peixoto's avatar
Tiago Peixoto committed
429
430
431
432
433
434
    register_exception_translator<GraphException>
        (graph_exception_translator<GraphException>);
    register_exception_translator<IOException>
        (graph_exception_translator<IOException>);
    register_exception_translator<ValueException>
        (graph_exception_translator<ValueException>);
Tiago Peixoto's avatar
Tiago Peixoto committed
435

436
    def("raise_error", &raise_error);
Tiago Peixoto's avatar
Tiago Peixoto committed
437
    def("get_property_types", &get_property_types);
438
    class_<boost::any>("any")
439
440
441
442
443
444
445
        .def("empty", &boost::any::empty)
        .def("type",  &boost::any::type,
             return_value_policy<reference_existing_object>());
    class_<std::type_info, boost::noncopyable>("type_info", no_init)
        .def("name", &std::type_info::name)
        .def("hash_code", &std::type_info::hash_code);
    def("gcc_demangle", &python::detail::gcc_demangle);
446

447
    def("graph_filtering_enabled", &graph_filtering_enabled);
448
    export_openmp();
449

Tiago Peixoto's avatar
Tiago Peixoto committed
450
    boost::mpl::for_each<boost::mpl::push_back<scalar_types,string>::type>(export_vector_types());
451
    export_vector_types()(size_t(), "size_t");
452
453

    class_<GraphInterface>("GraphInterface", init<>())
Tiago Peixoto's avatar
Tiago Peixoto committed
454
455
        .def(init<GraphInterface,bool,boost::python::object,
                  boost::python::object, boost::python::object>())
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
        .def("get_num_vertices", &GraphInterface::get_num_vertices)
        .def("get_num_edges", &GraphInterface::get_num_edges)
        .def("set_directed", &GraphInterface::set_directed)
        .def("get_directed", &GraphInterface::get_directed)
        .def("set_reversed", &GraphInterface::set_reversed)
        .def("get_reversed", &GraphInterface::get_reversed)
        .def("set_keep_epos", &GraphInterface::set_keep_epos)
        .def("get_keep_epos", &GraphInterface::get_keep_epos)
        .def("set_vertex_filter_property",
             &GraphInterface::set_vertex_filter_property)
        .def("is_vertex_filter_active", &GraphInterface::is_vertex_filter_active)
        .def("set_edge_filter_property",
             &GraphInterface::set_edge_filter_property)
        .def("is_edge_filter_active", &GraphInterface::is_edge_filter_active)
        .def("purge_vertices",  &GraphInterface::purge_vertices)
        .def("purge_edges",  &GraphInterface::purge_edges)
        .def("shift_vertex_property",  &GraphInterface::shift_vertex_property)
        .def("move_vertex_property",  &GraphInterface::move_vertex_property)
        .def("re_index_vertex_property",  &GraphInterface::re_index_vertex_property)
        .def("write_to_file", &GraphInterface::write_to_file)
        .def("read_from_file",&GraphInterface::read_from_file)
        .def("degree_map", &GraphInterface::degree_map)
        .def("clear", &GraphInterface::clear)
        .def("clear_edges", &GraphInterface::clear_edges)
        .def("get_vertex_index", &GraphInterface::get_vertex_index)
        .def("get_edge_index", &GraphInterface::get_edge_index)
482
        .def("get_edge_index_range", &GraphInterface::get_edge_index_range)
483
        .def("re_index_edges", &GraphInterface::re_index_edges)
484
        .def("shrink_to_fit", &GraphInterface::shrink_to_fit)
485
486
487
        .def("get_graph_index", &GraphInterface::get_graph_index)
        .def("copy_vertex_property", &GraphInterface::copy_vertex_property)
        .def("copy_edge_property", &GraphInterface::copy_edge_property);
488

489
490
491
492
    class_<GraphInterface::vertex_index_map_t>("vertex_index_map", no_init);
    class_<GraphInterface::edge_index_map_t>("edge_index_map", no_init);
    class_<GraphInterface::graph_index_map_t>("graph_index_map", no_init);

493
494
495
496
497
    enum_<GraphInterface::degree_t>("Degree")
        .value("In", GraphInterface::IN_DEGREE)
        .value("Out", GraphInterface::OUT_DEGREE)
        .value("Total", GraphInterface::TOTAL_DEGREE);

498
    variant_from_python<boost::any>();
499
    variant_from_python<GraphInterface::degree_t>();
500
    to_python_converter<pair<string,bool>, pair_to_tuple<string,bool> >();
501
    to_python_converter<pair<size_t,size_t>, pair_to_tuple<size_t,size_t> >();
502
    to_python_converter<pair<double,double>, pair_to_tuple<double,double> >();
503
504
    pair_from_tuple<double,double>();
    pair_from_tuple<size_t,size_t>();
505
506
507
508
509
510
511
512
513
514
515
    integer_from_convertible<uint8_t>();
    integer_from_convertible<int32_t>();
    integer_from_convertible<int64_t>();
    integer_from_convertible<uint32_t>();
    integer_from_convertible<uint64_t>();
    integer_from_convertible<size_t>();
    integer_from_convertible<bool>();
    float_from_convertible<float>();
    float_from_convertible<double>();
    float_from_convertible<long double>();

Tiago Peixoto's avatar
Tiago Peixoto committed
516
#ifdef HAVE_SCIPY
517
518
519
520
521
    to_python_converter<py::object, scxx_to_python<py::object> >();
    to_python_converter<py::tuple, scxx_to_python<py::tuple> >();
    to_python_converter<py::list, scxx_to_python<py::list> >();
    to_python_converter<py::dict, scxx_to_python<py::dict> >();
    to_python_converter<py::str, scxx_to_python<py::str> >();
Tiago Peixoto's avatar
Tiago Peixoto committed
522
#endif
Tiago Peixoto's avatar
Tiago Peixoto committed
523

524
525
526
    class_<IStream>("IStream", no_init).def("read", &IStream::read);
    class_<OStream>("OStream", no_init).def("write", &OStream::write).
        def("flush", &OStream::flush);
527
528
529
    def("set_pickler", &set_pickler);
    def("set_unpickler", &set_unpickler);

530
531
    def("group_vector_property", &group_vector_property);
    def("ungroup_vector_property", &ungroup_vector_property);
532
    def("property_map_values", &property_map_values);
533
    def("infect_vertex_property", &infect_vertex_property);
534
    def("edge_endpoint", &edge_endpoint);
535
    def("out_edges_op", &out_edges_op);
536
    def("mark_edges", &mark_edges);
Tiago Peixoto's avatar
Tiago Peixoto committed
537
538
    def("perfect_ehash", &perfect_ehash);
    def("perfect_vhash", &perfect_vhash);
539
540
    def("set_vertex_property", &set_vertex_property);
    def("set_edge_property", &set_edge_property);
541

Tiago Peixoto's avatar
Tiago Peixoto committed
542
    class_<LibInfo>("mod_info")
543
544
545
        .add_property("name", &LibInfo::GetName)
        .add_property("author", &LibInfo::GetAuthor)
        .add_property("copyright", &LibInfo::GetCopyright)
546
        .add_property("version", &LibInfo::GetVersion)
547
548
549
        .add_property("license", &LibInfo::GetLicense)
        .add_property("cxxflags", &LibInfo::GetCXXFLAGS)
        .add_property("install_prefix", &LibInfo::GetInstallPrefix)
Tiago Peixoto's avatar
Tiago Peixoto committed
550
551
        .add_property("python_dir", &LibInfo::GetPythonDir)
        .add_property("gcc_version", &LibInfo::GetGCCVersion);
Tiago Peixoto's avatar
Tiago Peixoto committed
552
553

    def("get_graph_type", &get_graph_type);
Tiago Peixoto's avatar
Tiago Peixoto committed
554
}