//======================================================================= | |
// Copyright 1997, 1998, 1999, 2000 University of Notre Dame. | |
// Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek | |
// | |
// Distributed under the Boost Software License, Version 1.0. (See | |
// accompanying file LICENSE_1_0.txt or copy at | |
// http://www.boost.org/LICENSE_1_0.txt) | |
//======================================================================= | |
#ifndef BOOST_FILTERED_GRAPH_HPP | |
#define BOOST_FILTERED_GRAPH_HPP | |
#include <boost/graph/graph_traits.hpp> | |
#include <boost/graph/properties.hpp> | |
#include <boost/graph/adjacency_iterator.hpp> | |
#include <boost/graph/detail/set_adaptor.hpp> | |
#include <boost/iterator/filter_iterator.hpp> | |
namespace boost { | |
//========================================================================= | |
// Some predicate classes. | |
struct keep_all { | |
template <typename T> | |
bool operator()(const T&) const { return true; } | |
}; | |
// Keep residual edges (used in maximum-flow algorithms). | |
template <typename ResidualCapacityEdgeMap> | |
struct is_residual_edge { | |
is_residual_edge() { } | |
is_residual_edge(ResidualCapacityEdgeMap rcap) : m_rcap(rcap) { } | |
template <typename Edge> | |
bool operator()(const Edge& e) const { | |
return 0 < get(m_rcap, e); | |
} | |
ResidualCapacityEdgeMap m_rcap; | |
}; | |
template <typename Set> | |
struct is_in_subset { | |
is_in_subset() : m_s(0) { } | |
is_in_subset(const Set& s) : m_s(&s) { } | |
template <typename Elt> | |
bool operator()(const Elt& x) const { | |
return set_contains(*m_s, x); | |
} | |
const Set* m_s; | |
}; | |
template <typename Set> | |
struct is_not_in_subset { | |
is_not_in_subset() : m_s(0) { } | |
is_not_in_subset(const Set& s) : m_s(&s) { } | |
template <typename Elt> | |
bool operator()(const Elt& x) const { | |
return !set_contains(*m_s, x); | |
} | |
const Set* m_s; | |
}; | |
namespace detail { | |
template <typename EdgePredicate, typename VertexPredicate, typename Graph> | |
struct out_edge_predicate { | |
out_edge_predicate() { } | |
out_edge_predicate(EdgePredicate ep, VertexPredicate vp, | |
const Graph& g) | |
: m_edge_pred(ep), m_vertex_pred(vp), m_g(&g) { } | |
template <typename Edge> | |
bool operator()(const Edge& e) const { | |
return m_edge_pred(e) && m_vertex_pred(target(e, *m_g)); | |
} | |
EdgePredicate m_edge_pred; | |
VertexPredicate m_vertex_pred; | |
const Graph* m_g; | |
}; | |
template <typename EdgePredicate, typename VertexPredicate, typename Graph> | |
struct in_edge_predicate { | |
in_edge_predicate() { } | |
in_edge_predicate(EdgePredicate ep, VertexPredicate vp, | |
const Graph& g) | |
: m_edge_pred(ep), m_vertex_pred(vp), m_g(&g) { } | |
template <typename Edge> | |
bool operator()(const Edge& e) const { | |
return m_edge_pred(e) && m_vertex_pred(source(e, *m_g)); | |
} | |
EdgePredicate m_edge_pred; | |
VertexPredicate m_vertex_pred; | |
const Graph* m_g; | |
}; | |
template <typename EdgePredicate, typename VertexPredicate, typename Graph> | |
struct edge_predicate { | |
edge_predicate() { } | |
edge_predicate(EdgePredicate ep, VertexPredicate vp, | |
const Graph& g) | |
: m_edge_pred(ep), m_vertex_pred(vp), m_g(&g) { } | |
template <typename Edge> | |
bool operator()(const Edge& e) const { | |
return m_edge_pred(e) | |
&& m_vertex_pred(source(e, *m_g)) && m_vertex_pred(target(e, *m_g)); | |
} | |
EdgePredicate m_edge_pred; | |
VertexPredicate m_vertex_pred; | |
const Graph* m_g; | |
}; | |
} // namespace detail | |
//=========================================================================== | |
// Filtered Graph | |
struct filtered_graph_tag { }; | |
// This base class is a stupid hack to change overload resolution | |
// rules for the source and target functions so that they are a | |
// worse match than the source and target functions defined for | |
// pairs in graph_traits.hpp. I feel dirty. -JGS | |
template <class G> | |
struct filtered_graph_base { | |
typedef graph_traits<G> Traits; | |
typedef typename Traits::vertex_descriptor vertex_descriptor; | |
typedef typename Traits::edge_descriptor edge_descriptor; | |
filtered_graph_base(const G& g) : m_g(g) { } | |
//protected: | |
const G& m_g; | |
}; | |
template <typename Graph, | |
typename EdgePredicate, | |
typename VertexPredicate = keep_all> | |
class filtered_graph : public filtered_graph_base<Graph> { | |
typedef filtered_graph_base<Graph> Base; | |
typedef graph_traits<Graph> Traits; | |
typedef filtered_graph self; | |
public: | |
typedef Graph graph_type; | |
typedef detail::out_edge_predicate<EdgePredicate, | |
VertexPredicate, self> OutEdgePred; | |
typedef detail::in_edge_predicate<EdgePredicate, | |
VertexPredicate, self> InEdgePred; | |
typedef detail::edge_predicate<EdgePredicate, | |
VertexPredicate, self> EdgePred; | |
// Constructors | |
filtered_graph(const Graph& g, EdgePredicate ep) | |
: Base(g), m_edge_pred(ep) { } | |
filtered_graph(const Graph& g, EdgePredicate ep, VertexPredicate vp) | |
: Base(g), m_edge_pred(ep), m_vertex_pred(vp) { } | |
// Graph requirements | |
typedef typename Traits::vertex_descriptor vertex_descriptor; | |
typedef typename Traits::edge_descriptor edge_descriptor; | |
typedef typename Traits::directed_category directed_category; | |
typedef typename Traits::edge_parallel_category edge_parallel_category; | |
typedef typename Traits::traversal_category traversal_category; | |
// IncidenceGraph requirements | |
typedef filter_iterator< | |
OutEdgePred, typename Traits::out_edge_iterator | |
> out_edge_iterator; | |
typedef typename Traits::degree_size_type degree_size_type; | |
// AdjacencyGraph requirements | |
typedef typename adjacency_iterator_generator<self, | |
vertex_descriptor, out_edge_iterator>::type adjacency_iterator; | |
// BidirectionalGraph requirements | |
typedef filter_iterator< | |
InEdgePred, typename Traits::in_edge_iterator | |
> in_edge_iterator; | |
// VertexListGraph requirements | |
typedef filter_iterator< | |
VertexPredicate, typename Traits::vertex_iterator | |
> vertex_iterator; | |
typedef typename Traits::vertices_size_type vertices_size_type; | |
// EdgeListGraph requirements | |
typedef filter_iterator< | |
EdgePred, typename Traits::edge_iterator | |
> edge_iterator; | |
typedef typename Traits::edges_size_type edges_size_type; | |
typedef filtered_graph_tag graph_tag; | |
#ifndef BOOST_GRAPH_NO_BUNDLED_PROPERTIES | |
// Bundled properties support | |
template<typename Descriptor> | |
typename graph::detail::bundled_result<Graph, Descriptor>::type& | |
operator[](Descriptor x) | |
{ return const_cast<Graph&>(this->m_g)[x]; } | |
template<typename Descriptor> | |
typename graph::detail::bundled_result<Graph, Descriptor>::type const& | |
operator[](Descriptor x) const | |
{ return this->m_g[x]; } | |
#endif // BOOST_GRAPH_NO_BUNDLED_PROPERTIES | |
static vertex_descriptor null_vertex() | |
{ | |
return Graph::null_vertex(); | |
} | |
//private: | |
EdgePredicate m_edge_pred; | |
VertexPredicate m_vertex_pred; | |
}; | |
// Do not instantiate these unless needed | |
template <typename Graph, | |
typename EdgePredicate, | |
typename VertexPredicate> | |
struct vertex_property_type<filtered_graph<Graph, EdgePredicate, VertexPredicate> > { | |
typedef typename vertex_property_type<Graph>::type type; | |
}; | |
template <typename Graph, | |
typename EdgePredicate, | |
typename VertexPredicate> | |
struct edge_property_type<filtered_graph<Graph, EdgePredicate, VertexPredicate> > { | |
typedef typename edge_property_type<Graph>::type type; | |
}; | |
template <typename Graph, | |
typename EdgePredicate, | |
typename VertexPredicate> | |
struct graph_property_type<filtered_graph<Graph, EdgePredicate, VertexPredicate> > { | |
typedef typename graph_property_type<Graph>::type type; | |
}; | |
#ifndef BOOST_GRAPH_NO_BUNDLED_PROPERTIES | |
template<typename Graph, typename EdgePredicate, typename VertexPredicate> | |
struct vertex_bundle_type<filtered_graph<Graph, EdgePredicate, | |
VertexPredicate> > | |
: vertex_bundle_type<Graph> { }; | |
template<typename Graph, typename EdgePredicate, typename VertexPredicate> | |
struct edge_bundle_type<filtered_graph<Graph, EdgePredicate, | |
VertexPredicate> > | |
: edge_bundle_type<Graph> { }; | |
template<typename Graph, typename EdgePredicate, typename VertexPredicate> | |
struct graph_bundle_type<filtered_graph<Graph, EdgePredicate, | |
VertexPredicate> > | |
: graph_bundle_type<Graph> { }; | |
#endif // BOOST_GRAPH_NO_BUNDLED_PROPERTIES | |
//=========================================================================== | |
// Non-member functions for the Filtered Edge Graph | |
// Helper functions | |
template <typename Graph, typename EdgePredicate> | |
inline filtered_graph<Graph, EdgePredicate> | |
make_filtered_graph(Graph& g, EdgePredicate ep) { | |
return filtered_graph<Graph, EdgePredicate>(g, ep); | |
} | |
template <typename Graph, typename EdgePredicate, typename VertexPredicate> | |
inline filtered_graph<Graph, EdgePredicate, VertexPredicate> | |
make_filtered_graph(Graph& g, EdgePredicate ep, VertexPredicate vp) { | |
return filtered_graph<Graph, EdgePredicate, VertexPredicate>(g, ep, vp); | |
} | |
template <typename Graph, typename EdgePredicate> | |
inline filtered_graph<const Graph, EdgePredicate> | |
make_filtered_graph(const Graph& g, EdgePredicate ep) { | |
return filtered_graph<const Graph, EdgePredicate>(g, ep); | |
} | |
template <typename Graph, typename EdgePredicate, typename VertexPredicate> | |
inline filtered_graph<const Graph, EdgePredicate, VertexPredicate> | |
make_filtered_graph(const Graph& g, EdgePredicate ep, VertexPredicate vp) { | |
return filtered_graph<const Graph, EdgePredicate, VertexPredicate>(g, ep, vp); | |
} | |
template <typename G, typename EP, typename VP> | |
std::pair<typename filtered_graph<G, EP, VP>::vertex_iterator, | |
typename filtered_graph<G, EP, VP>::vertex_iterator> | |
vertices(const filtered_graph<G, EP, VP>& g) | |
{ | |
typedef filtered_graph<G, EP, VP> Graph; | |
typename graph_traits<G>::vertex_iterator f, l; | |
boost::tie(f, l) = vertices(g.m_g); | |
typedef typename Graph::vertex_iterator iter; | |
return std::make_pair(iter(g.m_vertex_pred, f, l), | |
iter(g.m_vertex_pred, l, l)); | |
} | |
template <typename G, typename EP, typename VP> | |
std::pair<typename filtered_graph<G, EP, VP>::edge_iterator, | |
typename filtered_graph<G, EP, VP>::edge_iterator> | |
edges(const filtered_graph<G, EP, VP>& g) | |
{ | |
typedef filtered_graph<G, EP, VP> Graph; | |
typename Graph::EdgePred pred(g.m_edge_pred, g.m_vertex_pred, g); | |
typename graph_traits<G>::edge_iterator f, l; | |
boost::tie(f, l) = edges(g.m_g); | |
typedef typename Graph::edge_iterator iter; | |
return std::make_pair(iter(pred, f, l), iter(pred, l, l)); | |
} | |
// An alternative for num_vertices() and num_edges() would be to | |
// count the number in the filtered graph. This is problematic | |
// because of the interaction with the vertex indices... they would | |
// no longer go from 0 to num_vertices(), which would cause trouble | |
// for algorithms allocating property storage in an array. We could | |
// try to create a mapping to new recalibrated indices, but I don't | |
// see an efficient way to do this. | |
// | |
// However, the current solution is still unsatisfactory because | |
// the following semantic constraints no longer hold: | |
// boost::tie(vi, viend) = vertices(g); | |
// assert(std::distance(vi, viend) == num_vertices(g)); | |
template <typename G, typename EP, typename VP> | |
typename filtered_graph<G, EP, VP>::vertices_size_type | |
num_vertices(const filtered_graph<G, EP, VP>& g) { | |
return num_vertices(g.m_g); | |
} | |
template <typename G, typename EP, typename VP> | |
typename filtered_graph<G, EP, VP>::edges_size_type | |
num_edges(const filtered_graph<G, EP, VP>& g) { | |
return num_edges(g.m_g); | |
} | |
template <typename G> | |
typename filtered_graph_base<G>::vertex_descriptor | |
source(typename filtered_graph_base<G>::edge_descriptor e, | |
const filtered_graph_base<G>& g) | |
{ | |
return source(e, g.m_g); | |
} | |
template <typename G> | |
typename filtered_graph_base<G>::vertex_descriptor | |
target(typename filtered_graph_base<G>::edge_descriptor e, | |
const filtered_graph_base<G>& g) | |
{ | |
return target(e, g.m_g); | |
} | |
template <typename G, typename EP, typename VP> | |
std::pair<typename filtered_graph<G, EP, VP>::out_edge_iterator, | |
typename filtered_graph<G, EP, VP>::out_edge_iterator> | |
out_edges(typename filtered_graph<G, EP, VP>::vertex_descriptor u, | |
const filtered_graph<G, EP, VP>& g) | |
{ | |
typedef filtered_graph<G, EP, VP> Graph; | |
typename Graph::OutEdgePred pred(g.m_edge_pred, g.m_vertex_pred, g); | |
typedef typename Graph::out_edge_iterator iter; | |
typename graph_traits<G>::out_edge_iterator f, l; | |
boost::tie(f, l) = out_edges(u, g.m_g); | |
return std::make_pair(iter(pred, f, l), iter(pred, l, l)); | |
} | |
template <typename G, typename EP, typename VP> | |
typename filtered_graph<G, EP, VP>::degree_size_type | |
out_degree(typename filtered_graph<G, EP, VP>::vertex_descriptor u, | |
const filtered_graph<G, EP, VP>& g) | |
{ | |
typename filtered_graph<G, EP, VP>::degree_size_type n = 0; | |
typename filtered_graph<G, EP, VP>::out_edge_iterator f, l; | |
for (boost::tie(f, l) = out_edges(u, g); f != l; ++f) | |
++n; | |
return n; | |
} | |
template <typename G, typename EP, typename VP> | |
std::pair<typename filtered_graph<G, EP, VP>::adjacency_iterator, | |
typename filtered_graph<G, EP, VP>::adjacency_iterator> | |
adjacent_vertices(typename filtered_graph<G, EP, VP>::vertex_descriptor u, | |
const filtered_graph<G, EP, VP>& g) | |
{ | |
typedef filtered_graph<G, EP, VP> Graph; | |
typedef typename Graph::adjacency_iterator adjacency_iterator; | |
typename Graph::out_edge_iterator f, l; | |
boost::tie(f, l) = out_edges(u, g); | |
return std::make_pair(adjacency_iterator(f, const_cast<Graph*>(&g)), | |
adjacency_iterator(l, const_cast<Graph*>(&g))); | |
} | |
template <typename G, typename EP, typename VP> | |
std::pair<typename filtered_graph<G, EP, VP>::in_edge_iterator, | |
typename filtered_graph<G, EP, VP>::in_edge_iterator> | |
in_edges(typename filtered_graph<G, EP, VP>::vertex_descriptor u, | |
const filtered_graph<G, EP, VP>& g) | |
{ | |
typedef filtered_graph<G, EP, VP> Graph; | |
typename Graph::InEdgePred pred(g.m_edge_pred, g.m_vertex_pred, g); | |
typedef typename Graph::in_edge_iterator iter; | |
typename graph_traits<G>::in_edge_iterator f, l; | |
boost::tie(f, l) = in_edges(u, g.m_g); | |
return std::make_pair(iter(pred, f, l), iter(pred, l, l)); | |
} | |
template <typename G, typename EP, typename VP> | |
typename filtered_graph<G, EP, VP>::degree_size_type | |
in_degree(typename filtered_graph<G, EP, VP>::vertex_descriptor u, | |
const filtered_graph<G, EP, VP>& g) | |
{ | |
typename filtered_graph<G, EP, VP>::degree_size_type n = 0; | |
typename filtered_graph<G, EP, VP>::in_edge_iterator f, l; | |
for (boost::tie(f, l) = in_edges(u, g); f != l; ++f) | |
++n; | |
return n; | |
} | |
template <typename G, typename EP, typename VP> | |
std::pair<typename filtered_graph<G, EP, VP>::edge_descriptor, bool> | |
edge(typename filtered_graph<G, EP, VP>::vertex_descriptor u, | |
typename filtered_graph<G, EP, VP>::vertex_descriptor v, | |
const filtered_graph<G, EP, VP>& g) | |
{ | |
typename graph_traits<G>::edge_descriptor e; | |
bool exists; | |
boost::tie(e, exists) = edge(u, v, g.m_g); | |
return std::make_pair(e, exists && g.m_edge_pred(e)); | |
} | |
template <typename G, typename EP, typename VP> | |
std::pair<typename filtered_graph<G, EP, VP>::out_edge_iterator, | |
typename filtered_graph<G, EP, VP>::out_edge_iterator> | |
edge_range(typename filtered_graph<G, EP, VP>::vertex_descriptor u, | |
typename filtered_graph<G, EP, VP>::vertex_descriptor v, | |
const filtered_graph<G, EP, VP>& g) | |
{ | |
typedef filtered_graph<G, EP, VP> Graph; | |
typename Graph::OutEdgePred pred(g.m_edge_pred, g.m_vertex_pred, g); | |
typedef typename Graph::out_edge_iterator iter; | |
typename graph_traits<G>::out_edge_iterator f, l; | |
boost::tie(f, l) = edge_range(u, v, g.m_g); | |
return std::make_pair(iter(pred, f, l), iter(pred, l, l)); | |
} | |
//=========================================================================== | |
// Property map | |
template <typename G, typename EP, typename VP, typename Property> | |
struct property_map<filtered_graph<G, EP, VP>, Property> | |
: property_map<G, Property> {}; | |
template <typename G, typename EP, typename VP, typename Property> | |
typename property_map<G, Property>::type | |
get(Property p, filtered_graph<G, EP, VP>& g) | |
{ | |
return get(p, const_cast<G&>(g.m_g)); | |
} | |
template <typename G, typename EP, typename VP,typename Property> | |
typename property_map<G, Property>::const_type | |
get(Property p, const filtered_graph<G, EP, VP>& g) | |
{ | |
return get(p, (const G&)g.m_g); | |
} | |
template <typename G, typename EP, typename VP, typename Property, | |
typename Key> | |
typename property_map_value<G, Property>::type | |
get(Property p, const filtered_graph<G, EP, VP>& g, const Key& k) | |
{ | |
return get(p, (const G&)g.m_g, k); | |
} | |
template <typename G, typename EP, typename VP, typename Property, | |
typename Key, typename Value> | |
void | |
put(Property p, const filtered_graph<G, EP, VP>& g, const Key& k, | |
const Value& val) | |
{ | |
put(p, const_cast<G&>(g.m_g), k, val); | |
} | |
//=========================================================================== | |
// Some filtered subgraph specializations | |
template <typename Graph, typename Set> | |
struct vertex_subset_filter { | |
typedef filtered_graph<Graph, keep_all, is_in_subset<Set> > type; | |
}; | |
template <typename Graph, typename Set> | |
inline typename vertex_subset_filter<Graph, Set>::type | |
make_vertex_subset_filter(Graph& g, const Set& s) { | |
typedef typename vertex_subset_filter<Graph, Set>::type Filter; | |
is_in_subset<Set> p(s); | |
return Filter(g, keep_all(), p); | |
} | |
// This is misspelled, but present for backwards compatibility; new code | |
// should use the version below that has the correct spelling. | |
template <typename Graph, typename Set> | |
struct vertex_subset_compliment_filter { | |
typedef filtered_graph<Graph, keep_all, is_not_in_subset<Set> > type; | |
}; | |
template <typename Graph, typename Set> | |
inline typename vertex_subset_compliment_filter<Graph, Set>::type | |
make_vertex_subset_compliment_filter(Graph& g, const Set& s) { | |
typedef typename vertex_subset_compliment_filter<Graph, Set>::type Filter; | |
is_not_in_subset<Set> p(s); | |
return Filter(g, keep_all(), p); | |
} | |
template <typename Graph, typename Set> | |
struct vertex_subset_complement_filter { | |
typedef filtered_graph<Graph, keep_all, is_not_in_subset<Set> > type; | |
}; | |
template <typename Graph, typename Set> | |
inline typename vertex_subset_complement_filter<Graph, Set>::type | |
make_vertex_subset_complement_filter(Graph& g, const Set& s) { | |
typedef typename vertex_subset_complement_filter<Graph, Set>::type Filter; | |
is_not_in_subset<Set> p(s); | |
return Filter(g, keep_all(), p); | |
} | |
// Filter that uses a property map whose value_type is a boolean | |
template <typename PropertyMap> | |
struct property_map_filter { | |
property_map_filter() { } | |
property_map_filter(const PropertyMap& property_map) : | |
m_property_map(property_map) { } | |
template <typename Key> | |
bool operator()(const Key& key) const { | |
return (get(m_property_map, key)); | |
} | |
private : | |
PropertyMap m_property_map; | |
}; | |
} // namespace boost | |
#endif // BOOST_FILTERED_GRAPH_HPP |