Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 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,16 +47,16 @@ 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]
Expand All @@ -72,4 +74,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)