Population.next_population and better comments

This commit is contained in:
SimpleArt
2020-10-15 00:22:58 -04:00
parent 543b295e52
commit 5df19df643
6 changed files with 160 additions and 59 deletions

View File

@ -27,7 +27,7 @@ class GA:
self.chromosome_length = 10
self.population_size = 10
self.chromosome_impl = None
self.gene_impl = [random.randint,1,10]
self.gene_impl = None
self.population = None
self.target_fitness_type = 'maximum'
self.update_fitness = True
@ -68,10 +68,9 @@ class GA:
def evolve_generation(self, number_of_generations = 1, consider_termination = True):
"""Evolves the ga the specified number of generations."""
# Evolve the specified number of generations
# and if consider_termination flag is set then
# also check if termination conditions reached
while(number_of_generations > 0 and (not consider_termination or self.termination_impl(self))):
while(number_of_generations > 0 # Evolve the specified number of generations
and (not consider_termination # and if consider_termination flag is set
or self.termination_impl(self))): # then also check if termination conditions reached
# If its the first generation then initialize the population
if self.current_generation == 0:
@ -81,13 +80,13 @@ class GA:
# Otherwise evolve the population
else:
self.population.reset_mating_pool()
self.set_all_fitness()
self.population.sort_by_best_fitness(self)
self.parent_selection_impl(self)
next_population = self.crossover_population_impl(self)
self.survivor_selection_impl(self, next_population)
self.crossover_population_impl(self)
self.survivor_selection_impl(self)
self.mutation_population_impl(self)
self.population.update()
number_of_generations -= 1
self.current_generation += 1
@ -134,4 +133,6 @@ class GA:
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()
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):
@ -21,7 +29,15 @@ class Crossover_Methods:
"""
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:
@ -41,18 +57,27 @@ class Crossover_Methods:
def uniform(ga, parent_one, parent_two):
"""Cross two parents by swapping all genes randomly"""
return ga.make_chromosome([
random.choice([parent_one.get_gene(i), parent_two.get_gene(i)])
for i in range(parent_one.size())])
return ga.make_chromosome([ # Make a new chromosome
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:
"""Crossover methods for numerical genes"""
def int_random(ga, parent_one, parent_two):
"""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()])))
for i in range(parent_one.size())])
return ga.make_chromosome([ # Make a new chromosome
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):
@ -60,16 +85,26 @@ class Crossover_Methods:
# the percentage of genes taken from the first gene
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()))
for i in range(parent_one.size())])
return ga.make_chromosome([ # Make a new chromosome
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):
"""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()))
for i in range(parent_one.size())])
return ga.make_chromosome([ # Make a new chromosome
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):
@ -77,6 +112,10 @@ class Crossover_Methods:
# the percentage of genes taken from the first gene
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())
for i in range(parent_one.size())])
return ga.make_chromosome([ # Make a new chromosome
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

@ -110,8 +110,10 @@ class Parent_Selection:
print("Selection probability must be between 0 and 1 to select parents.")
return
max_fitness = ga.population.get_chromosome(0).get_fitness()
# 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("Consider using tournament selection.")
return
@ -123,5 +125,5 @@ class Parent_Selection:
index = random.randint(0, ga.population.size()-1)
# 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)

View File

@ -3,7 +3,7 @@ import EasyGA
# Create the Genetic algorithm
ga = EasyGA.GA()
ga.population_size = 100
ga.population_size = 25
ga.generation_goal = 100
ga.gene_impl = lambda: random.randint(1, 10)
ga.selection_probability = 0.5

View File

@ -10,6 +10,43 @@ class Population:
self.fitness = None
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):
@ -22,6 +59,11 @@ class Population:
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):
"""Get the chomosome that has the closets fitness to the value defined"""
pass
@ -39,19 +81,9 @@ class Population:
self.mating_pool.append(chromosome)
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 reset_mating_pool(self):
"""Clears the mating pool"""
self.mating_pool = []
def add_child(self, chromosome):
"""Adds a chromosome to the next population"""
self.next_population.append(chromosome)
def get_chromosome(self, index):
@ -64,6 +96,11 @@ class Population:
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):
"""Returns all chromosomes in the population"""
return self.chromosome_list
@ -74,16 +111,16 @@ class Population:
return self.mating_pool
def get_next_population(self):
"""Returns chromosomes in the next population"""
return self.next_population
def get_fitness(self):
"""Returns the population's 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):
"""Sets the chromosome list"""
self.chromosome_list = chromosome_list
@ -99,6 +136,11 @@ class Population:
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):
"""Sets the fitness value of the population"""
self.fitness = fitness

View File

@ -3,25 +3,42 @@ import random
class Survivor_Selection:
"""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"""
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"""
ga.population.set_chromosome_list([
random.choice(ga.population.get_chromosome_list())
for n in range(ga.population.size()-next_population.size())]
+ next_population.get_chromosome_list())
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())])
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"""
ga.population.set_chromosome_list([
random.choice(ga.population.get_chromosome_list())
for n in range(ga.population.size()-len(ga.population.get_mating_pool())-next_population.size())]
+ ga.population.get_mating_pool() + next_population.get_chromosome_list())
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())])
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())])