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