Skip to content
Merged
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
89 changes: 0 additions & 89 deletions 05-genetic-algorithms/python/ga.py

This file was deleted.

167 changes: 167 additions & 0 deletions 05-genetic-algorithms/python/ga/function_evolution.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
#!/usr/bin/env python

import copy
import ga
import operator
import random
import sys


INBREEDING_RATE = 0.25
MAX_TREE_DEPTH = 25


def target(x):
return 3*x - 5


class RandomOperator(object):
def __init__(self):
self.function, self._str = random.choice([(operator.add, "+"),
(operator.mul, "*"),
(operator.sub, "-"),
(operator.div, "/")])

def __call__(self, *args, **kwargs):
return self.function(*args, **kwargs)

def __repr__(self):
return self._str


class Oper(object):
def __init__(self, depth):
self.depth = depth
self.oper = RandomOperator()
self.children = [generate_tree(depth+1), generate_tree(depth+1)]

def __call__(self, x_val):
return self.oper(self.children[0](x_val), self.children[1](x_val))

def __repr__(self):
return "("+str(self.children[0])+str(self.oper)+str(self.children[1])+")"


class Leaf(object):
def __init__(self, depth):
self.oper = None
self.depth = depth
self.value = _choose_terminal()

def __call__(self, x_val):
return float(self.value) if self.value is not "x" else x_val

def __repr__(self):
return str(self.value)


def _choose_terminal():
return random.choice(["x", random.randint(-100, 100)])


def _is_leaf(tree):
if hasattr(tree, "children"):
return False
else:
return True


def generate_tree(depth=0):
if depth < MAX_TREE_DEPTH:
return random.choice([Oper, Leaf])(depth)
else:
return Leaf(depth)


def combine_trees(tree1, tree2):
tree1_copy = copy.deepcopy(tree1)
tree2_copy = copy.deepcopy(tree2)

if not _is_leaf(tree1):
if not _is_leaf(tree2):
tree1_copy.children[1] = tree2_copy.children[0]
else:
tree1_copy.children[1] = tree2_copy

child = tree1_copy
else:
if not _is_leaf(tree2):
tree2_copy.children[1] = tree1_copy
else:
tree2_copy.value = _choose_terminal()

child = tree2_copy

return child


def choose_random_tree_element(tree):
depth = random.randint(0, MAX_TREE_DEPTH)

tree_element = tree
for i in xrange(depth):
if not _is_leaf(tree_element):
child = random.choice([0, 1])
tree_element = tree_element.children[child]
else:
break

return tree_element


def mutate(tree):
tree_element = choose_random_tree_element(tree)

if _is_leaf(tree_element):
tree_element.value = _choose_terminal()
else:
tree_element.oper = RandomOperator()

return tree


def avoid_inbreeding():
if random.random() < INBREEDING_RATE:
return False
else:
return True


def breed(parent1, parent2):
if avoid_inbreeding():
new_blood = generate_tree()
child = combine_trees(parent1, new_blood)
else:
child = combine_trees(parent1, parent2)

child = mutate(child)

return child


def calc_fitness(func):
try:
x_vals = xrange(-100, 100, 1)
reference_vals = map(target, x_vals)
tested_vals = map(func, x_vals)
differences = [(r - t) for (r, t) in zip(reference_vals, tested_vals)]
sum_of_squares = sum([a*a for a in differences])
return -sum_of_squares

except ZeroDivisionError:
return -sys.maxint


def stop_condition(candidate):
if candidate.fitness == 0:
return True
else:
return False


if __name__ == "__main__":
ga.run_genetic_algorithm(spawn_func=generate_tree,
breed_func=breed,
fitness_func=calc_fitness,
stop_condition=stop_condition,
population_size=100)
77 changes: 77 additions & 0 deletions 05-genetic-algorithms/python/ga/ga.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#!/usr/bin/env python

import sys
import random
import time
from collections import namedtuple

Candidate = namedtuple("Candidate", "this fitness")
Population = namedtuple("Population", "average min max size best")


def generate_population(generator_func, fitness_func, population_size=100):
candidates = []
for i in xrange(population_size):
candidate = generator_func()
fitness = fitness_func(candidate)
candidate = Candidate(this=candidate, fitness=fitness)
candidates.append(candidate)
return candidates


def calculate_population_stats(population):
population = sorted(population, key=lambda x: -x.fitness)
population_size = len(population)
fitnesses = [candidate.fitness for candidate in population]
average_fitness = sum(fitnesses) / population_size
min_fitness = min(fitnesses)
max_fitness = max(fitnesses)
best_candidate = population[0]
population = Population(average=average_fitness,
min=min_fitness,
max=max_fitness,
size=population_size,
best=best_candidate.this)
return population


def select_candidates(population):
ordered_population = sorted(population, key=lambda x: x.fitness)
return ordered_population[len(ordered_population)/2:]


def breed_population(candidates, breed_func, fitness_func):
shuffled_candidates = sorted(candidates,
key=lambda x: random.randint(1, 100))
pairs = zip(candidates, shuffled_candidates)
next_gen = []
for parent1, parent2 in pairs:
child_dna = breed_func(parent1.this, parent2.this)
child_fitness = fitness_func(child_dna)
child = Candidate(this=child_dna, fitness=child_fitness)
next_gen.extend([parent1, child])
return next_gen


def run_genetic_algorithm(spawn_func,
breed_func,
fitness_func,
stop_condition,
population_size=100):
start = time.time()
candidates = generate_population(spawn_func,
fitness_func,
population_size)
num_iter = 0
while True:
print calculate_population_stats(candidates)
for candidate in candidates:
if stop_condition(candidate):
end = time.time()
print candidate
print "Number of Iterations: %d" % num_iter
print "Time Taken: %.1f seconds" % (end - start)
sys.exit(0)
candidates = select_candidates(candidates)
candidates = breed_population(candidates, breed_func, fitness_func)
num_iter += 1
59 changes: 59 additions & 0 deletions 05-genetic-algorithms/python/ga/string_evolution.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#!/usr/bin/env python

import ga
import random
import string


TARGET = "I LOVE GENETIC ALGORITHMS"
MUTATION_RATE = 0.75
MAX_STRING_LENGTH = 100


def generate_random_string():
return "".join([random.choice(string.ascii_letters + " ")
for i in xrange(random.randint(1, MAX_STRING_LENGTH))])


def calculate_fitness(dna):
fitness = 0
for (a, b) in zip(dna, TARGET):
if a == b:
fitness += 1
diff_length = abs(len(dna) - len(TARGET))
fitness -= (diff_length*1.1)
return fitness


def breed_strings(string1, string2):
(a1, a2) = split_string(string1)
(b1, b2) = split_string(string2)
child_dna = mutate(a1 + b2)
return child_dna


def split_string(dna):
return (dna[:len(dna)/2], dna[len(dna)/2:])


def mutate(dna):
new_dna = dna
if random.random() < MUTATION_RATE:
cut_point = random.randint(0, len(dna))
new_dna = dna[:cut_point-1] + random.choice(string.ascii_letters + " ") + dna[cut_point:]
return new_dna


def stop_condition(candidate):
if candidate.this == TARGET:
return True
else:
return False


if __name__ == "__main__":
ga.run_genetic_algorithm(spawn_func=generate_random_string,
breed_func=breed_strings,
fitness_func=calculate_fitness,
stop_condition=stop_condition,
population_size=100)