Saataa Andagii !
This commit is contained in:
parent
4f43c149ee
commit
d39467f070
3 changed files with 261 additions and 67 deletions
|
@ -51,6 +51,43 @@ def new_individual(): # -> set(str)
|
||||||
"chromozome": ""
|
"chromozome": ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def randomize(individual, l) -> str:
|
||||||
|
"""
|
||||||
|
Methode qui change la valeur d'un chromozome pour une valeur aléatoire
|
||||||
|
"""
|
||||||
|
new = ""
|
||||||
|
for i in range(l):
|
||||||
|
new += chr(random.randint(0, 255))
|
||||||
|
individual["chromozome"] = new
|
||||||
|
|
||||||
|
def fitness1(individual, pm) -> int:
|
||||||
|
"""
|
||||||
|
Première methode de fitness, fait la somme des différences entre les codages des caractères des deux chaînes.
|
||||||
|
"""
|
||||||
|
sum = 0
|
||||||
|
for i in range(len(individual["chromozome"])):
|
||||||
|
sum += abs(ord(individual["chromozome"][i]) - ord(pm[i]))
|
||||||
|
return -sum
|
||||||
|
|
||||||
|
def fitness2(individual, pm, alpha) -> int:
|
||||||
|
"""
|
||||||
|
Deuxième methode de fitness qui compte les caractères bien placés et mal placés et qui renvoie un int pondéré par alpha
|
||||||
|
"""
|
||||||
|
match = 0
|
||||||
|
missed_placed = 0
|
||||||
|
for i in range(len(individual["chromozome"])):
|
||||||
|
if individual["chromozome"][i] == pm[i]:
|
||||||
|
match += 1
|
||||||
|
else:
|
||||||
|
missed_placed += 1
|
||||||
|
return match + alpha * missed_placed
|
||||||
|
|
||||||
|
def fitness3(individual, pm) -> int:
|
||||||
|
"""
|
||||||
|
Troisième methode de fitness qui utilise la distance de Levenshtein
|
||||||
|
"""
|
||||||
|
return -Levenshtein.distance(individual["chromozome"], pm)
|
||||||
|
|
||||||
def get_fitness(population, individual) -> int:
|
def get_fitness(population, individual) -> int:
|
||||||
match population["fm"]:
|
match population["fm"]:
|
||||||
case 1:
|
case 1:
|
||||||
|
@ -62,6 +99,29 @@ def get_fitness(population, individual) -> int:
|
||||||
case _:
|
case _:
|
||||||
return fitness1(individual, population["pm"])
|
return fitness1(individual, population["pm"])
|
||||||
|
|
||||||
|
def get_best(population):
|
||||||
|
"""
|
||||||
|
Methode qui renvoie le meilleur individu de la population
|
||||||
|
"""
|
||||||
|
fitness_list = []
|
||||||
|
for individual in population["individuals"]:
|
||||||
|
fitness_list.append(get_fitness(population, individual))
|
||||||
|
return population["individuals"][max_i(fitness_list)]
|
||||||
|
|
||||||
|
def print_best(population) -> None:
|
||||||
|
"""
|
||||||
|
Methode qui affiche le meilleur individu de la population
|
||||||
|
"""
|
||||||
|
print(get_best(population)["chromozome"])
|
||||||
|
|
||||||
|
def mutate(individual) -> None:
|
||||||
|
"""
|
||||||
|
Methode qui change un des caractères du chromozome
|
||||||
|
"""
|
||||||
|
new = list(individual["chromozome"])
|
||||||
|
new[random.randint(0, len(new) - 1)] = chr(random.randint(0, 255))
|
||||||
|
individual["chromozome"] = "".join(new)
|
||||||
|
|
||||||
def select(population) -> None:
|
def select(population) -> None:
|
||||||
"""
|
"""
|
||||||
Methode qui sélectionne les meilleurs individus
|
Methode qui sélectionne les meilleurs individus
|
||||||
|
@ -106,21 +166,6 @@ def mutate_pop(population) -> None:
|
||||||
mutate(population["individuals"][to_mutate])
|
mutate(population["individuals"][to_mutate])
|
||||||
mutated.append(to_mutate)
|
mutated.append(to_mutate)
|
||||||
|
|
||||||
def get_best(population):
|
|
||||||
"""
|
|
||||||
Methode qui renvoie le meilleur individu de la population
|
|
||||||
"""
|
|
||||||
fitness_list = []
|
|
||||||
for individual in population["individuals"]:
|
|
||||||
fitness_list.append(get_fitness(population, individual))
|
|
||||||
return population["individuals"][max_i(fitness_list)]
|
|
||||||
|
|
||||||
def print_best(population) -> None:
|
|
||||||
"""
|
|
||||||
Methode qui affiche le meilleur individu de la population
|
|
||||||
"""
|
|
||||||
print(get_best(population)["chromozome"])
|
|
||||||
|
|
||||||
def run(population) -> None:
|
def run(population) -> None:
|
||||||
"""
|
"""
|
||||||
Boucle principale
|
Boucle principale
|
||||||
|
@ -130,48 +175,3 @@ def run(population) -> None:
|
||||||
reproduct(population)
|
reproduct(population)
|
||||||
mutate_pop(population)
|
mutate_pop(population)
|
||||||
print_best(population)
|
print_best(population)
|
||||||
|
|
||||||
def randomize(individual, l) -> str:
|
|
||||||
"""
|
|
||||||
Methode qui change la valeur d'un chromozome pour une valeur aléatoire
|
|
||||||
"""
|
|
||||||
new = ""
|
|
||||||
for i in range(l):
|
|
||||||
new += chr(random.randint(0, 255))
|
|
||||||
individual["chromozome"] = new
|
|
||||||
|
|
||||||
def fitness1(individual, pm) -> int:
|
|
||||||
"""
|
|
||||||
Première methode de fitness, fait la somme des différences entre les codages des caractères des deux chaînes.
|
|
||||||
"""
|
|
||||||
sum = 0
|
|
||||||
for i in range(len(individual["chromozome"])):
|
|
||||||
sum += abs(ord(individual["chromozome"][i]) - ord(pm[i]))
|
|
||||||
return -sum
|
|
||||||
|
|
||||||
def fitness2(individual, pm, alpha) -> int:
|
|
||||||
"""
|
|
||||||
Deuxième methode de fitness qui compte les caractères bien placés et mal placés et qui renvoie un int pondéré par alpha
|
|
||||||
"""
|
|
||||||
match = 0
|
|
||||||
missed_placed = 0
|
|
||||||
for i in range(len(individual["chromozome"])):
|
|
||||||
if individual["chromozome"][i] == pm[i]:
|
|
||||||
match += 1
|
|
||||||
else:
|
|
||||||
missed_placed += 1
|
|
||||||
return match + alpha * missed_placed
|
|
||||||
|
|
||||||
def fitness3(individual, pm) -> int:
|
|
||||||
"""
|
|
||||||
Troisième methode de fitness qui utilise la distance de Levenshtein
|
|
||||||
"""
|
|
||||||
return -Levenshtein.distance(individual["chromozome"], pm)
|
|
||||||
|
|
||||||
def 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)
|
|
||||||
|
|
185
lib/ultra_mastermind_pp_imp.py
Normal file
185
lib/ultra_mastermind_pp_imp.py
Normal file
|
@ -0,0 +1,185 @@
|
||||||
|
# Librairie du projet en version impératif
|
||||||
|
|
||||||
|
import random
|
||||||
|
import Levenshtein
|
||||||
|
|
||||||
|
def min_i(array: list[int]) -> int:
|
||||||
|
min_val = array[0]
|
||||||
|
min_i = 0
|
||||||
|
for i in range(len(array)):
|
||||||
|
if array[i] < min_val:
|
||||||
|
min_val = array[i]
|
||||||
|
min_i = i
|
||||||
|
return min_i
|
||||||
|
|
||||||
|
def max_i(array: list[int]) -> int:
|
||||||
|
max_val = array[0]
|
||||||
|
max_i = 0
|
||||||
|
for i in range(len(array)):
|
||||||
|
if array[i] > max_val:
|
||||||
|
max_val = array[i]
|
||||||
|
max_i = i
|
||||||
|
return max_i
|
||||||
|
|
||||||
|
|
||||||
|
def new_population(pm, ng, n, ts, tm, alpha, fm): # -> set(list(set(str)), str, int, int, int, float, float, float, int)
|
||||||
|
"""
|
||||||
|
fonction qui renvoie une nouvelle population
|
||||||
|
"""
|
||||||
|
population = {
|
||||||
|
"individuals": [new_individual() for i in range(n)],
|
||||||
|
"pm": pm,
|
||||||
|
"ng": ng,
|
||||||
|
"l": len(pm),
|
||||||
|
"n": n,
|
||||||
|
"ts": ts,
|
||||||
|
"tm": tm,
|
||||||
|
"alpha": alpha,
|
||||||
|
"fm": fm
|
||||||
|
}
|
||||||
|
|
||||||
|
for individual in population["individuals"]:
|
||||||
|
randomize(individual, 4, 30)
|
||||||
|
|
||||||
|
return population
|
||||||
|
|
||||||
|
def new_individual(): # -> set(str)
|
||||||
|
"""
|
||||||
|
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
|
||||||
|
|
||||||
|
def fitness1(individual, pm) -> int:
|
||||||
|
"""
|
||||||
|
Première methode de fitness, fait la somme des différences entre les codages des caractères des deux chaînes.
|
||||||
|
"""
|
||||||
|
sum = 0
|
||||||
|
for i in range(len(individual["chromozome"])):
|
||||||
|
sum += abs(ord(individual["chromozome"][i]) - ord(pm[i]))
|
||||||
|
return -sum
|
||||||
|
|
||||||
|
def fitness2(individual, pm, alpha) -> int:
|
||||||
|
"""
|
||||||
|
Deuxième methode de fitness qui compte les caractères bien placés et mal placés et qui renvoie un int pondéré par alpha
|
||||||
|
"""
|
||||||
|
match = 0
|
||||||
|
missed_placed = 0
|
||||||
|
for i in range(len(individual["chromozome"])):
|
||||||
|
if 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)
|
||||||
|
|
||||||
|
def get_fitness(population, individual) -> int:
|
||||||
|
match population["fm"]:
|
||||||
|
case 1:
|
||||||
|
return fitness1(individual, population["pm"])
|
||||||
|
case 2:
|
||||||
|
return fitness2(individual, population["pm"], population["alpha"])
|
||||||
|
case 3:
|
||||||
|
return fitness3(individual, population["pm"])
|
||||||
|
case _:
|
||||||
|
return fitness1(individual, population["pm"])
|
||||||
|
|
||||||
|
def get_best(population):
|
||||||
|
"""
|
||||||
|
Methode qui renvoie le meilleur individu de la population
|
||||||
|
"""
|
||||||
|
fitness_list = []
|
||||||
|
for individual in population["individuals"]:
|
||||||
|
fitness_list.append(get_fitness(population, individual))
|
||||||
|
return population["individuals"][max_i(fitness_list)]
|
||||||
|
|
||||||
|
def print_best(population) -> None:
|
||||||
|
"""
|
||||||
|
Methode qui affiche le meilleur individu de la population
|
||||||
|
"""
|
||||||
|
print(get_best(population)["chromozome"])
|
||||||
|
|
||||||
|
def mutate(individual) -> None:
|
||||||
|
"""
|
||||||
|
Methode qui change un des caractères du chromozome
|
||||||
|
"""
|
||||||
|
new = list(individual["chromozome"])
|
||||||
|
if random.randint(1, 2) == 1: new.insert(random.randint(0, len(new) - 1), chr(random.randint(0, 255)))
|
||||||
|
else : new[random.randint(0, len(new) - 1)] = chr(random.randint(0, 255))
|
||||||
|
individual["chromozome"] = "".join(new)
|
||||||
|
|
||||||
|
def select(population) -> None:
|
||||||
|
"""
|
||||||
|
Methode qui sélectionne les meilleurs individus
|
||||||
|
"""
|
||||||
|
fitness_list = []
|
||||||
|
for individual in population["individuals"]:
|
||||||
|
fitness_list.append(get_fitness(population, individual))
|
||||||
|
|
||||||
|
for i in range(int((1 - population["ts"]) * population["n"])):
|
||||||
|
least = min_i(fitness_list)
|
||||||
|
fitness_list.pop(least)
|
||||||
|
population["individuals"].pop(least)
|
||||||
|
|
||||||
|
def reproduct(population) -> None:
|
||||||
|
"""
|
||||||
|
Methode qui reproduit les individus entre eux jusqu'à obtenir une population de taille N
|
||||||
|
"""
|
||||||
|
new = []
|
||||||
|
while len(population["individuals"]) + len(new) != population["n"]:
|
||||||
|
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]
|
||||||
|
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)
|
||||||
|
population["individuals"] += new
|
||||||
|
|
||||||
|
def mutate_pop(population) -> None:
|
||||||
|
"""
|
||||||
|
Methode qui mute une partie de la population selon le taut de mutation
|
||||||
|
"""
|
||||||
|
mutated = []
|
||||||
|
for i in range(int(population["tm"] * population["n"])):
|
||||||
|
to_mutate = random.randint(0, population["n"] - 1)
|
||||||
|
while to_mutate in mutated:
|
||||||
|
to_mutate = random.randint(0, population["n"] - 1)
|
||||||
|
mutate(population["individuals"][to_mutate])
|
||||||
|
mutated.append(to_mutate)
|
||||||
|
|
||||||
|
def run(population) -> None:
|
||||||
|
"""
|
||||||
|
Boucle principale
|
||||||
|
"""
|
||||||
|
for i in range(population["ng"]):
|
||||||
|
select(population)
|
||||||
|
reproduct(population)
|
||||||
|
mutate_pop(population)
|
||||||
|
print_best(population)
|
23
main.py
23
main.py
|
@ -3,25 +3,34 @@
|
||||||
# project libs importations
|
# project libs importations
|
||||||
import lib.ultra_mastermind_obj as libobj
|
import lib.ultra_mastermind_obj as libobj
|
||||||
import lib.ultra_mastermind_imp as libimp
|
import lib.ultra_mastermind_imp as libimp
|
||||||
|
import lib.ultra_mastermind_pp_imp as libppimp
|
||||||
|
|
||||||
# constants
|
# constants
|
||||||
PM = "Hello, world!"
|
PM = ""
|
||||||
NG = 2000
|
NG = 500
|
||||||
N = 400
|
N = 200
|
||||||
TS = 0.5
|
TS = 0.5
|
||||||
TM = 0.01
|
TM = 0.25
|
||||||
ALPHA = 0.5
|
ALPHA = 0.5
|
||||||
FITNESS_METHOD = 1
|
FITNESS_METHOD = 3
|
||||||
|
|
||||||
# main function
|
# main function
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
|
# Get phrase from user
|
||||||
|
PM = input("Entrez une chaîne de caractères : ")
|
||||||
|
while len(PM) < 4 and len(PM) > 30: PM = input("Entrez une chaîne de caractères : ")
|
||||||
|
|
||||||
# object version
|
# object version
|
||||||
# pop = libobj.Population(pm = PM, ng = NG, n = N, ts = TS, tm = TM, alpha = ALPHA, fm = FITNESS_METHOD)
|
# pop = libobj.Population(pm = PM, ng = NG, n = N, ts = TS, tm = TM, alpha = ALPHA, fm = FITNESS_METHOD)
|
||||||
# pop.run()
|
# pop.run()
|
||||||
|
|
||||||
# imperative version
|
# imperative version
|
||||||
pop = libimp.new_population(PM, NG, N, TS, TM, ALPHA, FITNESS_METHOD)
|
# pop = libimp.new_population(PM, NG, N, TS, TM, ALPHA, FITNESS_METHOD)
|
||||||
libimp.run(pop)
|
# libimp.run(pop)
|
||||||
|
|
||||||
|
# imperative version ++
|
||||||
|
pop = libppimp.new_population(PM, NG, N, TS, TM, ALPHA, FITNESS_METHOD)
|
||||||
|
libppimp.run(pop)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue