Task 3 of 5
Every pass so far sorted every pair the same way. A bitonic network does not, and that is the whole trick. A sequence that rises and then falls is called bitonic, and a bitonic sequence is the one thing this network can merge into sorted order in log n passes. So the early passes exist to build bitonic runs: neighbouring blocks are deliberately sorted in opposite directions, so that gluing two of them together gives up then down.
Which way your block goes is another bit of your index — the one named by
stage, the size of the block currently being merged:
const dirBit = Math.floor(i / stage) % 2; // 0 → my block sorts ascending
So a thread now holds two bits. strideBit says whether it is the low or the
high member of its pair; dirBit says which way its block is sorting. And the
rule is as small as it could be: keep the smaller value exactly when the two bits
agree. Low member of an ascending block, or high member of a descending one —
either way, minimum.
One detail makes that legal: stride is always smaller than
stage, so flipping the stride bit never disturbs the direction bit. Both
members of a pair read the same dirBit and agree about which way they are
sorting — without exchanging a word.
(data, stage, stride) and returns each thread's new value.strideBit from stride, dirBit from stagestrideBit, exactly as in the last taskMath.min when the two bits agree and Math.max when they differFour cases, and they collapse to one comparison:
low + ascending → min (0, 0) agree
high + ascending → max (1, 0) differ
low + descending → max (0, 1) differ
high + descending → min (1, 1) agreeconst i = this.thread.x;
const strideBit = Math.floor(i / stride) % 2;
const dirBit = Math.floor(i / stage) % 2;
let partner = i - stride;
if (strideBit === 0) partner = i + stride;
const me = data[i];
const other = data[partner];
if (strideBit === dirBit) return Math.min(me, other);
return Math.max(me, other);(i & k) == 0, WGSL compute shaders write the same thing
with &, and the arithmetic spelling here says exactly the same. What none
of them need is communication: the direction is a property of your index, so a thread can
work it out alone, which is what makes the whole network barrier-free within a pass.
This page is an interactive exercise — the editor, the GPU runner and your saved progress need JavaScript. The text above is the full brief.