Commit 4d212c1b authored by Tiago Peixoto's avatar Tiago Peixoto
Browse files

Switch from boost::adjacency_list<> to custom made and lightweight adj_list<>

Dumping boost::adjacency_list<> improves memory usage by a factor of
two, and also slightly improves performance in some cases.
parent 5b67db19
......@@ -29,5 +29,4 @@ void price(GraphInterface& gi, size_t N, double gamma, double c, size_t m,
rng_t& rng)
{
run_action<>()(gi, bind<void>(get_price(), _1, N, gamma, c, m, ref(rng)))();
gi.ReIndexEdges();
}
......@@ -96,7 +96,7 @@ struct swap_edge
static void swap_target
(size_t e, const pair<size_t, bool>& te,
vector<typename graph_traits<Graph>::edge_descriptor>& edges,
EdgeIndexMap edge_index, Graph& g)
EdgeIndexMap, Graph& g)
{
// swap the source of the edge 'e' with the source of edge 'se', as
// such:
......@@ -109,19 +109,21 @@ struct swap_edge
// new edges which will replace the old ones
typename graph_traits<Graph>::edge_descriptor ne, nte;
ne = add_edge(source(edges[e], g), target(te, edges, g), g).first;
if (!te.second)
nte = add_edge(source(te, edges, g), target(edges[e], g), g).first;
else // keep invertedness (only for undirected graphs)
nte = add_edge(target(edges[e], g), source(te, edges, g), g).first;
edge_index[nte] = edge_index[edges[te.first]];
typename graph_traits<Graph>::vertex_descriptor
s_e = source(edges[e], g),
t_e = target(edges[e], g),
s_te = source(te, edges, g),
t_te = target(te, edges, g);
remove_edge(edges[e], g);
remove_edge(edges[te.first], g);
edges[te.first] = nte;
edge_index[ne] = edge_index[edges[e]];
remove_edge(edges[e], g);
ne = add_edge(s_e, t_te, g).first;
edges[e] = ne;
if (!te.second)
nte = add_edge(s_te, t_e, g).first;
else // keep invertedness (only for undirected graphs)
nte = add_edge(t_e, s_te, g).first;
edges[te.first] = nte;
}
};
......@@ -171,7 +173,7 @@ public:
template <class Graph>
block_t get_block(typename graph_traits<Graph>::vertex_descriptor v,
const Graph& g) const
const Graph&) const
{
return get(_p, v);
}
......@@ -308,9 +310,8 @@ public:
if (!parallel_edges && is_adjacent(s, t, _g))
return false;
edge_t ne = add_edge(s, t, _g).first;
_edge_index[ne] = _edge_index[_edges[ei]];
remove_edge(_edges[ei], _g);
edge_t ne = add_edge(s, t, _g).first;
_edges[ei] = ne;
return true;
......@@ -419,7 +420,7 @@ public:
bool, rng_t& rng)
: base_t(g, edge_index, edges, rng), _g(g) {}
pair<size_t,bool> get_target_edge(size_t e)
pair<size_t,bool> get_target_edge(size_t)
{
tr1::uniform_int<> sample(0, base_t::_edges.size() - 1);
pair<size_t, bool> et = make_pair(sample(base_t::_rng), false);
......@@ -431,7 +432,7 @@ public:
return et;
}
void update_edge(size_t e, bool insert) {}
void update_edge(size_t, bool) {}
private:
Graph& _g;
......@@ -495,7 +496,7 @@ public:
return elist[sample(base_t::_rng)];
}
void update_edge(size_t e, bool insert) {}
void update_edge(size_t, bool) {}
private:
typedef pair<size_t, size_t> deg_t;
......@@ -619,7 +620,7 @@ public:
return ep;
}
void update_edge(size_t e, bool insert) {}
void update_edge(size_t, bool) {}
private:
Graph& _g;
......
......@@ -106,5 +106,4 @@ void triangulation(GraphInterface& gi, python::object points, boost::any pos,
#endif
}
}
gi.ReIndexEdges();
}
......@@ -78,7 +78,7 @@ struct property_union
template <class UnionGraph, class Graph, class VertexMap, class EdgeMap,
class UnionProp, class Prop>
void dispatch(UnionGraph& ug, Graph& g, VertexMap vmap, EdgeMap emap,
void dispatch(UnionGraph&, Graph& g, VertexMap vmap, EdgeMap,
UnionProp uprop, Prop prop, mpl::true_) const
{
typename graph_traits<Graph>::vertex_iterator v, v_end;
......@@ -88,7 +88,7 @@ struct property_union
template <class UnionGraph, class Graph, class VertexMap, class EdgeMap,
class UnionProp, class Prop>
void dispatch(UnionGraph& ug, Graph& g, VertexMap vmap, EdgeMap emap,
void dispatch(UnionGraph&, Graph& g, VertexMap, EdgeMap emap,
UnionProp uprop, Prop prop, mpl::false_) const
{
typename graph_traits<Graph>::edge_iterator e, e_end;
......
......@@ -31,6 +31,16 @@
#include <boost/foreach.hpp>
#include <boost/type_traits.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/property_map/dynamic_property_map.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/bind/bind.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/properties.hpp>
#include <boost/python.hpp>
#include <iostream>
#include <fstream>
#include <string>
......
......@@ -30,9 +30,9 @@ using namespace graph_tool;
// this is the constructor for the graph interface
GraphInterface::GraphInterface()
:_state(new state_t()),
_vertex_index(get(vertex_index, _state->_mg)),
_edge_index(get(edge_index_t(), _state->_mg)),
:_mg(new multigraph_t()),
_vertex_index(get(vertex_index, *_mg)),
_edge_index(get(edge_index_t(), *_mg)),
_reversed(false),
_directed(true),
_graph_index(0),
......@@ -43,7 +43,6 @@ GraphInterface::GraphInterface()
_edge_filter_invert(false),
_edge_filter_active(false)
{
_state->_nedges = _state->_max_edge_index = 0;
}
// the destructor
......@@ -76,25 +75,19 @@ size_t GraphInterface::GetNumberOfEdges()
run_action<>()(*this, lambda::var(n) =
lambda::bind<size_t>(HardNumEdges(),lambda::_1))();
else
n = _state->_nedges;
n = num_edges(*_mg);
return n;
}
void GraphInterface::Clear()
{
_state->_mg.clear();
_state->_nedges = 0;
_state->_max_edge_index = 0;
_state->_free_indexes.clear();
*_mg = multigraph_t();
}
void GraphInterface::ClearEdges()
{
graph_traits<multigraph_t>::vertex_iterator v, v_end;
for (tie(v, v_end) = vertices(_state->_mg); v != v_end; ++v)
clear_vertex(*v, _state->_mg);
_state->_nedges = 0;
_state->_max_edge_index = 0;
_state->_free_indexes.clear();
for (tie(v, v_end) = vertices(*_mg); v != v_end; ++v)
clear_vertex(*v, *_mg);
_mg->reindex_edges();
}
......@@ -25,8 +25,9 @@
#include <deque>
#include "graph_adjacency.hh"
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/adjacency_list.hpp>
#include "fast_vector_property_map.hh"
#include <boost/variant.hpp>
......@@ -123,15 +124,17 @@ public:
// Internal types
//
// the following defines the edges' internal properties
typedef property<edge_index_t, size_t> EdgeProperty;
// this is the main graph type
typedef adjacency_list <vecS, // edges
vecS, // vertices
bidirectionalS,
no_property,
EdgeProperty> multigraph_t;
// // the following defines the edges' internal properties
// typedef property<edge_index_t, size_t> EdgeProperty;
// // this is the main graph type
// typedef adjacency_list <vecS, // edges
// vecS, // vertices
// bidirectionalS,
// no_property,
// EdgeProperty,
// vecS> multigraph_t;
typedef adj_list<size_t> multigraph_t;
typedef graph_traits<multigraph_t>::vertex_descriptor vertex_t;
typedef graph_traits<multigraph_t>::edge_descriptor edge_t;
......@@ -141,16 +144,13 @@ public:
// internal access
multigraph_t& GetGraph() {return _state->_mg;}
multigraph_t& GetGraph() {return *_mg;}
vertex_index_map_t GetVertexIndex() {return _vertex_index;}
edge_index_map_t GetEdgeIndex() {return _edge_index;}
size_t GetMaxEdgeIndex(){return _state->_max_edge_index;}
size_t GetMaxEdgeIndex(){return _mg->get_last_index();}
graph_index_map_t GetGraphIndex() {return graph_index_map_t(0);}
void AddEdgeIndex(const edge_t& e);
void RemoveEdgeIndex(const edge_t& e);
// Gets the encapsulated graph view. See graph_filtering.cc for details
boost::any GetGraphView() const;
......@@ -166,22 +166,8 @@ private:
template <class Graph>
friend class PythonEdge;
struct state_t
{
// this is the main graph
multigraph_t _mg;
// keep track of the number of edges, since num_edges() is O(V) in
// adjacency_list... :-(
size_t _nedges;
deque<size_t> _free_indexes; // indexes of deleted edges to be used up
// for new edges to avoid very large
// indexes, and property map memory usage
size_t _max_edge_index;
};
shared_ptr<state_t> _state;
shared_ptr<multigraph_t> _mg;
// vertex index map
vertex_index_map_t _vertex_index;
......
This diff is collapsed.
......@@ -87,7 +87,7 @@ struct do_graph_copy
void operator()(const GraphSrc& src, GraphTgt& tgt,
TgtVertexIndexMap src_vertex_index,
SrcVertexIndexMap tgt_vertex_index,
TgtEdgeIndexMap src_edge_index,
TgtEdgeIndexMap,
SrcEdgeIndexMap tgt_edge_index,
vector<pair<reference_wrapper<boost::any>,reference_wrapper<boost::any> > >& vprops,
vector<pair<reference_wrapper<boost::any>,reference_wrapper<boost::any> > >& eprops) const
......@@ -108,7 +108,6 @@ struct do_graph_copy
src, tgt, tgt_vertex_index);
}
size_t e_idx = 0;
typename graph_traits<GraphSrc>::edge_iterator e, e_end;
for (tie(e, e_end) = edges(src); e != e_end; ++e)
{
......@@ -116,8 +115,6 @@ struct do_graph_copy
size_t t = index_map[src_vertex_index[target(*e, src)]];
typedef typename graph_traits<GraphTgt>::edge_descriptor edge_t;
edge_t new_e = add_edge(vertex(s,tgt), vertex(t,tgt), tgt).first;
tgt_edge_index[new_e] = e_idx;
++e_idx;
for (size_t i = 0; i < eprops.size(); ++i)
copy_property<writable_edge_properties>
......@@ -130,9 +127,9 @@ struct do_graph_copy
// copy constructor
GraphInterface::GraphInterface(const GraphInterface& gi, bool keep_ref,
python::object ovprops, python::object oeprops)
:_state(keep_ref ? gi._state : shared_ptr<state_t>(new state_t())),
_vertex_index(get(vertex_index, _state->_mg)),
_edge_index(get(edge_index_t(), _state->_mg)),
:_mg(keep_ref ? gi._mg : shared_ptr<multigraph_t>(new multigraph_t())),
_vertex_index(get(vertex_index, *_mg)),
_edge_index(get(edge_index_t(), *_mg)),
_reversed(gi._reversed),
_directed(gi._directed),
_vertex_filter_map(_vertex_index),
......@@ -160,13 +157,9 @@ GraphInterface::GraphInterface(const GraphInterface& gi, bool keep_ref,
run_action<>()
(const_cast<GraphInterface&>(gi),
bind<void>(do_graph_copy(), _1, ref(_state->_mg),
bind<void>(do_graph_copy(), _1, ref(*_mg),
gi._vertex_index, _vertex_index,
gi._edge_index, _edge_index, ref(vprops),
ref(eprops)))();
_state->_nedges = num_edges(_state->_mg);
_state->_max_edge_index = _state->_nedges > 0 ? num_edges(_state->_mg) - 1 : 0;
// filters will be copied in python
}
......@@ -137,7 +137,7 @@ check_filtered(const Graph &g, const EdgeFilter& edge_filter,
if (e_active)
{
if (max_eindex > 0)
edge_filter.reserve(max_eindex+1);
edge_filter.reserve(max_eindex);
if (v_active)
{
if (num_vertices(g) > 0)
......@@ -186,11 +186,9 @@ check_filtered(const Graph &g, const EdgeFilter& edge_filter,
// gets the correct graph view at run time
boost::any GraphInterface::GetGraphView() const
{
// TODO: implement memoization
boost::any graph =
check_filtered(_state->_mg, _edge_filter_map, _edge_filter_invert,
_edge_filter_active, _state->_max_edge_index,
check_filtered(*_mg, _edge_filter_map, _edge_filter_invert,
_edge_filter_active, _mg->get_last_index(),
_vertex_filter_map, _vertex_filter_invert,
_vertex_filter_active,
const_cast<vector<boost::any>&>(_graph_views), _reversed,
......@@ -210,13 +208,7 @@ bool GraphInterface::IsEdgeFilterActive() const
// found
void GraphInterface::ReIndexEdges()
{
size_t index = 0;
graph_traits<multigraph_t>::edge_iterator e, e_end;
for (tie(e, e_end) = edges(_state->_mg); e != e_end; ++e)
_edge_index[*e] = index++;
_state->_max_edge_index = (index > 0) ? index - 1 : 0;
_state->_nedges = index;
_state->_free_indexes.clear();
_mg->reindex_edges();
}
// this will definitively remove all the edges from the graph, which are being
......@@ -230,14 +222,14 @@ void GraphInterface::PurgeEdges()
graph_traits<multigraph_t>::vertex_iterator v, v_end;
graph_traits<multigraph_t>::out_edge_iterator e, e_end;
vector<graph_traits<multigraph_t>::edge_descriptor> deleted_edges;
for (tie(v, v_end) = vertices(_state->_mg); v != v_end; ++v)
for (tie(v, v_end) = vertices(*_mg); v != v_end; ++v)
{
for (tie(e, e_end) = out_edges(*v, _state->_mg); e != e_end; ++e)
for (tie(e, e_end) = out_edges(*v, *_mg); e != e_end; ++e)
if (!filter(*e))
deleted_edges.push_back(*e);
for (typeof(deleted_edges.begin()) iter = deleted_edges.begin();
iter != deleted_edges.end(); ++iter)
RemoveEdgeIndex(*iter);
remove_edge(*iter, *_mg);
deleted_edges.clear();
}
}
......@@ -257,10 +249,10 @@ void GraphInterface::PurgeVertices(boost::any aold_index)
MaskFilter<vertex_filter_t> filter(_vertex_filter_map,
_vertex_filter_invert);
size_t N = num_vertices(_state->_mg);
size_t N = num_vertices(*_mg);
vector<bool> deleted(N, false);
for (size_t i = 0; i < N; ++i)
deleted[i] = !filter(vertex(i, _state->_mg));
deleted[i] = !filter(vertex(i, *_mg));
vector<int> old_indexes;
vector<graph_traits<multigraph_t>::edge_descriptor> edges;
......@@ -271,22 +263,8 @@ void GraphInterface::PurgeVertices(boost::any aold_index)
if (deleted[i])
{
graph_traits<multigraph_t>::vertex_descriptor v =
vertex(i, _state->_mg);
graph_traits<multigraph_t>::out_edge_iterator e, e_end;
for(tie(e, e_end) = out_edges(v, _state->_mg); e != e_end; ++e)
edges.push_back(*e);
graph_traits<multigraph_t>::in_edge_iterator ei, ei_end;
for(tie(ei, ei_end) = in_edges(v, _state->_mg); ei != ei_end; ++ei)
{
if (source(*ei, _state->_mg) == v)
continue;
edges.push_back(*ei);
}
for(size_t j = 0; j < edges.size(); ++j)
RemoveEdgeIndex(edges[j]);
clear_vertex(v, _state->_mg);
remove_vertex(v, _state->_mg);
edges.clear();
vertex(i, *_mg);
remove_vertex(v, *_mg);
}
else
{
......@@ -297,7 +275,7 @@ void GraphInterface::PurgeVertices(boost::any aold_index)
N = old_indexes.size();
for (int i = N-1; i >= 0; --i)
{
old_index[vertex((N - 1) - i, _state->_mg)] = old_indexes[i];
old_index[vertex((N - 1) - i, *_mg)] = old_indexes[i];
}
}
......@@ -338,4 +316,3 @@ void GraphInterface::SetEdgeFilterProperty(boost::any property, bool invert)
_edge_filter_active = false;
}
}
......@@ -47,11 +47,11 @@
#include <boost/mpl/transform_view.hpp>
#include <boost/mpl/quote.hpp>
#include <boost/mpl/range_c.hpp>
#include <boost/mpl/print.hpp>
#include "graph_adaptor.hh"
#include "graph_selectors.hh"
#include "graph_util.hh"
#include "graph_wrap.hh"
#include "mpl_nested_loop.hh"
namespace graph_tool
......@@ -514,9 +514,9 @@ struct action_wrap
: _a(a), _g(g), _max_v(max_v), _max_e(max_e) {}
template <class Type>
checked_vector_property_map<Type,GraphInterface::vertex_index_map_t>
checked_vector_property_map<Type,GraphInterface::vertex_index_map_t>&
uncheck(checked_vector_property_map
<Type,GraphInterface::vertex_index_map_t> a, mpl::true_) const
<Type,GraphInterface::vertex_index_map_t>& a, mpl::true_) const
{
return a;
}
......@@ -530,9 +530,9 @@ struct action_wrap
}
template <class Type>
checked_vector_property_map<Type,GraphInterface::edge_index_map_t>
checked_vector_property_map<Type,GraphInterface::edge_index_map_t>&
uncheck(checked_vector_property_map
<Type,GraphInterface::edge_index_map_t> a, mpl::true_) const
<Type,GraphInterface::edge_index_map_t>& a, mpl::true_) const
{
return a;
}
......@@ -555,38 +555,25 @@ struct action_wrap
//no op
template <class Type, class DoWrap>
Type uncheck(Type a, DoWrap) const { return a; }
template <class Graph>
GraphWrap<Graph> wrap(Graph* g, mpl::true_) const
{
return graph_wrap(*g, _g);
}
template <class Graph>
Graph& wrap(Graph* g, mpl::false_) const
{
return *g;
}
Type& uncheck(Type& a, DoWrap) const { return a; }
void operator()() const {};
template <class T1> void operator()(const T1& a1) const
{ _a(wrap(a1, Wrap())); }
template <class T1> void operator()(T1* a1) const
{ _a(*a1); }
template <class T1, class T2>
void operator()(const T1& a1, const T2& a2) const
{ _a(wrap(a1,Wrap()), uncheck(a2, Wrap())); }
void operator()(T1* a1, T2& a2) const
{ _a(*a1, uncheck(a2, Wrap())); }
template <class T1, class T2, class T3>
void operator()(const T1& a1, const T2& a2, const T3& a3) const
{ _a(wrap(a1,Wrap()), uncheck(a2, Wrap()), uncheck(a3, Wrap()));}
void operator()(T1* a1, T2& a2, T3& a3) const
{ _a(*a1, uncheck(a2, Wrap()), uncheck(a3, Wrap())); }
template <class T1, class T2, class T3, class T4>
void operator()(const T1& a1, const T2& a2, const T3& a3, const T4& a4)
void operator()(T1* a1, T2& a2, T3& a3, T4& a4)
const
{ _a(wrap(a1,Wrap()), uncheck(a2, Wrap()), uncheck(a3, Wrap()),
{ _a(*a1, uncheck(a2, Wrap()), uncheck(a3, Wrap()),
uncheck(a4, Wrap())); }
template <class T1, class T2, class T3, class T4, class T5>
void operator()(const T1& a1, const T2& a2, const T3& a3, const T4& a4,
const T5& a5) const
{ _a(wrap(a1,Wrap()), uncheck(a2, Wrap()), uncheck(a3, Wrap()),
void operator()(T1* a1, T2& a2, T3& a3, T4& a4, T5& a5) const
{ _a(*a1, uncheck(a2, Wrap()), uncheck(a3, Wrap()),
uncheck(a4, Wrap()), uncheck(a5, Wrap())); }
Action _a;
......@@ -604,8 +591,8 @@ struct graph_action
mpl::transform<GraphViews, mpl::quote1<add_pointer> >::type {};
graph_action(GraphInterface& g, Action a)
: _g(g), _a(a, g, num_vertices(g._state->_mg),
g._state->_max_edge_index + 1) {}
: _g(g), _a(a, g, num_vertices(*g._mg),
max(g._mg->get_last_index(), size_t(1))) {}
void operator()() const
{
......@@ -671,7 +658,7 @@ struct graph_action
bool found = false;
boost::any gview = _g.GetGraphView();
boost::mpl::nested_for_each<graph_view_pointers,TR1,TR2,TR3,TR4>()
(boost::mpl::select_types(_a, found, gview, a1, a2, a3,a4));
(boost::mpl::select_types(_a, found, gview, a1, a2, a3, a4));
if (!found)
{
vector<const std::type_info*> args;
......
......@@ -15,13 +15,14 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <boost/python/extract.hpp>
#include "gml.hh"
#include "graph.hh"
#include "graph_filtering.hh"
#include "graph_properties.hh"
#include "graph_util.hh"
#include <boost/python/extract.hpp>
#include <iostream>
#include <boost/algorithm/string.hpp>
#include <boost/iostreams/categories.hpp>
......@@ -35,8 +36,6 @@
#include <boost/lexical_cast.hpp>
#include <boost/xpressive/xpressive.hpp>
#include "gml.hh"
#include "graph_python_interface.hh"
#include "str_repr.hh"
......@@ -194,7 +193,7 @@ struct create_dynamic_map
create_dynamic_map(VertexIndexMap vertex_map, EdgeIndexMap edge_map)
:_vertex_map(vertex_map), _edge_map(edge_map) {}
DP_SMART_PTR<dynamic_property_map> operator()(const string& name,
DP_SMART_PTR<dynamic_property_map> operator()(const string&,
const boost::any& key,
const boost::any& value)
{
......@@ -232,82 +231,6 @@ struct create_dynamic_map
EdgeIndexMap _edge_map;
};
// this graph wrapper will update the edge index map when edges are added
template <class Graph, class EdgeIndexMap>
struct GraphEdgeIndexWrap
{
GraphEdgeIndexWrap(Graph &g, EdgeIndexMap edge_index_map)
: _g(g), _edge_index_map(edge_index_map), _n_edges(0) {}
Graph &_g;
EdgeIndexMap _edge_index_map;
size_t _n_edges;
typedef typename Graph::vertex_property_type vertex_property_type;
typedef typename Graph::edge_property_type edge_property_type;
typedef typename Graph::graph_tag graph_tag;
typedef typename Graph::graph_type graph_type;
#if (BOOST_VERSION / 100 % 1000 >= 45)
typedef typename Graph::graph_property_type graph_property_type;
typedef typename Graph::graph_bundled graph_bundled;
typedef typename Graph::edge_bundled edge_bundled;
typedef typename Graph::vertex_bundled vertex_bundled;
#endif