main.py
# Algorithme génétique - sélection empirique dans un champ de maïs
# Importation
import random
random.seed(3)
from random import randint, random
import numpy as np
# Définition des fonctions principales
def individual(min, max):
# Un individu est un épi de maïs, caractérisé par sa position 2D et son rendement
return randint(min, max)
def population(min, max, lx, ly):
# La population est un champ constitué d'épis de maïs
# lx, ly: longueur et largeur du champ, respectivement
pop = np.array([[individual(min, max) for i in range(lx)] for j in range(ly)], dtype = int)
return pop
def grade(pop, max, lx, ly):
# Calcul de la performance globale du champ à une génération donnée
total_yield = 0
number_of_indiv = lx*ly
for i in range(lx):
for j in range(ly):
ind_yield = pop[i][j]
total_yield += ind_yield
field_fitness = (lx*ly*max - total_yield)/(lx*ly*max)*100 # écart relatif au champ optimal (en pourcentage)
return field_fitness
def evolve(pop, min, max, lx, ly, retain_length = 0.1, random_select = 0.2, mutate = 0.1, verbose = 0):
"""
Cette fonction prend en entrée les paramètres :
pop : la population au tour N
min, max : les valeurs minimale et maximale du rendement possibles pour un épi
lx, ly : les dimensions du champ
retain_length : la proportion des meilleurs épis à garder d'une génération à l'autre
random_select : la proportion d'épis à retenir d'un tour à l'autre (indépendamment de leur rendement)
mutate : le taux de mutation (évolution aléatoire du rendement) chez la population
eps : paramètre de croisement
"""
# Classement des individus
grades = []
for i in range(lx):
for j in range(ly):
ind_yield = pop[i][j]
grades.append([ind_yield, i, j]) # l'évaluation des individus se fait directement via leur rendement
f = lambda x : x[0]
ranking = sorted(grades, key = f, reverse = True) # classement des épis par ordre décroissant de rendement
retain_length = int(len(grades)*retain_length)
# On garde une proportion des meilleurs individus pour peupler la prochaine génération
parents = ranking[:retain_length]
if verbose == 1:
print(len(parents), " épis ont été sélectionnés comme les plus performants.")
# Ajout d'épi de maïs au hasard parmi les autres individus pour la diversité génétique
for individual in ranking[retain_length:]:
if random_select > random():
parents.append(individual)
if verbose == 1:
print(len(parents), " épis ont été sélectionnés après diversité génétique.")
# Mutation de certains parents au hasard
for individual in parents:
if mutate > random():
new_yield = randint(min, max)
individual[0] = new_yield
# Croisement des parents pour créer la nouvelle génération
parents_length = len(parents)
parents_positions = [[indiv[1], indiv[2]] for indiv in parents]
children = []
# On itère sur les épis du champ
for i in range(lx):
for j in range(ly):
if not [i, j] in parents_positions:
# On choisit un épi père et un épi mère parmi les parents
ind_male = randint(0, parents_length - 1)
ind_female = randint(0, parents_length - 1)
while ind_male == ind_female:
# Il faut que les épis parents soient différents
ind_male = randint(0, parents_length - 1)
ind_female = randint(0, parents_length - 1)
# Puis on hybride les parents pour créer un enfant épi de maïs :)
male = parents[ind_male]
female = parents[ind_female]
if male[0] >= female[0]:
child_yield = randint(female[0], male[0])
child = [child_yield, i, j]
elif female[0] > male[0]:
child_yield = randint(male[0], female[0])
child = [child_yield, i, j]
# Que l'on l'ajoute aux enfants
children.append(child)
# Et enfin on ajoute les hybridés aux parents de la prochaine génération
parents.extend(children)
# Peuplement de la population par la nouvelle génération
for indiv in parents:
pop[indiv[1]][indiv[2]] = indiv[0]
return pop