Merge pull request #14 from danielwilczak101/jack

Updating with jacks code.
This commit is contained in:
Daniel Wilczak
2020-10-15 01:03:44 -04:00
committed by GitHub
8 changed files with 168 additions and 70 deletions

View File

@ -27,7 +27,7 @@ class GA:
self.chromosome_length = 10 self.chromosome_length = 10
self.population_size = 10 self.population_size = 10
self.chromosome_impl = None self.chromosome_impl = None
self.gene_impl = [random.randint,1,10] self.gene_impl = None
self.population = None self.population = None
self.target_fitness_type = 'maximum' self.target_fitness_type = 'maximum'
self.update_fitness = True self.update_fitness = True
@ -68,10 +68,9 @@ class GA:
def evolve_generation(self, number_of_generations = 1, consider_termination = True): def evolve_generation(self, number_of_generations = 1, consider_termination = True):
"""Evolves the ga the specified number of generations.""" """Evolves the ga the specified number of generations."""
# Evolve the specified number of generations while(number_of_generations > 0 # Evolve the specified number of generations
# and if consider_termination flag is set then and (not consider_termination # and if consider_termination flag is set
# also check if termination conditions reached or self.termination_impl(self))): # then also check if termination conditions reached
while(number_of_generations > 0 and (not consider_termination or self.termination_impl(self))):
# If its the first generation then initialize the population # If its the first generation then initialize the population
if self.current_generation == 0: if self.current_generation == 0:
@ -81,13 +80,13 @@ class GA:
# Otherwise evolve the population # Otherwise evolve the population
else: else:
self.population.reset_mating_pool()
self.set_all_fitness() self.set_all_fitness()
self.population.sort_by_best_fitness(self) self.population.sort_by_best_fitness(self)
self.parent_selection_impl(self) self.parent_selection_impl(self)
next_population = self.crossover_population_impl(self) self.crossover_population_impl(self)
self.survivor_selection_impl(self, next_population) self.survivor_selection_impl(self)
self.mutation_population_impl(self) self.mutation_population_impl(self)
self.population.update()
number_of_generations -= 1 number_of_generations -= 1
self.current_generation += 1 self.current_generation += 1
@ -134,4 +133,6 @@ class GA:
etc. etc.
""" """
return sorted(chromosome_set, key = lambda chromosome: chromosome.get_fitness(), reverse = True) return sorted(chromosome_set, # list to be sorted
key = lambda chromosome: chromosome.get_fitness(), # by fitness
reverse = True) # from highest to lowest fitness

View File

@ -12,7 +12,15 @@ class Crossover_Methods:
""" """
mating_pool = ga.population.get_mating_pool() mating_pool = ga.population.get_mating_pool()
return ga.make_population([ga.crossover_individual_impl(ga, mating_pool[index], mating_pool[index-1]) for index in range(len(mating_pool))])
for index in range(len(mating_pool)): # for each parent in the mating pool
ga.population.add_child( # add a child
ga.crossover_individual_impl( # by crossing
ga, #
mating_pool[index], # the parent and
mating_pool[index-1] # the previous parent
)
)
def random_selection(ga): def random_selection(ga):
@ -21,7 +29,15 @@ class Crossover_Methods:
""" """
mating_pool = ga.population.get_mating_pool() mating_pool = ga.population.get_mating_pool()
return ga.make_population([ga.crossover_individual_impl(ga, parent, random.choice(mating_pool)) for parent in mating_pool])
for parent in mating_pool: # for each parent in the mating pool
ga.population.add_child( # add a child
ga.crossover_individual_impl( # by crossing
ga, #
parent, # the parent and
random.choice(mating_pool) # a random parent
)
)
class Individual: class Individual:
@ -41,18 +57,27 @@ class Crossover_Methods:
def uniform(ga, parent_one, parent_two): def uniform(ga, parent_one, parent_two):
"""Cross two parents by swapping all genes randomly""" """Cross two parents by swapping all genes randomly"""
return ga.make_chromosome([
random.choice([parent_one.get_gene(i), parent_two.get_gene(i)]) return ga.make_chromosome([ # Make a new chromosome
for i in range(parent_one.size())]) random.choice([ # by selecting random genes from
parent_one.get_gene(i), # each parent
parent_two.get_gene(i) #
]) #
for i in range(parent_one.size())]) # for each gene
class Arithmetic: class Arithmetic:
"""Crossover methods for numerical genes""" """Crossover methods for numerical genes"""
def int_random(ga, parent_one, parent_two): def int_random(ga, parent_one, parent_two):
"""Cross two parents by taking a random integer value between each of the genes""" """Cross two parents by taking a random integer value between each of the genes"""
return ga.make_chromosome([
ga.make_gene(random.randint(*sorted([parent_one.get_gene(i).get_value(), parent_two.get_gene(i).get_value()]))) return ga.make_chromosome([ # Make a new chromosome
for i in range(parent_one.size())]) ga.make_gene( # filled with new genes
random.randint(*sorted([ # by choosing random integers between
parent_one.get_gene(i).get_value(), # the parents' genes
parent_two.get_gene(i).get_value() #
]))) #
for i in range(parent_one.size())]) # for each gene
def int_weighted(ga, parent_one, parent_two): def int_weighted(ga, parent_one, parent_two):
@ -60,16 +85,26 @@ class Crossover_Methods:
# the percentage of genes taken from the first gene # the percentage of genes taken from the first gene
weight = 0.25 weight = 0.25
return ga.make_chromosome([
ga.make_gene(int(weight*parent_one.get_gene(i).get_value()+(1-weight)*parent_two.get_gene(i).get_value())) return ga.make_chromosome([ # Make a new chromosome
for i in range(parent_one.size())]) ga.make_gene(int( # filled with new integer genes
weight*parent_one.get_gene(i).get_value()+ # with weight% from parent one and
(1-weight)*parent_two.get_gene(i).get_value() # (100-weight)% from parent two
)) #
for i in range(parent_one.size())]) # for each gene
def float_random(ga, parent_one, parent_two): def float_random(ga, parent_one, parent_two):
"""Cross two parents by taking a random numeric value between each of the genes""" """Cross two parents by taking a random numeric value between each of the genes"""
return ga.make_chromosome([
ga.make_gene(random.uniform(parent_one.get_gene(i).get_value(), parent_two.get_gene(i).get_value())) return ga.make_chromosome([ # Make a new chromosome
for i in range(parent_one.size())]) ga.make_gene( # filled with new genes
random.uniform( # by taking a random float between
parent_one.get_gene(i).get_value(), # the parents' genes
parent_two.get_gene(i).get_value() #
) #
) #
for i in range(parent_one.size())]) # for each gene
def float_weighted(ga, parent_one, parent_two): def float_weighted(ga, parent_one, parent_two):
@ -77,6 +112,10 @@ class Crossover_Methods:
# the percentage of genes taken from the first gene # the percentage of genes taken from the first gene
weight = 0.25 weight = 0.25
return ga.make_chromosome([
ga.make_gene(weight*parent_one.get_gene(i).get_value()+(1-weight)*parent_two.get_gene(i).get_value()) return ga.make_chromosome([ # Make a new chromosome
for i in range(parent_one.size())]) ga.make_gene( # filled with new float genes
weight*parent_one.get_gene(i).get_value()+ # with weight% from parent one and
(1-weight)*parent_two.get_gene(i).get_value() # (100-weight)% from parent two
) #
for i in range(parent_one.size())]) # for each gene

View File

@ -12,16 +12,15 @@ class Initialization_Methods:
if ga.chromosome_impl != None: if ga.chromosome_impl != None:
return ga.make_population([ return ga.make_population([
ga.make_chromosome([ ga.make_chromosome([
ga.make_gene(ga.chromosome_impl(j)) ga.make_gene(value)
for j in range(ga.chromosome_length)]) for value in ga.chromosome_impl()])
for i in range(ga.population_size)]) for i in range(ga.population_size)])
# Using the gene_impl to set every gene to be the same # Using the gene_impl to set every gene to be the same
elif ga.gene_impl != None: elif ga.gene_impl != None:
function = ga.gene_impl[0]
return ga.make_population([ return ga.make_population([
ga.make_chromosome([ ga.make_chromosome([
ga.make_gene(function(*ga.gene_impl[1:])) ga.make_gene(ga.gene_impl())
for j in range(ga.chromosome_length)]) for j in range(ga.chromosome_length)])
for i in range(ga.population_size)]) for i in range(ga.population_size)])

View File

@ -25,14 +25,13 @@ class Mutation_Methods:
# Using the chromosome_impl to set every index inside of the chromosome # Using the chromosome_impl to set every index inside of the chromosome
if ga.chromosome_impl != None: if ga.chromosome_impl != None:
return ga.make_chromosome([ return ga.make_chromosome([
ga.make_gene(ga.chromosome_impl(j)) ga.make_gene(value)
for j in range(chromosome.size())]) for value in ga.chromosome_impl()])
# Using the gene_impl # Using the gene_impl
elif ga.gene_impl != None: elif ga.gene_impl != None:
function = ga.gene_impl[0]
return ga.make_chromosome([ return ga.make_chromosome([
ga.make_gene(function(*ga.gene_impl[1:])) ga.make_gene(ga.gene_impl())
for j in range(chromosome.size())]) for j in range(chromosome.size())])
# Exit because no gene creation method specified # Exit because no gene creation method specified
@ -48,13 +47,12 @@ class Mutation_Methods:
# Using the chromosome_impl # Using the chromosome_impl
if ga.chromosome_impl != None: if ga.chromosome_impl != None:
index = random.randint(0, chromosome.size()-1) index = random.randint(0, chromosome.size()-1)
chromosome.set_gene(ga.make_gene(ga.chromosome_impl(index)), index) chromosome.set_gene(ga.make_gene(ga.chromosome_impl()[index]), index)
# Using the gene_impl # Using the gene_impl
elif ga.gene_impl != None: elif ga.gene_impl != None:
function = ga.gene_impl[0]
index = random.randint(0, chromosome.size()-1) index = random.randint(0, chromosome.size()-1)
chromosome.set_gene(ga.make_gene(function(*ga.gene_impl[1:])), index) chromosome.set_gene(ga.make_gene(ga.gene_impl()), index)
# Exit because no gene creation method specified # Exit because no gene creation method specified
else: else:

View File

@ -110,8 +110,10 @@ class Parent_Selection:
print("Selection probability must be between 0 and 1 to select parents.") print("Selection probability must be between 0 and 1 to select parents.")
return return
max_fitness = ga.population.get_chromosome(0).get_fitness()
# Error if the highest fitness is not positive # Error if the highest fitness is not positive
if ga.population.get_chromosome(0).get_fitness() <= 0: if max_fitness <= 0:
print("Error using stochastic roulette selection, best fitness must be positive.") print("Error using stochastic roulette selection, best fitness must be positive.")
print("Consider using tournament selection.") print("Consider using tournament selection.")
return return
@ -123,5 +125,5 @@ class Parent_Selection:
index = random.randint(0, ga.population.size()-1) index = random.randint(0, ga.population.size()-1)
# Probability of becoming a parent is fitness/max_fitness # Probability of becoming a parent is fitness/max_fitness
if random.uniform(ga.selection_probability, 1) < ga.population.get_chromosome(index).get_fitness() / ga.population.get_chromosome(0).get_fitness(): if random.uniform(ga.selection_probability, 1) < ga.population.get_chromosome(index).get_fitness()/max_fitness:
ga.population.set_parent(index) ga.population.set_parent(index)

View File

@ -5,7 +5,7 @@ import EasyGA
ga = EasyGA.GA() ga = EasyGA.GA()
ga.population_size = 25 ga.population_size = 25
ga.generation_goal = 100 ga.generation_goal = 100
ga.gene_impl = [random.randint,0,10] ga.gene_impl = lambda: random.randint(1, 10)
ga.selection_probability = 0.5 ga.selection_probability = 0.5
ga.fitness_function_impl = EasyGA.Fitness_Examples.near_5 ga.fitness_function_impl = EasyGA.Fitness_Examples.near_5
ga.parent_selection_impl = EasyGA.Parent_Selection.Roulette.stochastic_selection ga.parent_selection_impl = EasyGA.Parent_Selection.Roulette.stochastic_selection

View File

@ -10,6 +10,43 @@ class Population:
self.fitness = None self.fitness = None
self.mating_pool = [] self.mating_pool = []
self.next_population = []
def update(self):
self.set_chromosome_list(self.next_population)
self.reset_mating_pool()
self.reset_next_population()
def remove_chromosome(self, index):
"""Removes a chromosome from the indicated index from the population"""
del self.chromosome_list[index]
def remove_parent(self, index):
"""Removes a parent from the indicated index from the mating pool"""
del self.mating_pool[index]
def remove_child(self, index):
"""Removes a child from the indicated index from the next population"""
del self.next_population[index]
def reset_mating_pool(self):
"""Clears the mating pool"""
self.mating_pool = []
def reset_next_population(self):
"""Clears the next population"""
self.next_population = []
def append_children(self, chromosome_list):
"""Appends a list of chromosomes to the next population"""
self.next_population += chromosome_list
def sort_by_best_fitness(self, ga): def sort_by_best_fitness(self, ga):
@ -22,6 +59,11 @@ class Population:
return len(self.chromosome_list) return len(self.chromosome_list)
def total_children(self):
"""Returns the size of the next population"""
return len(self.next_population)
def get_closet_fitness(self,value): def get_closet_fitness(self,value):
"""Get the chomosome that has the closets fitness to the value defined""" """Get the chomosome that has the closets fitness to the value defined"""
pass pass
@ -39,19 +81,9 @@ class Population:
self.mating_pool.append(chromosome) self.mating_pool.append(chromosome)
def remove_chromosome(self, index): def add_child(self, chromosome):
"""Removes a chromosome from the indicated index from the population""" """Adds a chromosome to the next population"""
del self.chromosome_list[index] self.next_population.append(chromosome)
def remove_parent(self, index):
"""Removes a parent from the indicated index from the mating pool"""
del self.mating_pool[index]
def reset_mating_pool(self):
"""Clears the mating pool"""
self.mating_pool = []
def get_chromosome(self, index): def get_chromosome(self, index):
@ -64,6 +96,11 @@ class Population:
return self.mating_pool[index] return self.mating_pool[index]
def get_child(self, index):
"""Returns the child at the given index in the next population"""
return self.next_population[index]
def get_chromosome_list(self): def get_chromosome_list(self):
"""Returns all chromosomes in the population""" """Returns all chromosomes in the population"""
return self.chromosome_list return self.chromosome_list
@ -74,16 +111,16 @@ class Population:
return self.mating_pool return self.mating_pool
def get_next_population(self):
"""Returns chromosomes in the next population"""
return self.next_population
def get_fitness(self): def get_fitness(self):
"""Returns the population's fitness""" """Returns the population's fitness"""
return self.fitness return self.fitness
def set_parent(self, index):
"""Sets the indexed chromosome from the population as a parent"""
self.add_parent(self.get_chromosome(index))
def set_chromosome_list(self, chromosome_list): def set_chromosome_list(self, chromosome_list):
"""Sets the chromosome list""" """Sets the chromosome list"""
self.chromosome_list = chromosome_list self.chromosome_list = chromosome_list
@ -99,6 +136,11 @@ class Population:
self.chromosome_list[index] = chromosome self.chromosome_list[index] = chromosome
def set_parent(self, index):
"""Sets the indexed chromosome from the population as a parent"""
self.add_parent(self.get_chromosome(index))
def set_fitness(self, fitness): def set_fitness(self, fitness):
"""Sets the fitness value of the population""" """Sets the fitness value of the population"""
self.fitness = fitness self.fitness = fitness

View File

@ -3,25 +3,42 @@ import random
class Survivor_Selection: class Survivor_Selection:
"""Survivor selection determines which individuals should be brought to the next generation""" """Survivor selection determines which individuals should be brought to the next generation"""
def fill_in_best(ga, next_population): def fill_in_best(ga):
"""Fills in the next population with the best chromosomes from the last population""" """Fills in the next population with the best chromosomes from the last population"""
ga.population.set_chromosome_list(ga.population.get_chromosome_list()[:ga.population.size()-next_population.size()] + next_population.get_chromosome_list()) # add in chromosomes starting from
# the first chromosome in the population
# until the next population is full
ga.population.append_children(
ga.population.get_chromosome_list()[:ga.population.size()-len(ga.population.next_population)]
)
def fill_in_random(ga, next_population): def fill_in_random(ga):
"""Fills in the next population with random chromosomes from the last population""" """Fills in the next population with random chromosomes from the last population"""
ga.population.set_chromosome_list([ ga.population.append_children([ # add in chromosomes
random.choice(ga.population.get_chromosome_list()) random.choice( # randomly
for n in range(ga.population.size()-next_population.size())] ga.population.get_chromosome_list() # from the population
+ next_population.get_chromosome_list()) ) # until the next population is full
for n in range(ga.population.size()-ga.population.total_children())])
def fill_in_parents_then_random(ga, next_population): def fill_in_parents_then_random(ga):
"""Fills in the next population with all parents followed by random chromosomes from the last population""" """Fills in the next population with all parents followed by random chromosomes from the last population"""
ga.population.set_chromosome_list([ ga.population.append_children([ # add in chromosomes
random.choice(ga.population.get_chromosome_list()) random.choice( # randomly
for n in range(ga.population.size()-len(ga.population.get_mating_pool())-next_population.size())] ga.population.get_chromosome_list() # from the population
+ ga.population.get_mating_pool() + next_population.get_chromosome_list()) ) # until the next population is full
for n in range(ga.population.size()-ga.population.total_children())])
ga.population.append_children( # add in chromosomes
ga.population.get_mating_pool() # from the mating pool
) #
ga.population.append_children([ # add in chromosomes
random.choice( # randomly
ga.population.get_chromosome_list() # from the population
) # until the next population is full
for n in range(ga.population.size()-ga.population.total_children())])