9
9
* SPDX-License-Identifier: BSD-3-Clause *
10
10
****************************************************************************/
11
11
12
- #ifndef ARBORX_INTERP_SYMMETRIC_PSEUDO_INVERSE_SVD_HPP
13
- #define ARBORX_INTERP_SYMMETRIC_PSEUDO_INVERSE_SVD_HPP
12
+ #ifndef ARBORX_SYMMETRIC_SVD_HPP
13
+ #define ARBORX_SYMMETRIC_SVD_HPP
14
14
15
15
#include < kokkos_ext/ArborX_KokkosExtAccessibilityTraits.hpp>
16
16
#include < misc/ArborX_Exception.hpp>
17
17
18
18
#include < Kokkos_Core.hpp>
19
19
#include < Kokkos_Profiling_ScopedRegion.hpp>
20
20
21
- namespace ArborX ::Interpolation:: Details
21
+ namespace ArborX ::Details
22
22
{
23
23
24
24
template <typename Matrix>
@@ -77,18 +77,17 @@ KOKKOS_FUNCTION auto argmaxUpperTriangle(Matrix const &mat)
77
77
return result;
78
78
}
79
79
80
- // Pseudo-inverse of symmetric matrices using SVD
80
+ // SVD of a symmetric matrix
81
81
// We must find U, E (diagonal and positive) and V such that A = U.E.V^T
82
82
// We also suppose, as the input, that A is symmetric, so U = SV where S is
83
83
// a sign matrix (only 1 or -1 on the diagonal, 0 elsewhere).
84
- // Thus A = U.ES.U^T and A^-1 = U.[ ES^-1 ].U^T
84
+ // Thus A = U.ES.U^T.
85
85
//
86
86
// mat <=> initial ES
87
87
// diag <=> final ES
88
88
// unit <=> U
89
89
template <typename Matrix, typename Diag, typename Unit>
90
- KOKKOS_FUNCTION void symmetricPseudoInverseSVDKernel (Matrix &mat, Diag &diag,
91
- Unit &unit)
90
+ KOKKOS_FUNCTION void symmetricSVDKernel (Matrix &mat, Diag &diag, Unit &unit)
92
91
{
93
92
ensureIsSquareSymmetricMatrix (mat);
94
93
static_assert (!std::is_const_v<typename Matrix::value_type>,
@@ -203,13 +202,34 @@ KOKKOS_FUNCTION void symmetricPseudoInverseSVDKernel(Matrix &mat, Diag &diag,
203
202
}
204
203
}
205
204
205
+ for (int i = 0 ; i < size; i++)
206
+ diag (i) = mat (i, i);
207
+ }
208
+
209
+ // Pseudo-inverse of symmetric matrices using SVD
210
+ // We must find U, E (diagonal and positive) and V such that A = U.E.V^T
211
+ // We also suppose, as the input, that A is symmetric, so U = SV where S is
212
+ // a sign matrix (only 1 or -1 on the diagonal, 0 elsewhere).
213
+ // Thus A = U.ES.U^T and A^-1 = U.[ ES^-1 ].U^T
214
+ //
215
+ // mat <=> initial ES
216
+ // diag <=> final ES
217
+ // unit <=> U
218
+ template <typename Matrix, typename Diag, typename Unit>
219
+ KOKKOS_FUNCTION void symmetricPseudoInverseSVDKernel (Matrix &mat, Diag &diag,
220
+ Unit &unit)
221
+ {
222
+ symmetricSVDKernel (mat, diag, unit);
223
+
224
+ int const size = mat.extent (0 );
225
+
226
+ using Value = typename Matrix::non_const_value_type;
227
+ constexpr Value epsilon = Kokkos::Experimental::epsilon_v<float >;
228
+
206
229
// We compute the max to get a range of the invertible eigenvalues
207
230
auto max_eigen = epsilon;
208
231
for (int i = 0 ; i < size; i++)
209
- {
210
- diag (i) = mat (i, i);
211
232
max_eigen = Kokkos::max (Kokkos::abs (diag (i)), max_eigen);
212
- }
213
233
auto const threshold = max_eigen * epsilon;
214
234
215
235
// We invert the diagonal of 'mat', except if "0" is found
@@ -226,49 +246,6 @@ KOKKOS_FUNCTION void symmetricPseudoInverseSVDKernel(Matrix &mat, Diag &diag,
226
246
}
227
247
}
228
248
229
- template <typename ExecutionSpace, typename InOutMatrices>
230
- void symmetricPseudoInverseSVD (ExecutionSpace const &space,
231
- InOutMatrices &matrices)
232
- {
233
- auto guard =
234
- Kokkos::Profiling::ScopedRegion (" ArborX::SymmetricPseudoInverseSVD" );
235
-
236
- // InOutMatrices is a list of square symmetric matrices (3D view)
237
- static_assert (Kokkos::is_view_v<InOutMatrices>, " matrices must be a view" );
238
- static_assert (!std::is_const_v<typename InOutMatrices::value_type>,
239
- " matrices must be writable" );
240
- static_assert (InOutMatrices::rank () == 3 ,
241
- " matrices must be a list of square matrices" );
242
- static_assert (
243
- ArborX::Details::KokkosExt::is_accessible_from<
244
- typename InOutMatrices::memory_space, ExecutionSpace>::value,
245
- " matrices must be accessible from the execution space" );
246
-
247
- KOKKOS_ASSERT (matrices.extent (1 ) == matrices.extent (2 )); // Must be square
248
-
249
- using Value = typename InOutMatrices::non_const_value_type;
250
- using MemorySpace = typename InOutMatrices::memory_space;
251
-
252
- Kokkos::View<Value **, MemorySpace> diags (
253
- Kokkos::view_alloc (space, Kokkos::WithoutInitializing,
254
- " ArborX::SymmetricPseudoInverseSVD::diags" ),
255
- matrices.extent (0 ), matrices.extent (1 ));
256
- Kokkos::View<Value ***, MemorySpace> units (
257
- Kokkos::view_alloc (space, Kokkos::WithoutInitializing,
258
- " ArborX::SymmetricPseudoInverseSVD::units" ),
259
- matrices.extent (0 ), matrices.extent (1 ), matrices.extent (2 ));
260
-
261
- Kokkos::parallel_for (
262
- " ArborX::SymmetricPseudoInverseSVD::computations" ,
263
- Kokkos::RangePolicy (space, 0 , matrices.extent (0 )),
264
- KOKKOS_LAMBDA (int const i) {
265
- auto mat = Kokkos::subview (matrices, i, Kokkos::ALL, Kokkos::ALL);
266
- auto diag = Kokkos::subview (diags, i, Kokkos::ALL);
267
- auto unit = Kokkos::subview (units, i, Kokkos::ALL, Kokkos::ALL);
268
- symmetricPseudoInverseSVDKernel (mat, diag, unit);
269
- });
270
- }
271
-
272
- } // namespace ArborX::Interpolation::Details
249
+ } // namespace ArborX::Details
273
250
274
251
#endif
0 commit comments