Commit 224bd568 authored by Tiago Peixoto's avatar Tiago Peixoto
Browse files

* add EditVertexProperty() and EditEdgeProperty()

* cleanup src/graph/graph_python_filtering.hh


git-svn-id: https://svn.forked.de/graph-tool/trunk@39 d4600afd-f417-0410-95de-beed9576f240
parent 1152b5ed
...@@ -85,6 +85,8 @@ filtering.add_option("--edge-range-filter", action="callback", callback=push_opt ...@@ -85,6 +85,8 @@ filtering.add_option("--edge-range-filter", action="callback", callback=push_opt
filtering.add_option("--reset-edge-filter", action="callback", callback=push_option, help="remove edge filter") filtering.add_option("--reset-edge-filter", action="callback", callback=push_option, help="remove edge filter")
modification = parser.add_option_group("Graph Modification") modification = parser.add_option_group("Graph Modification")
modification.add_option("--edit-vertex-property", action="callback", callback=push_option, type="string", metavar="PROPERTY|EXPRESSION", help="edit the selected vertex property")
modification.add_option("--edit-edge-property", action="callback", callback=push_option, type="string", metavar="PROPERTY|EXPRESSION", help="edit the selected edge property")
modification.add_option("--remove-vertex-property", action="callback", callback=push_option, type="string", metavar="PROPERTY", help="remove vertex property from graph") modification.add_option("--remove-vertex-property", action="callback", callback=push_option, type="string", metavar="PROPERTY", help="remove vertex property from graph")
modification.add_option("--remove-edge-property", action="callback", callback=push_option, type="string", metavar="PROPERTY|RANGE", help="remove edge property from graph") modification.add_option("--remove-edge-property", action="callback", callback=push_option, type="string", metavar="PROPERTY|RANGE", help="remove edge property from graph")
modification.add_option("--insert-vertex-index-property", action="callback", callback=push_option, type="string", metavar="PROPERTY", help="insert vertex index as property") modification.add_option("--insert-vertex-index-property", action="callback", callback=push_option, type="string", metavar="PROPERTY", help="insert vertex index as property")
...@@ -586,6 +588,35 @@ def filter_function(): ...@@ -586,6 +588,35 @@ def filter_function():
if just_file: if just_file:
return None return None
graph.RemoveParallelEdges() graph.RemoveParallelEdges()
elif opt.name == "edit-vertex-property" or opt.name == "edit-edge-property":
values = parse_values(opt.value)
if len(values) != 2:
raise OptionError(opt.name, "invalid value '%s'" % opt.value)
if just_file:
return None
edit_vars = dict()
try:
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 edit_function():
return %s
""" % values[1] in edit_vars
except:
raise OptionError(opt.name, "invalid value '%s': %s" % (opt.value,sys.exc_info()[0]))
if opt.name == "edit-vertex-property":
graph.EditVertexProperty(values[0],(edit_vars["edit_function"],edit_vars))
else:
graph.EditEdgeProperty(values[0],(edit_vars["edit_function"],edit_vars))
elif opt.name == "remove-vertex-property": elif opt.name == "remove-vertex-property":
if just_file: if just_file:
return None return None
......
...@@ -330,50 +330,6 @@ GraphInterface::hist_t GraphInterface::GetComponentSizeHistogram() const ...@@ -330,50 +330,6 @@ GraphInterface::hist_t GraphInterface::GetComponentSizeHistogram() const
return hist; return hist;
} }
//==============================================================================
// RemoveVertexProperty(property)
//==============================================================================
void GraphInterface::RemoveVertexProperty(string property)
{
dynamic_properties_copy dp;
try
{
dynamic_property_map& prop_map = find_property_map(_properties, property, typeid(graph_traits<multigraph_t>::vertex_descriptor));
for (typeof(_properties.begin()) iter = _properties.begin(); iter != _properties.end(); ++iter)
{
if (iter->second != &prop_map)
dp.insert(iter->first, auto_ptr<dynamic_property_map>(iter->second));
}
}
catch (property_not_found)
{
throw GraphException("property '" + property + "' not found");
}
_properties = dp;
}
//==============================================================================
// RemoveEdgeProperty(property)
//==============================================================================
void GraphInterface::RemoveEdgeProperty(string property)
{
dynamic_properties_copy dp;
try
{
dynamic_property_map& prop_map = find_property_map(_properties, property, typeid(graph_traits<multigraph_t>::edge_descriptor));
for (typeof(_properties.begin()) iter = _properties.begin(); iter != _properties.end(); ++iter)
{
if (iter->second != &prop_map)
dp.insert(iter->first, auto_ptr<dynamic_property_map>(iter->second));
}
}
catch (property_not_found)
{
throw GraphException("property '" + property + "' not found");
}
_properties = dp;
}
//============================================================================== //==============================================================================
// InsertEdgeIndexProperty(property) // InsertEdgeIndexProperty(property)
//============================================================================== //==============================================================================
......
...@@ -120,6 +120,8 @@ public: ...@@ -120,6 +120,8 @@ public:
void RemoveVertexProperty(std::string property); void RemoveVertexProperty(std::string property);
void InsertEdgeIndexProperty(std::string property); void InsertEdgeIndexProperty(std::string property);
void InsertVertexIndexProperty(std::string property); void InsertVertexIndexProperty(std::string property);
void EditVertexProperty(std::string property, boost::python::object op);
void EditEdgeProperty(std::string property, boost::python::object op);
void RemoveParallelEdges(); void RemoveParallelEdges();
// layout // layout
......
...@@ -244,6 +244,8 @@ BOOST_PYTHON_MODULE(libgraph_tool) ...@@ -244,6 +244,8 @@ BOOST_PYTHON_MODULE(libgraph_tool)
.def("GetEdgeFilterRange", &GraphInterfaceWrap::GetEdgeFilterRange) .def("GetEdgeFilterRange", &GraphInterfaceWrap::GetEdgeFilterRange)
.def("IsEdgeFilterActive", &GraphInterfaceWrap::IsEdgeFilterActive) .def("IsEdgeFilterActive", &GraphInterfaceWrap::IsEdgeFilterActive)
.def("SetGenericEdgeFilter", &GraphInterfaceWrap::SetGenericEdgeFilter) .def("SetGenericEdgeFilter", &GraphInterfaceWrap::SetGenericEdgeFilter)
.def("EditEdgeProperty", &GraphInterfaceWrap::EditEdgeProperty)
.def("EditVertexProperty", &GraphInterfaceWrap::EditVertexProperty)
.def("RemoveEdgeProperty", &GraphInterfaceWrap::RemoveEdgeProperty) .def("RemoveEdgeProperty", &GraphInterfaceWrap::RemoveEdgeProperty)
.def("RemoveVertexProperty", &GraphInterfaceWrap::RemoveVertexProperty) .def("RemoveVertexProperty", &GraphInterfaceWrap::RemoveVertexProperty)
.def("InsertEdgeIndexProperty", &GraphInterfaceWrap::InsertEdgeIndexProperty) .def("InsertEdgeIndexProperty", &GraphInterfaceWrap::InsertEdgeIndexProperty)
......
...@@ -189,8 +189,8 @@ struct check_directed ...@@ -189,8 +189,8 @@ struct check_directed
template <class Graph, class Action, class ReverseCheck, class DirectedCheck> 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) void check_python_filter(const Graph& g, const GraphInterface &gi, Action a, bool& found, ReverseCheck, DirectedCheck)
{ {
typedef PythonFilter<Graph,mpl::bool_<true> > vertex_filter_t; typedef PythonFilter<Graph,typename graph_traits<Graph>::vertex_descriptor> vertex_filter_t;
typedef PythonFilter<Graph,mpl::bool_<false> > edge_filter_t; typedef PythonFilter<Graph,typename graph_traits<Graph>::edge_descriptor> edge_filter_t;
if (gi._edge_python_filter != python::object()) if (gi._edge_python_filter != python::object())
{ {
...@@ -199,7 +199,7 @@ void check_python_filter(const Graph& g, const GraphInterface &gi, Action a, boo ...@@ -199,7 +199,7 @@ void check_python_filter(const Graph& g, const GraphInterface &gi, Action a, boo
if (gi._vertex_python_filter != python::object()) if (gi._vertex_python_filter != python::object())
{ {
typedef PythonFilter<efg_t, mpl::bool_<true>, mpl::bool_<true> > vertex_filter_t; typedef PythonFilter<efg_t, typename graph_traits<efg_t>::vertex_descriptor, mpl::bool_<true> > vertex_filter_t;
typedef filtered_graph<efg_t,keep_all,vertex_filter_t> vefg_t; typedef filtered_graph<efg_t,keep_all,vertex_filter_t> vefg_t;
vefg_t vefg(efg,keep_all(),vertex_filter_t(efg, 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)); mpl::for_each<DirectedCheck>(check_directed<vefg_t,Action,ReverseCheck>(vefg, a, gi._reversed, gi._directed, found));
......
...@@ -16,17 +16,172 @@ ...@@ -16,17 +16,172 @@
// along with this program; if not, write to the Free Software // along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include <boost/lambda/bind.hpp>
#include "graph.hh"
#include "histogram.hh"
#include "graph_filtering.hh"
#include "graph_selectors.hh"
#include "graph_properties.hh" #include "graph_properties.hh"
using namespace std;
using namespace boost;
using namespace boost::lambda;
using namespace graph_tool;
//============================================================================== //==============================================================================
// find_property_map(dp,name,key_type) // find_property_map(dp,name,key_type)
//============================================================================== //==============================================================================
boost::dynamic_property_map& dynamic_property_map&
graph_tool::find_property_map(const boost::dynamic_properties& dp, std::string name, const std::type_info& key_type) graph_tool::find_property_map(const dynamic_properties& dp, string name, const type_info& key_type)
{ {
for(typeof(dp.begin()) iter = dp.begin(); iter != dp.end(); ++iter) for(typeof(dp.begin()) iter = dp.begin(); iter != dp.end(); ++iter)
if (iter->first == name && iter->second->key() == key_type) if (iter->first == name && iter->second->key() == key_type)
return *iter->second; return *iter->second;
throw boost::property_not_found(name); throw property_not_found(name);
}
//==============================================================================
// RemoveVertexProperty(property)
//==============================================================================
void GraphInterface::RemoveVertexProperty(string property)
{
dynamic_properties_copy dp;
try
{
dynamic_property_map& prop_map = find_property_map(_properties, property, typeid(graph_traits<multigraph_t>::vertex_descriptor));
for (typeof(_properties.begin()) iter = _properties.begin(); iter != _properties.end(); ++iter)
{
if (iter->second != &prop_map)
dp.insert(iter->first, auto_ptr<dynamic_property_map>(iter->second));
}
}
catch (property_not_found)
{
throw GraphException("property '" + property + "' not found");
}
_properties = dp;
}
//==============================================================================
// RemoveEdgeProperty(property)
//==============================================================================
void GraphInterface::RemoveEdgeProperty(string property)
{
dynamic_properties_copy dp;
try
{
dynamic_property_map& prop_map = find_property_map(_properties, property, typeid(graph_traits<multigraph_t>::edge_descriptor));
for (typeof(_properties.begin()) iter = _properties.begin(); iter != _properties.end(); ++iter)
{
if (iter->second != &prop_map)
dp.insert(iter->first, auto_ptr<dynamic_property_map>(iter->second));
}
}
catch (property_not_found)
{
throw GraphException("property '" + property + "' not found");
}
_properties = dp;
}
//==============================================================================
// edit_property
//==============================================================================
template <class Descriptor>
struct edit_property
{
template <class Graph, class PropertyMap>
void operator()(const Graph& g, const dynamic_properties& dp, PropertyMap prop_map, python::object& op) const
{
typedef mpl::vector<in_degreeS,out_degreeS,total_degreeS> degrees;
python::object operation = op[0], variables = op[1];
typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
typedef typename mpl::if_<is_same<Descriptor,vertex_descriptor>,vertex_descriptor,edge_descriptor>::type descriptor_t;
descriptor_t u;
populate_python_funcs<descriptor_t>()(g, u, dp, variables);
put_properties(g, u, prop_map, operation);
}
template<class Graph, class PropertyMap>
void put_properties(const Graph& g, typename graph_traits<Graph>::vertex_descriptor& v,
PropertyMap prop_map, python::object& operation) const
{
typename graph_traits<Graph>::vertex_iterator vi,v_end;
for (tie(vi, v_end) = vertices(g); vi != v_end; ++vi)
{
v = *vi;
typename property_traits<PropertyMap>::value_type val = python::extract<typename property_traits<PropertyMap>::value_type>(operation());
put(prop_map, v, val);
}
}
template<class Graph, class PropertyMap>
void put_properties(const Graph& g, typename graph_traits<Graph>::edge_descriptor& e,
PropertyMap prop_map, python::object& operation) const
{
typename graph_traits<Graph>::edge_iterator ei,e_end;
for (tie(ei, e_end) = edges(g); ei != e_end; ++ei)
{
e = *ei;
typename property_traits<PropertyMap>::value_type val = python::extract<typename property_traits<PropertyMap>::value_type>(operation());
put(prop_map, e, val);
}
}
};
//==============================================================================
// EditVertexProperty()
//==============================================================================
void GraphInterface::EditVertexProperty(string property, python::object op)
{
typedef graph_traits<multigraph_t>::vertex_descriptor vertex_descriptor;
try
{
dynamic_property_map& dpmap = find_property_map(_properties, property, typeid(graph_traits<multigraph_t>::vertex_descriptor));
typedef DynamicPropertyMapWrap<double,vertex_descriptor> prop_map_t;
prop_map_t prop_map(dpmap);
check_filter(*this, bind<void>(edit_property<vertex_descriptor>(), _1, var(_properties), prop_map, var(op)),
reverse_check(), directed_check());
}
catch (property_not_found)
{
typedef vector_property_map<double, vertex_index_map_t> prop_map_t;
prop_map_t prop_map(_vertex_index);
check_filter(*this, bind<void>(edit_property<vertex_descriptor>(), _1, var(_properties), prop_map, var(op)),
reverse_check(), directed_check());
_properties.property(property, prop_map);
}
}
void GraphInterface::EditEdgeProperty(string property, python::object op)
{
typedef graph_traits<multigraph_t>::edge_descriptor edge_descriptor;
try
{
dynamic_property_map& dpmap = find_property_map(_properties, property, typeid(graph_traits<multigraph_t>::edge_descriptor));
typedef DynamicPropertyMapWrap<double,edge_descriptor> prop_map_t;
prop_map_t prop_map(dpmap);
check_filter(*this, bind<void>(edit_property<edge_descriptor>(), _1, var(_properties), prop_map, var(op)),
reverse_check(), directed_check());
}
catch (property_not_found)
{
typedef vector_property_map<double, edge_index_map_t> prop_map_t;
prop_map_t prop_map(_edge_index);
check_filter(*this, bind<void>(edit_property<edge_descriptor>(), _1, var(_properties), prop_map, var(op)),
reverse_check(), directed_check());
_properties.property(property, prop_map);
}
} }
...@@ -39,60 +39,57 @@ namespace graph_tool ...@@ -39,60 +39,57 @@ namespace graph_tool
using namespace boost; using namespace boost;
//============================================================================== //==============================================================================
// PythonFilter // populate_python_funcs
//============================================================================== //==============================================================================
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(){} template <class Descriptor, class HasBase = mpl::bool_<false> >
PythonFilter(const Graph& g, const dynamic_properties& dp, python::object filter) struct populate_python_funcs
: _g(&g), _filter(filter[0]) {
template<class Graph>
void operator()(const Graph& g, Descriptor& u, const dynamic_properties& dp, python::object& variables)
{ {
python::object variables = filter[1];
for(typeof(dp.begin()) iter = dp.begin(); iter != dp.end(); ++iter) for(typeof(dp.begin()) iter = dp.begin(); iter != dp.end(); ++iter)
{ {
if (iter->second->key() == typeid(vertex_descriptor) && VertexFilter::value) if (iter->second->key() == typeid(Descriptor))
variables[iter->first] = python::make_function(get_value<vertex_descriptor>(*iter->second, _v), variables[iter->first] = python::make_function(get_value<Descriptor>(*iter->second, u),
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()); python::default_call_policies(), mpl::vector<python::object>::type());
} }
populate_specific(g, u, dp, variables);
}
if (VertexFilter::value) typedef mpl::vector<in_degreeS, out_degreeS, total_degreeS> degrees;
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(*_g, _v, variables)); mpl::for_each<degrees>(put_degree_function<Graph>(g, v, variables));
typedef typename mpl::if_<HasBase, degrees, mpl::vector<> >::type base_degrees; typedef typename mpl::if_<HasBase, degrees, mpl::vector<> >::type base_degrees;
mpl::for_each<base_degrees>(put_base_degree_function(*_g, _v, variables, "orig_")); mpl::for_each<base_degrees>(put_base_degree_function<Graph>(g, v, variables, "orig_"));
} }
else
template <class Graph>
void populate_specific(const Graph& g, typename graph_traits<Graph>::edge_descriptor& e, const dynamic_properties& dp, python::object& variables)
{ {
variables["is_loop"] = python::make_function(is_loop(*_g, _e), python::default_call_policies(), mpl::vector<python::object>::type()); typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
variables["is_loop"] = python::make_function(is_loop<Graph>(g, e), python::default_call_policies(), mpl::vector<python::object>::type());
for(typeof(dp.begin()) iter = dp.begin(); iter != dp.end(); ++iter) for(typeof(dp.begin()) iter = dp.begin(); iter != dp.end(); ++iter)
{ {
if (iter->second->key() == typeid(vertex_descriptor)) if (iter->second->key() == typeid(vertex_descriptor))
{ {
variables["source_"+iter->first] = python::make_function(get_source_or_target_value<true>(*_g, *iter->second, _e), 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()); 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), 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()); 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<Graph,true>(g, e, variables, "source_"));
mpl::for_each<degrees>(put_source_or_target_degree_function<false>(*_g, _e, variables, "target_")); mpl::for_each<degrees>(put_source_or_target_degree_function<Graph,false>(g, e, variables, "target_"));
}
} }
template <class VertexOrEdge> template <class VertexOrEdge>
struct get_value struct get_value
{ {
...@@ -127,9 +124,12 @@ public: ...@@ -127,9 +124,12 @@ public:
python::object _retval; python::object _retval;
}; };
template <bool Source> template <class Graph, bool Source>
struct get_source_or_target_value struct get_source_or_target_value
{ {
typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
get_source_or_target_value(const Graph& g, dynamic_property_map& dmap, const edge_descriptor& e) get_source_or_target_value(const Graph& g, dynamic_property_map& dmap, const edge_descriptor& e)
: _g(g),_dmap(dmap),_e(e){} : _g(g),_dmap(dmap),_e(e){}
...@@ -151,10 +151,12 @@ public: ...@@ -151,10 +151,12 @@ public:
const edge_descriptor& _e; const edge_descriptor& _e;
}; };
template <class G, class Degree> template <class Graph, class Degree>
struct get_degree struct get_degree
{ {
get_degree(const G& g, const vertex_descriptor& v) typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
get_degree(const Graph& g, const vertex_descriptor& v)
: _g(g), _v(v) {} : _g(g), _v(v) {}
python::object operator()() python::object operator()()
...@@ -162,13 +164,16 @@ public: ...@@ -162,13 +164,16 @@ public:
return python::object(_degree(_v, _g)); return python::object(_degree(_v, _g));
} }
const G& _g; const Graph& _g;
const vertex_descriptor& _v; const vertex_descriptor& _v;
Degree _degree; Degree _degree;
}; };
template <class Graph>
struct put_degree_function struct put_degree_function
{ {
typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
put_degree_function(const Graph& g, const vertex_descriptor& v, python::object variables, std::string prefix = "") put_degree_function(const Graph& g, const vertex_descriptor& v, python::object variables, std::string prefix = "")
: _g(g), _v(v), _variables(variables), _prefix(prefix) {} : _g(g), _v(v), _variables(variables), _prefix(prefix) {}
template <class Degree> template <class Degree>
...@@ -183,10 +188,13 @@ public: ...@@ -183,10 +188,13 @@ public:
std::string _prefix; std::string _prefix;
}; };
struct put_base_degree_function: public put_degree_function template <class Graph>
struct put_base_degree_function: public put_degree_function<Graph>
{ {
typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
put_base_degree_function(const Graph& g, const vertex_descriptor& v, python::object& variables, std::string prefix = "") put_base_degree_function(const Graph& g, const vertex_descriptor& v, python::object& variables, std::string prefix = "")
: put_degree_function(g, v, variables, prefix) {} : put_degree_function<Graph>(g, v, variables, prefix) {}
template <class Degree> template <class Degree>
void operator()(Degree degree) void operator()(Degree degree)
...@@ -196,9 +204,12 @@ public: ...@@ -196,9 +204,12 @@ public:
} }
}; };
template <bool Source> template <class Graph, bool Source>
struct put_source_or_target_degree_function struct put_source_or_target_degree_function
{ {
typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
put_source_or_target_degree_function(const Graph& g, const edge_descriptor& e, python::object& variables, std::string prefix = "") 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) {} : _g(g), _e(e), _variables(variables), _prefix(prefix) {}
template <class Degree> template <class Degree>
...@@ -209,7 +220,7 @@ public: ...@@ -209,7 +220,7 @@ public:
v = source(_e, this->_g); v = source(_e, this->_g);
else else
v = target(_e, this->_g); v = target(_e, this->_g);
put_degree_function(_g, v, _variables, _prefix)(d); put_degree_function<Graph>(_g, v, _variables, _prefix)(d);
} }
const Graph& _g;