# Librairie du projet en version impératif import random import Levenshtein def min_i(array: list[int]) -> int: min_val = array[0] min_i = 0 for i in range(len(array)): if array[i] < min_val: min_val = array[i] min_i = i return min_i def max_i(array: list[int]) -> int: max_val = array[0] max_i = 0 for i in range(len(array)): if array[i] > max_val: max_val = array[i] max_i = i return max_i def new_population(pm, ng, n, ts, tm, alpha, fm): # -> set(list(set(str)), str, int, int, int, float, float, float, int) """ fonction qui renvoie une nouvelle population """ population = { "individuals": [new_individual() for i in range(n)], "pm": pm, "ng": ng, "l": len(pm), "n": n, "ts": ts, "tm": tm, "alpha": alpha, "fm": fm } for individual in population["individuals"]: randomize(individual, len(pm)) return population def new_individual(): # -> set(str) """ fonction qui renvoie un nouvel individu """ return { "chromozome": "" } def randomize(individual, l) -> str: """ Methode qui change la valeur d'un chromozome pour une valeur aléatoire """ new = "" for i in range(l): new += chr(random.randint(0, 255)) individual["chromozome"] = new def fitness1(individual, pm) -> int: """ Première methode de fitness, fait la somme des différences entre les codages des caractères des deux chaînes. """ sum = 0 for i in range(len(individual["chromozome"])): sum += abs(ord(individual["chromozome"][i]) - ord(pm[i])) return -sum def fitness2(individual, pm, alpha) -> int: """ Deuxième methode de fitness qui compte les caractères bien placés et mal placés et qui renvoie un int pondéré par alpha """ match = 0 missed_placed = 0 for i in range(len(individual["chromozome"])): if individual["chromozome"][i] == pm[i]: match += 1 else: missed_placed += 1 return match + alpha * missed_placed def fitness3(individual, pm) -> int: """ Troisième methode de fitness qui utilise la distance de Levenshtein """ return -Levenshtein.distance(individual["chromozome"], pm) def get_fitness(population, individual) -> int: match population["fm"]: case 1: return fitness1(individual, population["pm"]) case 2: return fitness2(individual, population["pm"], population["alpha"]) case 3: return fitness3(individual, population["pm"]) case _: return fitness1(individual, population["pm"]) def get_best(population): """ Methode qui renvoie le meilleur individu de la population """ fitness_list = [] for individual in population["individuals"]: fitness_list.append(get_fitness(population, individual)) return population["individuals"][max_i(fitness_list)] def print_best(population) -> None: """ Methode qui affiche le meilleur individu de la population """ print(get_best(population)["chromozome"]) def mutate(individual) -> None: """ Methode qui change un des caractères du chromozome """ new = list(individual["chromozome"]) new[random.randint(0, len(new) - 1)] = chr(random.randint(0, 255)) individual["chromozome"] = "".join(new) def select(population) -> None: """ Methode qui sélectionne les meilleurs individus """ fitness_list = [] for individual in population["individuals"]: fitness_list.append(get_fitness(population, individual)) for i in range(int((1 - population["ts"]) * population["n"])): least = min_i(fitness_list) fitness_list.pop(least) population["individuals"].pop(least) def reproduct(population) -> None: """ Methode qui reproduit les individus entre eux jusqu'à obtenir une population de taille N """ new = [] while len(population["individuals"]) + len(new) != population["n"]: cut = random.randint(int(population["l"] / 3), int(2 * population["l"] / 3)) i = random.randint(0, len(population["individuals"]) - 1) j = random.randint(0, len(population["individuals"]) - 1) while i == j: j = random.randint(0, len(population["individuals"]) - 1) indivi_1 = population["individuals"][i] indivi_2 = population['individuals'][j] new_chromozome = indivi_1["chromozome"][:cut] + indivi_2["chromozome"][cut:] child = new_individual() child["chromozome"] = new_chromozome new.append(child) population["individuals"] += new def mutate_pop(population) -> None: """ Methode qui mute une partie de la population selon le taut de mutation """ mutated = [] for i in range(int(population["tm"] * population["n"])): to_mutate = random.randint(0, population["n"] - 1) while to_mutate in mutated: to_mutate = random.randint(0, population["n"] - 1) mutate(population["individuals"][to_mutate]) mutated.append(to_mutate) def run(population) -> None: """ Boucle principale """ for i in range(population["ng"]): select(population) reproduct(population) mutate_pop(population) print_best(population)