Sie sind auf Seite 1von 23

TP ALGORITME GENITIQUE

Master Recherche Oprationnelle

INTRODUCTION
Les algorithmes gntiques appartiennent la famille des algorithmes volutionnistes. Leur but est d'obtenir une solution approche un problme d'optimisation pour le rsoudre en un temps raisonnable. Les algorithmes gntiques utilisent la notion de slection naturelle et l'appliquent une population de solutions potentielles au problme donn. Origine : L'utilisation d'algorithmes gntiques, dans la rsolution de problmes, est l'origine le fruit des recherches de John Holland et de ses collgues et lves de l'Universit du Michigan qui ont, ds1960, travaill sur ce sujet. Problme de voyageur de commerce Le problme du voyageur de commerce consiste, tant donn un ensemble de villes spares par des distances donnes, trouver le plus court chemin qui relie toutes les villes et retourner la ville de dpart .tel que chaque ville nest visiter quune fois . Il s'agit d'un problme d'optimisation pour lequel on ne connait pas d'algorithme permettant de trouver une solution exacte en un temps polynomial.

Enonce :
On se propose de rsoudre le problme de voyageur de commerce par un AG . On cherche dterminer le plus court chemin Hamiltonien passant par les villes : Agadir, Casablanca, Fs, Marrakech, Mekns, Rabat, Tanger.

CODE :
#include<stdio.h> #include<conio.h> #include<stdlib.h> #include<time.h> int S[10][10]={{0,650,795,305,745,615,900}, {650,0,290,240,230,95,370}, {795,290,0,485,60,200,305}, {305,240,485,0,475,335,610}, {745,230,60,475,0,140,295}, {615,95,200,335,140,0,280}, {900,370,305,610,295,280,0}}; 3

int N=7; const int taille_pop=10; /* cette fonction affiche la matrice des cout (distance) */ void afficher(int N,int M,int S[10][10]) { for(int i=0;i<N;i++) { for(int j=0;j<M;j++) printf("%d\t",S[i][j]); printf("\n"); } }

/* cette fonction gnre un individu alatoirement et en mme temps fait le codage de l'individu en des nombres compris entre 0 et 6 */ void generer_ind(int ind[]) { for(int i=0;i<N;i++) { ind[i]=rand()%7; for(int j=0;j<i;j++) if(ind[j]==ind[i]) i--; // on s'assurent que lindividu soit ralisable (le meme nombre(ville)ne se rptent pas) } } /* gnre la population 4

*/ void {

generer_pop(int pop[taille_pop][10]) for(int i=0;i<taille_pop;i++) generer_ind(pop[i]);

} /* afficher un individu */ void afficher(int n,int T[]) { for(int i=0;i<n;i++) printf("%d\t",T[i]); } /* affiche un individu par nom de ville */ void afficher_ville(int n,int ind[]) { for(int i=0;i<n;i++) switch(ind[i]) { case 0:printf("Agadir ");break; case 1:printf("Casablanca ");break; case 2:printf("Fes ");break; case 3:printf("Marrakech ");break; case 4:printf("Meknes ");break; case 5:printf("Rabat ");break; case 6:printf("Tanger ");break; default:printf("Erreur, ville inconnue"); } }

/* calcule la distance (le cout ) d'un individu */ float distance(int ind[]) { float Dist=0; for(int i=0;i<N-1;i++) Dist+=S[ind[i]][ind[i+1]]; Dist+=S[ind[0]][ind[N-1]];// on ajoute le cout de retour return Dist; } /* calcule de fitness qui ne permettra d' valuer l'individu */ float fitness(int ind[]) { return 1./distance(ind); } /* fonction qui retourne le meilleure individu de la population */ int meilleur_ind(int pop[taille_pop][10]) { int id=0; for(int i=1;i<taille_pop;i++) if(fitness(pop[i])>fitness(pop[id])) id=i; return id; } /* fonction qui permet de slectionner alatoirement l'indice d'un individu on fera appelle a cette fonction dans selection_tournois */ int selection_alia() { int id; 6

de la population

id= rand()%10; return id; } /* la fonction selection_tournois selectionne le meilleure individu parmi des individu selectioner aliatiorement */ int selection_tournois(int pop[10][10]) {int i1,i2,i3,imax; i1=selection_alia(); i2=selection_alia(); i3=selection_alia(); imax=i1; if(fitness(pop[i2])>fitness(pop[imax])) imax=i2; if(fitness(pop[i3])>fitness(pop[imax])) imax=i3; return (imax); } /* on utilise la selection_tournois pour selectionner des individus de telles sortent a ne pas dpasser le pourcentage des individus slectionner ici 0,7. */ void selection_croisement(int*nc,int C[],int pop[10][10]) { float sommeFitness=0; int i; for(i=0;i<taille_pop;i++) sommeFitness+=fitness(pop[i]); int j=0; float pc=0; while(pc<=0.7) {int id; 7

id=selection_tournois( pop); pc+=fitness(pop[id])/sommeFitness;/* ici on associe a chaque individu selectioner un segment relatif a sa fitness */ C[j]=id;// on stok les indices des individus selectionner dans un tabeau pour les croiser aprs

*nc=j+1;/*on incremente chaque fois la taille du tableau des ind selectioner que on selectionent pr savoir dans le croisment combien on va croiser*/ j++; } } /* le mme principe pour la selection pour la mutation */ int* selection_mutation(int*nm,int M[],int pop[10][10]) { float sommeFitness=0; int i; for(i=0;i<taille_pop;i++) sommeFitness+=fitness(pop[i]); int j=0; float pm=0; while(pm<=0.3) {int id; id=selection_tournois(pop); pm+=fitness(pop[id])/sommeFitness; M[j]=id; *nm=j+1; j++; } return M; } 8

/* on fait le croisement un point des ind slectionner pour le croisement */ void croisement (int P1[],int P2[],int E1[],int E2[]) {int i,j; int k; do { k=rand()%7;// on slectionne un point de croisement alatoirement de faon qui il soit entre 1 et 6 }while(k==6);// pour seulement assurer que le croisement est fait si non si k=6 en tombe sur les mmes individu for(i=0;i<=k;i++) { E1[i]=P1[i]; E2[i]=P2[i]; } // Jusqua ici on a met la partie 1 de parent 1 dans enfant 1 // Et la partie 2 de parent 2 dans enfant 2 /* maintenant on va faire le croisement avec correction */ int id=k+1; /* on va complter l'enfant 1 par les gnes du parent 2 qui sont dfrent de ce qui existe dj dans l'enfant 1*/ for(i=0;i<N;i++) { int nb=0;/* on dclare un variable pour savoir si chaque gne de P1 Existe ou non dans tt E1*/ /* la variable vas prendre a la fin le nombre de comparaison faite et si le nombre est k+1 alors la gne n'apparu pas dans E1*/ for (j=0;j<=k;j++) {if (P2[i]!=E1[j]) nb++; else 9

break;// Si il y a galit pas la paine de continuit la comparaison } /* voila maintenant on va vrifier si notre variable pris k+1 ou On a sortie de la boucle sans terminer toutes les comparaisons est Donc avec une valeur inferieur k+1 */ if (nb==k+1) {E1[id]=P2[i];// si on a fait k+1 comparaisons donc la gne n'apparu pas et donc en l'ajoute a E1 id++;} } // le mm principe int ide=k+1; for(i=0;i<N;i++) { int nb=0; for (j=0;j<=k;j++) { if (P1[i]!=E2[j]) nb++; else break; } if (nb==k+1) {E2[ide]=P1[i]; ide++;} } } /* On fait maintenant la mutation */ void mutation(int P[], int E[]) { int i; for(i=0;i<7;i++) 10 se fait pour E2

E[i]=P[i]; int a,b,c; // on choisi les point de mutation alatoirement do { a=rand()%7; b=rand()%7; }while(a==b); c=E[a]; //on pose le contenu de E[a] dans un variable pour ne pas le perdre E[a]=E[b]; E[b]=c; } /* le remplacement et fait a l'intrieur du main */ int main(int argc, char *argv[]) { time_t ti; srand ((unsigned) time(&ti)); int ind[10],pop[taille_pop][10]; int r; int solution[7]={4,1,2,3,6,5,0}; int h=0; /* on va rpter un nombre des itrations quon choisi */ while(h<10) { generer_pop(pop); int nc=0; int nm=0; int C[10]; int M[10]; selection_mutation(&nm,M,pop); 11

selection_croisement(&nc, C, pop); int E[10]; int E1[10]; int E2[10];

int i=0; while(i<nc-1) {/* maintenant on vas faire la croisement de tt les individus de la population dans leur indices on t selectioner par la slection croisement */ croisement ( pop[C[i]], pop[C[i+1]], E1, E2); /* on fait le remplacement pour garder que les meilleurs entre les enfants est les parents*/ /* on a choisit de remplacer le pire des parents par le meilleur enfant si la fitness de ce dernier est plus grande de celle du pire parent */ if(fitness(E1)>=fitness(E2)) {if(fitness(pop[C[i]])<fitness(E1)&&fitness(pop[C[i]])<=fitness(pop[C[i+1]])) {int j; for(j=0;j<7;j++) pop[C[i]][j]=E1[j]; } else if(fitness(pop[C[i+1]])<fitness(E1)&&fitness(pop[C[i+1]])<fitness(pop[C[i]])) {int j; for(j=0;j<7;j++) pop[C[i+1]][j]=E1[j]; } } else {if(fitness(pop[C[i]])<fitness(E2)&&fitness(pop[C[i]])<=fitness(pop[C[i+1]])) {int j; for(j=0;j<7;j++) pop[C[i]][j]=E2[j]; } else if(fitness(pop[C[i+1]])<fitness(E2)&&fitness(pop[C[i+1]])<fitness(pop[C[i]])) {int j; 12

for(j=0;j<7;j++) pop[C[i+1]][j]=E2[j]; } } i=i+2; } // on mute la individu de la population slectionner en slection mutation et on remplace si enfant est meilleur while(i<nm) { mutation( pop[C[i]], E); if(fitness(pop[C[i]])<=fitness(E)) {int j; for(j=0;j<7;j++) pop[C[i]][j]=E[j]; } i++; } // a chaque itration on trouve l'indice de meilleur individu aprs tous les tapes r=meilleur_ind( pop); if(fitness(solution)<fitness(pop[r])) { int j; for(j=0;j<7;j++) solution[j]=pop[r][j]; } h++; } /* aprs rpter le while un nombre d'itrations on a une solution */ // on affiche la solution int i; printf("\nLa distance parcourue par la meilleur solution trouver est: 13

%.2f Km",distance(solution));

printf("\n"); printf("la soultion est "); printf("\n"); for(i=0;i<7;i++) printf("%d\t",solution[i]); getch(); return 0; }

Rsultat trouv avec 10 itrations

Remarque
14

La solution quon affiche la fin nest pas la seule avec une meilleure distance mais si la dernire meilleure solution que le programme a trouv. On peut aussi amliorer le programme on stockant toutes les meilleures solutions gales en une matrice et les afficher. On peut aussi afficher lhistorique de tous les rsultats trouvs et donc en peut chercher les rsultats gales la solution finale.
/* a chaque itration on affiche la meilleur solution trouver avant de faire les comparaison */ r=meilleur_ind( pop); printf(" ------iteration %d------" ,h); printf("\nLa distance parcourue est :%.2f Km",distance(pop[r])); printf("\nL'individu est :\n"); for(i=0;i<7;i++) printf("%d\t",pop[r][i]); printf("\n"); printf("\n");

Avec 4 itrations :

15

Si on augmente le nombre des itrations par exemple plus que nombre de ville est petit dans notre cas).

40 la solution trouver est optimale (car le

16

La solution toujours donner par le programme est 2030km qui la solution optimale.

Quelques tapes teste de notre programme : Le croisement :


int p1[7]={6,2,0,4,5,3,1}; int p2[7]={3,0,1,2,6,5,4}; int E1[7]; int E2[7]; croisement ( p1,p2,E1,E2); printf("--------------croisement1piont----------") printf("\nP1:") ; for (int i=0;i<7;i++) printf("\t%d",p1[i]) ; printf("\nP2:") ; for (int i=0;i<7;i++) printf("\t%d",p2[i]) ; printf("\n") ; printf("\nE1:") ; for (int i=0;i<7;i++) printf("\t%d",E1[i]) ; printf("\nE2:") ; for (int i=0;i<7;i++) printf("\t%d",E2[i]) ;

17

Mutation:

int p[7]={3,2,5,4,0,6,1}; int E[7]; mutation (p,E); printf("--------------Mutation deux ville qq ----------") printf("\np:") ; for (int i=0;i<7;i++) printf("\t%d",p[i]) ; printf("\n") ; printf("\nE:") ; for (int i=0;i<7;i++) printf("\t%d",E[i]) ;

18

Tentative croisement deux points


Comme le croisement deux points consiste prendre la partie entre les deux points de croisement pour lenfant1 du pre2 et les autres parties du pre1, et vis versa pour lenfant2. On a pens faire un croisement 1pionts jusqu le deuxime point de croisement avec le point de croisement ci la premier. Aprs on a juste a complter avec correction ce qui reste par les gnes du pre1. Comme ca la premire partie et la dernire seront pris du pre 1 et celle de milieu du pre2 (pour lenfant 1).
19

Code :
/* on a fait quelque changement dans le croisement ici il va recevoir K et m et on vas considrer qd vas croiser en individu de taille m au point k m et k son les de points qui vont tre choisi dans le croisement2piont et le reste si le mme principe que on a fait dans le croisement 1piont */ void croisement (int*k,int*m,int P1[],int P2[],int E1[],int E2[]) {int i,j; for(i=0;i<=*k;i++) { E1[i]=P1[i]; E2[i]=P2[i]; } int id=*k+1; for(i=0;i<=*m;i++) { int nb=0; for (j=0;j<=*k;j++) {if (P2[i]!=E1[j]) nb++; else break;} if (nb==*k+1) {E1[id]=P2[i]; id++;} } int ide=*k+1; 20

for(i=0;i<=*m;i++) { int nb=0; for (j=0;j<=*k;j++) { if (P1[i]!=E2[j]) nb++; else break; } if (nb==*k+1) {E2[ide]=P1[i]; ide++;} } } /* ici on reoit deux individu a croiser on fait appelle au croisement 1point pour croiser jusqu la grande points de croisement (le point de croisement et la plus petite) et on complte avec correction */ void croisement_2point (int P1[],int P2[],int E1[],int E2[]) {int i,j,h,m; int k; do{ k=rand()%7; h=rand()%7; }while(k+h>=6); m=k+h;/* pour sassurer de la plus petite et la plus grand on a choisi que la grande soit une somme de la plus petite et une autre valeur aussi choisi alatoirement et aussi que les deux point soit inferieur 6*/ int p1[7]; int p2[7]; // on pose les 2 individus dans deux autre jusqu la plus grand point de croisement for(i=0;i<=m;i++) {p1[i]=P1[i]; p2[i]=P2[i]; 21

} //on fait le croisement un point le point de croisement et k la plus petite croisement ( &k,&m,p1, p2, E1, E2); // On complte avec correction E1 de P1 ET E2 de P2 int id=m+1; for(i=0;i<N;i++) { int nb=0; for (j=0;j<=m;j++) {if (P1[i]!=E1[j]) nb++; else break;} if (nb==m+1) {E1[id]=P1[i]; id++;} } int ide=m+1; for(i=0;i<N;i++) { int nb=0; for (j=0;j<=m;j++) { if (P2[i]!=E2[j]) nb++; else break; } if (nb==m+1) {E2[ide]=P2[i]; ide++;} } } 22

23

Das könnte Ihnen auch gefallen