597 lines
19 KiB
Markdown
597 lines
19 KiB
Markdown
|
|
## Les algorithmes génétiques
|
|||
|
|
|
|||
|
|
* Présentation
|
|||
|
|
|
|||
|
|
- Les *algorithmes génétiques* font partie des algorithmes
|
|||
|
|
évolutionnistes.
|
|||
|
|
- S'inspirent des mécanismes de sélection naturelle pour approcher
|
|||
|
|
une solution d'un problème *d'optimisation*.
|
|||
|
|
- S'appliquent bien dans le cas où l'espace des solutions est grand.
|
|||
|
|
|
|||
|
|
|
|||
|
|
* Darwin
|
|||
|
|
|
|||
|
|
- /De l'origine des espèces/
|
|||
|
|
- les individus les mieux adaptés à leur environnement survivent et
|
|||
|
|
se reproduisent davantage en transmettant les variations utiles à
|
|||
|
|
la survie.
|
|||
|
|
- L'espèce évolue en s'adaptant à son environnement.
|
|||
|
|
- C'est le principe de *sélection naturelle*
|
|||
|
|
|
|||
|
|
|
|||
|
|
* Sélection naturelle
|
|||
|
|
|
|||
|
|
Trois principes :
|
|||
|
|
- Variation : les individus diffèrent les uns des autres et d'une
|
|||
|
|
génération à l'autre ;
|
|||
|
|
- Adaptation : les individus les mieux adaptés survivent et se
|
|||
|
|
reproduisent davantage ;
|
|||
|
|
- Hérédité : les caractéristiques sont héréditaires et se
|
|||
|
|
transmettent de génération en génération.
|
|||
|
|
|
|||
|
|
|
|||
|
|
* Principes
|
|||
|
|
|
|||
|
|
** Problèmes et solution
|
|||
|
|
|
|||
|
|
On dispose d'un problème d'optimisation :
|
|||
|
|
|
|||
|
|
$$\max_{s\in R}\lbrace f(s) \rbrace$$
|
|||
|
|
|
|||
|
|
- $R$ est l'espace des solutions *réalisables*
|
|||
|
|
- $f$ est la fonction *objectif*, où encore :
|
|||
|
|
- fonction d'évaluation ,
|
|||
|
|
- fonction d'adaptation ,
|
|||
|
|
- fonction de fitness.
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
** Le principe des algorithmes génétiques
|
|||
|
|
|
|||
|
|
- travailler avec un sous-ensemble $P$ de $R$ appelé *population* ;
|
|||
|
|
- On fait évoluer $P$ en lui appliquent des opérateurs génétiques
|
|||
|
|
pour produire une nouvelle génération ;
|
|||
|
|
- On favorise les individus les mieux adaptés (valeur de $f$ plus
|
|||
|
|
élevée) lors de la production de la génération suivante ;
|
|||
|
|
- Après $n$ générations, on choisit un individu dans la population.
|
|||
|
|
|
|||
|
|
|
|||
|
|
** génome
|
|||
|
|
|
|||
|
|
- Les individus sont représentés par leur génôme : suite finie de
|
|||
|
|
$k$ symboles ;
|
|||
|
|
- Ces symboles représentent les caractéristiques d'un individu,
|
|||
|
|
c'est-à-dire un gène ;
|
|||
|
|
|
|||
|
|
Chercher la solution optimale consiste à chercher une séquence de
|
|||
|
|
symboles optimale.
|
|||
|
|
|
|||
|
|
Idée à respecter : plus l'adaptation est élevée, plus l'individu
|
|||
|
|
est proche de la solution.
|
|||
|
|
|
|||
|
|
** Opérateurs génétiques
|
|||
|
|
|
|||
|
|
Il existe trois opérateurs génétiques :
|
|||
|
|
|
|||
|
|
*** la *sélection*
|
|||
|
|
choix des individus d'une population qui vont survivre à la
|
|||
|
|
génération suivante :
|
|||
|
|
- Les individus les mieux adaptés ont plus de
|
|||
|
|
chance de survivre ;
|
|||
|
|
- Méthode du /tournoi/ .
|
|||
|
|
|
|||
|
|
|
|||
|
|
*** le *croisement*
|
|||
|
|
|
|||
|
|
Combine les gènes de deux individus pour en produire deux
|
|||
|
|
nouveaux :
|
|||
|
|
- croisement **1 point** : découpe des deux génome au même
|
|||
|
|
endroit, puis échange ,
|
|||
|
|
- croisement **2 points** : découpe chacun des génomes en trois
|
|||
|
|
portions , on échange les gènes des parties médianes.
|
|||
|
|
|
|||
|
|
|
|||
|
|
*** La *mutation*
|
|||
|
|
|
|||
|
|
- Mutation /aléatoire/ des caractéristiques d'un individu ;
|
|||
|
|
- Réalisée avec une probabilité faible ;
|
|||
|
|
- Permet de faire apparaitre dans une population de nouvelles
|
|||
|
|
caractéristiques
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
* L'algorithme génétique
|
|||
|
|
|
|||
|
|
Notre algorithme travaillera avec une population constante d'une
|
|||
|
|
génération à l'autre.
|
|||
|
|
|
|||
|
|
** Entrées
|
|||
|
|
- la fonction de /fitness/ du problème ;
|
|||
|
|
- le nombre d'individus $n$ pair ;
|
|||
|
|
- le nombre de génération $g$ ;
|
|||
|
|
- la probabilité de mutation $p$.
|
|||
|
|
|
|||
|
|
|
|||
|
|
** L'algorithme
|
|||
|
|
|
|||
|
|
1. population $\leftarrow$ $n$ individus créés aléatoirement.
|
|||
|
|
2. calculer pour chaque individu de population son degré
|
|||
|
|
d'adaptation.
|
|||
|
|
3. répéter $g$ fois
|
|||
|
|
4. $\quad$ next_gen_1 $\leftarrow$ sélectionner par tournoi
|
|||
|
|
$\frac{n}{2}$ individus de la population
|
|||
|
|
5. $\quad$ next_gen_2 $\leftarrow$ créer $\frac{n}{2}$ individus
|
|||
|
|
par croisement entre individus de population
|
|||
|
|
6. $\quad$ next_gen $\leftarrow$ next_gen_1 + next_gen_2
|
|||
|
|
7. $\quad$ faire muter chacun des individus de next_gen
|
|||
|
|
8. $\quad$ calculer pour chaque individu de next_gen son degré
|
|||
|
|
d'adaptation
|
|||
|
|
9. $\quad$ meilleurs $\leftarrow$ les 5 individus les mieux adaptés de population
|
|||
|
|
10. $\quad$ retirer de next_gen les 5 individus les moins adaptés
|
|||
|
|
11. $\quad$ population $\leftarrow$ neilleurs + next_gen
|
|||
|
|
12. solution $\leftarrow$ individu le mieux adapté de population
|
|||
|
|
|
|||
|
|
** Sélection par tournoi
|
|||
|
|
|
|||
|
|
- La sélection par tournoi dans une population de taille $n$
|
|||
|
|
consiste à choisir aléatoirement deux individus de la population
|
|||
|
|
pour ne garder que l'individu le mieux adapté des deux.
|
|||
|
|
- On répète ce processus de sorte que chaque individu est choisi
|
|||
|
|
exactement une fois. On obtient donc $\frac{n}{2}$ individus à la
|
|||
|
|
fin de cette phase.
|
|||
|
|
|
|||
|
|
** Croisements
|
|||
|
|
|
|||
|
|
- Croisement à un point
|
|||
|
|
- On choisit aléatoirement deux individus de la population pour
|
|||
|
|
construire deux nouveaux individus
|
|||
|
|
- On applique ensuite un tournoi entre les deux individus produits
|
|||
|
|
pour ne garder que le meilleur
|
|||
|
|
- On répète ce processus de sorte que chaque individu est choisi
|
|||
|
|
exactement une fois. On obtient donc $\frac{n}{2}$ individus à la
|
|||
|
|
fin de cette phase.
|
|||
|
|
|
|||
|
|
** Mutations
|
|||
|
|
|
|||
|
|
- Pour chacun des individus considérés, il y a une probabilité $p$
|
|||
|
|
que chacune de ses caractéristiques mute. C'est-à-dire que la
|
|||
|
|
valeur de cette caractéristique est modifiée
|
|||
|
|
aléatoirement. L'individu est donc remplacé par sa /version
|
|||
|
|
mutée/.
|
|||
|
|
|
|||
|
|
- À la fin de la population la taille de la population est la même.
|
|||
|
|
|
|||
|
|
|
|||
|
|
* Programmation
|
|||
|
|
|
|||
|
|
Plusieurs classes :
|
|||
|
|
- l'algorithme génétique,
|
|||
|
|
- le problème traité et
|
|||
|
|
- les individus.
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
** l'algorithme génétique
|
|||
|
|
|
|||
|
|
- classe `AlgoGen`.
|
|||
|
|
|
|||
|
|
|
|||
|
|
#+begin_src python :tangle src/algo_gen.py :exports none
|
|||
|
|
import random
|
|||
|
|
|
|||
|
|
BEST_KEPT = 5
|
|||
|
|
|
|||
|
|
class AlgoGen(object):
|
|||
|
|
|
|||
|
|
def __init__(self, problem, population_size, crossover_rate, mutation_probability):
|
|||
|
|
'''
|
|||
|
|
build an genetic algorithm to solve problem using a population of size population_size and a probability of muation of mutation_probability
|
|||
|
|
|
|||
|
|
:param problem: the problem to solve
|
|||
|
|
:type problem: a Problem object
|
|||
|
|
:param population_size: the size of the population (must be even)
|
|||
|
|
:type population_size: int
|
|||
|
|
:param mutation_probability: the mutation probability
|
|||
|
|
:type mutation_probability: float
|
|||
|
|
:UC: population_size must be even and mutation_probability must be 0<= and <1
|
|||
|
|
'''
|
|||
|
|
self.__problem = problem
|
|||
|
|
self.__population_size = population_size
|
|||
|
|
self.__population = []
|
|||
|
|
self.__nb_crossover = crossover_rate
|
|||
|
|
self.__mutation_probability = mutation_probability
|
|||
|
|
|
|||
|
|
def get_population(self):
|
|||
|
|
return self.__population
|
|||
|
|
|
|||
|
|
def genesis(self):
|
|||
|
|
"""
|
|||
|
|
create the population
|
|||
|
|
"""
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
def evaluate_population(self, population):
|
|||
|
|
"""
|
|||
|
|
evalue la population passée en paramètre
|
|||
|
|
:param population: (list) la population
|
|||
|
|
"""
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
|
|||
|
|
def next_generation_tournament(self, population):
|
|||
|
|
'''
|
|||
|
|
organise un tournoi entre les individu d'une population .
|
|||
|
|
chaque individu choisi une et une seule fois, dans un tournoi ,
|
|||
|
|
vainqueur conservé taille résultat = 1/2 taille population
|
|||
|
|
|
|||
|
|
:param population: (list) la population
|
|||
|
|
:return: (list) les vainqueurs du tournoi
|
|||
|
|
'''
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
def crossover(self, population):
|
|||
|
|
'''Croise les individus d'une population.
|
|||
|
|
|
|||
|
|
Chaque individu est sélectionné une et une seule fois, on
|
|||
|
|
garde le meilleur descendant à chaque fois.
|
|||
|
|
|
|||
|
|
taille résultat = 1/2 taille population
|
|||
|
|
|
|||
|
|
:param population: (list) a population
|
|||
|
|
:return: (list) new individuals
|
|||
|
|
'''
|
|||
|
|
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
def mutate(self, individuals):
|
|||
|
|
"""
|
|||
|
|
mute les individus
|
|||
|
|
:param individuals: (list) une liste des individus
|
|||
|
|
"""
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
def one_round(self):
|
|||
|
|
'''
|
|||
|
|
applique successivement les opéréateurs
|
|||
|
|
- selection
|
|||
|
|
- croisement
|
|||
|
|
- mutation
|
|||
|
|
'''
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
|
|||
|
|
def solve(self, nb_rounds):
|
|||
|
|
"""
|
|||
|
|
tente d'approcher une solution en faisant muter la population
|
|||
|
|
:param nb_rounds: (int) nombre de génération
|
|||
|
|
"""
|
|||
|
|
self.genesis()
|
|||
|
|
self.evaluate_population(self.__population)
|
|||
|
|
self.display_stat('INITIAL')
|
|||
|
|
for step in range(nb_rounds):
|
|||
|
|
self.one_round()
|
|||
|
|
#self.display_population(step=step+1, number = 20)
|
|||
|
|
self.display_stat(step)
|
|||
|
|
#self.display_population(number = 20) # display 20 best individuals
|
|||
|
|
return self.__problem.best_individual(self.__population)
|
|||
|
|
|
|||
|
|
|
|||
|
|
def display_stat(self, step):
|
|||
|
|
best = self.__problem.best_individual(self.__population)
|
|||
|
|
all_scores = [ individual.get_score() for individual in self.__population ]
|
|||
|
|
average = sum (all_scores) / self.__population_size
|
|||
|
|
print ( ' STEP = {} -- best = {} - avg = {} '.format(step, best, average) )
|
|||
|
|
|
|||
|
|
|
|||
|
|
def display_population(self, step = ' ', number = 0):
|
|||
|
|
if number <= 0:
|
|||
|
|
individuals = self.__population
|
|||
|
|
else:
|
|||
|
|
individuals = self.__population[:min(number, len(self.__population))]
|
|||
|
|
print( ' **** STEP : {} ********* '.format(step) )
|
|||
|
|
for individual in individuals :
|
|||
|
|
print ( individual )
|
|||
|
|
print( )
|
|||
|
|
|
|||
|
|
|
|||
|
|
# tool function
|
|||
|
|
def biased_wheel(alea,scores):
|
|||
|
|
'''
|
|||
|
|
return smallest i such that alea < sum(scores[k], 0 <= k < i)
|
|||
|
|
CU : 0 <= alea < sum(scores)
|
|||
|
|
'''
|
|||
|
|
current_sum = 0
|
|||
|
|
result_index = -1
|
|||
|
|
while alea > current_sum :
|
|||
|
|
result_index = result_index + 1
|
|||
|
|
current_sum = current_sum + scores[result_index]
|
|||
|
|
return result_index
|
|||
|
|
#+end_src
|
|||
|
|
|
|||
|
|
** les problèmes
|
|||
|
|
|
|||
|
|
Comme indiqué, les classes pour représenter les problèmes devront
|
|||
|
|
partager certaines méthodes. Nous suggérons les méthodes suivantes
|
|||
|
|
comme méthodes communes aux problèmes. Evidemment, il peut exister
|
|||
|
|
d'autres méthodes spécifiques à chacun des problèmes. Notamment la
|
|||
|
|
manière de calculer l'adaptation d'un individu variera.
|
|||
|
|
|
|||
|
|
#+begin_src python :tangle src/problem_interface.py :exports none
|
|||
|
|
class Problem_Interface(object):
|
|||
|
|
'''
|
|||
|
|
a prototype class for "problems" in genetic algorithm
|
|||
|
|
|
|||
|
|
an Individual class must be associated to a problem to represent the individuals
|
|||
|
|
'''
|
|||
|
|
|
|||
|
|
def create_individual(self):
|
|||
|
|
'''
|
|||
|
|
create a randomly generated indidivual for this problem
|
|||
|
|
|
|||
|
|
:return: a randomly generated individual gfor this problem
|
|||
|
|
:rtype: an Individual object
|
|||
|
|
'''
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
def evaluate_fitness(self, individual):
|
|||
|
|
'''
|
|||
|
|
compute the fitness of individual for this problem
|
|||
|
|
|
|||
|
|
:param individual: the individual to consider
|
|||
|
|
:type individual: an Individual object
|
|||
|
|
:return: the fitness of individual for this problem
|
|||
|
|
:rtype: an Individual object
|
|||
|
|
'''
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
def sort_population(self, population):
|
|||
|
|
'''
|
|||
|
|
sort population from best fitted to worst fitted individuals.
|
|||
|
|
Depending on the problem, it can correspond to ascending or descending order with respect to the fitness function.
|
|||
|
|
|
|||
|
|
side effect : population is modified by this method
|
|||
|
|
|
|||
|
|
:param population: the list of individuals to sort
|
|||
|
|
:type population: list(Individual)
|
|||
|
|
'''
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
def best_individual(self, population):
|
|||
|
|
'''
|
|||
|
|
return the best fitted individual from population.
|
|||
|
|
Depending on the problem, it can correspond to the individual with the highest or the lowest fitness value.
|
|||
|
|
|
|||
|
|
|
|||
|
|
:param population: the list of individuals to sort
|
|||
|
|
:type population: list(Individual)
|
|||
|
|
:return: the best fitted individual of population
|
|||
|
|
:rtype: an Individual object
|
|||
|
|
'''
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
def tournament(self, first, second):
|
|||
|
|
'''
|
|||
|
|
perform a rounament between two individuals, the winner is the most fitted one, it is returned
|
|||
|
|
|
|||
|
|
|
|||
|
|
:param first: an individual
|
|||
|
|
:type first: an Indivdual object
|
|||
|
|
:param second: an individual
|
|||
|
|
:type second: an Individual object
|
|||
|
|
:return: the winner of the tournament
|
|||
|
|
:rtype: Individual object
|
|||
|
|
'''
|
|||
|
|
pass
|
|||
|
|
#+end_src
|
|||
|
|
|
|||
|
|
** les individus
|
|||
|
|
|
|||
|
|
Les classes pour les individus devront partager certaines
|
|||
|
|
méthodes. Nous suggérons les méthodes suivantes comme méthodes
|
|||
|
|
communes aux individus. Evidemment, il peut exister d'autres méthodes
|
|||
|
|
spécifiques à chacun des individus, et notamment, les valeurs des
|
|||
|
|
génomes vont différer.
|
|||
|
|
|
|||
|
|
#+begin_src python :tangle src/individual_interface.py :exports none
|
|||
|
|
import random
|
|||
|
|
|
|||
|
|
|
|||
|
|
class Individual_Interface(object):
|
|||
|
|
'''
|
|||
|
|
an Individual in genteic algorithm problem
|
|||
|
|
|
|||
|
|
the value (or genome) of an indal is a sequence (e.g string or list) of a fixed size
|
|||
|
|
|
|||
|
|
an individual has a fitness score
|
|||
|
|
'''
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
def __init__(self, size):
|
|||
|
|
'''
|
|||
|
|
create an Individual object, its genome value is randomly built. Initially score is not set.
|
|||
|
|
|
|||
|
|
:param size: size of the genome
|
|||
|
|
:type size: int
|
|||
|
|
'''
|
|||
|
|
self.__score = None
|
|||
|
|
self.__size = size
|
|||
|
|
self.__value = self.init_value()
|
|||
|
|
|
|||
|
|
def copy(self):
|
|||
|
|
'''
|
|||
|
|
build a copy of self, the genome is a copy of self's genome
|
|||
|
|
|
|||
|
|
:return: a new Individual which is a "clone" of self
|
|||
|
|
:rtype: an Individual object
|
|||
|
|
'''
|
|||
|
|
return None
|
|||
|
|
|
|||
|
|
def get_size(self):
|
|||
|
|
'''
|
|||
|
|
:return: the size of self's genome
|
|||
|
|
:rtype: int
|
|||
|
|
'''
|
|||
|
|
|
|||
|
|
return self.__size
|
|||
|
|
|
|||
|
|
def get_score(self):
|
|||
|
|
'''
|
|||
|
|
:return: the fitness score of self
|
|||
|
|
:rtype: number
|
|||
|
|
'''
|
|||
|
|
return self.__score
|
|||
|
|
|
|||
|
|
def set_score(self, new_score):
|
|||
|
|
'''
|
|||
|
|
change the fitness score of self
|
|||
|
|
|
|||
|
|
:param new_score: the new fitness score
|
|||
|
|
:type new_score: number
|
|||
|
|
'''
|
|||
|
|
self.__score = new_score
|
|||
|
|
|
|||
|
|
def __str__(self):
|
|||
|
|
return "{} ({})".format(self.__value, self.__score)
|
|||
|
|
|
|||
|
|
def __repr__(self):
|
|||
|
|
return self.__str__()
|
|||
|
|
|
|||
|
|
def get_value(self):
|
|||
|
|
'''
|
|||
|
|
:return: the genome of self
|
|||
|
|
:rtype: sequence
|
|||
|
|
'''
|
|||
|
|
return self.__value
|
|||
|
|
|
|||
|
|
def set_value(self, new_value):
|
|||
|
|
'''
|
|||
|
|
change the genome value of self
|
|||
|
|
|
|||
|
|
:param new_score: the new genome value
|
|||
|
|
:type new_score: sequence
|
|||
|
|
'''
|
|||
|
|
self.__value = new_value
|
|||
|
|
|
|||
|
|
def init_value(self):
|
|||
|
|
'''
|
|||
|
|
randomly initialize the genome value of self
|
|||
|
|
'''
|
|||
|
|
return None
|
|||
|
|
|
|||
|
|
def evaluate(self,problem):
|
|||
|
|
'''
|
|||
|
|
set the fitness score with the fitness computed by problem for self
|
|||
|
|
|
|||
|
|
:param problem: the problem
|
|||
|
|
:type problem: a Problem object
|
|||
|
|
'''
|
|||
|
|
self.set_score(problem.evaluate_fitness(self))
|
|||
|
|
|
|||
|
|
def cross_with(self, other):
|
|||
|
|
'''
|
|||
|
|
perform a 1 point crossover between self and other, two new built individuals are returned
|
|||
|
|
|
|||
|
|
:param other: the individual to croww with
|
|||
|
|
:type other: an Idnividual object
|
|||
|
|
:return: the two new Individuals built by 1 point crossover operation
|
|||
|
|
:rtype: 2-uple of individuals
|
|||
|
|
'''
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
def mutate(self, probability):
|
|||
|
|
'''
|
|||
|
|
apply mutation operation to self : each element of the geome sequence is randomly changed with given probabiliy
|
|||
|
|
|
|||
|
|
side effect : self's genome is modified
|
|||
|
|
|
|||
|
|
:param probability: the probability of mutation for every gene
|
|||
|
|
:type probability: float
|
|||
|
|
:UC: probability in [0,1[
|
|||
|
|
'''
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
def mutate_gene(self, gene):
|
|||
|
|
pass
|
|||
|
|
#+end_src
|
|||
|
|
|
|||
|
|
|
|||
|
|
* Problème 1 : Calcul de la valeur maximale d'une fonction
|
|||
|
|
|
|||
|
|
Problème : trouver dans un intervalle $[x_\mbox{min};x_\mbox{max}]$
|
|||
|
|
une valeur de $x$ pour laquelle $f(x)$ est maximale.
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
* Problème 2 : Recherche d'un message "secret"
|
|||
|
|
|
|||
|
|
** Description
|
|||
|
|
Cette fois, il ne s'agit pas à proprement parler d'un problème à
|
|||
|
|
résoudre, puisqu'on en connaît la solution au départ... Ce second
|
|||
|
|
exemple a pour objectif d'illustrer que les algorithmes génétiques
|
|||
|
|
peuvent trouver une solution dans un très grand espace de recherche.
|
|||
|
|
|
|||
|
|
** Problème
|
|||
|
|
Le problème est celui de faire trouver une chaîne de caractères à un
|
|||
|
|
algorithme génétique. On suppose cette chaîne construite à partir du
|
|||
|
|
caractère espace et des 26 lettres de l'alphabet (minuscules et non
|
|||
|
|
accentuées). Si elle est le longueur 30, il existe alors *27^30*
|
|||
|
|
chaînes possibles.
|
|||
|
|
|
|||
|
|
Nous allons donc vérifier qu'en explorant qu'une petite partie de
|
|||
|
|
toutes ces possibilités, un
|
|||
|
|
algorithme génétique est capable de trouver l'une d'entre elles.
|
|||
|
|
|
|||
|
|
|
|||
|
|
Par exemple, nous allons considérer la chaine
|
|||
|
|
*secret* = ~'ceci est un secret a retrouver'~.
|
|||
|
|
|
|||
|
|
|
|||
|
|
* Problème 3 : Recherche d'un chemin dans un labyrinthe
|
|||
|
|
|
|||
|
|
** Labyrinthe
|
|||
|
|
|
|||
|
|
#+begin_example
|
|||
|
|
7;7
|
|||
|
|
+-+-+-+-+-+-+-+
|
|||
|
|
| | |
|
|||
|
|
+ + +-+ + +-+ +
|
|||
|
|
| | | | |
|
|||
|
|
+ + +-+ + + + +
|
|||
|
|
| | | | |
|
|||
|
|
+ +-+ +-+-+ + +
|
|||
|
|
| | | |
|
|||
|
|
+ + +-+-+ +-+-+
|
|||
|
|
| | | |
|
|||
|
|
+ +-+-+ + +-+ +
|
|||
|
|
| | | | |
|
|||
|
|
+ + + +-+-+ +-+
|
|||
|
|
| | |
|
|||
|
|
+-+-+-+-+-+-+-+
|
|||
|
|
|
|||
|
|
#+end_example
|
|||
|
|
|
|||
|
|
** Problème
|
|||
|
|
Le problème consiste à trouver dans un tel labyrinthe de taille *N*
|
|||
|
|
(ici *N=7x7=49*) donné, un chemin entre la case d'entrée située en
|
|||
|
|
haut à gauche et celle de sortie située en bas à droite.
|
|||
|
|
|
|||
|
|
Pour simplifier on considère que les largeur et hauteur du
|
|||
|
|
labyrinthe sont identiques.
|
|||
|
|
|
|||
|
|
|
|||
|
|
** Matériel
|
|||
|
|
|
|||
|
|
- une classe ~Maze~ permettant de gérer les labyrinthes (fichier ~maze.py~);
|
|||
|
|
- des exemples de labyrinthe (fichier ~maze.zip~)
|
|||
|
|
|
|||
|
|
|
|||
|
|
* Problème 4 : le TSP
|
|||
|
|
|
|||
|
|
Utiliser un algorithme génétique pour approcher une solution du
|
|||
|
|
Problème du voyageur de commerce.
|