Informatica Applicata

Transcript

Informatica Applicata
Informatica Applicata
Algoritmi Evolutivi
Laurea In Informatica Applicata
Università degli studi di Pisa
A.A. 2003/2004
Laboratorio di Algoritmi Evolutivi
Autori: Dario Maggiari & Giorgio Montali
Introduzione
Il progetto di implementazione e sviluppo di un Algoritmo Genetico,
pone come obiettivo
principale lo studio di problemi di massimizzazione e minimizzazione di funzioni matematiche.
Lo scopo principale del funzionamento dell’algoritmo evolutivo, non è esclusivamente quello di
ottenere una soluzione ottima, ma piuttosto di studiare l’implementazione attraverso un linguaggio
orientato ad oggetti, quale Java, e approcciare in modo sistematico gli strumenti di ricerca nel
campo degli algoritmi evolutivi.
Il documento presentato è suddiviso nelle seguenti sezioni:

Descrizione del funzionamento e dell’implementazione degli operatori genetici.

Presentazione delle funzioni analizzate.

Risultati sperimentali: prove ed analisi.

Conclusioni.
1. Descrizione del funzionamento e dell’implementazione degli operatori genetici
1.1 Presentazione delle classi Java implementate
Le classi implementate sono le seguenti:
1. Classe Chromosome.
La classe Chromosome implementa l’oggetto cromosoma contenente le informazioni
genetiche necessarie al funzionamento dell’algoritmo, codificate in stringhe binarie di bit.
In questa classe sono implementati i metodi necessari a costruire casualmente i cromosomi
più adatti in relazione alle funzioni matematiche, nonché un metodo di decodifica della
stringa di bit in un numero reale. La classe presenta inoltre metodi utili a reperire
informazioni sul cromosoma stesso.
2. Classe Individual
La classe Individual mantiene tutte le informazioni relative ad un individuo di una
popolazione. Contiene il Cromosoma, il valore decodificato dello stesso, il valore di fitness
e tiene traccia delle informazioni evolutive relative all’individuo nelle varie generazioni.
3. Classe Population
La classe Population implementa tutto ciò che riguarda l’effettivo funzionamento
dell’algoritmo di ricerca.
Qui sono definiti i metodi di inizializzazione della popolazione, di selezione, di crossover e
di mutazione. Inoltre sono stati implementati alcuni metodi di utilità relativi al calcolo delle
statistiche delle generazioni nonché i metodi di stampa su file che mostrano il procedere
dell’algoritmo.
1.2 Funzionamento globale del GAS
Gli algoritmi evolutivi, come noto, utilizzano tre operatori principali:
• Operatore di selezione.
• Operatore di mutazione.
• Operatore di crossover.
Come primo passo la popolazione viene creata in modo (pseudo)casuale con la generazione di
stringhe adatte alla funzione da ottimizzare.
Successivamente è il primo operatore che si occupa di analizzare e selezionare gli individui più
adatti alla sopravvivenza.
Gli operatori di selezione che sono stati implementati sono i seguenti:
✔
Operatore di selezione basato sul metodo della Roulette.
Questo operatore effettua una ricerca globale sull’intera popolazione e assegna ad ogni individuo la
probabilità di sopravvivenza calcolata come:
fitness_individuo / fitness_totale
Dopodiché si seleziona con probabilità precedentemente assegnata un individuo della popolazione
che verrà poi utilizzato per il crossover.
In questo modo saranno selezionati gli individui con probabilità più alta che andranno a combinarsi
con altri individui presumibilmente con buona fitness.
VANTAGGI:
•
Semplicità di programmazione.
•
Semplicità computazionale.
•
Adattabilità ad ogni tipo di problema.
SVANTAGGI:
•
✔
Convergenza non assicurata (convergenza prematura e stagnazione).
Operatore di selezione con Torneo.
Questo operatore seleziona un certo numero di individui della popolazione e li confronta tra loro
restituendo il migliore tra essi. Permette una vastissima gamma di scelte implementative in
relazione al tipo di problema da ottimizzare.
Su una popolazione di 30 individui, ad esempio, se si selezionano 8 individui da raffrontare, con un
semplice calcolo probabilistico si noterà che in questo modo si avrà una probabilità di circa 84% di
selezionare almeno un individuo tra i migliori 6 dell’intera popolazione. A seconda del problema
che si intende risolvere/ottimizzare occorrerà decidere se aumentare o diminuire il numero di
individui da raffrontare che conseguentemente aumenterà o diminuirà la probabilità di ottenere
individui con fitness migliore.
VANTAGGI:
•
Scalabilità.
•
Buona funzionalità in termini di selezione degli individui migliori.
•
Bassa probabilità di stagnazione.
SVANTAGGI:
•
Convergenza non assicurata (convergenza prematura).
✔
Operatore di selezione d’Elite.
L’operatore di selezione d’Elite è un operatore che viene applicato sulla nuova generazione dopo
che gli altri operatori (selezione con Roulette o Torneo, Crossover e Mutazione) hanno già lavorato.
La selezione d’Elite si preoccupa di analizzare le fitness degli individui appena creati, in modo tale
da sostituire l’individuo peggiore con una copia del migliore della popolazione precedente.
VANTAGGI:
•
Sempre applicabile.
•
Convergenza assicurata.
SVANTAGGI:
•
In particolari casi soffre di stagnazione su valori prossimi ad una buona
soluzione.
Dopo l’operatore di selezione, l’algoritmo evolutivo procede con l’operatore di crossover, il quale
richiama al suo interno l’operatore di mutazione.
✔
Operatore di mutazione.
L’operatore di mutazione muta ciascun allele di ogni cromosoma in modo indipendente
con probabilità assegnata.
✔
Operatore di crossover.
L’operatore
di
crossover
combina
con
probabilità
assegnata
due
individui
precedentemente selezionati. Quindi genera un taglio casuale sul cromosoma e combina i
due cromosomi incrociandone gli alleli, ottenendo
nuovi individui (crossover one-
point). A seconda delle funzioni studiate sono stati implementati diversi operatori di
crossover per risolvere problemi di dimensione nella rappresentazione delle variabili
(parte intera e parte decimale) delle funzioni e per risolvere problemi di decisione del
segno algebrico.
2. Presentazione delle funzioni analizzate
Per testare il funzionamento dell’algoritmo sono state studiate 5 diverse funzioni matematiche che
sono state implementate nella classe ObjectiveFunction. Due di queste funzioni necessitano di
essere massimizzate, mentre le altre tre presentano un problema di minimizzazione.
2.1 Funzione presentata da Goldberg: f(x) = (x/c)10 (Problema di Massimizzazione)
Per lo studio di tale funzione la variabile x assume valori interi tra 0 e 230, mentre la costante di
normalizzazione c assume valore 1.073.741.823.
La massimizzazione di questa funzione non presenta né problemi di rappresentazione numerica
né particolari problemi di ricerca del massimo valore. La costante di normalizzazione è inserita
per verificare sperimentalmente il raggiungimento dell’ottimo che assume valore 1.
2.2 Funzione f(x) = x2 (Problema di Massimizzazione)
Per lo studio di tale funzione la variabile x assume valori interi tra 0 e 1.000.000. Questa
funzione è stata utilizzata per effettuare test su problematiche relative alla rappresentazione
binaria dei cromosomi e per verificare il corretto funzionamento dei vari operatori di selezione e
dell’operatore di crossover. L'ottimo di questa funzione, come logico, è posto in 1.000.000.
2.3 Prima Funzione di De Jong: f(xi) = ∑3i = 1 x2i (Problema di Minimizzazione)
Per lo studio di tale funzione la variabile x assume valori reali tra –5,12 e 5,12. La
rappresentazione binaria di tali valori è stata implementata codificando separatamente (…ma nel
solito cromosoma…) la parte intera e la parte decimale. Per la parte intera sono stati utilizzati 3
bits, mentre per la parte decimale ne sono stati utilizzati 7. La decodifica della stringa a valore
reale è stata effettuata decodificando la parte intera alla quale è stata sommata la centesima parte
della decodifica della parte decimale. A differenza delle precedenti funzioni si è dovuto tenere
conto del segno algebrico nel calcolo dell’ottimo (assunto in –15,36). Per questo motivo la
decodifica e i controlli dei valori delle stringhe binarie sono molteplici. Uno di questi è
l’assegnamento del segno ad un nuovo individuo creato dal Crossover (la prima popolazione
presenta individui con segno casuale). Dato che la funzione è composta di 3 variabili
indipendenti accorre verificare su quale variabile cade il taglio del crossover. Quindi occorre
verificare, per ogni individuo partecipante al crossover, il segno della variabile interessata dal
taglio e assegnare il segno ai nuovi individui creati secondo una logica dipendente dalla
tipologia del problema. In questo caso poiché si tratta di determinare un minimo a segno
negativo, la regola di assegnamento del segno è visualizzata in TAB1:
TAB1
SEGNO VAR 1° INDIVIDUO SEGNO VAR. 2° INDIVIDUO
Positivo
Positivo
Positivo
Negativo
Negativo
Positivo
Negativo
Negativo
SEGNO VAR. FIGLI
Negativo
Positivo
Positivo
Negativo
2.4 Funzione di Rosembrok: f(x, y) = (1 – x)2 + 105(y – x2)2 (Problema di Minimizzazione)
Per lo studio di tale funzione la variabile x assume valori reali tra –5,42 e 5,42. La
rappresentazione binaria di tali valori è stata implementata codificando separatamente (…ma nel
solito cromosoma…) la parte intera e la parte decimale. Per la parte intera sono stati utilizzati 3
bits, mentre per la parte decimale ne sono stati utilizzati 7. La decodifica della stringa avviene
come nella funzione precedente. L’ottimo di questa funzione si ha nel punto (1,1).
Per la decisione dei segni vedere TAB2:
TAB2
SEGNO VAR 1° INDIVIDUO SEGNO VAR. 2° INDIVIDUO
Positivo
Positivo
Positivo
Negativo
Negativo
Positivo
Negativo
Negativo
SEGNO VAR. FIGLI
Positivo
Negativo
Negativo
Positivo
2.5 Seconda Funzione di De Jong: f(x, y) = 100(x2 – y)2 + (1 –x)2 (Problema di minimo)
Per lo studio di tale funzione la variabile x assume valori reali tra –2,048 e 2,048. La
rappresentazione binaria di tali valori è stata implementata codificando separatamente (…ma nel
solito cromosoma…) la parte intera e la parte decimale. Per la parte intera sono stati utilizzati 2
bits, mentre per la parte decimale ne sono stati utilizzati 10. La decodifica della stringa avviene
come nella funzione precedente a differenza che contiene tripla precisione decimale. L’ottimo di
questa funzione, come nella funzione di Rosembrok, si trova nel punto (1,1). Per la decisione
dei segni vedere TAB2.
3. Risultati sperimentali: prove ed analisi
L’analisi del funzionamento dell’algoritmo evolutivo è stata effettuata attraverso numerosissime
prove eseguite su tutte le funzioni e modificando più volte gli operatori che intervengono
nell’algoritmo genetico fino ad ottenere un’implementazione molto buona in termini di
convergenza. Per ogni funzione sono stati implementati diversi tipi di crossover in relazione alle
caratteristiche della funzione stessa. Fra gli operatori di selezione si è deciso di utilizzare la
“Selezione con torneo”, anziché la “Selezione con Roulette”, dato che i numerosi test hanno
evidenziato un miglior comportamento in termini di ricerca degli individui migliori. L’operatore che
implementa la
“Selezione d’Elite” è utilizzabile, come già detto, indipendentemente dal tipo
selezione effettuata, perché lavora sulla popolazione appena generata sostituendo l’individuo
peggiore con una copia del migliore individuo. Si è notato che con l’utilizzo dell’Elite si limitano le
oscillazioni della fitness e si velocizza il processo di ottimizzazione, soprattutto per la funzioni di
Rosembrok e la seconda di DeJong. Presentiamo, di seguito, una breve analisi dei risultati
dell’algoritmo applicato alle varie funzioni.
Per ogni funzione studiata sono state effettuate 10 prove indipendenti su un campione di 30
individui con Probabilità di crossover posta a 0.6 e Probabilità di mutazione posta a 0.0333 usando
l’operatore di selezione con Torneo.
Funzione presentata da Goldberg: f(x) = (x/c)10 (Problema di Massimizzazione)
Sulle 10 prove effettuate, utilizzando Selezione con Torneo e 30 generazioni,
si raggiunge
SEMPRE il valore ottimo della funzione (pari a 1) a partire all’incirca dalla ventesima generazione
(si nota che già a partire dalla venticinquesima generazione si raggiunge comunque l’ottimo).
Utilizzando la Selezione d’Elite si raggiunge il valore ottimo già dalla quindicesima generazione.
Funzione f(x) = x2 (Problema di Massimizzazione)
I risultati presentati per questa funzione si basano anch’essi su 10 prove con 30 individui e 10
generazioni, utilizzando però la Selezione d’Elite.
La funzione non è così semplice da calcolare come quella precedente ed infatti fornisce risultati che
non sono sempre soddisfacenti. Sotto queste ipotesi, ad una prima analisi, si ha circa il 30-40% dei
casi che stagna su una soluzione prossima all'ottimo (dal punto di vista della codifica binaria); il 2030% che si avvicina molto a questa soluzione e il 30-40% che stagna sempre sul valore
9.66365675521 * 1011 contro il 9.98846332929 * 1011 dell'altro valore.
Analizzando in dettaglio la conformazione dei cromosomi che formano i due risultati si riesce a
capire meglio il comportamento quantomeno anomalo della funzione.
I due valori di stagnazione sono:
9.98846332929 * 1011
rappresentato dalla stringa
11110011111111111111
contro
9.66365675521 * 1011
rappresentato dalla stringa
11101111111111111111
Come si può notare le due stringhe binarie sono molto simili. Per quanto riguarda il valore più
basso, il funzionamento dell’algoritmo è tale che, qualora l’algoritmo generi una stringa della forma
1110[…] e fornisca essa stessa il valore massimo di fitness in un'attuale generazione, difficilmente
si riuscirà a smembrare questa conformazione. Non ci si può infatti affidare molto sul crossover, in
quanto il taglio effettuato è del tutto casuale e quindi la probabilità che vada a cadere sul 3° allele, è
sì equamente distribuita in relazione agli altri possibili tagli, ma diventa molto bassa se si considera
che si deve tagliare in posizione 3 l’individuo giusto (gli individui sono 30, quindi 1/30 = 0,033% di
probabilità di selezionare l'individuo in questione + la probabilità di tagliare in posizione 3). Non
possiamo inoltre affidarci molto neanche sulla mutazione, sempre per lo stesso motivo: dovremmo
infatti sperare che venga mutato il 4° allele del cromosoma. Inoltre, la mutazione non ha addirittura
alcuna possibilità di riuscita nel caso in cui si raggiunga uno dei valori di stagnazione. Infatti, La
loro codifica è tale che necessiterebbe di almeno due mutazioni dello stesso cromosoma: una in
posizione 4 e l'altra in una posizione superiore. Infatti, qualunque cromosoma di questo tipo:
1111*111111111111111
o
11111*11111111111111
viene scartato in fase di controllo perché oltrepassa il range di rappresentazione. Quindi, la
mutazione di questi individui genera un individuo da scartare e la mutazione a “singolo allele”
diventa inutile. Effettuando prove in cui si aumenta la probabilità di mutazione, si può cercare di
risolvere il problema della stagnazione. Portando la percentuale di mutazione al 23%, si elimina
definitivamente la stagnazione su quei valori, ma non si riesce comunque a raggiungere l'ottimo che
dovrebbe essere così codificato:
11110100001001000000 * 1012
Si sono effettuate quindi, 200 prove indipendenti iterando per ognuna fino a 100 generazioni
successive alla prima. Si è visto convergere l'algoritmo solo in 5 occasioni (le generazioni totali
sono 20.000...). Nella sola implementazione di selezione con torneo, i valori variano veramente di
poco, anche perché, lavorando su numeri naturali non si hanno oscillazioni intorno al valore
massimo di fitness che tende sempre e comunque a salire. L'unico dato rilevante è che su 100 prove
non si è osservata alcuna convergenza finale, ma solamente tre risultati ottimi in generazioni
intermedie (convergenza locale), fatto dovuto principalmente al caso (percentuale di mutazione
abbastanza elevata).
Prima Funzione di De Jong: f(xi) = ∑3i = 1 x2i (Problema di Minimizzazione)
Il primo problema di minimizzazione presentato, offre, sotto determinate ipotesi, risultati molto
soddisfacenti in relazione alla codifica effettuata su valori decimali e con segno (si veda la sezione
relativa alla descrizione delle funzioni). I risultati presentati, non si riferiscono al raggiungimento
dell'ottimo, che si attesta sul valore -15,36, ma si basa sul raggiungimento di valori inferiori a
-15,30. Questo è stato fatto perché la decodifica dei valori decimali, fatta con sette bit, nonostante
sia poco significativa nel risultato finale, ha molta influenza sia sul crossover che sulla mutazione
(intuitivamente, il crossover e la mutazione “influiscono poco” sul raggiungimento dell'ottimo dato
che i bit che rappresentano la parte decimale sono molto maggiori rispetto alla parte intera e quindi
il miglioramento è “lento”). Per questo motivo, risulta quantomeno più difficile raggiungere
precisamente il valore ottimo della funzione. Effettuando svariati test sia con Selezione con Torneo
che con selezione d'Elite, con percentuale di mutazione pari a 0.033, si è notato come su 20 prove
indipendenti, effettuate con 30, 50, e 100 generazioni successive alla prima, non si riescano a
raggiungere valori inferiori a -15,30.
Portando la percentuale di mutazione a 0.13, si ha un netto miglioramento:
•
Con Selezione di Elite su 30 generazioni, si ha circa il 50% di convergenza.
•
Su 50 generazioni, si ha circa il 90% di convergenza.
•
Su 100 generazioni, si ha il 100% di convergenza.
Effettuando i test con sola Selezione con Torneo, si ha solamente un leggerissimo calo dei valori,
ma le percentuali rimangono le stesse.
Funzione di Rosembrok: f(x, y) = (1 – x)2 + 105(y – x2)2
(Problema di Minimizzazione)
La funzione di Rosembrok è forse la funzione più difficile di questa serie da calcolare. Mette
insieme, infatti, i problemi di decodifica di valori decimali, i problemi di assegnamento del segno e
gli svariati problemi di ricerca della soluzione che possono interessare gli algoritmi genetici. Mentre
nelle funzioni precedenti, il valore ottimo della fitness corrispondeva anche a ricercare quale fosse il
valore minimo o massimo dei cromosomi corrispondenti alle variabili, in questa funzione, ciò non
accade. Infatti, il valore minimo di questa funzione si ha nel punto (1,1), vale a dire una soluzione
che sta all'incirca a metà del range di ricerca dell'algoritmo che tenta di trovare una soluzione
“pescando” i valori delle variabili tra -5.42 e 5.42. Chiaramente i valori decimali, per la risoluzione
di questa funzione, hanno ben poca influenza, ma si è scelto di inserirli per aumentare lo spazio di
ricerca e per simulare il funzionamento dell'algoritmo nell'ambito dei reali. Per questo si è deciso di
considerare pari all'ottimo tutti quei valori di fitness che pur non raggiungendo lo zero, si attestano
nell'intervallo compreso tra 0.0 e 0.09.
Effettuando i soliti test, con Selezione d'Elite e probabilità di mutazione pari a 0.033, si sono
ottenuti i seguenti risultati:
•
Su 20 prove di 30 generazioni si hanno circa 6 prove convergenti.
•
Su 20 prove di 50 e 100 generazioni si hanno circa 7 prove convergenti.
Dati gli scarsi risultati, si è aumentata la probabilità di mutazione portandola al 13% e effettuando
molteplici test, si sono ottenute le seguenti statistiche:
•
Su 30 generazioni, circa il 55% delle prove converge.
•
Su 50 generazioni, circa 70 – 80%.
•
Su 100 generazioni non si raggiunge il 100% , ma comunque un buon 90% .
In tutti i casi di insuccesso, non si riscontrano comunque particolari casi di stagnazione su
determinati valori, ma, salvo in alcuni rari casi, il valore finale di attesta intorno allo 0.1, quindi
molto vicino comunque allo zero. Nell'implementazione delle prove con sola Selezione con Torneo,
si ha un calo indicativamente del 10% nel raggiungimento dell'ottimo. Ciò è dovuto principalmente
al fatto che l'Elite, per questa funzione è piuttosto importante perché evita le oscillazioni intorno a
valori facilmente creabili dal crossover, ma poco efficienti per quanto riguarda il calcolo della
fitness. Una bassa percentuale di mutazione e una poco attenta implementazione dell'algoritmo nel
calcolo di funzioni quadratiche può portare a stagnazione sul punto (0,0). Ciò accade qualora non si
riesca a scendere a valori di fitness sotto lo zero in tempi abbastanza rapidi. Un bassa percentuale di
mutazione, infatti, andrà ad incidere maggiormente sulla parte decimale della codifica del
cromosoma, modificando così valori poco significativi nella ricerca del punto (1,1).
Seconda Funzione di De Jong: f(x, y) = 100(x2 – y)2 + (1 –x)2 (Problema di minimo)
La seconda funzione di De Jong è del tutto simile alla funzione di Rosembrok. Poteva anche non
essere inserita nello studio del funzionamento dell'algoritmo, ma è stata ugualmente implementata e
testata per verificare la correttezza e la modularità e adattabilità dell'implementazione scelta. Questa
funzione è stata calcolata prevedendo codifica a 3 cifre decimali e una intera. Nelle stesse
condizioni di ricerca della funzione di Rosembrok, i risultati ottenuti sono del tutto analoghi alla
stessa.
4. Conclusioni
4.1 In relazione al funzionamento dell'algoritmo
I buoni risultati ottenuti dai test evidenziano alcune caratteristiche riguardo al funzionamento
dell'algoritmo di ricerca evolutivo, algoritmo regolato dalla probabilità e dalla capacità di
autogestirsi in base, però, a linee guida fornite da operatori esterni, quali l'uomo.
In effetti, nonostante vi sia una indiscussa buona capacità di ricerca, l'algoritmo in sé, può fare ben
poco senza le informazioni base necessarie al suo funzionamento e in particolare, non sa riconoscere
input sbagliati che lo potrebbero portare a ricercare in spazi a volte molto lontani da quello che
dovrebbe essere lo spazio di ricerca ottimale. Ciò che più si è messo in evidenza è la criticità
dell'operatore di selezione. Come si sarà notato, l’operatore di Selezione con Roulette non è mai
stato utilizzato nei test di verifica. Questo è dovuto alla scarsa potenziale denotata in fase primo
sviluppo, quando già dai primi test di funzionamento si è notata la scarsa efficienza dei questo
operatore, che, su popolazioni di già di trenta individui, fatica a trovare gli individui più forti. Molto
probabilmente questo operatore è in grado di lavorare bene solo su piccole popolazioni, in cui è
possibile che la fitness di un individuo sia molto maggiore della fitness degli altri. In questo modo
la probabilità ad esso associata sarà molto più alta e quindi influirà positivamente sulla scelta di
quell'individuo. Su popolazioni di 30 o oltre individui, lo spazio ampio di ricerca, influisce
negativamente sulla scelta degli individui migliori. Molto più efficiente, sotto tutti i punti di vista si
è rivelata la Selezione con Torneo. In primo luogo perché non è condizionata dal numero di
individui che compongono la popolazione; in secondo luogo perché è “regolabile” proprio in
dipendenza di questo numero.
Questo tipo di selezione, è basata anch'essa sulla probabilità, ma è del tutto slegata dalla bontà di
ogni individuo. Alcuni individui vengono infatti selezionati e confrontati tra loro fino a restituire il
migliore di questa selezione. E' proprio il numero di questi individui confrontabili tra loro che
fornisce diverse probabilità di riuscita (vedere la sezione relativa alla descrizione e funzionamento
degli operatori genetici). A supporto di questo tipo di selezione interviene la Selezione d'Elite. Il
suo compito principale è quello di evitare oscillazioni intorno ai valori prossimi all'ottimo, nonché
di perdere proprio il cromosoma ottimo. Rimpiazzando di generazione in generazione l'elemento
peggiore con una copia del migliore della generazione precedente (a meno che un individuo ancora
più “forte” non si già presente...), previene in una certa misura il pericolo di stagnazione su valori
anomali di fitness, velocizza il processo di convergenza e aumenta la capacità di trovare l'ottimo.
L'altro elemento su cui si sono orientati i nostri studi è stata la probabilità di mutazione. Come si sa
una bassa probabilità di mutazione può portare ad una bassa capacità di ricerca, mentre un'alta
percentuale rischia di far fare all'algoritmo una ricerca pressoché casuale.
Come evidenziato dai valori dei test, si ha un'accettabile compromesso ponendo la percentuale al
13%, il che vuol dire, che ogni singolo allele ha questa probabilità di essere mutato indipendente
dagli altri: in totale, su trenta alleli (dimensione di un individuo), ne mutano circa 4. Non sono stati
invece effettuati studi sulla percentuale di crossover, perché, per come è stato implementato
l'operatore, ha poca influenza. Infatti, quello che accade, è che per ogni coppia di individui
selezionati, si ha il 60% di probabilità che questi vengano “crossati”.
In caso contrario, si ripete tutto il processo di selezione. Se questa è implementata con Torneo,
allora molto probabilmente, saranno individui molto simili che parteciperanno al nuovo crossover,
senza pregiudicare più di tanto la ricerca.
4.2 In relazione all'implementazione.
Quello che ancora è degno di nota, riguardo all'implementazione dell'algoritmo, è una breve
descrizione delle potenzialità e limitazioni del codice presentato.
Partendo dalle potenzialità, ciò che più è rilevante è la discreta modularità delle funzioni e
l'adattabilità e modularità sia delle classi che dei metodi implementati.
Le particolari condizioni dei test effettuati, sono solo un esempio dei possibili scenari di circa che
offre l'algoritmo.
Il calcolo e l'implementazione delle funzioni è totalmente staccato dai valori limite di ricerca
imposti. E' possibile infatti, con pochissimi settaggi di valori, ampliare, diminuire, modificare e
potenziare gli spazi di ricerca su cui lavorare e questo per ogni funzione.
E' possibile passare abbastanza facilmente da un problema di massimo ad uno minimo, è possibile
aumentare la precisione in termini di valori decimali o di valori interi, è possibile passare da valori
con segno a naturali e viceversa. Con un po' più di difficoltà si può ampliare il numero di funzioni
calcolabili, in quanto per ognuna occorrerà copiare e modificare opportunamente la funzione di
crossover, in relazione soprattutto al numero di variabili della funzione. E' possibile controllare
direttamente i progressi dell'algoritmo evolutivo al termine della ricerca, in quanto tutti i
cromosomi, i valori codificati, l'individuo massimo e minimo di una popolazione, sono scritti su file
e sono salvati su disco. Inoltre, attraverso particolari parametri, è possibile far calcolare
dall'algoritmo se si è avuta o meno convergenza e a quale generazione è avvenuta.
L'unico difetto di questa parte è che la formattazione del testo non è troppo precisa, ma ugualmente
molto leggibile.
I limiti di questo tipo di implementazione sono legati perlopiù alla decisione di codifica in stringa
binaria della parte decimale dei valori.
Vediamo un esempio numerico:
Nel nostro caso, si sono dovuti implementare numeri come 5,34 o 2,015.
Nel primo esempio, è sempre possibile scrivere 5,34 come 5 + (34/100) e questo è quello che è stato
fatto. Una codifica binari di questo tipo si ottiene con una stringa di 10 bit:
•
3 per la parte intera.
•
7 per la parte decimale.
ricordando che 5 è codificato come 101 e 99 come 1100011.
Quindi, nel procedimento da binari a reali, si sono decodificati i primi 3 bit e li si è sommati alla
decodifica dei secondi 7 bit divisi per 100 (cento).
Ciò che non si è riusciti a gestire troppo bene, anche perché java non supporta funzioni adatte a
questo tipo di lavoro, è il fatto che 7 bit sono “ troppi” per codificare valori tra 0 e 99.
Con 7 bit si oltrepassa il centinaio, e questo è stato controllato solo nell'inizializzazione della prima
popolazione, mentre non si è potuto far niente né in fase di crossover, né tantomeno in fase di
decodifica (che avviene subito dopo il crossover, ma in una sezione di programma indipendente).
Per questo, si è cercato di limitare i problemi dividendo per 1000 (mille) anziché per 100 (cento)
tutti quei valori superiori, appunto, a 100 (cento), per evitare che la parte dedicata ai decimali
generasse anche valori interi. Naturalmente sono stati potenziati i controlli in fase di crossover per
garantire di non generare individui che oltrepassassero i range di valori assumibili dalle variabili
inizialmente stabiliti.
Informatica Applicata
Autori: Dario Maggiari & Giorgio Montali