Task 2 of 5
Iterating is easy; knowing when to stop is the skill. The honest measure is the
residual: take the current guess, put it back into the equation, and see
how badly it is violated. For "every cell equals the average of its four neighbours" that
is the 5-point Laplacian — left + right + up + down − 4·centre — the same
stencil Reaction–Diffusion uses to diffuse, borrowed here as a scorecard. Zero where the
equation holds, large where it does not.
Boundary cells have no equation to violate: they are given, not solved. Their residual
is 0 by definition rather than by accident, and saying so in the kernel keeps
the edge from polluting the score forever.
A grid of numbers is not a progress report, so collapse it to one: the root-mean-square over the grid. Totalling a grid on the GPU is the halving ladder Reductions builds; at 1,024 cells the read-back is cheaper than the ladder, so this sum happens in plain JavaScript.
residual kernel and the
rmsOf helper. The sweep loop is already wired and will print the residual
every 10 sweeps — you should watch it fall by a factor of about 36.0 for boundary cellsleft + right + up + down − 4·centre — a sum, with no divisionrmsOf(grid) returns Math.sqrt(sum of every cell squared / (32 × 32))Same five reads as the Jacobi sweep, assembled differently: the update divides
the neighbour sum by 4, the residual subtracts 4 × centre from it.
return u[y][x - 1] + u[y][x + 1] + u[y - 1][x]
+ u[y + 1][x] - 4 * u[y][x];residual(u) hands back a plain 2D array of numbers, so:
let sum = 0;
for (let y = 0; y < 32; y++) {
for (let x = 0; x < 32; x++) sum += grid[y][x] * grid[y][x];
}
return Math.sqrt(sum / (32 * 32));
Square, mean, root — in that order. Divide by every cell in the grid, not just the interior ones.
This page is an interactive exercise — the editor, the GPU runner and your saved progress need JavaScript. The text above is the full brief.