Commit 3ba46e75 authored by Tiago Peixoto's avatar Tiago Peixoto
Browse files

Fix graph copying and filtered graph copying semantics

Graphs are now exactly copied, including filter state and filter
property maps.
parent 919ade0c
...@@ -66,18 +66,10 @@ struct graph_copy ...@@ -66,18 +66,10 @@ struct graph_copy
} }
}; };
typedef graph_tool::detail::get_all_graph_views
::apply<graph_tool::detail::scalar_pairs,
mpl::bool_<false>,
mpl::bool_<true>,
mpl::bool_<false>,
mpl::bool_<true>,
mpl::bool_<true> >::type graph_views;
// copy constructor // copy constructor
GraphInterface::GraphInterface(const GraphInterface& gi) GraphInterface::GraphInterface(const GraphInterface& gi)
:_mg(), :_mg(),
_reversed(false), _reversed(gi._reversed),
_directed(gi._directed), _directed(gi._directed),
_vertex_index(get(vertex_index,_mg)), _vertex_index(get(vertex_index,_mg)),
_edge_index(get(edge_index_t(),_mg)), _edge_index(get(edge_index_t(),_mg)),
...@@ -88,15 +80,11 @@ GraphInterface::GraphInterface(const GraphInterface& gi) ...@@ -88,15 +80,11 @@ GraphInterface::GraphInterface(const GraphInterface& gi)
_edge_filter_invert(false), _edge_filter_invert(false),
_edge_filter_active(false) _edge_filter_active(false)
{ {
typedef mpl::transform<detail::all_graph_views,
mpl::quote1<add_pointer> >::type all_graph_views; graph_copy()(&_mg, &gi._mg, _vertex_index,
gi._vertex_index, _edge_index,
run_action<>()(*this, bind<void>(graph_copy(), _1, _2, gi._edge_index);
_vertex_index, // filters will be copied in python
gi._vertex_index,
_edge_index,
gi._edge_index),
all_graph_views())(gi.GetGraphView());
} }
// //
...@@ -156,7 +144,11 @@ struct convert ...@@ -156,7 +144,11 @@ struct convert
{ {
T1 operator()(const string& v) const T1 operator()(const string& v) const
{ {
return lexical_cast<Type1>(v); //uint8_t is not char, it is bool!
if (is_same<T1, uint8_t>::value)
return convert<T1,int>()(lexical_cast<int>(v));
else
return lexical_cast<Type1>(v);
} }
}; };
...@@ -165,7 +157,11 @@ struct convert ...@@ -165,7 +157,11 @@ struct convert
{ {
string operator()(const T2& v) const string operator()(const T2& v) const
{ {
return lexical_cast<string>(v); //uint8_t is not char, it is bool!
if (is_same<T2, uint8_t>::value)
return lexical_cast<string>(convert<int,T2>()(v));
else
return lexical_cast<string>(v);
} }
}; };
...@@ -205,7 +201,7 @@ struct copy_property ...@@ -205,7 +201,7 @@ struct copy_property
{ {
template <class Graph, class PropertySrc, template <class Graph, class PropertySrc,
class PropertyTgt> class PropertyTgt>
void operator()(Graph* tgtp, boost::any srcp, PropertySrc src_map, void operator()(const Graph* tgtp, const Graph* srcp, PropertySrc src_map,
PropertyTgt dst_map) const PropertyTgt dst_map) const
{ {
typedef typename property_traits<PropertySrc>::value_type val_src; typedef typename property_traits<PropertySrc>::value_type val_src;
...@@ -213,8 +209,8 @@ struct copy_property ...@@ -213,8 +209,8 @@ struct copy_property
try try
{ {
Graph& tgt = *tgtp; const Graph& tgt = *tgtp;
Graph& src = *any_cast<Graph*>(srcp); const Graph& src = *srcp;
convert<val_tgt,val_src> c; convert<val_tgt,val_src> c;
typename IteratorSel::template apply<Graph>::type vs, vs_end; typename IteratorSel::template apply<Graph>::type vs, vs_end;
typename IteratorSel::template apply<Graph>::type vt, vt_end; typename IteratorSel::template apply<Graph>::type vt, vt_end;
...@@ -269,19 +265,17 @@ struct vertex_selector ...@@ -269,19 +265,17 @@ struct vertex_selector
} }
}; };
typedef mpl::vector<GraphInterface::multigraph_t> unfiltered;
void GraphInterface::CopyVertexProperty(const GraphInterface& src, void GraphInterface::CopyVertexProperty(const GraphInterface& src,
boost::any prop_src, boost::any prop_src,
boost::any prop_tgt) boost::any prop_tgt)
{ {
typedef property_map_types::apply<mpl::vector<string,vector<string> >,
GraphInterface::edge_index_map_t,
mpl::bool_<false> >::type
edge_properties;
typedef edge_properties writable_edge_properties; typedef edge_properties writable_edge_properties;
run_action<graph_views>() run_action<unfiltered>()
(*this, bind<void>(copy_property<vertex_selector>(), (*this, bind<void>(copy_property<vertex_selector>(),
_1, src.GetGraphView(), _2, _3), _1, &src._mg, _2, _3),
vertex_properties(), writable_vertex_properties()) vertex_properties(), writable_vertex_properties())
(prop_src, prop_tgt); (prop_src, prop_tgt);
} }
...@@ -290,15 +284,11 @@ void GraphInterface::CopyEdgeProperty(const GraphInterface& src, ...@@ -290,15 +284,11 @@ void GraphInterface::CopyEdgeProperty(const GraphInterface& src,
boost::any prop_src, boost::any prop_src,
boost::any prop_tgt) boost::any prop_tgt)
{ {
typedef property_map_types::apply<mpl::vector<double>,
GraphInterface::edge_index_map_t,
mpl::bool_<false> >::type
edge_properties;
typedef edge_properties writable_edge_properties; typedef edge_properties writable_edge_properties;
run_action<graph_views>() run_action<unfiltered>()
(*this, bind<void>(copy_property<edge_selector>(), (*this, bind<void>(copy_property<edge_selector>(),
_1, src.GetGraphView(), _2, _3), _1, &src._mg, _2, _3),
edge_properties(), writable_edge_properties()) edge_properties(), writable_edge_properties())
(prop_src, prop_tgt); (prop_src, prop_tgt);
} }
...@@ -55,7 +55,7 @@ def _prop(t, g, prop): ...@@ -55,7 +55,7 @@ def _prop(t, g, prop):
try: try:
pmap = g.properties[(t,prop)] pmap = g.properties[(t,prop)]
except KeyError: except KeyError:
raise GraphError("no internal %s property named: %d" %\ raise GraphError("no internal %s property named: %s" %\
("vertex" if t == "v" else \ ("vertex" if t == "v" else \
("edge" if t == "e" else "graph"),prop)) ("edge" if t == "e" else "graph"),prop))
else: else:
...@@ -214,10 +214,33 @@ class Graph(object): ...@@ -214,10 +214,33 @@ class Graph(object):
for k,v in g.__properties.iteritems(): for k,v in g.__properties.iteritems():
new_p = self.new_property(v.key_type(), v.value_type()) new_p = self.new_property(v.key_type(), v.value_type())
self.copy_property(v, new_p, g) self.copy_property(v, new_p, g)
self.properties[(v.key_type(),k)] = new_p self.properties[k] = new_p
self.__stashed_filter_state = [g.__filter_state] self.__stashed_filter_state = [g.__filter_state]
if libcore.graph_filtering_enabled(): v_filt, v_rev = g.__filter_state["vertex_filter"]
self.pop_filter() if v_filt != None:
if v_filt not in g.vertex_properties.values():
new_filt = self.new_vertex_property("bool")
self.copy_property(v_filt, new_filt)
else:
for k,v in g.vertex_properties.iteritems():
if v == v_filt:
new_filt = self.vertex_properties[k]
self.__stashed_filter_state[0]["vertex_filter"] = (new_filt,
v_rev)
e_filt, e_rev = g.__filter_state["edge_filter"]
if e_filt != None:
if e_filt not in g.edge_properties.values():
new_filt = self.new_edge_property("bool")
self.copy_property(e_filt, new_filt)
else:
for k,v in g.edge_properties.iteritems():
if v == e_filt:
new_filt = self.edge_properties[k]
self.__stashed_filter_state[0]["edge_filter"] = (new_filt,
e_rev)
self.pop_filter()
@_handle_exceptions @_handle_exceptions
def copy(self): def copy(self):
...@@ -427,11 +450,11 @@ class Graph(object): ...@@ -427,11 +450,11 @@ class Graph(object):
g.stash_filter() g.stash_filter()
self.stash_filter() self.stash_filter()
if src.key_type() == "v": if src.key_type() == "v":
self.__graph.CopyVertexProperty(g.__graph, src._PropertyMap__map, self.__graph.CopyVertexProperty(g.__graph, _prop("v", g, src),
tgt._PropertyMap__map) _prop("v", g, tgt))
elif src.key_type() == "e": elif src.key_type() == "e":
self.__graph.CopyEdgeProperty(g.__graph, src._PropertyMap__map, self.__graph.CopyEdgeProperty(g.__graph, _prop("e", g, src),
tgt._PropertyMap__map) _prop("e", g, tgt))
else: else:
tgt[self] = src[g] tgt[self] = src[g]
self.pop_filter() self.pop_filter()
...@@ -565,21 +588,22 @@ class Graph(object): ...@@ -565,21 +588,22 @@ class Graph(object):
"""Remove all vertices of the graph which are currently being filtered """Remove all vertices of the graph which are currently being filtered
out, and return to the unfiltered state""" out, and return to the unfiltered state"""
self.__graph.PurgeVertices() self.__graph.PurgeVertices()
self.__graph.SetVertexFilterProperty('') self.__graph.SetVertexFilterProperty(None)
@_handle_exceptions @_handle_exceptions
def purge_edges(self): def purge_edges(self):
"""Remove all edges of the graph which are currently being filtered out, """Remove all edges of the graph which are currently being filtered out,
and return to the unfiltered state""" and return to the unfiltered state"""
self.__graph.PurgeEdges() self.__graph.PurgeEdges()
self.__graph.SetEdgeFilterProperty('') self.__graph.SetEdgeFilterProperty(None)
@_handle_exceptions @_handle_exceptions
def stash_filter(self): def stash_filter(self):
"""Stash current filter state and recover unfiltered graph""" """Stash current filter state and recover unfiltered graph"""
self.__stashed_filter_state.append(self.__filter_state) self.__stashed_filter_state.append(self.__filter_state)
self.set_vertex_filter("") if libcore.graph_filtering_enabled():
self.set_edge_filter("") self.set_vertex_filter(None)
self.set_edge_filter(None)
self.directed() self.directed()
self.set_reversed(False) self.set_reversed(False)
...@@ -587,10 +611,11 @@ class Graph(object): ...@@ -587,10 +611,11 @@ class Graph(object):
def pop_filter(self): def pop_filter(self):
"""Pop last stashed filter state""" """Pop last stashed filter state"""
state = self.__stashed_filter_state.pop() state = self.__stashed_filter_state.pop()
self.set_vertex_filter(state["vertex_filter"][0], if libcore.graph_filtering_enabled():
state["vertex_filter"][1]) self.set_vertex_filter(state["vertex_filter"][0],
self.set_edge_filter(state["edge_filter"][0], state["vertex_filter"][1])
state["edge_filter"][1]) self.set_edge_filter(state["edge_filter"][0],
state["edge_filter"][1])
self.set_directed(state["directed"]) self.set_directed(state["directed"])
self.set_reversed(state["reversed"]) self.set_reversed(state["reversed"])
......
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