Tässä blogissa esitellään matematiikkaa visuaalisesti ja tee-se-itse-periaatteella. Tämä tarkoittaa sitä, että kaikki asiat esitetään matematiikan (joskus puisevaksi haukutun) kielen lisäksi kuvina. Kaikkiin kuviin sekä matematiikan konsepteihin annetaan myös python-ohjelmointikieliset koodit, jolla lukija voi itsekin luoda kuvia ja kokeilla miten asiat toimivat käytännössä. Pääaiheita ovat fraktaalit, kaaos ja 3d-grafiikka, jotka kaikki ovat helposti visualisoitavia aiheita, mutta samalla sisältävät asioita monilta matematiikan eri aloilta. Kaikissa näissä aiheissa alkuun pääsee helposti, mutta syvemmälle mentäessä aiheista löytyy yhä monimutkaisempia ja matemaattisesti haastavampia puolia.

lauantai 10. syyskuuta 2011

Julian joukko

Julian joukko hyvin samankaltainen kuin Mandelbrotin joukko, mutta Julian joukossa iterointi aloitetaankin tarkasteltavasta kompleksitason pisteestä z[0] = c, jossa c = x + iy. Iteroitavana funktiona on nyt z[n+1] = z[n]^2 + b, jossa b on jokin vapaasti valittava kompleksilukuvakio. Muutoin joukon määritelmä on täysin sama kuin Mandelbrotin joukon, eli piste c kuuluu joukkoon jos iteraatio ei mene äärettömään (ts. sen itseisarvo ei ylitä lukua 2).

Alla on esitettynä Julian joukko vakioparametrilla b = -0.8 + 0.156i (tai -0.8 + 0.156j Pythonin notaatiolla):





















Koodi kuvan tuottamiseen on tällainen:

from Tkinter import Tk, PhotoImage, Label
from math import *

def main():
    root = Tk()
    pic = PhotoImage(width=400, height=400)
    lbl = Label(root, image=pic)
    lbl.pack()
    root.update()

    b = -0.8 + 0.156j
    max_iter = 1000

    for y in range(pic.height()):
        for x in range(pic.width()):

            xs = 3.0 * x / pic.width() - 1.5
            ys = 3.0 * y / pic.height() - 1.5

            z = xs + ys*1j
            n = 0
            while n < max_iter and abs(z) <= 2:
                z = z**2 + b
                n = n + 1

            if n == max_iter:
                (red,green,blue) = (0,0,0)
            else:
                (red,green,blue) = (n,2*n,3*n + 150)

            color = "#%02x%02x%02x" % (red % 256, green % 256, blue % 256)

            pic.put(color, (x,y))

        root.update()
    root.mainloop()

main()

perjantai 2. syyskuuta 2011

Mandelbrotin joukon teoria

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.

tiistai 30. elokuuta 2011

Mandelbrotin joukon visualisointi Pythonilla

Yksi visuaalisesti kauneimpia matemattisia kuvioita ovat fraktaalit, joista tunnetuin lienee Mandelbrotin joukko, joka näyttää tältä:


Yllä oleva fraktaalikuvio on niin yleinen, että lukija saattaa olla törmännyt tähän aiemminkin. Tässä blogissa pääaiheena ovat fraktaalit, joita on helppo visualisoida ja ohjelmoida, mutta joihin sisältyy hyvinkin syvällistä ja abstraktia matemaatiikkaa.

Yksi syy omaan kiinnostukseeni matematiikkaan ovat juurikin fraktaalit, joita piirtelin joskus 90-luvun alussa ensi fractint-ohjelmistolla ja sen jälkeen ohjelmoimalla itse pascal- ja C-kielillä. Silloin muinoin fraktaaleja vielä piirreltiin VGA-grafiikalla kirjoittamalla pikselien värejä suoraan näyttömuistiin, mutta nykyään käyttöjärjestelmät ja ohjelmointikielet ovat sen verran kehittyneet eteenpäin, että näin rautatason koodaukseen ei ole tarvetta. Aiemmin ohjelmointikielissä ei myöskään ollut valmiina kompleksilukuja, joita tarvitaan monien fraktaalien piirtämisessä, mutta nykyään ne löytyvät valmiina melkein kaikista ohjelmointikielistä.

Sellainen huonokin puoli systeemien kehityksessä kyllä on, että enää ei voi vaan tekstimoodia vaihtaa graafiseksi ja sen jälkeen piirrellä pisteitä näytölle, vaan ensin pitää avata grafiikkakirjasto, avata ikkuna, kenties tehdä muita valmisteluja ja vasta tämän jälkeen voi näytölle piirrellä. Kuitenkin python-kielen Tk-kirjasto tarjoaa varsin yksinkertaisen tavan piirrellä pikseligrafiikkaa ikkunaan.

Esimerkiksi ylläoleva Mandelbrotin joukon kuva on tuotettu seuraavalla ohjelmakoodilla:
# Asenna ensin python-tulkki taalta: http://www.python.org/
# Talleta koodi tiedostoon nimelta mandel1_tk.py ja aja komennolla
# python mandel1_tk.py
from Tkinter import Tk, PhotoImage, Label
from math import *

def main():
    root = Tk()
    pic = PhotoImage(width=400, height=400)
    lbl = Label(root, image=pic)
    lbl.pack()
    root.update()

    max_iter = 1000
    for y in range(pic.height()):
        for x in range(pic.width()):

            xs = 2.0 * x / pic.width() - 1.5
            ys = 2.0 * y / pic.height() - 1.0

            c = xs + ys*1j
            z = 0
            n = 0
            while n < max_iter and abs(z) <= 2:
                z = z**2 + c
                n = n + 1

            if n == max_iter:
                (red,green,blue) = (0,0,0)
            else:
                (red,green,blue) = (n,2*n,3*n + 150)

            color = "#%02x%02x%02x" % (red % 256, green % 256, blue % 256)

            pic.put(color, (x,y))

        root.update()
    root.mainloop()

main()

Tämän Mandelbrotin joukon tuottamiseen liittyvään matematiikkaan mennään syvemmälle seuraavalla blogipostauksessa.