TP ALGORITME GENITIQUE Master Recherche Opérationnelle
INTRODUCTION Les algorithmes génétiques appartiennent à la famille des algorithmes évolutionnistes. Leur but est d'obtenir une solution approchée à un problème d'optimisation pour le résoudre en un temps raisonnable. Les algorithmes génétiques utilisent la notion de sélection naturelle et l'appliquent à une population de solutions potentielles au problème donné. Origine : L'utilisation d'algorithmes génétiques, dans la résolution de problèmes, est à l'origine le fruit des recherches de John Holland et de ses collègues et élèves de l'Université du Michigan qui ont, dès1960, travaillé sur ce sujet. Problème de voyageur de commerce Le problème du voyageur de commerce consiste, étant donné un ensemble de villes séparées par des distances données, à trouver le plus court chemin qui relie toutes les villes et retourner à la ville de départ .tel que chaque ville n’est visiter qu’une fois . Il s'agit d'un problème d'optimisation pour lequel on ne connait pas d'algorithme permettant de trouver une solution exacte en un temps polynomial.
2
Enoncée : On se propose de résoudre le problème de voyageur de commerce par un AG . On cherche à déterminer le plus court chemin Hamiltonien passant par les villes : Agadir, Casablanca, Fès, Marrakech, Meknès, Rabat, Tanger.
CODE : #include #include #include #include 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
/* cette fonction génère un individu aléatoirement et en même 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
*/ void {
generer_pop(int pop[taille_pop][10]) for(int i=0;i
} /* afficher un individu */ void afficher(int n,int T[]) { for(int i=0;i
5
/* calcule la distance (le cout ) d'un individu */ float distance(int ind[]) { float Dist=0; for(int i=0;ifitness(pop[id])) id=i; return id; } /* fonction qui permet de sélectionner aléatoirement 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 dépasser le pourcentage des individus à sélectionner ici 0,7. */ void selection_croisement(int*nc,int C[],int pop[10][10]) { float sommeFitness=0; int i; for(i=0;i
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 aprés
*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 même 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
/* on fait le croisement un point des ind sélectionner pour le croisement */ void croisement (int P1[],int P2[],int E1[],int E2[]) {int i,j; int k; do { k=rand()%7;// on sélectionne un point de croisement aléatoirement de façon 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 mêmes individu for(i=0;i<=k;i++) { E1[i]=P1[i]; E2[i]=P2[i]; } // Jusqu’a 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 compléter l'enfant 1 par les gènes du parent 2 qui sont déférent de ce qui existe déjà dans l'enfant 1*/ for(i=0;i
break;// Si il y a égalité pas la paine de continuité la comparaison } /* voila maintenant on va vérifier 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 gêne n'apparu pas et donc en l'ajoute a E1 id++;} } // le mm principe int ide=k+1; for(i=0;i
se fait pour E2
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
E[i]=P[i]; int a,b,c; // on choisi les point de mutation aléatoirement 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'intérieur 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 répéter un nombre des itérations qu’on 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=fitness(E2)) {if(fitness(pop[C[i]])
for(j=0;j<7;j++) pop[C[i+1]][j]=E2[j]; } } i=i+2; } // on mute la individu de la population sélectionner en sélection mutation et on remplace si enfant est meilleur while(i
%.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; }
Résultat trouvé avec 10 itérations
Remarque 14
La solution qu’on affiche à la fin n’est pas la seule avec une meilleure distance mais si la dernière meilleure solution que le programme a trouvé. On peut aussi améliorer le programme on stockant toutes les meilleures solutions égales en une matrice et les afficher. On peut aussi afficher l’historique de tous les résultats trouvés et donc en peut chercher les résultats égales à la solution finale. /* a chaque itération 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 itérations :
15
Si on augmente le nombre des itérations par exemple plus que nombre de ville est petit dans notre cas).
16
40 la solution trouver est optimale (car le
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 l’enfant1 du père2 et les autres parties du pére1, et vis versa pour l’enfant2. On a pensé à faire un croisement 1pionts jusqu’à le deuxième point de croisement avec le point de croisement ci la premier. Après on a juste a compléter avec correction ce qui reste par les gênes du pére1. Comme ca la première partie et la dernière seront pris du père 1 et celle de milieu du pére2 (pour l’enfant 1). 19
Code : /* on a fait quelque changement dans le croisement ici il va recevoir K et m et on vas considérer 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 même 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 reçoit 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 complète 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 s’assurer 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 aléatoirement 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 complète avec correction E1 de P1 ET E2 de P2 int id=m+1; for(i=0;i
23