graph_python_interface.hh 8.79 KB
Newer Older
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>
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
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
// along with this program. If not, see <http://www.gnu.org/licenses/>.
17

18
19
#ifndef PYTHON_INTERFACE_HH
#define PYTHON_INTERFACE_HH
20

21
#include <boost/python.hpp>
22
#include <boost/lambda/bind.hpp>
23
24
#include <boost/graph/graph_traits.hpp>
#include <boost/mpl/logical.hpp>
25
#include <boost/functional/hash.hpp>
26
#include <boost/iterator/iterator_facade.hpp>
27

28
#include "graph_selectors.hh"
29

30
// this file includes a simple python interface for the internally kept
31
32
33
34
// graph. It defines a PythonVertex, PythonEdge and PythonIterator template
// classes, which contain the proper member functions for graph traversal. These
// types are then specialized for each version of the adapted graph (directed,
// undirected, filtered, reversed).
35

36
37
38
39
namespace graph_tool
{
using namespace boost;

40
41
// generic iterator adaptor which can be used to iterate vertices, edges,
// out_edges and in_edges through python
42
template <class Descriptor, class Iterator>
43
class PythonIterator
44
{
45
public:
46
47
    PythonIterator(const GraphInterface& gi, std::pair<Iterator,Iterator> e)
        : _gi(gi), _e(e) {}
48
    Descriptor Next()
49
    {
50
51
        if (_e.first == _e.second)
            python::objects::stop_iteration_error();
52
        Descriptor e(_gi, *_e.first);
53
54
        ++_e.first;
        return e;
55
56
    }
private:
57
    const GraphInterface& _gi;
58
    std::pair<Iterator,Iterator> _e;
Tiago Peixoto's avatar
Tiago Peixoto committed
59
60
61
};


62
// forward declaration of PythonEdge
63
64
template <class Graph>
class PythonEdge;
65

66
// below are classes related to the PythonVertex type
67
class PythonVertex
68
69
{
public:
70
71
    PythonVertex(const GraphInterface& gi, GraphInterface::vertex_t v):
        _gi(gi), _v(v) {}
72

73
    PythonVertex(const PythonVertex& v): _gi(v._gi)
74
    {
75

76
        _v = v._v;
77
    }
78

79
    GraphInterface::vertex_t GetDescriptor() const
80
81
82
83
    {
        return _v;
    }

84
85
86
87
88
89
90
91
92
93
94
95
96
    template <class DegSelector>
    struct get_degree
    {
        template<class Graph>
        void operator()(const Graph* gp,
                        typename graph_traits<Graph>::vertex_descriptor v,
                        size_t& deg) const
        {
            deg = DegSelector()(v, *gp);
        }
    };
    

97
    size_t GetInDegree() const
98
    {
99
100
101
102
103
        size_t in_deg;
        run_action<>()(_gi,lambda::bind<void>(get_degree<in_degreeS>(),
                                              lambda::_1, _v,
                                              lambda::var(in_deg)))();
        return in_deg;
104
    }
105

106
    size_t GetOutDegree() const
107
    {
108
109
110
111
112
        size_t out_deg;
        run_action<>()(_gi,lambda::bind<void>(get_degree<out_degreeS>(),
                                              lambda::_1, _v,
                                              lambda::var(out_deg)))();
        return out_deg;
Tiago Peixoto's avatar
Tiago Peixoto committed
113
114
    }

115
    // provide iterator support for out_edges
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
    
    struct get_out_edges
    {
        template<class Graph>
        void operator()(const Graph* gp, const GraphInterface& gi,
                        typename graph_traits<Graph>::vertex_descriptor v,
                        python::object& iter) const
        {
            typedef typename graph_traits<Graph>::out_edge_iterator
                out_edge_iterator;
            iter = python::object(PythonIterator<PythonEdge<Graph>,
                                                 out_edge_iterator>
                                  (gi, out_edges(v, *gp)));
        }
    };

    python::object
133
    OutEdges() const
Tiago Peixoto's avatar
Tiago Peixoto committed
134
    {
135
136
137
138
139
        python::object iter;
        run_action<>()(_gi, lambda::bind<void>(get_out_edges(), lambda::_1,
                                               lambda::var(_gi), _v,
                                               lambda::var(iter)))();
        return iter;
140
    }
141

142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
    struct get_in_edges
    {
        template<class Graph>
        void operator()(const Graph* gp, const GraphInterface& gi,
                        typename graph_traits<Graph>::vertex_descriptor v,
                        python::object& iter) const
        {
            typedef typename in_edge_iteratorS<Graph>::type
                in_edge_iterator;
            iter = python::object
                (PythonIterator<PythonEdge<Graph>,in_edge_iterator>
                 (gi, in_edge_iteratorS<Graph>::get_edges(v, *gp)));
        }
    };

    python::object
158
    InEdges() const
159
    {
160
161
162
163
164
        python::object iter;
        run_action<>()(_gi, lambda::bind<void>(get_in_edges(), lambda::_1, 
                                               lambda::var(_gi), _v,
                                               lambda::var(iter)))();
        return iter;
Tiago Peixoto's avatar
Tiago Peixoto committed
165
    }
166
    
167
168
169
170
171
    std::string GetString() const
    {
        return lexical_cast<std::string>(_v);
    }

172
    size_t GetHash() const
173
    {
174
        return hash<GraphInterface::vertex_t>()(_v);
175
176
    }

177
    bool operator==(const PythonVertex& other) const
178
    {
179
        return other._v == _v;
180
    }
181

182
    bool operator!=(const PythonVertex& other) const
183
    {
184
        return other._v != _v;
185
186
    }

187
private:
188
189
    const GraphInterface& _gi;
    GraphInterface::vertex_t _v;
190
};
191

192
// below are classes related to the PythonEdge type
193

194
195
196
197
template <class Graph>
class PythonEdge
{
public:
Tiago Peixoto's avatar
Tiago Peixoto committed
198
    typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
199
200
201
    PythonEdge(const GraphInterface& gi, edge_descriptor e)
        : _gi(gi), _e(e) {}
    PythonEdge(const PythonEdge& e): _gi(e._gi)
Tiago Peixoto's avatar
Tiago Peixoto committed
202
    {
203
        _e = e._e;
Tiago Peixoto's avatar
Tiago Peixoto committed
204
205
    }

206
    const GraphInterface::edge_t& GetDescriptor() const
207
208
209
210
    {
        return _e;
    }

211
212
213
214
215
216
217
218
219
220
221
222
    struct get_source
    {
        template<class GraphType>
        void operator()(const GraphType* gp, const GraphInterface& gi,
                        const edge_descriptor& edge, python::object& vertex)
            const
        {
            vertex = python::object(PythonVertex(gi, source(edge, *gp)));
        }
    };
    
    python::object GetSource() const
Tiago Peixoto's avatar
Tiago Peixoto committed
223
    {
224
225
226
227
228
229
        python::object v;
        run_action<>()(_gi, lambda::bind<void>(get_source(), lambda::_1, 
                                               lambda::var(_gi),
                                               lambda::var(_e), 
                                               lambda::var(v)))();
        return v;
Tiago Peixoto's avatar
Tiago Peixoto committed
230
231
    }

232
233
234
235
236
237
238
239
240
241
242
243
    struct get_target
    {
        template<class GraphType>
        void operator()(const GraphType* gp, const GraphInterface& gi,
                        const edge_descriptor& edge, 
                        python::object& vertex) const
        {
            vertex = python::object(PythonVertex(gi, target(edge, *gp)));
        }
    };
    
    python::object GetTarget() const
Tiago Peixoto's avatar
Tiago Peixoto committed
244
    {
245
246
247
248
249
250
        python::object v;
        run_action<>()(_gi, lambda::bind<void>(get_target(), lambda::_1, 
                                               lambda::var(_gi),
                                               lambda::var(_e),
                                               lambda::var(v)))();
        return v;        
Tiago Peixoto's avatar
Tiago Peixoto committed
251
252
    }

253
254
    std::string GetString() const
    {
255
256
257
        PythonVertex& src = python::extract<PythonVertex&>(GetSource());
        PythonVertex& tgt = python::extract<PythonVertex&>(GetTarget());
        return "(" + src.GetString() + "," + tgt.GetString() + ")";
258
259
    }

260
    size_t GetHash() const
Tiago Peixoto's avatar
Tiago Peixoto committed
261
    {
262
        return _gi.GetEdgeHash(_e);;
Tiago Peixoto's avatar
Tiago Peixoto committed
263
264
    }

265
    bool operator==(const PythonEdge& other) const
Tiago Peixoto's avatar
Tiago Peixoto committed
266
    {
267
        return other._e == _e;
Tiago Peixoto's avatar
Tiago Peixoto committed
268
    }
269

270
    bool operator!=(const PythonEdge& other) const
271
    {
272
        return other._e != _e;
273
274
275
    }

private:
276
    const GraphInterface& _gi;
277
    edge_descriptor _e;
278
279
};

280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
template <class ValueType>
class PythonPropertyMap
{
public:
    PythonPropertyMap(const std::string& name, dynamic_property_map& pmap)
        : _name(name), _pmap(pmap) {}

    template <class PythonDescriptor>
    ValueType GetValue(const PythonDescriptor& key) const
    {
        any val = _pmap.get(key.GetDescriptor());
        return any_cast<ValueType>(val);
    }

    template <class PythonDescriptor>
    void SetValue(const PythonDescriptor& key, const ValueType& val)
    {
        _pmap.put(key.GetDescriptor(), val);
    }

    size_t GetHash() const
    {
        return hash<std::string>()(_name + this->GetType());
    }

    std::string GetType() const
    {
        return type_names[mpl::find<value_types,ValueType>::type::pos::value];
    }

private:
    const std::string& _name;
    dynamic_property_map& _pmap;
};


316
317
318
} //graph_tool namespace

#endif