Updated selection implementation, added with/without replacement variation

This commit is contained in:
RyleyGG
2020-10-04 15:54:38 -04:00
parent 89df506469
commit c18a531034
4 changed files with 101 additions and 50 deletions

View File

@ -23,10 +23,10 @@ class GA:
# Termination varibles # Termination varibles
self.current_generation = 0 self.current_generation = 0
self.current_fitness = 0 self.current_fitness = 0
self.generation_goal = 35 self.generation_goal = 50
self.fitness_goal = 3 self.fitness_goal = 3
# Mutation variables # Mutation variables
self.mutation_rate = 0.075 self.mutation_rate = 0.05
# Rerun already computed fitness # Rerun already computed fitness
self.update_fitness = True self.update_fitness = True
@ -35,7 +35,7 @@ class GA:
self.initialization_impl = Initialization_Types().random_initialization self.initialization_impl = Initialization_Types().random_initialization
self.fitness_function_impl = Fitness_Examples().is_it_5 self.fitness_function_impl = Fitness_Examples().is_it_5
self.mutation_impl = Mutation_Types().random_mutation self.mutation_impl = Mutation_Types().random_mutation
self.selection_impl = Selection_Types().tournament_selection self.selection_impl = Selection_Types().Tournament().with_replacement
self.crossover_impl = Crossover_Types().single_point_crossover self.crossover_impl = Crossover_Types().single_point_crossover
self.termination_impl = Termination_Types().generation_based self.termination_impl = Termination_Types().generation_based

View File

@ -25,9 +25,10 @@ class Crossover_Types:
new_gene_set = [] new_gene_set = []
parent_one = crossover_pool[i].get_genes() parent_one = crossover_pool[i].get_genes()
parent_two = crossover_pool[i+1].get_genes() parent_two = crossover_pool[i+1].get_genes()
halfway_point = int(ga.chromosome_length/2) #halfway_point = int(ga.chromosome_length/2)
new_gene_set.extend(parent_one[0:halfway_point]) split_point = random.randint(0,ga.chromosome_length)
new_gene_set.extend(parent_two[halfway_point:]) new_gene_set.extend(parent_one[0:split_point])
new_gene_set.extend(parent_two[split_point:])
new_chromosome = Chromosome(new_gene_set) new_chromosome = Chromosome(new_gene_set)
new_population.add_chromosome(new_chromosome) new_population.add_chromosome(new_chromosome)

View File

@ -5,9 +5,9 @@ import random
# Create the Genetic algorithm # Create the Genetic algorithm
ga = EasyGA.GA() ga = EasyGA.GA()
ga.gene_impl = [random.randrange,1,10] ga.gene_impl = [random.randrange,1,25]
# Run Everyhting # Run Everything
ga.evolve() ga.evolve()
# Print the current population # Print the current population

View File

@ -9,22 +9,69 @@ class Selection_Types:
def __init__(self): def __init__(self):
pass pass
def tournament_selection(self, ga): class Tournament:
"""This example currently uses a 'with replacement' approach (chromosomes are placed back into the pool after participating)""" def with_replacement(self, ga):
tournament_size = int(len(ga.population.get_all_chromosomes())/10) #currently hard-coded for purposes of the example. tournament_size = int(len(ga.population.get_all_chromosomes())/10) #currently hard-coded for purposes of the example.
if tournament_size < 3:
tournament_size = int(len(ga.population.get_all_chromosomes())/3)
#selection_probability is the likelihood that a chromosome will be selected. #selection_probability is the likelihood that a chromosome will be selected.
#best chromosome in a tournament is given a selection probablity of selection_probability #best chromosome in a tournament is given a selection probablity of selection_probability
#2nd best is given probability of selection_probability*(1-selection_probability) #2nd best is given probability of selection_probability*(1-selection_probability)
selection_probability = 0.95 #3rd best is given probability of selection_probability*(1-selection_probability)**2
total_selected = 0 #Total Chromosomes selected selection_probability = 0.95
total_selected = 0 #Total Chromosomes selected
while (total_selected <= ga.population_size*2): while (total_selected <= ga.population_size*2):
#create & gather tournament group #create & gather tournament group
tournament_group = [] tournament_group = []
for i in range(tournament_size):
tournament_group.append(random.choice(ga.population.get_all_chromosomes()))
for i in range(tournament_size):
tournament_group.append(random.choice(ga.population.get_all_chromosomes()))
total_selected = self.selection(tournament_group, tournament_size, total_selected, selection_probability)[0]
new_population = self.create_new_population(ga)
return new_population
def without_replacement(self, ga):
tournament_size = int(len(ga.population.get_all_chromosomes())/10) #currently hard-coded for purposes of the example.
if tournament_size < 3:
tournament_size = int(len(ga.population.get_all_chromosomes())/3)
#selection_probability is the likelihood that a chromosome will be selected.
#best chromosome in a tournament is given a selection probablity of selection_probability
#2nd best is given probability of selection_probability*(1-selection_probability)
#3rd best is given probability of selection_probability*(1-selection_probability)**2
selection_probability = 0.95
total_selected = 0 #Total Chromosomes selected
available_chromosome_indices = []
for i in range(len(ga.population.get_all_chromosomes())):
available_chromosome_indices.append(i)
continue_selecting = True
while (continue_selecting):
#create & gather tournament group
tournament_group = []
for i in range(tournament_size):
selected_chromosome_index = random.choice(available_chromosome_indices)
tournament_group.append(ga.population.get_all_chromosomes()[selected_chromosome_index])
winning_chromosome_index = self.selection(tournament_group, tournament_size, total_selected, selection_probability)[1]
for i in range(len(available_chromosome_indices)):
if tournament_group[winning_chromosome_index].selected:
del available_chromosome_indices[i]
break
#print(winning_chromosome_index)
#print(available_chromosome_indices)
if len(available_chromosome_indices) < 1:
continue_selecting = False
new_population = self.create_new_population(ga)
return new_population
def selection(self, tournament_group, tournament_size, total_selected, selection_probability):
#Sort the tournament contenders based on their fitness #Sort the tournament contenders based on their fitness
#currently hard-coded to only consider higher fitness = better; can be changed once this impl is agreed on #currently hard-coded to only consider higher fitness = better; can be changed once this impl is agreed on
#also currently uses bubble sort because its easy #also currently uses bubble sort because its easy
@ -43,6 +90,7 @@ class Selection_Types:
tournament_group = tournament_group_temp tournament_group = tournament_group_temp
#After sorting by fitness, randomly select a chromosome based on selection_probability #After sorting by fitness, randomly select a chromosome based on selection_probability
selected_chromosome_tournament_index = 0
for i in range(tournament_size): for i in range(tournament_size):
random_num = random.uniform(0,1) random_num = random.uniform(0,1)
@ -51,47 +99,49 @@ class Selection_Types:
if random_num <= selection_probability: if random_num <= selection_probability:
tournament_group[i].selected = True tournament_group[i].selected = True
total_selected += 1 total_selected += 1
selected_chromosome_tournament_index = i
break break
else: else:
if random_num <= selection_probability*((1-selection_probability)**(i-1)): if random_num <= selection_probability*((1-selection_probability)**(i-1)):
tournament_group[i].selected = True tournament_group[i].selected = True
total_selected += 1 total_selected += 1
selected_chromosome_tournament_index = i
break break
return total_selected,selected_chromosome_tournament_index
new_population = ga.crossover_impl(ga) def create_new_population(self, ga):
new_population = ga.crossover_impl(ga)
#If the crossover doesn't create enough chromosomes (ugly right now pls no judgerino, can be changed) #If the crossover doesn't create enough chromosomes (ugly right now pls no judgerino, can be changed)
#Just does single-point crossover at random indices #Just does single-point crossover at random indices
while len(new_population.chromosomes) < ga.population_size: while len(new_population.chromosomes) < ga.population_size:
crossover_pool = [] crossover_pool = []
for i in range(ga.population_size): for i in range(ga.population_size):
if ga.population.get_all_chromosomes()[i].selected: if ga.population.get_all_chromosomes()[i].selected:
crossover_pool.append(ga.population.get_all_chromosomes()[i]) crossover_pool.append(ga.population.get_all_chromosomes()[i])
split_point = random.randint(0,ga.chromosome_length) split_point = random.randint(0,ga.chromosome_length)
chromosome_list = [] chromosome_list = []
for i in range(len(crossover_pool)): for i in range(len(crossover_pool)):
if i + 1 < len(crossover_pool): if i + 1 < len(crossover_pool):
new_gene_set = [] new_gene_set = []
parent_one = crossover_pool[i].get_genes() parent_one = crossover_pool[i].get_genes()
parent_two = crossover_pool[i+1].get_genes() parent_two = crossover_pool[i+1].get_genes()
new_gene_set.extend(parent_one[0:split_point]) new_gene_set.extend(parent_one[0:split_point])
new_gene_set.extend(parent_two[split_point:]) new_gene_set.extend(parent_two[split_point:])
new_chromosome = Chromosome(new_gene_set) new_chromosome = Chromosome(new_gene_set)
chromosome_list.append(new_chromosome) chromosome_list.append(new_chromosome)
for i in range(len(chromosome_list)): for i in range(len(chromosome_list)):
new_population.add_chromosome(chromosome_list[i]) new_population.add_chromosome(chromosome_list[i])
if len(new_population.chromosomes) >= ga.population_size: if len(new_population.chromosomes) >= ga.population_size:
break break
new_chromosome_set = ga.mutation_impl(ga, new_population.get_all_chromosomes())
new_population.set_all_chromosomes(new_chromosome_set)
return new_population
new_chromosome_set = ga.mutation_impl(ga, new_population.get_all_chromosomes())
new_population.set_all_chromosomes(new_chromosome_set)
return new_population
def roulette_selection(self, ga): def roulette_selection(self, ga):
"""Roulette selection works based off of how strong the fitness is of the """Roulette selection works based off of how strong the fitness is of the