mirror of
https://github.com/Patoke/LCERenewed.git
synced 2026-11-08 23:50:17 +00:00
feat: init
This commit is contained in:
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
|
||||
+242
@@ -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
|
||||
+322
@@ -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__
|
||||
+873
@@ -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
|
||||
|
||||
+310
@@ -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
|
||||
+1607
File diff suppressed because it is too large.
Load diff
@@ -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
|
||||
+117
@@ -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 */
|
||||
+651
@@ -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
|
||||
+208
@@ -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
|
||||
+77
@@ -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
|
||||
+284
@@ -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
|
||||
+26
@@ -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
|
||||
+237
@@ -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
|
||||
+614
@@ -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
|
||||
+418
@@ -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
|
||||
+252
@@ -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
|
||||
+3994
File diff suppressed because it is too large.
Load diff
+148
@@ -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
|
||||
|
||||
+319
@@ -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
|
||||
+393
@@ -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
|
||||
+993
@@ -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
|
||||
|
||||
+1727
File diff suppressed because it is too large.
Load diff
+372
@@ -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
|
||||
+164
@@ -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
|
||||
+1988
File diff suppressed because it is too large.
Load diff
@@ -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
|
||||
+769
@@ -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
|
||||
+409
@@ -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
|
||||
+665
@@ -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
|
||||
+938
@@ -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
|
||||
+513
@@ -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
|
||||
+307
@@ -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
|
||||
+50
@@ -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
|
||||
+108
@@ -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
|
||||
+1007
File diff suppressed because it is too large.
Load diff
@@ -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
|
||||
+259
@@ -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
|
||||
+84
@@ -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
|
||||
+204
@@ -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
|
||||
+154
@@ -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
|
||||
+447
@@ -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
|
||||
+51
@@ -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
|
||||
+384
@@ -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
|
||||
+1130
File diff suppressed because it is too large.
Load diff
+175
@@ -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
|
||||
+809
@@ -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
|
||||
File diff suppressed because it is too large.
Load diff
+116
@@ -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
|
||||
+164
@@ -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 ¤t; }
|
||||
|
||||
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
|
||||
+114
@@ -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
|
||||
+988
@@ -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
|
||||
+116
@@ -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
Reference in new issue
Block a user