Task: hpcg_spmv_27pt
Category: HPC reference
Difficulty: 2
Tags: hpcg,spmv,csr,27_point_stencil,sparse_matrix_vector
Source: HPCG: https://github.com/hpcg-benchmark/hpcg
Description: Sparse matrix--vector multiplication on the 27-point structured stencil matrix used by HPCG.

Prompt template (YAML):
task: hpcg_spmv_27pt
summary: >
  Implement a GPU solution for the HPCG reference sparse matrix-vector product.
  The matrix comes from the official 27-point 3D stencil construction and is
  provided in CSR format. Compute y = A x exactly.
inputs:
  - row_ptr: int32[n+1]
  - col_idx: int32[nnz]
  - values: float64[nnz]
  - x: float64[n]
  - params: nx, ny, nz, n, nnz
output:
  - y: float64[n]
notes:
  - Match the CPU reference semantics exactly.
  - The matrix originates from the HPCG 27-point stencil generator.
  - Use CSR semantics as provided; do not assume a dense matrix.
  - Output must match the CPU reference within the configured numeric tolerance.

interface: |
  ```c
  // Single end-to-end call. Do H2D + kernel + D2H and synchronize before returning.
  // Called multiple times (warmup + timed); must be idempotent.
  extern "C" void solution_compute(
      int n,
      const int * row_ptr,
      const int * col_idx,
      const double * values,
      const double * x,
      double * y_out
  );
  ```


CPU reference implementation (C):
#include <stddef.h>
static int g_n = 0; static const int *g_row_ptr = 0; static const int *g_col_idx = 0; static const double *g_values = 0; static const double *g_x = 0;
static void _orbench_old_init(int n, const int *row_ptr, const int *col_idx, const double *values, const double *x) { g_n=n; g_row_ptr=row_ptr; g_col_idx=col_idx; g_values=values; g_x=x; }
static void _orbench_old_compute(double *y_out) { for (int i=0;i<g_n;++i) { double sum=0.0; for (int j=g_row_ptr[i]; j<g_row_ptr[i+1]; ++j) sum += g_values[j]*g_x[g_col_idx[j]]; y_out[i]=sum; } }

// ── Unified compute_only wrapper (auto-migrated) ──
void solution_compute(int n, const int * row_ptr, const int * col_idx, const double * values, const double * x, double * y_out) {
    _orbench_old_init(n, row_ptr, col_idx, values, x);
    _orbench_old_compute(y_out);
}