hohberg_biconnected_components.hpp 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128
  1. // Copyright 2005 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: Douglas Gregor
  6. // Andrew Lumsdaine
  7. // An implementation of Walter Hohberg's distributed biconnected
  8. // components algorithm, from:
  9. //
  10. // Walter Hohberg. How to Find Biconnected Components in Distributed
  11. // Networks. J. Parallel Distrib. Comput., 9(4):374-386, 1990.
  12. //
  13. #ifndef BOOST_GRAPH_DISTRIBUTED_HOHBERG_BICONNECTED_COMPONENTS_HPP
  14. #define BOOST_GRAPH_DISTRIBUTED_HOHBERG_BICONNECTED_COMPONENTS_HPP
  15. #ifndef BOOST_GRAPH_USE_MPI
  16. #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
  17. #endif
  18. /* You can define PBGL_HOHBERG_DEBUG to an integer value (1, 2, or 3)
  19. * to enable debugging information. 1 includes only the phases of the
  20. * algorithm and messages as their are received. 2 and 3 add
  21. * additional levels of detail about internal data structures related
  22. * to the algorithm itself.
  23. *
  24. * #define PBGL_HOHBERG_DEBUG 1
  25. */
  26. #include <boost/graph/graph_traits.hpp>
  27. #include <boost/graph/parallel/container_traits.hpp>
  28. #include <boost/graph/parallel/process_group.hpp>
  29. #include <boost/static_assert.hpp>
  30. #include <boost/mpi/operations.hpp>
  31. #include <boost/type_traits/is_convertible.hpp>
  32. #include <boost/graph/graph_concepts.hpp>
  33. #include <boost/graph/iteration_macros.hpp>
  34. #include <boost/optional.hpp>
  35. #include <utility> // for std::pair
  36. #include <boost/assert.hpp>
  37. #include <algorithm> // for std::find, std::mismatch
  38. #include <vector>
  39. #include <boost/graph/parallel/algorithm.hpp>
  40. #include <boost/graph/distributed/connected_components.hpp>
  41. #include <boost/concept/assert.hpp>
  42. namespace boost { namespace graph { namespace distributed {
  43. namespace hohberg_detail {
  44. enum message_kind {
  45. /* A header for the PATH message, stating which edge the message
  46. is coming on and how many vertices will be following. The data
  47. structure communicated will be a path_header. */
  48. msg_path_header,
  49. /* A message containing the vertices that make up a path. It will
  50. always follow a msg_path_header and will contain vertex
  51. descriptors, only. */
  52. msg_path_vertices,
  53. /* A header for the TREE message, stating the value of gamma and
  54. the number of vertices to come in the following
  55. msg_tree_vertices. */
  56. msg_tree_header,
  57. /* A message containing the vertices that make up the set of
  58. vertices in the same bicomponent as the sender. It will always
  59. follow a msg_tree_header and will contain vertex descriptors,
  60. only. */
  61. msg_tree_vertices,
  62. /* Provides a name for the biconnected component of the edge. */
  63. msg_name
  64. };
  65. // Payload for a msg_path_header message.
  66. template<typename EdgeDescriptor>
  67. struct path_header
  68. {
  69. // The edge over which the path is being communicated
  70. EdgeDescriptor edge;
  71. // The length of the path, i.e., the number of vertex descriptors
  72. // that will be coming in the next msg_path_vertices message.
  73. std::size_t path_length;
  74. template<typename Archiver>
  75. void serialize(Archiver& ar, const unsigned int /*version*/)
  76. {
  77. ar & edge & path_length;
  78. }
  79. };
  80. // Payload for a msg_tree_header message.
  81. template<typename Vertex, typename Edge>
  82. struct tree_header
  83. {
  84. // The edge over which the tree is being communicated
  85. Edge edge;
  86. // Gamma, which is the eta of the sender.
  87. Vertex gamma;
  88. // The length of the list of vertices in the bicomponent, i.e.,
  89. // the number of vertex descriptors that will be coming in the
  90. // next msg_tree_vertices message.
  91. std::size_t bicomp_length;
  92. template<typename Archiver>
  93. void serialize(Archiver& ar, const unsigned int /*version*/)
  94. {
  95. ar & edge & gamma & bicomp_length;
  96. }
  97. };
  98. // Payload for the msg_name message.
  99. template<typename EdgeDescriptor>
  100. struct name_header
  101. {
  102. // The edge being communicated and named.
  103. EdgeDescriptor edge;
  104. // The 0-based name of the component
  105. std::size_t name;
  106. template<typename Archiver>
  107. void serialize(Archiver& ar, const unsigned int /*version*/)
  108. {
  109. ar & edge & name;
  110. }
  111. };
  112. /* Computes the branch point between two paths. The branch point is
  113. the last position at which both paths are equivalent, beyond
  114. which the paths diverge. Both paths must have length > 0 and the
  115. initial elements of the paths must be equal. This is guaranteed
  116. in Hohberg's algorithm because all paths start at the
  117. leader. Returns the value at the branch point. */
  118. template<typename T>
  119. T branch_point(const std::vector<T>& p1, const std::vector<T>& p2)
  120. {
  121. BOOST_ASSERT(!p1.empty());
  122. BOOST_ASSERT(!p2.empty());
  123. BOOST_ASSERT(p1.front() == p2.front());
  124. typedef typename std::vector<T>::const_iterator iterator;
  125. iterator mismatch_pos;
  126. if (p1.size() <= p2.size())
  127. mismatch_pos = std::mismatch(p1.begin(), p1.end(), p2.begin()).first;
  128. else
  129. mismatch_pos = std::mismatch(p2.begin(), p2.end(), p1.begin()).first;
  130. --mismatch_pos;
  131. return *mismatch_pos;
  132. }
  133. /* Computes the infimum of vertices a and b in the given path. The
  134. infimum is the largest element that is on the paths from a to the
  135. root and from b to the root. */
  136. template<typename T>
  137. T infimum(const std::vector<T>& parent_path, T a, T b)
  138. {
  139. using std::swap;
  140. typedef typename std::vector<T>::const_iterator iterator;
  141. iterator first = parent_path.begin(), last = parent_path.end();
  142. #if defined(PBGL_HOHBERG_DEBUG) && PBGL_HOHBERG_DEBUG > 2
  143. std::cerr << "infimum(";
  144. for (iterator i = first; i != last; ++i) {
  145. if (i != first) std::cerr << ' ';
  146. std::cerr << local(*i) << '@' << owner(*i);
  147. }
  148. std::cerr << ", " << local(a) << '@' << owner(a) << ", "
  149. << local(b) << '@' << owner(b) << ") = ";
  150. #endif
  151. if (a == b) {
  152. #if defined(PBGL_HOHBERG_DEBUG) && PBGL_HOHBERG_DEBUG > 2
  153. std::cerr << local(a) << '@' << owner(a) << std::endl;
  154. #endif
  155. return a;
  156. }
  157. // Try to find a or b, whichever is closest to the end
  158. --last;
  159. while (*last != a) {
  160. // If we match b, swap the two so we'll be looking for b later.
  161. if (*last == b) { swap(a,b); break; }
  162. if (last == first) {
  163. #if defined(PBGL_HOHBERG_DEBUG) && PBGL_HOHBERG_DEBUG > 2
  164. std::cerr << local(*first) << '@' << owner(*first) << std::endl;
  165. #endif
  166. return *first;
  167. }
  168. else --last;
  169. }
  170. // Try to find b (which may originally have been a)
  171. while (*last != b) {
  172. if (last == first) {
  173. #if defined(PBGL_HOHBERG_DEBUG) && PBGL_HOHBERG_DEBUG > 2
  174. std::cerr << local(*first) << '@' << owner(*first) << std::endl;
  175. #endif
  176. return *first;
  177. }
  178. else --last;
  179. }
  180. #if defined(PBGL_HOHBERG_DEBUG) && PBGL_HOHBERG_DEBUG > 2
  181. std::cerr << local(*last) << '@' << owner(*last) << std::endl;
  182. #endif
  183. // We've found b; it's the infimum.
  184. return *last;
  185. }
  186. } // end namespace hohberg_detail
  187. /* A message that will be stored for each edge by Hohberg's algorithm. */
  188. template<typename Graph>
  189. struct hohberg_message
  190. {
  191. typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
  192. typedef typename graph_traits<Graph>::edge_descriptor Edge;
  193. // Assign from a path message
  194. void assign(const std::vector<Vertex>& path)
  195. {
  196. gamma = graph_traits<Graph>::null_vertex();
  197. path_or_bicomp = path;
  198. }
  199. // Assign from a tree message
  200. void assign(Vertex gamma, const std::vector<Vertex>& in_same_bicomponent)
  201. {
  202. this->gamma = gamma;
  203. path_or_bicomp = in_same_bicomponent;
  204. }
  205. bool is_path() const { return gamma == graph_traits<Graph>::null_vertex(); }
  206. bool is_tree() const { return gamma != graph_traits<Graph>::null_vertex(); }
  207. /// The "gamma" of a tree message, or null_vertex() for a path message
  208. Vertex gamma;
  209. // Either the path for a path message or the in_same_bicomponent
  210. std::vector<Vertex> path_or_bicomp;
  211. };
  212. /* An abstraction of a vertex processor in Hohberg's algorithm. The
  213. hohberg_vertex_processor class is responsible for processing
  214. messages transmitted to it via its edges. */
  215. template<typename Graph>
  216. class hohberg_vertex_processor
  217. {
  218. typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
  219. typedef typename graph_traits<Graph>::edge_descriptor Edge;
  220. typedef typename graph_traits<Graph>::degree_size_type degree_size_type;
  221. typedef typename graph_traits<Graph>::edges_size_type edges_size_type;
  222. typedef typename boost::graph::parallel::process_group_type<Graph>::type
  223. ProcessGroup;
  224. typedef std::vector<Vertex> path_t;
  225. typedef typename path_t::iterator path_iterator;
  226. public:
  227. hohberg_vertex_processor()
  228. : phase(1),
  229. parent(graph_traits<Graph>::null_vertex()),
  230. eta(graph_traits<Graph>::null_vertex())
  231. {
  232. }
  233. // Called to initialize a leader in the algorithm, which involves
  234. // sending out the initial path messages and being ready to receive
  235. // them.
  236. void initialize_leader(Vertex alpha, const Graph& g);
  237. /// Handle a path message on edge e. The path will be destroyed by
  238. /// this operation.
  239. void
  240. operator()(Edge e, path_t& path, const Graph& g);
  241. /// Handle a tree message on edge e. in_same_bicomponent will be
  242. /// destroyed by this operation.
  243. void
  244. operator()(Edge e, Vertex gamma, path_t& in_same_bicomponent,
  245. const Graph& g);
  246. // Handle a name message.
  247. void operator()(Edge e, edges_size_type name, const Graph& g);
  248. // Retrieve the phase
  249. unsigned char get_phase() const { return phase; }
  250. // Start the naming phase. The current phase must be 3 (echo), and
  251. // the offset contains the offset at which this processor should
  252. // begin when labelling its bicomponents. The offset is just a
  253. // parallel prefix sum of the number of bicomponents in each
  254. // processor that precedes it (globally).
  255. void
  256. start_naming_phase(Vertex alpha, const Graph& g, edges_size_type offset);
  257. /* Determine the number of bicomponents that we will be naming
  258. * ourselves.
  259. */
  260. edges_size_type num_starting_bicomponents(Vertex alpha, const Graph& g);
  261. // Fill in the edge component map with biconnected component
  262. // numbers.
  263. template<typename ComponentMap>
  264. void fill_edge_map(Vertex alpha, const Graph& g, ComponentMap& component);
  265. protected:
  266. /* Start the echo phase (phase 3) where we propagate information up
  267. the tree. */
  268. void echo_phase(Vertex alpha, const Graph& g);
  269. /* Retrieve the index of edge in the out-edges list of target(e, g). */
  270. std::size_t get_edge_index(Edge e, const Graph& g);
  271. /* Retrieve the index of the edge incidence on v in the out-edges
  272. list of vertex u. */
  273. std::size_t get_incident_edge_index(Vertex u, Vertex v, const Graph& g);
  274. /* Keeps track of which phase of the algorithm we are in. There are
  275. * four phases plus the "finished" phase:
  276. *
  277. * 1) Building the spanning tree
  278. * 2) Discovering cycles
  279. * 3) Echoing back up the spanning tree
  280. * 4) Labelling biconnected components
  281. * 5) Finished
  282. */
  283. unsigned char phase;
  284. /* The parent of this vertex in the spanning tree. This value will
  285. be graph_traits<Graph>::null_vertex() for the leader. */
  286. Vertex parent;
  287. /* The farthest ancestor up the tree that resides in the same
  288. biconnected component as we do. This information is approximate:
  289. we might not know about the actual farthest ancestor, but this is
  290. the farthest one we've seen so far. */
  291. Vertex eta;
  292. /* The number of edges that have not yet transmitted any messages to
  293. us. This starts at the degree of the vertex and decreases as we
  294. receive messages. When this counter hits zero, we're done with
  295. the second phase of the algorithm. In Hohberg's paper, the actual
  296. remaining edge set E is stored with termination when all edges
  297. have been removed from E, but we only need to detect termination
  298. so the set E need not be explicitly represented. */
  299. degree_size_type num_edges_not_transmitted;
  300. /* The path from the root of the spanning tree to this vertex. This
  301. vector will always store only the parts of the path leading up to
  302. this vertex, and not the vertex itself. Thus, it will be empty
  303. for the leader. */
  304. std::vector<Vertex> path_from_root;
  305. /* Structure containing all of the extra data we need to keep around
  306. PER EDGE. This information can not be contained within a property
  307. map, because it can't be shared among vertices without breaking
  308. the algorithm. Decreasing the size of this structure will drastically */
  309. struct per_edge_data
  310. {
  311. hohberg_message<Graph> msg;
  312. std::vector<Vertex> M;
  313. bool is_tree_edge;
  314. degree_size_type partition;
  315. };
  316. /* Data for each edge in the graph. This structure will be indexed
  317. by the position of the edge in the out_edges() list. */
  318. std::vector<per_edge_data> edge_data;
  319. /* The mapping from local partition numbers (0..n-1) to global
  320. partition numbers. */
  321. std::vector<edges_size_type> local_to_global_partitions;
  322. friend class boost::serialization::access;
  323. // We cannot actually serialize a vertex processor, nor would we
  324. // want to. However, the fact that we're putting instances into a
  325. // distributed_property_map means that we need to have a serialize()
  326. // function available.
  327. template<typename Archiver>
  328. void serialize(Archiver&, const unsigned int /*version*/)
  329. {
  330. BOOST_ASSERT(false);
  331. }
  332. };
  333. template<typename Graph>
  334. void
  335. hohberg_vertex_processor<Graph>::initialize_leader(Vertex alpha,
  336. const Graph& g)
  337. {
  338. using namespace hohberg_detail;
  339. ProcessGroup pg = process_group(g);
  340. typename property_map<Graph, vertex_owner_t>::const_type
  341. owner = get(vertex_owner, g);
  342. path_header<Edge> header;
  343. header.path_length = 1;
  344. BGL_FORALL_OUTEDGES_T(alpha, e, g, Graph) {
  345. header.edge = e;
  346. send(pg, get(owner, target(e, g)), msg_path_header, header);
  347. send(pg, get(owner, target(e, g)), msg_path_vertices, alpha);
  348. }
  349. num_edges_not_transmitted = degree(alpha, g);
  350. edge_data.resize(num_edges_not_transmitted);
  351. phase = 2;
  352. }
  353. template<typename Graph>
  354. void
  355. hohberg_vertex_processor<Graph>::operator()(Edge e, path_t& path,
  356. const Graph& g)
  357. {
  358. using namespace hohberg_detail;
  359. typename property_map<Graph, vertex_owner_t>::const_type
  360. owner = get(vertex_owner, g);
  361. #ifdef PBGL_HOHBERG_DEBUG
  362. // std::cerr << local(source(e, g)) << '@' << owner(source(e, g)) << " -> "
  363. // << local(target(e, g)) << '@' << owner(target(e, g)) << ": path(";
  364. // for (std::size_t i = 0; i < path.size(); ++i) {
  365. // if (i > 0) std::cerr << ' ';
  366. // std::cerr << local(path[i]) << '@' << owner(path[i]);
  367. // }
  368. std::cerr << "), phase = " << (int)phase << std::endl;
  369. #endif
  370. // Get access to edge-specific data
  371. if (edge_data.empty())
  372. edge_data.resize(degree(target(e, g), g));
  373. per_edge_data& edata = edge_data[get_edge_index(e, g)];
  374. // Record the message. We'll need it in phase 3.
  375. edata.msg.assign(path);
  376. // Note: "alpha" refers to the vertex "processor" receiving the
  377. // message.
  378. Vertex alpha = target(e, g);
  379. switch (phase) {
  380. case 1:
  381. {
  382. num_edges_not_transmitted = degree(alpha, g) - 1;
  383. edata.is_tree_edge = true;
  384. parent = path.back();
  385. eta = parent;
  386. edata.M.clear(); edata.M.push_back(parent);
  387. // Broadcast the path from the root to our potential children in
  388. // the spanning tree.
  389. path.push_back(alpha);
  390. path_header<Edge> header;
  391. header.path_length = path.size();
  392. ProcessGroup pg = process_group(g);
  393. BGL_FORALL_OUTEDGES_T(alpha, oe, g, Graph) {
  394. // Skip the tree edge we just received
  395. if (target(oe, g) != source(e, g)) {
  396. header.edge = oe;
  397. send(pg, get(owner, target(oe, g)), msg_path_header, header);
  398. send(pg, get(owner, target(oe, g)), msg_path_vertices, &path[0],
  399. header.path_length);
  400. }
  401. }
  402. path.pop_back();
  403. // Swap the old path in, to save some extra copying. Nobody
  404. path_from_root.swap(path);
  405. // Once we have received our place in the spanning tree, move on
  406. // to phase 2.
  407. phase = 2;
  408. // If we only had only edge, skip to phase 3.
  409. if (num_edges_not_transmitted == 0)
  410. echo_phase(alpha, g);
  411. return;
  412. }
  413. case 2:
  414. {
  415. --num_edges_not_transmitted;
  416. edata.is_tree_edge = false;
  417. // Determine if alpha (our vertex) is in the path
  418. path_iterator pos = std::find(path.begin(), path.end(), alpha);
  419. if (pos != path.end()) {
  420. // Case A: There is a cycle alpha beta ... gamma alpha
  421. // M(e) <- {beta, gammar}
  422. edata.M.clear();
  423. ++pos;
  424. // If pos == path.end(), we have a self-loop
  425. if (pos != path.end()) {
  426. // Add beta
  427. edata.M.push_back(*pos);
  428. ++pos;
  429. }
  430. // If pos == path.end(), we have a self-loop or beta == gamma
  431. // (parallel edge). Otherwise, add gamma.
  432. if (pos != path.end()) edata.M.push_back(path.back());
  433. } else {
  434. // Case B: There is a cycle but we haven't seen alpha yet.
  435. // M(e) = {parent, path.back()}
  436. edata.M.clear();
  437. edata.M.push_back(path.back());
  438. if (parent != path.back()) edata.M.push_back(parent);
  439. // eta = inf(eta, bra(pi_t, pi))
  440. eta = infimum(path_from_root, eta, branch_point(path_from_root, path));
  441. }
  442. if (num_edges_not_transmitted == 0)
  443. echo_phase(alpha, g);
  444. break;
  445. }
  446. default:
  447. // std::cerr << "Phase is " << int(phase) << "\n";
  448. BOOST_ASSERT(false);
  449. }
  450. }
  451. template<typename Graph>
  452. void
  453. hohberg_vertex_processor<Graph>::operator()(Edge e, Vertex gamma,
  454. path_t& in_same_bicomponent,
  455. const Graph& g)
  456. {
  457. using namespace hohberg_detail;
  458. #ifdef PBGL_HOHBERG_DEBUG
  459. std::cerr << local(source(e, g)) << '@' << owner(source(e, g)) << " -> "
  460. << local(target(e, g)) << '@' << owner(target(e, g)) << ": tree("
  461. << local(gamma) << '@' << owner(gamma) << ", ";
  462. for (std::size_t i = 0; i < in_same_bicomponent.size(); ++i) {
  463. if (i > 0) std::cerr << ' ';
  464. std::cerr << local(in_same_bicomponent[i]) << '@'
  465. << owner(in_same_bicomponent[i]);
  466. }
  467. std::cerr << ", " << local(source(e, g)) << '@' << owner(source(e, g))
  468. << "), phase = " << (int)phase << std::endl;
  469. #endif
  470. // Get access to edge-specific data
  471. per_edge_data& edata = edge_data[get_edge_index(e, g)];
  472. // Record the message. We'll need it in phase 3.
  473. edata.msg.assign(gamma, in_same_bicomponent);
  474. // Note: "alpha" refers to the vertex "processor" receiving the
  475. // message.
  476. Vertex alpha = target(e, g);
  477. Vertex beta = source(e, g);
  478. switch (phase) {
  479. case 2:
  480. --num_edges_not_transmitted;
  481. edata.is_tree_edge = true;
  482. if (gamma == alpha) {
  483. // Case C
  484. edata.M.swap(in_same_bicomponent);
  485. } else {
  486. // Case D
  487. edata.M.clear();
  488. edata.M.push_back(parent);
  489. if (beta != parent) edata.M.push_back(beta);
  490. eta = infimum(path_from_root, eta, gamma);
  491. }
  492. if (num_edges_not_transmitted == 0)
  493. echo_phase(alpha, g);
  494. break;
  495. default:
  496. BOOST_ASSERT(false);
  497. }
  498. }
  499. template<typename Graph>
  500. void
  501. hohberg_vertex_processor<Graph>::operator()(Edge e, edges_size_type name,
  502. const Graph& g)
  503. {
  504. using namespace hohberg_detail;
  505. #ifdef PBGL_HOHBERG_DEBUG
  506. std::cerr << local(source(e, g)) << '@' << owner(source(e, g)) << " -> "
  507. << local(target(e, g)) << '@' << owner(target(e, g)) << ": name("
  508. << name << "), phase = " << (int)phase << std::endl;
  509. #endif
  510. BOOST_ASSERT(phase == 4);
  511. typename property_map<Graph, vertex_owner_t>::const_type
  512. owner = get(vertex_owner, g);
  513. // Send name messages along the spanning tree edges that are in the
  514. // same bicomponent as the edge to our parent.
  515. ProcessGroup pg = process_group(g);
  516. Vertex alpha = target(e, g);
  517. std::size_t idx = 0;
  518. BGL_FORALL_OUTEDGES_T(alpha, e, g, Graph) {
  519. per_edge_data& edata = edge_data[idx++];
  520. if (edata.is_tree_edge
  521. && find(edata.M.begin(), edata.M.end(), parent) != edata.M.end()
  522. && target(e, g) != parent) {
  523. // Notify our children in the spanning tree of this name
  524. name_header<Edge> header;
  525. header.edge = e;
  526. header.name = name;
  527. send(pg, get(owner, target(e, g)), msg_name, header);
  528. } else if (target(e, g) == parent) {
  529. // Map from local partition numbers to global bicomponent numbers
  530. local_to_global_partitions[edata.partition] = name;
  531. }
  532. }
  533. // Final stage
  534. phase = 5;
  535. }
  536. template<typename Graph>
  537. typename hohberg_vertex_processor<Graph>::edges_size_type
  538. hohberg_vertex_processor<Graph>::
  539. num_starting_bicomponents(Vertex alpha, const Graph& g)
  540. {
  541. edges_size_type not_mapped = (std::numeric_limits<edges_size_type>::max)();
  542. edges_size_type result = 0;
  543. std::size_t idx = 0;
  544. BGL_FORALL_OUTEDGES_T(alpha, e, g, Graph) {
  545. per_edge_data& edata = edge_data[idx++];
  546. if (edata.is_tree_edge
  547. && find(edata.M.begin(), edata.M.end(), parent) == edata.M.end()) {
  548. // Map from local partition numbers to global bicomponent numbers
  549. if (local_to_global_partitions[edata.partition] == not_mapped)
  550. local_to_global_partitions[edata.partition] = result++;
  551. }
  552. }
  553. #ifdef PBGL_HOHBERG_DEBUG
  554. std::cerr << local(alpha) << '@' << owner(alpha) << " has " << result
  555. << " bicomponents originating at it." << std::endl;
  556. #endif
  557. return result;
  558. }
  559. template<typename Graph>
  560. template<typename ComponentMap>
  561. void
  562. hohberg_vertex_processor<Graph>::
  563. fill_edge_map(Vertex alpha, const Graph& g, ComponentMap& component)
  564. {
  565. std::size_t idx = 0;
  566. BGL_FORALL_OUTEDGES_T(alpha, e, g, Graph) {
  567. per_edge_data& edata = edge_data[idx++];
  568. local_put(component, e, local_to_global_partitions[edata.partition]);
  569. #if defined(PBGL_HOHBERG_DEBUG) && PBGL_HOHBERG_DEBUG > 2
  570. std::cerr << "component("
  571. << local(source(e, g)) << '@' << owner(source(e, g)) << " -> "
  572. << local(target(e, g)) << '@' << owner(target(e, g)) << ") = "
  573. << local_to_global_partitions[edata.partition]
  574. << " (partition = " << edata.partition << " of "
  575. << local_to_global_partitions.size() << ")" << std::endl;
  576. #endif
  577. }
  578. }
  579. template<typename Graph>
  580. void
  581. hohberg_vertex_processor<Graph>::
  582. start_naming_phase(Vertex alpha, const Graph& g, edges_size_type offset)
  583. {
  584. using namespace hohberg_detail;
  585. BOOST_ASSERT(phase == 4);
  586. typename property_map<Graph, vertex_owner_t>::const_type
  587. owner = get(vertex_owner, g);
  588. // Send name messages along the spanning tree edges of the
  589. // components that we get to number.
  590. ProcessGroup pg = process_group(g);
  591. bool has_more_children_to_name = false;
  592. // Map from local partition numbers to global bicomponent numbers
  593. edges_size_type not_mapped = (std::numeric_limits<edges_size_type>::max)();
  594. for (std::size_t i = 0; i < local_to_global_partitions.size(); ++i) {
  595. if (local_to_global_partitions[i] != not_mapped)
  596. local_to_global_partitions[i] += offset;
  597. }
  598. std::size_t idx = 0;
  599. BGL_FORALL_OUTEDGES_T(alpha, e, g, Graph) {
  600. per_edge_data& edata = edge_data[idx++];
  601. if (edata.is_tree_edge
  602. && find(edata.M.begin(), edata.M.end(), parent) == edata.M.end()) {
  603. // Notify our children in the spanning tree of this new name
  604. name_header<Edge> header;
  605. header.edge = e;
  606. header.name = local_to_global_partitions[edata.partition];
  607. send(pg, get(owner, target(e, g)), msg_name, header);
  608. } else if (edata.is_tree_edge) {
  609. has_more_children_to_name = true;
  610. }
  611. #if defined(PBGL_HOHBERG_DEBUG) && PBGL_HOHBERG_DEBUG > 2
  612. std::cerr << "M[" << local(source(e, g)) << '@' << owner(source(e, g))
  613. << " -> " << local(target(e, g)) << '@' << owner(target(e, g))
  614. << "] = ";
  615. for (std::size_t i = 0; i < edata.M.size(); ++i) {
  616. std::cerr << local(edata.M[i]) << '@' << owner(edata.M[i]) << ' ';
  617. }
  618. std::cerr << std::endl;
  619. #endif
  620. }
  621. // See if we're done.
  622. if (!has_more_children_to_name)
  623. // Final stage
  624. phase = 5;
  625. }
  626. template<typename Graph>
  627. void
  628. hohberg_vertex_processor<Graph>::echo_phase(Vertex alpha, const Graph& g)
  629. {
  630. using namespace hohberg_detail;
  631. typename property_map<Graph, vertex_owner_t>::const_type
  632. owner = get(vertex_owner, g);
  633. /* We're entering the echo phase. */
  634. phase = 3;
  635. if (parent != graph_traits<Graph>::null_vertex()) {
  636. Edge edge_to_parent;
  637. #if defined(PBGL_HOHBERG_DEBUG) && PBGL_HOHBERG_DEBUG > 1
  638. std::cerr << local(alpha) << '@' << owner(alpha) << " echo: parent = "
  639. << local(parent) << '@' << owner(parent) << ", eta = "
  640. << local(eta) << '@' << owner(eta) << ", Gamma = ";
  641. #endif
  642. std::vector<Vertex> bicomp;
  643. std::size_t e_index = 0;
  644. BGL_FORALL_OUTEDGES_T(alpha, e, g, Graph) {
  645. if (target(e, g) == parent && parent == eta) {
  646. edge_to_parent = e;
  647. if (find(bicomp.begin(), bicomp.end(), alpha) == bicomp.end()) {
  648. #if defined(PBGL_HOHBERG_DEBUG) && PBGL_HOHBERG_DEBUG > 1
  649. std::cerr << local(alpha) << '@' << owner(alpha) << ' ';
  650. #endif
  651. bicomp.push_back(alpha);
  652. }
  653. } else {
  654. if (target(e, g) == parent) edge_to_parent = e;
  655. per_edge_data& edata = edge_data[e_index];
  656. if (edata.msg.is_path()) {
  657. path_iterator pos = std::find(edata.msg.path_or_bicomp.begin(),
  658. edata.msg.path_or_bicomp.end(),
  659. eta);
  660. if (pos != edata.msg.path_or_bicomp.end()) {
  661. ++pos;
  662. if (pos != edata.msg.path_or_bicomp.end()
  663. && find(bicomp.begin(), bicomp.end(), *pos) == bicomp.end()) {
  664. #if defined(PBGL_HOHBERG_DEBUG) && PBGL_HOHBERG_DEBUG > 1
  665. std::cerr << local(*pos) << '@' << owner(*pos) << ' ';
  666. #endif
  667. bicomp.push_back(*pos);
  668. }
  669. }
  670. } else if (edata.msg.is_tree() && edata.msg.gamma == eta) {
  671. for (path_iterator i = edata.msg.path_or_bicomp.begin();
  672. i != edata.msg.path_or_bicomp.end(); ++i) {
  673. if (find(bicomp.begin(), bicomp.end(), *i) == bicomp.end()) {
  674. #if defined(PBGL_HOHBERG_DEBUG) && PBGL_HOHBERG_DEBUG > 1
  675. std::cerr << local(*i) << '@' << owner(*i) << ' ';
  676. #endif
  677. bicomp.push_back(*i);
  678. }
  679. }
  680. }
  681. }
  682. ++e_index;
  683. }
  684. #ifdef PBGL_HOHBERG_DEBUG
  685. std::cerr << std::endl;
  686. #endif
  687. // Send tree(eta, bicomp) to parent
  688. tree_header<Vertex, Edge> header;
  689. header.edge = edge_to_parent;
  690. header.gamma = eta;
  691. header.bicomp_length = bicomp.size();
  692. ProcessGroup pg = process_group(g);
  693. send(pg, get(owner, parent), msg_tree_header, header);
  694. send(pg, get(owner, parent), msg_tree_vertices, &bicomp[0],
  695. header.bicomp_length);
  696. }
  697. // Compute the partition of edges such that iff two edges e1 and e2
  698. // are in different subsets then M(e1) is disjoint from M(e2).
  699. // Start by putting each edge in a different partition
  700. std::vector<degree_size_type> parent_vec(edge_data.size());
  701. degree_size_type idx = 0;
  702. for (idx = 0; idx < edge_data.size(); ++idx)
  703. parent_vec[idx] = idx;
  704. // Go through each edge e, performing a union() on the edges
  705. // incident on all vertices in M[e].
  706. idx = 0;
  707. BGL_FORALL_OUTEDGES_T(alpha, e, g, Graph) {
  708. per_edge_data& edata = edge_data[idx++];
  709. // Compute union of vertices in M
  710. if (!edata.M.empty()) {
  711. degree_size_type e1 = get_incident_edge_index(alpha, edata.M.front(), g);
  712. while (parent_vec[e1] != e1) e1 = parent_vec[e1];
  713. for (std::size_t i = 1; i < edata.M.size(); ++i) {
  714. degree_size_type e2 = get_incident_edge_index(alpha, edata.M[i], g);
  715. while (parent_vec[e2] != e2) e2 = parent_vec[e2];
  716. parent_vec[e2] = e1;
  717. }
  718. }
  719. }
  720. edges_size_type not_mapped = (std::numeric_limits<edges_size_type>::max)();
  721. // Determine the number of partitions
  722. for (idx = 0; idx < parent_vec.size(); ++idx) {
  723. if (parent_vec[idx] == idx) {
  724. edge_data[idx].partition = local_to_global_partitions.size();
  725. local_to_global_partitions.push_back(not_mapped);
  726. }
  727. }
  728. // Assign partition numbers to each edge
  729. for (idx = 0; idx < parent_vec.size(); ++idx) {
  730. degree_size_type rep = parent_vec[idx];
  731. while (rep != parent_vec[rep]) rep = parent_vec[rep];
  732. edge_data[idx].partition = edge_data[rep].partition;
  733. }
  734. // Enter the naming phase (but don't send anything yet).
  735. phase = 4;
  736. }
  737. template<typename Graph>
  738. std::size_t
  739. hohberg_vertex_processor<Graph>::get_edge_index(Edge e, const Graph& g)
  740. {
  741. std::size_t result = 0;
  742. BGL_FORALL_OUTEDGES_T(target(e, g), oe, g, Graph) {
  743. if (source(e, g) == target(oe, g)) return result;
  744. ++result;
  745. }
  746. BOOST_ASSERT(false);
  747. }
  748. template<typename Graph>
  749. std::size_t
  750. hohberg_vertex_processor<Graph>::get_incident_edge_index(Vertex u, Vertex v,
  751. const Graph& g)
  752. {
  753. std::size_t result = 0;
  754. BGL_FORALL_OUTEDGES_T(u, e, g, Graph) {
  755. if (target(e, g) == v) return result;
  756. ++result;
  757. }
  758. BOOST_ASSERT(false);
  759. }
  760. template<typename Graph, typename InputIterator, typename ComponentMap,
  761. typename VertexProcessorMap>
  762. typename graph_traits<Graph>::edges_size_type
  763. hohberg_biconnected_components
  764. (const Graph& g,
  765. ComponentMap component,
  766. InputIterator first, InputIterator last,
  767. VertexProcessorMap vertex_processor)
  768. {
  769. using namespace boost::graph::parallel;
  770. using namespace hohberg_detail;
  771. using boost::parallel::all_reduce;
  772. typename property_map<Graph, vertex_owner_t>::const_type
  773. owner = get(vertex_owner, g);
  774. // The graph must be undirected
  775. BOOST_STATIC_ASSERT(
  776. (is_convertible<typename graph_traits<Graph>::directed_category,
  777. undirected_tag>::value));
  778. // The graph must model Incidence Graph
  779. BOOST_CONCEPT_ASSERT(( IncidenceGraphConcept<Graph> ));
  780. typedef typename graph_traits<Graph>::edges_size_type edges_size_type;
  781. typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
  782. typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
  783. // Retrieve the process group we will use for communication
  784. typedef typename process_group_type<Graph>::type process_group_type;
  785. process_group_type pg = process_group(g);
  786. // Keeps track of the edges that we know to be tree edges.
  787. std::vector<edge_descriptor> tree_edges;
  788. // The leaders send out a path message to initiate the algorithm
  789. while (first != last) {
  790. vertex_descriptor leader = *first;
  791. if (process_id(pg) == get(owner, leader))
  792. vertex_processor[leader].initialize_leader(leader, g);
  793. ++first;
  794. }
  795. synchronize(pg);
  796. // Will hold the number of bicomponents in the graph.
  797. edges_size_type num_bicomponents = 0;
  798. // Keep track of the path length that we should expect, based on the
  799. // level in the breadth-first search tree. At present, this is only
  800. // used as a sanity check. TBD: This could be used to decrease the
  801. // amount of communication required per-edge (by about 4 bytes).
  802. std::size_t path_length = 1;
  803. typedef std::vector<vertex_descriptor> path_t;
  804. unsigned char minimum_phase = 5;
  805. do {
  806. while (optional<std::pair<int, int> > msg = probe(pg)) {
  807. switch (msg->second) {
  808. case msg_path_header:
  809. {
  810. // Receive the path header
  811. path_header<edge_descriptor> header;
  812. receive(pg, msg->first, msg->second, header);
  813. BOOST_ASSERT(path_length == header.path_length);
  814. // Receive the path itself
  815. path_t path(path_length);
  816. receive(pg, msg->first, msg_path_vertices, &path[0], path_length);
  817. edge_descriptor e = header.edge;
  818. vertex_processor[target(e, g)](e, path, g);
  819. }
  820. break;
  821. case msg_path_vertices:
  822. // Should be handled in msg_path_header case, unless we're going
  823. // stateless.
  824. BOOST_ASSERT(false);
  825. break;
  826. case msg_tree_header:
  827. {
  828. // Receive the tree header
  829. tree_header<vertex_descriptor, edge_descriptor> header;
  830. receive(pg, msg->first, msg->second, header);
  831. // Receive the tree itself
  832. path_t in_same_bicomponent(header.bicomp_length);
  833. receive(pg, msg->first, msg_tree_vertices, &in_same_bicomponent[0],
  834. header.bicomp_length);
  835. edge_descriptor e = header.edge;
  836. vertex_processor[target(e, g)](e, header.gamma, in_same_bicomponent,
  837. g);
  838. }
  839. break;
  840. case msg_tree_vertices:
  841. // Should be handled in msg_tree_header case, unless we're
  842. // going stateless.
  843. BOOST_ASSERT(false);
  844. break;
  845. case msg_name:
  846. {
  847. name_header<edge_descriptor> header;
  848. receive(pg, msg->first, msg->second, header);
  849. edge_descriptor e = header.edge;
  850. vertex_processor[target(e, g)](e, header.name, g);
  851. }
  852. break;
  853. default:
  854. BOOST_ASSERT(false);
  855. }
  856. }
  857. ++path_length;
  858. // Compute minimum phase locally
  859. minimum_phase = 5;
  860. unsigned char maximum_phase = 1;
  861. BGL_FORALL_VERTICES_T(v, g, Graph) {
  862. minimum_phase = (std::min)(minimum_phase, vertex_processor[v].get_phase());
  863. maximum_phase = (std::max)(maximum_phase, vertex_processor[v].get_phase());
  864. }
  865. #ifdef PBGL_HOHBERG_DEBUG
  866. if (process_id(pg) == 0)
  867. std::cerr << "<---------End of stage------------->" << std::endl;
  868. #endif
  869. // Compute minimum phase globally
  870. minimum_phase = all_reduce(pg, minimum_phase, boost::mpi::minimum<char>());
  871. #ifdef PBGL_HOHBERG_DEBUG
  872. if (process_id(pg) == 0)
  873. std::cerr << "Minimum phase = " << (int)minimum_phase << std::endl;
  874. #endif
  875. if (minimum_phase == 4
  876. && all_reduce(pg, maximum_phase, boost::mpi::maximum<char>()) == 4) {
  877. #ifdef PBGL_HOHBERG_DEBUG
  878. if (process_id(pg) == 0)
  879. std::cerr << "<---------Naming phase------------->" << std::endl;
  880. #endif
  881. // Compute the biconnected component number offsets for each
  882. // vertex.
  883. std::vector<edges_size_type> local_offsets;
  884. local_offsets.reserve(num_vertices(g));
  885. edges_size_type num_local_bicomponents = 0;
  886. BGL_FORALL_VERTICES_T(v, g, Graph) {
  887. local_offsets.push_back(num_local_bicomponents);
  888. num_local_bicomponents +=
  889. vertex_processor[v].num_starting_bicomponents(v, g);
  890. }
  891. synchronize(pg);
  892. // Find our the number of bicomponent names that will originate
  893. // from each process. This tells us how many bicomponents are in
  894. // the entire graph and what our global offset is for computing
  895. // our own biconnected component names.
  896. std::vector<edges_size_type> all_bicomponents(num_processes(pg));
  897. all_gather(pg, &num_local_bicomponents, &num_local_bicomponents + 1,
  898. all_bicomponents);
  899. num_bicomponents = 0;
  900. edges_size_type my_global_offset = 0;
  901. for (std::size_t i = 0; i < all_bicomponents.size(); ++i) {
  902. if (i == (std::size_t)process_id(pg))
  903. my_global_offset = num_bicomponents;
  904. num_bicomponents += all_bicomponents[i];
  905. }
  906. std::size_t index = 0;
  907. BGL_FORALL_VERTICES_T(v, g, Graph) {
  908. edges_size_type offset = my_global_offset + local_offsets[index++];
  909. vertex_processor[v].start_naming_phase(v, g, offset);
  910. }
  911. }
  912. synchronize(pg);
  913. } while (minimum_phase < 5);
  914. // Number the edges appropriately.
  915. BGL_FORALL_VERTICES_T(v, g, Graph)
  916. vertex_processor[v].fill_edge_map(v, g, component);
  917. return num_bicomponents;
  918. }
  919. template<typename Graph, typename ComponentMap, typename InputIterator>
  920. typename graph_traits<Graph>::edges_size_type
  921. hohberg_biconnected_components
  922. (const Graph& g, ComponentMap component,
  923. InputIterator first, InputIterator last)
  924. {
  925. std::vector<hohberg_vertex_processor<Graph> >
  926. vertex_processors(num_vertices(g));
  927. return hohberg_biconnected_components
  928. (g, component, first, last,
  929. make_iterator_property_map(vertex_processors.begin(),
  930. get(vertex_index, g)));
  931. }
  932. template<typename Graph, typename ComponentMap, typename ParentMap>
  933. typename graph_traits<Graph>::edges_size_type
  934. hohberg_biconnected_components(const Graph& g, ComponentMap component,
  935. ParentMap parent)
  936. {
  937. // We need the connected components of the graph, but we don't care
  938. // about component numbers.
  939. connected_components(g, dummy_property_map(), parent);
  940. // Each root in the parent map is a leader
  941. typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
  942. std::vector<vertex_descriptor> leaders;
  943. BGL_FORALL_VERTICES_T(v, g, Graph)
  944. if (get(parent, v) == v) leaders.push_back(v);
  945. return hohberg_biconnected_components(g, component,
  946. leaders.begin(), leaders.end());
  947. }
  948. template<typename Graph, typename ComponentMap>
  949. typename graph_traits<Graph>::edges_size_type
  950. hohberg_biconnected_components(const Graph& g, ComponentMap component)
  951. {
  952. typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
  953. std::vector<vertex_descriptor> parents(num_vertices(g));
  954. return hohberg_biconnected_components
  955. (g, component, make_iterator_property_map(parents.begin(),
  956. get(vertex_index, g)));
  957. }
  958. } } } // end namespace boost::graph::distributed
  959. #endif // BOOST_GRAPH_DISTRIBUTED_HOHBERG_BICONNECTED_COMPONENTS_HPP