- Introduction
- Review of Complex Numbers
- Enter the Julia Set: Ordered Chaos
- The Mandelbrot Set: The Sum of All Julias
- Why Are These Functions Fractals?
- Mandelbrot and Julia Set Algorithms

[Top]

To help classify numbers, we often divide them up into *sets.* For example, there
is the set of all numbers, which contains every number possible. A better example is
the set of integers, which are all numbers which are whole and have no fractional
parts (-2, -1, 0, 1, 2,...). The set of *real numbers* are all numbers that can be
expressed by a rational fraction. This includes integers (2 = 2/1) as well as decimal
values (0.75 = 3/4).

Just like your mother used to make you distinguish between your real and imaginary
friends, there are also *imaginary numbers.* The most fundamental imaginary number
is the square root of -1, which we will assign to the variable ** i.** The
value if

Normally, real and imaginary numbers rarely meet. However, as calculus was invented and
mathematicians began solving more and more complex math problems to find special values,
strange things began to happen. Often, mathematicians would try to find the *roots*
of an equation; that is, where one of the inputs equals 0. While solving more complex
equations, they discovered that some roots did not fit in the set of real numbers. These
roots often had both a real and imaginary part. It has since been found that many, many
equations have such roots, and a special name has been assigned to such numbers. We call
any number with both a real and imaginary part a *complex number.*

Complex numbers are often written in the form ** x + yi,** where

**Addition:***(a + bi) + (c + di) = (a + c) + (b + d)i***Multiplication:***(a + bi)(c + di) = ac + adi + bci + bdi*^{2}= (ac - bd) + (ad + bc)i

There is a special case of multiplication where we multiply a complex number by itself: in other words, we raise it to the power of 2. This gives us the following equation:

*(a + bi)*^{2}= (a + bi)(a + bi) = a^{2}+ abi + abi + (bi)^{2}= (a^{2}- b^{2}) + 2abi

We single this particular fact out because it is very important to the graphs of the Mandelbrot and Julia sets.

We can graph complex numbers easily to a plane (2-dimensional graph). To do this, we
simply assign the ** x** value to an

- The values of
will increase without bound (go to infinity)*Z* - The values of
will collapse to 0 (zero)*Z* - The values of
will change, but will not fit in either of the above two categories*Z*

In the world of fractals, infinity and zero would be called *attractors,* because
many points approach (are attracted to) these points. The values that fit in the first
two categories are sometimes called the *Fatou set.* The values that fit in the
third category are said to be in the *Julia set.* Points in the Fatou set tend to
stick together; that is, points close to each other will follow similar paths, drawing
closer to either infinity or zero. Points in the Julia set, however, are said to be
*chaotic,* meaning that very small differences in points tend to show wildly
different results.

So where do all those cool pictures come from?

Since we do not know from the start which points are in the Fatou set and which are
in the Julia set, we must test each and every one. In reality, this is impossible, but
we can approximate this with the help of computers. In essence, we tell the computer
to create a graph where each pixel on the screen represents a point on the graph. How
far each pixel is apart from its neighbors is a function of the resolution (size) of
the graph and the boundaries we set for it. We then take each ** (x, y)** pair
(which represents a complex number, remember) and use that as our

The wild colors produced in *MMJ!* depend on how "quickly" escaping values move
toward infinity. For example, if you used the Grey Scale Palette, the lighter the color
is, the more quickly it reaches infinity. (However, there are only 256 colors, and if
the calculation goes beyond 256 iterations, the colors will cycle around and be reused.
Try this with "The Wheel" preset view to see what I mean.)
The very first color in any palette (such as black in the Grey Scale and Rainbow
palettes) denotes values inside the Julia set.

As you can easily imagine, testing every single point in the plane can take quite a long time, especially if we create large images (high resolution) with large cut-off values (many iterations). In general, the higher the resolution and the higher the iteration count, the more detail we see, but it will also take much, much longer to complete.

[Top]

The Mandelbrot set is named after Benoit Mandelbrot (1924-), a brilliant Polish
mathematician (and fellow IBMer).
Mandelbrot, inspired by Julia's published works, was one of the first to apply
computers to the study of Julia sets, and was the first to coin the term
*fractal.* With the aid of his trusty computer, he began to explore Julia sets, and
found (by accident) a very interesting relationship between them. As we discovered
above, Julia sets are all points where the sequence of ** Z** values change,
often drastically, but do not approach infinity nor zero. Points in the Julia set tend
to drift to other such points, and their graphs may connect. Some Julia sets may consist
of many disconnected points (called "dust sets"); others from larger "solid" areas that
seem all connected; some form thin, wiggly lines that are all connected but do not
outline any shapes ("dendritic" types).

Noting the different types of Julia sets, Mandelbrot set out to find some connection
between them. Why were some dust sets, some solid, and some dendritic? In time, he
discovered a very simple test to determine this value. By setting ** Z** to be
the origin of the complex plane

Or is it? Curious about this new-found information, Mandelbrot decided to plot a graph
of this new equation and colored the values depending on whether they were types (1),
(2), or (3). Interestingly, he created a sort of "master" Julia set, a totally different
fractal we know today as the *Mandelbrot set.*

If we zoom in on a portion of a Julia set, we will see the same detail repeated over
and over on a smaller scale. Other than size, it does not change. However, because the
Mandelbrot set is an amalgamation of all Julia sets, the detail changes drastically
depending on where you zoom in. It is based on the precise location in which you are
zooming, and is often similar in shape to the Julia sets derived from that area. The
Mandelbrot set is *never* the same twice, and you can technically zoom forever
(if it weren't for the limits of your computer's hardware).

[Top]

So why the Mandelbrot and Julia sets fractals? Technically, the sets themselves are not. However, the complex graphs created by graphing them in the complex plane are.

Unfortunately, the term *fractal* is extremely hard to define. The definition above
is highly simplistic. Through some highly complex mathematics, we can prove that the
Mandelbrot and Julia sets meet this definition, but I'll save you the headaches here.
Why don't we look as some other definitions of fractals and compare what we know to
them.

*The Divergent Measure definition: Any shape that has the unusual property that when
you measure its length, area, surface area or volume in discrete units, the measured
value varies exponentially with the size of the discrete unit.* We know this to be
true by the very definition of the two sets. As we stated above,
even minor changes in our starting values produce wildly different values of the result.
Close examination of the graphs also reveals this with the bizarre patterns displayed.

*Hausdorff definition: Any geometric form whose Hausdorff dimension is greater than
its topological dimension.* Hmmm... it might help to know what a Hausdorff dimension
is. For a shape
** F** imbedded in

where ** N_{e}** is the minimum number of points in the space

Ouch! My eyes just hurt looking at that! Suffice it to say we won't calculate all that, but it has been found that the Mandelbrot set has a Hausdorff dimension of 2, which is greater than the topological (boundary) dimension, which is 1. This means the graph is indeed a fractal.

*The Natural definition: A geometric figure or natural object that combines the
following characteristics: (a) its parts have the same form or structure as the whole,
except that they are at a different scale and may be slightly deformed; (b) its form is
extremely irregular or fragmented, and remains so, whatever the scale of examination;
(c) it contains "distinct elements" whose scales are very varied and cover a large
range.* This looks a little more within our grasp to prove. The first part is what
we like to call *self-similarity,* which the Julia set demonstrates easily (no
matter how far in we zoom, we see the same structures), but the Mandelbrot set is harder
to see. However, on closer examination, we see the master Mandelbrot set repeated over
and over leading us to believe that the first part is true. Part (b) is highly obvious
for our sets, as is part (c).

Thus, we can prove our graphs are indeed fractals. If this quick gloss-over doesn't satisfy you, I strongly suggest a quick jaunt to the Web, where tons of sites can give you far better definitions than I. For starters, here's a quick search of AltaVista that will give you many pages with definitions of fractals.

[Top]

and*xmin, xmax, ymin,*are the boundaries of our current view.*ymax*is the resolution, or size, of our image in pixels. Here, the image is square, so the*res*and*x*resolution will be the same.*y*is our color depth, or the number of colors available to us.*num_colors*is the number of iterations we allow before declaring a point to be in the set. If we escape the radius before this number is reached, we declare that the given point escapes to infinity.*iters*and*xgap*represent the distance between to pixels in the actual graph. The*ygap*value of point*x**p*will be_{n+1}more than the*xgap*value of point*x**p*The same follows for_{n}.values.*y*is the function that draws a pixel to the screen. It takes three arguments: an*setPixel()*value, a*x*value, and the color of the pixel. For us, we will use an indexed palette, where a positive integer between 0 and*y*will represent a given color.*num_colors*and*j*will be iterative values used to iterate through every point in the plane.*k*and*x, y, savex, savex2, savey, radius,*will be intermediate values used in the calculation.*count*

The algorithm:

xgap = (xmax - xmin) / res ygap = (ymax - ymin) / res for j = 0 to (res - 1) for k = 0 to (res - 1) x = xmin + j * xgap y = ymin + k * ygap savex = x savey = y radius = 0.0 count = 0 while (radius < 5.0) and (count < iters) savex2 = x x = x * x - y * y + savex y = 2.0 * savex2 * y + savey radius = x * x + y * y count = count + 1 endwhile if radius >= 5.0 setPixel(j, res - k, count mod num_colors) else setPixel(j, res - k, 0) endif endfor endfor

Notes:

- Note that in the
function calls, the*setPixel()*component*y*is subtracted from*k*This means we draw the graph from the bottom up (really!).*res.* - For Julia sets, instead of setting
and*savex*to the*savey*and*x*starting values, set them to the*y*and*x*parts of the constant*y*for the Julia set you wish to create (remember,*C*)*C = (x + yi)* - The escape
value is hard-coded to 5. Why? Because it has been proven that the origin stays bounded if and only if its image always stays within a distance of 2 from the origin. This gives us a circular boundary with a radius of*radius*= 2*x*^{2}+ y^{2}^{2}= 4 < 5. (A little extra for added measure.) Thevalue can be changed if you wish, but you should only make it higher.*radius* - Can you see where the multiplication and addition of complex numbers comes in?
If not, consider the following equations:
*Z*^{2}+ C = (z_{1}+ z_{2}i)^{2}+ (c_{1}+ c_{2}i)

*= ((z*_{1}^{2}- z_{2}^{2}) + 2z_{1}z_{2}i) + (c_{1}+ c_{2}i)

*= ((z*_{1}^{2}- z_{2}^{2}) + c_{1}) + (2z_{1}z_{2}+ c_{2})iRemember that

and*x*in the above algorithm corresponds to*y**(x + yi) = Z.* is used to hold the old value of*savex2*so we do not lose it after we recalculate*x**x.*- Note that
and*j, k, res, iters, num_colors,*are all integers, while all other variables should be floating point numbers, preferably double-precision. If you wish to use a language such as C++ or Java with this algorithm, you should explicitly cast these variables where appropriate.*count*

[Top]

© Copyright 1999, Jeffrey T. Darlington. All rights reserved.