DEFINITION
walk the integers outward in a square spiral; mark n when n is prime
NOTES
Ulam drew this while bored in a meeting. Write the whole numbers in a spiral and mark the primes: they fall on diagonals rather than scattering. Those diagonals correspond to prime-rich quadratic polynomials, and why some quadratics are so much richer than others is still open.
PROVENANCE
- Origin
- S. Ulam, 1963; published by Gardner in Scientific American, 1964
- Standing
- Public domain — an observation about integers
- Constants
- Larger extents make the diagonal structure clearer
HOUDINI · VEX
The same published mathematics as a Detail Wrangle body. Paste it into a Wrangle with Run Over set to Detail; every constant is the published value plus a tweak channel, so Create Spare Parameters gives a slider that starts where the paper does.
// FORMA — PL. 31 · ULAM SPIRAL — Stanisław Ulam, 1963
// walk the integers outward in a square spiral;
// mark n when n is prime
// Paste into a Detail Wrangle (Run Over: Detail), no inputs needed.
// Written from the published mathematics, not adapted from any code.
// Constants arrive at their published values. Press the node's Create
// Spare Parameters button and every tweak becomes a slider — starting
// at 0, the published figure, and moving in the constant's own units.
// https://forma-gen.com/#plate=ulam
float p_extent = 161 + chf('extent_tweak'); // grid width · live 41 .. 301
// The plate's own colour: FORMA's LATTICES accent as a cosine ramp,
// brightest near t = 0 and t = 1, near-black around t = 0.5.
vector forma_ramp(float t){
return set(
0.46 + 0.5 * cos(6.28318530718 * (t + 0)),
0.4185 + 0.4549 * cos(6.28318530718 * (t + 0.05)),
0.1389 + 0.151 * cos(6.28318530718 * (t + 0.1)));
}
// Ulam's doodle, complete: sieve the integers to extent², walk them outward
// in the square spiral, and put a point wherever the number is prime. The
// plate reveals the walk over its clock and lights the newest ninety in
// HILITE — a growth cursor, not part of the finished spiral, so neither is
// ported. One point per prime, in lattice units about the centre, coloured
// by the plate's own position-in-walk mapping. Deterministic by
// construction — there is nothing random in a sieve.
int n = int(rint(p_extent));
if (n % 2 == 0) n += 1; // the spiral needs its odd centre, as the plate takes it
int lim = n * n;
// the sieve: composite[i] = 1
int comp[];
resize(comp, lim + 1);
for (int i = 2; i * i <= lim; i++)
if (!comp[i])
for (int j = i * i; j <= lim; j += i) comp[j] = 1;
int half = n / 2;
int x = half, y = half, dx = 1, dy = 0, sl = 1, done = 0;
for (int v = 1; v <= lim; v++){
if (v > 1 && !comp[v] && x >= 0 && y >= 0 && x < n && y < n){
// canvas y runs down; negated so the diagonals lean as the plate shows them
int pt = addpoint(0, set(float(x - half), float(half - y), 0.0));
setpointattrib(0, "Cd", pt, forma_ramp(float(v) / float(lim) * 0.45 + 0.12));
}
x += dx; y += dy; done++;
if (done == sl){
done = 0;
int tmp = dx; dx = -dy; dy = tmp; // the spiral's quarter turn
if (dy == 0) sl++;
}
}
AFTER EFFECTS · DECLINED
Cells, not a path: the spiral is a grid of filled squares marking the primes, and a stroke has no way to say which cells are lit.