Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-30 09:46:55

0001 // Copyright (C) 2007 Trustees of Indiana University
0002 
0003 // Authors: Douglas Gregor
0004 //          Andrew Lumsdaine
0005 
0006 // Use, modification and distribution is subject to the Boost Software
0007 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
0008 // http://www.boost.org/LICENSE_1_0.txt)
0009 
0010 /** @file graph_communicator.hpp
0011  *
0012  *  This header defines facilities to support MPI communicators with
0013  *  graph topologies, using the graph interface defined by the Boost
0014  *  Graph Library. One can construct a communicator whose topology is
0015  *  described by any graph meeting the requirements of the Boost Graph
0016  *  Library's graph concepts. Likewise, any communicator that has a
0017  *  graph topology can be viewed as a graph by the Boost Graph
0018  *  Library, permitting one to use the BGL's graph algorithms on the
0019  *  process topology.
0020  */
0021 #ifndef BOOST_MPI_GRAPH_COMMUNICATOR_HPP
0022 #define BOOST_MPI_GRAPH_COMMUNICATOR_HPP
0023 
0024 #include <boost/mpi/communicator.hpp>
0025 #include <vector>
0026 #include <utility>
0027 
0028 // Headers required to implement graph topologies
0029 #include <boost/graph/graph_traits.hpp>
0030 #include <boost/graph/properties.hpp>
0031 #include <boost/iterator/counting_iterator.hpp>
0032 #include <boost/graph/iteration_macros.hpp>
0033 #include <boost/shared_array.hpp>
0034 #include <boost/assert.hpp>
0035 
0036 namespace boost { namespace mpi {
0037 
0038 /**
0039  * @brief An MPI communicator with a graph topology.
0040  *
0041  * A @c graph_communicator is a communicator whose topology is
0042  * expressed as a graph. Graph communicators have the same
0043  * functionality as (intra)communicators, but also allow one to query
0044  * the relationships among processes. Those relationships are
0045  * expressed via a graph, using the interface defined by the Boost
0046  * Graph Library. The @c graph_communicator class meets the
0047  * requirements of the BGL Graph, Incidence Graph, Adjacency Graph,
0048  * Vertex List Graph, and Edge List Graph concepts.
0049  */
0050 class BOOST_MPI_DECL graph_communicator : public communicator
0051 {
0052   friend class communicator;
0053 
0054   /**
0055    * INTERNAL ONLY
0056    *
0057    * Construct a graph communicator given a shared pointer to the
0058    * underlying MPI_Comm. This operation is used for "casting" from a
0059    * communicator to a graph communicator.
0060    */
0061   explicit graph_communicator(const shared_ptr<MPI_Comm>& comm_ptr)
0062   {
0063 #ifndef BOOST_DISABLE_ASSERTS
0064     int status;
0065     BOOST_MPI_CHECK_RESULT(MPI_Topo_test, ((MPI_Comm)*this, &status));
0066     BOOST_ASSERT(status == MPI_GRAPH);
0067 #endif
0068     this->comm_ptr = comm_ptr;
0069   }
0070 
0071 public:
0072   /**
0073    * Build a new Boost.MPI graph communicator based on the MPI
0074    * communicator @p comm with graph topology.
0075    *
0076    * @p comm may be any valid MPI communicator. If @p comm is
0077    * MPI_COMM_NULL, an empty communicator (that cannot be used for
0078    * communication) is created and the @p kind parameter is
0079    * ignored. Otherwise, the @p kind parameter determines how the
0080    * Boost.MPI communicator will be related to @p comm:
0081    *
0082    *   - If @p kind is @c comm_duplicate, duplicate @c comm to create
0083    *   a new communicator. This new communicator will be freed when
0084    *   the Boost.MPI communicator (and all copies of it) is
0085    *   destroyed. This option is only permitted if the underlying MPI
0086    *   implementation supports MPI 2.0; duplication of
0087    *   intercommunicators is not available in MPI 1.x.
0088    *
0089    *   - If @p kind is @c comm_take_ownership, take ownership of @c
0090    *   comm. It will be freed automatically when all of the Boost.MPI
0091    *   communicators go out of scope.
0092    *
0093    *   - If @p kind is @c comm_attach, this Boost.MPI communicator
0094    *   will reference the existing MPI communicator @p comm but will
0095    *   not free @p comm when the Boost.MPI communicator goes out of
0096    *   scope. This option should only be used when the communicator is
0097    *   managed by the user.
0098    */
0099   graph_communicator(const MPI_Comm& comm, comm_create_kind kind)
0100     : communicator(comm, kind)
0101   { 
0102 #ifndef BOOST_DISABLE_ASSERTS
0103     int status;
0104     BOOST_MPI_CHECK_RESULT(MPI_Topo_test, ((MPI_Comm)*this, &status));
0105     BOOST_ASSERT(status == MPI_GRAPH);
0106 #endif
0107   }
0108 
0109   /**
0110    *  Create a new communicator whose topology is described by the
0111    *  given graph. The indices of the vertices in the graph will be
0112    *  assumed to be the ranks of the processes within the
0113    *  communicator. There may be fewer vertices in the graph than
0114    *  there are processes in the communicator; in this case, the
0115    *  resulting communicator will be a NULL communicator.
0116    *
0117    *  @param comm The communicator that the new, graph communicator
0118    *  will be based on. 
0119    * 
0120    *  @param graph Any type that meets the requirements of the
0121    *  Incidence Graph and Vertex List Graph concepts from the Boost Graph
0122    *  Library. This structure of this graph will become the topology
0123    *  of the communicator that is returned.
0124    *
0125    *  @param reorder Whether MPI is permitted to re-order the process
0126    *  ranks within the returned communicator, to better optimize
0127    *  communication. If false, the ranks of each process in the
0128    *  returned process will match precisely the rank of that process
0129    *  within the original communicator.
0130    */
0131   template<typename Graph>
0132   explicit 
0133   graph_communicator(const communicator& comm, const Graph& graph, 
0134                      bool reorder = false);
0135 
0136   /**
0137    *  Create a new communicator whose topology is described by the
0138    *  given graph. The rank map (@p rank) gives the mapping from
0139    *  vertices in the graph to ranks within the communicator. There
0140    *  may be fewer vertices in the graph than there are processes in
0141    *  the communicator; in this case, the resulting communicator will
0142    *  be a NULL communicator.
0143    *
0144    *  @param comm The communicator that the new, graph communicator
0145    *  will be based on. The ranks in @c rank refer to the processes in
0146    *  this communicator.
0147    * 
0148    *  @param graph Any type that meets the requirements of the
0149    *  Incidence Graph and Vertex List Graph concepts from the Boost Graph
0150    *  Library. This structure of this graph will become the topology
0151    *  of the communicator that is returned.
0152    *
0153    *  @param rank This map translates vertices in the @c graph into
0154    *  ranks within the current communicator. It must be a Readable
0155    *  Property Map (see the Boost Property Map library) whose key type
0156    *  is the vertex type of the @p graph and whose value type is @c
0157    *  int.
0158    *
0159    *  @param reorder Whether MPI is permitted to re-order the process
0160    *  ranks within the returned communicator, to better optimize
0161    *  communication. If false, the ranks of each process in the
0162    *  returned process will match precisely the rank of that process
0163    *  within the original communicator.
0164    */
0165   template<typename Graph, typename RankMap>
0166   explicit 
0167   graph_communicator(const communicator& comm, const Graph& graph, 
0168                      RankMap rank, bool reorder = false);
0169 
0170 protected:
0171   /**
0172    * INTERNAL ONLY
0173    *
0174    * Used by the constructors to create the new communicator with a
0175    * graph topology.
0176    */
0177   template<typename Graph, typename RankMap>
0178   void
0179   setup_graph(const communicator& comm, const Graph& graph, RankMap rank, 
0180               bool reorder);
0181 };
0182 
0183 /****************************************************************************
0184  *  Implementation Details                                                  *
0185  ****************************************************************************/
0186 
0187 template<typename Graph>
0188 graph_communicator::graph_communicator(const communicator& comm, 
0189                                        const Graph& graph, 
0190                                        bool reorder)
0191 {
0192   this->setup_graph(comm, graph, get(vertex_index, graph), reorder);
0193 }
0194 
0195 template<typename Graph, typename RankMap>
0196 graph_communicator::graph_communicator(const communicator& comm, 
0197                                        const Graph& graph, 
0198                                        RankMap rank, bool reorder)
0199 {
0200   this->setup_graph(comm, graph, rank, reorder);
0201 }
0202 
0203 
0204 template<typename Graph, typename RankMap>
0205 void
0206 graph_communicator::setup_graph(const communicator& comm, const Graph& graph, 
0207                                 RankMap rank, bool reorder)
0208 {
0209   typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
0210 
0211   // Build a mapping from ranks to vertices
0212   std::vector<vertex_descriptor> vertex_with_rank(num_vertices(graph));
0213   if (vertex_with_rank.empty())
0214     return;
0215 
0216   BGL_FORALL_VERTICES_T(v, graph, Graph)
0217     vertex_with_rank[get(rank, v)] = v;
0218 
0219   // Build the representation of the graph required by
0220   // MPI_Graph_create.
0221   std::vector<int> indices(num_vertices(graph));
0222   std::vector<int> edges;
0223   int nvertices = indices.size();
0224   for (int vertex_index = 0; vertex_index < nvertices; ++vertex_index) {
0225     vertex_descriptor v = vertex_with_rank[vertex_index];
0226 
0227     BGL_FORALL_OUTEDGES_T(v, e, graph, Graph)
0228       edges.push_back(get(rank, target(e, graph)));
0229 
0230     indices[vertex_index] = edges.size();
0231   }
0232 
0233   // Create the new communicator
0234   MPI_Comm newcomm;
0235   BOOST_MPI_CHECK_RESULT(MPI_Graph_create,
0236                          ((MPI_Comm)comm, 
0237                           nvertices,
0238                           detail::c_data(indices),
0239                           detail::c_data(edges),
0240                           reorder,
0241                           &newcomm));
0242   this->comm_ptr.reset(new MPI_Comm(newcomm), comm_free());
0243 }
0244 
0245 /****************************************************************************
0246  *  Communicator with Graph Topology as BGL Graph                           *
0247  ****************************************************************************/
0248 namespace detail {
0249   /**
0250    *  INTERNAL ONLY
0251    *
0252    *  The iterator used to access the outgoing edges within a
0253    *  communicator's graph topology.
0254    */
0255   class comm_out_edge_iterator
0256     : public iterator_facade<comm_out_edge_iterator, 
0257                              std::pair<int, int>,
0258                              random_access_traversal_tag,
0259                              const std::pair<int, int>&, 
0260                              int>
0261   {
0262   public:
0263     comm_out_edge_iterator() { }
0264 
0265     comm_out_edge_iterator(int source, shared_array<int> neighbors, int index)
0266       : edge(source, -1), neighbors(neighbors), index(index) { }
0267 
0268   protected:
0269     friend class boost::iterator_core_access;
0270 
0271     const std::pair<int, int>& dereference() const
0272     {
0273       edge.second = neighbors[index];
0274       return edge;
0275     }
0276 
0277     bool equal(const comm_out_edge_iterator& other) const
0278     {
0279       return (edge.first == other.edge.first
0280               && index == other.index);
0281     }
0282 
0283     void increment() { ++index; }
0284 
0285     void decrement() { --index; }
0286 
0287     void advance(int n) { index += n; }
0288 
0289     int distance_to(const comm_out_edge_iterator& other) const
0290     {
0291       return other.index - index;
0292     }
0293 
0294     mutable std::pair<int, int> edge;
0295     shared_array<int> neighbors;
0296     int index;
0297   };
0298 
0299   /**
0300    *  INTERNAL ONLY
0301    *
0302    *  The iterator used to access the adjacent vertices within a
0303    *  communicator's graph topology.
0304    */
0305   class comm_adj_iterator
0306     : public iterator_facade<comm_adj_iterator, 
0307                              int,
0308                              random_access_traversal_tag,
0309                              int, 
0310                              int>
0311   {
0312   public:
0313     comm_adj_iterator() { }
0314 
0315     comm_adj_iterator(shared_array<int> neighbors, int index)
0316       : neighbors(neighbors), index(index) { }
0317 
0318   protected:
0319     friend class boost::iterator_core_access;
0320 
0321     int dereference() const { return neighbors[index]; }
0322 
0323     bool equal(const comm_adj_iterator& other) const
0324     {
0325       return (neighbors == other.neighbors
0326               && index == other.index);
0327     }
0328 
0329     void increment() { ++index; }
0330 
0331     void decrement() { --index; }
0332 
0333     void advance(int n) { index += n; }
0334 
0335     int distance_to(const comm_adj_iterator& other) const
0336     {
0337       return other.index - index;
0338     }
0339 
0340     shared_array<int> neighbors;
0341     int index;
0342   };
0343 
0344   /**
0345    *  INTERNAL ONLY
0346    *
0347    *  The iterator used to access the edges in a communicator's graph
0348    *  topology.
0349    */
0350   class comm_edge_iterator
0351     : public iterator_facade<comm_edge_iterator, 
0352                              std::pair<int, int>,
0353                              forward_traversal_tag,
0354                              const std::pair<int, int>&, 
0355                              int>
0356   {
0357   public:
0358     comm_edge_iterator() { }
0359 
0360     /// Constructor for a past-the-end iterator
0361     comm_edge_iterator(int nedges) : edge_index(nedges) { }
0362 
0363     comm_edge_iterator(shared_array<int> indices, shared_array<int> edges)
0364       : indices(indices), edges(edges), edge_index(0), edge(0, 0)
0365     { }
0366 
0367   protected:
0368     friend class boost::iterator_core_access;
0369 
0370     const std::pair<int, int>& dereference() const
0371     {
0372       while (edge_index == indices[edge.first])
0373         ++edge.first;
0374       edge.second = edges[edge_index];
0375       return edge;
0376     }
0377 
0378     bool equal(const comm_edge_iterator& other) const
0379     {
0380       return edge_index == other.edge_index;
0381     }
0382 
0383     void increment() 
0384     { 
0385       ++edge_index; 
0386     }
0387 
0388     shared_array<int> indices;
0389     shared_array<int> edges;
0390     int edge_index;
0391     mutable std::pair<int, int> edge;
0392   };
0393 
0394 } // end namespace detail
0395 
0396 // Incidence Graph requirements
0397 
0398 /**
0399  * @brief Returns the source vertex from an edge in the graph topology
0400  * of a communicator.
0401  */
0402 inline int source(const std::pair<int, int>& edge, const graph_communicator&)
0403 {
0404   return edge.first;
0405 }
0406 
0407 /**
0408  * @brief Returns the target vertex from an edge in the graph topology
0409  * of a communicator.
0410  */
0411 inline int target(const std::pair<int, int>& edge, const graph_communicator&)
0412 {
0413   return edge.second;
0414 }
0415 
0416 /**
0417  * @brief Returns an iterator range containing all of the edges
0418  * outgoing from the given vertex in a graph topology of a
0419  * communicator.
0420  */
0421 std::pair<detail::comm_out_edge_iterator, detail::comm_out_edge_iterator>
0422 out_edges(int vertex, const graph_communicator& comm);
0423 
0424 
0425 /**
0426  * @brief Returns the out-degree of a vertex in the graph topology of
0427  * a communicator.
0428  */
0429 int out_degree(int vertex, const graph_communicator& comm);
0430 
0431 // Adjacency Graph requirements
0432 
0433 /**
0434  * @brief Returns an iterator range containing all of the neighbors of
0435  * the given vertex in the communicator's graph topology.
0436  */
0437 std::pair<detail::comm_adj_iterator, detail::comm_adj_iterator>
0438 adjacent_vertices(int vertex, const graph_communicator& comm);
0439 
0440 // Vertex List Graph requirements
0441 
0442 /**
0443  * @brief Returns an iterator range that contains all of the vertices
0444  * with the communicator's graph topology, i.e., all of the process
0445  * ranks in the communicator.
0446  */
0447 inline std::pair<counting_iterator<int>, counting_iterator<int> >
0448 vertices(const graph_communicator& comm)
0449 {
0450   return std::make_pair(counting_iterator<int>(0),
0451                         counting_iterator<int>(comm.size()));
0452 }
0453 
0454 /**
0455  *  @brief Returns the number of vertices within the graph topology of
0456  *  the communicator, i.e., the number of processes in the
0457  *  communicator.
0458  */
0459 inline int num_vertices(const graph_communicator& comm) { return comm.size(); }
0460 
0461 // Edge List Graph requirements
0462 
0463 /**
0464  * @brief Returns an iterator range that contains all of the edges
0465  * with the communicator's graph topology.
0466  */
0467 std::pair<detail::comm_edge_iterator, detail::comm_edge_iterator>
0468 edges(const graph_communicator& comm);
0469 
0470 /**
0471  * @brief Returns the number of edges in the communicator's graph
0472  * topology.
0473  */
0474 int num_edges(const graph_communicator& comm);
0475 
0476 // Property Graph requirements
0477 
0478 /**
0479  *  @brief Returns a property map that maps from vertices in a
0480  *  communicator's graph topology to their index values. 
0481  *
0482  *  Since the vertices are ranks in the communicator, the returned
0483  *  property map is the identity property map.
0484  */
0485 inline identity_property_map get(vertex_index_t, const graph_communicator&)
0486 {
0487   return identity_property_map();
0488 }
0489 
0490 /**
0491  * @brief Returns the index of a vertex in the communicator's graph
0492  * topology.
0493  *
0494  * Since the vertices are ranks in the communicator, this is the
0495  *  identity function.
0496  */
0497 inline int get(vertex_index_t, const graph_communicator&, int vertex)
0498 {
0499   return vertex;
0500 }
0501 
0502 } } // end namespace boost::mpi
0503 
0504 namespace boost {
0505 
0506 /**
0507  * @brief Traits structure that allows a communicator with graph
0508  * topology to be view as a graph by the Boost Graph Library.
0509  *
0510  * The specialization of @c graph_traits for an MPI communicator
0511  * allows a communicator with graph topology to be viewed as a
0512  * graph. An MPI communicator with graph topology meets the
0513  * requirements of the Graph, Incidence Graph, Adjacency Graph, Vertex
0514  * List Graph, and Edge List Graph concepts from the Boost Graph
0515  * Library.
0516  */
0517 template<>
0518 struct graph_traits<mpi::graph_communicator> {
0519   // Graph concept requirements
0520   typedef int                        vertex_descriptor;
0521   typedef std::pair<int, int>        edge_descriptor;
0522   typedef directed_tag               directed_category;
0523   typedef disallow_parallel_edge_tag edge_parallel_category;
0524   
0525   /**
0526    * INTERNAL ONLY
0527    */
0528   struct traversal_category
0529     : incidence_graph_tag, 
0530       adjacency_graph_tag, 
0531       vertex_list_graph_tag, 
0532       edge_list_graph_tag 
0533   { 
0534   };
0535 
0536   /**
0537    * @brief Returns a vertex descriptor that can never refer to any
0538    * valid vertex.
0539    */
0540   static vertex_descriptor null_vertex() { return -1; }
0541 
0542   // Incidence Graph requirements
0543   typedef mpi::detail::comm_out_edge_iterator out_edge_iterator;
0544   typedef int degree_size_type;
0545 
0546   // Adjacency Graph requirements
0547   typedef mpi::detail::comm_adj_iterator adjacency_iterator;
0548 
0549   // Vertex List Graph requirements
0550   typedef counting_iterator<int> vertex_iterator;
0551   typedef int                    vertices_size_type;
0552 
0553   // Edge List Graph requirements
0554   typedef mpi::detail::comm_edge_iterator edge_iterator;
0555   typedef int                             edges_size_type;
0556 };
0557 
0558 // Property Graph requirements
0559 
0560 /**
0561  * INTERNAL ONLY
0562  */
0563 template<>
0564 struct property_map<mpi::graph_communicator, vertex_index_t>
0565 {
0566   typedef identity_property_map type;
0567   typedef identity_property_map const_type;
0568 };
0569 
0570 } // end namespace boost
0571 
0572 
0573 
0574 #endif // BOOST_MPI_GRAPH_COMMUNICATOR_HPP