Sei sulla pagina 1di 11

VBJ n.

77 settembre-ottobre 2007

Programmazione Genetica e Strategie di Pianicazione


di Fabio Fabozzi
Sono sempre stato affascinato dallIntelligenza Articiale e dagli Algo` ritmi Genetici. La Programmazione Genetica (PG), e il frutto di unapplicazione degli Algoritmi Genetici (AG) da parte di John Koza. I risultati ottenuti da Koza e dagli altri studiosi in questa disciplina sono stupefacenti.

Fabio Fabozzi ` Fabio Fabozzi e progettista software per tecnologie .NET e JAVA e di integrazioni tra differenti piattaforme. Attualmente, collabora con la ICM Italia S.p.A. sede di Roma. Tra i suoi principali interessi vi sono lIntelligenza Articiale e le Scienze ` Cognitive. E laureando in Scienze dei Processi Cognitivi, presso luni` versita La Sapienza ` di Roma. E autore del libro Intelligenza Articiale con VB edito dal Gruppo Infomedia, con cui collabora da diversi anni.

pubblicato su WWW.INFOMEDIA.IT stampa digitale da Lulu Enterprises Inc. stores.lulu.com/infomedia


Infomedia
` Infomedia e limpresa editoriale che da quasi venti anni ha raccolto la voce dei programmatori, dei sistemisti, dei professionisti, degli studenti, dei ricercatori e dei professori dinformatica italiani. Sono pi` di 800 gli autori che hanno realizzato per le teu state Computer Programming, Dev, Login, Visual Basic Journal e Java Journal, molte migliaia di articoli tecnici, presentazioni di prodotti, tecnologie, protocolli, strumenti di lavoro, tecniche di sviluppo e semplici trucchi e stratagemmi. Oltre 6 milioni di copie distribuite, trentamila pagine stampate, fanno di questa impresa la pi` grande ed u inuente realt` delleditoria specializzata nel campo della a programmazione e della sistemistica. In tutti questi anni le riviste Infomedia hanno vissuto della passione di quanti vedono nella programmazione non solo la propria professione ma unattivit` vitale e un vero a divertimento. ` Nel 2009, Infomedia e cambiata radicalmente adottando ` un nuovo modello aziendale ed editoriale e si e organizzata attorno ad una idea di Impresa Sociale di Comunit` , a partecipata da programmatori e sistemisti, separando le attivit` di gestione dellinformazione gestite da un board a comunitario professionale e quelle di produzione gesti` te da una impresa strumentale. Questo assetto e in linea con le migliori esperienze internazionali e rende Infomedia ancora di pi` parte della Comunit` nazionale degli u a sviluppatori di software. ` Infomedia e media-partner di manifestazioni ed eventi in ambito informatico, collabora con molti dei pi` imporu tanti editori informatici italiani come partner editoriale e fornitore di servizi di localizzazione in italiano di testi in lingua inglese.

Limpaginazione automatica di questa rivista e realizzata al ` 100% con strumenti Open Source usando OpenOffice, Emacs, BHL, LaTeX, Gimp, Inkscape e i linguaggi Lisp, Python e BASH

For copyright information about the contents of Visual Basic Journal, please see the section Copyright at the end of each article if exists, otherwise ask authors. Infomedia contents is 2007 Infomedia and released as Creative Commons 2.5 BY-NC-ND. Turing Club content is 2007 Turing Club released as Creative Commons 2.5 BY-ND. Le informazioni di copyright sul contenuto di Visual Basic Journal sono riportate nella sezione Copyright alla ne di ciascun articolo o vanno richieste direttamente agli autori. Il contenuto Infomedia e 2007 Infomedia ` e rilasciato con Licenza Creative Commons 2.5 BY-NCND. Il contenuto Turing Club e 2007 Turing Club e ` rilasciato con Licenza Creative Commons 2.5 BY-ND. Si applicano tutte le norme di tutela dei marchi e dei segni distintivi. ` E in ogni caso ammessa la riproduzione parziale o totale dei testi e delle immagini per scopo didattico purch e vengano integralmente citati gli autori e la completa identicazione della testata. Manoscritti e foto originali, anche se non pubblicati, non si restituiscono. Contenuto pubblicitario inferiore al 45%. La biograa dellautore riportata nellarticolo e sul sito www.infomedia.it e di norma quella disponibi` le nella stampa dellarticolo o aggiornata a cura dellautore stesso. Per aggiornarla scrivere a info@infomedia.it o farlo in autonomia allindirizzo http://mags.programmers.net/moduli/biograa

INTELLIGENZA ARTIFICIALE

Programmazione Genetica e Strategie di Pianificazione


Prima puntata

di Fabio Fabozzi

Sono sempre stato affascinato dallIntelligenza Artificiale e, soprattutto, dagli Algoritmi Genetici. In particolare, chi ha letto il mio primo libro e gli articoli scritti in passato, ha potuto apprezzare la bellezza di queste aree tematiche, naturalmente non grazie a me, ma al contributo dei grandi scienziati che vi hanno lavorato. La Programmazione Genetica (PG), il frutto di unapplicazione degli Algoritmi Genetici (AG) da parte di John Koza. I risultati ottenuti da Koza e dagli altri studiosi in questa disciplina sono stupefacenti. Vi consiglio di visitare il sito della Genetic Programming Foundation [1], per seguire gli ultimi aggiornamenti e le novit. In questo articolo parleremo della PG e dei problemi
Fabio Fabozzi progettista software per tecnologie .NET e JAVA e di integrazioni tra differenti piattaforme. Attualmente, collabora con la ICM Italia S.p.A. sede di Roma. Tra i suoi principali interessi vi sono lIntelligenza Artificiale e le Scienze Cognitive. laureando in Scienze dei Processi Cognitivi, presso luniversit La Sapienza di Roma. autore del libro Intelligenza Artificiale con VB edito dal Gruppo Infomedia, con cui collabora da diversi anni. Pu essere contattato allindirizzo fabozzi@infomedia.it

legati alle strategie di pianificazione, riproponendo un classico problema proposto (e risolto) da Koza: UNIVERSAL (Figura 1). Tale gioco o problema consiste nellimpilare dei cubi con delle lettere, disposti casualmente su un tavolo, finch non sia composta la parola UNIVERSAL, appunto. Un problema che pu sembrare banale, ma in realt non lo . Si tratta, infatti, di un problema riguardante le strategie di pianificazione, successivamente la presa di decisione e, naturalmente, la relativa generazione di programmi che risolvano il problema. Per ci che concerne le basi della PG si consiglia di consultare la bibliografia alla fine di questo articolo.

30

VBJ N. 77 - Settembre/Ottobre 2007

INTELLIGENZA ARTIFICIALE

Figura 1

rentetica di un albero. Tale peculiarit rende tale linguaggio particolarmente adatto a rappresentare le forme di pensiero deduttivo, sotto forma appunto di alberi decisionali e aiuta altres a rappresentare la popolazione di un Algoritmo Genetico per lapplicazione di operatori come lincrocio. Cosa succede quando si vuole utilizzare un linguaggio diverso dal LISP non , funzionale quindi, ma procedurale e/o ad oggetti? La direzione in cui indagheremo proprio questa.

Lidea di Koza Considerazioni iniziali


Koza ha sempre scelto la generazione di programmi in LISP La scelta in questo caso . giustificata: il LISP ha infatti a disposizione unampia scelta di primitive che consentono di effettuare operazioni immediate su liste, pile e code con estrema semplicit rispetto ad altri linguaggi. Inoltre il LISP consente di rappresentare le operazioni sotto forma di alberi decisionali, ossia come rappresentazione paIl problema dellimpilamento dei blocchi serve per sviluppare e verificare metodi di pianificazione. Koza per risolvere questo problema utilizz un insieme di tre terminali e cinque funzioni. I terminali erano rappresentati da sensori collegati ad una sorta di robot e controllato dal programma LISP Ognuno di . questi sensori rileva un insieme di informazioni (Tabella 1). Le cinque funzioni erano quelle riportate nella Tabella 2.

PA BS PN Tabella 1

Restituisce il nome del blocco in cima alla pila, altrimenti, se la pila vuota, restituisce NIL, il corrispettivo in LISP dellistruzione null, presente in altri linguaggi. Restituisce il nome del Blocco Superiore Corretto; NIL se non corretto. Restituisce il nome del blocco che necessario per completare la parola UNIVERSAL; NIL se non necessario nessun altro blocco.

VBJ N. 77 - Settembre/Ottobre 2007

31

INTELLIGENZA ARTIFICIALE

Figura 2

La generazione della Popolazione partiva da questi due insiemi. Koza gener casualmente 300 individui. L Idoneit era calcolata in base al numero di casi prova che risultavano impilati in modo corretto. Ci implica, in parole povere, che ogni pro-

gramma vada fatto girare prima di conoscere la sua Idoneit. Il resto, come nella PG, in generale segue le regole dIncrocio, cio i pi idonei vengono incrociati tra loro. I soggetti della popolazione erano rappresentati direttamente come espressioni LISP

SP(x) ST(x) RF(espressione1, espressione2) NOT(espressione1) EQ(espressione1, espressione2) Tabella 2

Sposta un blocco x dal tavolo, sulla pila Sposta un qualsiasi blocco x dalla pila al tavolo Esegue lespressione1 finche lespressione2, un predicato, non restituisce True. Restituisce True se lespressione1 NIL, altrimenti NIL Restituisce True se lespressione1 e lespressione2 sono equivalenti, NIL altrimenti.

32

VBJ N. 77 - Settembre/Ottobre 2007

INTELLIGENZA ARTIFICIALE

Figura 3

piuttosto che alberi nelle popolazioni PG classiche:


(EQ(ST PA)PN)

come e quanto impegnativo e relativamente oneroso sia scrivere queste primitive. Il premio finale comunque allettante.

Come procedere?
Per chi predilige la parte puramente tecnica, arriveremo a costruire questa applicazione in C# per .NET Framework 2.0. L ambiente di sviluppo usato sar SharpDevelop 2.2, un IDE open source, scaricabile liberamente. Ad ogni modo, andr bene qualsiasi versione di Visual Studio a vostra disposizione. Laddove sono presenti diagrammi UML, vi segnalo che sono stati creati con Star UML, un Modeler open source. I dati per risolvere il problema (linsieme delle informazioni e delle funzioni e lobiettivo)

Ancora una volta la PG ha entusiasmato per i risultati raggiunti, soprattutto per ci che concerne la complessit delle soluzioni candidate e per il fatto che tale complessit aumenti con levoluzione, piuttosto che rimanere prefissata come negli AG classici. Tuttavia le caratteristiche del LISP che possono esse, re considerate ottimali per le caratteristiche della PG, potrebbero rappresentare proprio una sua limitazione se trasposte in un altro linguaggio di programmazione. Questo problema potrebbe essere risolto scrivendo delle primitive ad hoc; il problema di scrutare Listato 1

private void MescolaLettere() { for (int i = 0; i < _blocchiLettere.Length; i++) { int tempIdx = _mescolatore.Next(0, _blocchiLettere.Length); string tmpStr = _blocchiLettere[tempIdx]; _blocchiLettere[tempIdx] = _blocchiLettere[i]; _blocchiLettere[i] = tmpStr;

} }

VBJ N. 77 - Settembre/Ottobre 2007

33

INTELLIGENZA ARTIFICIALE

Figura 4

li abbiamo gi. Non resta che pianificare la progettazione di questo software. La nostra ipotesi di partenza di vedere qual il risultato che si pu raggiungere, costruendo delle primitive in C# per risolvere questo problema. Funzioni e Terminali, specificati in questo problema, non sono altro che funzioni. L assunzione da cui si pu partire, ossia la pi semplice, di andare ad implementare delle primitive molto semplici. Tuttavia, prima di effettuare questa operazione, sar necessario definire la classe che definisce il soggetto della popolazione e le relative operazioni per generare la popolazione.

in ingresso 3 parametri: - la lunghezza del programma - linsieme dei terminali - linsieme delle funzioni Ci abbastanza semplice da intuire: la lunghezza del programma viene selezionata in modo random, dal programma principale, cos come linsieme dei terminali e delle funzioni ha gi dimensioni predefinite. Ci ci dice che ogni soggetto generer il suo programma in modo autonomo. La prima operazione che il costruttore esegue un metodo privato, ossia, MescolaLettere(). Tale metodo ha leffetto di effettuare il mescolamento dei blocchi che compongono la parola UNIVERSAL. Ogni generazione, dunque, mescoler i blocchi da impilare in modo diverso (Listato 1). Il metodo successivo lanciato dal costruttore si occuper di generare il programma relativo ad un determinato soggetto, con i parametri passati al costruttore. Naturalmente, lavvicendarsi tra terminali e funzioni regolato totalmente da generazioni random (Listato 2). Noterete che il programma un Array di tipo Istruzioni. Nello specifico, la classe istruzioni consente di memorizzare dei parametri che sono, praticamente, dei terminali e/o funzioni. In tal modo, sar possibile eseguire il flusso del programma senza troppe complica-

La classe soggetto e la classe istruzioni


Prima di analizzare Attributi, Propriet e Metodi della classe Soggetto e della classe Istruzioni, vediamo i relativi Class Diagram per una panoramica pi generale (Figura 2 e 3): Tralasciando attributi, propriet e metodi di ordine generale, andiamo ad analizzare le caratteristiche pi salienti della classe Soggetto. Iniziamo dai costruttori della classe. Il costruttore parametrico lo tralasciamo perch pi semplice. Per ci che concerne il costruttore parametrico, troveremo che esso riceve

34

VBJ N. 77 - Settembre/Ottobre 2007

INTELLIGENZA ARTIFICIALE

Figura 5

zioni. Per ci che concerne la classe istruzioni la sua implementazione abbastanza semplice, come avete potuto gi constatare dal suo class diagram. Infine, il metodo EseguiProgramma() esegue il programma per il soggetto e produce il risultato in termini di blocchi impilati, che rappresentano la soluzione che il programma stesso riuscito a risolvere (Listato 3). Come noterete, al verificarsi di alcune condizioni, EseguiProgramma(), richiama altri metodi al suo interno, che non sono altro che le primitive di cui avevamo bisogno. Questa tematica verr affrontata in modo pi approfondito, in quanto dall implementazione delle primitive dipende il successo di risoluzione del problema di pianificazione.

Strategie di definizione delle primitive allinterno della classe soggetto


Probabilmente qualcuno si sar posto la seguente domanda: possibile scrivere un AG, nellambito della PG, che possa scrivere un programma corretto seguendo la logica della scimmia che preme a caso i tasti su una tastiera e compone unopera letteraria? I risultati dicono che ci possibile. Pur pensando o credendo che questi risultati siano oltremodo oltraggiosi ed irriverenti nei confronti di tutti i nostri anni di studio nel campo dellingegneria del software, non possibile ignorarli. Tuttavia, il progettista del software ha ancora un ruolo: definire le procedure attraverso le quali la scimmia possa scrivere il program-

PUNTI DI FORZA - Risparmio tempo sulla definizione delle primitive - Realizzo una soluzione comunque robusta OPPORTUNITA - Arrivo ad una soluzione, per approssimazione, pressoch completa Tabella 3

PUNTI DI DEBOLEZZA - La soluzione che raggiungo completa solo al 89% circa MINACCE - I presupposti della mia progettazione mi portino su una strada sbagliata

VBJ N. 77 - Settembre/Ottobre 2007

35

INTELLIGENZA ARTIFICIALE

Listato 2

private void GeneraProgramma(string[] insiemeTerminali, string[] insiemeFunzioni) { _programma = new Istruzioni[_lunghezzaProgramma]; for (int i = 0; i < _programma.Length; i++) { int tmpSel = _selettoreTF.Next(0,2); if (tmpSel == 1) { int tmpSelT = _selettoreT.Next(0, 2); _programma[i] = new Istruzioni(); _programma[i].Istruzione = insiemeTerminali[tmpSelT]; } else { _programma[i] = new Istruzioni(); int tmpSelF = _selettoreF.Next(0, 4); _programma[i].Istruzione = insiemeFunzioni[tmpSelF]; if (_programma[i].Istruzione == RF(espressione1, espressione2)) { int tmpSelP1 = _selettorePar1.Next(0,1); _programma[i].Parametro1 = insiemeFunzioni[tmpSelP1]; int tmpSelP2 = _selettorePar2.Next(0, 2); _programma[i].Parametro2 = insiemeTerminali[tmpSelP2]; } if (_programma[i].Istruzione == NOT(espressione1)) { int tmpSelP1 = _selettorePar1.Next(0, 1); _programma[i].Parametro1 = insiemeFunzioni[tmpSelP1]; } if (_programma[i].Istruzione == EQ(espressione1, espressione2)) { int tmpSelP1 = _selettorePar1.Next(0, 1); _programma[i].Parametro1 = insiemeFunzioni[tmpSelP1]; int tmpSelP2 = _selettorePar2.Next(0, 2); _programma[i].Parametro2 = insiemeTerminali[tmpSelP2]; } } }

ma o lopera letteraria in modo corretto. Un modo corretto e completo sarebbe di progettare un parser che ricostruisca il flusso del programma in modo corretto. Nonostante ci, le primitive possono essere costruite in modo molto pi semplice, ma non solo: il flusso pu essere anche considerato come lineare, cio eseguendo il programma dalla prima istruzione fino allultima. Cosa si

perde e cosa si guadagna comportandosi cos? Questo comportamento progettuale potrebbe essere riassunto attraverso un quadro di analisi S.W.O.T. (Tabella 3). Per non lasciare il lettore perplesso e, soprattutto, per dimostrarvi che il mio ragionamento presentato nel quadro S.W.O.T. non errato, vi mostrer (solo in parte, per non rovinarvi il finale) due condizioni, attraverso le

36

VBJ N. 77 - Settembre/Ottobre 2007

INTELLIGENZA ARTIFICIALE

Listato 3

public void EseguiProgramma() { int spostaBloccoDaTavolo = 0; int spostaBloccoDaPila = 0; int maxBlocchi = 8; int minBlocchi = 0; bool _scelta = true; for (int i = 0; i < _programma.Length; i++) { ... if (_programma[i] == SP(X)) { SP(ref spostaBloccoDaTavolo, ref spostaBloccoDaPila, ref maxBlocchi); } if (_programma[i] == ST(X)) { ST(ref spostaBloccoDaTavolo, ref spostaBloccoDaPila, ref minBlocchi); ... } } }

quali posso sapere che le cose sono andate, tutto sommato, bene. Condizione 1 Faccio girare il mio AG con questi parametri : - popolazione max = 300 individui - fitness bersaglio da raggiungere = 8 Nonostante le condizioni un po pretenziose, cio popolazione esigua e fitness abbastanza alta da raggiungere, questo il risultato ottenuto (Figura 4). Ossia, in 3 epoche su 1.000 in cui il programma ha ciclato, ho ottenuto un certo numero di soggetti che hanno realizzato un programma che si avvicinato alla soluzione di circa il 89%, cio i programmi relativi ad ogni soggetto hanno impilato 8 blocchi su 9 correttamente. Non male direi.

Condizione 2 - popolazione max = 300 individui - fitness bersaglio da raggiungere = 9 Tuttavia, come avevo gi annunciato nel quadro S.W.O.T, nel voler raggiungere una fitness bersaglio = 9, con una popolazione di n soggetto ho raggiunto dei risultati piuttosto scarsi (Figura 5). Ho ottenuto una fitness pari a 6 ed i programmi sono stati accurati al 67% circa, ossia, hanno impilato 6 blocchi su 9. Questo punto importante, perch in questo modo, che in seguito potrete testare anche voi, so gi che il mio programma in grado di raggiungere sempre unaccuratezza, al minimo, del 89% circa. Cercheremo, naturalmente, in seguito di migliorare questa prestazione. Ora, se vi rivelassi che ho raggiunto questi risultati implementando due sole primitive, ci credereste? Beh! Dovete crederci perch proprio cos. VBJ N. 77 - Settembre/Ottobre 2007

37

INTELLIGENZA ARTIFICIALE

Listato 4

private void SP(ref int spostaBloccoDaTavolo,ref int spostaBloccoDaPila,ref int maxBlocchi) { if (spostaBloccoDaTavolo < maxBlocchi) { _blocchiDaImpilare[spostaBloccoDaPila] = _blocchiLettere[spostaBlocco DaTavolo]; spostaBloccoDaPila++; spostaBloccoDaTavolo++; } } private void ST(ref int spostaBloccoDaTavolo,ref int spostaBloccoDaPila,ref int min Blocchi) { if (spostaBloccoDaPila > minBlocchi) { _blocchiDaImpilare[spostaBloccoDaPila] = ; spostaBloccoDaPila--; spostaBloccoDaTavolo--; } }

Come mai? Per inciso, a mio avviso, le primitive pi importanti sono quelle che riguardano lo spostamento dei blocchi dal tavolo e, successivamente, vengono impilati per formare la parola UNIVERSAL. Due di queste, tra quelle che troverete nel codice sorgente, sono SP() e ST() (Listato 4). Per fare una digressione sulla scimmia, menzionata precedentemente, i risultati raggiungibili sono molto alti, seppur semplificati. Nonostante la nostra ricerca in questo articolo sia focalizzata sullo scrivere delle primitive in C#, che emulino il comportamento delle primitive in LISP in realt il meccani, smo pi grande lo gioca proprio l AG stesso. Naturalmente, se le primitive sono progettate ed implementate bene, allora tutto andr per il verso giusto.

formance globale di tutto lalgoritmo rispetto alle primitive delineate, per vedere se, e soprattutto quanto, ci siamo avvicinati al nostro obiettivo.

Bibliografia
[1] Genetic Programming Foundation http: //www.geneticprogramming.org [2] Fabio Fabozzi Predizione di flussi dati in sistemi caotici attraverso gli algoritmi genetici, Computer Programming, Febbraio 2006, Gruppo Editoriale Infomedia [3] Fabio Fabozzi Intelligenza Artificiale con Visual Basic, Dicembre 2004, Gruppo Editoriale Infomedia, ISBN 8881500183 [4] Fabio Fabozzi Programmazione Genetica in Visual Basic, VBJ n50, Marzo/Aprile 2003, Gruppo Editoriale Infomedia [5] Melanie Mitchell Introduzione agli Algoritmi Genetici, Apogeo Scientifica, 1998, ISBN 8873035000 [6] Kenneth Lange Mathematical and Statistical Methods for Genetic Analysis Springer, 1997, ISBN 0387949097 [7] Ilya Prigogine Le Leggi del Caos, Laterza Editore

Conclusioni
In questa prima parte abbiamo analizzato alcune tematiche per risolvere questo problema. I primi risultati sono stati abbastanza promettenti. Nella seconda parte analizzeremo la per-

38

VBJ N. 77 - Settembre/Ottobre 2007