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, ...@@ -29,5 +29,4 @@ void price(GraphInterface& gi, size_t N, double gamma, double c, size_t m,
rng_t& rng) rng_t& rng)
{ {
run_action<>()(gi, bind<void>(get_price(), _1, N, gamma, c, m, ref(rng)))(); run_action<>()(gi, bind<void>(get_price(), _1, N, gamma, c, m, ref(rng)))();
gi.ReIndexEdges();
} }
...@@ -96,7 +96,7 @@ struct swap_edge ...@@ -96,7 +96,7 @@ struct swap_edge
static void swap_target static void swap_target
(size_t e, const pair<size_t, bool>& te, (size_t e, const pair<size_t, bool>& te,
vector<typename graph_traits<Graph>::edge_descriptor>& edges, 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 // swap the source of the edge 'e' with the source of edge 'se', as
// such: // such:
...@@ -109,19 +109,21 @@ struct swap_edge ...@@ -109,19 +109,21 @@ struct swap_edge
// new edges which will replace the old ones // new edges which will replace the old ones
typename graph_traits<Graph>::edge_descriptor ne, nte; typename graph_traits<Graph>::edge_descriptor ne, nte;
ne = add_edge(source(edges[e], g), target(te, edges, g), g).first; typename graph_traits<Graph>::vertex_descriptor
if (!te.second) s_e = source(edges[e], g),
nte = add_edge(source(te, edges, g), target(edges[e], g), g).first; t_e = target(edges[e], g),
else // keep invertedness (only for undirected graphs) s_te = source(te, edges, g),
nte = add_edge(target(edges[e], g), source(te, edges, g), g).first; t_te = target(te, edges, g);
remove_edge(edges[e], g);
edge_index[nte] = edge_index[edges[te.first]];
remove_edge(edges[te.first], g); remove_edge(edges[te.first], g);
edges[te.first] = nte;
edge_index[ne] = edge_index[edges[e]]; ne = add_edge(s_e, t_te, g).first;
remove_edge(edges[e], g);
edges[e] = ne; 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: ...@@ -171,7 +173,7 @@ public:
template <class Graph> template <class Graph>
block_t get_block(typename graph_traits<Graph>::vertex_descriptor v, block_t get_block(typename graph_traits<Graph>::vertex_descriptor v,
const Graph& g) const const Graph&) const
{ {
return get(_p, v); return get(_p, v);
} }
...@@ -308,9 +310,8 @@ public: ...@@ -308,9 +310,8 @@ public:
if (!parallel_edges && is_adjacent(s, t, _g)) if (!parallel_edges && is_adjacent(s, t, _g))
return false; return false;
edge_t ne = add_edge(s, t, _g).first;
_edge_index[ne] = _edge_index[_edges[ei]];
remove_edge(_edges[ei], _g); remove_edge(_edges[ei], _g);
edge_t ne = add_edge(s, t, _g).first;
_edges[ei] = ne; _edges[ei] = ne;
return true; return true;
...@@ -419,7 +420,7 @@ public: ...@@ -419,7 +420,7 @@ public:
bool, rng_t& rng) bool, rng_t& rng)
: base_t(g, edge_index, edges, rng), _g(g) {} : 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); tr1::uniform_int<> sample(0, base_t::_edges.size() - 1);
pair<size_t, bool> et = make_pair(sample(base_t::_rng), false); pair<size_t, bool> et = make_pair(sample(base_t::_rng), false);
...@@ -431,7 +432,7 @@ public: ...@@ -431,7 +432,7 @@ public:
return et; return et;
} }
void update_edge(size_t e, bool insert) {} void update_edge(size_t, bool) {}
private: private:
Graph& _g; Graph& _g;
...@@ -495,7 +496,7 @@ public: ...@@ -495,7 +496,7 @@ public:
return elist[sample(base_t::_rng)]; return elist[sample(base_t::_rng)];
} }
void update_edge(size_t e, bool insert) {} void update_edge(size_t, bool) {}
private: private:
typedef pair<size_t, size_t> deg_t; typedef pair<size_t, size_t> deg_t;
...@@ -619,7 +620,7 @@ public: ...@@ -619,7 +620,7 @@ public:
return ep; return ep;
} }
void update_edge(size_t e, bool insert) {} void update_edge(size_t, bool) {}
private: private:
Graph& _g; Graph& _g;
......
...@@ -106,5 +106,4 @@ void triangulation(GraphInterface& gi, python::object points, boost::any pos, ...@@ -106,5 +106,4 @@ void triangulation(GraphInterface& gi, python::object points, boost::any pos,
#endif #endif
} }
} }
gi.ReIndexEdges();
} }
...@@ -78,7 +78,7 @@ struct property_union ...@@ -78,7 +78,7 @@ struct property_union
template <class UnionGraph, class Graph, class VertexMap, class EdgeMap, template <class UnionGraph, class Graph, class VertexMap, class EdgeMap,
class UnionProp, class Prop> 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 UnionProp uprop, Prop prop, mpl::true_) const
{ {
typename graph_traits<Graph>::vertex_iterator v, v_end; typename graph_traits<Graph>::vertex_iterator v, v_end;
...@@ -88,7 +88,7 @@ struct property_union ...@@ -88,7 +88,7 @@ struct property_union
template <class UnionGraph, class Graph, class VertexMap, class EdgeMap, template <class UnionGraph, class Graph, class VertexMap, class EdgeMap,
class UnionProp, class Prop> 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 UnionProp uprop, Prop prop, mpl::false_) const
{ {
typename graph_traits<Graph>::edge_iterator e, e_end; typename graph_traits<Graph>::edge_iterator e, e_end;
......
...@@ -31,6 +31,16 @@ ...@@ -31,6 +31,16 @@
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
#include <boost/type_traits.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 <iostream>
#include <fstream> #include <fstream>
#include <string> #include <string>
......
...@@ -30,9 +30,9 @@ using namespace graph_tool; ...@@ -30,9 +30,9 @@ using namespace graph_tool;
// this is the constructor for the graph interface // this is the constructor for the graph interface
GraphInterface::GraphInterface() GraphInterface::GraphInterface()
:_state(new state_t()), :_mg(new multigraph_t()),
_vertex_index(get(vertex_index, _state->_mg)), _vertex_index(get(vertex_index, *_mg)),
_edge_index(get(edge_index_t(), _state->_mg)), _edge_index(get(edge_index_t(), *_mg)),
_reversed(false), _reversed(false),
_directed(true), _directed(true),
_graph_index(0), _graph_index(0),
...@@ -43,7 +43,6 @@ GraphInterface::GraphInterface() ...@@ -43,7 +43,6 @@ GraphInterface::GraphInterface()
_edge_filter_invert(false), _edge_filter_invert(false),
_edge_filter_active(false) _edge_filter_active(false)
{ {
_state->_nedges = _state->_max_edge_index = 0;
} }
// the destructor // the destructor
...@@ -76,25 +75,19 @@ size_t GraphInterface::GetNumberOfEdges() ...@@ -76,25 +75,19 @@ size_t GraphInterface::GetNumberOfEdges()
run_action<>()(*this, lambda::var(n) = run_action<>()(*this, lambda::var(n) =
lambda::bind<size_t>(HardNumEdges(),lambda::_1))(); lambda::bind<size_t>(HardNumEdges(),lambda::_1))();
else else
n = _state->_nedges; n = num_edges(*_mg);
return n; return n;
} }
void GraphInterface::Clear() void GraphInterface::Clear()
{ {
_state->_mg.clear(); *_mg = multigraph_t();
_state->_nedges = 0;
_state->_max_edge_index = 0;
_state->_free_indexes.clear();
} }
void GraphInterface::ClearEdges() void GraphInterface::ClearEdges()
{ {
graph_traits<multigraph_t>::vertex_iterator v, v_end; graph_traits<multigraph_t>::vertex_iterator v, v_end;
for (tie(v, v_end) = vertices(_state->_mg); v != v_end; ++v) for (tie(v, v_end) = vertices(*_mg); v != v_end; ++v)
clear_vertex(*v, _state->_mg); clear_vertex(*v, *_mg);
_state->_nedges = 0; _mg->reindex_edges();
_state->_max_edge_index = 0;
_state->_free_indexes.clear();
} }
...@@ -25,8 +25,9 @@ ...@@ -25,8 +25,9 @@
#include <deque> #include <deque>
#include "graph_adjacency.hh"
#include <boost/graph/graph_traits.hpp> #include <boost/graph/graph_traits.hpp>
#include <boost/graph/adjacency_list.hpp>
#include "fast_vector_property_map.hh" #include "fast_vector_property_map.hh"
#include <boost/variant.hpp> #include <boost/variant.hpp>
...@@ -123,15 +124,17 @@ public: ...@@ -123,15 +124,17 @@ public:
// Internal types // Internal types
// //
// the following defines the edges' internal properties // // the following defines the edges' internal properties
typedef property<edge_index_t, size_t> EdgeProperty; // typedef property<edge_index_t, size_t> EdgeProperty;
// this is the main graph type // // this is the main graph type
typedef adjacency_list <vecS, // edges // typedef adjacency_list <vecS, // edges
vecS, // vertices // vecS, // vertices
bidirectionalS, // bidirectionalS,
no_property, // no_property,
EdgeProperty> multigraph_t; // 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>::vertex_descriptor vertex_t;
typedef graph_traits<multigraph_t>::edge_descriptor edge_t; typedef graph_traits<multigraph_t>::edge_descriptor edge_t;
...@@ -141,16 +144,13 @@ public: ...@@ -141,16 +144,13 @@ public:
// internal access // internal access
multigraph_t& GetGraph() {return _state->_mg;} multigraph_t& GetGraph() {return *_mg;}
vertex_index_map_t GetVertexIndex() {return _vertex_index;} vertex_index_map_t GetVertexIndex() {return _vertex_index;}
edge_index_map_t GetEdgeIndex() {return _edge_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);} 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 // Gets the encapsulated graph view. See graph_filtering.cc for details
boost::any GetGraphView() const; boost::any GetGraphView() const;
...@@ -166,22 +166,8 @@ private: ...@@ -166,22 +166,8 @@ private:
template <class Graph> template <class Graph>
friend class PythonEdge; friend class PythonEdge;
struct state_t // this is the main graph
{ shared_ptr<multigraph_t> _mg;
// 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;
// vertex index map // vertex index map
vertex_index_map_t _vertex_index; vertex_index_map_t _vertex_index;
......
This diff is collapsed.
...@@ -87,7 +87,7 @@ struct do_graph_copy ...@@ -87,7 +87,7 @@ struct do_graph_copy
void operator()(const GraphSrc& src, GraphTgt& tgt, void operator()(const GraphSrc& src, GraphTgt& tgt,
TgtVertexIndexMap src_vertex_index, TgtVertexIndexMap src_vertex_index,
SrcVertexIndexMap tgt_vertex_index, SrcVertexIndexMap tgt_vertex_index,
TgtEdgeIndexMap src_edge_index, TgtEdgeIndexMap,
SrcEdgeIndexMap tgt_edge_index, 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> > >& vprops,
vector<pair<reference_wrapper<boost::any>,reference_wrapper<boost::any> > >& eprops) const vector<pair<reference_wrapper<boost::any>,reference_wrapper<boost::any> > >& eprops) const
...@@ -108,7 +108,6 @@ struct do_graph_copy ...@@ -108,7 +108,6 @@ struct do_graph_copy
src, tgt, tgt_vertex_index); src, tgt, tgt_vertex_index);
} }
size_t e_idx = 0;
typename graph_traits<GraphSrc>::edge_iterator e, e_end; typename graph_traits<GraphSrc>::edge_iterator e, e_end;
for (tie(e, e_end) = edges(src); e != e_end; ++e) for (tie(e, e_end) = edges(src); e != e_end; ++e)
{ {
...@@ -116,8 +115,6 @@ struct do_graph_copy ...@@ -116,8 +115,6 @@ struct do_graph_copy
size_t t = index_map[src_vertex_index[target(*e, src)]]; size_t t = index_map[src_vertex_index[target(*e, src)]];
typedef typename graph_traits<GraphTgt>::edge_descriptor edge_t; typedef typename graph_traits<GraphTgt>::edge_descriptor edge_t;
edge_t new_e = add_edge(vertex(s,tgt), vertex(t,tgt), tgt).first; 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) for (size_t i = 0; i < eprops.size(); ++i)
copy_property<writable_edge_properties> copy_property<writable_edge_properties>
...@@ -130,9 +127,9 @@ struct do_graph_copy ...@@ -130,9 +127,9 @@ struct do_graph_copy
// copy constructor // copy constructor
GraphInterface::GraphInterface(const GraphInterface& gi, bool keep_ref, GraphInterface::GraphInterface(const GraphInterface& gi, bool keep_ref,
python::object ovprops, python::object oeprops) python::object ovprops, python::object oeprops)
:_state(keep_ref ? gi._state : shared_ptr<state_t>(new state_t())), :_mg(keep_ref ? gi._mg : shared_ptr<multigraph_t>(new multigraph_t())),
_vertex_index(get(vertex_index, _state->_mg)), _vertex_index(get(vertex_index, *_mg)),
_edge_index(get(edge_index_t(), _state->_mg)), _edge_index(get(edge_index_t(), *_mg)),
_reversed(gi._reversed), _reversed(gi._reversed),
_directed(gi._directed), _directed(gi._directed),
_vertex_filter_map(_vertex_index), _vertex_filter_map(_vertex_index),
...@@ -160,13 +157,9 @@ GraphInterface::GraphInterface(const GraphInterface& gi, bool keep_ref, ...@@ -160,13 +157,9 @@ GraphInterface::GraphInterface(const GraphInterface& gi, bool keep_ref,
run_action<>() run_action<>()
(const_cast<GraphInterface&>(gi), (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._vertex_index, _vertex_index,
gi._edge_index, _edge_index, ref(vprops), gi._edge_index, _edge_index, ref(vprops),
ref(eprops)))(); 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 // filters will be copied in python
} }
...@@ -137,7 +137,7 @@ check_filtered(const Graph &g, const EdgeFilter& edge_filter, ...@@ -137,7 +137,7 @@ check_filtered(const Graph &g, const EdgeFilter& edge_filter,
if (e_active) if (e_active)
{ {
if (max_eindex > 0) if (max_eindex > 0)
edge_filter.reserve(max_eindex+1); edge_filter.reserve(max_eindex);
if (v_active) if (v_active)
{ {
if (num_vertices(g) > 0) if (num_vertices(g) > 0)
...@@ -186,11 +186,9 @@ check_filtered(const Graph &g, const EdgeFilter& edge_filter, ...@@ -186,11 +186,9 @@ check_filtered(const Graph &g, const EdgeFilter& edge_filter,
// gets the correct graph view at run time // gets the correct graph view at run time
boost::any GraphInterface::GetGraphView() const boost::any GraphInterface::GetGraphView() const
{ {
// TODO: implement memoization
boost::any graph = boost::any graph =
check_filtered(_state->_mg, _edge_filter_map, _edge_filter_invert, check_filtered(*_mg, _edge_filter_map, _edge_filter_invert,
_edge_filter_active, _state->_max_edge_index, _edge_filter_active, _mg->get_last_index(),
_vertex_filter_map, _vertex_filter_invert, _vertex_filter_map, _vertex_filter_invert,
_vertex_filter_active, _vertex_filter_active,
const_cast<vector<boost::any>&>(_graph_views), _reversed, const_cast<vector<boost::any>&>(_graph_views), _reversed,
...@@ -210,13 +208,7 @@ bool GraphInterface::IsEdgeFilterActive() const ...@@ -210,13 +208,7 @@ bool GraphInterface::IsEdgeFilterActive() const
// found // found
void GraphInterface::ReIndexEdges() void GraphInterface::ReIndexEdges()
{ {
size_t index = 0; _mg->reindex_edges();
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();
} }
// this will definitively remove all the edges from the graph, which are being // this will definitively remove all the edges from the graph, which are being
...@@ -230,14 +222,14 @@ void GraphInterface::PurgeEdges() ...@@ -230,14 +222,14 @@ void GraphInterface::PurgeEdges()
graph_traits<multigraph_t>::vertex_iterator v, v_end; graph_traits<multigraph_t>::vertex_iterator v, v_end;
graph_traits<multigraph_t>::out_edge_iterator e, e_end; graph_traits<multigraph_t>::out_edge_iterator e, e_end;
vector<graph_traits<multigraph_t>::edge_descriptor> deleted_edges; 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)) if (!filter(*e))
deleted_edges.push_back(*e); deleted_edges.push_back(*e);
for (typeof(deleted_edges.begin()) iter = deleted_edges.begin(); for (typeof(deleted_edges.begin()) iter = deleted_edges.begin();
iter != deleted_edges.end(); ++iter) iter != deleted_edges.end(); ++iter)
RemoveEdgeIndex(*iter); remove_edge(*iter, *_mg);
deleted_edges.clear(); deleted_edges.clear();
} }
} }
...@@ -257,10 +249,10 @@ void GraphInterface::PurgeVertices(boost::any aold_index) ...@@ -257,10 +249,10 @@ void GraphInterface::PurgeVertices(boost::any aold_index)
MaskFilter<vertex_filter_t> filter(_vertex_filter_map, MaskFilter<vertex_filter_t> filter(_vertex_filter_map,
_vertex_filter_invert); _vertex_filter_invert);
size_t N = num_vertices(_state->_mg); size_t N = num_vertices(*_mg);
vector<bool> deleted(N, false); vector<bool> deleted(N, false);
for (size_t i = 0; i < N; ++i) 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<int> old_indexes;
vector<graph_traits<multigraph_t>::edge_descriptor> edges; vector<graph_traits<multigraph_t>::edge_descriptor> edges;
...@@ -271,22 +263,8 @@ void GraphInterface::PurgeVertices(boost::any aold_index) ...@@ -271,22 +263,8 @@ void GraphInterface::PurgeVertices(boost::any aold_index)
if (deleted[i]) if (deleted[i])
{ {
graph_traits<multigraph_t>::vertex_descriptor v = graph_traits<multigraph_t>::vertex_descriptor v =
vertex(i, _state->_mg); vertex(i, *_mg);
graph_traits<multigraph_t>::out_edge_iterator e, e_end; remove_vertex(v, *_mg);
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();
} }
else else
{ {
...@@ -297,7 +275,7 @@ void GraphInterface::PurgeVertices(boost::any aold_index) ...@@ -297,7 +275,7 @@ void GraphInterface::PurgeVertices(boost::any aold_index)
N = old_indexes.size(); N = old_indexes.size();
for (int i = N-1; i >= 0; --i) 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) ...@@ -338,4 +316,3 @@ void GraphInterface::SetEdgeFilterProperty(boost::any property, bool invert)
_edge_filter_active = false; _edge_filter_active = false;