Upload
others
View
2
Download
0
Embed Size (px)
Citation preview
SVEUČILIŠTE U ZAGREBU
FAKULTET ELEKTROTEHNIKE I RAČUNARSTVA
DIPLOMSKI RAD br. 50
UČINKOVITOST AUTOMATSKI
DEFINIRANIH FUNKCIJA U
EVOLUCIJSKIM ALGORITMIMA
Marko Pielić
Zagreb, lipanj 2010.
Sadržaj
Uvod ....................................................................................................................................... 1
1. Evolucijski algoritmi ...................................................................................................... 2
1.1. Općenito o evolucijskim algoritmima .................................................................... 2
1.2. Genetski algoritmi .................................................................................................. 2
1.2.1. Prikaz rješenja ................................................................................................ 4
1.2.2. Selekcija ......................................................................................................... 4
1.2.3. Križanje .......................................................................................................... 6
1.2.4. Mutacija ......................................................................................................... 7
1.2.5. Kriterij završetka ............................................................................................ 8
1.3. Genetsko programiranje ......................................................................................... 8
1.3.1. Pripremni koraci ............................................................................................ 9
1.3.2. Skup terminala ............................................................................................... 9
1.3.3. Skup funkcija ............................................................................................... 10
1.3.4. Mjera dobrote ............................................................................................... 10
1.3.5. Parametri kontrole izvođenja ....................................................................... 11
1.3.6. Izvođenje genetskog programiranja ............................................................. 12
2. Automatski definirane funkcije.................................................................................... 15
2.1. Pravilnosti pri rješavanju problema ..................................................................... 15
2.2. Hijerarhijsko rješavanje problema ....................................................................... 16
2.2.1. Pristup odozgo prema dolje ......................................................................... 16
2.2.2. Pristup odozdo prema gore .......................................................................... 17
2.2.3. Primjer hijerarhijske dekompozicije ............................................................ 18
2.2.4. Primjer rekurzivne hijerarhijske dekompozicije .......................................... 18
2.2.5. Primjer parametrizacije pri hijerarhijskoj dekompoziciji ............................ 19
2.2.6. Prednosti hijerarhijske dekompozicije ......................................................... 20
2.2.7. Problemi pri hijerarhijskoj dekompoziciji ................................................... 21
2.3. Automatski definirane funkcije............................................................................ 22
2.3.1. Struktura automatski definiranih funkcija ................................................... 22
2.3.2. Prilagodbe za uporabu automatski definiranih funkcija .............................. 24
2.3.3. Svojstva automatski definiranih funkcija .................................................... 25
2.3.4. Svojstva genetskog programiranja sa ADF-om ........................................... 26
2.3.5. Usporedba s ostalim područjima umjetne inteligencije ............................... 27
3. Evolutionary Computation Framework ....................................................................... 29
3.1. Što je Evolutionary Computation Framework? ................................................... 29
3.2. Pokretanje ............................................................................................................ 29
3.2.1. Definiranje parametara................................................................................. 30
3.2.2. Definiranje metode za izračunavanje dobrote.............................................. 34
3.2.3. Pokretanje algoritma .................................................................................... 35
3.3. Dinamičko učitavanje genotipova i algoritama ................................................... 35
3.3.1. Statičko i dinamičko učitavanje razreda ...................................................... 35
3.3.2. Implementacija u ECF-u .............................................................................. 36
3.4. Prikaz rješenja u obliku stabla ............................................................................. 38
3.4.1. Jednostavno križanje .................................................................................... 39
3.4.2. Uniformno križanje ...................................................................................... 41
3.4.3. Mutacija zamjenom čvora ............................................................................ 42
3.4.4. Mutacija permutacijom podstabala .............................................................. 42
3.5. Pokretanje genetskog programiranja.................................................................... 43
3.6. Uporaba automatski definiranih funkcija ............................................................ 47
4. Analiza rezultata .......................................................................................................... 50
4.1. Parametri genetskog programiranja ..................................................................... 50
4.1.1. Utjecaj veličine skupa funkcija .................................................................... 50
4.1.2. Utjecaj najveće dubine stabla ...................................................................... 51
4.1.3. Utjecaj veličine populacije ........................................................................... 52
4.1.4. Utjecaj vjerojatnosti mutacije ...................................................................... 54
4.1.5. Utjecaj odabira mutacije .............................................................................. 55
4.1.6. Utjecaj odabira križanja ............................................................................... 56
4.1.7. Utjecaj parametra functionProb ........................................................... 57
4.2. Utjecaj automatski definiranih funkcija ............................................................... 58
4.2.1. Problem dvije kutije ..................................................................................... 58
4.2.2. Polinom šestog stupnja ................................................................................ 65
4.2.3. Polinom dvanaestog stupnja ........................................................................ 66
4.2.4. Utjecaj više automatski definiranih funkcija ............................................... 68
Zaključak ............................................................................................................................. 70
Literatura .............................................................................................................................. 72
Sažetak ................................................................................................................................. 73
Summary .............................................................................................................................. 74
1
Uvod
Evolucijski algoritmi su stohastičke metode pretraživanja koje oponašaju prirodni tijek
biološke evolucije. Pretragu ne započinju od jedne točke kao konvencionalne
determinističke metode nego od niza točaka koje predstavljaju početnu populaciju. Upravo
u toj raznolikosti početne populacije i nedeterminističnosti pretrage leži snaga evolucijskih
algoritama, no zbog toga evolucijski algoritam ne mora nužno pronaći optimalno rješenje.
Cilj evolucijskih algoritama je pronalazak dovoljno dobrog rješenja, tj. onog rješenja koje
zadovoljava kriterij optimizacije.
Jedna vrsta evolucijskih algoritama je genetsko programiranje. Pri genetskom
programiranju rješenja su prikazana u obliku stabla, a stabla se najčešće tumače kao
računalni programi koji predstavljaju potencijalno rješenje nekog problema. Programi se
optimiziraju prema stupnju njihove dobrote na isti način kao i jedinke u genetskim
algoritmima.
U ovom su radu opisani evolucijski algoritmi s posebnim naglaskom na genetsko
programiranje. Prikaz rješenja u obliku stabla pri genetskom programiranju proširen je
konceptom automatski definiranih funkcija. Ocijenjena je učinkovitost prikaza u obliku
stabla s obzirom na probleme simboličke regresije, a posebna je pažnja stavljena na
učinkovitost i isplativost automatski definiranih funkcija.
2
1. Evolucijski algoritmi
1.1. Općenito o evolucijskim algoritmima
U prirodi preživljavaju jedinke koje se prilagode novim uvjetima. Jedinke sa vanjskim
karakteristikama bolje prilagođenim okolišu imaju veće šanse za preživljavanje i povećanje
svoje vrste, dok manje prilagođene jedinke izumiru, uzrokujući tako izumiranje čitavih
vrsta. Na taj se način provodi prirodna selekcija i osigurava da geni bolje prilagođenih
jedinki imaju veće šanse za preživljavanje od onih koji su lošije prilagođeni. Upotrebom
tog osnovnog biološkog modela nastali su evolucijski algoritmi (engl. Evolutionary
Algorithms, EA).
Evolucijski algoritmi obuhvaćaju vrlo široko područje, a dijele se na nekoliko podvrsta.
Neke od njih su genetski algoritmi, evolucijsko programiranje, evolucijske strategije,
genetsko programiranje i klasifikacijski sustavi. U nastavku ovog poglavlja opisani su
genetski algoritmi i genetsko programiranje.
1.2. Genetski algoritmi
Genetski algoritmi (engl. Genetic Algorithms, GA) su najpopularnija vrsta evolucijskih
algoritama, a predstavljaju model optimiziranja čije ponašanje potječe iz procesa evolucije
koji se odvija u prirodi. Osnovni cilj genetskih algoritama je pronalaženje rješenja nekog
problema koje tradicionalne determinističke metode ne mogu riješiti ([1]). Za razliku od
većine determinističkih algoritama, genetski algoritmi pretragu ne započinju od jedne
točke nego od cijelog niza potencijalnih rješenja. Ta potencijalna rješenja su najčešće
generirana slučajnim odabirom, a predstavljaju početnu populaciju genetskog algoritma
([2]).
Početnoj se populaciji određuje dobrota (engl. fitness). Dobrota je mjera kvalitete i govori
koliko je neko rješenje dobro – bolja rješenja imat će veću dobrotu i obrnuto. Dobrota se
određuje funkcijom cilja (funkcijom dobrote) koja ovisi o problemu koji se rješava ([3]).
Genetski proces može započeti nakon što se odredi dobrota početne populacije. Početna
populacija rješenja se iterira kroz generacije, a primjenjuje se princip preživljavanja
3
najspremnijeg (engl. survival of the fittest). U svakoj se generaciji odabiru bolja rješenja i
odbacuju ona lošija. Odabrana rješenja su podvrgnuta genetskim operatorima. Prvo se
križaju, a zatim s određenom vjerojatnošću i mutiraju. Tako nastaju nova potencijalna
rješenja koja predstavljaju novu generaciju genetskog algoritma. Ta nova rješenja su u
pravilu bolja nego stara rješenja od kojih su nastala. Cijeli se proces temelji na prirodnom
procesu evolucije (Slika 1.1).
Slika 1.1. Rješavanje problema genetskim algoritmom
Genetski_algoritam
{
t = 0
generiraj početnu populaciju potencijalnih rješenja P(0);
odredi dobrotu P(0);
sve dok nije zadovoljen uvjet završetka evolucijskog procesa {
t = t + 1;
izaberi roditelje P’(t) iz P(t-1);
križaj jedinke iz P’(t) i djecu spremi u P(t);
mutiraj jedinke iz P(t);
odredi dobrotu P(t);
}
ispiši rješenje;
}
Slika 1.2. Pseudokod genetskog algoritma
4
Stvaranje novih rješenja se nastavlja dok se ne zadovolji kriterij završetka genetskog
procesa koji je definirao korisnik (Slika 1.2). Kada se kriterij zadovolji, genetski algoritam
je završio s radom. Međutim, to ne znači da je pronađeno optimalno rješenje. Završetak
rada genetskog algoritma znači samo da je nađeno dovoljno dobro rješenje. Ono može, a i
ne mora biti najbolje ([4]).
1.2.1. Prikaz rješenja
Svojstva živih bića zapisana su u njihovim kromosomima. Kromosomi su lančaste
tvorevine koje se nalaze u jezgri svake stanice, a sastoje se od molekula DNK
(deoksiribonukleinska kiselina). Molekula DNK je nositelj informacija. Skup informacija
koje karakteriziraju jedno svojstvo naziva se gen. Živa bića dobivaju jedan kromosom od
oca, a jedan od majke što znači da za svako svojstvo postoje dva gena. Ti geni mogu biti
ravnopravni ili jedan može biti dominantan, a drugi recesivan. Ako su geni ravnopravni,
svojstvo potomka je negdje između svojstava oca i majke, a ako geni nisu ravnopravni
onda potomak zadržava svojstvo dominantnog gena.
Postavlja se pitanje kako preslikati ove prirodne operacije na model strojnog učenja, tj.
kako prikazati informaciju (rješenje) u genetskom algoritmu. Rješenja se najčešće
prikazuju nizom bitova i binarnim brojevima. Glavna prednost takvog prikaza je u tome što
se njegovi dijelovi zbog fiksne veličine mogu lako poravnati i uskladiti što omogućuje
jednostavnu operaciju križanja. Na isti način se mogu koristiti i druge, složenije strukture,
poput matrica ili stabala ([5]). Korištenje rješenja različite duljine otežava operaciju
križanja.
1.2.2. Selekcija
Selekcija (engl. selection) je odabir jedinki koje stvaraju potomstvo. Ona omogućava
čuvanje i prenošenje dobrih svojstava (dobrih gena) na sljedeću generaciju jedinki. Lošija
svojstva se odbacuju. Selekcija se vrši prema dobroti – jedinke s većom dobrotom imaju
veće šanse da budu odabrane za roditelje u sljedećoj generaciji. Vjerojatnost odabira
jedinke ovisi o njenoj dobroti, ali i o dobroti ostalih jedinki. Što je jedinka bliže ciljanom
rješenju u odnosu na druge jedinke, njezina vjerojatnost razmnožavanja se povećava.
Analogno tome, ako je iznos dobrote jedinke manji u odnosu na onaj drugih jedinki,
njezine mogućnosti preživljavanja se smanjuju.
5
Postupak selekcije mogao bi se ostvariti jednostavnim odabirom N najboljih jedinki (gdje
je N veličina populacije), ali takav odabir bi doveo do prerane konvergencije rješenja ([6]).
Problem je u tome što se takvim odabirom gubi dobar genetski materijal koji mogu
sadržavati loše jedinke. Zato i loše jedinke moraju imati određenu vjerojatnost
preživljavanja (veću od nule).
Odabir može biti eliminacijski (engl. steady-state) i generacijski (engl. generational). Kod
jednostavnog eliminacijskog odabira neke se jedinke eliminiraju, a nove ih nadoknađuju.
Najbolja jedinka uvijek ostaje prisutna i u sljedećoj generaciji. Pri generacijskom odabiru
nova populacija se stvara od kopija jedinki stare populacije pa se može dogoditi da najbolja
jedinka ne bude odabrana za sljedeću generaciju što može uzrokovati nazadovanje
genetskog procesa. Taj se problem rješava elitizmom. Ako se koristi elitizam u genetskom
algoritmu, najbolja jedinka iz trenutne generacije ide direktno u sljedeću, bez križanja i
mutiranja. Unatoč tome, ta jedinka može dodatno sudjelovati i u stvaranju djece. Može se
koristiti elitizam jedne jedinke ili elitizam više jedinki.
Postoji mnogo načina odabira roditelja (engl. parent selection shemes) za sljedeću
generaciju, a najpoznatiji od njih su:
1. Proporcionalni odabir (engl. Proportionate Selection). Jedinke se biraju
proporcionalno prema dobroti. Jedinka sa najvećom dobrotom ima najveće šanse
da bude izabrana, dok najlošija jedinka ima najmanje šanse preživljavanja.
Vjerojatnost preživljavanja ostalih jedinki je negdje između.
2. Odabir po rangu (engl. Ranking Selection). Populacija se sortira od najboljih
jedinki prema najgorima. Broj kopija koje jedinka dobije određuje se funkcijom
(engl. assignment function) i proporcionalan je rangu jedinke. Rang jedinke je
pozicija jedinke u odnosu na generaciju. Najbolja jedinka ima rang 1, dok najlošija
jedinka ima rang N (gdje je N veličina populacije).
3. Turnirski odabir (engl. Tournament Selection). Odabire se slučajan broj jedinki
iz populacije (sa ili bez zamjena, ovisno o implementaciji), a najbolje od njih
postaju roditelji sljedeće generacije. Postupak se ponavlja dok se ne popuni cijela
sljedeća generacija, tj. dok broj odabranih jedinki ne postane jednak veličini
populacije. Ovaj se odabir često naziva i k-turnirski odabir, gdje k označava broj
jedinki čije se dobrote uspoređuju. Taj se broj naziva veličina prozora.
6
1.2.3. Križanje
Križanjem u prirodi genetski se materijal prenosi s roditelja na djecu. Novonastalo dijete
posjeduje genetski materijal oba roditelja i ima jednak broj gena kao i oni, što znači da
svaki roditelj daje samo pola svojih gena djetetu.
Isti se princip primjenjuje i u genetskim algoritmima. Procesom križanja (engl. crossover)
nastaju nove jedinke koje imaju kombinirane informacije sadržane u dvoje ili više
roditelja. Križanje se često naziva i rekombinacija (engl. recombination). Odabir križanja
za genetski algoritam ovisi o odabranom načinu prikaza rješenja. [7] opisuje najpoznatije
izvedbe križanja za jednostavni prikaz rješenja binarnim brojevima:
1. Križanje u jednoj točki (engl. one point crossover). Odabire se jedna točka na
roditeljima (jednako udaljena od početka kod oba roditelja) i mijenja se desni dio
kromosoma prvog s desnim dijelom kromosoma drugog roditelja (Slika 1.3).
Slika 1.3. Križanje u jednoj točki
2. Križanje u dvije točke (engl. two point crossover). Odabiru se dvije točke na
roditeljima tako da je lijeva točka jednako udaljena od lijevog kraja i desna točka
od desnog kraja kromosoma kod oba roditelja. Roditelji izmjenjuju dijelove
kromosoma između tih točaka (Slika 1.4).
Slika 1.4. Križanje u dvije točke
7
3. Križanje rezanjem i spajanjem (engl. cut and splice crossover). Na roditeljima se
odabire točka koja nije jednako udaljena od početka roditeljskih kromosoma.
Mijenja se desni dio kromosoma jednog roditelja s desnim dijelom kromosoma
drugog. Na taj način nastaju djeca koja imaju različite duljine kromosoma (Slika
1.5).
Slika 1.5. Križanje rezanjem i spajanjem
4. Uniformno križanje (engl. uniform crossover). Uspoređuje se bit po bit oba
roditelja i mijenjaju se sa fiksnom vjerojatnošću od 50%
5. Polu-uniformno križanje (engl. half-uniform crossover). Uspoređuje se bit po bit
oba roditelja i računa koliko ih se ne poklapa. Polovica od tih koji se ne poklapaju
se mijenja.
1.2.4. Mutacija
U prirodi se mutacija definira kao slučajna promjena gena. Vjerojatnosti promjene za gene
su različite pa geni mogu biti stabilni i nestabilni. Vjerojatnost da gen A postane gen B nije
ista kao vjerojatnost da gen B postane gen A.
U genetskim algoritmima mutacija (engl. mutation) je genetski operator koji se
upotrebljava za dobivanje genetske raznolikosti sljedeće generacije rješenja od one
postojeće. Najjednostavniji primjer mutacije je vjerojatnost da se neki bit u genetskom
kodu (rješenju) promijeni iz svog originalnog stanja u novo stanje. To se postiže
uvođenjem neke varijable za svaki bit u nizu. Ta varijabla govori hoće li bit biti
modificiran ili neće. Ako se koristi binaran prikaz rješenja, mutacija je vjerojatnost da neki
bit iz nule prijeđe u jedinicu ili iz jedinice u nulu (Slika 1.6). Mutacija sprječava rješenja da
postanu preslična i na taj način uspore ili zaustave evoluciju. Kada se mutacija ne bi
koristila, rješenja genetskog algoritma najčešće bi konvergirala prema nekom lokalnom
optimumu.
8
Slika 1.6. Mutacija
1.2.5. Kriterij završetka
Genetski algoritam ponavlja proces generiranja sljedeće generacije sve dok se ne zadovolji
kriterij završetka evolucijskog procesa, koji se još naziva i uvjet kraja ili kriterij kraja.
Kriterij završetka je najčešće jedan od sljedećih:
• Pronađeno je rješenje koje zadovoljava minimalne kriterije,
• Dosegnut je unaprijed određeni broj generacija,
• Potrošen je budžet (vrijeme ili novac),
• Rješenje sa najvećim stupnjem dobrote dostiže ili je već dostiglo takvu granicu da
daljnje iteracije ne daju bolje rezultate,
• Ručno ispitivanje,
• Kombinacija gore navedenih.
1.3. Genetsko programiranje
Genetsko programiranje (engl. Genetic Programming, GP) je evolucijski algoritam koji se
može opisati kao proširenje genetskog algoritma. Pri genetskom programiranju jedinke su
prikazane u obliku stabla (Slika 1.7) i predstavljaju hijerarhijske računalne programe
promjenjivog oblika i veličine. Genetsko programiranje nastoji pronaći odgovor na neka od
temeljnih pitanja računalne znanosti: Mogu li računala naučiti rješavati probleme bez da ih
se eksplicitno programira? Kako računala mogu napraviti ono što je potrebno za rješavanje
problema, a da im se ne kaže točno kako da to naprave? Prostor pretrage (engl. search
9
space) genetskog programiranja obuhvaća sve računalne programe koji se mogu sastaviti
od funkcija i varijabli koje se nalaze u domeni problema koji se rješava ([8]).
+-
*
X
2
-2
/
Y
e
5
+
1
(X+1-2) * (-2/Y+e5)
Slika 1.7. Prikaz programa u obliku stabla
1.3.1. Pripremni koraci
Kako bi se problem rješavao genetskim programiranjem potrebno je definirati:
• skup terminala (završnih znakova),
• skup funkcija,
• mjeru dobrote,
• parametre kontrole izvođenja,
• kriterij završetka.
Ovih pet točaka predstavlja ujedno i pet pripremnih koraka koje je potrebno napraviti
ukoliko se želi koristiti genetsko programiranje. Definiranje skupa funkcija i skupa
terminala odgovara izboru prikaza rješenja kod genetskog algoritma, a preostale tri točke
su jednake za genetski algoritam i genetsko programiranje.
1.3.2. Skup terminala
Prvi pripremni korak za korištenje genetskog programiranja je identifikacija skupa
terminala (engl. terminal set) za zadani problem. Terminali odgovaraju ulazima (engl.
10
input) u računalne programe, a nazivaju se još i varijablama. Skup terminala obuhvaća i
konstante (engl. Ephemereal Random Constant, ERC).
1.3.3. Skup funkcija
U drugom pripremnom koraku identificira se skup funkcija (engl. function set). Funkcije
mogu biti aritmetičke (zbrajanje, oduzimanje, množenje, dijeljenje), matematičke (sinus,
kosinus, tangens, kotangens, logaritam, eksponencijalna funkcija), logičke (i, ili, ne, ni,
nili), programerske ili specifične za neku domenu. Funkcije obavljaju svoj posao i vraćaju
jednu ili više vrijednosti, a mogu mijenjati i stanje sustava.
Svaki računalni program je kompozicija funkcija iz skupa funkcija i terminala iz skupa
terminala. Skup terminala i skup funkcija se zajednički nazivaju skupom primitiva pa se
kaže da skup primitiva sadrži sve elemente potrebne za generiranje računalnog programa
koji može riješiti zadani problem. Skup primitiva mora sadržavati sve elemente (funkcije i
terminale) koji su potrebni za rješavanje problema ([9]). Ako primjerice skup primitiva
sadrži samo operacije zbrajanja, množenja i dijeljenja, no ne i operaciju oduzimanja, tada
se genetskim programiranjem ne može riješiti nijedan problem koji zahtijeva oduzimanje
dvaju podataka.
Svaka funkcija mora prihvaćati, kao svoj argument, bilo koju vrijednost koju vrati bilo
koja druga funkcija iz skupa funkcija i bilo koju vrijednost koju može poprimiti bilo koji
terminal iz skupa terminala. Za skup primitiva koji ispunjava taj uvjet se kaže da on
ispunjava uvjet zatvorenosti (engl. closure agreement).
1.3.4. Mjera dobrote
Dobrota je mjera kvalitete jedinke i koristi se za upravljanje evolucijskim procesom. Ona
procjenjuje koliko je pojedina jedinka dobra ili loša u danoj okolini, a ta procjena se dalje
koristi za vrednovanje uspješnosti pojedinog računalnog programa u populaciji. Mjera
dobrote mora biti potpuno definirana (engl. fully defined) što znači da ona mora biti u
stanju ocijeniti bilo koji računalni program u bilo kojoj generaciji.
Izbor mjere dobrote u potpunosti ovisi o domeni problema koji se rješava. Primjerice, ona
se može definirati kao razlika rezultata dobivenog računalnim programom i ispravnim
rješenjem. Čim je ta razlika bliža nuli, greška je manja, a rješenje je točnije. Za izračun
greške se najčešće rabi veći broj ulaza, a ukupna greška se definira kao prosječna
11
vrijednost ili suma apsolutnih vrijednosti pogrešaka. Ulazi koji se koriste za izračun
pogreške nazivaju se ulaznim točkama ispitivanja dobrote (engl. fitness cases). Oni mogu
biti odabrani slučajnim odabirom, koristeći strategiju biranja ili kombinacijom. Strategija
odabira ulaza najčešće se koristi kako bi se ispitala dobrota za granične ili najvažnije točke
domene, a može se koristiti kao dopuna slučajnom odabiru. Veći broj točaka ispitivanja
omogućuje točnije opisivanje tražene funkcije. Ako je ukupna greška definirana kao suma
apsolutnih vrijednosti pogrešaka, veći broj točaka ispitivanja uzrokovat će veće vrijednosti
pogreške i povećati vrijeme potrebno da genetsko programiranje pronađe rješenje.
Mjera dobrote se može optimizirati prema više kriterija, a takva dobrota se naziva
višekriterijska dobrota ili dobrota sa više ciljeva (engl. multi-objective fitness). Kriteriji
mogu biti točnost, jednostavnost, učinkovitost, štedljivost, brzina ili neki drugi.
1.3.5. Parametri kontrole izvođenja
Osnovni parametri kontrole izvođenja genetskog programiranja slični su kao i u ostalim
evolucijskim algoritmima, a to su:
• veličina populacije,
• kriterij završetka,
• vjerojatnost mutacije,
• izbor križanja,
• izbor mutacije,
• izbor selekcije.
Broj generacija najčešći je uvjet završetka genetskog programiranja, no umjesto njega ili
uz njega mogu biti i ostali parametri navedeni u poglavlju 1.2.5. Za razliku od genetskih
algoritama, u genetskom programiranju se obično koriste veće populacije uz manji broj
generacija. Tako su populacije od 5000 jedinki sasvim uobičajene, a nerijetko se koriste i
populacije sa više od 15000 jedinki ([9]). Većim populacijama nastoji se svladati ogromna
složenost prostora pretraživanja. Nedostatak velikih populacija je sporost izvođenja
algoritma, a to se obično kompenzira smanjenjem broja generacija.
12
Kada se zadovolji barem jedan uvjet završetka evolucijskog procesa, izvođenje genetskog
programiranja se prekida. Jedinka sa najboljom dobrotom se proglašava najboljom
jedinkom tog pokretanja (engl. best of run).
1.3.6. Izvođenje genetskog programiranja
U genetskom programiranju se stvara populacija računalnih programa koji su tada
podvrgnuti genetskim operatorima (selekcija, križanje i mutacija). Jedinke se
razmnožavaju koristeći Darwinov princip preživljavanja najspremnijeg što znači da bolje
jedinke imaju veće šanse za preživljavanje.
Genetsko programiranje najčešće započinje sa populacijom slučajno odabranih računalnih
programa koji se sastoje od funkcija i terminala pripadne domene problema. Kreiranje
početne populacije je obična "slijepa" pretraga prostora pa stoga rezultati dobiveni u
početnoj generaciji najčešće nisu nimalo dobri. Međutim, neke jedinke su bolje od drugih,
a te razlike se koriste kasnije tijekom evolucijskog procesa. Obzirom da postoji populacija
rješenja, genetsko programiranje se može smatrati i algoritmom paralelne pretrage (engl.
parallel search algorithm).
Operacija križanja se koristi za stvaranje novih računalnih programa iz onih postojećih.
Odabiru se dva programa koji predstavljaju roditelje. Roditelji se biraju prema dobroti, a
mogu se razlikovati u veličini i obliku. Iz roditelja nastaje dijete koje je različitog oblika i
veličine od svojih roditelja, a ono može imati bolju dobrotu od svojih roditelja obzirom da
sadrži njihove gene. Postoji puno vrsta križanja za genetsko programiranje, a jedno od njih
je križanje izmjenom podstabala prikazano na sljedećoj stranici (Slika 1.8). Na svakom se
roditelju odabire čvor koji predstavlja točku križanja (na slici je označen plavim rubom), a
podstabla tih čvorova se zamijene.
Nakon križanja s određenom vjerojatnošću se provodi i mutacija, a ona omogućuje
stvaranje novih kombinacija gena. Primjer mutacije prikazan je na slici na sljedećoj
stranici (Slika 1.9). U njoj se slučajnim odabirom odabire neki čvor, a njegov se primitiv
zamjenjuje nekim drugim primitivom iz skupa primitiva, pod uvjetom da oba primitiva
imaju isti broj argumenata.
13
+
- *
1 2 3 4
*
/ +
5 6 7
+
*
3 4
+
7
*
/
5 6
-
1 2
roditelj 1 roditelj 2
dijete 1 dijete 2
Slika 1.8. Križanje u genetskom programiranju
Slika 1.9. Mutacija u genetskom programiranju
14
Nakon mutacije se provodi izračunavanje dobrote nove generacije čime se algoritam
prebacuje u sljedeću generaciju, a cijeli postupak se ponavlja. Tijekom izvođenja
genetskog programiranja jedinke postaju sve bolje i sve uspješnije u rješavanju zadanog
problema. Kao i kod ostalih evolucijskih algoritama, nema garancije da će rezultat dobiven
genetskim programiranjem biti optimalno rješenje problema, pa čak niti da će to uopće biti
dobro rješenje.
Hijerarhijska struktura prikaza računalnih programa čini rezultate genetskog programiranja
inherentno hijerarhijskim. Rezultati se mogu tumačiti kao obične hijerarhije, hijerarhije s
prioritetom zadataka ili hijerarhije u kojima izvođenje jednog zadatka mora prethoditi
izvođenju drugog. Važna značajka genetskog programiranja je dinamična raznolikost
populacije računalnih programa koji nastaju tijekom evolucijskog procesa. Pri genetskom
programiranju najčešće nema pretprocesiranja ulaznih podataka ili postprocesiranja
izlaznih. Ulazi, međurezultati i izlazi se obični izražavaju direktno u prirodnoj
terminologiji domene problema. Računalni program se sastoji od skupa funkcija koje su
prirodne za njegovu domenu.
15
2. Automatski definirane funkcije
2.1. Pravilnosti pri rješavanju problema
Složeni sustavi u stvarnome svijetu sadrže veliku količinu pravilnosti (engl. regularity).
Razumijevanje, oblikovanje i izrada složenih sustava zahtijeva iskorištavanje prednosti
sadržane u pravilnostima, modularnostima i simetriji. Pravilnosti se pojavljuju pri širokom
spektru problema, bez obzira na to jesu li oni slični ili sasvim različiti:
• dizajneri mikroprocesora upotrebljavaju već gotove standardne sklopove koji
obavljaju neku osnovnu funkciju,
• biolozi su proučavali živa bića i shvatili da se mnogi mehanizmi stvoreni za
obavljanje neke funkcije upotrebljavaju u istom ili sličnom obliku za obavljanje
drugih funkcija,
• pri dizajniranju kuće arhitekti koriste osnovne građevne materijale u istom ili malo
promijenjenom obliku,
• u različitim radnim stanicama koriste se isti načini i materijali kako bi se različiti
dijelovi spojili u jedan,
• različiti činovnici provode različite transakcije na isti način,
• programeri upotrebljavaju gotove dijelove programskog koda (engl. reuse)
prilikom jednokratnog ili uzastopnog pozivanja potprograma.
Pisanje računalnih programa bilo bi krajnje nepraktično kada bi programeri morali stalno
ispočetka pisati sve funkcije koje im trebaju. Primjeri takvih funkcija su funkcija za
izračunavanje kvadratnog korijena, sinusa, kosinusa, dohvat elemenata polja, upravljanje
datotekama itd. Dizajniranje mikroprocesora koji sadrži tisuće standardnih ćelija bilo bi
jako otežano kada bi dizajneri svaku ćeliju morali dizajnirati u potpunosti ispočetka.
Živi svijet sadrži izobilje organizama čija se struktura i ponašanje ponavljaju na identičan
ili vrlo sličan način. Stanice živih bića sadrže milijune identičnih kopija različitih proteina
specijaliziranih za obavljanje neke funkcije. Ljudi sadrže trilijune takvih ćelija, ali cijela
struktura im je predodređena kromosomima koji sadrže "svega" nekoliko bilijuna bitova
16
informacija ([10]). Trodimenzionalne koordinate svakog atoma od svakog proteina i svake
ćelije nisu eksplicitno navedene u kromosomima već postoji hijerarhijski raspored
struktura i podstruktura u kojem se upotrebljavaju već gotovi osnovni konstrukti.
2.2. Hijerarhijsko rješavanje problema
Složeni problemi sa puno pravilnosti često se mogu riješiti hijerarhijskom dekompozicijom
problema. Hijerarhijska dekompozicija sadrži tri koraka (engl. three-step hierarchical
problem-solving process), a može se koristiti pristup odozgo prema dolje (engl. top-down)
ili odozdo prema gore (engl. bottom-up).
2.2.1. Pristup odozgo prema dolje
Pri pristupu odozgo prema dolje prvo se traži način da se početni problem rastavi na
potprobleme. Nakon toga se rješavaju potproblemi, a na kraju se rješava početni problem
upotrebom dostupnih rješenja potproblema. Cijeli proces prikazan je na slici ispod (Slika
2.1). Postupak se može izvoditi i rekurzivno pa se tako bilo koji od potproblema može
riješiti na isti način, primjenom još jednog procesa dekompozicije. Rekurzivni postupak se
primjenjuje ako su potproblemi i dalje presloženi za direktno rješavanje. Ako je
dekompozicija problema na potprobleme uspješna, dobije se hijerarhijsko i modularno
rješenje problema. Poznata tehnika "podijeli i vladaj" (lat. divide et impera) je primjer
ovog pristupa.
Slika 2.1. Hijerarhijska dekompozicija pristupom odozgo prema dolje
Programeri neprestano upotrebljavaju ovaj pristup za rješavanje svojih problema. Proces
započinje kada programer analizira početni problem i podijeli ga na dijelove. Nakon toga
programer piše potprograme (procedure, funkcije ili metode) koje rješavaju potprobleme, a
17
zatim piše i glavni program koji rješava ukupni (početni) problem pozivom potprograma.
Na taj način glavni program spaja rezultate dobivene potprogramima i izvršava zadani
zadatak.
Pristup odozgo prema dolje je vrlo koristan jer se često pokazuje da je ukupan trud
potreban za dekompoziciju problema na potprobleme, rješavanje potproblema i spajanje
rješenja potproblema u konačno rješenje manji od truda potrebnog za direktno rješavanje
početnog problema. Druga prednost ovog pristupa je da se rješenja potproblema, ako je
dekompozicija dobro zamišljena i uspješno izvedena, često mogu ponovno upotrijebiti u
identičnom ili promijenjenom obliku za rješavanje istog ili nekog drugog problema.
Ponovna upotrebljivost rješenja može dovesti do manjih rješenja koja su jednostavnija i
čitljivija čovjeku.
Neki problemi mogu biti teški za rješavanje ovom metodom. Ako se pravilna
dekompozicija ne može pronaći ili ako nema prilike za ponovno iskorištavanje
potproblema, ovaj postupak može biti kontraproduktivan.
2.2.2. Pristup odozdo prema gore
Hijerarhijska dekompozicija pristupom odozdo prema gore nastoji pronaći pravilnosti i
uzorke na najnižoj razini okoline problema. Prikaz problema se mijenja i ponovno izražava
u obliku u kojem se mogu razaznati pravilnosti. Na taj se način stvara novi problem. Novi
problem se potom rješava, a ako su pronalazak pravilnosti i promjena prikaza problema
ispravno napravljeni, novi će problem biti jednostavniji za rješavanje od početnog.
Postupak je prikazan na slici ispod (Slika 2.2). Pravilnosti su tim korisnije što se više puta
pojavljuju u zadanoj okolini.
Slika 2.2. Hijerarhijska dekompozicija pristupom odozdo prema gore
18
2.2.3. Primjer hijerarhijske dekompozicije
Potrebno je pronaći prvu derivaciju funkcije y(x)=sin(x)*ln(x). Ovaj se zadatak
može riješiti na vrlo jednostavan i brz način koristeći osnovna pravila deriviranja čime se
dobiva rješenje y'(x)=cos(x)*ln(x)+sin(x)/x.
No, zadatak je vrlo dobar i za primjenu hijerarhijske dekompozicije. Početni problem
pronalaska prve derivacije funkcije y se rastavlja na dva potproblema: pronalazak prve
derivacije funkcije sin(x) i pronalazak prve derivacije funkcije ln(x). Oba
potproblema predstavljaju elementarne funkcije koje je lako derivirati. Problemi se
rješavaju odvojeno, a njihovim rješavanjem dobije se da je derivacija funkcije sin(x)
jednaka cos(x) i derivacija funkcije ln(x) jednaka 1/x. Posljednji korak postupka
spaja dobivena rješenja potproblema u rješenje konačnog problema i to tako da se
derivacija prve funkcije množi drugom funkcijom, a rezultat se zbraja sa umnoškom prve
funkcije i derivacije druge funkcije. Cijeli je postupak prikazan na slici ispod (Slika 2.3).
Slika 2.3. Hijerarhijska dekompozicija funkcije y(x)=sin(x)*ln(x)
2.2.4. Primjer rekurzivne hijerarhijske dekompozicije
Potrebno je pronaći prvu derivaciju funkcije y(x)=sin(x)*ln(x)+x. Ovaj se zadatak
može riješiti na vrlo jednostavan i brz način koristeći osnovna pravila deriviranja čime se
dobiva rješenje y'(x)=cos(x)*ln(x)+sin(x)/x+1.
Zadatak se može riješiti primjenom hijerarhijske dekompozicije, a može se primijeniti čak
i rekurzivna hijerarhijska dekompozicija. Početni problem se dekomponira na dva
potproblema: pronalazak derivacije prvog pribrojnika i pronalazak derivacije drugog
pribrojnika. Obzirom da je pronalazak derivacije prvog pribrojnika dovoljno složen
problem, za njegovo se rješavanje iznova primjenjuje postupak hijerarhijske
19
dekompozicije, sličan onome u poglavlju 2.2.3. Primjena hijerarhijske dekompozicije
unutar hijerarhijske dekompozicije naziva se rekurzivnom hijerarhijskom dekompozicijom.
Rješavanjem potproblema dobije se da je derivacija od sin(x)*ln(x) jednaka
cos(x)*ln(x)+sin(x)/x, a derivacija od x jednaka 1. U posljednjem koraku
dobivena se rješenja spajaju u rješenje konačnog problema zbrajanjem. Cijeli je postupak
prikazan na slici ispod (Slika 2.4).
Slika 2.4. Hijerarhijska dekompozicija funkcije y(x)=sin(x)*ln(x)+x
2.2.5. Primjer parametrizacije pri hijerarhijskoj dekompoziciji
Potrebno je pronaći prvu derivaciju funkcije y(x)=x2+x. Ovaj se zadatak može riješiti na
vrlo jednostavan i brz način koristeći osnovna pravila deriviranja čime se dobiva rješenje
y'(x)=2x+1.
Zadatak se može riješiti primjenom hijerarhijske dekompozicije na više načina. Problem se
može dekomponirati na potprobleme deriviranja x i x2, a nakon toga se rješenja
potproblema mogu zbrojiti. No, ovaj način nije baš dobar jer ne daje nikakvo generičko
rješenje problema deriviranja eksponencijalne funkcije. Bolji pristup je iskoristiti sličnosti
u obliku oba pribrojnika i napraviti generički postupak koristeći parametar n, a zatim taj
generički postupak pozvati dva puta, svaki put za deriviranje jednog pribrojnika.
Slika 2.5 prikazuje postupak pronalaženja prve derivacije funkcije y koristeći
parametriziranu hijerarhijsku dekompoziciju. Pri dekompoziciji nastaje samo jedan
potproblem – problem pronalaska derivacije funkcije xn. U drugom koraku se rješava
potproblem čime se dobiva generičko rješenje n*xn-1. U trećem koraku se rješenje
potproblema poziva dvaput, jednom sa parametrom n=2, a drugi put sa parametrom n=1.
20
Na kraju trećeg koraka dobivena se rješenja zbrajaju čime se dobiva rješenje početnog
problema.
Slika 2.5. Hijerarhijska dekompozicija funkcije y(x)=x2+x
Ovaj se postupak može povezati sa potprogramima u programiranju. Glavni program
predaje potprogramu parametar i poziva ga. Potprogram preuzima parametar od glavnog
programa, računa rješenje i vraća ga glavnom programu. Na taj način glavni program može
jednostavno i učinkovito pozivati potprogram sa različitim parametrima, a uz minimalni
utrošak vremena pri programiranju.
2.2.6. Prednosti hijerarhijske dekompozicije
Rješavanje problema hijerarhijskom dekompozicijom vrlo je poželjno zbog nekoliko
razloga. Kada se složeni problem uspješno dekomponira potrebno je manje truda (vremena
ili računanja) za dekompoziciju problema na potprobleme, rješavanje potproblema i
spajanje rješenja potproblema u cjelovito rješenje nego da se početni problem izravno
rješava.
Hijerarhijska dekompozicija daje mogućnost rekurzivnog rješavanja problema. Rekurzija
se odvija tijekom drugog koraka, odnosno tijekom rješavanja potproblema nastalih
dekompozicijom. Time se omogućuje da se potproblem riješi uz manje truda nego što bi
bilo potrebno da se on direktno rješava.
Ako domena problema sadrži pravilnosti, uz uspješnu dekompoziciju rješenje potproblema
se može ponovno iskoristiti. Ponovno iskorištavanje rješenja omogućuje da se potproblem
koji se uzastopno javlja na isti način ne mora svaki put ponovno rješavati. Nadalje, rješenje
potproblema može postati ponovno iskoristivo ako se riješi cijeli razred sličnih
potproblema, a ne samo točno određeni potproblem. To se postiže parametrizacijom, a
posljedica takvog postupka je generalizacija rješenja. Ako se pri generalizaciji otkrije da su
21
neke varijable nebitne za zadani potproblem, tada se rješenje potproblema može ponovno
upotrijebiti pri svim kombinacijama nebitnih varijabli.
2.2.7. Problemi pri hijerarhijskoj dekompoziciji
Ideja genetskog programiranja je da računala nauče rješavati probleme bez eksplicitnog
programiranja. Svako smanjenje složenosti problema je poželjno, a ono se može postići
pronalaskom pravilnosti i modularnosti korištenjem hijerarhijske dekompozicije. Veliki i
složeni problemi u praksi se obično ne rješavaju odjednom već se rastavljaju na
potprobleme. Automatsko programiranje računala će biti teško primjenjivo na složene
probleme ako će se svaki dio ukupnog rješenja promatrati kao zaseban događaj koji se
nikada više neće pojaviti ([10]). Za uspješnu primjenu automatskog programiranja na
probleme srednje i velike složenosti potrebna je hijerarhijska organizacija i ponovna
upotreba dijelova rješenja.
Hijerarhijska dekompozicija je privlačan način za stjecanje prednosti koja je potrebna za
rješavanje velikih problema. Međutim, postavlja se pitanje kako se taj postupak može
koristiti na automatiziran način neovisan o samoj domeni problema. Za pristup odozgo
prema dolje potrebno je odgovoriti na sljedeća pitanja:
• kako rastaviti problem na potprobleme?
• kako riješiti potprobleme?
• kako spojiti rješenja potproblema u rješenje početnog problema?
Pristup odozdo prema gore traži odgovorena ova pitanja:
• kako pronaći pravilnosti na niskoj razini okoline problema?
• kako obaviti promjenu prikaza problema, a da se pritom iskoriste pronađene
pravilnosti?
• kako riješiti početni problem pomoću novog prikaza problema?
Drugo pitanje pristupa odozgo prema dolje može se riješiti, u potpunosti ili približno,
genetskim programiranjem. No što je sa ostala dva pitanja? Pokazuje se da se ona ne mogu
riješiti klasičnim genetskim programiranjem, no tu dolaze na red automatski definirane
funkcije. Pomoću automatski definiranih funkcija cijeli se spektar problema može riješiti
na automatski i dinamičan način tijekom izvođenja genetskog programiranja.
22
2.3. Automatski definirane funkcije
2.3.1. Struktura automatski definiranih funkcija
Automatski definirane funkcije (engl. Automatically Defined Functions, ADF) proširuju
klasični prikaz rješenja u obliku stabla koji se koristi u genetskom programiranju. Prikaz
rješenja u obliku stabla sadrži jedno stablo koje označava rješenje. Automatski definirane
funkcije su stabla koja se dodaju glavnom stablu, a odnose se prema njemu kao procedura
prema glavnom programu – glavno stablo može po želji pozivati automatski definirane
funkcije, a pritom im može ili ne mora davati neke parametre. Struktura prikaza rješenja u
obliku stabla uz korištenje automatski definiranih funkcija prikazana je na slici ispod (Slika
2.6).
jedinka
ADF povratna vrijednost
ime
tijelo potprogramatijelo glavnogprograma
povratna vrijednostargumenti
1
2
3 4 5
6
7 8
Slika 2.6. Prikaz rješenja u obliku stabla koristeći jednu automatski definiranu funkciju
Svaka jedinka koja prikazuje rješenje u obliku stabla koristeći automatski definirane
funkcije sadrži osam vrsta čvorova. Čvorovi označeni brojevima 1-6 su nepromjenjivi, dok
su čvorovi 7 i 8 promjenjivi i sadrže program same grane. Broj nepromjenjivih čvorova je
isti u svim jedinkama i oni se nalaze uvijek na istom mjestu u strukturi rješenja.
Promjenjivi čvorovi su stabla sami za sebe i sadrže tijelo samog rješenja, a njihova dubina,
oblik i broj čvorova su različiti u različitim jedinkama. Kada se ne bi koristile automatski
definirane funkcije, postojali bi samo čvorovi 1, 6 i 8, a tada se zbog jednostavnosti
najčešće prikazuje samo čvor 8.
23
Čvor označen brojem 1 predstavlja korijen stabla. Čvor 2 označava automatski definiranu
funkciju čije se ime nalazi u čvoru 3, a lista argumenata u čvoru 4. Čvor 5 predstavlja
sučelje prema potprogramu čije se tijelo nalazi u čvoru 7. Nakon izvršavanja potprograma,
povratna se vrijednost preko čvora 5 prenosi u glavni program. Čvorovi 6 i 8 su u sličnom
odnosu kao i čvorovi 5 i 7 – čvor 6 je sučelje prema tijelu glavnog programa i služi za
prijenos povratne vrijednosti.
Svaka jedinka u populaciji sadrži glavni program i automatski definiranu funkciju. Glavni
program se još naziva i grana koja vraća rezultat (engl. result-producing branch), a
automatski definirana funkcija je grana koja definira funkciju (engl. function-defining
branch). Svaki put kad glavni program poziva automatski definiranu funkciju, on poziva
onu automatski definiranu funkciju koja pripada jedinki u kojoj se nalazi točno taj glavni
program. Jedinka nikada ne može upotrebljavati automatski definiranu funkciju neke druge
jedinke.
Varijable koje se koriste za rješavanje problema se nalaze u glavnom programu. One se
obično ne pojavljuju u automatski definiranim funkcijama, no moguće su i drugačije
implementacije. Automatski definirane funkcije obično imaju vlastite varijable koje se
najčešće imenuju arg0, arg1,…, argN, gdje je N broj parametara automatski definirane
funkcije.
Jedinka može imati više od jedne automatski definirane funkcije. Broj automatski
definiranih funkcija nije ograničen. Ukoliko se koristi više od jedne automatski definirane
funkcije, tada se broj vrsta čvorova u prikazu jedinke povećava (dupliciraju se brojevi 2, 3,
4, 5 i 7). Svaka automatski definirana funkcija može upotrebljavati bilo koju drugu
automatski definiranu funkciju na isti način kao što glavni program upotrebljava bilo koju
funkciju, no treba paziti da se ne napravi petlja (primjerice ako funkcija ADF0 poziva
ADF1, a ADF1 poziva ADF0). Petlja se najčešće izbjegava tako da svaka automatski
definirana funkcija može pozivati samo one automatski definirane funkcije koje su
definirane prije nje. Iako nije preporučljivo napraviti petlju, u teoriji se spominje da
automatski definirana funkcija može pozivati i samu sebe ([10]).
24
2.3.2. Prilagodbe za uporabu automatski definiranih funkcija
Prije primjene genetskog programiranja sa automatski definiranim funkcijama potrebno je
proširiti pripremne korake genetskog programiranja opisane u poglavlju 1.3.1.
Prvo je potrebno odabrati koliko će se automatski definiranih funkcija koristiti pri
genetskom programiranju. Ovaj odabir uvelike ovisi o složenosti problema – za veće
probleme preporučljivo je odabrati veći broj funkcija. Odabir broja funkcija može se
prepustiti i samom evolucijskom procesu ([10]). Nakon odabira broja funkcija potrebno je
odrediti način na koji će se one pozivati. Ako postoji samo jedna funkcija tada je situacija
u potpunosti jasna – glavni program poziva tu funkciju. No ako postoji više funkcija, treba
odrediti način na koji se funkcije mogu pozivati međusobno. Odabir broja i veza
automatski definiranih funkcija je novi pripremni korak i on je potreban samo ukoliko se
koriste automatski definirane funkcije, a obično se provodi prije pet standardnih
pripremnih koraka genetskog programiranja.
Nakon odabira broja automatski definiranih funkcija potrebno je odrediti skup terminala i
skup funkcija glavnog programa i svake automatski definirane funkcije. To su prva dva
pripremna koraka genetskog programiranja. Skup terminala glavnog programa τrpb je isti
kada se koriste automatski definirane funkcije kao i kada se one ne koriste. Skup funkcija
glavnog programa ƒrpb je unija skupa funkcija kada se ne koriste automatski definirane
funkcije i dostupnih automatski definiranih funkcija. Skup terminala svake automatski
definirane funkcije τadf jednak je ulaznim argumentima te funkcije, a skup funkcija svake
automatski definirane funkcije ƒadf jednak je skupu funkcija genetskog programiranja bez
automatski definiranih funkcija. To se formalno može zapisati:
τrpb=τ
ƒrpb={ADF0,ADF1,…,ADFN}υƒ
τadf={ARG0,ARG1,…,ARGN}
ƒadf=ƒ,
gdje je τ je skup terminala genetskog programiranja bez uporabe automatski definiranih
funkcija, a ƒ skup funkcija genetskog programiranja bez uporabe automatski definiranih
funkcija.
25
Preostali pripremni koraci (3, 4 i 5) jednaki su za genetsko programiranje sa i bez
automatski definiranih funkcija.
Prilikom križanja jedinki uz korištenje automatski definiranih funkcija potrebno je paziti
na strukturu jedinke. Križati se mogu samo promjenjivi čvorovi koji su istog tipa (engl.
structure-preserving crossover). To znači da se glavni program jedne jedinke može križati
samo s glavnim programom druge jedinke, a automatski definirana funkcija jedne jedinke s
automatski definiranom funkcijom druge jedinke. Glavni program jedne jedinke nikako se
ne smije križati sa automatski definiranom funkcijom druge jedinke jer bi tako nastale
nekonzistentne situacije, primjerice ako bi glavni program dobio neki terminal iz skupa
τadf ili ako bi automatski definirana funkcija dobila terminal iz skupa τrpb.
2.3.3. Svojstva automatski definiranih funkcija
Ljudi tijekom programiranja pišu potprograme kako bi ubrzali ili olakšali rješavanje nekog
problema. Iako automatski definirane funkcije slijede istu ideju, one su dio stohastičkog
procesa pa kod mnogih jedinki njihova implementacija često ne mora imati neku jasnu
funkciju. Automatski definirane funkcije mogu:
• računati nešto što bi i programer računao (primjerice u nekom potprogramu),
• računati nešto što programer ne bi nikada računao,
• redundantno definirati funkciju jednaku funkciji koja već postoji u skupu funkcija,
• redundantno definirati terminal vraćajući vrijednost jednog od svojih ulaznih
argumenata,
• ignorirati svoje ulazne argumente,
• biti ignorirane u glavnom programu,
• definirati konstantu,
• pozivati drugu automatski definiranu funkciju.
Programer nikada ne bi napisao potprogram koji ignorira vlastite ulazne argumente ili
potprogram koji se ignorira u glavnom programu. Međutim, automatski definiranoj
funkciji se upravo takve na prvi pogled neobične stvari mogu dogoditi i to je sasvim
normalna pojava.
26
Ukoliko neka jedinka ima glavni program koji uspješno rješava zadani problem i ne poziva
svoju automatski definiranu funkciju, tada ona ima bolju dobrotu od jedinke čiji glavni
program poziva automatski definiranu funkciju, ali ne rješava zadani problem. Iako je, sa
ljudskog stajališta, u potpunosti besmisleno da glavni program ne poziva svoju funkciju,
kod genetskog programiranja evolucija se odvija pod utjecajem dobrote, što znači da
jedinka sa boljom dobrotom ima veće šanse za preživljavanje, bez obzira na to poziva li
njen glavni program svoju automatski definiranu funkciju ili ne. Stoga su sasvim moguće
situacije u kojima je rješenje dobiveno evolucijskim procesom neobično ili na neki način
"glupo" jer primjerice ne poziva svoju automatski definiranu funkciju ili ima evidentnu
redundanciju podataka.
2.3.4. Svojstva genetskog programiranja sa ADF-om
Uporaba automatski definiranih funkcija omogućava genetskom programiranju da
automatski tijekom izvođenja algoritma otkriva korisne funkcijske podjedinice.
Konkurentna evolucija funkcijskih podjedinica i pozivajućih programa omogućava
genetskom programiranju implicitno provođenje hijerarhijske dekompozicije.
Rezultati dobiveni genetskim programiranjem sa automatski definiranim funkcijama mogu
se protumačiti kao primjena hijerarhijske dekompozicije. Međutim, nijedan od tri koraka
hijerarhijske dekompozicije se ne provodi eksplicitno – kod pristupa odozgo prema dolje
nema eksplicitne dekompozicije početnog problema u potprobleme, nema rješavanja
potproblema i nema spajanja rješenja potproblema u cjelovito rješenje, a kod pristupa
odozdo prema gore nema eksplicitnog traženja pravilnosti i uzoraka, nema promjene
prikaza problema i nema rješavanja početnog problema pomoću novog prikaza problema.
Hijerarhijska dekompozicija i promjena prikaza problema su važne karakteristike i
pripisuju se rezultatima dobivenim genetskim programiranjem sa automatski definiranim
funkcijama.
Genetsko programiranje sa automatski definiranim funkcijama ima sljedeća svojstva
([10]):
• automatski definirane funkcije omogućuju genetskom programiranju rješavanje
širokog spektra problema na način koji se može tumačiti kao hijerarhijska
dekompozicija,
27
• automatski definirane funkcije pronalaze i koriste pravilnosti, simetrije,
homogenosti, sličnosti i modularnost domene problema na način koji je različit od
načina koji primjenjuju ljudi,
• genetsko programiranje sa automatski definiranim funkcijama zahtijeva manje
utrošenih resursa za rješavanje širokog spektra problema nego genetsko
programiranje bez automatski definiranih funkcija,
• za mnoge složenije probleme genetsko programiranje sa automatski definiranim
funkcijama daje rješenja koja su manje veličine, manje složenosti, jednostavnija ili
brža nego genetsko programiranje bez automatski definiranih funkcija,
• povećanjem veličine problema, složenost rješenja dobivenih genetskim
programiranjem sa automatski definiranim funkcijama raste sporijim tempom od
složenosti rješenja dobivenih genetskim programiranjem bez automatski
definiranih funkcija,
• povećanjem veličine problema, vrijeme izvođenja genetskog programiranja sa
automatski definiranim funkcijama raste sporijim tempom od vremena izvođenja
genetskog programiranja bez automatski definiranih funkcija,
• genetsko programiranje može istovremeno rješavati problem i razvijati arhitekturu
cjelokupnog programa.
2.3.5. Usporedba s ostalim područjima umjetne inteligencije
Potreba za potprogramima koji se mogu ponovno iskoristiti postoji u svim područjima
umjetne inteligencije i strojnog učenja. Mnoge poznate paradigme, poput neuronskih
mreža, tijekom izvođenja automatski i dinamično definiraju funkcijske podjedinice.
Ukoliko se radi o prepoznavanju nekog uzorka, sve te paradigme omogućuju da se naučeni
uzorak prepozna na širem području pretrage, no one ne omogućuju hijerarhijsku
dekompoziciju u smislu da se uzorak prepozna samo jednom, zaključci generaliziraju i
ponovno upotrijebe koristeći parametre ([10]). Automatski definirane funkcije djeluju na
nešto drugačiji način od uobičajenih funkcijskih podjedinica i omogućuju generalizaciju
korištenjem hijerarhijske dekompozicije.
Postoji razlika u načinu rada neuronskih mreža i automatski definiranih funkcija.
Neuronska funkcija se poziva samo jednom u cijeloj mreži, a njene podatke koristi samo
28
ulazni sloj mreže. Ulazi neuronske mreže se uvijek nalaze u točno određenom fiksnom
skupu ulaza, a pojedini neuron dobiva uvijek isti dio ulaznog vektora. Posao koji obavlja
neki neuron bi možda bio koristan i u nekom drugom dijelu mreže. Isto tako, posao koji
obavlja cijeli dio mreže bi mogao biti koristan u nekom drugom dijelu mreže. Uobičajene
implementacije učenja neuronskih mreža ne pružaju mogućnost ponovnog iskorištavanja
veza i težina koje su otkrivene u jednom dijelu mreže. One se ne mogu iskoristiti u drugim
dijelovima mreže u kojima se mora obaviti sličan zadatak, ali sa drugačijim vrijednostima
ulaza.
U neuronskim mrežama nema propagiranja generalizirane strukture – ne postoje argumenti
koji omogućuju pozivanje dijela neuronske mreže sa drukčijim skupom ulaza i nema
ponovne iskoristivosti jednog neurona na više od jednog mjesta. Umjesto toga, algoritam
za učenje neuronske mreže mora neovisno otkriti sve kombinacije težina i pragova za sve
neurone koji izvode isto ili slično izračunavanje na nekom skupu ulaza.
29
3. Evolutionary Computation Framework
3.1. Što je Evolutionary Computation Framework?
Evolutionary computation framework (ECF) je skup programskih alata koji omogućuje
izvođenje evolucijskih algoritama. Razvija se na Fakultetu elektrotehnike i računarstva
(FER) u Zagrebu, a paralelno se implementiraju C++ i Java inačica. U nastavku rada se
razmatra Java inačica čiji je subversion (svn) repozitorij dostupan za čitanje na adresi
svn://smaug.zemris.fer.hr/ecfj. U repozitoriju se nalaze izvorni kod, javadoc dokumentacija
i jar datoteka koja sadrži sve ECF razrede zapakirane u jednu biblioteku.
Iako slovi kao jedan od sporijih programskih jezika, Java ima svojih prednosti za pisanje
aplikacija koje zahtijevaju puno računanja. Java je platformski neovisan jezik, što znači da
se aplikacije pisane na jednom operacijskom sustavu mogu koristiti u bilo kojoj drugoj
okolini, bez potrebe za ponovnim prevođenjem ili promjenama u programskom kodu.
Jedini uvjet je da mora postojati Java virtualni stroj (engl. Java Virtual Machine) za
korišteni operacijski sustav, ali to nije problem jer postoji inačica virtualnog stroja za svaki
poznatiji operacijski sustav današnjice.
Druga velika prednost Jave je u jednostavnosti korištenja. Za pokretanje aplikacije pisane u
većini ostalih programskih jezika (primjerice C/C++) najčešće je potrebno prethodno
instalirati niz dodatnih biblioteka funkcija (engl. library), dok je u Javi puno toga već
ugrađeno u sam programski jezik ([11]). Za korisnika je prednost što se pokretanje
programa u Javi najčešće svodi na dvoklik na izvršnu jar datoteku, bez potrebe za
ponovnim prevođenjem cijelih projekata.
3.2. Pokretanje
Jedan od ciljeva ECF-a je pojednostaviti i olakšati uporabu evolucijskih algoritama za
krajnjeg korisnika. U ovom je poglavlju objašnjeno što sve korisnik mora napraviti kako bi
iskoristio ECF za rješavanje problema brojanja broja jedinica u nizu bitova (engl. onemax
problem) koristeći genetski algoritam. Idealno je rješenje čiji niz bitova sadrži sve jedinice,
a najlošije ono u kojem niz bitova sadrži nule na svim mjestima.
30
Kako bi korisnik koristio ECF, on mora uključiti u svoj projekt izvorni kod ili jar
datoteku od frameworka. Jar datoteka mora biti u korijenskom direktoriju projekta kako
bi učitavanje razreda funkcioniralo ispravno, no o tome više u poglavlju 3.3.2.
Aktivnosti korisnika pri korištenju ECF-a mogu se podijeliti u tri koraka:
1. Definiranje parametara
2. Definiranje metode za izračunavanje dobrote
3. Pokretanje algoritma
3.2.1. Definiranje parametara
Parametri algoritma se definiraju u konfiguracijskoj XML datoteci. Ime konfiguracijske
datoteke se zadaje se prvim parametrom iz komandne linije, a pretpostavljeno ime je
Parametri.xml. Definiranje konfiguracijske datoteke je uvjet za pokretanje algoritma.
Primjer konfiguracijske datoteke prikazan je na sljedećoj slici (Slika 3.1). Navedena
konfiguracijska datoteka omogućuje rješavanje onemax problema koristeći ECF. U njoj je
navedena većina parametara ECF-a, a ti su parametri u nastavku teksta objašnjeni.
<ECF>
<Algorithm>
<SteadyStateTournament>
<Entry key="tsize">3</Entry>
</SteadyStateTournament>
</Algorithm>
<Genotype>
<BitString>
<Entry key="size">20</Entry>
<Entry key="crx.onepoint">0.6</Entry>
<Entry key="crx.uniform">0.4</Entry>
<Entry key="mut.simple">0.7</Entry>
<Entry key="mut.mix">0.3</Entry>
</BitString>
</Genotype>
<Registry>
<!-- populacija -->
31
<Entry key="population.size">4000</Entry>
<Entry key="population.demes">1</Entry>
<Entry key="migration.freq">0</Entry>
<Entry key="migration.number">2</Entry>
<!-- operatori -->
<Entry key="mutation.indprob">0.5</Entry>
<Entry key="mutation.genotypes">random</Entry>
<Entry key="crossover.genotypes">random</Entry>
<!-- uvjeti završetka -->
<Entry key="term.maxgen">50</Entry>
<Entry key="term.maxtime">3000</Entry>
<Entry key="term.stagnation">10</Entry>
<!-- vođenje dnevnika -->
<Entry key="log.level">3</Entry>
<Entry key="log.filename">log.txt</Entry>
<Entry key="log.frequency">1</Entry>
</Registry>
</ECF>
Slika 3.1. Konfiguracijska datoteka za rješavanje onemax problema
Čvor Algorithm predstavlja implementaciju samog algoritma. U Java inačici ECF-a
implementiran je samo SteadyStateTournament algoritam objašnjen u poglavlju
1.2.2. Parametar tsize određuje veličinu turnira pri selekciji, a njegova pretpostavljena
vrijednost je turnir veličine 3. Konfiguracijska datoteka mora sadržavati točno jedan čvor
tipa Algorithm.
Čvor Genotype sadrži navedene genotipove koji se koriste u algoritmu. U Java inačici
ECF-a implementirani su BitString, Binary, FloatingPoint, Permutation i
Tree genotipovi. Konfiguracijska datoteka mora sadržavati točno jedan čvor tipa
Genotype, no unutar njega može biti proizvoljan broj genotipova. Svaki genotip dobiva
svoj indeks, a indeksi započinju od nule. Za rješavanje onemax problema dovoljan je jedan
genotip tipa BitString. ECF njemu dodjeljuje indeks 0.
Unutar BitString čvora dolaze podaci potrebni za korištenje pojedinog genotipa. Za
BitString genotip je potrebno znati samo duljinu niza bitova zadanu parametrom
32
size. Parametri koji započinju sa crx označavaju izbor križanja koje će se koristiti u tom
BitString genotipu, a parametri koji započinju sa mut označavaju izbor mutacije.
Svaki genotip može koristiti proizvoljan broj križanja i mutacija, a vrijednost parametra
označava vjerojatnost korištenja tog križanja ili te mutacije. Potrebno je paziti da zbroj svih
vjerojatnosti križanja i svih vjerojatnosti mutacija mora biti jednak 1. Ukoliko to nije
zadovoljeno, framework će generirati upozorenje (engl. warning) i nastaviti s radom. U
navedenoj konfiguracijskoj datoteci zadano da će se križanje s jednom točkom prekida
(crx.onepoint) koristiti u 60% slučajeva, a uniformno križanje (crx.uniform) u
40% slučajeva. Ista stvar vrijedi i za mutaciju – mutacija koja mijenja vrijednost nekog bita
(mut.simple) će se izvoditi u 70% slučajeva, a mutacija koja bitove između dvije točke
preslaguje slučajnim odabirom (mut.mix) u 30% slučajeva.
Čvor Registry služi za definiranje preostalih parametara. Tu spadaju parametri o
populaciji, operatori, uvjeti završetka i parametri o vođenju dnevnika.
Population.size predstavlja broj jedinki populacije, a njegova pretpostavljena
vrijednost je 100. To je jedan od najvažnijih parametara i svakako se preporuča njegovo
definiranje u svakoj konfiguracijskoj datoteci. Population.demes je broj otoka (engl.
deme) populacije. Njegova pretpostavljena vrijednost je 1, a ako se koristi broj veći od 1,
tada svaki otok ima population.size jedinki. Uz otoke je vezan i operator migracije.
Kako bi se koristila migracija, moraju postojati barem dva otoka. Migracija se odvija tako
da se svakih migration.freq generacija izmjenjuje migration.number jedinki.
Pri razmjeni se koristi prstenasta topologija.
Parametri mutation.genotypes i crossover.genotypes su važni samo ako se
koristi više od jednog genotipa. Ti parametri određuju koji će se genotipovi mutirati i
križati. Može se odabrati random što znači da će se genotip koji će se mutirati ili križati
odrediti slučajnim odabirom ili all što znači da će se mutirati ili križati svi genotipovi.
Pretpostavljena vrijednost ovih parametara je random. Parametar mutation.indprob
određuje vjerojatnost mutacije. Ne valja ga miješati sa parametrima poput mut.simple
ili mut.mix koji određuju omjere korištenja pojedinih mutacija ili križanja. Ako je
primjerice u konfiguracijskoj datoteci zadano mutation.indprob=0.2,
mut.simple=0.7 i mut.mix=0.3 tada će se mutacija provoditi s vjerojatnošću od
20%, a od tih 20% će 70% puta biti provedena mutacija mut.simple i 30% puta
mut.mix. Efektivna šansa pojedine mutacije dobije se množenjem njene vjerojatnosti s
33
mutation.indprob pa tako ispada da je efektivna vjerojatnost provođenja mutacije
mut.simple 14%, a mutacije mut.mix 6%.
Parametri vezani uz uvjet završetka ne moraju biti navedeni. Implementirana su tri kriterija
završetka: broj generacija algoritma (term.maxgen), vrijeme izvođenja algoritma
(term.maxtime) koje se mjeri u sekundama i broj uzastopnih generacija bez napretka
(term.stagnation). Ovi se parametri mogu i kombinirati, a ukoliko se ne navede niti
jedan od njih algoritam će se izvoditi beskonačno dugo, tj. dok se ne prekine njegov
proces. Ukoliko se pod vrijednost parametra term.stagnation upiše 0 tada se uzima
pretpostavljena vrijednost koja iznosi 5000/population.size.
Tablica 3.1. Vođenje dnevnika u ECF-u
log.level podaci o radu algoritma koji se zapisuju u log datoteku
1
podaci o učitanim razredima, greške pri izvođenju, najbolja jedinka i cijela
populacija nakon završetka algoritma, kriterij završetka koji je uzrokovao
prekid algoritma
2 broj generacije, proteklo vrijeme, upozorenja
3 vrijeme početka izvođenja
4 najbolja jedinka svake generacije
5
stanje cijele populacije, podaci o (ne)uspješnosti križanja i mutacija,
dobrote jedinki u turniru, dobrota najlošije jedinke turnira i jedinke koja ju
zamjenjuje
Parametri vezani uz vođenje dnevnika (engl. logging) su log.level, log.filename i
log.frequency. Podaci se u log datoteku imena log.filename i na ekran zapisuju
svakih log.frequency generacija sa razinom log.level. Vrijednost log.level
parametra se može odabrati iz intervala [1, 5] gdje veći broj znači opširnije zapisivanje
podataka. Tablica 3.1 prikazuje što se sve zapisuje u log datoteku pri različitim
vrijednostima log.level parametra. Zapisivanje pri većim log.level vrijednostima
uključuje i sve zapise manjih log.level vrijednosti. Tako se pri log.level=1
34
zapisuju samo podaci nabrojani u prvom retku tablice, dok se pri log.level=5 zapisuju
svi podaci navedeni u tablici (svih 5 redaka).
3.2.2. Definiranje metode za izračunavanje dobrote
Metoda za izračunavanje dobrote ovisi o vrsti problema i stoga ne može biti definirana
unutar frameworka već ju mora implementirati sam korisnik. Kako bi to napravio, korisnik
mora implementirati sučelje IEvaluate. Ovo sučelje sadrži četiri metode:
• evaluate() – metoda u kojoj se vrši izračunavanje dobrote.
• createFitness() – metoda u kojoj se kreira Fitness, objekt koji se koristi
za usporedbu jedinki u algoritmu.
• registerParameters() – metoda za registriranje parametara sučelja
IEvaluate. Ukoliko parametri nisu potrebni, implementacija ove metode može
ostati prazna.
• initialize() – metoda za inicijalizaciju sučelja IEvaluate. Ukoliko
inicijalizacija sučelja nije potrebna, implementacija ove metode može ostati prazna.
Za rješavanje jednostavnog onemax problema registriranje dodatnih parametara i
eksplicitna inicijalizacija sučelja nisu potrebni pa se implementacije metoda
registerParameters() i initialize() mogu ostaviti prazne. Primjer moguće
implementacije metoda createFitness() i evaluate() prikazan je u nastavku
(Slika 3.2).
public void evaluate(Fitness fitness) {
BitString bitstring = (BitString) fitness.getIndividual().get(0);
double value = 0.0;
//onemax problem - brojim jedinice u kromosomu
for (int i = 0; i < bitstring.size(); i++) {
if (bitstring.get(i) == 1) {
value++;
}
}
fitness.setValue(value);
}
35
public Fitness createFitness() {
return new FitnessMax();
}
Slika 3.2. Implementacija sučelja IEvaluate za rješavanje onemax problema
3.2.3. Pokretanje algoritma
Pokretanje ECF-a se svodi na kreiranje State objekta, njegovo inicijaliziranje i poziv
metode run() kojom se pokreće algoritam. Slika 3.3 pokazuje pokretanje algoritma za
rješavane onemax problema. Razredu State se u konstruktoru predaje referenca na razred
koji implementira sučelje IEvaluate na način kako je to objašnjeno u poglavlju 3.2.2.
public static void main(String[] args) {
State state = new State(ievaluate);
state.initialize(args);
state.run();
}
Slika 3.3. Pokretanje ECF-a
3.3. Dinamičko učitavanje genotipova i algoritama
3.3.1. Statičko i dinamičko učitavanje razreda
U Java inačici ECF-a svi genotipovi i algoritmi se učitavaju dinamički. Za to se koriste
Java classloaderi koji omogućuju dinamičko učitavanje razreda u Java virtualni stroj. U
nastavku ovog poglavlja pričat će se o dinamičkom učitavanju genotipova, a analogna
priča vrijedi i za učitavanje cijelih algoritama.
Dinamičko učitavanje genotipova za korisnika znači jednostavnije dodavanje novih
genotipova. Kod statičkog učitavanja korisnik bi morao svoj genotip prvo navesti u
konfiguracijskoj datoteci, a zatim ga ručno dodati u skup genotipova frameworka pozivom
funkcije za dodavanje novog genotipa. Tako korisnik obavlja dvostruki posao koji može
dovesti do grešaka poput zaboravljanja dodavanja genotipa na jedno od ta dva mjesta. Taj
se problem rješava dinamičkim učitavanjem u kojem korisnik mora svoj genotip dodati
samo u konfiguracijsku datoteku, a Java virtualni stroj se pobrine za dodavanje genotipa u
skup genotipova.
36
3.3.2. Implementacija u ECF-u
Kako bi ECF znao gdje tražiti nove genotipove (one koje je implementirao korisnik)
potrebno je definirati direktorij u kojem će se svi takvi razredi nalaziti. Taj direktorij se
frameworku predaje u obliku drugog parametra iz komandne linije (prvi parametar je ime
konfiguracijske datoteke). Primjerice, ako se ECF pokrene koristeći naredbu
java ecf.examples.OneMax Parametri.xml MojiGenotipovi
tada će pokrenuti algoritam imati sljedeća svojstva:
• razred ecf.examples.OneMax sadrži glavni program koji rješava zadani
problem,
• konfiguracijska datoteka algoritma je Parametri.xml,
• direktorij s dinamičkim razredima je MojiGenotipovi.
Kako bi ECF znao ispravno prepoznati genotipove i algoritme, korisnik se mora držati
definirane strukture direktorija koja je zadana sa sljedećih 6 pravila:
1. svi algoritmi moraju biti u paketu ecf.algorithm
2. svi genotipovi moraju biti u paketu ecf.genotype.[imeGenotipa]
3. sva križanja i mutacije nekog genotipa moraju biti u paketu
ecf.genotype.[imeGenotipa]
4. imena svih križanja moraju biti oblika [imeGenotipa]Crx[imeKrižanja]
5. imena svih mutacija moraju biti oblika [imeGenotipa]Mut[imeMutacije]
6. svi parametri unutar čvora Genotype koji predstavljaju križanje moraju imati ime
koje započinje sa crx., oni koji predstavljaju mutaciju moraju imati ime koje
započinje sa mut., a ostali moraju imati ime koje ne započinje niti sa crx. niti sa
mut.
Iako se ova pravila na prvi pogled doimaju strogo, njihovo poštivanje je vrlo prirodno i
jednostavno, a pravila dodatno tjeraju korisnika na smisleno i dosljedno davanje imena
svojim algoritmima, genotipovima, križanjima i mutacijama.
Struktura direktorija većinom je definirana izborom Java paketa. Java paketi su način za
organiziranje Java razreda. Ime Java paketa izravno je povezano sa strukturom direktorija
37
na disku računala. Primjerice, ako se java razred BitString nalazi u paketu
ecf.genotype to znači da se datoteka BitString.class nalazi u direktoriju
ecf/genotype. Slika 3.4 prikazuje strukturu direktorija koju je potrebno napraviti
ukoliko se želi koristiti SteadyStateTournament algoritam te BitString i
Binary genotipovi sa po dva križanja (CrxUniform i CrxOnePoint) i dvije mutacije
(MutSimple i MutMix). Slika pretpostavlja da je MojiGenotipovi direktorij koji je
odabran kao direktorij s dinamičkim razredima.
Slika 3.4. Struktura direktorija za dinamičko učitavanje razreda
ECF traži dinamičke razrede na četiri mjesta:
1. u ./ECF.jar datoteci
2. u direktoriju ./bin koji je pretpostavljeni direktorij sa Java razredima razvijenim
u programskom okruženju Eclipse
3. u direktoriju ./build/classes koji je pretpostavljeni direktorij sa Java
razredima razvijenim u programskom okruženju NetBeans.
4. u direktoriju s dinamičkim razredima koji se može definirati koristeći drugi
argument iz komandne linije
Ukoliko se koristi ECF zapakiran u jar datoteku, preporuča se da se ta datoteka nazove
ECF.jar i stavi u aktivni direktorij (aktivni direktorij je onaj direktorij iz kojeg se
pokreće program, a označava se sa "."). Razlog tome je što se unutar jar datoteke nalaze
implementirani neki genotipovi i steady-state tournament algoritam, a ECF.jar datoteka
38
u trenutno aktivnom direktoriju je jedno od mjesta na kojem se traže razredi za dinamičko
učitavanje.
3.4. Prikaz rješenja u obliku stabla
Jedinke su u genetskom programiranju prikazane u obliku stabla. Kako bi se omogućilo
genetsko programiranje u ECF-u, implementiran je Tree genotip koji sadrži potrebni
prikaz rješenja u obliku stabla. Prikaz jedinki u obliku stabla objašnjen je u poglavlju 1.3
koje govori o genetskom programiranju. U nastavku ovog poglavlja opisana je
implementacije Tree genotipa u ECF-u.
Tree genotip se sastoji od niza čvorova koji se nazivaju primitivi. Primitivi mogu biti
terminali ili funkcije. Implementirano je sljedećih 10 funkcija:
• Add – funkcija koja predstavlja operaciju zbrajanja,
• Sub – funkcija koja predstavlja operaciju oduzimanja,
• Mul – funkcija koja predstavlja operaciju množenja,
• Div – funkcija koja predstavlja operaciju dijeljenja. Obzirom da skup primitiva
mora zadovoljavati uvjet zatvorenosti, u slučaju dijeljenja s nulom vraća se 1,
• Max – funkcija koja vraća veći od dva argumenta,
• Min – funkcija koja vraća manji od dva argumenta,
• Pos – funkcija koja vraća ulazni argument ako je on veći od nule, a u protivnome
vraća 0,
• Neg – funkcija koja vraća ulazni argument ako je on manji od nule, a u protivnome
vraća 0,
• Sin – funkcija koja predstavlja operaciju sinus,
• Cos – funkcija koja predstavlja operaciju kosinus.
Svi primitivi u frameworku su implementirani koristeći Java predloške (engl. Java
generics). Predlošci omogućuju baratanje sa objektima različitog tipa, a pritom osiguravaju
da prevoditelj može detektirati grešku prilikom prevođenja programa (engl. compile-time
safety). Iako imaju sličnosti sa C++ predlošcima (engl. template), Java predlošci ne
39
dopuštaju metaprogramiranje (engl. template metaprogramming) i ne generiraju novi
razred za svaku specijalizaciju ([12]).
Dodatne funkcije za Tree genotip mogu se dodati u framework koristeći metodu
addUserDefinedFunction() razreda PrimitiveSet. Dodavanje je potrebno
napraviti prije inicijalizacije razreda State, a može i ranije. Primjer dodavanja korisnički
definirane funkcije prikazan je na sljedećoj slici (Slika 3.5). U primjeru korisnički
definirana funkcija se zove UserFunction i djeluje nad brojevima (Number). Jedina
razlika između pokretanja algoritma koristeći korisnički definirane funkcije i bez njih je u
jednoj liniji koda u kojoj se korisnički definirana funkcija dodaje u skup primitiva
frameworka.
public static void main(String[] args) {
PrimitiveSet.addUserDefinedFunction(new UserFunction<Number>());
State state = new State(ievaluate);
state.initialize(args);
state.run();
}
Slika 3.5. Dodavanje korisnički definirane funkcije i pokretanje algoritma
Križanjem dvaju roditelja u evolucijskim algoritmima obično nastaju dva djeteta, no mogu
se koristiti implementacije u kojima se uzima samo jedno od ta dva djeteta. Takav način
implementacije se koristi i u ECF-u, a njime se rješava problem kreiranja neparnog broja
djece. Za Tree genotip su implementirana dva križanja (jednostavno i uniformno) i dvije
mutacije (zamjena čvora i permutacija podstabala).
3.4.1. Jednostavno križanje
Jednostavno križanje (TreeCrxSimple) prikazano je na sljedećoj slici (Slika 3.6).
Slučajnim se odabirom odabire točka križanja na svakom od roditelja. Točke križanje su na
slici prikazane plavim rubom. Dijete nastaje tako da se kopija podstabla čiji je korijen
točka križanja jednog roditelja zamjenjuje sa kopijom podstabla čiji je korijen točka
križanja drugog roditelja. Kopije se koriste da se izbjegne dovođenje roditelja u
nekonzistentno stanje ukoliko bi jedan roditelj dao više djece.
40
+
- *
2 X 3 4
*
/ +
X Y 1
*
/
X Y
-
2 X
roditelj 2roditelj 1
dijete
Slika 3.6. Jednostavno križanje stabala
Problem koji se može javiti pri ovakvoj izvedbi križanja je da su šanse da se u stablu
slučajnim odabirom izabere list vrlo velike. U svakom stablu barem pola čvorova su
listovi, a udio listova još raste ako se koriste stabla koja nisu binarna. Zbog toga se
jednostavnim križanjem često izmjenjuje vrlo mali dio genetskog materijala pa se ono
često svede na jednostavnu izmjenu dvaju listova. Zbog toga se uvodi dodatni parametar
koji se naziva functionprob, a on određuje kolika je vjerojatnost da se pri križanju
odabere čvor koji je funkcija. Čvorovi koji su funkcije ujedno nisu listovi pa se tako
rješava problem prečestog odabira listova. Iako functionprob može poprimiti bilo koju
vrijednost iz intervala [0,1], on se najčešće postavlja na 0.8 ili 0.9.
41
3.4.2. Uniformno križanje
Slika 3.7 prikazuje uniformno križanje dvaju stabala (TreeCrxUniform). Područje
roditelja u kojem oni imaju zajedničku strukturu naziva se zajedničko područje (engl.
common region) i na slici je označeno plavom bojom. Za svaki čvor unutar zajedničkog
područja slučajnim se odabirom bira roditelj čiji će se čvor na toj poziciji kopirati u dijete.
Ako se čvor nalazi na dnu (rubu) zajedničkog područja, tada se cijelo podstablo tog čvora
kopira zajedno sa njim u stablo djeteta ([13]).
Na slici su sivom bojom označeni čvorovi koji se iz roditelja kopiraju u dijete. Čvorovi
označeni crvenim rubom su odabrani za kopiranje u dijete, a nalaze se na granici
zajedničkog područja pa se njihovo cijelo podstablo kopira u dijete.
+
/
+ X
*
3 4
dijete
roditelj 1
*
/ +
+ Y 1
5 6
+
- *
2 X 3 4
roditelj 2
5 6
Slika 3.7. Uniformno križanje stabala
42
3.4.3. Mutacija zamjenom čvora
Slika 3.8 prikazuje mutaciju zamjenom čvora (TreeMutNodeReplace). Na
roditeljskom stablu se odabire jedan čvor i njegov se primitiv mijenja sa drugim
primitivom iz skupa primitiva koji ima isti broj argumenata kao i primitiv koji se
zamjenjuje. Odabrani čvor je prikazan sivom bojom.
Slika 3.8. Mutacija zamjenom čvora
3.4.4. Mutacija permutacijom podstabala
Mutacija permutacijom podstabala (TreeMutPermutation) odabire funkciju koja sadrži
barem dva argumenta i njena dva slučajno odabrana podstabla zamjenjuje. Postupak je
prikazan na slici ispod (Slika 3.9). Sivom bojom je označena funkcija čija se podstabla
zamjenjuju.
Slika 3.9. Mutacija permutacijom podstabala
43
3.5. Pokretanje genetskog programiranja
O ovom je poglavlju opisano pokretanje genetskog programiranja koristeći ECF. Postupak
je isti kao i postupak pokretanja genetskog algoritma opisan u poglavlju 3.2, no ovaj se put
koristi prikaz rješenja u obliku stabla. Potrebno je definirati konfiguracijsku datoteku,
metodu za izračunavanje dobrote i pokrenuti algoritam. Primjer konfiguracijske datoteke
prikazan je na slici ispod (Slika 3.10).
<ECF>
<Algorithm>
<SteadyStateTournament>
<Entry key="tsize">3</Entry>
</SteadyStateTournament>
</Algorithm>
<Genotype>
<Tree>
<Entry key="maxdepth">5</Entry>
<Entry key="mindepth">2</Entry>
<Entry key="functionset">+ * - /</Entry>
<Entry key="terminalset">X</Entry>
<Entry key="mut.nodereplace">0.5</Entry>
<Entry key="crx.uniform">0.5</Entry>
<Entry key="mut.permutation">0.5</Entry>
<Entry key="crx.simple">0.5</Entry>
<Entry key="functionprob">0.9</Entry>
</Tree>
</Genotype>
<Registry>
<Entry key="population.size">4000</Entry>
<Entry key="population.demes">1</Entry>
<Entry key="mutation.indprob">0.5</Entry>
<Entry key="mutation.genotypes">random</Entry>
<Entry key="crossover.genotypes">random</Entry>
<Entry key="term.maxgen">50</Entry>
<Entry key="log.level">4</Entry>
<Entry key="log.filename">log.txt</Entry>
<Entry key="log.frequency">1</Entry>
44
<Entry key="domain"> -10.0 -8.0 -6.0 -4.0 -2.0 0.0 2.0 4.0
6.0 8.0 10.0 </Entry>
<Entry key="codomain"> 1010090.0 266296.0 47982.0 4364.0 82.0
0.0 86.0 4372.0 47994.0 266312.0 1010110.0 </Entry>
</Registry>
</ECF>
Slika 3.10. Konfiguracijska datoteka za genetsko programiranje
Većina parametara datoteke je ista kao i kada se koristi BitString genotip u
kombinaciji sa genetskim algoritmom (poglavlje 3.2.1). Tako je definirano da će se
populacija sastojati od 4000 jedinki, vjerojatnost mutacije će biti 0.5, a algoritam će se
izvršavati 50 generacija. Velik broj jedinki u populaciji u kombinaciji sa manjim brojem
generacija česta je kombinacija u genetskom programiranju.
Parametri vezani uz Tree genotip su maxdepth, mindepth, functionset i
terminalset, a oni zapravo definiraju pripremne korake genetskog programiranja
objašnjene u poglavlju 1.3.1. Veličina stabla ograničena je parametrom maxdepth na
najveću dubinu 5 i parametrom mindepth na najmanju dubinu 2. U genetskom
programiranju križanjima često nastaju sve veća stabla, a ograničenjem njihove veličine
može se spriječiti pretjerani rast složenosti rješenja. Parametar functionset predstavlja
skup funkcija, a terminalset skup terminala genetskog programiranja. Ova
konfiguracijska datoteka napisana je tako da koristi obje mutacije i oba križanja sa
vjerojatnošću od 50%. Parametar functionprob odnosi se na jednostavno križanje, a
objašnjen je u poglavlju 3.4.1.
Dva nova parametra su domain i codomain, a oni sadrže podatke o ulazima i
očekivanim izlazima simboličke regresije. Pri simboličkoj regresiji (engl. Symbolic
Regression) nastoji se pronaći analitički oblik nepoznate funkcije koja je zadana
određenim brojem parova ulaz – izlaz. Te parove mora definirati korisnik pri
implementaciji sučelja za evaluaciju dobrote IEvaluate, a pritom može koristiti metode
registerParameters() i initialize() čija je implementacija ostavljena
praznom prilikom pokretanja genetskog algoritma. Primjer implementacije sučelja
IEvaulate i pokretanja algoritma prikazan je na sljedećoj slici (Slika 3.11). Samo
pokretanje frameworka isto je kao u poglavlju 3.2.3.
45
public class SymbolicRegression implements IEvaluate {
private Vector<Double> domain = new Vector<Double>();
private Vector<Double> codomain = new Vector<Double>();
private State state;
public static void main(String[] args) {
SymbolicRegression symb = new SymbolicRegression();
symb.pokreni(args);
}
private void pokreni(String[] args) {
state = new State(this);
state.initialize(args);
state.run();
}
@Override
public Fitness createFitness() {
return new FitnessMin();
}
@Override
public void evaluate(Fitness fitness) {
Tree tree = (Tree)fitness.getIndividual().get(0);
double value = 0;
for(int i=0;i<domain.size();i++){
tree.setTerminalValue("X", domain.get(i));
double result = (Double)tree.execute();
value += Math.abs(codomain.get(i) - result);
}
fitness.setValue(value);
}
@Override
public void initialize() {
String domena =
state.getRegistry().getEntry("domain").trim();
46
String kodomena =
state.getRegistry().getEntry("codomain").trim();
String[] domenaPolje = domena.split("\\s+");
String[] kodomenaPolje = kodomena.split("\\s+");
if(domenaPolje.length!=kodomenaPolje.length){
throw new IllegalArgumentException("Error: Evaluation
operator initialization failed!");
}
for(int i=0;i<domenaPolje.length;i++){
domain.add(Double.valueOf(domenaPolje[i]));
codomain.add(Double.valueOf(kodomenaPolje[i]));
}
}
@Override
public void registerParameters() {
state.getRegistry().registerEntry("domain", "");
state.getRegistry().registerEntry("codomain", "");
}
Slika 3.11. Implementacija sučelja IEvaluate i pokretanje algoritma
U metodi registerParameters() potrebno je registrirati parametre koji će se
koristiti u konfiguracijskoj datoteci, a koje nije registrirao sam framework. U ovom slučaju
to su već spominjani domain i codomain. Registracijom parametara frameworku se
kaže da obrati pozornost na njih i učita ih iz konfiguracijske datoteke. Kada parametri ne bi
bili registrirani, ECF bi ih ignorirao.
U metodi initialize() se učitavaju vrijednosti tih dvaju parametara u memoriju.
Učitane vrijednosti se koriste pri implementaciji metode evaluate() za računanje
dobrote pojedinih rješenja. U ovom se primjeru dobrota računa kao suma apsolutnih
vrijednosti pogreške, a koristi se FitnessMin objekt što znači da je dobrota tim bolja
čim je njezina vrijednost manja.
47
3.6. Uporaba automatski definiranih funkcija
U ovom je poglavlju objašnjeno pokretanje genetskog programiranja uz uporabu
automatski definiranih funkcija. Kako bi se koristile automatski definirane funkcije,
potrebno je napraviti izmjene u konfiguracijskoj datoteci i metodi za evaluaciju dobrote.
Primjer konfiguracijske datoteke prikazan je na slici ispod (Slika 3.12).
<ECF>
<Algorithm>
<SteadyStateTournament>
<Entry key="tsize">3</Entry>
</SteadyStateTournament>
</Algorithm>
<Genotype>
<Tree>
<Entry key="adf">ADF0</Entry>
<Entry key="maxdepth">1</Entry>
<Entry key="mindepth">1</Entry>
<Entry key="functionset">+ * - /</Entry>
<Entry key="terminalset">ARG0 ARG1</Entry>
<Entry key="mut.nodereplace">0.5</Entry>
<Entry key="crx.uniform">0.5</Entry>
<Entry key="mut.permutation">0.5</Entry>
<Entry key="crx.simple">0.5</Entry>
<Entry key="functionprob">0.9</Entry>
</Tree>
<Tree>
<Entry key="maxdepth">4</Entry>
<Entry key="mindepth">2</Entry>
<Entry key="functionset">+ * - / ADF0</Entry>
<Entry key="terminalset">X</Entry>
<Entry key="mut.nodereplace">0.5</Entry>
<Entry key="crx.uniform">0.5</Entry>
<Entry key="mut.permutation">0.5</Entry>
<Entry key="crx.simple">0.5</Entry>
<Entry key="functionprob">0.9</Entry>
</Tree>
</Genotype>
48
<Registry>
<Entry key="population.size">4000</Entry>
<Entry key="population.demes">1</Entry>
<Entry key="mutation.indprob">0.1</Entry>
<Entry key="mutation.genotypes">random</Entry>
<Entry key="crossover.genotypes">random</Entry>
<Entry key="term.maxgen">150</Entry>
<Entry key="log.level">4</Entry>
<Entry key="log.filename">log.txt</Entry>
<Entry key="log.frequency">1</Entry>
<Entry key="domain"> -10.0 -8.0 -6.0 -4.0 -2.0 0.0 2.0 4.0
6.0 8.0 10.0 </Entry>
<Entry key="codomain"> 1010090.0 266296.0 47982.0 4364.0 82.0
0.0 86.0 4372.0 47994.0 266312.0 1010110.0 </Entry>
</Registry>
</ECF>
Slika 3.12. Konfiguracijska datoteka za korištenje automatski definiranih funkcija
Konfiguracijska datoteka vrlo je slična konfiguracijskoj datoteci za pokretanje genetskog
programiranja bez automatski definiranih funkcija objašnjenoj u poglavlju 3.5. Jedina
razlika je u Genotype dijelu konfiguracijske datoteke koji sada sadrži dva genotipa –
jedan koji je automatski definirana funkcija i drugi koji predstavlja glavni program. Svi
genotipovi koji predstavljaju automatski definirane funkcije u konfiguracijskoj datoteci
moraju biti navedeni prije genotipova koji koriste te automatski definirane funkcije. U
primjeru sa jednom automatski definiranom funkcijom, genotip koji predstavlja automatski
definiranu funkciju mora biti naveden prije genotipa koji predstavlja glavni program.
Prvi genotip predstavlja automatski definiranu funkciju imena ADF0. Svi genotipovi koji
predstavljaju automatski definirane funkcije moraju imati definiran parametar adf i u
njemu zadano ime automatski definirane funkcije. Ime svake automatski definirane
funkcije mora biti jedinstveno. Parametar terminalset koji predstavlja skup terminala
kod automatski definiranih funkcija označava broj i imena argumenata te funkcije. U ovom
primjeru automatski definirana funkcija ADF0 prima dva parametra imena ARG0 i ARG1.
Automatski definirana funkcija je stablo pa ona vraća jednu povratnu vrijednost koja
predstavlja rezultat izvođenja te automatski definirane funkcije. Ostali parametri Tree
49
čvora koji predstavlja automatski definiranu funkciju imaju isto značenje kao parametri
čvora koji nije automatski definirana funkcija.
Drugi Tree genotip jednak je Tree genotipu koji ne koristi automatski definirane
funkcije, no postoji jedna razlika. Riječ je o parametru functionset koji sada ima
dodanu još jednu funkciju imena ADF0. To je automatski definirana funkcija čija je
definicija zadana prvim Tree genotipom. Kada functionset ne bi sadržavao funkciju
ADF0, algoritam bi radio u potpunosti ispravno, no glavni program tada ne bi nikada
pozivao automatski definiranu funkciju. Rad algoritma bio bi istovjetan algoritmu bez
automatski definiranih funkcija, uz razliku što bi izvođenje bilo sporije jer bi križanje i
mutacija automatski definirane funkcije trošili procesorsko vrijeme.
Nakon definiranja konfiguracijske datoteke potrebno je implementirati sučelje
IEvaluate i pokrenuti algoritam. Implementacija sučelja IEvaluate i pokretanje
algoritma istovjetni su primjeru prikazanom na slici u prethodnom poglavlju (Slika 3.11)
uz razliku da glavni program sada nije prvi genotip u konfiguracijskoj datoteci nego drugi
pa je potrebno naredbu
Tree tree = (Tree)fitness.getIndividual().get(0);
u metodi evaluate()zamijeniti naredbom
Tree tree = (Tree)fitness.getIndividual().get(1);
te tako dati frameworku do znanja koji genotip predstavlja glavni program.
50
4. Analiza rezultata
U ovom su poglavlju opisani rezultati dobiveni korištenjem ECF-a za genetsko
programiranje. Ispitane su različite vrijednosti parametara genetskog programiranja i
uspoređeno je genetsko programiranje sa i bez automatski definiranih funkcija. Sva
ispitivanja su obavljena na dvojezgrenom Intelovom T3400 procesoru takta 2.16 Ghz, a
izvršavana su slijedno. Ukupna pogreška je računata kao suma apsolutnih vrijednosti
pogrešaka. Manje vrijednosti pogreške su bolje, a zbog računanja ukupne pogreške kao
sume apsolutnih vrijednosti pogrešaka iznosi dobivenih pogrešaka uvelike su ovisni o
problemu koji se rješava. Iznosi pogrešaka za neke su probleme vrlo veliki pa je na ordinati
pripadnih grafova iznos pogreške prikazan logaritamskim mjerilom. Na apscisi grafova
prikazan je ili broj generacije ili vrijeme izvođenja algoritma. Pri ispitivanju parametara
genetskog programiranja svaki je test pokretan 10 puta, a pri ispitivanju utjecaja
automatski definiranih funkcija testovi su pokretani 15 puta.
4.1. Parametri genetskog programiranja
4.1.1. Utjecaj veličine skupa funkcija
Za rješavanje problema genetskim programiranjem potrebno je definirati skup funkcija. On
mora sadržavati sve funkcije potrebne za rješavanje zadanog problema, no može sadržavati
i neke dodatne. Utjecaj veličine skupa funkcija ispitivan je na problemu simboličke
regresije funkcije f(x)=x6+x4+x2+x.
Ispitivanje je provedeno na populaciji od 4000 jedinki, a vjerojatnost mutacije je
postavljena na 0.5. Korištena su oba križanja i obje mutacije sa 50% vjerojatnosti, a
najveća dubina stabla ograničena je na 8. Za analitički oblik funkcije f(x) potrebna su
barem dva operatora (zbrajanje i množenje) pa je minimalna veličina skupa funkcija s
kojim se može uspješno riješiti problem dva. Osim skupa od dvije funkcije, ispitani su i
skupovi od 4, 6, 8 i 10 funkcija. Rezultati su prikazani na sljedećoj slici (Slika 4.1).
Iako su razlike u početnoj pogreški velike, genetsko programiranje je uspješno riješilo
zadani problem sa svim veličinama skupa funkcija. Veći skup funkcija povećava
51
vjerojatnost da se u početnoj populaciji odaberu "pogrešne" funkcije što uzrokuje veće
vrijednosti pogreške u početnoj populaciji. Veći skup funkcija povećava i prostor pretrage
pa je potrebno više generacija algoritma za dolazak do optimalnog rješenja. Manji skup
funkcija daje bolje rezultate što je i očekivano ponašanje. Treba imati na umu da skup
funkcija mora biti dovoljno velik da omogući rješavanje zadanog problema.
Slika 4.1. Utjecaj veličine skupa funkcija na izvođenje genetskog programiranja
4.1.2. Utjecaj najveće dubine stabla
Jedinke su u genetskom programiranju prikazane u obliku stabla. Najveća veličina stabla
se može ograničiti kako bi se spriječilo nastajanje pretjerano složenih rješenja, a na taj se
način ubrzava i rad algoritma. Utjecaj najveće dubine stabla jedinki ispitivan je na
problemu simboličke regresije funkcije f(x)=x6+x4+x2+x.
Ispitivanje je provedeno na populaciji od 1000 jedinki uz vjerojatnost mutacije od 0.5.
Korištena su oba križanja i obje mutacije sa vjerojatnošću od 50%, a skup funkcija sastojao
se od četiri operatora: zbrajanja, oduzimanja, množenja i dijeljenja. Ispitivana su stabla
najveće dubine 4, 5, 6, 8 i 10. Rezultati su prikazani slikom (Slika 4.2). Obzirom da
brzina izvođenja genetskog programiranja uvelike ovisi o dubini stabla, ispitivana je
ovisnost iznosa pogreške o proteklom vremenu, a ne broju generacija algoritma. Proteklo
vrijeme prikazano je u sekundama.
Optimalno rješenje pronađeno je pri svim kombinacijama dubine stabla, no iz grafa se vidi
da je za stabla manje najveće dubine algoritam brže pronašao rješenje. Nameće se
zaključak da je bolje koristiti stabla manje dubine, no pri tome valja paziti da se ne prijeđe
52
neka minimalna dubina te tako onemogući prikaz točnog rješenja. Primjerice, da je
ispitivanje provedeno za dubinu stabla iznosa 3 algoritam nikada ne bi pronašao rješenje
jer se tim stablom ne može ispravno prikazati funkcija f(x). Za složenije probleme
potrebno je povećati najveću dozvoljenu dubinu stabla kako bi algoritam imao više slobode
pri traženju rješenja.
Slika 4.2. Utjecaj najveće dubine stabla na izvođenje genetskog programiranja
4.1.3. Utjecaj veličine populacije
Svaka generacija algoritma s većom populacijom izvodi se vremenski dulje nego
generacija s manjom populacijom. Posljedica toga je da se genetsko programiranje sa
većom populacijom izvodi sporije od onog koje ima manju populaciju. Međutim, veća
populacija omogućuje da se rješenje problema pronađe u manje generacija pa se postavlja
pitanje koja je veličina populacije optimalna.
U ovom je poglavlju ispitan utjecaj veličine populacije na izvođenje genetskog
programiranja pri rješavanju problema simboličke regresije funkcije f(x)=x4cos(x)-
3x2+xsin(x). Kao i u prethodnom poglavlju, umjesto broja generacija promatralo se
proteklo vrijeme jer veličina populacije izravno utječe na brzinu rada algoritma. Skup
funkcija sadržavao je operacije zbrajanja, oduzimanja, množenja, dijeljenja, sinus i
kosinus, a vjerojatnost mutacije je postavljena na 0.5. Stabla su ograničena na najveću
dubinu od 5 razina, a korištena su oba križanja i obje mutacije sa vjerojatnošću od 50%.
Rezultati su prikazani slikom (Slika 4.3).
53
Dobiveni graf je vrlo zanimljiv i pokazuje da populacije od 20 i 100 jedinki ne mogu
riješiti zadani problem. Raznolikost njihove početne populacije je premala i algoritam tada
konvergira prema nekom lokalnom optimumu. Populacije od 500 i 1000 jedinki puno se
bolje nose s lokanim optimumima, no u zadanom vremenskom razdoblju nisu uvijek
uspjele pronaći potpuno točan oblik funkcije f(x). Najbolji rezultati postignuti su sa
populacijama od 4000 i 10000 jedinki. Obje su pri svakom pokretanju pronašle potpuno
točno rješenje. Populacija od 10000 jedinki optimum je pronašla za 24, a populacija od
4000 jedinke za 27 generacija, no populaciji od 4000 jedinki je bilo potrebno duplo
manje vremena (50-ak sekundi naspram 100-ak sekundi za populaciju od 10000 jedinki).
Usporedbe radi, populacija od 20 jedinki u vremenu od 500 sekundi je prešla više od
100000 generacija, a unatoč tome njeno najbolje rješenje nije bilo dobro. Ovim se testom
potvrđuje teza da je za genetsko programiranje bolje koristiti veće populacije sa manjim
brojem generacija, dok za genetski algoritam ta tvrdnja ne mora vrijediti. Također vrijedi i
da je veće populacije potrebno koristiti za rješavanje složenijih problema.
Na grafu se vidi i da veće populacije daju bolje rješenje u početnoj generaciji algoritma.
Takvo ponašanje je očekivano jer veće populacije imaju više šanse da pogode dobro
rješenje zbog većeg broja jedinki koje se u početnoj populaciji kreiraju slučajnim
odabirom. Graf jasno pokazuje da srednje velike populacije (500 i 1000 jedinki) brže
napreduju od velikih populacija (4000 i 10000 jedinki) sve dok ne dođu do nekog
lokalnog optimuma, a njihovo se napredovanje tada zaustavlja. Male populacije (20 i 100
jedinki) zaglave na lokalnom optimumu tako brzo da njihovog napretka skoro pa nema.
Slika 4.3. Utjecaj veličine populacije na izvođenje genetskog programiranja
54
4.1.4. Utjecaj vjerojatnosti mutacije
Utjecaj vjerojatnosti mutacije na izvođenje genetskog programiranja ispitivan je na
populaciji od 4000 jedinki, a korištena je kombinacija mutacije zamjenom čvora i
mutacije permutacijom podstabla. Obje mutacije imale su vjerojatnost od 50%. Ista stvar
napravljena je i sa križanjima. Najveća dubina stabla postavljena je na 5, a skup funkcija
sastojao se od šest operatora: zbrajanja, oduzimanja, množenja, dijeljenja, sinus i kosinus.
Pri rješavanju problema simboličke regresije funkcije f(x)=x4cos(x)-3x2+xsin(x)
ispitane su vjerojatnosti mutacije od 0.02, 0.1, 0.2, 0.4 i 1, a dobiveni rezultati
prikazani su na slici (Slika 4.4).
Najlošiji rezultati dobili su se sa vjerojatnošću mutacije od 0.02. Ta vjerojatnost je
premala za uspješno izbjegavanje lokalnih optimuma pa algoritam često "zaglavi" na
njima. Međutim, treba naglasiti da pogreške u tim lokalnim optimumima nisu jako velike
što znači da dobivena rješenja nisu u potpunosti promašena. Sve ostale vjerojatnosti
mutacije ponašaju se vrlo dobro, a kao optimalna vrijednost pokazala se vjerojatnost od
0.4. Za vjerojatnost mutacije od 0.4 algoritam je najbrže pronašao točno rješenje, za
svega 20 generacija. Veće vjerojatnosti mutacije malo usporavaju rad algoritma zbog
većeg broja operacija koje je potrebno obaviti, no to usporavanje se pokazalo zanemarivim.
Slika 4.4. Utjecaj vjerojatnosti mutacije na izvođenje genetskog programiranja
55
4.1.5. Utjecaj odabira mutacije
U Java inačici ECF-a implementirane su dvije mutacije: mutacija zamjenom čvora i
mutacija permutacijom podstabla. One se mogu i kombinirano koristiti prilikom izvođenja
algoritma. U ovom odjeljku ispitan je utjecaj odabira mutacije na izvođenje genetskog
programiranja pri rješavanju problema simboličke regresije funkcije f(x)=x4cos(x)-
3x2+xsin(x). Ispitano je ponašanje obje mutacije posebno i kombinacije obiju mutacija.
Pri kombinaciji vjerojatnosti korištenja svake mutacije postavljene su na 0.5 što znači da
se u 50% slučajeva koristi jedna mutacija, a u 50% druga.
Veličina populacije postavljena je na 4000 jedinki, najveća dubina stabla na 5, a korištena
su oba križanja sa 50% vjerojatnosti odabira i šest funkcija (zbrajanje, oduzimanje,
množenje, dijeljenje, sinus i kosinus). Vjerojatnost mutacije postavljena je na 0.5.
Rezultati su prikazani grafom na slici u nastavku (Slika 4.5).
Iz grafa je vidljivo da su obje vrste mutacije uspješno pronašle traženo rješenje. Nešto brža
je bila mutacija koja permutira podstabla jer ona mutira veći dio kromosoma. Korištenje
obje mutacije u kombinaciji pokazalo se još boljim i u svakom trenutku je imalo bolje
rezultate od korištenja pojedinih mutacija posebno.
Slika 4.5. Utjecaj odabira mutacije na izvođenje genetskog programiranja
56
4.1.6. Utjecaj odabira križanja
U Java inačici ECF-a implementirana su dva križanja: jednostavno i uniformno križanje.
Ona se mogu i kombinirano koristiti prilikom izvođenja algoritma. U ovom odjeljku
ispitan je utjecaj odabira križanja na izvođenje genetskog programiranja pri rješavanju
problema simboličke regresije funkcije f(x)=x4cos(x)-3x2+xsin(x). Ispitano je
ponašanje oba križanja posebno i ponašanje njihove kombinacije. Pri kombinaciji
vjerojatnosti korištenja svakog križanja postavljene su na 0.5 što znači da se u 50%
slučajeva koristi jedno križanje, a u 50% drugo.
Veličina populacije postavljena je na 4000 jedinki, najveća dubina stabla na 5, a korištene
su obje mutacije sa 50% vjerojatnosti odabira i šest funkcija (zbrajanje, oduzimanje,
množenje, dijeljenje, sinus i kosinus). Kako bi se smanjio utjecaj mutacije na izvođenje
algoritma, njena vjerojatnost je smanjena na 0.1. Rezultati su prikazani grafom na slici
ispod (Slika 4.6).
Slika 4.6. Utjecaj odabira križanja na izvođenje genetskog programiranja
Rezultati dobiveni uniformnim križanjem bolji su od rezultata jednostavnog križanja.
Jednostavno križanje nerijetko uzrokuje zapinjanje algoritma na lokalnim optimumima. Na
grafu se vidi da se najbolje rješenje dobiveno jednostavnim križanjem u prvih 5 generacija
praktički nije promijenilo, a slična tvrdnja vrijedi i za generacije od 10 do 30. Zanimljivi su
rezultati dobiveni kombinacijom oba križanja. Ona se pokazala puno boljom čak i od
uniformnog križanja, a optimum je pronađen za svega 20 generacija.
57
4.1.7. Utjecaj parametra functionProb
Jednostavno križanje sadrži dodatni parametar functionProb koji je objašnjen u
poglavlju 3.4.1. Njegov utjecaj na izvođenje genetskog programiranja ispitan je pri
rješavanju simboličke regresije funkcije f(x)=x4cos(x)-3x2+xsin(x). Odabrana je
populacija od 4000 jedinki, a obzirom da se testira križanje, vjerojatnost mutacije je
postavljena na 0.1. Korištene su obje mutacije sa vjerojatnošću od 50%, šest funkcija
(zbrajanje, oduzimanje, množenje, dijeljenje, sinus i kosinus), a najveća dozvoljena dubina
stabla postavljena je na 5. Dobiveni rezultati prikazani su grafom (Slika 4.7).
Slika 4.7. Utjecaj parametra functionProb pri jednostavnom križanju
Dobiveni rezultati ovaj su put vrlo neočekivani. Iako se u [10] preporuča postavljanje
parametra functionProb na vrijednost oko 0.9, dobiveni rezultati za takve vrijednosti
functionProb vrlo su loši, a algoritam najčešće niti ne pronalazi optimalno rješenje.
Tek pri vrijednostima functionProb=0.1 ili functionProb=0.2 križanje uspijeva
izbjeći lokalne optimume i omogućiti algoritmu da pronađe optimalno rješenje. Međutim,
rezultati ovog testa su vrlo stohastički pa se nerijetko dogodi da algoritam ne pronađe
optimum čak ni uz niske vrijednosti functionProb parametra ili pak da pronađe
optimum uz visoke vrijednosti functionProb.
58
4.2. Utjecaj automatski definiranih funkcija
U ovom je poglavlju analiziran utjecaj automatski definiranih funkcija na izvođenje
genetskog programiranja. Uspoređeni su rezultati genetskog programiranja sa i bez
automatski definiranih funkcija na nekoliko problema. Svi testovi su pokretani više puta, a
prosječni rezultati su analizirani. Iznos pogreške prikazan je u odnosu na vrijeme rada
algoritma koje je izraženo u sekundama. Testovi su trajali 500 sekundi jer su preliminarna
ispitivanja pokazala da nakon 500-ak sekundi sve jedinke u pravilu postanu slične ili iste
pa napretka algoritma više nema.
Pri analizi su korišteni parametri genetskog programiranja koji su se u prethodnim
poglavljima pokazali optimalnima. Tako su ispitivane populacije od 4000 jedinki sa
vjerojatnošću mutacije od 0.5. Najveća dubina stabla glavnog programa postavljena je na
5, a po potrebi se povećavala do 8. Korištena su oba križanja i obje mutacije sa
vjerojatnošću od 50%. Skup funkcija najčešće se sastojao od operacija zbrajanja,
oduzimanja, množenja i dijeljenja, a u slučaju potrebe za sinusom i kosinusom dodane su i
te funkcije. Parametri crossover.genotypes i mutation.genotypes postavljeni
su na slučajni odabir što znači da će se kod korištenja automatski definiranih funkcija u
jednom križanju i mutaciji križati i mutirati ili automatski definirana funkcija ili glavni
program, ali ne oba zajedno.
4.2.1. Problem dvije kutije
Problem dvije kutije (engl. Two Boxes Problem) ima šest neovisnih varijabli (L0, W0, H0 i
L1, W1 i H1) i jednu varijablu (D) koja ovisi o prethodnih šest. Rješenje problema dobiva se
primjenom formule
D=L0*W0*H0-L1*W1*H1, (4.1)
a interpretira se kao razlika volumena dviju kutija čiji su parametri duljina (L), širina (W) i
visina (H). U tablici (Tablica 4.1) su navedeni primjeri ulaznih varijabli i očekivana
vrijednost neovisne varijable D. Ti su primjeri korišteni za simboličku regresiju i
ispitivanje genetskog programiranja.
59
Tablica 4.1. Vrijednosti ulaza i izlaza korišteni za rješavanje problema dvije kutije
L0 W0 H0 L1 W1 H1 D
3 4 7 2 5 3 54
7 10 9 10 3 1 600
10 9 4 8 1 6 312
3 9 5 1 6 4 111
4 3 2 7 6 1 -18
3 3 1 9 5 4 -171
5 9 9 1 7 6 363
1 2 9 3 9 2 -36
2 6 8 2 6 10 -24
1 10 7 5 1 45 -155
Problem dvije kutije je funkcija više od jedne varijable. Na iduće dvije slike prikazani su
najvažniji dijelovi konfiguracijske datoteke za rješavanje problema dvije kutije. Slika 4.8
prikazuje dio konfiguracijske datoteke za genetsko programiranje bez automatski
definiranih funkcija. Slika 4.9 prikazuje dio konfiguracijske datoteke za genetsko
programiranje uz korištenje jedne automatski definirane funkcije. Ostali dijelovi
konfiguracijske datoteke su istovjetni onima opisanim u poglavljima 3.5 i 3.6. Broj
argumenata automatski definirane funkcije može se odabrati slučajnim odabirom, no bolje
je proučiti problem i iskoristiti znanje dobiveno proučavanjem. Obzirom da problem dvije
kutije ima tri dimenzije, najbolje je odabrati da automatski definirana funkcija prima tri
argumenta.
<Genotype>
<Tree>
<Entry key="maxdepth">5</Entry>
<Entry key="mindepth">2</Entry>
<Entry key="functionset">+ - * /</Entry>
<Entry key="terminalset">L0 W0 H0 L1 W1 H1</Entry>
<Entry key="mut.nodereplace">0.5</Entry>
<Entry key="crx.uniform">0.5</Entry>
60
<Entry key="mut.permutation">0.5</Entry>
<Entry key="crx.simple">0.5</Entry>
<Entry key="functionprob">0.9</Entry>
</Tree>
</Genotype>
Slika 4.8. Dio konfiguracijske datoteke za rješavanje problema dvije kutije
<Genotype>
<Tree>
<Entry key="adf">ADF0</Entry>
<Entry key="maxdepth">2</Entry>
<Entry key="mindepth">1</Entry>
<Entry key="functionset">* + - /</Entry>
<Entry key="terminalset">ARG0 ARG1 ARG2</Entry>
<Entry key="mut.nodereplace">0.5</Entry>
<Entry key="crx.uniform">0.5</Entry>
<Entry key="mut.permutation">0.5</Entry>
<Entry key="crx.simple">0.5</Entry>
<Entry key="functionprob">0.9</Entry>
</Tree>
<Tree>
<Entry key="maxdepth">5</Entry>
<Entry key="mindepth">2</Entry>
<Entry key="functionset">+ - * / ADF0</Entry>
<Entry key="terminalset">L0 W0 H0 L1 W1 H1</Entry>
<Entry key="mut.nodereplace">0.5</Entry>
<Entry key="crx.uniform">0.5</Entry>
<Entry key="mut.permutation">0.5</Entry>
<Entry key="crx.simple">0.5</Entry>
<Entry key="functionprob">0.9</Entry>
</Tree>
</Genotype>
Slika 4.9. Dio konfiguracijske datoteke za rješavanje problema dvije
kutije korištenjem automatski definiranih funkcija
Dobiveni rezultati prikazani su grafom (Slika 4.10). Iz slike je vidljivo da automatski
definirane funkcije za rješavanje problema dvije kutije ne donose nikakvu dobit. Rezultati
61
dobiveni genetskim programiranjem sa automatski definiranim funkcijama su lošiji od onih
dobivenih običnim genetskim programiranjem.
Slika 4.10. Rezultati rješavanja problema dvije kutije
Genetsko programiranje bez automatski definiranih funkcija je pri svakom od 15
pokretanja pronašlo optimalno rješenje problema. Valja naglasiti da to ne znači da ono
nužno uvijek pronalazi potpuno točno rješenje, no u velikoj većini slučajeva je tako ako se
koriste optimalne postavke parametara. Svih petnaest puta optimum je pronađen za manje
od 50 sekundi.
Genetsko programiranje uz automatski definirane funkcije postiglo je nešto lošije rezultate.
Optimum je pronašlo u 11 od 15 pokretanja (73.33%), a rezultati prikazani na grafu su u
svakom trenutku lošiji od rezultata običnog genetskog programiranja, osim u početnom
čije se jedinke dobivaju na potpuno slučajan način. Na grafu je vidljivo da se u prvih pet
sekundi izvođenja dobrota najbolje jedinke niti jednom nije promijenila. Uzrok tome je što
u tih pet sekundi nije završena niti jedna generacija algoritma zbog velike složenosti pri
inicijalizaciji 4000 jedinki sa dva genotipa.
Korištenjem automatski definiranih funkcija pri rješavanju problema dvije kutije šansa za
pronalazak optimalnog rješenja se smanjuje, brzina algoritma se smanjuje, a memorijski
zahtjevi povećavaju. Problem dvije kutije nema dovoljno pravilnosti, modularnosti i
simetrije pa se automatski definirane funkcije nisu pokazale isplativima. Rješenja dobivena
sa automatski definiranim funkcijama u pravilu su jednake ili veće složenosti od rješenja
dobivenih običnim genetskim programiranjem. Primjeri nekih u potpunosti točnih rješenja
62
dobivenih korištenjem automatski definiranih funkcija prikazani su u nastavku. Na slikama
su prikazani samo promjenjivi dijelovi rješenja (čvorovi tipa 7 i 8 opisani u poglavlju
2.3.1).
Slika 4.11 prikazuje jedno rješenje dobiveno genetskim programiranjem sa automatski
definiranim funkcijama. Ovo rješenje je vrlo logično i očekivano – automatski definirana
funkcija računa volumen jedne kutije tako da množi svoja tri ulazna argumenta, a glavni
program poziva automatski definiranu funkciju dvaput, prvi put sa parametrima L0, W0 i
H0, a drugi put sa parametrima H1, L1 i W1, a nakon toga računa razliku između povratnih
vrijednosti dobivenih tim pozivima. Ovo rješenje u potpunosti odgovara ideji potprograma
i hijerarhijskoj dekompoziciji složenog problema na jednostavnije.
Slika 4.11. Rješenje sa automatski definiranom funkcijom
Međutim, takvo logično rješenje ne dobiva se uvijek. Slika 4.12 prikazuje rješenje u
kojemu glavni program u potpunosti ignorira svoju automatski definiranu funkciju, a
funkcija obavlja neki izračun koji nije direktno povezan sa problemom dvije kutije. Da je u
korijenskom čvoru umjesto operacije oduzimanja operacija množenja, tada bi automatski
definirana funkcija računala volumen jedne kutije, na isti način kao i na prethodnoj slici.
No, čak i kada automatski definirana funkcija obavlja svoj zadatak potpuno ispravno, niti
tada nema garancije da ju njen glavni program neće ignorirati.
63
Slika 4.12. Rješenje koje ignorira automatski definiranu funkciju
/
glavni programautomatski definiranafunkcija ADF0
ARG2 ARG2
*
ARG1
*
Lo
H0
W0
ARG2
*
W0 L1
H1L0
ADF0
W1
*
-
ADF0
Slika 4.13. Rješenje sa neobičnom automatski definiranom funkcijom
Slika 4.13 ilustrira još jedno rješenje dobiveno prilikom testiranja. U njemu automatski
definirana funkcija ignorira jedan od svojih ulaznih argumenata (ARG0), a uz to radi i jalov
posao – argument ARG1 prvo dijeli sa argumentom ARG2, a zatim ga množi s njim dvaput.
Čovjek pri programiranju nikada ne bi napravio ovakav potprogram i na prvi pogled se čini
da ovakva automatski definirana funkcija ne može dati pozitivan doprinos rješavanju
problema. Ali pogled na glavni program otkriva da on poziva svoju automatski definiranu
funkciju dvaput, te uz još dva dodatna množenja ispravno rješava problem dvije kutije.
64
Ovakvo rješenje sa ljudskog je stajališta nepotrebno, besmisleno i nelogično, no sa
stajališta genetskog programiranja ono rješava zadani problem podjednako dobro kao i dva
prethodna rješenja.
Slika 4.14 prikazuje još jedno na prvi pogled neobično i nelogično rješenje. Ovo rješenje je
strukturno najsloženije od dosad spominjanih i koristi stablo dubine 5. Automatski
definirana funkcija ponovno radi neobičan posao, a kada se pogleda s kojim ju
parametrima glavni program poziva situacija postaje još čudnija. Glavni program ju poziva
samo jednom i to tako da joj kao prva dva argumenta predaje isti parametar što znači da će
automatski definirana funkcija uvijek vratiti nulu. Zbog toga će u glavnom programu doći
do dijeljenja s nulom koje je po definiciji dijeljenja u genetskom programiranju uvijek
jednako 1. Ta jedinica se kasnije množi sa L0 i sudjeluje u kreiranju još jednom naizgled
čudnog, a s druge strane potpuno točnog rješenja.
Sva opisana rješenja imaju jednaku dobrotu i podjednako su dobra za genetsko
programiranje, no sa ljudskog stajališta neka su bolja, a neka lošija. Kao kriterij ponajprije
se uzima strukturna složenost rješenja – rješenja sa manje operacija proglašavaju se
boljima od rješenja koja imaju više operacija.
/
glavni programautomatski definirana
funkcija ADF0
ARG2 ARG0
/
ARG2
* L0
+
L0W1 W0
/*
H0 W0
L1
H1
*
L1
W1
-ARG1
-
L0
ADF0
- L0
*
-
Slika 4.14. Strukturno složeno rješenje
65
4.2.2. Polinom šestog stupnja
Utjecaj automatski definiranih funkcija ispitan je na simboličkoj regresiji funkcije
f(x)=x6-3x5+2x4-5x3-7x2+x. Funkcija je polinom šestog stupnja i nema velikih
pravilnosti. U skup primitiva genetskog programiranja dodane su funkcije zbrajanja,
oduzimanja, množenja i dijeljenja, no nije dodana operacija potenciranja. Usporedba
rezultata dobivenih genetskim programiranjem i genetskim programiranjem sa automatski
definiranim funkcijama prikazana je na sljedećoj slici (Slika 4.15).
Slika 4.15. Simbolička regresija polinoma šestog stupnja
Na grafu sa slike se vidi da je genetsko programiranje bez automatski definiranih funkcija
postiglo bolje rezultate od genetskog programiranja sa jednom automatski definiranom
funkcijom. Tako je od 15 pokretanja genetsko programiranje sa automatski definiranom
funkcijom optimum pronašlo 3 puta (20%), a obično genetsko programiranje 11 puta
(73.33%). Obično genetsko programiranje je čak 9 od 11 optimuma pronašlo između 50. i
100. sekunde izvođenja.
Genetsko programiranje sa automatski definiranom funkcijom ima veći prostor
pretraživanja pa je zbog toga u nekim slučajevima još uvijek napredovalo nakon isteka
zadanih 8 minuta i 20 sekundi izvođenja, dok je obično genetsko programiranje u toj fazi
već uvelike stagniralo. Automatski definirana funkcija nije donijela neku korist jer funkcija
f(x) nema dovoljno pravilnosti i simetrije. Obzirom da je f(x) funkcija jedne varijable,
postavljeno je da automatski definirana funkcija prima jedan argument. Sve ostale
66
operacije iz skupa funkcija su binarne i primaju dva argumenta. Zbog toga automatski
definirana funkcija u mutaciji nije mogla biti zamijenjena nekom drugom operacijom – ne
postoji niti jedna operacija koja prima isti broj argumenata. Ovo je negativno utjecalo na
raznolikost obavljenih mutacija, a samim time i na rezultat dobiven genetskim
programiranjem.
4.2.3. Polinom dvanaestog stupnja
Drugi polinom na kojem je ispitan utjecaj automatski definiranih funkcija na genetsko
programiranje je funkcija g(x)=x12-4x10+6x8-4x6+x4. Skup primitiva genetskog
programiranja sastojao se od operacija zbrajanja, oduzimanja, množenja i dijeljenja.
Usporedba rezultata dobivenih genetskim programiranjem i genetskim programiranjem sa
automatski definiranim funkcijama prikazana je na sljedećem grafu (Slika 4.16).
Dobiveni rezultati sasvim su suprotni od rezultata iz prethodnog odjeljka. Genetsko
programiranje sa automatski definiranim funkcijama postiglo je puno bolje rezultate na
ovoj funkciji nego na funkciji iz prethodnog poglavlja koja je bila duplo nižeg stupnja, a
obično genetsko programiranje je podbacilo. To je na prvi pogled iznenađujuće i
neočekivano, a objašnjenje takvih rezultata leži u samoj funkciji g(x). Ta funkcija je
polinom dvanaestog stupnja, a posebno je zanimljiv njen rastav na faktore kojim se dobiva
g(x)=x4*(x-1)4*(x+1)4. Iz faktorizacije funkcije g(x) vidljivo je da ona sadrži
puno pravilnosti i zbog toga je iznimno pogodna za korištenje automatski definiranih
funkcija.
Slika 4.16. Simbolička regresija polinoma dvanaestog stupnja
67
Genetsko programiranje bez automatski definiranih funkcija samo je jednom u 15
pokretanja pronašlo optimalno rješenje (6.66%). Pri većini pokretanja ono nije bilo niti
blizu optimalnom rješenju, a greška najboljih rješenja bila je ogromna (reda veličine 105).
Slika 4.17. Učestalost poziva automatski definirane funkcije u najboljoj jedinki
Genetsko programiranje sa jednom automatski definiranom funkcijom je pronašlo 13
optimalnih rješenja u 15 pokušaja (86.67%). Pogreška u preostala dva pokretanja bila je
minimalna, a vrlo je zanimljivo da je u tri pokretanja optimalno rješenje pronađeno već u
drugoj generaciji algoritma. Korištena je jedna automatski definirana funkcija koja je
primala jedan argument. Svaka optimalna jedinka je iskoristila svoju automatski definiranu
funkciju pozivajući ju barem dva puta. Slika 4.17 prikazuje učestalost poziva automatski
definirane funkcije u najboljoj jedinki. Glavni program je pozivao automatski definiranu
funkciju prosječno 3.27 puta, a u jednom pokretanju broj poziva se popeo čak na 7. Iz
svega navedenog može se zaključiti da su automatski definirane funkcije iznimno korisne
pri simboličkoj regresiji funkcija koje sadrže pravilnosti i simetričnosti. Genetsko
programiranje uz zadovoljavajuće parametre može iskoristiti automatski definirane
funkcije koje mu stoje na raspolaganju te ih koristiti na isti način kao što bi programer
koristio potprograme.
68
4.2.4. Utjecaj više automatski definiranih funkcija
Utjecaj više automatski definiranih funkcija ispitan je pri simboličkoj regresiji funkcije
h(x)=x*sin(x)+2x*sin(2x)+3x*sin(3x)+4x*sin(4x). Skup primitiva
genetskog programiranja sastojao se od funkcija zbrajanja, oduzimanja, množenja,
dijeljenja, sinusa i kosinusa. Usporedba rezultata dobivenih genetskim programiranjem i
genetskim programiranjem sa jednom, dvije i tri automatski definirane funkcije prikazana
je na sljedećoj slici (Slika 4.18).
Iako funkcija h(x) sadrži određene pravilnosti, iz slike je vidljivo da su rezultati dobiveni
običnim genetskim programiranjem najbolji. Niti jedno pokretanje genetskog
programiranja nije dalo potpuno točno rješenje, a pogreške dobivene korištenjem
automatski definiranih funkcija veće su od pogrešaka dobivenih običnim genetskim
programiranjem. Automatski definirane funkcije povećavaju prostor pretraživanja, a
povećanje prostora pretrage nadmašuje dobit od iskorištavanja pravilnosti funkcije h(x).
Slika 4.18. Simbolička regresija funkcije
h(x)=x*sin(x)+2x*sin(2x)+3x*sin(3x)+4x*sin(4x)
Rezultati dobiveni uporabom jedne automatski definirane funkcije koja je primala jedan
argument lošiji su od rezultata običnog genetskog programiranja. Druga automatski
definirana funkcija primala je dva argumenta kako bi se olakšalo križanje i mutacija sa
binarnim funkcijama. Rezultati dobiveni koristeći obje automatski definirane funkcije
gotovo su identični onima dobivenim uporabom jedne automatski definirane funkcije.
69
Treća automatski definirana funkcija primala je jedan argument, ali je imala veću najveću
dubinu stabla. Genetsko programiranje sa sve tri automatski definirane funkcije ostvarilo je
najbolje rezultate u početnoj generaciji algoritma, no napredak mu je bio najlošiji pa su i
dobiveni rezultati najlošiji.
Može se zaključiti da se povećanjem broja automatski definiranih funkcija neće dobiti bolji
rezultati jer učinkovitost automatski definiranih funkcija ponajprije ovisi o pravilnostima u
zadanom problemu (funkciji), a ne o broju automatski definiranih funkcija. Veći broj
automatski definiranih funkcija može donijeti dobit samo pri rješavanju složenijih
problema koji imaju jako puno pravilnosti ili koji imaju više vrsta pravilnosti.
70
Zaključak
Prikaz rješenja u obliku stabla kakav se koristi u genetskom programiranju pogodan je za
rješavanje problema simboličke regresije. Rješenja predstavljaju računalne programe koji
rješavaju zadani problem. Lošija rješenja se tijekom izvođenja zamjenjuju boljima.
Problemi koji se rješavaju genetskim programiranjem mogu biti vrlo složeni, a složeni
problemi su teški za izravno rješavanje. Ljudi prilikom programiranja razbijaju složene
probleme na jednostavnije. Tu ulogu u genetskom programiranju imaju automatski
definirane funkcije.
Genetsko programiranje sa automatski definiranim funkcijama sadrži rješenja koja se
sastoje od dva osnovna dijela: stabla koje predstavlja glavni program i automatski
definirane funkcije (jedne ili više njih). Automatski definirana funkcija je stablo čije
izvršavanje može pozvati glavni program. Ona se prema njemu odnosi kao potprogram
prema glavnom programu u izravnom programiranju. Automatski definirane funkcije
omogućuju genetskom programiranju rješavanje širokog spektra problema na način koji se
može tumačiti kao hijerarhijska dekompozicija. One pronalaze i koriste pravilnosti,
simetrije, homogenosti, sličnosti i modularnosti domene problema na način koji je različit
od načina koji primjenjuju ljudi.
Uspješnost genetskog programiranja ovisi o njegovim parametrima. Za postizanje dobrih
rezultata potrebno je odabrati dobre vrijednosti svih parametara. Loša vrijednost samo
jednog parametra može biti uzrok vrlo loših rezultata. Populacije od nekoliko tisuća jedinki
pokazale su se optimalnima, a uspješnosti pridonosi uporaba više vrsta križanja i mutacija.
Dobiveni rezultati mogli bi se poboljšati implementacijom dodatnih križanja i mutacija te
detaljnijim testovima u kojima bi se ispitivale razne kombinacije parametara.
Isplativost automatski definiranih funkcija ovisi o problemu koji se rješava. Ako zadani
problem sadrži puno pravilnosti, simetričnosti i modularnosti, tada je genetsko
programiranje sa automatski definiranim funkcijama bolje i učinkovitije od običnog
genetskog programiranja, a složenost dobivenih rješenja je manja. Uporabom automatski
definiranih funkcija povećava se prostor pretrage što negativno utječe na brzinu izvođenja.
Ako problem ne sadrži dovoljno pravilnosti ili ih uopće ne sadrži genetsko programiranje
71
sa automatski definiranim funkcijama davat će u prosjeku lošije rezultate od običnog
genetskog programiranja.
72
Literatura
[1] Wikipedia, Genetic algorithm, http://en.wikipedia.org/wiki/Genetic_algorithm, 26.05.2010.
[2] Holland, J. Adaptation in Natural and Artificial System. University of Michigan, 1992.
[3] Golub, M. Genetski algoritam, prvi dio, http://www.zemris.fer.hr/~golub/ga/ga_skripta1.pdf, 26.05.2010.
[4] Beasley, D., Bull, R. D., Martin R. R. An Overview of Genetic Algorithms, http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.53.6836&rep=rep1&type=pdf, 27.5.2010.
[5] Michalewicz, Z. Genetic Algorithms + Data Structures = Evolution Programs. University of North Carolina, 1995.
[6] Schmitt, L. M. Theory of genetic algorithms. University of Aizu, 1999.
[7] Wikipedia, Crossover (genetic algorithm), http://en.wikipedia.org/wiki/Crossover_(genetic_algorithm), 26.05.2010.
[8] Poli, R. A Field Guide to Genetic Programming. University of Essex, 2010.
[9] Koza, J. Genetic Programming: On the Programming of Computers by Means of Natural Selection. Massachusetts Institute of Technology, 1992.
[10] Koza, J. Genetic Programming II: Automatic Discovery of Reusable Programs. Massachusetts Institute of Technology, 1994.
[11] Eckel, B. Thinking in Java. 3rd ed, 2002.
[12] Bracha, G. Generics in the Java Programming Language, http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf, 26.5.2010.
[13] Page, J., Poli, R., Langdon, W. B. Smooth Uniform Crossover with Smooth Point Mutation in Genetic Programming: A Preliminary Study. University of Birmingham, 1998.
73
Sažetak
Učinkovitost automatski definiranih funkcija u evolucijskim algoritmima
Genetsko programiranje je evolucijski algoritam u kojem su rješenja prikazana u obliku
stabla. Prikaz u obliku stabla pogodan je za rješavanje problema simboličke regresije u
kojima je potrebno pronaći analitički oblik funkcije zadane parovima ulaz – izlaz. Rješenja
predstavljaju računalne programe koji rješavaju zadani problem.
U ovom je diplomskom radu uspoređeno obično genetsko programiranje sa genetskim
programiranjem koje koristi automatski definirane funkcije. Ispitan je utjecaj parametara
na izvođenje genetskog programiranja. Teoretska usporedba popraćena je programskom
implementacijom Java inačice Evolutionary Computation Frameworka koji je pružio
okruženje za praktično ispitivanje teoretskih pretpostavki.
Ključne riječi
Genetsko programiranje, genetski algoritam, evolucijski algoritam, stablo, automatski
definirana funkcija, potprogram, Evolutionary Computation Framework, ECF, Java
74
Summary
Automatically defined functions in evolutionary algorithms
Genetic programming is an evolutionary algorithm which has solutions represented as tree
structures. Tree structures are useful for solving symbolic regression problems where it is
needed to find analytical representation of the function defined with its inputs and outputs.
Solutions are computer programs which solve a given problem.
This thesis compares plain genetic programming and genetic programming with
automatically defined functions. It tests the effect of different parameters on execution of
genetic programming. Theoretical comparison is verified with program implementation of
the Evolutionary Computation Framework written in Java which provides an enviroment
for practical testing of theoretical assumptions.
Keywords
Genetic programming, genetic algorithm, evolutionary algorithm, tree, automatically
defined function, subroutine, Evolutionary Computation Framework, ECF, Java