KokkosSparse::gauss_seidel_symbolic¶
Defined in header KokkosSparse_gauss_seidel.hpp
template <typename ExecutionSpace, typename KernelHandle, typename lno_row_view_t_, typename lno_nnz_view_t_>
void gauss_seidel_symbolic(const ExecutionSpace &space, KernelHandle *handle,
typename KernelHandle::const_nnz_lno_t num_rows,
typename KernelHandle::const_nnz_lno_t num_cols, lno_row_view_t_ row_map,
lno_nnz_view_t_ entries, bool is_graph_symmetric = true);
template <typename KernelHandle, typename lno_row_view_t_, typename lno_nnz_view_t_>
void gauss_seidel_symbolic(KernelHandle *handle, typename KernelHandle::const_nnz_lno_t num_rows,
typename KernelHandle::const_nnz_lno_t num_cols, lno_row_view_t_ row_map,
lno_nnz_view_t_ entries, bool is_graph_symmetric = true);
Performs the symbolic phase of the Gauss-Seidel preconditioner setup. The details of the setup depend on the algorithm selected by the handle.
Perform symbolic operations to setup the Gauss-Seidel/SOR preconditioner.
Same as 1. but uses the resources of the default execution space instance associated with
KernelHandle::HandleExecSpace
.
Parameters¶
- space:
execution space instance describing the resources available to run the kernels.
- handle:
an instance of
KokkosKernels::KokkosKernelsHandle
from which a gs_handle will be used to extract control parameters.- num_rows, num_cols:
the number of rows and columns of the input matrix.
- rowmap:
row map of the input matrix.
- entries:
column indices of the input matrix.
- is_graph_symmetric:
control parameters indicating if the graph of the input matrix is symmetric. This information may be used by the implementation to chose faster implementations.
Type Requirements¶
The types of the input parameters must be consistent with the types defined by the
KernelHandle
:std::is_same_v<typename KernelHandle::const_size_type, typename lno_row_view_t_::const_value_type>
std::is_same_v<typename KernelHandle::const_nnz_lno_t, typename lno_nnz_view_t_::const_value_type>
Example¶
#include "Kokkos_Core.hpp"
#include "KokkosKernels_Handle.hpp"
#include "KokkosSparse_IOUtils.hpp"
#include "KokkosSparse_spmv.hpp"
#include "KokkosSparse_CrsMatrix.hpp"
#include "KokkosSparse_gauss_seidel.hpp"
#include "KokkosBlas1_nrm2.hpp"
int main() {
using ExecSpace = Kokkos::DefaultExecutionSpace;
using MemSpace = typename ExecSpace::memory_space;
using Handle = KokkosKernels::KokkosKernelsHandle<int, int, double, ExecSpace, MemSpace, MemSpace>;
using Matrix = KokkosSparse::CrsMatrix<double, int, ExecSpace, void, int>;
using Vector = typename Matrix::values_type;
constexpr int numRows = 10000;
Kokkos::initialize();
{
// Generate a square, diagonally dominant, but nonsymmetric matrix
// on which Gauss-Seidel should converge in a few iterations.
// Insert about 20 entries per row.
int nnz = numRows * 20;
Matrix A = KokkosSparse::Impl::kk_generate_diagonally_dominant_sparse_matrix<Matrix>(
numRows, numRows, nnz, 2, 100, 1.05);
Handle handle;
handle.create_gs_handle(KokkosSparse::GS_DEFAULT);
// Symbolic setup (for A's sparsity pattern).
KokkosSparse::gauss_seidel_symbolic(
&handle, numRows, numRows, A.graph.row_map, A.graph.entries,
/* whether matrix is structurally symmetric */ false);
// Numeric setup (for A's values).
// If A's values change but sparsity pattern remains the same,
// gauss_seidel_numeric can be called again to reuse the handle.
KokkosSparse::gauss_seidel_numeric(
&handle, numRows, numRows, A.graph.row_map, A.graph.entries, A.values,
/* whether matrix is structurally symmetric */ false);
// Create random right-hand side vector b
Vector b(Kokkos::view_alloc(Kokkos::WithoutInitializing, "b"), numRows);
auto bHost = Kokkos::create_mirror_view(b);
for (int i = 0; i < numRows; i++) bHost(i) = 3 * ((1.0 * rand()) / RAND_MAX);
Kokkos::deep_copy(b, bHost);
// Create uninitialized left-hand side (solution) vector
Vector x(Kokkos::view_alloc(Kokkos::WithoutInitializing, "x"), numRows);
// Compute initial residual norm, (for initial guess x = 0)
double initialRes = KokkosBlas::nrm2(b);
double scaledResNorm = 1.0;
bool firstIter = true;
Vector res(Kokkos::view_alloc(Kokkos::WithoutInitializing, "res"), numRows);
// Iterate until reaching the tolerance
int numIters = 0;
while (scaledResNorm > 1e-6) {
KokkosSparse::forward_sweep_gauss_seidel_apply(
&handle, numRows, numRows, A.graph.row_map, A.graph.entries, A.values, x, b,
/* whether to zero out x */ firstIter,
/* that we are running with a new right-hand side b */ firstIter,
/* damping factor (omega) */ 1.0,
/* number of iterations */ 1);
firstIter = false;
// Compute residual: res := Ax - b
Kokkos::deep_copy(res, b);
KokkosSparse::spmv("N", 1.0, A, x, -1.0, res);
// Recompute the scaled norm
scaledResNorm = KokkosBlas::nrm2(res) / initialRes;
numIters++;
std::cout << "Iteration " << numIters << " scaled residual norm: " << scaledResNorm << '\n';
}
std::cout << "SUCCESS: converged in " << numIters << " iterations.\n";
}
Kokkos::finalize();
return 0;
}