Pencil and watercolour citrus slice collaged:

Monotype print (painted on perspex then transferred to paper):

Second print augmented with pastels:

An abstract print with lines:

An abstract print with circles:

Pastel landscape with multiple colours blended:

Pastel mug:

Pastel moonscape:

"Trousers" print from dented polystyrene:

"Waves" print from dented polystyrene:

"Eggs" print from dented polystyrene:

Black and white collage:

Oil pastels and watercolour:

]]>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.

]]>Some time ago I wrote Organism, a series of semiautobiographical microstories that I thought I would continue at a later date but I never got around to it. Here's some more from the same perspective but in a different style.

]]>the core beckons

whaddayareckon

with these weapons?!

plutonium nights

naked party on this demoted planet

androids devoid of purpose

questing in all directions at once

just ice on this rock

if thatafter the apocalypse

what's left -

the breath of the exploding star

the word

the spirit

the vibrating invitation to a dream...

Previously I made a trailer for Haystack Situations, but never got around to sorting out a way to make prints available. At the end of last year I set it up to generate a new image every day in the form of a podcast, but (sur)real life intervened and I didn't get around to publicising it until now.

Clicky the piccy for the Haystack Situations homepage with thumbnails of them all, the latest week's worth at the top are available as PDF, and there's a PDF podcast RSS feed (icon at the top right) should you get addicted to hunting needles on a daily basis.

You can get the source here: 2014-03-01_haystack_situations.tgz, but beware the not-so-clean and even less documented code - I can try to help if you have trouble compiling and running (just ask), it needs these Debian packages (and possibly others):

]]>aptitude install build-essential libgsl0-dev libcairo-dev lmodern

]]>beyond the eastern cliffs

lives a tired magician

wizened greybeard

no longer looking for answers

not because he found any

but because

the mud was alive

clay instructed

again constructed

built in machinery

generative scenery

hatching a plot

that went something like...boy meets girl

at the end of the world

run the tape in reverse

find each act rehearsed

researched and planned

five moves ahead

unwind the mind

game's up, reboot, rewind.bail out the mothership

all hands to the pump and dump

no entry bookkeeping

transact subprime factor fission reactor

``there's a commodity derivative imbalance

in your cranium and I've just the solution''

(quoth the magician)

relit flames

misfit games

broken chains

taking pains

feeding brains

needing change

catalyst

you're not on the list

not coming in

barred

charred

bard

beard turned black

the plot thickens...boy meets girl

at the end of the world

run the tape in reverse

find each act rehearsed

researched and planned

five moves ahead

unwind the mind

game's up, reboot, rewind.four square twenty seven

cube of bricks

counting tricks

small nicks and cuts

towards the real blend of

rational irrational

slice and dice

rolling double six

free parking forever

in this static monopoly

frozen

dozing

transfixed by glazed stories high

bank on bloodied knuckles

all belt and no trousers

rabble rousers

carousers

``come to the carousel''

ride a wooden horse

that bucks you off

at the perpetual bend

the eventual trend

flatlines

steamrollered entropy

was it meant to be?boy meets girl

at the end of the world

run the tape in reverse

find each act rehearsed

researched and planned

five moves ahead

unwind the mind

game's up, reboot, rewind.boy meets girl

at the end of the world

run the tape in reverse

machine chews it up

tangled mess of magnetic media

irreparably ripped

and creased

cassette deceased

magician released

peace.

imagination figment]]>

perceptual pigment

bacon origami

original army

navy airforce

marine mammalian

alien communication

replay the log

redeploy the fog

moment of clarity

sudden hilarity

mental topology

network theology

beauty

ambiguity

ubiquitous

ridiculous

precarity

rarity

extinct

succinct

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.

]]>Figure 4.22 on pages 204-205 of **The Science Of Fractal Images**
is presented with this description:

A region along the cardioid is continuously blown up and stretched out, so that the respective segment of the cardioid becomes a line segment. ... Our blow-up factor is chosen accordingly to the result that all disks in Figure 4.22 have the same size.

While waiting for a train the other day, I remembered this image, and wanted to recreate it, which required deriving the equations (they were not presented in the book).

A Möbius transformation of the complex plane is a rational function of the form

\[ f(z) = \frac{a z + b}{c z + d} \]

with \( a d − b c \ne 0 \). It has inverse

\[ f^{-1}(z) = \frac{d z - b}{-c z + a} \]

Möbius transformations are conformal, preserving angles but not lengths, and map generalized circles to generalized circles (generalized circles include lines as the special case of a circle through infinity). A Möbius transformation can be constructed from 3 points and their images. For our purposes, we can choose the images of \(P_0, P_1, P_\infty\) to be \(0, 1, \infty\), which gives

\[ F(z) = \frac {(z-P_0)(P_1-P_\infty)}{(z-P_\infty)(P_1-P_0)} \]

This \(F\) stretches and flattens a circle through \(P_0, P_1, P_\infty\) into a straight line, with the blow-up factor increasing towards \(\infty\). If \(P_\infty\) is chosen as a cusp, all the primary discs along the path to the cusp get stretched to be roughly the same size.

So far this works for circles, but cardioids require another conformal map to transform them into circles so that the Möbius transformation can work its magic. A cardioid with its cusp at \(0\) and its front at \(4\) is transformed into a unit circle centered at \(1\) by \(f(z) = \sqrt{z}\) (with the branch cut of the square root along the negative real axis). So to transform the period 1 cardioid of the Mandelbrot set (which has cusp at \(1/4\) and front at \(-3/4\)) to a unit circle centered at \(0\) the resulting conformal map is

\[ G(z) = \sqrt{1 - 4 z} - 1 \]

with inverse

\[ G^{-1}(z) = \frac{1 - (z+1)^2}{4} \]

Now, given \(P_0, P_1, P_\infty\) on the cardioid, form the Möbius transformation \(F\) for \(G(P_0), G(P_1), G(P_\infty)\), then \(F(G(c))\) maps \(c\) near the boundary of the Mandelbrot set cardioid to a flattened strip near the real axis. But when rendering images, we start from a rectangle with coordinates \([0..\text{width})\times[0..\text{height})\), so we have to work backwards to find the corresponding \(c\) in the parameter plane. Inverting \(k = F(G(c))\) gives \(G^{-1}(F^{-1}(k)) = c\).

Moreover, for distance estimation colouring it's useful to colour pixels according to the distance estimate relative to the pixel spacing, which is no longer fixed when applying a conformal mapping with non-constant scaling. The scale factor associated with a conformal mapping is the absolute value of its derivative, and the relevant derivatives are

\[ \begin{aligned} \frac{\partial}{\partial z} \frac{a z + b}{c z + d} &= \frac{a d - b c}{(c z + d)^2} \\ \frac{\partial}{\partial z} \frac{1 - (z+1)^2}{4} &= \frac{-(z+1)}{2} \\ \frac{\partial}{\partial z} f(g(z)) &= \frac{\partial f}{\partial z}(g(z)) \frac{\partial g}{\partial z}(z) \end{aligned} \]

The third equation is the chain rule for derivative of function composition, which can be intuitively expressed as "multiply all the derivatives at each step".

Putting together all the transformations and their derivatives and choosing the preimages \(P_0, P_1, P_\infty\) as bond points and cusps on the boundary of the Mandelbrot set, gives some stretched cusp pictures.

*Map of strip locations.*

*Elephant valley (cyan).*

*Seahorse valley (magenta).*

*"Double rabbit valley" (yellow).*

Back in 2009 I blogged about Crystalline Cortex from 2006. The original code doesn't work any more (GridFlow changed syntax years ago, and seems no longer maintained now), so I rewrote it in C99. Usage: 'make run', you need 'mplayer' and 'pngtopnm' along with the usual development tools.

Source code: crystalline-cortex.tar.bz2

]]>Based on a drawing from a year an a half ago:

I showed it to Brent Yorgey in the **#diagrams** IRC channel and he made this:

strip :: (Double -> Double) -> Double -> Double -> Int -> Double -> Diagram SVG R2 strip f lo hi n offset = [lo, lo + (hi - lo) / (fromIntegral n - 1) .. hi] # map (square . f) # hcat' with {sep = offset, catMethod = Distrib} # fc black example = vcat' with { sep = 3, catMethod = Distrib } (replicate 7 str) # centerXY # pad 1.5 where str = strip (\x -> cos x + 1) (-pi) pi 23 3--Lozenge (Brent Yorgey)

Then I showed him how they interleave and he made this:

strip :: (Double -> Double) -> Double -> Double -> Int -> Double -> Diagram SVG R2 strip f lo hi n offset = [lo, lo + (hi - lo) / (fromIntegral n - 1) .. hi] # map (square . f) # hcat' with {sep = offset, catMethod = Distrib} lozenge = vcat' with { sep = 3, catMethod = Distrib } (replicate 7 str) # centerXY where str = strip (\x -> cos x + 1) (-pi) pi 23 3 example = mconcat [ lozenge # fc black , lozenge # fc red # translateY (-1.5) # translateX (width lozenge / 2 - 4.5) ]--Lozenges (Brent Yorgey)

These are so much simpler than my original code which was horrible C numerical stuff to converge a waveform to the right shape, printing numbers which I fed into GNUplot and then editing the image with GIMP to correct the aspect ratio. I don't have that original code any more, but here's a similar version:

#include <math.h> #include <stdio.h> #include <stdlib.h> const double pi = 3.141592653589793; int cmp(const void *x, const void *y) { const double *a = x; const double *b = y; if (*a < *b) return -1; if (*a > *b) return 1; return 0; } double y(double x) { return (cos(pi * x) + 1) / 2; } int main(int argc, char **argv) { if (argc < 2) { return 1; } int n = atoi(argv[1]); double a[2]; double x[2][n+1]; int w = 0; a[0] = 0.001; for (int i = 0; i <= n; ++i) { x[0][i] = (2.0 * i) / (2.0 * n + 1.0); } x[1][0] = 0; while (1) { printf("a\t= %g\n", a[w]); for (int i = 0; i <= n; ++i) { printf("x[%d]\t= %g\t%g\n", i, x[w][i], y(x[w][i])); } double s = y(x[w][0]); for (int i = 1; i <= n; ++i) { s += 2 * y(x[w][i]); } a[1 - w] = 1 / s; for (int i = 1; i <= n; ++i) { x[1 - w][i] = x[w][i-1] + a[w] * ((y(x[w][i-1]) + y(x[w][i]))/2 + y(x[w][n+1-i])); } w = 1 - w; qsort(&x[w][0], n+1, sizeof(x[w][0]), cmp); } return 0; }gcc -std=c99 -lm lozenge.c ./a.out 19 | head -n 2100 | tail -n 20 > lozenge.dat ; gnuplotunset key unset xtics unset ytics unset border set style fill solid set terminal png size 8192,8192 set output "lozenge-raw.png" plot [-0.2:1.2] [-0.7:0.7] "lozenge.dat" using 3:(0):\ ($3 - $4 * 0.0512405/3):($3 + $4 * 0.0512405/3):\ ((-1+$4) * 0.0512405/3):((1-$4) * 0.0512405/3) with boxxyerrorbars,\ "lozenge.dat" using (1-$3):(0):\ (1-$3 - $4 * 0.0512405/3):(1-$3 + $4 * 0.0512405/3):\ ((-1+$4) * 0.0512405/3):((1-$4) * 0.0512405/3) with boxxyerrorbarsgimp (crop image)

A further experiment led to this gradient with 5 colours out of phase:

Do check out the links above to the Haskell diagrams pastebin, it's quite awesome.

]]>