Chapter 22
The Mandelbrot set is an interesting mathematical object that owes much of its popularity to the computer programs that create images of it.
Listing 22.1: Mandelbrot Set
1 # mandelbrot.py
2 from image import ImagePPM
3
4 def lerp(frac, low, high):
5 return low + frac * (high − low)
6
7 def testpoint(c, maxreps):
8 z = 0
9 reps = 0
10 while abs(z) < 2 and reps < maxreps:
11 z = z ** 2 + c
12 reps += 1
13 frac = reps / maxreps
14 return (0, 0, int(lerp(frac, 0, 255)))
15
16 def mandelbrot(xint, yint, size, maxreps):
17 width, height = size
18 img = ImagePPM.new(size)
19 for i in range(width):
20 for j in range(height):
21 a = lerp(i / width, xint[0], xint[1])
22 b = lerp(1 − j / height, yint[0], yint[1])
23 c = complex(a, b)
24 img.putpixel((i, j), testpoint(c, maxreps))
25 return img
26
27 def main():
28 img = mandelbrot((−2, 0.7), (−1.2, 1.2), (900, 800), 50)
29 img.save("mbrot.ppm")
30
31 main()
⇒ Caution: As you experiment with this program, some changes may cause it to take a long time to run.
The Mandelbrot set is defined using complex numbers, which have the form a + bi where i2 = −1. Complex numbers are visualized by plotting z = a + bi as the point (a, b) in the usual plane ℝ2.
Squaring a complex number z = a + bi works like this:
The size of a complex number is given by its absolute value, which is computed as
The following process decides whether or not a complex number c is in the Mandelbrot set:
Begin with z = 0.
Repeat: replace z with z ** 2 + c.
If abs(z) <= 2 forever, then c is in the Mandelbrot set.
Programs cannot wait forever, so some upper limit must be set on the number of repetitions.
Python supports complex numbers and complex arithmetic. We create a complex number with the built-in complex() function:
complex(a, b) |
Complex number a + bi. |
Then the arithmetic operations of addition, subtraction, multiplication, and exponentiation work as briefly described above. (Division is somewhat different, but we will not need it here.) The built-in absolute value function abs() also handles complex numbers correctly.
The mandelbrot() function in Listing 22.1 requires quite a few parameters to specify the region to draw, the size of the resulting image, and the maximum number of repetitions to use when deciding whether or not a point is in the Mandelbrot set. By grouping these together into natural tuples, we make the parameter list manageable.
There are several places in Listing 22.1 where we need to convert a fractional value in the interval [0, 1] to some other range [a, b]. Linear interpolation is the name for performing this conversion in a linear way, so that, for example, if the fraction is 1/3, then the interpolated value will be 1/3 of the way from a to b. Lerp is an abbreviation of linear interpolation.
reps == maxreps: black
0 <= frac < 0.5: interpolate (0, 0, 100) to (0, 255, 100)
0.5 <= frac < 1.0: interpolate (0, 255, 100) to white
Do either of the images appear distorted? Describe any distortion you see.
Explain the distortion you found in Exercise 22.9.
which is the same as the region being drawn. Thus, s can be used to control the final size of the image.
mandelbrotauto(xint, yint, scale, maxreps)
that draws the Mandelbrot set over the intervals xint and yint using the correct aspect ratio.
mandelbrotcentered(center, size, maxreps)
that draws the region of the Mandelbrot set centered at center with width and height specified by the tuple size. (These are not the image width and height, but the size of the region being drawn in the complex plane.) Use your function to draw the region centered at (−0.1, 1) with width and height 0.2.
for every c in the region:
test point c beginning with z = 0
In contrast, every c produces a different Julia set Jc. Given c, the Julia set algorithm for Jc is:
for every z in the region:
test point z beginning the iteration with z itself
Note that c is still used in the iteration that replaces z with z2 + c. Values of z that stay bounded in the iteration are in Jc.
Write a program to draw Jc for c = −0.8 + 0.2i over the region with x-interval [−1.6, 1.6] and y-interval [−0.9, 0.9].
3.136.97.64