• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

STEllAR-GROUP / hpx / #882

31 Aug 2023 07:44PM UTC coverage: 41.798% (-44.7%) from 86.546%
#882

push

19442 of 46514 relevant lines covered (41.8%)

126375.38 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.91
/libs/core/algorithms/include/hpx/parallel/algorithms/transform_reduce.hpp
1
//  Copyright (c) 2015 Daniel Bourgeois
2
//  Copyright (c) 2017-2023 Hartmut Kaiser
3
//  Copyright (c) 2022 Bhumit Attarde
4
//
5
//  SPDX-License-Identifier: BSL-1.0
6
//  Distributed under the Boost Software License, Version 1.0. (See accompanying
7
//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8

9
/// \file parallel/algorithms/transform_reduce.hpp
10
/// \page hpx::transform_reduce
11
/// \headerfile hpx/algorithm.hpp
12

13
#pragma once
14

15
#if defined(DOXYGEN)
16
namespace hpx {
17
    // clang-format off
18

19
    /// Returns GENERALIZED_SUM(red_op, init, conv_op(*first), ...,
20
    /// conv_op(*(first + (last - first) - 1))). Executed according to the
21
    /// policy.
22
    ///
23
    /// \note   Complexity: O(\a last - \a first) applications of the
24
    ///         predicates \a red_op and \a conv_op.
25
    ///
26
    /// \tparam ExPolicy    The type of the execution policy to use (deduced).
27
    ///                     It describes the manner in which the execution
28
    ///                     of the algorithm may be parallelized and the manner
29
    ///                     in which it executes the assignments.
30
    /// \tparam FwdIter     The type of the source iterators used (deduced).
31
    ///                     This iterator type must meet the requirements of a
32
    ///                     forward iterator.
33
    /// \tparam T           The type of the value to be used as initial (and
34
    ///                     intermediate) values (deduced).
35
    /// \tparam Reduce      The type of the binary function object used for
36
    ///                     the reduction operation.
37
    /// \tparam Convert     The type of the unary function object used to
38
    ///                     transform the elements of the input sequence before
39
    ///                     invoking the reduce function.
40
    ///
41
    /// \param policy       The execution policy to use for the scheduling of
42
    ///                     the iterations.
43
    /// \param first        Refers to the beginning of the sequence of elements
44
    ///                     the algorithm will be applied to.
45
    /// \param last         Refers to the end of the sequence of elements the
46
    ///                     algorithm will be applied to.
47
    /// \param init         The initial value for the generalized sum.
48
    /// \param red_op       Specifies the function (or function object) which
49
    ///                     will be invoked for each of the values returned
50
    ///                     from the invocation of \a conv_op. This is a
51
    ///                     binary predicate. The signature of this predicate
52
    ///                     should be equivalent to:
53
    ///                     \code
54
    ///                     Ret fun(const Type1 &a, const Type2 &b);
55
    ///                     \endcode \n
56
    ///                     The signature does not need to have const&, but
57
    ///                     the function must not modify the objects passed to
58
    ///                     it.
59
    ///                     The types \a Type1, \a Type2, and \a Ret must be
60
    ///                     such that an object of a type as returned from
61
    ///                     \a conv_op can be implicitly converted to any
62
    ///                     of those types.
63
    /// \param conv_op      Specifies the function (or function object) which
64
    ///                     will be invoked for each of the elements in the
65
    ///                     sequence specified by [first, last). This is a
66
    ///                     unary predicate. The signature of this predicate
67
    ///                     should be equivalent to:
68
    ///                     \code
69
    ///                     R fun(const Type &a);
70
    ///                     \endcode \n
71
    ///                     The signature does not need to have const&, but
72
    ///                     the function must not modify the objects passed to
73
    ///                     it. The type \a Type must be such that an object of
74
    ///                     type \a FwdIter can be dereferenced and then
75
    ///                     implicitly converted to Type.
76
    ///                     The type \a R must be such that an object of this
77
    ///                     type can be implicitly converted to \a T.
78
    ///
79
    /// The reduce operations in the parallel \a transform_reduce algorithm invoked
80
    /// with an execution policy object of type \a sequenced_policy
81
    /// execute in sequential order in the calling thread.
82
    ///
83
    /// The reduce operations in the parallel \a transform_reduce algorithm invoked
84
    /// with an execution policy object of type \a parallel_policy
85
    /// or \a parallel_task_policy are permitted to execute in an unordered
86
    /// fashion in unspecified threads, and indeterminately sequenced
87
    /// within each thread.
88
    ///
89
    /// \returns  The \a transform_reduce algorithm returns a \a hpx::future<T> if the
90
    ///           execution policy is of type \a parallel_task_policy and
91
    ///           returns \a T otherwise.
92
    ///           The \a transform_reduce algorithm returns the result of the
93
    ///           generalized sum over the values returned from \a conv_op when
94
    ///           applied to the elements given by the input range
95
    ///           [first, last).
96
    ///
97
    /// \note   GENERALIZED_SUM(op, a1, ..., aN) is defined as follows:
98
    ///         * a1 when N is 1
99
    ///         * op(GENERALIZED_SUM(op, b1, ..., bK), GENERALIZED_SUM(op, bM, ..., bN)),
100
    ///           where:
101
    ///           * b1, ..., bN may be any permutation of a1, ..., aN and
102
    ///           * 1 < K+1 = M <= N.
103
    ///
104
    /// The difference between \a transform_reduce and \a accumulate is
105
    /// that the behavior of transform_reduce may be non-deterministic for
106
    /// non-associative or non-commutative binary predicate.
107
    ///
108
    template <typename ExPolicy, typename FwdIter, typename T, typename Reduce,
109
        typename Convert>
110
    hpx::parallel::util::detail::algorithm_result_t<ExPolicy, T>
111
    transform_reduce(ExPolicy&& policy, FwdIter first, FwdIter last, T init,
112
        Reduce&& red_op, Convert&& conv_op);
113

114
    /// Returns GENERALIZED_SUM(red_op, init, conv_op(*first), ...,
115
    /// conv_op(*(first + (last - first) - 1))).
116
    ///
117
    /// \note   Complexity: O(\a last - \a first) applications of the
118
    ///         predicates \a red_op and \a conv_op.
119
    ///
120
    /// \tparam InIter      The type of the source iterators used (deduced).
121
    ///                     This iterator type must meet the requirements of an
122
    ///                     input iterator.
123
    /// \tparam T           The type of the value to be used as initial (and
124
    ///                     intermediate) values (deduced).
125
    /// \tparam Reduce      The type of the binary function object used for
126
    ///                     the reduction operation.
127
    /// \tparam Convert     The type of the unary function object used to
128
    ///                     transform the elements of the input sequence before
129
    ///                     invoking the reduce function.
130
    ///
131
    /// \param first        Refers to the beginning of the sequence of elements
132
    ///                     the algorithm will be applied to.
133
    /// \param last         Refers to the end of the sequence of elements the
134
    ///                     algorithm will be applied to.
135
    /// \param init         The initial value for the generalized sum.
136
    /// \param red_op       Specifies the function (or function object) which
137
    ///                     will be invoked for each of the values returned
138
    ///                     from the invocation of \a conv_op. This is a
139
    ///                     binary predicate. The signature of this predicate
140
    ///                     should be equivalent to:
141
    ///                     \code
142
    ///                     Ret fun(const Type1 &a, const Type2 &b);
143
    ///                     \endcode \n
144
    ///                     The signature does not need to have const&, but
145
    ///                     the function must not modify the objects passed to
146
    ///                     it.
147
    ///                     The types \a Type1, \a Type2, and \a Ret must be
148
    ///                     such that an object of a type as returned from
149
    ///                     \a conv_op can be implicitly converted to any
150
    ///                     of those types.
151
    /// \param conv_op      Specifies the function (or function object) which
152
    ///                     will be invoked for each of the elements in the
153
    ///                     sequence specified by [first, last). This is a
154
    ///                     unary predicate. The signature of this predicate
155
    ///                     should be equivalent to:
156
    ///                     \code
157
    ///                     R fun(const Type &a);
158
    ///                     \endcode \n
159
    ///                     The signature does not need to have const&, but
160
    ///                     the function must not modify the objects passed to
161
    ///                     it. The type \a Type must be such that an object of
162
    ///                     type \a InIter can be dereferenced and then
163
    ///                     implicitly converted to Type.
164
    ///                     The type \a R must be such that an object of this
165
    ///                     type can be implicitly converted to \a T.
166
    ///
167
    /// \returns  The \a transform_reduce algorithm returns a \a T.
168
    ///           The \a transform_reduce algorithm returns the result of the
169
    ///           generalized sum over the values returned from \a conv_op when
170
    ///           applied to the elements given by the input range
171
    ///           [first, last).
172
    ///
173
    /// \note   GENERALIZED_SUM(op, a1, ..., aN) is defined as follows:
174
    ///         * a1 when N is 1
175
    ///         * op(GENERALIZED_SUM(op, b1, ..., bK), GENERALIZED_SUM(op, bM, ..., bN)),
176
    ///           where:
177
    ///           * b1, ..., bN may be any permutation of a1, ..., aN and
178
    ///           * 1 < K+1 = M <= N.
179
    ///
180
    /// The difference between \a transform_reduce and \a accumulate is
181
    /// that the behavior of \a transform_reduce may be non-deterministic for
182
    /// non-associative or non-commutative binary predicate.
183
    ///
184
    template <typename InIter, typename T, typename Reduce, typename Convert>
185
    T transform_reduce(InIter first, InIter last, T init, Reduce&& red_op,
186
        Convert&& conv_op);
187

188
    ///////////////////////////////////////////////////////////////////////////
189
    /// Returns the result of accumulating init with the inner products of the
190
    /// pairs formed by the elements of two ranges starting at first1 and
191
    /// first2. Executed according to the policy.
192
    ///
193
    /// \note   Complexity: O(\a last - \a first) applications each of
194
    ///                     \a reduce and \a transform.
195
    /// \tparam ExPolicy    The type of the execution policy to use (deduced).
196
    ///                     It describes the manner in which the execution
197
    ///                     of the algorithm may be parallelized and the manner
198
    ///                     in which it executes the assignments.
199
    /// \tparam FwdIter1    The type of the first source iterators used
200
    ///                     (deduced). This iterator type must meet the
201
    ///                     requirements of a forward iterator.
202
    /// \tparam FwdIter2    The type of the second source iterators used
203
    ///                     (deduced). This iterator type must meet the
204
    ///                     requirements of a forward iterator.
205
    /// \tparam T           The type of the value to be used as return)
206
    ///                     values (deduced).
207
    /// \param policy       The execution policy to use for the scheduling of
208
    ///                     the iterations.
209
    /// \param first1       Refers to the beginning of the first sequence of
210
    ///                     elements the result will be calculated with.
211
    /// \param last1        Refers to the end of the first sequence of elements
212
    ///                     the algorithm will be applied to.
213
    /// \param first2       Refers to the beginning of the second sequence of
214
    ///                     elements the result will be calculated with.
215
    /// \param init         The initial value for the sum.
216
    ///
217
    /// The operations in the parallel \a transform_reduce algorithm invoked
218
    /// with an execution policy object of type \a sequenced_policy
219
    /// execute in sequential order in the calling thread.
220
    ///
221
    /// The operations in the parallel \a transform_reduce algorithm invoked
222
    /// with an execution policy object of type \a parallel_policy
223
    /// or \a parallel_task_policy are permitted to execute in an unordered
224
    /// fashion in unspecified threads, and indeterminately sequenced
225
    /// within each thread.
226
    ///
227
    /// \returns  The \a transform_reduce algorithm returns a \a hpx::future<T> if
228
    ///           the execution policy is of type
229
    ///           \a sequenced_task_policy or
230
    ///           \a parallel_task_policy and
231
    ///           returns \a T otherwise.
232
    ///
233
    template <typename ExPolicy, typename FwdIter1, typename FwdIter2, typename T>
234
    hpx::parallel::util::detail::algorithm_result_t<ExPolicy, T>
235
    transform_reduce(ExPolicy&& policy, FwdIter1 first1, FwdIter1 last1,
236
        FwdIter2 first2, T init);
237

238
    /////////////////////////////////////////////////////////////////////////
239
    /// Returns the result of accumulating init with the inner products of the
240
    /// pairs formed by the elements of two ranges starting at first1 and
241
    /// first2.
242
    ///
243
    /// \note   Complexity: O(\a last - \a first) applications each of
244
    ///                     \a reduce and \a transform.
245
    ///
246
    /// \tparam InIter1     The type of the first source iterators used
247
    ///                     (deduced). This iterator type must meet the
248
    ///                     requirements of an input iterator.
249
    /// \tparam InIter2     The type of the second source iterators used
250
    ///                     (deduced). This iterator type must meet the
251
    ///                     requirements of an input iterator.
252
    /// \tparam T           The type of the value to be used as return)
253
    ///                     values (deduced).
254
    /// \param first1       Refers to the beginning of the first sequence of
255
    ///                     elements the result will be calculated with.
256
    /// \param last1        Refers to the end of the first sequence of elements
257
    ///                     the algorithm will be applied to.
258
    /// \param first2       Refers to the beginning of the second sequence of
259
    ///                     elements the result will be calculated with.
260
    /// \param init         The initial value for the sum.
261
    ///
262
    /// \returns  The \a transform_reduce algorithm returns a \a T.
263
    ///
264
    template <typename InIter1, typename InIter2, typename T>
265
    T transform_reduce(InIter1 first1, InIter1 last1, InIter2 first2, T init);
266

267
    ///////////////////////////////////////////////////////////////////////////
268
    /// Returns the result of accumulating init with the inner products of the
269
    /// pairs formed by the elements of two ranges starting at first1 and
270
    /// first2. Executed according to the policy.
271
    ///
272
    /// \note   Complexity: O(\a last - \a first) applications each of
273
    ///                     \a reduce and \a transform.
274
    /// \tparam ExPolicy    The type of the execution policy to use (deduced).
275
    ///                     It describes the manner in which the execution
276
    ///                     of the algorithm may be parallelized and the manner
277
    ///                     in which it executes the assignments.
278
    /// \tparam FwdIter1    The type of the first source iterators used
279
    ///                     (deduced). This iterator type must meet the
280
    ///                     requirements of a forward iterator.
281
    /// \tparam FwdIter2    The type of the second source iterators used
282
    ///                     (deduced). This iterator type must meet the
283
    ///                     requirements of a forward iterator.
284
    /// \tparam T           The type of the value to be used as return)
285
    ///                     values (deduced).
286
    /// \tparam Reduce      The type of the binary function object used for
287
    ///                     the multiplication operation.
288
    /// \tparam Convert     The type of the unary function object used to
289
    ///                     transform the elements of the input sequence before
290
    ///                     invoking the reduce function.
291
    ///
292
    /// \param policy       The execution policy to use for the scheduling of
293
    ///                     the iterations.
294
    /// \param first1       Refers to the beginning of the first sequence of
295
    ///                     elements the result will be calculated with.
296
    /// \param last1        Refers to the end of the first sequence of elements
297
    ///                     the algorithm will be applied to.
298
    /// \param first2       Refers to the beginning of the second sequence of
299
    ///                     elements the result will be calculated with.
300
    /// \param init         The initial value for the sum.
301
    /// \param red_op       Specifies the function (or function object) which
302
    ///                     will be invoked for the initial value and each
303
    ///                     of the return values of \a conv_op.
304
    ///                     This is a binary predicate. The
305
    ///                     signature of this predicate should be equivalent to
306
    ///                     should be equivalent to:
307
    ///                     \code
308
    ///                     Ret fun(const Type1 &a, const Type1 &b);
309
    ///                     \endcode \n
310
    ///                     The signature does not need to have const&, but
311
    ///                     the function must not modify the objects passed to
312
    ///                     it.
313
    ///                     The type \a Ret must be
314
    ///                     such that it can be implicitly converted to a type
315
    ///                     of \a T.
316
    /// \param conv_op      Specifies the function (or function object) which
317
    ///                     will be invoked for each of the input values
318
    ///                     of the sequence. This is a binary predicate. The
319
    ///                     signature of this predicate should be equivalent to
320
    ///                     \code
321
    ///                     Ret fun(const Type1 &a, const Type2 &b);
322
    ///                     \endcode \n
323
    ///                     The signature does not need to have const&, but
324
    ///                     the function must not modify the objects passed to
325
    ///                     it.
326
    ///                     The type \a Ret must be such that it can be
327
    ///                     implicitly converted to an object for the second
328
    ///                     argument type of \a red_op.
329
    ///
330
    /// The operations in the parallel \a transform_reduce algorithm invoked
331
    /// with an execution policy object of type \a sequenced_policy
332
    /// execute in sequential order in the calling thread.
333
    ///
334
    /// The operations in the parallel \a transform_reduce algorithm invoked
335
    /// with an execution policy object of type \a parallel_policy
336
    /// or \a parallel_task_policy are permitted to execute in an unordered
337
    /// fashion in unspecified threads, and indeterminately sequenced
338
    /// within each thread.
339
    ///
340
    /// \returns  The \a transform_reduce algorithm returns a \a hpx::future<T>
341
    ///           if the execution policy is of type
342
    ///           \a sequenced_task_policy or
343
    ///           \a parallel_task_policy and
344
    ///           returns \a T otherwise.
345
    ///
346
    template <typename ExPolicy, typename FwdIter1, typename FwdIter2,
347
        typename T, typename Reduce, typename Convert>
348
    hpx::parallel::util::detail::algorithm_result_t<ExPolicy, T>
349
    transform_reduce(ExPolicy&& policy, FwdIter1 first1, FwdIter1 last1,
350
        FwdIter2 first2, T init, Reduce&& red_op, Convert&& conv_op);
351

352
    ///////////////////////////////////////////////////////////////////////////
353
    /// Returns the result of accumulating init with the inner products of the
354
    /// pairs formed by the elements of two ranges starting at first1 and
355
    /// first2.
356
    ///
357
    /// \note   Complexity: O(\a last - \a first) applications each of
358
    ///                     \a reduce and \a transform.
359
    /// \tparam InIter1     The type of the first source iterators used
360
    ///                     (deduced). This iterator type must meet the
361
    ///                     requirements of an input iterator.
362
    /// \tparam InIter2     The type of the second source iterators used
363
    ///                     (deduced). This iterator type must meet the
364
    ///                     requirements of an input iterator.
365
    /// \tparam T           The type of the value to be used as return)
366
    ///                     values (deduced).
367
    /// \tparam Reduce      The type of the binary function object used for
368
    ///                     the multiplication operation.
369
    /// \tparam Convert     The type of the unary function object used to
370
    ///                     transform the elements of the input sequence before
371
    ///                     invoking the reduce function.
372
    ///
373
    /// \param first1       Refers to the beginning of the first sequence of
374
    ///                     elements the result will be calculated with.
375
    /// \param last1        Refers to the end of the first sequence of elements
376
    ///                     the algorithm will be applied to.
377
    /// \param first2       Refers to the beginning of the second sequence of
378
    ///                     elements the result will be calculated with.
379
    /// \param init         The initial value for the sum.
380
    /// \param red_op       Specifies the function (or function object) which
381
    ///                     will be invoked for the initial value and each
382
    ///                     of the return values of \a conv_op.
383
    ///                     This is a binary predicate. The
384
    ///                     signature of this predicate should be equivalent to
385
    ///                     should be equivalent to:
386
    ///                     \code
387
    ///                     Ret fun(const Type1 &a, const Type1 &b);
388
    ///                     \endcode \n
389
    ///                     The signature does not need to have const&, but
390
    ///                     the function must not modify the objects passed to
391
    ///                     it.
392
    ///                     The type \a Ret must be
393
    ///                     such that it can be implicitly converted to a type
394
    ///                     of \a T.
395
    /// \param conv_op      Specifies the function (or function object) which
396
    ///                     will be invoked for each of the input values
397
    ///                     of the sequence. This is a binary predicate. The
398
    ///                     signature of this predicate should be equivalent to
399
    ///                     \code
400
    ///                     Ret fun(const Type1 &a, const Type2 &b);
401
    ///                     \endcode \n
402
    ///                     The signature does not need to have const&, but
403
    ///                     the function must not modify the objects passed to
404
    ///                     it.
405
    ///                     The type \a Ret must be such that it can be
406
    ///                     implicitly converted to an object for the second
407
    ///                     argument type of \a red_op.
408
    ///
409
    /// \returns  The \a transform_reduce algorithm returns a \a T.
410
    ///
411
    template <typename InIter1, typename InIter2,
412
        typename T, typename Reduce, typename Convert>
413
    T transform_reduce(ExPolicy&& policy, InIter1 first1, InIter1 last1,
414
        InIter2 first2, T init, Reduce&& red_op, Convert&& conv_op);
415

416
    // clang-format on
417
}    // namespace hpx
418

419
#else    // DOXYGEN
420

421
#include <hpx/config.hpp>
422
#include <hpx/modules/concepts.hpp>
423
#include <hpx/modules/execution.hpp>
424
#include <hpx/modules/executors.hpp>
425
#include <hpx/modules/functional.hpp>
426
#include <hpx/modules/iterator_support.hpp>
427
#include <hpx/modules/pack_traversal.hpp>
428
#include <hpx/modules/tag_invoke.hpp>
429
#include <hpx/parallel/algorithms/detail/dispatch.hpp>
430
#include <hpx/parallel/algorithms/detail/distance.hpp>
431
#include <hpx/parallel/algorithms/detail/reduce.hpp>
432
#include <hpx/parallel/util/detail/algorithm_result.hpp>
433
#include <hpx/parallel/util/detail/sender_util.hpp>
434
#include <hpx/parallel/util/loop.hpp>
435
#include <hpx/parallel/util/partitioner.hpp>
436
#include <hpx/parallel/util/zip_iterator.hpp>
437

438
#include <algorithm>
439
#include <cstddef>
440
#include <iterator>
441
#include <type_traits>
442
#include <utility>
443

444
namespace hpx::parallel {
445

446
    ///////////////////////////////////////////////////////////////////////////
447
    // transform_reduce
448
    namespace detail {
449

450
        HPX_CXX_EXPORT template <typename T>
451
        struct transform_reduce : public algorithm<transform_reduce<T>, T>
452
        {
453
            constexpr transform_reduce() noexcept
454
              : algorithm<transform_reduce, T>("transform_reduce")
455
            {
456
            }
457

458
            template <typename ExPolicy, typename Iter, typename Sent,
459
                typename T_, typename Reduce, typename Convert>
460
            static constexpr T sequential(ExPolicy&& policy, Iter first,
461
                Sent last, T_&& init, Reduce&& r, Convert&& conv)
462
            {
463
                return detail::sequential_reduce<ExPolicy>(
464
                    HPX_FORWARD(ExPolicy, policy), first, last,
465
                    HPX_FORWARD(T_, init), HPX_FORWARD(Reduce, r),
466
                    HPX_FORWARD(Convert, conv));
467
            }
468

469
            template <typename ExPolicy, typename Iter, typename Sent,
470
                typename T_, typename Reduce, typename Convert>
471
            static decltype(auto) parallel(ExPolicy&& policy, Iter first,
2✔
472
                Sent last, T_&& init, Reduce&& r, Convert&& conv)
473
            {
474
                constexpr bool has_scheduler_executor =
475
                    hpx::execution_policy_has_scheduler_executor_v<ExPolicy>;
2✔
476

477
                if constexpr (!has_scheduler_executor)
×
478
                {
479
                    if (first == last)
480
                    {
481
                        T init_ = init;
482
                        return util::detail::algorithm_result<ExPolicy, T>::get(
20✔
483
                            HPX_MOVE(init_));
484
                    }
20✔
485
                }
20✔
486

20✔
487
                auto f1 = [r, conv](
488
                              Iter part_begin, std::size_t part_size) mutable {
489
                    auto val = HPX_INVOKE(conv, *part_begin);
2✔
490
                    return detail::sequential_reduce<ExPolicy>(
491
                        ++part_begin, --part_size, HPX_MOVE(val), r, conv);
492
                };
6✔
493

494
                return util::partitioner<ExPolicy, T>::call(
495
                    HPX_FORWARD(ExPolicy, policy), first,
496
                    detail::distance(first, last), HPX_MOVE(f1),
2✔
497
                    hpx::unwrapping([init = HPX_FORWARD(T_, init),
2✔
498
                                        r = HPX_FORWARD(Reduce, r)](
499
                                        auto&& results) mutable -> T {
500
                        return detail::sequential_reduce<ExPolicy>(
501
                            hpx::util::begin(results), hpx::util::size(results),
502
                            init, r);
503
                    }));
504
            }
505
        };
506
    }    // namespace detail
507

508
    ///////////////////////////////////////////////////////////////////////////
509
    // transform_reduce_binary
510
    namespace detail {
511

512
        HPX_CXX_EXPORT template <typename T>
513
        struct transform_reduce_binary
514
          : public algorithm<transform_reduce_binary<T>, T>
515
        {
516
            constexpr transform_reduce_binary() noexcept
517
              : algorithm<transform_reduce_binary, T>("transform_reduce_binary")
518
            {
519
            }
520

521
            template <typename ExPolicy, typename Iter, typename Sent,
522
                typename Iter2, typename T_, typename Op1, typename Op2>
523
            static constexpr T sequential(ExPolicy&& /* policy */, Iter first1,
524
                Sent last1, Iter2 first2, T_ init, Op1&& op1, Op2&& op2)
525
            {
526
                return detail::sequential_reduce<ExPolicy>(first1, last1,
527
                    first2, HPX_FORWARD(T_, init), HPX_FORWARD(Op1, op1),
528
                    HPX_FORWARD(Op2, op2));
529
            }
530

531
            template <typename ExPolicy, typename Iter, typename Sent,
532
                typename Iter2, typename T_, typename Op1, typename Op2>
533
            static decltype(auto) parallel(ExPolicy&& policy, Iter first1,
534
                Sent last1, Iter2 first2, T_&& init, Op1&& op1, Op2&& op2)
535
            {
536
                using result = util::detail::algorithm_result<ExPolicy, T>;
537
                using zip_iterator = hpx::util::zip_iterator<Iter, Iter2>;
538
                using difference_type =
539
                    typename std::iterator_traits<Iter>::difference_type;
540
                constexpr bool has_scheduler_executor =
541
                    hpx::execution_policy_has_scheduler_executor_v<ExPolicy>;
542

543
                if constexpr (!has_scheduler_executor)
544
                {
545
                    if (first1 == last1)
546
                    {
547
                        T init_ = init;
548
                        return result::get(HPX_MOVE(init_));
549
                    }
550
                }
551

552
                difference_type count = detail::distance(first1, last1);
553

554
                auto f1 = [op1, op2 = HPX_FORWARD(Op2, op2)](
555
                              zip_iterator part_begin,
556
                              std::size_t part_size) mutable -> T {
557
                    auto iters = part_begin.get_iterator_tuple();
558
                    Iter it1 = hpx::get<0>(iters);
559
                    Iter2 it2 = hpx::get<1>(iters);
560

561
                    Iter last = it1;
562
                    std::advance(last, part_size);
563

564
                    auto&& r = HPX_INVOKE(op2, *it1, *it2);
565
                    ++it1;
566
                    ++it2;
567

568
                    return detail::sequential_reduce<ExPolicy>(it1, last, it2,
569
                        HPX_MOVE(r), HPX_FORWARD(Op1, op1),
570
                        HPX_FORWARD(Op2, op2));
571
                };
572

573
                return util::partitioner<ExPolicy, T>::call(
574
                    HPX_FORWARD(ExPolicy, policy), zip_iterator(first1, first2),
575
                    count, HPX_MOVE(f1),
576
                    [init = HPX_FORWARD(T_, init), op1 = HPX_FORWARD(Op1, op1)](
577
                        auto&& results) mutable -> T {
578
                        T ret = HPX_MOVE(init);
579
                        for (auto&& result : results)
580
                        {
581
                            ret = HPX_INVOKE(
582
                                op1, HPX_MOVE(ret), hpx::unwrap(result));
583
                        }
584
                        return ret;
585
                    });
586
            }
587
        };
588
    }    // namespace detail
589
}    // namespace hpx::parallel
590

591
namespace hpx {
592

593
    ///////////////////////////////////////////////////////////////////////////
594
    // CPO for hpx::transform_reduce
595
    HPX_CXX_EXPORT inline constexpr struct transform_reduce_t final
596
      : hpx::detail::tag_parallel_algorithm<transform_reduce_t>
597
    {
598
    private:
599
        template <typename ExPolicy, typename FwdIter, typename T,
600
            typename Reduce, typename Convert>
601
        // clang-format off
602
            requires (
603
                hpx::is_execution_policy_v<ExPolicy> &&
604
                hpx::traits::is_iterator_v<FwdIter> &&
605
                hpx::is_invocable_v<Convert,
606
                   typename std::iterator_traits<FwdIter>::value_type> &&
607
                hpx::is_invocable_v<Reduce,
608
                   hpx::util::invoke_result_t<Convert,
609
                       typename std::iterator_traits<FwdIter>::value_type>,
610
                   hpx::util::invoke_result_t<Convert,
611
                       typename std::iterator_traits<FwdIter>::value_type>
612
                >
613
            )
614
        // clang-format on
615
        friend decltype(auto) tag_fallback_invoke(transform_reduce_t,
616
            ExPolicy&& policy, FwdIter first, FwdIter last, T init,
617
            Reduce red_op, Convert conv_op)
618
        {
619
            static_assert(hpx::traits::is_forward_iterator_v<FwdIter>,
620
                "Requires at least forward iterator.");
621

622
            return hpx::parallel::detail::transform_reduce<T>().call(
623
                HPX_FORWARD(ExPolicy, policy), first, last, HPX_MOVE(init),
624
                HPX_MOVE(red_op), HPX_MOVE(conv_op));
625
        }
626

627
        template <typename InIter, typename T, typename Reduce,
628
            typename Convert>
629
        // clang-format off
630
            requires (
631
                hpx::traits::is_iterator_v<InIter> &&
632
                hpx::is_invocable_v<Convert,
633
                   typename std::iterator_traits<InIter>::value_type> &&
634
                hpx::is_invocable_v<Reduce,
635
                   hpx::util::invoke_result_t<Convert,
636
                       typename std::iterator_traits<InIter>::value_type>,
637
                   hpx::util::invoke_result_t<Convert,
638
                       typename std::iterator_traits<InIter>::value_type>
639
                >
640
            )
641
        // clang-format on
642
        friend T tag_fallback_invoke(transform_reduce_t, InIter first,
643
            InIter last, T init, Reduce red_op, Convert conv_op)
644
        {
645
            static_assert(hpx::traits::is_input_iterator_v<InIter>,
646
                "Requires at least input iterator.");
647

648
            return hpx::parallel::detail::transform_reduce<T>().call(
649
                hpx::execution::seq, first, last, HPX_MOVE(init),
650
                HPX_MOVE(red_op), HPX_MOVE(conv_op));
651
        }
652

653
        template <typename ExPolicy, typename FwdIter1, typename FwdIter2,
654
            typename T>
655
        // clang-format off
656
            requires (
657
                hpx::is_execution_policy_v<ExPolicy> &&
658
                hpx::traits::is_iterator_v<FwdIter1> &&
659
                hpx::traits::is_iterator_v<FwdIter2>
660
            )
661
        // clang-format on
662
        friend decltype(auto) tag_fallback_invoke(transform_reduce_t,
663
            ExPolicy&& policy, FwdIter1 first1, FwdIter1 last1, FwdIter2 first2,
664
            T init)
665
        {
666
            static_assert(hpx::traits::is_forward_iterator_v<FwdIter1>,
667
                "Requires at least forward iterator.");
668
            static_assert(hpx::traits::is_forward_iterator_v<FwdIter2>,
669
                "Requires at least forward iterator.");
670

671
            return hpx::parallel::detail::transform_reduce_binary<T>().call(
672
                HPX_FORWARD(ExPolicy, policy), first1, last1, first2,
673
                HPX_MOVE(init), hpx::parallel::detail::plus(),
674
                hpx::parallel::detail::multiplies());
675
        }
676

677
        template <typename InIter1, typename InIter2, typename T>
678
        // clang-format off
679
            requires (
680
                hpx::traits::is_iterator_v<InIter1> &&
681
                hpx::traits::is_iterator_v<InIter2>
682
            )
683
        // clang-format on
684
        friend T tag_fallback_invoke(transform_reduce_t, InIter1 first1,
685
            InIter1 last1, InIter2 first2, T init)
686
        {
687
            static_assert(hpx::traits::is_input_iterator_v<InIter1>,
688
                "Requires at least input iterator.");
689
            static_assert(hpx::traits::is_input_iterator_v<InIter2>,
690
                "Requires at least input iterator.");
691

692
            return hpx::parallel::detail::transform_reduce_binary<T>().call(
693
                hpx::execution::seq, first1, last1, first2, HPX_MOVE(init),
694
                hpx::parallel::detail::plus(),
695
                hpx::parallel::detail::multiplies());
696
        }
697

698
        template <typename ExPolicy, typename FwdIter1, typename FwdIter2,
699
            typename T, typename Reduce, typename Convert>
700
        // clang-format off
701
            requires (
702
                hpx::is_execution_policy_v<ExPolicy> &&
703
                hpx::traits::is_iterator_v<FwdIter1> &&
704
                hpx::traits::is_iterator_v<FwdIter2> &&
705
                hpx::is_invocable_v<Convert,
706
                    typename std::iterator_traits<FwdIter1>::value_type,
707
                    typename std::iterator_traits<FwdIter2>::value_type> &&
708
                hpx::is_invocable_v<Reduce,
709
                    hpx::util::invoke_result_t<Convert,
710
                        typename std::iterator_traits<FwdIter1>::value_type,
711
                        typename std::iterator_traits<FwdIter2>::value_type>,
712
                    hpx::util::invoke_result_t<Convert,
713
                        typename std::iterator_traits<FwdIter1>::value_type,
714
                        typename std::iterator_traits<FwdIter2>::value_type>
715
                >
716
            )
717
        // clang-format on
718
        friend decltype(auto) tag_fallback_invoke(transform_reduce_t,
719
            ExPolicy&& policy, FwdIter1 first1, FwdIter1 last1, FwdIter2 first2,
720
            T init, Reduce red_op, Convert conv_op)
721
        {
722
            static_assert(hpx::traits::is_forward_iterator_v<FwdIter1>,
723
                "Requires at least forward iterator.");
724
            static_assert(hpx::traits::is_forward_iterator_v<FwdIter2>,
725
                "Requires at least forward iterator.");
726

727
            return hpx::parallel::detail::transform_reduce_binary<T>().call(
728
                HPX_FORWARD(ExPolicy, policy), first1, last1, first2,
729
                HPX_MOVE(init), HPX_MOVE(red_op), HPX_MOVE(conv_op));
730
        }
731

732
        template <typename InIter1, typename InIter2, typename T,
733
            typename Reduce, typename Convert>
734
        // clang-format off
735
            requires (
736
                hpx::traits::is_iterator_v<InIter1> &&
737
                hpx::traits::is_iterator_v<InIter2> &&
738
                hpx::is_invocable_v<Convert,
739
                    typename std::iterator_traits<InIter1>::value_type,
740
                    typename std::iterator_traits<InIter2>::value_type> &&
741
                hpx::is_invocable_v<Reduce,
742
                    hpx::util::invoke_result_t<Convert,
743
                        typename std::iterator_traits<InIter1>::value_type,
744
                        typename std::iterator_traits<InIter2>::value_type>,
745
                    hpx::util::invoke_result_t<Convert,
746
                        typename std::iterator_traits<InIter1>::value_type,
747
                        typename std::iterator_traits<InIter2>::value_type>
748
                >
749
            )
750
        // clang-format on
751
        friend T tag_fallback_invoke(transform_reduce_t, InIter1 first1,
752
            InIter1 last1, InIter2 first2, T init, Reduce red_op,
753
            Convert conv_op)
754
        {
755
            static_assert(hpx::traits::is_input_iterator_v<InIter1>,
756
                "Requires at least input iterator.");
757
            static_assert(hpx::traits::is_input_iterator_v<InIter2>,
758
                "Requires at least input iterator.");
759

760
            return hpx::parallel::detail::transform_reduce_binary<T>().call(
761
                hpx::execution::seq, first1, last1, first2, HPX_MOVE(init),
762
                HPX_MOVE(red_op), HPX_MOVE(conv_op));
763
        }
764
    } transform_reduce{};
765
}    // namespace hpx
766

767
#endif    // DOXYGEN
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc