operations.hpp 9.6 KB

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