Created
May 20, 2013 05:12
-
-
Save Hydrotoast/5610527 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# author -- Gio Borje | |
import random | |
class GeneticProcessor(object): | |
def __init__(self, population_size, fitness_fn): | |
self.population_size = population_size | |
self.fitness_fn = fitness_fn | |
def next_gen(self, population): | |
"""Returns the next generation of a population based on fitness.""" | |
mating_pool = self.select(population) | |
offspring = self.recombine(mating_pool) | |
return mating_pool | |
def select(self, population): | |
"""Generates a mating pool based on roulette selection.""" | |
fitnesses = [self.fitness_fn(individual) for individual in population] | |
total_fitness = sum(fitnesses) | |
rel_fitness = [fitness/total_fitness for fitness in fitnesses] | |
probs = [sum(rel_fitness[:i+1]) for i, fitness in enumerate(rel_fitness)] | |
# Perform roulette selection | |
mating_pool = [] | |
while len(mating_pool) != self.population_size: | |
r = random.random() | |
for i, individual in enumerate(population): | |
if r <= probs[i]: | |
mating_pool.append(individual) | |
break | |
return mating_pool | |
def total_fitness(self, population): | |
"""Returns the total fitness of a population.""" | |
return sum(self.fitness_fn(individual) for individual in population) | |
def recombine(self, mating_pool): | |
"""Performs recombination on a mating pool to produce offspring.""" | |
cutpoint = random.randint(1, self.population_size - 1) | |
# Partition the mating pool | |
left = mating_pool[:len(mating_pool) // 2] | |
right = mating_pool[len(mating_pool) // 2:] | |
# Handle the odd case of mates | |
offspring = [] if len(mating_pool) % 2 == 0 else [mating_pool.pop()] | |
# Perform crossover | |
for i in range(len(left)): | |
offspring.append(right[i][:cutpoint] + left[i][cutpoint:]) | |
offspring.append(left[i][:cutpoint] + right[i][cutpoint:]) | |
return offspring | |
def generate_population(size): | |
"""Generates all individuals of the population.""" | |
population = [] | |
bitlength = len(bin(size)[2:]) | |
for i in range(size): | |
population.append(bin(i)[2:].zfill(bitlength)) | |
return population | |
def even_ones(chromosome): | |
"""Prefers chromosomes with 1 at even positions.""" | |
even_sum = sum(eval(allele) for pos, allele in enumerate(chromosome) if pos % 2 == 0) | |
even_sum -= sum(eval(allele) * 0.5 for pos, allele in enumerate(chromosome) if pos % 2 == 1) | |
return even_sum | |
if __name__ == '__main__': | |
population = generate_population(31) | |
processor = GeneticProcessor(32, even_ones) | |
print('Initial Generation', population) | |
for i in range(1, 40): | |
population = processor.next_gen(population) | |
# print('Generation %d %d: %s' % (i, processor.total_fitness(population), population)) | |
print('Final Generation Score %d: %s' % (processor.total_fitness(population), population)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment