Skip to content

Commit

Permalink
* fix Lucretiel#4
Browse files Browse the repository at this point in the history
  • Loading branch information
liuruoze committed Jun 24, 2018
1 parent f28983e commit 7bfd105
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 10 deletions.
22 changes: 12 additions & 10 deletions genetics/simulation/discrete.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
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)
return zip(x, x)


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
Expand Down Expand Up @@ -45,22 +47,23 @@ 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):
'''
Run a whole genetic step on a scored population, and yield the new
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]
# Generate parents
for elite in scored_population[:self.elite_size]:
yield elite

# Yield the crossover and mutate elements
for parent1, parent2 in pairwise(self.parents(scored_population)):
# crossover parents
mask = self.crossover_mask(parent1.total_length())
for child in parent1.combine(parent2, mask):
# mutate
Expand All @@ -72,4 +75,3 @@ def step(self, population):
list.
'''
return list(self.step_generator(population))

58 changes: 58 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
@@ -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)

0 comments on commit 7bfd105

Please sign in to comment.