Added ga.adapt()

This commit is contained in:
SimpleArt
2020-11-27 19:12:40 -05:00
parent a87103b80c
commit 1197447d7e
3 changed files with 81 additions and 9 deletions

View File

@ -79,6 +79,8 @@ class GA(Attributes):
number_of_generations -= 1 number_of_generations -= 1
self.current_generation += 1 self.current_generation += 1
self.adapt()
def evolve(self, number_of_generations = 1, consider_termination = True): def evolve(self, number_of_generations = 1, consider_termination = True):
"""Runs the ga until the termination point has been satisfied.""" """Runs the ga until the termination point has been satisfied."""
@ -93,6 +95,64 @@ class GA(Attributes):
return self.termination_impl(self) return self.termination_impl(self)
def adapt(self):
"""Modifies the parent ratio and mutation rates
based on the adapt rate and percent converged.
"""
# Don't adapt
if self.adapt_rate is None or self.adapt_rate <= 0:
return
# How much converged
best_fitness = self.population[0].fitness
threshhold_fitness = self.population[round(self.percent_converged*len(self.population)/4)].fitness
# Closeness required for convergence
tol = 0.01 if self.tolerance_goal is None else self.tolerance_goal
tol *= 1 + abs(best_fitness)
# Change rates with:
multiplier = 1 + self.adapt_rate
# Minimum and maximum rates allowed
min_val = 0.05
max_val = 0.75
limit = max_val / multiplier
# Too few converged: cross more and mutate less
if abs(best_fitness - threshhold_fitness) > tol:
threshhold_fitness = self.population[round(self.percent_converged*len(self.population)/8)].fitness
# Way too few converged
if abs(best_fitness - threshhold_fitness) > tol:
multiplier **= 2
limit = max_val / multiplier
self.parent_ratio = min(max_val, self.parent_ratio*multiplier)
self.selection_probability = min(max_val, self.selection_probability*multiplier)
self.chromosome_mutation_rate = max(min_val, self.chromosome_mutation_rate/multiplier)
self.gene_mutation_rate = max(min_val, self.gene_mutation_rate/multiplier)
# Too many converged: cross less and mutate more
else:
threshhold_fitness = self.population[round(self.percent_converged*len(self.population)/2)].fitness
# Way too many converged
if abs(best_fitness - threshhold_fitness) > tol:
multiplier **= 2
limit = max_val / multiplier
self.parent_ratio = max(min_val, self.parent_ratio/multiplier)
self.selection_probability = max(min_val, self.selection_probability/multiplier)
self.chromosome_mutation_rate = min(max_val, self.chromosome_mutation_rate*multiplier)
self.gene_mutation_rate = min(max_val, self.gene_mutation_rate*multiplier)
def initialize_population(self): def initialize_population(self):
"""Initialize the population using """Initialize the population using
the initialization implimentation the initialization implimentation
@ -117,13 +177,20 @@ class GA(Attributes):
chromosome.fitness = self.fitness_function_impl(chromosome) chromosome.fitness = self.fitness_function_impl(chromosome)
def sort_by_best_fitness(self, chromosome_list): def sort_by_best_fitness(self, chromosome_list, in_place = False):
"""Sorts the chromosome list by fitness based on fitness type. """Sorts the chromosome list by fitness based on fitness type.
1st element has best fitness. 1st element has best fitness.
2nd element has second best fitness. 2nd element has second best fitness.
etc. etc.
""" """
if in_place:
return chromosome_list.sort( # list to be sorted
key = lambda chromosome: chromosome.fitness, # by fitness
reverse = (self.target_fitness_type == 'max') # ordered by fitness type
)
else:
return sorted( return sorted(
chromosome_list, # list to be sorted chromosome_list, # list to be sorted
key = lambda chromosome: chromosome.fitness, # by fitness key = lambda chromosome: chromosome.fitness, # by fitness

View File

@ -66,6 +66,7 @@ class Attributes:
percent_converged = 0.50, percent_converged = 0.50,
chromosome_mutation_rate = 0.15, chromosome_mutation_rate = 0.15,
gene_mutation_rate = 0.05, gene_mutation_rate = 0.05,
adapt_rate = 0.05,
initialization_impl = Initialization_Methods.random_initialization, initialization_impl = Initialization_Methods.random_initialization,
fitness_function_impl = Fitness_Examples.is_it_5, fitness_function_impl = Fitness_Examples.is_it_5,
make_population = create_population, make_population = create_population,
@ -111,6 +112,7 @@ class Attributes:
self.fitness_goal = deepcopy(fitness_goal) self.fitness_goal = deepcopy(fitness_goal)
self.tolerance_goal = deepcopy(tolerance_goal) self.tolerance_goal = deepcopy(tolerance_goal)
self.percent_converged = deepcopy(percent_converged) self.percent_converged = deepcopy(percent_converged)
self.adapt_rate = deepcopy(adapt_rate)
# Mutation variables # Mutation variables
self.chromosome_mutation_rate = deepcopy(chromosome_mutation_rate) self.chromosome_mutation_rate = deepcopy(chromosome_mutation_rate)

View File

@ -46,13 +46,16 @@ class Population:
def append_children(self, chromosome_list): def append_children(self, chromosome_list):
"""Appends a list of chromosomes to the next population""" """Appends a list of chromosomes to the next population.
self.next_population += chromosome_list Appends to the front so that chromosomes with fitness
values already will stay sorted.
"""
self.next_population = chromosome_list + self.next_population
def sort_by_best_fitness(self, ga): def sort_by_best_fitness(self, ga):
"""Sorts the population by fitness""" """Sorts the population by fitness"""
self.chromosome_list = ga.sort_by_best_fitness(self.chromosome_list) ga.sort_by_best_fitness(self.chromosome_list, in_place = True)
def add_chromosome(self, chromosome, index = None): def add_chromosome(self, chromosome, index = None):