CotM
← archive

What an affine IFS actually is

Experimentspost2026-07-09

A handful of maps that shrink the plane, a theorem that says they have exactly one fixed shape, and a second theorem that tells you how to find the maps for a shape you already want.

An iterated function system is a small pile of functions that shrink things, and the surprising claim is that the pile has a shape.

Each map in the designer is affine, which is the most boring transformation that still does something interesting: a linear part and a shift.

wi(x)=Aix+bi,AiR2×2,biR2.w_i(x) = A_i x + b_i, \qquad A_i \in \mathbb{R}^{2\times 2}, \quad b_i \in \mathbb{R}^2.

The matrix AiA_i rotates, scales, and skews; the vector bib_i slides the result somewhere. That is exactly what a control point in the designer is. When you drag a point you are moving bib_i. When you hold Ctrl and turn it you are rotating AiA_i, and Alt and Shift get you the scale and the skew. The gizmo drawn around each point is a picture of AiA_i.

The attractor of three affine maps after moving one control point

Three affine maps, one of them nudged. The maps are the object you edit; the fractal is what falls out.

The one condition that matters is that each map has to be a contraction: there is some si<1s_i < 1 with

wi(x)wi(y)sixy\lVert w_i(x) - w_i(y) \rVert \le s_i \lVert x - y \rVert

for every pair of points. Applying wiw_i moves any two points strictly closer together. Everything below depends on that and on nothing else.

The Hutchinson operator

Take a compact set SS in the plane. Apply every map to the whole of it, and union the results:

W(S)=i=1Nwi(S).W(S) = \bigcup_{i=1}^{N} w_i(S).

That is the Hutchinson operator, and it eats a shape and produces a shape. It is the entire content of an IFS. Everything the designer does is either computing WW or arranging for something else to compute it for you.

Here is the good part. WW is itself a contraction, not on points but on sets, once you measure the distance between two compact sets with the Hausdorff metric. Its contractivity is s=maxisis = \max_i s_i, still less than one. Banach’s fixed point theorem then does what it always does: there is exactly one compact set AA with

W(A)=A,W(A) = A,

and starting from any nonempty compact S0S_0 and iterating Sn+1=W(Sn)S_{n+1} = W(S_n), the sequence converges to AA. Not usually. Always. It does not matter whether you start with a square, a circle, or a single dot.

That set AA is the attractor, and it is the thing every renderer on the site is trying to draw. It is defined by the maps and by nothing else — not by the starting shape, not by the algorithm, not by the resolution of your screen. Which is precisely why five different renderers have to agree, and why it means something when they don’t.

Why the picture has holes in it

The attractor is a fixed point of a set-valued map, and there is no reason for it to be a nice region. Usually it isn’t. If the maps shrink hard enough that their images don’t overlap much, AA ends up with empty space at every scale, and its area is zero.

That last part is not a technicality. It is the central practical fact about rendering an IFS, and I spent a while relearning it the hard way. The attractor typically has measure zero: it covers no area at all. Whatever you draw on a pixel grid is not the attractor, it is a picture of a neighbourhood of the attractor, and every algorithm has to decide what to do with a branch of the set that has become thinner than one pixel. The choices are to round it up to a full pixel, round it down to nothing, or carry a fraction. Two of the three are wrong in ways that take a while to notice.

The collage theorem

The other half of Barnsley’s idea runs backwards, and it is the reason the designer is a designer and not a viewer. Suppose you have a target shape TT — a fern, a coastline, your own handwriting — and you want maps whose attractor looks like it. You don’t have to solve for them. You just have to cover TT with small distorted copies of itself, and then read the maps off the copies.

Formally, if you can find maps such that W(T)W(T) is close to TT, then the attractor is close to TT too:

d(T,A)d(T,W(T))1s.d(T, A) \le \frac{d\bigl(T, W(T)\bigr)}{1 - s}.

Make the collage error small and the attractor error is small, inflated by 1/(1s)1/(1-s). That is the whole game. You never manipulate the fractal directly. You arrange a few affine copies of a shape so they tile the shape, and the fractal follows.

Which is what you are doing when you drag the control points around: assembling a collage and watching the fixed point of your collage rearrange itself to keep up. The maps are the object. The fractal is a consequence.

Three ways of computing that consequence follow. The chaos game samples the attractor with a random walk. The collage run backwards iterates WW on the pixel grid directly. Escape time without the escape never computes WW at all and asks a different question entirely.