$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
Subject: [Boost-commit] svn:boost r52300 - in trunk: boost/graph boost/graph/distributed boost/graph/distributed/adjlist boost/graph/distributed/detail boost/graph/parallel boost/graph/parallel/detail boost/pending libs/graph/build libs/graph/src
From: jewillco_at_[hidden]
Date: 2009-04-09 17:11:04
Author: jewillco
Date: 2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
New Revision: 52300
URL: http://svn.boost.org/trac/boost/changeset/52300
Log:
Merged headers and source files (but not examples, tests, or docs) from Parallel BGL
Added:
   trunk/boost/graph/distributed/
   trunk/boost/graph/distributed/adjacency_list.hpp   (contents, props changed)
   trunk/boost/graph/distributed/adjlist/
   trunk/boost/graph/distributed/adjlist/handlers.hpp   (contents, props changed)
   trunk/boost/graph/distributed/adjlist/initialize.hpp   (contents, props changed)
   trunk/boost/graph/distributed/adjlist/redistribute.hpp   (contents, props changed)
   trunk/boost/graph/distributed/adjlist/serialization.hpp   (contents, props changed)
   trunk/boost/graph/distributed/betweenness_centrality.hpp   (contents, props changed)
   trunk/boost/graph/distributed/boman_et_al_graph_coloring.hpp   (contents, props changed)
   trunk/boost/graph/distributed/breadth_first_search.hpp   (contents, props changed)
   trunk/boost/graph/distributed/compressed_sparse_row_graph.hpp   (contents, props changed)
   trunk/boost/graph/distributed/concepts.hpp   (contents, props changed)
   trunk/boost/graph/distributed/connected_components.hpp   (contents, props changed)
   trunk/boost/graph/distributed/connected_components_parallel_search.hpp   (contents, props changed)
   trunk/boost/graph/distributed/crauser_et_al_shortest_paths.hpp   (contents, props changed)
   trunk/boost/graph/distributed/dehne_gotz_min_spanning_tree.hpp   (contents, props changed)
   trunk/boost/graph/distributed/delta_stepping_shortest_paths.hpp   (contents, props changed)
   trunk/boost/graph/distributed/depth_first_search.hpp   (contents, props changed)
   trunk/boost/graph/distributed/detail/
   trunk/boost/graph/distributed/detail/dijkstra_shortest_paths.hpp   (contents, props changed)
   trunk/boost/graph/distributed/detail/filtered_queue.hpp   (contents, props changed)
   trunk/boost/graph/distributed/detail/mpi_process_group.tpp   (contents, props changed)
   trunk/boost/graph/distributed/detail/queue.cpp   (contents, props changed)
   trunk/boost/graph/distributed/detail/remote_update_set.hpp   (contents, props changed)
   trunk/boost/graph/distributed/detail/tag_allocator.hpp   (contents, props changed)
   trunk/boost/graph/distributed/dijkstra_shortest_paths.hpp   (contents, props changed)
   trunk/boost/graph/distributed/distributed_graph_utility.hpp   (contents, props changed)
   trunk/boost/graph/distributed/eager_dijkstra_shortest_paths.hpp   (contents, props changed)
   trunk/boost/graph/distributed/filtered_graph.hpp   (contents, props changed)
   trunk/boost/graph/distributed/fruchterman_reingold.hpp   (contents, props changed)
   trunk/boost/graph/distributed/graphviz.hpp   (contents, props changed)
   trunk/boost/graph/distributed/hohberg_biconnected_components.hpp   (contents, props changed)
   trunk/boost/graph/distributed/local_subgraph.hpp   (contents, props changed)
   trunk/boost/graph/distributed/mpi_process_group.hpp   (contents, props changed)
   trunk/boost/graph/distributed/named_graph.hpp   (contents, props changed)
   trunk/boost/graph/distributed/page_rank.hpp   (contents, props changed)
   trunk/boost/graph/distributed/queue.hpp   (contents, props changed)
   trunk/boost/graph/distributed/reverse_graph.hpp   (contents, props changed)
   trunk/boost/graph/distributed/rmat_graph_generator.hpp   (contents, props changed)
   trunk/boost/graph/distributed/selector.hpp   (contents, props changed)
   trunk/boost/graph/distributed/shuffled_distribution.hpp   (contents, props changed)
   trunk/boost/graph/distributed/st_connected.hpp   (contents, props changed)
   trunk/boost/graph/distributed/strong_components.hpp   (contents, props changed)
   trunk/boost/graph/distributed/two_bit_color_map.hpp   (contents, props changed)
   trunk/boost/graph/distributed/unsafe_serialize.hpp   (contents, props changed)
   trunk/boost/graph/distributed/vertex_list_adaptor.hpp   (contents, props changed)
   trunk/boost/graph/parallel/
   trunk/boost/graph/parallel/algorithm.hpp   (contents, props changed)
   trunk/boost/graph/parallel/basic_reduce.hpp   (contents, props changed)
   trunk/boost/graph/parallel/container_traits.hpp   (contents, props changed)
   trunk/boost/graph/parallel/detail/
   trunk/boost/graph/parallel/detail/inplace_all_to_all.hpp   (contents, props changed)
   trunk/boost/graph/parallel/detail/property_holders.hpp   (contents, props changed)
   trunk/boost/graph/parallel/detail/untracked_pair.hpp   (contents, props changed)
   trunk/boost/graph/parallel/distribution.hpp   (contents, props changed)
   trunk/boost/graph/parallel/process_group.hpp   (contents, props changed)
   trunk/boost/graph/parallel/properties.hpp   (contents, props changed)
   trunk/boost/graph/parallel/simple_trigger.hpp   (contents, props changed)
   trunk/boost/graph/use_mpi.hpp   (contents, props changed)
   trunk/libs/graph/src/mpi_process_group.cpp   (contents, props changed)
   trunk/libs/graph/src/tag_allocator.cpp   (contents, props changed)
Text files modified: 
   trunk/boost/graph/breadth_first_search.hpp    |    21 ++++++++++++++++++++                    
   trunk/boost/graph/connected_components.hpp    |     3 ++                                      
   trunk/boost/graph/depth_first_search.hpp      |     3 ++                                      
   trunk/boost/graph/dijkstra_shortest_paths.hpp |     4 +++                                     
   trunk/boost/graph/fruchterman_reingold.hpp    |     4 +++                                     
   trunk/boost/graph/graphviz.hpp                |     4 +++                                     
   trunk/boost/graph/page_rank.hpp               |     4 +++                                     
   trunk/boost/graph/rmat_graph_generator.hpp    |     4 +++                                     
   trunk/boost/graph/strong_components.hpp       |     4 +++                                     
   trunk/boost/graph/topology.hpp                |    21 ++++++++++++++++++++                    
   trunk/boost/graph/two_bit_color_map.hpp       |     4 +++                                     
   trunk/boost/pending/property_serialize.hpp    |    42 ++++++++++++++++++++++++++++++++++++++++
   trunk/libs/graph/build/Jamfile.v2             |    27 ++++++++++++++++++++++++                
   13 files changed, 144 insertions(+), 1 deletions(-)
Modified: trunk/boost/graph/breadth_first_search.hpp
==============================================================================
--- trunk/boost/graph/breadth_first_search.hpp	(original)
+++ trunk/boost/graph/breadth_first_search.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -25,6 +25,10 @@
 #include <boost/graph/graph_concepts.hpp>
 #include <boost/graph/two_bit_color_map.hpp>
 
+#ifdef BOOST_GRAPH_USE_MPI
+#include <boost/graph/distributed/concepts.hpp>
+#endif // BOOST_GRAPH_USE_MPI
+
 namespace boost {
 
   template <class Visitor, class Graph>
@@ -230,6 +234,19 @@
          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
@@ -329,5 +346,9 @@
 
 } // namespace boost
 
+#ifdef BOOST_GRAPH_USE_MPI
+#  include <boost/graph/distributed/breadth_first_search.hpp>
+#endif
+
 #endif // BOOST_GRAPH_BREADTH_FIRST_SEARCH_HPP
 
Modified: trunk/boost/graph/connected_components.hpp
==============================================================================
--- trunk/boost/graph/connected_components.hpp	(original)
+++ trunk/boost/graph/connected_components.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -99,5 +99,8 @@
   
 } // namespace boost
 
+#ifdef BOOST_GRAPH_USE_MPI
+#  include <boost/graph/distributed/connected_components.hpp>
+#endif
 
 #endif // BOOST_GRAPH_CONNECTED_COMPONENTS_HPP
Modified: trunk/boost/graph/depth_first_search.hpp
==============================================================================
--- trunk/boost/graph/depth_first_search.hpp	(original)
+++ trunk/boost/graph/depth_first_search.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -358,5 +358,8 @@
   }
 } // namespace boost
 
+#ifdef BOOST_GRAPH_USE_MPI
+#  include <boost/graph/distributed/depth_first_search.hpp>
+#endif
 
 #endif
Modified: trunk/boost/graph/dijkstra_shortest_paths.hpp
==============================================================================
--- trunk/boost/graph/dijkstra_shortest_paths.hpp	(original)
+++ trunk/boost/graph/dijkstra_shortest_paths.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -480,4 +480,8 @@
 
 } // namespace boost
 
+#ifdef BOOST_GRAPH_USE_MPI
+#  include <boost/graph/distributed/dijkstra_shortest_paths.hpp>
+#endif
+
 #endif // BOOST_GRAPH_DIJKSTRA_HPP
Added: trunk/boost/graph/distributed/adjacency_list.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/distributed/adjacency_list.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -0,0 +1,3963 @@
+// Copyright (C) 2004-2006 The Trustees of Indiana University.
+// 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)
+
+//  Authors: Douglas Gregor
+//           Andrew Lumsdaine
+
+#ifndef BOOST_GRAPH_DISTRIBUTED_ADJACENCY_LIST_HPP
+#define BOOST_GRAPH_DISTRIBUTED_ADJACENCY_LIST_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/adjacency_list.hpp>
+#include <boost/graph/properties.hpp>
+#include <boost/graph/graph_traits.hpp>
+#include <boost/graph/iteration_macros.hpp>
+#include <boost/graph/distributed/concepts.hpp>
+#include <boost/iterator/transform_iterator.hpp>
+#include <boost/property_map/property_map.hpp>
+#include <boost/graph/adjacency_iterator.hpp>
+#include <boost/property_map/parallel/distributed_property_map.hpp>
+#include <boost/property_map/parallel/local_property_map.hpp>
+#include <boost/graph/parallel/detail/property_holders.hpp>
+#include <boost/mpl/if.hpp>
+#include <boost/type_traits/is_same.hpp>
+#include <cassert>
+#include <list>
+#include <algorithm>
+#include <boost/limits.hpp>
+#include <boost/graph/parallel/properties.hpp>
+#include <boost/graph/parallel/distribution.hpp>
+#include <boost/graph/parallel/algorithm.hpp>
+#include <boost/graph/distributed/selector.hpp>
+#include <boost/graph/parallel/process_group.hpp>
+
+// Callbacks
+#include <boost/function/function2.hpp>
+
+// Serialization
+#include <boost/serialization/base_object.hpp>
+#include <boost/mpi/datatype.hpp>
+#include <boost/pending/property_serialize.hpp>
+#include <boost/graph/distributed/unsafe_serialize.hpp>
+
+// Named vertices
+#include <boost/graph/distributed/named_graph.hpp>
+
+#include <boost/graph/distributed/shuffled_distribution.hpp>
+
+namespace boost {
+
+  /// The type used to store an identifier that uniquely names a processor.
+  // NGE: I doubt we'll be running on more than 32768 procs for the time being
+  typedef /*int*/ short processor_id_type;
+
+  // Tell which processor the target of an edge resides on (for
+  // directed graphs) or which processor the other end point of the
+  // edge resides on (for undirected graphs).
+  enum edge_target_processor_id_t { edge_target_processor_id };
+  BOOST_INSTALL_PROPERTY(edge, target_processor_id);
+
+  // For undirected graphs, tells whether the edge is locally owned.
+  enum edge_locally_owned_t { edge_locally_owned };
+  BOOST_INSTALL_PROPERTY(edge, locally_owned);
+
+  // For bidirectional graphs, stores the incoming edges.
+  enum vertex_in_edges_t { vertex_in_edges };
+  BOOST_INSTALL_PROPERTY(vertex, in_edges);
+
+  /// Tag class for directed, distributed adjacency list
+  struct directed_distributed_adj_list_tag
+    : public virtual distributed_graph_tag,
+      public virtual distributed_vertex_list_graph_tag,
+      public virtual distributed_edge_list_graph_tag,
+      public virtual incidence_graph_tag,
+      public virtual adjacency_graph_tag {};
+
+  /// Tag class for bidirectional, distributed adjacency list
+  struct bidirectional_distributed_adj_list_tag
+    : public virtual distributed_graph_tag,
+      public virtual distributed_vertex_list_graph_tag,
+      public virtual distributed_edge_list_graph_tag,
+      public virtual incidence_graph_tag,
+      public virtual adjacency_graph_tag,
+      public virtual bidirectional_graph_tag {};
+
+  /// Tag class for undirected, distributed adjacency list
+  struct undirected_distributed_adj_list_tag
+    : public virtual distributed_graph_tag,
+      public virtual distributed_vertex_list_graph_tag,
+      public virtual distributed_edge_list_graph_tag,
+      public virtual incidence_graph_tag,
+      public virtual adjacency_graph_tag,
+      public virtual bidirectional_graph_tag {};
+
+  namespace detail {
+    template<typename Archiver, typename Directed, typename Vertex>
+    void
+    serialize(Archiver& ar, edge_base<Directed, Vertex>& e,
+              const unsigned int /*version*/)
+    {
+      ar & unsafe_serialize(e.m_source)
+         & unsafe_serialize(e.m_target);
+    }
+
+    template<typename Archiver, typename Directed, typename Vertex>
+    void
+    serialize(Archiver& ar, edge_desc_impl<Directed, Vertex>& e,
+              const unsigned int /*version*/)
+    {
+      ar & boost::serialization::base_object<edge_base<Directed, Vertex> >(e)
+         & unsafe_serialize(e.m_eproperty);
+    }
+  }
+
+  namespace detail { namespace parallel {
+  
+    /**
+     * A distributed vertex descriptor. These descriptors contain both
+     * the ID of the processor that owns the vertex and a local vertex
+     * descriptor that identifies the particular vertex for that
+     * processor.
+     */
+    template<typename LocalDescriptor>
+    struct global_descriptor
+    {
+      typedef LocalDescriptor local_descriptor_type;
+
+      global_descriptor() : owner(), local() { }
+
+      global_descriptor(processor_id_type owner, LocalDescriptor local)
+        : owner(owner), local(local) { }
+
+      processor_id_type owner;
+      LocalDescriptor local;
+
+      /**
+       * A function object that, given a processor ID, generates
+       * distributed vertex descriptors from local vertex
+       * descriptors. This function object is used by the
+       * vertex_iterator of the distributed adjacency list.
+       */
+      struct generator
+      {
+        typedef global_descriptor<LocalDescriptor> result_type;
+        typedef LocalDescriptor argument_type;
+
+        generator() {}
+        generator(processor_id_type owner) : owner(owner) {}
+
+        result_type operator()(argument_type v) const
+        { return result_type(owner, v); }
+
+      private:
+        processor_id_type owner;
+      };
+
+      template<typename Archiver>
+      void serialize(Archiver& ar, const unsigned int /*version*/)
+      {
+        ar & owner & unsafe_serialize(local);
+      }
+    };
+
+    /// Determine the process that owns the given descriptor
+    template<typename LocalDescriptor>
+    inline processor_id_type owner(const global_descriptor<LocalDescriptor>& v)
+    { return v.owner; }
+
+    /// Determine the local portion of the given descriptor
+    template<typename LocalDescriptor>
+    inline LocalDescriptor local(const global_descriptor<LocalDescriptor>& v)
+    { return v.local; }
+
+    /// Compare distributed vertex descriptors for equality
+    template<typename LocalDescriptor>
+    inline bool
+    operator==(const global_descriptor<LocalDescriptor>& u,
+               const global_descriptor<LocalDescriptor>& v)
+    {
+      return u.owner == v.owner && u.local == v.local;
+    }
+
+    /// Compare distributed vertex descriptors for inequality
+    template<typename LocalDescriptor>
+    inline bool
+    operator!=(const global_descriptor<LocalDescriptor>& u,
+               const global_descriptor<LocalDescriptor>& v)
+    { return !(u == v); }
+
+    template<typename LocalDescriptor>
+    inline bool
+    operator<(const global_descriptor<LocalDescriptor>& u,
+              const global_descriptor<LocalDescriptor>& v)
+    {
+      return (u.owner) < v.owner || (u.owner == v.owner && (u.local) < v.local);
+    }
+
+    template<typename LocalDescriptor>
+    inline bool
+    operator<=(const global_descriptor<LocalDescriptor>& u,
+               const global_descriptor<LocalDescriptor>& v)
+    {
+      return u.owner <= v.owner || (u.owner == v.owner && u.local <= v.local);
+    }
+
+    template<typename LocalDescriptor>
+    inline bool
+    operator>(const global_descriptor<LocalDescriptor>& u,
+              const global_descriptor<LocalDescriptor>& v)
+    {
+      return v < u;
+    }
+
+    template<typename LocalDescriptor>
+    inline bool
+    operator>=(const global_descriptor<LocalDescriptor>& u,
+               const global_descriptor<LocalDescriptor>& v)
+    {
+      return v <= u;
+    }
+
+    // DPG TBD: Add <, <=, >=, > for global descriptors
+
+    /**
+     * A Readable Property Map that extracts a global descriptor pair
+     * from a global_descriptor.
+     */
+    template<typename LocalDescriptor>
+    struct global_descriptor_property_map
+    {
+      typedef std::pair<processor_id_type, LocalDescriptor> value_type;
+      typedef value_type reference;
+      typedef global_descriptor<LocalDescriptor> key_type;
+      typedef readable_property_map_tag category;
+    };
+
+    template<typename LocalDescriptor>
+    inline std::pair<processor_id_type, LocalDescriptor>
+    get(global_descriptor_property_map<LocalDescriptor>,
+        global_descriptor<LocalDescriptor> x)
+    {
+      return std::pair<processor_id_type, LocalDescriptor>(x.owner, x.local);
+    }
+
+    /**
+     * A Readable Property Map that extracts the owner of a global
+     * descriptor.
+     */
+    template<typename LocalDescriptor>
+    struct owner_property_map
+    {
+      typedef processor_id_type value_type;
+      typedef value_type reference;
+      typedef global_descriptor<LocalDescriptor> key_type;
+      typedef readable_property_map_tag category;
+    };
+
+    template<typename LocalDescriptor>
+    inline processor_id_type
+    get(owner_property_map<LocalDescriptor>,
+        global_descriptor<LocalDescriptor> x)
+    {
+      return x.owner;
+    }
+
+    /**
+     * A Readable Property Map that extracts the local descriptor from
+     * a global descriptor.
+     */
+    template<typename LocalDescriptor>
+    struct local_descriptor_property_map
+    {
+      typedef LocalDescriptor value_type;
+      typedef value_type reference;
+      typedef global_descriptor<LocalDescriptor> key_type;
+      typedef readable_property_map_tag category;
+    };
+
+    template<typename LocalDescriptor>
+    inline LocalDescriptor
+    get(local_descriptor_property_map<LocalDescriptor>,
+        global_descriptor<LocalDescriptor> x)
+    {
+      return x.local;
+    }
+
+    /**
+     * Stores an incoming edge for a bidirectional distributed
+     * adjacency list. The user does not see this type directly,
+     * because it is just an implementation detail.
+     */
+    template<typename Edge>
+    struct stored_in_edge
+    {
+      stored_in_edge(processor_id_type sp, Edge e)
+        : source_processor(sp), e(e) {}
+
+      processor_id_type source_processor;
+      Edge e;
+    };
+
+    /**
+     * A distributed edge descriptor. These descriptors contain the
+     * underlying edge descriptor, the processor IDs for both the
+     * source and the target of the edge, and a boolean flag that
+     * indicates which of the processors actually owns the edge.
+     */
+    template<typename Edge>
+    struct edge_descriptor
+    {
+      edge_descriptor(processor_id_type sp = processor_id_type(),
+                      processor_id_type tp = processor_id_type(),
+                      bool owns = false, Edge ld = Edge())
+        : source_processor(sp), target_processor(tp),
+          source_owns_edge(owns), local(ld) {}
+
+      processor_id_type owner() const
+      {
+        return source_owns_edge? source_processor : target_processor;
+      }
+
+      /// The processor that the source vertex resides on
+      processor_id_type source_processor;
+
+      /// The processor that the target vertex resides on
+      processor_id_type target_processor;
+
+      /// True when the source processor owns the edge, false when the
+      /// target processor owns the edge.
+      bool source_owns_edge;
+
+      /// The local edge descriptor.
+      Edge local;
+
+      /**
+       * Function object that generates edge descriptors for the
+       * out_edge_iterator of the given distributed adjacency list
+       * from the edge descriptors of the underlying adjacency list.
+       */
+      template<typename Graph>
+      class out_generator
+      {
+        typedef typename Graph::directed_selector directed_selector;
+
+      public:
+        typedef edge_descriptor<Edge> result_type;
+        typedef Edge argument_type;
+
+        out_generator() : g(0) {}
+        explicit out_generator(const Graph& g) : g(&g) {}
+
+        result_type operator()(argument_type e) const
+        { return map(e, directed_selector()); }
+
+      private:
+        result_type map(argument_type e, directedS) const
+        {
+          return result_type(g->processor(),
+                             get(edge_target_processor_id, g->base(), e),
+                             true, e);
+        }
+
+        result_type map(argument_type e, bidirectionalS) const
+        {
+          return result_type(g->processor(),
+                             get(edge_target_processor_id, g->base(), e),
+                             true, e);
+        }
+
+        result_type map(argument_type e, undirectedS) const
+        {
+          return result_type(g->processor(),
+                             get(edge_target_processor_id, g->base(), e),
+                             get(edge_locally_owned, g->base(), e),
+                             e);
+        }
+
+        const Graph* g;
+      };
+
+      /**
+       * Function object that generates edge descriptors for the
+       * in_edge_iterator of the given distributed adjacency list
+       * from the edge descriptors of the underlying adjacency list.
+       */
+      template<typename Graph>
+      class in_generator
+      {
+        typedef typename Graph::directed_selector DirectedS;
+
+      public:
+        typedef typename ct_if<(is_same<DirectedS, bidirectionalS>::value),
+                               stored_in_edge<Edge>,
+                               Edge>::type argument_type;
+        typedef edge_descriptor<Edge> result_type;
+
+        in_generator() : g(0) {}
+        explicit in_generator(const Graph& g) : g(&g) {}
+
+        result_type operator()(argument_type e) const
+        { return map(e, DirectedS()); }
+
+      private:
+        /**
+         * For a bidirectional graph, we just generate the appropriate
+         * edge. No tricks.
+         */
+        result_type map(argument_type e, bidirectionalS) const
+        {
+          return result_type(e.source_processor,
+                             g->processor(),
+                             true,
+                             e.e);
+        }
+
+        /**
+         * For an undirected graph, we generate descriptors for the
+         * incoming edges by swapping the source/target of the
+         * underlying edge descriptor (a hack). The target processor
+         * ID on the edge is actually the source processor for this
+         * edge, and our processor is the target processor. If the
+         * edge is locally owned, then it is owned by the target (us);
+         * otherwise it is owned by the source.
+         */
+        result_type map(argument_type e, undirectedS) const
+        {
+          typename Graph::local_edge_descriptor local_edge(e);
+          // TBD: This is a very, VERY lame hack that takes advantage
+          // of our knowledge of the internals of the BGL
+          // adjacency_list. There should be a cleaner way to handle
+          // this...
+          using std::swap;
+          swap(local_edge.m_source, local_edge.m_target);
+          return result_type(get(edge_target_processor_id, g->base(), e),
+                             g->processor(),
+                             !get(edge_locally_owned, g->base(), e),
+                             local_edge);
+        }
+
+        const Graph* g;
+      };
+
+    private:
+      friend class boost::serialization::access;
+
+      template<typename Archiver>
+      void serialize(Archiver& ar, const unsigned int /*version*/)
+      {
+        ar
+          & source_processor
+          & target_processor
+          & source_owns_edge
+          & local;
+      }
+    };
+
+    /// Determine the process that owns this edge
+    template<typename Edge>
+    inline processor_id_type
+    owner(const edge_descriptor<Edge>& e)
+    { return e.source_owns_edge? e.source_processor : e.target_processor; }
+
+    /// Determine the local descriptor for this edge.
+    template<typename Edge>
+    inline Edge
+    local(const edge_descriptor<Edge>& e)
+    { return e.local; }
+
+    /**
+     * A Readable Property Map that extracts the owner and local
+     * descriptor of an edge descriptor.
+     */
+    template<typename Edge>
+    struct edge_global_property_map
+    {
+      typedef std::pair<processor_id_type, Edge> value_type;
+      typedef value_type reference;
+      typedef edge_descriptor<Edge> key_type;
+      typedef readable_property_map_tag category;
+    };
+
+    template<typename Edge>
+    inline std::pair<processor_id_type, Edge>
+    get(edge_global_property_map<Edge>, const edge_descriptor<Edge>& e)
+    {
+      typedef std::pair<processor_id_type, Edge> result_type;
+      return result_type(e.source_owns_edge? e.source_processor
+                         /* target owns edge*/: e.target_processor,
+                         e.local);
+    }
+
+    /**
+     * A Readable Property Map that extracts the owner of an edge
+     * descriptor.
+     */
+    template<typename Edge>
+    struct edge_owner_property_map
+    {
+      typedef processor_id_type value_type;
+      typedef value_type reference;
+      typedef edge_descriptor<Edge> key_type;
+      typedef readable_property_map_tag category;
+    };
+
+    template<typename Edge>
+    inline processor_id_type
+    get(edge_owner_property_map<Edge>, const edge_descriptor<Edge>& e)
+    {
+      return e.source_owns_edge? e.source_processor : e.target_processor;
+    }
+
+    /**
+     * A Readable Property Map that extracts the local descriptor from
+     * an edge descriptor.
+     */
+    template<typename Edge>
+    struct edge_local_property_map
+    {
+      typedef Edge value_type;
+      typedef value_type reference;
+      typedef edge_descriptor<Edge> key_type;
+      typedef readable_property_map_tag category;
+    };
+
+    template<typename Edge>
+    inline Edge
+    get(edge_local_property_map<Edge>,
+        const edge_descriptor<Edge>& e)
+    {
+      return e.local;
+    }
+
+    /** Compare distributed edge descriptors for equality.
+     *
+     * \todo need edge_descriptor to know if it is undirected so we
+     * can compare both ways.
+     */
+    template<typename Edge>
+    inline bool
+    operator==(const edge_descriptor<Edge>& e1,
+               const edge_descriptor<Edge>& e2)
+    {
+      return (e1.source_processor == e2.source_processor
+              && e1.target_processor == e2.target_processor
+              && e1.local == e2.local);
+    }
+
+    /// Compare distributed edge descriptors for inequality.
+    template<typename Edge>
+    inline bool
+    operator!=(const edge_descriptor<Edge>& e1,
+               const edge_descriptor<Edge>& e2)
+    { return !(e1 == e2); }
+
+    /**
+     * Configuration for the distributed adjacency list. We use this
+     * parameter to store all of the configuration details for the
+     * implementation of the distributed adjacency list, which allows us to
+     * get at the distribution type in the maybe_named_graph.
+     */
+    template<typename OutEdgeListS, typename ProcessGroup,
+             typename InVertexListS, typename InDistribution,
+             typename DirectedS, typename VertexProperty, 
+             typename EdgeProperty, typename GraphProperty, 
+             typename EdgeListS>
+    struct adjacency_list_config
+    {
+      typedef typename mpl::if_<is_same<InVertexListS, defaultS>, 
+                                vecS, InVertexListS>::type 
+        VertexListS;
+
+      /// Introduce the target processor ID property for each edge
+      typedef property<edge_target_processor_id_t, processor_id_type,
+                       EdgeProperty> edge_property_with_id;
+
+      /// For undirected graphs, introduce the locally-owned property for edges
+      typedef typename ct_if<(is_same<DirectedS, undirectedS>::value),
+                             property<edge_locally_owned_t, bool,
+                                      edge_property_with_id>,
+                             edge_property_with_id>::type
+        base_edge_property_type;
+
+      /// The edge descriptor type for the local subgraph
+      typedef typename adjacency_list_traits<OutEdgeListS,
+                                             VertexListS,
+                                             directedS>::edge_descriptor
+        local_edge_descriptor;
+
+      /// For bidirectional graphs, the type of an incoming stored edge
+      typedef stored_in_edge<local_edge_descriptor> bidir_stored_edge;
+
+      /// The container type that will store incoming edges for a
+      /// bidirectional graph.
+      typedef typename container_gen<EdgeListS, bidir_stored_edge>::type
+        in_edge_list_type;
+
+      // Bidirectional graphs have an extra vertex property to store
+      // the incoming edges.
+      typedef typename ct_if<(is_same<DirectedS, bidirectionalS>::value),
+                             property<vertex_in_edges_t, in_edge_list_type,
+                                      VertexProperty>,
+                             VertexProperty>::type 
+        base_vertex_property_type;
+
+      // The type of the distributed adjacency list
+      typedef adjacency_list<OutEdgeListS,
+                             distributedS<ProcessGroup, 
+                                          VertexListS, 
+                                          InDistribution>,
+                             DirectedS, VertexProperty, EdgeProperty,
+                             GraphProperty, EdgeListS> 
+        graph_type;
+
+      // The type of the underlying adjacency list implementation
+      typedef adjacency_list<OutEdgeListS, VertexListS, directedS,
+                             base_vertex_property_type,
+                             base_edge_property_type,
+                             GraphProperty,
+                             EdgeListS> 
+        inherited;
+      
+      typedef InDistribution in_distribution_type;
+      typedef typename inherited::vertices_size_type vertices_size_type;
+
+          typedef typename ::boost::graph::distributed::select_distribution<
+              in_distribution_type, VertexProperty, vertices_size_type, 
+              ProcessGroup>::type 
+        base_distribution_type;
+
+          typedef ::boost::graph::distributed::shuffled_distribution<
+          base_distribution_type> distribution_type;
+
+      typedef VertexProperty vertex_property_type;
+      typedef EdgeProperty edge_property_type;
+      typedef ProcessGroup process_group_type;
+
+      typedef VertexListS vertex_list_selector;
+      typedef OutEdgeListS out_edge_list_selector;
+      typedef DirectedS directed_selector;
+      typedef GraphProperty graph_property_type;
+      typedef EdgeListS edge_list_selector;
+    };
+
+    // Maybe initialize the indices of each vertex
+    template<typename IteratorPair, typename VertexIndexMap>
+    void
+    maybe_initialize_vertex_indices(IteratorPair p, VertexIndexMap to_index,
+                                    read_write_property_map_tag)
+    {
+      typedef typename property_traits<VertexIndexMap>::value_type index_t;
+      index_t next_index = 0;
+      while (p.first != p.second)
+        put(to_index, *p.first++, next_index++);
+    }
+
+    template<typename IteratorPair, typename VertexIndexMap>
+    inline void
+    maybe_initialize_vertex_indices(IteratorPair p, VertexIndexMap to_index,
+                                    readable_property_map_tag)
+    {
+      // Do nothing
+    }
+
+    template<typename IteratorPair, typename VertexIndexMap>
+    inline void
+    maybe_initialize_vertex_indices(IteratorPair p, VertexIndexMap to_index)
+    {
+      typedef typename property_traits<VertexIndexMap>::category category;
+      maybe_initialize_vertex_indices(p, to_index, category());
+    }
+
+    template<typename IteratorPair>
+    inline void
+    maybe_initialize_vertex_indices(IteratorPair p,
+                                    ::boost::detail::error_property_not_found)
+    { }
+
+    /***********************************************************************
+     * Message Payloads                                                    *
+     ***********************************************************************/
+
+    /**
+     * Data stored with a msg_add_edge message, which requests the
+     * remote addition of an edge.
+     */
+    template<typename Vertex, typename LocalVertex>
+    struct msg_add_edge_data
+    {
+      msg_add_edge_data() { }
+
+      msg_add_edge_data(Vertex source, Vertex target)
+        : source(source.local), target(target) { }
+
+      /// The source of the edge; the processor will be the
+      /// receiving processor.
+      LocalVertex source;
+        
+      /// The target of the edge.
+      Vertex target;
+        
+      template<typename Archiver>
+      void serialize(Archiver& ar, const unsigned int /*version*/)
+      {
+        ar & unsafe_serialize(source) & target;
+      }
+    };
+
+    /**
+     * Like @c msg_add_edge_data, but also includes a user-specified
+     * property value to be attached to the edge.
+     */
+    template<typename Vertex, typename LocalVertex, typename EdgeProperty>
+    struct msg_add_edge_with_property_data
+      : msg_add_edge_data<Vertex, LocalVertex>, 
+        maybe_store_property<EdgeProperty>
+    {
+    private:
+      typedef msg_add_edge_data<Vertex, LocalVertex> inherited_data;
+      typedef maybe_store_property<EdgeProperty> inherited_property;
+
+    public:
+      msg_add_edge_with_property_data() { }
+
+      msg_add_edge_with_property_data(Vertex source, 
+                                      Vertex target,
+                                      const EdgeProperty& property)
+        : inherited_data(source, target),
+          inherited_property(property) { }
+      
+      template<typename Archiver>
+      void serialize(Archiver& ar, const unsigned int /*version*/)
+      {
+        ar & boost::serialization::base_object<inherited_data>(*this) 
+           & boost::serialization::base_object<inherited_property>(*this);
+      }
+    };
+
+    //------------------------------------------------------------------------
+    // Distributed adjacency list property map details
+    /**
+     * Metafunction that extracts the given property from the given
+     * distributed adjacency list type. This could be implemented much
+     * more cleanly, but even newer versions of GCC (e.g., 3.2.3)
+     * cannot properly handle partial specializations involving
+     * enumerator types.
+     */
+    template<typename Property>
+    struct get_adj_list_pmap
+    {
+      template<typename Graph>
+      struct apply
+      {
+        typedef Graph graph_type;
+        typedef typename graph_type::process_group_type process_group_type;
+        typedef typename graph_type::inherited base_graph_type;
+        typedef typename property_map<base_graph_type, Property>::type
+          local_pmap;
+        typedef typename property_map<base_graph_type, Property>::const_type
+          local_const_pmap;
+
+        typedef graph_traits<graph_type> traits;
+        typedef typename graph_type::local_vertex_descriptor local_vertex;
+        typedef typename property_traits<local_pmap>::key_type local_key_type;
+
+        typedef typename property_traits<local_pmap>::value_type value_type;
+
+        typedef typename property_map<Graph, vertex_global_t>::const_type
+          vertex_global_map;
+        typedef typename property_map<Graph, edge_global_t>::const_type
+          edge_global_map;
+
+        typedef typename mpl::if_c<(is_same<local_key_type,
+                                            local_vertex>::value),
+                                   vertex_global_map, edge_global_map>::type
+          global_map;
+
+      public:
+        typedef ::boost::parallel::distributed_property_map<
+                  process_group_type, global_map, local_pmap> type;
+
+        typedef ::boost::parallel::distributed_property_map<
+                  process_group_type, global_map, local_const_pmap> const_type;
+      };
+    };
+
+    /**
+     * The local vertex index property map is actually a mapping from
+     * the local vertex descriptors to vertex indices.
+     */
+    template<>
+    struct get_adj_list_pmap<vertex_local_index_t>
+    {
+      template<typename Graph>
+      struct apply
+        : ::boost::property_map<typename Graph::inherited, vertex_index_t>
+      { };
+    };
+
+    /**
+     * The vertex index property map maps from global descriptors
+     * (e.g., the vertex descriptor of a distributed adjacency list)
+     * to the underlying local index. It is not valid to use this
+     * property map with nonlocal descriptors.
+     */
+    template<>
+    struct get_adj_list_pmap<vertex_index_t>
+    {
+      template<typename Graph>
+      struct apply
+      {
+      private:
+        typedef typename property_map<Graph, vertex_global_t>::const_type
+          global_map;
+
+        typedef property_map<typename Graph::inherited, vertex_index_t> local;
+
+      public:
+        typedef local_property_map<typename Graph::process_group_type,
+                                   global_map,
+                                   typename local::type> type;
+        typedef local_property_map<typename Graph::process_group_type,
+                                   global_map,
+                                   typename local::const_type> const_type;
+      };
+    };
+
+    /**
+     * The vertex owner property map maps from vertex descriptors to
+     * the processor that owns the vertex.
+     */
+    template<>
+    struct get_adj_list_pmap<vertex_global_t>
+    {
+      template<typename Graph>
+      struct apply
+      {
+      private:
+        typedef typename Graph::local_vertex_descriptor
+          local_vertex_descriptor;
+      public:
+        typedef global_descriptor_property_map<local_vertex_descriptor> type;
+        typedef type const_type;
+      };
+    };
+
+    /**
+     * The vertex owner property map maps from vertex descriptors to
+     * the processor that owns the vertex.
+     */
+    template<>
+    struct get_adj_list_pmap<vertex_owner_t>
+    {
+      template<typename Graph>
+      struct apply
+      {
+      private:
+        typedef typename Graph::local_vertex_descriptor
+          local_vertex_descriptor;
+      public:
+        typedef owner_property_map<local_vertex_descriptor> type;
+        typedef type const_type;
+      };
+    };
+
+    /**
+     * The vertex local property map maps from vertex descriptors to
+     * the local descriptor for that vertex.
+     */
+    template<>
+    struct get_adj_list_pmap<vertex_local_t>
+    {
+      template<typename Graph>
+      struct apply
+      {
+      private:
+        typedef typename Graph::local_vertex_descriptor
+          local_vertex_descriptor;
+      public:
+        typedef local_descriptor_property_map<local_vertex_descriptor> type;
+        typedef type const_type;
+      };
+    };
+
+    /**
+     * The edge global property map maps from edge descriptors to
+     * a pair of the owning processor and local descriptor.
+     */
+    template<>
+    struct get_adj_list_pmap<edge_global_t>
+    {
+      template<typename Graph>
+      struct apply
+      {
+      private:
+        typedef typename Graph::local_edge_descriptor
+          local_edge_descriptor;
+      public:
+        typedef edge_global_property_map<local_edge_descriptor> type;
+        typedef type const_type;
+      };
+    };
+
+    /**
+     * The edge owner property map maps from edge descriptors to
+     * the processor that owns the edge.
+     */
+    template<>
+    struct get_adj_list_pmap<edge_owner_t>
+    {
+      template<typename Graph>
+      struct apply
+      {
+      private:
+        typedef typename Graph::local_edge_descriptor
+          local_edge_descriptor;
+      public:
+        typedef edge_owner_property_map<local_edge_descriptor> type;
+        typedef type const_type;
+      };
+    };
+
+    /**
+     * The edge local property map maps from edge descriptors to
+     * the local descriptor for that edge.
+     */
+    template<>
+    struct get_adj_list_pmap<edge_local_t>
+    {
+      template<typename Graph>
+      struct apply
+      {
+      private:
+        typedef typename Graph::local_edge_descriptor
+          local_edge_descriptor;
+      public:
+        typedef edge_local_property_map<local_edge_descriptor> type;
+        typedef type const_type;
+      };
+    };
+    //------------------------------------------------------------------------
+
+    // Directed graphs do not have in edges, so this is a no-op
+    template<typename Graph>
+    inline void
+    remove_in_edge(typename Graph::edge_descriptor, Graph&, directedS)
+    { }
+
+    // Bidirectional graphs have in edges stored in the
+    // vertex_in_edges property.
+    template<typename Graph>
+    inline void
+    remove_in_edge(typename Graph::edge_descriptor e, Graph& g, bidirectionalS)
+    {
+      typedef typename Graph::in_edge_list_type in_edge_list_type;
+      in_edge_list_type& in_edges =
+        get(vertex_in_edges, g.base())[target(e, g).local];
+      typename in_edge_list_type::iterator i = in_edges.begin();
+      while (i != in_edges.end()
+             && !(i->source_processor == source(e, g).owner)
+             && i->e == e.local)
+        ++i;
+
+      assert(i != in_edges.end());
+      in_edges.erase(i);
+    }
+
+    // Undirected graphs have in edges stored as normal edges.
+    template<typename Graph>
+    inline void
+    remove_in_edge(typename Graph::edge_descriptor e, Graph& g, undirectedS)
+    {
+      typedef typename Graph::inherited base_type;
+      typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
+
+      // TBD: can we make this more efficient?
+      // Removing edge (v, u). v is local
+      base_type& bg = g.base();
+      vertex_descriptor u = source(e, g);
+      vertex_descriptor v = target(e, g);
+      if (v.owner != process_id(g.process_group())) {
+        using std::swap;
+        swap(u, v);
+      }
+
+      typename graph_traits<base_type>::out_edge_iterator ei, ei_end;
+      for (tie(ei, ei_end) = out_edges(v.local, bg); ei != ei_end; ++ei)
+      {
+        if (target(*ei, g.base()) == u.local
+            // TBD: deal with parallel edges properly && *ei == e
+            && get(edge_target_processor_id, bg, *ei) == u.owner) {
+          remove_edge(ei, bg);
+          return;
+        }
+      }
+
+      if (v.owner == process_id(g.process_group())) {
+
+      }
+    }
+
+    //------------------------------------------------------------------------
+    // Lazy addition of edges
+
+    // Work around the fact that an adjacency_list with vecS vertex
+    // storage automatically adds edges when the descriptor is
+    // out-of-range.
+    template <class Graph, class Config, class Base>
+    inline std::pair<typename Config::edge_descriptor, bool>
+    add_local_edge(typename Config::vertex_descriptor u,
+                   typename Config::vertex_descriptor v,
+                   const typename Config::edge_property_type& p,
+                   vec_adj_list_impl<Graph, Config, Base>& g_)
+    {
+      adj_list_helper<Config, Base>& g = g_;
+      return add_edge(u, v, p, g);
+    }
+
+    template <class Graph, class Config, class Base>
+    inline std::pair<typename Config::edge_descriptor, bool>
+    add_local_edge(typename Config::vertex_descriptor u,
+                   typename Config::vertex_descriptor v,
+                   const typename Config::edge_property_type& p,
+                   boost::adj_list_impl<Graph, Config, Base>& g)
+    {
+      return add_edge(u, v, p, g);
+    }
+
+    template <class EdgeProperty,class EdgeDescriptor>
+    struct msg_nonlocal_edge_data
+      : public detail::parallel::maybe_store_property<EdgeProperty>
+    {
+      typedef EdgeProperty edge_property_type;
+      typedef EdgeDescriptor local_edge_descriptor;
+      typedef detail::parallel::maybe_store_property<edge_property_type> 
+        inherited;
+
+      msg_nonlocal_edge_data() {}
+      msg_nonlocal_edge_data(local_edge_descriptor e,
+                             const edge_property_type& p)
+        : inherited(p), e(e) { }
+
+      local_edge_descriptor e;
+
+      template<typename Archiver>
+      void serialize(Archiver& ar, const unsigned int /*version*/)
+      {
+        ar & boost::serialization::base_object<inherited>(*this) & e;
+      }
+    };
+
+    template <class EdgeDescriptor>
+    struct msg_remove_edge_data
+    {
+      typedef EdgeDescriptor edge_descriptor;
+      msg_remove_edge_data() {}
+      explicit msg_remove_edge_data(edge_descriptor e) : e(e) {}
+
+      edge_descriptor e;
+
+      template<typename Archiver>
+      void serialize(Archiver& ar, const unsigned int /*version*/)
+      {
+        ar & e;
+      }
+    };
+
+  } } // end namespace detail::parallel
+
+  /**
+   * Adjacency list traits for a distributed adjacency list. Contains
+   * the vertex and edge descriptors, the directed-ness, and the
+   * parallel edges typedefs.
+   */
+  template<typename OutEdgeListS, typename ProcessGroup,
+           typename InVertexListS, typename InDistribution, typename DirectedS>
+  struct adjacency_list_traits<OutEdgeListS,
+                               distributedS<ProcessGroup, 
+                                            InVertexListS,
+                                            InDistribution>,
+                               DirectedS>
+  {
+  private:
+    typedef typename mpl::if_<is_same<InVertexListS, defaultS>,
+                              vecS,
+                              InVertexListS>::type VertexListS;
+
+    typedef adjacency_list_traits<OutEdgeListS, VertexListS, directedS>
+      base_type;
+
+  public:
+    typedef typename base_type::vertex_descriptor local_vertex_descriptor;
+    typedef typename base_type::edge_descriptor   local_edge_descriptor;
+
+    typedef typename boost::ct_if_t<typename DirectedS::is_bidir_t,
+      bidirectional_tag,
+      typename boost::ct_if_t<typename DirectedS::is_directed_t,
+        directed_tag, undirected_tag
+      >::type
+    >::type directed_category;
+
+    typedef typename parallel_edge_traits<OutEdgeListS>::type
+      edge_parallel_category;
+
+    typedef detail::parallel::global_descriptor<local_vertex_descriptor>
+      vertex_descriptor;
+
+    typedef detail::parallel::edge_descriptor<local_edge_descriptor>
+      edge_descriptor;
+  };
+
+#define PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS                                    \
+  typename OutEdgeListS, typename ProcessGroup, typename InVertexListS,        \
+  typename InDistribution, typename DirectedS, typename VertexProperty,        \
+  typename EdgeProperty,  typename GraphProperty, typename EdgeListS
+
+#define PBGL_DISTRIB_ADJLIST_TYPE                                              \
+  adjacency_list<OutEdgeListS,                                                 \
+                 distributedS<ProcessGroup, InVertexListS, InDistribution>,    \
+                 DirectedS, VertexProperty, EdgeProperty, GraphProperty,       \
+                 EdgeListS>
+
+#define PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG                             \
+  typename OutEdgeListS, typename ProcessGroup, typename InVertexListS,        \
+  typename InDistribution, typename VertexProperty,                            \
+  typename EdgeProperty,  typename GraphProperty, typename EdgeListS
+  
+#define PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(directed)                             \
+  adjacency_list<OutEdgeListS,                                                 \
+                 distributedS<ProcessGroup, InVertexListS, InDistribution>,    \
+                 directed, VertexProperty, EdgeProperty, GraphProperty,        \
+                 EdgeListS>
+                 
+  /** A distributed adjacency list.
+   *
+   * This class template partial specialization defines a distributed
+   * (or "partitioned") adjacency list graph. The distributed
+   * adjacency list is similar to the standard Boost Graph Library
+   * adjacency list, which stores a list of vertices and for each
+   * verted the list of edges outgoing from the vertex (and, in some
+   * cases, also the edges incoming to the vertex). The distributed
+   * adjacency list differs in that it partitions the graph into
+   * several subgraphs that are then divided among different
+   * processors (or nodes within a cluster). The distributed adjacency
+   * list attempts to maintain a high degree of compatibility with the
+   * standard, non-distributed adjacency list.
+   *
+   * The graph is partitioned by vertex, with each processor storing
+   * all of the required information for a particular subset of the
+   * vertices, including vertex properties, outgoing edges, and (for
+   * bidirectional graphs) incoming edges. This information is
+   * accessible only on the processor that owns the vertex: for
+   * instance, if processor 0 owns vertex @c v, no other processor can
+   * directly access the properties of @c v or enumerate its outgoing
+   * edges.
+   *
+   * Edges in a graph may be entirely local (connecting two local
+   * vertices), but more often it is the case that edges are
+   * non-local, meaning that the two vertices they connect reside in
+   * different processes. Edge properties are stored with the
+   * originating vertex for directed and bidirectional graphs, and are
+   * therefore only accessible from the processor that owns the
+   * originating vertex. Other processors may query the source and
+   * target of the edge, but cannot access its properties. This is
+   * particularly interesting when accessing the incoming edges of a
+   * bidirectional graph, which are not guaranteed to be stored on the
+   * processor that is able to perform the iteration. For undirected
+   * graphs the situation is more complicated, since no vertex clearly
+   * owns the edges: the list of edges incident to a vertex may
+   * contain a mix of local and non-local edges.
+   *
+   * The distributed adjacency list is able to model several of the
+   * existing Graph concepts. It models the Graph concept because it
+   * exposes vertex and edge descriptors in the normal way; these
+   * descriptors model the GlobalDescriptor concept (because they have
+   * an owner and a local descriptor), and as such the distributed
+   * adjacency list models the DistributedGraph concept. The adjacency
+   * list also models the IncidenceGraph and AdjacencyGraph concepts,
+   * although this is only true so long as the domain of the valid
+   * expression arguments are restricted to vertices and edges stored
+   * locally. Likewise, bidirectional and undirected distributed
+   * adjacency lists model the BidirectionalGraph concept (vertex and
+   * edge domains must be respectived) and the distributed adjacency
+   * list models the MutableGraph concept (vertices and edges can only
+   * be added or removed locally). T he distributed adjacency list
+   * does not, however, model the VertexListGraph or EdgeListGraph
+   * concepts, because we can not efficiently enumerate all vertices
+   * or edges in the graph. Instead, the local subsets of vertices and
+   * edges can be enumerated (with the same syntax): the distributed
+   * adjacency list therefore models the DistributedVertexListGraph
+   * and DistributedEdgeListGraph concepts, because concurrent
+   * iteration over all of the vertices or edges stored on each
+   * processor will visit each vertex or edge.
+   *
+   * The distributed adjacency list is distinguished from the
+   * non-distributed version by the vertex list descriptor, which will
+   * be @c distributedS<ProcessGroup,VertexListS>. Here,
+   * the VertexListS type plays the same role as the VertexListS type
+   * in the non-distributed adjacency list: it allows one to select
+   * the data structure that will be used to store the local
+   * vertices. The ProcessGroup type, on the other hand, is unique to
+   * distributed data structures: it is the type that abstracts a
+   * group of cooperating processes, and it used for process
+   * identification, communication, and synchronization, among other
+   * things. Different process group types represent different
+   * communication mediums (e.g., MPI, PVM, TCP) or different models
+   * of communication (LogP, CGM, BSP, synchronous, etc.). This
+   * distributed adjacency list assumes a model based on non-blocking
+   * sends.
+   *
+   * Distribution of vertices across different processors is
+   * accomplished in two different ways. When initially constructing
+   * the graph, the user may provide a distribution object (that
+   * models the Distribution concept), which will determine the
+   * distribution of vertices to each process. Additionally, the @c
+   * add_vertex and @c add_edge operations add vertices or edges
+   * stored on the local processor. For @c add_edge, this is
+   * accomplished by requiring that the source vertex of the new edge
+   * be local to the process executing @c add_edge.
+   *
+   * Internal properties of a distributed adjacency list are
+   * accessible in the same manner as internal properties for a
+   * non-distributed adjacency list for local vertices or
+   * edges. Access to properties for remote vertices or edges occurs
+   * with the same syntax, but involve communication with the owner of
+   * the information: for more information, refer to class template
+   * @ref distributed_property_map, which manages distributed
+   * property maps. Note that the distributed property maps created
+   * for internal properties determine their reduction operation via
+   * the metafunction @ref property_reduce, which for the vast
+   * majority of uses is correct behavior.
+   *
+   * Communication among the processes coordinating on a particular
+   * distributed graph relies on non-blocking message passing along
+   * with synchronization. Local portions of the distributed graph may
+   * be modified concurrently, including the introduction of non-local
+   * edges, but prior to accessing the graph it is recommended that
+   * the @c synchronize free function be invoked on the graph to clear
+   * up any pending interprocess communication and modifications. All
+   * processes will then be released from the synchronization barrier
+   * concurrently.
+   *
+   * \todo Determine precisely what we should do with nonlocal edges
+   * in undirected graphs. Our parallelization of certain algorithms
+   * relies on the ability to access edge property maps immediately
+   * (e.g., edge_weight_t), so it may be necessary to duplicate the
+   * edge properties in both processes (but then we need some form of
+   * coherence protocol).
+   *
+   * \todo What does the user do if @c property_reduce doesn't do the
+   * right thing?
+   */
+  template<typename OutEdgeListS, typename ProcessGroup,
+           typename InVertexListS, typename InDistribution, typename DirectedS,
+           typename VertexProperty, typename EdgeProperty, 
+           typename GraphProperty, typename EdgeListS>
+  class adjacency_list<OutEdgeListS,
+                       distributedS<ProcessGroup, 
+                                    InVertexListS, 
+                                    InDistribution>,
+                       DirectedS, VertexProperty,
+                       EdgeProperty, GraphProperty, EdgeListS>
+    : // Support for named vertices
+      public graph::distributed::maybe_named_graph<   
+        adjacency_list<OutEdgeListS,
+                       distributedS<ProcessGroup,
+                                    InVertexListS,
+                                    InDistribution>,
+                       DirectedS, VertexProperty,
+                       EdgeProperty, GraphProperty, EdgeListS>,
+        typename adjacency_list_traits<OutEdgeListS, 
+                                       distributedS<ProcessGroup,
+                                                    InVertexListS,
+                                                    InDistribution>,
+                                       DirectedS>::vertex_descriptor,
+        typename adjacency_list_traits<OutEdgeListS, 
+                                       distributedS<ProcessGroup,
+                                                    InVertexListS,
+                                                    InDistribution>,
+                                       DirectedS>::edge_descriptor,
+        detail::parallel::adjacency_list_config<OutEdgeListS, ProcessGroup, 
+                                                InVertexListS, InDistribution,
+                                                DirectedS, VertexProperty, 
+                                                EdgeProperty, GraphProperty, 
+                                                EdgeListS> >
+  {
+    typedef detail::parallel::adjacency_list_config<OutEdgeListS, ProcessGroup, 
+                                                InVertexListS, InDistribution,
+                                                DirectedS, VertexProperty, 
+                                                EdgeProperty, GraphProperty, 
+                                                EdgeListS>
+      config_type;
+      
+    typedef adjacency_list_traits<OutEdgeListS,
+                                  distributedS<ProcessGroup, 
+                                               InVertexListS, 
+                                               InDistribution>,
+                                  DirectedS> 
+      traits_type;
+
+    typedef typename DirectedS::is_directed_t is_directed;
+
+    typedef EdgeListS edge_list_selector;
+
+  public:
+    /// The container type that will store incoming edges for a
+    /// bidirectional graph.
+    typedef typename config_type::in_edge_list_type in_edge_list_type;
+//    typedef typename inherited::edge_descriptor   edge_descriptor;
+
+    /// The type of the underlying adjacency list implementation
+    typedef typename config_type::inherited inherited;
+
+    /// The type of properties stored in the local subgraph
+    /// Bidirectional graphs have an extra vertex property to store
+    /// the incoming edges.
+    typedef typename inherited::vertex_property_type
+      base_vertex_property_type;
+
+    /// The type of the distributed adjacency list (this type)
+    typedef typename config_type::graph_type graph_type;
+
+    /// Expose graph components and graph category
+    typedef typename traits_type::local_vertex_descriptor
+      local_vertex_descriptor;
+    typedef typename traits_type::local_edge_descriptor
+      local_edge_descriptor;
+    typedef typename traits_type::vertex_descriptor vertex_descriptor;
+    typedef typename traits_type::edge_descriptor edge_descriptor;
+
+    typedef typename traits_type::directed_category directed_category;
+    typedef typename inherited::edge_parallel_category
+      edge_parallel_category;
+    typedef typename inherited::graph_tag graph_tag;
+
+    // Current implementation requires the ability to have parallel
+    // edges in the underlying adjacency_list. Which processor each
+    // edge refers to is attached as an internal property. TBD:
+    // remove this restriction, which may require some rewriting.
+    BOOST_STATIC_ASSERT((is_same<edge_parallel_category,
+                                 allow_parallel_edge_tag>::value));
+
+    /** Determine the graph traversal category.
+     *
+     * A directed distributed adjacency list models the Distributed
+     * Graph, Incidence Graph, and Adjacency Graph
+     * concepts. Bidirectional and undirected graphs also model the
+     * Bidirectional Graph concept. Note that when modeling these
+     * concepts the domains of certain operations (e.g., in_edges)
+     * are restricted; see the distributed adjacency_list
+     * documentation.
+     */
+    typedef typename ct_if<
+              (is_same<DirectedS, directedS>::value),
+              directed_distributed_adj_list_tag,
+              typename ct_if<(is_same<DirectedS, bidirectionalS>::value),
+                             bidirectional_distributed_adj_list_tag,
+                             undirected_distributed_adj_list_tag>::type>
+      ::type traversal_category;
+
+    typedef typename inherited::degree_size_type degree_size_type;
+    typedef typename inherited::vertices_size_type vertices_size_type;
+    typedef typename inherited::edges_size_type edges_size_type;
+    typedef VertexProperty vertex_property_type;
+    typedef EdgeProperty edge_property_type;
+    typedef typename inherited::graph_property_type graph_property_type;
+    typedef typename inherited::vertex_bundled vertex_bundled;
+    typedef typename inherited::edge_bundled edge_bundled;
+
+    typedef typename container_gen<edge_list_selector, edge_descriptor>::type
+      local_edge_list_type;
+
+  private:
+    typedef typename ct_if<(is_same<DirectedS, bidirectionalS>::value),
+                           typename in_edge_list_type::const_iterator,
+                           typename inherited::out_edge_iterator>::type
+      base_in_edge_iterator;
+
+    typedef typename inherited::out_edge_iterator base_out_edge_iterator;
+    typedef typename graph_traits<inherited>::edge_iterator
+      base_edge_iterator;
+    typedef typename inherited::edge_property_type base_edge_property_type;
+
+    typedef typename local_edge_list_type::const_iterator
+      undirected_edge_iterator;
+
+    typedef InDistribution in_distribution_type;
+
+    typedef parallel::trigger_receive_context trigger_receive_context;
+
+  public:
+    /// Iterator over the (local) vertices of the graph
+    typedef transform_iterator<typename vertex_descriptor::generator,
+                               typename inherited::vertex_iterator>
+      vertex_iterator;
+
+    /// Helper for out_edge_iterator
+    typedef typename edge_descriptor::template out_generator<adjacency_list>
+      out_edge_generator;
+
+    /// Iterator over the outgoing edges of a vertex
+    typedef transform_iterator<out_edge_generator,
+                               typename inherited::out_edge_iterator>
+      out_edge_iterator;
+
+    /// Helper for in_edge_iterator
+    typedef typename edge_descriptor::template in_generator<adjacency_list>
+      in_edge_generator;
+
+    /// Iterator over the incoming edges of a vertex
+    typedef transform_iterator<in_edge_generator, base_in_edge_iterator>
+      in_edge_iterator;
+
+    /// Iterator over the neighbors of a vertex
+    typedef adjacency_iterator<
+              adjacency_list, vertex_descriptor, out_edge_iterator,
+              typename detail::iterator_traits<base_out_edge_iterator>
+                         ::difference_type>
+      adjacency_iterator;
+
+    /// Iterator over the (local) edges in a graph
+    typedef typename ct_if<(is_same<DirectedS, undirectedS>::value),
+                           undirected_edge_iterator,
+                           transform_iterator<out_edge_generator,
+                                              base_edge_iterator>
+                           >::type 
+      edge_iterator;
+
+  public:
+    /// The type of the mixin for named vertices
+    typedef graph::distributed::maybe_named_graph<graph_type, 
+                                                  vertex_descriptor, 
+                                                  edge_descriptor, 
+                                                  config_type> 
+      named_graph_mixin;
+        
+    /// Process group used for communication
+    typedef ProcessGroup process_group_type;
+
+    /// How to refer to a process
+    typedef typename process_group_type::process_id_type process_id_type;
+
+    /// Whether this graph is directed, undirected, or bidirectional
+    typedef DirectedS directed_selector;
+
+    // Structure used for the lazy addition of vertices
+    struct lazy_add_vertex_with_property;
+    friend struct lazy_add_vertex_with_property;
+
+    // Structure used for the lazy addition of edges
+    struct lazy_add_edge;
+    friend struct lazy_add_edge;
+
+    // Structure used for the lazy addition of edges with properties
+    struct lazy_add_edge_with_property;
+    friend struct lazy_add_edge_with_property;
+
+    /// default_distribution_type is the type of the distribution used if the
+    /// user didn't specify an explicit one
+    typedef typename graph::distributed::select_distribution<
+              InDistribution, VertexProperty, vertices_size_type, 
+              ProcessGroup>::default_type 
+      default_distribution_type;
+    
+    /// distribution_type is the type of the distribution instance stored in
+    /// the maybe_named_graph base class
+    typedef typename graph::distributed::select_distribution<
+              InDistribution, VertexProperty, vertices_size_type,
+              ProcessGroup>::type 
+      base_distribution_type;
+
+      typedef graph::distributed::shuffled_distribution<
+          base_distribution_type> distribution_type;
+
+  private:
+    // FIXME: the original adjacency_list contained this comment:
+    //    Default copy constructor and copy assignment operators OK??? TBD
+    // but the adj_list_impl contained these declarations:
+    adjacency_list(const adjacency_list& other);
+    adjacency_list& operator=(const adjacency_list& other);
+
+  public:
+    adjacency_list(const ProcessGroup& pg = ProcessGroup())
+      : named_graph_mixin(pg, default_distribution_type(pg, 0)),
+        m_local_graph(GraphProperty()), 
+        process_group_(pg, graph::parallel::attach_distributed_object())
+    {
+      setup_triggers();
+    }
+
+    adjacency_list(const ProcessGroup& pg, 
+                   const base_distribution_type& distribution)
+      : named_graph_mixin(pg, distribution),
+        m_local_graph(GraphProperty()), 
+        process_group_(pg, graph::parallel::attach_distributed_object())
+    {
+      setup_triggers();
+    }
+
+    adjacency_list(const GraphProperty& g,
+                   const ProcessGroup& pg = ProcessGroup())
+      : named_graph_mixin(pg, default_distribution_type(pg, 0)),
+        m_local_graph(g), 
+        process_group_(pg, graph::parallel::attach_distributed_object())
+    {
+      setup_triggers();
+    }
+
+    adjacency_list(vertices_size_type n,
+                   const GraphProperty& p,
+                   const ProcessGroup& pg,
+                   const base_distribution_type& distribution)
+      : named_graph_mixin(pg, distribution),
+        m_local_graph(distribution.block_size(process_id(pg), n), p),
+        process_group_(pg, graph::parallel::attach_distributed_object())
+    {
+      setup_triggers();
+
+      detail::parallel::maybe_initialize_vertex_indices(vertices(base()),
+                                      get(vertex_index, base()));
+    }
+
+    adjacency_list(vertices_size_type n,
+                   const ProcessGroup& pg,
+                   const base_distribution_type& distribution)
+      : named_graph_mixin(pg, distribution),
+        m_local_graph(distribution.block_size(process_id(pg), n), GraphProperty()),
+        process_group_(pg, graph::parallel::attach_distributed_object()) 
+    {
+      setup_triggers();
+
+      detail::parallel::maybe_initialize_vertex_indices(vertices(base()),
+                                      get(vertex_index, base()));
+    }
+
+    adjacency_list(vertices_size_type n,
+                   const GraphProperty& p,
+                   const ProcessGroup& pg = ProcessGroup())
+      : named_graph_mixin(pg, default_distribution_type(pg, n)),
+        m_local_graph(this->distribution().block_size(process_id(pg), n), p),
+        process_group_(pg, graph::parallel::attach_distributed_object())
+    {
+      setup_triggers();
+
+      detail::parallel::maybe_initialize_vertex_indices(vertices(base()),
+                                      get(vertex_index, base()));
+    }
+
+    adjacency_list(vertices_size_type n,
+                   const ProcessGroup& pg = ProcessGroup())
+      : named_graph_mixin(pg, default_distribution_type(pg, n)),
+        m_local_graph(this->distribution().block_size(process_id(pg), n), 
+                      GraphProperty()),
+        process_group_(pg, graph::parallel::attach_distributed_object())
+    {
+      setup_triggers();
+
+      detail::parallel::maybe_initialize_vertex_indices(vertices(base()),
+                                      get(vertex_index, base()));
+    }
+
+    /*
+     * We assume that every processor sees the same list of edges, so
+     * they skip over any that don't originate from themselves. This
+     * means that programs switching between a local and a distributed
+     * graph will keep the same semantics.
+     */
+    template <class EdgeIterator>
+    adjacency_list(EdgeIterator first, EdgeIterator last,
+                   vertices_size_type n,
+                   const ProcessGroup& pg = ProcessGroup(),
+                   const GraphProperty& p = GraphProperty())
+      : named_graph_mixin(pg, default_distribution_type(pg, n)),
+        m_local_graph(this->distribution().block_size(process_id(pg), n), p),
+        process_group_(pg, graph::parallel::attach_distributed_object())
+    {
+      setup_triggers();
+
+      typedef typename config_type::VertexListS vertex_list_selector;
+      initialize(first, last, n, this->distribution(), vertex_list_selector());
+      detail::parallel::maybe_initialize_vertex_indices(vertices(base()),
+                                      get(vertex_index, base()));
+
+    }
+
+    template <class EdgeIterator, class EdgePropertyIterator>
+    adjacency_list(EdgeIterator first, EdgeIterator last,
+                   EdgePropertyIterator ep_iter,
+                   vertices_size_type n,
+                   const ProcessGroup& pg = ProcessGroup(),
+                   const GraphProperty& p = GraphProperty())
+      : named_graph_mixin(pg, default_distribution_type(pg, n)),
+        m_local_graph(this->distribution().block_size(process_id(pg), n), p),
+        process_group_(pg, graph::parallel::attach_distributed_object())
+    {
+      setup_triggers();
+
+      typedef typename config_type::VertexListS vertex_list_selector;
+      initialize(first, last, ep_iter, n, this->distribution(),
+                 vertex_list_selector());
+      detail::parallel::maybe_initialize_vertex_indices(vertices(base()),
+                                      get(vertex_index, base()));
+
+    }
+
+    template <class EdgeIterator>
+    adjacency_list(EdgeIterator first, EdgeIterator last,
+                   vertices_size_type n,
+                   const ProcessGroup& pg,
+                   const base_distribution_type& distribution,
+                   const GraphProperty& p = GraphProperty())
+      : named_graph_mixin(pg, distribution),
+        m_local_graph(distribution.block_size(process_id(pg), n), p),
+        process_group_(pg, graph::parallel::attach_distributed_object())
+    {
+      setup_triggers();
+
+      typedef typename config_type::VertexListS vertex_list_selector;
+      initialize(first, last, n, this->distribution(), vertex_list_selector());
+      detail::parallel::maybe_initialize_vertex_indices(vertices(base()),
+                                      get(vertex_index, base()));
+
+    }
+
+    template <class EdgeIterator, class EdgePropertyIterator>
+    adjacency_list(EdgeIterator first, EdgeIterator last,
+                   EdgePropertyIterator ep_iter,
+                   vertices_size_type n,
+                   const ProcessGroup& pg,
+                   const base_distribution_type& distribution,
+                   const GraphProperty& p = GraphProperty())
+      : named_graph_mixin(pg, distribution),
+        m_local_graph(this->distribution().block_size(process_id(pg), n), p),
+        process_group_(pg, graph::parallel::attach_distributed_object())
+    {
+      setup_triggers();
+
+      typedef typename config_type::VertexListS vertex_list_selector;
+      initialize(first, last, ep_iter, n, distribution,
+                 vertex_list_selector());
+      detail::parallel::maybe_initialize_vertex_indices(vertices(base()),
+                                      get(vertex_index, base()));
+
+    }
+
+    ~adjacency_list()
+    {
+      synchronize(process_group_);
+    }
+
+    void clear()
+    {
+      base().clear();
+      local_edges_.clear();
+      named_graph_mixin::clearing_graph();
+    }
+
+    void swap(adjacency_list& other)
+    {
+      using std::swap;
+
+      base().swap(other);
+      swap(process_group_, other.process_group_);
+    }
+
+    static vertex_descriptor null_vertex()
+    {
+      return vertex_descriptor(processor_id_type(0),
+                               inherited::null_vertex());
+    }
+
+    inherited&       base()       { return m_local_graph; }
+    const inherited& base() const { return m_local_graph; }
+
+    processor_id_type processor() const { return process_id(process_group_); }
+    process_group_type process_group() const { return process_group_.base(); }
+
+    local_edge_list_type&       local_edges()       { return local_edges_; }
+    const local_edge_list_type& local_edges() const { return local_edges_; }
+
+    // Redistribute the vertices of the graph by placing each vertex
+    // v on the processor get(vertex_to_processor, v).
+    template<typename VertexProcessorMap>
+    void redistribute(VertexProcessorMap vertex_to_processor);
+
+    // Directly access a vertex or edge bundle
+    vertex_bundled& operator[](vertex_descriptor v)
+    {
+      assert(v.owner == processor());
+      return base()[v.local];
+    }
+    
+    const vertex_bundled& operator[](vertex_descriptor v) const
+    {
+      assert(v.owner == processor());
+      return base()[v.local];
+    }
+    
+    edge_bundled& operator[](edge_descriptor e)
+    {
+      assert(e.owner() == processor());
+      return base()[e.local];
+    }
+    
+    const edge_bundled& operator[](edge_descriptor e) const
+    {
+      assert(e.owner() == processor());
+      return base()[e.local];
+    }
+
+    template<typename OStreamConstructibleArchive>
+    void save(std::string const& filename) const;
+
+    template<typename IStreamConstructibleArchive>
+    void load(std::string const& filename);
+
+    // Callback that will be invoked whenever a new vertex is added locally
+    boost::function<void(vertex_descriptor, adjacency_list&)> on_add_vertex;
+
+    // Callback that will be invoked whenever a new edge is added locally
+    boost::function<void(edge_descriptor, adjacency_list&)> on_add_edge;
+
+  private:
+    // Request vertex->processor mapping for neighbors <does nothing>
+    template<typename VertexProcessorMap>
+    void
+    request_in_neighbors(vertex_descriptor,
+                         VertexProcessorMap,
+                         directedS) { }
+
+    // Request vertex->processor mapping for neighbors <does nothing>
+    template<typename VertexProcessorMap>
+    void
+    request_in_neighbors(vertex_descriptor,
+                         VertexProcessorMap,
+                         undirectedS) { }
+
+    // Request vertex->processor mapping for neighbors
+    template<typename VertexProcessorMap>
+    void
+    request_in_neighbors(vertex_descriptor v,
+                         VertexProcessorMap vertex_to_processor,
+                         bidirectionalS);
+
+    // Clear the list of in-edges, but don't tell the remote processor
+    void clear_in_edges_local(vertex_descriptor v, directedS) {}
+    void clear_in_edges_local(vertex_descriptor v, undirectedS) {}
+
+    void clear_in_edges_local(vertex_descriptor v, bidirectionalS)
+    { get(vertex_in_edges, base())[v.local].clear(); }
+
+    // Remove in-edges that have migrated <does nothing>
+    template<typename VertexProcessorMap>
+    void
+    remove_migrated_in_edges(vertex_descriptor,
+                             VertexProcessorMap,
+                             directedS) { }
+
+    // Remove in-edges that have migrated <does nothing>
+    template<typename VertexProcessorMap>
+    void
+    remove_migrated_in_edges(vertex_descriptor,
+                             VertexProcessorMap,
+                             undirectedS) { }
+
+    // Remove in-edges that have migrated
+    template<typename VertexProcessorMap>
+    void
+    remove_migrated_in_edges(vertex_descriptor v,
+                             VertexProcessorMap vertex_to_processor,
+                             bidirectionalS);
+
+    // Initialize the graph with the given edge list and vertex
+    // distribution. This variation works only when
+    // VertexListS=vecS, and we know how to create remote vertex
+    // descriptors based solely on the distribution.
+    template<typename EdgeIterator>
+    void
+    initialize(EdgeIterator first, EdgeIterator last,
+               vertices_size_type, const base_distribution_type& distribution, 
+               vecS);
+
+    // Initialize the graph with the given edge list, edge
+    // properties, and vertex distribution. This variation works
+    // only when VertexListS=vecS, and we know how to create remote
+    // vertex descriptors based solely on the distribution.
+    template<typename EdgeIterator, typename EdgePropertyIterator>
+    void
+    initialize(EdgeIterator first, EdgeIterator last,
+               EdgePropertyIterator ep_iter,
+               vertices_size_type, const base_distribution_type& distribution, 
+               vecS);
+
+    // Initialize the graph with the given edge list, edge
+    // properties, and vertex distribution.
+    template<typename EdgeIterator, typename EdgePropertyIterator,
+             typename VertexListS>
+    void
+    initialize(EdgeIterator first, EdgeIterator last,
+               EdgePropertyIterator ep_iter,
+               vertices_size_type n, 
+               const base_distribution_type& distribution,
+               VertexListS);
+
+    // Initialize the graph with the given edge list and vertex
+    // distribution. This is nearly identical to the one below it,
+    // for which I should be flogged. However, this version does use
+    // slightly less memory than the version that accepts an edge
+    // property iterator.
+    template<typename EdgeIterator, typename VertexListS>
+    void
+    initialize(EdgeIterator first, EdgeIterator last,
+               vertices_size_type n, 
+               const base_distribution_type& distribution,
+               VertexListS);
+
+  public:
+    //---------------------------------------------------------------------
+    // Build a vertex property instance for the underlying adjacency
+    // list from the given property instance of the type exposed to
+    // the user.
+    base_vertex_property_type 
+    build_vertex_property(const vertex_property_type& p)
+    { return build_vertex_property(p, directed_selector()); }
+
+    base_vertex_property_type
+    build_vertex_property(const vertex_property_type& p, directedS)
+    {
+      return base_vertex_property_type(p);
+    }
+
+    base_vertex_property_type
+    build_vertex_property(const vertex_property_type& p, bidirectionalS)
+    {
+      return base_vertex_property_type(in_edge_list_type(), p);
+    }
+
+    base_vertex_property_type
+    build_vertex_property(const vertex_property_type& p, undirectedS)
+    {
+      return base_vertex_property_type(p);
+    }
+    //---------------------------------------------------------------------
+
+    //---------------------------------------------------------------------
+    // Build an edge property instance for the underlying adjacency
+    // list from the given property instance of the type exposed to
+    // the user.
+    base_edge_property_type build_edge_property(const edge_property_type& p)
+    { return build_edge_property(p, directed_selector()); }
+
+    base_edge_property_type
+    build_edge_property(const edge_property_type& p, directedS)
+    {
+      return base_edge_property_type(0, p);
+    }
+
+    base_edge_property_type
+    build_edge_property(const edge_property_type& p, bidirectionalS)
+    {
+      return base_edge_property_type(0, p);
+    }
+
+    base_edge_property_type
+    build_edge_property(const edge_property_type& p, undirectedS)
+    {
+      typedef typename base_edge_property_type::next_type
+        edge_property_with_id;
+      return base_edge_property_type(true, edge_property_with_id(0, p));
+    }
+    //---------------------------------------------------------------------
+
+    /** The set of messages that can be transmitted and received by
+     *  a distributed adjacency list. This list will eventually be
+     *  exhaustive, but is currently quite limited.
+     */
+    enum {
+      /**
+       * Request to add or find a vertex with the given vertex
+       * property. The data will be a vertex_property_type
+       * structure.
+       */
+      msg_add_vertex_with_property = 0,
+
+      /**
+       * Request to add or find a vertex with the given vertex
+       * property, and request that the remote processor return the
+       * descriptor for the added/found edge. The data will be a
+       * vertex_property_type structure.
+       */
+      msg_add_vertex_with_property_and_reply,
+
+      /**
+       * Reply to a msg_add_vertex_* message, containing the local
+       * vertex descriptor that was added or found.
+       */
+      msg_add_vertex_reply,
+
+      /**
+       * Request to add an edge remotely. The data will be a
+       * msg_add_edge_data structure. 
+       */
+      msg_add_edge,
+
+      /**
+       * Request to add an edge remotely. The data will be a
+       * msg_add_edge_with_property_data structure. 
+       */
+      msg_add_edge_with_property,
+
+      /**
+       * Request to add an edge remotely and reply back with the
+       * edge descriptor. The data will be a
+       * msg_add_edge_data structure. 
+       */
+      msg_add_edge_with_reply,
+
+      /**
+       * Request to add an edge remotely and reply back with the
+       * edge descriptor. The data will be a
+       * msg_add_edge_with_property_data structure.
+       */
+      msg_add_edge_with_property_and_reply,
+
+      /**
+       * Reply message responding to an @c msg_add_edge_with_reply
+       * or @c msg_add_edge_with_property_and_reply messages. The
+       * data will be a std::pair<edge_descriptor, bool>.
+       */
+      msg_add_edge_reply,
+
+      /**
+       * Indicates that a nonlocal edge has been created that should
+       * be added locally. Only valid for bidirectional and
+       * undirected graphs. The message carries a
+       * msg_nonlocal_edge_data structure.
+       */
+      msg_nonlocal_edge,
+
+      /**
+       * Indicates that a remote edge should be removed. This
+       * message does not exist for directedS graphs but may refer
+       * to either in-edges or out-edges for undirectedS graphs.
+       */
+      msg_remove_edge,
+
+      /**
+       * Indicates the number of vertices and edges that will be
+       * relocated from the source processor to the target
+       * processor. The data will be a pair<vertices_size_type,
+       * edges_size_type>.
+       */
+      msg_num_relocated
+    };
+
+    typedef detail::parallel::msg_add_edge_data<vertex_descriptor,
+                                                local_vertex_descriptor>
+      msg_add_edge_data;
+
+    typedef detail::parallel::msg_add_edge_with_property_data
+              <vertex_descriptor, local_vertex_descriptor, 
+               edge_property_type> msg_add_edge_with_property_data;
+
+    typedef  boost::detail::parallel::msg_nonlocal_edge_data<
+      edge_property_type,local_edge_descriptor> msg_nonlocal_edge_data;
+
+    typedef boost::detail::parallel::msg_remove_edge_data<edge_descriptor>
+      msg_remove_edge_data;
+
+    void send_remove_edge_request(edge_descriptor e)
+    {
+      process_id_type dest = e.target_processor;
+      if (e.target_processor == process_id(process_group_))
+        dest = e.source_processor;
+      send(process_group_, dest, msg_remove_edge, msg_remove_edge_data(e));
+    }
+
+    /// Process incoming messages.
+    void setup_triggers();
+
+    void 
+    handle_add_vertex_with_property(int source, int tag,
+                                    const vertex_property_type&,
+                                    trigger_receive_context);
+
+    local_vertex_descriptor
+    handle_add_vertex_with_property_and_reply(int source, int tag,
+                                        const vertex_property_type&,
+                                        trigger_receive_context);
+
+    void 
+    handle_add_edge(int source, int tag, const msg_add_edge_data& data,
+                    trigger_receive_context);
+
+    boost::parallel::detail::untracked_pair<edge_descriptor, bool>
+    handle_add_edge_with_reply(int source, int tag, 
+                         const msg_add_edge_data& data,
+                         trigger_receive_context);
+
+    void 
+    handle_add_edge_with_property(int source, int tag,
+                                  const msg_add_edge_with_property_data&,
+                                  trigger_receive_context);
+              
+    boost::parallel::detail::untracked_pair<edge_descriptor, bool>
+    handle_add_edge_with_property_and_reply
+      (int source, int tag, const msg_add_edge_with_property_data&,
+       trigger_receive_context);
+
+    void 
+    handle_nonlocal_edge(int source, int tag, 
+                         const msg_nonlocal_edge_data& data,
+                         trigger_receive_context);
+
+    void 
+    handle_remove_edge(int source, int tag, 
+                       const msg_remove_edge_data& data,
+                       trigger_receive_context);
+         
+  protected:
+    /** Add an edge (locally) that was received from another
+     * processor. This operation is a no-op for directed graphs,
+     * because all edges reside on the local processor. For
+     * bidirectional graphs, this routine places the edge onto the
+     * list of incoming edges for the target vertex. For undirected
+     * graphs, the edge is placed along with all of the other edges
+     * for the target vertex, but it is marked as a non-local edge
+     * descriptor.
+     *
+     * \todo There is a potential problem here, where we could
+     * unintentionally allow duplicate edges in undirected graphs
+     * because the same edge is added on two different processors
+     * simultaneously. It's not an issue now, because we require
+     * that the graph allow parallel edges. Once we do support
+     * containers such as setS or hash_setS that disallow parallel
+     * edges we will need to deal with this.
+     */
+    void
+    add_remote_edge(const msg_nonlocal_edge_data&,
+                    processor_id_type, directedS)
+    { }
+
+
+    /**
+     * \overload
+     */
+    void
+    add_remote_edge(const msg_nonlocal_edge_data& data,
+                    processor_id_type other_proc, bidirectionalS)
+    {
+      typedef detail::parallel::stored_in_edge<local_edge_descriptor> stored_edge;
+
+      stored_edge edge(other_proc, data.e);
+      local_vertex_descriptor v = target(data.e, base());
+      boost::graph_detail::push(get(vertex_in_edges, base())[v], edge);
+    }
+
+    /**
+     * \overload
+     */
+    void
+    add_remote_edge(const msg_nonlocal_edge_data& data,
+                    processor_id_type other_proc, undirectedS)
+    {
+      std::pair<local_edge_descriptor, bool> edge =
+        detail::parallel::add_local_edge(target(data.e, base()), 
+                       source(data.e, base()),
+                       build_edge_property(data.get_property()), base());
+      assert(edge.second);
+      put(edge_target_processor_id, base(), edge.first, other_proc);
+
+      if (edge.second && on_add_edge)
+        on_add_edge(edge_descriptor(processor(), other_proc, false, 
+                                    edge.first),
+                    *this);
+    }
+
+    void
+    remove_local_edge(const msg_remove_edge_data&, processor_id_type,
+                      directedS)
+    { }
+
+    void
+    remove_local_edge(const msg_remove_edge_data& data,
+                      processor_id_type other_proc, bidirectionalS)
+    {
+      /* When the source is local, we first check if the edge still
+       * exists (it may have been deleted locally) and, if so,
+       * remove it locally.
+       */
+      vertex_descriptor src = source(data.e, *this);
+      vertex_descriptor tgt = target(data.e, *this);
+
+      if (src.owner == process_id(process_group_)) {
+        base_out_edge_iterator ei, ei_end;
+        for (tie(ei, ei_end) = out_edges(src.local, base());
+             ei != ei_end; ++ei) {
+          // TBD: can't check the descriptor here, because it could
+          // have changed if we're allowing the removal of
+          // edges. Egads!
+          if (tgt.local == target(*ei, base())
+              && get(edge_target_processor_id, base(), *ei) == other_proc)
+            break;
+        }
+
+        if (ei != ei_end) boost::remove_edge(ei, base());
+
+        remove_local_edge_from_list(src, tgt, undirectedS());
+      } else {
+        assert(tgt.owner == process_id(process_group_));
+        in_edge_list_type& in_edges =
+          get(vertex_in_edges, base())[tgt.local];
+        typename in_edge_list_type::iterator ei;
+        for (ei = in_edges.begin(); ei != in_edges.end(); ++ei) {
+          if (src.local == source(ei->e, base())
+              && src.owner == ei->source_processor)
+            break;
+        }
+
+        if (ei != in_edges.end()) in_edges.erase(ei);
+      }
+    }
+
+    void
+    remove_local_edge(const msg_remove_edge_data& data,
+                      processor_id_type other_proc, undirectedS)
+    {
+      vertex_descriptor local_vertex = source(data.e, *this);
+      vertex_descriptor remote_vertex = target(data.e, *this);
+      if (remote_vertex.owner == process_id(process_group_)) {
+        using std::swap;
+        swap(local_vertex, remote_vertex);
+      }
+
+      // Remove the edge from the out-edge list, if it is there
+      {
+        base_out_edge_iterator ei, ei_end;
+        for (tie(ei, ei_end) = out_edges(local_vertex.local, base());
+             ei != ei_end; ++ei) {
+          // TBD: can't check the descriptor here, because it could
+          // have changed if we're allowing the removal of
+          // edges. Egads!
+          if (remote_vertex.local == target(*ei, base())
+              && get(edge_target_processor_id, base(), *ei) == other_proc)
+            break;
+        }
+
+        if (ei != ei_end) boost::remove_edge(ei, base());
+      }
+
+      remove_local_edge_from_list(local_vertex, remote_vertex, undirectedS());
+    }
+
+  public:
+    void
+    remove_local_edge_from_list(vertex_descriptor, vertex_descriptor,
+                                directedS)
+    {
+    }
+
+    void
+    remove_local_edge_from_list(vertex_descriptor, vertex_descriptor,
+                                bidirectionalS)
+    {
+    }
+
+    void
+    remove_local_edge_from_list(vertex_descriptor src, vertex_descriptor tgt,
+                                undirectedS)
+    {
+      // TBD: At some point we'll be able to improve the speed here
+      // because we'll know when the edge can't be in the local
+      // list.
+      {
+        typename local_edge_list_type::iterator ei;
+        for (ei = local_edges_.begin(); ei != local_edges_.end(); ++ei) {
+          if ((source(*ei, *this) == src
+               && target(*ei, *this) == tgt)
+              || (source(*ei, *this) == tgt
+                  && target(*ei, *this) == src))
+            break;
+        }
+
+        if (ei != local_edges_.end()) local_edges_.erase(ei);
+      }
+
+    }
+
+  private:
+    /// The local subgraph
+    inherited m_local_graph;
+
+    /// The process group through which this distributed graph
+    /// communicates.
+    process_group_type process_group_;
+
+    // TBD: should only be available for undirected graphs, but for
+    // now it'll just be empty for directed and bidirectional
+    // graphs.
+    local_edge_list_type local_edges_;
+  };
+
+  //------------------------------------------------------------------------
+  // Lazy addition of vertices
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  struct PBGL_DISTRIB_ADJLIST_TYPE::lazy_add_vertex_with_property
+  {
+    /// Construct a lazy request to add a vertex
+    lazy_add_vertex_with_property(adjacency_list& self, 
+                                  const vertex_property_type& property)
+      : self(self), property(property), committed(false) { }
+
+    /// Copying a lazy_add_vertex_with_property transfers the
+    /// responsibility for adding the vertex to the newly-constructed
+    /// object.
+    lazy_add_vertex_with_property(const lazy_add_vertex_with_property& other)
+      : self(other.self), property(other.property),
+        committed(other.committed)
+    {
+      other.committed = true;
+    }
+
+    /// If the vertex has not yet been added, add the vertex but don't
+    /// wait for a reply.
+    ~lazy_add_vertex_with_property();
+
+    /// Returns commit().
+    operator vertex_descriptor() const { return commit(); }
+
+    // Add the vertex. This operation will block if the vertex is
+    // being added remotely.
+    vertex_descriptor commit() const;
+
+  protected:
+    adjacency_list& self;
+    vertex_property_type property;
+    mutable bool committed;
+
+  private:
+    // No copy-assignment semantics
+    void operator=(lazy_add_vertex_with_property&);
+  };
+
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  PBGL_DISTRIB_ADJLIST_TYPE::lazy_add_vertex_with_property::
+  ~lazy_add_vertex_with_property()
+  {
+    /// If this vertex has already been created or will be created by
+    /// someone else, or if someone threw an exception, we will not
+    /// create the vertex now.
+    if (committed || std::uncaught_exception())
+      return;
+
+    committed = true;
+
+    process_id_type owner 
+      = static_cast<graph_type&>(self).owner_by_property(property);
+    if (owner == self.processor()) {
+      /// Add the vertex locally.
+      vertex_descriptor v(owner, 
+                          add_vertex(self.build_vertex_property(property), 
+                                     self.base()));
+      if (self.on_add_vertex)
+        self.on_add_vertex(v, self);
+    }
+    else
+      /// Ask the owner of this new vertex to add the vertex. We
+      /// don't need a reply.
+      send(self.process_group_, owner, msg_add_vertex_with_property,
+           property);
+  }
+
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor 
+  PBGL_DISTRIB_ADJLIST_TYPE::lazy_add_vertex_with_property::
+  commit() const
+  {
+    assert(!this->committed);
+    this->committed = true;
+
+    process_id_type owner 
+      = static_cast<graph_type&>(self).owner_by_property(property);
+    local_vertex_descriptor local_v;
+    if (owner == self.processor())
+      /// Add the vertex locally.
+      local_v = add_vertex(self.build_vertex_property(property), 
+                           self.base());
+    else {
+      // Request that the remote process add the vertex immediately
+      send_oob_with_reply(self.process_group_, owner,
+               msg_add_vertex_with_property_and_reply, property,
+               local_v);
+    }
+
+    vertex_descriptor v(owner, local_v);
+    if (self.on_add_vertex)
+      self.on_add_vertex(v, self);
+
+    // Build the full vertex descriptor to return
+    return v;
+  }
+  
+
+  /** 
+   * Data structure returned from add_edge that will "lazily" add
+   * the edge, either when it is converted to a
+   * @c pair<edge_descriptor, bool> or when the most recent copy has
+   * been destroyed.
+   */
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  struct PBGL_DISTRIB_ADJLIST_TYPE::lazy_add_edge
+  {
+    /// Construct a lazy request to add an edge
+    lazy_add_edge(adjacency_list& self, 
+                  vertex_descriptor source, vertex_descriptor target)
+      : self(self), source(source), target(target), committed(false) { }
+
+    /// Copying a lazy_add_edge transfers the responsibility for
+    /// adding the edge to the newly-constructed object.
+    lazy_add_edge(const lazy_add_edge& other)
+      : self(other.self), source(other.source), target(other.target), 
+        committed(other.committed)
+    {
+      other.committed = true;
+    }
+
+    /// If the edge has not yet been added, add the edge but don't
+    /// wait for a reply.
+    ~lazy_add_edge();
+
+    /// Returns commit().
+    operator std::pair<edge_descriptor, bool>() const { return commit(); }
+
+    // Add the edge. This operation will block if a remote edge is
+    // being added.
+    std::pair<edge_descriptor, bool> commit() const;
+
+  protected:
+    std::pair<edge_descriptor, bool> 
+    add_local_edge(const edge_property_type& property, directedS) const;
+
+    std::pair<edge_descriptor, bool> 
+    add_local_edge(const edge_property_type& property, bidirectionalS) const;
+
+    std::pair<edge_descriptor, bool> 
+    add_local_edge(const edge_property_type& property, undirectedS) const;
+
+    adjacency_list& self;
+    vertex_descriptor source;
+    vertex_descriptor target;
+    mutable bool committed;
+
+  private:
+    // No copy-assignment semantics
+    void operator=(lazy_add_edge&);
+  };
+
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  PBGL_DISTRIB_ADJLIST_TYPE::lazy_add_edge::~lazy_add_edge()
+  {
+    /// If this edge has already been created or will be created by
+    /// someone else, or if someone threw an exception, we will not
+    /// create the edge now.
+    if (committed || std::uncaught_exception())
+      return;
+
+    committed = true;
+
+    if (source.owner == self.processor())
+      this->add_local_edge(edge_property_type(), DirectedS());
+    else
+      // Request that the remote processor add an edge and, but
+      // don't wait for a reply.
+      send(self.process_group_, source.owner, msg_add_edge,
+           msg_add_edge_data(source, target));
+  }
+
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  std::pair<typename PBGL_DISTRIB_ADJLIST_TYPE::edge_descriptor, bool>
+  PBGL_DISTRIB_ADJLIST_TYPE::lazy_add_edge::commit() const
+  {
+    assert(!committed);
+    committed = true;
+
+    if (source.owner == self.processor())
+      return this->add_local_edge(edge_property_type(), DirectedS());
+    else {
+      // Request that the remote processor add an edge
+      boost::parallel::detail::untracked_pair<edge_descriptor, bool> result;
+      send_oob_with_reply(self.process_group_, source.owner, 
+                          msg_add_edge_with_reply,
+                          msg_add_edge_data(source, target), result);
+      return result;
+    }
+  }
+
+  // Add a local edge into a directed graph
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  std::pair<typename PBGL_DISTRIB_ADJLIST_TYPE::edge_descriptor, bool>
+  PBGL_DISTRIB_ADJLIST_TYPE::lazy_add_edge::
+  add_local_edge(const edge_property_type& property, directedS) const
+  {
+    // Add the edge to the local part of the graph
+    std::pair<local_edge_descriptor, bool> inserted =
+      detail::parallel::add_local_edge(source.local, target.local,
+                                       self.build_edge_property(property), 
+                                       self.base());
+
+    if (inserted.second)
+      // Keep track of the owner of the target
+      put(edge_target_processor_id, self.base(), inserted.first, 
+          target.owner);
+
+    // Compose the edge descriptor and return the result
+    edge_descriptor e(source.owner, target.owner, true, inserted.first);
+
+    // Trigger the on_add_edge event
+    if (inserted.second && self.on_add_edge)
+      self.on_add_edge(e, self);
+
+    return std::pair<edge_descriptor, bool>(e, inserted.second);
+  }
+
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  std::pair<typename PBGL_DISTRIB_ADJLIST_TYPE::edge_descriptor, bool>
+  PBGL_DISTRIB_ADJLIST_TYPE::lazy_add_edge::
+  add_local_edge(const edge_property_type& property, bidirectionalS) const
+  {
+    // Add the directed edge.
+    std::pair<edge_descriptor, bool> result 
+      = this->add_local_edge(property, directedS());
+
+    if (result.second) {
+      if (target.owner == self.processor()) {
+        // Edge is local, so add the stored edge to the in_edges list
+        typedef detail::parallel::stored_in_edge<local_edge_descriptor>
+          stored_edge;
+
+        stored_edge e(self.processor(), result.first.local);
+        boost::graph_detail::push(get(vertex_in_edges, 
+                                      self.base())[target.local], e);
+      } 
+      else {
+        // Edge is remote, so notify the target's owner that an edge
+        // has been added.
+        if (self.process_group_.trigger_context() == graph::parallel::trc_out_of_band)
+          send_oob(self.process_group_, target.owner, msg_nonlocal_edge,
+                   msg_nonlocal_edge_data(result.first.local, property));
+        else
+          send(self.process_group_, target.owner, msg_nonlocal_edge,
+               msg_nonlocal_edge_data(result.first.local, property));
+      }
+    }
+
+    return result;
+  }
+
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  std::pair<typename PBGL_DISTRIB_ADJLIST_TYPE::edge_descriptor, bool>
+  PBGL_DISTRIB_ADJLIST_TYPE::lazy_add_edge::
+  add_local_edge(const edge_property_type& property, undirectedS) const
+  {
+    // Add the directed edge
+    std::pair<edge_descriptor, bool> result
+      = this->add_local_edge(property, directedS());
+
+    typedef detail::parallel::stored_in_edge<local_edge_descriptor>
+      stored_edge;
+
+    if (result.second) {
+      if (target.owner == self.processor()) {
+        // Edge is local, so add the new edge to the list
+
+        // TODO: This is not what we want to do for an undirected
+        // edge, because we haven't linked the source and target's
+        // representations of those edges.
+        local_edge_descriptor return_edge =
+          detail::parallel::add_local_edge(target.local, source.local,
+                                           self.build_edge_property(property),
+                                           self.base()).first;
+
+        put(edge_target_processor_id, self.base(), return_edge, 
+            source.owner);
+      }
+      else {
+        // Edge is remote, so notify the target's owner that an edge
+        // has been added.
+        if (self.process_group_.trigger_context() == graph::parallel::trc_out_of_band)
+          send_oob(self.process_group_, target.owner, msg_nonlocal_edge,
+                   msg_nonlocal_edge_data(result.first.local, property));
+        else
+          send(self.process_group_, target.owner, msg_nonlocal_edge,
+               msg_nonlocal_edge_data(result.first.local, property));
+          
+      }
+
+      // Add this edge to the list of local edges
+      graph_detail::push(self.local_edges(), result.first);
+    }
+
+    return result;
+  }
+
+
+  /** 
+   * Data structure returned from add_edge that will "lazily" add
+   * the edge with its property, either when it is converted to a
+   * pair<edge_descriptor, bool> or when the most recent copy has
+   * been destroyed.
+   */
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  struct PBGL_DISTRIB_ADJLIST_TYPE::lazy_add_edge_with_property
+    : lazy_add_edge
+  {
+    /// Construct a lazy request to add an edge
+    lazy_add_edge_with_property(adjacency_list& self, 
+                                vertex_descriptor source, 
+                                vertex_descriptor target,
+                                const edge_property_type& property)
+      : lazy_add_edge(self, source, target), property(property) { }
+
+    /// Copying a lazy_add_edge transfers the responsibility for
+    /// adding the edge to the newly-constructed object.
+    lazy_add_edge_with_property(const lazy_add_edge& other)
+      : lazy_add_edge(other), property(other.property) { }
+
+    /// If the edge has not yet been added, add the edge but don't
+    /// wait for a reply.
+    ~lazy_add_edge_with_property();
+
+    /// Returns commit().
+    operator std::pair<edge_descriptor, bool>() const { return commit(); }
+
+    // Add the edge. This operation will block if a remote edge is
+    // being added.
+    std::pair<edge_descriptor, bool> commit() const;
+
+  private:
+    // No copy-assignment semantics
+    void operator=(lazy_add_edge_with_property&);
+
+    edge_property_type property;
+  };
+
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  PBGL_DISTRIB_ADJLIST_TYPE::lazy_add_edge_with_property::
+  ~lazy_add_edge_with_property()
+  {
+    /// If this edge has already been created or will be created by
+    /// someone else, or if someone threw an exception, we will not
+    /// create the edge now.
+    if (this->committed || std::uncaught_exception())
+      return;
+
+    this->committed = true;
+
+    if (this->source.owner == this->self.processor())
+      // Add a local edge
+      this->add_local_edge(property, DirectedS());
+    else
+      // Request that the remote processor add an edge and, but
+      // don't wait for a reply.
+      send(this->self.process_group_, this->source.owner, 
+           msg_add_edge_with_property,
+           msg_add_edge_with_property_data(this->source, this->target, 
+                                           property));
+  }
+
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  std::pair<typename PBGL_DISTRIB_ADJLIST_TYPE::edge_descriptor, bool>
+  PBGL_DISTRIB_ADJLIST_TYPE::lazy_add_edge_with_property::
+  commit() const
+  {
+    assert(!this->committed);
+    this->committed = true;
+
+    if (this->source.owner == this->self.processor())
+      // Add a local edge
+      return this->add_local_edge(property, DirectedS());
+    else {
+      // Request that the remote processor add an edge
+      boost::parallel::detail::untracked_pair<edge_descriptor, bool> result;
+      send_oob_with_reply(this->self.process_group_, this->source.owner, 
+                          msg_add_edge_with_property_and_reply,
+                          msg_add_edge_with_property_data(this->source, 
+                                                          this->target, 
+                                                          property),
+                          result);
+      return result;
+    }
+  }
+
+
+  /**
+   * Returns the set of vertices local to this processor. Note that
+   * although this routine matches a valid expression of a
+   * VertexListGraph, it does not meet the semantic requirements of
+   * VertexListGraph because it returns only local vertices (not all
+   * vertices).
+   */
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  std::pair<typename PBGL_DISTRIB_ADJLIST_TYPE
+                       ::vertex_iterator,
+            typename PBGL_DISTRIB_ADJLIST_TYPE
+                       ::vertex_iterator>
+  vertices(const PBGL_DISTRIB_ADJLIST_TYPE& g)
+  {
+    typedef typename PBGL_DISTRIB_ADJLIST_TYPE
+      ::vertex_descriptor Vertex;
+
+    typedef typename Vertex::generator generator;
+
+    return std::make_pair(make_transform_iterator(vertices(g.base()).first,
+                                                  generator(g.processor())),
+                          make_transform_iterator(vertices(g.base()).second,
+                                                  generator(g.processor())));
+  }
+
+  /**
+   * Returns the number of vertices local to this processor. Note that
+   * although this routine matches a valid expression of a
+   * VertexListGraph, it does not meet the semantic requirements of
+   * VertexListGraph because it returns only a count of local vertices
+   * (not all vertices).
+   */
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  typename PBGL_DISTRIB_ADJLIST_TYPE
+             ::vertices_size_type
+  num_vertices(const PBGL_DISTRIB_ADJLIST_TYPE& g)
+  {
+    return num_vertices(g.base());
+  }
+
+  /***************************************************************************
+   * Implementation of Incidence Graph concept
+   ***************************************************************************/
+  /**
+   * Returns the source of edge @param e in @param g.
+   */
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS, typename Edge>
+  typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor
+  source(const detail::parallel::edge_descriptor<Edge>& e,
+         const PBGL_DISTRIB_ADJLIST_TYPE& g)
+  {
+    typedef typename PBGL_DISTRIB_ADJLIST_TYPE
+      ::vertex_descriptor Vertex;
+    return Vertex(e.source_processor, source(e.local, g.base()));
+  }
+
+  /**
+   * Returns the target of edge @param e in @param g.
+   */
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS, typename Edge>
+  typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor
+  target(const detail::parallel::edge_descriptor<Edge>& e,
+         const PBGL_DISTRIB_ADJLIST_TYPE& g)
+  {
+    typedef typename PBGL_DISTRIB_ADJLIST_TYPE
+      ::vertex_descriptor Vertex;
+    return Vertex(e.target_processor, target(e.local, g.base()));
+  }
+
+  /**
+   * Return the set of edges outgoing from a particular vertex. The
+   * vertex @param v must be local to the processor executing this
+   * routine.
+   */
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  std::pair<typename PBGL_DISTRIB_ADJLIST_TYPE::out_edge_iterator,
+            typename PBGL_DISTRIB_ADJLIST_TYPE::out_edge_iterator>
+  out_edges(typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor v,
+            const PBGL_DISTRIB_ADJLIST_TYPE& g)
+  {
+    assert(v.owner == g.processor());
+
+    typedef PBGL_DISTRIB_ADJLIST_TYPE impl;
+    typedef typename impl::out_edge_generator generator;
+
+    return std::make_pair(
+             make_transform_iterator(out_edges(v.local, g.base()).first,
+                                     generator(g)),
+             make_transform_iterator(out_edges(v.local, g.base()).second,
+                                     generator(g)));
+  }
+
+  /**
+   * Return the number of edges outgoing from a particular vertex. The
+   * vertex @param v must be local to the processor executing this
+   * routine.
+   */
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  typename PBGL_DISTRIB_ADJLIST_TYPE::degree_size_type
+  out_degree(typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor v,
+             const PBGL_DISTRIB_ADJLIST_TYPE& g)
+  {
+    assert(v.owner == g.processor());
+
+    return out_degree(v.local, g.base());
+  }
+
+  /***************************************************************************
+   * Implementation of Bidirectional Graph concept
+   ***************************************************************************/
+  /**
+   * Returns the set of edges incoming to a particular vertex. The
+   * vertex @param v must be local to the processor executing this
+   * routine.
+   */
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG>
+  std::pair<typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS)
+                       ::in_edge_iterator,
+            typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS)
+                       ::in_edge_iterator>
+  in_edges(typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS)
+                         ::vertex_descriptor v,
+           const PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS)& g)
+  {
+    assert(v.owner == g.processor());
+
+    typedef PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS) impl;
+    typedef typename impl::inherited base_graph_type;
+    typedef typename impl::in_edge_generator generator;
+
+
+    typename property_map<base_graph_type, vertex_in_edges_t>::const_type
+      in_edges = get(vertex_in_edges, g.base());
+
+    return std::make_pair(make_transform_iterator(in_edges[v.local].begin(),
+                                                  generator(g)),
+                          make_transform_iterator(in_edges[v.local].end(),
+                                                  generator(g)));
+  }
+
+  /**
+   * \overload
+   */
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG>
+  std::pair<typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)
+                       ::in_edge_iterator,
+            typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)
+                       ::in_edge_iterator>
+  in_edges(typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)
+                         ::vertex_descriptor v,
+           const PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)& g)
+  {
+    assert(v.owner == g.processor());
+
+    typedef PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS) impl;
+    typedef typename impl::in_edge_generator generator;
+
+    return std::make_pair(
+              make_transform_iterator(out_edges(v.local, g.base()).first,
+                                     generator(g)),
+             make_transform_iterator(out_edges(v.local, g.base()).second,
+                                     generator(g)));
+  }
+
+  /**
+   * Returns the number of edges incoming to a particular vertex. The
+   * vertex @param v must be local to the processor executing this
+   * routine.
+   */
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG>
+  typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS)::degree_size_type
+  in_degree(typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS)
+                           ::vertex_descriptor v,
+            const PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS)& g)
+  {
+    assert(v.owner == g.processor());
+
+    return get(vertex_in_edges, g.base())[v.local].size();
+  }
+
+  /**
+   * \overload
+   */
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG>
+  typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)::degree_size_type
+  in_degree(typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)
+                           ::vertex_descriptor v,
+            const PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)& g)
+  {
+    assert(v.owner == g.processor());
+
+    return out_degree(v.local, g.base());
+  }
+
+  /**
+   * Returns the number of edges incident on the given vertex. The
+   * vertex @param v must be local to the processor executing this
+   * routine.
+   */
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG>
+  typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)
+                       ::degree_size_type
+  degree(typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)
+                         ::vertex_descriptor v,
+         const PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)& g)
+  {
+    assert(v.owner == g.processor());
+    return out_degree(v.local, g.base());
+  }
+
+  /**
+   * \overload
+   */
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG>
+  typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS)
+                       ::degree_size_type
+  degree(typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS)
+                         ::vertex_descriptor v,
+         const PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS)& g)
+  {
+    assert(v.owner == g.processor());
+    return out_degree(v, g) + in_degree(v, g);
+  }
+
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  typename PBGL_DISTRIB_ADJLIST_TYPE::edges_size_type
+  num_edges(const PBGL_DISTRIB_ADJLIST_TYPE& g)
+  {
+    return num_edges(g.base());
+  }
+
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG>
+  typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)::edges_size_type
+  num_edges(const PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)& g)
+  {
+    return g.local_edges().size();
+  }
+
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  std::pair<
+    typename PBGL_DISTRIB_ADJLIST_TYPE::edge_iterator,
+    typename PBGL_DISTRIB_ADJLIST_TYPE::edge_iterator>
+  edges(const PBGL_DISTRIB_ADJLIST_TYPE& g)
+  {
+    typedef PBGL_DISTRIB_ADJLIST_TYPE impl;
+    typedef typename impl::out_edge_generator generator;
+
+    return std::make_pair(make_transform_iterator(edges(g.base()).first,
+                                                  generator(g)),
+                          make_transform_iterator(edges(g.base()).second,
+                                                  generator(g)));
+  }
+
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG>
+  std::pair<
+    typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)::edge_iterator,
+    typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)::edge_iterator>
+  edges(const PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)& g)
+  {
+    return std::make_pair(g.local_edges().begin(), g.local_edges().end());
+  }
+
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  inline
+  typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor
+  vertex(typename PBGL_DISTRIB_ADJLIST_TYPE::vertices_size_type n,
+         const PBGL_DISTRIB_ADJLIST_TYPE& g)
+  {
+    typedef typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor 
+      vertex_descriptor;
+
+    return vertex_descriptor(g.distribution()(n), g.distribution().local(n));
+  }
+
+  /***************************************************************************
+   * Access to particular edges
+   ***************************************************************************/
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG>
+  std::pair<
+    typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(directedS)::edge_descriptor,
+    bool
+  >
+  edge(typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(directedS)::vertex_descriptor u,
+       typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(directedS)::vertex_descriptor v,
+       const PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(directedS)& g)
+  {
+    typedef typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(directedS)
+                       ::edge_descriptor edge_descriptor;
+
+    // For directed graphs, u must be local
+    assert(u.owner == process_id(g.process_group()));
+
+    typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(directedS)
+        ::out_edge_iterator ei, ei_end;
+    for (tie(ei, ei_end) = out_edges(u, g); ei != ei_end; ++ei) {
+      if (target(*ei, g) == v) return std::make_pair(*ei, true);
+    }
+    return std::make_pair(edge_descriptor(), false);
+  }
+
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  std::pair<
+    typename PBGL_DISTRIB_ADJLIST_TYPE::edge_descriptor,
+    bool
+  >
+  edge(typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor u,
+       typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor v,
+       const PBGL_DISTRIB_ADJLIST_TYPE& g)
+  {
+    typedef typename PBGL_DISTRIB_ADJLIST_TYPE
+                       ::edge_descriptor edge_descriptor;
+
+    // For bidirectional and undirected graphs, u must be local or v
+    // must be local
+    if (u.owner == process_id(g.process_group())) {
+      typename PBGL_DISTRIB_ADJLIST_TYPE::out_edge_iterator ei, ei_end;
+      for (tie(ei, ei_end) = out_edges(u, g); ei != ei_end; ++ei) {
+        if (target(*ei, g) == v) return std::make_pair(*ei, true);
+      }
+      return std::make_pair(edge_descriptor(), false);
+    } else if (v.owner == process_id(g.process_group())) {
+      typename PBGL_DISTRIB_ADJLIST_TYPE::in_edge_iterator ei, ei_end;
+      for (tie(ei, ei_end) = in_edges(v, g); ei != ei_end; ++ei) {
+        if (source(*ei, g) == u) return std::make_pair(*ei, true);
+      }
+      return std::make_pair(edge_descriptor(), false);
+    } else {
+      assert(false);
+      exit(1);
+    }
+  }
+
+#if 0
+  // TBD: not yet supported
+  std::pair<out_edge_iterator, out_edge_iterator>
+  edge_range(vertex_descriptor u, vertex_descriptor v,
+             const adjacency_list& g);
+#endif
+
+  /***************************************************************************
+   * Implementation of Adjacency Graph concept
+   ***************************************************************************/
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  std::pair<typename PBGL_DISTRIB_ADJLIST_TYPE::adjacency_iterator,
+            typename PBGL_DISTRIB_ADJLIST_TYPE::adjacency_iterator>
+  adjacent_vertices(typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor v,
+                    const PBGL_DISTRIB_ADJLIST_TYPE& g)
+  {
+    typedef typename PBGL_DISTRIB_ADJLIST_TYPE::adjacency_iterator iter;
+    return std::make_pair(iter(out_edges(v, g).first, &g),
+                          iter(out_edges(v, g).second, &g));
+  }
+
+  /***************************************************************************
+   * Implementation of Mutable Graph concept
+   ***************************************************************************/
+
+  /************************************************************************
+   * add_edge
+   ************************************************************************/
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  typename PBGL_DISTRIB_ADJLIST_TYPE::lazy_add_edge
+  add_edge(typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor u,
+           typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor v,
+           PBGL_DISTRIB_ADJLIST_TYPE& g)
+  {
+    typedef typename PBGL_DISTRIB_ADJLIST_TYPE::lazy_add_edge lazy_add_edge;
+
+    return lazy_add_edge(g, u, v);
+  }
+
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  typename PBGL_DISTRIB_ADJLIST_TYPE
+    ::lazy_add_edge_with_property
+  add_edge(typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor u,
+           typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor v,
+           typename PBGL_DISTRIB_ADJLIST_TYPE::edge_property_type const& p,
+           PBGL_DISTRIB_ADJLIST_TYPE& g)
+  {
+    typedef typename PBGL_DISTRIB_ADJLIST_TYPE
+      ::lazy_add_edge_with_property lazy_add_edge_with_property;
+    return lazy_add_edge_with_property(g, u, v, p);
+  }
+
+  /************************************************************************
+   *
+   * remove_edge
+   *
+   ************************************************************************/
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  void
+  remove_edge(typename PBGL_DISTRIB_ADJLIST_TYPE::edge_descriptor e,
+              PBGL_DISTRIB_ADJLIST_TYPE& g)
+  {
+    assert(source(e, g).owner == g.processor()
+           || target(e, g).owner == g.processor());
+
+    if (target(e, g).owner == g.processor())
+      detail::parallel::remove_in_edge(e, g, DirectedS());
+    if (source(e, g).owner == g.processor())
+      remove_edge(e.local, g.base());
+
+    g.remove_local_edge_from_list(source(e, g), target(e, g), DirectedS());
+
+    if (source(e, g).owner != g.processor()
+        || (target(e, g).owner != g.processor()
+            && !(is_same<DirectedS, directedS>::value))) {
+      g.send_remove_edge_request(e);
+    }
+  }
+
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  void
+  remove_edge(typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor u,
+              typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor v,
+              PBGL_DISTRIB_ADJLIST_TYPE& g)
+  {
+    typedef typename PBGL_DISTRIB_ADJLIST_TYPE
+                       ::vertex_descriptor vertex_descriptor;
+    typedef typename PBGL_DISTRIB_ADJLIST_TYPE
+                       ::edge_descriptor edge_descriptor;
+    std::pair<edge_descriptor, bool> the_edge = edge(u, v, g);
+    if (the_edge.second) remove_edge(the_edge.first, g);
+  }
+
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  inline void
+  remove_edge(typename PBGL_DISTRIB_ADJLIST_TYPE::out_edge_iterator ei,
+              PBGL_DISTRIB_ADJLIST_TYPE& g)
+  {
+    remove_edge(*ei, g);
+  }
+
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG>
+  inline void
+  remove_edge(typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(directedS)
+                ::out_edge_iterator ei,
+              PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(directedS)& g)
+  {
+    assert(source(*ei, g).owner == g.processor());
+    remove_edge(ei->local, g.base());
+  }
+
+  /************************************************************************
+   *
+   * remove_out_edge_if
+   *
+   ************************************************************************/
+  namespace parallel { namespace detail {
+    /**
+     * Function object that applies the underlying predicate to
+     * determine if an out-edge should be removed. If so, either
+     * removes the incoming edge (if it is stored locally) or sends a
+     * message to the owner of the target requesting that it remove
+     * the edge.
+     */
+    template<typename Graph, typename Predicate>
+    struct remove_out_edge_predicate
+    {
+      typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
+      typedef typename Graph::local_edge_descriptor         argument_type;
+      typedef typename Graph::directed_selector             directed_selector;
+      typedef bool result_type;
+
+      remove_out_edge_predicate(Graph& g, Predicate& predicate)
+        : g(g), predicate(predicate) { }
+
+      bool operator()(const argument_type& le)
+      {
+        typedef typename edge_descriptor::template out_generator<Graph>
+          generator;
+
+        edge_descriptor e = generator(g)(le);
+
+        if (predicate(e)) {
+          if (source(e, g).owner != target(e, g).owner
+              && !(is_same<directed_selector, directedS>::value))
+            g.send_remove_edge_request(e);
+          else
+            ::boost::detail::parallel::remove_in_edge(e, g,
+                                                      directed_selector());
+
+           g.remove_local_edge_from_list(source(e, g), target(e, g),
+                                         directed_selector());
+          return true;
+        } else return false;
+      }
+
+    private:
+      Graph& g;
+      Predicate predicate;
+    };
+  } } // end namespace parallel::detail
+
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS, typename Predicate>
+  inline void
+  remove_out_edge_if
+     (typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor u,
+      Predicate predicate,
+      PBGL_DISTRIB_ADJLIST_TYPE& g)
+  {
+    typedef PBGL_DISTRIB_ADJLIST_TYPE Graph;
+    typedef parallel::detail::remove_out_edge_predicate<Graph, Predicate>
+      Pred;
+
+    assert(u.owner == g.processor());
+    remove_out_edge_if(u.local, Pred(g, predicate), g.base());
+  }
+
+  /************************************************************************
+   *
+   * remove_in_edge_if
+   *
+   ************************************************************************/
+  namespace parallel { namespace detail {
+    /**
+     * Function object that applies the underlying predicate to
+     * determine if an in-edge should be removed. If so, either
+     * removes the outgoing edge (if it is stored locally) or sends a
+     * message to the owner of the target requesting that it remove
+     * the edge. Only required for bidirectional graphs.
+     */
+    template<typename Graph, typename Predicate>
+    struct remove_in_edge_predicate
+    {
+      typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
+      typedef bool result_type;
+
+      remove_in_edge_predicate(Graph& g, const Predicate& predicate)
+        : g(g), predicate(predicate) { }
+
+      template<typename StoredEdge>
+      bool operator()(const StoredEdge& le)
+      {
+        typedef typename edge_descriptor::template in_generator<Graph>
+          generator;
+
+        edge_descriptor e = generator(g)(le);
+
+        if (predicate(e)) {
+          if (source(e, g).owner != target(e, g).owner)
+            g.send_remove_edge_request(e);
+          else
+            remove_edge(source(e, g).local, target(e, g).local, g.base());
+          return true;
+        } else return false;
+      }
+
+    private:
+      Graph& g;
+      Predicate predicate;
+    };
+  } } // end namespace parallel::detail
+
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG, typename Predicate>
+  inline void
+  remove_in_edge_if
+     (typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS)
+                 ::vertex_descriptor u,
+      Predicate predicate,
+      PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS)& g)
+  {
+    typedef PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS) Graph;
+    typedef parallel::detail::remove_in_edge_predicate<Graph, Predicate>
+      Pred;
+
+    assert(u.owner == g.processor());
+    graph_detail::erase_if(get(vertex_in_edges, g.base())[u.local],
+                           Pred(g, predicate));
+  }
+
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG, typename Predicate>
+  inline void
+  remove_in_edge_if
+     (typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)
+                 ::vertex_descriptor u,
+      Predicate predicate,
+      PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)& g)
+  {
+    remove_out_edge_if(u, predicate, g);
+  }
+
+  /************************************************************************
+   *
+   * remove_edge_if
+   *
+   ************************************************************************/
+  namespace parallel { namespace detail {
+    /**
+     * Function object that applies the underlying predicate to
+     * determine if a directed edge can be removed. This only applies
+     * to directed graphs.
+     */
+    template<typename Graph, typename Predicate>
+    struct remove_directed_edge_predicate
+    {
+      typedef typename Graph::local_edge_descriptor argument_type;
+      typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
+      typedef bool result_type;
+
+      remove_directed_edge_predicate(Graph& g, const Predicate& predicate)
+        : g(g), predicate(predicate) { }
+
+      bool operator()(const argument_type& le)
+      {
+        typedef typename edge_descriptor::template out_generator<Graph>
+          generator;
+
+        edge_descriptor e = generator(g)(le);
+        return predicate(e);
+      }
+
+    private:
+      Graph& g;
+      Predicate predicate;
+    };
+  } } // end namespace parallel::detail
+
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG, typename Predicate>
+  inline void
+  remove_edge_if(Predicate predicate, 
+                 PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(directedS)& g)
+  {
+    typedef PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(directedS) Graph;
+    typedef parallel::detail::remove_directed_edge_predicate<Graph,
+                                                             Predicate> Pred;
+    remove_edge_if(Pred(g, predicate), g.base());
+  }
+
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG, typename Predicate>
+  inline void
+  remove_edge_if(Predicate predicate,
+                 PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS)& g)
+  {
+    typedef PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS) Graph;
+    typedef parallel::detail::remove_out_edge_predicate<Graph,
+                                                        Predicate> Pred;
+    remove_edge_if(Pred(g, predicate), g.base());
+  }
+
+  namespace parallel { namespace detail {
+    /**
+     * Function object that applies the underlying predicate to
+     * determine if an undirected edge should be removed. If so,
+     * removes the local edges associated with the edge and
+     * (potentially) sends a message to the remote processor that also
+     * is removing this edge.
+     */
+    template<typename Graph, typename Predicate>
+    struct remove_undirected_edge_predicate
+    {
+      typedef typename graph_traits<Graph>::edge_descriptor argument_type;
+      typedef bool result_type;
+
+      remove_undirected_edge_predicate(Graph& g, Predicate& predicate)
+        : g(g), predicate(predicate) { }
+
+      bool operator()(const argument_type& e)
+      {
+        if (predicate(e)) {
+          if (source(e, g).owner != target(e, g).owner)
+            g.send_remove_edge_request(e);
+          if (target(e, g).owner == g.processor())
+            ::boost::detail::parallel::remove_in_edge(e, g, undirectedS());
+          if (source(e, g).owner == g.processor())
+            remove_edge(e.local, g.base());
+          return true;
+        } else return false;
+      }
+
+    private:
+      Graph& g;
+      Predicate predicate;
+    };
+  } } // end namespace parallel::detail
+
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG, typename Predicate>
+  inline void
+  remove_edge_if(Predicate predicate,
+                 PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)& g)
+  {
+    typedef PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS) Graph;
+    typedef parallel::detail::remove_undirected_edge_predicate<Graph,
+                                                               Predicate> Pred;
+    graph_detail::erase_if(g.local_edges(), Pred(g, predicate));
+  }
+
+  /************************************************************************
+   *
+   * clear_vertex
+   *
+   ************************************************************************/
+  namespace parallel { namespace detail {
+    struct always_true
+    {
+      typedef bool result_type;
+
+      template<typename T> bool operator()(const T&) const { return true; }
+    };
+  } } // end namespace parallel::detail
+
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG>
+  void
+  clear_vertex
+    (typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS)
+          ::vertex_descriptor u,
+      PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS)& g)
+  {
+    clear_out_edges(u, g);
+    clear_in_edges(u, g);
+  }
+
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG>
+  void
+  clear_vertex
+    (typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)
+                ::vertex_descriptor u,
+      PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)& g)
+  {
+    remove_out_edge_if(u, parallel::detail::always_true(), g);
+  }
+
+  /************************************************************************
+   *
+   * clear_out_edges
+   *
+   ************************************************************************/
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG>
+  void
+  clear_out_edges
+    (typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(directedS)::vertex_descriptor u,
+      PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(directedS)& g)
+  {
+    assert(u.owner == g.processor());
+    clear_out_edges(u.local, g.base());
+  }
+
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG>
+  void
+  clear_out_edges
+    (typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS)
+                ::vertex_descriptor u,
+      PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS)& g)
+  {
+    remove_out_edge_if(u, parallel::detail::always_true(), g);
+  }
+
+  /************************************************************************
+   *
+   * clear_in_edges
+   *
+   ************************************************************************/
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG>
+  void
+  clear_in_edges
+    (typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS)
+                ::vertex_descriptor u,
+      PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS)& g)
+  {
+    remove_in_edge_if(u, parallel::detail::always_true(), g);
+  }
+
+  /************************************************************************
+   *
+   * add_vertex
+   *
+   ************************************************************************/
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor
+  add_vertex(PBGL_DISTRIB_ADJLIST_TYPE& g)
+  {
+    typedef PBGL_DISTRIB_ADJLIST_TYPE graph_type;
+    typename graph_type::vertex_property_type p;
+    return add_vertex(p, g);
+  }
+
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  typename PBGL_DISTRIB_ADJLIST_TYPE::lazy_add_vertex_with_property
+  add_vertex(typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_property_type const& p,
+             PBGL_DISTRIB_ADJLIST_TYPE& g)
+  {
+    typedef typename PBGL_DISTRIB_ADJLIST_TYPE
+                       ::lazy_add_vertex_with_property lazy_add_vertex;
+    return lazy_add_vertex(g, p);
+  }
+
+  /************************************************************************
+   *
+   * remove_vertex
+   *
+   ************************************************************************/
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  void
+  remove_vertex(typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor u,
+                PBGL_DISTRIB_ADJLIST_TYPE& g)
+  {
+    typedef typename PBGL_DISTRIB_ADJLIST_TYPE::graph_type graph_type;
+    typedef typename graph_type::named_graph_mixin named_graph_mixin;
+    assert(u.owner == g.processor());
+    static_cast<named_graph_mixin&>(static_cast<graph_type&>(g))
+      .removing_vertex(u);
+    g.distribution().clear();
+    remove_vertex(u.local, g.base());
+  }
+
+  /***************************************************************************
+   * Implementation of Property Graph concept
+   ***************************************************************************/
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS, typename Property>
+  struct property_map<PBGL_DISTRIB_ADJLIST_TYPE, Property>
+  : detail::parallel::get_adj_list_pmap<Property>
+      ::template apply<PBGL_DISTRIB_ADJLIST_TYPE>
+  { };
+
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS, typename Property>
+  struct property_map<PBGL_DISTRIB_ADJLIST_TYPE const, Property>
+          : boost::detail::parallel::get_adj_list_pmap<Property>
+// FIXME: in the original code the following was not const
+      ::template apply<PBGL_DISTRIB_ADJLIST_TYPE const>
+  { };
+
+  template<typename Property, PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, Property>::type
+  get(Property p, PBGL_DISTRIB_ADJLIST_TYPE& g)
+  {
+    typedef PBGL_DISTRIB_ADJLIST_TYPE Graph;
+    typedef typename property_map<Graph, Property>::type result_type;
+    typedef typename property_traits<result_type>::value_type value_type;
+    typedef typename property_reduce<Property>::template apply<value_type>
+      reduce;
+
+    typedef typename property_traits<result_type>::key_type descriptor;
+    typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
+    typedef typename mpl::if_<is_same<descriptor, vertex_descriptor>,
+                              vertex_global_t, edge_global_t>::type
+      global_map_t;
+
+    return result_type(g.process_group(), get(global_map_t(), g),
+                       get(p, g.base()), reduce());
+  }
+
+  template<typename Property, PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, Property>::const_type
+  get(Property p, const PBGL_DISTRIB_ADJLIST_TYPE& g)
+  {
+    typedef PBGL_DISTRIB_ADJLIST_TYPE Graph;
+    typedef typename property_map<Graph, Property>::const_type result_type;
+    typedef typename property_traits<result_type>::value_type value_type;
+    typedef typename property_reduce<Property>::template apply<value_type>
+      reduce;
+
+    typedef typename property_traits<result_type>::key_type descriptor;
+    typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
+    typedef typename mpl::if_<is_same<descriptor, vertex_descriptor>,
+                              vertex_global_t, edge_global_t>::type
+      global_map_t;
+
+    return result_type(g.process_group(), get(global_map_t(), g),
+                       get(p, g.base()), reduce());
+  }
+
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, vertex_local_index_t>::type
+  get(vertex_local_index_t, PBGL_DISTRIB_ADJLIST_TYPE& g)
+  {
+    return get(vertex_local_index, g.base());
+  }
+
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  typename property_map<PBGL_DISTRIB_ADJLIST_TYPE,
+                        vertex_local_index_t>::const_type
+  get(vertex_local_index_t, const PBGL_DISTRIB_ADJLIST_TYPE& g)
+  {
+    return get(vertex_local_index, g.base());
+  }
+
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, vertex_global_t>::const_type
+  get(vertex_global_t, const PBGL_DISTRIB_ADJLIST_TYPE& g)
+  {
+    typedef typename property_map<
+                       PBGL_DISTRIB_ADJLIST_TYPE,
+                       vertex_global_t>::const_type result_type;
+    return result_type();
+  }
+
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, vertex_global_t>::const_type
+  get(vertex_global_t, PBGL_DISTRIB_ADJLIST_TYPE& g)
+  {
+    typedef typename property_map<
+                       PBGL_DISTRIB_ADJLIST_TYPE,
+                       vertex_global_t>::const_type result_type;
+    return result_type();
+  }
+
+  /// Retrieve a property map mapping from a vertex descriptor to its
+  /// owner.
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, vertex_owner_t>::type
+  get(vertex_owner_t, PBGL_DISTRIB_ADJLIST_TYPE& g)
+  {
+    typedef typename property_map<
+                       PBGL_DISTRIB_ADJLIST_TYPE,
+                       vertex_owner_t>::type result_type;
+    return result_type();
+  }
+
+  /// Retrieve a property map mapping from a vertex descriptor to its
+  /// owner.
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, vertex_owner_t>::const_type
+  get(vertex_owner_t, const PBGL_DISTRIB_ADJLIST_TYPE& g)
+  {
+    typedef typename property_map<
+                       PBGL_DISTRIB_ADJLIST_TYPE,
+                       vertex_owner_t>::const_type result_type;
+    return result_type();
+  }
+
+  /// Retrieve the owner of a vertex
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  inline processor_id_type
+  get(vertex_owner_t, PBGL_DISTRIB_ADJLIST_TYPE&,
+      typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor v)
+  {
+    return v.owner;
+  }
+
+  /// Retrieve the owner of a vertex
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  inline processor_id_type
+  get(vertex_owner_t, const PBGL_DISTRIB_ADJLIST_TYPE&,
+      typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor v)
+  {
+    return v.owner;
+  }
+
+  /// Retrieve a property map that maps from a vertex descriptor to
+  /// its local descriptor.
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, vertex_local_t>::type
+  get(vertex_local_t, PBGL_DISTRIB_ADJLIST_TYPE& g)
+  {
+    typedef typename property_map<
+                       PBGL_DISTRIB_ADJLIST_TYPE,
+                       vertex_local_t>::type result_type;
+    return result_type();
+  }
+
+  /// Retrieve a property map that maps from a vertex descriptor to
+  /// its local descriptor.
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, vertex_local_t>::const_type
+  get(vertex_local_t, const PBGL_DISTRIB_ADJLIST_TYPE& g)
+  {
+    typedef typename property_map<
+                       PBGL_DISTRIB_ADJLIST_TYPE,
+                       vertex_local_t>::const_type result_type;
+    return result_type();
+  }
+
+  /// Retrieve the local descriptor of a vertex
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  inline typename PBGL_DISTRIB_ADJLIST_TYPE::local_vertex_descriptor
+  get(vertex_local_t, PBGL_DISTRIB_ADJLIST_TYPE&,
+      typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor v)
+  {
+    return v.local;
+  }
+
+  /// Retrieve the local descriptor of a vertex
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  inline typename PBGL_DISTRIB_ADJLIST_TYPE::local_vertex_descriptor
+  get(vertex_local_t, const PBGL_DISTRIB_ADJLIST_TYPE&,
+      typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor v)
+  {
+    return v.local;
+  }
+
+
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, edge_global_t>::const_type
+  get(edge_global_t, const PBGL_DISTRIB_ADJLIST_TYPE& g)
+  {
+    typedef typename property_map<
+                       PBGL_DISTRIB_ADJLIST_TYPE,
+                       edge_global_t>::const_type result_type;
+    return result_type();
+  }
+
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, edge_global_t>::const_type
+  get(edge_global_t, PBGL_DISTRIB_ADJLIST_TYPE& g)
+  {
+    typedef typename property_map<
+                       PBGL_DISTRIB_ADJLIST_TYPE,
+                       edge_global_t>::const_type result_type;
+    return result_type();
+  }
+
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, edge_owner_t>::type
+  get(edge_owner_t, PBGL_DISTRIB_ADJLIST_TYPE& g)
+  {
+    typedef typename property_map<
+                       PBGL_DISTRIB_ADJLIST_TYPE,
+                       edge_owner_t>::type result_type;
+    return result_type();
+  }
+
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, edge_owner_t>::const_type
+  get(edge_owner_t, const PBGL_DISTRIB_ADJLIST_TYPE& g)
+  {
+    typedef typename property_map<
+                       PBGL_DISTRIB_ADJLIST_TYPE,
+                       edge_owner_t>::const_type result_type;
+    return result_type();
+  }
+
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, edge_local_t>::type
+  get(edge_local_t, PBGL_DISTRIB_ADJLIST_TYPE& g)
+  {
+    typedef typename property_map<
+                       PBGL_DISTRIB_ADJLIST_TYPE,
+                       edge_local_t>::type result_type;
+    return result_type();
+  }
+
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, edge_local_t>::const_type
+  get(edge_local_t, const PBGL_DISTRIB_ADJLIST_TYPE& g)
+  {
+    typedef typename property_map<
+                       PBGL_DISTRIB_ADJLIST_TYPE,
+                       edge_local_t>::const_type result_type;
+    return result_type();
+  }
+
+  template<typename Property, PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS,
+           typename Key>
+  inline
+  typename property_traits<typename property_map<
+                PBGL_DISTRIB_ADJLIST_TYPE, Property>::const_type
+           >::value_type
+  get(Property p, const PBGL_DISTRIB_ADJLIST_TYPE& g, const Key& key)
+  {
+    if (owner(key) == process_id(g.process_group()))
+      return get(p, g.base(), local(key));
+    else
+      assert(false);
+  }
+
+  template<typename Property, PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS,
+           typename Key, typename Value>
+  void
+  put(Property p, PBGL_DISTRIB_ADJLIST_TYPE& g, const Key& key, const Value& v)
+  {
+    if (owner(key) == process_id(g.process_group()))
+      put(p, g.base(), local(key), v);
+    else
+      assert(false);
+  }
+
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, vertex_index_t>::type
+  get(vertex_index_t vi, PBGL_DISTRIB_ADJLIST_TYPE& g)
+  {
+    typedef PBGL_DISTRIB_ADJLIST_TYPE graph_type;
+    typedef typename property_map<graph_type, vertex_index_t>::type
+      result_type;
+    return result_type(g.process_group(), get(vertex_global, g),
+                       get(vi, g.base()));
+  }
+
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, vertex_index_t>::const_type
+  get(vertex_index_t vi, const PBGL_DISTRIB_ADJLIST_TYPE& g)
+  {
+    typedef PBGL_DISTRIB_ADJLIST_TYPE graph_type;
+    typedef typename property_map<graph_type, vertex_index_t>::const_type
+      result_type;
+    return result_type(g.process_group(), get(vertex_global, g),
+                       get(vi, g.base()));
+  }
+
+  /***************************************************************************
+   * Implementation of bundled properties
+   ***************************************************************************/
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS, typename T, typename Bundle>
+  struct property_map<PBGL_DISTRIB_ADJLIST_TYPE, T Bundle::*>
+    : detail::parallel::get_adj_list_pmap<T Bundle::*>
+      ::template apply<PBGL_DISTRIB_ADJLIST_TYPE>
+  { };
+
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS, typename T, typename Bundle>
+  struct property_map<PBGL_DISTRIB_ADJLIST_TYPE const, T Bundle::*>
+    : detail::parallel::get_adj_list_pmap<T Bundle::*>
+      ::template apply<PBGL_DISTRIB_ADJLIST_TYPE const>
+  { };
+
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS, typename T, typename Bundle>
+  typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, T Bundle::*>::type
+  get(T Bundle::* p, PBGL_DISTRIB_ADJLIST_TYPE& g)
+  {
+    typedef PBGL_DISTRIB_ADJLIST_TYPE Graph;
+    typedef typename property_map<Graph, T Bundle::*>::type result_type;
+    typedef typename property_traits<result_type>::value_type value_type;
+    typedef typename property_reduce<T Bundle::*>::template apply<value_type>
+      reduce;
+
+    typedef typename property_traits<result_type>::key_type descriptor;
+    typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
+    typedef typename mpl::if_<is_same<descriptor, vertex_descriptor>,
+                              vertex_global_t, edge_global_t>::type
+      global_map_t;
+
+    return result_type(g.process_group(), get(global_map_t(), g),
+                       get(p, g.base()), reduce());
+  }
+
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS, typename T, typename Bundle>
+  typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, T Bundle::*>::const_type
+  get(T Bundle::* p, const PBGL_DISTRIB_ADJLIST_TYPE& g)
+  {
+    typedef PBGL_DISTRIB_ADJLIST_TYPE Graph;
+    typedef typename property_map<Graph, T Bundle::*>::const_type result_type;
+    typedef typename property_traits<result_type>::value_type value_type;
+    typedef typename property_reduce<T Bundle::*>::template apply<value_type>
+      reduce;
+
+    typedef typename property_traits<result_type>::key_type descriptor;
+    typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
+    typedef typename mpl::if_<is_same<descriptor, vertex_descriptor>,
+                              vertex_global_t, edge_global_t>::type
+      global_map_t;
+
+    return result_type(g.process_group(), get(global_map_t(), g),
+                       get(p, g.base()), reduce());
+  }
+
+  /***************************************************************************
+   * Implementation of DistributedGraph concept
+   ***************************************************************************/
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  void synchronize(const PBGL_DISTRIB_ADJLIST_TYPE& g)
+  {
+    typedef PBGL_DISTRIB_ADJLIST_TYPE graph_type;
+    synchronize(g.process_group());
+  }
+
+  template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
+  ProcessGroup
+  process_group(const PBGL_DISTRIB_ADJLIST_TYPE& g)
+  { return g.process_group(); }
+
+  /***************************************************************************
+   * Specializations of is_mpi_datatype for Serializable entities
+   ***************************************************************************/
+  namespace mpi {
+    template<typename Directed, typename Vertex>
+    struct is_mpi_datatype<boost::detail::edge_base<Directed, Vertex> >
+      : is_mpi_datatype<Vertex> { };
+
+    template<typename Directed, typename Vertex>
+    struct is_mpi_datatype<boost::detail::edge_desc_impl<Directed, Vertex> >
+      : is_mpi_datatype<boost::detail::edge_base<Directed, Vertex> > { };
+
+    template<typename LocalDescriptor>
+    struct is_mpi_datatype<boost::detail::parallel::global_descriptor<LocalDescriptor> >
+      : is_mpi_datatype<LocalDescriptor> { };
+
+    template<typename Edge>
+    struct is_mpi_datatype<boost::detail::parallel::edge_descriptor<Edge> >
+      : is_mpi_datatype<Edge> { };
+
+    template<typename Vertex, typename LocalVertex>
+    struct is_mpi_datatype<boost::detail::parallel::
+                             msg_add_edge_data<Vertex, LocalVertex> >
+      : is_mpi_datatype<Vertex> { };
+
+    template<typename Vertex, typename LocalVertex, typename EdgeProperty>
+    struct is_mpi_datatype<boost::detail::parallel::
+                             msg_add_edge_with_property_data<Vertex, 
+                                                             LocalVertex,
+                                                             EdgeProperty> >
+      : mpl::and_<is_mpi_datatype<Vertex>, is_mpi_datatype<EdgeProperty> > { };
+
+
+   template<typename EdgeProperty, typename EdgeDescriptor>
+   struct is_mpi_datatype<boost::detail::parallel::msg_nonlocal_edge_data<
+                          EdgeProperty,EdgeDescriptor> >
+           : mpl::and_<
+               is_mpi_datatype<boost::detail::parallel::maybe_store_property<
+                           EdgeProperty> >,
+           is_mpi_datatype<EdgeDescriptor> >
+  {};
+   
+   template<typename EdgeDescriptor>
+   struct is_mpi_datatype<
+            boost::detail::parallel::msg_remove_edge_data<EdgeDescriptor> >
+           : is_mpi_datatype<EdgeDescriptor> {};
+  }
+
+  /***************************************************************************
+   * Specializations of is_bitwise_serializable for Serializable entities
+   ***************************************************************************/
+  namespace serialization {
+    template<typename Directed, typename Vertex>
+    struct is_bitwise_serializable<boost::detail::edge_base<Directed, Vertex> >
+      : is_bitwise_serializable<Vertex> { };
+
+    template<typename Directed, typename Vertex>
+    struct is_bitwise_serializable<boost::detail::edge_desc_impl<Directed, Vertex> >
+      : is_bitwise_serializable<boost::detail::edge_base<Directed, Vertex> > { };
+
+    template<typename LocalDescriptor>
+    struct is_bitwise_serializable<boost::detail::parallel::global_descriptor<LocalDescriptor> >
+      : is_bitwise_serializable<LocalDescriptor> { };
+
+    template<typename Edge>
+    struct is_bitwise_serializable<boost::detail::parallel::edge_descriptor<Edge> >
+      : is_bitwise_serializable<Edge> { };
+
+    template<typename Vertex, typename LocalVertex>
+    struct is_bitwise_serializable<boost::detail::parallel::
+                             msg_add_edge_data<Vertex, LocalVertex> >
+      : is_bitwise_serializable<Vertex> { };
+
+    template<typename Vertex, typename LocalVertex, typename EdgeProperty>
+    struct is_bitwise_serializable<boost::detail::parallel::
+                             msg_add_edge_with_property_data<Vertex, 
+                                                             LocalVertex,
+                                                             EdgeProperty> >
+      : mpl::and_<is_bitwise_serializable<Vertex>, 
+                  is_bitwise_serializable<EdgeProperty> > { };
+
+   template<typename EdgeProperty, typename EdgeDescriptor>
+   struct is_bitwise_serializable<boost::detail::parallel::msg_nonlocal_edge_data<
+                                  EdgeProperty,EdgeDescriptor> >
+           : mpl::and_<
+               is_bitwise_serializable<
+                boost::detail::parallel::maybe_store_property<EdgeProperty> >,
+           is_bitwise_serializable<EdgeDescriptor> >
+  {};
+   
+   template<typename EdgeDescriptor>
+   struct is_bitwise_serializable<
+            boost::detail::parallel::msg_remove_edge_data<EdgeDescriptor> >
+           : is_bitwise_serializable<EdgeDescriptor> {};
+   
+    template<typename Directed, typename Vertex>
+    struct implementation_level<boost::detail::edge_base<Directed, Vertex> >
+      : mpl::int_<object_serializable> {};
+
+    template<typename Directed, typename Vertex>
+    struct implementation_level<boost::detail::edge_desc_impl<Directed, Vertex> >
+      : mpl::int_<object_serializable> {};
+
+    template<typename LocalDescriptor>
+    struct implementation_level<boost::detail::parallel::global_descriptor<LocalDescriptor> >
+      : mpl::int_<object_serializable> {};
+
+    template<typename Edge>
+    struct implementation_level<boost::detail::parallel::edge_descriptor<Edge> >
+      : mpl::int_<object_serializable> {};
+
+    template<typename Vertex, typename LocalVertex>
+    struct implementation_level<boost::detail::parallel::
+                             msg_add_edge_data<Vertex, LocalVertex> >
+      : mpl::int_<object_serializable> {};
+
+    template<typename Vertex, typename LocalVertex, typename EdgeProperty>
+    struct implementation_level<boost::detail::parallel::
+                             msg_add_edge_with_property_data<Vertex, 
+                                                             LocalVertex,
+                                                             EdgeProperty> >
+      : mpl::int_<object_serializable> {};
+
+   template<typename EdgeProperty, typename EdgeDescriptor>
+   struct implementation_level<boost::detail::parallel::msg_nonlocal_edge_data<
+                               EdgeProperty,EdgeDescriptor> >
+           : mpl::int_<object_serializable> {};
+   
+   template<typename EdgeDescriptor>
+   struct implementation_level<
+            boost::detail::parallel::msg_remove_edge_data<EdgeDescriptor> >
+          : mpl::int_<object_serializable> {};
+   
+    template<typename Directed, typename Vertex>
+    struct tracking_level<boost::detail::edge_base<Directed, Vertex> >
+      : mpl::int_<track_never> {};
+
+    template<typename Directed, typename Vertex>
+    struct tracking_level<boost::detail::edge_desc_impl<Directed, Vertex> >
+      : mpl::int_<track_never> {};
+
+    template<typename LocalDescriptor>
+    struct tracking_level<boost::detail::parallel::global_descriptor<LocalDescriptor> >
+      : mpl::int_<track_never> {};
+
+    template<typename Edge>
+    struct tracking_level<boost::detail::parallel::edge_descriptor<Edge> >
+      : mpl::int_<track_never> {};
+
+    template<typename Vertex, typename LocalVertex>
+    struct tracking_level<boost::detail::parallel::
+                             msg_add_edge_data<Vertex, LocalVertex> >
+      : mpl::int_<track_never> {};
+
+    template<typename Vertex, typename LocalVertex, typename EdgeProperty>
+    struct tracking_level<boost::detail::parallel::
+                             msg_add_edge_with_property_data<Vertex, 
+                                                             LocalVertex,
+                                                             EdgeProperty> >
+      : mpl::int_<track_never> {};
+
+   template<typename EdgeProperty, typename EdgeDescriptor>
+   struct tracking_level<boost::detail::parallel::msg_nonlocal_edge_data<
+                         EdgeProperty,EdgeDescriptor> >
+           : mpl::int_<track_never> {};
+   
+   template<typename EdgeDescriptor>
+   struct tracking_level<
+            boost::detail::parallel::msg_remove_edge_data<EdgeDescriptor> >
+          : mpl::int_<track_never> {};
+  }
+
+  // Hash function for global descriptors
+  template<typename LocalDescriptor>
+  struct hash<detail::parallel::global_descriptor<LocalDescriptor> >
+  {
+    typedef detail::parallel::global_descriptor<LocalDescriptor> argument_type;
+    std::size_t operator()(argument_type const& x) const
+    {
+      std::size_t hash = hash_value(x.owner);
+      hash_combine(hash, x.local);
+      return hash;
+    }
+  };
+
+  // Hash function for parallel edge descriptors
+  template<typename Edge>
+  struct hash<detail::parallel::edge_descriptor<Edge> >
+  {
+    typedef detail::parallel::edge_descriptor<Edge> argument_type;
+
+    std::size_t operator()(argument_type const& x) const
+    {
+      std::size_t hash = hash_value(x.owner());
+      hash_combine(hash, x.local);
+      return hash;
+    }
+  };
+
+} // end namespace boost
+
+#include <boost/graph/distributed/adjlist/handlers.hpp>
+#include <boost/graph/distributed/adjlist/initialize.hpp>
+#include <boost/graph/distributed/adjlist/redistribute.hpp>
+#include <boost/graph/distributed/adjlist/serialization.hpp>
+
+#endif // BOOST_GRAPH_DISTRIBUTED_ADJACENCY_LIST_HPP
Added: trunk/boost/graph/distributed/adjlist/handlers.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/distributed/adjlist/handlers.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -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
+
Added: trunk/boost/graph/distributed/adjlist/initialize.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/distributed/adjlist/initialize.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -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
Added: trunk/boost/graph/distributed/adjlist/redistribute.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/distributed/adjlist/redistribute.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -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 (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 (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, 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 (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
Added: trunk/boost/graph/distributed/adjlist/serialization.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/distributed/adjlist/serialization.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -0,0 +1,1007 @@
+// 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/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 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"));
+
+#if BOOST_VERSION >= 103600
+              std::string process_name = i->path().filename();
+#else
+              std::string process_name = i->leaf();
+#endif
+              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
+          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());
+      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)
+          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)
+          {
+              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))
+      {
+          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;
+
+    // We retag the property list here so that bundled properties are
+    // properly placed into property<edge_bundle_t, Bundle>.
+    typedef typename boost::detail::retag_property_list<
+              edge_bundle_t,
+              typename Graph::edge_property_type>::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
+{
+    // We retag the property list here so that bundled properties are
+    // properly placed into property<vertex_bundle_t, Bundle>.
+    typedef typename boost::detail::retag_property_list<
+        vertex_bundle_t, vertex_property_type
+    >::type vertex_property_type;
+
+    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
+
Added: trunk/boost/graph/distributed/betweenness_centrality.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/distributed/betweenness_centrality.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -0,0 +1,1718 @@
+// 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_PARALLEL_BRANDES_BETWEENNESS_CENTRALITY_HPP
+#define BOOST_GRAPH_PARALLEL_BRANDES_BETWEENNESS_CENTRALITY_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 COMPUTE_PATH_COUNTS_INLINE
+
+#include <boost/graph/betweenness_centrality.hpp>
+#include <boost/graph/overloading.hpp>
+#include <boost/graph/distributed/concepts.hpp>
+#include <boost/graph/graph_traits.hpp>
+#include <boost/config.hpp>
+
+// For additive_reducer
+#include <boost/graph/distributed/distributed_graph_utility.hpp>
+#include <boost/type_traits/is_convertible.hpp>
+#include <boost/type_traits/is_same.hpp>
+#include <boost/property_map/property_map.hpp>
+#include <boost/graph/named_function_params.hpp>
+
+#include <boost/property_map/parallel/distributed_property_map.hpp>
+#include <boost/graph/distributed/detail/dijkstra_shortest_paths.hpp>
+#include <boost/tuple/tuple.hpp>
+
+// NGE - Needed for minstd_rand at L807, should pass vertex list
+//       or generator instead 
+#include <boost/random/linear_congruential.hpp>
+
+#include <algorithm>
+#include <stack>
+#include <vector>
+
+// Appending reducer
+template <typename T>
+struct append_reducer {
+  BOOST_STATIC_CONSTANT(bool, non_default_resolver = true);
+      
+  template<typename K>
+  T operator()(const K&) const { return T(); }
+      
+  template<typename K>
+  T operator()(const K&, const T& x, const T& y) const 
+  { 
+    T z(x.begin(), x.end());
+    for (typename T::const_iterator iter = y.begin(); iter != y.end(); ++iter)
+      if (std::find(z.begin(), z.end(), *iter) == z.end())
+        z.push_back(*iter);
+    
+    return z;
+  }
+};
+
+namespace boost {
+
+  namespace serialization {
+
+    // TODO(nge): Write generalized serialization for tuples
+    template<typename Archive, typename T1, typename T2, typename T3, 
+             typename T4>
+    void serialize(Archive & ar,
+                   boost::tuple<T1,T2,T3, T4>& t,
+                   const unsigned int)
+    {
+      ar & get<0>(t);
+      ar & get<1>(t);
+      ar & get<2>(t);
+      ar & get<3>(t);
+    }
+
+  } // serialization
+
+  namespace graph { namespace distributed {
+
+    // HACKY: Overload get on a tuple to return the value at the key indicated 
+    // by the first element of the tuple so that we can use tuples in a distributed queue
+    template<typename PropertyMap, typename Vertex, typename X, typename Y, typename Z>
+    inline
+    typename PropertyMap::value_type
+    get(PropertyMap& pm, boost::tuple<Vertex, X, Y, Z> const& t)
+    {
+      return get(pm, boost::tuples::get<0>(t));
+    }
+
+    // HACKY: Same as above for std::pair
+    template<typename PropertyMap, typename Vertex, typename X>
+    inline
+    typename PropertyMap::value_type
+    get(PropertyMap& pm, std::pair<Vertex, X> const& t)
+    {
+      return get(pm, t.first);
+    }
+
+  } } // graph::distributed
+
+  namespace graph { namespace parallel { namespace detail {
+
+  template<typename DistanceMap, typename IncomingMap>
+  class betweenness_centrality_msg_value
+  {
+    typedef typename property_traits<DistanceMap>::value_type distance_type;
+    typedef typename property_traits<IncomingMap>::value_type incoming_type;
+    typedef typename incoming_type::value_type incoming_value_type;
+
+  public:
+    typedef std::pair<distance_type, incoming_value_type> type;
+    
+    static type create(distance_type dist, incoming_value_type source)
+    { return std::make_pair(dist, source); }
+  };
+
+
+  /************************************************************************/
+  /* Delta-stepping Betweenness Centrality                                */
+  /************************************************************************/
+
+  template<typename Graph, typename DistanceMap, typename IncomingMap, 
+           typename EdgeWeightMap, typename PathCountMap
+#ifdef COMPUTE_PATH_COUNTS_INLINE
+           , typename IsSettledMap, typename VertexIndexMap
+#endif
+           >
+  class betweenness_centrality_delta_stepping_impl { 
+    // Could inherit from delta_stepping_impl to get run() method
+    // but for the time being it's just reproduced here
+
+    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 property_traits<IncomingMap>::value_type IncomingType;
+    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 betweenness_centrality_msg_value<DistanceMap, IncomingMap> 
+      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:
+
+    // Must supply delta, ctor that guesses delta removed 
+    betweenness_centrality_delta_stepping_impl(const Graph& g,
+                                               DistanceMap distance, 
+                                               IncomingMap incoming,
+                                               EdgeWeightMap weight,
+                                               PathCountMap path_count,
+#ifdef COMPUTE_PATH_COUNTS_INLINE
+                                               IsSettledMap is_settled,
+                                               VertexIndexMap vertex_index,
+#endif
+                                               Dist delta);
+    
+    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()
+    {
+      using boost::graph::parallel::synchronize;
+      synchronize(pg);
+    }
+    
+    // Setup triggers for msg_relax messages
+    void setup_triggers()
+    {
+      using boost::graph::parallel::simple_trigger;
+      simple_trigger(pg, msg_relax, this, 
+                     &betweenness_centrality_delta_stepping_impl::handle_msg_relax);
+    }
+
+    void handle_msg_relax(int /*source*/, int /*tag*/,
+                          const std::pair<Vertex, typename MessageValue::type>& data,
+                          trigger_receive_context)
+    { relax(data.second.second, data.first, data.second.first); }
+
+    const Graph& g;
+    IncomingMap incoming;
+    DistanceMap distance;
+    EdgeWeightMap weight;
+    PathCountMap path_count;
+#ifdef COMPUTE_PATH_COUNTS_INLINE
+    IsSettledMap is_settled;
+    VertexIndexMap vertex_index;
+#endif
+    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 DistanceMap, typename IncomingMap, 
+           typename EdgeWeightMap, typename PathCountMap
+#ifdef COMPUTE_PATH_COUNTS_INLINE
+           , typename IsSettledMap, typename VertexIndexMap
+#endif
+           >
+  betweenness_centrality_delta_stepping_impl<
+    Graph, DistanceMap, IncomingMap, EdgeWeightMap, PathCountMap
+#ifdef COMPUTE_PATH_COUNTS_INLINE
+           , IsSettledMap, VertexIndexMap
+#endif
+    >::
+  betweenness_centrality_delta_stepping_impl(const Graph& g,
+                                             DistanceMap distance,
+                                             IncomingMap incoming,
+                                             EdgeWeightMap weight,
+                                             PathCountMap path_count,
+#ifdef COMPUTE_PATH_COUNTS_INLINE
+                                             IsSettledMap is_settled,
+                                             VertexIndexMap vertex_index,
+#endif
+                                             Dist delta)
+    : g(g),
+      distance(distance),
+      incoming(incoming),
+      weight(weight),
+      path_count(path_count),
+#ifdef COMPUTE_PATH_COUNTS_INLINE
+      is_settled(is_settled),
+      vertex_index(vertex_index),
+#endif
+      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 DistanceMap, typename IncomingMap, 
+           typename EdgeWeightMap, typename PathCountMap
+#ifdef COMPUTE_PATH_COUNTS_INLINE
+           , typename IsSettledMap, typename VertexIndexMap
+#endif
+           >
+  void
+  betweenness_centrality_delta_stepping_impl<
+    Graph, DistanceMap, IncomingMap, EdgeWeightMap, PathCountMap
+#ifdef COMPUTE_PATH_COUNTS_INLINE
+           , IsSettledMap, VertexIndexMap
+#endif
+    >::
+  run(Vertex s)
+  {
+    typedef typename boost::graph::parallel::process_group_type<Graph>::type 
+      process_group_type;
+    typename process_group_type::process_id_type id = process_id(pg);
+
+    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) == id) 
+      // 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);
+    
+#ifdef COMPUTE_PATH_COUNTS_INLINE
+    // Synchronize here to deliver initial relaxation since we don't
+    // synchronize at the beginning of the inner loop any more
+    synchronize(); 
+
+    // Incoming edge count map is an implementation detail and should
+    // be freed as soon as possible so build it here
+    typedef typename graph_traits<Graph>::edges_size_type edges_size_type;
+
+    std::vector<edges_size_type> incoming_edge_countS(num_vertices(g));
+    iterator_property_map<typename std::vector<edges_size_type>::iterator, VertexIndexMap> 
+      incoming_edge_count(incoming_edge_countS.begin(), vertex_index);
+#endif
+
+    BucketIndex max_bucket = (std::numeric_limits<BucketIndex>::max)();
+    BucketIndex current_bucket = 0;
+    do {
+#ifdef COMPUTE_PATH_COUNTS_INLINE
+      // We need to clear the outgoing map after every bucket so just build it here
+      std::vector<IncomingType> outgoingS(num_vertices(g));
+      IncomingMap outgoing(outgoingS.begin(), vertex_index);
+      
+      outgoing.set_reduce(append_reducer<IncomingType>());
+#else
+      // Synchronize with all of the other processes.
+      synchronize();
+#endif    
+  
+      // 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;
+      
+      // 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;
+      
+      // 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();
+            
+            // 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)); 
+
+#ifdef COMPUTE_PATH_COUNTS_INLINE
+        // Set outgoing paths
+        IncomingType in = get(incoming, u);
+        for (typename IncomingType::iterator pred = in.begin(); pred != in.end(); ++pred) 
+          if (get(owner, *pred) == id) {
+            IncomingType x = get(outgoing, *pred);
+            if (std::find(x.begin(), x.end(), u) == x.end())
+              x.push_back(u);
+            put(outgoing, *pred, x);
+          } else {
+            IncomingType in;
+            in.push_back(u);
+            put(outgoing, *pred, in);
+          }
+
+        // Set incoming edge counts
+        put(incoming_edge_count, u, in.size());
+#endif
+      }
+
+#ifdef COMPUTE_PATH_COUNTS_INLINE
+      synchronize();  // Deliver heavy edge relaxations and outgoing paths
+
+      // Build Queue
+      typedef typename property_traits<PathCountMap>::value_type PathCountType;
+      typedef std::pair<Vertex, PathCountType> queue_value_type;
+      typedef typename property_map<Graph, vertex_owner_t>::const_type OwnerMap;
+
+      typedef boost::queue<queue_value_type> local_queue_type;
+      typedef boost::graph::distributed::distributed_queue<process_group_type,
+                                                           OwnerMap,
+                                                           local_queue_type> dist_queue_type;
+      dist_queue_type Q(pg, owner);
+
+      // Find sources to initialize queue
+      BGL_FORALL_VERTICES_T(v, g, Graph) {
+        if (get(is_settled, v) && !(get(outgoing, v).empty())) {
+          put(incoming_edge_count, v, 1); 
+          Q.push(std::make_pair(v, 0)); // Push this vertex with no additional path count
+        }
+      }
+
+      // Set path counts for vertices in this bucket
+      while (!Q.empty()) {
+        queue_value_type t = Q.top(); Q.pop();
+        Vertex v = t.first;
+        PathCountType p = t.second;
+
+        put(path_count, v, get(path_count, v) + p);
+        put(incoming_edge_count, v, get(incoming_edge_count, v) - 1);
+
+        if (get(incoming_edge_count, v) == 0) {
+          IncomingType out = get(outgoing, v);
+          for (typename IncomingType::iterator iter = out.begin(); iter != out.end(); ++iter)
+            Q.push(std::make_pair(*iter, get(path_count, v)));
+        }
+      }
+
+      // Mark the vertices in this bucket settled 
+      for (typename std::vector<Vertex>::iterator iter = deleted_vertices.begin();
+           iter != deleted_vertices.end(); ++iter) 
+        put(is_settled, *iter, true);
+
+      // No need to clear path count map as it is never read/written remotely
+      // No need to clear outgoing map as it is re-alloced every bucket 
+#endif
+      
+      // 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 DistanceMap, typename IncomingMap, 
+           typename EdgeWeightMap, typename PathCountMap
+#ifdef COMPUTE_PATH_COUNTS_INLINE
+           , typename IsSettledMap, typename VertexIndexMap
+#endif
+           >
+  void
+  betweenness_centrality_delta_stepping_impl<
+    Graph, DistanceMap, IncomingMap, EdgeWeightMap, PathCountMap
+#ifdef COMPUTE_PATH_COUNTS_INLINE
+           , IsSettledMap, VertexIndexMap
+#endif
+    >::
+  relax(Vertex u, Vertex v, Dist x)
+  {
+
+    if (x <= get(distance, v)) {
+      
+      // We're relaxing the edge to vertex v.
+      if (get(owner, v) == process_id(pg)) {
+        if (x < get(distance, v)) {
+          // 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 tentative distance information and incoming, path_count
+          if (u != v) put(incoming, v, IncomingType(1, u));
+          put(distance, v, x);
+        }        // u != v covers initial source relaxation and self-loops
+        else if (x == get(distance, v) && u != v) {
+
+          // Add incoming edge if it's not already in the list
+          IncomingType in = get(incoming, v);
+          if (std::find(in.begin(), in.end(), u) == in.end()) {
+            in.push_back(u);
+            put(incoming, v, in);
+          }
+        }
+      } else {
+        // 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);
+      }
+    }
+  }
+
+  /************************************************************************/
+  /* Shortest Paths function object for betweenness centrality            */
+  /************************************************************************/
+
+  template<typename WeightMap>
+  struct brandes_shortest_paths {
+    typedef typename property_traits<WeightMap>::value_type weight_type;
+
+    brandes_shortest_paths() 
+      : weight(1), delta(0)  { }
+    brandes_shortest_paths(weight_type delta) 
+      : weight(1), delta(delta)  { }
+    brandes_shortest_paths(WeightMap w) 
+      : weight(w), delta(0)  { }
+    brandes_shortest_paths(WeightMap w, weight_type delta) 
+      : weight(w), delta(delta)  { }
+
+    template<typename Graph, typename IncomingMap, typename DistanceMap,
+             typename PathCountMap
+#ifdef COMPUTE_PATH_COUNTS_INLINE
+             , typename IsSettledMap, typename VertexIndexMap
+#endif
+
+             > 
+    void 
+    operator()(Graph& g, 
+               typename graph_traits<Graph>::vertex_descriptor s,
+               IncomingMap incoming,
+               DistanceMap distance,
+               PathCountMap path_count
+#ifdef COMPUTE_PATH_COUNTS_INLINE
+               , IsSettledMap is_settled,
+               VertexIndexMap vertex_index 
+#endif
+               )
+    {  
+      typedef typename property_traits<DistanceMap>::value_type 
+        distance_type;
+
+      typedef std::plus<distance_type> Combine;
+      typedef std::less<distance_type> Compare;
+
+      // The "distance" map needs to act like one, retrieving the default
+      // value of infinity.
+      set_property_map_role(vertex_distance, distance);
+      
+      // Only calculate delta the first time operator() is called
+      // This presumes g is the same every time, but so does the fact
+      // that we're reusing the weight map
+      if (delta == 0)
+        set_delta(g);
+      
+      // TODO (NGE): Restructure the code so we don't have to construct
+      //             impl every time?
+      betweenness_centrality_delta_stepping_impl<
+          Graph, DistanceMap, IncomingMap, WeightMap, PathCountMap
+#ifdef COMPUTE_PATH_COUNTS_INLINE
+          , IsSettledMap, VertexIndexMap
+#endif
+            >
+        impl(g, distance, incoming, weight, path_count, 
+#ifdef COMPUTE_PATH_COUNTS_INLINE
+             is_settled, vertex_index, 
+#endif
+             delta);
+
+      impl.run(s);
+    }
+
+  private:
+
+    template <typename Graph>
+    void
+    set_delta(const Graph& g)
+    {
+      using boost::parallel::all_reduce;
+      using boost::parallel::maximum;
+      using std::max;
+
+      typedef typename graph_traits<Graph>::degree_size_type Degree;
+      typedef weight_type Dist;
+
+      // 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(process_group(g), max_edge_weight, maximum<Dist>());
+      max_degree = all_reduce(process_group(g), 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;
+    }
+
+    WeightMap     weight;
+    weight_type   delta;
+  };
+
+  // Perform a single SSSP from the specified vertex and update the centrality map(s)
+  template<typename Graph, typename CentralityMap, typename EdgeCentralityMap,
+           typename IncomingMap, typename DistanceMap, typename DependencyMap, 
+           typename PathCountMap, 
+#ifdef COMPUTE_PATH_COUNTS_INLINE
+           typename IsSettledMap,
+#endif 
+           typename VertexIndexMap, typename ShortestPaths> 
+  void
+  do_brandes_sssp(const Graph& g, 
+                  CentralityMap centrality,     
+                  EdgeCentralityMap edge_centrality_map,
+                  IncomingMap incoming,
+                  DistanceMap distance,
+                  DependencyMap dependency,
+                  PathCountMap path_count, 
+#ifdef COMPUTE_PATH_COUNTS_INLINE
+                  IsSettledMap is_settled,
+#endif 
+                  VertexIndexMap vertex_index,
+                  ShortestPaths shortest_paths,
+                  typename graph_traits<Graph>::vertex_descriptor s)
+  {
+    using boost::detail::graph::update_centrality;      
+    using boost::graph::parallel::process_group;
+
+    typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
+    typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
+    typedef typename graph_traits<Graph>::edges_size_type edges_size_type;
+
+    typedef typename property_traits<IncomingMap>::value_type incoming_type;
+    typedef typename property_traits<DistanceMap>::value_type distance_type;
+    typedef typename property_traits<DependencyMap>::value_type dependency_type;
+    typedef typename property_traits<PathCountMap>::value_type path_count_type;
+
+    typedef typename incoming_type::iterator incoming_iterator;
+
+    typedef typename property_map<Graph, vertex_owner_t>::const_type OwnerMap;
+    OwnerMap owner = get(vertex_owner, g);
+
+    typedef typename boost::graph::parallel::process_group_type<Graph>::type 
+      process_group_type;
+    process_group_type pg = process_group(g);
+    typename process_group_type::process_id_type id = process_id(pg);
+
+    // TODO: Is it faster not to clear some of these maps?
+    // Initialize for this iteration
+    distance.clear();
+    incoming.clear();
+    path_count.clear();
+    dependency.clear();
+    BGL_FORALL_VERTICES_T(v, g, Graph) {
+      put(path_count, v, 0);
+      put(dependency, v, 0);
+    }
+
+    if (get(owner, s) == id) {
+      put(incoming, s, incoming_type());
+#ifdef COMPUTE_PATH_COUNTS_INLINE
+      put(path_count, s, 1);
+      put(is_settled, s, true);
+#endif
+    }
+
+    // Execute the shortest paths algorithm. This will be either
+    // a weighted or unweighted customized breadth-first search,
+    shortest_paths(g, s, incoming, distance, path_count
+#ifdef COMPUTE_PATH_COUNTS_INLINE
+                   , is_settled, vertex_index
+#endif 
+                   );
+
+#ifndef COMPUTE_PATH_COUNTS_INLINE
+
+    //
+    // TODO: Optimize case where source has no out-edges
+    //
+ 
+    // Count of incoming edges to tell when all incoming edges have been relaxed in 
+    // the induced shortest paths DAG 
+    std::vector<edges_size_type> incoming_edge_countS(num_vertices(g));
+    iterator_property_map<typename std::vector<edges_size_type>::iterator, VertexIndexMap> 
+      incoming_edge_count(incoming_edge_countS.begin(), vertex_index);
+
+    BGL_FORALL_VERTICES_T(v, g, Graph) {
+      put(incoming_edge_count, v, get(incoming, v).size());
+    }
+
+    if (get(owner, s) == id) {
+      put(incoming_edge_count, s, 1);
+      put(incoming, s, incoming_type());
+    }
+
+    std::vector<incoming_type> outgoingS(num_vertices(g));
+    iterator_property_map<typename std::vector<incoming_type>::iterator, VertexIndexMap> 
+      outgoing(outgoingS.begin(), vertex_index);
+
+    outgoing.set_reduce(append_reducer<incoming_type>());
+
+    // Mark forward adjacencies in DAG of shortest paths
+
+    // TODO: It's possible to do this using edge flags but it's not currently done this way
+    //       because during traversal of the DAG we would have to examine all out edges
+    //       which would lead to more memory accesses and a larger cache footprint.
+    //
+    //       In the bidirectional graph case edge flags would be an excellent way of marking
+    //       edges in the DAG of shortest paths  
+    BGL_FORALL_VERTICES_T(v, g, Graph) {
+      incoming_type i = get(incoming, v);
+      for (typename incoming_type::iterator iter = i.begin(); iter != i.end(); ++iter) {
+        if (get(owner, *iter) == id) {
+          incoming_type x = get(outgoing, *iter);
+          if (std::find(x.begin(), x.end(), v) == x.end())
+            x.push_back(v);
+          put(outgoing, *iter, x);
+        } else {
+          incoming_type in;
+          in.push_back(v);
+          put(outgoing, *iter, in);
+        }
+      }
+    }
+
+    synchronize(pg);
+
+    // Traverse DAG induced by forward edges in dependency order and compute path counts
+    {
+      typedef std::pair<vertex_descriptor, path_count_type> queue_value_type;
+
+      typedef boost::queue<queue_value_type> local_queue_type;
+      typedef boost::graph::distributed::distributed_queue<process_group_type,
+                                                           OwnerMap,
+                                                           local_queue_type> dist_queue_type;
+      dist_queue_type Q(pg, owner);
+
+      if (get(owner, s) == id)
+        Q.push(std::make_pair(s, 1));
+
+      while (!Q.empty()) {
+        queue_value_type t = Q.top(); Q.pop();
+        vertex_descriptor v = t.first;
+        path_count_type p = t.second;
+
+        put(path_count, v, get(path_count, v) + p);
+        put(incoming_edge_count, v, get(incoming_edge_count, v) - 1);
+
+        if (get(incoming_edge_count, v) == 0) {
+          incoming_type out = get(outgoing, v);
+          for (typename incoming_type::iterator iter = out.begin(); iter != out.end(); ++iter)
+            Q.push(std::make_pair(*iter, get(path_count, v)));
+        }
+      }
+    }
+
+#endif // COMPUTE_PATH_COUNTS_INLINE
+
+    //
+    // Compute dependencies 
+    //    
+
+
+    // Build the distributed_queue
+    // Value type consists of 1) target of update 2) source of update
+    // 3) dependency of source 4) path count of source
+    typedef boost::tuple<vertex_descriptor, vertex_descriptor, dependency_type, path_count_type>
+      queue_value_type;
+
+    typedef boost::queue<queue_value_type> local_queue_type;
+    typedef boost::graph::distributed::distributed_queue<process_group_type,
+                                                         OwnerMap,
+                                                         local_queue_type> dist_queue_type;
+    dist_queue_type Q(pg, owner);
+
+    // Calculate number of vertices each vertex depends on, when a vertex has been pushed
+    // that number of times then we will update it
+    // AND Request path counts of sources of incoming edges
+    std::vector<dependency_type> dependency_countS(num_vertices(g), 0);
+    iterator_property_map<typename std::vector<dependency_type>::iterator, VertexIndexMap> 
+      dependency_count(dependency_countS.begin(), vertex_index);
+
+    dependency_count.set_reduce(boost::graph::distributed::additive_reducer<dependency_type>());
+
+    path_count.set_max_ghost_cells(0);
+
+    BGL_FORALL_VERTICES_T(v, g, Graph) {
+      if (get(distance, v) < (std::numeric_limits<distance_type>::max)()) {
+        incoming_type el = get(incoming, v);
+        for (incoming_iterator vw = el.begin(); vw != el.end(); ++vw) {
+          if (get(owner, *vw) == id)
+            put(dependency_count, *vw, get(dependency_count, *vw) + 1);
+          else {
+            put(dependency_count, *vw, 1);
+
+            // Request path counts
+            get(path_count, *vw); 
+          }
+
+          // request() doesn't work here, perhaps because we don't have a copy of this 
+          // ghost cell already?
+        }
+      }
+    }
+
+    synchronize(pg);
+
+    // Push vertices with non-zero distance/path count and zero dependency count
+    BGL_FORALL_VERTICES_T(v, g, Graph) {
+      if (get(distance, v) < (std::numeric_limits<distance_type>::max)()
+          && get(dependency_count, v) == 0) 
+        Q.push(boost::make_tuple(v, v, get(dependency, v), get(path_count, v)));
+    }
+
+    dependency.set_max_ghost_cells(0);
+    while(!Q.empty()) {
+
+      queue_value_type x = Q.top(); Q.pop();
+      vertex_descriptor w = get<0>(x);
+      vertex_descriptor source = get<1>(x);
+      dependency_type dep = get<2>(x);
+      path_count_type pc = get<3>(x);
+
+      cache(dependency, source, dep);
+      cache(path_count, source, pc);
+
+      if (get(dependency_count, w) != 0)
+        put(dependency_count, w, get(dependency_count, w) - 1);
+
+      if (get(dependency_count, w) == 0) { 
+
+        // Update dependency and centrality of sources of incoming edges
+        incoming_type el = get(incoming, w);
+        for (incoming_iterator vw = el.begin(); vw != el.end(); ++vw) {
+          vertex_descriptor v = *vw;
+
+          assert(get(path_count, w) != 0);
+
+          dependency_type factor = dependency_type(get(path_count, v))
+            / dependency_type(get(path_count, w));
+          factor *= (dependency_type(1) + get(dependency, w));
+          
+          if (get(owner, v) == id)
+            put(dependency, v, get(dependency, v) + factor);
+          else
+            put(dependency, v, factor);
+          
+          update_centrality(edge_centrality_map, v, factor);
+        }
+        
+        if (w != s)
+          update_centrality(centrality, w, get(dependency, w));
+
+        // Push sources of edges in incoming edge list
+        for (incoming_iterator vw = el.begin(); vw != el.end(); ++vw)
+          Q.push(boost::make_tuple(*vw, w, get(dependency, w), get(path_count, w)));
+      }
+    }
+  }
+
+  template<typename Graph, typename CentralityMap, typename EdgeCentralityMap,
+           typename IncomingMap, typename DistanceMap, typename DependencyMap, 
+           typename PathCountMap, typename VertexIndexMap, typename ShortestPaths, 
+           typename Buffer>
+  void 
+  brandes_betweenness_centrality_impl(const Graph& g, 
+                                      CentralityMap centrality,     
+                                      EdgeCentralityMap edge_centrality_map,
+                                      IncomingMap incoming,
+                                      DistanceMap distance,
+                                      DependencyMap dependency,
+                                      PathCountMap path_count, 
+                                      VertexIndexMap vertex_index,
+                                      ShortestPaths shortest_paths,
+                                      Buffer sources)
+  {
+    using boost::detail::graph::init_centrality_map;
+    using boost::detail::graph::divide_centrality_by_two;       
+    using boost::graph::parallel::process_group;
+    
+    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;
+    typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type;
+
+    typedef typename property_traits<DistanceMap>::value_type distance_type;
+    typedef typename property_traits<DependencyMap>::value_type dependency_type;
+
+    // Initialize centrality
+    init_centrality_map(vertices(g), centrality);
+    init_centrality_map(edges(g), edge_centrality_map);
+
+    // Set the reduction operation on the dependency map to be addition
+    dependency.set_reduce(boost::graph::distributed::additive_reducer<dependency_type>()); 
+    distance.set_reduce(boost::graph::distributed::choose_min_reducer<distance_type>());
+
+    // Don't allow remote procs to write incoming or path_count maps
+    // updating them is handled inside the betweenness_centrality_queue
+    incoming.set_consistency_model(0);
+    path_count.set_consistency_model(0);
+
+    typedef typename boost::graph::parallel::process_group_type<Graph>::type 
+      process_group_type;
+    process_group_type pg = process_group(g);
+
+#ifdef COMPUTE_PATH_COUNTS_INLINE
+    // Build is_settled maps
+    std::vector<bool> is_settledS(num_vertices(g));
+    typedef iterator_property_map<std::vector<bool>::iterator, VertexIndexMap> 
+      IsSettledMap;
+
+    IsSettledMap is_settled(is_settledS.begin(), vertex_index);
+#endif
+
+    if (!sources.empty()) {
+      // DO SSSPs
+      while (!sources.empty()) {
+        do_brandes_sssp(g, centrality, edge_centrality_map, incoming, distance,
+                        dependency, path_count, 
+#ifdef COMPUTE_PATH_COUNTS_INLINE
+                        is_settled,
+#endif 
+                        vertex_index, shortest_paths, sources.top());
+        sources.pop();
+      }
+    } else { // Exact Betweenness Centrality
+      typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type;
+      vertices_size_type n = num_vertices(g);
+      n = boost::parallel::all_reduce(pg, n, std::plus<vertices_size_type>());
+      
+      for (int i = 0; i < n; ++i) {
+        vertex_descriptor v = vertex(i, g);
+
+        do_brandes_sssp(g, centrality, edge_centrality_map, incoming, distance,
+                        dependency, path_count, 
+#ifdef COMPUTE_PATH_COUNTS_INLINE
+                        is_settled,
+#endif 
+                        vertex_index, shortest_paths, v);
+      }
+    }
+
+    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);
+    }
+  }
+
+  template<typename Graph, typename CentralityMap, typename EdgeCentralityMap,
+           typename IncomingMap, typename DistanceMap, typename DependencyMap, 
+           typename PathCountMap, typename VertexIndexMap, typename ShortestPaths,
+           typename Stack>
+  void
+  do_sequential_brandes_sssp(const Graph& g, 
+                             CentralityMap centrality,     
+                             EdgeCentralityMap edge_centrality_map,
+                             IncomingMap incoming,
+                             DistanceMap distance,
+                             DependencyMap dependency,
+                             PathCountMap path_count, 
+                             VertexIndexMap vertex_index,
+                             ShortestPaths shortest_paths,
+                             Stack& ordered_vertices,
+                             typename graph_traits<Graph>::vertex_descriptor v)
+  {
+    using boost::detail::graph::update_centrality;
+
+    typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
+    typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
+
+    typedef typename property_traits<IncomingMap>::value_type incoming_type;
+
+    // Initialize for this iteration
+    BGL_FORALL_VERTICES_T(w, g, Graph) {
+      // put(path_count, w, 0);
+      incoming[w].clear();
+      put(dependency, w, 0);
+    }
+
+    put(path_count, v, 1);
+    incoming[v].clear();
+
+    // 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, v, 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 != v) {
+        update_centrality(centrality, w, get(dependency, w));
+      }
+    }
+  }
+
+  // Betweenness Centrality variant that duplicates graph across processors
+  // and parallizes SSSPs
+  // This function expects a non-distributed graph and property-maps
+  template<typename ProcessGroup, typename Graph, 
+           typename CentralityMap, typename EdgeCentralityMap,
+           typename IncomingMap, typename DistanceMap, 
+           typename DependencyMap, typename PathCountMap,
+           typename VertexIndexMap, typename ShortestPaths>
+  void
+  non_distributed_brandes_betweenness_centrality_impl(const ProcessGroup& pg,
+                                                      const Graph& g,
+                                                      CentralityMap centrality,
+                                                      EdgeCentralityMap edge_centrality_map,
+                                                      IncomingMap incoming, // P
+                                                      DistanceMap distance,         // d
+                                                      DependencyMap dependency,     // delta
+                                                      PathCountMap path_count,      // sigma
+                                                      VertexIndexMap vertex_index,
+                                                      ShortestPaths shortest_paths,
+                                                      typename graph_traits<Graph>::vertices_size_type num_sources = 0)
+  {
+    using boost::detail::graph::init_centrality_map;
+    using boost::detail::graph::divide_centrality_by_two;       
+    using boost::graph::parallel::process_group;
+
+    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;
+    typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type;
+
+    typedef typename property_traits<DistanceMap>::value_type distance_type;
+
+    typedef ProcessGroup process_group_type;
+
+    typename process_group_type::process_id_type id = process_id(pg);
+    typename process_group_type::process_size_type p = num_processes(pg);
+
+    // Initialize centrality
+    init_centrality_map(vertices(g), centrality);
+    init_centrality_map(edges(g), edge_centrality_map);
+
+    std::stack<vertex_descriptor> ordered_vertices;
+
+    if (num_sources != 0) {
+      
+      minstd_rand gen;
+      uniform_int<vertices_size_type> rand_vertex(0, num_vertices(g) - 1);
+      std::vector<vertex_descriptor> sources;
+      typename std::vector<vertex_descriptor>::iterator s, s_end;
+
+      for (int i = 0; i < num_sources; ++i) {
+        vertex_iterator iter = vertices(g).first;
+        std::advance(iter, rand_vertex(gen));
+        
+        if (out_degree(*iter, g) != 0
+            && std::find(sources.begin(), sources.end(), *iter) == sources.end()) {
+          sources.push_back(*iter);
+        }
+      }
+
+      int N = sources.size();
+      s = sources.begin(), s_end = sources.end();
+      if (id != (p - 1)) {
+        s_end = s;
+        std::advance(s_end, (id + 1) * N/p);
+      }
+      std::advance(s, id * N/p);
+
+      for ( ; s != s_end; ++s)
+        do_sequential_brandes_sssp(g, centrality, edge_centrality_map, incoming,
+                                   distance, dependency, path_count, vertex_index,
+                                   shortest_paths, ordered_vertices, *s);
+    } else {
+      vertex_iterator s, s_end;
+
+      int N = num_vertices(g);
+      tie(s, s_end) = vertices(g);
+      if (id != (p - 1)) {
+        s_end = s;
+        std::advance(s_end, (id + 1) * N/p);
+      }
+      std::advance(s, id * N/p);
+
+      for ( ; s != s_end; ++s)
+        do_sequential_brandes_sssp(g, centrality, edge_centrality_map, incoming,
+                                   distance, dependency, path_count, vertex_index,
+                                   shortest_paths, ordered_vertices, *s);
+    }
+
+    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);
+    }
+
+    // Merge the centrality maps by summing the values at each vertex)
+    // TODO(nge): this copy-out, reduce, copy-in is lame
+    typedef typename property_traits<CentralityMap>::value_type centrality_type;
+    typedef typename property_traits<EdgeCentralityMap>::value_type edge_centrality_type;
+
+    std::vector<centrality_type> centrality_v(num_vertices(g));
+    std::vector<edge_centrality_type> edge_centrality_v;
+    edge_centrality_v.reserve(num_edges(g));
+
+    BGL_FORALL_VERTICES_T(v, g, Graph) {
+      centrality_v[get(vertex_index, v)] = get(centrality, v);
+    }
+    
+    // Skip when EdgeCentralityMap is a dummy_property_map
+    if (!is_same<EdgeCentralityMap, dummy_property_map>::value) {
+      BGL_FORALL_EDGES_T(e, g, Graph) {
+        edge_centrality_v.push_back(get(edge_centrality_map, e));
+      }
+      // NGE: If we trust that the order of elements in the vector isn't changed in the
+      //      all_reduce below then this method avoids the need for an edge index map
+    }
+
+    using boost::parallel::all_reduce;
+
+    all_reduce(pg, ¢rality_v[0], ¢rality_v[centrality_v.size()],
+               ¢rality_v[0], std::plus<centrality_type>());
+
+    if (edge_centrality_v.size()) 
+      all_reduce(pg, &edge_centrality_v[0], &edge_centrality_v[edge_centrality_v.size()],
+                 &edge_centrality_v[0], std::plus<edge_centrality_type>());
+
+    BGL_FORALL_VERTICES_T(v, g, Graph) {
+      put(centrality, v, centrality_v[get(vertex_index, v)]);
+    }
+
+    // Skip when EdgeCentralityMap is a dummy_property_map
+    if (!is_same<EdgeCentralityMap, dummy_property_map>::value) {
+      int i = 0;
+      BGL_FORALL_EDGES_T(e, g, Graph) {
+        put(edge_centrality_map, e, edge_centrality_v[i]);
+        ++i;
+      }
+    }
+  }
+
+} } } // end namespace graph::parallel::detail
+
+template<typename Graph, typename CentralityMap, typename EdgeCentralityMap,
+         typename IncomingMap, typename DistanceMap, typename DependencyMap, 
+         typename PathCountMap, typename VertexIndexMap, typename Buffer>
+void 
+brandes_betweenness_centrality(const Graph& g, 
+                               CentralityMap centrality,
+                               EdgeCentralityMap edge_centrality_map,
+                               IncomingMap incoming, 
+                               DistanceMap distance, 
+                               DependencyMap dependency,     
+                               PathCountMap path_count,   
+                               VertexIndexMap vertex_index,
+                               Buffer sources,
+                               typename property_traits<DistanceMap>::value_type delta
+                               BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag))
+{
+  typedef typename property_traits<DistanceMap>::value_type distance_type;
+  typedef static_property_map<distance_type> WeightMap;
+
+  graph::parallel::detail::brandes_shortest_paths<WeightMap> 
+    shortest_paths(delta);
+
+  graph::parallel::detail::brandes_betweenness_centrality_impl(g, centrality, 
+                                                               edge_centrality_map,
+                                                               incoming, distance,
+                                                               dependency, path_count,
+                                                               vertex_index, 
+                                                               shortest_paths,
+                                                               sources);
+}
+
+template<typename Graph, typename CentralityMap, typename EdgeCentralityMap, 
+         typename IncomingMap, typename DistanceMap, typename DependencyMap, 
+         typename PathCountMap, typename VertexIndexMap, typename WeightMap, 
+         typename Buffer>    
+void 
+brandes_betweenness_centrality(const Graph& g, 
+                               CentralityMap centrality,
+                               EdgeCentralityMap edge_centrality_map,
+                               IncomingMap incoming, 
+                               DistanceMap distance, 
+                               DependencyMap dependency,
+                               PathCountMap path_count, 
+                               VertexIndexMap vertex_index,
+                               Buffer sources,
+                               typename property_traits<WeightMap>::value_type delta,
+                               WeightMap weight_map
+                               BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag))
+{
+  graph::parallel::detail::brandes_shortest_paths<WeightMap> shortest_paths(weight_map, delta);
+
+  graph::parallel::detail::brandes_betweenness_centrality_impl(g, centrality, 
+                                                               edge_centrality_map,
+                                                               incoming, distance,
+                                                               dependency, path_count,
+                                                               vertex_index, 
+                                                               shortest_paths,
+                                                               sources);
+}
+
+namespace graph { namespace parallel { namespace detail {
+  template<typename Graph, typename CentralityMap, typename EdgeCentralityMap,
+           typename WeightMap, typename VertexIndexMap, typename EdgeIndexMap,
+           typename Buffer>
+  void 
+  brandes_betweenness_centrality_dispatch2(const Graph& g,
+                                           CentralityMap centrality,
+                                           EdgeCentralityMap edge_centrality_map,
+                                           WeightMap weight_map,
+                                           VertexIndexMap vertex_index,
+                                           EdgeIndexMap edge_index,
+                                           Buffer sources,
+                                           typename property_traits<WeightMap>::value_type delta)
+  {
+    typedef typename graph_traits<Graph>::degree_size_type degree_size_type;
+    typedef typename graph_traits<Graph>::vertex_descriptor vertex_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<vertex_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, sources.ref, delta,
+      weight_map);
+  }
+  
+  // TODO: Should the type of the distance and dependency map depend on the 
+  //       value type of the centrality map?
+  template<typename Graph, typename CentralityMap, typename EdgeCentralityMap,
+           typename VertexIndexMap, typename EdgeIndexMap, typename Buffer>
+  void 
+  brandes_betweenness_centrality_dispatch2(const Graph& g,
+                                           CentralityMap centrality,
+                                           EdgeCentralityMap edge_centrality_map,
+                                           VertexIndexMap vertex_index,
+                                           EdgeIndexMap edge_index,
+                                           Buffer sources,
+                                           typename graph_traits<Graph>::edges_size_type delta)
+  {
+    typedef typename graph_traits<Graph>::degree_size_type degree_size_type;
+    typedef typename graph_traits<Graph>::edges_size_type edges_size_type;
+    typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
+    typedef typename mpl::if_c<(is_same<CentralityMap, 
+                                        dummy_property_map>::value),
+                                         EdgeCentralityMap, 
+                               CentralityMap>::type a_centrality_map;
+
+    typename graph_traits<Graph>::vertices_size_type V = num_vertices(g);
+    
+    std::vector<std::vector<vertex_descriptor> > incoming(V);
+    std::vector<edges_size_type> distance(V);
+    std::vector<edges_size_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, sources.ref, delta); 
+  }
+
+  template<typename WeightMap>
+  struct brandes_betweenness_centrality_dispatch1
+  {
+    template<typename Graph, typename CentralityMap, typename EdgeCentralityMap, 
+             typename VertexIndexMap, typename EdgeIndexMap, typename Buffer>
+    static void 
+    run(const Graph& g, CentralityMap centrality, EdgeCentralityMap edge_centrality_map, 
+        VertexIndexMap vertex_index, EdgeIndexMap edge_index, Buffer sources,
+        typename property_traits<WeightMap>::value_type delta, WeightMap weight_map) 
+    {
+      boost::graph::parallel::detail::brandes_betweenness_centrality_dispatch2(
+       g, centrality, edge_centrality_map, weight_map, vertex_index, edge_index, sources, delta);
+    }
+  };
+
+  template<>
+  struct brandes_betweenness_centrality_dispatch1<boost::detail::error_property_not_found> 
+  {
+    template<typename Graph, typename CentralityMap, typename EdgeCentralityMap, 
+             typename VertexIndexMap, typename EdgeIndexMap, typename Buffer>
+    static void 
+    run(const Graph& g, CentralityMap centrality, EdgeCentralityMap edge_centrality_map, 
+        VertexIndexMap vertex_index, EdgeIndexMap edge_index, Buffer sources,
+        typename graph_traits<Graph>::edges_size_type delta,
+        boost::detail::error_property_not_found)
+    {
+      boost::graph::parallel::detail::brandes_betweenness_centrality_dispatch2(
+       g, centrality, edge_centrality_map, vertex_index, edge_index, sources, delta);
+    }
+  };
+
+} } } // end namespace graph::parallel::detail
+
+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,distributed_graph_tag))
+{
+  typedef bgl_named_params<Param,Tag,Rest> named_params;
+
+  typedef queue<int> queue_t;
+  queue_t q;
+
+  typedef typename property_value<named_params, edge_weight_t>::type ew;
+  graph::parallel::detail::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),
+    choose_const_pmap(get_param(params, edge_index), g, edge_index),
+    choose_param(get_param(params, buffer_param_t()),
+                 detail::wrap_ref<queue_t>(q)),
+    choose_param(get_param(params, lookahead_t()), 0),
+    get_param(params, edge_weight));
+}
+
+template<typename Graph, typename CentralityMap>
+void 
+brandes_betweenness_centrality(const Graph& g, CentralityMap centrality
+                               BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,distributed_graph_tag))
+{
+  typedef queue<int> queue_t;
+  queue_t q;
+
+  boost::graph::parallel::detail::brandes_betweenness_centrality_dispatch2(
+    g, centrality, dummy_property_map(), get(vertex_index, g), get(edge_index, g), 
+    detail::wrap_ref<queue_t>(q), 0);
+}
+
+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,distributed_graph_tag))
+{
+  typedef queue<int> queue_t;
+  queue_t q;
+
+  boost::graph::parallel::detail::brandes_betweenness_centrality_dispatch2(
+    g, centrality, edge_centrality_map, get(vertex_index, g), get(edge_index, g), 
+    detail::wrap_ref<queue_t>(q), 0);
+}
+  
+template<typename ProcessGroup, typename Graph, 
+         typename CentralityMap, typename EdgeCentralityMap,
+         typename IncomingMap, typename DistanceMap, 
+         typename DependencyMap, typename PathCountMap, 
+         typename VertexIndexMap>
+void 
+non_distributed_brandes_betweenness_centrality(const ProcessGroup& pg,
+                                               const Graph& g, 
+                                               CentralityMap centrality,
+                                               EdgeCentralityMap edge_centrality_map,
+                                               IncomingMap incoming, 
+                                               DistanceMap distance, 
+                                               DependencyMap dependency,     
+                                               PathCountMap path_count,      
+                                               VertexIndexMap vertex_index,
+                                               typename graph_traits<Graph>::vertices_size_type num_sources)
+{
+  typedef typename property_traits<DistanceMap>::value_type distance_type;
+  typedef static_property_map<distance_type> WeightMap;
+  
+  detail::graph::brandes_unweighted_shortest_paths shortest_paths;
+  
+  graph::parallel::detail::non_distributed_brandes_betweenness_centrality_impl(pg, g, centrality, 
+                                                                               edge_centrality_map,
+                                                                               incoming, distance,
+                                                                               dependency, path_count,
+                                                                               vertex_index, 
+                                                                               shortest_paths,
+                                                                               num_sources);
+}
+  
+template<typename ProcessGroup, typename Graph, 
+         typename CentralityMap, typename EdgeCentralityMap, 
+         typename IncomingMap, typename DistanceMap, 
+         typename DependencyMap, typename PathCountMap, 
+         typename VertexIndexMap, typename WeightMap>    
+void 
+non_distributed_brandes_betweenness_centrality(const ProcessGroup& pg,
+                                               const Graph& g, 
+                                               CentralityMap centrality,
+                                               EdgeCentralityMap edge_centrality_map,
+                                               IncomingMap incoming, 
+                                               DistanceMap distance, 
+                                               DependencyMap dependency,
+                                               PathCountMap path_count, 
+                                               VertexIndexMap vertex_index,
+                                               WeightMap weight_map,
+                                               typename graph_traits<Graph>::vertices_size_type num_sources)
+{
+  detail::graph::brandes_dijkstra_shortest_paths<WeightMap> shortest_paths(weight_map);
+
+  graph::parallel::detail::non_distributed_brandes_betweenness_centrality_impl(pg, g, centrality, 
+                                                                               edge_centrality_map,
+                                                                               incoming, distance,
+                                                                               dependency, path_count,
+                                                                               vertex_index, 
+                                                                               shortest_paths,
+                                                                               num_sources);
+}
+
+namespace detail { namespace graph {
+  template<typename ProcessGroup, typename Graph, typename CentralityMap, 
+           typename EdgeCentralityMap, typename WeightMap, typename VertexIndexMap>
+  void 
+  non_distributed_brandes_betweenness_centrality_dispatch2(const ProcessGroup& pg,
+                                                           const Graph& g,
+                                                           CentralityMap centrality,
+                                                           EdgeCentralityMap edge_centrality_map,
+                                                           WeightMap weight_map,
+                                                           VertexIndexMap vertex_index,
+                                                           typename graph_traits<Graph>::vertices_size_type num_sources)
+  {
+    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);
+
+    non_distributed_brandes_betweenness_centrality(
+      pg, 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, num_sources);
+  }
+  
+
+  template<typename ProcessGroup, typename Graph, typename CentralityMap, 
+           typename EdgeCentralityMap, typename VertexIndexMap>
+  void 
+  non_distributed_brandes_betweenness_centrality_dispatch2(const ProcessGroup& pg,
+                                                           const Graph& g,
+                                                           CentralityMap centrality,
+                                                           EdgeCentralityMap edge_centrality_map,
+                                                           VertexIndexMap vertex_index,
+                                                           typename graph_traits<Graph>::vertices_size_type num_sources)
+  {
+    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);
+
+    non_distributed_brandes_betweenness_centrality(
+      pg, 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, num_sources);
+  }
+
+  template<typename WeightMap>
+  struct non_distributed_brandes_betweenness_centrality_dispatch1
+  {
+    template<typename ProcessGroup, typename Graph, typename CentralityMap, 
+             typename EdgeCentralityMap, typename VertexIndexMap>
+    static void 
+    run(const ProcessGroup& pg, const Graph& g, CentralityMap centrality, 
+        EdgeCentralityMap edge_centrality_map, VertexIndexMap vertex_index,
+        typename graph_traits<Graph>::vertices_size_type num_sources, 
+        WeightMap weight_map)
+    {
+      non_distributed_brandes_betweenness_centrality_dispatch2(pg, g, centrality, edge_centrality_map,
+                                                               weight_map, vertex_index, num_sources);
+    }
+  };
+
+  template<>
+  struct non_distributed_brandes_betweenness_centrality_dispatch1<detail::error_property_not_found>
+  {
+    template<typename ProcessGroup, typename Graph, typename CentralityMap, 
+             typename EdgeCentralityMap, typename VertexIndexMap>
+    static void 
+    run(const ProcessGroup& pg, const Graph& g, CentralityMap centrality, 
+        EdgeCentralityMap edge_centrality_map, VertexIndexMap vertex_index,
+        typename graph_traits<Graph>::vertices_size_type num_sources, 
+        detail::error_property_not_found)
+    {
+      non_distributed_brandes_betweenness_centrality_dispatch2(pg, g, centrality, edge_centrality_map,
+                                                               vertex_index, num_sources);
+    }
+  };
+
+} } // end namespace detail::graph
+
+// TODO: Make named parameter variant work
+
+// template<typename ProcessGroup, typename Graph, typename Param, typename Tag, typename Rest>
+// void 
+// non_distributed_brandes_betweenness_centrality(const ProcessGroup& pg, const Graph& g, 
+//                                    const bgl_named_params<Param,Tag,Rest>& params)
+// {
+//   typedef bgl_named_params<Param,Tag,Rest> named_params;
+
+//   typedef typename property_value<named_params, edge_weight_t>::type ew;
+//   detail::graph::non_distributed_brandes_betweenness_centrality_dispatch1<ew>::run(
+//     pg, 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));
+// }
+
+template<typename ProcessGroup, typename Graph, typename CentralityMap>
+void 
+non_distributed_brandes_betweenness_centrality(const ProcessGroup& pg, const Graph& g, CentralityMap centrality)
+{
+  detail::graph::non_distributed_brandes_betweenness_centrality_dispatch2(
+    pg, g, centrality, dummy_property_map(), get(vertex_index, g), 0);
+}
+
+template<typename ProcessGroup, typename Graph, typename CentralityMap>
+void 
+non_distributed_brandes_betweenness_centrality(const ProcessGroup& pg, const Graph& g, CentralityMap centrality,
+                                               typename graph_traits<Graph>::vertices_size_type num_sources)
+{
+  detail::graph::non_distributed_brandes_betweenness_centrality_dispatch2(
+    pg, g, centrality, dummy_property_map(), get(vertex_index, g), num_sources);
+}
+
+template<typename ProcessGroup, typename Graph, typename CentralityMap, 
+         typename EdgeCentralityMap>
+void 
+non_distributed_brandes_betweenness_centrality(const ProcessGroup& pg, const Graph& g, CentralityMap centrality,
+                                               EdgeCentralityMap edge_centrality_map,
+                                               typename graph_traits<Graph>::vertices_size_type num_sources)
+{
+  detail::graph::non_distributed_brandes_betweenness_centrality_dispatch2(
+    pg, g, centrality, edge_centrality_map, get(vertex_index, g), num_sources);
+}
+
+// Compute the central point dominance of a graph.
+// TODO: Make sure central point dominance works in parallel case
+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,distributed_graph_tag))
+{
+  using std::max;
+
+  typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
+  typedef typename property_traits<CentralityMap>::value_type centrality_type;
+  typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type;
+
+  typedef typename boost::graph::parallel::process_group_type<Graph>::type 
+    process_group_type;
+  process_group_type pg = boost::graph::parallel::process_group(g);
+
+  vertices_size_type n = num_vertices(g);
+
+  using boost::parallel::all_reduce;  
+  n = all_reduce(pg, n, std::plus<vertices_size_type>());
+
+  // Find max centrality
+  centrality_type max_centrality(0);
+  vertex_iterator v, v_end;
+  for (tie(v, v_end) = vertices(g); v != v_end; ++v) {
+    max_centrality = (max)(max_centrality, get(centrality, *v));
+  }
+
+  // All reduce to get global max centrality
+  max_centrality = all_reduce(pg, max_centrality, boost::parallel::maximum<centrality_type>());
+
+  // Compute central point dominance
+  centrality_type sum(0);
+  for (tie(v, v_end) = vertices(g); v != v_end; ++v) {
+    sum += (max_centrality - get(centrality, *v));
+  }
+
+  sum = all_reduce(pg, sum, std::plus<centrality_type>());
+
+  return sum/(n-1);
+}
+
+} // end namespace boost
+
+#endif // BOOST_GRAPH_PARALLEL_BRANDES_BETWEENNESS_CENTRALITY_HPP
Added: trunk/boost/graph/distributed/boman_et_al_graph_coloring.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/distributed/boman_et_al_graph_coloring.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -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 <cassert>
+#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)) {
+          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)) {
+      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);
+    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
Added: trunk/boost/graph/distributed/breadth_first_search.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/distributed/breadth_first_search.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -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,
+       error_property_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
Added: trunk/boost/graph/distributed/compressed_sparse_row_graph.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/distributed/compressed_sparse_row_graph.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -0,0 +1,1314 @@
+// 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 compressed sparse row graph type
+
+#ifndef BOOST_GRAPH_DISTRIBUTED_CSR_HPP
+#define BOOST_GRAPH_DISTRIBUTED_CSR_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/compressed_sparse_row_graph.hpp>
+#include <boost/graph/distributed/selector.hpp>
+#include <boost/mpl/if.hpp>
+#include <boost/type_traits/is_same.hpp>
+#include <boost/graph/distributed/concepts.hpp>
+#include <boost/graph/parallel/properties.hpp>
+#include <boost/graph/parallel/distribution.hpp>
+#include <boost/property_map/parallel/local_property_map.hpp>
+#include <boost/property_map/parallel/distributed_property_map.hpp>
+
+namespace boost {
+
+// The number of bits we reserve for the processor ID. 
+// DPG TBD: This is a hack. It will eventually be a run-time quantity.
+static const int processor_bits = 8;
+
+// Tag class for a distributed CSR graph
+struct distributed_csr_tag
+  : public virtual distributed_graph_tag,
+    public virtual distributed_vertex_list_graph_tag,
+    public virtual distributed_edge_list_graph_tag,
+    public virtual incidence_graph_tag,
+    public virtual adjacency_graph_tag {};
+
+template<typename Directed, typename VertexProperty, typename EdgeProperty,
+         typename GraphProperty, typename ProcessGroup, typename InVertex,
+         typename InDistribution, typename InEdgeIndex>
+class compressed_sparse_row_graph<
+         Directed, VertexProperty, EdgeProperty, GraphProperty,
+         distributedS<ProcessGroup, InVertex, InDistribution>,
+         InEdgeIndex>
+{
+  typedef compressed_sparse_row_graph self_type;
+
+ private:
+  /**
+   *  Determine the type used to represent vertices in the graph. If
+   *  the user has overridden the default, use the user's
+   *  parameter. Otherwise, fall back to std::size_t.
+   */
+  typedef typename mpl::if_<is_same<InVertex, defaultS>,
+                            std::size_t,
+                            InVertex>::type Vertex;
+
+  /**
+   *  Determine the type used to represent edges in the graph. If
+   *  the user has overridden the default (which is to be the same as
+   *  the distributed vertex selector type), use the user's
+   *  parameter. Otherwise, fall back to the value of @c Vertex.
+   */
+  typedef typename mpl::if_<is_same<InEdgeIndex,
+                                    distributedS<ProcessGroup, InVertex,
+                                                 InDistribution> >,
+                            Vertex,
+                            InEdgeIndex>::type EdgeIndex;
+
+ public:
+  /**
+   * The type of the CSR graph that will be stored locally.
+   */
+  typedef compressed_sparse_row_graph<Directed, VertexProperty, EdgeProperty,
+                                      GraphProperty, Vertex, EdgeIndex>
+    base_type;
+
+  // -----------------------------------------------------------------
+  // Graph concept requirements
+  typedef Vertex vertex_descriptor;
+  typedef typename graph_traits<base_type>::edge_descriptor edge_descriptor;
+  typedef directed_tag directed_category;
+  typedef allow_parallel_edge_tag edge_parallel_category;
+  typedef distributed_csr_tag traversal_category;
+  static vertex_descriptor null_vertex();
+
+  // -----------------------------------------------------------------
+  // Distributed Vertex List Graph concept requirements
+  typedef Vertex vertices_size_type;
+  class vertex_iterator;
+
+  // -----------------------------------------------------------------
+  // Distributed Edge List Graph concept requirements
+  typedef EdgeIndex edges_size_type;
+  class edge_iterator;
+
+  // -----------------------------------------------------------------
+  // Incidence Graph concept requirements
+  typedef typename graph_traits<base_type>::out_edge_iterator
+    out_edge_iterator;
+  typedef typename graph_traits<base_type>::degree_size_type
+    degree_size_type;
+
+  // -----------------------------------------------------------------
+  // Adjacency Graph concept requirements
+  typedef typename graph_traits<base_type>::adjacency_iterator
+    adjacency_iterator;
+
+  // Note: This graph type does not model Bidirectional Graph.
+  // However, this typedef is required to satisfy graph_traits.
+  typedef void in_edge_iterator;
+
+  // -----------------------------------------------------------------
+  // Distributed Container concept requirements
+  typedef ProcessGroup process_group_type;
+  typedef boost::parallel::variant_distribution<process_group_type, Vertex>
+    distribution_type;
+
+  // -----------------------------------------------------------------
+  // Workarounds
+  typedef no_property vertex_property_type;
+  typedef no_property edge_property_type;
+  typedef typename mpl::if_<is_void<VertexProperty>,
+                            void****,
+                            VertexProperty>::type vertex_bundled;
+  typedef typename mpl::if_<is_void<EdgeProperty>,
+                            void****,
+                            EdgeProperty>::type edge_bundled;
+
+  // -----------------------------------------------------------------
+  // Useful types
+  typedef typename ProcessGroup::process_id_type process_id_type;
+
+  // -----------------------------------------------------------------
+  // Graph constructors
+  compressed_sparse_row_graph(const ProcessGroup& pg = ProcessGroup())
+    : m_process_group(pg), m_distribution(parallel::block(pg, 0)) {}
+
+  template<typename InputIterator>
+  compressed_sparse_row_graph(InputIterator edge_begin, InputIterator edge_end,
+                              vertices_size_type numverts,
+                              const ProcessGroup& pg = ProcessGroup(),
+                              const GraphProperty& prop = GraphProperty());
+
+  template<typename InputIterator, typename EdgePropertyIterator>
+  compressed_sparse_row_graph(InputIterator edge_begin, InputIterator edge_end,
+                              EdgePropertyIterator ep_iter,
+                              vertices_size_type numverts,
+                              const ProcessGroup& pg = ProcessGroup(),
+                              const GraphProperty& prop = GraphProperty());
+
+  template<typename InputIterator, typename Distribution>
+  compressed_sparse_row_graph(InputIterator edge_begin, InputIterator edge_end,
+                              vertices_size_type numverts,
+                              const ProcessGroup& pg,
+                              const Distribution& dist,
+                              const GraphProperty& prop = GraphProperty());
+
+  template<typename InputIterator, typename EdgePropertyIterator, 
+           typename Distribution>
+  compressed_sparse_row_graph(InputIterator edge_begin, InputIterator edge_end,
+                              EdgePropertyIterator ep_iter,
+                              vertices_size_type numverts,
+                              const ProcessGroup& pg,
+                              const Distribution& dist,
+                              const GraphProperty& prop = GraphProperty());
+
+  base_type&       base()       { return m_base; }
+  const base_type& base() const { return m_base; }
+
+  process_group_type process_group() const { return m_process_group.base(); }
+
+  distribution_type&       distribution()       { return m_distribution; }
+  const distribution_type& distribution() const { return m_distribution; }
+
+  // Directly access a vertex or edge bundle
+  vertex_bundled& operator[](vertex_descriptor v)
+  {
+    std::pair<process_id_type, vertex_descriptor> locator
+      = get(vertex_global, *this, v);
+    assert(locator.first == process_id(m_process_group));
+    return base().m_vertex_properties[locator.second];
+  }
+
+  const vertex_bundled& operator[](vertex_descriptor v) const
+  {
+    std::pair<process_id_type, vertex_descriptor> locator
+      = get(vertex_global, *this, v);
+    assert(locator.first == process_id(m_process_group));
+    return base().m_process_group[locator.second];
+  }
+
+  edge_bundled& operator[](edge_descriptor e)
+  {
+    assert(get(vertex_owner, *this, e.src) == process_id(m_process_group));
+    return base().m_edge_properties[e.idx];
+  }
+
+  const edge_bundled& operator[](edge_descriptor e) const
+  {
+    assert(get(vertex_owner, *this, e.src) == process_id(m_process_group));
+    return base().m_edge_properties[e.idx];
+  }
+
+  // Create a vertex descriptor from a process ID and a local index.
+  vertex_descriptor 
+  make_vertex_descriptor(process_id_type p, vertex_descriptor v) const
+  {
+    vertex_descriptor vertex_local_index_bits = 
+      sizeof(vertex_descriptor) * CHAR_BIT - processor_bits;
+    return v | ((vertex_descriptor)p << vertex_local_index_bits);
+  }
+
+  // Convert a local vertex descriptor into a global vertex descriptor
+  vertex_descriptor local_to_global_vertex(vertex_descriptor v) const
+  {
+    return make_vertex_descriptor(process_id(m_process_group), v);
+  }
+
+ protected:
+  ProcessGroup m_process_group;
+  distribution_type m_distribution;
+  base_type m_base;
+};
+
+/** @brief Helper macro containing the template parameters for the
+ *   distributed CSR graph.
+ *
+ *  This macro contains all of the template parameters needed for the
+ *  distributed compressed_sparse_row graph type. It is used to reduce
+ *  the amount of typing required to declare free functions for this
+ *  graph type.
+ */
+#define BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS                          \
+  typename Directed, typename VertexProperty, typename EdgeProperty,    \
+  typename GraphProperty, typename ProcessGroup, typename InVertex,     \
+  typename InDistribution, typename InEdgeIndex
+
+/** @brief Helper macro containing the typical instantiation of the
+ *   distributed CSR graph.
+ *
+ *  This macro contains an instantiation of the distributed CSR graph
+ *  type using the typical template parameters names (e.g., those
+ *  provided by the macro @c
+ *  BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS). It is used to reduce
+ *  the amount of typing required to declare free functions for this
+ *  graph type.
+ */
+#define BOOST_DISTRIB_CSR_GRAPH_TYPE                            \
+  compressed_sparse_row_graph<                                  \
+    Directed, VertexProperty, EdgeProperty, GraphProperty,      \
+    distributedS<ProcessGroup, InVertex, InDistribution>,       \
+    InEdgeIndex>
+
+// -----------------------------------------------------------------
+// Graph concept operations
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+inline typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor
+BOOST_DISTRIB_CSR_GRAPH_TYPE::null_vertex()
+{
+  return graph_traits<base_type>::null_vertex();
+}
+
+// -----------------------------------------------------------------
+// Incidence Graph concept operations
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+inline typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor
+source(typename BOOST_DISTRIB_CSR_GRAPH_TYPE::edge_descriptor e,
+       const BOOST_DISTRIB_CSR_GRAPH_TYPE&)
+{ return e.src; }
+
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+inline typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor
+target(typename BOOST_DISTRIB_CSR_GRAPH_TYPE::edge_descriptor e,
+       const BOOST_DISTRIB_CSR_GRAPH_TYPE& g)
+{ return target(e, g.base()); }
+
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+inline std::pair<typename BOOST_DISTRIB_CSR_GRAPH_TYPE::out_edge_iterator,
+                 typename BOOST_DISTRIB_CSR_GRAPH_TYPE::out_edge_iterator>
+out_edges(typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor u,
+          const BOOST_DISTRIB_CSR_GRAPH_TYPE& g)
+{
+  typedef typename BOOST_DISTRIB_CSR_GRAPH_TYPE::edges_size_type
+    edges_size_type;
+  typedef typename BOOST_DISTRIB_CSR_GRAPH_TYPE::edge_descriptor ed;
+  typedef typename BOOST_DISTRIB_CSR_GRAPH_TYPE::out_edge_iterator it;
+  edges_size_type u_local = get(vertex_local, g, u);
+  edges_size_type u_row_start = g.base().m_rowstart[u_local];
+  edges_size_type next_row_start = g.base().m_rowstart[u_local + 1];
+  return std::make_pair(it(ed(u, u_row_start)),
+                        it(ed(u, (std::max)(u_row_start, next_row_start))));
+}
+
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+inline typename BOOST_DISTRIB_CSR_GRAPH_TYPE::degree_size_type
+out_degree(typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor u,
+           const BOOST_DISTRIB_CSR_GRAPH_TYPE& g)
+{
+  return out_degree(get(vertex_local, g, u), g.base());
+}
+
+// -----------------------------------------------------------------
+// DistributedGraph concept requirements
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+void synchronize(const BOOST_DISTRIB_CSR_GRAPH_TYPE& g)
+{
+  typedef BOOST_DISTRIB_CSR_GRAPH_TYPE graph_type;
+  synchronize(g.process_group());
+}
+
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS> 
+ProcessGroup
+process_group(const BOOST_DISTRIB_CSR_GRAPH_TYPE& g)
+{ return g.process_group(); }
+
+
+// -----------------------------------------------------------------
+// Adjacency Graph concept requirements
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+inline std::pair<typename BOOST_DISTRIB_CSR_GRAPH_TYPE::adjacency_iterator,
+                 typename BOOST_DISTRIB_CSR_GRAPH_TYPE::adjacency_iterator>
+adjacent_vertices(typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor u,
+                  const BOOST_DISTRIB_CSR_GRAPH_TYPE& g)
+{
+  return adjacent_vertices(get(vertex_local, g, u), g.base());
+}
+
+// -----------------------------------------------------------------
+// Distributed Vertex List Graph concept operations
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+class BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_iterator
+  : public iterator_adaptor<vertex_iterator,
+                            counting_iterator<Vertex>,
+                            Vertex,
+                            random_access_traversal_tag,
+                            Vertex>
+{
+  typedef iterator_adaptor<vertex_iterator,
+                           counting_iterator<Vertex>,
+                           Vertex,
+                           random_access_traversal_tag,
+                           Vertex> inherited;
+ public:
+  vertex_iterator() {}
+
+  explicit vertex_iterator(Vertex v, const self_type* graph)
+    : inherited(counting_iterator<Vertex>(v)), graph(graph) { }
+
+  Vertex dereference() const
+  {
+    return graph->local_to_global_vertex(*(this->base_reference()));
+  }
+
+  friend class iterator_core_access;
+
+ private:
+  const self_type* graph;
+};
+
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+inline typename BOOST_DISTRIB_CSR_GRAPH_TYPE::degree_size_type
+num_vertices(const BOOST_DISTRIB_CSR_GRAPH_TYPE& g)
+{
+  return num_vertices(g.base());
+}
+
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+inline std::pair<typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_iterator,
+                 typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_iterator>
+vertices(const BOOST_DISTRIB_CSR_GRAPH_TYPE& g)
+{
+  typedef typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_iterator
+    vertex_iterator;
+  return std::make_pair(vertex_iterator(0, &g),
+                        vertex_iterator(num_vertices(g), &g));
+}
+
+// -----------------------------------------------------------------
+// Distributed Edge List Graph concept operations
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+class BOOST_DISTRIB_CSR_GRAPH_TYPE::edge_iterator
+{
+ public:
+  typedef std::forward_iterator_tag iterator_category;
+  typedef edge_descriptor value_type;
+
+  typedef const edge_descriptor* pointer;
+
+  typedef edge_descriptor reference;
+  typedef typename int_t<CHAR_BIT * sizeof(EdgeIndex)>::fast difference_type;
+
+  edge_iterator() : graph(0), current_edge(), end_of_this_vertex(0) {}
+
+  edge_iterator(const compressed_sparse_row_graph& graph,
+                edge_descriptor current_edge,
+                EdgeIndex end_of_this_vertex)
+    : graph(&graph), local_src(current_edge.src), current_edge(current_edge),
+      end_of_this_vertex(end_of_this_vertex)
+  {
+    // The edge that comes in has a local source vertex. Make it global.
+    current_edge.src = graph.local_to_global_vertex(current_edge.src);
+  }
+
+  // From InputIterator
+  reference operator*() const { return current_edge; }
+  pointer operator->() const { return ¤t_edge; }
+
+  bool operator==(const edge_iterator& o) const {
+    return current_edge == o.current_edge;
+  }
+  bool operator!=(const edge_iterator& o) const {
+    return current_edge != o.current_edge;
+  }
+
+  edge_iterator& operator++()
+  {
+    ++current_edge.idx;
+    while (current_edge.idx == end_of_this_vertex && local_src < num_vertices(*graph)-1) {
+      ++local_src;
+      current_edge.src = graph->local_to_global_vertex(local_src);
+      end_of_this_vertex = graph->base().m_rowstart[local_src + 1];
+    }
+    return *this;
+  }
+
+  edge_iterator operator++(int) {
+    edge_iterator temp = *this;
+    ++*this;
+    return temp;
+  }
+
+ private:
+  const compressed_sparse_row_graph* graph;
+  EdgeIndex local_src;
+  edge_descriptor current_edge;
+  EdgeIndex end_of_this_vertex;
+};
+
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+inline typename BOOST_DISTRIB_CSR_GRAPH_TYPE::edges_size_type
+num_edges(const BOOST_DISTRIB_CSR_GRAPH_TYPE& g)
+{
+  return g.base().m_column.size();
+}
+
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+std::pair<typename BOOST_DISTRIB_CSR_GRAPH_TYPE::edge_iterator,
+          typename BOOST_DISTRIB_CSR_GRAPH_TYPE::edge_iterator>
+edges(const BOOST_DISTRIB_CSR_GRAPH_TYPE& g)
+{
+  typedef typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor Vertex;
+  typedef typename BOOST_DISTRIB_CSR_GRAPH_TYPE::edge_iterator ei;
+  typedef typename BOOST_DISTRIB_CSR_GRAPH_TYPE::edge_descriptor edgedesc;
+  if (g.base().m_rowstart.size() == 1 || g.base().m_column.empty()) {
+    return std::make_pair(ei(), ei());
+  } else {
+    // Find the first vertex that has outgoing edges
+    Vertex src = 0;
+    while (g.base().m_rowstart[src + 1] == 0) ++src;
+    return std::make_pair(ei(g, edgedesc(src, 0), g.base().m_rowstart[src + 1]),
+                          ei(g, edgedesc(num_vertices(g), g.base().m_column.size()), 0));
+  }
+}
+
+// -----------------------------------------------------------------
+// Graph constructors
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+template<typename InputIterator>
+BOOST_DISTRIB_CSR_GRAPH_TYPE::
+compressed_sparse_row_graph(InputIterator edge_begin, InputIterator edge_end,
+                            vertices_size_type numverts,
+                            const ProcessGroup& pg,
+                            const GraphProperty& prop)
+  : m_process_group(pg),
+    m_distribution(parallel::block(m_process_group, numverts)),
+    m_base(m_distribution.block_size(process_id(m_process_group), numverts))
+{
+  parallel::block dist(m_process_group, numverts);
+
+  // Allows us to add edges
+  m_base.m_last_source = 0;
+
+  typename ProcessGroup::process_id_type id = process_id(m_process_group);
+
+  while (edge_begin != edge_end) {
+    vertex_descriptor src = edge_begin->first;
+    if (static_cast<process_id_type>(dist(src)) == id) {
+      vertex_descriptor tgt = 
+        make_vertex_descriptor(dist(edge_begin->second), 
+                               dist.local(edge_begin->second));
+      add_edge(dist.local(src), tgt, m_base);
+    }
+    ++edge_begin;
+  }
+}
+
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+template<typename InputIterator, typename EdgePropertyIterator>
+BOOST_DISTRIB_CSR_GRAPH_TYPE::
+compressed_sparse_row_graph(InputIterator edge_begin, InputIterator edge_end,
+                            EdgePropertyIterator ep_iter,
+                            vertices_size_type numverts,
+                            const ProcessGroup& pg,
+                            const GraphProperty& prop)
+  : m_process_group(pg),
+    m_distribution(parallel::block(m_process_group, numverts)),
+    m_base(m_distribution.block_size(process_id(m_process_group), numverts))
+{
+  parallel::block dist(m_process_group, numverts);
+
+  // Allows us to add edges
+  m_base.m_last_source = 0;
+
+  typename ProcessGroup::process_id_type id = process_id(m_process_group);
+
+  while (edge_begin != edge_end) {
+    EdgeIndex src = edge_begin->first;
+    if (static_cast<process_id_type>(dist(src)) == id) {
+      EdgeIndex tgt = 
+        make_vertex_descriptor(dist(edge_begin->second), 
+                               dist.local(edge_begin->second));
+
+      add_edge(dist.local(src), tgt, *ep_iter, m_base);
+    }
+    ++edge_begin;
+    ++ep_iter;
+  }
+}
+
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+template<typename InputIterator, typename Distribution>
+BOOST_DISTRIB_CSR_GRAPH_TYPE::
+compressed_sparse_row_graph(InputIterator edge_begin, InputIterator edge_end,
+                            vertices_size_type numverts,
+                            const ProcessGroup& pg,
+                            const Distribution& dist,
+                            const GraphProperty& prop)
+  : m_process_group(pg),
+    m_distribution(dist),
+    m_base(dist.block_size(process_id(m_process_group), numverts))
+{
+  // Allows us to add edges
+  m_base.m_last_source = 0;
+
+  typename ProcessGroup::process_id_type id = process_id(m_process_group);
+
+  while (edge_begin != edge_end) {
+    vertex_descriptor src = edge_begin->first;
+    if (static_cast<process_id_type>(dist(src)) == id) {
+      vertex_descriptor tgt = 
+        make_vertex_descriptor(dist(edge_begin->second), 
+                               dist.local(edge_begin->second));
+      assert(get(vertex_owner, *this, tgt) == dist(edge_begin->second));
+      assert(get(vertex_local, *this, tgt) == dist.local(edge_begin->second));
+      add_edge(dist.local(src), tgt, m_base);
+    }
+    ++edge_begin;
+  }
+}
+
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+template<typename InputIterator, typename EdgePropertyIterator, 
+         typename Distribution>
+BOOST_DISTRIB_CSR_GRAPH_TYPE::
+compressed_sparse_row_graph(InputIterator edge_begin, InputIterator edge_end,
+                            EdgePropertyIterator ep_iter,
+                            vertices_size_type numverts,
+                            const ProcessGroup& pg,
+                            const Distribution& dist,
+                            const GraphProperty& prop)
+  : m_process_group(pg),
+    m_distribution(dist),
+    m_base(dist.block_size(process_id(m_process_group), numverts))
+{
+  // Allows us to add edges
+  m_base.m_last_source = 0;
+
+  typename ProcessGroup::process_id_type id = process_id(m_process_group);
+
+  while (edge_begin != edge_end) {
+    EdgeIndex src = edge_begin->first;
+    if (static_cast<process_id_type>(dist(src)) == id) {
+      EdgeIndex tgt = 
+        make_vertex_descriptor(dist(edge_begin->second), 
+                               dist.local(edge_begin->second));
+      add_edge(dist.local(src), tgt, *ep_iter, m_base);
+    }
+    ++edge_begin;
+    ++ep_iter;
+  }
+}
+
+// -----------------------------------------------------------------
+// Vertex Global Property Map
+template<typename ProcessID, typename Key>
+class csr_vertex_global_map
+{
+ public:
+  // -----------------------------------------------------------------
+  // Readable Property Map concept requirements
+  typedef std::pair<ProcessID, Key> value_type;
+  typedef value_type reference;
+  typedef Key key_type;
+  typedef readable_property_map_tag category;
+};
+
+template<typename ProcessID, typename Key>
+inline std::pair<ProcessID, Key>
+get(csr_vertex_global_map<ProcessID, Key>,
+    typename csr_vertex_global_map<ProcessID, Key>::key_type k)
+{
+  const int local_index_bits = sizeof(Key) * CHAR_BIT - processor_bits;
+  const Key local_index_mask = Key(-1) >> processor_bits;
+
+  return std::pair<ProcessID, Key>(k >> local_index_bits,
+                                   k & local_index_mask);
+}
+
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+class property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_global_t>
+{
+ public:
+  typedef csr_vertex_global_map<
+            typename ProcessGroup::process_id_type,
+            typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor> type;
+  typedef type const_type;
+};
+
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+inline
+typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_global_t>::type
+get(vertex_global_t, BOOST_DISTRIB_CSR_GRAPH_TYPE& g)
+{
+  typedef typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_global_t>
+    ::type result_type;
+  return result_type();
+}
+
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+inline
+std::pair<typename ProcessGroup::process_id_type,
+          typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor>
+get(vertex_global_t, BOOST_DISTRIB_CSR_GRAPH_TYPE& g,
+    typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor k)
+{
+  return get(vertex_global, 
+             const_cast<const BOOST_DISTRIB_CSR_GRAPH_TYPE&>(g), 
+             k);
+}
+
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+inline
+typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_global_t>::const_type
+get(vertex_global_t, const BOOST_DISTRIB_CSR_GRAPH_TYPE& g)
+{
+  typedef typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_global_t>
+    ::const_type result_type;
+  return result_type();
+}
+
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+inline
+std::pair<typename ProcessGroup::process_id_type,
+          typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor>
+get(vertex_global_t, const BOOST_DISTRIB_CSR_GRAPH_TYPE& g,
+    typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor k)
+{
+  typedef typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor
+    vertex_descriptor;
+  typedef std::pair<typename ProcessGroup::process_id_type, vertex_descriptor>
+    result_type;
+  const int local_index_bits = 
+    sizeof(vertex_descriptor) * CHAR_BIT - processor_bits;
+  const vertex_descriptor local_index_mask = 
+    vertex_descriptor(-1) >> processor_bits;
+
+  return result_type(k >> local_index_bits, k & local_index_mask);
+}
+
+// -----------------------------------------------------------------
+// Extra, common functions
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+inline typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor
+vertex(typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertices_size_type i,
+       const BOOST_DISTRIB_CSR_GRAPH_TYPE& g)
+{
+  return g.make_vertex_descriptor(g.distribution()(i), 
+                                  g.distribution().local(i));
+}
+
+// Unlike for an adjacency_matrix, edge_range and edge take lg(out_degree(i))
+// time
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+inline std::pair<typename BOOST_DISTRIB_CSR_GRAPH_TYPE::out_edge_iterator,
+                 typename BOOST_DISTRIB_CSR_GRAPH_TYPE::out_edge_iterator>
+edge_range(typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor i,
+           typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor j,
+           const BOOST_DISTRIB_CSR_GRAPH_TYPE& g)
+{
+  typedef typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor Vertex;
+  typedef typename BOOST_DISTRIB_CSR_GRAPH_TYPE::edges_size_type EdgeIndex;
+  typedef typename std::vector<Vertex>::const_iterator adj_iter;
+  typedef typename BOOST_DISTRIB_CSR_GRAPH_TYPE::out_edge_iterator out_edge_iter;
+  typedef typename BOOST_DISTRIB_CSR_GRAPH_TYPE::edge_descriptor edge_desc;
+  std::pair<adj_iter, adj_iter> raw_adjacencies = adjacent_vertices(i, g);
+  std::pair<adj_iter, adj_iter> adjacencies =
+    std::equal_range(raw_adjacencies.first, raw_adjacencies.second, j);
+  EdgeIndex idx_begin = adjacencies.first - g.base().m_column.begin();
+  EdgeIndex idx_end = adjacencies.second - g.base().m_column.begin();
+  return std::make_pair(out_edge_iter(edge_desc(i, idx_begin)),
+                        out_edge_iter(edge_desc(i, idx_end)));
+}
+
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+inline std::pair<typename BOOST_DISTRIB_CSR_GRAPH_TYPE::edge_descriptor, bool>
+edge(typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor i,
+     typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor j,
+     const BOOST_DISTRIB_CSR_GRAPH_TYPE& g)
+{
+  typedef typename BOOST_DISTRIB_CSR_GRAPH_TYPE::out_edge_iterator out_edge_iter;
+  std::pair<out_edge_iter, out_edge_iter> range = edge_range(i, j, g);
+  if (range.first == range.second)
+    return std::make_pair(typename BOOST_DISTRIB_CSR_GRAPH_TYPE::edge_descriptor(),
+                          false);
+  else
+    return std::make_pair(*range.first, true);
+}
+
+// A helper that turns requests for property maps for const graphs
+// into property maps for non-const graphs.
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS, typename Property>
+class property_map<const BOOST_DISTRIB_CSR_GRAPH_TYPE, Property>
+{
+ public:
+  typedef typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, Property>
+    ::const_type type;
+  typedef type const_type;
+};
+
+// -----------------------------------------------------------------
+// Vertex Owner Property Map
+template<typename ProcessID, typename Key>
+class csr_vertex_owner_map
+{
+ public:
+  // -----------------------------------------------------------------
+  // Readable Property Map concept requirements
+  typedef ProcessID value_type;
+  typedef value_type reference;
+  typedef Key key_type;
+  typedef readable_property_map_tag category;
+};
+
+template<typename ProcessID, typename Key>
+inline ProcessID
+get(csr_vertex_owner_map<ProcessID, Key> pm,
+    typename csr_vertex_owner_map<ProcessID, Key>::key_type k)
+{
+  const int local_index_bits = sizeof(Key) * CHAR_BIT - processor_bits;
+  return k >> local_index_bits;
+}
+
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+class property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_owner_t>
+{
+ public:
+  typedef csr_vertex_owner_map<
+            typename ProcessGroup::process_id_type,
+            typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor> type;
+  typedef type const_type;
+};
+
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+inline
+typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_owner_t>::type
+get(vertex_owner_t, BOOST_DISTRIB_CSR_GRAPH_TYPE& g)
+{
+  typedef typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_owner_t>
+    ::type result_type;
+  return result_type();
+}
+
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+inline typename ProcessGroup::process_id_type
+get(vertex_owner_t, BOOST_DISTRIB_CSR_GRAPH_TYPE& g,
+    typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor k)
+{
+  return get(vertex_owner, 
+             const_cast<const BOOST_DISTRIB_CSR_GRAPH_TYPE&>(g),
+             k);
+}
+
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+inline
+typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_owner_t>::const_type
+get(vertex_owner_t, const BOOST_DISTRIB_CSR_GRAPH_TYPE& g)
+{
+  typedef typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_owner_t>
+    ::const_type result_type;
+  return result_type();
+}
+
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+inline typename ProcessGroup::process_id_type
+get(vertex_owner_t, const BOOST_DISTRIB_CSR_GRAPH_TYPE& g,
+    typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor k)
+{
+  typedef typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor
+    vertex_descriptor;
+  const int local_index_bits = 
+    sizeof(vertex_descriptor) * CHAR_BIT - processor_bits;
+  return k >> local_index_bits;
+}
+
+// -----------------------------------------------------------------
+// Vertex Local Property Map
+template<typename Key>
+class csr_vertex_local_map
+{
+ public:
+  // -----------------------------------------------------------------
+  // Readable Property Map concept requirements
+  typedef Key value_type;
+  typedef value_type reference;
+  typedef Key key_type;
+  typedef readable_property_map_tag category;
+};
+
+template<typename Key>
+inline Key
+get(csr_vertex_local_map<Key> pm,
+    typename csr_vertex_local_map<Key>::key_type k)
+{
+  const Key local_index_mask = Key(-1) >> processor_bits;
+  return k & local_index_mask;
+}
+
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+class property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_local_t>
+{
+ public:
+  typedef csr_vertex_local_map<
+            typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor> type;
+  typedef type const_type;
+};
+
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+inline
+typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_local_t>::type
+get(vertex_local_t, BOOST_DISTRIB_CSR_GRAPH_TYPE& g)
+{
+  typedef typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_local_t>
+    ::type result_type;
+  return result_type();
+}
+
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+inline typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor
+get(vertex_local_t, BOOST_DISTRIB_CSR_GRAPH_TYPE& g,
+    typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor k)
+{
+  return get(vertex_local, 
+             const_cast<const BOOST_DISTRIB_CSR_GRAPH_TYPE&>(g),
+             k);
+}
+
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+inline
+typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_local_t>::const_type
+get(vertex_local_t, const BOOST_DISTRIB_CSR_GRAPH_TYPE& g)
+{
+  typedef typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_local_t>
+    ::const_type result_type;
+  return result_type();
+}
+
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+inline typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor
+get(vertex_local_t, const BOOST_DISTRIB_CSR_GRAPH_TYPE& g,
+    typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor k)
+{
+  typedef typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor 
+    vertex_descriptor;
+  const vertex_descriptor local_index_mask = 
+    vertex_descriptor(-1) >> processor_bits;
+  return k & local_index_mask;
+}
+
+// -----------------------------------------------------------------
+// Vertex Index Property Map
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+class property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_index_t>
+{
+  typedef typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, 
+                                vertex_global_t>::const_type
+    global_map;
+  typedef typename BOOST_DISTRIB_CSR_GRAPH_TYPE::process_group_type
+    process_group_type;
+
+  typedef property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_local_t> local;
+
+public:
+  typedef local_property_map<process_group_type, 
+                             global_map, 
+                             typename local::type> type;
+  typedef local_property_map<process_group_type, 
+                             global_map, 
+                             typename local::const_type> const_type;
+};
+
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+inline
+typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_index_t>::type
+get(vertex_index_t, BOOST_DISTRIB_CSR_GRAPH_TYPE& g)
+{
+  typedef typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_index_t>
+    ::type result_type;
+
+  return result_type(g.process_group(), get(vertex_global, g),
+                     get(vertex_local, g));
+}
+
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+inline typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertices_size_type
+get(vertex_index_t, BOOST_DISTRIB_CSR_GRAPH_TYPE& g,
+    typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor k)
+{
+  return get(vertex_local, g, k);
+}
+
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+inline
+typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_index_t>::const_type
+get(vertex_index_t, const BOOST_DISTRIB_CSR_GRAPH_TYPE& g)
+{
+  typedef typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_index_t>
+    ::const_type result_type;
+  return result_type(g.process_group(), get(vertex_global, g),
+                     get(vertex_local, g));
+}
+
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+inline typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertices_size_type
+get(vertex_index_t, const BOOST_DISTRIB_CSR_GRAPH_TYPE& g,
+    typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor k)
+{
+  return get(vertex_local, g, k);
+}
+
+// -----------------------------------------------------------------
+// Vertex Local Index Property Map
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+class property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_local_index_t>
+  : public property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_local_t> { };
+
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+inline
+typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_local_index_t>::type
+get(vertex_local_index_t, BOOST_DISTRIB_CSR_GRAPH_TYPE& g)
+{
+  return get(vertex_local, g);
+}
+
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+inline typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertices_size_type
+get(vertex_local_index_t, BOOST_DISTRIB_CSR_GRAPH_TYPE& g,
+    typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor k)
+{
+  return get(vertex_local, g, k);
+}
+
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+inline
+typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, vertex_local_index_t>::const_type
+get(vertex_local_index_t, const BOOST_DISTRIB_CSR_GRAPH_TYPE& g)
+{
+  return get(vertex_local, g);
+}
+
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+inline typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertices_size_type
+get(vertex_local_index_t, const BOOST_DISTRIB_CSR_GRAPH_TYPE& g,
+    typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor k)
+{
+  return get(vertex_local, g, k);
+}
+
+// -----------------------------------------------------------------
+// Edge Global Property Map
+template<typename ProcessID, typename Vertex, typename EdgeIndex>
+class csr_edge_global_map
+{
+ public:
+  // -----------------------------------------------------------------
+  // Readable Property Map concept requirements
+  typedef std::pair<ProcessID, EdgeIndex> value_type;
+  typedef value_type reference;
+  typedef csr_edge_descriptor<Vertex, EdgeIndex> key_type;
+  typedef readable_property_map_tag category;
+};
+
+template<typename ProcessID, typename Vertex, typename EdgeIndex>
+inline std::pair<ProcessID, EdgeIndex>
+get(csr_edge_global_map<ProcessID, Vertex, EdgeIndex> pm,
+    typename csr_edge_global_map<ProcessID, Vertex, EdgeIndex>::key_type k)
+{
+  const int local_index_bits = sizeof(Vertex) * CHAR_BIT - processor_bits;
+  return std::pair<ProcessID, EdgeIndex>(k.src >> local_index_bits, k.idx);
+}
+
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+class property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, edge_global_t>
+{
+ public:
+  typedef csr_edge_global_map<
+            typename ProcessGroup::process_id_type,
+            typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor,
+            typename BOOST_DISTRIB_CSR_GRAPH_TYPE::edges_size_type> type;
+  typedef type const_type;
+};
+
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+inline
+typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, edge_global_t>::type
+get(edge_global_t, BOOST_DISTRIB_CSR_GRAPH_TYPE& g)
+{
+  typedef typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, edge_global_t>
+    ::type result_type;
+  return result_type();
+}
+
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+inline
+std::pair<typename ProcessGroup::process_id_type,
+          typename BOOST_DISTRIB_CSR_GRAPH_TYPE::edges_size_type>
+get(edge_global_t, BOOST_DISTRIB_CSR_GRAPH_TYPE& g,
+    typename BOOST_DISTRIB_CSR_GRAPH_TYPE::edge_descriptor k)
+{
+  return get(edge_global, 
+             const_cast<const BOOST_DISTRIB_CSR_GRAPH_TYPE&>(g),
+             k);
+}
+
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+inline
+typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, edge_global_t>::const_type
+get(edge_global_t, const BOOST_DISTRIB_CSR_GRAPH_TYPE& g)
+{
+  typedef typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, edge_global_t>
+    ::const_type result_type;
+  return result_type();
+}
+
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+inline
+std::pair<typename ProcessGroup::process_id_type,
+          typename BOOST_DISTRIB_CSR_GRAPH_TYPE::edges_size_type>
+get(edge_global_t, const BOOST_DISTRIB_CSR_GRAPH_TYPE& g,
+    typename BOOST_DISTRIB_CSR_GRAPH_TYPE::edge_descriptor k)
+{
+  typedef typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor
+    vertex_descriptor;
+
+  const int local_index_bits = 
+    sizeof(vertex_descriptor) * CHAR_BIT - processor_bits;
+  
+  typedef std::pair<typename ProcessGroup::process_id_type,
+                    typename BOOST_DISTRIB_CSR_GRAPH_TYPE::edges_size_type>
+    result_type;
+
+  return result_type(k.src >> local_index_bits, k.idx);
+}
+
+// -----------------------------------------------------------------
+// Edge Index Property Map
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+class property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, edge_index_t>
+{
+   typedef typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, edge_global_t>
+    ::type global_map;
+
+ public:
+  typedef local_property_map<
+            typename BOOST_DISTRIB_CSR_GRAPH_TYPE::process_group_type,
+            global_map,
+            identity_property_map> type;
+  typedef type const_type;
+};
+
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+inline
+typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, edge_index_t>::type
+get(edge_index_t, BOOST_DISTRIB_CSR_GRAPH_TYPE& g)
+{
+  typedef typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, edge_index_t>
+    ::type result_type;
+  return result_type(g.process_group(), get(edge_global, g),
+                     identity_property_map());
+}
+
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+inline typename BOOST_DISTRIB_CSR_GRAPH_TYPE::edges_size_type
+get(edge_index_t, BOOST_DISTRIB_CSR_GRAPH_TYPE& g,
+    typename BOOST_DISTRIB_CSR_GRAPH_TYPE::edge_descriptor k)
+{
+  return k.idx;
+}
+
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+inline
+typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, edge_index_t>::const_type
+get(edge_index_t, const BOOST_DISTRIB_CSR_GRAPH_TYPE& g)
+{
+  typedef typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, edge_index_t>
+    ::const_type result_type;
+  return result_type(g.process_group(), get(edge_global, g),
+                     identity_property_map());
+}
+
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS>
+inline typename BOOST_DISTRIB_CSR_GRAPH_TYPE::edges_size_type
+get(edge_index_t, const BOOST_DISTRIB_CSR_GRAPH_TYPE& g,
+    typename BOOST_DISTRIB_CSR_GRAPH_TYPE::edge_descriptor k)
+{
+  return k.idx;
+}
+
+// -----------------------------------------------------------------
+// Bundled Properties
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS, typename T, typename Bundle>
+class property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, T Bundle::*>
+{
+  typedef BOOST_DISTRIB_CSR_GRAPH_TYPE Graph;
+  typedef typename Graph::process_group_type process_group_type;
+
+  // Determine which locator map to use (vertex or edge)
+  typedef typename mpl::if_<detail::is_vertex_bundle<VertexProperty,
+                                                     EdgeProperty,
+                                                     Bundle>,
+                            vertex_global_t, edge_global_t>::type global_t;
+
+  // Extract the global property map for our key type.
+  typedef typename property_map<Graph, global_t>::const_type global_map;
+  typedef typename property_traits<global_map>::value_type locator;
+
+  // Determine which bundle type we are using
+  typedef typename mpl::if_<detail::is_vertex_bundle<VertexProperty,
+                                                     EdgeProperty,
+                                                     Bundle>,
+                            VertexProperty, EdgeProperty>::type bundle_t;
+
+public:
+  // Build the local property map
+  typedef bundle_property_map<std::vector<bundle_t>,
+                              typename locator::second_type,
+                              bundle_t,
+                              T> local_pmap;
+
+  // Build the local const property map
+  typedef bundle_property_map<const std::vector<bundle_t>,
+                              typename locator::second_type,
+                              bundle_t,
+                              const T> local_const_pmap;
+  typedef ::boost::parallel::distributed_property_map<
+            process_group_type, global_map, local_pmap> type;
+
+  typedef ::boost::parallel::distributed_property_map<
+            process_group_type, global_map, local_const_pmap> const_type;
+};
+
+namespace detail {
+  // Retrieve the local bundle_property_map corresponding to a
+  // non-const vertex property.
+  template<typename Graph, typename T, typename Bundle>
+  inline bundle_property_map<std::vector<typename Graph::vertex_bundled>,
+                             typename Graph::vertex_descriptor,
+                             typename Graph::vertex_bundled, T>
+  get_distrib_csr_bundle(T Bundle::* p, Graph& g, mpl::true_)
+  {
+    typedef bundle_property_map<std::vector<typename Graph::vertex_bundled>,
+                                typename Graph::vertex_descriptor,
+                                typename Graph::vertex_bundled, T> result_type;
+    return result_type(&g.base().vertex_properties().m_vertex_properties, p);
+  }
+
+  // Retrieve the local bundle_property_map corresponding to a
+  // const vertex property.
+  template<typename Graph, typename T, typename Bundle>
+  inline bundle_property_map<const std::vector<typename Graph::vertex_bundled>,
+                             typename Graph::vertex_descriptor,
+                             typename Graph::vertex_bundled, const T>
+  get_distrib_csr_bundle(T Bundle::* p, const Graph& g, mpl::true_)
+  {
+    typedef bundle_property_map<
+              const std::vector<typename Graph::vertex_bundled>,
+              typename Graph::vertex_descriptor,
+              typename Graph::vertex_bundled, const T> result_type;
+    return result_type(&g.base().vertex_properties().m_vertex_properties, p);
+  }
+
+  // Retrieve the local bundle_property_map corresponding to a
+  // non-const edge property.
+  template<typename Graph, typename T, typename Bundle>
+  inline bundle_property_map<std::vector<typename Graph::edge_bundled>,
+                             typename Graph::edges_size_type,
+                             typename Graph::edge_bundled, T>
+  get_distrib_csr_bundle(T Bundle::* p, Graph& g, mpl::false_)
+  {
+    typedef bundle_property_map<std::vector<typename Graph::edge_bundled>,
+                                typename Graph::edges_size_type,
+                                typename Graph::edge_bundled, T> result_type;
+    return result_type(&g.base().edge_properties().m_edge_properties, p);
+  }
+
+  // Retrieve the local bundle_property_map corresponding to a
+  // const edge property.
+  template<typename Graph, typename T, typename Bundle>
+  inline bundle_property_map<const std::vector<typename Graph::edge_bundled>,
+                             typename Graph::edges_size_type,
+                             typename Graph::edge_bundled, const T>
+  get_distrib_csr_bundle(T Bundle::* p, const Graph& g, mpl::false_)
+  {
+    typedef bundle_property_map<
+              const std::vector<typename Graph::edge_bundled>,
+              typename Graph::edges_size_type,
+              typename Graph::edge_bundled, const T> result_type;
+    return result_type(&g.base().edge_properties().m_edge_properties, p);
+  }
+}
+
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS, typename T, typename Bundle>
+typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, T Bundle::*>::type
+get(T Bundle::* p, BOOST_DISTRIB_CSR_GRAPH_TYPE& g)
+{
+  typedef BOOST_DISTRIB_CSR_GRAPH_TYPE Graph;
+  typedef typename property_map<Graph, T Bundle::*>::type result_type;
+  typedef typename property_map<Graph, T Bundle::*>::local_pmap local_pmap;
+
+  // Resolver
+  typedef typename property_traits<result_type>::value_type value_type;
+  typedef typename property_reduce<T Bundle::*>::template apply<value_type>
+    reduce;
+
+  typedef typename property_traits<result_type>::key_type descriptor;
+  typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
+  typedef typename mpl::if_<is_same<descriptor, vertex_descriptor>,
+                            vertex_global_t, edge_global_t>::type
+    global_map_t;
+
+  return result_type(g.process_group(), get(global_map_t(), g),
+                     detail::get_distrib_csr_bundle
+                       (p, g, mpl::bool_<is_same<descriptor,
+                                         vertex_descriptor>::value>()),
+                     reduce());
+}
+
+template<BOOST_DISTRIB_CSR_GRAPH_TEMPLATE_PARMS, typename T, typename Bundle>
+typename property_map<BOOST_DISTRIB_CSR_GRAPH_TYPE, T Bundle::*>::const_type
+get(T Bundle::* p, const BOOST_DISTRIB_CSR_GRAPH_TYPE& g)
+{
+  typedef BOOST_DISTRIB_CSR_GRAPH_TYPE Graph;
+  typedef typename property_map<Graph, T Bundle::*>::const_type result_type;
+  typedef typename property_map<Graph, T Bundle::*>::local_const_pmap
+    local_pmap;
+
+  // Resolver
+  typedef typename property_traits<result_type>::value_type value_type;
+  typedef typename property_reduce<T Bundle::*>::template apply<value_type>
+    reduce;
+
+  typedef typename property_traits<result_type>::key_type descriptor;
+  typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
+  typedef typename mpl::if_<is_same<descriptor, vertex_descriptor>,
+                            vertex_global_t, edge_global_t>::type
+    global_map_t;
+
+  return result_type(g.process_group(), get(global_map_t(), g),
+                     detail::get_distrib_csr_bundle
+                       (p, g, mpl::bool_<is_same<descriptor,
+                                                 vertex_descriptor>::value>()),
+                     reduce());
+}
+
+namespace mpi {
+  template<typename Vertex, typename EdgeIndex>
+  struct is_mpi_datatype<csr_edge_descriptor<Vertex, EdgeIndex> >
+    : mpl::true_ { };
+}
+
+namespace serialization {
+  template<typename Vertex, typename EdgeIndex>
+  struct is_bitwise_serializable<csr_edge_descriptor<Vertex, EdgeIndex> >
+    : mpl::true_ { };
+
+  template<typename Vertex, typename EdgeIndex>
+  struct implementation_level<csr_edge_descriptor<Vertex, EdgeIndex> >
+   : mpl::int_<object_serializable> {} ;
+
+  template<typename Vertex, typename EdgeIndex>
+  struct tracking_level<csr_edge_descriptor<Vertex, EdgeIndex> >
+   : mpl::int_<track_never> {} ;
+
+}
+
+} // end namespace boost
+
+#endif // BOOST_GRAPH_DISTRIBUTED_CSR_HPP
Added: trunk/boost/graph/distributed/concepts.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/distributed/concepts.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -0,0 +1,216 @@
+// 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>
+
+#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() {
+    function_requires< GraphConcept<G> >();
+    function_requires< MultiPassInputIteratorConcept<vertex_iterator> >();
+    function_requires< 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() {
+    function_requires< GraphConcept<G> >();
+    function_requires< MultiPassInputIteratorConcept<edge_iterator> >();
+    function_requires< DefaultConstructibleConcept<edge_descriptor> >();
+    function_requires< EqualityComparableConcept<edge_descriptor> >();
+    function_requires< AssignableConcept<edge_descriptor> >();
+    function_requires< 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
Added: trunk/boost/graph/distributed/connected_components.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/distributed/connected_components.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -0,0 +1,767 @@
+// 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/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 <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)) {
+          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 (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
+            (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
+          sort(my_adj.begin(), my_adj.end(), std::less<vertex_descriptor>());
+          my_adj.erase(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
+      size_t lone_vertex_count = roots.size();
+
+      // 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
+                assert(__gnu_cxx::is_sorted(my_adj.begin(),
+                                            my_adj.end() - adj[*liter].size(),
+                                            std::less<vertex_descriptor>()));
+                assert(__gnu_cxx::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
+            assert(__gnu_cxx::is_sorted(my_adj.begin(),
+                                        my_adj.end() - (num_incoming_edges-1),
+                                        std::less<vertex_descriptor>()));
+            assert(__gnu_cxx::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
+              (remove_if(my_adj.begin(), my_adj.end(),
+                         cull_adjacency_list<vertex_descriptor,
+                                             ParentMap>(*liter, p) ),
+               my_adj.end());
+#ifndef PBGL_IN_PLACE_MERGE
+            sort(my_adj.begin(), my_adj.end(),
+                 std::less<vertex_descriptor>() );
+#endif
+            my_adj.erase(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( 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
Added: trunk/boost/graph/distributed/connected_components_parallel_search.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/distributed/connected_components_parallel_search.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -0,0 +1,408 @@
+// 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/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) 
+      {
+        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)
+      {
+        assert(num_unique > 0);
+        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)
+      {
+        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;
+    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
Added: trunk/boost/graph/distributed/crauser_et_al_shortest_paths.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/distributed/crauser_et_al_shortest_paths.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -0,0 +1,664 @@
+// 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/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;
+      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 (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
Added: trunk/boost/graph/distributed/dehne_gotz_min_spanning_tree.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/distributed/dehne_gotz_min_spanning_tree.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -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 (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 (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 (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
Added: trunk/boost/graph/distributed/delta_stepping_shortest_paths.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/distributed/delta_stepping_shortest_paths.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -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
Added: trunk/boost/graph/distributed/depth_first_search.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/distributed/depth_first_search.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -0,0 +1,306 @@
+// 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/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 (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 (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:
+            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
Added: trunk/boost/graph/distributed/detail/dijkstra_shortest_paths.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/distributed/detail/dijkstra_shortest_paths.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -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
Added: trunk/boost/graph/distributed/detail/filtered_queue.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/distributed/detail/filtered_queue.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -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
Added: trunk/boost/graph/distributed/detail/mpi_process_group.tpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/distributed/detail/mpi_process_group.tpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -0,0 +1,1006 @@
+// -*- C++ -*-
+
+// Copyright (C) 2004-2008 The Trustees of Indiana University.
+// Copyright (C) 2007  Douglas Gregor <doug.gregor_at_[hidden]>
+// Copyright (C) 2007  Matthias Troyer  <troyer_at_[hidden]>
+
+// 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
+//           Matthias Troyer
+
+//#define PBGL_PROCESS_GROUP_DEBUG
+
+#ifndef BOOST_GRAPH_USE_MPI
+#error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
+#endif
+
+#include <cassert>
+#include <algorithm>
+#include <boost/graph/parallel/detail/untracked_pair.hpp>
+#include <numeric>
+#include <iterator>
+#include <functional>
+#include <vector>
+#include <queue>
+#include <stack>
+#include <boost/graph/distributed/detail/tag_allocator.hpp>
+
+// #define PBGL_PROCESS_GROUP_DEBUG
+
+#ifdef PBGL_PROCESS_GROUP_DEBUG
+#  include <iostream>
+#endif
+
+namespace boost { namespace graph { namespace distributed {
+
+struct mpi_process_group::impl
+{
+  
+  typedef mpi_process_group::message_header message_header;
+  typedef mpi_process_group::outgoing_messages outgoing_messages;
+
+  /**
+   * Stores the incoming messages from a particular processor.
+   *
+   * @todo Evaluate whether we should use a deque instance, which
+   * would reduce could reduce the cost of "receiving" messages and
+     allow us to deallocate memory earlier, but increases the time
+     spent in the synchronization step.
+   */
+  struct incoming_messages {
+    incoming_messages();
+    ~incoming_messages() {}
+
+    std::vector<message_header> headers;
+    buffer_type                 buffer;
+    std::vector<std::vector<message_header>::iterator> next_header;
+  };
+
+  struct batch_request {
+    MPI_Request request;
+    buffer_type buffer;
+  };
+
+  // send once we have a certain number of messages or bytes in the buffer
+  // these numbers need to be tuned, we keep them small at first for testing
+  std::size_t batch_header_number;
+  std::size_t batch_buffer_size;
+  std::size_t batch_message_size;
+  
+  /**
+   * The actual MPI communicator used to transmit data.
+   */
+  boost::mpi::communicator             comm;
+
+  /**
+   * The MPI communicator used to transmit out-of-band replies.
+   */
+  boost::mpi::communicator             oob_reply_comm;
+
+  /// Outgoing message information, indexed by destination processor.
+  std::vector<outgoing_messages> outgoing;
+
+  /// Incoming message information, indexed by source processor.
+  std::vector<incoming_messages> incoming;
+
+  /// The numbers of processors that have entered a synchronization stage
+  std::vector<int> processors_synchronizing_stage;
+  
+  /// The synchronization stage of a processor
+  std::vector<int> synchronizing_stage;
+
+  /// Number of processors still sending messages
+  std::vector<int> synchronizing_unfinished;
+  
+  /// Number of batches sent since last synchronization stage
+  std::vector<int> number_sent_batches;
+  
+  /// Number of batches received minus number of expected batches
+  std::vector<int> number_received_batches;
+  
+
+  /// The context of the currently-executing trigger, or @c trc_none
+  /// if no trigger is executing.
+  trigger_receive_context trigger_context;
+
+  /// Non-zero indicates that we're processing batches
+  /// Increment this when processing patches,
+  /// decrement it when you're done.
+  int processing_batches;
+
+  /**
+   * Contains all of the active blocks corresponding to attached
+   * distributed data structures.
+   */
+  blocks_type blocks;
+
+  /// Whether we are currently synchronizing
+  bool synchronizing;
+
+  /// The MPI requests for posted sends of oob messages
+  std::vector<MPI_Request> requests;
+  
+  /// The MPI buffers for posted irecvs of oob messages
+  std::map<int,buffer_type> buffers;
+
+  /// Queue for message batches received while already processing messages
+  std::queue<std::pair<int,outgoing_messages> > new_batches;
+  /// Maximum encountered size of the new_batches queue
+  std::size_t max_received;
+
+  /// The MPI requests and buffers for batchess being sent
+  std::list<batch_request> sent_batches;
+  /// Maximum encountered size of the sent_batches list
+  std::size_t max_sent;
+
+  /// Pre-allocated requests in a pool
+  std::vector<batch_request> batch_pool;
+  /// A stack controlling which batches are available
+  std::stack<std::size_t> free_batches;
+
+  void free_sent_batches();
+  
+  // Tag allocator
+  detail::tag_allocator allocated_tags;
+
+  impl(std::size_t num_headers, std::size_t buffers_size,
+       communicator_type parent_comm);
+  ~impl();
+  
+private:
+  void set_batch_size(std::size_t header_num, std::size_t buffer_sz);
+};
+
+inline trigger_receive_context mpi_process_group::trigger_context() const
+{
+  return impl_->trigger_context;
+}
+
+template<typename T>
+void
+mpi_process_group::send_impl(int dest, int tag, const T& value,
+                             mpl::true_ /*is_mpi_datatype*/) const
+{
+  assert(tag <  msg_reserved_first || tag > msg_reserved_last);
+
+  impl::outgoing_messages& outgoing = impl_->outgoing[dest];
+
+  // Start constructing the message header
+  impl::message_header header;
+  header.source = process_id(*this);
+  header.tag = tag;
+  header.offset = outgoing.buffer.size();
+  
+  boost::mpi::packed_oarchive oa(impl_->comm, outgoing.buffer);
+  oa << value;
+
+#ifdef PBGL_PROCESS_GROUP_DEBUG
+  std::cerr << "SEND: " << process_id(*this) << " -> " << dest << ", tag = "
+            << tag << ", bytes = " << packed_size << std::endl;
+#endif
+
+  // Store the header
+  header.bytes = outgoing.buffer.size() - header.offset;
+  outgoing.headers.push_back(header);
+
+  maybe_send_batch(dest);
+}
+
+
+template<typename T>
+void
+mpi_process_group::send_impl(int dest, int tag, const T& value,
+                             mpl::false_ /*is_mpi_datatype*/) const
+{
+  assert(tag <  msg_reserved_first || tag > msg_reserved_last);
+
+  impl::outgoing_messages& outgoing = impl_->outgoing[dest];
+
+  // Start constructing the message header
+  impl::message_header header;
+  header.source = process_id(*this);
+  header.tag = tag;
+  header.offset = outgoing.buffer.size();
+
+  // Serialize into the buffer
+  boost::mpi::packed_oarchive out(impl_->comm, outgoing.buffer);
+  out << value;
+
+  // Store the header
+  header.bytes = outgoing.buffer.size() - header.offset;
+  outgoing.headers.push_back(header);
+  maybe_send_batch(dest);
+
+#ifdef PBGL_PROCESS_GROUP_DEBUG
+  std::cerr << "SEND: " << process_id(*this) << " -> " << dest << ", tag = "
+            << tag << ", bytes = " << header.bytes << std::endl;
+#endif
+}
+
+template<typename T>
+inline void
+send(const mpi_process_group& pg, mpi_process_group::process_id_type dest,
+     int tag, const T& value)
+{
+  pg.send_impl(dest, pg.encode_tag(pg.my_block_number(), tag), value,
+               boost::mpi::is_mpi_datatype<T>());
+}
+
+template<typename T>
+typename enable_if<boost::mpi::is_mpi_datatype<T>, void>::type
+send(const mpi_process_group& pg, mpi_process_group::process_id_type dest,
+     int tag, const T values[], std::size_t n)
+{
+  pg.send_impl(dest, pg.encode_tag(pg.my_block_number(), tag),
+                 boost::serialization::make_array(values,n), 
+                 boost::mpl::true_());
+}
+
+template<typename T>
+typename disable_if<boost::mpi::is_mpi_datatype<T>, void>::type
+mpi_process_group::
+array_send_impl(int dest, int tag, const T values[], std::size_t n) const
+{
+  assert(tag <  msg_reserved_first || tag > msg_reserved_last);
+
+  impl::outgoing_messages& outgoing = impl_->outgoing[dest];
+
+  // Start constructing the message header
+  impl::message_header header;
+  header.source = process_id(*this);
+  header.tag = tag;
+  header.offset = outgoing.buffer.size();
+
+  // Serialize into the buffer
+  boost::mpi::packed_oarchive out(impl_->comm, outgoing.buffer);
+  out << n;
+
+  for (std::size_t i = 0; i < n; ++i)
+    out << values[i];
+
+  // Store the header
+  header.bytes = outgoing.buffer.size() - header.offset;
+  outgoing.headers.push_back(header);
+  maybe_send_batch(dest);
+
+#ifdef PBGL_PROCESS_GROUP_DEBUG
+  std::cerr << "SEND: " << process_id(*this) << " -> " << dest << ", tag = "
+            << tag << ", bytes = " << header.bytes << std::endl;
+#endif
+}
+
+template<typename T>
+typename disable_if<boost::mpi::is_mpi_datatype<T>, void>::type
+send(const mpi_process_group& pg, mpi_process_group::process_id_type dest,
+     int tag, const T values[], std::size_t n)
+{
+  pg.array_send_impl(dest, pg.encode_tag(pg.my_block_number(), tag), 
+                     values, n);
+}
+
+template<typename InputIterator>
+void
+send(const mpi_process_group& pg, mpi_process_group::process_id_type dest,
+     int tag, InputIterator first, InputIterator last)
+{
+  typedef typename std::iterator_traits<InputIterator>::value_type value_type;
+  std::vector<value_type> values(first, last);
+  if (values.empty()) send(pg, dest, tag, static_cast<value_type*>(0), 0);
+  else send(pg, dest, tag, &values[0], values.size());
+}
+
+template<typename T>
+bool
+mpi_process_group::receive_impl(int source, int tag, T& value,
+                                mpl::true_ /*is_mpi_datatype*/) const
+{
+#ifdef PBGL_PROCESS_GROUP_DEBUG
+  std::cerr << "RECV: " << process_id(*this) << " <- " << source << ", tag = "
+            << tag << std::endl;
+#endif
+
+  impl::incoming_messages& incoming = impl_->incoming[source];
+
+  // Find the next header with the right tag
+  std::vector<impl::message_header>::iterator header =
+    incoming.next_header[my_block_number()];
+  while (header != incoming.headers.end() && header->tag != tag) ++header;
+
+  // If no header is found, notify the caller
+  if (header == incoming.headers.end()) return false;
+
+  // Unpack the data
+  if (header->bytes > 0) {
+    boost::mpi::packed_iarchive ia(impl_->comm, incoming.buffer, 
+                                   archive::no_header, header->offset);
+    ia >> value;
+  }
+
+  // Mark this message as received
+  header->tag = -1;
+
+  // Move the "next header" indicator to the next unreceived message
+  while (incoming.next_header[my_block_number()] != incoming.headers.end()
+         && incoming.next_header[my_block_number()]->tag == -1)
+    ++incoming.next_header[my_block_number()];
+
+  if (incoming.next_header[my_block_number()] == incoming.headers.end()) {
+    bool finished = true;
+    for (std::size_t i = 0; i < incoming.next_header.size() && finished; ++i) {
+      if (incoming.next_header[i] != incoming.headers.end()) finished = false;
+    }
+
+    if (finished) {
+      std::vector<impl::message_header> no_headers;
+      incoming.headers.swap(no_headers);
+      buffer_type empty_buffer;
+      incoming.buffer.swap(empty_buffer);
+      for (std::size_t i = 0; i < incoming.next_header.size(); ++i)
+        incoming.next_header[i] = incoming.headers.end();
+    }
+  }
+
+  return true;
+}
+
+template<typename T>
+bool
+mpi_process_group::receive_impl(int source, int tag, T& value,
+                                mpl::false_ /*is_mpi_datatype*/) const
+{
+  impl::incoming_messages& incoming = impl_->incoming[source];
+
+  // Find the next header with the right tag
+  std::vector<impl::message_header>::iterator header =
+    incoming.next_header[my_block_number()];
+  while (header != incoming.headers.end() && header->tag != tag) ++header;
+
+  // If no header is found, notify the caller
+  if (header == incoming.headers.end()) return false;
+
+  // Deserialize the data
+  boost::mpi::packed_iarchive in(impl_->comm, incoming.buffer, 
+                                 archive::no_header, header->offset);
+  in >> value;
+
+  // Mark this message as received
+  header->tag = -1;
+
+  // Move the "next header" indicator to the next unreceived message
+  while (incoming.next_header[my_block_number()] != incoming.headers.end()
+         && incoming.next_header[my_block_number()]->tag == -1)
+    ++incoming.next_header[my_block_number()];
+
+  if (incoming.next_header[my_block_number()] == incoming.headers.end()) {
+    bool finished = true;
+    for (std::size_t i = 0; i < incoming.next_header.size() && finished; ++i) {
+      if (incoming.next_header[i] != incoming.headers.end()) finished = false;
+    }
+
+    if (finished) {
+      std::vector<impl::message_header> no_headers;
+      incoming.headers.swap(no_headers);
+      buffer_type empty_buffer;
+      incoming.buffer.swap(empty_buffer);
+      for (std::size_t i = 0; i < incoming.next_header.size(); ++i)
+        incoming.next_header[i] = incoming.headers.end();
+    }
+  }
+
+  return true;
+}
+
+template<typename T>
+typename disable_if<boost::mpi::is_mpi_datatype<T>, bool>::type
+mpi_process_group::
+array_receive_impl(int source, int tag, T* values, std::size_t& n) const
+{
+  impl::incoming_messages& incoming = impl_->incoming[source];
+
+  // Find the next header with the right tag
+  std::vector<impl::message_header>::iterator header =
+    incoming.next_header[my_block_number()];
+  while (header != incoming.headers.end() && header->tag != tag) ++header;
+
+  // If no header is found, notify the caller
+  if (header == incoming.headers.end()) return false;
+
+  // Deserialize the data
+  boost::mpi::packed_iarchive in(impl_->comm, incoming.buffer, 
+                                 archive::no_header, header->offset);
+  std::size_t num_sent;
+  in >> num_sent;
+  if (num_sent > n)
+    std::cerr << "ERROR: Have " << num_sent << " items but only space for "
+              << n << " items\n";
+
+  for (std::size_t i = 0; i < num_sent; ++i)
+    in >> values[i];
+  n = num_sent;
+
+  // Mark this message as received
+  header->tag = -1;
+
+  // Move the "next header" indicator to the next unreceived message
+  while (incoming.next_header[my_block_number()] != incoming.headers.end()
+         && incoming.next_header[my_block_number()]->tag == -1)
+    ++incoming.next_header[my_block_number()];
+
+  if (incoming.next_header[my_block_number()] == incoming.headers.end()) {
+    bool finished = true;
+    for (std::size_t i = 0; i < incoming.next_header.size() && finished; ++i) {
+      if (incoming.next_header[i] != incoming.headers.end()) finished = false;
+    }
+
+    if (finished) {
+      std::vector<impl::message_header> no_headers;
+      incoming.headers.swap(no_headers);
+      buffer_type empty_buffer;
+      incoming.buffer.swap(empty_buffer);
+      for (std::size_t i = 0; i < incoming.next_header.size(); ++i)
+        incoming.next_header[i] = incoming.headers.end();
+    }
+  }
+
+  return true;
+}
+
+// Construct triggers
+template<typename Type, typename Handler>
+void mpi_process_group::trigger(int tag, const Handler& handler)
+{
+  assert(block_num);
+  install_trigger(tag,my_block_number(),shared_ptr<trigger_base>(
+    new trigger_launcher<Type, Handler>(*this, tag, handler)));
+}
+
+template<typename Type, typename Handler>
+void mpi_process_group::trigger_with_reply(int tag, const Handler& handler)
+{
+  assert(block_num);
+  install_trigger(tag,my_block_number(),shared_ptr<trigger_base>(
+    new reply_trigger_launcher<Type, Handler>(*this, tag, handler)));
+}
+
+template<typename Type, typename Handler>
+void mpi_process_group::global_trigger(int tag, const Handler& handler, 
+      std::size_t sz)
+{
+  if (sz==0) // normal trigger
+    install_trigger(tag,0,shared_ptr<trigger_base>(
+      new global_trigger_launcher<Type, Handler>(*this, tag, handler)));
+  else // trigger with irecv
+    install_trigger(tag,0,shared_ptr<trigger_base>(
+      new global_irecv_trigger_launcher<Type, Handler>(*this, tag, handler,sz)));
+  
+}
+
+namespace detail {
+
+template<typename Type>
+void  do_oob_receive(mpi_process_group const& self,
+    int source, int tag, Type& data, mpl::true_ /*is_mpi_datatype*/) 
+{
+  using boost::mpi::get_mpi_datatype;
+
+  //self.impl_->comm.recv(source,tag,data);
+  MPI_Recv(&data, 1, get_mpi_datatype<Type>(data), source, tag, self.impl_->comm,
+           MPI_STATUS_IGNORE);
+}
+
+template<typename Type>
+void do_oob_receive(mpi_process_group const& self,
+    int source, int tag, Type& data, mpl::false_ /*is_mpi_datatype*/) 
+{
+  //  self.impl_->comm.recv(source,tag,data);
+  // Receive the size of the data packet
+  boost::mpi::status status;
+  status = self.impl_->comm.probe(source, tag);
+
+#if BOOST_VERSION >= 103600
+  int size = status.count<boost::mpi::packed>().get();
+#else
+  int size;
+  MPI_Status& mpi_status = status;
+  MPI_Get_count(&mpi_status, MPI_PACKED, &size);
+#endif
+
+  // Receive the data packed itself
+  boost::mpi::packed_iarchive in(self.impl_->comm);
+  in.resize(size);
+  MPI_Recv(in.address(), size, MPI_PACKED, source, tag, self.impl_->comm,
+       MPI_STATUS_IGNORE);
+
+  // Deserialize the data
+  in >> data;
+}
+
+template<typename Type>
+void do_oob_receive(mpi_process_group const& self, int source, int tag, Type& data) 
+{
+  do_oob_receive(self, source, tag, data,
+                           boost::mpi::is_mpi_datatype<Type>());
+}
+
+
+} // namespace detail
+
+
+template<typename Type, typename Handler>
+void 
+mpi_process_group::trigger_launcher<Type, Handler>::
+receive(mpi_process_group const&, int source, int tag, 
+        trigger_receive_context context, int block) const
+{
+#ifdef PBGL_PROCESS_GROUP_DEBUG
+  std::cerr << (out_of_band? "OOB trigger" : "Trigger") 
+            << " receive from source " << source << " and tag " << tag
+        << " in block " << (block == -1 ? self.my_block_number() : block) << std::endl;
+#endif
+
+  Type data;
+
+  if (context == trc_out_of_band) {
+    // Receive the message directly off the wire
+    int realtag  = self.encode_tag(
+      block == -1 ? self.my_block_number() : block, tag);
+    detail::do_oob_receive(self,source,realtag,data);
+  }
+  else
+    // Receive the message out of the local buffer
+    boost::graph::distributed::receive(self, source, tag, data);
+
+  // Pass the message off to the handler
+  handler(source, tag, data, context);
+}
+
+template<typename Type, typename Handler>
+void 
+mpi_process_group::reply_trigger_launcher<Type, Handler>::
+receive(mpi_process_group const&, int source, int tag, 
+        trigger_receive_context context, int block) const
+{
+#ifdef PBGL_PROCESS_GROUP_DEBUG
+  std::cerr << (out_of_band? "OOB reply trigger" : "Reply trigger") 
+            << " receive from source " << source << " and tag " << tag
+        << " in block " << (block == -1 ? self.my_block_number() : block) << std::endl;
+#endif
+  assert(context == trc_out_of_band);
+
+  boost::parallel::detail::untracked_pair<int, Type> data;
+
+  // Receive the message directly off the wire
+  int realtag  = self.encode_tag(block == -1 ? self.my_block_number() : block,
+                                 tag);
+  detail::do_oob_receive(self, source, realtag, data);
+
+  // Pass the message off to the handler and send the result back to
+  // the source.
+  send_oob(self, source, data.first, 
+           handler(source, tag, data.second, context), -2);
+}
+
+template<typename Type, typename Handler>
+void 
+mpi_process_group::global_trigger_launcher<Type, Handler>::
+receive(mpi_process_group const& self, int source, int tag, 
+        trigger_receive_context context, int block) const
+{
+#ifdef PBGL_PROCESS_GROUP_DEBUG
+  std::cerr << (out_of_band? "OOB trigger" : "Trigger") 
+            << " receive from source " << source << " and tag " << tag
+        << " in block " << (block == -1 ? self.my_block_number() : block) << std::endl;
+#endif
+
+  Type data;
+
+  if (context == trc_out_of_band) {
+    // Receive the message directly off the wire
+    int realtag  = self.encode_tag(
+      block == -1 ? self.my_block_number() : block, tag);
+    detail::do_oob_receive(self,source,realtag,data);
+  }
+  else
+    // Receive the message out of the local buffer
+    boost::graph::distributed::receive(self, source, tag, data);
+
+  // Pass the message off to the handler
+  handler(self, source, tag, data, context);
+}
+
+
+template<typename Type, typename Handler>
+void 
+mpi_process_group::global_irecv_trigger_launcher<Type, Handler>::
+receive(mpi_process_group const& self, int source, int tag, 
+        trigger_receive_context context, int block) const
+{
+#ifdef PBGL_PROCESS_GROUP_DEBUG
+  std::cerr << (out_of_band? "OOB trigger" : "Trigger") 
+            << " receive from source " << source << " and tag " << tag
+        << " in block " << (block == -1 ? self.my_block_number() : block) << std::endl;
+#endif
+
+  Type data;
+
+  if (context == trc_out_of_band) {
+    return;
+  }
+  assert (context == trc_irecv_out_of_band);
+
+  // force posting of new MPI_Irecv, even though buffer is already allocated
+  boost::mpi::packed_iarchive ia(self.impl_->comm,self.impl_->buffers[tag]);
+  ia >> data;
+  // Start a new receive
+  prepare_receive(self,tag,true);
+  // Pass the message off to the handler
+  handler(self, source, tag, data, context);
+}
+
+
+template<typename Type, typename Handler>
+void 
+mpi_process_group::global_irecv_trigger_launcher<Type, Handler>::
+prepare_receive(mpi_process_group const& self, int tag, bool force) const
+{
+#ifdef PBGL_PROCESS_GROUP_DEBUG
+ std::cerr << ("Posting Irecv for trigger") 
+      << " receive with tag " << tag << std::endl;
+#endif
+  if (self.impl_->buffers.find(tag) == self.impl_->buffers.end()) {
+    self.impl_->buffers[tag].resize(buffer_size);
+    force = true;
+  }
+  assert(static_cast<int>(self.impl_->buffers[tag].size()) >= buffer_size);
+  
+  //BOOST_MPL_ASSERT(mpl::not_<is_mpi_datatype<Type> >);
+  if (force) {
+    self.impl_->requests.push_back(MPI_Request());
+    MPI_Request* request = &self.impl_->requests.back();
+    MPI_Irecv(&self.impl_->buffers[tag].front(),buffer_size,
+               MPI_PACKED,MPI_ANY_SOURCE,tag,self.impl_->comm,request);
+  }
+}
+
+
+template<typename T>
+inline mpi_process_group::process_id_type
+receive(const mpi_process_group& pg, int tag, T& value)
+{
+  for (std::size_t source = 0; source < pg.impl_->incoming.size(); ++source) {
+    if (pg.receive_impl(source, pg.encode_tag(pg.my_block_number(), tag),
+                        value, boost::mpi::is_mpi_datatype<T>()))
+      return source;
+  }
+  assert (false);
+}
+
+template<typename T>
+typename 
+  enable_if<boost::mpi::is_mpi_datatype<T>, 
+            std::pair<mpi_process_group::process_id_type, std::size_t> >::type
+receive(const mpi_process_group& pg, int tag, T values[], std::size_t n)
+{
+  for (std::size_t source = 0; source < pg.impl_->incoming.size(); ++source) {
+    bool result =
+      pg.receive_impl(source, pg.encode_tag(pg.my_block_number(), tag),
+                 boost::serialization::make_array(values,n),
+                 boost::mpl::true_());
+    if (result) 
+      return std::make_pair(source, n);
+  }
+  assert(false);
+}
+
+template<typename T>
+typename 
+  disable_if<boost::mpi::is_mpi_datatype<T>, 
+             std::pair<mpi_process_group::process_id_type, std::size_t> >::type
+receive(const mpi_process_group& pg, int tag, T values[], std::size_t n)
+{
+  for (std::size_t source = 0; source < pg.impl_->incoming.size(); ++source) {
+    if (pg.array_receive_impl(source, pg.encode_tag(pg.my_block_number(), tag),
+                              values, n))
+      return std::make_pair(source, n);
+  }
+  assert(false);
+}
+
+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)
+{
+  if (pg.receive_impl(source, pg.encode_tag(pg.my_block_number(), tag),
+                      value, boost::mpi::is_mpi_datatype<T>()))
+    return source;
+  else {
+    fprintf(stderr,
+            "Process %d failed to receive a message from process %d with tag %d in block %d.\n",
+            process_id(pg), source, tag, pg.my_block_number());
+
+    assert(false);
+    exit(1);
+  }
+}
+
+template<typename T>
+typename 
+  enable_if<boost::mpi::is_mpi_datatype<T>, 
+            std::pair<mpi_process_group::process_id_type, std::size_t> >::type
+receive(const mpi_process_group& pg, int source, int tag, T values[], 
+        std::size_t n)
+{
+  if (pg.receive_impl(source, pg.encode_tag(pg.my_block_number(), tag),
+                      boost::serialization::make_array(values,n), 
+                      boost::mpl::true_()))
+    return std::make_pair(source,n);
+  else {
+    fprintf(stderr,
+            "Process %d failed to receive a message from process %d with tag %d in block %d.\n",
+            process_id(pg), source, tag, pg.my_block_number());
+
+    assert(false);
+    exit(1);
+  }
+}
+
+template<typename T>
+typename 
+  disable_if<boost::mpi::is_mpi_datatype<T>, 
+             std::pair<mpi_process_group::process_id_type, std::size_t> >::type
+receive(const mpi_process_group& pg, int source, int tag, T values[], 
+        std::size_t n)
+{
+  pg.array_receive_impl(source, pg.encode_tag(pg.my_block_number(), tag),
+                        values, n);
+
+  return std::make_pair(source, n);
+}
+
+template<typename T, typename BinaryOperation>
+T*
+all_reduce(const mpi_process_group& pg, T* first, T* last, T* out,
+           BinaryOperation bin_op)
+{
+  synchronize(pg);
+
+  bool inplace = first == out;
+
+  if (inplace) out = new T [last-first];
+
+  boost::mpi::all_reduce(boost::mpi::communicator(communicator(pg),
+                                                  boost::mpi::comm_attach), 
+                         first, last-first, out, bin_op);
+
+  if (inplace) {
+    std::copy(out, out + (last-first), first);
+    delete [] out;
+    return last;
+  }
+
+  return out;
+}
+
+template<typename T>
+void
+broadcast(const mpi_process_group& pg, T& val, 
+          mpi_process_group::process_id_type root)
+{
+  // broadcast the seed  
+  boost::mpi::communicator comm(communicator(pg),boost::mpi::comm_attach);
+  boost::mpi::broadcast(comm,val,root);
+}
+
+
+template<typename T, typename BinaryOperation>
+T*
+scan(const mpi_process_group& pg, T* first, T* last, T* out,
+           BinaryOperation bin_op)
+{
+  synchronize(pg);
+
+  bool inplace = first == out;
+
+  if (inplace) out = new T [last-first];
+
+  boost::mpi::scan(communicator(pg), first, last-first, out, bin_op);
+
+  if (inplace) {
+    std::copy(out, out + (last-first), first);
+    delete [] out;
+    return last;
+  }
+
+  return out;
+}
+
+
+template<typename InputIterator, typename T>
+void
+all_gather(const mpi_process_group& pg, InputIterator first,
+           InputIterator last, std::vector<T>& out)
+{
+  synchronize(pg);
+
+  // Stick a copy of the local values into a vector, so we can broadcast it
+  std::vector<T> local_values(first, last);
+
+  // Collect the number of vertices stored in each process
+  int size = local_values.size();
+  std::vector<int> sizes(num_processes(pg));
+  int result = MPI_Allgather(&size, 1, MPI_INT,
+                             &sizes[0], 1, MPI_INT,
+                             communicator(pg));
+  assert(result == MPI_SUCCESS);
+
+  // Adjust sizes based on the number of bytes
+  std::transform(sizes.begin(), sizes.end(), sizes.begin(),
+                 std::bind2nd(std::multiplies<int>(), sizeof(T)));
+
+  // Compute displacements
+  std::vector<int> displacements;
+  displacements.reserve(sizes.size() + 1);
+  displacements.push_back(0);
+  std::partial_sum(sizes.begin(), sizes.end(),
+                   std::back_inserter(displacements));
+
+  // Gather all of the values
+  out.resize(displacements.back() / sizeof(T));
+  if (!out.empty()) {
+    result = MPI_Allgatherv(local_values.empty()? (void*)&local_values
+                            /* local results */: (void*)&local_values[0],
+                            local_values.size() * sizeof(T),
+                            MPI_BYTE,
+                            &out[0], &sizes[0], &displacements[0], MPI_BYTE,
+                            communicator(pg));
+  }
+  assert(result == MPI_SUCCESS);
+}
+
+template<typename InputIterator>
+mpi_process_group
+process_subgroup(const mpi_process_group& pg,
+                 InputIterator first, InputIterator last)
+{
+/*
+  boost::mpi::group current_group = communicator(pg).group();
+  boost::mpi::group new_group = current_group.include(first,last);
+  boost::mpi::communicator new_comm(communicator(pg),new_group);
+  return mpi_process_group(new_comm);
+*/
+  std::vector<int> ranks(first, last);
+
+  MPI_Group current_group;
+  int result = MPI_Comm_group(communicator(pg), ¤t_group);
+  assert(result == MPI_SUCCESS);
+
+  MPI_Group new_group;
+  result = MPI_Group_incl(current_group, ranks.size(), &ranks[0], &new_group);
+  assert(result == MPI_SUCCESS);
+
+  MPI_Comm new_comm;
+  result = MPI_Comm_create(communicator(pg), new_group, &new_comm);
+  assert(result == MPI_SUCCESS);
+
+  result = MPI_Group_free(&new_group);
+  assert(result == MPI_SUCCESS);
+  result = MPI_Group_free(¤t_group);
+  assert(result == MPI_SUCCESS);
+
+  if (new_comm != MPI_COMM_NULL) {
+    mpi_process_group result_pg(boost::mpi::communicator(new_comm,boost::mpi::comm_attach));
+    result = MPI_Comm_free(&new_comm);
+    assert(result == 0);
+    return result_pg;
+  } else {
+    return mpi_process_group(mpi_process_group::create_empty());
+  }
+
+}
+
+
+template<typename Receiver>
+Receiver* mpi_process_group::get_receiver()
+{
+  return impl_->blocks[my_block_number()]->on_receive
+           .template target<Receiver>();
+}
+
+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)
+{
+  using boost::mpi::get_mpi_datatype;
+
+  // Determine the actual message we expect to receive, and which
+  // communicator it will come by.
+  std::pair<boost::mpi::communicator, int> actual
+    = pg.actual_communicator_and_tag(tag, block);
+
+  // Post a non-blocking receive that waits until we complete this request.
+  MPI_Request request;
+  MPI_Irecv(&value, 1, get_mpi_datatype<T>(value),  
+            source, actual.second, actual.first, &request); 
+
+  int done = 0;
+  do {
+    MPI_Test(&request, &done, MPI_STATUS_IGNORE);
+    if (!done)
+      pg.poll(/*wait=*/false, block);
+  } while (!done);
+}
+
+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)
+{
+  // Determine the actual message we expect to receive, and which
+  // communicator it will come by.
+  std::pair<boost::mpi::communicator, int> actual
+    = pg.actual_communicator_and_tag(tag, block);
+
+  boost::optional<boost::mpi::status> status;
+  do {
+    status = actual.first.iprobe(source, actual.second);
+    if (!status)
+      pg.poll();
+  } while (!status);
+
+  //actual.first.recv(status->source(), status->tag(),value);
+
+  // Allocate the receive buffer
+  boost::mpi::packed_iarchive in(actual.first);
+
+#if BOOST_VERSION >= 103600
+  in.resize(status->count<boost::mpi::packed>().get());
+#else
+  int size;
+  MPI_Status mpi_status = *status;
+  MPI_Get_count(&mpi_status, MPI_PACKED, &size);
+  in.resize(size);
+#endif
+  
+  // Receive the message data
+  MPI_Recv(in.address(), in.size(), MPI_PACKED,
+           status->source(), status->tag(), actual.first, MPI_STATUS_IGNORE);
+  
+  // Unpack the message data
+  in >> value;
+}
+
+
+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)
+{
+  detail::tag_allocator::token reply_tag = pg.impl_->allocated_tags.get_tag();
+  send_oob(pg, dest, tag, boost::parallel::detail::make_untracked_pair(
+        (int)reply_tag, send_value), block);
+  receive_oob(pg, dest, reply_tag, reply_value);
+}
+
+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)
+{
+  detail::tag_allocator::token reply_tag = pg.impl_->allocated_tags.get_tag();
+  send_oob(pg, dest, tag, 
+           boost::parallel::detail::make_untracked_pair((int)reply_tag, 
+                                                        send_value), block);
+  receive_oob(pg, dest, reply_tag, reply_value);
+}
+
+} } } // end namespace boost::graph::distributed
Added: trunk/boost/graph/distributed/detail/queue.cpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/distributed/detail/queue.cpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -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
Added: trunk/boost/graph/distributed/detail/remote_update_set.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/distributed/detail/remote_update_set.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -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 <cassert>
+#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];
+          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
+      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
Added: trunk/boost/graph/distributed/detail/tag_allocator.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/distributed/detail/tag_allocator.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -0,0 +1,84 @@
+// -*- C++ -*-
+
+// Copyright (C) 2007  Douglas Gregor  <doug.gregor_at_[hidden]>
+
+// 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
Added: trunk/boost/graph/distributed/dijkstra_shortest_paths.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/distributed/dijkstra_shortest_paths.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -0,0 +1,205 @@
+// 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::detail::error_property_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::detail::error_property_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::detail::error_property_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::detail::error_property_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 property_value< bgl_named_params<T, Tag, Base>,
+      vertex_color_t>::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
Added: trunk/boost/graph/distributed/distributed_graph_utility.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/distributed/distributed_graph_utility.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -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
Added: trunk/boost/graph/distributed/eager_dijkstra_shortest_paths.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/distributed/eager_dijkstra_shortest_paths.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -0,0 +1,446 @@
+// 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/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;
+      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 (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
Added: trunk/boost/graph/distributed/filtered_graph.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/distributed/filtered_graph.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -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
Added: trunk/boost/graph/distributed/fruchterman_reingold.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/distributed/fruchterman_reingold.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -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
Added: trunk/boost/graph/distributed/graphviz.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/distributed/graphviz.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -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 (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 (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
Added: trunk/boost/graph/distributed/hohberg_biconnected_components.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/distributed/hohberg_biconnected_components.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -0,0 +1,1129 @@
+// 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
+
+// An implementation of Walter Hohberg's distributed biconnected
+// components algorithm, from:
+//
+//   Walter Hohberg. How to Find Biconnected Components in Distributed
+//   Networks. J. Parallel Distrib. Comput., 9(4):374-386, 1990.
+//
+#ifndef BOOST_GRAPH_DISTRIBUTED_HOHBERG_BICONNECTED_COMPONENTS_HPP
+#define BOOST_GRAPH_DISTRIBUTED_HOHBERG_BICONNECTED_COMPONENTS_HPP
+
+#ifndef BOOST_GRAPH_USE_MPI
+#error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
+#endif
+
+/* You can define PBGL_HOHBERG_DEBUG to an integer value (1, 2, or 3)
+ * to enable debugging information. 1 includes only the phases of the
+ * algorithm and messages as their are received. 2 and 3 add
+ * additional levels of detail about internal data structures related
+ * to the algorithm itself.
+ *
+ * #define PBGL_HOHBERG_DEBUG 1
+*/
+
+#include <boost/graph/graph_traits.hpp>
+#include <boost/graph/parallel/container_traits.hpp>
+#include <boost/graph/parallel/process_group.hpp>
+#include <boost/static_assert.hpp>
+#include <boost/mpi/operations.hpp>
+#include <boost/type_traits/is_convertible.hpp>
+#include <boost/graph/graph_concepts.hpp>
+#include <boost/graph/iteration_macros.hpp>
+#include <boost/optional.hpp>
+#include <utility> // for std::pair
+#include <cassert>
+#include <algorithm> // for std::find, std::mismatch
+#include <vector>
+#include <boost/graph/parallel/algorithm.hpp>
+#include <boost/graph/distributed/connected_components.hpp>
+
+namespace boost { namespace graph { namespace distributed {
+
+namespace hohberg_detail {
+  enum message_kind {
+    /* A header for the PATH message, stating which edge the message
+       is coming on and how many vertices will be following. The data
+       structure communicated will be a path_header. */
+    msg_path_header,
+    /* A message containing the vertices that make up a path. It will
+       always follow a msg_path_header and will contain vertex
+       descriptors, only. */
+    msg_path_vertices,
+    /* A header for the TREE message, stating the value of gamma and
+       the number of vertices to come in the following
+       msg_tree_vertices. */
+    msg_tree_header,
+    /* A message containing the vertices that make up the set of
+       vertices in the same bicomponent as the sender. It will always
+       follow a msg_tree_header and will contain vertex descriptors,
+       only. */
+    msg_tree_vertices,
+    /* Provides a name for the biconnected component of the edge. */
+    msg_name
+  };
+
+  // Payload for a msg_path_header message.
+  template<typename EdgeDescriptor>
+  struct path_header
+  {
+    // The edge over which the path is being communicated
+    EdgeDescriptor edge;
+
+    // The length of the path, i.e., the number of vertex descriptors
+    // that will be coming in the next msg_path_vertices message.
+    std::size_t    path_length;
+
+    template<typename Archiver>
+    void serialize(Archiver& ar, const unsigned int /*version*/)
+    {
+      ar & edge & path_length;
+    }
+  };
+
+  // Payload for a msg_tree_header message.
+  template<typename Vertex, typename Edge>
+  struct tree_header
+  {
+    // The edge over which the tree is being communicated
+    Edge edge;
+
+    // Gamma, which is the eta of the sender.
+    Vertex gamma;
+
+    // The length of the list of vertices in the bicomponent, i.e.,
+    // the number of vertex descriptors that will be coming in the
+    // next msg_tree_vertices message.
+    std::size_t    bicomp_length;
+
+    template<typename Archiver>
+    void serialize(Archiver& ar, const unsigned int /*version*/)
+    {
+      ar & edge & gamma & bicomp_length;
+    }
+  };
+
+  // Payload for the msg_name message.
+  template<typename EdgeDescriptor>
+  struct name_header
+  {
+    // The edge being communicated and named.
+    EdgeDescriptor edge;
+
+    // The 0-based name of the component
+    std::size_t name;
+
+    template<typename Archiver>
+    void serialize(Archiver& ar, const unsigned int /*version*/)
+    {
+      ar & edge & name;
+    }
+  };
+
+  /* Computes the branch point between two paths. The branch point is
+     the last position at which both paths are equivalent, beyond
+     which the paths diverge. Both paths must have length > 0 and the
+     initial elements of the paths must be equal. This is guaranteed
+     in Hohberg's algorithm because all paths start at the
+     leader. Returns the value at the branch point. */
+  template<typename T>
+  T branch_point(const std::vector<T>& p1, const std::vector<T>& p2)
+  {
+    assert(!p1.empty());
+    assert(!p2.empty());
+    assert(p1.front() == p2.front());
+
+    typedef typename std::vector<T>::const_iterator iterator;
+
+    iterator mismatch_pos;
+    if (p1.size() <= p2.size())
+      mismatch_pos = std::mismatch(p1.begin(), p1.end(), p2.begin()).first;
+    else
+      mismatch_pos = std::mismatch(p2.begin(), p2.end(), p1.begin()).first;
+    --mismatch_pos;
+    return *mismatch_pos;
+  }
+
+  /* Computes the infimum of vertices a and b in the given path. The
+     infimum is the largest element that is on the paths from a to the
+     root and from b to the root. */
+  template<typename T>
+  T infimum(const std::vector<T>& parent_path, T a, T b)
+  {
+    using std::swap;
+
+    typedef typename std::vector<T>::const_iterator iterator;
+    iterator first = parent_path.begin(), last = parent_path.end();
+
+#if defined(PBGL_HOHBERG_DEBUG) and PBGL_HOHBERG_DEBUG > 2
+    std::cerr << "infimum(";
+    for (iterator i = first; i != last; ++i) {
+      if (i != first) std::cerr << ' ';
+      std::cerr << local(*i) << '@' << owner(*i);
+    }
+    std::cerr << ", " << local(a) << '@' << owner(a) << ", "
+              << local(b) << '@' << owner(b) << ") = ";
+#endif
+
+    if (a == b) {
+#if defined(PBGL_HOHBERG_DEBUG) and PBGL_HOHBERG_DEBUG > 2
+      std::cerr << local(a) << '@' << owner(a) << std::endl;
+#endif
+      return a;
+    }
+
+    // Try to find a or b, whichever is closest to the end
+    --last;
+    while (*last != a) {
+      // If we match b, swap the two so we'll be looking for b later.
+      if (*last == b) { swap(a,b); break; }
+
+      if (last == first) {
+#if defined(PBGL_HOHBERG_DEBUG) and PBGL_HOHBERG_DEBUG > 2
+        std::cerr << local(*first) << '@' << owner(*first) << std::endl;
+#endif
+        return *first;
+      }
+      else --last;
+    }
+
+    // Try to find b (which may originally have been a)
+    while (*last != b) {
+      if (last == first) {
+#if defined(PBGL_HOHBERG_DEBUG) and PBGL_HOHBERG_DEBUG > 2
+        std::cerr << local(*first) << '@' << owner(*first) << std::endl;
+#endif
+        return *first;
+      }
+      else --last;
+    }
+
+#if defined(PBGL_HOHBERG_DEBUG) and PBGL_HOHBERG_DEBUG > 2
+    std::cerr << local(*last) << '@' << owner(*last) << std::endl;
+#endif
+    // We've found b; it's the infimum.
+    return *last;
+  }
+} // end namespace hohberg_detail
+
+/* A message that will be stored for each edge by Hohberg's algorithm. */
+template<typename Graph>
+struct hohberg_message
+{
+  typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
+  typedef typename graph_traits<Graph>::edge_descriptor   Edge;
+
+  // Assign from a path message
+  void assign(const std::vector<Vertex>& path)
+  {
+    gamma = graph_traits<Graph>::null_vertex();
+    path_or_bicomp = path;
+  }
+
+  // Assign from a tree message
+  void assign(Vertex gamma, const std::vector<Vertex>& in_same_bicomponent)
+  {
+    this->gamma = gamma;
+    path_or_bicomp = in_same_bicomponent;
+  }
+
+  bool is_path() const { return gamma == graph_traits<Graph>::null_vertex(); }
+  bool is_tree() const { return gamma != graph_traits<Graph>::null_vertex(); }
+
+  /// The "gamma" of a tree message, or null_vertex() for a path message
+  Vertex gamma;
+
+  // Either the path for a path message or the in_same_bicomponent
+  std::vector<Vertex> path_or_bicomp;
+};
+
+
+/* An abstraction of a vertex processor in Hohberg's algorithm. The
+   hohberg_vertex_processor class is responsible for processing
+   messages transmitted to it via its edges. */
+template<typename Graph>
+class hohberg_vertex_processor
+{
+  typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
+  typedef typename graph_traits<Graph>::edge_descriptor   Edge;
+  typedef typename graph_traits<Graph>::degree_size_type  degree_size_type;
+  typedef typename graph_traits<Graph>::edges_size_type   edges_size_type;
+  typedef typename boost::graph::parallel::process_group_type<Graph>::type
+    ProcessGroup;
+  typedef std::vector<Vertex> path_t;
+  typedef typename path_t::iterator path_iterator;
+
+ public:
+  hohberg_vertex_processor()
+    : phase(1),
+      parent(graph_traits<Graph>::null_vertex()),
+      eta(graph_traits<Graph>::null_vertex())
+  {
+  }
+
+  // Called to initialize a leader in the algorithm, which involves
+  // sending out the initial path messages and being ready to receive
+  // them.
+  void initialize_leader(Vertex alpha, const Graph& g);
+
+  /// Handle a path message on edge e. The path will be destroyed by
+  /// this operation.
+  void
+  operator()(Edge e, path_t& path, const Graph& g);
+
+  /// Handle a tree message on edge e. in_same_bicomponent will be
+  /// destroyed by this operation.
+  void
+  operator()(Edge e, Vertex gamma, path_t& in_same_bicomponent,
+             const Graph& g);
+
+  // Handle a name message.
+  void operator()(Edge e, edges_size_type name, const Graph& g);
+
+  // Retrieve the phase
+  unsigned char get_phase() const { return phase; }
+
+  // Start the naming phase. The current phase must be 3 (echo), and
+  // the offset contains the offset at which this processor should
+  // begin when labelling its bicomponents. The offset is just a
+  // parallel prefix sum of the number of bicomponents in each
+  // processor that precedes it (globally).
+  void
+  start_naming_phase(Vertex alpha, const Graph& g, edges_size_type offset);
+
+  /* Determine the number of bicomponents that we will be naming
+   * ourselves.
+   */
+  edges_size_type num_starting_bicomponents(Vertex alpha, const Graph& g);
+
+  // Fill in the edge component map with biconnected component
+  // numbers.
+  template<typename ComponentMap>
+  void fill_edge_map(Vertex alpha, const Graph& g, ComponentMap& component);
+
+ protected:
+  /* Start the echo phase (phase 3) where we propagate information up
+     the tree. */
+  void echo_phase(Vertex alpha, const Graph& g);
+
+  /* Retrieve the index of edge in the out-edges list of target(e, g). */
+  std::size_t get_edge_index(Edge e, const Graph& g);
+
+  /* Retrieve the index of the edge incidence on v in the out-edges
+     list of vertex u. */
+  std::size_t get_incident_edge_index(Vertex u, Vertex v, const Graph& g);
+
+  /* Keeps track of which phase of the algorithm we are in. There are
+   * four phases plus the "finished" phase:
+   *
+   *   1) Building the spanning tree
+   *   2) Discovering cycles
+   *   3) Echoing back up the spanning tree
+   *   4) Labelling biconnected components
+   *   5) Finished
+   */
+  unsigned char phase;
+
+  /* The parent of this vertex in the spanning tree. This value will
+     be graph_traits<Graph>::null_vertex() for the leader. */
+  Vertex parent;
+
+  /* The farthest ancestor up the tree that resides in the same
+     biconnected component as we do. This information is approximate:
+     we might not know about the actual farthest ancestor, but this is
+     the farthest one we've seen so far. */
+  Vertex eta;
+
+  /* The number of edges that have not yet transmitted any messages to
+     us. This starts at the degree of the vertex and decreases as we
+     receive messages. When this counter hits zero, we're done with
+     the second phase of the algorithm. In Hohberg's paper, the actual
+     remaining edge set E is stored with termination when all edges
+     have been removed from E, but we only need to detect termination
+     so the set E need not be explicitly represented. */
+  degree_size_type num_edges_not_transmitted;
+
+  /* The path from the root of the spanning tree to this vertex. This
+     vector will always store only the parts of the path leading up to
+     this vertex, and not the vertex itself. Thus, it will be empty
+     for the leader. */
+  std::vector<Vertex> path_from_root;
+
+  /* Structure containing all of the extra data we need to keep around
+     PER EDGE. This information can not be contained within a property
+     map, because it can't be shared among vertices without breaking
+     the algorithm. Decreasing the size of this structure will drastically */
+  struct per_edge_data
+  {
+    hohberg_message<Graph> msg;
+    std::vector<Vertex> M;
+    bool is_tree_edge;
+    degree_size_type partition;
+  };
+
+  /* Data for each edge in the graph. This structure will be indexed
+     by the position of the edge in the out_edges() list. */
+  std::vector<per_edge_data> edge_data;
+
+  /* The mapping from local partition numbers (0..n-1) to global
+     partition numbers. */
+  std::vector<edges_size_type> local_to_global_partitions;
+
+  friend class boost::serialization::access;
+
+  // We cannot actually serialize a vertex processor, nor would we
+  // want to. However, the fact that we're putting instances into a
+  // distributed_property_map means that we need to have a serialize()
+  // function available.
+  template<typename Archiver>
+  void serialize(Archiver&, const unsigned int /*version*/)
+  {
+    assert(false);
+  }
+};
+
+template<typename Graph>
+void
+hohberg_vertex_processor<Graph>::initialize_leader(Vertex alpha,
+                                                   const Graph& g)
+{
+  using namespace hohberg_detail;
+
+  ProcessGroup pg = process_group(g);
+
+  typename property_map<Graph, vertex_owner_t>::const_type
+    owner = get(vertex_owner, g);
+
+  path_header<Edge> header;
+  header.path_length = 1;
+  BGL_FORALL_OUTEDGES_T(alpha, e, g, Graph) {
+    header.edge = e;
+    send(pg, get(owner, target(e, g)), msg_path_header, header);
+    send(pg, get(owner, target(e, g)), msg_path_vertices, alpha);
+  }
+
+  num_edges_not_transmitted = degree(alpha, g);
+  edge_data.resize(num_edges_not_transmitted);
+  phase = 2;
+}
+
+template<typename Graph>
+void
+hohberg_vertex_processor<Graph>::operator()(Edge e, path_t& path,
+                                            const Graph& g)
+{
+  using namespace hohberg_detail;
+
+  typename property_map<Graph, vertex_owner_t>::const_type
+    owner = get(vertex_owner, g);
+
+#ifdef PBGL_HOHBERG_DEBUG
+//  std::cerr << local(source(e, g)) << '@' << owner(source(e, g)) << " -> "
+//            << local(target(e, g)) << '@' << owner(target(e, g)) << ": path(";
+//  for (std::size_t i = 0; i < path.size(); ++i) {
+//    if (i > 0) std::cerr << ' ';
+//    std::cerr << local(path[i]) << '@' << owner(path[i]);
+//  }
+  std::cerr << "), phase = " << (int)phase << std::endl;
+#endif
+
+  // Get access to edge-specific data
+  if (edge_data.empty())
+    edge_data.resize(degree(target(e, g), g));
+  per_edge_data& edata = edge_data[get_edge_index(e, g)];
+
+  // Record the message. We'll need it in phase 3.
+  edata.msg.assign(path);
+
+  // Note: "alpha" refers to the vertex "processor" receiving the
+  // message.
+  Vertex alpha = target(e, g);
+
+  switch (phase) {
+  case 1:
+    {
+      num_edges_not_transmitted = degree(alpha, g) - 1;
+      edata.is_tree_edge = true;
+      parent = path.back();
+      eta = parent;
+      edata.M.clear(); edata.M.push_back(parent);
+
+      // Broadcast the path from the root to our potential children in
+      // the spanning tree.
+      path.push_back(alpha);
+      path_header<Edge> header;
+      header.path_length = path.size();
+      ProcessGroup pg = process_group(g);
+      BGL_FORALL_OUTEDGES_T(alpha, oe, g, Graph) {
+        // Skip the tree edge we just received
+        if (target(oe, g) != source(e, g)) {
+          header.edge = oe;
+          send(pg, get(owner, target(oe, g)), msg_path_header, header);
+          send(pg, get(owner, target(oe, g)), msg_path_vertices, &path[0],
+               header.path_length);
+        }
+      }
+      path.pop_back();
+
+      // Swap the old path in, to save some extra copying. Nobody
+      path_from_root.swap(path);
+
+      // Once we have received our place in the spanning tree, move on
+      // to phase 2.
+      phase = 2;
+
+      // If we only had only edge, skip to phase 3.
+      if (num_edges_not_transmitted == 0)
+        echo_phase(alpha, g);
+      return;
+    }
+
+  case 2:
+    {
+      --num_edges_not_transmitted;
+      edata.is_tree_edge = false;
+
+      // Determine if alpha (our vertex) is in the path
+      path_iterator pos = std::find(path.begin(), path.end(), alpha);
+      if (pos != path.end()) {
+        // Case A: There is a cycle alpha beta ... gamma alpha
+        // M(e) <- {beta, gammar}
+        edata.M.clear();
+        ++pos;
+        // If pos == path.end(), we have a self-loop
+        if (pos != path.end()) {
+          // Add beta
+          edata.M.push_back(*pos);
+          ++pos;
+        }
+        // If pos == path.end(), we have a self-loop or beta == gamma
+        // (parallel edge). Otherwise, add gamma.
+        if (pos != path.end()) edata.M.push_back(path.back());
+      } else {
+        // Case B: There is a cycle but we haven't seen alpha yet.
+        // M(e) = {parent, path.back()}
+        edata.M.clear();
+        edata.M.push_back(path.back());
+        if (parent != path.back()) edata.M.push_back(parent);
+
+        // eta = inf(eta, bra(pi_t, pi))
+        eta = infimum(path_from_root, eta, branch_point(path_from_root, path));
+      }
+      if (num_edges_not_transmitted == 0)
+        echo_phase(alpha, g);
+      break;
+    }
+
+  default:
+//    std::cerr << "Phase is " << int(phase) << "\n";
+    assert(false);
+  }
+}
+
+template<typename Graph>
+void
+hohberg_vertex_processor<Graph>::operator()(Edge e, Vertex gamma,
+                                            path_t& in_same_bicomponent,
+                                            const Graph& g)
+{
+  using namespace hohberg_detail;
+
+#ifdef PBGL_HOHBERG_DEBUG
+  std::cerr << local(source(e, g)) << '@' << owner(source(e, g)) << " -> "
+            << local(target(e, g)) << '@' << owner(target(e, g)) << ": tree("
+            << local(gamma) << '@' << owner(gamma) << ", ";
+  for (std::size_t i = 0; i < in_same_bicomponent.size(); ++i) {
+    if (i > 0) std::cerr << ' ';
+    std::cerr << local(in_same_bicomponent[i]) << '@'
+              << owner(in_same_bicomponent[i]);
+  }
+  std::cerr << ", " << local(source(e, g)) << '@' << owner(source(e, g))
+            << "), phase = " << (int)phase << std::endl;
+#endif
+
+  // Get access to edge-specific data
+  per_edge_data& edata = edge_data[get_edge_index(e, g)];
+
+  // Record the message. We'll need it in phase 3.
+  edata.msg.assign(gamma, in_same_bicomponent);
+
+  // Note: "alpha" refers to the vertex "processor" receiving the
+  // message.
+  Vertex alpha = target(e, g);
+  Vertex beta = source(e, g);
+
+  switch (phase) {
+  case 2:
+    --num_edges_not_transmitted;
+    edata.is_tree_edge = true;
+
+    if (gamma == alpha) {
+      // Case C
+      edata.M.swap(in_same_bicomponent);
+    } else {
+      // Case D
+      edata.M.clear();
+      edata.M.push_back(parent);
+      if (beta != parent) edata.M.push_back(beta);
+      eta = infimum(path_from_root, eta, gamma);
+    }
+    if (num_edges_not_transmitted == 0)
+      echo_phase(alpha, g);
+    break;
+
+  default:
+    assert(false);
+  }
+}
+
+template<typename Graph>
+void
+hohberg_vertex_processor<Graph>::operator()(Edge e, edges_size_type name,
+                                            const Graph& g)
+{
+  using namespace hohberg_detail;
+
+#ifdef PBGL_HOHBERG_DEBUG
+  std::cerr << local(source(e, g)) << '@' << owner(source(e, g)) << " -> "
+            << local(target(e, g)) << '@' << owner(target(e, g)) << ": name("
+            << name << "), phase = " << (int)phase << std::endl;
+#endif
+
+  assert(phase == 4);
+
+  typename property_map<Graph, vertex_owner_t>::const_type
+    owner = get(vertex_owner, g);
+
+  // Send name messages along the spanning tree edges that are in the
+  // same bicomponent as the edge to our parent.
+  ProcessGroup pg = process_group(g);
+
+  Vertex alpha = target(e, g);
+
+  std::size_t idx = 0;
+  BGL_FORALL_OUTEDGES_T(alpha, e, g, Graph) {
+    per_edge_data& edata = edge_data[idx++];
+    if (edata.is_tree_edge
+        && find(edata.M.begin(), edata.M.end(), parent) != edata.M.end()
+        && target(e, g) != parent) {
+      // Notify our children in the spanning tree of this name
+      name_header<Edge> header;
+      header.edge = e;
+      header.name = name;
+      send(pg, get(owner, target(e, g)), msg_name, header);
+    } else if (target(e, g) == parent) {
+      // Map from local partition numbers to global bicomponent numbers
+      local_to_global_partitions[edata.partition] = name;
+    }
+  }
+
+  // Final stage
+  phase = 5;
+}
+
+template<typename Graph>
+typename hohberg_vertex_processor<Graph>::edges_size_type
+hohberg_vertex_processor<Graph>::
+num_starting_bicomponents(Vertex alpha, const Graph& g)
+{
+  edges_size_type not_mapped = (std::numeric_limits<edges_size_type>::max)();
+
+  edges_size_type result = 0;
+  std::size_t idx = 0;
+  BGL_FORALL_OUTEDGES_T(alpha, e, g, Graph) {
+    per_edge_data& edata = edge_data[idx++];
+    if (edata.is_tree_edge
+        && find(edata.M.begin(), edata.M.end(), parent) == edata.M.end()) {
+      // Map from local partition numbers to global bicomponent numbers
+      if (local_to_global_partitions[edata.partition] == not_mapped)
+        local_to_global_partitions[edata.partition] = result++;
+    }
+  }
+
+#ifdef PBGL_HOHBERG_DEBUG
+  std::cerr << local(alpha) << '@' << owner(alpha) << " has " << result
+            << " bicomponents originating at it." << std::endl;
+#endif
+
+  return result;
+}
+
+template<typename Graph>
+template<typename ComponentMap>
+void
+hohberg_vertex_processor<Graph>::
+fill_edge_map(Vertex alpha, const Graph& g, ComponentMap& component)
+{
+  std::size_t idx = 0;
+  BGL_FORALL_OUTEDGES_T(alpha, e, g, Graph) {
+    per_edge_data& edata = edge_data[idx++];
+    local_put(component, e, local_to_global_partitions[edata.partition]);
+
+#if defined(PBGL_HOHBERG_DEBUG) && PBGL_HOHBERG_DEBUG > 2
+    std::cerr << "component("
+              << local(source(e, g)) << '@' << owner(source(e, g)) << " -> "
+              << local(target(e, g)) << '@' << owner(target(e, g)) << ") = "
+              << local_to_global_partitions[edata.partition]
+              << " (partition = " << edata.partition << " of "
+              << local_to_global_partitions.size() << ")" << std::endl;
+#endif
+  }
+}
+
+template<typename Graph>
+void
+hohberg_vertex_processor<Graph>::
+start_naming_phase(Vertex alpha, const Graph& g, edges_size_type offset)
+{
+  using namespace hohberg_detail;
+
+  assert(phase == 4);
+
+  typename property_map<Graph, vertex_owner_t>::const_type
+    owner = get(vertex_owner, g);
+
+  // Send name messages along the spanning tree edges of the
+  // components that we get to number.
+  ProcessGroup pg = process_group(g);
+
+  bool has_more_children_to_name = false;
+
+  // Map from local partition numbers to global bicomponent numbers
+  edges_size_type not_mapped = (std::numeric_limits<edges_size_type>::max)();
+  for (std::size_t i = 0; i < local_to_global_partitions.size(); ++i) {
+    if (local_to_global_partitions[i] != not_mapped)
+      local_to_global_partitions[i] += offset;
+  }
+
+  std::size_t idx = 0;
+  BGL_FORALL_OUTEDGES_T(alpha, e, g, Graph) {
+    per_edge_data& edata = edge_data[idx++];
+    if (edata.is_tree_edge
+        && find(edata.M.begin(), edata.M.end(), parent) == edata.M.end()) {
+      // Notify our children in the spanning tree of this new name
+      name_header<Edge> header;
+      header.edge = e;
+      header.name = local_to_global_partitions[edata.partition];
+      send(pg, get(owner, target(e, g)), msg_name, header);
+    } else if (edata.is_tree_edge) {
+      has_more_children_to_name = true;
+    }
+#if defined(PBGL_HOHBERG_DEBUG) and PBGL_HOHBERG_DEBUG > 2
+    std::cerr << "M[" << local(source(e, g)) << '@' << owner(source(e, g))
+              << " -> " << local(target(e, g)) << '@' << owner(target(e, g))
+              << "] = ";
+    for (std::size_t i = 0; i < edata.M.size(); ++i) {
+      std::cerr << local(edata.M[i]) << '@' << owner(edata.M[i]) << ' ';
+    }
+    std::cerr << std::endl;
+#endif
+  }
+
+  // See if we're done.
+  if (!has_more_children_to_name)
+    // Final stage
+    phase = 5;
+}
+
+template<typename Graph>
+void
+hohberg_vertex_processor<Graph>::echo_phase(Vertex alpha, const Graph& g)
+{
+  using namespace hohberg_detail;
+
+  typename property_map<Graph, vertex_owner_t>::const_type
+    owner = get(vertex_owner, g);
+
+  /* We're entering the echo phase. */
+  phase = 3;
+
+  if (parent != graph_traits<Graph>::null_vertex()) {
+    Edge edge_to_parent;
+
+#if defined(PBGL_HOHBERG_DEBUG) and PBGL_HOHBERG_DEBUG > 1
+     std::cerr << local(alpha) << '@' << owner(alpha) << " echo: parent = "
+               << local(parent) << '@' << owner(parent) << ", eta = "
+               << local(eta) << '@' << owner(eta) << ", Gamma = ";
+#endif
+
+    std::vector<Vertex> bicomp;
+    std::size_t e_index = 0;
+    BGL_FORALL_OUTEDGES_T(alpha, e, g, Graph) {
+      if (target(e, g) == parent && parent == eta) {
+        edge_to_parent = e;
+        if (find(bicomp.begin(), bicomp.end(), alpha) == bicomp.end()) {
+#if defined(PBGL_HOHBERG_DEBUG) and PBGL_HOHBERG_DEBUG > 1
+          std::cerr << local(alpha) << '@' << owner(alpha) << ' ';
+#endif
+          bicomp.push_back(alpha);
+        }
+      } else {
+        if (target(e, g) == parent) edge_to_parent = e;
+
+        per_edge_data& edata = edge_data[e_index];
+
+        if (edata.msg.is_path()) {
+          path_iterator pos = std::find(edata.msg.path_or_bicomp.begin(),
+                                        edata.msg.path_or_bicomp.end(),
+                                        eta);
+          if (pos != edata.msg.path_or_bicomp.end()) {
+            ++pos;
+            if (pos != edata.msg.path_or_bicomp.end()
+                && find(bicomp.begin(), bicomp.end(), *pos) == bicomp.end()) {
+#if defined(PBGL_HOHBERG_DEBUG) and PBGL_HOHBERG_DEBUG > 1
+              std::cerr << local(*pos) << '@' << owner(*pos) << ' ';
+#endif
+              bicomp.push_back(*pos);
+            }
+          }
+        } else if (edata.msg.is_tree() && edata.msg.gamma == eta) {
+          for (path_iterator i = edata.msg.path_or_bicomp.begin();
+               i != edata.msg.path_or_bicomp.end(); ++i) {
+            if (find(bicomp.begin(), bicomp.end(), *i) == bicomp.end()) {
+#if defined(PBGL_HOHBERG_DEBUG) and PBGL_HOHBERG_DEBUG > 1
+              std::cerr << local(*i) << '@' << owner(*i) << ' ';
+#endif
+              bicomp.push_back(*i);
+            }
+          }
+        }
+      }
+      ++e_index;
+    }
+#ifdef PBGL_HOHBERG_DEBUG
+    std::cerr << std::endl;
+#endif
+
+    // Send tree(eta, bicomp) to parent
+    tree_header<Vertex, Edge> header;
+    header.edge = edge_to_parent;
+    header.gamma = eta;
+    header.bicomp_length = bicomp.size();
+    ProcessGroup pg = process_group(g);
+    send(pg, get(owner, parent), msg_tree_header, header);
+    send(pg, get(owner, parent), msg_tree_vertices, &bicomp[0],
+         header.bicomp_length);
+  }
+
+  // Compute the partition of edges such that iff two edges e1 and e2
+  // are in different subsets then M(e1) is disjoint from M(e2).
+
+  // Start by putting each edge in a different partition
+  std::vector<degree_size_type> parent_vec(edge_data.size());
+  degree_size_type idx = 0;
+  for (idx = 0; idx < edge_data.size(); ++idx)
+    parent_vec[idx] = idx;
+
+  // Go through each edge e, performing a union() on the edges
+  // incident on all vertices in M[e].
+  idx = 0;
+  BGL_FORALL_OUTEDGES_T(alpha, e, g, Graph) {
+    per_edge_data& edata = edge_data[idx++];
+
+    // Compute union of vertices in M
+    if (!edata.M.empty()) {
+      degree_size_type e1 = get_incident_edge_index(alpha, edata.M.front(), g);
+      while (parent_vec[e1] != e1) e1 = parent_vec[e1];
+
+      for (std::size_t i = 1; i < edata.M.size(); ++i) {
+        degree_size_type e2 = get_incident_edge_index(alpha, edata.M[i], g);
+        while (parent_vec[e2] != e2) e2 = parent_vec[e2];
+        parent_vec[e2] = e1;
+      }
+    }
+  }
+
+  edges_size_type not_mapped = (std::numeric_limits<edges_size_type>::max)();
+
+  // Determine the number of partitions
+  for (idx = 0; idx < parent_vec.size(); ++idx) {
+    if (parent_vec[idx] == idx) {
+      edge_data[idx].partition = local_to_global_partitions.size();
+      local_to_global_partitions.push_back(not_mapped);
+    }
+  }
+
+  // Assign partition numbers to each edge
+  for (idx = 0; idx < parent_vec.size(); ++idx) {
+    degree_size_type rep = parent_vec[idx];
+    while (rep != parent_vec[rep]) rep = parent_vec[rep];
+    edge_data[idx].partition = edge_data[rep].partition;
+  }
+
+  // Enter the naming phase (but don't send anything yet).
+  phase = 4;
+}
+
+template<typename Graph>
+std::size_t
+hohberg_vertex_processor<Graph>::get_edge_index(Edge e, const Graph& g)
+{
+  std::size_t result = 0;
+  BGL_FORALL_OUTEDGES_T(target(e, g), oe, g, Graph) {
+    if (source(e, g) == target(oe, g)) return result;
+    ++result;
+  }
+  assert(false);
+}
+
+template<typename Graph>
+std::size_t
+hohberg_vertex_processor<Graph>::get_incident_edge_index(Vertex u, Vertex v,
+                                                         const Graph& g)
+{
+  std::size_t result = 0;
+  BGL_FORALL_OUTEDGES_T(u, e, g, Graph) {
+    if (target(e, g) == v) return result;
+    ++result;
+  }
+  assert(false);
+}
+
+template<typename Graph, typename InputIterator, typename ComponentMap,
+         typename VertexProcessorMap>
+typename graph_traits<Graph>::edges_size_type
+hohberg_biconnected_components
+  (const Graph& g,
+   ComponentMap component,
+   InputIterator first, InputIterator last,
+   VertexProcessorMap vertex_processor)
+{
+  using namespace boost::graph::parallel;
+  using namespace hohberg_detail;
+  using boost::parallel::all_reduce;
+
+  typename property_map<Graph, vertex_owner_t>::const_type
+    owner = get(vertex_owner, g);
+
+  // The graph must be undirected
+  BOOST_STATIC_ASSERT(
+    (is_convertible<typename graph_traits<Graph>::directed_category,
+                    undirected_tag>::value));
+
+  // The graph must model Incidence Graph
+  function_requires< IncidenceGraphConcept<Graph> >();
+
+  typedef typename graph_traits<Graph>::edges_size_type edges_size_type;
+  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;
+
+  // Retrieve the process group we will use for communication
+  typedef typename process_group_type<Graph>::type process_group_type;
+  process_group_type pg = process_group(g);
+
+  // Keeps track of the edges that we know to be tree edges.
+  std::vector<edge_descriptor> tree_edges;
+
+  // The leaders send out a path message to initiate the algorithm
+  while (first != last) {
+    vertex_descriptor leader = *first;
+    if (process_id(pg) == get(owner, leader))
+      vertex_processor[leader].initialize_leader(leader, g);
+    ++first;
+  }
+  synchronize(pg);
+
+  // Will hold the number of bicomponents in the graph.
+  edges_size_type num_bicomponents = 0;
+
+  // Keep track of the path length that we should expect, based on the
+  // level in the breadth-first search tree. At present, this is only
+  // used as a sanity check. TBD: This could be used to decrease the
+  // amount of communication required per-edge (by about 4 bytes).
+  std::size_t path_length = 1;
+
+  typedef std::vector<vertex_descriptor> path_t;
+  typedef typename path_t::iterator path_iterator;
+
+  unsigned char minimum_phase = 5;
+  do {
+    while (optional<std::pair<int, int> > msg = probe(pg)) {
+      switch (msg->second) {
+      case msg_path_header:
+        {
+          // Receive the path header
+          path_header<edge_descriptor> header;
+          receive(pg, msg->first, msg->second, header);
+          assert(path_length == header.path_length);
+
+          // Receive the path itself
+          path_t path(path_length);
+          receive(pg, msg->first, msg_path_vertices, &path[0], path_length);
+
+          edge_descriptor e = header.edge;
+          vertex_processor[target(e, g)](e, path, g);
+        }
+        break;
+
+      case msg_path_vertices:
+        // Should be handled in msg_path_header case, unless we're going
+        // stateless.
+        assert(false);
+        break;
+
+      case msg_tree_header:
+        {
+          // Receive the tree header
+          tree_header<vertex_descriptor, edge_descriptor> header;
+          receive(pg, msg->first, msg->second, header);
+
+          // Receive the tree itself
+          path_t in_same_bicomponent(header.bicomp_length);
+          receive(pg, msg->first, msg_tree_vertices, &in_same_bicomponent[0],
+                  header.bicomp_length);
+
+          edge_descriptor e = header.edge;
+          vertex_processor[target(e, g)](e, header.gamma, in_same_bicomponent,
+                                         g);
+        }
+        break;
+
+      case msg_tree_vertices:
+        // Should be handled in msg_tree_header case, unless we're
+        // going stateless.
+        assert(false);
+        break;
+
+      case msg_name:
+        {
+          name_header<edge_descriptor> header;
+          receive(pg, msg->first, msg->second, header);
+          edge_descriptor e = header.edge;
+          vertex_processor[target(e, g)](e, header.name, g);
+        }
+        break;
+
+      default:
+        assert(false);
+      }
+    }
+    ++path_length;
+
+    // Compute minimum phase locally
+    minimum_phase = 5;
+    unsigned char maximum_phase = 1;
+    BGL_FORALL_VERTICES_T(v, g, Graph) {
+      minimum_phase = (std::min)(minimum_phase, vertex_processor[v].get_phase());
+      maximum_phase = (std::max)(maximum_phase, vertex_processor[v].get_phase());
+    }
+
+#ifdef PBGL_HOHBERG_DEBUG
+    if (process_id(pg) == 0)
+      std::cerr << "<---------End of stage------------->" << std::endl;
+#endif
+    // Compute minimum phase globally
+    minimum_phase = all_reduce(pg, minimum_phase, boost::mpi::minimum<char>());
+
+#ifdef PBGL_HOHBERG_DEBUG
+    if (process_id(pg) == 0)
+      std::cerr << "Minimum phase = " << (int)minimum_phase << std::endl;
+#endif
+
+    if (minimum_phase == 4
+        && all_reduce(pg, maximum_phase, boost::mpi::maximum<char>()) == 4) {
+
+#ifdef PBGL_HOHBERG_DEBUG
+      if (process_id(pg) == 0)
+        std::cerr << "<---------Naming phase------------->" << std::endl;
+#endif
+      // Compute the biconnected component number offsets for each
+      // vertex.
+      std::vector<edges_size_type> local_offsets;
+      local_offsets.reserve(num_vertices(g));
+      edges_size_type num_local_bicomponents = 0;
+      BGL_FORALL_VERTICES_T(v, g, Graph) {
+        local_offsets.push_back(num_local_bicomponents);
+        num_local_bicomponents +=
+          vertex_processor[v].num_starting_bicomponents(v, g);
+      }
+
+      synchronize(pg);
+
+      // Find our the number of bicomponent names that will originate
+      // from each process. This tells us how many bicomponents are in
+      // the entire graph and what our global offset is for computing
+      // our own biconnected component names.
+      std::vector<edges_size_type> all_bicomponents(num_processes(pg));
+      all_gather(pg, &num_local_bicomponents, &num_local_bicomponents + 1,
+                 all_bicomponents);
+      num_bicomponents = 0;
+      edges_size_type my_global_offset = 0;
+      for (std::size_t i = 0; i < all_bicomponents.size(); ++i) {
+        if (i == (std::size_t)process_id(pg)) 
+          my_global_offset = num_bicomponents;
+        num_bicomponents += all_bicomponents[i];
+      }
+
+      std::size_t index = 0;
+      BGL_FORALL_VERTICES_T(v, g, Graph) {
+        edges_size_type offset = my_global_offset + local_offsets[index++];
+        vertex_processor[v].start_naming_phase(v, g, offset);
+      }
+    }
+
+    synchronize(pg);
+  } while (minimum_phase < 5);
+
+  // Number the edges appropriately.
+  BGL_FORALL_VERTICES_T(v, g, Graph)
+    vertex_processor[v].fill_edge_map(v, g, component);
+
+  return num_bicomponents;
+}
+
+template<typename Graph, typename ComponentMap, typename InputIterator>
+typename graph_traits<Graph>::edges_size_type
+hohberg_biconnected_components
+  (const Graph& g, ComponentMap component,
+   InputIterator first, InputIterator last)
+
+{
+  std::vector<hohberg_vertex_processor<Graph> >
+    vertex_processors(num_vertices(g));
+  return hohberg_biconnected_components
+           (g, component, first, last,
+            make_iterator_property_map(vertex_processors.begin(),
+                                       get(vertex_index, g)));
+}
+
+template<typename Graph, typename ComponentMap, typename ParentMap>
+typename graph_traits<Graph>::edges_size_type
+hohberg_biconnected_components(const Graph& g, ComponentMap component,
+                               ParentMap parent)
+{
+  // We need the connected components of the graph, but we don't care
+  // about component numbers.
+  connected_components(g, dummy_property_map(), parent);
+
+  // Each root in the parent map is a leader
+  typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
+  std::vector<vertex_descriptor> leaders;
+  BGL_FORALL_VERTICES_T(v, g, Graph)
+    if (get(parent, v) == v) leaders.push_back(v);
+
+  return hohberg_biconnected_components(g, component,
+                                        leaders.begin(), leaders.end());
+}
+
+template<typename Graph, typename ComponentMap>
+typename graph_traits<Graph>::edges_size_type
+hohberg_biconnected_components(const Graph& g, ComponentMap component)
+{
+  typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
+  std::vector<vertex_descriptor> parents(num_vertices(g));
+  return hohberg_biconnected_components
+           (g, component, make_iterator_property_map(parents.begin(),
+                                                     get(vertex_index, g)));
+}
+
+} } } // end namespace boost::graph::distributed
+
+#endif // BOOST_GRAPH_DISTRIBUTED_HOHBERG_BICONNECTED_COMPONENTS_HPP
Added: trunk/boost/graph/distributed/local_subgraph.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/distributed/local_subgraph.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -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
Added: trunk/boost/graph/distributed/mpi_process_group.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/distributed/mpi_process_group.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -0,0 +1,809 @@
+// Copyright (C) 2004-2008 The Trustees of Indiana University.
+// Copyright (C) 2007   Douglas Gregor
+// Copyright (C) 2007  Matthias Troyer  <troyer_at_[hidden]>
+
+// 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.tpp>
+
+#endif // BOOST_PARALLEL_MPI_MPI_PROCESS_GROUP_HPP
Added: trunk/boost/graph/distributed/named_graph.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/distributed/named_graph.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -0,0 +1,1239 @@
+// Copyright (C) 2007 Douglas Gregor 
+// Copyright (C) 2007 Hartmut Kaiser
+
+// 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)
+
+// TODO:
+//   - Cache (some) remote vertex names?
+#ifndef BOOST_GRAPH_DISTRIBUTED_NAMED_GRAPH_HPP
+#define BOOST_GRAPH_DISTRIBUTED_NAMED_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/named_graph.hpp>
+#include <boost/functional/hash.hpp>
+#include <boost/variant.hpp>
+#include <boost/graph/parallel/simple_trigger.hpp>
+#include <boost/graph/parallel/process_group.hpp>
+#include <boost/graph/parallel/detail/property_holders.hpp>
+
+namespace boost { namespace graph { namespace distributed {
+
+using boost::parallel::trigger_receive_context;
+using boost::detail::parallel::pair_with_property;
+
+/*******************************************************************
+ * Hashed distribution of named entities                           *
+ *******************************************************************/
+
+template<typename T>
+struct hashed_distribution
+{
+  template<typename ProcessGroup>
+  hashed_distribution(const ProcessGroup& pg, std::size_t /*num_vertices*/ = 0)
+    : n(num_processes(pg)) { }
+
+  int operator()(const T& value) const 
+  {
+    return hasher(value) % n;
+  }
+
+  std::size_t n;
+  hash<T> hasher;
+};
+
+/// Specialization for named graphs
+template <typename InDistribution, typename VertexProperty, typename VertexSize,
+          typename ProcessGroup,
+          typename ExtractName 
+            = typename internal_vertex_name<VertexProperty>::type>
+struct select_distribution
+{
+private:
+  /// The type used to name vertices in the graph
+  typedef typename remove_cv<
+            typename remove_reference<
+              typename ExtractName::result_type>::type>::type
+    vertex_name_type;
+
+public:
+  /**
+   *  The @c type field provides a distribution object that maps
+   *  vertex names to processors. The distribution object will be
+   *  constructed with the process group over which communication will
+   *  occur. The distribution object shall also be a function
+   *  object mapping from the type of the name to a processor number
+   *  in @c [0, @c p) (for @c p processors). By default, the mapping
+   *  function uses the @c boost::hash value of the name, modulo @c p.
+   */
+  typedef typename mpl::if_<is_same<InDistribution, defaultS>,
+                            hashed_distribution<vertex_name_type>,
+                            InDistribution>::type 
+    type;
+
+  /// for named graphs the default type is the same as the stored distribution 
+  /// type
+  typedef type default_type;
+};
+
+/// Specialization for non-named graphs
+template <typename InDistribution, typename VertexProperty, typename VertexSize,
+          typename ProcessGroup>
+struct select_distribution<InDistribution, VertexProperty, VertexSize, 
+                           ProcessGroup, void>
+{
+  /// the distribution type stored in the graph for non-named graphs should be
+  /// the variant_distribution type
+  typedef typename mpl::if_<is_same<InDistribution, defaultS>,
+                            boost::parallel::variant_distribution<ProcessGroup, 
+                                                                  VertexSize>,
+                            InDistribution>::type type;
+
+  /// default_type is used as the distribution functor for the
+  /// adjacency_list, it should be parallel::block by default
+  typedef typename mpl::if_<is_same<InDistribution, defaultS>,
+                            boost::parallel::block, type>::type
+    default_type;
+};
+
+
+/*******************************************************************
+ * Named graph mixin                                               *
+ *******************************************************************/
+
+/**
+ * named_graph is a mixin that provides names for the vertices of a
+ * graph, including a mapping from names to vertices. Graph types that
+ * may or may not be have vertex names (depending on the properties
+ * supplied by the user) should use maybe_named_graph.
+ *
+ * Template parameters:
+ *
+ *   Graph: the graph type that derives from named_graph
+ *
+ *   Vertex: the type of a vertex descriptor in Graph. Note: we cannot
+ *   use graph_traits here, because the Graph is not yet defined.
+ *
+ *   VertexProperty: the type of the property stored along with the
+ *   vertex.
+ *
+ *   ProcessGroup: the process group over which the distributed name
+ *   graph mixin will communicate.
+ */
+template<typename Graph, typename Vertex, typename Edge, typename Config>
+class named_graph
+{
+public:
+  /// Messages passed within the distributed named graph
+  enum message_kind {
+    /**
+     * Requests the addition of a vertex on a remote processor. The
+     * message data is a @c vertex_name_type.
+     */
+    msg_add_vertex_name,
+
+    /**
+     * Requests the addition of a vertex on a remote processor. The
+     * message data is a @c vertex_name_type. The remote processor
+     * will send back a @c msg_add_vertex_name_reply message
+     * containing the vertex descriptor.
+     */
+    msg_add_vertex_name_with_reply,
+
+    /**
+     * Requests the vertex descriptor corresponding to the given
+     * vertex name. The remote process will reply with a 
+     * @c msg_find_vertex_reply message containing the answer.
+     */
+    msg_find_vertex,
+
+    /**
+     * Requests the addition of an edge on a remote processor. The
+     * data stored in these messages is a @c pair<source, target>@,
+     * where @c source and @c target may be either names (of type @c
+     * vertex_name_type) or vertex descriptors, depending on what
+     * information we have locally.  
+     */
+    msg_add_edge_name_name,
+    msg_add_edge_vertex_name,
+    msg_add_edge_name_vertex,
+
+    /**
+     * These messages are identical to msg_add_edge_*_*, except that
+     * the process actually adding the edge will send back a @c
+     * pair<edge_descriptor,bool>
+     */
+    msg_add_edge_name_name_with_reply,
+    msg_add_edge_vertex_name_with_reply,
+    msg_add_edge_name_vertex_with_reply,
+
+    /**
+     * Requests the addition of an edge with a property on a remote
+     * processor. The data stored in these messages is a @c
+     * pair<vertex_property_type, pair<source, target>>@, where @c
+     * source and @c target may be either names (of type @c
+     * vertex_name_type) or vertex descriptors, depending on what
+     * information we have locally.
+     */
+    msg_add_edge_name_name_with_property,
+    msg_add_edge_vertex_name_with_property,
+    msg_add_edge_name_vertex_with_property,
+
+    /**
+     * These messages are identical to msg_add_edge_*_*_with_property,
+     * except that the process actually adding the edge will send back
+     * a @c pair<edge_descriptor,bool>.
+     */
+    msg_add_edge_name_name_with_reply_and_property,
+    msg_add_edge_vertex_name_with_reply_and_property,
+    msg_add_edge_name_vertex_with_reply_and_property
+  };
+
+  /// The vertex descriptor type
+  typedef Vertex vertex_descriptor;
+  
+  /// The edge descriptor type
+  typedef Edge edge_descriptor;
+
+  /// The vertex property type
+  typedef typename Config::vertex_property_type vertex_property_type;
+  
+  /// The vertex property type
+  typedef typename Config::edge_property_type edge_property_type;
+  
+  /// The type used to extract names from the property structure
+  typedef typename internal_vertex_name<vertex_property_type>::type
+    extract_name_type;
+
+  /// The type used to name vertices in the graph
+  typedef typename remove_cv<
+            typename remove_reference<
+              typename extract_name_type::result_type>::type>::type
+    vertex_name_type;
+
+  /// The type used to distribute named vertices in the graph
+  typedef typename Config::distribution_type distribution_type;
+  typedef typename Config::base_distribution_type base_distribution_type;
+
+  /// The type used for communication in the distributed structure
+  typedef typename Config::process_group_type process_group_type;
+
+  /// Type used to identify processes
+  typedef typename process_group_type::process_id_type process_id_type;
+
+  /// a reference to this class, which is used for disambiguation of the 
+  //  add_vertex function
+  typedef named_graph named_graph_type;
+  
+  /// Structure returned when adding a vertex by vertex name
+  struct lazy_add_vertex;
+  friend struct lazy_add_vertex;
+
+  /// Structure returned when adding an edge by vertex name
+  struct lazy_add_edge;
+  friend struct lazy_add_edge;
+
+  /// Structure returned when adding an edge by vertex name with a property
+  struct lazy_add_edge_with_property;
+  friend struct lazy_add_edge_with_property;
+
+  explicit named_graph(const process_group_type& pg);
+
+  named_graph(const process_group_type& pg, const base_distribution_type& distribution);
+
+  /// Set up triggers, but only for the BSP process group
+  void setup_triggers();
+
+  /// Retrieve the derived instance
+  Graph&       derived()       { return static_cast<Graph&>(*this); }
+  const Graph& derived() const { return static_cast<const Graph&>(*this); }
+
+  /// Retrieve the process group
+  process_group_type&       process_group()       { return process_group_; }
+  const process_group_type& process_group() const { return process_group_; }
+
+  // Retrieve the named distribution
+  distribution_type&       named_distribution()       { return distribution_; }
+  const distribution_type& named_distribution() const { return distribution_; }
+
+  /// Notify the named_graph that we have added the given vertex. This
+  /// is a no-op.
+  void added_vertex(Vertex) { }
+
+  /// Notify the named_graph that we are removing the given
+  /// vertex. This is a no-op.
+  void removing_vertex(Vertex) { }
+
+  /// Notify the named_graph that we are clearing the graph
+  void clearing_graph() { }
+
+  /// Retrieve the owner of a given vertex based on the properties
+  /// associated with that vertex. This operation just returns the
+  /// number of the local processor, adding all vertices locally.
+  process_id_type owner_by_property(const vertex_property_type&);
+
+protected:
+  void 
+  handle_add_vertex_name(int source, int tag, const vertex_name_type& msg,
+                         trigger_receive_context);
+
+  vertex_descriptor 
+  handle_add_vertex_name_with_reply(int source, int tag, 
+                                    const vertex_name_type& msg,
+                                    trigger_receive_context);
+
+  boost::parallel::detail::untracked_pair<vertex_descriptor, bool>
+  handle_find_vertex(int source, int tag, const vertex_name_type& msg,
+                     trigger_receive_context);
+
+  template<typename U, typename V>
+  void handle_add_edge(int source, int tag, const boost::parallel::detail::untracked_pair<U, V>& msg,
+                       trigger_receive_context);
+
+  template<typename U, typename V>
+  boost::parallel::detail::untracked_pair<edge_descriptor, bool> 
+  handle_add_edge_with_reply(int source, int tag, const boost::parallel::detail::untracked_pair<U, V>& msg,
+                             trigger_receive_context);
+
+  template<typename U, typename V>
+  void 
+  handle_add_edge_with_property
+    (int source, int tag, 
+     const pair_with_property<U, V, edge_property_type>& msg,
+     trigger_receive_context);
+
+  template<typename U, typename V>
+  boost::parallel::detail::untracked_pair<edge_descriptor, bool> 
+  handle_add_edge_with_reply_and_property
+    (int source, int tag, 
+     const pair_with_property<U, V, edge_property_type>& msg,
+     trigger_receive_context);
+
+  /// The process group for this distributed data structure
+  process_group_type process_group_;
+
+  /// The distribution we will use to map names to processors
+  distribution_type distribution_;
+};
+
+/// Helper macro containing the template parameters of named_graph
+#define BGL_NAMED_GRAPH_PARAMS \
+  typename Graph, typename Vertex, typename Edge, typename Config
+/// Helper macro containing the named_graph<...> instantiation
+#define BGL_NAMED_GRAPH \
+  named_graph<Graph, Vertex, Edge, Config>
+
+/**
+ * Data structure returned from add_vertex that will "lazily" add the
+ * vertex, either when it is converted to a @c vertex_descriptor or
+ * when the most recent copy has been destroyed.
+ */
+template<BGL_NAMED_GRAPH_PARAMS>
+struct BGL_NAMED_GRAPH::lazy_add_vertex
+{
+  /// Construct a new lazyily-added vertex
+  lazy_add_vertex(named_graph& self, const vertex_name_type& name)
+    : self(self), name(name), committed(false) { }
+
+  /// Transfer responsibility for adding the vertex from the source of
+  /// the copy to the newly-constructed opbject.
+  lazy_add_vertex(const lazy_add_vertex& other)
+    : self(self), name(other.name), committed(other.committed)
+  {
+    other.committed = true;
+  }
+
+  /// If the vertex has not been added yet, add it
+  ~lazy_add_vertex();
+
+  /// Add the vertex and return its descriptor. This conversion can
+  /// only occur once, and only when this object is responsible for
+  /// creating the vertex.
+  operator vertex_descriptor() const { return commit(); }
+
+  /// Add the vertex and return its descriptor. This can only be
+  /// called once, and only when this object is responsible for
+  /// creating the vertex.
+  vertex_descriptor commit() const;
+
+protected:
+  named_graph&     self;
+  vertex_name_type name;
+  mutable bool     committed;
+};
+
+template<BGL_NAMED_GRAPH_PARAMS>
+BGL_NAMED_GRAPH::lazy_add_vertex::~lazy_add_vertex()
+{
+  typedef typename BGL_NAMED_GRAPH::process_id_type process_id_type;
+
+  /// If this vertex has already been created or will be created by
+  /// someone else, or if someone threw an exception, we will not
+  /// create the vertex now.
+  if (committed || std::uncaught_exception())
+    return;
+
+  committed = true;
+
+  process_id_type owner = self.named_distribution()(name);
+  if (owner == process_id(self.process_group()))
+    /// Add the vertex locally
+    add_vertex(self.derived().base().vertex_constructor(name), self.derived()); 
+  else
+    /// Ask the owner of the vertex to add a vertex with this name
+    send(self.process_group(), owner, msg_add_vertex_name, name);
+}
+
+template<BGL_NAMED_GRAPH_PARAMS>
+typename BGL_NAMED_GRAPH::vertex_descriptor
+BGL_NAMED_GRAPH::lazy_add_vertex::commit() const
+{
+  typedef typename BGL_NAMED_GRAPH::process_id_type process_id_type;
+  assert (!committed);
+  committed = true;
+
+  process_id_type owner = self.named_distribution()(name);
+  if (owner == process_id(self.process_group()))
+    /// Add the vertex locally
+    return add_vertex(self.derived().base().vertex_constructor(name),
+                      self.derived()); 
+  else {
+    /// Ask the owner of the vertex to add a vertex with this name
+    vertex_descriptor result;
+    send_oob_with_reply(self.process_group(), owner, 
+                        msg_add_vertex_name_with_reply, name, result);
+    return result;
+  }
+}
+
+/**
+ * Data structure returned from add_edge that will "lazily" add the
+ * edge, either when it is converted to a @c
+ * pair<edge_descriptor,bool> or when the most recent copy has been
+ * destroyed.
+ */
+template<BGL_NAMED_GRAPH_PARAMS>
+struct BGL_NAMED_GRAPH::lazy_add_edge 
+{
+  /// The graph's edge descriptor
+  typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
+
+  /// Add an edge for the edge (u, v) based on vertex names
+  lazy_add_edge(BGL_NAMED_GRAPH& self, 
+                const vertex_name_type& u_name,
+                const vertex_name_type& v_name) 
+    : self(self), u(u_name), v(v_name), committed(false) { }
+
+  /// Add an edge for the edge (u, v) based on a vertex descriptor and name
+  lazy_add_edge(BGL_NAMED_GRAPH& self,
+                vertex_descriptor u,
+                const vertex_name_type& v_name)
+    : self(self), u(u), v(v_name), committed(false) { }
+
+  /// Add an edge for the edge (u, v) based on a vertex name and descriptor
+  lazy_add_edge(BGL_NAMED_GRAPH& self,
+                const vertex_name_type& u_name,
+                vertex_descriptor v)
+    : self(self), u(u_name), v(v), committed(false) { }
+
+  /// Add an edge for the edge (u, v) based on vertex descriptors
+  lazy_add_edge(BGL_NAMED_GRAPH& self,
+                vertex_descriptor u,
+                vertex_descriptor v)
+    : self(self), u(u), v(v), committed(false) { }
+
+  /// Copy a lazy_add_edge structure, which transfers responsibility
+  /// for adding the edge to the newly-constructed object.
+  lazy_add_edge(const lazy_add_edge& other)
+    : self(other.self), u(other.u), v(other.v), committed(other.committed)
+  {
+    other.committed = true;
+  }
+
+  /// If the edge has not yet been added, add the edge but don't wait
+  /// for a reply.
+  ~lazy_add_edge();
+
+  /// Returns commit().
+  operator std::pair<edge_descriptor, bool>() const { return commit(); }
+
+  // Add the edge. This operation will block if a remote edge is
+  // being added.
+  std::pair<edge_descriptor, bool> commit() const;
+
+protected:
+  BGL_NAMED_GRAPH& self;
+  mutable variant<vertex_descriptor, vertex_name_type> u;
+  mutable variant<vertex_descriptor, vertex_name_type> v;
+  mutable bool committed;
+
+private:
+  // No copy-assignment semantics
+  void operator=(lazy_add_edge&);
+};
+
+template<BGL_NAMED_GRAPH_PARAMS>
+BGL_NAMED_GRAPH::lazy_add_edge::~lazy_add_edge()
+{
+  typedef typename BGL_NAMED_GRAPH::process_id_type process_id_type;
+
+  using boost::parallel::detail::make_untracked_pair;
+
+  /// If this edge has already been created or will be created by
+  /// someone else, or if someone threw an exception, we will not
+  /// create the edge now.
+  if (committed || std::uncaught_exception())
+    return;
+
+  committed = true;
+
+  if (vertex_name_type* v_name = boost::get<vertex_name_type>(&v)) {
+    // We haven't resolved the target vertex to a descriptor yet, so
+    // it must not be local. Send a message to the owner of the target
+    // of the edge. If the owner of the target does not happen to own
+    // the source, it will resolve the target to a vertex descriptor
+    // and pass the message along to the owner of the source. 
+    if (vertex_name_type* u_name = boost::get<vertex_name_type>(&u))
+      send(self.process_group(), self.distribution_(*v_name),
+           BGL_NAMED_GRAPH::msg_add_edge_name_name,
+           make_untracked_pair(*u_name, *v_name));
+    else
+      send(self.process_group(), self.distribution_(*v_name),
+           BGL_NAMED_GRAPH::msg_add_edge_vertex_name,
+           make_untracked_pair(boost::get<vertex_descriptor>(u), *v_name));
+  } else {
+    if (vertex_name_type* u_name = boost::get<vertex_name_type>(&u))
+      // We haven't resolved the source vertex to a descriptor yet, so
+      // it must not be local. Send a message to the owner of the
+      // source vertex requesting the edge addition.
+      send(self.process_group(), self.distribution_(*u_name),
+           BGL_NAMED_GRAPH::msg_add_edge_name_vertex,
+           make_untracked_pair(*u_name, boost::get<vertex_descriptor>(v)));
+    else
+      // We have descriptors for both of the vertices, either of which
+      // may be remote or local. Tell the owner of the source vertex
+      // to add the edge (it may be us!).
+      add_edge(boost::get<vertex_descriptor>(u), 
+               boost::get<vertex_descriptor>(v), 
+               self.derived());
+  }
+}
+
+template<BGL_NAMED_GRAPH_PARAMS>
+std::pair<typename graph_traits<Graph>::edge_descriptor, bool>
+BGL_NAMED_GRAPH::lazy_add_edge::commit() const
+{
+  typedef typename BGL_NAMED_GRAPH::process_id_type process_id_type;
+  using boost::parallel::detail::make_untracked_pair;
+
+  assert(!committed);
+  committed = true;
+
+  /// The result we will return, if we are sending a message to
+  /// request that someone else add the edge.
+  boost::parallel::detail::untracked_pair<edge_descriptor, bool> result;
+
+  /// The owner of the vertex "u"
+  process_id_type u_owner;
+
+  process_id_type rank = process_id(self.process_group());
+  if (const vertex_name_type* u_name = boost::get<vertex_name_type>(&u)) {
+    /// We haven't resolved the source vertex to a descriptor yet, so
+    /// it must not be local. 
+    u_owner = self.named_distribution()(*u_name);
+
+    /// Send a message to the remote vertex requesting that it add the
+    /// edge. The message differs depending on whether we have a
+    /// vertex name or a vertex descriptor for the target.
+    if (const vertex_name_type* v_name = boost::get<vertex_name_type>(&v))
+      send_oob_with_reply(self.process_group(), u_owner,
+                          BGL_NAMED_GRAPH::msg_add_edge_name_name_with_reply,
+                          make_untracked_pair(*u_name, *v_name), result);
+    else
+      send_oob_with_reply(self.process_group(), u_owner,
+                          BGL_NAMED_GRAPH::msg_add_edge_name_vertex_with_reply,
+                          make_untracked_pair(*u_name, 
+                                         boost::get<vertex_descriptor>(v)),
+                          result);
+  } else {
+    /// We have resolved the source vertex to a descriptor, which may
+    /// either be local or remote.
+    u_owner 
+      = get(vertex_owner, self.derived(),
+            boost::get<vertex_descriptor>(u));
+    if (u_owner == rank) {
+      /// The source is local. If we need to, resolve the target vertex.
+      if (const vertex_name_type* v_name = boost::get<vertex_name_type>(&v))
+        v = add_vertex(*v_name, self.derived());
+
+      /// Add the edge using vertex descriptors
+      return add_edge(boost::get<vertex_descriptor>(u), 
+                      boost::get<vertex_descriptor>(v), 
+                      self.derived());
+    } else {
+      /// The source is remote. Just send a message to its owner
+      /// requesting that the owner add the new edge, either directly
+      /// or via the derived class's add_edge function.
+      if (const vertex_name_type* v_name = boost::get<vertex_name_type>(&v))
+        send_oob_with_reply
+          (self.process_group(), u_owner,
+           BGL_NAMED_GRAPH::msg_add_edge_vertex_name_with_reply,
+           make_untracked_pair(boost::get<vertex_descriptor>(u), *v_name),
+           result);
+      else
+        return add_edge(boost::get<vertex_descriptor>(u), 
+                        boost::get<vertex_descriptor>(v), 
+                        self.derived());
+    }
+  }
+
+  // If we get here, the edge has been added remotely and "result"
+  // contains the result of that edge addition.
+  return result;
+}
+
+/**
+ * Data structure returned from add_edge that will "lazily" add the
+ * edge with a property, either when it is converted to a @c
+ * pair<edge_descriptor,bool> or when the most recent copy has been
+ * destroyed.
+ */
+template<BGL_NAMED_GRAPH_PARAMS>
+struct BGL_NAMED_GRAPH::lazy_add_edge_with_property 
+{
+  /// The graph's edge descriptor
+  typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
+
+  /// The Edge property type for our graph
+  typedef typename Config::edge_property_type edge_property_type;
+  
+  /// Add an edge for the edge (u, v) based on vertex names
+  lazy_add_edge_with_property(BGL_NAMED_GRAPH& self, 
+                              const vertex_name_type& u_name,
+                              const vertex_name_type& v_name,
+                              const edge_property_type& property) 
+    : self(self), u(u_name), v(v_name), property(property), committed(false)
+  { 
+  }
+
+  /// Add an edge for the edge (u, v) based on a vertex descriptor and name
+  lazy_add_edge_with_property(BGL_NAMED_GRAPH& self,
+                vertex_descriptor u,
+                const vertex_name_type& v_name,
+                                  const edge_property_type& property)
+    : self(self), u(u), v(v_name), property(property), committed(false) { }
+
+  /// Add an edge for the edge (u, v) based on a vertex name and descriptor
+  lazy_add_edge_with_property(BGL_NAMED_GRAPH& self,
+                              const vertex_name_type& u_name,
+                              vertex_descriptor v,
+                              const edge_property_type& property)
+    : self(self), u(u_name), v(v), property(property), committed(false) { }
+
+  /// Add an edge for the edge (u, v) based on vertex descriptors
+  lazy_add_edge_with_property(BGL_NAMED_GRAPH& self,
+                              vertex_descriptor u,
+                              vertex_descriptor v,
+                              const edge_property_type& property)
+    : self(self), u(u), v(v), property(property), committed(false) { }
+
+  /// Copy a lazy_add_edge_with_property structure, which transfers
+  /// responsibility for adding the edge to the newly-constructed
+  /// object.
+  lazy_add_edge_with_property(const lazy_add_edge_with_property& other)
+    : self(other.self), u(other.u), v(other.v), property(other.property), 
+      committed(other.committed)
+  {
+    other.committed = true;
+  }
+
+  /// If the edge has not yet been added, add the edge but don't wait
+  /// for a reply.
+  ~lazy_add_edge_with_property();
+
+  /// Returns commit().
+  operator std::pair<edge_descriptor, bool>() const { return commit(); }
+
+  // Add the edge. This operation will block if a remote edge is
+  // being added.
+  std::pair<edge_descriptor, bool> commit() const;
+
+protected:
+  BGL_NAMED_GRAPH& self;
+  mutable variant<vertex_descriptor, vertex_name_type> u;
+  mutable variant<vertex_descriptor, vertex_name_type> v;
+  edge_property_type property;
+  mutable bool committed;
+
+private:
+  // No copy-assignment semantics
+  void operator=(lazy_add_edge_with_property&);
+};
+
+template<BGL_NAMED_GRAPH_PARAMS>
+BGL_NAMED_GRAPH::lazy_add_edge_with_property::~lazy_add_edge_with_property()
+{
+  typedef typename BGL_NAMED_GRAPH::process_id_type process_id_type;
+  using boost::detail::parallel::make_pair_with_property;
+
+  /// If this edge has already been created or will be created by
+  /// someone else, or if someone threw an exception, we will not
+  /// create the edge now.
+  if (committed || std::uncaught_exception())
+    return;
+
+  committed = true;
+
+  if (vertex_name_type* v_name = boost::get<vertex_name_type>(&v)) {
+    // We haven't resolved the target vertex to a descriptor yet, so
+    // it must not be local. Send a message to the owner of the target
+    // of the edge. If the owner of the target does not happen to own
+    // the source, it will resolve the target to a vertex descriptor
+    // and pass the message along to the owner of the source. 
+    if (vertex_name_type* u_name = boost::get<vertex_name_type>(&u))
+      send(self.process_group(), self.distribution_(*v_name),
+           BGL_NAMED_GRAPH::msg_add_edge_name_name_with_property,
+           make_pair_with_property(*u_name, *v_name, property));
+    else
+      send(self.process_group(), self.distribution_(*v_name),
+           BGL_NAMED_GRAPH::msg_add_edge_vertex_name_with_property,
+           make_pair_with_property(boost::get<vertex_descriptor>(u), *v_name, 
+                                   property));
+  } else {
+    if (vertex_name_type* u_name = boost::get<vertex_name_type>(&u))
+      // We haven't resolved the source vertex to a descriptor yet, so
+      // it must not be local. Send a message to the owner of the
+      // source vertex requesting the edge addition.
+      send(self.process_group(), self.distribution_(*u_name),
+           BGL_NAMED_GRAPH::msg_add_edge_name_vertex_with_property,
+           make_pair_with_property(*u_name, boost::get<vertex_descriptor>(v), 
+                                   property));
+    else
+      // We have descriptors for both of the vertices, either of which
+      // may be remote or local. Tell the owner of the source vertex
+      // to add the edge (it may be us!).
+      add_edge(boost::get<vertex_descriptor>(u), 
+               boost::get<vertex_descriptor>(v), 
+               property,
+               self.derived());
+  }
+}
+
+template<BGL_NAMED_GRAPH_PARAMS>
+std::pair<typename graph_traits<Graph>::edge_descriptor, bool>
+BGL_NAMED_GRAPH::lazy_add_edge_with_property::commit() const
+{
+  using boost::detail::parallel::make_pair_with_property;
+  typedef typename BGL_NAMED_GRAPH::process_id_type process_id_type;
+  assert(!committed);
+  committed = true;
+
+  /// The result we will return, if we are sending a message to
+  /// request that someone else add the edge.
+  boost::parallel::detail::untracked_pair<edge_descriptor, bool> result;
+
+  /// The owner of the vertex "u"
+  process_id_type u_owner;
+
+  process_id_type rank = process_id(self.process_group());
+  if (const vertex_name_type* u_name = boost::get<vertex_name_type>(&u)) {
+    /// We haven't resolved the source vertex to a descriptor yet, so
+    /// it must not be local. 
+    u_owner = self.named_distribution()(*u_name);
+
+    /// Send a message to the remote vertex requesting that it add the
+    /// edge. The message differs depending on whether we have a
+    /// vertex name or a vertex descriptor for the target.
+    if (const vertex_name_type* v_name = boost::get<vertex_name_type>(&v))
+      send_oob_with_reply
+        (self.process_group(), u_owner,
+         BGL_NAMED_GRAPH::msg_add_edge_name_name_with_reply_and_property,
+         make_pair_with_property(*u_name, *v_name, property),
+         result);
+    else
+      send_oob_with_reply
+        (self.process_group(), u_owner,
+         BGL_NAMED_GRAPH::msg_add_edge_name_vertex_with_reply_and_property,
+         make_pair_with_property(*u_name, 
+                                 boost::get<vertex_descriptor>(v),
+                                 property),
+         result);
+  } else {
+    /// We have resolved the source vertex to a descriptor, which may
+    /// either be local or remote.
+    u_owner 
+      = get(vertex_owner, self.derived(),
+            boost::get<vertex_descriptor>(u));
+    if (u_owner == rank) {
+      /// The source is local. If we need to, resolve the target vertex.
+      if (const vertex_name_type* v_name = boost::get<vertex_name_type>(&v))
+        v = add_vertex(*v_name, self.derived());
+
+      /// Add the edge using vertex descriptors
+      return add_edge(boost::get<vertex_descriptor>(u), 
+                      boost::get<vertex_descriptor>(v), 
+                      property,
+                      self.derived());
+    } else {
+      /// The source is remote. Just send a message to its owner
+      /// requesting that the owner add the new edge, either directly
+      /// or via the derived class's add_edge function.
+      if (const vertex_name_type* v_name = boost::get<vertex_name_type>(&v))
+        send_oob_with_reply
+          (self.process_group(), u_owner,
+           BGL_NAMED_GRAPH::msg_add_edge_vertex_name_with_reply_and_property,
+           make_pair_with_property(boost::get<vertex_descriptor>(u), *v_name,
+                                   property),
+           result);
+      else
+        return add_edge(boost::get<vertex_descriptor>(u), 
+                        boost::get<vertex_descriptor>(v), 
+                        property,
+                        self.derived());
+    }
+  }
+
+  // If we get here, the edge has been added remotely and "result"
+  // contains the result of that edge addition.
+  return result;
+}
+
+/// Construct the named_graph with a particular process group
+template<BGL_NAMED_GRAPH_PARAMS>
+BGL_NAMED_GRAPH::named_graph(const process_group_type& pg)
+  : process_group_(pg, parallel::attach_distributed_object()),
+    distribution_(pg)
+{
+  setup_triggers();
+}
+
+/// Construct the named_graph mixin with a particular process group
+/// and distribution function
+template<BGL_NAMED_GRAPH_PARAMS>
+BGL_NAMED_GRAPH::named_graph(const process_group_type& pg,
+                             const base_distribution_type& distribution)
+  : process_group_(pg, parallel::attach_distributed_object()),
+    distribution_(pg, distribution)
+{
+  setup_triggers();
+}
+
+template<BGL_NAMED_GRAPH_PARAMS>
+void
+BGL_NAMED_GRAPH::setup_triggers()
+{
+  using boost::graph::parallel::simple_trigger;
+
+  simple_trigger(process_group_, msg_add_vertex_name, this,
+                 &named_graph::handle_add_vertex_name);
+  simple_trigger(process_group_, msg_add_vertex_name_with_reply, this,
+                 &named_graph::handle_add_vertex_name_with_reply);
+  simple_trigger(process_group_, msg_find_vertex, this, 
+                 &named_graph::handle_find_vertex);
+  simple_trigger(process_group_, msg_add_edge_name_name, this, 
+                 &named_graph::template handle_add_edge<vertex_name_type, 
+                                                        vertex_name_type>);
+  simple_trigger(process_group_, msg_add_edge_name_name_with_reply, this,
+                 &named_graph::template handle_add_edge_with_reply
+                   <vertex_name_type, vertex_name_type>);
+  simple_trigger(process_group_, msg_add_edge_name_vertex, this,
+                 &named_graph::template handle_add_edge<vertex_name_type, 
+                                                        vertex_descriptor>);
+  simple_trigger(process_group_, msg_add_edge_name_vertex_with_reply, this,
+                 &named_graph::template handle_add_edge_with_reply
+                   <vertex_name_type, vertex_descriptor>);
+  simple_trigger(process_group_, msg_add_edge_vertex_name, this,
+                 &named_graph::template handle_add_edge<vertex_descriptor, 
+                                                        vertex_name_type>);
+  simple_trigger(process_group_, msg_add_edge_vertex_name_with_reply, this,
+                 &named_graph::template handle_add_edge_with_reply
+                   <vertex_descriptor, vertex_name_type>);
+  simple_trigger(process_group_, msg_add_edge_name_name_with_property, this, 
+                 &named_graph::
+                   template handle_add_edge_with_property<vertex_name_type, 
+                                                          vertex_name_type>);
+  simple_trigger(process_group_, 
+                 msg_add_edge_name_name_with_reply_and_property, this,
+                 &named_graph::template handle_add_edge_with_reply_and_property
+                   <vertex_name_type, vertex_name_type>);
+  simple_trigger(process_group_, msg_add_edge_name_vertex_with_property, this,
+                 &named_graph::
+                   template handle_add_edge_with_property<vertex_name_type, 
+                                                          vertex_descriptor>);
+  simple_trigger(process_group_, 
+                 msg_add_edge_name_vertex_with_reply_and_property, this,
+                 &named_graph::template handle_add_edge_with_reply_and_property
+                   <vertex_name_type, vertex_descriptor>);
+  simple_trigger(process_group_, msg_add_edge_vertex_name_with_property, this,
+                 &named_graph::
+                   template handle_add_edge_with_property<vertex_descriptor, 
+                                                          vertex_name_type>);
+  simple_trigger(process_group_, 
+                 msg_add_edge_vertex_name_with_reply_and_property, this,
+                 &named_graph::template handle_add_edge_with_reply_and_property
+                   <vertex_descriptor, vertex_name_type>);
+}
+
+/// Retrieve the vertex associated with the given name
+template<BGL_NAMED_GRAPH_PARAMS>
+optional<Vertex> 
+find_vertex(typename BGL_NAMED_GRAPH::vertex_name_type const& name,
+            const BGL_NAMED_GRAPH& g)
+{
+  typedef typename Graph::local_vertex_descriptor local_vertex_descriptor;
+  typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
+
+  // Determine the owner of this name
+  typename BGL_NAMED_GRAPH::process_id_type owner 
+    = g.named_distribution()(name);
+
+  if (owner == process_id(g.process_group())) {
+    // The vertex is local, so search for a mapping here
+    optional<local_vertex_descriptor> result 
+      = find_vertex(name, g.derived().base());
+    if (result)
+      return Vertex(owner, *result);
+    else
+      return optional<Vertex>();
+  }
+  else {
+    // Ask the ownering process for the name of this vertex
+    boost::parallel::detail::untracked_pair<vertex_descriptor, bool> result;
+    send_oob_with_reply(g.process_group(), owner, 
+                        BGL_NAMED_GRAPH::msg_find_vertex, name, result);
+    if (result.second)
+      return result.first;
+    else
+      return optional<Vertex>();
+  }
+}
+
+/// meta-function helping in figuring out if the given VertextProerty belongs to 
+/// a named graph
+template<typename VertexProperty>
+struct not_is_named_graph
+  : is_same<typename internal_vertex_name<VertexProperty>::type, void>
+{};
+
+/// Retrieve the vertex associated with the given name
+template<typename Graph>
+typename Graph::named_graph_type::lazy_add_vertex
+add_vertex(typename Graph::vertex_name_type const& name,
+           Graph& g, 
+           typename disable_if<
+              not_is_named_graph<typename Graph::vertex_property_type>, 
+              void*>::type = 0)
+{
+  return typename Graph::named_graph_type::lazy_add_vertex(g, name);
+}
+
+/// Add an edge using vertex names to refer to the vertices
+template<BGL_NAMED_GRAPH_PARAMS>
+typename BGL_NAMED_GRAPH::lazy_add_edge
+add_edge(typename BGL_NAMED_GRAPH::vertex_name_type const& u_name,
+         typename BGL_NAMED_GRAPH::vertex_name_type const& v_name,
+         BGL_NAMED_GRAPH& g)
+{
+  typedef typename BGL_NAMED_GRAPH::lazy_add_edge lazy_add_edge;
+  typedef typename BGL_NAMED_GRAPH::process_id_type process_id_type;
+
+  process_id_type rank = process_id(g.process_group());
+  process_id_type u_owner = g.named_distribution()(u_name);
+  process_id_type v_owner = g.named_distribution()(v_name);
+
+  // Resolve local vertex names before building the "lazy" edge
+  // addition structure.
+  if (u_owner == rank && v_owner == rank)
+    return lazy_add_edge(g, add_vertex(u_name, g), add_vertex(v_name, g));
+  else if (u_owner == rank && v_owner != rank)
+    return lazy_add_edge(g, add_vertex(u_name, g), v_name);
+  else if (u_owner != rank && v_owner == rank)
+    return lazy_add_edge(g, u_name, add_vertex(v_name, g));
+  else
+    return lazy_add_edge(g, u_name, v_name);
+}
+
+template<BGL_NAMED_GRAPH_PARAMS>
+typename BGL_NAMED_GRAPH::lazy_add_edge
+add_edge(typename BGL_NAMED_GRAPH::vertex_name_type const& u_name,
+         typename BGL_NAMED_GRAPH::vertex_descriptor const& v,
+         BGL_NAMED_GRAPH& g)
+{
+  // Resolve local vertex names before building the "lazy" edge
+  // addition structure.
+  typedef typename BGL_NAMED_GRAPH::lazy_add_edge lazy_add_edge;
+  if (g.named_distribution()(u_name) == process_id(g.process_group()))
+    return lazy_add_edge(g, add_vertex(u_name, g), v);
+  else
+    return lazy_add_edge(g, u_name, v);
+}
+
+template<BGL_NAMED_GRAPH_PARAMS>
+typename BGL_NAMED_GRAPH::lazy_add_edge
+add_edge(typename BGL_NAMED_GRAPH::vertex_descriptor const& u,
+         typename BGL_NAMED_GRAPH::vertex_name_type const& v_name,
+         BGL_NAMED_GRAPH& g)
+{
+  // Resolve local vertex names before building the "lazy" edge
+  // addition structure.
+  typedef typename BGL_NAMED_GRAPH::lazy_add_edge lazy_add_edge;
+  if (g.named_distribution()(v_name) == process_id(g.process_group()))
+    return lazy_add_edge(g, u, add_vertex(v_name, g));
+  else
+    return lazy_add_edge(g, u, v_name);
+}
+
+/// Add an edge using vertex names to refer to the vertices
+template<BGL_NAMED_GRAPH_PARAMS>
+typename BGL_NAMED_GRAPH::lazy_add_edge_with_property
+add_edge(typename BGL_NAMED_GRAPH::vertex_name_type const& u_name,
+         typename BGL_NAMED_GRAPH::vertex_name_type const& v_name,
+         typename Graph::edge_property_type const& property,
+         BGL_NAMED_GRAPH& g)
+{
+  typedef typename BGL_NAMED_GRAPH::lazy_add_edge_with_property lazy_add_edge;
+  typedef typename BGL_NAMED_GRAPH::process_id_type process_id_type;
+
+  process_id_type rank = process_id(g.process_group());
+  process_id_type u_owner = g.named_distribution()(u_name);
+  process_id_type v_owner = g.named_distribution()(v_name);
+
+  // Resolve local vertex names before building the "lazy" edge
+  // addition structure.
+  if (u_owner == rank && v_owner == rank)
+    return lazy_add_edge(g, add_vertex(u_name, g), add_vertex(v_name, g), 
+                         property);
+  else if (u_owner == rank && v_owner != rank)
+    return lazy_add_edge(g, add_vertex(u_name, g), v_name, property);
+  else if (u_owner != rank && v_owner == rank)
+    return lazy_add_edge(g, u_name, add_vertex(v_name, g), property);
+  else
+    return lazy_add_edge(g, u_name, v_name, property);
+}
+
+template<BGL_NAMED_GRAPH_PARAMS>
+typename BGL_NAMED_GRAPH::lazy_add_edge_with_property
+add_edge(typename BGL_NAMED_GRAPH::vertex_name_type const& u_name,
+         typename BGL_NAMED_GRAPH::vertex_descriptor const& v,
+         typename Graph::edge_property_type const& property,
+         BGL_NAMED_GRAPH& g)
+{
+  // Resolve local vertex names before building the "lazy" edge
+  // addition structure.
+  typedef typename BGL_NAMED_GRAPH::lazy_add_edge_with_property lazy_add_edge;
+  if (g.named_distribution()(u_name) == process_id(g.process_group()))
+    return lazy_add_edge(g, add_vertex(u_name, g), v, property);
+  else
+    return lazy_add_edge(g, u_name, v, property);
+}
+
+template<BGL_NAMED_GRAPH_PARAMS>
+typename BGL_NAMED_GRAPH::lazy_add_edge_with_property
+add_edge(typename BGL_NAMED_GRAPH::vertex_descriptor const& u,
+         typename BGL_NAMED_GRAPH::vertex_name_type const& v_name,
+         typename Graph::edge_property_type const& property,
+         BGL_NAMED_GRAPH& g)
+{
+  // Resolve local vertex names before building the "lazy" edge
+  // addition structure.
+  typedef typename BGL_NAMED_GRAPH::lazy_add_edge_with_property lazy_add_edge;
+  if (g.named_distribution()(v_name) == process_id(g.process_group()))
+    return lazy_add_edge(g, u, add_vertex(v_name, g), property);
+  else
+    return lazy_add_edge(g, u, v_name, property);
+}
+
+template<BGL_NAMED_GRAPH_PARAMS>
+typename BGL_NAMED_GRAPH::process_id_type 
+BGL_NAMED_GRAPH::owner_by_property(const vertex_property_type& property)
+{
+  return distribution_(derived().base().extract_name(property));
+}
+
+
+/*******************************************************************
+ * Message handlers                                                *
+ *******************************************************************/
+
+template<BGL_NAMED_GRAPH_PARAMS>
+void 
+BGL_NAMED_GRAPH::
+handle_add_vertex_name(int /*source*/, int /*tag*/, 
+                       const vertex_name_type& msg, trigger_receive_context)
+{
+  add_vertex(msg, derived());
+}
+
+template<BGL_NAMED_GRAPH_PARAMS>
+typename BGL_NAMED_GRAPH::vertex_descriptor
+BGL_NAMED_GRAPH::
+handle_add_vertex_name_with_reply(int source, int /*tag*/, 
+                                  const vertex_name_type& msg, 
+                                  trigger_receive_context)
+{
+  return add_vertex(msg, derived());
+}
+
+template<BGL_NAMED_GRAPH_PARAMS>
+boost::parallel::detail::untracked_pair<typename BGL_NAMED_GRAPH::vertex_descriptor, bool>
+BGL_NAMED_GRAPH::
+handle_find_vertex(int source, int /*tag*/, const vertex_name_type& msg, 
+                   trigger_receive_context)
+{
+  using boost::parallel::detail::make_untracked_pair;
+
+  optional<vertex_descriptor> v = find_vertex(msg, derived());
+  if (v)
+    return make_untracked_pair(*v, true);
+  else
+    return make_untracked_pair(graph_traits<Graph>::null_vertex(), false);
+}
+
+template<BGL_NAMED_GRAPH_PARAMS>
+template<typename U, typename V>
+void
+BGL_NAMED_GRAPH::
+handle_add_edge(int source, int /*tag*/, const boost::parallel::detail::untracked_pair<U, V>& msg, 
+                trigger_receive_context)
+{
+  add_edge(msg.first, msg.second, derived());
+}
+
+template<BGL_NAMED_GRAPH_PARAMS>
+template<typename U, typename V>
+boost::parallel::detail::untracked_pair<typename BGL_NAMED_GRAPH::edge_descriptor, bool>
+BGL_NAMED_GRAPH::
+handle_add_edge_with_reply(int source, int /*tag*/, const boost::parallel::detail::untracked_pair<U, V>& msg,
+                           trigger_receive_context)
+{
+  std::pair<typename BGL_NAMED_GRAPH::edge_descriptor, bool> p =
+    add_edge(msg.first, msg.second, derived());
+   return p;
+}
+
+template<BGL_NAMED_GRAPH_PARAMS>
+template<typename U, typename V>
+void 
+BGL_NAMED_GRAPH::
+handle_add_edge_with_property
+  (int source, int tag, 
+   const pair_with_property<U, V, edge_property_type>& msg,
+   trigger_receive_context)
+{
+  add_edge(msg.first, msg.second, msg.get_property(), derived());
+}
+
+template<BGL_NAMED_GRAPH_PARAMS>
+template<typename U, typename V>
+boost::parallel::detail::untracked_pair<typename BGL_NAMED_GRAPH::edge_descriptor, bool>
+BGL_NAMED_GRAPH::
+handle_add_edge_with_reply_and_property
+  (int source, int tag, 
+   const pair_with_property<U, V, edge_property_type>& msg,
+   trigger_receive_context)
+{
+  std:: pair<typename BGL_NAMED_GRAPH::edge_descriptor, bool> p =
+    add_edge(msg.first, msg.second, msg.get_property(), derived());
+  return p;
+}
+
+#undef BGL_NAMED_GRAPH
+#undef BGL_NAMED_GRAPH_PARAMS
+
+/*******************************************************************
+ * Maybe named graph mixin                                         *
+ *******************************************************************/
+
+/**
+ * A graph mixin that can provide a mapping from names to vertices,
+ * and use that mapping to simplify creation and manipulation of
+ * graphs. 
+ */
+template<typename Graph, typename Vertex, typename Edge, typename Config, 
+  typename ExtractName 
+    = typename internal_vertex_name<typename Config::vertex_property_type>::type>
+struct maybe_named_graph 
+  : public named_graph<Graph, Vertex, Edge, Config> 
+{
+private:
+  typedef named_graph<Graph, Vertex, Edge, Config> inherited;
+  typedef typename Config::process_group_type process_group_type;
+  
+public:
+  /// The type used to distribute named vertices in the graph
+  typedef typename Config::distribution_type distribution_type;
+  typedef typename Config::base_distribution_type base_distribution_type;
+  
+  explicit maybe_named_graph(const process_group_type& pg) : inherited(pg) { }
+
+  maybe_named_graph(const process_group_type& pg, 
+                    const base_distribution_type& distribution)
+    : inherited(pg, distribution) { }  
+
+  distribution_type&       distribution()       { return this->distribution_; }
+  const distribution_type& distribution() const { return this->distribution_; }
+};
+
+/**
+ * A graph mixin that can provide a mapping from names to vertices,
+ * and use that mapping to simplify creation and manipulation of
+ * graphs. This partial specialization turns off this functionality
+ * when the @c VertexProperty does not have an internal vertex name.
+ */
+template<typename Graph, typename Vertex, typename Edge, typename Config>
+struct maybe_named_graph<Graph, Vertex, Edge, Config, void> 
+{ 
+private:
+  typedef typename Config::process_group_type process_group_type;
+  typedef typename Config::vertex_property_type vertex_property_type;
+  
+public:
+  typedef typename process_group_type::process_id_type process_id_type;
+
+  /// The type used to distribute named vertices in the graph
+  typedef typename Config::distribution_type distribution_type;
+  typedef typename Config::base_distribution_type base_distribution_type;
+
+  explicit maybe_named_graph(const process_group_type&)  { }
+
+  maybe_named_graph(const process_group_type& pg, 
+                    const base_distribution_type& distribution) 
+    : distribution_(pg, distribution) { }
+
+  /// Notify the named_graph that we have added the given vertex. This
+  /// is a no-op.
+  void added_vertex(Vertex) { }
+
+  /// Notify the named_graph that we are removing the given
+  /// vertex. This is a no-op.
+  void removing_vertex(Vertex) { }
+
+  /// Notify the named_graph that we are clearing the graph
+  void clearing_graph() { }
+
+  /// Retrieve the owner of a given vertex based on the properties
+  /// associated with that vertex. This operation just returns the
+  /// number of the local processor, adding all vertices locally.
+  process_id_type owner_by_property(const vertex_property_type&)
+  {
+    return process_id(pg);
+  }
+
+  distribution_type&       distribution()       { return distribution_; }
+  const distribution_type& distribution() const { return distribution_; }
+
+protected:
+  /// The process group of the graph
+  process_group_type pg;
+  
+  /// The distribution used for the graph
+  distribution_type distribution_;
+};
+
+} } } // end namespace boost::graph::distributed
+
+#endif // BOOST_GRAPH_DISTRIBUTED_NAMED_GRAPH_HPP
Added: trunk/boost/graph/distributed/page_rank.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/distributed/page_rank.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -0,0 +1,225 @@
+// 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/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);
+        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);
+
+  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);
+
+  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
+
+  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 (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
Added: trunk/boost/graph/distributed/queue.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/distributed/queue.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -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.cpp>
+
+#undef BOOST_DISTRIBUTED_QUEUE_TYPE
+#undef BOOST_DISTRIBUTED_QUEUE_PARMS
+
+#endif // BOOST_GRAPH_DISTRIBUTED_QUEUE_HPP
Added: trunk/boost/graph/distributed/reverse_graph.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/distributed/reverse_graph.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -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
Added: trunk/boost/graph/distributed/rmat_graph_generator.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/distributed/rmat_graph_generator.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -0,0 +1,162 @@
+// 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/graph/parallel/algorithm.hpp>
+#include <boost/graph/distributed/mpi_process_group.hpp>
+
+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 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(boost::graph::distributed::mpi_process_group 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)
+      {
+          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(log2(n)));
+          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;
+                  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
Added: trunk/boost/graph/distributed/selector.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/distributed/selector.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -0,0 +1,36 @@
+// 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
+
+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;
+  };
+}
+
+#endif // BOOST_GRAPH_DISTRIBUTED_SELECTOR_HPP
Added: trunk/boost/graph/distributed/shuffled_distribution.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/distributed/shuffled_distribution.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -0,0 +1,113 @@
+// 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/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);
+        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
+
Added: trunk/boost/graph/distributed/st_connected.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/distributed/st_connected.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -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/parallel/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::parallel::process_group;
+  using boost::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
Added: trunk/boost/graph/distributed/strong_components.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/distributed/strong_components.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -0,0 +1,985 @@
+// 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/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( 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( 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( 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( 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( 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( 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)) {
+          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) {
+             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) {
+               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,g))) == 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( 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( 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( tie(vstart, vend) = vertices(g); vstart != vend; vstart++ )
+        for( 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)) {
+        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( 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( 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
Added: trunk/boost/graph/distributed/two_bit_color_map.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/distributed/two_bit_color_map.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -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 two_bit_color_map<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 two_bit_color_map<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 two_bit_color_map<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 two_bit_color_map<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
Added: trunk/boost/graph/distributed/unsafe_serialize.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/distributed/unsafe_serialize.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -0,0 +1,75 @@
+// 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
+
+// This file contains the "unsafe_serialize" routine, which transforms
+// types they may not be serializable (such as void*) into
+// serializable equivalents.
+#ifndef PBGL_UNSAFE_SERIALIZE_HPP
+#define PBGL_UNSAFE_SERIALIZE_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/mpi/datatype.hpp>
+#include <boost/serialization/is_bitwise_serializable.hpp>
+#include <boost/mpl/bool.hpp>
+#include <boost/mpl/if.hpp>
+#include <utility>
+
+BOOST_IS_BITWISE_SERIALIZABLE(void*)
+namespace boost { namespace mpi {
+    template<> struct is_mpi_datatype<void*> : mpl::true_ { };
+} } // end namespace boost::mpi
+
+namespace boost {
+  typedef mpl::if_c<(sizeof(int) == sizeof(void*)), 
+                    int, 
+                    mpl::if_c<(sizeof(long) == sizeof(void*)), long, void>::type
+                    >::type ptr_serialize_type;
+    
+  template<typename T> inline T& unsafe_serialize(T& x) { return x; }
+
+  inline ptr_serialize_type& unsafe_serialize(void*& x)
+  { return reinterpret_cast<ptr_serialize_type&>(x); }
+
+  // Force Boost.MPI to serialize a void* like a ptr_serialize_type
+  namespace mpi {
+    template<> inline MPI_Datatype get_mpi_datatype<void*>(void* const& x)
+    {
+      return get_mpi_datatype<ptr_serialize_type>();
+    }
+  }
+
+  template<typename T, typename U>
+  struct unsafe_pair
+  {
+    unsafe_pair() { }
+    unsafe_pair(const T& t, const U& u) : first(t), second(u) { }
+    unsafe_pair(const std::pair<T, U>& p) : first(p.first), second(p.second) { }
+    T first;
+    U second;
+
+    template<typename Archiver>
+    void serialize(Archiver& ar, const unsigned /*version*/)
+    {
+      ar & unsafe_serialize(first) & unsafe_serialize(second);
+    }
+  };
+
+  template<typename T, typename U>
+  bool operator<(unsafe_pair<T,U> const& x, unsafe_pair<T,U> const& y)
+  {
+    return std::make_pair(x.first, x.second) < 
+      std::make_pair(y.first, y.second);  
+  }
+
+} // end namespace boost
+
+#endif // PBGL_UNSAFE_SERIALIZE_HPP
Added: trunk/boost/graph/distributed/vertex_list_adaptor.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/distributed/vertex_list_adaptor.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -0,0 +1,403 @@
+// 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_VERTEX_LIST_ADAPTOR_HPP
+#define BOOST_VERTEX_LIST_ADAPTOR_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 <vector>
+#include <boost/shared_ptr.hpp>
+#include <boost/property_map/property_map.hpp>
+#include <boost/graph/parallel/algorithm.hpp>
+#include <boost/graph/parallel/container_traits.hpp>
+#include <boost/property_map/vector_property_map.hpp>
+
+namespace boost { namespace graph {
+
+// --------------------------------------------------------------------------
+// Global index map built from a distribution 
+// --------------------------------------------------------------------------
+template<typename Distribution, typename OwnerPropertyMap, 
+         typename LocalPropertyMap>
+class distribution_global_index_map
+{
+ public:
+  typedef std::size_t value_type;
+  typedef value_type reference;
+  typedef typename property_traits<OwnerPropertyMap>::key_type key_type;
+  typedef readable_property_map_tag category;
+
+  distribution_global_index_map(const Distribution& distribution,
+                                const OwnerPropertyMap& owner,
+                                const LocalPropertyMap& local)
+    : distribution_(distribution), owner(owner), local(local) { }
+
+  Distribution distribution_;
+  OwnerPropertyMap owner;
+  LocalPropertyMap local;
+};
+
+template<typename Distribution, typename OwnerPropertyMap, 
+         typename LocalPropertyMap>
+inline 
+typename distribution_global_index_map<Distribution, OwnerPropertyMap,
+                                       LocalPropertyMap>::value_type
+get(const distribution_global_index_map<Distribution, OwnerPropertyMap,
+                                        LocalPropertyMap>& p,
+    typename distribution_global_index_map<Distribution, OwnerPropertyMap,
+                                           LocalPropertyMap>::key_type x)
+{ 
+  using boost::get;
+  return p.distribution_.global(get(p.owner, x), get(p.local, x));
+}
+
+template<typename Graph, typename Distribution>
+inline
+distribution_global_index_map<
+  Distribution, 
+  typename property_map<Graph, vertex_owner_t>::const_type,
+  typename property_map<Graph, vertex_local_t>::const_type>
+make_distribution_global_index_map(const Graph& g, const Distribution& d)
+{
+  typedef distribution_global_index_map<
+            Distribution, 
+            typename property_map<Graph, vertex_owner_t>::const_type,
+            typename property_map<Graph, vertex_local_t>::const_type> 
+    result_type;
+  return result_type(d, get(vertex_owner, g), get(vertex_local, g));
+}
+
+// --------------------------------------------------------------------------
+// Global index map built from a distributed index map and list of vertices
+// --------------------------------------------------------------------------
+template<typename IndexMap>
+class stored_global_index_map : public IndexMap
+{
+ public:
+  typedef readable_property_map_tag category;
+
+  stored_global_index_map(const IndexMap& index_map) : IndexMap(index_map) { 
+    // When we have a global index, we need to always have the indices
+    // of every key we've seen
+    this->set_max_ghost_cells(0);
+  }
+};
+
+// --------------------------------------------------------------------------
+// Global index map support code
+// --------------------------------------------------------------------------
+namespace detail {
+  template<typename PropertyMap, typename ForwardIterator>
+  inline void 
+  initialize_global_index_map(const PropertyMap&, 
+                              ForwardIterator, ForwardIterator) 
+  { }
+
+  template<typename IndexMap, typename ForwardIterator>
+  void 
+  initialize_global_index_map(stored_global_index_map<IndexMap>& p,
+                              ForwardIterator first, ForwardIterator last)
+  {
+    using std::distance;
+
+    typedef typename property_traits<IndexMap>::value_type size_t;
+
+    size_t n = distance(first, last);
+    for (size_t i = 0; i < n; ++i, ++first) local_put(p, *first, i);
+  }
+}
+
+// --------------------------------------------------------------------------
+// Adapts a Distributed Vertex List Graph to a Vertex List Graph
+// --------------------------------------------------------------------------
+template<typename Graph, typename GlobalIndexMap>
+class vertex_list_adaptor : public graph_traits<Graph>
+{
+  typedef graph_traits<Graph> inherited;
+
+  typedef typename inherited::traversal_category base_traversal_category;
+  
+ public:
+  typedef typename inherited::vertex_descriptor vertex_descriptor;
+  typedef typename std::vector<vertex_descriptor>::iterator vertex_iterator;
+  typedef typename std::vector<vertex_descriptor>::size_type
+    vertices_size_type;
+
+  struct traversal_category 
+    : public virtual base_traversal_category,
+      public virtual vertex_list_graph_tag {};
+
+  vertex_list_adaptor(const Graph& g, 
+                      const GlobalIndexMap& index_map = GlobalIndexMap())
+    : g(&g), index_map(index_map)
+  {
+    using boost::vertices;
+
+    all_vertices_.reset(new std::vector<vertex_descriptor>());
+    all_gather(process_group(), vertices(g).first, vertices(g).second,
+               *all_vertices_);
+    detail::initialize_global_index_map(this->index_map, 
+                                        all_vertices_->begin(),
+                                        all_vertices_->end());
+  }
+
+  const Graph& base() const { return *g; }
+
+  // --------------------------------------------------------------------------
+  // Distributed Container
+  // --------------------------------------------------------------------------
+  typedef typename boost::graph::parallel::process_group_type<Graph>::type 
+    process_group_type;
+
+  process_group_type process_group() const 
+  { 
+    using boost::graph::parallel::process_group;
+    return process_group(*g); 
+  }
+
+  std::pair<vertex_iterator, vertex_iterator> vertices() const
+  { return std::make_pair(all_vertices_->begin(), all_vertices_->end()); }
+
+  vertices_size_type num_vertices() const { return all_vertices_->size(); }
+
+  GlobalIndexMap get_index_map() const { return index_map; }
+
+ private:
+  const Graph* g;
+  GlobalIndexMap index_map;
+  shared_ptr<std::vector<vertex_descriptor> > all_vertices_;
+};
+
+template<typename Graph, typename GlobalIndexMap>
+inline vertex_list_adaptor<Graph, GlobalIndexMap>
+make_vertex_list_adaptor(const Graph& g, const GlobalIndexMap& index_map)
+{ return vertex_list_adaptor<Graph, GlobalIndexMap>(g, index_map); }
+
+namespace detail {
+  template<typename Graph>
+  class default_global_index_map
+  {
+    typedef typename graph_traits<Graph>::vertices_size_type value_type;
+    typedef typename property_map<Graph, vertex_index_t>::const_type local_map;
+
+  public:
+    typedef vector_property_map<value_type, local_map> distributed_map;
+    typedef stored_global_index_map<distributed_map> type;
+  };
+}
+
+template<typename Graph>
+inline 
+vertex_list_adaptor<Graph, 
+                    typename detail::default_global_index_map<Graph>::type>
+make_vertex_list_adaptor(const Graph& g)
+{ 
+  typedef typename detail::default_global_index_map<Graph>::type 
+    GlobalIndexMap;
+  typedef typename detail::default_global_index_map<Graph>::distributed_map
+    DistributedMap;
+  typedef vertex_list_adaptor<Graph, GlobalIndexMap> result_type;
+  return result_type(g, 
+                     GlobalIndexMap(DistributedMap(num_vertices(g), 
+                                                   get(vertex_index, g))));
+}
+
+// --------------------------------------------------------------------------
+// Incidence Graph
+// --------------------------------------------------------------------------
+template<typename Graph, typename GlobalIndexMap>
+inline typename vertex_list_adaptor<Graph, GlobalIndexMap>::vertex_descriptor
+source(typename vertex_list_adaptor<Graph, GlobalIndexMap>::edge_descriptor e,
+       const vertex_list_adaptor<Graph, GlobalIndexMap>& g)
+{ return source(e, g.base()); }
+
+template<typename Graph, typename GlobalIndexMap>
+inline typename vertex_list_adaptor<Graph, GlobalIndexMap>::vertex_descriptor
+target(typename vertex_list_adaptor<Graph, GlobalIndexMap>::edge_descriptor e,
+       const vertex_list_adaptor<Graph, GlobalIndexMap>& g)
+{ return target(e, g.base()); }
+
+template<typename Graph, typename GlobalIndexMap>
+inline
+std::pair<typename vertex_list_adaptor<Graph, GlobalIndexMap>::out_edge_iterator,
+          typename vertex_list_adaptor<Graph, GlobalIndexMap>::out_edge_iterator>
+out_edges(typename vertex_list_adaptor<Graph, GlobalIndexMap>::vertex_descriptor v,
+          const vertex_list_adaptor<Graph, GlobalIndexMap>& g)
+{ return out_edges(v, g.base()); }
+
+template<typename Graph, typename GlobalIndexMap>
+inline typename vertex_list_adaptor<Graph, GlobalIndexMap>::degree_size_type
+out_degree(typename vertex_list_adaptor<Graph, GlobalIndexMap>::vertex_descriptor v,
+          const vertex_list_adaptor<Graph, GlobalIndexMap>& g)
+{ return out_degree(v, g.base()); }
+
+// --------------------------------------------------------------------------
+// Bidirectional Graph
+// --------------------------------------------------------------------------
+template<typename Graph, typename GlobalIndexMap>
+inline
+std::pair<typename vertex_list_adaptor<Graph, GlobalIndexMap>::in_edge_iterator,
+          typename vertex_list_adaptor<Graph, GlobalIndexMap>::in_edge_iterator>
+in_edges(typename vertex_list_adaptor<Graph, GlobalIndexMap>::vertex_descriptor v,
+         const vertex_list_adaptor<Graph, GlobalIndexMap>& g)
+{ return in_edges(v, g.base()); }
+
+template<typename Graph, typename GlobalIndexMap>
+inline typename vertex_list_adaptor<Graph, GlobalIndexMap>::degree_size_type
+in_degree(typename vertex_list_adaptor<Graph, GlobalIndexMap>::vertex_descriptor v,
+          const vertex_list_adaptor<Graph, GlobalIndexMap>& g)
+{ return in_degree(v, g.base()); }
+
+template<typename Graph, typename GlobalIndexMap>
+inline typename vertex_list_adaptor<Graph, GlobalIndexMap>::degree_size_type
+degree(typename vertex_list_adaptor<Graph, GlobalIndexMap>::vertex_descriptor v,
+       const vertex_list_adaptor<Graph, GlobalIndexMap>& g)
+{ return degree(v, g.base()); }
+
+// --------------------------------------------------------------------------
+// Adjacency Graph
+// --------------------------------------------------------------------------
+template<typename Graph, typename GlobalIndexMap>
+inline
+std::pair<typename vertex_list_adaptor<Graph, GlobalIndexMap>::adjacency_iterator,
+          typename vertex_list_adaptor<Graph, GlobalIndexMap>::adjacency_iterator>
+adjacent_vertices(typename vertex_list_adaptor<Graph, GlobalIndexMap>::vertex_descriptor v,
+                  const vertex_list_adaptor<Graph, GlobalIndexMap>& g)
+{ return adjacent_vertices(v, g.base()); }
+
+
+// --------------------------------------------------------------------------
+// Vertex List Graph
+// --------------------------------------------------------------------------
+template<typename Graph, typename GlobalIndexMap>
+inline
+std::pair<typename vertex_list_adaptor<Graph, GlobalIndexMap>::vertex_iterator,
+          typename vertex_list_adaptor<Graph, GlobalIndexMap>::vertex_iterator>
+vertices(const vertex_list_adaptor<Graph, GlobalIndexMap>& g)
+{ return g.vertices(); }
+
+template<typename Graph, typename GlobalIndexMap>
+inline
+typename vertex_list_adaptor<Graph, GlobalIndexMap>::vertices_size_type
+num_vertices(const vertex_list_adaptor<Graph, GlobalIndexMap>& g)
+{ return g.num_vertices(); }
+
+// --------------------------------------------------------------------------
+// Edge List Graph
+// --------------------------------------------------------------------------
+template<typename Graph, typename GlobalIndexMap>
+inline
+std::pair<typename vertex_list_adaptor<Graph, GlobalIndexMap>::edge_iterator,
+          typename vertex_list_adaptor<Graph, GlobalIndexMap>::edge_iterator>
+edges(const vertex_list_adaptor<Graph, GlobalIndexMap>& g)
+{ return edges(g.base()); }
+
+template<typename Graph, typename GlobalIndexMap>
+inline
+typename vertex_list_adaptor<Graph, GlobalIndexMap>::edges_size_type
+num_edges(const vertex_list_adaptor<Graph, GlobalIndexMap>& g)
+{ return num_edges(g.base()); }
+
+// --------------------------------------------------------------------------
+// Property Graph
+// --------------------------------------------------------------------------
+template<typename PropertyTag, typename Graph, typename GlobalIndexMap>
+inline typename property_map<Graph, PropertyTag>::type
+get(PropertyTag p, vertex_list_adaptor<Graph, GlobalIndexMap>& g)
+{ return get(p, g.base()); }
+
+template<typename PropertyTag, typename Graph, typename GlobalIndexMap>
+inline typename property_map<Graph, PropertyTag>::const_type
+get(PropertyTag p, const vertex_list_adaptor<Graph, GlobalIndexMap>& g)
+{ return get(p, g.base()); }
+
+template<typename PropertyTag, typename Graph, typename GlobalIndexMap>
+inline typename property_traits<
+                  typename property_map<Graph, PropertyTag>::type
+                >::value_type
+get(PropertyTag p, const vertex_list_adaptor<Graph, GlobalIndexMap>& g,
+    typename property_traits<
+               typename property_map<Graph, PropertyTag>::type
+             >::key_type const& x)
+{ return get(p, g.base(), x); }
+
+template<typename PropertyTag, typename Graph, typename GlobalIndexMap>
+inline void
+put(PropertyTag p, vertex_list_adaptor<Graph, GlobalIndexMap>& g,
+    typename property_traits<
+               typename property_map<Graph, PropertyTag>::type
+             >::key_type const& x,
+    typename property_traits<
+               typename property_map<Graph, PropertyTag>::type
+             >::value_type const& v)
+{ return put(p, g.base(), x, v); }
+
+// --------------------------------------------------------------------------
+// Property Graph: vertex_index property
+// --------------------------------------------------------------------------
+template<typename Graph, typename GlobalIndexMap>
+inline GlobalIndexMap
+get(vertex_index_t, const vertex_list_adaptor<Graph, GlobalIndexMap>& g)
+{ return g.get_index_map(); }
+
+template<typename Graph, typename GlobalIndexMap>
+inline typename vertex_list_adaptor<Graph, GlobalIndexMap>::vertices_size_type
+get(vertex_index_t, const vertex_list_adaptor<Graph, GlobalIndexMap>& g,
+    typename vertex_list_adaptor<Graph, GlobalIndexMap>::vertex_descriptor x)
+{ return get(g.get_index_map(), x); }
+
+// --------------------------------------------------------------------------
+// Adjacency Matrix Graph
+// --------------------------------------------------------------------------
+template<typename Graph, typename GlobalIndexMap>
+std::pair<typename vertex_list_adaptor<Graph, GlobalIndexMap>::edge_descriptor,
+          bool>
+edge(typename vertex_list_adaptor<Graph, GlobalIndexMap>::vertex_descriptor u,
+     typename vertex_list_adaptor<Graph, GlobalIndexMap>::vertex_descriptor v,
+     vertex_list_adaptor<Graph, GlobalIndexMap>& g)
+{ return edge(u, v, g.base()); }
+
+} } // end namespace boost::graph
+
+namespace boost {
+
+// --------------------------------------------------------------------------
+// Property Graph: vertex_index property
+// --------------------------------------------------------------------------
+template<typename Graph, typename GlobalIndexMap>
+class property_map<vertex_index_t, 
+                   graph::vertex_list_adaptor<Graph, GlobalIndexMap> >
+{
+public:
+  typedef GlobalIndexMap type;
+  typedef type const_type;
+};
+
+template<typename Graph, typename GlobalIndexMap>
+class property_map<vertex_index_t, 
+                   const graph::vertex_list_adaptor<Graph, GlobalIndexMap> >
+{
+public:
+  typedef GlobalIndexMap type;
+  typedef type const_type;
+};
+
+using graph::distribution_global_index_map;
+using graph::make_distribution_global_index_map;
+using graph::stored_global_index_map;
+using graph::make_vertex_list_adaptor;
+using graph::vertex_list_adaptor;
+
+} // end namespace boost
+
+#endif // BOOST_VERTEX_LIST_ADAPTOR_HPP
Modified: trunk/boost/graph/fruchterman_reingold.hpp
==============================================================================
--- trunk/boost/graph/fruchterman_reingold.hpp	(original)
+++ trunk/boost/graph/fruchterman_reingold.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -457,4 +457,8 @@
 
 } // end namespace boost
 
+#ifdef BOOST_GRAPH_USE_MPI
+#  include <boost/graph/distributed/fruchterman_reingold.hpp>
+#endif
+
 #endif // BOOST_GRAPH_FRUCHTERMAN_REINGOLD_FORCE_DIRECTED_LAYOUT_HPP
Modified: trunk/boost/graph/graphviz.hpp
==============================================================================
--- trunk/boost/graph/graphviz.hpp	(original)
+++ trunk/boost/graph/graphviz.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -794,4 +794,8 @@
 #  include <boost/graph/detail/read_graphviz_spirit.hpp>
 #endif // BOOST_GRAPH_READ_GRAPHVIZ_ITERATORS
 
+#ifdef BOOST_GRAPH_USE_MPI
+#  include <boost/graph/distributed/graphviz.hpp>
+#endif
+
 #endif // BOOST_GRAPHVIZ_HPP
Modified: trunk/boost/graph/page_rank.hpp
==============================================================================
--- trunk/boost/graph/page_rank.hpp	(original)
+++ trunk/boost/graph/page_rank.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -154,4 +154,8 @@
 
 } } // end namespace boost::graph
 
+#ifdef BOOST_GRAPH_USE_MPI
+#  include <boost/graph/distributed/page_rank.hpp>
+#endif
+
 #endif // BOOST_GRAPH_PAGE_RANK_HPP
Added: trunk/boost/graph/parallel/algorithm.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/parallel/algorithm.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -0,0 +1,84 @@
+// 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_PARALLEL_ALGORITHM_HPP
+#define BOOST_PARALLEL_ALGORITHM_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/optional.hpp>
+#include <boost/config.hpp> // for BOOST_STATIC_CONSTANT
+#include <vector>
+#include <functional>
+
+namespace boost { namespace parallel {
+  template<typename BinaryOp>
+  struct is_commutative
+  {
+    BOOST_STATIC_CONSTANT(bool, value = false);
+  };
+
+  template<typename T>
+  struct minimum : std::binary_function<T, T, T>
+  {
+    const T& operator()(const T& x, const T& y) const { return x < y? x : y; }
+  };
+
+  template<typename T>
+  struct maximum : std::binary_function<T, T, T>
+  {
+    const T& operator()(const T& x, const T& y) const { return x < y? y : x; }
+  };
+
+  template<typename T>
+  struct sum : std::binary_function<T, T, T>
+  {
+    const T operator()(const T& x, const T& y) const { return x + y; }
+  };
+
+  template<typename ProcessGroup, typename InputIterator,
+           typename OutputIterator, typename BinaryOperation>
+  OutputIterator
+  reduce(ProcessGroup pg, typename ProcessGroup::process_id_type root,
+         InputIterator first, InputIterator last, OutputIterator out,
+         BinaryOperation bin_op);
+
+  template<typename ProcessGroup, typename T, typename BinaryOperation>
+  inline T
+  all_reduce(ProcessGroup pg, const T& value, BinaryOperation bin_op)
+  {
+    T result;
+    all_reduce(pg,
+               const_cast<T*>(&value), const_cast<T*>(&value+1),
+               &result, bin_op);
+    return result;
+  }
+
+  template<typename ProcessGroup, typename T, typename BinaryOperation>
+  inline T
+  scan(ProcessGroup pg, const T& value, BinaryOperation bin_op)
+  {
+    T result;
+    scan(pg,
+         const_cast<T*>(&value), const_cast<T*>(&value+1),
+         &result, bin_op);
+    return result;
+  }
+
+
+  template<typename ProcessGroup, typename InputIterator, typename T>
+  void
+  all_gather(ProcessGroup pg, InputIterator first, InputIterator last,
+             std::vector<T>& out);
+} } // end namespace boost::parallel
+
+#include <boost/graph/parallel/detail/inplace_all_to_all.hpp>
+
+#endif // BOOST_PARALLEL_ALGORITHM_HPP
Added: trunk/boost/graph/parallel/basic_reduce.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/parallel/basic_reduce.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -0,0 +1,42 @@
+// 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_PARALLEL_BASIC_REDUCE_HPP
+#define BOOST_PARALLEL_BASIC_REDUCE_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 parallel {
+
+/** Reduction operation used to reconcile differences between local
+ * and remote values for a particular key in a property map.  The
+ * type @c T is typically the @c value_type of the property
+ * map. This basic reduction returns a default-constructed @c T as
+ * the default value and always resolves to the remote value.
+ */
+template<typename T>
+struct basic_reduce
+{
+  BOOST_STATIC_CONSTANT(bool, non_default_resolver = false);
+
+  /// Returns a default-constructed T object
+  template<typename Key>
+  T operator()(const Key&) const { return T(); }
+  
+  /// Returns the remote value
+  template<typename Key>
+  const T& operator()(const Key&, const T&, const T& remote) const 
+  { return remote; }
+};
+
+} } // end namespace boost::parallel
+
+#endif // BOOST_PARALLEL_BASIC_REDUCE_HPP
Added: trunk/boost/graph/parallel/container_traits.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/parallel/container_traits.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -0,0 +1,45 @@
+// 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 file contains traits that describe 
+//
+#ifndef BOOST_GRAPH_PARALLEL_CONTAINER_TRAITS_HPP
+#define BOOST_GRAPH_PARALLEL_CONTAINER_TRAITS_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 parallel {
+
+template<typename T>
+struct process_group_type
+{
+  typedef typename T::process_group_type type;
+};
+
+template<typename T>
+inline typename process_group_type<T>::type
+process_group(const T& x)
+{ return x.process_group(); }
+
+// Helper function that algorithms should use to get the process group
+// out of a container.
+template<typename Container>
+inline typename process_group_type<Container>::type
+process_group_adl(const Container& container)
+{
+  return process_group(container);
+}
+
+
+} } } // end namespace boost::graph::parallel 
+
+#endif // BOOST_GRAPH_PARALLEL_CONTAINER_TRAITS_HPP
Added: trunk/boost/graph/parallel/detail/inplace_all_to_all.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/parallel/detail/inplace_all_to_all.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -0,0 +1,78 @@
+// 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_PARALLEL_INPLACE_ALL_TO_ALL_HPP
+#define BOOST_GRAPH_PARALLEL_INPLACE_ALL_TO_ALL_HPP
+
+#ifndef BOOST_GRAPH_USE_MPI
+#error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
+#endif
+
+//
+// Implements the inplace all-to-all communication algorithm.
+//
+#include <vector>
+#include <iterator>
+
+namespace boost { namespace parallel { 
+
+template<typename ProcessGroup, typename T>
+// where {LinearProcessGroup<ProcessGroup>, MessagingProcessGroup<ProcessGroup>}
+void 
+inplace_all_to_all(ProcessGroup pg, 
+                   const std::vector<std::vector<T> >& outgoing,
+                   std::vector<std::vector<T> >& incoming)
+{
+  typedef typename std::vector<T>::size_type size_type;
+
+  typedef typename ProcessGroup::process_size_type process_size_type;
+  typedef typename ProcessGroup::process_id_type process_id_type;
+
+  process_size_type p = num_processes(pg);
+
+  // Make sure there are no straggling messages
+  synchronize(pg);
+
+  // Send along the count (always) and the data (if count > 0)
+  for (process_id_type dest = 0; dest < p; ++dest) {
+    if (dest != process_id(pg)) {
+      send(pg, dest, 0, outgoing[dest].size());
+      if (!outgoing[dest].empty())
+        send(pg, dest, 1, &outgoing[dest].front(), outgoing[dest].size());
+    }
+  }
+
+  // Make sure all of the data gets transferred
+  synchronize(pg);
+
+  // Receive the sizes and data
+  for (process_id_type source = 0; source < p; ++source) {
+    if (source != process_id(pg)) {
+      size_type size;
+      receive(pg, source, 0, size);
+      incoming[source].resize(size);
+      if (size > 0)
+        receive(pg, source, 1, &incoming[source].front(), size);
+    } else if (&incoming != &outgoing) {
+      incoming[source] = outgoing[source];
+    }
+  }
+}
+
+template<typename ProcessGroup, typename T>
+// where {LinearProcessGroup<ProcessGroup>, MessagingProcessGroup<ProcessGroup>}
+void 
+inplace_all_to_all(ProcessGroup pg, std::vector<std::vector<T> >& data)
+{
+  inplace_all_to_all(pg, data, data);
+}
+
+} } // end namespace boost::parallel
+
+#endif // BOOST_GRAPH_PARALLEL_INPLACE_ALL_TO_ALL_HPP
Added: trunk/boost/graph/parallel/detail/property_holders.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/parallel/detail/property_holders.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -0,0 +1,152 @@
+// Copyright (C) 2007 Douglas Gregor and Matthias Troyer
+//
+// Use, modification and distribution is subject to the Boost Software
+// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+//
+// This file contains helper data structures for use in transmitting
+// properties. The basic idea is to optimize away any storage for the
+// properties when no properties are specified.
+#ifndef BOOST_PARALLEL_DETAIL_PROPERTY_HOLDERS_HPP
+#define BOOST_PARALLEL_DETAIL_PROPERTY_HOLDERS_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/mpi/datatype.hpp>
+#include <boost/property_map/property_map.hpp>
+#include <boost/serialization/base_object.hpp>
+#include <boost/mpl/and.hpp>
+#include <boost/graph/parallel/detail/untracked_pair.hpp>
+
+namespace boost { namespace detail { namespace parallel {
+
+/**
+ * This structure contains an instance of @c Property, unless @c
+ * Property is a placeholder for "no property". Always access the
+ * property through @c get_property. Typically used as a base class.
+ */
+template<typename Property>
+struct maybe_store_property
+{
+  maybe_store_property() {}
+  maybe_store_property(const Property& p) : p(p) {}
+
+  Property&       get_property()       { return p; }
+  const Property& get_property() const { return p; }
+
+private:
+  Property p;
+
+  friend class boost::serialization::access;
+
+  template<typename Archiver>
+  void serialize(Archiver& ar, const unsigned int /*version*/)
+  {
+    ar & p;
+  }
+};
+
+template<>
+struct maybe_store_property<no_property>
+{
+  maybe_store_property() {}
+  maybe_store_property(no_property) {}
+
+  no_property get_property() const { return no_property(); }
+
+private:
+  friend class boost::serialization::access;
+
+  template<typename Archiver>
+  void serialize(Archiver&, const unsigned int /*version*/) { }
+};
+
+/**
+ * This structure is a simple pair that also contains a property.
+ */
+template<typename T, typename U, typename Property>
+class pair_with_property
+  : public boost::parallel::detail::untracked_pair<T, U>
+  , public maybe_store_property<Property>
+{
+public:
+  typedef boost::parallel::detail::untracked_pair<T, U>           pair_base;
+  typedef maybe_store_property<Property> property_base;
+
+  pair_with_property() { }
+
+  pair_with_property(const T& t, const U& u, const Property& property)
+    : pair_base(t, u), property_base(property) { }
+
+private:
+  friend class boost::serialization::access;
+
+  template<typename Archiver>
+  void serialize(Archiver& ar, const unsigned int /*version*/) 
+  { 
+    ar & boost::serialization::base_object<pair_base>(*this)
+       & boost::serialization::base_object<property_base>(*this);
+  }
+};
+
+template<typename T, typename U, typename Property>
+inline pair_with_property<T, U, Property>
+make_pair_with_property(const T& t, const U& u, const Property& property)
+{
+  return pair_with_property<T, U, Property>(t, u, property);
+}
+
+} } } // end namespace boost::parallel::detail
+
+namespace boost { namespace mpi {
+
+template<> 
+struct is_mpi_datatype<boost::detail::parallel::maybe_store_property<no_property> > : mpl::true_ { };
+
+template<typename Property>
+struct is_mpi_datatype<boost::detail::parallel::maybe_store_property<Property> >
+  : is_mpi_datatype<Property> { };
+
+template<typename T, typename U, typename Property>
+struct is_mpi_datatype<boost::detail::parallel::pair_with_property<T, U, Property> >
+  : boost::mpl::and_<is_mpi_datatype<boost::parallel::detail::untracked_pair<T, U> >,
+                     is_mpi_datatype<Property> > { };
+
+} } // end namespace boost::mpi
+
+BOOST_IS_BITWISE_SERIALIZABLE(boost::detail::parallel::maybe_store_property<no_property>)
+
+namespace boost { namespace serialization {
+
+template<typename Property>
+struct is_bitwise_serializable<boost::detail::parallel::maybe_store_property<Property> >
+  : is_bitwise_serializable<Property> { };
+
+template<typename Property>
+struct implementation_level<boost::detail::parallel::maybe_store_property<Property> >
+ : mpl::int_<object_serializable> {} ;
+
+template<typename Property>
+struct tracking_level<boost::detail::parallel::maybe_store_property<Property> >
+ : mpl::int_<track_never> {} ;
+
+template<typename T, typename U, typename Property>
+struct is_bitwise_serializable<
+        boost::detail::parallel::pair_with_property<T, U, Property> >
+  : boost::mpl::and_<is_bitwise_serializable<boost::parallel::detail::untracked_pair<T, U> >,
+                     is_bitwise_serializable<Property> > { };
+
+template<typename T, typename U, typename Property>
+struct implementation_level<
+        boost::detail::parallel::pair_with_property<T, U, Property> >
+ : mpl::int_<object_serializable> {} ;
+
+template<typename T, typename U, typename Property>
+struct tracking_level<
+        boost::detail::parallel::pair_with_property<T, U, Property> >
+ : mpl::int_<track_never> {} ;
+
+} } // end namespace boost::serialization
+
+#endif // BOOST_PARALLEL_DETAIL_PROPERTY_HOLDERS_HPP
Added: trunk/boost/graph/parallel/detail/untracked_pair.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/parallel/detail/untracked_pair.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -0,0 +1,85 @@
+// Copyright (C) 2007 Matthias Troyer
+//
+// Use, modification and distribution is subject to the Boost Software
+// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+//
+// This file contains helper data structures for use in transmitting
+// properties. The basic idea is to optimize away any storage for the
+// properties when no properties are specified.
+#ifndef BOOST_PARALLEL_DETAIL_UNTRACKED_PAIR_HPP
+#define BOOST_PARALLEL_DETAIL_UNTRACKED_PAIR_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/mpi/datatype.hpp>
+#include <utility> // for std::pair
+#include <boost/serialization/utility.hpp>
+
+namespace boost { namespace parallel { namespace detail {
+
+/**
+ * This structure is like std::pair, with the only difference
+ * that tracking in the serialization library is turned off.
+ */
+ 
+template<typename T, typename U>
+struct untracked_pair : public std::pair<T,U>
+{
+  untracked_pair() {}
+
+  untracked_pair(const T& t, const U& u)
+  : std::pair<T,U>(t,u) {}
+
+  template<class T1, class U1>
+  untracked_pair(std::pair<T1,U1> const& p)
+  : std::pair<T,U>(p) {}  
+};
+
+template<typename T, typename U>
+inline untracked_pair<T, U>
+make_untracked_pair(const T& t, const U& u)
+{
+  return untracked_pair<T,U>(t,u);
+}
+
+} } } // end namespace boost::parallel::detail
+
+namespace boost { namespace mpi {
+
+template<typename T, typename U>
+struct is_mpi_datatype<boost::parallel::detail::untracked_pair<T, U> >
+  : is_mpi_datatype<std::pair<T,U> > {};
+
+} } // end namespace boost::mpi
+
+namespace boost { namespace serialization {
+
+// pair
+template<class Archive, class F, class S>
+inline void serialize(
+    Archive & ar,
+    boost::parallel::detail::untracked_pair<F, S> & p,
+    const unsigned int /* file_version */
+){
+    ar & boost::serialization::make_nvp("first", p.first);
+    ar & boost::serialization::make_nvp("second", p.second);
+}
+
+template<typename T, typename U>
+struct is_bitwise_serializable<
+        boost::parallel::detail::untracked_pair<T, U> >
+  : is_bitwise_serializable<std::pair<T, U> > {};
+
+template<typename T, typename U>
+struct implementation_level<boost::parallel::detail::untracked_pair<T, U> >
+ : mpl::int_<object_serializable> {} ;
+
+template<typename T, typename U>
+struct tracking_level<boost::parallel::detail::untracked_pair<T, U> >
+ : mpl::int_<track_never> {} ;
+
+} } // end namespace boost::serialization
+
+#endif // BOOST_PARALLEL_DETAIL_UNTRACKED_PAIR_HPP
Added: trunk/boost/graph/parallel/distribution.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/parallel/distribution.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -0,0 +1,614 @@
+// 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
+//           Peter Gottschling
+//           Andrew Lumsdaine
+#ifndef BOOST_PARALLEL_DISTRIBUTION_HPP
+#define BOOST_PARALLEL_DISTRIBUTION_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 <cstddef>
+#include <vector>
+#include <algorithm>
+#include <numeric>
+#include <boost/iterator/counting_iterator.hpp>
+#include <boost/random/uniform_int.hpp>
+#include <boost/shared_ptr.hpp>
+#include <typeinfo>
+
+namespace boost { namespace parallel {
+
+template<typename ProcessGroup, typename SizeType = std::size_t>
+class variant_distribution
+{
+public:
+  typedef typename ProcessGroup::process_id_type process_id_type;
+  typedef typename ProcessGroup::process_size_type process_size_type;
+  typedef SizeType size_type;
+
+private:
+  struct basic_distribution
+  {
+    virtual ~basic_distribution() {}
+    virtual size_type block_size(process_id_type, size_type) const = 0;
+    virtual process_id_type in_process(size_type) const = 0;
+    virtual size_type local(size_type) const = 0;
+    virtual size_type global(size_type) const = 0;
+    virtual size_type global(process_id_type, size_type) const = 0;
+    virtual void* address() = 0;
+    virtual const void* address() const = 0;
+    virtual const std::type_info& type() const = 0;
+  };
+
+  template<typename Distribution>
+  struct poly_distribution : public basic_distribution
+  {
+    explicit poly_distribution(const Distribution& distribution)
+      : distribution_(distribution) { }
+
+    virtual size_type block_size(process_id_type id, size_type n) const
+    { return distribution_.block_size(id, n); }
+
+    virtual process_id_type in_process(size_type i) const
+    { return distribution_(i); }
+
+    virtual size_type local(size_type i) const
+    { return distribution_.local(i); }
+
+    virtual size_type global(size_type n) const
+    { return distribution_.global(n); }
+
+    virtual size_type global(process_id_type id, size_type n) const
+    { return distribution_.global(id, n); }
+
+    virtual void* address() { return &distribution_; }
+    virtual const void* address() const { return &distribution_; }
+    virtual const std::type_info& type() const { return typeid(Distribution); }
+
+  private:
+    Distribution distribution_;
+  };
+
+public:
+  variant_distribution() { }
+
+  template<typename Distribution>
+  variant_distribution(const Distribution& distribution)
+    : distribution_(new poly_distribution<Distribution>(distribution)) { }
+
+  size_type block_size(process_id_type id, size_type n) const
+  { return distribution_->block_size(id, n); }
+  
+  process_id_type operator()(size_type i) const
+  { return distribution_->in_process(i); }
+  
+  size_type local(size_type i) const
+  { return distribution_->local(i); }
+  
+  size_type global(size_type n) const
+  { return distribution_->global(n); }
+
+  size_type global(process_id_type id, size_type n) const
+  { return distribution_->global(id, n); }
+
+  operator bool() const { return distribution_; }
+
+  void clear() { distribution_.reset(); }
+
+  template<typename T>
+  T* as()
+  {
+    if (distribution_->type() == typeid(T))
+      return static_cast<T*>(distribution_->address());
+    else
+      return 0;
+  }
+
+  template<typename T>
+  const T* as() const
+  {
+    if (distribution_->type() == typeid(T))
+      return static_cast<T*>(distribution_->address());
+    else
+      return 0;
+  }
+
+private:
+  shared_ptr<basic_distribution> distribution_;
+};
+
+struct block
+{
+  template<typename LinearProcessGroup>
+  explicit block(const LinearProcessGroup& pg, std::size_t n) 
+    : id(process_id(pg)), p(num_processes(pg)), n(n) { }
+
+  // If there are n elements in the distributed data structure, returns the number of elements stored locally.
+  template<typename SizeType>
+  SizeType block_size(SizeType n) const
+  { return (n / p) + ((std::size_t)(n % p) > id? 1 : 0); }
+
+  // If there are n elements in the distributed data structure, returns the number of elements stored on processor ID
+  template<typename SizeType, typename ProcessID>
+  SizeType block_size(ProcessID id, SizeType n) const
+  { return (n / p) + ((ProcessID)(n % p) > id? 1 : 0); }
+
+  // Returns the processor on which element with global index i is stored
+  template<typename SizeType>
+  SizeType operator()(SizeType i) const
+  { 
+    SizeType cutoff_processor = n % p;
+    SizeType cutoff = cutoff_processor * (n / p + 1);
+
+    if (i < cutoff) return i / (n / p + 1);
+    else return cutoff_processor + (i - cutoff) / (n / p);
+  }
+
+  // Find the starting index for processor with the given id
+  template<typename ID>
+  std::size_t start(ID id) const
+  {
+    std::size_t estimate = id * (n / p + 1);
+    ID cutoff_processor = n % p;
+    if (id < cutoff_processor) return estimate;
+    else return estimate - (id - cutoff_processor);
+  }
+
+  // Find the local index for the ith global element
+  template<typename SizeType>
+  SizeType local(SizeType i) const
+  { 
+    SizeType owner = (*this)(i);
+    return i - start(owner);
+  }
+
+  // Returns the global index of local element i
+  template<typename SizeType>
+  SizeType global(SizeType i) const
+  { return global(id, i); }
+
+  // Returns the global index of the ith local element on processor id
+  template<typename ProcessID, typename SizeType>
+  SizeType global(ProcessID id, SizeType i) const
+  { return i + start(id); }
+
+ private:
+  std::size_t id; //< The ID number of this processor
+  std::size_t p;  //< The number of processors
+  std::size_t n;  //< The size of the problem space
+};
+
+// Block distribution with arbitrary block sizes
+struct uneven_block
+{
+  typedef std::vector<std::size_t>    size_vector;
+
+  template<typename LinearProcessGroup>
+  explicit uneven_block(const LinearProcessGroup& pg, const std::vector<std::size_t>& local_sizes) 
+    : id(process_id(pg)), p(num_processes(pg)), local_sizes(local_sizes)
+  { 
+    assert(local_sizes.size() == p);
+    local_starts.resize(p + 1);
+    local_starts[0] = 0;
+    std::partial_sum(local_sizes.begin(), local_sizes.end(), &local_starts[1]);
+    n = local_starts[p];
+  }
+
+  // To do maybe: enter local size in each process and gather in constructor (much handier)
+  // template<typename LinearProcessGroup>
+  // explicit uneven_block(const LinearProcessGroup& pg, std::size_t my_local_size) 
+
+  // If there are n elements in the distributed data structure, returns the number of elements stored locally.
+  template<typename SizeType>
+  SizeType block_size(SizeType) const
+  { return local_sizes[id]; }
+
+  // If there are n elements in the distributed data structure, returns the number of elements stored on processor ID
+  template<typename SizeType, typename ProcessID>
+  SizeType block_size(ProcessID id, SizeType) const
+  { return local_sizes[id]; }
+
+  // Returns the processor on which element with global index i is stored
+  template<typename SizeType>
+  SizeType operator()(SizeType i) const
+  {
+    assert (i >= (SizeType) 0 && i < (SizeType) n); // check for valid range
+    size_vector::const_iterator lb = std::lower_bound(local_starts.begin(), local_starts.end(), (std::size_t) i);
+    return ((SizeType)(*lb) == i ? lb : --lb) - local_starts.begin();
+  }
+
+  // Find the starting index for processor with the given id
+  template<typename ID>
+  std::size_t start(ID id) const 
+  {
+    return local_starts[id];
+  }
+
+  // Find the local index for the ith global element
+  template<typename SizeType>
+  SizeType local(SizeType i) const
+  { 
+    SizeType owner = (*this)(i);
+    return i - start(owner);
+  }
+
+  // Returns the global index of local element i
+  template<typename SizeType>
+  SizeType global(SizeType i) const
+  { return global(id, i); }
+
+  // Returns the global index of the ith local element on processor id
+  template<typename ProcessID, typename SizeType>
+  SizeType global(ProcessID id, SizeType i) const
+  { return i + start(id); }
+
+ private:
+  std::size_t              id;           //< The ID number of this processor
+  std::size_t              p;            //< The number of processors
+  std::size_t              n;            //< The size of the problem space
+  std::vector<std::size_t> local_sizes;  //< The sizes of all blocks
+  std::vector<std::size_t> local_starts; //< Lowest global index of each block
+};
+
+
+struct oned_block_cyclic
+{
+  template<typename LinearProcessGroup>
+  explicit oned_block_cyclic(const LinearProcessGroup& pg, std::size_t size)
+    : id(process_id(pg)), p(num_processes(pg)), size(size) { }
+      
+  template<typename SizeType>
+  SizeType block_size(SizeType n) const
+  { 
+    return block_size(id, n);
+  }
+
+  template<typename SizeType, typename ProcessID>
+  SizeType block_size(ProcessID id, SizeType n) const
+  {
+    SizeType all_blocks = n / size;
+    SizeType extra_elements = n % size;
+    SizeType everyone_gets = all_blocks / p;
+    SizeType extra_blocks = all_blocks % p;
+    SizeType my_blocks = everyone_gets + (p < extra_blocks? 1 : 0);
+    SizeType my_elements = my_blocks * size 
+                         + (p == extra_blocks? extra_elements : 0);
+    return my_elements;
+  }
+
+  template<typename SizeType>
+  SizeType operator()(SizeType i) const
+  { 
+    return (i / size) % p;
+  }
+
+  template<typename SizeType>
+  SizeType local(SizeType i) const
+  { 
+    return ((i / size) / p) * size + i % size;
+  }
+
+  template<typename SizeType>
+  SizeType global(SizeType i) const
+  { return global(id, i); }
+
+  template<typename ProcessID, typename SizeType>
+  SizeType global(ProcessID id, SizeType i) const
+  { 
+    return ((i / size) * p + id) * size + i % size;
+  }
+
+ private:
+  std::size_t id;                   //< The ID number of this processor
+  std::size_t p;                    //< The number of processors
+  std::size_t size;                 //< Block size
+};
+
+struct twod_block_cyclic
+{
+  template<typename LinearProcessGroup>
+  explicit twod_block_cyclic(const LinearProcessGroup& pg,
+                             std::size_t block_rows, std::size_t block_columns,
+                             std::size_t data_columns_per_row)
+    : id(process_id(pg)), p(num_processes(pg)), 
+      block_rows(block_rows), block_columns(block_columns), 
+      data_columns_per_row(data_columns_per_row)
+  { }
+      
+  template<typename SizeType>
+  SizeType block_size(SizeType n) const
+  { 
+    return block_size(id, n);
+  }
+
+  template<typename SizeType, typename ProcessID>
+  SizeType block_size(ProcessID id, SizeType n) const
+  {
+    // TBD: This is really lame :)
+    int result = -1;
+    while (n > 0) {
+      --n;
+      if ((*this)(n) == id && (int)local(n) > result) result = local(n);
+    }
+    ++result;
+
+    //    std::cerr << "Block size of id " << id << " is " << result << std::endl;
+    return result;
+  }
+
+  template<typename SizeType>
+  SizeType operator()(SizeType i) const
+  { 
+    SizeType result = get_block_num(i) % p;
+    //    std::cerr << "Item " << i << " goes on processor " << result << std::endl;
+    return result;
+  }
+
+  template<typename SizeType>
+  SizeType local(SizeType i) const
+  { 
+    // Compute the start of the block
+    std::size_t block_num = get_block_num(i);
+    //    std::cerr << "Item " << i << " is in block #" << block_num << std::endl;
+
+    std::size_t local_block_num = block_num / p;
+    std::size_t block_start = local_block_num * block_rows * block_columns;
+
+    // Compute the offset into the block 
+    std::size_t data_row = i / data_columns_per_row;
+    std::size_t data_col = i % data_columns_per_row;
+    std::size_t block_offset = (data_row % block_rows) * block_columns 
+                             + (data_col % block_columns);    
+
+    //    std::cerr << "Item " << i << " maps to local index " << block_start+block_offset << std::endl;
+    return block_start + block_offset;
+  }
+
+  template<typename SizeType>
+  SizeType global(SizeType i) const
+  { 
+    // Compute the (global) block in which this element resides
+    SizeType local_block_num = i / (block_rows * block_columns);
+    SizeType block_offset = i % (block_rows * block_columns);
+    SizeType block_num = local_block_num * p + id;
+
+    // Compute the position of the start of the block (globally)
+    SizeType block_start = block_num * block_rows * block_columns;
+
+    std::cerr << "Block " << block_num << " starts at index " << block_start
+              << std::endl;
+
+    // Compute the row and column of this block
+    SizeType block_row = block_num / (data_columns_per_row / block_columns);
+    SizeType block_col = block_num % (data_columns_per_row / block_columns);
+
+    SizeType row_in_block = block_offset / block_columns;
+    SizeType col_in_block = block_offset % block_columns;
+
+    std::cerr << "Local index " << i << " is in block at row " << block_row
+              << ", column " << block_col << ", in-block row " << row_in_block
+              << ", in-block col " << col_in_block << std::endl;
+
+    SizeType result = block_row * block_rows + block_col * block_columns
+                    + row_in_block * block_rows + col_in_block;
+
+
+    std::cerr << "global(" << i << "@" << id << ") = " << result 
+              << " =? " << local(result) << std::endl;
+    assert(i == local(result));
+    return result;
+  }
+
+ private:
+  template<typename SizeType>
+  std::size_t get_block_num(SizeType i) const
+  {
+    std::size_t data_row = i / data_columns_per_row;
+    std::size_t data_col = i % data_columns_per_row;
+    std::size_t block_row = data_row / block_rows;
+    std::size_t block_col = data_col / block_columns;
+    std::size_t blocks_in_row = data_columns_per_row / block_columns;
+    std::size_t block_num = block_col * blocks_in_row + block_row;
+    return block_num;
+  }
+
+  std::size_t id;                   //< The ID number of this processor
+  std::size_t p;                    //< The number of processors
+  std::size_t block_rows;           //< The # of rows in each block
+  std::size_t block_columns;        //< The # of columns in each block
+  std::size_t data_columns_per_row; //< The # of columns per row of data
+};
+
+class twod_random
+{
+  template<typename RandomNumberGen>
+  struct random_int
+  {
+    explicit random_int(RandomNumberGen& gen) : gen(gen) { }
+
+    template<typename T>
+    T operator()(T n) const
+    {
+      uniform_int<T> distrib(0, n-1);
+      return distrib(gen);
+    }
+
+  private:
+    RandomNumberGen& gen;
+  };
+  
+ public:
+  template<typename LinearProcessGroup, typename RandomNumberGen>
+  explicit twod_random(const LinearProcessGroup& pg,
+                       std::size_t block_rows, std::size_t block_columns,
+                       std::size_t data_columns_per_row,
+                       std::size_t n,
+                       RandomNumberGen& gen)
+    : id(process_id(pg)), p(num_processes(pg)), 
+      block_rows(block_rows), block_columns(block_columns), 
+      data_columns_per_row(data_columns_per_row),
+      global_to_local(n / (block_rows * block_columns))
+  { 
+    std::copy(make_counting_iterator(std::size_t(0)),
+              make_counting_iterator(global_to_local.size()),
+              global_to_local.begin());
+
+    random_int<RandomNumberGen> rand(gen);
+    std::random_shuffle(global_to_local.begin(), global_to_local.end(), rand);
+  }
+      
+  template<typename SizeType>
+  SizeType block_size(SizeType n) const
+  { 
+    return block_size(id, n);
+  }
+
+  template<typename SizeType, typename ProcessID>
+  SizeType block_size(ProcessID id, SizeType n) const
+  {
+    // TBD: This is really lame :)
+    int result = -1;
+    while (n > 0) {
+      --n;
+      if ((*this)(n) == id && (int)local(n) > result) result = local(n);
+    }
+    ++result;
+
+    //    std::cerr << "Block size of id " << id << " is " << result << std::endl;
+    return result;
+  }
+
+  template<typename SizeType>
+  SizeType operator()(SizeType i) const
+  { 
+    SizeType result = get_block_num(i) % p;
+    //    std::cerr << "Item " << i << " goes on processor " << result << std::endl;
+    return result;
+  }
+
+  template<typename SizeType>
+  SizeType local(SizeType i) const
+  { 
+    // Compute the start of the block
+    std::size_t block_num = get_block_num(i);
+    //    std::cerr << "Item " << i << " is in block #" << block_num << std::endl;
+
+    std::size_t local_block_num = block_num / p;
+    std::size_t block_start = local_block_num * block_rows * block_columns;
+
+    // Compute the offset into the block 
+    std::size_t data_row = i / data_columns_per_row;
+    std::size_t data_col = i % data_columns_per_row;
+    std::size_t block_offset = (data_row % block_rows) * block_columns 
+                             + (data_col % block_columns);    
+
+    //    std::cerr << "Item " << i << " maps to local index " << block_start+block_offset << std::endl;
+    return block_start + block_offset;
+  }
+
+ private:
+  template<typename SizeType>
+  std::size_t get_block_num(SizeType i) const
+  {
+    std::size_t data_row = i / data_columns_per_row;
+    std::size_t data_col = i % data_columns_per_row;
+    std::size_t block_row = data_row / block_rows;
+    std::size_t block_col = data_col / block_columns;
+    std::size_t blocks_in_row = data_columns_per_row / block_columns;
+    std::size_t block_num = block_col * blocks_in_row + block_row;
+    return global_to_local[block_num];
+  }
+
+  std::size_t id;                   //< The ID number of this processor
+  std::size_t p;                    //< The number of processors
+  std::size_t block_rows;           //< The # of rows in each block
+  std::size_t block_columns;        //< The # of columns in each block
+  std::size_t data_columns_per_row; //< The # of columns per row of data
+  std::vector<std::size_t> global_to_local;
+};
+
+class random_distribution
+{
+  template<typename RandomNumberGen>
+  struct random_int
+  {
+    explicit random_int(RandomNumberGen& gen) : gen(gen) { }
+
+    template<typename T>
+    T operator()(T n) const
+    {
+      uniform_int<T> distrib(0, n-1);
+      return distrib(gen);
+    }
+
+  private:
+    RandomNumberGen& gen;
+  };
+  
+ public:
+  template<typename LinearProcessGroup, typename RandomNumberGen>
+  random_distribution(const LinearProcessGroup& pg, RandomNumberGen& gen,
+                      std::size_t n)
+    : base(pg, n), local_to_global(n), global_to_local(n)
+  {
+    std::copy(make_counting_iterator(std::size_t(0)),
+              make_counting_iterator(n),
+              local_to_global.begin());
+
+    random_int<RandomNumberGen> rand(gen);
+    std::random_shuffle(local_to_global.begin(), local_to_global.end(), rand);
+                        
+
+    for (std::vector<std::size_t>::size_type i = 0; i < n; ++i)
+      global_to_local[local_to_global[i]] = i;
+  }
+
+  template<typename SizeType>
+  SizeType block_size(SizeType n) const
+  { return base.block_size(n); }
+
+  template<typename SizeType, typename ProcessID>
+  SizeType block_size(ProcessID id, SizeType n) const
+  { return base.block_size(id, n); }
+
+  template<typename SizeType>
+  SizeType operator()(SizeType i) const
+  {
+    return base(global_to_local[i]);
+  }
+
+  template<typename SizeType>
+  SizeType local(SizeType i) const
+  { 
+    return base.local(global_to_local[i]);
+  }
+
+  template<typename ProcessID, typename SizeType>
+  SizeType global(ProcessID p, SizeType i) const
+  { 
+    return local_to_global[base.global(p, i)];
+  }
+
+  template<typename SizeType>
+  SizeType global(SizeType i) const
+  { 
+    return local_to_global[base.global(i)];
+  }
+
+ private:
+  block base;
+  std::vector<std::size_t> local_to_global;
+  std::vector<std::size_t> global_to_local;
+};
+
+} } // end namespace boost::parallel
+
+#endif // BOOST_PARALLEL_DISTRIBUTION_HPP
+
Added: trunk/boost/graph/parallel/process_group.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/parallel/process_group.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -0,0 +1,101 @@
+// 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_PROCESS_GROUP_HPP
+#define BOOST_GRAPH_PARALLEL_PROCESS_GROUP_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 <cstdlib>
+#include <utility>
+
+namespace boost { namespace graph { namespace parallel {
+
+/**
+ * A special type used as a flag to a process group constructor that
+ * indicates that the copy of a process group will represent a new
+ * distributed data structure.
+ */
+struct attach_distributed_object { };
+
+/**
+ * Describes the context in which a trigger is being invoked to
+ * receive a message.
+ */
+enum trigger_receive_context {
+  /// No trigger is active at this time.
+  trc_none,
+  /// The trigger is being invoked during synchronization, at the end
+  /// of a superstep.
+  trc_in_synchronization,
+  /// The trigger is being invoked as an "early" receive of a message
+  /// that was sent through the normal "send" operations to be
+  /// received by the end of the superstep, but the process group sent
+  /// the message earlier to clear its buffers.
+  trc_early_receive,
+  /// The trigger is being invoked for an out-of-band message, which
+  /// must be handled immediately.
+  trc_out_of_band,
+  /// The trigger is being invoked for an out-of-band message, which
+  /// must be handled immediately and has alredy been received by 
+  /// an MPI_IRecv call.
+  trc_irecv_out_of_band  
+};
+
+// Process group tags
+struct process_group_tag {};
+struct linear_process_group_tag : virtual process_group_tag {};
+struct messaging_process_group_tag : virtual process_group_tag {};
+struct immediate_process_group_tag : virtual messaging_process_group_tag {};
+struct bsp_process_group_tag : virtual messaging_process_group_tag {};
+struct batch_process_group_tag : virtual messaging_process_group_tag {};
+struct locking_process_group_tag : virtual process_group_tag {};
+struct spawning_process_group_tag : virtual process_group_tag {};
+
+struct process_group_archetype
+{
+  typedef int process_id_type;
+};
+
+void wait(process_group_archetype&);
+void synchronize(process_group_archetype&);
+int process_id(const process_group_archetype&);
+int num_processes(const process_group_archetype&);
+
+template<typename T> void send(process_group_archetype&, int, int, const T&);
+
+template<typename T>
+process_group_archetype::process_id_type
+receive(const process_group_archetype& pg,
+        process_group_archetype::process_id_type source, int tag, T& value);
+
+template<typename T>
+std::pair<process_group_archetype::process_id_type, std::size_t>
+receive(const process_group_archetype& pg, int tag, T values[], std::size_t n);
+
+template<typename T>
+std::pair<process_group_archetype::process_id_type, std::size_t>
+receive(const process_group_archetype& pg,
+        process_group_archetype::process_id_type source, int tag, T values[],
+        std::size_t n);
+
+} } } // end namespace boost::graph::parallel
+
+namespace boost { namespace graph { namespace distributed {
+  using parallel::trigger_receive_context;
+  using parallel::trc_early_receive;
+  using parallel::trc_out_of_band;
+  using parallel::trc_irecv_out_of_band;
+  using parallel::trc_in_synchronization;
+  using parallel::trc_none;
+  using parallel::attach_distributed_object;
+} } } // end namespace boost::graph::distributed
+
+#endif // BOOST_GRAPH_PARALLEL_PROCESS_GROUP_HPP
Added: trunk/boost/graph/parallel/properties.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/parallel/properties.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -0,0 +1,111 @@
+// 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_PROPERTIES_HPP
+#define BOOST_GRAPH_PARALLEL_PROPERTIES_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/properties.hpp>
+#include <boost/property_map/parallel/distributed_property_map.hpp>
+
+namespace boost {
+  /***************************************************************************
+   * Property map reduction operations
+   ***************************************************************************/
+  /**
+   * Metafunction that produces a reduction operation for the given
+   * property. The default behavior merely forwards to @ref
+   * basic_reduce, but it is expected that this class template will be
+   * specified for important properties.
+   */
+  template<typename Property>
+  struct property_reduce
+  {
+    template<typename Value>
+    class apply : public parallel::basic_reduce<Value> {};
+  };
+
+  /**
+   * Reduction of vertex colors can only darken, not lighten, the
+   * color. Black cannot turn black, grey can only turn black, and
+   * white can be changed to either color. The default color is white.
+   */ 
+  template<> 
+  struct property_reduce<vertex_color_t>
+  {
+    template<typename Color>
+    class apply
+    {
+      typedef color_traits<Color> traits;
+      
+    public:
+      BOOST_STATIC_CONSTANT(bool, non_default_resolver = true);
+
+      template<typename Key>
+      Color operator()(const Key&) const { return traits::white(); }
+      
+      template<typename Key>
+      Color operator()(const Key&, Color local, Color remote) const {
+        if (local == traits::white()) return remote;
+        else if (remote == traits::black()) return remote;
+        else return local;
+      }
+    };
+  };
+
+  /**
+   * Reduction of a distance always takes the shorter distance. The
+   * default distance value is the maximum value for the data type.
+   */
+  template<> 
+  struct property_reduce<vertex_distance_t>
+  {
+    template<typename T>
+    class apply
+    {
+    public:
+      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 x, T y) const { return x < y? x : y; }
+    };
+  };
+
+  template<> 
+  struct property_reduce<vertex_predecessor_t>
+  {
+    template<typename T>
+    class apply
+    {
+    public:
+      BOOST_STATIC_CONSTANT(bool, non_default_resolver = true);
+
+      T operator()(T key) const { return key; }
+      T operator()(T key, T, T y) const { return y; }
+    };
+  };
+
+  template<typename Property, typename PropertyMap>
+  inline void set_property_map_role(Property p, PropertyMap pm)
+  {
+    typedef typename property_traits<PropertyMap>::value_type value_type;
+    typedef property_reduce<Property> property_red;
+    typedef typename property_red::template apply<value_type> reduce;
+
+    pm.set_reduce(reduce());
+  }
+
+} // end namespace boost
+#endif // BOOST_GRAPH_PARALLEL_PROPERTIES_HPP
Added: trunk/boost/graph/parallel/simple_trigger.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/parallel/simple_trigger.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -0,0 +1,108 @@
+// 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 a simplification of the "trigger" method for
+// process groups. The simple trigger handles the common case where
+// the handler associated with a trigger is a member function bound to
+// a particular pointer.
+
+#ifndef BOOST_GRAPH_PARALLEL_SIMPLE_TRIGGER_HPP
+#define 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
+
+#include <boost/graph/parallel/process_group.hpp>
+
+namespace boost { namespace graph { namespace parallel {
+
+namespace detail {
+
+/**
+ * INTERNAL ONLY
+ *
+ * The actual function object that bridges from the normal trigger
+ * interface to the simplified interface. This is the equivalent of
+ * bind(pmf, self, _1, _2, _3, _4), but without the compile-time
+ * overhead of bind.
+ */
+template<typename Class, typename T, typename Result>
+class simple_trigger_t 
+{
+public:
+  simple_trigger_t(Class* self, 
+                   Result (Class::*pmf)(int, int, const T&, 
+                                        trigger_receive_context))
+    : self(self), pmf(pmf) { }
+
+  Result 
+  operator()(int source, int tag, const T& data, 
+             trigger_receive_context context) const
+  {
+    return (self->*pmf)(source, tag, data, context);
+  }
+
+private:
+  Class* self;
+  Result (Class::*pmf)(int, int, const T&, trigger_receive_context);
+};
+
+} // end namespace detail
+
+/**
+ * Simplified trigger interface that reduces the amount of code
+ * required to connect a process group trigger to a handler that is
+ * just a bound member function.
+ *
+ * INTERNAL ONLY
+ */
+template<typename ProcessGroup, typename Class, typename T>
+inline void 
+simple_trigger(ProcessGroup& pg, int tag, Class* self, 
+               void (Class::*pmf)(int source, int tag, const T& data, 
+                                  trigger_receive_context context), int)
+{
+  pg.template trigger<T>(tag, 
+                         detail::simple_trigger_t<Class, T, void>(self, pmf));
+}
+
+/**
+ * Simplified trigger interface that reduces the amount of code
+ * required to connect a process group trigger with a reply to a
+ * handler that is just a bound member function.
+ *
+ * INTERNAL ONLY
+ */
+template<typename ProcessGroup, typename Class, typename T, typename Result>
+inline void 
+simple_trigger(ProcessGroup& pg, int tag, Class* self, 
+               Result (Class::*pmf)(int source, int tag, const T& data, 
+                                    trigger_receive_context context), long)
+{
+  pg.template trigger_with_reply<T>
+    (tag, detail::simple_trigger_t<Class, T, Result>(self, pmf));
+}
+
+/**
+ * Simplified trigger interface that reduces the amount of code
+ * required to connect a process group trigger to a handler that is
+ * just a bound member function.
+ */
+template<typename ProcessGroup, typename Class, typename T, typename Result>
+inline void 
+simple_trigger(ProcessGroup& pg, int tag, Class* self, 
+               Result (Class::*pmf)(int source, int tag, const T& data, 
+                                    trigger_receive_context context))
+{
+        // We pass 0 (an int) to help VC++ disambiguate calls to simple_trigger 
+        // with Result=void.
+        simple_trigger(pg, tag, self, pmf, 0); 
+}
+
+} } } // end namespace boost::graph::parallel
+
+#endif // BOOST_GRAPH_PARALLEL_SIMPLE_TRIGGER_HPP
Modified: trunk/boost/graph/rmat_graph_generator.hpp
==============================================================================
--- trunk/boost/graph/rmat_graph_generator.hpp	(original)
+++ trunk/boost/graph/rmat_graph_generator.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -581,4 +581,8 @@
 
 } // end namespace boost
 
+#ifdef BOOST_GRAPH_USE_MPI
+#include <boost/graph/distributed/rmat_graph_generator.hpp>
+#endif // BOOST_GRAPH_USE_MPI
+
 #endif // BOOST_GRAPH_RMAT_GENERATOR_HPP
Modified: trunk/boost/graph/strong_components.hpp
==============================================================================
--- trunk/boost/graph/strong_components.hpp	(original)
+++ trunk/boost/graph/strong_components.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -334,4 +334,8 @@
 
 } // namespace boost
 
+#ifdef BOOST_GRAPH_USE_MPI
+#  include <boost/graph/distributed/strong_components.hpp>
+#endif
+
 #endif // BOOST_GRAPH_STRONG_COMPONENTS_HPP
Modified: trunk/boost/graph/topology.hpp
==============================================================================
--- trunk/boost/graph/topology.hpp	(original)
+++ trunk/boost/graph/topology.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -246,6 +246,13 @@
     return dist;
   }
 
+  point_type center() const {
+    point_type result;
+    for (std::size_t i = 0; i < Dims; ++i)
+      result[i] = 0;
+    return result;
+  }
+
  private:
   shared_ptr<RandomNumberGenerator> gen_ptr;
   shared_ptr<rand_t> rand;
@@ -319,6 +326,13 @@
     return dist;
   }
 
+  point_type center() const {
+    point_type result;
+    result[0] = (left + right) / 2.;
+    result[1] = (top + bottom) / 2.;
+    return result;
+  }
+
  private:
   shared_ptr<RandomNumberGenerator> gen_ptr;
   shared_ptr<rand_t> rand;
@@ -392,6 +406,13 @@
     return radius - r;
   }
 
+  point_type center() const {
+    point_type result;
+    for (std::size_t i = 0; i < Dims; ++i)
+      result[i] = 0;
+    return result;
+  }
+
  private:
   shared_ptr<RandomNumberGenerator> gen_ptr;
   shared_ptr<rand_t> rand;
Modified: trunk/boost/graph/two_bit_color_map.hpp
==============================================================================
--- trunk/boost/graph/two_bit_color_map.hpp	(original)
+++ trunk/boost/graph/two_bit_color_map.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -91,3 +91,7 @@
 } // end namespace boost
 
 #endif // BOOST_TWO_BIT_COLOR_MAP_HPP
+
+#ifdef BOOST_GRAPH_USE_MPI
+#  include <boost/graph/distributed/two_bit_color_map.hpp>
+#endif
Added: trunk/boost/graph/use_mpi.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/graph/use_mpi.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -0,0 +1,15 @@
+// Copyright (C) 2004-2009 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_USE_MPI_HPP
+#define BOOST_GRAPH_USE_MPI_HPP
+
+#define BOOST_GRAPH_USE_MPI
+
+#endif // BOOST_GRAPH_USE_MPI_HPP
Modified: trunk/boost/pending/property_serialize.hpp
==============================================================================
--- trunk/boost/pending/property_serialize.hpp	(original)
+++ trunk/boost/pending/property_serialize.hpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -7,6 +7,10 @@
 #define BOOST_PROPERTY_SERIALIZE_HPP
 
 #include <boost/pending/property.hpp>
+#ifdef BOOST_GRAPH_USE_MPI
+#include <boost/mpi/datatype.hpp>
+#include <boost/serialization/is_bitwise_serializable.hpp>
+#endif // BOOST_GRAPH_USE_MPI
 
 #include <boost/serialization/base_object.hpp>
 #include <boost/serialization/nvp.hpp>
@@ -23,6 +27,44 @@
     ar & serialization::make_nvp( "property_base" , boost::serialization::base_object<Base>(prop) );
     ar & serialization::make_nvp( "property_value" , prop.m_value );
   }
+
+#ifdef BOOST_GRAPH_USE_MPI
+  namespace mpi {
+    template<typename Tag, typename T, typename Base>
+    struct is_mpi_datatype<property<Tag, T, Base> >
+      : mpl::and_<is_mpi_datatype<T>,
+                  is_mpi_datatype<Base> > { };
+  }
+
+  namespace serialization {
+    template<typename Tag, typename T, typename Base>
+    struct is_bitwise_serializable<property<Tag, T, Base> >
+      : mpl::and_<is_bitwise_serializable<T>,
+                  is_bitwise_serializable<Base> > { };
+
+  template<typename Tag, typename T, typename Base>
+  struct implementation_level<property<Tag, T, Base>  >
+   : mpl::int_<object_serializable> {} ;
+
+  template<typename Tag, typename T, typename Base>
+  struct tracking_level<property<Tag, T, Base>  >
+   : mpl::int_<track_never> {} ;
+
+  }
+#endif // BOOST_GRAPH_USE_MPI
+  
 } // end namespace boost
 
+#ifdef BOOST_GRAPH_USE_MPI
+namespace boost { namespace mpi {
+    template<>
+    struct is_mpi_datatype<boost::no_property> : mpl::true_ { };
+
+} } // end namespace boost::mpi
+
+BOOST_IS_BITWISE_SERIALIZABLE(boost::no_property)
+BOOST_CLASS_IMPLEMENTATION(boost::no_property,object_serializable)
+BOOST_CLASS_TRACKING(boost::no_property,track_never)
+#endif // BOOST_GRAPH_USE_MPI
+
 #endif // BOOST_PROPERTY_SERIALIZE_HPP
Modified: trunk/libs/graph/build/Jamfile.v2
==============================================================================
--- trunk/libs/graph/build/Jamfile.v2	(original)
+++ trunk/libs/graph/build/Jamfile.v2	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -4,6 +4,8 @@
 # (See accompanying file LICENSE_1_0.txt or copy at
 # http://www.boost.org/LICENSE_1_0.txt)
 
+import mpi ;
+
 project boost/graph
     : requirements <include>../src
     : source-location ../src
@@ -43,10 +45,33 @@
 }
 explicit graphml ;
 
+if [ mpi.configured ]
+{
+  alias pbgl
+      : mpi_process_group.cpp tag_allocator.cpp
+      : # requirements
+        <library>../../mpi/build//boost_mpi
+        <library>/mpi//mpi [ mpi.extra-requirements ]
+      : # default built
+      : # usage requirements
+        <library>../../mpi/build//boost_mpi
+        <library>/mpi//mpi [ mpi.extra-requirements ]
+      ;
+}
+else
+{
+    message pbgl
+      : "warning: Graph library does not contain MPI-based parallel components."
+      : "note: to enable them, add \"using mpi ;\" to your user_config.jam"
+      ;
+}
+explicit graphml ;
+
 lib boost_graph
     :
     read_graphviz_spirit.cpp
     graphml
+    pbgl
     :
     <define>BOOST_GRAPH_NO_LIB=1
     <link>shared:<define>BOOST_GRAPH_DYN_LINK=1
@@ -57,4 +82,4 @@
     <toolset>msvc-8.0:<cxxflags>-GR-
     ;
 
-boost-install boost_graph ;
\ No newline at end of file
+boost-install boost_graph ;
Added: trunk/libs/graph/src/mpi_process_group.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/graph/src/mpi_process_group.cpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -0,0 +1,1108 @@
+// Copyright (C) 2004-2006 The Trustees of Indiana University.
+// Copyright (C) 2007  Douglas Gregor  <doug.gregor_at_[hidden]>
+// Copyright (C) 2007  Matthias Troyer  <troyer_at_[hidden]>
+
+// 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
+//           Matthias Troyer
+#include <boost/graph/use_mpi.hpp>
+#include <boost/graph/distributed/mpi_process_group.hpp>
+#include <boost/mpi/environment.hpp>
+#include <boost/lexical_cast.hpp>
+#include <memory>
+#include <algorithm>
+
+//#define DEBUG 1
+
+
+//#define MAX_BATCHES 1500
+#define PREALLOCATE_BATCHES 250  
+// 500 is a better setting for PREALLOCATE_BATCHES if you're not using process 
+// subgroups and are building 64-bit binaries.  250 allows all the CTest
+// tests to pass in both 32 and 64-bit modes.  If you create multiple process 
+// groups with PREALLOCATE_BATCHES at a reasonable level in 32-bit mode you 
+// _will_ run out of memory and get "malloc failed" errors
+
+//#define NO_ISEND_BATCHES
+//#define NO_IMMEDIATE_PROCESSING
+//#define NO_SPLIT_BATCHES
+#define IRECV_BATCH
+
+// we cannot keep track of how many we received if we do not process them
+#ifdef NO_IMMEDIATE_PROCESSING
+#undef IRECV_BATCH
+#endif
+
+#ifdef DEBUG
+#  include <iostream>
+#endif // DEBUG
+
+namespace boost { namespace graph { namespace distributed {
+
+struct mpi_process_group::deallocate_block
+{
+  explicit deallocate_block(blocks_type* blocks) : blocks(blocks) { }
+
+  void operator()(int* block_num)
+  {
+    block_type* block = (*blocks)[*block_num];
+
+    // Mark this block as inactive
+    (*blocks)[*block_num] = 0;
+
+#ifdef DEBUG
+    fprintf(stderr, "Processor %i deallocated block #%i\n", 
+            boost::mpi::communicator().rank(), *block_num);
+#endif
+
+    // Delete the block and its block number
+    delete block_num;
+    delete block;
+  }
+
+private:
+  blocks_type* blocks;
+};
+
+mpi_process_group::impl::incoming_messages::incoming_messages()
+{
+  next_header.push_back(headers.begin());
+}
+
+mpi_process_group::impl::impl(std::size_t num_headers, std::size_t buffer_sz, 
+                              communicator_type parent_comm)
+  : comm(parent_comm, boost::mpi::comm_duplicate),
+    oob_reply_comm(parent_comm, boost::mpi::comm_duplicate),
+    allocated_tags(boost::mpi::environment::max_tag())
+{
+  max_sent=0;
+  max_received=0;
+  int n = comm.size();
+  outgoing.resize(n);
+  incoming.resize(n);
+  
+  // no synchronization stage means -1
+  // to keep the convention
+  synchronizing_stage.resize(n,-1); 
+  number_sent_batches.resize(n);
+  number_received_batches.resize(n);
+  trigger_context = trc_none;
+  processing_batches = 0;
+  
+  // Allocator a placeholder block "0"
+  blocks.push_back(new block_type);
+
+  synchronizing = false;
+
+  set_batch_size(num_headers,buffer_sz);
+  
+  for (int i = 0; i < n; ++i) {
+    incoming[i].next_header.front() = incoming[i].headers.end();
+    outgoing[i].buffer.reserve(batch_message_size);
+  }
+
+#ifdef PREALLOCATE_BATCHES
+  batch_pool.resize(PREALLOCATE_BATCHES);
+  for (std::size_t i = 0 ; i < batch_pool.size(); ++i) {
+    batch_pool[i].buffer.reserve(batch_message_size);
+    batch_pool[i].request=MPI_REQUEST_NULL;
+    free_batches.push(i);
+  }  
+#endif
+}
+
+void mpi_process_group::impl::set_batch_size(std::size_t header_num, std::size_t buffer_sz)
+{
+  batch_header_number = header_num;
+  batch_buffer_size = buffer_sz;
+
+  // determine batch message size by serializing the largest possible batch
+  outgoing_messages msg;
+  msg.headers.resize(batch_header_number);
+  msg.buffer.resize(batch_buffer_size);
+  boost::mpi::packed_oarchive oa(comm);
+  oa << const_cast<const outgoing_messages&>(msg);
+  batch_message_size = oa.size();
+}
+
+
+mpi_process_group::impl::~impl()
+{
+  // Delete the placeholder "0" block
+  delete blocks.front();
+  if (!boost::mpi::environment::finalized()) 
+  for (std::vector<MPI_Request>::iterator it=requests.begin(); 
+       it != requests.end();++it)
+    MPI_Cancel(&(*it));
+}
+
+namespace detail {
+// global batch handlers
+void handle_batch (mpi_process_group const& self, int source, int, 
+    mpi_process_group::outgoing_messages& batch,bool out_of_band)
+{
+#ifdef DEBUG
+  std::cerr << "Processing batch trigger\n";
+  std::cerr << "BATCH: " << process_id(self) << " <- " << source << " ("
+            << batch.headers.size() << " headers, "
+            << batch.buffer.size() << " bytes)"
+            << std::endl;
+#endif
+  // If we are not synchronizing, then this must be an early receive
+  trigger_receive_context old_context = self.impl_->trigger_context;
+  if (self.impl_->trigger_context != trc_in_synchronization)
+    self.impl_->trigger_context = trc_early_receive;
+
+  // Receive the batched messages
+  self.receive_batch(source,batch);
+
+  // Restore the previous context
+  self.impl_->trigger_context = old_context;
+}
+
+// synchronization handler
+void handle_sync (mpi_process_group const& self, int source, int tag, int val,
+                  bool)
+{
+  // increment the stage for the source
+  std::size_t stage = static_cast<std::size_t>(
+    ++self.impl_->synchronizing_stage[source]);
+
+  assert(source != process_id(self));
+
+#ifdef DEBUG
+  std::ostringstream out;
+  out << process_id(self) << ": handle_sync from " << source 
+      << " (stage = " << self.impl_->synchronizing_stage[source] << ")\n";
+  std::cerr << out.str();
+#endif
+
+  // record how many still have messages to be sent
+  if (self.impl_->synchronizing_unfinished.size()<=stage) {
+    assert(self.impl_->synchronizing_unfinished.size() == stage);
+    self.impl_->synchronizing_unfinished.push_back(val >= 0 ? 1 : 0);
+  }
+  else
+    self.impl_->synchronizing_unfinished[stage]+=(val >= 0 ? 1 : 0);
+
+  // record how many are in that stage
+  if (self.impl_->processors_synchronizing_stage.size()<=stage) {
+    assert(self.impl_->processors_synchronizing_stage.size() == stage);
+    self.impl_->processors_synchronizing_stage.push_back(1);
+  }
+  else
+    ++self.impl_->processors_synchronizing_stage[stage];
+    
+  // subtract how many batches we were supposed to receive
+  if (val>0)
+    self.impl_->number_received_batches[source] -= val;
+}
+
+
+}
+
+mpi_process_group::mpi_process_group(communicator_type parent_comm)
+{
+  // 64K messages and 1MB buffer turned out to be a reasonable choice
+  impl_.reset(new impl(64*1024,1024*1024,parent_comm));
+#ifndef IRECV_BATCH
+  global_trigger<outgoing_messages>(msg_batch,&detail::handle_batch);
+#else // use irecv version by providing a maximum buffer size
+  global_trigger<outgoing_messages>(msg_batch,&detail::handle_batch,
+         impl_->batch_message_size);
+#endif
+  global_trigger<outgoing_messages>(msg_large_batch,&detail::handle_batch);
+  global_trigger<int>(msg_synchronizing,&detail::handle_sync);
+  rank = impl_->comm.rank();
+  size = impl_->comm.size();
+  
+#ifdef SEND_OOB_BSEND
+  // let us try with a default bufferr size of 16 MB
+  if (!message_buffer_size())
+    set_message_buffer_size(16*1024*1024);
+#endif
+}
+
+mpi_process_group::mpi_process_group(std::size_t h, std::size_t sz, 
+                                     communicator_type parent_comm)
+{
+  impl_.reset(new impl(h,sz,parent_comm));
+#ifndef IRECV_BATCH
+  global_trigger<outgoing_messages>(msg_batch,&detail::handle_batch);
+#else // use irecv version by providing a maximum buffer size
+  global_trigger<outgoing_messages>(msg_batch,&detail::handle_batch,
+         impl_->batch_message_size);
+#endif
+  global_trigger<outgoing_messages>(msg_large_batch,&detail::handle_batch);
+  global_trigger<int>(msg_synchronizing,&detail::handle_sync);
+  rank = impl_->comm.rank();
+  size = impl_->comm.size();
+#ifdef SEND_OOB_BSEND
+  // let us try with a default bufferr size of 16 MB
+  if (!message_buffer_size())
+    set_message_buffer_size(16*1024*1024);
+#endif
+}
+
+mpi_process_group::mpi_process_group(const mpi_process_group& other,
+                                     const receiver_type& handler, bool)
+  : impl_(other.impl_)
+{ 
+  rank = impl_->comm.rank();
+  size = impl_->comm.size();
+  replace_handler(handler); 
+}
+
+mpi_process_group::mpi_process_group(const mpi_process_group& other,
+                                     attach_distributed_object, bool)
+  : impl_(other.impl_)
+{ 
+  rank = impl_->comm.rank();
+  size = impl_->comm.size();
+  allocate_block();
+
+  for (std::size_t i = 0; i < impl_->incoming.size(); ++i) {
+    if (my_block_number() >= (int)impl_->incoming[i].next_header.size()) {
+      impl_->incoming[i].next_header
+        .push_back(impl_->incoming[i].headers.begin());
+    } else {
+      impl_->incoming[i].next_header[my_block_number()] =
+        impl_->incoming[i].headers.begin();
+    }
+
+#ifdef DEBUG
+    if (process_id(*this) == 0) {
+      std::cerr << "Allocated tag block " << my_block_number() << std::endl;
+    }
+#endif
+  }
+}
+
+mpi_process_group::~mpi_process_group()  {
+  /*
+  std::string msg = boost::lexical_cast<std::string>(process_id(*this)) + " " +
+            boost::lexical_cast<std::string>(impl_->max_received) + " " +
+            boost::lexical_cast<std::string>(impl_->max_sent) + "\n";
+     std::cerr << msg << "\n";
+     */
+}
+
+
+mpi_process_group::communicator_type communicator(const mpi_process_group& pg)
+{ return pg.impl_->comm; }
+
+void
+mpi_process_group::replace_handler(const receiver_type& handler,
+                                   bool out_of_band_receive)
+{
+  make_distributed_object();
+
+  // Attach the receive handler
+  impl_->blocks[my_block_number()]->on_receive = handler;
+}
+
+void
+mpi_process_group::make_distributed_object()
+{
+  if (my_block_number() == 0) {
+    allocate_block();
+
+    for (std::size_t i = 0; i < impl_->incoming.size(); ++i) {
+      if (my_block_number() >= (int)impl_->incoming[i].next_header.size()) {
+        impl_->incoming[i].next_header
+          .push_back(impl_->incoming[i].headers.begin());
+      } else {
+        impl_->incoming[i].next_header[my_block_number()] =
+          impl_->incoming[i].headers.begin();
+      }
+
+#ifdef DEBUG
+      if (process_id(*this) == 0) {
+        std::cerr << "Allocated tag block " << my_block_number() << std::endl;
+      }
+#endif
+    }
+  } else {
+    // Clear out the existing triggers
+    std::vector<shared_ptr<trigger_base> >()
+      .swap(impl_->blocks[my_block_number()]->triggers); 
+  }
+
+  // Clear out the receive handler
+  impl_->blocks[my_block_number()]->on_receive = 0;
+}
+
+void
+mpi_process_group::
+replace_on_synchronize_handler(const on_synchronize_event_type& handler)
+{
+  if (my_block_number() > 0)
+    impl_->blocks[my_block_number()]->on_synchronize = handler;
+}
+
+int mpi_process_group::allocate_block(bool out_of_band_receive)
+{
+  assert(!block_num);
+  block_iterator i = impl_->blocks.begin();
+  while (i != impl_->blocks.end() && *i) ++i;
+
+  if (i == impl_->blocks.end()) {
+    impl_->blocks.push_back(new block_type());
+    i = impl_->blocks.end() - 1;
+  } else {
+    *i = new block_type();
+  }
+
+  block_num.reset(new int(i - impl_->blocks.begin()),
+                  deallocate_block(&impl_->blocks));
+
+#ifdef DEBUG
+  fprintf(stderr,
+          "Processor %i allocated block #%i\n", process_id(*this), *block_num);
+#endif
+
+  return *block_num;
+}
+
+bool mpi_process_group::maybe_emit_receive(int process, int encoded_tag) const
+{
+  std::pair<int, int> decoded = decode_tag(encoded_tag);
+
+  assert (decoded.first < static_cast<int>(impl_->blocks.size()));
+
+  block_type* block = impl_->blocks[decoded.first];
+  if (!block) {
+    std::cerr << "Received message from process " << process << " with tag "
+              << decoded.second << " for non-active block "
+              << decoded.first << std::endl;
+    std::cerr << "Active blocks are: ";
+    for (std::size_t i = 0; i < impl_->blocks.size(); ++i)
+      if (impl_->blocks[i])
+        std::cerr << i << ' ';
+    std::cerr << std::endl;
+    assert(block);
+  }
+  
+  if (decoded.second < static_cast<int>(block->triggers.size())
+      && block->triggers[decoded.second]) {
+    // We have a trigger for this message; use it
+    trigger_receive_context old_context = impl_->trigger_context;
+    impl_->trigger_context = trc_out_of_band;
+    block->triggers[decoded.second]->receive(*this, process, decoded.second, 
+                                             impl_->trigger_context, 
+                                             decoded.first);
+    impl_->trigger_context = old_context;
+  }
+  else
+    return false;
+  // We receives the message above
+  return true;
+}
+
+bool mpi_process_group::emit_receive(int process, int encoded_tag) const
+{
+  std::pair<int, int> decoded = decode_tag(encoded_tag);
+
+  if (decoded.first >= static_cast<int>(impl_->blocks.size()))
+    // This must be an out-of-band message destined for
+    // send_oob_with_reply; ignore it.
+    return false;
+
+  // Find the block that will receive this message
+  block_type* block = impl_->blocks[decoded.first];
+  assert(block);
+  if (decoded.second < static_cast<int>(block->triggers.size())
+      && block->triggers[decoded.second])
+    // We have a trigger for this message; use it
+    block->triggers[decoded.second]->receive(*this,process, decoded.second, 
+                                             impl_->trigger_context);
+  else if (block->on_receive)
+    // Fall back to the normal message handler
+    block->on_receive(process, decoded.second);
+  else
+    // There was no handler for this message
+    return false;
+
+  // The message was handled above
+  return true;
+}
+
+void mpi_process_group::emit_on_synchronize() const
+{
+  for (block_iterator i = impl_->blocks.begin(); i != impl_->blocks.end(); ++i)
+    if (*i && (*i)->on_synchronize) (*i)->on_synchronize();
+}
+
+
+optional<std::pair<mpi_process_group::process_id_type, int> >
+mpi_process_group::probe() const
+{
+#ifdef DEBUG
+  std::cerr << "PROBE: " << process_id(*this) << ", tag block = "
+            << my_block_number() << std::endl;
+#endif
+
+  typedef std::pair<process_id_type, int> result_type;
+
+  int tag_block = my_block_number();
+
+  for (std::size_t source = 0; source < impl_->incoming.size(); ++source) {
+    impl::incoming_messages& incoming = impl_->incoming[source];
+    std::vector<impl::message_header>::iterator& i =
+      incoming.next_header[tag_block];
+    std::vector<impl::message_header>::iterator end =  incoming.headers.end();
+
+    while (i != end) {
+      if (i->tag != -1 && decode_tag(i->tag).first == my_block_number()) {
+#ifdef DEBUG
+        std::cerr << "PROBE: " << process_id(*this) << " <- " << source
+                  << ", block = " << my_block_number() << ", tag = "
+                  << decode_tag(i->tag).second << ", bytes = " << i->bytes
+                  << std::endl;
+#endif
+        return result_type(source, decode_tag(i->tag).second);
+      }
+      ++i;
+    }
+  }
+  return optional<result_type>();
+}
+
+void
+mpi_process_group::maybe_send_batch(process_id_type dest) const
+{
+#ifndef NO_SPLIT_BATCHES  
+  impl::outgoing_messages& outgoing = impl_->outgoing[dest];
+  if (outgoing.buffer.size() >= impl_->batch_buffer_size ||
+      outgoing.headers.size() >= impl_->batch_header_number) {
+    // we are full and need to send
+    outgoing_messages batch;
+    batch.buffer.reserve(impl_->batch_buffer_size);
+    batch.swap(outgoing);
+    if (batch.buffer.size() >= impl_->batch_buffer_size 
+         && batch.headers.size()>1 ) {
+      // we are too large, keep the last message in the outgoing buffer
+      std::copy(batch.buffer.begin()+batch.headers.back().offset,
+                batch.buffer.end(),std::back_inserter(outgoing.buffer));
+      batch.buffer.resize(batch.headers.back().offset);
+      outgoing.headers.push_back(batch.headers.back());
+      batch.headers.pop_back();
+      outgoing.headers.front().offset=0;
+    }
+    send_batch(dest,batch);
+  }
+#endif
+}
+
+void
+mpi_process_group::send_batch(process_id_type dest) const
+{
+  impl::outgoing_messages& outgoing = impl_->outgoing[dest];
+  if (outgoing.headers.size()) {
+    // need to copy to avoid race conditions
+    outgoing_messages batch;
+    batch.buffer.reserve(impl_->batch_buffer_size);
+    batch.swap(outgoing); 
+    send_batch(dest,batch);
+  }
+}
+
+
+void
+mpi_process_group::send_batch(process_id_type dest, 
+                              outgoing_messages& outgoing) const
+{
+  impl_->free_sent_batches();
+  process_id_type id = process_id(*this);
+
+  // clear the batch
+#ifdef DEBUG
+  std::cerr << "Sending batch: " << id << " -> "  << dest << std::endl;
+#endif
+  // we increment the number of batches sent
+  ++impl_->number_sent_batches[dest];
+  // and send the batch
+  assert(outgoing.headers.size() <= impl_->batch_header_number);
+  if (id != dest) {
+#ifdef NO_ISEND_BATCHES
+    impl::batch_request req;
+#else
+#ifdef PREALLOCATE_BATCHES
+    while (impl_->free_batches.empty()) {
+      impl_->free_sent_batches();
+      poll();
+    }
+    impl::batch_request& req = impl_->batch_pool[impl_->free_batches.top()];
+    impl_->free_batches.pop();
+#else
+    impl_->sent_batches.push_back(impl::batch_request());
+    impl::batch_request& req = impl_->sent_batches.back();
+#endif
+#endif
+    boost::mpi::packed_oarchive oa(impl_->comm,req.buffer);
+    oa << outgoing;
+
+    int tag = msg_batch;
+    
+#ifdef IRECV_BATCH
+    if (oa.size() > impl_->batch_message_size)
+      tag = msg_large_batch;
+#endif
+
+    int result = MPI_Isend(const_cast<void*>(oa.address()), oa.size(),
+                       MPI_PACKED, dest, tag, impl_->comm,
+                       &req.request);
+    assert(result == MPI_SUCCESS);
+    impl_->max_sent = (std::max)(impl_->max_sent,impl_->sent_batches.size());
+#ifdef NO_ISEND_BATCHES
+    int done=0;
+    do {                                                        
+        poll();                                                
+        MPI_Test(&req.request,&done,MPI_STATUS_IGNORE);               
+       } while (!done);                                            
+#else
+#ifdef MAX_BATCHES
+    while (impl_->sent_batches.size() >= MAX_BATCHES-1) {
+      impl_->free_sent_batches();
+      poll();
+    }
+#endif
+#endif
+  }
+  else
+    receive_batch(id,outgoing);
+}
+
+void mpi_process_group::process_batch(int source) const
+{
+  bool processing_from_queue = !impl_->new_batches.empty();
+  impl_->processing_batches++;
+  typedef std::vector<impl::message_header>::iterator iterator;
+
+  impl::incoming_messages& incoming = impl_->incoming[source];
+  
+  // Set up the iterators pointing to the next header in each block
+  for (std::size_t i = 0; i < incoming.next_header.size(); ++i)
+        incoming.next_header[i] = incoming.headers.begin();
+
+  buffer_type remaining_buffer;
+  std::vector<impl::message_header> remaining_headers;
+
+  iterator end = incoming.headers.end();
+
+  for (iterator i = incoming.headers.begin(); i != end; ++i) {
+    // This this message has already been received, skip it
+    if (i->tag == -1)
+      continue;
+
+#ifdef BATCH_DEBUG
+    std::cerr << process_id(*this) << ": emit_receive(" << source << ", "
+              << decode_tag(i->tag).first << ":" << decode_tag(i->tag).second
+              << ")\n";
+#endif
+
+    if (!emit_receive(source, i->tag)) {
+#ifdef BATCH_DEBUG
+      std::cerr << process_id(*this) << ": keeping message # " 
+            << remaining_headers.size() << " from " << source << " ("
+            << decode_tag(i->tag).first << ":" 
+            << decode_tag(i->tag).second << ", " 
+            << i->bytes << " bytes)\n";
+#endif
+      // Hold on to this message until the next stage
+      remaining_headers.push_back(*i);
+      remaining_headers.back().offset = remaining_buffer.size();
+      remaining_buffer.insert(remaining_buffer.end(),
+                  &incoming.buffer[i->offset],
+                  &incoming.buffer[i->offset] + i->bytes);
+    }
+  }
+
+  // Swap the remaining messages into the "incoming" set.
+  incoming.headers.swap(remaining_headers);
+  incoming.buffer.swap(remaining_buffer);
+
+  // Set up the iterators pointing to the next header in each block
+  for (std::size_t i = 0; i < incoming.next_header.size(); ++i)
+    incoming.next_header[i] = incoming.headers.begin();
+  impl_->processing_batches--;
+  
+  if (!processing_from_queue)
+    while (!impl_->new_batches.empty()) {
+      receive_batch(impl_->new_batches.front().first,
+                    impl_->new_batches.front().second);
+      impl_->new_batches.pop();
+    }
+}
+
+
+void mpi_process_group::receive_batch(process_id_type source, 
+  outgoing_messages& new_messages) const
+{
+  impl_->free_sent_batches();
+  if(!impl_->processing_batches) {
+    // increase the number of received batches
+    ++impl_->number_received_batches[source];
+    // and receive the batch
+    impl::incoming_messages& incoming = impl_->incoming[source];
+    typedef std::vector<impl::message_header>::iterator iterator;
+    iterator end = new_messages.headers.end();
+    for (iterator i = new_messages.headers.begin(); i != end; ++i) {
+      incoming.headers.push_back(*i);
+      incoming.headers.back().offset = incoming.buffer.size();
+      incoming.buffer.insert(incoming.buffer.end(),
+                  &new_messages.buffer[i->offset],
+                  &new_messages.buffer[i->offset] + i->bytes);
+    }
+    // Set up the iterators pointing to the next header in each block
+    for (std::size_t i = 0; i < incoming.next_header.size(); ++i)
+      incoming.next_header[i] = incoming.headers.begin();
+#ifndef NO_IMMEDIATE_PROCESSING
+    process_batch(source);
+#endif
+  }
+  else {
+  #ifdef DEBUG
+    std::cerr << "Pushing incoming message batch onto queue since we are already processing a batch.\n";
+  #endif
+    // use swap to avoid copying
+    impl_->new_batches.push(std::make_pair(int(source),outgoing_messages()));
+    impl_->new_batches.back().second.swap(new_messages);
+    impl_->max_received = (std::max)(impl_->max_received,impl_->new_batches.size());
+  }
+}
+
+
+void mpi_process_group::pack_headers() const 
+{
+  for (process_id_type other = 0; other < num_processes(*this); ++other) {
+    typedef std::vector<impl::message_header>::iterator iterator;
+
+    impl::incoming_messages& incoming = impl_->incoming[other];
+
+    buffer_type remaining_buffer;
+    std::vector<impl::message_header> remaining_headers;
+
+    iterator end = incoming.headers.end();
+    for (iterator i = incoming.headers.begin(); i != end; ++i) {
+      if (i->tag == -1)
+        continue;
+
+      // Hold on to this message until the next stage
+      remaining_headers.push_back(*i);
+      remaining_headers.back().offset = remaining_buffer.size();
+      remaining_buffer.insert(remaining_buffer.end(),
+                              &incoming.buffer[i->offset],
+                              &incoming.buffer[i->offset] + i->bytes);
+    }
+    
+    // Swap the remaining messages into the "incoming" set.
+    incoming.headers.swap(remaining_headers);
+    incoming.buffer.swap(remaining_buffer);
+
+    // Set up the iterators pointing to the next header in each block
+    for (std::size_t i = 0; i < incoming.next_header.size(); ++i)
+      incoming.next_header[i] = incoming.headers.begin();
+  }
+}
+
+void mpi_process_group::receive_batch(boost::mpi::status& status) const
+{
+  //std::cerr << "Handling batch\n";
+  outgoing_messages batch;
+  //impl_->comm.recv(status.source(),status.tag(),batch);
+
+  //receive_oob(*this,status.source(),msg_batch,batch);
+    
+  // Determine how big the receive buffer should be
+#if BOOST_VERSION >= 103600
+  int size = status.count<boost::mpi::packed>().get();
+#else
+  int size;
+  MPI_Status mpi_status(status);
+  MPI_Get_count(&mpi_status, MPI_PACKED, &size);
+#endif
+
+  // Allocate the receive buffer
+  boost::mpi::packed_iarchive in(impl_->comm,size);
+  
+  // Receive the message data
+  MPI_Recv(in.address(), size, MPI_PACKED,
+           status.source(), status.tag(), 
+           impl_->comm, MPI_STATUS_IGNORE);
+
+  // Unpack the message data
+  in >> batch;
+  receive_batch(status.source(),batch);
+}
+
+std::pair<boost::mpi::communicator, int> 
+mpi_process_group::actual_communicator_and_tag(int tag, int block) const
+{
+  if (tag >= max_tags * static_cast<int>(impl_->blocks.size()))
+    // Use the out-of-band reply communicator
+    return std::make_pair(impl_->oob_reply_comm, tag);
+  else
+    // Use the normal communicator and translate the tag
+    return std::make_pair(impl_->comm, 
+                          encode_tag(block == -1? my_block_number() : block,
+                                     tag));
+}
+
+
+void mpi_process_group::synchronize() const
+{
+  // Don't synchronize if we've already finished
+  if (boost::mpi::environment::finalized()) 
+    return;
+
+#ifdef DEBUG
+  std::cerr << "SYNC: " << process_id(*this) << std::endl;
+#endif
+
+  emit_on_synchronize();
+
+  process_id_type id = process_id(*this);     // Our rank
+  process_size_type p = num_processes(*this); // The number of processes
+
+  // Pack the remaining incoming messages into the beginning of the
+  // buffers, so that we can receive new messages in this
+  // synchronization step without losing those messages that have not
+  // yet been received.
+  pack_headers();
+
+  impl_->synchronizing_stage[id] = -1;
+  int stage=-1;
+  bool no_new_messages = false;
+  while (true) {
+      ++stage;
+#ifdef DEBUG
+      std::cerr << "SYNC: " << id << " starting stage " << (stage+1) << ".\n";
+#endif
+
+      // Tell everyone that we are synchronizing. Note: we use MPI_Isend since 
+      // we absolutely cannot have any of these operations blocking.
+      
+      // increment the stage for the source
+       ++impl_->synchronizing_stage[id];
+       if (impl_->synchronizing_stage[id] != stage)
+         std::cerr << "Expected stage " << stage << ", got " << impl_->synchronizing_stage[id] << std::endl;
+       assert(impl_->synchronizing_stage[id]==stage);
+      // record how many still have messages to be sent
+      if (static_cast<int>(impl_->synchronizing_unfinished.size())<=stage) {
+        assert(static_cast<int>(impl_->synchronizing_unfinished.size()) == stage);
+        impl_->synchronizing_unfinished.push_back(no_new_messages ? 0 : 1);
+      }
+      else
+        impl_->synchronizing_unfinished[stage]+=(no_new_messages ? 0 : 1);
+
+      // record how many are in that stage
+      if (static_cast<int>(impl_->processors_synchronizing_stage.size())<=stage) {
+        assert(static_cast<int>(impl_->processors_synchronizing_stage.size()) == stage);
+        impl_->processors_synchronizing_stage.push_back(1);
+      }
+      else
+        ++impl_->processors_synchronizing_stage[stage];
+
+      impl_->synchronizing = true;
+
+      for (int dest = 0; dest < p; ++dest) {
+        int sync_message = no_new_messages ? -1 : impl_->number_sent_batches[dest];
+        if (dest != id) {
+          impl_->number_sent_batches[dest]=0;       
+          MPI_Request request;
+          MPI_Isend(&sync_message, 1, MPI_INT, dest, msg_synchronizing, impl_->comm,&request);
+          int done=0;
+          do {
+            poll();
+            MPI_Test(&request,&done,MPI_STATUS_IGNORE);
+          } while (!done);
+        }
+        else { // need to subtract how many messages I should have received
+          impl_->number_received_batches[id] -=impl_->number_sent_batches[id];
+          impl_->number_sent_batches[id]=0;
+        }
+      }
+
+      // Keep handling out-of-band messages until everyone has gotten
+      // to this point.
+      while (impl_->processors_synchronizing_stage[stage] <p) {
+        // with the trigger based solution we cannot easily pass true here 
+        poll(/*wait=*/false, -1, true);
+
+      }
+
+      // check that everyone is at least here
+      for (int source=0; source<p ; ++source)
+        assert(impl_->synchronizing_stage[source] >= stage);
+
+      // receive any batches sent in the meantime
+      // all have to be available already
+      while (true) {
+        bool done=true;
+        for (int source=0; source<p ; ++source)
+          if(impl_->number_received_batches[source] < 0)
+            done = false;
+        if (done)
+          break;
+        poll(false,-1,true);
+      }
+      
+#ifndef NO_IMMEDIATE_PROCESSING
+      for (int source=0; source<p ; ++source)
+        assert(impl_->number_received_batches[source] >= 0);
+#endif
+
+      impl_->synchronizing = false;
+      
+      // Flush out remaining messages
+      if (impl_->synchronizing_unfinished[stage]==0)
+        break;
+#ifdef NO_IMMEDIATE_PROCESSING
+      for (process_id_type dest = 0; dest < p; ++dest)
+        process_batch(dest);
+#endif
+
+      no_new_messages = true;
+      for (process_id_type dest = 0; dest < p; ++dest) {
+        if (impl_->outgoing[dest].headers.size() || 
+            impl_->number_sent_batches[dest]>0)
+          no_new_messages = false;
+        send_batch(dest);
+      }
+    }
+
+  impl_->comm.barrier/*nomacro*/();
+#if 0
+  // set up for next synchronize call
+  for (int source=0; source<p; ++source) {
+    if (impl_->synchronizing_stage[source] != stage) {
+      std::cerr << id << ": expecting stage " << stage << " from source "
+                << source << ", got " << impl_->synchronizing_stage[source]
+                << std::endl;
+    }
+    assert(impl_->synchronizing_stage[source]==stage);
+  }
+#endif
+  std::fill(impl_->synchronizing_stage.begin(),
+            impl_->synchronizing_stage.end(), -1);
+            
+  // get rid of the information regarding recorded numbers of processors
+  // for the stages we just finished
+  impl_->processors_synchronizing_stage.clear();
+  impl_->synchronizing_unfinished.clear();
+
+  for (process_id_type dest = 0; dest < p; ++dest)
+    assert (impl_->outgoing[dest].headers.empty());
+#ifndef NO_IMMEDIATE_PROCESSING
+      for (int source=0; source<p ; ++source)
+        assert (impl_->number_received_batches[source] == 0);
+#endif
+
+  impl_->free_sent_batches();
+#ifdef DEBUG
+  std::cerr << "SYNC: " << process_id(*this) << " completed." << std::endl;
+#endif
+}
+
+optional<std::pair<mpi_process_group::process_id_type, int> >
+probe(const mpi_process_group& pg)
+{ return pg.probe(); }
+
+void mpi_process_group::poll_requests(int block) const
+{
+  int size = impl_->requests.size();
+  if (size==0)
+    return;
+  std::vector<MPI_Status> statuses(size);
+  std::vector<int> indices(size);
+  
+  while (true) {
+    MPI_Testsome(impl_->requests.size(),&impl_->requests[0],
+       &size,&indices[0],&statuses[0]);
+    if (size==0)
+      return; // no message waiting
+
+    // remove handled requests before we get the chance to be recursively called
+    if (size) {
+      std::vector<MPI_Request> active_requests;
+      std::size_t i=0;
+      int j=0;
+      for (;i< impl_->requests.size() && j< size; ++i) {
+        if (int(i)==indices[j])
+          // release the dealt-with request 
+          ++j;
+        else // copy and keep the request
+          active_requests.push_back(impl_->requests[i]);
+      }    
+      while (i < impl_->requests.size())
+        active_requests.push_back(impl_->requests[i++]);
+      impl_->requests.swap(active_requests);
+    }
+
+    optional<std::pair<int, int> > result;
+    for (int i=0;i < size; ++i) {
+      std::pair<int, int> decoded = decode_tag(statuses[i].MPI_TAG);
+      block_type* block = impl_->blocks[decoded.first];
+      
+      assert (decoded.second < static_cast<int>(block->triggers.size()) && block->triggers[decoded.second]);
+        // We have a trigger for this message; use it
+      trigger_receive_context old_context = impl_->trigger_context;
+      impl_->trigger_context = trc_irecv_out_of_band;
+      block->triggers[decoded.second]->receive(*this, statuses[i].MPI_SOURCE, 
+            decoded.second, impl_->trigger_context, decoded.first);
+      impl_->trigger_context = old_context;
+    }
+  }
+}
+
+
+optional<std::pair<int, int> > 
+mpi_process_group::
+poll(bool wait, int block, bool synchronizing) const
+{
+  // Set the new trigger context for these receive operations
+  trigger_receive_context old_context = impl_->trigger_context;
+  if (synchronizing)
+    impl_->trigger_context = trc_in_synchronization;
+  else
+    impl_->trigger_context = trc_out_of_band;
+
+  //wait = false;
+  optional<boost::mpi::status> status;
+  bool finished=false;
+  optional<std::pair<int, int> > result;
+  do {
+    poll_requests(block);
+    // Check for any messages not yet received.
+#ifdef PBGL_PROCESS_GROUP_NO_IRECV
+    if (wait)
+      status = impl_->comm.probe();
+    else 
+#endif
+       status = impl_->comm.iprobe();
+
+    if (status) { // we have a message
+      // Decode the message
+      std::pair<int, int> decoded = decode_tag(status.get().tag());
+      if (maybe_emit_receive(status.get().source(), status.get().tag()))
+        // We received the message out-of-band; poll again
+        finished = false;
+      else if (decoded.first == (block == -1 ? my_block_number() : block)) {
+        // This message is for us, but not through a trigger. Return
+        // the decoded message.
+        result = std::make_pair(status.get().source(), decoded.second);
+      // otherwise we didn't match any message we know how to deal with, so
+      // pretend no message exists.
+        finished = true;
+      }
+    }
+    else
+      // We don't have a message to process; we're done.
+      finished=!wait;
+  } while (!finished);
+
+  // Restore the prior trigger context
+  impl_->trigger_context = old_context;
+  poll_requests(block);
+  return result;
+}
+
+void synchronize(const mpi_process_group& pg) { pg.synchronize(); }
+
+mpi_process_group mpi_process_group::base() const
+{
+  mpi_process_group copy(*this);
+  copy.block_num.reset();
+  return copy;
+}
+  
+
+void mpi_process_group::impl::free_sent_batches()
+{
+  typedef std::list<batch_request>::iterator iterator;
+  iterator it = sent_batches.begin();
+  int flag;
+  int result;
+  while(it != sent_batches.end()) {
+    result = MPI_Test(&it->request,&flag,MPI_STATUS_IGNORE);
+    assert(result == MPI_SUCCESS);
+    iterator next=it;
+    ++next;
+    if (flag)
+      sent_batches.erase(it);
+    it=next;
+  }  
+#ifdef PREALLOCATE_BATCHES
+  for (std::size_t i=0; i< batch_pool.size();++i) {
+    if(batch_pool[i].request != MPI_REQUEST_NULL) {
+      result = MPI_Test(&batch_pool[i].request,&flag,MPI_STATUS_IGNORE);
+      assert(result == MPI_SUCCESS);
+      if (flag) {
+        free_batches.push(i);
+        batch_pool[i].request = MPI_REQUEST_NULL;
+        batch_pool[i].buffer.resize(0);
+      }
+    }
+  } 
+#endif
+}
+
+void 
+mpi_process_group::install_trigger(int tag, int block, 
+      shared_ptr<trigger_base> const& launcher)
+{
+  block_type* my_block = impl_->blocks[block];
+  assert(my_block);
+
+  // Make sure we have enough space in the structure for this trigger.
+  if (launcher->tag() >= static_cast<int>(my_block->triggers.size()))
+    my_block->triggers.resize(launcher->tag() + 1);
+
+  // If someone already put a trigger in this spot, we have a big
+  // problem.
+  if (my_block->triggers[launcher->tag()]) {
+    std::cerr << "Block " << my_block_number() 
+              << " already has a trigger for tag " << launcher->tag()
+              << std::endl;
+  }
+  assert(!my_block->triggers[launcher->tag()]);
+
+  // Attach a new trigger launcher
+  my_block->triggers[launcher->tag()] = launcher;
+}
+
+std::size_t mpi_process_group::message_buffer_size()
+{
+  return message_buffer.size();
+}
+
+
+void mpi_process_group::set_message_buffer_size(std::size_t s)
+{
+  int sz;
+  void* ptr;
+  if (!message_buffer.empty()) {
+    MPI_Buffer_detach(&ptr,&sz);
+    assert(ptr == &message_buffer.front());
+    assert(static_cast<std::size_t>(sz)  == message_buffer.size());
+  }
+  else if (old_buffer != 0)
+    MPI_Buffer_detach(&old_buffer,&old_buffer_size);
+  message_buffer.resize(s);
+  if (s)
+    MPI_Buffer_attach(&message_buffer.front(), message_buffer.size());
+  else if (old_buffer_size)
+    MPI_Buffer_attach(old_buffer, old_buffer_size);
+}
+
+
+std::vector<char> mpi_process_group::message_buffer;
+int mpi_process_group::old_buffer_size=0;
+void* mpi_process_group::old_buffer=0;
+
+} } } // end namespace boost::graph::distributed
Added: trunk/libs/graph/src/tag_allocator.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/graph/src/tag_allocator.cpp	2009-04-09 17:10:55 EDT (Thu, 09 Apr 2009)
@@ -0,0 +1,45 @@
+// Copyright (C) 2007  Douglas Gregor  <doug.gregor_at_[hidden]>
+
+// 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)
+#include <boost/graph/use_mpi.hpp>
+#include <boost/graph/distributed/detail/tag_allocator.hpp>
+
+namespace boost { namespace graph { namespace distributed { namespace detail {
+
+tag_allocator::token tag_allocator::get_tag() 
+{
+  int tag;
+
+  if (!freed.empty()) {
+    // Grab the tag at the top of the stack.
+    tag = freed.back();
+    freed.pop_back();
+  } else
+    // Grab the bottom tag and move the bottom down
+    tag = bottom--;
+
+  return token(this, tag);
+}
+
+tag_allocator::token::token(const token& other)
+  : allocator(other.allocator), tag_(other.tag_)
+{
+  // other no longer owns this tag
+  other.tag_ = -1;
+}
+
+tag_allocator::token::~token()
+{
+  if (tag_ != -1) {
+    if (tag_ == allocator->bottom + 1)
+      // This is the bottommost tag: just bump up the bottom
+      ++allocator->bottom;
+    else
+      // This tag isn't the bottom, so push it only the freed stack
+      allocator->freed.push_back(tag_);
+  }
+}
+
+} } } } // end namespace boost::graph::distributed::detail