K I Martin recently popularized a perturbation technique to accelerate Mandelbrot set rendering in his SuperFractalThing program. I wrote up some of the mathematics behind it, extending Martin's description to handle interior distance estimation too. Unfortunately it's very easy to get glitchy images that are wrong in sometimes subtle ways.

The most obvious reference point is usually in a central minibrot, which means it is strictly periodic:

-1.760732891182472726272e+00 + 1.302137831089206469511e-02 i 4.0194366942304651e-14 @ -1.760732891182472889620498413132e+00 +R 1.302137831089204904674633295328e-02 iR

The current version of mightymandel computes an error estimate and shades worse errors redder. A better reference point for this image is in a non-central minibrot near the tip of a solid red patch:

-1.760732891182472726272e+00 + 1.302137831089206469511e-02 i 4.0194366942304651e-14 @ -1.76073289118248636633168329119453103e+00 +R 1.30213783108675495217125732772512438e-02 iR

Nearby higher period non-central minibrots tend to work even better, and their limit is a pre-periodic point - one that becomes periodic after a finite number of iterations. I explored a bit the basins of attraction of preperiodic points for a couple of embedded Julia sets (which are the features that are most often glitchy).

-1.7607328089719322109e+00 + 1.3021307542195548201e-02 i 1.5258789062500003e-05 @ 1 1/2 2 1/2 3 1/3 6 4/5 35 A

The saturated dots at the tips and spirals in this period 35 embedded Julia set are the preperiodic points of interest. They have period 3 (matching the outer influencing island) and preperiods 35 (matching the inner influencing island) and 36.

Then zooming deeper to the near the period 35 island and into one of its hairs finds a doubly-embedded Julia set between the period 35 outer influencing island and a period 177 inner influencing island. Rendering the Newton Basins now needs more than double precision floating point, and my Haskell code using qd's DoubleDouble took almost 4 hours on a quad core. This time the points of interest have period 35 (matching the outer island) and preperiods 177 (matching the inner island) and 178.

-1.76073288182181309054484516839 + 0.01302138541499395659022491468 i 2.2737367544323211e-13 @

Here's the same view rendered with mightymandel, first with the central minibrot as reference:

-1.76073288182181252065e+00 + 1.30213854149941790026e-02 i 2.2737367544323211e-13 @

Then a non-central minibrot:

-1.76073288182181252e+00 + 1.302138541499417901e-02 i 2.2737367544323211e-13 @ -1.760732881821779248788320301573183e+00 +R 1.302138541488527885806724080050218e-02 iR

And finally a limiting pre-periodic reference point:

-1.76073288182181252e+00 + 1.302138541499417901e-02 i 2.2737367544323211e-13 @ -1.7607328818218582927504155115035552 +R 1.3021385414920574393027950216090353e-2 iR

No single reference point gives a red-free image, but combining multiple reference points, each appropriate to various parts of the image, looks like it would be a promising approach - and the knowledge about where the view is in relation to outer and inner influencing islands and their (potentially echoed) embedded Julia sets could perhaps be used to calculate a few candidate reference points automatically.

]]>I finally got around to postprocessing the photos I took of the pages in my notebook written on topics concerning the Mandelbrot set. You can see it here: Mandelbrot Notebook

One of the (too-many) long term projects I have is to write a book about the Mandelbrot set that bridges the gap between popular science books ("wow fractals are cool") and mathematical texts ("theorem: something hard and obscure"). I've never written a book before and found myself getting distracted by irrelevancies (like page layout, fonts etc) and re-editing text over and over instead of actually adding new content, so I've been experimenting with git version control commit messages:

git clone https://git.gitorious.org/maximus/book.git cd book git log --color -u --reverse

The working title is How to write a book about the Mandelbrot set.

]]>The Buddhabrot fractal is related to the Mandelbrot set: for each
point \(c\) that is **not** in the Mandelbrot set, plot
all its iterates \(z_m\) where \(z_0 = 0\) and \(z_{n+1} = z_n^2 + c\).
The anti-Buddhabrot flips this, plotting all the iterates for points
that **are** in the Mandelbrot set. For the Buddhabrot,
the points not in the Mandelbrot set will escape to \(\infty\), so we
know when to stop iterating. Points in the interior don't escape, but
almost all converge to a periodic cycle. In the limit of plotting a
very large number of iterations, the iterates in these cycles will
strongly dominate due to the periodic repetition, such that the earlier
iterates will be invisible. Define the **ultimate**
anti-Buddhabrot to be the iterate plots of these limit cycles.

Now, a point \(z_c\) in the limit cycle for \(c\) of period \(p\)
satisfies \( F^p(z_c, c) = z_c \). There will be \(p\) different
\(z_c\) for each \(c\), but we just need one, and we can find it
numerically using Newton's method. Given an arbitrary \(c\) we need
to find its period first, which we can do by checking the interior
distance estimate for each **partial**. Define a partial
as a \(q\) such that \(|z_q| \lt |z_m|, 1 \le m \lt q\). If the interior
distance for \(c\) is negative, then \(c\) is not inside a component
of the Mandelbrot set of that period. Once we have \(z_c\), we can
plot the \(p\) iterates in the cycle.

Buddhabrot colouring commonly uses several monochrome image planes with different iteration limits, brighter where more iterates hit each pixel, which are combined into a colour image. With the ultimate anti-Buddhabrot, we can accumulate a colour image: each period is associated to an RGB value, and we can plot RGBA pixels (with A set to 1) with additive blending. The final A channel indicates how many iterates hit the pixel, but we also have the accumulated colours that can show which periods were involved. Post-processing the high dynamic range accumulation buffer to bring it down to something that can be displayed on a screen can bring out more of the details.

Calculation can be sped up using recursive subdivision. The root of the recursion passes over the Mandelbrot set parameter plane. There are a few different cases that can occur at each point:

- exterior
- Compute the exterior distance estimate: if it's so large that all of the subdivided child pixels would be exterior, bail out now, otherwise subdivide and recurse without plotting iterates.
- interior
- If the interior distance is so large that all of the subdivided child pixels would be interior to the same component, subdivide and recurse with the now-known period, otherwise recurse with the general method described above; plot the iterates in both cases.
- unknown
- If the iteration limit is reached, bail out without recursing.

The key speedup is switching to a simpler algorithm that just calculates \(z_c\) and plots the iterates with a known period. Another optimisation exploits the symmetry of the Mandelbrot set about the real axis. Finally it's possible to parallelize using OpenMP, with atomic pragmas to avoid race conditions when accumulating pixels.

Source code in C99: Ultimate Anti-Buddhabrot reference implementation. Runtime just under 20mins on a 3GHz quadcore CPU.

]]>I started with distance estimator for Julia sets for the case of a super-attracting fixed point:

\[ \delta = - \lim_{k \to \infty} \frac{|z_k - z_\infty| \log |z_k - z_\infty|}{|\frac{d}{dz}_k|} \]

This formula is slightly different to the formula on the linked page, haven't worked out yet exactly why it works and what the significance of the differences are. Anyway, I wanted to apply it to Newton fractals for rational functions.

Recall Newton's root finding method for a function \(G(z)\):

\[ z_{k+1} = z_k - \frac{G(z_k)}{\frac{d}{dz}G(z_k)} \]

If there are more than two roots of G, the boundary between regions that converge to different roots is a fractal. It's actually a Julia set for \(F(z)\) where

\[ F(z) = z - \frac{G(z)}{\frac{d}{dz}G(z)} \]

So we need to compute \(F^k(z)\) and\(\frac{d}{dz}F^k(z)\) for the distance estimate. By the product rule for derivatives, the derivative is the product of the derivatives at each step. It turns out that the actual calculations are very simple. Here's the derivation:

\[ \begin{aligned} F(z) &= z - \frac{G(z)}{\frac{d}{dz}G(z)} \\ \frac{d}{dz} F(z) &= 1 - (\frac{d}{dz} G(z) \frac{1}{\frac{d}{dz} G(z)} + G(z) \frac{d}{dz} \frac{1}{\frac{d}{dz} G(z)}) \\ &= 1 - (1 + G(z) \frac{- \frac{d}{dz}\frac{d}{dz} G(z)}{(\frac{d}{dz} G(z))^2})\\ &= \frac{G(z) \frac{d}{dz}\frac{d}{dz} G(z)}{(\frac{d}{dz} G(z))^2} \end{aligned} \]

As \(\frac{d}{dz}F(z)\) has a factor \(G(z)\), and iterations of F(z) converge to a root \(z_\infty\) where \(G(z_\infty) = 0\), the roots are super-attracting fixed points.

Now, \(G(z)\) is a rational function:

\[ G(z) = \frac{P(z)}{Q(z)} = \frac{\prod_{i} (z - p_i)^{P_i}}{\prod_{j} (z - q_j)^{Q_j}} \]

We need to compute \(F\) and \(\frac{d}{dz}F\), and happily this doesn't need the calculation of all of \(G\), \(\frac{d}{dz}G\) and \(\frac{d}{dz}\frac{d}{dz}G\), because lots of terms cancel each other out:

\[ \begin{aligned} \frac{d}{dz} G(z) &= \frac{ Q(z) \frac{d}{dz} P(z) - P(z) \frac{d}{dz} Q(z) }{ (Q(z))^2 } \\ \frac{d}{dz} P(z) &= \sum_I{(P_I (z - p_I)^{P_I - 1} \prod_{i \ne I} (z - p_i)^P_i)} \\ &= (\prod_i{ (z-p_i)^P_i }) (\sum_i{ \frac{P_i}{z - p_i}}) \\ &= (\sum_i{ \frac{P_i}{z - p_i}}) P(z) \\ \frac{d}{dz} Q(z) &= (\sum_j{ \frac{Q_j}{z - q_j}}) Q(z) \\ \frac{G(z)}{\frac{d}{dz}G(z)} &= \frac{\frac{P(z)}{Q(z)}}{\frac{Q(z)(\sum_i{ \frac{P_i}{z - p_i}})P(z) - P(z) (\sum_j{ \frac{Q_j}{z - q_j}}) Q(z)}{(Q(z))^2}}) \\ &= (P / Q) / ((P Q (\sum_P) - P Q (\sum_Q)) / (Q Q)) \\ &= 1 / ((\sum_P) - (\sum_Q)) \\ F(z) &= z - \frac{1}{(\sum_i{ \frac{P_i}{z - p_i} }) - (\sum_j{ \frac{Q_j}{z - q_j}})} \\ \frac{d}{dz} F(z) &= 1 + \frac{ (\sum_j{ \frac{Q_j}{(z - q_j)^2}}) - (\sum_i{ \frac{P_i}{(z - p_i)^2} }) }{((\sum_i{ \frac{P_i}{z - p_i} }) - (\sum_j{ \frac{Q_j}{z - q_j}}))^2} \end{aligned} \]

where the derivation of the last line is left as an exercise (in other words, I couldn't be bothered to type up all the pages of equations I scribbled on paper).

Putting it into code, here's the algorithm in C99:

#include <complex.h> #include <math.h> typedef unsigned int N; typedef double R; typedef double complex C; R // OUTPUT the distance estimate distance ( C z0 // INPUT starting point , N nzero // INPUT number of zeros , const C *zero // INPUT the zeros , const C *zerop // INPUT the power of each zero , N npole // INPUT number of poles , const C *pole // INPUT the poles , const C *polep // INPUT the power of each pole , N *which // OUTPUT the index of the zero converged to ) { C z = z0; C dz = 1.0; R eps = 0.1; // root radius, should be as large as possible for (N k = 0; k < 1024; ++k) { // fixed iteration limit for (N i = 0; i < nzero; ++i) { // check if converged R e = cabs(z - zero[i]); if (e < eps) { *which = i; return e * -log(e) / cabs(dz); // compute distance } } C sz = 0.0; C sz2 = 0.0; for (N i = 0; i < nzero; ++i) { C d = z - zero[i]; sz += zerop[i] / d; sz2 += zerop[i] / (d * d); } C sp = 0.0; C sp2 = 0.0; for (N j = 0; j < npole; ++j) { C d = z - pole[j]; sp += polep[j] / d; sp2 += polep[j] / (d * d); } C d = sz - sp; z -= 1.0 / d; dz *= (sp2 - sz2) / (d * d) + 1.0; } *which = nzero; return -1; // didn't converge }

complete C99 source code for distance estimated Newton fractals.

]]>I previously wrote about
Mandelbrot set Newton basins
in the context of finding islands, whose nuclei are periodic points. A
periodic point of a function **g** satisfies
**g ^{p} = g^{0}**, where

Newton's method tries to find a root of a function **h(x) = 0**
by iterating **x → x - h(x) / h'(x)** where **h' = dh/dx**,
namely the differential of **h** with respect to **x**.
Here the quadratic function **f** in the Mandelbrot set is
considered as a function of **c**, with **f' = df/dc**
and we want to find a preperiodic **c _{0}** satisfying

Now, **f** and **f'** can be computed by
recurrence relations:

F_{c}^{0}= 0

F'_{c}^{0}= 0

F_{c}^{n+1}= (F_{c}^{n})² + c

F'_{c}^{n+1}= 2 F_{c}^{n}F'_{c}^{n}+ 1

Applying Newton's method gives:

c → c - (F_{c}^{p+k}- F_{c}^{k}) / (F'_{c}^{p+k}- F'_{c}^{k})

But solving this isn't the whole story - it might converge to a preperiodic
point with a preperiod less than **k**, say **k'**.
(Even the target period **p** may be a multiple of the true period,
say **p'**.) The next step is to find the true preperiod of the
resulting **c _{0}**, which can be done by finding the
smallest

Enough of how (for full details read the source linked below), here are some images, each with a certain fixed period and coloured according to the true preperiod of the root converged to at each pixel.

Image *a* shows the whole Mandelbrot set with some preperiodic
basins of period 1 highlighted. You can see they surround some terminal
and branch points, but not all. Images *b* and *c* show
enlarged regions near the 1/3 and 2/5 bulbs. Image *d* starts to
get interesting - this is zoomed in near the 1/3 child of the 1/2 bulb.
Notice how only the outer filaments have basins attached. Compare with
image *e* which increases the target period to 2: here the inner
filaments have basins attached.

This leads me to conjecture that multiplicative *tuning* is at
work: the inner filaments near a child atom will have preperiodic branch
points that have a period a multiple of the parent atom's period, compared
to the corresponding preperiodic branch points at the root. This seems
to be supported by the remaining images: *f*, *g*, *h*
with periods 1, 2, 3 highlighted near the period 3 island; *i*
near a period 4 island with period 4 highlighted, and *j* near a
period 5 island with period 5 highlighted. Note the inner filaments
being highlighted when the periods match.

Newton's root finding method has a few applications when exploring the Mandelbrot set. You can use it to find the center of a component given a reasonable location estimate, or find a particular point on the boundary of a component given its center, and it is also used when tracing external rays from infinity inwards towards the boundary.

Tracing external rays is a slow process, needing many steps with many iterations of Newton's method for each step. When tracing rays to a particular component, it would be desireable to switch to Newton's method for center finding as soon as possible. A rough heuristic (ie, I haven't proved that it works everywhere) might be to trace a few rays in parallel, and check the atom domain at the ray end points, switching when all ray end points are in an atom domain of the target period using the average of the endpoints as initial estimate.

The images show fractal basins of convergence for Newton's method for a particular period, with the atom domains of the target period highlighted, overlayed with the boundary of the Mandelbrot set. It seems that the atom domain is wholy within its own Newton basin, and also significantly larger than the corresponding component.

]]>Combine fractals with juggling and you might get something like this.

This is from six months ago but I didn't get around to posting it before.

Videos available on the Internet Archive:

You can get the code as part of *fractaloids* here:

git clone git://gitorious.org/maximus/fractaloids.git

Or browse fractaloids on Gitorious.

]]>