Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Splines linear problem 3x3 blocks #478

Merged
merged 36 commits into from
Jun 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
2b9071a
wip
blegouix May 29, 2024
af23572
wip
blegouix May 29, 2024
8c53a90
Merge branch 'main' into splines-linear-proble-2x2-blocks
blegouix May 29, 2024
4a714bd
runs but wrong result
blegouix May 29, 2024
17062e1
fix
blegouix May 30, 2024
769da52
rely on Kokkos::View to store nb and k
blegouix May 30, 2024
fdbfecf
renaming
blegouix May 30, 2024
1d4a8ed
misc
blegouix May 30, 2024
68b826f
release candidate
blegouix May 30, 2024
6f1f29f
Merge branch 'main' into splines-linear-proble-2x2-blocks
blegouix May 30, 2024
4cc3a1d
autoreview
blegouix May 30, 2024
ed6115b
autoreview
blegouix May 30, 2024
21155ff
wip
blegouix May 31, 2024
3793667
wip
blegouix May 31, 2024
a158101
thomas' review
blegouix May 31, 2024
7fec07c
improve gemv
blegouix May 31, 2024
4f0422a
minor fix
blegouix May 31, 2024
3b6d736
minor fix
blegouix May 31, 2024
a49541d
renaming
blegouix May 31, 2024
d0bb2de
fix
blegouix Jun 1, 2024
1c0321b
Merge branch 'main' into splines-linear-problem-3x3-blocks
blegouix Jun 5, 2024
a5b2cc2
init
blegouix Jun 5, 2024
cc69eb2
autoreview + missing files
blegouix Jun 5, 2024
eac561b
autoreview
blegouix Jun 5, 2024
605c662
autoreview
blegouix Jun 5, 2024
a13d691
Merge branch 'main' into splines-linear-problem-3x3-blocks
blegouix Jun 17, 2024
54b0e42
Merge branch 'main' into splines-linear-problem-3x3-blocks
blegouix Jun 17, 2024
f435791
Merge branch 'splines-linear-problem-3x3-blocks' of github.com:Maison…
blegouix Jun 17, 2024
2b752ec
Merge branch 'main' into splines-linear-problem-3x3-blocks
blegouix Jun 21, 2024
6922df5
Merge branch 'main' into splines-linear-problem-3x3-blocks
blegouix Jun 25, 2024
46c6f5e
Apply suggestions from code review
blegouix Jun 26, 2024
fa77eb9
Update include/ddc/kernels/splines/splines_linear_problem_3x3_blocks.hpp
blegouix Jun 26, 2024
3c2da24
Apply suggestions from code review
blegouix Jun 26, 2024
406228f
Update include/ddc/kernels/splines/splines_linear_problem_3x3_blocks.hpp
blegouix Jun 26, 2024
c56c130
asserts to prevent overlapping allocations
blegouix Jun 26, 2024
8ab0cb2
Merge branch 'main' into splines-linear-problem-3x3-blocks
blegouix Jun 26, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/ddc/kernels/splines.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "splines/spline_evaluator_2d.hpp"
#include "splines/splines_linear_problem.hpp"
#include "splines/splines_linear_problem_2x2_blocks.hpp"
#include "splines/splines_linear_problem_3x3_blocks.hpp"
#include "splines/splines_linear_problem_band.hpp"
#include "splines/splines_linear_problem_dense.hpp"
#include "splines/splines_linear_problem_maker.hpp"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class SplinesLinearProblem2x2Blocks : public SplinesLinearProblem<ExecSpace>
* @brief SplinesLinearProblem2x2Blocks constructor.
*
* @param mat_size The size of one of the dimensions of the square matrix.
* @param top_left_block A pointer toward the top-left SplinesLinearProblem. `setup_solver` must not have been called on `q`.
* @param top_left_block A pointer toward the top-left SplinesLinearProblem. `setup_solver` must not have been called on it.
*/
explicit SplinesLinearProblem2x2Blocks(
std::size_t const mat_size,
Expand Down
185 changes: 185 additions & 0 deletions include/ddc/kernels/splines/splines_linear_problem_3x3_blocks.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
// Copyright (C) The DDC development team, see COPYRIGHT.md file
//
// SPDX-License-Identifier: MIT

#pragma once

#include <cassert>
#include <memory>
#include <string>

#include "splines_linear_problem.hpp"
#include "splines_linear_problem_2x2_blocks.hpp"

namespace ddc::detail {

/**
* @brief A 3x3-blocks linear problem dedicated to the computation of a spline approximation,
* with all blocks except center one being stored in dense format.
*
* A = | a | b | c |
* | d | Q | e |
* | f | g | h |
*
* The storage format is dense for all blocks except center one, whose storage format is determined by its type.
*
* The matrix itself and blocks a, Q and h are square (which fully determines the dimensions of the others).
*
* This class implements row & columns interchanges of the matrix and of multiple right-hand sides to restructure the
* 3x3-blocks linear problem into a 2x2-blocks linear problem, relying then on the operations implemented in SplinesLinearProblem2x2Blocks.
*
* @tparam ExecSpace The Kokkos::ExecutionSpace on which operations related to the matrix are supposed to be performed.
*/
template <class ExecSpace>
class SplinesLinearProblem3x3Blocks : public SplinesLinearProblem2x2Blocks<ExecSpace>
{
public:
using typename SplinesLinearProblem2x2Blocks<ExecSpace>::MultiRHS;
using SplinesLinearProblem2x2Blocks<ExecSpace>::size;
using SplinesLinearProblem2x2Blocks<ExecSpace>::solve;
using SplinesLinearProblem2x2Blocks<ExecSpace>::m_top_left_block;

protected:
std::size_t m_top_size;

public:
/**
* @brief SplinesLinearProblem3x3Blocks constructor.
*
* @param mat_size The size of one of the dimensions of the square matrix.
* @param top_size The size of one of the dimensions of the top-left square block.
* @param center_block A pointer toward the center SplinesLinearProblem. `setup_solver` must not have been called on it.
*/
explicit SplinesLinearProblem3x3Blocks(
std::size_t const mat_size,
std::size_t const top_size,
std::unique_ptr<SplinesLinearProblem<ExecSpace>> center_block)
: SplinesLinearProblem2x2Blocks<ExecSpace>(mat_size, std::move(center_block))
, m_top_size(top_size)
{
}

private:
/// @brief Adjust indices, governs the row & columns interchanges to restructure the 3x3-blocks matrix into a 2x2-blocks matrix.
void adjust_indices(std::size_t& i, std::size_t& j) const
{
std::size_t const nq = m_top_left_block->size(); // size of the center block

if (i < m_top_size) {
i += nq;
} else if (i < m_top_size + nq) {
i -= m_top_size;
}

if (j < m_top_size) {
j += nq;
} else if (j < m_top_size + nq) {
j -= m_top_size;
}
}

public:
double get_element(std::size_t i, std::size_t j) const override
{
adjust_indices(i, j);
return SplinesLinearProblem2x2Blocks<ExecSpace>::get_element(i, j);
}

void set_element(std::size_t i, std::size_t j, double const aij) override
{
adjust_indices(i, j);
return SplinesLinearProblem2x2Blocks<ExecSpace>::set_element(i, j, aij);
}

private:
/**
* @brief Perform row interchanges on multiple right-hand sides to get a 2-blocks structure (matching the requirements
* of the SplinesLinearProblem2x2Blocks solver).
*
* | b_top | | b_center |
* | b_center | -> | b_top | -- Considered as a
* | b_bottom | | b_bottom | -- single bottom block
*
* @param b The multiple right-hand sides.
*/
void interchange_rows_from_3_to_2_blocks_rhs(MultiRHS const b) const
{
std::size_t const nq = m_top_left_block->size(); // size of the center block

// prevent Kokkos::deep_copy(b_top_dst, b_top) to be a deep_copy between overlapping allocations
assert(nq >= m_top_size);

MultiRHS const b_top = Kokkos::
subview(b, std::pair<std::size_t, std::size_t> {0, m_top_size}, Kokkos::ALL);
MultiRHS const b_center = Kokkos::
subview(b,
std::pair<std::size_t, std::size_t> {m_top_size, m_top_size + nq},
Kokkos::ALL);

MultiRHS const b_center_dst
= Kokkos::subview(b, std::pair<std::size_t, std::size_t> {0, nq}, Kokkos::ALL);
MultiRHS const b_top_dst = Kokkos::
subview(b, std::pair<std::size_t, std::size_t> {nq, nq + m_top_size}, Kokkos::ALL);

MultiRHS const buffer = Kokkos::create_mirror(ExecSpace(), b_center);

Kokkos::deep_copy(buffer, b_center);
Kokkos::deep_copy(b_top_dst, b_top);
Kokkos::deep_copy(b_center_dst, buffer);
}

/**
* @brief Perform row interchanges on multiple right-hand sides to restore its 3-blocks structure.
*
* | b_center | | b_top |
* | b_top | -> | b_center |
* | b_bottom | | b_bottom |
*
* @param b The multiple right-hand sides.
*/
void interchange_rows_from_2_to_3_blocks_rhs(MultiRHS const b) const
{
std::size_t const nq = m_top_left_block->size(); // size of the center block

// prevent Kokkos::deep_copy(b_top, b_top_src) to be a deep_copy between overlapping allocations
assert(nq >= m_top_size);

MultiRHS const b_center_src
= Kokkos::subview(b, std::pair<std::size_t, std::size_t> {0, nq}, Kokkos::ALL);
MultiRHS const b_top_src = Kokkos::
subview(b, std::pair<std::size_t, std::size_t> {nq, nq + m_top_size}, Kokkos::ALL);

MultiRHS const b_top = Kokkos::
subview(b, std::pair<std::size_t, std::size_t> {0, m_top_size}, Kokkos::ALL);
MultiRHS const b_center = Kokkos::
subview(b,
std::pair<std::size_t, std::size_t> {m_top_size, m_top_size + nq},
Kokkos::ALL);

MultiRHS const buffer = Kokkos::create_mirror(ExecSpace(), b_center);

Kokkos::deep_copy(buffer, b_center_src);
Kokkos::deep_copy(b_top, b_top_src);
blegouix marked this conversation as resolved.
Show resolved Hide resolved
Kokkos::deep_copy(b_center, buffer);
}

public:
/**
* @brief Solve the multiple right-hand sides linear problem Ax=b or its transposed version A^tx=b inplace.
*
* Perform row interchanges on multiple right-hand sides to obtain a 2x2-blocks linear problem and call the SplinesLinearProblem2x2Blocks solver.
*
* @param[in, out] b A 2D Kokkos::View storing the multiple right-hand sides of the problem and receiving the corresponding solution.
* @param transpose Choose between the direct or transposed version of the linear problem.
*/
void solve(MultiRHS const b, bool const transpose) const override
{
assert(b.extent(0) == size());

interchange_rows_from_3_to_2_blocks_rhs(b);
SplinesLinearProblem2x2Blocks<ExecSpace>::solve(b, transpose);
interchange_rows_from_2_to_3_blocks_rhs(b);
}
};

} // namespace ddc::detail
23 changes: 15 additions & 8 deletions include/ddc/kernels/splines/splines_linear_problem_maker.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <optional>

#include "splines_linear_problem_2x2_blocks.hpp"
#include "splines_linear_problem_3x3_blocks.hpp"
#include "splines_linear_problem_band.hpp"
#include "splines_linear_problem_dense.hpp"
#include "splines_linear_problem_pds_band.hpp"
Expand Down Expand Up @@ -65,15 +66,16 @@ class SplinesLinearProblemMaker
}

/**
* @brief Construct a 2x2-blocks linear problem with band "main" block (the one called
* Q in SplinesLinearProblem2x2Blocks).
* @brief Construct a 2x2-blocks or 3x3-blocks linear problem with band "main" block (the one called
* Q in SplinesLinearProblem2x2Blocks and SplinesLinearProblem3x3Blocks).
*
* @tparam the Kokkos::ExecutionSpace on which matrix-related operation will be performed.
* @param n The size of one of the dimensions of the whole square matrix.
* @param kl The number of subdiagonals in the band block.
* @param ku The number of superdiagonals in the band block.
* @param pds A boolean indicating if the band block is positive-definite symetric or not.
* @param bottom_right_size The size of one of the dimensions of the bottom-right block.
* @param bottom_right_size The size of one of the dimensions of the bottom-right square block.
* @param top_left_size The size of one of the dimensions of the top-left square block.
*
* @return The SplinesLinearProblem instance.
*/
Expand All @@ -84,13 +86,18 @@ class SplinesLinearProblemMaker
int const kl,
int const ku,
bool const pds,
int const bottom_size)
int const bottom_right_size,
int const top_left_size = 0)
{
int const top_size = n - bottom_size;
std::unique_ptr<SplinesLinearProblem<ExecSpace>> top_left_block
= make_new_band<ExecSpace>(top_size, kl, ku, pds);
int const main_size = n - top_left_size - bottom_right_size;
std::unique_ptr<SplinesLinearProblem<ExecSpace>> main_block
= make_new_band<ExecSpace>(main_size, kl, ku, pds);
if (top_left_size == 0) {
return std::make_unique<
SplinesLinearProblem2x2Blocks<ExecSpace>>(n, std::move(main_block));
}
return std::make_unique<
SplinesLinearProblem2x2Blocks<ExecSpace>>(n, std::move(top_left_block));
SplinesLinearProblem3x3Blocks<ExecSpace>>(n, top_left_size, std::move(main_block));
}

/**
Expand Down
48 changes: 47 additions & 1 deletion tests/splines/matrix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ TEST(Matrix, 2x2Blocks)
std::size_t const k = 10;
std::unique_ptr<ddc::detail::SplinesLinearProblem<Kokkos::DefaultExecutionSpace>> top_left_block
= std::make_unique<
ddc::detail::SplinesLinearProblemDense<Kokkos::DefaultExecutionSpace>>(3);
ddc::detail::SplinesLinearProblemDense<Kokkos::DefaultExecutionSpace>>(7);
std::unique_ptr<ddc::detail::SplinesLinearProblem<Kokkos::DefaultExecutionSpace>> matrix
= std::make_unique<ddc::detail::SplinesLinearProblem2x2Blocks<
Kokkos::DefaultExecutionSpace>>(N, std::move(top_left_block));
Expand All @@ -248,6 +248,31 @@ TEST(Matrix, 2x2Blocks)
solve_and_validate(*matrix);
}

TEST(Matrix, 3x3Blocks)
{
std::size_t const N = 10;
std::size_t const k = 10;
std::unique_ptr<ddc::detail::SplinesLinearProblem<Kokkos::DefaultExecutionSpace>> center_block
= std::make_unique<
ddc::detail::SplinesLinearProblemDense<Kokkos::DefaultExecutionSpace>>(N - 5);
std::unique_ptr<ddc::detail::SplinesLinearProblem<Kokkos::DefaultExecutionSpace>> matrix
= std::make_unique<ddc::detail::SplinesLinearProblem3x3Blocks<
Kokkos::DefaultExecutionSpace>>(N, 2, std::move(center_block));

// Build a non-symmetric full-rank matrix (without zero)
for (std::size_t i(0); i < N; ++i) {
std::cout << i;
matrix->set_element(i, i, 3. / 4 * ((N + 1) * i + 1));
for (std::size_t j(std::max(0, int(i) - int(k))); j < i; ++j) {
matrix->set_element(i, j, -(1. / 4) / k * (N * i + j + 1));
}
for (std::size_t j(i + 1); j < std::min(N, i + k + 1); ++j) {
matrix->set_element(i, j, -(1. / 4) / k * (N * i + j + 1));
}
}

solve_and_validate(*matrix);
}

class MatrixSizesFixture : public testing::TestWithParam<std::tuple<std::size_t, std::size_t>>
{
Expand Down Expand Up @@ -339,6 +364,27 @@ TEST_P(MatrixSizesFixture, 2x2Blocks)
solve_and_validate(*matrix);
}

TEST_P(MatrixSizesFixture, 3x3Blocks)
{
auto const [N, k] = GetParam();
std::unique_ptr<ddc::detail::SplinesLinearProblem<Kokkos::DefaultExecutionSpace>> matrix
= ddc::detail::SplinesLinearProblemMaker::make_new_block_matrix_with_band_main_block<
Kokkos::DefaultExecutionSpace>(N, k, k, false, 3, 2);

// Build a non-symmetric full-rank band matrix
for (std::size_t i(0); i < N; ++i) {
matrix->set_element(i, i, 3. / 4 * ((N + 1) * i + 1));
for (std::size_t j(std::max(0, int(i) - int(k))); j < i; ++j) {
matrix->set_element(i, j, -(1. / 4) / k * (N * i + j + 1));
}
for (std::size_t j(i + 1); j < std::min(N, i + k + 1); ++j) {
matrix->set_element(i, j, -(1. / 4) / k * (N * i + j + 1));
}
}

solve_and_validate(*matrix);
}

TEST_P(MatrixSizesFixture, PeriodicBand)
{
auto const [N, k] = GetParam();
Expand Down