graph_bind.cc 13.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) 2007-2012 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 20
#include <boost/python.hpp>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>

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

#include "graph.hh"
25
#include "graph_python_interface.hh"
26
#include "graph_util.hh"
Tiago Peixoto's avatar
Tiago Peixoto committed
27

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 38 39 40
using namespace std;
using namespace graph_tool;
using namespace boost;
using namespace boost::python;

41
struct LibInfo
Tiago Peixoto's avatar
Tiago Peixoto committed
42
{
43 44 45 46 47 48
    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
49
    string GetCXXFLAGS()  const {return CPPFLAGS " " CXXFLAGS " " LDFLAGS;}
50 51
    string GetInstallPrefix() const {return INSTALL_PREFIX;}
    string GetPythonDir() const {return PYTHON_DIR;}
Tiago Peixoto's avatar
Tiago Peixoto committed
52 53 54 55 56 57
    string GetGCCVersion() const
    {
        stringstream s;
        s << __GNUC__ << "." << __GNUC_MINOR__ << "." <<  __GNUC_PATCHLEVEL__;
        return s.str();
    }
Tiago Peixoto's avatar
Tiago Peixoto committed
58 59
};

60 61
template <class ValueType>
struct vector_from_list
Tiago Peixoto's avatar
Tiago Peixoto committed
62
{
63
    vector_from_list()
Tiago Peixoto's avatar
Tiago Peixoto committed
64
    {
65
        converter::registry::push_back
66
            (&convertible, &construct,
67
             boost::python::type_id<vector<ValueType> >());
Tiago Peixoto's avatar
Tiago Peixoto committed
68 69 70 71
    }

    static void* convertible(PyObject* obj_ptr)
    {
72 73
        handle<> x(borrowed(obj_ptr));
        object o(x);
74 75 76 77 78 79 80
        size_t N = len(o);
        for (size_t i = 0; i < N; ++i)
        {
            extract<ValueType> elem(o[i]);
            if (!elem.check())
                return 0;
        }
81
        return obj_ptr;
Tiago Peixoto's avatar
Tiago Peixoto committed
82 83
    }

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

101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
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);
}

122
struct export_vector_types
Tiago Peixoto's avatar
Tiago Peixoto committed
123
{
124 125
    template <class ValueType>
    void operator()(ValueType) const
Tiago Peixoto's avatar
Tiago Peixoto committed
126
    {
127 128 129 130
        string type_name = get_type_name<>()(typeid(ValueType));
        if (type_name == "long double")
            type_name = "long_double";
        string name = "Vector_" + type_name;
131 132
        class_<vector<ValueType> > vc(name.c_str());
        vc.def(vector_indexing_suite<vector<ValueType> >())
133 134
            .def("__eq__", &vector_equal_compare<ValueType>)
            .def("__ne__", &vector_nequal_compare<ValueType>);
135
        wrap_array(vc, typename mpl::has_key<numpy_types,ValueType>::type());
136
        vector_from_list<ValueType>();
Tiago Peixoto's avatar
Tiago Peixoto committed
137
    }
138 139 140 141 142 143 144 145 146 147 148

    template <class ValueType>
    void wrap_array(class_<vector<ValueType> >& vc, mpl::true_) const
    {
        vc.def("get_array", &wrap_vector_not_owned<ValueType>);
    }

    template <class ValueType>
    void wrap_array(class_<vector<ValueType> >& vc, mpl::false_) const
    {
    }
149
};
Tiago Peixoto's avatar
Tiago Peixoto committed
150

151 152
// exception translation
template <class Exception>
Tiago Peixoto's avatar
Tiago Peixoto committed
153
void graph_exception_translator(const Exception& e)
154
{
Tiago Peixoto's avatar
Tiago Peixoto committed
155 156 157 158 159 160 161 162 163 164 165
    PyObject* error;
    if (is_same<Exception, GraphException>::value)
        error = PyExc_RuntimeError;
    if (is_same<Exception, IOException>::value)
        error = PyExc_IOError;
    if (is_same<Exception, ValueException>::value)
        error = PyExc_ValueError;

    PyObject* message = PyString_FromString(e.what());
    PyObject_SetAttrString(error, "message", message);
    PyErr_SetString(error, e.what());
166
}
Tiago Peixoto's avatar
Tiago Peixoto committed
167

168 169 170 171
void raise_error(const string& msg)
{
    throw GraphException(msg);
}
Tiago Peixoto's avatar
Tiago Peixoto committed
172

173 174
template <class T1, class T2>
struct pair_to_tuple
Tiago Peixoto's avatar
Tiago Peixoto committed
175
{
176
    static PyObject* convert(const pair<T1,T2>& p)
Tiago Peixoto's avatar
Tiago Peixoto committed
177
    {
178 179
        boost::python::tuple t = boost::python::make_tuple(p.first,p.second);
        return incref(t.ptr());
Tiago Peixoto's avatar
Tiago Peixoto committed
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 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
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
254 255
// scipy weave integration
#ifdef HAVE_SCIPY
256
template <class ScxxType>
Tiago Peixoto's avatar
Tiago Peixoto committed
257 258
struct scxx_to_python
{
259
    static PyObject* convert(const ScxxType& o)
Tiago Peixoto's avatar
Tiago Peixoto committed
260 261 262 263 264 265
    {
        return incref((PyObject*)(o));
    }
};
#endif

266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282
// 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
283 284 285 286 287 288 289 290
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;
}

Tiago Peixoto's avatar
Tiago Peixoto committed
291 292 293
struct graph_type_name
{
    template <class Graph>
294
    void operator()(const Graph& g, string& name) const
Tiago Peixoto's avatar
Tiago Peixoto committed
295 296 297 298 299 300 301 302 303
    {
        using python::detail::gcc_demangle;
        name = string(gcc_demangle(typeid(Graph).name()));
    }
};

string get_graph_type(GraphInterface& g)
{
    string name;
304
    run_action<>()(g, bind<void>(graph_type_name(), _1, ref(name)))();
Tiago Peixoto's avatar
Tiago Peixoto committed
305 306 307
    return name;
}

Tiago Peixoto's avatar
Tiago Peixoto committed
308 309
bool openmp_enabled()
{
Tiago Peixoto's avatar
Tiago Peixoto committed
310
#ifdef USING_OPENMP
Tiago Peixoto's avatar
Tiago Peixoto committed
311
    return true;
Tiago Peixoto's avatar
Tiago Peixoto committed
312
#else
Tiago Peixoto's avatar
Tiago Peixoto committed
313
    return false;
Tiago Peixoto's avatar
Tiago Peixoto committed
314
#endif
Tiago Peixoto's avatar
Tiago Peixoto committed
315 316
}

317 318 319 320
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);
321 322
void infect_vertex_property(GraphInterface& gi, boost::any prop,
                            python::object val);
Tiago Peixoto's avatar
Tiago Peixoto committed
323 324
void edge_difference(GraphInterface& gi, boost::any prop,
                     boost::any eprop);
325
void export_python_interface();
326

327
BOOST_PYTHON_MODULE(libgraph_tool_core)
Tiago Peixoto's avatar
Tiago Peixoto committed
328
{
329 330 331
    // numpy
    import_array();

332
    export_python_interface();
Tiago Peixoto's avatar
Tiago Peixoto committed
333

Tiago Peixoto's avatar
Tiago Peixoto committed
334 335 336 337 338 339
    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
340

341
    def("raise_error", &raise_error);
Tiago Peixoto's avatar
Tiago Peixoto committed
342
    def("get_property_types", &get_property_types);
343
    class_<boost::any>("any");
344

345
    def("graph_filtering_enabled", &graph_filtering_enabled);
Tiago Peixoto's avatar
Tiago Peixoto committed
346
    def("openmp_enabled", &openmp_enabled);
347

348 349 350
    mpl::for_each<mpl::push_back<scalar_types,string>::type>(export_vector_types());

    class_<GraphInterface>("GraphInterface", init<>())
Tiago Peixoto's avatar
Tiago Peixoto committed
351
        .def(init<GraphInterface,bool>())
352 353 354 355 356 357 358 359 360
        .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)
        .def("IsVertexFilterActive", &GraphInterface::IsVertexFilterActive)
361
        .def("SetEdgeFilterProperty",
362 363 364 365
             &GraphInterface::SetEdgeFilterProperty)
        .def("IsEdgeFilterActive", &GraphInterface::IsEdgeFilterActive)
        .def("PurgeVertices",  &GraphInterface::PurgeVertices)
        .def("PurgeEdges",  &GraphInterface::PurgeEdges)
366
        .def("ShiftVertexProperty",  &GraphInterface::ShiftVertexProperty)
367
        .def("ReIndexVertexProperty",  &GraphInterface::ReIndexVertexProperty)
368 369
        .def("WriteToFile", &GraphInterface::WriteToFile)
        .def("ReadFromFile",&GraphInterface::ReadFromFile)
370
        .def("DegreeMap", &GraphInterface::DegreeMap)
371
        .def("Clear", &GraphInterface::Clear)
372 373 374
        .def("ClearEdges", &GraphInterface::ClearEdges)
        .def("GetVertexIndex", &GraphInterface::GetVertexIndex)
        .def("GetEdgeIndex", &GraphInterface::GetEdgeIndex)
375
        .def("GetMaxEdgeIndex", &GraphInterface::GetMaxEdgeIndex)
376
        .def("ReIndexEdges", &GraphInterface::ReIndexEdges)
377 378 379
        .def("GetGraphIndex", &GraphInterface::GetGraphIndex)
        .def("CopyVertexProperty", &GraphInterface::CopyVertexProperty)
        .def("CopyEdgeProperty", &GraphInterface::CopyEdgeProperty);
380

381 382 383 384
    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);

385 386 387 388 389
    enum_<GraphInterface::degree_t>("Degree")
        .value("In", GraphInterface::IN_DEGREE)
        .value("Out", GraphInterface::OUT_DEGREE)
        .value("Total", GraphInterface::TOTAL_DEGREE);

390
    variant_from_python<boost::any>();
391
    variant_from_python<GraphInterface::degree_t>();
392
    to_python_converter<pair<string,bool>, pair_to_tuple<string,bool> >();
393
    to_python_converter<pair<size_t,size_t>, pair_to_tuple<size_t,size_t> >();
394
    to_python_converter<pair<double,double>, pair_to_tuple<double,double> >();
395 396
    pair_from_tuple<double,double>();
    pair_from_tuple<size_t,size_t>();
Tiago Peixoto's avatar
Tiago Peixoto committed
397
#ifdef HAVE_SCIPY
398 399 400 401 402
    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
403
#endif
Tiago Peixoto's avatar
Tiago Peixoto committed
404

405 406 407 408 409 410
    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);

411 412
    def("group_vector_property", &group_vector_property);
    def("ungroup_vector_property", &ungroup_vector_property);
413
    def("infect_vertex_property", &infect_vertex_property);
Tiago Peixoto's avatar
Tiago Peixoto committed
414
    def("edge_difference", &edge_difference);
415

Tiago Peixoto's avatar
Tiago Peixoto committed
416
    class_<LibInfo>("mod_info")
417 418 419
        .add_property("name", &LibInfo::GetName)
        .add_property("author", &LibInfo::GetAuthor)
        .add_property("copyright", &LibInfo::GetCopyright)
420
        .add_property("version", &LibInfo::GetVersion)
421 422 423
        .add_property("license", &LibInfo::GetLicense)
        .add_property("cxxflags", &LibInfo::GetCXXFLAGS)
        .add_property("install_prefix", &LibInfo::GetInstallPrefix)
Tiago Peixoto's avatar
Tiago Peixoto committed
424 425
        .add_property("python_dir", &LibInfo::GetPythonDir)
        .add_property("gcc_version", &LibInfo::GetGCCVersion);
Tiago Peixoto's avatar
Tiago Peixoto committed
426 427

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