graph_python_filtering.hh 9.92 KB
Newer Older
1
2
3
4
5
6
7
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
33
34
35
36
37
38
39
40
41
// graph-tool -- a general graph modification and manipulation thingy
//
// Copyright (C) 2006  Tiago de Paula Peixoto <tiago@forked.de>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// 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>
#include <boost/python/dict.hpp>
#include <boost/python/extract.hpp>
#include <boost/python/make_function.hpp>

namespace graph_tool
{
using namespace boost;

//==============================================================================
42
// populate_python_funcs
43
44
//==============================================================================

45
46
47
48
49
template <class Descriptor, class HasBase = mpl::bool_<false> >
struct populate_python_funcs
{
    template<class Graph>
    void operator()(const Graph& g, Descriptor& u, const dynamic_properties& dp, python::object& variables)
50
51
52
    {
	for(typeof(dp.begin()) iter = dp.begin(); iter != dp.end(); ++iter)
	{
53
54
	    if (iter->second->key() == typeid(Descriptor))
		variables[iter->first] = python::make_function(get_value<Descriptor>(*iter->second, u), 
55
56
							       python::default_call_policies(), mpl::vector<python::object>::type());
	}
57
58
	populate_specific(g, u, dp, variables);
    }
59

60
    typedef mpl::vector<in_degreeS, out_degreeS, total_degreeS> degrees;
61

62
63
64
65
66
67
68
69
70
71
72
73
74
75
    template <class Graph>
    void populate_specific(const Graph& g, typename graph_traits<Graph>::vertex_descriptor& v, const dynamic_properties& dp, python::object& variables)
    {
	mpl::for_each<degrees>(put_degree_function<Graph>(g, v, variables));

	typedef typename mpl::if_<HasBase, degrees, mpl::vector<> >::type base_degrees;
	mpl::for_each<base_degrees>(put_base_degree_function<Graph>(g, v, variables, "orig_"));
    }

    template <class Graph>
    void populate_specific(const Graph& g, typename graph_traits<Graph>::edge_descriptor& e, const dynamic_properties& dp, python::object& variables)
    {
	typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;

76
	variables["is_self"] = python::make_function(is_self<Graph>(g, e), python::default_call_policies(), mpl::vector<python::object>::type()); 
77
	variables["n_parallel"] = python::make_function(n_parallel<Graph>(g, e), python::default_call_policies(), mpl::vector<python::object>::type()); 
78
	
79
80
81
	for(typeof(dp.begin()) iter = dp.begin(); iter != dp.end(); ++iter)
	{
	    if (iter->second->key() == typeid(vertex_descriptor))
82
	    {
83
84
85
86
		variables["source_"+iter->first] = python::make_function(get_source_or_target_value<Graph,true>(g, *iter->second, e), 
									 python::default_call_policies(), mpl::vector<python::object>::type());
		variables["target_"+iter->first] = python::make_function(get_source_or_target_value<Graph,false>(g, *iter->second, e), 
									 python::default_call_policies(), mpl::vector<python::object>::type());
87
88
	    }
	}
89
90
	mpl::for_each<degrees>(put_source_or_target_degree_function<Graph,true>(g, e, variables, "source_"));
	mpl::for_each<degrees>(put_source_or_target_degree_function<Graph,false>(g, e, variables, "target_"));
91
    }
92
93


94
95
96
97
98
99
100
101
102
103
104
105
106
    template <class VertexOrEdge>
    struct get_value
    {
	get_value(const dynamic_property_map& dmap, const VertexOrEdge& e)
	    : _dmap(dmap), _e(e) {}
	
	struct try_conversion
	{
	    try_conversion(get_value& parent): _parent(parent) {}

	    template <class Type>
	    void operator()(Type)
	    {
107
108
109
110
		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);
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
	    }
	    
	    get_value& _parent;
	};
	
	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;
	}

	const dynamic_property_map& _dmap;
	const VertexOrEdge& _e;
	python::object _retval;
    };

128
    template <class Graph, bool Source>
129
130
    struct get_source_or_target_value
    {
131
132
133
	typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
	typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;

134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
	get_source_or_target_value(const Graph& g, dynamic_property_map& dmap, const edge_descriptor& e)
	    : _g(g),_dmap(dmap),_e(e){}

	python::object operator()()
	{
	    vertex_descriptor _s;

	    if (Source)
		_s = source(_e, _g);
	    else
		_s = target(_e, _g);

	    get_value<vertex_descriptor> get_value(_dmap, _s);
	    return get_value();
	}

	const Graph& _g;	
	const dynamic_property_map& _dmap;
	const edge_descriptor& _e;	
    };

155
    template <class Graph, class Degree>
156
157
    struct get_degree
    {
158
159
160
	typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;

	get_degree(const Graph& g, const vertex_descriptor& v)
161
162
163
164
165
166
167
	    : _g(g), _v(v) {}
		
	python::object operator()()
	{
	    return python::object(_degree(_v, _g));
	}

168
	const Graph& _g;
169
170
171
172
	const vertex_descriptor& _v;
	Degree _degree;
    };

173
    template <class Graph>
174
175
    struct put_degree_function
    {
176
177
	typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;

178
179
180
181
182
183
184
185
186
187
188
189
190
	put_degree_function(const Graph& g, const vertex_descriptor& v, python::object variables, std::string prefix = "")
	    : _g(g), _v(v), _variables(variables), _prefix(prefix) {}
	template <class Degree>
	void operator()(Degree degree)
	{
	    _variables[_prefix+degree.name()] =  python::make_function(get_degree<Graph,Degree>(_g, _v),
								       python::default_call_policies(), mpl::vector<python::object>::type());
	}
	const Graph& _g;
	const vertex_descriptor& _v;
	python::object& _variables;
	std::string _prefix;
    };
191
192
193

    template <class Graph>    
    struct put_base_degree_function: public put_degree_function<Graph>
194
    {
195
196
	typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;

197
	put_base_degree_function(const Graph& g, const vertex_descriptor& v, python::object& variables, std::string prefix = "")
198
	    : put_degree_function<Graph>(g, v, variables, prefix) {}
199
200
201
202
203
204
205
206
207

	template <class Degree>
	void operator()(Degree degree)
	{
	    this->_variables[this->_prefix+degree.name()] = python::make_function(get_degree<typename Graph::graph_type,Degree>(this->_g.m_g, this->_v),
										  python::default_call_policies(), mpl::vector<python::object>::type());
	}
    };

208
    template <class Graph, bool Source>
209
210
    struct put_source_or_target_degree_function
    {
211
212
213
	typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
	typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;

214
215
216
217
218
219
220
221
222
223
	put_source_or_target_degree_function(const Graph& g, const edge_descriptor& e, python::object& variables, std::string prefix = "")
	    : _g(g), _e(e), _variables(variables), _prefix(prefix) {}
	template <class Degree>
	void operator()(Degree d)
	{
	    vertex_descriptor v;	    
	    if (Source)
		v = source(_e, this->_g);
	    else
		v = target(_e, this->_g);
224
	    put_degree_function<Graph>(_g, v, _variables, _prefix)(d);
225
226
227
228
229
230
231
232
	}

	const Graph& _g;
	const edge_descriptor& _e;
	python::object& _variables;
	std::string _prefix;
    };

233
    template<class Graph>
234
    struct is_self
235
    {
236
237
	typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;

238
	is_self(const Graph& g, const edge_descriptor& e): _g(g), _e(e) {}
239
240
241
242
243
244
245
	python::object operator()()
	{
	    return python::object(source(_e, _g) == target(_e, _g));
	}
	const Graph& _g;
	const edge_descriptor& _e;
    };
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267

    template<class Graph>
    struct n_parallel
    {
	typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;

	n_parallel(const Graph& g, const edge_descriptor& e): _g(g), _e(e) {}
	python::object operator()()
	{
	    size_t n = 0;
	    typename graph_traits<Graph>::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);
	}
	const Graph& _g;
	const edge_descriptor& _e;
    };
268
269
    

270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
};


//==============================================================================
// PythonFilter
//==============================================================================
template <class Graph, class Descriptor, class HasBase = mpl::bool_<false> >
class PythonFilter
{
public:
    typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
    typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;

    typedef mpl::vector<in_degreeS,out_degreeS,total_degreeS> degrees;

    PythonFilter(){}
    PythonFilter(const Graph& g, const dynamic_properties& dp, python::object filter)
        : _g(&g), _filter(filter[0])
    {
	python::object variables = filter[1];
	populate_python_funcs<Descriptor, HasBase>()(*_g, _u, dp, variables);
    }
    
 
    inline bool operator() (Descriptor u) const
295
    {	      
296
	_u = u;
297
298
299
300
301
302
	return python::extract<bool>(_filter());
    }

private:
    Graph const*  _g;
    python::object _filter;
303
    static Descriptor _u;
304
305
};

306
307
template <class Graph, class Descriptor, class HasBase> 
Descriptor PythonFilter<Graph,Descriptor,HasBase>::_u;
308
309
310
311

} //graph_tool namespace

#endif