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