Added ga.adapt()
This commit is contained in:
@ -79,6 +79,8 @@ class GA(Attributes):
|
||||
number_of_generations -= 1
|
||||
self.current_generation += 1
|
||||
|
||||
self.adapt()
|
||||
|
||||
|
||||
def evolve(self, number_of_generations = 1, consider_termination = True):
|
||||
"""Runs the ga until the termination point has been satisfied."""
|
||||
@ -93,6 +95,64 @@ class GA(Attributes):
|
||||
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):
|
||||
"""Initialize the population using
|
||||
the initialization implimentation
|
||||
@ -117,18 +177,25 @@ class GA(Attributes):
|
||||
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.
|
||||
1st element has best fitness.
|
||||
2nd element has second best fitness.
|
||||
etc.
|
||||
"""
|
||||
|
||||
return sorted(
|
||||
chromosome_list, # list to be sorted
|
||||
key = lambda chromosome: chromosome.fitness, # by fitness
|
||||
reverse = (self.target_fitness_type == 'max') # ordered by fitness type
|
||||
)
|
||||
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(
|
||||
chromosome_list, # list to be sorted
|
||||
key = lambda chromosome: chromosome.fitness, # by fitness
|
||||
reverse = (self.target_fitness_type == 'max') # ordered by fitness type
|
||||
)
|
||||
|
||||
|
||||
def get_chromosome_fitness(self, index):
|
||||
|
||||
@ -66,6 +66,7 @@ class Attributes:
|
||||
percent_converged = 0.50,
|
||||
chromosome_mutation_rate = 0.15,
|
||||
gene_mutation_rate = 0.05,
|
||||
adapt_rate = 0.05,
|
||||
initialization_impl = Initialization_Methods.random_initialization,
|
||||
fitness_function_impl = Fitness_Examples.is_it_5,
|
||||
make_population = create_population,
|
||||
@ -111,6 +112,7 @@ class Attributes:
|
||||
self.fitness_goal = deepcopy(fitness_goal)
|
||||
self.tolerance_goal = deepcopy(tolerance_goal)
|
||||
self.percent_converged = deepcopy(percent_converged)
|
||||
self.adapt_rate = deepcopy(adapt_rate)
|
||||
|
||||
# Mutation variables
|
||||
self.chromosome_mutation_rate = deepcopy(chromosome_mutation_rate)
|
||||
|
||||
@ -46,13 +46,16 @@ class Population:
|
||||
|
||||
|
||||
def append_children(self, chromosome_list):
|
||||
"""Appends a list of chromosomes to the next population"""
|
||||
self.next_population += chromosome_list
|
||||
"""Appends a list of chromosomes to the next population.
|
||||
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):
|
||||
"""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):
|
||||
|
||||
Reference in New Issue
Block a user