• Regolamento Macrocategoria DEV
    Prima di aprire un topic nella Macrocategoria DEV, è bene leggerne il suo regolamento. Sei un'azienda o un hosting/provider? Qui sono anche contenute informazioni per collaborare con Sciax2 ed ottenere l'accredito nella nostra community!

Guida La Memoizzazione

Dvdxseo

Redattore Onorario
Autore del topic
Redattore
User Legend
27 Maggio 2008
5.522
158
Miglior risposta
0
La memoizzazione, per quanto il computer e forse anche l'accademia della crusca la segnino come una parola sbagliata, è in realtà una tecnica di programmazione che spesso può salvare la vita di un programma e risparmiare tanto lavoro inutile al processore (con conseguente risparmio di qualche milione di anni di tempo di calcolo).

Consideriamo l'algoritmo ricorsivo classico (qui riportato in C per semplicità (???)) per il calcolo dell'n-esimo numero di
Perfavore, Entra oppure Registrati per vedere i Link!
che discende direttamente dalla definizione della successione:
C:
Perfavore, Entra oppure Registrati per vedere i codici!
Un algoritmo senz'altro molto elegante e compatto, ma che cela al suo interno un odiosissimo dettaglio: il numero di chiamate ricorsive effettuate da questa funzione cresce insieme al valore di n, risultando così (e tralasciando i dettagli da informatica teorica) in un algoritmo pienamente esponenziale, che richiede tempo
png.latex
(per esempio la chiamata a fibonacci(1) viene fatta proprio
png.latex
volte). Come ci possiamo salvare quindi da questa nefasta sciagura che si abbatte inesorabilmente su chiunque abbia mai provato almeno una volta ad implementare un algoritmo per il calcolo dei numeri di Fibonacci? Con la memoizzazione.

In pratica questa tecnica si basa su un'idea molto banale e cioè quella che se si è già calcolato un risultato, questo non deve essere più ricalcolato ma salvato. Ecco quindi che ci basta introdurre un array in cui salviamo i risultati via via che li calcoliamo per tornare di nuovo nel paradiso degli algoritmi polinomiali, con un tempo pari a
png.latex
:
C:
Perfavore, Entra oppure Registrati per vedere i codici!
(L'array è globale ma si potrebbe anche dichiarare static all'interno della funzione)
Ed ecco qui la nostra funzione memoizzata e più veloce rispetto all'algoritmo precedente. L'obiezione adesso è che usiamo anche
png.latex
spazio, e infatti nella versione definitiva uno potrebbe limitarsi a salvare in due variabili temporanee i valori di fibonacci(n-1) e fibonacci(n-2) per ottenere spazio costante, ma questo non ha a che vedere con la memoizzazione in sé, il cui effetto è principalmente sul tempo di esecuzione e in base a cui l'algoritmo appena visto è perfetto.

Concludo dicendo che nei linguaggi che trattano le funzioni come "cittadini di prima classe" o "di serie A" è possibile costruire meccanicamente funzioni memoizzate tramite una funzione memoize(f) che prende in input la funzione da memoizzare e resituisce una nuova funzione che funzionerà più o meno come quella per il calcolo del numero di Fibonacci (cioè calcola una sola volta i valori e quando essi siano già stati calcolati vengono subito restituiti). Uno pseudo-codice per la funzione memoize() si può trovare nella
Perfavore, Entra oppure Registrati per vedere i Link!
relativa alla memoizzazione.
 
  • Like
Reactions: sant0 and Matheeus
Ammetto che inizialmente ho pensato che avessi sbagliato a scrivere il titolo del topic... :emoji_relieved:

Comunque la memoizzazione è molto interessante, ma non sarebbe riconducibile in pratica una sorta di "caching" dei valori già ottenuti? A proposito...

linguaggi che trattano le funzioni come "cittadini di prima classe" o "di serie A"

Che significa? Non sapevo di ciò...
 
Ammetto che inizialmente ho pensato che avessi sbagliato a scrivere il titolo del topic… :emoji_relieved:
Per l'appunto, anche io sono all'oscuro dei motivi che hanno portato a chiamarla così, ma tant'è: almeno ce la ricordiamo bene :emoji_laughing:

Comunque la memoizzazione è molto interessante, ma non sarebbe riconducibile in pratica una sorta di "caching" dei valori già ottenuti?
Per l'appunto funziona come una cache, molto semplice e niente di così fuori dal mondo come suggerirebbe il nome… ma alla fine le cose semplici spesso portano a grandi risultati. :P

L'esempio con Fibonacci può apparire un po' fine a sé stesso, ma la memoization è alla fine alla base anche della programmazione dinamica, per esempio, con cui si possono risolvere in maniera interessante un po' di problemi (allineamento di sequenze, Longest Common Subsequence ecc..)

linguaggi che trattano le funzioni come "cittadini di prima classe" o "di serie A"
Che significa? Non sapevo di ciò…
Il modo in cui l'ho scritto è molto informale, lo riconosco: sono linguaggi dotati di funzioni di ordine superiore e cioè linguaggi che considerano le funzioni come "tipi" che quindi si possono passare ad altre funzioni. Banalmente il C lo consente, tramite il puntatore alla funzione, oppure lo consentono tutti i linguaggi funzionali come F#, ML, Lisp et simila.
In altre parole tu ricevi una funzione come parametro di un'altra funzione e la puoi applicare all'interno di quest'ultima. :emoji_slight_smile:
 
  • Like
Reactions: Matheeus
La parola memoizzazione deriva da memo, ovvero ricordarsi di un valore per poterlo ricordare successivamente.

Introduction to Algorithms, 3rd Edition, pag. 365

Per il resto è sempre un bene che se ne parli, troppo spesso è una tecnica che viene dimenticata, me per primo. Oltretutto si può ridurre ulteriormente la complessità a O(lgn) usando somma e prodotto di matrici.

Di fatto, però, non vorrei che dal punto di vista pratico possano trarne vantaggio solo i linguaggi che lavorano nativamente con matrici, tipo R o MATLAB.
 
  • Like
Reactions: Matheeus
Per il resto è sempre un bene che se ne parli, troppo spesso è una tecnica che viene dimenticata, me per primo. Oltretutto si può ridurre ulteriormente la complessità a O(lgn) usando somma e prodotto di matrici.

Di fatto, però, non vorrei che dal punto di vista pratico possano trarne vantaggio solo i linguaggi che lavorano nativamente con matrici, tipo R o MATLAB.
Non proprio logaritmica: giusto per fare i pignoli, per calcolare l'n-esimo numero ti serve
gif.latex
tempo solo per scrivere il risultato, perché questo è lungo circa
gif.latex
cifre decimali (e poche più cifre binarie). In realtà usando le matrici si può arrivare a complessità
gif.latex
dove M(n) è la complessità di una moltiplicazione tra due numeri di n cifre. E siccome il miglior algoritmo conosciuto finora per la moltiplicazione usa tempo
png.latex
la complessità minima che si può raggiungere, per ora, è questa (dove il log* è il logaritmo iterato). (
Perfavore, Entra oppure Registrati per vedere i Link!
)


Per quanto riguarda i linguaggi che possono trarne vantaggio non saprei, potrebbe dipendere molto da come vengono salvate le matrici in memoria e da come vengono scorse, forse R o MATLAB hanno già delle ottimizzazioni al loro interno, ma credo che lavorando a basso livello in C/C++ o simili si possa riuscire a tirare fuori qualcosa di molto buono comunque!
 
Non proprio logaritmica: giusto per fare i pignoli, per calcolare l'n-esimo numero ti serve
gif.latex
tempo solo per scrivere il risultato, perché questo è lungo circa
gif.latex
cifre decimali (e poche più cifre binarie). In realtà usando le matrici si può arrivare a complessità
gif.latex
dove M(n) è la complessità di una moltiplicazione tra due numeri di n cifre. E siccome il miglior algoritmo conosciuto finora per la moltiplicazione usa tempo
png.latex
la complessità minima che si può raggiungere, per ora, è questa (dove il log* è il logaritmo iterato). (
Perfavore, Entra oppure Registrati per vedere i Link!
)


Per quanto riguarda i linguaggi che possono trarne vantaggio non saprei, potrebbe dipendere molto da come vengono salvate le matrici in memoria e da come vengono scorse, forse R o MATLAB hanno già delle ottimizzazioni al loro interno, ma credo che lavorando a basso livello in C/C++ o simili si possa riuscire a tirare fuori qualcosa di molto buono comunque!
Quello che dicevo era lasciato come esercizio intermedio proprio in Introduction to Algorithms, credo che quando avrò del tempo proverò a farli proprio per verificarlo. Inoltre ottimo avere anche la fonte, mi farà sicuramente piacere leggermela con più calma. :emoji_thumbsup:
 
  • Like
Reactions: Matheeus
Quello che dicevo era lasciato come esercizio intermedio proprio in Introduction to Algorithms, credo che quando avrò del tempo proverò a farli proprio per verificarlo. Inoltre ottimo avere anche la fonte, mi farà sicuramente piacere leggermela con più calma. :emoji_thumbsup:
Se lo dice Tomas H. Cormen allora bisogna fidarsi! Probabilmente c'è qualcosa di logaritmico in tutto questo, oppure intende considerare le operazioni come se avessero costo costante e quindi effettivamente si arriva a O(log n). :emoji_slight_smile:
 
  • Like
Reactions: Matheeus