KaMPIng 0.2.1
(Near) zero-overhead MPI wrapper for C++
Loading...
Searching...
No Matches
reduce_ops.hpp
Go to the documentation of this file.
1// This file is part of KaMPIng.
2//
3// Copyright 2021-2026 The KaMPIng Authors
4//
5// KaMPIng is free software : you can redistribute it and/or modify it under the terms of the GNU Lesser General Public
6// License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
7// version. KaMPIng is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
8// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
9// for more details.
10//
11// You should have received a copy of the GNU Lesser General Public License along with KaMPIng. If not, see
12// <https://www.gnu.org/licenses/>.
13
14/// @file
15/// @brief MPI reduction operation functor vocabulary, type traits, and RAII handle.
16///
17/// Provides:
18/// - `kamping::ops::` — functor types and commutativity tags
19/// - `kamping::types::mpi_operation_traits<Op, T>` — maps (functor, element type) → `MPI_Op`
20/// - `kamping::types::ScopedOp` — RAII wrapper for an `MPI_Op`
21/// - `kamping::types::ScopedFunctorOp` — creates an `MPI_Op` from a default-constructible C++ functor
22/// - `kamping::types::ScopedCallbackOp` — creates an `MPI_Op` from a raw MPI callback function pointer
23/// - `kamping::types::with_operation_functor` — maps a runtime `MPI_Op` to its functor
24
25#pragma once
26
27#include <algorithm>
28#include <functional>
29#include <limits>
30#include <type_traits>
31
32#include <mpi.h>
33
34#include "kamping/kassert/kassert.hpp"
36
37// ---------------------------------------------------------------------------
38// kamping::ops — functor vocabulary
39// ---------------------------------------------------------------------------
40
41namespace kamping::ops::internal {
42
43/// @brief Wrapper struct for std::max.
44///
45/// `std::max` is a function, not a function object. This wrapper allows template matching for
46/// builtin MPI operation detection. The `<void>` specialization uses type deduction.
47/// @tparam T the type of the operands
48template <typename T>
49struct max_impl {
50 /// @brief Returns the maximum of the two parameters.
51 /// @param lhs the first operand
52 /// @param rhs the second operand
53 constexpr T operator()(T const& lhs, T const& rhs) const {
54 return std::max(lhs, rhs);
55 }
56};
57/// @brief Template specialization of max_impl without type parameter, leaving the operand type to be deduced.
58template <>
59struct max_impl<void> {
60 /// @brief Returns the maximum of the two parameters.
61 /// @tparam T the type of the operands
62 /// @param lhs the first operand
63 /// @param rhs the second operand
64 template <typename T>
65 constexpr auto operator()(T const& lhs, T const& rhs) const {
66 return std::max(lhs, rhs);
67 }
68};
69
70/// @brief Wrapper struct for std::min (same rationale as max_impl).
71/// @tparam T the type of the operands
72template <typename T>
73struct min_impl {
74 /// @brief Returns the minimum of the two parameters.
75 /// @param lhs the first operand
76 /// @param rhs the second operand
77 constexpr T operator()(T const& lhs, T const& rhs) const {
78 return std::min(lhs, rhs);
79 }
80};
81/// @brief Template specialization of min_impl without type parameter, leaving the operand type to be deduced.
82template <>
83struct min_impl<void> {
84 /// @brief Returns the minimum of the two parameters.
85 /// @tparam T the type of the operands
86 /// @param lhs the first operand
87 /// @param rhs the second operand
88 template <typename T>
89 constexpr auto operator()(T const& lhs, T const& rhs) const {
90 return std::min(lhs, rhs);
91 }
92};
93
94/// @brief Logical XOR function object (no STL equivalent).
95/// @tparam T type of the operands
96template <typename T>
98 /// @brief Returns the logical XOR of the two parameters.
99 /// @param lhs the first operand
100 /// @param rhs the second operand
101 constexpr bool operator()(T const& lhs, T const& rhs) const {
102 return (lhs && !rhs) || (!lhs && rhs);
103 }
104};
105/// @brief Template specialization of logical_xor_impl without type parameter, leaving operand types to be deduced.
106template <>
108 /// @brief Returns the logical XOR of the two parameters.
109 /// @tparam T type of the left operand
110 /// @tparam S type of the right operand
111 /// @param lhs the left operand
112 /// @param rhs the right operand
113 template <typename T, typename S>
114 constexpr bool operator()(T const& lhs, S const& rhs) const {
115 return (lhs && !rhs) || (!lhs && rhs);
116 }
117};
118
119/// @brief Tag for a commutative user-defined reduce operation.
121/// @brief Tag for a non-commutative user-defined reduce operation.
123/// @brief Tag for a reduce operation without a manually declared commutativity (builtin ops only).
125
126} // namespace kamping::ops::internal
127
128namespace kamping::ops {
129
130/// @brief Builtin maximum operation (`MPI_MAX`).
131template <typename T = void>
133
134/// @brief Builtin minimum operation (`MPI_MIN`).
135template <typename T = void>
137
138/// @brief Builtin summation (`MPI_SUM`).
139template <typename T = void>
140using plus = std::plus<T>;
141
142/// @brief Builtin multiplication (`MPI_PROD`).
143template <typename T = void>
144using multiplies = std::multiplies<T>;
145
146/// @brief Builtin logical AND (`MPI_LAND`).
147template <typename T = void>
148using logical_and = std::logical_and<T>;
149
150/// @brief Builtin bitwise AND (`MPI_BAND`).
151template <typename T = void>
152using bit_and = std::bit_and<T>;
153
154/// @brief Builtin logical OR (`MPI_LOR`).
155template <typename T = void>
156using logical_or = std::logical_or<T>;
157
158/// @brief Builtin bitwise OR (`MPI_BOR`).
159template <typename T = void>
160using bit_or = std::bit_or<T>;
161
162/// @brief Builtin logical XOR (`MPI_LXOR`).
163template <typename T = void>
165
166/// @brief Builtin bitwise XOR (`MPI_BXOR`).
167template <typename T = void>
168using bit_xor = std::bit_xor<T>;
169
170/// @brief Null operation (`MPI_OP_NULL`).
171template <typename T = void>
172struct null {};
173
174[[maybe_unused]] constexpr internal::commutative_tag commutative{}; ///< Tag: operation is commutative.
175[[maybe_unused]] constexpr internal::non_commutative_tag non_commutative{}; ///< Tag: operation is non-commutative.
176
177} // namespace kamping::ops
178
179// ---------------------------------------------------------------------------
180// kamping::types — mpi_operation_traits, ScopedOp, with_operation_functor
181// ---------------------------------------------------------------------------
182
183namespace kamping::types {
184
185#ifdef KAMPING_DOXYGEN_ONLY
186/// @brief Type trait that maps a (functor type, element type) pair to its builtin `MPI_Op`.
187///
188/// `mpi_operation_traits<Op, T>::is_builtin` is `true` when `Op` applied to `T` corresponds to
189/// a predefined MPI operation constant. When `true`, `::op()` returns that constant and
190/// `::identity` holds the identity element for the operation.
191///
192/// Example:
193/// @code
194/// mpi_operation_traits<kamping::ops::plus<>, int>::is_builtin // true
195/// mpi_operation_traits<kamping::ops::plus<>, int>::op() // MPI_SUM
196/// mpi_operation_traits<std::plus<>, int>::is_builtin // true
197/// mpi_operation_traits<std::minus<>, int>::is_builtin // false
198/// @endcode
199/// @tparam Op Functor type of the operation.
200/// @tparam T Element type to apply the operation to.
201template <typename Op, typename T>
203 /// @brief \c true if \c Op applied to \c T corresponds to a predefined MPI operation constant.
204 static constexpr bool is_builtin;
205
206 /// @brief The identity element for this operation and data type.
207 ///
208 /// Only defined when \c is_builtin is \c true.
209 static constexpr T identity;
210
211 /// @brief Returns the predefined \c MPI_Op constant for this operation.
212 ///
213 /// Only defined when \c is_builtin is \c true.
214 static MPI_Op op();
215};
216#else
217
218template <typename Op, typename T, typename Enable = void>
220 static constexpr bool is_builtin = false;
221};
222
223template <typename T, typename S>
224struct mpi_operation_traits<
225 kamping::ops::max<S>,
226 T,
227 std::enable_if_t<(std::is_same_v<S, void> || std::is_same_v<T, S>)&&(
228 builtin_type<T>::category == TypeCategory::integer || builtin_type<T>::category == TypeCategory::floating
229 )> > {
230 static constexpr bool is_builtin = true;
231 static constexpr T identity = std::numeric_limits<T>::lowest();
232 static MPI_Op op() {
233 return MPI_MAX;
234 }
235};
236
237template <typename T, typename S>
238struct mpi_operation_traits<
239 kamping::ops::min<S>,
240 T,
241 std::enable_if_t<(std::is_same_v<S, void> || std::is_same_v<T, S>)&&(
242 builtin_type<T>::category == TypeCategory::integer || builtin_type<T>::category == TypeCategory::floating
243 )> > {
244 static constexpr bool is_builtin = true;
245 static constexpr T identity = std::numeric_limits<T>::max();
246 static MPI_Op op() {
247 return MPI_MIN;
248 }
249};
250
251template <typename T, typename S>
252struct mpi_operation_traits<
253 kamping::ops::plus<S>,
254 T,
255 std::enable_if_t<(std::is_same_v<S, void> || std::is_same_v<T, S>)&&(
256 builtin_type<T>::category == TypeCategory::integer || builtin_type<T>::category == TypeCategory::floating
257 || builtin_type<T>::category == TypeCategory::complex
258 )> > {
259 static constexpr bool is_builtin = true;
260 static constexpr T identity = 0;
261 static MPI_Op op() {
262 return MPI_SUM;
263 }
264};
265
266template <typename T, typename S>
267struct mpi_operation_traits<
268 kamping::ops::multiplies<S>,
269 T,
270 std::enable_if_t<(std::is_same_v<S, void> || std::is_same_v<T, S>)&&(
271 builtin_type<T>::category == TypeCategory::integer || builtin_type<T>::category == TypeCategory::floating
272 || builtin_type<T>::category == TypeCategory::complex
273 )> > {
274 static constexpr bool is_builtin = true;
275 static constexpr T identity = 1;
276 static MPI_Op op() {
277 return MPI_PROD;
278 }
279};
280
281template <typename T, typename S>
282struct mpi_operation_traits<
283 kamping::ops::logical_and<S>,
284 T,
285 std::enable_if_t<(std::is_same_v<S, void> || std::is_same_v<T, S>)&&(
286 builtin_type<T>::category == TypeCategory::integer || builtin_type<T>::category == TypeCategory::logical
287 )> > {
288 static constexpr bool is_builtin = true;
289 static constexpr T identity = true;
290 static MPI_Op op() {
291 return MPI_LAND;
292 }
293};
294
295template <typename T, typename S>
296struct mpi_operation_traits<
297 kamping::ops::logical_or<S>,
298 T,
299 std::enable_if_t<(std::is_same_v<S, void> || std::is_same_v<T, S>)&&(
300 builtin_type<T>::category == TypeCategory::integer || builtin_type<T>::category == TypeCategory::logical
301 )> > {
302 static constexpr bool is_builtin = true;
303 static constexpr T identity = false;
304 static MPI_Op op() {
305 return MPI_LOR;
306 }
307};
308
309template <typename T, typename S>
310struct mpi_operation_traits<
311 kamping::ops::logical_xor<S>,
312 T,
313 std::enable_if_t<(std::is_same_v<S, void> || std::is_same_v<T, S>)&&(
314 builtin_type<T>::category == TypeCategory::integer || builtin_type<T>::category == TypeCategory::logical
315 )> > {
316 static constexpr bool is_builtin = true;
317 static constexpr T identity = false;
318 static MPI_Op op() {
319 return MPI_LXOR;
320 }
321};
322
323template <typename T, typename S>
324struct mpi_operation_traits<
325 kamping::ops::bit_and<S>,
326 T,
327 std::enable_if_t<(std::is_same_v<S, void> || std::is_same_v<T, S>)&&(
328 builtin_type<T>::category == TypeCategory::integer || builtin_type<T>::category == TypeCategory::byte
329 )> > {
330 static constexpr bool is_builtin = true;
331 static constexpr T identity = ~(T{0});
332 static MPI_Op op() {
333 return MPI_BAND;
334 }
335};
336
337template <typename T, typename S>
338struct mpi_operation_traits<
339 kamping::ops::bit_or<S>,
340 T,
341 std::enable_if_t<(std::is_same_v<S, void> || std::is_same_v<T, S>)&&(
342 builtin_type<T>::category == TypeCategory::integer || builtin_type<T>::category == TypeCategory::byte
343 )> > {
344 static constexpr bool is_builtin = true;
345 static constexpr T identity = T{0};
346 static MPI_Op op() {
347 return MPI_BOR;
348 }
349};
350
351template <typename T, typename S>
352struct mpi_operation_traits<
353 kamping::ops::bit_xor<S>,
354 T,
355 std::enable_if_t<(std::is_same_v<S, void> || std::is_same_v<T, S>)&&(
356 builtin_type<T>::category == TypeCategory::integer || builtin_type<T>::category == TypeCategory::byte
357 )> > {
358 static constexpr bool is_builtin = true;
359 static constexpr T identity = T{0};
360 static MPI_Op op() {
361 return MPI_BXOR;
362 }
363};
364
365#endif // KAMPING_DOXYGEN_ONLY
366
367// ---------------------------------------------------------------------------
368// ScopedOp — RAII handle for MPI_Op
369// ---------------------------------------------------------------------------
370
371/// @brief RAII wrapper for an `MPI_Op`.
372///
373/// Calls `MPI_Op_free` on destruction only when `owns` is true (i.e. the op was created via
374/// `MPI_Op_create` for a user-defined functor). Predefined MPI constants (`MPI_SUM`,
375/// `MPI_MAX`, …) are never freed.
376///
377/// Analogous to `ScopedDatatype` for `MPI_Datatype`.
378class ScopedOp {
379public:
380 /// @brief Constructs an empty, non-owning handle (`MPI_OP_NULL`).
381 ScopedOp() noexcept : _op(MPI_OP_NULL), _owns(false) {}
382
383 /// @brief Wrap an existing `MPI_Op`.
384 /// @param op The op to wrap.
385 /// @param owns If `true`, `MPI_Op_free` is called on destruction.
386 ScopedOp(MPI_Op op, bool owns) noexcept : _op(op), _owns(owns) {}
387
388 ScopedOp(ScopedOp const&) = delete;
389 ScopedOp& operator=(ScopedOp const&) = delete;
390
391 /// @brief Move constructor. Transfers ownership; the moved-from handle no longer frees the op.
392 ScopedOp(ScopedOp&& other) noexcept : _op(other._op), _owns(other._owns) {
393 other._owns = false;
394 }
395 /// @brief Move assignment. Frees any currently owned op, then transfers ownership.
397 if (this != &other) {
398 _free();
399 _op = other._op;
400 _owns = other._owns;
401 other._owns = false;
402 }
403 return *this;
404 }
405
406 ~ScopedOp() {
407 _free();
408 }
409
410 /// @returns The underlying `MPI_Op`.
412 return _op;
413 }
414
415private:
416 void _free() noexcept {
417 if (_owns) {
418 int const err = MPI_Op_free(&_op);
419 KAMPING_ASSERT(err == MPI_SUCCESS, "MPI_Op_free failed");
420 _owns = false;
421 }
422 }
423
424 MPI_Op _op;
425 bool _owns;
426};
427
428// ---------------------------------------------------------------------------
429// ScopedFunctorOp — MPI_Op_create from a default-constructible C++ functor
430// ---------------------------------------------------------------------------
431
432/// @brief RAII handle that creates an `MPI_Op` from a default-constructible C++ functor.
433///
434/// Calls `MPI_Op_create` on construction and `MPI_Op_free` on destruction.
435/// The functor is invoked via `MPI_Op_create`'s callback and must be default-constructible
436/// (i.e. stateless or state carried via static variables). For capturing lambdas use `ScopedCallbackOp`.
437///
438/// @tparam is_commutative Whether the operation is commutative.
439/// @tparam T Element type the functor operates on.
440/// @tparam Op Functor type. Must be default-constructible and callable as `T(T const&, T const&)`.
441template <bool is_commutative, typename T, typename Op>
443 static_assert(
444 std::is_default_constructible_v<Op>,
445 "ScopedFunctorOp requires a default-constructible functor. Use ScopedCallbackOp for lambdas."
446 );
447 static_assert(std::is_invocable_r_v<T, Op, T const&, T const&>, "Op must be callable as T(T const&, T const&).");
448
449public:
450 /// @brief Creates an `MPI_Op` for the given functor.
451 ScopedFunctorOp(Op op) : _functor(std::move(op)), _op(_make_scoped_op()) {}
452
453 ScopedFunctorOp(ScopedFunctorOp const&) = delete;
454 ScopedFunctorOp& operator=(ScopedFunctorOp const&) = delete;
456 ScopedFunctorOp& operator=(ScopedFunctorOp&&) = delete;
457
458 /// @returns The underlying `MPI_Op`. Do not free manually — the destructor does it.
460 return _op.get();
461 }
462
463 /// @brief Applies the functor to two values.
464 T operator()(T const& lhs, T const& rhs) const {
465 return _functor(lhs, rhs);
466 }
467
468private:
469 /// @brief MPI callback: applies a default-constructed `Op` element-wise.
470 static void _execute(void* invec, void* inoutvec, int* len, MPI_Datatype* /*datatype*/) {
471 T* in = static_cast<T*>(invec);
472 T* inout = static_cast<T*>(inoutvec);
473 std::transform(in, in + *len, inout, inout, Op{});
474 }
475
476 static ScopedOp _make_scoped_op() {
477 MPI_Op raw;
478 MPI_Op_create(_execute, static_cast<int>(is_commutative), &raw);
479 return ScopedOp{raw, true};
480 }
481
482 Op _functor;
483 ScopedOp _op;
484};
485
486// ---------------------------------------------------------------------------
487// ScopedCallbackOp — MPI_Op_create from a raw MPI callback function pointer
488// ---------------------------------------------------------------------------
489
490/// @brief RAII handle that creates an `MPI_Op` from a raw MPI callback function pointer.
491///
492/// Calls `MPI_Op_create` on construction and `MPI_Op_free` on destruction.
493/// A default-constructed `ScopedCallbackOp` is empty (`MPI_OP_NULL`, non-owning).
494/// Supports move construction and assignment; the moved-from handle becomes empty.
495///
496/// Typically used for lambdas with captures, where the lambda is stored separately and a
497/// raw function pointer (via a static trampoline) is passed to `MPI_Op_create`.
498///
499/// @tparam is_commutative Whether the operation is commutative.
500template <bool is_commutative>
502public:
503 /// @brief The MPI callback signature expected by `MPI_Op_create`.
504 using callback_type = void (*)(void*, void*, int*, MPI_Datatype*);
505
506 /// @brief Constructs an empty, non-owning handle (`MPI_OP_NULL`).
508
509 /// @brief Creates an `MPI_Op` for the given callback.
510 /// @param ptr Non-null MPI callback function pointer.
511 explicit ScopedCallbackOp(callback_type ptr) : _op(_make_scoped_op(ptr)) {
512 KAMPING_ASSERT(ptr != nullptr);
513 }
514
515 ScopedCallbackOp(ScopedCallbackOp const&) = delete;
516 ScopedCallbackOp& operator=(ScopedCallbackOp const&) = delete;
517
518 /// @brief Move constructor. The moved-from handle becomes empty.
520 /// @brief Move assignment. Frees any currently owned op, then takes ownership.
522
523 /// @returns The underlying `MPI_Op` (`MPI_OP_NULL` if default-constructed). Do not free manually.
525 return _op.get();
526 }
527
528private:
529 static ScopedOp _make_scoped_op(callback_type ptr) {
530 MPI_Op raw;
531 MPI_Op_create(ptr, static_cast<int>(is_commutative), &raw);
532 return ScopedOp{raw, true};
533 }
534
535 ScopedOp _op; // default-constructed: MPI_OP_NULL, non-owning
536};
537
538// ---------------------------------------------------------------------------
539// with_operation_functor — runtime MPI_Op → functor dispatch
540// ---------------------------------------------------------------------------
541
542/// @brief Calls `func` with the functor object corresponding to the given builtin `MPI_Op`.
543///
544/// For unknown ops, calls `func(kamping::ops::null<>{})`. Useful for implementing
545/// `MPI_Reduce_local`-style helpers that need a C++ callable for a runtime `MPI_Op`.
546///
547/// @tparam Functor Callable accepting any `kamping::ops::*` functor type.
548template <typename Functor>
549auto with_operation_functor(MPI_Op op, Functor&& func) {
550 if (op == MPI_MAX)
551 return func(ops::max<>{});
552 else if (op == MPI_MIN)
553 return func(ops::min<>{});
554 else if (op == MPI_SUM)
555 return func(ops::plus<>{});
556 else if (op == MPI_PROD)
557 return func(ops::multiplies<>{});
558 else if (op == MPI_LAND)
559 return func(ops::logical_and<>{});
560 else if (op == MPI_LOR)
561 return func(ops::logical_or<>{});
562 else if (op == MPI_LXOR)
563 return func(ops::logical_xor<>{});
564 else if (op == MPI_BAND)
565 return func(ops::bit_and<>{});
566 else if (op == MPI_BOR)
567 return func(ops::bit_or<>{});
568 else if (op == MPI_BXOR)
569 return func(ops::bit_xor<>{});
570 else
571 return func(ops::null<>{});
572}
573
574} // namespace kamping::types
STL-compatible allocator for requesting memory using the builtin MPI allocator.
Definition allocator.hpp:32
RAII handle that creates an MPI_Op from a raw MPI callback function pointer.
Definition reduce_ops.hpp:501
MPI_Op get() const noexcept
Definition reduce_ops.hpp:524
void(*)(void *, void *, int *, MPI_Datatype *) callback_type
The MPI callback signature expected by MPI_Op_create.
Definition reduce_ops.hpp:504
ScopedCallbackOp(ScopedCallbackOp &&) noexcept=default
Move constructor. The moved-from handle becomes empty.
ScopedCallbackOp() noexcept=default
Constructs an empty, non-owning handle (MPI_OP_NULL).
RAII handle that creates an MPI_Op from a default-constructible C++ functor.
Definition reduce_ops.hpp:442
T operator()(T const &lhs, T const &rhs) const
Applies the functor to two values.
Definition reduce_ops.hpp:464
MPI_Op get() const noexcept
Definition reduce_ops.hpp:459
ScopedFunctorOp(Op op)
Creates an MPI_Op for the given functor.
Definition reduce_ops.hpp:451
RAII wrapper for an MPI_Op.
Definition reduce_ops.hpp:378
ScopedOp & operator=(ScopedOp &&other) noexcept
Move assignment. Frees any currently owned op, then transfers ownership.
Definition reduce_ops.hpp:396
MPI_Op get() const noexcept
Definition reduce_ops.hpp:411
ScopedOp(MPI_Op op, bool owns) noexcept
Wrap an existing MPI_Op.
Definition reduce_ops.hpp:386
ScopedOp() noexcept
Constructs an empty, non-owning handle (MPI_OP_NULL).
Definition reduce_ops.hpp:381
ScopedOp(ScopedOp &&other) noexcept
Move constructor. Transfers ownership; the moved-from handle no longer frees the op.
Definition reduce_ops.hpp:392
internal::OperationBuilder< Op, Commutative > op(Op &&op, Commutative commute=ops::internal::undefined_commutative_tag{})
Passes a reduction operation to ther underlying call. Accepts function objects, lambdas,...
Definition named_parameters.hpp:1219
Mapping of C++ datatypes to builtin MPI types.
STL namespace.
std::logical_and< T > logical_and
Builtin logical AND (MPI_LAND).
Definition reduce_ops.hpp:148
constexpr internal::commutative_tag commutative
Tag: operation is commutative.
Definition reduce_ops.hpp:174
std::bit_or< T > bit_or
Builtin bitwise OR (MPI_BOR).
Definition reduce_ops.hpp:160
std::logical_or< T > logical_or
Builtin logical OR (MPI_LOR).
Definition reduce_ops.hpp:156
std::bit_and< T > bit_and
Builtin bitwise AND (MPI_BAND).
Definition reduce_ops.hpp:152
std::bit_xor< T > bit_xor
Builtin bitwise XOR (MPI_BXOR).
Definition reduce_ops.hpp:168
std::plus< T > plus
Builtin summation (MPI_SUM).
Definition reduce_ops.hpp:140
constexpr internal::non_commutative_tag non_commutative
Tag: operation is non-commutative.
Definition reduce_ops.hpp:175
std::multiplies< T > multiplies
Builtin multiplication (MPI_PROD).
Definition reduce_ops.hpp:144
Tag for a commutative user-defined reduce operation.
Definition reduce_ops.hpp:120
constexpr bool operator()(T const &lhs, S const &rhs) const
Returns the logical XOR of the two parameters.
Definition reduce_ops.hpp:114
Logical XOR function object (no STL equivalent).
Definition reduce_ops.hpp:97
constexpr bool operator()(T const &lhs, T const &rhs) const
Returns the logical XOR of the two parameters.
Definition reduce_ops.hpp:101
constexpr auto operator()(T const &lhs, T const &rhs) const
Returns the maximum of the two parameters.
Definition reduce_ops.hpp:65
Wrapper struct for std::max.
Definition reduce_ops.hpp:49
constexpr T operator()(T const &lhs, T const &rhs) const
Returns the maximum of the two parameters.
Definition reduce_ops.hpp:53
constexpr auto operator()(T const &lhs, T const &rhs) const
Returns the minimum of the two parameters.
Definition reduce_ops.hpp:89
Wrapper struct for std::min (same rationale as max_impl).
Definition reduce_ops.hpp:73
constexpr T operator()(T const &lhs, T const &rhs) const
Returns the minimum of the two parameters.
Definition reduce_ops.hpp:77
Tag for a non-commutative user-defined reduce operation.
Definition reduce_ops.hpp:122
Tag for a reduce operation without a manually declared commutativity (builtin ops only).
Definition reduce_ops.hpp:124
Null operation (MPI_OP_NULL).
Definition reduce_ops.hpp:172
Type trait that maps a (functor type, element type) pair to its builtin MPI_Op.
Definition reduce_ops.hpp:202
static constexpr bool is_builtin
true if Op applied to T corresponds to a predefined MPI operation constant.
Definition reduce_ops.hpp:204
static MPI_Op op()
Returns the predefined MPI_Op constant for this operation.
static constexpr T identity
The identity element for this operation and data type.
Definition reduce_ops.hpp:209