IncRay

scene001

E’ un bel po’ che non parlo di programmazione di computer, uno degli argomenti annunciati di questo blog. Il motivo è semplice: non mi ci dedico da un bel po’, se non per tempi brevissimi. Vi voglio tuttavia aggiornare sul progetto più ambizioso che ho intrapreso finora, un programma a sviluppo infinito a cui ho fatto procedere, fino ad oggi, una strada a zig-zag: il mio codice di computer-graphic scritto da zero, il mio motore di rendering, il mo orgoglio, IncRay!

Il nome sta per Incident Ray-tracer: tracciamento dei raggi di luce incidenti, la tecnica abituale di ray-tracing. L’idea era di un software lineare, che prediligesse la semplicità alla massima efficienza, e che fosse espandibile. L’obiettivo era di realizzare immagini fotorealistiche (parola grossa) di geometrie semplici, che avessero una chiara rappresentazione matematica. La prima cosa che mi venne in mente erano le sfere: il luogo dei punti equidistanti da un punto dato detto centro (reminiscenze di geometria), poi passare a piani, triangoli e da questi, in teoria, a qualsiasi geometria.

scena000

Aggiungere nel contempo caratteristiche varie: posizione e colore della luce, colore e proprietà delle superfici, posizione ed angolo d’inquadratura del punto di vista, dimensione dell’immagine.

La storia è stata variegata, incoerente e legata al mio bighellonare hobbistico nell’informatica. Sono partito con una versione in Free Pascal puramente procedurale, poi una in Java strutturata ad oggetti ed infine una in C++. Queste ultime due hanno proceduto per un certo tempo in parallelo per poi concentrare gli sforzi sull’ultima: il C++ è per alcuni versi più scomodo, ma più efficiente. Tuttavia ogni versione ha le sue peculiarità, la convergenza delle funzionalità sul C++ non è ancora completa. Ad esempio solo la vecchia versione Pascal può disegnare triangolo, mentre solo in Java ci possono essere superfici a specchio (che mi piacciono molto), mentre solo nell’ “edizione” in C++ è possibile spostare il punto di vista nelle tre dimensioni, funzionalità che rende molto più flessibile e pratico l’utilizzo.

triangoli04

Lo schema di funzionamento è lo stesso. Un file di testo contiene la descrizione della scena; il programma lo legge, calcola le traiettorie dei raggi di luce a ritroso, partendo dal punto di vista (la macchina da presa, per così dire), li interseca con gli oggetti e verifica le interazioni con la sorgente di luce e gli altri oggetti. In base a questo calcola il colore risultante di ogni punto. Alla fine, salva il file immagine complessivo. Nel post ne ho messo qualche esempio.

Ecco la mia struttura “ad oggetti”. Un sistema gerarchico ricollega tutte le “forme” ad una classe “Geom”, piena di funzioni virtuali (linguaggio C++…). “Sphere” è una sottoclasse di “Geom”, così come “Plane”. “Triangle”, a sua volta, è/sarà una sottoclasse di “Plane”. Ci sono poi classi per i tipi base “Vec3” per il vettore a tre componenti, che ha per sottoclassi “Point” e “Color”; “Surface” per le proprietà di superficie.

C’è molto da fare, ma sono relativamente orgoglione di me stesso. Che ve ne pare?

provaSpecchio

Annunci

Basic Tweets

blocchi

Tutti o quasi conoscono le regole di Twitter: massimo 140 caratteri per esprimere un pensiero, uno stato mentale, un concetto.

Mi è venuto in mente di provare a scrivere qualche tweet, possibilmente umoristico, usando la grammatica del vecchio Basic, quello stile “Commodor 64” per chi se lo ricorda. D’altra parte il linguaggio era sintetico e facile da apprendere: io ed altri ragazzini ne andavamo pazzi.

Per questo gioco è importante la perfetta correttezza sintattica, ma l’idea che si porta. Ecco quello che sono riuscito a tirare fuori.

Il più semplice tweet BASIC

10 REM THIS IS A USELESS TWEET

Il tweet BASIC ideale

10 PRINT “A NEW FOLLOWER”
20 GOTO 10

Il tweet BASIC della verità irraggiungibile

10 GOTO 30
20 PRINT “THE ANSWER IS 42”
30 GOTO 10

Il tweet BASIC di Douglas Adams

10 PRINT “THE ANSWER IS 42.”
20 INPUT “WHAT’S THE QUESTION”, Q$
30 END

PS: Per apprezzare gli ultimi due, conviene aver letto “La guida galattica per autostoppisti”.

Tempo di scelte per la scrivania

Ormai mi devo decidere: il mio Linux Ubuntu 10.04 è attempato e bisognoso di aggiornamento. Tocca prendere il toro per le corna, fare un back-up completo e reinstallare tutto.

Nessun aggiornamento: è già tutto troppo caotico, ci vuole un “fresh install”.

Ma che desktop scegliere? E’ una decisione importante, perché è l’aspetto del sistema operativo con cui ti tocca convivere di più. Il desktop te lo trovi davanti appena accendi il computer e te lo tieni finché non ti alzi dalla sedia e te ne vai.

Il problema è che anche i desktop classici di Linux stanno andando verso soluzioni “pesanti”, a furia di aggiungere funzionalità, opzioni, girandole e campanelle: anche la buona vecchia Gnome non è più la stessa. Tutti i programmi vogliono fare tutto e così diventano dei bestioni che solo un main frame di ultima generazione è capace di gestire.

Il mio vecchio desktop (non vecchio come quello della foto…) ha forse bisogno di qualcosa che lo ringiovanisca. Qualcosa che sia pratico per Internet, scrivere e programmare quando ne ho voglia.

Ecco le mie opzioni, più o meno in ordine di “peso”:

  • Unity (Ubuntu) <<< Dal web si direbbe “troppo” per il mio PC.
  • KDE <<< Un po’ pesante… e sembra in recessione come numero di utilizzatori. Ma solida.
  • Xfce  <<< Leggero ma configurabile e sviluppato da molti anni. Mi sto orientando…
  • Lxde <<< Il più leggero (e non è male). Sembra perfetto per il netbook più che per il desktop…

Forse passerò attraverso qualche “live-CD” prima di prendere una decisione.

 

Aggiornamento: alla fine (luglio 2012) ho optato per Mind Debian Edition, con desktop Xfce. Sono moderatamente soddisfatto, o meglio più soddisfatto man mano che lo uso ed imparo a cofigurarlo (non tutto è menu-driven). Debian ha recentemente scelto Xfce come desktop di riferimento. Pare che Gnome 3, oltre ad essere più ingombrante del vecchio Gnome, sia anche poco gradito a molti utenti. Xfce Non è male, ma a mio modo di vedere ha ancora strada da fare prima di essere davvero d’impiego comune. D’altra parte tutto il mondo open source va avanti per tentativi ed aggiustamenti.

Primi numeri

Per me programmare i computer è un’attività simile a quello che per molti sono i giochi enigmistici: un piacevole impegno per la mente, in cui il lavorio per ottenere un risultato è più importante del risultato stesso ed in cui il tempo è una variabile indipendente. Insomma il classico hobby da cui non si pretende di ricavare necessariamente qualcosa di concreto… eppure ci si appassiona molto.

Ho cominciato ad interessarmi ai numeri primi leggendo “L’enigma dei numeri primi”, un libro che ha la tensione di un thriller pur parlando di numeri; ed essendo un tecnico, per me i numeri sono, seppure in maniere un po’ meno astratta, un pane quotidiano.

Mi sono allora impegnato a scrivere qualche programmino per calcolare la serie dei numeri primi. Algoritmi semplici: esaminare i numeri uno dopo l’altro dividendoli per i primi già trovati. mi sono serviti per fare pratica su diversi linguaggi (Basic, Pascal, C, Python…). Sono stato contento quando, sul mio vecchi PC, sono riuscito a tirarne fuori oltre sessantamila in meno di trenta secondi!

Poi mi sono imbattuto nel setaccio di Eratostene. Ho provato ad “implementarlo” e il risultato è stato sorprendente: un secondo o giù di li per arrivare al più grande numero primo che poteva essere contenuto in una variabile intera.

Per un verso ci sono stato male: come matematico sono una vera schifezza. Il vecchio Eratostene di Cirene, dal suo terzo secolo avanti Cristo, mi batte con un solo dito.

Per chi fosse interessato, ecco qualcuno dei miei codici.

>>> CodiciNumeriPrimi <<<

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.