Commit 91872c4b authored by Tiago Peixoto's avatar Tiago Peixoto
Browse files

Improve performance of Graph.add_vertex() and Graph.add_edge()

parent f7020a22
......@@ -109,12 +109,13 @@ boost::any
check_filtered(const Graph &g, const EdgeFilter& edge_filter,
const bool& e_invert, bool e_active, size_t max_eindex,
const VertexFilter& vertex_filter, const bool& v_invert,
bool v_active, GraphInterface& gi, bool reverse,
bool directed)
bool v_active, GraphInterface& gi, bool reverse, bool directed)
{
#ifndef NO_GRAPH_FILTERING
MaskFilter<EdgeFilter> e_filter(edge_filter, e_invert);
MaskFilter<VertexFilter> v_filter(vertex_filter, v_invert);
MaskFilter<EdgeFilter> e_filter(const_cast<EdgeFilter&>(edge_filter),
e_invert);
MaskFilter<VertexFilter> v_filter(const_cast<VertexFilter&>(vertex_filter),
v_invert);
if (e_active)
{
......
......@@ -141,7 +141,7 @@ class MaskFilter
public:
typedef typename boost::property_traits<DescriptorProperty>::value_type value_t;
MaskFilter(){}
MaskFilter(const DescriptorProperty& filtered_property, bool invert)
MaskFilter(DescriptorProperty& filtered_property, bool invert)
: _filtered_property(&filtered_property), _invert(invert) {}
template <class Descriptor>
......@@ -151,13 +151,15 @@ public:
return get(*_filtered_property, std::forward<Descriptor>(d)) ^ _invert;
// This is a critical section. It will be called for every vertex
// or edge in the graph, every time they're iterated
// through.
// This is a critical section. It will be called for every vertex or
// edge in the graph, every time they're iterated through.
}
DescriptorProperty& get_filter() { return *_filtered_property; }
bool is_inverted() { return _invert; }
private:
const DescriptorProperty* _filtered_property;
DescriptorProperty* _filtered_property;
bool _invert;
};
......@@ -554,4 +556,42 @@ retrieve_graph_view(GraphInterface& gi, Graph& init)
} //graph_tool namespace
// Overload add_vertex() and add_edge() to filtered graphs, so that the new
// descriptors are always valid
namespace boost
{
template <class Graph, class EdgeProperty, class VertexProperty>
typename graph_traits<filtered_graph<Graph,
graph_tool::detail::MaskFilter<EdgeProperty>,
graph_tool::detail::MaskFilter<VertexProperty>>>::vertex_descriptor
add_vertex(boost::filtered_graph<Graph,
graph_tool::detail::MaskFilter<EdgeProperty>,
graph_tool::detail::MaskFilter<VertexProperty>>& g)
{
auto v = add_vertex(const_cast<Graph&>(g.m_g));
auto& filt = g.m_vertex_pred.get_filter();
auto cfilt = filt.get_checked();
cfilt[v] = !g.m_vertex_pred.is_inverted();
return v;
}
template <class Graph, class EdgeProperty, class VertexProperty, class Vertex>
std::pair<typename graph_traits<filtered_graph<Graph,
graph_tool::detail::MaskFilter<EdgeProperty>,
graph_tool::detail::MaskFilter<VertexProperty>>>::edge_descriptor, bool>
add_edge(Vertex s, Vertex t, filtered_graph<Graph,
graph_tool::detail::MaskFilter<EdgeProperty>,
graph_tool::detail::MaskFilter<VertexProperty>>& g)
{
auto e = add_edge(s, t, const_cast<Graph&>(g.m_g));
auto& filt = g.m_edge_pred.get_filter();
auto cfilt = filt.get_checked();
cfilt[e.first] = !g.m_edge_pred.is_inverted();
return e;
}
} // namespace boost
#endif // FILTERING_HH
......@@ -71,7 +71,11 @@ struct get_vertex_soft
void operator()(Graph& g, GraphInterface& gi, size_t i, python::object& v) const
{
std::shared_ptr<Graph> gp = retrieve_graph_view<Graph>(gi, g);
v = python::object(PythonVertex<Graph>(gp, vertex(i, g)));
if (i < num_vertices(g))
v = python::object(PythonVertex<Graph>(gp, vertex(i, g)));
else
v = python::object(PythonVertex<Graph>(gp,
graph_traits<Graph>::null_vertex()));
}
};
......@@ -96,10 +100,10 @@ struct get_vertex_hard
}
};
python::object get_vertex(GraphInterface& gi, size_t i)
python::object get_vertex(GraphInterface& gi, size_t i, bool use_index)
{
python::object v;
if (gi.is_vertex_filter_active())
if (!use_index)
run_action<>()(gi,
std::bind(get_vertex_hard(), placeholders::_1,
std::ref(gi), i, std::ref(v)))();
......@@ -138,7 +142,7 @@ struct add_new_vertex
python::object& new_v) const
{
std::shared_ptr<Graph> gp = retrieve_graph_view<Graph>(gi, g);
if (n > 1)
if (n != 1)
{
for (size_t i = 0; i < n; ++i)
add_vertex(g);
......
......@@ -363,19 +363,9 @@ public:
other.check_valid();
Graph& g = *std::shared_ptr<Graph>(_g);
OGraph& og = *std::shared_ptr<OGraph>(other._g);
auto s = source(_e, g);
auto t = target(_e, g);
auto os = source(other._e, og);
auto ot = target(other._e, og);
if (not is_directed::apply<Graph>::type::value ||
not is_directed::apply<OGraph>::type::value)
{
if (t < s)
std::swap(s, t);
if (ot < os)
std::swap(os, ot);
}
return s < os && t < ot;
auto eindex = get(boost::edge_index_t(), g);
auto eindex2 = get(boost::edge_index_t(), og);
return eindex[_e] < eindex2[other._e];
}
template <class OGraph>
bool operator<=(const PythonEdge<OGraph>& other) const {return *this < other || *this == other;}
......
......@@ -1674,17 +1674,7 @@ class Graph(object):
the necessary number of missing vertices are inserted, and the new
vertex is returned.
"""
vfilt = self.get_vertex_filter()
if vfilt[0] is None or not use_index:
v = libcore.get_vertex(self.__graph, int(i))
else:
try:
self.set_vertex_filter(None)
v = libcore.get_vertex(self.__graph, int(i))
if v.is_valid() and vfilt[0][v] == vfilt[1]:
raise ValueError("Invalid vertex index: %d (filtered out)" % int(i))
finally:
self.set_vertex_filter(vfilt[0], vfilt[1])
v = libcore.get_vertex(self.__graph, int(i), use_index)
if not v.is_valid():
if add_missing:
self.add_vertex(int(i) - self.num_vertices(use_index) + 1)
......@@ -1706,9 +1696,6 @@ class Graph(object):
"""
s = self.vertex(int(s))
t = self.vertex(int(t))
if s is None or t is None:
return None
efilt = self.get_edge_filter()
edges = libcore.get_edge(self.__graph, int(s), int(t), all_edges)
if add_missing and len(edges) == 0:
edges.append(self.add_edge(s, t))
......@@ -1740,17 +1727,9 @@ class Graph(object):
vertices are inserted and an iterator over the new vertices is returned.
This operation is :math:`O(n)`.
"""
if n == 0:
return (None for i in range(0, 0))
v = libcore.add_vertex(self.__graph, n)
vfilt = self.get_vertex_filter()
if vfilt[0] is not None:
N = self.num_vertices(True)
vfilt[0].a[N - n: N] = not vfilt[1]
if n <= 1:
if n == 1:
return v
else:
pos = self.num_vertices(True) - n
......@@ -1841,14 +1820,10 @@ class Graph(object):
If ``add_missing == True``, the source and target vertices are included
in the graph if they don't yet exist.
"""
e = libcore.add_edge(self.__graph,
self.vertex(int(source), add_missing=add_missing),
self.vertex(int(target), add_missing=add_missing))
efilt = self.get_edge_filter()
if efilt[0] is not None:
efilt[0][e] = not efilt[1]
return e
def remove_edge(self, edge):
......
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