From 757ea77cc575217d0b072d26819e30c439a17a79 Mon Sep 17 00:00:00 2001 From: Lukian Date: Tue, 7 Jan 2025 23:05:40 +0100 Subject: [PATCH] Saataa andagii ! --- README.md | 4 +- analyse.py | 103 +++++++++++ images/vari_ng.png | Bin 44831 -> 0 bytes lib/ultra_mastermind_imp.py | 274 ++++++++++++++--------------- lib/ultra_mastermind_obj.py | 300 ++++++++++++++++---------------- lib/ultra_mastermind_pp_imp.py | 308 +++++++++++++++++---------------- main.py | 1 + tests.py | 59 ------- 8 files changed, 549 insertions(+), 500 deletions(-) create mode 100644 analyse.py delete mode 100644 images/vari_ng.png delete mode 100644 tests.py diff --git a/README.md b/README.md index bfe4a5a..8e6cd88 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ ### Linux - `git clone https://git.leizour.fr/lucien/ultra-mastermind-implementation` +- `cd ultra-mastermind-implementation` - `python -m venv .venv` - `source .venv/bin/activate` - `pip install -r requirements.txt` @@ -20,8 +21,9 @@ #### Second method - `git clone https://git.leizour.fr/lucien/ultra-mastermind-implementation` +- `cd ultra-mastermind-implementation` - `python -m venv .venv` -- `./.venv/bin/activate` +- `.venv/bin/activate` - `pip install -r requirements.txt` - `python main.py` diff --git a/analyse.py b/analyse.py new file mode 100644 index 0000000..667761e --- /dev/null +++ b/analyse.py @@ -0,0 +1,103 @@ +# fichier de tests du projet + +import matplotlib.pyplot as plt +import random + +# project libs importations +import lib.ultra_mastermind_obj as libobj +import lib.ultra_mastermind_imp as libimp +import lib.ultra_mastermind_pp_imp as libppimp + +PM = "Hello, world!" +NG = 4000 +N = 400 +TS = 0.7 +TM = 0.25 +ALPHA = 0.5 +FITNESS_METHOD = 3 + +# Variation de la taille de la phrase +length_ng = [] +length = [] + +for i in range(5, 26, 3): + print(f"Step {i}:") + length.append(i) + vals = [] + for j in range(5): + print(f" Part {j}") + PM = "".join([chr(random.randint(0, 255)) for _ in range(i)]) + pop = libppimp.new_population(PM, NG, N, TS, TM, ALPHA, FITNESS_METHOD) + ng = libppimp.run(pop) + vals.append(ng) + length_ng.append(sum(vals) / len(vals)) + +plt.plot(length, length_ng) +plt.title("Nombre de générations nécéssaires en fonction de la taille de la phrase.") +plt.xlabel("Taille de la phrase") +plt.ylabel("Nombre de générations") +plt.show() + +# Variation de la taille de la population +n_ng = [] +n = [] + +for i in range(50, 1000, 100): + print(f"Step {i}:") + n.append(i) + vals = [] + for j in range(5): + print(f" Part {j}") + pop = libppimp.new_population(PM, NG, i, TS, TM, ALPHA, FITNESS_METHOD) + ng = libppimp.run(pop) + vals.append(ng) + n_ng.append(sum(vals) / len(vals)) + +plt.plot(n, n_ng) +plt.title("Nombre de générations nécéssaires en fonction de la taille de la population.") +plt.xlabel("Taille de la population") +plt.ylabel("Nombre de générations") +plt.show() + +# Variation du taut de sélection +ts_ng = [] +ts = [] + +for i in range(1, 9, 1): + print(f"Step {i / 10}:") + ts.append(i / 10) + vals = [] + for j in range(5): + print(f" Part {j}") + pop = libppimp.new_population(PM, NG, N, i / 10, TM, ALPHA, FITNESS_METHOD) + ng = libppimp.run(pop) + vals.append(ng) + ts_ng.append(sum(vals) / len(vals)) + +plt.plot(ts, ts_ng) +plt.title("Nombre de générations nécéssaires en fonction du taut de sélection.") +plt.xlabel("Taut de sélection") +plt.ylabel("Nombre de générations") +plt.show() + +# Variation du taut de mutation +tm_ng = [] +tm = [] + +for i in range(10, 40, 5): + print(f"Step {i / 100}:") + tm.append(i / 100) + vals = [] + for j in range(5): + print(f" Part {j}") + pop = libppimp.new_population(PM, NG, N, TS, i / 100, ALPHA, FITNESS_METHOD) + ng = libppimp.run(pop) + vals.append(ng) + tm_ng.append(sum(vals) / len(vals)) + +plt.plot(tm, tm_ng) +plt.title("Nombre de générations nécéssaires en fonction du taut de mutation.") +plt.xlabel("Taut de mutation") +plt.ylabel("Nombre de générations") +plt.show() + diff --git a/images/vari_ng.png b/images/vari_ng.png deleted file mode 100644 index 1611f4cafb82c23e2efadb665a0d01548e3cb007..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 44831 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 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 + 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 + 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 - } + """ + 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)) + for individual in population["individuals"]: + randomize(individual, len(pm)) - return population + return population def new_individual(): # -> set(str) - """ - fonction qui renvoie un nouvel individu - """ - return { - "chromozome": "" - } + """ + 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 + """ + 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 + """ + 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 + """ + 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) + """ + 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"]) + 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)] + """ + 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"]) + """ + 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) + """ + 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)) + """ + 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) + 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 + """ + 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) + """ + 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) + """ + Boucle principale + """ + for i in range(population["ng"]): + select(population) + reproduct(population) + mutate_pop(population) + print_best(population) diff --git a/lib/ultra_mastermind_obj.py b/lib/ultra_mastermind_obj.py index 6979883..499c4a9 100644 --- a/lib/ultra_mastermind_obj.py +++ b/lib/ultra_mastermind_obj.py @@ -4,170 +4,170 @@ 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 + 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 + 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 class Population: - """ - Classe qui représente notre population d'individuts - """ - def __init__(self, pm, ng, n, ts, tm, alpha, fm): - self.individuals = [Individual() for _ in range(n)] - for individual in self.individuals: - individual.randomize(len(pm)) - self.pm = pm - self.ng = ng - self.l = len(pm) - self.n = n - self.ts = ts - self.tm = tm - self.alpha = alpha - self.fitness_method = fm + """ + Classe qui représente notre population d'individuts + """ + def __init__(self, pm, ng, n, ts, tm, alpha, fm): + self.individuals = [Individual() for _ in range(n)] + for individual in self.individuals: + individual.randomize(len(pm)) + self.pm = pm + self.ng = ng + self.l = len(pm) + self.n = n + self.ts = ts + self.tm = tm + self.alpha = alpha + self.fitness_method = fm - def select(self) -> None: - """ - Methode qui sélectionne les meilleurs individus - """ - fitness_list = [] - for individual in self.individuals: - match self.fitness_method: - case 1: - fitness_list.append(individual.fitness1(self.pm)) - case 2: - fitness_list.append(individual.fitness2(self.pm, self.alpha)) - case 3: - fitness_list.append(individual.fitness3(self.pm)) - case _: - fitness_list.append(individual.fitness1(self.pm)) - for i in range(int((1 - self.ts) * self.n)): - least = min_i(fitness_list) - fitness_list.pop(least) - self.individuals.pop(least) + def select(self) -> None: + """ + Methode qui sélectionne les meilleurs individus + """ + fitness_list = [] + for individual in self.individuals: + match self.fitness_method: + case 1: + fitness_list.append(individual.fitness1(self.pm)) + case 2: + fitness_list.append(individual.fitness2(self.pm, self.alpha)) + case 3: + fitness_list.append(individual.fitness3(self.pm)) + case _: + fitness_list.append(individual.fitness1(self.pm)) + for i in range(int((1 - self.ts) * self.n)): + least = min_i(fitness_list) + fitness_list.pop(least) + self.individuals.pop(least) - def reproduct(self) -> None: - """ - Methode qui reproduit les individus entre eux jusqu'à obtenir une population de taille N - """ - new = [] - while len(self.individuals) + len(new) != self.n: - cut = random.randint(int(self.l / 3), int(2 * self.l / 3)) - indivi_1 = self.individuals[random.randint(0, len(self.individuals) - 1)] - indivi_2 = self.individuals[random.randint(0, len(self.individuals) - 1)] - while indivi_1 == indivi_2: - indivi_2 = self.individuals[random.randint(0, len(self.individuals) - 1)] - new_chromozome = indivi_1.getChromozome()[:cut] + indivi_2.getChromozome()[cut:] - child = Individual() - child.setChromozome(new_chromozome) - new.append(child) - self.individuals += new + def reproduct(self) -> None: + """ + Methode qui reproduit les individus entre eux jusqu'à obtenir une population de taille N + """ + new = [] + while len(self.individuals) + len(new) != self.n: + cut = random.randint(int(self.l / 3), int(2 * self.l / 3)) + indivi_1 = self.individuals[random.randint(0, len(self.individuals) - 1)] + indivi_2 = self.individuals[random.randint(0, len(self.individuals) - 1)] + while indivi_1 == indivi_2: + indivi_2 = self.individuals[random.randint(0, len(self.individuals) - 1)] + new_chromozome = indivi_1.getChromozome()[:cut] + indivi_2.getChromozome()[cut:] + child = Individual() + child.setChromozome(new_chromozome) + new.append(child) + self.individuals += new - def mutate(self) -> None: - """ - Methode qui mute une partie de la population selon le taut de mutation - """ - mutated = [] - for i in range(int(self.tm * self.n)): - to_mutate = random.randint(0, self.n - 1) - while to_mutate in mutated: - to_mutate = random.randint(0, self.n - 1) - self.individuals[to_mutate].mutate() - mutated.append(to_mutate) + def mutate(self) -> None: + """ + Methode qui mute une partie de la population selon le taut de mutation + """ + mutated = [] + for i in range(int(self.tm * self.n)): + to_mutate = random.randint(0, self.n - 1) + while to_mutate in mutated: + to_mutate = random.randint(0, self.n - 1) + self.individuals[to_mutate].mutate() + mutated.append(to_mutate) - def print_best(self) -> None: - """ - Methode qui affiche le meilleur individu de la population - """ - fitness_list = [] - for individual in self.individuals: - match self.fitness_method: - case 1: - fitness_list.append(individual.fitness1(self.pm)) - case 2: - fitness_list.append(individual.fitness2(self.pm, self.alpha)) - case 3: - fitness_list.append(individual.fitness3(self.pm)) - case _: - fitness_list.append(individual.fitness1(self.pm)) - print(self.individuals[max_i(fitness_list)].getChromozome()) + def print_best(self) -> None: + """ + Methode qui affiche le meilleur individu de la population + """ + fitness_list = [] + for individual in self.individuals: + match self.fitness_method: + case 1: + fitness_list.append(individual.fitness1(self.pm)) + case 2: + fitness_list.append(individual.fitness2(self.pm, self.alpha)) + case 3: + fitness_list.append(individual.fitness3(self.pm)) + case _: + fitness_list.append(individual.fitness1(self.pm)) + print(self.individuals[max_i(fitness_list)].getChromozome()) - def run(self) -> None: - """ - Boucle principale - """ - for i in range(self.ng): - self.select() - self.reproduct() - self.mutate() - self.print_best() + def run(self) -> None: + """ + Boucle principale + """ + for i in range(self.ng): + self.select() + self.reproduct() + self.mutate() + self.print_best() class Individual: - """ - Classe qui représente les individuts de la population (les solutions potentielles) - """ - def __init__(self): - self.chromozome = "" + """ + Classe qui représente les individuts de la population (les solutions potentielles) + """ + def __init__(self): + self.chromozome = "" - def setChromozome(self, c: str) -> None: - self.chromozome = c - - def getChromozome(self) -> str: - return self.chromozome + def setChromozome(self, c: str) -> None: + self.chromozome = c + + def getChromozome(self) -> str: + return self.chromozome - def randomize(self, l) -> None: - """ - 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)) - self.chromozome = new + def randomize(self, l) -> None: + """ + 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)) + self.chromozome = new - def fitness1(self, 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(self.chromozome)): - sum += abs(ord(self.chromozome[i]) - ord(pm[i])) - return -sum + def fitness1(self, 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(self.chromozome)): + sum += abs(ord(self.chromozome[i]) - ord(pm[i])) + return -sum - def fitness2(self, 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(self.chromozome)): - if self.chromozome[i] == pm[i]: - match += 1 - else: - missed_placed += 1 - return match + alpha * missed_placed + def fitness2(self, 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(self.chromozome)): + if self.chromozome[i] == pm[i]: + match += 1 + else: + missed_placed += 1 + return match + alpha * missed_placed - def fitness3(self, pm) -> int: - """ - Troisième methode de fitness qui utilise la distance de Levenshtein - """ - return -Levenshtein.distance(self.chromozome, pm) + def fitness3(self, pm) -> int: + """ + Troisième methode de fitness qui utilise la distance de Levenshtein + """ + return -Levenshtein.distance(self.chromozome, pm) - def mutate(self) -> None: - """ - Methode qui change un des caractères du chromozome - """ - new = list(self.chromozome) - new[random.randint(0, len(new) - 1)] = chr(random.randint(0, 255)) - self.chromozome = "".join(new) + def mutate(self) -> None: + """ + Methode qui change un des caractères du chromozome + """ + new = list(self.chromozome) + new[random.randint(0, len(new) - 1)] = chr(random.randint(0, 255)) + self.chromozome = "".join(new) diff --git a/lib/ultra_mastermind_pp_imp.py b/lib/ultra_mastermind_pp_imp.py index 96c25e0..8e007b9 100644 --- a/lib/ultra_mastermind_pp_imp.py +++ b/lib/ultra_mastermind_pp_imp.py @@ -4,194 +4,196 @@ 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 + 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 + 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): - """ - 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 - } + """ + 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, 4, 30) + for individual in population["individuals"]: + randomize(individual, 4, 30) - return population + return population def new_individual(): - """ - fonction qui renvoie un nouvel individu - """ - return { - "chromozome": "" - } + """ + fonction qui renvoie un nouvel individu + """ + return { + "chromozome": "" + } def randomize(individual, min_l, max_l) -> str: - """ - Methode qui change la valeur d'un chromozome pour une valeur aléatoire - """ - new = "" - for i in range(random.randint(min_l, max_l)): - new += chr(random.randint(0, 255)) - individual["chromozome"] = new + """ + Methode qui change la valeur d'un chromozome pour une valeur aléatoire + """ + new = "" + for i in range(random.randint(min_l, max_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"])): - if i < len(pm) and i < len(individual["chromozome"]): - sum += abs(ord(individual["chromozome"][i]) - ord(pm[i])) - return -sum + """ + 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"])): + if i < len(pm) and i < 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 i >= len(pm): - missed_placed += len(individual["chromozome"]) - len(pm) - break - elif individual["chromozome"][i] == pm[i]: - match += 1 - else: - missed_placed += 1 - if len(pm) > len(individual["chromozome"]): - missed_placed += len(pm) - len(individual["chromozome"]) - return match + alpha * missed_placed + """ + 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 i >= len(pm): + missed_placed += len(individual["chromozome"]) - len(pm) + break + elif individual["chromozome"][i] == pm[i]: + match += 1 + else: + missed_placed += 1 + if len(pm) > len(individual["chromozome"]): + missed_placed += len(pm) - len(individual["chromozome"]) + 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) + """ + 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"]) + 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_fitness_list(population): - fitness_list = [] - for individual in population["individuals"]: - fitness_list.append(get_fitness(population, individual)) - return fitness_list + fitness_list = [] + for individual in population["individuals"]: + fitness_list.append(get_fitness(population, individual)) + return fitness_list def get_best(population): - """ - Methode qui renvoie le meilleur individu de la population - """ - fitness_list = get_fitness_list(population) - return population["individuals"][max_i(fitness_list)] + """ + Methode qui renvoie le meilleur individu de la population + """ + fitness_list = get_fitness_list(population) + 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"]) + """ + Methode qui affiche le meilleur individu de la population + """ + print(get_best(population)["chromozome"]) def select(population) -> None: - """ - Methode qui sélectionne les meilleurs individus - """ - fitness_list = get_fitness_list(population) - for i in range(int((1 - population["ts"]) * population["n"])): - least = min_i(fitness_list) - fitness_list.pop(least) - population["individuals"].pop(least) + """ + Methode qui sélectionne les meilleurs individus + """ + fitness_list = get_fitness_list(population) + for i in range(int((1 - population["ts"]) * population["n"])): + least = min_i(fitness_list) + fitness_list.pop(least) + population["individuals"].pop(least) def get_two_random_individuals(population): - 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) - return (population["individuals"][i], population['individuals'][j]) + 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) + return (population["individuals"][i], population['individuals'][j]) 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"]: - indivi_1, indivi_2 = get_two_random_individuals(population) + """ + Methode qui reproduit les individus entre eux jusqu'à obtenir une population de taille N + """ + new = [] + while len(population["individuals"]) + len(new) != population["n"]: + indivi_1, indivi_2 = get_two_random_individuals(population) - avg = (len(indivi_1) + len(indivi_2)) // 2 - cut = random.randint(avg // 3, 2 * avg // 3) - while cut > len(indivi_1) or cut > len(indivi_2): - cut = random.randint(avg // 3, 2 * avg // 3) + avg = (len(indivi_1) + len(indivi_2)) // 2 + cut = random.randint(avg // 3, 2 * avg // 3) + while cut > len(indivi_1) or cut > len(indivi_2): + cut = random.randint(avg // 3, 2 * avg // 3) - new_chromozome = indivi_1["chromozome"][:cut] + indivi_2["chromozome"][cut:] - child = new_individual() - child["chromozome"] = new_chromozome - new.append(child) + new_chromozome = indivi_1["chromozome"][:cut] + indivi_2["chromozome"][cut:] + child = new_individual() + child["chromozome"] = new_chromozome + new.append(child) - population["individuals"] += new + population["individuals"] += new def mutate(individual) -> None: - """ - Methode qui change un des caractères du chromozome - """ - new = list(individual["chromozome"]) - dice = random.randint(1,3) - if dice == 1 and len(new) < 30: - new.insert(random.randint(0, len(new) - 1), chr(random.randint(0, 255))) - elif dice == 2 and len(new) > 4: - new.pop(random.randint(0, len(new) - 1)) - else : - new[random.randint(0, len(new) - 1)] = chr(random.randint(0, 255)) - individual["chromozome"] = "".join(new) + """ + Methode qui change un des caractères du chromozome + """ + new = list(individual["chromozome"]) + dice = random.randint(1, 6) + if dice == 1 and len(new) < 30: + new.insert(random.randint(0, len(new) - 1), chr(random.randint(0, 255))) + elif dice == 2 and len(new) > 4: + new.pop(random.randint(0, len(new) - 1)) + else : + new[random.randint(0, len(new) - 1)] = chr(random.randint(0, 255)) + individual["chromozome"] = "".join(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) + """ + 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) +def run(population) -> int: + """ + Boucle principale + """ + for i in range(population["ng"]): + if get_best(population)["chromozome"] == population["pm"]: + return i + select(population) + reproduct(population) + mutate_pop(population) + return population["ng"] diff --git a/main.py b/main.py index 4d6d75c..b57170f 100644 --- a/main.py +++ b/main.py @@ -31,6 +31,7 @@ def main() -> None: # imperative version ++ pop = libppimp.new_population(PM, NG, N, TS, TM, ALPHA, FITNESS_METHOD) libppimp.run(pop) + print(libppimp.get_best(pop)["chromozome"]) if __name__ == "__main__": main() diff --git a/tests.py b/tests.py deleted file mode 100644 index 5d3d0a7..0000000 --- a/tests.py +++ /dev/null @@ -1,59 +0,0 @@ -# fichier de tests du projet - -import matplotlib.pyplot as plt - -# project libs importations -import lib.ultra_mastermind_obj as libobj -import lib.ultra_mastermind_imp as libimp -import lib.ultra_mastermind_pp_imp as libppimp - -# Variation du nombre de générations -PM = "Hello, world!" -# NG = 2000 -N = 400 -TS = 0.5 -TM = 0.25 -ALPHA = 0.5 -FITNESS_METHOD = 3 - -fitness_ng = [] -all_ng = [] - -for i in range(1, 11): - NG = i * 200 - all_ng.append(NG) - pop = libppimp.new_population(PM, NG, N, TS, TM, ALPHA, FITNESS_METHOD) - libppimp.run(pop) - fitness_ng.append(libppimp.get_fitness(pop, libppimp.get_best(pop))) - -plt.plot(all_ng, fitness_ng) -plt.title("Fitness du meilleur individu en fonction du nombre de générations") -plt.xlabel("Nombre de générations") -plt.ylabel("Fitness du meilleur individu") -plt.show() - -# Variation du nombre de générations -PM = "Hello, world!" -NG = 500 -# N = 400 -TS = 0.5 -TM = 0.25 -ALPHA = 0.5 -FITNESS_METHOD = 3 - -fitness_n = [] -all_n = [] - -for i in range(1, 11): - N = i * 100 - all_n.append(N) - pop = libppimp.new_population(PM, NG, N, TS, TM, ALPHA, FITNESS_METHOD) - libppimp.run(pop) - fitness_n.append(libppimp.get_fitness(pop, libppimp.get_best(pop))) - -plt.plot(all_n, fitness_n) -plt.title("Fitness du meilleur individu en fonction de la taille de population") -plt.xlabel("Taille de population") -plt.ylabel("Fitness du meilleur individu") -plt.show() -