annotate DEPENDENCIES/generic/include/boost/graph/distributed/hohberg_biconnected_components.hpp @ 125:34e428693f5d vext

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