Jeg holder for tiden på med The Emperor's New Mind, en nokså omfattende bok om fysikk og matematikk og livet og slikt, av Roger Penrose. Poenget hans er visstnok at det ikke er mulig å simulere en menneskelig bevissthet med en vanlig datamaskin, uansett hvor kraftig den måtte være, skjønt jeg har ikke kommet til den delen av boken ennå. På veien til denne konklusjonen er han imidlertid innom mye annet interessant som egentlig gjør boken verdt å lese i seg selv. En av tingene han streifer innom er Mandelbrot-settet, og inspirert av det jeg leste bestemte jeg meg for å kikke litt nærmere på dette selv.
Jeg regner med alle har sett et bilde av Mandelbrot-settet, eller Mandelbrot-mannen som det gjerne også kalles, men det er kanskje ikke alle som vet hvordan man lager dette bildet. Selv har jeg lest om det ved et par anledninger tidligere, men det var ikke før jeg leste om det boken til Penrose jeg innså at det faktisk er ganske lettvint å programmere en utregning av dette settet.
Oppskriften går som følger: Begynn med et komplekst tall, c. Dette tallet kaller vi z0. Regn så ut et nytt tall, z1 = z02 + c. Regn så ut enda et nytt tall, z2 = z12 + c. Etc, etc. Rent formelt skal man gjøre dette uendelig mange ganger, men i praksis nøyer vi oss med ganske mange ganger, for eksempel 100. Så regner man ut absoluttverdien av det siste tallet, i dette eksempelet z100. Hvis absoluttverdien er større enn 2 er c ikke med i Mandelbrot-settet, og hvis absoluttverdien er mindre eller lik 2 er c med i Mandelbrot-settet. Ved å følge denne prosedyren for 1280 x 800 punkter i det komplekse planet, og farge punktene svarte hvis de er med i settet, og hvite hvis ikke, genererte jeg denne figuren:
# Numpy has mathematical functions
import numpy as np
# Will use Python Imaging Library (PIL) to save picture
from PIL import Image
# Some parameters
pixels = (1000, 1000)
x_lims = (-2.0, 2.0)
y_lims = (-2.0, 2.0)
max_iter = 16
max_value = 2
def f(z, c):
# Function which does the iterations
# Takes z_{n} as input, returns z_{n+1}
return z**2 + c
def draw_picture(picture, filename):
# Save the image to file
im = Image.fromarray(picture, 'L')
im.save(filename)
def main():
# Setting up the area to calculate for
# Create two vectors, the number of points is given by
# the variable pixels, the points are equally spaced
# in the ranges given by x_lims and y_lims
x_range = np.linspace(x_lims[0], x_lims[1], pixels[0])
y_range = np.linspace(y_lims[0], y_lims[1], pixels[1])
# Create an array to hold the picture data
# The type uint8 is suitable for saving as an 8 bit
# black and white picture
picture = np.zeros(pixels, dtype = np.uint8)
# Loop over points in complex plane,
# constructed from x_range and y_range
for i in range(pixels[0]):
for j in range(pixels[1]):
# Create initial complex numbers
x = x_range[i]
y = y_range[j]
c = x + 1j * y
z = 0 + 0j
# Iterate until abs(z) > max_value
# or max number of iterations
for k in range(max_iter):
# Calculate new value of z from old value
z = f(z, c)
# Check the absolute value
if abs(z) > max_value:
# If the absolute value is greater than
# max_value, set the pixel to white and
# step out of the loop.
# All other pixels remain black.
picture[i, j] = 255
break
# Draw and save picture
draw_picture(picture, "mandelbrot.png")
if __name__ == '__main__':
main()