Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-30 09:46:55

0001 // Copyright (C) 2004 The Trustees of Indiana University.
0002 // Copyright (C) 2005-2006 Douglas Gregor <doug.gregor -at- gmail.com>
0003 
0004 // Use, modification and distribution is subject to the Boost Software
0005 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
0006 // http://www.boost.org/LICENSE_1_0.txt)
0007 
0008 //  Authors: Douglas Gregor
0009 //           Andrew Lumsdaine
0010 
0011 /** @file operations.hpp
0012  *
0013  *  This header provides a mapping from function objects to @c MPI_Op
0014  *  constants used in MPI collective operations. It also provides
0015  *  several new function object types not present in the standard @c
0016  *  <functional> header that have direct mappings to @c MPI_Op.
0017  */
0018 #ifndef BOOST_MPI_IS_MPI_OP_HPP
0019 #define BOOST_MPI_IS_MPI_OP_HPP
0020 
0021 #include <boost/mpi/config.hpp>
0022 #include <boost/mpl/bool.hpp>
0023 #include <boost/mpl/if.hpp>
0024 #include <boost/mpl/and.hpp>
0025 #include <boost/mpi/datatype.hpp>
0026 #include <boost/core/enable_if.hpp>
0027 #include <boost/core/uncaught_exceptions.hpp>
0028 #include <functional>
0029 
0030 namespace boost { namespace mpi {
0031 
0032 template<typename Op, typename T> struct is_mpi_op;
0033 
0034 /**
0035  * @brief Determine if a function object type is commutative.
0036  *
0037  * This trait determines if an operation @c Op is commutative when
0038  * applied to values of type @c T. Parallel operations such as @c
0039  * reduce and @c prefix_sum can be implemented more efficiently with
0040  * commutative operations. To mark an operation as commutative, users
0041  * should specialize @c is_commutative and derive from the class @c
0042  * mpl::true_.
0043  */
0044 template<typename Op, typename T>
0045 struct is_commutative : public mpl::false_ { };
0046 
0047 /**************************************************************************
0048  * Function objects for MPI operations not in <functional> header         *
0049  **************************************************************************/
0050 
0051 /**
0052  *  @brief Compute the maximum of two values.
0053  *
0054  *  This binary function object computes the maximum of the two values
0055  *  it is given. When used with MPI and a type @c T that has an
0056  *  associated, built-in MPI data type, translates to @c MPI_MAX.
0057  */
0058 template<typename T>
0059 struct maximum
0060 {
0061   typedef T first_argument_type;
0062   typedef T second_argument_type;
0063   typedef T result_type;
0064   /** @returns the maximum of x and y. */
0065   const T& operator()(const T& x, const T& y) const
0066   {
0067     return x < y? y : x;
0068   }
0069 };
0070 
0071 /**
0072  *  @brief Compute the minimum of two values.
0073  *
0074  *  This binary function object computes the minimum of the two values
0075  *  it is given. When used with MPI and a type @c T that has an
0076  *  associated, built-in MPI data type, translates to @c MPI_MIN.
0077  */
0078 template<typename T>
0079 struct minimum
0080 {
0081   typedef T first_argument_type;
0082   typedef T second_argument_type;
0083   typedef T result_type;
0084   /** @returns the minimum of x and y. */
0085   const T& operator()(const T& x, const T& y) const
0086   {
0087     return x < y? x : y;
0088   }
0089 };
0090 
0091 
0092 /**
0093  *  @brief Compute the bitwise AND of two integral values.
0094  *
0095  *  This binary function object computes the bitwise AND of the two
0096  *  values it is given. When used with MPI and a type @c T that has an
0097  *  associated, built-in MPI data type, translates to @c MPI_BAND.
0098  */
0099 template<typename T>
0100 struct bitwise_and
0101 {
0102   typedef T first_argument_type;
0103   typedef T second_argument_type;
0104   typedef T result_type;
0105   /** @returns @c x & y. */
0106   T operator()(const T& x, const T& y) const
0107   {
0108     return x & y;
0109   }
0110 };
0111 
0112 /**
0113  *  @brief Compute the bitwise OR of two integral values.
0114  *
0115  *  This binary function object computes the bitwise OR of the two
0116  *  values it is given. When used with MPI and a type @c T that has an
0117  *  associated, built-in MPI data type, translates to @c MPI_BOR.
0118  */
0119 template<typename T>
0120 struct bitwise_or
0121 {
0122   typedef T first_argument_type;
0123   typedef T second_argument_type;
0124   typedef T result_type;
0125   /** @returns the @c x | y. */
0126   T operator()(const T& x, const T& y) const
0127   {
0128     return x | y;
0129   }
0130 };
0131 
0132 /**
0133  *  @brief Compute the logical exclusive OR of two integral values.
0134  *
0135  *  This binary function object computes the logical exclusive of the
0136  *  two values it is given. When used with MPI and a type @c T that has
0137  *  an associated, built-in MPI data type, translates to @c MPI_LXOR.
0138  */
0139 template<typename T>
0140 struct logical_xor
0141 {
0142   typedef T first_argument_type;
0143   typedef T second_argument_type;
0144   typedef T result_type;
0145   /** @returns the logical exclusive OR of x and y. */
0146   T operator()(const T& x, const T& y) const
0147   {
0148     return (x || y) && !(x && y);
0149   }
0150 };
0151 
0152 /**
0153  *  @brief Compute the bitwise exclusive OR of two integral values.
0154  *
0155  *  This binary function object computes the bitwise exclusive OR of
0156  *  the two values it is given. When used with MPI and a type @c T that
0157  *  has an associated, built-in MPI data type, translates to @c
0158  *  MPI_BXOR.
0159  */
0160 template<typename T>
0161 struct bitwise_xor
0162 {
0163   typedef T first_argument_type;
0164   typedef T second_argument_type;
0165   typedef T result_type;
0166   /** @returns @c x ^ y. */
0167   T operator()(const T& x, const T& y) const
0168   {
0169     return x ^ y;
0170   }
0171 };
0172 
0173 /**************************************************************************
0174  * MPI_Op queries                                                         *
0175  **************************************************************************/
0176 
0177 /**
0178  *  @brief Determine if a function object has an associated @c MPI_Op.
0179  *
0180  *  This trait determines if a function object type @c Op, when used
0181  *  with argument type @c T, has an associated @c MPI_Op. If so, @c
0182  *  is_mpi_op<Op,T> will derive from @c mpl::false_ and will
0183  *  contain a static member function @c op that takes no arguments but
0184  *  returns the associated @c MPI_Op value. For instance, @c
0185  *  is_mpi_op<std::plus<int>,int>::op() returns @c MPI_SUM.
0186  *
0187  *  Users may specialize @c is_mpi_op for any other class templates
0188  *  that map onto operations that have @c MPI_Op equivalences, such as
0189  *  bitwise OR, logical and, or maximum. However, users are encouraged
0190  *  to use the standard function objects in the @c functional and @c
0191  *  boost/mpi/operations.hpp headers whenever possible. For
0192  *  function objects that are class templates with a single template
0193  *  parameter, it may be easier to specialize @c is_builtin_mpi_op.
0194  */
0195 template<typename Op, typename T>
0196 struct is_mpi_op : public mpl::false_ { };
0197 
0198 /// INTERNAL ONLY
0199 template<typename T>
0200 struct is_mpi_op<maximum<T>, T>
0201   : public boost::mpl::or_<is_mpi_integer_datatype<T>,
0202                            is_mpi_floating_point_datatype<T> >
0203 {
0204   static MPI_Op op() { return MPI_MAX; }
0205 };
0206 
0207 /// INTERNAL ONLY
0208 template<typename T>
0209 struct is_mpi_op<minimum<T>, T>
0210   : public boost::mpl::or_<is_mpi_integer_datatype<T>,
0211                            is_mpi_floating_point_datatype<T> >
0212 {
0213   static MPI_Op op() { return MPI_MIN; }
0214 };
0215 
0216 /// INTERNAL ONLY
0217 template<typename T>
0218  struct is_mpi_op<std::plus<T>, T>
0219   : public boost::mpl::or_<is_mpi_integer_datatype<T>,
0220                            is_mpi_floating_point_datatype<T>,
0221                            is_mpi_complex_datatype<T> >
0222 {
0223   static MPI_Op op() { return MPI_SUM; }
0224 };
0225 
0226 /// INTERNAL ONLY
0227 template<typename T>
0228  struct is_mpi_op<std::multiplies<T>, T>
0229   : public boost::mpl::or_<is_mpi_integer_datatype<T>,
0230                            is_mpi_floating_point_datatype<T>,
0231                            is_mpi_complex_datatype<T> >
0232 {
0233   static MPI_Op op() { return MPI_PROD; }
0234 };
0235 
0236 /// INTERNAL ONLY
0237 template<typename T>
0238  struct is_mpi_op<std::logical_and<T>, T>
0239   : public boost::mpl::or_<is_mpi_integer_datatype<T>,
0240                            is_mpi_logical_datatype<T> >
0241 {
0242   static MPI_Op op() { return MPI_LAND; }
0243 };
0244 
0245 /// INTERNAL ONLY
0246 template<typename T>
0247  struct is_mpi_op<std::logical_or<T>, T>
0248   : public boost::mpl::or_<is_mpi_integer_datatype<T>,
0249                            is_mpi_logical_datatype<T> >
0250 {
0251   static MPI_Op op() { return MPI_LOR; }
0252 };
0253 
0254 /// INTERNAL ONLY
0255 template<typename T>
0256  struct is_mpi_op<logical_xor<T>, T>
0257   : public boost::mpl::or_<is_mpi_integer_datatype<T>,
0258                            is_mpi_logical_datatype<T> >
0259 {
0260   static MPI_Op op() { return MPI_LXOR; }
0261 };
0262 
0263 /// INTERNAL ONLY
0264 template<typename T>
0265  struct is_mpi_op<bitwise_and<T>, T>
0266   : public boost::mpl::or_<is_mpi_integer_datatype<T>,
0267                            is_mpi_byte_datatype<T> >
0268 {
0269   static MPI_Op op() { return MPI_BAND; }
0270 };
0271 
0272 /// INTERNAL ONLY
0273 template<typename T>
0274  struct is_mpi_op<bitwise_or<T>, T>
0275   : public boost::mpl::or_<is_mpi_integer_datatype<T>,
0276                            is_mpi_byte_datatype<T> >
0277 {
0278   static MPI_Op op() { return MPI_BOR; }
0279 };
0280 
0281 /// INTERNAL ONLY
0282 template<typename T>
0283  struct is_mpi_op<bitwise_xor<T>, T>
0284   : public boost::mpl::or_<is_mpi_integer_datatype<T>,
0285                            is_mpi_byte_datatype<T> >
0286 {
0287   static MPI_Op op() { return MPI_BXOR; }
0288 };
0289 
0290 namespace detail {
0291   // A helper class used to create user-defined MPI_Ops
0292   template<typename Op, typename T>
0293   class user_op
0294   {
0295   public:
0296     user_op()
0297     {
0298       BOOST_MPI_CHECK_RESULT(MPI_Op_create,
0299                              (&user_op<Op, T>::perform,
0300                               is_commutative<Op, T>::value,
0301                               &mpi_op));
0302     }
0303 
0304     ~user_op()
0305     {
0306       if (boost::core::uncaught_exceptions() > 0) {
0307         // Ignore failure cases: there are obviously other problems
0308         // already, and we don't want to cause program termination if
0309         // MPI_Op_free fails.
0310         MPI_Op_free(&mpi_op);
0311       } else {
0312         BOOST_MPI_CHECK_RESULT(MPI_Op_free, (&mpi_op));
0313       }
0314     }
0315 
0316     MPI_Op& get_mpi_op()
0317     {
0318       return mpi_op;
0319     }
0320 
0321   private:
0322     MPI_Op mpi_op;
0323 
0324     static void BOOST_MPI_CALLING_CONVENTION perform(void* vinvec, void* voutvec, int* plen, MPI_Datatype*)
0325     {
0326       T* invec = static_cast<T*>(vinvec);
0327       T* outvec = static_cast<T*>(voutvec);
0328       Op op;
0329       std::transform(invec, invec + *plen, outvec, outvec, op);
0330     }
0331   };
0332 
0333 } // end namespace detail
0334 
0335 } } // end namespace boost::mpi
0336 
0337 #endif // BOOST_MPI_GET_MPI_OP_HPP