Task 1 of 5

Filter Has No Kernel

On a CPU, filtering is four words: data.filter(v => v >= 50). Underneath it is a loop with a moving write cursor — every element that passes gets pushed at wherever the last one left off:

const kept = [];
for (const v of data) {
  if (v >= 50) kept.push(v);   // ← push() knows where the cursor is
}

That cursor is the problem. Thread 7 can tell you instantly whether data[7] survives. It cannot tell you where it goes, because that depends on how many of elements 0…6 survived — six other threads' business, none of which thread 7 is allowed to ask about. An output position that depends on other threads is not something a single kernel can compute, which is why there is no filter kernel and never will be.

So compaction gets built out of pieces, and the first piece is the one part that is perfectly independent: the flag pass. Turn the predicate into a mask of 1s and 0s — a plain map, one thread per element, nobody talking to anybody. Run it and look at what you get: the ones and zeros line up under the input, holes and all. Flags say who survives. They move nothing.

Goal: return 1 when this thread's sample is at or above this.constants.threshold, and 0 when it is not.

Requirements

Hint 1 — a predicate is just a map

Read your own element and compare it — nothing else. The comparison samples[this.thread.x] >= this.constants.threshold is the whole decision; all that is left is turning it into a number.

Hint 2 — the one-liner
return samples[this.thread.x] >= this.constants.threshold ? 1 : 0;

Same idea elsewhere

Every compaction library on every platform starts here, and most of them let you hand the mask in yourself: CUB's DeviceSelect::Flagged takes a flags array beside the data, Thrust's copy_if takes the predicate and builds the same mask internally, and a WebGPU pipeline writes it to a storage buffer with one dispatch. The predicate pass is the cheap, embarrassingly parallel part — everything after it is the interesting problem.

All tasks in Stream Compaction

  1. Filter Has No Kernel
  2. Where Do I Land?
  3. Turn the Scatter Around
  4. Find It in log n
  5. Payoff: How Many Survived

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