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