KaMPIng 0.1.0
(Near) zero-overhead C++ MPI bindings.
Loading...
Searching...
No Matches
flatten.hpp
1// This file is part of KaMPIng.
2//
3// Copyright 2024 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#pragma once
15#include <numeric>
16#include <utility>
17#include <vector>
18
19#include <kamping/utils/traits.hpp>
20
22
23namespace kamping {
24namespace internal {
25
26/// @brief A wrapper around a functor \p F that makes it callable using the `call` method.
27template <typename F>
29 F f; ///< The functor to wrap.
30
31 /// @brief Calls the wrapped functor with the given arguments.
32 template <typename... Args>
33 auto call(Args&&... args) {
34 return f(std::forward<Args...>(args)...);
35 }
36};
37
38/// @brief A factory function for \ref CallableWrapper.
39template <typename F>
41 return CallableWrapper<F>{std::move(f)};
42}
43
44/// @brief Maps a container to is underlying nested container.
45template <typename T, typename Enable = void>
46struct FlatContainer {};
47
48/// @brief Maps a container to is underlying nested container.
49template <typename T>
50struct FlatContainer<T, std::enable_if_t<is_sparse_send_buffer_v<T>>> {
51 using type =
52 std::remove_const_t<std::tuple_element_t<1, typename T::value_type>>; ///< The type of the nested container.
53};
54
55/// @brief Maps a container to is underlying nested container.
56template <typename T>
57struct FlatContainer<T, std::enable_if_t<is_nested_send_buffer_v<T>>> {
58 using type = std::remove_const_t<typename T::value_type>; ///< The type of the nested container.
59};
60
61} // namespace internal
62
63/// @brief Flattens a container of containers or destination-container-pairs and provides the flattened buffer, send
64/// counts and send displacements as parameters to be passed to an \c MPI call.
65///
66/// This returns a callable wrapper that can be called with a functor which accepts a parameter pack of these arguments.
67///
68/// Example:
69/// ```cpp
70/// Communicator comm;
71/// std::vector<std::vector<int>> nested_send_buf(comm.size()); // or std::unordered_map<int, std::vector<int>>
72/// auto [recv_buf, recv_counts, recv_displs] = with_flattened(nested_send_buf).call([&](auto... flattened) {
73/// return comm.alltoallv(std::move(flattened)..., recv_counts_out(), recv_displs_out());
74/// });
75/// ```
76///
77/// The container can be a range of pair-like types of destination and data (see \c is_sparse_send_buffer_v ) or
78/// a container of containers (see \c is_nested_send_buffer_v ).
79///
80/// @param nested_send_buf The nested container of send buffers.
81/// @param comm_size The size of the communicator, used as number of elements in the computed count buffers.
82/// @tparam CountContainer The type of the container to use for the send counts and send displacements.
83/// @tparam Container The type of the nested container.
84/// @tparam Enable SFINAE.
85///
86template <
87 template <typename...> typename CountContainer = std::vector,
88 typename Container,
89 typename Enable = std::enable_if_t<is_sparse_send_buffer_v<Container> || is_nested_send_buffer_v<Container>>>
90auto with_flattened(Container const& nested_send_buf, size_t comm_size) {
93 for (auto const& [destination, message]: nested_send_buf) {
96 }
97 } else {
98 static_assert(is_nested_send_buffer_v<Container>);
99 size_t i = 0;
100 for (auto const& message: nested_send_buf) {
101 auto send_buf = kamping::send_buf(message);
102 send_counts[i] = asserting_cast<int>(send_buf.size());
103 i++;
104 }
105 }
106 CountContainer<int> send_displs(comm_size);
107 std::exclusive_scan(send_counts.begin(), send_counts.end(), send_displs.begin(), 0);
108 size_t total_send_count = asserting_cast<size_t>(send_displs.back() + send_counts.back());
109 typename internal::FlatContainer<Container>::type flat_send_buf;
110 flat_send_buf.resize(total_send_count);
111 if constexpr (is_sparse_send_buffer_v<Container>) {
112 for (auto const& [destination, message]: nested_send_buf) {
113 auto send_buf = kamping::send_buf(message).construct_buffer_or_rebind();
114 std::copy_n(
115 send_buf.data(),
116 send_buf.size(),
117 flat_send_buf.data() + send_displs[asserting_cast<size_t>(destination)]
118 );
119 }
120 } else {
121 static_assert(is_nested_send_buffer_v<Container>);
122 size_t i = 0;
123 for (auto const& message: nested_send_buf) {
124 auto send_buf = kamping::send_buf(message).construct_buffer_or_rebind();
125 std::copy_n(send_buf.data(), send_buf.size(), flat_send_buf.data() + send_displs[i]);
126 i++;
127 }
128 }
129 return internal::make_callable_wrapper([flat_send_buf = std::move(flat_send_buf),
130 send_counts = std::move(send_counts),
131 send_displs = std::move(send_displs)](auto&& f) {
132 return std::apply(
133 std::forward<decltype(f)>(f),
134 std::tuple(
135 kamping::send_buf(flat_send_buf),
138 )
139 );
140 });
141}
142
143/// @brief Flattens a container of containers and provides the flattened buffer, send counts and send
144/// displacements as parameters to be passed to an \c MPI call.
145///
146/// This returns a callable wrapper that can be called with a functor which accepts a parameter pack of these arguments.
147/// The size of the computed count buffers is the size of the container.
148///
149/// Example:
150/// ```cpp
151/// Communicator comm;
152/// std::vector<std::vector<int>> nested_send_buf(comm.size());
153/// auto [recv_buf, recv_counts, recv_displs] = with_flattened(nested_send_buf).call([&](auto... flattened) {
154/// return comm.alltoallv(std::move(flattened)..., recv_counts_out(), recv_displs_out());
155/// });
156/// ```
157///
158/// @param nested_send_buf The nested container of send buffers. Must satisfy \c is_nested_send_buffer_v.
159/// @tparam CountContainer The type of the container to use for the send counts and send displacements.
160/// @tparam Container The type of the nested container.
161/// @tparam Enable SFINAE.
162///
163template <
164 template <typename...> typename CountContainer = std::vector,
165 typename Container,
166 typename Enable = std::enable_if_t<is_nested_send_buffer_v<Container>>>
167auto with_flattened(Container const& nested_send_buf) {
168 return with_flattened<CountContainer>(nested_send_buf, nested_send_buf.size());
169}
170} // namespace kamping
STL-compatible allocator for requesting memory using the builtin MPI allocator.
Definition allocator.hpp:32
auto destination(int rank)
Passes rank as destination rank to the underlying call. This parameter is needed in point-to-point ex...
Definition named_parameters.hpp:999
auto send_buf(internal::ignore_t< Data > ignore)
Generates a dummy send buf that wraps a nullptr.
Definition named_parameters.hpp:51
auto send_counts(Container &&container)
Passes a container as send counts to the underlying call, i.e. the container's storage must contain t...
Definition named_parameters.hpp:203
auto send_displs(Container &&container)
Passes a container as send displacements to the underlying call, i.e. the container's storage must co...
Definition named_parameters.hpp:574
Factory methods for buffer wrappers.
auto make_callable_wrapper(F f)
A factory function for CallableWrapper.
Definition flatten.hpp:40
STL namespace.
A wrapper around a functor F that makes it callable using the call method.
Definition flatten.hpp:28
auto call(Args &&... args)
Calls the wrapped functor with the given arguments.
Definition flatten.hpp:33
F f
The functor to wrap.
Definition flatten.hpp:29
std::remove_const_t< typename T::value_type > type
The type of the nested container.
Definition flatten.hpp:58
std::remove_const_t< std::tuple_element_t< 1, typename T::value_type > > type
The type of the nested container.
Definition flatten.hpp:51
Maps a container to is underlying nested container.
Definition flatten.hpp:46