strong_components.hpp 40 KB

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