group.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  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 group.hpp
  8. *
  9. * This header defines the @c group class, which allows one to
  10. * manipulate and query groups of processes.
  11. */
  12. #ifndef BOOST_MPI_GROUP_HPP
  13. #define BOOST_MPI_GROUP_HPP
  14. #include <boost/mpi/exception.hpp>
  15. #include <boost/shared_ptr.hpp>
  16. #include <boost/optional.hpp>
  17. #include <vector>
  18. namespace boost { namespace mpi {
  19. /**
  20. * @brief A @c group is a representation of a subset of the processes
  21. * within a @c communicator.
  22. *
  23. * The @c group class allows one to create arbitrary subsets of the
  24. * processes within a communicator. One can compute the union,
  25. * intersection, or difference of two groups, or create new groups by
  26. * specifically including or excluding certain processes. Given a
  27. * group, one can create a new communicator containing only the
  28. * processes in that group.
  29. */
  30. class BOOST_MPI_DECL group
  31. {
  32. public:
  33. /**
  34. * @brief Constructs an empty group.
  35. */
  36. group() : group_ptr() { }
  37. /**
  38. * @brief Constructs a group from an @c MPI_Group.
  39. *
  40. * This routine allows one to construct a Boost.MPI @c group from a
  41. * C @c MPI_Group. The @c group object can (optionally) adopt the @c
  42. * MPI_Group, after which point the @c group object becomes
  43. * responsible for freeing the @c MPI_Group when the last copy of @c
  44. * group disappears.
  45. *
  46. * @param in_group The @c MPI_Group used to construct this @c group.
  47. *
  48. * @param adopt Whether the @c group should adopt the @c
  49. * MPI_Group. When true, the @c group object (or one of its copies)
  50. * will free the group (via @c MPI_Comm_free) when the last copy is
  51. * destroyed. Otherwise, the user is responsible for calling @c
  52. * MPI_Group_free.
  53. */
  54. group(const MPI_Group& in_group, bool adopt);
  55. /**
  56. * @brief Determine the rank of the calling process in the group.
  57. *
  58. * This routine is equivalent to @c MPI_Group_rank.
  59. *
  60. * @returns The rank of the calling process in the group, which will
  61. * be a value in [0, size()). If the calling process is not in the
  62. * group, returns an empty value.
  63. */
  64. optional<int> rank() const;
  65. /**
  66. * @brief Determine the number of processes in the group.
  67. *
  68. * This routine is equivalent to @c MPI_Group_size.
  69. *
  70. * @returns The number of processes in the group.
  71. */
  72. int size() const;
  73. /**
  74. * @brief Translates the ranks from one group into the ranks of the
  75. * same processes in another group.
  76. *
  77. * This routine translates each of the integer rank values in the
  78. * iterator range @c [first, last) from the current group into rank
  79. * values of the corresponding processes in @p to_group. The
  80. * corresponding rank values are written via the output iterator @c
  81. * out. When there is no correspondence between a rank in the
  82. * current group and a rank in @c to_group, the value @c
  83. * MPI_UNDEFINED is written to the output iterator.
  84. *
  85. * @param first Beginning of the iterator range of ranks in the
  86. * current group.
  87. *
  88. * @param last Past the end of the iterator range of ranks in the
  89. * current group.
  90. *
  91. * @param to_group The group that we are translating ranks to.
  92. *
  93. * @param out The output iterator to which the translated ranks will
  94. * be written.
  95. *
  96. * @returns the output iterator, which points one step past the last
  97. * rank written.
  98. */
  99. template<typename InputIterator, typename OutputIterator>
  100. OutputIterator translate_ranks(InputIterator first, InputIterator last,
  101. const group& to_group, OutputIterator out);
  102. /**
  103. * @brief Determines whether the group is non-empty.
  104. *
  105. * @returns True if the group is not empty, false if it is empty.
  106. */
  107. operator bool() const { return (bool)group_ptr; }
  108. /**
  109. * @brief Retrieves the underlying @c MPI_Group associated with this
  110. * group.
  111. *
  112. * @returns The @c MPI_Group handle manipulated by this object. If
  113. * this object represents the empty group, returns @c
  114. * MPI_GROUP_EMPTY.
  115. */
  116. operator MPI_Group() const
  117. {
  118. if (group_ptr)
  119. return *group_ptr;
  120. else
  121. return MPI_GROUP_EMPTY;
  122. }
  123. /**
  124. * @brief Creates a new group including a subset of the processes
  125. * in the current group.
  126. *
  127. * This routine creates a new @c group which includes only those
  128. * processes in the current group that are listed in the integer
  129. * iterator range @c [first, last). Equivalent to @c
  130. * MPI_Group_incl.
  131. *
  132. * @c first The beginning of the iterator range of ranks to include.
  133. *
  134. * @c last Past the end of the iterator range of ranks to include.
  135. *
  136. * @returns A new group containing those processes with ranks @c
  137. * [first, last) in the current group.
  138. */
  139. template<typename InputIterator>
  140. group include(InputIterator first, InputIterator last);
  141. /**
  142. * @brief Creates a new group from all of the processes in the
  143. * current group, exluding a specific subset of the processes.
  144. *
  145. * This routine creates a new @c group which includes all of the
  146. * processes in the current group except those whose ranks are
  147. * listed in the integer iterator range @c [first,
  148. * last). Equivalent to @c MPI_Group_excl.
  149. *
  150. * @c first The beginning of the iterator range of ranks to exclude.
  151. *
  152. * @c last Past the end of the iterator range of ranks to exclude.
  153. *
  154. * @returns A new group containing all of the processes in the
  155. * current group except those processes with ranks @c [first, last)
  156. * in the current group.
  157. */
  158. template<typename InputIterator>
  159. group exclude(InputIterator first, InputIterator last);
  160. protected:
  161. /**
  162. * INTERNAL ONLY
  163. *
  164. * Function object that frees an MPI group and deletes the
  165. * memory associated with it. Intended to be used as a deleter with
  166. * shared_ptr.
  167. */
  168. struct group_free
  169. {
  170. void operator()(MPI_Group* comm) const
  171. {
  172. int finalized;
  173. BOOST_MPI_CHECK_RESULT(MPI_Finalized, (&finalized));
  174. if (!finalized)
  175. BOOST_MPI_CHECK_RESULT(MPI_Group_free, (comm));
  176. delete comm;
  177. }
  178. };
  179. /**
  180. * The underlying MPI group. This is a shared pointer, so the actual
  181. * MPI group which will be shared among all related instances of the
  182. * @c group class. When there are no more such instances, the group
  183. * will be automatically freed.
  184. */
  185. shared_ptr<MPI_Group> group_ptr;
  186. };
  187. /**
  188. * @brief Determines whether two process groups are identical.
  189. *
  190. * Equivalent to calling @c MPI_Group_compare and checking whether the
  191. * result is @c MPI_IDENT.
  192. *
  193. * @returns True when the two process groups contain the same
  194. * processes in the same order.
  195. */
  196. BOOST_MPI_DECL bool operator==(const group& g1, const group& g2);
  197. /**
  198. * @brief Determines whether two process groups are not identical.
  199. *
  200. * Equivalent to calling @c MPI_Group_compare and checking whether the
  201. * result is not @c MPI_IDENT.
  202. *
  203. * @returns False when the two process groups contain the same
  204. * processes in the same order.
  205. */
  206. inline bool operator!=(const group& g1, const group& g2)
  207. {
  208. return !(g1 == g2);
  209. }
  210. /**
  211. * @brief Computes the union of two process groups.
  212. *
  213. * This routine returns a new @c group that contains all processes
  214. * that are either in group @c g1 or in group @c g2 (or both). The
  215. * processes that are in @c g1 will be first in the resulting group,
  216. * followed by the processes from @c g2 (but not also in @c
  217. * g1). Equivalent to @c MPI_Group_union.
  218. */
  219. BOOST_MPI_DECL group operator|(const group& g1, const group& g2);
  220. /**
  221. * @brief Computes the intersection of two process groups.
  222. *
  223. * This routine returns a new @c group that contains all processes
  224. * that are in group @c g1 and in group @c g2, ordered in the same way
  225. * as @c g1. Equivalent to @c MPI_Group_intersection.
  226. */
  227. BOOST_MPI_DECL group operator&(const group& g1, const group& g2);
  228. /**
  229. * @brief Computes the difference between two process groups.
  230. *
  231. * This routine returns a new @c group that contains all processes
  232. * that are in group @c g1 but not in group @c g2, ordered in the same way
  233. * as @c g1. Equivalent to @c MPI_Group_difference.
  234. */
  235. BOOST_MPI_DECL group operator-(const group& g1, const group& g2);
  236. /************************************************************************
  237. * Implementation details *
  238. ************************************************************************/
  239. template<typename InputIterator, typename OutputIterator>
  240. OutputIterator
  241. group::translate_ranks(InputIterator first, InputIterator last,
  242. const group& to_group, OutputIterator out)
  243. {
  244. std::vector<int> in_array(first, last);
  245. if (in_array.empty())
  246. return out;
  247. std::vector<int> out_array(in_array.size());
  248. BOOST_MPI_CHECK_RESULT(MPI_Group_translate_ranks,
  249. ((MPI_Group)*this,
  250. in_array.size(),
  251. &in_array[0],
  252. (MPI_Group)to_group,
  253. &out_array[0]));
  254. for (std::vector<int>::size_type i = 0, n = out_array.size(); i < n; ++i)
  255. *out++ = out_array[i];
  256. return out;
  257. }
  258. /**
  259. * INTERNAL ONLY
  260. *
  261. * Specialization of translate_ranks that handles the one case where
  262. * we can avoid any memory allocation or copying.
  263. */
  264. template<>
  265. BOOST_MPI_DECL int*
  266. group::translate_ranks(int* first, int* last, const group& to_group, int* out);
  267. template<typename InputIterator>
  268. group group::include(InputIterator first, InputIterator last)
  269. {
  270. if (first == last)
  271. return group();
  272. std::vector<int> ranks(first, last);
  273. MPI_Group result;
  274. BOOST_MPI_CHECK_RESULT(MPI_Group_incl,
  275. ((MPI_Group)*this, ranks.size(), &ranks[0], &result));
  276. return group(result, /*adopt=*/true);
  277. }
  278. /**
  279. * INTERNAL ONLY
  280. *
  281. * Specialization of group::include that handles the one case where we
  282. * can avoid any memory allocation or copying before creating the
  283. * group.
  284. */
  285. template<> BOOST_MPI_DECL group group::include(int* first, int* last);
  286. template<typename InputIterator>
  287. group group::exclude(InputIterator first, InputIterator last)
  288. {
  289. if (first == last)
  290. return group();
  291. std::vector<int> ranks(first, last);
  292. MPI_Group result;
  293. BOOST_MPI_CHECK_RESULT(MPI_Group_excl,
  294. ((MPI_Group)*this, ranks.size(), &ranks[0], &result));
  295. return group(result, /*adopt=*/true);
  296. }
  297. /**
  298. * INTERNAL ONLY
  299. *
  300. * Specialization of group::exclude that handles the one case where we
  301. * can avoid any memory allocation or copying before creating the
  302. * group.
  303. */
  304. template<> BOOST_MPI_DECL group group::exclude(int* first, int* last);
  305. } } // end namespace boost::mpi
  306. #endif // BOOST_MPI_GROUP_HPP