Task 1 of 6

What a Flip Would Cost

A magnet, stripped to almost nothing: a grid of arrows, each one either up (+1) or down (−1), and a single rule — neighbours would rather agree. Ernst Ising's 1925 model is that sentence and no more, and it is still the standard proving ground for phase transitions, because it is simple enough to be solved exactly and rich enough to have one.

Agreement is written as energy. Every neighbouring pair contributes −s·s': −1 when the two agree, +1 when they do not, so the lattice's total energy falls as more spins line up. Now ask what one spin flipping would do. Its four bonds all reverse, so the change is

ΔE = 2 · s · (up + down + left + right)

and because every spin and every neighbour is ±1, that has exactly five possible values: −8 when all four neighbours disagree with you (flipping is a bargain), through 0, up to +8 when all four agree (flipping is the most expensive move on the board). This lattice is a torus — the right edge is glued to the left, the top to the bottom — so there are no boundary cells to special-case, and every one of the 16,384 threads does the identical four reads. Pure gather, the shape Thinking in Parallel calls the one that always parallelises.

five neighbourhoods, five prices — and only two of them are ever a gamble — Five spin neighbourhoods side by side, with four, three, two, one and zero neighbours agreeing with the centre spin, and the resulting flip costs +8, +4, 0, -4 and -8.
Goal: finish the kernel so cell [y][x] holds 2 · s[y][x] · (sum of its four neighbours), with the neighbour indices wrapping round the lattice.

Requirements

Hint 1 — where the 2 comes from

This spin's share of the energy is −s · (neighbour sum). Flip it and the share becomes +s · (neighbour sum). The difference between those two is 2 · s · (neighbour sum) — the bonds do not just vanish, they reverse, so the change is twice the share, not once.

Hint 2 — the wrap that bites

(x - 1) % n is -1 at x = 0, in JavaScript and in gpu.js's GLSL alike — both keep the sign of the left operand. Reading s[y][-1] gives you undefined on the CPU backend and a zero out of nowhere on WebGL. Add the size before you subtract:

const left  = s[y][(x + n - 1) % n];
const right = s[y][(x + 1) % n];
const up    = s[(y + n - 1) % n][x];
const down  = s[(y + 1) % n][x];
Hint 3 — the whole body
const sum = s[y][(x + 1) % n] + s[y][(x + n - 1) % n]
          + s[(y + 1) % n][x] + s[(y + n - 1) % n][x];
return 2 * s[y][x] * sum;

Same idea elsewhere

A four-neighbour gather with periodic wrap is one of the most-written kernels there is — CUDA and WGSL spell it the same way, and a graphics API gives you the wrap for free by setting a texture's address mode to repeat instead of doing modular arithmetic at all. The five-value structure matters too: a stencil whose result comes from a tiny discrete set is exactly the case where production Ising codes drop the exponential and look the answer up in a five-entry table.

All tasks in The Ising Model: Colour to Break the Race

  1. What a Flip Would Cost
  2. Randomness Without a Random Number Generator
  3. Everyone at Once Is Wrong
  4. Colour the Lattice
  5. Two Halves Make a Sweep
  6. Drag the Temperature Across Tc

This page is an interactive exercise — the editor, the GPU runner and your saved progress need JavaScript. The text above is the full brief.