1 // Copyright (c) 2007-2017 Hartmut Kaiser 2 // 3 // Distributed under the Boost Software License, Version 1.0. (See accompanying 4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5 6 /// \file parallel/algorithms/reduce.hpp 7 8 #if !defined(HPX_PARALLEL_DETAIL_REDUCE_JUN_01_2014_0903AM) 9 #define HPX_PARALLEL_DETAIL_REDUCE_JUN_01_2014_0903AM 10 11 #include <hpx/config.hpp> 12 #include <hpx/traits/is_iterator.hpp> 13 #include <hpx/util/range.hpp> 14 #include <hpx/util/unwrap.hpp> 15 16 #include <hpx/parallel/algorithms/detail/dispatch.hpp> 17 #include <hpx/parallel/execution_policy.hpp> 18 #include <hpx/parallel/util/detail/algorithm_result.hpp> 19 #include <hpx/parallel/util/loop.hpp> 20 #include <hpx/parallel/util/partitioner.hpp> 21 22 #include <algorithm> 23 #include <cstddef> 24 #include <iterator> 25 #include <numeric> 26 #include <type_traits> 27 #include <utility> 28 #include <vector> 29 30 namespace hpx { namespace parallel { inline namespace v1 31 { 32 /////////////////////////////////////////////////////////////////////////// 33 // reduce 34 namespace detail 35 { 36 /// \cond NOINTERNAL 37 template <typename T> 38 struct reduce : public detail::algorithm<reduce<T>, T> 39 { reducehpx::parallel::v1::detail::reduce40 reduce() 41 : reduce::algorithm("reduce") 42 {} 43 44 template <typename ExPolicy, typename InIter, typename T_, 45 typename Reduce> 46 static T sequentialhpx::parallel::v1::detail::reduce47 sequential(ExPolicy, InIter first, InIter last, T_ && init, 48 Reduce && r) 49 { 50 return std::accumulate(first, last, std::forward<T_>(init), 51 std::forward<Reduce>(r)); 52 } 53 54 template <typename ExPolicy, typename FwdIter, typename T_, 55 typename Reduce> 56 static typename util::detail::algorithm_result<ExPolicy, T>::type parallelhpx::parallel::v1::detail::reduce57 parallel(ExPolicy && policy, FwdIter first, FwdIter last, 58 T_ && init, Reduce && r) 59 { 60 if (first == last) 61 { 62 return util::detail::algorithm_result<ExPolicy, T>::get( 63 std::forward<T_>(init)); 64 } 65 66 auto f1 = 67 [r](FwdIter part_begin, std::size_t part_size) -> T 68 { 69 T val = *part_begin; 70 return util::accumulate_n(++part_begin, --part_size, 71 std::move(val), r); 72 }; 73 74 return util::partitioner<ExPolicy, T>::call( 75 std::forward<ExPolicy>(policy), 76 first, std::distance(first, last), 77 std::move(f1), 78 hpx::util::unwrapping( 79 [HPX_CAPTURE_FORWARD(init), 80 HPX_CAPTURE_FORWARD(r) 81 ](std::vector<T> && results) -> T 82 { 83 return util::accumulate_n(hpx::util::begin(results), 84 hpx::util::size(results), init, r); 85 })); 86 } 87 }; 88 /// \endcond 89 // Non Segmented Reduce 90 template <typename ExPolicy, typename FwdIter, typename T, typename F> 91 inline typename std::enable_if< 92 execution::is_execution_policy<ExPolicy>::value, 93 typename util::detail::algorithm_result<ExPolicy, T>::type 94 >::type reduce_(ExPolicy && policy,FwdIter first,FwdIter last,T init,F && f,std::false_type)95 reduce_(ExPolicy&& policy, FwdIter first, FwdIter last 96 , T init, F && f, std::false_type) 97 { 98 #if defined(HPX_HAVE_ALGORITHM_INPUT_ITERATOR_SUPPORT) 99 static_assert( 100 (hpx::traits::is_input_iterator<FwdIter>::value), 101 "Requires at least input iterator."); 102 typedef std::integral_constant<bool, 103 execution::is_sequenced_execution_policy<ExPolicy>::value || 104 !hpx::traits::is_forward_iterator<FwdIter>::value 105 > is_seq; 106 #else 107 static_assert( 108 (hpx::traits::is_forward_iterator<FwdIter>::value), 109 "Requires at least forward iterator."); 110 111 typedef execution::is_sequenced_execution_policy<ExPolicy> is_seq; 112 #endif 113 114 return detail::reduce<T>().call( 115 std::forward<ExPolicy>(policy), is_seq(), 116 first, last, std::move(init), std::forward<F>(f)); 117 } 118 119 // Forward Declaration of Segmented Reduce 120 template <typename ExPolicy, typename FwdIter, typename T, typename F> 121 inline typename std::enable_if< 122 execution::is_execution_policy<ExPolicy>::value, 123 typename util::detail::algorithm_result<ExPolicy, T>::type 124 >::type 125 reduce_(ExPolicy&& policy, FwdIter first, FwdIter last 126 , T init, F && f, std::true_type); 127 } 128 129 /// Returns GENERALIZED_SUM(f, init, *first, ..., *(first + (last - first) - 1)). 130 /// 131 /// \note Complexity: O(\a last - \a first) applications of the 132 /// predicate \a f. 133 /// 134 /// \tparam ExPolicy The type of the execution policy to use (deduced). 135 /// It describes the manner in which the execution 136 /// of the algorithm may be parallelized and the manner 137 /// in which it executes the assignments. 138 /// \tparam FwdIter The type of the source iterators used (deduced). 139 /// This iterator type must meet the requirements of an 140 /// forward iterator. 141 /// \tparam F The type of the function/function object to use 142 /// (deduced). Unlike its sequential form, the parallel 143 /// overload of \a copy_if requires \a F to meet the 144 /// requirements of \a CopyConstructible. 145 /// \tparam T The type of the value to be used as initial (and 146 /// intermediate) values (deduced). 147 /// 148 /// \param policy The execution policy to use for the scheduling of 149 /// the iterations. 150 /// \param first Refers to the beginning of the sequence of elements 151 /// the algorithm will be applied to. 152 /// \param last Refers to the end of the sequence of elements the 153 /// algorithm will be applied to. 154 /// \param f Specifies the function (or function object) which 155 /// will be invoked for each of the elements in the 156 /// sequence specified by [first, last). This is a 157 /// binary predicate. The signature of this predicate 158 /// should be equivalent to: 159 /// \code 160 /// Ret fun(const Type1 &a, const Type1 &b); 161 /// \endcode \n 162 /// The signature does not need to have const&. 163 /// The types \a Type1 \a Ret must be 164 /// such that an object of type \a FwdIter can be 165 /// dereferenced and then implicitly converted to any 166 /// of those types. 167 /// \param init The initial value for the generalized sum. 168 /// 169 /// The reduce operations in the parallel \a reduce algorithm invoked 170 /// with an execution policy object of type \a sequenced_policy 171 /// execute in sequential order in the calling thread. 172 /// 173 /// The reduce operations in the parallel \a copy_if algorithm invoked 174 /// with an execution policy object of type \a parallel_policy 175 /// or \a parallel_task_policy are permitted to execute in an unordered 176 /// fashion in unspecified threads, and indeterminately sequenced 177 /// within each thread. 178 /// 179 /// \returns The \a reduce algorithm returns a \a hpx::future<T> if the 180 /// execution policy is of type 181 /// \a sequenced_task_policy or 182 /// \a parallel_task_policy and 183 /// returns \a T otherwise. 184 /// The \a reduce algorithm returns the result of the 185 /// generalized sum over the elements given by the input range 186 /// [first, last). 187 /// 188 /// \note GENERALIZED_SUM(op, a1, ..., aN) is defined as follows: 189 /// * a1 when N is 1 190 /// * op(GENERALIZED_SUM(op, b1, ..., bK), GENERALIZED_SUM(op, bM, ..., bN)), 191 /// where: 192 /// * b1, ..., bN may be any permutation of a1, ..., aN and 193 /// * 1 < K+1 = M <= N. 194 /// 195 /// The difference between \a reduce and \a accumulate is 196 /// that the behavior of reduce may be non-deterministic for 197 /// non-associative or non-commutative binary predicate. 198 /// 199 template <typename ExPolicy, typename FwdIter, typename T, typename F> 200 inline typename std::enable_if< 201 execution::is_execution_policy<ExPolicy>::value, 202 typename util::detail::algorithm_result<ExPolicy, T>::type 203 >::type reduce(ExPolicy && policy,FwdIter first,FwdIter last,T init,F && f)204 reduce(ExPolicy&& policy, FwdIter first, FwdIter last, T init, F && f) 205 { 206 typedef hpx::traits::is_segmented_iterator<FwdIter> is_segmented; 207 208 return detail::reduce_( 209 std::forward<ExPolicy>(policy), first, last, 210 std::move(init), std::forward<F>(f), is_segmented()); 211 } 212 213 /// Returns GENERALIZED_SUM(+, init, *first, ..., *(first + (last - first) - 1)). 214 /// 215 /// \note Complexity: O(\a last - \a first) applications of the 216 /// operator+(). 217 /// 218 /// \tparam ExPolicy The type of the execution policy to use (deduced). 219 /// It describes the manner in which the execution 220 /// of the algorithm may be parallelized and the manner 221 /// in which it executes the assignments. 222 /// \tparam FwdIter The type of the source iterators used (deduced). 223 /// This iterator type must meet the requirements of an 224 /// forward iterator. 225 /// \tparam T The type of the value to be used as initial (and 226 /// intermediate) values (deduced). 227 /// 228 /// \param policy The execution policy to use for the scheduling of 229 /// the iterations. 230 /// \param first Refers to the beginning of the sequence of elements 231 /// the algorithm will be applied to. 232 /// \param last Refers to the end of the sequence of elements the 233 /// algorithm will be applied to. 234 /// \param init The initial value for the generalized sum. 235 /// 236 /// The reduce operations in the parallel \a reduce algorithm invoked 237 /// with an execution policy object of type \a sequenced_policy 238 /// execute in sequential order in the calling thread. 239 /// 240 /// The reduce operations in the parallel \a copy_if algorithm invoked 241 /// with an execution policy object of type \a parallel_policy 242 /// or \a parallel_task_policy are permitted to execute in an unordered 243 /// fashion in unspecified threads, and indeterminately sequenced 244 /// within each thread. 245 /// 246 /// \returns The \a reduce algorithm returns a \a hpx::future<T> if the 247 /// execution policy is of type 248 /// \a sequenced_task_policy or 249 /// \a parallel_task_policy and 250 /// returns \a T otherwise. 251 /// The \a reduce algorithm returns the result of the 252 /// generalized sum (applying operator+()) over the elements given 253 /// by the input range [first, last). 254 /// 255 /// \note GENERALIZED_SUM(+, a1, ..., aN) is defined as follows: 256 /// * a1 when N is 1 257 /// * op(GENERALIZED_SUM(+, b1, ..., bK), GENERALIZED_SUM(+, bM, ..., bN)), 258 /// where: 259 /// * b1, ..., bN may be any permutation of a1, ..., aN and 260 /// * 1 < K+1 = M <= N. 261 /// 262 /// The difference between \a reduce and \a accumulate is 263 /// that the behavior of reduce may be non-deterministic for 264 /// non-associative or non-commutative binary predicate. 265 /// 266 template <typename ExPolicy, typename FwdIter, typename T> 267 inline typename std::enable_if< 268 execution::is_execution_policy<ExPolicy>::value, 269 typename util::detail::algorithm_result<ExPolicy, T>::type 270 >::type reduce(ExPolicy && policy,FwdIter first,FwdIter last,T init)271 reduce(ExPolicy&& policy, FwdIter first, FwdIter last, T init) 272 { 273 typedef hpx::traits::is_segmented_iterator<FwdIter> is_segmented; 274 275 return detail::reduce_( 276 std::forward<ExPolicy>(policy), first, last, 277 std::move(init), std::plus<T>(),is_segmented()); 278 } 279 280 /// Returns GENERALIZED_SUM(+, T(), *first, ..., *(first + (last - first) - 1)). 281 /// 282 /// \note Complexity: O(\a last - \a first) applications of the 283 /// operator+(). 284 /// 285 /// \tparam ExPolicy The type of the execution policy to use (deduced). 286 /// It describes the manner in which the execution 287 /// of the algorithm may be parallelized and the manner 288 /// in which it executes the assignments. 289 /// \tparam FwdIter The type of the source iterators used (deduced). 290 /// This iterator type must meet the requirements of an 291 /// forward iterator. 292 /// 293 /// \param policy The execution policy to use for the scheduling of 294 /// the iterations. 295 /// \param first Refers to the beginning of the sequence of elements 296 /// the algorithm will be applied to. 297 /// \param last Refers to the end of the sequence of elements the 298 /// algorithm will be applied to. 299 /// 300 /// The reduce operations in the parallel \a reduce algorithm invoked 301 /// with an execution policy object of type \a sequenced_policy 302 /// execute in sequential order in the calling thread. 303 /// 304 /// The reduce operations in the parallel \a copy_if algorithm invoked 305 /// with an execution policy object of type \a parallel_policy 306 /// or \a parallel_task_policy are permitted to execute in an unordered 307 /// fashion in unspecified threads, and indeterminately sequenced 308 /// within each thread. 309 /// 310 /// \returns The \a reduce algorithm returns a \a hpx::future<T> if the 311 /// execution policy is of type 312 /// \a sequenced_task_policy or 313 /// \a parallel_task_policy and 314 /// returns T otherwise (where T is the value_type of 315 /// \a FwdIter). 316 /// The \a reduce algorithm returns the result of the 317 /// generalized sum (applying operator+()) over the elements given 318 /// by the input range [first, last). 319 /// 320 /// \note The type of the initial value (and the result type) \a T is 321 /// determined from the value_type of the used \a FwdIter. 322 /// 323 /// \note GENERALIZED_SUM(+, a1, ..., aN) is defined as follows: 324 /// * a1 when N is 1 325 /// * op(GENERALIZED_SUM(+, b1, ..., bK), GENERALIZED_SUM(+, bM, ..., bN)), 326 /// where: 327 /// * b1, ..., bN may be any permutation of a1, ..., aN and 328 /// * 1 < K+1 = M <= N. 329 /// 330 /// The difference between \a reduce and \a accumulate is 331 /// that the behavior of reduce may be non-deterministic for 332 /// non-associative or non-commutative binary predicate. 333 /// 334 template <typename ExPolicy, typename FwdIter> 335 inline typename std::enable_if< 336 execution::is_execution_policy<ExPolicy>::value, 337 typename util::detail::algorithm_result<ExPolicy, 338 typename std::iterator_traits<FwdIter>::value_type 339 >::type 340 >::type reduce(ExPolicy && policy,FwdIter first,FwdIter last)341 reduce(ExPolicy&& policy, FwdIter first, FwdIter last) 342 { 343 typedef typename std::iterator_traits<FwdIter>::value_type value_type; 344 345 typedef hpx::traits::is_segmented_iterator<FwdIter> is_segmented; 346 347 return detail::reduce_( 348 std::forward<ExPolicy>(policy), first, last, 349 value_type(), std::plus<value_type>(), is_segmented()); 350 } 351 }}} 352 353 #endif 354