From 63c4304f480a467c4fb255ac3e21b44cfec4a74a Mon Sep 17 00:00:00 2001 From: SimpleArt <71458112+SimpleArt@users.noreply.github.com> Date: Mon, 30 Nov 2020 14:21:52 -0500 Subject: [PATCH] Cleaned up and improved ga.adapt() - Cleaned up some stuff (variables). - Added adapt by heavy crossover. --- src/EasyGA.py | 72 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 42 insertions(+), 30 deletions(-) diff --git a/src/EasyGA.py b/src/EasyGA.py index b0cd81c..27bdf8e 100644 --- a/src/EasyGA.py +++ b/src/EasyGA.py @@ -98,58 +98,70 @@ class GA(Attributes): def adapt(self): """Modifies the parent ratio and mutation rates based on the adapt rate and percent converged. - Attempts to balance out so that 25% of the desired - percent converged (50%*25% = 12.5% default) - is the amount converged at all times. + Attempts to balance out so that a portion of the + population gradually approaches the solution. + + Afterwards also heavily crosses the worst chromosomes + with the best chromosome, depending on how well the + overall population is doing. """ # Don't adapt if self.adapt_rate is None or self.adapt_rate <= 0: 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 - 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 - tol = 0.01 if self.tolerance_goal is None else self.tolerance_goal - tol *= 1 + abs(best_fitness) + tol_half = abs(best_fitness - threshhold_fitness)/2 + + # 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: multiplier = 1 + self.adapt_rate - # Minimum and maximum rates allowed - min_val = 0.05 - max_val = 0.25 - limit = max_val / multiplier + # Minimum and maximum mutation rates + min_rate = 0.05 + max_rate = 0.25 + + # 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 - 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 - - # Way too few converged, adapt twice as fast - 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) + self.selection_probability = min(0.75 , self.selection_probability * multiplier) + self.chromosome_mutation_rate = max(min_rate, self.chromosome_mutation_rate / multiplier) + self.gene_mutation_rate = max(min_rate, 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)*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 - if abs(best_fitness - threshhold_fitness) < tol: - multiplier **= 2 - limit = max_val / multiplier + # Strongly cross the best chromosome with the worst chromosomes + for n in range(1, amount_converged//4): + self.population[-n] = self.crossover_individual_impl( + 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.chromosome_mutation_rate = min(max_val, self.chromosome_mutation_rate * multiplier) - self.gene_mutation_rate = min(max_val, self.gene_mutation_rate * multiplier) + self.population.sort_by_best_fitness(self) def initialize_population(self):