DEFINITION
tₙ = 0.4 − 6/(1 + xₙ² + yₙ²) xₙ₊₁ = 1 + u(xₙ·cos tₙ − yₙ·sin tₙ) yₙ₊₁ = u(xₙ·sin tₙ + yₙ·cos tₙ)
NOTES
Derived from light circulating in a ring cavity filled with a nonlinear medium — the rotation angle depends on the intensity, so bright parts of the beam twist further than dim ones. The attractor is a spiral shell that keeps folding back into itself. Chaotic above u ≈ 0.6, and only transiently past u ≈ 0.9 — there the orbit wanders the shell for a while, then falls onto a stable fixed point far outside it.
PROVENANCE
- Origin
- K. Ikeda, Optics Communications 30, 1979
- Standing
- Public domain — a physical model published openly
- Constants
- u = 0.9 is the classic choice; the attractor dies in a crisis near u ≈ 0.902, so the slider stops at 0.9
- Source
- doi:10.1016/0030-4018(79)90090-7
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. 12 · IKEDA MAP — Kensuke Ikeda, 1979
// tₙ = 0.4 − 6/(1 + xₙ² + yₙ²)
// xₙ₊₁ = 1 + u(xₙ·cos tₙ − yₙ·sin tₙ)
// yₙ₊₁ = u(xₙ·sin tₙ + yₙ·cos tₙ)
// 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=ikeda
float p_u = 0.9 + chf('u_tweak'); // u — dissipation · live 0.6 .. 0.9
// The plate's own colour: FORMA's ATTRACTORS 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.0956 + 0.1039 * cos(6.28318530718 * (t + 0)),
0.4041 + 0.4392 * cos(6.28318530718 * (t + 0.05)),
0.46 + 0.5 * cos(6.28318530718 * (t + 0.1)));
}
// The exposure replayed as a point cloud: iterate from (0.1, 0.1) and discard
// the first 20 landings, as the plate's expose() does.
int forma_pts = 120000;
int forma_skip = 20;
float x = 0.1, y = 0.1;
for (int i = 0; i < forma_pts + forma_skip; i++){
float tn = 0.4 - 6.0 / (1.0 + x * x + y * y);
float nx = 1.0 + p_u * (x * cos(tn) - y * sin(tn));
float ny = p_u * (x * sin(tn) + y * cos(tn));
x = nx; y = ny;
if (i < forma_skip) continue;
// canvas y runs down; negated so the figure sits as the plate shows it
int pt = addpoint(0, set(x, -y, 0.0));
float u = float(i) / float(forma_pts + forma_skip);
setpointattrib(0, "Cd", pt, forma_ramp(0.8 + 0.3 * u));
}