N-ar fi rău să-ţi schimbi perspectiva!
RO FR EN
 
Oamenii Rareşului  |  Organigrama  |  Istoric  |  Ştiri şi publicaţii  |  Arhivă
COMPUTERSCIENCEWHY.net
 
Curriculum  |  Competiţii şi examene  |  Proiecte  |  Parteneriate  |  De prin Rareş
RARESiKIDS
infolight®

motor de căutare

(beta)

info
 
   Ştiri şi publicaţii  Articole  Algoritmi genetici  


cautarestart

Algoritmi genetici

prof. Liviu-Constantin  Olaru
liviu.olaru@cnpetrurares.ro

Sorin-Gabriel  Dascălu (12B)

Tudor  Scurtu (12B)

Cuprins:   Argument  |  Principiul  |  Implementări ale algoritmilor genetici:  Problema damelor şi Problema existenţei unui ciclu hamiltonian

Argument

Ca şi celelalte discipline exacte, informatica încearcă să modeleze lumea reală cu mijloace abstracte. Deşi fiecare „ştiinţă exactă“, pare să existe prin ea însăşi (fiecare dispune de un set de noţiuni fundamentale, definiţii şi teoreme care împreună dau caracterul de „autosuficienţă“), originea comună tuturor acestor discipline, este localizată în nevoia acută de pârghii necesare rezolvării problemelor practice ale universului cotidian. În cazul algoritmilor genetici, legătura cu lumea fizică (şi modelul de inspiraţie) este Teoria Evoluţionistă a lui Darwin. Vom parcurge, în acest articol, câteva dintre principiile fundamentale ale Teoriei Evoluţioniste, cu implementările similare oferite de Teoria Algoritmilor. Ne propunem să amintim pe scurt câteva dintre principiile celebrei Teorii Evoluţioniste şi să punem accent pe exemple practice ale algoritmilor genetici, realizate cu ajutorul limbajului de programare C++.

Principiul

Soluţia unei probleme rezolvabile cu ajutorul algoritmilor genetici, este o construcţie foarte asemănătoare cu un cromozom: ea are mai multe componente care sunt asimilate genelor care formează cromozomul.

Se porneşte de la o populaţie iniţială de cromozomi care evoluează în timp. După mai multe generaţii (stări ale populaţiei, în diferite momente de timp), prin îmbunătăţiri succesive ale calităţii cromozomilor (aceştia se transformă în timp), se ajunge la soluţia problemei.

O nouă generaţie de cromozomi este construită în urma unui proces de selecţie care are rolul de a alege cromozomii supravieţuitori. Aceştia vor forma o piscină de încrucişare. În acest scop, se va implementa o funcţie de calitate (adaptabilitate) a cromozomilor. În toate problemele rezolvate cu ajutorul algoritmilor genetici, funcţia de calitate este cel mai important criteriu cu ajutorul căruia se construieşte piscina de încrucişare.

Pe lângă funcţia de calitate, în practică, sunt acceptate şi alte metode cu ajutorul cărora se realizează selecţia cromozomilor care vor face parte din piscina de încrucişare; turneul şi ruleta sunt două astfel de tehnici de selecţie.

Turneul (sau „lupta dreaptă“) presupune, în esenţă, că din generaţia curentă se aleg câte doi cromozomi şi numai cel mai performant este inclus în piscina de încrucişare. Se pot imagina variante diverse de turneu, specifice problemei date.

Ruleta este folosită în special atunci când numărul cromozomilor din piscina de încrucişare trebuie să fie egal cu numărul de cromozomi din populaţia curentă. Aceasta nu înseamnă că piscina de încrucişare va fi identică cu generaţia curentă: cromozomii mai bine adaptaţi vor fi prezenţi în mai multe exemplare în piscină, iar cei slabi nu vor mai fi incluşi. Şi în cazul ruletei se pot implementa maniere multiple de creare a piscinei de încrucişare, toate bazate pe scenariul următor: fiecărui cromozom din generaţia curentă îi va corespunde, pe ruletă, o zonă de mărime proporţională cu performanţa lui; ruleta va fi învârtită (prin generarea unei valori aleatoare) şi cromozomul corespunzător zonei pe care s-a oprit acul ruletei, va fi lansat în piscina de încrucişare.

Asupra mulţimii de cromozomi din piscina de încrucişare se aplică operatori genetici (cum ar fi mutaţia sau încrucişarea), astfel încât, din cromozomii supravieţuitori ai generaţiei curente, se obţin cromozomii generaţiei următoare.

Dacă mutaţia este definită ca fiind alterarea minoră a unui cromozom, încrucişarea presupune crearea a doi fii, din doi cromozomi (părinţi) ai piscinei de încrucişare în urma unor operaţii de transfer de gene între aceştia din urmă. Trebuie amintit că mutaţia şi încrucişarea sunt operatorii genetici cei mai folosiţi.

În consecinţă, evoluţia populaţiei de cromozomi, poate fi descrisă de următorii paşi:

  1. crearea populaţiei iniţiale (o singură dată);
  2. stabilirea calităţii cromozomilor (la fiecare generaţie);
  3. selecţia cromozomilor din piscina de încrucişare (la fiecare generaţie);
  4. efectuarea mutaţiilor (la fiecare generaţie);
  5. efectuarea încrucişărilor (la fiecare generaţie);
  6. crearea noii generaţii (la fiecare generaţie);
  7. oprirea evoluţiei (o singură dată).

Implementări ale algoritmilor genetici

Trebuie să amintim că nu întotdeauna implementările cu ajutorul algoritmilor genetici sunt cele mai eficiente (în fond şi procesul de evoluţie în lumea vie, este foarte îndelungat, conform Teoriei Evoluţioniste!). De regulă, lipsa de eficienţă îşi are originea în procesul de selecţie care este unul anevoios şi consumator de timp. Sub rezerva acestei observaţii, propunem următoarele aplicaţii: determinarea existenţei unui ciclu hamiltonian şi problema damelor. Ambele sunt probleme clasice de programare rezolvabile şi prin backtracking.

Problema damelor: fiind dată o tablă de şah de dimensiuni nXn, să se aranjeze n dame (regine) astfel încât nici una să nu fie ameninţată de o altă damă (să nu fie poziţionate pe aceeaşi linie, coloană sau diagonală).

Pentru înţelegerea facilă a algoritmului propus mai jos, sunt necesare următoarele observaţii:

  1. matricea v reţine generaţia curentă, în v[k][0] fiind reţinută calitatea unui cromozom;
  2. p reprezintă piscina de încrucişare, în care se introduc automat cel mai slab, precum şi cel mai bun cromozom;
  3. s este o variabilă care devine nenulă dacă se ajunge la o soluţie, şi deci se opreşte execuţia programului;
  4. i, j, k, min, max, p1, p2, c, aux sunt variabile auxiliare care pot avea sau nu mai multe întrebuinţări;
  5. execuţia programului se opreşte dacă după o anumită perioadă de timp nu se ajunge la o soluţie.

#include <fstream.h>
#include <time.h>
#include <stdlib.h>
ifstream f("genetic.in");
ofstream g("genetic.out");
int n, s, v[100][100], p[100][100], i, j, k, min=0, max=0, p1, p2, c, aux;
clock_t start=clock(), stop;
struct ruleta
{
int i,s;
} r[100];
int calitate(int k)
{
int c=1;
for(i=2; i<=n; i++)
for(j=1; j<i; j++)
if(v[k][i]!=v[k][j] && v[k][i]+i!=v[k][j]+j && abs(v[k][i]-v[k][j])!=abs(i-j))
c++;
return c;
}
int cautare(int k, int x)
{
if(k>=r[x].i && k<=r[x].s)
return x;
if(k<r[x].i)
return cautare(k, !(x/2)?1:(x/2));
return cautare(k, x+(!((n-x)/2)?1:((n-x)/2)));
}
void mutatie(int k, int x)
{
if(p[k][x]<n)
p[k][x]++;
}
void evolutie()
{
/*stabilirea calitatii cromozomilor*/
for(i=1; i<=n && !s; i++)
{
v[i][0]=calitate(i);
if(v[i][0]==n*(n-1)/2+1)
s=i;
if(v[i][0]>max)
{
max=v[i][0];
p2=i;
}
if(i!=p2 && (!min || v[i][0]<min))
{
min=v[i][0];
p1=i;
}
r[i].i=r[i-1].s+1;
r[i].s=r[i].i+v[i][0];
}
/*selectia cromozomilor pentru piscina de incrucisare*/
if(!s)
{
for(i=1; i<=n; i++)
{
p[1][i]=v[p1][i];
p[2][i]=v[p2][i];
}
for(i=3; i<=n; i++)
{
randomize();
c=cautare(rand()%(r[n].s+1),n/2);
for(j=1; j<=n; j++)

p[i][j]=v[c][j];
}
/*efectuarea mutatiilor*/
for(k=1; k<=n; k++)
{
c=0;
for(i=2; i<=n; i++)
for(j=1; j<i && !c; j++)
if(p[k][i]==p[k][j])
{
c++;
if(p[k][j]<n)
p[k][j]++;
else
p[k][j]=1;
}
randomize();
if(!c && rand()%2)
{
randomize();
c=rand()%n+1;
if(p[k][c]<n)
p[k][c]++;
else
p[k][c]=1;
}
}
/*efectuarea incrucisarilor*/
for(i=1; i<=n/2; i++)
{
randomize();
if(rand()%2)
{
randomize();
c=2+rand()%(n-1);
for(j=c; j<=n; j++)
{
aux=p[i][j];
p[i][j]=p[n-i+1][j];
p[n-i+1][j]=aux;
}
}
}
/*stabilirea noii generatii*/
for(i=1; i<=n; i++)
for(j=1; j<=n; j++)
v[i][j]=p[i][j];
stop=clock();
if(stop<start+2000)
evolutie();
}
}
int main()
{
f>>n;
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
v[i][j]=i;
r[0].s=-1;
evolutie();
if(s)
{
g<<v[s][1];
for(i=2; i<=n; i++)
g<<' '<<v[s][i];
}
else
g<<"Nu s-a ajuns la o solutie in timp acceptabil";
g<<endl;
f.close();
g.close();
return 0;
}

Problema existenţei unui ciclu hamiltonian: se dă un graf neorientat şi se cere să se verifice dacă acesta este graf hamiltonian (dacă acesta are un ciclu hamiltonian). În caz afirmativ să se genereze un astfel de ciclu.

#include <fstream.h>
#include <string.h>
#include <stdlib.h>
ifstream f("f.in");
ofstream g("f.out");
char *gen[100], *newgen[100];
int mat[100][100], n;
/*functia pop_init() construieste populatia initiala de cromzomi*/
void pop_init()
{
int j;
for(int i=0; i<n; i++)
for(j=0; j<n; j++)
gen[i][j]=random(2)+48;
}
/*functia detcal() determina calitatea fiecarui cromozom*/
int detcal(char *p)
{
int j, a, c=0;
for(int i=0; i<n; i++)
if(p[i]=='1')
if(!c) c++;
else
{
a=0;
for(j=0; j<n; j++)
if(p[j]=='1' && mat[i][j])
{
a=1;
break;
}
if(a)
c++;
else
c--;
}
return c;
}
/*functia sf_gen() stabileste daca sa ajuns la rezultatul final, utilizand drept conditie calitatea cromozomilor din generatia actuala*/
int sf_gen()
{
for(int i=0; i<n; i++)
if(detcal(gen[i])==n)
return 1;
return 0;
}

/*functia det_new_gen() construieste noua generatie; ea foloseste in piscina de incrucisare toti vechii cromozomi; altfel, nu se mai realizeaza o generatie intermediara intrucat det_new_gen() face si mutatii pe cromozomii noi obtinuti*/
void det_new_gen()
{
int a,j;
for(int i=0; i<n; i++)
{
do
{
a=random(n);
}
while(a!=i);
for(j=0; j<n; j++)
if(gen[i][j]=='1' && gen[a][j]=='1')
newgen[i][j]='1';
else
newgen[i][j]=random(2)+48;
}
for(i=0; i<n; i++)
strcpy(gen[i], newgen[i]);
}
int main()
{
int a;
long count=0;
f>>n;
for(int i=0; i<n; i++)
for(int j=0; j<n; j++)
f>>mat[i][j];
a=0;
pop_init();
a=sf_gen();
while(!a && count<10000)
{
det_new_gen();
count++;
a=sf_gen();
}
if(a)
g<<"Exista un ciclu hamiltonian";
else
g<<"Nu exista ciclu hamiltonian";
f.close();
g.close();
return 0;
}

cautarestop
 

© 2005-2009 Colegiul Naţional „Petru Rareş“ - Piatra Neamţ. Toate drepturile rezervate.
 
Ora României este 03:43 iar tu vizitezi versiunea de noapte a site-ului C.N.P.R.!
 
2006
 
Trimite-ne şi tu o fotografie!