diff --git a/genetics/simulation/discrete.py b/genetics/simulation/discrete.py index 555a5b9..1cc5a13 100644 --- a/genetics/simulation/discrete.py +++ b/genetics/simulation/discrete.py @@ -1,9 +1,10 @@ from collections.abc import Sequence + def pairwise(iterable): ''' Given an iterable, yield the items in it in pairs. For instance: - + list(pairwise([1,2,3,4])) == [(1,2), (3,4)] ''' x = iter(iterable) @@ -11,9 +12,10 @@ def pairwise(iterable): class DiscreteSimulation: + def __init__(self, population_size, mutation_mask, crossover_mask, - selection_function, elite_size, - initial_generator, fitness_function): + selection_function, elite_size, + initial_generator, fitness_function): self.population_size = population_size self.mutation_mask = mutation_mask self.crossover_mask = crossover_mask @@ -45,7 +47,7 @@ def initial_population(self): Create an initial populaton ''' return [self.initial_generator() for _ in - range(self.population_size)] + range(self.population_size)] def step_generator(self, population): ''' @@ -53,8 +55,8 @@ def step_generator(self, population): population members ''' # Score and sort population - scored_population = sorted(self.find_scores(population), reverse=True, - key=lambda member: member[0]) + scored_population = [m[1] for m in sorted(self.find_scores(population), reverse=True, + key=lambda member: member[0])] # Yield the elite elements yield from scored_population[:self.elite_size] @@ -72,4 +74,3 @@ def step(self, population): list. ''' return list(self.step_generator(population)) - diff --git a/main.py b/main.py new file mode 100644 index 0000000..44d15d3 --- /dev/null +++ b/main.py @@ -0,0 +1,58 @@ + +import string +import random + +import genetics + +letters = string.ascii_uppercase + string.ascii_lowercase + string.punctuation + ' ' +solution = 'Hello World!' + + +class LetterComponent(genetics.DNAComponent): + + def mutate_value(self): + return random.choice(letters) + + +class WordDNA(genetics.arrayed_segment(len(solution), LetterComponent)): + + def score(self): + score = sum(comp.value == letter for comp, letter in zip(self, solution)) + return score + + def __str__(self): + return ''.join(comp.value for comp in self) + + def __gt__(self, other): + return self.score() > other.score() + +sim = genetics.DiscreteSimulation( + population_size=100, + mutation_mask=genetics.mutation_rate(0.05), # Mutate at a 5% rate + crossover_mask=genetics.two_point_crossover, + selection_function=genetics.tournament(2), + elite_size=2, + initial_generator=WordDNA, + fitness_function=WordDNA.score) + + +def dna_stats(population): + '''Best DNA, best score, average score''' + best_dna = max(population) + best_score = best_dna.score + average_score = sum(member.score() for member in population) / len(population) + + return best_dna, best_score, average_score + + +population = sim.initial_population() + +while True: + best, best_score, average_score = dna_stats(population) + + print('{} | Average score: {}'.format(str(best), average_score)) + + if str(best) == solution: + break + + population = sim.step(population)