Chris@16
|
1 // Copyright (C) 2004 The Trustees of Indiana University.
|
Chris@16
|
2 // Copyright (C) 2005-2006 Douglas Gregor <doug.gregor -at- gmail.com>
|
Chris@16
|
3
|
Chris@16
|
4 // Use, modification and distribution is subject to the Boost Software
|
Chris@16
|
5 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
Chris@16
|
6 // http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
7
|
Chris@16
|
8 // Authors: Douglas Gregor
|
Chris@16
|
9 // Andrew Lumsdaine
|
Chris@16
|
10
|
Chris@16
|
11 /** @file operations.hpp
|
Chris@16
|
12 *
|
Chris@16
|
13 * This header provides a mapping from function objects to @c MPI_Op
|
Chris@16
|
14 * constants used in MPI collective operations. It also provides
|
Chris@16
|
15 * several new function object types not present in the standard @c
|
Chris@16
|
16 * <functional> header that have direct mappings to @c MPI_Op.
|
Chris@16
|
17 */
|
Chris@16
|
18 #ifndef BOOST_MPI_IS_MPI_OP_HPP
|
Chris@16
|
19 #define BOOST_MPI_IS_MPI_OP_HPP
|
Chris@16
|
20
|
Chris@16
|
21 #include <boost/mpi/config.hpp>
|
Chris@16
|
22 #include <boost/mpl/bool.hpp>
|
Chris@16
|
23 #include <boost/mpl/if.hpp>
|
Chris@16
|
24 #include <boost/mpl/and.hpp>
|
Chris@16
|
25 #include <boost/mpi/datatype.hpp>
|
Chris@16
|
26 #include <boost/utility/enable_if.hpp>
|
Chris@16
|
27 #include <functional>
|
Chris@16
|
28
|
Chris@16
|
29 namespace boost { namespace mpi {
|
Chris@16
|
30
|
Chris@16
|
31 template<typename Op, typename T> struct is_mpi_op;
|
Chris@16
|
32
|
Chris@16
|
33 /**
|
Chris@16
|
34 * @brief Determine if a function object type is commutative.
|
Chris@16
|
35 *
|
Chris@16
|
36 * This trait determines if an operation @c Op is commutative when
|
Chris@16
|
37 * applied to values of type @c T. Parallel operations such as @c
|
Chris@16
|
38 * reduce and @c prefix_sum can be implemented more efficiently with
|
Chris@16
|
39 * commutative operations. To mark an operation as commutative, users
|
Chris@16
|
40 * should specialize @c is_commutative and derive from the class @c
|
Chris@16
|
41 * mpl::true_.
|
Chris@16
|
42 */
|
Chris@16
|
43 template<typename Op, typename T>
|
Chris@16
|
44 struct is_commutative : public mpl::false_ { };
|
Chris@16
|
45
|
Chris@16
|
46 /**************************************************************************
|
Chris@16
|
47 * Function objects for MPI operations not in <functional> header *
|
Chris@16
|
48 **************************************************************************/
|
Chris@16
|
49
|
Chris@16
|
50 /**
|
Chris@16
|
51 * @brief Compute the maximum of two values.
|
Chris@16
|
52 *
|
Chris@16
|
53 * This binary function object computes the maximum of the two values
|
Chris@16
|
54 * it is given. When used with MPI and a type @c T that has an
|
Chris@16
|
55 * associated, built-in MPI data type, translates to @c MPI_MAX.
|
Chris@16
|
56 */
|
Chris@16
|
57 template<typename T>
|
Chris@16
|
58 struct maximum : public std::binary_function<T, T, T>
|
Chris@16
|
59 {
|
Chris@16
|
60 /** @returns the maximum of x and y. */
|
Chris@16
|
61 const T& operator()(const T& x, const T& y) const
|
Chris@16
|
62 {
|
Chris@16
|
63 return x < y? y : x;
|
Chris@16
|
64 }
|
Chris@16
|
65 };
|
Chris@16
|
66
|
Chris@16
|
67 /**
|
Chris@16
|
68 * @brief Compute the minimum of two values.
|
Chris@16
|
69 *
|
Chris@16
|
70 * This binary function object computes the minimum of the two values
|
Chris@16
|
71 * it is given. When used with MPI and a type @c T that has an
|
Chris@16
|
72 * associated, built-in MPI data type, translates to @c MPI_MIN.
|
Chris@16
|
73 */
|
Chris@16
|
74 template<typename T>
|
Chris@16
|
75 struct minimum : public std::binary_function<T, T, T>
|
Chris@16
|
76 {
|
Chris@16
|
77 /** @returns the minimum of x and y. */
|
Chris@16
|
78 const T& operator()(const T& x, const T& y) const
|
Chris@16
|
79 {
|
Chris@16
|
80 return x < y? x : y;
|
Chris@16
|
81 }
|
Chris@16
|
82 };
|
Chris@16
|
83
|
Chris@16
|
84
|
Chris@16
|
85 /**
|
Chris@16
|
86 * @brief Compute the bitwise AND of two integral values.
|
Chris@16
|
87 *
|
Chris@16
|
88 * This binary function object computes the bitwise AND of the two
|
Chris@16
|
89 * values it is given. When used with MPI and a type @c T that has an
|
Chris@16
|
90 * associated, built-in MPI data type, translates to @c MPI_BAND.
|
Chris@16
|
91 */
|
Chris@16
|
92 template<typename T>
|
Chris@16
|
93 struct bitwise_and : public std::binary_function<T, T, T>
|
Chris@16
|
94 {
|
Chris@16
|
95 /** @returns @c x & y. */
|
Chris@16
|
96 T operator()(const T& x, const T& y) const
|
Chris@16
|
97 {
|
Chris@16
|
98 return x & y;
|
Chris@16
|
99 }
|
Chris@16
|
100 };
|
Chris@16
|
101
|
Chris@16
|
102 /**
|
Chris@16
|
103 * @brief Compute the bitwise OR of two integral values.
|
Chris@16
|
104 *
|
Chris@16
|
105 * This binary function object computes the bitwise OR of the two
|
Chris@16
|
106 * values it is given. When used with MPI and a type @c T that has an
|
Chris@16
|
107 * associated, built-in MPI data type, translates to @c MPI_BOR.
|
Chris@16
|
108 */
|
Chris@16
|
109 template<typename T>
|
Chris@16
|
110 struct bitwise_or : public std::binary_function<T, T, T>
|
Chris@16
|
111 {
|
Chris@16
|
112 /** @returns the @c x | y. */
|
Chris@16
|
113 T operator()(const T& x, const T& y) const
|
Chris@16
|
114 {
|
Chris@16
|
115 return x | y;
|
Chris@16
|
116 }
|
Chris@16
|
117 };
|
Chris@16
|
118
|
Chris@16
|
119 /**
|
Chris@16
|
120 * @brief Compute the logical exclusive OR of two integral values.
|
Chris@16
|
121 *
|
Chris@16
|
122 * This binary function object computes the logical exclusive of the
|
Chris@16
|
123 * two values it is given. When used with MPI and a type @c T that has
|
Chris@16
|
124 * an associated, built-in MPI data type, translates to @c MPI_LXOR.
|
Chris@16
|
125 */
|
Chris@16
|
126 template<typename T>
|
Chris@16
|
127 struct logical_xor : public std::binary_function<T, T, T>
|
Chris@16
|
128 {
|
Chris@16
|
129 /** @returns the logical exclusive OR of x and y. */
|
Chris@16
|
130 T operator()(const T& x, const T& y) const
|
Chris@16
|
131 {
|
Chris@16
|
132 return (x || y) && !(x && y);
|
Chris@16
|
133 }
|
Chris@16
|
134 };
|
Chris@16
|
135
|
Chris@16
|
136 /**
|
Chris@16
|
137 * @brief Compute the bitwise exclusive OR of two integral values.
|
Chris@16
|
138 *
|
Chris@16
|
139 * This binary function object computes the bitwise exclusive OR of
|
Chris@16
|
140 * the two values it is given. When used with MPI and a type @c T that
|
Chris@16
|
141 * has an associated, built-in MPI data type, translates to @c
|
Chris@16
|
142 * MPI_BXOR.
|
Chris@16
|
143 */
|
Chris@16
|
144 template<typename T>
|
Chris@16
|
145 struct bitwise_xor : public std::binary_function<T, T, T>
|
Chris@16
|
146 {
|
Chris@16
|
147 /** @returns @c x ^ y. */
|
Chris@16
|
148 T operator()(const T& x, const T& y) const
|
Chris@16
|
149 {
|
Chris@16
|
150 return x ^ y;
|
Chris@16
|
151 }
|
Chris@16
|
152 };
|
Chris@16
|
153
|
Chris@16
|
154 /**************************************************************************
|
Chris@16
|
155 * MPI_Op queries *
|
Chris@16
|
156 **************************************************************************/
|
Chris@16
|
157
|
Chris@16
|
158 /**
|
Chris@16
|
159 * @brief Determine if a function object has an associated @c MPI_Op.
|
Chris@16
|
160 *
|
Chris@16
|
161 * This trait determines if a function object type @c Op, when used
|
Chris@16
|
162 * with argument type @c T, has an associated @c MPI_Op. If so, @c
|
Chris@16
|
163 * is_mpi_op<Op,T> will derive from @c mpl::false_ and will
|
Chris@16
|
164 * contain a static member function @c op that takes no arguments but
|
Chris@16
|
165 * returns the associated @c MPI_Op value. For instance, @c
|
Chris@16
|
166 * is_mpi_op<std::plus<int>,int>::op() returns @c MPI_SUM.
|
Chris@16
|
167 *
|
Chris@16
|
168 * Users may specialize @c is_mpi_op for any other class templates
|
Chris@16
|
169 * that map onto operations that have @c MPI_Op equivalences, such as
|
Chris@16
|
170 * bitwise OR, logical and, or maximum. However, users are encouraged
|
Chris@16
|
171 * to use the standard function objects in the @c functional and @c
|
Chris@16
|
172 * boost/mpi/operations.hpp headers whenever possible. For
|
Chris@16
|
173 * function objects that are class templates with a single template
|
Chris@16
|
174 * parameter, it may be easier to specialize @c is_builtin_mpi_op.
|
Chris@16
|
175 */
|
Chris@16
|
176 template<typename Op, typename T>
|
Chris@16
|
177 struct is_mpi_op : public mpl::false_ { };
|
Chris@16
|
178
|
Chris@16
|
179 /// INTERNAL ONLY
|
Chris@16
|
180 template<typename T>
|
Chris@16
|
181 struct is_mpi_op<maximum<T>, T>
|
Chris@16
|
182 : public boost::mpl::or_<is_mpi_integer_datatype<T>,
|
Chris@16
|
183 is_mpi_floating_point_datatype<T> >
|
Chris@16
|
184 {
|
Chris@16
|
185 static MPI_Op op() { return MPI_MAX; }
|
Chris@16
|
186 };
|
Chris@16
|
187
|
Chris@16
|
188 /// INTERNAL ONLY
|
Chris@16
|
189 template<typename T>
|
Chris@16
|
190 struct is_mpi_op<minimum<T>, T>
|
Chris@16
|
191 : public boost::mpl::or_<is_mpi_integer_datatype<T>,
|
Chris@16
|
192 is_mpi_floating_point_datatype<T> >
|
Chris@16
|
193 {
|
Chris@16
|
194 static MPI_Op op() { return MPI_MIN; }
|
Chris@16
|
195 };
|
Chris@16
|
196
|
Chris@16
|
197 /// INTERNAL ONLY
|
Chris@16
|
198 template<typename T>
|
Chris@16
|
199 struct is_mpi_op<std::plus<T>, T>
|
Chris@16
|
200 : public boost::mpl::or_<is_mpi_integer_datatype<T>,
|
Chris@16
|
201 is_mpi_floating_point_datatype<T>,
|
Chris@16
|
202 is_mpi_complex_datatype<T> >
|
Chris@16
|
203 {
|
Chris@16
|
204 static MPI_Op op() { return MPI_SUM; }
|
Chris@16
|
205 };
|
Chris@16
|
206
|
Chris@16
|
207 /// INTERNAL ONLY
|
Chris@16
|
208 template<typename T>
|
Chris@16
|
209 struct is_mpi_op<std::multiplies<T>, T>
|
Chris@16
|
210 : public boost::mpl::or_<is_mpi_integer_datatype<T>,
|
Chris@16
|
211 is_mpi_floating_point_datatype<T>,
|
Chris@16
|
212 is_mpi_complex_datatype<T> >
|
Chris@16
|
213 {
|
Chris@16
|
214 static MPI_Op op() { return MPI_PROD; }
|
Chris@16
|
215 };
|
Chris@16
|
216
|
Chris@16
|
217 /// INTERNAL ONLY
|
Chris@16
|
218 template<typename T>
|
Chris@16
|
219 struct is_mpi_op<std::logical_and<T>, T>
|
Chris@16
|
220 : public boost::mpl::or_<is_mpi_integer_datatype<T>,
|
Chris@16
|
221 is_mpi_logical_datatype<T> >
|
Chris@16
|
222 {
|
Chris@16
|
223 static MPI_Op op() { return MPI_LAND; }
|
Chris@16
|
224 };
|
Chris@16
|
225
|
Chris@16
|
226 /// INTERNAL ONLY
|
Chris@16
|
227 template<typename T>
|
Chris@16
|
228 struct is_mpi_op<std::logical_or<T>, T>
|
Chris@16
|
229 : public boost::mpl::or_<is_mpi_integer_datatype<T>,
|
Chris@16
|
230 is_mpi_logical_datatype<T> >
|
Chris@16
|
231 {
|
Chris@16
|
232 static MPI_Op op() { return MPI_LOR; }
|
Chris@16
|
233 };
|
Chris@16
|
234
|
Chris@16
|
235 /// INTERNAL ONLY
|
Chris@16
|
236 template<typename T>
|
Chris@16
|
237 struct is_mpi_op<logical_xor<T>, T>
|
Chris@16
|
238 : public boost::mpl::or_<is_mpi_integer_datatype<T>,
|
Chris@16
|
239 is_mpi_logical_datatype<T> >
|
Chris@16
|
240 {
|
Chris@16
|
241 static MPI_Op op() { return MPI_LXOR; }
|
Chris@16
|
242 };
|
Chris@16
|
243
|
Chris@16
|
244 /// INTERNAL ONLY
|
Chris@16
|
245 template<typename T>
|
Chris@16
|
246 struct is_mpi_op<bitwise_and<T>, T>
|
Chris@16
|
247 : public boost::mpl::or_<is_mpi_integer_datatype<T>,
|
Chris@16
|
248 is_mpi_byte_datatype<T> >
|
Chris@16
|
249 {
|
Chris@16
|
250 static MPI_Op op() { return MPI_BAND; }
|
Chris@16
|
251 };
|
Chris@16
|
252
|
Chris@16
|
253 /// INTERNAL ONLY
|
Chris@16
|
254 template<typename T>
|
Chris@16
|
255 struct is_mpi_op<bitwise_or<T>, T>
|
Chris@16
|
256 : public boost::mpl::or_<is_mpi_integer_datatype<T>,
|
Chris@16
|
257 is_mpi_byte_datatype<T> >
|
Chris@16
|
258 {
|
Chris@16
|
259 static MPI_Op op() { return MPI_BOR; }
|
Chris@16
|
260 };
|
Chris@16
|
261
|
Chris@16
|
262 /// INTERNAL ONLY
|
Chris@16
|
263 template<typename T>
|
Chris@16
|
264 struct is_mpi_op<bitwise_xor<T>, T>
|
Chris@16
|
265 : public boost::mpl::or_<is_mpi_integer_datatype<T>,
|
Chris@16
|
266 is_mpi_byte_datatype<T> >
|
Chris@16
|
267 {
|
Chris@16
|
268 static MPI_Op op() { return MPI_BXOR; }
|
Chris@16
|
269 };
|
Chris@16
|
270
|
Chris@16
|
271 namespace detail {
|
Chris@16
|
272 // A helper class used to create user-defined MPI_Ops
|
Chris@16
|
273 template<typename Op, typename T>
|
Chris@16
|
274 class user_op
|
Chris@16
|
275 {
|
Chris@16
|
276 public:
|
Chris@16
|
277 explicit user_op(Op& op)
|
Chris@16
|
278 {
|
Chris@16
|
279 BOOST_MPI_CHECK_RESULT(MPI_Op_create,
|
Chris@16
|
280 (&user_op<Op, T>::perform,
|
Chris@16
|
281 is_commutative<Op, T>::value,
|
Chris@16
|
282 &mpi_op));
|
Chris@16
|
283
|
Chris@16
|
284 op_ptr = &op;
|
Chris@16
|
285 }
|
Chris@16
|
286
|
Chris@16
|
287 ~user_op()
|
Chris@16
|
288 {
|
Chris@16
|
289 if (std::uncaught_exception()) {
|
Chris@16
|
290 // Ignore failure cases: there are obviously other problems
|
Chris@16
|
291 // already, and we don't want to cause program termination if
|
Chris@16
|
292 // MPI_Op_free fails.
|
Chris@16
|
293 MPI_Op_free(&mpi_op);
|
Chris@16
|
294 } else {
|
Chris@16
|
295 BOOST_MPI_CHECK_RESULT(MPI_Op_free, (&mpi_op));
|
Chris@16
|
296 }
|
Chris@16
|
297 }
|
Chris@16
|
298
|
Chris@16
|
299 MPI_Op& get_mpi_op()
|
Chris@16
|
300 {
|
Chris@16
|
301 return mpi_op;
|
Chris@16
|
302 }
|
Chris@16
|
303
|
Chris@16
|
304 private:
|
Chris@16
|
305 MPI_Op mpi_op;
|
Chris@16
|
306 static Op* op_ptr;
|
Chris@16
|
307
|
Chris@16
|
308 static void BOOST_MPI_CALLING_CONVENTION perform(void* vinvec, void* voutvec, int* plen, MPI_Datatype*)
|
Chris@16
|
309 {
|
Chris@16
|
310 T* invec = static_cast<T*>(vinvec);
|
Chris@16
|
311 T* outvec = static_cast<T*>(voutvec);
|
Chris@16
|
312 std::transform(invec, invec + *plen, outvec, outvec, *op_ptr);
|
Chris@16
|
313 }
|
Chris@16
|
314 };
|
Chris@16
|
315
|
Chris@16
|
316 template<typename Op, typename T> Op* user_op<Op, T>::op_ptr = 0;
|
Chris@16
|
317
|
Chris@16
|
318 } // end namespace detail
|
Chris@16
|
319
|
Chris@16
|
320 } } // end namespace boost::mpi
|
Chris@16
|
321
|
Chris@16
|
322 #endif // BOOST_MPI_GET_MPI_OP_HPP
|