Cleaned up and improved ga.adapt()
- Cleaned up some stuff (variables). - Added adapt by heavy crossover.
This commit is contained in:
@ -98,58 +98,70 @@ class GA(Attributes):
|
|||||||
def adapt(self):
|
def adapt(self):
|
||||||
"""Modifies the parent ratio and mutation rates
|
"""Modifies the parent ratio and mutation rates
|
||||||
based on the adapt rate and percent converged.
|
based on the adapt rate and percent converged.
|
||||||
Attempts to balance out so that 25% of the desired
|
Attempts to balance out so that a portion of the
|
||||||
percent converged (50%*25% = 12.5% default)
|
population gradually approaches the solution.
|
||||||
is the amount converged at all times.
|
|
||||||
|
Afterwards also heavily crosses the worst chromosomes
|
||||||
|
with the best chromosome, depending on how well the
|
||||||
|
overall population is doing.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Don't adapt
|
# Don't adapt
|
||||||
if self.adapt_rate is None or self.adapt_rate <= 0:
|
if self.adapt_rate is None or self.adapt_rate <= 0:
|
||||||
return
|
return
|
||||||
|
|
||||||
# How much converged
|
# Amount of the population desired to converge (default 50%)
|
||||||
|
amount_converged = round(self.percent_converged*len(self.population))
|
||||||
|
|
||||||
|
# How much converged halfway
|
||||||
best_fitness = self.population[0].fitness
|
best_fitness = self.population[0].fitness
|
||||||
threshhold_fitness = self.population[round(self.percent_converged*len(self.population)/4)].fitness
|
threshhold_fitness = self.population[amount_converged//2].fitness
|
||||||
|
|
||||||
# Closeness required for convergence
|
# Closeness required for convergence
|
||||||
tol = 0.01 if self.tolerance_goal is None else self.tolerance_goal
|
tol_half = abs(best_fitness - threshhold_fitness)/2
|
||||||
tol *= 1 + abs(best_fitness)
|
|
||||||
|
# How much converged a quarter of the way
|
||||||
|
threshhold_fitness = self.population[amount_converged//4].fitness
|
||||||
|
|
||||||
|
# Tolerance result
|
||||||
|
tol_quar = abs(best_fitness - threshhold_fitness)
|
||||||
|
|
||||||
# Change rates with:
|
# Change rates with:
|
||||||
multiplier = 1 + self.adapt_rate
|
multiplier = 1 + self.adapt_rate
|
||||||
|
|
||||||
# Minimum and maximum rates allowed
|
# Minimum and maximum mutation rates
|
||||||
min_val = 0.05
|
min_rate = 0.05
|
||||||
max_val = 0.25
|
max_rate = 0.25
|
||||||
limit = max_val / multiplier
|
|
||||||
|
# Adapt twice as fast if it's really bad
|
||||||
|
if tol_quar < tol_half/2 or tol_quar > tol_half*2:
|
||||||
|
multiplier **= 2
|
||||||
|
|
||||||
# Too few converged: cross more and mutate less
|
# Too few converged: cross more and mutate less
|
||||||
if abs(best_fitness - threshhold_fitness) > tol:
|
if tol_quar > tol_half:
|
||||||
|
|
||||||
threshhold_fitness = self.population[round(self.percent_converged*len(self.population)/8)].fitness
|
self.selection_probability = min(0.75 , self.selection_probability * multiplier)
|
||||||
|
self.chromosome_mutation_rate = max(min_rate, self.chromosome_mutation_rate / multiplier)
|
||||||
# Way too few converged, adapt twice as fast
|
self.gene_mutation_rate = max(min_rate, self.gene_mutation_rate / multiplier)
|
||||||
if abs(best_fitness - threshhold_fitness) > tol:
|
|
||||||
multiplier **= 2
|
|
||||||
limit = max_val / 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
|
# Too many converged: cross less and mutate more
|
||||||
else:
|
else:
|
||||||
|
|
||||||
threshhold_fitness = self.population[round(self.percent_converged*len(self.population)*3/8)].fitness
|
self.selection_probability = max(0.25 , self.selection_probability / multiplier)
|
||||||
|
self.chromosome_mutation_rate = min(max_rate, self.chromosome_mutation_rate * multiplier)
|
||||||
|
self.gene_mutation_rate = min(max_rate, self.gene_mutation_rate * multiplier)
|
||||||
|
|
||||||
# Way too many converged, adapt twice as fast
|
# Strongly cross the best chromosome with the worst chromosomes
|
||||||
if abs(best_fitness - threshhold_fitness) < tol:
|
for n in range(1, amount_converged//4):
|
||||||
multiplier **= 2
|
self.population[-n] = self.crossover_individual_impl(
|
||||||
limit = max_val / multiplier
|
self,
|
||||||
|
self.population[-n],
|
||||||
|
self.population[0],
|
||||||
|
min(0.5, tol_half)
|
||||||
|
)
|
||||||
|
self.population[-n].fitness = self.fitness_function_impl(self.population[-n])
|
||||||
|
|
||||||
self.selection_probability = max(min_val, self.selection_probability / multiplier)
|
self.population.sort_by_best_fitness(self)
|
||||||
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):
|
||||||
|
|||||||
Reference in New Issue
Block a user