graph_python_interface.hh 38.4 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
20
21
22
23
24
25
26
27
28
29
30
31

#ifndef PYTHON_FILTERING_HH
#define PYTHON_FILTERING_HH

#include <boost/graph/graph_traits.hpp>
#include <boost/graph/filtered_graph.hpp>
#include <boost/graph/reverse_graph.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/map.hpp>
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/at.hpp>
#include <boost/mpl/or.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/logical.hpp>
#include <boost/python/object.hpp>
32
#include <boost/python/class.hpp>
33
#include <boost/python/dict.hpp>
34
#include <boost/python/long.hpp>
35
36
#include <boost/python/extract.hpp>
#include <boost/python/make_function.hpp>
37
38
#include <boost/python/self.hpp>
#include <boost/python/operators.hpp>
Tiago Peixoto's avatar
Tiago Peixoto committed
39
#include <boost/python/iterator.hpp>
40
#include <boost/functional/hash.hpp>
Tiago Peixoto's avatar
Tiago Peixoto committed
41
42
#include <boost/iterator/transform_iterator.hpp>
#include <boost/functional.hpp>
43

44
45
#include "graph_properties.hh"

46
47
48
49
50
// this file includes a simple python interface for the internally kept
// graph. It defines a PythonVertex, PythonEdge and PythonGraph types, which
// contain the proper member functions for graph traversal and property
// manipulation

51
52
53
54
namespace graph_tool
{
using namespace boost;

55
56
template <class VertexOrEdge>
class get_python_property_value
57
{
58
public:
59
60
    get_python_property_value(const dynamic_property_map& dmap,
                              const VertexOrEdge& e)
61
        : _dmap(dmap), _e(e) {}
62

63
64
65
66
67
68
69
70
    python::object operator()()
    {
        mpl::for_each<value_types>(try_conversion(*this));
        return _retval;
    }

private:
    struct try_conversion
71
    {
72
        try_conversion(get_python_property_value& parent): _parent(parent) {}
73

74
75
        template <class Type>
        void operator()(Type)
76
        {
77
78
79
            any any_val =
                const_cast
                <dynamic_property_map&>(_parent._dmap).get(_parent._e);
80
81
82
            Type* value = any_cast<Type>(&any_val);
            if (value != 0)
                _parent._retval = python::object(*value);
83
        }
84
85
        get_python_property_value& _parent;
    };
86

87
88
89
90
    const dynamic_property_map& _dmap;
    const VertexOrEdge& _e;
    python::object _retval;
};
91

Tiago Peixoto's avatar
Tiago Peixoto committed
92
93
94
95
template <class VertexOrEdge>
class put_python_property_value
{
public:
96
97
    put_python_property_value(dynamic_property_map& dmap, const VertexOrEdge& e,
                              python::object val)
Tiago Peixoto's avatar
Tiago Peixoto committed
98
        : _dmap(dmap), _e(e), _val(val) {}
99

Tiago Peixoto's avatar
Tiago Peixoto committed
100
101
    void operator()()
    {
102
103
        typedef mpl::vector<bool,int,long,size_t,float,double,std::string>
            value_types;
Tiago Peixoto's avatar
Tiago Peixoto committed
104
105
106
107
108
109
110
        mpl::for_each<value_types>(try_conversion(*this));
    }

private:
    struct try_conversion
    {
        try_conversion(put_python_property_value& parent): _parent(parent) {}
111

Tiago Peixoto's avatar
Tiago Peixoto committed
112
113
114
115
116
117
118
119
120
        template <class Type>
        void operator()(Type)
        {
            if (typeid(Type) == _parent._dmap.value())
            {
                Type val = python::extract<Type>(_parent._val);
                _parent._dmap.put(_parent._e, val);
            }
        }
121

Tiago Peixoto's avatar
Tiago Peixoto committed
122
123
        put_python_property_value& _parent;
    };
124

Tiago Peixoto's avatar
Tiago Peixoto committed
125
126
127
128
129
130
    dynamic_property_map& _dmap;
    const VertexOrEdge& _e;
    python::object _val;
};


131
132
template <class Graph>
class PythonEdge;
133

Tiago Peixoto's avatar
Tiago Peixoto committed
134

135
136
137
// below are classes related to the PythonVertex type

template <class Graph, class IsDirected>
Tiago Peixoto's avatar
Tiago Peixoto committed
138
139
140
struct in_edge_iterator
{
    BOOST_MPL_ASSERT((is_same<IsDirected, boost::true_type>));
141
142
143
    BOOST_MPL_ASSERT((is_convertible
                      <typename graph_traits<Graph>::directed_category,
                       boost::directed_tag>));
Tiago Peixoto's avatar
Tiago Peixoto committed
144
145
    typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
    typedef typename graph_traits<Graph>::in_edge_iterator type;
146
147
148
149
    static std::pair<type,type> in_edges(vertex_descriptor v, const Graph& g)
    {
        return boost::in_edges(v,g);
    }
Tiago Peixoto's avatar
Tiago Peixoto committed
150
151
152
153
154
};

template <class Graph>
struct in_edge_iterator<Graph, boost::false_type>
{
155
156
157
    BOOST_MPL_ASSERT((is_convertible
                      <typename graph_traits<Graph>::directed_category,
                       boost::undirected_tag>));
Tiago Peixoto's avatar
Tiago Peixoto committed
158
159
    typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
    typedef typename graph_traits<Graph>::out_edge_iterator type;
160
161
162
163
    static std::pair<type,type> in_edges(vertex_descriptor v, const Graph& g)
    {
        return make_pair(type(), type());
    }
Tiago Peixoto's avatar
Tiago Peixoto committed
164
165
};

166
167
168
169
170
template <class Graph>
class PythonVertex
{
public:
    PythonVertex(python::object base): _base(base)
171
    {
172
173
174
175
176
177
178
        static bool first_time = true;
        if (first_time)
        {
            _python_class.def(python::init<python::object>());
            _python_class.def("in_degree", &PythonVertex::GetInDegree);
            _python_class.def("out_degree", &PythonVertex::GetOutDegree);
            _python_class.def("get_property", &PythonVertex::GetProperty);
Tiago Peixoto's avatar
Tiago Peixoto committed
179
            _python_class.def("put_property", &PythonVertex::PutProperty);
180
181
182
183
184
185
            _python_class.def("out_edges",
                              python::range(&PythonVertex::OutEdgesBegin,
                                            &PythonVertex::OutEdgesEnd));
            _python_class.def("in_edges",
                              python::range(&PythonVertex::InEdgesBegin,
                                            &PythonVertex::InEdgesEnd));
186
            _python_class.def(python::self == python::self);
187
            _python_class.def(python::self != python::self);
188
            _python_class.def("__hash__", &PythonVertex::GetHash);
189
190
191
192
            first_time = false;
        }
    }
    PythonVertex(): _base(python::object()) { *this = PythonVertex(_base); }
193

194
195
196
    PythonVertex(const PythonVertex& v)
    {
        if (v._base != python::object())
197
        {
198
199
            base_t base = python::extract<base_t>(_base);
            if (get<3>(base))
200
            {
201
202
203
204
                vertex_descriptor* new_v = new vertex_descriptor;
                *new_v = get<1>(base);
                base_t new_base(get<0>(base), *new_v, get<2>(base), true);
                _base = python::object(new_base);
205
206
            }
        }
207
208
    }

209
    ~PythonVertex()
210
    {
211
        if (_base != python::object())
212
        {
213
214
215
            base_t base = python::extract<base_t>(_base);
            if (get<3>(base))
                delete &get<1>(base);
216
        }
217
    }
218

219
220
    typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
    typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
221
222
    typedef tuple<const Graph&, const vertex_descriptor&,
                  const dynamic_properties&, bool> base_t;
223

224
    python::object GetInDegree()
225
    {
226
        if (_base != python::object())
227
        {
228
229
230
231
            base_t base = python::extract<base_t>(_base);
            return python::object(in_degreeS()(get<1>(base), get<0>(base)));
        }
        else
232
        {
233
            return python::object();
234
        }
235
    }
236

237
    python::object GetOutDegree()
238
    {
239
240
241
242
243
244
        if (_base != python::object())
        {
            base_t base = python::extract<base_t>(_base);
            return python::object(out_degree(get<1>(base), get<0>(base)));
        }
        else
245
        {
246
            return python::object();
247
        }
248
    }
249

250
251
252
    python::object GetProperty(std::string prop)
    {
        if (_base != python::object())
253
        {
254
255
256
            base_t base = python::extract<base_t>(_base);
            const dynamic_properties& dp = get<2>(base);
            const vertex_descriptor& v = get<1>(base);
257
258
            for(typeof(dp.begin()) iter = dp.lower_bound(prop);
                iter != dp.end(); ++iter)
259
            {
260
                if (iter->second->key() == typeid(vertex_descriptor))
261
262
                    return get_python_property_value
                        <vertex_descriptor>(*iter->second, v)();
263
            }
264
        }
Tiago Peixoto's avatar
Tiago Peixoto committed
265
        return python::object();
266
    }
267

Tiago Peixoto's avatar
Tiago Peixoto committed
268
    void PutProperty(std::string prop, python::object val)
269
270
    {
        if (_base != python::object())
271
        {
272
273
            base_t base = python::extract<base_t>(_base);
            const dynamic_properties& dp = get<2>(base);
Tiago Peixoto's avatar
Tiago Peixoto committed
274
            const vertex_descriptor& v = get<1>(base);
275
276
            for(typeof(dp.begin()) iter = dp.lower_bound(prop);
                iter != dp.end(); ++iter)
277
            {
Tiago Peixoto's avatar
Tiago Peixoto committed
278
                if (iter->second->key() == typeid(vertex_descriptor))
279
280
                    put_python_property_value
                        <vertex_descriptor>(*iter->second, v, val)();
281
282
            }
        }
Tiago Peixoto's avatar
Tiago Peixoto committed
283
284
285
286
287
    }


    struct descriptor_wrap
    {
288
289
290
        descriptor_wrap(const Graph &g, const dynamic_properties& dp)
            : _g(g), _dp(dp) {}

Tiago Peixoto's avatar
Tiago Peixoto committed
291
        python::object operator()(edge_descriptor e)
292
        {
Tiago Peixoto's avatar
Tiago Peixoto committed
293
294
295
            edge_descriptor *new_e = new edge_descriptor;
            *new_e = e;
            typename PythonEdge<Graph>::base_t edge_base(_g, *new_e, _dp, true);
296
297
298
            python::object edge =
                (PythonEdge<Graph>().GetPythonClass())
                    (python::object(edge_base));
Tiago Peixoto's avatar
Tiago Peixoto committed
299
300
301
302
303
304
305
306
307
            return edge;
        }

        const Graph& _g;
        const dynamic_properties& _dp;
    };

    typedef typename graph_traits<Graph>::out_edge_iterator out_edge_iterator;
    typedef function<python::object (edge_descriptor)> edge_wrap_function;
308
309
    typedef transform_iterator<edge_wrap_function, out_edge_iterator>
        wrapped_out_edge_iterator;
Tiago Peixoto's avatar
Tiago Peixoto committed
310
311
312
313
314
315
316
317
318

    wrapped_out_edge_iterator OutEdgesBegin()
    {
        if (_base != python::object())
        {
            base_t base = python::extract<base_t>(_base);
            const Graph& g = get<0>(base);
            vertex_descriptor v = get<1>(base);
            const dynamic_properties& dp(get<2>(base));
319
320
321
            return wrapped_out_edge_iterator
                (out_edges(v,g).first,
                 edge_wrap_function(descriptor_wrap(g,dp)));
322
        }
Tiago Peixoto's avatar
Tiago Peixoto committed
323
        return wrapped_out_edge_iterator();
324
    }
325

Tiago Peixoto's avatar
Tiago Peixoto committed
326
    wrapped_out_edge_iterator OutEdgesEnd()
327
    {
328
329
330
331
        if (_base != python::object())
        {
            base_t base = python::extract<base_t>(_base);
            const Graph& g = get<0>(base);
Tiago Peixoto's avatar
Tiago Peixoto committed
332
333
            vertex_descriptor v = get<1>(base);
            const dynamic_properties& dp(get<2>(base));
334
335
336
            return wrapped_out_edge_iterator
                (out_edges(v,g).second,
                 edge_wrap_function(descriptor_wrap(g,dp)));
337
        }
Tiago Peixoto's avatar
Tiago Peixoto committed
338
339
340
        return wrapped_out_edge_iterator();
    }

341
342
343
344
345
346
347
    typedef typename graph_traits<Graph>::directed_category directed_category;
    typedef typename is_convertible<directed_category,
                                    boost::directed_tag>::type is_directed;
    typedef typename in_edge_iterator<Graph,is_directed>::type
        in_edge_iterator_type;
    typedef transform_iterator<edge_wrap_function, in_edge_iterator_type>
        wrapped_in_edge_iterator;
Tiago Peixoto's avatar
Tiago Peixoto committed
348
349
350
351

    wrapped_in_edge_iterator InEdgesBegin()
    {
        if (_base != python::object())
352
        {
Tiago Peixoto's avatar
Tiago Peixoto committed
353
354
355
356
            base_t base = python::extract<base_t>(_base);
            const Graph& g = get<0>(base);
            vertex_descriptor v = get<1>(base);
            const dynamic_properties& dp(get<2>(base));
357
358
359
            return wrapped_in_edge_iterator
                (in_edge_iterator<Graph,is_directed>::in_edges(v,g).first,
                 edge_wrap_function(descriptor_wrap(g,dp)));
360
        }
Tiago Peixoto's avatar
Tiago Peixoto committed
361
362
363
364
365
366
367
368
369
370
371
        return wrapped_in_edge_iterator();
    }

    wrapped_in_edge_iterator InEdgesEnd()
    {
        if (_base != python::object())
        {
            base_t base = python::extract<base_t>(_base);
            const Graph& g = get<0>(base);
            vertex_descriptor v = get<1>(base);
            const dynamic_properties& dp(get<2>(base));
372
373
374
            return wrapped_in_edge_iterator
                (in_edge_iterator<Graph,is_directed>::in_edges(v,g).second,
                 edge_wrap_function(descriptor_wrap(g,dp)));
Tiago Peixoto's avatar
Tiago Peixoto committed
375
376
        }
        return wrapped_in_edge_iterator();
377
378
379
380
381
    }

    python::object GetHash()
    {
        if (_base != python::object())
382
        {
383
384
385
386
387
388
389
390
391
392
393
394
            base_t base = python::extract<base_t>(_base);
            return python::object(hash<vertex_descriptor>()(get<1>(base)));
        }
        else
        {
            return python::object(0);
        }
    }

    bool operator==(const PythonVertex& other)
    {
        if (_base != python::object() && other._base != python::object())
395
        {
396
397
398
399
400
            const base_t o_base = python::extract<base_t>(other._base);
            base_t base = python::extract<base_t>(_base);
            return python::object(get<1>(base) == get<1>(o_base));
        }
        else
401
        {
402
403
            return false;
        }
404
    }
405

406
407
408
409
410
    bool operator!=(const PythonVertex& other)
    {
        return !(*this == other);
    }

411
    python::class_<PythonVertex> GetPythonClass() { return _python_class; }
412

413
414
415
416
private:
    python::object _base;
    static python::class_<PythonVertex> _python_class;
};
417

418
419
420
template <class Graph> python::class_<PythonVertex<Graph> >
PythonVertex<Graph>::_python_class =
    python::class_<PythonVertex<Graph> >("Vertex", python::no_init);
421

422
423
424


// below are classes related to the PythonEdge type
425

426
427
428
429
430
431
432
433
434
435
436
437
438
template <class Graph>
class PythonEdge
{
public:
    PythonEdge(python::object base): _base(base)
    {
        static bool first_time = true;
        if (first_time)
        {
            _python_class.def(python::init<python::object>());
            _python_class.def("source", &PythonEdge::GetSource);
            _python_class.def("target", &PythonEdge::GetTarget);
            _python_class.def("get_property", &PythonEdge::GetProperty);
439
            _python_class.def("put_property", &PythonEdge::PutProperty);
440
            _python_class.def("n_parallel", &PythonEdge::GetNParallel);
441
            _python_class.def(python::self == python::self);
442
            _python_class.def(python::self != python::self);
443
            _python_class.def("__hash__", &PythonEdge::GetHash);
444
445
446
447
448
            first_time = false;
        }
    }
    PythonEdge(): _base(python::object()) { *this = PythonEdge(_base); }
    PythonEdge(const PythonEdge& e)
449
    {
450
451
452
453
454
455
456
457
458
459
460
        if (e._base != python::object())
        {
            base_t base = python::extract<base_t>(_base);
            if (get<3>(base))
            {
                edge_descriptor* new_e = new edge_descriptor;
                base_t new_base(get<0>(base), *new_e, get<2>(base), true);
                _base = python::object(new_base);
            }
        }
    }
461

462
463
464
    ~PythonEdge()
    {
        if (_base != python::object())
465
        {
466
467
468
            base_t base = python::extract<base_t>(_base);
            if (get<3>(base))
                delete &get<1>(base);
469
        }
470
    }
471

472
473
    typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
    typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
474
475
    typedef tuple<const Graph&, const edge_descriptor&,
                  const dynamic_properties&, bool> base_t;
476

477
    python::object GetSource()
478
    {
479
        if (_base != python::object())
480
        {
481
482
483
            base_t base = python::extract<base_t>(_base);
            vertex_descriptor *v = new vertex_descriptor;
            *v = source(get<1>(base), get<0>(base));
484
485
486
487
488
            typename PythonVertex<Graph>::base_t
                vertex_base(get<0>(base), *v, get<2>(base), true);
            python::object source_vertex =
                (PythonVertex<Graph>().GetPythonClass())
                    (python::object(vertex_base));
489
            return source_vertex;
490
        }
491
492
493
494
495
        else
        {
            return python::object();
        }
    }
496

497
    python::object GetTarget()
498
    {
499
500
        if (_base != python::object())
        {
501
            base_t base = python::extract<base_t>(_base);
502
503
            vertex_descriptor *v = new vertex_descriptor;
            *v = target(get<1>(base), get<0>(base));
504
505
506
507
508
            typename PythonVertex<Graph>::base_t
                vertex_base(get<0>(base), *v, get<2>(base), true);
            python::object target_vertex =
                (PythonVertex<Graph>().GetPythonClass())
                (python::object(vertex_base));
509
510
511
512
513
514
515
            return target_vertex;
        }
        else
        {
            return python::object();
        }
    }
516

517
518
519
520
521
522
523
    python::object GetProperty(std::string prop)
    {
        if (_base != python::object())
        {
            base_t base = python::extract<base_t>(_base);
            const dynamic_properties& dp = get<2>(base);
            const edge_descriptor& e = get<1>(base);
524
525
            for(typeof(dp.begin()) iter = dp.lower_bound(prop);
                iter != dp.end(); ++iter)
526
            {
527
528
529
530
531
532
533
534
                typedef typename graph_traits<Graph>::directed_category
                    directed_category;
                if (iter->second->key() != typeid(vertex_descriptor) &&
                    iter->second->key() != typeid(graph_property_tag))
                    return do_get_property(*iter->second, e,
                                           typename is_convertible
                                               <directed_category,
                                                undirected_tag>::type());
535
536
537
538
539
540
541
542
            }
            return python::object();
        }
        else
        {
            return python::object();
        }
    }
543

544
545
    python::object do_get_property(const dynamic_property_map& dmap,
                                   const edge_descriptor& e, false_type)
546
547
548
549
    {
        return get_python_property_value<edge_descriptor>(dmap, e)();
    }

550
551
    python::object do_get_property(const dynamic_property_map& dmap,
                                   const edge_descriptor& e, true_type)
552
553
    {
        typedef typename edge_descriptor::original_edge_t original_edge_t;
554
555
        return get_python_property_value<original_edge_t>
            (dmap, original_edge_t(e))();
556
557
558
559
    }


    void PutProperty(const std::string& prop, const python::object& val)
Tiago Peixoto's avatar
Tiago Peixoto committed
560
561
562
563
564
565
    {
        if (_base != python::object())
        {
            base_t base = python::extract<base_t>(_base);
            const dynamic_properties& dp = get<2>(base);
            const edge_descriptor& e = get<1>(base);
566
567
            for(typeof(dp.begin()) iter = dp.lower_bound(prop);
                iter != dp.end(); ++iter)
Tiago Peixoto's avatar
Tiago Peixoto committed
568
            {
569
570
571
572
573
574
575
576
577
                typedef typename graph_traits<Graph>::directed_category
                    directed_category;

                if (iter->second->key() != typeid(vertex_descriptor) &&
                    iter->second->key() != typeid(graph_property_tag))
                    do_put_property(*iter->second, e, val,
                                    typename is_convertible
                                        <directed_category,
                                         undirected_tag>::type());
Tiago Peixoto's avatar
Tiago Peixoto committed
578
579
580
581
            }
        }
    }

582
583
    void do_put_property(dynamic_property_map& dmap, const edge_descriptor& e,
                         python::object val, false_type)
584
585
586
587
    {
        put_python_property_value<edge_descriptor>(dmap, e, val)();
    }

588
589
    void do_put_property(dynamic_property_map& dmap, const edge_descriptor& e,
                         python::object val, true_type)
590
591
592
593
594
595
    {
        typedef typename edge_descriptor::original_edge_t original_edge_t;
        const original_edge_t& oe = e;
        put_python_property_value<original_edge_t>(dmap, oe, val)();
    }

596
597
598
    python::object GetNParallel()
    {
        if (_base != python::object())
599
        {
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
            base_t base = python::extract<base_t>(_base);
            const Graph& g = get<0>(base);
            const edge_descriptor& e = get<1>(base);
            size_t n = 0;
            vertex_descriptor s,t;
            s = source(e, g);
            t = target(e, g);
            typename graph_traits<Graph>::adjacency_iterator a, a_end;
            for(tie(a, a_end) = adjacent_vertices(s, g); a != a_end; ++a)
                if (*a == t)
                    n++;
            return python::object(n-1);
        }
        else
        {
            return python::object();
616
        }
617
618
    };

619
620
621
    python::object GetHash()
    {
        if (_base != python::object())
622
        {
623
624
625
626
627
628
            base_t base = python::extract<base_t>(_base);
            const Graph& g = get<0>(base);
            const edge_descriptor& e = get<1>(base);
            vertex_descriptor s,t;
            s = source(e, g);
            t = target(e, g);
629
630
631
            return python::object(hash<std::pair<vertex_descriptor,
                                                 vertex_descriptor> >()
                                  (make_pair(s,t)));
632
633
634
635
636
637
638
639
640
641
        }
        else
        {
            return python::object(0);
        }
    }

    bool operator==(const PythonEdge& other)
    {
        if (_base != python::object() && other._base != python::object())
642
        {
643
644
645
646
647
648
649
650
651
652
            const base_t o_base = python::extract<base_t>(other._base);
            base_t base = python::extract<base_t>(_base);
            return python::object(get<1>(base) == get<1>(o_base));
        }
        else
        {
            return false;
        }
    }

653
654
655
656
657
    bool operator!=(const PythonEdge& other)
    {
        return !(*this == other);
    }

658
    python::class_<PythonEdge> GetPythonClass() { return _python_class; }
659

660
661
662
663
664
private:

    python::object _base;
    static python::class_<PythonEdge> _python_class;
};
665

666
667
668
669
template <class Graph>
python::class_<PythonEdge<Graph> >
PythonEdge<Graph>::_python_class =
    python::class_<PythonEdge<Graph> >("Edge", python::no_init);
670

Tiago Peixoto's avatar
Tiago Peixoto committed
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
//==============================================================================
// PythonGraph
//==============================================================================

template <class Graph>
class PythonGraph
{
public:
    PythonGraph(python::object base): _base(base)
    {
        static bool first_time = true;
        if (first_time)
        {
            _python_class.def(python::init<python::object>());
            _python_class.def("num_vertices", &PythonGraph::GetNumVertices);
            _python_class.def("num_edges", &PythonGraph::GetNumEdges);
            _python_class.def("get_vertex", &PythonGraph::GetVertex);
            _python_class.def("get_edge", &PythonGraph::GetEdge);
            _python_class.def("get_property", &PythonGraph::GetProperty);
690
691
692
693
694
695
            _python_class.def("vertices",
                              python::range(&PythonGraph::VertexBegin,
                                            &PythonGraph::VertexEnd));
            _python_class.def("edges",
                              python::range(&PythonGraph::EdgeBegin,
                                            &PythonGraph::EdgeEnd));
Tiago Peixoto's avatar
Tiago Peixoto committed
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
            first_time = false;
        }
    }
    PythonGraph(): _base(python::object()) { *this = PythonGraph(_base); }

    PythonGraph(const PythonGraph& g)
    {
        _base = g._base;
    }

    ~PythonGraph()
    {
    }

    typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
    typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
712
713
    typedef tuple<const Graph&, const edge_descriptor&,
                  const dynamic_properties&, bool> base_t;
Tiago Peixoto's avatar
Tiago Peixoto committed
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750

    python::object GetNumVertices()
    {
        if (_base != python::object())
        {
            base_t base = python::extract<base_t>(_base);
            const Graph& g = get<0>(base);

            return python::object(HardNumVertices()(g));
        }
        else
        {
            return python::object();
        }
    }

    python::object GetNumEdges()
    {
        if (_base != python::object())
        {
            base_t base = python::extract<base_t>(_base);
            const Graph& g = get<0>(base);

            return python::object(HardNumEdges()(g));
        }
        else
        {
            return python::object();
        }
    }

    python::object GetVertex(size_t v_index)
    {
        if (_base != python::object())
        {
            base_t base = python::extract<base_t>(_base);
            const Graph& g = get<0>(base);
751

Tiago Peixoto's avatar
Tiago Peixoto committed
752
753
754
755
756
757
758
759
            size_t count = 0;
            typename graph_traits<Graph>::vertex_iterator v, v_end;
            for (tie(v,v_end) = vertices(g); v != v_end; ++v)
            {
                if (count == v_index)
                {
                    vertex_descriptor *new_v = new vertex_descriptor;
                    *new_v = *v;
760
761
762
763
764
                    typename PythonVertex<Graph>::base_t
                        vertex_base(g, *new_v, get<2>(base), true);
                    python::object vertex =
                        (PythonVertex<Graph>().GetPythonClass())
                        (python::object(vertex_base));
Tiago Peixoto's avatar
Tiago Peixoto committed
765
766
767
768
769
770
771
772
773
774
775
776
777
778
                    return vertex;
                }
                count++;
            }
        }
        return python::object();
    }

    python::object GetEdge(size_t e_index)
    {
        if (_base != python::object())
        {
            base_t base = python::extract<base_t>(_base);
            const Graph& g = get<0>(base);
779

Tiago Peixoto's avatar
Tiago Peixoto committed
780
781
782
783
784
785
786
787
            size_t count = 0;
            typename graph_traits<Graph>::edge_iterator e, e_end;
            for (tie(e,e_end) = edges(g); e != e_end; ++e)
            {
                if (count == e_index)
                {
                    edge_descriptor *new_e = new edge_descriptor;
                    *new_e = *e;
788
789
790
791
792
                    typename PythonEdge<Graph>::base_t edge_base
                        (g, *new_e, get<2>(base), true);
                    python::object edge =
                        (PythonEdge<Graph>().GetPythonClass())
                        (python::object(edge_base));
Tiago Peixoto's avatar
Tiago Peixoto committed
793
794
795
796
797
798
799
800
801
802
803
804
805
806
                    return edge;
                }
                count++;
            }
        }
        return python::object();
    }

    python::object GetProperty(std::string prop)
    {
        if (_base != python::object())
        {
            base_t base = python::extract<base_t>(_base);
            const dynamic_properties& dp = get<2>(base);
807
808
            for(typeof(dp.begin()) iter = dp.lower_bound(prop);
                iter != dp.end(); ++iter)
Tiago Peixoto's avatar
Tiago Peixoto committed
809
810
            {
                if (iter->second->key() == typeid(graph_property_tag))
811
812
                    return get_python_property_value<graph_property_tag>
                        (*iter->second, graph_property_tag())();
Tiago Peixoto's avatar
Tiago Peixoto committed
813
814
815
816
817
818
819
820
821
822
823
            }
        }
        return python::object();
    }

    void PutProperty(std::string prop, python::object val)
    {
        if (_base != python::object())
        {
            base_t base = python::extract<base_t>(_base);
            const dynamic_properties& dp = get<2>(base);
824
825
            for(typeof(dp.begin()) iter = dp.lower_bound(prop);
                iter != dp.end(); ++iter)
Tiago Peixoto's avatar
Tiago Peixoto committed
826
827
            {
                if (iter->second->key() == typeid(graph_property_tag))
828
829
                    put_python_property_value<vertex_descriptor>
                        (*iter->second, graph_property_tag(), val)();
Tiago Peixoto's avatar
Tiago Peixoto committed
830
831
832
833
834
835
            }
        }
    }

    struct descriptor_wrap
    {
836
837
        descriptor_wrap(const Graph &g, const dynamic_properties& dp)
            : _g(g), _dp(dp) {}
Tiago Peixoto's avatar
Tiago Peixoto committed
838
839
840
841
        python::object operator()(vertex_descriptor v)
        {
            vertex_descriptor *new_v = new vertex_descriptor;
            *new_v = v;
842
843
844
845
            typename PythonVertex<Graph>::base_t
                vertex_base(_g, *new_v, _dp, true);
            python::object vertex = (PythonVertex<Graph>().GetPythonClass())
                (python::object(vertex_base));
Tiago Peixoto's avatar
Tiago Peixoto committed
846
847
848
849
850
851
852
853
            return vertex;
        }

        python::object operator()(edge_descriptor e)
        {
            edge_descriptor *new_e = new edge_descriptor;
            *new_e = e;
            typename PythonEdge<Graph>::base_t edge_base(_g, *new_e, _dp, true);
854
855
856
            python::object edge =
                (PythonEdge<Graph>().GetPythonClass())
                (python::object(edge_base));
Tiago Peixoto's avatar
Tiago Peixoto committed
857
858
859
860
861
862
863
864
865
            return edge;
        }

        const Graph& _g;
        const dynamic_properties& _dp;
    };

    typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
    typedef function<python::object (vertex_descriptor)> vertex_wrap_function;
866
867
    typedef transform_iterator<vertex_wrap_function, vertex_iterator>
        wrapped_vertex_iterator;
Tiago Peixoto's avatar
Tiago Peixoto committed
868
869
870
871
872
873
874
875

    wrapped_vertex_iterator VertexBegin()
    {
        if (_base != python::object())
        {
            base_t base = python::extract<base_t>(_base);
            const Graph& g = get<0>(base);
            const dynamic_properties& dp(get<2>(base));
876
877
878
            return wrapped_vertex_iterator
                (vertices(g).first,
                 vertex_wrap_function(descriptor_wrap(g,dp)));
Tiago Peixoto's avatar
Tiago Peixoto committed
879
880
881
882
883
884
885
886
887
888
889
        }
        return wrapped_vertex_iterator();
    }

    wrapped_vertex_iterator VertexEnd()
    {
        if (_base != python::object())
        {
            base_t base = python::extract<base_t>(_base);
            const Graph& g = get<0>(base);
            const dynamic_properties& dp(get<2>(base));
890
891
892
            return wrapped_vertex_iterator
                (vertices(g).second,
                 vertex_wrap_function(descriptor_wrap(g,dp)));
Tiago Peixoto's avatar
Tiago Peixoto committed
893
894
895
896
897
898
        }
        return wrapped_vertex_iterator();
    }

    typedef typename graph_traits<Graph>::edge_iterator edge_iterator;
    typedef function<python::object (edge_descriptor)> edge_wrap_function;
899
900
    typedef transform_iterator<edge_wrap_function, edge_iterator>
        wrapped_edge_iterator;
Tiago Peixoto's avatar
Tiago Peixoto committed
901
902
903
904
905
906
907
908

    wrapped_edge_iterator EdgeBegin()
    {
        if (_base != python::object())
        {
            base_t base = python::extract<base_t>(_base);
            const Graph& g = get<0>(base);
            const dynamic_properties& dp(get<2>(base));
909
910
911
            return wrapped_edge_iterator(edges(g).first,
                                         edge_wrap_function
                                         (descriptor_wrap(g,dp)));
Tiago Peixoto's avatar
Tiago Peixoto committed
912
913
914
915
916
917
918
919
920
921
922
        }
        return wrapped_edge_iterator();
    }

    wrapped_edge_iterator EdgeEnd()
    {
        if (_base != python::object())
        {
            base_t base = python::extract<base_t>(_base);
            const Graph& g = get<0>(base);
            const dynamic_properties& dp(get<2>(base));
923
924
925
            return wrapped_edge_iterator
                (edges(g).second,
                 edge_wrap_function(descriptor_wrap(g,dp)));
Tiago Peixoto's avatar
Tiago Peixoto committed
926
927
928
        }
        return wrapped_edge_iterator();
    }
929

Tiago Peixoto's avatar
Tiago Peixoto committed
930
    python::class_<PythonGraph> GetPythonClass() { return _python_class; }
931

Tiago Peixoto's avatar
Tiago Peixoto committed
932
933
934
935
936
937
private:

    python::object _base;
    static python::class_<PythonGraph> _python_class;
};

938
939
940
941
template <class Graph>
python::class_<PythonGraph<Graph> >
PythonGraph<Graph>::_python_class =
    python::class_<PythonGraph<Graph> >("Graph", python::no_init);
Tiago Peixoto's avatar
Tiago Peixoto committed
942
943


944
945
// the function populate_python_funcs below will populate, in the python
// context, the classes above with its member functions
946
947
948
949
950
951
952
953
954
955
956
957
958

template <class Graph>
struct init_counter
{
    static bool registered;
};
template <class Graph> bool init_counter<Graph>::registered = false;

template <class Descriptor, class HasBase = mpl::bool_<false> >
class populate_python_funcs
{
public:
    template<class Graph>
959
960
    void operator()(const Graph& g, Descriptor& u, const dynamic_properties& dp,
                    python::object& variables)
961
962
    {
        if (!init_counter<Graph>::registered)
963
        {
964
            base_from_tuple<typename PythonVertex<Graph>::base_t>();
965
966
967
            python::to_python_converter
                <typename PythonVertex<Graph>::base_t,
                 base_to_tuple<typename PythonVertex<Graph>::base_t> >();
968
            base_from_tuple<typename PythonEdge<Graph>::base_t>();
969
970
971
            python::to_python_converter
                <typename PythonEdge<Graph>::base_t,
                 base_to_tuple<typename PythonEdge<Graph>::base_t> >();
972
            init_counter<Graph>::registered = true;
973
974
        }

975
976
        variables["Vertex"] = PythonVertex<Graph>().GetPythonClass();
        variables["Edge"] = PythonEdge<Graph>().GetPythonClass();
Tiago Peixoto's avatar
Tiago Peixoto committed
977
        variables["Graph"] = PythonGraph<Graph>().GetPythonClass();
978
979
980
981
982
983
984
985
986
987
        populate_specific(g, u, dp, variables);
    }

private:

    template <class Base>
    struct base_to_tuple
    {
        static PyObject* convert(const Base& b)
        {
988
989
990
991
992
            boost::python::tuple t =
                boost::python::make_tuple(python::long_(size_t(&get<0>(b))),
                                          python::long_(size_t(&get<1>(b))),
                                          python::long_(size_t(&get<2>(b))),
                                          get<3>(b));
993
994
            return python::incref(t.ptr());
        }
995
996
    };

997
998
    template <class Base>
    struct base_from_tuple
999
    {
1000
1001
        base_from_tuple()
        {
1002
1003
            python::converter::registry::push_back(&convertible, &construct,
                                                   boost::python::type_id<Base>());
1004
        }
1005

1006
        static void* convertible(PyObject* obj_ptr)
1007
        {
1008
1009
1010
1011
1012
1013
            python::handle<> x(python::borrowed(obj_ptr));
            python::object o(x);
            python::extract<size_t> first(o[0]);
            python::extract<size_t> second(o[1]);
            python::extract<size_t> third(o[2]);
            python::extract<bool> fourth(o[3]);
1014
1015
            if (!first.check() || !second.check() || !third.check() ||
                !fourth.check())
1016
1017
1018
                return 0;
            return obj_ptr;
        }
1019
1020
1021
1022
1023

        static void construct
            (PyObject* obj_ptr,
             python::converter::rvalue_from_python_stage1_data* data)
        {
1024
1025
            python::handle<> x(python::borrowed(obj_ptr));
            python::object o(x);
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
            typedef typename remove_reference
                <typename tuples::element<0,Base>::type>::type t0;
            typedef typename remove_reference
                <typename tuples::element<1,Base>::type>::type t1;
            typedef typename remove_reference
                <typename tuples::element<2,Base>::type>::type t2;
            t0* p0 = static_cast<t0*>((void *)
                                      size_t(python::extract<size_t>(o[0])));
            t1* p1 = static_cast<t1*>((void *)
                                      size_t(python::extract<size_t>(o[1])));
            t2* p2 = static_cast<t2*>((void *)
                                      size_t(python::extract<size_t>(o[2])));
1038
1039
            bool p4 = python::extract<bool>(o[3]);
            Base value(*p0, *p1, *p2, p4);
1040
1041
1042
1043

            void* storage =
                ( (python::converter::rvalue_from_python_storage<Base>*)
                  data)->storage.bytes;
1044
1045
            new (storage) Base(value);
            data->convertible = storage;
1046
        }
1047
    };
1048

1049
1050

    template <class Graph>
1051
1052
1053
1054
    void populate_specific(const Graph& g,
                           typename graph_traits<Graph>::vertex_descriptor& v,
                           const dynamic_properties& dp,
                           python::object& variables)
1055
    {
1056
        typename PythonVertex<Graph>::base_t vertex_base(g, v, dp, false);
1057
1058
1059
        python::object vertex =
            (PythonVertex<Graph>().GetPythonClass())
            (python::object(vertex_base));
1060
        variables["v"] = vertex;
1061
1062
1063
1064
1065
        typename PythonGraph<Graph>::base_t
            graph_base(g, typename graph_traits<Graph>::edge_descriptor(), dp,
                       false);
        python::object graph =
            (PythonGraph<Graph>().GetPythonClass())(python::object(graph_base));
Tiago Peixoto's avatar
Tiago Peixoto committed
1066
        variables["g"] = graph;
1067
1068
        populate_base(g, v, dp, variables, HasBase());
    }
1069

1070
1071

    template <class Graph>
1072
1073
1074
1075
    void populate_base(const Graph& g,
                       typename graph_traits<Graph>::vertex_descriptor& v,
                       const dynamic_properties& dp, python::object& variables,
                       mpl::bool_<true>)
1076
1077
    {
        if (!init_counter<Graph>::registered)
1078
        {
1079
1080
1081
1082
1083
1084
1085
1086
1087
            typedef typename PythonVertex<typename Graph::graph_type>::base_t
                v_base_t;
            base_from_tuple <v_base_t>();
            python::to_python_converter<v_base_t,base_to_tuple<v_base_t> >();

            typedef typename PythonEdge<typename Graph::graph_type>::base_t
                e_base_t;
            base_from_tuple<e_base_t>();
            python::to_python_converter<e_base_t, base_to_tuple<e_base_t> >();
1088
            init_counter<Graph>::registered = true;
1089
        }
1090

1091
1092
1093
1094
1095
1096
1097
1098
1099
        variables["BaseVertex"] =
            PythonVertex<typename Graph::graph_type>().GetPythonClass();
        variables["BaseEdge"] =
            PythonEdge<typename Graph::graph_type>().GetPythonClass();
        typename PythonVertex<typename Graph::graph_type>::base_t
            vertex_base(g.m_g, v, dp, false);
        python::object vertex =
            (PythonVertex<typename Graph::graph_type>().GetPythonClass())
            (python::object(vertex_base));
1100
        variables["base_v"] = vertex;
1101
1102
1103
1104
1105
1106
1107
        typedef typename graph_traits
            <typename Graph::graph_type>::edge_descriptor edge_t;
        typename PythonGraph<typename Graph::graph_type>::base_t
            graph_base(g.m_g, edge_t(), dp, false);
        python::object graph =
            (PythonGraph<typename Graph::graph_type>().GetPythonClass())
            (python::object(graph_base));
Tiago Peixoto's avatar
Tiago Peixoto committed
1108
        variables["base_g"] = graph;
1109
1110
1111
    }

    template <class Graph>
1112
1113
1114
1115
    void populate_base(const Graph& g,
                       typename graph_traits<Graph>::vertex_descriptor& v,
                       const dynamic_properties& dp, python::object& variables,
                       mpl::bool_<false>)
1116
1117
1118
1119
    {
    }

    template <class Graph>
1120
1121
1122
1123
    void populate_specific(const Graph& g,
                           typename graph_traits<Graph>::edge_descriptor& e,
                           const dynamic_properties& dp,
                           python::object& variables)
1124
1125
    {
        typename PythonEdge<Graph>::base_t edge_base(g, e, dp, false);
1126
1127
        python::object edge =
            (PythonEdge<Graph>().GetPythonClass())(python::object(edge_base));
1128
        variables["e"] = edge;
1129
1130
1131
1132
1133
        typename PythonGraph<Graph>::base_t
            graph_base(g, typename graph_traits<Graph>::edge_descriptor(), dp,
                       false);
        python::object graph =
            (PythonGraph<Graph>().GetPythonClass())(python::object(graph_base));
Tiago Peixoto's avatar
Tiago Peixoto committed
1134
1135
1136
1137
        variables["g"] = graph;
    }

    template <class Graph>
1138
1139
1140
    void populate_specific(const Graph& g, graph_property_tag, 
                           const dynamic_properties& dp, 
                           python::object& variables)
Tiago Peixoto's avatar
Tiago Peixoto committed
1141
    {
1142
1143
1144
1145
1146
        typename PythonGraph<Graph>::base_t 
            graph_base(g, typename graph_traits<Graph>::edge_descriptor(), dp, 
                       false);
        python::object graph = (PythonGraph<Graph>().GetPythonClass())
            (python::object(graph_base));
Tiago Peixoto's avatar
Tiago Peixoto committed
1147
        variables["g"] = graph;
1148
    }
Tiago Peixoto's avatar
Tiago Peixoto committed
1149

1150
1151
};

1152
1153
1154
} //graph_tool namespace

#endif