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;
// this is the main graph
shared_ptr<multigraph_t> _mg;
// vertex index map
vertex_index_map_t _vertex_index;
......
#ifndef GRAPH_ADJACENCY_HH
#define GRAPH_ADJACENCY_HH
#include <vector>
#include <deque>
#include <utility>
#include <numeric>
#include <iostream>
#include <boost/iterator.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/range/irange.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/graph/properties.hpp>
#include <boost/iterator/transform_iterator.hpp>
#include <boost/iterator/iterator_facade.hpp>
#include "tr1_include.hh"
#include TR1_HEADER(tuple)
namespace boost
{
// ========================================================================
// Forward declarations
// ========================================================================
template <class Vertex>
class adj_list;
// forward declaration of manipulation functions
template <class Vertex>
std::pair<typename adj_list<Vertex>::vertex_iterator,
typename adj_list<Vertex>::vertex_iterator>
vertices(const adj_list<Vertex>& g);
template <class Vertex>
std::pair<typename adj_list<Vertex>::edge_iterator,
typename adj_list<Vertex>::edge_iterator>
edges(const adj_list<Vertex>& g);
template <class Vertex>
std::pair<typename adj_list<Vertex>::edge_iterator, bool>
edge(Vertex s, Vertex t, const adj_list<Vertex>& g);
template <class Vertex>
size_t out_degree(Vertex v, const adj_list<Vertex>& g);
template <class Vertex>
size_t in_degree(Vertex v, const adj_list<Vertex>& g);
template <class Vertex>
std::pair<typename adj_list<Vertex>::out_edge_iterator,
typename adj_list<Vertex>::out_edge_iterator>
out_edges(Vertex v, const adj_list<Vertex>& g);
template <class Vertex>
std::pair<typename adj_list<Vertex>::in_edge_iterator,
typename adj_list<Vertex>::in_edge_iterator>
in_edges(Vertex v, const adj_list<Vertex>& g);
template <class Vertex>
std::pair<typename adj_list<Vertex>::adjacency_iterator,
typename adj_list<Vertex>::adjacency_iterator>
adjacent_vertices(Vertex v, const adj_list<Vertex>& g);
template <class Vertex>
size_t num_vertices(const adj_list<Vertex>& g);
template <class Vertex>
size_t num_edges(const adj_list<Vertex>& g);
template <class Vertex>
Vertex add_vertex(adj_list<Vertex>& g);
template <class Vertex>
void clear_vertex(Vertex v, adj_list<Vertex>& g);
template <class Vertex>
void remove_vertex(Vertex v, adj_list<Vertex>& g);
template <class Vertex>
std::pair<typename adj_list<Vertex>::edge_descriptor, bool>
add_edge(Vertex s, Vertex t, adj_list<Vertex>& g);
template <class Vertex>
void remove_edge(Vertex s, Vertex t, adj_list<Vertex>& g);
template <class Vertex>
void remove_edge(const typename adj_list<Vertex>::edge_descriptor& e,
adj_list<Vertex>& g);
// ========================================================================
// adj_list<Vertex>
// ========================================================================
//
// adj_list is a very simple adjacency list implementation for bidirectional
// graphs based on std::vector, meant to be reasonably efficient both
// memory-wise and computationally. It maintains a list of in and out-edges for
// each vertex, and each edge has a built-in index (which is replicated in both
// lists). For each edge, a total of 4 integers is necessary: the source and
// target vertices, in the in_edges and out_edges lists, respectively, and the
// (same) edge index in both lists. The integer type is given by the Vertex
// template parameter. It achieves about half as much memory as
// boost::adjacency_list with an edge index property map and the same integer
// type.
// The complexity guarantees and iterator invalidation rules are the same as
// boost::adjacency_list with vector storage selectors for both vertex and edge
// lists.
template <class Vertex = size_t>
class adj_list
{
public:
struct graph_tag {};
typedef Vertex vertex_t;
typedef std::tr1::tuple<vertex_t, vertex_t, vertex_t> edge_descriptor;
typedef std::vector<std::pair<vertex_t, vertex_t> > edge_list_t;
typedef typename integer_range<Vertex>::iterator vertex_iterator;
struct get_vertex
{
get_vertex() {}
typedef Vertex result_type;
Vertex operator()(const std::pair<vertex_t, vertex_t>& v) const
{ return v.first; }
};
typedef transform_iterator<get_vertex, typename edge_list_t::const_iterator>
adjacency_iterator;
struct make_out_edge
{
make_out_edge(vertex_t src): _src(src) {}
make_out_edge() {}
vertex_t _src;
typedef edge_descriptor result_type;
edge_descriptor operator()(const std::pair<vertex_t, vertex_t>& v) const
{ return std::tr1::make_tuple(_src, v.first, v.second); }
};
struct make_in_edge
{
make_in_edge(vertex_t tgt): _tgt(tgt) {}
make_in_edge() {}
vertex_t _tgt;
typedef edge_descriptor result_type;
edge_descriptor operator()(const std::pair<vertex_t, vertex_t>& v) const
{ return std::tr1::make_tuple(v.first, _tgt, v.second); }
};
typedef transform_iterator<make_out_edge, typename edge_list_t::const_iterator>
out_edge_iterator;
typedef transform_iterator<make_in_edge, typename edge_list_t::const_iterator>
in_edge_iterator;
class edge_iterator:
public boost::iterator_facade<edge_iterator,
edge_descriptor,
boost::forward_traversal_tag,
edge_descriptor>
{
public:
edge_iterator() {}
explicit edge_iterator(const typename std::vector<edge_list_t>::const_iterator& vi_begin,
const typename std::vector<edge_list_t>::const_iterator& vi_end,
const typename std::vector<edge_list_t>::const_iterator& vi,
const typename edge_list_t::const_iterator& ei)
: _vi_begin(vi_begin), _vi_end(vi_end), _vi(vi), _ei(ei)
{
// move position to first edge
skip();
}
private:
friend class boost::iterator_core_access;
void skip()
{
//skip empty vertices
while (_vi != _vi_end && _ei == _vi->end())
{
++_vi;
if (_vi != _vi_end)
_ei = _vi->begin();
}
}
void increment()
{
++_ei;
skip();
}
bool equal(edge_iterator const& other) const
{
if (_vi_begin == _vi_end)
return _vi == other._vi;
return _vi == other._vi && _ei == other._ei;
}
edge_descriptor dereference() const
{
return std::tr1::make_tuple(vertex_t(_vi - _vi_begin),
_ei->first, _ei->second);
}
typename std::vector<edge_list_t>::const_iterator _vi_begin;
typename std::vector<edge_list_t>::const_iterator _vi_end;
typename std::vector<edge_list_t>::const_iterator _vi;
typename edge_list_t::const_iterator _ei;
};
void reindex_edges()
{
_free_indexes.clear();
_last_idx = 0;
_in_edges.clear();
_in_edges.resize(_out_edges.size());
for (size_t i = 0; i < _out_edges.size(); ++i)
for (size_t j = 0; j < _out_edges[i].size(); ++j)
{
Vertex v = _out_edges[i][j].first;
_out_edges[i][j].second = _last_idx;
_in_edges[v].push_back(std::make_pair(Vertex(i),
_last_idx));
_last_idx++;
}
}
size_t get_last_index() const {return _last_idx;}
private:
typedef std::vector<edge_list_t> vertex_list_t;
vertex_list_t _out_edges;
vertex_list_t _in_edges;
size_t _n_edges;
size_t _last_idx;
std::deque<size_t> _free_indexes; // indexes of deleted edges to be used up
// for new edges to avoid very large
// indexes, and unnecessary property map
// memory use
// manipulation functions
friend std::pair<vertex_iterator, vertex_iterator>
vertices<>(const adj_list<Vertex>& g);
friend std::pair<edge_iterator, edge_iterator>
edges<>(const adj_list<Vertex>& g);
friend std::pair<edge_iterator, bool>
edge<>(Vertex s, Vertex t, const adj_list<Vertex>& g);
friend size_t out_degree<>(Vertex v, const adj_list<Vertex>& g);
friend size_t in_degree<>(Vertex v, const adj_list<Vertex>& g);
friend std::pair<out_edge_iterator, out_edge_iterator>
out_edges<>(Vertex v, const adj_list<Vertex>& g);
friend std::pair<in_edge_iterator, in_edge_iterator>
in_edges<>(Vertex v, const adj_list<Vertex>& g);
friend std::pair<adjacency_iterator, adjacency_iterator>
adjacent_vertices<>(Vertex v, const adj_list<Vertex>& g);
friend size_t num_vertices<>(const adj_list<Vertex>& g);
friend size_t num_edges<>(const adj_list<Vertex>& g);
friend Vertex add_vertex<>(adj_list<Vertex>& g);
friend void clear_vertex<>(Vertex v, adj_list<Vertex>& g);
friend void remove_vertex<>(Vertex v, adj_list<Vertex>& g);
friend std::pair<edge_descriptor, bool>
add_edge<>(Vertex s, Vertex t, adj_list<Vertex>& g);
friend void remove_edge<>(Vertex s, Vertex t, adj_list<Vertex>& g);
friend void remove_edge<>(const edge_descriptor& e, adj_list<Vertex>& g);
};
//========================================================================
// Graph traits and BGL scaffolding
//========================================================================
struct adj_list_traversal_tag
: public vertex_list_graph_tag,
public edge_list_graph_tag,
public adjacency_graph_tag,
public bidirectional_graph_tag { };
template <class Vertex>
struct graph_traits<adj_list<Vertex> >
{
typedef Vertex vertex_descriptor;
typedef typename adj_list<Vertex>::edge_descriptor edge_descriptor;
typedef typename adj_list<Vertex>::edge_iterator edge_iterator;
typedef typename adj_list<Vertex>::adjacency_iterator adjacency_iterator;
typedef typename adj_list<Vertex>::out_edge_iterator out_edge_iterator;
typedef typename adj_list<Vertex>::in_edge_iterator in_edge_iterator;
typedef typename adj_list<Vertex>::vertex_iterator vertex_iterator;
typedef bidirectional_tag directed_category;
typedef allow_parallel_edge_tag edge_parallel_category;
typedef adj_list_traversal_tag traversal_category;
typedef Vertex vertices_size_type;
typedef Vertex edges_size_type;
typedef size_t degree_size_type;
static Vertex null_vertex() { return std::numeric_limits<Vertex>::max(); }
};
template <class Vertex>
struct graph_traits<const adj_list<Vertex> >
: public graph_traits<adj_list<Vertex> >
{
};
template <class Vertex>
struct edge_property_type<adj_list<Vertex> >
{
typedef void type;