Archive for August, 2011

Children of Julia Sets

August 23rd, 2011

Here’s a pretty specimen I found while playing with a bit of code I wrote to produce quadratic Julia sets:

If you know your Julia sets, you might be thinking something odd is going on here.

If you don’t, here’s a quick primer.

Pick a complex constant c. Then for every point z in the complex plane, create a sequence with the following recursive definition:

z
0 = z
zn+1 = zn2 + c

This sequence will do one of two things. Either it will zip away from 0 and eventually go indefinitely far away, or it won’t. (It could converge to a single point, or alternate between a few points, or bounce around chaotically. It doesn’t matter.) The points where the sequence sticks around near zero form a quadratic Julia set. There are other kinds of Julia sets, defined using different formulas. But the kind of Julia set you will most commonly encounter is this one, and henceforward I will use the term Julia set to refer to this kind of Julia set.

Julia sets are fun to play with because they are fractals, with infinite levels of detail and self-similarity. Some Julia sets form a single connected blob:


Julia set for c = .3 + .2i

Other Julia sets form dusts, where any region that appears to be in the set is actually divided into separate disconnected regions, and these regions are themselves divided, ad infinitum:


Julia set for c = .7 + .33i

I should note that I’m cheating here slightly. A dust isn’t actually much to look at. Although it contains an infinite number of points, the probability of an individual point being in a dust-like Julia set is 0, so if I were plotting it properly, there would be nothing to see. What I’m actually plotting for each point is a level of grey on a scale from 0 to 255 (the latter being black) corresponding to the number of iterations it took for the sequence to escape beyond a given bound. The use of a grayscale gives dusts a more organic look, which I rather like.

Every Julia set is either a dust or a blob. The famous Mandelbrot set effectively catalogs this aspect of Julia sets. For every possible constant c, one checks only the behavior of 0 in the Julia set for that constant. If 0 escapes to infinity, we have a dust, otherwise we have a blob.  Near the boundary, the blob thins into increasingly narrow filaments, but it remains in a single connected piece until the boundary is crossed, and the blob shatters into a dust. The Mandelbrot set contains all of the constants that give “blob-like” Julia sets.


The Mandelbrot Set

Getting back to my first image in this post, you can now see why I said there was something odd about it. That fractal is not a single blob; there are many disconnected parts. But it also isn’t a dust; there are filled solid regions. So it can’t be a proper Julia set. But it does have a Julia set “feel” to its self-similarity. So what’s going on?

The answer is that instead of using a single constant at every step of iterating the sequences for each point, as one would for a proper Julia set, I alternated between two constants. In fact, the two constants I alternated between were precisely the constants for the blob and dust I showed above. Thus it is perhaps unsurprising that the “child” of a blob and a dust would show characteristics of each: those characteristics were in its “genes”.

Alternating between the two constants in the opposite order gives the following:

Looks like the same basic pattern as before, but with two big connected bits instead of one. Notice that in this one the center point (z=0) is outside the set, while for the other one it was inside the set. Since this is the point that would tell us if we had a blob or a dust in a normal Julia set, it feels appropriate that it can go either way depending on the order here.

Here’s the Python code that produced the last image:

from PIL import Image
size = 400
im = Image.new("RGB", (size, size))
c = [.3 + .2j, -.70 + .33j] #j is i in python
for x in xrange(size):
    for y in xrange(size):
        z = x * (4.0 / size) - 2 + (y * (4.0 / size) - 2) * 1j 
        i = 0
        while abs(z) < 4 and i < 256:  
            z = z ** 2 + c[i % 2]
            i += 1
        im.putpixel((x,size-y-1), (255-i,255-i,255-i))

im.save("julia6.png")