File indexing completed on 2025-01-18 09:40:57
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #ifndef BOOST_MPI_SCAN_HPP
0013 #define BOOST_MPI_SCAN_HPP
0014
0015 #include <boost/mpi/exception.hpp>
0016 #include <boost/mpi/datatype.hpp>
0017
0018
0019 #include <boost/mpi/packed_oarchive.hpp>
0020 #include <boost/mpi/packed_iarchive.hpp>
0021
0022
0023 #include <boost/mpi/detail/point_to_point.hpp>
0024
0025 #include <boost/mpi/communicator.hpp>
0026 #include <boost/mpi/environment.hpp>
0027 #include <boost/mpi/detail/computation_tree.hpp>
0028 #include <boost/mpi/operations.hpp>
0029 #include <algorithm>
0030 #include <exception>
0031 #include <boost/assert.hpp>
0032
0033 namespace boost { namespace mpi {
0034
0035
0036
0037
0038
0039 namespace detail {
0040
0041
0042
0043
0044
0045
0046
0047 template<typename T, typename Op>
0048 void
0049 scan_impl(const communicator& comm, const T* in_values, int n, T* out_values,
0050 Op , mpl::true_ , mpl::true_ )
0051 {
0052 BOOST_MPI_CHECK_RESULT(MPI_Scan,
0053 (const_cast<T*>(in_values), out_values, n,
0054 boost::mpi::get_mpi_datatype<T>(*in_values),
0055 (is_mpi_op<Op, T>::op()), comm));
0056 }
0057
0058
0059
0060
0061
0062
0063
0064
0065 template<typename T, typename Op>
0066 void
0067 scan_impl(const communicator& comm, const T* in_values, int n, T* out_values,
0068 Op op, mpl::false_ , mpl::true_ )
0069 {
0070 user_op<Op, T> mpi_op;
0071 BOOST_MPI_CHECK_RESULT(MPI_Scan,
0072 (const_cast<T*>(in_values), out_values, n,
0073 boost::mpi::get_mpi_datatype<T>(*in_values),
0074 mpi_op.get_mpi_op(), comm));
0075 }
0076
0077
0078
0079
0080
0081 template<typename T, typename Op>
0082 void
0083 upper_lower_scan(const communicator& comm, const T* in_values, int n,
0084 T* out_values, Op& op, int lower, int upper)
0085 {
0086 int tag = environment::collectives_tag();
0087 int rank = comm.rank();
0088
0089 if (lower + 1 == upper) {
0090 std::copy(in_values, in_values + n, out_values);
0091 } else {
0092 int middle = (lower + upper) / 2;
0093
0094 if (rank < middle) {
0095
0096 upper_lower_scan(comm, in_values, n, out_values, op, lower, middle);
0097
0098
0099
0100 if (rank == middle - 1) {
0101 packed_oarchive oa(comm);
0102 for (int i = 0; i < n; ++i)
0103 oa << out_values[i];
0104
0105 for (int p = middle; p < upper; ++p)
0106 comm.send(p, tag, oa);
0107 }
0108 } else {
0109
0110 upper_lower_scan(comm, in_values, n, out_values, op, middle, upper);
0111
0112
0113 packed_iarchive ia(comm);
0114 comm.recv(middle - 1, tag, ia);
0115
0116
0117 T left_value;
0118 for (int i = 0; i < n; ++i)
0119 {
0120 ia >> left_value;
0121 out_values[i] = op(left_value, out_values[i]);
0122 }
0123 }
0124 }
0125 }
0126
0127
0128
0129
0130 template<typename T, typename Op>
0131 inline void
0132 scan_impl(const communicator& comm, const T* in_values, int n, T* out_values,
0133 Op op, mpl::false_ , mpl::false_)
0134 {
0135 upper_lower_scan(comm, in_values, n, out_values, op, 0, comm.size());
0136 }
0137 }
0138
0139
0140 template<typename T, typename Op>
0141 inline void
0142 scan(const communicator& comm, const T& in_value, T& out_value, Op op)
0143 {
0144 detail::scan_impl(comm, &in_value, 1, &out_value, op,
0145 is_mpi_op<Op, T>(), is_mpi_datatype<T>());
0146 }
0147
0148 template<typename T, typename Op>
0149 inline void
0150 scan(const communicator& comm, const T* in_values, int n, T* out_values, Op op)
0151 {
0152 detail::scan_impl(comm, in_values, n, out_values, op,
0153 is_mpi_op<Op, T>(), is_mpi_datatype<T>());
0154 }
0155
0156 template<typename T, typename Op>
0157 inline T
0158 scan(const communicator& comm, const T& in_value, Op op)
0159 {
0160 T out_value;
0161 detail::scan_impl(comm, &in_value, 1, &out_value, op,
0162 is_mpi_op<Op, T>(), is_mpi_datatype<T>());
0163 return out_value;
0164 }
0165
0166 } }
0167
0168 #endif