Saataa andagii !

This commit is contained in:
Lukian 2025-01-08 14:39:45 +01:00
parent 026033e6ad
commit 303063b78e

View file

@ -4,6 +4,9 @@ import random
import Levenshtein import Levenshtein
def min_i(array: list[int]) -> int: def min_i(array: list[int]) -> int:
"""
Fonction renvoyant l'indexe du minimum d'une liste d'entiers
"""
min_val = array[0] min_val = array[0]
min_i = 0 min_i = 0
for i in range(len(array)): for i in range(len(array)):
@ -13,6 +16,9 @@ def min_i(array: list[int]) -> int:
return min_i return min_i
def max_i(array: list[int]) -> int: def max_i(array: list[int]) -> int:
"""
Fonction renvoyant l'indexe du maximum d'une liste d'entiers
"""
max_val = array[0] max_val = array[0]
max_i = 0 max_i = 0
for i in range(len(array)): for i in range(len(array)):
@ -37,6 +43,7 @@ def new_population(pm, ng, n, ts, tm, alpha, fm):
"fm": fm "fm": fm
} }
# On rend aléatoire les chromozomes des individus
for individual in population["individuals"]: for individual in population["individuals"]:
randomize(individual, 4, 30) randomize(individual, 4, 30)
@ -76,6 +83,7 @@ def fitness2(individual, pm, alpha) -> int:
match = 0 match = 0
missed_placed = 0 missed_placed = 0
for i in range(len(individual["chromozome"])): for i in range(len(individual["chromozome"])):
# Si la chaîne est plus grande que la phrase alors on rajoute des caractères mal placés
if i >= len(pm): if i >= len(pm):
missed_placed += len(individual["chromozome"]) - len(pm) missed_placed += len(individual["chromozome"]) - len(pm)
break break
@ -83,6 +91,7 @@ def fitness2(individual, pm, alpha) -> int:
match += 1 match += 1
else: else:
missed_placed += 1 missed_placed += 1
# Si la phrase est trop longue on rajoute autant de caractères mal placés que de caractères en trop
if len(pm) > len(individual["chromozome"]): if len(pm) > len(individual["chromozome"]):
missed_placed += len(pm) - len(individual["chromozome"]) missed_placed += len(pm) - len(individual["chromozome"])
return match + alpha * missed_placed return match + alpha * missed_placed
@ -94,6 +103,9 @@ def fitness3(individual, pm) -> int:
return -Levenshtein.distance(individual["chromozome"], pm) return -Levenshtein.distance(individual["chromozome"], pm)
def get_fitness(population, individual) -> int: def get_fitness(population, individual) -> int:
"""
Fonction qui renvoie la fitness d'un individu en utilisant la fonction choisie en paramètre de la population
"""
match population["fm"]: match population["fm"]:
case 1: case 1:
return fitness1(individual, population["pm"]) return fitness1(individual, population["pm"])
@ -105,6 +117,9 @@ def get_fitness(population, individual) -> int:
return fitness1(individual, population["pm"]) return fitness1(individual, population["pm"])
def get_fitness_list(population): def get_fitness_list(population):
"""
Fonction renvoyant une liste des fitness de touts les individus d'une population
"""
fitness_list = [] fitness_list = []
for individual in population["individuals"]: for individual in population["individuals"]:
fitness_list.append(get_fitness(population, individual)) fitness_list.append(get_fitness(population, individual))
@ -129,11 +144,16 @@ def select(population) -> None:
""" """
fitness_list = get_fitness_list(population) fitness_list = get_fitness_list(population)
for i in range(int((1 - population["ts"]) * population["n"])): for i in range(int((1 - population["ts"]) * population["n"])):
# On détermine quel est le moins bon individu
least = min_i(fitness_list) least = min_i(fitness_list)
# On le supprime des deux listes
fitness_list.pop(least) fitness_list.pop(least)
population["individuals"].pop(least) population["individuals"].pop(least)
def get_two_random_individuals(population): def get_two_random_individuals(population):
"""
Fonction renvoyant deux individus choisis aléatoirement
"""
i = random.randint(0, len(population["individuals"]) - 1) i = random.randint(0, len(population["individuals"]) - 1)
j = random.randint(0, len(population["individuals"]) - 1) j = random.randint(0, len(population["individuals"]) - 1)
while i == j: while i == j:
@ -145,14 +165,19 @@ def reproduct(population) -> None:
Methode qui reproduit les individus entre eux jusqu'à obtenir une population de taille N Methode qui reproduit les individus entre eux jusqu'à obtenir une population de taille N
""" """
new = [] new = []
# On créé de nouveaux individus jusqu'à avoir atteint la taille de population demandée
while len(population["individuals"]) + len(new) != population["n"]: while len(population["individuals"]) + len(new) != population["n"]:
# On prend deux individus aléatoires
indivi_1, indivi_2 = get_two_random_individuals(population) indivi_1, indivi_2 = get_two_random_individuals(population)
# On calcule le cut en fonction de la moyenne des tailles des deux individus
avg = (len(indivi_1) + len(indivi_2)) // 2 avg = (len(indivi_1) + len(indivi_2)) // 2
cut = random.randint(avg // 3, 2 * avg // 3) cut = random.randint(avg // 3, 2 * avg // 3)
# On fait en sorte que le cut reste dans les valeurs possibles
while cut > len(indivi_1) or cut > len(indivi_2): while cut > len(indivi_1) or cut > len(indivi_2):
cut = random.randint(avg // 3, 2 * avg // 3) cut = random.randint(avg // 3, 2 * avg // 3)
# On créé le nouvel individu et on l'ajoute à la population
new_chromozome = indivi_1["chromozome"][:cut] + indivi_2["chromozome"][cut:] new_chromozome = indivi_1["chromozome"][:cut] + indivi_2["chromozome"][cut:]
child = new_individual() child = new_individual()
child["chromozome"] = new_chromozome child["chromozome"] = new_chromozome
@ -165,11 +190,15 @@ def mutate(individual) -> None:
Methode qui change un des caractères du chromozome Methode qui change un des caractères du chromozome
""" """
new = list(individual["chromozome"]) new = list(individual["chromozome"])
# On jette un dé 6 pour déterminer l'effet qu'aura la mutation
dice = random.randint(1, 6) dice = random.randint(1, 6)
# Sur un 1 on ajoute un caractère aléatoire
if dice == 1 and len(new) < 30: if dice == 1 and len(new) < 30:
new.insert(random.randint(0, len(new) - 1), chr(random.randint(0, 255))) new.insert(random.randint(0, len(new) - 1), chr(random.randint(0, 255)))
# Sur un 2 on retire un caractère aléatoire
elif dice == 2 and len(new) > 4: elif dice == 2 and len(new) > 4:
new.pop(random.randint(0, len(new) - 1)) new.pop(random.randint(0, len(new) - 1))
# Sinon on modifie un caractère déjà existant
else : else :
new[random.randint(0, len(new) - 1)] = chr(random.randint(0, 255)) new[random.randint(0, len(new) - 1)] = chr(random.randint(0, 255))
individual["chromozome"] = "".join(new) individual["chromozome"] = "".join(new)
@ -180,9 +209,11 @@ def mutate_pop(population) -> None:
""" """
mutated = [] mutated = []
for i in range(int(population["tm"] * population["n"])): for i in range(int(population["tm"] * population["n"])):
# Sélectionne un individu aléatoire qui n'a pas encore été muté à cette génération
to_mutate = random.randint(0, population["n"] - 1) to_mutate = random.randint(0, population["n"] - 1)
while to_mutate in mutated: while to_mutate in mutated:
to_mutate = random.randint(0, population["n"] - 1) to_mutate = random.randint(0, population["n"] - 1)
# Mutation de l'individu choisi
mutate(population["individuals"][to_mutate]) mutate(population["individuals"][to_mutate])
mutated.append(to_mutate) mutated.append(to_mutate)
@ -190,7 +221,9 @@ def run(population) -> int:
""" """
Boucle principale Boucle principale
""" """
# On fait autant de générations que demandé
for i in range(population["ng"]): for i in range(population["ng"]):
# On arrête le programme une fois la phrase retrouvée et on renvoie le nombre de générations utilisées
if get_best(population)["chromozome"] == population["pm"]: if get_best(population)["chromozome"] == population["pm"]:
return i return i
select(population) select(population)