Saataa andagii !

This commit is contained in:
Lukian 2025-01-07 23:05:40 +01:00
parent d99a556d3d
commit 757ea77cc5
8 changed files with 549 additions and 500 deletions

View file

@ -5,6 +5,7 @@
### Linux ### Linux
- `git clone https://git.leizour.fr/lucien/ultra-mastermind-implementation` - `git clone https://git.leizour.fr/lucien/ultra-mastermind-implementation`
- `cd ultra-mastermind-implementation`
- `python -m venv .venv` - `python -m venv .venv`
- `source .venv/bin/activate` - `source .venv/bin/activate`
- `pip install -r requirements.txt` - `pip install -r requirements.txt`
@ -20,8 +21,9 @@
#### Second method #### Second method
- `git clone https://git.leizour.fr/lucien/ultra-mastermind-implementation` - `git clone https://git.leizour.fr/lucien/ultra-mastermind-implementation`
- `cd ultra-mastermind-implementation`
- `python -m venv .venv` - `python -m venv .venv`
- `./.venv/bin/activate` - `.venv/bin/activate`
- `pip install -r requirements.txt` - `pip install -r requirements.txt`
- `python main.py` - `python main.py`

103
analyse.py Normal file
View file

@ -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()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

View file

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

View file

@ -4,170 +4,170 @@ import random
import Levenshtein import Levenshtein
def min_i(array: list[int]) -> int: def min_i(array: list[int]) -> int:
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)):
if array[i] < min_val: if array[i] < min_val:
min_val = array[i] min_val = array[i]
min_i = i min_i = i
return min_i return min_i
def max_i(array: list[int]) -> int: def max_i(array: list[int]) -> int:
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)):
if array[i] > max_val: if array[i] > max_val:
max_val = array[i] max_val = array[i]
max_i = i max_i = i
return max_i return max_i
class Population: class Population:
""" """
Classe qui représente notre population d'individuts Classe qui représente notre population d'individuts
""" """
def __init__(self, pm, ng, n, ts, tm, alpha, fm): def __init__(self, pm, ng, n, ts, tm, alpha, fm):
self.individuals = [Individual() for _ in range(n)] self.individuals = [Individual() for _ in range(n)]
for individual in self.individuals: for individual in self.individuals:
individual.randomize(len(pm)) individual.randomize(len(pm))
self.pm = pm self.pm = pm
self.ng = ng self.ng = ng
self.l = len(pm) self.l = len(pm)
self.n = n self.n = n
self.ts = ts self.ts = ts
self.tm = tm self.tm = tm
self.alpha = alpha self.alpha = alpha
self.fitness_method = fm self.fitness_method = fm
def select(self) -> None: def select(self) -> None:
""" """
Methode qui sélectionne les meilleurs individus Methode qui sélectionne les meilleurs individus
""" """
fitness_list = [] fitness_list = []
for individual in self.individuals: for individual in self.individuals:
match self.fitness_method: match self.fitness_method:
case 1: case 1:
fitness_list.append(individual.fitness1(self.pm)) fitness_list.append(individual.fitness1(self.pm))
case 2: case 2:
fitness_list.append(individual.fitness2(self.pm, self.alpha)) fitness_list.append(individual.fitness2(self.pm, self.alpha))
case 3: case 3:
fitness_list.append(individual.fitness3(self.pm)) fitness_list.append(individual.fitness3(self.pm))
case _: case _:
fitness_list.append(individual.fitness1(self.pm)) fitness_list.append(individual.fitness1(self.pm))
for i in range(int((1 - self.ts) * self.n)): for i in range(int((1 - self.ts) * self.n)):
least = min_i(fitness_list) least = min_i(fitness_list)
fitness_list.pop(least) fitness_list.pop(least)
self.individuals.pop(least) self.individuals.pop(least)
def reproduct(self) -> None: def reproduct(self) -> 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 = []
while len(self.individuals) + len(new) != self.n: while len(self.individuals) + len(new) != self.n:
cut = random.randint(int(self.l / 3), int(2 * self.l / 3)) cut = random.randint(int(self.l / 3), int(2 * self.l / 3))
indivi_1 = self.individuals[random.randint(0, len(self.individuals) - 1)] indivi_1 = self.individuals[random.randint(0, len(self.individuals) - 1)]
indivi_2 = 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: while indivi_1 == indivi_2:
indivi_2 = self.individuals[random.randint(0, len(self.individuals) - 1)] indivi_2 = self.individuals[random.randint(0, len(self.individuals) - 1)]
new_chromozome = indivi_1.getChromozome()[:cut] + indivi_2.getChromozome()[cut:] new_chromozome = indivi_1.getChromozome()[:cut] + indivi_2.getChromozome()[cut:]
child = Individual() child = Individual()
child.setChromozome(new_chromozome) child.setChromozome(new_chromozome)
new.append(child) new.append(child)
self.individuals += new self.individuals += new
def mutate(self) -> None: def mutate(self) -> None:
""" """
Methode qui mute une partie de la population selon le taut de mutation Methode qui mute une partie de la population selon le taut de mutation
""" """
mutated = [] mutated = []
for i in range(int(self.tm * self.n)): for i in range(int(self.tm * self.n)):
to_mutate = random.randint(0, self.n - 1) to_mutate = random.randint(0, self.n - 1)
while to_mutate in mutated: while to_mutate in mutated:
to_mutate = random.randint(0, self.n - 1) to_mutate = random.randint(0, self.n - 1)
self.individuals[to_mutate].mutate() self.individuals[to_mutate].mutate()
mutated.append(to_mutate) mutated.append(to_mutate)
def print_best(self) -> None: def print_best(self) -> None:
""" """
Methode qui affiche le meilleur individu de la population Methode qui affiche le meilleur individu de la population
""" """
fitness_list = [] fitness_list = []
for individual in self.individuals: for individual in self.individuals:
match self.fitness_method: match self.fitness_method:
case 1: case 1:
fitness_list.append(individual.fitness1(self.pm)) fitness_list.append(individual.fitness1(self.pm))
case 2: case 2:
fitness_list.append(individual.fitness2(self.pm, self.alpha)) fitness_list.append(individual.fitness2(self.pm, self.alpha))
case 3: case 3:
fitness_list.append(individual.fitness3(self.pm)) fitness_list.append(individual.fitness3(self.pm))
case _: case _:
fitness_list.append(individual.fitness1(self.pm)) fitness_list.append(individual.fitness1(self.pm))
print(self.individuals[max_i(fitness_list)].getChromozome()) print(self.individuals[max_i(fitness_list)].getChromozome())
def run(self) -> None: def run(self) -> None:
""" """
Boucle principale Boucle principale
""" """
for i in range(self.ng): for i in range(self.ng):
self.select() self.select()
self.reproduct() self.reproduct()
self.mutate() self.mutate()
self.print_best() self.print_best()
class Individual: class Individual:
""" """
Classe qui représente les individuts de la population (les solutions potentielles) Classe qui représente les individuts de la population (les solutions potentielles)
""" """
def __init__(self): def __init__(self):
self.chromozome = "" self.chromozome = ""
def setChromozome(self, c: str) -> None: def setChromozome(self, c: str) -> None:
self.chromozome = c self.chromozome = c
def getChromozome(self) -> str: def getChromozome(self) -> str:
return self.chromozome return self.chromozome
def randomize(self, l) -> None: def randomize(self, l) -> None:
""" """
Methode qui change la valeur d'un chromozome pour une valeur aléatoire Methode qui change la valeur d'un chromozome pour une valeur aléatoire
""" """
new = "" new = ""
for i in range(l): for i in range(l):
new += chr(random.randint(0, 255)) new += chr(random.randint(0, 255))
self.chromozome = new self.chromozome = new
def fitness1(self, pm) -> int: 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. Première methode de fitness, fait la somme des différences entre les codages des caractères des deux chaînes.
""" """
sum = 0 sum = 0
for i in range(len(self.chromozome)): for i in range(len(self.chromozome)):
sum += abs(ord(self.chromozome[i]) - ord(pm[i])) sum += abs(ord(self.chromozome[i]) - ord(pm[i]))
return -sum return -sum
def fitness2(self, pm, alpha) -> int: 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 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 match = 0
missed_placed = 0 missed_placed = 0
for i in range(len(self.chromozome)): for i in range(len(self.chromozome)):
if self.chromozome[i] == pm[i]: if self.chromozome[i] == pm[i]:
match += 1 match += 1
else: else:
missed_placed += 1 missed_placed += 1
return match + alpha * missed_placed return match + alpha * missed_placed
def fitness3(self, pm) -> int: def fitness3(self, pm) -> int:
""" """
Troisième methode de fitness qui utilise la distance de Levenshtein Troisième methode de fitness qui utilise la distance de Levenshtein
""" """
return -Levenshtein.distance(self.chromozome, pm) return -Levenshtein.distance(self.chromozome, pm)
def mutate(self) -> None: def mutate(self) -> None:
""" """
Methode qui change un des caractères du chromozome Methode qui change un des caractères du chromozome
""" """
new = list(self.chromozome) new = list(self.chromozome)
new[random.randint(0, len(new) - 1)] = chr(random.randint(0, 255)) new[random.randint(0, len(new) - 1)] = chr(random.randint(0, 255))
self.chromozome = "".join(new) self.chromozome = "".join(new)

View file

@ -4,194 +4,196 @@ import random
import Levenshtein import Levenshtein
def min_i(array: list[int]) -> int: def min_i(array: list[int]) -> int:
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)):
if array[i] < min_val: if array[i] < min_val:
min_val = array[i] min_val = array[i]
min_i = i min_i = i
return min_i return min_i
def max_i(array: list[int]) -> int: def max_i(array: list[int]) -> int:
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)):
if array[i] > max_val: if array[i] > max_val:
max_val = array[i] max_val = array[i]
max_i = i max_i = i
return max_i return max_i
def new_population(pm, ng, n, ts, tm, alpha, fm): def new_population(pm, ng, n, ts, tm, alpha, fm):
""" """
fonction qui renvoie une nouvelle population fonction qui renvoie une nouvelle population
""" """
population = { population = {
"individuals": [new_individual() for i in range(n)], "individuals": [new_individual() for i in range(n)],
"pm": pm, "pm": pm,
"ng": ng, "ng": ng,
"l": len(pm), "l": len(pm),
"n": n, "n": n,
"ts": ts, "ts": ts,
"tm": tm, "tm": tm,
"alpha": alpha, "alpha": alpha,
"fm": fm "fm": fm
} }
for individual in population["individuals"]: for individual in population["individuals"]:
randomize(individual, 4, 30) randomize(individual, 4, 30)
return population return population
def new_individual(): def new_individual():
""" """
fonction qui renvoie un nouvel individu fonction qui renvoie un nouvel individu
""" """
return { return {
"chromozome": "" "chromozome": ""
} }
def randomize(individual, min_l, max_l) -> str: def randomize(individual, min_l, max_l) -> str:
""" """
Methode qui change la valeur d'un chromozome pour une valeur aléatoire Methode qui change la valeur d'un chromozome pour une valeur aléatoire
""" """
new = "" new = ""
for i in range(random.randint(min_l, max_l)): for i in range(random.randint(min_l, max_l)):
new += chr(random.randint(0, 255)) new += chr(random.randint(0, 255))
individual["chromozome"] = new individual["chromozome"] = new
def fitness1(individual, pm) -> int: 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. Première methode de fitness, fait la somme des différences entre les codages des caractères des deux chaînes.
""" """
sum = 0 sum = 0
for i in range(len(individual["chromozome"])): for i in range(len(individual["chromozome"])):
if i < len(pm) and i < len(individual["chromozome"]): if i < len(pm) and i < len(individual["chromozome"]):
sum += abs(ord(individual["chromozome"][i]) - ord(pm[i])) sum += abs(ord(individual["chromozome"][i]) - ord(pm[i]))
return -sum return -sum
def fitness2(individual, pm, alpha) -> int: 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 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 match = 0
missed_placed = 0 missed_placed = 0
for i in range(len(individual["chromozome"])): for i in range(len(individual["chromozome"])):
if i >= len(pm): if i >= len(pm):
missed_placed += len(individual["chromozome"]) - len(pm) missed_placed += len(individual["chromozome"]) - len(pm)
break break
elif individual["chromozome"][i] == pm[i]: elif individual["chromozome"][i] == pm[i]:
match += 1 match += 1
else: else:
missed_placed += 1 missed_placed += 1
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
def fitness3(individual, pm) -> int: def fitness3(individual, pm) -> int:
""" """
Troisième methode de fitness qui utilise la distance de Levenshtein Troisième methode de fitness qui utilise la distance de Levenshtein
""" """
return -Levenshtein.distance(individual["chromozome"], pm) return -Levenshtein.distance(individual["chromozome"], pm)
def get_fitness(population, individual) -> int: def get_fitness(population, individual) -> int:
match population["fm"]: match population["fm"]:
case 1: case 1:
return fitness1(individual, population["pm"]) return fitness1(individual, population["pm"])
case 2: case 2:
return fitness2(individual, population["pm"], population["alpha"]) return fitness2(individual, population["pm"], population["alpha"])
case 3: case 3:
return fitness3(individual, population["pm"]) return fitness3(individual, population["pm"])
case _: case _:
return fitness1(individual, population["pm"]) return fitness1(individual, population["pm"])
def get_fitness_list(population): def get_fitness_list(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))
return fitness_list return fitness_list
def get_best(population): def get_best(population):
""" """
Methode qui renvoie le meilleur individu de la population Methode qui renvoie le meilleur individu de la population
""" """
fitness_list = get_fitness_list(population) fitness_list = get_fitness_list(population)
return population["individuals"][max_i(fitness_list)] return population["individuals"][max_i(fitness_list)]
def print_best(population) -> None: def print_best(population) -> None:
""" """
Methode qui affiche le meilleur individu de la population Methode qui affiche le meilleur individu de la population
""" """
print(get_best(population)["chromozome"]) print(get_best(population)["chromozome"])
def select(population) -> None: def select(population) -> None:
""" """
Methode qui sélectionne les meilleurs individus Methode qui sélectionne les meilleurs individus
""" """
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"])):
least = min_i(fitness_list) least = min_i(fitness_list)
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):
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:
j = random.randint(0, len(population["individuals"]) - 1) j = random.randint(0, len(population["individuals"]) - 1)
return (population["individuals"][i], population['individuals'][j]) return (population["individuals"][i], population['individuals'][j])
def reproduct(population) -> None: 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 = []
while len(population["individuals"]) + len(new) != population["n"]: while len(population["individuals"]) + len(new) != population["n"]:
indivi_1, indivi_2 = get_two_random_individuals(population) indivi_1, indivi_2 = get_two_random_individuals(population)
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)
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)
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
new.append(child) new.append(child)
population["individuals"] += new population["individuals"] += new
def mutate(individual) -> None: 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"])
dice = random.randint(1,3) dice = random.randint(1, 6)
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)))
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))
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)
def mutate_pop(population) -> None: def mutate_pop(population) -> None:
""" """
Methode qui mute une partie de la population selon le taut de mutation Methode qui mute une partie de la population selon le taut de mutation
""" """
mutated = [] mutated = []
for i in range(int(population["tm"] * population["n"])): for i in range(int(population["tm"] * population["n"])):
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)
mutate(population["individuals"][to_mutate]) mutate(population["individuals"][to_mutate])
mutated.append(to_mutate) mutated.append(to_mutate)
def run(population) -> None: def run(population) -> int:
""" """
Boucle principale Boucle principale
""" """
for i in range(population["ng"]): for i in range(population["ng"]):
select(population) if get_best(population)["chromozome"] == population["pm"]:
reproduct(population) return i
mutate_pop(population) select(population)
print_best(population) reproduct(population)
mutate_pop(population)
return population["ng"]

View file

@ -31,6 +31,7 @@ def main() -> None:
# imperative version ++ # imperative version ++
pop = libppimp.new_population(PM, NG, N, TS, TM, ALPHA, FITNESS_METHOD) pop = libppimp.new_population(PM, NG, N, TS, TM, ALPHA, FITNESS_METHOD)
libppimp.run(pop) libppimp.run(pop)
print(libppimp.get_best(pop)["chromozome"])
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View file

@ -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()