DDC 0.1.0
Loading...
Searching...
No Matches
splines_linear_problem_3x3_blocks.hpp
1// Copyright (C) The DDC development team, see COPYRIGHT.md file
2//
3// SPDX-License-Identifier: MIT
4
5#pragma once
6
7#include <cassert>
8#include <cstddef>
9#include <memory>
10#include <string>
11#include <utility>
12
13#include <Kokkos_Core.hpp>
14
15#include "splines_linear_problem.hpp"
16#include "splines_linear_problem_2x2_blocks.hpp"
17
18namespace ddc::detail {
19
20/**
21 * @brief A 3x3-blocks linear problem dedicated to the computation of a spline approximation,
22 * with all blocks except center one being stored in dense format.
23 *
24 * A = | a | b | c |
25 * | d | Q | e |
26 * | f | g | h |
27 *
28 * The storage format is dense for all blocks except center one, whose storage format is determined by its type.
29 *
30 * The matrix itself and blocks a, Q and h are square (which fully determines the dimensions of the others).
31 *
32 * This class implements row & columns interchanges of the matrix and of multiple right-hand sides to restructure the
33 * 3x3-blocks linear problem into a 2x2-blocks linear problem, relying then on the operations implemented in SplinesLinearProblem2x2Blocks.
34 *
35 * @tparam ExecSpace The Kokkos::ExecutionSpace on which operations related to the matrix are supposed to be performed.
36 */
37template <class ExecSpace>
38class SplinesLinearProblem3x3Blocks : public SplinesLinearProblem2x2Blocks<ExecSpace>
39{
40public:
41 using typename SplinesLinearProblem2x2Blocks<ExecSpace>::MultiRHS;
42 using SplinesLinearProblem2x2Blocks<ExecSpace>::size;
43 using SplinesLinearProblem2x2Blocks<ExecSpace>::solve;
44 using SplinesLinearProblem2x2Blocks<ExecSpace>::m_top_left_block;
45
46protected:
47 std::size_t m_top_size;
48
49public:
50 /**
51 * @brief SplinesLinearProblem3x3Blocks constructor.
52 *
53 * @param mat_size The size of one of the dimensions of the square matrix.
54 * @param top_size The size of one of the dimensions of the top-left square block.
55 * @param center_block A pointer toward the center SplinesLinearProblem. `setup_solver` must not have been called on it.
56 */
57 explicit SplinesLinearProblem3x3Blocks(
58 std::size_t const mat_size,
59 std::size_t const top_size,
60 std::unique_ptr<SplinesLinearProblem<ExecSpace>> center_block)
61 : SplinesLinearProblem2x2Blocks<ExecSpace>(mat_size, std::move(center_block))
62 , m_top_size(top_size)
63 {
64 }
65
66private:
67 /// @brief Adjust indices, governs the row & columns interchanges to restructure the 3x3-blocks matrix into a 2x2-blocks matrix.
68 void adjust_indices(std::size_t& i, std::size_t& j) const
69 {
70 std::size_t const nq = m_top_left_block->size(); // size of the center block
71
72 if (i < m_top_size) {
73 i += nq;
74 } else if (i < m_top_size + nq) {
75 i -= m_top_size;
76 }
77
78 if (j < m_top_size) {
79 j += nq;
80 } else if (j < m_top_size + nq) {
81 j -= m_top_size;
82 }
83 }
84
85public:
86 double get_element(std::size_t i, std::size_t j) const override
87 {
88 adjust_indices(i, j);
89 return SplinesLinearProblem2x2Blocks<ExecSpace>::get_element(i, j);
90 }
91
92 void set_element(std::size_t i, std::size_t j, double const aij) override
93 {
94 adjust_indices(i, j);
95 return SplinesLinearProblem2x2Blocks<ExecSpace>::set_element(i, j, aij);
96 }
97
98private:
99 /**
100 * @brief Perform row interchanges on multiple right-hand sides to get a 2-blocks structure (matching the requirements
101 * of the SplinesLinearProblem2x2Blocks solver).
102 *
103 * | b_top | | - |
104 * | b_center | -> | b_center |
105 * | b_bottom | | b_top | -- Considered as a
106 * | - | | b_bottom | -- single bottom block
107 *
108 * @param b The multiple right-hand sides.
109 */
110 void interchange_rows_from_3_to_2_blocks_rhs(MultiRHS const b) const
111 {
112 std::size_t const nq = m_top_left_block->size(); // size of the center block
113
114 MultiRHS const b_top = Kokkos::
115 subview(b, std::pair<std::size_t, std::size_t> {0, m_top_size}, Kokkos::ALL);
116 MultiRHS const b_bottom = Kokkos::
117 subview(b,
118 std::pair<std::size_t, std::size_t> {m_top_size + nq, size()},
119 Kokkos::ALL);
120
121 MultiRHS const b_top_dst = Kokkos::
122 subview(b,
123 std::pair<std::size_t, std::size_t> {m_top_size + nq, 2 * m_top_size + nq},
124 Kokkos::ALL);
125 MultiRHS const b_bottom_dst = Kokkos::
126 subview(b,
127 std::pair<
128 std::size_t,
129 std::size_t> {2 * m_top_size + nq, m_top_size + size()},
130 Kokkos::ALL);
131
132 if (b_bottom.extent(0) > b_top.extent(0)) {
133 // Need a buffer to prevent overlapping
134 MultiRHS const buffer = Kokkos::create_mirror(ExecSpace(), b_bottom);
135
136 Kokkos::deep_copy(buffer, b_bottom);
137 Kokkos::deep_copy(b_bottom_dst, buffer);
138 } else {
139 Kokkos::deep_copy(b_bottom_dst, b_bottom);
140 }
141 Kokkos::deep_copy(b_top_dst, b_top);
142 }
143
144 /**
145 * @brief Perform row interchanges on multiple right-hand sides to restore its 3-blocks structure.
146 *
147 * | - | | b_top |
148 * | b_center | -> | b_center |
149 * | b_top | | b_bottom |
150 * | b_bottom | | - |
151 *
152 * @param b The multiple right-hand sides.
153 */
154 void interchange_rows_from_2_to_3_blocks_rhs(MultiRHS const b) const
155 {
156 std::size_t const nq = m_top_left_block->size(); // size of the center block
157
158 MultiRHS const b_top = Kokkos::
159 subview(b, std::pair<std::size_t, std::size_t> {0, m_top_size}, Kokkos::ALL);
160 MultiRHS const b_bottom = Kokkos::
161 subview(b,
162 std::pair<std::size_t, std::size_t> {m_top_size + nq, size()},
163 Kokkos::ALL);
164
165 MultiRHS const b_top_src = Kokkos::
166 subview(b,
167 std::pair<std::size_t, std::size_t> {m_top_size + nq, 2 * m_top_size + nq},
168 Kokkos::ALL);
169 MultiRHS const b_bottom_src = Kokkos::
170 subview(b,
171 std::pair<
172 std::size_t,
173 std::size_t> {2 * m_top_size + nq, m_top_size + size()},
174 Kokkos::ALL);
175
176 Kokkos::deep_copy(b_top, b_top_src);
177 if (b_bottom.extent(0) > b_top.extent(0)) {
178 // Need a buffer to prevent overlapping
179 MultiRHS const buffer = Kokkos::create_mirror(ExecSpace(), b_bottom);
180
181 Kokkos::deep_copy(buffer, b_bottom_src);
182 Kokkos::deep_copy(b_bottom, buffer);
183 } else {
184 Kokkos::deep_copy(b_bottom, b_bottom_src);
185 }
186 }
187
188public:
189 /**
190 * @brief Solve the multiple right-hand sides linear problem Ax=b or its transposed version A^tx=b inplace.
191 *
192 * Perform row interchanges on multiple right-hand sides to obtain a 2x2-blocks linear problem and call the SplinesLinearProblem2x2Blocks solver.
193 *
194 * This class requires an additional allocation corresponding to top_size rows for internal operation.
195 *
196 * @param[in, out] b A 2D Kokkos::View storing the multiple right-hand sides (+ additional garbage allocation) of the problem and receiving the corresponding solution.
197 * @param transpose Choose between the direct or transposed version of the linear problem.
198 */
199 void solve(MultiRHS const b, bool const transpose) const override
200 {
201 assert(b.extent(0) == size() + m_top_size);
202
203 interchange_rows_from_3_to_2_blocks_rhs(b);
204 SplinesLinearProblem2x2Blocks<ExecSpace>::
205 solve(Kokkos::
206 subview(b,
207 std::pair<
208 std::size_t,
209 std::size_t> {m_top_size, m_top_size + size()},
210 Kokkos::ALL),
211 transpose);
212 interchange_rows_from_2_to_3_blocks_rhs(b);
213 }
214
215private:
216 std::size_t impl_required_number_of_rhs_rows() const override
217 {
218 return size() + m_top_size;
219 }
220};
221
222} // namespace ddc::detail
The top-level namespace of DDC.