From 8e2698fc0d431c1c814771c7482ea9a9645bdc28 Mon Sep 17 00:00:00 2001 From: SimpleArt <71458112+SimpleArt@users.noreply.github.com> Date: Wed, 21 Oct 2020 14:11:43 -0400 Subject: [PATCH] Implemented basic functionality for using different target fitness types --- src/EasyGA.py | 24 ++++++++++++++++++- src/attributes.py | 2 +- .../parent_selection_methods.py | 12 +++++----- src/run_testing.py | 14 ++++++++++- .../survivor_selection_methods.py | 10 ++------ 5 files changed, 45 insertions(+), 17 deletions(-) diff --git a/src/EasyGA.py b/src/EasyGA.py index 2f1955d..14d7ff2 100644 --- a/src/EasyGA.py +++ b/src/EasyGA.py @@ -80,4 +80,26 @@ class GA(attributes): return sorted(chromosome_set, # list to be sorted key = lambda chromosome: chromosome.get_fitness(), # by fitness - reverse = True) # from highest to lowest fitness + reverse = (self.target_fitness_type == 'max')) # from highest to lowest fitness + + + def get_chromosome_fitness(self, index): + """Returns the fitness value of the chromosome + at the specified index after conversion based + on the target fitness type. + """ + return self.convert_fitness( + self.population.get_chromosome(index).get_fitness() + ) + + + def convert_fitness(self, fitness_value): + """Returns the fitness value if the type of problem + is a maximization problem. Otherwise the fitness is + inverted using max - value + min. + """ + + if self.target_fitness_type == 'max': return fitness_value + max_fitness = self.population.get_chromosome(-1).get_fitness() + min_fitness = self.population.get_chromosome(0).get_fitness() + return max_fitness - fitness_value + min_fitness diff --git a/src/attributes.py b/src/attributes.py index 1c6f49b..5430926 100644 --- a/src/attributes.py +++ b/src/attributes.py @@ -28,7 +28,7 @@ class attributes: self.chromosome_impl = None self.gene_impl = lambda: random.randint(1, 10) self.population = None - self.target_fitness_type = 'maximum' + self.target_fitness_type = 'max' self.update_fitness = True # Selection variables diff --git a/src/parent_selection/parent_selection_methods.py b/src/parent_selection/parent_selection_methods.py index e4aa21f..5c14c4c 100644 --- a/src/parent_selection/parent_selection_methods.py +++ b/src/parent_selection/parent_selection_methods.py @@ -66,20 +66,20 @@ class Parent_Selection: return # Error if not all chromosomes has positive fitness - if (ga.population.get_chromosome(0).get_fitness() == 0 or ga.population.get_chromosome(-1).get_fitness() < 0): + if (ga.get_chromosome_fitness(0) == 0 or ga.get_chromosome_fitness(-1) < 0): print("Error using roulette selection, all fitnesses must be positive.") print("Consider using stockastic roulette selection or tournament selection.") return # The sum of all the fitnessess in a population - fitness_sum = sum(chromosome.get_fitness() for chromosome in ga.population.get_all_chromosomes()) + fitness_sum = sum(ga.get_chromosome_fitness(index) for index in range(ga.population.size())) # A list of ranges that represent the probability of a chromosome getting chosen probability = [ga.selection_probability] # The chance of being selected increases incrementally - for chromosome in ga.population.chromosome_list: - probability.append(probability[-1]+chromosome.fitness/fitness_sum) + for index in range(ga.population.size()): + probability.append(probability[-1]+ga.get_chromosome_fitness(index)/fitness_sum) probability = probability[1:] @@ -111,7 +111,7 @@ class Parent_Selection: print("Selection probability must be between 0 and 1 to select parents.") return - max_fitness = ga.population.get_chromosome(0).get_fitness() + max_fitness = ga.get_chromosome_fitness(0) # Error if the highest fitness is not positive if max_fitness <= 0: @@ -126,5 +126,5 @@ class Parent_Selection: index = random.randint(0, ga.population.size()-1) # Probability of becoming a parent is fitness/max_fitness - if random.uniform(ga.selection_probability, 1) < ga.population.get_chromosome(index).get_fitness()/max_fitness: + if random.uniform(ga.selection_probability, 1) < ga.get_chromosome_fitness(index)/max_fitness: ga.population.set_parent(index) diff --git a/src/run_testing.py b/src/run_testing.py index 78765f0..56b8260 100644 --- a/src/run_testing.py +++ b/src/run_testing.py @@ -3,10 +3,22 @@ import EasyGA # Create the Genetic algorithm ga = EasyGA.GA() +ga.target_fitness_type = 'min' +ga.chromosome_length = 10 +ga.population_size = 25 +ga.generation_goal = 50 +ga.gene_impl = lambda: random.randint(0, 10) -ga.chromosome_length = 100 +def fitness_function(chromosome): + return sum( + gene.get_value() + for gene in chromosome.get_gene_list()) + +ga.fitness_function_impl = fitness_function ga.evolve() +ga.set_all_fitness() +ga.population.sort_by_best_fitness(ga) print(f"Current Generation: {ga.current_generation}") ga.population.print_all() diff --git a/src/survivor_selection/survivor_selection_methods.py b/src/survivor_selection/survivor_selection_methods.py index 958c0c4..0aaa574 100644 --- a/src/survivor_selection/survivor_selection_methods.py +++ b/src/survivor_selection/survivor_selection_methods.py @@ -27,16 +27,10 @@ class Survivor_Selection: def fill_in_parents_then_random(ga): """Fills in the next population with all parents followed by random chromosomes from the last population""" - ga.population.append_children([ # add in chromosomes - random.choice( # randomly - ga.population.get_chromosome_list() # from the population - ) # until the next population is full - for n in range(ga.population.size()-ga.population.total_children())]) - - ga.population.append_children( # add in chromosomes ga.population.get_mating_pool() # from the mating pool - ) # + ) # + ga.population.append_children([ # add in chromosomes random.choice( # randomly ga.population.get_chromosome_list() # from the population