## Smooth colouring is the key to the Mandelbrot set

#### « previous entry | next entry »

** 10th Nov 2010 | 15:54**

At Cambridge Geek Night 6 on Monday I gave a brief talk about what has been occupying some of my spare time in recent weeks. Since Benoît Mandelbrot died last month I have been playing around with making pretty pictures of Mandelbrot sets, culminating (so far) in a movie of a deep zoom targeted near *z* = -0.15 + 1.04*i*. The software and materials for my talk are at http://dotat.at/prog/mandelbrot/.

One of the nicest renderings I did when I was a teenager was a 300dpi laser-printed binary decomposition of the level sets of the exterior of the Mandelbrot set. It took a whole afternoon to generate using BBC BASIC on my Archimedes, which was the best tool for numeric code I had available. I wanted to be able to produce smoothly coloured renderings like the ones in the fractal art books by Heinz-Otto Peitgen and his collaborators, but a few things prevented me. Firstly the lack of a computer that could display true colour images :-) and secondly the difficulty of the mathematics. If I remember correctly, I just about grasped enough of the distance estimation method to understand that it requires significantly more work per iteration, which also made it unattractive on the slow computers I had to hand.

Revisiting the Mandelbrot set now, I have the luxury of computers that are thousands of times faster and thousands of times more colourful and millions of times more accurate with their arithmetic. The Internet also provides more accessible resources on the mathematics of the Mandelbrot set. A page by Linas Vepstas was particularly helpful with the smooth colouring problem. Even better, it turns out that his simple recipe arises from the mathematics that gives us our deepest understanding of the Mandelbrot set.

First some basic notation to make the formulae less cluttered.

To generate a Julia set, *c* is a fixed parameter and *z* varies across the complex plane. For the Mandelbrot set, *c* varies across the plane and *z* starts its iteration at 0. In both cases we iterate until *z* escapes to infinity, in which case it is outside the set, or remains bounded, in which case it is inside. Because we are most interested in the behaviour of *z* as it is iterated, we usually leave the parameter *c* implicit.

The simplest Julia set, when *c* = 0, is just the unit circle. In this case we can write down a direct formula for *z _{n}*:

There is something called a Böttcher map which transforms the exterior of Julia set *c* = 0 into the exterior of other connected Julia sets and back again. It's like a Riemann map, but it operates on the complement of the set.

The definition of the map is as follows. Observe that Φ_{0}(*z*) is the identity function.

Adrien Douady and John Hubbard showed that the Böttcher map Φ_{c}(0) is a conformal mapping from the exterior of the Mandelbrot set M to the exterior of the unit disk, and therefore the Mandelbrot set is connected.

The Böttcher map allows us to treat the exterior of the set as an electrostatic field. Imagine an infinitely long crinkly cylinder whose cross-section is the set. If you electrically charge the cylinder it creates a field in the surrounding space. The Böttcher map tells you how the simple circular equipotential curves and radial field lines of the Julia set *c* = 0 correspond to those surrounding the Mandelbrot set and the other connected Julia sets.

This is a powerful tool for understanding the Mandelbrot set. The binary decomposition makes a lot of the field structure visible, since the boundaries between the black and white areas are formed from segments of field lines and equipotential curves. If you express the angle of a field line as a binary fraction of a whole turn, you get the sequence of black and white segments that the field line crosses in the binary decomposition. Field lines with rational angles correspond to pinch points on the Mandelbrot set.

For our purposes we are less interested in field lines and more interested in the Douady-Hubbard potential function. We use the Böttcher map to warp the space around the set into its simplest form. This allows us to use the standard formula for the electrostatic potential around an infinite wire, which is the log of the distance from the wire. The base of the logarithm is related to how highly charged the wire is; we can choose it for our convenience.

Since we don't have time to count to infinity, in practice we define a bail-out radius *R* and stop iterating points that get further than that from the origin. The iteration count *n* is used for the flat blocky level-set colouring scheme.

The way to get a smooth colouring is to ask what fractional iteration value *ν* would make the point land exactly on the bail-out radius.

We can use the potential function to formalize this idea. If *R* is large, varying it will not make much difference to the potential we calculate for a point. So to derive *ν* we assume that we get the same result from the two expressions for the potential in the first line below. (I think this is what causes the small errors and discontinuities discussed by Linas.)

The final term in that equation is a constant, since *R* is a fixed parameter of our implementation. We might as well throw it away since it does not add any useful information.

And thus we get the equation to use for smoothly colouring of the exterior of the Mandelbrot set.

from:ewxdate:10th Nov 2010 16:24 (UTC)Permalink

## Reply | Thread

from:crazyscotdate:10th Nov 2010 17:08 (UTC)Permalink

I'm currently seeing precision artefacts at the same place they crop up in

fanf's video - 2^52 zoom or so - which tallies with scraping the bottom ofdouble, and I'm wondering whether there's a way to reliably detect that that is happening and disallow further zoom. Possibly (L)DBL_EPSILON is going to be my friend...## Reply | Parent | Thread

from:ewxdate:10th Nov 2010 17:19 (UTC)Permalink

All the interesting stuff has magnitudes between about 0.25 and 2, so with

doubleyour pixels can't go much below 2^{-53}or so and the 'floating' in floating point is of little use - fixed point is what you need. So 96 fractional bits should get you around 40 2x zooms beyond thedoubleversion.32 bits for the integer part is a bit excessive but it makes the C implementation easier to put the units column at the bottom of a word. (That might not be true for assembler though, I've not thought this through. Another 16 bits wouldn't hurt.)

## Reply | Parent | Thread

from:fanfdate:10th Nov 2010 17:22 (UTC)Permalink

32.96 would allow me to make a 6 minute movie zooming at a factor of 2 every 4 seconds (i.e. 1-2^-100 per frame).

## Reply | Parent | Thread

from:fanfdate:10th Nov 2010 23:21 (UTC)Permalink

## Reply | Parent | Thread

from:ewxdate:14th Nov 2010 18:14 (UTC)Permalink

double. Still, a fixed point log_{2}sounds like a fun exercise sometime.## Reply | Parent | Thread

from:nonameyetdate:10th Nov 2010 22:32 (UTC)Permalink

Did you just pick the most appropriate compression algorithm available in MPEG-4 or did you analyze the special features of this video ? I'm fairly sure that it must have coherencies that make a custom compression algorithm incredibly good (though not so much use unless everyone has the decompression algorithm).

## Reply | Thread

from:fanfdate:10th Nov 2010 22:49 (UTC)Permalink

I initially tried making the movie with ffmpeg's own h.264 compressor and the result was

disastrous. I installed x264 (which required a new binutils so that the assembler could support SSE3 instructions!) and recreated the movie and the result looked fine and was also smaller.## Reply | Parent | Thread

from:fanfdate:10th Nov 2010 23:17 (UTC)Permalink

Mandelbrot set implementations coded without a complex number abstraction usually deal with the square of the modulus

r_{n}^{2}since that saves the cost of a square root in each iteration. When you user^{2}in the formula for the smoothed iteration count, the log allows you to replace the square root with a division:This division can be eliminated for the same reason as the log(

R) term:If you only have natural logarithms,

If you only have logs to the base 2, then you can play the constant offset game again to get

Edited at 2010-11-10 11:20 pm (UTC)## Reply | Thread

from:dwmalonedate:12th Nov 2010 22:57 (UTC)Permalink

http://www.maths.tcd.ie/~dwmalone/m

http://www.maths.tcd.ie/~dwmalone/m

http://www.maths.tcd.ie/~dwmalone/m

http://www.maths.tcd.ie/~dwmalone/m

The first is a straight forward zoom. The second morphs a Circle (i.e. Julia set with constant 0) into dust by changing the constant value. The third morphs the regular Mandelbrot set into the z -> z^3 Mandelbrot set by varying the power between 2 and 3. Because you have some choices about which branch of the power to take for non-int powers, you get some interesting edges. The final one morphs the z -> conj(z^2) Mandelbrot set into the cubic one in a similar way. The Mandelbrot set with the conjugate Mandelbrot set is quite interesting 'cos it seems to have both smooth and fractal bits.

## Reply | Thread

from:fanfdate:14th Nov 2010 21:18 (UTC)Permalink

## Reply | Parent | Thread

## Nicely colored visualization of the Mandebrot Set

from:ext_329527date:21st Nov 2010 17:07 (UTC)Permalink

## Reply | Thread