annotate DEPENDENCIES/generic/include/boost/graph/distributed/connected_components.hpp @ 133:4acb5d8d80b6 tip

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