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