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