PageRenderTime 80ms CodeModel.GetById 15ms app.highlight 57ms RepoModel.GetById 1ms app.codeStats 0ms

/Src/Dependencies/Boost/boost/graph/distributed/connected_components.hpp

http://hadesmem.googlecode.com/
C++ Header | 769 lines | 543 code | 127 blank | 99 comment | 112 complexity | f9964bf509734f553619d93f7af572fd MD5 | raw file
  1// Copyright (C) 2004-2006 The Trustees of Indiana University.
  2
  3// Use, modification and distribution is subject to the Boost Software
  4// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  5// http://www.boost.org/LICENSE_1_0.txt)
  6
  7//  Authors: Nick Edmonds
  8//           Douglas Gregor
  9//           Andrew Lumsdaine
 10#ifndef BOOST_GRAPH_PARALLEL_CC_HPP
 11#define BOOST_GRAPH_PARALLEL_CC_HPP
 12
 13#ifndef BOOST_GRAPH_USE_MPI
 14#error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
 15#endif
 16
 17#include <boost/detail/is_sorted.hpp>
 18#include <boost/assert.hpp>
 19#include <boost/property_map/property_map.hpp>
 20#include <boost/property_map/parallel/caching_property_map.hpp>
 21#include <boost/graph/parallel/algorithm.hpp>
 22#include <boost/pending/indirect_cmp.hpp>
 23#include <boost/graph/graph_traits.hpp>
 24#include <boost/graph/overloading.hpp>
 25#include <boost/graph/distributed/concepts.hpp>
 26#include <boost/graph/parallel/properties.hpp>
 27#include <boost/graph/distributed/local_subgraph.hpp>
 28#include <boost/graph/connected_components.hpp>
 29#include <boost/graph/named_function_params.hpp>
 30#include <boost/graph/parallel/process_group.hpp>
 31#include <boost/optional.hpp>
 32#include <functional>
 33#include <algorithm>
 34#include <vector>
 35#include <list>
 36#include <boost/graph/parallel/container_traits.hpp>
 37#include <boost/graph/iteration_macros.hpp>
 38
 39#define PBGL_IN_PLACE_MERGE /* In place merge instead of sorting */
 40//#define PBGL_SORT_ASSERT    /* Assert sorted for in place merge */
 41
 42/* Explicit sychronization in pointer doubling step? */
 43#define PBGL_EXPLICIT_SYNCH
 44//#define PBGL_CONSTRUCT_METAGRAPH
 45#ifdef PBGL_CONSTRUCT_METAGRAPH
 46#  define MAX_VERTICES_IN_METAGRAPH 10000
 47#endif
 48
 49namespace boost { namespace graph { namespace distributed {
 50  namespace cc_detail {
 51    enum connected_components_message { 
 52      edges_msg, req_parents_msg, parents_msg, root_adj_msg
 53    };
 54
 55    template <typename Vertex>
 56    struct metaVertex {
 57      metaVertex() {}
 58      metaVertex(const Vertex& v) : name(v) {}
 59
 60      template<typename Archiver>
 61      void serialize(Archiver& ar, const unsigned int /*version*/)
 62      {
 63        ar & name;
 64      }
 65
 66      Vertex name;
 67    };
 68
 69#ifdef PBGL_CONSTRUCT_METAGRAPH
 70    // Build meta-graph on result of local connected components
 71    template <typename Graph, typename ParentMap, typename RootIterator,
 72              typename AdjacencyMap>
 73    void
 74    build_local_metagraph(const Graph& g, ParentMap p, RootIterator r,
 75                          RootIterator r_end, AdjacencyMap& adj)
 76    {
 77      // TODO: Static assert that AdjacencyMap::value_type is std::vector<vertex_descriptor>
 78
 79      typedef typename boost::graph::parallel::process_group_type<Graph>::type
 80        process_group_type;
 81      typedef typename process_group_type::process_id_type process_id_type;
 82
 83      typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
 84
 85      BOOST_STATIC_ASSERT((is_same<typename AdjacencyMap::mapped_type,
 86                                     std::vector<vertex_descriptor> >::value));
 87
 88      using boost::graph::parallel::process_group;
 89
 90      process_group_type pg = process_group(g);
 91      process_id_type id = process_id(pg);
 92      
 93      if (id != 0) {
 94
 95        // Send component roots and their associated edges to P0
 96        for ( ; r != r_end; ++r ) {
 97          std::vector<vertex_descriptor> adjs(1, *r); // Root
 98          adjs.reserve(adjs.size() + adj[*r].size());
 99          for (typename std::vector<vertex_descriptor>::iterator iter = adj[*r].begin();
100               iter != adj[*r].end(); ++iter)
101            adjs.push_back(get(p, *iter)); // Adjacencies
102
103          send(pg, 0, root_adj_msg, adjs); 
104        }
105      }
106      
107      synchronize(pg);
108
109      if (id == 0) {
110        typedef metaVertex<vertex_descriptor> VertexProperties;
111
112        typedef boost::adjacency_list<vecS, vecS, undirectedS, 
113          VertexProperties> metaGraph;
114        typedef typename graph_traits<metaGraph>::vertex_descriptor 
115          meta_vertex_descriptor;
116
117        std::map<vertex_descriptor, meta_vertex_descriptor> vertex_map;
118        std::vector<std::pair<vertex_descriptor, vertex_descriptor> > edges;
119
120        // Receive remote roots and edges
121        while (optional<std::pair<process_id_type, int> > m = probe(pg)) {
122          BOOST_ASSERT(m->second == root_adj_msg);
123
124          std::vector<vertex_descriptor> adjs;
125          receive(pg, m->first, m->second, adjs);
126
127          vertex_map[adjs[0]] = graph_traits<metaGraph>::null_vertex();
128          for (typename std::vector<vertex_descriptor>::iterator iter 
129                 = ++adjs.begin(); iter != adjs.end(); ++iter)
130            edges.push_back(std::make_pair(adjs[0], *iter));
131        }
132
133        // Add local roots and edges
134        for ( ; r != r_end; ++r ) {
135          vertex_map[*r] = graph_traits<metaGraph>::null_vertex();
136          edges.reserve(edges.size() + adj[*r].size());
137          for (typename std::vector<vertex_descriptor>::iterator iter = adj[*r].begin();
138               iter != adj[*r].end(); ++iter)
139            edges.push_back(std::make_pair(*r, get(p, *iter)));
140        } 
141
142        // Build local meta-graph
143        metaGraph mg;
144
145        // Add vertices with property to map back to distributed graph vertex
146        for (typename std::map<vertex_descriptor, meta_vertex_descriptor>::iterator
147               iter = vertex_map.begin(); iter != vertex_map.end(); ++iter)
148          vertex_map[iter->first] 
149            = add_vertex(metaVertex<vertex_descriptor>(iter->first), mg);
150
151        // Build meta-vertex map
152        typename property_map<metaGraph, vertex_descriptor VertexProperties::*>::type 
153          metaVertexMap = get(&VertexProperties::name, mg);
154
155        typename std::vector<std::pair<vertex_descriptor, vertex_descriptor> >
156          ::iterator edge_iter = edges.begin();
157        for ( ; edge_iter != edges.end(); ++edge_iter)
158          add_edge(vertex_map[edge_iter->first], vertex_map[edge_iter->second], mg);
159        
160        edges.clear();
161  
162        // Call connected_components on it
163        typedef typename property_map<metaGraph, vertex_index_t>::type 
164          meta_index_map_type;
165        meta_index_map_type meta_index = get(vertex_index, mg);
166
167        std::vector<std::size_t> mg_component_vec(num_vertices(mg));
168        typedef iterator_property_map<std::vector<std::size_t>::iterator,
169                                      meta_index_map_type>
170        meta_components_map_type;
171        meta_components_map_type mg_component(mg_component_vec.begin(),
172                                              meta_index);
173        std::size_t num_comp = connected_components(mg, mg_component);
174
175        // Update Parent pointers
176        std::vector<meta_vertex_descriptor> roots(num_comp, graph_traits<metaGraph>::null_vertex());
177
178        BGL_FORALL_VERTICES_T(v, mg, metaGraph) {
179          size_t component = get(mg_component, v);
180          if (roots[component] == graph_traits<metaGraph>::null_vertex() ||
181              get(meta_index, v) < get(meta_index, roots[component])) 
182            roots[component] = v;
183        }
184
185        // Set all the local parent pointers
186        BGL_FORALL_VERTICES_T(v, mg, metaGraph) {
187          // Problem in value being put (3rd parameter)
188          put(p, get(metaVertexMap, v), get(metaVertexMap, roots[get(mg_component, v)]));
189        }
190      }
191
192      synchronize(p);
193    }
194#endif
195
196    /* Function object used to remove internal vertices and vertices >
197       the current vertex from the adjacent vertex lists at each
198       root */
199    template <typename Vertex, typename ParentMap>
200    class cull_adjacency_list
201    {
202    public:
203      cull_adjacency_list(const Vertex v, const ParentMap p) : v(v), p(p) {}
204      bool operator() (const Vertex x) { return (get(p, x) == v || x == v); }
205
206    private:
207      const Vertex    v;
208      const ParentMap p;
209    };
210
211    /* Comparison operator used to choose targets for hooking s.t. vertices 
212       that are hooked to are evenly distributed across processors */
213    template <typename OwnerMap, typename LocalMap>
214    class hashed_vertex_compare
215    {
216    public:
217      hashed_vertex_compare (const OwnerMap& o, const LocalMap& l)
218        : owner(o), local(l) { }
219
220      template <typename Vertex>
221      bool operator() (const Vertex x, const Vertex y) 
222      { 
223        if (get(local, x) < get(local, y))
224          return true;
225        else if (get(local, x) == get(local, y))
226          return (get(owner, x) < get(owner, y));
227        return false;
228      }
229
230    private:
231      OwnerMap   owner;
232      LocalMap   local;
233    };
234
235#ifdef PBGL_EXPLICIT_SYNCH
236    template <typename Graph, typename ParentMap, typename VertexList>
237    void
238    request_parent_map_entries(const Graph& g, ParentMap p,
239                               std::vector<VertexList>& parent_requests)
240    {
241      typedef typename boost::graph::parallel::process_group_type<Graph>
242        ::type process_group_type;
243      typedef typename process_group_type::process_id_type process_id_type;
244
245      typedef typename graph_traits<Graph>::vertex_descriptor
246        vertex_descriptor;
247
248      process_group_type pg = process_group(g);
249      
250      /*
251        This should probably be send_oob_with_reply, especially when Dave 
252        finishes prefetch-batching
253      */
254
255      // Send root requests
256      for (process_id_type i = 0; i < num_processes(pg); ++i) {
257        if (!parent_requests[i].empty()) {
258          std::vector<vertex_descriptor> reqs(parent_requests[i].begin(),
259                                              parent_requests[i].end());
260          send(pg, i, req_parents_msg, reqs);
261        }
262      }
263      
264      synchronize(pg);
265      
266      // Receive root requests and reply to them
267      while (optional<std::pair<process_id_type, int> > m = probe(pg)) {
268        std::vector<vertex_descriptor> requests;
269        receive(pg, m->first, m->second, requests);
270        for (std::size_t i = 0; i < requests.size(); ++i)
271          requests[i] = get(p, requests[i]);
272        send(pg, m->first, parents_msg, requests);
273      }
274      
275      synchronize(pg);
276      
277      // Receive requested parents
278      std::vector<vertex_descriptor> responses;
279      for (process_id_type i = 0; i < num_processes(pg); ++i) {
280        if (!parent_requests[i].empty()) {
281          receive(pg, i, parents_msg, responses);
282          std::size_t parent_idx = 0;
283          for (typename VertexList::iterator v = parent_requests[i].begin();
284               v != parent_requests[i].end(); ++v, ++parent_idx)
285            put(p, *v, responses[parent_idx]);
286        }
287      }
288    }
289#endif
290    
291    template<typename DistributedGraph, typename ParentMap>
292    void
293    parallel_connected_components(DistributedGraph& g, ParentMap p)
294    {
295      using boost::connected_components;
296
297      typedef typename graph_traits<DistributedGraph>::adjacency_iterator
298        adjacency_iterator;
299      typedef typename graph_traits<DistributedGraph>::out_edge_iterator
300        out_edge_iterator;
301      typedef typename graph_traits<DistributedGraph>::edge_iterator
302        edge_iterator;
303      typedef typename graph_traits<DistributedGraph>::vertex_descriptor
304        vertex_descriptor;
305      typedef typename graph_traits<DistributedGraph>::edge_descriptor
306        edge_descriptor;
307
308      typedef typename boost::graph::parallel::process_group_type<DistributedGraph>
309        ::type process_group_type;
310      typedef typename process_group_type::process_id_type process_id_type;
311
312      using boost::graph::parallel::process_group;
313
314      process_group_type pg = process_group(g);
315      process_id_type id = process_id(pg);
316
317      // TODO (NGE): Should old_roots, roots, and completed_roots be std::list
318      adjacency_iterator av1, av2;
319      std::vector<vertex_descriptor> old_roots;
320      typename std::vector<vertex_descriptor>::iterator liter;
321      typename std::vector<vertex_descriptor>::iterator aliter;
322      typename std::map<vertex_descriptor,
323                        std::vector<vertex_descriptor> > adj;
324
325      typedef typename property_map<DistributedGraph, vertex_owner_t>::const_type
326        OwnerMap;
327      OwnerMap owner = get(vertex_owner, g);
328      typedef typename property_map<DistributedGraph, vertex_local_t>::const_type
329        LocalMap;
330      LocalMap local = get(vertex_local, g);
331
332      // We need to hold on to all of the parent pointers
333      p.set_max_ghost_cells(0);
334
335      //
336      // STAGE 1 : Compute local components
337      //
338      local_subgraph<const DistributedGraph> ls(g);
339      typedef typename property_map<local_subgraph<const DistributedGraph>,
340                                    vertex_index_t>::type local_index_map_type;
341      local_index_map_type local_index = get(vertex_index, ls);
342
343      // Compute local connected components
344      std::vector<std::size_t> ls_components_vec(num_vertices(ls));
345      typedef iterator_property_map<std::vector<std::size_t>::iterator,
346                                    local_index_map_type>
347        ls_components_map_type;
348      ls_components_map_type ls_component(ls_components_vec.begin(),
349                                          local_index);
350      std::size_t num_comp = connected_components(ls, ls_component);
351
352      std::vector<vertex_descriptor> 
353        roots(num_comp, graph_traits<DistributedGraph>::null_vertex());
354
355      BGL_FORALL_VERTICES_T(v, g, DistributedGraph) {
356        size_t component = get(ls_component, v);
357        if (roots[component] == graph_traits<DistributedGraph>::null_vertex() ||
358            get(local_index, v) < get(local_index, roots[component])) 
359          roots[component] = v;
360      }
361
362      // Set all the local parent pointers
363      BGL_FORALL_VERTICES_T(v, g, DistributedGraph) {
364        put(p, v, roots[get(ls_component, v)]);
365      }
366
367      if (num_processes(pg) == 1) return;
368
369      // Build adjacency list for all roots
370      BGL_FORALL_VERTICES_T(v, g, DistributedGraph) {
371        std::vector<vertex_descriptor>& my_adj = adj[get(p, v)];
372        for (boost::tie(av1, av2) = adjacent_vertices(v, g);
373             av1 != av2; ++av1) {
374          if (get(owner, *av1) != id) my_adj.push_back(*av1);
375        }
376      }
377
378      // For all vertices adjacent to a local vertex get p(v)
379      for ( liter = roots.begin(); liter != roots.end(); ++liter ) {
380        std::vector<vertex_descriptor>& my_adj = adj[*liter];
381        for ( aliter = my_adj.begin(); aliter != my_adj.end(); ++aliter )
382          request(p, *aliter);
383      }
384      synchronize(p);
385
386      // Update adjacency list at root to make sure all adjacent
387      // vertices are roots of remote components
388      for ( liter = roots.begin(); liter != roots.end(); ++liter )
389        {
390          std::vector<vertex_descriptor>& my_adj = adj[*liter];
391          for ( aliter = my_adj.begin(); aliter != my_adj.end(); ++aliter )
392            *aliter = get(p, *aliter);
393
394          my_adj.erase
395            (std::remove_if(my_adj.begin(), my_adj.end(),
396                       cull_adjacency_list<vertex_descriptor, 
397                                           ParentMap>(*liter, p) ),
398             my_adj.end());
399          // This sort needs to be here to make sure the initial
400          // adjacency list is sorted
401          std::sort(my_adj.begin(), my_adj.end(), std::less<vertex_descriptor>());
402          my_adj.erase(std::unique(my_adj.begin(), my_adj.end()), my_adj.end());
403        }
404
405      // Get p(v) for the new adjacent roots
406      p.clear();
407      for ( liter = roots.begin(); liter != roots.end(); ++liter ) {
408        std::vector<vertex_descriptor>& my_adj = adj[*liter];
409        for ( aliter = my_adj.begin(); aliter != my_adj.end(); ++aliter )
410          request(p, *aliter);
411      }
412#ifdef PBGL_EXPLICIT_SYNCH
413      synchronize(p);
414#endif
415
416      // Lastly, remove roots with no adjacent vertices, this is
417      // unnecessary but will speed up sparse graphs
418      for ( liter = roots.begin(); liter != roots.end(); /*in loop*/)
419        {
420          if ( adj[*liter].empty() )
421            liter = roots.erase(liter);
422          else
423            ++liter;
424        }
425
426#ifdef PBGL_CONSTRUCT_METAGRAPH
427      /* TODO: If the number of roots is sufficiently small, we can 
428               use a 'problem folding' approach like we do in MST
429               to gather all the roots and their adjacencies on one proc
430               and solve for the connected components of the meta-graph */
431      using boost::parallel::all_reduce;
432      std::size_t num_roots = all_reduce(pg, roots.size(), std::plus<std::size_t>());
433      if (num_roots < MAX_VERTICES_IN_METAGRAPH) {
434        build_local_metagraph(g, p, roots.begin(), roots.end(), adj);
435        
436        // For each vertex in g, p(v) = p(p(v)), assign parent of leaf
437        // vertices from first step to final parent
438        BGL_FORALL_VERTICES_T(v, g, DistributedGraph) {
439          put(p, v, get(p, get(p, v)));
440        }
441        
442        synchronize(p);
443        
444        return;
445      }
446#endif
447
448      //
449      // Parallel Phase
450      //
451
452      std::vector<vertex_descriptor> completed_roots;
453      hashed_vertex_compare<OwnerMap, LocalMap> v_compare(owner, local);
454      bool any_hooked;
455      vertex_descriptor new_root;
456
457      std::size_t steps = 0;
458
459      do {
460        ++steps;
461
462        // Pull in new parents for hooking phase
463        synchronize(p);
464
465        //
466        // Hooking
467        //
468        bool hooked = false;
469        completed_roots.clear();
470        for ( liter = roots.begin(); liter != roots.end(); )
471          {
472            new_root = graph_traits<DistributedGraph>::null_vertex();
473            std::vector<vertex_descriptor>& my_adj = adj[*liter];
474            for ( aliter = my_adj.begin(); aliter != my_adj.end(); ++aliter )
475              // try to hook to better adjacent vertex
476              if ( v_compare( get(p, *aliter), *liter ) )
477                new_root = get(p, *aliter);
478
479            if ( new_root != graph_traits<DistributedGraph>::null_vertex() )
480              {
481                hooked = true;
482                put(p, *liter, new_root);
483                old_roots.push_back(*liter);
484                completed_roots.push_back(*liter);
485                liter = roots.erase(liter);
486              }
487            else
488              ++liter;
489          }
490
491        //
492        // Pointer jumping, perform until new roots determined
493        //
494
495        // TODO: Implement cycle reduction rules to reduce this from
496        // O(n) to O(log n) [n = cycle length]
497        bool all_done;
498        std::size_t parent_root_count;
499
500        std::size_t double_steps = 0;
501
502        do {
503          ++double_steps;
504#ifndef PBGL_EXPLICIT_SYNCH
505          // Get p(p(v)) for all old roots, and p(v) for all current roots
506          for ( liter = old_roots.begin(); liter != old_roots.end(); ++liter )
507            request(p, get(p, *liter));
508
509          synchronize(p);
510#else
511          // Build root requests
512          typedef std::set<vertex_descriptor> VertexSet;
513          std::vector<VertexSet> parent_requests(num_processes(pg));
514          for ( liter = old_roots.begin(); liter != old_roots.end(); ++liter )
515            {
516              vertex_descriptor p1 = *liter;
517              if (get(owner, p1) != id) parent_requests[get(owner, p1)].insert(p1);
518              vertex_descriptor p2 = get(p, p1);
519              if (get(owner, p2) != id) parent_requests[get(owner, p2)].insert(p2);
520            }
521
522          request_parent_map_entries(g, p, parent_requests);
523#endif
524          // Perform a pointer jumping step on all old roots
525          for ( liter = old_roots.begin(); liter != old_roots.end(); ++liter )
526              put(p, *liter, get(p, get(p, *liter)));
527
528          // make sure the parent of all old roots is itself a root
529          parent_root_count = 0;
530          for ( liter = old_roots.begin(); liter != old_roots.end(); ++liter )
531            if ( get(p, *liter) == get(p, get(p, *liter)) )
532              parent_root_count++;
533
534          bool done = parent_root_count == old_roots.size();
535
536          all_reduce(pg, &done, &done+1, &all_done,
537                     std::logical_and<bool>());
538        } while ( !all_done );
539#ifdef PARALLEL_BGL_DEBUG
540        if (id == 0) std::cerr << double_steps << " doubling steps.\n";
541#endif
542        //
543        // Add adjacent vertices of just completed roots to adjacent
544        // vertex list at new parent
545        //
546        typename std::vector<vertex_descriptor> outgoing_edges;
547        for ( liter = completed_roots.begin(); liter != completed_roots.end();
548              ++liter )
549          {
550            vertex_descriptor new_parent = get(p, *liter);
551
552            if ( get(owner, new_parent) == id )
553              {
554                std::vector<vertex_descriptor>& my_adj = adj[new_parent];
555                my_adj.reserve(my_adj.size() + adj[*liter].size());
556                my_adj.insert( my_adj.end(),
557                               adj[*liter].begin(), adj[*liter].end() );
558#ifdef PBGL_IN_PLACE_MERGE
559#ifdef PBGL_SORT_ASSERT
560                BOOST_ASSERT(::boost::detail::is_sorted(my_adj.begin(),
561                                                  my_adj.end() - adj[*liter].size(),
562                                                  std::less<vertex_descriptor>()));
563                BOOST_ASSERT(::boost::detail::is_sorted(my_adj.end() - adj[*liter].size(),
564                                                  my_adj.end(),
565                                                  std::less<vertex_descriptor>()));
566#endif
567                std::inplace_merge(my_adj.begin(),
568                                   my_adj.end() - adj[*liter].size(),
569                                   my_adj.end(),
570                                   std::less<vertex_descriptor>());
571#endif
572
573
574              }
575            else if ( adj[*liter].begin() != adj[*liter].end() )
576              {
577                outgoing_edges.clear();
578                outgoing_edges.reserve(adj[*liter].size() + 1);
579                // First element is the destination of the adjacency list
580                outgoing_edges.push_back(new_parent);
581                outgoing_edges.insert(outgoing_edges.end(),
582                                      adj[*liter].begin(), adj[*liter].end() );
583                send(pg, get(owner, new_parent), edges_msg, outgoing_edges);
584                adj[*liter].clear();
585              }
586          }
587        synchronize(pg);
588
589        // Receive edges sent by remote nodes and add them to the
590        // indicated vertex's adjacency list
591        while (optional<std::pair<process_id_type, int> > m
592               = probe(pg))
593          {
594            std::vector<vertex_descriptor> incoming_edges;
595            receive(pg, m->first, edges_msg, incoming_edges);
596            typename std::vector<vertex_descriptor>::iterator aviter
597              = incoming_edges.begin();
598            ++aviter;
599
600            std::vector<vertex_descriptor>& my_adj = adj[incoming_edges[0]];
601
602            my_adj.reserve(my_adj.size() + incoming_edges.size() - 1);
603            my_adj.insert( my_adj.end(), aviter, incoming_edges.end() );
604
605#ifdef PBGL_IN_PLACE_MERGE
606            std::size_t num_incoming_edges = incoming_edges.size();
607#ifdef PBGL_SORT_ASSERT
608            BOOST_ASSERT(::boost::detail::is_sorted(my_adj.begin(),
609                                              my_adj.end() - (num_incoming_edges-1),
610                                              std::less<vertex_descriptor>()));
611            BOOST_ASSERT(::boost::detail::is_sorted(my_adj.end() - (num_incoming_edges-1),
612                                              my_adj.end(),
613                                              std::less<vertex_descriptor>()));
614#endif
615            std::inplace_merge(my_adj.begin(),
616                               my_adj.end() - (num_incoming_edges - 1),
617                               my_adj.end(),
618                               std::less<vertex_descriptor>());
619#endif
620
621          }
622
623
624        // Remove any adjacent vertices that are in the same component
625        // as a root from that root's list
626        for ( liter = roots.begin(); liter != roots.end(); ++liter )
627          {
628            // We can probably get away without sorting and removing
629            // duplicates Though sorting *may* cause root
630            // determination to occur faster by choosing the root with
631            // the most potential to hook to at each step
632            std::vector<vertex_descriptor>& my_adj = adj[*liter];
633            my_adj.erase
634              (std::remove_if(my_adj.begin(), my_adj.end(),
635                         cull_adjacency_list<vertex_descriptor,
636                                             ParentMap>(*liter, p) ),
637               my_adj.end());
638#ifndef PBGL_IN_PLACE_MERGE
639            std::sort(my_adj.begin(), my_adj.end(),
640                 std::less<vertex_descriptor>() );
641#endif
642            my_adj.erase(std::unique(my_adj.begin(), my_adj.end()), my_adj.end());
643          }
644
645        // Reduce result of empty root list test
646        all_reduce(pg, &hooked, &hooked+1, &any_hooked,
647                   std::logical_or<bool>());
648      } while ( any_hooked );
649#ifdef PARALLEL_BGL_DEBUG
650      if (id == 0) std::cerr << steps << " iterations.\n";
651#endif
652      //
653      // Finalize
654      //
655
656      // For each vertex in g, p(v) = p(p(v)), assign parent of leaf
657      // vertices from first step to final parent
658      BGL_FORALL_VERTICES_T(v, g, DistributedGraph) {
659        put(p, v, get(p, get(p, v)));
660      }
661      
662      synchronize(p);
663    }
664
665  } // end namespace cc_detail
666
667  template<typename Graph, typename ParentMap, typename ComponentMap>
668  typename property_traits<ComponentMap>::value_type
669  number_components_from_parents(const Graph& g, ParentMap p, ComponentMap c)
670  {
671    typedef typename graph_traits<Graph>::vertex_descriptor
672      vertex_descriptor;
673    typedef typename boost::graph::parallel::process_group_type<Graph>::type
674      process_group_type;
675    typedef typename property_traits<ComponentMap>::value_type
676      ComponentMapType;
677
678    process_group_type pg = process_group(g);
679
680    /* Build list of roots */
681    std::vector<vertex_descriptor> my_roots, all_roots;
682
683    BGL_FORALL_VERTICES_T(v, g, Graph) {
684      if( std::find( my_roots.begin(), my_roots.end(), get(p, v) )
685          == my_roots.end() )
686        my_roots.push_back( get(p, v) );
687    }
688
689    all_gather(pg, my_roots.begin(), my_roots.end(), all_roots);
690
691    /* Number components */
692    std::map<vertex_descriptor, ComponentMapType> comp_numbers;
693    ComponentMapType c_num = 0;
694
695    // Compute component numbers
696    for (std::size_t i = 0; i < all_roots.size(); i++ )
697      if ( comp_numbers.count(all_roots[i]) == 0 )
698        comp_numbers[all_roots[i]] = c_num++;
699
700    // Broadcast component numbers
701    BGL_FORALL_VERTICES_T(v, g, Graph) {
702      put( c, v, comp_numbers[get(p, v)] );
703    }
704
705    // Broadcast number of components
706    if (process_id(pg) == 0) {
707      typedef typename process_group_type::process_size_type
708        process_size_type;
709      for (process_size_type dest = 1, n = num_processes(pg);
710           dest != n; ++dest)
711        send(pg, dest, 0, c_num);
712    }
713    synchronize(pg);
714
715    if (process_id(pg) != 0) receive(pg, 0, 0, c_num);
716
717    synchronize(c);
718
719    return c_num;
720  }
721
722  template<typename Graph, typename ParentMap>
723  int
724  number_components_from_parents(const Graph& g, ParentMap p, 
725                                 dummy_property_map)
726  {
727    using boost::parallel::all_reduce;
728
729    // Count local roots.
730    int num_roots = 0;
731    BGL_FORALL_VERTICES_T(v, g, Graph)
732      if (get(p, v) == v) ++num_roots;
733    return all_reduce(g.process_group(), num_roots, std::plus<int>());
734  }
735
736  template<typename Graph, typename ComponentMap, typename ParentMap>
737  typename property_traits<ComponentMap>::value_type
738  connected_components
739    (const Graph& g, ComponentMap c, ParentMap p
740     BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph, distributed_graph_tag))
741  {
742    cc_detail::parallel_connected_components(g, p);
743    return number_components_from_parents(g, p, c);
744  }
745
746  /* Construct ParentMap by default */
747  template<typename Graph, typename ComponentMap>
748  typename property_traits<ComponentMap>::value_type
749  connected_components
750    ( const Graph& g, ComponentMap c
751      BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph, distributed_graph_tag) )
752  {
753    typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
754
755    std::vector<vertex_descriptor> x(num_vertices(g));
756
757    return connected_components
758             (g, c,
759              make_iterator_property_map(x.begin(), get(vertex_index, g)));
760  }
761} // end namespace distributed
762
763using distributed::connected_components;
764} // end namespace graph
765
766using graph::distributed::connected_components;
767} // end namespace boost
768
769#endif // BOOST_GRAPH_PARALLEL_CC_HPP