Changed implementation framework
Instead of a nested approach, selection/crossover/mutation are all called separately and directly by the GA. selection_impl was also separated into parent_selection_impl and survivor_selection_impl, as both are needed separately.
This commit is contained in:
@ -16,17 +16,17 @@ class GA:
|
|||||||
"""Initialize the GA."""
|
"""Initialize the GA."""
|
||||||
# Initilization variables
|
# Initilization variables
|
||||||
self.chromosome_length = 10
|
self.chromosome_length = 10
|
||||||
self.population_size = 100
|
self.population_size = 150
|
||||||
self.chromosome_impl = None
|
self.chromosome_impl = None
|
||||||
self.gene_impl = None
|
self.gene_impl = None
|
||||||
self.population = None
|
self.population = None
|
||||||
# Termination varibles
|
# Termination varibles
|
||||||
self.current_generation = 0
|
self.current_generation = 0
|
||||||
self.current_fitness = 0
|
self.current_fitness = 0
|
||||||
self.generation_goal = 50
|
self.generation_goal = 100
|
||||||
self.fitness_goal = 3
|
self.fitness_goal = 3
|
||||||
# Mutation variables
|
# Mutation variables
|
||||||
self.mutation_rate = 0.05
|
self.mutation_rate = 0.10
|
||||||
|
|
||||||
# Rerun already computed fitness
|
# Rerun already computed fitness
|
||||||
self.update_fitness = True
|
self.update_fitness = True
|
||||||
@ -34,8 +34,9 @@ class GA:
|
|||||||
# Defualt EastGA implimentation structure
|
# Defualt EastGA implimentation structure
|
||||||
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().per_gene_mutation
|
||||||
self.selection_impl = Selection_Types().Tournament().with_replacement
|
self.parent_selection_impl = Selection_Types().Parent_Selection().Tournament().with_replacement
|
||||||
|
self.survivor_selection_impl = Selection_Types().Survivor_Selection().repeated_crossover
|
||||||
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
|
||||||
|
|
||||||
@ -70,7 +71,11 @@ class GA:
|
|||||||
self.initialize_population()
|
self.initialize_population()
|
||||||
self.set_all_fitness(self.population.chromosomes)
|
self.set_all_fitness(self.population.chromosomes)
|
||||||
|
|
||||||
next_population = self.selection_impl(self)
|
self.parent_selection_impl(self)
|
||||||
|
next_population = self.crossover_impl(self)
|
||||||
|
next_population = self.survivor_selection_impl(self, next_population)
|
||||||
|
next_population.set_all_chromosomes(self.mutation_impl(self, next_population.get_all_chromosomes()))
|
||||||
|
|
||||||
self.population = next_population
|
self.population = next_population
|
||||||
self.set_all_fitness(self.population.chromosomes)
|
self.set_all_fitness(self.population.chromosomes)
|
||||||
|
|
||||||
|
|||||||
@ -30,8 +30,10 @@ class Population:
|
|||||||
def set_all_chromosomes(self, chromosomes):
|
def set_all_chromosomes(self, chromosomes):
|
||||||
self.chromosomes = chromosomes
|
self.chromosomes = chromosomes
|
||||||
|
|
||||||
def set_chromosome(self, chromosomes, index):
|
def set_chromosome(self, chromosome, index = -1):
|
||||||
self.chromosome[index] = chromosome
|
if index == -1:
|
||||||
|
index = len(self.chromosomes)-1
|
||||||
|
self.chromosomes[index] = chromosome
|
||||||
|
|
||||||
def set_fitness(self, fitness):
|
def set_fitness(self, fitness):
|
||||||
self.fitness = fitness
|
self.fitness = fitness
|
||||||
|
|||||||
@ -8,7 +8,7 @@ class Mutation_Types:
|
|||||||
def random_mutation(self, ga, chromosome_set = None):
|
def random_mutation(self, ga, chromosome_set = None):
|
||||||
|
|
||||||
if chromosome_set == None:
|
if chromosome_set == None:
|
||||||
chromosome_set = ga.population
|
chromosome_set = ga.population.get_all_chromosomes()
|
||||||
|
|
||||||
chromosome_mutate_num = int(len(chromosome_set)*ga.mutation_rate)
|
chromosome_mutate_num = int(len(chromosome_set)*ga.mutation_rate)
|
||||||
temp_population = ga.initialization_impl(ga)
|
temp_population = ga.initialization_impl(ga)
|
||||||
@ -18,4 +18,25 @@ class Mutation_Types:
|
|||||||
chromosome_mutate_num -= 1
|
chromosome_mutate_num -= 1
|
||||||
|
|
||||||
return chromosome_set
|
return chromosome_set
|
||||||
|
|
||||||
|
def per_gene_mutation(self, ga, chromosome_set = None, gene_mutate_count = 1):
|
||||||
|
|
||||||
|
gene_mutate_count_static = int(gene_mutate_count)
|
||||||
|
|
||||||
|
if chromosome_set == None:
|
||||||
|
chromosome_set = ga.population.get_all_chromosomes()
|
||||||
|
|
||||||
|
for i in range(len(chromosome_set)):
|
||||||
|
random_num = random.uniform(0,1)
|
||||||
|
|
||||||
|
if (random_num <= ga.mutation_rate):
|
||||||
|
while gene_mutate_count > 0:
|
||||||
|
dummy_population = ga.initialization_impl(ga) #Really inefficient, but works for now
|
||||||
|
random_index = random.randint(0, ga.chromosome_length-1)
|
||||||
|
chromosome_set[i].get_genes()[random_index] = dummy_population.get_all_chromosomes()[random.randint(0,ga.population_size-1)].get_genes()[random_index]
|
||||||
|
gene_mutate_count -= 1
|
||||||
|
gene_mutate_count = int(gene_mutate_count_static)
|
||||||
|
|
||||||
|
return chromosome_set
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,10 @@ import random
|
|||||||
# Create the Genetic algorithm
|
# Create the Genetic algorithm
|
||||||
ga = EasyGA.GA()
|
ga = EasyGA.GA()
|
||||||
|
|
||||||
ga.gene_impl = [random.randrange,1,25]
|
#def random_parent_selection(population):
|
||||||
|
#while ()
|
||||||
|
|
||||||
|
ga.gene_impl = [random.randrange,1,100]
|
||||||
|
|
||||||
# Run Everything
|
# Run Everything
|
||||||
ga.evolve()
|
ga.evolve()
|
||||||
|
|||||||
@ -9,113 +9,67 @@ class Selection_Types:
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class Tournament:
|
class Parent_Selection:
|
||||||
def with_replacement(self, ga):
|
class Tournament:
|
||||||
tournament_size = int(len(ga.population.get_all_chromosomes())/10) #currently hard-coded for purposes of the example.
|
def with_replacement(self, ga):
|
||||||
if tournament_size < 3:
|
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())/3)
|
if tournament_size < 3:
|
||||||
|
tournament_size = int(len(ga.population.get_all_chromosomes())/3)
|
||||||
|
parent_ratio = 0.25
|
||||||
|
|
||||||
#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)
|
||||||
#3rd best is given probability of selection_probability*(1-selection_probability)**2
|
#3rd best is given probability of selection_probability*(1-selection_probability)**2
|
||||||
selection_probability = 0.95
|
selection_probability = 0.95
|
||||||
total_selected = 0 #Total Chromosomes selected
|
total_selected = 0 #Total Chromosomes selected
|
||||||
|
|
||||||
while (total_selected <= ga.population_size*2):
|
while (total_selected < parent_ratio*ga.population_size):
|
||||||
#create & gather tournament group
|
#create & gather tournament group
|
||||||
tournament_group = []
|
tournament_group = []
|
||||||
|
|
||||||
for i in range(tournament_size):
|
for i in range(tournament_size):
|
||||||
tournament_group.append(random.choice(ga.population.get_all_chromosomes()))
|
tournament_group.append(random.choice(ga.population.get_all_chromosomes()))
|
||||||
total_selected = self.selection(tournament_group, tournament_size, total_selected, selection_probability)[0]
|
|
||||||
|
#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
|
||||||
|
#also currently uses bubble sort because its easy
|
||||||
|
tournament_group_temp = tournament_group
|
||||||
|
not_sorted_check = 0
|
||||||
|
while (not_sorted_check != len(tournament_group_temp)):
|
||||||
|
not_sorted_check = 0
|
||||||
|
for i in range(len(tournament_group_temp)):
|
||||||
|
if ((i + 1 < len(tournament_group_temp)) and (tournament_group_temp[i + 1].fitness > tournament_group_temp[i].fitness)):
|
||||||
|
temp = tournament_group[i]
|
||||||
|
tournament_group_temp[i] = tournament_group[i + 1]
|
||||||
|
tournament_group_temp[i + 1] = temp
|
||||||
|
else:
|
||||||
|
not_sorted_check += 1
|
||||||
|
|
||||||
new_population = self.create_new_population(ga)
|
tournament_group = tournament_group_temp
|
||||||
return new_population
|
|
||||||
|
|
||||||
def without_replacement(self, ga):
|
#After sorting by fitness, randomly select a chromosome based on selection_probability
|
||||||
tournament_size = int(len(ga.population.get_all_chromosomes())/10) #currently hard-coded for purposes of the example.
|
selected_chromosome_tournament_index = 0
|
||||||
if tournament_size < 3:
|
for i in range(tournament_size):
|
||||||
tournament_size = int(len(ga.population.get_all_chromosomes())/3)
|
random_num = random.uniform(0,1)
|
||||||
|
|
||||||
#selection_probability is the likelihood that a chromosome will be selected.
|
#ugly implementation but its functional
|
||||||
#best chromosome in a tournament is given a selection probablity of selection_probability
|
if i == 0:
|
||||||
#2nd best is given probability of selection_probability*(1-selection_probability)
|
if random_num <= selection_probability:
|
||||||
#3rd best is given probability of selection_probability*(1-selection_probability)**2
|
tournament_group[i].selected = True
|
||||||
selection_probability = 0.95
|
total_selected += 1
|
||||||
total_selected = 0 #Total Chromosomes selected
|
selected_chromosome_tournament_index = i
|
||||||
available_chromosome_indices = []
|
break
|
||||||
for i in range(len(ga.population.get_all_chromosomes())):
|
else:
|
||||||
available_chromosome_indices.append(i)
|
if random_num <= selection_probability*((1-selection_probability)**(i-1)):
|
||||||
|
tournament_group[i].selected = True
|
||||||
|
total_selected += 1
|
||||||
|
selected_chromosome_tournament_index = i
|
||||||
|
break
|
||||||
|
|
||||||
continue_selecting = True
|
class Survivor_Selection:
|
||||||
|
def repeated_crossover(self, ga, next_population):
|
||||||
while (continue_selecting):
|
while len(next_population.chromosomes) < ga.population_size:
|
||||||
#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
|
|
||||||
#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
|
|
||||||
tournament_group_temp = tournament_group
|
|
||||||
not_sorted_check = 0
|
|
||||||
while (not_sorted_check != len(tournament_group_temp)):
|
|
||||||
not_sorted_check = 0
|
|
||||||
for i in range(len(tournament_group_temp)):
|
|
||||||
if ((i + 1 < len(tournament_group_temp)) and (tournament_group_temp[i + 1].fitness > tournament_group_temp[i].fitness)):
|
|
||||||
temp = tournament_group[i]
|
|
||||||
tournament_group_temp[i] = tournament_group[i + 1]
|
|
||||||
tournament_group_temp[i + 1] = temp
|
|
||||||
else:
|
|
||||||
not_sorted_check += 1
|
|
||||||
|
|
||||||
tournament_group = tournament_group_temp
|
|
||||||
|
|
||||||
#After sorting by fitness, randomly select a chromosome based on selection_probability
|
|
||||||
selected_chromosome_tournament_index = 0
|
|
||||||
for i in range(tournament_size):
|
|
||||||
random_num = random.uniform(0,1)
|
|
||||||
|
|
||||||
#ugly implementation but its functional
|
|
||||||
if i == 0:
|
|
||||||
if random_num <= selection_probability:
|
|
||||||
tournament_group[i].selected = True
|
|
||||||
total_selected += 1
|
|
||||||
selected_chromosome_tournament_index = i
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
if random_num <= selection_probability*((1-selection_probability)**(i-1)):
|
|
||||||
tournament_group[i].selected = True
|
|
||||||
total_selected += 1
|
|
||||||
selected_chromosome_tournament_index = i
|
|
||||||
break
|
|
||||||
|
|
||||||
return total_selected,selected_chromosome_tournament_index
|
|
||||||
|
|
||||||
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)
|
|
||||||
#Just does single-point crossover at random indices
|
|
||||||
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:
|
||||||
@ -130,19 +84,16 @@ class Selection_Types:
|
|||||||
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 = create_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])
|
next_population.add_chromosome(chromosome_list[i])
|
||||||
if len(new_population.chromosomes) >= ga.population_size:
|
if len(next_population.chromosomes) >= ga.population_size:
|
||||||
break
|
break
|
||||||
|
return next_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
|
||||||
chromosomes in the population. The stronger the fitness the higher the probability
|
chromosomes in the population. The stronger the fitness the higher the probability
|
||||||
|
|||||||
Reference in New Issue
Block a user