Vous êtes sur la page 1sur 23
TP ALGORITME GENITIQUE Master Recherche Opérationnelle

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<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 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<N;i++)

{

ind[i]=rand()%7;

for(int j=0;j<i;j++) if(ind[j]==ind[i]) i--; // on s'assurent que l’individu soit réalisable (le meme nombre(ville)ne se répètent pas)

}

}

/* génère 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");

}

}

5

/* 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 sélectionner aléatoirement l'indice d'un individu de la population on fera appelle a cette fonction dans selection_tournois */ int selection_alia() { int id;

6

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<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 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<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 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<N;i++)

{

int nb=0;/* on déclare un variable pour savoir si chaque gêne 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 gêne 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 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<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++;}

}

}

se fait pour E2

/* 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<nc-1)

{/* maintenant on vas faire la croisement de tt les individus de la population dans leur indices on été selectioner par la sélection 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 sélectionner en sélection 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 itération on trouve l'indice de meilleur individu après 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++;

/*

après répéter le while un nombre d'itérations on a une solution */ // on affiche la solution int i; printf("\nLa distance parcourue par la meilleur solution trouver est:

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

13

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

printf( "%d\t" ,solution[i]); getch(); return 0 ; } Résultat trouvé avec 10 itérations Remarque 14

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 40 la solution

Si on augmente le nombre des itérations par exemple plus que 40 la solution trouver est optimale (car le nombre de ville est petit dans notre cas).

par exemple plus que 40 la solution trouver est optimale (car le nombre de ville est

16

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

Quelques étapes Le croisement :

teste de notre programme :

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 ,

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

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 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 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<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