strong_components.hpp 39 KB

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