Можно увеличив количество итераций и размер картинки, убедиться что шаблон повторяется.
Может возникнуть вопрос, как длина линии может быть бесконечной при конечной длине. Примерной аналогией может быть сумма ряда:
S = 0.9 + 0.09 + 0.009 + …
Как нетрудно догадаться, сам по себе ряд бесконечный, но его сумма стремится ко вполне определенному числу 0.999999… = 1.
“Снежинка Коха” интересна своей простотой, но есть и более сложные варианты фракталов. Рассмотрим множество Мандельброта, которое строится по следующему алгоритму: для каждой точки c=x + j*y на комплексной плоскости, эта точка попадает в множество при условии что ряд Zn+1 = Zn2 + c не расходится при z0 = 0.
Рассмотрим пример.
При c = (0,0) = 0 + 0j, ряд очевидно, всегда равен нулю, т.е. не расходится, значит точка (0,0) попадает в множество.
При с = (0.5, 0.5) = 0.5 + 0.5j, получаем следующие значения:
Z0 = 0
Z1 = Z0 + c = 0.5+0.5j
Z2 = Z1 + c = 0.5+1j
Z3 = Z2 + c = -0.25+1.5j
Z4 = Z3 + c = -1.6875-0.25j
Z5 = Z4 + c = 3.28515625+1.34375j
Z6 = Z5 + c = 9.48658752+9.32885j
Легко видеть, что ряд расходящийся, числа увеличиваются, значит (0.5, 0.5) не попадает в множество.
При с = (0.25, 0.25) = 0.25 + 0.25j, имеем следующий ряд:
Z0 = 0
Z1 = Z0 + c = 0.25+0.25j
Z2 = Z1 + c = 0.25+0.375j
Z3 = Z2 + c = 0.171875+0.4375j
Z4 = Z3 + c = 0.088134+0.400390625j
Z5 = Z4 + c = 0.09745508+0.32057666j
Z6 = Z5 + c = 0.15672809+0.31248365j
Z7 = Z6 + c = 0.17691766+0.34794993j
Z8 = Z7 + c = 0.160230+0.37311697j
Z9 = Z8 + c = 0.1364575+0.36956959j
Как можно видеть, ряд не расходится, т.е. точка (0.25, 0.25) попадает в множество.
Разумеется, вручную делать такие проверки было бы крайне неудобно, собственно это одна из основных причин, по которой фракталы не были известны до появления компьютеров. Чтобы заметить какие-либо закономерности фрактальной природы, необходима возможность их автоматического рисования. Кстати, сам Мандельброт работал в IBM и имел доступ к весьма мощным компьютерам своего времени.
На языке Python проверку попадания точки в множество легко записать в виде функции. Для нас удобно то, что Python умеет работать с комплексными числами, что делает запись кода более короткой.
Сама функция имеет следующий вид:
def countMandelbrotIterationsForPt(pt):
z = 0
c = pt
threshold = 64
for iteration in xrange(threshold):
z = z*z + c
if abs(z) > 4:
break
return iteration
Здесь вычисляется 64 итерации, которых вполне достаточно чтобы определить, является ли ряд расходящимся или нет.
Чтобы сохранить весь фрактал, нужно перебрать все точки в диапазоне [-2, 2], программа, сохраняющая фрактал в файл, приведена ниже:
from PIL import Image
points = 1000
img = Image.new('RGB', (2*points,2*points), "black")
pixels = img.load()
# Range.X: -2..2,
# Range.Y: -2..2
for ix in xrange(-points, points, 1):
for iy in xrange(-points, points, 1):
pt = complex(2.0*ix/points, 2.0*iy/points)
i = countMandelbrotIterationsForPt(pt)
if i > 16:
colR, colG, colB = 4*i, 4*i, 0
if colR >= 255: colR = 255
if colB >= 255: colB = 255
if colB >= 255: colB = 255
img_x = points + ix
img_y = points + iy
pixels[img_x, img_y] = (colR, colG, colB)
if ix % 10 is 0:
print "Done: {}%".format(100.0*(ix + points)/(2*points))
img.save("fractal.png")
Как можно видеть, программа содержит 2 вложенных цикла ix, iy, затем значение преобразуются в комплексное число, для которого и выполняется описанная выше функция проверки.
Результат выполнения программы для 1000 точек, показан на рисунке:
Если в несколько раз увеличить количество точек, можно увидеть структуру верхней части более детально:
Немного изменив формулу, можно получить другие виды фракталов. Например, множество Жюлиа, описывается также, но Z0 = pt, и c = const. Казалось бы, небольшое отличие, приводит к совершенно другому рисунку фрактала:
Кстати, этот рисунок напоминает сорт цветной капусты “Романеско”:
Наконец, если в формуле фрактала Мандельброта Zn+1 = Zn2 + c, вычислять абсолютное значение Z*Z в виде (|a| + j|b|)*(|a| + j|b|), мы получим фрактал с названием “горящий корабль”:
Сложно сказать, насколько форма напоминает корабль, верхняя часть под увеличением скорее напоминает береговую линию, видимую с высоты: