feat: init

This commit is contained in:
dxfiscool committed 2026-03-08 10:09:54 +01:00
commit 25809b8455
18807 files changed
+3944357

No files matched your search

@@ -0,0 +1,36 @@
// Copyright 2005 The Trustees of Indiana University.
// Use, modification and distribution is subject to 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)
// Authors: Douglas Gregor
// Andrew Lumsdaine
#ifndef BOOST_GRAPH_ACCOUNTING_HPP
#define BOOST_GRAPH_ACCOUNTING_HPP
#include <iomanip>
#include <iostream>
#include <string>
#include <sstream>
#include <boost/mpi/config.hpp>
namespace boost { namespace graph { namespace accounting {
typedef double time_type;
inline time_type get_time()
{
return MPI_Wtime();
}
inline std::string print_time(time_type t)
{
std::ostringstream out;
out << std::setiosflags(std::ios::fixed) << std::setprecision(2) << t;
return out.str();
}
} } } // end namespace boost::graph::accounting
#endif // BOOST_GRAPH_ACCOUNTING_HPP
@@ -0,0 +1,116 @@
//=======================================================================
// Copyright 2005 Jeremy G. Siek
// Authors: 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 ADJ_LIST_SERIALIZE_HPP
#define ADJ_LIST_SERIALIZE_HPP
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/iteration_macros.hpp>
#include <boost/pending/property_serialize.hpp>
#include <boost/config.hpp>
#include <boost/detail/workaround.hpp>
#include <boost/serialization/collections_save_imp.hpp>
#include <boost/serialization/collections_load_imp.hpp>
#include <boost/serialization/split_free.hpp>
namespace boost {
namespace serialization {
// Turn off tracking for adjacency_list. It's not polymorphic, and we
// need to do this to enable saving of non-const adjacency lists.
template<class OEL, class VL, class D, class VP, class EP, class GP, class EL>
struct tracking_level<boost::adjacency_list<OEL,VL,D,VP,EP,GP,EL> > {
typedef mpl::integral_c_tag tag;
typedef mpl::int_<track_never> type;
BOOST_STATIC_CONSTANT(int, value = tracking_level::type::value);
};
template<class Archive, class OEL, class VL, class D,
class VP, class EP, class GP, class EL>
inline void save(
Archive & ar,
const boost::adjacency_list<OEL,VL,D,VP,EP,GP,EL> &graph,
const unsigned int /* file_version */
){
typedef adjacency_list<OEL,VL,D,VP,EP,GP,EL> Graph;
typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
int V = num_vertices(graph);
int E = num_edges(graph);
ar << BOOST_SERIALIZATION_NVP(V);
ar << BOOST_SERIALIZATION_NVP(E);
// assign indices to vertices
std::map<Vertex,int> indices;
int num = 0;
BGL_FORALL_VERTICES_T(v, graph, Graph) {
indices[v] = num++;
ar << serialization::make_nvp("vertex_property", get(vertex_all_t(), graph, v) );
}
// write edges
BGL_FORALL_EDGES_T(e, graph, Graph) {
ar << serialization::make_nvp("u" , indices[source(e,graph)]);
ar << serialization::make_nvp("v" , indices[target(e,graph)]);
ar << serialization::make_nvp("edge_property", get(edge_all_t(), graph, e) );
}
ar << serialization::make_nvp("graph_property", get_property(graph, graph_all_t()) );
}
template<class Archive, class OEL, class VL, class D,
class VP, class EP, class GP, class EL>
inline void load(
Archive & ar,
boost::adjacency_list<OEL,VL,D,VP,EP,GP,EL> &graph,
const unsigned int /* file_version */
){
typedef adjacency_list<OEL,VL,D,VP,EP,GP,EL> Graph;
typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
typedef typename graph_traits<Graph>::edge_descriptor Edge;
unsigned int V;
ar >> BOOST_SERIALIZATION_NVP(V);
unsigned int E;
ar >> BOOST_SERIALIZATION_NVP(E);
std::vector<Vertex> verts(V);
int i = 0;
while(V-- > 0){
Vertex v = add_vertex(graph);
verts[i++] = v;
ar >> serialization::make_nvp("vertex_property", get(vertex_all_t(), graph, v) );
}
while(E-- > 0){
int u; int v;
ar >> BOOST_SERIALIZATION_NVP(u);
ar >> BOOST_SERIALIZATION_NVP(v);
Edge e; bool inserted;
boost::tie(e,inserted) = add_edge(verts[u], verts[v], graph);
ar >> serialization::make_nvp("edge_property", get(edge_all_t(), graph, e) );
}
ar >> serialization::make_nvp("graph_property", get_property(graph, graph_all_t()) );
}
template<class Archive, class OEL, class VL, class D, class VP, class EP, class GP, class EL>
inline void serialize(
Archive & ar,
boost::adjacency_list<OEL,VL,D,VP,EP,GP,EL> &graph,
const unsigned int file_version
){
boost::serialization::split_free(ar, graph, file_version);
}
}//serialization
}//boost
#endif // ADJ_LIST_SERIALIZE_HPP
@@ -0,0 +1,102 @@
//=======================================================================
// Copyright 2002 Indiana University.
// 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_ADJACENCY_ITERATOR_HPP
#define BOOST_ADJACENCY_ITERATOR_HPP
#include <boost/iterator/iterator_adaptor.hpp>
#include <boost/graph/graph_traits.hpp>
namespace boost
{
template <class Graph, class Vertex, class OutEdgeIter, class Difference>
struct adjacency_iterator
: iterator_adaptor<
adjacency_iterator<Graph,Vertex,OutEdgeIter,Difference>
, OutEdgeIter
, Vertex
, use_default
, Vertex
, Difference
>
{
typedef iterator_adaptor<
adjacency_iterator<Graph,Vertex,OutEdgeIter,Difference>
, OutEdgeIter
, Vertex
, use_default
, Vertex
, Difference
> super_t;
inline adjacency_iterator() {}
inline adjacency_iterator(OutEdgeIter const& i, const Graph* g) : super_t(i), m_g(g) { }
inline Vertex
dereference() const
{ return target(*this->base(), *m_g); }
const Graph* m_g;
};
template <class Graph,
class Vertex = typename graph_traits<Graph>::vertex_descriptor,
class OutEdgeIter=typename graph_traits<Graph>::out_edge_iterator>
class adjacency_iterator_generator
{
typedef typename boost::detail::iterator_traits<OutEdgeIter>
::difference_type difference_type;
public:
typedef adjacency_iterator<Graph,Vertex,OutEdgeIter,difference_type> type;
};
template <class Graph, class Vertex, class InEdgeIter, class Difference>
struct inv_adjacency_iterator
: iterator_adaptor<
inv_adjacency_iterator<Graph,Vertex,InEdgeIter,Difference>
, InEdgeIter
, Vertex
, use_default
, Vertex
, Difference
>
{
typedef iterator_adaptor<
inv_adjacency_iterator<Graph,Vertex,InEdgeIter,Difference>
, InEdgeIter
, Vertex
, use_default
, Vertex
, Difference
> super_t;
inline inv_adjacency_iterator() { }
inline inv_adjacency_iterator(InEdgeIter const& i, const Graph* g) : super_t(i), m_g(g) { }
inline Vertex
dereference() const
{ return source(*this->base(), *m_g); }
const Graph* m_g;
};
template <class Graph,
class Vertex = typename graph_traits<Graph>::vertex_descriptor,
class InEdgeIter = typename graph_traits<Graph>::in_edge_iterator>
class inv_adjacency_iterator_generator {
typedef typename boost::detail::iterator_traits<InEdgeIter>
::difference_type difference_type;
public:
typedef inv_adjacency_iterator<Graph, Vertex, InEdgeIter, difference_type> type;
};
} // namespace boost
#endif // BOOST_DETAIL_ADJACENCY_ITERATOR_HPP
@@ -0,0 +1,458 @@
//=======================================================================
// Copyright 1997, 1998, 1999, 2000 University of Notre Dame.
// Copyright 2010 Thomas Claveirole
// Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek, Thomas Claveirole
//
// 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_GRAPH_ADJACENCY_LIST_HPP
#define BOOST_GRAPH_ADJACENCY_LIST_HPP
#include <boost/config.hpp>
#include <vector>
#include <list>
#include <set>
#include <boost/unordered_set.hpp>
#if !defined BOOST_NO_SLIST
# ifdef BOOST_SLIST_HEADER
# include BOOST_SLIST_HEADER
# else
# include <slist>
# endif
#endif
#include <boost/scoped_ptr.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/graph_mutability_traits.hpp>
#include <boost/graph/graph_selectors.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/and.hpp>
#include <boost/mpl/not.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/graph/detail/edge.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/detail/workaround.hpp>
#include <boost/graph/properties.hpp>
#include <boost/graph/named_graph.hpp>
namespace boost {
//===========================================================================
// Selectors for the VertexList and EdgeList template parameters of
// adjacency_list, and the container_gen traits class which is used
// to map the selectors to the container type used to implement the
// graph.
#if !defined BOOST_NO_SLIST
struct slistS {};
#endif
struct vecS { };
struct listS { };
struct setS { };
struct mapS { };
struct multisetS { };
struct multimapS { };
struct hash_setS { };
struct hash_mapS { };
struct hash_multisetS { };
struct hash_multimapS { };
template <class Selector, class ValueType>
struct container_gen { };
template <class ValueType>
struct container_gen<listS, ValueType> {
typedef std::list<ValueType> type;
};
#if !defined BOOST_NO_SLIST
template <class ValueType>
struct container_gen<slistS, ValueType> {
typedef BOOST_STD_EXTENSION_NAMESPACE::slist<ValueType> type;
};
#endif
template <class ValueType>
struct container_gen<vecS, ValueType> {
typedef std::vector<ValueType> type;
};
template <class ValueType>
struct container_gen<mapS, ValueType> {
typedef std::set<ValueType> type;
};
template <class ValueType>
struct container_gen<setS, ValueType> {
typedef std::set<ValueType> type;
};
template <class ValueType>
struct container_gen<multisetS, ValueType> {
typedef std::multiset<ValueType> type;
};
template <class ValueType>
struct container_gen<multimapS, ValueType> {
typedef std::multiset<ValueType> type;
};
template <class ValueType>
struct container_gen<hash_setS, ValueType> {
typedef boost::unordered_set<ValueType> type;
};
template <class ValueType>
struct container_gen<hash_mapS, ValueType> {
typedef boost::unordered_set<ValueType> type;
};
template <class ValueType>
struct container_gen<hash_multisetS, ValueType> {
typedef boost::unordered_multiset<ValueType> type;
};
template <class ValueType>
struct container_gen<hash_multimapS, ValueType> {
typedef boost::unordered_multiset<ValueType> type;
};
template <class StorageSelector>
struct parallel_edge_traits { };
template <>
struct parallel_edge_traits<vecS> {
typedef allow_parallel_edge_tag type; };
template <>
struct parallel_edge_traits<listS> {
typedef allow_parallel_edge_tag type; };
#if !defined BOOST_NO_SLIST
template <>
struct parallel_edge_traits<slistS> {
typedef allow_parallel_edge_tag type; };
#endif
template <>
struct parallel_edge_traits<setS> {
typedef disallow_parallel_edge_tag type; };
template <>
struct parallel_edge_traits<multisetS> {
typedef allow_parallel_edge_tag type; };
template <>
struct parallel_edge_traits<hash_setS> {
typedef disallow_parallel_edge_tag type;
};
// mapS is obsolete, replaced with setS
template <>
struct parallel_edge_traits<mapS> {
typedef disallow_parallel_edge_tag type; };
template <>
struct parallel_edge_traits<hash_mapS> {
typedef disallow_parallel_edge_tag type;
};
template <>
struct parallel_edge_traits<hash_multisetS> {
typedef allow_parallel_edge_tag type;
};
template <>
struct parallel_edge_traits<hash_multimapS> {
typedef allow_parallel_edge_tag type;
};
namespace detail {
template <class Directed> struct is_random_access {
enum { value = false};
typedef mpl::false_ type;
};
template <>
struct is_random_access<vecS> {
enum { value = true };
typedef mpl::true_ type;
};
} // namespace detail
template <typename Selector> struct is_distributed_selector: mpl::false_ {};
//===========================================================================
// The adjacency_list_traits class, which provides a way to access
// some of the associated types of an adjacency_list type without
// having to first create the adjacency_list type. This is useful
// when trying to create interior vertex or edge properties who's
// value type is a vertex or edge descriptor.
template <class OutEdgeListS = vecS,
class VertexListS = vecS,
class DirectedS = directedS,
class EdgeListS = listS>
struct adjacency_list_traits
{
typedef typename detail::is_random_access<VertexListS>::type
is_rand_access;
typedef typename DirectedS::is_bidir_t is_bidir;
typedef typename DirectedS::is_directed_t is_directed;
typedef typename mpl::if_<is_bidir,
bidirectional_tag,
typename mpl::if_<is_directed,
directed_tag, undirected_tag
>::type
>::type directed_category;
typedef typename parallel_edge_traits<OutEdgeListS>::type
edge_parallel_category;
typedef std::size_t vertices_size_type;
typedef void* vertex_ptr;
typedef typename mpl::if_<is_rand_access,
vertices_size_type, vertex_ptr>::type vertex_descriptor;
typedef detail::edge_desc_impl<directed_category, vertex_descriptor>
edge_descriptor;
private:
// Logic to figure out the edges_size_type
struct dummy {};
typedef typename container_gen<EdgeListS, dummy>::type EdgeContainer;
typedef typename DirectedS::is_bidir_t BidirectionalT;
typedef typename DirectedS::is_directed_t DirectedT;
typedef typename mpl::and_<DirectedT,
typename mpl::not_<BidirectionalT>::type >::type on_edge_storage;
public:
typedef typename mpl::if_<on_edge_storage,
std::size_t, typename EdgeContainer::size_type
>::type edges_size_type;
};
} // namespace boost
#include <boost/graph/detail/adjacency_list.hpp>
namespace boost {
//===========================================================================
// The adjacency_list class.
//
template <class OutEdgeListS = vecS, // a Sequence or an AssociativeContainer
class VertexListS = vecS, // a Sequence or a RandomAccessContainer
class DirectedS = directedS,
class VertexProperty = no_property,
class EdgeProperty = no_property,
class GraphProperty = no_property,
class EdgeListS = listS>
class adjacency_list
: public detail::adj_list_gen<
adjacency_list<OutEdgeListS,VertexListS,DirectedS,
VertexProperty,EdgeProperty,GraphProperty,EdgeListS>,
VertexListS, OutEdgeListS, DirectedS,
VertexProperty, EdgeProperty,
GraphProperty, EdgeListS>::type,
// Support for named vertices
public graph::maybe_named_graph<
adjacency_list<OutEdgeListS,VertexListS,DirectedS,
VertexProperty,EdgeProperty,GraphProperty,EdgeListS>,
typename adjacency_list_traits<OutEdgeListS, VertexListS, DirectedS,
EdgeListS>::vertex_descriptor,
VertexProperty>
{
public:
typedef GraphProperty graph_property_type;
typedef typename lookup_one_property<GraphProperty, graph_bundle_t>::type graph_bundled;
typedef VertexProperty vertex_property_type;
typedef typename lookup_one_property<VertexProperty, vertex_bundle_t>::type vertex_bundled;
typedef EdgeProperty edge_property_type;
typedef typename lookup_one_property<EdgeProperty, edge_bundle_t>::type edge_bundled;
private:
typedef adjacency_list self;
typedef typename detail::adj_list_gen<
self, VertexListS, OutEdgeListS, DirectedS,
vertex_property_type, edge_property_type, GraphProperty, EdgeListS
>::type Base;
public:
typedef typename Base::stored_vertex stored_vertex;
typedef typename Base::vertices_size_type vertices_size_type;
typedef typename Base::edges_size_type edges_size_type;
typedef typename Base::degree_size_type degree_size_type;
typedef typename Base::vertex_descriptor vertex_descriptor;
typedef typename Base::edge_descriptor edge_descriptor;
typedef OutEdgeListS out_edge_list_selector;
typedef VertexListS vertex_list_selector;
typedef DirectedS directed_selector;
typedef EdgeListS edge_list_selector;
adjacency_list(const GraphProperty& p = GraphProperty())
: m_property(new graph_property_type(p))
{ }
adjacency_list(const adjacency_list& x)
: Base(x), m_property(new graph_property_type(*x.m_property))
{ }
adjacency_list& operator=(const adjacency_list& x) {
// TBD: probably should give the strong guarantee
if (&x != this) {
Base::operator=(x);
// Copy/swap the ptr since we can't just assign it...
property_ptr p(new graph_property_type(*x.m_property));
m_property.swap(p);
}
return *this;
}
// Required by Mutable Graph
adjacency_list(vertices_size_type num_vertices,
const GraphProperty& p = GraphProperty())
: Base(num_vertices), m_property(new graph_property_type(p))
{ }
#if !defined(BOOST_MSVC) || BOOST_MSVC >= 1300
// Required by Iterator Constructible Graph
template <class EdgeIterator>
adjacency_list(EdgeIterator first, EdgeIterator last,
vertices_size_type n,
edges_size_type = 0,
const GraphProperty& p = GraphProperty())
: Base(n, first, last), m_property(new graph_property_type(p))
{ }
template <class EdgeIterator, class EdgePropertyIterator>
adjacency_list(EdgeIterator first, EdgeIterator last,
EdgePropertyIterator ep_iter,
vertices_size_type n,
edges_size_type = 0,
const GraphProperty& p = GraphProperty())
: Base(n, first, last, ep_iter), m_property(new graph_property_type(p))
{ }
#endif
void swap(adjacency_list& x) {
// Is there a more efficient way to do this?
adjacency_list tmp(x);
x = *this;
*this = tmp;
}
void clear()
{
this->clearing_graph();
Base::clear();
}
#ifndef BOOST_GRAPH_NO_BUNDLED_PROPERTIES
// Directly access a vertex or edge bundle
vertex_bundled& operator[](vertex_descriptor v)
{ return get(vertex_bundle, *this)[v]; }
const vertex_bundled& operator[](vertex_descriptor v) const
{ return get(vertex_bundle, *this)[v]; }
edge_bundled& operator[](edge_descriptor e)
{ return get(edge_bundle, *this)[e]; }
const edge_bundled& operator[](edge_descriptor e) const
{ return get(edge_bundle, *this)[e]; }
graph_bundled& operator[](graph_bundle_t)
{ return get_property(*this); }
graph_bundled const& operator[](graph_bundle_t) const
{ return get_property(*this); }
#endif
// protected: (would be protected if friends were more portable)
typedef scoped_ptr<graph_property_type> property_ptr;
property_ptr m_property;
};
#define ADJLIST_PARAMS \
typename OEL, typename VL, typename D, typename VP, typename EP, \
typename GP, typename EL
#define ADJLIST adjacency_list<OEL,VL,D,VP,EP,GP,EL>
template<ADJLIST_PARAMS, typename Tag, typename Value>
inline void set_property(ADJLIST& g, Tag tag, Value const& value) {
get_property_value(*g.m_property, tag) = value;
}
template<ADJLIST_PARAMS, typename Tag>
inline typename graph_property<ADJLIST, Tag>::type&
get_property(ADJLIST& g, Tag tag) {
return get_property_value(*g.m_property, tag);
}
template<ADJLIST_PARAMS, typename Tag>
inline typename graph_property<ADJLIST, Tag>::type const&
get_property(ADJLIST const& g, Tag tag) {
return get_property_value(*g.m_property, tag);
}
// dwa 09/25/00 - needed to be more explicit so reverse_graph would work.
template <class Directed, class Vertex,
class OutEdgeListS,
class VertexListS,
class DirectedS,
class VertexProperty,
class EdgeProperty,
class GraphProperty, class EdgeListS>
inline Vertex
source(const detail::edge_base<Directed,Vertex>& e,
const adjacency_list<OutEdgeListS, VertexListS, DirectedS,
VertexProperty, EdgeProperty, GraphProperty, EdgeListS>&)
{
return e.m_source;
}
template <class Directed, class Vertex, class OutEdgeListS,
class VertexListS, class DirectedS, class VertexProperty,
class EdgeProperty, class GraphProperty, class EdgeListS>
inline Vertex
target(const detail::edge_base<Directed,Vertex>& e,
const adjacency_list<OutEdgeListS, VertexListS, DirectedS,
VertexProperty, EdgeProperty, GraphProperty, EdgeListS>&)
{
return e.m_target;
}
// Mutability Traits
template <ADJLIST_PARAMS>
struct graph_mutability_traits<ADJLIST> {
typedef mutable_property_graph_tag category;
};
// Can't remove vertices from adjacency lists with VL==vecS
template <typename OEL, typename D, typename VP, typename EP, typename GP, typename EL>
struct graph_mutability_traits< adjacency_list<OEL,vecS,D,VP,EP,GP,EL> > {
typedef add_only_property_graph_tag category;
};
#undef ADJLIST_PARAMS
#undef ADJLIST
} // namespace boost
#endif // BOOST_GRAPH_ADJACENCY_LIST_HPP
@@ -0,0 +1,406 @@
//=======================================================================
// Copyright 2001 Universite Joseph Fourier, Grenoble.
// Author: Francois Faure
//
// 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_GRAPH_ADJACENCY_LIST_IO_HPP
#define BOOST_GRAPH_ADJACENCY_LIST_IO_HPP
#include <iostream>
#include <vector>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/iteration_macros.hpp>
#include <cctype>
// Method read to parse an adjacency list from an input stream. Examples:
// cin >> read( G );
// cin >> read( G, NodePropertySubset(), EdgepropertySubset() );
//
// Method write to print an adjacency list to an output stream. Examples:
// cout << write( G );
// cout << write( G, NodePropertySubset(), EdgepropertySubset() );
namespace boost {
/* outline
- basic property input
- get property subset
- graph parser
- property printer
- graph printer
- user methods
*/
//===========================================================================
// basic property input
template<class Tag, class Value, class Next>
std::istream& operator >> ( std::istream& in, property<Tag,Value,Next>& p )
{
in >> p.m_value >> p.m_base; // houpla !!
return in;
}
template<class Tag, class Value>
std::istream& operator >> ( std::istream& in, property<Tag,Value,no_property>& p )
{
in >> p.m_value;
return in;
}
inline std::istream& operator >> ( std::istream& in, no_property& )
{
return in;
}
// basic property input
//===========================================================================
// get property subsets
// get a single property tagged Stag
template<class Tag, class Value, class Next, class V, class Stag>
void get
( property<Tag,Value,Next>& p, const V& v, Stag s )
{
get( p.m_base,v,s );
}
template<class Value, class Next, class V, class Stag>
void get
( property<Stag,Value,Next>& p, const V& v, Stag )
{
p.m_value = v;
}
// get a subset of properties tagged Stag
template<class Tag, class Value, class Next,
class Stag, class Svalue, class Snext>
void getSubset
( property<Tag,Value,Next>& p, const property<Stag,Svalue,Snext>& s )
{
get( p, s.m_value, Stag() );
getSubset( p, s.m_base );
}
template<class Tag, class Value, class Next,
class Stag, class Svalue>
void getSubset
( property<Tag,Value,Next>& p, const property<Stag,Svalue,no_property>& s)
{
get( p, s.m_value, Stag() );
}
inline void getSubset
( no_property&, const no_property& )
{
}
#if !defined(BOOST_GRAPH_NO_BUNDLED_PROPERTIES)
template<typename T, typename U>
void getSubset(T& p, const U& s)
{
p = s;
}
template<typename T>
void getSubset(T&, const no_property&)
{
}
#endif
// get property subset
//===========================================================================
// graph parser
typedef enum{ PARSE_NUM_NODES, PARSE_VERTEX, PARSE_EDGE } GraphParserState;
template<class Graph_t, class VertexProperty, class EdgeProperty, class VertexPropertySubset,
class EdgePropertySubset>
struct GraphParser
{
typedef Graph_t Graph;
GraphParser( Graph* g ): graph(g)
{}
GraphParser& operator () ( std::istream& in )
{
typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
std::vector<Vertex> nodes;
GraphParserState state = PARSE_VERTEX;
unsigned int numLine = 1;
char c;
while ( in.get(c) )
{
if( c== '#' ) skip(in);
else if( c== 'n' ) state = PARSE_NUM_NODES;
else if( c== 'v' ) state = PARSE_VERTEX;
else if( c== 'e' ) state = PARSE_EDGE;
else if( c== '\n' ) numLine++;
else if( !std::isspace(c) ){
in.putback(c);
if( state == PARSE_VERTEX ){
VertexPropertySubset readProp;
if( in >> readProp )
{
VertexProperty vp;
getSubset( vp, readProp );
nodes.push_back( add_vertex(vp, *graph) );
}
else
std::cerr<<"read vertex, parse error at line"<<numLine<<std::endl;
}
else if( state == PARSE_EDGE ) {
int source, target;
EdgePropertySubset readProp;
in >> source >> target;
if( in >> readProp )
{
EdgeProperty ep;
getSubset( ep, readProp );
add_edge(nodes[source], nodes[target], ep, *graph);
}
else
std::cerr<<"read edge, parse error at line"<<numLine<<std::endl;
}
else { // state == PARSE_NUM_NODES
int n;
if( in >> n ){
for( int i=0; i<n; ++i )
nodes.push_back( add_vertex( *graph ));
}
else
std::cerr<<"read num_nodes, parse error at line "<< numLine << std::endl;
}
}
}
return (*this);
}
protected:
Graph* graph;
void skip( std::istream& in )
{
char c = 0;
while( c!='\n' && !in.eof() )
in.get(c);
in.putback(c);
}
};
// parser
//=======================================================================
// property printer
#if defined(BOOST_GRAPH_NO_BUNDLED_PROPERTIES)
template<class Graph, class Property>
struct PropertyPrinter
{
typedef typename Property::value_type Value;
typedef typename Property::tag_type Tag;
typedef typename Property::next_type Next;
PropertyPrinter( const Graph& g ):graph(&g){}
template<class Val>
PropertyPrinter& operator () ( std::ostream& out, const Val& v )
{
typename property_map<Graph,Tag>::const_type ps = get(Tag(), *graph);
out << ps[ v ] <<" ";
PropertyPrinter<Graph,Next> print(*graph);
print(out, v);
return (*this);
}
private:
const Graph* graph;
};
#else
template<class Graph, typename Property>
struct PropertyPrinter
{
PropertyPrinter( const Graph& g ):graph(&g){}
template<class Val>
PropertyPrinter& operator () ( std::ostream& out, const Val& v )
{
out << (*graph)[ v ] <<" ";
return (*this);
}
private:
const Graph* graph;
};
template<class Graph, typename Tag, typename Value, typename Next>
struct PropertyPrinter<Graph, property<Tag, Value, Next> >
{
PropertyPrinter( const Graph& g ):graph(&g){}
template<class Val>
PropertyPrinter& operator () ( std::ostream& out, const Val& v )
{
typename property_map<Graph,Tag>::const_type ps = get(Tag(), *graph);
out << ps[ v ] <<" ";
PropertyPrinter<Graph,Next> print(*graph);
print(out, v);
return (*this);
}
private:
const Graph* graph;
};
#endif
template<class Graph>
struct PropertyPrinter<Graph, no_property>
{
PropertyPrinter( const Graph& ){}
template<class Val>
PropertyPrinter& operator () ( std::ostream&, const Val& ){ return *this; }
};
// property printer
//=========================================================================
// graph printer
template<class Graph_t, class EdgeProperty>
struct EdgePrinter
{
typedef Graph_t Graph;
typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
EdgePrinter( const Graph& g )
: graph(g)
{}
const EdgePrinter& operator () ( std::ostream& out ) const
{
// assign indices to vertices
std::map<Vertex,int> indices;
int num = 0;
BGL_FORALL_VERTICES_T(v, graph, Graph) {
indices[v] = num++;
}
// write edges
PropertyPrinter<Graph, EdgeProperty> print_Edge(graph);
out << "e" << std::endl;
BGL_FORALL_EDGES_T(e, graph, Graph) {
out << indices[source(e,graph)] << " " << indices[target(e,graph)] << " ";
print_Edge(out,e);
out << std::endl;
}
out << std::endl;
return (*this);
}
protected:
const Graph& graph;
};
template<class Graph, class V, class E>
struct GraphPrinter: public EdgePrinter<Graph,E>
{
GraphPrinter( const Graph& g )
: EdgePrinter<Graph,E>(g)
{}
const GraphPrinter& operator () ( std::ostream& out ) const
{
PropertyPrinter<Graph, V> printNode(this->graph);
out << "v"<<std::endl;
BGL_FORALL_VERTICES_T(v, this->graph, Graph) {
printNode(out,v);
out << std::endl;
}
EdgePrinter<Graph,E>::operator ()( out );
return (*this);
}
};
template<class Graph, class E>
struct GraphPrinter<Graph,no_property,E>
: public EdgePrinter<Graph,E>
{
GraphPrinter( const Graph& g )
: EdgePrinter<Graph,E>(g)
{}
const GraphPrinter& operator () ( std::ostream& out ) const
{
out << "n "<< num_vertices(this->graph) << std::endl;
EdgePrinter<Graph,E>::operator ()( out );
return (*this);
}
};
// graph printer
//=========================================================================
// user methods
/// input stream for reading a graph
template<class Graph, class VP, class EP, class VPS, class EPS>
std::istream& operator >> ( std::istream& in, GraphParser<Graph,VP,EP,VPS,EPS> gp )
{
gp(in);
return in;
}
/// graph parser for given subsets of internal vertex and edge properties
template<class EL, class VL, class D, class VP, class EP, class GP, class VPS, class EPS>
GraphParser<adjacency_list<EL,VL,D,VP,EP,GP>,VP,EP,VPS,EPS>
read( adjacency_list<EL,VL,D,VP,EP,GP>& g, VPS vps, EPS eps )
{
return GraphParser<adjacency_list<EL,VL,D,VP,EP,GP>,VP,EP,VPS,EPS>(&g);
}
/// graph parser for all internal vertex and edge properties
template<class EL, class VL, class D, class VP, class EP, class GP>
GraphParser<adjacency_list<EL,VL,D,VP,EP,GP>,VP,EP,VP,EP>
read( adjacency_list<EL,VL,D,VP,EP,GP>& g )
{
return GraphParser<adjacency_list<EL,VL,D,VP,EP,GP>,VP,EP,VP,EP>(&g);
}
/// output stream for writing a graph
template<class Graph, class VP, class EP>
std::ostream& operator << ( std::ostream& out, const GraphPrinter<Graph,VP,EP>& gp )
{
gp(out);
return out;
}
/// write the graph with given property subsets
template<class EL, class VL, class D, class VP, class EP, class GP, class VPS, class EPS>
GraphPrinter<adjacency_list<EL,VL,D,VP,EP,GP>,VPS,EPS>
write( const adjacency_list<EL,VL,D,VP,EP,GP>& g, VPS, EPS )
{
return GraphPrinter<adjacency_list<EL,VL,D,VP,EP,GP>,VPS,EPS>(g);
}
/// write the graph with all internal vertex and edge properties
template<class EL, class VL, class D, class VP, class EP, class GP>
GraphPrinter<adjacency_list<EL,VL,D,VP,EP,GP>,VP,EP>
write( const adjacency_list<EL,VL,D,VP,EP,GP>& g )
{
return GraphPrinter<adjacency_list<EL,VL,D,VP,EP,GP>,VP,EP>(g);
}
// user methods
//=========================================================================
}// boost
#endif
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,564 @@
//
//=======================================================================
// Copyright (c) 2004 Kristopher Beevers
//
// 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_GRAPH_ASTAR_SEARCH_HPP
#define BOOST_GRAPH_ASTAR_SEARCH_HPP
#include <functional>
#include <vector>
#include <boost/limits.hpp>
#include <boost/throw_exception.hpp>
#include <boost/graph/named_function_params.hpp>
#include <boost/graph/relax.hpp>
#include <boost/graph/exception.hpp>
#include <boost/graph/breadth_first_search.hpp>
#include <boost/graph/iteration_macros.hpp>
#include <boost/graph/detail/d_ary_heap.hpp>
#include <boost/graph/property_maps/constant_property_map.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/property_map/vector_property_map.hpp>
#include <boost/property_map/function_property_map.hpp>
#include <boost/concept/assert.hpp>
namespace boost {
template <class Heuristic, class Graph>
struct AStarHeuristicConcept {
void constraints()
{
BOOST_CONCEPT_ASSERT(( CopyConstructibleConcept<Heuristic> ));
h(u);
}
Heuristic h;
typename graph_traits<Graph>::vertex_descriptor u;
};
template <class Graph, class CostType>
class astar_heuristic : public std::unary_function<
typename graph_traits<Graph>::vertex_descriptor, CostType>
{
public:
typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
astar_heuristic() {}
CostType operator()(Vertex u) { return static_cast<CostType>(0); }
};
template <class Visitor, class Graph>
struct AStarVisitorConcept {
void constraints()
{
BOOST_CONCEPT_ASSERT(( CopyConstructibleConcept<Visitor> ));
vis.initialize_vertex(u, g);
vis.discover_vertex(u, g);
vis.examine_vertex(u, g);
vis.examine_edge(e, g);
vis.edge_relaxed(e, g);
vis.edge_not_relaxed(e, g);
vis.black_target(e, g);
vis.finish_vertex(u, g);
}
Visitor vis;
Graph g;
typename graph_traits<Graph>::vertex_descriptor u;
typename graph_traits<Graph>::edge_descriptor e;
};
template <class Visitors = null_visitor>
class astar_visitor : public bfs_visitor<Visitors> {
public:
astar_visitor() {}
astar_visitor(Visitors vis)
: bfs_visitor<Visitors>(vis) {}
template <class Edge, class Graph>
void edge_relaxed(Edge e, const Graph& g) {
invoke_visitors(this->m_vis, e, g, on_edge_relaxed());
}
template <class Edge, class Graph>
void edge_not_relaxed(Edge e, const Graph& g) {
invoke_visitors(this->m_vis, e, g, on_edge_not_relaxed());
}
private:
template <class Edge, class Graph>
void tree_edge(Edge e, const Graph& g) {}
template <class Edge, class Graph>
void non_tree_edge(Edge e, const Graph& g) {}
};
template <class Visitors>
astar_visitor<Visitors>
make_astar_visitor(Visitors vis) {
return astar_visitor<Visitors>(vis);
}
typedef astar_visitor<> default_astar_visitor;
namespace detail {
template <class AStarHeuristic, class UniformCostVisitor,
class UpdatableQueue, class PredecessorMap,
class CostMap, class DistanceMap, class WeightMap,
class ColorMap, class BinaryFunction,
class BinaryPredicate>
struct astar_bfs_visitor
{
typedef typename property_traits<CostMap>::value_type C;
typedef typename property_traits<ColorMap>::value_type ColorValue;
typedef color_traits<ColorValue> Color;
typedef typename property_traits<DistanceMap>::value_type distance_type;
astar_bfs_visitor(AStarHeuristic h, UniformCostVisitor vis,
UpdatableQueue& Q, PredecessorMap p,
CostMap c, DistanceMap d, WeightMap w,
ColorMap col, BinaryFunction combine,
BinaryPredicate compare, C zero)
: m_h(h), m_vis(vis), m_Q(Q), m_predecessor(p), m_cost(c),
m_distance(d), m_weight(w), m_color(col),
m_combine(combine), m_compare(compare), m_zero(zero) {}
template <class Vertex, class Graph>
void initialize_vertex(Vertex u, const Graph& g) {
m_vis.initialize_vertex(u, g);
}
template <class Vertex, class Graph>
void discover_vertex(Vertex u, const Graph& g) {
m_vis.discover_vertex(u, g);
}
template <class Vertex, class Graph>
void examine_vertex(Vertex u, const Graph& g) {
m_vis.examine_vertex(u, g);
}
template <class Vertex, class Graph>
void finish_vertex(Vertex u, const Graph& g) {
m_vis.finish_vertex(u, g);
}
template <class Edge, class Graph>
void examine_edge(Edge e, const Graph& g) {
if (m_compare(get(m_weight, e), m_zero))
BOOST_THROW_EXCEPTION(negative_edge());
m_vis.examine_edge(e, g);
}
template <class Edge, class Graph>
void non_tree_edge(Edge, const Graph&) {}
template <class Edge, class Graph>
void tree_edge(Edge e, const Graph& g) {
using boost::get;
bool m_decreased =
relax(e, g, m_weight, m_predecessor, m_distance,
m_combine, m_compare);
if(m_decreased) {
m_vis.edge_relaxed(e, g);
put(m_cost, target(e, g),
m_combine(get(m_distance, target(e, g)),
m_h(target(e, g))));
} else
m_vis.edge_not_relaxed(e, g);
}
template <class Edge, class Graph>
void gray_target(Edge e, const Graph& g) {
using boost::get;
bool m_decreased =
relax(e, g, m_weight, m_predecessor, m_distance,
m_combine, m_compare);
if(m_decreased) {
put(m_cost, target(e, g),
m_combine(get(m_distance, target(e, g)),
m_h(target(e, g))));
m_Q.update(target(e, g));
m_vis.edge_relaxed(e, g);
} else
m_vis.edge_not_relaxed(e, g);
}
template <class Edge, class Graph>
void black_target(Edge e, const Graph& g) {
using boost::get;
bool m_decreased =
relax(e, g, m_weight, m_predecessor, m_distance,
m_combine, m_compare);
if(m_decreased) {
m_vis.edge_relaxed(e, g);
put(m_cost, target(e, g),
m_combine(get(m_distance, target(e, g)),
m_h(target(e, g))));
m_Q.push(target(e, g));
put(m_color, target(e, g), Color::gray());
m_vis.black_target(e, g);
} else
m_vis.edge_not_relaxed(e, g);
}
AStarHeuristic m_h;
UniformCostVisitor m_vis;
UpdatableQueue& m_Q;
PredecessorMap m_predecessor;
CostMap m_cost;
DistanceMap m_distance;
WeightMap m_weight;
ColorMap m_color;
BinaryFunction m_combine;
BinaryPredicate m_compare;
C m_zero;
};
} // namespace detail
template <typename VertexListGraph, typename AStarHeuristic,
typename AStarVisitor, typename PredecessorMap,
typename CostMap, typename DistanceMap,
typename WeightMap, typename ColorMap,
typename VertexIndexMap,
typename CompareFunction, typename CombineFunction,
typename CostInf, typename CostZero>
inline void
astar_search_no_init
(const VertexListGraph &g,
typename graph_traits<VertexListGraph>::vertex_descriptor s,
AStarHeuristic h, AStarVisitor vis,
PredecessorMap predecessor, CostMap cost,
DistanceMap distance, WeightMap weight,
ColorMap color, VertexIndexMap index_map,
CompareFunction compare, CombineFunction combine,
CostInf /*inf*/, CostZero zero)
{
typedef typename graph_traits<VertexListGraph>::vertex_descriptor
Vertex;
typedef boost::vector_property_map<std::size_t, VertexIndexMap> IndexInHeapMap;
IndexInHeapMap index_in_heap(index_map);
typedef d_ary_heap_indirect<Vertex, 4, IndexInHeapMap, CostMap, CompareFunction>
MutableQueue;
MutableQueue Q(cost, index_in_heap, compare);
detail::astar_bfs_visitor<AStarHeuristic, AStarVisitor,
MutableQueue, PredecessorMap, CostMap, DistanceMap,
WeightMap, ColorMap, CombineFunction, CompareFunction>
bfs_vis(h, vis, Q, predecessor, cost, distance, weight,
color, combine, compare, zero);
breadth_first_visit(g, s, Q, bfs_vis, color);
}
namespace graph_detail {
template <typename A, typename B>
struct select1st {
typedef std::pair<A, B> argument_type;
typedef A result_type;
A operator()(const std::pair<A, B>& p) const {return p.first;}
};
}
template <typename VertexListGraph, typename AStarHeuristic,
typename AStarVisitor, typename PredecessorMap,
typename CostMap, typename DistanceMap,
typename WeightMap,
typename CompareFunction, typename CombineFunction,
typename CostInf, typename CostZero>
inline void
astar_search_no_init_tree
(const VertexListGraph &g,
typename graph_traits<VertexListGraph>::vertex_descriptor s,
AStarHeuristic h, AStarVisitor vis,
PredecessorMap predecessor, CostMap cost,
DistanceMap distance, WeightMap weight,
CompareFunction compare, CombineFunction combine,
CostInf /*inf*/, CostZero zero)
{
typedef typename graph_traits<VertexListGraph>::vertex_descriptor
Vertex;
typedef typename property_traits<DistanceMap>::value_type Distance;
typedef d_ary_heap_indirect<
std::pair<Distance, Vertex>,
4,
null_property_map<std::pair<Distance, Vertex>, std::size_t>,
function_property_map<graph_detail::select1st<Distance, Vertex>, std::pair<Distance, Vertex> >,
CompareFunction>
MutableQueue;
MutableQueue Q(
make_function_property_map<std::pair<Distance, Vertex> >(graph_detail::select1st<Distance, Vertex>()),
null_property_map<std::pair<Distance, Vertex>, std::size_t>(),
compare);
vis.discover_vertex(s, g);
Q.push(std::make_pair(get(cost, s), s));
while (!Q.empty()) {
Vertex v;
Distance v_rank;
boost::tie(v_rank, v) = Q.top();
Q.pop();
vis.examine_vertex(v, g);
BGL_FORALL_OUTEDGES_T(v, e, g, VertexListGraph) {
Vertex w = target(e, g);
vis.examine_edge(e, g);
Distance e_weight = get(weight, e);
if (compare(e_weight, zero))
BOOST_THROW_EXCEPTION(negative_edge());
bool decreased =
relax(e, g, weight, predecessor, distance,
combine, compare);
Distance w_d = combine(get(distance, v), e_weight);
if (decreased) {
vis.edge_relaxed(e, g);
Distance w_rank = combine(get(distance, w), h(w));
put(cost, w, w_rank);
vis.discover_vertex(w, g);
Q.push(std::make_pair(w_rank, w));
} else {
vis.edge_not_relaxed(e, g);
}
}
vis.finish_vertex(v, g);
}
}
// Non-named parameter interface
template <typename VertexListGraph, typename AStarHeuristic,
typename AStarVisitor, typename PredecessorMap,
typename CostMap, typename DistanceMap,
typename WeightMap, typename VertexIndexMap,
typename ColorMap,
typename CompareFunction, typename CombineFunction,
typename CostInf, typename CostZero>
inline void
astar_search
(const VertexListGraph &g,
typename graph_traits<VertexListGraph>::vertex_descriptor s,
AStarHeuristic h, AStarVisitor vis,
PredecessorMap predecessor, CostMap cost,
DistanceMap distance, WeightMap weight,
VertexIndexMap index_map, ColorMap color,
CompareFunction compare, CombineFunction combine,
CostInf inf, CostZero zero)
{
typedef typename property_traits<ColorMap>::value_type ColorValue;
typedef color_traits<ColorValue> Color;
typename graph_traits<VertexListGraph>::vertex_iterator ui, ui_end;
for (boost::tie(ui, ui_end) = vertices(g); ui != ui_end; ++ui) {
put(color, *ui, Color::white());
put(distance, *ui, inf);
put(cost, *ui, inf);
put(predecessor, *ui, *ui);
vis.initialize_vertex(*ui, g);
}
put(distance, s, zero);
put(cost, s, h(s));
astar_search_no_init
(g, s, h, vis, predecessor, cost, distance, weight,
color, index_map, compare, combine, inf, zero);
}
// Non-named parameter interface
template <typename VertexListGraph, typename AStarHeuristic,
typename AStarVisitor, typename PredecessorMap,
typename CostMap, typename DistanceMap,
typename WeightMap,
typename CompareFunction, typename CombineFunction,
typename CostInf, typename CostZero>
inline void
astar_search_tree
(const VertexListGraph &g,
typename graph_traits<VertexListGraph>::vertex_descriptor s,
AStarHeuristic h, AStarVisitor vis,
PredecessorMap predecessor, CostMap cost,
DistanceMap distance, WeightMap weight,
CompareFunction compare, CombineFunction combine,
CostInf inf, CostZero zero)
{
typename graph_traits<VertexListGraph>::vertex_iterator ui, ui_end;
for (boost::tie(ui, ui_end) = vertices(g); ui != ui_end; ++ui) {
put(distance, *ui, inf);
put(cost, *ui, inf);
put(predecessor, *ui, *ui);
vis.initialize_vertex(*ui, g);
}
put(distance, s, zero);
put(cost, s, h(s));
astar_search_no_init_tree
(g, s, h, vis, predecessor, cost, distance, weight,
compare, combine, inf, zero);
}
// Named parameter interfaces
template <typename VertexListGraph,
typename AStarHeuristic,
typename P, typename T, typename R>
void
astar_search
(const VertexListGraph &g,
typename graph_traits<VertexListGraph>::vertex_descriptor s,
AStarHeuristic h, const bgl_named_params<P, T, R>& params)
{
using namespace boost::graph::keywords;
typedef bgl_named_params<P, T, R> params_type;
BOOST_GRAPH_DECLARE_CONVERTED_PARAMETERS(params_type, params)
// Distance type is the value type of the distance map if there is one,
// otherwise the value type of the weight map.
typedef
typename detail::override_const_property_result<
arg_pack_type, tag::weight_map, edge_weight_t, VertexListGraph>::type
weight_map_type;
typedef typename boost::property_traits<weight_map_type>::value_type W;
typedef
typename detail::map_maker<VertexListGraph, arg_pack_type, tag::distance_map, W>::map_type
distance_map_type;
typedef typename boost::property_traits<distance_map_type>::value_type D;
const D inf = arg_pack[_distance_inf | (std::numeric_limits<D>::max)()];
astar_search
(g, s, h,
arg_pack[_visitor | make_astar_visitor(null_visitor())],
arg_pack[_predecessor_map | dummy_property_map()],
detail::make_property_map_from_arg_pack_gen<tag::rank_map, D>(D())(g, arg_pack),
detail::make_property_map_from_arg_pack_gen<tag::distance_map, W>(W())(g, arg_pack),
detail::override_const_property(arg_pack, _weight_map, g, edge_weight),
detail::override_const_property(arg_pack, _vertex_index_map, g, vertex_index),
detail::make_color_map_from_arg_pack(g, arg_pack),
arg_pack[_distance_compare | std::less<D>()],
arg_pack[_distance_combine | closed_plus<D>(inf)],
inf,
arg_pack[_distance_zero | D()]);
}
// Named parameter interfaces
template <typename VertexListGraph,
typename AStarHeuristic,
typename P, typename T, typename R>
void
astar_search_tree
(const VertexListGraph &g,
typename graph_traits<VertexListGraph>::vertex_descriptor s,
AStarHeuristic h, const bgl_named_params<P, T, R>& params)
{
using namespace boost::graph::keywords;
typedef bgl_named_params<P, T, R> params_type;
BOOST_GRAPH_DECLARE_CONVERTED_PARAMETERS(params_type, params)
// Distance type is the value type of the distance map if there is one,
// otherwise the value type of the weight map.
typedef
typename detail::override_const_property_result<
arg_pack_type, tag::weight_map, edge_weight_t, VertexListGraph>::type
weight_map_type;
typedef typename boost::property_traits<weight_map_type>::value_type W;
typedef
typename detail::map_maker<VertexListGraph, arg_pack_type, tag::distance_map, W>::map_type
distance_map_type;
typedef typename boost::property_traits<distance_map_type>::value_type D;
const D inf = arg_pack[_distance_inf | (std::numeric_limits<D>::max)()];
astar_search_tree
(g, s, h,
arg_pack[_visitor | make_astar_visitor(null_visitor())],
arg_pack[_predecessor_map | dummy_property_map()],
detail::make_property_map_from_arg_pack_gen<tag::rank_map, D>(D())(g, arg_pack),
detail::make_property_map_from_arg_pack_gen<tag::distance_map, W>(W())(g, arg_pack),
detail::override_const_property(arg_pack, _weight_map, g, edge_weight),
arg_pack[_distance_compare | std::less<D>()],
arg_pack[_distance_combine | closed_plus<D>(inf)],
inf,
arg_pack[_distance_zero | D()]);
}
template <typename VertexListGraph,
typename AStarHeuristic,
typename P, typename T, typename R>
void
astar_search_no_init
(const VertexListGraph &g,
typename graph_traits<VertexListGraph>::vertex_descriptor s,
AStarHeuristic h, const bgl_named_params<P, T, R>& params)
{
using namespace boost::graph::keywords;
typedef bgl_named_params<P, T, R> params_type;
BOOST_GRAPH_DECLARE_CONVERTED_PARAMETERS(params_type, params)
typedef
typename detail::override_const_property_result<
arg_pack_type, tag::weight_map, edge_weight_t, VertexListGraph>::type
weight_map_type;
typedef typename boost::property_traits<weight_map_type>::value_type D;
const D inf = arg_pack[_distance_inf | (std::numeric_limits<D>::max)()];
astar_search_no_init
(g, s, h,
arg_pack[_visitor | make_astar_visitor(null_visitor())],
arg_pack[_predecessor_map | dummy_property_map()],
detail::make_property_map_from_arg_pack_gen<tag::rank_map, D>(D())(g, arg_pack),
detail::make_property_map_from_arg_pack_gen<tag::distance_map, D>(D())(g, arg_pack),
detail::override_const_property(arg_pack, _weight_map, g, edge_weight),
detail::make_color_map_from_arg_pack(g, arg_pack),
detail::override_const_property(arg_pack, _vertex_index_map, g, vertex_index),
arg_pack[_distance_compare | std::less<D>()],
arg_pack[_distance_combine | closed_plus<D>(inf)],
inf,
arg_pack[_distance_zero | D()]);
}
template <typename VertexListGraph,
typename AStarHeuristic,
typename P, typename T, typename R>
void
astar_search_no_init_tree
(const VertexListGraph &g,
typename graph_traits<VertexListGraph>::vertex_descriptor s,
AStarHeuristic h, const bgl_named_params<P, T, R>& params)
{
using namespace boost::graph::keywords;
typedef bgl_named_params<P, T, R> params_type;
BOOST_GRAPH_DECLARE_CONVERTED_PARAMETERS(params_type, params)
typedef
typename detail::override_const_property_result<
arg_pack_type, tag::weight_map, edge_weight_t, VertexListGraph>::type
weight_map_type;
typedef typename boost::property_traits<weight_map_type>::value_type D;
const D inf = arg_pack[_distance_inf | (std::numeric_limits<D>::max)()];
astar_search_no_init_tree
(g, s, h,
arg_pack[_visitor | make_astar_visitor(null_visitor())],
arg_pack[_predecessor_map | dummy_property_map()],
detail::make_property_map_from_arg_pack_gen<tag::rank_map, D>(D())(g, arg_pack),
detail::make_property_map_from_arg_pack_gen<tag::distance_map, D>(D())(g, arg_pack),
detail::override_const_property(arg_pack, _weight_map, g, edge_weight),
arg_pack[_distance_compare | std::less<D>()],
arg_pack[_distance_combine | closed_plus<D>(inf)],
inf,
arg_pack[_distance_zero | D()]);
}
} // namespace boost
#endif // BOOST_GRAPH_ASTAR_SEARCH_HPP
@@ -0,0 +1,87 @@
// Copyright (c) Jeremy Siek 2001, Marc Wintermantel 2002
//
// 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_GRAPH_BANDWIDTH_HPP
#define BOOST_GRAPH_BANDWIDTH_HPP
#include <algorithm> // for std::min and std::max
#include <boost/config.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/detail/numeric_traits.hpp>
namespace boost {
template <typename Graph, typename VertexIndexMap>
typename graph_traits<Graph>::vertices_size_type
ith_bandwidth(typename graph_traits<Graph>::vertex_descriptor i,
const Graph& g,
VertexIndexMap index)
{
BOOST_USING_STD_MAX();
using std::abs;
typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type;
vertices_size_type b = 0;
typename graph_traits<Graph>::out_edge_iterator e, end;
for (boost::tie(e, end) = out_edges(i, g); e != end; ++e) {
int f_i = get(index, i);
int f_j = get(index, target(*e, g));
b = max BOOST_PREVENT_MACRO_SUBSTITUTION (b, vertices_size_type(abs(f_i - f_j)));
}
return b;
}
template <typename Graph>
typename graph_traits<Graph>::vertices_size_type
ith_bandwidth(typename graph_traits<Graph>::vertex_descriptor i,
const Graph& g)
{
return ith_bandwidth(i, g, get(vertex_index, g));
}
template <typename Graph, typename VertexIndexMap>
typename graph_traits<Graph>::vertices_size_type
bandwidth(const Graph& g, VertexIndexMap index)
{
BOOST_USING_STD_MAX();
using std::abs;
typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type;
vertices_size_type b = 0;
typename graph_traits<Graph>::edge_iterator i, end;
for (boost::tie(i, end) = edges(g); i != end; ++i) {
int f_i = get(index, source(*i, g));
int f_j = get(index, target(*i, g));
b = max BOOST_PREVENT_MACRO_SUBSTITUTION (b, vertices_size_type(abs(f_i - f_j)));
}
return b;
}
template <typename Graph>
typename graph_traits<Graph>::vertices_size_type
bandwidth(const Graph& g)
{
return bandwidth(g, get(vertex_index, g));
}
template <typename Graph, typename VertexIndexMap>
typename graph_traits<Graph>::vertices_size_type
edgesum(const Graph& g, VertexIndexMap index_map)
{
typedef typename graph_traits<Graph>::vertices_size_type size_type;
typedef typename detail::numeric_traits<size_type>::difference_type diff_t;
size_type sum = 0;
typename graph_traits<Graph>::edge_iterator i, end;
for (boost::tie(i, end) = edges(g); i != end; ++i) {
diff_t f_u = get(index_map, source(*i, g));
diff_t f_v = get(index_map, target(*i, g));
using namespace std; // to call abs() unqualified
sum += abs(f_u - f_v);
}
return sum;
}
} // namespace boost
#endif // BOOST_GRAPH_BANDWIDTH_HPP
@@ -0,0 +1,166 @@
// Copyright 2004 The Trustees of Indiana University.
// 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)
// Authors: Douglas Gregor
// Andrew Lumsdaine
#ifndef BOOST_GRAPH_BETWEENNESS_CENTRALITY_CLUSTERING_HPP
#define BOOST_GRAPH_BETWEENNESS_CENTRALITY_CLUSTERING_HPP
#include <boost/graph/betweenness_centrality.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/graph_utility.hpp>
#include <boost/pending/indirect_cmp.hpp>
#include <algorithm>
#include <vector>
#include <boost/property_map/property_map.hpp>
namespace boost {
/** Threshold termination function for the betweenness centrality
* clustering algorithm.
*/
template<typename T>
struct bc_clustering_threshold
{
typedef T centrality_type;
/// Terminate clustering when maximum absolute edge centrality is
/// below the given threshold.
explicit bc_clustering_threshold(T threshold)
: threshold(threshold), dividend(1.0) {}
/**
* Terminate clustering when the maximum edge centrality is below
* the given threshold.
*
* @param threshold the threshold value
*
* @param g the graph on which the threshold will be calculated
*
* @param normalize when true, the threshold is compared against the
* normalized edge centrality based on the input graph; otherwise,
* the threshold is compared against the absolute edge centrality.
*/
template<typename Graph>
bc_clustering_threshold(T threshold, const Graph& g, bool normalize = true)
: threshold(threshold), dividend(1.0)
{
if (normalize) {
typename graph_traits<Graph>::vertices_size_type n = num_vertices(g);
dividend = T((n - 1) * (n - 2)) / T(2);
}
}
/** Returns true when the given maximum edge centrality (potentially
* normalized) falls below the threshold.
*/
template<typename Graph, typename Edge>
bool operator()(T max_centrality, Edge, const Graph&)
{
return (max_centrality / dividend) < threshold;
}
protected:
T threshold;
T dividend;
};
/** Graph clustering based on edge betweenness centrality.
*
* This algorithm implements graph clustering based on edge
* betweenness centrality. It is an iterative algorithm, where in each
* step it compute the edge betweenness centrality (via @ref
* brandes_betweenness_centrality) and removes the edge with the
* maximum betweenness centrality. The @p done function object
* determines when the algorithm terminates (the edge found when the
* algorithm terminates will not be removed).
*
* @param g The graph on which clustering will be performed. The type
* of this parameter (@c MutableGraph) must be a model of the
* VertexListGraph, IncidenceGraph, EdgeListGraph, and Mutable Graph
* concepts.
*
* @param done The function object that indicates termination of the
* algorithm. It must be a ternary function object thats accepts the
* maximum centrality, the descriptor of the edge that will be
* removed, and the graph @p g.
*
* @param edge_centrality (UTIL/OUT) The property map that will store
* the betweenness centrality for each edge. When the algorithm
* terminates, it will contain the edge centralities for the
* graph. The type of this property map must model the
* ReadWritePropertyMap concept. Defaults to an @c
* iterator_property_map whose value type is
* @c Done::centrality_type and using @c get(edge_index, g) for the
* index map.
*
* @param vertex_index (IN) The property map that maps vertices to
* indices in the range @c [0, num_vertices(g)). This type of this
* property map must model the ReadablePropertyMap concept and its
* value type must be an integral type. Defaults to
* @c get(vertex_index, g).
*/
template<typename MutableGraph, typename Done, typename EdgeCentralityMap,
typename VertexIndexMap>
void
betweenness_centrality_clustering(MutableGraph& g, Done done,
EdgeCentralityMap edge_centrality,
VertexIndexMap vertex_index)
{
typedef typename property_traits<EdgeCentralityMap>::value_type
centrality_type;
typedef typename graph_traits<MutableGraph>::edge_iterator edge_iterator;
typedef typename graph_traits<MutableGraph>::edge_descriptor edge_descriptor;
typedef typename graph_traits<MutableGraph>::vertices_size_type
vertices_size_type;
if (has_no_edges(g)) return;
// Function object that compares the centrality of edges
indirect_cmp<EdgeCentralityMap, std::less<centrality_type> >
cmp(edge_centrality);
bool is_done;
do {
brandes_betweenness_centrality(g,
edge_centrality_map(edge_centrality)
.vertex_index_map(vertex_index));
std::pair<edge_iterator, edge_iterator> edges_iters = edges(g);
edge_descriptor e = *max_element(edges_iters.first, edges_iters.second, cmp);
is_done = done(get(edge_centrality, e), e, g);
if (!is_done) remove_edge(e, g);
} while (!is_done && !has_no_edges(g));
}
/**
* \overload
*/
template<typename MutableGraph, typename Done, typename EdgeCentralityMap>
void
betweenness_centrality_clustering(MutableGraph& g, Done done,
EdgeCentralityMap edge_centrality)
{
betweenness_centrality_clustering(g, done, edge_centrality,
get(vertex_index, g));
}
/**
* \overload
*/
template<typename MutableGraph, typename Done>
void
betweenness_centrality_clustering(MutableGraph& g, Done done)
{
typedef typename Done::centrality_type centrality_type;
std::vector<centrality_type> edge_centrality(num_edges(g));
betweenness_centrality_clustering(g, done,
make_iterator_property_map(edge_centrality.begin(), get(edge_index, g)),
get(vertex_index, g));
}
} // end namespace boost
#endif // BOOST_GRAPH_BETWEENNESS_CENTRALITY_CLUSTERING_HPP
@@ -0,0 +1,242 @@
//
//=======================================================================
// 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)
//=======================================================================
//
/*
This file implements the function
template <class EdgeListGraph, class Size, class P, class T, class R>
bool bellman_ford_shortest_paths(EdgeListGraph& g, Size N,
const bgl_named_params<P, T, R>& params)
*/
#ifndef BOOST_GRAPH_BELLMAN_FORD_SHORTEST_PATHS_HPP
#define BOOST_GRAPH_BELLMAN_FORD_SHORTEST_PATHS_HPP
#include <boost/config.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/graph_concepts.hpp>
#include <boost/graph/properties.hpp>
#include <boost/graph/relax.hpp>
#include <boost/graph/visitors.hpp>
#include <boost/graph/named_function_params.hpp>
#include <boost/concept/assert.hpp>
namespace boost {
template <class Visitor, class Graph>
struct BellmanFordVisitorConcept {
void constraints() {
BOOST_CONCEPT_ASSERT(( CopyConstructibleConcept<Visitor> ));
vis.examine_edge(e, g);
vis.edge_relaxed(e, g);
vis.edge_not_relaxed(e, g);
vis.edge_minimized(e, g);
vis.edge_not_minimized(e, g);
}
Visitor vis;
Graph g;
typename graph_traits<Graph>::edge_descriptor e;
};
template <class Visitors = null_visitor>
class bellman_visitor {
public:
bellman_visitor() { }
bellman_visitor(Visitors vis) : m_vis(vis) { }
template <class Edge, class Graph>
void examine_edge(Edge u, Graph& g) {
invoke_visitors(m_vis, u, g, on_examine_edge());
}
template <class Edge, class Graph>
void edge_relaxed(Edge u, Graph& g) {
invoke_visitors(m_vis, u, g, on_edge_relaxed());
}
template <class Edge, class Graph>
void edge_not_relaxed(Edge u, Graph& g) {
invoke_visitors(m_vis, u, g, on_edge_not_relaxed());
}
template <class Edge, class Graph>
void edge_minimized(Edge u, Graph& g) {
invoke_visitors(m_vis, u, g, on_edge_minimized());
}
template <class Edge, class Graph>
void edge_not_minimized(Edge u, Graph& g) {
invoke_visitors(m_vis, u, g, on_edge_not_minimized());
}
protected:
Visitors m_vis;
};
template <class Visitors>
bellman_visitor<Visitors>
make_bellman_visitor(Visitors vis) {
return bellman_visitor<Visitors>(vis);
}
typedef bellman_visitor<> default_bellman_visitor;
template <class EdgeListGraph, class Size, class WeightMap,
class PredecessorMap, class DistanceMap,
class BinaryFunction, class BinaryPredicate,
class BellmanFordVisitor>
bool bellman_ford_shortest_paths(EdgeListGraph& g, Size N,
WeightMap weight,
PredecessorMap pred,
DistanceMap distance,
BinaryFunction combine,
BinaryPredicate compare,
BellmanFordVisitor v)
{
BOOST_CONCEPT_ASSERT(( EdgeListGraphConcept<EdgeListGraph> ));
typedef graph_traits<EdgeListGraph> GTraits;
typedef typename GTraits::edge_descriptor Edge;
typedef typename GTraits::vertex_descriptor Vertex;
BOOST_CONCEPT_ASSERT(( ReadWritePropertyMapConcept<DistanceMap, Vertex> ));
BOOST_CONCEPT_ASSERT(( ReadablePropertyMapConcept<WeightMap, Edge> ));
typedef typename property_traits<DistanceMap>::value_type D_value;
typedef typename property_traits<WeightMap>::value_type W_value;
typename GTraits::edge_iterator i, end;
for (Size k = 0; k < N; ++k) {
bool at_least_one_edge_relaxed = false;
for (boost::tie(i, end) = edges(g); i != end; ++i) {
v.examine_edge(*i, g);
if (relax(*i, g, weight, pred, distance, combine, compare)) {
at_least_one_edge_relaxed = true;
v.edge_relaxed(*i, g);
} else
v.edge_not_relaxed(*i, g);
}
if (!at_least_one_edge_relaxed)
break;
}
for (boost::tie(i, end) = edges(g); i != end; ++i)
if (compare(combine(get(distance, source(*i, g)), get(weight, *i)),
get(distance, target(*i,g))))
{
v.edge_not_minimized(*i, g);
return false;
} else
v.edge_minimized(*i, g);
return true;
}
namespace detail {
template<typename VertexAndEdgeListGraph, typename Size,
typename WeightMap, typename PredecessorMap, typename DistanceMap,
typename P, typename T, typename R>
bool
bellman_dispatch2
(VertexAndEdgeListGraph& g,
typename graph_traits<VertexAndEdgeListGraph>::vertex_descriptor s,
Size N, WeightMap weight, PredecessorMap pred, DistanceMap distance,
const bgl_named_params<P, T, R>& params)
{
typedef typename property_traits<DistanceMap>::value_type D;
bellman_visitor<> null_vis;
typedef typename property_traits<WeightMap>::value_type weight_type;
typename graph_traits<VertexAndEdgeListGraph>::vertex_iterator v, v_end;
for (boost::tie(v, v_end) = vertices(g); v != v_end; ++v) {
put(distance, *v, (std::numeric_limits<weight_type>::max)());
put(pred, *v, *v);
}
put(distance, s, weight_type(0));
return bellman_ford_shortest_paths
(g, N, weight, pred, distance,
choose_param(get_param(params, distance_combine_t()),
closed_plus<D>()),
choose_param(get_param(params, distance_compare_t()),
std::less<D>()),
choose_param(get_param(params, graph_visitor),
null_vis)
);
}
template<typename VertexAndEdgeListGraph, typename Size,
typename WeightMap, typename PredecessorMap, typename DistanceMap,
typename P, typename T, typename R>
bool
bellman_dispatch2
(VertexAndEdgeListGraph& g,
param_not_found,
Size N, WeightMap weight, PredecessorMap pred, DistanceMap distance,
const bgl_named_params<P, T, R>& params)
{
typedef typename property_traits<DistanceMap>::value_type D;
bellman_visitor<> null_vis;
return bellman_ford_shortest_paths
(g, N, weight, pred, distance,
choose_param(get_param(params, distance_combine_t()),
closed_plus<D>()),
choose_param(get_param(params, distance_compare_t()),
std::less<D>()),
choose_param(get_param(params, graph_visitor),
null_vis)
);
}
template <class EdgeListGraph, class Size, class WeightMap,
class DistanceMap, class P, class T, class R>
bool bellman_dispatch(EdgeListGraph& g, Size N,
WeightMap weight, DistanceMap distance,
const bgl_named_params<P, T, R>& params)
{
dummy_property_map dummy_pred;
return
detail::bellman_dispatch2
(g,
get_param(params, root_vertex_t()),
N, weight,
choose_param(get_param(params, vertex_predecessor), dummy_pred),
distance,
params);
}
} // namespace detail
template <class EdgeListGraph, class Size, class P, class T, class R>
bool bellman_ford_shortest_paths
(EdgeListGraph& g, Size N,
const bgl_named_params<P, T, R>& params)
{
return detail::bellman_dispatch
(g, N,
choose_const_pmap(get_param(params, edge_weight), g, edge_weight),
choose_pmap(get_param(params, vertex_distance), g, vertex_distance),
params);
}
template <class EdgeListGraph, class Size>
bool bellman_ford_shortest_paths(EdgeListGraph& g, Size N)
{
bgl_named_params<int,int> params(0);
return bellman_ford_shortest_paths(g, N, params);
}
template <class VertexAndEdgeListGraph, class P, class T, class R>
bool bellman_ford_shortest_paths
(VertexAndEdgeListGraph& g,
const bgl_named_params<P, T, R>& params)
{
BOOST_CONCEPT_ASSERT(( VertexListGraphConcept<VertexAndEdgeListGraph> ));
return detail::bellman_dispatch
(g, num_vertices(g),
choose_const_pmap(get_param(params, edge_weight), g, edge_weight),
choose_pmap(get_param(params, vertex_distance), g, vertex_distance),
params);
}
} // namespace boost
#endif // BOOST_GRAPH_BELLMAN_FORD_SHORTEST_PATHS_HPP
@@ -0,0 +1,619 @@
// Copyright 2004 The Trustees of Indiana University.
// 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)
// Authors: Douglas Gregor
// Andrew Lumsdaine
#ifndef BOOST_GRAPH_BRANDES_BETWEENNESS_CENTRALITY_HPP
#define BOOST_GRAPH_BRANDES_BETWEENNESS_CENTRALITY_HPP
#include <stack>
#include <vector>
#include <boost/graph/overloading.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <boost/graph/breadth_first_search.hpp>
#include <boost/graph/relax.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/mpl/if.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/graph/named_function_params.hpp>
#include <algorithm>
namespace boost {
namespace detail { namespace graph {
/**
* Customized visitor passed to Dijkstra's algorithm by Brandes'
* betweenness centrality algorithm. This visitor is responsible for
* keeping track of the order in which vertices are discovered, the
* predecessors on the shortest path(s) to a vertex, and the number
* of shortest paths.
*/
template<typename Graph, typename WeightMap, typename IncomingMap,
typename DistanceMap, typename PathCountMap>
struct brandes_dijkstra_visitor : public bfs_visitor<>
{
typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
brandes_dijkstra_visitor(std::stack<vertex_descriptor>& ordered_vertices,
WeightMap weight,
IncomingMap incoming,
DistanceMap distance,
PathCountMap path_count)
: ordered_vertices(ordered_vertices), weight(weight),
incoming(incoming), distance(distance),
path_count(path_count)
{ }
/**
* Whenever an edge e = (v, w) is relaxed, the incoming edge list
* for w is set to {(v, w)} and the shortest path count of w is set to
* the number of paths that reach {v}.
*/
void edge_relaxed(edge_descriptor e, const Graph& g)
{
vertex_descriptor v = source(e, g), w = target(e, g);
incoming[w].clear();
incoming[w].push_back(e);
put(path_count, w, get(path_count, v));
}
/**
* If an edge e = (v, w) was not relaxed, it may still be the case
* that we've found more equally-short paths, so include {(v, w)} in the
* incoming edges of w and add all of the shortest paths to v to the
* shortest path count of w.
*/
void edge_not_relaxed(edge_descriptor e, const Graph& g)
{
typedef typename property_traits<WeightMap>::value_type weight_type;
typedef typename property_traits<DistanceMap>::value_type distance_type;
vertex_descriptor v = source(e, g), w = target(e, g);
distance_type d_v = get(distance, v), d_w = get(distance, w);
weight_type w_e = get(weight, e);
closed_plus<distance_type> combine;
if (d_w == combine(d_v, w_e)) {
put(path_count, w, get(path_count, w) + get(path_count, v));
incoming[w].push_back(e);
}
}
/// Keep track of vertices as they are reached
void examine_vertex(vertex_descriptor w, const Graph&)
{
ordered_vertices.push(w);
}
private:
std::stack<vertex_descriptor>& ordered_vertices;
WeightMap weight;
IncomingMap incoming;
DistanceMap distance;
PathCountMap path_count;
};
/**
* Function object that calls Dijkstra's shortest paths algorithm
* using the Dijkstra visitor for the Brandes betweenness centrality
* algorithm.
*/
template<typename WeightMap>
struct brandes_dijkstra_shortest_paths
{
brandes_dijkstra_shortest_paths(WeightMap weight_map)
: weight_map(weight_map) { }
template<typename Graph, typename IncomingMap, typename DistanceMap,
typename PathCountMap, typename VertexIndexMap>
void
operator()(Graph& g,
typename graph_traits<Graph>::vertex_descriptor s,
std::stack<typename graph_traits<Graph>::vertex_descriptor>& ov,
IncomingMap incoming,
DistanceMap distance,
PathCountMap path_count,
VertexIndexMap vertex_index)
{
typedef brandes_dijkstra_visitor<Graph, WeightMap, IncomingMap,
DistanceMap, PathCountMap> visitor_type;
visitor_type visitor(ov, weight_map, incoming, distance, path_count);
dijkstra_shortest_paths(g, s,
boost::weight_map(weight_map)
.vertex_index_map(vertex_index)
.distance_map(distance)
.visitor(visitor));
}
private:
WeightMap weight_map;
};
/**
* Function object that invokes breadth-first search for the
* unweighted form of the Brandes betweenness centrality algorithm.
*/
struct brandes_unweighted_shortest_paths
{
/**
* Customized visitor passed to breadth-first search, which
* records predecessor and the number of shortest paths to each
* vertex.
*/
template<typename Graph, typename IncomingMap, typename DistanceMap,
typename PathCountMap>
struct visitor_type : public bfs_visitor<>
{
typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
typedef typename graph_traits<Graph>::vertex_descriptor
vertex_descriptor;
visitor_type(IncomingMap incoming, DistanceMap distance,
PathCountMap path_count,
std::stack<vertex_descriptor>& ordered_vertices)
: incoming(incoming), distance(distance),
path_count(path_count), ordered_vertices(ordered_vertices) { }
/// Keep track of vertices as they are reached
void examine_vertex(vertex_descriptor v, Graph&)
{
ordered_vertices.push(v);
}
/**
* Whenever an edge e = (v, w) is labelled a tree edge, the
* incoming edge list for w is set to {(v, w)} and the shortest
* path count of w is set to the number of paths that reach {v}.
*/
void tree_edge(edge_descriptor e, Graph& g)
{
vertex_descriptor v = source(e, g);
vertex_descriptor w = target(e, g);
put(distance, w, get(distance, v) + 1);
put(path_count, w, get(path_count, v));
incoming[w].push_back(e);
}
/**
* If an edge e = (v, w) is not a tree edge, it may still be the
* case that we've found more equally-short paths, so include (v, w)
* in the incoming edge list of w and add all of the shortest
* paths to v to the shortest path count of w.
*/
void non_tree_edge(edge_descriptor e, Graph& g)
{
vertex_descriptor v = source(e, g);
vertex_descriptor w = target(e, g);
if (get(distance, w) == get(distance, v) + 1) {
put(path_count, w, get(path_count, w) + get(path_count, v));
incoming[w].push_back(e);
}
}
private:
IncomingMap incoming;
DistanceMap distance;
PathCountMap path_count;
std::stack<vertex_descriptor>& ordered_vertices;
};
template<typename Graph, typename IncomingMap, typename DistanceMap,
typename PathCountMap, typename VertexIndexMap>
void
operator()(Graph& g,
typename graph_traits<Graph>::vertex_descriptor s,
std::stack<typename graph_traits<Graph>::vertex_descriptor>& ov,
IncomingMap incoming,
DistanceMap distance,
PathCountMap path_count,
VertexIndexMap vertex_index)
{
typedef typename graph_traits<Graph>::vertex_descriptor
vertex_descriptor;
visitor_type<Graph, IncomingMap, DistanceMap, PathCountMap>
visitor(incoming, distance, path_count, ov);
std::vector<default_color_type>
colors(num_vertices(g), color_traits<default_color_type>::white());
boost::queue<vertex_descriptor> Q;
breadth_first_visit(g, s, Q, visitor,
make_iterator_property_map(colors.begin(),
vertex_index));
}
};
// When the edge centrality map is a dummy property map, no
// initialization is needed.
template<typename Iter>
inline void
init_centrality_map(std::pair<Iter, Iter>, dummy_property_map) { }
// When we have a real edge centrality map, initialize all of the
// centralities to zero.
template<typename Iter, typename Centrality>
void
init_centrality_map(std::pair<Iter, Iter> keys, Centrality centrality_map)
{
typedef typename property_traits<Centrality>::value_type
centrality_type;
while (keys.first != keys.second) {
put(centrality_map, *keys.first, centrality_type(0));
++keys.first;
}
}
// When the edge centrality map is a dummy property map, no update
// is performed.
template<typename Key, typename T>
inline void
update_centrality(dummy_property_map, const Key&, const T&) { }
// When we have a real edge centrality map, add the value to the map
template<typename CentralityMap, typename Key, typename T>
inline void
update_centrality(CentralityMap centrality_map, Key k, const T& x)
{ put(centrality_map, k, get(centrality_map, k) + x); }
template<typename Iter>
inline void
divide_centrality_by_two(std::pair<Iter, Iter>, dummy_property_map) {}
template<typename Iter, typename CentralityMap>
inline void
divide_centrality_by_two(std::pair<Iter, Iter> keys,
CentralityMap centrality_map)
{
typename property_traits<CentralityMap>::value_type two(2);
while (keys.first != keys.second) {
put(centrality_map, *keys.first, get(centrality_map, *keys.first) / two);
++keys.first;
}
}
template<typename Graph, typename CentralityMap, typename EdgeCentralityMap,
typename IncomingMap, typename DistanceMap,
typename DependencyMap, typename PathCountMap,
typename VertexIndexMap, typename ShortestPaths>
void
brandes_betweenness_centrality_impl(const Graph& g,
CentralityMap centrality, // C_B
EdgeCentralityMap edge_centrality_map,
IncomingMap incoming, // P
DistanceMap distance, // d
DependencyMap dependency, // delta
PathCountMap path_count, // sigma
VertexIndexMap vertex_index,
ShortestPaths shortest_paths)
{
typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
typedef typename graph_traits<Graph>::edge_iterator edge_iterator;
typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
// Initialize centrality
init_centrality_map(vertices(g), centrality);
init_centrality_map(edges(g), edge_centrality_map);
std::stack<vertex_descriptor> ordered_vertices;
vertex_iterator s, s_end;
for (boost::tie(s, s_end) = vertices(g); s != s_end; ++s) {
// Initialize for this iteration
vertex_iterator w, w_end;
for (boost::tie(w, w_end) = vertices(g); w != w_end; ++w) {
incoming[*w].clear();
put(path_count, *w, 0);
put(dependency, *w, 0);
}
put(path_count, *s, 1);
// Execute the shortest paths algorithm. This will be either
// Dijkstra's algorithm or a customized breadth-first search,
// depending on whether the graph is weighted or unweighted.
shortest_paths(g, *s, ordered_vertices, incoming, distance,
path_count, vertex_index);
while (!ordered_vertices.empty()) {
vertex_descriptor w = ordered_vertices.top();
ordered_vertices.pop();
typedef typename property_traits<IncomingMap>::value_type
incoming_type;
typedef typename incoming_type::iterator incoming_iterator;
typedef typename property_traits<DependencyMap>::value_type
dependency_type;
for (incoming_iterator vw = incoming[w].begin();
vw != incoming[w].end(); ++vw) {
vertex_descriptor v = source(*vw, g);
dependency_type factor = dependency_type(get(path_count, v))
/ dependency_type(get(path_count, w));
factor *= (dependency_type(1) + get(dependency, w));
put(dependency, v, get(dependency, v) + factor);
update_centrality(edge_centrality_map, *vw, factor);
}
if (w != *s) {
update_centrality(centrality, w, get(dependency, w));
}
}
}
typedef typename graph_traits<Graph>::directed_category directed_category;
const bool is_undirected =
is_convertible<directed_category*, undirected_tag*>::value;
if (is_undirected) {
divide_centrality_by_two(vertices(g), centrality);
divide_centrality_by_two(edges(g), edge_centrality_map);
}
}
} } // end namespace detail::graph
template<typename Graph, typename CentralityMap, typename EdgeCentralityMap,
typename IncomingMap, typename DistanceMap,
typename DependencyMap, typename PathCountMap,
typename VertexIndexMap>
void
brandes_betweenness_centrality(const Graph& g,
CentralityMap centrality, // C_B
EdgeCentralityMap edge_centrality_map,
IncomingMap incoming, // P
DistanceMap distance, // d
DependencyMap dependency, // delta
PathCountMap path_count, // sigma
VertexIndexMap vertex_index
BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,vertex_list_graph_tag))
{
detail::graph::brandes_unweighted_shortest_paths shortest_paths;
detail::graph::brandes_betweenness_centrality_impl(g, centrality,
edge_centrality_map,
incoming, distance,
dependency, path_count,
vertex_index,
shortest_paths);
}
template<typename Graph, typename CentralityMap, typename EdgeCentralityMap,
typename IncomingMap, typename DistanceMap,
typename DependencyMap, typename PathCountMap,
typename VertexIndexMap, typename WeightMap>
void
brandes_betweenness_centrality(const Graph& g,
CentralityMap centrality, // C_B
EdgeCentralityMap edge_centrality_map,
IncomingMap incoming, // P
DistanceMap distance, // d
DependencyMap dependency, // delta
PathCountMap path_count, // sigma
VertexIndexMap vertex_index,
WeightMap weight_map
BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,vertex_list_graph_tag))
{
detail::graph::brandes_dijkstra_shortest_paths<WeightMap>
shortest_paths(weight_map);
detail::graph::brandes_betweenness_centrality_impl(g, centrality,
edge_centrality_map,
incoming, distance,
dependency, path_count,
vertex_index,
shortest_paths);
}
namespace detail { namespace graph {
template<typename Graph, typename CentralityMap, typename EdgeCentralityMap,
typename WeightMap, typename VertexIndexMap>
void
brandes_betweenness_centrality_dispatch2(const Graph& g,
CentralityMap centrality,
EdgeCentralityMap edge_centrality_map,
WeightMap weight_map,
VertexIndexMap vertex_index)
{
typedef typename graph_traits<Graph>::degree_size_type degree_size_type;
typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
typedef typename mpl::if_c<(is_same<CentralityMap,
dummy_property_map>::value),
EdgeCentralityMap,
CentralityMap>::type a_centrality_map;
typedef typename property_traits<a_centrality_map>::value_type
centrality_type;
typename graph_traits<Graph>::vertices_size_type V = num_vertices(g);
std::vector<std::vector<edge_descriptor> > incoming(V);
std::vector<centrality_type> distance(V);
std::vector<centrality_type> dependency(V);
std::vector<degree_size_type> path_count(V);
brandes_betweenness_centrality(
g, centrality, edge_centrality_map,
make_iterator_property_map(incoming.begin(), vertex_index),
make_iterator_property_map(distance.begin(), vertex_index),
make_iterator_property_map(dependency.begin(), vertex_index),
make_iterator_property_map(path_count.begin(), vertex_index),
vertex_index,
weight_map);
}
template<typename Graph, typename CentralityMap, typename EdgeCentralityMap,
typename VertexIndexMap>
void
brandes_betweenness_centrality_dispatch2(const Graph& g,
CentralityMap centrality,
EdgeCentralityMap edge_centrality_map,
VertexIndexMap vertex_index)
{
typedef typename graph_traits<Graph>::degree_size_type degree_size_type;
typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
typedef typename mpl::if_c<(is_same<CentralityMap,
dummy_property_map>::value),
EdgeCentralityMap,
CentralityMap>::type a_centrality_map;
typedef typename property_traits<a_centrality_map>::value_type
centrality_type;
typename graph_traits<Graph>::vertices_size_type V = num_vertices(g);
std::vector<std::vector<edge_descriptor> > incoming(V);
std::vector<centrality_type> distance(V);
std::vector<centrality_type> dependency(V);
std::vector<degree_size_type> path_count(V);
brandes_betweenness_centrality(
g, centrality, edge_centrality_map,
make_iterator_property_map(incoming.begin(), vertex_index),
make_iterator_property_map(distance.begin(), vertex_index),
make_iterator_property_map(dependency.begin(), vertex_index),
make_iterator_property_map(path_count.begin(), vertex_index),
vertex_index);
}
template<typename WeightMap>
struct brandes_betweenness_centrality_dispatch1
{
template<typename Graph, typename CentralityMap,
typename EdgeCentralityMap, typename VertexIndexMap>
static void
run(const Graph& g, CentralityMap centrality,
EdgeCentralityMap edge_centrality_map, VertexIndexMap vertex_index,
WeightMap weight_map)
{
brandes_betweenness_centrality_dispatch2(g, centrality, edge_centrality_map,
weight_map, vertex_index);
}
};
template<>
struct brandes_betweenness_centrality_dispatch1<param_not_found>
{
template<typename Graph, typename CentralityMap,
typename EdgeCentralityMap, typename VertexIndexMap>
static void
run(const Graph& g, CentralityMap centrality,
EdgeCentralityMap edge_centrality_map, VertexIndexMap vertex_index,
param_not_found)
{
brandes_betweenness_centrality_dispatch2(g, centrality, edge_centrality_map,
vertex_index);
}
};
template <typename T>
struct is_bgl_named_params {
BOOST_STATIC_CONSTANT(bool, value = false);
};
template <typename Param, typename Tag, typename Rest>
struct is_bgl_named_params<bgl_named_params<Param, Tag, Rest> > {
BOOST_STATIC_CONSTANT(bool, value = true);
};
} } // end namespace detail::graph
template<typename Graph, typename Param, typename Tag, typename Rest>
void
brandes_betweenness_centrality(const Graph& g,
const bgl_named_params<Param,Tag,Rest>& params
BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,vertex_list_graph_tag))
{
typedef bgl_named_params<Param,Tag,Rest> named_params;
typedef typename get_param_type<edge_weight_t, named_params>::type ew;
detail::graph::brandes_betweenness_centrality_dispatch1<ew>::run(
g,
choose_param(get_param(params, vertex_centrality),
dummy_property_map()),
choose_param(get_param(params, edge_centrality),
dummy_property_map()),
choose_const_pmap(get_param(params, vertex_index), g, vertex_index),
get_param(params, edge_weight));
}
// disable_if is required to work around problem with MSVC 7.1 (it seems to not
// get partial ordering getween this overload and the previous one correct)
template<typename Graph, typename CentralityMap>
typename disable_if<detail::graph::is_bgl_named_params<CentralityMap>,
void>::type
brandes_betweenness_centrality(const Graph& g, CentralityMap centrality
BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,vertex_list_graph_tag))
{
detail::graph::brandes_betweenness_centrality_dispatch2(
g, centrality, dummy_property_map(), get(vertex_index, g));
}
template<typename Graph, typename CentralityMap, typename EdgeCentralityMap>
void
brandes_betweenness_centrality(const Graph& g, CentralityMap centrality,
EdgeCentralityMap edge_centrality_map
BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,vertex_list_graph_tag))
{
detail::graph::brandes_betweenness_centrality_dispatch2(
g, centrality, edge_centrality_map, get(vertex_index, g));
}
/**
* Converts "absolute" betweenness centrality (as computed by the
* brandes_betweenness_centrality algorithm) in the centrality map
* into "relative" centrality. The result is placed back into the
* given centrality map.
*/
template<typename Graph, typename CentralityMap>
void
relative_betweenness_centrality(const Graph& g, CentralityMap centrality)
{
typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
typedef typename property_traits<CentralityMap>::value_type centrality_type;
typename graph_traits<Graph>::vertices_size_type n = num_vertices(g);
centrality_type factor = centrality_type(2)/centrality_type(n*n - 3*n + 2);
vertex_iterator v, v_end;
for (boost::tie(v, v_end) = vertices(g); v != v_end; ++v) {
put(centrality, *v, factor * get(centrality, *v));
}
}
// Compute the central point dominance of a graph.
template<typename Graph, typename CentralityMap>
typename property_traits<CentralityMap>::value_type
central_point_dominance(const Graph& g, CentralityMap centrality
BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,vertex_list_graph_tag))
{
using std::max;
typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
typedef typename property_traits<CentralityMap>::value_type centrality_type;
typename graph_traits<Graph>::vertices_size_type n = num_vertices(g);
// Find max centrality
centrality_type max_centrality(0);
vertex_iterator v, v_end;
for (boost::tie(v, v_end) = vertices(g); v != v_end; ++v) {
max_centrality = (max)(max_centrality, get(centrality, *v));
}
// Compute central point dominance
centrality_type sum(0);
for (boost::tie(v, v_end) = vertices(g); v != v_end; ++v) {
sum += (max_centrality - get(centrality, *v));
}
return sum/(n-1);
}
} // end namespace boost
#endif // BOOST_GRAPH_BRANDES_BETWEENNESS_CENTRALITY_HPP
@@ -0,0 +1,417 @@
// Copyright (c) Jeremy Siek 2001
// Copyright (c) Douglas Gregor 2004
//
// 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)
// NOTE: this final is generated by libs/graph/doc/biconnected_components.w
#ifndef BOOST_GRAPH_BICONNECTED_COMPONENTS_HPP
#define BOOST_GRAPH_BICONNECTED_COMPONENTS_HPP
#include <stack>
#include <vector>
#include <algorithm> // for std::min and std::max
#include <boost/config.hpp>
#include <boost/limits.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/graph_concepts.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/graph/depth_first_search.hpp>
#include <boost/graph/graph_utility.hpp>
#include <boost/concept/assert.hpp>
#include <boost/assert.hpp>
namespace boost
{
namespace detail
{
template<typename ComponentMap, typename DiscoverTimeMap,
typename LowPointMap, typename PredecessorMap,
typename OutputIterator, typename Stack,
typename ArticulationVector, typename IndexMap,
typename DFSVisitor>
struct biconnected_components_visitor : public dfs_visitor<>
{
biconnected_components_visitor
(ComponentMap comp, std::size_t& c,
std::size_t& children_of_root, DiscoverTimeMap dtm,
std::size_t& dfs_time, LowPointMap lowpt, PredecessorMap pred,
OutputIterator out, Stack& S,
ArticulationVector& is_articulation_point, IndexMap index_map,
DFSVisitor vis)
: comp(comp), c(c), children_of_root(children_of_root),
dtm(dtm), dfs_time(dfs_time), lowpt(lowpt),
pred(pred), out(out), S(S),
is_articulation_point(is_articulation_point),
index_map(index_map), vis(vis) { }
template <typename Vertex, typename Graph>
void initialize_vertex(const Vertex& u, Graph& g)
{
put(pred, u, u);
vis.initialize_vertex(u, g);
}
template <typename Vertex, typename Graph>
void start_vertex(const Vertex& u, Graph& g)
{
children_of_root = 0;
vis.start_vertex(u, g);
}
template <typename Vertex, typename Graph>
void discover_vertex(const Vertex& u, Graph& g)
{
put(dtm, u, ++dfs_time);
put(lowpt, u, get(dtm, u));
vis.discover_vertex(u, g);
}
template <typename Edge, typename Graph>
void examine_edge(const Edge& e, Graph& g)
{
vis.examine_edge(e, g);
}
template <typename Edge, typename Graph>
void tree_edge(const Edge& e, Graph& g)
{
typename boost::graph_traits<Graph>::vertex_descriptor src = source(e, g);
typename boost::graph_traits<Graph>::vertex_descriptor tgt = target(e, g);
S.push(e);
put(pred, tgt, src);
if ( get(pred, src) == src ) {
++children_of_root;
}
vis.tree_edge(e, g);
}
template <typename Edge, typename Graph>
void back_edge(const Edge& e, Graph& g)
{
BOOST_USING_STD_MIN();
typename boost::graph_traits<Graph>::vertex_descriptor src = source(e, g);
typename boost::graph_traits<Graph>::vertex_descriptor tgt = target(e, g);
if ( tgt != get(pred, src) ) {
S.push(e);
put(lowpt, src,
min BOOST_PREVENT_MACRO_SUBSTITUTION(get(lowpt, src),
get(dtm, tgt)));
}
vis.back_edge(e, g);
}
template <typename Edge, typename Graph>
void forward_or_cross_edge(const Edge& e, Graph& g)
{
vis.forward_or_cross_edge(e, g);
}
template <typename Vertex, typename Graph>
void finish_vertex(const Vertex& u, Graph& g)
{
BOOST_USING_STD_MIN();
Vertex parent = get(pred, u);
if (parent == u) { // Root of tree is special
is_articulation_point[get(index_map, u)] = (children_of_root > 1);
} else {
put(lowpt, parent,
min BOOST_PREVENT_MACRO_SUBSTITUTION(get(lowpt, parent),
get(lowpt, u)));
if ( get(lowpt, u) >= get(dtm, parent) ) {
is_articulation_point[get(index_map, parent)] = true;
while ( get(dtm, source(S.top(), g)) >= get(dtm, u) ) {
put(comp, S.top(), c);
S.pop();
}
BOOST_ASSERT (source(S.top(), g) == parent);
BOOST_ASSERT (target(S.top(), g) == u);
put(comp, S.top(), c);
S.pop();
++c;
}
}
if ( is_articulation_point[get(index_map, u)] ) {
*out++ = u;
}
vis.finish_vertex(u, g);
}
ComponentMap comp;
std::size_t& c;
std::size_t& children_of_root;
DiscoverTimeMap dtm;
std::size_t& dfs_time;
LowPointMap lowpt;
PredecessorMap pred;
OutputIterator out;
Stack& S;
ArticulationVector& is_articulation_point;
IndexMap index_map;
DFSVisitor vis;
};
template<typename Graph, typename ComponentMap, typename OutputIterator,
typename VertexIndexMap, typename DiscoverTimeMap, typename LowPointMap,
typename PredecessorMap, typename DFSVisitor>
std::pair<std::size_t, OutputIterator>
biconnected_components_impl(const Graph & g, ComponentMap comp,
OutputIterator out, VertexIndexMap index_map, DiscoverTimeMap dtm,
LowPointMap lowpt, PredecessorMap pred, DFSVisitor dfs_vis)
{
typedef typename graph_traits<Graph>::vertex_descriptor vertex_t;
typedef typename graph_traits<Graph>::edge_descriptor edge_t;
BOOST_CONCEPT_ASSERT(( VertexListGraphConcept<Graph> ));
BOOST_CONCEPT_ASSERT(( IncidenceGraphConcept<Graph> ));
BOOST_CONCEPT_ASSERT(( WritablePropertyMapConcept<ComponentMap, edge_t> ));
BOOST_CONCEPT_ASSERT(( ReadWritePropertyMapConcept<DiscoverTimeMap,
vertex_t> ));
BOOST_CONCEPT_ASSERT(( ReadWritePropertyMapConcept<LowPointMap, vertex_t > ));
BOOST_CONCEPT_ASSERT(( ReadWritePropertyMapConcept<PredecessorMap,
vertex_t> ));
std::size_t num_components = 0;
std::size_t children_of_root;
std::size_t dfs_time = 0;
std::stack<edge_t> S;
std::vector<char> is_articulation_point(num_vertices(g));
biconnected_components_visitor<ComponentMap, DiscoverTimeMap,
LowPointMap, PredecessorMap, OutputIterator, std::stack<edge_t>,
std::vector<char>, VertexIndexMap, DFSVisitor>
vis(comp, num_components, children_of_root, dtm, dfs_time,
lowpt, pred, out, S, is_articulation_point, index_map, dfs_vis);
depth_first_search(g, visitor(vis).vertex_index_map(index_map));
return std::pair<std::size_t, OutputIterator>(num_components, vis.out);
}
template <typename PredecessorMap>
struct bicomp_dispatch3
{
template<typename Graph, typename ComponentMap, typename OutputIterator,
typename VertexIndexMap, typename DiscoverTimeMap,
typename LowPointMap, class P, class T, class R>
static std::pair<std::size_t, OutputIterator> apply (const Graph & g,
ComponentMap comp, OutputIterator out, VertexIndexMap index_map,
DiscoverTimeMap dtm, LowPointMap lowpt,
const bgl_named_params<P, T, R>& params, PredecessorMap pred)
{
return biconnected_components_impl
(g, comp, out, index_map, dtm, lowpt, pred,
choose_param(get_param(params, graph_visitor),
make_dfs_visitor(null_visitor())));
}
};
template <>
struct bicomp_dispatch3<param_not_found>
{
template<typename Graph, typename ComponentMap, typename OutputIterator,
typename VertexIndexMap, typename DiscoverTimeMap,
typename LowPointMap, class P, class T, class R>
static std::pair<std::size_t, OutputIterator> apply (const Graph & g,
ComponentMap comp, OutputIterator out, VertexIndexMap index_map,
DiscoverTimeMap dtm, LowPointMap lowpt,
const bgl_named_params<P, T, R>& params,
param_not_found)
{
typedef typename graph_traits<Graph>::vertex_descriptor vertex_t;
std::vector<vertex_t> pred(num_vertices(g));
vertex_t vert = graph_traits<Graph>::null_vertex();
return biconnected_components_impl
(g, comp, out, index_map, dtm, lowpt,
make_iterator_property_map(pred.begin(), index_map, vert),
choose_param(get_param(params, graph_visitor),
make_dfs_visitor(null_visitor())));
}
};
template <typename LowPointMap>
struct bicomp_dispatch2
{
template<typename Graph, typename ComponentMap, typename OutputIterator,
typename VertexIndexMap, typename DiscoverTimeMap,
typename P, typename T, typename R>
static std::pair<std::size_t, OutputIterator> apply (const Graph& g,
ComponentMap comp, OutputIterator out, VertexIndexMap index_map,
DiscoverTimeMap dtm, const bgl_named_params<P, T, R>& params,
LowPointMap lowpt)
{
typedef typename get_param_type< vertex_predecessor_t, bgl_named_params<P,T,R> >::type dispatch_type;
return bicomp_dispatch3<dispatch_type>::apply
(g, comp, out, index_map, dtm, lowpt, params,
get_param(params, vertex_predecessor));
}
};
template <>
struct bicomp_dispatch2<param_not_found>
{
template<typename Graph, typename ComponentMap, typename OutputIterator,
typename VertexIndexMap, typename DiscoverTimeMap,
typename P, typename T, typename R>
static std::pair<std::size_t, OutputIterator> apply (const Graph& g,
ComponentMap comp, OutputIterator out, VertexIndexMap index_map,
DiscoverTimeMap dtm, const bgl_named_params<P, T, R>& params,
param_not_found)
{
typedef typename graph_traits<Graph>::vertices_size_type
vertices_size_type;
std::vector<vertices_size_type> lowpt(num_vertices(g));
vertices_size_type vst(0);
typedef typename get_param_type< vertex_predecessor_t, bgl_named_params<P,T,R> >::type dispatch_type;
return bicomp_dispatch3<dispatch_type>::apply
(g, comp, out, index_map, dtm,
make_iterator_property_map(lowpt.begin(), index_map, vst),
params, get_param(params, vertex_predecessor));
}
};
template <typename DiscoverTimeMap>
struct bicomp_dispatch1
{
template<typename Graph, typename ComponentMap, typename OutputIterator,
typename VertexIndexMap, class P, class T, class R>
static std::pair<std::size_t, OutputIterator> apply(const Graph& g,
ComponentMap comp, OutputIterator out, VertexIndexMap index_map,
const bgl_named_params<P, T, R>& params, DiscoverTimeMap dtm)
{
typedef typename get_param_type< vertex_lowpoint_t, bgl_named_params<P,T,R> >::type dispatch_type;
return bicomp_dispatch2<dispatch_type>::apply
(g, comp, out, index_map, dtm, params,
get_param(params, vertex_lowpoint));
}
};
template <>
struct bicomp_dispatch1<param_not_found>
{
template<typename Graph, typename ComponentMap, typename OutputIterator,
typename VertexIndexMap, class P, class T, class R>
static std::pair<std::size_t, OutputIterator> apply(const Graph& g,
ComponentMap comp, OutputIterator out, VertexIndexMap index_map,
const bgl_named_params<P, T, R>& params, param_not_found)
{
typedef typename graph_traits<Graph>::vertices_size_type
vertices_size_type;
std::vector<vertices_size_type> discover_time(num_vertices(g));
vertices_size_type vst(0);
typedef typename get_param_type< vertex_lowpoint_t, bgl_named_params<P,T,R> >::type dispatch_type;
return bicomp_dispatch2<dispatch_type>::apply
(g, comp, out, index_map,
make_iterator_property_map(discover_time.begin(), index_map, vst),
params, get_param(params, vertex_lowpoint));
}
};
}
template<typename Graph, typename ComponentMap, typename OutputIterator,
typename DiscoverTimeMap, typename LowPointMap>
std::pair<std::size_t, OutputIterator>
biconnected_components(const Graph& g, ComponentMap comp,
OutputIterator out, DiscoverTimeMap dtm, LowPointMap lowpt)
{
typedef param_not_found dispatch_type;
return detail::bicomp_dispatch3<dispatch_type>::apply
(g, comp, out,
get(vertex_index, g),
dtm, lowpt,
bgl_named_params<int, buffer_param_t>(0),
param_not_found());
}
template <typename Graph, typename ComponentMap, typename OutputIterator,
typename P, typename T, typename R>
std::pair<std::size_t, OutputIterator>
biconnected_components(const Graph& g, ComponentMap comp, OutputIterator out,
const bgl_named_params<P, T, R>& params)
{
typedef typename get_param_type< vertex_discover_time_t, bgl_named_params<P,T,R> >::type dispatch_type;
return detail::bicomp_dispatch1<dispatch_type>::apply(g, comp, out,
choose_const_pmap(get_param(params, vertex_index), g, vertex_index),
params, get_param(params, vertex_discover_time));
}
template < typename Graph, typename ComponentMap, typename OutputIterator>
std::pair<std::size_t, OutputIterator>
biconnected_components(const Graph& g, ComponentMap comp, OutputIterator out)
{
return biconnected_components(g, comp, out,
bgl_named_params<int, buffer_param_t>(0));
}
namespace graph_detail {
struct dummy_output_iterator
{
typedef std::output_iterator_tag iterator_category;
typedef void value_type;
typedef void pointer;
typedef void difference_type;
struct reference {
template<typename T>
reference& operator=(const T&) { return *this; }
};
reference operator*() const { return reference(); }
dummy_output_iterator& operator++() { return *this; }
dummy_output_iterator operator++(int) { return *this; }
};
} // end namespace graph_detail
template <typename Graph, typename ComponentMap,
typename P, typename T, typename R>
std::size_t
biconnected_components(const Graph& g, ComponentMap comp,
const bgl_named_params<P, T, R>& params)
{
return biconnected_components(g, comp,
graph_detail::dummy_output_iterator(), params).first;
}
template <typename Graph, typename ComponentMap>
std::size_t
biconnected_components(const Graph& g, ComponentMap comp)
{
return biconnected_components(g, comp,
graph_detail::dummy_output_iterator()).first;
}
template<typename Graph, typename OutputIterator,
typename P, typename T, typename R>
OutputIterator
articulation_points(const Graph& g, OutputIterator out,
const bgl_named_params<P, T, R>& params)
{
return biconnected_components(g, dummy_property_map(), out,
params).second;
}
template<typename Graph, typename OutputIterator>
OutputIterator
articulation_points(const Graph& g, OutputIterator out)
{
return biconnected_components(g, dummy_property_map(), out,
bgl_named_params<int, buffer_param_t>(0)).second;
}
} // namespace boost
#endif /* BOOST_GRAPH_BICONNECTED_COMPONENTS_HPP */
@@ -0,0 +1,382 @@
/**
*
* Copyright (c) 2010 Matthias Walter (xammy@xammy.homelinux.net)
*
* Authors: Matthias Walter
*
* 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_GRAPH_BIPARTITE_HPP
#define BOOST_GRAPH_BIPARTITE_HPP
#include <utility>
#include <vector>
#include <exception>
#include <boost/graph/properties.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/depth_first_search.hpp>
#include <boost/graph/one_bit_color_map.hpp>
#include <boost/bind.hpp>
namespace boost {
namespace detail {
/**
* The bipartite_visitor_error is thrown if an edge cannot be colored.
* The witnesses are the edges incident vertices.
*/
template <typename Vertex>
struct bipartite_visitor_error: std::exception
{
std::pair <Vertex, Vertex> witnesses;
bipartite_visitor_error (Vertex a, Vertex b) :
witnesses (a, b)
{
}
const char* what () const throw ()
{
return "Graph is not bipartite.";
}
};
/**
* Functor which colors edges to be non-monochromatic.
*/
template <typename PartitionMap>
struct bipartition_colorize
{
typedef on_tree_edge event_filter;
bipartition_colorize (PartitionMap partition_map) :
partition_map_ (partition_map)
{
}
template <typename Edge, typename Graph>
void operator() (Edge e, const Graph& g)
{
typedef typename graph_traits <Graph>::vertex_descriptor vertex_descriptor_t;
typedef color_traits <typename property_traits <PartitionMap>::value_type> color_traits;
vertex_descriptor_t source_vertex = source (e, g);
vertex_descriptor_t target_vertex = target (e, g);
if (get (partition_map_, source_vertex) == color_traits::white ())
put (partition_map_, target_vertex, color_traits::black ());
else
put (partition_map_, target_vertex, color_traits::white ());
}
private:
PartitionMap partition_map_;
};
/**
* Creates a bipartition_colorize functor which colors edges
* to be non-monochromatic.
*
* @param partition_map Color map for the bipartition
* @return The functor.
*/
template <typename PartitionMap>
inline bipartition_colorize <PartitionMap> colorize_bipartition (PartitionMap partition_map)
{
return bipartition_colorize <PartitionMap> (partition_map);
}
/**
* Functor which tests an edge to be monochromatic.
*/
template <typename PartitionMap>
struct bipartition_check
{
typedef on_back_edge event_filter;
bipartition_check (PartitionMap partition_map) :
partition_map_ (partition_map)
{
}
template <typename Edge, typename Graph>
void operator() (Edge e, const Graph& g)
{
typedef typename graph_traits <Graph>::vertex_descriptor vertex_descriptor_t;
vertex_descriptor_t source_vertex = source (e, g);
vertex_descriptor_t target_vertex = target (e, g);
if (get (partition_map_, source_vertex) == get (partition_map_, target_vertex))
throw bipartite_visitor_error <vertex_descriptor_t> (source_vertex, target_vertex);
}
private:
PartitionMap partition_map_;
};
/**
* Creates a bipartition_check functor which raises an error if a
* monochromatic edge is found.
*
* @param partition_map The map for a bipartition.
* @return The functor.
*/
template <typename PartitionMap>
inline bipartition_check <PartitionMap> check_bipartition (PartitionMap partition_map)
{
return bipartition_check <PartitionMap> (partition_map);
}
/**
* Find the beginning of a common suffix of two sequences
*
* @param sequence1 Pair of bidirectional iterators defining the first sequence.
* @param sequence2 Pair of bidirectional iterators defining the second sequence.
* @return Pair of iterators pointing to the beginning of the common suffix.
*/
template <typename BiDirectionalIterator1, typename BiDirectionalIterator2>
inline std::pair <BiDirectionalIterator1, BiDirectionalIterator2> reverse_mismatch (std::pair <
BiDirectionalIterator1, BiDirectionalIterator1> sequence1, std::pair <BiDirectionalIterator2,
BiDirectionalIterator2> sequence2)
{
if (sequence1.first == sequence1.second || sequence2.first == sequence2.second)
return std::make_pair (sequence1.first, sequence2.first);
BiDirectionalIterator1 iter1 = sequence1.second;
BiDirectionalIterator2 iter2 = sequence2.second;
while (true)
{
--iter1;
--iter2;
if (*iter1 != *iter2)
{
++iter1;
++iter2;
break;
}
if (iter1 == sequence1.first)
break;
if (iter2 == sequence2.first)
break;
}
return std::make_pair (iter1, iter2);
}
}
/**
* Checks a given graph for bipartiteness and fills the given color map with
* white and black according to the bipartition. If the graph is not
* bipartite, the contents of the color map are undefined. Runs in linear
* time in the size of the graph, if access to the property maps is in
* constant time.
*
* @param graph The given graph.
* @param index_map An index map associating vertices with an index.
* @param partition_map A color map to fill with the bipartition.
* @return true if and only if the given graph is bipartite.
*/
template <typename Graph, typename IndexMap, typename PartitionMap>
bool is_bipartite (const Graph& graph, const IndexMap index_map, PartitionMap partition_map)
{
/// General types and variables
typedef typename property_traits <PartitionMap>::value_type partition_color_t;
typedef typename graph_traits <Graph>::vertex_descriptor vertex_descriptor_t;
typedef typename graph_traits <Graph>::vertex_iterator vertex_iterator_t;
/// Declare dfs visitor
// detail::empty_recorder recorder;
// typedef detail::bipartite_visitor <PartitionMap, detail::empty_recorder> dfs_visitor_t;
// dfs_visitor_t dfs_visitor (partition_map, recorder);
/// Call dfs
try
{
depth_first_search (graph, vertex_index_map (index_map).visitor (make_dfs_visitor (std::make_pair (
detail::colorize_bipartition (partition_map), std::make_pair (detail::check_bipartition (partition_map),
put_property (partition_map, color_traits <partition_color_t>::white (), on_start_vertex ()))))));
}
catch (detail::bipartite_visitor_error <vertex_descriptor_t> error)
{
return false;
}
return true;
}
/**
* Checks a given graph for bipartiteness.
*
* @param graph The given graph.
* @param index_map An index map associating vertices with an index.
* @return true if and only if the given graph is bipartite.
*/
template <typename Graph, typename IndexMap>
bool is_bipartite (const Graph& graph, const IndexMap index_map)
{
typedef one_bit_color_map <IndexMap> partition_map_t;
partition_map_t partition_map (num_vertices (graph), index_map);
return is_bipartite (graph, index_map, partition_map);
}
/**
* Checks a given graph for bipartiteness. The graph must
* have an internal vertex_index property. Runs in linear time in the
* size of the graph, if access to the property maps is in constant time.
*
* @param graph The given graph.
* @return true if and only if the given graph is bipartite.
*/
template <typename Graph>
bool is_bipartite (const Graph& graph)
{
return is_bipartite (graph, get (vertex_index, graph));
}
/**
* Checks a given graph for bipartiteness and fills a given color map with
* white and black according to the bipartition. If the graph is not
* bipartite, a sequence of vertices, producing an odd-cycle, is written to
* the output iterator. The final iterator value is returned. Runs in linear
* time in the size of the graph, if access to the property maps is in
* constant time.
*
* @param graph The given graph.
* @param index_map An index map associating vertices with an index.
* @param partition_map A color map to fill with the bipartition.
* @param result An iterator to write the odd-cycle vertices to.
* @return The final iterator value after writing.
*/
template <typename Graph, typename IndexMap, typename PartitionMap, typename OutputIterator>
OutputIterator find_odd_cycle (const Graph& graph, const IndexMap index_map, PartitionMap partition_map,
OutputIterator result)
{
/// General types and variables
typedef typename property_traits <PartitionMap>::value_type partition_color_t;
typedef typename graph_traits <Graph>::vertex_descriptor vertex_descriptor_t;
typedef typename graph_traits <Graph>::vertex_iterator vertex_iterator_t;
vertex_iterator_t vertex_iter, vertex_end;
/// Declare predecessor map
typedef std::vector <vertex_descriptor_t> predecessors_t;
typedef iterator_property_map <typename predecessors_t::iterator, IndexMap, vertex_descriptor_t,
vertex_descriptor_t&> predecessor_map_t;
predecessors_t predecessors (num_vertices (graph), graph_traits <Graph>::null_vertex ());
predecessor_map_t predecessor_map (predecessors.begin (), index_map);
/// Initialize predecessor map
for (boost::tie (vertex_iter, vertex_end) = vertices (graph); vertex_iter != vertex_end; ++vertex_iter)
{
put (predecessor_map, *vertex_iter, *vertex_iter);
}
/// Call dfs
try
{
depth_first_search (graph, vertex_index_map (index_map).visitor (make_dfs_visitor (std::make_pair (
detail::colorize_bipartition (partition_map), std::make_pair (detail::check_bipartition (partition_map),
std::make_pair (put_property (partition_map, color_traits <partition_color_t>::white (),
on_start_vertex ()), record_predecessors (predecessor_map, on_tree_edge ())))))));
}
catch (detail::bipartite_visitor_error <vertex_descriptor_t> error)
{
typedef std::vector <vertex_descriptor_t> path_t;
path_t path1, path2;
vertex_descriptor_t next, current;
/// First path
next = error.witnesses.first;
do
{
current = next;
path1.push_back (current);
next = predecessor_map[current];
}
while (current != next);
/// Second path
next = error.witnesses.second;
do
{
current = next;
path2.push_back (current);
next = predecessor_map[current];
}
while (current != next);
/// Find beginning of common suffix
std::pair <typename path_t::iterator, typename path_t::iterator> mismatch = detail::reverse_mismatch (
std::make_pair (path1.begin (), path1.end ()), std::make_pair (path2.begin (), path2.end ()));
/// Copy the odd-length cycle
result = std::copy (path1.begin (), mismatch.first + 1, result);
return std::reverse_copy (path2.begin (), mismatch.second, result);
}
return result;
}
/**
* Checks a given graph for bipartiteness. If the graph is not bipartite, a
* sequence of vertices, producing an odd-cycle, is written to the output
* iterator. The final iterator value is returned. Runs in linear time in the
* size of the graph, if access to the property maps is in constant time.
*
* @param graph The given graph.
* @param index_map An index map associating vertices with an index.
* @param result An iterator to write the odd-cycle vertices to.
* @return The final iterator value after writing.
*/
template <typename Graph, typename IndexMap, typename OutputIterator>
OutputIterator find_odd_cycle (const Graph& graph, const IndexMap index_map, OutputIterator result)
{
typedef one_bit_color_map <IndexMap> partition_map_t;
partition_map_t partition_map (num_vertices (graph), index_map);
return find_odd_cycle (graph, index_map, partition_map, result);
}
/**
* Checks a given graph for bipartiteness. If the graph is not bipartite, a
* sequence of vertices, producing an odd-cycle, is written to the output
* iterator. The final iterator value is returned. The graph must have an
* internal vertex_index property. Runs in linear time in the size of the
* graph, if access to the property maps is in constant time.
*
* @param graph The given graph.
* @param result An iterator to write the odd-cycle vertices to.
* @return The final iterator value after writing.
*/
template <typename Graph, typename OutputIterator>
OutputIterator find_odd_cycle (const Graph& graph, OutputIterator result)
{
return find_odd_cycle (graph, get (vertex_index, graph), result);
}
}
#endif /// BOOST_GRAPH_BIPARTITE_HPP
@@ -0,0 +1,322 @@
//=======================================================================
// Copyright 2007 Aaron Windsor
//
// 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 __BOYER_MYRVOLD_PLANAR_TEST_HPP__
#define __BOYER_MYRVOLD_PLANAR_TEST_HPP__
#include <boost/graph/planar_detail/boyer_myrvold_impl.hpp>
#include <boost/parameter.hpp>
#include <boost/type_traits.hpp>
#include <boost/mpl/bool.hpp>
namespace boost
{
struct no_kuratowski_subgraph_isolation {};
struct no_planar_embedding {};
namespace boyer_myrvold_params
{
BOOST_PARAMETER_KEYWORD(tag, graph)
BOOST_PARAMETER_KEYWORD(tag, embedding)
BOOST_PARAMETER_KEYWORD(tag, kuratowski_subgraph)
BOOST_PARAMETER_KEYWORD(tag, vertex_index_map)
BOOST_PARAMETER_KEYWORD(tag, edge_index_map)
typedef parameter::parameters< parameter::required<tag::graph>,
tag::embedding,
tag::kuratowski_subgraph,
tag::vertex_index_map,
tag::edge_index_map
> boyer_myrvold_params_t;
namespace core
{
template <typename ArgumentPack>
bool dispatched_boyer_myrvold(ArgumentPack const& args,
mpl::true_,
mpl::true_
)
{
//Dispatch for no planar embedding, no kuratowski subgraph isolation
typedef typename remove_const
<
typename remove_reference
< typename parameter::binding
< ArgumentPack, tag::graph>::type
>::type
>::type graph_t;
typedef typename parameter::binding
< ArgumentPack,
tag::vertex_index_map,
typename property_map
< typename remove_reference<graph_t>::type,
vertex_index_t>::const_type
>::type vertex_index_map_t;
boyer_myrvold_impl
<graph_t,
vertex_index_map_t,
graph::detail::no_old_handles,
graph::detail::no_embedding
>
planarity_tester(args[graph],
args[vertex_index_map |
get(vertex_index, args[graph])
]
);
return planarity_tester.is_planar() ? true : false;
}
template <typename ArgumentPack>
bool dispatched_boyer_myrvold(ArgumentPack const& args,
mpl::true_,
mpl::false_
)
{
//Dispatch for no planar embedding, kuratowski subgraph isolation
typedef typename remove_const
<
typename remove_reference
< typename parameter::binding
< ArgumentPack, tag::graph>::type
>::type
>::type graph_t;
typedef typename parameter::binding
< ArgumentPack,
tag::vertex_index_map,
typename property_map<graph_t, vertex_index_t>::type
>::type vertex_index_map_t;
boyer_myrvold_impl
<graph_t,
vertex_index_map_t,
graph::detail::store_old_handles,
graph::detail::no_embedding
>
planarity_tester(args[graph],
args[vertex_index_map |
get(vertex_index, args[graph])
]
);
if (planarity_tester.is_planar())
return true;
else
{
planarity_tester.extract_kuratowski_subgraph
(args[kuratowski_subgraph],
args[edge_index_map|get(edge_index, args[graph])]
);
return false;
}
}
template <typename ArgumentPack>
bool dispatched_boyer_myrvold(ArgumentPack const& args,
mpl::false_,
mpl::true_
)
{
//Dispatch for planar embedding, no kuratowski subgraph isolation
typedef typename remove_const
<
typename remove_reference
< typename parameter::binding
< ArgumentPack, tag::graph>::type
>::type
>::type graph_t;
typedef typename parameter::binding
< ArgumentPack,
tag::vertex_index_map,
typename property_map<graph_t, vertex_index_t>::type
>::type vertex_index_map_t;
boyer_myrvold_impl
<graph_t,
vertex_index_map_t,
graph::detail::no_old_handles,
#ifdef BOOST_GRAPH_PREFER_STD_LIB
graph::detail::std_list
#else
graph::detail::recursive_lazy_list
#endif
>
planarity_tester(args[graph],
args[vertex_index_map |
get(vertex_index, args[graph])
]
);
if (planarity_tester.is_planar())
{
planarity_tester.make_edge_permutation(args[embedding]);
return true;
}
else
return false;
}
template <typename ArgumentPack>
bool dispatched_boyer_myrvold(ArgumentPack const& args,
mpl::false_,
mpl::false_
)
{
//Dispatch for planar embedding, kuratowski subgraph isolation
typedef typename remove_const
<
typename remove_reference
< typename parameter::binding
< ArgumentPack, tag::graph>::type
>::type
>::type graph_t;
typedef typename parameter::binding
< ArgumentPack,
tag::vertex_index_map,
typename property_map<graph_t, vertex_index_t>::type
>::type vertex_index_map_t;
boyer_myrvold_impl
<graph_t,
vertex_index_map_t,
graph::detail::store_old_handles,
#ifdef BOOST_BGL_PREFER_STD_LIB
graph::detail::std_list
#else
graph::detail::recursive_lazy_list
#endif
>
planarity_tester(args[graph],
args[vertex_index_map |
get(vertex_index, args[graph])
]
);
if (planarity_tester.is_planar())
{
planarity_tester.make_edge_permutation(args[embedding]);
return true;
}
else
{
planarity_tester.extract_kuratowski_subgraph
(args[kuratowski_subgraph],
args[edge_index_map | get(edge_index, args[graph])]
);
return false;
}
}
template <typename ArgumentPack>
bool boyer_myrvold_planarity_test(ArgumentPack const& args)
{
typedef typename parameter::binding
< ArgumentPack,
tag::kuratowski_subgraph,
const no_kuratowski_subgraph_isolation&
>::type
kuratowski_arg_t;
typedef typename parameter::binding
< ArgumentPack,
tag::embedding,
const no_planar_embedding&
>::type
embedding_arg_t;
return dispatched_boyer_myrvold
(args,
boost::is_same
<embedding_arg_t, const no_planar_embedding&>(),
boost::is_same
<kuratowski_arg_t, const no_kuratowski_subgraph_isolation&>()
);
}
} //namespace core
} //namespace boyer_myrvold_params
template <typename A0>
bool boyer_myrvold_planarity_test(A0 const& arg0)
{
return boyer_myrvold_params::core::boyer_myrvold_planarity_test
(boyer_myrvold_params::boyer_myrvold_params_t()(arg0));
}
template <typename A0, typename A1>
// bool boyer_myrvold_planarity_test(A0 const& arg0, A1 const& arg1)
bool boyer_myrvold_planarity_test(A0 const& arg0, A1 const& arg1)
{
return boyer_myrvold_params::core::boyer_myrvold_planarity_test
(boyer_myrvold_params::boyer_myrvold_params_t()(arg0,arg1));
}
template <typename A0, typename A1, typename A2>
bool boyer_myrvold_planarity_test(A0 const& arg0,
A1 const& arg1,
A2 const& arg2
)
{
return boyer_myrvold_params::core::boyer_myrvold_planarity_test
(boyer_myrvold_params::boyer_myrvold_params_t()(arg0,arg1,arg2));
}
template <typename A0, typename A1, typename A2, typename A3>
bool boyer_myrvold_planarity_test(A0 const& arg0,
A1 const& arg1,
A2 const& arg2,
A3 const& arg3
)
{
return boyer_myrvold_params::core::boyer_myrvold_planarity_test
(boyer_myrvold_params::boyer_myrvold_params_t()(arg0,arg1,arg2,arg3));
}
template <typename A0, typename A1, typename A2, typename A3, typename A4>
bool boyer_myrvold_planarity_test(A0 const& arg0,
A1 const& arg1,
A2 const& arg2,
A3 const& arg3,
A4 const& arg4
)
{
return boyer_myrvold_params::core::boyer_myrvold_planarity_test
(boyer_myrvold_params::boyer_myrvold_params_t()
(arg0,arg1,arg2,arg3,arg4)
);
}
}
#endif //__BOYER_MYRVOLD_PLANAR_TEST_HPP__
@@ -0,0 +1,873 @@
// Copyright (c) 2006, Stephan Diederich
//
// This code may be used under either of the following two licences:
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE. OF SUCH DAMAGE.
//
// Or:
//
// 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_BOYKOV_KOLMOGOROV_MAX_FLOW_HPP
#define BOOST_BOYKOV_KOLMOGOROV_MAX_FLOW_HPP
#include <boost/config.hpp>
#include <boost/assert.hpp>
#include <vector>
#include <list>
#include <utility>
#include <iosfwd>
#include <algorithm> // for std::min and std::max
#include <boost/pending/queue.hpp>
#include <boost/limits.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/none_t.hpp>
#include <boost/graph/graph_concepts.hpp>
#include <boost/graph/named_function_params.hpp>
#include <boost/graph/lookup_edge.hpp>
#include <boost/concept/assert.hpp>
// The algorithm impelemented here is described in:
//
// Boykov, Y., Kolmogorov, V. "An Experimental Comparison of Min-Cut/Max-Flow
// Algorithms for Energy Minimization in Vision", In IEEE Transactions on
// Pattern Analysis and Machine Intelligence, vol. 26, no. 9, pp. 1124-1137,
// Sep 2004.
//
// For further reading, also see:
//
// Kolmogorov, V. "Graph Based Algorithms for Scene Reconstruction from Two or
// More Views". PhD thesis, Cornell University, Sep 2003.
namespace boost {
namespace detail {
template <class Graph,
class EdgeCapacityMap,
class ResidualCapacityEdgeMap,
class ReverseEdgeMap,
class PredecessorMap,
class ColorMap,
class DistanceMap,
class IndexMap>
class bk_max_flow {
typedef typename property_traits<EdgeCapacityMap>::value_type tEdgeVal;
typedef graph_traits<Graph> tGraphTraits;
typedef typename tGraphTraits::vertex_iterator vertex_iterator;
typedef typename tGraphTraits::vertex_descriptor vertex_descriptor;
typedef typename tGraphTraits::edge_descriptor edge_descriptor;
typedef typename tGraphTraits::edge_iterator edge_iterator;
typedef typename tGraphTraits::out_edge_iterator out_edge_iterator;
typedef boost::queue<vertex_descriptor> tQueue; //queue of vertices, used in adoption-stage
typedef typename property_traits<ColorMap>::value_type tColorValue;
typedef color_traits<tColorValue> tColorTraits;
typedef typename property_traits<DistanceMap>::value_type tDistanceVal;
public:
bk_max_flow(Graph& g,
EdgeCapacityMap cap,
ResidualCapacityEdgeMap res,
ReverseEdgeMap rev,
PredecessorMap pre,
ColorMap color,
DistanceMap dist,
IndexMap idx,
vertex_descriptor src,
vertex_descriptor sink):
m_g(g),
m_index_map(idx),
m_cap_map(cap),
m_res_cap_map(res),
m_rev_edge_map(rev),
m_pre_map(pre),
m_tree_map(color),
m_dist_map(dist),
m_source(src),
m_sink(sink),
m_active_nodes(),
m_in_active_list_vec(num_vertices(g), false),
m_in_active_list_map(make_iterator_property_map(m_in_active_list_vec.begin(), m_index_map)),
m_has_parent_vec(num_vertices(g), false),
m_has_parent_map(make_iterator_property_map(m_has_parent_vec.begin(), m_index_map)),
m_time_vec(num_vertices(g), 0),
m_time_map(make_iterator_property_map(m_time_vec.begin(), m_index_map)),
m_flow(0),
m_time(1),
m_last_grow_vertex(graph_traits<Graph>::null_vertex()){
// initialize the color-map with gray-values
vertex_iterator vi, v_end;
for(boost::tie(vi, v_end) = vertices(m_g); vi != v_end; ++vi){
set_tree(*vi, tColorTraits::gray());
}
// Initialize flow to zero which means initializing
// the residual capacity equal to the capacity
edge_iterator ei, e_end;
for(boost::tie(ei, e_end) = edges(m_g); ei != e_end; ++ei) {
put(m_res_cap_map, *ei, get(m_cap_map, *ei));
BOOST_ASSERT(get(m_rev_edge_map, get(m_rev_edge_map, *ei)) == *ei); //check if the reverse edge map is build up properly
}
//init the search trees with the two terminals
set_tree(m_source, tColorTraits::black());
set_tree(m_sink, tColorTraits::white());
put(m_time_map, m_source, 1);
put(m_time_map, m_sink, 1);
}
tEdgeVal max_flow(){
//augment direct paths from SOURCE->SINK and SOURCE->VERTEX->SINK
augment_direct_paths();
//start the main-loop
while(true){
bool path_found;
edge_descriptor connecting_edge;
boost::tie(connecting_edge, path_found) = grow(); //find a path from source to sink
if(!path_found){
//we're finished, no more paths were found
break;
}
++m_time;
augment(connecting_edge); //augment that path
adopt(); //rebuild search tree structure
}
return m_flow;
}
// the complete class is protected, as we want access to members in
// derived test-class (see test/boykov_kolmogorov_max_flow_test.cpp)
protected:
void augment_direct_paths(){
// in a first step, we augment all direct paths from source->NODE->sink
// and additionally paths from source->sink. This improves especially
// graphcuts for segmentation, as most of the nodes have source/sink
// connects but shouldn't have an impact on other maxflow problems
// (this is done in grow() anyway)
out_edge_iterator ei, e_end;
for(boost::tie(ei, e_end) = out_edges(m_source, m_g); ei != e_end; ++ei){
edge_descriptor from_source = *ei;
vertex_descriptor current_node = target(from_source, m_g);
if(current_node == m_sink){
tEdgeVal cap = get(m_res_cap_map, from_source);
put(m_res_cap_map, from_source, 0);
m_flow += cap;
continue;
}
edge_descriptor to_sink;
bool is_there;
boost::tie(to_sink, is_there) = lookup_edge(current_node, m_sink, m_g);
if(is_there){
tEdgeVal cap_from_source = get(m_res_cap_map, from_source);
tEdgeVal cap_to_sink = get(m_res_cap_map, to_sink);
if(cap_from_source > cap_to_sink){
set_tree(current_node, tColorTraits::black());
add_active_node(current_node);
set_edge_to_parent(current_node, from_source);
put(m_dist_map, current_node, 1);
put(m_time_map, current_node, 1);
// add stuff to flow and update residuals. we dont need to
// update reverse_edges, as incoming/outgoing edges to/from
// source/sink don't count for max-flow
put(m_res_cap_map, from_source, get(m_res_cap_map, from_source) - cap_to_sink);
put(m_res_cap_map, to_sink, 0);
m_flow += cap_to_sink;
} else if(cap_to_sink > 0){
set_tree(current_node, tColorTraits::white());
add_active_node(current_node);
set_edge_to_parent(current_node, to_sink);
put(m_dist_map, current_node, 1);
put(m_time_map, current_node, 1);
// add stuff to flow and update residuals. we dont need to update
// reverse_edges, as incoming/outgoing edges to/from source/sink
// don't count for max-flow
put(m_res_cap_map, to_sink, get(m_res_cap_map, to_sink) - cap_from_source);
put(m_res_cap_map, from_source, 0);
m_flow += cap_from_source;
}
} else if(get(m_res_cap_map, from_source)){
// there is no sink connect, so we can't augment this path, but to
// avoid adding m_source to the active nodes, we just activate this
// node and set the approciate things
set_tree(current_node, tColorTraits::black());
set_edge_to_parent(current_node, from_source);
put(m_dist_map, current_node, 1);
put(m_time_map, current_node, 1);
add_active_node(current_node);
}
}
for(boost::tie(ei, e_end) = out_edges(m_sink, m_g); ei != e_end; ++ei){
edge_descriptor to_sink = get(m_rev_edge_map, *ei);
vertex_descriptor current_node = source(to_sink, m_g);
if(get(m_res_cap_map, to_sink)){
set_tree(current_node, tColorTraits::white());
set_edge_to_parent(current_node, to_sink);
put(m_dist_map, current_node, 1);
put(m_time_map, current_node, 1);
add_active_node(current_node);
}
}
}
/**
* Returns a pair of an edge and a boolean. if the bool is true, the
* edge is a connection of a found path from s->t , read "the link" and
* source(returnVal, m_g) is the end of the path found in the source-tree
* target(returnVal, m_g) is the beginning of the path found in the sink-tree
*/
std::pair<edge_descriptor, bool> grow(){
BOOST_ASSERT(m_orphans.empty());
vertex_descriptor current_node;
while((current_node = get_next_active_node()) != graph_traits<Graph>::null_vertex()){ //if there is one
BOOST_ASSERT(get_tree(current_node) != tColorTraits::gray() &&
(has_parent(current_node) ||
current_node == m_source ||
current_node == m_sink));
if(get_tree(current_node) == tColorTraits::black()){
//source tree growing
out_edge_iterator ei, e_end;
if(current_node != m_last_grow_vertex){
m_last_grow_vertex = current_node;
boost::tie(m_last_grow_edge_it, m_last_grow_edge_end) = out_edges(current_node, m_g);
}
for(; m_last_grow_edge_it != m_last_grow_edge_end; ++m_last_grow_edge_it) {
edge_descriptor out_edge = *m_last_grow_edge_it;
if(get(m_res_cap_map, out_edge) > 0){ //check if we have capacity left on this edge
vertex_descriptor other_node = target(out_edge, m_g);
if(get_tree(other_node) == tColorTraits::gray()){ //it's a free node
set_tree(other_node, tColorTraits::black()); //aquire other node to our search tree
set_edge_to_parent(other_node, out_edge); //set us as parent
put(m_dist_map, other_node, get(m_dist_map, current_node) + 1); //and update the distance-heuristic
put(m_time_map, other_node, get(m_time_map, current_node));
add_active_node(other_node);
} else if(get_tree(other_node) == tColorTraits::black()) {
// we do this to get shorter paths. check if we are nearer to
// the source as its parent is
if(is_closer_to_terminal(current_node, other_node)){
set_edge_to_parent(other_node, out_edge);
put(m_dist_map, other_node, get(m_dist_map, current_node) + 1);
put(m_time_map, other_node, get(m_time_map, current_node));
}
} else{
BOOST_ASSERT(get_tree(other_node)==tColorTraits::white());
//kewl, found a path from one to the other search tree, return
// the connecting edge in src->sink dir
return std::make_pair(out_edge, true);
}
}
} //for all out-edges
} //source-tree-growing
else{
BOOST_ASSERT(get_tree(current_node) == tColorTraits::white());
out_edge_iterator ei, e_end;
if(current_node != m_last_grow_vertex){
m_last_grow_vertex = current_node;
boost::tie(m_last_grow_edge_it, m_last_grow_edge_end) = out_edges(current_node, m_g);
}
for(; m_last_grow_edge_it != m_last_grow_edge_end; ++m_last_grow_edge_it){
edge_descriptor in_edge = get(m_rev_edge_map, *m_last_grow_edge_it);
if(get(m_res_cap_map, in_edge) > 0){ //check if there is capacity left
vertex_descriptor other_node = source(in_edge, m_g);
if(get_tree(other_node) == tColorTraits::gray()){ //it's a free node
set_tree(other_node, tColorTraits::white()); //aquire that node to our search tree
set_edge_to_parent(other_node, in_edge); //set us as parent
add_active_node(other_node); //activate that node
put(m_dist_map, other_node, get(m_dist_map, current_node) + 1); //set its distance
put(m_time_map, other_node, get(m_time_map, current_node));//and time
} else if(get_tree(other_node) == tColorTraits::white()){
if(is_closer_to_terminal(current_node, other_node)){
//we are closer to the sink than its parent is, so we "adopt" him
set_edge_to_parent(other_node, in_edge);
put(m_dist_map, other_node, get(m_dist_map, current_node) + 1);
put(m_time_map, other_node, get(m_time_map, current_node));
}
} else{
BOOST_ASSERT(get_tree(other_node)==tColorTraits::black());
//kewl, found a path from one to the other search tree,
// return the connecting edge in src->sink dir
return std::make_pair(in_edge, true);
}
}
} //for all out-edges
} //sink-tree growing
//all edges of that node are processed, and no more paths were found.
// remove if from the front of the active queue
finish_node(current_node);
} //while active_nodes not empty
//no active nodes anymore and no path found, we're done
return std::make_pair(edge_descriptor(), false);
}
/**
* augments path from s->t and updates residual graph
* source(e, m_g) is the end of the path found in the source-tree
* target(e, m_g) is the beginning of the path found in the sink-tree
* this phase generates orphans on satured edges, if the attached verts are
* from different search-trees orphans are ordered in distance to
* sink/source. first the farest from the source are front_inserted into
* the orphans list, and after that the sink-tree-orphans are
* front_inserted. when going to adoption stage the orphans are popped_front,
* and so we process the nearest verts to the terminals first
*/
void augment(edge_descriptor e) {
BOOST_ASSERT(get_tree(target(e, m_g)) == tColorTraits::white());
BOOST_ASSERT(get_tree(source(e, m_g)) == tColorTraits::black());
BOOST_ASSERT(m_orphans.empty());
const tEdgeVal bottleneck = find_bottleneck(e);
//now we push the found flow through the path
//for each edge we saturate we have to look for the verts that belong to that edge, one of them becomes an orphans
//now process the connecting edge
put(m_res_cap_map, e, get(m_res_cap_map, e) - bottleneck);
BOOST_ASSERT(get(m_res_cap_map, e) >= 0);
put(m_res_cap_map, get(m_rev_edge_map, e), get(m_res_cap_map, get(m_rev_edge_map, e)) + bottleneck);
//now we follow the path back to the source
vertex_descriptor current_node = source(e, m_g);
while(current_node != m_source){
edge_descriptor pred = get_edge_to_parent(current_node);
put(m_res_cap_map, pred, get(m_res_cap_map, pred) - bottleneck);
BOOST_ASSERT(get(m_res_cap_map, pred) >= 0);
put(m_res_cap_map, get(m_rev_edge_map, pred), get(m_res_cap_map, get(m_rev_edge_map, pred)) + bottleneck);
if(get(m_res_cap_map, pred) == 0){
set_no_parent(current_node);
m_orphans.push_front(current_node);
}
current_node = source(pred, m_g);
}
//then go forward in the sink-tree
current_node = target(e, m_g);
while(current_node != m_sink){
edge_descriptor pred = get_edge_to_parent(current_node);
put(m_res_cap_map, pred, get(m_res_cap_map, pred) - bottleneck);
BOOST_ASSERT(get(m_res_cap_map, pred) >= 0);
put(m_res_cap_map, get(m_rev_edge_map, pred), get(m_res_cap_map, get(m_rev_edge_map, pred)) + bottleneck);
if(get(m_res_cap_map, pred) == 0){
set_no_parent(current_node);
m_orphans.push_front(current_node);
}
current_node = target(pred, m_g);
}
//and add it to the max-flow
m_flow += bottleneck;
}
/**
* returns the bottleneck of a s->t path (end_of_path is last vertex in
* source-tree, begin_of_path is first vertex in sink-tree)
*/
inline tEdgeVal find_bottleneck(edge_descriptor e){
BOOST_USING_STD_MIN();
tEdgeVal minimum_cap = get(m_res_cap_map, e);
vertex_descriptor current_node = source(e, m_g);
//first go back in the source tree
while(current_node != m_source){
edge_descriptor pred = get_edge_to_parent(current_node);
minimum_cap = min BOOST_PREVENT_MACRO_SUBSTITUTION(minimum_cap, get(m_res_cap_map, pred));
current_node = source(pred, m_g);
}
//then go forward in the sink-tree
current_node = target(e, m_g);
while(current_node != m_sink){
edge_descriptor pred = get_edge_to_parent(current_node);
minimum_cap = min BOOST_PREVENT_MACRO_SUBSTITUTION(minimum_cap, get(m_res_cap_map, pred));
current_node = target(pred, m_g);
}
return minimum_cap;
}
/**
* rebuild search trees
* empty the queue of orphans, and find new parents for them or just drop
* them from the search trees
*/
void adopt(){
while(!m_orphans.empty() || !m_child_orphans.empty()){
vertex_descriptor current_node;
if(m_child_orphans.empty()){
//get the next orphan from the main-queue and remove it
current_node = m_orphans.front();
m_orphans.pop_front();
} else{
current_node = m_child_orphans.front();
m_child_orphans.pop();
}
if(get_tree(current_node) == tColorTraits::black()){
//we're in the source-tree
tDistanceVal min_distance = (std::numeric_limits<tDistanceVal>::max)();
edge_descriptor new_parent_edge;
out_edge_iterator ei, e_end;
for(boost::tie(ei, e_end) = out_edges(current_node, m_g); ei != e_end; ++ei){
const edge_descriptor in_edge = get(m_rev_edge_map, *ei);
BOOST_ASSERT(target(in_edge, m_g) == current_node); //we should be the target of this edge
if(get(m_res_cap_map, in_edge) > 0){
vertex_descriptor other_node = source(in_edge, m_g);
if(get_tree(other_node) == tColorTraits::black() && has_source_connect(other_node)){
if(get(m_dist_map, other_node) < min_distance){
min_distance = get(m_dist_map, other_node);
new_parent_edge = in_edge;
}
}
}
}
if(min_distance != (std::numeric_limits<tDistanceVal>::max)()){
set_edge_to_parent(current_node, new_parent_edge);
put(m_dist_map, current_node, min_distance + 1);
put(m_time_map, current_node, m_time);
} else{
put(m_time_map, current_node, 0);
for(boost::tie(ei, e_end) = out_edges(current_node, m_g); ei != e_end; ++ei){
edge_descriptor in_edge = get(m_rev_edge_map, *ei);
vertex_descriptor other_node = source(in_edge, m_g);
if(get_tree(other_node) == tColorTraits::black() && other_node != m_source){
if(get(m_res_cap_map, in_edge) > 0){
add_active_node(other_node);
}
if(has_parent(other_node) && source(get_edge_to_parent(other_node), m_g) == current_node){
//we are the parent of that node
//it has to find a new parent, too
set_no_parent(other_node);
m_child_orphans.push(other_node);
}
}
}
set_tree(current_node, tColorTraits::gray());
} //no parent found
} //source-tree-adoption
else{
//now we should be in the sink-tree, check that...
BOOST_ASSERT(get_tree(current_node) == tColorTraits::white());
out_edge_iterator ei, e_end;
edge_descriptor new_parent_edge;
tDistanceVal min_distance = (std::numeric_limits<tDistanceVal>::max)();
for(boost::tie(ei, e_end) = out_edges(current_node, m_g); ei != e_end; ++ei){
const edge_descriptor out_edge = *ei;
if(get(m_res_cap_map, out_edge) > 0){
const vertex_descriptor other_node = target(out_edge, m_g);
if(get_tree(other_node) == tColorTraits::white() && has_sink_connect(other_node))
if(get(m_dist_map, other_node) < min_distance){
min_distance = get(m_dist_map, other_node);
new_parent_edge = out_edge;
}
}
}
if(min_distance != (std::numeric_limits<tDistanceVal>::max)()){
set_edge_to_parent(current_node, new_parent_edge);
put(m_dist_map, current_node, min_distance + 1);
put(m_time_map, current_node, m_time);
} else{
put(m_time_map, current_node, 0);
for(boost::tie(ei, e_end) = out_edges(current_node, m_g); ei != e_end; ++ei){
const edge_descriptor out_edge = *ei;
const vertex_descriptor other_node = target(out_edge, m_g);
if(get_tree(other_node) == tColorTraits::white() && other_node != m_sink){
if(get(m_res_cap_map, out_edge) > 0){
add_active_node(other_node);
}
if(has_parent(other_node) && target(get_edge_to_parent(other_node), m_g) == current_node){
//we were it's parent, so it has to find a new one, too
set_no_parent(other_node);
m_child_orphans.push(other_node);
}
}
}
set_tree(current_node, tColorTraits::gray());
} //no parent found
} //sink-tree adoption
} //while !orphans.empty()
} //adopt
/**
* return next active vertex if there is one, otherwise a null_vertex
*/
inline vertex_descriptor get_next_active_node(){
while(true){
if(m_active_nodes.empty())
return graph_traits<Graph>::null_vertex();
vertex_descriptor v = m_active_nodes.front();
//if it has no parent, this node can't be active (if its not source or sink)
if(!has_parent(v) && v != m_source && v != m_sink){
m_active_nodes.pop();
put(m_in_active_list_map, v, false);
} else{
BOOST_ASSERT(get_tree(v) == tColorTraits::black() || get_tree(v) == tColorTraits::white());
return v;
}
}
}
/**
* adds v as an active vertex, but only if its not in the list already
*/
inline void add_active_node(vertex_descriptor v){
BOOST_ASSERT(get_tree(v) != tColorTraits::gray());
if(get(m_in_active_list_map, v)){
if (m_last_grow_vertex == v) {
m_last_grow_vertex = graph_traits<Graph>::null_vertex();
}
return;
} else{
put(m_in_active_list_map, v, true);
m_active_nodes.push(v);
}
}
/**
* finish_node removes a node from the front of the active queue (its called in grow phase, if no more paths can be found using this node)
*/
inline void finish_node(vertex_descriptor v){
BOOST_ASSERT(m_active_nodes.front() == v);
m_active_nodes.pop();
put(m_in_active_list_map, v, false);
m_last_grow_vertex = graph_traits<Graph>::null_vertex();
}
/**
* removes a vertex from the queue of active nodes (actually this does nothing,
* but checks if this node has no parent edge, as this is the criteria for
* being no more active)
*/
inline void remove_active_node(vertex_descriptor v){
BOOST_ASSERT(!has_parent(v));
}
/**
* returns the search tree of v; tColorValue::black() for source tree,
* white() for sink tree, gray() for no tree
*/
inline tColorValue get_tree(vertex_descriptor v) const {
return get(m_tree_map, v);
}
/**
* sets search tree of v; tColorValue::black() for source tree, white()
* for sink tree, gray() for no tree
*/
inline void set_tree(vertex_descriptor v, tColorValue t){
put(m_tree_map, v, t);
}
/**
* returns edge to parent vertex of v;
*/
inline edge_descriptor get_edge_to_parent(vertex_descriptor v) const{
return get(m_pre_map, v);
}
/**
* returns true if the edge stored in m_pre_map[v] is a valid entry
*/
inline bool has_parent(vertex_descriptor v) const{
return get(m_has_parent_map, v);
}
/**
* sets edge to parent vertex of v;
*/
inline void set_edge_to_parent(vertex_descriptor v, edge_descriptor f_edge_to_parent){
BOOST_ASSERT(get(m_res_cap_map, f_edge_to_parent) > 0);
put(m_pre_map, v, f_edge_to_parent);
put(m_has_parent_map, v, true);
}
/**
* removes the edge to parent of v (this is done by invalidating the
* entry an additional map)
*/
inline void set_no_parent(vertex_descriptor v){
put(m_has_parent_map, v, false);
}
/**
* checks if vertex v has a connect to the sink-vertex (@var m_sink)
* @param v the vertex which is checked
* @return true if a path to the sink was found, false if not
*/
inline bool has_sink_connect(vertex_descriptor v){
tDistanceVal current_distance = 0;
vertex_descriptor current_vertex = v;
while(true){
if(get(m_time_map, current_vertex) == m_time){
//we found a node which was already checked this round. use it for distance calculations
current_distance += get(m_dist_map, current_vertex);
break;
}
if(current_vertex == m_sink){
put(m_time_map, m_sink, m_time);
break;
}
if(has_parent(current_vertex)){
//it has a parent, so get it
current_vertex = target(get_edge_to_parent(current_vertex), m_g);
++current_distance;
} else{
//no path found
return false;
}
}
current_vertex=v;
while(get(m_time_map, current_vertex) != m_time){
put(m_dist_map, current_vertex, current_distance);
--current_distance;
put(m_time_map, current_vertex, m_time);
current_vertex = target(get_edge_to_parent(current_vertex), m_g);
}
return true;
}
/**
* checks if vertex v has a connect to the source-vertex (@var m_source)
* @param v the vertex which is checked
* @return true if a path to the source was found, false if not
*/
inline bool has_source_connect(vertex_descriptor v){
tDistanceVal current_distance = 0;
vertex_descriptor current_vertex = v;
while(true){
if(get(m_time_map, current_vertex) == m_time){
//we found a node which was already checked this round. use it for distance calculations
current_distance += get(m_dist_map, current_vertex);
break;
}
if(current_vertex == m_source){
put(m_time_map, m_source, m_time);
break;
}
if(has_parent(current_vertex)){
//it has a parent, so get it
current_vertex = source(get_edge_to_parent(current_vertex), m_g);
++current_distance;
} else{
//no path found
return false;
}
}
current_vertex=v;
while(get(m_time_map, current_vertex) != m_time){
put(m_dist_map, current_vertex, current_distance);
--current_distance;
put(m_time_map, current_vertex, m_time);
current_vertex = source(get_edge_to_parent(current_vertex), m_g);
}
return true;
}
/**
* returns true, if p is closer to a terminal than q
*/
inline bool is_closer_to_terminal(vertex_descriptor p, vertex_descriptor q){
//checks the timestamps first, to build no cycles, and after that the real distance
return (get(m_time_map, q) <= get(m_time_map, p) &&
get(m_dist_map, q) > get(m_dist_map, p)+1);
}
////////
// member vars
////////
Graph& m_g;
IndexMap m_index_map;
EdgeCapacityMap m_cap_map;
ResidualCapacityEdgeMap m_res_cap_map;
ReverseEdgeMap m_rev_edge_map;
PredecessorMap m_pre_map; //stores paths found in the growth stage
ColorMap m_tree_map; //maps each vertex into one of the two search tree or none (gray())
DistanceMap m_dist_map; //stores distance to source/sink nodes
vertex_descriptor m_source;
vertex_descriptor m_sink;
tQueue m_active_nodes;
std::vector<bool> m_in_active_list_vec;
iterator_property_map<std::vector<bool>::iterator, IndexMap> m_in_active_list_map;
std::list<vertex_descriptor> m_orphans;
tQueue m_child_orphans; // we use a second queuqe for child orphans, as they are FIFO processed
std::vector<bool> m_has_parent_vec;
iterator_property_map<std::vector<bool>::iterator, IndexMap> m_has_parent_map;
std::vector<long> m_time_vec; //timestamp of each node, used for sink/source-path calculations
iterator_property_map<std::vector<long>::iterator, IndexMap> m_time_map;
tEdgeVal m_flow;
long m_time;
vertex_descriptor m_last_grow_vertex;
out_edge_iterator m_last_grow_edge_it;
out_edge_iterator m_last_grow_edge_end;
};
} //namespace boost::detail
/**
* non-named-parameter version, given everything
* this is the catch all version
*/
template<class Graph,
class CapacityEdgeMap,
class ResidualCapacityEdgeMap,
class ReverseEdgeMap, class PredecessorMap,
class ColorMap,
class DistanceMap,
class IndexMap>
typename property_traits<CapacityEdgeMap>::value_type
boykov_kolmogorov_max_flow(Graph& g,
CapacityEdgeMap cap,
ResidualCapacityEdgeMap res_cap,
ReverseEdgeMap rev_map,
PredecessorMap pre_map,
ColorMap color,
DistanceMap dist,
IndexMap idx,
typename graph_traits<Graph>::vertex_descriptor src,
typename graph_traits<Graph>::vertex_descriptor sink)
{
typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
//as this method is the last one before we instantiate the solver, we do the concept checks here
BOOST_CONCEPT_ASSERT(( VertexListGraphConcept<Graph> )); //to have vertices(), num_vertices(),
BOOST_CONCEPT_ASSERT(( EdgeListGraphConcept<Graph> )); //to have edges()
BOOST_CONCEPT_ASSERT(( IncidenceGraphConcept<Graph> )); //to have source(), target() and out_edges()
BOOST_CONCEPT_ASSERT(( ReadablePropertyMapConcept<CapacityEdgeMap, edge_descriptor> )); //read flow-values from edges
BOOST_CONCEPT_ASSERT(( ReadWritePropertyMapConcept<ResidualCapacityEdgeMap, edge_descriptor> )); //write flow-values to residuals
BOOST_CONCEPT_ASSERT(( ReadablePropertyMapConcept<ReverseEdgeMap, edge_descriptor> )); //read out reverse edges
BOOST_CONCEPT_ASSERT(( ReadWritePropertyMapConcept<PredecessorMap, vertex_descriptor> )); //store predecessor there
BOOST_CONCEPT_ASSERT(( ReadWritePropertyMapConcept<ColorMap, vertex_descriptor> )); //write corresponding tree
BOOST_CONCEPT_ASSERT(( ReadWritePropertyMapConcept<DistanceMap, vertex_descriptor> )); //write distance to source/sink
BOOST_CONCEPT_ASSERT(( ReadablePropertyMapConcept<IndexMap, vertex_descriptor> )); //get index 0...|V|-1
BOOST_ASSERT(num_vertices(g) >= 2 && src != sink);
detail::bk_max_flow<
Graph, CapacityEdgeMap, ResidualCapacityEdgeMap, ReverseEdgeMap,
PredecessorMap, ColorMap, DistanceMap, IndexMap
> algo(g, cap, res_cap, rev_map, pre_map, color, dist, idx, src, sink);
return algo.max_flow();
}
/**
* non-named-parameter version, given capacity, residucal_capacity,
* reverse_edges, and an index map.
*/
template<class Graph,
class CapacityEdgeMap,
class ResidualCapacityEdgeMap,
class ReverseEdgeMap,
class IndexMap>
typename property_traits<CapacityEdgeMap>::value_type
boykov_kolmogorov_max_flow(Graph& g,
CapacityEdgeMap cap,
ResidualCapacityEdgeMap res_cap,
ReverseEdgeMap rev,
IndexMap idx,
typename graph_traits<Graph>::vertex_descriptor src,
typename graph_traits<Graph>::vertex_descriptor sink)
{
typename graph_traits<Graph>::vertices_size_type n_verts = num_vertices(g);
std::vector<typename graph_traits<Graph>::edge_descriptor> predecessor_vec(n_verts);
std::vector<default_color_type> color_vec(n_verts);
std::vector<typename graph_traits<Graph>::vertices_size_type> distance_vec(n_verts);
return
boykov_kolmogorov_max_flow(
g, cap, res_cap, rev,
make_iterator_property_map(predecessor_vec.begin(), idx),
make_iterator_property_map(color_vec.begin(), idx),
make_iterator_property_map(distance_vec.begin(), idx),
idx, src, sink);
}
/**
* non-named-parameter version, some given: capacity, residual_capacity,
* reverse_edges, color_map and an index map. Use this if you are interested in
* the minimum cut, as the color map provides that info.
*/
template<class Graph,
class CapacityEdgeMap,
class ResidualCapacityEdgeMap,
class ReverseEdgeMap,
class ColorMap,
class IndexMap>
typename property_traits<CapacityEdgeMap>::value_type
boykov_kolmogorov_max_flow(Graph& g,
CapacityEdgeMap cap,
ResidualCapacityEdgeMap res_cap,
ReverseEdgeMap rev,
ColorMap color,
IndexMap idx,
typename graph_traits<Graph>::vertex_descriptor src,
typename graph_traits<Graph>::vertex_descriptor sink)
{
typename graph_traits<Graph>::vertices_size_type n_verts = num_vertices(g);
std::vector<typename graph_traits<Graph>::edge_descriptor> predecessor_vec(n_verts);
std::vector<typename graph_traits<Graph>::vertices_size_type> distance_vec(n_verts);
return
boykov_kolmogorov_max_flow(
g, cap, res_cap, rev,
make_iterator_property_map(predecessor_vec.begin(), idx),
color,
make_iterator_property_map(distance_vec.begin(), idx),
idx, src, sink);
}
/**
* named-parameter version, some given
*/
template<class Graph, class P, class T, class R>
typename property_traits<typename property_map<Graph, edge_capacity_t>::const_type>::value_type
boykov_kolmogorov_max_flow(Graph& g,
typename graph_traits<Graph>::vertex_descriptor src,
typename graph_traits<Graph>::vertex_descriptor sink,
const bgl_named_params<P, T, R>& params)
{
return
boykov_kolmogorov_max_flow(
g,
choose_const_pmap(get_param(params, edge_capacity), g, edge_capacity),
choose_pmap(get_param(params, edge_residual_capacity), g, edge_residual_capacity),
choose_const_pmap(get_param(params, edge_reverse), g, edge_reverse),
choose_pmap(get_param(params, vertex_predecessor), g, vertex_predecessor),
choose_pmap(get_param(params, vertex_color), g, vertex_color),
choose_pmap(get_param(params, vertex_distance), g, vertex_distance),
choose_const_pmap(get_param(params, vertex_index), g, vertex_index),
src, sink);
}
/**
* named-parameter version, none given
*/
template<class Graph>
typename property_traits<typename property_map<Graph, edge_capacity_t>::const_type>::value_type
boykov_kolmogorov_max_flow(Graph& g,
typename graph_traits<Graph>::vertex_descriptor src,
typename graph_traits<Graph>::vertex_descriptor sink)
{
bgl_named_params<int, buffer_param_t> params(0); // bogus empty param
return boykov_kolmogorov_max_flow(g, src, sink, params);
}
} // namespace boost
#endif // BOOST_BOYKOV_KOLMOGOROV_MAX_FLOW_HPP
@@ -0,0 +1,408 @@
//
//=======================================================================
// 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_GRAPH_BREADTH_FIRST_SEARCH_HPP
#define BOOST_GRAPH_BREADTH_FIRST_SEARCH_HPP
/*
Breadth First Search Algorithm (Cormen, Leiserson, and Rivest p. 470)
*/
#include <boost/config.hpp>
#include <vector>
#include <boost/pending/queue.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/graph_concepts.hpp>
#include <boost/graph/visitors.hpp>
#include <boost/graph/named_function_params.hpp>
#include <boost/graph/overloading.hpp>
#include <boost/graph/graph_concepts.hpp>
#include <boost/graph/two_bit_color_map.hpp>
#include <boost/concept/assert.hpp>
#ifdef BOOST_GRAPH_USE_MPI
#include <boost/graph/distributed/concepts.hpp>
#endif // BOOST_GRAPH_USE_MPI
namespace boost {
template <class Visitor, class Graph>
struct BFSVisitorConcept {
void constraints() {
BOOST_CONCEPT_ASSERT(( CopyConstructibleConcept<Visitor> ));
vis.initialize_vertex(u, g);
vis.discover_vertex(u, g);
vis.examine_vertex(u, g);
vis.examine_edge(e, g);
vis.tree_edge(e, g);
vis.non_tree_edge(e, g);
vis.gray_target(e, g);
vis.black_target(e, g);
vis.finish_vertex(u, g);
}
Visitor vis;
Graph g;
typename graph_traits<Graph>::vertex_descriptor u;
typename graph_traits<Graph>::edge_descriptor e;
};
// Multiple-source version
template <class IncidenceGraph, class Buffer, class BFSVisitor,
class ColorMap, class SourceIterator>
void breadth_first_visit
(const IncidenceGraph& g,
SourceIterator sources_begin, SourceIterator sources_end,
Buffer& Q, BFSVisitor vis, ColorMap color)
{
BOOST_CONCEPT_ASSERT(( IncidenceGraphConcept<IncidenceGraph> ));
typedef graph_traits<IncidenceGraph> GTraits;
typedef typename GTraits::vertex_descriptor Vertex;
typedef typename GTraits::edge_descriptor Edge;
BOOST_CONCEPT_ASSERT(( BFSVisitorConcept<BFSVisitor, IncidenceGraph> ));
BOOST_CONCEPT_ASSERT(( ReadWritePropertyMapConcept<ColorMap, Vertex> ));
typedef typename property_traits<ColorMap>::value_type ColorValue;
typedef color_traits<ColorValue> Color;
typename GTraits::out_edge_iterator ei, ei_end;
for (; sources_begin != sources_end; ++sources_begin) {
Vertex s = *sources_begin;
put(color, s, Color::gray()); vis.discover_vertex(s, g);
Q.push(s);
}
while (! Q.empty()) {
Vertex u = Q.top(); Q.pop(); vis.examine_vertex(u, g);
for (boost::tie(ei, ei_end) = out_edges(u, g); ei != ei_end; ++ei) {
Vertex v = target(*ei, g); vis.examine_edge(*ei, g);
ColorValue v_color = get(color, v);
if (v_color == Color::white()) { vis.tree_edge(*ei, g);
put(color, v, Color::gray()); vis.discover_vertex(v, g);
Q.push(v);
} else { vis.non_tree_edge(*ei, g);
if (v_color == Color::gray()) vis.gray_target(*ei, g);
else vis.black_target(*ei, g);
}
} // end for
put(color, u, Color::black()); vis.finish_vertex(u, g);
} // end while
} // breadth_first_visit
// Single-source version
template <class IncidenceGraph, class Buffer, class BFSVisitor,
class ColorMap>
void breadth_first_visit
(const IncidenceGraph& g,
typename graph_traits<IncidenceGraph>::vertex_descriptor s,
Buffer& Q, BFSVisitor vis, ColorMap color)
{
typename graph_traits<IncidenceGraph>::vertex_descriptor sources[1] = {s};
breadth_first_visit(g, sources, sources + 1, Q, vis, color);
}
template <class VertexListGraph, class SourceIterator,
class Buffer, class BFSVisitor,
class ColorMap>
void breadth_first_search
(const VertexListGraph& g,
SourceIterator sources_begin, SourceIterator sources_end,
Buffer& Q, BFSVisitor vis, ColorMap color)
{
// Initialization
typedef typename property_traits<ColorMap>::value_type ColorValue;
typedef color_traits<ColorValue> Color;
typename boost::graph_traits<VertexListGraph>::vertex_iterator i, i_end;
for (boost::tie(i, i_end) = vertices(g); i != i_end; ++i) {
vis.initialize_vertex(*i, g);
put(color, *i, Color::white());
}
breadth_first_visit(g, sources_begin, sources_end, Q, vis, color);
}
template <class VertexListGraph, class Buffer, class BFSVisitor,
class ColorMap>
void breadth_first_search
(const VertexListGraph& g,
typename graph_traits<VertexListGraph>::vertex_descriptor s,
Buffer& Q, BFSVisitor vis, ColorMap color)
{
typename graph_traits<VertexListGraph>::vertex_descriptor sources[1] = {s};
breadth_first_search(g, sources, sources + 1, Q, vis, color);
}
namespace graph { struct bfs_visitor_event_not_overridden {}; }
template <class Visitors = null_visitor>
class bfs_visitor {
public:
bfs_visitor() { }
bfs_visitor(Visitors vis) : m_vis(vis) { }
template <class Vertex, class Graph>
graph::bfs_visitor_event_not_overridden
initialize_vertex(Vertex u, Graph& g)
{
invoke_visitors(m_vis, u, g, ::boost::on_initialize_vertex());
return graph::bfs_visitor_event_not_overridden();
}
template <class Vertex, class Graph>
graph::bfs_visitor_event_not_overridden
discover_vertex(Vertex u, Graph& g)
{
invoke_visitors(m_vis, u, g, ::boost::on_discover_vertex());
return graph::bfs_visitor_event_not_overridden();
}
template <class Vertex, class Graph>
graph::bfs_visitor_event_not_overridden
examine_vertex(Vertex u, Graph& g)
{
invoke_visitors(m_vis, u, g, ::boost::on_examine_vertex());
return graph::bfs_visitor_event_not_overridden();
}
template <class Edge, class Graph>
graph::bfs_visitor_event_not_overridden
examine_edge(Edge e, Graph& g)
{
invoke_visitors(m_vis, e, g, ::boost::on_examine_edge());
return graph::bfs_visitor_event_not_overridden();
}
template <class Edge, class Graph>
graph::bfs_visitor_event_not_overridden
tree_edge(Edge e, Graph& g)
{
invoke_visitors(m_vis, e, g, ::boost::on_tree_edge());
return graph::bfs_visitor_event_not_overridden();
}
template <class Edge, class Graph>
graph::bfs_visitor_event_not_overridden
non_tree_edge(Edge e, Graph& g)
{
invoke_visitors(m_vis, e, g, ::boost::on_non_tree_edge());
return graph::bfs_visitor_event_not_overridden();
}
template <class Edge, class Graph>
graph::bfs_visitor_event_not_overridden
gray_target(Edge e, Graph& g)
{
invoke_visitors(m_vis, e, g, ::boost::on_gray_target());
return graph::bfs_visitor_event_not_overridden();
}
template <class Edge, class Graph>
graph::bfs_visitor_event_not_overridden
black_target(Edge e, Graph& g)
{
invoke_visitors(m_vis, e, g, ::boost::on_black_target());
return graph::bfs_visitor_event_not_overridden();
}
template <class Vertex, class Graph>
graph::bfs_visitor_event_not_overridden
finish_vertex(Vertex u, Graph& g)
{
invoke_visitors(m_vis, u, g, ::boost::on_finish_vertex());
return graph::bfs_visitor_event_not_overridden();
}
BOOST_GRAPH_EVENT_STUB(on_initialize_vertex,bfs)
BOOST_GRAPH_EVENT_STUB(on_discover_vertex,bfs)
BOOST_GRAPH_EVENT_STUB(on_examine_vertex,bfs)
BOOST_GRAPH_EVENT_STUB(on_examine_edge,bfs)
BOOST_GRAPH_EVENT_STUB(on_tree_edge,bfs)
BOOST_GRAPH_EVENT_STUB(on_non_tree_edge,bfs)
BOOST_GRAPH_EVENT_STUB(on_gray_target,bfs)
BOOST_GRAPH_EVENT_STUB(on_black_target,bfs)
BOOST_GRAPH_EVENT_STUB(on_finish_vertex,bfs)
protected:
Visitors m_vis;
};
template <class Visitors>
bfs_visitor<Visitors>
make_bfs_visitor(Visitors vis) {
return bfs_visitor<Visitors>(vis);
}
typedef bfs_visitor<> default_bfs_visitor;
namespace detail {
template <class VertexListGraph, class ColorMap, class BFSVisitor,
class P, class T, class R>
void bfs_helper
(VertexListGraph& g,
typename graph_traits<VertexListGraph>::vertex_descriptor s,
ColorMap color,
BFSVisitor vis,
const bgl_named_params<P, T, R>& params,
BOOST_GRAPH_ENABLE_IF_MODELS(VertexListGraph, vertex_list_graph_tag,
void)* = 0)
{
typedef graph_traits<VertexListGraph> Traits;
// Buffer default
typedef typename Traits::vertex_descriptor Vertex;
typedef boost::queue<Vertex> queue_t;
queue_t Q;
breadth_first_search
(g, s,
choose_param(get_param(params, buffer_param_t()), boost::ref(Q)).get(),
vis, color);
}
#ifdef BOOST_GRAPH_USE_MPI
template <class DistributedGraph, class ColorMap, class BFSVisitor,
class P, class T, class R>
void bfs_helper
(DistributedGraph& g,
typename graph_traits<DistributedGraph>::vertex_descriptor s,
ColorMap color,
BFSVisitor vis,
const bgl_named_params<P, T, R>& params,
BOOST_GRAPH_ENABLE_IF_MODELS(DistributedGraph, distributed_graph_tag,
void)* = 0);
#endif // BOOST_GRAPH_USE_MPI
//-------------------------------------------------------------------------
// Choose between default color and color parameters. Using
// function dispatching so that we don't require vertex index if
// the color default is not being used.
template <class ColorMap>
struct bfs_dispatch {
template <class VertexListGraph, class P, class T, class R>
static void apply
(VertexListGraph& g,
typename graph_traits<VertexListGraph>::vertex_descriptor s,
const bgl_named_params<P, T, R>& params,
ColorMap color)
{
bfs_helper
(g, s, color,
choose_param(get_param(params, graph_visitor),
make_bfs_visitor(null_visitor())),
params);
}
};
template <>
struct bfs_dispatch<param_not_found> {
template <class VertexListGraph, class P, class T, class R>
static void apply
(VertexListGraph& g,
typename graph_traits<VertexListGraph>::vertex_descriptor s,
const bgl_named_params<P, T, R>& params,
param_not_found)
{
null_visitor null_vis;
bfs_helper
(g, s,
make_two_bit_color_map
(num_vertices(g),
choose_const_pmap(get_param(params, vertex_index),
g, vertex_index)),
choose_param(get_param(params, graph_visitor),
make_bfs_visitor(null_vis)),
params);
}
};
} // namespace detail
#if 1
// Named Parameter Variant
template <class VertexListGraph, class P, class T, class R>
void breadth_first_search
(const VertexListGraph& g,
typename graph_traits<VertexListGraph>::vertex_descriptor s,
const bgl_named_params<P, T, R>& params)
{
// The graph is passed by *const* reference so that graph adaptors
// (temporaries) can be passed into this function. However, the
// graph is not really const since we may write to property maps
// of the graph.
VertexListGraph& ng = const_cast<VertexListGraph&>(g);
typedef typename get_param_type< vertex_color_t, bgl_named_params<P,T,R> >::type C;
detail::bfs_dispatch<C>::apply(ng, s, params,
get_param(params, vertex_color));
}
#endif
// This version does not initialize colors, user has to.
template <class IncidenceGraph, class P, class T, class R>
void breadth_first_visit
(const IncidenceGraph& g,
typename graph_traits<IncidenceGraph>::vertex_descriptor s,
const bgl_named_params<P, T, R>& params)
{
// The graph is passed by *const* reference so that graph adaptors
// (temporaries) can be passed into this function. However, the
// graph is not really const since we may write to property maps
// of the graph.
IncidenceGraph& ng = const_cast<IncidenceGraph&>(g);
typedef graph_traits<IncidenceGraph> Traits;
// Buffer default
typedef typename Traits::vertex_descriptor vertex_descriptor;
typedef boost::queue<vertex_descriptor> queue_t;
queue_t Q;
breadth_first_visit
(ng, s,
choose_param(get_param(params, buffer_param_t()), boost::ref(Q)).get(),
choose_param(get_param(params, graph_visitor),
make_bfs_visitor(null_visitor())),
choose_pmap(get_param(params, vertex_color), ng, vertex_color)
);
}
namespace graph {
namespace detail {
template <typename Graph, typename Source>
struct breadth_first_search_impl {
typedef void result_type;
template <typename ArgPack>
void operator()(const Graph& g, const Source& source, const ArgPack& arg_pack) {
using namespace boost::graph::keywords;
typename boost::graph_traits<Graph>::vertex_descriptor sources[1] = {source};
boost::queue<typename boost::graph_traits<Graph>::vertex_descriptor> Q;
boost::breadth_first_search(g,
&sources[0],
&sources[1],
boost::unwrap_ref(arg_pack[_buffer | boost::ref(Q)]),
arg_pack[_visitor | make_bfs_visitor(null_visitor())],
boost::detail::make_color_map_from_arg_pack(g, arg_pack));
}
};
}
BOOST_GRAPH_MAKE_FORWARDING_FUNCTION(breadth_first_search, 2, 4)
}
#if 0
// Named Parameter Variant
BOOST_GRAPH_MAKE_OLD_STYLE_PARAMETER_FUNCTION(breadth_first_search, 2)
#endif
} // namespace boost
#ifdef BOOST_GRAPH_USE_MPI
# include <boost/graph/distributed/breadth_first_search.hpp>
#endif
#endif // BOOST_GRAPH_BREADTH_FIRST_SEARCH_HPP
@@ -0,0 +1,310 @@
// (C) Copyright 2007-2009 Andrew Sutton
//
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0 (See accompanying file
// LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GRAPH_CLIQUE_HPP
#define BOOST_GRAPH_CLIQUE_HPP
#include <vector>
#include <deque>
#include <boost/config.hpp>
#include <boost/concept/assert.hpp>
#include <boost/graph/graph_concepts.hpp>
#include <boost/graph/lookup_edge.hpp>
#include <boost/concept/detail/concept_def.hpp>
namespace boost {
namespace concepts {
BOOST_concept(CliqueVisitor,(Visitor)(Clique)(Graph))
{
BOOST_CONCEPT_USAGE(CliqueVisitor)
{
vis.clique(k, g);
}
private:
Visitor vis;
Graph g;
Clique k;
};
} /* namespace concepts */
using concepts::CliqueVisitorConcept;
} /* namespace boost */
#include <boost/concept/detail/concept_undef.hpp>
namespace boost
{
// The algorithm implemented in this paper is based on the so-called
// Algorithm 457, published as:
//
// @article{362367,
// author = {Coen Bron and Joep Kerbosch},
// title = {Algorithm 457: finding all cliques of an undirected graph},
// journal = {Communications of the ACM},
// volume = {16},
// number = {9},
// year = {1973},
// issn = {0001-0782},
// pages = {575--577},
// doi = {http://doi.acm.org/10.1145/362342.362367},
// publisher = {ACM Press},
// address = {New York, NY, USA},
// }
//
// Sort of. This implementation is adapted from the 1st version of the
// algorithm and does not implement the candidate selection optimization
// described as published - it could, it just doesn't yet.
//
// The algorithm is given as proportional to (3.14)^(n/3) power. This is
// not the same as O(...), but based on time measures and approximation.
//
// Unfortunately, this implementation may be less efficient on non-
// AdjacencyMatrix modeled graphs due to the non-constant implementation
// of the edge(u,v,g) functions.
//
// TODO: It might be worthwhile to provide functionality for passing
// a connectivity matrix to improve the efficiency of those lookups
// when needed. This could simply be passed as a BooleanMatrix
// s.t. edge(u,v,B) returns true or false. This could easily be
// abstracted for adjacency matricies.
//
// The following paper is interesting for a number of reasons. First,
// it lists a number of other such algorithms and second, it describes
// a new algorithm (that does not appear to require the edge(u,v,g)
// function and appears fairly efficient. It is probably worth investigating.
//
// @article{DBLP:journals/tcs/TomitaTT06,
// author = {Etsuji Tomita and Akira Tanaka and Haruhisa Takahashi},
// title = {The worst-case time complexity for generating all maximal cliques and computational experiments},
// journal = {Theor. Comput. Sci.},
// volume = {363},
// number = {1},
// year = {2006},
// pages = {28-42}
// ee = {http://dx.doi.org/10.1016/j.tcs.2006.06.015}
// }
/**
* The default clique_visitor supplies an empty visitation function.
*/
struct clique_visitor
{
template <typename VertexSet, typename Graph>
void clique(const VertexSet&, Graph&)
{ }
};
/**
* The max_clique_visitor records the size of the maximum clique (but not the
* clique itself).
*/
struct max_clique_visitor
{
max_clique_visitor(std::size_t& max)
: maximum(max)
{ }
template <typename Clique, typename Graph>
inline void clique(const Clique& p, const Graph& g)
{
BOOST_USING_STD_MAX();
maximum = max BOOST_PREVENT_MACRO_SUBSTITUTION (maximum, p.size());
}
std::size_t& maximum;
};
inline max_clique_visitor find_max_clique(std::size_t& max)
{ return max_clique_visitor(max); }
namespace detail
{
template <typename Graph>
inline bool
is_connected_to_clique(const Graph& g,
typename graph_traits<Graph>::vertex_descriptor u,
typename graph_traits<Graph>::vertex_descriptor v,
typename graph_traits<Graph>::undirected_category)
{
return lookup_edge(u, v, g).second;
}
template <typename Graph>
inline bool
is_connected_to_clique(const Graph& g,
typename graph_traits<Graph>::vertex_descriptor u,
typename graph_traits<Graph>::vertex_descriptor v,
typename graph_traits<Graph>::directed_category)
{
// Note that this could alternate between using an || to determine
// full connectivity. I believe that this should produce strongly
// connected components. Note that using && instead of || will
// change the results to a fully connected subgraph (i.e., symmetric
// edges between all vertices s.t., if a->b, then b->a.
return lookup_edge(u, v, g).second && lookup_edge(v, u, g).second;
}
template <typename Graph, typename Container>
inline void
filter_unconnected_vertices(const Graph& g,
typename graph_traits<Graph>::vertex_descriptor v,
const Container& in,
Container& out)
{
BOOST_CONCEPT_ASSERT(( GraphConcept<Graph> ));
typename graph_traits<Graph>::directed_category cat;
typename Container::const_iterator i, end = in.end();
for(i = in.begin(); i != end; ++i) {
if(is_connected_to_clique(g, v, *i, cat)) {
out.push_back(*i);
}
}
}
template <
typename Graph,
typename Clique, // compsub type
typename Container, // candidates/not type
typename Visitor>
void extend_clique(const Graph& g,
Clique& clique,
Container& cands,
Container& nots,
Visitor vis,
std::size_t min)
{
BOOST_CONCEPT_ASSERT(( GraphConcept<Graph> ));
BOOST_CONCEPT_ASSERT(( CliqueVisitorConcept<Visitor,Clique,Graph> ));
typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
// Is there vertex in nots that is connected to all vertices
// in the candidate set? If so, no clique can ever be found.
// This could be broken out into a separate function.
{
typename Container::iterator ni, nend = nots.end();
typename Container::iterator ci, cend = cands.end();
for(ni = nots.begin(); ni != nend; ++ni) {
for(ci = cands.begin(); ci != cend; ++ci) {
// if we don't find an edge, then we're okay.
if(!lookup_edge(*ni, *ci, g).second) break;
}
// if we iterated all the way to the end, then *ni
// is connected to all *ci
if(ci == cend) break;
}
// if we broke early, we found *ni connected to all *ci
if(ni != nend) return;
}
// TODO: the original algorithm 457 describes an alternative
// (albeit really complicated) mechanism for selecting candidates.
// The given optimizaiton seeks to bring about the above
// condition sooner (i.e., there is a vertex in the not set
// that is connected to all candidates). unfortunately, the
// method they give for doing this is fairly unclear.
// basically, for every vertex in not, we should know how many
// vertices it is disconnected from in the candidate set. if
// we fix some vertex in the not set, then we want to keep
// choosing vertices that are not connected to that fixed vertex.
// apparently, by selecting fix point with the minimum number
// of disconnections (i.e., the maximum number of connections
// within the candidate set), then the previous condition wil
// be reached sooner.
// there's some other stuff about using the number of disconnects
// as a counter, but i'm jot really sure i followed it.
// TODO: If we min-sized cliques to visit, then theoretically, we
// should be able to stop recursing if the clique falls below that
// size - maybe?
// otherwise, iterate over candidates and and test
// for maxmimal cliquiness.
typename Container::iterator i, j;
for(i = cands.begin(); i != cands.end(); ) {
Vertex candidate = *i;
// add the candidate to the clique (keeping the iterator!)
// typename Clique::iterator ci = clique.insert(clique.end(), candidate);
clique.push_back(candidate);
// remove it from the candidate set
i = cands.erase(i);
// build new candidate and not sets by removing all vertices
// that are not connected to the current candidate vertex.
// these actually invert the operation, adding them to the new
// sets if the vertices are connected. its semantically the same.
Container new_cands, new_nots;
filter_unconnected_vertices(g, candidate, cands, new_cands);
filter_unconnected_vertices(g, candidate, nots, new_nots);
if(new_cands.empty() && new_nots.empty()) {
// our current clique is maximal since there's nothing
// that's connected that we haven't already visited. If
// the clique is below our radar, then we won't visit it.
if(clique.size() >= min) {
vis.clique(clique, g);
}
}
else {
// recurse to explore the new candidates
extend_clique(g, clique, new_cands, new_nots, vis, min);
}
// we're done with this vertex, so we need to move it
// to the nots, and remove the candidate from the clique.
nots.push_back(candidate);
clique.pop_back();
}
}
} /* namespace detail */
template <typename Graph, typename Visitor>
inline void
bron_kerbosch_all_cliques(const Graph& g, Visitor vis, std::size_t min)
{
BOOST_CONCEPT_ASSERT(( IncidenceGraphConcept<Graph> ));
BOOST_CONCEPT_ASSERT(( VertexListGraphConcept<Graph> ));
BOOST_CONCEPT_ASSERT(( AdjacencyMatrixConcept<Graph> )); // Structural requirement only
typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
typedef typename graph_traits<Graph>::vertex_iterator VertexIterator;
typedef std::vector<Vertex> VertexSet;
typedef std::deque<Vertex> Clique;
BOOST_CONCEPT_ASSERT(( CliqueVisitorConcept<Visitor,Clique,Graph> ));
// NOTE: We're using a deque to implement the clique, because it provides
// constant inserts and removals at the end and also a constant size.
VertexIterator i, end;
boost::tie(i, end) = vertices(g);
VertexSet cands(i, end); // start with all vertices as candidates
VertexSet nots; // start with no vertices visited
Clique clique; // the first clique is an empty vertex set
detail::extend_clique(g, clique, cands, nots, vis, min);
}
// NOTE: By default the minimum number of vertices per clique is set at 2
// because singleton cliques aren't really very interesting.
template <typename Graph, typename Visitor>
inline void
bron_kerbosch_all_cliques(const Graph& g, Visitor vis)
{ bron_kerbosch_all_cliques(g, vis, 2); }
template <typename Graph>
inline std::size_t
bron_kerbosch_clique_number(const Graph& g)
{
std::size_t ret = 0;
bron_kerbosch_all_cliques(g, find_max_clique(ret));
return ret;
}
} /* namespace boost */
#endif
@@ -0,0 +1,91 @@
// Copyright Daniel Trebbien 2010.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or the copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GRAPH_BUFFER_CONCEPTS_HPP
#define BOOST_GRAPH_BUFFER_CONCEPTS_HPP 1
#include <boost/concept_check.hpp>
#include <boost/concept/detail/concept_def.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/typeof/typeof.hpp>
#include <boost/type_traits/add_const.hpp>
#include <boost/type_traits/add_reference.hpp>
#include <boost/type_traits/remove_reference.hpp>
namespace boost {
BOOST_concept(Buffer, (B))
{
typedef typename B::value_type value_type;
typedef typename B::size_type size_type;
BOOST_CONCEPT_USAGE(Buffer) {
typedef typename boost::add_reference<value_type>::type reference;
BOOST_CONCEPT_ASSERT((Assignable<value_type>));
buf.push(g_ct);
buf.pop();
reference t = buf.top();
boost::ignore_unused_variable_warning(t);
}
void const_constraints(const B& cbuf) {
typedef typename boost::add_const<typename boost::remove_reference<value_type>::type>::type& const_reference;
const_reference ct = cbuf.top();
s = cbuf.size();
if (cbuf.empty())
dummy = __LINE__;
}
int dummy;
static const value_type g_ct;
size_type s;
B buf;
};
BOOST_concept(UpdatableQueue, (Q))
: Buffer<Q>
{
BOOST_CONCEPT_USAGE(UpdatableQueue) {
q.update(g_ct);
}
void const_constraints(const Q& cq) {
if (cq.contains(g_ct))
dummy = __LINE__;
}
int dummy;
static const typename Buffer<Q>::value_type g_ct;
Q q;
};
BOOST_concept(KeyedUpdatableQueue, (Q))
: UpdatableQueue<Q>
{
typedef typename Q::key_type key_type;
typedef typename Q::key_map key_map;
BOOST_CONCEPT_USAGE(KeyedUpdatableQueue) {
BOOST_CONCEPT_ASSERT((boost::ReadWritePropertyMapConcept<key_map, typename Buffer<Q>::value_type>));
}
void const_constraints(const Q& cq) {
km = cq.keys();
k = get(km, g_ct);
}
static const typename Buffer<Q>::value_type g_ct;
key_type k;
key_map km;
Q q;
};
} // end `namespace boost`
#endif // !BOOST_GRAPH_BUFFER_CONCEPTS_HPP
@@ -0,0 +1,280 @@
//=======================================================================
// Copyright (c) Aaron Windsor 2007
//
// 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 __CHROBAK_PAYNE_DRAWING_HPP__
#define __CHROBAK_PAYNE_DRAWING_HPP__
#include <vector>
#include <list>
#include <stack>
#include <boost/config.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/property_map/property_map.hpp>
namespace boost
{
namespace graph { namespace detail
{
template<typename Graph,
typename VertexToVertexMap,
typename VertexTo1DCoordMap>
void accumulate_offsets(typename graph_traits<Graph>::vertex_descriptor v,
std::size_t offset,
const Graph& g,
VertexTo1DCoordMap x,
VertexTo1DCoordMap delta_x,
VertexToVertexMap left,
VertexToVertexMap right)
{
typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
// Suggestion of explicit stack from Aaron Windsor to avoid system stack
// overflows.
typedef std::pair<vertex_descriptor, std::size_t> stack_entry;
std::stack<stack_entry> st;
st.push(stack_entry(v, offset));
while (!st.empty()) {
vertex_descriptor v = st.top().first;
std::size_t offset = st.top().second;
st.pop();
if (v != graph_traits<Graph>::null_vertex()) {
x[v] += delta_x[v] + offset;
st.push(stack_entry(left[v], x[v]));
st.push(stack_entry(right[v], x[v]));
}
}
}
} /*namespace detail*/ } /*namespace graph*/
template<typename Graph,
typename PlanarEmbedding,
typename ForwardIterator,
typename GridPositionMap,
typename VertexIndexMap>
void chrobak_payne_straight_line_drawing(const Graph& g,
PlanarEmbedding embedding,
ForwardIterator ordering_begin,
ForwardIterator ordering_end,
GridPositionMap drawing,
VertexIndexMap vm
)
{
typedef typename graph_traits<Graph>::vertex_descriptor vertex_t;
typedef typename graph_traits<Graph>::edge_descriptor edge_t;
typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator_t;
typedef typename PlanarEmbedding::value_type::const_iterator
edge_permutation_iterator_t;
typedef typename graph_traits<Graph>::vertices_size_type v_size_t;
typedef std::vector<vertex_t> vertex_vector_t;
typedef std::vector<v_size_t> vsize_vector_t;
typedef std::vector<bool> bool_vector_t;
typedef boost::iterator_property_map
<typename vertex_vector_t::iterator, VertexIndexMap>
vertex_to_vertex_map_t;
typedef boost::iterator_property_map
<typename vsize_vector_t::iterator, VertexIndexMap>
vertex_to_vsize_map_t;
typedef boost::iterator_property_map
<typename bool_vector_t::iterator, VertexIndexMap>
vertex_to_bool_map_t;
vertex_vector_t left_vector(num_vertices(g),
graph_traits<Graph>::null_vertex()
);
vertex_vector_t right_vector(num_vertices(g),
graph_traits<Graph>::null_vertex()
);
vsize_vector_t seen_as_right_vector(num_vertices(g), 0);
vsize_vector_t seen_vector(num_vertices(g), 0);
vsize_vector_t delta_x_vector(num_vertices(g),0);
vsize_vector_t y_vector(num_vertices(g));
vsize_vector_t x_vector(num_vertices(g),0);
bool_vector_t installed_vector(num_vertices(g),false);
vertex_to_vertex_map_t left(left_vector.begin(), vm);
vertex_to_vertex_map_t right(right_vector.begin(), vm);
vertex_to_vsize_map_t seen_as_right(seen_as_right_vector.begin(), vm);
vertex_to_vsize_map_t seen(seen_vector.begin(), vm);
vertex_to_vsize_map_t delta_x(delta_x_vector.begin(), vm);
vertex_to_vsize_map_t y(y_vector.begin(), vm);
vertex_to_vsize_map_t x(x_vector.begin(), vm);
vertex_to_bool_map_t installed(installed_vector.begin(), vm);
v_size_t timestamp = 1;
vertex_vector_t installed_neighbors;
ForwardIterator itr = ordering_begin;
vertex_t v1 = *itr; ++itr;
vertex_t v2 = *itr; ++itr;
vertex_t v3 = *itr; ++itr;
delta_x[v2] = 1;
delta_x[v3] = 1;
y[v1] = 0;
y[v2] = 0;
y[v3] = 1;
right[v1] = v3;
right[v3] = v2;
installed[v1] = installed[v2] = installed[v3] = true;
for(ForwardIterator itr_end = ordering_end; itr != itr_end; ++itr)
{
vertex_t v = *itr;
// First, find the leftmost and rightmost neighbor of v on the outer
// cycle of the embedding.
// Note: since we're moving clockwise through the edges adjacent to v,
// we're actually moving from right to left among v's neighbors on the
// outer face (since v will be installed above them all) looking for
// the leftmost and rightmost installed neigbhors
vertex_t leftmost = graph_traits<Graph>::null_vertex();
vertex_t rightmost = graph_traits<Graph>::null_vertex();
installed_neighbors.clear();
vertex_t prev_vertex = graph_traits<Graph>::null_vertex();
edge_permutation_iterator_t pi, pi_end;
pi_end = embedding[v].end();
for(pi = embedding[v].begin(); pi != pi_end; ++pi)
{
vertex_t curr_vertex = source(*pi,g) == v ?
target(*pi,g) : source(*pi,g);
// Skip any self-loops or parallel edges
if (curr_vertex == v || curr_vertex == prev_vertex)
continue;
if (installed[curr_vertex])
{
seen[curr_vertex] = timestamp;
if (right[curr_vertex] != graph_traits<Graph>::null_vertex())
{
seen_as_right[right[curr_vertex]] = timestamp;
}
installed_neighbors.push_back(curr_vertex);
}
prev_vertex = curr_vertex;
}
typename vertex_vector_t::iterator vi, vi_end;
vi_end = installed_neighbors.end();
for(vi = installed_neighbors.begin(); vi != vi_end; ++vi)
{
if (right[*vi] == graph_traits<Graph>::null_vertex() ||
seen[right[*vi]] != timestamp
)
rightmost = *vi;
if (seen_as_right[*vi] != timestamp)
leftmost = *vi;
}
++timestamp;
//stretch gaps
++delta_x[right[leftmost]];
++delta_x[rightmost];
//adjust offsets
std::size_t delta_p_q = 0;
vertex_t stopping_vertex = right[rightmost];
for(vertex_t temp = right[leftmost]; temp != stopping_vertex;
temp = right[temp]
)
{
delta_p_q += delta_x[temp];
}
delta_x[v] = ((y[rightmost] + delta_p_q) - y[leftmost])/2;
y[v] = y[leftmost] + delta_x[v];
delta_x[rightmost] = delta_p_q - delta_x[v];
bool leftmost_and_rightmost_adjacent = right[leftmost] == rightmost;
if (!leftmost_and_rightmost_adjacent)
delta_x[right[leftmost]] -= delta_x[v];
//install v
if (!leftmost_and_rightmost_adjacent)
{
left[v] = right[leftmost];
vertex_t next_to_rightmost;
for(vertex_t temp = leftmost; temp != rightmost;
temp = right[temp]
)
{
next_to_rightmost = temp;
}
right[next_to_rightmost] = graph_traits<Graph>::null_vertex();
}
else
{
left[v] = graph_traits<Graph>::null_vertex();
}
right[leftmost] = v;
right[v] = rightmost;
installed[v] = true;
}
graph::detail::accumulate_offsets
(*ordering_begin,0,g,x,delta_x,left,right);
vertex_iterator_t vi, vi_end;
for(boost::tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi)
{
vertex_t v(*vi);
drawing[v].x = x[v];
drawing[v].y = y[v];
}
}
template<typename Graph,
typename PlanarEmbedding,
typename ForwardIterator,
typename GridPositionMap>
inline void chrobak_payne_straight_line_drawing(const Graph& g,
PlanarEmbedding embedding,
ForwardIterator ord_begin,
ForwardIterator ord_end,
GridPositionMap drawing
)
{
chrobak_payne_straight_line_drawing(g,
embedding,
ord_begin,
ord_end,
drawing,
get(vertex_index,g)
);
}
} // namespace boost
#endif //__CHROBAK_PAYNE_DRAWING_HPP__
@@ -0,0 +1,58 @@
// Copyright 2004 The Trustees of Indiana University.
// 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)
// Authors: Douglas Gregor
// Andrew Lumsdaine
#ifndef BOOST_GRAPH_CIRCLE_LAYOUT_HPP
#define BOOST_GRAPH_CIRCLE_LAYOUT_HPP
#include <boost/config/no_tr1/cmath.hpp>
#include <boost/math/constants/constants.hpp>
#include <utility>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/iteration_macros.hpp>
#include <boost/graph/topology.hpp>
#include <boost/static_assert.hpp>
namespace boost {
/**
* \brief Layout the graph with the vertices at the points of a regular
* n-polygon.
*
* The distance from the center of the polygon to each point is
* determined by the @p radius parameter. The @p position parameter
* must be an Lvalue Property Map whose value type is a class type
* containing @c x and @c y members that will be set to the @c x and
* @c y coordinates.
*/
template<typename VertexListGraph, typename PositionMap, typename Radius>
void
circle_graph_layout(const VertexListGraph& g, PositionMap position,
Radius radius)
{
BOOST_STATIC_ASSERT (property_traits<PositionMap>::value_type::dimensions >= 2);
const double pi = boost::math::constants::pi<double>();
#ifndef BOOST_NO_STDC_NAMESPACE
using std::sin;
using std::cos;
#endif // BOOST_NO_STDC_NAMESPACE
typedef typename graph_traits<VertexListGraph>::vertices_size_type
vertices_size_type;
vertices_size_type n = num_vertices(g);
vertices_size_type i = 0;
double two_pi_over_n = 2. * pi / n;
BGL_FORALL_VERTICES_T(v, g, VertexListGraph) {
position[v][0] = radius * cos(i * two_pi_over_n);
position[v][1] = radius * sin(i * two_pi_over_n);
++i;
}
}
} // end namespace boost
#endif // BOOST_GRAPH_CIRCLE_LAYOUT_HPP
@@ -0,0 +1,158 @@
// (C) Copyright 2007-2009 Andrew Sutton
//
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0 (See accompanying file
// LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GRAPH_CLOSENESS_CENTRALITY_HPP
#define BOOST_GRAPH_CLOSENESS_CENTRALITY_HPP
#include <boost/graph/detail/geodesic.hpp>
#include <boost/graph/exterior_property.hpp>
#include <boost/concept/assert.hpp>
namespace boost
{
template <typename Graph,
typename DistanceType,
typename ResultType,
typename Reciprocal = detail::reciprocal<ResultType> >
struct closeness_measure
: public geodesic_measure<Graph, DistanceType, ResultType>
{
typedef geodesic_measure< Graph, DistanceType, ResultType> base_type;
typedef typename base_type::distance_type distance_type;
typedef typename base_type::result_type result_type;
result_type operator ()(distance_type d, const Graph&)
{
BOOST_CONCEPT_ASSERT(( NumericValueConcept<DistanceType> ));
BOOST_CONCEPT_ASSERT(( NumericValueConcept<ResultType> ));
BOOST_CONCEPT_ASSERT(( AdaptableUnaryFunctionConcept<Reciprocal,ResultType,ResultType> ));
return (d == base_type::infinite_distance())
? base_type::zero_result()
: rec(result_type(d));
}
Reciprocal rec;
};
template <typename Graph, typename DistanceMap>
inline closeness_measure<
Graph, typename property_traits<DistanceMap>::value_type, double,
detail::reciprocal<double> >
measure_closeness(const Graph&, DistanceMap)
{
typedef typename property_traits<DistanceMap>::value_type Distance;
return closeness_measure<Graph, Distance, double, detail::reciprocal<double> >();
}
template <typename T, typename Graph, typename DistanceMap>
inline closeness_measure<
Graph, typename property_traits<DistanceMap>::value_type, T,
detail::reciprocal<T> >
measure_closeness(const Graph&, DistanceMap)
{
typedef typename property_traits<DistanceMap>::value_type Distance;
return closeness_measure<Graph, Distance, T, detail::reciprocal<T> >();
}
template <typename T, typename Graph, typename DistanceMap, typename Reciprocal>
inline closeness_measure<
Graph, typename property_traits<DistanceMap>::value_type, T,
Reciprocal>
measure_closeness(const Graph&, DistanceMap)
{
typedef typename property_traits<DistanceMap>::value_type Distance;
return closeness_measure<Graph, Distance, T, Reciprocal>();
}
template <typename Graph,
typename DistanceMap,
typename Measure,
typename Combinator>
inline typename Measure::result_type
closeness_centrality(const Graph& g,
DistanceMap dist,
Measure measure,
Combinator combine)
{
BOOST_CONCEPT_ASSERT(( VertexListGraphConcept<Graph> ));
typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
BOOST_CONCEPT_ASSERT(( ReadablePropertyMapConcept<DistanceMap,Vertex> ));
typedef typename property_traits<DistanceMap>::value_type Distance;
BOOST_CONCEPT_ASSERT(( NumericValueConcept<Distance> ));
BOOST_CONCEPT_ASSERT(( DistanceMeasureConcept<Measure,Graph> ));
Distance n = detail::combine_distances(g, dist, combine, Distance(0));
return measure(n, g);
}
template <typename Graph, typename DistanceMap, typename Measure>
inline typename Measure::result_type
closeness_centrality(const Graph& g, DistanceMap dist, Measure measure)
{
BOOST_CONCEPT_ASSERT(( GraphConcept<Graph> ));
typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
BOOST_CONCEPT_ASSERT(( ReadablePropertyMapConcept<DistanceMap,Vertex> ));
typedef typename property_traits<DistanceMap>::value_type Distance;
return closeness_centrality(g, dist, measure, std::plus<Distance>());
}
template <typename Graph, typename DistanceMap>
inline double closeness_centrality(const Graph& g, DistanceMap dist)
{ return closeness_centrality(g, dist, measure_closeness(g, dist)); }
template <typename T, typename Graph, typename DistanceMap>
inline T closeness_centrality(const Graph& g, DistanceMap dist)
{ return closeness_centrality(g, dist, measure_closeness<T>(g, dist)); }
template <typename Graph,
typename DistanceMatrixMap,
typename CentralityMap,
typename Measure>
inline void
all_closeness_centralities(const Graph& g,
DistanceMatrixMap dist,
CentralityMap cent,
Measure measure)
{
BOOST_CONCEPT_ASSERT(( VertexListGraphConcept<Graph> ));
typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
BOOST_CONCEPT_ASSERT(( ReadablePropertyMapConcept<DistanceMatrixMap,Vertex> ));
typedef typename property_traits<DistanceMatrixMap>::value_type DistanceMap;
BOOST_CONCEPT_ASSERT(( ReadablePropertyMapConcept<DistanceMap,Vertex> ));
BOOST_CONCEPT_ASSERT(( WritablePropertyMapConcept<CentralityMap,Vertex> ));
typedef typename property_traits<DistanceMap>::value_type Distance;
typedef typename property_traits<CentralityMap>::value_type Centrality;
typename graph_traits<Graph>::vertex_iterator i, end;
for(boost::tie(i, end) = vertices(g); i != end; ++i) {
DistanceMap dm = get(dist, *i);
Centrality c = closeness_centrality(g, dm, measure);
put(cent, *i, c);
}
}
template <typename Graph,
typename DistanceMatrixMap,
typename CentralityMap>
inline void
all_closeness_centralities(const Graph& g,
DistanceMatrixMap dist,
CentralityMap cent)
{
BOOST_CONCEPT_ASSERT(( GraphConcept<Graph> ));
typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
BOOST_CONCEPT_ASSERT(( ReadablePropertyMapConcept<DistanceMatrixMap,Vertex> ));
typedef typename property_traits<DistanceMatrixMap>::value_type DistanceMap;
BOOST_CONCEPT_ASSERT(( ReadablePropertyMapConcept<DistanceMap,Vertex> ));
typedef typename property_traits<DistanceMap>::value_type Distance;
typedef typename property_traits<CentralityMap>::value_type Result;
all_closeness_centralities(g, dist, cent, measure_closeness<Result>(g, DistanceMap()));
}
} /* namespace boost */
#endif
@@ -0,0 +1,159 @@
// (C) Copyright 2007-2009 Andrew Sutton
//
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0 (See accompanying file
// LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GRAPH_CLUSTERING_COEFFICIENT_HPP
#define BOOST_GRAPH_CLUSTERING_COEFFICIENT_HPP
#include <boost/next_prior.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/graph_concepts.hpp>
#include <boost/graph/lookup_edge.hpp>
#include <boost/concept/assert.hpp>
namespace boost
{
namespace detail
{
template <class Graph>
inline typename graph_traits<Graph>::degree_size_type
possible_edges(const Graph& g, std::size_t k, directed_tag)
{
BOOST_CONCEPT_ASSERT(( GraphConcept<Graph> ));
typedef typename graph_traits<Graph>::degree_size_type T;
return T(k) * (T(k) - 1);
}
template <class Graph>
inline typename graph_traits<Graph>::degree_size_type
possible_edges(const Graph& g, size_t k, undirected_tag)
{
// dirty little trick...
return possible_edges(g, k, directed_tag()) / 2;
}
// This template matches directedS and bidirectionalS.
template <class Graph>
inline typename graph_traits<Graph>::degree_size_type
count_edges(const Graph& g,
typename graph_traits<Graph>::vertex_descriptor u,
typename graph_traits<Graph>::vertex_descriptor v,
directed_tag)
{
BOOST_CONCEPT_ASSERT(( AdjacencyMatrixConcept<Graph> ));
return (lookup_edge(u, v, g).second ? 1 : 0) +
(lookup_edge(v, u, g).second ? 1 : 0);
}
// This template matches undirectedS
template <class Graph>
inline typename graph_traits<Graph>::degree_size_type
count_edges(const Graph& g,
typename graph_traits<Graph>::vertex_descriptor u,
typename graph_traits<Graph>::vertex_descriptor v,
undirected_tag)
{
BOOST_CONCEPT_ASSERT(( AdjacencyMatrixConcept<Graph> ));
return lookup_edge(u, v, g).second ? 1 : 0;
}
}
template <typename Graph, typename Vertex>
inline typename graph_traits<Graph>::degree_size_type
num_paths_through_vertex(const Graph& g, Vertex v)
{
BOOST_CONCEPT_ASSERT(( AdjacencyGraphConcept<Graph> ));
typedef typename graph_traits<Graph>::directed_category Directed;
typedef typename graph_traits<Graph>::adjacency_iterator AdjacencyIterator;
// TODO: There should actually be a set of neighborhood functions
// for things like this (num_neighbors() would be great).
AdjacencyIterator i, end;
boost::tie(i, end) = adjacent_vertices(v, g);
std::size_t k = std::distance(i, end);
return detail::possible_edges(g, k, Directed());
}
template <typename Graph, typename Vertex>
inline typename graph_traits<Graph>::degree_size_type
num_triangles_on_vertex(const Graph& g, Vertex v)
{
BOOST_CONCEPT_ASSERT(( IncidenceGraphConcept<Graph> ));
BOOST_CONCEPT_ASSERT(( AdjacencyGraphConcept<Graph> ));
typedef typename graph_traits<Graph>::degree_size_type Degree;
typedef typename graph_traits<Graph>::directed_category Directed;
typedef typename graph_traits<Graph>::adjacency_iterator AdjacencyIterator;
// TODO: I might be able to reduce the requirement from adjacency graph
// to incidence graph by using out edges.
Degree count(0);
AdjacencyIterator i, j, end;
for(boost::tie(i, end) = adjacent_vertices(v, g); i != end; ++i) {
for(j = boost::next(i); j != end; ++j) {
count += detail::count_edges(g, *i, *j, Directed());
}
}
return count;
} /* namespace detail */
template <typename T, typename Graph, typename Vertex>
inline T
clustering_coefficient(const Graph& g, Vertex v)
{
T zero(0);
T routes = T(num_paths_through_vertex(g, v));
return (routes > zero) ?
T(num_triangles_on_vertex(g, v)) / routes : zero;
}
template <typename Graph, typename Vertex>
inline double
clustering_coefficient(const Graph& g, Vertex v)
{ return clustering_coefficient<double>(g, v); }
template <typename Graph, typename ClusteringMap>
inline typename property_traits<ClusteringMap>::value_type
all_clustering_coefficients(const Graph& g, ClusteringMap cm)
{
BOOST_CONCEPT_ASSERT(( VertexListGraphConcept<Graph> ));
typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
typedef typename graph_traits<Graph>::vertex_iterator VertexIterator;
BOOST_CONCEPT_ASSERT(( WritablePropertyMapConcept<ClusteringMap,Vertex> ));
typedef typename property_traits<ClusteringMap>::value_type Coefficient;
Coefficient sum(0);
VertexIterator i, end;
for(boost::tie(i, end) = vertices(g); i != end; ++i) {
Coefficient cc = clustering_coefficient<Coefficient>(g, *i);
put(cm, *i, cc);
sum += cc;
}
return sum / Coefficient(num_vertices(g));
}
template <typename Graph, typename ClusteringMap>
inline typename property_traits<ClusteringMap>::value_type
mean_clustering_coefficient(const Graph& g, ClusteringMap cm)
{
BOOST_CONCEPT_ASSERT(( VertexListGraphConcept<Graph> ));
typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
typedef typename graph_traits<Graph>::vertex_iterator VertexIterator;
BOOST_CONCEPT_ASSERT(( ReadablePropertyMapConcept<ClusteringMap,Vertex> ));
typedef typename property_traits<ClusteringMap>::value_type Coefficient;
Coefficient cc(0);
VertexIterator i, end;
for(boost::tie(i, end) = vertices(g); i != end; ++i) {
cc += get(cm, *i);
}
return cc / Coefficient(num_vertices(g));
}
} /* namespace boost */
#endif
@@ -0,0 +1,107 @@
//
//=======================================================================
// Copyright 1997-2001 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_GRAPH_CONNECTED_COMPONENTS_HPP
#define BOOST_GRAPH_CONNECTED_COMPONENTS_HPP
#include <boost/config.hpp>
#include <boost/graph/depth_first_search.hpp>
#include <boost/graph/properties.hpp>
#include <boost/graph/graph_concepts.hpp>
#include <boost/graph/overloading.hpp>
#include <boost/static_assert.hpp>
#include <boost/concept/assert.hpp>
namespace boost {
namespace detail {
// This visitor is used both in the connected_components algorithm
// and in the kosaraju strong components algorithm during the
// second DFS traversal.
template <class ComponentsMap>
class components_recorder : public dfs_visitor<>
{
typedef typename property_traits<ComponentsMap>::value_type comp_type;
public:
components_recorder(ComponentsMap c,
comp_type& c_count)
: m_component(c), m_count(c_count) {}
template <class Vertex, class Graph>
void start_vertex(Vertex, Graph&) {
if (m_count == (std::numeric_limits<comp_type>::max)())
m_count = 0; // start counting components at zero
else
++m_count;
}
template <class Vertex, class Graph>
void discover_vertex(Vertex u, Graph&) {
put(m_component, u, m_count);
}
protected:
ComponentsMap m_component;
comp_type& m_count;
};
} // namespace detail
// This function computes the connected components of an undirected
// graph using a single application of depth first search.
template <class Graph, class ComponentMap, class P, class T, class R>
inline typename property_traits<ComponentMap>::value_type
connected_components(const Graph& g, ComponentMap c,
const bgl_named_params<P, T, R>& params
BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph, vertex_list_graph_tag))
{
if (num_vertices(g) == 0) return 0;
typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
BOOST_CONCEPT_ASSERT(( WritablePropertyMapConcept<ComponentMap, Vertex> ));
typedef typename boost::graph_traits<Graph>::directed_category directed;
BOOST_STATIC_ASSERT((boost::is_same<directed, undirected_tag>::value));
typedef typename property_traits<ComponentMap>::value_type comp_type;
// c_count initialized to "nil" (with nil represented by (max)())
comp_type c_count((std::numeric_limits<comp_type>::max)());
detail::components_recorder<ComponentMap> vis(c, c_count);
depth_first_search(g, params.visitor(vis));
return c_count + 1;
}
template <class Graph, class ComponentMap>
inline typename property_traits<ComponentMap>::value_type
connected_components(const Graph& g, ComponentMap c
BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph, vertex_list_graph_tag))
{
if (num_vertices(g) == 0) return 0;
typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
BOOST_CONCEPT_ASSERT(( WritablePropertyMapConcept<ComponentMap, Vertex> ));
typedef typename boost::graph_traits<Graph>::directed_category directed;
// BOOST_STATIC_ASSERT((boost::is_same<directed, undirected_tag>::value));
typedef typename property_traits<ComponentMap>::value_type comp_type;
// c_count initialized to "nil" (with nil represented by (max)())
comp_type c_count((std::numeric_limits<comp_type>::max)());
detail::components_recorder<ComponentMap> vis(c, c_count);
depth_first_search(g, visitor(vis));
return c_count + 1;
}
} // namespace boost
#ifdef BOOST_GRAPH_USE_MPI
# include <boost/graph/distributed/connected_components.hpp>
#endif
#endif // BOOST_GRAPH_CONNECTED_COMPONENTS_HPP
@@ -0,0 +1,511 @@
//
//=======================================================================
// Copyright 1997-2001 University of Notre Dame.
// Authors: Jeremy G. Siek, Lie-Quan Lee, Andrew Lumsdaine
//
// 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)
//=======================================================================
//
/*
This file implements the following functions:
template <typename VertexListGraph, typename MutableGraph>
void copy_graph(const VertexListGraph& g_in, MutableGraph& g_out)
template <typename VertexListGraph, typename MutableGraph,
class P, class T, class R>
void copy_graph(const VertexListGraph& g_in, MutableGraph& g_out,
const bgl_named_params<P, T, R>& params)
template <typename IncidenceGraph, typename MutableGraph>
typename graph_traits<MutableGraph>::vertex_descriptor
copy_component(IncidenceGraph& g_in,
typename graph_traits<IncidenceGraph>::vertex_descriptor src,
MutableGraph& g_out)
template <typename IncidenceGraph, typename MutableGraph,
typename P, typename T, typename R>
typename graph_traits<MutableGraph>::vertex_descriptor
copy_component(IncidenceGraph& g_in,
typename graph_traits<IncidenceGraph>::vertex_descriptor src,
MutableGraph& g_out,
const bgl_named_params<P, T, R>& params)
*/
#ifndef BOOST_GRAPH_COPY_HPP
#define BOOST_GRAPH_COPY_HPP
#include <boost/config.hpp>
#include <vector>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/reverse_graph.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/graph/named_function_params.hpp>
#include <boost/graph/breadth_first_search.hpp>
#include <boost/type_traits/conversion_traits.hpp>
namespace boost {
namespace detail {
// Hack to make transpose_graph work with the same interface as before
template <typename Graph, typename Desc>
struct remove_reverse_edge_descriptor {
typedef Desc type;
static Desc convert(const Desc& d, const Graph&) {return d;}
};
template <typename Graph, typename Desc>
struct remove_reverse_edge_descriptor<Graph, reverse_graph_edge_descriptor<Desc> > {
typedef Desc type;
static Desc convert(const reverse_graph_edge_descriptor<Desc>& d, const Graph& g) {
return get(edge_underlying, g, d);
}
};
// Add a reverse_graph_edge_descriptor wrapper if the Graph is a
// reverse_graph but the edge descriptor is from the original graph (this
// case comes from the fact that transpose_graph uses reverse_graph
// internally but doesn't expose the different edge descriptor type to the
// user).
template <typename Desc, typename Graph>
struct add_reverse_edge_descriptor {
typedef Desc type;
static Desc convert(const Desc& d) {return d;}
};
template <typename Desc, typename G, typename GR>
struct add_reverse_edge_descriptor<Desc, boost::reverse_graph<G, GR> > {
typedef reverse_graph_edge_descriptor<Desc> type;
static reverse_graph_edge_descriptor<Desc> convert(const Desc& d) {
return reverse_graph_edge_descriptor<Desc>(d);
}
};
template <typename Desc, typename G, typename GR>
struct add_reverse_edge_descriptor<reverse_graph_edge_descriptor<Desc>, boost::reverse_graph<G, GR> > {
typedef reverse_graph_edge_descriptor<Desc> type;
static reverse_graph_edge_descriptor<Desc> convert(const reverse_graph_edge_descriptor<Desc>& d) {
return d;
}
};
// Default edge and vertex property copiers
template <typename Graph1, typename Graph2>
struct edge_copier {
edge_copier(const Graph1& g1, Graph2& g2)
: edge_all_map1(get(edge_all, g1)),
edge_all_map2(get(edge_all, g2)) { }
template <typename Edge1, typename Edge2>
void operator()(const Edge1& e1, Edge2& e2) const {
put(edge_all_map2, e2, get(edge_all_map1, add_reverse_edge_descriptor<Edge1, Graph1>::convert(e1)));
}
typename property_map<Graph1, edge_all_t>::const_type edge_all_map1;
mutable typename property_map<Graph2, edge_all_t>::type edge_all_map2;
};
template <typename Graph1, typename Graph2>
inline edge_copier<Graph1,Graph2>
make_edge_copier(const Graph1& g1, Graph2& g2)
{
return edge_copier<Graph1,Graph2>(g1, g2);
}
template <typename Graph1, typename Graph2>
struct vertex_copier {
vertex_copier(const Graph1& g1, Graph2& g2)
: vertex_all_map1(get(vertex_all, g1)),
vertex_all_map2(get(vertex_all, g2)) { }
template <typename Vertex1, typename Vertex2>
void operator()(const Vertex1& v1, Vertex2& v2) const {
put(vertex_all_map2, v2, get(vertex_all_map1, v1));
}
typename property_map<Graph1, vertex_all_t>::const_type vertex_all_map1;
mutable typename property_map<Graph2, vertex_all_t>::type
vertex_all_map2;
};
template <typename Graph1, typename Graph2>
inline vertex_copier<Graph1,Graph2>
make_vertex_copier(const Graph1& g1, Graph2& g2)
{
return vertex_copier<Graph1,Graph2>(g1, g2);
}
// Copy all the vertices and edges of graph g_in into graph g_out.
// The copy_vertex and copy_edge function objects control how vertex
// and edge properties are copied.
template <int Version>
struct copy_graph_impl { };
template <> struct copy_graph_impl<0>
{
template <typename Graph, typename MutableGraph,
typename CopyVertex, typename CopyEdge, typename IndexMap,
typename Orig2CopyVertexIndexMap>
static void apply(const Graph& g_in, MutableGraph& g_out,
CopyVertex copy_vertex, CopyEdge copy_edge,
Orig2CopyVertexIndexMap orig2copy, IndexMap)
{
typedef remove_reverse_edge_descriptor<Graph, typename graph_traits<Graph>::edge_descriptor> cvt;
typename graph_traits<Graph>::vertex_iterator vi, vi_end;
for (boost::tie(vi, vi_end) = vertices(g_in); vi != vi_end; ++vi) {
typename graph_traits<MutableGraph>::vertex_descriptor
new_v = add_vertex(g_out);
put(orig2copy, *vi, new_v);
copy_vertex(*vi, new_v);
}
typename graph_traits<Graph>::edge_iterator ei, ei_end;
for (boost::tie(ei, ei_end) = edges(g_in); ei != ei_end; ++ei) {
typename graph_traits<MutableGraph>::edge_descriptor new_e;
bool inserted;
boost::tie(new_e, inserted) = add_edge(get(orig2copy, source(*ei, g_in)),
get(orig2copy, target(*ei, g_in)),
g_out);
copy_edge(cvt::convert(*ei, g_in), new_e);
}
}
};
// for directed graphs
template <> struct copy_graph_impl<1>
{
template <typename Graph, typename MutableGraph,
typename CopyVertex, typename CopyEdge, typename IndexMap,
typename Orig2CopyVertexIndexMap>
static void apply(const Graph& g_in, MutableGraph& g_out,
CopyVertex copy_vertex, CopyEdge copy_edge,
Orig2CopyVertexIndexMap orig2copy, IndexMap)
{
typedef remove_reverse_edge_descriptor<Graph, typename graph_traits<Graph>::edge_descriptor> cvt;
typename graph_traits<Graph>::vertex_iterator vi, vi_end;
for (boost::tie(vi, vi_end) = vertices(g_in); vi != vi_end; ++vi) {
typename graph_traits<MutableGraph>::vertex_descriptor
new_v = add_vertex(g_out);
put(orig2copy, *vi, new_v);
copy_vertex(*vi, new_v);
}
for (boost::tie(vi, vi_end) = vertices(g_in); vi != vi_end; ++vi) {
typename graph_traits<Graph>::out_edge_iterator ei, ei_end;
for (boost::tie(ei, ei_end) = out_edges(*vi, g_in); ei != ei_end; ++ei) {
typename graph_traits<MutableGraph>::edge_descriptor new_e;
bool inserted;
boost::tie(new_e, inserted) = add_edge(get(orig2copy, source(*ei, g_in)),
get(orig2copy, target(*ei, g_in)),
g_out);
copy_edge(cvt::convert(*ei, g_in), new_e);
}
}
}
};
// for undirected graphs
template <> struct copy_graph_impl<2>
{
template <typename Graph, typename MutableGraph,
typename CopyVertex, typename CopyEdge, typename IndexMap,
typename Orig2CopyVertexIndexMap>
static void apply(const Graph& g_in, MutableGraph& g_out,
CopyVertex copy_vertex, CopyEdge copy_edge,
Orig2CopyVertexIndexMap orig2copy,
IndexMap index_map)
{
typedef remove_reverse_edge_descriptor<Graph, typename graph_traits<Graph>::edge_descriptor> cvt;
typedef color_traits<default_color_type> Color;
std::vector<default_color_type>
color(num_vertices(g_in), Color::white());
typename graph_traits<Graph>::vertex_iterator vi, vi_end;
for (boost::tie(vi, vi_end) = vertices(g_in); vi != vi_end; ++vi) {
typename graph_traits<MutableGraph>::vertex_descriptor
new_v = add_vertex(g_out);
put(orig2copy, *vi, new_v);
copy_vertex(*vi, new_v);
}
for (boost::tie(vi, vi_end) = vertices(g_in); vi != vi_end; ++vi) {
typename graph_traits<Graph>::out_edge_iterator ei, ei_end;
for (boost::tie(ei, ei_end) = out_edges(*vi, g_in); ei != ei_end; ++ei) {
typename graph_traits<MutableGraph>::edge_descriptor new_e;
bool inserted;
if (color[get(index_map, target(*ei, g_in))] == Color::white()) {
boost::tie(new_e, inserted) = add_edge(get(orig2copy, source(*ei,g_in)),
get(orig2copy, target(*ei,g_in)),
g_out);
copy_edge(cvt::convert(*ei, g_in), new_e);
}
}
color[get(index_map, *vi)] = Color::black();
}
}
};
template <class Graph>
struct choose_graph_copy {
typedef typename Graph::traversal_category Trv;
typedef typename Graph::directed_category Dr;
enum { algo =
(is_convertible<Trv, vertex_list_graph_tag>::value
&& is_convertible<Trv, edge_list_graph_tag>::value)
? 0 : is_convertible<Dr, directed_tag>::value ? 1 : 2 };
typedef copy_graph_impl<algo> type;
};
//-------------------------------------------------------------------------
struct choose_copier_parameter {
template <class P, class G1, class G2>
struct bind_ {
typedef const P& result_type;
static result_type apply(const P& p, const G1&, G2&)
{ return p; }
};
};
struct choose_default_edge_copier {
template <class P, class G1, class G2>
struct bind_ {
typedef edge_copier<G1, G2> result_type;
static result_type apply(const P&, const G1& g1, G2& g2) {
return result_type(g1, g2);
}
};
};
template <class Param>
struct choose_edge_copy {
typedef choose_copier_parameter type;
};
template <>
struct choose_edge_copy<param_not_found> {
typedef choose_default_edge_copier type;
};
template <class Param, class G1, class G2>
struct choose_edge_copier_helper {
typedef typename choose_edge_copy<Param>::type Selector;
typedef typename Selector:: template bind_<Param, G1, G2> Bind;
typedef Bind type;
typedef typename Bind::result_type result_type;
};
template <typename Param, typename G1, typename G2>
typename detail::choose_edge_copier_helper<Param,G1,G2>::result_type
choose_edge_copier(const Param& params, const G1& g_in, G2& g_out)
{
typedef typename
detail::choose_edge_copier_helper<Param,G1,G2>::type Choice;
return Choice::apply(params, g_in, g_out);
}
struct choose_default_vertex_copier {
template <class P, class G1, class G2>
struct bind_ {
typedef vertex_copier<G1, G2> result_type;
static result_type apply(const P&, const G1& g1, G2& g2) {
return result_type(g1, g2);
}
};
};
template <class Param>
struct choose_vertex_copy {
typedef choose_copier_parameter type;
};
template <>
struct choose_vertex_copy<param_not_found> {
typedef choose_default_vertex_copier type;
};
template <class Param, class G1, class G2>
struct choose_vertex_copier_helper {
typedef typename choose_vertex_copy<Param>::type Selector;
typedef typename Selector:: template bind_<Param, G1, G2> Bind;
typedef Bind type;
typedef typename Bind::result_type result_type;
};
template <typename Param, typename G1, typename G2>
typename detail::choose_vertex_copier_helper<Param,G1,G2>::result_type
choose_vertex_copier(const Param& params, const G1& g_in, G2& g_out)
{
typedef typename
detail::choose_vertex_copier_helper<Param,G1,G2>::type Choice;
return Choice::apply(params, g_in, g_out);
}
} // namespace detail
template <typename VertexListGraph, typename MutableGraph>
void copy_graph(const VertexListGraph& g_in, MutableGraph& g_out)
{
if (num_vertices(g_in) == 0)
return;
typedef typename graph_traits<MutableGraph>::vertex_descriptor vertex_t;
std::vector<vertex_t> orig2copy(num_vertices(g_in));
typedef typename detail::choose_graph_copy<VertexListGraph>::type
copy_impl;
copy_impl::apply
(g_in, g_out,
detail::make_vertex_copier(g_in, g_out),
detail::make_edge_copier(g_in, g_out),
make_iterator_property_map(orig2copy.begin(),
get(vertex_index, g_in), orig2copy[0]),
get(vertex_index, g_in)
);
}
template <typename VertexListGraph, typename MutableGraph,
class P, class T, class R>
void copy_graph(const VertexListGraph& g_in, MutableGraph& g_out,
const bgl_named_params<P, T, R>& params)
{
typename std::vector<T>::size_type n;
n = is_default_param(get_param(params, orig_to_copy_t()))
? num_vertices(g_in) : 1;
if (n == 0)
return;
std::vector<BOOST_DEDUCED_TYPENAME graph_traits<MutableGraph>::vertex_descriptor>
orig2copy(n);
typedef typename detail::choose_graph_copy<VertexListGraph>::type
copy_impl;
copy_impl::apply
(g_in, g_out,
detail::choose_vertex_copier(get_param(params, vertex_copy_t()),
g_in, g_out),
detail::choose_edge_copier(get_param(params, edge_copy_t()),
g_in, g_out),
choose_param(get_param(params, orig_to_copy_t()),
make_iterator_property_map
(orig2copy.begin(),
choose_const_pmap(get_param(params, vertex_index),
g_in, vertex_index), orig2copy[0])),
choose_const_pmap(get_param(params, vertex_index), g_in, vertex_index)
);
}
namespace detail {
template <class NewGraph, class Copy2OrigIndexMap,
class CopyVertex, class CopyEdge>
struct graph_copy_visitor : public bfs_visitor<>
{
graph_copy_visitor(NewGraph& graph, Copy2OrigIndexMap c,
CopyVertex cv, CopyEdge ce)
: g_out(graph), orig2copy(c), copy_vertex(cv), copy_edge(ce) { }
template <class Vertex, class Graph>
typename graph_traits<NewGraph>::vertex_descriptor copy_one_vertex(Vertex u) const {
typename graph_traits<NewGraph>::vertex_descriptor
new_u = add_vertex(g_out);
put(orig2copy, u, new_u);
copy_vertex(u, new_u);
return new_u;
}
template <class Edge, class Graph>
void tree_edge(Edge e, const Graph& g_in) const {
// For a tree edge, the target vertex has not been copied yet.
typename graph_traits<NewGraph>::edge_descriptor new_e;
bool inserted;
boost::tie(new_e, inserted) = add_edge(get(orig2copy, source(e, g_in)),
this->copy_one_vertex(target(e, g_in)),
g_out);
copy_edge(e, new_e);
}
template <class Edge, class Graph>
void non_tree_edge(Edge e, const Graph& g_in) const {
// For a non-tree edge, the target vertex has already been copied.
typename graph_traits<NewGraph>::edge_descriptor new_e;
bool inserted;
boost::tie(new_e, inserted) = add_edge(get(orig2copy, source(e, g_in)),
get(orig2copy, target(e, g_in)),
g_out);
copy_edge(e, new_e);
}
private:
NewGraph& g_out;
Copy2OrigIndexMap orig2copy;
CopyVertex copy_vertex;
CopyEdge copy_edge;
};
template <typename Graph, typename MutableGraph,
typename CopyVertex, typename CopyEdge,
typename Orig2CopyVertexIndexMap, typename Params>
typename graph_traits<MutableGraph>::vertex_descriptor
copy_component_impl
(const Graph& g_in,
typename graph_traits<Graph>::vertex_descriptor src,
MutableGraph& g_out,
CopyVertex copy_vertex, CopyEdge copy_edge,
Orig2CopyVertexIndexMap orig2copy,
const Params& params)
{
graph_copy_visitor<MutableGraph, Orig2CopyVertexIndexMap,
CopyVertex, CopyEdge> vis(g_out, orig2copy, copy_vertex, copy_edge);
typename graph_traits<MutableGraph>::vertex_descriptor src_copy
= vis.copy_one_vertex(src);
breadth_first_search(g_in, src, params.visitor(vis));
return src_copy;
}
} // namespace detail
// Copy all the vertices and edges of graph g_in that are reachable
// from the source vertex into graph g_out. Return the vertex
// in g_out that matches the source vertex of g_in.
template <typename IncidenceGraph, typename MutableGraph,
typename P, typename T, typename R>
typename graph_traits<MutableGraph>::vertex_descriptor
copy_component(IncidenceGraph& g_in,
typename graph_traits<IncidenceGraph>::vertex_descriptor src,
MutableGraph& g_out,
const bgl_named_params<P, T, R>& params)
{
typename std::vector<T>::size_type n;
n = is_default_param(get_param(params, orig_to_copy_t()))
? num_vertices(g_in) : 1;
std::vector<typename graph_traits<IncidenceGraph>::vertex_descriptor>
orig2copy(n);
return detail::copy_component_impl
(g_in, src, g_out,
detail::choose_vertex_copier(get_param(params, vertex_copy_t()),
g_in, g_out),
detail::choose_edge_copier(get_param(params, edge_copy_t()),
g_in, g_out),
choose_param(get_param(params, orig_to_copy_t()),
make_iterator_property_map
(orig2copy.begin(),
choose_pmap(get_param(params, vertex_index),
g_in, vertex_index), orig2copy[0])),
params
);
}
template <typename IncidenceGraph, typename MutableGraph>
typename graph_traits<MutableGraph>::vertex_descriptor
copy_component(IncidenceGraph& g_in,
typename graph_traits<IncidenceGraph>::vertex_descriptor src,
MutableGraph& g_out)
{
std::vector<typename graph_traits<IncidenceGraph>::vertex_descriptor>
orig2copy(num_vertices(g_in));
return detail::copy_component_impl
(g_in, src, g_out,
make_vertex_copier(g_in, g_out),
make_edge_copier(g_in, g_out),
make_iterator_property_map(orig2copy.begin(),
get(vertex_index, g_in), orig2copy[0]),
bgl_named_params<char,char>('x') // dummy param object
);
}
} // namespace boost
#endif // BOOST_GRAPH_COPY_HPP
@@ -0,0 +1,352 @@
//
//=======================================================================
// Copyright 2007 Stanford University
// Authors: David Gleich
//
// 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_GRAPH_CORE_NUMBERS_HPP
#define BOOST_GRAPH_CORE_NUMBERS_HPP
#include <boost/graph/detail/d_ary_heap.hpp>
#include <boost/graph/breadth_first_search.hpp>
#include <boost/iterator/reverse_iterator.hpp>
#include <boost/concept/assert.hpp>
/*
* core_numbers
*
* Requirement: IncidenceGraph
*/
// History
//
// 30 July 2007
// Added visitors to the implementation
//
// 8 February 2008
// Fixed headers and missing typename
namespace boost {
// A linear time O(m) algorithm to compute the indegree core number
// of a graph for unweighted graphs.
//
// and a O((n+m) log n) algorithm to compute the in-edge-weight core
// numbers of a weighted graph.
//
// The linear algorithm comes from:
// Vladimir Batagelj and Matjaz Zaversnik, "An O(m) Algorithm for Cores
// Decomposition of Networks." Sept. 1 2002.
template <typename Visitor, typename Graph>
struct CoreNumbersVisitorConcept {
void constraints()
{
BOOST_CONCEPT_ASSERT(( CopyConstructibleConcept<Visitor> ));
vis.examine_vertex(u,g);
vis.finish_vertex(u,g);
vis.examine_edge(e,g);
}
Visitor vis;
Graph g;
typename graph_traits<Graph>::vertex_descriptor u;
typename graph_traits<Graph>::edge_descriptor e;
};
template <class Visitors = null_visitor>
class core_numbers_visitor : public bfs_visitor<Visitors> {
public:
core_numbers_visitor() {}
core_numbers_visitor(Visitors vis)
: bfs_visitor<Visitors>(vis) {}
private:
template <class Vertex, class Graph>
void initialize_vertex(Vertex, Graph&) {}
template <class Vertex, class Graph>
void discover_vertex(Vertex , Graph&) {}
template <class Vertex, class Graph>
void gray_target(Vertex, Graph&) {}
template <class Vertex, class Graph>
void black_target(Vertex, Graph&) {}
template <class Edge, class Graph>
void tree_edge(Edge, Graph&) {}
template <class Edge, class Graph>
void non_tree_edge(Edge, Graph&) {}
};
template <class Visitors>
core_numbers_visitor<Visitors> make_core_numbers_visitor(Visitors vis)
{ return core_numbers_visitor<Visitors>(vis); }
typedef core_numbers_visitor<> default_core_numbers_visitor;
namespace detail {
// implement a constant_property_map to simplify compute_in_degree
// for the weighted and unweighted case
// this is based on dummy property map
template <typename ValueType>
class constant_value_property_map
: public boost::put_get_helper<ValueType,
constant_value_property_map<ValueType> >
{
public:
typedef void key_type;
typedef ValueType value_type;
typedef const ValueType& reference;
typedef boost::readable_property_map_tag category;
inline constant_value_property_map(ValueType cc) : c(cc) { }
inline constant_value_property_map(const constant_value_property_map<ValueType>& x)
: c(x.c) { }
template <class Vertex>
inline reference operator[](Vertex) const { return c; }
protected:
ValueType c;
};
// the core numbers start as the indegree or inweight. This function
// will initialize these values
template <typename Graph, typename CoreMap, typename EdgeWeightMap>
void compute_in_degree_map(Graph& g, CoreMap d, EdgeWeightMap wm)
{
typename graph_traits<Graph>::vertex_iterator vi,vi_end;
typename graph_traits<Graph>::out_edge_iterator ei,ei_end;
for (boost::tie(vi,vi_end) = vertices(g); vi!=vi_end; ++vi) {
put(d,*vi,0);
}
for (boost::tie(vi,vi_end) = vertices(g); vi!=vi_end; ++vi) {
for (boost::tie(ei,ei_end) = out_edges(*vi,g); ei!=ei_end; ++ei) {
put(d,target(*ei,g),get(d,target(*ei,g))+get(wm,*ei));
}
}
}
// the version for weighted graphs is a little different
template <typename Graph, typename CoreMap,
typename EdgeWeightMap, typename MutableQueue,
typename Visitor>
typename property_traits<CoreMap>::value_type
core_numbers_impl(Graph& g, CoreMap c, EdgeWeightMap wm,
MutableQueue& Q, Visitor vis)
{
typename property_traits<CoreMap>::value_type v_cn = 0;
typedef typename graph_traits<Graph>::vertex_descriptor vertex;
while (!Q.empty())
{
// remove v from the Q, and then decrease the core numbers
// of its successors
vertex v = Q.top();
vis.examine_vertex(v,g);
Q.pop();
v_cn = get(c,v);
typename graph_traits<Graph>::out_edge_iterator oi,oi_end;
for (boost::tie(oi,oi_end) = out_edges(v,g); oi!=oi_end; ++oi) {
vis.examine_edge(*oi,g);
vertex u = target(*oi,g);
// if c[u] > c[v], then u is still in the graph,
if (get(c,u) > v_cn) {
// remove the edge
put(c,u,get(c,u)-get(wm,*oi));
if (Q.contains(u))
Q.update(u);
}
}
vis.finish_vertex(v,g);
}
return (v_cn);
}
template <typename Graph, typename CoreMap, typename EdgeWeightMap,
typename IndexMap, typename CoreNumVisitor>
typename property_traits<CoreMap>::value_type
core_numbers_dispatch(Graph&g, CoreMap c, EdgeWeightMap wm,
IndexMap im, CoreNumVisitor vis)
{
typedef typename property_traits<CoreMap>::value_type D;
typedef std::less<D> Cmp;
// build the mutable queue
typedef typename graph_traits<Graph>::vertex_descriptor vertex;
std::vector<std::size_t> index_in_heap_data(num_vertices(g));
typedef iterator_property_map<std::vector<std::size_t>::iterator, IndexMap>
index_in_heap_map_type;
index_in_heap_map_type index_in_heap_map(index_in_heap_data.begin(), im);
typedef d_ary_heap_indirect<vertex, 4, index_in_heap_map_type, CoreMap, Cmp> MutableQueue;
MutableQueue Q(c, index_in_heap_map, Cmp());
typename graph_traits<Graph>::vertex_iterator vi,vi_end;
for (boost::tie(vi,vi_end) = vertices(g); vi!=vi_end; ++vi) {
Q.push(*vi);
}
return core_numbers_impl(g, c, wm, Q, vis);
}
// the version for the unweighted case
// for this functions CoreMap must be initialized
// with the in degree of each vertex
template <typename Graph, typename CoreMap, typename PositionMap,
typename Visitor>
typename property_traits<CoreMap>::value_type
core_numbers_impl(Graph& g, CoreMap c, PositionMap pos, Visitor vis)
{
typedef typename graph_traits<Graph>::vertices_size_type size_type;
typedef typename graph_traits<Graph>::degree_size_type degree_type;
typedef typename graph_traits<Graph>::vertex_descriptor vertex;
typename graph_traits<Graph>::vertex_iterator vi,vi_end;
// store the vertex core numbers
typename property_traits<CoreMap>::value_type v_cn = 0;
// compute the maximum degree (degrees are in the coremap)
typename graph_traits<Graph>::degree_size_type max_deg = 0;
for (boost::tie(vi,vi_end) = vertices(g); vi!=vi_end; ++vi) {
max_deg = (std::max<typename graph_traits<Graph>::degree_size_type>)(max_deg, get(c,*vi));
}
// store the vertices in bins by their degree
// allocate two extra locations to ease boundary cases
std::vector<size_type> bin(max_deg+2);
for (boost::tie(vi,vi_end) = vertices(g); vi!=vi_end; ++vi) {
++bin[get(c,*vi)];
}
// this loop sets bin[d] to the starting position of vertices
// with degree d in the vert array for the bucket sort
size_type cur_pos = 0;
for (degree_type cur_deg = 0; cur_deg < max_deg+2; ++cur_deg) {
degree_type tmp = bin[cur_deg];
bin[cur_deg] = cur_pos;
cur_pos += tmp;
}
// perform the bucket sort with pos and vert so that
// pos[0] is the vertex of smallest degree
std::vector<vertex> vert(num_vertices(g));
for (boost::tie(vi,vi_end) = vertices(g); vi!=vi_end; ++vi) {
vertex v=*vi;
size_type p=bin[get(c,v)];
put(pos,v,p);
vert[p]=v;
++bin[get(c,v)];
}
// we ``abused'' bin while placing the vertices, now,
// we need to restore it
std::copy(boost::make_reverse_iterator(bin.end()-2),
boost::make_reverse_iterator(bin.begin()),
boost::make_reverse_iterator(bin.end()-1));
// now simulate removing the vertices
for (size_type i=0; i < num_vertices(g); ++i) {
vertex v = vert[i];
vis.examine_vertex(v,g);
v_cn = get(c,v);
typename graph_traits<Graph>::out_edge_iterator oi,oi_end;
for (boost::tie(oi,oi_end) = out_edges(v,g); oi!=oi_end; ++oi) {
vis.examine_edge(*oi,g);
vertex u = target(*oi,g);
// if c[u] > c[v], then u is still in the graph,
if (get(c,u) > v_cn) {
degree_type deg_u = get(c,u);
degree_type pos_u = get(pos,u);
// w is the first vertex with the same degree as u
// (this is the resort operation!)
degree_type pos_w = bin[deg_u];
vertex w = vert[pos_w];
if (u!=v) {
// swap u and w
put(pos,u,pos_w);
put(pos,w,pos_u);
vert[pos_w] = u;
vert[pos_u] = w;
}
// now, the vertices array is sorted assuming
// we perform the following step
// start the set of vertices with degree of u
// one into the future (this now points at vertex
// w which we swapped with u).
++bin[deg_u];
// we are removing v from the graph, so u's degree
// decreases
put(c,u,get(c,u)-1);
}
}
vis.finish_vertex(v,g);
}
return v_cn;
}
} // namespace detail
// non-named parameter version for the unweighted case
template <typename Graph, typename CoreMap, typename CoreNumVisitor>
typename property_traits<CoreMap>::value_type
core_numbers(Graph& g, CoreMap c, CoreNumVisitor vis)
{
typedef typename graph_traits<Graph>::vertices_size_type size_type;
detail::compute_in_degree_map(g,c,
detail::constant_value_property_map<
typename property_traits<CoreMap>::value_type>(1) );
return detail::core_numbers_impl(g,c,
make_iterator_property_map(
std::vector<size_type>(num_vertices(g)).begin(),get(vertex_index, g)),
vis
);
}
// non-named paramter version for the unweighted case
template <typename Graph, typename CoreMap>
typename property_traits<CoreMap>::value_type
core_numbers(Graph& g, CoreMap c)
{
return core_numbers(g, c, make_core_numbers_visitor(null_visitor()));
}
// non-named parameter version for the weighted case
template <typename Graph, typename CoreMap, typename EdgeWeightMap,
typename VertexIndexMap, typename CoreNumVisitor>
typename property_traits<CoreMap>::value_type
core_numbers(Graph& g, CoreMap c, EdgeWeightMap wm, VertexIndexMap vim,
CoreNumVisitor vis)
{
typedef typename graph_traits<Graph>::vertices_size_type size_type;
detail::compute_in_degree_map(g,c,wm);
return detail::core_numbers_dispatch(g,c,wm,vim,vis);
}
// non-named parameter version for the weighted case
// template <typename Graph, typename CoreMap, typename EdgeWeightMap>
// typename property_traits<CoreMap>::value_type
// core_numbers(Graph& g, CoreMap c, EdgeWeightMap wm)
// {
// typedef typename graph_traits<Graph>::vertices_size_type size_type;
// detail::compute_in_degree_map(g,c,wm);
// return detail::core_numbers_dispatch(g,c,wm,get(vertex_index,g),
// make_core_numbers_visitor(null_visitor()));
// }
template <typename Graph, typename CoreMap>
typename property_traits<CoreMap>::value_type
weighted_core_numbers(Graph& g, CoreMap c)
{
return weighted_core_numbers(
g,c, make_core_numbers_visitor(null_visitor())
);
}
template <typename Graph, typename CoreMap, typename CoreNumVisitor>
typename property_traits<CoreMap>::value_type
weighted_core_numbers(Graph& g, CoreMap c, CoreNumVisitor vis)
{ return core_numbers(g,c,get(edge_weight,g),get(vertex_index,g),vis); }
} // namespace boost
#endif // BOOST_GRAPH_CORE_NUMBERS_HPP
@@ -0,0 +1,83 @@
//=======================================================================
// Copyright 2002 Indiana University.
// 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_CREATE_CONDENSATION_GRAPH_HPP
#define BOOST_CREATE_CONDENSATION_GRAPH_HPP
#include <boost/graph/graph_traits.hpp>
#include <boost/property_map/property_map.hpp>
namespace boost {
template <typename Graph, typename ComponentLists,
typename ComponentNumberMap,
typename CondensationGraph, typename EdgeMultiplicityMap>
void create_condensation_graph(const Graph& g,
const ComponentLists& components,
ComponentNumberMap component_number,
CondensationGraph& cg,
EdgeMultiplicityMap edge_mult_map)
{
typedef typename graph_traits<Graph>::vertex_descriptor vertex;
typedef typename graph_traits<Graph>::vertices_size_type size_type;
typedef typename graph_traits<CondensationGraph>::vertex_descriptor
cg_vertex;
std::vector<cg_vertex> to_cg_vertex(components.size());
for (size_type s = 0; s < components.size(); ++s)
to_cg_vertex[s] = add_vertex(cg);
for (size_type si = 0; si < components.size(); ++si) {
cg_vertex s = to_cg_vertex[si];
std::vector<cg_vertex> adj;
for (size_type i = 0; i < components[si].size(); ++i) {
vertex u = components[s][i];
typename graph_traits<Graph>::adjacency_iterator v, v_end;
for (boost::tie(v, v_end) = adjacent_vertices(u, g); v != v_end; ++v) {
cg_vertex t = to_cg_vertex[component_number[*v]];
if (s != t) // Avoid loops in the condensation graph
adj.push_back(t);
}
}
std::sort(adj.begin(), adj.end());
if (! adj.empty()) {
size_type i = 0;
cg_vertex t = adj[i];
typename graph_traits<CondensationGraph>::edge_descriptor e;
bool inserted;
boost::tie(e, inserted) = add_edge(s, t, cg);
put(edge_mult_map, e, 1);
++i;
while (i < adj.size()) {
if (adj[i] == t)
put(edge_mult_map, e, get(edge_mult_map, e) + 1);
else {
t = adj[i];
boost::tie(e, inserted) = add_edge(s, t, cg);
put(edge_mult_map, e, 1);
}
++i;
}
}
}
}
template <typename Graph, typename ComponentLists,
typename ComponentNumberMap, typename CondensationGraph>
void create_condensation_graph(const Graph& g,
const ComponentLists& components,
ComponentNumberMap component_number,
CondensationGraph& cg)
{
create_condensation_graph(g, components, component_number, cg,
dummy_property_map());
}
} // namespace boost
#endif // BOOST_CREATE_CONDENSATION_GRAPH_HPP
@@ -0,0 +1,191 @@
//=======================================================================
// Copyright 1997, 1998, 1999, 2000 University of Notre Dame.
// Copyright 2004, 2005 Trustees of Indiana University
// Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek,
// Doug Gregor, D. Kevin McGrath
//
// 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_GRAPH_CUTHILL_MCKEE_HPP
#define BOOST_GRAPH_CUTHILL_MCKEE_HPP
#include <boost/config.hpp>
#include <boost/graph/detail/sparse_ordering.hpp>
#include <boost/graph/graph_utility.hpp>
#include <algorithm>
/*
(Reverse) Cuthill-McKee Algorithm for matrix reordering
*/
namespace boost {
namespace detail {
template < typename OutputIterator, typename Buffer, typename DegreeMap >
class bfs_rcm_visitor:public default_bfs_visitor
{
public:
bfs_rcm_visitor(OutputIterator *iter, Buffer *b, DegreeMap deg):
permutation(iter), Qptr(b), degree(deg) { }
template <class Vertex, class Graph>
void examine_vertex(Vertex u, Graph&) {
*(*permutation)++ = u;
index_begin = Qptr->size();
}
template <class Vertex, class Graph>
void finish_vertex(Vertex, Graph&) {
using std::sort;
typedef typename property_traits<DegreeMap>::value_type ds_type;
typedef indirect_cmp<DegreeMap, std::less<ds_type> > Compare;
Compare comp(degree);
sort(Qptr->begin()+index_begin, Qptr->end(), comp);
}
protected:
OutputIterator *permutation;
int index_begin;
Buffer *Qptr;
DegreeMap degree;
};
} // namespace detail
// Reverse Cuthill-McKee algorithm with a given starting Vertex.
//
// If user provides a reverse iterator, this will be a reverse-cuthill-mckee
// algorithm, otherwise it will be a standard CM algorithm
template <class Graph, class OutputIterator,
class ColorMap, class DegreeMap>
OutputIterator
cuthill_mckee_ordering(const Graph& g,
std::deque< typename
graph_traits<Graph>::vertex_descriptor > vertex_queue,
OutputIterator permutation,
ColorMap color, DegreeMap degree)
{
//create queue, visitor...don't forget namespaces!
typedef typename property_traits<DegreeMap>::value_type ds_type;
typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
typedef typename boost::sparse::sparse_ordering_queue<Vertex> queue;
typedef typename detail::bfs_rcm_visitor<OutputIterator, queue, DegreeMap> Visitor;
typedef typename property_traits<ColorMap>::value_type ColorValue;
typedef color_traits<ColorValue> Color;
queue Q;
//create a bfs_rcm_visitor as defined above
Visitor vis(&permutation, &Q, degree);
typename graph_traits<Graph>::vertex_iterator ui, ui_end;
// Copy degree to pseudo_degree
// initialize the color map
for (boost::tie(ui, ui_end) = vertices(g); ui != ui_end; ++ui){
put(color, *ui, Color::white());
}
while( !vertex_queue.empty() ) {
Vertex s = vertex_queue.front();
vertex_queue.pop_front();
//call BFS with visitor
breadth_first_visit(g, s, Q, vis, color);
}
return permutation;
}
// This is the case where only a single starting vertex is supplied.
template <class Graph, class OutputIterator,
class ColorMap, class DegreeMap>
OutputIterator
cuthill_mckee_ordering(const Graph& g,
typename graph_traits<Graph>::vertex_descriptor s,
OutputIterator permutation,
ColorMap color, DegreeMap degree)
{
std::deque< typename graph_traits<Graph>::vertex_descriptor > vertex_queue;
vertex_queue.push_front( s );
return cuthill_mckee_ordering(g, vertex_queue, permutation, color, degree);
}
// This is the version of CM which selects its own starting vertex
template < class Graph, class OutputIterator,
class ColorMap, class DegreeMap>
OutputIterator
cuthill_mckee_ordering(const Graph& G, OutputIterator permutation,
ColorMap color, DegreeMap degree)
{
if (boost::graph::has_no_vertices(G))
return permutation;
typedef typename boost::graph_traits<Graph>::vertex_descriptor Vertex;
typedef typename boost::graph_traits<Graph>::vertex_iterator VerIter;
typedef typename property_traits<ColorMap>::value_type ColorValue;
typedef color_traits<ColorValue> Color;
std::deque<Vertex> vertex_queue;
// Mark everything white
BGL_FORALL_VERTICES_T(v, G, Graph) put(color, v, Color::white());
// Find one vertex from each connected component
BGL_FORALL_VERTICES_T(v, G, Graph) {
if (get(color, v) == Color::white()) {
depth_first_visit(G, v, dfs_visitor<>(), color);
vertex_queue.push_back(v);
}
}
// Find starting nodes for all vertices
// TBD: How to do this with a directed graph?
for (typename std::deque<Vertex>::iterator i = vertex_queue.begin();
i != vertex_queue.end(); ++i)
*i = find_starting_node(G, *i, color, degree);
return cuthill_mckee_ordering(G, vertex_queue, permutation,
color, degree);
}
template<typename Graph, typename OutputIterator, typename VertexIndexMap>
OutputIterator
cuthill_mckee_ordering(const Graph& G, OutputIterator permutation,
VertexIndexMap index_map)
{
if (boost::graph::has_no_vertices(G))
return permutation;
typedef out_degree_property_map<Graph> DegreeMap;
std::vector<default_color_type> colors(num_vertices(G));
return cuthill_mckee_ordering(G, permutation,
make_iterator_property_map(&colors[0],
index_map,
colors[0]),
make_out_degree_map(G));
}
template<typename Graph, typename OutputIterator>
inline OutputIterator
cuthill_mckee_ordering(const Graph& G, OutputIterator permutation)
{ return cuthill_mckee_ordering(G, permutation, get(vertex_index, G)); }
} // namespace boost
#endif // BOOST_GRAPH_CUTHILL_MCKEE_HPP
@@ -0,0 +1,159 @@
//=======================================================================
// Copyright 2002 Indiana University.
// 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_GRAPH_DAG_SHORTEST_PATHS_HPP
#define BOOST_GRAPH_DAG_SHORTEST_PATHS_HPP
#include <boost/graph/topological_sort.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
// single-source shortest paths for a Directed Acyclic Graph (DAG)
namespace boost {
// Initalize distances and call depth first search
template <class VertexListGraph, class DijkstraVisitor,
class DistanceMap, class WeightMap, class ColorMap,
class PredecessorMap,
class Compare, class Combine,
class DistInf, class DistZero>
inline void
dag_shortest_paths
(const VertexListGraph& g,
typename graph_traits<VertexListGraph>::vertex_descriptor s,
DistanceMap distance, WeightMap weight, ColorMap color,
PredecessorMap pred,
DijkstraVisitor vis, Compare compare, Combine combine,
DistInf inf, DistZero zero)
{
typedef typename graph_traits<VertexListGraph>::vertex_descriptor Vertex;
std::vector<Vertex> rev_topo_order;
rev_topo_order.reserve(num_vertices(g));
// Call 'depth_first_visit', not 'topological_sort', because we don't
// want to traverse the entire graph, only vertices reachable from 's',
// and 'topological_sort' will traverse everything. The logic below
// is the same as for 'topological_sort', only we call 'depth_first_visit'
// and 'topological_sort' calls 'depth_first_search'.
topo_sort_visitor<std::back_insert_iterator<std::vector<Vertex> > >
topo_visitor(std::back_inserter(rev_topo_order));
depth_first_visit(g, s, topo_visitor, color);
typename graph_traits<VertexListGraph>::vertex_iterator ui, ui_end;
for (boost::tie(ui, ui_end) = vertices(g); ui != ui_end; ++ui) {
put(distance, *ui, inf);
put(pred, *ui, *ui);
}
put(distance, s, zero);
vis.discover_vertex(s, g);
typename std::vector<Vertex>::reverse_iterator i;
for (i = rev_topo_order.rbegin(); i != rev_topo_order.rend(); ++i) {
Vertex u = *i;
vis.examine_vertex(u, g);
typename graph_traits<VertexListGraph>::out_edge_iterator e, e_end;
for (boost::tie(e, e_end) = out_edges(u, g); e != e_end; ++e) {
vis.discover_vertex(target(*e, g), g);
bool decreased = relax(*e, g, weight, pred, distance,
combine, compare);
if (decreased)
vis.edge_relaxed(*e, g);
else
vis.edge_not_relaxed(*e, g);
}
vis.finish_vertex(u, g);
}
}
namespace detail {
// Defaults are the same as Dijkstra's algorithm
// Handle Distance Compare, Combine, Inf and Zero defaults
template <class VertexListGraph, class DijkstraVisitor,
class DistanceMap, class WeightMap, class ColorMap,
class IndexMap, class Params>
inline void
dag_sp_dispatch2
(const VertexListGraph& g,
typename graph_traits<VertexListGraph>::vertex_descriptor s,
DistanceMap distance, WeightMap weight, ColorMap color, IndexMap /*id*/,
DijkstraVisitor vis, const Params& params)
{
typedef typename property_traits<DistanceMap>::value_type D;
dummy_property_map p_map;
D inf =
choose_param(get_param(params, distance_inf_t()),
(std::numeric_limits<D>::max)());
dag_shortest_paths
(g, s, distance, weight, color,
choose_param(get_param(params, vertex_predecessor), p_map),
vis,
choose_param(get_param(params, distance_compare_t()), std::less<D>()),
choose_param(get_param(params, distance_combine_t()), closed_plus<D>(inf)),
inf,
choose_param(get_param(params, distance_zero_t()),
D()));
}
// Handle DistanceMap and ColorMap defaults
template <class VertexListGraph, class DijkstraVisitor,
class DistanceMap, class WeightMap, class ColorMap,
class IndexMap, class Params>
inline void
dag_sp_dispatch1
(const VertexListGraph& g,
typename graph_traits<VertexListGraph>::vertex_descriptor s,
DistanceMap distance, WeightMap weight, ColorMap color, IndexMap id,
DijkstraVisitor vis, const Params& params)
{
typedef typename property_traits<WeightMap>::value_type T;
typename std::vector<T>::size_type n;
n = is_default_param(distance) ? num_vertices(g) : 1;
std::vector<T> distance_map(n);
n = is_default_param(color) ? num_vertices(g) : 1;
std::vector<default_color_type> color_map(n);
dag_sp_dispatch2
(g, s,
choose_param(distance,
make_iterator_property_map(distance_map.begin(), id,
distance_map[0])),
weight,
choose_param(color,
make_iterator_property_map(color_map.begin(), id,
color_map[0])),
id, vis, params);
}
} // namespace detail
template <class VertexListGraph, class Param, class Tag, class Rest>
inline void
dag_shortest_paths
(const VertexListGraph& g,
typename graph_traits<VertexListGraph>::vertex_descriptor s,
const bgl_named_params<Param,Tag,Rest>& params)
{
// assert that the graph is directed...
null_visitor null_vis;
detail::dag_sp_dispatch1
(g, s,
get_param(params, vertex_distance),
choose_const_pmap(get_param(params, edge_weight), g, edge_weight),
get_param(params, vertex_color),
choose_const_pmap(get_param(params, vertex_index), g, vertex_index),
choose_param(get_param(params, graph_visitor),
make_dijkstra_visitor(null_vis)),
params);
}
} // namespace boost
#endif // BOOST_GRAPH_DAG_SHORTEST_PATHS_HPP
@@ -0,0 +1,131 @@
// (C) Copyright 2007-2009 Andrew Sutton
//
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0 (See accompanying file
// LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GRAPH_DEGREE_CENTRALITY_HPP
#define BOOST_GRAPH_DEGREE_CENTRALITY_HPP
#include <boost/graph/graph_concepts.hpp>
#include <boost/concept/assert.hpp>
namespace boost {
template <typename Graph>
struct degree_centrality_measure
{
typedef typename graph_traits<Graph>::degree_size_type degree_type;
typedef typename graph_traits<Graph>::vertex_descriptor vertex_type;
};
template <typename Graph>
struct influence_measure
: public degree_centrality_measure<Graph>
{
typedef degree_centrality_measure<Graph> base_type;
typedef typename base_type::degree_type degree_type;
typedef typename base_type::vertex_type vertex_type;
inline degree_type operator ()(vertex_type v, const Graph& g)
{
BOOST_CONCEPT_ASSERT(( IncidenceGraphConcept<Graph> ));
return out_degree(v, g);
}
};
template <typename Graph>
inline influence_measure<Graph>
measure_influence(const Graph&)
{ return influence_measure<Graph>(); }
template <typename Graph>
struct prestige_measure
: public degree_centrality_measure<Graph>
{
typedef degree_centrality_measure<Graph> base_type;
typedef typename base_type::degree_type degree_type;
typedef typename base_type::vertex_type vertex_type;
inline degree_type operator ()(vertex_type v, const Graph& g)
{
BOOST_CONCEPT_ASSERT(( BidirectionalGraphConcept<Graph> ));
return in_degree(v, g);
}
};
template <typename Graph>
inline prestige_measure<Graph>
measure_prestige(const Graph&)
{ return prestige_measure<Graph>(); }
template <typename Graph, typename Vertex, typename Measure>
inline typename Measure::degree_type
degree_centrality(const Graph& g, Vertex v, Measure measure)
{
BOOST_CONCEPT_ASSERT(( DegreeMeasureConcept<Measure, Graph> ));
return measure(v, g);
}
template <typename Graph, typename Vertex>
inline typename graph_traits<Graph>::degree_size_type
degree_centrality(const Graph& g, Vertex v)
{
return degree_centrality(g, v, measure_influence(g));
}
// These are alias functions, intended to provide a more expressive interface.
template <typename Graph, typename Vertex>
inline typename graph_traits<Graph>::degree_size_type
influence(const Graph& g, Vertex v)
{ return degree_centrality(g, v, measure_influence(g)); }
template <typename Graph, typename Vertex>
inline typename graph_traits<Graph>::degree_size_type
prestige(const Graph& g, Vertex v)
{ return degree_centrality(g, v, measure_prestige(g)); }
template <typename Graph, typename CentralityMap, typename Measure>
inline void
all_degree_centralities(const Graph& g, CentralityMap cent, Measure measure)
{
BOOST_CONCEPT_ASSERT(( VertexListGraphConcept<Graph> ));
typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
typedef typename graph_traits<Graph>::vertex_iterator VertexIterator;
BOOST_CONCEPT_ASSERT(( WritablePropertyMapConcept<CentralityMap,Vertex> ));
typedef typename property_traits<CentralityMap>::value_type Centrality;
VertexIterator i, end;
for(boost::tie(i, end) = vertices(g); i != end; ++i) {
Centrality c = degree_centrality(g, *i, measure);
put(cent, *i, c);
}
}
template <typename Graph, typename CentralityMap>
inline void all_degree_centralities(const Graph& g, CentralityMap cent)
{ all_degree_centralities(g, cent, measure_influence(g)); }
// More helper functions for computing influence and prestige.
// I hate the names of these functions, but influence and prestige
// don't pluralize too well.
template <typename Graph, typename CentralityMap>
inline void all_influence_values(const Graph& g, CentralityMap cent)
{ all_degree_centralities(g, cent, measure_influence(g)); }
template <typename Graph, typename CentralityMap>
inline void all_prestige_values(const Graph& g, CentralityMap cent)
{ all_degree_centralities(g, cent, measure_prestige(g)); }
} /* namespace boost */
#endif
@@ -0,0 +1,333 @@
//=======================================================================
// Copyright 1997, 1998, 1999, 2000 University of Notre Dame.
// Copyright 2003 Bruce Barr
// 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)
//=======================================================================
// Nonrecursive implementation of depth_first_visit_impl submitted by
// Bruce Barr, schmoost <at> yahoo.com, May/June 2003.
#ifndef BOOST_GRAPH_RECURSIVE_DFS_HPP
#define BOOST_GRAPH_RECURSIVE_DFS_HPP
#include <boost/config.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/graph_concepts.hpp>
#include <boost/graph/properties.hpp>
#include <boost/graph/visitors.hpp>
#include <boost/graph/named_function_params.hpp>
#include <boost/ref.hpp>
#include <boost/implicit_cast.hpp>
#include <boost/parameter.hpp>
#include <boost/concept/assert.hpp>
#include <vector>
#include <utility>
namespace boost {
template <class Visitor, class Graph>
class DFSVisitorConcept {
public:
void constraints() {
BOOST_CONCEPT_ASSERT(( CopyConstructibleConcept<Visitor> ));
vis.initialize_vertex(u, g);
vis.start_vertex(u, g);
vis.discover_vertex(u, g);
vis.examine_edge(e, g);
vis.tree_edge(e, g);
vis.back_edge(e, g);
vis.forward_or_cross_edge(e, g);
vis.finish_vertex(u, g);
}
private:
Visitor vis;
Graph g;
typename graph_traits<Graph>::vertex_descriptor u;
typename graph_traits<Graph>::edge_descriptor e;
};
namespace detail {
struct nontruth2 {
template<class T, class T2>
bool operator()(const T&, const T2&) const { return false; }
};
// Define BOOST_RECURSIVE_DFS to use older, recursive version.
// It is retained for a while in order to perform performance
// comparison.
#ifndef BOOST_RECURSIVE_DFS
// If the vertex u and the iterators ei and ei_end are thought of as the
// context of the algorithm, each push and pop from the stack could
// be thought of as a context shift.
// Each pass through "while (ei != ei_end)" may refer to the out-edges of
// an entirely different vertex, because the context of the algorithm
// shifts every time a white adjacent vertex is discovered.
// The corresponding context shift back from the adjacent vertex occurs
// after all of its out-edges have been examined.
//
// See http://lists.boost.org/MailArchives/boost/msg48752.php for FAQ.
template <class IncidenceGraph, class DFSVisitor, class ColorMap,
class TerminatorFunc>
void depth_first_visit_impl
(const IncidenceGraph& g,
typename graph_traits<IncidenceGraph>::vertex_descriptor u,
DFSVisitor& vis,
ColorMap color, TerminatorFunc func = TerminatorFunc())
{
BOOST_CONCEPT_ASSERT(( IncidenceGraphConcept<IncidenceGraph> ));
BOOST_CONCEPT_ASSERT(( DFSVisitorConcept<DFSVisitor, IncidenceGraph> ));
typedef typename graph_traits<IncidenceGraph>::vertex_descriptor Vertex;
BOOST_CONCEPT_ASSERT(( ReadWritePropertyMapConcept<ColorMap, Vertex> ));
typedef typename property_traits<ColorMap>::value_type ColorValue;
BOOST_CONCEPT_ASSERT(( ColorValueConcept<ColorValue> ));
typedef color_traits<ColorValue> Color;
typedef typename graph_traits<IncidenceGraph>::out_edge_iterator Iter;
typedef std::pair<Vertex, std::pair<Iter, Iter> > VertexInfo;
Iter ei, ei_end;
std::vector<VertexInfo> stack;
// Possible optimization for vector
//stack.reserve(num_vertices(g));
typedef typename unwrap_reference<TerminatorFunc>::type TF;
put(color, u, Color::gray());
vis.discover_vertex(u, g);
boost::tie(ei, ei_end) = out_edges(u, g);
// Variable is needed to workaround a borland bug.
TF& fn = static_cast<TF&>(func);
if (fn(u, g)) {
// If this vertex terminates the search, we push empty range
stack.push_back(std::make_pair(u, std::make_pair(ei_end, ei_end)));
} else {
stack.push_back(std::make_pair(u, std::make_pair(ei, ei_end)));
}
while (!stack.empty()) {
VertexInfo& back = stack.back();
u = back.first;
boost::tie(ei, ei_end) = back.second;
stack.pop_back();
while (ei != ei_end) {
Vertex v = target(*ei, g);
vis.examine_edge(*ei, g);
ColorValue v_color = get(color, v);
if (v_color == Color::white()) {
vis.tree_edge(*ei, g);
stack.push_back(std::make_pair(u, std::make_pair(++ei, ei_end)));
u = v;
put(color, u, Color::gray());
vis.discover_vertex(u, g);
boost::tie(ei, ei_end) = out_edges(u, g);
if (fn(u, g)) {
ei = ei_end;
}
} else if (v_color == Color::gray()) {
vis.back_edge(*ei, g);
++ei;
} else {
vis.forward_or_cross_edge(*ei, g);
++ei;
}
}
put(color, u, Color::black());
vis.finish_vertex(u, g);
}
}
#else // BOOST_RECURSIVE_DFS is defined
template <class IncidenceGraph, class DFSVisitor, class ColorMap,
class TerminatorFunc>
void depth_first_visit_impl
(const IncidenceGraph& g,
typename graph_traits<IncidenceGraph>::vertex_descriptor u,
DFSVisitor& vis, // pass-by-reference here, important!
ColorMap color, TerminatorFunc func)
{
BOOST_CONCEPT_ASSERT(( IncidenceGraphConcept<IncidenceGraph> ));
BOOST_CONCEPT_ASSERT(( DFSVisitorConcept<DFSVisitor, IncidenceGraph> ));
typedef typename graph_traits<IncidenceGraph>::vertex_descriptor Vertex;
BOOST_CONCEPT_ASSERT(( ReadWritePropertyMapConcept<ColorMap, Vertex> ));
typedef typename property_traits<ColorMap>::value_type ColorValue;
BOOST_CONCEPT_ASSERT(( ColorValueConcept<ColorValue> ));
typedef color_traits<ColorValue> Color;
typename graph_traits<IncidenceGraph>::out_edge_iterator ei, ei_end;
put(color, u, Color::gray()); vis.discover_vertex(u, g);
typedef typename unwrap_reference<TerminatorFunc>::type TF;
// Variable is needed to workaround a borland bug.
TF& fn = static_cast<TF&>(func);
if (!fn(u, g))
for (boost::tie(ei, ei_end) = out_edges(u, g); ei != ei_end; ++ei) {
Vertex v = target(*ei, g); vis.examine_edge(*ei, g);
ColorValue v_color = get(color, v);
if (v_color == Color::white()) { vis.tree_edge(*ei, g);
depth_first_visit_impl(g, v, vis, color, func);
} else if (v_color == Color::gray()) vis.back_edge(*ei, g);
else vis.forward_or_cross_edge(*ei, g);
}
put(color, u, Color::black()); vis.finish_vertex(u, g);
}
#endif
} // namespace detail
template <class VertexListGraph, class DFSVisitor, class ColorMap>
void
depth_first_search(const VertexListGraph& g, DFSVisitor vis, ColorMap color,
typename graph_traits<VertexListGraph>::vertex_descriptor start_vertex)
{
typedef typename graph_traits<VertexListGraph>::vertex_descriptor Vertex;
BOOST_CONCEPT_ASSERT(( DFSVisitorConcept<DFSVisitor, VertexListGraph> ));
typedef typename property_traits<ColorMap>::value_type ColorValue;
typedef color_traits<ColorValue> Color;
typename graph_traits<VertexListGraph>::vertex_iterator ui, ui_end;
for (boost::tie(ui, ui_end) = vertices(g); ui != ui_end; ++ui) {
Vertex u = implicit_cast<Vertex>(*ui);
put(color, u, Color::white()); vis.initialize_vertex(u, g);
}
if (start_vertex != detail::get_default_starting_vertex(g)){ vis.start_vertex(start_vertex, g);
detail::depth_first_visit_impl(g, start_vertex, vis, color,
detail::nontruth2());
}
for (boost::tie(ui, ui_end) = vertices(g); ui != ui_end; ++ui) {
Vertex u = implicit_cast<Vertex>(*ui);
ColorValue u_color = get(color, u);
if (u_color == Color::white()) { vis.start_vertex(u, g);
detail::depth_first_visit_impl(g, u, vis, color, detail::nontruth2());
}
}
}
template <class VertexListGraph, class DFSVisitor, class ColorMap>
void
depth_first_search(const VertexListGraph& g, DFSVisitor vis, ColorMap color)
{
typedef typename boost::graph_traits<VertexListGraph>::vertex_iterator vi;
std::pair<vi, vi> verts = vertices(g);
if (verts.first == verts.second)
return;
depth_first_search(g, vis, color, detail::get_default_starting_vertex(g));
}
template <class Visitors = null_visitor>
class dfs_visitor {
public:
dfs_visitor() { }
dfs_visitor(Visitors vis) : m_vis(vis) { }
template <class Vertex, class Graph>
void initialize_vertex(Vertex u, const Graph& g) {
invoke_visitors(m_vis, u, g, ::boost::on_initialize_vertex());
}
template <class Vertex, class Graph>
void start_vertex(Vertex u, const Graph& g) {
invoke_visitors(m_vis, u, g, ::boost::on_start_vertex());
}
template <class Vertex, class Graph>
void discover_vertex(Vertex u, const Graph& g) {
invoke_visitors(m_vis, u, g, ::boost::on_discover_vertex());
}
template <class Edge, class Graph>
void examine_edge(Edge u, const Graph& g) {
invoke_visitors(m_vis, u, g, ::boost::on_examine_edge());
}
template <class Edge, class Graph>
void tree_edge(Edge u, const Graph& g) {
invoke_visitors(m_vis, u, g, ::boost::on_tree_edge());
}
template <class Edge, class Graph>
void back_edge(Edge u, const Graph& g) {
invoke_visitors(m_vis, u, g, ::boost::on_back_edge());
}
template <class Edge, class Graph>
void forward_or_cross_edge(Edge u, const Graph& g) {
invoke_visitors(m_vis, u, g, ::boost::on_forward_or_cross_edge());
}
template <class Vertex, class Graph>
void finish_vertex(Vertex u, const Graph& g) {
invoke_visitors(m_vis, u, g, ::boost::on_finish_vertex());
}
BOOST_GRAPH_EVENT_STUB(on_initialize_vertex,dfs)
BOOST_GRAPH_EVENT_STUB(on_start_vertex,dfs)
BOOST_GRAPH_EVENT_STUB(on_discover_vertex,dfs)
BOOST_GRAPH_EVENT_STUB(on_examine_edge,dfs)
BOOST_GRAPH_EVENT_STUB(on_tree_edge,dfs)
BOOST_GRAPH_EVENT_STUB(on_back_edge,dfs)
BOOST_GRAPH_EVENT_STUB(on_forward_or_cross_edge,dfs)
BOOST_GRAPH_EVENT_STUB(on_finish_vertex,dfs)
protected:
Visitors m_vis;
};
template <class Visitors>
dfs_visitor<Visitors>
make_dfs_visitor(Visitors vis) {
return dfs_visitor<Visitors>(vis);
}
typedef dfs_visitor<> default_dfs_visitor;
// Boost.Parameter named parameter variant
namespace graph {
namespace detail {
template <typename Graph>
struct depth_first_search_impl {
typedef void result_type;
template <typename ArgPack>
void operator()(const Graph& g, const ArgPack& arg_pack) const {
using namespace boost::graph::keywords;
boost::depth_first_search(g,
arg_pack[_visitor | make_dfs_visitor(null_visitor())],
boost::detail::make_color_map_from_arg_pack(g, arg_pack),
arg_pack[_root_vertex || boost::detail::get_default_starting_vertex_t<Graph>(g)]);
}
};
}
BOOST_GRAPH_MAKE_FORWARDING_FUNCTION(depth_first_search, 1, 4)
}
BOOST_GRAPH_MAKE_OLD_STYLE_PARAMETER_FUNCTION(depth_first_search, 1)
template <class IncidenceGraph, class DFSVisitor, class ColorMap>
void depth_first_visit
(const IncidenceGraph& g,
typename graph_traits<IncidenceGraph>::vertex_descriptor u,
DFSVisitor vis, ColorMap color)
{
vis.start_vertex(u, g);
detail::depth_first_visit_impl(g, u, vis, color, detail::nontruth2());
}
template <class IncidenceGraph, class DFSVisitor, class ColorMap,
class TerminatorFunc>
void depth_first_visit
(const IncidenceGraph& g,
typename graph_traits<IncidenceGraph>::vertex_descriptor u,
DFSVisitor vis, ColorMap color, TerminatorFunc func = TerminatorFunc())
{
vis.start_vertex(u, g);
detail::depth_first_visit_impl(g, u, vis, color, func);
}
} // namespace boost
#ifdef BOOST_GRAPH_USE_MPI
# include <boost/graph/distributed/depth_first_search.hpp>
#endif
#endif
@@ -0,0 +1,117 @@
//
//=======================================================================
// 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_GRAPH_DETAIL_ADJ_LIST_EDGE_ITERATOR_HPP
#define BOOST_GRAPH_DETAIL_ADJ_LIST_EDGE_ITERATOR_HPP
#include <iterator>
#include <utility>
#include <boost/detail/workaround.hpp>
#if BOOST_WORKAROUND( __IBMCPP__, <= 600 )
# define BOOST_GRAPH_NO_OPTIONAL
#endif
#ifdef BOOST_GRAPH_NO_OPTIONAL
# define BOOST_GRAPH_MEMBER .
#else
# define BOOST_GRAPH_MEMBER ->
# include <boost/optional.hpp>
#endif // ndef BOOST_GRAPH_NO_OPTIONAL
namespace boost {
namespace detail {
template <class VertexIterator, class OutEdgeIterator, class Graph>
class adj_list_edge_iterator {
typedef adj_list_edge_iterator self;
public:
typedef std::forward_iterator_tag iterator_category;
typedef typename OutEdgeIterator::value_type value_type;
typedef typename OutEdgeIterator::reference reference;
typedef typename OutEdgeIterator::pointer pointer;
typedef typename OutEdgeIterator::difference_type difference_type;
typedef difference_type distance_type;
inline adj_list_edge_iterator() {}
inline adj_list_edge_iterator(const self& x)
: vBegin(x.vBegin), vCurr(x.vCurr), vEnd(x.vEnd),
edges(x.edges), m_g(x.m_g) { }
template <class G>
inline adj_list_edge_iterator(VertexIterator b,
VertexIterator c,
VertexIterator e,
const G& g)
: vBegin(b), vCurr(c), vEnd(e), m_g(&g) {
if ( vCurr != vEnd ) {
while ( vCurr != vEnd && out_degree(*vCurr, *m_g) == 0 )
++vCurr;
if ( vCurr != vEnd )
edges = out_edges(*vCurr, *m_g);
}
}
/*Note:
In the directed graph cases, it is fine.
For undirected graphs, one edge go through twice.
*/
inline self& operator++() {
++edges BOOST_GRAPH_MEMBER first;
if (edges BOOST_GRAPH_MEMBER first == edges BOOST_GRAPH_MEMBER second)
{
++vCurr;
while ( vCurr != vEnd && out_degree(*vCurr, *m_g) == 0 )
++vCurr;
if ( vCurr != vEnd )
edges = out_edges(*vCurr, *m_g);
}
return *this;
}
inline self operator++(int) {
self tmp = *this;
++(*this);
return tmp;
}
inline value_type operator*() const
{ return *edges BOOST_GRAPH_MEMBER first; }
inline bool operator==(const self& x) const {
return vCurr == x.vCurr
&& (vCurr == vEnd
|| edges BOOST_GRAPH_MEMBER first == x.edges BOOST_GRAPH_MEMBER first);
}
inline bool operator!=(const self& x) const {
return vCurr != x.vCurr
|| (vCurr != vEnd
&& edges BOOST_GRAPH_MEMBER first != x.edges BOOST_GRAPH_MEMBER first);
}
protected:
VertexIterator vBegin;
VertexIterator vCurr;
VertexIterator vEnd;
#ifdef BOOST_GRAPH_NO_OPTIONAL
std::pair<OutEdgeIterator, OutEdgeIterator> edges;
#else
boost::optional<std::pair<OutEdgeIterator, OutEdgeIterator> >
edges;
#endif // ndef BOOST_GRAPH_NO_OPTIONAL
const Graph* m_g;
};
} // namespace detail
}
#undef BOOST_GRAPH_MEMBER
#endif // BOOST_GRAPH_DETAIL_ADJ_LIST_EDGE_ITERATOR_HPP
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,181 @@
//
//=======================================================================
// 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_ARRAY_BINARY_TREE_HPP
#define BOOST_ARRAY_BINARY_TREE_HPP
#include <iterator>
#include <functional>
#include <boost/config.hpp>
namespace boost {
/*
* Note: array_binary_tree is a completey balanced binary tree.
*/
#if !defined BOOST_NO_STD_ITERATOR_TRAITS
template <class RandomAccessIterator, class ID>
#else
template <class RandomAccessIterator, class ValueType, class ID>
#endif
class array_binary_tree_node {
public:
typedef array_binary_tree_node ArrayBinaryTreeNode;
typedef RandomAccessIterator rep_iterator;
#if !defined BOOST_NO_STD_ITERATOR_TRAITS
typedef typename std::iterator_traits<RandomAccessIterator>::difference_type
difference_type;
typedef typename std::iterator_traits<RandomAccessIterator>::value_type
value_type;
#else
typedef int difference_type;
typedef ValueType value_type;
#endif
typedef difference_type size_type;
struct children_type {
struct iterator
: boost::iterator<std::bidirectional_iterator_tag, ArrayBinaryTreeNode,
difference_type, array_binary_tree_node*, ArrayBinaryTreeNode&>
{ // replace with iterator_adaptor implementation -JGS
inline iterator() : i(0), n(0) { }
inline iterator(const iterator& x) : r(x.r), i(x.i), n(x.n), id(x.id) { }
inline iterator& operator=(const iterator& x) {
r = x.r; i = x.i; n = x.n;
/*egcs generate a warning*/
id = x.id;
return *this;
}
inline iterator(rep_iterator rr,
size_type ii,
size_type nn,
const ID& _id) : r(rr), i(ii), n(nn), id(_id) { }
inline array_binary_tree_node operator*() {
return ArrayBinaryTreeNode(r, i, n, id); }
inline iterator& operator++() { ++i; return *this; }
inline iterator operator++(int)
{ iterator t = *this; ++(*this); return t; }
inline bool operator==(const iterator& x) const { return i == x.i; }
inline bool operator!=(const iterator& x) const
{ return !(*this == x); }
rep_iterator r;
size_type i;
size_type n;
ID id;
};
inline children_type() : i(0), n(0) { }
inline children_type(const children_type& x)
: r(x.r), i(x.i), n(x.n), id(x.id) { }
inline children_type& operator=(const children_type& x) {
r = x.r; i = x.i; n = x.n;
/*egcs generate a warning*/
id = x.id;
return *this;
}
inline children_type(rep_iterator rr,
size_type ii,
size_type nn,
const ID& _id) : r(rr), i(ii), n(nn), id(_id) { }
inline iterator begin() { return iterator(r, 2 * i + 1, n, id); }
inline iterator end() { return iterator(r, 2 * i + 1 + size(), n, id); }
inline size_type size() const {
size_type c = 2 * i + 1;
size_type s;
if (c + 1 < n) s = 2;
else if (c < n) s = 1;
else s = 0;
return s;
}
rep_iterator r;
size_type i;
size_type n;
ID id;
};
inline array_binary_tree_node() : i(0), n(0) { }
inline array_binary_tree_node(const array_binary_tree_node& x)
: r(x.r), i(x.i), n(x.n), id(x.id) { }
inline ArrayBinaryTreeNode& operator=(const ArrayBinaryTreeNode& x) {
r = x.r;
i = x.i;
n = x.n;
/*egcs generate a warning*/
id = x.id;
return *this;
}
inline array_binary_tree_node(rep_iterator start,
rep_iterator end,
rep_iterator pos, const ID& _id)
: r(start), i(pos - start), n(end - start), id(_id) { }
inline array_binary_tree_node(rep_iterator rr,
size_type ii,
size_type nn, const ID& _id)
: r(rr), i(ii), n(nn), id(_id) { }
inline value_type& value() { return *(r + i); }
inline const value_type& value() const { return *(r + i); }
inline ArrayBinaryTreeNode parent() const {
return ArrayBinaryTreeNode(r, (i - 1) / 2, n, id);
}
inline bool has_parent() const { return i != 0; }
inline children_type children() { return children_type(r, i, n, id); }
/*
inline void swap(array_binary_tree_node x) {
value_type tmp = x.value();
x.value() = value();
value() = tmp;
i = x.i;
}
*/
template <class ExternalData>
inline void swap(ArrayBinaryTreeNode x, ExternalData& edata ) {
using boost::get;
value_type tmp = x.value();
/*swap external data*/
edata[ get(id, tmp) ] = i;
edata[ get(id, value()) ] = x.i;
x.value() = value();
value() = tmp;
i = x.i;
}
inline const children_type children() const {
return children_type(r, i, n);
}
inline size_type index() const { return i; }
rep_iterator r;
size_type i;
size_type n;
ID id;
};
template <class RandomAccessContainer,
class Compare = std::less<typename RandomAccessContainer::value_type> >
struct compare_array_node {
typedef typename RandomAccessContainer::value_type value_type;
compare_array_node(const Compare& x) : comp(x) {}
compare_array_node(const compare_array_node& x) : comp(x.comp) {}
template< class node_type >
inline bool operator()(const node_type& x, const node_type& y) {
return comp(x.value(), y.value());
}
template< class node_type >
inline bool operator()(const node_type& x, const node_type& y) const {
return comp(x.value(), y.value());
}
Compare comp;
};
} // namespace boost
#endif /* BOOST_ARRAY_BINARY_TREE_HPP */
@@ -0,0 +1,651 @@
// Copyright 2005-2009 The Trustees of Indiana University.
// 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)
// Authors: Jeremiah Willcock
// Douglas Gregor
// Andrew Lumsdaine
// Compressed sparse row graph type internal structure
#ifndef BOOST_GRAPH_COMPRESSED_SPARSE_ROW_STRUCT_HPP
#define BOOST_GRAPH_COMPRESSED_SPARSE_ROW_STRUCT_HPP
#ifndef BOOST_GRAPH_COMPRESSED_SPARSE_ROW_GRAPH_HPP
#error This file should only be included from boost/graph/compressed_sparse_row_graph.hpp
#endif
#include <vector>
#include <utility>
#include <algorithm>
#include <climits>
#include <boost/assert.hpp>
#include <iterator>
#if 0
#include <iostream> // For some debugging code below
#endif
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/properties.hpp>
#include <boost/graph/filtered_graph.hpp> // For keep_all
#include <boost/graph/detail/indexed_properties.hpp>
#include <boost/graph/detail/histogram_sort.hpp>
#include <boost/graph/iteration_macros.hpp>
#include <boost/iterator/counting_iterator.hpp>
#include <boost/iterator/reverse_iterator.hpp>
#include <boost/iterator/zip_iterator.hpp>
#include <boost/iterator/transform_iterator.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/integer.hpp>
#include <boost/iterator/iterator_facade.hpp>
#include <boost/mpl/if.hpp>
#include <boost/graph/graph_selectors.hpp>
#include <boost/static_assert.hpp>
#include <boost/functional/hash.hpp>
namespace boost {
namespace detail {
// Forward declaration of CSR edge descriptor type, needed to pass to
// indexed_edge_properties.
template<typename Vertex, typename EdgeIndex>
class csr_edge_descriptor;
// Add edge_index property map
template<typename Vertex, typename EdgeIndex>
struct csr_edge_index_map
{
typedef EdgeIndex value_type;
typedef EdgeIndex reference;
typedef csr_edge_descriptor<Vertex, EdgeIndex> key_type;
typedef readable_property_map_tag category;
};
template<typename Vertex, typename EdgeIndex>
inline EdgeIndex
get(const csr_edge_index_map<Vertex, EdgeIndex>&,
const csr_edge_descriptor<Vertex, EdgeIndex>& key)
{
return key.idx;
}
/** Compressed sparse row graph internal structure.
*
* Vertex and EdgeIndex should be unsigned integral types and should
* specialize numeric_limits.
*/
template <typename EdgeProperty,
typename Vertex = std::size_t, typename EdgeIndex = Vertex>
class compressed_sparse_row_structure :
public detail::indexed_edge_properties<
compressed_sparse_row_structure<EdgeProperty, Vertex, EdgeIndex>,
EdgeProperty,
csr_edge_descriptor<Vertex, EdgeIndex>,
csr_edge_index_map<Vertex, EdgeIndex> > {
public:
typedef detail::indexed_edge_properties<
compressed_sparse_row_structure<EdgeProperty, Vertex, EdgeIndex>,
EdgeProperty,
csr_edge_descriptor<Vertex, EdgeIndex>,
csr_edge_index_map<Vertex, EdgeIndex> >
inherited_edge_properties;
typedef Vertex vertices_size_type;
typedef Vertex vertex_descriptor;
typedef EdgeIndex edges_size_type;
static vertex_descriptor null_vertex() { return vertex_descriptor(-1); }
std::vector<EdgeIndex> m_rowstart;
std::vector<Vertex> m_column;
compressed_sparse_row_structure(Vertex numverts = 0)
: m_rowstart(numverts + 1, EdgeIndex(0)), m_column()
{}
// Rebuild graph from number of vertices and multi-pass unsorted list of
// edges (filtered using source_pred and mapped using global_to_local)
template <typename MultiPassInputIterator, typename GlobalToLocal, typename SourcePred>
void
assign_unsorted_multi_pass_edges(MultiPassInputIterator edge_begin,
MultiPassInputIterator edge_end,
vertices_size_type numlocalverts,
const GlobalToLocal& global_to_local,
const SourcePred& source_pred) {
m_rowstart.clear();
m_rowstart.resize(numlocalverts + 1, 0);
typedef std::pair<vertices_size_type, vertices_size_type> edge_type;
typedef boost::transform_iterator<boost::graph::detail::project1st<edge_type>, MultiPassInputIterator> source_iterator;
typedef boost::transform_iterator<boost::graph::detail::project2nd<edge_type>, MultiPassInputIterator> target_iterator;
source_iterator sources_begin(edge_begin, boost::graph::detail::project1st<edge_type>());
source_iterator sources_end(edge_end, boost::graph::detail::project1st<edge_type>());
target_iterator targets_begin(edge_begin, boost::graph::detail::project2nd<edge_type>());
target_iterator targets_end(edge_end, boost::graph::detail::project2nd<edge_type>());
boost::graph::detail::count_starts
(sources_begin, sources_end, m_rowstart.begin(), numlocalverts,
source_pred, boost::make_property_map_function(global_to_local));
m_column.resize(m_rowstart.back());
inherited_edge_properties::resize(m_rowstart.back());
boost::graph::detail::histogram_sort
(sources_begin, sources_end, m_rowstart.begin(), numlocalverts,
targets_begin, m_column.begin(),
source_pred, boost::make_property_map_function(global_to_local));
}
// Rebuild graph from number of vertices and multi-pass unsorted list of
// edges and their properties (filtered using source_pred and mapped using
// global_to_local)
template <typename MultiPassInputIterator, typename EdgePropertyIterator, typename GlobalToLocal, typename SourcePred>
void
assign_unsorted_multi_pass_edges(MultiPassInputIterator edge_begin,
MultiPassInputIterator edge_end,
EdgePropertyIterator ep_iter,
vertices_size_type numlocalverts,
const GlobalToLocal& global_to_local,
const SourcePred& source_pred) {
m_rowstart.clear();
m_rowstart.resize(numlocalverts + 1, 0);
typedef std::pair<vertices_size_type, vertices_size_type> edge_type;
typedef boost::transform_iterator<boost::graph::detail::project1st<edge_type>, MultiPassInputIterator> source_iterator;
typedef boost::transform_iterator<boost::graph::detail::project2nd<edge_type>, MultiPassInputIterator> target_iterator;
source_iterator sources_begin(edge_begin, boost::graph::detail::project1st<edge_type>());
source_iterator sources_end(edge_end, boost::graph::detail::project1st<edge_type>());
target_iterator targets_begin(edge_begin, boost::graph::detail::project2nd<edge_type>());
target_iterator targets_end(edge_end, boost::graph::detail::project2nd<edge_type>());
boost::graph::detail::count_starts
(sources_begin, sources_end, m_rowstart.begin(), numlocalverts,
source_pred, boost::make_property_map_function(global_to_local));
m_column.resize(m_rowstart.back());
inherited_edge_properties::resize(m_rowstart.back());
boost::graph::detail::histogram_sort
(sources_begin, sources_end, m_rowstart.begin(), numlocalverts,
targets_begin, m_column.begin(),
ep_iter, inherited_edge_properties::begin(),
source_pred, boost::make_property_map_function(global_to_local));
}
// Assign from number of vertices and sorted list of edges
template<typename InputIterator, typename GlobalToLocal, typename SourcePred>
void assign_from_sorted_edges(
InputIterator edge_begin, InputIterator edge_end,
const GlobalToLocal& global_to_local,
const SourcePred& source_pred,
vertices_size_type numlocalverts,
edges_size_type numedges_or_zero) {
m_column.clear();
m_column.reserve(numedges_or_zero);
m_rowstart.resize(numlocalverts + 1);
EdgeIndex current_edge = 0;
Vertex current_vertex_plus_one = 1;
m_rowstart[0] = 0;
for (InputIterator ei = edge_begin; ei != edge_end; ++ei) {
if (!source_pred(ei->first)) continue;
Vertex src = get(global_to_local, ei->first);
Vertex tgt = ei->second;
for (; current_vertex_plus_one != src + 1; ++current_vertex_plus_one)
m_rowstart[current_vertex_plus_one] = current_edge;
m_column.push_back(tgt);
++current_edge;
}
// The remaining vertices have no edges
for (; current_vertex_plus_one != numlocalverts + 1; ++current_vertex_plus_one)
m_rowstart[current_vertex_plus_one] = current_edge;
// Default-construct properties for edges
inherited_edge_properties::resize(m_column.size());
}
// Assign from number of vertices and sorted list of edges
template<typename InputIterator, typename EdgePropertyIterator, typename GlobalToLocal, typename SourcePred>
void assign_from_sorted_edges(
InputIterator edge_begin, InputIterator edge_end,
EdgePropertyIterator ep_iter,
const GlobalToLocal& global_to_local,
const SourcePred& source_pred,
vertices_size_type numlocalverts,
edges_size_type numedges_or_zero) {
// Reserving storage in advance can save us lots of time and
// memory, but it can only be done if we have forward iterators or
// the user has supplied the number of edges.
edges_size_type numedges = numedges_or_zero;
if (numedges == 0) {
typedef typename std::iterator_traits<InputIterator>::iterator_category
category;
numedges = boost::graph::detail::reserve_count_for_single_pass(edge_begin, edge_end);
}
m_column.clear();
m_column.reserve(numedges_or_zero);
inherited_edge_properties::clear();
inherited_edge_properties::reserve(numedges_or_zero);
m_rowstart.resize(numlocalverts + 1);
EdgeIndex current_edge = 0;
Vertex current_vertex_plus_one = 1;
m_rowstart[0] = 0;
for (InputIterator ei = edge_begin; ei != edge_end; ++ei, ++ep_iter) {
if (!source_pred(ei->first)) continue;
Vertex src = get(global_to_local, ei->first);
Vertex tgt = ei->second;
for (; current_vertex_plus_one != src + 1; ++current_vertex_plus_one)
m_rowstart[current_vertex_plus_one] = current_edge;
m_column.push_back(tgt);
inherited_edge_properties::push_back(*ep_iter);
++current_edge;
}
// The remaining vertices have no edges
for (; current_vertex_plus_one != numlocalverts + 1; ++current_vertex_plus_one)
m_rowstart[current_vertex_plus_one] = current_edge;
}
// Replace graph with sources and targets given, sorting them in-place, and
// using the given global-to-local property map to get local indices from
// global ones in the two arrays.
template <typename GlobalToLocal>
void assign_sources_and_targets_global(std::vector<vertex_descriptor>& sources,
std::vector<vertex_descriptor>& targets,
vertices_size_type numverts,
GlobalToLocal global_to_local) {
BOOST_ASSERT (sources.size() == targets.size());
// Do an in-place histogram sort (at least that's what I think it is) to
// sort sources and targets
m_rowstart.clear();
m_rowstart.resize(numverts + 1);
boost::graph::detail::count_starts
(sources.begin(), sources.end(), m_rowstart.begin(), numverts,
keep_all(), boost::make_property_map_function(global_to_local));
boost::graph::detail::histogram_sort_inplace
(sources.begin(), m_rowstart.begin(), numverts,
targets.begin(), boost::make_property_map_function(global_to_local));
// Now targets is the correct vector (properly sorted by source) for
// m_column
m_column.swap(targets);
inherited_edge_properties::resize(m_rowstart.back());
}
// Replace graph with sources and targets and edge properties given, sorting
// them in-place, and using the given global-to-local property map to get
// local indices from global ones in the two arrays.
template <typename GlobalToLocal>
void assign_sources_and_targets_global(std::vector<vertex_descriptor>& sources,
std::vector<vertex_descriptor>& targets,
std::vector<typename inherited_edge_properties::edge_bundled>& edge_props,
vertices_size_type numverts,
GlobalToLocal global_to_local) {
BOOST_ASSERT (sources.size() == targets.size());
BOOST_ASSERT (sources.size() == edge_props.size());
// Do an in-place histogram sort (at least that's what I think it is) to
// sort sources and targets
m_rowstart.clear();
m_rowstart.resize(numverts + 1);
boost::graph::detail::count_starts
(sources.begin(), sources.end(), m_rowstart.begin(), numverts,
keep_all(), boost::make_property_map_function(global_to_local));
boost::graph::detail::histogram_sort_inplace
(sources.begin(), m_rowstart.begin(), numverts,
targets.begin(), edge_props.begin(),
boost::make_property_map_function(global_to_local));
// Now targets is the correct vector (properly sorted by source) for
// m_column, and edge_props for m_edge_properties
m_column.swap(targets);
this->m_edge_properties.swap(edge_props);
}
// From any graph (slow and uses a lot of memory)
// Requires IncidenceGraph and a vertex index map
// Internal helper function
// Note that numedges must be doubled for undirected source graphs
template<typename Graph, typename VertexIndexMap>
void
assign(const Graph& g, const VertexIndexMap& vi,
vertices_size_type numverts, edges_size_type numedges)
{
m_rowstart.resize(numverts + 1);
m_column.resize(numedges);
inherited_edge_properties::resize(numedges);
EdgeIndex current_edge = 0;
typedef typename boost::graph_traits<Graph>::vertex_descriptor g_vertex;
typedef typename boost::graph_traits<Graph>::edge_descriptor g_edge;
typedef typename boost::graph_traits<Graph>::out_edge_iterator
g_out_edge_iter;
std::vector<g_vertex> ordered_verts_of_g(numverts);
BGL_FORALL_VERTICES_T(v, g, Graph) {
ordered_verts_of_g[get(vertex_index, g, v)] = v;
}
for (Vertex i = 0; i != numverts; ++i) {
m_rowstart[i] = current_edge;
g_vertex v = ordered_verts_of_g[i];
g_out_edge_iter ei, ei_end;
for (boost::tie(ei, ei_end) = out_edges(v, g); ei != ei_end; ++ei) {
m_column[current_edge++] = get(vi, target(*ei, g));
}
}
m_rowstart[numverts] = current_edge;
}
// Add edges from a sorted (smallest sources first) range of pairs and edge
// properties
template <typename BidirectionalIteratorOrig, typename EPIterOrig,
typename GlobalToLocal>
void
add_edges_sorted_internal(
BidirectionalIteratorOrig first_sorted,
BidirectionalIteratorOrig last_sorted,
EPIterOrig ep_iter_sorted,
const GlobalToLocal& global_to_local) {
typedef boost::reverse_iterator<BidirectionalIteratorOrig> BidirectionalIterator;
typedef boost::reverse_iterator<EPIterOrig> EPIter;
// Flip sequence
BidirectionalIterator first(last_sorted);
BidirectionalIterator last(first_sorted);
typedef Vertex vertex_t;
typedef Vertex vertex_num;
typedef EdgeIndex edge_num;
edge_num new_edge_count = std::distance(first, last);
EPIter ep_iter(ep_iter_sorted);
std::advance(ep_iter, -(std::ptrdiff_t)new_edge_count);
edge_num edges_added_before_i = new_edge_count; // Count increment to add to rowstarts
m_column.resize(m_column.size() + new_edge_count);
inherited_edge_properties::resize(inherited_edge_properties::size() + new_edge_count);
BidirectionalIterator current_new_edge = first, prev_new_edge = first;
EPIter current_new_edge_prop = ep_iter;
for (vertex_num i_plus_1 = m_rowstart.size() - 1; i_plus_1 > 0; --i_plus_1) {
vertex_num i = i_plus_1 - 1;
prev_new_edge = current_new_edge;
// edges_added_to_this_vertex = #mbrs of new_edges with first == i
edge_num edges_added_to_this_vertex = 0;
while (current_new_edge != last) {
if (get(global_to_local, current_new_edge->first) != i) break;
++current_new_edge;
++current_new_edge_prop;
++edges_added_to_this_vertex;
}
edges_added_before_i -= edges_added_to_this_vertex;
// Invariant: edges_added_before_i = #mbrs of new_edges with first < i
edge_num old_rowstart = m_rowstart[i];
edge_num new_rowstart = m_rowstart[i] + edges_added_before_i;
edge_num old_degree = m_rowstart[i + 1] - m_rowstart[i];
edge_num new_degree = old_degree + edges_added_to_this_vertex;
// Move old edges forward (by #new_edges before this i) to make room
// new_rowstart > old_rowstart, so use copy_backwards
if (old_rowstart != new_rowstart) {
std::copy_backward(m_column.begin() + old_rowstart,
m_column.begin() + old_rowstart + old_degree,
m_column.begin() + new_rowstart + old_degree);
inherited_edge_properties::move_range(old_rowstart, old_rowstart + old_degree, new_rowstart);
}
// Add new edges (reversed because current_new_edge is a
// const_reverse_iterator)
BidirectionalIterator temp = current_new_edge;
EPIter temp_prop = current_new_edge_prop;
for (; temp != prev_new_edge; ++old_degree) {
--temp;
--temp_prop;
m_column[new_rowstart + old_degree] = temp->second;
inherited_edge_properties::write_by_index(new_rowstart + old_degree, *temp_prop);
}
m_rowstart[i + 1] = new_rowstart + new_degree;
if (edges_added_before_i == 0) break; // No more edges inserted before this point
// m_rowstart[i] will be fixed up on the next iteration (to avoid
// changing the degree of vertex i - 1); the last iteration never changes
// it (either because of the condition of the break or because
// m_rowstart[0] is always 0)
}
}
};
template<typename Vertex, typename EdgeIndex>
class csr_edge_descriptor
{
public:
Vertex src;
EdgeIndex idx;
csr_edge_descriptor(Vertex src, EdgeIndex idx): src(src), idx(idx) {}
csr_edge_descriptor(): src(0), idx(0) {}
bool operator==(const csr_edge_descriptor& e) const {return idx == e.idx;}
bool operator!=(const csr_edge_descriptor& e) const {return idx != e.idx;}
bool operator<(const csr_edge_descriptor& e) const {return idx < e.idx;}
bool operator>(const csr_edge_descriptor& e) const {return idx > e.idx;}
bool operator<=(const csr_edge_descriptor& e) const {return idx <= e.idx;}
bool operator>=(const csr_edge_descriptor& e) const {return idx >= e.idx;}
template<typename Archiver>
void serialize(Archiver& ar, const unsigned int /*version*/)
{
ar & src & idx;
}
};
// Common out edge and edge iterators
template<typename CSRGraph>
class csr_out_edge_iterator
: public iterator_facade<csr_out_edge_iterator<CSRGraph>,
typename CSRGraph::edge_descriptor,
std::random_access_iterator_tag,
const typename CSRGraph::edge_descriptor&,
typename int_t<CHAR_BIT * sizeof(typename CSRGraph::edges_size_type)>::fast>
{
public:
typedef typename CSRGraph::edges_size_type EdgeIndex;
typedef typename CSRGraph::edge_descriptor edge_descriptor;
typedef typename int_t<CHAR_BIT * sizeof(EdgeIndex)>::fast difference_type;
csr_out_edge_iterator() {}
// Implicit copy constructor OK
explicit csr_out_edge_iterator(edge_descriptor edge) : m_edge(edge) { }
public: // GCC 4.2.1 doesn't like the private-and-friend thing
// iterator_facade requirements
const edge_descriptor& dereference() const { return m_edge; }
bool equal(const csr_out_edge_iterator& other) const
{ return m_edge == other.m_edge; }
void increment() { ++m_edge.idx; }
void decrement() { --m_edge.idx; }
void advance(difference_type n) { m_edge.idx += n; }
difference_type distance_to(const csr_out_edge_iterator& other) const
{ return other.m_edge.idx - m_edge.idx; }
edge_descriptor m_edge;
friend class iterator_core_access;
};
template<typename CSRGraph>
class csr_edge_iterator
: public iterator_facade<csr_edge_iterator<CSRGraph>,
typename CSRGraph::edge_descriptor,
boost::forward_traversal_tag,
typename CSRGraph::edge_descriptor>
{
private:
typedef typename CSRGraph::edge_descriptor edge_descriptor;
typedef typename CSRGraph::edges_size_type EdgeIndex;
public:
csr_edge_iterator() : rowstart_array(0), current_edge(), end_of_this_vertex(0), total_num_edges(0) {}
csr_edge_iterator(const CSRGraph& graph,
edge_descriptor current_edge,
EdgeIndex end_of_this_vertex)
: rowstart_array(&graph.m_forward.m_rowstart[0]),
current_edge(current_edge),
end_of_this_vertex(end_of_this_vertex),
total_num_edges(num_edges(graph)) {}
public: // See above
friend class boost::iterator_core_access;
edge_descriptor dereference() const {return current_edge;}
bool equal(const csr_edge_iterator& o) const {
return current_edge == o.current_edge;
}
void increment() {
++current_edge.idx;
if (current_edge.idx == total_num_edges) return;
while (current_edge.idx == end_of_this_vertex) {
++current_edge.src;
end_of_this_vertex = rowstart_array[current_edge.src + 1];
}
}
const EdgeIndex* rowstart_array;
edge_descriptor current_edge;
EdgeIndex end_of_this_vertex;
EdgeIndex total_num_edges;
};
// Only for bidirectional graphs
template<typename CSRGraph>
class csr_in_edge_iterator
: public iterator_facade<csr_in_edge_iterator<CSRGraph>,
typename CSRGraph::edge_descriptor,
boost::forward_traversal_tag,
typename CSRGraph::edge_descriptor>
{
public:
typedef typename CSRGraph::edges_size_type EdgeIndex;
typedef typename CSRGraph::edge_descriptor edge_descriptor;
csr_in_edge_iterator(): m_graph(0) {}
// Implicit copy constructor OK
csr_in_edge_iterator(const CSRGraph& graph,
EdgeIndex index_in_backward_graph)
: m_index_in_backward_graph(index_in_backward_graph), m_graph(&graph) {}
public: // See above
// iterator_facade requirements
edge_descriptor dereference() const {
return edge_descriptor(
m_graph->m_backward.m_column[m_index_in_backward_graph],
m_graph->m_backward.m_edge_properties[m_index_in_backward_graph]);
}
bool equal(const csr_in_edge_iterator& other) const
{ return m_index_in_backward_graph == other.m_index_in_backward_graph; }
void increment() { ++m_index_in_backward_graph; }
void decrement() { --m_index_in_backward_graph; }
void advance(std::ptrdiff_t n) { m_index_in_backward_graph += n; }
std::ptrdiff_t distance_to(const csr_in_edge_iterator& other) const
{ return other.m_index_in_backward_graph - m_index_in_backward_graph; }
EdgeIndex m_index_in_backward_graph;
const CSRGraph* m_graph;
friend class iterator_core_access;
};
template <typename A, typename B>
struct transpose_pair {
typedef std::pair<B, A> result_type;
result_type operator()(const std::pair<A, B>& p) const {
return result_type(p.second, p.first);
}
};
template <typename Iter>
struct transpose_iterator_gen {
typedef typename std::iterator_traits<Iter>::value_type vt;
typedef typename vt::first_type first_type;
typedef typename vt::second_type second_type;
typedef transpose_pair<first_type, second_type> transpose;
typedef boost::transform_iterator<transpose, Iter> type;
static type make(Iter it) {
return type(it, transpose());
}
};
template <typename Iter>
typename transpose_iterator_gen<Iter>::type transpose_edges(Iter i) {
return transpose_iterator_gen<Iter>::make(i);
}
template<typename GraphT, typename VertexIndexMap>
class edge_to_index_pair
{
typedef typename boost::graph_traits<GraphT>::vertices_size_type
vertices_size_type;
typedef typename boost::graph_traits<GraphT>::edge_descriptor edge_descriptor;
public:
typedef std::pair<vertices_size_type, vertices_size_type> result_type;
edge_to_index_pair() : g(0), index() { }
edge_to_index_pair(const GraphT& g, const VertexIndexMap& index)
: g(&g), index(index)
{ }
result_type operator()(edge_descriptor e) const
{
return result_type(get(index, source(e, *g)), get(index, target(e, *g)));
}
private:
const GraphT* g;
VertexIndexMap index;
};
template<typename GraphT, typename VertexIndexMap>
edge_to_index_pair<GraphT, VertexIndexMap>
make_edge_to_index_pair(const GraphT& g, const VertexIndexMap& index)
{
return edge_to_index_pair<GraphT, VertexIndexMap>(g, index);
}
template<typename GraphT>
edge_to_index_pair
<GraphT,
typename boost::property_map<GraphT,boost::vertex_index_t>::const_type>
make_edge_to_index_pair(const GraphT& g)
{
typedef typename boost::property_map<GraphT,
boost::vertex_index_t>::const_type
VertexIndexMap;
return edge_to_index_pair<GraphT, VertexIndexMap>(g,
get(boost::vertex_index,
g));
}
template<typename GraphT, typename VertexIndexMap, typename Iter>
boost::transform_iterator<edge_to_index_pair<GraphT, VertexIndexMap>, Iter>
make_edge_to_index_pair_iter(const GraphT& g, const VertexIndexMap& index,
Iter it) {
return boost::transform_iterator<edge_to_index_pair<GraphT, VertexIndexMap>, Iter>(it, edge_to_index_pair<GraphT, VertexIndexMap>(g, index));
}
} // namespace detail
template<typename Vertex, typename EdgeIndex>
struct hash<detail::csr_edge_descriptor<Vertex, EdgeIndex> >
{
std::size_t operator()
(detail::csr_edge_descriptor<Vertex, EdgeIndex> const& x) const
{
std::size_t hash = hash_value(x.src);
hash_combine(hash, x.idx);
return hash;
}
};
} // namespace boost
#endif // BOOST_GRAPH_COMPRESSED_SPARSE_ROW_STRUCT_HPP
@@ -0,0 +1,208 @@
//=======================================================================
// 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_GRAPH_DETAIL_CONNECTED_COMPONENTS_HPP
#define BOOST_GRAPH_DETAIL_CONNECTED_COMPONENTS_HPP
#if defined(__sgi) && !defined(__GNUC__)
#pragma set woff 1234
#endif
#include <boost/operators.hpp>
namespace boost {
namespace detail {
//=========================================================================
// Implementation details of connected_components
// This is used both in the connected_components algorithm and in
// the kosaraju strong components algorithm during the second DFS
// traversal.
template <class ComponentsPA, class DFSVisitor>
class components_recorder : public DFSVisitor
{
typedef typename property_traits<ComponentsPA>::value_type comp_type;
public:
components_recorder(ComponentsPA c,
comp_type& c_count,
DFSVisitor v)
: DFSVisitor(v), m_component(c), m_count(c_count) {}
template <class Vertex, class Graph>
void start_vertex(Vertex u, Graph& g) {
++m_count;
DFSVisitor::start_vertex(u, g);
}
template <class Vertex, class Graph>
void discover_vertex(Vertex u, Graph& g) {
put(m_component, u, m_count);
DFSVisitor::discover_vertex(u, g);
}
protected:
ComponentsPA m_component;
comp_type& m_count;
};
template <class DiscoverTimeMap, class FinishTimeMap, class TimeT,
class DFSVisitor>
class time_recorder : public DFSVisitor
{
public:
time_recorder(DiscoverTimeMap d, FinishTimeMap f, TimeT& t, DFSVisitor v)
: DFSVisitor(v), m_discover_time(d), m_finish_time(f), m_t(t) {}
template <class Vertex, class Graph>
void discover_vertex(Vertex u, Graph& g) {
put(m_discover_time, u, ++m_t);
DFSVisitor::discover_vertex(u, g);
}
template <class Vertex, class Graph>
void finish_vertex(Vertex u, Graph& g) {
put(m_finish_time, u, ++m_t);
DFSVisitor::discover_vertex(u, g);
}
protected:
DiscoverTimeMap m_discover_time;
FinishTimeMap m_finish_time;
TimeT m_t;
};
template <class DiscoverTimeMap, class FinishTimeMap, class TimeT,
class DFSVisitor>
time_recorder<DiscoverTimeMap, FinishTimeMap, TimeT, DFSVisitor>
record_times(DiscoverTimeMap d, FinishTimeMap f, TimeT& t, DFSVisitor vis)
{
return time_recorder<DiscoverTimeMap, FinishTimeMap, TimeT, DFSVisitor>
(d, f, t, vis);
}
//=========================================================================
// Implementation detail of dynamic_components
//-------------------------------------------------------------------------
// Helper functions for the component_index class
// Record the representative vertices in the header array.
// Representative vertices now point to the component number.
template <class Parent, class OutputIterator, class Integer>
inline void
build_components_header(Parent p,
OutputIterator header,
Integer num_nodes)
{
Parent component = p;
Integer component_num = 0;
for (Integer v = 0; v != num_nodes; ++v)
if (p[v] == v) {
*header++ = v;
component[v] = component_num++;
}
}
// Pushes x onto the front of the list. The list is represented in
// an array.
template <class Next, class T, class V>
inline void push_front(Next next, T& head, V x)
{
T tmp = head;
head = x;
next[x] = tmp;
}
// Create a linked list of the vertices in each component
// by reusing the representative array.
template <class Parent1, class Parent2,
class Integer>
void
link_components(Parent1 component, Parent2 header,
Integer num_nodes, Integer num_components)
{
// Make the non-representative vertices point to their component
Parent1 representative = component;
for (Integer v = 0; v != num_nodes; ++v)
if (component[v] >= num_components || header[component[v]] != v)
component[v] = component[representative[v]];
// initialize the "head" of the lists to "NULL"
std::fill_n(header, num_components, num_nodes);
// Add each vertex to the linked list for its component
Parent1 next = component;
for (Integer k = 0; k != num_nodes; ++k)
push_front(next, header[component[k]], k);
}
template <class IndexContainer, class HeaderContainer>
void
construct_component_index(IndexContainer& index, HeaderContainer& header)
{
build_components_header(index.begin(),
std::back_inserter(header),
index.end() - index.begin());
link_components(index.begin(), header.begin(),
index.end() - index.begin(),
header.end() - header.begin());
}
template <class IndexIterator, class Integer, class Distance>
class component_iterator
: boost::forward_iterator_helper<
component_iterator<IndexIterator,Integer,Distance>,
Integer, Distance,Integer*, Integer&>
{
public:
typedef component_iterator self;
IndexIterator next;
Integer node;
typedef std::forward_iterator_tag iterator_category;
typedef Integer value_type;
typedef Integer& reference;
typedef Integer* pointer;
typedef Distance difference_type;
component_iterator() {}
component_iterator(IndexIterator x, Integer i)
: next(x), node(i) {}
Integer operator*() const {
return node;
}
self& operator++() {
node = next[node];
return *this;
}
};
template <class IndexIterator, class Integer, class Distance>
inline bool
operator==(const component_iterator<IndexIterator, Integer, Distance>& x,
const component_iterator<IndexIterator, Integer, Distance>& y)
{
return x.node == y.node;
}
} // namespace detail
} // namespace detail
#if defined(__sgi) && !defined(__GNUC__)
#pragma reset woff 1234
#endif
#endif
@@ -0,0 +1,319 @@
//
//=======================================================================
// Copyright 2009 Trustees of Indiana University
// Authors: Jeremiah J. Willcock, Andrew Lumsdaine
//
// 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_D_ARY_HEAP_HPP
#define BOOST_D_ARY_HEAP_HPP
#include <vector>
#include <cstddef>
#include <algorithm>
#include <utility>
#include <boost/assert.hpp>
#include <boost/static_assert.hpp>
#include <boost/shared_array.hpp>
#include <boost/property_map/property_map.hpp>
// WARNING: it is not safe to copy a d_ary_heap_indirect and then modify one of
// the copies. The class is required to be copyable so it can be passed around
// (without move support from C++11), but it deep-copies the heap contents yet
// shallow-copies the index_in_heap_map.
namespace boost {
// Swap two elements in a property map without assuming they model
// LvaluePropertyMap -- currently not used
template <typename PropMap>
inline void property_map_swap(
PropMap prop_map,
const typename boost::property_traits<PropMap>::key_type& ka,
const typename boost::property_traits<PropMap>::key_type& kb) {
typename boost::property_traits<PropMap>::value_type va = get(prop_map, ka);
put(prop_map, ka, get(prop_map, kb));
put(prop_map, kb, va);
}
namespace detail {
template <typename Value>
class fixed_max_size_vector {
boost::shared_array<Value> m_data;
std::size_t m_size;
public:
typedef std::size_t size_type;
fixed_max_size_vector(std::size_t max_size)
: m_data(new Value[max_size]), m_size(0) {}
std::size_t size() const {return m_size;}
bool empty() const {return m_size == 0;}
Value& operator[](std::size_t i) {return m_data[i];}
const Value& operator[](std::size_t i) const {return m_data[i];}
void push_back(Value v) {m_data[m_size++] = v;}
void pop_back() {--m_size;}
Value& back() {return m_data[m_size - 1];}
const Value& back() const {return m_data[m_size - 1];}
};
}
// D-ary heap using an indirect compare operator (use identity_property_map
// as DistanceMap to get a direct compare operator). This heap appears to be
// commonly used for Dijkstra's algorithm for its good practical performance
// on some platforms; asymptotically, it has an O(lg N) decrease-key
// operation while that can be done in constant time on a relaxed heap. The
// implementation is mostly based on the binary heap page on Wikipedia and
// online sources that state that the operations are the same for d-ary
// heaps. This code is not based on the old Boost d-ary heap code.
//
// - d_ary_heap_indirect is a model of UpdatableQueue as is needed for
// dijkstra_shortest_paths.
//
// - Value must model Assignable.
// - Arity must be at least 2 (optimal value appears to be 4, both in my and
// third-party experiments).
// - IndexInHeapMap must be a ReadWritePropertyMap from Value to
// Container::size_type (to store the index of each stored value within the
// heap for decrease-key aka update).
// - DistanceMap must be a ReadablePropertyMap from Value to something
// (typedef'ed as distance_type).
// - Compare must be a BinaryPredicate used as a less-than operator on
// distance_type.
// - Container must be a random-access, contiguous container (in practice,
// the operations used probably require that it is std::vector<Value>).
//
template <typename Value,
std::size_t Arity,
typename IndexInHeapPropertyMap,
typename DistanceMap,
typename Compare = std::less<Value>,
typename Container = std::vector<Value> >
class d_ary_heap_indirect {
BOOST_STATIC_ASSERT (Arity >= 2);
public:
typedef typename Container::size_type size_type;
typedef Value value_type;
typedef typename boost::property_traits<DistanceMap>::value_type key_type;
typedef DistanceMap key_map;
d_ary_heap_indirect(DistanceMap distance,
IndexInHeapPropertyMap index_in_heap,
const Compare& compare = Compare(),
const Container& data = Container())
: compare(compare), data(data), distance(distance),
index_in_heap(index_in_heap) {}
/* Implicit copy constructor */
/* Implicit assignment operator */
size_type size() const {
return data.size();
}
bool empty() const {
return data.empty();
}
void push(const Value& v) {
size_type index = data.size();
data.push_back(v);
put(index_in_heap, v, index);
preserve_heap_property_up(index);
verify_heap();
}
Value& top() {
BOOST_ASSERT (!this->empty());
return data[0];
}
const Value& top() const {
BOOST_ASSERT (!this->empty());
return data[0];
}
void pop() {
BOOST_ASSERT (!this->empty());
put(index_in_heap, data[0], (size_type)(-1));
if (data.size() != 1) {
data[0] = data.back();
put(index_in_heap, data[0], (size_type)(0));
data.pop_back();
preserve_heap_property_down();
verify_heap();
} else {
data.pop_back();
}
}
// This function assumes the key has been updated (using an external write
// to the distance map or such)
// See http://coding.derkeiler.com/Archive/General/comp.theory/2007-05/msg00043.html
void update(const Value& v) { /* decrease-key */
size_type index = get(index_in_heap, v);
preserve_heap_property_up(index);
verify_heap();
}
bool contains(const Value& v) const {
size_type index = get(index_in_heap, v);
return (index != (size_type)(-1));
}
void push_or_update(const Value& v) { /* insert if not present, else update */
size_type index = get(index_in_heap, v);
if (index == (size_type)(-1)) {
index = data.size();
data.push_back(v);
put(index_in_heap, v, index);
}
preserve_heap_property_up(index);
verify_heap();
}
DistanceMap keys() const {
return distance;
}
private:
Compare compare;
Container data;
DistanceMap distance;
IndexInHeapPropertyMap index_in_heap;
// The distances being compared using compare and that are stored in the
// distance map
typedef typename boost::property_traits<DistanceMap>::value_type distance_type;
// Get the parent of a given node in the heap
static size_type parent(size_type index) {
return (index - 1) / Arity;
}
// Get the child_idx'th child of a given node; 0 <= child_idx < Arity
static size_type child(size_type index, std::size_t child_idx) {
return index * Arity + child_idx + 1;
}
// Swap two elements in the heap by index, updating index_in_heap
void swap_heap_elements(size_type index_a, size_type index_b) {
using std::swap;
Value value_a = data[index_a];
Value value_b = data[index_b];
data[index_a] = value_b;
data[index_b] = value_a;
put(index_in_heap, value_a, index_b);
put(index_in_heap, value_b, index_a);
}
// Emulate the indirect_cmp that is now folded into this heap class
bool compare_indirect(const Value& a, const Value& b) const {
return compare(get(distance, a), get(distance, b));
}
// Verify that the array forms a heap; commented out by default
void verify_heap() const {
// This is a very expensive test so it should be disabled even when
// NDEBUG is not defined
#if 0
for (size_t i = 1; i < data.size(); ++i) {
if (compare_indirect(data[i], data[parent(i)])) {
BOOST_ASSERT (!"Element is smaller than its parent");
}
}
#endif
}
// Starting at a node, move up the tree swapping elements to preserve the
// heap property
void preserve_heap_property_up(size_type index) {
size_type orig_index = index;
size_type num_levels_moved = 0;
// The first loop just saves swaps that need to be done in order to avoid
// aliasing issues in its search; there is a second loop that does the
// necessary swap operations
if (index == 0) return; // Do nothing on root
Value currently_being_moved = data[index];
distance_type currently_being_moved_dist =
get(distance, currently_being_moved);
for (;;) {
if (index == 0) break; // Stop at root
size_type parent_index = parent(index);
Value parent_value = data[parent_index];
if (compare(currently_being_moved_dist, get(distance, parent_value))) {
++num_levels_moved;
index = parent_index;
continue;
} else {
break; // Heap property satisfied
}
}
// Actually do the moves -- move num_levels_moved elements down in the
// tree, then put currently_being_moved at the top
index = orig_index;
for (size_type i = 0; i < num_levels_moved; ++i) {
size_type parent_index = parent(index);
Value parent_value = data[parent_index];
put(index_in_heap, parent_value, index);
data[index] = parent_value;
index = parent_index;
}
data[index] = currently_being_moved;
put(index_in_heap, currently_being_moved, index);
verify_heap();
}
// From the root, swap elements (each one with its smallest child) if there
// are any parent-child pairs that violate the heap property
void preserve_heap_property_down() {
if (data.empty()) return;
size_type index = 0;
Value currently_being_moved = data[0];
distance_type currently_being_moved_dist =
get(distance, currently_being_moved);
size_type heap_size = data.size();
Value* data_ptr = &data[0];
for (;;) {
size_type first_child_index = child(index, 0);
if (first_child_index >= heap_size) break; /* No children */
Value* child_base_ptr = data_ptr + first_child_index;
size_type smallest_child_index = 0;
distance_type smallest_child_dist = get(distance, child_base_ptr[smallest_child_index]);
if (first_child_index + Arity <= heap_size) {
// Special case for a statically known loop count (common case)
for (size_t i = 1; i < Arity; ++i) {
Value i_value = child_base_ptr[i];
distance_type i_dist = get(distance, i_value);
if (compare(i_dist, smallest_child_dist)) {
smallest_child_index = i;
smallest_child_dist = i_dist;
}
}
} else {
for (size_t i = 1; i < heap_size - first_child_index; ++i) {
distance_type i_dist = get(distance, child_base_ptr[i]);
if (compare(i_dist, smallest_child_dist)) {
smallest_child_index = i;
smallest_child_dist = i_dist;
}
}
}
if (compare(smallest_child_dist, currently_being_moved_dist)) {
swap_heap_elements(smallest_child_index + first_child_index, index);
index = smallest_child_index + first_child_index;
continue;
} else {
break; // Heap property satisfied
}
}
verify_heap();
}
};
} // namespace boost
#endif // BOOST_D_ARY_HEAP_HPP
@@ -0,0 +1,124 @@
//
//=======================================================================
// 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_GRAPH_DETAIL_EDGE_HPP
#define BOOST_GRAPH_DETAIL_EDGE_HPP
#if __GNUC__ < 3
#include <iostream>
#else
#include <iosfwd>
#endif
namespace boost {
namespace detail {
template <typename Directed, typename Vertex>
struct edge_base
{
inline edge_base() {}
inline edge_base(Vertex s, Vertex d)
: m_source(s), m_target(d) { }
Vertex m_source;
Vertex m_target;
};
template <typename Directed, typename Vertex>
class edge_desc_impl : public edge_base<Directed,Vertex> {
typedef edge_desc_impl self;
typedef edge_base<Directed,Vertex> Base;
public:
typedef void property_type;
inline edge_desc_impl() : m_eproperty(0) {}
inline edge_desc_impl(Vertex s, Vertex d, const property_type* eplug)
: Base(s,d), m_eproperty(const_cast<property_type*>(eplug)) { }
property_type* get_property() { return m_eproperty; }
const property_type* get_property() const { return m_eproperty; }
// protected:
property_type* m_eproperty;
};
template <class D, class V>
inline bool
operator==(const detail::edge_desc_impl<D,V>& a,
const detail::edge_desc_impl<D,V>& b)
{
return a.get_property() == b.get_property();
}
template <class D, class V>
inline bool
operator!=(const detail::edge_desc_impl<D,V>& a,
const detail::edge_desc_impl<D,V>& b)
{
return ! (a.get_property() == b.get_property());
}
// Order edges according to the address of their property object
template <class D, class V>
inline bool
operator<(const detail::edge_desc_impl<D,V>& a,
const detail::edge_desc_impl<D,V>& b)
{
return a.get_property() < b.get_property();
}
template <class D, class V>
inline bool
operator<=(const detail::edge_desc_impl<D,V>& a,
const detail::edge_desc_impl<D,V>& b)
{
return a.get_property() <= b.get_property();
}
template <class D, class V>
inline bool
operator>(const detail::edge_desc_impl<D,V>& a,
const detail::edge_desc_impl<D,V>& b)
{
return a.get_property() > b.get_property();
}
template <class D, class V>
inline bool
operator>=(const detail::edge_desc_impl<D,V>& a,
const detail::edge_desc_impl<D,V>& b)
{
return a.get_property() >= b.get_property();
}
} //namespace detail
} // namespace boost
namespace std {
#if __GNUC__ < 3
template <class D, class V>
std::ostream&
operator<<(std::ostream& os, const boost::detail::edge_desc_impl<D,V>& e)
{
return os << "(" << e.m_source << "," << e.m_target << ")";
}
#else
template <class Char, class Traits, class D, class V>
std::basic_ostream<Char, Traits>&
operator<<(std::basic_ostream<Char, Traits>& os,
const boost::detail::edge_desc_impl<D,V>& e)
{
return os << "(" << e.m_source << "," << e.m_target << ")";
}
#endif
}
#endif // BOOST_GRAPH_DETAIL_DETAIL_EDGE_HPP
@@ -0,0 +1,131 @@
// (C) Copyright 2007 Andrew Sutton
//
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0 (See accompanying file
// LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GRAPH_DETAIL_GEODESIC_HPP
#define BOOST_GRAPH_DETAIL_GEODESIC_HPP
#include <functional>
#include <boost/config.hpp>
#include <boost/graph/graph_concepts.hpp>
#include <boost/graph/numeric_values.hpp>
#include <boost/concept/assert.hpp>
// TODO: Should this really be in detail?
namespace boost
{
// This is a very good discussion on centrality measures. While I can't
// say that this has been the motivating factor for the design and
// implementation of ths centrality framework, it does provide a single
// point of reference for defining things like degree and closeness
// centrality. Plus, the bibliography seems fairly complete.
//
// @article{citeulike:1144245,
// author = {Borgatti, Stephen P. and Everett, Martin G.},
// citeulike-article-id = {1144245},
// doi = {10.1016/j.socnet.2005.11.005},
// journal = {Social Networks},
// month = {October},
// number = {4},
// pages = {466--484},
// priority = {0},
// title = {A Graph-theoretic perspective on centrality},
// url = {http://dx.doi.org/10.1016/j.socnet.2005.11.005},
// volume = {28},
// year = {2006}
// }
// }
namespace detail {
// Note that this assumes T == property_traits<DistanceMap>::value_type
// and that the args and return of combine are also T.
template <typename Graph,
typename DistanceMap,
typename Combinator,
typename Distance>
inline Distance
combine_distances(const Graph& g,
DistanceMap dist,
Combinator combine,
Distance init)
{
BOOST_CONCEPT_ASSERT(( VertexListGraphConcept<Graph> ));
typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
typedef typename graph_traits<Graph>::vertex_iterator VertexIterator;
BOOST_CONCEPT_ASSERT(( ReadablePropertyMapConcept<DistanceMap,Vertex> ));
BOOST_CONCEPT_ASSERT(( NumericValueConcept<Distance> ));
typedef numeric_values<Distance> DistanceNumbers;
BOOST_CONCEPT_ASSERT(( AdaptableBinaryFunction<Combinator,Distance,Distance,Distance> ));
// If there's ever an infinite distance, then we simply return
// infinity. Note that this /will/ include the a non-zero
// distance-to-self in the combined values. However, this is usually
// zero, so it shouldn't be too problematic.
Distance ret = init;
VertexIterator i, end;
for(boost::tie(i, end) = vertices(g); i != end; ++i) {
Vertex v = *i;
if(get(dist, v) != DistanceNumbers::infinity()) {
ret = combine(ret, get(dist, v));
}
else {
ret = DistanceNumbers::infinity();
break;
}
}
return ret;
}
// Similar to std::plus<T>, but maximizes parameters
// rather than adding them.
template <typename T>
struct maximize : public std::binary_function<T, T, T>
{
T operator ()(T x, T y) const
{ BOOST_USING_STD_MAX(); return max BOOST_PREVENT_MACRO_SUBSTITUTION (x, y); }
};
// Another helper, like maximize() to help abstract functional
// concepts. This is trivially instantiated for builtin numeric
// types, but should be specialized for those types that have
// discrete notions of reciprocals.
template <typename T>
struct reciprocal : public std::unary_function<T, T>
{
typedef std::unary_function<T, T> function_type;
typedef typename function_type::result_type result_type;
typedef typename function_type::argument_type argument_type;
T operator ()(T t)
{ return T(1) / t; }
};
} /* namespace detail */
// This type defines the basic facilities used for computing values
// based on the geodesic distances between vertices. Examples include
// closeness centrality and mean geodesic distance.
template <typename Graph, typename DistanceType, typename ResultType>
struct geodesic_measure
{
typedef DistanceType distance_type;
typedef ResultType result_type;
typedef typename graph_traits<Graph>::vertices_size_type size_type;
typedef numeric_values<distance_type> distance_values;
typedef numeric_values<result_type> result_values;
static inline distance_type infinite_distance()
{ return distance_values::infinity(); }
static inline result_type infinite_result()
{ return result_values::infinity(); }
static inline result_type zero_result()
{ return result_values::zero(); }
};
} /* namespace boost */
#endif
@@ -0,0 +1,293 @@
// Copyright 2009 The Trustees of Indiana University.
// 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)
// Authors: Jeremiah Willcock
// Andrew Lumsdaine
#ifndef BOOST_GRAPH_DETAIL_HISTOGRAM_SORT_HPP
#define BOOST_GRAPH_DETAIL_HISTOGRAM_SORT_HPP
#include <boost/assert.hpp>
namespace boost {
namespace graph {
namespace detail {
template<typename InputIterator>
size_t
reserve_count_for_single_pass_helper(InputIterator, InputIterator,
std::input_iterator_tag)
{
// Do nothing: we have no idea how much storage to reserve.
return 0;
}
template<typename InputIterator>
size_t
reserve_count_for_single_pass_helper(InputIterator first, InputIterator last,
std::random_access_iterator_tag)
{
using std::distance;
typename std::iterator_traits<InputIterator>::difference_type n =
distance(first, last);
return (size_t)n;
}
template<typename InputIterator>
size_t
reserve_count_for_single_pass(InputIterator first, InputIterator last) {
typedef typename std::iterator_traits<InputIterator>::iterator_category
category;
return reserve_count_for_single_pass_helper(first, last, category());
}
template <typename KeyIterator, typename RowstartIterator,
typename VerticesSize, typename KeyFilter, typename KeyTransform>
void
count_starts
(KeyIterator begin, KeyIterator end,
RowstartIterator starts, // Must support numverts + 1 elements
VerticesSize numkeys,
KeyFilter key_filter,
KeyTransform key_transform) {
typedef VerticesSize vertices_size_type;
typedef typename std::iterator_traits<RowstartIterator>::value_type EdgeIndex;
// Put the degree of each vertex v into m_rowstart[v + 1]
for (KeyIterator i = begin; i != end; ++i) {
if (key_filter(*i)) {
BOOST_ASSERT (key_transform(*i) < numkeys);
++starts[key_transform(*i) + 1];
}
}
// Compute the partial sum of the degrees to get the actual values of
// m_rowstart
EdgeIndex start_of_this_row = 0;
starts[0] = start_of_this_row;
for (vertices_size_type i = 1; i <= numkeys; ++i) {
start_of_this_row += starts[i];
starts[i] = start_of_this_row;
}
}
template <typename KeyIterator, typename RowstartIterator,
typename NumKeys,
typename Value1InputIter,
typename Value1OutputIter, typename KeyFilter, typename KeyTransform>
void
histogram_sort(KeyIterator key_begin, KeyIterator key_end,
RowstartIterator rowstart, // Must support numkeys + 1 elements and be precomputed
NumKeys numkeys,
Value1InputIter values1_begin,
Value1OutputIter values1_out,
KeyFilter key_filter,
KeyTransform key_transform) {
typedef NumKeys vertices_size_type;
typedef typename std::iterator_traits<RowstartIterator>::value_type EdgeIndex;
// Histogram sort the edges by their source vertices, putting the targets
// into m_column. The index current_insert_positions[v] contains the next
// location to insert out edges for vertex v.
std::vector<EdgeIndex>
current_insert_positions(rowstart, rowstart + numkeys);
Value1InputIter v1i = values1_begin;
for (KeyIterator i = key_begin; i != key_end; ++i, ++v1i) {
if (key_filter(*i)) {
vertices_size_type source = key_transform(*i);
BOOST_ASSERT (source < numkeys);
EdgeIndex insert_pos = current_insert_positions[source];
++current_insert_positions[source];
values1_out[insert_pos] = *v1i;
}
}
}
template <typename KeyIterator, typename RowstartIterator,
typename NumKeys,
typename Value1InputIter,
typename Value1OutputIter,
typename Value2InputIter,
typename Value2OutputIter,
typename KeyFilter, typename KeyTransform>
void
histogram_sort(KeyIterator key_begin, KeyIterator key_end,
RowstartIterator rowstart, // Must support numkeys + 1 elements and be precomputed
NumKeys numkeys,
Value1InputIter values1_begin,
Value1OutputIter values1_out,
Value2InputIter values2_begin,
Value2OutputIter values2_out,
KeyFilter key_filter,
KeyTransform key_transform) {
typedef NumKeys vertices_size_type;
typedef typename std::iterator_traits<RowstartIterator>::value_type EdgeIndex;
// Histogram sort the edges by their source vertices, putting the targets
// into m_column. The index current_insert_positions[v] contains the next
// location to insert out edges for vertex v.
std::vector<EdgeIndex>
current_insert_positions(rowstart, rowstart + numkeys);
Value1InputIter v1i = values1_begin;
Value2InputIter v2i = values2_begin;
for (KeyIterator i = key_begin; i != key_end; ++i, ++v1i, ++v2i) {
if (key_filter(*i)) {
vertices_size_type source = key_transform(*i);
BOOST_ASSERT (source < numkeys);
EdgeIndex insert_pos = current_insert_positions[source];
++current_insert_positions[source];
values1_out[insert_pos] = *v1i;
values2_out[insert_pos] = *v2i;
}
}
}
template <typename KeyIterator, typename RowstartIterator,
typename NumKeys,
typename Value1Iter,
typename KeyTransform>
void
histogram_sort_inplace(KeyIterator key_begin,
RowstartIterator rowstart, // Must support numkeys + 1 elements and be precomputed
NumKeys numkeys,
Value1Iter values1,
KeyTransform key_transform) {
typedef NumKeys vertices_size_type;
typedef typename std::iterator_traits<RowstartIterator>::value_type EdgeIndex;
// 1. Copy m_rowstart (except last element) to get insert positions
std::vector<EdgeIndex> insert_positions(rowstart, rowstart + numkeys);
// 2. Swap the sources and targets into place
for (size_t i = 0; i < rowstart[numkeys]; ++i) {
BOOST_ASSERT (key_transform(key_begin[i]) < numkeys);
// While edge i is not in the right bucket:
while (!(i >= rowstart[key_transform(key_begin[i])] && i < insert_positions[key_transform(key_begin[i])])) {
// Add a slot in the right bucket
size_t target_pos = insert_positions[key_transform(key_begin[i])]++;
BOOST_ASSERT (target_pos < rowstart[key_transform(key_begin[i]) + 1]);
if (target_pos == i) continue;
// Swap this edge into place
using std::swap;
swap(key_begin[i], key_begin[target_pos]);
swap(values1[i], values1[target_pos]);
}
}
}
template <typename KeyIterator, typename RowstartIterator,
typename NumKeys,
typename Value1Iter,
typename Value2Iter,
typename KeyTransform>
void
histogram_sort_inplace(KeyIterator key_begin,
RowstartIterator rowstart, // Must support numkeys + 1 elements and be precomputed
NumKeys numkeys,
Value1Iter values1,
Value2Iter values2,
KeyTransform key_transform) {
typedef NumKeys vertices_size_type;
typedef typename std::iterator_traits<RowstartIterator>::value_type EdgeIndex;
// 1. Copy m_rowstart (except last element) to get insert positions
std::vector<EdgeIndex> insert_positions(rowstart, rowstart + numkeys);
// 2. Swap the sources and targets into place
for (size_t i = 0; i < rowstart[numkeys]; ++i) {
BOOST_ASSERT (key_transform(key_begin[i]) < numkeys);
// While edge i is not in the right bucket:
while (!(i >= rowstart[key_transform(key_begin[i])] && i < insert_positions[key_transform(key_begin[i])])) {
// Add a slot in the right bucket
size_t target_pos = insert_positions[key_transform(key_begin[i])]++;
BOOST_ASSERT (target_pos < rowstart[key_transform(key_begin[i]) + 1]);
if (target_pos == i) continue;
// Swap this edge into place
using std::swap;
swap(key_begin[i], key_begin[target_pos]);
swap(values1[i], values1[target_pos]);
swap(values2[i], values2[target_pos]);
}
}
}
template <typename InputIterator, typename VerticesSize>
void split_into_separate_coords(InputIterator begin, InputIterator end,
std::vector<VerticesSize>& firsts,
std::vector<VerticesSize>& seconds) {
firsts.clear();
seconds.clear();
size_t reserve_size
= detail::reserve_count_for_single_pass(begin, end);
firsts.reserve(reserve_size);
seconds.reserve(reserve_size);
for (; begin != end; ++begin) {
std::pair<VerticesSize, VerticesSize> edge = *begin;
firsts.push_back(edge.first);
seconds.push_back(edge.second);
}
}
template <typename InputIterator, typename VerticesSize, typename SourceFilter>
void split_into_separate_coords_filtered
(InputIterator begin, InputIterator end,
std::vector<VerticesSize>& firsts,
std::vector<VerticesSize>& seconds,
const SourceFilter& filter) {
firsts.clear();
seconds.clear();
for (; begin != end; ++begin) {
std::pair<VerticesSize, VerticesSize> edge = *begin;
if (filter(edge.first)) {
firsts.push_back(edge.first);
seconds.push_back(edge.second);
}
}
}
template <typename InputIterator, typename PropInputIterator,
typename VerticesSize, typename PropType, typename SourceFilter>
void split_into_separate_coords_filtered
(InputIterator begin, InputIterator end,
PropInputIterator props,
std::vector<VerticesSize>& firsts,
std::vector<VerticesSize>& seconds,
std::vector<PropType>& props_out,
const SourceFilter& filter) {
firsts.clear();
seconds.clear();
props_out.clear();
for (; begin != end; ++begin) {
std::pair<VerticesSize, VerticesSize> edge = *begin;
if (filter(edge.first)) {
firsts.push_back(edge.first);
seconds.push_back(edge.second);
props_out.push_back(*props);
}
++props;
}
}
template <typename Pair>
struct project1st {
typedef typename Pair::first_type result_type;
const result_type& operator()(const Pair& p) const {return p.first;}
};
template <typename Pair>
struct project2nd {
typedef typename Pair::second_type result_type;
const result_type& operator()(const Pair& p) const {return p.second;}
};
}
}
}
#endif // BOOST_GRAPH_DETAIL_HISTOGRAM_SORT_HPP
@@ -0,0 +1,79 @@
//
//=======================================================================
// 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_GRAPH_DETAIL_INCIDENCE_ITERATOR_HPP
#define BOOST_GRAPH_DETAIL_INCIDENCE_ITERATOR_HPP
#include <utility>
#include <iterator>
// OBSOLETE
namespace boost {
namespace detail {
// EdgeDir tags
struct in_edge_tag { };
struct out_edge_tag { };
template <class Vertex, class Edge, class Iterator1D, class EdgeDir>
struct bidir_incidence_iterator {
typedef bidir_incidence_iterator self;
typedef Edge edge_type;
typedef typename Edge::property_type EdgeProperty;
public:
typedef int difference_type;
typedef std::forward_iterator_tag iterator_category;
typedef edge_type reference;
typedef edge_type value_type;
typedef value_type* pointer;
inline bidir_incidence_iterator() {}
inline bidir_incidence_iterator(Iterator1D ii, Vertex src)
: i(ii), _src(src) { }
inline self& operator++() { ++i; return *this; }
inline self operator++(int) { self tmp = *this; ++(*this); return tmp; }
inline reference operator*() const {
return deref_helper(EdgeDir());
}
inline self* operator->() { return this; }
Iterator1D& iter() { return i; }
const Iterator1D& iter() const { return i; }
Iterator1D i;
Vertex _src;
protected:
inline reference deref_helper(out_edge_tag) const {
return edge_type( _src, (*i).get_target(), &(*i).get_property() );
}
inline reference deref_helper(in_edge_tag) const {
return edge_type((*i).get_target(), _src, &(*i).get_property() );
}
};
template <class V, class E, class Iter, class Dir>
inline bool operator==(const bidir_incidence_iterator<V,E,Iter,Dir>& x,
const bidir_incidence_iterator<V,E,Iter,Dir>& y)
{
return x.i == y.i;
}
template <class V, class E, class Iter, class Dir>
inline bool operator!=(const bidir_incidence_iterator<V,E,Iter,Dir>& x,
const bidir_incidence_iterator<V,E,Iter,Dir>& y)
{
return x.i != y.i;
}
}
}
#endif
@@ -0,0 +1,77 @@
//=======================================================================
// Copyright 2002 Indiana University.
// Copyright 2009 Trustees of Indiana University.
// Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek, Michael Hansen
//
// 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_GRAPH_DETAIL_INCREMENTAL_COMPONENTS_HPP
#define BOOST_GRAPH_DETAIL_INCREMENTAL_COMPONENTS_HPP
#include <boost/operators.hpp>
namespace boost {
namespace detail {
// Iterator for a component index linked list. The contents of
// each array element represent the next index in the list. A
// special value (the maximum index + 1) is used to terminate a
// list.
template <typename IndexRandomAccessIterator>
class component_index_iterator :
boost::forward_iterator_helper<component_index_iterator<IndexRandomAccessIterator>,
typename std::iterator_traits<IndexRandomAccessIterator>::value_type,
typename std::iterator_traits<IndexRandomAccessIterator>::difference_type,
typename std::iterator_traits<IndexRandomAccessIterator>::pointer,
typename std::iterator_traits<IndexRandomAccessIterator>::reference> {
private:
typedef component_index_iterator<IndexRandomAccessIterator> self;
public:
typedef std::forward_iterator_tag iterator_category;
typedef typename std::iterator_traits<IndexRandomAccessIterator>::value_type value_type;
typedef typename std::iterator_traits<IndexRandomAccessIterator>::difference_type reference;
typedef typename std::iterator_traits<IndexRandomAccessIterator>::pointer pointer;
typedef typename std::iterator_traits<IndexRandomAccessIterator>::reference difference_type;
// Constructor for "begin" iterator
component_index_iterator(IndexRandomAccessIterator index_iterator,
value_type begin_index) :
m_index_iterator(index_iterator),
m_current_index(begin_index) { }
// Constructor for "end" iterator (end_index should be the linked
// list terminator).
component_index_iterator(value_type end_index) :
m_current_index(end_index) { }
inline value_type operator*() const {
return (m_current_index);
}
self& operator++() {
// Move to the next element in the linked list
m_current_index = m_index_iterator[m_current_index];
return (*this);
}
bool operator==(const self& other_iterator) const {
return (m_current_index == *other_iterator);
}
protected:
IndexRandomAccessIterator m_index_iterator;
value_type m_current_index;
}; // class component_index_iterator
} // namespace detail
} // namespace detail
#endif // BOOST_GRAPH_DETAIL_INCREMENTAL_COMPONENTS_HPP
@@ -0,0 +1,74 @@
// (C) Copyright 2007-2009 Andrew Sutton
//
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0 (See accompanying file
// LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GRAPH_DETAIL_INDEX_HPP
#define BOOST_GRAPH_DETAIL_INDEX_HPP
#include <boost/graph/graph_traits.hpp>
// The structures in this module are responsible for selecting and defining
// types for accessing a builting index map. Note that the selection of these
// types requires the Graph parameter to model either VertexIndexGraph or
// EdgeIndexGraph.
namespace boost
{
namespace detail
{
template <typename Graph>
struct vertex_indexer
{
typedef vertex_index_t index_type;
typedef typename property_map<Graph, vertex_index_t>::type map_type;
typedef typename property_map<Graph, vertex_index_t>::const_type const_map_type;
typedef typename property_traits<map_type>::value_type value_type;
typedef typename graph_traits<Graph>::vertex_descriptor key_type;
static const_map_type index_map(const Graph& g)
{ return get(vertex_index, g); }
static map_type index_map(Graph& g)
{ return get(vertex_index, g); }
static value_type index(key_type k, const Graph& g)
{ return get(vertex_index, g, k); }
};
template <typename Graph>
struct edge_indexer
{
typedef edge_index_t index_type;
typedef typename property_map<Graph, edge_index_t>::type map_type;
typedef typename property_map<Graph, edge_index_t>::const_type const_map_type;
typedef typename property_traits<map_type>::value_type value_type;
typedef typename graph_traits<Graph>::edge_descriptor key_type;
static const_map_type index_map(const Graph& g)
{ return get(edge_index, g); }
static map_type index_map(Graph& g)
{ return get(edge_index, g); }
static value_type index(key_type k, const Graph& g)
{ return get(edge_index, g, k); }
};
// NOTE: The Graph parameter MUST be a model of VertexIndexGraph or
// VertexEdgeGraph - whichever type Key is selecting.
template <typename Graph, typename Key>
struct choose_indexer
{
typedef typename mpl::if_<
is_same<Key, typename graph_traits<Graph>::vertex_descriptor>,
vertex_indexer<Graph>,
edge_indexer<Graph>
>::type indexer_type;
typedef typename indexer_type::index_type index_type;
};
}
}
#endif
@@ -0,0 +1,284 @@
// Copyright 2005 The Trustees of Indiana University.
// 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)
// Authors: Jeremiah Willcock
// Douglas Gregor
// Andrew Lumsdaine
// Indexed properties -- used for CSR and CSR-like graphs
#ifndef BOOST_GRAPH_INDEXED_PROPERTIES_HPP
#define BOOST_GRAPH_INDEXED_PROPERTIES_HPP
#include <vector>
#include <utility>
#include <algorithm>
#include <climits>
#include <iterator>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/properties.hpp>
#include <boost/iterator/counting_iterator.hpp>
#include <boost/integer.hpp>
#include <boost/iterator/iterator_facade.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/mpl/if.hpp>
namespace boost {
namespace detail {
template<typename Derived, typename Property, typename Descriptor, typename IndexMap>
class indexed_vertex_properties
{
public:
typedef no_property vertex_property_type;
typedef Property vertex_bundled;
typedef iterator_property_map<
typename std::vector<Property>::iterator,
IndexMap> vertex_map_type;
typedef iterator_property_map<
typename std::vector<Property>::const_iterator,
IndexMap> const_vertex_map_type;
// Directly access a vertex or edge bundle
Property& operator[](Descriptor v)
{ return m_vertex_properties[get(vertex_index, derived(), v)]; }
const Property& operator[](Descriptor v) const
{ return m_vertex_properties[get(vertex_index, derived(), v)]; }
vertex_map_type get_vertex_bundle(const IndexMap& index_map = IndexMap()) {
return vertex_map_type(m_vertex_properties.begin(), index_map);
}
const_vertex_map_type get_vertex_bundle(const IndexMap& index_map = IndexMap()) const {
return const_vertex_map_type(m_vertex_properties.begin(), index_map);
}
protected:
// Default-construct with no property values
indexed_vertex_properties() {}
// Initialize with n default-constructed property values
indexed_vertex_properties(std::size_t n) : m_vertex_properties(n) { }
public:
// Clear the properties vector
void clear()
{
m_vertex_properties.clear();
}
// Resize the properties vector
void resize(std::size_t n)
{
m_vertex_properties.resize(n);
}
// Reserve space in the vector of properties
void reserve(std::size_t n)
{
m_vertex_properties.reserve(n);
}
// Add a new property value to the back
void push_back(const Property& prop)
{
m_vertex_properties.push_back(prop);
}
// Write an element by raw index
void write_by_index(std::size_t idx, const Property& prop)
{
m_vertex_properties[idx] = prop;
}
// Access to the derived object
Derived& derived() { return *static_cast<Derived*>(this); }
const Derived& derived() const
{ return *static_cast<const Derived*>(this); }
public: // should be private, but friend templates not portable
std::vector<Property> m_vertex_properties;
};
template<typename Derived, typename Descriptor, typename IndexMap>
class indexed_vertex_properties<Derived, void, Descriptor, IndexMap>
{
struct secret {};
public:
typedef no_property vertex_property_type;
typedef void vertex_bundled;
typedef secret vertex_map_type;
typedef secret const_vertex_map_type;
secret operator[](secret) { return secret(); }
vertex_map_type get_vertex_bundle() const {
return vertex_map_type();
}
protected:
// All operations do nothing.
indexed_vertex_properties() { }
indexed_vertex_properties(std::size_t) { }
public:
void clear() { }
void resize(std::size_t) { }
void reserve(std::size_t) { }
};
template<typename Derived, typename Property, typename Descriptor, typename IndexMap>
class indexed_edge_properties
{
public:
typedef no_property edge_property_type;
typedef Property edge_bundled;
typedef Property edge_push_back_type;
typedef iterator_property_map<
typename std::vector<Property>::iterator,
IndexMap> edge_map_type;
typedef iterator_property_map<
typename std::vector<Property>::const_iterator,
IndexMap> const_edge_map_type;
// Directly access a edge or edge bundle
Property& operator[](Descriptor v)
{ return m_edge_properties[get(edge_index, derived(), v)]; }
const Property& operator[](Descriptor v) const
{ return m_edge_properties[get(edge_index, derived(), v)]; }
edge_map_type get_edge_bundle(const IndexMap& index_map = IndexMap()) {
return edge_map_type(m_edge_properties.begin(), index_map);
}
const_edge_map_type get_edge_bundle(const IndexMap& index_map = IndexMap()) const {
return const_edge_map_type(m_edge_properties.begin(), index_map);
}
protected:
// Default-construct with no property values
indexed_edge_properties() {}
// Initialize with n default-constructed property values
indexed_edge_properties(std::size_t n) : m_edge_properties(n) { }
// Get the size of the properties vector
std::size_t size() const
{
return m_edge_properties.size();
}
// Clear the properties vector
void clear()
{
m_edge_properties.clear();
}
// Resize the properties vector
void resize(std::size_t n)
{
m_edge_properties.resize(n);
}
// Reserve space in the vector of properties
void reserve(std::size_t n)
{
m_edge_properties.reserve(n);
}
// Write an element by raw index
void write_by_index(std::size_t idx, const Property& prop)
{
m_edge_properties[idx] = prop;
}
public:
// Add a new property value to the back
void push_back(const Property& prop)
{
m_edge_properties.push_back(prop);
}
// Move range of properties backwards
void move_range(std::size_t src_begin, std::size_t src_end, std::size_t dest_begin) {
std::copy_backward(
m_edge_properties.begin() + src_begin,
m_edge_properties.begin() + src_end,
m_edge_properties.begin() + dest_begin + (src_end - src_begin));
}
typedef typename std::vector<Property>::iterator iterator;
iterator begin() {return m_edge_properties.begin();}
iterator end() {return m_edge_properties.end();}
private:
// Access to the derived object
Derived& derived() { return *static_cast<Derived*>(this); }
const Derived& derived() const
{ return *static_cast<const Derived*>(this); }
public: // should be private, but friend templates not portable
std::vector<Property> m_edge_properties;
};
struct dummy_no_property_iterator
: public boost::iterator_facade<dummy_no_property_iterator, no_property, std::random_access_iterator_tag> {
mutable no_property prop;
no_property& dereference() const {return prop;}
bool equal(const dummy_no_property_iterator&) const {return true;}
void increment() {}
void decrement() {}
void advance(std::ptrdiff_t) {}
std::ptrdiff_t distance_to(const dummy_no_property_iterator) const {return 0;}
};
template<typename Derived, typename Descriptor, typename IndexMap>
class indexed_edge_properties<Derived, void, Descriptor, IndexMap>
{
struct secret {};
public:
typedef no_property edge_property_type;
typedef void edge_bundled;
typedef void* edge_push_back_type;
typedef secret edge_map_type;
typedef secret const_edge_map_type;
secret operator[](secret) { return secret(); }
void write_by_index(std::size_t /*idx*/, const no_property& /*prop*/) {}
edge_map_type get_edge_bundle(const IndexMap& = IndexMap()) const {
return edge_map_type();
}
protected:
// All operations do nothing.
indexed_edge_properties() { }
indexed_edge_properties(std::size_t) { }
std::size_t size() const {return 0;}
void clear() { }
void resize(std::size_t) { }
void reserve(std::size_t) { }
public:
void push_back(const edge_push_back_type&) { }
void move_range(std::size_t /*src_begin*/, std::size_t /*src_end*/, std::size_t /*dest_begin*/) {}
typedef dummy_no_property_iterator iterator;
iterator begin() {return dummy_no_property_iterator();}
iterator end() {return dummy_no_property_iterator();}
};
}
}
#endif // BOOST_GRAPH_INDEXED_PROPERTIES_HPP
@@ -0,0 +1,26 @@
// Copyright 2012 The Trustees of Indiana University.
// 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)
// Authors: Jeremiah Willcock
// Andrew Lumsdaine
// Selector to determine whether a selector is distributedS (can only be true
// if <boost/graph/distributed/selector.hpp> has been included) so that we can
// disable various sequential-graph-only traits specializations for distributed
// graphs.
#ifndef BOOST_GRAPH_DETAIL_IS_DISTRIBUTED_SELECTOR_HPP
#define BOOST_GRAPH_DETAIL_IS_DISTRIBUTED_SELECTOR_HPP
#include <boost/mpl/bool.hpp>
namespace boost {
namespace detail {
template <typename> struct is_distributed_selector: boost::mpl::false_ {};
}
}
#endif // BOOST_GRAPH_DETAIL_IS_DISTRIBUTED_SELECTOR_HPP
@@ -0,0 +1,237 @@
// Copyright (C) 2009 Andrew Sutton
// Use, modification and distribution is subject to 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_GRAPH_LABELED_GRAPH_TRAITS_HPP
#define BOOST_GRAPH_LABELED_GRAPH_TRAITS_HPP
#include <boost/graph/graph_mutability_traits.hpp>
namespace boost {
// Extend the graph mutability traits (and metafunctions) to include options
// for labeled graphs.
// NOTE: the label_vertex tag denotes the fact that you can basically assign
// arbitrary labels to vertices without modifying the actual graph.
// TODO: We might also overlay the uniqueness/multiplicity of labels in this
// hierarchy also. For now, we just assumed that labels are unique.
struct label_vertex_tag { };
struct labeled_add_vertex_tag : virtual label_vertex_tag { };
struct labeled_add_vertex_property_tag : virtual labeled_add_vertex_tag { };
struct labeled_remove_vertex_tag { };
struct labeled_add_edge_tag : virtual label_vertex_tag { };
struct labeled_add_edge_property_tag : virtual labeled_add_edge_tag{ };
struct labeled_remove_edge_tag { };
struct labeled_mutable_vertex_graph_tag
: virtual labeled_add_vertex_tag, virtual labeled_remove_vertex_tag
{ };
struct labeled_mutable_vertex_property_graph_tag
: virtual labeled_add_vertex_property_tag, virtual labeled_remove_vertex_tag
{ };
struct labeled_mutable_edge_graph_tag
: virtual labeled_add_edge_tag, virtual labeled_remove_edge_tag
{ };
struct labeled_mutable_edge_property_graph_tag
: virtual labeled_add_edge_property_tag, virtual labeled_remove_edge_tag
{ };
struct labeled_graph_tag
: virtual label_vertex_tag
{ };
struct labeled_mutable_graph_tag
: virtual labeled_mutable_vertex_graph_tag
, virtual labeled_mutable_edge_graph_tag
{ };
struct labeled_mutable_property_graph_tag
: virtual labeled_mutable_vertex_property_graph_tag
, virtual labeled_mutable_edge_property_graph_tag
{ };
struct labeled_add_only_property_graph_tag
: virtual labeled_add_vertex_property_tag
, virtual labeled_mutable_edge_property_graph_tag
{ };
// Metafunctions
template <typename Graph>
struct graph_has_add_vertex_by_label
: mpl::bool_<
is_convertible<
typename graph_mutability_traits<Graph>::category,
labeled_add_vertex_tag
>::value
>
{ };
template <typename Graph>
struct graph_has_add_vertex_by_label_with_property
: mpl::bool_<
is_convertible<
typename graph_mutability_traits<Graph>::category,
labeled_add_vertex_property_tag
>::value
>
{ };
template <typename Graph>
struct graph_has_remove_vertex_by_label
: mpl::bool_<
is_convertible<
typename graph_mutability_traits<Graph>::category,
labeled_remove_vertex_tag
>::value
>
{ };
template <typename Graph>
struct graph_has_add_edge_by_label
: mpl::bool_<
is_convertible<
typename graph_mutability_traits<Graph>::category,
labeled_add_edge_tag
>::value
>
{ };
template <typename Graph>
struct graph_has_add_edge_by_label_with_property
: mpl::bool_<
is_convertible<
typename graph_mutability_traits<Graph>::category,
labeled_add_edge_property_tag
>::value
>
{ };
template <typename Graph>
struct graph_has_remove_edge_by_label
: mpl::bool_<
is_convertible<
typename graph_mutability_traits<Graph>::category,
labeled_remove_edge_tag
>::value
>
{ };
template <typename Graph>
struct is_labeled_mutable_vertex_graph
: mpl::and_<
graph_has_add_vertex_by_label<Graph>,
graph_has_remove_vertex_by_label<Graph>
>
{ };
template <typename Graph>
struct is_labeled_mutable_vertex_property_graph
: mpl::and_<
graph_has_add_vertex_by_label<Graph>,
graph_has_remove_vertex_by_label<Graph>
>
{ };
template <typename Graph>
struct is_labeled_mutable_edge_graph
: mpl::and_<
graph_has_add_edge_by_label<Graph>,
graph_has_remove_edge_by_label<Graph>
>
{ };
template <typename Graph>
struct is_labeled_mutable_edge_property_graph
: mpl::and_<
graph_has_add_edge_by_label<Graph>,
graph_has_remove_edge_by_label<Graph>
>
{ };
template <typename Graph>
struct is_labeled_mutable_graph
: mpl::and_<
is_labeled_mutable_vertex_graph<Graph>,
is_labeled_mutable_edge_graph<Graph>
>
{ };
template <typename Graph>
struct is_labeled_mutable_property_graph
: mpl::and_<
is_labeled_mutable_vertex_property_graph<Graph>,
is_labeled_mutable_edge_property_graph<Graph>
>
{ };
template <typename Graph>
struct is_labeled_add_only_property_graph
: mpl::bool_<
is_convertible<
typename graph_mutability_traits<Graph>::category,
labeled_add_only_property_graph_tag
>::value
>
{ };
template <typename Graph>
struct is_labeled_graph
: mpl::bool_<
is_convertible<
typename graph_mutability_traits<Graph>::category,
label_vertex_tag
>::value
>
{ };
template <typename> struct graph_mutability_traits;
namespace graph_detail {
// The determine mutability metafunction computes a labeled mutability tag
// based on the mutability of the given graph type. This is used by the
// graph_mutability_traits specialization below.
template <typename Graph>
struct determine_mutability {
typedef typename mpl::if_<
is_add_only_property_graph<Graph>,
labeled_add_only_property_graph_tag,
typename mpl::if_<
is_mutable_property_graph<Graph>,
labeled_mutable_property_graph_tag,
typename mpl::if_<
is_mutable_graph<Graph>,
labeled_mutable_graph_tag,
typename mpl::if_<
is_mutable_edge_graph<Graph>,
labeled_graph_tag,
typename graph_mutability_traits<Graph>::category
>::type
>::type
>::type
>::type type;
};
} // namespace graph_detail
#define LABELED_GRAPH_PARAMS typename G, typename L, typename S
#define LABELED_GRAPH labeled_graph<G,L,S>
// Specialize mutability traits for the labeled graph.
// This specialization depends on the mutability of the underlying graph type.
// If the underlying graph is fully mutable, this is also fully mutable.
// Otherwise, it's different.
template <LABELED_GRAPH_PARAMS>
struct graph_mutability_traits< LABELED_GRAPH > {
typedef typename graph_detail::determine_mutability<
typename LABELED_GRAPH::graph_type
>::type category;
};
#undef LABELED_GRAPH_PARAMS
#undef LABELED_GRAPH
} // namespace boost
#endif
@@ -0,0 +1,220 @@
//=======================================================================
// Copyright 2002 Indiana University.
// 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_LIST_BASE_HPP
#define BOOST_LIST_BASE_HPP
#include <boost/iterator_adaptors.hpp>
// Perhaps this should go through formal review, and move to <boost/>.
/*
An alternate interface idea:
Extend the std::list functionality by creating remove/insert
functions that do not require the container object!
*/
namespace boost {
namespace detail {
//=========================================================================
// Linked-List Generic Implementation Functions
template <class Node, class Next>
inline Node
slist_insert_after(Node pos, Node x,
Next next)
{
next(x) = next(pos);
next(pos) = x;
return x;
}
// return next(pos) or next(next(pos)) ?
template <class Node, class Next>
inline Node
slist_remove_after(Node pos,
Next next)
{
Node n = next(pos);
next(pos) = next(n);
return n;
}
template <class Node, class Next>
inline Node
slist_remove_range(Node before_first, Node last,
Next next)
{
next(before_first) = last;
return last;
}
template <class Node, class Next>
inline Node
slist_previous(Node head, Node x, Node nil,
Next next)
{
while (head != nil && next(head) != x)
head = next(head);
return head;
}
template<class Node, class Next>
inline void
slist_splice_after(Node pos, Node before_first, Node before_last,
Next next)
{
if (pos != before_first && pos != before_last) {
Node first = next(before_first);
Node after = next(pos);
next(before_first) = next(before_last);
next(pos) = first;
next(before_last) = after;
}
}
template <class Node, class Next>
inline Node
slist_reverse(Node node, Node nil,
Next next)
{
Node result = node;
node = next(node);
next(result) = nil;
while(node) {
Node next = next(node);
next(node) = result;
result = node;
node = next;
}
return result;
}
template <class Node, class Next>
inline std::size_t
slist_size(Node head, Node nil,
Next next)
{
std::size_t s = 0;
for ( ; head != nil; head = next(head))
++s;
return s;
}
template <class Next, class Data>
class slist_iterator_policies
{
public:
explicit slist_iterator_policies(const Next& n, const Data& d)
: m_next(n), m_data(d) { }
template <class Reference, class Node>
Reference dereference(type<Reference>, const Node& x) const
{ return m_data(x); }
template <class Node>
void increment(Node& x) const
{ x = m_next(x); }
template <class Node>
bool equal(Node& x, Node& y) const
{ return x == y; }
protected:
Next m_next;
Data m_data;
};
//===========================================================================
// Doubly-Linked List Generic Implementation Functions
template <class Node, class Next, class Prev>
inline void
dlist_insert_before(Node pos, Node x,
Next next, Prev prev)
{
next(x) = pos;
prev(x) = prev(pos);
next(prev(pos)) = x;
prev(pos) = x;
}
template <class Node, class Next, class Prev>
void
dlist_remove(Node pos,
Next next, Prev prev)
{
Node next_node = next(pos);
Node prev_node = prev(pos);
next(prev_node) = next_node;
prev(next_node) = prev_node;
}
// This deletes every node in the list except the
// sentinel node.
template <class Node, class Delete>
inline void
dlist_clear(Node sentinel, Delete del)
{
Node i, tmp;
i = next(sentinel);
while (i != sentinel) {
tmp = i;
i = next(i);
del(tmp);
}
}
template <class Node>
inline bool
dlist_empty(Node dummy)
{
return next(dummy) == dummy;
}
template <class Node, class Next, class Prev>
void
dlist_transfer(Node pos, Node first, Node last,
Next next, Prev prev)
{
if (pos != last) {
// Remove [first,last) from its old position
next(prev(last)) = pos;
next(prev(first)) = last;
next(prev(pos)) = first;
// Splice [first,last) into its new position
Node tmp = prev(pos);
prev(pos) = prev(last);
prev(last) = prev(first);
prev(first) = tmp;
}
}
template <class Next, class Prev, class Data>
class dlist_iterator_policies
: public slist_iterator_policies<Next, Data>
{
typedef slist_iterator_policies<Next, Data> Base;
public:
template <class Node>
void decrement(Node& x) const
{ x = m_prev(x); }
dlist_iterator_policies(Next n, Prev p, Data d)
: Base(n,d), m_prev(p) { }
protected:
Prev m_prev;
};
} // namespace detail
} // namespace boost
#endif // BOOST_LIST_BASE_HPP
@@ -0,0 +1,205 @@
// (C) Copyright Jeremy Siek 2001.
// 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_PERMUTATION_HPP
#define BOOST_PERMUTATION_HPP
#include <vector>
#include <memory>
#include <functional>
#include <algorithm>
#include <boost/graph/detail/shadow_iterator.hpp>
namespace boost {
template <class Iter1, class Iter2>
void permute_serial(Iter1 permuter, Iter1 last, Iter2 result)
{
#ifdef BOOST_NO_STD_ITERATOR_TRAITS
typedef std::ptrdiff_t D:
#else
typedef typename std::iterator_traits<Iter1>::difference_type D;
#endif
D n = 0;
while (permuter != last) {
std::swap(result[n], result[*permuter]);
++n;
++permuter;
}
}
template <class InIter, class RandIterP, class RandIterR>
void permute_copy(InIter first, InIter last, RandIterP p, RandIterR result)
{
#ifdef BOOST_NO_STD_ITERATOR_TRAITS
typedef std::ptrdiff_t i = 0;
#else
typename std::iterator_traits<RandIterP>::difference_type i = 0;
#endif
for (; first != last; ++first, ++i)
result[p[i]] = *first;
}
namespace detail {
template <class RandIter, class RandIterPerm, class D, class T>
void permute_helper(RandIter first, RandIter last, RandIterPerm p, D, T)
{
D i = 0, pi, n = last - first, cycle_start;
T tmp;
std::vector<int> visited(n, false);
while (i != n) { // continue until all elements have been processed
cycle_start = i;
tmp = first[i];
do { // walk around a cycle
pi = p[i];
visited[pi] = true;
std::swap(tmp, first[pi]);
i = pi;
} while (i != cycle_start);
// find the next cycle
for (i = 0; i < n; ++i)
if (visited[i] == false)
break;
}
}
} // namespace detail
template <class RandIter, class RandIterPerm>
void permute(RandIter first, RandIter last, RandIterPerm p)
{
detail::permute_helper(first, last, p, last - first, *first);
}
// Knuth 1.3.3, Vol. 1 p 176
// modified for zero-based arrays
// time complexity?
//
// WARNING: T must be a signed integer!
template <class PermIter>
void invert_permutation(PermIter X, PermIter Xend)
{
#ifdef BOOST_NO_STD_ITERATOR_TRAITS
typedef std::ptrdiff_t T:
#else
typedef typename std::iterator_traits<PermIter>::value_type T;
#endif
T n = Xend - X;
T m = n;
T j = -1;
while (m > 0) {
T i = X[m-1] + 1;
if (i > 0) {
do {
X[m-1] = j - 1;
j = -m;
m = i;
i = X[m-1] + 1;
} while (i > 0);
i = j;
}
X[m-1] = -i - 1;
--m;
}
}
// Takes a "normal" permutation array (and its inverse), and turns it
// into a BLAS-style permutation array (which can be thought of as a
// serialized permutation).
template <class Iter1, class Iter2, class Iter3>
inline void serialize_permutation(Iter1 q, Iter1 q_end, Iter2 q_inv, Iter3 p)
{
#ifdef BOOST_NO_STD_ITERATOR_TRAITS
typedef std::ptrdiff_t P1;
typedef std::ptrdiff_t P2;
typedef std::ptrdiff_t D;
#else
typedef typename std::iterator_traits<Iter1>::value_type P1;
typedef typename std::iterator_traits<Iter2>::value_type P2;
typedef typename std::iterator_traits<Iter1>::difference_type D;
#endif
D n = q_end - q;
for (D i = 0; i < n; ++i) {
P1 qi = q[i];
P2 qii = q_inv[i];
*p++ = qii;
std::swap(q[i], q[qii]);
std::swap(q_inv[i], q_inv[qi]);
}
}
// Not used anymore, leaving it here for future reference.
template <typename Iter, typename Compare>
void merge_sort(Iter first, Iter last, Compare cmp)
{
if (first + 1 < last) {
Iter mid = first + (last - first)/2;
merge_sort(first, mid, cmp);
merge_sort(mid, last, cmp);
std::inplace_merge(first, mid, last, cmp);
}
}
// time: N log N + 3N + ?
// space: 2N
template <class Iter, class IterP, class Cmp, class Alloc>
inline void sortp(Iter first, Iter last, IterP p, Cmp cmp, Alloc alloc)
{
typedef typename std::iterator_traits<IterP>::value_type P;
typedef typename std::iterator_traits<IterP>::difference_type D;
D n = last - first;
std::vector<P, Alloc> q(n);
for (D i = 0; i < n; ++i)
q[i] = i;
std::sort(make_shadow_iter(first, q.begin()),
make_shadow_iter(last, q.end()),
shadow_cmp<Cmp>(cmp));
invert_permutation(q.begin(), q.end());
std::copy(q.begin(), q.end(), p);
}
template <class Iter, class IterP, class Cmp>
inline void sortp(Iter first, Iter last, IterP p, Cmp cmp)
{
typedef typename std::iterator_traits<IterP>::value_type P;
sortp(first, last, p, cmp, std::allocator<P>());
}
template <class Iter, class IterP>
inline void sortp(Iter first, Iter last, IterP p)
{
typedef typename std::iterator_traits<Iter>::value_type T;
typedef typename std::iterator_traits<IterP>::value_type P;
sortp(first, last, p, std::less<T>(), std::allocator<P>());
}
template <class Iter, class IterP, class Cmp, class Alloc>
inline void sortv(Iter first, Iter last, IterP p, Cmp cmp, Alloc alloc)
{
typedef typename std::iterator_traits<IterP>::value_type P;
typedef typename std::iterator_traits<IterP>::difference_type D;
D n = last - first;
std::vector<P, Alloc> q(n), q_inv(n);
for (D i = 0; i < n; ++i)
q_inv[i] = i;
std::sort(make_shadow_iter(first, q_inv.begin()),
make_shadow_iter(last, q_inv.end()),
shadow_cmp<Cmp>(cmp));
std::copy(q_inv, q_inv.end(), q.begin());
invert_permutation(q.begin(), q.end());
serialize_permutation(q.begin(), q.end(), q_inv.end(), p);
}
} // namespace boost
#endif // BOOST_PERMUTATION_HPP
@@ -0,0 +1,108 @@
// Copyright 2004-9 Trustees of Indiana University
// 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)
//
// read_graphviz_new.hpp -
// Initialize a model of the BGL's MutableGraph concept and an associated
// collection of property maps using a graph expressed in the GraphViz
// DOT Language.
//
// Based on the grammar found at:
// http://www.graphviz.org/cvs/doc/info/lang.html
//
// Jeremiah rewrite used grammar found at:
// http://www.graphviz.org/doc/info/lang.html
// and page 34 or http://www.graphviz.org/pdf/dotguide.pdf
//
// See documentation for this code at:
// http://www.boost.org/libs/graph/doc/read-graphviz.html
//
// Author: Jeremiah Willcock
// Ronald Garcia
//
#ifndef BOOST_READ_GRAPHVIZ_NEW_HPP
#define BOOST_READ_GRAPHVIZ_NEW_HPP
#include <boost/ref.hpp>
#include <boost/property_map/dynamic_property_map.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/detail/workaround.hpp>
#include <algorithm>
#include <string>
#include <vector>
#include <set>
#include <utility>
#include <map>
#include <iostream>
#include <cstdlib>
namespace boost {
namespace read_graphviz_detail {
typedef std::string node_name;
typedef std::string subgraph_name;
typedef std::map<std::string, std::string> properties;
struct node_and_port {
node_name name;
std::string angle; // Or empty if no angle
std::vector<std::string> location; // Up to two identifiers
friend inline bool operator==(const node_and_port& a, const node_and_port& b) {
return a.name == b.name &&
a.angle == b.angle &&
a.location == b.location;
}
friend inline bool operator<(const node_and_port& a, const node_and_port& b) {
if (a.name != b.name) return a.name < b.name;
if (a.angle != b.angle) return a.angle < b.angle;
return a.location < b.location;
}
};
struct edge_info {
node_and_port source;
node_and_port target;
properties props;
};
struct parser_result {
bool graph_is_directed;
bool graph_is_strict;
std::map<node_name, properties> nodes; // Global set
std::vector<edge_info> edges;
std::map<subgraph_name, properties> graph_props; // Root and subgraphs
};
// The actual parser, from libs/graph/src/read_graphviz_new.cpp
void parse_graphviz_from_string(const std::string& str, parser_result& result, bool want_directed);
// Translate from those results to a graph
void translate_results_to_graph(const parser_result& r, ::boost::detail::graph::mutate_graph* mg);
} // namespace read_graphviz_detail
namespace detail {
namespace graph {
BOOST_GRAPH_DECL bool read_graphviz_new(const std::string& str, boost::detail::graph::mutate_graph* mg);
} // end namespace graph
} // end namespace detail
template <typename MutableGraph>
bool read_graphviz_new(const std::string& str,
MutableGraph& graph, boost::dynamic_properties& dp,
std::string const& node_id = "node_id") {
boost::detail::graph::mutate_graph_impl<MutableGraph> mg(graph, dp, node_id);
return detail::graph::read_graphviz_new(str, &mg);
}
} // namespace boost
#endif // BOOST_READ_GRAPHVIZ_NEW_HPP
@@ -0,0 +1,614 @@
// Copyright 2004-9 Trustees of Indiana University
// 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)
//
// read_graphviz_spirit.hpp -
// Initialize a model of the BGL's MutableGraph concept and an associated
// collection of property maps using a graph expressed in the GraphViz
// DOT Language.
//
// Based on the grammar found at:
// http://www.graphviz.org/cvs/doc/info/lang.html
//
// See documentation for this code at:
// http://www.boost.org/libs/graph/doc/read-graphviz.html
//
// Author: Ronald Garcia
//
#ifndef BOOST_READ_GRAPHVIZ_SPIRIT_HPP
#define BOOST_READ_GRAPHVIZ_SPIRIT_HPP
// Phoenix/Spirit set these limits to 3, but I need more.
#define PHOENIX_LIMIT 6
#define BOOST_SPIRIT_CLOSURE_LIMIT 6
#include <boost/spirit/include/classic_multi_pass.hpp>
#include <boost/spirit/include/classic_core.hpp>
#include <boost/spirit/include/classic_confix.hpp>
#include <boost/spirit/include/classic_distinct.hpp>
#include <boost/spirit/include/classic_lists.hpp>
#include <boost/spirit/include/classic_escape_char.hpp>
#include <boost/spirit/include/classic_attribute.hpp>
#include <boost/spirit/include/classic_dynamic.hpp>
#include <boost/spirit/include/classic_actor.hpp>
#include <boost/spirit/include/classic_closure.hpp>
#include <boost/spirit/include/phoenix1.hpp>
#include <boost/spirit/include/phoenix1_binders.hpp>
#include <boost/ref.hpp>
#include <boost/function/function2.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/property_map/dynamic_property_map.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/detail/workaround.hpp>
#include <algorithm>
#include <exception> // for std::exception
#include <string>
#include <vector>
#include <set>
#include <utility>
#include <map>
#include <boost/graph/graphviz.hpp>
#include <boost/throw_exception.hpp>
namespace phoenix {
// Workaround: std::map::operator[] uses a different return type than all
// other standard containers. Phoenix doesn't account for that.
template <typename TK, typename T0, typename T1>
struct binary_operator<index_op, std::map<TK,T0>, T1>
{
typedef typename std::map<TK,T0>::mapped_type& result_type;
static result_type eval(std::map<TK,T0>& container, T1 const& index)
{ return container[index]; }
};
} // namespace phoenix
namespace boost {
namespace detail {
namespace graph {
/////////////////////////////////////////////////////////////////////////////
// Application-specific type definitions
/////////////////////////////////////////////////////////////////////////////
typedef std::set<edge_t> edges_t;
typedef std::set<node_t> nodes_t;
typedef std::set<id_t> ids_t;
typedef std::map<edge_t,ids_t> edge_map_t;
typedef std::map<node_t,ids_t> node_map_t;
typedef std::map<id_t,id_t> props_t;
typedef std::map<id_t,props_t> subgraph_props_t;
typedef boost::function2<void, id_t const&, id_t const&> actor_t;
typedef std::vector<edge_t> edge_stack_t;
typedef std::map<id_t,nodes_t> subgraph_nodes_t;
typedef std::map<id_t,edges_t> subgraph_edges_t;
/////////////////////////////////////////////////////////////////////////////
// Stack frames used by semantic actions
/////////////////////////////////////////////////////////////////////////////
struct id_closure : boost::spirit::classic::closure<id_closure, node_t> {
member1 name;
};
struct node_id_closure : boost::spirit::classic::closure<node_id_closure, node_t> {
member1 name;
};
struct attr_list_closure : boost::spirit::classic::closure<attr_list_closure, actor_t> {
member1 prop_actor;
};
struct property_closure : boost::spirit::classic::closure<property_closure, id_t, id_t> {
member1 key;
member2 value;
};
struct data_stmt_closure : boost::spirit::classic::closure<data_stmt_closure,
nodes_t,nodes_t,edge_stack_t,bool,node_t> {
member1 sources;
member2 dests;
member3 edge_stack;
member4 saw_node;
member5 active_node;
};
struct subgraph_closure : boost::spirit::classic::closure<subgraph_closure,
nodes_t, edges_t, node_t> {
member1 nodes;
member2 edges;
member3 name;
};
/////////////////////////////////////////////////////////////////////////////
// Grammar and Actions for the DOT Language
/////////////////////////////////////////////////////////////////////////////
// Grammar for a dot file.
struct dot_grammar : public boost::spirit::classic::grammar<dot_grammar> {
mutate_graph& graph_;
explicit dot_grammar(mutate_graph& graph) : graph_(graph) { }
template <class ScannerT>
struct definition {
definition(dot_grammar const& self) : self(self), subgraph_depth(0),
keyword_p("0-9a-zA-Z_") {
using namespace boost::spirit::classic;
using namespace phoenix;
// RG - Future Work
// - Handle multi-line strings using \ line continuation
// - Make keywords case insensitive
ID
= ( lexeme_d[((alpha_p | ch_p('_')) >> *(alnum_p | ch_p('_')))]
| real_p
| lexeme_d[confix_p('"', *c_escape_ch_p, '"')]
| comment_nest_p('<', '>')
)[ID.name = construct_<std::string>(arg1,arg2)]
;
a_list
= list_p( ID[(a_list.key = arg1),
(a_list.value = "true")
]
>> !( ch_p('=')
>> ID[a_list.value = arg1])
[phoenix::bind(&definition::call_prop_actor)
(var(*this),a_list.key,a_list.value)],!ch_p(','));
attr_list = +(ch_p('[') >> !a_list >> ch_p(']'));
// RG - disregard port id's for now.
port_location
= (ch_p(':') >> ID)
| (ch_p(':') >> ch_p('(') >> ID >> ch_p(',') >> ID >> ch_p(')'))
;
port_angle = ch_p('@') >> ID;
port
= port_location >> (!port_angle)
| port_angle >> (!port_location);
node_id
= ( ID[node_id.name = arg1] >> (!port) )
[phoenix::bind(&definition::memoize_node)(var(*this))];
graph_stmt
= (ID[graph_stmt.key = arg1] >>
ch_p('=') >>
ID[graph_stmt.value = arg1])
[phoenix::bind(&definition::call_graph_prop)
(var(*this),graph_stmt.key,graph_stmt.value)]
; // Graph property.
attr_stmt
= (as_lower_d[keyword_p("graph")]
>> attr_list(actor_t(phoenix::bind(&definition::default_graph_prop)
(var(*this),arg1,arg2))))
| (as_lower_d[keyword_p("node")]
>> attr_list(actor_t(phoenix::bind(&definition::default_node_prop)
(var(*this),arg1,arg2))))
| (as_lower_d[keyword_p("edge")]
>> attr_list(actor_t(phoenix::bind(&definition::default_edge_prop)
(var(*this),arg1,arg2))))
;
// edge_head is set depending on the graph type (directed/undirected)
edgeop = ch_p('-') >> ch_p(boost::ref(edge_head));
edgeRHS
= +( edgeop[(data_stmt.sources = data_stmt.dests),
(data_stmt.dests = construct_<nodes_t>())]
>> ( subgraph[data_stmt.dests = arg1]
| node_id[phoenix::bind(&definition::insert_node)
(var(*this),data_stmt.dests,arg1)]
)
[phoenix::bind(&definition::activate_edge)
(var(*this),data_stmt.sources,data_stmt.dests,
var(edges), var(default_edge_props))]
);
// To avoid backtracking, edge, node, and subgraph statements are
// processed as one nonterminal.
data_stmt
= ( subgraph[(data_stmt.dests = arg1),// will get moved in rhs
(data_stmt.saw_node = false)]
| node_id[(phoenix::bind(&definition::insert_node)
(var(*this),data_stmt.dests,arg1)),
(data_stmt.saw_node = true),
#ifdef BOOST_GRAPH_DEBUG
(std::cout << val("AcTive Node: ") << arg1 << "\n"),
#endif // BOOST_GRAPH_DEBUG
(data_stmt.active_node = arg1)]
) >> if_p(edgeRHS)[
!attr_list(
actor_t(phoenix::bind(&definition::edge_prop)
(var(*this),arg1,arg2)))
].else_p[
if_p(data_stmt.saw_node)[
!attr_list(
actor_t(phoenix::bind(&definition::node_prop)
(var(*this),arg1,arg2)))
] // otherwise it's a subgraph, nothing more to do.
];
stmt
= graph_stmt
| attr_stmt
| data_stmt
;
stmt_list = *( stmt >> !ch_p(';') );
subgraph
= !( as_lower_d[keyword_p("subgraph")]
>> (!ID[(subgraph.name = arg1),
(subgraph.nodes = (var(subgraph_nodes))[arg1]),
(subgraph.edges = (var(subgraph_edges))[arg1])])
)
>> ch_p('{')[++var(subgraph_depth)]
>> stmt_list
>> ch_p('}')[--var(subgraph_depth)]
[(var(subgraph_nodes))[subgraph.name] = subgraph.nodes]
[(var(subgraph_edges))[subgraph.name] = subgraph.edges]
| as_lower_d[keyword_p("subgraph")]
>> ID[(subgraph.nodes = (var(subgraph_nodes))[arg1]),
(subgraph.edges = (var(subgraph_edges))[arg1])]
;
the_grammar
= (!as_lower_d[keyword_p("strict")])
>> ( as_lower_d[keyword_p("graph")][
(var(edge_head) = '-'),
(phoenix::bind(&definition::check_undirected)(var(*this)))]
| as_lower_d[keyword_p("digraph")][
(var(edge_head) = '>'),
(phoenix::bind(&definition::check_directed)(var(*this)))]
)
>> (!ID) >> ch_p('{') >> stmt_list >> ch_p('}');
} // definition()
typedef boost::spirit::classic::rule<ScannerT> rule_t;
rule_t const& start() const { return the_grammar; }
//
// Semantic actions
//
void check_undirected() {
if(self.graph_.is_directed())
boost::throw_exception(boost::undirected_graph_error());
}
void check_directed() {
if(!self.graph_.is_directed())
boost::throw_exception(boost::directed_graph_error());
}
void memoize_node() {
id_t const& node = node_id.name();
props_t& node_props = default_node_props;
if(nodes.find(node) == nodes.end()) {
nodes.insert(node);
self.graph_.do_add_vertex(node);
node_map.insert(std::make_pair(node,ids_t()));
#ifdef BOOST_GRAPH_DEBUG
std::cout << "Add new node " << node << std::endl;
#endif // BOOST_GRAPH_DEBUG
// Set the default properties for this edge
// RG: Here I would actually set the properties
for(props_t::iterator i = node_props.begin();
i != node_props.end(); ++i) {
set_node_property(node,i->first,i->second);
}
if(subgraph_depth > 0) {
subgraph.nodes().insert(node);
// Set the subgraph's default properties as well
props_t& props = subgraph_node_props[subgraph.name()];
for(props_t::iterator i = props.begin(); i != props.end(); ++i) {
set_node_property(node,i->first,i->second);
}
}
} else {
#ifdef BOOST_GRAPH_DEBUG
std::cout << "See node " << node << std::endl;
#endif // BOOST_GRAPH_DEBUG
}
}
void activate_edge(nodes_t& sources, nodes_t& dests, edges_t& edges,
props_t& edge_props) {
edge_stack_t& edge_stack = data_stmt.edge_stack();
for(nodes_t::iterator i = sources.begin(); i != sources.end(); ++i) {
for(nodes_t::iterator j = dests.begin(); j != dests.end(); ++j) {
// Create the edge and push onto the edge stack.
#ifdef BOOST_GRAPH_DEBUG
std::cout << "Edge " << *i << " to " << *j << std::endl;
#endif // BOOST_GRAPH_DEBUG
edge_t edge = edge_t::new_edge();
edge_stack.push_back(edge);
edges.insert(edge);
edge_map.insert(std::make_pair(edge,ids_t()));
// Add the real edge.
self.graph_.do_add_edge(edge, *i, *j);
// Set the default properties for this edge
for(props_t::iterator k = edge_props.begin();
k != edge_props.end(); ++k) {
set_edge_property(edge,k->first,k->second);
}
if(subgraph_depth > 0) {
subgraph.edges().insert(edge);
// Set the subgraph's default properties as well
props_t& props = subgraph_edge_props[subgraph.name()];
for(props_t::iterator k = props.begin(); k != props.end(); ++k) {
set_edge_property(edge,k->first,k->second);
}
}
}
}
}
// node_prop - Assign the property for the current active node.
void node_prop(id_t const& key, id_t const& value) {
node_t& active_object = data_stmt.active_node();
set_node_property(active_object, key, value);
}
// edge_prop - Assign the property for the current active edges.
void edge_prop(id_t const& key, id_t const& value) {
edge_stack_t const& active_edges_ = data_stmt.edge_stack();
for (edge_stack_t::const_iterator i = active_edges_.begin();
i != active_edges_.end(); ++i) {
set_edge_property(*i,key,value);
}
}
// default_graph_prop - Store as a graph property.
void default_graph_prop(id_t const& key, id_t const& value) {
#ifdef BOOST_GRAPH_DEBUG
std::cout << key << " = " << value << std::endl;
#endif // BOOST_GRAPH_DEBUG
self.graph_.set_graph_property(key, value);
}
// default_node_prop - declare default properties for any future new nodes
void default_node_prop(id_t const& key, id_t const& value) {
nodes_t& nodes_ =
subgraph_depth == 0 ? nodes : subgraph.nodes();
props_t& node_props_ =
subgraph_depth == 0 ?
default_node_props :
subgraph_node_props[subgraph.name()];
// add this to the selected list of default node properties.
node_props_[key] = value;
// for each node, set its property to default-constructed value
// if it hasn't been set already.
// set the dynamic property map value
for(nodes_t::iterator i = nodes_.begin(); i != nodes_.end(); ++i)
if(node_map[*i].find(key) == node_map[*i].end()) {
set_node_property(*i,key,id_t());
}
}
// default_edge_prop - declare default properties for any future new edges
void default_edge_prop(id_t const& key, id_t const& value) {
edges_t& edges_ =
subgraph_depth == 0 ? edges : subgraph.edges();
props_t& edge_props_ =
subgraph_depth == 0 ?
default_edge_props :
subgraph_edge_props[subgraph.name()];
// add this to the list of default edge properties.
edge_props_[key] = value;
// for each edge, set its property to be empty string
// set the dynamic property map value
for(edges_t::iterator i = edges_.begin(); i != edges_.end(); ++i)
if(edge_map[*i].find(key) == edge_map[*i].end())
set_edge_property(*i,key,id_t());
}
// helper function
void insert_node(nodes_t& nodes, id_t const& name) {
nodes.insert(name);
}
void call_prop_actor(std::string const& lhs, std::string const& rhs) {
actor_t& actor = attr_list.prop_actor();
// If first and last characters of the rhs are double-quotes,
// remove them.
if (!rhs.empty() && rhs[0] == '"' && rhs[rhs.size() - 1] == '"')
actor(lhs, rhs.substr(1, rhs.size()-2));
else
actor(lhs,rhs);
}
void call_graph_prop(std::string const& lhs, std::string const& rhs) {
// If first and last characters of the rhs are double-quotes,
// remove them.
if (!rhs.empty() && rhs[0] == '"' && rhs[rhs.size() - 1] == '"')
this->default_graph_prop(lhs, rhs.substr(1, rhs.size()-2));
else
this->default_graph_prop(lhs,rhs);
}
void set_node_property(node_t const& node, id_t const& key,
id_t const& value) {
// Add the property key to the "set" table to avoid default overwrite
node_map[node].insert(key);
// Set the user's property map
self.graph_.set_node_property(key, node, value);
#ifdef BOOST_GRAPH_DEBUG
// Tell the world
std::cout << node << ": " << key << " = " << value << std::endl;
#endif // BOOST_GRAPH_DEBUG
}
void set_edge_property(edge_t const& edge, id_t const& key,
id_t const& value) {
// Add the property key to the "set" table to avoid default overwrite
edge_map[edge].insert(key);
// Set the user's property map
self.graph_.set_edge_property(key, edge, value);
#ifdef BOOST_GRAPH_DEBUG
// Tell the world
#if 0 // RG - edge representation changed,
std::cout << "(" << edge.first << "," << edge.second << "): "
#else
std::cout << "an edge: "
#endif // 0
<< key << " = " << value << std::endl;
#endif // BOOST_GRAPH_DEBUG
}
// Variables explicitly initialized
dot_grammar const& self;
// if subgraph_depth > 0, then we're processing a subgraph.
int subgraph_depth;
// Keywords;
const boost::spirit::classic::distinct_parser<> keyword_p;
//
// rules that make up the grammar
//
boost::spirit::classic::rule<ScannerT,id_closure::context_t> ID;
boost::spirit::classic::rule<ScannerT,property_closure::context_t> a_list;
boost::spirit::classic::rule<ScannerT,attr_list_closure::context_t> attr_list;
rule_t port_location;
rule_t port_angle;
rule_t port;
boost::spirit::classic::rule<ScannerT,node_id_closure::context_t> node_id;
boost::spirit::classic::rule<ScannerT,property_closure::context_t> graph_stmt;
rule_t attr_stmt;
boost::spirit::classic::rule<ScannerT,data_stmt_closure::context_t> data_stmt;
boost::spirit::classic::rule<ScannerT,subgraph_closure::context_t> subgraph;
rule_t edgeop;
rule_t edgeRHS;
rule_t stmt;
rule_t stmt_list;
rule_t the_grammar;
// The grammar uses edge_head to dynamically set the syntax for edges
// directed graphs: edge_head = '>', and so edgeop = "->"
// undirected graphs: edge_head = '-', and so edgeop = "--"
char edge_head;
//
// Support data structures
//
nodes_t nodes; // list of node names seen
edges_t edges; // list of edges seen
node_map_t node_map; // remember the properties set for each node
edge_map_t edge_map; // remember the properties set for each edge
subgraph_nodes_t subgraph_nodes; // per-subgraph lists of nodes
subgraph_edges_t subgraph_edges; // per-subgraph lists of edges
props_t default_node_props; // global default node properties
props_t default_edge_props; // global default edge properties
subgraph_props_t subgraph_node_props; // per-subgraph default node properties
subgraph_props_t subgraph_edge_props; // per-subgraph default edge properties
}; // struct definition
}; // struct dot_grammar
//
// dot_skipper - GraphViz whitespace and comment skipper
//
struct dot_skipper : public boost::spirit::classic::grammar<dot_skipper>
{
dot_skipper() {}
template <typename ScannerT>
struct definition
{
definition(dot_skipper const& /*self*/) {
using namespace boost::spirit::classic;
using namespace phoenix;
// comment forms
skip = eol_p >> comment_p("#")
| space_p
| comment_p("//")
#if BOOST_WORKAROUND(BOOST_MSVC, <= 1400)
| confix_p(str_p("/*") ,*anychar_p, str_p("*/"))
#else
| confix_p("/*" ,*anychar_p, "*/")
#endif
;
#ifdef BOOST_SPIRIT_DEBUG
BOOST_SPIRIT_DEBUG_RULE(skip);
#endif
}
boost::spirit::classic::rule<ScannerT> skip;
boost::spirit::classic::rule<ScannerT> const&
start() const { return skip; }
}; // definition
}; // dot_skipper
} // namespace graph
} // namespace detail
template <typename MultiPassIterator, typename MutableGraph>
bool read_graphviz_spirit(MultiPassIterator begin, MultiPassIterator end,
MutableGraph& graph, dynamic_properties& dp,
std::string const& node_id = "node_id") {
using namespace boost;
using namespace boost::spirit::classic;
typedef MultiPassIterator iterator_t;
typedef skip_parser_iteration_policy< boost::detail::graph::dot_skipper>
iter_policy_t;
typedef scanner_policies<iter_policy_t> scanner_policies_t;
typedef scanner<iterator_t, scanner_policies_t> scanner_t;
::boost::detail::graph::mutate_graph_impl<MutableGraph>
m_graph(graph, dp, node_id);
::boost::detail::graph::dot_grammar p(m_graph);
::boost::detail::graph::dot_skipper skip_p;
iter_policy_t iter_policy(skip_p);
scanner_policies_t policies(iter_policy);
scanner_t scan(begin, end, policies);
bool ok = p.parse(scan);
m_graph.finish_building_graph();
return ok;
}
} // namespace boost
#endif // BOOST_READ_GRAPHVIZ_SPIRIT_HPP
@@ -0,0 +1,418 @@
//=======================================================================
// 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_SELF_AVOIDING_WALK_HPP
#define BOOST_SELF_AVOIDING_WALK_HPP
/*
This file defines necessary components for SAW.
mesh language: (defined by myself to clearify what is what)
A triangle in mesh is called an triangle.
An edge in mesh is called an line.
A vertex in mesh is called a point.
A triangular mesh corresponds to a graph in which a vertex is a
triangle and an edge(u, v) stands for triangle u and triangle v
share an line.
After this point, a vertex always refers to vertex in graph,
therefore it is a traingle in mesh.
*/
#include <utility>
#include <boost/config.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/property_map/property_map.hpp>
#define SAW_SENTINAL -1
namespace boost {
template <class T1, class T2, class T3>
struct triple {
T1 first;
T2 second;
T3 third;
triple(const T1& a, const T2& b, const T3& c) : first(a), second(b), third(c) {}
triple() : first(SAW_SENTINAL), second(SAW_SENTINAL), third(SAW_SENTINAL) {}
};
typedef triple<int, int, int> Triple;
/* Define a vertex property which has a triangle inside. Triangle is
represented by a triple. */
struct triangle_tag { enum { num = 100 }; };
typedef property<triangle_tag,Triple> triangle_property;
/* Define an edge property with a line. A line is represented by a
pair. This is not required for SAW though.
*/
struct line_tag { enum { num = 101 }; };
template <class T> struct line_property
: public property<line_tag, std::pair<T,T> > { };
/*Precondition: Points in a Triangle are in order */
template <class Triangle, class Line>
inline void get_sharing(const Triangle& a, const Triangle& b, Line& l)
{
l.first = SAW_SENTINAL;
l.second = SAW_SENTINAL;
if ( a.first == b.first ) {
l.first = a.first;
if ( a.second == b.second || a.second == b.third )
l.second = a.second;
else if ( a.third == b.second || a.third == b.third )
l.second = a.third;
} else if ( a.first == b.second ) {
l.first = a.first;
if ( a.second == b.third )
l.second = a.second;
else if ( a.third == b.third )
l.second = a.third;
} else if ( a.first == b.third ) {
l.first = a.first;
} else if ( a.second == b.first ) {
l.first = a.second;
if ( a.third == b.second || a.third == b.third )
l.second = a.third;
} else if ( a.second == b.second ) {
l.first = a.second;
if ( a.third == b.third )
l.second = a.third;
} else if ( a.second == b.third ) {
l.first = a.second;
} else if ( a.third == b.first
|| a.third == b.second
|| a.third == b.third )
l.first = a.third;
/*Make it in order*/
if ( l.first > l.second ) {
typename Line::first_type i = l.first;
l.first = l.second;
l.second = i;
}
}
template <class TriangleDecorator, class Vertex, class Line>
struct get_vertex_sharing {
typedef std::pair<Vertex, Line> Pair;
get_vertex_sharing(const TriangleDecorator& _td) : td(_td) {}
inline Line operator()(const Vertex& u, const Vertex& v) const {
Line l;
get_sharing(td[u], td[v], l);
return l;
}
inline Line operator()(const Pair& u, const Vertex& v) const {
Line l;
get_sharing(td[u.first], td[v], l);
return l;
}
inline Line operator()(const Pair& u, const Pair& v) const {
Line l;
get_sharing(td[u.first], td[v.first], l);
return l;
}
TriangleDecorator td;
};
/* HList has to be a handle of data holder so that pass-by-value is
* in right logic.
*
* The element of HList is a pair of vertex and line. (remember a
* line is a pair of two ints.). That indicates the walk w from
* current vertex is across line. (If the first of line is -1, it is
* a point though.
*/
template < class TriangleDecorator, class HList, class IteratorD>
class SAW_visitor
: public bfs_visitor<>, public dfs_visitor<>
{
typedef typename boost::property_traits<IteratorD>::value_type iter;
/*use boost shared_ptr*/
typedef typename HList::element_type::value_type::second_type Line;
public:
typedef tree_edge_tag category;
inline SAW_visitor(TriangleDecorator _td, HList _hlist, IteratorD ia)
: td(_td), hlist(_hlist), iter_d(ia) {}
template <class Vertex, class Graph>
inline void start_vertex(Vertex v, Graph&) {
Line l1;
l1.first = SAW_SENTINAL;
l1.second = SAW_SENTINAL;
hlist->push_front(std::make_pair(v, l1));
iter_d[v] = hlist->begin();
}
/*Several symbols:
w(i): i-th triangle in walk w
w(i) |- w(i+1): w enter w(i+1) from w(i) over a line
w(i) ~> w(i+1): w enter w(i+1) from w(i) over a point
w(i) -> w(i+1): w enter w(i+1) from w(i)
w(i) ^ w(i+1): the line or point w go over from w(i) to w(i+1)
*/
template <class Edge, class Graph>
bool tree_edge(Edge e, Graph& G) {
using std::make_pair;
typedef typename boost::graph_traits<Graph>::vertex_descriptor Vertex;
Vertex tau = target(e, G);
Vertex i = source(e, G);
get_vertex_sharing<TriangleDecorator, Vertex, Line> get_sharing_line(td);
Line tau_i = get_sharing_line(tau, i);
iter w_end = hlist->end();
iter w_i = iter_d[i];
iter w_i_m_1 = w_i;
iter w_i_p_1 = w_i;
/*----------------------------------------------------------
* true false
*==========================================================
*a w(i-1) |- w(i) w(i-1) ~> w(i) or w(i-1) is null
*----------------------------------------------------------
*b w(i) |- w(i+1) w(i) ~> w(i+1) or no w(i+1) yet
*----------------------------------------------------------
*/
bool a = false, b = false;
--w_i_m_1;
++w_i_p_1;
b = ( w_i->second.first != SAW_SENTINAL );
if ( w_i_m_1 != w_end ) {
a = ( w_i_m_1->second.first != SAW_SENTINAL );
}
if ( a ) {
if ( b ) {
/*Case 1:
w(i-1) |- w(i) |- w(i+1)
*/
Line l1 = get_sharing_line(*w_i_m_1, tau);
iter w_i_m_2 = w_i_m_1;
--w_i_m_2;
bool c = true;
if ( w_i_m_2 != w_end ) {
c = w_i_m_2->second != l1;
}
if ( c ) { /* w(i-1) ^ tau != w(i-2) ^ w(i-1) */
/*extension: w(i-1) -> tau |- w(i) */
w_i_m_1->second = l1;
/*insert(pos, const T&) is to insert before pos*/
iter_d[tau] = hlist->insert(w_i, make_pair(tau, tau_i));
} else { /* w(i-1) ^ tau == w(i-2) ^ w(i-1) */
/*must be w(i-2) ~> w(i-1) */
bool d = true;
//need to handle the case when w_i_p_1 is null
Line l3 = get_sharing_line(*w_i_p_1, tau);
if ( w_i_p_1 != w_end )
d = w_i_p_1->second != l3;
if ( d ) { /* w(i+1) ^ tau != w(i+1) ^ w(i+2) */
/*extension: w(i) |- tau -> w(i+1) */
w_i->second = tau_i;
iter_d[tau] = hlist->insert(w_i_p_1, make_pair(tau, l3));
} else { /* w(i+1) ^ tau == w(i+1) ^ w(i+2) */
/*must be w(1+1) ~> w(i+2) */
Line l5 = get_sharing_line(*w_i_m_1, *w_i_p_1);
if ( l5 != w_i_p_1->second ) { /* w(i-1) ^ w(i+1) != w(i+1) ^ w(i+2) */
/*extension: w(i-2) -> tau |- w(i) |- w(i-1) -> w(i+1) */
w_i_m_2->second = get_sharing_line(*w_i_m_2, tau);
iter_d[tau] = hlist->insert(w_i, make_pair(tau, tau_i));
w_i->second = w_i_m_1->second;
w_i_m_1->second = l5;
iter_d[w_i_m_1->first] = hlist->insert(w_i_p_1, *w_i_m_1);
hlist->erase(w_i_m_1);
} else {
/*mesh is tetrahedral*/
// dont know what that means.
;
}
}
}
} else {
/*Case 2:
w(i-1) |- w(i) ~> w(1+1)
*/
if ( w_i->second.second == tau_i.first
|| w_i->second.second == tau_i.second ) { /*w(i) ^ w(i+1) < w(i) ^ tau*/
/*extension: w(i) |- tau -> w(i+1) */
w_i->second = tau_i;
Line l1 = get_sharing_line(*w_i_p_1, tau);
iter_d[tau] = hlist->insert(w_i_p_1, make_pair(tau, l1));
} else { /*w(i) ^ w(i+1) !< w(i) ^ tau*/
Line l1 = get_sharing_line(*w_i_m_1, tau);
bool c = true;
iter w_i_m_2 = w_i_m_1;
--w_i_m_2;
if ( w_i_m_2 != w_end )
c = l1 != w_i_m_2->second;
if (c) { /*w(i-1) ^ tau != w(i-2) ^ w(i-1)*/
/*extension: w(i-1) -> tau |- w(i)*/
w_i_m_1->second = l1;
iter_d[tau] = hlist->insert(w_i, make_pair(tau, tau_i));
} else { /*w(i-1) ^ tau == w(i-2) ^ w(i-1)*/
/*must be w(i-2)~>w(i-1)*/
/*extension: w(i-2) -> tau |- w(i) |- w(i-1) -> w(i+1)*/
w_i_m_2->second = get_sharing_line(*w_i_m_2, tau);
iter_d[tau] = hlist->insert(w_i, make_pair(tau, tau_i));
w_i->second = w_i_m_1->second;
w_i_m_1->second = get_sharing_line(*w_i_m_1, *w_i_p_1);
iter_d[w_i_m_1->first] = hlist->insert(w_i_p_1, *w_i_m_1);
hlist->erase(w_i_m_1);
}
}
}
} else {
if ( b ) {
/*Case 3:
w(i-1) ~> w(i) |- w(i+1)
*/
bool c = false;
if ( w_i_m_1 != w_end )
c = ( w_i_m_1->second.second == tau_i.first)
|| ( w_i_m_1->second.second == tau_i.second);
if ( c ) { /*w(i-1) ^ w(i) < w(i) ^ tau*/
/* extension: w(i-1) -> tau |- w(i) */
if ( w_i_m_1 != w_end )
w_i_m_1->second = get_sharing_line(*w_i_m_1, tau);
iter_d[tau] = hlist->insert(w_i, make_pair(tau, tau_i));
} else {
bool d = true;
Line l1;
l1.first = SAW_SENTINAL;
l1.second = SAW_SENTINAL;
if ( w_i_p_1 != w_end ) {
l1 = get_sharing_line(*w_i_p_1, tau);
d = l1 != w_i_p_1->second;
}
if (d) { /*w(i+1) ^ tau != w(i+1) ^ w(i+2)*/
/*extension: w(i) |- tau -> w(i+1) */
w_i->second = tau_i;
iter_d[tau] = hlist->insert(w_i_p_1, make_pair(tau, l1));
} else {
/*must be w(i+1) ~> w(i+2)*/
/*extension: w(i-1) -> w(i+1) |- w(i) |- tau -> w(i+2) */
iter w_i_p_2 = w_i_p_1;
++w_i_p_2;
w_i_p_1->second = w_i->second;
iter_d[i] = hlist->insert(w_i_p_2, make_pair(i, tau_i));
hlist->erase(w_i);
Line l2 = get_sharing_line(*w_i_p_2, tau);
iter_d[tau] = hlist->insert(w_i_p_2, make_pair(tau, l2));
}
}
} else {
/*Case 4:
w(i-1) ~> w(i) ~> w(i+1)
*/
bool c = false;
if ( w_i_m_1 != w_end ) {
c = (w_i_m_1->second.second == tau_i.first)
|| (w_i_m_1->second.second == tau_i.second);
}
if ( c ) { /*w(i-1) ^ w(i) < w(i) ^ tau */
/*extension: w(i-1) -> tau |- w(i) */
if ( w_i_m_1 != w_end )
w_i_m_1->second = get_sharing_line(*w_i_m_1, tau);
iter_d[tau] = hlist->insert(w_i, make_pair(tau, tau_i));
} else {
/*extension: w(i) |- tau -> w(i+1) */
w_i->second = tau_i;
Line l1;
l1.first = SAW_SENTINAL;
l1.second = SAW_SENTINAL;
if ( w_i_p_1 != w_end )
l1 = get_sharing_line(*w_i_p_1, tau);
iter_d[tau] = hlist->insert(w_i_p_1, make_pair(tau, l1));
}
}
}
return true;
}
protected:
TriangleDecorator td; /*a decorator for vertex*/
HList hlist;
/*This must be a handle of list to record the SAW
The element type of the list is pair<Vertex, Line>
*/
IteratorD iter_d;
/*Problem statement: Need a fast access to w for triangle i.
*Possible solution: mantain an array to record.
iter_d[i] will return an iterator
which points to w(i), where i is a vertex
representing triangle i.
*/
};
template <class Triangle, class HList, class Iterator>
inline
SAW_visitor<Triangle, HList, Iterator>
visit_SAW(Triangle t, HList hl, Iterator i) {
return SAW_visitor<Triangle, HList, Iterator>(t, hl, i);
}
template <class Tri, class HList, class Iter>
inline
SAW_visitor< random_access_iterator_property_map<Tri*,Tri,Tri&>,
HList, random_access_iterator_property_map<Iter*,Iter,Iter&> >
visit_SAW_ptr(Tri* t, HList hl, Iter* i) {
typedef random_access_iterator_property_map<Tri*,Tri,Tri&> TriD;
typedef random_access_iterator_property_map<Iter*,Iter,Iter&> IterD;
return SAW_visitor<TriD, HList, IterD>(t, hl, i);
}
// should also have combo's of pointers, and also const :(
}
#endif /*BOOST_SAW_H*/
@@ -0,0 +1,123 @@
// (C) Copyright Jeremy Siek 2001.
// 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_SET_ADAPTOR_HPP
#define BOOST_SET_ADAPTOR_HPP
#include <set>
#include <boost/unordered_set.hpp>
namespace boost {
template <class K, class C, class A, class T>
bool set_contains(const std::set<K,C,A>& s, const T& x) {
return s.find(x) != s.end();
}
template <class K, class H, class C, class A, class T>
bool set_contains(const boost::unordered_set<K,H,C,A>& s, const T& x) {
return s.find(x) != s.end();
}
template <class K, class C, class A>
bool set_equal(const std::set<K,C,A>& x,
const std::set<K,C,A>& y)
{
return x == y;
}
// Not the same as lexicographical_compare_3way applied to std::set.
// this is equivalent semantically to bitset::operator<()
template <class K, class C, class A>
int set_lex_order(const std::set<K,C,A>& x,
const std::set<K,C,A>& y)
{
typename std::set<K,C,A>::iterator
xi = x.begin(), yi = y.begin(), xend = x.end(), yend = y.end();
for (; xi != xend && yi != yend; ++xi, ++yi) {
if (*xi < *yi)
return 1;
else if (*yi < *xi)
return -1;
}
if (xi == xend)
return (yi == yend) ? 0 : -1;
else
return 1;
}
template <class K, class C, class A>
void set_clear(std::set<K,C,A>& x) {
x.clear();
}
template <class K, class C, class A>
bool set_empty(const std::set<K,C,A>& x) {
return x.empty();
}
template <class K, class C, class A, class T>
void set_insert(std::set<K,C,A>& x, const T& a) {
x.insert(a);
}
template <class K, class C, class A, class T>
void set_remove(std::set<K,C,A>& x, const T& a) {
x.erase(a);
}
template <class K, class C, class A>
void set_intersect(const std::set<K,C,A>& x,
const std::set<K,C,A>& y,
std::set<K,C,A>& z)
{
z.clear();
std::set_intersection(x.begin(), x.end(),
y.begin(), y.end(),
std::inserter(z));
}
template <class K, class C, class A>
void set_union(const std::set<K,C,A>& x,
const std::set<K,C,A>& y,
std::set<K,C,A>& z)
{
z.clear();
std::set_union(x.begin(), x.end(),
y.begin(), y.end(),
std::inserter(z));
}
template <class K, class C, class A>
void set_difference(const std::set<K,C,A>& x,
const std::set<K,C,A>& y,
std::set<K,C,A>& z)
{
z.clear();
std::set_difference(x.begin(), x.end(),
y.begin(), y.end(),
std::inserter(z, z.begin()));
}
template <class K, class C, class A>
bool set_subset(const std::set<K,C,A>& x,
const std::set<K,C,A>& y)
{
return std::includes(x.begin(), x.end(), y.begin(), y.end());
}
// Shit, can't implement this without knowing the size of the
// universe.
template <class K, class C, class A>
void set_compliment(const std::set<K,C,A>& /*x*/,
std::set<K,C,A>& z)
{
z.clear();
}
} // namespace boost
#endif // BOOST_SET_ADAPTOR_HPP
@@ -0,0 +1,139 @@
// (C) Copyright Jeremy Siek 2001.
// 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_SHADOW_ITERATOR_HPP
#define BOOST_SHADOW_ITERATOR_HPP
#include <boost/iterator_adaptors.hpp>
#include <boost/operators.hpp>
namespace boost {
namespace detail {
template <class A, class B, class D>
class shadow_proxy
: boost::operators< shadow_proxy<A,B,D> >
{
typedef shadow_proxy self;
public:
inline shadow_proxy(A aa, B bb) : a(aa), b(bb) { }
inline shadow_proxy(const self& x) : a(x.a), b(x.b) { }
template <class Self>
inline shadow_proxy(Self x) : a(x.a), b(x.b) { }
inline self& operator=(const self& x) { a = x.a; b = x.b; return *this; }
inline self& operator++() { ++a; return *this; }
inline self& operator--() { --a; return *this; }
inline self& operator+=(const self& x) { a += x.a; return *this; }
inline self& operator-=(const self& x) { a -= x.a; return *this; }
inline self& operator*=(const self& x) { a *= x.a; return *this; }
inline self& operator/=(const self& x) { a /= x.a; return *this; }
inline self& operator%=(const self& x) { return *this; } // JGS
inline self& operator&=(const self& x) { return *this; } // JGS
inline self& operator|=(const self& x) { return *this; } // JGS
inline self& operator^=(const self& x) { return *this; } // JGS
inline friend D operator-(const self& x, const self& y) {
return x.a - y.a;
}
inline bool operator==(const self& x) const { return a == x.a; }
inline bool operator<(const self& x) const { return a < x.a; }
// protected:
A a;
B b;
};
struct shadow_iterator_policies
{
template <typename iter_pair>
void initialize(const iter_pair&) { }
template <typename Iter>
typename Iter::reference dereference(const Iter& i) const {
typedef typename Iter::reference R;
return R(*i.base().first, *i.base().second);
}
template <typename Iter>
bool equal(const Iter& p1, const Iter& p2) const {
return p1.base().first == p2.base().first;
}
template <typename Iter>
void increment(Iter& i) { ++i.base().first; ++i.base().second; }
template <typename Iter>
void decrement(Iter& i) { --i.base().first; --i.base().second; }
template <typename Iter>
bool less(const Iter& x, const Iter& y) const {
return x.base().first < y.base().first;
}
template <typename Iter>
typename Iter::difference_type
distance(const Iter& x, const Iter& y) const {
return y.base().first - x.base().first;
}
template <typename D, typename Iter>
void advance(Iter& p, D n) { p.base().first += n; p.base().second += n; }
};
} // namespace detail
template <typename IterA, typename IterB>
struct shadow_iterator_generator {
// To use the iterator_adaptor we can't derive from
// random_access_iterator because we don't have a real reference.
// However, we want the STL algorithms to treat the shadow
// iterator like a random access iterator.
struct shadow_iterator_tag : public std::input_iterator_tag {
operator std::random_access_iterator_tag() {
return std::random_access_iterator_tag();
};
};
typedef typename std::iterator_traits<IterA>::value_type Aval;
typedef typename std::iterator_traits<IterB>::value_type Bval;
typedef typename std::iterator_traits<IterA>::reference Aref;
typedef typename std::iterator_traits<IterB>::reference Bref;
typedef typename std::iterator_traits<IterA>::difference_type D;
typedef detail::shadow_proxy<Aval,Bval,Aval> V;
typedef detail::shadow_proxy<Aref,Bref,Aval> R;
typedef iterator_adaptor< std::pair<IterA, IterB>,
detail::shadow_iterator_policies,
V, R, V*, shadow_iterator_tag,
D> type;
};
// short cut for creating a shadow iterator
template <class IterA, class IterB>
inline typename shadow_iterator_generator<IterA,IterB>::type
make_shadow_iter(IterA a, IterB b) {
typedef typename shadow_iterator_generator<IterA,IterB>::type Iter;
return Iter(std::make_pair(a,b));
}
template <class Cmp>
struct shadow_cmp {
inline shadow_cmp(const Cmp& c) : cmp(c) { }
template <class ShadowProxy1, class ShadowProxy2>
inline bool operator()(const ShadowProxy1& x, const ShadowProxy2& y) const
{
return cmp(x.a, y.a);
}
Cmp cmp;
};
} // namespace boost
namespace std {
template <class A1, class B1, class D1,
class A2, class B2, class D2>
void swap(boost::detail::shadow_proxy<A1&,B1&,D1> x,
boost::detail::shadow_proxy<A2&,B2&,D2> y)
{
std::swap(x.a, y.a);
std::swap(x.b, y.b);
}
}
#endif // BOOST_SHADOW_ITERATOR_HPP
@@ -0,0 +1,198 @@
//=======================================================================
// Copyright 1997, 1998, 1999, 2000 University of Notre Dame.
// Copyright 2004, 2005 Trustees of Indiana University
// Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek,
// Doug Gregor, D. Kevin McGrath
//
// 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_GRAPH_DETAIL_SPARSE_ORDERING_HPP
#define BOOST_GRAPH_DETAIL_SPARSE_ORDERING_HPP
#include <boost/config.hpp>
#include <vector>
#include <queue>
#include <boost/pending/queue.hpp>
#include <boost/pending/mutable_queue.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/breadth_first_search.hpp>
#include <boost/graph/properties.hpp>
#include <boost/pending/indirect_cmp.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/bind.hpp>
#include <boost/graph/iteration_macros.hpp>
#include <boost/graph/depth_first_search.hpp>
namespace boost {
namespace sparse {
// rcm_queue
//
// This is a custom queue type used in the
// *_ordering algorithms.
// In addition to the normal queue operations, the
// rcm_queue provides:
//
// int eccentricity() const;
// value_type spouse() const;
//
// yes, it's a bad name...but it works, so use it
template < class Vertex, class DegreeMap,
class Container = std::deque<Vertex> >
class rcm_queue : public std::queue<Vertex, Container> {
typedef std::queue<Vertex> base;
public:
typedef typename base::value_type value_type;
typedef typename base::size_type size_type;
/* SGI queue has not had a contructor queue(const Container&) */
inline rcm_queue(DegreeMap deg)
: _size(0), Qsize(1), eccen(-1), degree(deg) { }
inline void pop() {
if ( !_size )
Qsize = base::size();
base::pop();
if ( _size == Qsize-1 ) {
_size = 0;
++eccen;
} else
++_size;
}
inline value_type& front() {
value_type& u = base::front();
if ( _size == 0 )
w = u;
else if (get(degree,u) < get(degree,w) )
w = u;
return u;
}
inline const value_type& front() const {
const value_type& u = base::front();
if ( _size == 0 )
w = u;
else if (get(degree,u) < get(degree,w) )
w = u;
return u;
}
inline value_type& top() { return front(); }
inline const value_type& top() const { return front(); }
inline size_type size() const { return base::size(); }
inline size_type eccentricity() const { return eccen; }
inline value_type spouse() const { return w; }
protected:
size_type _size;
size_type Qsize;
int eccen;
mutable value_type w;
DegreeMap degree;
};
template <typename Tp, typename Sequence = std::deque<Tp> >
class sparse_ordering_queue : public boost::queue<Tp, Sequence>{
public:
typedef typename Sequence::iterator iterator;
typedef typename Sequence::reverse_iterator reverse_iterator;
typedef queue<Tp,Sequence> base;
typedef typename Sequence::size_type size_type;
inline iterator begin() { return this->c.begin(); }
inline reverse_iterator rbegin() { return this->c.rbegin(); }
inline iterator end() { return this->c.end(); }
inline reverse_iterator rend() { return this->c.rend(); }
inline Tp &operator[](int n) { return this->c[n]; }
inline size_type size() {return this->c.size(); }
protected:
//nothing
};
} // namespace sparse
// Compute Pseudo peripheral
//
// To compute an approximated peripheral for a given vertex.
// Used in <tt>king_ordering</tt> algorithm.
//
template <class Graph, class Vertex, class ColorMap, class DegreeMap>
Vertex
pseudo_peripheral_pair(Graph const& G, const Vertex& u, int& ecc,
ColorMap color, DegreeMap degree)
{
typedef typename property_traits<ColorMap>::value_type ColorValue;
typedef color_traits<ColorValue> Color;
sparse::rcm_queue<Vertex, DegreeMap> Q(degree);
typename boost::graph_traits<Graph>::vertex_iterator ui, ui_end;
for (boost::tie(ui, ui_end) = vertices(G); ui != ui_end; ++ui)
if (get(color, *ui) != Color::red()) put(color, *ui, Color::white());
breadth_first_visit(G, u, buffer(Q).color_map(color));
ecc = Q.eccentricity();
return Q.spouse();
}
// Find a good starting node
//
// This is to find a good starting node for the
// king_ordering algorithm. "good" is in the sense
// of the ordering generated by RCM.
//
template <class Graph, class Vertex, class Color, class Degree>
Vertex find_starting_node(Graph const& G, Vertex r, Color color, Degree degree)
{
Vertex x, y;
int eccen_r, eccen_x;
x = pseudo_peripheral_pair(G, r, eccen_r, color, degree);
y = pseudo_peripheral_pair(G, x, eccen_x, color, degree);
while (eccen_x > eccen_r) {
r = x;
eccen_r = eccen_x;
x = y;
y = pseudo_peripheral_pair(G, x, eccen_x, color, degree);
}
return x;
}
template <typename Graph>
class out_degree_property_map
: public put_get_helper<typename graph_traits<Graph>::degree_size_type,
out_degree_property_map<Graph> >
{
public:
typedef typename graph_traits<Graph>::vertex_descriptor key_type;
typedef typename graph_traits<Graph>::degree_size_type value_type;
typedef value_type reference;
typedef readable_property_map_tag category;
out_degree_property_map(const Graph& g) : m_g(g) { }
value_type operator[](const key_type& v) const {
return out_degree(v, m_g);
}
private:
const Graph& m_g;
};
template <typename Graph>
inline out_degree_property_map<Graph>
make_out_degree_map(const Graph& g) {
return out_degree_property_map<Graph>(g);
}
} // namespace boost
#endif // BOOST_GRAPH_KING_HPP
@@ -0,0 +1,490 @@
//=======================================================================
// 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)
//=======================================================================
//
//
// Revision History:
// 04 April 2001: Added named parameter variant. (Jeremy Siek)
// 01 April 2001: Modified to use new <boost/limits.hpp> header. (JMaddock)
//
#ifndef BOOST_GRAPH_DIJKSTRA_HPP
#define BOOST_GRAPH_DIJKSTRA_HPP
#include <functional>
#include <boost/limits.hpp>
#include <boost/graph/named_function_params.hpp>
#include <boost/graph/breadth_first_search.hpp>
#include <boost/graph/relax.hpp>
#include <boost/pending/indirect_cmp.hpp>
#include <boost/graph/exception.hpp>
#include <boost/pending/relaxed_heap.hpp>
#include <boost/graph/overloading.hpp>
#include <boost/smart_ptr.hpp>
#include <boost/graph/detail/d_ary_heap.hpp>
#include <boost/graph/two_bit_color_map.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/property_map/vector_property_map.hpp>
#include <boost/type_traits.hpp>
#include <boost/concept/assert.hpp>
#ifdef BOOST_GRAPH_DIJKSTRA_TESTING
# include <boost/pending/mutable_queue.hpp>
#endif // BOOST_GRAPH_DIJKSTRA_TESTING
namespace boost {
/**
* @brief Updates a particular value in a queue used by Dijkstra's
* algorithm.
*
* This routine is called by Dijkstra's algorithm after it has
* decreased the distance from the source vertex to the given @p
* vertex. By default, this routine will just call @c
* Q.update(vertex). However, other queues may provide more
* specialized versions of this routine.
*
* @param Q the queue that will be updated.
* @param vertex the vertex whose distance has been updated
* @param old_distance the previous distance to @p vertex
*/
template<typename Buffer, typename Vertex, typename DistanceType>
inline void
dijkstra_queue_update(Buffer& Q, Vertex vertex, DistanceType old_distance)
{
(void)old_distance;
Q.update(vertex);
}
#ifdef BOOST_GRAPH_DIJKSTRA_TESTING
// This is a misnomer now: it now just refers to the "default heap", which is
// currently d-ary (d=4) but can be changed by a #define.
static bool dijkstra_relaxed_heap = true;
#endif
template <class Visitor, class Graph>
struct DijkstraVisitorConcept {
void constraints() {
BOOST_CONCEPT_ASSERT(( CopyConstructibleConcept<Visitor> ));
vis.initialize_vertex(u, g);
vis.discover_vertex(u, g);
vis.examine_vertex(u, g);
vis.examine_edge(e, g);
vis.edge_relaxed(e, g);
vis.edge_not_relaxed(e, g);
vis.finish_vertex(u, g);
}
Visitor vis;
Graph g;
typename graph_traits<Graph>::vertex_descriptor u;
typename graph_traits<Graph>::edge_descriptor e;
};
template <class Visitors = null_visitor>
class dijkstra_visitor : public bfs_visitor<Visitors> {
public:
dijkstra_visitor() { }
dijkstra_visitor(Visitors vis)
: bfs_visitor<Visitors>(vis) { }
template <class Edge, class Graph>
void edge_relaxed(Edge e, Graph& g) {
invoke_visitors(this->m_vis, e, g, on_edge_relaxed());
}
template <class Edge, class Graph>
void edge_not_relaxed(Edge e, Graph& g) {
invoke_visitors(this->m_vis, e, g, on_edge_not_relaxed());
}
private:
template <class Edge, class Graph>
void tree_edge(Edge u, Graph& g) { }
};
template <class Visitors>
dijkstra_visitor<Visitors>
make_dijkstra_visitor(Visitors vis) {
return dijkstra_visitor<Visitors>(vis);
}
typedef dijkstra_visitor<> default_dijkstra_visitor;
namespace detail {
template <class UniformCostVisitor, class UpdatableQueue,
class WeightMap, class PredecessorMap, class DistanceMap,
class BinaryFunction, class BinaryPredicate>
struct dijkstra_bfs_visitor
{
typedef typename property_traits<DistanceMap>::value_type D;
dijkstra_bfs_visitor(UniformCostVisitor vis, UpdatableQueue& Q,
WeightMap w, PredecessorMap p, DistanceMap d,
BinaryFunction combine, BinaryPredicate compare,
D zero)
: m_vis(vis), m_Q(Q), m_weight(w), m_predecessor(p), m_distance(d),
m_combine(combine), m_compare(compare), m_zero(zero) { }
template <class Edge, class Graph>
void tree_edge(Edge e, Graph& g) {
bool decreased = relax(e, g, m_weight, m_predecessor, m_distance,
m_combine, m_compare);
if (decreased)
m_vis.edge_relaxed(e, g);
else
m_vis.edge_not_relaxed(e, g);
}
template <class Edge, class Graph>
void gray_target(Edge e, Graph& g) {
D old_distance = get(m_distance, target(e, g));
bool decreased = relax(e, g, m_weight, m_predecessor, m_distance,
m_combine, m_compare);
if (decreased) {
dijkstra_queue_update(m_Q, target(e, g), old_distance);
m_vis.edge_relaxed(e, g);
} else
m_vis.edge_not_relaxed(e, g);
}
template <class Vertex, class Graph>
void initialize_vertex(Vertex u, Graph& g)
{ m_vis.initialize_vertex(u, g); }
template <class Edge, class Graph>
void non_tree_edge(Edge, Graph&) { }
template <class Vertex, class Graph>
void discover_vertex(Vertex u, Graph& g) { m_vis.discover_vertex(u, g); }
template <class Vertex, class Graph>
void examine_vertex(Vertex u, Graph& g) { m_vis.examine_vertex(u, g); }
template <class Edge, class Graph>
void examine_edge(Edge e, Graph& g) {
if (m_compare(get(m_weight, e), m_zero))
boost::throw_exception(negative_edge());
m_vis.examine_edge(e, g);
}
template <class Edge, class Graph>
void black_target(Edge, Graph&) { }
template <class Vertex, class Graph>
void finish_vertex(Vertex u, Graph& g) { m_vis.finish_vertex(u, g); }
UniformCostVisitor m_vis;
UpdatableQueue& m_Q;
WeightMap m_weight;
PredecessorMap m_predecessor;
DistanceMap m_distance;
BinaryFunction m_combine;
BinaryPredicate m_compare;
D m_zero;
};
} // namespace detail
namespace detail {
template <class Graph, class IndexMap, class Value, bool KnownNumVertices>
struct vertex_property_map_generator_helper {};
template <class Graph, class IndexMap, class Value>
struct vertex_property_map_generator_helper<Graph, IndexMap, Value, true> {
typedef boost::iterator_property_map<Value*, IndexMap> type;
static type build(const Graph& g, const IndexMap& index, boost::scoped_array<Value>& array_holder) {
array_holder.reset(new Value[num_vertices(g)]);
std::fill(array_holder.get(), array_holder.get() + num_vertices(g), Value());
return make_iterator_property_map(array_holder.get(), index);
}
};
template <class Graph, class IndexMap, class Value>
struct vertex_property_map_generator_helper<Graph, IndexMap, Value, false> {
typedef boost::vector_property_map<Value, IndexMap> type;
static type build(const Graph& g, const IndexMap& index, boost::scoped_array<Value>& array_holder) {
return boost::make_vector_property_map<Value>(index);
}
};
template <class Graph, class IndexMap, class Value>
struct vertex_property_map_generator {
typedef boost::is_base_and_derived<
boost::vertex_list_graph_tag,
typename boost::graph_traits<Graph>::traversal_category>
known_num_vertices;
typedef vertex_property_map_generator_helper<Graph, IndexMap, Value, known_num_vertices::value> helper;
typedef typename helper::type type;
static type build(const Graph& g, const IndexMap& index, boost::scoped_array<Value>& array_holder) {
return helper::build(g, index, array_holder);
}
};
}
namespace detail {
template <class Graph, class IndexMap, bool KnownNumVertices>
struct default_color_map_generator_helper {};
template <class Graph, class IndexMap>
struct default_color_map_generator_helper<Graph, IndexMap, true> {
typedef boost::two_bit_color_map<IndexMap> type;
static type build(const Graph& g, const IndexMap& index) {
size_t nv = num_vertices(g);
return boost::two_bit_color_map<IndexMap>(nv, index);
}
};
template <class Graph, class IndexMap>
struct default_color_map_generator_helper<Graph, IndexMap, false> {
typedef boost::vector_property_map<boost::two_bit_color_type, IndexMap> type;
static type build(const Graph& g, const IndexMap& index) {
return boost::make_vector_property_map<boost::two_bit_color_type>(index);
}
};
template <class Graph, class IndexMap>
struct default_color_map_generator {
typedef boost::is_base_and_derived<
boost::vertex_list_graph_tag,
typename boost::graph_traits<Graph>::traversal_category>
known_num_vertices;
typedef default_color_map_generator_helper<Graph, IndexMap, known_num_vertices::value> helper;
typedef typename helper::type type;
static type build(const Graph& g, const IndexMap& index) {
return helper::build(g, index);
}
};
}
// Call breadth first search with default color map.
template <class Graph, class DijkstraVisitor,
class PredecessorMap, class DistanceMap,
class WeightMap, class IndexMap, class Compare, class Combine,
class DistZero>
inline void
dijkstra_shortest_paths_no_init
(const Graph& g,
typename graph_traits<Graph>::vertex_descriptor s,
PredecessorMap predecessor, DistanceMap distance, WeightMap weight,
IndexMap index_map,
Compare compare, Combine combine, DistZero zero,
DijkstraVisitor vis)
{
typedef
detail::default_color_map_generator<Graph, IndexMap>
ColorMapHelper;
typedef typename ColorMapHelper::type ColorMap;
ColorMap color =
ColorMapHelper::build(g, index_map);
dijkstra_shortest_paths_no_init( g, s, predecessor, distance, weight,
index_map, compare, combine, zero, vis,
color);
}
// Call breadth first search
template <class Graph, class DijkstraVisitor,
class PredecessorMap, class DistanceMap,
class WeightMap, class IndexMap, class Compare, class Combine,
class DistZero, class ColorMap>
inline void
dijkstra_shortest_paths_no_init
(const Graph& g,
typename graph_traits<Graph>::vertex_descriptor s,
PredecessorMap predecessor, DistanceMap distance, WeightMap weight,
IndexMap index_map,
Compare compare, Combine combine, DistZero zero,
DijkstraVisitor vis, ColorMap color)
{
typedef indirect_cmp<DistanceMap, Compare> IndirectCmp;
IndirectCmp icmp(distance, compare);
typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
#ifdef BOOST_GRAPH_DIJKSTRA_TESTING
if (!dijkstra_relaxed_heap) {
typedef mutable_queue<Vertex, std::vector<Vertex>, IndirectCmp, IndexMap>
MutableQueue;
MutableQueue Q(num_vertices(g), icmp, index_map);
detail::dijkstra_bfs_visitor<DijkstraVisitor, MutableQueue, WeightMap,
PredecessorMap, DistanceMap, Combine, Compare>
bfs_vis(vis, Q, weight, predecessor, distance, combine, compare, zero);
breadth_first_visit(g, s, Q, bfs_vis, color);
return;
}
#endif // BOOST_GRAPH_DIJKSTRA_TESTING
#ifdef BOOST_GRAPH_DIJKSTRA_USE_RELAXED_HEAP
typedef relaxed_heap<Vertex, IndirectCmp, IndexMap> MutableQueue;
MutableQueue Q(num_vertices(g), icmp, index_map);
#else // Now the default: use a d-ary heap
boost::scoped_array<std::size_t> index_in_heap_map_holder;
typedef
detail::vertex_property_map_generator<Graph, IndexMap, std::size_t>
IndexInHeapMapHelper;
typedef typename IndexInHeapMapHelper::type IndexInHeapMap;
IndexInHeapMap index_in_heap =
IndexInHeapMapHelper::build(g, index_map, index_in_heap_map_holder);
typedef d_ary_heap_indirect<Vertex, 4, IndexInHeapMap, DistanceMap, Compare>
MutableQueue;
MutableQueue Q(distance, index_in_heap, compare);
#endif // Relaxed heap
detail::dijkstra_bfs_visitor<DijkstraVisitor, MutableQueue, WeightMap,
PredecessorMap, DistanceMap, Combine, Compare>
bfs_vis(vis, Q, weight, predecessor, distance, combine, compare, zero);
breadth_first_visit(g, s, Q, bfs_vis, color);
}
// Initialize distances and call breadth first search with default color map
template <class VertexListGraph, class DijkstraVisitor,
class PredecessorMap, class DistanceMap,
class WeightMap, class IndexMap, class Compare, class Combine,
class DistInf, class DistZero, typename T, typename Tag,
typename Base>
inline void
dijkstra_shortest_paths
(const VertexListGraph& g,
typename graph_traits<VertexListGraph>::vertex_descriptor s,
PredecessorMap predecessor, DistanceMap distance, WeightMap weight,
IndexMap index_map,
Compare compare, Combine combine, DistInf inf, DistZero zero,
DijkstraVisitor vis,
const bgl_named_params<T, Tag, Base>&
BOOST_GRAPH_ENABLE_IF_MODELS_PARM(VertexListGraph,vertex_list_graph_tag))
{
boost::two_bit_color_map<IndexMap> color(num_vertices(g), index_map);
dijkstra_shortest_paths(g, s, predecessor, distance, weight, index_map,
compare, combine, inf, zero, vis,
color);
}
// Initialize distances and call breadth first search
template <class VertexListGraph, class DijkstraVisitor,
class PredecessorMap, class DistanceMap,
class WeightMap, class IndexMap, class Compare, class Combine,
class DistInf, class DistZero, class ColorMap>
inline void
dijkstra_shortest_paths
(const VertexListGraph& g,
typename graph_traits<VertexListGraph>::vertex_descriptor s,
PredecessorMap predecessor, DistanceMap distance, WeightMap weight,
IndexMap index_map,
Compare compare, Combine combine, DistInf inf, DistZero zero,
DijkstraVisitor vis, ColorMap color)
{
typedef typename property_traits<ColorMap>::value_type ColorValue;
typedef color_traits<ColorValue> Color;
typename graph_traits<VertexListGraph>::vertex_iterator ui, ui_end;
for (boost::tie(ui, ui_end) = vertices(g); ui != ui_end; ++ui) {
vis.initialize_vertex(*ui, g);
put(distance, *ui, inf);
put(predecessor, *ui, *ui);
put(color, *ui, Color::white());
}
put(distance, s, zero);
dijkstra_shortest_paths_no_init(g, s, predecessor, distance, weight,
index_map, compare, combine, zero, vis, color);
}
// Initialize distances and call breadth first search
template <class VertexListGraph, class DijkstraVisitor,
class PredecessorMap, class DistanceMap,
class WeightMap, class IndexMap, class Compare, class Combine,
class DistInf, class DistZero>
inline void
dijkstra_shortest_paths
(const VertexListGraph& g,
typename graph_traits<VertexListGraph>::vertex_descriptor s,
PredecessorMap predecessor, DistanceMap distance, WeightMap weight,
IndexMap index_map,
Compare compare, Combine combine, DistInf inf, DistZero zero,
DijkstraVisitor vis)
{
dijkstra_shortest_paths(g, s, predecessor, distance, weight, index_map,
compare, combine, inf, zero, vis,
no_named_parameters());
}
namespace detail {
// Handle defaults for PredecessorMap and
// Distance Compare, Combine, Inf and Zero
template <class VertexListGraph, class DistanceMap, class WeightMap,
class IndexMap, class Params>
inline void
dijkstra_dispatch2
(const VertexListGraph& g,
typename graph_traits<VertexListGraph>::vertex_descriptor s,
DistanceMap distance, WeightMap weight, IndexMap index_map,
const Params& params)
{
// Default for predecessor map
dummy_property_map p_map;
typedef typename property_traits<DistanceMap>::value_type D;
D inf = choose_param(get_param(params, distance_inf_t()),
(std::numeric_limits<D>::max)());
dijkstra_shortest_paths
(g, s,
choose_param(get_param(params, vertex_predecessor), p_map),
distance, weight, index_map,
choose_param(get_param(params, distance_compare_t()),
std::less<D>()),
choose_param(get_param(params, distance_combine_t()),
closed_plus<D>(inf)),
inf,
choose_param(get_param(params, distance_zero_t()),
D()),
choose_param(get_param(params, graph_visitor),
make_dijkstra_visitor(null_visitor())),
params);
}
template <class VertexListGraph, class DistanceMap, class WeightMap,
class IndexMap, class Params>
inline void
dijkstra_dispatch1
(const VertexListGraph& g,
typename graph_traits<VertexListGraph>::vertex_descriptor s,
DistanceMap distance, WeightMap weight, IndexMap index_map,
const Params& params)
{
// Default for distance map
typedef typename property_traits<WeightMap>::value_type D;
typename std::vector<D>::size_type
n = is_default_param(distance) ? num_vertices(g) : 1;
std::vector<D> distance_map(n);
detail::dijkstra_dispatch2
(g, s, choose_param(distance, make_iterator_property_map
(distance_map.begin(), index_map,
distance_map[0])),
weight, index_map, params);
}
} // namespace detail
// Named Parameter Variant
template <class VertexListGraph, class Param, class Tag, class Rest>
inline void
dijkstra_shortest_paths
(const VertexListGraph& g,
typename graph_traits<VertexListGraph>::vertex_descriptor s,
const bgl_named_params<Param,Tag,Rest>& params)
{
// Default for edge weight and vertex index map is to ask for them
// from the graph. Default for the visitor is null_visitor.
detail::dijkstra_dispatch1
(g, s,
get_param(params, vertex_distance),
choose_const_pmap(get_param(params, edge_weight), g, edge_weight),
choose_const_pmap(get_param(params, vertex_index), g, vertex_index),
params);
}
} // namespace boost
#ifdef BOOST_GRAPH_USE_MPI
# include <boost/graph/distributed/dijkstra_shortest_paths.hpp>
#endif
#endif // BOOST_GRAPH_DIJKSTRA_HPP
@@ -0,0 +1,252 @@
//=======================================================================
// Copyright 1997, 1998, 1999, 2000 University of Notre Dame.
// Copyright 2009 Trustees of Indiana University.
// Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek, Michael Hansen
//
// 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_GRAPH_DIJKSTRA_NO_COLOR_MAP_HPP
#define BOOST_GRAPH_DIJKSTRA_NO_COLOR_MAP_HPP
#include <boost/pending/indirect_cmp.hpp>
#include <boost/graph/relax.hpp>
#include <boost/pending/relaxed_heap.hpp>
#include <boost/graph/detail/d_ary_heap.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <boost/graph/iteration_macros.hpp>
namespace boost {
// No init version
template <typename Graph, typename DijkstraVisitor,
typename PredecessorMap, typename DistanceMap,
typename WeightMap, typename VertexIndexMap,
typename DistanceCompare, typename DistanceWeightCombine,
typename DistanceInfinity, typename DistanceZero>
void dijkstra_shortest_paths_no_color_map_no_init
(const Graph& graph,
typename graph_traits<Graph>::vertex_descriptor start_vertex,
PredecessorMap predecessor_map,
DistanceMap distance_map,
WeightMap weight_map,
VertexIndexMap index_map,
DistanceCompare distance_compare,
DistanceWeightCombine distance_weight_combine,
DistanceInfinity distance_infinity,
DistanceZero distance_zero,
DijkstraVisitor visitor)
{
typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
typedef typename property_traits<DistanceMap>::value_type Distance;
typedef typename property_traits<WeightMap>::value_type Weight;
typedef indirect_cmp<DistanceMap, DistanceCompare> DistanceIndirectCompare;
DistanceIndirectCompare
distance_indirect_compare(distance_map, distance_compare);
// Choose vertex queue type
#if BOOST_GRAPH_DIJKSTRA_USE_RELAXED_HEAP
typedef relaxed_heap<Vertex, DistanceIndirectCompare, VertexIndexMap>
VertexQueue;
VertexQueue vertex_queue(num_vertices(graph),
distance_indirect_compare,
index_map);
#else
// Default - use d-ary heap (d = 4)
typedef
detail::vertex_property_map_generator<Graph, VertexIndexMap, std::size_t>
IndexInHeapMapHelper;
typedef typename IndexInHeapMapHelper::type IndexInHeapMap;
typedef
d_ary_heap_indirect<Vertex, 4, IndexInHeapMap, DistanceMap, DistanceCompare>
VertexQueue;
boost::scoped_array<std::size_t> index_in_heap_map_holder;
IndexInHeapMap index_in_heap =
IndexInHeapMapHelper::build(graph, index_map,
index_in_heap_map_holder);
VertexQueue vertex_queue(distance_map, index_in_heap, distance_compare);
#endif
// Add vertex to the queue
vertex_queue.push(start_vertex);
// Starting vertex will always be the first discovered vertex
visitor.discover_vertex(start_vertex, graph);
while (!vertex_queue.empty()) {
Vertex min_vertex = vertex_queue.top();
vertex_queue.pop();
visitor.examine_vertex(min_vertex, graph);
// Check if any other vertices can be reached
Distance min_vertex_distance = get(distance_map, min_vertex);
if (!distance_compare(min_vertex_distance, distance_infinity)) {
// This is the minimum vertex, so all other vertices are unreachable
return;
}
// Examine neighbors of min_vertex
typedef typename graph_traits<Graph>::edge_descriptor Edge;
BGL_FORALL_OUTEDGES_T(min_vertex, current_edge, graph, Graph) {
visitor.examine_edge(current_edge, graph);
// Check if the edge has a negative weight
if (distance_compare(get(weight_map, current_edge), distance_zero)) {
boost::throw_exception(negative_edge());
}
// Extract the neighboring vertex and get its distance
Vertex neighbor_vertex = target(current_edge, graph);
Distance neighbor_vertex_distance = get(distance_map, neighbor_vertex);
bool is_neighbor_undiscovered =
!distance_compare(neighbor_vertex_distance, distance_infinity);
// Attempt to relax the edge
bool was_edge_relaxed = relax(current_edge, graph, weight_map,
predecessor_map, distance_map,
distance_weight_combine, distance_compare);
if (was_edge_relaxed) {
visitor.edge_relaxed(current_edge, graph);
if (is_neighbor_undiscovered) {
visitor.discover_vertex(neighbor_vertex, graph);
vertex_queue.push(neighbor_vertex);
} else {
vertex_queue.update(neighbor_vertex);
}
} else {
visitor.edge_not_relaxed(current_edge, graph);
}
} // end out edge iteration
visitor.finish_vertex(min_vertex, graph);
} // end while queue not empty
}
// Full init version
template <typename Graph, typename DijkstraVisitor,
typename PredecessorMap, typename DistanceMap,
typename WeightMap, typename VertexIndexMap,
typename DistanceCompare, typename DistanceWeightCombine,
typename DistanceInfinity, typename DistanceZero>
void dijkstra_shortest_paths_no_color_map
(const Graph& graph,
typename graph_traits<Graph>::vertex_descriptor start_vertex,
PredecessorMap predecessor_map,
DistanceMap distance_map,
WeightMap weight_map,
VertexIndexMap index_map,
DistanceCompare distance_compare,
DistanceWeightCombine distance_weight_combine,
DistanceInfinity distance_infinity,
DistanceZero distance_zero,
DijkstraVisitor visitor)
{
// Initialize vertices
BGL_FORALL_VERTICES_T(current_vertex, graph, Graph) {
visitor.initialize_vertex(current_vertex, graph);
// Default all distances to infinity
put(distance_map, current_vertex, distance_infinity);
// Default all vertex predecessors to the vertex itself
put(predecessor_map, current_vertex, current_vertex);
}
// Set distance for start_vertex to zero
put(distance_map, start_vertex, distance_zero);
// Pass everything on to the no_init version
dijkstra_shortest_paths_no_color_map_no_init(graph,
start_vertex, predecessor_map, distance_map, weight_map,
index_map, distance_compare, distance_weight_combine,
distance_infinity, distance_zero, visitor);
}
namespace detail {
// Handle defaults for PredecessorMap, DistanceCompare,
// DistanceWeightCombine, DistanceInfinity and DistanceZero
template <typename Graph, typename DistanceMap, typename WeightMap,
typename VertexIndexMap, typename Params>
inline void
dijkstra_no_color_map_dispatch2
(const Graph& graph,
typename graph_traits<Graph>::vertex_descriptor start_vertex,
DistanceMap distance_map, WeightMap weight_map,
VertexIndexMap index_map, const Params& params)
{
// Default for predecessor map
dummy_property_map predecessor_map;
typedef typename property_traits<DistanceMap>::value_type DistanceType;
DistanceType inf =
choose_param(get_param(params, distance_inf_t()),
(std::numeric_limits<DistanceType>::max)());
dijkstra_shortest_paths_no_color_map
(graph, start_vertex,
choose_param(get_param(params, vertex_predecessor), predecessor_map),
distance_map, weight_map, index_map,
choose_param(get_param(params, distance_compare_t()),
std::less<DistanceType>()),
choose_param(get_param(params, distance_combine_t()),
closed_plus<DistanceType>(inf)),
inf,
choose_param(get_param(params, distance_zero_t()),
DistanceType()),
choose_param(get_param(params, graph_visitor),
make_dijkstra_visitor(null_visitor())));
}
template <typename Graph, typename DistanceMap, typename WeightMap,
typename IndexMap, typename Params>
inline void
dijkstra_no_color_map_dispatch1
(const Graph& graph,
typename graph_traits<Graph>::vertex_descriptor start_vertex,
DistanceMap distance_map, WeightMap weight_map,
IndexMap index_map, const Params& params)
{
// Default for distance map
typedef typename property_traits<WeightMap>::value_type DistanceType;
typename std::vector<DistanceType>::size_type
vertex_count = is_default_param(distance_map) ? num_vertices(graph) : 1;
std::vector<DistanceType> default_distance_map(vertex_count);
detail::dijkstra_no_color_map_dispatch2
(graph, start_vertex, choose_param(distance_map,
make_iterator_property_map(default_distance_map.begin(), index_map,
default_distance_map[0])),
weight_map, index_map, params);
}
} // namespace detail
// Named parameter version
template <typename Graph, typename Param, typename Tag, typename Rest>
inline void
dijkstra_shortest_paths_no_color_map
(const Graph& graph,
typename graph_traits<Graph>::vertex_descriptor start_vertex,
const bgl_named_params<Param, Tag, Rest>& params)
{
// Default for edge weight and vertex index map is to ask for them
// from the graph. Default for the visitor is null_visitor.
detail::dijkstra_no_color_map_dispatch1
(graph, start_vertex,
get_param(params, vertex_distance),
choose_const_pmap(get_param(params, edge_weight), graph, edge_weight),
choose_const_pmap(get_param(params, vertex_index), graph, vertex_index),
params);
}
} // namespace boost
#endif // BOOST_GRAPH_DIJKSTRA_NO_COLOR_MAP_HPP
@@ -0,0 +1,310 @@
// Copyright 2005 The Trustees of Indiana University.
// Use, modification and distribution is subject to 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)
// Authors: Alex Breuer
// Andrew Lumsdaine
#ifndef BOOST_GRAPH_DIMACS_HPP
#define BOOST_GRAPH_DIMACS_HPP
#include <string>
#include <sstream>
#include <iostream>
#include <fstream>
#include <iterator>
#include <exception>
#include <vector>
#include <queue>
#include <boost/assert.hpp>
namespace boost { namespace graph {
class dimacs_exception : public std::exception {};
class dimacs_basic_reader {
public:
typedef std::size_t vertices_size_type;
typedef std::size_t edges_size_type;
typedef double vertex_weight_type;
typedef double edge_weight_type;
typedef std::pair<vertices_size_type,
vertices_size_type> edge_type;
enum incr_mode {edge, edge_weight};
dimacs_basic_reader( std::istream& in, bool want_weights = true ) :
inpt( in ), seen_edges( 0 ), want_weights(want_weights)
{
while( getline( inpt, buf ) && !buf.empty() && buf[0] == 'c' );
if( buf[0] != 'p' ) {
boost::throw_exception(dimacs_exception());
}
std::stringstream instr( buf );
std::string junk;
instr >> junk >> junk >> num_vertices >> num_edges;
read_edge_weights.push( -1 );
incr( edge_weight );
}
//for a past the end iterator
dimacs_basic_reader() : inpt( std::cin ), num_vertices( 0 ),
num_edges( 0 ), seen_edges( 0 ), want_weights(false) {}
edge_type edge_deref() {
BOOST_ASSERT( !read_edges.empty() );
return read_edges.front();
}
inline edge_type* edge_ref() {
BOOST_ASSERT( !read_edges.empty() );
return &read_edges.front();
}
inline edge_weight_type edge_weight_deref() {
BOOST_ASSERT( !read_edge_weights.empty() );
return read_edge_weights.front();
}
inline dimacs_basic_reader incr( incr_mode mode ) {
if( mode == edge ) {
BOOST_ASSERT( !read_edges.empty() );
read_edges.pop();
}
else if( mode == edge_weight ) {
BOOST_ASSERT( !read_edge_weights.empty() );
read_edge_weights.pop();
}
if( (mode == edge && read_edges.empty()) ||
(mode == edge_weight && read_edge_weights.empty() )) {
if( seen_edges > num_edges ) {
boost::throw_exception(dimacs_exception());
}
while( getline( inpt, buf ) && !buf.empty() && buf[0] == 'c' );
if( !inpt.eof() ) {
int source, dest, weight;
read_edge_line((char*) buf.c_str(), source, dest, weight);
seen_edges++;
source--;
dest--;
read_edges.push( edge_type( source, dest ) );
if (want_weights) {
read_edge_weights.push( weight );
}
}
BOOST_ASSERT( read_edges.size() < 100 );
BOOST_ASSERT( read_edge_weights.size() < 100 );
}
// the 1000000 just happens to be about how many edges can be read in
// 10s
// if( !(seen_edges % 1000000) && !process_id( pg ) && mode == edge ) {
// std::cout << "read " << seen_edges << " edges" << std::endl;
// }
return *this;
}
inline bool done_edges() {
return inpt.eof() && read_edges.size() == 0;
}
inline bool done_edge_weights() {
return inpt.eof() && read_edge_weights.size() == 0;
}
inline vertices_size_type n_vertices() {
return num_vertices;
}
inline vertices_size_type processed_edges() {
return seen_edges - read_edges.size();
}
inline vertices_size_type processed_edge_weights() {
return seen_edges - read_edge_weights.size();
}
inline vertices_size_type n_edges() {
return num_edges;
}
protected:
bool read_edge_line(char *linebuf, int &from, int &to, int &weight)
{
char *fs = NULL, *ts = NULL, *ws = NULL;
char *tmp = linebuf + 2;
fs = tmp;
if ('e' == linebuf[0]) {
while (*tmp != '\n' && *tmp != '\0') {
if (*tmp == ' ') {
*tmp = '\0';
ts = ++tmp;
break;
}
tmp++;
}
*tmp = '\0';
if (NULL == fs || NULL == ts) return false;
from = atoi(fs); to = atoi(ts); weight = 0;
} else if ('a' == linebuf[0]) {
while (*tmp != '\n' && *tmp != '\0') {
if (*tmp == ' ') {
*tmp = '\0';
ts = ++tmp;
break;
}
tmp++;
}
while (*tmp != '\n' && *tmp != '\0') {
if (*tmp == ' ') {
*tmp = '\0';
ws = ++tmp;
break;
}
tmp++;
}
while (*tmp != '\n' && *tmp != '\0') tmp++;
*tmp = '\0';
if (fs == NULL || ts == NULL || ws == NULL) return false;
from = atoi(fs); to = atoi(ts) ;
if (want_weights) weight = atoi(ws); else weight = 0;
} else {
return false;
}
return true;
}
std::queue<edge_type> read_edges;
std::queue<edge_weight_type> read_edge_weights;
std::istream& inpt;
std::string buf;
vertices_size_type num_vertices, num_edges, seen_edges;
bool want_weights;
};
template<typename T>
class dimacs_edge_iterator {
public:
typedef dimacs_basic_reader::edge_type edge_type;
typedef dimacs_basic_reader::incr_mode incr_mode;
typedef std::input_iterator_tag iterator_category;
typedef edge_type value_type;
typedef value_type reference;
typedef edge_type* pointer;
typedef std::ptrdiff_t difference_type;
dimacs_edge_iterator( T& reader ) :
reader( reader ) {}
inline dimacs_edge_iterator& operator++() {
reader.incr( dimacs_basic_reader::edge );
return *this;
}
inline edge_type operator*() {
return reader.edge_deref();
}
inline edge_type* operator->() {
return reader.edge_ref();
}
// don't expect this to do the right thing if you're not comparing against a
// general past-the-end-iterator made with the default constructor for
// dimacs_basic_reader
inline bool operator==( dimacs_edge_iterator arg ) {
if( reader.n_vertices() == 0 ) {
return arg.reader.done_edges();
}
else if( arg.reader.n_vertices() == 0 ) {
return reader.done_edges();
}
else {
return false;
}
return false;
}
inline bool operator!=( dimacs_edge_iterator arg ) {
if( reader.n_vertices() == 0 ) {
return !arg.reader.done_edges();
}
else if( arg.reader.n_vertices() == 0 ) {
return !reader.done_edges();
}
else {
return true;
}
return true;
}
private:
T& reader;
};
template<typename T>
class dimacs_edge_weight_iterator {
public:
typedef dimacs_basic_reader::edge_weight_type edge_weight_type;
typedef dimacs_basic_reader::incr_mode incr_mode;
dimacs_edge_weight_iterator( T& reader ) : reader( reader ) {}
inline dimacs_edge_weight_iterator& operator++() {
reader.incr( dimacs_basic_reader::edge_weight );
return *this;
}
inline edge_weight_type operator*() {
return reader.edge_weight_deref();
}
// don't expect this to do the right thing if you're not comparing against a
// general past-the-end-iterator made with the default constructor for
// dimacs_basic_reader
inline bool operator==( dimacs_edge_weight_iterator arg ) {
if( reader.n_vertices() == 0 ) {
return arg.reader.done_edge_weights();
}
else if( arg.reader.n_vertices() == 0 ) {
return reader.done_edge_weights();
}
else {
return false;
}
return false;
}
inline bool operator!=( dimacs_edge_weight_iterator arg ) {
if( reader.n_vertices() == 0 ) {
return !arg.reader.done_edge_weights();
}
else if( arg.reader.n_vertices() == 0 ) {
return !reader.done_edge_weights();
}
else {
return true;
}
return true;
}
private:
T& reader;
};
} } // end namespace boost::graph
#endif
@@ -0,0 +1,701 @@
// (C) Copyright 2007-2009 Andrew Sutton
//
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0 (See accompanying file
// LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GRAPH_DIRECTED_GRAPH_HPP
#define BOOST_GRAPH_DIRECTED_GRAPH_HPP
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/properties.hpp>
#include <boost/pending/property.hpp>
#include <boost/property_map/transform_value_property_map.hpp>
#include <boost/type_traits.hpp>
#include <boost/mpl/if.hpp>
namespace boost
{
struct directed_graph_tag { };
/**
* The directed_graph class template is a simplified version of the BGL
* adjacency list. This class is provided for ease of use, but may not
* perform as well as custom-defined adjacency list classes. Instances of
* this template model the BidirectionalGraph, VertexIndexGraph, and
* EdgeIndexGraph concepts. The graph is also fully mutable, supporting
* both insertions and removals of vertices and edges.
*
* @note Special care must be taken when removing vertices or edges since
* those operations can invalidate the numbering of vertices.
*/
template <
typename VertexProp = no_property,
typename EdgeProp = no_property,
typename GraphProp = no_property>
class directed_graph
{
public:
typedef GraphProp graph_property_type;
typedef VertexProp vertex_property_type;
typedef EdgeProp edge_property_type;
typedef typename lookup_one_property<GraphProp, graph_bundle_t>::type graph_bundled;
typedef typename lookup_one_property<VertexProp, vertex_bundle_t>::type vertex_bundled;
typedef typename lookup_one_property<EdgeProp, edge_bundle_t>::type edge_bundled;
public:
// Embed indices into the vertex type.
typedef property<vertex_index_t, unsigned, vertex_property_type> internal_vertex_property;
typedef property<edge_index_t, unsigned, edge_property_type> internal_edge_property;
public:
typedef adjacency_list<
listS, listS, bidirectionalS,
internal_vertex_property, internal_edge_property, GraphProp,
listS
> graph_type;
private:
// storage selectors
typedef typename graph_type::vertex_list_selector vertex_list_selector;
typedef typename graph_type::edge_list_selector edge_list_selector;
typedef typename graph_type::out_edge_list_selector out_edge_list_selector;
typedef typename graph_type::directed_selector directed_selector;
public:
// more commonly used graph types
typedef typename graph_type::stored_vertex stored_vertex;
typedef typename graph_type::vertices_size_type vertices_size_type;
typedef typename graph_type::edges_size_type edges_size_type;
typedef typename graph_type::degree_size_type degree_size_type;
typedef typename graph_type::vertex_descriptor vertex_descriptor;
typedef typename graph_type::edge_descriptor edge_descriptor;
// iterator types
typedef typename graph_type::vertex_iterator vertex_iterator;
typedef typename graph_type::edge_iterator edge_iterator;
typedef typename graph_type::out_edge_iterator out_edge_iterator;
typedef typename graph_type::in_edge_iterator in_edge_iterator;
typedef typename graph_type::adjacency_iterator adjacency_iterator;
// miscellaneous types
typedef directed_graph_tag graph_tag;
typedef typename graph_type::directed_category directed_category;
typedef typename graph_type::edge_parallel_category edge_parallel_category;
typedef typename graph_type::traversal_category traversal_category;
typedef std::size_t vertex_index_type;
typedef std::size_t edge_index_type;
directed_graph(GraphProp const& p = GraphProp())
: m_graph(p), m_num_vertices(0), m_num_edges(0), m_max_vertex_index(0)
, m_max_edge_index(0)
{ }
directed_graph(directed_graph const& x)
: m_graph(x), m_num_vertices(x.m_num_vertices), m_num_edges(x.m_num_edges)
, m_max_vertex_index(x.m_max_vertex_index), m_max_edge_index(x.m_max_edge_index)
{ }
directed_graph(vertices_size_type n, GraphProp const& p = GraphProp())
: m_graph(n, p), m_num_vertices(n), m_num_edges(0), m_max_vertex_index(n)
, m_max_edge_index(0)
{ renumber_vertex_indices(); }
template <typename EdgeIterator>
directed_graph(EdgeIterator f,
EdgeIterator l,
vertices_size_type n,
edges_size_type m = 0,
GraphProp const& p = GraphProp())
: m_graph(f, l, n, m, p), m_num_vertices(n), m_num_edges(0)
, m_max_vertex_index(n), m_max_edge_index(0)
{
// Unfortunately, we have to renumber the entire graph.
renumber_indices();
// Can't always guarantee that the number of edges is actually
// m if distance(f, l) != m (or is undefined).
m_num_edges = m_max_edge_index = boost::num_edges(m_graph);
}
directed_graph& operator=(directed_graph const& g) {
if(&g != this) {
m_graph = g.m_graph;
m_num_vertices = g.m_num_vertices;
m_num_edges = g.m_num_edges;
m_max_vertex_index = g.m_max_vertex_index;
m_max_edge_index = g.m_max_edge_index;
}
return *this;
}
// The impl_() methods are not part of the public interface.
graph_type& impl()
{ return m_graph; }
graph_type const& impl() const
{ return m_graph; }
// The following methods are not part of the public interface
vertices_size_type num_vertices() const
{ return m_num_vertices; }
private:
// This helper function manages the attribution of vertex indices.
vertex_descriptor make_index(vertex_descriptor v) {
boost::put(vertex_index, m_graph, v, m_max_vertex_index);
m_num_vertices++;
m_max_vertex_index++;
return v;
}
public:
vertex_descriptor add_vertex()
{ return make_index(boost::add_vertex(m_graph)); }
vertex_descriptor add_vertex(vertex_property_type const& p)
{ return make_index(boost::add_vertex(internal_vertex_property(0u, p), m_graph)); }
void clear_vertex(vertex_descriptor v)
{
m_num_edges -= boost::degree(v, m_graph);
boost::clear_vertex(v, m_graph);
}
void remove_vertex(vertex_descriptor v)
{
boost::remove_vertex(v, m_graph);
--m_num_vertices;
}
edges_size_type num_edges() const
{ return m_num_edges; }
private:
// A helper fucntion for managing edge index attributes.
std::pair<edge_descriptor, bool> const&
make_index(std::pair<edge_descriptor, bool> const& x)
{
if(x.second) {
boost::put(edge_index, m_graph, x.first, m_max_edge_index);
++m_num_edges;
++m_max_edge_index;
}
return x;
}
public:
std::pair<edge_descriptor, bool>
add_edge(vertex_descriptor u, vertex_descriptor v)
{ return make_index(boost::add_edge(u, v, m_graph)); }
std::pair<edge_descriptor, bool>
add_edge(vertex_descriptor u, vertex_descriptor v, edge_property_type const& p)
{ return make_index(boost::add_edge(u, v, internal_edge_property(0u, p), m_graph)); }
void remove_edge(vertex_descriptor u, vertex_descriptor v)
{
// find all edges, (u, v)
std::vector<edge_descriptor> edges;
out_edge_iterator i, i_end;
for(boost::tie(i, i_end) = boost::out_edges(u, m_graph); i != i_end; ++i) {
if(boost::target(*i, m_graph) == v) {
edges.push_back(*i);
}
}
// remove all edges, (u, v)
typename std::vector<edge_descriptor>::iterator
j = edges.begin(), j_end = edges.end();
for( ; j != j_end; ++j) {
remove_edge(*j);
}
}
void remove_edge(edge_iterator i)
{
remove_edge(*i);
}
void remove_edge(edge_descriptor e)
{
boost::remove_edge(e, m_graph);
--m_num_edges;
}
vertex_index_type max_vertex_index() const
{ return m_max_vertex_index; }
void
renumber_vertex_indices()
{
vertex_iterator i, end;
boost::tie(i, end) = vertices(m_graph);
m_max_vertex_index = renumber_vertex_indices(i, end, 0);
}
void
remove_vertex_and_renumber_indices(vertex_iterator i)
{
vertex_iterator j = next(i), end = vertices(m_graph).second;
vertex_index_type n = get(vertex_index, m_graph, *i);
// remove the offending vertex and renumber everything after
remove_vertex(*i);
m_max_vertex_index = renumber_vertex_indices(j, end, n);
}
edge_index_type
max_edge_index() const
{ return m_max_edge_index; }
void
renumber_edge_indices()
{
edge_iterator i, end;
boost::tie(i, end) = edges(m_graph);
m_max_edge_index = renumber_edge_indices(i, end, 0);
}
void
remove_edge_and_renumber_indices(edge_iterator i)
{
edge_iterator j = next(i), end = edges(m_graph).second;
edge_index_type n = get(edge_index, m_graph, *i);
// remove the offending edge and renumber everything after
remove_edge(*i);
m_max_edge_index = renumber_edge_indices(j, end, n);
}
void
renumber_indices()
{
renumber_vertex_indices();
renumber_edge_indices();
}
// bundled property support
#ifndef BOOST_GRAPH_NO_BUNDLED_PROPERTIES
vertex_bundled& operator[](vertex_descriptor v)
{ return m_graph[v]; }
vertex_bundled const& operator[](vertex_descriptor v) const
{ return m_graph[v]; }
edge_bundled& operator[](edge_descriptor e)
{ return m_graph[e]; }
edge_bundled const& operator[](edge_descriptor e) const
{ return m_graph[e]; }
graph_bundled& operator[](graph_bundle_t)
{ return get_property(*this); }
graph_bundled const& operator[](graph_bundle_t) const
{ return get_property(*this); }
#endif
// Graph concepts
static vertex_descriptor null_vertex()
{ return graph_type::null_vertex(); }
void clear()
{
m_graph.clear();
m_num_vertices = m_max_vertex_index = 0;
m_num_edges = m_max_edge_index = 0;
}
void swap(directed_graph& g)
{
m_graph.swap(g);
std::swap(m_num_vertices, g.m_num_vertices);
std::swap(m_max_vertex_index, g.m_max_vertex_index);
std::swap(m_num_edges, g.m_num_edges);
std::swap(m_max_edge_index, g.m_max_edge_index);
}
private:
vertices_size_type
renumber_vertex_indices(vertex_iterator i,
vertex_iterator end,
vertices_size_type n)
{
typedef typename property_map<graph_type, vertex_index_t>::type IndexMap;
IndexMap indices = get(vertex_index, m_graph);
for( ; i != end; ++i) {
indices[*i] = n++;
}
return n;
}
vertices_size_type
renumber_edge_indices(edge_iterator i,
edge_iterator end,
vertices_size_type n)
{
typedef typename property_map<graph_type, edge_index_t>::type IndexMap;
IndexMap indices = get(edge_index, m_graph);
for( ; i != end; ++i) {
indices[*i] = n++;
}
return n;
}
graph_type m_graph;
vertices_size_type m_num_vertices;
edges_size_type m_num_edges;
vertex_index_type m_max_vertex_index;
edge_index_type m_max_edge_index;
};
#define DIRECTED_GRAPH_PARAMS typename VP, typename EP, typename GP
#define DIRECTED_GRAPH directed_graph<VP,EP,GP>
// IncidenceGraph concepts
template <DIRECTED_GRAPH_PARAMS>
inline typename DIRECTED_GRAPH::vertex_descriptor
source(typename DIRECTED_GRAPH::edge_descriptor e, DIRECTED_GRAPH const& g)
{ return source(e, g.impl()); }
template <DIRECTED_GRAPH_PARAMS>
inline typename DIRECTED_GRAPH::vertex_descriptor
target(typename DIRECTED_GRAPH::edge_descriptor e, DIRECTED_GRAPH const& g)
{ return target(e, g.impl()); }
template <DIRECTED_GRAPH_PARAMS>
inline typename DIRECTED_GRAPH::degree_size_type
out_degree(typename DIRECTED_GRAPH::vertex_descriptor v, DIRECTED_GRAPH const& g)
{ return out_degree(v, g.impl()); }
template <DIRECTED_GRAPH_PARAMS>
inline std::pair<
typename DIRECTED_GRAPH::out_edge_iterator,
typename DIRECTED_GRAPH::out_edge_iterator
>
out_edges(typename DIRECTED_GRAPH::vertex_descriptor v,
DIRECTED_GRAPH const& g)
{ return out_edges(v, g.impl()); }
// BidirectionalGraph concepts
template <DIRECTED_GRAPH_PARAMS>
inline typename DIRECTED_GRAPH::degree_size_type
in_degree(typename DIRECTED_GRAPH::vertex_descriptor v, DIRECTED_GRAPH const& g)
{ return in_degree(v, g.impl()); }
template <DIRECTED_GRAPH_PARAMS>
inline std::pair<
typename DIRECTED_GRAPH::in_edge_iterator,
typename DIRECTED_GRAPH::in_edge_iterator
>
in_edges(typename DIRECTED_GRAPH::vertex_descriptor v,
DIRECTED_GRAPH const& g)
{ return in_edges(v, g.impl()); }
template <DIRECTED_GRAPH_PARAMS>
inline typename DIRECTED_GRAPH::degree_size_type
degree(typename DIRECTED_GRAPH::vertex_descriptor v, DIRECTED_GRAPH const& g)
{ return degree(v, g.impl()); }
// AdjacencyGraph concepts
template <DIRECTED_GRAPH_PARAMS>
inline std::pair<
typename DIRECTED_GRAPH::adjacency_iterator,
typename DIRECTED_GRAPH::adjacency_iterator
>
adjacent_vertices(typename DIRECTED_GRAPH::vertex_descriptor v,
DIRECTED_GRAPH const& g)
{ return adjacent_vertices(v, g.impl()); }
template <DIRECTED_GRAPH_PARAMS>
typename DIRECTED_GRAPH::vertex_descriptor
vertex(typename DIRECTED_GRAPH::vertices_size_type n,
DIRECTED_GRAPH const& g)
{ return vertex(n, g.impl()); }
template <DIRECTED_GRAPH_PARAMS>
std::pair<typename DIRECTED_GRAPH::edge_descriptor, bool>
edge(typename DIRECTED_GRAPH::vertex_descriptor u,
typename DIRECTED_GRAPH::vertex_descriptor v,
DIRECTED_GRAPH const& g)
{ return edge(u, v, g.impl()); }
// VertexListGraph concepts
template <DIRECTED_GRAPH_PARAMS>
inline typename DIRECTED_GRAPH::vertices_size_type
num_vertices(DIRECTED_GRAPH const& g)
{ return g.num_vertices(); }
template <DIRECTED_GRAPH_PARAMS>
inline std::pair<
typename DIRECTED_GRAPH::vertex_iterator,
typename DIRECTED_GRAPH::vertex_iterator
>
vertices(DIRECTED_GRAPH const& g)
{ return vertices(g.impl()); }
// EdgeListGraph concepts
template <DIRECTED_GRAPH_PARAMS>
inline typename DIRECTED_GRAPH::edges_size_type
num_edges(DIRECTED_GRAPH const& g)
{ return g.num_edges(); }
template <DIRECTED_GRAPH_PARAMS>
inline std::pair<
typename DIRECTED_GRAPH::edge_iterator,
typename DIRECTED_GRAPH::edge_iterator
>
edges(DIRECTED_GRAPH const& g)
{ return edges(g.impl()); }
// MutableGraph concepts
template <DIRECTED_GRAPH_PARAMS>
inline typename DIRECTED_GRAPH::vertex_descriptor
add_vertex(DIRECTED_GRAPH& g)
{ return g.add_vertex(); }
template <DIRECTED_GRAPH_PARAMS>
inline typename DIRECTED_GRAPH::vertex_descriptor
add_vertex(typename DIRECTED_GRAPH::vertex_property_type const& p,
DIRECTED_GRAPH& g)
{ return g.add_vertex(p); }
template <DIRECTED_GRAPH_PARAMS>
inline void
clear_vertex(typename DIRECTED_GRAPH::vertex_descriptor v,
DIRECTED_GRAPH& g)
{ return g.clear_vertex(v); }
template <DIRECTED_GRAPH_PARAMS>
inline void
remove_vertex(typename DIRECTED_GRAPH::vertex_descriptor v,
DIRECTED_GRAPH& g)
{ return g.remove_vertex(v); }
template <DIRECTED_GRAPH_PARAMS>
inline std::pair<typename DIRECTED_GRAPH::edge_descriptor, bool>
add_edge(typename DIRECTED_GRAPH::vertex_descriptor u,
typename DIRECTED_GRAPH::vertex_descriptor v,
DIRECTED_GRAPH& g)
{ return g.add_edge(u, v); }
template <DIRECTED_GRAPH_PARAMS>
inline std::pair<typename DIRECTED_GRAPH::edge_descriptor, bool>
add_edge(typename DIRECTED_GRAPH::vertex_descriptor u,
typename DIRECTED_GRAPH::vertex_descriptor v,
typename DIRECTED_GRAPH::edge_property_type const& p,
DIRECTED_GRAPH& g)
{ return g.add_edge(u, v, p); }
template <DIRECTED_GRAPH_PARAMS>
inline void remove_edge(typename DIRECTED_GRAPH::vertex_descriptor u,
typename DIRECTED_GRAPH::vertex_descriptor v,
DIRECTED_GRAPH& g)
{ return g.remove_edge(u, v); }
template <DIRECTED_GRAPH_PARAMS>
inline void remove_edge(typename DIRECTED_GRAPH::edge_descriptor e, DIRECTED_GRAPH& g)
{ return g.remove_edge(e); }
template <DIRECTED_GRAPH_PARAMS>
inline void remove_edge(typename DIRECTED_GRAPH::edge_iterator i, DIRECTED_GRAPH& g)
{ return g.remove_edge(i); }
template <DIRECTED_GRAPH_PARAMS, class Predicate>
inline void remove_edge_if(Predicate pred, DIRECTED_GRAPH& g)
{ return remove_edge_if(pred, g.impl()); }
template <DIRECTED_GRAPH_PARAMS, class Predicate>
inline void
remove_out_edge_if(typename DIRECTED_GRAPH::vertex_descriptor v,
Predicate pred,
DIRECTED_GRAPH& g)
{ return remove_out_edge_if(v, pred, g.impl()); }
template <DIRECTED_GRAPH_PARAMS, class Predicate>
inline void
remove_in_edge_if(typename DIRECTED_GRAPH::vertex_descriptor v,
Predicate pred,
DIRECTED_GRAPH& g)
{ return remove_in_edge_if(v, pred, g.impl()); }
template <DIRECTED_GRAPH_PARAMS, typename Property>
struct property_map<DIRECTED_GRAPH, Property>: property_map<typename DIRECTED_GRAPH::graph_type, Property> {};
template <DIRECTED_GRAPH_PARAMS>
struct property_map<DIRECTED_GRAPH, vertex_all_t> {
typedef transform_value_property_map<
detail::remove_first_property,
typename property_map<typename DIRECTED_GRAPH::graph_type, vertex_all_t>::const_type>
const_type;
typedef transform_value_property_map<
detail::remove_first_property,
typename property_map<typename DIRECTED_GRAPH::graph_type, vertex_all_t>::type>
type;
};
template <DIRECTED_GRAPH_PARAMS>
struct property_map<DIRECTED_GRAPH, edge_all_t> {
typedef transform_value_property_map<
detail::remove_first_property,
typename property_map<typename DIRECTED_GRAPH::graph_type, edge_all_t>::const_type>
const_type;
typedef transform_value_property_map<
detail::remove_first_property,
typename property_map<typename DIRECTED_GRAPH::graph_type, edge_all_t>::type>
type;
};
// PropertyGraph concepts
template <DIRECTED_GRAPH_PARAMS, typename Property>
inline typename property_map<DIRECTED_GRAPH, Property>::type
get(Property p, DIRECTED_GRAPH& g)
{ return get(p, g.impl()); }
template <DIRECTED_GRAPH_PARAMS, typename Property>
inline typename property_map<DIRECTED_GRAPH, Property>::const_type
get(Property p, DIRECTED_GRAPH const& g)
{ return get(p, g.impl()); }
template <DIRECTED_GRAPH_PARAMS>
inline typename property_map<DIRECTED_GRAPH, vertex_all_t>::type
get(vertex_all_t, DIRECTED_GRAPH& g)
{ return typename property_map<DIRECTED_GRAPH, vertex_all_t>::type(detail::remove_first_property(), get(vertex_all, g.impl())); }
template <DIRECTED_GRAPH_PARAMS>
inline typename property_map<DIRECTED_GRAPH, vertex_all_t>::const_type
get(vertex_all_t, DIRECTED_GRAPH const& g)
{ return typename property_map<DIRECTED_GRAPH, vertex_all_t>::const_type(detail::remove_first_property(), get(vertex_all, g.impl())); }
template <DIRECTED_GRAPH_PARAMS>
inline typename property_map<DIRECTED_GRAPH, edge_all_t>::type
get(edge_all_t, DIRECTED_GRAPH& g)
{ return typename property_map<DIRECTED_GRAPH, edge_all_t>::type(detail::remove_first_property(), get(edge_all, g.impl())); }
template <DIRECTED_GRAPH_PARAMS>
inline typename property_map<DIRECTED_GRAPH, edge_all_t>::const_type
get(edge_all_t, DIRECTED_GRAPH const& g)
{ return typename property_map<DIRECTED_GRAPH, edge_all_t>::const_type(detail::remove_first_property(), get(edge_all, g.impl())); }
template <DIRECTED_GRAPH_PARAMS, typename Property, typename Key>
inline typename property_traits<
typename property_map<
typename DIRECTED_GRAPH::graph_type, Property
>::const_type
>::value_type
get(Property p, DIRECTED_GRAPH const& g, Key const& k)
{ return get(p, g.impl(), k); }
template <DIRECTED_GRAPH_PARAMS, typename Key>
inline typename property_traits<
typename property_map<
typename DIRECTED_GRAPH::graph_type, vertex_all_t
>::const_type
>::value_type
get(vertex_all_t, DIRECTED_GRAPH const& g, Key const& k)
{ return get(vertex_all, g.impl(), k).m_base; }
template <DIRECTED_GRAPH_PARAMS, typename Key>
inline typename property_traits<
typename property_map<
typename DIRECTED_GRAPH::graph_type, edge_all_t
>::const_type
>::value_type
get(edge_all_t, DIRECTED_GRAPH const& g, Key const& k)
{ return get(edge_all, g.impl(), k).m_base; }
template <DIRECTED_GRAPH_PARAMS, typename Property, typename Key, typename Value>
inline void put(Property p, DIRECTED_GRAPH& g, Key const& k, Value const& v)
{ put(p, g.impl(), k, v); }
template <DIRECTED_GRAPH_PARAMS, typename Key, typename Value>
inline void put(vertex_all_t, DIRECTED_GRAPH& g, Key const& k, Value const& v)
{ put(vertex_all, g.impl(), k,
typename DIRECTED_GRAPH::internal_vertex_property(get(vertex_index, g.impl(), k), v));
}
template <DIRECTED_GRAPH_PARAMS, typename Key, typename Value>
inline void put(edge_all_t, DIRECTED_GRAPH& g, Key const& k, Value const& v)
{ put(edge_all, g.impl(), k,
typename DIRECTED_GRAPH::internal_vertex_property(get(edge_index, g.impl(), k), v));
}
template <DIRECTED_GRAPH_PARAMS, class Property>
typename graph_property<DIRECTED_GRAPH, Property>::type&
get_property(DIRECTED_GRAPH& g, Property p)
{ return get_property(g.impl(), p); }
template <DIRECTED_GRAPH_PARAMS, class Property>
typename graph_property<DIRECTED_GRAPH, Property>::type const&
get_property(DIRECTED_GRAPH const& g, Property p)
{ return get_property(g.impl(), p); }
template <DIRECTED_GRAPH_PARAMS, class Property, class Value>
void
set_property(DIRECTED_GRAPH& g, Property p, Value v)
{ return set_property(g.impl(), p, v); }
// Vertex index management
template <DIRECTED_GRAPH_PARAMS>
inline typename DIRECTED_GRAPH::vertex_index_type
get_vertex_index(typename DIRECTED_GRAPH::vertex_descriptor v,
DIRECTED_GRAPH const& g)
{ return get(vertex_index, g, v); }
template <DIRECTED_GRAPH_PARAMS>
typename DIRECTED_GRAPH::vertex_index_type
max_vertex_index(DIRECTED_GRAPH const& g)
{ return g.max_vertex_index(); }
template <DIRECTED_GRAPH_PARAMS>
inline void
renumber_vertex_indices(DIRECTED_GRAPH& g)
{ g.renumber_vertex_indices(); }
template <DIRECTED_GRAPH_PARAMS>
inline void
remove_vertex_and_renumber_indices(typename DIRECTED_GRAPH::vertex_iterator i,
DIRECTED_GRAPH& g)
{ g.remove_vertex_and_renumber_indices(i); }
// Edge index management
template <DIRECTED_GRAPH_PARAMS>
inline typename DIRECTED_GRAPH::edge_index_type
get_edge_index(typename DIRECTED_GRAPH::edge_descriptor v, DIRECTED_GRAPH const& g)
{ return get(edge_index, g, v); }
template <DIRECTED_GRAPH_PARAMS>
typename DIRECTED_GRAPH::edge_index_type
max_edge_index(DIRECTED_GRAPH const& g)
{ return g.max_edge_index(); }
template <DIRECTED_GRAPH_PARAMS>
inline void renumber_edge_indices(DIRECTED_GRAPH& g)
{ g.renumber_edge_indices(); }
template <DIRECTED_GRAPH_PARAMS>
inline void
remove_edge_and_renumber_indices(typename DIRECTED_GRAPH::edge_iterator i,
DIRECTED_GRAPH& g)
{ g.remove_edge_and_renumber_indices(i); }
// Index management
template <DIRECTED_GRAPH_PARAMS>
inline void
renumber_indices(DIRECTED_GRAPH& g)
{ g.renumber_indices(); }
// Mutability Traits
template <DIRECTED_GRAPH_PARAMS>
struct graph_mutability_traits<DIRECTED_GRAPH> {
typedef mutable_property_graph_tag category;
};
#undef DIRECTED_GRAPH_PARAMS
#undef DIRECTED_GRAPH
} /* namespace boost */
#endif
@@ -0,0 +1,148 @@
// Copyright (C) 2007 Douglas Gregor
// Use, modification and distribution is subject to 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)
// This file contains code for the distributed adjacency list's
// message handlers. It should not be included directly by users.
#ifndef BOOST_GRAPH_DISTRIBUTED_ADJLIST_HANDLERS_HPP
#define BOOST_GRAPH_DISTRIBUTED_ADJLIST_HANDLERS_HPP
#ifndef BOOST_GRAPH_USE_MPI
#error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
#endif
#include <boost/graph/parallel/simple_trigger.hpp>
#include <boost/graph/parallel/detail/untracked_pair.hpp>
namespace boost {
template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
void
PBGL_DISTRIB_ADJLIST_TYPE::
setup_triggers()
{
using boost::graph::parallel::simple_trigger;
simple_trigger(process_group_, msg_add_vertex_with_property, this,
&adjacency_list::handle_add_vertex_with_property);
simple_trigger(process_group_, msg_add_vertex_with_property_and_reply, this,
&adjacency_list::handle_add_vertex_with_property_and_reply);
simple_trigger(process_group_, msg_add_edge, this,
&adjacency_list::handle_add_edge);
simple_trigger(process_group_, msg_add_edge_with_reply, this,
&adjacency_list::handle_add_edge_with_reply);
simple_trigger(process_group_, msg_add_edge_with_property, this,
&adjacency_list::handle_add_edge_with_property);
simple_trigger(process_group_, msg_add_edge_with_property_and_reply, this,
&adjacency_list::handle_add_edge_with_property_and_reply);
simple_trigger(process_group_, msg_nonlocal_edge, this,
&adjacency_list::handle_nonlocal_edge);
simple_trigger(process_group_, msg_remove_edge, this,
&adjacency_list::handle_remove_edge);
}
template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
void
PBGL_DISTRIB_ADJLIST_TYPE::
handle_add_vertex_with_property(int source, int tag,
const vertex_property_type& data,
trigger_receive_context)
{
vertex_descriptor v(this->processor(),
add_vertex(this->build_vertex_property(data),
this->base()));
if (on_add_vertex)
on_add_vertex(v, *this);
}
template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
typename PBGL_DISTRIB_ADJLIST_TYPE::local_vertex_descriptor
PBGL_DISTRIB_ADJLIST_TYPE::
handle_add_vertex_with_property_and_reply(int source, int tag,
const vertex_property_type& data,
trigger_receive_context)
{
// Try to find a vertex with this name
local_vertex_descriptor local_v
= add_vertex(this->build_vertex_property(data), this->base());
vertex_descriptor v(processor(), local_v);
if (on_add_vertex)
on_add_vertex(v, *this);
return local_v;
}
template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
void
PBGL_DISTRIB_ADJLIST_TYPE::
handle_add_edge(int source, int tag, const msg_add_edge_data& data,
trigger_receive_context)
{
add_edge(vertex_descriptor(processor(), data.source),
data.target, *this);
}
template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
boost::parallel::detail::untracked_pair<typename PBGL_DISTRIB_ADJLIST_TYPE::edge_descriptor, bool>
PBGL_DISTRIB_ADJLIST_TYPE::
handle_add_edge_with_reply(int source, int tag, const msg_add_edge_data& data,
trigger_receive_context)
{
std::pair<typename PBGL_DISTRIB_ADJLIST_TYPE::edge_descriptor, bool> p =
add_edge(vertex_descriptor(processor(), data.source),data.target, *this);
return p;
}
template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
void
PBGL_DISTRIB_ADJLIST_TYPE::
handle_add_edge_with_property(int source, int tag,
const msg_add_edge_with_property_data& data,
trigger_receive_context)
{
add_edge(vertex_descriptor(processor(), data.source),
data.target, data.get_property(), *this);
}
template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
boost::parallel::detail::untracked_pair<typename PBGL_DISTRIB_ADJLIST_TYPE::edge_descriptor, bool>
PBGL_DISTRIB_ADJLIST_TYPE::
handle_add_edge_with_property_and_reply
(int source, int tag,
const msg_add_edge_with_property_data& data,
trigger_receive_context)
{
std::pair<typename PBGL_DISTRIB_ADJLIST_TYPE::edge_descriptor, bool> p =
add_edge(vertex_descriptor(processor(), data.source),
data.target, data.get_property(), *this);
return p;
}
template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
void
PBGL_DISTRIB_ADJLIST_TYPE::
handle_nonlocal_edge(int source, int tag,
const msg_nonlocal_edge_data& data,
trigger_receive_context)
{
add_remote_edge(data, source, directed_selector());
}
template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
void
PBGL_DISTRIB_ADJLIST_TYPE::
handle_remove_edge(int source, int tag,
const msg_remove_edge_data& data,
trigger_receive_context)
{
remove_local_edge(data, source, directed_selector());
}
}
#endif // BOOST_GRAPH_DISTRIBUTED_ADJLIST_HANDLERS_HPP
@@ -0,0 +1,319 @@
// Copyright (C) 2007 Douglas Gregor
// Use, modification and distribution is subject to 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)
// This file contains code for the distributed adjacency list's
// initializations. It should not be included directly by users.
#ifndef BOOST_GRAPH_DISTRIBUTED_ADJLIST_INITIALIZE_HPP
#define BOOST_GRAPH_DISTRIBUTED_ADJLIST_INITIALIZE_HPP
#ifndef BOOST_GRAPH_USE_MPI
#error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
#endif
namespace boost {
template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
template<typename EdgeIterator>
void
PBGL_DISTRIB_ADJLIST_TYPE::
initialize(EdgeIterator first, EdgeIterator last,
vertices_size_type, const base_distribution_type& distribution,
vecS)
{
process_id_type id = process_id(process_group_);
while (first != last) {
if ((process_id_type)distribution(first->first) == id) {
vertex_descriptor source(id, distribution.local(first->first));
vertex_descriptor target(distribution(first->second),
distribution.local(first->second));
add_edge(source, target, *this);
}
++first;
}
synchronize(process_group_);
}
template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
template<typename EdgeIterator, typename EdgePropertyIterator>
void
PBGL_DISTRIB_ADJLIST_TYPE::
initialize(EdgeIterator first, EdgeIterator last,
EdgePropertyIterator ep_iter,
vertices_size_type, const base_distribution_type& distribution,
vecS)
{
process_id_type id = process_id(process_group_);
while (first != last) {
if (static_cast<process_id_type>(distribution(first->first)) == id) {
vertex_descriptor source(id, distribution.local(first->first));
vertex_descriptor target(distribution(first->second),
distribution.local(first->second));
add_edge(source, target, *ep_iter, *this);
}
++first;
++ep_iter;
}
synchronize(process_group_);
}
template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
template<typename EdgeIterator, typename EdgePropertyIterator,
typename VertexListS>
void
PBGL_DISTRIB_ADJLIST_TYPE::
initialize(EdgeIterator first, EdgeIterator last,
EdgePropertyIterator ep_iter,
vertices_size_type n, const base_distribution_type& distribution,
VertexListS)
{
using boost::parallel::inplace_all_to_all;
typedef vertices_size_type vertex_number_t;
typedef typename std::iterator_traits<EdgePropertyIterator>::value_type
edge_property_init_t;
typedef std::pair<vertex_descriptor, vertex_number_t>
st_pair;
typedef std::pair<st_pair, edge_property_init_t> delayed_edge_t;
process_group_type pg = process_group();
process_id_type id = process_id(pg);
// Vertex indices
std::vector<local_vertex_descriptor> index_to_vertex;
index_to_vertex.reserve(num_vertices(*this));
BGL_FORALL_VERTICES_T(v, base(), inherited)
index_to_vertex.push_back(v);
// The list of edges we can't add immediately.
std::vector<delayed_edge_t> delayed_edges;
std::vector<std::vector<vertex_number_t> > descriptor_requests;
descriptor_requests.resize(num_processes(pg));
// Add all of the edges we can, up to the point where we run
// into a descriptor we don't know.
while (first != last) {
if (distribution(first->first) == id) {
if (distribution(first->second) != id) break;
vertex_descriptor source
(id, index_to_vertex[distribution.local(first->first)]);
vertex_descriptor target
(distribution(first->second),
index_to_vertex[distribution.local(first->second)]);
add_edge(source, target, *ep_iter, *this);
}
++first;
++ep_iter;
}
// Queue all of the remaining edges and determine the set of
// descriptors we need to know about.
while (first != last) {
if (distribution(first->first) == id) {
vertex_descriptor source
(id, index_to_vertex[distribution.local(first->first)]);
process_id_type dest = distribution(first->second);
if (dest != id) {
descriptor_requests[dest]
.push_back(distribution.local(first->second));
// Compact request list if we need to
if (descriptor_requests[dest].size() >
distribution.block_size(dest, n)) {
std::sort(descriptor_requests[dest].begin(),
descriptor_requests[dest].end());
descriptor_requests[dest].erase(
std::unique(descriptor_requests[dest].begin(),
descriptor_requests[dest].end()),
descriptor_requests[dest].end());
}
}
// Save the edge for later
delayed_edges.push_back
(delayed_edge_t(st_pair(source, first->second), *ep_iter));
}
++first;
++ep_iter;
}
// Compact descriptor requests
for (process_id_type dest = 0; dest < num_processes(pg); ++dest) {
std::sort(descriptor_requests[dest].begin(),
descriptor_requests[dest].end());
descriptor_requests[dest].erase(
std::unique(descriptor_requests[dest].begin(),
descriptor_requests[dest].end()),
descriptor_requests[dest].end());
}
// Send out all of the descriptor requests
std::vector<std::vector<vertex_number_t> > in_descriptor_requests;
in_descriptor_requests.resize(num_processes(pg));
inplace_all_to_all(pg, descriptor_requests, in_descriptor_requests);
// Reply to all of the descriptor requests
std::vector<std::vector<local_vertex_descriptor> >
descriptor_responses;
descriptor_responses.resize(num_processes(pg));
for (process_id_type dest = 0; dest < num_processes(pg); ++dest) {
for (std::size_t i = 0; i < in_descriptor_requests[dest].size(); ++i) {
local_vertex_descriptor v =
index_to_vertex[in_descriptor_requests[dest][i]];
descriptor_responses[dest].push_back(v);
}
in_descriptor_requests[dest].clear();
}
in_descriptor_requests.clear();
inplace_all_to_all(pg, descriptor_responses);
// Add the queued edges
for(typename std::vector<delayed_edge_t>::iterator i
= delayed_edges.begin(); i != delayed_edges.end(); ++i) {
process_id_type dest = distribution(i->first.second);
local_vertex_descriptor tgt_local;
if (dest == id) {
tgt_local = index_to_vertex[distribution.local(i->first.second)];
} else {
std::vector<vertex_number_t>& requests = descriptor_requests[dest];
typename std::vector<vertex_number_t>::iterator pos =
std::lower_bound(requests.begin(), requests.end(),
distribution.local(i->first.second));
tgt_local = descriptor_responses[dest][pos - requests.begin()];
}
add_edge(i->first.first, vertex_descriptor(dest, tgt_local),
i->second, *this);
}
synchronize(process_group_);
}
template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
template<typename EdgeIterator, typename VertexListS>
void
PBGL_DISTRIB_ADJLIST_TYPE::
initialize(EdgeIterator first, EdgeIterator last,
vertices_size_type n, const base_distribution_type& distribution,
VertexListS)
{
using boost::parallel::inplace_all_to_all;
typedef vertices_size_type vertex_number_t;
typedef std::pair<vertex_descriptor, vertex_number_t> delayed_edge_t;
process_group_type pg = process_group();
process_id_type id = process_id(pg);
// Vertex indices
std::vector<local_vertex_descriptor> index_to_vertex;
index_to_vertex.reserve(num_vertices(*this));
BGL_FORALL_VERTICES_T(v, base(), inherited)
index_to_vertex.push_back(v);
// The list of edges we can't add immediately.
std::vector<delayed_edge_t> delayed_edges;
std::vector<std::vector<vertex_number_t> > descriptor_requests;
descriptor_requests.resize(num_processes(pg));
// Add all of the edges we can, up to the point where we run
// into a descriptor we don't know.
while (first != last) {
if (distribution(first->first) == id) {
if (distribution(first->second) != id) break;
vertex_descriptor source
(id, index_to_vertex[distribution.local(first->first)]);
vertex_descriptor target
(distribution(first->second),
index_to_vertex[distribution.local(first->second)]);
add_edge(source, target, *this);
}
++first;
}
// Queue all of the remaining edges and determine the set of
// descriptors we need to know about.
while (first != last) {
if (distribution(first->first) == id) {
vertex_descriptor source
(id, index_to_vertex[distribution.local(first->first)]);
process_id_type dest = distribution(first->second);
if (dest != id) {
descriptor_requests[dest]
.push_back(distribution.local(first->second));
// Compact request list if we need to
if (descriptor_requests[dest].size() >
distribution.block_size(dest, n)) {
std::sort(descriptor_requests[dest].begin(),
descriptor_requests[dest].end());
descriptor_requests[dest].erase(
std::unique(descriptor_requests[dest].begin(),
descriptor_requests[dest].end()),
descriptor_requests[dest].end());
}
}
// Save the edge for later
delayed_edges.push_back(delayed_edge_t(source, first->second));
}
++first;
}
// Compact descriptor requests
for (process_id_type dest = 0; dest < num_processes(pg); ++dest) {
std::sort(descriptor_requests[dest].begin(),
descriptor_requests[dest].end());
descriptor_requests[dest].erase(
std::unique(descriptor_requests[dest].begin(),
descriptor_requests[dest].end()),
descriptor_requests[dest].end());
}
// Send out all of the descriptor requests
std::vector<std::vector<vertex_number_t> > in_descriptor_requests;
in_descriptor_requests.resize(num_processes(pg));
inplace_all_to_all(pg, descriptor_requests, in_descriptor_requests);
// Reply to all of the descriptor requests
std::vector<std::vector<local_vertex_descriptor> >
descriptor_responses;
descriptor_responses.resize(num_processes(pg));
for (process_id_type dest = 0; dest < num_processes(pg); ++dest) {
for (std::size_t i = 0; i < in_descriptor_requests[dest].size(); ++i) {
local_vertex_descriptor v =
index_to_vertex[in_descriptor_requests[dest][i]];
descriptor_responses[dest].push_back(v);
}
in_descriptor_requests[dest].clear();
}
in_descriptor_requests.clear();
inplace_all_to_all(pg, descriptor_responses);
// Add the queued edges
for(typename std::vector<delayed_edge_t>::iterator i
= delayed_edges.begin(); i != delayed_edges.end(); ++i) {
process_id_type dest = distribution(i->second);
local_vertex_descriptor tgt_local;
if (dest == id) {
tgt_local = index_to_vertex[distribution.local(i->second)];
} else {
std::vector<vertex_number_t>& requests = descriptor_requests[dest];
typename std::vector<vertex_number_t>::iterator pos =
std::lower_bound(requests.begin(), requests.end(),
distribution.local(i->second));
tgt_local = descriptor_responses[dest][pos - requests.begin()];
}
add_edge(i->first, vertex_descriptor(dest, tgt_local), *this);
}
synchronize(process_group_);
}
} // end namespace boost
#endif // BOOST_GRAPH_DISTRIBUTED_ADJLIST_INITIALIZE_HPP
@@ -0,0 +1,393 @@
// Copyright (C) 2005-2006 The Trustees of Indiana University.
// Use, modification and distribution is subject to 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)
// Authors: Douglas Gregor
// Andrew Lumsdaine
//
// Implements redistribution of vertices for a distributed adjacency
// list. This file should not be included by users. It will be
// included by the distributed adjacency list header.
//
#ifndef BOOST_GRAPH_USE_MPI
#error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
#endif
#include <boost/pending/container_traits.hpp>
namespace boost { namespace detail { namespace parallel {
/* This structure contains a (vertex or edge) descriptor that is being
moved from one processor to another. It contains the properties for
that descriptor (if any).
*/
template<typename Descriptor, typename DescriptorProperty>
struct redistributed_descriptor : maybe_store_property<DescriptorProperty>
{
typedef maybe_store_property<DescriptorProperty> inherited;
redistributed_descriptor() { }
redistributed_descriptor(const Descriptor& v, const DescriptorProperty& p)
: inherited(p), descriptor(v) { }
Descriptor descriptor;
private:
friend class boost::serialization::access;
template<typename Archiver>
void serialize(Archiver& ar, unsigned int /*version*/)
{
ar & boost::serialization::base_object<inherited>(*this)
& unsafe_serialize(descriptor);
}
};
/* Predicate that returns true if the target has migrated. */
template<typename VertexProcessorMap, typename Graph>
struct target_migrated_t
{
typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
typedef typename graph_traits<Graph>::edge_descriptor Edge;
target_migrated_t(VertexProcessorMap vertex_to_processor, const Graph& g)
: vertex_to_processor(vertex_to_processor), g(g) { }
bool operator()(Edge e) const
{
typedef global_descriptor<Vertex> DVertex;
processor_id_type owner = get(edge_target_processor_id, g, e);
return get(vertex_to_processor, DVertex(owner, target(e, g))) != owner;
}
private:
VertexProcessorMap vertex_to_processor;
const Graph& g;
};
template<typename VertexProcessorMap, typename Graph>
inline target_migrated_t<VertexProcessorMap, Graph>
target_migrated(VertexProcessorMap vertex_to_processor, const Graph& g)
{ return target_migrated_t<VertexProcessorMap, Graph>(vertex_to_processor, g); }
/* Predicate that returns true if the source of an in-edge has migrated. */
template<typename VertexProcessorMap, typename Graph>
struct source_migrated_t
{
typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
typedef typename graph_traits<Graph>::edge_descriptor Edge;
source_migrated_t(VertexProcessorMap vertex_to_processor, const Graph& g)
: vertex_to_processor(vertex_to_processor), g(g) { }
bool operator()(stored_in_edge<Edge> e) const
{
return get(vertex_to_processor, DVertex(e.source_processor, source(e.e, g)))
!= e.source_processor;
}
private:
VertexProcessorMap vertex_to_processor;
const Graph& g;
};
template<typename VertexProcessorMap, typename Graph>
inline source_migrated_t<VertexProcessorMap, Graph>
source_migrated(VertexProcessorMap vertex_to_processor, const Graph& g)
{ return source_migrated_t<VertexProcessorMap, Graph>(vertex_to_processor, g); }
/* Predicate that returns true if the target has migrated. */
template<typename VertexProcessorMap, typename Graph>
struct source_or_target_migrated_t
{
typedef typename graph_traits<Graph>::edge_descriptor Edge;
source_or_target_migrated_t(VertexProcessorMap vertex_to_processor,
const Graph& g)
: vertex_to_processor(vertex_to_processor), g(g) { }
bool operator()(Edge e) const
{
return get(vertex_to_processor, source(e, g)) != source(e, g).owner
|| get(vertex_to_processor, target(e, g)) != target(e, g).owner;
}
private:
VertexProcessorMap vertex_to_processor;
const Graph& g;
};
template<typename VertexProcessorMap, typename Graph>
inline source_or_target_migrated_t<VertexProcessorMap, Graph>
source_or_target_migrated(VertexProcessorMap vertex_to_processor,
const Graph& g)
{
typedef source_or_target_migrated_t<VertexProcessorMap, Graph> result_type;
return result_type(vertex_to_processor, g);
}
} } // end of namespace detail::parallel
template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
template<typename VertexProcessorMap>
void
PBGL_DISTRIB_ADJLIST_TYPE
::request_in_neighbors(vertex_descriptor v,
VertexProcessorMap vertex_to_processor,
bidirectionalS)
{
BGL_FORALL_INEDGES_T(v, e, *this, graph_type)
request(vertex_to_processor, source(e, *this));
}
template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
template<typename VertexProcessorMap>
void
PBGL_DISTRIB_ADJLIST_TYPE
::remove_migrated_in_edges(vertex_descriptor v,
VertexProcessorMap vertex_to_processor,
bidirectionalS)
{
graph_detail::erase_if(get(vertex_in_edges, base())[v.local],
source_migrated(vertex_to_processor, base()));
}
template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
template<typename VertexProcessorMap>
void
PBGL_DISTRIB_ADJLIST_TYPE
::redistribute(VertexProcessorMap vertex_to_processor)
{
using boost::parallel::inplace_all_to_all;
// When we have stable descriptors, we only move those descriptors
// that actually need to be moved. Otherwise, we essentially have to
// regenerate the entire graph.
const bool has_stable_descriptors =
is_same<typename config_type::vertex_list_selector, listS>::value
|| is_same<typename config_type::vertex_list_selector, setS>::value
|| is_same<typename config_type::vertex_list_selector, multisetS>::value;
typedef detail::parallel::redistributed_descriptor<vertex_descriptor,
vertex_property_type>
redistributed_vertex;
typedef detail::parallel::redistributed_descriptor<edge_descriptor,
edge_property_type>
redistributed_edge;
typedef std::pair<vertices_size_type, edges_size_type> num_relocated_pair;
vertex_iterator vi, vi_end;
edge_iterator ei, ei_end;
process_group_type pg = process_group();
// Initial synchronization makes sure that we have all of our ducks
// in a row. We don't want any outstanding add/remove messages
// coming in mid-redistribution!
synchronize(process_group_);
// We cannot cope with eviction of ghost cells
vertex_to_processor.set_max_ghost_cells(0);
process_id_type p = num_processes(pg);
// Send vertices and edges to the processor where they will
// actually reside. This requires O(|V| + |E|) communication
std::vector<std::vector<redistributed_vertex> > redistributed_vertices(p);
std::vector<std::vector<redistributed_edge> > redistributed_edges(p);
// Build the sets of relocated vertices for each process and then do
// an all-to-all transfer.
for (boost::tie(vi, vi_end) = vertices(*this); vi != vi_end; ++vi) {
if (!has_stable_descriptors
|| get(vertex_to_processor, *vi) != vi->owner) {
redistributed_vertices[get(vertex_to_processor, *vi)]
.push_back(redistributed_vertex(*vi, get(vertex_all_t(), base(),
vi->local)));
}
// When our descriptors are stable, we need to determine which
// adjacent descriptors are stable to determine which edges will
// be removed.
if (has_stable_descriptors) {
BGL_FORALL_OUTEDGES_T(*vi, e, *this, graph_type)
request(vertex_to_processor, target(e, *this));
request_in_neighbors(*vi, vertex_to_processor, directed_selector());
}
}
inplace_all_to_all(pg, redistributed_vertices);
// If we have stable descriptors, we need to know where our neighbor
// vertices are moving.
if (has_stable_descriptors)
synchronize(vertex_to_processor);
// Build the sets of relocated edges for each process and then do
// an all-to-all transfer.
for (boost::tie(ei, ei_end) = edges(*this); ei != ei_end; ++ei) {
vertex_descriptor src = source(*ei, *this);
vertex_descriptor tgt = target(*ei, *this);
if (!has_stable_descriptors
|| get(vertex_to_processor, src) != src.owner
|| get(vertex_to_processor, tgt) != tgt.owner)
redistributed_edges[get(vertex_to_processor, source(*ei, *this))]
.push_back(redistributed_edge(*ei, split_edge_property(get(edge_all_t(), base(),
ei->local))));
}
inplace_all_to_all(pg, redistributed_edges);
// A mapping from old vertex descriptors to new vertex
// descriptors. This is an STL map partly because I'm too lazy to
// build a real property map (which is hard in the general case) but
// also because it won't try to look in the graph itself, because
// the keys are all vertex descriptors that have been invalidated.
std::map<vertex_descriptor, vertex_descriptor> old_to_new_vertex_map;
if (has_stable_descriptors) {
// Clear out all vertices and edges that will have moved. There
// are several stages to this.
// First, eliminate all outgoing edges from the (local) vertices
// that have been moved or whose targets have been moved.
BGL_FORALL_VERTICES_T(v, *this, graph_type) {
if (get(vertex_to_processor, v) != v.owner) {
clear_out_edges(v.local, base());
clear_in_edges_local(v, directed_selector());
} else {
remove_out_edge_if(v.local,
target_migrated(vertex_to_processor, base()),
base());
remove_migrated_in_edges(v, vertex_to_processor, directed_selector());
}
}
// Next, eliminate locally-stored edges that have migrated (for
// undirected graphs).
graph_detail::erase_if(local_edges_,
source_or_target_migrated(vertex_to_processor, *this));
// Eliminate vertices that have migrated
for (boost::tie(vi, vi_end) = vertices(*this); vi != vi_end; /* in loop */) {
if (get(vertex_to_processor, *vi) != vi->owner)
remove_vertex((*vi++).local, base());
else {
// Add the identity relation for vertices that have not migrated
old_to_new_vertex_map[*vi] = *vi;
++vi;
}
}
} else {
// Clear out the local graph: the entire graph is in transit
clear();
}
// Add the new vertices to the graph. When we do so, update the old
// -> new vertex mapping both locally and for the owner of the "old"
// vertex.
{
typedef std::pair<vertex_descriptor, vertex_descriptor> mapping_pair;
std::vector<std::vector<mapping_pair> > mappings(p);
for (process_id_type src = 0; src < p; ++src) {
for (typename std::vector<redistributed_vertex>::iterator vi =
redistributed_vertices[src].begin();
vi != redistributed_vertices[src].end(); ++vi) {
vertex_descriptor new_vertex =
add_vertex(vi->get_property(), *this);
old_to_new_vertex_map[vi->descriptor] = new_vertex;
mappings[vi->descriptor.owner].push_back(mapping_pair(vi->descriptor,
new_vertex));
}
redistributed_vertices[src].clear();
}
inplace_all_to_all(pg, mappings);
// Add the mappings we were sent into the old->new map.
for (process_id_type src = 0; src < p; ++src)
old_to_new_vertex_map.insert(mappings[src].begin(), mappings[src].end());
}
// Get old->new vertex mappings for all of the vertices we need to
// know about.
// TBD: An optimization here might involve sending the
// request-response pairs without an explicit request step (for
// bidirectional and undirected graphs). However, it may not matter
// all that much given the cost of redistribution.
{
std::vector<std::vector<vertex_descriptor> > vertex_map_requests(p);
std::vector<std::vector<vertex_descriptor> > vertex_map_responses(p);
// We need to know about all of the vertices incident on edges
// that have been relocated to this processor. Tell each processor
// what each other processor needs to know.
for (process_id_type src = 0; src < p; ++src)
for (typename std::vector<redistributed_edge>::iterator ei =
redistributed_edges[src].begin();
ei != redistributed_edges[src].end(); ++ei) {
vertex_descriptor need_vertex = target(ei->descriptor, *this);
if (old_to_new_vertex_map.find(need_vertex)
== old_to_new_vertex_map.end())
{
old_to_new_vertex_map[need_vertex] = need_vertex;
vertex_map_requests[need_vertex.owner].push_back(need_vertex);
}
}
inplace_all_to_all(pg,
vertex_map_requests,
vertex_map_responses);
// Process the requests made for vertices we own. Then perform yet
// another all-to-all swap. This one matches the requests we've
// made to the responses we were given.
for (process_id_type src = 0; src < p; ++src)
for (typename std::vector<vertex_descriptor>::iterator vi =
vertex_map_responses[src].begin();
vi != vertex_map_responses[src].end(); ++vi)
*vi = old_to_new_vertex_map[*vi];
inplace_all_to_all(pg, vertex_map_responses);
// Matching the requests to the responses, update the old->new
// vertex map for all of the vertices we will need to know.
for (process_id_type src = 0; src < p; ++src) {
typedef typename std::vector<vertex_descriptor>::size_type size_type;
for (size_type i = 0; i < vertex_map_requests[src].size(); ++i) {
old_to_new_vertex_map[vertex_map_requests[src][i]] =
vertex_map_responses[src][i];
}
}
}
// Add edges to the graph by mapping the source and target.
for (process_id_type src = 0; src < p; ++src) {
for (typename std::vector<redistributed_edge>::iterator ei =
redistributed_edges[src].begin();
ei != redistributed_edges[src].end(); ++ei) {
add_edge(old_to_new_vertex_map[source(ei->descriptor, *this)],
old_to_new_vertex_map[target(ei->descriptor, *this)],
ei->get_property(),
*this);
}
redistributed_edges[src].clear();
}
// Be sure that edge-addition messages are received now, completing
// the graph.
synchronize(process_group_);
this->distribution().clear();
detail::parallel::maybe_initialize_vertex_indices(vertices(base()),
get(vertex_index, base()));
}
} // end namespace boost
@@ -0,0 +1,993 @@
// Copyright Daniel Wallin 2007. Use, modification and distribution is
// subject to 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_GRAPH_DISTRIBUTED_ADJLIST_SERIALIZATION_070925_HPP
#define BOOST_GRAPH_DISTRIBUTED_ADJLIST_SERIALIZATION_070925_HPP
#ifndef BOOST_GRAPH_USE_MPI
#error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
#endif
# include <boost/assert.hpp>
# include <boost/lexical_cast.hpp>
# include <boost/foreach.hpp>
# include <boost/filesystem/path.hpp>
# include <boost/filesystem/operations.hpp>
# include <cctype>
# include <fstream>
namespace boost {
namespace detail { namespace parallel
{
// Wraps a local descriptor, making it serializable.
template <class Local>
struct serializable_local_descriptor
{
serializable_local_descriptor()
{}
serializable_local_descriptor(Local local)
: local(local)
{}
operator Local const&() const
{
return local;
}
bool operator==(serializable_local_descriptor const& other) const
{
return local == other.local;
}
bool operator<(serializable_local_descriptor const& other) const
{
return local < other.local;
}
template <class Archive>
void serialize(Archive& ar, const unsigned int /*version*/)
{
ar & unsafe_serialize(local);
}
Local local;
};
template <class Vertex, class Properties>
struct pending_edge
{
pending_edge(
Vertex source, Vertex target
, Properties properties, void* property_ptr
)
: source(source)
, target(target)
, properties(properties)
, property_ptr(property_ptr)
{}
Vertex source;
Vertex target;
Properties properties;
void* property_ptr;
};
inline bool is_digit(char c)
{
return (bool)std::isdigit(c);
}
inline std::vector<int>
available_process_files(std::string const& filename)
{
if (!filesystem::exists(filename))
return std::vector<int>();
std::vector<int> result;
for (filesystem::directory_iterator i(filename), end; i != end; ++i)
{
if (!filesystem::is_regular(*i))
boost::throw_exception(std::runtime_error("directory contains non-regular entries"));
std::string process_name = i->path().filename().string();
for (std::string::size_type i = 0; i < process_name.size(); ++i)
if (!is_digit(process_name[i]))
boost::throw_exception(std::runtime_error("directory contains files with invalid names"));
result.push_back(boost::lexical_cast<int>(process_name));
}
return result;
}
template <class Archive, class Tag, class T, class Base>
void maybe_load_properties(
Archive& ar, char const* name, property<Tag, T, Base>& properties)
{
ar >> serialization::make_nvp(name, get_property_value(properties, Tag()));
maybe_load_properties(ar, name, static_cast<Base&>(properties));
}
template <class Archive>
void maybe_load_properties(
Archive&, char const*, no_property&)
{}
template <class Archive, typename Bundle>
void maybe_load_properties(
Archive& ar, char const* name, Bundle& bundle)
{
ar >> serialization::make_nvp(name, bundle);
no_property prop;
maybe_load_properties(ar, name, prop);
}
template <class Graph, class Archive, class VertexListS>
struct graph_loader
{
typedef typename Graph::vertex_descriptor vertex_descriptor;
typedef typename Graph::local_vertex_descriptor local_vertex_descriptor;
typedef typename Graph::vertex_property_type vertex_property_type;
typedef typename Graph::edge_descriptor edge_descriptor;
typedef typename Graph::local_edge_descriptor local_edge_descriptor;
typedef typename Graph::edge_property_type edge_property_type;
typedef typename Graph::process_group_type process_group_type;
typedef typename process_group_type::process_id_type process_id_type;
typedef typename Graph::directed_selector directed_selector;
typedef typename mpl::if_<
is_same<VertexListS, defaultS>, vecS, VertexListS
>::type vertex_list_selector;
typedef pending_edge<vertex_descriptor, edge_property_type>
pending_edge_type;
typedef serializable_local_descriptor<local_vertex_descriptor>
serializable_vertex_descriptor;
graph_loader(Graph& g, Archive& ar)
: m_g(g)
, m_ar(ar)
, m_pg(g.process_group())
, m_requested_vertices(num_processes(m_pg))
, m_remote_vertices(num_processes(m_pg))
, m_property_ptrs(num_processes(m_pg))
{
g.clear();
load_prefix();
load_vertices();
load_edges();
ar >> make_nvp("distribution", m_g.distribution());
}
private:
struct pending_in_edge
{
pending_in_edge(
vertex_descriptor u, vertex_descriptor v, void* property_ptr
)
: u(u)
, v(v)
, property_ptr(property_ptr)
{}
vertex_descriptor u;
vertex_descriptor v;
void* property_ptr;
};
bool is_root() const
{
return process_id(m_pg) == 0;
}
template <class T>
serialization::nvp<T> const make_nvp(char const* name, T& value) const
{
return serialization::nvp<T>(name, value);
}
void load_prefix();
void load_vertices();
template <class Anything>
void maybe_load_and_store_local_vertex(Anything);
void maybe_load_and_store_local_vertex(vecS);
void load_edges();
void load_in_edges(bidirectionalS);
void load_in_edges(directedS);
void add_pending_in_edge(
vertex_descriptor u, vertex_descriptor v, void* property_ptr, vecS);
template <class Anything>
void add_pending_in_edge(
vertex_descriptor u, vertex_descriptor v, void* property_ptr, Anything);
template <class Anything>
void add_edge(
vertex_descriptor u, vertex_descriptor v
, edge_property_type const& property, void* property_ptr, Anything);
void add_edge(
vertex_descriptor u, vertex_descriptor v
, edge_property_type const& property, void* property_ptr, vecS);
void add_remote_vertex_request(
vertex_descriptor u, vertex_descriptor v, directedS);
void add_remote_vertex_request(
vertex_descriptor u, vertex_descriptor v, bidirectionalS);
void add_in_edge(
edge_descriptor const&, void*, directedS);
void add_in_edge(
edge_descriptor const& edge, void* old_property_ptr, bidirectionalS);
void resolve_remote_vertices(directedS);
void resolve_remote_vertices(bidirectionalS);
vertex_descriptor resolve_remote_vertex(vertex_descriptor u) const;
vertex_descriptor resolve_remote_vertex(vertex_descriptor u, vecS) const;
template <class Anything>
vertex_descriptor resolve_remote_vertex(vertex_descriptor u, Anything) const;
void resolve_property_ptrs();
void commit_pending_edges(vecS);
template <class Anything>
void commit_pending_edges(Anything);
void commit_pending_in_edges(directedS);
void commit_pending_in_edges(bidirectionalS);
void* maybe_load_property_ptr(directedS) { return 0; }
void* maybe_load_property_ptr(bidirectionalS);
Graph& m_g;
Archive& m_ar;
process_group_type m_pg;
std::vector<process_id_type> m_id_mapping;
// Maps local vertices as loaded from the archive to
// the ones actually added to the graph. Only used
// when !vecS.
std::map<local_vertex_descriptor, local_vertex_descriptor> m_local_vertices;
// This is the list of remote vertex descriptors that we
// are going to receive from other processes. This is
// kept sorted so that we can determine the position of
// the matching vertex descriptor in m_remote_vertices.
std::vector<std::vector<serializable_vertex_descriptor> > m_requested_vertices;
// This is the list of remote vertex descriptors that
// we send and receive from other processes.
std::vector<std::vector<serializable_vertex_descriptor> > m_remote_vertices;
// ...
std::vector<pending_edge_type> m_pending_edges;
// The pending in-edges that will be added in the commit step, after
// the remote vertex descriptors has been resolved. Only used
// when bidirectionalS and !vecS.
std::vector<pending_in_edge> m_pending_in_edges;
std::vector<std::vector<unsafe_pair<void*,void*> > > m_property_ptrs;
};
template <class Graph, class Archive, class VertexListS>
void graph_loader<Graph, Archive, VertexListS>::load_prefix()
{
typename process_group_type::process_size_type num_processes_;
m_ar >> make_nvp("num_processes", num_processes_);
if (num_processes_ != num_processes(m_pg))
boost::throw_exception(std::runtime_error("number of processes mismatch"));
process_id_type old_id;
m_ar >> make_nvp("id", old_id);
std::vector<typename Graph::distribution_type::size_type> mapping;
m_ar >> make_nvp("mapping", mapping);
// Fetch all the old id's from the other processes.
std::vector<process_id_type> old_ids;
all_gather(m_pg, &old_id, &old_id+1, old_ids);
m_id_mapping.resize(num_processes(m_pg), -1);
for (process_id_type i = 0; i < num_processes(m_pg); ++i)
{
# ifdef PBGL_SERIALIZE_DEBUG
if (is_root())
std::cout << i << " used to be " << old_ids[i] << "\n";
# endif
BOOST_ASSERT(m_id_mapping[old_ids[i]] == -1);
m_id_mapping[old_ids[i]] = i;
}
std::vector<typename Graph::distribution_type::size_type> new_mapping(
mapping.size());
for (int i = 0; i < num_processes(m_pg); ++i)
{
new_mapping[mapping[old_ids[i]]] = i;
}
m_g.distribution().assign_mapping(
new_mapping.begin(), new_mapping.end());
}
template <class Graph, class Archive, class VertexListS>
void graph_loader<Graph, Archive, VertexListS>::load_vertices()
{
int V;
m_ar >> BOOST_SERIALIZATION_NVP(V);
# ifdef PBGL_SERIALIZE_DEBUG
if (is_root())
std::cout << "Loading vertices\n";
# endif
for (int i = 0; i < V; ++i)
{
maybe_load_and_store_local_vertex(vertex_list_selector());
}
}
template <class Graph, class Archive, class VertexListS>
template <class Anything>
void graph_loader<Graph, Archive, VertexListS>::maybe_load_and_store_local_vertex(Anything)
{
// Load the original vertex descriptor
local_vertex_descriptor local;
m_ar >> make_nvp("local", unsafe_serialize(local));
// Load the properties
vertex_property_type property;
detail::parallel::maybe_load_properties(m_ar, "vertex_property",
property);
// Add the vertex
vertex_descriptor v(process_id(m_pg), add_vertex(property, m_g.base()));
if (m_g.on_add_vertex)
m_g.on_add_vertex(v, m_g);
// Create the mapping from the "old" local descriptor to the new
// local descriptor.
m_local_vertices[local] = v.local;
}
template <class Graph, class Archive, class VertexListS>
void graph_loader<Graph, Archive, VertexListS>::maybe_load_and_store_local_vertex(vecS)
{
// Load the properties
vertex_property_type property;
detail::parallel::maybe_load_properties(m_ar, "vertex_property",
property);
// Add the vertex
vertex_descriptor v(process_id(m_pg),
add_vertex(m_g.build_vertex_property(property),
m_g.base()));
if (m_g.on_add_vertex)
m_g.on_add_vertex(v, m_g);
}
template <class Graph, class Archive, class VertexListS>
void graph_loader<Graph, Archive, VertexListS>::load_edges()
{
int E;
m_ar >> BOOST_SERIALIZATION_NVP(E);
# ifdef PBGL_SERIALIZE_DEBUG
if (is_root())
std::cout << "Loading edges\n";
# endif
for (int i = 0; i < E; ++i)
{
local_vertex_descriptor local_src;
process_id_type target_owner;
local_vertex_descriptor local_tgt;
m_ar >> make_nvp("source", unsafe_serialize(local_src));
m_ar >> make_nvp("target_owner", target_owner);
m_ar >> make_nvp("target", unsafe_serialize(local_tgt));
process_id_type new_src_owner = process_id(m_pg);
process_id_type new_tgt_owner = m_id_mapping[target_owner];
vertex_descriptor source(new_src_owner, local_src);
vertex_descriptor target(new_tgt_owner, local_tgt);
edge_property_type properties;
detail::parallel::maybe_load_properties(m_ar, "edge_property", properties);
void* property_ptr = maybe_load_property_ptr(directed_selector());
add_edge(source, target, properties, property_ptr, vertex_list_selector());
}
load_in_edges(directed_selector());
commit_pending_edges(vertex_list_selector());
}
template <class Graph, class Archive, class VertexListS>
void graph_loader<Graph, Archive, VertexListS>::load_in_edges(bidirectionalS)
{
std::size_t I;
m_ar >> BOOST_SERIALIZATION_NVP(I);
# ifdef PBGL_SERIALIZE_DEBUG
if (is_root())
std::cout << "Loading in-edges\n";
# endif
for (int i = 0; i < I; ++i)
{
process_id_type src_owner;
local_vertex_descriptor local_src;
local_vertex_descriptor local_target;
void* property_ptr;
m_ar >> make_nvp("src_owner", src_owner);
m_ar >> make_nvp("source", unsafe_serialize(local_src));
m_ar >> make_nvp("target", unsafe_serialize(local_target));
m_ar >> make_nvp("property_ptr", unsafe_serialize(property_ptr));
src_owner = m_id_mapping[src_owner];
vertex_descriptor u(src_owner, local_src);
vertex_descriptor v(process_id(m_pg), local_target);
add_pending_in_edge(u, v, property_ptr, vertex_list_selector());
}
}
template <class Graph, class Archive, class VertexListS>
void graph_loader<Graph, Archive, VertexListS>::load_in_edges(directedS)
{}
template <class Graph, class Archive, class VertexListS>
void graph_loader<Graph, Archive, VertexListS>::add_pending_in_edge(
vertex_descriptor u, vertex_descriptor v, void* property_ptr, vecS)
{
m_pending_in_edges.push_back(pending_in_edge(u,v,property_ptr));
}
template <class Graph, class Archive, class VertexListS>
template <class Anything>
void graph_loader<Graph, Archive, VertexListS>::add_pending_in_edge(
vertex_descriptor u, vertex_descriptor v, void* property_ptr, Anything)
{
// u and v represent the out-edge here, meaning v is local
// to us, and u is always remote.
m_pending_in_edges.push_back(pending_in_edge(u,v,property_ptr));
add_remote_vertex_request(v, u, bidirectionalS());
}
template <class Graph, class Archive, class VertexListS>
template <class Anything>
void graph_loader<Graph, Archive, VertexListS>::add_edge(
vertex_descriptor u, vertex_descriptor v
, edge_property_type const& property, void* property_ptr, Anything)
{
m_pending_edges.push_back(pending_edge_type(u, v, property, property_ptr));
add_remote_vertex_request(u, v, directed_selector());
}
template <class Graph, class Archive, class VertexListS>
void graph_loader<Graph, Archive, VertexListS>::add_remote_vertex_request(
vertex_descriptor u, vertex_descriptor v, directedS)
{
// We have to request the remote vertex.
m_requested_vertices[owner(v)].push_back(local(v));
}
template <class Graph, class Archive, class VertexListS>
void graph_loader<Graph, Archive, VertexListS>::add_remote_vertex_request(
vertex_descriptor u, vertex_descriptor v, bidirectionalS)
{
// If the edge spans to another process, we know
// that that process has a matching in-edge, so
// we can just send our vertex. No requests
// necessary.
if (owner(v) != m_g.processor())
{
m_remote_vertices[owner(v)].push_back(local(u));
m_requested_vertices[owner(v)].push_back(local(v));
}
}
template <class Graph, class Archive, class VertexListS>
void graph_loader<Graph, Archive, VertexListS>::add_edge(
vertex_descriptor u, vertex_descriptor v
, edge_property_type const& property, void* property_ptr, vecS)
{
std::pair<local_edge_descriptor, bool> inserted =
detail::parallel::add_local_edge(
local(u), local(v)
, m_g.build_edge_property(property), m_g.base());
BOOST_ASSERT(inserted.second);
put(edge_target_processor_id, m_g.base(), inserted.first, owner(v));
edge_descriptor e(owner(u), owner(v), true, inserted.first);
if (inserted.second && m_g.on_add_edge)
m_g.on_add_edge(e, m_g);
add_in_edge(e, property_ptr, directed_selector());
}
template <class Graph, class Archive, class VertexListS>
void graph_loader<Graph, Archive, VertexListS>::add_in_edge(
edge_descriptor const&, void*, directedS)
{}
template <class Graph, class Archive, class VertexListS>
void graph_loader<Graph, Archive, VertexListS>::add_in_edge(
edge_descriptor const& edge, void* old_property_ptr, bidirectionalS)
{
if (owner(target(edge, m_g)) == m_g.processor())
{
detail::parallel::stored_in_edge<local_edge_descriptor>
e(m_g.processor(), local(edge));
boost::graph_detail::push(get(
vertex_in_edges, m_g.base())[local(target(edge, m_g))], e);
}
else
{
// We send the (old,new) property pointer pair to
// the remote process. This could be optimized to
// only send the new one -- the ordering can be
// made implicit because the old pointer value is
// stored on the remote process.
//
// Doing that is a little bit more complicated, but
// in case it turns out it's important we can do it.
void* property_ptr = local(edge).get_property();
m_property_ptrs[owner(target(edge, m_g))].push_back(
unsafe_pair<void*,void*>(old_property_ptr, property_ptr));
}
}
template <class Graph, class Archive, class VertexListS>
void graph_loader<Graph, Archive, VertexListS>::resolve_property_ptrs()
{
# ifdef PBGL_SERIALIZE_DEBUG
if (is_root())
std::cout << "Resolving property pointers\n";
# endif
for (int i = 0; i < num_processes(m_pg); ++i)
{
std::sort(
m_property_ptrs[i].begin(), m_property_ptrs[i].end());
}
boost::parallel::inplace_all_to_all(m_pg, m_property_ptrs);
}
template <class Graph, class Archive, class VertexListS>
void graph_loader<Graph, Archive, VertexListS>::resolve_remote_vertices(directedS)
{
for (int i = 0; i < num_processes(m_pg); ++i)
{
std::sort(m_requested_vertices[i].begin(), m_requested_vertices[i].end());
}
boost::parallel::inplace_all_to_all(
m_pg, m_requested_vertices, m_remote_vertices);
for (int i = 0; i < num_processes(m_pg); ++i)
{
BOOST_FOREACH(serializable_vertex_descriptor& u, m_remote_vertices[i])
{
u = m_local_vertices[u];
}
}
boost::parallel::inplace_all_to_all(m_pg, m_remote_vertices);
}
template <class Graph, class Archive, class VertexListS>
void graph_loader<Graph, Archive, VertexListS>::resolve_remote_vertices(bidirectionalS)
{
# ifdef PBGL_SERIALIZE_DEBUG
if (is_root())
std::cout << "Resolving remote vertices\n";
# endif
for (int i = 0; i < num_processes(m_pg); ++i)
{
std::sort(m_requested_vertices[i].begin(), m_requested_vertices[i].end());
std::sort(m_remote_vertices[i].begin(), m_remote_vertices[i].end());
BOOST_FOREACH(serializable_vertex_descriptor& u, m_remote_vertices[i])
{
u = m_local_vertices[u];
}
}
boost::parallel::inplace_all_to_all(m_pg, m_remote_vertices);
for (int i = 0; i < num_processes(m_pg); ++i)
BOOST_ASSERT(m_remote_vertices[i].size() == m_requested_vertices[i].size());
}
template <class Graph, class Archive, class VertexListS>
void graph_loader<Graph, Archive, VertexListS>::commit_pending_edges(vecS)
{
commit_pending_in_edges(directed_selector());
}
template <class Graph, class Archive, class VertexListS>
template <class Anything>
void graph_loader<Graph, Archive, VertexListS>::commit_pending_edges(Anything)
{
resolve_remote_vertices(directed_selector());
BOOST_FOREACH(pending_edge_type const& e, m_pending_edges)
{
vertex_descriptor u = resolve_remote_vertex(e.source);
vertex_descriptor v = resolve_remote_vertex(e.target);
add_edge(u, v, e.properties, e.property_ptr, vecS());
}
commit_pending_in_edges(directed_selector());
}
template <class Graph, class Archive, class VertexListS>
void graph_loader<Graph, Archive, VertexListS>::commit_pending_in_edges(directedS)
{}
template <class Graph, class Archive, class VertexListS>
void graph_loader<Graph, Archive, VertexListS>::commit_pending_in_edges(bidirectionalS)
{
resolve_property_ptrs();
BOOST_FOREACH(pending_in_edge const& e, m_pending_in_edges)
{
vertex_descriptor u = resolve_remote_vertex(e.u, vertex_list_selector());
vertex_descriptor v = resolve_remote_vertex(e.v, vertex_list_selector());
typedef detail::parallel::stored_in_edge<local_edge_descriptor> stored_edge;
std::vector<unsafe_pair<void*,void*> >::iterator i = std::lower_bound(
m_property_ptrs[owner(u)].begin()
, m_property_ptrs[owner(u)].end()
, unsafe_pair<void*,void*>(e.property_ptr, 0)
);
if (i == m_property_ptrs[owner(u)].end()
|| i->first != e.property_ptr)
{
BOOST_ASSERT(false);
}
local_edge_descriptor local_edge(local(u), local(v), i->second);
stored_edge edge(owner(u), local_edge);
boost::graph_detail::push(
get(vertex_in_edges, m_g.base())[local(v)], edge);
}
}
template <class Graph, class Archive, class VertexListS>
typename graph_loader<Graph, Archive, VertexListS>::vertex_descriptor
graph_loader<Graph, Archive, VertexListS>::resolve_remote_vertex(
vertex_descriptor u) const
{
if (owner(u) == process_id(m_pg))
{
return vertex_descriptor(
process_id(m_pg), m_local_vertices.find(local(u))->second);
}
typename std::vector<serializable_vertex_descriptor>::const_iterator
i = std::lower_bound(
m_requested_vertices[owner(u)].begin()
, m_requested_vertices[owner(u)].end()
, serializable_vertex_descriptor(local(u))
);
if (i == m_requested_vertices[owner(u)].end()
|| *i != local(u))
{
BOOST_ASSERT(false);
}
local_vertex_descriptor local =
m_remote_vertices[owner(u)][m_requested_vertices[owner(u)].end() - i];
return vertex_descriptor(owner(u), local);
}
template <class Graph, class Archive, class VertexListS>
typename graph_loader<Graph, Archive, VertexListS>::vertex_descriptor
graph_loader<Graph, Archive, VertexListS>::resolve_remote_vertex(
vertex_descriptor u, vecS) const
{
return u;
}
template <class Graph, class Archive, class VertexListS>
template <class Anything>
typename graph_loader<Graph, Archive, VertexListS>::vertex_descriptor
graph_loader<Graph, Archive, VertexListS>::resolve_remote_vertex(
vertex_descriptor u, Anything) const
{
return resolve_remote_vertex(u);
}
template <class Graph, class Archive, class VertexListS>
void*
graph_loader<Graph, Archive, VertexListS>::maybe_load_property_ptr(bidirectionalS)
{
void* ptr;
m_ar >> make_nvp("property_ptr", unsafe_serialize(ptr));
return ptr;
}
template <class Archive, class D>
void maybe_save_local_descriptor(Archive& ar, D const&, vecS)
{}
template <class Archive, class D, class NotVecS>
void maybe_save_local_descriptor(Archive& ar, D const& d, NotVecS)
{
ar << serialization::make_nvp(
"local", unsafe_serialize(const_cast<D&>(d)));
}
template <class Archive>
void maybe_save_properties(
Archive&, char const*, no_property const&)
{}
template <class Archive, class Tag, class T, class Base>
void maybe_save_properties(
Archive& ar, char const* name, property<Tag, T, Base> const& properties)
{
ar & serialization::make_nvp(name, get_property_value(properties, Tag()));
maybe_save_properties(ar, name, static_cast<Base const&>(properties));
}
template <class Archive, class Graph>
void save_in_edges(Archive& ar, Graph const& g, directedS)
{}
// We need to save the edges in the base edge
// list, and the in_edges that are stored in the
// vertex_in_edges vertex property.
template <class Archive, class Graph>
void save_in_edges(Archive& ar, Graph const& g, bidirectionalS)
{
typedef typename Graph::process_group_type
process_group_type;
typedef typename process_group_type::process_id_type
process_id_type;
typedef typename graph_traits<
Graph>::vertex_descriptor vertex_descriptor;
typedef typename vertex_descriptor::local_descriptor_type
local_vertex_descriptor;
typedef typename graph_traits<
Graph>::edge_descriptor edge_descriptor;
process_id_type id = g.processor();
typedef std::pair<local_vertex_descriptor, vertex_descriptor> in_edge;
std::vector<edge_descriptor> saved_in_edges;
BGL_FORALL_VERTICES_T(v, g, Graph)
{
BOOST_FOREACH(edge_descriptor const& e, in_edges(v, g))
{
// Only save the in_edges that isn't owned by this process.
if (owner(e) == id)
continue;
saved_in_edges.push_back(e);
}
}
std::size_t I = saved_in_edges.size();
ar << BOOST_SERIALIZATION_NVP(I);
BOOST_FOREACH(edge_descriptor const& e, saved_in_edges)
{
process_id_type src_owner = owner(source(e,g));
local_vertex_descriptor local_src = local(source(e,g));
local_vertex_descriptor local_target = local(target(e,g));
void* property_ptr = local(e).get_property();
using serialization::make_nvp;
ar << make_nvp("src_owner", src_owner);
ar << make_nvp("source", unsafe_serialize(local_src));
ar << make_nvp("target", unsafe_serialize(local_target));
ar << make_nvp("property_ptr", unsafe_serialize(property_ptr));
}
}
template <class Archive, class Edge>
void maybe_save_property_ptr(Archive&, Edge const&, directedS)
{}
template <class Archive, class Edge>
void maybe_save_property_ptr(Archive& ar, Edge const& e, bidirectionalS)
{
void* ptr = local(e).get_property();
ar << serialization::make_nvp("property_ptr", unsafe_serialize(ptr));
}
template <class Archive, class Graph, class DirectedS>
void save_edges(Archive& ar, Graph const& g, DirectedS)
{
typedef typename Graph::process_group_type
process_group_type;
typedef typename process_group_type::process_id_type
process_id_type;
typedef typename graph_traits<
Graph>::vertex_descriptor vertex_descriptor;
typedef typename graph_traits<
Graph>::edge_descriptor edge_descriptor;
typedef typename Graph::edge_property_type edge_property_type;
int E = num_edges(g);
ar << BOOST_SERIALIZATION_NVP(E);
// For *directed* graphs, we can just save
// the edge list and be done.
//
// For *bidirectional* graphs, we need to also
// save the "vertex_in_edges" property map,
// because it might contain in-edges that
// are not locally owned.
BGL_FORALL_EDGES_T(e, g, Graph)
{
vertex_descriptor src(source(e, g));
vertex_descriptor tgt(target(e, g));
typename vertex_descriptor::local_descriptor_type
local_u(local(src));
typename vertex_descriptor::local_descriptor_type
local_v(local(tgt));
process_id_type target_owner = owner(tgt);
using serialization::make_nvp;
ar << make_nvp("source", unsafe_serialize(local_u));
ar << make_nvp("target_owner", target_owner);
ar << make_nvp("target", unsafe_serialize(local_v));
maybe_save_properties(
ar, "edge_property"
, static_cast<edge_property_type const&>(get(edge_all_t(), g, e))
);
maybe_save_property_ptr(ar, e, DirectedS());
}
save_in_edges(ar, g, DirectedS());
}
}} // namespace detail::parallel
template <PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
template <class IStreamConstructibleArchive>
void PBGL_DISTRIB_ADJLIST_TYPE::load(std::string const& filename)
{
typedef typename config_type::VertexListS vertex_list_selector;
process_group_type pg = process_group();
process_id_type id = process_id(pg);
synchronize(pg);
std::vector<int> disk_files = detail::parallel::available_process_files(filename);
std::sort(disk_files.begin(), disk_files.end());
// Negotiate which process gets which file. Serialized.
std::vector<int> consumed_files;
int picked_file = -1;
if (id > 0)
receive_oob(pg, id-1, 0, consumed_files);
std::sort(consumed_files.begin(), consumed_files.end());
std::vector<int> available_files;
std::set_difference(
disk_files.begin(), disk_files.end()
, consumed_files.begin(), consumed_files.end()
, std::back_inserter(available_files)
);
if (available_files.empty())
boost::throw_exception(std::runtime_error("no file available"));
// back() used for debug purposes. Making sure the
// ranks are shuffled.
picked_file = available_files.back();
# ifdef PBGL_SERIALIZE_DEBUG
std::cout << id << " picked " << picked_file << "\n";
# endif
consumed_files.push_back(picked_file);
if (id < num_processes(pg) - 1)
send_oob(pg, id+1, 0, consumed_files);
std::string local_filename = filename + "/" +
lexical_cast<std::string>(picked_file);
std::ifstream in(local_filename.c_str(), std::ios_base::binary);
IStreamConstructibleArchive ar(in);
detail::parallel::graph_loader<
graph_type, IStreamConstructibleArchive, InVertexListS
> loader(*this, ar);
# ifdef PBGL_SERIALIZE_DEBUG
std::cout << "Process " << id << " done loading.\n";
# endif
synchronize(pg);
}
template <PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
template <class OStreamConstructibleArchive>
void PBGL_DISTRIB_ADJLIST_TYPE::save(std::string const& filename) const
{
typedef typename config_type::VertexListS vertex_list_selector;
process_group_type pg = process_group();
process_id_type id = process_id(pg);
if (filesystem::exists(filename) && !filesystem::is_directory(filename))
boost::throw_exception(std::runtime_error("entry exists, but is not a directory"));
filesystem::remove_all(filename);
filesystem::create_directory(filename);
synchronize(pg);
std::string local_filename = filename + "/" +
lexical_cast<std::string>(id);
std::ofstream out(local_filename.c_str(), std::ios_base::binary);
OStreamConstructibleArchive ar(out);
using serialization::make_nvp;
typename process_group_type::process_size_type num_processes_ = num_processes(pg);
ar << make_nvp("num_processes", num_processes_);
ar << BOOST_SERIALIZATION_NVP(id);
ar << make_nvp("mapping", this->distribution().mapping());
int V = num_vertices(*this);
ar << BOOST_SERIALIZATION_NVP(V);
BGL_FORALL_VERTICES_T(v, *this, graph_type)
{
local_vertex_descriptor local_descriptor(local(v));
detail::parallel::maybe_save_local_descriptor(
ar, local_descriptor, vertex_list_selector());
detail::parallel::maybe_save_properties(
ar, "vertex_property"
, static_cast<vertex_property_type const&>(get(vertex_all_t(), *this, v))
);
}
detail::parallel::save_edges(ar, *this, directed_selector());
ar << make_nvp("distribution", this->distribution());
}
} // namespace boost
#endif // BOOST_GRAPH_DISTRIBUTED_ADJLIST_SERIALIZATION_070925_HPP
@@ -0,0 +1,372 @@
// Copyright (C) 2005-2008 The Trustees of Indiana University.
// Use, modification and distribution is subject to 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)
// Authors: Douglas Gregor
// Andrew Lumsdaine
#ifndef BOOST_GRAPH_DISTRIBUTED_BOMAN_ET_AL_GRAPH_COLORING_HPP
#define BOOST_GRAPH_DISTRIBUTED_BOMAN_ET_AL_GRAPH_COLORING_HPP
#ifndef BOOST_GRAPH_USE_MPI
#error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
#endif
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/parallel/algorithm.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/graph/parallel/process_group.hpp>
#include <functional>
#include <vector>
#include <utility>
#include <boost/graph/iteration_macros.hpp>
#include <boost/optional.hpp>
#include <boost/assert.hpp>
#include <boost/graph/parallel/container_traits.hpp>
#include <boost/graph/properties.hpp>
#ifdef PBGL_ACCOUNTING
# include <boost/graph/accounting.hpp>
#endif // PBGL_ACCOUNTING
namespace boost { namespace graph { namespace distributed {
/**************************************************************************
* This source file implements the distributed graph coloring algorithm *
* by Boman et al in: *
* *
* Erik G. Boman, Doruk Bozdag, Umit Catalyurek, Assefaw H. Gebremedhin,*
* and Fredrik Manne. A Scalable Parallel Graph Coloring Algorithm for *
* Distributed Memory Computers. [unpublished preprint?] *
* *
**************************************************************************/
#ifdef PBGL_ACCOUNTING
struct boman_et_al_graph_coloring_stats_t
{
/* The size of the blocks to step through (i.e., the parameter s). */
std::size_t block_size;
/* Total wall-clock time used by the algorithm.*/
accounting::time_type execution_time;
/* The number of conflicts that occurred during execution. */
std::size_t conflicts;
/* The number of supersteps. */
std::size_t supersteps;
/* The number of colors used. */
std::size_t num_colors;
template<typename OutputStream>
void print(OutputStream& out)
{
out << "Problem = \"Coloring\"\n"
<< "Algorithm = \"Boman et al\"\n"
<< "Function = boman_et_al_graph_coloring\n"
<< "(P) Block size = " << block_size << "\n"
<< "Wall clock time = " << accounting::print_time(execution_time)
<< "\nConflicts = " << conflicts << "\n"
<< "Supersteps = " << supersteps << "\n"
<< "(R) Colors = " << num_colors << "\n";
}
};
static boman_et_al_graph_coloring_stats_t boman_et_al_graph_coloring_stats;
#endif
namespace detail {
template<typename T>
struct graph_coloring_reduce
{
BOOST_STATIC_CONSTANT(bool, non_default_resolver = true);
template<typename Key>
T operator()(const Key&) const { return (std::numeric_limits<T>::max)(); }
template<typename Key> T operator()(const Key&, T, T y) const { return y; }
};
}
template<typename Color>
struct first_fit_color
{
template<typename T>
Color operator()(const std::vector<T>& marked, T marked_true)
{
Color k = 0;
while (k < (Color)marked.size() && marked[k] == marked_true)
++k;
return k;
}
};
template<typename DistributedGraph, typename ColorMap, typename ChooseColor,
typename VertexOrdering, typename VertexIndexMap>
typename property_traits<ColorMap>::value_type
boman_et_al_graph_coloring
(const DistributedGraph& g,
ColorMap color,
typename graph_traits<DistributedGraph>::vertices_size_type s,
ChooseColor choose_color,
VertexOrdering ordering, VertexIndexMap vertex_index)
{
using namespace boost::graph::parallel;
using boost::parallel::all_reduce;
typename property_map<DistributedGraph, vertex_owner_t>::const_type
owner = get(vertex_owner, g);
typedef typename process_group_type<DistributedGraph>::type
process_group_type;
typedef typename process_group_type::process_id_type process_id_type;
typedef typename graph_traits<DistributedGraph>::vertex_descriptor Vertex;
typedef typename graph_traits<DistributedGraph>::edge_descriptor Edge;
typedef typename graph_traits<DistributedGraph>::vertices_size_type
vertices_size_type;
typedef typename property_traits<ColorMap>::value_type color_type;
typedef unsigned long long iterations_type;
typedef typename std::vector<Vertex>::iterator vertex_set_iterator;
typedef std::pair<Vertex, color_type> message_type;
#ifdef PBGL_ACCOUNTING
boman_et_al_graph_coloring_stats.block_size = s;
boman_et_al_graph_coloring_stats.execution_time = accounting::get_time();
boman_et_al_graph_coloring_stats.conflicts = 0;
boman_et_al_graph_coloring_stats.supersteps = 0;
#endif
// Initialize color map
color_type no_color = (std::numeric_limits<color_type>::max)();
BGL_FORALL_VERTICES_T(v, g, DistributedGraph)
put(color, v, no_color);
color.set_reduce(detail::graph_coloring_reduce<color_type>());
// Determine if we'll be using synchronous or asynchronous communication.
typedef typename process_group_type::communication_category
communication_category;
static const bool asynchronous =
is_convertible<communication_category, immediate_process_group_tag>::value;
process_group_type pg = process_group(g);
// U_i <- V_i
std::vector<Vertex> vertices_to_color(vertices(g).first, vertices(g).second);
iterations_type iter_num = 1, outer_iter_num = 1;
std::vector<iterations_type> marked;
std::vector<iterations_type> marked_conflicting(num_vertices(g), 0);
std::vector<bool> sent_to_processors;
std::size_t rounds = vertices_to_color.size() / s
+ (vertices_to_color.size() % s == 0? 0 : 1);
rounds = all_reduce(pg, rounds, boost::parallel::maximum<std::size_t>());
#ifdef PBGL_GRAPH_COLORING_DEBUG
std::cerr << "Number of rounds = " << rounds << std::endl;
#endif
while (rounds > 0) {
if (!vertices_to_color.empty()) {
// Set of conflicting vertices
std::vector<Vertex> conflicting_vertices;
vertex_set_iterator first = vertices_to_color.begin();
while (first != vertices_to_color.end()) {
// For each subset of size s (or smaller for the last subset)
vertex_set_iterator start = first;
for (vertices_size_type counter = s;
first != vertices_to_color.end() && counter > 0;
++first, --counter) {
// This vertex hasn't been sent to anyone yet
sent_to_processors.assign(num_processes(pg), false);
sent_to_processors[process_id(pg)] = true;
// Mark all of the colors that we see
BGL_FORALL_OUTEDGES_T(*first, e, g, DistributedGraph) {
color_type k = get(color, target(e, g));
if (k != no_color) {
if (k >= (color_type)marked.size()) marked.resize(k + 1, 0);
marked[k] = iter_num;
}
}
// Find a color for this vertex
put(color, *first, choose_color(marked, iter_num));
#ifdef PBGL_GRAPH_COLORING_DEBUG
std::cerr << "Chose color " << get(color, *first) << " for vertex "
<< *first << std::endl;
#endif
// Send this vertex's color to the owner of the edge target.
BGL_FORALL_OUTEDGES_T(*first, e, g, DistributedGraph) {
if (!sent_to_processors[get(owner, target(e, g))]) {
send(pg, get(owner, target(e, g)), 17,
message_type(source(e, g), get(color, source(e, g))));
sent_to_processors[get(owner, target(e, g))] = true;
}
}
++iter_num;
}
// Synchronize for non-immediate process groups.
if (!asynchronous) {
--rounds;
synchronize(pg);
}
// Receive boundary colors from other processors
while (optional<std::pair<process_id_type, int> > stp = probe(pg)) {
BOOST_ASSERT(stp->second == 17);
message_type msg;
receive(pg, stp->first, stp->second, msg);
cache(color, msg.first, msg.second);
#ifdef PBGL_GRAPH_COLORING_DEBUG
std::cerr << "Cached color " << msg.second << " for vertex "
<< msg.first << std::endl;
#endif
}
// Compute the set of conflicting vertices
// [start, first) contains all vertices in this subset
for (vertex_set_iterator vi = start; vi != first; ++vi) {
Vertex v = *vi;
BGL_FORALL_OUTEDGES_T(v, e, g, DistributedGraph) {
Vertex w = target(e, g);
if (get(owner, w) != process_id(pg) // boundary vertex
&& marked_conflicting[get(vertex_index, v)] != outer_iter_num
&& get(color, v) == get(color, w)
&& ordering(v, w)) {
conflicting_vertices.push_back(v);
marked_conflicting[get(vertex_index, v)] = outer_iter_num;
put(color, v, no_color);
#ifdef PBGL_GRAPH_COLORING_DEBUG
std::cerr << "Vertex " << v << " has a conflict with vertex "
<< w << std::endl;
#endif
break;
}
}
}
#ifdef PBGL_ACCOUNTING
boman_et_al_graph_coloring_stats.conflicts +=
conflicting_vertices.size();
#endif
}
if (asynchronous) synchronize(pg);
else {
while (rounds > 0) {
synchronize(pg);
--rounds;
}
}
conflicting_vertices.swap(vertices_to_color);
++outer_iter_num;
} else {
if (asynchronous) synchronize(pg);
else {
while (rounds > 0) {
synchronize(pg);
--rounds;
}
}
}
// Receive boundary colors from other processors
while (optional<std::pair<process_id_type, int> > stp = probe(pg)) {
BOOST_ASSERT(stp->second == 17);
message_type msg;
receive(pg, stp->first, stp->second, msg);
cache(color, msg.first, msg.second);
}
rounds = vertices_to_color.size() / s
+ (vertices_to_color.size() % s == 0? 0 : 1);
rounds = all_reduce(pg, rounds, boost::parallel::maximum<std::size_t>());
#ifdef PBGL_ACCOUNTING
++boman_et_al_graph_coloring_stats.supersteps;
#endif
}
// Determine the number of colors used.
color_type num_colors = 0;
BGL_FORALL_VERTICES_T(v, g, DistributedGraph) {
color_type k = get(color, v);
BOOST_ASSERT(k != no_color);
if (k != no_color) {
if (k >= (color_type)marked.size()) marked.resize(k + 1, 0); // TBD: perf?
if (marked[k] != iter_num) {
marked[k] = iter_num;
++num_colors;
}
}
}
num_colors =
all_reduce(pg, num_colors, boost::parallel::maximum<color_type>());
#ifdef PBGL_ACCOUNTING
boman_et_al_graph_coloring_stats.execution_time =
accounting::get_time() - boman_et_al_graph_coloring_stats.execution_time;
boman_et_al_graph_coloring_stats.conflicts =
all_reduce(pg, boman_et_al_graph_coloring_stats.conflicts,
std::plus<color_type>());
boman_et_al_graph_coloring_stats.num_colors = num_colors;
#endif
return num_colors;
}
template<typename DistributedGraph, typename ColorMap, typename ChooseColor,
typename VertexOrdering>
inline typename property_traits<ColorMap>::value_type
boman_et_al_graph_coloring
(const DistributedGraph& g, ColorMap color,
typename graph_traits<DistributedGraph>::vertices_size_type s,
ChooseColor choose_color, VertexOrdering ordering)
{
return boman_et_al_graph_coloring(g, color, s, choose_color, ordering,
get(vertex_index, g));
}
template<typename DistributedGraph, typename ColorMap, typename ChooseColor>
inline typename property_traits<ColorMap>::value_type
boman_et_al_graph_coloring
(const DistributedGraph& g,
ColorMap color,
typename graph_traits<DistributedGraph>::vertices_size_type s,
ChooseColor choose_color)
{
typedef typename graph_traits<DistributedGraph>::vertex_descriptor
vertex_descriptor;
return boman_et_al_graph_coloring(g, color, s, choose_color,
std::less<vertex_descriptor>());
}
template<typename DistributedGraph, typename ColorMap>
inline typename property_traits<ColorMap>::value_type
boman_et_al_graph_coloring
(const DistributedGraph& g,
ColorMap color,
typename graph_traits<DistributedGraph>::vertices_size_type s = 100)
{
typedef typename property_traits<ColorMap>::value_type Color;
return boman_et_al_graph_coloring(g, color, s, first_fit_color<Color>());
}
} } } // end namespace boost::graph::distributed
namespace boost { namespace graph {
using distributed::boman_et_al_graph_coloring;
} } // end namespace boost::graph
#endif // BOOST_GRAPH_DISTRIBUTED_BOMAN_ET_AL_GRAPH_COLORING_HPP
@@ -0,0 +1,164 @@
// Copyright 2004 The Trustees of Indiana University.
// Use, modification and distribution is subject to 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)
// Authors: Douglas Gregor
// Andrew Lumsdaine
#ifndef BOOST_GRAPH_PARALLEL_BFS_HPP
#define BOOST_GRAPH_PARALLEL_BFS_HPP
#ifndef BOOST_GRAPH_USE_MPI
#error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
#endif
#include <boost/graph/breadth_first_search.hpp>
#include <boost/graph/overloading.hpp>
#include <boost/graph/distributed/concepts.hpp>
#include <boost/graph/distributed/detail/filtered_queue.hpp>
#include <boost/graph/distributed/queue.hpp>
#include <boost/dynamic_bitset.hpp>
#include <boost/pending/queue.hpp>
#include <boost/graph/parallel/properties.hpp>
#include <boost/graph/parallel/container_traits.hpp>
namespace boost {
namespace detail {
/** @brief A unary predicate that decides when to push into a
* breadth-first search queue.
*
* This predicate stores a color map that is used to determine
* when to push. If it is provided with a key for which the color
* is white, it darkens the color to gray and returns true (so
* that the value will be pushed appropriately); if the color is
* not white, it returns false so that the vertex will be
* ignored.
*/
template<typename ColorMap>
struct darken_and_push
{
typedef typename property_traits<ColorMap>::key_type argument_type;
typedef bool result_type;
explicit darken_and_push(const ColorMap& color) : color(color) { }
bool operator()(const argument_type& value) const
{
typedef color_traits<typename property_traits<ColorMap>::value_type>
Color;
if (get(color, value) == Color::white()) {
put(color, value, Color::gray());
return true;
} else {
return false;
}
}
ColorMap color;
};
template<typename IndexMap>
struct has_not_been_seen
{
typedef bool result_type;
has_not_been_seen() { }
has_not_been_seen(std::size_t n, IndexMap index_map)
: seen(n), index_map(index_map) {}
template<typename Key>
result_type operator()(Key key)
{
bool result = seen[get(index_map, key)];
seen[get(index_map, key)] = true;
return !result;
}
void swap(has_not_been_seen& other)
{
using std::swap;
swap(seen, other.seen);
swap(index_map, other.index_map);
}
private:
dynamic_bitset<> seen;
IndexMap index_map;
};
template<typename IndexMap>
inline void
swap(has_not_been_seen<IndexMap>& x, has_not_been_seen<IndexMap>& y)
{
x.swap(y);
}
template <class DistributedGraph, class ColorMap, class BFSVisitor,
class BufferRef, class VertexIndexMap>
inline void
parallel_bfs_helper
(DistributedGraph& g,
typename graph_traits<DistributedGraph>::vertex_descriptor s,
ColorMap color,
BFSVisitor vis,
BufferRef Q,
VertexIndexMap)
{
set_property_map_role(vertex_color, color);
color.set_consistency_model(0);
breadth_first_search(g, s, Q.ref, vis, color);
}
template <class DistributedGraph, class ColorMap, class BFSVisitor,
class VertexIndexMap>
void parallel_bfs_helper
(DistributedGraph& g,
typename graph_traits<DistributedGraph>::vertex_descriptor s,
ColorMap color,
BFSVisitor vis,
boost::param_not_found,
VertexIndexMap vertex_index)
{
using boost::graph::parallel::process_group;
typedef graph_traits<DistributedGraph> Traits;
typedef typename Traits::vertex_descriptor Vertex;
typedef typename boost::graph::parallel::process_group_type<DistributedGraph>::type
process_group_type;
set_property_map_role(vertex_color, color);
color.set_consistency_model(0);
// Buffer default
typedef typename property_map<DistributedGraph, vertex_owner_t>
::const_type vertex_owner_map;
typedef boost::graph::distributed::distributed_queue<
process_group_type, vertex_owner_map, queue<Vertex>,
detail::darken_and_push<ColorMap> > queue_t;
queue_t Q(process_group(g),
get(vertex_owner, g),
detail::darken_and_push<ColorMap>(color));
breadth_first_search(g, s, Q, vis, color);
}
template <class DistributedGraph, class ColorMap, class BFSVisitor,
class P, class T, class R>
void bfs_helper
(DistributedGraph& g,
typename graph_traits<DistributedGraph>::vertex_descriptor s,
ColorMap color,
BFSVisitor vis,
const bgl_named_params<P, T, R>& params,
BOOST_GRAPH_ENABLE_IF_MODELS(DistributedGraph, distributed_graph_tag,
void)*)
{
parallel_bfs_helper
(g, s, color, vis, get_param(params, buffer_param_t()),
choose_const_pmap(get_param(params, vertex_index), g, vertex_index));
}
}
}
#endif // BOOST_GRAPH_PARALLEL_BFS_HPP
@@ -0,0 +1,217 @@
// Copyright (C) 2004-2006 The Trustees of Indiana University.
// Use, modification and distribution is subject to 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)
// Authors: Douglas Gregor
// Andrew Lumsdaine
//
// Distributed graph concepts and helpers
//
#ifndef BOOST_GRAPH_DISTRIBUTED_CONCEPTS_HPP
#define BOOST_GRAPH_DISTRIBUTED_CONCEPTS_HPP
#ifndef BOOST_GRAPH_USE_MPI
#error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
#endif
#include <boost/version.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/graph_concepts.hpp>
#include <boost/concept/assert.hpp>
#if BOOST_VERSION >= 103500
# include <boost/concept/detail/concept_def.hpp>
#endif
namespace boost {
class distributed_graph_tag { };
class distributed_vertex_list_graph_tag { };
class distributed_edge_list_graph_tag { };
#if BOOST_VERSION >= 103500
namespace concepts {
#endif
#if BOOST_VERSION < 103500
template <class G>
struct DistributedVertexListGraphConcept
{
typedef typename graph_traits<G>::vertex_iterator vertex_iterator;
typedef typename graph_traits<G>::vertices_size_type vertices_size_type;
typedef typename graph_traits<G>::traversal_category
traversal_category;
void constraints() {
BOOST_CONCEPT_ASSERT(( GraphConcept<G> ));
BOOST_CONCEPT_ASSERT(( MultiPassInputIteratorConcept<vertex_iterator> ));
BOOST_CONCEPT_ASSERT(( ConvertibleConcept<traversal_category,
distributed_vertex_list_graph_tag> ));
#ifdef BOOST_VECTOR_AS_GRAPH_GRAPH_ADL_HACK
// dwa 2003/7/11 -- This clearly shouldn't be necessary, but if
// you want to use vector_as_graph, it is! I'm sure the graph
// library leaves these out all over the place. Probably a
// redesign involving specializing a template with a static
// member function is in order :(
using boost::vertices;
#endif
p = vertices(g);
v = *p.first;
const_constraints(g);
}
void const_constraints(const G& cg) {
#ifdef BOOST_VECTOR_AS_GRAPH_GRAPH_ADL_HACK
// dwa 2003/7/11 -- This clearly shouldn't be necessary, but if
// you want to use vector_as_graph, it is! I'm sure the graph
// library leaves these out all over the place. Probably a
// redesign involving specializing a template with a static
// member function is in order :(
using boost::vertices;
#endif
p = vertices(cg);
v = *p.first;
V = num_vertices(cg);
}
std::pair<vertex_iterator,vertex_iterator> p;
typename graph_traits<G>::vertex_descriptor v;
G g;
vertices_size_type V;
};
template <class G>
struct DistributedEdgeListGraphConcept
{
typedef typename graph_traits<G>::edge_descriptor edge_descriptor;
typedef typename graph_traits<G>::edge_iterator edge_iterator;
typedef typename graph_traits<G>::edges_size_type edges_size_type;
typedef typename graph_traits<G>::traversal_category
traversal_category;
void constraints() {
BOOST_CONCEPT_ASSERT(( GraphConcept<G> ));
BOOST_CONCEPT_ASSERT(( MultiPassInputIteratorConcept<edge_iterator> ));
BOOST_CONCEPT_ASSERT(( DefaultConstructibleConcept<edge_descriptor> ));
BOOST_CONCEPT_ASSERT(( EqualityComparableConcept<edge_descriptor> ));
BOOST_CONCEPT_ASSERT(( AssignableConcept<edge_descriptor> ));
BOOST_CONCEPT_ASSERT(( ConvertibleConcept<traversal_category,
distributed_edge_list_graph_tag> ));
p = edges(g);
e = *p.first;
u = source(e, g);
v = target(e, g);
const_constraints(g);
}
void const_constraints(const G& cg) {
p = edges(cg);
E = num_edges(cg);
e = *p.first;
u = source(e, cg);
v = target(e, cg);
}
std::pair<edge_iterator,edge_iterator> p;
typename graph_traits<G>::vertex_descriptor u, v;
typename graph_traits<G>::edge_descriptor e;
edges_size_type E;
G g;
};
#else
BOOST_concept(DistributedVertexListGraph,(G))
: Graph<G>
{
typedef typename graph_traits<G>::vertex_iterator vertex_iterator;
typedef typename graph_traits<G>::vertices_size_type vertices_size_type;
typedef typename graph_traits<G>::traversal_category
traversal_category;
~DistributedVertexListGraph() {
BOOST_CONCEPT_ASSERT((MultiPassInputIterator<vertex_iterator>));
BOOST_CONCEPT_ASSERT((Convertible<traversal_category,
distributed_vertex_list_graph_tag>));
#ifdef BOOST_VECTOR_AS_GRAPH_GRAPH_ADL_HACK
// dwa 2003/7/11 -- This clearly shouldn't be necessary, but if
// you want to use vector_as_graph, it is! I'm sure the graph
// library leaves these out all over the place. Probably a
// redesign involving specializing a template with a static
// member function is in order :(
using boost::vertices;
#endif
p = vertices(g);
v = *p.first;
const_constraints(g);
}
void const_constraints(const G& cg) {
#ifdef BOOST_VECTOR_AS_GRAPH_GRAPH_ADL_HACK
// dwa 2003/7/11 -- This clearly shouldn't be necessary, but if
// you want to use vector_as_graph, it is! I'm sure the graph
// library leaves these out all over the place. Probably a
// redesign involving specializing a template with a static
// member function is in order :(
using boost::vertices;
#endif
p = vertices(cg);
v = *p.first;
V = num_vertices(cg);
}
std::pair<vertex_iterator,vertex_iterator> p;
typename graph_traits<G>::vertex_descriptor v;
G g;
vertices_size_type V;
};
BOOST_concept(DistributedEdgeListGraph,(G))
: Graph<G>
{
typedef typename graph_traits<G>::edge_descriptor edge_descriptor;
typedef typename graph_traits<G>::edge_iterator edge_iterator;
typedef typename graph_traits<G>::edges_size_type edges_size_type;
typedef typename graph_traits<G>::traversal_category
traversal_category;
~DistributedEdgeListGraph() {
BOOST_CONCEPT_ASSERT((MultiPassInputIterator<edge_iterator>));
BOOST_CONCEPT_ASSERT((DefaultConstructible<edge_descriptor>));
BOOST_CONCEPT_ASSERT((EqualityComparable<edge_descriptor>));
BOOST_CONCEPT_ASSERT((Assignable<edge_descriptor>));
BOOST_CONCEPT_ASSERT((Convertible<traversal_category,
distributed_edge_list_graph_tag>));
p = edges(g);
e = *p.first;
u = source(e, g);
v = target(e, g);
const_constraints(g);
}
void const_constraints(const G& cg) {
p = edges(cg);
E = num_edges(cg);
e = *p.first;
u = source(e, cg);
v = target(e, cg);
}
std::pair<edge_iterator,edge_iterator> p;
typename graph_traits<G>::vertex_descriptor u, v;
typename graph_traits<G>::edge_descriptor e;
edges_size_type E;
G g;
};
#endif
#if BOOST_VERSION >= 103500
} // end namespace concepts
using concepts::DistributedVertexListGraphConcept;
using concepts::DistributedEdgeListGraphConcept;
#endif
} // end namespace boost
#if BOOST_VERSION >= 103500
# include <boost/concept/detail/concept_undef.hpp>
#endif
#endif // BOOST_GRAPH_DISTRIBUTED_CONCEPTS_HPP
@@ -0,0 +1,769 @@
// Copyright (C) 2004-2006 The Trustees of Indiana University.
// Use, modification and distribution is subject to 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)
// Authors: Nick Edmonds
// Douglas Gregor
// Andrew Lumsdaine
#ifndef BOOST_GRAPH_PARALLEL_CC_HPP
#define BOOST_GRAPH_PARALLEL_CC_HPP
#ifndef BOOST_GRAPH_USE_MPI
#error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
#endif
#include <boost/detail/is_sorted.hpp>
#include <boost/assert.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/property_map/parallel/caching_property_map.hpp>
#include <boost/graph/parallel/algorithm.hpp>
#include <boost/pending/indirect_cmp.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/overloading.hpp>
#include <boost/graph/distributed/concepts.hpp>
#include <boost/graph/parallel/properties.hpp>
#include <boost/graph/distributed/local_subgraph.hpp>
#include <boost/graph/connected_components.hpp>
#include <boost/graph/named_function_params.hpp>
#include <boost/graph/parallel/process_group.hpp>
#include <boost/optional.hpp>
#include <functional>
#include <algorithm>
#include <vector>
#include <list>
#include <boost/graph/parallel/container_traits.hpp>
#include <boost/graph/iteration_macros.hpp>
#define PBGL_IN_PLACE_MERGE /* In place merge instead of sorting */
//#define PBGL_SORT_ASSERT /* Assert sorted for in place merge */
/* Explicit sychronization in pointer doubling step? */
#define PBGL_EXPLICIT_SYNCH
//#define PBGL_CONSTRUCT_METAGRAPH
#ifdef PBGL_CONSTRUCT_METAGRAPH
# define MAX_VERTICES_IN_METAGRAPH 10000
#endif
namespace boost { namespace graph { namespace distributed {
namespace cc_detail {
enum connected_components_message {
edges_msg, req_parents_msg, parents_msg, root_adj_msg
};
template <typename Vertex>
struct metaVertex {
metaVertex() {}
metaVertex(const Vertex& v) : name(v) {}
template<typename Archiver>
void serialize(Archiver& ar, const unsigned int /*version*/)
{
ar & name;
}
Vertex name;
};
#ifdef PBGL_CONSTRUCT_METAGRAPH
// Build meta-graph on result of local connected components
template <typename Graph, typename ParentMap, typename RootIterator,
typename AdjacencyMap>
void
build_local_metagraph(const Graph& g, ParentMap p, RootIterator r,
RootIterator r_end, AdjacencyMap& adj)
{
// TODO: Static assert that AdjacencyMap::value_type is std::vector<vertex_descriptor>
typedef typename boost::graph::parallel::process_group_type<Graph>::type
process_group_type;
typedef typename process_group_type::process_id_type process_id_type;
typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
BOOST_STATIC_ASSERT((is_same<typename AdjacencyMap::mapped_type,
std::vector<vertex_descriptor> >::value));
using boost::graph::parallel::process_group;
process_group_type pg = process_group(g);
process_id_type id = process_id(pg);
if (id != 0) {
// Send component roots and their associated edges to P0
for ( ; r != r_end; ++r ) {
std::vector<vertex_descriptor> adjs(1, *r); // Root
adjs.reserve(adjs.size() + adj[*r].size());
for (typename std::vector<vertex_descriptor>::iterator iter = adj[*r].begin();
iter != adj[*r].end(); ++iter)
adjs.push_back(get(p, *iter)); // Adjacencies
send(pg, 0, root_adj_msg, adjs);
}
}
synchronize(pg);
if (id == 0) {
typedef metaVertex<vertex_descriptor> VertexProperties;
typedef boost::adjacency_list<vecS, vecS, undirectedS,
VertexProperties> metaGraph;
typedef typename graph_traits<metaGraph>::vertex_descriptor
meta_vertex_descriptor;
std::map<vertex_descriptor, meta_vertex_descriptor> vertex_map;
std::vector<std::pair<vertex_descriptor, vertex_descriptor> > edges;
// Receive remote roots and edges
while (optional<std::pair<process_id_type, int> > m = probe(pg)) {
BOOST_ASSERT(m->second == root_adj_msg);
std::vector<vertex_descriptor> adjs;
receive(pg, m->first, m->second, adjs);
vertex_map[adjs[0]] = graph_traits<metaGraph>::null_vertex();
for (typename std::vector<vertex_descriptor>::iterator iter
= ++adjs.begin(); iter != adjs.end(); ++iter)
edges.push_back(std::make_pair(adjs[0], *iter));
}
// Add local roots and edges
for ( ; r != r_end; ++r ) {
vertex_map[*r] = graph_traits<metaGraph>::null_vertex();
edges.reserve(edges.size() + adj[*r].size());
for (typename std::vector<vertex_descriptor>::iterator iter = adj[*r].begin();
iter != adj[*r].end(); ++iter)
edges.push_back(std::make_pair(*r, get(p, *iter)));
}
// Build local meta-graph
metaGraph mg;
// Add vertices with property to map back to distributed graph vertex
for (typename std::map<vertex_descriptor, meta_vertex_descriptor>::iterator
iter = vertex_map.begin(); iter != vertex_map.end(); ++iter)
vertex_map[iter->first]
= add_vertex(metaVertex<vertex_descriptor>(iter->first), mg);
// Build meta-vertex map
typename property_map<metaGraph, vertex_descriptor VertexProperties::*>::type
metaVertexMap = get(&VertexProperties::name, mg);
typename std::vector<std::pair<vertex_descriptor, vertex_descriptor> >
::iterator edge_iter = edges.begin();
for ( ; edge_iter != edges.end(); ++edge_iter)
add_edge(vertex_map[edge_iter->first], vertex_map[edge_iter->second], mg);
edges.clear();
// Call connected_components on it
typedef typename property_map<metaGraph, vertex_index_t>::type
meta_index_map_type;
meta_index_map_type meta_index = get(vertex_index, mg);
std::vector<std::size_t> mg_component_vec(num_vertices(mg));
typedef iterator_property_map<std::vector<std::size_t>::iterator,
meta_index_map_type>
meta_components_map_type;
meta_components_map_type mg_component(mg_component_vec.begin(),
meta_index);
std::size_t num_comp = connected_components(mg, mg_component);
// Update Parent pointers
std::vector<meta_vertex_descriptor> roots(num_comp, graph_traits<metaGraph>::null_vertex());
BGL_FORALL_VERTICES_T(v, mg, metaGraph) {
size_t component = get(mg_component, v);
if (roots[component] == graph_traits<metaGraph>::null_vertex() ||
get(meta_index, v) < get(meta_index, roots[component]))
roots[component] = v;
}
// Set all the local parent pointers
BGL_FORALL_VERTICES_T(v, mg, metaGraph) {
// Problem in value being put (3rd parameter)
put(p, get(metaVertexMap, v), get(metaVertexMap, roots[get(mg_component, v)]));
}
}
synchronize(p);
}
#endif
/* Function object used to remove internal vertices and vertices >
the current vertex from the adjacent vertex lists at each
root */
template <typename Vertex, typename ParentMap>
class cull_adjacency_list
{
public:
cull_adjacency_list(const Vertex v, const ParentMap p) : v(v), p(p) {}
bool operator() (const Vertex x) { return (get(p, x) == v || x == v); }
private:
const Vertex v;
const ParentMap p;
};
/* Comparison operator used to choose targets for hooking s.t. vertices
that are hooked to are evenly distributed across processors */
template <typename OwnerMap, typename LocalMap>
class hashed_vertex_compare
{
public:
hashed_vertex_compare (const OwnerMap& o, const LocalMap& l)
: owner(o), local(l) { }
template <typename Vertex>
bool operator() (const Vertex x, const Vertex y)
{
if (get(local, x) < get(local, y))
return true;
else if (get(local, x) == get(local, y))
return (get(owner, x) < get(owner, y));
return false;
}
private:
OwnerMap owner;
LocalMap local;
};
#ifdef PBGL_EXPLICIT_SYNCH
template <typename Graph, typename ParentMap, typename VertexList>
void
request_parent_map_entries(const Graph& g, ParentMap p,
std::vector<VertexList>& parent_requests)
{
typedef typename boost::graph::parallel::process_group_type<Graph>
::type process_group_type;
typedef typename process_group_type::process_id_type process_id_type;
typedef typename graph_traits<Graph>::vertex_descriptor
vertex_descriptor;
process_group_type pg = process_group(g);
/*
This should probably be send_oob_with_reply, especially when Dave
finishes prefetch-batching
*/
// Send root requests
for (process_id_type i = 0; i < num_processes(pg); ++i) {
if (!parent_requests[i].empty()) {
std::vector<vertex_descriptor> reqs(parent_requests[i].begin(),
parent_requests[i].end());
send(pg, i, req_parents_msg, reqs);
}
}
synchronize(pg);
// Receive root requests and reply to them
while (optional<std::pair<process_id_type, int> > m = probe(pg)) {
std::vector<vertex_descriptor> requests;
receive(pg, m->first, m->second, requests);
for (std::size_t i = 0; i < requests.size(); ++i)
requests[i] = get(p, requests[i]);
send(pg, m->first, parents_msg, requests);
}
synchronize(pg);
// Receive requested parents
std::vector<vertex_descriptor> responses;
for (process_id_type i = 0; i < num_processes(pg); ++i) {
if (!parent_requests[i].empty()) {
receive(pg, i, parents_msg, responses);
std::size_t parent_idx = 0;
for (typename VertexList::iterator v = parent_requests[i].begin();
v != parent_requests[i].end(); ++v, ++parent_idx)
put(p, *v, responses[parent_idx]);
}
}
}
#endif
template<typename DistributedGraph, typename ParentMap>
void
parallel_connected_components(DistributedGraph& g, ParentMap p)
{
using boost::connected_components;
typedef typename graph_traits<DistributedGraph>::adjacency_iterator
adjacency_iterator;
typedef typename graph_traits<DistributedGraph>::out_edge_iterator
out_edge_iterator;
typedef typename graph_traits<DistributedGraph>::edge_iterator
edge_iterator;
typedef typename graph_traits<DistributedGraph>::vertex_descriptor
vertex_descriptor;
typedef typename graph_traits<DistributedGraph>::edge_descriptor
edge_descriptor;
typedef typename boost::graph::parallel::process_group_type<DistributedGraph>
::type process_group_type;
typedef typename process_group_type::process_id_type process_id_type;
using boost::graph::parallel::process_group;
process_group_type pg = process_group(g);
process_id_type id = process_id(pg);
// TODO (NGE): Should old_roots, roots, and completed_roots be std::list
adjacency_iterator av1, av2;
std::vector<vertex_descriptor> old_roots;
typename std::vector<vertex_descriptor>::iterator liter;
typename std::vector<vertex_descriptor>::iterator aliter;
typename std::map<vertex_descriptor,
std::vector<vertex_descriptor> > adj;
typedef typename property_map<DistributedGraph, vertex_owner_t>::const_type
OwnerMap;
OwnerMap owner = get(vertex_owner, g);
typedef typename property_map<DistributedGraph, vertex_local_t>::const_type
LocalMap;
LocalMap local = get(vertex_local, g);
// We need to hold on to all of the parent pointers
p.set_max_ghost_cells(0);
//
// STAGE 1 : Compute local components
//
local_subgraph<const DistributedGraph> ls(g);
typedef typename property_map<local_subgraph<const DistributedGraph>,
vertex_index_t>::type local_index_map_type;
local_index_map_type local_index = get(vertex_index, ls);
// Compute local connected components
std::vector<std::size_t> ls_components_vec(num_vertices(ls));
typedef iterator_property_map<std::vector<std::size_t>::iterator,
local_index_map_type>
ls_components_map_type;
ls_components_map_type ls_component(ls_components_vec.begin(),
local_index);
std::size_t num_comp = connected_components(ls, ls_component);
std::vector<vertex_descriptor>
roots(num_comp, graph_traits<DistributedGraph>::null_vertex());
BGL_FORALL_VERTICES_T(v, g, DistributedGraph) {
size_t component = get(ls_component, v);
if (roots[component] == graph_traits<DistributedGraph>::null_vertex() ||
get(local_index, v) < get(local_index, roots[component]))
roots[component] = v;
}
// Set all the local parent pointers
BGL_FORALL_VERTICES_T(v, g, DistributedGraph) {
put(p, v, roots[get(ls_component, v)]);
}
if (num_processes(pg) == 1) return;
// Build adjacency list for all roots
BGL_FORALL_VERTICES_T(v, g, DistributedGraph) {
std::vector<vertex_descriptor>& my_adj = adj[get(p, v)];
for (boost::tie(av1, av2) = adjacent_vertices(v, g);
av1 != av2; ++av1) {
if (get(owner, *av1) != id) my_adj.push_back(*av1);
}
}
// For all vertices adjacent to a local vertex get p(v)
for ( liter = roots.begin(); liter != roots.end(); ++liter ) {
std::vector<vertex_descriptor>& my_adj = adj[*liter];
for ( aliter = my_adj.begin(); aliter != my_adj.end(); ++aliter )
request(p, *aliter);
}
synchronize(p);
// Update adjacency list at root to make sure all adjacent
// vertices are roots of remote components
for ( liter = roots.begin(); liter != roots.end(); ++liter )
{
std::vector<vertex_descriptor>& my_adj = adj[*liter];
for ( aliter = my_adj.begin(); aliter != my_adj.end(); ++aliter )
*aliter = get(p, *aliter);
my_adj.erase
(std::remove_if(my_adj.begin(), my_adj.end(),
cull_adjacency_list<vertex_descriptor,
ParentMap>(*liter, p) ),
my_adj.end());
// This sort needs to be here to make sure the initial
// adjacency list is sorted
std::sort(my_adj.begin(), my_adj.end(), std::less<vertex_descriptor>());
my_adj.erase(std::unique(my_adj.begin(), my_adj.end()), my_adj.end());
}
// Get p(v) for the new adjacent roots
p.clear();
for ( liter = roots.begin(); liter != roots.end(); ++liter ) {
std::vector<vertex_descriptor>& my_adj = adj[*liter];
for ( aliter = my_adj.begin(); aliter != my_adj.end(); ++aliter )
request(p, *aliter);
}
#ifdef PBGL_EXPLICIT_SYNCH
synchronize(p);
#endif
// Lastly, remove roots with no adjacent vertices, this is
// unnecessary but will speed up sparse graphs
for ( liter = roots.begin(); liter != roots.end(); /*in loop*/)
{
if ( adj[*liter].empty() )
liter = roots.erase(liter);
else
++liter;
}
#ifdef PBGL_CONSTRUCT_METAGRAPH
/* TODO: If the number of roots is sufficiently small, we can
use a 'problem folding' approach like we do in MST
to gather all the roots and their adjacencies on one proc
and solve for the connected components of the meta-graph */
using boost::parallel::all_reduce;
std::size_t num_roots = all_reduce(pg, roots.size(), std::plus<std::size_t>());
if (num_roots < MAX_VERTICES_IN_METAGRAPH) {
build_local_metagraph(g, p, roots.begin(), roots.end(), adj);
// For each vertex in g, p(v) = p(p(v)), assign parent of leaf
// vertices from first step to final parent
BGL_FORALL_VERTICES_T(v, g, DistributedGraph) {
put(p, v, get(p, get(p, v)));
}
synchronize(p);
return;
}
#endif
//
// Parallel Phase
//
std::vector<vertex_descriptor> completed_roots;
hashed_vertex_compare<OwnerMap, LocalMap> v_compare(owner, local);
bool any_hooked;
vertex_descriptor new_root;
std::size_t steps = 0;
do {
++steps;
// Pull in new parents for hooking phase
synchronize(p);
//
// Hooking
//
bool hooked = false;
completed_roots.clear();
for ( liter = roots.begin(); liter != roots.end(); )
{
new_root = graph_traits<DistributedGraph>::null_vertex();
std::vector<vertex_descriptor>& my_adj = adj[*liter];
for ( aliter = my_adj.begin(); aliter != my_adj.end(); ++aliter )
// try to hook to better adjacent vertex
if ( v_compare( get(p, *aliter), *liter ) )
new_root = get(p, *aliter);
if ( new_root != graph_traits<DistributedGraph>::null_vertex() )
{
hooked = true;
put(p, *liter, new_root);
old_roots.push_back(*liter);
completed_roots.push_back(*liter);
liter = roots.erase(liter);
}
else
++liter;
}
//
// Pointer jumping, perform until new roots determined
//
// TODO: Implement cycle reduction rules to reduce this from
// O(n) to O(log n) [n = cycle length]
bool all_done;
std::size_t parent_root_count;
std::size_t double_steps = 0;
do {
++double_steps;
#ifndef PBGL_EXPLICIT_SYNCH
// Get p(p(v)) for all old roots, and p(v) for all current roots
for ( liter = old_roots.begin(); liter != old_roots.end(); ++liter )
request(p, get(p, *liter));
synchronize(p);
#else
// Build root requests
typedef std::set<vertex_descriptor> VertexSet;
std::vector<VertexSet> parent_requests(num_processes(pg));
for ( liter = old_roots.begin(); liter != old_roots.end(); ++liter )
{
vertex_descriptor p1 = *liter;
if (get(owner, p1) != id) parent_requests[get(owner, p1)].insert(p1);
vertex_descriptor p2 = get(p, p1);
if (get(owner, p2) != id) parent_requests[get(owner, p2)].insert(p2);
}
request_parent_map_entries(g, p, parent_requests);
#endif
// Perform a pointer jumping step on all old roots
for ( liter = old_roots.begin(); liter != old_roots.end(); ++liter )
put(p, *liter, get(p, get(p, *liter)));
// make sure the parent of all old roots is itself a root
parent_root_count = 0;
for ( liter = old_roots.begin(); liter != old_roots.end(); ++liter )
if ( get(p, *liter) == get(p, get(p, *liter)) )
parent_root_count++;
bool done = parent_root_count == old_roots.size();
all_reduce(pg, &done, &done+1, &all_done,
std::logical_and<bool>());
} while ( !all_done );
#ifdef PARALLEL_BGL_DEBUG
if (id == 0) std::cerr << double_steps << " doubling steps.\n";
#endif
//
// Add adjacent vertices of just completed roots to adjacent
// vertex list at new parent
//
typename std::vector<vertex_descriptor> outgoing_edges;
for ( liter = completed_roots.begin(); liter != completed_roots.end();
++liter )
{
vertex_descriptor new_parent = get(p, *liter);
if ( get(owner, new_parent) == id )
{
std::vector<vertex_descriptor>& my_adj = adj[new_parent];
my_adj.reserve(my_adj.size() + adj[*liter].size());
my_adj.insert( my_adj.end(),
adj[*liter].begin(), adj[*liter].end() );
#ifdef PBGL_IN_PLACE_MERGE
#ifdef PBGL_SORT_ASSERT
BOOST_ASSERT(::boost::detail::is_sorted(my_adj.begin(),
my_adj.end() - adj[*liter].size(),
std::less<vertex_descriptor>()));
BOOST_ASSERT(::boost::detail::is_sorted(my_adj.end() - adj[*liter].size(),
my_adj.end(),
std::less<vertex_descriptor>()));
#endif
std::inplace_merge(my_adj.begin(),
my_adj.end() - adj[*liter].size(),
my_adj.end(),
std::less<vertex_descriptor>());
#endif
}
else if ( adj[*liter].begin() != adj[*liter].end() )
{
outgoing_edges.clear();
outgoing_edges.reserve(adj[*liter].size() + 1);
// First element is the destination of the adjacency list
outgoing_edges.push_back(new_parent);
outgoing_edges.insert(outgoing_edges.end(),
adj[*liter].begin(), adj[*liter].end() );
send(pg, get(owner, new_parent), edges_msg, outgoing_edges);
adj[*liter].clear();
}
}
synchronize(pg);
// Receive edges sent by remote nodes and add them to the
// indicated vertex's adjacency list
while (optional<std::pair<process_id_type, int> > m
= probe(pg))
{
std::vector<vertex_descriptor> incoming_edges;
receive(pg, m->first, edges_msg, incoming_edges);
typename std::vector<vertex_descriptor>::iterator aviter
= incoming_edges.begin();
++aviter;
std::vector<vertex_descriptor>& my_adj = adj[incoming_edges[0]];
my_adj.reserve(my_adj.size() + incoming_edges.size() - 1);
my_adj.insert( my_adj.end(), aviter, incoming_edges.end() );
#ifdef PBGL_IN_PLACE_MERGE
std::size_t num_incoming_edges = incoming_edges.size();
#ifdef PBGL_SORT_ASSERT
BOOST_ASSERT(::boost::detail::is_sorted(my_adj.begin(),
my_adj.end() - (num_incoming_edges-1),
std::less<vertex_descriptor>()));
BOOST_ASSERT(::boost::detail::is_sorted(my_adj.end() - (num_incoming_edges-1),
my_adj.end(),
std::less<vertex_descriptor>()));
#endif
std::inplace_merge(my_adj.begin(),
my_adj.end() - (num_incoming_edges - 1),
my_adj.end(),
std::less<vertex_descriptor>());
#endif
}
// Remove any adjacent vertices that are in the same component
// as a root from that root's list
for ( liter = roots.begin(); liter != roots.end(); ++liter )
{
// We can probably get away without sorting and removing
// duplicates Though sorting *may* cause root
// determination to occur faster by choosing the root with
// the most potential to hook to at each step
std::vector<vertex_descriptor>& my_adj = adj[*liter];
my_adj.erase
(std::remove_if(my_adj.begin(), my_adj.end(),
cull_adjacency_list<vertex_descriptor,
ParentMap>(*liter, p) ),
my_adj.end());
#ifndef PBGL_IN_PLACE_MERGE
std::sort(my_adj.begin(), my_adj.end(),
std::less<vertex_descriptor>() );
#endif
my_adj.erase(std::unique(my_adj.begin(), my_adj.end()), my_adj.end());
}
// Reduce result of empty root list test
all_reduce(pg, &hooked, &hooked+1, &any_hooked,
std::logical_or<bool>());
} while ( any_hooked );
#ifdef PARALLEL_BGL_DEBUG
if (id == 0) std::cerr << steps << " iterations.\n";
#endif
//
// Finalize
//
// For each vertex in g, p(v) = p(p(v)), assign parent of leaf
// vertices from first step to final parent
BGL_FORALL_VERTICES_T(v, g, DistributedGraph) {
put(p, v, get(p, get(p, v)));
}
synchronize(p);
}
} // end namespace cc_detail
template<typename Graph, typename ParentMap, typename ComponentMap>
typename property_traits<ComponentMap>::value_type
number_components_from_parents(const Graph& g, ParentMap p, ComponentMap c)
{
typedef typename graph_traits<Graph>::vertex_descriptor
vertex_descriptor;
typedef typename boost::graph::parallel::process_group_type<Graph>::type
process_group_type;
typedef typename property_traits<ComponentMap>::value_type
ComponentMapType;
process_group_type pg = process_group(g);
/* Build list of roots */
std::vector<vertex_descriptor> my_roots, all_roots;
BGL_FORALL_VERTICES_T(v, g, Graph) {
if( std::find( my_roots.begin(), my_roots.end(), get(p, v) )
== my_roots.end() )
my_roots.push_back( get(p, v) );
}
all_gather(pg, my_roots.begin(), my_roots.end(), all_roots);
/* Number components */
std::map<vertex_descriptor, ComponentMapType> comp_numbers;
ComponentMapType c_num = 0;
// Compute component numbers
for (std::size_t i = 0; i < all_roots.size(); i++ )
if ( comp_numbers.count(all_roots[i]) == 0 )
comp_numbers[all_roots[i]] = c_num++;
// Broadcast component numbers
BGL_FORALL_VERTICES_T(v, g, Graph) {
put( c, v, comp_numbers[get(p, v)] );
}
// Broadcast number of components
if (process_id(pg) == 0) {
typedef typename process_group_type::process_size_type
process_size_type;
for (process_size_type dest = 1, n = num_processes(pg);
dest != n; ++dest)
send(pg, dest, 0, c_num);
}
synchronize(pg);
if (process_id(pg) != 0) receive(pg, 0, 0, c_num);
synchronize(c);
return c_num;
}
template<typename Graph, typename ParentMap>
int
number_components_from_parents(const Graph& g, ParentMap p,
dummy_property_map)
{
using boost::parallel::all_reduce;
// Count local roots.
int num_roots = 0;
BGL_FORALL_VERTICES_T(v, g, Graph)
if (get(p, v) == v) ++num_roots;
return all_reduce(g.process_group(), num_roots, std::plus<int>());
}
template<typename Graph, typename ComponentMap, typename ParentMap>
typename property_traits<ComponentMap>::value_type
connected_components
(const Graph& g, ComponentMap c, ParentMap p
BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph, distributed_graph_tag))
{
cc_detail::parallel_connected_components(g, p);
return number_components_from_parents(g, p, c);
}
/* Construct ParentMap by default */
template<typename Graph, typename ComponentMap>
typename property_traits<ComponentMap>::value_type
connected_components
( const Graph& g, ComponentMap c
BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph, distributed_graph_tag) )
{
typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
std::vector<vertex_descriptor> x(num_vertices(g));
return connected_components
(g, c,
make_iterator_property_map(x.begin(), get(vertex_index, g)));
}
} // end namespace distributed
using distributed::connected_components;
} // end namespace graph
using graph::distributed::connected_components;
} // end namespace boost
#endif // BOOST_GRAPH_PARALLEL_CC_HPP
@@ -0,0 +1,409 @@
// Copyright (C) 2004-2006 The Trustees of Indiana University.
// Use, modification and distribution is subject to 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)
// Authors: Brian Barrett
// Douglas Gregor
// Andrew Lumsdaine
#ifndef BOOST_GRAPH_PARALLEL_CC_PS_HPP
#define BOOST_GRAPH_PARALLEL_CC_PS_HPP
#ifndef BOOST_GRAPH_USE_MPI
#error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
#endif
#include <boost/assert.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/graph/parallel/algorithm.hpp>
#include <boost/pending/indirect_cmp.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/overloading.hpp>
#include <boost/graph/distributed/concepts.hpp>
#include <boost/graph/parallel/properties.hpp>
#include <boost/graph/parallel/process_group.hpp>
#include <boost/optional.hpp>
#include <algorithm>
#include <vector>
#include <queue>
#include <limits>
#include <map>
#include <boost/graph/parallel/container_traits.hpp>
#include <boost/graph/iteration_macros.hpp>
// Connected components algorithm based on a parallel search.
//
// Every N nodes starts a parallel search from the first vertex in
// their local vertex list during the first superstep (the other nodes
// remain idle during the first superstep to reduce the number of
// conflicts in numbering the components). At each superstep, all new
// component mappings from remote nodes are handled. If there is no
// work from remote updates, a new vertex is removed from the local
// list and added to the work queue.
//
// Components are allocated from the component_value_allocator object,
// which ensures that a given component number is unique in the
// system, currently by using the rank and number of processes to
// stride allocations.
//
// When two components are discovered to actually be the same
// component, a mapping is created in the collisions object. The
// lower component number is prefered in the resolution, so component
// numbering resolution is consistent. After the search has exhausted
// all vertices in the graph, the mapping is shared with all
// processes, and they independently resolve the comonent mapping (so
// O((N * NP) + (V * NP)) work, in O(N + V) time, where N is the
// number of mappings and V is the number of local vertices). This
// phase can likely be significantly sped up if a clever algorithm for
// the reduction can be found.
namespace boost { namespace graph { namespace distributed {
namespace cc_ps_detail {
// Local object for allocating component numbers. There are two
// places this happens in the code, and I was getting sick of them
// getting out of sync. Components are not tightly packed in
// numbering, but are numbered to ensure each rank has its own
// independent sets of numberings.
template<typename component_value_type>
class component_value_allocator {
public:
component_value_allocator(int num, int size) :
last(0), num(num), size(size)
{
}
component_value_type allocate(void)
{
component_value_type ret = num + (last * size);
last++;
return ret;
}
private:
component_value_type last;
int num;
int size;
};
// Map of the "collisions" between component names in the global
// component mapping. TO make cleanup easier, component numbers
// are added, pointing to themselves, when a new component is
// found. In order to make the results deterministic, the lower
// component number is always taken. The resolver will drill
// through the map until it finds a component entry that points to
// itself as the next value, allowing some cleanup to happen at
// update() time. Attempts are also made to update the mapping
// when new entries are created.
//
// Note that there's an assumption that the entire mapping is
// shared during the end of the algorithm, but before component
// name resolution.
template<typename component_value_type>
class collision_map {
public:
collision_map() : num_unique(0)
{
}
// add new component mapping first time component is used. Own
// function only so that we can sanity check there isn't already
// a mapping for that component number (which would be bad)
void add(const component_value_type &a)
{
BOOST_ASSERT(collisions.count(a) == 0);
collisions[a] = a;
}
// add a mapping between component values saying they're the
// same component
void add(const component_value_type &a, const component_value_type &b)
{
component_value_type high, low, tmp;
if (a > b) {
high = a;
low = b;
} else {
high = b;
low = a;
}
if (collisions.count(high) != 0 && collisions[high] != low) {
tmp = collisions[high];
if (tmp > low) {
collisions[tmp] = low;
collisions[high] = low;
} else {
collisions[low] = tmp;
collisions[high] = tmp;
}
} else {
collisions[high] = low;
}
}
// get the "real" component number for the given component.
// Used to resolve mapping at end of run.
component_value_type update(component_value_type a)
{
BOOST_ASSERT(num_unique > 0);
BOOST_ASSERT(collisions.count(a) != 0);
return collisions[a];
}
// collapse the collisions tree, so that update is a one lookup
// operation. Count unique components at the same time.
void uniqify(void)
{
typename std::map<component_value_type, component_value_type>::iterator i, end;
end = collisions.end();
for (i = collisions.begin() ; i != end ; ++i) {
if (i->first == i->second) {
num_unique++;
} else {
i->second = collisions[i->second];
}
}
}
// get the number of component entries that have an associated
// component number of themselves, which are the real components
// used in the final mapping. This is the number of unique
// components in the graph.
int unique(void)
{
BOOST_ASSERT(num_unique > 0);
return num_unique;
}
// "serialize" into a vector for communication.
std::vector<component_value_type> serialize(void)
{
std::vector<component_value_type> ret;
typename std::map<component_value_type, component_value_type>::iterator i, end;
end = collisions.end();
for (i = collisions.begin() ; i != end ; ++i) {
ret.push_back(i->first);
ret.push_back(i->second);
}
return ret;
}
private:
std::map<component_value_type, component_value_type> collisions;
int num_unique;
};
// resolver to handle remote updates. The resolver will add
// entries into the collisions map if required, and if it is the
// first time the vertex has been touched, it will add the vertex
// to the remote queue. Note that local updates are handled
// differently, in the main loop (below).
// BWB - FIX ME - don't need graph anymore - can pull from key value of Component Map.
template<typename ComponentMap, typename work_queue>
struct update_reducer {
BOOST_STATIC_CONSTANT(bool, non_default_resolver = false);
typedef typename property_traits<ComponentMap>::value_type component_value_type;
typedef typename property_traits<ComponentMap>::key_type vertex_descriptor;
update_reducer(work_queue *q,
cc_ps_detail::collision_map<component_value_type> *collisions,
processor_id_type pg_id) :
q(q), collisions(collisions), pg_id(pg_id)
{
}
// ghost cell initialization routine. This should never be
// called in this imlementation.
template<typename K>
component_value_type operator()(const K&) const
{
return component_value_type(0);
}
// resolver for remote updates. I'm not entirely sure why, but
// I decided to not change the value of the vertex if it's
// already non-infinite. It doesn't matter in the end, as we'll
// touch every vertex in the cleanup phase anyway. If the
// component is currently infinite, set to the new component
// number and add the vertex to the work queue. If it's not
// infinite, we've touched it already so don't add it to the
// work queue. Do add a collision entry so that we know the two
// components are the same.
component_value_type operator()(const vertex_descriptor &v,
const component_value_type& current,
const component_value_type& update) const
{
const component_value_type max = (std::numeric_limits<component_value_type>::max)();
component_value_type ret = current;
if (max == current) {
q->push(v);
ret = update;
} else if (current != update) {
collisions->add(current, update);
}
return ret;
}
// So for whatever reason, the property map can in theory call
// the resolver with a local descriptor in addition to the
// standard global descriptor. As far as I can tell, this code
// path is never taken in this implementation, but I need to
// have this code here to make it compile. We just make a
// global descriptor and call the "real" operator().
template<typename K>
component_value_type operator()(const K& v,
const component_value_type& current,
const component_value_type& update) const
{
return (*this)(vertex_descriptor(pg_id, v), current, update);
}
private:
work_queue *q;
collision_map<component_value_type> *collisions;
boost::processor_id_type pg_id;
};
} // namespace cc_ps_detail
template<typename Graph, typename ComponentMap>
typename property_traits<ComponentMap>::value_type
connected_components_ps(const Graph& g, ComponentMap c)
{
using boost::graph::parallel::process_group;
typedef typename property_traits<ComponentMap>::value_type component_value_type;
typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
typedef typename boost::graph::parallel::process_group_type<Graph>
::type process_group_type;
typedef typename process_group_type::process_id_type process_id_type;
typedef typename property_map<Graph, vertex_owner_t>
::const_type vertex_owner_map;
typedef std::queue<vertex_descriptor> work_queue;
static const component_value_type max_component =
(std::numeric_limits<component_value_type>::max)();
typename property_map<Graph, vertex_owner_t>::const_type
owner = get(vertex_owner, g);
// standard who am i? stuff
process_group_type pg = process_group(g);
process_id_type id = process_id(pg);
// Initialize every vertex to have infinite component number
BGL_FORALL_VERTICES_T(v, g, Graph) put(c, v, max_component);
vertex_iterator current, end;
boost::tie(current, end) = vertices(g);
cc_ps_detail::component_value_allocator<component_value_type> cva(process_id(pg), num_processes(pg));
cc_ps_detail::collision_map<component_value_type> collisions;
work_queue q; // this is intentionally a local data structure
c.set_reduce(cc_ps_detail::update_reducer<ComponentMap, work_queue>(&q, &collisions, id));
// add starting work
while (true) {
bool useful_found = false;
component_value_type val = cva.allocate();
put(c, *current, val);
collisions.add(val);
q.push(*current);
if (0 != out_degree(*current, g)) useful_found = true;
++current;
if (useful_found) break;
}
// Run the loop until everyone in the system is done
bool global_done = false;
while (!global_done) {
// drain queue of work for this superstep
while (!q.empty()) {
vertex_descriptor v = q.front();
q.pop();
// iterate through outedges of the vertex currently being
// examined, setting their component to our component. There
// is no way to end up in the queue without having a component
// number already.
BGL_FORALL_ADJ_T(v, peer, g, Graph) {
component_value_type my_component = get(c, v);
// update other vertex with our component information.
// Resolver will handle remote collisions as well as whether
// to put the vertex on the work queue or not. We have to
// handle local collisions and work queue management
if (id == get(owner, peer)) {
if (max_component == get(c, peer)) {
put(c, peer, my_component);
q.push(peer);
} else if (my_component != get(c, peer)) {
collisions.add(my_component, get(c, peer));
}
} else {
put(c, peer, my_component);
}
}
}
// synchronize / start a new superstep.
synchronize(pg);
global_done = all_reduce(pg, (q.empty() && (current == end)), boost::parallel::minimum<bool>());
// If the queue is currently empty, add something to do to start
// the current superstep (supersteps start at the sync, not at
// the top of the while loop as one might expect). Down at the
// bottom of the while loop so that not everyone starts the
// algorithm with something to do, to try to reduce component
// name conflicts
if (q.empty()) {
bool useful_found = false;
for ( ; current != end && !useful_found ; ++current) {
if (max_component == get(c, *current)) {
component_value_type val = cva.allocate();
put(c, *current, val);
collisions.add(val);
q.push(*current);
if (0 != out_degree(*current, g)) useful_found = true;
}
}
}
}
// share component mappings
std::vector<component_value_type> global;
std::vector<component_value_type> mine = collisions.serialize();
all_gather(pg, mine.begin(), mine.end(), global);
for (size_t i = 0 ; i < global.size() ; i += 2) {
collisions.add(global[i], global[i + 1]);
}
collisions.uniqify();
// update the component mappings
BGL_FORALL_VERTICES_T(v, g, Graph) {
put(c, v, collisions.update(get(c, v)));
}
return collisions.unique();
}
} // end namespace distributed
} // end namespace graph
} // end namespace boost
#endif // BOOST_GRAPH_PARALLEL_CC_HPP
@@ -0,0 +1,665 @@
// Copyright (C) 2004-2006 The Trustees of Indiana University.
// Use, modification and distribution is subject to 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)
// Authors: Douglas Gregor
// Andrew Lumsdaine
/**************************************************************************
* This source file implements the variation on Dijkstra's algorithm *
* presented by Crauser et al. in: *
* *
* Andreas Crauser, Kurt Mehlhorn, Ulrich Meyer, and Peter *
* Sanders. A Parallelization of Dijkstra's Shortest Path *
* Algorithm. In Lubos Brim, Jozef Gruska, and Jiri Zlatuska, *
* editors, Mathematical Foundations of Computer Science (MFCS), *
* volume 1450 of Lecture Notes in Computer Science, pages *
* 722--731, 1998. Springer. *
* *
* This implementation is, however, restricted to the distributed-memory *
* case, where the work is distributed by virtue of the vertices being *
* distributed. In a shared-memory (single address space) context, we *
* would want to add an explicit balancing step. *
**************************************************************************/
#ifndef BOOST_GRAPH_CRAUSER_ET_AL_SHORTEST_PATHS_HPP
#define BOOST_GRAPH_CRAUSER_ET_AL_SHORTEST_PATHS_HPP
#ifndef BOOST_GRAPH_USE_MPI
#error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
#endif
#include <boost/assert.hpp>
#include <boost/graph/distributed/detail/dijkstra_shortest_paths.hpp>
#include <boost/graph/parallel/algorithm.hpp>
#include <functional>
#include <boost/graph/iteration_macros.hpp>
#include <boost/property_map/property_map_iterator.hpp>
#include <boost/type_traits/is_same.hpp>
#include <algorithm>
#include <boost/property_map/parallel/caching_property_map.hpp>
#include <boost/pending/indirect_cmp.hpp>
#include <boost/graph/distributed/detail/remote_update_set.hpp>
#include <vector>
#include <boost/graph/breadth_first_search.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <boost/graph/parallel/container_traits.hpp>
#ifdef PBGL_ACCOUNTING
# include <boost/graph/accounting.hpp>
# include <numeric>
#endif // PBGL_ACCOUNTING
#ifdef MUTABLE_QUEUE
# include <boost/pending/mutable_queue.hpp>
#endif
namespace boost { namespace graph { namespace distributed {
#ifdef PBGL_ACCOUNTING
struct crauser_et_al_shortest_paths_stats_t
{
/* Total wall-clock time used by the algorithm.*/
accounting::time_type execution_time;
/* The number of vertices deleted in each superstep. */
std::vector<std::size_t> deleted_vertices;
template<typename OutputStream>
void print(OutputStream& out)
{
double avg_deletions = std::accumulate(deleted_vertices.begin(),
deleted_vertices.end(),
0.0);
avg_deletions /= deleted_vertices.size();
out << "Problem = \"Single-Source Shortest Paths\"\n"
<< "Algorithm = \"Crauser et al\"\n"
<< "Function = crauser_et_al_shortest_paths\n"
<< "Wall clock time = " << accounting::print_time(execution_time)
<< "\nSupersteps = " << deleted_vertices.size() << "\n"
<< "Avg. deletions per superstep = " << avg_deletions << "\n";
}
};
static crauser_et_al_shortest_paths_stats_t crauser_et_al_shortest_paths_stats;
#endif
namespace detail {
/************************************************************************
* Function objects that perform distance comparisons modified by the *
* minimum or maximum edge weights. *
************************************************************************/
template<typename Vertex, typename DistanceMap, typename MinInWeightMap,
typename Combine, typename Compare>
struct min_in_distance_compare
: std::binary_function<Vertex, Vertex, bool>
{
min_in_distance_compare(DistanceMap d, MinInWeightMap m,
Combine combine, Compare compare)
: distance_map(d), min_in_weight(m), combine(combine),
compare(compare)
{
}
bool operator()(const Vertex& x, const Vertex& y) const
{
return compare(combine(get(distance_map, x), -get(min_in_weight, x)),
combine(get(distance_map, y), -get(min_in_weight, y)));
}
private:
DistanceMap distance_map;
MinInWeightMap min_in_weight;
Combine combine;
Compare compare;
};
template<typename Vertex, typename DistanceMap, typename MinOutWeightMap,
typename Combine, typename Compare>
struct min_out_distance_compare
: std::binary_function<Vertex, Vertex, bool>
{
min_out_distance_compare(DistanceMap d, MinOutWeightMap m,
Combine combine, Compare compare)
: distance_map(d), min_out_weight(m), combine(combine),
compare(compare)
{
}
bool operator()(const Vertex& x, const Vertex& y) const
{
return compare(combine(get(distance_map, x), get(min_out_weight, x)),
combine(get(distance_map, y), get(min_out_weight, y)));
}
private:
DistanceMap distance_map;
MinOutWeightMap min_out_weight;
Combine combine;
Compare compare;
};
/************************************************************************/
/************************************************************************
* Dijkstra queue that implements Crauser et al.'s criteria. This queue *
* actually stores three separate priority queues, to help expose all *
* vertices that can be processed in a single phase. *
************************************************************************/
template<typename Graph, typename Combine,
typename Compare, typename VertexIndexMap, typename DistanceMap,
typename PredecessorMap, typename MinOutWeightMap,
typename MinInWeightMap>
class crauser_et_al_dijkstra_queue
: public graph::detail::remote_update_set<
crauser_et_al_dijkstra_queue<
Graph, Combine, Compare, VertexIndexMap, DistanceMap,
PredecessorMap, MinOutWeightMap, MinInWeightMap>,
typename boost::graph::parallel::process_group_type<Graph>::type,
typename dijkstra_msg_value<DistanceMap, PredecessorMap>::type,
typename property_map<Graph, vertex_owner_t>::const_type>
{
typedef typename graph_traits<Graph>::vertex_descriptor
vertex_descriptor;
typedef crauser_et_al_dijkstra_queue self_type;
typedef dijkstra_msg_value<DistanceMap, PredecessorMap> msg_value_creator;
typedef typename msg_value_creator::type msg_value_type;
typedef typename graph_traits<Graph>::vertices_size_type
vertices_size_type;
typedef typename property_map<Graph, vertex_owner_t>::const_type
OwnerPropertyMap;
typedef typename boost::graph::parallel::process_group_type<Graph>::type
process_group_type;
typedef graph::detail::remote_update_set<self_type, process_group_type,
msg_value_type, OwnerPropertyMap>
inherited;
// Priority queue for tentative distances
typedef indirect_cmp<DistanceMap, Compare> dist_queue_compare_type;
typedef typename property_traits<DistanceMap>::value_type distance_type;
#ifdef MUTABLE_QUEUE
typedef mutable_queue<vertex_descriptor, std::vector<vertex_descriptor>,
dist_queue_compare_type, VertexIndexMap> dist_queue_type;
#else
typedef relaxed_heap<vertex_descriptor, dist_queue_compare_type,
VertexIndexMap> dist_queue_type;
#endif // MUTABLE_QUEUE
// Priority queue for OUT criteria
typedef min_out_distance_compare<vertex_descriptor, DistanceMap,
MinOutWeightMap, Combine, Compare>
out_queue_compare_type;
#ifdef MUTABLE_QUEUE
typedef mutable_queue<vertex_descriptor, std::vector<vertex_descriptor>,
out_queue_compare_type, VertexIndexMap> out_queue_type;
#else
typedef relaxed_heap<vertex_descriptor, out_queue_compare_type,
VertexIndexMap> out_queue_type;
#endif // MUTABLE_QUEUE
// Priority queue for IN criteria
typedef min_in_distance_compare<vertex_descriptor, DistanceMap,
MinInWeightMap, Combine, Compare>
in_queue_compare_type;
#ifdef MUTABLE_QUEUE
typedef mutable_queue<vertex_descriptor, std::vector<vertex_descriptor>,
in_queue_compare_type, VertexIndexMap> in_queue_type;
#else
typedef relaxed_heap<vertex_descriptor, in_queue_compare_type,
VertexIndexMap> in_queue_type;
#endif // MUTABLE_QUEUE
typedef typename process_group_type::process_id_type process_id_type;
public:
typedef typename dist_queue_type::size_type size_type;
typedef typename dist_queue_type::value_type value_type;
crauser_et_al_dijkstra_queue(const Graph& g,
const Combine& combine,
const Compare& compare,
const VertexIndexMap& id,
const DistanceMap& distance_map,
const PredecessorMap& predecessor_map,
const MinOutWeightMap& min_out_weight,
const MinInWeightMap& min_in_weight)
: inherited(boost::graph::parallel::process_group(g), get(vertex_owner, g)),
dist_queue(num_vertices(g),
dist_queue_compare_type(distance_map, compare),
id),
out_queue(num_vertices(g),
out_queue_compare_type(distance_map, min_out_weight,
combine, compare),
id),
in_queue(num_vertices(g),
in_queue_compare_type(distance_map, min_in_weight,
combine, compare),
id),
g(g),
distance_map(distance_map),
predecessor_map(predecessor_map),
min_out_weight(min_out_weight),
min_in_weight(min_in_weight),
min_distance(0),
min_out_distance(0)
#ifdef PBGL_ACCOUNTING
, local_deletions(0)
#endif
{ }
void push(const value_type& x)
{
msg_value_type msg_value =
msg_value_creator::create(get(distance_map, x),
predecessor_value(get(predecessor_map, x)));
inherited::update(x, msg_value);
}
void update(const value_type& x) { push(x); }
void pop()
{
// Remove from distance queue
dist_queue.remove(top_vertex);
// Remove from OUT queue
out_queue.remove(top_vertex);
// Remove from IN queue
in_queue.remove(top_vertex);
#ifdef PBGL_ACCOUNTING
++local_deletions;
#endif
}
vertex_descriptor& top() { return top_vertex; }
const vertex_descriptor& top() const { return top_vertex; }
bool empty()
{
inherited::collect();
// If there are no suitable messages, wait until we get something
while (!has_suitable_vertex()) {
if (do_synchronize()) return true;
}
// Return true only if nobody has any messages; false if we
// have suitable messages
return false;
}
bool do_synchronize()
{
using boost::parallel::all_reduce;
using boost::parallel::minimum;
inherited::synchronize();
// TBD: could use combine here, but then we need to stop using
// minimum<distance_type>() as the function object.
distance_type local_distances[2];
local_distances[0] =
dist_queue.empty()? (std::numeric_limits<distance_type>::max)()
: get(distance_map, dist_queue.top());
local_distances[1] =
out_queue.empty()? (std::numeric_limits<distance_type>::max)()
: (get(distance_map, out_queue.top())
+ get(min_out_weight, out_queue.top()));
distance_type distances[2];
all_reduce(this->process_group, local_distances, local_distances + 2,
distances, minimum<distance_type>());
min_distance = distances[0];
min_out_distance = distances[1];
#ifdef PBGL_ACCOUNTING
std::size_t deletions = 0;
all_reduce(this->process_group, &local_deletions, &local_deletions + 1,
&deletions, std::plus<std::size_t>());
if (process_id(this->process_group) == 0) {
crauser_et_al_shortest_paths_stats.deleted_vertices.push_back(deletions);
}
local_deletions = 0;
BOOST_ASSERT(deletions > 0);
#endif
return min_distance == (std::numeric_limits<distance_type>::max)();
}
private:
vertex_descriptor predecessor_value(vertex_descriptor v) const
{ return v; }
vertex_descriptor
predecessor_value(property_traits<dummy_property_map>::reference) const
{ return graph_traits<Graph>::null_vertex(); }
bool has_suitable_vertex() const
{
if (!dist_queue.empty()) {
top_vertex = dist_queue.top();
if (get(distance_map, dist_queue.top()) <= min_out_distance)
return true;
}
if (!in_queue.empty()) {
top_vertex = in_queue.top();
return (get(distance_map, top_vertex)
- get(min_in_weight, top_vertex)) <= min_distance;
}
return false;
}
public:
void
receive_update(process_id_type source, vertex_descriptor vertex,
distance_type distance)
{
// Update the queue if the received distance is better than
// the distance we know locally
if (distance < get(distance_map, vertex)
|| (distance == get(distance_map, vertex)
&& source == process_id(this->process_group))) {
// Update the local distance map
put(distance_map, vertex, distance);
bool is_in_queue = dist_queue.contains(vertex);
if (!is_in_queue) {
dist_queue.push(vertex);
out_queue.push(vertex);
in_queue.push(vertex);
}
else {
dist_queue.update(vertex);
out_queue.update(vertex);
in_queue.update(vertex);
}
}
}
void
receive_update(process_id_type source, vertex_descriptor vertex,
std::pair<distance_type, vertex_descriptor> p)
{
if (p.first <= get(distance_map, vertex)) {
put(predecessor_map, vertex, p.second);
receive_update(source, vertex, p.first);
}
}
private:
dist_queue_type dist_queue;
out_queue_type out_queue;
in_queue_type in_queue;
mutable value_type top_vertex;
const Graph& g;
DistanceMap distance_map;
PredecessorMap predecessor_map;
MinOutWeightMap min_out_weight;
MinInWeightMap min_in_weight;
distance_type min_distance;
distance_type min_out_distance;
#ifdef PBGL_ACCOUNTING
std::size_t local_deletions;
#endif
};
/************************************************************************/
/************************************************************************
* Initialize the property map that contains the minimum incoming edge *
* weight for each vertex. There are separate implementations for *
* directed, bidirectional, and undirected graph. *
************************************************************************/
template<typename Graph, typename MinInWeightMap, typename WeightMap,
typename Inf, typename Compare>
void
initialize_min_in_weights(const Graph& g, MinInWeightMap min_in_weight,
WeightMap weight, Inf inf, Compare compare,
directed_tag, incidence_graph_tag)
{
// Send minimum weights off to the owners
set_property_map_role(vertex_distance, min_in_weight);
BGL_FORALL_VERTICES_T(v, g, Graph) {
BGL_FORALL_OUTEDGES_T(v, e, g, Graph) {
if (get(weight, e) < get(min_in_weight, target(e, g)))
put(min_in_weight, target(e, g), get(weight, e));
}
}
using boost::graph::parallel::process_group;
synchronize(process_group(g));
// Replace any infinities with zeros
BGL_FORALL_VERTICES_T(v, g, Graph) {
if (get(min_in_weight, v) == inf) put(min_in_weight, v, 0);
}
}
template<typename Graph, typename MinInWeightMap, typename WeightMap,
typename Inf, typename Compare>
void
initialize_min_in_weights(const Graph& g, MinInWeightMap min_in_weight,
WeightMap weight, Inf inf, Compare compare,
directed_tag, bidirectional_graph_tag)
{
#if 0
typename property_map<Graph, vertex_local_t>::const_type
local = get(vertex_local, g);
// This code assumes that the properties of the in-edges are
// available locally. This is not necessarily the case, so don't
// do this yet.
set_property_map_role(vertex_distance, min_in_weight);
BGL_FORALL_VERTICES_T(v, g, Graph) {
if (in_edges(v, g).first != in_edges(v, g).second) {
std::cerr << "weights(" << g.distribution().global(get(local, v))
<< ") = ";
BGL_FORALL_INEDGES_T(v, e, g, Graph) {
std::cerr << get(weight, e) << ' ';
}
std::cerr << std::endl;
put(min_in_weight, v,
*std::min_element
(make_property_map_iterator(weight, in_edges(v, g).first),
make_property_map_iterator(weight, in_edges(v, g).second),
compare));
} else {
put(min_in_weight, v, 0);
}
std::cerr << "miw(" << g.distribution().global(get(local, v)) << ") = "
<< get(min_in_weight, v) << std::endl;
}
#else
initialize_min_in_weights(g, min_in_weight, weight, inf, compare,
directed_tag(), incidence_graph_tag());
#endif
}
template<typename Graph, typename MinInWeightMap, typename WeightMap,
typename Inf, typename Compare>
inline void
initialize_min_in_weights(const Graph&, MinInWeightMap, WeightMap, Inf,
Compare, undirected_tag, bidirectional_graph_tag)
{
// In weights are the same as out weights, so do nothing
}
/************************************************************************/
/************************************************************************
* Initialize the property map that contains the minimum outgoing edge *
* weight for each vertex. *
************************************************************************/
template<typename Graph, typename MinOutWeightMap, typename WeightMap,
typename Compare>
void
initialize_min_out_weights(const Graph& g, MinOutWeightMap min_out_weight,
WeightMap weight, Compare compare)
{
typedef typename property_traits<WeightMap>::value_type weight_type;
BGL_FORALL_VERTICES_T(v, g, Graph) {
if (out_edges(v, g).first != out_edges(v, g).second) {
put(min_out_weight, v,
*std::min_element
(make_property_map_iterator(weight, out_edges(v, g).first),
make_property_map_iterator(weight, out_edges(v, g).second),
compare));
if (get(min_out_weight, v) < weight_type(0))
boost::throw_exception(negative_edge());
}
}
}
/************************************************************************/
} // end namespace detail
template<typename DistributedGraph, typename DijkstraVisitor,
typename PredecessorMap, typename DistanceMap, typename WeightMap,
typename IndexMap, typename ColorMap, typename Compare,
typename Combine, typename DistInf, typename DistZero>
void
crauser_et_al_shortest_paths
(const DistributedGraph& g,
typename graph_traits<DistributedGraph>::vertex_descriptor s,
PredecessorMap predecessor, DistanceMap distance, WeightMap weight,
IndexMap index_map, ColorMap color_map,
Compare compare, Combine combine, DistInf inf, DistZero zero,
DijkstraVisitor vis)
{
typedef typename boost::graph::parallel::process_group_type<DistributedGraph>::type
process_group_type;
typedef typename process_group_type::process_id_type process_id_type;
typedef typename graph_traits<DistributedGraph>::vertex_descriptor
Vertex;
typedef typename graph_traits<DistributedGraph>::vertices_size_type
vertices_size_type;
#ifdef PBGL_ACCOUNTING
crauser_et_al_shortest_paths_stats.deleted_vertices.clear();
crauser_et_al_shortest_paths_stats.execution_time = accounting::get_time();
#endif
// Property map that stores the lowest edge weight outgoing from
// each vertex. If a vertex has no out-edges, the stored weight
// is zero.
typedef typename property_traits<WeightMap>::value_type weight_type;
typedef iterator_property_map<weight_type*, IndexMap> MinOutWeightMap;
std::vector<weight_type> min_out_weights_vec(num_vertices(g), inf);
MinOutWeightMap min_out_weight(&min_out_weights_vec.front(), index_map);
detail::initialize_min_out_weights(g, min_out_weight, weight, compare);
// Property map that stores the lowest edge weight incoming to
// each vertex. For undirected graphs, this will just be a
// shallow copy of the version for outgoing edges.
typedef typename graph_traits<DistributedGraph>::directed_category
directed_category;
const bool is_undirected =
is_same<directed_category, undirected_tag>::value;
typedef MinOutWeightMap MinInWeightMap;
std::vector<weight_type>
min_in_weights_vec(is_undirected? 1 : num_vertices(g), inf);
MinInWeightMap min_in_weight(&min_in_weights_vec.front(), index_map);
typedef typename graph_traits<DistributedGraph>::traversal_category
category;
detail::initialize_min_in_weights(g, min_in_weight, weight, inf, compare,
directed_category(), category());
// Initialize local portion of property maps
typename graph_traits<DistributedGraph>::vertex_iterator ui, ui_end;
for (boost::tie(ui, ui_end) = vertices(g); ui != ui_end; ++ui) {
put(distance, *ui, inf);
put(predecessor, *ui, *ui);
}
put(distance, s, zero);
// Dijkstra Queue
typedef detail::crauser_et_al_dijkstra_queue
<DistributedGraph, Combine, Compare, IndexMap, DistanceMap,
PredecessorMap, MinOutWeightMap, MinInWeightMap>
Queue;
Queue Q(g, combine, compare, index_map, distance, predecessor,
min_out_weight, is_undirected? min_out_weight : min_in_weight);
// Parallel Dijkstra visitor
::boost::detail::dijkstra_bfs_visitor<
DijkstraVisitor, Queue, WeightMap,
boost::parallel::caching_property_map<PredecessorMap>,
boost::parallel::caching_property_map<DistanceMap>, Combine, Compare
> bfs_vis(vis, Q, weight,
boost::parallel::make_caching_property_map(predecessor),
boost::parallel::make_caching_property_map(distance),
combine, compare, zero);
set_property_map_role(vertex_color, color_map);
set_property_map_role(vertex_distance, distance);
breadth_first_search(g, s, Q, bfs_vis, color_map);
#ifdef PBGL_ACCOUNTING
crauser_et_al_shortest_paths_stats.execution_time =
accounting::get_time() - crauser_et_al_shortest_paths_stats.execution_time;
#endif
}
template<typename DistributedGraph, typename PredecessorMap,
typename DistanceMap, typename WeightMap>
void
crauser_et_al_shortest_paths
(const DistributedGraph& g,
typename graph_traits<DistributedGraph>::vertex_descriptor s,
PredecessorMap predecessor, DistanceMap distance, WeightMap weight)
{
typedef typename property_traits<DistanceMap>::value_type distance_type;
std::vector<default_color_type> colors(num_vertices(g), white_color);
crauser_et_al_shortest_paths(g, s, predecessor, distance, weight,
get(vertex_index, g),
make_iterator_property_map(&colors[0],
get(vertex_index, g)),
std::less<distance_type>(),
closed_plus<distance_type>(),
(std::numeric_limits<distance_type>::max)(),
distance_type(),
dijkstra_visitor<>());
}
template<typename DistributedGraph, typename PredecessorMap,
typename DistanceMap>
void
crauser_et_al_shortest_paths
(const DistributedGraph& g,
typename graph_traits<DistributedGraph>::vertex_descriptor s,
PredecessorMap predecessor, DistanceMap distance)
{
crauser_et_al_shortest_paths(g, s, predecessor, distance,
get(edge_weight, g));
}
} // end namespace distributed
#ifdef PBGL_ACCOUNTING
using distributed::crauser_et_al_shortest_paths_stats;
#endif
using distributed::crauser_et_al_shortest_paths;
} } // end namespace boost::graph
#endif // BOOST_GRAPH_CRAUSER_ET_AL_SHORTEST_PATHS_HPP
@@ -0,0 +1,938 @@
// Copyright (C) 2004-2006 The Trustees of Indiana University.
// Use, modification and distribution is subject to 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)
// Authors: Douglas Gregor
// Andrew Lumsdaine
/**
* This header implements four distributed algorithms to compute
* the minimum spanning tree (actually, minimum spanning forest) of a
* graph. All of the algorithms were implemented as specified in the
* paper by Dehne and Gotz:
*
* Frank Dehne and Silvia Gotz. Practical Parallel Algorithms for Minimum
* Spanning Trees. In Symposium on Reliable Distributed Systems,
* pages 366--371, 1998.
*
* There are four algorithm variants implemented.
*/
#ifndef BOOST_DEHNE_GOTZ_MIN_SPANNING_TREE_HPP
#define BOOST_DEHNE_GOTZ_MIN_SPANNING_TREE_HPP
#ifndef BOOST_GRAPH_USE_MPI
#error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
#endif
#include <boost/graph/graph_traits.hpp>
#include <boost/property_map/property_map.hpp>
#include <vector>
#include <boost/graph/parallel/algorithm.hpp>
#include <boost/limits.hpp>
#include <utility>
#include <boost/pending/disjoint_sets.hpp>
#include <boost/pending/indirect_cmp.hpp>
#include <boost/property_map/parallel/caching_property_map.hpp>
#include <boost/graph/vertex_and_edge_range.hpp>
#include <boost/graph/kruskal_min_spanning_tree.hpp>
#include <boost/iterator/counting_iterator.hpp>
#include <boost/iterator/transform_iterator.hpp>
#include <boost/graph/parallel/container_traits.hpp>
#include <boost/graph/parallel/detail/untracked_pair.hpp>
#include <cmath>
namespace boost { namespace graph { namespace distributed {
namespace detail {
/**
* Binary function object type that selects the (edge, weight) pair
* with the minimum weight. Used within a Boruvka merge step to select
* the candidate edges incident to each supervertex.
*/
struct smaller_weighted_edge
{
template<typename Edge, typename Weight>
std::pair<Edge, Weight>
operator()(const std::pair<Edge, Weight>& x,
const std::pair<Edge, Weight>& y) const
{ return x.second < y.second? x : y; }
};
/**
* Unary predicate that determines if the source and target vertices
* of the given edge have the same representative within a disjoint
* sets data structure. Used to indicate when an edge is now a
* self-loop because of supervertex merging in Boruvka's algorithm.
*/
template<typename DisjointSets, typename Graph>
class do_has_same_supervertex
{
public:
typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
do_has_same_supervertex(DisjointSets& dset, const Graph& g)
: dset(dset), g(g) { }
bool operator()(edge_descriptor e)
{ return dset.find_set(source(e, g)) == dset.find_set(target(e, g)); }
private:
DisjointSets& dset;
const Graph& g;
};
/**
* Build a @ref do_has_same_supervertex object.
*/
template<typename DisjointSets, typename Graph>
inline do_has_same_supervertex<DisjointSets, Graph>
has_same_supervertex(DisjointSets& dset, const Graph& g)
{ return do_has_same_supervertex<DisjointSets, Graph>(dset, g); }
/** \brief A single distributed Boruvka merge step.
*
* A distributed Boruvka merge step involves computing (globally)
* the minimum weight edges incident on each supervertex and then
* merging supervertices along these edges. Once supervertices are
* merged, self-loops are eliminated.
*
* The set of parameters passed to this algorithm is large, and
* considering this algorithm in isolation there are several
* redundancies. However, the more asymptotically efficient
* distributed MSF algorithms require mixing Boruvka steps with the
* merging of local MSFs (implemented in
* merge_local_minimum_spanning_trees_step): the interaction of the
* two algorithms mandates the addition of these parameters.
*
* \param pg The process group over which communication should be
* performed. Within the distributed Boruvka algorithm, this will be
* equivalent to \code process_group(g); however, in the context of
* the mixed MSF algorithms, the process group @p pg will be a
* (non-strict) process subgroup of \code process_group(g).
*
* \param g The underlying graph on which the MSF is being
* computed. The type of @p g must model DistributedGraph, but there
* are no other requirements because the edge and (super)vertex
* lists are passed separately.
*
* \param weight_map Property map containing the weights of each
* edge. The type of this property map must model
* ReadablePropertyMap and must support caching.
*
* \param out An output iterator that will be written with the set
* of edges selected to build the MSF. Every process within the
* process group @p pg will receive all edges in the MSF.
*
* \param dset Disjoint sets data structure mapping from vertices in
* the graph @p g to their representative supervertex.
*
* \param supervertex_map Mapping from supervertex descriptors to
* indices.
*
* \param supervertices A vector containing all of the
* supervertices. Will be modified to include only the remaining
* supervertices after merging occurs.
*
* \param edge_list The list of edges that remain in the graph. This
* list will be pruned to remove self-loops once MSF edges have been
* found.
*/
template<typename ProcessGroup, typename Graph, typename WeightMap,
typename OutputIterator, typename RankMap, typename ParentMap,
typename SupervertexMap, typename Vertex, typename EdgeList>
OutputIterator
boruvka_merge_step(ProcessGroup pg, const Graph& g, WeightMap weight_map,
OutputIterator out,
disjoint_sets<RankMap, ParentMap>& dset,
SupervertexMap supervertex_map,
std::vector<Vertex>& supervertices,
EdgeList& edge_list)
{
typedef typename graph_traits<Graph>::vertex_descriptor
vertex_descriptor;
typedef typename graph_traits<Graph>::vertices_size_type
vertices_size_type;
typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
typedef typename EdgeList::iterator edge_iterator;
typedef typename property_traits<WeightMap>::value_type
weight_type;
typedef boost::parallel::detail::untracked_pair<edge_descriptor,
weight_type> w_edge;
typedef typename property_traits<SupervertexMap>::value_type
supervertex_index;
smaller_weighted_edge min_edge;
weight_type inf = (std::numeric_limits<weight_type>::max)();
// Renumber the supervertices
for (std::size_t i = 0; i < supervertices.size(); ++i)
put(supervertex_map, supervertices[i], i);
// BSP-B1: Find local minimum-weight edges for each supervertex
std::vector<w_edge> candidate_edges(supervertices.size(),
w_edge(edge_descriptor(), inf));
for (edge_iterator ei = edge_list.begin(); ei != edge_list.end(); ++ei) {
weight_type w = get(weight_map, *ei);
supervertex_index u =
get(supervertex_map, dset.find_set(source(*ei, g)));
supervertex_index v =
get(supervertex_map, dset.find_set(target(*ei, g)));
if (u != v) {
candidate_edges[u] = min_edge(candidate_edges[u], w_edge(*ei, w));
candidate_edges[v] = min_edge(candidate_edges[v], w_edge(*ei, w));
}
}
// BSP-B2 (a): Compute global minimum edges for each supervertex
all_reduce(pg,
&candidate_edges[0],
&candidate_edges[0] + candidate_edges.size(),
&candidate_edges[0], min_edge);
// BSP-B2 (b): Use the edges to compute sequentially the new
// connected components and emit the edges.
for (vertices_size_type i = 0; i < candidate_edges.size(); ++i) {
if (candidate_edges[i].second != inf) {
edge_descriptor e = candidate_edges[i].first;
vertex_descriptor u = dset.find_set(source(e, g));
vertex_descriptor v = dset.find_set(target(e, g));
if (u != v) {
// Emit the edge, but cache the weight so everyone knows it
cache(weight_map, e, candidate_edges[i].second);
*out++ = e;
// Link the two supervertices
dset.link(u, v);
// Whichever vertex was reparented will be removed from the
// list of supervertices.
vertex_descriptor victim = u;
if (dset.find_set(u) == u) victim = v;
supervertices[get(supervertex_map, victim)] =
graph_traits<Graph>::null_vertex();
}
}
}
// BSP-B3: Eliminate self-loops
edge_list.erase(std::remove_if(edge_list.begin(), edge_list.end(),
has_same_supervertex(dset, g)),
edge_list.end());
// TBD: might also eliminate multiple edges between supervertices
// when the edges do not have the best weight, but this is not
// strictly necessary.
// Eliminate supervertices that have been absorbed
supervertices.erase(std::remove(supervertices.begin(),
supervertices.end(),
graph_traits<Graph>::null_vertex()),
supervertices.end());
return out;
}
/**
* An edge descriptor adaptor that reroutes the source and target
* edges to different vertices, but retains the original edge
* descriptor for, e.g., property maps. This is used when we want to
* turn a set of edges in the overall graph into a set of edges
* between supervertices.
*/
template<typename Graph>
struct supervertex_edge_descriptor
{
typedef supervertex_edge_descriptor self_type;
typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
typedef typename graph_traits<Graph>::edge_descriptor Edge;
Vertex source;
Vertex target;
Edge e;
operator Edge() const { return e; }
friend inline bool operator==(const self_type& x, const self_type& y)
{ return x.e == y.e; }
friend inline bool operator!=(const self_type& x, const self_type& y)
{ return x.e != y.e; }
};
template<typename Graph>
inline typename supervertex_edge_descriptor<Graph>::Vertex
source(supervertex_edge_descriptor<Graph> se, const Graph&)
{ return se.source; }
template<typename Graph>
inline typename supervertex_edge_descriptor<Graph>::Vertex
target(supervertex_edge_descriptor<Graph> se, const Graph&)
{ return se.target; }
/**
* Build a supervertex edge descriptor from a normal edge descriptor
* using the given disjoint sets data structure to identify
* supervertex representatives.
*/
template<typename Graph, typename DisjointSets>
struct build_supervertex_edge_descriptor
{
typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
typedef typename graph_traits<Graph>::edge_descriptor Edge;
typedef Edge argument_type;
typedef supervertex_edge_descriptor<Graph> result_type;
build_supervertex_edge_descriptor() : g(0), dsets(0) { }
build_supervertex_edge_descriptor(const Graph& g, DisjointSets& dsets)
: g(&g), dsets(&dsets) { }
result_type operator()(argument_type e) const
{
result_type result;
result.source = dsets->find_set(source(e, *g));
result.target = dsets->find_set(target(e, *g));
result.e = e;
return result;
}
private:
const Graph* g;
DisjointSets* dsets;
};
template<typename Graph, typename DisjointSets>
inline build_supervertex_edge_descriptor<Graph, DisjointSets>
make_supervertex_edge_descriptor(const Graph& g, DisjointSets& dsets)
{ return build_supervertex_edge_descriptor<Graph, DisjointSets>(g, dsets); }
template<typename T>
struct identity_function
{
typedef T argument_type;
typedef T result_type;
result_type operator()(argument_type x) const { return x; }
};
template<typename Graph, typename DisjointSets, typename EdgeMapper>
class is_not_msf_edge
{
typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
typedef typename graph_traits<Graph>::edge_descriptor Edge;
public:
is_not_msf_edge(const Graph& g, DisjointSets dset, EdgeMapper edge_mapper)
: g(g), dset(dset), edge_mapper(edge_mapper) { }
bool operator()(Edge e)
{
Vertex u = dset.find_set(source(edge_mapper(e), g));
Vertex v = dset.find_set(target(edge_mapper(e), g));
if (u == v) return true;
else {
dset.link(u, v);
return false;
}
}
private:
const Graph& g;
DisjointSets dset;
EdgeMapper edge_mapper;
};
template<typename Graph, typename ForwardIterator, typename EdgeList,
typename EdgeMapper, typename RankMap, typename ParentMap>
void
sorted_mutating_kruskal(const Graph& g,
ForwardIterator first_vertex,
ForwardIterator last_vertex,
EdgeList& edge_list, EdgeMapper edge_mapper,
RankMap rank_map, ParentMap parent_map)
{
typedef disjoint_sets<RankMap, ParentMap> DisjointSets;
// Build and initialize disjoint-sets data structure
DisjointSets dset(rank_map, parent_map);
for (ForwardIterator v = first_vertex; v != last_vertex; ++v)
dset.make_set(*v);
is_not_msf_edge<Graph, DisjointSets, EdgeMapper>
remove_non_msf_edges(g, dset, edge_mapper);
edge_list.erase(std::remove_if(edge_list.begin(), edge_list.end(),
remove_non_msf_edges),
edge_list.end());
}
/**
* Merge local minimum spanning forests from p processes into
* minimum spanning forests on p/D processes (where D is the tree
* factor, currently fixed at 3), eliminating unnecessary edges in
* the process.
*
* As with @ref boruvka_merge_step, this routine has many
* parameters, not all of which make sense within the limited
* context of this routine. The parameters are required for the
* Boruvka and local MSF merging steps to interoperate.
*
* \param pg The process group on which local minimum spanning
* forests should be merged. The top (D-1)p/D processes will be
* eliminated, and a new process subgroup containing p/D processors
* will be returned. The value D is a constant factor that is
* currently fixed to 3.
*
* \param g The underlying graph whose MSF is being computed. It must model
* the DistributedGraph concept.
*
* \param first_vertex Iterator to the first vertex in the graph
* that should be considered. While the local MSF merging algorithm
* typically operates on the entire vertex set, within the hybrid
* distributed MSF algorithms this will refer to the first
* supervertex.
*
* \param last_vertex The past-the-end iterator for the vertex list.
*
* \param edge_list The list of local edges that will be
* considered. For the p/D processes that remain, this list will
* contain edges in the MSF known to the vertex after other
* processes' edge lists have been merged. The edge list must be
* sorted in order of increasing weight.
*
* \param weight Property map containing the weights of each
* edge. The type of this property map must model
* ReadablePropertyMap and must support caching.
*
* \param global_index Mapping from vertex descriptors to a global
* index. The type must model ReadablePropertyMap.
*
* \param edge_mapper A function object that can remap edge descriptors
* in the edge list to any alternative edge descriptor. This
* function object will be the identity function when a pure merging
* of local MSFs is required, but may be a mapping to a supervertex
* edge when the local MSF merging occurs on a supervertex
* graph. This function object saves us the trouble of having to
* build a supervertex graph adaptor.
*
* \param already_local_msf True when the edge list already
* constitutes a local MSF. If false, Kruskal's algorithm will first
* be applied to the local edge list to select MSF edges.
*
* \returns The process subgroup containing the remaining p/D
* processes. If the size of this process group is greater than one,
* the MSF edges contained in the edge list do not constitute an MSF
* for the entire graph.
*/
template<typename ProcessGroup, typename Graph, typename ForwardIterator,
typename EdgeList, typename WeightMap, typename GlobalIndexMap,
typename EdgeMapper>
ProcessGroup
merge_local_minimum_spanning_trees_step(ProcessGroup pg,
const Graph& g,
ForwardIterator first_vertex,
ForwardIterator last_vertex,
EdgeList& edge_list,
WeightMap weight,
GlobalIndexMap global_index,
EdgeMapper edge_mapper,
bool already_local_msf)
{
typedef typename ProcessGroup::process_id_type process_id_type;
typedef typename EdgeList::value_type edge_descriptor;
typedef typename property_traits<WeightMap>::value_type weight_type;
typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
// The tree factor, often called "D"
process_id_type const tree_factor = 3;
process_id_type num_procs = num_processes(pg);
process_id_type id = process_id(pg);
process_id_type procs_left = (num_procs + tree_factor - 1) / tree_factor;
std::size_t n = std::size_t(last_vertex - first_vertex);
if (!already_local_msf) {
// Compute local minimum spanning forest. We only care about the
// edges in the MSF, because only edges in the local MSF can be in
// the global MSF.
std::vector<std::size_t> ranks(n);
std::vector<vertex_descriptor> parents(n);
detail::sorted_mutating_kruskal
(g, first_vertex, last_vertex,
edge_list, edge_mapper,
make_iterator_property_map(ranks.begin(), global_index),
make_iterator_property_map(parents.begin(), global_index));
}
typedef std::pair<edge_descriptor, weight_type> w_edge;
// Order edges based on their weights.
indirect_cmp<WeightMap, std::less<weight_type> > cmp_edge_weight(weight);
if (id < procs_left) {
// The p/D processes that remain will receive local MSF edges from
// D-1 other processes.
synchronize(pg);
for (process_id_type from_id = procs_left + id; from_id < num_procs;
from_id += procs_left) {
std::size_t num_incoming_edges;
receive(pg, from_id, 0, num_incoming_edges);
if (num_incoming_edges > 0) {
std::vector<w_edge> incoming_edges(num_incoming_edges);
receive(pg, from_id, 1, &incoming_edges[0], num_incoming_edges);
edge_list.reserve(edge_list.size() + num_incoming_edges);
for (std::size_t i = 0; i < num_incoming_edges; ++i) {
cache(weight, incoming_edges[i].first, incoming_edges[i].second);
edge_list.push_back(incoming_edges[i].first);
}
std::inplace_merge(edge_list.begin(),
edge_list.end() - num_incoming_edges,
edge_list.end(),
cmp_edge_weight);
}
}
// Compute the local MSF from union of the edges in the MSFs of
// all children.
std::vector<std::size_t> ranks(n);
std::vector<vertex_descriptor> parents(n);
detail::sorted_mutating_kruskal
(g, first_vertex, last_vertex,
edge_list, edge_mapper,
make_iterator_property_map(ranks.begin(), global_index),
make_iterator_property_map(parents.begin(), global_index));
} else {
// The (D-1)p/D processes that are dropping out of further
// computations merely send their MSF edges to their parent
// process in the process tree.
send(pg, id % procs_left, 0, edge_list.size());
if (edge_list.size() > 0) {
std::vector<w_edge> outgoing_edges;
outgoing_edges.reserve(edge_list.size());
for (std::size_t i = 0; i < edge_list.size(); ++i) {
outgoing_edges.push_back(std::make_pair(edge_list[i],
get(weight, edge_list[i])));
}
send(pg, id % procs_left, 1, &outgoing_edges[0],
outgoing_edges.size());
}
synchronize(pg);
}
// Return a process subgroup containing the p/D parent processes
return process_subgroup(pg,
make_counting_iterator(process_id_type(0)),
make_counting_iterator(procs_left));
}
} // end namespace detail
// ---------------------------------------------------------------------
// Dense Boruvka MSF algorithm
// ---------------------------------------------------------------------
template<typename Graph, typename WeightMap, typename OutputIterator,
typename VertexIndexMap, typename RankMap, typename ParentMap,
typename SupervertexMap>
OutputIterator
dense_boruvka_minimum_spanning_tree(const Graph& g, WeightMap weight_map,
OutputIterator out,
VertexIndexMap index_map,
RankMap rank_map, ParentMap parent_map,
SupervertexMap supervertex_map)
{
using boost::graph::parallel::process_group;
typedef typename graph_traits<Graph>::traversal_category traversal_category;
BOOST_STATIC_ASSERT((is_convertible<traversal_category*,
vertex_list_graph_tag*>::value));
typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type;
typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
// Don't throw away cached edge weights
weight_map.set_max_ghost_cells(0);
// Initialize the disjoint sets structures
disjoint_sets<RankMap, ParentMap> dset(rank_map, parent_map);
vertex_iterator vi, vi_end;
for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)
dset.make_set(*vi);
std::vector<vertex_descriptor> supervertices;
supervertices.assign(vertices(g).first, vertices(g).second);
// Use Kruskal's algorithm to find the minimum spanning forest
// considering only the local edges. The resulting edges are not
// necessarily going to be in the final minimum spanning
// forest. However, any edge not part of the local MSF cannot be a
// part of the global MSF, so we should have eliminated some edges
// from consideration.
std::vector<edge_descriptor> edge_list;
kruskal_minimum_spanning_tree
(make_vertex_and_edge_range(g, vertices(g).first, vertices(g).second,
edges(g).first, edges(g).second),
std::back_inserter(edge_list),
boost::weight_map(weight_map).
vertex_index_map(index_map));
// While the number of supervertices is decreasing, keep executing
// Boruvka steps to identify additional MSF edges. This loop will
// execute log |V| times.
vertices_size_type old_num_supervertices;
do {
old_num_supervertices = supervertices.size();
out = detail::boruvka_merge_step(process_group(g), g,
weight_map, out,
dset, supervertex_map, supervertices,
edge_list);
} while (supervertices.size() < old_num_supervertices);
return out;
}
template<typename Graph, typename WeightMap, typename OutputIterator,
typename VertexIndex>
OutputIterator
dense_boruvka_minimum_spanning_tree(const Graph& g, WeightMap weight_map,
OutputIterator out, VertexIndex i_map)
{
typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
std::vector<std::size_t> ranks(num_vertices(g));
std::vector<vertex_descriptor> parents(num_vertices(g));
std::vector<std::size_t> supervertices(num_vertices(g));
return dense_boruvka_minimum_spanning_tree
(g, weight_map, out, i_map,
make_iterator_property_map(ranks.begin(), i_map),
make_iterator_property_map(parents.begin(), i_map),
make_iterator_property_map(supervertices.begin(), i_map));
}
template<typename Graph, typename WeightMap, typename OutputIterator>
OutputIterator
dense_boruvka_minimum_spanning_tree(const Graph& g, WeightMap weight_map,
OutputIterator out)
{
return dense_boruvka_minimum_spanning_tree(g, weight_map, out,
get(vertex_index, g));
}
// ---------------------------------------------------------------------
// Merge local MSFs MSF algorithm
// ---------------------------------------------------------------------
template<typename Graph, typename WeightMap, typename OutputIterator,
typename GlobalIndexMap>
OutputIterator
merge_local_minimum_spanning_trees(const Graph& g, WeightMap weight,
OutputIterator out,
GlobalIndexMap global_index)
{
using boost::graph::parallel::process_group_type;
using boost::graph::parallel::process_group;
typedef typename graph_traits<Graph>::traversal_category traversal_category;
BOOST_STATIC_ASSERT((is_convertible<traversal_category*,
vertex_list_graph_tag*>::value));
typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
// Don't throw away cached edge weights
weight.set_max_ghost_cells(0);
// Compute the initial local minimum spanning forests
std::vector<edge_descriptor> edge_list;
kruskal_minimum_spanning_tree
(make_vertex_and_edge_range(g, vertices(g).first, vertices(g).second,
edges(g).first, edges(g).second),
std::back_inserter(edge_list),
boost::weight_map(weight).vertex_index_map(global_index));
// Merge the local MSFs from p processes into p/D processes,
// reducing the number of processes in each step. Continue looping
// until either (a) the current process drops out or (b) only one
// process remains in the group. This loop will execute log_D p
// times.
typename process_group_type<Graph>::type pg = process_group(g);
while (pg && num_processes(pg) > 1) {
pg = detail::merge_local_minimum_spanning_trees_step
(pg, g, vertices(g).first, vertices(g).second,
edge_list, weight, global_index,
detail::identity_function<edge_descriptor>(), true);
}
// Only process 0 has the entire edge list, so emit it to the output
// iterator.
if (pg && process_id(pg) == 0) {
out = std::copy(edge_list.begin(), edge_list.end(), out);
}
synchronize(process_group(g));
return out;
}
template<typename Graph, typename WeightMap, typename OutputIterator>
inline OutputIterator
merge_local_minimum_spanning_trees(const Graph& g, WeightMap weight,
OutputIterator out)
{
return merge_local_minimum_spanning_trees(g, weight, out,
get(vertex_index, g));
}
// ---------------------------------------------------------------------
// Boruvka-then-merge MSF algorithm
// ---------------------------------------------------------------------
template<typename Graph, typename WeightMap, typename OutputIterator,
typename GlobalIndexMap, typename RankMap, typename ParentMap,
typename SupervertexMap>
OutputIterator
boruvka_then_merge(const Graph& g, WeightMap weight, OutputIterator out,
GlobalIndexMap index, RankMap rank_map,
ParentMap parent_map, SupervertexMap supervertex_map)
{
using std::log;
using boost::graph::parallel::process_group_type;
using boost::graph::parallel::process_group;
typedef typename graph_traits<Graph>::traversal_category traversal_category;
BOOST_STATIC_ASSERT((is_convertible<traversal_category*,
vertex_list_graph_tag*>::value));
typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type;
typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
// Don't throw away cached edge weights
weight.set_max_ghost_cells(0);
// Compute the initial local minimum spanning forests
std::vector<edge_descriptor> edge_list;
kruskal_minimum_spanning_tree
(make_vertex_and_edge_range(g, vertices(g).first, vertices(g).second,
edges(g).first, edges(g).second),
std::back_inserter(edge_list),
boost::weight_map(weight).
vertex_index_map(index));
// Initialize the disjoint sets structures for Boruvka steps
disjoint_sets<RankMap, ParentMap> dset(rank_map, parent_map);
vertex_iterator vi, vi_end;
for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)
dset.make_set(*vi);
// Construct the initial set of supervertices (all vertices)
std::vector<vertex_descriptor> supervertices;
supervertices.assign(vertices(g).first, vertices(g).second);
// Continue performing Boruvka merge steps until the number of
// supervertices reaches |V| / (log_D p)^2.
const std::size_t tree_factor = 3; // TBD: same as above! should be param
double log_d_p = log((double)num_processes(process_group(g)))
/ log((double)tree_factor);
vertices_size_type target_supervertices =
vertices_size_type(num_vertices(g) / (log_d_p * log_d_p));
vertices_size_type old_num_supervertices;
while (supervertices.size() > target_supervertices) {
old_num_supervertices = supervertices.size();
out = detail::boruvka_merge_step(process_group(g), g,
weight, out, dset,
supervertex_map, supervertices,
edge_list);
if (supervertices.size() == old_num_supervertices)
return out;
}
// Renumber the supervertices
for (std::size_t i = 0; i < supervertices.size(); ++i)
put(supervertex_map, supervertices[i], i);
// Merge local MSFs on the supervertices. (D-1)p/D processors drop
// out each iteration, so this loop executes log_D p times.
typename process_group_type<Graph>::type pg = process_group(g);
bool have_msf = false;
while (pg && num_processes(pg) > 1) {
pg = detail::merge_local_minimum_spanning_trees_step
(pg, g, supervertices.begin(), supervertices.end(),
edge_list, weight, supervertex_map,
detail::make_supervertex_edge_descriptor(g, dset),
have_msf);
have_msf = true;
}
// Only process 0 has the complete list of _supervertex_ MST edges,
// so emit those to the output iterator. This is not the complete
// list of edges in the MSF, however: the Boruvka steps in the
// beginning of the algorithm emitted any edges used to merge
// supervertices.
if (pg && process_id(pg) == 0)
out = std::copy(edge_list.begin(), edge_list.end(), out);
synchronize(process_group(g));
return out;
}
template<typename Graph, typename WeightMap, typename OutputIterator,
typename GlobalIndexMap>
inline OutputIterator
boruvka_then_merge(const Graph& g, WeightMap weight, OutputIterator out,
GlobalIndexMap index)
{
typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type;
std::vector<vertices_size_type> ranks(num_vertices(g));
std::vector<vertex_descriptor> parents(num_vertices(g));
std::vector<vertices_size_type> supervertex_indices(num_vertices(g));
return boruvka_then_merge
(g, weight, out, index,
make_iterator_property_map(ranks.begin(), index),
make_iterator_property_map(parents.begin(), index),
make_iterator_property_map(supervertex_indices.begin(), index));
}
template<typename Graph, typename WeightMap, typename OutputIterator>
inline OutputIterator
boruvka_then_merge(const Graph& g, WeightMap weight, OutputIterator out)
{ return boruvka_then_merge(g, weight, out, get(vertex_index, g)); }
// ---------------------------------------------------------------------
// Boruvka-mixed-merge MSF algorithm
// ---------------------------------------------------------------------
template<typename Graph, typename WeightMap, typename OutputIterator,
typename GlobalIndexMap, typename RankMap, typename ParentMap,
typename SupervertexMap>
OutputIterator
boruvka_mixed_merge(const Graph& g, WeightMap weight, OutputIterator out,
GlobalIndexMap index, RankMap rank_map,
ParentMap parent_map, SupervertexMap supervertex_map)
{
using boost::graph::parallel::process_group_type;
using boost::graph::parallel::process_group;
typedef typename graph_traits<Graph>::traversal_category traversal_category;
BOOST_STATIC_ASSERT((is_convertible<traversal_category*,
vertex_list_graph_tag*>::value));
typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type;
typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
// Don't throw away cached edge weights
weight.set_max_ghost_cells(0);
// Initialize the disjoint sets structures for Boruvka steps
disjoint_sets<RankMap, ParentMap> dset(rank_map, parent_map);
vertex_iterator vi, vi_end;
for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)
dset.make_set(*vi);
// Construct the initial set of supervertices (all vertices)
std::vector<vertex_descriptor> supervertices;
supervertices.assign(vertices(g).first, vertices(g).second);
// Compute the initial local minimum spanning forests
std::vector<edge_descriptor> edge_list;
kruskal_minimum_spanning_tree
(make_vertex_and_edge_range(g, vertices(g).first, vertices(g).second,
edges(g).first, edges(g).second),
std::back_inserter(edge_list),
boost::weight_map(weight).
vertex_index_map(index));
if (num_processes(process_group(g)) == 1) {
return std::copy(edge_list.begin(), edge_list.end(), out);
}
// Like the merging local MSFs algorithm and the Boruvka-then-merge
// algorithm, each iteration of this loop reduces the number of
// processes by a constant factor D, and therefore we require log_D
// p iterations. Note also that the number of edges in the edge list
// decreases geometrically, giving us an efficient distributed MSF
// algorithm.
typename process_group_type<Graph>::type pg = process_group(g);
vertices_size_type old_num_supervertices;
while (pg && num_processes(pg) > 1) {
// A single Boruvka step. If this doesn't change anything, we're done
old_num_supervertices = supervertices.size();
out = detail::boruvka_merge_step(pg, g, weight, out, dset,
supervertex_map, supervertices,
edge_list);
if (old_num_supervertices == supervertices.size()) {
edge_list.clear();
break;
}
// Renumber the supervertices
for (std::size_t i = 0; i < supervertices.size(); ++i)
put(supervertex_map, supervertices[i], i);
// A single merging of local MSTs, which reduces the number of
// processes we're using by a constant factor D.
pg = detail::merge_local_minimum_spanning_trees_step
(pg, g, supervertices.begin(), supervertices.end(),
edge_list, weight, supervertex_map,
detail::make_supervertex_edge_descriptor(g, dset),
true);
}
// Only process 0 has the complete edge list, so emit it for the
// user. Note that list edge list only contains the MSF edges in the
// final supervertex graph: all of the other edges were used to
// merge supervertices and have been emitted by the Boruvka steps,
// although only process 0 has received the complete set.
if (pg && process_id(pg) == 0)
out = std::copy(edge_list.begin(), edge_list.end(), out);
synchronize(process_group(g));
return out;
}
template<typename Graph, typename WeightMap, typename OutputIterator,
typename GlobalIndexMap>
inline OutputIterator
boruvka_mixed_merge(const Graph& g, WeightMap weight, OutputIterator out,
GlobalIndexMap index)
{
typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type;
std::vector<vertices_size_type> ranks(num_vertices(g));
std::vector<vertex_descriptor> parents(num_vertices(g));
std::vector<vertices_size_type> supervertex_indices(num_vertices(g));
return boruvka_mixed_merge
(g, weight, out, index,
make_iterator_property_map(ranks.begin(), index),
make_iterator_property_map(parents.begin(), index),
make_iterator_property_map(supervertex_indices.begin(), index));
}
template<typename Graph, typename WeightMap, typename OutputIterator>
inline OutputIterator
boruvka_mixed_merge(const Graph& g, WeightMap weight, OutputIterator out)
{ return boruvka_mixed_merge(g, weight, out, get(vertex_index, g)); }
} // end namespace distributed
using distributed::dense_boruvka_minimum_spanning_tree;
using distributed::merge_local_minimum_spanning_trees;
using distributed::boruvka_then_merge;
using distributed::boruvka_mixed_merge;
} } // end namespace boost::graph
#endif // BOOST_DEHNE_GOTZ_MIN_SPANNING_TREE_HPP
@@ -0,0 +1,513 @@
// Copyright (C) 2007 The Trustees of Indiana University.
// Use, modification and distribution is subject to 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)
// Authors: Douglas Gregor
// Andrew Lumsdaine
/**************************************************************************
* This source file implements the Delta-stepping algorithm: *
* *
* Ulrich Meyer and Peter Sanders. Parallel Shortest Path for Arbitrary *
* Graphs. In Proceedings from the 6th International Euro-Par *
* Conference on Parallel Processing, pages 461--470, 2000. *
* *
* Ulrich Meyer, Peter Sanders: [Delta]-stepping: A Parallelizable *
* Shortest Path Algorithm. J. Algorithms 49(1): 114-152, 2003. *
* *
* There are several potential optimizations we could still perform for *
* this algorithm implementation: *
* *
* - Implement "shortcuts", which bound the number of reinsertions *
* in a single bucket (to one). The computation of shortcuts looks *
* expensive in a distributed-memory setting, but it could be *
* ammortized over many queries. *
* *
* - The size of the "buckets" data structure can be bounded to *
* max_edge_weight/delta buckets, if we treat the buckets as a *
* circular array. *
* *
* - If we partition light/heavy edges ahead of time, we could improve *
* relaxation performance by only iterating over the right portion *
* of the out-edge list each time. *
* *
* - Implement a more sophisticated algorithm for guessing "delta", *
* based on the shortcut-finding algorithm. *
**************************************************************************/
#ifndef BOOST_GRAPH_DELTA_STEPPING_SHORTEST_PATHS_HPP
#define BOOST_GRAPH_DELTA_STEPPING_SHORTEST_PATHS_HPP
#ifndef BOOST_GRAPH_USE_MPI
#error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
#endif
#include <boost/config.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/graph/iteration_macros.hpp>
#include <limits>
#include <list>
#include <vector>
#include <boost/graph/parallel/container_traits.hpp>
#include <boost/graph/parallel/properties.hpp>
#include <boost/graph/distributed/detail/dijkstra_shortest_paths.hpp>
#include <utility> // for std::pair
#include <functional> // for std::logical_or
#include <boost/graph/parallel/algorithm.hpp> // for all_reduce
#include <cassert>
#include <algorithm> // for std::min, std::max
#include <boost/graph/parallel/simple_trigger.hpp>
#ifdef PBGL_DELTA_STEPPING_DEBUG
# include <iostream> // for std::cerr
#endif
namespace boost { namespace graph { namespace distributed {
template<typename Graph, typename PredecessorMap, typename DistanceMap,
typename EdgeWeightMap>
class delta_stepping_impl {
typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
typedef typename graph_traits<Graph>::degree_size_type Degree;
typedef typename property_traits<EdgeWeightMap>::value_type Dist;
typedef typename boost::graph::parallel::process_group_type<Graph>::type
ProcessGroup;
typedef std::list<Vertex> Bucket;
typedef typename Bucket::iterator BucketIterator;
typedef typename std::vector<Bucket*>::size_type BucketIndex;
typedef detail::dijkstra_msg_value<DistanceMap, PredecessorMap> MessageValue;
enum {
// Relax a remote vertex. The message contains a pair<Vertex,
// MessageValue>, the first part of which is the vertex whose
// tentative distance is being relaxed and the second part
// contains either the new distance (if there is no predecessor
// map) or a pair with the distance and predecessor.
msg_relax
};
public:
delta_stepping_impl(const Graph& g,
PredecessorMap predecessor,
DistanceMap distance,
EdgeWeightMap weight,
Dist delta);
delta_stepping_impl(const Graph& g,
PredecessorMap predecessor,
DistanceMap distance,
EdgeWeightMap weight);
void run(Vertex s);
private:
// Relax the edge (u, v), creating a new best path of distance x.
void relax(Vertex u, Vertex v, Dist x);
// Synchronize all of the processes, by receiving all messages that
// have not yet been received.
void synchronize();
// Handle a relax message that contains only the target and
// distance. This kind of message will be received when the
// predecessor map is a dummy_property_map.
void handle_relax_message(Vertex v, Dist x) { relax(v, v, x); }
// Handle a relax message that contains the source (predecessor),
// target, and distance. This kind of message will be received when
// the predecessor map is not a dummy_property_map.
void handle_relax_message(Vertex v, const std::pair<Dist, Vertex>& p)
{ relax(p.second, v, p.first); }
// Setup triggers for msg_relax messages
void setup_triggers();
void handle_msg_relax(int /*source*/, int /*tag*/,
const std::pair<Vertex, typename MessageValue::type>& data,
trigger_receive_context)
{ handle_relax_message(data.first, data.second); }
const Graph& g;
PredecessorMap predecessor;
DistanceMap distance;
EdgeWeightMap weight;
Dist delta;
ProcessGroup pg;
typename property_map<Graph, vertex_owner_t>::const_type owner;
typename property_map<Graph, vertex_local_t>::const_type local;
// A "property map" that contains the position of each vertex in
// whatever bucket it resides in.
std::vector<BucketIterator> position_in_bucket;
// Bucket data structure. The ith bucket contains all local vertices
// with (tentative) distance in the range [i*delta,
// (i+1)*delta).
std::vector<Bucket*> buckets;
// This "dummy" list is used only so that we can initialize the
// position_in_bucket property map with non-singular iterators. This
// won't matter for most implementations of the C++ Standard
// Library, but it avoids undefined behavior and allows us to run
// with library "debug modes".
std::list<Vertex> dummy_list;
// A "property map" that states which vertices have been deleted
// from the bucket in this iteration.
std::vector<bool> vertex_was_deleted;
};
template<typename Graph, typename PredecessorMap, typename DistanceMap,
typename EdgeWeightMap>
delta_stepping_impl<Graph, PredecessorMap, DistanceMap, EdgeWeightMap>::
delta_stepping_impl(const Graph& g,
PredecessorMap predecessor,
DistanceMap distance,
EdgeWeightMap weight,
Dist delta)
: g(g),
predecessor(predecessor),
distance(distance),
weight(weight),
delta(delta),
pg(boost::graph::parallel::process_group_adl(g), attach_distributed_object()),
owner(get(vertex_owner, g)),
local(get(vertex_local, g))
{
setup_triggers();
}
template<typename Graph, typename PredecessorMap, typename DistanceMap,
typename EdgeWeightMap>
delta_stepping_impl<Graph, PredecessorMap, DistanceMap, EdgeWeightMap>::
delta_stepping_impl(const Graph& g,
PredecessorMap predecessor,
DistanceMap distance,
EdgeWeightMap weight)
: g(g),
predecessor(predecessor),
distance(distance),
weight(weight),
pg(boost::graph::parallel::process_group_adl(g), attach_distributed_object()),
owner(get(vertex_owner, g)),
local(get(vertex_local, g))
{
using boost::parallel::all_reduce;
using boost::parallel::maximum;
using std::max;
// Compute the maximum edge weight and degree
Dist max_edge_weight = 0;
Degree max_degree = 0;
BGL_FORALL_VERTICES_T(u, g, Graph) {
max_degree = max BOOST_PREVENT_MACRO_SUBSTITUTION (max_degree, out_degree(u, g));
BGL_FORALL_OUTEDGES_T(u, e, g, Graph)
max_edge_weight = max BOOST_PREVENT_MACRO_SUBSTITUTION (max_edge_weight, get(weight, e));
}
max_edge_weight = all_reduce(pg, max_edge_weight, maximum<Dist>());
max_degree = all_reduce(pg, max_degree, maximum<Degree>());
// Take a guess at delta, based on what works well for random
// graphs.
delta = max_edge_weight / max_degree;
if (delta == 0)
delta = 1;
setup_triggers();
}
template<typename Graph, typename PredecessorMap, typename DistanceMap,
typename EdgeWeightMap>
void
delta_stepping_impl<Graph, PredecessorMap, DistanceMap, EdgeWeightMap>::
run(Vertex s)
{
Dist inf = (std::numeric_limits<Dist>::max)();
// None of the vertices are stored in the bucket.
position_in_bucket.clear();
position_in_bucket.resize(num_vertices(g), dummy_list.end());
// None of the vertices have been deleted
vertex_was_deleted.clear();
vertex_was_deleted.resize(num_vertices(g), false);
// No path from s to any other vertex, yet
BGL_FORALL_VERTICES_T(v, g, Graph)
put(distance, v, inf);
// The distance to the starting node is zero
if (get(owner, s) == process_id(pg))
// Put "s" into its bucket (bucket 0)
relax(s, s, 0);
else
// Note that we know the distance to s is zero
cache(distance, s, 0);
BucketIndex max_bucket = (std::numeric_limits<BucketIndex>::max)();
BucketIndex current_bucket = 0;
do {
// Synchronize with all of the other processes.
synchronize();
// Find the next bucket that has something in it.
while (current_bucket < buckets.size()
&& (!buckets[current_bucket] || buckets[current_bucket]->empty()))
++current_bucket;
if (current_bucket >= buckets.size())
current_bucket = max_bucket;
#ifdef PBGL_DELTA_STEPPING_DEBUG
std::cerr << "#" << process_id(pg) << ": lowest bucket is #"
<< current_bucket << std::endl;
#endif
// Find the smallest bucket (over all processes) that has vertices
// that need to be processed.
using boost::parallel::all_reduce;
using boost::parallel::minimum;
current_bucket = all_reduce(pg, current_bucket, minimum<BucketIndex>());
if (current_bucket == max_bucket)
// There are no non-empty buckets in any process; exit.
break;
#ifdef PBGL_DELTA_STEPPING_DEBUG
if (process_id(pg) == 0)
std::cerr << "Processing bucket #" << current_bucket << std::endl;
#endif
// Contains the set of vertices that have been deleted in the
// relaxation of "light" edges. Note that we keep track of which
// vertices were deleted with the property map
// "vertex_was_deleted".
std::vector<Vertex> deleted_vertices;
// Repeatedly relax light edges
bool nonempty_bucket;
do {
// Someone has work to do in this bucket.
if (current_bucket < buckets.size() && buckets[current_bucket]) {
Bucket& bucket = *buckets[current_bucket];
// For each element in the bucket
while (!bucket.empty()) {
Vertex u = bucket.front();
#ifdef PBGL_DELTA_STEPPING_DEBUG
std::cerr << "#" << process_id(pg) << ": processing vertex "
<< get(vertex_global, g, u).second << "@"
<< get(vertex_global, g, u).first
<< std::endl;
#endif
// Remove u from the front of the bucket
bucket.pop_front();
// Insert u into the set of deleted vertices, if it hasn't
// been done already.
if (!vertex_was_deleted[get(local, u)]) {
vertex_was_deleted[get(local, u)] = true;
deleted_vertices.push_back(u);
}
// Relax each light edge.
Dist u_dist = get(distance, u);
BGL_FORALL_OUTEDGES_T(u, e, g, Graph)
if (get(weight, e) <= delta) // light edge
relax(u, target(e, g), u_dist + get(weight, e));
}
}
// Synchronize with all of the other processes.
synchronize();
// Is the bucket empty now?
nonempty_bucket = (current_bucket < buckets.size()
&& buckets[current_bucket]
&& !buckets[current_bucket]->empty());
} while (all_reduce(pg, nonempty_bucket, std::logical_or<bool>()));
// Relax heavy edges for each of the vertices that we previously
// deleted.
for (typename std::vector<Vertex>::iterator iter = deleted_vertices.begin();
iter != deleted_vertices.end(); ++iter) {
// Relax each heavy edge.
Vertex u = *iter;
Dist u_dist = get(distance, u);
BGL_FORALL_OUTEDGES_T(u, e, g, Graph)
if (get(weight, e) > delta) // heavy edge
relax(u, target(e, g), u_dist + get(weight, e));
}
// Go to the next bucket: the current bucket must already be empty.
++current_bucket;
} while (true);
// Delete all of the buckets.
for (typename std::vector<Bucket*>::iterator iter = buckets.begin();
iter != buckets.end(); ++iter) {
if (*iter) {
delete *iter;
*iter = 0;
}
}
}
template<typename Graph, typename PredecessorMap, typename DistanceMap,
typename EdgeWeightMap>
void
delta_stepping_impl<Graph, PredecessorMap, DistanceMap, EdgeWeightMap>::
relax(Vertex u, Vertex v, Dist x)
{
#ifdef PBGL_DELTA_STEPPING_DEBUG
std::cerr << "#" << process_id(pg) << ": relax("
<< get(vertex_global, g, u).second << "@"
<< get(vertex_global, g, u).first << ", "
<< get(vertex_global, g, v).second << "@"
<< get(vertex_global, g, v).first << ", "
<< x << ")" << std::endl;
#endif
if (x < get(distance, v)) {
// We're relaxing the edge to vertex v.
if (get(owner, v) == process_id(pg)) {
// Compute the new bucket index for v
BucketIndex new_index = static_cast<BucketIndex>(x / delta);
// Make sure there is enough room in the buckets data structure.
if (new_index >= buckets.size()) buckets.resize(new_index + 1, 0);
// Make sure that we have allocated the bucket itself.
if (!buckets[new_index]) buckets[new_index] = new Bucket;
if (get(distance, v) != (std::numeric_limits<Dist>::max)()
&& !vertex_was_deleted[get(local, v)]) {
// We're moving v from an old bucket into a new one. Compute
// the old index, then splice it in.
BucketIndex old_index
= static_cast<BucketIndex>(get(distance, v) / delta);
buckets[new_index]->splice(buckets[new_index]->end(),
*buckets[old_index],
position_in_bucket[get(local, v)]);
} else {
// We're inserting v into a bucket for the first time. Put it
// at the end.
buckets[new_index]->push_back(v);
}
// v is now at the last position in the new bucket
position_in_bucket[get(local, v)] = buckets[new_index]->end();
--position_in_bucket[get(local, v)];
// Update predecessor and tentative distance information
put(predecessor, v, u);
put(distance, v, x);
} else {
#ifdef PBGL_DELTA_STEPPING_DEBUG
std::cerr << "#" << process_id(pg) << ": sending relax("
<< get(vertex_global, g, u).second << "@"
<< get(vertex_global, g, u).first << ", "
<< get(vertex_global, g, v).second << "@"
<< get(vertex_global, g, v).first << ", "
<< x << ") to " << get(owner, v) << std::endl;
#endif
// The vertex is remote: send a request to the vertex's owner
send(pg, get(owner, v), msg_relax,
std::make_pair(v, MessageValue::create(x, u)));
// Cache tentative distance information
cache(distance, v, x);
}
}
}
template<typename Graph, typename PredecessorMap, typename DistanceMap,
typename EdgeWeightMap>
void
delta_stepping_impl<Graph, PredecessorMap, DistanceMap, EdgeWeightMap>::
synchronize()
{
using boost::graph::parallel::synchronize;
// Synchronize at the process group level.
synchronize(pg);
// Receive any relaxation request messages.
// typedef typename ProcessGroup::process_id_type process_id_type;
// while (optional<std::pair<process_id_type, int> > stp = probe(pg)) {
// // Receive the relaxation message
// assert(stp->second == msg_relax);
// std::pair<Vertex, typename MessageValue::type> data;
// receive(pg, stp->first, stp->second, data);
// // Turn it into a "relax" call
// handle_relax_message(data.first, data.second);
// }
}
template<typename Graph, typename PredecessorMap, typename DistanceMap,
typename EdgeWeightMap>
void
delta_stepping_impl<Graph, PredecessorMap, DistanceMap, EdgeWeightMap>::
setup_triggers()
{
using boost::graph::parallel::simple_trigger;
simple_trigger(pg, msg_relax, this,
&delta_stepping_impl::handle_msg_relax);
}
template<typename Graph, typename PredecessorMap, typename DistanceMap,
typename EdgeWeightMap>
void
delta_stepping_shortest_paths
(const Graph& g,
typename graph_traits<Graph>::vertex_descriptor s,
PredecessorMap predecessor, DistanceMap distance, EdgeWeightMap weight,
typename property_traits<EdgeWeightMap>::value_type delta)
{
// The "distance" map needs to act like one, retrieving the default
// value of infinity.
set_property_map_role(vertex_distance, distance);
// Construct the implementation object, which will perform all of
// the actual work.
delta_stepping_impl<Graph, PredecessorMap, DistanceMap, EdgeWeightMap>
impl(g, predecessor, distance, weight, delta);
// Run the delta-stepping algorithm. The results will show up in
// "predecessor" and "weight".
impl.run(s);
}
template<typename Graph, typename PredecessorMap, typename DistanceMap,
typename EdgeWeightMap>
void
delta_stepping_shortest_paths
(const Graph& g,
typename graph_traits<Graph>::vertex_descriptor s,
PredecessorMap predecessor, DistanceMap distance, EdgeWeightMap weight)
{
// The "distance" map needs to act like one, retrieving the default
// value of infinity.
set_property_map_role(vertex_distance, distance);
// Construct the implementation object, which will perform all of
// the actual work.
delta_stepping_impl<Graph, PredecessorMap, DistanceMap, EdgeWeightMap>
impl(g, predecessor, distance, weight);
// Run the delta-stepping algorithm. The results will show up in
// "predecessor" and "weight".
impl.run(s);
}
} } } // end namespace boost::graph::distributed
#endif // BOOST_GRAPH_DELTA_STEPPING_SHORTEST_PATHS_HPP
@@ -0,0 +1,307 @@
// Copyright (C) 2004-2008 The Trustees of Indiana University.
// Use, modification and distribution is subject to 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)
// Authors: Douglas Gregor
// Andrew Lumsdaine
#ifndef BOOST_GRAPH_DISTRIBUTED_DFS_HPP
#define BOOST_GRAPH_DISTRIBUTED_DFS_HPP
#ifndef BOOST_GRAPH_USE_MPI
#error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
#endif
#include <boost/graph/graph_traits.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/graph/overloading.hpp>
#include <boost/graph/properties.hpp>
#include <boost/graph/distributed/concepts.hpp>
#include <boost/static_assert.hpp>
#include <boost/assert.hpp>
#include <boost/graph/parallel/process_group.hpp>
#include <boost/graph/parallel/container_traits.hpp>
namespace boost {
namespace graph { namespace distributed { namespace detail {
template<typename DistributedGraph, typename ColorMap, typename ParentMap,
typename ExploreMap, typename VertexIndexMap, typename DFSVisitor>
class parallel_dfs
{
typedef typename graph_traits<DistributedGraph>::vertex_iterator
vertex_iterator;
typedef typename graph_traits<DistributedGraph>::vertex_descriptor
vertex_descriptor;
typedef typename graph_traits<DistributedGraph>::out_edge_iterator
out_edge_iterator;
typedef typename boost::graph::parallel::process_group_type<DistributedGraph>
::type process_group_type;
typedef typename process_group_type::process_id_type process_id_type;
/**
* The first vertex in the pair is the local node (i) and the
* second vertex in the pair is the (possibly remote) node (j).
*/
typedef boost::parallel::detail::untracked_pair<vertex_descriptor, vertex_descriptor> vertex_pair;
typedef typename property_traits<ColorMap>::value_type color_type;
typedef color_traits<color_type> Color;
// Message types
enum { discover_msg = 10, return_msg = 50, visited_msg = 100 , done_msg = 150};
public:
parallel_dfs(const DistributedGraph& g, ColorMap color,
ParentMap parent, ExploreMap explore,
VertexIndexMap index_map, DFSVisitor vis)
: g(g), color(color), parent(parent), explore(explore),
index_map(index_map), vis(vis), pg(process_group(g)),
owner(get(vertex_owner, g)), next_out_edge(num_vertices(g))
{ }
void run(vertex_descriptor s)
{
vertex_iterator vi, vi_end;
for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) {
put(color, *vi, Color::white());
put(parent, *vi, *vi);
put(explore, *vi, *vi);
next_out_edge[get(index_map, *vi)] = out_edges(*vi, g).first;
vis.initialize_vertex(*vi, g);
}
vis.start_vertex(s, g);
if (get(owner, s) == process_id(pg)) {
send_oob(pg, get(owner, s), discover_msg, vertex_pair(s, s));
}
bool done = false;
while (!done) {
std::pair<process_id_type, int> msg = *pg.poll(true);
switch (msg.second) {
case discover_msg:
{
vertex_pair p;
receive_oob(pg, msg.first, msg.second, p);
if (p.first != p.second) {
// delete j from nomessage(j)
if (get(color, p.second) != Color::black())
local_put(color, p.second, Color::gray());
if (recover(p)) break;
}
if (get(color, p.first) == Color::white()) {
put(color, p.first, Color::gray());
put(parent, p.first, p.second);
vis.discover_vertex(p.first, g);
if (shift_center_of_activity(p.first)) break;
out_edge_iterator ei, ei_end;
for (boost::tie(ei,ei_end) = out_edges(p.first, g); ei != ei_end; ++ei)
{
// Notify everyone who may not know that the source
// vertex has been visited. They can then mark the
// corresponding color map entry gray.
if (get(parent, p.first) != target(*ei, g)
&& get(explore, p.first) != target(*ei, g)) {
vertex_pair visit(target(*ei, g), p.first);
send_oob(pg, get(owner, target(*ei, g)), visited_msg, visit);
}
}
}
}
break;
case visited_msg:
{
vertex_pair p;
receive_oob(pg, msg.first, msg.second, p);
// delete j from nomessage(j)
if (get(color, p.second) != Color::black())
local_put(color, p.second, Color::gray());
recover(p);
}
break;
case return_msg:
{
vertex_pair p;
receive_oob(pg, msg.first, msg.second, p);
// delete j from nomessage(i)
local_put(color, p.second, Color::black());
shift_center_of_activity(p.first);
}
break;
case done_msg:
{
receive_oob(pg, msg.first, msg.second, done);
// Propagate done message downward in tree
done = true;
process_id_type id = process_id(pg);
process_id_type left = 2*id + 1;
process_id_type right = left + 1;
if (left < num_processes(pg))
send_oob(pg, left, done_msg, done);
if (right < num_processes(pg))
send_oob(pg, right, done_msg, done);
}
break;
default:
BOOST_ASSERT(false);
}
}
}
private:
bool recover(const vertex_pair& p)
{
if (get(explore, p.first) == p.second) {
return shift_center_of_activity(p.first);
}
else
return false;
}
bool shift_center_of_activity(vertex_descriptor i)
{
for (out_edge_iterator ei = next_out_edge[get(index_map, i)],
ei_end = out_edges(i, g).second;
ei != ei_end; ++ei) {
vis.examine_edge(*ei, g);
vertex_descriptor k = target(*ei, g);
color_type target_color = get(color, k);
if (target_color == Color::black()) vis.forward_or_cross_edge(*ei, g);
else if (target_color == Color::gray()) vis.back_edge(*ei, g);
else {
put(explore, i, k);
vis.tree_edge(*ei, g);
vertex_pair p(k, i);
send_oob(pg, get(owner, k), discover_msg, p);
next_out_edge[get(index_map, i)] = ++ei;
return false;
}
}
next_out_edge[get(index_map, i)] = out_edges(i, g).second;
put(explore, i, i);
put(color, i, Color::black());
vis.finish_vertex(i, g);
if (get(parent, i) == i) {
send_oob(pg, 0, done_msg, true);
return true;
}
else {
vertex_pair ret(get(parent, i), i);
send_oob(pg, get(owner, ret.first), return_msg, ret);
}
return false;
}
const DistributedGraph& g;
ColorMap color;
ParentMap parent;
ExploreMap explore;
VertexIndexMap index_map;
DFSVisitor vis;
process_group_type pg;
typename property_map<DistributedGraph, vertex_owner_t>::const_type owner;
std::vector<out_edge_iterator> next_out_edge;
};
} // end namespace detail
template<typename DistributedGraph, typename ColorMap, typename ParentMap,
typename ExploreMap, typename VertexIndexMap, typename DFSVisitor>
void
tsin_depth_first_visit
(const DistributedGraph& g,
typename graph_traits<DistributedGraph>::vertex_descriptor s,
DFSVisitor vis, ColorMap color, ParentMap parent, ExploreMap explore,
VertexIndexMap index_map)
{
typedef typename graph_traits<DistributedGraph>::directed_category
directed_category;
BOOST_STATIC_ASSERT(
(is_convertible<directed_category, undirected_tag>::value));
set_property_map_role(vertex_color, color);
graph::distributed::detail::parallel_dfs
<DistributedGraph, ColorMap, ParentMap, ExploreMap, VertexIndexMap,
DFSVisitor> do_dfs(g, color, parent, explore, index_map, vis);
do_dfs.run(s);
using boost::graph::parallel::process_group;
synchronize(process_group(g));
}
template<typename DistributedGraph, typename DFSVisitor,
typename VertexIndexMap>
void
tsin_depth_first_visit
(const DistributedGraph& g,
typename graph_traits<DistributedGraph>::vertex_descriptor s,
DFSVisitor vis,
VertexIndexMap index_map)
{
typedef typename graph_traits<DistributedGraph>::vertex_descriptor
vertex_descriptor;
std::vector<default_color_type> colors(num_vertices(g));
std::vector<vertex_descriptor> parent(num_vertices(g));
std::vector<vertex_descriptor> explore(num_vertices(g));
tsin_depth_first_visit
(g, s,
vis,
make_iterator_property_map(colors.begin(), index_map),
make_iterator_property_map(parent.begin(), index_map),
make_iterator_property_map(explore.begin(), index_map),
index_map);
}
template<typename DistributedGraph, typename DFSVisitor,
typename VertexIndexMap>
void
tsin_depth_first_visit
(const DistributedGraph& g,
typename graph_traits<DistributedGraph>::vertex_descriptor s,
DFSVisitor vis)
{
tsin_depth_first_visit(g, s, vis, get(vertex_index, g));
}
} // end namespace distributed
using distributed::tsin_depth_first_visit;
} // end namespace graph
template<typename DistributedGraph, typename DFSVisitor>
void
depth_first_visit
(const DistributedGraph& g,
typename graph_traits<DistributedGraph>::vertex_descriptor s,
DFSVisitor vis)
{
graph::tsin_depth_first_visit(g, s, vis, get(vertex_index, g));
}
} // end namespace boost
#endif // BOOST_GRAPH_DISTRIBUTED_DFS_HPP
@@ -0,0 +1,50 @@
// Copyright (C) 2004-2006 The Trustees of Indiana University.
// Use, modification and distribution is subject to 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)
// Authors: Douglas Gregor
// Andrew Lumsdaine
#ifndef BOOST_GRAPH_PARALLEL_DIJKSTRA_DETAIL_HPP
#define BOOST_GRAPH_PARALLEL_DIJKSTRA_DETAIL_HPP
#ifndef BOOST_GRAPH_USE_MPI
#error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
#endif
#include <boost/property_map/property_map.hpp>
namespace boost { namespace graph { namespace distributed { namespace detail {
/**********************************************************************
* Dijkstra queue message data *
**********************************************************************/
template<typename DistanceMap, typename PredecessorMap>
class dijkstra_msg_value
{
typedef typename property_traits<DistanceMap>::value_type distance_type;
typedef typename property_traits<PredecessorMap>::value_type
predecessor_type;
public:
typedef std::pair<distance_type, predecessor_type> type;
static type create(distance_type dist, predecessor_type pred)
{ return std::make_pair(dist, pred); }
};
template<typename DistanceMap>
class dijkstra_msg_value<DistanceMap, dummy_property_map>
{
typedef typename property_traits<DistanceMap>::key_type vertex_descriptor;
public:
typedef typename property_traits<DistanceMap>::value_type type;
static type create(type dist, vertex_descriptor) { return dist; }
};
/**********************************************************************/
} } } } // end namespace boost::graph::distributed::detail
#endif // BOOST_GRAPH_PARALLEL_DIJKSTRA_DETAIL_HPP
@@ -0,0 +1,108 @@
// Copyright (C) 2004-2006 The Trustees of Indiana University.
// Use, modification and distribution is subject to 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)
// Authors: Douglas Gregor
// Andrew Lumsdaine
#ifndef BOOST_FILTERED_QUEUE_HPP
#define BOOST_FILTERED_QUEUE_HPP
#ifndef BOOST_GRAPH_USE_MPI
#error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
#endif
#include <algorithm>
namespace boost {
/** Queue adaptor that filters elements pushed into the queue
* according to some predicate.
*/
template<typename Buffer, typename Predicate>
class filtered_queue
{
public:
typedef Buffer buffer_type;
typedef Predicate predicate_type;
typedef typename Buffer::value_type value_type;
typedef typename Buffer::size_type size_type;
/**
* Constructs a new filtered queue with an initial buffer and a
* predicate.
*
* @param buffer the initial buffer
* @param pred the predicate
*/
explicit
filtered_queue(const buffer_type& buffer = buffer_type(),
const predicate_type& pred = predicate_type())
: buffer(buffer), pred(pred) {}
/** Push a value into the queue.
*
* If the predicate returns @c true for @p x, pushes @p x into the
* buffer.
*/
void push(const value_type& x) { if (pred(x)) buffer.push(x); }
/** Pop the front element off the buffer.
*
* @pre @c !empty()
*/
void pop() { buffer.pop(); }
/** Retrieve the front (top) element in the buffer.
*
* @pre @c !empty()
*/
value_type& top() { return buffer.top(); }
/**
* \overload
*/
const value_type& top() const { return buffer.top(); }
/** Determine the number of elements in the buffer. */
size_type size() const { return buffer.size(); }
/** Determine if the buffer is empty. */
bool empty() const { return buffer.empty(); }
/** Get a reference to the underlying buffer. */
buffer_type& base() { return buffer; }
const buffer_type& base() const { return buffer; }
/** Swap the contents of this with @p other. */
void swap(filtered_queue& other)
{
using std::swap;
swap(buffer, other.buffer);
swap(pred, other.pred);
}
private:
buffer_type buffer;
predicate_type pred;
};
/** Create a filtered queue. */
template<typename Buffer, typename Predicate>
inline filtered_queue<Buffer, Predicate>
make_filtered_queue(const Buffer& buffer, const Predicate& pred)
{ return filtered_queue<Buffer, Predicate>(buffer, pred); }
/** Swap a filtered_queue. */
template<typename Buffer, typename Predicate>
inline void
swap(filtered_queue<Buffer, Predicate>& x,
filtered_queue<Buffer, Predicate>& y)
{
x.swap(y);
}
} // end namespace boost
#endif // BOOST_FILTERED_QUEUE_HPP
@@ -0,0 +1,177 @@
// Copyright (C) 2004-2006 The Trustees of Indiana University.
// Use, modification and distribution is subject to 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)
// Authors: Douglas Gregor
// Andrew Lumsdaine
#include <boost/optional.hpp>
#include <cassert>
#include <boost/graph/parallel/algorithm.hpp>
#include <boost/graph/parallel/process_group.hpp>
#include <functional>
#include <algorithm>
#include <boost/graph/parallel/simple_trigger.hpp>
#ifndef BOOST_GRAPH_USE_MPI
#error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
#endif
namespace boost { namespace graph { namespace distributed {
template<BOOST_DISTRIBUTED_QUEUE_PARMS>
BOOST_DISTRIBUTED_QUEUE_TYPE::
distributed_queue(const ProcessGroup& process_group, const OwnerMap& owner,
const Buffer& buffer, bool polling)
: process_group(process_group, attach_distributed_object()),
owner(owner),
buffer(buffer),
polling(polling)
{
if (!polling)
outgoing_buffers.reset(
new outgoing_buffers_t(num_processes(process_group)));
setup_triggers();
}
template<BOOST_DISTRIBUTED_QUEUE_PARMS>
BOOST_DISTRIBUTED_QUEUE_TYPE::
distributed_queue(const ProcessGroup& process_group, const OwnerMap& owner,
const Buffer& buffer, const UnaryPredicate& pred,
bool polling)
: process_group(process_group, attach_distributed_object()),
owner(owner),
buffer(buffer),
pred(pred),
polling(polling)
{
if (!polling)
outgoing_buffers.reset(
new outgoing_buffers_t(num_processes(process_group)));
setup_triggers();
}
template<BOOST_DISTRIBUTED_QUEUE_PARMS>
BOOST_DISTRIBUTED_QUEUE_TYPE::
distributed_queue(const ProcessGroup& process_group, const OwnerMap& owner,
const UnaryPredicate& pred, bool polling)
: process_group(process_group, attach_distributed_object()),
owner(owner),
pred(pred),
polling(polling)
{
if (!polling)
outgoing_buffers.reset(
new outgoing_buffers_t(num_processes(process_group)));
setup_triggers();
}
template<BOOST_DISTRIBUTED_QUEUE_PARMS>
void
BOOST_DISTRIBUTED_QUEUE_TYPE::push(const value_type& x)
{
typename ProcessGroup::process_id_type dest = get(owner, x);
if (outgoing_buffers)
outgoing_buffers->at(dest).push_back(x);
else if (dest == process_id(process_group))
buffer.push(x);
else
send(process_group, get(owner, x), msg_push, x);
}
template<BOOST_DISTRIBUTED_QUEUE_PARMS>
bool
BOOST_DISTRIBUTED_QUEUE_TYPE::empty() const
{
/* Processes will stay here until the buffer is nonempty or
synchronization with the other processes indicates that all local
buffers are empty (and no messages are in transit).
*/
while (buffer.empty() && !do_synchronize()) ;
return buffer.empty();
}
template<BOOST_DISTRIBUTED_QUEUE_PARMS>
typename BOOST_DISTRIBUTED_QUEUE_TYPE::size_type
BOOST_DISTRIBUTED_QUEUE_TYPE::size() const
{
empty();
return buffer.size();
}
template<BOOST_DISTRIBUTED_QUEUE_PARMS>
void BOOST_DISTRIBUTED_QUEUE_TYPE::setup_triggers()
{
using boost::graph::parallel::simple_trigger;
simple_trigger(process_group, msg_push, this,
&distributed_queue::handle_push);
simple_trigger(process_group, msg_multipush, this,
&distributed_queue::handle_multipush);
}
template<BOOST_DISTRIBUTED_QUEUE_PARMS>
void
BOOST_DISTRIBUTED_QUEUE_TYPE::
handle_push(int /*source*/, int /*tag*/, const value_type& value,
trigger_receive_context)
{
if (pred(value)) buffer.push(value);
}
template<BOOST_DISTRIBUTED_QUEUE_PARMS>
void
BOOST_DISTRIBUTED_QUEUE_TYPE::
handle_multipush(int /*source*/, int /*tag*/,
const std::vector<value_type>& values,
trigger_receive_context)
{
for (std::size_t i = 0; i < values.size(); ++i)
if (pred(values[i])) buffer.push(values[i]);
}
template<BOOST_DISTRIBUTED_QUEUE_PARMS>
bool
BOOST_DISTRIBUTED_QUEUE_TYPE::do_synchronize() const
{
#ifdef PBGL_ACCOUNTING
++num_synchronizations;
#endif
using boost::parallel::all_reduce;
using std::swap;
typedef typename ProcessGroup::process_id_type process_id_type;
if (outgoing_buffers) {
// Transfer all of the push requests
process_id_type id = process_id(process_group);
process_id_type np = num_processes(process_group);
for (process_id_type dest = 0; dest < np; ++dest) {
outgoing_buffer_t& outgoing = outgoing_buffers->at(dest);
std::size_t size = outgoing.size();
if (size != 0) {
if (dest != id) {
send(process_group, dest, msg_multipush, outgoing);
} else {
for (std::size_t i = 0; i < size; ++i)
buffer.push(outgoing[i]);
}
outgoing.clear();
}
}
}
synchronize(process_group);
unsigned local_size = buffer.size();
unsigned global_size =
all_reduce(process_group, local_size, std::plus<unsigned>());
return global_size == 0;
}
} } } // end namespace boost::graph::distributed
@@ -0,0 +1,259 @@
// Copyright (C) 2005-2006 The Trustees of Indiana University.
// Use, modification and distribution is subject to 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)
// Authors: Douglas Gregor
// Andrew Lumsdaine
#ifndef BOOST_GRAPH_DETAIL_REMOTE_UPDATE_SET_HPP
#define BOOST_GRAPH_DETAIL_REMOTE_UPDATE_SET_HPP
#ifndef BOOST_GRAPH_USE_MPI
#error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
#endif
#include <boost/graph/parallel/process_group.hpp>
#include <boost/type_traits/is_convertible.hpp>
#include <vector>
#include <boost/assert.hpp>
#include <boost/optional.hpp>
#include <queue>
namespace boost { namespace graph { namespace detail {
template<typename ProcessGroup>
void do_synchronize(ProcessGroup& pg)
{
using boost::parallel::synchronize;
synchronize(pg);
}
struct remote_set_queued {};
struct remote_set_immediate {};
template<typename ProcessGroup>
class remote_set_semantics
{
BOOST_STATIC_CONSTANT
(bool,
queued = (is_convertible<
typename ProcessGroup::communication_category,
parallel::bsp_process_group_tag>::value));
public:
typedef typename mpl::if_c<queued,
remote_set_queued,
remote_set_immediate>::type type;
};
template<typename Derived, typename ProcessGroup, typename Value,
typename OwnerMap,
typename Semantics = typename remote_set_semantics<ProcessGroup>::type>
class remote_update_set;
/**********************************************************************
* Remote updating set that queues messages until synchronization *
**********************************************************************/
template<typename Derived, typename ProcessGroup, typename Value,
typename OwnerMap>
class remote_update_set<Derived, ProcessGroup, Value, OwnerMap,
remote_set_queued>
{
typedef typename property_traits<OwnerMap>::key_type Key;
typedef std::vector<std::pair<Key, Value> > Updates;
typedef typename Updates::size_type updates_size_type;
typedef typename Updates::value_type updates_pair_type;
public:
private:
typedef typename ProcessGroup::process_id_type process_id_type;
enum message_kind {
/** Message containing the number of updates that will be sent in
* a msg_updates message that will immediately follow. This
* message will contain a single value of type
* updates_size_type.
*/
msg_num_updates,
/** Contains (key, value) pairs with all of the updates from a
* particular source. The number of updates is variable, but will
* be provided in a msg_num_updates message that immediately
* preceeds this message.
*
*/
msg_updates
};
struct handle_messages
{
explicit
handle_messages(remote_update_set* self, const ProcessGroup& pg)
: self(self), update_sizes(num_processes(pg), 0) { }
void operator()(process_id_type source, int tag)
{
switch(tag) {
case msg_num_updates:
{
// Receive the # of updates
updates_size_type num_updates;
receive(self->process_group, source, tag, num_updates);
update_sizes[source] = num_updates;
}
break;
case msg_updates:
{
updates_size_type num_updates = update_sizes[source];
BOOST_ASSERT(num_updates);
// Receive the actual updates
std::vector<updates_pair_type> updates(num_updates);
receive(self->process_group, source, msg_updates, &updates[0],
num_updates);
// Send updates to derived "receive_update" member
Derived* derived = static_cast<Derived*>(self);
for (updates_size_type u = 0; u < num_updates; ++u)
derived->receive_update(source, updates[u].first, updates[u].second);
update_sizes[source] = 0;
}
break;
};
}
private:
remote_update_set* self;
std::vector<updates_size_type> update_sizes;
};
friend struct handle_messages;
protected:
remote_update_set(const ProcessGroup& pg, const OwnerMap& owner)
: process_group(pg, handle_messages(this, pg)),
updates(num_processes(pg)), owner(owner) {
}
void update(const Key& key, const Value& value)
{
if (get(owner, key) == process_id(process_group)) {
Derived* derived = static_cast<Derived*>(this);
derived->receive_update(get(owner, key), key, value);
}
else {
updates[get(owner, key)].push_back(std::make_pair(key, value));
}
}
void collect() { }
void synchronize()
{
// Emit all updates and then remove them
process_id_type num_processes = updates.size();
for (process_id_type p = 0; p < num_processes; ++p) {
if (!updates[p].empty()) {
send(process_group, p, msg_num_updates, updates[p].size());
send(process_group, p, msg_updates,
&updates[p].front(), updates[p].size());
updates[p].clear();
}
}
do_synchronize(process_group);
}
ProcessGroup process_group;
private:
std::vector<Updates> updates;
OwnerMap owner;
};
/**********************************************************************
* Remote updating set that sends messages immediately *
**********************************************************************/
template<typename Derived, typename ProcessGroup, typename Value,
typename OwnerMap>
class remote_update_set<Derived, ProcessGroup, Value, OwnerMap,
remote_set_immediate>
{
typedef typename property_traits<OwnerMap>::key_type Key;
typedef std::pair<Key, Value> update_pair_type;
typedef typename std::vector<update_pair_type>::size_type updates_size_type;
public:
typedef typename ProcessGroup::process_id_type process_id_type;
private:
enum message_kind {
/** Contains a (key, value) pair that will be updated. */
msg_update
};
struct handle_messages
{
explicit handle_messages(remote_update_set* self, const ProcessGroup& pg)
: self(self)
{ update_sizes.resize(num_processes(pg), 0); }
void operator()(process_id_type source, int tag)
{
// Receive the # of updates
BOOST_ASSERT(tag == msg_update);
update_pair_type update;
receive(self->process_group, source, tag, update);
// Send update to derived "receive_update" member
Derived* derived = static_cast<Derived*>(self);
derived->receive_update(source, update.first, update.second);
}
private:
std::vector<updates_size_type> update_sizes;
remote_update_set* self;
};
friend struct handle_messages;
protected:
remote_update_set(const ProcessGroup& pg, const OwnerMap& owner)
: process_group(pg, handle_messages(this, pg)), owner(owner) { }
void update(const Key& key, const Value& value)
{
if (get(owner, key) == process_id(process_group)) {
Derived* derived = static_cast<Derived*>(this);
derived->receive_update(get(owner, key), key, value);
}
else
send(process_group, get(owner, key), msg_update,
update_pair_type(key, value));
}
void collect()
{
typedef std::pair<process_id_type, int> probe_type;
handle_messages handler(this, process_group);
while (optional<probe_type> stp = probe(process_group))
if (stp->second == msg_update) handler(stp->first, stp->second);
}
void synchronize()
{
do_synchronize(process_group);
}
ProcessGroup process_group;
OwnerMap owner;
};
} } } // end namespace boost::graph::detail
#endif // BOOST_GRAPH_DETAIL_REMOTE_UPDATE_SET_HPP
@@ -0,0 +1,84 @@
// -*- C++ -*-
// Copyright (C) 2007 Douglas Gregor <doug.gregor@gmail.com>
// Use, modification and distribution is subject to 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_GRAPH_DISTRIBUTED_TAG_ALLOCATOR_HPP
#define BOOST_GRAPH_DISTRIBUTED_TAG_ALLOCATOR_HPP
#ifndef BOOST_GRAPH_USE_MPI
#error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
#endif
#include <vector>
namespace boost { namespace graph { namespace distributed { namespace detail {
/**
* \brief The tag allocator allows clients to request unique tags that
* can be used for one-time communications.
*
* The tag allocator hands out tag values from a predefined maximum
* (given in the constructor) moving downward. Tags are provided one
* at a time via a @c token. When the @c token goes out of scope, the
* tag is returned and may be reallocated. These tags should be used,
* for example, for one-time communication of values.
*/
class tag_allocator {
public:
class token;
friend class token;
/**
* Construct a new tag allocator that provides unique tags starting
* with the value @p top_tag and moving lower, as necessary.
*/
explicit tag_allocator(int top_tag) : bottom(top_tag) { }
/**
* Retrieve a new tag. The token itself holds onto the tag, which
* will be released when the token is destroyed.
*/
token get_tag();
private:
int bottom;
std::vector<int> freed;
};
/**
* A token used to represent an allocated tag.
*/
class tag_allocator::token {
public:
/// Transfer ownership of the tag from @p other.
token(const token& other);
/// De-allocate the tag, if this token still owns it.
~token();
/// Retrieve the tag allocated for this task.
operator int() const { return tag_; }
private:
/// Create a token with a specific tag from the given tag_allocator
token(tag_allocator* allocator, int tag)
: allocator(allocator), tag_(tag) { }
/// Undefined: tokens are not copy-assignable
token& operator=(const token&);
/// The allocator from which this tag was allocated.
tag_allocator* allocator;
/// The stored tag flag. If -1, this token does not own the tag.
mutable int tag_;
friend class tag_allocator;
};
} } } } // end namespace boost::graph::distributed::detail
#endif // BOOST_GRAPH_DISTRIBUTED_TAG_ALLOCATOR_HPP
@@ -0,0 +1,204 @@
// Copyright (C) 2004-2006 The Trustees of Indiana University.
// Use, modification and distribution is subject to 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)
// Authors: Douglas Gregor
// Andrew Lumsdaine
#ifndef BOOST_GRAPH_PARALLEL_DIJKSTRA_HPP
#define BOOST_GRAPH_PARALLEL_DIJKSTRA_HPP
#ifndef BOOST_GRAPH_USE_MPI
#error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
#endif
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <boost/graph/overloading.hpp>
#include <boost/graph/distributed/concepts.hpp>
#include <boost/graph/parallel/properties.hpp>
#include <boost/graph/distributed/crauser_et_al_shortest_paths.hpp>
#include <boost/graph/distributed/eager_dijkstra_shortest_paths.hpp>
namespace boost {
namespace graph { namespace detail {
template<typename Lookahead>
struct parallel_dijkstra_impl2
{
template<typename DistributedGraph, typename DijkstraVisitor,
typename PredecessorMap, typename DistanceMap,
typename WeightMap, typename IndexMap, typename ColorMap,
typename Compare, typename Combine, typename DistInf,
typename DistZero>
static void
run(const DistributedGraph& g,
typename graph_traits<DistributedGraph>::vertex_descriptor s,
PredecessorMap predecessor, DistanceMap distance,
typename property_traits<DistanceMap>::value_type lookahead,
WeightMap weight, IndexMap index_map, ColorMap color_map,
Compare compare, Combine combine, DistInf inf, DistZero zero,
DijkstraVisitor vis)
{
eager_dijkstra_shortest_paths(g, s, predecessor, distance, lookahead,
weight, index_map, color_map, compare,
combine, inf, zero, vis);
}
};
template<>
struct parallel_dijkstra_impl2< ::boost::param_not_found >
{
template<typename DistributedGraph, typename DijkstraVisitor,
typename PredecessorMap, typename DistanceMap,
typename WeightMap, typename IndexMap, typename ColorMap,
typename Compare, typename Combine, typename DistInf,
typename DistZero>
static void
run(const DistributedGraph& g,
typename graph_traits<DistributedGraph>::vertex_descriptor s,
PredecessorMap predecessor, DistanceMap distance,
::boost::param_not_found,
WeightMap weight, IndexMap index_map, ColorMap color_map,
Compare compare, Combine combine, DistInf inf, DistZero zero,
DijkstraVisitor vis)
{
crauser_et_al_shortest_paths(g, s, predecessor, distance, weight,
index_map, color_map, compare, combine,
inf, zero, vis);
}
};
template<typename ColorMap>
struct parallel_dijkstra_impl
{
template<typename DistributedGraph, typename DijkstraVisitor,
typename PredecessorMap, typename DistanceMap,
typename Lookahead, typename WeightMap, typename IndexMap,
typename Compare, typename Combine,
typename DistInf, typename DistZero>
static void
run(const DistributedGraph& g,
typename graph_traits<DistributedGraph>::vertex_descriptor s,
PredecessorMap predecessor, DistanceMap distance,
Lookahead lookahead,
WeightMap weight, IndexMap index_map, ColorMap color_map,
Compare compare, Combine combine, DistInf inf, DistZero zero,
DijkstraVisitor vis)
{
graph::detail::parallel_dijkstra_impl2<Lookahead>
::run(g, s, predecessor, distance, lookahead, weight, index_map,
color_map, compare, combine, inf, zero, vis);
}
};
template<>
struct parallel_dijkstra_impl< ::boost::param_not_found >
{
private:
template<typename DistributedGraph, typename DijkstraVisitor,
typename PredecessorMap, typename DistanceMap,
typename Lookahead, typename WeightMap, typename IndexMap,
typename ColorMap, typename Compare, typename Combine,
typename DistInf, typename DistZero>
static void
run_impl(const DistributedGraph& g,
typename graph_traits<DistributedGraph>::vertex_descriptor s,
PredecessorMap predecessor, DistanceMap distance,
Lookahead lookahead, WeightMap weight, IndexMap index_map,
ColorMap color_map, Compare compare, Combine combine,
DistInf inf, DistZero zero, DijkstraVisitor vis)
{
BGL_FORALL_VERTICES_T(u, g, DistributedGraph)
BGL_FORALL_OUTEDGES_T(u, e, g, DistributedGraph)
local_put(color_map, target(e, g), white_color);
graph::detail::parallel_dijkstra_impl2<Lookahead>
::run(g, s, predecessor, distance, lookahead, weight, index_map,
color_map, compare, combine, inf, zero, vis);
}
public:
template<typename DistributedGraph, typename DijkstraVisitor,
typename PredecessorMap, typename DistanceMap,
typename Lookahead, typename WeightMap, typename IndexMap,
typename Compare, typename Combine,
typename DistInf, typename DistZero>
static void
run(const DistributedGraph& g,
typename graph_traits<DistributedGraph>::vertex_descriptor s,
PredecessorMap predecessor, DistanceMap distance,
Lookahead lookahead, WeightMap weight, IndexMap index_map,
::boost::param_not_found,
Compare compare, Combine combine, DistInf inf, DistZero zero,
DijkstraVisitor vis)
{
typedef typename graph_traits<DistributedGraph>::vertices_size_type
vertices_size_type;
vertices_size_type n = num_vertices(g);
std::vector<default_color_type> colors(n, white_color);
run_impl(g, s, predecessor, distance, lookahead, weight, index_map,
make_iterator_property_map(colors.begin(), index_map),
compare, combine, inf, zero, vis);
}
};
} } // end namespace graph::detail
/** Dijkstra's single-source shortest paths algorithm for distributed
* graphs.
*
* Also implements the heuristics of:
*
* Andreas Crauser, Kurt Mehlhorn, Ulrich Meyer, and Peter
* Sanders. A Parallelization of Dijkstra's Shortest Path
* Algorithm. In Lubos Brim, Jozef Gruska, and Jiri Zlatuska,
* editors, Mathematical Foundations of Computer Science (MFCS),
* volume 1450 of Lecture Notes in Computer Science, pages
* 722--731, 1998. Springer.
*/
template<typename DistributedGraph, typename DijkstraVisitor,
typename PredecessorMap, typename DistanceMap,
typename WeightMap, typename IndexMap, typename Compare,
typename Combine, typename DistInf, typename DistZero,
typename T, typename Tag, typename Base>
inline
void
dijkstra_shortest_paths
(const DistributedGraph& g,
typename graph_traits<DistributedGraph>::vertex_descriptor s,
PredecessorMap predecessor, DistanceMap distance, WeightMap weight,
IndexMap index_map,
Compare compare, Combine combine, DistInf inf, DistZero zero,
DijkstraVisitor vis,
const bgl_named_params<T, Tag, Base>& params
BOOST_GRAPH_ENABLE_IF_MODELS_PARM(DistributedGraph,distributed_graph_tag))
{
typedef typename graph_traits<DistributedGraph>::vertices_size_type
vertices_size_type;
// Build a distributed property map for vertex colors, if we need it
bool use_default_color_map
= is_default_param(get_param(params, vertex_color));
vertices_size_type n = use_default_color_map? num_vertices(g) : 1;
std::vector<default_color_type> color(n, white_color);
typedef iterator_property_map<std::vector<default_color_type>::iterator,
IndexMap> DefColorMap;
DefColorMap color_map(color.begin(), index_map);
typedef typename get_param_type< vertex_color_t, bgl_named_params<T, Tag, Base> >::type color_map_type;
graph::detail::parallel_dijkstra_impl<color_map_type>
::run(g, s, predecessor, distance,
get_param(params, lookahead_t()),
weight, index_map,
get_param(params, vertex_color),
compare, combine, inf, zero, vis);
}
} // end namespace boost
#endif // BOOST_GRAPH_PARALLEL_DIJKSTRA_HPP
@@ -0,0 +1,154 @@
// Copyright (C) 2005-2006 The Trustees of Indiana University.
// Use, modification and distribution is subject to 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)
// Authors: Peter Gottschling
// Douglas Gregor
// Andrew Lumsdaine
#include <boost/graph/iteration_macros.hpp>
#include <boost/property_map/parallel/global_index_map.hpp>
#ifndef BOOST_GRAPH_DISTRIBUTED_GRAPH_UTILITY_INCLUDE
#define BOOST_GRAPH_DISTRIBUTED_GRAPH_UTILITY_INCLUDE
#ifndef BOOST_GRAPH_USE_MPI
#error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
#endif
namespace boost { namespace graph {
template <class Property, class Graph>
void property_on_inedges(Property p, const Graph& g)
{
BGL_FORALL_VERTICES_T(u, g, Graph)
BGL_FORALL_INEDGES_T(u, e, g, Graph)
request(p, e);
synchronize(p);
}
// For reverse graphs
template <class Property, class Graph>
void property_on_outedges(Property p, const Graph& g)
{
BGL_FORALL_VERTICES_T(u, g, Graph)
BGL_FORALL_OUTEDGES_T(u, e, g, Graph)
request(p, e);
synchronize(p);
}
template <class Property, class Graph>
void property_on_successors(Property p, const Graph& g)
{
BGL_FORALL_VERTICES_T(u, g, Graph)
BGL_FORALL_OUTEDGES_T(u, e, g, Graph)
request(p, target(e, g));
synchronize(p);
}
template <class Property, class Graph>
void property_on_predecessors(Property p, const Graph& g)
{
BGL_FORALL_VERTICES_T(u, g, Graph)
BGL_FORALL_INEDGES_T(u, e, g, Graph)
request(p, source(e, g));
synchronize(p);
}
// Like successors and predecessors but saves one synchronize (and a call)
template <class Property, class Graph>
void property_on_adjacents(Property p, const Graph& g)
{
BGL_FORALL_VERTICES_T(u, g, Graph) {
BGL_FORALL_OUTEDGES_T(u, e, g, Graph)
request(p, target(e, g));
BGL_FORALL_INEDGES_T(u, e, g, Graph)
request(p, source(e, g));
}
synchronize(p);
}
template <class PropertyIn, class PropertyOut, class Graph>
void copy_vertex_property(PropertyIn p_in, PropertyOut p_out, Graph& g)
{
BGL_FORALL_VERTICES_T(u, g, Graph)
put(p_out, u, get(p_in, g));
}
template <class PropertyIn, class PropertyOut, class Graph>
void copy_edge_property(PropertyIn p_in, PropertyOut p_out, Graph& g)
{
BGL_FORALL_EDGES_T(e, g, Graph)
put(p_out, e, get(p_in, g));
}
namespace distributed {
// Define global_index<Graph> global(graph);
// Then global(v) returns global index of v
template <typename Graph>
struct global_index
{
typedef typename property_map<Graph, vertex_index_t>::const_type
VertexIndexMap;
typedef typename property_map<Graph, vertex_global_t>::const_type
VertexGlobalMap;
explicit global_index(Graph const& g)
: global_index_map(process_group(g), num_vertices(g), get(vertex_index, g),
get(vertex_global, g)) {}
int operator() (typename graph_traits<Graph>::vertex_descriptor v)
{ return get(global_index_map, v); }
protected:
boost::parallel::global_index_map<VertexIndexMap, VertexGlobalMap>
global_index_map;
};
template<typename T>
struct additive_reducer {
BOOST_STATIC_CONSTANT(bool, non_default_resolver = true);
template<typename K>
T operator()(const K&) const { return T(0); }
template<typename K>
T operator()(const K&, const T& local, const T& remote) const { return local + remote; }
};
template <typename T>
struct choose_min_reducer {
BOOST_STATIC_CONSTANT(bool, non_default_resolver = true);
template<typename K>
T operator()(const K&) const { return (std::numeric_limits<T>::max)(); }
template<typename K>
T operator()(const K&, const T& x, const T& y) const
{ return x < y ? x : y; }
};
// To use a property map syntactically like a function
template <typename PropertyMap>
struct property_map_reader
{
explicit property_map_reader(PropertyMap pm) : pm(pm) {}
template <typename T>
typename PropertyMap::value_type
operator() (const T& v)
{
return get(pm, v);
}
private:
PropertyMap pm;
};
} // namespace distributed
}} // namespace boost::graph
#endif // BOOST_GRAPH_DISTRIBUTED_GRAPH_UTILITY_INCLUDE
@@ -0,0 +1,447 @@
// Copyright (C) 2004-2006 The Trustees of Indiana University.
// Use, modification and distribution is subject to 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)
// Authors: Douglas Gregor
// Andrew Lumsdaine
/**************************************************************************
* This source file implements a variation on distributed Dijkstra's *
* algorithm that can expose additional parallelism by permitting *
* vertices within a certain distance from the minimum to be processed, *
* even though they may not be at their final distance. This can *
* introduce looping, but the algorithm will still terminate so long as *
* there are no negative loops. *
**************************************************************************/
#ifndef BOOST_GRAPH_EAGER_DIJKSTRA_SHORTEST_PATHS_HPP
#define BOOST_GRAPH_EAGER_DIJKSTRA_SHORTEST_PATHS_HPP
#ifndef BOOST_GRAPH_USE_MPI
#error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
#endif
#include <boost/assert.hpp>
#include <boost/graph/distributed/detail/dijkstra_shortest_paths.hpp>
#include <boost/property_map/parallel/caching_property_map.hpp>
#include <boost/pending/indirect_cmp.hpp>
#include <boost/graph/distributed/detail/remote_update_set.hpp>
#include <vector>
#include <boost/graph/breadth_first_search.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <boost/graph/parallel/container_traits.hpp>
#ifdef PBGL_ACCOUNTING
# include <boost/graph/accounting.hpp>
# include <numeric>
#endif // PBGL_ACCOUNTING
#ifdef MUTABLE_QUEUE
# include <boost/pending/mutable_queue.hpp>
#endif
namespace boost { namespace graph { namespace distributed {
#ifdef PBGL_ACCOUNTING
struct eager_dijkstra_shortest_paths_stats_t
{
/* The value of the lookahead parameter. */
double lookahead;
/* Total wall-clock time used by the algorithm.*/
accounting::time_type execution_time;
/* The number of vertices deleted in each superstep. */
std::vector<std::size_t> deleted_vertices;
template<typename OutputStream>
void print(OutputStream& out)
{
double avg_deletions = std::accumulate(deleted_vertices.begin(),
deleted_vertices.end(),
0.0);
avg_deletions /= deleted_vertices.size();
out << "Problem = \"Single-Source Shortest Paths\"\n"
<< "Algorithm = \"Eager Dijkstra\"\n"
<< "Function = eager_dijkstra_shortest_paths\n"
<< "(P) Lookahead = " << lookahead << "\n"
<< "Wall clock time = " << accounting::print_time(execution_time)
<< "\nSupersteps = " << deleted_vertices.size() << "\n"
<< "Avg. deletions per superstep = " << avg_deletions << "\n";
}
};
static eager_dijkstra_shortest_paths_stats_t eager_dijkstra_shortest_paths_stats;
#endif
namespace detail {
// Borrowed from BGL's dijkstra_shortest_paths
template <class UniformCostVisitor, class Queue,
class WeightMap, class PredecessorMap, class DistanceMap,
class BinaryFunction, class BinaryPredicate>
struct parallel_dijkstra_bfs_visitor : bfs_visitor<>
{
typedef typename property_traits<DistanceMap>::value_type distance_type;
parallel_dijkstra_bfs_visitor(UniformCostVisitor vis, Queue& Q,
WeightMap w, PredecessorMap p, DistanceMap d,
BinaryFunction combine, BinaryPredicate compare,
distance_type zero)
: m_vis(vis), m_Q(Q), m_weight(w), m_predecessor(p), m_distance(d),
m_combine(combine), m_compare(compare), m_zero(zero) { }
template <class Vertex, class Graph>
void initialize_vertex(Vertex u, Graph& g)
{ m_vis.initialize_vertex(u, g); }
template <class Vertex, class Graph>
void discover_vertex(Vertex u, Graph& g) { m_vis.discover_vertex(u, g); }
template <class Vertex, class Graph>
void examine_vertex(Vertex u, Graph& g) { m_vis.examine_vertex(u, g); }
/* Since the eager formulation of Parallel Dijkstra's algorithm can
loop, we may relax on *any* edge, not just those associated with
white and gray targets. */
template <class Edge, class Graph>
void examine_edge(Edge e, Graph& g) {
if (m_compare(get(m_weight, e), m_zero))
boost::throw_exception(negative_edge());
m_vis.examine_edge(e, g);
boost::parallel::caching_property_map<PredecessorMap> c_pred(m_predecessor);
boost::parallel::caching_property_map<DistanceMap> c_dist(m_distance);
distance_type old_distance = get(c_dist, target(e, g));
bool m_decreased = relax(e, g, m_weight, c_pred, c_dist,
m_combine, m_compare);
/* On x86 Linux with optimization, we sometimes get into a
horrible case where m_decreased is true but the distance hasn't
actually changed. This occurs when the comparison inside
relax() occurs with the 80-bit precision of the x87 floating
point unit, but the difference is lost when the resulting
values are written back to lower-precision memory (e.g., a
double). With the eager Dijkstra's implementation, this results
in looping. */
if (m_decreased && old_distance != get(c_dist, target(e, g))) {
m_Q.update(target(e, g));
m_vis.edge_relaxed(e, g);
} else
m_vis.edge_not_relaxed(e, g);
}
template <class Vertex, class Graph>
void finish_vertex(Vertex u, Graph& g) { m_vis.finish_vertex(u, g); }
UniformCostVisitor m_vis;
Queue& m_Q;
WeightMap m_weight;
PredecessorMap m_predecessor;
DistanceMap m_distance;
BinaryFunction m_combine;
BinaryPredicate m_compare;
distance_type m_zero;
};
/**********************************************************************
* Dijkstra queue that implements arbitrary "lookahead" *
**********************************************************************/
template<typename Graph, typename Combine, typename Compare,
typename VertexIndexMap, typename DistanceMap,
typename PredecessorMap>
class lookahead_dijkstra_queue
: public graph::detail::remote_update_set<
lookahead_dijkstra_queue<
Graph, Combine, Compare, VertexIndexMap, DistanceMap,
PredecessorMap>,
typename boost::graph::parallel::process_group_type<Graph>::type,
typename dijkstra_msg_value<DistanceMap, PredecessorMap>::type,
typename property_map<Graph, vertex_owner_t>::const_type>
{
typedef typename graph_traits<Graph>::vertex_descriptor
vertex_descriptor;
typedef lookahead_dijkstra_queue self_type;
typedef typename boost::graph::parallel::process_group_type<Graph>::type
process_group_type;
typedef dijkstra_msg_value<DistanceMap, PredecessorMap> msg_value_creator;
typedef typename msg_value_creator::type msg_value_type;
typedef typename property_map<Graph, vertex_owner_t>::const_type
OwnerPropertyMap;
typedef graph::detail::remote_update_set<self_type, process_group_type,
msg_value_type, OwnerPropertyMap>
inherited;
// Priority queue for tentative distances
typedef indirect_cmp<DistanceMap, Compare> queue_compare_type;
typedef typename property_traits<DistanceMap>::value_type distance_type;
#ifdef MUTABLE_QUEUE
typedef mutable_queue<vertex_descriptor, std::vector<vertex_descriptor>,
queue_compare_type, VertexIndexMap> queue_type;
#else
typedef relaxed_heap<vertex_descriptor, queue_compare_type,
VertexIndexMap> queue_type;
#endif // MUTABLE_QUEUE
typedef typename process_group_type::process_id_type process_id_type;
public:
typedef vertex_descriptor value_type;
lookahead_dijkstra_queue(const Graph& g,
const Combine& combine,
const Compare& compare,
const VertexIndexMap& id,
const DistanceMap& distance_map,
const PredecessorMap& predecessor_map,
distance_type lookahead)
: inherited(boost::graph::parallel::process_group(g), get(vertex_owner, g)),
queue(num_vertices(g), queue_compare_type(distance_map, compare), id),
distance_map(distance_map),
predecessor_map(predecessor_map),
min_distance(0),
lookahead(lookahead)
#ifdef PBGL_ACCOUNTING
, local_deletions(0)
#endif
{ }
void push(const value_type& x)
{
msg_value_type msg_value =
msg_value_creator::create(get(distance_map, x),
predecessor_value(get(predecessor_map, x)));
inherited::update(x, msg_value);
}
void update(const value_type& x) { push(x); }
void pop()
{
queue.pop();
#ifdef PBGL_ACCOUNTING
++local_deletions;
#endif
}
value_type& top() { return queue.top(); }
const value_type& top() const { return queue.top(); }
bool empty()
{
inherited::collect();
// If there are no suitable messages, wait until we get something
while (!has_suitable_vertex()) {
if (do_synchronize()) return true;
}
// Return true only if nobody has any messages; false if we
// have suitable messages
return false;
}
private:
vertex_descriptor predecessor_value(vertex_descriptor v) const
{ return v; }
vertex_descriptor
predecessor_value(property_traits<dummy_property_map>::reference) const
{ return graph_traits<Graph>::null_vertex(); }
bool has_suitable_vertex() const
{
return (!queue.empty()
&& get(distance_map, queue.top()) <= min_distance + lookahead);
}
bool do_synchronize()
{
using boost::parallel::all_reduce;
using boost::parallel::minimum;
inherited::synchronize();
// TBD: could use combine here, but then we need to stop using
// minimum<distance_type>() as the function object.
distance_type local_distance =
queue.empty()? (std::numeric_limits<distance_type>::max)()
: get(distance_map, queue.top());
all_reduce(this->process_group, &local_distance, &local_distance + 1,
&min_distance, minimum<distance_type>());
#ifdef PBGL_ACCOUNTING
std::size_t deletions = 0;
all_reduce(this->process_group, &local_deletions, &local_deletions + 1,
&deletions, std::plus<std::size_t>());
if (process_id(this->process_group) == 0)
eager_dijkstra_shortest_paths_stats.deleted_vertices
.push_back(deletions);
local_deletions = 0;
BOOST_ASSERT(deletions > 0);
#endif
return min_distance == (std::numeric_limits<distance_type>::max)();
}
public:
void
receive_update(process_id_type source, vertex_descriptor vertex,
distance_type distance)
{
// Update the queue if the received distance is better than
// the distance we know locally
if (distance <= get(distance_map, vertex)) {
// Update the local distance map
put(distance_map, vertex, distance);
bool is_in_queue = queue.contains(vertex);
if (!is_in_queue)
queue.push(vertex);
else
queue.update(vertex);
}
}
void
receive_update(process_id_type source, vertex_descriptor vertex,
std::pair<distance_type, vertex_descriptor> p)
{
if (p.first <= get(distance_map, vertex)) {
put(predecessor_map, vertex, p.second);
receive_update(source, vertex, p.first);
}
}
private:
queue_type queue;
DistanceMap distance_map;
PredecessorMap predecessor_map;
distance_type min_distance;
distance_type lookahead;
#ifdef PBGL_ACCOUNTING
std::size_t local_deletions;
#endif
};
/**********************************************************************/
} // end namespace detail
template<typename DistributedGraph, typename DijkstraVisitor,
typename PredecessorMap, typename DistanceMap, typename WeightMap,
typename IndexMap, typename ColorMap, typename Compare,
typename Combine, typename DistInf, typename DistZero>
void
eager_dijkstra_shortest_paths
(const DistributedGraph& g,
typename graph_traits<DistributedGraph>::vertex_descriptor s,
PredecessorMap predecessor, DistanceMap distance,
typename property_traits<DistanceMap>::value_type lookahead,
WeightMap weight, IndexMap index_map, ColorMap color_map,
Compare compare, Combine combine, DistInf inf, DistZero zero,
DijkstraVisitor vis)
{
typedef typename boost::graph::parallel::process_group_type<DistributedGraph>::type
process_group_type;
typedef typename graph_traits<DistributedGraph>::vertex_descriptor
Vertex;
typedef typename graph_traits<DistributedGraph>::vertices_size_type
vertices_size_type;
#ifdef PBGL_ACCOUNTING
eager_dijkstra_shortest_paths_stats.deleted_vertices.clear();
eager_dijkstra_shortest_paths_stats.lookahead = lookahead;
eager_dijkstra_shortest_paths_stats.execution_time = accounting::get_time();
#endif
// Initialize local portion of property maps
typename graph_traits<DistributedGraph>::vertex_iterator ui, ui_end;
for (boost::tie(ui, ui_end) = vertices(g); ui != ui_end; ++ui) {
put(distance, *ui, inf);
put(predecessor, *ui, *ui);
}
put(distance, s, zero);
// Dijkstra Queue
typedef detail::lookahead_dijkstra_queue
<DistributedGraph, Combine, Compare, IndexMap, DistanceMap,
PredecessorMap> Queue;
Queue Q(g, combine, compare, index_map, distance,
predecessor, lookahead);
// Parallel Dijkstra visitor
detail::parallel_dijkstra_bfs_visitor
<DijkstraVisitor, Queue, WeightMap, PredecessorMap, DistanceMap, Combine,
Compare> bfs_vis(vis, Q, weight, predecessor, distance, combine, compare,
zero);
set_property_map_role(vertex_color, color_map);
set_property_map_role(vertex_distance, distance);
breadth_first_search(g, s, Q, bfs_vis, color_map);
#ifdef PBGL_ACCOUNTING
eager_dijkstra_shortest_paths_stats.execution_time =
accounting::get_time()
- eager_dijkstra_shortest_paths_stats.execution_time;
#endif
}
template<typename DistributedGraph, typename DijkstraVisitor,
typename PredecessorMap, typename DistanceMap, typename WeightMap>
void
eager_dijkstra_shortest_paths
(const DistributedGraph& g,
typename graph_traits<DistributedGraph>::vertex_descriptor s,
PredecessorMap predecessor, DistanceMap distance,
typename property_traits<DistanceMap>::value_type lookahead,
WeightMap weight)
{
typedef typename property_traits<DistanceMap>::value_type distance_type;
std::vector<default_color_type> colors(num_vertices(g), white_color);
eager_dijkstra_shortest_paths(g, s, predecessor, distance, lookahead, weight,
get(vertex_index, g),
make_iterator_property_map(&colors[0],
get(vertex_index,
g)),
std::less<distance_type>(),
closed_plus<distance_type>(),
distance_type(),
(std::numeric_limits<distance_type>::max)(),
dijkstra_visitor<>());
}
template<typename DistributedGraph, typename DijkstraVisitor,
typename PredecessorMap, typename DistanceMap>
void
eager_dijkstra_shortest_paths
(const DistributedGraph& g,
typename graph_traits<DistributedGraph>::vertex_descriptor s,
PredecessorMap predecessor, DistanceMap distance,
typename property_traits<DistanceMap>::value_type lookahead)
{
eager_dijkstra_shortest_paths(g, s, predecessor, distance, lookahead,
get(edge_weight, g));
}
} // end namespace distributed
#ifdef PBGL_ACCOUNTING
using distributed::eager_dijkstra_shortest_paths_stats;
#endif
using distributed::eager_dijkstra_shortest_paths;
} } // end namespace boost::graph
#endif // BOOST_GRAPH_EAGER_DIJKSTRA_SHORTEST_PATHS_HPP
@@ -0,0 +1,51 @@
// Copyright (C) 2004-2008 The Trustees of Indiana University.
// Use, modification and distribution is subject to 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)
// Authors: Nick Edmonds
// Douglas Gregor
// Andrew Lumsdaine
#ifndef BOOST_DISTRIBUTED_FILTERED_GRAPH_HPP
#define BOOST_DISTRIBUTED_FILTERED_GRAPH_HPP
#ifndef BOOST_GRAPH_USE_MPI
#error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
#endif
#include <boost/graph/parallel/process_group.hpp>
#include <boost/graph/filtered_graph.hpp>
namespace boost {
namespace graph {
namespace parallel {
/// Retrieve the process group from a filtered graph
template<typename Graph, typename EdgePredicate, typename VertexPredicate>
struct process_group_type<filtered_graph<Graph, EdgePredicate, VertexPredicate> >
: process_group_type<Graph> { };
template<typename Graph, typename EdgePredicate, typename VertexPredicate>
struct process_group_type<const filtered_graph<Graph, EdgePredicate, VertexPredicate> >
: process_group_type<Graph> { };
}
}
/// Retrieve the process group from a filtered graph
template<typename Graph, typename EdgePredicate, typename VertexPredicate>
inline typename graph::parallel::process_group_type<Graph>::type
process_group(filtered_graph<Graph, EdgePredicate, VertexPredicate> const& g) {
return process_group(g.m_g);
}
/// Forward vertex() to vertex() of the base graph
template <typename Graph, typename EdgePredicate, typename VertexPredicate>
typename graph_traits<Graph>::vertex_descriptor
vertex(typename graph_traits<Graph>::vertices_size_type i,
filtered_graph<Graph, EdgePredicate, VertexPredicate> const& g)
{ return vertex(i, g.m_g); }
}
#endif // BOOST_DISTRIBUTED_FILTERED_GRAPH_HPP
@@ -0,0 +1,384 @@
// Copyright (C) 2005-2006 The Trustees of Indiana University.
// Use, modification and distribution is subject to 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)
// Authors: Douglas Gregor
// Andrew Lumsdaine
#ifndef BOOST_GRAPH_DISTRIBUTED_FRUCHTERMAN_REINGOLD_HPP
#define BOOST_GRAPH_DISTRIBUTED_FRUCHTERMAN_REINGOLD_HPP
#ifndef BOOST_GRAPH_USE_MPI
#error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
#endif
#include <boost/graph/fruchterman_reingold.hpp>
namespace boost { namespace graph { namespace distributed {
class simple_tiling
{
public:
simple_tiling(int columns, int rows, bool flip = true)
: columns(columns), rows(rows), flip(flip)
{
}
// Convert from a position (x, y) in the tiled display into a
// processor ID number
int operator()(int x, int y) const
{
return flip? (rows - y - 1) * columns + x : y * columns + x;
}
// Convert from a process ID to a position (x, y) in the tiled
// display
std::pair<int, int> operator()(int id)
{
int my_col = id % columns;
int my_row = flip? rows - (id / columns) - 1 : id / columns;
return std::make_pair(my_col, my_row);
}
int columns, rows;
private:
bool flip;
};
// Force pairs function object that does nothing
struct no_force_pairs
{
template<typename Graph, typename ApplyForce>
void operator()(const Graph&, const ApplyForce&)
{
}
};
// Computes force pairs in the distributed case.
template<typename PositionMap, typename DisplacementMap, typename LocalForces,
typename NonLocalForces = no_force_pairs>
class distributed_force_pairs_proxy
{
public:
distributed_force_pairs_proxy(const PositionMap& position,
const DisplacementMap& displacement,
const LocalForces& local_forces,
const NonLocalForces& nonlocal_forces = NonLocalForces())
: position(position), displacement(displacement),
local_forces(local_forces), nonlocal_forces(nonlocal_forces)
{
}
template<typename Graph, typename ApplyForce>
void operator()(const Graph& g, ApplyForce apply_force)
{
// Flush remote displacements
displacement.flush();
// Receive updated positions for all of our neighbors
synchronize(position);
// Reset remote displacements
displacement.reset();
// Compute local repulsive forces
local_forces(g, apply_force);
// Compute neighbor repulsive forces
nonlocal_forces(g, apply_force);
}
protected:
PositionMap position;
DisplacementMap displacement;
LocalForces local_forces;
NonLocalForces nonlocal_forces;
};
template<typename PositionMap, typename DisplacementMap, typename LocalForces>
inline
distributed_force_pairs_proxy<PositionMap, DisplacementMap, LocalForces>
make_distributed_force_pairs(const PositionMap& position,
const DisplacementMap& displacement,
const LocalForces& local_forces)
{
typedef
distributed_force_pairs_proxy<PositionMap, DisplacementMap, LocalForces>
result_type;
return result_type(position, displacement, local_forces);
}
template<typename PositionMap, typename DisplacementMap, typename LocalForces,
typename NonLocalForces>
inline
distributed_force_pairs_proxy<PositionMap, DisplacementMap, LocalForces,
NonLocalForces>
make_distributed_force_pairs(const PositionMap& position,
const DisplacementMap& displacement,
const LocalForces& local_forces,
const NonLocalForces& nonlocal_forces)
{
typedef
distributed_force_pairs_proxy<PositionMap, DisplacementMap, LocalForces,
NonLocalForces>
result_type;
return result_type(position, displacement, local_forces, nonlocal_forces);
}
// Compute nonlocal force pairs based on the shared borders with
// adjacent tiles.
template<typename PositionMap>
class neighboring_tiles_force_pairs
{
public:
typedef typename property_traits<PositionMap>::value_type Point;
typedef typename point_traits<Point>::component_type Dim;
enum bucket_position { left, top, right, bottom, end_position };
neighboring_tiles_force_pairs(PositionMap position, Point origin,
Point extent, simple_tiling tiling)
: position(position), origin(origin), extent(extent), tiling(tiling)
{
}
template<typename Graph, typename ApplyForce>
void operator()(const Graph& g, ApplyForce apply_force)
{
// TBD: Do this some smarter way
if (tiling.columns == 1 && tiling.rows == 1)
return;
typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
#ifndef BOOST_NO_STDC_NAMESPACE
using std::sqrt;
#endif // BOOST_NO_STDC_NAMESPACE
// TBD: num_vertices(g) should be the global number of vertices?
Dim two_k = Dim(2) * sqrt(extent[0] * extent[1] / num_vertices(g));
std::vector<vertex_descriptor> my_vertices[4];
std::vector<vertex_descriptor> neighbor_vertices[4];
// Compute cutoff positions
Dim cutoffs[4];
cutoffs[left] = origin[0] + two_k;
cutoffs[top] = origin[1] + two_k;
cutoffs[right] = origin[0] + extent[0] - two_k;
cutoffs[bottom] = origin[1] + extent[1] - two_k;
// Compute neighbors
typename PositionMap::process_group_type pg = position.process_group();
std::pair<int, int> my_tile = tiling(process_id(pg));
int neighbors[4] = { -1, -1, -1, -1 } ;
if (my_tile.first > 0)
neighbors[left] = tiling(my_tile.first - 1, my_tile.second);
if (my_tile.second > 0)
neighbors[top] = tiling(my_tile.first, my_tile.second - 1);
if (my_tile.first < tiling.columns - 1)
neighbors[right] = tiling(my_tile.first + 1, my_tile.second);
if (my_tile.second < tiling.rows - 1)
neighbors[bottom] = tiling(my_tile.first, my_tile.second + 1);
// Sort vertices along the edges into buckets
BGL_FORALL_VERTICES_T(v, g, Graph) {
if (position[v][0] <= cutoffs[left]) my_vertices[left].push_back(v);
if (position[v][1] <= cutoffs[top]) my_vertices[top].push_back(v);
if (position[v][0] >= cutoffs[right]) my_vertices[right].push_back(v);
if (position[v][1] >= cutoffs[bottom]) my_vertices[bottom].push_back(v);
}
// Send vertices to neighbors, and gather our neighbors' vertices
bucket_position pos;
for (pos = left; pos < end_position; pos = bucket_position(pos + 1)) {
if (neighbors[pos] != -1) {
send(pg, neighbors[pos], 0, my_vertices[pos].size());
if (!my_vertices[pos].empty())
send(pg, neighbors[pos], 1,
&my_vertices[pos].front(), my_vertices[pos].size());
}
}
// Pass messages around
synchronize(pg);
// Receive neighboring vertices
for (pos = left; pos < end_position; pos = bucket_position(pos + 1)) {
if (neighbors[pos] != -1) {
std::size_t incoming_vertices;
receive(pg, neighbors[pos], 0, incoming_vertices);
if (incoming_vertices) {
neighbor_vertices[pos].resize(incoming_vertices);
receive(pg, neighbors[pos], 1, &neighbor_vertices[pos].front(),
incoming_vertices);
}
}
}
// For each neighboring vertex, we need to get its current position
for (pos = left; pos < end_position; pos = bucket_position(pos + 1))
for (typename std::vector<vertex_descriptor>::iterator i =
neighbor_vertices[pos].begin();
i != neighbor_vertices[pos].end();
++i)
request(position, *i);
synchronize(position);
// Apply forces in adjacent bins. This is O(n^2) in the worst
// case. Oh well.
for (pos = left; pos < end_position; pos = bucket_position(pos + 1)) {
for (typename std::vector<vertex_descriptor>::iterator i =
my_vertices[pos].begin();
i != my_vertices[pos].end();
++i)
for (typename std::vector<vertex_descriptor>::iterator j =
neighbor_vertices[pos].begin();
j != neighbor_vertices[pos].end();
++j)
apply_force(*i, *j);
}
}
protected:
PositionMap position;
Point origin;
Point extent;
simple_tiling tiling;
};
template<typename PositionMap>
inline neighboring_tiles_force_pairs<PositionMap>
make_neighboring_tiles_force_pairs
(PositionMap position,
typename property_traits<PositionMap>::value_type origin,
typename property_traits<PositionMap>::value_type extent,
simple_tiling tiling)
{
return neighboring_tiles_force_pairs<PositionMap>(position, origin, extent,
tiling);
}
template<typename DisplacementMap, typename Cooling>
class distributed_cooling_proxy
{
public:
typedef typename Cooling::result_type result_type;
distributed_cooling_proxy(const DisplacementMap& displacement,
const Cooling& cooling)
: displacement(displacement), cooling(cooling)
{
}
result_type operator()()
{
// Accumulate displacements computed on each processor
synchronize(displacement.data->process_group);
// Allow the underlying cooling to occur
return cooling();
}
protected:
DisplacementMap displacement;
Cooling cooling;
};
template<typename DisplacementMap, typename Cooling>
inline distributed_cooling_proxy<DisplacementMap, Cooling>
make_distributed_cooling(const DisplacementMap& displacement,
const Cooling& cooling)
{
typedef distributed_cooling_proxy<DisplacementMap, Cooling> result_type;
return result_type(displacement, cooling);
}
template<typename Point>
struct point_accumulating_reducer {
BOOST_STATIC_CONSTANT(bool, non_default_resolver = true);
template<typename K>
Point operator()(const K&) const { return Point(); }
template<typename K>
Point operator()(const K&, const Point& p1, const Point& p2) const
{ return Point(p1[0] + p2[0], p1[1] + p2[1]); }
};
template<typename Graph, typename PositionMap,
typename AttractiveForce, typename RepulsiveForce,
typename ForcePairs, typename Cooling, typename DisplacementMap>
void
fruchterman_reingold_force_directed_layout
(const Graph& g,
PositionMap position,
typename property_traits<PositionMap>::value_type const& origin,
typename property_traits<PositionMap>::value_type const& extent,
AttractiveForce attractive_force,
RepulsiveForce repulsive_force,
ForcePairs force_pairs,
Cooling cool,
DisplacementMap displacement)
{
typedef typename property_traits<PositionMap>::value_type Point;
// Reduction in the displacement map involves summing the forces
displacement.set_reduce(point_accumulating_reducer<Point>());
// We need to track the positions of all of our neighbors
BGL_FORALL_VERTICES_T(u, g, Graph)
BGL_FORALL_ADJ_T(u, v, g, Graph)
request(position, v);
// Invoke the "sequential" Fruchterman-Reingold implementation
boost::fruchterman_reingold_force_directed_layout
(g, position, origin, extent,
attractive_force, repulsive_force,
make_distributed_force_pairs(position, displacement, force_pairs),
make_distributed_cooling(displacement, cool),
displacement);
}
template<typename Graph, typename PositionMap,
typename AttractiveForce, typename RepulsiveForce,
typename ForcePairs, typename Cooling, typename DisplacementMap>
void
fruchterman_reingold_force_directed_layout
(const Graph& g,
PositionMap position,
typename property_traits<PositionMap>::value_type const& origin,
typename property_traits<PositionMap>::value_type const& extent,
AttractiveForce attractive_force,
RepulsiveForce repulsive_force,
ForcePairs force_pairs,
Cooling cool,
DisplacementMap displacement,
simple_tiling tiling)
{
typedef typename property_traits<PositionMap>::value_type Point;
// Reduction in the displacement map involves summing the forces
displacement.set_reduce(point_accumulating_reducer<Point>());
// We need to track the positions of all of our neighbors
BGL_FORALL_VERTICES_T(u, g, Graph)
BGL_FORALL_ADJ_T(u, v, g, Graph)
request(position, v);
// Invoke the "sequential" Fruchterman-Reingold implementation
boost::fruchterman_reingold_force_directed_layout
(g, position, origin, extent,
attractive_force, repulsive_force,
make_distributed_force_pairs
(position, displacement, force_pairs,
make_neighboring_tiles_force_pairs(position, origin, extent, tiling)),
make_distributed_cooling(displacement, cool),
displacement);
}
} } } // end namespace boost::graph::distributed
#endif // BOOST_GRAPH_DISTRIBUTED_FRUCHTERMAN_REINGOLD_HPP
@@ -0,0 +1,294 @@
// Copyright (C) 2004-2006 The Trustees of Indiana University.
// Use, modification and distribution is subject to 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)
// Authors: Douglas Gregor
// Andrew Lumsdaine
#ifndef BOOST_GRAPH_PARALLEL_GRAPHVIZ_HPP
#define BOOST_GRAPH_PARALLEL_GRAPHVIZ_HPP
#ifndef BOOST_GRAPH_USE_MPI
#error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
#endif
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/distributed/concepts.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/graph/graphviz.hpp>
#include <boost/type_traits/is_base_and_derived.hpp>
#include <boost/type_traits/is_same.hpp>
#include <fstream>
#include <sstream>
#include <iostream>
#include <string>
#include <boost/graph/parallel/container_traits.hpp>
#include <boost/graph/parallel/process_group.hpp>
#include <boost/property_map/parallel/global_index_map.hpp>
namespace boost {
template<typename Graph>
struct graph_id_writer
{
explicit graph_id_writer(const Graph& g) : g(g) { }
void operator()(std::ostream& out)
{
out << " label=\"p" << process_id(g.process_group()) << "\";\n";
}
private:
const Graph& g;
};
template<typename NumberMap>
struct paint_by_number_writer
{
explicit paint_by_number_writer(NumberMap number) : number(number) { }
template<typename Descriptor>
void operator()(std::ostream& out, Descriptor k)
{
static const char* color_names[] = {
"blue",
"brown",
"cyan",
"darkgreen",
"darkorchid",
"darksalmon",
"darkviolet",
"deeppink",
"gold3",
"green",
"magenta",
"navy",
"red",
"yellow",
"palegreen",
"gray65",
"gray21",
"bisque2",
"greenyellow",
"indianred4",
"lightblue2",
"mediumspringgreen",
"orangered",
"orange"
};
const int colors = sizeof(color_names) / sizeof(color_names[0]);
if (get(number, k) < colors) {
out << " [ style=\"filled\", fillcolor=\"" << color_names[get(number, k)]
<< "\" ]";
} else {
out << " [ label=\"(" << get(number, k) << ")\" ]";
}
}
private:
NumberMap number;
};
template<typename NumberMap>
inline paint_by_number_writer<NumberMap>
paint_by_number(NumberMap number)
{ return paint_by_number_writer<NumberMap>(number); }
template<typename Graph, typename VertexPropertiesWriter,
typename EdgePropertiesWriter, typename GraphPropertiesWriter>
void
write_graphviz(std::ostream& out,
const Graph& g,
VertexPropertiesWriter vpw,
EdgePropertiesWriter epw,
GraphPropertiesWriter gpw
BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag))
{
typedef typename graph_traits<Graph>::directed_category directed_category;
typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type;
typedef typename boost::graph::parallel::process_group_type<Graph>::type
process_group_type;
typedef typename process_group_type::process_id_type process_id_type;
typedef typename property_map<Graph, vertex_index_t>::const_type
VertexIndexMap;
typedef typename property_map<Graph, vertex_global_t>::const_type
VertexGlobalMap;
static const bool is_undirected
= (is_base_and_derived<undirected_tag, directed_category>::value
|| is_same<undirected_tag, directed_category>::value);
static const char* graph_kind = is_undirected? "graph" : "digraph";
static const char* edge_kind = is_undirected? "--" : "->";
using boost::graph::parallel::process_group;
process_group_type pg = process_group(g);
parallel::global_index_map<VertexIndexMap, VertexGlobalMap>
global_index(pg, num_vertices(g), get(vertex_index, g),
get(vertex_global, g));
std::ostringstream local_graph_out;
local_graph_out << " subgraph cluster_" << process_id(pg) << " {\n";
gpw(local_graph_out);
typename graph_traits<Graph>::vertex_iterator vi, vi_end;
for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) {
int global_idx = get(global_index, *vi);
local_graph_out << " n" << global_idx;
vpw(local_graph_out, *vi);
local_graph_out << ";\n";
}
local_graph_out << " }\n\n";
typename graph_traits<Graph>::edge_iterator ei, ei_end;
for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) {
int source_idx = get(global_index, source(*ei, g));
int target_idx = get(global_index, target(*ei, g));
local_graph_out << " n" << source_idx << " " << edge_kind << " n"
<< target_idx;
epw(local_graph_out, *ei);
local_graph_out << ";\n";
}
if (process_id(pg) == 0) {
out << graph_kind << " g {\n";
out << local_graph_out.str();
synchronize(pg);
for (int i = 1; i < num_processes(pg); ++i) {
int len;
receive(pg, i, 0, len);
char* data = new char [len+1];
data[len] = 0;
receive(pg, i, 1, data, len);
out << std::endl << data;
delete [] data;
}
out << "}\n";
} else {
std::string result_str = local_graph_out.str();
const char* data = result_str.c_str();
int len = result_str.length();
send(pg, 0, 0, len);
send(pg, 0, 1, data, len);
synchronize(pg);
}
synchronize(pg);
synchronize(pg);
synchronize(pg);
}
template<typename Graph, typename VertexPropertiesWriter,
typename EdgePropertiesWriter>
inline void
write_graphviz(std::ostream& out,
const Graph& g,
VertexPropertiesWriter vpw,
EdgePropertiesWriter epw
BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag))
{
write_graphviz(out, g, vpw, epw, graph_id_writer<Graph>(g));
}
template<typename Graph, typename VertexPropertiesWriter>
inline void
write_graphviz(std::ostream& out,
const Graph& g,
VertexPropertiesWriter vpw
BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag))
{
write_graphviz(out, g, vpw, default_writer());
}
template<typename Graph>
inline void
write_graphviz(std::ostream& out, const Graph& g
BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag))
{
write_graphviz(out, g, default_writer());
}
template<typename Graph, typename VertexPropertiesWriter,
typename EdgePropertiesWriter, typename GraphPropertiesWriter>
void
write_graphviz(const std::string& filename,
const Graph& g,
VertexPropertiesWriter vpw,
EdgePropertiesWriter epw,
GraphPropertiesWriter gpw
BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag))
{
if (process_id(g.process_group()) == 0) {
std::ofstream out(filename.c_str());
write_graphviz(out, g, vpw, epw, gpw);
} else {
write_graphviz(std::cout, g, vpw, epw, gpw);
}
}
template<typename Graph, typename VertexPropertiesWriter,
typename EdgePropertiesWriter>
void
write_graphviz(const std::string& filename,
const Graph& g,
VertexPropertiesWriter vpw,
EdgePropertiesWriter epw
BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag))
{
if (process_id(g.process_group()) == 0) {
std::ofstream out(filename.c_str());
write_graphviz(out, g, vpw, epw);
} else {
write_graphviz(std::cout, g, vpw, epw);
}
}
template<typename Graph, typename VertexPropertiesWriter>
void
write_graphviz(const std::string& filename,
const Graph& g,
VertexPropertiesWriter vpw
BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag))
{
if (process_id(g.process_group()) == 0) {
std::ofstream out(filename.c_str());
write_graphviz(out, g, vpw);
} else {
write_graphviz(std::cout, g, vpw);
}
}
template<typename Graph>
void
write_graphviz(const std::string& filename, const Graph& g
BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag))
{
if (process_id(g.process_group()) == 0) {
std::ofstream out(filename.c_str());
write_graphviz(out, g);
} else {
write_graphviz(std::cout, g);
}
}
template<typename Graph>
void
write_graphviz(std::ostream& out, const Graph& g,
const dynamic_properties& dp,
const std::string& node_id = "node_id"
BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag))
{
write_graphviz
(out, g,
/*vertex_writer=*/dynamic_vertex_properties_writer(dp, node_id),
/*edge_writer=*/dynamic_properties_writer(dp));
}
} // end namespace boost
#endif // BOOST_GRAPH_PARALLEL_GRAPHVIZ_HPP
@@ -0,0 +1,175 @@
// Copyright (C) 2004-2006 The Trustees of Indiana University.
// Use, modification and distribution is subject to 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)
// Authors: Douglas Gregor
// Andrew Lumsdaine
#ifndef BOOST_GRAPH_LOCAL_SUBGRAPH_HPP
#define BOOST_GRAPH_LOCAL_SUBGRAPH_HPP
#ifndef BOOST_GRAPH_USE_MPI
#error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
#endif
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/filtered_graph.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/type_traits/is_base_and_derived.hpp>
#include <boost/graph/parallel/container_traits.hpp>
namespace boost {
namespace graph { namespace detail {
// Optionally, virtually derive from a base class
template<bool Derive, typename Base> struct derive_from_if;
template<typename Base> struct derive_from_if<true, Base> : virtual Base {};
template<typename Base> struct derive_from_if<false, Base> {};
template<typename NewBase, typename Tag, typename OldBase = NewBase>
struct derive_from_if_tag_is :
derive_from_if<(is_base_and_derived<OldBase, Tag>::value
|| is_same<OldBase, Tag>::value),
NewBase>
{
};
} } // end namespace graph::detail
template<typename DistributedGraph>
class is_local_edge
{
public:
typedef bool result_type;
typedef typename graph_traits<DistributedGraph>::edge_descriptor
argument_type;
is_local_edge() : g(0) {}
is_local_edge(DistributedGraph& g) : g(&g), owner(get(vertex_owner, g)) {}
// Since either the source or target vertex must be local, the
// equivalence of their owners indicates a local edge.
result_type operator()(const argument_type& e) const
{ return get(owner, source(e, *g)) == get(owner, target(e, *g)); }
private:
DistributedGraph* g;
typename property_map<DistributedGraph, vertex_owner_t>::const_type owner;
};
template<typename DistributedGraph>
class is_local_vertex
{
public:
typedef bool result_type;
typedef typename graph_traits<DistributedGraph>::vertex_descriptor
argument_type;
is_local_vertex() : g(0) {}
is_local_vertex(DistributedGraph& g) : g(&g), owner(get(vertex_owner, g)) { }
// Since either the source or target vertex must be local, the
// equivalence of their owners indicates a local edge.
result_type operator()(const argument_type& v) const
{
return get(owner, v) == process_id(process_group(*g));
}
private:
DistributedGraph* g;
typename property_map<DistributedGraph, vertex_owner_t>::const_type owner;
};
template<typename DistributedGraph>
class local_subgraph
: public filtered_graph<DistributedGraph,
is_local_edge<DistributedGraph>,
is_local_vertex<DistributedGraph> >
{
typedef filtered_graph<DistributedGraph,
is_local_edge<DistributedGraph>,
is_local_vertex<DistributedGraph> >
inherited;
typedef typename graph_traits<DistributedGraph>::traversal_category
inherited_category;
public:
struct traversal_category :
graph::detail::derive_from_if_tag_is<incidence_graph_tag,
inherited_category>,
graph::detail::derive_from_if_tag_is<adjacency_graph_tag,
inherited_category>,
graph::detail::derive_from_if_tag_is<vertex_list_graph_tag,
inherited_category>,
graph::detail::derive_from_if_tag_is<edge_list_graph_tag,
inherited_category>,
graph::detail::derive_from_if_tag_is<vertex_list_graph_tag,
inherited_category,
distributed_vertex_list_graph_tag>,
graph::detail::derive_from_if_tag_is<edge_list_graph_tag,
inherited_category,
distributed_edge_list_graph_tag>
{ };
local_subgraph(DistributedGraph& g)
: inherited(g,
is_local_edge<DistributedGraph>(g),
is_local_vertex<DistributedGraph>(g)),
g(g)
{
}
// Distributed Container
typedef typename boost::graph::parallel::process_group_type<DistributedGraph>::type
process_group_type;
process_group_type& process_group()
{
using boost::graph::parallel::process_group;
return process_group(g);
}
const process_group_type& process_group() const
{
using boost::graph::parallel::process_group;
return boost::graph::parallel::process_group(g);
}
DistributedGraph& base() { return g; }
const DistributedGraph& base() const { return g; }
private:
DistributedGraph& g;
};
template<typename DistributedGraph, typename PropertyTag>
class property_map<local_subgraph<DistributedGraph>, PropertyTag>
: public property_map<DistributedGraph, PropertyTag> { };
template<typename DistributedGraph, typename PropertyTag>
class property_map<local_subgraph<const DistributedGraph>, PropertyTag>
{
public:
typedef typename property_map<DistributedGraph, PropertyTag>::const_type
type;
typedef type const_type;
};
template<typename PropertyTag, typename DistributedGraph>
inline typename property_map<local_subgraph<DistributedGraph>, PropertyTag>::type
get(PropertyTag p, local_subgraph<DistributedGraph>& g)
{ return get(p, g.base()); }
template<typename PropertyTag, typename DistributedGraph>
inline typename property_map<local_subgraph<DistributedGraph>, PropertyTag>
::const_type
get(PropertyTag p, const local_subgraph<DistributedGraph>& g)
{ return get(p, g.base()); }
template<typename DistributedGraph>
inline local_subgraph<DistributedGraph>
make_local_subgraph(DistributedGraph& g)
{ return local_subgraph<DistributedGraph>(g); }
} // end namespace boost
#endif // BOOST_GRAPH_LOCAL_SUBGRAPH_HPP
@@ -0,0 +1,809 @@
// Copyright (C) 2004-2008 The Trustees of Indiana University.
// Copyright (C) 2007 Douglas Gregor
// Copyright (C) 2007 Matthias Troyer <troyer@boost-consulting.com>
// Use, modification and distribution is subject to 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)
// Authors: Douglas Gregor
// Matthias Troyer
// Andrew Lumsdaine
#ifndef BOOST_GRAPH_DISTRIBUTED_MPI_PROCESS_GROUP
#define BOOST_GRAPH_DISTRIBUTED_MPI_PROCESS_GROUP
#ifndef BOOST_GRAPH_USE_MPI
#error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
#endif
//#define NO_SPLIT_BATCHES
#define SEND_OOB_BSEND
#include <boost/optional.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <utility>
#include <memory>
#include <boost/function/function1.hpp>
#include <boost/function/function2.hpp>
#include <boost/function/function0.hpp>
#include <boost/mpi.hpp>
#include <boost/graph/parallel/process_group.hpp>
#include <boost/utility/enable_if.hpp>
namespace boost { namespace graph { namespace distributed {
// Process group tags
struct mpi_process_group_tag : virtual parallel::linear_process_group_tag { };
class mpi_process_group
{
struct impl;
public:
/// Number of tags available to each data structure.
static const int max_tags = 256;
/**
* The type of a "receive" handler, that will be provided with
* (source, tag) pairs when a message is received. Users can provide a
* receive handler for a distributed data structure, for example, to
* automatically pick up and respond to messages as needed.
*/
typedef function<void(int source, int tag)> receiver_type;
/**
* The type of a handler for the on-synchronize event, which will be
* executed at the beginning of synchronize().
*/
typedef function0<void> on_synchronize_event_type;
/// Used as a tag to help create an "empty" process group.
struct create_empty {};
/// The type used to buffer message data
typedef boost::mpi::packed_oprimitive::buffer_type buffer_type;
/// The type used to identify a process
typedef int process_id_type;
/// The type used to count the number of processes
typedef int process_size_type;
/// The type of communicator used to transmit data via MPI
typedef boost::mpi::communicator communicator_type;
/// Classification of the capabilities of this process group
struct communication_category
: virtual parallel::bsp_process_group_tag,
virtual mpi_process_group_tag { };
// TBD: We can eliminate the "source" field and possibly the
// "offset" field.
struct message_header {
/// The process that sent the message
process_id_type source;
/// The message tag
int tag;
/// The offset of the message into the buffer
std::size_t offset;
/// The length of the message in the buffer, in bytes
std::size_t bytes;
template <class Archive>
void serialize(Archive& ar, int)
{
ar & source & tag & offset & bytes;
}
};
/**
* Stores the outgoing messages for a particular processor.
*
* @todo Evaluate whether we should use a deque instance, which
* would reduce could reduce the cost of "sending" messages but
* increases the time spent in the synchronization step.
*/
struct outgoing_messages {
outgoing_messages() {}
~outgoing_messages() {}
std::vector<message_header> headers;
buffer_type buffer;
template <class Archive>
void serialize(Archive& ar, int)
{
ar & headers & buffer;
}
void swap(outgoing_messages& x)
{
headers.swap(x.headers);
buffer.swap(x.buffer);
}
};
private:
/**
* Virtual base from which every trigger will be launched. See @c
* trigger_launcher for more information.
*/
class trigger_base : boost::noncopyable
{
public:
explicit trigger_base(int tag) : tag_(tag) { }
/// Retrieve the tag associated with this trigger
int tag() const { return tag_; }
virtual ~trigger_base() { }
/**
* Invoked to receive a message that matches a particular trigger.
*
* @param source the source of the message
* @param tag the (local) tag of the message
* @param context the context under which the trigger is being
* invoked
*/
virtual void
receive(mpi_process_group const& pg, int source, int tag,
trigger_receive_context context, int block=-1) const = 0;
protected:
// The message tag associated with this trigger
int tag_;
};
/**
* Launches a specific handler in response to a trigger. This
* function object wraps up the handler function object and a buffer
* for incoming data.
*/
template<typename Type, typename Handler>
class trigger_launcher : public trigger_base
{
public:
explicit trigger_launcher(mpi_process_group& self, int tag,
const Handler& handler)
: trigger_base(tag), self(self), handler(handler)
{}
void
receive(mpi_process_group const& pg, int source, int tag,
trigger_receive_context context, int block=-1) const;
private:
mpi_process_group& self;
mutable Handler handler;
};
/**
* Launches a specific handler with a message reply in response to a
* trigger. This function object wraps up the handler function
* object and a buffer for incoming data.
*/
template<typename Type, typename Handler>
class reply_trigger_launcher : public trigger_base
{
public:
explicit reply_trigger_launcher(mpi_process_group& self, int tag,
const Handler& handler)
: trigger_base(tag), self(self), handler(handler)
{}
void
receive(mpi_process_group const& pg, int source, int tag,
trigger_receive_context context, int block=-1) const;
private:
mpi_process_group& self;
mutable Handler handler;
};
template<typename Type, typename Handler>
class global_trigger_launcher : public trigger_base
{
public:
explicit global_trigger_launcher(mpi_process_group& self, int tag,
const Handler& handler)
: trigger_base(tag), handler(handler)
{
}
void
receive(mpi_process_group const& pg, int source, int tag,
trigger_receive_context context, int block=-1) const;
private:
mutable Handler handler;
// TBD: do not forget to cancel any outstanding Irecv when deleted,
// if we decide to use Irecv
};
template<typename Type, typename Handler>
class global_irecv_trigger_launcher : public trigger_base
{
public:
explicit global_irecv_trigger_launcher(mpi_process_group& self, int tag,
const Handler& handler, int sz)
: trigger_base(tag), handler(handler), buffer_size(sz)
{
prepare_receive(self,tag);
}
void
receive(mpi_process_group const& pg, int source, int tag,
trigger_receive_context context, int block=-1) const;
private:
void prepare_receive(mpi_process_group const& pg, int tag, bool force=false) const;
Handler handler;
int buffer_size;
// TBD: do not forget to cancel any outstanding Irecv when deleted,
// if we decide to use Irecv
};
public:
/**
* Construct a new BSP process group from an MPI communicator. The
* MPI communicator will be duplicated to create a new communicator
* for this process group to use.
*/
mpi_process_group(communicator_type parent_comm = communicator_type());
/**
* Construct a new BSP process group from an MPI communicator. The
* MPI communicator will be duplicated to create a new communicator
* for this process group to use. This constructor allows to tune the
* size of message batches.
*
* @param num_headers The maximum number of headers in a message batch
*
* @param buffer_size The maximum size of the message buffer in a batch.
*
*/
mpi_process_group( std::size_t num_headers, std::size_t buffer_size,
communicator_type parent_comm = communicator_type());
/**
* Construct a copy of the BSP process group for a new distributed
* data structure. This data structure will synchronize with all
* other members of the process group's equivalence class (including
* @p other), but will have its own set of tags.
*
* @param other The process group that this new process group will
* be based on, using a different set of tags within the same
* communication and synchronization space.
*
* @param handler A message handler that will be passed (source,
* tag) pairs for each message received by this data
* structure. The handler is expected to receive the messages
* immediately. The handler can be changed after-the-fact by
* calling @c replace_handler.
*
* @param out_of_band_receive An anachronism. TODO: remove this.
*/
mpi_process_group(const mpi_process_group& other,
const receiver_type& handler,
bool out_of_band_receive = false);
/**
* Construct a copy of the BSP process group for a new distributed
* data structure. This data structure will synchronize with all
* other members of the process group's equivalence class (including
* @p other), but will have its own set of tags.
*/
mpi_process_group(const mpi_process_group& other,
attach_distributed_object,
bool out_of_band_receive = false);
/**
* Create an "empty" process group, with no information. This is an
* internal routine that users should never need.
*/
explicit mpi_process_group(create_empty) {}
/**
* Destroys this copy of the process group.
*/
~mpi_process_group();
/**
* Replace the current message handler with a new message handler.
*
* @param handle The new message handler.
* @param out_of_band_receive An anachronism: remove this
*/
void replace_handler(const receiver_type& handler,
bool out_of_band_receive = false);
/**
* Turns this process group into the process group for a new
* distributed data structure or object, allocating its own tag
* block.
*/
void make_distributed_object();
/**
* Replace the handler to be invoked at the beginning of synchronize.
*/
void
replace_on_synchronize_handler(const on_synchronize_event_type& handler = 0);
/**
* Return the block number of the current data structure. A value of
* 0 indicates that this particular instance of the process group is
* not associated with any distributed data structure.
*/
int my_block_number() const { return block_num? *block_num : 0; }
/**
* Encode a block number/tag pair into a single encoded tag for
* transmission.
*/
int encode_tag(int block_num, int tag) const
{ return block_num * max_tags + tag; }
/**
* Decode an encoded tag into a block number/tag pair.
*/
std::pair<int, int> decode_tag(int encoded_tag) const
{ return std::make_pair(encoded_tag / max_tags, encoded_tag % max_tags); }
// @todo Actually write up the friend declarations so these could be
// private.
// private:
/** Allocate a block of tags for this instance. The block should not
* have been allocated already, e.g., my_block_number() ==
* 0. Returns the newly-allocated block number.
*/
int allocate_block(bool out_of_band_receive = false);
/** Potentially emit a receive event out of band. Returns true if an event
* was actually sent, false otherwise.
*/
bool maybe_emit_receive(int process, int encoded_tag) const;
/** Emit a receive event. Returns true if an event was actually
* sent, false otherwise.
*/
bool emit_receive(int process, int encoded_tag) const;
/** Emit an on-synchronize event to all block handlers. */
void emit_on_synchronize() const;
/** Retrieve a reference to the stored receiver in this block. */
template<typename Receiver>
Receiver* get_receiver();
template<typename T>
void
send_impl(int dest, int tag, const T& value,
mpl::true_ /*is_mpi_datatype*/) const;
template<typename T>
void
send_impl(int dest, int tag, const T& value,
mpl::false_ /*is_mpi_datatype*/) const;
template<typename T>
typename disable_if<boost::mpi::is_mpi_datatype<T>, void>::type
array_send_impl(int dest, int tag, const T values[], std::size_t n) const;
template<typename T>
bool
receive_impl(int source, int tag, T& value,
mpl::true_ /*is_mpi_datatype*/) const;
template<typename T>
bool
receive_impl(int source, int tag, T& value,
mpl::false_ /*is_mpi_datatype*/) const;
// Receive an array of values
template<typename T>
typename disable_if<boost::mpi::is_mpi_datatype<T>, bool>::type
array_receive_impl(int source, int tag, T* values, std::size_t& n) const;
optional<std::pair<mpi_process_group::process_id_type, int> > probe() const;
void synchronize() const;
operator bool() { return impl_; }
mpi_process_group base() const;
/**
* Create a new trigger for a specific message tag. Triggers handle
* out-of-band messaging, and the handler itself will be called
* whenever a message is available. The handler itself accepts four
* arguments: the source of the message, the message tag (which will
* be the same as @p tag), the message data (of type @c Type), and a
* boolean flag that states whether the message was received
* out-of-band. The last will be @c true for out-of-band receives,
* or @c false for receives at the end of a synchronization step.
*/
template<typename Type, typename Handler>
void trigger(int tag, const Handler& handler);
/**
* Create a new trigger for a specific message tag, along with a way
* to send a reply with data back to the sender. Triggers handle
* out-of-band messaging, and the handler itself will be called
* whenever a message is available. The handler itself accepts four
* arguments: the source of the message, the message tag (which will
* be the same as @p tag), the message data (of type @c Type), and a
* boolean flag that states whether the message was received
* out-of-band. The last will be @c true for out-of-band receives,
* or @c false for receives at the end of a synchronization
* step. The handler also returns a value, which will be routed back
* to the sender.
*/
template<typename Type, typename Handler>
void trigger_with_reply(int tag, const Handler& handler);
template<typename Type, typename Handler>
void global_trigger(int tag, const Handler& handler, std::size_t buffer_size=0);
/**
* Poll for any out-of-band messages. This routine will check if any
* out-of-band messages are available. Those that are available will
* be handled immediately, if possible.
*
* @returns if an out-of-band message has been received, but we are
* unable to actually receive the message, a (source, tag) pair will
* be returned. Otherwise, returns an empty optional.
*
* @param wait When true, we should block until a message comes in.
*
* @param synchronizing whether we are currently synchronizing the
* process group
*/
optional<std::pair<int, int> >
poll(bool wait = false, int block = -1, bool synchronizing = false) const;
/**
* Determines the context of the trigger currently executing. If
* multiple triggers are executing (recursively), then the context
* for the most deeply nested trigger will be returned. If no
* triggers are executing, returns @c trc_none. This might be used,
* for example, to determine whether a reply to a message should
* itself be sent out-of-band or whether it can go via the normal,
* slower communication route.
*/
trigger_receive_context trigger_context() const;
/// INTERNAL ONLY
void receive_batch(process_id_type source, outgoing_messages& batch) const;
/// INTERNAL ONLY
///
/// Determine the actual communicator and tag will be used for a
/// transmission with the given tag.
std::pair<boost::mpi::communicator, int>
actual_communicator_and_tag(int tag, int block) const;
/// set the size of the message buffer used for buffered oob sends
static void set_message_buffer_size(std::size_t s);
/// get the size of the message buffer used for buffered oob sends
static std::size_t message_buffer_size();
static int old_buffer_size;
static void* old_buffer;
private:
void install_trigger(int tag, int block,
shared_ptr<trigger_base> const& launcher);
void poll_requests(int block=-1) const;
// send a batch if the buffer is full now or would get full
void maybe_send_batch(process_id_type dest) const;
// actually send a batch
void send_batch(process_id_type dest, outgoing_messages& batch) const;
void send_batch(process_id_type dest) const;
void pack_headers() const;
/**
* Process a batch of incoming messages immediately.
*
* @param source the source of these messages
*/
void process_batch(process_id_type source) const;
void receive_batch(boost::mpi::status& status) const;
//void free_finished_sends() const;
/// Status messages used internally by the process group
enum status_messages {
/// the first of the reserved message tags
msg_reserved_first = 126,
/// Sent from a processor when sending batched messages
msg_batch = 126,
/// Sent from a processor when sending large batched messages, larger than
/// the maximum buffer size for messages to be received by MPI_Irecv
msg_large_batch = 127,
/// Sent from a source processor to everyone else when that
/// processor has entered the synchronize() function.
msg_synchronizing = 128,
/// the last of the reserved message tags
msg_reserved_last = 128
};
/**
* Description of a block of tags associated to a particular
* distributed data structure. This structure will live as long as
* the distributed data structure is around, and will be used to
* help send messages to the data structure.
*/
struct block_type
{
block_type() { }
/// Handler for receive events
receiver_type on_receive;
/// Handler executed at the start of synchronization
on_synchronize_event_type on_synchronize;
/// Individual message triggers. Note: at present, this vector is
/// indexed by the (local) tag of the trigger. Any tags that
/// don't have triggers will have NULL pointers in that spot.
std::vector<shared_ptr<trigger_base> > triggers;
};
/**
* Data structure containing all of the blocks for the distributed
* data structures attached to a process group.
*/
typedef std::vector<block_type*> blocks_type;
/// Iterator into @c blocks_type.
typedef blocks_type::iterator block_iterator;
/**
* Deleter used to deallocate a block when its distributed data
* structure is destroyed. This type will be used as the deleter for
* @c block_num.
*/
struct deallocate_block;
static std::vector<char> message_buffer;
public:
/**
* Data associated with the process group and all of its attached
* distributed data structures.
*/
shared_ptr<impl> impl_;
/**
* When non-null, indicates that this copy of the process group is
* associated with a particular distributed data structure. The
* integer value contains the block number (a value > 0) associated
* with that data structure. The deleter for this @c shared_ptr is a
* @c deallocate_block object that will deallocate the associated
* block in @c impl_->blocks.
*/
shared_ptr<int> block_num;
/**
* Rank of this process, to avoid having to call rank() repeatedly.
*/
int rank;
/**
* Number of processes in this process group, to avoid having to
* call communicator::size() repeatedly.
*/
int size;
};
inline mpi_process_group::process_id_type
process_id(const mpi_process_group& pg)
{ return pg.rank; }
inline mpi_process_group::process_size_type
num_processes(const mpi_process_group& pg)
{ return pg.size; }
mpi_process_group::communicator_type communicator(const mpi_process_group& pg);
template<typename T>
void
send(const mpi_process_group& pg, mpi_process_group::process_id_type dest,
int tag, const T& value);
template<typename InputIterator>
void
send(const mpi_process_group& pg, mpi_process_group::process_id_type dest,
int tag, InputIterator first, InputIterator last);
template<typename T>
inline void
send(const mpi_process_group& pg, mpi_process_group::process_id_type dest,
int tag, T* first, T* last)
{ send(pg, dest, tag, first, last - first); }
template<typename T>
inline void
send(const mpi_process_group& pg, mpi_process_group::process_id_type dest,
int tag, const T* first, const T* last)
{ send(pg, dest, tag, first, last - first); }
template<typename T>
mpi_process_group::process_id_type
receive(const mpi_process_group& pg, int tag, T& value);
template<typename T>
mpi_process_group::process_id_type
receive(const mpi_process_group& pg,
mpi_process_group::process_id_type source, int tag, T& value);
optional<std::pair<mpi_process_group::process_id_type, int> >
probe(const mpi_process_group& pg);
void synchronize(const mpi_process_group& pg);
template<typename T, typename BinaryOperation>
T*
all_reduce(const mpi_process_group& pg, T* first, T* last, T* out,
BinaryOperation bin_op);
template<typename T, typename BinaryOperation>
T*
scan(const mpi_process_group& pg, T* first, T* last, T* out,
BinaryOperation bin_op);
template<typename InputIterator, typename T>
void
all_gather(const mpi_process_group& pg,
InputIterator first, InputIterator last, std::vector<T>& out);
template<typename InputIterator>
mpi_process_group
process_subgroup(const mpi_process_group& pg,
InputIterator first, InputIterator last);
template<typename T>
void
broadcast(const mpi_process_group& pg, T& val,
mpi_process_group::process_id_type root);
/*******************************************************************
* Out-of-band communication *
*******************************************************************/
template<typename T>
typename enable_if<boost::mpi::is_mpi_datatype<T> >::type
send_oob(const mpi_process_group& pg, mpi_process_group::process_id_type dest,
int tag, const T& value, int block=-1)
{
using boost::mpi::get_mpi_datatype;
// Determine the actual message tag we will use for the send, and which
// communicator we will use.
std::pair<boost::mpi::communicator, int> actual
= pg.actual_communicator_and_tag(tag, block);
#ifdef SEND_OOB_BSEND
if (mpi_process_group::message_buffer_size()) {
MPI_Bsend(const_cast<T*>(&value), 1, get_mpi_datatype<T>(value), dest,
actual.second, actual.first);
return;
}
#endif
MPI_Request request;
MPI_Isend(const_cast<T*>(&value), 1, get_mpi_datatype<T>(value), dest,
actual.second, actual.first, &request);
int done=0;
do {
pg.poll();
MPI_Test(&request,&done,MPI_STATUS_IGNORE);
} while (!done);
}
template<typename T>
typename disable_if<boost::mpi::is_mpi_datatype<T> >::type
send_oob(const mpi_process_group& pg, mpi_process_group::process_id_type dest,
int tag, const T& value, int block=-1)
{
using boost::mpi::packed_oarchive;
// Determine the actual message tag we will use for the send, and which
// communicator we will use.
std::pair<boost::mpi::communicator, int> actual
= pg.actual_communicator_and_tag(tag, block);
// Serialize the data into a buffer
packed_oarchive out(actual.first);
out << value;
std::size_t size = out.size();
// Send the actual message data
#ifdef SEND_OOB_BSEND
if (mpi_process_group::message_buffer_size()) {
MPI_Bsend(const_cast<void*>(out.address()), size, MPI_PACKED,
dest, actual.second, actual.first);
return;
}
#endif
MPI_Request request;
MPI_Isend(const_cast<void*>(out.address()), size, MPI_PACKED,
dest, actual.second, actual.first, &request);
int done=0;
do {
pg.poll();
MPI_Test(&request,&done,MPI_STATUS_IGNORE);
} while (!done);
}
template<typename T>
typename enable_if<boost::mpi::is_mpi_datatype<T> >::type
receive_oob(const mpi_process_group& pg,
mpi_process_group::process_id_type source, int tag, T& value, int block=-1);
template<typename T>
typename disable_if<boost::mpi::is_mpi_datatype<T> >::type
receive_oob(const mpi_process_group& pg,
mpi_process_group::process_id_type source, int tag, T& value, int block=-1);
template<typename SendT, typename ReplyT>
typename enable_if<boost::mpi::is_mpi_datatype<ReplyT> >::type
send_oob_with_reply(const mpi_process_group& pg,
mpi_process_group::process_id_type dest,
int tag, const SendT& send_value, ReplyT& reply_value,
int block = -1);
template<typename SendT, typename ReplyT>
typename disable_if<boost::mpi::is_mpi_datatype<ReplyT> >::type
send_oob_with_reply(const mpi_process_group& pg,
mpi_process_group::process_id_type dest,
int tag, const SendT& send_value, ReplyT& reply_value,
int block = -1);
} } } // end namespace boost::graph::distributed
BOOST_IS_BITWISE_SERIALIZABLE(boost::graph::distributed::mpi_process_group::message_header)
namespace boost { namespace mpi {
template<>
struct is_mpi_datatype<boost::graph::distributed::mpi_process_group::message_header> : mpl::true_ { };
} } // end namespace boost::mpi
namespace std {
/// optimized swap for outgoing messages
inline void
swap(boost::graph::distributed::mpi_process_group::outgoing_messages& x,
boost::graph::distributed::mpi_process_group::outgoing_messages& y)
{
x.swap(y);
}
}
BOOST_CLASS_IMPLEMENTATION(boost::graph::distributed::mpi_process_group::outgoing_messages,object_serializable)
BOOST_CLASS_TRACKING(boost::graph::distributed::mpi_process_group::outgoing_messages,track_never)
#include <boost/graph/distributed/detail/mpi_process_group.ipp>
#endif // BOOST_PARALLEL_MPI_MPI_PROCESS_GROUP_HPP
@@ -0,0 +1,116 @@
// Copyright (C) 2006-2010 The Trustees of Indiana University.
// Use, modification and distribution is subject to 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)
// Authors: Douglas Gregor
// Jeremiah Willcock
// Andrew Lumsdaine
// Distributed version of the one-bit color map
#ifndef BOOST_DISTRIBUTED_ONE_BIT_COLOR_MAP_HPP
#define BOOST_DISTRIBUTED_ONE_BIT_COLOR_MAP_HPP
#ifndef BOOST_GRAPH_USE_MPI
#error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
#endif
#include <boost/graph/one_bit_color_map.hpp>
#include <boost/property_map/parallel/distributed_property_map.hpp>
#include <boost/property_map/parallel/local_property_map.hpp>
namespace boost {
template<typename ProcessGroup, typename GlobalMap, typename StorageMap>
class one_bit_color_map<local_property_map<ProcessGroup,GlobalMap,StorageMap> >
: public parallel::distributed_property_map<ProcessGroup, GlobalMap,
one_bit_color_map<StorageMap> >
{
typedef one_bit_color_map<StorageMap> local_map;
typedef parallel::distributed_property_map<ProcessGroup, GlobalMap,
local_map >
inherited;
typedef local_property_map<ProcessGroup, GlobalMap, StorageMap>
index_map_type;
public:
one_bit_color_map(std::size_t inital_size,
const index_map_type& index = index_map_type())
: inherited(index.process_group(), index.global(),
local_map(inital_size, index.base())) { }
inherited& base() { return *this; }
const inherited& base() const { return *this; }
};
template<typename ProcessGroup, typename GlobalMap, typename StorageMap>
inline one_bit_color_type
get(one_bit_color_map<local_property_map<ProcessGroup,GlobalMap,StorageMap> >
const& pm,
typename property_traits<GlobalMap>::key_type key)
{
return get(pm.base(), key);
}
template<typename ProcessGroup, typename GlobalMap, typename StorageMap>
inline void
put(one_bit_color_map<local_property_map<ProcessGroup,GlobalMap,StorageMap> >
const& pm,
typename property_traits<GlobalMap>::key_type key,
one_bit_color_type value)
{
put(pm.base(), key, value);
}
template<typename ProcessGroup, typename GlobalMap, typename StorageMap>
class one_bit_color_map<parallel::distributed_property_map<
ProcessGroup, GlobalMap, StorageMap> >
: public parallel::distributed_property_map<
ProcessGroup, GlobalMap, one_bit_color_map<StorageMap> >
{
typedef one_bit_color_map<StorageMap> local_map;
typedef parallel::distributed_property_map<ProcessGroup,GlobalMap,local_map>
inherited;
typedef parallel::distributed_property_map<ProcessGroup, GlobalMap,
StorageMap>
index_map_type;
public:
one_bit_color_map(std::size_t inital_size,
const index_map_type& index = index_map_type())
: inherited(index.process_group(), index.global(),
local_map(inital_size, index.base())) { }
inherited& base() { return *this; }
const inherited& base() const { return *this; }
};
template<typename ProcessGroup, typename GlobalMap, typename StorageMap>
inline one_bit_color_type
get(one_bit_color_map<
parallel::distributed_property_map<
ProcessGroup, GlobalMap, one_bit_color_map<StorageMap> > > const& pm,
typename property_traits<GlobalMap>::key_type key)
{
return get(pm.base(), key);
}
template<typename ProcessGroup, typename GlobalMap, typename StorageMap>
inline void
put(one_bit_color_map<
parallel::distributed_property_map<
ProcessGroup, GlobalMap, one_bit_color_map<StorageMap> > > const& pm,
typename property_traits<GlobalMap>::key_type key,
one_bit_color_type value)
{
put(pm.base(), key, value);
}
} // end namespace boost
#endif // BOOST_DISTRIBUTED_ONE_BIT_COLOR_MAP_HPP
@@ -0,0 +1,227 @@
// Copyright (C) 2004-2006 The Trustees of Indiana University.
// Copyright (C) 2002 Brad King and Douglas Gregor
// Use, modification and distribution is subject to 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)
// Authors: Douglas Gregor
// Andrew Lumsdaine
// Brian Barrett
#ifndef BOOST_PARALLEL_GRAPH_PAGE_RANK_HPP
#define BOOST_PARALLEL_GRAPH_PAGE_RANK_HPP
#ifndef BOOST_GRAPH_USE_MPI
#error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
#endif
#include <boost/assert.hpp>
#include <boost/graph/overloading.hpp>
#include <boost/graph/page_rank.hpp>
#include <boost/graph/distributed/concepts.hpp>
#include <boost/property_map/parallel/distributed_property_map.hpp>
#include <boost/property_map/parallel/caching_property_map.hpp>
#include <boost/graph/parallel/algorithm.hpp>
#include <boost/graph/parallel/container_traits.hpp>
// #define WANT_MPI_ONESIDED 1
namespace boost { namespace graph { namespace distributed {
namespace detail {
#ifdef WANT_MPI_ONESIDED
template<typename Graph, typename RankMap, typename owner_map_t>
void page_rank_step(const Graph& g, RankMap from_rank, MPI_Win to_win,
typename property_traits<RankMap>::value_type damping,
owner_map_t owner)
{
typedef typename property_traits<RankMap>::value_type rank_type;
int me, ret;
MPI_Comm_rank(MPI_COMM_WORLD, &me);
// MPI_Accumulate is not required to store the value of the data
// being sent, only the address. The value of the memory location
// must not change until the end of the access epoch, meaning the
// call to MPI_Fence. We therefore store the updated value back
// into the from_rank map before the accumulate rather than using
// a temporary. We're going to reset the values in the from_rank
// before the end of page_rank_step() anyway, so this isn't a huge
// deal. But MPI-2 One-sided is an abomination.
BGL_FORALL_VERTICES_T(u, g, Graph) {
put(from_rank, u, (damping * get(from_rank, u) / out_degree(u, g)));
BGL_FORALL_ADJ_T(u, v, g, Graph) {
ret = MPI_Accumulate(&(from_rank[u]),
1, MPI_DOUBLE,
get(owner, v), local(v),
1, MPI_DOUBLE, MPI_SUM, to_win);
BOOST_ASSERT(MPI_SUCCESS == ret);
}
}
MPI_Win_fence(0, to_win);
// Set new rank maps for the other map. Do this now to get around
// the stupid synchronization rules of MPI-2 One-sided
BGL_FORALL_VERTICES_T(v, g, Graph) put(from_rank, v, rank_type(1 - damping));
}
#endif
template<typename T>
struct rank_accumulate_reducer {
BOOST_STATIC_CONSTANT(bool, non_default_resolver = true);
template<typename K>
T operator()(const K&) const { return T(0); }
template<typename K>
T operator()(const K&, const T& x, const T& y) const { return x + y; }
};
} // end namespace detail
template<typename Graph, typename RankMap, typename Done, typename RankMap2>
void
page_rank_impl(const Graph& g, RankMap rank_map, Done done,
typename property_traits<RankMap>::value_type damping,
typename graph_traits<Graph>::vertices_size_type n,
RankMap2 rank_map2)
{
typedef typename property_traits<RankMap>::value_type rank_type;
int me;
MPI_Comm_rank(MPI_COMM_WORLD, &me);
typedef typename property_map<Graph, vertex_owner_t>
::const_type vertex_owner_map;
typename property_map<Graph, vertex_owner_t>::const_type
owner = get(vertex_owner, g);
(void)owner;
typedef typename boost::graph::parallel::process_group_type<Graph>
::type process_group_type;
typedef typename process_group_type::process_id_type process_id_type;
process_group_type pg = process_group(g);
process_id_type id = process_id(pg);
BOOST_ASSERT(me == id);
rank_type initial_rank = rank_type(rank_type(1) / n);
BGL_FORALL_VERTICES_T(v, g, Graph) put(rank_map, v, initial_rank);
#ifdef WANT_MPI_ONESIDED
BOOST_ASSERT(sizeof(rank_type) == sizeof(double));
bool to_map_2 = true;
MPI_Win win, win2;
MPI_Win_create(&(rank_map[*(vertices(g).first)]),
sizeof(double) * num_vertices(g),
sizeof(double),
MPI_INFO_NULL, MPI_COMM_WORLD, &win);
MPI_Win_set_name(win, "rank_map_win");
MPI_Win_create(&(rank_map2[*(vertices(g).first)]),
sizeof(double) * num_vertices(g),
sizeof(double),
MPI_INFO_NULL, MPI_COMM_WORLD, &win2);
MPI_Win_set_name(win, "rank_map2_win");
// set initial rank maps for the first iteration...
BGL_FORALL_VERTICES_T(v, g, Graph) put(rank_map2, v, rank_type(1 - damping));
MPI_Win_fence(0, win);
MPI_Win_fence(0, win2);
while ((to_map_2 && !done(rank_map, g)) ||
(!to_map_2 && !done(rank_map2, g))) {
if (to_map_2) {
graph::distributed::detail::page_rank_step(g, rank_map, win2, damping, owner);
to_map_2 = false;
} else {
graph::distributed::detail::page_rank_step(g, rank_map2, win, damping, owner);
to_map_2 = true;
}
}
synchronize(boost::graph::parallel::process_group(g));
MPI_Win_free(&win);
MPI_Win_free(&win2);
#else
// The ranks accumulate after each step.
rank_map.set_reduce(detail::rank_accumulate_reducer<rank_type>());
rank_map2.set_reduce(detail::rank_accumulate_reducer<rank_type>());
rank_map.set_consistency_model(boost::parallel::cm_flush | boost::parallel::cm_reset);
rank_map2.set_consistency_model(boost::parallel::cm_flush | boost::parallel::cm_reset);
bool to_map_2 = true;
while ((to_map_2 && !done(rank_map, g)) ||
(!to_map_2 && !done(rank_map2, g))) {
/**
* PageRank can implemented slightly more efficiently on a
* bidirectional graph than on an incidence graph. However,
* distributed PageRank requires that we have the rank of the
* source vertex available locally, so we force the incidence
* graph implementation, which pushes rank from source to
* target.
*/
typedef incidence_graph_tag category;
if (to_map_2) {
graph::detail::page_rank_step(g, rank_map, rank_map2, damping,
category());
to_map_2 = false;
} else {
graph::detail::page_rank_step(g, rank_map2, rank_map, damping,
category());
to_map_2 = true;
}
using boost::graph::parallel::process_group;
synchronize(process_group(g));
}
rank_map.reset();
#endif
if (!to_map_2)
BGL_FORALL_VERTICES_T(v, g, Graph) put(rank_map, v, get(rank_map2, v));
}
template<typename Graph, typename RankMap, typename Done, typename RankMap2>
void
page_rank(const Graph& g, RankMap rank_map, Done done,
typename property_traits<RankMap>::value_type damping,
typename graph_traits<Graph>::vertices_size_type n,
RankMap2 rank_map2
BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph, distributed_graph_tag))
{
(page_rank_impl)(g, rank_map, done, damping, n, rank_map2);
}
template<typename MutableGraph>
void
remove_dangling_links(MutableGraph& g
BOOST_GRAPH_ENABLE_IF_MODELS_PARM(MutableGraph,
distributed_graph_tag))
{
typename graph_traits<MutableGraph>::vertices_size_type old_n;
do {
old_n = num_vertices(g);
typename graph_traits<MutableGraph>::vertex_iterator vi, vi_end;
for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; /* in loop */) {
typename graph_traits<MutableGraph>::vertex_descriptor v = *vi++;
if (out_degree(v, g) == 0) {
clear_vertex(v, g);
remove_vertex(v, g);
}
}
} while (num_vertices(g) < old_n);
}
} // end namespace distributed
using distributed::page_rank;
using distributed::remove_dangling_links;
} } // end namespace boost::graph
#endif // BOOST_PARALLEL_GRAPH_PAGE_RANK_HPP
@@ -0,0 +1,278 @@
// Copyright (C) 2004-2006 The Trustees of Indiana University.
// Use, modification and distribution is subject to 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)
// Authors: Douglas Gregor
// Andrew Lumsdaine
#ifndef BOOST_GRAPH_DISTRIBUTED_QUEUE_HPP
#define BOOST_GRAPH_DISTRIBUTED_QUEUE_HPP
#ifndef BOOST_GRAPH_USE_MPI
#error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
#endif
#include <boost/graph/parallel/process_group.hpp>
#include <boost/optional.hpp>
#include <boost/shared_ptr.hpp>
#include <vector>
namespace boost { namespace graph { namespace distributed {
/// A unary predicate that always returns "true".
struct always_push
{
template<typename T> bool operator()(const T&) const { return true; }
};
/** A distributed queue adaptor.
*
* Class template @c distributed_queue implements a distributed queue
* across a process group. The distributed queue is an adaptor over an
* existing (local) queue, which must model the @ref Buffer
* concept. Each process stores a distinct copy of the local queue,
* from which it draws or removes elements via the @ref pop and @ref
* top members.
*
* The value type of the local queue must be a model of the @ref
* GlobalDescriptor concept. The @ref push operation of the
* distributed queue passes (via a message) the value to its owning
* processor. Thus, the elements within a particular local queue are
* guaranteed to have the process owning that local queue as an owner.
*
* Synchronization of distributed queues occurs in the @ref empty and
* @ref size functions, which will only return "empty" values (true or
* 0, respectively) when the entire distributed queue is empty. If the
* local queue is empty but the distributed queue is not, the
* operation will block until either condition changes. When the @ref
* size function of a nonempty queue returns, it returns the size of
* the local queue. These semantics were selected so that sequential
* code that processes elements in the queue via the following idiom
* can be parallelized via introduction of a distributed queue:
*
* distributed_queue<...> Q;
* Q.push(x);
* while (!Q.empty()) {
* // do something, that may push a value onto Q
* }
*
* In the parallel version, the initial @ref push operation will place
* the value @c x onto its owner's queue. All processes will
* synchronize at the call to empty, and only the process owning @c x
* will be allowed to execute the loop (@ref Q.empty() returns
* false). This iteration may in turn push values onto other remote
* queues, so when that process finishes execution of the loop body
* and all processes synchronize again in @ref empty, more processes
* may have nonempty local queues to execute. Once all local queues
* are empty, @ref Q.empty() returns @c false for all processes.
*
* The distributed queue can receive messages at two different times:
* during synchronization and when polling @ref empty. Messages are
* always received during synchronization, to ensure that accurate
* local queue sizes can be determines. However, whether @ref empty
* should poll for messages is specified as an option to the
* constructor. Polling may be desired when the order in which
* elements in the queue are processed is not important, because it
* permits fewer synchronization steps and less communication
* overhead. However, when more strict ordering guarantees are
* required, polling may be semantically incorrect. By disabling
* polling, one ensures that parallel execution using the idiom above
* will not process an element at a later "level" before an earlier
* "level".
*
* The distributed queue nearly models the @ref Buffer
* concept. However, the @ref push routine does not necessarily
* increase the result of @c size() by one (although the size of the
* global queue does increase by one).
*/
template<typename ProcessGroup, typename OwnerMap, typename Buffer,
typename UnaryPredicate = always_push>
class distributed_queue
{
typedef distributed_queue self_type;
enum {
/** Message indicating a remote push. The message contains a
* single value x of type value_type that is to be pushed on the
* receiver's queue.
*/
msg_push,
/** Push many elements at once. */
msg_multipush
};
public:
typedef ProcessGroup process_group_type;
typedef Buffer buffer_type;
typedef typename buffer_type::value_type value_type;
typedef typename buffer_type::size_type size_type;
/** Construct a new distributed queue.
*
* Build a new distributed queue that communicates over the given @p
* process_group, whose local queue is initialized via @p buffer and
* which may or may not poll for messages.
*/
explicit
distributed_queue(const ProcessGroup& process_group,
const OwnerMap& owner,
const Buffer& buffer,
bool polling = false);
/** Construct a new distributed queue.
*
* Build a new distributed queue that communicates over the given @p
* process_group, whose local queue is initialized via @p buffer and
* which may or may not poll for messages.
*/
explicit
distributed_queue(const ProcessGroup& process_group = ProcessGroup(),
const OwnerMap& owner = OwnerMap(),
const Buffer& buffer = Buffer(),
const UnaryPredicate& pred = UnaryPredicate(),
bool polling = false);
/** Construct a new distributed queue.
*
* Build a new distributed queue that communicates over the given @p
* process_group, whose local queue is default-initalized and which
* may or may not poll for messages.
*/
distributed_queue(const ProcessGroup& process_group, const OwnerMap& owner,
const UnaryPredicate& pred, bool polling = false);
/** Virtual destructor required with virtual functions.
*
*/
virtual ~distributed_queue() {}
/** Push an element onto the distributed queue.
*
* The element will be sent to its owner process to be added to that
* process's local queue. If polling is enabled for this queue and
* the owner process is the current process, the value will be
* immediately pushed onto the local queue.
*
* Complexity: O(1) messages of size O(sizeof(value_type)) will be
* transmitted.
*/
void push(const value_type& x);
/** Pop an element off the local queue.
*
* @p @c !empty()
*/
void pop() { buffer.pop(); }
/**
* Return the element at the top of the local queue.
*
* @p @c !empty()
*/
value_type& top() { return buffer.top(); }
/**
* \overload
*/
const value_type& top() const { return buffer.top(); }
/** Determine if the queue is empty.
*
* When the local queue is nonempty, returns @c true. If the local
* queue is empty, synchronizes with all other processes in the
* process group until either (1) the local queue is nonempty
* (returns @c true) (2) the entire distributed queue is empty
* (returns @c false).
*/
bool empty() const;
/** Determine the size of the local queue.
*
* The behavior of this routine is equivalent to the behavior of
* @ref empty, except that when @ref empty returns true this
* function returns the size of the local queue and when @ref empty
* returns false this function returns zero.
*/
size_type size() const;
// private:
/** Synchronize the distributed queue and determine if all queues
* are empty.
*
* \returns \c true when all local queues are empty, or false if at least
* one of the local queues is nonempty.
* Defined as virtual for derived classes like depth_limited_distributed_queue.
*/
virtual bool do_synchronize() const;
private:
// Setup triggers
void setup_triggers();
// Message handlers
void
handle_push(int source, int tag, const value_type& value,
trigger_receive_context);
void
handle_multipush(int source, int tag, const std::vector<value_type>& values,
trigger_receive_context);
mutable ProcessGroup process_group;
OwnerMap owner;
mutable Buffer buffer;
UnaryPredicate pred;
bool polling;
typedef std::vector<value_type> outgoing_buffer_t;
typedef std::vector<outgoing_buffer_t> outgoing_buffers_t;
shared_ptr<outgoing_buffers_t> outgoing_buffers;
};
/// Helper macro containing the normal names for the template
/// parameters to distributed_queue.
#define BOOST_DISTRIBUTED_QUEUE_PARMS \
typename ProcessGroup, typename OwnerMap, typename Buffer, \
typename UnaryPredicate
/// Helper macro containing the normal template-id for
/// distributed_queue.
#define BOOST_DISTRIBUTED_QUEUE_TYPE \
distributed_queue<ProcessGroup, OwnerMap, Buffer, UnaryPredicate>
/** Synchronize all processes involved with the given distributed queue.
*
* This function will synchronize all of the local queues for a given
* distributed queue, by ensuring that no additional messages are in
* transit. It is rarely required by the user, because most
* synchronization of distributed queues occurs via the @c empty or @c
* size methods.
*/
template<BOOST_DISTRIBUTED_QUEUE_PARMS>
inline void
synchronize(const BOOST_DISTRIBUTED_QUEUE_TYPE& Q)
{ Q.do_synchronize(); }
/// Construct a new distributed queue.
template<typename ProcessGroup, typename OwnerMap, typename Buffer>
inline distributed_queue<ProcessGroup, OwnerMap, Buffer>
make_distributed_queue(const ProcessGroup& process_group,
const OwnerMap& owner,
const Buffer& buffer,
bool polling = false)
{
typedef distributed_queue<ProcessGroup, OwnerMap, Buffer> result_type;
return result_type(process_group, owner, buffer, polling);
}
} } } // end namespace boost::graph::distributed
#include <boost/graph/distributed/detail/queue.ipp>
#undef BOOST_DISTRIBUTED_QUEUE_TYPE
#undef BOOST_DISTRIBUTED_QUEUE_PARMS
#endif // BOOST_GRAPH_DISTRIBUTED_QUEUE_HPP
@@ -0,0 +1,38 @@
// Copyright (C) 2005-2006 The Trustees of Indiana University.
// Use, modification and distribution is subject to 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)
// Authors: Nick Edmonds
// Andrew Lumsdaine
#ifndef BOOST_GRAPH_DISTRIBUTED_REVERSE_GRAPH_HPP
#define BOOST_GRAPH_DISTRIBUTED_REVERSE_GRAPH_HPP
#ifndef BOOST_GRAPH_USE_MPI
#error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
#endif
#include <boost/graph/reverse_graph.hpp>
#include <boost/graph/parallel/container_traits.hpp>
namespace boost {
namespace graph {
namespace parallel {
/// Retrieve the process group from a reverse graph
template<typename Graph, typename GraphRef>
struct process_group_type<reverse_graph<Graph, GraphRef> >
: process_group_type<Graph> { };
}
}
/// Retrieve the process group from a reverse graph
template<typename Graph, typename GraphRef>
inline typename graph::parallel::process_group_type<Graph>::type
process_group(reverse_graph<Graph, GraphRef> const& g) {
return process_group(g.m_g);
}
} // namespace boost
#endif
@@ -0,0 +1,164 @@
// Copyright 2004, 2005 The Trustees of Indiana University.
// Use, modification and distribution is subject to 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)
// Authors: Nick Edmonds
// Andrew Lumsdaine
#ifndef BOOST_GRAPH_DISTRIBUTED_RMAT_GENERATOR_HPP
#define BOOST_GRAPH_DISTRIBUTED_RMAT_GENERATOR_HPP
#ifndef BOOST_GRAPH_USE_MPI
#error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
#endif
#include <boost/assert.hpp>
#include <boost/graph/parallel/algorithm.hpp>
#include <boost/graph/parallel/process_group.hpp>
#include <math.h>
namespace boost {
// Memory-scalable (amount of memory required will scale down
// linearly as the number of processes increases) generator, which
// requires an MPI process group. Run-time is slightly worse than
// the unique rmat generator. Edge list generated is sorted and
// unique.
template<typename ProcessGroup, typename Distribution,
typename RandomGenerator, typename Graph>
class scalable_rmat_iterator
{
typedef typename graph_traits<Graph>::directed_category directed_category;
typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type;
typedef typename graph_traits<Graph>::edges_size_type edges_size_type;
public:
typedef std::input_iterator_tag iterator_category;
typedef std::pair<vertices_size_type, vertices_size_type> value_type;
typedef const value_type& reference;
typedef const value_type* pointer;
typedef void difference_type;
// No argument constructor, set to terminating condition
scalable_rmat_iterator()
: gen(), done(true)
{ }
// Initialize for edge generation
scalable_rmat_iterator(ProcessGroup pg, Distribution distrib,
RandomGenerator& gen, vertices_size_type n,
edges_size_type m, double a, double b, double c,
double d, bool permute_vertices = true)
: gen(), done(false)
{
BOOST_ASSERT(a + b + c + d == 1);
int id = process_id(pg);
this->gen.reset(new uniform_01<RandomGenerator>(gen));
std::vector<vertices_size_type> vertexPermutation;
if (permute_vertices)
generate_permutation_vector(gen, vertexPermutation, n);
int SCALE = int(floor(log(double(n))/log(2.)));
boost::uniform_01<RandomGenerator> prob(gen);
std::map<value_type, bool> edge_map;
edges_size_type generated = 0, local_edges = 0;
do {
edges_size_type tossed = 0;
do {
vertices_size_type u, v;
boost::tie(u, v) = generate_edge(this->gen, n, SCALE, a, b, c, d);
if (permute_vertices) {
u = vertexPermutation[u];
v = vertexPermutation[v];
}
// Lowest vertex number always comes first (this
// means we don't have to worry about i->j and j->i
// being in the edge list)
if (u > v && is_same<directed_category, undirected_tag>::value)
std::swap(u, v);
if (distrib(u) == id || distrib(v) == id) {
if (edge_map.find(std::make_pair(u, v)) == edge_map.end()) {
edge_map[std::make_pair(u, v)] = true;
local_edges++;
} else {
tossed++;
// special case - if both u and v are on same
// proc, ++ twice, since we divide by two (to
// cover the two process case)
if (distrib(u) == id && distrib(v) == id)
tossed++;
}
}
generated++;
} while (generated < m);
tossed = all_reduce(pg, tossed, boost::parallel::sum<vertices_size_type>());
generated -= (tossed / 2);
} while (generated < m);
// NGE - Asking for more than n^2 edges will result in an infinite loop here
// Asking for a value too close to n^2 edges may as well
values.reserve(local_edges);
typename std::map<value_type, bool>::reverse_iterator em_end = edge_map.rend();
for (typename std::map<value_type, bool>::reverse_iterator em_i = edge_map.rbegin();
em_i != em_end ;
++em_i) {
values.push_back(em_i->first);
}
current = values.back();
values.pop_back();
}
reference operator*() const { return current; }
pointer operator->() const { return &current; }
scalable_rmat_iterator& operator++()
{
if (!values.empty()) {
current = values.back();
values.pop_back();
} else
done = true;
return *this;
}
scalable_rmat_iterator operator++(int)
{
scalable_rmat_iterator temp(*this);
++(*this);
return temp;
}
bool operator==(const scalable_rmat_iterator& other) const
{
return values.empty() && other.values.empty() && done && other.done;
}
bool operator!=(const scalable_rmat_iterator& other) const
{ return !(*this == other); }
private:
// Parameters
shared_ptr<uniform_01<RandomGenerator> > gen;
// Internal data structures
std::vector<value_type> values;
value_type current;
bool done;
};
} // end namespace boost
#endif // BOOST_GRAPH_DISTRIBUTED_RMAT_GENERATOR_HPP
@@ -0,0 +1,44 @@
// Copyright (C) 2006 The Trustees of Indiana University.
// Use, modification and distribution is subject to 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)
// Authors: Douglas Gregor
// Andrew Lumsdaine
#ifndef BOOST_GRAPH_DISTRIBUTED_SELECTOR_HPP
#define BOOST_GRAPH_DISTRIBUTED_SELECTOR_HPP
#ifndef BOOST_GRAPH_USE_MPI
#error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
#endif
#include <boost/graph/detail/is_distributed_selector.hpp>
namespace boost {
/* The default local selector for a distributedS selector. */
struct defaultS {};
/**
* Selector that specifies that the graph should be distributed
* among different processes organized based on the given process
* group.
*/
template<typename ProcessGroup, typename LocalS = defaultS,
typename DistributionS = defaultS>
struct distributedS
{
typedef ProcessGroup process_group_type;
typedef LocalS local_selector;
typedef DistributionS distribution;
};
namespace detail {
template<typename ProcessGroup, typename LocalS, typename DistributionS>
struct is_distributed_selector<distributedS<ProcessGroup, LocalS, DistributionS> >: mpl::true_ {};
}
}
#endif // BOOST_GRAPH_DISTRIBUTED_SELECTOR_HPP
@@ -0,0 +1,114 @@
// Copyright Daniel Wallin 2007. Use, modification and distribution is
// subject to 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_SHUFFLED_DISTRIBUTION_070923_HPP
#define BOOST_SHUFFLED_DISTRIBUTION_070923_HPP
#ifndef BOOST_GRAPH_USE_MPI
#error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
#endif
# include <boost/assert.hpp>
# include <boost/iterator/counting_iterator.hpp>
# include <vector>
namespace boost { namespace graph { namespace distributed {
template <class BaseDistribution>
struct shuffled_distribution : BaseDistribution
{
typedef std::size_t size_type;
template <class ProcessGroup>
shuffled_distribution(ProcessGroup const& pg, BaseDistribution const& base)
: BaseDistribution(base)
, n(num_processes(pg))
, mapping_(make_counting_iterator(size_type(0)), make_counting_iterator(n))
, reverse_mapping(mapping_)
{}
std::vector<size_type> const& mapping() const
{
return mapping_;
}
template <class InputIterator>
void assign_mapping(InputIterator first, InputIterator last)
{
mapping_.assign(first, last);
BOOST_ASSERT(mapping_.size() == n);
reverse_mapping.resize(mapping_.size());
for (std::vector<size_t>::iterator i(mapping_.begin());
i != mapping_.end(); ++i)
{
reverse_mapping[*i] = i - mapping_.begin();
}
}
BaseDistribution& base()
{
return *this;
}
BaseDistribution const& base() const
{
return *this;
}
template <class ProcessID>
size_type block_size(ProcessID id, size_type n) const
{
return base().block_size(reverse_mapping[id], n);
}
template <class T>
size_type operator()(T const& value) const
{
return mapping_[base()(value)];
}
template <class ProcessID>
size_type start(ProcessID id) const
{
return base().start(reverse_mapping[id]);
}
size_type local(size_type i) const
{
return base().local(i);
}
size_type global(size_type i) const
{
return base().global(i);
}
template <class ProcessID>
size_type global(ProcessID id, size_type n) const
{
return base().global(reverse_mapping[id], n);
}
template <class Archive>
void serialize(Archive& ar, unsigned long /*version*/)
{
ar & serialization::make_nvp("base", base());
}
void clear()
{
base().clear();
}
private:
size_type n;
std::vector<size_type> mapping_;
std::vector<size_type> reverse_mapping;
};
}}} // namespace boost::graph::distributed
#endif // BOOST_SHUFFLED_DISTRIBUTION_070923_HPP
@@ -0,0 +1,186 @@
// Copyright (C) 2006 The Trustees of Indiana University.
// Use, modification and distribution is subject to 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)
// Authors: Douglas Gregor
// Andrew Lumsdaine
#ifndef BOOST_GRAPH_DISTRIBUTED_ST_CONNECTED_HPP
#define BOOST_GRAPH_DISTRIBUTED_ST_CONNECTED_HPP
#ifndef BOOST_GRAPH_USE_MPI
#error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
#endif
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/two_bit_color_map.hpp>
#include <boost/graph/distributed/queue.hpp>
#include <boost/pending/queue.hpp>
#include <boost/graph/iteration_macros.hpp>
#include <boost/graph/parallel/container_traits.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/graph/parallel/algorithm.hpp>
#include <utility>
#include <boost/optional.hpp>
namespace boost { namespace graph { namespace distributed {
namespace detail {
struct pair_and_or
{
std::pair<bool, bool>
operator()(std::pair<bool, bool> x, std::pair<bool, bool> y) const
{
return std::pair<bool, bool>(x.first && y.first,
x.second || y.second);
}
};
} // end namespace detail
template<typename DistributedGraph, typename ColorMap, typename OwnerMap>
bool
st_connected(const DistributedGraph& g,
typename graph_traits<DistributedGraph>::vertex_descriptor s,
typename graph_traits<DistributedGraph>::vertex_descriptor t,
ColorMap color, OwnerMap owner)
{
using boost::graph::parallel::process_group;
using boost::graph::parallel::process_group_type;
using boost::parallel::all_reduce;
typedef typename property_traits<ColorMap>::value_type Color;
typedef color_traits<Color> ColorTraits;
typedef typename process_group_type<DistributedGraph>::type ProcessGroup;
typedef typename ProcessGroup::process_id_type ProcessID;
typedef typename graph_traits<DistributedGraph>::vertex_descriptor Vertex;
// Set all vertices to white (unvisited)
BGL_FORALL_VERTICES_T(v, g, DistributedGraph)
put(color, v, ColorTraits::white());
// "color" plays the role of a color map, with no synchronization.
set_property_map_role(vertex_color, color);
color.set_consistency_model(0);
// Vertices found from the source are grey
put(color, s, ColorTraits::gray());
// Vertices found from the target are green
put(color, t, ColorTraits::green());
ProcessGroup pg = process_group(g);
ProcessID rank = process_id(pg);
// Build a local queue
queue<Vertex> Q;
if (get(owner, s) == rank) Q.push(s);
if (get(owner, t) == rank) Q.push(t);
queue<Vertex> other_Q;
while (true) {
bool found = false;
// Process all vertices in the local queue
while (!found && !Q.empty()) {
Vertex u = Q.top(); Q.pop();
Color u_color = get(color, u);
BGL_FORALL_OUTEDGES_T(u, e, g, DistributedGraph) {
Vertex v = target(e, g);
Color v_color = get(color, v);
if (v_color == ColorTraits::white()) {
// We have not seen "v" before; mark it with the same color as u
Color u_color = get(color, u);
put(color, v, u_color);
// Either push v into the local queue or send it off to its
// owner.
ProcessID v_owner = get(owner, v);
if (v_owner == rank)
other_Q.push(v);
else
send(pg, v_owner, 0,
std::make_pair(v, u_color == ColorTraits::gray()));
} else if (v_color != ColorTraits::black() && u_color != v_color) {
// Colors have collided. We're done!
found = true;
break;
}
}
// u is done, so mark it black
put(color, u, ColorTraits::black());
}
// Ensure that all transmitted messages have been received.
synchronize(pg);
// Move all of the send-to-self values into the local Q.
other_Q.swap(Q);
if (!found) {
// Receive all messages
while (optional<std::pair<ProcessID, int> > msg = probe(pg)) {
std::pair<Vertex, bool> data;
receive(pg, msg->first, msg->second, data);
// Determine the colors of u and v, the source and target
// vertices (v is local).
Vertex v = data.first;
Color v_color = get(color, v);
Color u_color = data.second? ColorTraits::gray() : ColorTraits::green();
if (v_color == ColorTraits::white()) {
// v had no color before, so give it u's color and push it
// into the queue.
Q.push(v);
put(color, v, u_color);
} else if (v_color != ColorTraits::black() && u_color != v_color) {
// Colors have collided. We're done!
found = true;
break;
}
}
}
// Check if either all queues are empty or
std::pair<bool, bool> results = all_reduce(pg,
boost::parallel::detail::make_untracked_pair(Q.empty(), found),
detail::pair_and_or());
// If someone found the answer, we're done!
if (results.second)
return true;
// If all queues are empty, we're done.
if (results.first)
return false;
}
}
template<typename DistributedGraph, typename ColorMap>
inline bool
st_connected(const DistributedGraph& g,
typename graph_traits<DistributedGraph>::vertex_descriptor s,
typename graph_traits<DistributedGraph>::vertex_descriptor t,
ColorMap color)
{
return st_connected(g, s, t, color, get(vertex_owner, g));
}
template<typename DistributedGraph>
inline bool
st_connected(const DistributedGraph& g,
typename graph_traits<DistributedGraph>::vertex_descriptor s,
typename graph_traits<DistributedGraph>::vertex_descriptor t)
{
return st_connected(g, s, t,
make_two_bit_color_map(num_vertices(g),
get(vertex_index, g)));
}
} } } // end namespace boost::graph::distributed
#endif // BOOST_GRAPH_DISTRIBUTED_ST_CONNECTED_HPP
@@ -0,0 +1,988 @@
// Copyright (C) 2004-2008 The Trustees of Indiana University.
// Use, modification and distribution is subject to 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)
// Authors: Nick Edmonds
// Douglas Gregor
// Andrew Lumsdaine
#ifndef BOOST_GRAPH_DISTRIBUTED_SCC_HPP
#define BOOST_GRAPH_DISTRIBUTED_SCC_HPP
#ifndef BOOST_GRAPH_USE_MPI
#error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
#endif
// #define PBGL_SCC_DEBUG
#include <boost/assert.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/property_map/parallel/distributed_property_map.hpp>
#include <boost/property_map/parallel/caching_property_map.hpp>
#include <boost/graph/parallel/algorithm.hpp>
#include <boost/graph/parallel/process_group.hpp>
#include <boost/graph/distributed/queue.hpp>
#include <boost/graph/distributed/filtered_graph.hpp>
#include <boost/pending/indirect_cmp.hpp>
#include <boost/graph/breadth_first_search.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/overloading.hpp>
#include <boost/graph/distributed/concepts.hpp>
#include <boost/graph/distributed/local_subgraph.hpp>
#include <boost/graph/parallel/properties.hpp>
#include <boost/graph/named_function_params.hpp>
#include <boost/graph/random.hpp>
#include <boost/graph/distributed/reverse_graph.hpp>
#include <boost/optional.hpp>
#include <boost/graph/distributed/detail/filtered_queue.hpp>
#include <boost/graph/distributed/adjacency_list.hpp>
#ifdef PBGL_SCC_DEBUG
#include <iostream>
#include <cstdlib>
#include <iomanip>
#include <sys/time.h>
#include <boost/graph/distributed/graphviz.hpp> // for ostringstream
#endif
#include <vector>
#include <map>
#include <boost/graph/parallel/container_traits.hpp>
#ifdef PBGL_SCC_DEBUG
# include <boost/graph/accounting.hpp>
#endif /* PBGL_SCC_DEBUG */
// If your graph is likely to have large numbers of small strongly connected
// components then running the sequential SCC algorithm on the local subgraph
// and filtering components with no remote edges may increase performance
// #define FILTER_LOCAL_COMPONENTS
namespace boost { namespace graph { namespace distributed { namespace detail {
template<typename vertex_descriptor>
struct v_sets{
std::vector<vertex_descriptor> pred, succ, intersect, ps_union;
};
/* Serialize vertex set */
template<typename Graph>
void
marshal_set( std::vector<std::vector<typename graph_traits<Graph>::vertex_descriptor> > in,
std::vector<typename graph_traits<Graph>::vertex_descriptor>& out )
{
typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
for( std::size_t i = 0; i < in.size(); ++i ) {
out.insert( out.end(), graph_traits<Graph>::null_vertex() );
out.insert( out.end(), in[i].begin(), in[i].end() );
}
}
/* Un-serialize vertex set */
template<typename Graph>
void
unmarshal_set( std::vector<typename graph_traits<Graph>::vertex_descriptor> in,
std::vector<std::vector<typename graph_traits<Graph>::vertex_descriptor> >& out )
{
typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
while( !in.empty() ) {
typename std::vector<vertex_descriptor>::iterator end
= std::find( in.begin(), in.end(), graph_traits<Graph>::null_vertex() );
if( end == in.begin() )
in.erase( in.begin() );
else {
out.push_back(std::vector<vertex_descriptor>());
out[out.size() - 1].insert( out[out.size() - 1].end(), in.begin(), end );
in.erase( in.begin(), end );
}
}
}
/* Determine if vertex is in subset */
template <typename Set>
struct in_subset {
in_subset() : m_s(0) { }
in_subset(const Set& s) : m_s(&s) { }
template <typename Elt>
bool operator()(const Elt& x) const {
return ((*m_s).find(x) != (*m_s).end());
}
private:
const Set* m_s;
};
template<typename T>
struct vertex_identity_property_map
: public boost::put_get_helper<T, vertex_identity_property_map<T> >
{
typedef T key_type;
typedef T value_type;
typedef T reference;
typedef boost::readable_property_map_tag category;
inline value_type operator[](const key_type& v) const { return v; }
inline void clear() { }
};
template <typename T>
inline void synchronize( vertex_identity_property_map<T> & ) { }
/* BFS visitor for SCC */
template<typename Graph, typename SourceMap>
struct scc_discovery_visitor : bfs_visitor<>
{
scc_discovery_visitor(SourceMap& sourceM)
: sourceM(sourceM) {}
template<typename Edge>
void tree_edge(Edge e, const Graph& g)
{
put(sourceM, target(e,g), get(sourceM, source(e,g)));
}
private:
SourceMap& sourceM;
};
} } } } /* End namespace boost::graph::distributed::detail */
namespace boost { namespace graph { namespace distributed {
enum fhp_message_tags { fhp_edges_size_msg, fhp_add_edges_msg, fhp_pred_size_msg,
fhp_pred_msg, fhp_succ_size_msg, fhp_succ_msg };
template<typename Graph, typename ReverseGraph,
typename VertexComponentMap, typename IsoMapFR, typename IsoMapRF,
typename VertexIndexMap>
void
fleischer_hendrickson_pinar_strong_components(const Graph& g,
VertexComponentMap c,
const ReverseGraph& gr,
IsoMapFR fr, IsoMapRF rf,
VertexIndexMap vertex_index_map)
{
typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
typedef typename graph_traits<ReverseGraph>::vertex_iterator rev_vertex_iterator;
typedef typename graph_traits<ReverseGraph>::vertex_descriptor rev_vertex_descriptor;
typedef typename boost::graph::parallel::process_group_type<Graph>::type
process_group_type;
typedef typename process_group_type::process_id_type process_id_type;
typedef iterator_property_map<typename std::vector<vertex_descriptor>::iterator,
VertexIndexMap> ParentMap;
typedef iterator_property_map<typename std::vector<default_color_type>::iterator,
VertexIndexMap> ColorMap;
typedef iterator_property_map<typename std::vector<vertex_descriptor>::iterator,
VertexIndexMap> Rev_ParentMap;
typedef std::vector<std::pair<vertex_descriptor, vertex_descriptor> > VertexPairVec;
typedef typename property_map<Graph, vertex_owner_t>::const_type
OwnerMap;
OwnerMap owner = get(vertex_owner, g);
using boost::graph::parallel::process_group;
process_group_type pg = process_group(g);
process_id_type id = process_id(pg);
int num_procs = num_processes(pg);
int n = 0;
int my_n = num_vertices(g);
all_reduce(pg, &my_n, &my_n+1, &n, std::plus<int>());
//
// Initialization
//
#ifdef PBGL_SCC_DEBUG
accounting::time_type start = accounting::get_time();
#endif
vertex_iterator vstart, vend;
rev_vertex_iterator rev_vstart, rev_vend;
std::vector<std::vector<vertex_descriptor> > vertex_sets, new_vertex_sets;
vertex_sets.push_back(std::vector<vertex_descriptor>());
// Remove vertices that do not have at least one in edge and one out edge
new_vertex_sets.push_back(std::vector<vertex_descriptor>());
for( boost::tie(vstart, vend) = vertices(g); vstart != vend; vstart++ )
if( out_degree( get(fr, *vstart), gr) > 0 && out_degree(*vstart, g) > 0 )
new_vertex_sets[0].push_back( *vstart );
// Perform sequential SCC on local subgraph, filter all components with external
// edges, mark remaining components and remove them from vertex_sets
#ifdef FILTER_LOCAL_COMPONENTS
// This doesn't actually speed up SCC in connected graphs it seems, but it does work
// and may help in the case where there are lots of small strong components.
{
local_subgraph<const Graph> ls(g);
typedef typename property_map<local_subgraph<const Graph>, vertex_index_t>::type
local_index_map_type;
local_index_map_type local_index = get(vertex_index, ls);
std::vector<int> ls_components_vec(num_vertices(ls));
typedef iterator_property_map<std::vector<int>::iterator, local_index_map_type>
ls_components_map_type;
ls_components_map_type ls_component(ls_components_vec.begin(), local_index);
int num_comp = boost::strong_components(ls, ls_component);
// Create map of components
std::map<int, std::vector<vertex_descriptor> > local_comp_map;
typedef typename graph_traits<local_subgraph<const Graph> >::vertex_iterator ls_vertex_iterator;
ls_vertex_iterator vstart, vend;
for( boost::tie(vstart,vend) = vertices(ls); vstart != vend; vstart++ )
local_comp_map[get(ls_component, *vstart)].push_back( *vstart );
// Filter components that have no non-local edges
typedef typename graph_traits<Graph>::adjacency_iterator adjacency_iterator;
typedef typename graph_traits<ReverseGraph>::adjacency_iterator rev_adjacency_iterator;
adjacency_iterator abegin, aend;
rev_adjacency_iterator rev_abegin, rev_aend;
for( std::size_t i = 0; i < num_comp; ++i ) {
bool local = true;
for( std::size_t j = 0; j < local_comp_map[i].size(); j++ ) {
for( boost::tie(abegin,aend) = adjacent_vertices(local_comp_map[i][j], g);
abegin != aend; abegin++ )
if( get(owner, *abegin) != id ) {
local = false;
break;
}
if( local )
for( boost::tie(rev_abegin,rev_aend) = adjacent_vertices(get(fr, local_comp_map[i][j]), gr);
rev_abegin != rev_aend; rev_abegin++ )
if( get(owner, *rev_abegin) != id ) {
local = false;
break;
}
if( !local ) break;
}
if( local ) // Mark and remove from new_vertex_sets
for( std::size_t j = 0; j < local_comp_map[i].size(); j++ ) {
put( c, local_comp_map[i][j], local_comp_map[i][0] );
typename std::vector<vertex_descriptor>::iterator pos =
std::find(new_vertex_sets[0].begin(), new_vertex_sets[0].end(), local_comp_map[i][j]);
if( pos != new_vertex_sets[0].end() )
new_vertex_sets[0].erase(pos);
}
}
}
#endif // FILTER_LOCAL_COMPONENTS
all_gather( pg, new_vertex_sets[0].begin(), new_vertex_sets[0].end(), vertex_sets[0] );
new_vertex_sets.clear();
#ifdef PBGL_SCC_DEBUG
accounting::time_type end = accounting::get_time();
if(id == 0)
std::cerr << "Trim local SCCs time = " << accounting::print_time(end - start) << " seconds.\n";
#endif
if( vertex_sets[0].empty() ) return;
//
// Recursively determine SCCs
//
#ifdef PBGL_SCC_DEBUG
int iterations = 0;
#endif
// Only need to be able to map starting vertices for BFS from now on
fr.clear();
do {
#ifdef PBGL_SCC_DEBUG
if(id == 0) {
printf("\n\nIteration %d:\n\n", iterations++);
if( iterations > 1 ) {
end = accounting::get_time();
std::cerr << "Running main loop destructors time = " << accounting::print_time(end - start) << " seconds.\n";
}
start = accounting::get_time();
}
#endif
// Get forward->reverse mappings for BFS start vertices
for (std::size_t i = 0; i < vertex_sets.size(); ++i)
get(fr, vertex_sets[i][0]);
synchronize(fr);
// Determine local vertices to start BFS from
std::vector<vertex_descriptor> local_start;
for( std::size_t i = id; i < vertex_sets.size(); i += num_procs )
local_start.push_back(vertex_sets[i][0]);
if( local_start.empty() )
local_start.push_back(vertex_sets[0][0]);
// Make filtered graphs
typedef std::set<vertex_descriptor> VertexSet;
typedef std::set<rev_vertex_descriptor> Rev_VertexSet;
VertexSet filter_set_g;
Rev_VertexSet filter_set_gr;
typename VertexSet::iterator fs;
int active_vertices = 0;
for (std::size_t i = 0; i < vertex_sets.size(); i++)
active_vertices += vertex_sets[i].size();
// This is a completely random bound
if ( active_vertices < 0.05*n ) {
// TODO: This set insertion is ridiculously inefficient, make it an in-place-merge?
for (std::size_t i = 0; i < vertex_sets.size(); i++)
filter_set_g.insert(vertex_sets[i].begin(), vertex_sets[i].end());
for (fs = filter_set_g.begin(); fs != filter_set_g.end(); ++fs )
filter_set_gr.insert(get(fr, *fs));
}
filtered_graph<const Graph, keep_all, detail::in_subset<VertexSet> >
fg(g, keep_all(), detail::in_subset<VertexSet>(filter_set_g));
filtered_graph<const ReverseGraph, keep_all, detail::in_subset<VertexSet> >
fgr(gr, keep_all(), detail::in_subset<VertexSet>(filter_set_gr));
// Add additional starting vertices to BFS queue
typedef filtered_queue<queue<vertex_descriptor>, boost::detail::has_not_been_seen<VertexIndexMap> >
local_queue_type;
typedef boost::graph::distributed::distributed_queue<process_group_type, OwnerMap, local_queue_type>
queue_t;
typedef typename property_map<ReverseGraph, vertex_owner_t>::const_type
RevOwnerMap;
typedef filtered_queue<queue<rev_vertex_descriptor>, boost::detail::has_not_been_seen<VertexIndexMap> >
rev_local_queue_type;
typedef boost::graph::distributed::distributed_queue<process_group_type, RevOwnerMap, rev_local_queue_type>
rev_queue_t;
queue_t Q(process_group(g),
owner,
make_filtered_queue(queue<vertex_descriptor>(),
boost::detail::has_not_been_seen<VertexIndexMap>
(num_vertices(g), vertex_index_map)),
false);
rev_queue_t Qr(process_group(gr),
get(vertex_owner, gr),
make_filtered_queue(queue<rev_vertex_descriptor>(),
boost::detail::has_not_been_seen<VertexIndexMap>
(num_vertices(gr), vertex_index_map)),
false);
for( std::size_t i = 1; i < local_start.size(); ++i ) {
Q.push(local_start[i]);
Qr.push(get(fr, local_start[i]));
}
#ifdef PBGL_SCC_DEBUG
end = accounting::get_time();
if(id == 0)
std::cerr << " Initialize BFS time = " << accounting::print_time(end - start) << " seconds.\n";
start = accounting::get_time();
#endif
#ifdef PBGL_SCC_DEBUG
accounting::time_type start2 = accounting::get_time();
#endif
// Forward BFS
std::vector<default_color_type> color_map_s(num_vertices(g));
ColorMap color_map(color_map_s.begin(), vertex_index_map);
std::vector<vertex_descriptor> succ_map_s(num_vertices(g), graph_traits<Graph>::null_vertex());
ParentMap succ_map(succ_map_s.begin(), vertex_index_map);
for( std::size_t i = 0; i < vertex_sets.size(); ++i )
put(succ_map, vertex_sets[i][0], vertex_sets[i][0]);
#ifdef PBGL_SCC_DEBUG
accounting::time_type end2 = accounting::get_time();
if(id == 0)
std::cerr << " Initialize forward BFS time = " << accounting::print_time(end2 - start2) << " seconds.\n";
#endif
if (active_vertices < 0.05*n)
breadth_first_search(fg, local_start[0], Q,
detail::scc_discovery_visitor<filtered_graph<const Graph, keep_all,
detail::in_subset<VertexSet> >, ParentMap>
(succ_map),
color_map);
else
breadth_first_search(g, local_start[0], Q,
detail::scc_discovery_visitor<const Graph, ParentMap>(succ_map),
color_map);
#ifdef PBGL_SCC_DEBUG
start2 = accounting::get_time();
#endif
// Reverse BFS
color_map.clear(); // reuse color map since g and gr have same vertex index
std::vector<vertex_descriptor> pred_map_s(num_vertices(gr), graph_traits<Graph>::null_vertex());
Rev_ParentMap pred_map(pred_map_s.begin(), vertex_index_map);
for( std::size_t i = 0; i < vertex_sets.size(); ++i )
put(pred_map, get(fr, vertex_sets[i][0]), vertex_sets[i][0]);
#ifdef PBGL_SCC_DEBUG
end2 = accounting::get_time();
if(id == 0)
std::cerr << " Initialize reverse BFS time = " << accounting::print_time(end2 - start2) << " seconds.\n";
#endif
if (active_vertices < 0.05*n)
breadth_first_search(fgr, get(fr, local_start[0]),
Qr,
detail::scc_discovery_visitor<filtered_graph<const ReverseGraph, keep_all,
detail::in_subset<Rev_VertexSet> >, Rev_ParentMap>
(pred_map),
color_map);
else
breadth_first_search(gr, get(fr, local_start[0]),
Qr,
detail::scc_discovery_visitor<const ReverseGraph, Rev_ParentMap>(pred_map),
color_map);
#ifdef PBGL_SCC_DEBUG
end = accounting::get_time();
if(id == 0)
std::cerr << " Perform forward and reverse BFS time = " << accounting::print_time(end - start) << " seconds.\n";
start = accounting::get_time();
#endif
// Send predecessors and successors discovered by this proc to the proc responsible for
// this BFS tree
typedef struct detail::v_sets<vertex_descriptor> Vsets;
std::map<vertex_descriptor, Vsets> set_map;
std::map<vertex_descriptor, int> dest_map;
std::vector<VertexPairVec> successors(num_procs);
std::vector<VertexPairVec> predecessors(num_procs);
// Calculate destinations for messages
for (std::size_t i = 0; i < vertex_sets.size(); ++i)
dest_map[vertex_sets[i][0]] = i % num_procs;
for( boost::tie(vstart, vend) = vertices(g); vstart != vend; vstart++ ) {
vertex_descriptor v = get(succ_map, *vstart);
if( v != graph_traits<Graph>::null_vertex() ) {
if (dest_map[v] == id)
set_map[v].succ.push_back(*vstart);
else
successors[dest_map[v]].push_back( std::make_pair(v, *vstart) );
}
}
for( boost::tie(rev_vstart, rev_vend) = vertices(gr); rev_vstart != rev_vend; rev_vstart++ ) {
vertex_descriptor v = get(pred_map, *rev_vstart);
if( v != graph_traits<Graph>::null_vertex() ) {
if (dest_map[v] == id)
set_map[v].pred.push_back(get(rf, *rev_vstart));
else
predecessors[dest_map[v]].push_back( std::make_pair(v, get(rf, *rev_vstart)) );
}
}
// Send predecessor and successor messages
for (process_id_type i = 0; i < num_procs; ++i) {
if (!successors[i].empty()) {
send(pg, i, fhp_succ_size_msg, successors[i].size());
send(pg, i, fhp_succ_msg, &successors[i][0], successors[i].size());
}
if (!predecessors[i].empty()) {
send(pg, i, fhp_pred_size_msg, predecessors[i].size());
send(pg, i, fhp_pred_msg, &predecessors[i][0], predecessors[i].size());
}
}
synchronize(pg);
// Receive predecessor and successor messages and handle them
while (optional<std::pair<process_id_type, int> > m = probe(pg)) {
BOOST_ASSERT(m->second == fhp_succ_size_msg || m->second == fhp_pred_size_msg);
std::size_t num_requests;
receive(pg, m->first, m->second, num_requests);
VertexPairVec requests(num_requests);
if (m->second == fhp_succ_size_msg) {
receive(pg, m->first, fhp_succ_msg, &requests[0],
num_requests);
std::map<vertex_descriptor, int> added;
for (std::size_t i = 0; i < requests.size(); ++i) {
set_map[requests[i].first].succ.push_back(requests[i].second);
added[requests[i].first]++;
}
// If order of vertex traversal in vertices() is std::less<vertex_descriptor>,
// then the successor sets will be in order
for (std::size_t i = 0; i < local_start.size(); ++i)
if (added[local_start[i]] > 0)
std::inplace_merge(set_map[local_start[i]].succ.begin(),
set_map[local_start[i]].succ.end() - added[local_start[i]],
set_map[local_start[i]].succ.end(),
std::less<vertex_descriptor>());
} else {
receive(pg, m->first, fhp_pred_msg, &requests[0],
num_requests);
std::map<vertex_descriptor, int> added;
for (std::size_t i = 0; i < requests.size(); ++i) {
set_map[requests[i].first].pred.push_back(requests[i].second);
added[requests[i].first]++;
}
if (boost::is_same<detail::vertex_identity_property_map<vertex_descriptor>, IsoMapRF>::value)
for (std::size_t i = 0; i < local_start.size(); ++i)
if (added[local_start[i]] > 0)
std::inplace_merge(set_map[local_start[i]].pred.begin(),
set_map[local_start[i]].pred.end() - added[local_start[i]],
set_map[local_start[i]].pred.end(),
std::less<vertex_descriptor>());
}
}
#ifdef PBGL_SCC_DEBUG
end = accounting::get_time();
if(id == 0)
std::cerr << " All gather successors and predecessors time = " << accounting::print_time(end - start) << " seconds.\n";
start = accounting::get_time();
#endif
//
// Filter predecessor and successor sets and perform set arithmetic
//
new_vertex_sets.clear();
if( std::size_t(id) < vertex_sets.size() ) { //If this proc has one or more unique starting points
for( std::size_t i = 0; i < local_start.size(); ++i ) {
vertex_descriptor v = local_start[i];
// Replace this sort with an in-place merges during receive step if possible
if (!boost::is_same<detail::vertex_identity_property_map<vertex_descriptor>, IsoMapRF>::value)
std::sort(set_map[v].pred.begin(), set_map[v].pred.end(), std::less<vertex_descriptor>());
// Limit predecessor and successor sets to members of the original set
std::vector<vertex_descriptor> temp;
std::set_intersection( vertex_sets[id + i*num_procs].begin(), vertex_sets[id + i*num_procs].end(),
set_map[v].pred.begin(), set_map[v].pred.end(),
back_inserter(temp),
std::less<vertex_descriptor>());
set_map[v].pred.clear();
std::swap(set_map[v].pred, temp);
std::set_intersection( vertex_sets[id + i*num_procs].begin(), vertex_sets[id + i*num_procs].end(),
set_map[v].succ.begin(), set_map[v].succ.end(),
back_inserter(temp),
std::less<vertex_descriptor>());
set_map[v].succ.clear();
std::swap(set_map[v].succ, temp);
// Intersection(pred, succ)
std::set_intersection(set_map[v].pred.begin(), set_map[v].pred.end(),
set_map[v].succ.begin(), set_map[v].succ.end(),
back_inserter(set_map[v].intersect),
std::less<vertex_descriptor>());
// Union(pred, succ)
std::set_union(set_map[v].pred.begin(), set_map[v].pred.end(),
set_map[v].succ.begin(), set_map[v].succ.end(),
back_inserter(set_map[v].ps_union),
std::less<vertex_descriptor>());
new_vertex_sets.push_back(std::vector<vertex_descriptor>());
// Original set - Union(pred, succ)
std::set_difference(vertex_sets[id + i*num_procs].begin(), vertex_sets[id + i*num_procs].end(),
set_map[v].ps_union.begin(), set_map[v].ps_union.end(),
back_inserter(new_vertex_sets[new_vertex_sets.size() - 1]),
std::less<vertex_descriptor>());
set_map[v].ps_union.clear();
new_vertex_sets.push_back(std::vector<vertex_descriptor>());
// Pred - Intersect(pred, succ)
std::set_difference(set_map[v].pred.begin(), set_map[v].pred.end(),
set_map[v].intersect.begin(), set_map[v].intersect.end(),
back_inserter(new_vertex_sets[new_vertex_sets.size() - 1]),
std::less<vertex_descriptor>());
set_map[v].pred.clear();
new_vertex_sets.push_back(std::vector<vertex_descriptor>());
// Succ - Intersect(pred, succ)
std::set_difference(set_map[v].succ.begin(), set_map[v].succ.end(),
set_map[v].intersect.begin(), set_map[v].intersect.end(),
back_inserter(new_vertex_sets[new_vertex_sets.size() - 1]),
std::less<vertex_descriptor>());
set_map[v].succ.clear();
// Label SCC just identified with the 'first' vertex in that SCC
for( std::size_t j = 0; j < set_map[v].intersect.size(); j++ )
put(c, set_map[v].intersect[j], set_map[v].intersect[0]);
set_map[v].intersect.clear();
}
}
#ifdef PBGL_SCC_DEBUG
end = accounting::get_time();
if(id == 0)
std::cerr << " Perform set arithemetic time = " << accounting::print_time(end - start) << " seconds.\n";
start = accounting::get_time();
#endif
// Remove sets of size 1 from new_vertex_sets
typename std::vector<std::vector<vertex_descriptor> >::iterator vviter;
for( vviter = new_vertex_sets.begin(); vviter != new_vertex_sets.end(); /*in loop*/ )
if( (*vviter).size() < 2 )
vviter = new_vertex_sets.erase( vviter );
else
vviter++;
// All gather new sets and recur (gotta marshal and unmarshal sets first)
vertex_sets.clear();
std::vector<vertex_descriptor> serial_sets, all_serial_sets;
detail::marshal_set<Graph>( new_vertex_sets, serial_sets );
all_gather( pg, serial_sets.begin(), serial_sets.end(), all_serial_sets );
detail::unmarshal_set<Graph>( all_serial_sets, vertex_sets );
#ifdef PBGL_SCC_DEBUG
end = accounting::get_time();
if(id == 0) {
std::cerr << " Serialize and gather new vertex sets time = " << accounting::print_time(end - start) << " seconds.\n\n\n";
printf("Vertex sets: %d\n", (int)vertex_sets.size() );
for( std::size_t i = 0; i < vertex_sets.size(); ++i )
printf(" %d: %d\n", i, (int)vertex_sets[i].size() );
}
start = accounting::get_time();
#endif
// HACK!?! -- This would be more properly implemented as a topological sort
// Remove vertices without an edge to another vertex in the set and an edge from another
// vertex in the set
typedef typename graph_traits<Graph>::out_edge_iterator out_edge_iterator;
out_edge_iterator estart, eend;
typedef typename graph_traits<ReverseGraph>::out_edge_iterator r_out_edge_iterator;
r_out_edge_iterator restart, reend;
for (std::size_t i = 0; i < vertex_sets.size(); ++i) {
std::vector<vertex_descriptor> new_set;
for (std::size_t j = 0; j < vertex_sets[i].size(); ++j) {
vertex_descriptor v = vertex_sets[i][j];
if (get(owner, v) == id) {
boost::tie(estart, eend) = out_edges(v, g);
while (estart != eend && find(vertex_sets[i].begin(), vertex_sets[i].end(),
target(*estart,g)) == vertex_sets[i].end()) estart++;
if (estart != eend) {
boost::tie(restart, reend) = out_edges(get(fr, v), gr);
while (restart != reend && find(vertex_sets[i].begin(), vertex_sets[i].end(),
get(rf, target(*restart,gr))) == vertex_sets[i].end()) restart++;
if (restart != reend)
new_set.push_back(v);
}
}
}
vertex_sets[i].clear();
all_gather(pg, new_set.begin(), new_set.end(), vertex_sets[i]);
std::sort(vertex_sets[i].begin(), vertex_sets[i].end(), std::less<vertex_descriptor>());
}
#ifdef PBGL_SCC_DEBUG
end = accounting::get_time();
if(id == 0)
std::cerr << " Trim vertex sets time = " << accounting::print_time(end - start) << " seconds.\n\n\n";
start = accounting::get_time();
#endif
} while ( !vertex_sets.empty() );
// Label vertices not in a SCC as their own SCC
for( boost::tie(vstart, vend) = vertices(g); vstart != vend; vstart++ )
if( get(c, *vstart) == graph_traits<Graph>::null_vertex() )
put(c, *vstart, *vstart);
synchronize(c);
}
template<typename Graph, typename ReverseGraph, typename IsoMap>
void
build_reverse_graph( const Graph& g, ReverseGraph& gr, IsoMap& fr, IsoMap& rf )
{
typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
typedef typename graph_traits<Graph>::out_edge_iterator out_edge_iterator;
typedef typename boost::graph::parallel::process_group_type<Graph>::type process_group_type;
typedef typename process_group_type::process_id_type process_id_type;
typedef std::vector<std::pair<vertex_descriptor, vertex_descriptor> > VertexPairVec;
typedef typename graph_traits<Graph>::directed_category directed_category;
typename property_map<Graph, vertex_owner_t>::const_type
owner = get(vertex_owner, g);
process_group_type pg = process_group(g);
process_id_type id = process_id(pg);
int n;
vertex_iterator vstart, vend;
int num_procs = num_processes(pg);
vertex_descriptor v;
out_edge_iterator oestart, oeend;
for( boost::tie(vstart, vend) = vertices(g); vstart != vend; vstart++ )
{
v = add_vertex(gr);
put(fr, *vstart, v);
put(rf, v, *vstart);
}
gr.distribution() = g.distribution();
int my_n = num_vertices(g);
all_reduce(pg, &my_n, &my_n+1, &n, std::plus<int>());
for (int i = 0; i < n; ++i)
get(fr, vertex(i,g));
synchronize(fr);
// Add edges to gr
std::vector<std::pair<vertex_descriptor, vertex_descriptor> > new_edges;
for( boost::tie(vstart, vend) = vertices(g); vstart != vend; vstart++ )
for( boost::tie(oestart, oeend) = out_edges(*vstart, g); oestart != oeend; oestart++ )
new_edges.push_back( std::make_pair(get(fr, target(*oestart,g)), get(fr, source(*oestart, g))) );
std::vector<VertexPairVec> edge_requests(num_procs);
typename std::vector<std::pair<vertex_descriptor, vertex_descriptor> >::iterator iter;
for( iter = new_edges.begin(); iter != new_edges.end(); iter++ ) {
std::pair<vertex_descriptor, vertex_descriptor> p1 = *iter;
if( get(owner, p1.first ) == id )
add_edge( p1.first, p1.second, gr );
else
edge_requests[get(owner, p1.first)].push_back(p1);
}
new_edges.clear();
// Send edge addition requests
for (process_id_type p = 0; p < num_procs; ++p) {
if (!edge_requests[p].empty()) {
VertexPairVec reqs(edge_requests[p].begin(), edge_requests[p].end());
send(pg, p, fhp_edges_size_msg, reqs.size());
send(pg, p, fhp_add_edges_msg, &reqs[0], reqs.size());
}
}
synchronize(pg);
// Receive edge addition requests and handle them
while (optional<std::pair<process_id_type, int> > m = probe(pg)) {
BOOST_ASSERT(m->second == fhp_edges_size_msg);
std::size_t num_requests;
receive(pg, m->first, m->second, num_requests);
VertexPairVec requests(num_requests);
receive(pg, m->first, fhp_add_edges_msg, &requests[0],
num_requests);
for( std::size_t i = 0; i < requests.size(); ++i )
add_edge( requests[i].first, requests[i].second, gr );
}
synchronize(gr);
}
template<typename Graph, typename VertexComponentMap, typename ComponentMap>
typename property_traits<ComponentMap>::value_type
number_components(const Graph& g, VertexComponentMap r, ComponentMap c)
{
typedef typename boost::graph::parallel::process_group_type<Graph>::type process_group_type;
typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
typedef typename property_traits<ComponentMap>::value_type ComponentMapType;
std::vector<vertex_descriptor> my_roots, all_roots;
vertex_iterator vstart, vend;
for( boost::tie(vstart, vend) = vertices(g); vstart != vend; vstart++ )
if( find( my_roots.begin(), my_roots.end(), get(r, *vstart) ) == my_roots.end() )
my_roots.push_back( get(r, *vstart) );
all_gather( process_group(g), my_roots.begin(), my_roots.end(), all_roots );
/* Number components */
std::map<vertex_descriptor, ComponentMapType> comp_numbers;
ComponentMapType c_num = 0;
// Compute component numbers
for (std::size_t i = 0; i < all_roots.size(); ++i )
if ( comp_numbers.count(all_roots[i]) == 0 )
comp_numbers[all_roots[i]] = c_num++;
// Broadcast component numbers
for( boost::tie(vstart, vend) = vertices(g); vstart != vend; vstart++ )
put( c, *vstart, comp_numbers[get(r,*vstart)] );
// Broadcast number of components
if (process_id(process_group(g)) == 0) {
typedef typename process_group_type::process_size_type
process_size_type;
for (process_size_type dest = 1, n = num_processes(process_group(g));
dest != n; ++dest)
send(process_group(g), dest, 0, c_num);
}
synchronize(process_group(g));
if (process_id(process_group(g)) != 0) receive(process_group(g), 0, 0, c_num);
synchronize(c);
return c_num;
}
template<typename Graph, typename ComponentMap, typename VertexComponentMap,
typename VertexIndexMap>
typename property_traits<ComponentMap>::value_type
fleischer_hendrickson_pinar_strong_components_impl
(const Graph& g,
ComponentMap c,
VertexComponentMap r,
VertexIndexMap vertex_index_map,
incidence_graph_tag)
{
typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
typedef iterator_property_map<typename std::vector<vertex_descriptor>::iterator,
VertexIndexMap> IsoMap;
typename boost::graph::parallel::process_group_type<Graph>::type pg = process_group(g);
#ifdef PBGL_SCC_DEBUG
accounting::time_type start = accounting::get_time();
#endif
typedef adjacency_list<listS,
distributedS<typename boost::graph::parallel::process_group_type<Graph>::type, vecS>,
directedS > ReverseGraph;
ReverseGraph gr(0, pg);
std::vector<vertex_descriptor> fr_s(num_vertices(g));
std::vector<vertex_descriptor> rf_s(num_vertices(g));
IsoMap fr(fr_s.begin(), vertex_index_map); // fr = forward->reverse
IsoMap rf(rf_s.begin(), vertex_index_map); // rf = reverse->forward
build_reverse_graph(g, gr, fr, rf);
#ifdef PBGL_SCC_DEBUG
accounting::time_type end = accounting::get_time();
if(process_id(process_group(g)) == 0)
std::cerr << "Reverse graph initialization time = " << accounting::print_time(end - start) << " seconds.\n";
#endif
fleischer_hendrickson_pinar_strong_components(g, r, gr, fr, rf,
vertex_index_map);
typename property_traits<ComponentMap>::value_type c_num = number_components(g, r, c);
return c_num;
}
template<typename Graph, typename ComponentMap, typename VertexComponentMap,
typename VertexIndexMap>
typename property_traits<ComponentMap>::value_type
fleischer_hendrickson_pinar_strong_components_impl
(const Graph& g,
ComponentMap c,
VertexComponentMap r,
VertexIndexMap vertex_index_map,
bidirectional_graph_tag)
{
typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
reverse_graph<Graph> gr(g);
detail::vertex_identity_property_map<vertex_descriptor> fr, rf;
fleischer_hendrickson_pinar_strong_components(g, r, gr, fr, rf,
vertex_index_map);
typename property_traits<ComponentMap>::value_type c_num
= number_components(g, r, c);
return c_num;
}
template<typename Graph, typename ComponentMap, typename VertexIndexMap>
inline typename property_traits<ComponentMap>::value_type
fleischer_hendrickson_pinar_strong_components
(const Graph& g,
ComponentMap c,
VertexIndexMap vertex_index_map)
{
typedef typename graph_traits<Graph>::vertex_descriptor
vertex_descriptor;
typedef iterator_property_map<typename std::vector<vertex_descriptor>::iterator,
VertexIndexMap> VertexComponentMap;
typename boost::graph::parallel::process_group_type<Graph>::type pg
= process_group(g);
if (num_processes(pg) == 1) {
local_subgraph<const Graph> ls(g);
return boost::strong_components(ls, c);
}
// Create a VertexComponentMap for intermediate labeling of SCCs
std::vector<vertex_descriptor> r_s(num_vertices(g), graph_traits<Graph>::null_vertex());
VertexComponentMap r(r_s.begin(), vertex_index_map);
return fleischer_hendrickson_pinar_strong_components_impl
(g, c, r, vertex_index_map,
typename graph_traits<Graph>::traversal_category());
}
template<typename Graph, typename ComponentMap>
inline typename property_traits<ComponentMap>::value_type
fleischer_hendrickson_pinar_strong_components(const Graph& g,
ComponentMap c)
{
return fleischer_hendrickson_pinar_strong_components(g, c, get(vertex_index, g));
}
} // end namespace distributed
using distributed::fleischer_hendrickson_pinar_strong_components;
} // end namespace graph
template<class Graph, class ComponentMap, class P, class T, class R>
inline typename property_traits<ComponentMap>::value_type
strong_components
(const Graph& g, ComponentMap comp,
const bgl_named_params<P, T, R>&
BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph, distributed_graph_tag))
{
return graph::fleischer_hendrickson_pinar_strong_components(g, comp);
}
template<class Graph, class ComponentMap>
inline typename property_traits<ComponentMap>::value_type
strong_components
(const Graph& g, ComponentMap comp
BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph, distributed_graph_tag))
{
return graph::fleischer_hendrickson_pinar_strong_components(g, comp);
}
} /* end namespace boost */
#endif // BOOST_GRAPH_DISTRIBUTED_SCC_HPP
@@ -0,0 +1,116 @@
// Copyright (C) 2006 The Trustees of Indiana University.
// Use, modification and distribution is subject to 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)
// Authors: Douglas Gregor
// Jeremiah Willcock
// Andrew Lumsdaine
// Distributed version of the two-bit color map
#ifndef BOOST_DISTRIBUTED_TWO_BIT_COLOR_MAP_HPP
#define BOOST_DISTRIBUTED_TWO_BIT_COLOR_MAP_HPP
#ifndef BOOST_GRAPH_USE_MPI
#error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
#endif
#include <boost/graph/two_bit_color_map.hpp>
#include <boost/property_map/parallel/distributed_property_map.hpp>
#include <boost/property_map/parallel/local_property_map.hpp>
namespace boost {
template<typename ProcessGroup, typename GlobalMap, typename StorageMap>
class two_bit_color_map<local_property_map<ProcessGroup,GlobalMap,StorageMap> >
: public parallel::distributed_property_map<ProcessGroup, GlobalMap,
two_bit_color_map<StorageMap> >
{
typedef two_bit_color_map<StorageMap> local_map;
typedef parallel::distributed_property_map<ProcessGroup, GlobalMap,
local_map >
inherited;
typedef local_property_map<ProcessGroup, GlobalMap, StorageMap>
index_map_type;
public:
two_bit_color_map(std::size_t inital_size,
const index_map_type& index = index_map_type())
: inherited(index.process_group(), index.global(),
local_map(inital_size, index.base())) { }
inherited& base() { return *this; }
const inherited& base() const { return *this; }
};
template<typename ProcessGroup, typename GlobalMap, typename StorageMap>
inline two_bit_color_type
get(two_bit_color_map<local_property_map<ProcessGroup,GlobalMap,StorageMap> >
const& pm,
typename property_traits<GlobalMap>::key_type key)
{
return get(pm.base(), key);
}
template<typename ProcessGroup, typename GlobalMap, typename StorageMap>
inline void
put(two_bit_color_map<local_property_map<ProcessGroup,GlobalMap,StorageMap> >
const& pm,
typename property_traits<GlobalMap>::key_type key,
two_bit_color_type value)
{
put(pm.base(), key, value);
}
template<typename ProcessGroup, typename GlobalMap, typename StorageMap>
class two_bit_color_map<parallel::distributed_property_map<
ProcessGroup, GlobalMap, StorageMap> >
: public parallel::distributed_property_map<
ProcessGroup, GlobalMap, two_bit_color_map<StorageMap> >
{
typedef two_bit_color_map<StorageMap> local_map;
typedef parallel::distributed_property_map<ProcessGroup,GlobalMap,local_map>
inherited;
typedef parallel::distributed_property_map<ProcessGroup, GlobalMap,
StorageMap>
index_map_type;
public:
two_bit_color_map(std::size_t inital_size,
const index_map_type& index = index_map_type())
: inherited(index.process_group(), index.global(),
local_map(inital_size, index.base())) { }
inherited& base() { return *this; }
const inherited& base() const { return *this; }
};
template<typename ProcessGroup, typename GlobalMap, typename StorageMap>
inline two_bit_color_type
get(two_bit_color_map<
parallel::distributed_property_map<
ProcessGroup, GlobalMap, two_bit_color_map<StorageMap> > > const& pm,
typename property_traits<GlobalMap>::key_type key)
{
return get(pm.base(), key);
}
template<typename ProcessGroup, typename GlobalMap, typename StorageMap>
inline void
put(two_bit_color_map<
parallel::distributed_property_map<
ProcessGroup, GlobalMap, two_bit_color_map<StorageMap> > > const& pm,
typename property_traits<GlobalMap>::key_type key,
two_bit_color_type value)
{
put(pm.base(), key, value);
}
} // end namespace boost
#endif // BOOST_DISTRIBUTED_TWO_BIT_COLOR_MAP_HPP
Loaded 100 of 18807 files, more files were not shown because too many files have changed in this diff. Show more