LOVE Mandelbrot!

djmzu2qwsaelippIl frattale di Mandelbrot ha sempre il suo fascino, combinando infinita complessità geometrica con estrema semplicità dell’algoritmo per realizzarlo. Se non l’avete mai incontrato, approfonditelo, come tutta la questione dei frattali e della teoria del caos. Tra le altre cose, lo considero un buon test per fare pratica su un nuovo linguaggio di programmazione.

Eccone una versione programmata tramite LOVE, ambiente “ultraleggero” per lo sviluppo di “giochini”, che impiega il linguaggio di programmazione Lua. Di entrambi ho parlato in un recente post.

Mi hanno sorpreso la facilità di realizzazione e anche la velocità di esecuzione. Che dire, molta resa con poca spesa!

Si può variare la mappa di colori in base alla propria fantasia, da un “serio” bianco e nero a variazioni più sgargianti, come ho provato a fare. Possibili evoluzioni potrebbero essere un “navigatore”, che tramite il mouse consenta di ingrandire parti a scelta, oppure un “Julia set”, che, cliccando in un punto, consenta di disegnare il frattale di Julia collegato. Realizzai entrambe le cose alcuni anni fa, con C++ assieme alle librerie SDL per la grafica e l’interfaccia con il mouse… forse un giorno li ripescherò. All’epoca utilizzavo quasi esclusivamente Linux. Tra l’altro SDL è la libreria che implementa anche LOVE.

Sono solo un programmatore hobbistico per cui, se qualcuno un po’ più esperto ha miglioramenti o estensioni da proporre, è il benvenuto!

-- Dimensioni finestra grafica
xmax = 800
ymax = 600

-- Angolo del frattale
left = -2
top = -1
-- Dimensioni "fisiche" frattale
xside = 3.0
yside = 2.0

-- "Sfasamento" per migliorare la grafica
eps = 1e-3
left = left-eps
top = top-eps

love.window.setMode(xmax, ymax)

-- max cicli
countend = 256

xscale = xside/xmax
yscale = yside/ymax

function love.draw()
    for x=1,xmax do
        cx = x * xscale + left
        for y=1,ymax do
            cy = y * yscale + top
            cc = 0
            zx = 0.0
            zy = 0.0
            while ((zx*zx+zy*zy < 4) and (cc < countend)) do
                tempx = zx*zx - zy*zy + cx
                zy = 2*zx*zy + cy
                zx = tempx
                cc = cc+1
            end
            ccolor = cc/countend
            love.graphics.setColor(zx/2, zy/2, ccolor)
            love.graphics.points(x, y)
        end
    end
    -- Riduce carico processore
    love.timer.sleep(2)
end


Annunci

Programmare leggeri

provaSpecchio

È tanto che non scrivo di programmazione dei computer.

Da poco ho ripreso a trastullarmi, talvolta, con C++ e Java, tuttavia il tempo è sempre tiranno e, per di più, non riesco a concentrarmi su progetti complessi. Finisco per vagare e, magari, imparare qualcosa. Ultimamente, mi sono innamorato di una soluzione ultraleggera e aperta (nel senso di “open source”) che però consente di fare un sacco di cose. In un’epoca in cui gli ambienti di programmazione, anche quelli open-source, sono dei titanici mastodonti, qualcosa di leggero e “portatile” mi attira, mi sembra razionale e proporzionato a quello che è un semplice hobby. La “suite” che provo a mettere insieme è composta da:

TCC Tiny C Compiler: il più leggero tra i compilatori C completi. Copre tutte le funzionalità standard del linguaggio e anche qualcosa in più, è piccolo, compila a tempo di record e genera eseguibili efficienti (anche se non iper-ottimizzati) e di dimensioni davvero minuscole.

Lua: linguaggio di scripting veloce, semplice ed elegante. Lo trovo ancora più facile e immediato di Python e similmente efficiente.

LÖVE: ambiente grafico 2d che incorpora Lua e dà accesso a audio, mouse, immagini ecc… Nasce per i giochi ma ci si può divertire anche in altre direzioni.

Il tutto composto da codice aperto e aggiornato, che occupa, inclusi accessori non indispensabili, poche decine di Mb e, abbinato al vostro editor di testo preferito (nel mio caso Notepad++) consente di fare, se non tutto, moltissimo. Se volete, buon divertimento!

Silly Python testing


Decollo!Python è un linguaggio di programmazione molto diffuso, soprattutto in ambiente Linux. E’ considerato facile da imparare e potente nell’utilizzo. E’ spesso criticato per la scarsa velocità, anche se poi molti tecnici e scienziati lo adoperano. Mi sono divertito a fare qualche test, ispirandomi ad un “benchmark” pubblicato sul sito di un compilatore Basic, un po’ insensato ma facile da capire e realizzare, un semplice ciclo ripetuto milioni di volte in cui sono eseguite alcune funzioni matematiche. Come riferimento è certamente criticabile. Eccone qua la prima versione.

import math 
import time 
 
starttime = time.time() 
 
Y = .5 
I=0 
for I in range(50000000): 
# while I < 50000000: 
    Y = Y / 1.1234 
    Y = Y * 1.1234 
    X = math.acos(Y) 
    X = math.asin(Y) 
    X = math.atan(Y) 
    X = math.cos(Y) 
    X = math.exp(Y) 
    X = math.log(Y) 
    X = math.sin(Y) 
    X = math.sqrt(Y) 
    X = math.tan(Y) 
 
print(X, " ", Y) 
 
print("Elapsed time = ", time.time() - starttime, " seconds")

 

Sul mio vecchio desktop con Python 2.6 ed Ubuntu 10.04 LTS il tempo di esecuzione è stato di circa 235 secondi. Niente di eccezionale ma neanche tragico, circa dieci volte il tempo ottenuto con compilatori utilizzati senza richiamare ottimizzazioni, mi sembra che per un linguaggio interpretato ci possa stare.

Ho poi trovato questa pagina web che spiega come ottimizzare gli “script” Python. Per prima cosa ho raccolto tutte le operazioni in una subroutine, in modo da utilizzare variabili locali:

 

import math 
import time 
 
def calc(): 
    Y = .5 
    for I in range(50000000): 
        Y = Y / 1.1234 
        Y = Y * 1.1234 
        X = math.acos(Y) 
        X = math.asin(Y) 
        X = math.atan(Y) 
        X = math.cos(Y) 
        X = math.exp(Y) 
        X = math.log(Y) 
        X = math.sin(Y) 
        X = math.sqrt(Y) 
        X = math.tan(Y) 
         
    return X 
 
# MAIN 
starttime = time.time() 
XX = calc() 
print(XX) 
print("Elapsed time = ", time.time() - starttime, " seconds")

 
Il tempo di esecuzione è “crollato” a168 secondi. Un guadagno di quasi il 30% con pochissimo sforzo! Ho poi tentato un’altra operazione suggerita: eliminare la “dot notation” rendendo locali anche le funzioni di libreria “invocate” molte volte.

 
import math 
import time 
 
def calc(): 
    acos = math.acos 
    asin = math.sin 
    atan = math.tan 
    cos = math.cos 
    exp = math.exp 
    log = math.log 
    sin = math.sin 
    sqrt = math.sqrt 
    tan = math.tan 
    Y = .5 
    for I in range(50000000): 
        Y = Y / 1.1234 
        Y = Y * 1.1234 
        X = acos(Y) 
        X = asin(Y) 
        X = atan(Y) 
        X = cos(Y) 
        X = exp(Y) 
        X = log(Y) 
        X = sin(Y) 
        X = sqrt(Y) 
        X = tan(Y) 
         
    return X 
 
# MAIN 
starttime = time.time() 
XX = calc() 
print(XX) 
print("Elapsed time = ", time.time() - starttime, " seconds")

 

Come si vede questa operazione è più macchinosa, ma il guadagno c’è, anche se non drammatico come nel caso precedente: 143 secondi di tempo totale.

Poi ho scoperto l’ “arma totale” per il Python, almeno se si vogliono fare solo calcoli: con il Pypy, “just in time compiler”, i tempi crollano a 34 secondi per la prima versione del test ed a 27 per l’ultima.

Che siano pochi o molti, in assoluto, non lo so, ma i risultati mi hanno colpito. La morale mi sembra che bisogna fare le cose in modo corretto prima di dare giudizi, e forse non solo in informatica.