Fractal friends

Continuing with my theme of making every hobby programming project I do have some relation to the Mandelbrot set, I recently whipped up a fun little app that allows you to explore the Mandelbrot set’s associated Julia sets.

You can check the app out here or keep reading if you want to understand what’s going on first.

Some math for those interested

The Mandelbrot set

The Mandelbrot set is defined as the set of complex numbers cc such that the sequence

z0=cz1=z02+cz2=z12+c  zn=zn12+c  \begin{align*} z_0 &= c \\ z_1 &= z_0^2 + c \\ z_2 &= z_1^2 + c \\ &\ \ \vdots \\ z_n &= z_{n-1}^2 + c \\ &\ \ \vdots \end{align*}

does not diverge. Roughly put, a point is in the Mandelbrot set if we can continue squaring it and adding the original value forever without it getting arbitrarily large. We can generate images of the Mandelbrot set by giving assigning each pixel a complex value based on its x and y coordinates. (Typically, we’ll have x coordinates represent the real part, and the y coordinates represent the imaginary part, so the pixel at position (x,y)(x, y) would represent the complex number x+yix + yi, where ii is the imaginary unit, 1\sqrt{-1}.) We can then assign colors to each pixel depending on whether they are or aren’t inside the set.

In practice, we set some maximum number of iterations for each point, which we can call nmaxn_\text{max}. We can take advantage of the fact that the {zn}\{z_n\} sequence always diverges if there is any point znz_n with zn>2\|z_n\| > 2, and assume that a point belongs to the set if its corresponding sequence hasn’t gone outside that limit after nmaxn_\text{max} iterations (i.e., if nnmax,zn2\forall n \leq n_\text{max}, \|z_n\| \leq 2). We can then even create a gradient of colors outside the set based on how many iterations it takes until we get a value bigger than 2. (Of course, this won’t be 100% accurate for any finite nmaxn_\text{max}, but we don’t have infinite computing power to check iterations until the end of time, so we have to make do with checking finitely many iterations.)

Here’s some code we can use to check each point (adapted from here):

mandelbrotIteration(c: Complex) {
    let z = c;
    for (let i = 0; i < this.maxIterations; i++) {
        z = z.mul(z).add(c);
        if (z.abs() > 2) {
            return i / this.maxIterations;
        }
    }
    return 1;
}
The central, white, region in this image is the interior of the Mandelbrot set.

Julia sets

Given some function ff that maps complex numbers onto other complex numbers (and satisfies some other technical requirements), we can define a set of complex numbers zz such that the sequence

z0=zz1=f(z0)z2=f(z1)  zn=f(zn1)  \begin{align*} z_0 &= z \\ z_1 &= f(z_0) \\ z_2 &= f(z_1) \\ &\ \ \vdots \\ z_{n} &= f(z_{n-1}) \\ &\ \ \vdots \end{align*}

does not diverge.

The Julia set for ff is the boundary of this set.

Here, we’re interested in the Julia sets based on functions of the form fc(z)=z2+cf_c(z) = z^2 + c, which, you may notice, is the same as the function used to define the Mandelbrot set. The difference here is that, when generating the Mandelbrot set, the number cc that we add at each step is different for each point in the set (and equal to the starting value of the iteration), whereas when we generate these Julia sets, we add the same number cc regardless of the starting value of our iteration. That is, every number cc in the complex plane generates its own Julia set.

The code below shows an iteration we could use to render the Julia set for fc(z)f_c(z) (adapted from here).

juliaIteration(z: Complex) {
    for (let i = 0; i < this.maxIterations; i++) {
        z = z.mul(z).add(this.c as Complex);
        if (z.abs() > 2) {
            return i / this.maxIterations;
        }
    }
    return 1;
}

Notice that the value cc we add at each iteration is independent of the starting value zz. This means that each point in the Mandelbrot set has its own associated Julia set. In fact, the Julia set for fc(z)=z2+cf_c(z) = z^2 + c will be nonempty if and only if cc is within the Mandelbrot set.

The app I created allows you to explore the relationship between the position of these cc points in the Mandelbrot set and their associated Julia sets. Check it out here.

A rendering of the Julia set for the function f(z)=z²+c
 with c = 0.27 - 0.56i. The Julia set is technically the boundary of the central white region.
goodness, truth, and summer rainstorms