graph_python_interface.hh 35.6 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
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// 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
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

#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>
33
#include <boost/python/class.hpp>
34
#include <boost/python/dict.hpp>
35
#include <boost/python/long.hpp>
36
37
#include <boost/python/extract.hpp>
#include <boost/python/make_function.hpp>
38
39
#include <boost/python/self.hpp>
#include <boost/python/operators.hpp>
Tiago Peixoto's avatar
Tiago Peixoto committed
40
#include <boost/python/iterator.hpp>
41
#include <boost/functional/hash.hpp>
Tiago Peixoto's avatar
Tiago Peixoto committed
42
43
#include <boost/iterator/transform_iterator.hpp>
#include <boost/functional.hpp>
44
45
46
47
48

namespace graph_tool
{
using namespace boost;

49
50
template <class VertexOrEdge>
class get_python_property_value
51
{
52
53
54
55
56
57
58
59
60
61
62
63
64
public:
    get_python_property_value(const dynamic_property_map& dmap, const VertexOrEdge& e)
        : _dmap(dmap), _e(e) {}
        
    python::object operator()()
    {
        typedef mpl::vector<bool,int,long,size_t,float,double,std::string> value_types;
        mpl::for_each<value_types>(try_conversion(*this));
        return _retval;
    }

private:
    struct try_conversion
65
    {
66
67
68
69
        try_conversion(get_python_property_value& parent): _parent(parent) {}
        
        template <class Type>
        void operator()(Type)
70
        {
71
72
73
74
            any any_val = const_cast<dynamic_property_map&>(_parent._dmap).get(_parent._e);
            Type* value = any_cast<Type>(&any_val);
            if (value != 0)
                _parent._retval = python::object(*value);
Tiago Peixoto's avatar
Tiago Peixoto committed
75
        }        
76
77
78
79
80
81
82
        get_python_property_value& _parent;
    };
    
    const dynamic_property_map& _dmap;
    const VertexOrEdge& _e;
    python::object _retval;
};
83

Tiago Peixoto's avatar
Tiago Peixoto committed
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
template <class VertexOrEdge>
class put_python_property_value
{
public:
    put_python_property_value(dynamic_property_map& dmap, const VertexOrEdge& e, python::object val)
        : _dmap(dmap), _e(e), _val(val) {}
        
    void operator()()
    {
        typedef mpl::vector<bool,int,long,size_t,float,double,std::string> value_types;
        mpl::for_each<value_types>(try_conversion(*this));
    }

private:
    struct try_conversion
    {
        try_conversion(put_python_property_value& parent): _parent(parent) {}
        
        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);
            }
        }
        
        put_python_property_value& _parent;
    };
    
    dynamic_property_map& _dmap;
    const VertexOrEdge& _e;
    python::object _val;
};


121
122
template <class Graph>
class PythonEdge;
123

Tiago Peixoto's avatar
Tiago Peixoto committed
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
//==============================================================================
// PythonVertex
//==============================================================================

template <class Graph, class IsDirected> 
struct in_edge_iterator
{
    BOOST_MPL_ASSERT((is_same<IsDirected, boost::true_type>));
    BOOST_MPL_ASSERT((is_convertible<typename graph_traits<Graph>::directed_category, boost::directed_tag>));
    typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
    typedef typename graph_traits<Graph>::in_edge_iterator type;
    static std::pair<type,type> in_edges(vertex_descriptor v, const Graph& g) { return boost::in_edges(v,g); }
};

template <class Graph>
struct in_edge_iterator<Graph, boost::false_type>
{
    BOOST_MPL_ASSERT((is_convertible<typename graph_traits<Graph>::directed_category, boost::undirected_tag>));
    typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
    typedef typename graph_traits<Graph>::out_edge_iterator type;
    static std::pair<type,type> in_edges(vertex_descriptor v, const Graph& g) { return make_pair(type(), type()); }
};


148
149
150
151
152
template <class Graph>
class PythonVertex
{
public:
    PythonVertex(python::object base): _base(base)
153
    {
154
155
156
157
158
159
160
        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
161
162
163
            _python_class.def("put_property", &PythonVertex::PutProperty);
            _python_class.def("out_edges", python::range(&PythonVertex::OutEdgesBegin, &PythonVertex::OutEdgesEnd));
            _python_class.def("in_edges", python::range(&PythonVertex::InEdgesBegin, &PythonVertex::InEdgesEnd));
164
            _python_class.def(python::self == python::self);
165
            _python_class.def(python::self != python::self);
166
            _python_class.def("__hash__", &PythonVertex::GetHash);
167
168
169
170
            first_time = false;
        }
    }
    PythonVertex(): _base(python::object()) { *this = PythonVertex(_base); }
171

172
173
174
    PythonVertex(const PythonVertex& v)
    {
        if (v._base != python::object())
175
        {
176
177
            base_t base = python::extract<base_t>(_base);
            if (get<3>(base))
178
            {
179
180
181
182
                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);
183
184
            }
        }
185
186
    }

187
    ~PythonVertex()
188
    {
189
        if (_base != python::object())
190
        {
191
192
193
            base_t base = python::extract<base_t>(_base);
            if (get<3>(base))
                delete &get<1>(base);
194
        }
195
    }
196

197
198
199
    typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
    typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
    typedef tuple<const Graph&, const vertex_descriptor&, const dynamic_properties&, bool> base_t;
200

201
    python::object GetInDegree()
202
    {
203
        if (_base != python::object())
204
        {
205
206
207
208
            base_t base = python::extract<base_t>(_base);
            return python::object(in_degreeS()(get<1>(base), get<0>(base)));
        }
        else
209
        {
210
            return python::object();
211
        }
212
    }
213

214
    python::object GetOutDegree()
215
    {
216
217
218
219
220
221
        if (_base != python::object())
        {
            base_t base = python::extract<base_t>(_base);
            return python::object(out_degree(get<1>(base), get<0>(base)));
        }
        else
222
        {
223
            return python::object();
224
        }
225
    }
226

227
228
229
    python::object GetProperty(std::string prop)
    {
        if (_base != python::object())
230
        {
231
232
233
234
            base_t base = python::extract<base_t>(_base);
            const dynamic_properties& dp = get<2>(base);
            const vertex_descriptor& v = get<1>(base);
            for(typeof(dp.begin()) iter = dp.lower_bound(prop); iter != dp.end(); ++iter)
235
            {
236
237
                if (iter->second->key() == typeid(vertex_descriptor))
                    return get_python_property_value<vertex_descriptor>(*iter->second, v)();
238
            }
239
        }
Tiago Peixoto's avatar
Tiago Peixoto committed
240
        return python::object();
241
    }
242

Tiago Peixoto's avatar
Tiago Peixoto committed
243
    void PutProperty(std::string prop, python::object val)
244
245
    {
        if (_base != python::object())
246
        {
247
248
            base_t base = python::extract<base_t>(_base);
            const dynamic_properties& dp = get<2>(base);
Tiago Peixoto's avatar
Tiago Peixoto committed
249
250
            const vertex_descriptor& v = get<1>(base);
            for(typeof(dp.begin()) iter = dp.lower_bound(prop); iter != dp.end(); ++iter)
251
            {
Tiago Peixoto's avatar
Tiago Peixoto committed
252
253
                if (iter->second->key() == typeid(vertex_descriptor))
                    put_python_property_value<vertex_descriptor>(*iter->second, v, val)();
254
255
            }
        }
Tiago Peixoto's avatar
Tiago Peixoto committed
256
257
258
259
260
261
262
263
    }


    struct descriptor_wrap
    {
        descriptor_wrap(const Graph &g, const dynamic_properties& dp): _g(g), _dp(dp) {}
    
        python::object operator()(edge_descriptor e)
264
        {
Tiago Peixoto's avatar
Tiago Peixoto committed
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
            edge_descriptor *new_e = new edge_descriptor;
            *new_e = e;
            typename PythonEdge<Graph>::base_t edge_base(_g, *new_e, _dp, true);
            python::object edge = (PythonEdge<Graph>().GetPythonClass())(python::object(edge_base));
            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;
    typedef transform_iterator<edge_wrap_function, out_edge_iterator> wrapped_out_edge_iterator;

    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));
            return wrapped_out_edge_iterator(out_edges(v,g).first, edge_wrap_function(descriptor_wrap(g,dp)));
289
        }
Tiago Peixoto's avatar
Tiago Peixoto committed
290
        return wrapped_out_edge_iterator();
291
    }
292

Tiago Peixoto's avatar
Tiago Peixoto committed
293
    wrapped_out_edge_iterator OutEdgesEnd()
294
    {
295
296
297
298
        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
299
300
301
            vertex_descriptor v = get<1>(base);
            const dynamic_properties& dp(get<2>(base));
            return wrapped_out_edge_iterator(out_edges(v,g).second, edge_wrap_function(descriptor_wrap(g,dp)));
302
        }
Tiago Peixoto's avatar
Tiago Peixoto committed
303
304
305
306
307
308
309
310
311
312
        return wrapped_out_edge_iterator();
    }

    typedef typename is_convertible<typename graph_traits<Graph>::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;

    wrapped_in_edge_iterator InEdgesBegin()
    {
        if (_base != python::object())
313
        {
Tiago Peixoto's avatar
Tiago Peixoto committed
314
315
316
317
318
            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));
            return wrapped_in_edge_iterator(in_edge_iterator<Graph,is_directed>::in_edges(v,g).first, edge_wrap_function(descriptor_wrap(g,dp)));
319
        }
Tiago Peixoto's avatar
Tiago Peixoto committed
320
321
322
323
324
325
326
327
328
329
330
331
332
333
        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));
            return wrapped_in_edge_iterator(in_edge_iterator<Graph,is_directed>::in_edges(v,g).second, edge_wrap_function(descriptor_wrap(g,dp)));
        }
        return wrapped_in_edge_iterator();
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
    }

    python::object GetHash()
    {
        if (_base != python::object())
        {            
            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())
        {            
            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
358
        {            
359
360
            return false;
        }
361
    }
362

363
364
365
366
367
    bool operator!=(const PythonVertex& other)
    {
        return !(*this == other);
    }

368
369
370
371
372
373
    python::class_<PythonVertex> GetPythonClass() { return _python_class; }
        
private:
    python::object _base;
    static python::class_<PythonVertex> _python_class;
};
374

375
template <class Graph> python::class_<PythonVertex<Graph> > PythonVertex<Graph>::_python_class =  python::class_<PythonVertex<Graph> >("Vertex", python::no_init);
376

Tiago Peixoto's avatar
Tiago Peixoto committed
377
378
379
//==============================================================================
// PythonEdge
//==============================================================================
380

381
382
383
384
385
386
387
388
389
390
391
392
393
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);
394
            _python_class.def("put_property", &PythonEdge::PutProperty);
395
            _python_class.def("n_parallel", &PythonEdge::GetNParallel);
396
            _python_class.def(python::self == python::self);
397
            _python_class.def(python::self != python::self);
398
            _python_class.def("__hash__", &PythonEdge::GetHash);
399
400
401
402
403
            first_time = false;
        }
    }
    PythonEdge(): _base(python::object()) { *this = PythonEdge(_base); }
    PythonEdge(const PythonEdge& e)
404
    {
405
406
407
408
409
410
411
412
413
414
415
        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);
            }
        }
    }
416

417
418
419
    ~PythonEdge()
    {
        if (_base != python::object())
420
        {
421
422
423
            base_t base = python::extract<base_t>(_base);
            if (get<3>(base))
                delete &get<1>(base);
424
        }
425
    }
426

427
428
429
    typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
    typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
    typedef tuple<const Graph&, const edge_descriptor&, const dynamic_properties&, bool> base_t;
430

431
    python::object GetSource()
432
    {
433
        if (_base != python::object())
434
        {
435
436
437
438
439
440
            base_t base = python::extract<base_t>(_base);
            vertex_descriptor *v = new vertex_descriptor;
            *v = source(get<1>(base), get<0>(base));
            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));
            return source_vertex;
441
        }
442
443
444
445
446
        else
        {
            return python::object();
        }
    }
447

448
    python::object GetTarget()
449
    {
450
451
452
453
454
455
456
457
458
459
460
461
462
463
        if (_base != python::object())
        {
            base_t base = python::extract<base_t>(_base);            
            vertex_descriptor *v = new vertex_descriptor;
            *v = target(get<1>(base), get<0>(base));
            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));
            return target_vertex;
        }
        else
        {
            return python::object();
        }
    }
464

465
466
467
468
469
470
471
472
473
    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);
            for(typeof(dp.begin()) iter = dp.lower_bound(prop); iter != dp.end(); ++iter)
            {
Tiago Peixoto's avatar
Tiago Peixoto committed
474
                if (iter->second->key() != typeid(vertex_descriptor) && iter->second->key() != typeid(graph_property_tag))
475
                    return do_get_property(*iter->second, e, typename is_convertible<typename graph_traits<Graph>::directed_category, undirected_tag>::type());
476
477
478
479
480
481
482
483
            }
            return python::object();
        }
        else
        {
            return python::object();
        }
    }
484

485
486
487
488
489
490
491
492
493
494
495
496
497
    python::object do_get_property(const dynamic_property_map& dmap, const edge_descriptor& e, false_type)
    {
        return get_python_property_value<edge_descriptor>(dmap, e)();
    }

    python::object do_get_property(const dynamic_property_map& dmap, const edge_descriptor& e, true_type)
    {
        typedef typename edge_descriptor::original_edge_t original_edge_t;
        return get_python_property_value<original_edge_t>(dmap, original_edge_t(e))();
    }


    void PutProperty(const std::string& prop, const python::object& val)
Tiago Peixoto's avatar
Tiago Peixoto committed
498
499
500
501
502
503
504
505
506
    {
        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);
            for(typeof(dp.begin()) iter = dp.lower_bound(prop); iter != dp.end(); ++iter)
            {
                if (iter->second->key() != typeid(vertex_descriptor) && iter->second->key() != typeid(graph_property_tag))
507
                    do_put_property(*iter->second, e, val, typename is_convertible<typename graph_traits<Graph>::directed_category, undirected_tag>::type());
Tiago Peixoto's avatar
Tiago Peixoto committed
508
509
510
511
            }
        }
    }

512
513
514
515
516
517
518
519
520
521
522
523
    void do_put_property(dynamic_property_map& dmap, const edge_descriptor& e, python::object val, false_type)
    {
        put_python_property_value<edge_descriptor>(dmap, e, val)();
    }

    void do_put_property(dynamic_property_map& dmap, const edge_descriptor& e, python::object val, true_type)
    {
        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)();
    }

524
525
526
    python::object GetNParallel()
    {
        if (_base != python::object())
527
        {
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
            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();
544
        }
545
546
    };

547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
    python::object GetHash()
    {
        if (_base != python::object())
        {            
            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);
            return python::object(hash<std::pair<vertex_descriptor,vertex_descriptor> >()(make_pair(s,t)));
        }
        else
        {
            return python::object(0);
        }
    }

    bool operator==(const PythonEdge& other)
    {
        if (_base != python::object() && other._base != python::object())
        {            
            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;
        }
    }

579
580
581
582
583
    bool operator!=(const PythonEdge& other)
    {
        return !(*this == other);
    }

584
585
586
587
588
589
590
    python::class_<PythonEdge> GetPythonClass() { return _python_class; }
        
private:

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

592
593
template <class Graph> python::class_<PythonEdge<Graph> > PythonEdge<Graph>::_python_class =  python::class_<PythonEdge<Graph> >("Edge", python::no_init);

Tiago Peixoto's avatar
Tiago Peixoto committed
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
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
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
//==============================================================================
// 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);
            _python_class.def("vertices", python::range(&PythonGraph::VertexBegin, &PythonGraph::VertexEnd));
            _python_class.def("edges", python::range(&PythonGraph::EdgeBegin, &PythonGraph::EdgeEnd));
            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;
    typedef tuple<const Graph&, const edge_descriptor&, const dynamic_properties&, bool> base_t;

    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);
            
            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;
                    typename PythonVertex<Graph>::base_t vertex_base(g, *new_v, get<2>(base), true);
                    python::object vertex = (PythonVertex<Graph>().GetPythonClass())(python::object(vertex_base));
                    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);
            
            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;
                    typename PythonEdge<Graph>::base_t edge_base(g, *new_e, get<2>(base), true);
                    python::object edge = (PythonEdge<Graph>().GetPythonClass())(python::object(edge_base));
                    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);
            for(typeof(dp.begin()) iter = dp.lower_bound(prop); iter != dp.end(); ++iter)
            {
                if (iter->second->key() == typeid(graph_property_tag))
                    return get_python_property_value<graph_property_tag>(*iter->second, graph_property_tag())();
            }
        }
        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);
            for(typeof(dp.begin()) iter = dp.lower_bound(prop); iter != dp.end(); ++iter)
            {
                if (iter->second->key() == typeid(graph_property_tag))
                    put_python_property_value<vertex_descriptor>(*iter->second, graph_property_tag(), val)();
            }
        }
    }

    struct descriptor_wrap
    {
        descriptor_wrap(const Graph &g, const dynamic_properties& dp): _g(g), _dp(dp) {}
        python::object operator()(vertex_descriptor v)
        {
            vertex_descriptor *new_v = new vertex_descriptor;
            *new_v = v;
            typename PythonVertex<Graph>::base_t vertex_base(_g, *new_v, _dp, true);
            python::object vertex = (PythonVertex<Graph>().GetPythonClass())(python::object(vertex_base));
            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);
            python::object edge = (PythonEdge<Graph>().GetPythonClass())(python::object(edge_base));
            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;
    typedef transform_iterator<vertex_wrap_function, vertex_iterator> wrapped_vertex_iterator;

    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));
            return wrapped_vertex_iterator(vertices(g).first, vertex_wrap_function(descriptor_wrap(g,dp)));
        }
        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));
            return wrapped_vertex_iterator(vertices(g).second, vertex_wrap_function(descriptor_wrap(g,dp)));
        }
        return wrapped_vertex_iterator();
    }

    typedef typename graph_traits<Graph>::edge_iterator edge_iterator;
    typedef function<python::object (edge_descriptor)> edge_wrap_function;
    typedef transform_iterator<edge_wrap_function, edge_iterator> wrapped_edge_iterator;

    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));
            return wrapped_edge_iterator(edges(g).first, edge_wrap_function(descriptor_wrap(g,dp)));
        }
        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));
            return wrapped_edge_iterator(edges(g).second, edge_wrap_function(descriptor_wrap(g,dp)));
        }
        return wrapped_edge_iterator();
    }
    
    python::class_<PythonGraph> GetPythonClass() { return _python_class; }
        
private:

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

template <class Graph> python::class_<PythonGraph<Graph> > PythonGraph<Graph>::_python_class =  python::class_<PythonGraph<Graph> >("Graph", python::no_init);


834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
//==============================================================================
// populate_python_funcs
//==============================================================================

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>
    void operator()(const Graph& g, Descriptor& u, const dynamic_properties& dp, python::object& variables)
    {
        if (!init_counter<Graph>::registered)
853
        {
854
855
856
857
858
            base_from_tuple<typename PythonVertex<Graph>::base_t>();
            python::to_python_converter<typename PythonVertex<Graph>::base_t, base_to_tuple<typename PythonVertex<Graph>::base_t> >();
            base_from_tuple<typename PythonEdge<Graph>::base_t>();
            python::to_python_converter<typename PythonEdge<Graph>::base_t, base_to_tuple<typename PythonEdge<Graph>::base_t> >();
            init_counter<Graph>::registered = true;
859
860
        }

861
862
        variables["Vertex"] = PythonVertex<Graph>().GetPythonClass();
        variables["Edge"] = PythonEdge<Graph>().GetPythonClass();
Tiago Peixoto's avatar
Tiago Peixoto committed
863
        variables["Graph"] = PythonGraph<Graph>().GetPythonClass();
864
865
866
867
868
869
870
871
872
873
874
875
876
        populate_specific(g, u, dp, variables);
    }

private:

    template <class Base>
    struct base_to_tuple
    {
        static PyObject* convert(const Base& b)
        {
            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));
            return python::incref(t.ptr());
        }
877
878
    };

879
880
    template <class Base>
    struct base_from_tuple
881
    {
882
883
884
885
        base_from_tuple()
        {
            python::converter::registry::push_back(&convertible, &construct, boost::python::type_id<Base>());
        }
886

887
        static void* convertible(PyObject* obj_ptr)
888
        {
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
            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]);
            if (!first.check() || !second.check() || !third.check() || !fourth.check())
                return 0;
            return obj_ptr;
        }
        
        static void construct(PyObject* obj_ptr, python::converter::rvalue_from_python_stage1_data* data)
        {          
            python::handle<> x(python::borrowed(obj_ptr));
            python::object o(x);
            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])));
            bool p4 = python::extract<bool>(o[3]);
            Base value(*p0, *p1, *p2, p4);
            
            void* storage = ( (python::converter::rvalue_from_python_storage<Base>*) data)->storage.bytes;
            new (storage) Base(value);
            data->convertible = storage;
916
        }
917
    };
918

919
920
921

    template <class Graph>
    void populate_specific(const Graph& g, typename graph_traits<Graph>::vertex_descriptor& v, const dynamic_properties& dp, python::object& variables)
922
    {
923
924
925
        typename PythonVertex<Graph>::base_t vertex_base(g, v, dp, false);
        python::object vertex = (PythonVertex<Graph>().GetPythonClass())(python::object(vertex_base));                
        variables["v"] = vertex;
Tiago Peixoto's avatar
Tiago Peixoto committed
926
927
928
        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));                
        variables["g"] = graph;
929
930
        populate_base(g, v, dp, variables, HasBase());
    }
931

932
933
934
935
936

    template <class Graph>
    void populate_base(const Graph& g, typename graph_traits<Graph>::vertex_descriptor& v, const dynamic_properties& dp, python::object& variables,  mpl::bool_<true>) 
    {
        if (!init_counter<Graph>::registered)
937
        {
938
939
940
941
942
            base_from_tuple<typename PythonVertex<typename Graph::graph_type>::base_t>();
            python::to_python_converter<typename PythonVertex<typename Graph::graph_type>::base_t, base_to_tuple<typename PythonVertex<typename Graph::graph_type>::base_t> >();
            base_from_tuple<typename PythonEdge<typename Graph::graph_type>::base_t>();
            python::to_python_converter<typename PythonEdge<typename Graph::graph_type>::base_t, base_to_tuple<typename PythonEdge<typename Graph::graph_type>::base_t> >();
            init_counter<Graph>::registered = true;
943
        }
944

945
946
947
948
949
        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));
        variables["base_v"] = vertex;
Tiago Peixoto's avatar
Tiago Peixoto committed
950
951
952
        typename PythonGraph<typename Graph::graph_type>::base_t graph_base(g.m_g, typename graph_traits<typename Graph::graph_type>::edge_descriptor(), dp, false);
        python::object graph = (PythonGraph<typename Graph::graph_type>().GetPythonClass())(python::object(graph_base));
        variables["base_g"] = graph;
953
954
955
956
957
958
959
960
961
962
963
964
965
    }

    template <class Graph>
    void populate_base(const Graph& g, typename graph_traits<Graph>::vertex_descriptor& v, const dynamic_properties& dp, python::object& variables,  mpl::bool_<false>)
    {
    }

    template <class Graph>
    void populate_specific(const Graph& g, typename graph_traits<Graph>::edge_descriptor& e, const dynamic_properties& dp, python::object& variables)
    {
        typename PythonEdge<Graph>::base_t edge_base(g, e, dp, false);
        python::object edge = (PythonEdge<Graph>().GetPythonClass())(python::object(edge_base));                
        variables["e"] = edge;
Tiago Peixoto's avatar
Tiago Peixoto committed
966
967
968
969
970
971
972
973
974
975
976
        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));                
        variables["g"] = graph;
    }

    template <class Graph>
    void populate_specific(const Graph& g, graph_property_tag, const dynamic_properties& dp, python::object& variables)
    {
        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));                
        variables["g"] = graph;
977
    }
Tiago Peixoto's avatar
Tiago Peixoto committed
978

979
980
};

981
982
983
} //graph_tool namespace

#endif