Commit 8e962092 authored by Tiago Peixoto's avatar Tiago Peixoto
Browse files

Simplify range filtering, and definitely remove python filtering
    
Simplify range filtering of vertices and edges, by always filtering
both at once, even if all vertices or edges are being considered. This
severely reduces compilation time and memory, at a small potential
cost in run-time speed, which will probably be overshadowed by other
things, such as dynamic_map look-ups ("premature optimization is the
root of all evil"). Also, remove python-filtering, since, in the end,
it is just code bloat, since it is quite slow for most uses and can be
replaced, generally, by python property editing + range filtering.
parent fbf7f175
......@@ -74,22 +74,6 @@ AC_ARG_ENABLE([visibility], [AC_HELP_STRING([--disable-visibility],
)
AC_MSG_CHECKING(whether to enable graph python filtering...)
AC_ARG_ENABLE([python-filtering], [AC_HELP_STRING([--enable-python-filtering],
[enable python graph filtering [default=disabled] ])],
if test $enableval = no; then
[AC_MSG_RESULT(no)]
[AC_DEFINE([NO_PYTHON_FILTERING], 1, [disable graph filtering])]
NO_PYTHON_FILTERING=yes
else
[AC_MSG_RESULT(yes)]
fi
,
[AC_MSG_RESULT(no)]
[AC_DEFINE([NO_PYTHON_FILTERING], 1, [disable graph filtering])]
NO_PYTHON_FILTERING=yes
)
AC_MSG_CHECKING(whether to enable graph range filtering...)
AC_ARG_ENABLE([range-filtering], [AC_HELP_STRING([--disable-range-filtering],
[disable range filtering [default=enabled] ])],
......
......@@ -21,7 +21,7 @@ libgraph_tool_la_SOURCES = \
graph.hh\
graph.cc\
graph_filtering.hh\
graph_python_filtering.hh\
graph_python_interface.hh\
graph_selectors.hh\
graph_properties.hh\
graph_properties.cc\
......
......@@ -70,8 +70,14 @@ GraphInterface::GraphInterface()
_directed(true),
_vertex_index(get(vertex_index,_mg)),
_edge_index(get(edge_index_t(),_mg)),
_vertex_filter_map(_vertex_index),
_vertex_range(make_pair(numeric_limits<double>::min(), numeric_limits<double>::max())),
_edge_range(make_pair(numeric_limits<double>::min(), numeric_limits<double>::max()))
_vertex_range_include(make_pair(false, false)),
_vertex_range_invert(false),
_edge_filter_map(_edge_index),
_edge_range(make_pair(numeric_limits<double>::min(), numeric_limits<double>::max())),
_edge_range_include(make_pair(false, false)),
_edge_range_invert(false)
{
}
......@@ -116,13 +122,20 @@ void GraphInterface::SetVertexFilterProperty(string property)
throw GraphException("property " + property + " not found");
}
}
else
{
_vertex_filter_map = _vertex_index;
_vertex_range = make_pair(numeric_limits<double>::min(), numeric_limits<double>::max());
_vertex_range_include = make_pair(false, false);
_vertex_range_invert = false;
}
#else
if (property != "")
throw GraphException("support for graph range filtering was not enabled during compilation.");
#endif
}
bool GraphInterface::IsVertexFilterActive() const { return _vertex_filter_property != "" || _vertex_python_filter != python::object(); }
bool GraphInterface::IsVertexFilterActive() const { return _vertex_filter_property != ""; }
void GraphInterface::SetEdgeFilterProperty(string property)
{
......@@ -153,46 +166,43 @@ void GraphInterface::SetEdgeFilterProperty(string property)
throw GraphException("property " + property + " not found");
}
}
else
{
_edge_filter_map = _edge_index;
_edge_range = make_pair(numeric_limits<double>::min(), numeric_limits<double>::max());
_edge_range_include = make_pair(false, false);
_edge_range_invert = false;
}
#else
if (property != "")
throw GraphException("support for graph range filtering was not enabled during compilation.");
#endif
}
bool GraphInterface::IsEdgeFilterActive() const {return _edge_filter_property != "" || _edge_python_filter != python::object();}
bool GraphInterface::IsEdgeFilterActive() const {return _edge_filter_property != "";}
void GraphInterface::SetVertexFilterRange(std::pair<double,double> allowed_range)
void GraphInterface::SetVertexFilterRange(std::pair<double,double> allowed_range, std::pair<bool,bool> include, bool invert)
{
#ifndef NO_RANGE_FILTERING
_vertex_range = allowed_range;
_vertex_range_include = include;
_vertex_range_invert = invert;
#else
throw GraphException("support for graph range filtering was not enabled during compilation.");
#endif
}
void GraphInterface::SetGenericVertexFilter(boost::python::object filter)
{
#ifndef NO_PYTHON_FILTERING
_vertex_python_filter = filter;
#else
if (filter != python::object())
throw GraphException("support for graph python filtering was not enabled during compilation.");
#endif
}
void GraphInterface::SetGenericEdgeFilter(boost::python::object filter)
void GraphInterface::SetEdgeFilterRange(std::pair<double,double> allowed_range, std::pair<bool,bool> include, bool invert)
{
#ifndef NO_PYTHON_FILTERING
_edge_python_filter = filter;
#ifndef NO_RANGE_FILTERING
_edge_range = allowed_range;
_edge_range_include = include;
_edge_range_invert = invert;
#else
if (filter != python::object())
throw GraphException("support for graph python filtering was not enabled during compilation.");
throw GraphException("support for graph range filtering was not enabled during compilation.");
#endif
}
//==============================================================================
// GetNumberOfVertices()
//==============================================================================
......
......@@ -129,20 +129,13 @@ public:
bool GetReversed() const {return _reversed;}
void SetVertexFilterProperty(std::string property);
std::string GetVertexFilterProperty() const {return _vertex_filter_property;}
void SetVertexFilterRange(std::pair<double,double> allowed_range);
std::pair<double, double> GetVertexFilterRange() const {return _vertex_range;}
void SetVertexFilterRange(std::pair<double,double> allowed_range, std::pair<bool,bool> include, bool invert);
bool IsVertexFilterActive() const;
void SetEdgeFilterProperty(std::string property);
std::string GetEdgeFilterProperty() const {return _edge_filter_property;}
void SetEdgeFilterRange(std::pair<double,double> allowed_range) {_edge_range = allowed_range;}
std::pair<double,double> GetEdgeFilterRange() const {return _edge_range;}
void SetEdgeFilterRange(std::pair<double,double> allowed_range, std::pair<bool,bool> include, bool invert);
bool IsEdgeFilterActive() const;
void SetGenericVertexFilter(boost::python::object filter);
void SetGenericEdgeFilter(boost::python::object filter);
// modification
void RemoveVertexProperty(std::string property);
void RemoveEdgeProperty(std::string property);
......@@ -211,7 +204,8 @@ private:
DynamicPropertyMapWrap<double, boost::graph_traits<multigraph_t>::vertex_descriptor> > vertex_filter_map_t;
vertex_filter_map_t _vertex_filter_map;
std::pair<double,double> _vertex_range;
boost::python::object _vertex_python_filter;
std::pair<bool,bool> _vertex_range_include;
bool _vertex_range_invert;
// edge filter
std::string _edge_filter_property;
......@@ -223,7 +217,8 @@ private:
DynamicPropertyMapWrap<double, boost::graph_traits<multigraph_t>::edge_descriptor> > edge_filter_map_t;
edge_filter_map_t _edge_filter_map;
std::pair<double,double> _edge_range;
boost::python::object _edge_python_filter;
std::pair<bool,bool> _edge_range_include;
bool _edge_range_invert;
};
......
......@@ -291,17 +291,10 @@ BOOST_PYTHON_MODULE(libgraph_tool)
.def("SetReversed", &GraphInterfaceWrap::SetReversed)
.def("GetReversed", &GraphInterfaceWrap::GetReversed)
.def("SetVertexFilterProperty", &GraphInterfaceWrap::SetVertexFilterProperty)
.def("GetVertexFilterProperty", &GraphInterfaceWrap::GetVertexFilterProperty)
.def("SetVertexFilterRange", &GraphInterfaceWrap::SetVertexFilterRange)
.def("GetVertexFilterRange", &GraphInterfaceWrap::GetVertexFilterRange)
.def("IsVertexFilterActive", &GraphInterfaceWrap::IsVertexFilterActive)
.def("SetGenericVertexFilter", &GraphInterfaceWrap::SetGenericVertexFilter)
.def("SetEdgeFilterProperty", &GraphInterfaceWrap::SetEdgeFilterProperty)
.def("GetEdgeFilterProperty", &GraphInterfaceWrap::GetEdgeFilterProperty)
.def("SetEdgeFilterRange", &GraphInterfaceWrap::SetEdgeFilterRange)
.def("GetEdgeFilterRange", &GraphInterfaceWrap::GetEdgeFilterRange)
.def("IsEdgeFilterActive", &GraphInterfaceWrap::IsEdgeFilterActive)
.def("SetGenericEdgeFilter", &GraphInterfaceWrap::SetGenericEdgeFilter)
.def("EditEdgeProperty", &GraphInterfaceWrap::EditEdgeProperty)
.def("EditVertexProperty", &GraphInterfaceWrap::EditVertexProperty)
.def("EditGraphProperty", &GraphInterfaceWrap::EditGraphProperty)
......
......@@ -36,10 +36,6 @@
#include "graph_adaptor.hh"
#include "graph_selectors.hh"
#ifndef NO_PYTHON_FILTERING
#include "graph_python_filtering.hh"
#endif
// some additional functions...
namespace boost
{
......@@ -158,14 +154,15 @@ class RangeFilter
{
public:
RangeFilter(){}
RangeFilter(FilteredPropertyMap filtered_property, std::pair<double, double> range)
: _filtered_property(filtered_property), _range(range) {}
RangeFilter(FilteredPropertyMap filtered_property, std::pair<double, double> range,
std::pair<bool, bool> include, bool invert)
: _filtered_property(filtered_property), _range(range), _include(include), _invert(invert) {}
template <class VertexOrEdge>
bool operator() (VertexOrEdge e) const
{
bool retval;
map_visitor<VertexOrEdge> visitor(e, _range, retval);
map_visitor<VertexOrEdge> visitor(e, _range, _include, _invert, retval);
apply_visitor(visitor, _filtered_property);
return retval;
}
......@@ -175,22 +172,39 @@ private:
class map_visitor: public static_visitor<void>
{
public:
map_visitor(const VertexOrEdge& descriptor, const std::pair<double, double>& range, bool& retval)
: _descriptor(descriptor), _range(range), _retval(retval) {}
map_visitor(const VertexOrEdge& descriptor, const std::pair<double, double>& range,
const std::pair<bool, bool>& include, bool invert, bool& retval)
: _descriptor(descriptor), _range(range), _include(include), _invert(invert), _retval(retval) {}
template <class MapType>
void operator()(MapType& filter_prop)
{
// ignore if outside allowed range
_retval = !(double(get(filter_prop, _descriptor)) < _range.first || double(get(filter_prop, _descriptor)) > _range.second);
bool lower;
if (_include.first)
lower = double(get(filter_prop, _descriptor)) <= _range.first;
else
lower = double(get(filter_prop, _descriptor)) < _range.first;
bool upper;
if (_include.second)
upper = double(get(filter_prop, _descriptor)) >= _range.second;
else
upper = double(get(filter_prop, _descriptor)) > _range.second;
_retval = !(lower || upper);
if (_invert)
_retval = !_retval;
}
private:
const VertexOrEdge& _descriptor;
const std::pair<double, double>& _range;
const std::pair<bool, bool>& _include;
bool _invert;
bool& _retval;
};
FilteredPropertyMap _filtered_property;
std::pair<double, double> _range;
std::pair<bool, bool> _include;
bool _invert;
};
typedef mpl::vector<mpl::bool_<true>, mpl::bool_<false> > reverse_check;
......@@ -261,43 +275,6 @@ struct check_directed
bool& _found;
};
#ifndef NO_PYTHON_FILTERING
template <class Graph, class Action, class ReverseCheck, class DirectedCheck>
void check_python_filter(const Graph& g, const GraphInterface &gi, Action a, bool& found, ReverseCheck, DirectedCheck)
{
typedef PythonFilter<Graph,typename graph_traits<Graph>::vertex_descriptor> vertex_filter_t;
typedef PythonFilter<Graph,typename graph_traits<Graph>::edge_descriptor> edge_filter_t;
if (gi._edge_python_filter != python::object())
{
typedef filtered_graph<Graph, edge_filter_t, keep_all> efg_t;
efg_t efg(g,edge_filter_t(g, gi._properties, gi._edge_python_filter), keep_all());
if (gi._vertex_python_filter != python::object())
{
typedef PythonFilter<efg_t, typename graph_traits<efg_t>::vertex_descriptor, mpl::bool_<true> > vertex_filter_t;
typedef filtered_graph<efg_t,keep_all,vertex_filter_t> vefg_t;
vefg_t vefg(efg,keep_all(),vertex_filter_t(efg, gi._properties, gi._vertex_python_filter));
mpl::for_each<DirectedCheck>(check_directed<vefg_t,Action,ReverseCheck>(vefg, a, gi._reversed, gi._directed, found));
}
else
{
mpl::for_each<DirectedCheck>(check_directed<efg_t,Action,ReverseCheck>(efg, a, gi._reversed, gi._directed, found));
}
}
else if (gi._vertex_python_filter != python::object())
{
typedef filtered_graph<Graph,keep_all,vertex_filter_t> vfg_t;
vfg_t vfg(g,keep_all(),vertex_filter_t(g, gi._properties, gi._vertex_python_filter));
mpl::for_each<DirectedCheck>(check_directed<vfg_t,Action,ReverseCheck>(vfg, a, gi._reversed, gi._directed, found));
}
else
{
mpl::for_each<DirectedCheck>(check_directed<Graph,Action,ReverseCheck>(g, a, gi._reversed, gi._directed, found));
}
}
#endif
template <class Action, class ReverseCheck, class DirectedCheck>
void check_filter(const GraphInterface &g, Action a, ReverseCheck, DirectedCheck)
{
......@@ -306,27 +283,12 @@ void check_filter(const GraphInterface &g, Action a, ReverseCheck, DirectedCheck
typedef RangeFilter<GraphInterface::vertex_filter_map_t> vertex_filter_t;
typedef RangeFilter<GraphInterface::edge_filter_map_t> edge_filter_t;
#ifndef NO_PYTHON_FILTERING
if (g._edge_python_filter == python::object() && g._vertex_python_filter == python::object())
{
#endif
#ifndef NO_RANGE_FILTERING
if (g._vertex_filter_property != "" && g._edge_filter_property != "")
if (g._vertex_filter_property != "" || g._edge_filter_property != "")
{
typedef filtered_graph<GraphInterface::multigraph_t, edge_filter_t, vertex_filter_t> fg_t;
fg_t fg(g._mg, edge_filter_t(g._edge_filter_map, g._edge_range), vertex_filter_t(g._vertex_filter_map, g._vertex_range));
mpl::for_each<DirectedCheck>(check_directed<fg_t,Action,ReverseCheck>(fg, a, g._reversed, g._directed, found));
}
else if (g._vertex_filter_property != "")
{
typedef filtered_graph<GraphInterface::multigraph_t, keep_all, vertex_filter_t> fg_t;
fg_t fg(g._mg, keep_all(), vertex_filter_t(g._vertex_filter_map, g._vertex_range));
mpl::for_each<DirectedCheck>(check_directed<fg_t,Action,ReverseCheck>(fg, a, g._reversed, g._directed, found));
}
else if (g._edge_filter_property != "")
{
typedef filtered_graph<GraphInterface::multigraph_t, edge_filter_t, keep_all> fg_t;
fg_t fg(g._mg, edge_filter_t(g._edge_filter_map, g._edge_range), keep_all());
fg_t fg(g._mg, edge_filter_t(g._edge_filter_map, g._edge_range, g._edge_range_include, g._edge_range_invert),
vertex_filter_t(g._vertex_filter_map, g._vertex_range, g._vertex_range_include, g._vertex_range_invert));
mpl::for_each<DirectedCheck>(check_directed<fg_t,Action,ReverseCheck>(fg, a, g._reversed, g._directed, found));
}
else
......@@ -336,22 +298,10 @@ void check_filter(const GraphInterface &g, Action a, ReverseCheck, DirectedCheck
#else
mpl::for_each<DirectedCheck>(check_directed<GraphInterface::multigraph_t,Action,ReverseCheck>(g._mg, a, g._reversed, g._directed, found));
#endif
#ifndef NO_PYTHON_FILTERING
}
else
{
check_python_filter(g._mg, g, a, found, ReverseCheck(), DirectedCheck());
}
#else
#ifdef NO_RANGE_FILTERING
mpl::for_each<DirectedCheck>(check_directed<GraphInterface::multigraph_t,Action,ReverseCheck>(g._mg, a, g._reversed, g._directed, found));
#endif
#endif
if (!found)
throw GraphException("graph filtering error: filter not found");
}
} //graph_tool namespace
#endif
#endif // FILTERING_HH
......@@ -21,7 +21,7 @@
#include "graph.hh"
#include "histogram.hh"
#include "graph_filtering.hh"
#include "graph_python_filtering.hh"
#include "graph_python_interface.hh"
#include "graph_selectors.hh"
#include "graph_properties.hh"
......
......@@ -978,43 +978,6 @@ private:
};
//==============================================================================
// PythonFilter
//==============================================================================
template <class Graph, class Descriptor, class HasBase = mpl::bool_<false> >
class PythonFilter
{
public:
typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
typedef mpl::vector<in_degreeS,out_degreeS,total_degreeS> degrees;
PythonFilter(){}
PythonFilter(const Graph& g, const dynamic_properties& dp, python::object filter)
: _g(&g), _filter(filter[0])
{
python::object variables = filter[1];
populate_python_funcs<Descriptor, HasBase>()(*_g, _u, dp, variables);
}
inline bool operator() (Descriptor u) const
{
_u = u;
return python::extract<bool>(_filter());
}
private:
Graph const* _g;
python::object _filter;
static Descriptor _u;
};
template <class Graph, class Descriptor, class HasBase>
Descriptor PythonFilter<Graph,Descriptor,HasBase>::_u;
} //graph_tool namespace
#endif
Supports Markdown
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