Commit 78d42c38 authored by Tiago Peixoto's avatar Tiago Peixoto

Faster Graph copying if filter state is identical

parent 27d059c2
......@@ -79,8 +79,169 @@ void copy_property(const Descriptor& src_d, const Descriptor& tgt_d,
throw ValueException("Cannot find property map type.");
}
template <class GraphSrc, class GraphTgt, class IndexMap, class SrcIndexMap,
class TgtIndexMap>
struct copy_vertex_property_dispatch
{
copy_vertex_property_dispatch(const GraphSrc& src, const GraphTgt& tgt,
boost::any& prop_src, boost::any& prop_tgt,
IndexMap& index_map,
SrcIndexMap& src_vertex_index,
TgtIndexMap& tgt_vertex_index,
bool& found)
: src(src), tgt(tgt), prop_src(prop_src),
prop_tgt(prop_tgt), index_map(index_map),
src_vertex_index(src_vertex_index),
tgt_vertex_index(tgt_vertex_index), found(found) {}
const GraphSrc& src;
const GraphTgt& tgt;
boost::any& prop_src;
boost::any& prop_tgt;
IndexMap& index_map;
SrcIndexMap& src_vertex_index;
TgtIndexMap& tgt_vertex_index;
bool& found;
template <class PropertyMap>
void operator()(PropertyMap) const
{
PropertyMap* psrc = any_cast<PropertyMap>(&prop_src);
if (psrc == NULL)
return;
if (prop_tgt.empty())
prop_tgt = PropertyMap(tgt_vertex_index);
PropertyMap* ptgt = any_cast<PropertyMap>(&prop_tgt);
if (ptgt == NULL)
return;
found = true;
typename PropertyMap::unchecked_t p_src =
psrc->get_unchecked(num_vertices(src));
typename PropertyMap::unchecked_t p_tgt =
ptgt->get_unchecked(num_vertices(tgt));
int i, N = num_vertices(src);
#pragma omp parallel for default(shared) private(i) schedule(static) if (N > 100)
for (i = 0; i < N; ++i)
{
typename graph_traits<GraphSrc>::vertex_descriptor v = vertex(i, src);
if (v == graph_traits<GraphSrc>::null_vertex())
continue;
typename graph_traits<GraphTgt>::vertex_descriptor new_v =
vertex(index_map[i], tgt);
p_tgt[new_v] = p_src[v];
}
}
};
template <class PropertyMaps, class GraphSrc, class GraphTgt,
class IndexMap, class SrcIndexMap, class TgtIndexMap>
void copy_vertex_property(boost::any& prop_src, boost::any& prop_tgt,
const GraphSrc& src, const GraphTgt& tgt,
IndexMap& index_map, SrcIndexMap& src_vertex_index,
TgtIndexMap& tgt_vertex_index)
{
bool found = false;
mpl::for_each<PropertyMaps>(copy_vertex_property_dispatch<GraphSrc, GraphTgt,
IndexMap, SrcIndexMap,
TgtIndexMap>
(src, tgt, prop_src, prop_tgt, index_map, src_vertex_index,
tgt_vertex_index, found));
if (!found)
throw ValueException("Cannot find property map type.");
}
template <class GraphSrc, class GraphTgt, class IndexMap, class SrcIndexMap>
struct copy_edge_property_dispatch
{
copy_edge_property_dispatch(const GraphSrc& src, const GraphTgt& tgt,
boost::any& prop_src, boost::any& prop_tgt,
IndexMap& index_map,
SrcIndexMap& src_edge_index,
size_t max_src_edge_index,
bool& found)
: src(src), tgt(tgt), prop_src(prop_src),
prop_tgt(prop_tgt), index_map(index_map),
src_edge_index(src_edge_index),
max_src_edge_index(max_src_edge_index), found(found) {}
const GraphSrc& src;
const GraphTgt& tgt;
boost::any& prop_src;
boost::any& prop_tgt;
IndexMap& index_map;
SrcIndexMap& src_edge_index;
size_t max_src_edge_index;
bool& found;
template <class PropertyMap>
void operator()(PropertyMap) const
{
PropertyMap* psrc = any_cast<PropertyMap>(&prop_src);
if (psrc == NULL)
return;
if (prop_tgt.empty())
prop_tgt = PropertyMap(get(edge_index_t(), tgt));
PropertyMap* ptgt = any_cast<PropertyMap>(&prop_tgt);
if (ptgt == NULL)
return;
found = true;
typename PropertyMap::unchecked_t p_src =
psrc->get_unchecked(max_src_edge_index + 1);
typename PropertyMap::unchecked_t p_tgt =
ptgt->get_unchecked(num_edges(tgt));
int i, N = num_vertices(src);
#pragma omp parallel for default(shared) private(i) schedule(static) if (N > 100)
for (i = 0; i < N; ++i)
{
typename graph_traits<GraphSrc>::vertex_descriptor v = vertex(i, src);
if (v == graph_traits<GraphSrc>::null_vertex())
continue;
typename graph_traits<GraphSrc>::out_edge_iterator e, e_end;
for (tie(e, e_end) = out_edges(v, src); e != e_end; ++e)
{
typename graph_traits<GraphSrc>::vertex_descriptor s = source(*e, src);
typename graph_traits<GraphSrc>::vertex_descriptor t = target(*e, src);
if (!is_directed::apply<GraphSrc>::type::value && s > t)
continue;
size_t ei = src_edge_index[*e];
typename graph_traits<GraphTgt>::edge_descriptor new_e = index_map[ei];
p_tgt[new_e] = p_src[*e];
}
}
}
};
template <class PropertyMaps, class GraphSrc, class GraphTgt,
class IndexMap, class SrcIndexMap>
void copy_edge_property(boost::any& prop_src, boost::any& prop_tgt,
const GraphSrc& src, const GraphTgt& tgt,
IndexMap& index_map, SrcIndexMap& src_vertex_index,
size_t max_src_edge_index)
{
bool found = false;
mpl::for_each<PropertyMaps>(copy_edge_property_dispatch<GraphSrc, GraphTgt,
IndexMap, SrcIndexMap>
(src, tgt, prop_src, prop_tgt, index_map, src_vertex_index,
max_src_edge_index, found));
if (!found)
throw ValueException("Cannot find property map type.");
}
struct do_graph_copy
{
do_graph_copy(size_t max_src_edge_index)
: max_src_edge_index(max_src_edge_index) {}
size_t max_src_edge_index;
template <class GraphTgt, class GraphSrc, class TgtVertexIndexMap,
class SrcVertexIndexMap, class TgtEdgeIndexMap,
class SrcEdgeIndexMap, class OrderMap>
......@@ -88,7 +249,7 @@ struct do_graph_copy
TgtVertexIndexMap src_vertex_index,
SrcVertexIndexMap tgt_vertex_index,
TgtEdgeIndexMap,
SrcEdgeIndexMap tgt_edge_index,
SrcEdgeIndexMap src_edge_index,
OrderMap vertex_order,
vector<pair<reference_wrapper<boost::any>,reference_wrapper<boost::any> > >& vprops,
vector<pair<reference_wrapper<boost::any>,reference_wrapper<boost::any> > >& eprops) const
......@@ -99,17 +260,20 @@ struct do_graph_copy
{
if (src_vertex_index[*v] >= index_map.size())
index_map.resize(src_vertex_index[*v]+1);
typename graph_traits<GraphTgt>::vertex_descriptor new_v = get(vertex_order, *v);
typename graph_traits<GraphTgt>::vertex_descriptor new_v =
get(vertex_order, *v);
while (new_v >= num_vertices(tgt))
add_vertex(tgt);
index_map[src_vertex_index[*v]] = tgt_vertex_index[new_v];
for (size_t i = 0; i < vprops.size(); ++i)
copy_property<writable_vertex_properties>
(*v, new_v, vprops[i].first.get(), vprops[i].second.get(),
src, tgt, tgt_vertex_index);
}
for (size_t i = 0; i < vprops.size(); ++i)
copy_vertex_property<writable_vertex_properties>
(vprops[i].first.get(), vprops[i].second.get(),
src, tgt, index_map, src_vertex_index, tgt_vertex_index);
vector<typename graph_traits<GraphTgt>::edge_descriptor> edge_map(num_edges(src));
typename graph_traits<GraphSrc>::edge_iterator e, e_end;
for (tie(e, e_end) = edges(src); e != e_end; ++e)
{
......@@ -118,11 +282,18 @@ struct do_graph_copy
typedef typename graph_traits<GraphTgt>::edge_descriptor edge_t;
edge_t new_e = add_edge(vertex(s,tgt), vertex(t,tgt), tgt).first;
for (size_t i = 0; i < eprops.size(); ++i)
copy_property<writable_edge_properties>
(edge_t(*e), new_e, eprops[i].first.get(), eprops[i].second.get(),
src, tgt, tgt_edge_index);
size_t ei = src_edge_index[*e];
if (ei >= edge_map.size())
edge_map.resize(ei + 1);
edge_map[ei] = new_e;
}
for (size_t i = 0; i < eprops.size(); ++i)
copy_edge_property<writable_edge_properties>
(eprops[i].first.get(), eprops[i].second.get(),
src, tgt, edge_map, src_edge_index, max_src_edge_index);
}
};
......@@ -145,6 +316,13 @@ GraphInterface::GraphInterface(const GraphInterface& gi, bool keep_ref,
if (keep_ref)
return;
if (vorder == python::object())
{
// simple copying
*_mg = *gi._mg;
return;
}
vector<pair<reference_wrapper<boost::any>,reference_wrapper<boost::any> > > vprops;
for (int i = 0; i < python::len(ovprops); ++i)
{
......@@ -161,9 +339,9 @@ GraphInterface::GraphInterface(const GraphInterface& gi, bool keep_ref,
boost::any avorder = python::extract<boost::any>(vorder);
run_action<>()
(const_cast<GraphInterface&>(gi),
bind<void>(do_graph_copy(), _1, ref(*_mg),
gi._vertex_index, _vertex_index,
gi._edge_index, _edge_index, _2, ref(vprops),
ref(eprops)), vertex_scalar_properties())(avorder);
bind<void>(do_graph_copy(gi._mg->get_last_index()), _1, ref(*_mg),
gi._vertex_index, _vertex_index, gi._edge_index,
_edge_index, _2, ref(vprops), ref(eprops)),
vertex_scalar_properties())(avorder);
// filters will be copied in python
}
......@@ -1060,66 +1060,90 @@ class Graph(object):
vfilt = g.get_vertex_filter()[0]
efilt = g.get_edge_filter()[0]
# Copy all internal properties from original graph.
vprops = []
eprops = []
ef_pos = vf_pos = None
for k, m in gv.vertex_properties.items():
if not vprune and m is vfilt:
if (vorder is None and
((g.get_vertex_filter()[0] is None and g.get_edge_filter()[0] is None) or
(not vprune and not eprune))):
# Do a simpler, faster copy.
self.__graph = libcore.GraphInterface(gv.__graph, False,
[], [], None)
nvfilt = nefilt = None
for k, m in g.properties.items():
nmap = self.copy_property(m, g=gv)
self.properties[k] = nmap
if m is vfilt:
nvfilt = nmap
if m is efilt:
nefilt = nmap
if vfilt is not None:
if nvfilt is None:
nvfilt = self.copy_property(vfilt, g=gv)
self.set_vertex_filter(nvfilt, g.get_vertex_filter()[1])
if efilt is not None:
if nefilt is None:
nefilt = self.copy_property(efilt, g=gv)
self.set_edge_filter(nefilt, g.get_edge_filter()[1])
else:
# Copy all internal properties from original graph.
vprops = []
eprops = []
ef_pos = vf_pos = None
for k, m in gv.vertex_properties.items():
if not vprune and m is vfilt:
vf_pos = len(vprops)
vprops.append([_prop("v", gv, m), libcore.any()])
for k, m in gv.edge_properties.items():
if not eprune and m is efilt:
ef_pos = len(eprops)
eprops.append([_prop("e", gv, m), libcore.any()])
if not vprune and vf_pos is None and vfilt is not None:
vf_pos = len(vprops)
vprops.append([_prop("v", gv, m), libcore.any()])
for k, m in gv.edge_properties.items():
if not eprune and m is efilt:
vprops.append([_prop("v", gv, vfilt), libcore.any()])
if not eprune and ef_pos is None and efilt is not None:
ef_pos = len(eprops)
eprops.append([_prop("e", gv, m), libcore.any()])
if not vprune and vf_pos is None and vfilt is not None:
vf_pos = len(vprops)
vprops.append([_prop("v", gv, vfilt), libcore.any()])
if not eprune and ef_pos is None and efilt is not None:
ef_pos = len(eprops)
eprops.append([_prop("e", gv, efilt), libcore.any()])
# The vertex ordering
if vorder is None:
vorder = gv.new_vertex_property("int")
vorder.fa = numpy.arange(gv.num_vertices())
# The actual copying of the graph and property maps
self.__graph = libcore.GraphInterface(gv.__graph, False,
vprops,
eprops,
_prop("v", gv, vorder))
# Put the copied properties in the internal dictionary
for i, (k, m) in enumerate(g.vertex_properties.items()):
pmap = new_vertex_property(m.value_type(),
self.__graph.GetVertexIndex(),
vprops[i][1])
self.vertex_properties[k] = PropertyMap(pmap, self, "v")
for i, (k, m) in enumerate(g.edge_properties.items()):
pmap = new_edge_property(m.value_type(),
self.__graph.GetEdgeIndex(),
eprops[i][1])
self.edge_properties[k] = PropertyMap(pmap, self, "e")
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 vf_pos is not None:
pmap = new_vertex_property("bool",
self.__graph.GetVertexIndex(),
vprops[vf_pos][1])
pmap = PropertyMap(pmap, self, "v")
self.set_vertex_filter(pmap, g.get_vertex_filter()[1])
if ef_pos is not None:
pmap = new_edge_property("bool",
self.__graph.GetEdgeIndex(),
eprops[ef_pos][1])
pmap = PropertyMap(pmap, self, "e")
self.set_edge_filter(pmap, g.get_edge_filter()[1])
eprops.append([_prop("e", gv, efilt), libcore.any()])
# The vertex ordering
if vorder is None:
vorder = gv.new_vertex_property("int")
vorder.fa = numpy.arange(gv.num_vertices())
# The actual copying of the graph and property maps
self.__graph = libcore.GraphInterface(gv.__graph, False,
vprops,
eprops,
_prop("v", gv, vorder))
# Put the copied properties in the internal dictionary
for i, (k, m) in enumerate(g.vertex_properties.items()):
pmap = new_vertex_property(m.value_type(),
self.__graph.GetVertexIndex(),
vprops[i][1])
self.vertex_properties[k] = PropertyMap(pmap, self, "v")
for i, (k, m) in enumerate(g.edge_properties.items()):
pmap = new_edge_property(m.value_type(),
self.__graph.GetEdgeIndex(),
eprops[i][1])
self.edge_properties[k] = PropertyMap(pmap, self, "e")
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 vf_pos is not None:
pmap = new_vertex_property("bool",
self.__graph.GetVertexIndex(),
vprops[vf_pos][1])
pmap = PropertyMap(pmap, self, "v")
self.set_vertex_filter(pmap, g.get_vertex_filter()[1])
if ef_pos is not None:
pmap = new_edge_property("bool",
self.__graph.GetEdgeIndex(),
eprops[ef_pos][1])
pmap = PropertyMap(pmap, self, "e")
self.set_edge_filter(pmap, g.get_edge_filter()[1])
if not rprune:
self.set_reversed(g.is_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