SimiLie
Loading...
Searching...
No Matches
small_matrix.hpp
1// SPDX-FileCopyrightText: 2026 Baptiste Legouix
2// SPDX-License-Identifier: MIT
3
4#pragma once
5
6#include <array>
7#include <cstddef>
8
9#include <ddc/ddc.hpp>
10
11namespace sil::misc::math {
12
13template <class Scalar, class MemorySpace>
15 View<Scalar**, Kokkos::LayoutRight, MemorySpace, Kokkos::MemoryTraits<Kokkos::Unmanaged>>;
16
17template <class Scalar, class MemorySpace>
19 View<Scalar*, Kokkos::LayoutRight, MemorySpace, Kokkos::MemoryTraits<Kokkos::Unmanaged>>;
20
21template <class Scalar, class MemorySpace>
23 Scalar* data,
24 std::size_t rows,
25 std::size_t cols)
26{
27 return unmanaged_matrix_view_t<Scalar, MemorySpace>(data, rows, cols);
28}
29
30template <class Scalar, class MemorySpace>
32 Scalar* data,
33 std::size_t n)
34{
36}
37
38template <class MatrixView>
39KOKKOS_FUNCTION void fill_identity(MatrixView matrix)
40{
41 for (std::size_t i = 0; i < matrix.extent(0); ++i) {
42 for (std::size_t j = 0; j < matrix.extent(1); ++j) {
43 matrix(i, j) = (i == j) ? 1. : 0.;
44 }
45 }
46}
47
48template <class MatrixView1, class MatrixView2>
49KOKKOS_FUNCTION void copy_matrix(MatrixView1 dst, MatrixView2 src)
50{
51 assert(dst.extent(0) == src.extent(0) && dst.extent(1) == src.extent(1));
52 for (std::size_t i = 0; i < dst.extent(0); ++i) {
53 for (std::size_t j = 0; j < dst.extent(1); ++j) {
54 dst(i, j) = src(i, j);
55 }
56 }
57}
58
59template <class MatrixView, class RowIds, class ColIds, class SubmatrixView>
60KOKKOS_FUNCTION void extract_submatrix(
61 SubmatrixView submatrix,
62 MatrixView matrix,
63 RowIds const& row_ids,
64 ColIds const& col_ids)
65{
66 assert(submatrix.extent(0) == row_ids.size() && submatrix.extent(1) == col_ids.size());
67 for (std::size_t i = 0; i < row_ids.size(); ++i) {
68 for (std::size_t j = 0; j < col_ids.size(); ++j) {
69 submatrix(i, j) = matrix(row_ids[i], col_ids[j]);
70 }
71 }
72}
73
74template <class MatrixView>
75KOKKOS_FUNCTION typename MatrixView::non_const_value_type determinant(MatrixView matrix)
76{
77 assert(matrix.extent(0) == matrix.extent(1) && "Matrix should be square.");
78 if (matrix.extent(0) == 0) {
79 return 1.;
80 }
81 typename MatrixView::non_const_value_type det = 1.;
82 int sign = 1;
83
84 for (std::size_t i = 0; i < matrix.extent(0); ++i) {
85 std::size_t pivot = i;
86 auto pivot_abs = Kokkos::abs(matrix(i, i));
87 for (std::size_t row = i + 1; row < matrix.extent(0); ++row) {
88 auto const candidate_abs = Kokkos::abs(matrix(row, i));
89 if (candidate_abs > pivot_abs) {
90 pivot = row;
91 pivot_abs = candidate_abs;
92 }
93 }
94
95 if (pivot_abs == 0.) {
96 return 0.;
97 }
98
99 if (pivot != i) {
100 sign *= -1;
101 for (std::size_t col = 0; col < matrix.extent(1); ++col) {
102 Kokkos::kokkos_swap(matrix(i, col), matrix(pivot, col));
103 }
104 }
105
106 auto const diagonal = matrix(i, i);
107 det *= diagonal;
108 for (std::size_t row = i + 1; row < matrix.extent(0); ++row) {
109 auto const factor = matrix(row, i) / diagonal;
110 for (std::size_t col = i + 1; col < matrix.extent(1); ++col) {
111 matrix(row, col) -= factor * matrix(i, col);
112 }
113 matrix(row, i) = 0.;
114 }
115 }
116 return sign * det;
117}
118
119template <class InverseView, class MatrixView, class WorkspaceView>
120KOKKOS_FUNCTION bool invert(InverseView inverse, MatrixView matrix, WorkspaceView workspace)
121{
122 assert(inverse.extent(0) == inverse.extent(1) && "Inverse target should be square.");
123 assert(matrix.extent(0) == matrix.extent(1) && "Input matrix should be square.");
124 assert(inverse.extent(0) == matrix.extent(0) && "Input/output matrix sizes should match.");
125 assert(workspace.extent(0) >= matrix.extent(0) * matrix.extent(1) && "Workspace is too small.");
126
127 auto matrix_work = matrix_view<
128 typename MatrixView::non_const_value_type,
129 typename MatrixView::
130 memory_space>(workspace.data(), matrix.extent(0), matrix.extent(1));
131 copy_matrix(matrix_work, matrix);
132 fill_identity(inverse);
133
134 for (std::size_t i = 0; i < matrix.extent(0); ++i) {
135 std::size_t pivot = i;
136 auto pivot_abs = Kokkos::abs(matrix_work(i, i));
137 for (std::size_t row = i + 1; row < matrix.extent(0); ++row) {
138 auto const candidate_abs = Kokkos::abs(matrix_work(row, i));
139 if (candidate_abs > pivot_abs) {
140 pivot = row;
141 pivot_abs = candidate_abs;
142 }
143 }
144
145 if (pivot_abs == 0.) {
146 for (std::size_t row = 0; row < inverse.extent(0); ++row) {
147 for (std::size_t col = 0; col < inverse.extent(1); ++col) {
148 inverse(row, col) = 0.;
149 }
150 }
151 return false;
152 }
153
154 if (pivot != i) {
155 for (std::size_t col = 0; col < matrix_work.extent(1); ++col) {
156 Kokkos::kokkos_swap(matrix_work(i, col), matrix_work(pivot, col));
157 Kokkos::kokkos_swap(inverse(i, col), inverse(pivot, col));
158 }
159 }
160
161 auto const diagonal = matrix_work(i, i);
162 for (std::size_t col = 0; col < matrix_work.extent(1); ++col) {
163 matrix_work(i, col) /= diagonal;
164 inverse(i, col) /= diagonal;
165 }
166
167 for (std::size_t row = 0; row < matrix_work.extent(0); ++row) {
168 if (row == i) {
169 continue;
170 }
171 auto const factor = matrix_work(row, i);
172 for (std::size_t col = 0; col < matrix_work.extent(1); ++col) {
173 matrix_work(row, col) -= factor * matrix_work(i, col);
174 inverse(row, col) -= factor * inverse(i, col);
175 }
176 }
177 }
178
179 return true;
180}
181
182template <std::size_t N, class MatrixView, class RowIds, class ColIds>
183KOKKOS_FUNCTION double submatrix_determinant(
184 MatrixView matrix,
185 RowIds const& row_ids,
186 ColIds const& col_ids,
187 std::array<double, N * N>& submatrix_alloc)
188{
189 if constexpr (N == 0) {
190 return 1.;
191 } else {
192 auto submatrix = matrix_view<
193 double,
194 typename MatrixView::memory_space>(submatrix_alloc.data(), N, N);
195 extract_submatrix(submatrix, matrix, row_ids, col_ids);
196 return determinant(submatrix);
197 }
198}
199
200} // namespace sil::misc::math
Kokkos:: View< Scalar *, Kokkos::LayoutRight, MemorySpace, Kokkos::MemoryTraits< Kokkos::Unmanaged > > unmanaged_vector_view_t
KOKKOS_FUNCTION void extract_submatrix(SubmatrixView submatrix, MatrixView matrix, RowIds const &row_ids, ColIds const &col_ids)
KOKKOS_FUNCTION bool invert(InverseView inverse, MatrixView matrix, WorkspaceView workspace)
KOKKOS_FUNCTION void fill_identity(MatrixView matrix)
KOKKOS_FUNCTION unmanaged_vector_view_t< Scalar, MemorySpace > vector_view(Scalar *data, std::size_t n)
KOKKOS_FUNCTION void copy_matrix(MatrixView1 dst, MatrixView2 src)
KOKKOS_FUNCTION double submatrix_determinant(MatrixView matrix, RowIds const &row_ids, ColIds const &col_ids, std::array< double, N *N > &submatrix_alloc)
KOKKOS_FUNCTION unmanaged_matrix_view_t< Scalar, MemorySpace > matrix_view(Scalar *data, std::size_t rows, std::size_t cols)
KOKKOS_FUNCTION MatrixView::non_const_value_type determinant(MatrixView matrix)
Kokkos:: View< Scalar **, Kokkos::LayoutRight, MemorySpace, Kokkos::MemoryTraits< Kokkos::Unmanaged > > unmanaged_matrix_view_t