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

Fix problem with Graph.clear_vertex() when using filtered graphs

parent 34172d3e
......@@ -103,6 +103,9 @@ Vertex add_vertex(adj_list<Vertex>& g);
template <class Vertex>
void clear_vertex(Vertex v, adj_list<Vertex>& g);
template <class Vertex, class Pred>
void clear_vertex(Vertex v, adj_list<Vertex>& g, Pred&& pred);
template <class Vertex>
void remove_vertex(Vertex v, adj_list<Vertex>& g);
......@@ -451,7 +454,8 @@ private:
friend Vertex add_vertex<>(adj_list<Vertex>& g);
friend void clear_vertex<>(Vertex v, adj_list<Vertex>& g);
template <class V, class Pred>
friend void clear_vertex(V v, adj_list<V>& g, Pred&& pred);
friend void remove_vertex<>(Vertex v, adj_list<Vertex>& g);
......@@ -704,22 +708,27 @@ Vertex add_vertex(adj_list<Vertex>& g)
return g._out_edges.size() - 1;
}
template <class Vertex>
inline void clear_vertex(Vertex v, adj_list<Vertex>& g)
template <class Vertex, class Pred>
inline void clear_vertex(Vertex v, adj_list<Vertex>& g, Pred&& pred)
{
if (!g._keep_epos)
{
auto remove_es = [&] (auto& out_edges, auto& in_edges)
auto remove_es = [&] (auto& out_edges, auto& in_edges,
auto&& mk_out_edge, auto&& mk_in_edge)
{
auto& oes = out_edges[v];
for (const auto& oe : oes)
{
if (!pred(mk_out_edge.def(v, oe)))
continue;
Vertex t = oe.first;
auto& ies = in_edges[t];
auto iter =
std::remove_if(ies.begin(), ies.end(),
[&](const auto& ei) -> bool
{
if (!pred(mk_in_edge.def(t, ei)))
return false;
if (ei.first == v)
{
g._free_indexes.push_back(ei.second);
......@@ -729,20 +738,34 @@ inline void clear_vertex(Vertex v, adj_list<Vertex>& g)
});
ies.erase(iter, ies.end());
}
g._n_edges -= oes.size();
oes.clear();
size_t noes = oes.size();
auto iter =
std::remove_if(oes.begin(), oes.end(),
[&](auto& oe)
{
return pred(mk_out_edge.def(v, oe));
});
oes.erase(iter, oes.end());
g._n_edges -= noes - oes.size();
};
remove_es(g._out_edges, g._in_edges);
remove_es(g._in_edges, g._out_edges);
remove_es(g._out_edges, g._in_edges,
typename adj_list<Vertex>::make_out_edge(),
typename adj_list<Vertex>::make_in_edge());
remove_es(g._in_edges, g._out_edges,
typename adj_list<Vertex>::make_in_edge(),
typename adj_list<Vertex>::make_out_edge());
}
else
{
auto remove_es = [&] (auto& out_edges, auto& in_edges,
const auto& get_pos)
auto&& get_pos, auto&& mk_out_edge)
{
auto& oes = out_edges[v];
for (const auto& ei : oes)
{
if (!pred(mk_out_edge.def(v, ei)))
continue;
Vertex t = ei.first;
size_t idx = ei.second;
auto& ies = in_edges[t];
......@@ -754,16 +777,33 @@ inline void clear_vertex(Vertex v, adj_list<Vertex>& g)
ies.pop_back();
g._free_indexes.push_back(idx);
}
g._n_edges -= oes.size();
oes.clear();
size_t noes = oes.size();
auto iter =
std::remove_if(oes.begin(), oes.end(),
[&](auto& oe)
{
return pred(mk_out_edge.def(v, oe));
});
oes.erase(iter, oes.end());
g._n_edges -= noes - oes.size();
};
remove_es(g._out_edges, g._in_edges,
[&](size_t idx) -> auto& {return g._epos[idx].second;});
[&](size_t idx) -> auto& {return g._epos[idx].second;},
typename adj_list<Vertex>::make_out_edge());
remove_es(g._in_edges, g._out_edges,
[&](size_t idx) -> auto& {return g._epos[idx].first;});
[&](size_t idx) -> auto& {return g._epos[idx].first;},
typename adj_list<Vertex>::make_in_edge());
}
}
template <class Vertex>
inline void clear_vertex(Vertex v, adj_list<Vertex>& g)
{
clear_vertex(v, g, [](auto&&){ return true; });
}
// O(V + E)
template <class Vertex>
inline void remove_vertex(Vertex v, adj_list<Vertex>& g)
......
......@@ -593,6 +593,26 @@ public:
{
}
size_t data_ptr()
{
typename boost::mpl::or_<
std::is_same<PropertyMap,
GraphInterface::vertex_index_map_t>,
std::is_same<PropertyMap,
GraphInterface::edge_index_map_t> >::type is_index;
return data_ptr_dispatch(is_index);
}
size_t data_ptr_dispatch(boost::mpl::bool_<true>)
{
return 0;
}
size_t data_ptr_dispatch(boost::mpl::bool_<false>)
{
return size_t(_pmap.get_storage().data());
}
private:
PropertyMap _pmap; // hold an internal copy, since it's cheap
};
......
......@@ -65,7 +65,8 @@ struct export_vertex_property_map
.def("is_writable", &pmap_t::is_writable)
.def("reserve", &pmap_t::reserve)
.def("resize", &pmap_t::resize)
.def("shrink_to_fit", &pmap_t::shrink_to_fit);
.def("shrink_to_fit", &pmap_t::shrink_to_fit)
.def("data_ptr", &pmap_t::data_ptr);
typedef boost::mpl::transform<graph_tool::all_graph_views,
boost::mpl::quote1<std::add_const> >::type const_graph_views;
......
......@@ -304,7 +304,10 @@ add_edge(typename boost::graph_traits
VertexPredicate>>::vertex_descriptor v,
filtered_graph<Graph,EdgePredicate,VertexPredicate>& g)
{
return add_edge(u,v, const_cast<Graph&>(g.m_g));
auto ret = add_edge(u, v, const_cast<Graph&>(g.m_g));
auto filt = g.m_edge_pred.get_filter().get_checked();
filt[ret.first] = !g.m_edge_pred.is_inverted();
return ret;
}
//==============================================================================
......@@ -316,12 +319,10 @@ clear_vertex(typename boost::graph_traits
<filtered_graph<Graph,EdgePredicate,VertexPredicate>>::vertex_descriptor v,
filtered_graph<Graph,EdgePredicate,VertexPredicate>& g)
{
typedef typename boost::graph_traits<filtered_graph<Graph,EdgePredicate,VertexPredicate>>::edge_descriptor e_t;
std::vector<e_t> e_list;
for (auto e : graph_tool::all_edges_range(v, g))
e_list.push_back(e);
for (auto& e : e_list)
remove_edge(e, g);
clear_vertex(v, const_cast<Graph&>(g.m_g),
[&](auto&& e){ return (g.m_edge_pred(e) &&
g.m_vertex_pred(source(e, g.m_g)) &&
g.m_vertex_pred(target(e, g.m_g))); });
}
//==============================================================================
......@@ -376,6 +377,9 @@ void remove_vertex(typename boost::graph_traits
VertexPredicate>>::vertex_descriptor v,
filtered_graph<Graph,EdgePredicate,VertexPredicate>& g)
{
auto& filt = g.m_vertex_pred.get_filter();
for (size_t i = v; i < num_vertices(g) - 1; ++i)
filt[i] = filt[i + 1];
return remove_vertex(v,const_cast<Graph&>(g.m_g));
}
......@@ -389,6 +393,9 @@ void remove_vertex_fast(typename boost::graph_traits
VertexPredicate>>::vertex_descriptor v,
filtered_graph<Graph,EdgePredicate,VertexPredicate>& g)
{
size_t back = num_vertices(g) - 1;
auto& filt = g.m_vertex_pred.get_filter();
filt[v] = filt[back];
return remove_vertex_fast(v,const_cast<Graph&>(g.m_g));
}
......@@ -445,7 +452,10 @@ typename boost::graph_traits
<filtered_graph<Graph,EdgePredicate,VertexPredicate>>::vertex_descriptor
add_vertex(filtered_graph<Graph,EdgePredicate,VertexPredicate>& g)
{
return add_vertex(const_cast<Graph&>(g.m_g));
auto filt = g.m_vertex_pred.get_filter().get_checked();
auto v = add_vertex(const_cast<Graph&>(g.m_g));
filt[v] = !g.m_vertex_pred.is_inverted();
return v;
}
//==============================================================================
......
......@@ -827,6 +827,10 @@ class PropertyMap(object):
self.__map.resize(size)
self.__map.shrink_to_fit()
def data_ptr(self):
"""Return the pointer to memory where the data resides."""
return self.__map.data_ptr()
def __getstate__(self):
g = self.get_graph()
if g is None:
......@@ -1847,12 +1851,21 @@ class Graph(object):
if vmax != back:
if not is_iter:
vs = numpy.asarray((vertex,), dtype="int64")
for pmap in self.__known_properties.values():
if pmap() is not None and pmap().key_type() == "v" and pmap().is_writable():
vfilt = self.get_vertex_filter()[0]
if vfilt is not None:
vfiltptr = vfilt._get_data_ptr()
else:
vfiltprt = None
for pmap_ in self.__known_properties.values():
pmap = pmap_()
if (pmap is not None and
pmap.key_type() == "v" and
pmap.is_writable() and
pmap._get_data_ptr() != vfiltptr):
if fast:
self.__graph.move_vertex_property(_prop("v", self, pmap()), vs)
self.__graph.move_vertex_property(_prop("v", self, pmap), vs)
else:
self.__graph.shift_vertex_property(_prop("v", self, pmap()), vs)
self.__graph.shift_vertex_property(_prop("v", self, pmap), vs)
if is_iter:
libcore.remove_vertex_array(self.__graph, vs, fast)
......
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