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 ...@@ -84,8 +84,10 @@ filtering.add_option("--reset-edge-filter", action="callback", callback=push_opt
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[|TYPE]|EXPRESSION", help="edit the selected vertex property") 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-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-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("--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-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("--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") modification.add_option("--list-properties", action="callback", callback=push_option, help="list all properties")
...@@ -149,9 +151,8 @@ graph = GraphInterface() ...@@ -149,9 +151,8 @@ graph = GraphInterface()
def parse_values(value): def parse_values(value):
"this will parse the options with multiple values" "this will parse the options with multiple values"
p = re.compile(r"([^\|'\"]+|[^\|]+'[^']*'[^\|'\"]+|[^\|]+\"[^\"]*\")(?:\||$)") p = re.compile(r"((('[^']*')|(\"[^\"']*\"))|([^\|]+)(?=\||$))")
values = p.findall(value) values = [x[0].strip() for x in p.findall(value)]
values = [x.strip() for x in values]
return values return values
def get_suboption(suboption, string): def get_suboption(suboption, string):
...@@ -758,7 +759,7 @@ def parse_option(opt, just_file=False): ...@@ -758,7 +759,7 @@ def parse_option(opt, just_file=False):
if just_file: if just_file:
return None return None
graph.SetReversed(not graph.GetReversed()) 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) values = parse_values(opt.value)
if len(values) < 2 or len(values) > 3: if len(values) < 2 or len(values) > 3:
raise OptionError(opt.name, "invalid value '%s'" % opt.value) raise OptionError(opt.name, "invalid value '%s'" % opt.value)
...@@ -777,15 +778,17 @@ def parse_option(opt, just_file=False): ...@@ -777,15 +778,17 @@ def parse_option(opt, just_file=False):
exec expressions[0] in edit_vars exec expressions[0] in edit_vars
exec open(expressions[1].strip()).read() in edit_vars exec open(expressions[1].strip()).read() in edit_vars
else: 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"] edit_function = edit_vars["edit_function"]
else: else:
def edit_function(): def edit_function():
return (eval(expr,edit_vars)) return (eval(expr,edit_vars))
if opt.name == "edit-vertex-property": if opt.name == "edit-vertex-property":
graph.EditVertexProperty(values[0], val_type, (edit_function,edit_vars)) 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)) 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": elif opt.name == "remove-vertex-property":
if just_file: if just_file:
return None return None
...@@ -794,6 +797,10 @@ def parse_option(opt, just_file=False): ...@@ -794,6 +797,10 @@ def parse_option(opt, just_file=False):
if just_file: if just_file:
return None return None
graph.RemoveEdgeProperty(opt.value) 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": elif opt.name == "insert-edge-index-property":
if just_file: if just_file:
return None return None
......
...@@ -133,12 +133,14 @@ public: ...@@ -133,12 +133,14 @@ public:
void SetGenericEdgeFilter(boost::python::object filter); void SetGenericEdgeFilter(boost::python::object filter);
// modification // modification
void RemoveEdgeProperty(std::string property);
void RemoveVertexProperty(std::string property); void RemoveVertexProperty(std::string property);
void RemoveEdgeProperty(std::string property);
void RemoveGraphProperty(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, std::string type, boost::python::object op); 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 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; void ListProperties() const;
// layout // layout
......
...@@ -260,8 +260,10 @@ BOOST_PYTHON_MODULE(libgraph_tool) ...@@ -260,8 +260,10 @@ BOOST_PYTHON_MODULE(libgraph_tool)
.def("SetGenericEdgeFilter", &GraphInterfaceWrap::SetGenericEdgeFilter) .def("SetGenericEdgeFilter", &GraphInterfaceWrap::SetGenericEdgeFilter)
.def("EditEdgeProperty", &GraphInterfaceWrap::EditEdgeProperty) .def("EditEdgeProperty", &GraphInterfaceWrap::EditEdgeProperty)
.def("EditVertexProperty", &GraphInterfaceWrap::EditVertexProperty) .def("EditVertexProperty", &GraphInterfaceWrap::EditVertexProperty)
.def("EditGraphProperty", &GraphInterfaceWrap::EditGraphProperty)
.def("RemoveEdgeProperty", &GraphInterfaceWrap::RemoveEdgeProperty) .def("RemoveEdgeProperty", &GraphInterfaceWrap::RemoveEdgeProperty)
.def("RemoveVertexProperty", &GraphInterfaceWrap::RemoveVertexProperty) .def("RemoveVertexProperty", &GraphInterfaceWrap::RemoveVertexProperty)
.def("RemoveGraphProperty", &GraphInterfaceWrap::RemoveGraphProperty)
.def("ListProperties", &GraphInterfaceWrap::ListProperties) .def("ListProperties", &GraphInterfaceWrap::ListProperties)
.def("InsertEdgeIndexProperty", &GraphInterfaceWrap::InsertEdgeIndexProperty) .def("InsertEdgeIndexProperty", &GraphInterfaceWrap::InsertEdgeIndexProperty)
.def("InsertVertexIndexProperty", &GraphInterfaceWrap::InsertVertexIndexProperty) .def("InsertVertexIndexProperty", &GraphInterfaceWrap::InsertVertexIndexProperty)
......
...@@ -34,6 +34,9 @@ using namespace boost; ...@@ -34,6 +34,9 @@ using namespace boost;
using namespace boost::lambda; using namespace boost::lambda;
using namespace graph_tool; 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) // find_property_map(dp,name,key_type)
...@@ -92,14 +95,37 @@ void GraphInterface::RemoveEdgeProperty(string property) ...@@ -92,14 +95,37 @@ void GraphInterface::RemoveEdgeProperty(string property)
_properties = dp; _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 // edit_property
//============================================================================== //==============================================================================
template <class Descriptor> template <class Descriptor>
struct edit_property struct edit_property
{ {
template <class Graph, class PropertyMap> template <class Graph>
void operator()(const Graph& g, const dynamic_properties& dp, PropertyMap prop_map, python::object& op) const 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; typedef mpl::vector<in_degreeS,out_degreeS,total_degreeS> degrees;
...@@ -108,51 +134,85 @@ struct edit_property ...@@ -108,51 +134,85 @@ struct edit_property
typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor; typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
typedef typename graph_traits<Graph>::edge_descriptor edge_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; descriptor_t u;
populate_python_funcs<descriptor_t>()(g, u, dp, variables); 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, 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; typename graph_traits<Graph>::vertex_iterator vi,v_end;
for (tie(vi, v_end) = vertices(g); vi != v_end; ++vi) for (tie(vi, v_end) = vertices(g); vi != v_end; ++vi)
{ {
v = *vi; v = *vi;
typename property_traits<PropertyMap>::value_type val = python::extract<typename property_traits<PropertyMap>::value_type>(operation()); python::object val = operation();
put(prop_map, v, val); 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, 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; typename graph_traits<Graph>::edge_iterator ei,e_end;
for (tie(ei, e_end) = edges(g); ei != e_end; ++ei) for (tie(ei, e_end) = edges(g); ei != e_end; ++ei)
{ {
e = *ei; e = *ei;
typename property_traits<PropertyMap>::value_type val = python::extract<typename property_traits<PropertyMap>::value_type>(operation()); python::object val = operation();
put(prop_map, e, val); 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> template <class ValueTypes, class Descriptor, class IndexMap>
class update_property_map class get_property_map
{ {
public: public:
update_property_map(GraphInterface& gi, dynamic_properties& dp, IndexMap index_map, string property, string type, char* types[], python::object 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) {} : _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> template <class ValueType>
void operator()(ValueType) void operator()(ValueType)
...@@ -161,21 +221,19 @@ public: ...@@ -161,21 +221,19 @@ public:
{ {
try try
{ {
dynamic_property_map& dpmap = find_property_map(_dp, _property, typeid(Descriptor)); dynamic_property_map& pmap = find_property_map(_dp, _property, typeid(Descriptor));
typedef DynamicPropertyMapWrap<ValueType,Descriptor> prop_map_t; if (pmap.value() != typeid(ValueType))
prop_map_t prop_map(dpmap); throw GraphException("property \""+ _property + "\" already exists with a type other than " + _type +
check_filter(_gi, bind<void>(edit_property<Descriptor>(), _1, var(_dp), prop_map, var(_op)), ". Remove it first, or use the same type when editing.");
reverse_check(), directed_check()); _pmap = new python_dynamic_property_map<ValueType>(pmap);
} }
catch (property_not_found) catch (property_not_found)
{ {
typedef vector_property_map<ValueType, IndexMap> prop_map_t; typedef vector_property_map<ValueType, IndexMap> prop_map_t;
prop_map_t prop_map(_index_map); 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); _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: ...@@ -187,6 +245,7 @@ private:
string _type; string _type;
char** _types; char** _types;
python::object _op; python::object _op;
dynamic_property_map*& _pmap;
}; };
...@@ -196,9 +255,6 @@ private: ...@@ -196,9 +255,6 @@ private:
void GraphInterface::EditVertexProperty(string property, string type, python::object op) 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; bool valid = false;
for(int i = 0; i < mpl::size<value_types>::type::value; ++i) for(int i = 0; i < mpl::size<value_types>::type::value; ++i)
if (type == type_names[i]) if (type == type_names[i])
...@@ -206,8 +262,12 @@ void GraphInterface::EditVertexProperty(string property, string type, python::ob ...@@ -206,8 +262,12 @@ void GraphInterface::EditVertexProperty(string property, string type, python::ob
if (!valid) if (!valid)
throw GraphException("invalid type: " + type); throw GraphException("invalid type: " + type);
dynamic_property_map* pmap;
typedef graph_traits<multigraph_t>::vertex_descriptor vertex_descriptor; 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 ...@@ -216,9 +276,6 @@ void GraphInterface::EditVertexProperty(string property, string type, python::ob
void GraphInterface::EditEdgeProperty(string property, string type, python::object op) 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; bool valid = false;
for(int i = 0; i < mpl::size<value_types>::type::value; ++i) for(int i = 0; i < mpl::size<value_types>::type::value; ++i)
if (type == type_names[i]) if (type == type_names[i])
...@@ -226,10 +283,36 @@ void GraphInterface::EditEdgeProperty(string property, string type, python::obje ...@@ -226,10 +283,36 @@ void GraphInterface::EditEdgeProperty(string property, string type, python::obje
if (!valid) if (!valid)
throw GraphException("invalid type: " + type); throw GraphException("invalid type: " + type);
dynamic_property_map* pmap;
typedef graph_traits<multigraph_t>::edge_descriptor edge_descriptor; 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() // ListProperties()
//============================================================================== //==============================================================================
...@@ -253,9 +336,6 @@ private: ...@@ -253,9 +336,6 @@ private:
void GraphInterface::ListProperties() const 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) for (typeof(_properties.begin()) p = _properties.begin(); p != _properties.end(); ++p)
{ {
cout << setw(15) << left << p->first << " " << setw(8) << left; cout << setw(15) << left << p->first << " " << setw(8) << left;
......
This diff is collapsed.
Supports Markdown
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