graph_communicator.hpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574
  1. // Copyright (C) 2007 Trustees of Indiana University
  2. // Authors: Douglas Gregor
  3. // Andrew Lumsdaine
  4. // Use, modification and distribution is subject to the Boost Software
  5. // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt)
  7. /** @file graph_communicator.hpp
  8. *
  9. * This header defines facilities to support MPI communicators with
  10. * graph topologies, using the graph interface defined by the Boost
  11. * Graph Library. One can construct a communicator whose topology is
  12. * described by any graph meeting the requirements of the Boost Graph
  13. * Library's graph concepts. Likewise, any communicator that has a
  14. * graph topology can be viewed as a graph by the Boost Graph
  15. * Library, permitting one to use the BGL's graph algorithms on the
  16. * process topology.
  17. */
  18. #ifndef BOOST_MPI_GRAPH_COMMUNICATOR_HPP
  19. #define BOOST_MPI_GRAPH_COMMUNICATOR_HPP
  20. #include <boost/mpi/communicator.hpp>
  21. #include <vector>
  22. #include <utility>
  23. // Headers required to implement graph topologies
  24. #include <boost/graph/graph_traits.hpp>
  25. #include <boost/graph/properties.hpp>
  26. #include <boost/iterator/counting_iterator.hpp>
  27. #include <boost/graph/iteration_macros.hpp>
  28. #include <boost/shared_array.hpp>
  29. #include <boost/assert.hpp>
  30. namespace boost { namespace mpi {
  31. /**
  32. * @brief An MPI communicator with a graph topology.
  33. *
  34. * A @c graph_communicator is a communicator whose topology is
  35. * expressed as a graph. Graph communicators have the same
  36. * functionality as (intra)communicators, but also allow one to query
  37. * the relationships among processes. Those relationships are
  38. * expressed via a graph, using the interface defined by the Boost
  39. * Graph Library. The @c graph_communicator class meets the
  40. * requirements of the BGL Graph, Incidence Graph, Adjacency Graph,
  41. * Vertex List Graph, and Edge List Graph concepts.
  42. */
  43. class BOOST_MPI_DECL graph_communicator : public communicator
  44. {
  45. friend class communicator;
  46. /**
  47. * INTERNAL ONLY
  48. *
  49. * Construct a graph communicator given a shared pointer to the
  50. * underlying MPI_Comm. This operation is used for "casting" from a
  51. * communicator to a graph communicator.
  52. */
  53. explicit graph_communicator(const shared_ptr<MPI_Comm>& comm_ptr)
  54. {
  55. #ifndef BOOST_DISABLE_ASSERTS
  56. int status;
  57. BOOST_MPI_CHECK_RESULT(MPI_Topo_test, ((MPI_Comm)*this, &status));
  58. BOOST_ASSERT(status == MPI_GRAPH);
  59. #endif
  60. this->comm_ptr = comm_ptr;
  61. }
  62. public:
  63. /**
  64. * Build a new Boost.MPI graph communicator based on the MPI
  65. * communicator @p comm with graph topology.
  66. *
  67. * @p comm may be any valid MPI communicator. If @p comm is
  68. * MPI_COMM_NULL, an empty communicator (that cannot be used for
  69. * communication) is created and the @p kind parameter is
  70. * ignored. Otherwise, the @p kind parameter determines how the
  71. * Boost.MPI communicator will be related to @p comm:
  72. *
  73. * - If @p kind is @c comm_duplicate, duplicate @c comm to create
  74. * a new communicator. This new communicator will be freed when
  75. * the Boost.MPI communicator (and all copies of it) is
  76. * destroyed. This option is only permitted if the underlying MPI
  77. * implementation supports MPI 2.0; duplication of
  78. * intercommunicators is not available in MPI 1.x.
  79. *
  80. * - If @p kind is @c comm_take_ownership, take ownership of @c
  81. * comm. It will be freed automatically when all of the Boost.MPI
  82. * communicators go out of scope.
  83. *
  84. * - If @p kind is @c comm_attach, this Boost.MPI communicator
  85. * will reference the existing MPI communicator @p comm but will
  86. * not free @p comm when the Boost.MPI communicator goes out of
  87. * scope. This option should only be used when the communicator is
  88. * managed by the user.
  89. */
  90. graph_communicator(const MPI_Comm& comm, comm_create_kind kind)
  91. : communicator(comm, kind)
  92. {
  93. #ifndef BOOST_DISABLE_ASSERTS
  94. int status;
  95. BOOST_MPI_CHECK_RESULT(MPI_Topo_test, ((MPI_Comm)*this, &status));
  96. BOOST_ASSERT(status == MPI_GRAPH);
  97. #endif
  98. }
  99. /**
  100. * Create a new communicator whose topology is described by the
  101. * given graph. The indices of the vertices in the graph will be
  102. * assumed to be the ranks of the processes within the
  103. * communicator. There may be fewer vertices in the graph than
  104. * there are processes in the communicator; in this case, the
  105. * resulting communicator will be a NULL communicator.
  106. *
  107. * @param comm The communicator that the new, graph communicator
  108. * will be based on.
  109. *
  110. * @param graph Any type that meets the requirements of the
  111. * Incidence Graph and Vertex List Graph concepts from the Boost Graph
  112. * Library. This structure of this graph will become the topology
  113. * of the communicator that is returned.
  114. *
  115. * @param reorder Whether MPI is permitted to re-order the process
  116. * ranks within the returned communicator, to better optimize
  117. * communication. If false, the ranks of each process in the
  118. * returned process will match precisely the rank of that process
  119. * within the original communicator.
  120. */
  121. template<typename Graph>
  122. explicit
  123. graph_communicator(const communicator& comm, const Graph& graph,
  124. bool reorder = false);
  125. /**
  126. * Create a new communicator whose topology is described by the
  127. * given graph. The rank map (@p rank) gives the mapping from
  128. * vertices in the graph to ranks within the communicator. There
  129. * may be fewer vertices in the graph than there are processes in
  130. * the communicator; in this case, the resulting communicator will
  131. * be a NULL communicator.
  132. *
  133. * @param comm The communicator that the new, graph communicator
  134. * will be based on. The ranks in @c rank refer to the processes in
  135. * this communicator.
  136. *
  137. * @param graph Any type that meets the requirements of the
  138. * Incidence Graph and Vertex List Graph concepts from the Boost Graph
  139. * Library. This structure of this graph will become the topology
  140. * of the communicator that is returned.
  141. *
  142. * @param rank This map translates vertices in the @c graph into
  143. * ranks within the current communicator. It must be a Readable
  144. * Property Map (see the Boost Property Map library) whose key type
  145. * is the vertex type of the @p graph and whose value type is @c
  146. * int.
  147. *
  148. * @param reorder Whether MPI is permitted to re-order the process
  149. * ranks within the returned communicator, to better optimize
  150. * communication. If false, the ranks of each process in the
  151. * returned process will match precisely the rank of that process
  152. * within the original communicator.
  153. */
  154. template<typename Graph, typename RankMap>
  155. explicit
  156. graph_communicator(const communicator& comm, const Graph& graph,
  157. RankMap rank, bool reorder = false);
  158. protected:
  159. /**
  160. * INTERNAL ONLY
  161. *
  162. * Used by the constructors to create the new communicator with a
  163. * graph topology.
  164. */
  165. template<typename Graph, typename RankMap>
  166. void
  167. setup_graph(const communicator& comm, const Graph& graph, RankMap rank,
  168. bool reorder);
  169. };
  170. /****************************************************************************
  171. * Implementation Details *
  172. ****************************************************************************/
  173. template<typename Graph>
  174. graph_communicator::graph_communicator(const communicator& comm,
  175. const Graph& graph,
  176. bool reorder)
  177. {
  178. this->setup_graph(comm, graph, get(vertex_index, graph), reorder);
  179. }
  180. template<typename Graph, typename RankMap>
  181. graph_communicator::graph_communicator(const communicator& comm,
  182. const Graph& graph,
  183. RankMap rank, bool reorder)
  184. {
  185. this->setup_graph(comm, graph, rank, reorder);
  186. }
  187. template<typename Graph, typename RankMap>
  188. void
  189. graph_communicator::setup_graph(const communicator& comm, const Graph& graph,
  190. RankMap rank, bool reorder)
  191. {
  192. typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
  193. // Build a mapping from ranks to vertices
  194. std::vector<vertex_descriptor> vertex_with_rank(num_vertices(graph));
  195. if (vertex_with_rank.empty())
  196. return;
  197. BGL_FORALL_VERTICES_T(v, graph, Graph)
  198. vertex_with_rank[get(rank, v)] = v;
  199. // Build the representation of the graph required by
  200. // MPI_Graph_create.
  201. std::vector<int> indices(num_vertices(graph));
  202. std::vector<int> edges;
  203. int nvertices = indices.size();
  204. for (int vertex_index = 0; vertex_index < nvertices; ++vertex_index) {
  205. vertex_descriptor v = vertex_with_rank[vertex_index];
  206. BGL_FORALL_OUTEDGES_T(v, e, graph, Graph)
  207. edges.push_back(get(rank, target(e, graph)));
  208. indices[vertex_index] = edges.size();
  209. }
  210. // Create the new communicator
  211. MPI_Comm newcomm;
  212. BOOST_MPI_CHECK_RESULT(MPI_Graph_create,
  213. ((MPI_Comm)comm,
  214. nvertices,
  215. detail::c_data(indices),
  216. detail::c_data(edges),
  217. reorder,
  218. &newcomm));
  219. this->comm_ptr.reset(new MPI_Comm(newcomm), comm_free());
  220. }
  221. /****************************************************************************
  222. * Communicator with Graph Topology as BGL Graph *
  223. ****************************************************************************/
  224. namespace detail {
  225. /**
  226. * INTERNAL ONLY
  227. *
  228. * The iterator used to access the outgoing edges within a
  229. * communicator's graph topology.
  230. */
  231. class comm_out_edge_iterator
  232. : public iterator_facade<comm_out_edge_iterator,
  233. std::pair<int, int>,
  234. random_access_traversal_tag,
  235. const std::pair<int, int>&,
  236. int>
  237. {
  238. public:
  239. comm_out_edge_iterator() { }
  240. comm_out_edge_iterator(int source, shared_array<int> neighbors, int index)
  241. : edge(source, -1), neighbors(neighbors), index(index) { }
  242. protected:
  243. friend class boost::iterator_core_access;
  244. const std::pair<int, int>& dereference() const
  245. {
  246. edge.second = neighbors[index];
  247. return edge;
  248. }
  249. bool equal(const comm_out_edge_iterator& other) const
  250. {
  251. return (edge.first == other.edge.first
  252. && index == other.index);
  253. }
  254. void increment() { ++index; }
  255. void decrement() { --index; }
  256. void advance(int n) { index += n; }
  257. int distance_to(const comm_out_edge_iterator& other) const
  258. {
  259. return other.index - index;
  260. }
  261. mutable std::pair<int, int> edge;
  262. shared_array<int> neighbors;
  263. int index;
  264. };
  265. /**
  266. * INTERNAL ONLY
  267. *
  268. * The iterator used to access the adjacent vertices within a
  269. * communicator's graph topology.
  270. */
  271. class comm_adj_iterator
  272. : public iterator_facade<comm_adj_iterator,
  273. int,
  274. random_access_traversal_tag,
  275. int,
  276. int>
  277. {
  278. public:
  279. comm_adj_iterator() { }
  280. comm_adj_iterator(shared_array<int> neighbors, int index)
  281. : neighbors(neighbors), index(index) { }
  282. protected:
  283. friend class boost::iterator_core_access;
  284. int dereference() const { return neighbors[index]; }
  285. bool equal(const comm_adj_iterator& other) const
  286. {
  287. return (neighbors == other.neighbors
  288. && index == other.index);
  289. }
  290. void increment() { ++index; }
  291. void decrement() { --index; }
  292. void advance(int n) { index += n; }
  293. int distance_to(const comm_adj_iterator& other) const
  294. {
  295. return other.index - index;
  296. }
  297. shared_array<int> neighbors;
  298. int index;
  299. };
  300. /**
  301. * INTERNAL ONLY
  302. *
  303. * The iterator used to access the edges in a communicator's graph
  304. * topology.
  305. */
  306. class comm_edge_iterator
  307. : public iterator_facade<comm_edge_iterator,
  308. std::pair<int, int>,
  309. forward_traversal_tag,
  310. const std::pair<int, int>&,
  311. int>
  312. {
  313. public:
  314. comm_edge_iterator() { }
  315. /// Constructor for a past-the-end iterator
  316. comm_edge_iterator(int nedges) : edge_index(nedges) { }
  317. comm_edge_iterator(shared_array<int> indices, shared_array<int> edges)
  318. : indices(indices), edges(edges), edge_index(0), edge(0, 0)
  319. { }
  320. protected:
  321. friend class boost::iterator_core_access;
  322. const std::pair<int, int>& dereference() const
  323. {
  324. while (edge_index == indices[edge.first])
  325. ++edge.first;
  326. edge.second = edges[edge_index];
  327. return edge;
  328. }
  329. bool equal(const comm_edge_iterator& other) const
  330. {
  331. return edge_index == other.edge_index;
  332. }
  333. void increment()
  334. {
  335. ++edge_index;
  336. }
  337. shared_array<int> indices;
  338. shared_array<int> edges;
  339. int edge_index;
  340. mutable std::pair<int, int> edge;
  341. };
  342. } // end namespace detail
  343. // Incidence Graph requirements
  344. /**
  345. * @brief Returns the source vertex from an edge in the graph topology
  346. * of a communicator.
  347. */
  348. inline int source(const std::pair<int, int>& edge, const graph_communicator&)
  349. {
  350. return edge.first;
  351. }
  352. /**
  353. * @brief Returns the target vertex from an edge in the graph topology
  354. * of a communicator.
  355. */
  356. inline int target(const std::pair<int, int>& edge, const graph_communicator&)
  357. {
  358. return edge.second;
  359. }
  360. /**
  361. * @brief Returns an iterator range containing all of the edges
  362. * outgoing from the given vertex in a graph topology of a
  363. * communicator.
  364. */
  365. std::pair<detail::comm_out_edge_iterator, detail::comm_out_edge_iterator>
  366. out_edges(int vertex, const graph_communicator& comm);
  367. /**
  368. * @brief Returns the out-degree of a vertex in the graph topology of
  369. * a communicator.
  370. */
  371. int out_degree(int vertex, const graph_communicator& comm);
  372. // Adjacency Graph requirements
  373. /**
  374. * @brief Returns an iterator range containing all of the neighbors of
  375. * the given vertex in the communicator's graph topology.
  376. */
  377. std::pair<detail::comm_adj_iterator, detail::comm_adj_iterator>
  378. adjacent_vertices(int vertex, const graph_communicator& comm);
  379. // Vertex List Graph requirements
  380. /**
  381. * @brief Returns an iterator range that contains all of the vertices
  382. * with the communicator's graph topology, i.e., all of the process
  383. * ranks in the communicator.
  384. */
  385. inline std::pair<counting_iterator<int>, counting_iterator<int> >
  386. vertices(const graph_communicator& comm)
  387. {
  388. return std::make_pair(counting_iterator<int>(0),
  389. counting_iterator<int>(comm.size()));
  390. }
  391. /**
  392. * @brief Returns the number of vertices within the graph topology of
  393. * the communicator, i.e., the number of processes in the
  394. * communicator.
  395. */
  396. inline int num_vertices(const graph_communicator& comm) { return comm.size(); }
  397. // Edge List Graph requirements
  398. /**
  399. * @brief Returns an iterator range that contains all of the edges
  400. * with the communicator's graph topology.
  401. */
  402. std::pair<detail::comm_edge_iterator, detail::comm_edge_iterator>
  403. edges(const graph_communicator& comm);
  404. /**
  405. * @brief Returns the number of edges in the communicator's graph
  406. * topology.
  407. */
  408. int num_edges(const graph_communicator& comm);
  409. // Property Graph requirements
  410. /**
  411. * @brief Returns a property map that maps from vertices in a
  412. * communicator's graph topology to their index values.
  413. *
  414. * Since the vertices are ranks in the communicator, the returned
  415. * property map is the identity property map.
  416. */
  417. inline identity_property_map get(vertex_index_t, const graph_communicator&)
  418. {
  419. return identity_property_map();
  420. }
  421. /**
  422. * @brief Returns the index of a vertex in the communicator's graph
  423. * topology.
  424. *
  425. * Since the vertices are ranks in the communicator, this is the
  426. * identity function.
  427. */
  428. inline int get(vertex_index_t, const graph_communicator&, int vertex)
  429. {
  430. return vertex;
  431. }
  432. } } // end namespace boost::mpi
  433. namespace boost {
  434. /**
  435. * @brief Traits structure that allows a communicator with graph
  436. * topology to be view as a graph by the Boost Graph Library.
  437. *
  438. * The specialization of @c graph_traits for an MPI communicator
  439. * allows a communicator with graph topology to be viewed as a
  440. * graph. An MPI communicator with graph topology meets the
  441. * requirements of the Graph, Incidence Graph, Adjacency Graph, Vertex
  442. * List Graph, and Edge List Graph concepts from the Boost Graph
  443. * Library.
  444. */
  445. template<>
  446. struct graph_traits<mpi::graph_communicator> {
  447. // Graph concept requirements
  448. typedef int vertex_descriptor;
  449. typedef std::pair<int, int> edge_descriptor;
  450. typedef directed_tag directed_category;
  451. typedef disallow_parallel_edge_tag edge_parallel_category;
  452. /**
  453. * INTERNAL ONLY
  454. */
  455. struct traversal_category
  456. : incidence_graph_tag,
  457. adjacency_graph_tag,
  458. vertex_list_graph_tag,
  459. edge_list_graph_tag
  460. {
  461. };
  462. /**
  463. * @brief Returns a vertex descriptor that can never refer to any
  464. * valid vertex.
  465. */
  466. static vertex_descriptor null_vertex() { return -1; }
  467. // Incidence Graph requirements
  468. typedef mpi::detail::comm_out_edge_iterator out_edge_iterator;
  469. typedef int degree_size_type;
  470. // Adjacency Graph requirements
  471. typedef mpi::detail::comm_adj_iterator adjacency_iterator;
  472. // Vertex List Graph requirements
  473. typedef counting_iterator<int> vertex_iterator;
  474. typedef int vertices_size_type;
  475. // Edge List Graph requirements
  476. typedef mpi::detail::comm_edge_iterator edge_iterator;
  477. typedef int edges_size_type;
  478. };
  479. // Property Graph requirements
  480. /**
  481. * INTERNAL ONLY
  482. */
  483. template<>
  484. struct property_map<mpi::graph_communicator, vertex_index_t>
  485. {
  486. typedef identity_property_map type;
  487. typedef identity_property_map const_type;
  488. };
  489. } // end namespace boost
  490. #endif // BOOST_MPI_GRAPH_COMMUNICATOR_HPP