You are on page 1of 4

SIMULAREA UNUI ALGORITM GENETIC ELEMENTAR FOLOSIND PERL (algoritm bazat pe modelul propus de Prof. dr. Juan J.

Merelo Guervós, Univ. Granada, Spania)
use strict; my my my my my my $generatii = shift || 1000; $dimensiunePopulatie = 100; $solutiaOptima = 'valoareoptima'; $lungimeSir = length( $solutiaOptima ); @alfabet = ('a'..'z'); @populatie;

Comment [BIOFIZ1]: Scopul programului este să identifice cu ajutorul operatorilor genetici un număr de generaţii necesare evoluţiei unei populaţii, iniţializate aleatoriu, să atingă soluţia optimă reprezentată chiar prin şirul respectiv. Comment [BIOFIZ2]: Utilizarea modulului strict impune eliminarea utilizării variabilelor globale şi folosirea exclusivă a variabilelor cu caracter local sau privat. Variabilele şi subrutinele nu pot fi utilizate înainte de a fi declarate. Acest aspect impune următoarea regulă de existenţă a variabilelor. Programul principal nu poate opera decât numai cu variabilele private declarate în blocul principal, nici o variabilă privată declarată în subrutine nu poate fi accesibilă din programul principal. Subrutinele vor putea opera cu variabilele declarate atât în blocul principal cât şi în cadrul subrutinei. O sub-sub-rutină poate folosi variabilele din blocul principal, variabilele din subrutina în care a fost construită cât şi propriile variabile. Deci, „vizibilitatea” variabilelor se face întotdeauna de jos în sus. Altfel spus blocul principal nu poate „vedea” decât propriile lui variabile, o subrutină însă, fiind „mai jos”, le vede atât pe ale ei cât şi pe cele ale blocului principal ş.a.m.d. Comment [BIOFIZ3]: Dacă nu se specifică un anumit număr de generaţii la lansarea programului (parametru care iniţializează tabloul @ARGV şi este ulterior preluat prin shift) atunci se utilizează 1000 de generaţii. Comment [BIOFIZ4]: Dimensiunea populaţiei este fixată prin program la 100 de componente. Se poate extinde aici programul după preferinţă cu posibilitatea de a introduce utilizatorul o valoare la cerere. Comment [BIOFIZ5]: Variabila care deţine „soluţia optimă” spre care algoritmul genetic trebuie să se îndrepte parcurgând un număr variabil de generaţii. Şi aceasta poate fi la nevoie introdusă de către utilizator la cerere. Ea este însă restricţionată de utilizarea unui alfabet limitat doar la caracterele minuscule de la a la z, vezi variabila @alfabet. Comment [BIOFIZ6]: Conţine elementele populaţiei la un moment dat. Ea este iniţializată în mod aleatoriu cu ajutorul unei subrutine dedicate. Comment [BIOFIZ7]: Subrutina performanţă evaluează şi selectează cele mai bune rezultate care se apropie de $solutiaOptima. Detalii pentru funcţiile abs, ord, substr, vezi link-uri utile (documentaţia Perl). Funcţia ord are rolul de a extrage codul numeric corespunzător caracterului din şir, fiecare caracter de la tastatură are un cod numeric asignat printr-un standard. Funcţia substr extrage un subşir dintr-un şir de caractere existent într-o variabilă, se comportă oarecum similar cu splice asupra conţinutului tablourilor.

sub performanta { my $sir = shift; my $distanta = 0; my $i; for ($i = 0; $i < ($lungimeSir -1); $i++) { $distanta += abs( ord( substr( $sir, $i, 1)) - ord( substr( $solutiaOptima, $i, 1))); } return $distanta; } sub afisarePopulatie { foreach (@populatie) { # print "$_\n"; print "$_->{_str} : $_->{_performanta} \n"; } } sub mutatie { my $cromozom = shift; my $mutatiePunctiforma = rand( length( $cromozom->{_str})); my $caracter_rand = $alfabet[( rand( @alfabet))]; substr( $cromozom->{_secventa}, $mutatiePunctiforma, 1, $caracter_rand); } sub initializarePopulatie { for ( 1..$dimensiunePopulatie ) { my $cromozom = { _sir => '', _valoare => 0 }; for ( 1..$lungimeSir ) { $cromozom->{_str} .= $alfabet[( rand( @alfabet))]; } $cromozom->{_performanta} = performanta( $cromozom->{_str} ); push @populatie, $cromozom; } } initializarePopulatie(); afisarePopulatie(); @populatie = sort { $a->{_performanta} <=> $b->{_performanta} } @populatie; for ( 1..$generatii ) { my $cromozom = $populatie[ rand( @populatie)]; my $clone ={}; do { $clone = { _str => $cromozom->{_str}, _performanta => 0 }; mutatie( $clone ); $clone->{_performanta} = performanta( $clone->{_str} );

În prima iteraţie s-ar iniţializa două locaţii de memorie _sir şi _valoare de tipurile indicate care aparţin unui hash ca structură de date. printr-o expresie simplă. Variabila locală (privată) my $cromozom este o referinţă la un hash fără nume (anonim). În cazul de faţă este creat un hash cu două componente care se iniţializează cu tipul de dată corespunzător. Următorul for are atâtea iteraţii cât de mare este $lungimeSir._performanta. locaţie ce conţine şirul care va forma un cromozom al populaţiei. Dacă reducem şirul atribuit variabilei $solutieOptima la „actg” atunci $lungimeSir se iniţializează prin aplicarea funcţiei length cu valoarea 4. Scopul subrutinei performanta este să stabilească. astfel încât variabila locală my $sir preia prin funcţia shift valoarea şirului din @_. La această locaţie desemnată $cromozom -> . prin intermediul variabilei $cromozom. last if $populatie[0]->{_performanta} == 0. ambele componente fiind identificare cu _ înaintea numelui).se va concatena (. } FUNCŢIONALITATEA PROGRAMULUI Blocul principal al programului porneşte de la apelarea subrutinei initializarePopulatie. În timpul execuţiei are loc următorul algoritm. @populatie = sort { $a->{_performanta} <=> $b->{_performanta} } @populatie. b).=) câte un caracter obţinut în mod aleatoriu din expresia din partea dreaptă. deci acest ciclu for se va executa de 4 ori. valoarea ei fiind 100) şi de $lungimeSir (variabilă scalară a cărei dimensiune este obţinută în funcţie de cât de lung este şirul „valoareoptima” spre care trebuie să evolueze sistemul). $cromozom -> . Referinţa presupune o legătură la un array.} until ( $clone->{_performanta} > $cromozom->{_performanta}). Aceasta conţine două structuri for condiţionate de $dimensiunePopulatie (o variabilă scalară fixă.reprezintă accesarea locaţiei de memorie (construită anterior prin referinţă). o valoare numerică care momentan e zero. Litera b se concatenează în locaţia de memorie care este referită prin asociaţia dintre numele $cromozom şi hash-ul cu structura indicată. $cromozom. Accesul la aceste locaţii de memorie se face însă._str. hash. print "Cel mai performant: $populatie[0]->{_str} ==> $populatie[0]>{_performanta} \n".este încărcată cu un rezultat numeric prin evaluarea performanţei combinaţiei obţinute. sau la o subrutină prin asocierea unei variabile scalare (cazul de faţă $cromozom) cu un obiect (zona de memorie unde este stocată instanţa) de tipul datei (array sau hash). Cu alte cuvinte. se creează un hash anonim cu structură determinată (prima componentă fiind un şir de caractere. Când se termină for-ul se încheie sinteza cromozomului din componentele impuse de alfabet. cât de departe este rezultatul obţinut faţă de . Acest lucru se realizează prin apelarea subrutinei performanta cu parametrul identificat cu ultima valoare existentă în locaţia memoriei referită de $cromozom->._str. se transferă către subrutina respectivă conţinutul existent la locaţia de memorie referită. Ex. La fiecare iteraţie se mai adaugă câte o literă din alfabet.pdf pentru detalii. $populatie[$#populatie] = $clone. Vezi fişierul references. @populatie fiind o variabilă array este formată din mai mulţi cromozomi. cu alte cuvinte._str-. Funcţia rand aplicată pe array-ul alfabet va extrage la întâmplare un index (de ex. 2). acesta nefiind iniţializat (pentru început este un şir gol ’ ’) şi al doilea tip de dată. dacă $dimensiunePopulatie ar fi 2 atunci s-ar executa un ciclu for cu două iteraţii. Deoarece această referinţă este apelată prin intermediul unui scalar. adică cu şirul obţinut prin concatenarea randomizată. „distanţa” faţă de soluţia ideală de evoluţie. situaţie în care apelarea prin scalar $alfabet*2+ înseamnă a doua literă din alfabetul impus (ex. După acest for imbricat se continuă instrucţiunile din for-ul anterior unde locaţia de memorie stabilită pentru valoare $cromozom->. înseamnă că în cadrul subrutinei se iniţializează array-ul @_ cu un singur component. Deci.

Dacă eliminaţi simbolul # care comentează instrucţiunea print "$_\n". După execuţia performanţei se returnează valoarea obţinută prin diferenţă ca rezultat reprezentativ al acesteia. în primul caz şirul. Această valoare numerică aleatorie este folosită ulterior pentru a modifica un singur caracter prin apelarea substr pe şirul de caractere de la locaţia point-ată de $cromozom->. fiecare cromozom fiind de fapt o componentă bidimensională. Întrucât subrutina se bazează pe pointeri nu mai este necesară utilizarea instrucţiunii return. în care este utilizată ca referinţă către o locaţie de memorie. deci este condiţionată de un ciclu for a cărui număr de iteraţii este limitat de valoarea introdusă la $generatii. Din acest punct de vedere utilizarea pointer-ilor simplifică modul de exploatare a datelor şi a resurselor într-un program. Mare atenţie la acest aspect. Mutaţia se efectuează pe număr de generaţii. $clone ca parametru al subrutinei este tot un pointer pentru că prin intermediul lui se transferă către variabila locală $cromozom prin aplicarea lui shift pe array-ul @_ cele două componente ale cromozomului din populaţie. iar subrutina initializarePopulatie care încă nu s-a încheiat. ea va determina print-area conţinutului acelei locaţii. programul introduce şi un operator de mutaţie în populaţie. Este evident că dacă se atinge valoarea zero. Evaluarea condiţiei Comment [BIOFIZ8]: În programare. . aceasta fiind asemănătoare cu while numai că este cu post-condiţie. Scopul algoritmului este de a-l selecta pe cel cu valoarea cea mai mică.valoarea ideală. populaţia astfel obţinută este sortată (vezi funcţia sort). Întrucât în spatele $cromozom se află un hash anonim. tehnica pointer este folosită ca o soluţie elegantă pentru accesul direct la conţinutul locaţiilor de memorie fără ca programatorul să fie nevoit să ţină evidenţa acestora. Deoarece adresele hexazecimale ale memoriei alocate de program pentru stocarea datelor sunt dificil de utilizat. Conţinutul locaţiilor de memorie odată alterat este disponibil în continuare doar în această variantă modificată. veţi observa afişată valoarea adresei de memorie la care se face referire. În variabila $distanta se adună diferenţele în valoare absolută dintre codurile ASCII (vezi link-uri utile) ale caracterelor întâlnite în şirul din cromozom şi în şirul ideal spre care se tinde. deci se obţine un array bidimensional conform schemei de mai jos. În final. Mecanismul de mutaţie este repetat în cadrul unei iteraţii do – until. Dacă nu ar exista aşa ceva populaţia nu ar mai putea evolua şi s-ar opri la soluţiile aleatoare produse la iniţializare. compus. Printr-o simplă asociere cu o variabilă scalară se creează un pointer realizându-se o legătură între adresa de memorie şi conţinutul acesteia. şirul şi performanţa. elimină nevoia de a utiliza foarte multe variabile pentru transferul datelor între subrutine. După generarea aleatoare şi afişarea rezultatelor. din două componente (şirul de caractere care compune un cromozom şi valoarea numerică a performanţei acestuia) înseamnă că array-ul respectiv se va completa cu un număr de cromozomi. Din acest punct de vedere mutaţia este aleatorie folosind strict materialul disponibil în @alfabet. adaugă în array-ul populaţie o componentă de tip cromozom cu ajutorul funcţiei push. Afişarea componentelor populaţiei se realizează prin parcurgerea @populatie cu ajutorul funcţiei foreach care ia fiecare cromozom din populaţie şi afişează prin intermediul print şirul din care e compus cromozomul şi performanţa acestuia. În cadrul acestui mecanism se extrage aleatoriu un cromozom din @populatie şi se iniţializează o variabilă locală $clone care va prelua conţinutul cromozomului transferând-ul subrutinei mutatie. la rândul lui. numai că în situaţia de faţă. Index [0] Cromozom_1 Şir_1 Perfromanţă_1 Index [1] Cromozom_2 Şir_2 Perfromanţă_2 Index [2] Cromozom_3 Şir_3 Perfromanţă_3 Index [3] Cromozom_4 Şir_4 Perfromanţă_4 Index [n] Cromozom_n Şir_n Perfromanţă_n Odată populaţia iniţializată. Acest şir va fi alterat cu un caracter ales aleatoriu din @alfabet folosind expresia $alfabet[( rand( @alfabet))]. această tehnică este cunoscută sub denumirea generică de exploatarea memoriei prin intermediul pointer-ilor. deci în urma aplicării funcţiei sort pe componentele @populatie. aceasta va conţine aceleaşi componente doar că ordinea lor este ascendentă în funcţie de valoarea performanţei. Variabila $mutatiePunctiforma se iniţializează cu o valoare aleatoare între 0 şi lungimea şirului de caractere al cromozomului. Variabila internă $_ este exploatată similar ca şi array-ul _. evoluţia se încheie deoarece şirul cromozomului comparat este identic cu valoarea optimă. aceasta urmează a fi afişată pentru a putea vizualiza ce fel de componente are şi ce performanţă are fiecare component. în al doilea caz valoarea performanţei corespunzătoare şir-ului._str-. accesând locaţiile de memorie stabilite prin referinţele create anterior.

$populatie*$#populatie+ = $clone. În stânga.perl.html http://www.org/independent/web/cgi/perlmanual/index. b. practic mutaţia nu face altceva decât să modifice această valoare.se face după ce se trece obligatoriu măcar o dată prin ciclu. LINK-URI UTILE http://perldoc. ultimul cromozom (cel mai îndepărtat de soluţia ideală) este înlocuit cu cel obţinut prin mutaţie.org/ http://www. Întrucât algoritmul indicat este departe de un model real în ceea ce priveşte evoluţia populaţiei.org/ http://www.perl.html http://ro.comptechdoc. Programul se încheie forţat (last) atunci când performanţă este zero. Să se adapteze programul astfel încât utilizatorul să poată controla prin introducerea unor valori de la tastatură pentru $generatii. să se îmbunătăţească programul prin introducerea unei subrutine care să simuleze recombinarea prin crossing over. Întrucât populaţia a fost deja sortată ascendent. Se resortează populaţia ascendent şi se afişează primul cromozom care este şi cel mai performant. $solutiaOptima şi @alfabet.wikipedia. adică s-a atins valoarea ideală. în căsuţa Reference sunt reunite principalele capitole care descriu cu exemple detaliate toate funcţiile (în ordine alfabetică).sdsc.edu/~moreland/courses/IntroPerl/docs/manual/pod/perlop. .org/wiki/ASCII Comment [BIOFIZ9]: Documentaţia oficială pentru Perl. Comment [BIOFIZ10]: Descriere amănunţită a operatorilor folosiţi în Perl. $dimensiunePopulatie. Comment [BIOFIZ11]: Tutorial Perl cu descrieri concise şi exemple simple. instrucţiunile şi operatorii limbajului. Ca şi condiţie de oprire este luată chiar valoarea performanţei. TEMĂ a.