sinatras/pmpp-eval huggingface dataset:
Task: ch15-bfs-edge-centric-single
            Target file: student_kernel.cu

            Implementation requirements:
- Initialize levels to INF_LVL with level[src] = 0.
- Optionally precompute an edge->vertex mapping for efficient edge traversal.
- Iteratively launch an edge-centric kernel that marks newly discovered vertices and sets an activity flag.
- Stop when no edge discovers new vertices; CSR arrays must remain unchanged.

            Here is the current student_kernel.cu:

            ```cuda
            // ch15-bfs-edge-centric-single / student_kernel.cu
#include <cuda_runtime.h>
#include <limits.h>

#ifndef INF_LVL
#define INF_LVL 0x3f3f3f3f
#endif

__global__ void _init_levels_edge(int* __restrict__ level, int V, int src){
    // TODO: Initialize the level array and seed the source vertex.
    int i = blockIdx.x * blockDim.x + threadIdx.x;
    if (i < V) {
        level[i] = INF_LVL;
    }
    if (i == src) {
        level[i] = 0;
    }
}

__global__ void bfs_edge_centric_kernel(const int* __restrict__ row_ptr,
                                        const int* __restrict__ col_idx,
                                        int* __restrict__ level,
                                        int cur_level,
                                        int E,
                                        int* __restrict__ active_found)
{
    // TODO: Iterate one edge per thread, discover newly reached vertices, and
    // signal progress via active_found.
    if (blockIdx.x * blockDim.x + threadIdx.x < E) {
        (void)row_ptr;
        (void)col_idx;
        (void)level;
        (void)cur_level;
        (void)active_found;
    }
}

extern "C" void bfs_edge_centric_gpu(const int* d_row_ptr,
                                     const int* d_col_idx,
                                     int V, int E,
                                     int src,
                                     int* d_level)
{
    // TODO: Alternate between edge-centric relaxations until no progress is
    // made.  Maintain device-side flags and handle empty graphs gracefully.
    if (V <= 0 || E < 0) {
        return;
    }

    dim3 b(128);
    dim3 g((V + b.x - 1) / b.x);
    _init_levels_edge<<<g, b>>>(d_level, V, src);
}
            ```
Task: ch16-conv2d-forward-single
            Target file: student_kernel.cu

            Implementation requirements:
- Decode each thread id into (n, oc, oh, ow) for NCHW output layout.
- Accumulate input[n,c,ih,iw] * weight[oc,c,kh,kw] over channels and kernel, skipping out-of-bounds taps.
- Add bias[oc] if provided and write to output; guard threads with tid >= total outputs.

            Here is the current student_kernel.cu:

            ```cuda
            // ch16-conv2d-forward-single / student_kernel.cu
#include <cuda_runtime.h>

extern "C" __global__
void conv2d_forward_kernel(
    const float* __restrict__ input,
    const float* __restrict__ weight,
    const float* __restrict__ bias,
    float* __restrict__ output,
    int N, int C, int H, int W,
    int OC, int kernel_h, int kernel_w,
    int stride_h, int stride_w,
    int out_h, int out_w)
{
    (void)input;
    (void)weight;
    (void)bias;
    (void)N; (void)C; (void)H; (void)W;
    (void)OC; (void)kernel_h; (void)kernel_w;
    (void)stride_h; (void)stride_w;
    (void)out_h; (void)out_w;

    // TODO: Map each thread to a unique (n, oc, oh, ow) output element and
    // perform the convolution accumulation over the input tensor.

    int tid = blockIdx.x * blockDim.x + threadIdx.x;
    long long total = 1LL * N * OC * out_h * out_w;
    if ((long long)tid >= total) {
        return;
    }

    if (output) {
        output[tid] = 0.0f; // placeholder value so the stub compiles
    }
}
            ```
Task: ch16-maxpool2d-forward-single
            Target file: student_kernel.cu

            Implementation requirements:
- Assign one thread per output element (n, c, oh, ow).
- Scan the pooling window, tracking both maximum value and argmax index (kh*kernel_w + kw).
- Store the max into output and argmax into indices; initialize indices to -1.
- Guard threads with tid >= total outputs.

            Here is the current student_kernel.cu:

            ```cuda
            // ch16-maxpool2d-forward-single / student_kernel.cu
#include <cuda_runtime.h>

extern "C" __global__
void maxpool2d_forward_kernel(const float* input, float* output, int* indices,
                              int batch_size, int channels,
                              int height, int width,
                              int kernel_h, int kernel_w,
                              int stride_h, int stride_w,
                              int out_h, int out_w)
{
    (void)input;
    (void)batch_size; (void)channels;
    (void)height; (void)width;
    (void)kernel_h; (void)kernel_w;
    (void)stride_h; (void)stride_w;
    (void)out_h; (void)out_w;

    // TODO: For each thread, compute the maximum value within the pooling
    // window and track the argmax (flattened kernel index).

    int tid = blockIdx.x * blockDim.x + threadIdx.x;
    long long total = 1LL * batch_size * channels * out_h * out_w;
    if ((long long)tid >= total) {
        return;
    }

    if (output) {
        output[tid] = 0.0f;
    }
    if (indices) {
        indices[tid] = -1;
    }
}
            ```
Task: ch17-fhd-accumulate-single
Target file: student_kernel.cu

Here is the current skeleton you must complete:

```cuda
// ch17-fhd-accumulate-single/student_kernel.cu
#include <cuda_runtime.h>
#include <math_constants.h>

extern "C" __global__
void fhd_accumulate_kernel(const float* __restrict__ rPhi,
                           const float* __restrict__ iPhi,
                           const float* __restrict__ rD,
                           const float* __restrict__ iD,
                           const float* __restrict__ kx,
                           const float* __restrict__ ky,
                           const float* __restrict__ kz,
                           const float* __restrict__ x,
                           const float* __restrict__ y,
                           const float* __restrict__ z,
                           int M, int N,
                           float* __restrict__ rFhD,
                           float* __restrict__ iFhD)
{
    // TODO:
    // - 1 thread per n (global id = blockIdx.x*blockDim.x + threadIdx.x)
    // - Guard: if (n >= N) return;
    // - Load x[n], y[n], z[n] into registers
    // - Accumulate over m=0..M-1:
    //      rmu = rPhi[m]*rD[m] + iPhi[m]*iD[m]
    //      imu = rPhi[m]*iD[m] - iPhi[m]*rD[m]
    //      ang = 2*pi*(kx[m]*xn + ky[m]*yn + kz[m]*zn)
    //      c = cosf(ang); s = sinf(ang)
    //      r_acc += rmu*c - imu*s
    //      i_acc += imu*c + rmu*s
    // - Finally: rFhD[n] += r_acc; iFhD[n] += i_acc;

    // TODO: Implement the FHD accumulation kernel here
}
```
Task: ch17-fhd-fission-two-kernels-single
Target file: student_kernel.cu

Goal: Split the fissioned FHD computation into two kernels. First, compute the complex products `(rMu, iMu)` for every frequency `m`. Second, accumulate those precomputed values across all `m` for each spatial sample `n`, matching the fused reference implementation.

Key requirements:
- Keep the inputs read-only and accumulate results into `rFhD` / `iFhD` using `+=`.
- Use the provided TWO_PI constant when computing `ang`.
- Launch `compute_mu_kernel` with one thread per `m`; launch `fhd_accumulate_mu_kernel` with one thread per `n`.
- Preserve the maths shown in the comments and guard index bounds.

Skeleton:
```cuda
// ch17-fhd-fission-two-kernels-single/student_kernel.cu
#include <cuda_runtime.h>

// TODO (A): compute_mu_kernel
// Each thread handles one m (if m < M):
//   rMu[m] = rPhi[m]*rD[m] + iPhi[m]*iD[m]
//   iMu[m] = rPhi[m]*iD[m] - iPhi[m]*rD[m]
extern "C" __global__
void compute_mu_kernel(const float* __restrict__ rPhi,
                       const float* __restrict__ iPhi,
                       const float* __restrict__ rD,
                       const float* __restrict__ iD,
                       int M,
                       float* __restrict__ rMu,
                       float* __restrict__ iMu)
{
    // TODO: Implement complex multiplication for each m
    // Hint: int m = blockIdx.x * blockDim.x + threadIdx.x;
}

// TODO (B): fhd_accumulate_mu_kernel
// One thread per n; loop over m using precomputed rMu/iMu.
// Accumulate into rFhD[n], iFhD[n] using Fourier transform formula.
//
// IMPORTANT FORMULAS:
// 1. Angle calculation must include TWO_PI (2pi):
//    const float TWO_PI = 6.2831853071795864769f;
//    float ang = TWO_PI * (kx[m]*xn + ky[m]*yn + kz[m]*zn);
//
// 2. Use ACCUMULATION (+=), not assignment (=), because this kernel may be
//    called multiple times:
//    rFhD[n] += r_acc;  // NOT rFhD[n] = r_acc;
//    iFhD[n] += i_acc;  // NOT iFhD[n] = i_acc;
//
// Algorithm:
//   int n = blockIdx.x * blockDim.x + threadIdx.x;
//   if (n < N) {
//       float r_acc = 0.0f, i_acc = 0.0f;
//       for (int m = 0; m < M; ++m) {
//           float ang = TWO_PI * (kx[m]*x[n] + ky[m]*y[n] + kz[m]*z[n]);
//           float c = cosf(ang), s = sinf(ang);
//           r_acc += rMu[m] * c - iMu[m] * s;
//           i_acc += iMu[m] * c + rMu[m] * s;
//       }
//       rFhD[n] += r_acc;
//       iFhD[n] += i_acc;
//   }
extern "C" __global__
void fhd_accumulate_mu_kernel(const float* __restrict__ rMu,
                              const float* __restrict__ iMu,
                              const float* __restrict__ kx,
                              const float* __restrict__ ky,
                              const float* __restrict__ kz,
                              const float* __restrict__ x,
                              const float* __restrict__ y,
                              const float* __restrict__ z,
                              int M, int N,
                              float* __restrict__ rFhD,
                              float* __restrict__ iFhD)
{
    // TODO: Implement accumulation using precomputed rMu, iMu (see formula above)
}
```
Task: ch18-energy-scatter-single
Target file: student_kernel.cu

Here is the current skeleton you must complete:

```cuda
// ch18-energy-scatter-single / student_kernel.cu
//
// Implement Fig. 18.5 (SCATTER): one thread per atom, looping over all (i,j)
// grid points on a fixed z-slice and ATOMICALLY accumulating into energygrid.
//
// CONTRACT
// - Constant memory holds a *chunk* of atoms: __constant__ float atoms[CHUNK_SIZE*4]
//   as (x,y,z,charge) AoS, 4 floats per atom.
// - The test harness uploads atoms chunk-by-chunk via cudaMemcpyToSymbol and then
//   launches the kernel once per chunk, accumulating into the same output slice.
// - Kernel params:
//     energygrid    : pointer to [grid.x * grid.y * grid.z] floats
//     grid          : logical 3D grid dimensions (x,y,z) for indexing
//     gridspacing   : spacing used to compute x = i*gridspacing, y = j*gridspacing
//     z             : world-space z coordinate of the slice (must be multiple of gridspacing)
//     atoms_in_chunk: number of atoms loaded in constant memory for this launch (<= CHUNK_SIZE)
//     start_atom    : global offset of first atom of the chunk (not needed for correct math;
//                     included so your signature matches reference; you may ignore it)
// - Must use atomicAdd on energygrid writes (scatter means threads collide on same cell).
// - Bounds: guard i in [0,grid.x), j in [0,grid.y).
//
// HINTS
// - Compute k = int(z / gridspacing) once per kernel; assume z aligns.
// - Thread id tid covers one atom in [0, atoms_in_chunk).
// - Load (ax,ay,az,q) from constant memory as atoms[4*tid + {0,1,2,3}].
// - For each j row, precompute y and (y-ay), (z-az) and reuse (dy*dy + dz*dz).
// - Use sqrtf for single-precision.
// - Use 1D blocks and grids for atom threads (e.g., blockDim.x = 256).
//
// PERFORMANCE is not graded here-correctness, safety (no OOB), and atomicity are.

#ifndef CHUNK_SIZE
#define CHUNK_SIZE 256
#endif

__constant__ float atoms[CHUNK_SIZE * 4];

extern "C" __global__
void cenergyScatterKernel(float* __restrict__ energygrid,
                          dim3 grid,
                          float gridspacing,
                          float z,
                          int atoms_in_chunk,
                          int /*start_atom_unused*/) {
    // TODO: Implement scatter kernel (one thread per atom)
    // 1. Get thread ID and bounds check
    // 2. Load atom data from constant memory
    // 3. Compute z-slice index k
    // 4. Loop over all (i,j) grid points in the slice
    // 5. For each grid point, compute distance and contribution
    // 6. Use atomicAdd to accumulate into energygrid
}
```
Task: ch18-energy-gather-single
Target file: student_kernel.cu

Goal: Implement the gather variant of the molecular energy kernel. Each thread owns one grid cell, loops over the atoms in the constant-memory chunk, accumulates a private sum, and writes exactly once to the output grid.

Key requirements:
- Use a 2D launch (threadIdx.x/y) to cover the grid tile and guard indices.
- Loop over all atoms in the uploaded chunk and accumulate into a private `energy` value.
- Write exactly one `+=` update per grid cell (no atomics).
- Follow the provided formulas for indexing and distance accumulation.

Skeleton:
```cuda
// ch18-energy-gather-single / student_kernel.cu
//
// Implement Fig. 18.6 (GATHER): one thread per grid point (on a fixed z-slice).
// Each thread loops over all atoms in the current constant-memory chunk and
// accumulates a private sum, then writes exactly once to energygrid (+=).
//
// CONTRACT
// - Constant memory holds a *chunk* of atoms: __constant__ float atoms[CHUNK_SIZE*4].
// - Kernel params:
//     energygrid    : pointer to [grid.x * grid.y * grid.z] floats
//     grid          : logical 3D grid dimensions (x,y,z) for indexing
//     gridspacing   : spacing for x=i*h, y=j*h
//     z             : world-space z of the slice
//     atoms_in_chunk: number of atoms currently loaded (<= CHUNK_SIZE)
//     start_atom    : global offset of first atom in the chunk (not needed here)
// - NO atomics: each thread owns its output cell and does `energygrid[idx] += local_sum`.
// - 2D launch is expected (e.g., block=(16,16)).
//
// HINTS
// - Compute (dy*dy + dz*dz) per row and reuse where reasonable.
// - Use sqrtf and a small denominator clamp to avoid division by zero.

#ifndef CHUNK_SIZE
#define CHUNK_SIZE 256
#endif

__constant__ float atoms[CHUNK_SIZE * 4];

extern "C" __global__
void cenergyGatherKernel(float* __restrict__ energygrid,
                         dim3 grid,
                         float gridspacing,
                         float z,
                         int atoms_in_chunk,
                         int /*start_atom_unused*/) {
    // TODO: Implement gather kernel (one thread per grid cell)
    // 1. Get 2D thread indices (i,j) for grid position
    // 2. Bounds check against grid dimensions (grid.x, grid.y)
    // 3. Compute z-slice index and validate:
    //    int k = int(z / gridspacing);
    //    if (k < 0 || k >= (int)grid.z) return;
    // 4. Compute world-space coordinates (x = i*gridspacing, y = j*gridspacing)
    // 5. Loop over all atoms in the current chunk
    // 6. For each atom, compute distance and contribution
    // 7. Compute 3D linearized index into energygrid:
    //    size_t idx = (size_t)grid.x * grid.y * k + (size_t)grid.x * j + (size_t)i;
    // 8. Accumulate private sum, then write once: energygrid[idx] += sum
}
```
Task: ch18-energy-gather-coarsened-single
            Target file: student_kernel.cu

            Implementation requirements:
- Compute base_i and j from block/thread indices and determine k from z/gridspacing.
- Maintain a register array of size COARSEN_FACTOR to accumulate per-thread contributions.
- Loop over atoms_in_chunk, accumulating q / max(distance, 1e-12f) for owned cells.
- Write each owned grid cell exactly once without atomics, guarding grid bounds.

            Here is the current student_kernel.cu:

            ```cuda
            // ch18-energy-gather-coarsened-single / student_kernel.cu
//
// Implement a coarsened gather kernel (Fig. 18.8).  The reference solution
// shows the full algorithm; here we deliberately leave the core computation as
// a TODO so the student model must fill it in.

#ifndef CHUNK_SIZE
#define CHUNK_SIZE 256
#endif
#ifndef COARSEN_FACTOR
#define COARSEN_FACTOR 8
#endif

__constant__ float atoms[CHUNK_SIZE * 4];

extern "C" __global__
void cenergyCoarsenKernel(float* __restrict__ energygrid,
                          dim3 grid,
                          float gridspacing,
                          float z,
                          int /*atoms_in_chunk*/,
                          int /*start_atom_unused*/) {
    int base_i = blockIdx.x * (blockDim.x * COARSEN_FACTOR) + threadIdx.x * COARSEN_FACTOR;
    int j      = blockIdx.y * blockDim.y + threadIdx.y;

    if (j < 0 || j >= (int)grid.y) {
        return;
    }

    int k = int(z / gridspacing);
    if (k < 0 || k >= (int)grid.z) {
        return;
    }

    // TODO: Implement thread-coarsened energy accumulation:
    // - Each thread processes COARSEN_FACTOR grid points (base_i to base_i + COARSEN_FACTOR - 1)
    // - For each grid point (i, j, k), accumulate energy contributions from all atoms in constant memory
    // - Atoms are stored in constant memory as [x, y, z, charge] in structure-of-arrays layout
    // - Compute distance from each atom to grid point: dx, dy, dz
    // - Energy contribution: charge / sqrt(dx^2 + dy^2 + dz^2)
    // - Add accumulated energy to energygrid[idx] (no atomics needed - each thread owns its points)
    // - Use proper bounds checking for i in [0, grid.x)
    //
    // Hints:
    // - Grid point coordinates: x = i * gridspacing, y = j * gridspacing, z already given
    // - Atom coordinates: atoms[a*4+0], atoms[a*4+1], atoms[a*4+2], atoms[a*4+3] (charge)
    // - 3D array index: idx = k * grid.x * grid.y + j * grid.x + i
}
            ```
Task: ch20-stencil-25pt-single-gpu-single
Target file: student_kernel.cu

Here is the current skeleton you must complete:

```cuda
#include <cuda_runtime.h>

// TODO: Implement a single-GPU axis-aligned 25-point stencil with radius R=4.
// Contract:
//  - Input/Output are dense 3D grids (dimx*dimy*dimz), row-major:
//      idx(i,j,k) = (k*dimy + j)*dimx + i
//  - For interior cells (i,j,k  [4 .. dim-1-4]) compute:
//      out = w0*center + _{d=1..4} w[d] * (d along x + d along y + d along z)
//    with weights: w0=0.5, w1=0.10, w2=0.05, w3=0.025, w4=0.0125
//  - Boundary cells (within 4 of any face) must be copy-through: out=in
//  - Reasonable 3D launch config and synchronization
//
// Suggested steps:
//  1) write idx3 helper
//  2) in-kernel boundary test => copy-through
//  3) accumulate using a small unrolled loop d=1..4
//  4) host wrapper launches kernel

static inline __device__ size_t idx3(int i,int j,int k,int dx,int dy){
    return (size_t(k)*dy + j)*dx + i;
}

__global__ void stencil25_kernel(const float* __restrict__ in,
                                 float* __restrict__ out,
                                 int dimx, int dimy, int dimz)
{
    // TODO
}

extern "C" void stencil25_single_gpu(const float* d_in, float* d_out,
                                     int dimx, int dimy, int dimz)
{
    // TODO: choose block/grid and launch kernel, then cudaDeviceSynchronize()
}
```
Task: ch20-stencil-25pt-slab-stage1-boundary
Target file: student_kernel.cu

Goal: Update only the Stage-1 boundary planes (the first and last four owned slices) of a 3D 25-point stencil on a slab with halo padding. Leave interior planes untouched; rely on halos that already exist for this phase.

Key requirements:
- Operate on input `d_in` / output `d_out` arranged with four halo planes on each side (`owned z  [4 .. 4+dimz-1]`).
- Compute stencil weights using the provided coefficients for 1..4 offsets in x, y, and z.
- When i or j are within the halo distance, copy-through rather than reading out-of-bounds.
- Do not modify interior or halo planes; only Stage-1 boundary planes should be written.

Skeleton:
```cuda
#include <cuda_runtime.h>

// TODO: Implement Stage-1 boundary update for axis-aligned 25-point stencil (R=4)
// Local z layout has halos: total_z = dimz + 8
// Owned region z  [4 .. 4+dimz-1]
// Stage-1 planes: [4..7] and [4+dimz-4 .. 4+dimz-1]
// Within Stage-1 planes:
//   - For i/j interior (>=4 and <dim-4) compute stencil
//   - For i/j near faces, copy-through
// Do not write interior planes or halos.
//
// STENCIL WEIGHTS: Use distance-based weighted stencil (NOT simple averaging!)
// - w0 = 0.5   (center point)
// - w1 = 0.10  (distance 1 neighbors: 1 in each axis)
// - w2 = 0.05  (distance 2 neighbors: 2 in each axis)
// - w3 = 0.025 (distance 3 neighbors: 3 in each axis)
// - w4 = 0.0125 (distance 4 neighbors: 4 in each axis)
//
// Formula: out[i,j,k] = w0 * in[i,j,k]
//                     + w1 * (in[i1,j,k] + in[i,j1,k] + in[i,j,k1])
//                     + w2 * (in[i2,j,k] + in[i,j2,k] + in[i,j,k2])
//                     + w3 * (in[i3,j,k] + in[i,j3,k] + in[i,j,k3])
//                     + w4 * (in[i4,j,k] + in[i,j4,k] + in[i,j,k4])

static inline __device__ size_t idx3(int i,int j,int k,int dx,int dy){
    return (size_t(k)*dy + j)*dx + i;
}

__global__ void stencil25_stage1_kernel(const float* __restrict__ in,
                                        float* __restrict__ out,
                                        int dimx,int dimy,int dimz)
{
    // TODO
}

extern "C" void stencil25_stage1_boundary(const float* d_in, float* d_out,
                                          int dimx,int dimy,int dimz)
{
    // TODO: launch 3D grid over local z  [0 .. dimz+7]
}
```
Task: ch20-mpi-halo-pack-unpack
Target file: student_kernel.cu

Here is the current skeleton you must complete:

```cuda
#include <cuda_runtime.h>

// TODOs:
// Implement two host wrappers that launch simple 2D grids:
//
// 1) halo_pack_boundaries(d_grid, dimx,dimy,dimz, d_left_send, d_right_send)
//    - Read 4 owned boundary planes and pack into left/right buffers.
//      Owned z range is [4 .. 4+dimz-1]. Pack planes:
//         left : k = 4 + p,           p  [0..3]
//         right: k = (4+dimz-4) + p,  p  [0..3]
//    - Packed layout is plane-major then row-major:
//         pack_idx(p,j,i) = (p*dimy + j)*dimx + i
//
// 2) halo_unpack_to_halos(d_grid, dimx,dimy,dimz, d_left_recv, d_right_recv)
//    - Write left_recv to left halo k = 0..3  (k = 0 + p)
//    - Write right_recv to right halo k = dimz+4 .. dimz+7 (k = dimz+4 + p)
//    - Same pack_idx layout for sources.
//
// Keep the rest of the grid untouched.

static inline __device__ size_t idx3(int i,int j,int k,int dx,int dy){
    return (size_t(k)*dy + j)*dx + i;
}
static inline __device__ size_t pack_idx(int p,int j,int i,int dx,int dy){
    return (size_t(p)*dy + j)*dx + i;
}

__global__ void k_pack_student(const float* __restrict__ grid,
                               int dimx,int dimy,int dimz,
                               float* __restrict__ left_send,
                               float* __restrict__ right_send)
{
    // TODO: implement (mirror reference description above)
}

__global__ void k_unpack_student(float* __restrict__ grid,
                                 int dimx,int dimy,int dimz,
                                 const float* __restrict__ left_recv,
                                 const float* __restrict__ right_recv)
{
    // TODO: implement (mirror reference description above)
}

extern "C" void halo_pack_boundaries(const float* d_grid,
                                     int dimx,int dimy,int dimz,
                                     float* d_left_send,
                                     float* d_right_send)
{
    // TODO: choose block(16,16) grid(ceil) and launch k_pack_student, then sync
}

extern "C" void halo_unpack_to_halos(float* d_grid,
                                     int dimx,int dimy,int dimz,
                                     const float* d_left_recv,
                                     const float* d_right_recv)
{
    // TODO: choose block(16,16) grid(ceil) and launch k_unpack_student, then sync
}
```