graph_bind.cc 11.5 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
    class_<boost::any>("any");
286

287 288
    def("graph_filtering_enabled", &graph_filtering_enabled);

289 290 291 292
    mpl::for_each<mpl::push_back<scalar_types,string>::type>(export_vector_types());

    class_<GraphInterface>("GraphInterface", init<>())
        .def(init<GraphInterface>())
293 294 295 296 297 298 299 300 301
        .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)
302
        .def("SetEdgeFilterProperty",
303 304 305 306
             &GraphInterface::SetEdgeFilterProperty)
        .def("IsEdgeFilterActive", &GraphInterface::IsEdgeFilterActive)
        .def("PurgeVertices",  &GraphInterface::PurgeVertices)
        .def("PurgeEdges",  &GraphInterface::PurgeEdges)
307
        .def("ShiftVertexProperty",  &GraphInterface::ShiftVertexProperty)
308 309
        .def("WriteToFile", &GraphInterface::WriteToFile)
        .def("ReadFromFile",&GraphInterface::ReadFromFile)
310
        .def("Vertices", &GraphInterface::Vertices)
311
        .def("Vertex", &GraphInterface::Vertex)
312 313 314 315 316
        .def("Edges", &GraphInterface::Edges)
        .def("AddVertex", &GraphInterface::AddVertex)
        .def("AddEdge", &GraphInterface::AddEdge)
        .def("RemoveVertex", &GraphInterface::RemoveVertex)
        .def("RemoveEdge", &GraphInterface::RemoveEdge)
317
        .def("Clear", &GraphInterface::Clear)
318 319 320 321 322 323
        .def("ClearEdges", &GraphInterface::ClearEdges)
        .def("GetVertexIndex", &GraphInterface::GetVertexIndex)
        .def("GetEdgeIndex", &GraphInterface::GetEdgeIndex)
        .def("GetGraphIndex", &GraphInterface::GetGraphIndex)
        .def("CopyVertexProperty", &GraphInterface::CopyVertexProperty)
        .def("CopyEdgeProperty", &GraphInterface::CopyEdgeProperty);
324

325 326 327 328 329
    enum_<GraphInterface::degree_t>("Degree")
        .value("In", GraphInterface::IN_DEGREE)
        .value("Out", GraphInterface::OUT_DEGREE)
        .value("Total", GraphInterface::TOTAL_DEGREE);

330
    variant_from_python<boost::any>();
331
    variant_from_python<GraphInterface::degree_t>();
332
    to_python_converter<pair<string,bool>, pair_to_tuple<string,bool> >();
333
    to_python_converter<pair<size_t,size_t>, pair_to_tuple<size_t,size_t> >();
334
    to_python_converter<pair<double,double>, pair_to_tuple<double,double> >();
335 336
    pair_from_tuple<double,double>();
    pair_from_tuple<size_t,size_t>();
Tiago Peixoto's avatar
Tiago Peixoto committed
337
#ifdef HAVE_SCIPY
338 339 340 341 342
    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
343
#endif
Tiago Peixoto's avatar
Tiago Peixoto committed
344

345 346 347 348 349 350
    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
351
    class_<LibInfo>("mod_info")
352 353 354
        .add_property("name", &LibInfo::GetName)
        .add_property("author", &LibInfo::GetAuthor)
        .add_property("copyright", &LibInfo::GetCopyright)
355
        .add_property("version", &LibInfo::GetVersion)
356 357 358 359
        .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
360
}