graph_bind.cc 12.2 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) 2007  Tiago de Paula Peixoto <tiago@forked.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/>.

Tiago Peixoto's avatar
Tiago Peixoto committed
18
#include "graph.hh"
19
#include "graph_python_interface.hh"
20
#include "graph_util.hh"
21
22
#define NUMPY_EXPORT
#include "numpy_bind.hh"
Tiago Peixoto's avatar
Tiago Peixoto committed
23

24
25
26
#include <boost/python.hpp>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>

Tiago Peixoto's avatar
Tiago Peixoto committed
27
28
#ifdef HAVE_SCIPY // integration with scipy weave
#include "weave/scxx/object.h"
29
30
31
32
#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
33
34
#endif

Tiago Peixoto's avatar
Tiago Peixoto committed
35
36
37
38
39
using namespace std;
using namespace graph_tool;
using namespace boost;
using namespace boost::python;

40
struct LibInfo
Tiago Peixoto's avatar
Tiago Peixoto committed
41
{
42
43
44
45
46
47
    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";}
48
    string GetCXXFLAGS()  const {return CXXFLAGS " " CPPFLAGS;}
49
50
    string GetInstallPrefix() const {return INSTALL_PREFIX;}
    string GetPythonDir() const {return PYTHON_DIR;}
Tiago Peixoto's avatar
Tiago Peixoto committed
51
52
};

53
54
template <class ValueType>
struct vector_from_list
Tiago Peixoto's avatar
Tiago Peixoto committed
55
{
56
    vector_from_list()
Tiago Peixoto's avatar
Tiago Peixoto committed
57
    {
58
        converter::registry::push_back
59
            (&convertible, &construct,
60
             boost::python::type_id<vector<ValueType> >());
Tiago Peixoto's avatar
Tiago Peixoto committed
61
62
63
64
    }

    static void* convertible(PyObject* obj_ptr)
    {
65
66
        handle<> x(borrowed(obj_ptr));
        object o(x);
67
68
69
70
71
72
73
        size_t N = len(o);
        for (size_t i = 0; i < N; ++i)
        {
            extract<ValueType> elem(o[i]);
            if (!elem.check())
                return 0;
        }
74
        return obj_ptr;
Tiago Peixoto's avatar
Tiago Peixoto committed
75
76
    }

77
    static void construct(PyObject* obj_ptr,
78
                          converter::rvalue_from_python_stage1_data* data)
79
    {
80
81
        handle<> x(borrowed(obj_ptr));
        object o(x);
82
83
84
85
        vector<ValueType> value;
        size_t N = len(o);
        for (size_t i = 0; i < N; ++i)
            value.push_back(extract<ValueType>(o[i]));
86
        void* storage =
87
            ( (boost::python::converter::rvalue_from_python_storage
88
89
               <vector<ValueType> >*) data)->storage.bytes;
        new (storage) vector<ValueType>(value);
90
        data->convertible = storage;
Tiago Peixoto's avatar
Tiago Peixoto committed
91
92
93
    }
};

94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
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);
}

115
struct export_vector_types
Tiago Peixoto's avatar
Tiago Peixoto committed
116
{
117
118
    template <class ValueType>
    void operator()(ValueType) const
Tiago Peixoto's avatar
Tiago Peixoto committed
119
    {
120
121
122
123
124
        string type_name = get_type_name<>()(typeid(ValueType));
        if (type_name == "long double")
            type_name = "long_double";
        string name = "Vector_" + type_name;
        class_<vector<ValueType> >(name.c_str())
125
126
127
            .def(vector_indexing_suite<vector<ValueType> >())
            .def("__eq__", &vector_equal_compare<ValueType>)
            .def("__ne__", &vector_nequal_compare<ValueType>);
128
        vector_from_list<ValueType>();
Tiago Peixoto's avatar
Tiago Peixoto committed
129
    }
130
};
Tiago Peixoto's avatar
Tiago Peixoto committed
131

132
133
134
135
// exception translation
static PyObject* pyex =
    PyErr_NewException((char *) "libgraph_tool_core.GraphError",
                       PyExc_Exception, NULL);
Tiago Peixoto's avatar
Tiago Peixoto committed
136

137
138
139
140
141
142
void graph_exception_translator(const GraphException& e)
{
    PyObject* message = PyString_FromString(e.what());
    PyObject_SetAttrString(pyex, "message", message);
    PyErr_SetString(pyex, e.what());
}
Tiago Peixoto's avatar
Tiago Peixoto committed
143

144
145
146
147
148
template <class Exception>
void translate(const Exception& e)
{
    PyErr_SetString(PyExc_RuntimeError, e.what());
}
Tiago Peixoto's avatar
Tiago Peixoto committed
149

150
151
152
153
void raise_error(const string& msg)
{
    throw GraphException(msg);
}
Tiago Peixoto's avatar
Tiago Peixoto committed
154

155
156
template <class T1, class T2>
struct pair_to_tuple
Tiago Peixoto's avatar
Tiago Peixoto committed
157
{
158
    static PyObject* convert(const pair<T1,T2>& p)
Tiago Peixoto's avatar
Tiago Peixoto committed
159
    {
160
161
        boost::python::tuple t = boost::python::make_tuple(p.first,p.second);
        return incref(t.ptr());
Tiago Peixoto's avatar
Tiago Peixoto committed
162
163
164
    }
};

165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
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);
        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;
        value.first = extract<T1>(o[0]);
        value.second = extract<T2>(o[1]);
        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);
        ValueType value = extract<ValueType>(o);
        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
236
237
// scipy weave integration
#ifdef HAVE_SCIPY
238
template <class ScxxType>
Tiago Peixoto's avatar
Tiago Peixoto committed
239
240
struct scxx_to_python
{
241
    static PyObject* convert(const ScxxType& o)
Tiago Peixoto's avatar
Tiago Peixoto committed
242
243
244
245
246
247
    {
        return incref((PyObject*)(o));
    }
};
#endif

248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
// persistent python object IO
namespace graph_tool
{
extern python::object object_pickler;
extern python::object object_unpickler;
}

void set_pickler(python::object o)
{
    graph_tool::object_pickler = o;
}

void set_unpickler(python::object o)
{
    graph_tool::object_unpickler = o;
}

Tiago Peixoto's avatar
Tiago Peixoto committed
265
266
267
268
269
270
271
272
python::list get_property_types()
{
    python::list plist;
    for (int i = 0; i < mpl::size<value_types>::value; ++i)
        plist.append(string(type_names[i]));
    return plist;
}

273
BOOST_PYTHON_MODULE(libgraph_tool_core)
Tiago Peixoto's avatar
Tiago Peixoto committed
274
{
275
276
277
    // numpy
    import_array();

278
    GraphInterface().ExportPythonInterface();
Tiago Peixoto's avatar
Tiago Peixoto committed
279

280
281
    PyModule_AddObject(python::detail::current_scope, "GraphError", pyex);
    register_exception_translator<GraphException>(graph_exception_translator);
Tiago Peixoto's avatar
Tiago Peixoto committed
282

283
    def("raise_error", &raise_error);
Tiago Peixoto's avatar
Tiago Peixoto committed
284
    def("get_property_types", &get_property_types);
285

286
287
288
289
    mpl::for_each<mpl::push_back<scalar_types,string>::type>(export_vector_types());

    class_<GraphInterface>("GraphInterface", init<>())
        .def(init<GraphInterface>())
290
291
292
293
294
295
296
297
        .def("GetNumberOfVertices", &GraphInterface::GetNumberOfVertices)
        .def("GetNumberOfEdges", &GraphInterface::GetNumberOfEdges)
        .def("SetDirected", &GraphInterface::SetDirected)
        .def("GetDirected", &GraphInterface::GetDirected)
        .def("SetReversed", &GraphInterface::SetReversed)
        .def("GetReversed", &GraphInterface::GetReversed)
        .def("SetVertexFilterProperty",
             &GraphInterface::SetVertexFilterProperty)
298
299
        .def("GetVertexFilterProperty",
             &GraphInterface::GetVertexFilterProperty)
300
        .def("IsVertexFilterActive", &GraphInterface::IsVertexFilterActive)
301
        .def("SetEdgeFilterProperty",
302
             &GraphInterface::SetEdgeFilterProperty)
303
304
        .def("GetEdgeFilterProperty",
             &GraphInterface::GetEdgeFilterProperty)
305
        .def("IsEdgeFilterActive", &GraphInterface::IsEdgeFilterActive)
306
307
308
        .def("AddEdgeProperty",  &GraphInterface::AddEdgeProperty)
        .def("AddVertexProperty",  &GraphInterface::AddVertexProperty)
        .def("AddGraphProperty",  &GraphInterface::AddGraphProperty)
309
310
311
312
313
        .def("RemoveEdgeProperty",  &GraphInterface::RemoveEdgeProperty)
        .def("RemoveVertexProperty",  &GraphInterface::RemoveVertexProperty)
        .def("RemoveGraphProperty",  &GraphInterface::RemoveGraphProperty)
        .def("PurgeVertices",  &GraphInterface::PurgeVertices)
        .def("PurgeEdges",  &GraphInterface::PurgeEdges)
314
        .def("ReIndexEdges",  &GraphInterface::ReIndexEdges)
315
316
317
318
        .def("InsertEdgeIndexProperty",
             &GraphInterface::InsertEdgeIndexProperty)
        .def("InsertVertexIndexProperty",
             &GraphInterface::InsertVertexIndexProperty)
319
320
        .def("WriteToFile", &GraphInterface::WriteToFile)
        .def("ReadFromFile",&GraphInterface::ReadFromFile)
321
        .def("Vertices", &GraphInterface::Vertices)
322
        .def("Vertex", &GraphInterface::Vertex)
323
324
325
326
327
        .def("Edges", &GraphInterface::Edges)
        .def("AddVertex", &GraphInterface::AddVertex)
        .def("AddEdge", &GraphInterface::AddEdge)
        .def("RemoveVertex", &GraphInterface::RemoveVertex)
        .def("RemoveEdge", &GraphInterface::RemoveEdge)
328
        .def("Clear", &GraphInterface::Clear)
329
330
331
        .def("GetVertexProperties", &GraphInterface::GetVertexProperties)
        .def("GetEdgeProperties", &GraphInterface::GetEdgeProperties)
        .def("GetGraphProperties", &GraphInterface::GetGraphProperties)
332
        .def("PutPropertyMap", &GraphInterface::PutPropertyMap)
333
334
        .def("InitSignalHandling", &GraphInterface::InitSignalHandling);

335
336
337
338
339
340
341
342
    enum_<GraphInterface::degree_t>("Degree")
        .value("In", GraphInterface::IN_DEGREE)
        .value("Out", GraphInterface::OUT_DEGREE)
        .value("Total", GraphInterface::TOTAL_DEGREE);


    variant_from_python<string>();
    variant_from_python<GraphInterface::degree_t>();
343
    to_python_converter<pair<string,bool>, pair_to_tuple<string,bool> >();
344
    to_python_converter<pair<size_t,size_t>, pair_to_tuple<size_t,size_t> >();
345
    to_python_converter<pair<double,double>, pair_to_tuple<double,double> >();
346
347
    pair_from_tuple<double,double>();
    pair_from_tuple<size_t,size_t>();
Tiago Peixoto's avatar
Tiago Peixoto committed
348
#ifdef HAVE_SCIPY
349
350
351
352
353
    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
354
#endif
Tiago Peixoto's avatar
Tiago Peixoto committed
355

356
357
358
359
360
361
    class_<IStream>("IStream", no_init).def("Read", &IStream::Read);
    class_<OStream>("OStream", no_init).def("Write", &OStream::Write).
        def("Flush", &OStream::Flush);
    def("set_pickler", &set_pickler);
    def("set_unpickler", &set_unpickler);

Tiago Peixoto's avatar
Tiago Peixoto committed
362
    class_<LibInfo>("mod_info")
363
364
365
        .add_property("name", &LibInfo::GetName)
        .add_property("author", &LibInfo::GetAuthor)
        .add_property("copyright", &LibInfo::GetCopyright)
366
        .add_property("version", &LibInfo::GetVersion)
367
368
369
370
        .add_property("license", &LibInfo::GetLicense)
        .add_property("cxxflags", &LibInfo::GetCXXFLAGS)
        .add_property("install_prefix", &LibInfo::GetInstallPrefix)
        .add_property("python_dir", &LibInfo::GetPythonDir);
Tiago Peixoto's avatar
Tiago Peixoto committed
371
}