Cleaned up and improved ga.adapt()

- Cleaned up some stuff (variables).
- Added adapt by heavy crossover.
This commit is contained in:
SimpleArt
2020-11-30 14:21:52 -05:00
parent cd19725a5a
commit 63c4304f48

View File

@ -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):