Mandelbrot Set
3 min read

Categories

  • perl

The Mandelbrot set is created from this very simple formula in which both Z and C are complex numbers.

\[Z_{n+1}=Z_n^2+c\]

The formula is iterated to determine whether Z is bounded or tends to infinity. To demonstrate this assume a test case where the imaginary part is zero and focus just on the real part. In this case, the formula is trivial to evaluate starting with Z = 0. The table below shows the outcome at C=0.2 and C=0.3 and where one is clearly bounded and the other is not!

Iteration C = 0.2 C = 0.3
  0 0
1 0.2 0.3
2 0.24 0.39
3 0.2576 0.4521
4 0.266358 0.504394
5 0.270946 0.554414
6 0.273412 0.607375
7 0.274754 0.668904
8 0.27549 0.747432
9 0.275895 0.858655
10 0.276118 1.037289
11 0.276241 1.375968
12 0.276309 2.193288
13 0.276347 5.110511
14 0.276368 26.41732
15 0.276379 698.1747
16 0.276385 487448.2
17 0.276389 2.38E+11
18 0.276391 5.65E+22

C=0.2 is said to be part of the set where C=0.3 is not. Typical this point is coloured by some arbitrary function of the number of iterations it took for the modulus of Z to exceed 2.

The set is plotted on the complex number plane with the real part using the x-axis and the imaginary part using the y-axis, thus:

Given that computers don’t natively work with complex numbers we need to break the formula down into manageable pieces. Firstly write the formula including both the real and complex parts then expand the brackets and group the terms.

\[Z_{n+1}=Z_n^2+c\] \[Z_{n+1}=(Z_{re}+Z_{im}i)^2+c_{re}+c_{im}i\] \[Z_{n+1}=Z_{re}^2-Z_{im}^2+2Z_{re}Z_{im}i+c_{re}+c_{im}i\] \[\mathbb R(Z_{n+1})=Z_{re}^2-Z_{im}^2+c_{re}\] \[\mathbb I(Z_{n+1})=2Z_{re}Z_{im}+c_{im}\]

Here’s a Perl program to generate a PNG file. Over the years I’ve written this same program in many languages starting with Pascal at school, PostScript at University and Excel VBA and JavaScript…

Here’s a Perl program to generate a PNG file. Over the years I’ve written this same program in many languages starting with Pascal at school, PostScript at University and Excel VBA and JavaScript…

#!/usr/bin/perl -w

use strict;
use GD;

my $width = 1024;
my $height = 1024;

GD::Image->trueColor(1);
my $img = new GD::Image($width, $height);

Focus on an interesting bit. Real should be between -2.5 and 1 and imaginary between -1 and 1.

my $MINre = -0.56;
my $MAXre = -0.55;
my $MINim = -0.56;
my $MAXim = -0.55;

Maximum number of iterations before the point is classified as bounded. I’ve used 255 because I am using this as the colour component later

my $max = 255;

Setup the loops to move through all the pixels in the image. The value of C is calculate from the image size and scale. Note that GD creates images with the origin in the top left.

for my $row (1 .. $height) {
    my $Cim = $MINim + ($MAXim - $MINim) * $row / $height;
    for my $col (0 .. $width - 1) {
        my $Cre = $MINre + ($MAXre - $MINre) * $col / $width;

Z starts at the origin

        my $Zre = 0;
        my $Zim = 0;
        my $iteration = 0;

Loop until the modulus of Z < 2 or the maximum number of iterations have passed. Note that I’ve squared both sides to avoid a wasting time calculating the square root

while ($Zre * $Zre + $Zim * $Zim <= 4 && $iteration < $max) {

Here’s the formula from above to calculate the next value

            my $ZNre = $Zre * $Zre - $Zim * $Zim + $Cre;
            $Zim = 2 * $Zre * $Zim + $Cim;
            $Zre = $ZNre;

Move on to the next iteration

            $iteration++;
        }

Determine why we finished the loop - was it bound or not - and then colour the pixel appropriately

        if ($iteration < $max) {
            $img->setPixel($col, $height - $row, $iteration * 0x010101);
        } else {
            $img->setPixel($col, $height - $row, 0x00);
        }
    }
}

Output the PNG file to STDOUT

binmode STDOUT;
print $img->png;