by Simon Tatham, mathematician and programmer
Filigrams are a type of pretty pictures generated by mathematical means. They're not technically a type of fractal, although they contain elements which people who know fractals might find hauntingly familiar. They're something I invented by accident once and decided to polish up because it looked pretty.
I produced the first filigram completely by mistake. When I was 14 or so, my GCSE Computer Studies teacher showed me a short BASIC program on a BBC Micro that plotted a pleasant repeating pattern of interlocking circles:
I thought it was pretty enough that I should take the program home and run it on my Amiga, where I could give it the benefit of better graphics and see how much prettier it looked then.
So I memorised the important details of the program and went home to a real computer. Completely by accident, I got one character wrong when I typed the program back in, and it generated this instead:
Now that's much more interesting than interlocking circles, isn't it? It's got clear structure at the centre – black fades to white and jumps back to black again, repeatedly, in narrower and narrower stripes. Then, once the stripes become smaller than the distance between pixels, the delicate filigree (hence the name) degenerates into chaos. But beyond that, as if by magic, the chaos reforms into a new order, with little butterfly shapes embedded in the swirling black and white maelstrom. I stared at this feast of interlocking detail and was very glad I'd typed the circles formula in wrong. Then I set about enlarging it to poster size, so I could print it out and put it on my wall.
Unfortunately, the pattern proved to be elusive. The way it was generated provided an obvious way of magnifying it: the program was computing a function at every point of a square grid, so to enlarge it you just compute the same function at some new points in between the original points, right? Wrong – if you try that, a lot of the interesting detail in the butterfly shapes just disappears. Some of it remains, but more and more of the detail disappears the further you enlarge the image. It was like trying to nail fog to the wall – at 320 × 256 resolution, the image obediently sat there and looked pretty, but as soon as I looked any closer it vanished. Infuriating.
And there the matter rested for nearly ten years, until one day, after having done a maths degree, I remembered it and came back to see if I could finally find a way to catch that fog and nail it down.
(Warning to non-mathematicians: this section may get a little intense. But there are pretty pictures to look at, so that's all right :-)
The formula I'd completely failed to type correctly was the obvious "circular" formula: $x^2+y^2$. The program I saw computed the fractional part of this function at every point on the screen and converted it to a colour value. This produces an N-colour image of interlocking circles, and the pattern ends up repeating itself after long enough. Instead of this, though, I replaced the addition with a multiplication: $x^2\times y^2$, with its fractional part taken, generates the picture shown above.
So that explains the central section: each stripe in the centre follows a line along which $xy$ is constant. Based on this level of understanding, I was able to replace the function with the slightly more complex $(2x+y)(2x-y)(x+2y)(x-2y)$, which produces a nice symmetric cross shape at the centre:
But we still haven't explained the butterflies – and I knew that I would have to understand what the butterflies were if I were to avoid them disappearing when magnified. So when I came back to the problem nearly ten years later, I looked at it with the eyes of a much more highly trained mathematician, and was finally able to see far enough into the chaos to pin down the cause of the butterflies.
The reason the central section of the image has such smooth changes of colour is that the values of $f(x,y)$ don't vary by much over the distance between pixels. But out in the butterfly regions, $f(x,y)$ is growing much faster than that; so why are those butterflies appearing? Answer: it must be because the difference in $f(x,y)$ between one pixel and the next is very close to an integer – so that the difference in the fractional part of $f(x,y)$ is very small even though the actual values of $f$ differ by a lot. And that's why half the butterflies disappear when you enlarge the image by a factor of two: when the difference in $f$ between two pixels is close to an odd integer, then the fractional part of $f$ half-way between the two pixels will be about $\frac12$ away from what it was at the original pixels themselves – as different as it's possible to be. No wonder the butterflies disappeared so easily.
So at the centre of every butterfly, the fractional part of $f(x,y)$ is close to the fractional part of $f(x+1,y)$, and also close to the fractional part of $f(x,y+1)$. In other words – and here's where the calculus begins – the partial derivatives of $f$ with respect to $x$ and $y$ are both integers at the centre of each butterfly. (Well, actually they're integer multiples of the reciprocal of the inter-pixel spacing; but it obscures the essence of the mathematics to have to keep remembering about the inconvenient constants. Putting the correct constants back in is left as an exercise for the reader :-)
This also suggests that if we plot the lines along which the partial derivatives $\partial f/\partial x$ and $\partial f/\partial y$ are equal to an integer and a half, we might well find ourselves drawing a set of lines that precisely mark the divisions between the butterflies. And it's true: we get the following picture. (The partial derivatives in $x$ and $y$ are $16x^3-34xy^2$ and $16y^3-34yx^2$ respectively. Black lines mark contours of $\partial f/\partial x$; red lines mark contours of $\partial f/\partial y$.)
(Notice in the above graph that the contours of the derivatives have a three-fold symmetry. These three-way symmetric curves can clearly be seen by following the lines of butterflies in the original image; at first sight they seem a bit odd because the function being plotted is four-way symmetric, right? But it does make sense: the positions of the butterflies depend on the derivatives of the degree-4 polynomial we started with, which are degree-3 polynomials and can therefore indeed be expected to be three-way symmetric.)
Now we're getting closer. With the above piece of analysis to help us, we can isolate each butterfly and treat it separately.
For a moment, let's pretend this whole thing is only happening in one dimension, instead of two. Consider the situation at the centre: the value of $f$ itself varies very little between pixels, so computing the halfway point between two pixels will produce a value that still fits in sensibly with the ones around it. No problem.
Now consider the situation in a butterfly region. The difference in $f$ between two adjacent pixels is close to an integer, let's say $a$. So $f(x+1)=f(x)+a+\epsilon$, where $\epsilon$ is the error term. Therefore, we would expect the halfway point to be $f(x)+a/2+\epsilon'$, where $\epsilon'$ is comparable to $\epsilon$. More generally, $f(x+b)$ (where $b$ is between 0 and 1) can be expected to be $f(x)+ab+\epsilon(b)$. So this gives what seems like a sensible way to plot a point whose coordinates are fractional. To plot the point at $x+b$, compute the nearest integer $g$ to the partial derivative at $x$; then compute $f(x+b)$ as normal, but subtract $bg$ before taking the fractional part.
And this works! Returning to two dimensions, it still works. Every clearly defined butterfly in the original image holds together when viewed at higher resolution. Let's enlarge the image above by a factor of two to prove it:
To summarise, the algorithm for enlarging the image is as follows.
After doing all of this, I made a further discovery. The original function $x^2y^2$, and the replacement $(2x+y)(2x-y)(x+2y)(x-2y)$ that I then switched to, are both products of real linear factors. What happens, I wonder, when you try using a polynomial without real factors?
So I tried it, of course. I replaced the function $(2x+y)(2x-y)(x+2y)(x-2y)$ with the alternative function $(2x+iy)(2x-iy)(x+2iy)(x-2iy)$ (which of course multiplies out to a real polynomial, since the factors come in conjugate pairs). The result was qualitatively different from the other images:
Suddenly we're getting circle shapes instead of butterfly shapes! In retrospect, this makes reasonable sense: you get a circle shape when the function is locally shaped like a paraboloid – curving upwards on all sides, or downwards on all sides – and a butterfly shape when the function is locally saddle-shaped, curving upwards in one direction and downwards in the perpendicular direction. By choosing polynomials with real factors, it seems I inadvertently also chose functions which were saddle-shaped everywhere.
This is very nice; what happens when we try a function with some real factors? So I tried the polynomial $y(2x-iy)(2x+iy)$ ... and this happened.
Isn't that something? Butterflies in parts of the plot, circles in other parts – and some really fun things, like small fish shapes, happening where the two meet.
We can work out which type of feature we expect to see in which parts of the plane, by applying a bit more calculus: given a twice partially differentiable function $f(x,y)$, a few hours of intense thought will tell you that the double partial derivatives can be combined into the formula $$\left(\frac{\partial^2 f}{\partial x \partial y}\right)^2-\left(\frac{\partial^2 f}{\partial x^2}\right)\left(\frac{\partial^2f}{\partial y^2}\right)$$ and that this is greater than zero in saddle-shaped regions and less than zero in circle-shaped regions. (Also, this formula only varies by a positive constant factor when you change the axes on the diagram, so it's a genuine reliable way to tell.) But this doesn't seem to help with the pretty pictures – it just gives us a useful tool to analyse them with.
So that's the heavy-duty maths over with. We're now able to take the original simple plots of the fractional part of $f(x,y)$, and enhance them into high-resolution images that can be fed to a seriously high quality printer to generate eye-twisting posters. But that isn't the end of it: some of the by-products of the algorithm above can be used to produce some more fun effects.
In particular, when the partial derivatives above are rounded to the nearest integer, it's instructive to note the amount by which each derivative had to change when rounded. This will be close to zero (in both directions) at the centre of each butterfly, close to one-half (in both directions) at the corner between four butterflies, and close to one-half (in only one direction) on the edge between two butterflies. So we could take the maximum of the fractional part of each partial derivative and use it to fade the butterflies out at the edges:
Also, keeping the integer parts of the partial derivatives provides a good way to differentiate one butterfly from the next by changing the colour. Here's what happens if we colour each butterfly purple or green depending on whether the sum of the integer parts of the partial derivatives is even or odd (this looks a bit strange unless the fading effect is used at the same time):
In case you want to try doing some of these for yourself, a program to generate filigrams is available for download here: C source code and precompiled Windows executable. The program will produce PNG, Windows .BMP, or PPM files, and image processing software should be able to convert those to other formats if you prefer.
Here's a selection of sample command lines you might like to try:
filigram -o cross.png -s 640x512 -I 0.03125 -p 4x4-17x2y2+4y4
-x 10 -O 0.015625
filigram -o accident.png -s 640x512 -I 0.025 -p x2y2 -x
8
filigram -o circles.png -s 640x512 -I 0.025 -p x2+y2 -x 8 -O
4
filigram -o complex.png -s 640x512 -I 0.03125 -p 4x4+17x2y2+4y4
-x 10 -O 0.015625
cross.png
above, except for one crucial plus sign replacing a minus sign in
the polynomial.
filigram -o fish.png -s 640x512 -I 0.03125 -p 4x2y+y3
-x 10 -O 0.5
To add colour effects to any of the above pictures, try putting these extra options on the end of the command line:
-f -c 0.7,0,1:0,0.63,0
-f -c 2+0.61,0.0,0.0:0.48,0.0,0.56:0.82,0.64,0.0:0.0,0.7,0.0
-f -c 1,0,0:1,1,0:0,1,0:0,1,1:0,0,1:1,0,1
-f -c 1,1,1:0,0,0
-f -c 0,0.4,1:0,0.7,0.5
fish.png
:-)
To generate a bigger version of any of those images, change the
image size specification after the "-s
" option.
Here are a few bigger (800 × 600) images I generated
myself. All these are in PNG format.
[checkers]
[rainbow]
[jewels]
[wormhole]
[deepsea]