annotate DEPENDENCIES/generic/include/boost/graph/distributed/strong_components.hpp @ 118:770eb830ec19 emscripten

Typo fix
author Chris Cannam
date Wed, 18 May 2016 16:14:08 +0100
parents 2665513ce2d3
children
rev   line source
Chris@16 1 // Copyright (C) 2004-2008 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_DISTRIBUTED_SCC_HPP
Chris@16 11 #define BOOST_GRAPH_DISTRIBUTED_SCC_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 // #define PBGL_SCC_DEBUG
Chris@16 18
Chris@16 19 #include <boost/assert.hpp>
Chris@16 20 #include <boost/property_map/property_map.hpp>
Chris@16 21 #include <boost/property_map/parallel/distributed_property_map.hpp>
Chris@16 22 #include <boost/property_map/parallel/caching_property_map.hpp>
Chris@16 23 #include <boost/graph/parallel/algorithm.hpp>
Chris@16 24 #include <boost/graph/parallel/process_group.hpp>
Chris@16 25 #include <boost/graph/distributed/queue.hpp>
Chris@16 26 #include <boost/graph/distributed/filtered_graph.hpp>
Chris@16 27 #include <boost/pending/indirect_cmp.hpp>
Chris@16 28 #include <boost/graph/breadth_first_search.hpp>
Chris@16 29 #include <boost/graph/graph_traits.hpp>
Chris@16 30 #include <boost/graph/overloading.hpp>
Chris@16 31 #include <boost/graph/distributed/concepts.hpp>
Chris@16 32 #include <boost/graph/distributed/local_subgraph.hpp>
Chris@16 33 #include <boost/graph/parallel/properties.hpp>
Chris@16 34 #include <boost/graph/named_function_params.hpp>
Chris@16 35 #include <boost/graph/random.hpp>
Chris@16 36 #include <boost/graph/distributed/reverse_graph.hpp>
Chris@16 37 #include <boost/optional.hpp>
Chris@16 38 #include <boost/graph/distributed/detail/filtered_queue.hpp>
Chris@16 39 #include <boost/graph/distributed/adjacency_list.hpp>
Chris@16 40 #ifdef PBGL_SCC_DEBUG
Chris@16 41 #include <iostream>
Chris@16 42 #include <cstdlib>
Chris@16 43 #include <iomanip>
Chris@16 44 #include <sys/time.h>
Chris@16 45 #include <boost/graph/distributed/graphviz.hpp> // for ostringstream
Chris@16 46 #endif
Chris@16 47 #include <vector>
Chris@16 48 #include <map>
Chris@16 49 #include <boost/graph/parallel/container_traits.hpp>
Chris@16 50
Chris@16 51 #ifdef PBGL_SCC_DEBUG
Chris@16 52 # include <boost/graph/accounting.hpp>
Chris@16 53 #endif /* PBGL_SCC_DEBUG */
Chris@16 54
Chris@16 55 // If your graph is likely to have large numbers of small strongly connected
Chris@16 56 // components then running the sequential SCC algorithm on the local subgraph
Chris@16 57 // and filtering components with no remote edges may increase performance
Chris@16 58 // #define FILTER_LOCAL_COMPONENTS
Chris@16 59
Chris@16 60 namespace boost { namespace graph { namespace distributed { namespace detail {
Chris@16 61
Chris@16 62 template<typename vertex_descriptor>
Chris@16 63 struct v_sets{
Chris@16 64 std::vector<vertex_descriptor> pred, succ, intersect, ps_union;
Chris@16 65 };
Chris@16 66
Chris@16 67 /* Serialize vertex set */
Chris@16 68 template<typename Graph>
Chris@16 69 void
Chris@16 70 marshal_set( std::vector<std::vector<typename graph_traits<Graph>::vertex_descriptor> > in,
Chris@16 71 std::vector<typename graph_traits<Graph>::vertex_descriptor>& out )
Chris@16 72 {
Chris@16 73 for( std::size_t i = 0; i < in.size(); ++i ) {
Chris@16 74 out.insert( out.end(), graph_traits<Graph>::null_vertex() );
Chris@16 75 out.insert( out.end(), in[i].begin(), in[i].end() );
Chris@16 76 }
Chris@16 77 }
Chris@16 78
Chris@16 79 /* Un-serialize vertex set */
Chris@16 80 template<typename Graph>
Chris@16 81 void
Chris@16 82 unmarshal_set( std::vector<typename graph_traits<Graph>::vertex_descriptor> in,
Chris@16 83 std::vector<std::vector<typename graph_traits<Graph>::vertex_descriptor> >& out )
Chris@16 84 {
Chris@16 85 typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
Chris@16 86
Chris@16 87 while( !in.empty() ) {
Chris@16 88 typename std::vector<vertex_descriptor>::iterator end
Chris@16 89 = std::find( in.begin(), in.end(), graph_traits<Graph>::null_vertex() );
Chris@16 90
Chris@16 91 if( end == in.begin() )
Chris@16 92 in.erase( in.begin() );
Chris@16 93 else {
Chris@16 94 out.push_back(std::vector<vertex_descriptor>());
Chris@16 95 out[out.size() - 1].insert( out[out.size() - 1].end(), in.begin(), end );
Chris@16 96 in.erase( in.begin(), end );
Chris@16 97 }
Chris@16 98 }
Chris@16 99 }
Chris@16 100
Chris@16 101 /* Determine if vertex is in subset */
Chris@16 102 template <typename Set>
Chris@16 103 struct in_subset {
Chris@16 104 in_subset() : m_s(0) { }
Chris@16 105 in_subset(const Set& s) : m_s(&s) { }
Chris@16 106
Chris@16 107 template <typename Elt>
Chris@16 108 bool operator()(const Elt& x) const {
Chris@16 109 return ((*m_s).find(x) != (*m_s).end());
Chris@16 110 }
Chris@16 111
Chris@16 112 private:
Chris@16 113 const Set* m_s;
Chris@16 114 };
Chris@16 115
Chris@16 116 template<typename T>
Chris@16 117 struct vertex_identity_property_map
Chris@16 118 : public boost::put_get_helper<T, vertex_identity_property_map<T> >
Chris@16 119 {
Chris@16 120 typedef T key_type;
Chris@16 121 typedef T value_type;
Chris@16 122 typedef T reference;
Chris@16 123 typedef boost::readable_property_map_tag category;
Chris@16 124
Chris@16 125 inline value_type operator[](const key_type& v) const { return v; }
Chris@16 126 inline void clear() { }
Chris@16 127 };
Chris@16 128
Chris@16 129 template <typename T>
Chris@16 130 inline void synchronize( vertex_identity_property_map<T> & ) { }
Chris@16 131
Chris@16 132 /* BFS visitor for SCC */
Chris@16 133 template<typename Graph, typename SourceMap>
Chris@16 134 struct scc_discovery_visitor : bfs_visitor<>
Chris@16 135 {
Chris@16 136 scc_discovery_visitor(SourceMap& sourceM)
Chris@16 137 : sourceM(sourceM) {}
Chris@16 138
Chris@16 139 template<typename Edge>
Chris@16 140 void tree_edge(Edge e, const Graph& g)
Chris@16 141 {
Chris@16 142 put(sourceM, target(e,g), get(sourceM, source(e,g)));
Chris@16 143 }
Chris@16 144
Chris@16 145 private:
Chris@16 146 SourceMap& sourceM;
Chris@16 147 };
Chris@16 148
Chris@16 149 } } } } /* End namespace boost::graph::distributed::detail */
Chris@16 150
Chris@16 151 namespace boost { namespace graph { namespace distributed {
Chris@16 152 enum fhp_message_tags { fhp_edges_size_msg, fhp_add_edges_msg, fhp_pred_size_msg,
Chris@16 153 fhp_pred_msg, fhp_succ_size_msg, fhp_succ_msg };
Chris@16 154
Chris@16 155 template<typename Graph, typename ReverseGraph,
Chris@16 156 typename VertexComponentMap, typename IsoMapFR, typename IsoMapRF,
Chris@16 157 typename VertexIndexMap>
Chris@16 158 void
Chris@16 159 fleischer_hendrickson_pinar_strong_components(const Graph& g,
Chris@16 160 VertexComponentMap c,
Chris@16 161 const ReverseGraph& gr,
Chris@16 162 IsoMapFR fr, IsoMapRF rf,
Chris@16 163 VertexIndexMap vertex_index_map)
Chris@16 164 {
Chris@16 165 typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
Chris@16 166 typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
Chris@16 167 typedef typename graph_traits<ReverseGraph>::vertex_iterator rev_vertex_iterator;
Chris@16 168 typedef typename graph_traits<ReverseGraph>::vertex_descriptor rev_vertex_descriptor;
Chris@16 169 typedef typename boost::graph::parallel::process_group_type<Graph>::type
Chris@16 170 process_group_type;
Chris@16 171 typedef typename process_group_type::process_id_type process_id_type;
Chris@16 172 typedef iterator_property_map<typename std::vector<vertex_descriptor>::iterator,
Chris@16 173 VertexIndexMap> ParentMap;
Chris@16 174 typedef iterator_property_map<typename std::vector<default_color_type>::iterator,
Chris@16 175 VertexIndexMap> ColorMap;
Chris@16 176 typedef iterator_property_map<typename std::vector<vertex_descriptor>::iterator,
Chris@16 177 VertexIndexMap> Rev_ParentMap;
Chris@16 178 typedef std::vector<std::pair<vertex_descriptor, vertex_descriptor> > VertexPairVec;
Chris@16 179
Chris@16 180 typedef typename property_map<Graph, vertex_owner_t>::const_type
Chris@16 181 OwnerMap;
Chris@16 182
Chris@16 183 OwnerMap owner = get(vertex_owner, g);
Chris@16 184
Chris@16 185 using boost::graph::parallel::process_group;
Chris@16 186 process_group_type pg = process_group(g);
Chris@16 187 process_id_type id = process_id(pg);
Chris@16 188 int num_procs = num_processes(pg);
Chris@16 189 int n = 0;
Chris@16 190
Chris@16 191 int my_n = num_vertices(g);
Chris@16 192 all_reduce(pg, &my_n, &my_n+1, &n, std::plus<int>());
Chris@16 193
Chris@16 194 //
Chris@16 195 // Initialization
Chris@16 196 //
Chris@16 197
Chris@16 198 #ifdef PBGL_SCC_DEBUG
Chris@16 199 accounting::time_type start = accounting::get_time();
Chris@16 200 #endif
Chris@16 201
Chris@16 202 vertex_iterator vstart, vend;
Chris@16 203 rev_vertex_iterator rev_vstart, rev_vend;
Chris@16 204 std::vector<std::vector<vertex_descriptor> > vertex_sets, new_vertex_sets;
Chris@16 205
Chris@16 206 vertex_sets.push_back(std::vector<vertex_descriptor>());
Chris@16 207
Chris@16 208 // Remove vertices that do not have at least one in edge and one out edge
Chris@16 209 new_vertex_sets.push_back(std::vector<vertex_descriptor>());
Chris@16 210 for( boost::tie(vstart, vend) = vertices(g); vstart != vend; vstart++ )
Chris@16 211 if( out_degree( get(fr, *vstart), gr) > 0 && out_degree(*vstart, g) > 0 )
Chris@16 212 new_vertex_sets[0].push_back( *vstart );
Chris@16 213
Chris@16 214 // Perform sequential SCC on local subgraph, filter all components with external
Chris@16 215 // edges, mark remaining components and remove them from vertex_sets
Chris@16 216 #ifdef FILTER_LOCAL_COMPONENTS
Chris@16 217 // This doesn't actually speed up SCC in connected graphs it seems, but it does work
Chris@16 218 // and may help in the case where there are lots of small strong components.
Chris@16 219 {
Chris@16 220 local_subgraph<const Graph> ls(g);
Chris@16 221 typedef typename property_map<local_subgraph<const Graph>, vertex_index_t>::type
Chris@16 222 local_index_map_type;
Chris@16 223 local_index_map_type local_index = get(vertex_index, ls);
Chris@16 224
Chris@16 225 std::vector<int> ls_components_vec(num_vertices(ls));
Chris@16 226 typedef iterator_property_map<std::vector<int>::iterator, local_index_map_type>
Chris@16 227 ls_components_map_type;
Chris@16 228 ls_components_map_type ls_component(ls_components_vec.begin(), local_index);
Chris@16 229 int num_comp = boost::strong_components(ls, ls_component);
Chris@16 230
Chris@16 231 // Create map of components
Chris@16 232 std::map<int, std::vector<vertex_descriptor> > local_comp_map;
Chris@16 233 typedef typename graph_traits<local_subgraph<const Graph> >::vertex_iterator ls_vertex_iterator;
Chris@16 234 ls_vertex_iterator vstart, vend;
Chris@16 235 for( boost::tie(vstart,vend) = vertices(ls); vstart != vend; vstart++ )
Chris@16 236 local_comp_map[get(ls_component, *vstart)].push_back( *vstart );
Chris@16 237
Chris@16 238 // Filter components that have no non-local edges
Chris@16 239 typedef typename graph_traits<Graph>::adjacency_iterator adjacency_iterator;
Chris@16 240 typedef typename graph_traits<ReverseGraph>::adjacency_iterator rev_adjacency_iterator;
Chris@16 241 adjacency_iterator abegin, aend;
Chris@16 242 rev_adjacency_iterator rev_abegin, rev_aend;
Chris@16 243 for( std::size_t i = 0; i < num_comp; ++i ) {
Chris@16 244 bool local = true;
Chris@16 245 for( std::size_t j = 0; j < local_comp_map[i].size(); j++ ) {
Chris@16 246 for( boost::tie(abegin,aend) = adjacent_vertices(local_comp_map[i][j], g);
Chris@16 247 abegin != aend; abegin++ )
Chris@16 248 if( get(owner, *abegin) != id ) {
Chris@16 249 local = false;
Chris@16 250 break;
Chris@16 251 }
Chris@16 252
Chris@16 253 if( local )
Chris@16 254 for( boost::tie(rev_abegin,rev_aend) = adjacent_vertices(get(fr, local_comp_map[i][j]), gr);
Chris@16 255 rev_abegin != rev_aend; rev_abegin++ )
Chris@16 256 if( get(owner, *rev_abegin) != id ) {
Chris@16 257 local = false;
Chris@16 258 break;
Chris@16 259 }
Chris@16 260
Chris@16 261 if( !local ) break;
Chris@16 262 }
Chris@16 263
Chris@16 264 if( local ) // Mark and remove from new_vertex_sets
Chris@16 265 for( std::size_t j = 0; j < local_comp_map[i].size(); j++ ) {
Chris@16 266 put( c, local_comp_map[i][j], local_comp_map[i][0] );
Chris@16 267 typename std::vector<vertex_descriptor>::iterator pos =
Chris@16 268 std::find(new_vertex_sets[0].begin(), new_vertex_sets[0].end(), local_comp_map[i][j]);
Chris@16 269 if( pos != new_vertex_sets[0].end() )
Chris@16 270 new_vertex_sets[0].erase(pos);
Chris@16 271 }
Chris@16 272 }
Chris@16 273 }
Chris@16 274 #endif // FILTER_LOCAL_COMPONENTS
Chris@16 275
Chris@16 276 all_gather( pg, new_vertex_sets[0].begin(), new_vertex_sets[0].end(), vertex_sets[0] );
Chris@16 277 new_vertex_sets.clear();
Chris@16 278
Chris@16 279 #ifdef PBGL_SCC_DEBUG
Chris@16 280 accounting::time_type end = accounting::get_time();
Chris@16 281 if(id == 0)
Chris@16 282 std::cerr << "Trim local SCCs time = " << accounting::print_time(end - start) << " seconds.\n";
Chris@16 283 #endif
Chris@16 284
Chris@16 285 if( vertex_sets[0].empty() ) return;
Chris@16 286
Chris@16 287 //
Chris@16 288 // Recursively determine SCCs
Chris@16 289 //
Chris@16 290
Chris@16 291 #ifdef PBGL_SCC_DEBUG
Chris@16 292 int iterations = 0;
Chris@16 293 #endif
Chris@16 294
Chris@16 295 // Only need to be able to map starting vertices for BFS from now on
Chris@16 296 fr.clear();
Chris@16 297
Chris@16 298 do {
Chris@16 299
Chris@16 300 #ifdef PBGL_SCC_DEBUG
Chris@16 301 if(id == 0) {
Chris@16 302 printf("\n\nIteration %d:\n\n", iterations++);
Chris@16 303
Chris@16 304 if( iterations > 1 ) {
Chris@16 305 end = accounting::get_time();
Chris@16 306 std::cerr << "Running main loop destructors time = " << accounting::print_time(end - start) << " seconds.\n";
Chris@16 307 }
Chris@16 308
Chris@16 309 start = accounting::get_time();
Chris@16 310 }
Chris@16 311 #endif
Chris@16 312
Chris@16 313 // Get forward->reverse mappings for BFS start vertices
Chris@16 314 for (std::size_t i = 0; i < vertex_sets.size(); ++i)
Chris@16 315 get(fr, vertex_sets[i][0]);
Chris@16 316 synchronize(fr);
Chris@16 317
Chris@16 318 // Determine local vertices to start BFS from
Chris@16 319 std::vector<vertex_descriptor> local_start;
Chris@16 320 for( std::size_t i = id; i < vertex_sets.size(); i += num_procs )
Chris@16 321 local_start.push_back(vertex_sets[i][0]);
Chris@16 322
Chris@16 323 if( local_start.empty() )
Chris@16 324 local_start.push_back(vertex_sets[0][0]);
Chris@16 325
Chris@16 326
Chris@16 327 // Make filtered graphs
Chris@16 328 typedef std::set<vertex_descriptor> VertexSet;
Chris@16 329 typedef std::set<rev_vertex_descriptor> Rev_VertexSet;
Chris@16 330
Chris@16 331 VertexSet filter_set_g;
Chris@16 332 Rev_VertexSet filter_set_gr;
Chris@16 333 typename VertexSet::iterator fs;
Chris@16 334
Chris@16 335 int active_vertices = 0;
Chris@16 336 for (std::size_t i = 0; i < vertex_sets.size(); i++)
Chris@16 337 active_vertices += vertex_sets[i].size();
Chris@16 338
Chris@16 339 // This is a completely random bound
Chris@16 340 if ( active_vertices < 0.05*n ) {
Chris@16 341 // TODO: This set insertion is ridiculously inefficient, make it an in-place-merge?
Chris@16 342 for (std::size_t i = 0; i < vertex_sets.size(); i++)
Chris@16 343 filter_set_g.insert(vertex_sets[i].begin(), vertex_sets[i].end());
Chris@16 344
Chris@16 345 for (fs = filter_set_g.begin(); fs != filter_set_g.end(); ++fs )
Chris@16 346 filter_set_gr.insert(get(fr, *fs));
Chris@16 347 }
Chris@16 348
Chris@16 349 filtered_graph<const Graph, keep_all, detail::in_subset<VertexSet> >
Chris@16 350 fg(g, keep_all(), detail::in_subset<VertexSet>(filter_set_g));
Chris@16 351
Chris@16 352 filtered_graph<const ReverseGraph, keep_all, detail::in_subset<VertexSet> >
Chris@16 353 fgr(gr, keep_all(), detail::in_subset<VertexSet>(filter_set_gr));
Chris@16 354
Chris@16 355 // Add additional starting vertices to BFS queue
Chris@16 356 typedef filtered_queue<queue<vertex_descriptor>, boost::detail::has_not_been_seen<VertexIndexMap> >
Chris@16 357 local_queue_type;
Chris@16 358 typedef boost::graph::distributed::distributed_queue<process_group_type, OwnerMap, local_queue_type>
Chris@16 359 queue_t;
Chris@16 360
Chris@16 361 typedef typename property_map<ReverseGraph, vertex_owner_t>::const_type
Chris@16 362 RevOwnerMap;
Chris@16 363
Chris@16 364 typedef filtered_queue<queue<rev_vertex_descriptor>, boost::detail::has_not_been_seen<VertexIndexMap> >
Chris@16 365 rev_local_queue_type;
Chris@16 366 typedef boost::graph::distributed::distributed_queue<process_group_type, RevOwnerMap, rev_local_queue_type>
Chris@16 367 rev_queue_t;
Chris@16 368
Chris@16 369 queue_t Q(process_group(g),
Chris@16 370 owner,
Chris@16 371 make_filtered_queue(queue<vertex_descriptor>(),
Chris@16 372 boost::detail::has_not_been_seen<VertexIndexMap>
Chris@16 373 (num_vertices(g), vertex_index_map)),
Chris@16 374 false);
Chris@16 375
Chris@16 376 rev_queue_t Qr(process_group(gr),
Chris@16 377 get(vertex_owner, gr),
Chris@16 378 make_filtered_queue(queue<rev_vertex_descriptor>(),
Chris@16 379 boost::detail::has_not_been_seen<VertexIndexMap>
Chris@16 380 (num_vertices(gr), vertex_index_map)),
Chris@16 381 false);
Chris@16 382
Chris@16 383 for( std::size_t i = 1; i < local_start.size(); ++i ) {
Chris@16 384 Q.push(local_start[i]);
Chris@16 385 Qr.push(get(fr, local_start[i]));
Chris@16 386 }
Chris@16 387
Chris@16 388 #ifdef PBGL_SCC_DEBUG
Chris@16 389 end = accounting::get_time();
Chris@16 390 if(id == 0)
Chris@16 391 std::cerr << " Initialize BFS time = " << accounting::print_time(end - start) << " seconds.\n";
Chris@16 392 start = accounting::get_time();
Chris@16 393 #endif
Chris@16 394
Chris@16 395 #ifdef PBGL_SCC_DEBUG
Chris@16 396 accounting::time_type start2 = accounting::get_time();
Chris@16 397 #endif
Chris@16 398
Chris@16 399 // Forward BFS
Chris@16 400 std::vector<default_color_type> color_map_s(num_vertices(g));
Chris@16 401 ColorMap color_map(color_map_s.begin(), vertex_index_map);
Chris@16 402 std::vector<vertex_descriptor> succ_map_s(num_vertices(g), graph_traits<Graph>::null_vertex());
Chris@16 403 ParentMap succ_map(succ_map_s.begin(), vertex_index_map);
Chris@16 404
Chris@16 405 for( std::size_t i = 0; i < vertex_sets.size(); ++i )
Chris@16 406 put(succ_map, vertex_sets[i][0], vertex_sets[i][0]);
Chris@16 407
Chris@16 408 #ifdef PBGL_SCC_DEBUG
Chris@16 409 accounting::time_type end2 = accounting::get_time();
Chris@16 410 if(id == 0)
Chris@16 411 std::cerr << " Initialize forward BFS time = " << accounting::print_time(end2 - start2) << " seconds.\n";
Chris@16 412 #endif
Chris@16 413
Chris@16 414 if (active_vertices < 0.05*n)
Chris@16 415 breadth_first_search(fg, local_start[0], Q,
Chris@16 416 detail::scc_discovery_visitor<filtered_graph<const Graph, keep_all,
Chris@16 417 detail::in_subset<VertexSet> >, ParentMap>
Chris@16 418 (succ_map),
Chris@16 419 color_map);
Chris@16 420 else
Chris@16 421 breadth_first_search(g, local_start[0], Q,
Chris@16 422 detail::scc_discovery_visitor<const Graph, ParentMap>(succ_map),
Chris@16 423 color_map);
Chris@16 424
Chris@16 425 #ifdef PBGL_SCC_DEBUG
Chris@16 426 start2 = accounting::get_time();
Chris@16 427 #endif
Chris@16 428
Chris@16 429 // Reverse BFS
Chris@16 430 color_map.clear(); // reuse color map since g and gr have same vertex index
Chris@16 431 std::vector<vertex_descriptor> pred_map_s(num_vertices(gr), graph_traits<Graph>::null_vertex());
Chris@16 432 Rev_ParentMap pred_map(pred_map_s.begin(), vertex_index_map);
Chris@16 433
Chris@16 434 for( std::size_t i = 0; i < vertex_sets.size(); ++i )
Chris@16 435 put(pred_map, get(fr, vertex_sets[i][0]), vertex_sets[i][0]);
Chris@16 436
Chris@16 437 #ifdef PBGL_SCC_DEBUG
Chris@16 438 end2 = accounting::get_time();
Chris@16 439 if(id == 0)
Chris@16 440 std::cerr << " Initialize reverse BFS time = " << accounting::print_time(end2 - start2) << " seconds.\n";
Chris@16 441 #endif
Chris@16 442
Chris@16 443 if (active_vertices < 0.05*n)
Chris@16 444 breadth_first_search(fgr, get(fr, local_start[0]),
Chris@16 445 Qr,
Chris@16 446 detail::scc_discovery_visitor<filtered_graph<const ReverseGraph, keep_all,
Chris@16 447 detail::in_subset<Rev_VertexSet> >, Rev_ParentMap>
Chris@16 448 (pred_map),
Chris@16 449 color_map);
Chris@16 450 else
Chris@16 451 breadth_first_search(gr, get(fr, local_start[0]),
Chris@16 452 Qr,
Chris@16 453 detail::scc_discovery_visitor<const ReverseGraph, Rev_ParentMap>(pred_map),
Chris@16 454 color_map);
Chris@16 455
Chris@16 456 #ifdef PBGL_SCC_DEBUG
Chris@16 457 end = accounting::get_time();
Chris@16 458 if(id == 0)
Chris@16 459 std::cerr << " Perform forward and reverse BFS time = " << accounting::print_time(end - start) << " seconds.\n";
Chris@16 460 start = accounting::get_time();
Chris@16 461 #endif
Chris@16 462
Chris@16 463 // Send predecessors and successors discovered by this proc to the proc responsible for
Chris@16 464 // this BFS tree
Chris@16 465 typedef struct detail::v_sets<vertex_descriptor> Vsets;
Chris@16 466 std::map<vertex_descriptor, Vsets> set_map;
Chris@16 467
Chris@16 468 std::map<vertex_descriptor, int> dest_map;
Chris@16 469
Chris@16 470 std::vector<VertexPairVec> successors(num_procs);
Chris@16 471 std::vector<VertexPairVec> predecessors(num_procs);
Chris@16 472
Chris@16 473 // Calculate destinations for messages
Chris@16 474 for (std::size_t i = 0; i < vertex_sets.size(); ++i)
Chris@16 475 dest_map[vertex_sets[i][0]] = i % num_procs;
Chris@16 476
Chris@16 477 for( boost::tie(vstart, vend) = vertices(g); vstart != vend; vstart++ ) {
Chris@16 478 vertex_descriptor v = get(succ_map, *vstart);
Chris@16 479 if( v != graph_traits<Graph>::null_vertex() ) {
Chris@16 480 if (dest_map[v] == id)
Chris@16 481 set_map[v].succ.push_back(*vstart);
Chris@16 482 else
Chris@16 483 successors[dest_map[v]].push_back( std::make_pair(v, *vstart) );
Chris@16 484 }
Chris@16 485 }
Chris@16 486
Chris@16 487 for( boost::tie(rev_vstart, rev_vend) = vertices(gr); rev_vstart != rev_vend; rev_vstart++ ) {
Chris@16 488 vertex_descriptor v = get(pred_map, *rev_vstart);
Chris@16 489 if( v != graph_traits<Graph>::null_vertex() ) {
Chris@16 490 if (dest_map[v] == id)
Chris@16 491 set_map[v].pred.push_back(get(rf, *rev_vstart));
Chris@16 492 else
Chris@16 493 predecessors[dest_map[v]].push_back( std::make_pair(v, get(rf, *rev_vstart)) );
Chris@16 494 }
Chris@16 495 }
Chris@16 496
Chris@16 497 // Send predecessor and successor messages
Chris@16 498 for (process_id_type i = 0; i < num_procs; ++i) {
Chris@16 499 if (!successors[i].empty()) {
Chris@16 500 send(pg, i, fhp_succ_size_msg, successors[i].size());
Chris@16 501 send(pg, i, fhp_succ_msg, &successors[i][0], successors[i].size());
Chris@16 502 }
Chris@16 503 if (!predecessors[i].empty()) {
Chris@16 504 send(pg, i, fhp_pred_size_msg, predecessors[i].size());
Chris@16 505 send(pg, i, fhp_pred_msg, &predecessors[i][0], predecessors[i].size());
Chris@16 506 }
Chris@16 507 }
Chris@16 508 synchronize(pg);
Chris@16 509
Chris@16 510 // Receive predecessor and successor messages and handle them
Chris@16 511 while (optional<std::pair<process_id_type, int> > m = probe(pg)) {
Chris@16 512 BOOST_ASSERT(m->second == fhp_succ_size_msg || m->second == fhp_pred_size_msg);
Chris@16 513 std::size_t num_requests;
Chris@16 514 receive(pg, m->first, m->second, num_requests);
Chris@16 515 VertexPairVec requests(num_requests);
Chris@16 516 if (m->second == fhp_succ_size_msg) {
Chris@16 517 receive(pg, m->first, fhp_succ_msg, &requests[0],
Chris@16 518 num_requests);
Chris@16 519
Chris@16 520 std::map<vertex_descriptor, int> added;
Chris@16 521 for (std::size_t i = 0; i < requests.size(); ++i) {
Chris@16 522 set_map[requests[i].first].succ.push_back(requests[i].second);
Chris@16 523 added[requests[i].first]++;
Chris@16 524 }
Chris@16 525
Chris@16 526 // If order of vertex traversal in vertices() is std::less<vertex_descriptor>,
Chris@16 527 // then the successor sets will be in order
Chris@16 528 for (std::size_t i = 0; i < local_start.size(); ++i)
Chris@16 529 if (added[local_start[i]] > 0)
Chris@16 530 std::inplace_merge(set_map[local_start[i]].succ.begin(),
Chris@16 531 set_map[local_start[i]].succ.end() - added[local_start[i]],
Chris@16 532 set_map[local_start[i]].succ.end(),
Chris@16 533 std::less<vertex_descriptor>());
Chris@16 534
Chris@16 535 } else {
Chris@16 536 receive(pg, m->first, fhp_pred_msg, &requests[0],
Chris@16 537 num_requests);
Chris@16 538
Chris@16 539 std::map<vertex_descriptor, int> added;
Chris@16 540 for (std::size_t i = 0; i < requests.size(); ++i) {
Chris@16 541 set_map[requests[i].first].pred.push_back(requests[i].second);
Chris@16 542 added[requests[i].first]++;
Chris@16 543 }
Chris@16 544
Chris@16 545 if (boost::is_same<detail::vertex_identity_property_map<vertex_descriptor>, IsoMapRF>::value)
Chris@16 546 for (std::size_t i = 0; i < local_start.size(); ++i)
Chris@16 547 if (added[local_start[i]] > 0)
Chris@16 548 std::inplace_merge(set_map[local_start[i]].pred.begin(),
Chris@16 549 set_map[local_start[i]].pred.end() - added[local_start[i]],
Chris@16 550 set_map[local_start[i]].pred.end(),
Chris@16 551 std::less<vertex_descriptor>());
Chris@16 552 }
Chris@16 553 }
Chris@16 554
Chris@16 555 #ifdef PBGL_SCC_DEBUG
Chris@16 556 end = accounting::get_time();
Chris@16 557 if(id == 0)
Chris@16 558 std::cerr << " All gather successors and predecessors time = " << accounting::print_time(end - start) << " seconds.\n";
Chris@16 559 start = accounting::get_time();
Chris@16 560 #endif
Chris@16 561
Chris@16 562 //
Chris@16 563 // Filter predecessor and successor sets and perform set arithmetic
Chris@16 564 //
Chris@16 565 new_vertex_sets.clear();
Chris@16 566
Chris@16 567 if( std::size_t(id) < vertex_sets.size() ) { //If this proc has one or more unique starting points
Chris@16 568
Chris@16 569 for( std::size_t i = 0; i < local_start.size(); ++i ) {
Chris@16 570
Chris@16 571 vertex_descriptor v = local_start[i];
Chris@16 572
Chris@16 573 // Replace this sort with an in-place merges during receive step if possible
Chris@16 574 if (!boost::is_same<detail::vertex_identity_property_map<vertex_descriptor>, IsoMapRF>::value)
Chris@16 575 std::sort(set_map[v].pred.begin(), set_map[v].pred.end(), std::less<vertex_descriptor>());
Chris@16 576
Chris@16 577 // Limit predecessor and successor sets to members of the original set
Chris@16 578 std::vector<vertex_descriptor> temp;
Chris@16 579
Chris@16 580 std::set_intersection( vertex_sets[id + i*num_procs].begin(), vertex_sets[id + i*num_procs].end(),
Chris@16 581 set_map[v].pred.begin(), set_map[v].pred.end(),
Chris@16 582 back_inserter(temp),
Chris@16 583 std::less<vertex_descriptor>());
Chris@16 584 set_map[v].pred.clear();
Chris@16 585 std::swap(set_map[v].pred, temp);
Chris@16 586
Chris@16 587 std::set_intersection( vertex_sets[id + i*num_procs].begin(), vertex_sets[id + i*num_procs].end(),
Chris@16 588 set_map[v].succ.begin(), set_map[v].succ.end(),
Chris@16 589 back_inserter(temp),
Chris@16 590 std::less<vertex_descriptor>());
Chris@16 591 set_map[v].succ.clear();
Chris@16 592 std::swap(set_map[v].succ, temp);
Chris@16 593
Chris@16 594 // Intersection(pred, succ)
Chris@16 595 std::set_intersection(set_map[v].pred.begin(), set_map[v].pred.end(),
Chris@16 596 set_map[v].succ.begin(), set_map[v].succ.end(),
Chris@16 597 back_inserter(set_map[v].intersect),
Chris@16 598 std::less<vertex_descriptor>());
Chris@16 599
Chris@16 600 // Union(pred, succ)
Chris@16 601 std::set_union(set_map[v].pred.begin(), set_map[v].pred.end(),
Chris@16 602 set_map[v].succ.begin(), set_map[v].succ.end(),
Chris@16 603 back_inserter(set_map[v].ps_union),
Chris@16 604 std::less<vertex_descriptor>());
Chris@16 605
Chris@16 606 new_vertex_sets.push_back(std::vector<vertex_descriptor>());
Chris@16 607 // Original set - Union(pred, succ)
Chris@16 608 std::set_difference(vertex_sets[id + i*num_procs].begin(), vertex_sets[id + i*num_procs].end(),
Chris@16 609 set_map[v].ps_union.begin(), set_map[v].ps_union.end(),
Chris@16 610 back_inserter(new_vertex_sets[new_vertex_sets.size() - 1]),
Chris@16 611 std::less<vertex_descriptor>());
Chris@16 612
Chris@16 613 set_map[v].ps_union.clear();
Chris@16 614
Chris@16 615 new_vertex_sets.push_back(std::vector<vertex_descriptor>());
Chris@16 616 // Pred - Intersect(pred, succ)
Chris@16 617 std::set_difference(set_map[v].pred.begin(), set_map[v].pred.end(),
Chris@16 618 set_map[v].intersect.begin(), set_map[v].intersect.end(),
Chris@16 619 back_inserter(new_vertex_sets[new_vertex_sets.size() - 1]),
Chris@16 620 std::less<vertex_descriptor>());
Chris@16 621
Chris@16 622 set_map[v].pred.clear();
Chris@16 623
Chris@16 624 new_vertex_sets.push_back(std::vector<vertex_descriptor>());
Chris@16 625 // Succ - Intersect(pred, succ)
Chris@16 626 std::set_difference(set_map[v].succ.begin(), set_map[v].succ.end(),
Chris@16 627 set_map[v].intersect.begin(), set_map[v].intersect.end(),
Chris@16 628 back_inserter(new_vertex_sets[new_vertex_sets.size() - 1]),
Chris@16 629 std::less<vertex_descriptor>());
Chris@16 630
Chris@16 631 set_map[v].succ.clear();
Chris@16 632
Chris@16 633 // Label SCC just identified with the 'first' vertex in that SCC
Chris@16 634 for( std::size_t j = 0; j < set_map[v].intersect.size(); j++ )
Chris@16 635 put(c, set_map[v].intersect[j], set_map[v].intersect[0]);
Chris@16 636
Chris@16 637 set_map[v].intersect.clear();
Chris@16 638 }
Chris@16 639 }
Chris@16 640
Chris@16 641 #ifdef PBGL_SCC_DEBUG
Chris@16 642 end = accounting::get_time();
Chris@16 643 if(id == 0)
Chris@16 644 std::cerr << " Perform set arithemetic time = " << accounting::print_time(end - start) << " seconds.\n";
Chris@16 645 start = accounting::get_time();
Chris@16 646 #endif
Chris@16 647
Chris@16 648 // Remove sets of size 1 from new_vertex_sets
Chris@16 649 typename std::vector<std::vector<vertex_descriptor> >::iterator vviter;
Chris@16 650 for( vviter = new_vertex_sets.begin(); vviter != new_vertex_sets.end(); /*in loop*/ )
Chris@16 651 if( (*vviter).size() < 2 )
Chris@16 652 vviter = new_vertex_sets.erase( vviter );
Chris@16 653 else
Chris@16 654 vviter++;
Chris@16 655
Chris@16 656 // All gather new sets and recur (gotta marshal and unmarshal sets first)
Chris@16 657 vertex_sets.clear();
Chris@16 658 std::vector<vertex_descriptor> serial_sets, all_serial_sets;
Chris@16 659 detail::marshal_set<Graph>( new_vertex_sets, serial_sets );
Chris@16 660 all_gather( pg, serial_sets.begin(), serial_sets.end(), all_serial_sets );
Chris@16 661 detail::unmarshal_set<Graph>( all_serial_sets, vertex_sets );
Chris@16 662
Chris@16 663 #ifdef PBGL_SCC_DEBUG
Chris@16 664 end = accounting::get_time();
Chris@16 665 if(id == 0) {
Chris@16 666 std::cerr << " Serialize and gather new vertex sets time = " << accounting::print_time(end - start) << " seconds.\n\n\n";
Chris@16 667
Chris@16 668 printf("Vertex sets: %d\n", (int)vertex_sets.size() );
Chris@16 669 for( std::size_t i = 0; i < vertex_sets.size(); ++i )
Chris@16 670 printf(" %d: %d\n", i, (int)vertex_sets[i].size() );
Chris@16 671 }
Chris@16 672 start = accounting::get_time();
Chris@16 673 #endif
Chris@16 674
Chris@16 675 // HACK!?! -- This would be more properly implemented as a topological sort
Chris@16 676 // Remove vertices without an edge to another vertex in the set and an edge from another
Chris@16 677 // vertex in the set
Chris@16 678 typedef typename graph_traits<Graph>::out_edge_iterator out_edge_iterator;
Chris@16 679 out_edge_iterator estart, eend;
Chris@16 680 typedef typename graph_traits<ReverseGraph>::out_edge_iterator r_out_edge_iterator;
Chris@16 681 r_out_edge_iterator restart, reend;
Chris@16 682 for (std::size_t i = 0; i < vertex_sets.size(); ++i) {
Chris@16 683 std::vector<vertex_descriptor> new_set;
Chris@16 684 for (std::size_t j = 0; j < vertex_sets[i].size(); ++j) {
Chris@16 685 vertex_descriptor v = vertex_sets[i][j];
Chris@16 686 if (get(owner, v) == id) {
Chris@16 687 boost::tie(estart, eend) = out_edges(v, g);
Chris@16 688 while (estart != eend && find(vertex_sets[i].begin(), vertex_sets[i].end(),
Chris@16 689 target(*estart,g)) == vertex_sets[i].end()) estart++;
Chris@16 690 if (estart != eend) {
Chris@16 691 boost::tie(restart, reend) = out_edges(get(fr, v), gr);
Chris@16 692 while (restart != reend && find(vertex_sets[i].begin(), vertex_sets[i].end(),
Chris@16 693 get(rf, target(*restart,gr))) == vertex_sets[i].end()) restart++;
Chris@16 694 if (restart != reend)
Chris@16 695 new_set.push_back(v);
Chris@16 696 }
Chris@16 697 }
Chris@16 698 }
Chris@16 699 vertex_sets[i].clear();
Chris@16 700 all_gather(pg, new_set.begin(), new_set.end(), vertex_sets[i]);
Chris@16 701 std::sort(vertex_sets[i].begin(), vertex_sets[i].end(), std::less<vertex_descriptor>());
Chris@16 702 }
Chris@16 703 #ifdef PBGL_SCC_DEBUG
Chris@16 704 end = accounting::get_time();
Chris@16 705 if(id == 0)
Chris@16 706 std::cerr << " Trim vertex sets time = " << accounting::print_time(end - start) << " seconds.\n\n\n";
Chris@16 707 start = accounting::get_time();
Chris@16 708 #endif
Chris@16 709
Chris@16 710 } while ( !vertex_sets.empty() );
Chris@16 711
Chris@16 712
Chris@16 713 // Label vertices not in a SCC as their own SCC
Chris@16 714 for( boost::tie(vstart, vend) = vertices(g); vstart != vend; vstart++ )
Chris@16 715 if( get(c, *vstart) == graph_traits<Graph>::null_vertex() )
Chris@16 716 put(c, *vstart, *vstart);
Chris@16 717
Chris@16 718 synchronize(c);
Chris@16 719 }
Chris@16 720
Chris@16 721 template<typename Graph, typename ReverseGraph, typename IsoMap>
Chris@16 722 void
Chris@16 723 build_reverse_graph( const Graph& g, ReverseGraph& gr, IsoMap& fr, IsoMap& rf )
Chris@16 724 {
Chris@16 725 typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
Chris@16 726 typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
Chris@16 727 typedef typename graph_traits<Graph>::out_edge_iterator out_edge_iterator;
Chris@16 728 typedef typename boost::graph::parallel::process_group_type<Graph>::type process_group_type;
Chris@16 729 typedef typename process_group_type::process_id_type process_id_type;
Chris@16 730 typedef std::vector<std::pair<vertex_descriptor, vertex_descriptor> > VertexPairVec;
Chris@16 731
Chris@16 732 typename property_map<Graph, vertex_owner_t>::const_type
Chris@16 733 owner = get(vertex_owner, g);
Chris@16 734
Chris@16 735 process_group_type pg = process_group(g);
Chris@16 736 process_id_type id = process_id(pg);
Chris@16 737
Chris@16 738 int n;
Chris@16 739 vertex_iterator vstart, vend;
Chris@16 740 int num_procs = num_processes(pg);
Chris@16 741
Chris@16 742 vertex_descriptor v;
Chris@16 743 out_edge_iterator oestart, oeend;
Chris@16 744 for( boost::tie(vstart, vend) = vertices(g); vstart != vend; vstart++ )
Chris@16 745 {
Chris@16 746 v = add_vertex(gr);
Chris@16 747 put(fr, *vstart, v);
Chris@16 748 put(rf, v, *vstart);
Chris@16 749 }
Chris@16 750
Chris@16 751 gr.distribution() = g.distribution();
Chris@16 752
Chris@16 753 int my_n = num_vertices(g);
Chris@16 754 all_reduce(pg, &my_n, &my_n+1, &n, std::plus<int>());
Chris@16 755
Chris@16 756 for (int i = 0; i < n; ++i)
Chris@16 757 get(fr, vertex(i,g));
Chris@16 758 synchronize(fr);
Chris@16 759
Chris@16 760 // Add edges to gr
Chris@16 761 std::vector<std::pair<vertex_descriptor, vertex_descriptor> > new_edges;
Chris@16 762 for( boost::tie(vstart, vend) = vertices(g); vstart != vend; vstart++ )
Chris@16 763 for( boost::tie(oestart, oeend) = out_edges(*vstart, g); oestart != oeend; oestart++ )
Chris@16 764 new_edges.push_back( std::make_pair(get(fr, target(*oestart,g)), get(fr, source(*oestart, g))) );
Chris@16 765
Chris@16 766 std::vector<VertexPairVec> edge_requests(num_procs);
Chris@16 767
Chris@16 768 typename std::vector<std::pair<vertex_descriptor, vertex_descriptor> >::iterator iter;
Chris@16 769 for( iter = new_edges.begin(); iter != new_edges.end(); iter++ ) {
Chris@16 770 std::pair<vertex_descriptor, vertex_descriptor> p1 = *iter;
Chris@16 771 if( get(owner, p1.first ) == id )
Chris@16 772 add_edge( p1.first, p1.second, gr );
Chris@16 773 else
Chris@16 774 edge_requests[get(owner, p1.first)].push_back(p1);
Chris@16 775 }
Chris@16 776 new_edges.clear();
Chris@16 777
Chris@16 778 // Send edge addition requests
Chris@16 779 for (process_id_type p = 0; p < num_procs; ++p) {
Chris@16 780 if (!edge_requests[p].empty()) {
Chris@16 781 VertexPairVec reqs(edge_requests[p].begin(), edge_requests[p].end());
Chris@16 782 send(pg, p, fhp_edges_size_msg, reqs.size());
Chris@16 783 send(pg, p, fhp_add_edges_msg, &reqs[0], reqs.size());
Chris@16 784 }
Chris@16 785 }
Chris@16 786 synchronize(pg);
Chris@16 787
Chris@16 788 // Receive edge addition requests and handle them
Chris@16 789 while (optional<std::pair<process_id_type, int> > m = probe(pg)) {
Chris@16 790 BOOST_ASSERT(m->second == fhp_edges_size_msg);
Chris@16 791 std::size_t num_requests;
Chris@16 792 receive(pg, m->first, m->second, num_requests);
Chris@16 793 VertexPairVec requests(num_requests);
Chris@16 794 receive(pg, m->first, fhp_add_edges_msg, &requests[0],
Chris@16 795 num_requests);
Chris@16 796 for( std::size_t i = 0; i < requests.size(); ++i )
Chris@16 797 add_edge( requests[i].first, requests[i].second, gr );
Chris@16 798 }
Chris@16 799 synchronize(gr);
Chris@16 800 }
Chris@16 801
Chris@16 802 template<typename Graph, typename VertexComponentMap, typename ComponentMap>
Chris@16 803 typename property_traits<ComponentMap>::value_type
Chris@16 804 number_components(const Graph& g, VertexComponentMap r, ComponentMap c)
Chris@16 805 {
Chris@16 806 typedef typename boost::graph::parallel::process_group_type<Graph>::type process_group_type;
Chris@16 807 typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
Chris@16 808 typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
Chris@16 809 typedef typename property_traits<ComponentMap>::value_type ComponentMapType;
Chris@16 810 std::vector<vertex_descriptor> my_roots, all_roots;
Chris@16 811 vertex_iterator vstart, vend;
Chris@16 812
Chris@16 813 for( boost::tie(vstart, vend) = vertices(g); vstart != vend; vstart++ )
Chris@16 814 if( find( my_roots.begin(), my_roots.end(), get(r, *vstart) ) == my_roots.end() )
Chris@16 815 my_roots.push_back( get(r, *vstart) );
Chris@16 816
Chris@16 817 all_gather( process_group(g), my_roots.begin(), my_roots.end(), all_roots );
Chris@16 818
Chris@16 819 /* Number components */
Chris@16 820 std::map<vertex_descriptor, ComponentMapType> comp_numbers;
Chris@16 821 ComponentMapType c_num = 0;
Chris@16 822
Chris@16 823 // Compute component numbers
Chris@16 824 for (std::size_t i = 0; i < all_roots.size(); ++i )
Chris@16 825 if ( comp_numbers.count(all_roots[i]) == 0 )
Chris@16 826 comp_numbers[all_roots[i]] = c_num++;
Chris@16 827
Chris@16 828 // Broadcast component numbers
Chris@16 829 for( boost::tie(vstart, vend) = vertices(g); vstart != vend; vstart++ )
Chris@16 830 put( c, *vstart, comp_numbers[get(r,*vstart)] );
Chris@16 831
Chris@16 832 // Broadcast number of components
Chris@16 833 if (process_id(process_group(g)) == 0) {
Chris@16 834 typedef typename process_group_type::process_size_type
Chris@16 835 process_size_type;
Chris@16 836 for (process_size_type dest = 1, n = num_processes(process_group(g));
Chris@16 837 dest != n; ++dest)
Chris@16 838 send(process_group(g), dest, 0, c_num);
Chris@16 839 }
Chris@16 840
Chris@16 841 synchronize(process_group(g));
Chris@16 842
Chris@16 843 if (process_id(process_group(g)) != 0) receive(process_group(g), 0, 0, c_num);
Chris@16 844
Chris@16 845 synchronize(c);
Chris@16 846 return c_num;
Chris@16 847 }
Chris@16 848
Chris@16 849
Chris@16 850 template<typename Graph, typename ComponentMap, typename VertexComponentMap,
Chris@16 851 typename VertexIndexMap>
Chris@16 852 typename property_traits<ComponentMap>::value_type
Chris@16 853 fleischer_hendrickson_pinar_strong_components_impl
Chris@16 854 (const Graph& g,
Chris@16 855 ComponentMap c,
Chris@16 856 VertexComponentMap r,
Chris@16 857 VertexIndexMap vertex_index_map,
Chris@16 858 incidence_graph_tag)
Chris@16 859 {
Chris@16 860 typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
Chris@16 861 typedef iterator_property_map<typename std::vector<vertex_descriptor>::iterator,
Chris@16 862 VertexIndexMap> IsoMap;
Chris@16 863 typename boost::graph::parallel::process_group_type<Graph>::type pg = process_group(g);
Chris@16 864
Chris@16 865 #ifdef PBGL_SCC_DEBUG
Chris@16 866 accounting::time_type start = accounting::get_time();
Chris@16 867 #endif
Chris@16 868
Chris@16 869 typedef adjacency_list<listS,
Chris@16 870 distributedS<typename boost::graph::parallel::process_group_type<Graph>::type, vecS>,
Chris@16 871 directedS > ReverseGraph;
Chris@16 872
Chris@16 873 ReverseGraph gr(0, pg);
Chris@16 874 std::vector<vertex_descriptor> fr_s(num_vertices(g));
Chris@16 875 std::vector<vertex_descriptor> rf_s(num_vertices(g));
Chris@16 876 IsoMap fr(fr_s.begin(), vertex_index_map); // fr = forward->reverse
Chris@16 877 IsoMap rf(rf_s.begin(), vertex_index_map); // rf = reverse->forward
Chris@16 878
Chris@16 879 build_reverse_graph(g, gr, fr, rf);
Chris@16 880
Chris@16 881 #ifdef PBGL_SCC_DEBUG
Chris@16 882 accounting::time_type end = accounting::get_time();
Chris@16 883 if(process_id(process_group(g)) == 0)
Chris@16 884 std::cerr << "Reverse graph initialization time = " << accounting::print_time(end - start) << " seconds.\n";
Chris@16 885 #endif
Chris@16 886
Chris@16 887 fleischer_hendrickson_pinar_strong_components(g, r, gr, fr, rf,
Chris@16 888 vertex_index_map);
Chris@16 889
Chris@16 890 typename property_traits<ComponentMap>::value_type c_num = number_components(g, r, c);
Chris@16 891
Chris@16 892 return c_num;
Chris@16 893 }
Chris@16 894
Chris@16 895 template<typename Graph, typename ComponentMap, typename VertexComponentMap,
Chris@16 896 typename VertexIndexMap>
Chris@16 897 typename property_traits<ComponentMap>::value_type
Chris@16 898 fleischer_hendrickson_pinar_strong_components_impl
Chris@16 899 (const Graph& g,
Chris@16 900 ComponentMap c,
Chris@16 901 VertexComponentMap r,
Chris@16 902 VertexIndexMap vertex_index_map,
Chris@16 903 bidirectional_graph_tag)
Chris@16 904 {
Chris@16 905 typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
Chris@16 906
Chris@16 907 reverse_graph<Graph> gr(g);
Chris@16 908 detail::vertex_identity_property_map<vertex_descriptor> fr, rf;
Chris@16 909
Chris@16 910 fleischer_hendrickson_pinar_strong_components(g, r, gr, fr, rf,
Chris@16 911 vertex_index_map);
Chris@16 912
Chris@16 913 typename property_traits<ComponentMap>::value_type c_num
Chris@16 914 = number_components(g, r, c);
Chris@16 915
Chris@16 916 return c_num;
Chris@16 917 }
Chris@16 918
Chris@16 919 template<typename Graph, typename ComponentMap, typename VertexIndexMap>
Chris@16 920 inline typename property_traits<ComponentMap>::value_type
Chris@16 921 fleischer_hendrickson_pinar_strong_components
Chris@16 922 (const Graph& g,
Chris@16 923 ComponentMap c,
Chris@16 924 VertexIndexMap vertex_index_map)
Chris@16 925 {
Chris@16 926 typedef typename graph_traits<Graph>::vertex_descriptor
Chris@16 927 vertex_descriptor;
Chris@16 928 typedef iterator_property_map<typename std::vector<vertex_descriptor>::iterator,
Chris@16 929 VertexIndexMap> VertexComponentMap;
Chris@16 930 typename boost::graph::parallel::process_group_type<Graph>::type pg
Chris@16 931 = process_group(g);
Chris@16 932
Chris@16 933 if (num_processes(pg) == 1) {
Chris@16 934 local_subgraph<const Graph> ls(g);
Chris@16 935 return boost::strong_components(ls, c);
Chris@16 936 }
Chris@16 937
Chris@16 938 // Create a VertexComponentMap for intermediate labeling of SCCs
Chris@16 939 std::vector<vertex_descriptor> r_s(num_vertices(g), graph_traits<Graph>::null_vertex());
Chris@16 940 VertexComponentMap r(r_s.begin(), vertex_index_map);
Chris@16 941
Chris@16 942 return fleischer_hendrickson_pinar_strong_components_impl
Chris@16 943 (g, c, r, vertex_index_map,
Chris@16 944 typename graph_traits<Graph>::traversal_category());
Chris@16 945 }
Chris@16 946
Chris@16 947 template<typename Graph, typename ComponentMap>
Chris@16 948 inline typename property_traits<ComponentMap>::value_type
Chris@16 949 fleischer_hendrickson_pinar_strong_components(const Graph& g,
Chris@16 950 ComponentMap c)
Chris@16 951 {
Chris@16 952 return fleischer_hendrickson_pinar_strong_components(g, c, get(vertex_index, g));
Chris@16 953 }
Chris@16 954
Chris@16 955 } // end namespace distributed
Chris@16 956
Chris@16 957 using distributed::fleischer_hendrickson_pinar_strong_components;
Chris@16 958
Chris@16 959 } // end namespace graph
Chris@16 960
Chris@16 961 template<class Graph, class ComponentMap, class P, class T, class R>
Chris@16 962 inline typename property_traits<ComponentMap>::value_type
Chris@16 963 strong_components
Chris@16 964 (const Graph& g, ComponentMap comp,
Chris@16 965 const bgl_named_params<P, T, R>&
Chris@16 966 BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph, distributed_graph_tag))
Chris@16 967 {
Chris@16 968 return graph::fleischer_hendrickson_pinar_strong_components(g, comp);
Chris@16 969 }
Chris@16 970
Chris@16 971 template<class Graph, class ComponentMap>
Chris@16 972 inline typename property_traits<ComponentMap>::value_type
Chris@16 973 strong_components
Chris@16 974 (const Graph& g, ComponentMap comp
Chris@16 975 BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph, distributed_graph_tag))
Chris@16 976 {
Chris@16 977 return graph::fleischer_hendrickson_pinar_strong_components(g, comp);
Chris@16 978 }
Chris@16 979
Chris@16 980 } /* end namespace boost */
Chris@16 981
Chris@16 982 #endif // BOOST_GRAPH_DISTRIBUTED_SCC_HPP