From Stateful to Stateless Blue Noise reduces a tree of five-state error diffusion machines, one node per output bit, to a tree whose nodes store nothing: each node pairs its visits, and a hash of the node and the pair number decides which of the two gets the 1. The review of hash-based Owen scrambling sets that form beside the literature it belongs to, the shuffled and scrambled radical inverse, and its stream lab shows what the form does in time: it deals. Every aligned block of 2k samples is exact, and a window that slides along the stream is exact on the block boundaries and not between them. That is the starting point here. This article keeps the common-grid form as the reference, removes the grid, and then folds the common-grid form's loop into two nested hashes.
01Where Each Form Came From
None of these was designed in one sitting. Each came out of a question about the one before it, and the order below is the order they were found in.
Asked whether the machine could lose its state. The five-state tree carries an error in every node. Proposed in answer, by the AI co-author of these articles: let every node pair its visits on the sample index, and let a hash of the node and the pair number say which visit of the pair gets the 1. Nothing is stored, any sample can be computed alone, and every aligned block of 2k samples is exact. Up to the hash it is the shuffled radical inverse of the rendering literature, which is very likely where it came from.
Seen dealing. The review that set that form beside its literature has a lab that slides a window along a stream and colours the bins it misses. At one bin per sample the common-grid form went clean on a block boundary, red between, clean again: exact where the grid says, and only there, where the machine with memory stayed level everywhere. The question that raised was whether the grid is intrinsic to having no state. It is not: a node has to pair its visits, but which two visits make a pair is free. Let each node choose by a hash of itself, and the grid is gone.
Asked whether the loop could go. Both listings draw two hashes per level and keep one bit of each. For the common-grid form two nested hashes and three bit reversals give a stream that matches the loop on every stream-wide measure (fair pairs, spectra, exact blocks) once the constants are chosen for fair pairs; a sliding window still tells them apart, because its flips are a pair part and a node part combined, not one draw per node per pair, and its deals come out tied to each other. For the offset form the loop cannot go at all: the offset is added into the visit number, its carries cross the levels, and it is chosen by the output prefix.
What the three have in common, and where they differ:
Bit l is bit l of t, flipped by a hash of the node and the pair number t >> (l + 1). One node visited per level, two hashes per bit. Every aligned block of 2k samples holds each of 2k bins once.
Section 02 · listing blue32_at
Each node pairs its visits at its own hashed offset, so the nodes' pairs no longer line up with the sample index. No block is guaranteed exact, and over seeds no window is worse than another: the sliding window behaviour of the machines with memory, with nothing stored.
Section 03 · listing blue32_continuous_at
Two nested hashes and three bit reversals: one flips every pair at once, one flips every node at once. Eight multiplies for all thirty-two bits, no loop, the same blocks and the same spectra; the deals are tied to each other, which the sliding window shows.
Section 04 · listing blue32_flat_at
02The Common Grid
The reference form, as the previous article left it. A node is the output bits already decided; its visits come in pairs, visits 2m and 2m + 1 of the node, and the pair is 01 or 10 by a hash of the node and m. Because every node takes the pairing (2m, 2m + 1), every node's pairs line up with the sample index, and the exact blocks follow: the root deals the halves in every aligned pair of samples, each child deals the quarters in every aligned block of four, and so on down.
hash(node, t >> (l + 1)) ^ ((t >> l) & 1)node: the output bits already decided, levels 0 to l − 1The node is named by the output bits above it, so the levels are computed in order, most significant first, one hash per level.
Up to the hash this is the radical inverse with its index shuffled and its value scrambled, Laine and Karras 2011 and Burley 2020; the review has the two side by side. What the pages here pursue is the stream in index order, thresholded, and what the generators do in windows that are not aligned.
In C, at 32 bits
At 32 bits the node is named by a per-level key and the output bits above it, rather than by a heap index. The keys depend only on the seed. The hash is the low-bias 32-bit hash the generator already uses, and the flip is its top bit.
/*
* A stateless blue noise generator: every threshold of its output is blue noise in time, and
* any sample can be computed directly.
* From "From Stateful to Stateless Blue Noise" by Jan Boon (Kaetemi),
* https://polyverse.dev/articles/bluenoise-generators.html
* Implementations derived from this code or from that article must keep this reference and
* this notice.
*/
#include <stdint.h>
/* lowbias32, from Chris Wellons's hash-prospector (public domain). The constants are the ones
* TheIronBorn posted in issue 19 of that repository on 2022-05-07:
* https://github.com/skeeto/hash-prospector/issues/19#issuecomment-1120105785 */
static inline uint32_t lowbias32(uint32_t x) {
x ^= x >> 16; x *= 0x21f0aaadu;
x ^= x >> 15; x *= 0x735a2d97u;
x ^= x >> 15; return x;
}
typedef struct { uint32_t key[32]; } blue32; /* per-level keys, fixed for a seed */
void blue32_init(blue32 *g, uint32_t seed) {
for (uint32_t l = 0; l < 32; l++) g->key[l] = lowbias32(seed + (l + 1) * 0x9e3779b9u);
}
uint32_t blue32_at(const blue32 *g, uint32_t t) { /* sample t, directly */
uint32_t acc = 0; /* the output bits decided so far */
for (int l = 0; l < 32; l++) {
uint32_t pair = (l < 31) ? t >> (l + 1) : 0; /* which pair of visits */
uint32_t flip = lowbias32(lowbias32(g->key[l] ^ acc) ^ pair) >> 31;
acc = (acc << 1) | (flip ^ ((t >> l) & 1));
}
return acc;
}The sequence is 232 samples long. For a longer one, make t and pair 64-bit and fold the upper half of pair into the hash. This code and the page's own version give the same values.
03An Offset per Node
One thing in that formula was a choice, and it was made without noticing. A node has to pair up its visits, and that much cannot be avoided without memory: two samples can only balance each other if both can find the same hashed bit, so they must agree on which pair they are in. But which two visits make a pair is free. A node can pair visits 2m and 2m + 1, or 2m + 1 and 2m + 2. Taking the phase from bit l of t gives every node the first choice, and that lines every node's pairs up with the sample index: the exact blocks above, and a grid that a sliding window moves in and out of. Let each node take one or the other by a hash of the node, and the generator is as stateless as before. A node's visit number still follows from the index, because it is its parent's pair number.
u = visit + offset(node); bit = hash(node, u >> 1) ^ (u & 1); visit = u >> 1visit starts as t; offset(node) is one hashed bit; with every offset 0 this is the formula aboveBlocks and binsDetails
The common-grid form deals: every aligned block holds each bin once, and so does the form without the loop of the next section. The offset form does not deal at any block size, and it is not meant to; a block that happens to hold each bin once (a few percent of blocks of 16) is chance. What it has instead is below.
The spectrum does not change at all (+5.98 dB per octave at threshold ½ either way). What changes is where the evenness is: no block is guaranteed exact any more, and over seeds no window is worse than another. It behaves in a sliding window as the five-state tree does, and section 05 has the numbers. Only the root keeps a rhythm, because it is a single node and its two possible pairings are the even and the odd samples; the shipped generator's root has the same.
The same at 32 bits, with the node's offset taken from the top bit of the node's own hash. It shares the first listing's hash, keys and blue32_init; they are repeated so that this block stands alone.
/*
* A stateless blue noise generator with no common grid: every node of the tree pairs its visits at its own offset, so no
* window of the stream is special. Any sample can still be computed directly.
* From "Stateless Blue Noise Generators" by Jan Boon (Kaetemi),
* https://polyverse.dev/articles/bluenoise-stateless.html
* Implementations derived from this code or from that article must keep this reference and
* this notice.
*/
#include <stdint.h>
/* lowbias32, from Chris Wellons's hash-prospector (public domain). The constants are the ones
* TheIronBorn posted in issue 19 of that repository on 2022-05-07:
* https://github.com/skeeto/hash-prospector/issues/19#issuecomment-1120105785 */
static inline uint32_t lowbias32(uint32_t x) {
x ^= x >> 16; x *= 0x21f0aaadu;
x ^= x >> 15; x *= 0x735a2d97u;
x ^= x >> 15; return x;
}
typedef struct { uint32_t key[32]; } blue32; /* per-level keys, fixed for a seed */
void blue32_init(blue32 *g, uint32_t seed) {
for (uint32_t l = 0; l < 32; l++) g->key[l] = lowbias32(seed + (l + 1) * 0x9e3779b9u);
}
uint32_t blue32_continuous_at(const blue32 *g, uint32_t t) { /* sample t, directly */
uint32_t acc = 0; /* the output bits decided so far */
uint64_t visit = t; /* which visit to the current node this is */
for (int l = 0; l < 32; l++) {
uint32_t h = lowbias32(g->key[l] ^ acc); /* the node */
uint64_t u = visit + (h >> 31); /* the node's own pairing offset, 0 or 1 */
uint32_t pair = (uint32_t)(u >> 1); /* which pair of visits, for this node */
uint32_t flip = lowbias32(h ^ pair) >> 31;
acc = (acc << 1) | (flip ^ (uint32_t)(u & 1));
visit = pair; /* a pair sends one visit to each child */
}
return acc;
}04Without the Loop
The loop of the common-grid listing draws two hashes per level and keeps one bit of each. The question was whether it could go. The whole common-grid form can be written as two hashes and three bit reversals, Laine and Karras's shuffle followed by Owen's scramble, provided the hash is nested: bit l of its result depends only on bits 0 to l of its input. Applied to the reversed index, such a hash flips every index bit by the bits above it, which is the flip for every pair at once; the shuffled index read back is the radical inverse; applied to the reversed value, the same hash flips every value bit by the bits above it, which is the flip for every node at once. The multiply-and-xor chain that Laine and Karras built for this is nested by construction, and Burley uses it for both steps. What the previous article measured against it was the fairness of its pairs, and that turns out to be the constants, not the construction. With the constants of PBRT's FastOwenScrambler, which add the seed and an odd multiply between the rounds, the loop-free form measures the same as the loop over eight seeds on everything the stream shows: next bit equal 0.250 against 0.249 to 0.250, slope at ½ +5.97 to +6.02 against +5.96 to +6.00 dB per octave, low frequencies −28 dB for both, every aligned block exact for both, and at ¼ and 0.3 the same within 0.04 dB.
/*
* The common-grid stateless blue noise generator without the loop: a nested hash shuffles the
* index, a bit reversal reads it as the radical inverse, a nested hash scrambles the value.
* Every threshold of its output is blue noise in time, and it measures the same as blue32_at.
* From "Stateless Blue Noise Generators" by Jan Boon (Kaetemi),
* https://polyverse.dev/articles/bluenoise-stateless.html
* Implementations derived from this code or from that article must keep this reference and
* this notice.
*/
#include <stdint.h>
/* lowbias32, from Chris Wellons's hash-prospector (public domain). The constants are the ones
* TheIronBorn posted in issue 19 of that repository on 2022-05-07:
* https://github.com/skeeto/hash-prospector/issues/19#issuecomment-1120105785 */
static inline uint32_t lowbias32(uint32_t x) {
x ^= x >> 16; x *= 0x21f0aaadu;
x ^= x >> 15; x *= 0x735a2d97u;
x ^= x >> 15; return x;
}
static inline uint32_t reverse32(uint32_t x) {
x = ((x >> 1) & 0x55555555u) | ((x & 0x55555555u) << 1);
x = ((x >> 2) & 0x33333333u) | ((x & 0x33333333u) << 2);
x = ((x >> 4) & 0x0f0f0f0fu) | ((x & 0x0f0f0f0fu) << 4);
x = ((x >> 8) & 0x00ff00ffu) | ((x & 0x00ff00ffu) << 8);
return (x >> 16) | (x << 16);
}
/* Nested: bit l of the result depends only on bits 0 to l of x, so after a reversal every bit is
* flipped by the bits above it. The constants are PBRT's FastOwenScrambler. */
static inline uint32_t nested32(uint32_t x, uint32_t seed) {
x ^= x * 0x3d20adeau;
x += seed;
x *= (seed >> 16) | 1u;
x ^= x * 0x05526c56u;
x ^= x * 0x53a22864u;
return x;
}
typedef struct { uint32_t shuffle, scramble; } blue32_flat; /* two seeds, fixed for a seed */
void blue32_flat_init(blue32_flat *g, uint32_t seed) {
g->shuffle = lowbias32(seed ^ 0x206e614au);
g->scramble = lowbias32(seed ^ 0x6e6f6f42u);
}
uint32_t blue32_flat_at(const blue32_flat *g, uint32_t t) { /* sample t, directly */
uint32_t r = nested32(reverse32(t), g->shuffle); /* every pair's flip: the shuffled index, reversed */
return reverse32(nested32(reverse32(r), g->scramble)); /* every node's flip: the scrambled value */
}
Eight multiplies and no loop, against sixty-four hashes, and the same figures as the loop on every measure above. The window lab below is where the two part. Slid along the stream, the loop-free form's share of exact bins does not only fall to about half between blocks, it can fall to nothing: halfway between two blocks, when the two halves in the window are the same set of bins, half the bins are held twice and the other half are empty. Over all positions its share runs from 0 to 100%, where the loop's never falls below about 30%, at every window length. The reason is in how the two forms decide a flip. Here the flip of a bit is a pair part, from the shuffle, which depends on the pair number and is shared by every node of the level, XOR a node part, from the scramble, which depends on the node and is the same in every block. In the loop the flip is one hash of the node and the pair together. So from one block to the next, the loop-free form changes every node's flip at a level by the same amount, and each half of a block is either the same set of bins as its neighbour's half or the complement of it: over eight seeds, the halves of adjacent blocks of 16 are the same set 46 to 54% of the time, against under 1% for the loop, which draws every node's flip afresh in every block. The pairs are fair, the spectra are the same, the blocks are exact, and the deals are tied to each other.
That is the answer to the question. The loop can go and keep every property of the stream in index order; it cannot go and keep the deals independent, because independence between deals needs the flip to be a joint function of node and pair, and a nested hash gives the pair its say only through bits the whole level shares. It cannot do the offset per node of the previous section either: there each node adds its own bit to its visit number before pairing, the carries of that addition cross the levels, and the bit is chosen by the node, which is the output prefix.
05Deals and Windows
The forms divide in two, and the division matters more than the count of states or of hashes. The pair forms deal. Every run of 2k samples that starts on a multiple of 2k is a complete deal, each bin served once; then the deck is shuffled and dealt again. A window that lies across two deals sees the end of one shuffle and the start of another. The machines with memory do not deal. Each decision is made against a running balance that is never reset, so there is no place where the memory ends, and every window, wherever it starts, is out of balance by the same small bounded amount.
Slide a window along the streamDetails
| Form | Window on a block | Half a block later | Over all positions |
|---|
The dealt forms climb to 100% at every multiple of the window length and fall to between 40 and 50% halfway to the next, the form without the loop at times to nothing (section 04). The shipped tree and the stateless form with an offset per node hold level at about 65%, with nothing to mark where a block would be. The five-state tree with an aligned start is in the lab to show that the dealing comes from the alignment, not from the node: the same machine, started on the grid, deals. Both kinds are much more even than white noise, and on average equally so. They differ in where the evenness is. A renderer takes whole deals, and wants them exact. A token sampler, a dither on a live signal, anything without a natural block length, has no deals to take, and wants the window that slides. The generator was designed for the second, which is why it began as error diffusion, and the literature the stateless form turned out to belong to (reviewed here) is about the first. The common-grid form shares mechanisms with that literature. The finite sliding-window behaviour is a separate comparison, developed in the research notes below. The five-state tree meets it, with 2 to 3 dB less low frequency energy for its memory. So does the stateless form once each node pairs its visits at its own offset (section 03): the grid was never needed for statelessness, only for exact blocks.
06As Sample Positions
A generator whose every aligned block is a complete deal is a low-discrepancy sequence, and its values can be used as sample positions. The question is what the deals are worth when the window that consumes them starts anywhere.
Use the values as sample positionsDetails
Measured on 16-bit trees with aligned starts, 222 samples each:
| Seven-state | Five-state | Pair, one bit | Pair, no state | White | |
|---|---|---|---|---|---|
| Slope at threshold 1⁄2 · 1⁄4 · 1⁄8, dB per octave | 6.20 · 6.47 · 6.10 | 6.19 · 6.46 · 6.04 | 6.00 · 5.86 · 5.37 | 5.99 · 5.86 · 5.37 | 0.00 |
| Low frequencies against the mean, dB | −30.9 · −26.0 · −20.5 | −30.3 · −24.7 · −18.9 | −28.0 · −22.7 · −17.2 | −28.0 · −22.8 · −17.3 | 0.0 |
- As blue noise the error diffusion machines lead: 2 to 3 dB less low frequency energy, and a slope that holds at ¼ and ⅛. At thresholds that are not a power of one half all forms are alike, at about +2.8 dB per octave, and the pair forms swing least from one threshold to the next.
- As sample positions every form converges as 1⁄N where white noise converges as 1⁄√N, one to three orders of magnitude ahead of it, and with windows that start anywhere the forms cannot be told apart. Started on a block, the dealt forms pull away at every power of two, where they have whole deals: at 1,024 samples the pair on the common grid integrates x² ten to thirty times more accurately than the shipped tree. Between the powers of two they are back with the rest.
- The continuous forms have no common grid, but they are not without rhythm. The top of the tree is a few nodes, each with a pairing phase of its own, so every seed has index phases it favours: for one seed of the shipped tree, windows of 64 that start at t ≡ 0 (mod 8) integrate x² to 2.8 × 10−3 and windows at odd t to 6 or 7 × 10−3; for another seed the favoured start is t ≡ 3. The stateless form with an offset per node does the same. Over seeds, as in the lab, no start is special.
- The seven-state machine is the most regular and the pair the most random: entropy rates of 0.32, 0.46 and 0.50 bits per output bit for seven, five and pair.
07Which Bits, and the Spectrum
One more thing about the listings. The flip is the top bit of the hash, on purpose. The low bits of a hash are its weakest, and here a weak bit shows as spikes in the low band of the spectrum, where a blue noise spectrum has the least energy to hide them in. How much depends on the hash.
| Stateless pair, threshold ½, eight seeds | Flip from the top bit | Flip from the bottom bit |
|---|---|---|
| lowbias32, as in the listing | 0.77 dB · +5.98 to +6.01 | 0.85 dB · +5.97 to +6.02 |
| Wang hash | 1.01 dB · +5.94 to +6.00 | 1.96 dB · +5.81 to +5.87 |
| A bare multiply | 5.2 dB · +6.0 to +7.1 | periodic, not noise |
The first figure is how far the low band of the measured spectrum, below 1⁄256 cycle per sample, strays from its own running median; a smooth spectrum measured this way leaves 0.77 dB. The second is the slope in dB per octave. With lowbias32 either end is at that floor, the top a hair closer. With a weaker hash the bottom bit is plainly spikier and the slope sags; with no mixing at all the bottom bit of the hash is the bottom bit of the index. The five-state tree takes a bit per level from one hash, sixteen of them, so it has no good end to choose with a weak hash (1.6 dB from either end with the Wang hash) and depends on the hash being a good one: the C reference takes routing bit l from bit l, the llama.cpp patch from the top, and with lowbias32 both measure at the floor.
The spectra themselves, for the stateless forms and the shipped machine. At threshold ½ only the root decides: the stateless forms sit on the pair's curve, and the machine with memory a little under it at low frequencies. Away from ½ the machine holds its slope, where the pairs' sags.
Measured spectraDetails
| Form | Slope | Low frequencies |
|---|
That difference is what the machine's memory across pairs buys: the pair forgets everything at each pair boundary, the machine carries an error across it.
The first four thresholds of the lab are powers of one half, and that matters. At ½ only the root decides, at ¼ the root and one child. A threshold such as 0.3 has no finite binary expansion, so the comparison reaches every level of the tree, and a node at level l is visited once in 2l samples: its pairs act on a time scale 2l times longer. The sum of those is still blue, but it rises at about +3 dB per octave, not +6. This is true of every form here, the shipped generator included.
Swept over every threshold k⁄1024, the slope depends on how many levels of the tree the threshold involves, and hardly at all on the form. Averaged over the thresholds of each kind, from 0 to 1, for the shipped five-state generator: +6.2, +6.5 and +6.0 dB per octave with one, two and three levels, +4.6 with four, +3.5 with five, +3.0 with six, and about +2.8 from there on. The peaks stand alone: the thresholds right beside ½ involve ten levels, and have the lowest slopes in the middle of the range.
The pair forms trace the same comb with less swing. Over thresholds from 0.1 to 0.9 every form averages +3.0 dB per octave; the spread around that average is 0.60 for the five-state machine and 0.48 for the pair. The pair's peaks are lower (+6.0 at most, against +6.5) and its dip beside ½ is shallower (+2.9 against +2.5, and +2.2 for the seven-state machine). Between 0.1 and 0.9, at thresholds that involve seven levels or more, which is nearly all of them, the forms cannot be told apart: +2.9 to +3.0 dB per octave, and low frequencies 13 to 14 dB under the mean.
08The Family
The forms of both articles in one table. The stateless forms differ from the machines in what they store and in whether a sample can be computed on its own; among themselves they differ only in the hashes per sample and in whether the evenness sits on a grid.
| Form | Per node | 16-bit tree | Hashes per sample | Memory across pairs | Random access |
|---|---|---|---|---|---|
| Seven-state (fractional pair, exact) | 7 states | 131 KB as two slots, 25 KB packed | 1 | yes | no |
| Five-state (binary routing, shipped) | 5 states | 131 KB as two slots, 25 KB packed | 1 | yes | no |
| Random pair | 1 bit | 8 KB | 1 | no | no |
| Random pair, hashed, common grid | nothing | nothing | two per bit | no | yes |
| The same, without the loop | nothing | nothing | two for all bits | no | yes |
| Random pair, hashed, offset per node | nothing | nothing | two per bit | no | yes |
09Open Questions
- The rhythm at the top of the tree. A single root can only pair its visits on the even samples or on the odd ones, and the two nodes below it have two choices each, so every seed of a continuous form has a few favoured index phases (section 06). Deeper in the tree there are enough nodes for the phases to average out. Whether the top levels can be given a pairing that moves, without state and without breaking the pairs, is open.
- The offset form in use. The shipped five-state tree runs in a production llama.cpp build. In a sliding window the stateless form with an offset per node measures the same as that tree, and it stores nothing, but it has not been run as a token sampler.
- More dimensions. Owen scrambling is normally applied to Sobol points in several dimensions. Whether redrawing the scrambling per pair does anything useful there is not something this article has looked at. A quadtree over pixels, and a construction over pixels and frames, are in Stateless Blue Noise in Space and Time.
- What the offset form is, and prior work. The pair rule, hierarchical scrambling and random-access index shuffling have established precedents. The per-node offsets need a more specific mapping comparison, with the common-grid counting guarantee and phase-dependent window errors kept separate. The comparison notes below collect the relevant sources and outstanding tests.
10What Is New Here, and What Is Not
Part by part, against the sources in the reading list. Six labels are used. Existing: existing art, whether used knowingly or arrived at independently and then matched to a source. Variant: an existing construction with one stated change. Combination: existing parts put together in a way not found in the sources reviewed. New: no counterpart found in the sources reviewed. Result: a measurement or derivation about the objects on this page; a fact about them, not a technique. Implementation: code for a construction on this page; only its correctness is claimed. "Not found" means not found in the sources listed below, of which some are read in full and some are not; the reading list says which.
| Part | Status | Basis |
|---|---|---|
| The stateless form on the common grid (section 02) | Existing, up to the hash | The radical inverse with its index bits flipped by a hash of the bits above them: Laine and Karras 2011, named a nested uniform shuffle by Burley 2020. Checked by running Burley's listings in index order: random 01/10 pairs, exact aligned blocks, a blue slope at ½. The difference is where the randomness comes from: one hash of the node and the pair here, a flip per pair shared by a level combined with a fixed flip per node there; it shows twice. The fairer pairs (next bit equal 0.25, against 0.13 to 0.35 over twelve seeds of the Laine–Karras shuffle) are a difference of hash: with PBRT's constants the composed construction draws fair pairs too (section 04). The deals are a difference of construction: the composed flip ties adjacent deals together, which a sliding window shows. What is not in that literature is the reading: the sequence run in index order, thresholded, as a random stream, and the spectra that reading has. |
| The form without the loop (section 04) | Existing; the comparison is a Result | Laine and Karras's shuffle followed by Owen's scramble, as Burley composes them, with PBRT's FastOwenScrambler constants. Measured here: the same as the common-grid form on every stream-wide measure (pairs, spectra, aligned blocks), the earlier difference in pair fairness being the Laine and Karras constants; different in sliding windows, because its flips are a pair part XOR a node part where the loop's are one joint draw, so adjacent deals are tied. The joint flip has no loop-free form in this family. |
| An offset per node (section 03) | Variant | Of the shuffled radical inverse: each node adds one hashed bit to its visit number before pairing and passes the quotient to its child. Not found in the sources reviewed; the full mappings of ART-Owen, Q-ART and NILE remain to be compared. It gives up every aligned stratum for a stream with no special windows. |
| The flip from the top bit of the hash (section 07) | Existing | The mixer is lowbias32 from hash-prospector, with TheIronBorn's constants. That a hash's low bits are its weakest is common knowledge; the table showing what it costs in the low band of these spectra is a Result. |
| Dealt against continuous, and the sliding window (section 05) | Result; the criterion is Existing | Evenness in a window that starts anywhere is, in the limit, the classical property of a well-distributed sequence (Petersen 1956; Kuipers and Niederreiter 1974). Measuring it at a fixed short length, and finding that the forms with memory and the offset form hold level where the dealt forms pulse, is a Result. No randomized construction aimed at that property was found. |
| Error of the mean, 1⁄N (section 06) | Result | That scrambled nets integrate smooth functions better than random points is Owen 1997. The comparison of the four forms, on and off the block grid, is a measurement. |
| Favoured index phases of the continuous forms (sections 06, 09) | Result | A few nodes at the top of the tree each have a pairing phase, so each seed favours a few starts. Found while building the integration lab. |
| The C listings (sections 02 to 04) | Implementation | Of the stateless forms, with per-level keys so that a node is named without a heap index. The mixer is an existing helper. |
11Related Work and Comparisons to Make
| Method | Connection | Next comparison |
|---|---|---|
| Shuffled, scrambled radical inverse | Index shuffling and value scrambling already provide random-access sequences with exact aligned strata. | Compare the complete mapping and dependence between flips, not only the root's 01/10 pairs. |
| ART-Owen; Q-ART | Grammar-based scrambling offers control over permutations, access and inversion. | Test as alternative scrambling implementations. Their tree structure alone does not establish equivalence to the per-node visit offsets. |
| NILE | Local sampling elements coordinated across a sequence; consistency of sample-space spectra across blocks. | Separate the spectrum of sample positions within a block from the spectrum of a thresholded scalar stream in index order. |
Which bits determine the flip?
Keep three baselines separate: a fixed Owen scramble of the radical inverse, a nested shuffle of its indices, and the combination of both. Burley's §§3–4 distinguish these operations explicitly. The existing Owen review and stream lab are the starting point for reproducing the comparison at equal precision.
The common-grid rule here keys a flip on both the output prefix and the current pair number. In the shuffle-then-scramble construction, dependencies arise through two composed permutations. Matching the balanced pairs and aligned counts establishes shared properties; it does not by itself establish identical mappings or identical distributions over mappings.
A useful check is to enumerate small bit depths and compare the realizable permutations and correlations between nodes and successive pairs. Keep ideal independent flip tables separate from the practical hash implementations. A difference between two short hash mixers is not automatically a difference between the underlying constructions; section 04 measures exactly that: the Laine and Karras constants against PBRT's in the same construction, where the difference in pair fairness is the constants, and the composed flip against the joint flip, where the difference in sliding windows is the construction.
Offsets change the visit coordinates
The offset form changes the node's visit coordinate before halving it, then passes that quotient to its child. It therefore needs a separate comparison from changing the hash or replacing binary flips with base-four permutations. An offset at the root alone merely translates the pairing; deeper, prefix-dependent offsets are the part to isolate.
Giving up the common aligned-block guarantee does not mean that no individual window can happen to be exact. Nor does it prove that all windows of one seeded stream are equally good: section 06 already measures preferred phases near the root. The useful distinction is between exact counts guaranteed on a common grid and the distribution of errors over starts and seeds.
No equivalent per-node visit-offset recursion has been found in the sources below. That is a comparison still to make, rather than a conclusion that the method lies outside the sampling literature. ART-Owen's invertibility and NILE's interval hierarchy are reasons to inspect their full mappings carefully.
A comparison plan for the next pass
- Separate the signals. Measure the scalar stream, fixed-threshold bit streams, and sample-position distributions separately. For the ideal pair, the stated autocorrelation averages the two index phases; a fixed-phase pair stream has alternating neighbour correlations. Check phase-conditioned statistics alongside the average spectrum.
- Separate alignment from the node. Compare common-grid pairs, root translation only, full per-node offsets, and both starts of the stateful machines. Sweep window starts and lengths, including non-powers of two. Report means, variation and worst observed windows across independent seeds.
- Keep the controls appropriate to one dimension. At threshold ½ only the root contributes; deeper offsets cannot change that slice. Include ¼, ⅛, 3/8 and 0.3 to involve descendants. Keep aligned-bin counts and spectral measurements separate.
- Test the consumer. Fixed thresholds do not describe a token sampler whose cumulative probabilities change after every token. Compare moving thresholds, changing categorical distributions and stride-dependent consumption before transferring the fixed-distribution results to that setting.
- Measure costs consistently. Distinguish evolving node state from immutable keys and temporary registers. The C listings retain 32 keys and use finite-width indices; “stateless” means no sample-to-sample update, not unlimited period or literally no storage. Benchmark the actual listings at equal output precision.
The existing measurements remain useful evidence for these particular implementations. General guarantees about arbitrary thresholds, all window positions or other sampling dimensions need their own bounds or experiments.
Implementations derived from this article, in any language, must keep a reference to it: the address https://polyverse.dev/articles/bluenoise-stateless.html, credit to Jan Boon (Kaetemi), and this requirement itself, so that the reference is carried into whatever is derived from them in turn.
12Reading List
The forms here are relatives of the shuffled and scrambled radical inverse; the sliding window criterion has a classical asymptotic name; the sample-position use puts them beside the low-discrepancy literature.
The sequence and its scrambling
- J. G. van der Corput, "Verteilungsfunktionen (Erste Mitteilung)," Proceedings of the Koninklijke Akademie van Wetenschappen te Amsterdam 38, 1935, 813–821. Volume PDF. The sequence.
- A. B. Owen, "Randomly Permuted (t,m,s)-Nets and (t,s)-Sequences," in Monte Carlo and Quasi-Monte Carlo Methods in Scientific Computing, Lecture Notes in Statistics 106, Springer, 1995, 299–317. Nested uniform scrambling: the tree of flips.
- A. B. Owen, "Scrambled Net Variance for Integrals of Smooth Functions," Annals of Statistics 25(4), 1997, 1541–1562. Why scrambled nets beat both plain nets and random sampling on smooth integrands; relevant to the x² row of the comparison.
- A. B. Owen, "Monte Carlo Variance of Scrambled Net Quadrature," SIAM Journal on Numerical Analysis 34(5), 1997, 1884–1910.
- M. Pharr, W. Jakob, G. Humphreys, Physically Based Rendering, 4th edition, section 8.6 (radical inverse, van der Corput, Owen scrambling) and section 8.7 (hash-based scramblers). The most readable introduction; start here for the stateless form.
- S. Laine, T. Karras, "Stratified Sampling for Stochastic Transparency," Computer Graphics Forum 30(4), 2011. The hash in which each bit is changed only by the bits on one side of it, used there to shuffle the order of the samples: the per-pair redraw of section 02, in 2011.
- B. Burley, "Practical Hash-based Owen Scrambling," Journal of Computer Graphics Techniques 9(4), 2020. Owen scrambling computed with a hash instead of a stored tree, and the distinction between scrambling the values and shuffling the index. Sections 3–4 distinguish value scrambling from index shuffling; the latter is essential to the stream comparison in section 02.
- T. Kollig, A. Keller, "Efficient Multidimensional Sampling," Computer Graphics Forum 21(3), 2002, 557–563. Random digit scrambling, the cheaper relative of Owen's.
- P. Christensen, A. Kensler, C. Kilpatrick, "Progressive Multi-Jittered Sample Sequences," Computer Graphics Forum 37(4), 2018, 21–33. Progressive stratification with a random choice inside each stratum.
- A. Helmer, P. Christensen, A. Kensler, "Stochastic Generation of (t,s) Sample Sequences," EGSR 2021. Owen-scrambled sequences generated as "the next sample goes in the opposite stratum", which is the pair rule; the scrambling is fixed per node.
The requirement, and its nearest classical name
- G. M. Petersen, "Almost Convergence and Uniformly Distributed Sequences," Quarterly Journal of Mathematics 7, 1956, 188–191; L. Kuipers, H. Niederreiter, Uniform Distribution of Sequences, Wiley, 1974. A sequence is well-distributed when the share of xn … xn+N−1 that falls in an interval tends to the interval's length uniformly in the starting index n: evenness in a window that slides. It is a statement about the limit, and classical sequences such as van der Corput's satisfy it; the distinction of section 05 is about windows of a fixed short length, where a sequence dealt in blocks and one that keeps a running balance behave differently. No randomized construction offered for this property was found.
- J. X. Wei (ATI), US patent 7,580,157, "High-pass dither generator and method," 2009. The closest stated goal found outside the author's own work: multi-bit dither with a uniform distribution and a high-pass spectrum, made by filtering the words of a shift register. No tree, and no evenness at every threshold.
Blue noise and low discrepancy together
- R. A. Ulichney, "Dithering with Blue Noise," Proceedings of the IEEE 76(1), 1988, 56–79.
- A. G. M. Ahmed, H. Perrier, D. Coeurjolly, V. Ostromoukhov, J. Guo, D.-M. Yan, H. Huang, O. Deussen, "Low-Discrepancy Blue Noise Sampling," ACM Transactions on Graphics 35(6), 2016.
- H. Perrier, D. Coeurjolly, F. Xie, M. Pharr, P. Hanrahan, V. Ostromoukhov, "Sequences with Low-Discrepancy Blue-Noise 2-D Projections," Computer Graphics Forum 37(2), 2018, 339–353.
- E. Heitz, L. Belcour, V. Ostromoukhov, D. Coeurjolly, J.-C. Iehl, "A Low-Discrepancy Sampler that Distributes Monte Carlo Errors as a Blue Noise in Screen Space," ACM SIGGRAPH 2019 Talks.
- A. G. M. Ahmed, P. Wonka, "Screen-Space Blue-Noise Diffusion of Monte Carlo Sampling Error via Hierarchical Ordering of Pixels," ACM Transactions on Graphics 39(6), 2020. Stratified blocks of one sequence laid along an Owen-scrambled pixel order, so that the blocks' evenness becomes blue noise in space. The nearest relative in two dimensions.
- A. Wolfe, N. Morrical, T. Akenine-Möller, R. Ramamoorthi, "Spatiotemporal Blue Noise Masks," EGSR 2022, arXiv:2112.09629. Blue noise along the time axis, from optimised masks rather than a generator.
Spectra and integration error
- K. Subr, J. Kautz, "Fourier Analysis of Stochastic Sampling Strategies for Assessing Bias and Variance in Integration," ACM Transactions on Graphics 32(4), 2013.
- A. Pilleboue, G. Singh, D. Coeurjolly, M. Kazhdan, V. Ostromoukhov, "Variance Analysis for Monte Carlo Integration," ACM Transactions on Graphics 34(4), 2015. How the low frequency shape of a sampler's spectrum sets its convergence rate. Their spectra are over sample positions, not over time; the connection to the time spectra measured here still has to be worked out.
- G. Singh, C. Öztireli, A. G. M. Ahmed, D. Coeurjolly, K. Subr, O. Deussen, V. Ostromoukhov, R. Ramamoorthi, W. Jarosz, "Analysis of Sample Correlations for Monte Carlo Rendering," Computer Graphics Forum 38(2), 2019, 473–491. A survey of the above.
Where this came from
- Jan Boon (Kaetemi), "Stochastic Kernel-Switching Error Diffusion," blog.kaetemi.be, 2026.
- Jan Boon (Kaetemi), "Blue Noise Token Sampling," polyverse.dev, 2026.
- Jan Boon (Kaetemi), "From Stateful to Stateless Blue Noise," polyverse.dev, 2026. The machines, the pair, and the common-grid form this article starts from.
- Jan Boon (Kaetemi), "Hash-Based Owen Scrambling, in Pictures," polyverse.dev, 2026. A review of the literature the common-grid form belongs to, with the stream lab where its dealing is visible.
Further comparisons: controlled scrambling and sample blocks
- A. G. M. Ahmed, M. Pharr, P. Wonka, "ART-Owen Scrambling," ACM Transactions on Graphics 42(6), 2023, doi:10.1145/3618307. Grammar-based scrambling and inversion; §§4 and 6.2 are relevant to the tree comparison. These sections were reviewed; equivalence to the visit-offset construction has not been established.
- A. G. M. Ahmed, "Q-ART Owen Scrambling," EG UK Computer Graphics & Visual Computing, 2025, doi:10.2312/cgvc.20251215. Extends ART to all 24 base-four permutations through affine digit transformations. The two-page conference paper was read in full; the expanded 2026 journal version remains to be reviewed. Relevant to larger-radix experiments, not evidence of a one-dimensional temporal spectrum.
- A. G. M. Ahmed, M. Pharr, V. Ostromoukhov, H. Huang, "NILE: Nested Interleaving of Low-Dimensional Elements," ACM Transactions on Graphics, July 2026, doi:10.1145/3811283 (paper). Read in full. See §5.4 and Figure 10 for successive sample blocks, and §5.6 for implementation costs. A scalar-stream comparison remains to be constructed.
- Christopher Wellons, hash-prospector (public domain): the two-round XOR/multiply mixer named lowbias32 in its README. The constants in the listings are the ones TheIronBorn posted in issue 19 on 2022-05-07 (bias 0.107 by the project's measure, against 0.174 for the README's); Boost's hash_mix_impl<32> (1.85.0) uses the same. An existing helper. Its suitability for these threshold spectra is a separate implementation measurement.