Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:37:18

0001 // Copyright 2005 The Trustees of Indiana University.
0002 
0003 // Use, modification and distribution is subject to the Boost Software
0004 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
0005 // http://www.boost.org/LICENSE_1_0.txt)
0006 
0007 //  Authors: Douglas Gregor
0008 //           Andrew Lumsdaine
0009 
0010 // An implementation of Walter Hohberg's distributed biconnected
0011 // components algorithm, from:
0012 //
0013 //   Walter Hohberg. How to Find Biconnected Components in Distributed
0014 //   Networks. J. Parallel Distrib. Comput., 9(4):374-386, 1990.
0015 //
0016 #ifndef BOOST_GRAPH_DISTRIBUTED_HOHBERG_BICONNECTED_COMPONENTS_HPP
0017 #define BOOST_GRAPH_DISTRIBUTED_HOHBERG_BICONNECTED_COMPONENTS_HPP
0018 
0019 #ifndef BOOST_GRAPH_USE_MPI
0020 #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
0021 #endif
0022 
0023 /* You can define PBGL_HOHBERG_DEBUG to an integer value (1, 2, or 3)
0024  * to enable debugging information. 1 includes only the phases of the
0025  * algorithm and messages as their are received. 2 and 3 add
0026  * additional levels of detail about internal data structures related
0027  * to the algorithm itself.
0028  *
0029  * #define PBGL_HOHBERG_DEBUG 1
0030 */
0031 
0032 #include <boost/graph/graph_traits.hpp>
0033 #include <boost/graph/parallel/container_traits.hpp>
0034 #include <boost/graph/parallel/process_group.hpp>
0035 #include <boost/static_assert.hpp>
0036 #include <boost/mpi/operations.hpp>
0037 #include <boost/type_traits/is_convertible.hpp>
0038 #include <boost/graph/graph_concepts.hpp>
0039 #include <boost/graph/iteration_macros.hpp>
0040 #include <boost/optional.hpp>
0041 #include <utility> // for std::pair
0042 #include <boost/assert.hpp>
0043 #include <algorithm> // for std::find, std::mismatch
0044 #include <vector>
0045 #include <boost/graph/parallel/algorithm.hpp>
0046 #include <boost/graph/distributed/connected_components.hpp>
0047 #include <boost/concept/assert.hpp>
0048 
0049 namespace boost { namespace graph { namespace distributed {
0050 
0051 namespace hohberg_detail {
0052   enum message_kind {
0053     /* A header for the PATH message, stating which edge the message
0054        is coming on and how many vertices will be following. The data
0055        structure communicated will be a path_header. */
0056     msg_path_header,
0057     /* A message containing the vertices that make up a path. It will
0058        always follow a msg_path_header and will contain vertex
0059        descriptors, only. */
0060     msg_path_vertices,
0061     /* A header for the TREE message, stating the value of gamma and
0062        the number of vertices to come in the following
0063        msg_tree_vertices. */
0064     msg_tree_header,
0065     /* A message containing the vertices that make up the set of
0066        vertices in the same bicomponent as the sender. It will always
0067        follow a msg_tree_header and will contain vertex descriptors,
0068        only. */
0069     msg_tree_vertices,
0070     /* Provides a name for the biconnected component of the edge. */
0071     msg_name
0072   };
0073 
0074   // Payload for a msg_path_header message.
0075   template<typename EdgeDescriptor>
0076   struct path_header
0077   {
0078     // The edge over which the path is being communicated
0079     EdgeDescriptor edge;
0080 
0081     // The length of the path, i.e., the number of vertex descriptors
0082     // that will be coming in the next msg_path_vertices message.
0083     std::size_t    path_length;
0084 
0085     template<typename Archiver>
0086     void serialize(Archiver& ar, const unsigned int /*version*/)
0087     {
0088       ar & edge & path_length;
0089     }
0090   };
0091 
0092   // Payload for a msg_tree_header message.
0093   template<typename Vertex, typename Edge>
0094   struct tree_header
0095   {
0096     // The edge over which the tree is being communicated
0097     Edge edge;
0098 
0099     // Gamma, which is the eta of the sender.
0100     Vertex gamma;
0101 
0102     // The length of the list of vertices in the bicomponent, i.e.,
0103     // the number of vertex descriptors that will be coming in the
0104     // next msg_tree_vertices message.
0105     std::size_t    bicomp_length;
0106 
0107     template<typename Archiver>
0108     void serialize(Archiver& ar, const unsigned int /*version*/)
0109     {
0110       ar & edge & gamma & bicomp_length;
0111     }
0112   };
0113 
0114   // Payload for the msg_name message.
0115   template<typename EdgeDescriptor>
0116   struct name_header
0117   {
0118     // The edge being communicated and named.
0119     EdgeDescriptor edge;
0120 
0121     // The 0-based name of the component
0122     std::size_t name;
0123 
0124     template<typename Archiver>
0125     void serialize(Archiver& ar, const unsigned int /*version*/)
0126     {
0127       ar & edge & name;
0128     }
0129   };
0130 
0131   /* Computes the branch point between two paths. The branch point is
0132      the last position at which both paths are equivalent, beyond
0133      which the paths diverge. Both paths must have length > 0 and the
0134      initial elements of the paths must be equal. This is guaranteed
0135      in Hohberg's algorithm because all paths start at the
0136      leader. Returns the value at the branch point. */
0137   template<typename T>
0138   T branch_point(const std::vector<T>& p1, const std::vector<T>& p2)
0139   {
0140     BOOST_ASSERT(!p1.empty());
0141     BOOST_ASSERT(!p2.empty());
0142     BOOST_ASSERT(p1.front() == p2.front());
0143 
0144     typedef typename std::vector<T>::const_iterator iterator;
0145 
0146     iterator mismatch_pos;
0147     if (p1.size() <= p2.size())
0148       mismatch_pos = std::mismatch(p1.begin(), p1.end(), p2.begin()).first;
0149     else
0150       mismatch_pos = std::mismatch(p2.begin(), p2.end(), p1.begin()).first;
0151     --mismatch_pos;
0152     return *mismatch_pos;
0153   }
0154 
0155   /* Computes the infimum of vertices a and b in the given path. The
0156      infimum is the largest element that is on the paths from a to the
0157      root and from b to the root. */
0158   template<typename T>
0159   T infimum(const std::vector<T>& parent_path, T a, T b)
0160   {
0161     using std::swap;
0162 
0163     typedef typename std::vector<T>::const_iterator iterator;
0164     iterator first = parent_path.begin(), last = parent_path.end();
0165 
0166 #if defined(PBGL_HOHBERG_DEBUG) && PBGL_HOHBERG_DEBUG > 2
0167     std::cerr << "infimum(";
0168     for (iterator i = first; i != last; ++i) {
0169       if (i != first) std::cerr << ' ';
0170       std::cerr << local(*i) << '@' << owner(*i);
0171     }
0172     std::cerr << ", " << local(a) << '@' << owner(a) << ", "
0173               << local(b) << '@' << owner(b) << ") = ";
0174 #endif
0175 
0176     if (a == b) {
0177 #if defined(PBGL_HOHBERG_DEBUG) && PBGL_HOHBERG_DEBUG > 2
0178       std::cerr << local(a) << '@' << owner(a) << std::endl;
0179 #endif
0180       return a;
0181     }
0182 
0183     // Try to find a or b, whichever is closest to the end
0184     --last;
0185     while (*last != a) {
0186       // If we match b, swap the two so we'll be looking for b later.
0187       if (*last == b) { swap(a,b); break; }
0188 
0189       if (last == first) {
0190 #if defined(PBGL_HOHBERG_DEBUG) && PBGL_HOHBERG_DEBUG > 2
0191         std::cerr << local(*first) << '@' << owner(*first) << std::endl;
0192 #endif
0193         return *first;
0194       }
0195       else --last;
0196     }
0197 
0198     // Try to find b (which may originally have been a)
0199     while (*last != b) {
0200       if (last == first) {
0201 #if defined(PBGL_HOHBERG_DEBUG) && PBGL_HOHBERG_DEBUG > 2
0202         std::cerr << local(*first) << '@' << owner(*first) << std::endl;
0203 #endif
0204         return *first;
0205       }
0206       else --last;
0207     }
0208 
0209 #if defined(PBGL_HOHBERG_DEBUG) && PBGL_HOHBERG_DEBUG > 2
0210     std::cerr << local(*last) << '@' << owner(*last) << std::endl;
0211 #endif
0212     // We've found b; it's the infimum.
0213     return *last;
0214   }
0215 } // end namespace hohberg_detail
0216 
0217 /* A message that will be stored for each edge by Hohberg's algorithm. */
0218 template<typename Graph>
0219 struct hohberg_message
0220 {
0221   typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
0222   typedef typename graph_traits<Graph>::edge_descriptor   Edge;
0223 
0224   // Assign from a path message
0225   void assign(const std::vector<Vertex>& path)
0226   {
0227     gamma = graph_traits<Graph>::null_vertex();
0228     path_or_bicomp = path;
0229   }
0230 
0231   // Assign from a tree message
0232   void assign(Vertex gamma, const std::vector<Vertex>& in_same_bicomponent)
0233   {
0234     this->gamma = gamma;
0235     path_or_bicomp = in_same_bicomponent;
0236   }
0237 
0238   bool is_path() const { return gamma == graph_traits<Graph>::null_vertex(); }
0239   bool is_tree() const { return gamma != graph_traits<Graph>::null_vertex(); }
0240 
0241   /// The "gamma" of a tree message, or null_vertex() for a path message
0242   Vertex gamma;
0243 
0244   // Either the path for a path message or the in_same_bicomponent
0245   std::vector<Vertex> path_or_bicomp;
0246 };
0247 
0248 
0249 /* An abstraction of a vertex processor in Hohberg's algorithm. The
0250    hohberg_vertex_processor class is responsible for processing
0251    messages transmitted to it via its edges. */
0252 template<typename Graph>
0253 class hohberg_vertex_processor
0254 {
0255   typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
0256   typedef typename graph_traits<Graph>::edge_descriptor   Edge;
0257   typedef typename graph_traits<Graph>::degree_size_type  degree_size_type;
0258   typedef typename graph_traits<Graph>::edges_size_type   edges_size_type;
0259   typedef typename boost::graph::parallel::process_group_type<Graph>::type
0260     ProcessGroup;
0261   typedef std::vector<Vertex> path_t;
0262   typedef typename path_t::iterator path_iterator;
0263 
0264  public:
0265   hohberg_vertex_processor()
0266     : phase(1),
0267       parent(graph_traits<Graph>::null_vertex()),
0268       eta(graph_traits<Graph>::null_vertex())
0269   {
0270   }
0271 
0272   // Called to initialize a leader in the algorithm, which involves
0273   // sending out the initial path messages and being ready to receive
0274   // them.
0275   void initialize_leader(Vertex alpha, const Graph& g);
0276 
0277   /// Handle a path message on edge e. The path will be destroyed by
0278   /// this operation.
0279   void
0280   operator()(Edge e, path_t& path, const Graph& g);
0281 
0282   /// Handle a tree message on edge e. in_same_bicomponent will be
0283   /// destroyed by this operation.
0284   void
0285   operator()(Edge e, Vertex gamma, path_t& in_same_bicomponent,
0286              const Graph& g);
0287 
0288   // Handle a name message.
0289   void operator()(Edge e, edges_size_type name, const Graph& g);
0290 
0291   // Retrieve the phase
0292   unsigned char get_phase() const { return phase; }
0293 
0294   // Start the naming phase. The current phase must be 3 (echo), and
0295   // the offset contains the offset at which this processor should
0296   // begin when labelling its bicomponents. The offset is just a
0297   // parallel prefix sum of the number of bicomponents in each
0298   // processor that precedes it (globally).
0299   void
0300   start_naming_phase(Vertex alpha, const Graph& g, edges_size_type offset);
0301 
0302   /* Determine the number of bicomponents that we will be naming
0303    * ourselves.
0304    */
0305   edges_size_type num_starting_bicomponents(Vertex alpha, const Graph& g);
0306 
0307   // Fill in the edge component map with biconnected component
0308   // numbers.
0309   template<typename ComponentMap>
0310   void fill_edge_map(Vertex alpha, const Graph& g, ComponentMap& component);
0311 
0312  protected:
0313   /* Start the echo phase (phase 3) where we propagate information up
0314      the tree. */
0315   void echo_phase(Vertex alpha, const Graph& g);
0316 
0317   /* Retrieve the index of edge in the out-edges list of target(e, g). */
0318   std::size_t get_edge_index(Edge e, const Graph& g);
0319 
0320   /* Retrieve the index of the edge incidence on v in the out-edges
0321      list of vertex u. */
0322   std::size_t get_incident_edge_index(Vertex u, Vertex v, const Graph& g);
0323 
0324   /* Keeps track of which phase of the algorithm we are in. There are
0325    * four phases plus the "finished" phase:
0326    *
0327    *   1) Building the spanning tree
0328    *   2) Discovering cycles
0329    *   3) Echoing back up the spanning tree
0330    *   4) Labelling biconnected components
0331    *   5) Finished
0332    */
0333   unsigned char phase;
0334 
0335   /* The parent of this vertex in the spanning tree. This value will
0336      be graph_traits<Graph>::null_vertex() for the leader. */
0337   Vertex parent;
0338 
0339   /* The farthest ancestor up the tree that resides in the same
0340      biconnected component as we do. This information is approximate:
0341      we might not know about the actual farthest ancestor, but this is
0342      the farthest one we've seen so far. */
0343   Vertex eta;
0344 
0345   /* The number of edges that have not yet transmitted any messages to
0346      us. This starts at the degree of the vertex and decreases as we
0347      receive messages. When this counter hits zero, we're done with
0348      the second phase of the algorithm. In Hohberg's paper, the actual
0349      remaining edge set E is stored with termination when all edges
0350      have been removed from E, but we only need to detect termination
0351      so the set E need not be explicitly represented. */
0352   degree_size_type num_edges_not_transmitted;
0353 
0354   /* The path from the root of the spanning tree to this vertex. This
0355      vector will always store only the parts of the path leading up to
0356      this vertex, and not the vertex itself. Thus, it will be empty
0357      for the leader. */
0358   std::vector<Vertex> path_from_root;
0359 
0360   /* Structure containing all of the extra data we need to keep around
0361      PER EDGE. This information can not be contained within a property
0362      map, because it can't be shared among vertices without breaking
0363      the algorithm. Decreasing the size of this structure will drastically */
0364   struct per_edge_data
0365   {
0366     hohberg_message<Graph> msg;
0367     std::vector<Vertex> M;
0368     bool is_tree_edge;
0369     degree_size_type partition;
0370   };
0371 
0372   /* Data for each edge in the graph. This structure will be indexed
0373      by the position of the edge in the out_edges() list. */
0374   std::vector<per_edge_data> edge_data;
0375 
0376   /* The mapping from local partition numbers (0..n-1) to global
0377      partition numbers. */
0378   std::vector<edges_size_type> local_to_global_partitions;
0379 
0380   friend class boost::serialization::access;
0381 
0382   // We cannot actually serialize a vertex processor, nor would we
0383   // want to. However, the fact that we're putting instances into a
0384   // distributed_property_map means that we need to have a serialize()
0385   // function available.
0386   template<typename Archiver>
0387   void serialize(Archiver&, const unsigned int /*version*/)
0388   {
0389     BOOST_ASSERT(false);
0390   }
0391 };
0392 
0393 template<typename Graph>
0394 void
0395 hohberg_vertex_processor<Graph>::initialize_leader(Vertex alpha,
0396                                                    const Graph& g)
0397 {
0398   using namespace hohberg_detail;
0399 
0400   ProcessGroup pg = process_group(g);
0401 
0402   typename property_map<Graph, vertex_owner_t>::const_type
0403     owner = get(vertex_owner, g);
0404 
0405   path_header<Edge> header;
0406   header.path_length = 1;
0407   BGL_FORALL_OUTEDGES_T(alpha, e, g, Graph) {
0408     header.edge = e;
0409     send(pg, get(owner, target(e, g)), msg_path_header, header);
0410     send(pg, get(owner, target(e, g)), msg_path_vertices, alpha);
0411   }
0412 
0413   num_edges_not_transmitted = degree(alpha, g);
0414   edge_data.resize(num_edges_not_transmitted);
0415   phase = 2;
0416 }
0417 
0418 template<typename Graph>
0419 void
0420 hohberg_vertex_processor<Graph>::operator()(Edge e, path_t& path,
0421                                             const Graph& g)
0422 {
0423   using namespace hohberg_detail;
0424 
0425   typename property_map<Graph, vertex_owner_t>::const_type
0426     owner = get(vertex_owner, g);
0427 
0428 #ifdef PBGL_HOHBERG_DEBUG
0429 //  std::cerr << local(source(e, g)) << '@' << owner(source(e, g)) << " -> "
0430 //            << local(target(e, g)) << '@' << owner(target(e, g)) << ": path(";
0431 //  for (std::size_t i = 0; i < path.size(); ++i) {
0432 //    if (i > 0) std::cerr << ' ';
0433 //    std::cerr << local(path[i]) << '@' << owner(path[i]);
0434 //  }
0435   std::cerr << "), phase = " << (int)phase << std::endl;
0436 #endif
0437 
0438   // Get access to edge-specific data
0439   if (edge_data.empty())
0440     edge_data.resize(degree(target(e, g), g));
0441   per_edge_data& edata = edge_data[get_edge_index(e, g)];
0442 
0443   // Record the message. We'll need it in phase 3.
0444   edata.msg.assign(path);
0445 
0446   // Note: "alpha" refers to the vertex "processor" receiving the
0447   // message.
0448   Vertex alpha = target(e, g);
0449 
0450   switch (phase) {
0451   case 1:
0452     {
0453       num_edges_not_transmitted = degree(alpha, g) - 1;
0454       edata.is_tree_edge = true;
0455       parent = path.back();
0456       eta = parent;
0457       edata.M.clear(); edata.M.push_back(parent);
0458 
0459       // Broadcast the path from the root to our potential children in
0460       // the spanning tree.
0461       path.push_back(alpha);
0462       path_header<Edge> header;
0463       header.path_length = path.size();
0464       ProcessGroup pg = process_group(g);
0465       BGL_FORALL_OUTEDGES_T(alpha, oe, g, Graph) {
0466         // Skip the tree edge we just received
0467         if (target(oe, g) != source(e, g)) {
0468           header.edge = oe;
0469           send(pg, get(owner, target(oe, g)), msg_path_header, header);
0470           send(pg, get(owner, target(oe, g)), msg_path_vertices, &path[0],
0471                header.path_length);
0472         }
0473       }
0474       path.pop_back();
0475 
0476       // Swap the old path in, to save some extra copying. Nobody
0477       path_from_root.swap(path);
0478 
0479       // Once we have received our place in the spanning tree, move on
0480       // to phase 2.
0481       phase = 2;
0482 
0483       // If we only had only edge, skip to phase 3.
0484       if (num_edges_not_transmitted == 0)
0485         echo_phase(alpha, g);
0486       return;
0487     }
0488 
0489   case 2:
0490     {
0491       --num_edges_not_transmitted;
0492       edata.is_tree_edge = false;
0493 
0494       // Determine if alpha (our vertex) is in the path
0495       path_iterator pos = std::find(path.begin(), path.end(), alpha);
0496       if (pos != path.end()) {
0497         // Case A: There is a cycle alpha beta ... gamma alpha
0498         // M(e) <- {beta, gammar}
0499         edata.M.clear();
0500         ++pos;
0501         // If pos == path.end(), we have a self-loop
0502         if (pos != path.end()) {
0503           // Add beta
0504           edata.M.push_back(*pos);
0505           ++pos;
0506         }
0507         // If pos == path.end(), we have a self-loop or beta == gamma
0508         // (parallel edge). Otherwise, add gamma.
0509         if (pos != path.end()) edata.M.push_back(path.back());
0510       } else {
0511         // Case B: There is a cycle but we haven't seen alpha yet.
0512         // M(e) = {parent, path.back()}
0513         edata.M.clear();
0514         edata.M.push_back(path.back());
0515         if (parent != path.back()) edata.M.push_back(parent);
0516 
0517         // eta = inf(eta, bra(pi_t, pi))
0518         eta = infimum(path_from_root, eta, branch_point(path_from_root, path));
0519       }
0520       if (num_edges_not_transmitted == 0)
0521         echo_phase(alpha, g);
0522       break;
0523     }
0524 
0525   default:
0526 //    std::cerr << "Phase is " << int(phase) << "\n";
0527     BOOST_ASSERT(false);
0528   }
0529 }
0530 
0531 template<typename Graph>
0532 void
0533 hohberg_vertex_processor<Graph>::operator()(Edge e, Vertex gamma,
0534                                             path_t& in_same_bicomponent,
0535                                             const Graph& g)
0536 {
0537   using namespace hohberg_detail;
0538 
0539 #ifdef PBGL_HOHBERG_DEBUG
0540   std::cerr << local(source(e, g)) << '@' << owner(source(e, g)) << " -> "
0541             << local(target(e, g)) << '@' << owner(target(e, g)) << ": tree("
0542             << local(gamma) << '@' << owner(gamma) << ", ";
0543   for (std::size_t i = 0; i < in_same_bicomponent.size(); ++i) {
0544     if (i > 0) std::cerr << ' ';
0545     std::cerr << local(in_same_bicomponent[i]) << '@'
0546               << owner(in_same_bicomponent[i]);
0547   }
0548   std::cerr << ", " << local(source(e, g)) << '@' << owner(source(e, g))
0549             << "), phase = " << (int)phase << std::endl;
0550 #endif
0551 
0552   // Get access to edge-specific data
0553   per_edge_data& edata = edge_data[get_edge_index(e, g)];
0554 
0555   // Record the message. We'll need it in phase 3.
0556   edata.msg.assign(gamma, in_same_bicomponent);
0557 
0558   // Note: "alpha" refers to the vertex "processor" receiving the
0559   // message.
0560   Vertex alpha = target(e, g);
0561   Vertex beta = source(e, g);
0562 
0563   switch (phase) {
0564   case 2:
0565     --num_edges_not_transmitted;
0566     edata.is_tree_edge = true;
0567 
0568     if (gamma == alpha) {
0569       // Case C
0570       edata.M.swap(in_same_bicomponent);
0571     } else {
0572       // Case D
0573       edata.M.clear();
0574       edata.M.push_back(parent);
0575       if (beta != parent) edata.M.push_back(beta);
0576       eta = infimum(path_from_root, eta, gamma);
0577     }
0578     if (num_edges_not_transmitted == 0)
0579       echo_phase(alpha, g);
0580     break;
0581 
0582   default:
0583     BOOST_ASSERT(false);
0584   }
0585 }
0586 
0587 template<typename Graph>
0588 void
0589 hohberg_vertex_processor<Graph>::operator()(Edge e, edges_size_type name,
0590                                             const Graph& g)
0591 {
0592   using namespace hohberg_detail;
0593 
0594 #ifdef PBGL_HOHBERG_DEBUG
0595   std::cerr << local(source(e, g)) << '@' << owner(source(e, g)) << " -> "
0596             << local(target(e, g)) << '@' << owner(target(e, g)) << ": name("
0597             << name << "), phase = " << (int)phase << std::endl;
0598 #endif
0599 
0600   BOOST_ASSERT(phase == 4);
0601 
0602   typename property_map<Graph, vertex_owner_t>::const_type
0603     owner = get(vertex_owner, g);
0604 
0605   // Send name messages along the spanning tree edges that are in the
0606   // same bicomponent as the edge to our parent.
0607   ProcessGroup pg = process_group(g);
0608 
0609   Vertex alpha = target(e, g);
0610 
0611   std::size_t idx = 0;
0612   BGL_FORALL_OUTEDGES_T(alpha, e, g, Graph) {
0613     per_edge_data& edata = edge_data[idx++];
0614     if (edata.is_tree_edge
0615         && find(edata.M.begin(), edata.M.end(), parent) != edata.M.end()
0616         && target(e, g) != parent) {
0617       // Notify our children in the spanning tree of this name
0618       name_header<Edge> header;
0619       header.edge = e;
0620       header.name = name;
0621       send(pg, get(owner, target(e, g)), msg_name, header);
0622     } else if (target(e, g) == parent) {
0623       // Map from local partition numbers to global bicomponent numbers
0624       local_to_global_partitions[edata.partition] = name;
0625     }
0626   }
0627 
0628   // Final stage
0629   phase = 5;
0630 }
0631 
0632 template<typename Graph>
0633 typename hohberg_vertex_processor<Graph>::edges_size_type
0634 hohberg_vertex_processor<Graph>::
0635 num_starting_bicomponents(Vertex alpha, const Graph& g)
0636 {
0637   edges_size_type not_mapped = (std::numeric_limits<edges_size_type>::max)();
0638 
0639   edges_size_type result = 0;
0640   std::size_t idx = 0;
0641   BGL_FORALL_OUTEDGES_T(alpha, e, g, Graph) {
0642     per_edge_data& edata = edge_data[idx++];
0643     if (edata.is_tree_edge
0644         && find(edata.M.begin(), edata.M.end(), parent) == edata.M.end()) {
0645       // Map from local partition numbers to global bicomponent numbers
0646       if (local_to_global_partitions[edata.partition] == not_mapped)
0647         local_to_global_partitions[edata.partition] = result++;
0648     }
0649   }
0650 
0651 #ifdef PBGL_HOHBERG_DEBUG
0652   std::cerr << local(alpha) << '@' << owner(alpha) << " has " << result
0653             << " bicomponents originating at it." << std::endl;
0654 #endif
0655 
0656   return result;
0657 }
0658 
0659 template<typename Graph>
0660 template<typename ComponentMap>
0661 void
0662 hohberg_vertex_processor<Graph>::
0663 fill_edge_map(Vertex alpha, const Graph& g, ComponentMap& component)
0664 {
0665   std::size_t idx = 0;
0666   BGL_FORALL_OUTEDGES_T(alpha, e, g, Graph) {
0667     per_edge_data& edata = edge_data[idx++];
0668     local_put(component, e, local_to_global_partitions[edata.partition]);
0669 
0670 #if defined(PBGL_HOHBERG_DEBUG) && PBGL_HOHBERG_DEBUG > 2
0671     std::cerr << "component("
0672               << local(source(e, g)) << '@' << owner(source(e, g)) << " -> "
0673               << local(target(e, g)) << '@' << owner(target(e, g)) << ") = "
0674               << local_to_global_partitions[edata.partition]
0675               << " (partition = " << edata.partition << " of "
0676               << local_to_global_partitions.size() << ")" << std::endl;
0677 #endif
0678   }
0679 }
0680 
0681 template<typename Graph>
0682 void
0683 hohberg_vertex_processor<Graph>::
0684 start_naming_phase(Vertex alpha, const Graph& g, edges_size_type offset)
0685 {
0686   using namespace hohberg_detail;
0687 
0688   BOOST_ASSERT(phase == 4);
0689 
0690   typename property_map<Graph, vertex_owner_t>::const_type
0691     owner = get(vertex_owner, g);
0692 
0693   // Send name messages along the spanning tree edges of the
0694   // components that we get to number.
0695   ProcessGroup pg = process_group(g);
0696 
0697   bool has_more_children_to_name = false;
0698 
0699   // Map from local partition numbers to global bicomponent numbers
0700   edges_size_type not_mapped = (std::numeric_limits<edges_size_type>::max)();
0701   for (std::size_t i = 0; i < local_to_global_partitions.size(); ++i) {
0702     if (local_to_global_partitions[i] != not_mapped)
0703       local_to_global_partitions[i] += offset;
0704   }
0705 
0706   std::size_t idx = 0;
0707   BGL_FORALL_OUTEDGES_T(alpha, e, g, Graph) {
0708     per_edge_data& edata = edge_data[idx++];
0709     if (edata.is_tree_edge
0710         && find(edata.M.begin(), edata.M.end(), parent) == edata.M.end()) {
0711       // Notify our children in the spanning tree of this new name
0712       name_header<Edge> header;
0713       header.edge = e;
0714       header.name = local_to_global_partitions[edata.partition];
0715       send(pg, get(owner, target(e, g)), msg_name, header);
0716     } else if (edata.is_tree_edge) {
0717       has_more_children_to_name = true;
0718     }
0719 #if defined(PBGL_HOHBERG_DEBUG) && PBGL_HOHBERG_DEBUG > 2
0720     std::cerr << "M[" << local(source(e, g)) << '@' << owner(source(e, g))
0721               << " -> " << local(target(e, g)) << '@' << owner(target(e, g))
0722               << "] = ";
0723     for (std::size_t i = 0; i < edata.M.size(); ++i) {
0724       std::cerr << local(edata.M[i]) << '@' << owner(edata.M[i]) << ' ';
0725     }
0726     std::cerr << std::endl;
0727 #endif
0728   }
0729 
0730   // See if we're done.
0731   if (!has_more_children_to_name)
0732     // Final stage
0733     phase = 5;
0734 }
0735 
0736 template<typename Graph>
0737 void
0738 hohberg_vertex_processor<Graph>::echo_phase(Vertex alpha, const Graph& g)
0739 {
0740   using namespace hohberg_detail;
0741 
0742   typename property_map<Graph, vertex_owner_t>::const_type
0743     owner = get(vertex_owner, g);
0744 
0745   /* We're entering the echo phase. */
0746   phase = 3;
0747 
0748   if (parent != graph_traits<Graph>::null_vertex()) {
0749     Edge edge_to_parent;
0750 
0751 #if defined(PBGL_HOHBERG_DEBUG) && PBGL_HOHBERG_DEBUG > 1
0752      std::cerr << local(alpha) << '@' << owner(alpha) << " echo: parent = "
0753                << local(parent) << '@' << owner(parent) << ", eta = "
0754                << local(eta) << '@' << owner(eta) << ", Gamma = ";
0755 #endif
0756 
0757     std::vector<Vertex> bicomp;
0758     std::size_t e_index = 0;
0759     BGL_FORALL_OUTEDGES_T(alpha, e, g, Graph) {
0760       if (target(e, g) == parent && parent == eta) {
0761         edge_to_parent = e;
0762         if (find(bicomp.begin(), bicomp.end(), alpha) == bicomp.end()) {
0763 #if defined(PBGL_HOHBERG_DEBUG) && PBGL_HOHBERG_DEBUG > 1
0764           std::cerr << local(alpha) << '@' << owner(alpha) << ' ';
0765 #endif
0766           bicomp.push_back(alpha);
0767         }
0768       } else {
0769         if (target(e, g) == parent) edge_to_parent = e;
0770 
0771         per_edge_data& edata = edge_data[e_index];
0772 
0773         if (edata.msg.is_path()) {
0774           path_iterator pos = std::find(edata.msg.path_or_bicomp.begin(),
0775                                         edata.msg.path_or_bicomp.end(),
0776                                         eta);
0777           if (pos != edata.msg.path_or_bicomp.end()) {
0778             ++pos;
0779             if (pos != edata.msg.path_or_bicomp.end()
0780                 && find(bicomp.begin(), bicomp.end(), *pos) == bicomp.end()) {
0781 #if defined(PBGL_HOHBERG_DEBUG) && PBGL_HOHBERG_DEBUG > 1
0782               std::cerr << local(*pos) << '@' << owner(*pos) << ' ';
0783 #endif
0784               bicomp.push_back(*pos);
0785             }
0786           }
0787         } else if (edata.msg.is_tree() && edata.msg.gamma == eta) {
0788           for (path_iterator i = edata.msg.path_or_bicomp.begin();
0789                i != edata.msg.path_or_bicomp.end(); ++i) {
0790             if (find(bicomp.begin(), bicomp.end(), *i) == bicomp.end()) {
0791 #if defined(PBGL_HOHBERG_DEBUG) && PBGL_HOHBERG_DEBUG > 1
0792               std::cerr << local(*i) << '@' << owner(*i) << ' ';
0793 #endif
0794               bicomp.push_back(*i);
0795             }
0796           }
0797         }
0798       }
0799       ++e_index;
0800     }
0801 #ifdef PBGL_HOHBERG_DEBUG
0802     std::cerr << std::endl;
0803 #endif
0804 
0805     // Send tree(eta, bicomp) to parent
0806     tree_header<Vertex, Edge> header;
0807     header.edge = edge_to_parent;
0808     header.gamma = eta;
0809     header.bicomp_length = bicomp.size();
0810     ProcessGroup pg = process_group(g);
0811     send(pg, get(owner, parent), msg_tree_header, header);
0812     send(pg, get(owner, parent), msg_tree_vertices, &bicomp[0],
0813          header.bicomp_length);
0814   }
0815 
0816   // Compute the partition of edges such that iff two edges e1 and e2
0817   // are in different subsets then M(e1) is disjoint from M(e2).
0818 
0819   // Start by putting each edge in a different partition
0820   std::vector<degree_size_type> parent_vec(edge_data.size());
0821   degree_size_type idx = 0;
0822   for (idx = 0; idx < edge_data.size(); ++idx)
0823     parent_vec[idx] = idx;
0824 
0825   // Go through each edge e, performing a union() on the edges
0826   // incident on all vertices in M[e].
0827   idx = 0;
0828   BGL_FORALL_OUTEDGES_T(alpha, e, g, Graph) {
0829     per_edge_data& edata = edge_data[idx++];
0830 
0831     // Compute union of vertices in M
0832     if (!edata.M.empty()) {
0833       degree_size_type e1 = get_incident_edge_index(alpha, edata.M.front(), g);
0834       while (parent_vec[e1] != e1) e1 = parent_vec[e1];
0835 
0836       for (std::size_t i = 1; i < edata.M.size(); ++i) {
0837         degree_size_type e2 = get_incident_edge_index(alpha, edata.M[i], g);
0838         while (parent_vec[e2] != e2) e2 = parent_vec[e2];
0839         parent_vec[e2] = e1;
0840       }
0841     }
0842   }
0843 
0844   edges_size_type not_mapped = (std::numeric_limits<edges_size_type>::max)();
0845 
0846   // Determine the number of partitions
0847   for (idx = 0; idx < parent_vec.size(); ++idx) {
0848     if (parent_vec[idx] == idx) {
0849       edge_data[idx].partition = local_to_global_partitions.size();
0850       local_to_global_partitions.push_back(not_mapped);
0851     }
0852   }
0853 
0854   // Assign partition numbers to each edge
0855   for (idx = 0; idx < parent_vec.size(); ++idx) {
0856     degree_size_type rep = parent_vec[idx];
0857     while (rep != parent_vec[rep]) rep = parent_vec[rep];
0858     edge_data[idx].partition = edge_data[rep].partition;
0859   }
0860 
0861   // Enter the naming phase (but don't send anything yet).
0862   phase = 4;
0863 }
0864 
0865 template<typename Graph>
0866 std::size_t
0867 hohberg_vertex_processor<Graph>::get_edge_index(Edge e, const Graph& g)
0868 {
0869   std::size_t result = 0;
0870   BGL_FORALL_OUTEDGES_T(target(e, g), oe, g, Graph) {
0871     if (source(e, g) == target(oe, g)) return result;
0872     ++result;
0873   }
0874   BOOST_ASSERT(false);
0875 }
0876 
0877 template<typename Graph>
0878 std::size_t
0879 hohberg_vertex_processor<Graph>::get_incident_edge_index(Vertex u, Vertex v,
0880                                                          const Graph& g)
0881 {
0882   std::size_t result = 0;
0883   BGL_FORALL_OUTEDGES_T(u, e, g, Graph) {
0884     if (target(e, g) == v) return result;
0885     ++result;
0886   }
0887   BOOST_ASSERT(false);
0888 }
0889 
0890 template<typename Graph, typename InputIterator, typename ComponentMap,
0891          typename VertexProcessorMap>
0892 typename graph_traits<Graph>::edges_size_type
0893 hohberg_biconnected_components
0894   (const Graph& g,
0895    ComponentMap component,
0896    InputIterator first, InputIterator last,
0897    VertexProcessorMap vertex_processor)
0898 {
0899   using namespace boost::graph::parallel;
0900   using namespace hohberg_detail;
0901   using boost::parallel::all_reduce;
0902 
0903   typename property_map<Graph, vertex_owner_t>::const_type
0904     owner = get(vertex_owner, g);
0905 
0906   // The graph must be undirected
0907   BOOST_STATIC_ASSERT(
0908     (is_convertible<typename graph_traits<Graph>::directed_category,
0909                     undirected_tag>::value));
0910 
0911   // The graph must model Incidence Graph
0912   BOOST_CONCEPT_ASSERT(( IncidenceGraphConcept<Graph> ));
0913 
0914   typedef typename graph_traits<Graph>::edges_size_type edges_size_type;
0915   typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
0916   typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
0917 
0918   // Retrieve the process group we will use for communication
0919   typedef typename process_group_type<Graph>::type process_group_type;
0920   process_group_type pg = process_group(g);
0921 
0922   // Keeps track of the edges that we know to be tree edges.
0923   std::vector<edge_descriptor> tree_edges;
0924 
0925   // The leaders send out a path message to initiate the algorithm
0926   while (first != last) {
0927     vertex_descriptor leader = *first;
0928     if (process_id(pg) == get(owner, leader))
0929       vertex_processor[leader].initialize_leader(leader, g);
0930     ++first;
0931   }
0932   synchronize(pg);
0933 
0934   // Will hold the number of bicomponents in the graph.
0935   edges_size_type num_bicomponents = 0;
0936 
0937   // Keep track of the path length that we should expect, based on the
0938   // level in the breadth-first search tree. At present, this is only
0939   // used as a sanity check. TBD: This could be used to decrease the
0940   // amount of communication required per-edge (by about 4 bytes).
0941   std::size_t path_length = 1;
0942 
0943   typedef std::vector<vertex_descriptor> path_t;
0944 
0945   unsigned char minimum_phase = 5;
0946   do {
0947     while (optional<std::pair<int, int> > msg = probe(pg)) {
0948       switch (msg->second) {
0949       case msg_path_header:
0950         {
0951           // Receive the path header
0952           path_header<edge_descriptor> header;
0953           receive(pg, msg->first, msg->second, header);
0954           BOOST_ASSERT(path_length == header.path_length);
0955 
0956           // Receive the path itself
0957           path_t path(path_length);
0958           receive(pg, msg->first, msg_path_vertices, &path[0], path_length);
0959 
0960           edge_descriptor e = header.edge;
0961           vertex_processor[target(e, g)](e, path, g);
0962         }
0963         break;
0964 
0965       case msg_path_vertices:
0966         // Should be handled in msg_path_header case, unless we're going
0967         // stateless.
0968         BOOST_ASSERT(false);
0969         break;
0970 
0971       case msg_tree_header:
0972         {
0973           // Receive the tree header
0974           tree_header<vertex_descriptor, edge_descriptor> header;
0975           receive(pg, msg->first, msg->second, header);
0976 
0977           // Receive the tree itself
0978           path_t in_same_bicomponent(header.bicomp_length);
0979           receive(pg, msg->first, msg_tree_vertices, &in_same_bicomponent[0],
0980                   header.bicomp_length);
0981 
0982           edge_descriptor e = header.edge;
0983           vertex_processor[target(e, g)](e, header.gamma, in_same_bicomponent,
0984                                          g);
0985         }
0986         break;
0987 
0988       case msg_tree_vertices:
0989         // Should be handled in msg_tree_header case, unless we're
0990         // going stateless.
0991         BOOST_ASSERT(false);
0992         break;
0993 
0994       case msg_name:
0995         {
0996           name_header<edge_descriptor> header;
0997           receive(pg, msg->first, msg->second, header);
0998           edge_descriptor e = header.edge;
0999           vertex_processor[target(e, g)](e, header.name, g);
1000         }
1001         break;
1002 
1003       default:
1004         BOOST_ASSERT(false);
1005       }
1006     }
1007     ++path_length;
1008 
1009     // Compute minimum phase locally
1010     minimum_phase = 5;
1011     unsigned char maximum_phase = 1;
1012     BGL_FORALL_VERTICES_T(v, g, Graph) {
1013       minimum_phase = (std::min)(minimum_phase, vertex_processor[v].get_phase());
1014       maximum_phase = (std::max)(maximum_phase, vertex_processor[v].get_phase());
1015     }
1016 
1017 #ifdef PBGL_HOHBERG_DEBUG
1018     if (process_id(pg) == 0)
1019       std::cerr << "<---------End of stage------------->" << std::endl;
1020 #endif
1021     // Compute minimum phase globally
1022     minimum_phase = all_reduce(pg, minimum_phase, boost::mpi::minimum<char>());
1023 
1024 #ifdef PBGL_HOHBERG_DEBUG
1025     if (process_id(pg) == 0)
1026       std::cerr << "Minimum phase = " << (int)minimum_phase << std::endl;
1027 #endif
1028 
1029     if (minimum_phase == 4
1030         && all_reduce(pg, maximum_phase, boost::mpi::maximum<char>()) == 4) {
1031 
1032 #ifdef PBGL_HOHBERG_DEBUG
1033       if (process_id(pg) == 0)
1034         std::cerr << "<---------Naming phase------------->" << std::endl;
1035 #endif
1036       // Compute the biconnected component number offsets for each
1037       // vertex.
1038       std::vector<edges_size_type> local_offsets;
1039       local_offsets.reserve(num_vertices(g));
1040       edges_size_type num_local_bicomponents = 0;
1041       BGL_FORALL_VERTICES_T(v, g, Graph) {
1042         local_offsets.push_back(num_local_bicomponents);
1043         num_local_bicomponents +=
1044           vertex_processor[v].num_starting_bicomponents(v, g);
1045       }
1046 
1047       synchronize(pg);
1048 
1049       // Find our the number of bicomponent names that will originate
1050       // from each process. This tells us how many bicomponents are in
1051       // the entire graph and what our global offset is for computing
1052       // our own biconnected component names.
1053       std::vector<edges_size_type> all_bicomponents(num_processes(pg));
1054       all_gather(pg, &num_local_bicomponents, &num_local_bicomponents + 1,
1055                  all_bicomponents);
1056       num_bicomponents = 0;
1057       edges_size_type my_global_offset = 0;
1058       for (std::size_t i = 0; i < all_bicomponents.size(); ++i) {
1059         if (i == (std::size_t)process_id(pg)) 
1060           my_global_offset = num_bicomponents;
1061         num_bicomponents += all_bicomponents[i];
1062       }
1063 
1064       std::size_t index = 0;
1065       BGL_FORALL_VERTICES_T(v, g, Graph) {
1066         edges_size_type offset = my_global_offset + local_offsets[index++];
1067         vertex_processor[v].start_naming_phase(v, g, offset);
1068       }
1069     }
1070 
1071     synchronize(pg);
1072   } while (minimum_phase < 5);
1073 
1074   // Number the edges appropriately.
1075   BGL_FORALL_VERTICES_T(v, g, Graph)
1076     vertex_processor[v].fill_edge_map(v, g, component);
1077 
1078   return num_bicomponents;
1079 }
1080 
1081 template<typename Graph, typename ComponentMap, typename InputIterator>
1082 typename graph_traits<Graph>::edges_size_type
1083 hohberg_biconnected_components
1084   (const Graph& g, ComponentMap component,
1085    InputIterator first, InputIterator last)
1086 
1087 {
1088   std::vector<hohberg_vertex_processor<Graph> >
1089     vertex_processors(num_vertices(g));
1090   return hohberg_biconnected_components
1091            (g, component, first, last,
1092             make_iterator_property_map(vertex_processors.begin(),
1093                                        get(vertex_index, g)));
1094 }
1095 
1096 template<typename Graph, typename ComponentMap, typename ParentMap>
1097 typename graph_traits<Graph>::edges_size_type
1098 hohberg_biconnected_components(const Graph& g, ComponentMap component,
1099                                ParentMap parent)
1100 {
1101   // We need the connected components of the graph, but we don't care
1102   // about component numbers.
1103   connected_components(g, dummy_property_map(), parent);
1104 
1105   // Each root in the parent map is a leader
1106   typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
1107   std::vector<vertex_descriptor> leaders;
1108   BGL_FORALL_VERTICES_T(v, g, Graph)
1109     if (get(parent, v) == v) leaders.push_back(v);
1110 
1111   return hohberg_biconnected_components(g, component,
1112                                         leaders.begin(), leaders.end());
1113 }
1114 
1115 template<typename Graph, typename ComponentMap>
1116 typename graph_traits<Graph>::edges_size_type
1117 hohberg_biconnected_components(const Graph& g, ComponentMap component)
1118 {
1119   typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
1120   std::vector<vertex_descriptor> parents(num_vertices(g));
1121   return hohberg_biconnected_components
1122            (g, component, make_iterator_property_map(parents.begin(),
1123                                                      get(vertex_index, g)));
1124 }
1125 
1126 } } } // end namespace boost::graph::distributed
1127 
1128 #endif // BOOST_GRAPH_DISTRIBUTED_HOHBERG_BICONNECTED_COMPONENTS_HPP