Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:37:14

0001 // Copyright (C) 2004-2006 The Trustees of Indiana University.
0002 // Copyright (C) 2007 Douglas Gregor 
0003 
0004 // Use, modification and distribution is subject to the Boost Software
0005 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
0006 // http://www.boost.org/LICENSE_1_0.txt)
0007 
0008 //  Authors: Douglas Gregor
0009 //           Andrew Lumsdaine
0010 
0011 #ifndef BOOST_GRAPH_DISTRIBUTED_ADJACENCY_LIST_HPP
0012 #define BOOST_GRAPH_DISTRIBUTED_ADJACENCY_LIST_HPP
0013 
0014 #ifndef BOOST_GRAPH_USE_MPI
0015 #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
0016 #endif
0017 
0018 #include <boost/core/uncaught_exceptions.hpp>
0019 #include <boost/graph/adjacency_list.hpp>
0020 #include <boost/graph/properties.hpp>
0021 #include <boost/graph/graph_traits.hpp>
0022 #include <boost/graph/iteration_macros.hpp>
0023 #include <boost/graph/distributed/concepts.hpp>
0024 #include <boost/iterator/transform_iterator.hpp>
0025 #include <boost/property_map/property_map.hpp>
0026 #include <boost/property_map/parallel/parallel_property_maps.hpp>
0027 #include <boost/graph/adjacency_iterator.hpp>
0028 #include <boost/property_map/parallel/distributed_property_map.hpp>
0029 #include <boost/property_map/parallel/local_property_map.hpp>
0030 #include <boost/graph/parallel/detail/property_holders.hpp>
0031 #include <boost/mpl/if.hpp>
0032 #include <boost/type_traits/is_same.hpp>
0033 #include <boost/assert.hpp>
0034 #include <list>
0035 #include <iterator>
0036 #include <algorithm>
0037 #include <boost/limits.hpp>
0038 #include <boost/graph/parallel/properties.hpp>
0039 #include <boost/graph/parallel/distribution.hpp>
0040 #include <boost/graph/parallel/algorithm.hpp>
0041 #include <boost/graph/distributed/selector.hpp>
0042 #include <boost/graph/parallel/process_group.hpp>
0043 #include <boost/pending/container_traits.hpp>
0044 
0045 // Callbacks
0046 #include <boost/function/function2.hpp>
0047 
0048 // Serialization
0049 #include <boost/serialization/base_object.hpp>
0050 #include <boost/mpi/datatype.hpp>
0051 #include <boost/pending/property_serialize.hpp>
0052 #include <boost/graph/distributed/unsafe_serialize.hpp>
0053 
0054 // Named vertices
0055 #include <boost/graph/distributed/named_graph.hpp>
0056 
0057 #include <boost/graph/distributed/shuffled_distribution.hpp>
0058 
0059 namespace boost {
0060 
0061   /// The type used to store an identifier that uniquely names a processor.
0062   // NGE: I doubt we'll be running on more than 32768 procs for the time being
0063   typedef /*int*/ short processor_id_type;
0064 
0065   // Tell which processor the target of an edge resides on (for
0066   // directed graphs) or which processor the other end point of the
0067   // edge resides on (for undirected graphs).
0068   enum edge_target_processor_id_t { edge_target_processor_id };
0069   BOOST_INSTALL_PROPERTY(edge, target_processor_id);
0070 
0071   // For undirected graphs, tells whether the edge is locally owned.
0072   enum edge_locally_owned_t { edge_locally_owned };
0073   BOOST_INSTALL_PROPERTY(edge, locally_owned);
0074 
0075   // For bidirectional graphs, stores the incoming edges.
0076   enum vertex_in_edges_t { vertex_in_edges };
0077   BOOST_INSTALL_PROPERTY(vertex, in_edges);
0078 
0079   /// Tag class for directed, distributed adjacency list
0080   struct directed_distributed_adj_list_tag
0081     : public virtual distributed_graph_tag,
0082       public virtual distributed_vertex_list_graph_tag,
0083       public virtual distributed_edge_list_graph_tag,
0084       public virtual incidence_graph_tag,
0085       public virtual adjacency_graph_tag {};
0086 
0087   /// Tag class for bidirectional, distributed adjacency list
0088   struct bidirectional_distributed_adj_list_tag
0089     : public virtual distributed_graph_tag,
0090       public virtual distributed_vertex_list_graph_tag,
0091       public virtual distributed_edge_list_graph_tag,
0092       public virtual incidence_graph_tag,
0093       public virtual adjacency_graph_tag,
0094       public virtual bidirectional_graph_tag {};
0095 
0096   /// Tag class for undirected, distributed adjacency list
0097   struct undirected_distributed_adj_list_tag
0098     : public virtual distributed_graph_tag,
0099       public virtual distributed_vertex_list_graph_tag,
0100       public virtual distributed_edge_list_graph_tag,
0101       public virtual incidence_graph_tag,
0102       public virtual adjacency_graph_tag,
0103       public virtual bidirectional_graph_tag {};
0104 
0105   namespace detail {
0106     template<typename Archiver, typename Directed, typename Vertex>
0107     void
0108     serialize(Archiver& ar, edge_base<Directed, Vertex>& e,
0109               const unsigned int /*version*/)
0110     {
0111       ar & unsafe_serialize(e.m_source)
0112          & unsafe_serialize(e.m_target);
0113     }
0114 
0115     template<typename Archiver, typename Directed, typename Vertex>
0116     void
0117     serialize(Archiver& ar, edge_desc_impl<Directed, Vertex>& e,
0118               const unsigned int /*version*/)
0119     {
0120       ar & boost::serialization::base_object<edge_base<Directed, Vertex> >(e)
0121          & unsafe_serialize(e.m_eproperty);
0122     }
0123   }
0124 
0125   namespace detail { namespace parallel {
0126   
0127     /**
0128      * A distributed vertex descriptor. These descriptors contain both
0129      * the ID of the processor that owns the vertex and a local vertex
0130      * descriptor that identifies the particular vertex for that
0131      * processor.
0132      */
0133     template<typename LocalDescriptor>
0134     struct global_descriptor
0135     {
0136       typedef LocalDescriptor local_descriptor_type;
0137 
0138       global_descriptor() : owner(), local() { }
0139 
0140       global_descriptor(processor_id_type owner, LocalDescriptor local)
0141         : owner(owner), local(local) { }
0142 
0143       processor_id_type owner;
0144       LocalDescriptor local;
0145 
0146       /**
0147        * A function object that, given a processor ID, generates
0148        * distributed vertex descriptors from local vertex
0149        * descriptors. This function object is used by the
0150        * vertex_iterator of the distributed adjacency list.
0151        */
0152       struct generator
0153       {
0154         typedef global_descriptor<LocalDescriptor> result_type;
0155         typedef LocalDescriptor argument_type;
0156 
0157         generator() {}
0158         generator(processor_id_type owner) : owner(owner) {}
0159 
0160         result_type operator()(argument_type v) const
0161         { return result_type(owner, v); }
0162 
0163       private:
0164         processor_id_type owner;
0165       };
0166 
0167       template<typename Archiver>
0168       void serialize(Archiver& ar, const unsigned int /*version*/)
0169       {
0170         ar & owner & unsafe_serialize(local);
0171       }
0172     };
0173 
0174     /// Determine the process that owns the given descriptor
0175     template<typename LocalDescriptor>
0176     inline processor_id_type owner(const global_descriptor<LocalDescriptor>& v)
0177     { return v.owner; }
0178 
0179     /// Determine the local portion of the given descriptor
0180     template<typename LocalDescriptor>
0181     inline LocalDescriptor local(const global_descriptor<LocalDescriptor>& v)
0182     { return v.local; }
0183 
0184     /// Compare distributed vertex descriptors for equality
0185     template<typename LocalDescriptor>
0186     inline bool
0187     operator==(const global_descriptor<LocalDescriptor>& u,
0188                const global_descriptor<LocalDescriptor>& v)
0189     {
0190       return u.owner == v.owner && u.local == v.local;
0191     }
0192 
0193     /// Compare distributed vertex descriptors for inequality
0194     template<typename LocalDescriptor>
0195     inline bool
0196     operator!=(const global_descriptor<LocalDescriptor>& u,
0197                const global_descriptor<LocalDescriptor>& v)
0198     { return !(u == v); }
0199 
0200     template<typename LocalDescriptor>
0201     inline bool
0202     operator<(const global_descriptor<LocalDescriptor>& u,
0203               const global_descriptor<LocalDescriptor>& v)
0204     {
0205       return (u.owner) < v.owner || (u.owner == v.owner && (u.local) < v.local);
0206     }
0207 
0208     template<typename LocalDescriptor>
0209     inline bool
0210     operator<=(const global_descriptor<LocalDescriptor>& u,
0211                const global_descriptor<LocalDescriptor>& v)
0212     {
0213       return u.owner <= v.owner || (u.owner == v.owner && u.local <= v.local);
0214     }
0215 
0216     template<typename LocalDescriptor>
0217     inline bool
0218     operator>(const global_descriptor<LocalDescriptor>& u,
0219               const global_descriptor<LocalDescriptor>& v)
0220     {
0221       return v < u;
0222     }
0223 
0224     template<typename LocalDescriptor>
0225     inline bool
0226     operator>=(const global_descriptor<LocalDescriptor>& u,
0227                const global_descriptor<LocalDescriptor>& v)
0228     {
0229       return v <= u;
0230     }
0231 
0232     // DPG TBD: Add <, <=, >=, > for global descriptors
0233 
0234     /**
0235      * A Readable Property Map that extracts a global descriptor pair
0236      * from a global_descriptor.
0237      */
0238     template<typename LocalDescriptor>
0239     struct global_descriptor_property_map
0240     {
0241       typedef std::pair<processor_id_type, LocalDescriptor> value_type;
0242       typedef value_type reference;
0243       typedef global_descriptor<LocalDescriptor> key_type;
0244       typedef readable_property_map_tag category;
0245     };
0246 
0247     template<typename LocalDescriptor>
0248     inline std::pair<processor_id_type, LocalDescriptor>
0249     get(global_descriptor_property_map<LocalDescriptor>,
0250         global_descriptor<LocalDescriptor> x)
0251     {
0252       return std::pair<processor_id_type, LocalDescriptor>(x.owner, x.local);
0253     }
0254 
0255     /**
0256      * A Readable Property Map that extracts the owner of a global
0257      * descriptor.
0258      */
0259     template<typename LocalDescriptor>
0260     struct owner_property_map
0261     {
0262       typedef processor_id_type value_type;
0263       typedef value_type reference;
0264       typedef global_descriptor<LocalDescriptor> key_type;
0265       typedef readable_property_map_tag category;
0266     };
0267 
0268     template<typename LocalDescriptor>
0269     inline processor_id_type
0270     get(owner_property_map<LocalDescriptor>,
0271         global_descriptor<LocalDescriptor> x)
0272     {
0273       return x.owner;
0274     }
0275 
0276     /**
0277      * A Readable Property Map that extracts the local descriptor from
0278      * a global descriptor.
0279      */
0280     template<typename LocalDescriptor>
0281     struct local_descriptor_property_map
0282     {
0283       typedef LocalDescriptor value_type;
0284       typedef value_type reference;
0285       typedef global_descriptor<LocalDescriptor> key_type;
0286       typedef readable_property_map_tag category;
0287     };
0288 
0289     template<typename LocalDescriptor>
0290     inline LocalDescriptor
0291     get(local_descriptor_property_map<LocalDescriptor>,
0292         global_descriptor<LocalDescriptor> x)
0293     {
0294       return x.local;
0295     }
0296 
0297     /**
0298      * Stores an incoming edge for a bidirectional distributed
0299      * adjacency list. The user does not see this type directly,
0300      * because it is just an implementation detail.
0301      */
0302     template<typename Edge>
0303     struct stored_in_edge
0304     {
0305       stored_in_edge(processor_id_type sp, Edge e)
0306         : source_processor(sp), e(e) {}
0307 
0308       processor_id_type source_processor;
0309       Edge e;
0310     };
0311 
0312     /**
0313      * A distributed edge descriptor. These descriptors contain the
0314      * underlying edge descriptor, the processor IDs for both the
0315      * source and the target of the edge, and a boolean flag that
0316      * indicates which of the processors actually owns the edge.
0317      */
0318     template<typename Edge>
0319     struct edge_descriptor
0320     {
0321       edge_descriptor(processor_id_type sp = processor_id_type(),
0322                       processor_id_type tp = processor_id_type(),
0323                       bool owns = false, Edge ld = Edge())
0324         : source_processor(sp), target_processor(tp),
0325           source_owns_edge(owns), local(ld) {}
0326 
0327       processor_id_type owner() const
0328       {
0329         return source_owns_edge? source_processor : target_processor;
0330       }
0331 
0332       /// The processor that the source vertex resides on
0333       processor_id_type source_processor;
0334 
0335       /// The processor that the target vertex resides on
0336       processor_id_type target_processor;
0337 
0338       /// True when the source processor owns the edge, false when the
0339       /// target processor owns the edge.
0340       bool source_owns_edge;
0341 
0342       /// The local edge descriptor.
0343       Edge local;
0344 
0345       /**
0346        * Function object that generates edge descriptors for the
0347        * out_edge_iterator of the given distributed adjacency list
0348        * from the edge descriptors of the underlying adjacency list.
0349        */
0350       template<typename Graph>
0351       class out_generator
0352       {
0353         typedef typename Graph::directed_selector directed_selector;
0354 
0355       public:
0356         typedef edge_descriptor<Edge> result_type;
0357         typedef Edge argument_type;
0358 
0359         out_generator() : g(0) {}
0360         explicit out_generator(const Graph& g) : g(&g) {}
0361 
0362         result_type operator()(argument_type e) const
0363         { return map(e, directed_selector()); }
0364 
0365       private:
0366         result_type map(argument_type e, directedS) const
0367         {
0368           return result_type(g->processor(),
0369                              get(edge_target_processor_id, g->base(), e),
0370                              true, e);
0371         }
0372 
0373         result_type map(argument_type e, bidirectionalS) const
0374         {
0375           return result_type(g->processor(),
0376                              get(edge_target_processor_id, g->base(), e),
0377                              true, e);
0378         }
0379 
0380         result_type map(argument_type e, undirectedS) const
0381         {
0382           return result_type(g->processor(),
0383                              get(edge_target_processor_id, g->base(), e),
0384                              get(edge_locally_owned, g->base(), e),
0385                              e);
0386         }
0387 
0388         const Graph* g;
0389       };
0390 
0391       /**
0392        * Function object that generates edge descriptors for the
0393        * in_edge_iterator of the given distributed adjacency list
0394        * from the edge descriptors of the underlying adjacency list.
0395        */
0396       template<typename Graph>
0397       class in_generator
0398       {
0399         typedef typename Graph::directed_selector DirectedS;
0400 
0401       public:
0402         typedef typename boost::mpl::if_<is_same<DirectedS, bidirectionalS>,
0403                                          stored_in_edge<Edge>,
0404                                          Edge>::type argument_type;
0405         typedef edge_descriptor<Edge> result_type;
0406 
0407         in_generator() : g(0) {}
0408         explicit in_generator(const Graph& g) : g(&g) {}
0409 
0410         result_type operator()(argument_type e) const
0411         { return map(e, DirectedS()); }
0412 
0413       private:
0414         /**
0415          * For a bidirectional graph, we just generate the appropriate
0416          * edge. No tricks.
0417          */
0418         result_type map(argument_type e, bidirectionalS) const
0419         {
0420           return result_type(e.source_processor,
0421                              g->processor(),
0422                              true,
0423                              e.e);
0424         }
0425 
0426         /**
0427          * For an undirected graph, we generate descriptors for the
0428          * incoming edges by swapping the source/target of the
0429          * underlying edge descriptor (a hack). The target processor
0430          * ID on the edge is actually the source processor for this
0431          * edge, and our processor is the target processor. If the
0432          * edge is locally owned, then it is owned by the target (us);
0433          * otherwise it is owned by the source.
0434          */
0435         result_type map(argument_type e, undirectedS) const
0436         {
0437           typename Graph::local_edge_descriptor local_edge(e);
0438           // TBD: This is a very, VERY lame hack that takes advantage
0439           // of our knowledge of the internals of the BGL
0440           // adjacency_list. There should be a cleaner way to handle
0441           // this...
0442           using std::swap;
0443           swap(local_edge.m_source, local_edge.m_target);
0444           return result_type(get(edge_target_processor_id, g->base(), e),
0445                              g->processor(),
0446                              !get(edge_locally_owned, g->base(), e),
0447                              local_edge);
0448         }
0449 
0450         const Graph* g;
0451       };
0452 
0453     private:
0454       friend class boost::serialization::access;
0455 
0456       template<typename Archiver>
0457       void serialize(Archiver& ar, const unsigned int /*version*/)
0458       {
0459         ar
0460           & source_processor
0461           & target_processor
0462           & source_owns_edge
0463           & local;
0464       }
0465     };
0466 
0467     /// Determine the process that owns this edge
0468     template<typename Edge>
0469     inline processor_id_type
0470     owner(const edge_descriptor<Edge>& e)
0471     { return e.source_owns_edge? e.source_processor : e.target_processor; }
0472 
0473     /// Determine the local descriptor for this edge.
0474     template<typename Edge>
0475     inline Edge
0476     local(const edge_descriptor<Edge>& e)
0477     { return e.local; }
0478 
0479     /**
0480      * A Readable Property Map that extracts the owner and local
0481      * descriptor of an edge descriptor.
0482      */
0483     template<typename Edge>
0484     struct edge_global_property_map
0485     {
0486       typedef std::pair<processor_id_type, Edge> value_type;
0487       typedef value_type reference;
0488       typedef edge_descriptor<Edge> key_type;
0489       typedef readable_property_map_tag category;
0490     };
0491 
0492     template<typename Edge>
0493     inline std::pair<processor_id_type, Edge>
0494     get(edge_global_property_map<Edge>, const edge_descriptor<Edge>& e)
0495     {
0496       typedef std::pair<processor_id_type, Edge> result_type;
0497       return result_type(e.source_owns_edge? e.source_processor
0498                          /* target owns edge*/: e.target_processor,
0499                          e.local);
0500     }
0501 
0502     /**
0503      * A Readable Property Map that extracts the owner of an edge
0504      * descriptor.
0505      */
0506     template<typename Edge>
0507     struct edge_owner_property_map
0508     {
0509       typedef processor_id_type value_type;
0510       typedef value_type reference;
0511       typedef edge_descriptor<Edge> key_type;
0512       typedef readable_property_map_tag category;
0513     };
0514 
0515     template<typename Edge>
0516     inline processor_id_type
0517     get(edge_owner_property_map<Edge>, const edge_descriptor<Edge>& e)
0518     {
0519       return e.source_owns_edge? e.source_processor : e.target_processor;
0520     }
0521 
0522     /**
0523      * A Readable Property Map that extracts the local descriptor from
0524      * an edge descriptor.
0525      */
0526     template<typename Edge>
0527     struct edge_local_property_map
0528     {
0529       typedef Edge value_type;
0530       typedef value_type reference;
0531       typedef edge_descriptor<Edge> key_type;
0532       typedef readable_property_map_tag category;
0533     };
0534 
0535     template<typename Edge>
0536     inline Edge
0537     get(edge_local_property_map<Edge>,
0538         const edge_descriptor<Edge>& e)
0539     {
0540       return e.local;
0541     }
0542 
0543     /** Compare distributed edge descriptors for equality.
0544      *
0545      * \todo need edge_descriptor to know if it is undirected so we
0546      * can compare both ways.
0547      */
0548     template<typename Edge>
0549     inline bool
0550     operator==(const edge_descriptor<Edge>& e1,
0551                const edge_descriptor<Edge>& e2)
0552     {
0553       return (e1.source_processor == e2.source_processor
0554               && e1.target_processor == e2.target_processor
0555               && e1.local == e2.local);
0556     }
0557 
0558     /// Compare distributed edge descriptors for inequality.
0559     template<typename Edge>
0560     inline bool
0561     operator!=(const edge_descriptor<Edge>& e1,
0562                const edge_descriptor<Edge>& e2)
0563     { return !(e1 == e2); }
0564 
0565     /**
0566      * Configuration for the distributed adjacency list. We use this
0567      * parameter to store all of the configuration details for the
0568      * implementation of the distributed adjacency list, which allows us to
0569      * get at the distribution type in the maybe_named_graph.
0570      */
0571     template<typename OutEdgeListS, typename ProcessGroup,
0572              typename InVertexListS, typename InDistribution,
0573              typename DirectedS, typename VertexProperty, 
0574              typename EdgeProperty, typename GraphProperty, 
0575              typename EdgeListS>
0576     struct adjacency_list_config
0577     {
0578       typedef typename mpl::if_<is_same<InVertexListS, defaultS>, 
0579                                 vecS, InVertexListS>::type 
0580         VertexListS;
0581 
0582       /// Introduce the target processor ID property for each edge
0583       typedef property<edge_target_processor_id_t, processor_id_type,
0584                        EdgeProperty> edge_property_with_id;
0585 
0586       /// For undirected graphs, introduce the locally-owned property for edges
0587       typedef typename boost::mpl::if_<is_same<DirectedS, undirectedS>,
0588                                        property<edge_locally_owned_t, bool,
0589                                                 edge_property_with_id>,
0590                                        edge_property_with_id>::type
0591         base_edge_property_type;
0592 
0593       /// The edge descriptor type for the local subgraph
0594       typedef typename adjacency_list_traits<OutEdgeListS,
0595                                              VertexListS,
0596                                              directedS>::edge_descriptor
0597         local_edge_descriptor;
0598 
0599       /// For bidirectional graphs, the type of an incoming stored edge
0600       typedef stored_in_edge<local_edge_descriptor> bidir_stored_edge;
0601 
0602       /// The container type that will store incoming edges for a
0603       /// bidirectional graph.
0604       typedef typename container_gen<EdgeListS, bidir_stored_edge>::type
0605         in_edge_list_type;
0606 
0607       // Bidirectional graphs have an extra vertex property to store
0608       // the incoming edges.
0609       typedef typename boost::mpl::if_<is_same<DirectedS, bidirectionalS>,
0610                                        property<vertex_in_edges_t, in_edge_list_type,
0611                                                 VertexProperty>,
0612                                        VertexProperty>::type 
0613         base_vertex_property_type;
0614 
0615       // The type of the distributed adjacency list
0616       typedef adjacency_list<OutEdgeListS,
0617                              distributedS<ProcessGroup, 
0618                                           VertexListS, 
0619                                           InDistribution>,
0620                              DirectedS, VertexProperty, EdgeProperty,
0621                              GraphProperty, EdgeListS> 
0622         graph_type;
0623 
0624       // The type of the underlying adjacency list implementation
0625       typedef adjacency_list<OutEdgeListS, VertexListS, directedS,
0626                              base_vertex_property_type,
0627                              base_edge_property_type,
0628                              GraphProperty,
0629                              EdgeListS> 
0630         inherited;
0631       
0632       typedef InDistribution in_distribution_type;
0633       typedef typename inherited::vertices_size_type vertices_size_type;
0634 
0635           typedef typename ::boost::graph::distributed::select_distribution<
0636               in_distribution_type, VertexProperty, vertices_size_type, 
0637               ProcessGroup>::type 
0638         base_distribution_type;
0639 
0640           typedef ::boost::graph::distributed::shuffled_distribution<
0641           base_distribution_type> distribution_type;
0642 
0643       typedef VertexProperty vertex_property_type;
0644       typedef EdgeProperty edge_property_type;
0645       typedef ProcessGroup process_group_type;
0646 
0647       typedef VertexListS vertex_list_selector;
0648       typedef OutEdgeListS out_edge_list_selector;
0649       typedef DirectedS directed_selector;
0650       typedef GraphProperty graph_property_type;
0651       typedef EdgeListS edge_list_selector;
0652     };
0653 
0654     // Maybe initialize the indices of each vertex
0655     template<typename IteratorPair, typename VertexIndexMap>
0656     void
0657     maybe_initialize_vertex_indices(IteratorPair p, VertexIndexMap to_index,
0658                                     read_write_property_map_tag)
0659     {
0660       typedef typename property_traits<VertexIndexMap>::value_type index_t;
0661       index_t next_index = 0;
0662       while (p.first != p.second)
0663         put(to_index, *p.first++, next_index++);
0664     }
0665 
0666     template<typename IteratorPair, typename VertexIndexMap>
0667     inline void
0668     maybe_initialize_vertex_indices(IteratorPair p, VertexIndexMap to_index,
0669                                     readable_property_map_tag)
0670     {
0671       // Do nothing
0672     }
0673 
0674     template<typename IteratorPair, typename VertexIndexMap>
0675     inline void
0676     maybe_initialize_vertex_indices(IteratorPair p, VertexIndexMap to_index)
0677     {
0678       typedef typename property_traits<VertexIndexMap>::category category;
0679       maybe_initialize_vertex_indices(p, to_index, category());
0680     }
0681 
0682     template<typename IteratorPair>
0683     inline void
0684     maybe_initialize_vertex_indices(IteratorPair p,
0685                                     ::boost::detail::error_property_not_found)
0686     { }
0687 
0688     /***********************************************************************
0689      * Message Payloads                                                    *
0690      ***********************************************************************/
0691 
0692     /**
0693      * Data stored with a msg_add_edge message, which requests the
0694      * remote addition of an edge.
0695      */
0696     template<typename Vertex, typename LocalVertex>
0697     struct msg_add_edge_data
0698     {
0699       msg_add_edge_data() { }
0700 
0701       msg_add_edge_data(Vertex source, Vertex target)
0702         : source(source.local), target(target) { }
0703 
0704       /// The source of the edge; the processor will be the
0705       /// receiving processor.
0706       LocalVertex source;
0707         
0708       /// The target of the edge.
0709       Vertex target;
0710         
0711       template<typename Archiver>
0712       void serialize(Archiver& ar, const unsigned int /*version*/)
0713       {
0714         ar & unsafe_serialize(source) & target;
0715       }
0716     };
0717 
0718     /**
0719      * Like @c msg_add_edge_data, but also includes a user-specified
0720      * property value to be attached to the edge.
0721      */
0722     template<typename Vertex, typename LocalVertex, typename EdgeProperty>
0723     struct msg_add_edge_with_property_data
0724       : msg_add_edge_data<Vertex, LocalVertex>, 
0725         maybe_store_property<EdgeProperty>
0726     {
0727     private:
0728       typedef msg_add_edge_data<Vertex, LocalVertex> inherited_data;
0729       typedef maybe_store_property<EdgeProperty> inherited_property;
0730 
0731     public:
0732       msg_add_edge_with_property_data() { }
0733 
0734       msg_add_edge_with_property_data(Vertex source, 
0735                                       Vertex target,
0736                                       const EdgeProperty& property)
0737         : inherited_data(source, target),
0738           inherited_property(property) { }
0739       
0740       template<typename Archiver>
0741       void serialize(Archiver& ar, const unsigned int /*version*/)
0742       {
0743         ar & boost::serialization::base_object<inherited_data>(*this) 
0744            & boost::serialization::base_object<inherited_property>(*this);
0745       }
0746     };
0747 
0748     //------------------------------------------------------------------------
0749     // Distributed adjacency list property map details
0750     /**
0751      * Metafunction that extracts the given property from the given
0752      * distributed adjacency list type. This could be implemented much
0753      * more cleanly, but even newer versions of GCC (e.g., 3.2.3)
0754      * cannot properly handle partial specializations involving
0755      * enumerator types.
0756      */
0757     template<typename Property>
0758     struct get_adj_list_pmap
0759     {
0760       template<typename Graph>
0761       struct apply
0762       {
0763         typedef Graph graph_type;
0764         typedef typename graph_type::process_group_type process_group_type;
0765         typedef typename graph_type::inherited base_graph_type;
0766         typedef typename property_map<base_graph_type, Property>::type
0767           local_pmap;
0768         typedef typename property_map<base_graph_type, Property>::const_type
0769           local_const_pmap;
0770 
0771         typedef graph_traits<graph_type> traits;
0772         typedef typename graph_type::local_vertex_descriptor local_vertex;
0773         typedef typename property_traits<local_pmap>::key_type local_key_type;
0774 
0775         typedef typename property_traits<local_pmap>::value_type value_type;
0776 
0777         typedef typename property_map<Graph, vertex_global_t>::const_type
0778           vertex_global_map;
0779         typedef typename property_map<Graph, edge_global_t>::const_type
0780           edge_global_map;
0781 
0782         typedef typename mpl::if_c<(is_same<local_key_type,
0783                                             local_vertex>::value),
0784                                    vertex_global_map, edge_global_map>::type
0785           global_map;
0786 
0787       public:
0788         typedef ::boost::parallel::distributed_property_map<
0789                   process_group_type, global_map, local_pmap> type;
0790 
0791         typedef ::boost::parallel::distributed_property_map<
0792                   process_group_type, global_map, local_const_pmap> const_type;
0793       };
0794     };
0795 
0796     /**
0797      * The local vertex index property map is actually a mapping from
0798      * the local vertex descriptors to vertex indices.
0799      */
0800     template<>
0801     struct get_adj_list_pmap<vertex_local_index_t>
0802     {
0803       template<typename Graph>
0804       struct apply
0805         : ::boost::property_map<typename Graph::inherited, vertex_index_t>
0806       { };
0807     };
0808 
0809     /**
0810      * The vertex index property map maps from global descriptors
0811      * (e.g., the vertex descriptor of a distributed adjacency list)
0812      * to the underlying local index. It is not valid to use this
0813      * property map with nonlocal descriptors.
0814      */
0815     template<>
0816     struct get_adj_list_pmap<vertex_index_t>
0817     {
0818       template<typename Graph>
0819       struct apply
0820       {
0821       private:
0822         typedef typename property_map<Graph, vertex_global_t>::const_type
0823           global_map;
0824 
0825         typedef property_map<typename Graph::inherited, vertex_index_t> local;
0826 
0827       public:
0828         typedef local_property_map<typename Graph::process_group_type,
0829                                    global_map,
0830                                    typename local::type> type;
0831         typedef local_property_map<typename Graph::process_group_type,
0832                                    global_map,
0833                                    typename local::const_type> const_type;
0834       };
0835     };
0836 
0837     /**
0838      * The vertex owner property map maps from vertex descriptors to
0839      * the processor that owns the vertex.
0840      */
0841     template<>
0842     struct get_adj_list_pmap<vertex_global_t>
0843     {
0844       template<typename Graph>
0845       struct apply
0846       {
0847       private:
0848         typedef typename Graph::local_vertex_descriptor
0849           local_vertex_descriptor;
0850       public:
0851         typedef global_descriptor_property_map<local_vertex_descriptor> type;
0852         typedef type const_type;
0853       };
0854     };
0855 
0856     /**
0857      * The vertex owner property map maps from vertex descriptors to
0858      * the processor that owns the vertex.
0859      */
0860     template<>
0861     struct get_adj_list_pmap<vertex_owner_t>
0862     {
0863       template<typename Graph>
0864       struct apply
0865       {
0866       private:
0867         typedef typename Graph::local_vertex_descriptor
0868           local_vertex_descriptor;
0869       public:
0870         typedef owner_property_map<local_vertex_descriptor> type;
0871         typedef type const_type;
0872       };
0873     };
0874 
0875     /**
0876      * The vertex local property map maps from vertex descriptors to
0877      * the local descriptor for that vertex.
0878      */
0879     template<>
0880     struct get_adj_list_pmap<vertex_local_t>
0881     {
0882       template<typename Graph>
0883       struct apply
0884       {
0885       private:
0886         typedef typename Graph::local_vertex_descriptor
0887           local_vertex_descriptor;
0888       public:
0889         typedef local_descriptor_property_map<local_vertex_descriptor> type;
0890         typedef type const_type;
0891       };
0892     };
0893 
0894     /**
0895      * The edge global property map maps from edge descriptors to
0896      * a pair of the owning processor and local descriptor.
0897      */
0898     template<>
0899     struct get_adj_list_pmap<edge_global_t>
0900     {
0901       template<typename Graph>
0902       struct apply
0903       {
0904       private:
0905         typedef typename Graph::local_edge_descriptor
0906           local_edge_descriptor;
0907       public:
0908         typedef edge_global_property_map<local_edge_descriptor> type;
0909         typedef type const_type;
0910       };
0911     };
0912 
0913     /**
0914      * The edge owner property map maps from edge descriptors to
0915      * the processor that owns the edge.
0916      */
0917     template<>
0918     struct get_adj_list_pmap<edge_owner_t>
0919     {
0920       template<typename Graph>
0921       struct apply
0922       {
0923       private:
0924         typedef typename Graph::local_edge_descriptor
0925           local_edge_descriptor;
0926       public:
0927         typedef edge_owner_property_map<local_edge_descriptor> type;
0928         typedef type const_type;
0929       };
0930     };
0931 
0932     /**
0933      * The edge local property map maps from edge descriptors to
0934      * the local descriptor for that edge.
0935      */
0936     template<>
0937     struct get_adj_list_pmap<edge_local_t>
0938     {
0939       template<typename Graph>
0940       struct apply
0941       {
0942       private:
0943         typedef typename Graph::local_edge_descriptor
0944           local_edge_descriptor;
0945       public:
0946         typedef edge_local_property_map<local_edge_descriptor> type;
0947         typedef type const_type;
0948       };
0949     };
0950     //------------------------------------------------------------------------
0951 
0952     // Directed graphs do not have in edges, so this is a no-op
0953     template<typename Graph>
0954     inline void
0955     remove_in_edge(typename Graph::edge_descriptor, Graph&, directedS)
0956     { }
0957 
0958     // Bidirectional graphs have in edges stored in the
0959     // vertex_in_edges property.
0960     template<typename Graph>
0961     inline void
0962     remove_in_edge(typename Graph::edge_descriptor e, Graph& g, bidirectionalS)
0963     {
0964       typedef typename Graph::in_edge_list_type in_edge_list_type;
0965       in_edge_list_type& in_edges =
0966         get(vertex_in_edges, g.base())[target(e, g).local];
0967       typename in_edge_list_type::iterator i = in_edges.begin();
0968       while (i != in_edges.end()
0969              && !(i->source_processor == source(e, g).owner)
0970              && i->e == e.local)
0971         ++i;
0972 
0973       BOOST_ASSERT(i != in_edges.end());
0974       in_edges.erase(i);
0975     }
0976 
0977     // Undirected graphs have in edges stored as normal edges.
0978     template<typename Graph>
0979     inline void
0980     remove_in_edge(typename Graph::edge_descriptor e, Graph& g, undirectedS)
0981     {
0982       typedef typename Graph::inherited base_type;
0983       typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
0984 
0985       // TBD: can we make this more efficient?
0986       // Removing edge (v, u). v is local
0987       base_type& bg = g.base();
0988       vertex_descriptor u = source(e, g);
0989       vertex_descriptor v = target(e, g);
0990       if (v.owner != process_id(g.process_group())) {
0991         using std::swap;
0992         swap(u, v);
0993       }
0994 
0995       typename graph_traits<base_type>::out_edge_iterator ei, ei_end;
0996       for (boost::tie(ei, ei_end) = out_edges(v.local, bg); ei != ei_end; ++ei)
0997       {
0998         if (target(*ei, g.base()) == u.local
0999             // TBD: deal with parallel edges properly && *ei == e
1000             && get(edge_target_processor_id, bg, *ei) == u.owner) {
1001           remove_edge(ei, bg);
1002           return;
1003         }
1004       }
1005 
1006       if (v.owner == process_id(g.process_group())) {
1007 
1008       }
1009     }
1010 
1011     //------------------------------------------------------------------------
1012     // Lazy addition of edges
1013 
1014     // Work around the fact that an adjacency_list with vecS vertex
1015     // storage automatically adds edges when the descriptor is
1016     // out-of-range.
1017     template <class Graph, class Config, class Base>
1018     inline std::pair<typename Config::edge_descriptor, bool>
1019     add_local_edge(typename Config::vertex_descriptor u,
1020                    typename Config::vertex_descriptor v,
1021                    const typename Config::edge_property_type& p,
1022                    vec_adj_list_impl<Graph, Config, Base>& g_)
1023     {
1024       adj_list_helper<Config, Base>& g = g_;
1025       return add_edge(u, v, p, g);
1026     }
1027 
1028     template <class Graph, class Config, class Base>
1029     inline std::pair<typename Config::edge_descriptor, bool>
1030     add_local_edge(typename Config::vertex_descriptor u,
1031                    typename Config::vertex_descriptor v,
1032                    const typename Config::edge_property_type& p,
1033                    boost::adj_list_impl<Graph, Config, Base>& g)
1034     {
1035       return add_edge(u, v, p, g);
1036     }
1037 
1038     template <class EdgeProperty,class EdgeDescriptor>
1039     struct msg_nonlocal_edge_data
1040       : public detail::parallel::maybe_store_property<EdgeProperty>
1041     {
1042       typedef EdgeProperty edge_property_type;
1043       typedef EdgeDescriptor local_edge_descriptor;
1044       typedef detail::parallel::maybe_store_property<edge_property_type> 
1045         inherited;
1046 
1047       msg_nonlocal_edge_data() {}
1048       msg_nonlocal_edge_data(local_edge_descriptor e,
1049                              const edge_property_type& p)
1050         : inherited(p), e(e) { }
1051 
1052       local_edge_descriptor e;
1053 
1054       template<typename Archiver>
1055       void serialize(Archiver& ar, const unsigned int /*version*/)
1056       {
1057         ar & boost::serialization::base_object<inherited>(*this) & e;
1058       }
1059     };
1060 
1061     template <class EdgeDescriptor>
1062     struct msg_remove_edge_data
1063     {
1064       typedef EdgeDescriptor edge_descriptor;
1065       msg_remove_edge_data() {}
1066       explicit msg_remove_edge_data(edge_descriptor e) : e(e) {}
1067 
1068       edge_descriptor e;
1069 
1070       template<typename Archiver>
1071       void serialize(Archiver& ar, const unsigned int /*version*/)
1072       {
1073         ar & e;
1074       }
1075     };
1076 
1077   } } // end namespace detail::parallel
1078 
1079   /**
1080    * Adjacency list traits for a distributed adjacency list. Contains
1081    * the vertex and edge descriptors, the directed-ness, and the
1082    * parallel edges typedefs.
1083    */
1084   template<typename OutEdgeListS, typename ProcessGroup,
1085            typename InVertexListS, typename InDistribution, typename DirectedS>
1086   struct adjacency_list_traits<OutEdgeListS,
1087                                distributedS<ProcessGroup, 
1088                                             InVertexListS,
1089                                             InDistribution>,
1090                                DirectedS>
1091   {
1092   private:
1093     typedef typename mpl::if_<is_same<InVertexListS, defaultS>,
1094                               vecS,
1095                               InVertexListS>::type VertexListS;
1096 
1097     typedef adjacency_list_traits<OutEdgeListS, VertexListS, directedS>
1098       base_type;
1099 
1100   public:
1101     typedef typename base_type::vertex_descriptor local_vertex_descriptor;
1102     typedef typename base_type::edge_descriptor   local_edge_descriptor;
1103 
1104     typedef typename boost::mpl::if_<typename DirectedS::is_bidir_t,
1105       bidirectional_tag,
1106       typename boost::mpl::if_<typename DirectedS::is_directed_t,
1107         directed_tag, undirected_tag
1108       >::type
1109     >::type directed_category;
1110 
1111     typedef typename parallel_edge_traits<OutEdgeListS>::type
1112       edge_parallel_category;
1113 
1114     typedef detail::parallel::global_descriptor<local_vertex_descriptor>
1115       vertex_descriptor;
1116 
1117     typedef detail::parallel::edge_descriptor<local_edge_descriptor>
1118       edge_descriptor;
1119   };
1120 
1121 #define PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS                                    \
1122   typename OutEdgeListS, typename ProcessGroup, typename InVertexListS,        \
1123   typename InDistribution, typename DirectedS, typename VertexProperty,        \
1124   typename EdgeProperty,  typename GraphProperty, typename EdgeListS
1125 
1126 #define PBGL_DISTRIB_ADJLIST_TYPE                                              \
1127   adjacency_list<OutEdgeListS,                                                 \
1128                  distributedS<ProcessGroup, InVertexListS, InDistribution>,    \
1129                  DirectedS, VertexProperty, EdgeProperty, GraphProperty,       \
1130                  EdgeListS>
1131 
1132 #define PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG                             \
1133   typename OutEdgeListS, typename ProcessGroup, typename InVertexListS,        \
1134   typename InDistribution, typename VertexProperty,                            \
1135   typename EdgeProperty,  typename GraphProperty, typename EdgeListS
1136   
1137 #define PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(directed)                             \
1138   adjacency_list<OutEdgeListS,                                                 \
1139                  distributedS<ProcessGroup, InVertexListS, InDistribution>,    \
1140                  directed, VertexProperty, EdgeProperty, GraphProperty,        \
1141                  EdgeListS>
1142                  
1143   /** A distributed adjacency list.
1144    *
1145    * This class template partial specialization defines a distributed
1146    * (or "partitioned") adjacency list graph. The distributed
1147    * adjacency list is similar to the standard Boost Graph Library
1148    * adjacency list, which stores a list of vertices and for each
1149    * verted the list of edges outgoing from the vertex (and, in some
1150    * cases, also the edges incoming to the vertex). The distributed
1151    * adjacency list differs in that it partitions the graph into
1152    * several subgraphs that are then divided among different
1153    * processors (or nodes within a cluster). The distributed adjacency
1154    * list attempts to maintain a high degree of compatibility with the
1155    * standard, non-distributed adjacency list.
1156    *
1157    * The graph is partitioned by vertex, with each processor storing
1158    * all of the required information for a particular subset of the
1159    * vertices, including vertex properties, outgoing edges, and (for
1160    * bidirectional graphs) incoming edges. This information is
1161    * accessible only on the processor that owns the vertex: for
1162    * instance, if processor 0 owns vertex @c v, no other processor can
1163    * directly access the properties of @c v or enumerate its outgoing
1164    * edges.
1165    *
1166    * Edges in a graph may be entirely local (connecting two local
1167    * vertices), but more often it is the case that edges are
1168    * non-local, meaning that the two vertices they connect reside in
1169    * different processes. Edge properties are stored with the
1170    * originating vertex for directed and bidirectional graphs, and are
1171    * therefore only accessible from the processor that owns the
1172    * originating vertex. Other processors may query the source and
1173    * target of the edge, but cannot access its properties. This is
1174    * particularly interesting when accessing the incoming edges of a
1175    * bidirectional graph, which are not guaranteed to be stored on the
1176    * processor that is able to perform the iteration. For undirected
1177    * graphs the situation is more complicated, since no vertex clearly
1178    * owns the edges: the list of edges incident to a vertex may
1179    * contain a mix of local and non-local edges.
1180    *
1181    * The distributed adjacency list is able to model several of the
1182    * existing Graph concepts. It models the Graph concept because it
1183    * exposes vertex and edge descriptors in the normal way; these
1184    * descriptors model the GlobalDescriptor concept (because they have
1185    * an owner and a local descriptor), and as such the distributed
1186    * adjacency list models the DistributedGraph concept. The adjacency
1187    * list also models the IncidenceGraph and AdjacencyGraph concepts,
1188    * although this is only true so long as the domain of the valid
1189    * expression arguments are restricted to vertices and edges stored
1190    * locally. Likewise, bidirectional and undirected distributed
1191    * adjacency lists model the BidirectionalGraph concept (vertex and
1192    * edge domains must be respectived) and the distributed adjacency
1193    * list models the MutableGraph concept (vertices and edges can only
1194    * be added or removed locally). T he distributed adjacency list
1195    * does not, however, model the VertexListGraph or EdgeListGraph
1196    * concepts, because we can not efficiently enumerate all vertices
1197    * or edges in the graph. Instead, the local subsets of vertices and
1198    * edges can be enumerated (with the same syntax): the distributed
1199    * adjacency list therefore models the DistributedVertexListGraph
1200    * and DistributedEdgeListGraph concepts, because concurrent
1201    * iteration over all of the vertices or edges stored on each
1202    * processor will visit each vertex or edge.
1203    *
1204    * The distributed adjacency list is distinguished from the
1205    * non-distributed version by the vertex list descriptor, which will
1206    * be @c distributedS<ProcessGroup,VertexListS>. Here,
1207    * the VertexListS type plays the same role as the VertexListS type
1208    * in the non-distributed adjacency list: it allows one to select
1209    * the data structure that will be used to store the local
1210    * vertices. The ProcessGroup type, on the other hand, is unique to
1211    * distributed data structures: it is the type that abstracts a
1212    * group of cooperating processes, and it used for process
1213    * identification, communication, and synchronization, among other
1214    * things. Different process group types represent different
1215    * communication mediums (e.g., MPI, PVM, TCP) or different models
1216    * of communication (LogP, CGM, BSP, synchronous, etc.). This
1217    * distributed adjacency list assumes a model based on non-blocking
1218    * sends.
1219    *
1220    * Distribution of vertices across different processors is
1221    * accomplished in two different ways. When initially constructing
1222    * the graph, the user may provide a distribution object (that
1223    * models the Distribution concept), which will determine the
1224    * distribution of vertices to each process. Additionally, the @c
1225    * add_vertex and @c add_edge operations add vertices or edges
1226    * stored on the local processor. For @c add_edge, this is
1227    * accomplished by requiring that the source vertex of the new edge
1228    * be local to the process executing @c add_edge.
1229    *
1230    * Internal properties of a distributed adjacency list are
1231    * accessible in the same manner as internal properties for a
1232    * non-distributed adjacency list for local vertices or
1233    * edges. Access to properties for remote vertices or edges occurs
1234    * with the same syntax, but involve communication with the owner of
1235    * the information: for more information, refer to class template
1236    * @ref distributed_property_map, which manages distributed
1237    * property maps. Note that the distributed property maps created
1238    * for internal properties determine their reduction operation via
1239    * the metafunction @ref property_reduce, which for the vast
1240    * majority of uses is correct behavior.
1241    *
1242    * Communication among the processes coordinating on a particular
1243    * distributed graph relies on non-blocking message passing along
1244    * with synchronization. Local portions of the distributed graph may
1245    * be modified concurrently, including the introduction of non-local
1246    * edges, but prior to accessing the graph it is recommended that
1247    * the @c synchronize free function be invoked on the graph to clear
1248    * up any pending interprocess communication and modifications. All
1249    * processes will then be released from the synchronization barrier
1250    * concurrently.
1251    *
1252    * \todo Determine precisely what we should do with nonlocal edges
1253    * in undirected graphs. Our parallelization of certain algorithms
1254    * relies on the ability to access edge property maps immediately
1255    * (e.g., edge_weight_t), so it may be necessary to duplicate the
1256    * edge properties in both processes (but then we need some form of
1257    * coherence protocol).
1258    *
1259    * \todo What does the user do if @c property_reduce doesn't do the
1260    * right thing?
1261    */
1262   template<typename OutEdgeListS, typename ProcessGroup,
1263            typename InVertexListS, typename InDistribution, typename DirectedS,
1264            typename VertexProperty, typename EdgeProperty, 
1265            typename GraphProperty, typename EdgeListS>
1266   class adjacency_list<OutEdgeListS,
1267                        distributedS<ProcessGroup, 
1268                                     InVertexListS, 
1269                                     InDistribution>,
1270                        DirectedS, VertexProperty,
1271                        EdgeProperty, GraphProperty, EdgeListS>
1272     : // Support for named vertices
1273       public graph::distributed::maybe_named_graph<   
1274         adjacency_list<OutEdgeListS,
1275                        distributedS<ProcessGroup,
1276                                     InVertexListS,
1277                                     InDistribution>,
1278                        DirectedS, VertexProperty,
1279                        EdgeProperty, GraphProperty, EdgeListS>,
1280         typename adjacency_list_traits<OutEdgeListS, 
1281                                        distributedS<ProcessGroup,
1282                                                     InVertexListS,
1283                                                     InDistribution>,
1284                                        DirectedS>::vertex_descriptor,
1285         typename adjacency_list_traits<OutEdgeListS, 
1286                                        distributedS<ProcessGroup,
1287                                                     InVertexListS,
1288                                                     InDistribution>,
1289                                        DirectedS>::edge_descriptor,
1290         detail::parallel::adjacency_list_config<OutEdgeListS, ProcessGroup, 
1291                                                 InVertexListS, InDistribution,
1292                                                 DirectedS, VertexProperty, 
1293                                                 EdgeProperty, GraphProperty, 
1294                                                 EdgeListS> >
1295   {
1296     typedef detail::parallel::adjacency_list_config<OutEdgeListS, ProcessGroup, 
1297                                                 InVertexListS, InDistribution,
1298                                                 DirectedS, VertexProperty, 
1299                                                 EdgeProperty, GraphProperty, 
1300                                                 EdgeListS>
1301       config_type;
1302       
1303     typedef adjacency_list_traits<OutEdgeListS,
1304                                   distributedS<ProcessGroup, 
1305                                                InVertexListS, 
1306                                                InDistribution>,
1307                                   DirectedS> 
1308       traits_type;
1309 
1310     typedef typename DirectedS::is_directed_t is_directed;
1311 
1312     typedef EdgeListS edge_list_selector;
1313 
1314   public:
1315     /// The container type that will store incoming edges for a
1316     /// bidirectional graph.
1317     typedef typename config_type::in_edge_list_type in_edge_list_type;
1318 //    typedef typename inherited::edge_descriptor   edge_descriptor;
1319 
1320     /// The type of the underlying adjacency list implementation
1321     typedef typename config_type::inherited inherited;
1322 
1323     /// The type of properties stored in the local subgraph
1324     /// Bidirectional graphs have an extra vertex property to store
1325     /// the incoming edges.
1326     typedef typename inherited::vertex_property_type
1327       base_vertex_property_type;
1328 
1329     /// The type of the distributed adjacency list (this type)
1330     typedef typename config_type::graph_type graph_type;
1331 
1332     /// Expose graph components and graph category
1333     typedef typename traits_type::local_vertex_descriptor
1334       local_vertex_descriptor;
1335     typedef typename traits_type::local_edge_descriptor
1336       local_edge_descriptor;
1337     typedef typename traits_type::vertex_descriptor vertex_descriptor;
1338     typedef typename traits_type::edge_descriptor edge_descriptor;
1339 
1340     typedef typename traits_type::directed_category directed_category;
1341     typedef typename inherited::edge_parallel_category
1342       edge_parallel_category;
1343     typedef typename inherited::graph_tag graph_tag;
1344 
1345     // Current implementation requires the ability to have parallel
1346     // edges in the underlying adjacency_list. Which processor each
1347     // edge refers to is attached as an internal property. TBD:
1348     // remove this restriction, which may require some rewriting.
1349     BOOST_STATIC_ASSERT((is_same<edge_parallel_category,
1350                                  allow_parallel_edge_tag>::value));
1351 
1352     /** Determine the graph traversal category.
1353      *
1354      * A directed distributed adjacency list models the Distributed
1355      * Graph, Incidence Graph, and Adjacency Graph
1356      * concepts. Bidirectional and undirected graphs also model the
1357      * Bidirectional Graph concept. Note that when modeling these
1358      * concepts the domains of certain operations (e.g., in_edges)
1359      * are restricted; see the distributed adjacency_list
1360      * documentation.
1361      */
1362     typedef typename boost::mpl::if_<
1363               is_same<DirectedS, directedS>,
1364               directed_distributed_adj_list_tag,
1365               typename boost::mpl::if_<is_same<DirectedS, bidirectionalS>,
1366                                        bidirectional_distributed_adj_list_tag,
1367                                        undirected_distributed_adj_list_tag>::type>
1368       ::type traversal_category;
1369 
1370     typedef typename inherited::degree_size_type degree_size_type;
1371     typedef typename inherited::vertices_size_type vertices_size_type;
1372     typedef typename inherited::edges_size_type edges_size_type;
1373     typedef VertexProperty vertex_property_type;
1374     typedef EdgeProperty edge_property_type;
1375     typedef typename inherited::graph_property_type graph_property_type;
1376     typedef typename inherited::vertex_bundled vertex_bundled;
1377     typedef typename inherited::edge_bundled edge_bundled;
1378     typedef typename inherited::graph_bundled graph_bundled;
1379 
1380     typedef typename container_gen<edge_list_selector, edge_descriptor>::type
1381       local_edge_list_type;
1382 
1383   private:
1384     typedef typename boost::mpl::if_<is_same<DirectedS, bidirectionalS>,
1385                                      typename in_edge_list_type::const_iterator,
1386                                      typename inherited::out_edge_iterator>::type
1387       base_in_edge_iterator;
1388 
1389     typedef typename inherited::out_edge_iterator base_out_edge_iterator;
1390     typedef typename graph_traits<inherited>::edge_iterator
1391       base_edge_iterator;
1392     typedef typename inherited::edge_property_type base_edge_property_type;
1393 
1394     typedef typename local_edge_list_type::const_iterator
1395       undirected_edge_iterator;
1396 
1397     typedef InDistribution in_distribution_type;
1398 
1399     typedef parallel::trigger_receive_context trigger_receive_context;
1400 
1401   public:
1402     /// Iterator over the (local) vertices of the graph
1403     typedef transform_iterator<typename vertex_descriptor::generator,
1404                                typename inherited::vertex_iterator>
1405       vertex_iterator;
1406 
1407     /// Helper for out_edge_iterator
1408     typedef typename edge_descriptor::template out_generator<adjacency_list>
1409       out_edge_generator;
1410 
1411     /// Iterator over the outgoing edges of a vertex
1412     typedef transform_iterator<out_edge_generator,
1413                                typename inherited::out_edge_iterator>
1414       out_edge_iterator;
1415 
1416     /// Helper for in_edge_iterator
1417     typedef typename edge_descriptor::template in_generator<adjacency_list>
1418       in_edge_generator;
1419 
1420     /// Iterator over the incoming edges of a vertex
1421     typedef transform_iterator<in_edge_generator, base_in_edge_iterator>
1422       in_edge_iterator;
1423 
1424     /// Iterator over the neighbors of a vertex
1425     typedef boost::adjacency_iterator<
1426               adjacency_list, vertex_descriptor, out_edge_iterator,
1427               typename std::iterator_traits<base_out_edge_iterator>
1428                          ::difference_type>
1429       adjacency_iterator;
1430 
1431     /// Iterator over the (local) edges in a graph
1432     typedef typename boost::mpl::if_<is_same<DirectedS, undirectedS>,
1433                                      undirected_edge_iterator,
1434                                      transform_iterator<out_edge_generator,
1435                                                         base_edge_iterator>
1436                                      >::type 
1437       edge_iterator;
1438 
1439   public:
1440     /// The type of the mixin for named vertices
1441     typedef graph::distributed::maybe_named_graph<graph_type, 
1442                                                   vertex_descriptor, 
1443                                                   edge_descriptor, 
1444                                                   config_type> 
1445       named_graph_mixin;
1446         
1447     /// Process group used for communication
1448     typedef ProcessGroup process_group_type;
1449 
1450     /// How to refer to a process
1451     typedef typename process_group_type::process_id_type process_id_type;
1452 
1453     /// Whether this graph is directed, undirected, or bidirectional
1454     typedef DirectedS directed_selector;
1455 
1456     // Structure used for the lazy addition of vertices
1457     struct lazy_add_vertex_with_property;
1458     friend struct lazy_add_vertex_with_property;
1459 
1460     // Structure used for the lazy addition of edges
1461     struct lazy_add_edge;
1462     friend struct lazy_add_edge;
1463 
1464     // Structure used for the lazy addition of edges with properties
1465     struct lazy_add_edge_with_property;
1466     friend struct lazy_add_edge_with_property;
1467 
1468     /// default_distribution_type is the type of the distribution used if the
1469     /// user didn't specify an explicit one
1470     typedef typename graph::distributed::select_distribution<
1471               InDistribution, VertexProperty, vertices_size_type, 
1472               ProcessGroup>::default_type 
1473       default_distribution_type;
1474     
1475     /// distribution_type is the type of the distribution instance stored in
1476     /// the maybe_named_graph base class
1477     typedef typename graph::distributed::select_distribution<
1478               InDistribution, VertexProperty, vertices_size_type,
1479               ProcessGroup>::type 
1480       base_distribution_type;
1481 
1482       typedef graph::distributed::shuffled_distribution<
1483           base_distribution_type> distribution_type;
1484 
1485   private:
1486     // FIXME: the original adjacency_list contained this comment:
1487     //    Default copy constructor and copy assignment operators OK??? TBD
1488     // but the adj_list_impl contained these declarations:
1489     adjacency_list(const adjacency_list& other);
1490     adjacency_list& operator=(const adjacency_list& other);
1491 
1492   public:
1493     adjacency_list(const ProcessGroup& pg = ProcessGroup())
1494       : named_graph_mixin(pg, default_distribution_type(pg, 0)),
1495         m_local_graph(GraphProperty()), 
1496         process_group_(pg, boost::parallel::attach_distributed_object())
1497     {
1498       setup_triggers();
1499     }
1500 
1501     adjacency_list(const ProcessGroup& pg, 
1502                    const base_distribution_type& distribution)
1503       : named_graph_mixin(pg, distribution),
1504         m_local_graph(GraphProperty()), 
1505         process_group_(pg, boost::parallel::attach_distributed_object())
1506     {
1507       setup_triggers();
1508     }
1509 
1510     adjacency_list(const GraphProperty& g,
1511                    const ProcessGroup& pg = ProcessGroup())
1512       : named_graph_mixin(pg, default_distribution_type(pg, 0)),
1513         m_local_graph(g), 
1514         process_group_(pg, boost::parallel::attach_distributed_object())
1515     {
1516       setup_triggers();
1517     }
1518 
1519     adjacency_list(vertices_size_type n,
1520                    const GraphProperty& p,
1521                    const ProcessGroup& pg,
1522                    const base_distribution_type& distribution)
1523       : named_graph_mixin(pg, distribution),
1524         m_local_graph(distribution.block_size(process_id(pg), n), p),
1525         process_group_(pg, boost::parallel::attach_distributed_object())
1526     {
1527       setup_triggers();
1528 
1529       detail::parallel::maybe_initialize_vertex_indices(vertices(base()),
1530                                       get(vertex_index, base()));
1531     }
1532 
1533     adjacency_list(vertices_size_type n,
1534                    const ProcessGroup& pg,
1535                    const base_distribution_type& distribution)
1536       : named_graph_mixin(pg, distribution),
1537         m_local_graph(distribution.block_size(process_id(pg), n), GraphProperty()),
1538         process_group_(pg, boost::parallel::attach_distributed_object()) 
1539     {
1540       setup_triggers();
1541 
1542       detail::parallel::maybe_initialize_vertex_indices(vertices(base()),
1543                                       get(vertex_index, base()));
1544     }
1545 
1546     adjacency_list(vertices_size_type n,
1547                    const GraphProperty& p,
1548                    const ProcessGroup& pg = ProcessGroup())
1549       : named_graph_mixin(pg, default_distribution_type(pg, n)),
1550         m_local_graph(this->distribution().block_size(process_id(pg), n), p),
1551         process_group_(pg, boost::parallel::attach_distributed_object())
1552     {
1553       setup_triggers();
1554 
1555       detail::parallel::maybe_initialize_vertex_indices(vertices(base()),
1556                                       get(vertex_index, base()));
1557     }
1558 
1559     adjacency_list(vertices_size_type n,
1560                    const ProcessGroup& pg = ProcessGroup())
1561       : named_graph_mixin(pg, default_distribution_type(pg, n)),
1562         m_local_graph(this->distribution().block_size(process_id(pg), n), 
1563                       GraphProperty()),
1564         process_group_(pg, boost::parallel::attach_distributed_object())
1565     {
1566       setup_triggers();
1567 
1568       detail::parallel::maybe_initialize_vertex_indices(vertices(base()),
1569                                       get(vertex_index, base()));
1570     }
1571 
1572     /*
1573      * We assume that every processor sees the same list of edges, so
1574      * they skip over any that don't originate from themselves. This
1575      * means that programs switching between a local and a distributed
1576      * graph will keep the same semantics.
1577      */
1578     template <class EdgeIterator>
1579     adjacency_list(EdgeIterator first, EdgeIterator last,
1580                    vertices_size_type n,
1581                    const ProcessGroup& pg = ProcessGroup(),
1582                    const GraphProperty& p = GraphProperty())
1583       : named_graph_mixin(pg, default_distribution_type(pg, n)),
1584         m_local_graph(this->distribution().block_size(process_id(pg), n), p),
1585         process_group_(pg, boost::parallel::attach_distributed_object())
1586     {
1587       setup_triggers();
1588 
1589       typedef typename config_type::VertexListS vertex_list_selector;
1590       initialize(first, last, n, this->distribution(), vertex_list_selector());
1591       detail::parallel::maybe_initialize_vertex_indices(vertices(base()),
1592                                       get(vertex_index, base()));
1593 
1594     }
1595 
1596     template <class EdgeIterator, class EdgePropertyIterator>
1597     adjacency_list(EdgeIterator first, EdgeIterator last,
1598                    EdgePropertyIterator ep_iter,
1599                    vertices_size_type n,
1600                    const ProcessGroup& pg = ProcessGroup(),
1601                    const GraphProperty& p = GraphProperty())
1602       : named_graph_mixin(pg, default_distribution_type(pg, n)),
1603         m_local_graph(this->distribution().block_size(process_id(pg), n), p),
1604         process_group_(pg, boost::parallel::attach_distributed_object())
1605     {
1606       setup_triggers();
1607 
1608       typedef typename config_type::VertexListS vertex_list_selector;
1609       initialize(first, last, ep_iter, n, this->distribution(),
1610                  vertex_list_selector());
1611       detail::parallel::maybe_initialize_vertex_indices(vertices(base()),
1612                                       get(vertex_index, base()));
1613 
1614     }
1615 
1616     template <class EdgeIterator>
1617     adjacency_list(EdgeIterator first, EdgeIterator last,
1618                    vertices_size_type n,
1619                    const ProcessGroup& pg,
1620                    const base_distribution_type& distribution,
1621                    const GraphProperty& p = GraphProperty())
1622       : named_graph_mixin(pg, distribution),
1623         m_local_graph(distribution.block_size(process_id(pg), n), p),
1624         process_group_(pg, boost::parallel::attach_distributed_object())
1625     {
1626       setup_triggers();
1627 
1628       typedef typename config_type::VertexListS vertex_list_selector;
1629       initialize(first, last, n, this->distribution(), vertex_list_selector());
1630       detail::parallel::maybe_initialize_vertex_indices(vertices(base()),
1631                                       get(vertex_index, base()));
1632 
1633     }
1634 
1635     template <class EdgeIterator, class EdgePropertyIterator>
1636     adjacency_list(EdgeIterator first, EdgeIterator last,
1637                    EdgePropertyIterator ep_iter,
1638                    vertices_size_type n,
1639                    const ProcessGroup& pg,
1640                    const base_distribution_type& distribution,
1641                    const GraphProperty& p = GraphProperty())
1642       : named_graph_mixin(pg, distribution),
1643         m_local_graph(this->distribution().block_size(process_id(pg), n), p),
1644         process_group_(pg, boost::parallel::attach_distributed_object())
1645     {
1646       setup_triggers();
1647 
1648       typedef typename config_type::VertexListS vertex_list_selector;
1649       initialize(first, last, ep_iter, n, distribution,
1650                  vertex_list_selector());
1651       detail::parallel::maybe_initialize_vertex_indices(vertices(base()),
1652                                       get(vertex_index, base()));
1653 
1654     }
1655 
1656     ~adjacency_list()
1657     {
1658       synchronize(process_group_);
1659     }
1660 
1661     void clear()
1662     {
1663       base().clear();
1664       local_edges_.clear();
1665       named_graph_mixin::clearing_graph();
1666     }
1667 
1668     void swap(adjacency_list& other)
1669     {
1670       using std::swap;
1671 
1672       base().swap(other);
1673       swap(process_group_, other.process_group_);
1674     }
1675 
1676     static vertex_descriptor null_vertex()
1677     {
1678       return vertex_descriptor(processor_id_type(0),
1679                                inherited::null_vertex());
1680     }
1681 
1682     inherited&       base()       { return m_local_graph; }
1683     const inherited& base() const { return m_local_graph; }
1684 
1685     processor_id_type processor() const { return process_id(process_group_); }
1686     process_group_type process_group() const { return process_group_.base(); }
1687 
1688     local_edge_list_type&       local_edges()       { return local_edges_; }
1689     const local_edge_list_type& local_edges() const { return local_edges_; }
1690 
1691     // Redistribute the vertices of the graph by placing each vertex
1692     // v on the processor get(vertex_to_processor, v).
1693     template<typename VertexProcessorMap>
1694     void redistribute(VertexProcessorMap vertex_to_processor);
1695 
1696     // Directly access a vertex or edge bundle
1697     vertex_bundled& operator[](vertex_descriptor v)
1698     {
1699       BOOST_ASSERT(v.owner == processor());
1700       return base()[v.local];
1701     }
1702     
1703     const vertex_bundled& operator[](vertex_descriptor v) const
1704     {
1705       BOOST_ASSERT(v.owner == processor());
1706       return base()[v.local];
1707     }
1708     
1709     edge_bundled& operator[](edge_descriptor e)
1710     {
1711       BOOST_ASSERT(e.owner() == processor());
1712       return base()[e.local];
1713     }
1714     
1715     const edge_bundled& operator[](edge_descriptor e) const
1716     {
1717       BOOST_ASSERT(e.owner() == processor());
1718       return base()[e.local];
1719     }
1720 
1721     graph_bundled& operator[](graph_bundle_t)
1722     { return get_property(*this); }
1723 
1724     graph_bundled const& operator[](graph_bundle_t) const
1725     { return get_property(*this); }
1726 
1727     template<typename OStreamConstructibleArchive>
1728     void save(std::string const& filename) const;
1729 
1730     template<typename IStreamConstructibleArchive>
1731     void load(std::string const& filename);
1732 
1733     // Callback that will be invoked whenever a new vertex is added locally
1734     boost::function<void(vertex_descriptor, adjacency_list&)> on_add_vertex;
1735 
1736     // Callback that will be invoked whenever a new edge is added locally
1737     boost::function<void(edge_descriptor, adjacency_list&)> on_add_edge;
1738 
1739   private:
1740     // Request vertex->processor mapping for neighbors <does nothing>
1741     template<typename VertexProcessorMap>
1742     void
1743     request_in_neighbors(vertex_descriptor,
1744                          VertexProcessorMap,
1745                          directedS) { }
1746 
1747     // Request vertex->processor mapping for neighbors <does nothing>
1748     template<typename VertexProcessorMap>
1749     void
1750     request_in_neighbors(vertex_descriptor,
1751                          VertexProcessorMap,
1752                          undirectedS) { }
1753 
1754     // Request vertex->processor mapping for neighbors
1755     template<typename VertexProcessorMap>
1756     void
1757     request_in_neighbors(vertex_descriptor v,
1758                          VertexProcessorMap vertex_to_processor,
1759                          bidirectionalS);
1760 
1761     // Clear the list of in-edges, but don't tell the remote processor
1762     void clear_in_edges_local(vertex_descriptor v, directedS) {}
1763     void clear_in_edges_local(vertex_descriptor v, undirectedS) {}
1764 
1765     void clear_in_edges_local(vertex_descriptor v, bidirectionalS)
1766     { get(vertex_in_edges, base())[v.local].clear(); }
1767 
1768     // Remove in-edges that have migrated <does nothing>
1769     template<typename VertexProcessorMap>
1770     void
1771     remove_migrated_in_edges(vertex_descriptor,
1772                              VertexProcessorMap,
1773                              directedS) { }
1774 
1775     // Remove in-edges that have migrated <does nothing>
1776     template<typename VertexProcessorMap>
1777     void
1778     remove_migrated_in_edges(vertex_descriptor,
1779                              VertexProcessorMap,
1780                              undirectedS) { }
1781 
1782     // Remove in-edges that have migrated
1783     template<typename VertexProcessorMap>
1784     void
1785     remove_migrated_in_edges(vertex_descriptor v,
1786                              VertexProcessorMap vertex_to_processor,
1787                              bidirectionalS);
1788 
1789     // Initialize the graph with the given edge list and vertex
1790     // distribution. This variation works only when
1791     // VertexListS=vecS, and we know how to create remote vertex
1792     // descriptors based solely on the distribution.
1793     template<typename EdgeIterator>
1794     void
1795     initialize(EdgeIterator first, EdgeIterator last,
1796                vertices_size_type, const base_distribution_type& distribution, 
1797                vecS);
1798 
1799     // Initialize the graph with the given edge list, edge
1800     // properties, and vertex distribution. This variation works
1801     // only when VertexListS=vecS, and we know how to create remote
1802     // vertex descriptors based solely on the distribution.
1803     template<typename EdgeIterator, typename EdgePropertyIterator>
1804     void
1805     initialize(EdgeIterator first, EdgeIterator last,
1806                EdgePropertyIterator ep_iter,
1807                vertices_size_type, const base_distribution_type& distribution, 
1808                vecS);
1809 
1810     // Initialize the graph with the given edge list, edge
1811     // properties, and vertex distribution.
1812     template<typename EdgeIterator, typename EdgePropertyIterator,
1813              typename VertexListS>
1814     void
1815     initialize(EdgeIterator first, EdgeIterator last,
1816                EdgePropertyIterator ep_iter,
1817                vertices_size_type n, 
1818                const base_distribution_type& distribution,
1819                VertexListS);
1820 
1821     // Initialize the graph with the given edge list and vertex
1822     // distribution. This is nearly identical to the one below it,
1823     // for which I should be flogged. However, this version does use
1824     // slightly less memory than the version that accepts an edge
1825     // property iterator.
1826     template<typename EdgeIterator, typename VertexListS>
1827     void
1828     initialize(EdgeIterator first, EdgeIterator last,
1829                vertices_size_type n, 
1830                const base_distribution_type& distribution,
1831                VertexListS);
1832 
1833   public:
1834     //---------------------------------------------------------------------
1835     // Build a vertex property instance for the underlying adjacency
1836     // list from the given property instance of the type exposed to
1837     // the user.
1838     base_vertex_property_type 
1839     build_vertex_property(const vertex_property_type& p)
1840     { return build_vertex_property(p, directed_selector()); }
1841 
1842     base_vertex_property_type
1843     build_vertex_property(const vertex_property_type& p, directedS)
1844     {
1845       return base_vertex_property_type(p);
1846     }
1847 
1848     base_vertex_property_type
1849     build_vertex_property(const vertex_property_type& p, bidirectionalS)
1850     {
1851       return base_vertex_property_type(in_edge_list_type(), p);
1852     }
1853 
1854     base_vertex_property_type
1855     build_vertex_property(const vertex_property_type& p, undirectedS)
1856     {
1857       return base_vertex_property_type(p);
1858     }
1859     //---------------------------------------------------------------------
1860 
1861     //---------------------------------------------------------------------
1862     // Build an edge property instance for the underlying adjacency
1863     // list from the given property instance of the type exposed to
1864     // the user.
1865     base_edge_property_type build_edge_property(const edge_property_type& p)
1866     { return build_edge_property(p, directed_selector()); }
1867 
1868     base_edge_property_type
1869     build_edge_property(const edge_property_type& p, directedS)
1870     {
1871       return base_edge_property_type(0, p);
1872     }
1873 
1874     base_edge_property_type
1875     build_edge_property(const edge_property_type& p, bidirectionalS)
1876     {
1877       return base_edge_property_type(0, p);
1878     }
1879 
1880     base_edge_property_type
1881     build_edge_property(const edge_property_type& p, undirectedS)
1882     {
1883       typedef typename base_edge_property_type::next_type
1884         edge_property_with_id;
1885       return base_edge_property_type(true, edge_property_with_id(0, p));
1886     }
1887     //---------------------------------------------------------------------
1888 
1889     //---------------------------------------------------------------------
1890     // Opposite of above.
1891     edge_property_type split_edge_property(const base_edge_property_type& p)
1892     { return split_edge_property(p, directed_selector()); }
1893 
1894     edge_property_type
1895     split_edge_property(const base_edge_property_type& p, directedS)
1896     {
1897       return p.m_base;
1898     }
1899 
1900     edge_property_type
1901     split_edge_property(const base_edge_property_type& p, bidirectionalS)
1902     {
1903       return p.m_base;
1904     }
1905 
1906     edge_property_type
1907     split_edge_property(const base_edge_property_type& p, undirectedS)
1908     {
1909       return p.m_base.m_base;
1910     }
1911     //---------------------------------------------------------------------
1912 
1913     /** The set of messages that can be transmitted and received by
1914      *  a distributed adjacency list. This list will eventually be
1915      *  exhaustive, but is currently quite limited.
1916      */
1917     enum {
1918       /**
1919        * Request to add or find a vertex with the given vertex
1920        * property. The data will be a vertex_property_type
1921        * structure.
1922        */
1923       msg_add_vertex_with_property = 0,
1924 
1925       /**
1926        * Request to add or find a vertex with the given vertex
1927        * property, and request that the remote processor return the
1928        * descriptor for the added/found edge. The data will be a
1929        * vertex_property_type structure.
1930        */
1931       msg_add_vertex_with_property_and_reply,
1932 
1933       /**
1934        * Reply to a msg_add_vertex_* message, containing the local
1935        * vertex descriptor that was added or found.
1936        */
1937       msg_add_vertex_reply,
1938 
1939       /**
1940        * Request to add an edge remotely. The data will be a
1941        * msg_add_edge_data structure. 
1942        */
1943       msg_add_edge,
1944 
1945       /**
1946        * Request to add an edge remotely. The data will be a
1947        * msg_add_edge_with_property_data structure. 
1948        */
1949       msg_add_edge_with_property,
1950 
1951       /**
1952        * Request to add an edge remotely and reply back with the
1953        * edge descriptor. The data will be a
1954        * msg_add_edge_data structure. 
1955        */
1956       msg_add_edge_with_reply,
1957 
1958       /**
1959        * Request to add an edge remotely and reply back with the
1960        * edge descriptor. The data will be a
1961        * msg_add_edge_with_property_data structure.
1962        */
1963       msg_add_edge_with_property_and_reply,
1964 
1965       /**
1966        * Reply message responding to an @c msg_add_edge_with_reply
1967        * or @c msg_add_edge_with_property_and_reply messages. The
1968        * data will be a std::pair<edge_descriptor, bool>.
1969        */
1970       msg_add_edge_reply,
1971 
1972       /**
1973        * Indicates that a nonlocal edge has been created that should
1974        * be added locally. Only valid for bidirectional and
1975        * undirected graphs. The message carries a
1976        * msg_nonlocal_edge_data structure.
1977        */
1978       msg_nonlocal_edge,
1979 
1980       /**
1981        * Indicates that a remote edge should be removed. This
1982        * message does not exist for directedS graphs but may refer
1983        * to either in-edges or out-edges for undirectedS graphs.
1984        */
1985       msg_remove_edge,
1986 
1987       /**
1988        * Indicates the number of vertices and edges that will be
1989        * relocated from the source processor to the target
1990        * processor. The data will be a pair<vertices_size_type,
1991        * edges_size_type>.
1992        */
1993       msg_num_relocated
1994     };
1995 
1996     typedef detail::parallel::msg_add_edge_data<vertex_descriptor,
1997                                                 local_vertex_descriptor>
1998       msg_add_edge_data;
1999 
2000     typedef detail::parallel::msg_add_edge_with_property_data
2001               <vertex_descriptor, local_vertex_descriptor, 
2002                edge_property_type> msg_add_edge_with_property_data;
2003 
2004     typedef  boost::detail::parallel::msg_nonlocal_edge_data<
2005       edge_property_type,local_edge_descriptor> msg_nonlocal_edge_data;
2006 
2007     typedef boost::detail::parallel::msg_remove_edge_data<edge_descriptor>
2008       msg_remove_edge_data;
2009 
2010     void send_remove_edge_request(edge_descriptor e)
2011     {
2012       process_id_type dest = e.target_processor;
2013       if (e.target_processor == process_id(process_group_))
2014         dest = e.source_processor;
2015       send(process_group_, dest, msg_remove_edge, msg_remove_edge_data(e));
2016     }
2017 
2018     /// Process incoming messages.
2019     void setup_triggers();
2020 
2021     void 
2022     handle_add_vertex_with_property(int source, int tag,
2023                                     const vertex_property_type&,
2024                                     trigger_receive_context);
2025 
2026     local_vertex_descriptor
2027     handle_add_vertex_with_property_and_reply(int source, int tag,
2028                                         const vertex_property_type&,
2029                                         trigger_receive_context);
2030 
2031     void 
2032     handle_add_edge(int source, int tag, const msg_add_edge_data& data,
2033                     trigger_receive_context);
2034 
2035     boost::parallel::detail::untracked_pair<edge_descriptor, bool>
2036     handle_add_edge_with_reply(int source, int tag, 
2037                          const msg_add_edge_data& data,
2038                          trigger_receive_context);
2039 
2040     void 
2041     handle_add_edge_with_property(int source, int tag,
2042                                   const msg_add_edge_with_property_data&,
2043                                   trigger_receive_context);
2044               
2045     boost::parallel::detail::untracked_pair<edge_descriptor, bool>
2046     handle_add_edge_with_property_and_reply
2047       (int source, int tag, const msg_add_edge_with_property_data&,
2048        trigger_receive_context);
2049 
2050     void 
2051     handle_nonlocal_edge(int source, int tag, 
2052                          const msg_nonlocal_edge_data& data,
2053                          trigger_receive_context);
2054 
2055     void 
2056     handle_remove_edge(int source, int tag, 
2057                        const msg_remove_edge_data& data,
2058                        trigger_receive_context);
2059          
2060   protected:
2061     /** Add an edge (locally) that was received from another
2062      * processor. This operation is a no-op for directed graphs,
2063      * because all edges reside on the local processor. For
2064      * bidirectional graphs, this routine places the edge onto the
2065      * list of incoming edges for the target vertex. For undirected
2066      * graphs, the edge is placed along with all of the other edges
2067      * for the target vertex, but it is marked as a non-local edge
2068      * descriptor.
2069      *
2070      * \todo There is a potential problem here, where we could
2071      * unintentionally allow duplicate edges in undirected graphs
2072      * because the same edge is added on two different processors
2073      * simultaneously. It's not an issue now, because we require
2074      * that the graph allow parallel edges. Once we do support
2075      * containers such as setS or hash_setS that disallow parallel
2076      * edges we will need to deal with this.
2077      */
2078     void
2079     add_remote_edge(const msg_nonlocal_edge_data&,
2080                     processor_id_type, directedS)
2081     { }
2082 
2083 
2084     /**
2085      * \overload
2086      */
2087     void
2088     add_remote_edge(const msg_nonlocal_edge_data& data,
2089                     processor_id_type other_proc, bidirectionalS)
2090     {
2091       typedef detail::parallel::stored_in_edge<local_edge_descriptor> stored_edge;
2092 
2093       stored_edge edge(other_proc, data.e);
2094       local_vertex_descriptor v = target(data.e, base());
2095       boost::graph_detail::push(get(vertex_in_edges, base())[v], edge);
2096     }
2097 
2098     /**
2099      * \overload
2100      */
2101     void
2102     add_remote_edge(const msg_nonlocal_edge_data& data,
2103                     processor_id_type other_proc, undirectedS)
2104     {
2105       std::pair<local_edge_descriptor, bool> edge =
2106         detail::parallel::add_local_edge(target(data.e, base()), 
2107                        source(data.e, base()),
2108                        build_edge_property(data.get_property()), base());
2109       BOOST_ASSERT(edge.second);
2110       put(edge_target_processor_id, base(), edge.first, other_proc);
2111 
2112       if (edge.second && on_add_edge)
2113         on_add_edge(edge_descriptor(processor(), other_proc, false, 
2114                                     edge.first),
2115                     *this);
2116     }
2117 
2118     void
2119     remove_local_edge(const msg_remove_edge_data&, processor_id_type,
2120                       directedS)
2121     { }
2122 
2123     void
2124     remove_local_edge(const msg_remove_edge_data& data,
2125                       processor_id_type other_proc, bidirectionalS)
2126     {
2127       /* When the source is local, we first check if the edge still
2128        * exists (it may have been deleted locally) and, if so,
2129        * remove it locally.
2130        */
2131       vertex_descriptor src = source(data.e, *this);
2132       vertex_descriptor tgt = target(data.e, *this);
2133 
2134       if (src.owner == process_id(process_group_)) {
2135         base_out_edge_iterator ei, ei_end;
2136         for (boost::tie(ei, ei_end) = out_edges(src.local, base());
2137              ei != ei_end; ++ei) {
2138           // TBD: can't check the descriptor here, because it could
2139           // have changed if we're allowing the removal of
2140           // edges. Egads!
2141           if (tgt.local == target(*ei, base())
2142               && get(edge_target_processor_id, base(), *ei) == other_proc)
2143             break;
2144         }
2145 
2146         if (ei != ei_end) boost::remove_edge(ei, base());
2147 
2148         remove_local_edge_from_list(src, tgt, undirectedS());
2149       } else {
2150         BOOST_ASSERT(tgt.owner == process_id(process_group_));
2151         in_edge_list_type& in_edges =
2152           get(vertex_in_edges, base())[tgt.local];
2153         typename in_edge_list_type::iterator ei;
2154         for (ei = in_edges.begin(); ei != in_edges.end(); ++ei) {
2155           if (src.local == source(ei->e, base())
2156               && src.owner == ei->source_processor)
2157             break;
2158         }
2159 
2160         if (ei != in_edges.end()) in_edges.erase(ei);
2161       }
2162     }
2163 
2164     void
2165     remove_local_edge(const msg_remove_edge_data& data,
2166                       processor_id_type other_proc, undirectedS)
2167     {
2168       vertex_descriptor local_vertex = source(data.e, *this);
2169       vertex_descriptor remote_vertex = target(data.e, *this);
2170       if (remote_vertex.owner == process_id(process_group_)) {
2171         using std::swap;
2172         swap(local_vertex, remote_vertex);
2173       }
2174 
2175       // Remove the edge from the out-edge list, if it is there
2176       {
2177         base_out_edge_iterator ei, ei_end;
2178         for (boost::tie(ei, ei_end) = out_edges(local_vertex.local, base());
2179              ei != ei_end; ++ei) {
2180           // TBD: can't check the descriptor here, because it could
2181           // have changed if we're allowing the removal of
2182           // edges. Egads!
2183           if (remote_vertex.local == target(*ei, base())
2184               && get(edge_target_processor_id, base(), *ei) == other_proc)
2185             break;
2186         }
2187 
2188         if (ei != ei_end) boost::remove_edge(ei, base());
2189       }
2190 
2191       remove_local_edge_from_list(local_vertex, remote_vertex, undirectedS());
2192     }
2193 
2194   public:
2195     void
2196     remove_local_edge_from_list(vertex_descriptor, vertex_descriptor,
2197                                 directedS)
2198     {
2199     }
2200 
2201     void
2202     remove_local_edge_from_list(vertex_descriptor, vertex_descriptor,
2203                                 bidirectionalS)
2204     {
2205     }
2206 
2207     void
2208     remove_local_edge_from_list(vertex_descriptor src, vertex_descriptor tgt,
2209                                 undirectedS)
2210     {
2211       // TBD: At some point we'll be able to improve the speed here
2212       // because we'll know when the edge can't be in the local
2213       // list.
2214       {
2215         typename local_edge_list_type::iterator ei;
2216         for (ei = local_edges_.begin(); ei != local_edges_.end(); ++ei) {
2217           if ((source(*ei, *this) == src
2218                && target(*ei, *this) == tgt)
2219               || (source(*ei, *this) == tgt
2220                   && target(*ei, *this) == src))
2221             break;
2222         }
2223 
2224         if (ei != local_edges_.end()) local_edges_.erase(ei);
2225       }
2226 
2227     }
2228 
2229   private:
2230     /// The local subgraph
2231     inherited m_local_graph;
2232 
2233     /// The process group through which this distributed graph
2234     /// communicates.
2235     process_group_type process_group_;
2236 
2237     // TBD: should only be available for undirected graphs, but for
2238     // now it'll just be empty for directed and bidirectional
2239     // graphs.
2240     local_edge_list_type local_edges_;
2241   };
2242 
2243   //------------------------------------------------------------------------
2244   // Lazy addition of vertices
2245   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
2246   struct PBGL_DISTRIB_ADJLIST_TYPE::lazy_add_vertex_with_property
2247   {
2248     /// Construct a lazy request to add a vertex
2249     lazy_add_vertex_with_property(adjacency_list& self, 
2250                                   const vertex_property_type& property)
2251       : self(self), property(property), committed(false) { }
2252 
2253     /// Copying a lazy_add_vertex_with_property transfers the
2254     /// responsibility for adding the vertex to the newly-constructed
2255     /// object.
2256     lazy_add_vertex_with_property(const lazy_add_vertex_with_property& other)
2257       : self(other.self), property(other.property),
2258         committed(other.committed)
2259     {
2260       other.committed = true;
2261     }
2262 
2263     /// If the vertex has not yet been added, add the vertex but don't
2264     /// wait for a reply.
2265     ~lazy_add_vertex_with_property();
2266 
2267     /// Returns commit().
2268     operator vertex_descriptor() const { return commit(); }
2269 
2270     // Add the vertex. This operation will block if the vertex is
2271     // being added remotely.
2272     vertex_descriptor commit() const;
2273 
2274   protected:
2275     adjacency_list& self;
2276     vertex_property_type property;
2277     mutable bool committed;
2278 
2279   private:
2280     // No copy-assignment semantics
2281     void operator=(lazy_add_vertex_with_property&);
2282   };
2283 
2284   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
2285   PBGL_DISTRIB_ADJLIST_TYPE::lazy_add_vertex_with_property::
2286   ~lazy_add_vertex_with_property()
2287   {
2288     /// If this vertex has already been created or will be created by
2289     /// someone else, or if someone threw an exception, we will not
2290     /// create the vertex now.
2291     if (committed || boost::core::uncaught_exceptions() > 0)
2292       return;
2293 
2294     committed = true;
2295 
2296     process_id_type owner 
2297       = static_cast<graph_type&>(self).owner_by_property(property);
2298     if (owner == self.processor()) {
2299       /// Add the vertex locally.
2300       vertex_descriptor v(owner, 
2301                           add_vertex(self.build_vertex_property(property), 
2302                                      self.base()));
2303       if (self.on_add_vertex)
2304         self.on_add_vertex(v, self);
2305     }
2306     else
2307       /// Ask the owner of this new vertex to add the vertex. We
2308       /// don't need a reply.
2309       send(self.process_group_, owner, msg_add_vertex_with_property,
2310            property);
2311   }
2312 
2313   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
2314   typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor 
2315   PBGL_DISTRIB_ADJLIST_TYPE::lazy_add_vertex_with_property::
2316   commit() const
2317   {
2318     BOOST_ASSERT(!this->committed);
2319     this->committed = true;
2320 
2321     process_id_type owner 
2322       = static_cast<graph_type&>(self).owner_by_property(property);
2323     local_vertex_descriptor local_v;
2324     if (owner == self.processor())
2325       /// Add the vertex locally.
2326       local_v = add_vertex(self.build_vertex_property(property), 
2327                            self.base());
2328     else {
2329       // Request that the remote process add the vertex immediately
2330       send_oob_with_reply(self.process_group_, owner,
2331                msg_add_vertex_with_property_and_reply, property,
2332                local_v);
2333     }
2334 
2335     vertex_descriptor v(owner, local_v);
2336     if (self.on_add_vertex)
2337       self.on_add_vertex(v, self);
2338 
2339     // Build the full vertex descriptor to return
2340     return v;
2341   }
2342   
2343 
2344   /** 
2345    * Data structure returned from add_edge that will "lazily" add
2346    * the edge, either when it is converted to a
2347    * @c pair<edge_descriptor, bool> or when the most recent copy has
2348    * been destroyed.
2349    */
2350   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
2351   struct PBGL_DISTRIB_ADJLIST_TYPE::lazy_add_edge
2352   {
2353     /// Construct a lazy request to add an edge
2354     lazy_add_edge(adjacency_list& self, 
2355                   vertex_descriptor source, vertex_descriptor target)
2356       : self(self), source(source), target(target), committed(false) { }
2357 
2358     /// Copying a lazy_add_edge transfers the responsibility for
2359     /// adding the edge to the newly-constructed object.
2360     lazy_add_edge(const lazy_add_edge& other)
2361       : self(other.self), source(other.source), target(other.target), 
2362         committed(other.committed)
2363     {
2364       other.committed = true;
2365     }
2366 
2367     /// If the edge has not yet been added, add the edge but don't
2368     /// wait for a reply.
2369     ~lazy_add_edge();
2370 
2371     /// Returns commit().
2372     operator std::pair<edge_descriptor, bool>() const { return commit(); }
2373 
2374     // Add the edge. This operation will block if a remote edge is
2375     // being added.
2376     std::pair<edge_descriptor, bool> commit() const;
2377 
2378   protected:
2379     std::pair<edge_descriptor, bool> 
2380     add_local_edge(const edge_property_type& property, directedS) const;
2381 
2382     std::pair<edge_descriptor, bool> 
2383     add_local_edge(const edge_property_type& property, bidirectionalS) const;
2384 
2385     std::pair<edge_descriptor, bool> 
2386     add_local_edge(const edge_property_type& property, undirectedS) const;
2387 
2388     adjacency_list& self;
2389     vertex_descriptor source;
2390     vertex_descriptor target;
2391     mutable bool committed;
2392 
2393   private:
2394     // No copy-assignment semantics
2395     void operator=(lazy_add_edge&);
2396   };
2397 
2398   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
2399   PBGL_DISTRIB_ADJLIST_TYPE::lazy_add_edge::~lazy_add_edge()
2400   {
2401     /// If this edge has already been created or will be created by
2402     /// someone else, or if someone threw an exception, we will not
2403     /// create the edge now.
2404     if (committed || boost::core::uncaught_exceptions() > 0)
2405       return;
2406 
2407     committed = true;
2408 
2409     if (source.owner == self.processor())
2410       this->add_local_edge(edge_property_type(), DirectedS());
2411     else
2412       // Request that the remote processor add an edge and, but
2413       // don't wait for a reply.
2414       send(self.process_group_, source.owner, msg_add_edge,
2415            msg_add_edge_data(source, target));
2416   }
2417 
2418   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
2419   std::pair<typename PBGL_DISTRIB_ADJLIST_TYPE::edge_descriptor, bool>
2420   PBGL_DISTRIB_ADJLIST_TYPE::lazy_add_edge::commit() const
2421   {
2422     BOOST_ASSERT(!committed);
2423     committed = true;
2424 
2425     if (source.owner == self.processor())
2426       return this->add_local_edge(edge_property_type(), DirectedS());
2427     else {
2428       // Request that the remote processor add an edge
2429       boost::parallel::detail::untracked_pair<edge_descriptor, bool> result;
2430       send_oob_with_reply(self.process_group_, source.owner, 
2431                           msg_add_edge_with_reply,
2432                           msg_add_edge_data(source, target), result);
2433       return result;
2434     }
2435   }
2436 
2437   // Add a local edge into a directed graph
2438   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
2439   std::pair<typename PBGL_DISTRIB_ADJLIST_TYPE::edge_descriptor, bool>
2440   PBGL_DISTRIB_ADJLIST_TYPE::lazy_add_edge::
2441   add_local_edge(const edge_property_type& property, directedS) const
2442   {
2443     // Add the edge to the local part of the graph
2444     std::pair<local_edge_descriptor, bool> inserted =
2445       detail::parallel::add_local_edge(source.local, target.local,
2446                                        self.build_edge_property(property), 
2447                                        self.base());
2448 
2449     if (inserted.second)
2450       // Keep track of the owner of the target
2451       put(edge_target_processor_id, self.base(), inserted.first, 
2452           target.owner);
2453 
2454     // Compose the edge descriptor and return the result
2455     edge_descriptor e(source.owner, target.owner, true, inserted.first);
2456 
2457     // Trigger the on_add_edge event
2458     if (inserted.second && self.on_add_edge)
2459       self.on_add_edge(e, self);
2460 
2461     return std::pair<edge_descriptor, bool>(e, inserted.second);
2462   }
2463 
2464   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
2465   std::pair<typename PBGL_DISTRIB_ADJLIST_TYPE::edge_descriptor, bool>
2466   PBGL_DISTRIB_ADJLIST_TYPE::lazy_add_edge::
2467   add_local_edge(const edge_property_type& property, bidirectionalS) const
2468   {
2469     // Add the directed edge.
2470     std::pair<edge_descriptor, bool> result 
2471       = this->add_local_edge(property, directedS());
2472 
2473     if (result.second) {
2474       if (target.owner == self.processor()) {
2475         // Edge is local, so add the stored edge to the in_edges list
2476         typedef detail::parallel::stored_in_edge<local_edge_descriptor>
2477           stored_edge;
2478 
2479         stored_edge e(self.processor(), result.first.local);
2480         boost::graph_detail::push(get(vertex_in_edges, 
2481                                       self.base())[target.local], e);
2482       } 
2483       else {
2484         // Edge is remote, so notify the target's owner that an edge
2485         // has been added.
2486         if (self.process_group_.trigger_context() == boost::parallel::trc_out_of_band)
2487           send_oob(self.process_group_, target.owner, msg_nonlocal_edge,
2488                    msg_nonlocal_edge_data(result.first.local, property));
2489         else
2490           send(self.process_group_, target.owner, msg_nonlocal_edge,
2491                msg_nonlocal_edge_data(result.first.local, property));
2492       }
2493     }
2494 
2495     return result;
2496   }
2497 
2498   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
2499   std::pair<typename PBGL_DISTRIB_ADJLIST_TYPE::edge_descriptor, bool>
2500   PBGL_DISTRIB_ADJLIST_TYPE::lazy_add_edge::
2501   add_local_edge(const edge_property_type& property, undirectedS) const
2502   {
2503     // Add the directed edge
2504     std::pair<edge_descriptor, bool> result
2505       = this->add_local_edge(property, directedS());
2506 
2507     if (result.second) {
2508       if (target.owner == self.processor()) {
2509         // Edge is local, so add the new edge to the list
2510 
2511         // TODO: This is not what we want to do for an undirected
2512         // edge, because we haven't linked the source and target's
2513         // representations of those edges.
2514         local_edge_descriptor return_edge =
2515           detail::parallel::add_local_edge(target.local, source.local,
2516                                            self.build_edge_property(property),
2517                                            self.base()).first;
2518 
2519         put(edge_target_processor_id, self.base(), return_edge, 
2520             source.owner);
2521       }
2522       else {
2523         // Edge is remote, so notify the target's owner that an edge
2524         // has been added.
2525         if (self.process_group_.trigger_context() == boost::parallel::trc_out_of_band)
2526           send_oob(self.process_group_, target.owner, msg_nonlocal_edge,
2527                    msg_nonlocal_edge_data(result.first.local, property));
2528         else
2529           send(self.process_group_, target.owner, msg_nonlocal_edge,
2530                msg_nonlocal_edge_data(result.first.local, property));
2531           
2532       }
2533 
2534       // Add this edge to the list of local edges
2535       graph_detail::push(self.local_edges(), result.first);
2536     }
2537 
2538     return result;
2539   }
2540 
2541 
2542   /** 
2543    * Data structure returned from add_edge that will "lazily" add
2544    * the edge with its property, either when it is converted to a
2545    * pair<edge_descriptor, bool> or when the most recent copy has
2546    * been destroyed.
2547    */
2548   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
2549   struct PBGL_DISTRIB_ADJLIST_TYPE::lazy_add_edge_with_property
2550     : lazy_add_edge
2551   {
2552     /// Construct a lazy request to add an edge
2553     lazy_add_edge_with_property(adjacency_list& self, 
2554                                 vertex_descriptor source, 
2555                                 vertex_descriptor target,
2556                                 const edge_property_type& property)
2557       : lazy_add_edge(self, source, target), property(property) { }
2558 
2559     /// Copying a lazy_add_edge transfers the responsibility for
2560     /// adding the edge to the newly-constructed object.
2561     lazy_add_edge_with_property(const lazy_add_edge& other)
2562       : lazy_add_edge(other), property(other.property) { }
2563 
2564     /// If the edge has not yet been added, add the edge but don't
2565     /// wait for a reply.
2566     ~lazy_add_edge_with_property();
2567 
2568     /// Returns commit().
2569     operator std::pair<edge_descriptor, bool>() const { return commit(); }
2570 
2571     // Add the edge. This operation will block if a remote edge is
2572     // being added.
2573     std::pair<edge_descriptor, bool> commit() const;
2574 
2575   private:
2576     // No copy-assignment semantics
2577     void operator=(lazy_add_edge_with_property&);
2578 
2579     edge_property_type property;
2580   };
2581 
2582   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
2583   PBGL_DISTRIB_ADJLIST_TYPE::lazy_add_edge_with_property::
2584   ~lazy_add_edge_with_property()
2585   {
2586     /// If this edge has already been created or will be created by
2587     /// someone else, or if someone threw an exception, we will not
2588     /// create the edge now.
2589     if (this->committed || boost::core::uncaught_exceptions() > 0)
2590       return;
2591 
2592     this->committed = true;
2593 
2594     if (this->source.owner == this->self.processor())
2595       // Add a local edge
2596       this->add_local_edge(property, DirectedS());
2597     else
2598       // Request that the remote processor add an edge and, but
2599       // don't wait for a reply.
2600       send(this->self.process_group_, this->source.owner, 
2601            msg_add_edge_with_property,
2602            msg_add_edge_with_property_data(this->source, this->target, 
2603                                            property));
2604   }
2605 
2606   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
2607   std::pair<typename PBGL_DISTRIB_ADJLIST_TYPE::edge_descriptor, bool>
2608   PBGL_DISTRIB_ADJLIST_TYPE::lazy_add_edge_with_property::
2609   commit() const
2610   {
2611     BOOST_ASSERT(!this->committed);
2612     this->committed = true;
2613 
2614     if (this->source.owner == this->self.processor())
2615       // Add a local edge
2616       return this->add_local_edge(property, DirectedS());
2617     else {
2618       // Request that the remote processor add an edge
2619       boost::parallel::detail::untracked_pair<edge_descriptor, bool> result;
2620       send_oob_with_reply(this->self.process_group_, this->source.owner, 
2621                           msg_add_edge_with_property_and_reply,
2622                           msg_add_edge_with_property_data(this->source, 
2623                                                           this->target, 
2624                                                           property),
2625                           result);
2626       return result;
2627     }
2628   }
2629 
2630 
2631   /**
2632    * Returns the set of vertices local to this processor. Note that
2633    * although this routine matches a valid expression of a
2634    * VertexListGraph, it does not meet the semantic requirements of
2635    * VertexListGraph because it returns only local vertices (not all
2636    * vertices).
2637    */
2638   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
2639   std::pair<typename PBGL_DISTRIB_ADJLIST_TYPE
2640                        ::vertex_iterator,
2641             typename PBGL_DISTRIB_ADJLIST_TYPE
2642                        ::vertex_iterator>
2643   vertices(const PBGL_DISTRIB_ADJLIST_TYPE& g)
2644   {
2645     typedef typename PBGL_DISTRIB_ADJLIST_TYPE
2646       ::vertex_descriptor Vertex;
2647 
2648     typedef typename Vertex::generator generator;
2649 
2650     return std::make_pair(make_transform_iterator(vertices(g.base()).first,
2651                                                   generator(g.processor())),
2652                           make_transform_iterator(vertices(g.base()).second,
2653                                                   generator(g.processor())));
2654   }
2655 
2656   /**
2657    * Returns the number of vertices local to this processor. Note that
2658    * although this routine matches a valid expression of a
2659    * VertexListGraph, it does not meet the semantic requirements of
2660    * VertexListGraph because it returns only a count of local vertices
2661    * (not all vertices).
2662    */
2663   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
2664   typename PBGL_DISTRIB_ADJLIST_TYPE
2665              ::vertices_size_type
2666   num_vertices(const PBGL_DISTRIB_ADJLIST_TYPE& g)
2667   {
2668     return num_vertices(g.base());
2669   }
2670 
2671   /***************************************************************************
2672    * Implementation of Incidence Graph concept
2673    ***************************************************************************/
2674   /**
2675    * Returns the source of edge @param e in @param g.
2676    */
2677   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS, typename Edge>
2678   typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor
2679   source(const detail::parallel::edge_descriptor<Edge>& e,
2680          const PBGL_DISTRIB_ADJLIST_TYPE& g)
2681   {
2682     typedef typename PBGL_DISTRIB_ADJLIST_TYPE
2683       ::vertex_descriptor Vertex;
2684     return Vertex(e.source_processor, source(e.local, g.base()));
2685   }
2686 
2687   /**
2688    * Returns the target of edge @param e in @param g.
2689    */
2690   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS, typename Edge>
2691   typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor
2692   target(const detail::parallel::edge_descriptor<Edge>& e,
2693          const PBGL_DISTRIB_ADJLIST_TYPE& g)
2694   {
2695     typedef typename PBGL_DISTRIB_ADJLIST_TYPE
2696       ::vertex_descriptor Vertex;
2697     return Vertex(e.target_processor, target(e.local, g.base()));
2698   }
2699 
2700   /**
2701    * Return the set of edges outgoing from a particular vertex. The
2702    * vertex @param v must be local to the processor executing this
2703    * routine.
2704    */
2705   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
2706   std::pair<typename PBGL_DISTRIB_ADJLIST_TYPE::out_edge_iterator,
2707             typename PBGL_DISTRIB_ADJLIST_TYPE::out_edge_iterator>
2708   out_edges(typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor v,
2709             const PBGL_DISTRIB_ADJLIST_TYPE& g)
2710   {
2711     BOOST_ASSERT(v.owner == g.processor());
2712 
2713     typedef PBGL_DISTRIB_ADJLIST_TYPE impl;
2714     typedef typename impl::out_edge_generator generator;
2715 
2716     return std::make_pair(
2717              make_transform_iterator(out_edges(v.local, g.base()).first,
2718                                      generator(g)),
2719              make_transform_iterator(out_edges(v.local, g.base()).second,
2720                                      generator(g)));
2721   }
2722 
2723   /**
2724    * Return the number of edges outgoing from a particular vertex. The
2725    * vertex @param v must be local to the processor executing this
2726    * routine.
2727    */
2728   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
2729   typename PBGL_DISTRIB_ADJLIST_TYPE::degree_size_type
2730   out_degree(typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor v,
2731              const PBGL_DISTRIB_ADJLIST_TYPE& g)
2732   {
2733     BOOST_ASSERT(v.owner == g.processor());
2734 
2735     return out_degree(v.local, g.base());
2736   }
2737 
2738   /***************************************************************************
2739    * Implementation of Bidirectional Graph concept
2740    ***************************************************************************/
2741   /**
2742    * Returns the set of edges incoming to a particular vertex. The
2743    * vertex @param v must be local to the processor executing this
2744    * routine.
2745    */
2746   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG>
2747   std::pair<typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS)
2748                        ::in_edge_iterator,
2749             typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS)
2750                        ::in_edge_iterator>
2751   in_edges(typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS)
2752                          ::vertex_descriptor v,
2753            const PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS)& g)
2754   {
2755     BOOST_ASSERT(v.owner == g.processor());
2756 
2757     typedef PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS) impl;
2758     typedef typename impl::inherited base_graph_type;
2759     typedef typename impl::in_edge_generator generator;
2760 
2761 
2762     typename property_map<base_graph_type, vertex_in_edges_t>::const_type
2763       in_edges = get(vertex_in_edges, g.base());
2764 
2765     return std::make_pair(make_transform_iterator(in_edges[v.local].begin(),
2766                                                   generator(g)),
2767                           make_transform_iterator(in_edges[v.local].end(),
2768                                                   generator(g)));
2769   }
2770 
2771   /**
2772    * \overload
2773    */
2774   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG>
2775   std::pair<typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)
2776                        ::in_edge_iterator,
2777             typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)
2778                        ::in_edge_iterator>
2779   in_edges(typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)
2780                          ::vertex_descriptor v,
2781            const PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)& g)
2782   {
2783     BOOST_ASSERT(v.owner == g.processor());
2784 
2785     typedef PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS) impl;
2786     typedef typename impl::in_edge_generator generator;
2787 
2788     return std::make_pair(
2789               make_transform_iterator(out_edges(v.local, g.base()).first,
2790                                      generator(g)),
2791              make_transform_iterator(out_edges(v.local, g.base()).second,
2792                                      generator(g)));
2793   }
2794 
2795   /**
2796    * Returns the number of edges incoming to a particular vertex. The
2797    * vertex @param v must be local to the processor executing this
2798    * routine.
2799    */
2800   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG>
2801   typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS)::degree_size_type
2802   in_degree(typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS)
2803                            ::vertex_descriptor v,
2804             const PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS)& g)
2805   {
2806     BOOST_ASSERT(v.owner == g.processor());
2807 
2808     return get(vertex_in_edges, g.base())[v.local].size();
2809   }
2810 
2811   /**
2812    * \overload
2813    */
2814   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG>
2815   typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)::degree_size_type
2816   in_degree(typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)
2817                            ::vertex_descriptor v,
2818             const PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)& g)
2819   {
2820     BOOST_ASSERT(v.owner == g.processor());
2821 
2822     return out_degree(v.local, g.base());
2823   }
2824 
2825   /**
2826    * Returns the number of edges incident on the given vertex. The
2827    * vertex @param v must be local to the processor executing this
2828    * routine.
2829    */
2830   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG>
2831   typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)
2832                        ::degree_size_type
2833   degree(typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)
2834                          ::vertex_descriptor v,
2835          const PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)& g)
2836   {
2837     BOOST_ASSERT(v.owner == g.processor());
2838     return out_degree(v.local, g.base());
2839   }
2840 
2841   /**
2842    * \overload
2843    */
2844   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG>
2845   typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS)
2846                        ::degree_size_type
2847   degree(typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS)
2848                          ::vertex_descriptor v,
2849          const PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS)& g)
2850   {
2851     BOOST_ASSERT(v.owner == g.processor());
2852     return out_degree(v, g) + in_degree(v, g);
2853   }
2854 
2855   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
2856   typename PBGL_DISTRIB_ADJLIST_TYPE::edges_size_type
2857   num_edges(const PBGL_DISTRIB_ADJLIST_TYPE& g)
2858   {
2859     return num_edges(g.base());
2860   }
2861 
2862   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG>
2863   typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)::edges_size_type
2864   num_edges(const PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)& g)
2865   {
2866     return g.local_edges().size();
2867   }
2868 
2869   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
2870   std::pair<
2871     typename PBGL_DISTRIB_ADJLIST_TYPE::edge_iterator,
2872     typename PBGL_DISTRIB_ADJLIST_TYPE::edge_iterator>
2873   edges(const PBGL_DISTRIB_ADJLIST_TYPE& g)
2874   {
2875     typedef PBGL_DISTRIB_ADJLIST_TYPE impl;
2876     typedef typename impl::out_edge_generator generator;
2877 
2878     return std::make_pair(make_transform_iterator(edges(g.base()).first,
2879                                                   generator(g)),
2880                           make_transform_iterator(edges(g.base()).second,
2881                                                   generator(g)));
2882   }
2883 
2884   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG>
2885   std::pair<
2886     typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)::edge_iterator,
2887     typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)::edge_iterator>
2888   edges(const PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)& g)
2889   {
2890     return std::make_pair(g.local_edges().begin(), g.local_edges().end());
2891   }
2892 
2893   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
2894   inline
2895   typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor
2896   vertex(typename PBGL_DISTRIB_ADJLIST_TYPE::vertices_size_type n,
2897          const PBGL_DISTRIB_ADJLIST_TYPE& g)
2898   {
2899     typedef typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor 
2900       vertex_descriptor;
2901 
2902     return vertex_descriptor(g.distribution()(n), g.distribution().local(n));
2903   }
2904 
2905   /***************************************************************************
2906    * Access to particular edges
2907    ***************************************************************************/
2908   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG>
2909   std::pair<
2910     typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(directedS)::edge_descriptor,
2911     bool
2912   >
2913   edge(typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(directedS)::vertex_descriptor u,
2914        typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(directedS)::vertex_descriptor v,
2915        const PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(directedS)& g)
2916   {
2917     typedef typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(directedS)
2918                        ::edge_descriptor edge_descriptor;
2919 
2920     // For directed graphs, u must be local
2921     BOOST_ASSERT(u.owner == process_id(g.process_group()));
2922 
2923     typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(directedS)
2924         ::out_edge_iterator ei, ei_end;
2925     for (boost::tie(ei, ei_end) = out_edges(u, g); ei != ei_end; ++ei) {
2926       if (target(*ei, g) == v) return std::make_pair(*ei, true);
2927     }
2928     return std::make_pair(edge_descriptor(), false);
2929   }
2930 
2931   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
2932   std::pair<
2933     typename PBGL_DISTRIB_ADJLIST_TYPE::edge_descriptor,
2934     bool
2935   >
2936   edge(typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor u,
2937        typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor v,
2938        const PBGL_DISTRIB_ADJLIST_TYPE& g)
2939   {
2940     typedef typename PBGL_DISTRIB_ADJLIST_TYPE
2941                        ::edge_descriptor edge_descriptor;
2942 
2943     // For bidirectional and undirected graphs, u must be local or v
2944     // must be local
2945     if (u.owner == process_id(g.process_group())) {
2946       typename PBGL_DISTRIB_ADJLIST_TYPE::out_edge_iterator ei, ei_end;
2947       for (boost::tie(ei, ei_end) = out_edges(u, g); ei != ei_end; ++ei) {
2948         if (target(*ei, g) == v) return std::make_pair(*ei, true);
2949       }
2950       return std::make_pair(edge_descriptor(), false);
2951     } else if (v.owner == process_id(g.process_group())) {
2952       typename PBGL_DISTRIB_ADJLIST_TYPE::in_edge_iterator ei, ei_end;
2953       for (boost::tie(ei, ei_end) = in_edges(v, g); ei != ei_end; ++ei) {
2954         if (source(*ei, g) == u) return std::make_pair(*ei, true);
2955       }
2956       return std::make_pair(edge_descriptor(), false);
2957     } else {
2958       BOOST_ASSERT(false);
2959       abort();
2960     }
2961   }
2962 
2963 #if 0
2964   // TBD: not yet supported
2965   std::pair<out_edge_iterator, out_edge_iterator>
2966   edge_range(vertex_descriptor u, vertex_descriptor v,
2967              const adjacency_list& g);
2968 #endif
2969 
2970   /***************************************************************************
2971    * Implementation of Adjacency Graph concept
2972    ***************************************************************************/
2973   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
2974   std::pair<typename PBGL_DISTRIB_ADJLIST_TYPE::adjacency_iterator,
2975             typename PBGL_DISTRIB_ADJLIST_TYPE::adjacency_iterator>
2976   adjacent_vertices(typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor v,
2977                     const PBGL_DISTRIB_ADJLIST_TYPE& g)
2978   {
2979     typedef typename PBGL_DISTRIB_ADJLIST_TYPE::adjacency_iterator iter;
2980     return std::make_pair(iter(out_edges(v, g).first, &g),
2981                           iter(out_edges(v, g).second, &g));
2982   }
2983 
2984   /***************************************************************************
2985    * Implementation of Mutable Graph concept
2986    ***************************************************************************/
2987 
2988   /************************************************************************
2989    * add_edge
2990    ************************************************************************/
2991   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
2992   typename PBGL_DISTRIB_ADJLIST_TYPE::lazy_add_edge
2993   add_edge(typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor u,
2994            typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor v,
2995            PBGL_DISTRIB_ADJLIST_TYPE& g)
2996   {
2997     typedef typename PBGL_DISTRIB_ADJLIST_TYPE::lazy_add_edge lazy_add_edge;
2998 
2999     return lazy_add_edge(g, u, v);
3000   }
3001 
3002   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
3003   typename PBGL_DISTRIB_ADJLIST_TYPE
3004     ::lazy_add_edge_with_property
3005   add_edge(typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor u,
3006            typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor v,
3007            typename PBGL_DISTRIB_ADJLIST_TYPE::edge_property_type const& p,
3008            PBGL_DISTRIB_ADJLIST_TYPE& g)
3009   {
3010     typedef typename PBGL_DISTRIB_ADJLIST_TYPE
3011       ::lazy_add_edge_with_property lazy_add_edge_with_property;
3012     return lazy_add_edge_with_property(g, u, v, p);
3013   }
3014 
3015   /************************************************************************
3016    *
3017    * remove_edge
3018    *
3019    ************************************************************************/
3020   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
3021   void
3022   remove_edge(typename PBGL_DISTRIB_ADJLIST_TYPE::edge_descriptor e,
3023               PBGL_DISTRIB_ADJLIST_TYPE& g)
3024   {
3025     BOOST_ASSERT(source(e, g).owner == g.processor()
3026                  || target(e, g).owner == g.processor());
3027 
3028     if (target(e, g).owner == g.processor())
3029       detail::parallel::remove_in_edge(e, g, DirectedS());
3030     if (source(e, g).owner == g.processor())
3031       remove_edge(e.local, g.base());
3032 
3033     g.remove_local_edge_from_list(source(e, g), target(e, g), DirectedS());
3034 
3035     if (source(e, g).owner != g.processor()
3036         || (target(e, g).owner != g.processor()
3037             && !(is_same<DirectedS, directedS>::value))) {
3038       g.send_remove_edge_request(e);
3039     }
3040   }
3041 
3042   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
3043   void
3044   remove_edge(typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor u,
3045               typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor v,
3046               PBGL_DISTRIB_ADJLIST_TYPE& g)
3047   {
3048     typedef typename PBGL_DISTRIB_ADJLIST_TYPE
3049                        ::edge_descriptor edge_descriptor;
3050     std::pair<edge_descriptor, bool> the_edge = edge(u, v, g);
3051     if (the_edge.second) remove_edge(the_edge.first, g);
3052   }
3053 
3054   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
3055   inline void
3056   remove_edge(typename PBGL_DISTRIB_ADJLIST_TYPE::out_edge_iterator ei,
3057               PBGL_DISTRIB_ADJLIST_TYPE& g)
3058   {
3059     remove_edge(*ei, g);
3060   }
3061 
3062   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG>
3063   inline void
3064   remove_edge(typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(directedS)
3065                 ::out_edge_iterator ei,
3066               PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(directedS)& g)
3067   {
3068     BOOST_ASSERT(source(*ei, g).owner == g.processor());
3069     remove_edge(ei->local, g.base());
3070   }
3071 
3072   /************************************************************************
3073    *
3074    * remove_out_edge_if
3075    *
3076    ************************************************************************/
3077   namespace parallel { namespace detail {
3078     /**
3079      * Function object that applies the underlying predicate to
3080      * determine if an out-edge should be removed. If so, either
3081      * removes the incoming edge (if it is stored locally) or sends a
3082      * message to the owner of the target requesting that it remove
3083      * the edge.
3084      */
3085     template<typename Graph, typename Predicate>
3086     struct remove_out_edge_predicate
3087     {
3088       typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
3089       typedef typename Graph::local_edge_descriptor         argument_type;
3090       typedef typename Graph::directed_selector             directed_selector;
3091       typedef bool result_type;
3092 
3093       remove_out_edge_predicate(Graph& g, Predicate& predicate)
3094         : g(g), predicate(predicate) { }
3095 
3096       bool operator()(const argument_type& le)
3097       {
3098         typedef typename edge_descriptor::template out_generator<Graph>
3099           generator;
3100 
3101         edge_descriptor e = generator(g)(le);
3102 
3103         if (predicate(e)) {
3104           if (source(e, g).owner != target(e, g).owner
3105               && !(is_same<directed_selector, directedS>::value))
3106             g.send_remove_edge_request(e);
3107           else
3108             ::boost::detail::parallel::remove_in_edge(e, g,
3109                                                       directed_selector());
3110 
3111            g.remove_local_edge_from_list(source(e, g), target(e, g),
3112                                          directed_selector());
3113           return true;
3114         } else return false;
3115       }
3116 
3117     private:
3118       Graph& g;
3119       Predicate predicate;
3120     };
3121   } } // end namespace parallel::detail
3122 
3123   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS, typename Predicate>
3124   inline void
3125   remove_out_edge_if
3126      (typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor u,
3127       Predicate predicate,
3128       PBGL_DISTRIB_ADJLIST_TYPE& g)
3129   {
3130     typedef PBGL_DISTRIB_ADJLIST_TYPE Graph;
3131     typedef parallel::detail::remove_out_edge_predicate<Graph, Predicate>
3132       Pred;
3133 
3134     BOOST_ASSERT(u.owner == g.processor());
3135     remove_out_edge_if(u.local, Pred(g, predicate), g.base());
3136   }
3137 
3138   /************************************************************************
3139    *
3140    * remove_in_edge_if
3141    *
3142    ************************************************************************/
3143   namespace parallel { namespace detail {
3144     /**
3145      * Function object that applies the underlying predicate to
3146      * determine if an in-edge should be removed. If so, either
3147      * removes the outgoing edge (if it is stored locally) or sends a
3148      * message to the owner of the target requesting that it remove
3149      * the edge. Only required for bidirectional graphs.
3150      */
3151     template<typename Graph, typename Predicate>
3152     struct remove_in_edge_predicate
3153     {
3154       typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
3155       typedef bool result_type;
3156 
3157       remove_in_edge_predicate(Graph& g, const Predicate& predicate)
3158         : g(g), predicate(predicate) { }
3159 
3160       template<typename StoredEdge>
3161       bool operator()(const StoredEdge& le)
3162       {
3163         typedef typename edge_descriptor::template in_generator<Graph>
3164           generator;
3165 
3166         edge_descriptor e = generator(g)(le);
3167 
3168         if (predicate(e)) {
3169           if (source(e, g).owner != target(e, g).owner)
3170             g.send_remove_edge_request(e);
3171           else
3172             remove_edge(source(e, g).local, target(e, g).local, g.base());
3173           return true;
3174         } else return false;
3175       }
3176 
3177     private:
3178       Graph& g;
3179       Predicate predicate;
3180     };
3181   } } // end namespace parallel::detail
3182 
3183   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG, typename Predicate>
3184   inline void
3185   remove_in_edge_if
3186      (typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS)
3187                  ::vertex_descriptor u,
3188       Predicate predicate,
3189       PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS)& g)
3190   {
3191     typedef PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS) Graph;
3192     typedef parallel::detail::remove_in_edge_predicate<Graph, Predicate>
3193       Pred;
3194 
3195     BOOST_ASSERT(u.owner == g.processor());
3196     graph_detail::erase_if(get(vertex_in_edges, g.base())[u.local],
3197                            Pred(g, predicate));
3198   }
3199 
3200   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG, typename Predicate>
3201   inline void
3202   remove_in_edge_if
3203      (typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)
3204                  ::vertex_descriptor u,
3205       Predicate predicate,
3206       PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)& g)
3207   {
3208     remove_out_edge_if(u, predicate, g);
3209   }
3210 
3211   /************************************************************************
3212    *
3213    * remove_edge_if
3214    *
3215    ************************************************************************/
3216   namespace parallel { namespace detail {
3217     /**
3218      * Function object that applies the underlying predicate to
3219      * determine if a directed edge can be removed. This only applies
3220      * to directed graphs.
3221      */
3222     template<typename Graph, typename Predicate>
3223     struct remove_directed_edge_predicate
3224     {
3225       typedef typename Graph::local_edge_descriptor argument_type;
3226       typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
3227       typedef bool result_type;
3228 
3229       remove_directed_edge_predicate(Graph& g, const Predicate& predicate)
3230         : g(g), predicate(predicate) { }
3231 
3232       bool operator()(const argument_type& le)
3233       {
3234         typedef typename edge_descriptor::template out_generator<Graph>
3235           generator;
3236 
3237         edge_descriptor e = generator(g)(le);
3238         return predicate(e);
3239       }
3240 
3241     private:
3242       Graph& g;
3243       Predicate predicate;
3244     };
3245   } } // end namespace parallel::detail
3246 
3247   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG, typename Predicate>
3248   inline void
3249   remove_edge_if(Predicate predicate, 
3250                  PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(directedS)& g)
3251   {
3252     typedef PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(directedS) Graph;
3253     typedef parallel::detail::remove_directed_edge_predicate<Graph,
3254                                                              Predicate> Pred;
3255     remove_edge_if(Pred(g, predicate), g.base());
3256   }
3257 
3258   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG, typename Predicate>
3259   inline void
3260   remove_edge_if(Predicate predicate,
3261                  PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS)& g)
3262   {
3263     typedef PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS) Graph;
3264     typedef parallel::detail::remove_out_edge_predicate<Graph,
3265                                                         Predicate> Pred;
3266     remove_edge_if(Pred(g, predicate), g.base());
3267   }
3268 
3269   namespace parallel { namespace detail {
3270     /**
3271      * Function object that applies the underlying predicate to
3272      * determine if an undirected edge should be removed. If so,
3273      * removes the local edges associated with the edge and
3274      * (potentially) sends a message to the remote processor that also
3275      * is removing this edge.
3276      */
3277     template<typename Graph, typename Predicate>
3278     struct remove_undirected_edge_predicate
3279     {
3280       typedef typename graph_traits<Graph>::edge_descriptor argument_type;
3281       typedef bool result_type;
3282 
3283       remove_undirected_edge_predicate(Graph& g, Predicate& predicate)
3284         : g(g), predicate(predicate) { }
3285 
3286       bool operator()(const argument_type& e)
3287       {
3288         if (predicate(e)) {
3289           if (source(e, g).owner != target(e, g).owner)
3290             g.send_remove_edge_request(e);
3291           if (target(e, g).owner == g.processor())
3292             ::boost::detail::parallel::remove_in_edge(e, g, undirectedS());
3293           if (source(e, g).owner == g.processor())
3294             remove_edge(e.local, g.base());
3295           return true;
3296         } else return false;
3297       }
3298 
3299     private:
3300       Graph& g;
3301       Predicate predicate;
3302     };
3303   } } // end namespace parallel::detail
3304 
3305   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG, typename Predicate>
3306   inline void
3307   remove_edge_if(Predicate predicate,
3308                  PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)& g)
3309   {
3310     typedef PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS) Graph;
3311     typedef parallel::detail::remove_undirected_edge_predicate<Graph,
3312                                                                Predicate> Pred;
3313     graph_detail::erase_if(g.local_edges(), Pred(g, predicate));
3314   }
3315 
3316   /************************************************************************
3317    *
3318    * clear_vertex
3319    *
3320    ************************************************************************/
3321   namespace parallel { namespace detail {
3322     struct always_true
3323     {
3324       typedef bool result_type;
3325 
3326       template<typename T> bool operator()(const T&) const { return true; }
3327     };
3328   } } // end namespace parallel::detail
3329 
3330   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG>
3331   void
3332   clear_vertex
3333     (typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS)
3334           ::vertex_descriptor u,
3335       PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS)& g)
3336   {
3337     clear_out_edges(u, g);
3338     clear_in_edges(u, g);
3339   }
3340 
3341   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG>
3342   void
3343   clear_vertex
3344     (typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)
3345                 ::vertex_descriptor u,
3346       PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(undirectedS)& g)
3347   {
3348     remove_out_edge_if(u, parallel::detail::always_true(), g);
3349   }
3350 
3351   /************************************************************************
3352    *
3353    * clear_out_edges
3354    *
3355    ************************************************************************/
3356   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG>
3357   void
3358   clear_out_edges
3359     (typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(directedS)::vertex_descriptor u,
3360       PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(directedS)& g)
3361   {
3362     BOOST_ASSERT(u.owner == g.processor());
3363     clear_out_edges(u.local, g.base());
3364   }
3365 
3366   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG>
3367   void
3368   clear_out_edges
3369     (typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS)
3370                 ::vertex_descriptor u,
3371       PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS)& g)
3372   {
3373     remove_out_edge_if(u, parallel::detail::always_true(), g);
3374   }
3375 
3376   /************************************************************************
3377    *
3378    * clear_in_edges
3379    *
3380    ************************************************************************/
3381   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS_CONFIG>
3382   void
3383   clear_in_edges
3384     (typename PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS)
3385                 ::vertex_descriptor u,
3386       PBGL_DISTRIB_ADJLIST_TYPE_CONFIG(bidirectionalS)& g)
3387   {
3388     remove_in_edge_if(u, parallel::detail::always_true(), g);
3389   }
3390 
3391   /************************************************************************
3392    *
3393    * add_vertex
3394    *
3395    ************************************************************************/
3396   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
3397   typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor
3398   add_vertex(PBGL_DISTRIB_ADJLIST_TYPE& g)
3399   {
3400     typedef PBGL_DISTRIB_ADJLIST_TYPE graph_type;
3401     typename graph_type::vertex_property_type p;
3402     return add_vertex(p, g);
3403   }
3404 
3405   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
3406   typename PBGL_DISTRIB_ADJLIST_TYPE::lazy_add_vertex_with_property
3407   add_vertex(typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_property_type const& p,
3408              PBGL_DISTRIB_ADJLIST_TYPE& g)
3409   {
3410     typedef typename PBGL_DISTRIB_ADJLIST_TYPE
3411                        ::lazy_add_vertex_with_property lazy_add_vertex;
3412     return lazy_add_vertex(g, p);
3413   }
3414 
3415   /************************************************************************
3416    *
3417    * remove_vertex
3418    *
3419    ************************************************************************/
3420   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
3421   void
3422   remove_vertex(typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor u,
3423                 PBGL_DISTRIB_ADJLIST_TYPE& g)
3424   {
3425     typedef typename PBGL_DISTRIB_ADJLIST_TYPE::graph_type graph_type;
3426     typedef typename graph_type::named_graph_mixin named_graph_mixin;
3427     BOOST_ASSERT(u.owner == g.processor());
3428     static_cast<named_graph_mixin&>(static_cast<graph_type&>(g))
3429       .removing_vertex(u, boost::graph_detail::iterator_stability(g.base().m_vertices));
3430     g.distribution().clear();
3431     remove_vertex(u.local, g.base());
3432   }
3433 
3434   /***************************************************************************
3435    * Implementation of Property Graph concept
3436    ***************************************************************************/
3437   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS, typename Property>
3438   struct property_map<PBGL_DISTRIB_ADJLIST_TYPE, Property>
3439   : detail::parallel::get_adj_list_pmap<Property>
3440       ::template apply<PBGL_DISTRIB_ADJLIST_TYPE>
3441   { };
3442 
3443   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS, typename Property>
3444   struct property_map<PBGL_DISTRIB_ADJLIST_TYPE const, Property>
3445           : boost::detail::parallel::get_adj_list_pmap<Property>
3446 // FIXME: in the original code the following was not const
3447       ::template apply<PBGL_DISTRIB_ADJLIST_TYPE const>
3448   { };
3449 
3450   template<typename Property, PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
3451   typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, Property>::type
3452   get(Property p, PBGL_DISTRIB_ADJLIST_TYPE& g)
3453   {
3454     typedef PBGL_DISTRIB_ADJLIST_TYPE Graph;
3455     typedef typename property_map<Graph, Property>::type result_type;
3456     typedef typename property_traits<result_type>::value_type value_type;
3457     typedef typename property_reduce<Property>::template apply<value_type>
3458       reduce;
3459 
3460     typedef typename property_traits<result_type>::key_type descriptor;
3461     typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
3462     typedef typename mpl::if_<is_same<descriptor, vertex_descriptor>,
3463                               vertex_global_t, edge_global_t>::type
3464       global_map_t;
3465 
3466     return result_type(g.process_group(), get(global_map_t(), g),
3467                        get(p, g.base()), reduce());
3468   }
3469 
3470   template<typename Property, PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
3471   typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, Property>::const_type
3472   get(Property p, const PBGL_DISTRIB_ADJLIST_TYPE& g)
3473   {
3474     typedef PBGL_DISTRIB_ADJLIST_TYPE Graph;
3475     typedef typename property_map<Graph, Property>::const_type result_type;
3476     typedef typename property_traits<result_type>::value_type value_type;
3477     typedef typename property_reduce<Property>::template apply<value_type>
3478       reduce;
3479 
3480     typedef typename property_traits<result_type>::key_type descriptor;
3481     typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
3482     typedef typename mpl::if_<is_same<descriptor, vertex_descriptor>,
3483                               vertex_global_t, edge_global_t>::type
3484       global_map_t;
3485 
3486     return result_type(g.process_group(), get(global_map_t(), g),
3487                        get(p, g.base()), reduce());
3488   }
3489 
3490   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
3491   typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, vertex_local_index_t>::type
3492   get(vertex_local_index_t, PBGL_DISTRIB_ADJLIST_TYPE& g)
3493   {
3494     return get(vertex_local_index, g.base());
3495   }
3496 
3497   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
3498   typename property_map<PBGL_DISTRIB_ADJLIST_TYPE,
3499                         vertex_local_index_t>::const_type
3500   get(vertex_local_index_t, const PBGL_DISTRIB_ADJLIST_TYPE& g)
3501   {
3502     return get(vertex_local_index, g.base());
3503   }
3504 
3505   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
3506   typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, vertex_global_t>::const_type
3507   get(vertex_global_t, const PBGL_DISTRIB_ADJLIST_TYPE& g)
3508   {
3509     typedef typename property_map<
3510                        PBGL_DISTRIB_ADJLIST_TYPE,
3511                        vertex_global_t>::const_type result_type;
3512     return result_type();
3513   }
3514 
3515   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
3516   typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, vertex_global_t>::const_type
3517   get(vertex_global_t, PBGL_DISTRIB_ADJLIST_TYPE& g)
3518   {
3519     typedef typename property_map<
3520                        PBGL_DISTRIB_ADJLIST_TYPE,
3521                        vertex_global_t>::const_type result_type;
3522     return result_type();
3523   }
3524 
3525   /// Retrieve a property map mapping from a vertex descriptor to its
3526   /// owner.
3527   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
3528   typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, vertex_owner_t>::type
3529   get(vertex_owner_t, PBGL_DISTRIB_ADJLIST_TYPE& g)
3530   {
3531     typedef typename property_map<
3532                        PBGL_DISTRIB_ADJLIST_TYPE,
3533                        vertex_owner_t>::type result_type;
3534     return result_type();
3535   }
3536 
3537   /// Retrieve a property map mapping from a vertex descriptor to its
3538   /// owner.
3539   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
3540   typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, vertex_owner_t>::const_type
3541   get(vertex_owner_t, const PBGL_DISTRIB_ADJLIST_TYPE& g)
3542   {
3543     typedef typename property_map<
3544                        PBGL_DISTRIB_ADJLIST_TYPE,
3545                        vertex_owner_t>::const_type result_type;
3546     return result_type();
3547   }
3548 
3549   /// Retrieve the owner of a vertex
3550   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
3551   inline processor_id_type
3552   get(vertex_owner_t, PBGL_DISTRIB_ADJLIST_TYPE&,
3553       typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor v)
3554   {
3555     return v.owner;
3556   }
3557 
3558   /// Retrieve the owner of a vertex
3559   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
3560   inline processor_id_type
3561   get(vertex_owner_t, const PBGL_DISTRIB_ADJLIST_TYPE&,
3562       typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor v)
3563   {
3564     return v.owner;
3565   }
3566 
3567   /// Retrieve a property map that maps from a vertex descriptor to
3568   /// its local descriptor.
3569   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
3570   typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, vertex_local_t>::type
3571   get(vertex_local_t, PBGL_DISTRIB_ADJLIST_TYPE& g)
3572   {
3573     typedef typename property_map<
3574                        PBGL_DISTRIB_ADJLIST_TYPE,
3575                        vertex_local_t>::type result_type;
3576     return result_type();
3577   }
3578 
3579   /// Retrieve a property map that maps from a vertex descriptor to
3580   /// its local descriptor.
3581   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
3582   typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, vertex_local_t>::const_type
3583   get(vertex_local_t, const PBGL_DISTRIB_ADJLIST_TYPE& g)
3584   {
3585     typedef typename property_map<
3586                        PBGL_DISTRIB_ADJLIST_TYPE,
3587                        vertex_local_t>::const_type result_type;
3588     return result_type();
3589   }
3590 
3591   /// Retrieve the local descriptor of a vertex
3592   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
3593   inline typename PBGL_DISTRIB_ADJLIST_TYPE::local_vertex_descriptor
3594   get(vertex_local_t, PBGL_DISTRIB_ADJLIST_TYPE&,
3595       typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor v)
3596   {
3597     return v.local;
3598   }
3599 
3600   /// Retrieve the local descriptor of a vertex
3601   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
3602   inline typename PBGL_DISTRIB_ADJLIST_TYPE::local_vertex_descriptor
3603   get(vertex_local_t, const PBGL_DISTRIB_ADJLIST_TYPE&,
3604       typename PBGL_DISTRIB_ADJLIST_TYPE::vertex_descriptor v)
3605   {
3606     return v.local;
3607   }
3608 
3609 
3610   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
3611   typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, edge_global_t>::const_type
3612   get(edge_global_t, const PBGL_DISTRIB_ADJLIST_TYPE& g)
3613   {
3614     typedef typename property_map<
3615                        PBGL_DISTRIB_ADJLIST_TYPE,
3616                        edge_global_t>::const_type result_type;
3617     return result_type();
3618   }
3619 
3620   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
3621   typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, edge_global_t>::const_type
3622   get(edge_global_t, PBGL_DISTRIB_ADJLIST_TYPE& g)
3623   {
3624     typedef typename property_map<
3625                        PBGL_DISTRIB_ADJLIST_TYPE,
3626                        edge_global_t>::const_type result_type;
3627     return result_type();
3628   }
3629 
3630   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
3631   typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, edge_owner_t>::type
3632   get(edge_owner_t, PBGL_DISTRIB_ADJLIST_TYPE& g)
3633   {
3634     typedef typename property_map<
3635                        PBGL_DISTRIB_ADJLIST_TYPE,
3636                        edge_owner_t>::type result_type;
3637     return result_type();
3638   }
3639 
3640   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
3641   typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, edge_owner_t>::const_type
3642   get(edge_owner_t, const PBGL_DISTRIB_ADJLIST_TYPE& g)
3643   {
3644     typedef typename property_map<
3645                        PBGL_DISTRIB_ADJLIST_TYPE,
3646                        edge_owner_t>::const_type result_type;
3647     return result_type();
3648   }
3649 
3650   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
3651   typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, edge_local_t>::type
3652   get(edge_local_t, PBGL_DISTRIB_ADJLIST_TYPE& g)
3653   {
3654     typedef typename property_map<
3655                        PBGL_DISTRIB_ADJLIST_TYPE,
3656                        edge_local_t>::type result_type;
3657     return result_type();
3658   }
3659 
3660   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
3661   typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, edge_local_t>::const_type
3662   get(edge_local_t, const PBGL_DISTRIB_ADJLIST_TYPE& g)
3663   {
3664     typedef typename property_map<
3665                        PBGL_DISTRIB_ADJLIST_TYPE,
3666                        edge_local_t>::const_type result_type;
3667     return result_type();
3668   }
3669 
3670   template<typename Property, PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS,
3671            typename Key>
3672   inline
3673   typename property_traits<typename property_map<
3674                 PBGL_DISTRIB_ADJLIST_TYPE, Property>::const_type
3675            >::value_type
3676   get(Property p, const PBGL_DISTRIB_ADJLIST_TYPE& g, const Key& key)
3677   {
3678     if (owner(key) == process_id(g.process_group()))
3679       return get(p, g.base(), local(key));
3680     else
3681       BOOST_ASSERT(false);
3682   }
3683 
3684   template<typename Property, PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS,
3685            typename Key, typename Value>
3686   void
3687   put(Property p, PBGL_DISTRIB_ADJLIST_TYPE& g, const Key& key, const Value& v)
3688   {
3689     if (owner(key) == process_id(g.process_group()))
3690       put(p, g.base(), local(key), v);
3691     else
3692       BOOST_ASSERT(false);
3693   }
3694 
3695   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
3696   typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, vertex_index_t>::type
3697   get(vertex_index_t vi, PBGL_DISTRIB_ADJLIST_TYPE& g)
3698   {
3699     typedef PBGL_DISTRIB_ADJLIST_TYPE graph_type;
3700     typedef typename property_map<graph_type, vertex_index_t>::type
3701       result_type;
3702     return result_type(g.process_group(), get(vertex_global, g),
3703                        get(vi, g.base()));
3704   }
3705 
3706   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
3707   typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, vertex_index_t>::const_type
3708   get(vertex_index_t vi, const PBGL_DISTRIB_ADJLIST_TYPE& g)
3709   {
3710     typedef PBGL_DISTRIB_ADJLIST_TYPE graph_type;
3711     typedef typename property_map<graph_type, vertex_index_t>::const_type
3712       result_type;
3713     return result_type(g.process_group(), get(vertex_global, g),
3714                        get(vi, g.base()));
3715   }
3716 
3717   /***************************************************************************
3718    * Implementation of bundled properties
3719    ***************************************************************************/
3720   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS, typename T, typename Bundle>
3721   struct property_map<PBGL_DISTRIB_ADJLIST_TYPE, T Bundle::*>
3722     : detail::parallel::get_adj_list_pmap<T Bundle::*>
3723       ::template apply<PBGL_DISTRIB_ADJLIST_TYPE>
3724   { };
3725 
3726   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS, typename T, typename Bundle>
3727   struct property_map<PBGL_DISTRIB_ADJLIST_TYPE const, T Bundle::*>
3728     : detail::parallel::get_adj_list_pmap<T Bundle::*>
3729       ::template apply<PBGL_DISTRIB_ADJLIST_TYPE const>
3730   { };
3731 
3732   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS, typename T, typename Bundle>
3733   typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, T Bundle::*>::type
3734   get(T Bundle::* p, PBGL_DISTRIB_ADJLIST_TYPE& g)
3735   {
3736     typedef PBGL_DISTRIB_ADJLIST_TYPE Graph;
3737     typedef typename property_map<Graph, T Bundle::*>::type result_type;
3738     typedef typename property_traits<result_type>::value_type value_type;
3739     typedef typename property_reduce<T Bundle::*>::template apply<value_type>
3740       reduce;
3741 
3742     typedef typename property_traits<result_type>::key_type descriptor;
3743     typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
3744     typedef typename mpl::if_<is_same<descriptor, vertex_descriptor>,
3745                               vertex_global_t, edge_global_t>::type
3746       global_map_t;
3747 
3748     return result_type(g.process_group(), get(global_map_t(), g),
3749                        get(p, g.base()), reduce());
3750   }
3751 
3752   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS, typename T, typename Bundle>
3753   typename property_map<PBGL_DISTRIB_ADJLIST_TYPE, T Bundle::*>::const_type
3754   get(T Bundle::* p, const PBGL_DISTRIB_ADJLIST_TYPE& g)
3755   {
3756     typedef PBGL_DISTRIB_ADJLIST_TYPE Graph;
3757     typedef typename property_map<Graph, T Bundle::*>::const_type result_type;
3758     typedef typename property_traits<result_type>::value_type value_type;
3759     typedef typename property_reduce<T Bundle::*>::template apply<value_type>
3760       reduce;
3761 
3762     typedef typename property_traits<result_type>::key_type descriptor;
3763     typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
3764     typedef typename mpl::if_<is_same<descriptor, vertex_descriptor>,
3765                               vertex_global_t, edge_global_t>::type
3766       global_map_t;
3767 
3768     return result_type(g.process_group(), get(global_map_t(), g),
3769                        get(p, g.base()), reduce());
3770   }
3771 
3772   /***************************************************************************
3773    * Implementation of DistributedGraph concept
3774    ***************************************************************************/
3775   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
3776   void synchronize(const PBGL_DISTRIB_ADJLIST_TYPE& g)
3777   {
3778     synchronize(g.process_group());
3779   }
3780 
3781   template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
3782   ProcessGroup
3783   process_group(const PBGL_DISTRIB_ADJLIST_TYPE& g)
3784   { return g.process_group(); }
3785 
3786   /***************************************************************************
3787    * Specializations of is_mpi_datatype for Serializable entities
3788    ***************************************************************************/
3789   namespace mpi {
3790     template<typename Directed, typename Vertex>
3791     struct is_mpi_datatype<boost::detail::edge_base<Directed, Vertex> >
3792       : is_mpi_datatype<Vertex> { };
3793 
3794     template<typename Directed, typename Vertex>
3795     struct is_mpi_datatype<boost::detail::edge_desc_impl<Directed, Vertex> >
3796       : is_mpi_datatype<boost::detail::edge_base<Directed, Vertex> > { };
3797 
3798     template<typename LocalDescriptor>
3799     struct is_mpi_datatype<boost::detail::parallel::global_descriptor<LocalDescriptor> >
3800       : is_mpi_datatype<LocalDescriptor> { };
3801 
3802     template<typename Edge>
3803     struct is_mpi_datatype<boost::detail::parallel::edge_descriptor<Edge> >
3804       : is_mpi_datatype<Edge> { };
3805 
3806     template<typename Vertex, typename LocalVertex>
3807     struct is_mpi_datatype<boost::detail::parallel::
3808                              msg_add_edge_data<Vertex, LocalVertex> >
3809       : is_mpi_datatype<Vertex> { };
3810 
3811     template<typename Vertex, typename LocalVertex, typename EdgeProperty>
3812     struct is_mpi_datatype<boost::detail::parallel::
3813                              msg_add_edge_with_property_data<Vertex, 
3814                                                              LocalVertex,
3815                                                              EdgeProperty> >
3816       : mpl::and_<is_mpi_datatype<Vertex>, is_mpi_datatype<EdgeProperty> > { };
3817 
3818 
3819    template<typename EdgeProperty, typename EdgeDescriptor>
3820    struct is_mpi_datatype<boost::detail::parallel::msg_nonlocal_edge_data<
3821                           EdgeProperty,EdgeDescriptor> >
3822            : mpl::and_<
3823                is_mpi_datatype<boost::detail::parallel::maybe_store_property<
3824                            EdgeProperty> >,
3825            is_mpi_datatype<EdgeDescriptor> >
3826   {};
3827    
3828    template<typename EdgeDescriptor>
3829    struct is_mpi_datatype<
3830             boost::detail::parallel::msg_remove_edge_data<EdgeDescriptor> >
3831            : is_mpi_datatype<EdgeDescriptor> {};
3832   }
3833 
3834   /***************************************************************************
3835    * Specializations of is_bitwise_serializable for Serializable entities
3836    ***************************************************************************/
3837   namespace serialization {
3838     template<typename Directed, typename Vertex>
3839     struct is_bitwise_serializable<boost::detail::edge_base<Directed, Vertex> >
3840       : is_bitwise_serializable<Vertex> { };
3841 
3842     template<typename Directed, typename Vertex>
3843     struct is_bitwise_serializable<boost::detail::edge_desc_impl<Directed, Vertex> >
3844       : is_bitwise_serializable<boost::detail::edge_base<Directed, Vertex> > { };
3845 
3846     template<typename LocalDescriptor>
3847     struct is_bitwise_serializable<boost::detail::parallel::global_descriptor<LocalDescriptor> >
3848       : is_bitwise_serializable<LocalDescriptor> { };
3849 
3850     template<typename Edge>
3851     struct is_bitwise_serializable<boost::detail::parallel::edge_descriptor<Edge> >
3852       : is_bitwise_serializable<Edge> { };
3853 
3854     template<typename Vertex, typename LocalVertex>
3855     struct is_bitwise_serializable<boost::detail::parallel::
3856                              msg_add_edge_data<Vertex, LocalVertex> >
3857       : is_bitwise_serializable<Vertex> { };
3858 
3859     template<typename Vertex, typename LocalVertex, typename EdgeProperty>
3860     struct is_bitwise_serializable<boost::detail::parallel::
3861                              msg_add_edge_with_property_data<Vertex, 
3862                                                              LocalVertex,
3863                                                              EdgeProperty> >
3864       : mpl::and_<is_bitwise_serializable<Vertex>, 
3865                   is_bitwise_serializable<EdgeProperty> > { };
3866 
3867    template<typename EdgeProperty, typename EdgeDescriptor>
3868    struct is_bitwise_serializable<boost::detail::parallel::msg_nonlocal_edge_data<
3869                                   EdgeProperty,EdgeDescriptor> >
3870            : mpl::and_<
3871                is_bitwise_serializable<
3872                 boost::detail::parallel::maybe_store_property<EdgeProperty> >,
3873            is_bitwise_serializable<EdgeDescriptor> >
3874   {};
3875    
3876    template<typename EdgeDescriptor>
3877    struct is_bitwise_serializable<
3878             boost::detail::parallel::msg_remove_edge_data<EdgeDescriptor> >
3879            : is_bitwise_serializable<EdgeDescriptor> {};
3880    
3881     template<typename Directed, typename Vertex>
3882     struct implementation_level<boost::detail::edge_base<Directed, Vertex> >
3883       : mpl::int_<object_serializable> {};
3884 
3885     template<typename Directed, typename Vertex>
3886     struct implementation_level<boost::detail::edge_desc_impl<Directed, Vertex> >
3887       : mpl::int_<object_serializable> {};
3888 
3889     template<typename LocalDescriptor>
3890     struct implementation_level<boost::detail::parallel::global_descriptor<LocalDescriptor> >
3891       : mpl::int_<object_serializable> {};
3892 
3893     template<typename Edge>
3894     struct implementation_level<boost::detail::parallel::edge_descriptor<Edge> >
3895       : mpl::int_<object_serializable> {};
3896 
3897     template<typename Vertex, typename LocalVertex>
3898     struct implementation_level<boost::detail::parallel::
3899                              msg_add_edge_data<Vertex, LocalVertex> >
3900       : mpl::int_<object_serializable> {};
3901 
3902     template<typename Vertex, typename LocalVertex, typename EdgeProperty>
3903     struct implementation_level<boost::detail::parallel::
3904                              msg_add_edge_with_property_data<Vertex, 
3905                                                              LocalVertex,
3906                                                              EdgeProperty> >
3907       : mpl::int_<object_serializable> {};
3908 
3909    template<typename EdgeProperty, typename EdgeDescriptor>
3910    struct implementation_level<boost::detail::parallel::msg_nonlocal_edge_data<
3911                                EdgeProperty,EdgeDescriptor> >
3912            : mpl::int_<object_serializable> {};
3913    
3914    template<typename EdgeDescriptor>
3915    struct implementation_level<
3916             boost::detail::parallel::msg_remove_edge_data<EdgeDescriptor> >
3917           : mpl::int_<object_serializable> {};
3918    
3919     template<typename Directed, typename Vertex>
3920     struct tracking_level<boost::detail::edge_base<Directed, Vertex> >
3921       : mpl::int_<track_never> {};
3922 
3923     template<typename Directed, typename Vertex>
3924     struct tracking_level<boost::detail::edge_desc_impl<Directed, Vertex> >
3925       : mpl::int_<track_never> {};
3926 
3927     template<typename LocalDescriptor>
3928     struct tracking_level<boost::detail::parallel::global_descriptor<LocalDescriptor> >
3929       : mpl::int_<track_never> {};
3930 
3931     template<typename Edge>
3932     struct tracking_level<boost::detail::parallel::edge_descriptor<Edge> >
3933       : mpl::int_<track_never> {};
3934 
3935     template<typename Vertex, typename LocalVertex>
3936     struct tracking_level<boost::detail::parallel::
3937                              msg_add_edge_data<Vertex, LocalVertex> >
3938       : mpl::int_<track_never> {};
3939 
3940     template<typename Vertex, typename LocalVertex, typename EdgeProperty>
3941     struct tracking_level<boost::detail::parallel::
3942                              msg_add_edge_with_property_data<Vertex, 
3943                                                              LocalVertex,
3944                                                              EdgeProperty> >
3945       : mpl::int_<track_never> {};
3946 
3947    template<typename EdgeProperty, typename EdgeDescriptor>
3948    struct tracking_level<boost::detail::parallel::msg_nonlocal_edge_data<
3949                          EdgeProperty,EdgeDescriptor> >
3950            : mpl::int_<track_never> {};
3951    
3952    template<typename EdgeDescriptor>
3953    struct tracking_level<
3954             boost::detail::parallel::msg_remove_edge_data<EdgeDescriptor> >
3955           : mpl::int_<track_never> {};
3956   }
3957 
3958   // Hash function for global descriptors
3959   template<typename LocalDescriptor>
3960   struct hash<detail::parallel::global_descriptor<LocalDescriptor> >
3961   {
3962     typedef detail::parallel::global_descriptor<LocalDescriptor> argument_type;
3963     std::size_t operator()(argument_type const& x) const
3964     {
3965       std::size_t hash = hash_value(x.owner);
3966       hash_combine(hash, x.local);
3967       return hash;
3968     }
3969   };
3970 
3971   // Hash function for parallel edge descriptors
3972   template<typename Edge>
3973   struct hash<detail::parallel::edge_descriptor<Edge> >
3974   {
3975     typedef detail::parallel::edge_descriptor<Edge> argument_type;
3976 
3977     std::size_t operator()(argument_type const& x) const
3978     {
3979       std::size_t hash = hash_value(x.owner());
3980       hash_combine(hash, x.local);
3981       return hash;
3982     }
3983   };
3984 
3985 } // end namespace boost
3986 
3987 #include <boost/graph/distributed/adjlist/handlers.hpp>
3988 #include <boost/graph/distributed/adjlist/initialize.hpp>
3989 #include <boost/graph/distributed/adjlist/redistribute.hpp>
3990 #include <boost/graph/distributed/adjlist/serialization.hpp>
3991 
3992 #endif // BOOST_GRAPH_DISTRIBUTED_ADJACENCY_LIST_HPP