KokkosBatched::AddRadial¶
Defined in header: KokkosBatched_AddRadial_Decl.hpp
struct SerialAddRadial {
template <typename ScalarType, typename AViewType>
KOKKOS_INLINE_FUNCTION
static int
invoke(const ScalarType tiny,
const AViewType& A);
};
template <typename MemberType>
struct TeamAddRadial {
template <typename ScalarType, typename AViewType>
KOKKOS_INLINE_FUNCTION
static int
invoke(const MemberType& member,
const ScalarType tiny,
const AViewType& A);
};
The AddRadial
operation adds tiny values to the diagonal elements of a matrix to ensure that the absolute values of the diagonals become larger. This is typically used to improve numerical stability in matrix operations like LU or Cholesky factorizations by preventing division by zero or near-zero values.
Mathematically, the operation performs:
Parameters¶
- member:
Team execution policy instance (only for team version)
- tiny:
Scalar value to add to diagonal elements
- A:
Input/output matrix view to which diagonal values are added
Type Requirements¶
MemberType
must be a Kokkos TeamPolicy member typeScalarType
must be a scalar type compatible with the element type of the matrix viewAViewType
must be a rank-2 view representing a square matrixThe view must be accessible in the execution space
Example¶
#include <Kokkos_Core.hpp>
#include <KokkosBatched_AddRadial_Decl.hpp>
using execution_space = Kokkos::DefaultExecutionSpace;
using memory_space = execution_space::memory_space;
// Scalar type to use
using scalar_type = double;
int main(int argc, char* argv[]) {
Kokkos::initialize(argc, argv);
{
// Matrix dimensions
int n = 5; // Square matrix size
// Create matrix
Kokkos::View<scalar_type**, Kokkos::LayoutRight, memory_space> A("A", n, n);
// Initialize matrix on host
auto A_host = Kokkos::create_mirror_view(A);
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
if (i == j) {
// Set diagonal elements to small values to demonstrate AddRadial effect
A_host(i, j) = 1.0e-8;
} else {
// Off-diagonal elements
A_host(i, j) = i*n + j + 1;
}
}
}
// Copy to device
Kokkos::deep_copy(A, A_host);
// Save a copy of the original matrix for verification
Kokkos::View<scalar_type**, Kokkos::LayoutRight, memory_space> A_orig("A_orig", n, n);
Kokkos::deep_copy(A_orig, A);
// Value to add to diagonal
scalar_type tiny = 1.0e-2;
// Apply AddRadial operation
Kokkos::parallel_for(1, KOKKOS_LAMBDA(const int i) {
KokkosBatched::SerialAddRadial::invoke(tiny, A);
});
// Copy results back to host
Kokkos::deep_copy(A_host, A);
// Verify results
auto A_orig_host = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), A_orig);
bool test_passed = true;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
if (i == j) {
// Diagonal elements should have tiny added
scalar_type expected = A_orig_host(i, j) + tiny;
if (std::abs(A_host(i, j) - expected) > 1e-15) {
test_passed = false;
std::cout << "Diagonal mismatch at (" << i << ", " << j << "): "
<< A_host(i, j) << " vs expected " << expected << std::endl;
}
} else {
// Off-diagonal elements should remain unchanged
if (A_host(i, j) != A_orig_host(i, j)) {
test_passed = false;
std::cout << "Off-diagonal value changed at (" << i << ", " << j << "): "
<< A_host(i, j) << " vs original " << A_orig_host(i, j) << std::endl;
}
}
}
}
if (test_passed) {
std::cout << "AddRadial test: PASSED" << std::endl;
} else {
std::cout << "AddRadial test: FAILED" << std::endl;
}
}
Kokkos::finalize();
return 0;
}
Team Version Example¶
#include <Kokkos_Core.hpp>
#include <KokkosBatched_AddRadial_Decl.hpp>
using execution_space = Kokkos::DefaultExecutionSpace;
using memory_space = execution_space::memory_space;
// Scalar type to use
using scalar_type = double;
int main(int argc, char* argv[]) {
Kokkos::initialize(argc, argv);
{
// Batch and matrix dimensions
int batch_size = 10; // Number of matrices
int n = 5; // Square matrix size
// Create batched matrices
Kokkos::View<scalar_type***, Kokkos::LayoutRight, memory_space>
A("A", batch_size, n, n);
// Initialize on host
auto A_host = Kokkos::create_mirror_view(A);
for (int b = 0; b < batch_size; ++b) {
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
if (i == j) {
// Set diagonal elements to small values for each batch
A_host(b, i, j) = 1.0e-8 * (b + 1);
} else {
// Off-diagonal elements
A_host(b, i, j) = b*n*n + i*n + j + 1;
}
}
}
}
// Copy to device
Kokkos::deep_copy(A, A_host);
// Save original for verification
Kokkos::View<scalar_type***, Kokkos::LayoutRight, memory_space>
A_orig("A_orig", batch_size, n, n);
Kokkos::deep_copy(A_orig, A);
// Values to add to diagonals (one per batch)
Kokkos::View<scalar_type*, memory_space> tiny("tiny", batch_size);
auto tiny_host = Kokkos::create_mirror_view(tiny);
for (int b = 0; b < batch_size; ++b) {
tiny_host(b) = 1.0e-2 * (b + 1);
}
Kokkos::deep_copy(tiny, tiny_host);
// Create team policy
using policy_type = Kokkos::TeamPolicy<execution_space>;
policy_type policy(batch_size, Kokkos::AUTO);
// Apply AddRadial to each matrix using team parallelism
Kokkos::parallel_for("BatchedAddRadial", policy,
KOKKOS_LAMBDA(const typename policy_type::member_type& member) {
const int b = member.league_rank();
auto A_b = Kokkos::subview(A, b, Kokkos::ALL(), Kokkos::ALL());
KokkosBatched::TeamAddRadial<typename policy_type::member_type>
::invoke(member, tiny(b), A_b);
}
);
// Copy results back to host
Kokkos::deep_copy(A_host, A);
// Verify for each batch
auto A_orig_host = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), A_orig);
bool test_passed = true;
for (int b = 0; b < batch_size; ++b) {
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
if (i == j) {
// Diagonal elements should have tiny added
scalar_type expected = A_orig_host(b, i, j) + tiny_host(b);
if (std::abs(A_host(b, i, j) - expected) > 1e-15) {
test_passed = false;
std::cout << "Batch " << b << " diagonal mismatch at (" << i << ", " << j << "): "
<< A_host(b, i, j) << " vs expected " << expected << std::endl;
break;
}
} else {
// Off-diagonal elements should remain unchanged
if (A_host(b, i, j) != A_orig_host(b, i, j)) {
test_passed = false;
std::cout << "Batch " << b << " off-diagonal value changed at (" << i << ", " << j << "): "
<< A_host(b, i, j) << " vs original " << A_orig_host(b, i, j) << std::endl;
break;
}
}
}
if (!test_passed) break;
}
if (!test_passed) break;
}
if (test_passed) {
std::cout << "Batched TeamAddRadial test: PASSED" << std::endl;
} else {
std::cout << "Batched TeamAddRadial test: FAILED" << std::endl;
}
}
Kokkos::finalize();
return 0;
}