Commit c8506c63 authored by Tiago Peixoto's avatar Tiago Peixoto
Browse files

* new python filtering code with different syntax. Now faster...

* definition of HashedDescriptorMap


git-svn-id: https://svn.forked.de/graph-tool/trunk@34 d4600afd-f417-0410-95de-beed9576f240
parent 0ef1419f
......@@ -39,6 +39,7 @@ import math
try:
import psyco
psyco.full()
except ImportError:
pass
......@@ -210,7 +211,8 @@ try:
from scipy.special import *
from scipy.optimize import *
from scipy.optimize.minpack import *
import psyco
import psyco
psyco.full()
except ImportError:
pass
""" in variables
......@@ -453,19 +455,28 @@ def parse_option(opt, just_file=False):
if just_file:
return None
filter_vars = dict()
filter_vars["variables"] = filter_vars
def populate_vars(dict, variables):
for k,v in dict.iteritems():
variables[k] = v
filter_vars["populate_vars"] = populate_vars
try:
exec "def filter_function(props):\n populate_vars(props,variables); return not %s\n" % opt.value in filter_vars
exec """
try:
from math import *
from scipy import *
from scipy.special import *
from scipy.optimize import *
from scipy.optimize.minpack import *
import psyco
psyco.full()
except ImportError:
pass
def filter_function():
return not %s
""" % opt.value in filter_vars
except:
raise OptionError(opt.name, "invalid value '%s': %s" % (opt.value,sys.exc_info()[0]))
if opt.name == "vertex-filter":
graph.SetGenericVertexFilter(filter_vars["filter_function"])
graph.SetGenericVertexFilter((filter_vars["filter_function"],filter_vars))
else:
graph.SetGenericEdgeFilter(filter_vars["filter_function"])
graph.SetGenericEdgeFilter((filter_vars["filter_function"],filter_vars))
elif opt.name == "vertex-range-filter" or opt.name == "edge-range-filter":
if just_file:
return None
......
......@@ -21,6 +21,7 @@ libgraph_tool_la_SOURCES = \
graph.hh\
graph.cc\
graph_filtering.hh\
graph_python_filtering.hh\
graph_selectors.hh\
graph_properties.hh\
graph_properties.cc\
......
......@@ -301,12 +301,8 @@ struct get_component_size_histogram
template <class Graph, class IndexMap, class Hist>
void operator()(const Graph &g, IndexMap index_map, Hist &hist) const
{
typedef DescriptorHash<typename graph_traits<Graph>::vertex_descriptor,IndexMap> hashfc_t;
typedef tr1::unordered_map<typename graph_traits<Graph>::vertex_descriptor, size_t, hashfc_t> map_t;
hashfc_t hasher(index_map);
map_t vertex_to_comp(0,hasher);
typedef associative_property_map<map_t> comp_map_t;
comp_map_t comp_map(vertex_to_comp);
typedef HashedDescriptorMap<IndexMap, size_t> comp_map_t;
comp_map_t comp_map(index_map);
_components(g, comp_map);
......@@ -475,13 +471,8 @@ istream& operator>>(istream &o, pos_t &p ) { char c; o >> p.x >> c >> p.y; retur
void GraphInterface::ComputeGraphLayoutGursoy(size_t iter, size_t seed)
{
// vertex postion map
typedef DescriptorHash<graph_traits<multigraph_t>::vertex_descriptor,vertex_index_map_t> hashfc_t;
typedef tr1::unordered_map<graph_traits<multigraph_t>::vertex_descriptor, pos_t, hashfc_t> map_t;
hashfc_t hasher(_vertex_index);
static map_t vertex_to_pos(0, hasher);
vertex_to_pos = map_t(0, hasher);
typedef associative_property_map<map_t> pos_map_t;
pos_map_t pos_map(vertex_to_pos);
typedef HashedDescriptorMap<vertex_index_map_t, pos_t> pos_map_t;
pos_map_t pos_map(_vertex_index);
check_filter(*this,bind<void>(compute_gursoy(),_1,iter,seed,var(pos_map),var(_vertex_index)),reverse_check(),directed_check());
......@@ -515,13 +506,8 @@ struct compute_spring_block
void GraphInterface::ComputeGraphLayoutSpringBlock(size_t iter, size_t seed)
{
// vertex postion map
typedef DescriptorHash<graph_traits<multigraph_t>::vertex_descriptor,vertex_index_map_t> hashfc_t;
typedef tr1::unordered_map<graph_traits<multigraph_t>::vertex_descriptor, pos_t, hashfc_t> map_t;
hashfc_t hasher(_vertex_index);
static map_t vertex_to_pos(0, hasher);
vertex_to_pos = map_t(0, hasher);
typedef associative_property_map<map_t> pos_map_t;
pos_map_t pos_map(vertex_to_pos);
typedef HashedDescriptorMap<vertex_index_map_t,pos_t> pos_map_t;
pos_map_t pos_map(_vertex_index);
check_filter(*this,bind<void>(compute_spring_block(),_1,iter,seed,var(pos_map),var(_vertex_index)),reverse_check(),directed_check());
......
......@@ -170,14 +170,8 @@ struct set_clustering_to_property
void GraphInterface::SetLocalClusteringToProperty(string property)
{
// vertex postion map
typedef DescriptorHash<graph_traits<multigraph_t>::vertex_descriptor,vertex_index_map_t> hashfc_t;
typedef tr1::unordered_map<graph_traits<multigraph_t>::vertex_descriptor,double,hashfc_t> map_t;
hashfc_t hasher(_vertex_index);
static map_t vertex_to_clust(0, hasher);
vertex_to_clust = map_t(0, hasher);
typedef associative_property_map<map_t> clust_map_t;
clust_map_t clust_map(vertex_to_clust);
typedef HashedDescriptorMap<vertex_index_map_t,double> clust_map_t;
clust_map_t clust_map(_vertex_index);
bool directed = _directed;
_directed = false;
......
......@@ -89,12 +89,8 @@ struct get_average_distance
template <class Graph, class IndexMap, class WeightMap>
void operator()(const Graph &g, IndexMap index_map, WeightMap weights, double &dist) const
{
typedef DescriptorHash<typename graph_traits<Graph>::vertex_descriptor,IndexMap> hashfc_t;
typedef tr1::unordered_map<typename graph_traits<Graph>::vertex_descriptor, double, hashfc_t> map_t;
hashfc_t hasher(index_map);
map_t vertex_to_dist(0,hasher);
typedef associative_property_map<map_t> dist_map_t;
dist_map_t dist_map(vertex_to_dist);
typedef HashedDescriptorMap<IndexMap,double> dist_map_t;
dist_map_t dist_map(index_map);
double distsum = 0;
size_t n = 0;
......
......@@ -35,6 +35,7 @@
#include "graph_adaptor.hh"
#include "graph_selectors.hh"
#include "graph_python_filtering.hh"
namespace graph_tool
{
......@@ -117,128 +118,6 @@ private:
std::pair<value_type, value_type> _range;
};
//==============================================================================
// PythonFilter
//==============================================================================
template <class Graph, class IndexMap, class HasBase = mpl::bool_<false> >
class PythonFilter
{
public:
PythonFilter(){}
PythonFilter(const Graph& g, IndexMap index_map, const dynamic_properties& dp, python::object filter)
: _g(&g), _index_map(index_map), _dp(&dp), _filter(filter) {}
typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
struct get_value
{
get_value(const std::string& name, dynamic_property_map& map, any key, python::dict& d)
: _name(name), _map(map), _key(key), _d(d) {}
template <class Type>
void operator()(Type)
{
try
{
_d[_name] = any_cast<Type>(const_cast<dynamic_property_map&>(_map).get(_key));
}
catch (bad_any_cast){}
}
const std::string& _name;
const dynamic_property_map& _map;
any _key;
python::dict& _d;
};
//FIXME: It would be better to do a specialization for vertex_descriptor, and a general
// dummy put_degree. But GCC doesn't seem to like nested full template specializations
template <class Vertex>
struct put_degree
{
put_degree(const Graph& g, Vertex v, python::dict& d, std::string prefix = "")
: _g(g), _v(v), _d(d), _prefix(prefix) {}
template <class Degree>
void operator()(Degree degree)
{
_d[_prefix+degree.name()] = degree(_v, _g);
}
const Graph& _g;
Vertex _v;
python::dict& _d;
std::string _prefix;
};
template <class Vertex>
struct put_base_degree: public put_degree<Vertex>
{
put_base_degree(const Graph& g, Vertex v, python::dict& d, std::string prefix = ""): put_degree<Vertex>(g,v,d,prefix) {}
template <class Degree>
void operator()(Degree degree)
{
this->_d[this->_prefix+degree.name()] = degree(this->_v, this->_g.m_g);
}
};
typedef mpl::vector<in_degreeS,out_degreeS,total_degreeS> degrees;
inline void put_edge_info(edge_descriptor e, python::dict& d) const
{
if (source(e,*_g) == target(e,*_g))
d["is_loop"] = true;
else
d["is_loop"] = false;
for(typeof(_dp->begin()) iter = _dp->begin(); iter != _dp->end(); ++iter)
{
if (iter->second->key() == typeid(vertex_descriptor))
{
typedef mpl::vector<bool,int,long,size_t,float,double,std::string> value_types;
mpl::for_each<value_types>(get_value("source_"+iter->first, *iter->second, source(e, *_g), d));
mpl::for_each<value_types>(get_value("target_"+iter->first, *iter->second, target(e, *_g), d));
}
}
mpl::for_each<degrees>(put_degree<vertex_descriptor>(*_g, source(e,*_g), d, "source_"));
mpl::for_each<degrees>(put_degree<vertex_descriptor>(*_g, target(e,*_g), d, "target_"));
}
inline void put_edge_info(vertex_descriptor v, python::dict& d) const
{
}
template <class VertexOrEdge>
inline bool operator() (VertexOrEdge e) const
{
BOOST_MPL_ASSERT(( mpl::or_<is_same<VertexOrEdge,vertex_descriptor>,
is_same<VertexOrEdge,edge_descriptor> > ));
python::dict properties;
for(typeof(_dp->begin()) iter = _dp->begin(); iter != _dp->end(); ++iter)
{
if (iter->second->key() == typeid(VertexOrEdge))
{
typedef mpl::vector<bool,int,long,size_t,float,double,std::string> value_types;
mpl::for_each<value_types>(get_value(iter->first, *iter->second, e, properties));
}
}
typedef typename mpl::if_<is_same<VertexOrEdge,vertex_descriptor>, degrees, mpl::vector<> >::type vertex_degrees;
mpl::for_each<vertex_degrees>(put_degree<VertexOrEdge>(*_g, e, properties));
typedef typename mpl::if_<HasBase, vertex_degrees, mpl::vector<> >::type base_degrees;
mpl::for_each<base_degrees>(put_base_degree<VertexOrEdge>(*_g, e, properties, "orig_"));
put_edge_info(e, properties);
return python::extract<bool>(_filter(properties));
}
private:
Graph const* _g;
IndexMap _index_map;
dynamic_properties const* _dp;
python::object _filter;
};
typedef mpl::vector<mpl::bool_<true>, mpl::bool_<false> > reverse_check;
typedef mpl::vector<mpl::bool_<false> > never_reversed;
typedef mpl::vector<mpl::bool_<true> > always_reversed;
......@@ -310,19 +189,19 @@ struct check_directed
template <class Graph, class Action, class ReverseCheck, class DirectedCheck>
void check_python_filter(const Graph& g, const GraphInterface &gi, Action a, bool& found, ReverseCheck, DirectedCheck)
{
typedef PythonFilter<Graph,GraphInterface::vertex_index_map_t> vertex_filter_t;
typedef PythonFilter<Graph,GraphInterface::edge_index_map_t> edge_filter_t;
typedef PythonFilter<Graph,mpl::bool_<true> > vertex_filter_t;
typedef PythonFilter<Graph,mpl::bool_<false> > edge_filter_t;
if (gi._edge_python_filter != python::object())
{
typedef filtered_graph<Graph, edge_filter_t, keep_all> efg_t;
efg_t efg(g,edge_filter_t(g, gi._edge_index, gi._properties, gi._edge_python_filter), keep_all());
efg_t efg(g,edge_filter_t(g, gi._properties, gi._edge_python_filter), keep_all());
if (gi._vertex_python_filter != python::object())
{
typedef PythonFilter<efg_t,GraphInterface::vertex_index_map_t, mpl::bool_<true> > vertex_filter_t;
typedef PythonFilter<efg_t, mpl::bool_<true>, mpl::bool_<true> > vertex_filter_t;
typedef filtered_graph<efg_t,keep_all,vertex_filter_t> vefg_t;
vefg_t vefg(efg,keep_all(),vertex_filter_t(efg, gi._vertex_index, gi._properties, gi._vertex_python_filter));
vefg_t vefg(efg,keep_all(),vertex_filter_t(efg, gi._properties, gi._vertex_python_filter));
mpl::for_each<DirectedCheck>(check_directed<vefg_t,Action,ReverseCheck>(vefg, a, gi._reversed, gi._directed, found));
}
else
......@@ -333,7 +212,7 @@ void check_python_filter(const Graph& g, const GraphInterface &gi, Action a, boo
else if (gi._vertex_python_filter != python::object())
{
typedef filtered_graph<Graph,keep_all,vertex_filter_t> vfg_t;
vfg_t vfg(g,keep_all(),vertex_filter_t(g, gi._vertex_index, gi._properties, gi._vertex_python_filter));
vfg_t vfg(g,keep_all(),vertex_filter_t(g, gi._properties, gi._vertex_python_filter));
mpl::for_each<DirectedCheck>(check_directed<vfg_t,Action,ReverseCheck>(vfg, a, gi._reversed, gi._directed, found));
}
else
......@@ -385,17 +264,32 @@ void check_filter(const GraphInterface &g, Action a, ReverseCheck, DirectedCheck
}
template <class Descriptor, class IndexMap>
class DescriptorHash: public std::unary_function<Descriptor, std::size_t>
template <class IndexMap>
class DescriptorHash: public std::unary_function<typename IndexMap::key_type, std::size_t>
{
public:
DescriptorHash() {}
DescriptorHash(IndexMap index_map): _index_map(index_map) {}
std::size_t operator()(Descriptor const& d) const { return boost::hash_value(_index_map[d]); }
std::size_t operator()(typename IndexMap::key_type const& d) const { return boost::hash_value(_index_map[d]); }
private:
IndexMap _index_map;
};
template <class IndexMap, class Value>
class HashedDescriptorMap:
public associative_property_map<std::tr1::unordered_map<typename IndexMap::key_type,Value,DescriptorHash<IndexMap> > >
{
public:
typedef DescriptorHash<IndexMap> hashfc_t;
typedef std::tr1::unordered_map<typename IndexMap::key_type,Value,hashfc_t> map_t;
typedef associative_property_map<map_t> prop_map_t;
HashedDescriptorMap(IndexMap index_map): prop_map_t(base_map), base_map(0, hashfc_t(index_map)) {}
HashedDescriptorMap(){}
private:
map_t base_map;
};
} //namespace graph_tool
#endif
// 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;
//==============================================================================
// PythonFilter
//==============================================================================
template <class Graph, class VertexFilter, 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];
for(typeof(dp.begin()) iter = dp.begin(); iter != dp.end(); ++iter)
{
if (iter->second->key() == typeid(vertex_descriptor) && VertexFilter::value)
variables[iter->first] = python::make_function(get_value<vertex_descriptor>(*iter->second, _v),
python::default_call_policies(), mpl::vector<python::object>::type());
if (iter->second->key() == typeid(edge_descriptor) && !VertexFilter::value)
variables[iter->first] = python::make_function(get_value<edge_descriptor>(*iter->second, _e),
python::default_call_policies(), mpl::vector<python::object>::type());
}
if (VertexFilter::value)
{
mpl::for_each<degrees>(put_degree_function(*_g, _v, variables));
typedef typename mpl::if_<HasBase, degrees, mpl::vector<> >::type base_degrees;
mpl::for_each<base_degrees>(put_base_degree_function(*_g, _v, variables, "orig_"));
}
else
{
variables["is_loop"] = python::make_function(is_loop(*_g, _e), python::default_call_policies(), mpl::vector<python::object>::type());
for(typeof(dp.begin()) iter = dp.begin(); iter != dp.end(); ++iter)
{
if (iter->second->key() == typeid(vertex_descriptor))
{
variables["source_"+iter->first] = python::make_function(get_source_or_target_value<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<false>(*_g, *iter->second, _e),
python::default_call_policies(), mpl::vector<python::object>::type());
}
}
mpl::for_each<degrees>(put_source_or_target_degree_function<true>(*_g, _e, variables, "source_"));
mpl::for_each<degrees>(put_source_or_target_degree_function<false>(*_g, _e, variables, "target_"));
}
}
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)
{
try
{
_parent._retval = python::object(any_cast<Type>(const_cast<dynamic_property_map&>(_parent._dmap).get(_parent._e)));
}
catch (bad_any_cast){}
}
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;
};
template <bool Source>
struct get_source_or_target_value
{
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;
};
template <class G, class Degree>
struct get_degree
{
get_degree(const G& g, const vertex_descriptor& v)
: _g(g), _v(v) {}
python::object operator()()
{
return python::object(_degree(_v, _g));
}
const G& _g;
const vertex_descriptor& _v;
Degree _degree;
};
struct put_degree_function
{
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;
};
struct put_base_degree_function: public put_degree_function
{
put_base_degree_function(const Graph& g, const vertex_descriptor& v, python::object& variables, std::string prefix = "")
: put_degree_function(g, v, variables, prefix) {}
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());
}
};
template <bool Source>
struct put_source_or_target_degree_function
{
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);
put_degree_function(_g, v, _variables, _prefix)(d);
}
const Graph& _g;
const edge_descriptor& _e;
python::object& _variables;
std::string _prefix;
};
struct is_loop
{
is_loop(const Graph& g, const edge_descriptor& e): _g(g), _e(e) {}
python::object operator()()
{
return python::object(source(_e, _g) == target(_e, _g));
}
const Graph& _g;
const edge_descriptor& _e;
};
inline bool operator() (edge_descriptor e) const
{
_e = e;