Benoit Mandelbrotin mukaan nimetty Mandelbrotin joukko, josta esitin kuvan edellisessä blogipostauksessa, on yksi tunnetuimmista fraktaaleista. Kyseinen fraktaali on oikeastaan oikeastaan joukko, koska siinä jaetaan kompleksitason pisteet c = x + iy niihin pisteisiin, joissa iteraatio z[n+1] = z[n]^2 + c suppenee ja niihin jotka eivät. Jos joukkoon kuuluvat pisteet värjätään mustaksi ja loput jollain muulla värillä, saadaan aikaan tuttu kuva Mandelbrotin joukosta.
Joukon idea perustuu siis iteraatioon z[n+1] = z[n] + c, jossa c on joukon piste mitä tarkastellaan, ja iteraatio aloitetaan nollasta z[0] = 0. Esimerkiksi jos c=1, saadaan (pythonilla laskettuna)
>>> c = 1
>>> z = 0
>>> z = z**2 + c
>>> z
1
>>> z = z**2 + c
>>> z
2
>>> z = z**2 + c
>>> z
5
...
Nyt tätä voitaisiin jatkaa loputtomiin ja lopputuloksena olisi ääretön - siispä c=1 ei kuulu mandelbrotin joukkoon. Sen sijaan arvolla c=0.1 saadaan (lopun ..0001 on pythonin pyöristysvirhe):
>>> c = 0.1
>>> z = 0
>>> z = z**2 + c
>>> z
0.10000000000000001
>>> z = z**2 + c
>>> z
0.11000000000000001
>>> z = z**2 + c
>>> z
0.11210000000000001
...
joka äärettömyydessä päätyy arvoon 0.112701665379258..., joka on äärellinen. Siispä c=0.1 kuluu Mandelbrotin joukkoon.
Mielenkiintoisemmaksi homma menee, kun luku c onkin kompleksiluku muotoa c = x + iy, jossa i^2 = -1. Kompleksiluvut voidaan esittää (x,y)-tasossa niin, että reaaliosa piirretään x-akselille ja imaginääriosa y-akselille, jolloin jokainen kompleksiluku c vastaa yhtä pistettä kompleksitasolla.
Python-kielessä imaginääriyksikköä merkitään j:llä i:n sijaan (tämä on sähkötekniikan merkintätapa, varmaan joku historiallinen juttu), joten esimerkiksi reaaliosaltaan 1.0 ja imaginääriosaltaan 2.0 kompleksiluku pythonissa on 1.0+2.0j. Nyt voidaan kokeilla, että kuuluuko kompleksitason piste (1,2) eli 1+2i (tai pythonilla 1+2j) Mandelbrotin joukkoon seuraavasti:
>>> c = 1.0 + 2.0j
>>> z = z**2 + c
>>> z
(1.0127016653792582+2j)
>>> z = z**2 + c
>>> z
(-1.9744353369380772+6.0508066615170328j)
>>> z = z**2 + c
>>> z
(-31.713866355309122-21.893852978959089j)
...
Jos tätä jatkettaisiin äärettömään, saataisiin kompleksinen ääretön. Tai oikeastaan kompleksiluvun itseisarvo (luvulle x+iy se on sqrt(x^2+y^2)) menisi äärettömään. Itseisarvon pythonissa saa näin:
>>> abs(z)
38.537126481701819
Siispä jos aiempaa iteraatiota jatketaan loputtomiin, menisi luvun itseisarvo äärettömään, joten piste 1+2i tai siis piste (1,2) ei kuulu Mandelbrotin joukkoon. Sen sijaan esimerkiksi piste 0.1+0.2i kuuluu, koska iteraatio näyttää tältä:
>>> c = 0.1 + 0.2j
>>> z = 0
>>> z = z**2 + c
>>> z
(0.10000000000000001+0.20000000000000001j)
>>> z = z**2 + c
>>> z
(0.070000000000000007+0.24000000000000002j)
>>> z = z**2 + c
>>> z
(0.047299999999999995+0.23360000000000003j)
...
ja jos kokeilet jatkaa iteraatiota huomaat, että z:n itseisarvo pysyy aina vaan järkevissä rajoissa.
Voidaan matemaattisesti osoittaa, että jos luvun z itseisarvo jossain iteraation vaiheessa ylittää luvun 2, se välttämättä menee äärettömään. Siispä iterointi voidaan lopettaa kun itseisarvo ylittää luvun 2.
Ihan alkuperäinen Mandelbrotin joukon visualisointi saadaan, kun ne pisteet kompleksitasossa värjätään mustaksi, mitkä kuuluvat joukkoon ja ne valkoiseksi mitkä eivät. Tämä musta vastaa mustaa osaa edellisen blogipostauksen kuvassa ja loppuosa olisi valkoista. Huomattavasti hienompi visualisointi kuitenkin saadaan, kun Mandelbrotin joukkoon kuulumattomat pisteet värjätään sen mukaan kuinka monta iteraatiota meni raja-luvun 2 ylittämiseen. Tämän luvun n perusteella voidaan esimerkiksi muodostaa väriarvo, jonka perusteella piste värjätään. Juuri tällä tavalla on muodostettu edellisessä blogientryssä muodostettu kuva ja värin muodostus on tehty muodostamalla RGB-väriarvo iteraatioiden määrästä hyväksi todetulla (hihasta vedetyllä) pienellä matemaattisella operaatiolla. Lisäksi, koska iteraatiota ei haluta tehdä äärettömään asti, on ohjelmanpätkässä määritelty maksimi iteraatioiden määrä max_iter, jonka jälkeen tulkitaan pisteen kuuluvan joukkoon.