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

Fix copying of internal property maps during graph pruning

parent 0072e255
......@@ -57,7 +57,8 @@ class GraphInterface
GraphInterface(const GraphInterface& g, bool keep_ref);
GraphInterface(const GraphInterface& g, bool keep_ref,
python::object ovprops, python::object oeprops);
// useful enums
......@@ -347,7 +347,8 @@ BOOST_PYTHON_MODULE(libgraph_tool_core)
def("raise_error", &raise_error);
def("get_property_types", &get_property_types);
.def("empty", &boost::any::empty);
def("graph_filtering_enabled", &graph_filtering_enabled);
def("openmp_enabled", &openmp_enabled);
......@@ -355,7 +356,7 @@ BOOST_PYTHON_MODULE(libgraph_tool_core)
class_<GraphInterface>("GraphInterface", init<>())
.def("GetNumberOfVertices", &GraphInterface::GetNumberOfVertices)
.def("GetNumberOfEdges", &GraphInterface::GetNumberOfEdges)
.def("SetDirected", &GraphInterface::SetDirected)
......@@ -18,7 +18,9 @@
#include "graph.hh"
#include "graph_filtering.hh"
#include "graph_properties.hh"
#include "graph_selectors.hh"
#include <boost/mpl/for_each.hpp>
#include <boost/mpl/contains.hpp>
#include <boost/python/extract.hpp>
......@@ -26,16 +28,69 @@ using namespace std;
using namespace boost;
using namespace graph_tool;
template <class Descriptor, class GraphTgt, class GraphSrc, class IndexMap>
struct copy_property_dispatch
copy_property_dispatch(const Descriptor& src_d, const Descriptor& tgt_d,
const GraphTgt& tgt, const GraphSrc& src,
boost::any& prop_src, boost::any& prop_tgt,
IndexMap& index_map, bool& found)
: src_d(src_d), tgt_d(tgt_d), tgt(tgt), src(src), prop_src(prop_src),
prop_tgt(prop_tgt), index_map(index_map), found(found) {}
const Descriptor& src_d;
const Descriptor& tgt_d;
const GraphTgt& tgt;
const GraphSrc& src;
boost::any& prop_src;
boost::any& prop_tgt;
IndexMap& index_map;
bool& found;
template <class PropertyMap>
void operator()(PropertyMap) const
PropertyMap* psrc = any_cast<PropertyMap>(&prop_src);
if (psrc == NULL)
if (prop_tgt.empty())
prop_tgt = PropertyMap(index_map);
PropertyMap* ptgt = any_cast<PropertyMap>(&prop_tgt);
if (ptgt == NULL)
(*ptgt)[tgt_d] = (*psrc)[src_d];
found = true;
template <class PropertyMaps, class Descriptor, class GraphTgt, class GraphSrc,
class IndexMap>
void copy_property(const Descriptor& src_d, const Descriptor& tgt_d,
boost::any& prop_src, boost::any& prop_tgt,
const GraphTgt& tgt, const GraphSrc& src,
IndexMap& index_map)
bool found = false;
mpl::for_each<PropertyMaps>(copy_property_dispatch<Descriptor, GraphTgt, GraphSrc, IndexMap>
(src_d, tgt_d, tgt, src, prop_src, prop_tgt, index_map,
if (!found)
throw ValueException("Cannot find property map type.");
struct do_graph_copy
template <class GraphDst, class GraphSrc, class DstVertexIndexMap,
class SrcVertexIndexMap, class DstEdgeIndexMap,
template <class GraphTgt, class GraphSrc, class TgtVertexIndexMap,
class SrcVertexIndexMap, class TgtEdgeIndexMap,
class SrcEdgeIndexMap>
void operator()(const GraphSrc& src, GraphDst& dst,
DstVertexIndexMap src_vertex_index,
SrcVertexIndexMap dst_vertex_index,
DstEdgeIndexMap src_edge_index,
SrcEdgeIndexMap dst_edge_index) const
void operator()(const GraphSrc& src, GraphTgt& tgt,
TgtVertexIndexMap src_vertex_index,
SrcVertexIndexMap tgt_vertex_index,
TgtEdgeIndexMap src_edge_index,
SrcEdgeIndexMap tgt_edge_index,
vector<pair<reference_wrapper<boost::any>,reference_wrapper<boost::any> > >& vprops,
vector<pair<reference_wrapper<boost::any>,reference_wrapper<boost::any> > >& eprops) const
vector<size_t> index_map(num_vertices(src));
typename graph_traits<GraphSrc>::vertex_iterator v, v_end;
......@@ -43,25 +98,38 @@ struct do_graph_copy
if (src_vertex_index[*v] >= index_map.size())
typename graph_traits<GraphDst>::vertex_descriptor new_v =
index_map[src_vertex_index[*v]] = dst_vertex_index[new_v];
typename graph_traits<GraphTgt>::vertex_descriptor new_v =
index_map[src_vertex_index[*v]] = tgt_vertex_index[new_v];
for (size_t i = 0; i < vprops.size(); ++i)
(*v, new_v, vprops[i].first.get(), vprops[i].second.get(),
src, tgt, tgt_vertex_index);
size_t e_idx = 0;
typename graph_traits<GraphSrc>::edge_iterator e, e_end;
for (tie(e, e_end) = edges(src); e != e_end; ++e)
size_t s = index_map[src_vertex_index[source(*e, src)]];
size_t t = index_map[src_vertex_index[target(*e, src)]];
typename graph_traits<GraphDst>::edge_descriptor new_e =
add_edge(vertex(s,dst), vertex(t,dst), dst).first;
dst_edge_index[new_e] = src_edge_index[*e];
typedef typename graph_traits<GraphTgt>::edge_descriptor edge_t;
edge_t new_e = add_edge(vertex(s,tgt), vertex(t,tgt), tgt).first;
tgt_edge_index[new_e] = e_idx;
for (size_t i = 0; i < eprops.size(); ++i)
(edge_t(*e), new_e, eprops[i].first.get(), eprops[i].second.get(),
src, tgt, tgt_edge_index);
// copy constructor
GraphInterface::GraphInterface(const GraphInterface& gi, bool keep_ref)
GraphInterface::GraphInterface(const GraphInterface& gi, bool keep_ref,
python::object ovprops, python::object oeprops)
:_state(keep_ref ? gi._state : shared_ptr<state_t>(new state_t())),
_vertex_index(get(vertex_index, _state->_mg)),
_edge_index(get(edge_index_t(), _state->_mg)),
......@@ -76,15 +144,29 @@ GraphInterface::GraphInterface(const GraphInterface& gi, bool keep_ref)
if (keep_ref)
_state->_nedges = gi._state->_nedges;
_state->_max_edge_index = gi._state->_max_edge_index;
_state->_free_indexes = gi._state->_free_indexes;
vector<pair<reference_wrapper<boost::any>,reference_wrapper<boost::any> > > vprops;
for (int i = 0; i < python::len(ovprops); ++i)
vector<pair<reference_wrapper<boost::any>,reference_wrapper<boost::any> > > eprops;
for (int i = 0; i < python::len(oeprops); ++i)
bind<void>(do_graph_copy(), _1, ref(_state->_mg),
gi._vertex_index, _vertex_index,
gi._edge_index, _edge_index))();
gi._vertex_index, _vertex_index,
gi._edge_index, _edge_index, ref(vprops),
_state->_nedges = num_edges(_state->_mg);
_state->_max_edge_index = _state->_nedges > 0 ? num_edges(_state->_mg) - 1 : 0;
// filters will be copied in python
......@@ -515,14 +515,19 @@ struct new_property_map
template <class ValueType, class IndexMap>
void operator()(ValueType, IndexMap index, const string& type_name,
python::object& new_prop, bool& found) const
boost::any pmap, python::object& new_prop, bool& found) const
size_t i = mpl::find<value_types,ValueType>::type::pos::value;
if (type_name == type_names[i])
typedef typename property_map_type::apply<ValueType, IndexMap>::type
map_t prop(index);
map_t prop;
if (pmap.empty())
prop = map_t(index);
prop = any_cast<map_t>(pmap);
new_prop = python::object(PythonPropertyMap<map_t>(prop));
found = true;
......@@ -530,12 +535,13 @@ struct new_property_map
template <class IndexMap>
python::object new_property(const string& type, IndexMap index_map)
python::object new_property(const string& type, IndexMap index_map,
boost::any pmap)
python::object prop;
bool found = false;
mpl::for_each<value_types>(bind<void>(new_property_map(), _1, index_map,
ref(type), ref(prop), ref(found)));
ref(type), pmap, ref(prop), ref(found)));
if (!found)
throw ValueException("Invalid property type: " + type);
return prop;
......@@ -375,7 +375,7 @@ class PropertyMap(object):
``python::object`` ``object``
======================= ======================
def __init__(self, pmap, g, key_type, key_trans=None):
def __init__(self, pmap, g, key_type):
self.__map = pmap
self.__g = weakref.ref(g)
self.__base_g = lambda: None
......@@ -387,9 +387,15 @@ class PropertyMap(object):
except NameError:
pass # ignore if GraphView is yet undefined
self.__key_type = key_type
self.__key_trans = key_trans if key_trans is not None else lambda k: k
def __key_trans(self, key):
if self.key_type() == "g":
return key._Graph__graph
return key
def __register_map(self):
for g in [self.__g(), self.__base_g()]:
if g is not None:
......@@ -932,15 +938,41 @@ class Graph(object):
vprune, eprune, rprune = prune
if not (vprune or eprune or rprune):
g.stash_filter(vertex=vprune, edge=vprune, reversed=rprune)
self.__graph = libcore.GraphInterface(g.__graph, False)
# Copy all internal properties from original graph.
vprops = []
eprops = []
for k, v in g.vertex_properties.items():
vprops.append([_prop("v", g, v), libcore.any()])
for k, v in g.edge_properties.items():
eprops.append([_prop("e", g, v), libcore.any()])
# The actual copying of the graph and property maps
self.__graph = libcore.GraphInterface(g.__graph, False, vprops, eprops)
# Put the copied properties in the internal dictionary
for k, v in g.vertex_properties.items():
pmap = new_vertex_property(v.value_type(),
self.vertex_properties[k] = PropertyMap(pmap, self, "v")
del vprops[0]
for k, v in g.edge_properties.items():
pmap = new_edge_property(v.value_type(),
self.edge_properties[k] = PropertyMap(pmap, self, "e")
del eprops[0]
for k, v in g.graph_properties.items():
new_p = self.new_graph_property(v.value_type())
new_p[self] = v[g]
self.graph_properties[k] = new_p
if not (vprune or eprune or rprune):
g.pop_filter(vertex=vprune, edge=vprune, reversed=rprune)
for k, v in g.__properties.items():
new_p = self.new_property(v.key_type(), v.value_type())
self.copy_property(v, new_p, g=g)[k] = new_p
self.__stashed_filter_state = [self.get_filter_state()]
if not vprune:
......@@ -977,9 +1009,6 @@ class Graph(object):
if vprune or eprune:
# internal index maps
self.__vertex_index = \
PropertyMap(libcore.get_vertex_index(self.__graph), self, "v")
......@@ -1364,23 +1393,26 @@ class Graph(object):
"""Create a new (uninitialized) vertex property map of type
``value_type``, and return it."""
return PropertyMap(new_vertex_property(_type_alias(value_type),
self, "v")
def new_edge_property(self, value_type):
"""Create a new (uninitialized) edge property map of type
``value_type``, and return it."""
return PropertyMap(new_edge_property(_type_alias(value_type),
self, "e")
def new_graph_property(self, value_type, val=None):
"""Create a new graph property map of type ``value_type``, and return
it. If ``val`` is not None, the property is initialized to its value."""
prop = PropertyMap(new_graph_property(_type_alias(value_type),
self, "g", lambda k: k.__graph)
if val != None:
self, "g")
if val is not None:
prop[self] = val
return prop
......@@ -1464,8 +1496,7 @@ class Graph(object):
for name, prop in props[1].items():
self.edge_properties[name] = PropertyMap(prop, self, "e")
for name, prop in props[2].items():
self.graph_properties[name] = PropertyMap(prop, self, "g",
lambda k: k.__graph)
self.graph_properties[name] = PropertyMap(prop, self, "g")
if "_Graph__save__vfilter" in self.graph_properties:
......@@ -1886,9 +1917,11 @@ class GraphView(Graph):
self.__base = g if not isinstance(g, GraphView) else g.base
# copy graph reference
self._Graph__graph = libcore.GraphInterface(g._Graph__graph, True)
self._Graph__properties = g._Graph__properties
self._Graph__known_properties = g._Graph__known_properties
self._Graph__graph = libcore.GraphInterface(g._Graph__graph, True,
[], [])
for k, v in[k] = self.own_property(v)
# set already existent filters
vf = g.get_vertex_filter()
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