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

* edit graph property support

* 'Graph' type now available to python editing, with iterators to access all vertices and edges
* out_edges and in_edges return iterators instead of lists for python editing


git-svn-id: https://svn.forked.de/graph-tool/trunk@82 d4600afd-f417-0410-95de-beed9576f240
parent 0cf8f07e
......@@ -84,8 +84,10 @@ filtering.add_option("--reset-edge-filter", action="callback", callback=push_opt
modification = parser.add_option_group("Graph Modification")
modification.add_option("--edit-vertex-property", action="callback", callback=push_option, type="string", metavar="PROPERTY[|TYPE]|EXPRESSION", help="edit the selected vertex property")
modification.add_option("--edit-edge-property", action="callback", callback=push_option, type="string", metavar="PROPERTY[|TYPE]|EXPRESSION", help="edit the selected edge property")
modification.add_option("--edit-graph-property", action="callback", callback=push_option, type="string", metavar="PROPERTY[|TYPE]|EXPRESSION", help="edit the selected graph 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-edge-property", action="callback", callback=push_option, type="string", metavar="PROPERTY|RANGE", help="remove edge property from graph")
modification.add_option("--remove-graph-property", action="callback", callback=push_option, type="string", metavar="PROPERTY|RANGE", help="remove graph 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-edge-index-property", action="callback", callback=push_option, type="string", metavar="PROPERTY", help="insert edge index as property")
modification.add_option("--list-properties", action="callback", callback=push_option, help="list all properties")
......@@ -149,9 +151,8 @@ graph = GraphInterface()
def parse_values(value):
"this will parse the options with multiple values"
p = re.compile(r"([^\|'\"]+|[^\|]+'[^']*'[^\|'\"]+|[^\|]+\"[^\"]*\")(?:\||$)")
values = p.findall(value)
values = [x.strip() for x in values]
p = re.compile(r"((('[^']*')|(\"[^\"']*\"))|([^\|]+)(?=\||$))")
values = [x[0].strip() for x in p.findall(value)]
return values
def get_suboption(suboption, string):
......@@ -758,7 +759,7 @@ def parse_option(opt, just_file=False):
if just_file:
return None
graph.SetReversed(not graph.GetReversed())
elif opt.name == "edit-vertex-property" or opt.name == "edit-edge-property":
elif opt.name in ["edit-vertex-property", "edit-edge-property", "edit-graph-property"]:
values = parse_values(opt.value)
if len(values) < 2 or len(values) > 3:
raise OptionError(opt.name, "invalid value '%s'" % opt.value)
......@@ -777,15 +778,17 @@ def parse_option(opt, just_file=False):
exec expressions[0] in edit_vars
exec open(expressions[1].strip()).read() in edit_vars
else:
exec open(expressions[0].strip()).read() in edit_vars
exec open(expressions[0].strip()).read() in edit_vars
edit_function = edit_vars["edit_function"]
else:
def edit_function():
return (eval(expr,edit_vars))
if opt.name == "edit-vertex-property":
graph.EditVertexProperty(values[0], val_type, (edit_function,edit_vars))
else:
elif opt.name == "edit-edge-property":
graph.EditEdgeProperty(values[0], val_type, (edit_function,edit_vars))
else:
graph.EditGraphProperty(values[0], val_type, (edit_function,edit_vars))
elif opt.name == "remove-vertex-property":
if just_file:
return None
......@@ -794,6 +797,10 @@ def parse_option(opt, just_file=False):
if just_file:
return None
graph.RemoveEdgeProperty(opt.value)
elif opt.name == "remove-graph-property":
if just_file:
return None
graph.RemoveGraphProperty(opt.value)
elif opt.name == "insert-edge-index-property":
if just_file:
return None
......
......@@ -133,12 +133,14 @@ public:
void SetGenericEdgeFilter(boost::python::object filter);
// modification
void RemoveEdgeProperty(std::string property);
void RemoveVertexProperty(std::string property);
void RemoveEdgeProperty(std::string property);
void RemoveGraphProperty(std::string property);
void InsertEdgeIndexProperty(std::string property);
void InsertVertexIndexProperty(std::string property);
void EditVertexProperty(std::string property, std::string type, boost::python::object op);
void EditEdgeProperty(std::string property, std::string type, boost::python::object op);
void EditGraphProperty(std::string property, std::string type, boost::python::object op);
void ListProperties() const;
// layout
......
......@@ -260,8 +260,10 @@ BOOST_PYTHON_MODULE(libgraph_tool)
.def("SetGenericEdgeFilter", &GraphInterfaceWrap::SetGenericEdgeFilter)
.def("EditEdgeProperty", &GraphInterfaceWrap::EditEdgeProperty)
.def("EditVertexProperty", &GraphInterfaceWrap::EditVertexProperty)
.def("EditGraphProperty", &GraphInterfaceWrap::EditGraphProperty)
.def("RemoveEdgeProperty", &GraphInterfaceWrap::RemoveEdgeProperty)
.def("RemoveVertexProperty", &GraphInterfaceWrap::RemoveVertexProperty)
.def("RemoveGraphProperty", &GraphInterfaceWrap::RemoveGraphProperty)
.def("ListProperties", &GraphInterfaceWrap::ListProperties)
.def("InsertEdgeIndexProperty", &GraphInterfaceWrap::InsertEdgeIndexProperty)
.def("InsertVertexIndexProperty", &GraphInterfaceWrap::InsertVertexIndexProperty)
......
......@@ -34,6 +34,9 @@ using namespace boost;
using namespace boost::lambda;
using namespace graph_tool;
typedef mpl::vector<bool, int, long, float, double, std::string> value_types;
char* type_names[] = {"boolean", "int", "long", "float", "double", "string"};
//==============================================================================
// find_property_map(dp,name,key_type)
......@@ -92,14 +95,37 @@ void GraphInterface::RemoveEdgeProperty(string property)
_properties = dp;
}
//==============================================================================
// RemoveGraphProperty(property)
//==============================================================================
void GraphInterface::RemoveGraphProperty(string property)
{
dynamic_properties_copy dp;
try
{
dynamic_property_map& prop_map = find_property_map(_properties, property, typeid(graph_property_tag));
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
template <class Graph>
void operator()(const Graph& g, const dynamic_properties& dp, dynamic_property_map* prop_map, python::object& op) const
{
typedef mpl::vector<in_degreeS,out_degreeS,total_degreeS> degrees;
......@@ -108,51 +134,85 @@ struct edit_property
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;
typedef typename mpl::if_< is_same<Descriptor,vertex_descriptor>,
vertex_descriptor,
typename mpl::if_<is_same<Descriptor,graph_property_tag>,
graph_property_tag,
edge_descriptor>::type >::type descriptor_t;
descriptor_t u;
populate_python_funcs<descriptor_t>()(g, u, dp, variables);
put_properties(g, u, prop_map, operation);
put_properties(g, u, *prop_map, operation);
}
template<class Graph, class PropertyMap>
template<class Graph>
void put_properties(const Graph& g, typename graph_traits<Graph>::vertex_descriptor& v,
PropertyMap prop_map, python::object& operation) const
dynamic_property_map& 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);
python::object val = operation();
prop_map.put(*vi, val);
}
}
template<class Graph, class PropertyMap>
template<class Graph>
void put_properties(const Graph& g, typename graph_traits<Graph>::edge_descriptor& e,
PropertyMap prop_map, python::object& operation) const
dynamic_property_map& 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);
python::object val = operation();
prop_map.put(*ei, val);
}
}
template<class Graph>
void put_properties(const Graph& g, graph_property_tag,
dynamic_property_map& prop_map, python::object& operation) const
{
python::object val = operation();
prop_map.put(graph_property_tag(), val);
}
};
//==============================================================================
// update_property_map()
// get_property_map()
//==============================================================================
template <class ValueTypes, class Descriptor, class IndexMap>
class update_property_map
class get_property_map
{
public:
update_property_map(GraphInterface& gi, dynamic_properties& dp, IndexMap index_map, string property, string type, char* types[], python::object op)
: _gi(gi), _dp(dp), _index_map(index_map), _property(property), _type(type), _types(types), _op(op) {}
get_property_map(GraphInterface& gi, dynamic_properties& dp, IndexMap index_map, string property, string type, char* types[], python::object op, dynamic_property_map*& pmap)
: _gi(gi), _dp(dp), _index_map(index_map), _property(property), _type(type), _types(types), _op(op), _pmap(pmap) {}
template <class ValueType>
class python_dynamic_property_map: public dynamic_property_map
{
public:
python_dynamic_property_map(dynamic_property_map& dmap): _dmap(dmap) {}
virtual void put(const any& key, const any& val)
{
const python::object& o = any_cast<python::object>(val);
ValueType value = python::extract<ValueType>(o);
_dmap.put(key, value);
}
virtual any get(const any& key) { return _dmap.get(key); }
virtual string get_string(const any& key) { return _dmap.get_string(key); }
virtual const std::type_info& key() const { return _dmap.key(); }
virtual const std::type_info& value() const { return _dmap.value(); }
private:
dynamic_property_map& _dmap;
};
template <class ValueType>
void operator()(ValueType)
......@@ -161,21 +221,19 @@ public:
{
try
{
dynamic_property_map& dpmap = find_property_map(_dp, _property, typeid(Descriptor));
typedef DynamicPropertyMapWrap<ValueType,Descriptor> prop_map_t;
prop_map_t prop_map(dpmap);
check_filter(_gi, bind<void>(edit_property<Descriptor>(), _1, var(_dp), prop_map, var(_op)),
reverse_check(), directed_check());
dynamic_property_map& pmap = find_property_map(_dp, _property, typeid(Descriptor));
if (pmap.value() != typeid(ValueType))
throw GraphException("property \""+ _property + "\" already exists with a type other than " + _type +
". Remove it first, or use the same type when editing.");
_pmap = new python_dynamic_property_map<ValueType>(pmap);
}
catch (property_not_found)
{
typedef vector_property_map<ValueType, IndexMap> prop_map_t;
prop_map_t prop_map(_index_map);
check_filter(_gi, bind<void>(edit_property<Descriptor>(), _1, var(_dp), prop_map, var(_op)),
reverse_check(), directed_check());
_dp.property(_property, prop_map);
}
_pmap = new python_dynamic_property_map<ValueType>(find_property_map(_dp, _property, typeid(typename IndexMap::key_type)));
}
}
}
......@@ -187,6 +245,7 @@ private:
string _type;
char** _types;
python::object _op;
dynamic_property_map*& _pmap;
};
......@@ -196,9 +255,6 @@ private:
void GraphInterface::EditVertexProperty(string property, string type, python::object op)
{
typedef mpl::vector<bool, int, long, float, double, std::string> value_types;
char* type_names[] = {"boolean", "int", "long", "float", "double", "string"};
bool valid = false;
for(int i = 0; i < mpl::size<value_types>::type::value; ++i)
if (type == type_names[i])
......@@ -206,8 +262,12 @@ void GraphInterface::EditVertexProperty(string property, string type, python::ob
if (!valid)
throw GraphException("invalid type: " + type);
dynamic_property_map* pmap;
typedef graph_traits<multigraph_t>::vertex_descriptor vertex_descriptor;
mpl::for_each<value_types>(update_property_map<value_types,vertex_descriptor,vertex_index_map_t>(*this, _properties, _vertex_index, property, type, type_names, op));
mpl::for_each<value_types>(get_property_map<value_types,vertex_descriptor,vertex_index_map_t>(*this, _properties, _vertex_index, property, type, type_names, op, pmap));
check_filter(*this, lambda::bind<void>(edit_property<vertex_descriptor>(), lambda::_1, var(_properties), var(pmap), var(op)),
reverse_check(), directed_check());
delete pmap;
}
//==============================================================================
......@@ -216,9 +276,6 @@ void GraphInterface::EditVertexProperty(string property, string type, python::ob
void GraphInterface::EditEdgeProperty(string property, string type, python::object op)
{
typedef mpl::vector<bool, int, long, float, double, std::string> value_types;
char* type_names[] = {"boolean", "int", "long", "float", "double", "string"};
bool valid = false;
for(int i = 0; i < mpl::size<value_types>::type::value; ++i)
if (type == type_names[i])
......@@ -226,10 +283,36 @@ void GraphInterface::EditEdgeProperty(string property, string type, python::obje
if (!valid)
throw GraphException("invalid type: " + type);
dynamic_property_map* pmap;
typedef graph_traits<multigraph_t>::edge_descriptor edge_descriptor;
mpl::for_each<value_types>(update_property_map<value_types,edge_descriptor,edge_index_map_t>(*this, _properties, _edge_index, property, type, type_names, op));
mpl::for_each<value_types>(get_property_map<value_types,edge_descriptor,edge_index_map_t>(*this, _properties, _edge_index, property, type, type_names, op, pmap));
check_filter(*this, lambda::bind<void>(edit_property<edge_descriptor>(), lambda::_1, var(_properties), var(pmap), var(op)),
reverse_check(), directed_check());
delete pmap;
}
//==============================================================================
// EditGraphProperty()
//==============================================================================
void GraphInterface::EditGraphProperty(string property, string type, python::object op)
{
bool valid = false;
for(int i = 0; i < mpl::size<value_types>::type::value; ++i)
if (type == type_names[i])
valid = true;
if (!valid)
throw GraphException("invalid type: " + type);
dynamic_property_map* pmap;
ConstantPropertyMap<size_t,graph_property_tag> graph_index(0);
mpl::for_each<value_types>(get_property_map<value_types,graph_property_tag,ConstantPropertyMap<size_t,graph_property_tag> >(*this, _properties, graph_index, property, type, type_names, op, pmap));
check_filter(*this, lambda::bind<void>(edit_property<graph_property_tag>(), lambda::_1, var(_properties), var(pmap), var(op)),
reverse_check(), directed_check());
delete pmap;
}
//==============================================================================
// ListProperties()
//==============================================================================
......@@ -253,9 +336,6 @@ private:
void GraphInterface::ListProperties() const
{
typedef mpl::vector<bool, int, long, float, double, std::string> value_types;
char* type_names[] = {"boolean", "int", "long", "float", "double", "string"};
for (typeof(_properties.begin()) p = _properties.begin(); p != _properties.end(); ++p)
{
cout << setw(15) << left << p->first << " " << setw(8) << left;
......
This diff is collapsed.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment