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 1611f4c..0000000 Binary files a/images/vari_ng.png and /dev/null differ diff --git a/lib/ultra_mastermind_imp.py b/lib/ultra_mastermind_imp.py index b67082c..3faecf5 100644 --- a/lib/ultra_mastermind_imp.py +++ b/lib/ultra_mastermind_imp.py @@ -4,174 +4,174 @@ 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): # -> 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() -