Commit 80692ffd authored by Tiago Peixoto's avatar Tiago Peixoto

Improve underlying adjacency list implementation

This changes the underlying adjacency matrix implementation to a single
mixed in + out edge list for each node, instead of separate ones. This
simplifies the undirected_adaptor<> so that its out-edge iterators
become trivial, and also faster.
parent 7f73bc97
This diff is collapsed.
......@@ -314,15 +314,6 @@ and :meth:`~graph_tool.Vertex.in_neighbours` methods, respectively.
The code above will print the out-edges and out-neighbours of all
vertices in the graph.
.. note::
The ordering of the vertices and edges visited by the iterators is
always the same as the order in which they were added to the graph
(with the exception of the iterator returned by
:meth:`~graph_tool.Graph.edges`). Usually, algorithms do not care
about this order, but if it is ever needed, this inherent ordering
can be relied upon.
.. warning::
You should never remove vertex or edge descriptors when iterating
......
This diff is collapsed.
This diff is collapsed.
......@@ -58,6 +58,7 @@ libgraph_tool_core_la_include_HEADERS = \
graph_adjacency.hh \
graph_adaptor.hh \
graph_exceptions.hh \
graph_filtered.hh \
graph_filtering.hh \
graph_io_binary.hh \
graph_properties.hh \
......@@ -65,6 +66,7 @@ libgraph_tool_core_la_include_HEADERS = \
graph_properties_group.hh \
graph_properties_map_values.hh \
graph_python_interface.hh \
graph_reverse.hh \
graph_selectors.hh \
graph_tool.hh \
graph_util.hh \
......@@ -81,7 +83,6 @@ libgraph_tool_core_la_workarounddir = $(MOD_DIR)/include/boost-workaround/boost/
libgraph_tool_core_la_workaround_HEADERS = \
../boost-workaround/boost/graph/betweenness_centrality.hpp \
../boost-workaround/boost/graph/detail/read_graphviz_new.hpp \
../boost-workaround/boost/graph/filtered_graph.hpp \
../boost-workaround/boost/graph/graphml.hpp \
../boost-workaround/boost/graph/graphviz.hpp \
../boost-workaround/boost/graph/isomorphism.hpp \
......@@ -91,7 +92,6 @@ libgraph_tool_core_la_workaround_HEADERS = \
../boost-workaround/boost/graph/overloading.hpp \
../boost-workaround/boost/graph/push_relabel_max_flow.hpp \
../boost-workaround/boost/graph/copy_alt.hpp \
../boost-workaround/boost/graph/reverse_graph_alt.hpp \
../boost-workaround/boost/graph/stoer_wagner_min_cut.hpp
libgraph_tool_core_la_LIBADD = $(MOD_LIBADD)
......
......@@ -130,7 +130,7 @@ struct get_trust_transitivity
source_map[boost::source(*e,g)] = true;
// filter vertex w out of the graph
typedef filtered_graph<Graph, boost::keep_all, filter_vertex_pred>
typedef filt_graph<Graph, boost::keep_all, filter_vertex_pred>
fg_t;
fg_t fg(g, boost::keep_all(), filter_vertex_pred(tgt));
......@@ -183,7 +183,7 @@ struct get_trust_transitivity
{
typedef typename
mpl::if_<typename is_directed::apply<Graph>::type,
reverse_graph<fg_t>,
reversed_graph<fg_t>,
fg_t>::type rg_t;
rg_t rg(fg);
dist_map_t sum_w(vertex_index, num_vertices(g));
......
......@@ -150,7 +150,7 @@ struct set_clustering_to_property
typedef typename mpl::if_
<std::is_convertible<typename graph_traits<Graph>::directed_category,
directed_tag>,
const UndirectedAdaptor<Graph>,
const undirected_adaptor<Graph>,
const Graph& >::type type;
};
};
......
......@@ -119,7 +119,7 @@ struct get_extended_clustering
{
// We must disconsider paths through the original vertex
typedef single_vertex_filter<vertex_t> filter_t;
typedef filtered_graph<Graph, keep_all, filter_t> fg_t;
typedef filt_graph<Graph, keep_all, filter_t> fg_t;
fg_t fg(g, keep_all(), filter_t(v));
typedef DescriptorHash<IndexMap> hasher_t;
......
......@@ -252,14 +252,14 @@ bool graph_cmp(Graph& g1, Graph& g2)
// short hand for subgraph types
typedef boost::adj_list<size_t> d_graph_t;
// we need this wrap to use the UndirectedAdaptor only on directed graphs
// we need this wrap to use the undirected_adaptor only on directed graphs
struct wrap_undirected
{
template <class Graph>
struct apply
{
typedef typename mpl::if_<typename is_directed::apply<Graph>::type,
boost::UndirectedAdaptor<Graph>,
boost::undirected_adaptor<Graph>,
Graph&>::type type;
};
};
......@@ -271,7 +271,7 @@ struct wrap_directed
{
typedef typename mpl::if_<typename is_directed::apply<Graph>::type,
Sub&,
boost::UndirectedAdaptor<Sub>>::type type;
boost::undirected_adaptor<Sub>>::type type;
};
};
......
......@@ -174,7 +174,7 @@ void graph_path(Graph& g, size_t s, size_t t, vector<size_t>& path)
cpred;
auto pred = cpred.get_unchecked(num_vertices(g));
UndirectedAdaptor<Graph> ug(g);
undirected_adaptor<Graph> ug(g);
boost::breadth_first_search(ug, s,
boost::visitor(
......
......@@ -56,7 +56,7 @@ double min_cut(GraphInterface& gi, boost::any weight, boost::any part_map)
weight_maps;
run_action<graph_tool::detail::never_directed>()
(gi, std::bind(get_min_cut(), std::placeholders::_1, std::placeholders::_2,
(gi, std::bind(get_min_cut(), std::placeholders::_1, std::placeholders::_2,
std::placeholders::_3, std::ref(mc)),
weight_maps(), writable_vertex_scalar_properties())(weight, part_map);
return mc;
......
......@@ -78,7 +78,7 @@ using namespace graph_tool;
void triangulation(GraphInterface& gi, boost::python::object points,
boost::any pos, string type, bool periodic)
{
UndirectedAdaptor<GraphInterface::multigraph_t> g(gi.get_graph());
undirected_adaptor<GraphInterface::multigraph_t> g(gi.get_graph());
multi_array_ref<double,2> points_array = get_array<double,2>(points);
typedef property_map_type::apply
<vector<double>, GraphInterface::vertex_index_map_t>::type pos_type_t;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -50,40 +50,6 @@ graph_tool::ActionNotFound::ActionNotFound(const type_info& action,
}
}
// this will check whether a graph is reversed and return the proper view
// encapsulated
template <class Graph>
boost::any check_reverse(const Graph& g, bool reverse, GraphInterface& gi)
{
if (reverse)
{
typedef typename boost::mpl::if_<std::is_const<Graph>,
const reverse_graph<typename std::remove_const<Graph>::type>,
reverse_graph<Graph> >::type
reverse_graph_t;
reverse_graph_t rg(g);
return std::ref(*retrieve_graph_view(gi, rg));
}
return boost::any(std::ref(const_cast<Graph&>(g)));
};
// this will check whether a graph is directed and return the proper view
// encapsulated
template <class Graph>
boost::any check_directed(const Graph &g, bool reverse, bool directed,
GraphInterface& gi)
{
if (directed)
{
return check_reverse(g, reverse, gi);
}
typedef UndirectedAdaptor<Graph> ug_t;
ug_t ug(g);
return std::ref(*retrieve_graph_view(gi, ug));
};
// this will check whether a graph is filtered and return the proper view
// encapsulated
......@@ -94,37 +60,71 @@ check_filtered(const Graph& g, const EdgeFilter& edge_filter,
const VertexFilter& vertex_filter, const bool& v_invert,
bool v_active, GraphInterface& gi, bool reverse, bool directed)
{
#ifndef NO_GRAPH_FILTERING
if (e_active || v_active)
{
MaskFilter<EdgeFilter>
e_filter(const_cast<EdgeFilter&>(edge_filter),
const_cast<bool&>(e_invert));
MaskFilter<VertexFilter>
v_filter(const_cast<VertexFilter&>(vertex_filter),
const_cast<bool&>(v_invert));
if (max_eindex > 0)
edge_filter.reserve(max_eindex);
if (num_vertices(g) > 0)
vertex_filter.reserve(num_vertices(g));
typedef filtered_graph<Graph, MaskFilter<EdgeFilter>,
MaskFilter<VertexFilter> > fg_t;
fg_t init(g, e_filter, v_filter);
fg_t& fg = *retrieve_graph_view(gi, init);
return check_directed(fg, reverse, directed, gi);
}
else
{
return check_directed(g, reverse, directed, gi);
}
auto check_filt = [&](auto&& u) -> boost::any
{
typedef typename std::remove_const<
typename std::remove_reference<decltype(u)>::type>::type g_t;
#ifndef NO_GRAPH_FILTERING
if (e_active || v_active)
{
MaskFilter<EdgeFilter>
e_filter(const_cast<EdgeFilter&>(edge_filter),
const_cast<bool&>(e_invert));
MaskFilter<VertexFilter>
v_filter(const_cast<VertexFilter&>(vertex_filter),
const_cast<bool&>(v_invert));
if (max_eindex > 0)
edge_filter.reserve(max_eindex);
if (num_vertices(g) > 0)
vertex_filter.reserve(num_vertices(g));
typedef filt_graph<g_t,
MaskFilter<EdgeFilter>,
MaskFilter<VertexFilter>> fg_t;
fg_t init(u, e_filter, v_filter);
fg_t& fg = *retrieve_graph_view(gi, init);
return std::ref(fg);
}
else
{
return std::ref(const_cast<g_t&>(u));
}
#else
return check_directed(g, reverse, directed, gi);
return std::ref(const_cast<g_t&>(u));
#endif
};
auto check_reverse = [&](auto&& u) -> boost::any
{
typedef typename std::remove_const<
typename std::remove_reference<decltype(u)>::type>::type g_t;
if (reverse)
{
typedef typename
std::conditional<std::is_const<g_t>::value,
const reversed_graph<typename std::remove_const<g_t>::type>,
reversed_graph<g_t> >::type
reversed_graph_t;
reversed_graph_t rg(u);
return check_filt(*retrieve_graph_view(gi, rg));
}
return check_filt(u);
};
auto check_directed = [&](auto&& u) -> boost::any
{
typedef typename std::remove_const<
typename std::remove_reference<decltype(u)>::type>::type g_t;
if (directed)
return check_reverse(u);
typedef undirected_adaptor<g_t> ug_t;
ug_t ug(u);
return check_filt(*retrieve_graph_view(gi, ug));
};
return check_directed(g);
}
// gets the correct graph view at run time
......@@ -212,10 +212,8 @@ void GraphInterface::purge_vertices(boost::any aold_index)
}
N = old_indexes.size();
for (int i = N-1; i >= 0; --i)
{
for (int64_t i = N-1; i >= 0; --i)
old_index[vertex((N - 1) - i, *_mg)] = old_indexes[i];
}
}
void GraphInterface::set_vertex_filter_property(boost::any property, bool invert)
......
......@@ -21,8 +21,6 @@
#include "graph.hh"
#include <boost/version.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/filtered_graph.hpp>
#include <boost/graph/reverse_graph_alt.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/erase.hpp>
#include <boost/mpl/clear.hpp>
......@@ -46,6 +44,8 @@
#include <boost/mpl/print.hpp>
#include "graph_adaptor.hh"
#include "graph_filtered.hh"
#include "graph_reverse.hh"
#include "graph_selectors.hh"
#include "graph_util.hh"
#include "mpl_nested_loop.hh"
......@@ -188,9 +188,9 @@ struct graph_filter
typedef typename get_predicate<EdgeProperty>::type edge_predicate;
typedef typename get_predicate<VertexProperty>::type vertex_predicate;
typedef boost::filtered_graph<Graph,
edge_predicate,
vertex_predicate> filtered_graph_t;
typedef boost::filt_graph<Graph,
edge_predicate,
vertex_predicate> filtered_graph_t;
// If both predicates are keep_all, then return the original graph
// type. Otherwise return the filtered_graph type.
......@@ -212,7 +212,7 @@ struct graph_undirect
template <class Graph>
struct apply
{
typedef boost::UndirectedAdaptor<Graph> type;
typedef boost::undirected_adaptor<Graph> type;
};
};
......@@ -222,7 +222,7 @@ struct graph_reverse
template <class Graph>
struct apply
{
typedef boost::reverse_graph<Graph> type;
typedef boost::reversed_graph<Graph> type;
};
};
......@@ -241,24 +241,23 @@ struct get_property_map_type<boost::keep_all, IndexMap>
typedef boost::keep_all type;
};
// this metafunction returns a filtered graph type, given the scalar types to be
// used in the property maps
// this metafunction returns a filtered graph type
struct get_graph_filtered
{
template <class Scalar>
template <class Graph>
struct apply
{
// if the 'scalar' is the index map itself, use simply that, otherwise
// get the specific property map
typedef typename get_property_map_type<
Scalar,
uint8_t,
GraphInterface::edge_index_map_t>::type edge_property_map;
typedef typename get_property_map_type<
Scalar,
uint8_t,
GraphInterface::vertex_index_map_t>::type vertex_property_map;
typedef typename graph_filter::apply<GraphInterface::multigraph_t,
typedef typename graph_filter::apply<Graph,
edge_property_map,
vertex_property_map>::type type;
};
......@@ -275,46 +274,56 @@ struct get_all_graph_views
class NeverFiltered = boost::mpl::bool_<false> >
struct apply
{
// filtered graphs
struct filtered_graphs:
boost::mpl::if_<NeverFiltered,
boost::mpl::vector1<GraphInterface::multigraph_t>,
boost::mpl::vector2<GraphInterface::multigraph_t,
typename get_graph_filtered::apply<FiltType>::type>
>::type {};
// filtered + reversed graphs
struct base_graphs:
boost::mpl::vector1<GraphInterface::multigraph_t> {};
// reversed graphs
struct reversed_graphs:
boost::mpl::if_<AlwaysReversed,
typename boost::mpl::transform<filtered_graphs,
typename boost::mpl::transform<base_graphs,
graph_reverse>::type,
typename boost::mpl::if_<
NeverReversed,
filtered_graphs,
base_graphs,
typename boost::mpl::transform<
filtered_graphs,
base_graphs,
graph_reverse,
boost::mpl::back_inserter<filtered_graphs>
boost::mpl::back_inserter<base_graphs>
>::type
>::type
>::type {};
// undirected + filtereed + reversed graphs
// undirected graphs
struct undirected_graphs:
boost::mpl::if_<AlwaysDirected,
reversed_graphs,
typename boost::mpl::if_<
NeverDirected,
typename boost::mpl::transform<filtered_graphs,
graph_undirect>::type,
typename boost::mpl::transform<
filtered_graphs,
base_graphs,
graph_undirect,
boost::mpl::back_inserter<boost::mpl::vector0<>>
>::type,
typename boost::mpl::transform<
base_graphs,
graph_undirect,
boost::mpl::back_inserter<reversed_graphs>
>::type
>::type
>::type {};
typedef undirected_graphs type;
// filtered graphs
struct filtered_graphs:
boost::mpl::if_<NeverFiltered,
undirected_graphs,
typename boost::mpl::transform<
undirected_graphs,
get_graph_filtered,
boost::mpl::back_inserter<undirected_graphs>>::type
>::type {};
typedef filtered_graphs type;
};
};
......@@ -540,59 +549,55 @@ retrieve_graph_view(GraphInterface& gi, Graph& init)
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
add_vertex(boost::filt_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 v = add_vertex(const_cast<Graph&>(g._g));
auto& filt = g._vertex_pred.get_filter();
auto cfilt = filt.get_checked();
cfilt[v] = !g.m_vertex_pred.is_inverted();
cfilt[v] = !g._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
add_edge(Vertex s, Vertex t, filt_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 e = add_edge(s, t, const_cast<Graph&>(g._g));
auto& filt = g._edge_pred.get_filter();
auto cfilt = filt.get_checked();
cfilt[e.first] = !g.m_edge_pred.is_inverted();
cfilt[e.first] = !g._edge_pred.is_inverted();
return e;
}
// Used to skip filtered vertices
template <class Graph, class EdgePred, class VertexPred, class Vertex>
bool is_valid_vertex(Vertex v, const boost::filtered_graph<Graph,EdgePred,VertexPred>&)
template <class Graph, class EP, class VP, class Vertex>
bool is_valid_vertex(Vertex v, const boost::filt_graph<Graph,EP,VP>&)
{
return v != graph_traits<boost::filtered_graph<Graph,EdgePred, VertexPred>>::null_vertex();
return v != graph_traits<boost::filt_graph<Graph,EP,VP>>::null_vertex();
}
template <class Graph, class Vertex>
bool is_valid_vertex(Vertex, const Graph&)
bool is_valid_vertex(Vertex v, const boost::reversed_graph<Graph>& g)
{
return true;
return is_valid_vertex(v, g._g);
}
template <class Graph, class Vertex>
bool is_valid_vertex(Vertex v, const boost::reverse_graph<Graph>& g)
bool is_valid_vertex(Vertex v, const boost::undirected_adaptor<Graph>& g)
{
return is_valid_vertex(v, g.m_g);
return is_valid_vertex(v, g.original_graph());
}
template <class Graph, class Vertex>
bool is_valid_vertex(Vertex v, const boost::UndirectedAdaptor<Graph>& g)
bool is_valid_vertex(Vertex, const Graph&)
{
return is_valid_vertex(v, g.original_graph());
return true;
}
......
......@@ -275,58 +275,6 @@ struct create_dynamic_map
EdgeIndexMap _edge_map;
};
// this graph wraps an UndirectedAdaptor, but overrides the underlying
// edge_descriptor type with the original type. This will make the edge property
// maps compatible with the original graph, but will break some things which
// are not relevant here
template <class Graph>
struct FakeUndirGraph: public UndirectedAdaptor<Graph>
{
FakeUndirGraph(const Graph &g): UndirectedAdaptor<Graph>(g) {}
FakeUndirGraph(UndirectedAdaptor<Graph> &g): UndirectedAdaptor<Graph>(g) {}
};
template <class Graph>
struct FakeEdgeIterator:
public graph_traits<UndirectedAdaptor<Graph> >::edge_iterator
{
typedef typename graph_traits<FakeUndirGraph<Graph> >::edge_descriptor
edge_descriptor;
typedef typename graph_traits<UndirectedAdaptor<Graph> >::edge_iterator
edge_iterator;
FakeEdgeIterator(){}
FakeEdgeIterator(edge_iterator e): edge_iterator(e) {}
edge_descriptor operator*() const
{
return edge_descriptor(*edge_iterator(*this));
}
};
namespace boost {
template <class Graph>
struct graph_traits<FakeUndirGraph<Graph> >
: public graph_traits<UndirectedAdaptor<Graph> >
{
typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
typedef FakeEdgeIterator<Graph> edge_iterator;
};
template <class Graph>
std::pair<FakeEdgeIterator<Graph>,
FakeEdgeIterator<Graph>> edges(const FakeUndirGraph<Graph>& g)
{
auto e = edges(UndirectedAdaptor<Graph>(g));
return std::make_pair(FakeEdgeIterator<Graph>(e.first),
FakeEdgeIterator<Graph>(e.second));
}
}
//==============================================================================
// read_from_file(file, pfile, format)
//==============================================================================
......@@ -488,18 +436,6 @@ struct do_write_to_file
}
};
struct do_write_to_file_fake_undir: public do_write_to_file
{
template <class Graph, class IndexMap>
void operator()(ostream& stream, Graph& g, IndexMap index_map,
dynamic_properties& dp, const string& format) const
{
typedef typename Graph::original_graph_t graph_t;
FakeUndirGraph<graph_t> ug(g);
do_write_to_file(*this)(stream, ug, index_map, dp, format);
}
};
struct do_write_to_binary_file
{
template <class Graph, class IndexMap>
......@@ -633,35 +569,22 @@ void GraphInterface::write_to_file(string file, boost::python::object pfile,
if (format == "dot")
graphviz_insert_index(dp, index_map);
if (get_directed())
run_action<detail::always_directed>()
(*this, boost::bind<void>(do_write_to_file(),
boost::ref(stream), _1,
index_map, boost::ref(dp),
format))();
else
run_action<detail::never_directed>()