Updated Implementation Framework

Updated to cover changes made by Dan to Master regarding general design changes

Also added remove_two_worst survivor selection method
This commit is contained in:
RyleyGG
2020-10-05 20:46:25 -04:00
parent e05aa7f62b
commit 665062fdf1
24 changed files with 133 additions and 126 deletions

View File

@ -3,25 +3,29 @@ import random
from initialization import Population as create_population
from initialization import Chromosome as create_chromosome
from initialization import Gene as create_gene
# Import example classes
# Structure Methods
from fitness_function import Fitness_Examples
from initialization import Initialization_Types
from termination_point import Termination_Types
from selection import Selection_Types
from crossover import Crossover_Types
from mutation import Mutation_Types
from initialization import Initialization_Methods
from termination_point import Termination_Methods
# Population Methods
from selection import Selection_Methods
# Manipulation Methods
from mutation import Mutation_Methods
from crossover import Crossover_Methods
class GA:
def __init__(self):
"""Initialize the GA."""
# Initilization variables
self.chromosome_length = 10
self.population_size = 150
self.population_size = 100
self.chromosome_impl = None
self.gene_impl = None
self.population = None
# Termination varibles
self.current_generation = 0
self.generation_goal = 50
self.current_fitness = 0
self.generation_goal = 100
self.fitness_goal = 3
@ -32,13 +36,46 @@ class GA:
self.update_fitness = True
# Defualt EastGA implimentation structure
self.initialization_impl = Initialization_Types().random_initialization
self.initialization_impl = Initialization_Methods().random_initialization
self.fitness_function_impl = Fitness_Examples().is_it_5
self.mutation_impl = Mutation_Types().per_gene_mutation
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.termination_impl = Termination_Types().generation_based
# Selects which chromosomes should be automaticly moved to the next population
self.survivor_selection_impl = Selection_Methods().Survivor_Selection().remove_two_worst
# Methods for accomplishing parent-selection -> Crossover -> Mutation
self.parent_selection_impl = Selection_Methods().Parent_Selection().Tournament().with_replacement
self.crossover_impl = Crossover_Methods().single_point_crossover
self.mutation_impl = Mutation_Methods().per_gene_mutation
# The type of termination to impliment
self.termination_impl = Termination_Methods().generation_based
def evolve_generation(self, number_of_generations = 1, consider_termination = True):
"""Evolves the ga the specified number of generations."""
while(number_of_generations > 0 and (consider_termination == False or self.termination_impl(self))):
# If its the first generation then initialize the population
if self.current_generation == 0:
self.initialize_population()
self.set_all_fitness(self.population.chromosome_list)
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.set_all_fitness(self.population.chromosome_list)
number_of_generations -= 1
self.current_generation += 1
def evolve(self):
"""Runs the ga until the termination point has been satisfied."""
# While the termination point hasnt been reached keep running
while(self.active()):
self.evolve_generation()
def active(self):
"""Returns if the ga should terminate base on the termination implimented"""
# Send termination_impl the whole ga class
return self.termination_impl(self)
def initialize_population(self):
"""Initialize the population using the initialization
@ -69,7 +106,7 @@ class GA:
# If its the first generation then initialize the population
if self.current_generation == 0:
self.initialize_population()
self.set_all_fitness(self.population.chromosomes)
self.set_all_fitness(self.population.chromosome_list)
self.parent_selection_impl(self)
next_population = self.crossover_impl(self)
@ -77,7 +114,7 @@ class GA:
next_population.set_all_chromosomes(self.mutation_impl(self, next_population.get_all_chromosomes()))
self.population = next_population
self.set_all_fitness(self.population.chromosomes)
self.set_all_fitness(self.population.chromosome_list)
number_of_generations -= 1
self.current_generation += 1

View File

@ -1,2 +1,2 @@
# FROM (. means local) file_name IMPORT function_name
from .crossover_types import Crossover_Types
from .crossover_methods import Crossover_Methods

View File

@ -2,7 +2,7 @@ import random
from initialization.chromosome_structure.chromosome import Chromosome
from initialization.population_structure.population import Population
class Crossover_Types:
class Crossover_Methods:
""" Crossover explination goes here.
Points - Defined as sections between the chromosomes genetic makeup

View File

View File

@ -1,2 +1,2 @@
# FROM (. means local) file_name IMPORT class name
from .examples import Fitness_Examples
from .fitness_examples import Fitness_Examples

View File

@ -1,13 +1,12 @@
class Fitness_Examples:
"""Fitness function examples used"""
def is_it_5(self, chromosome):
"""A very simple case test function - If the chromosomes gene value is a 5 add one
to the chromosomes overall fitness value."""
# Overall fitness value
fitness = 0
# For each gene in the chromosome
for gene in chromosome.genes:
for gene in chromosome.gene_list:
# Check if its value = 5
if(gene.value == 5):
# If its value is 5 then add one to

View File

@ -0,0 +1,12 @@
class test_fitness_funciton:
def get_fitness(self, chromosome):
# For every gene in chromosome
for i in range(len(chromosome.genes)):
# If the gene has a five then add one to the fitness
# Example -> Chromosome = [5],[2],[2],[5],[5] then fitness = 3
if (chromosome.genes[i].get_value == 5):
# Add to the genes fitness
chromosome.genes[i].fitness += 1
# Add to the chromosomes fitness
chromosome.fitness += 1
return chromosome.fitness

View File

@ -1,5 +1,5 @@
# FROM (. means local) file_name IMPORT function_name
from .initialization_types import Initialization_Types
from .initialization_methods import Initialization_Methods
from .population_structure.population import Population
from .chromosome_structure.chromosome import Chromosome
from .gene_structure.gene import Gene

View File

@ -2,37 +2,37 @@ class Chromosome:
def __init__(self, genes = None):
if genes is None:
self.genes = []
self.gene_list = []
else:
self.genes = genes
self.gene_list = genes
self.fitness = None
self.selected = False
def add_gene(self, gene, index = -1):
if index == -1:
index = len(self.genes)
self.genes.insert(index, gene)
index = len(self.gene_list)
self.gene_list.insert(index, gene)
def remove_gene(self, index):
del self.genes[index]
del self.gene_list[index]
def get_genes(self):
return self.genes
return self.gene_list
def get_fitness(self):
return self.fitness
def set_gene(self, gene, index):
self.genes[index] = gene
self.gene_list[index] = gene
def set_genes(self, genes):
self.genes = genes
self.gene_list = genes
def set_fitness(self, fitness):
self.fitness = fitness
def __repr__(self):
output_str = ''
for gene in self.genes:
for gene in self.gene_list:
output_str += gene.__repr__()
return output_str

View File

@ -1,22 +0,0 @@
# Imported library
import random
def check_values(low,high):
#Check to make sure its not less then zero
assert low > 0 , "The random gene low can not be less then zero"
# Check to make sure the high value is not
# lower than or equal to low and not 0.
assert high > low, "High value can not be smaller then low value"
assert high != 0, "High value can not be zero"
def random_gene(gene_input, gene_input_type, gene_index):
created_gene = None
if gene_input_type[gene_index] == "range":
created_gene = random.randint(gene_input[gene_index][0], gene_input[gene_index][1])
elif gene_input_type[gene_index] == "domain":
created_gene = random.choice(gene_input[gene_index])
elif gene_input_type[gene_index] == "float-range":
created_gene = random.uniform(gene_input[gene_index][0], gene_input[gene_index][1])
return created_gene

View File

@ -3,12 +3,12 @@ from .population_structure.population import Population as create_population
from .chromosome_structure.chromosome import Chromosome as create_chromosome
from .gene_structure.gene import Gene as create_gene
class Initialization_Types:
class Initialization_Methods:
"""Initialization examples that are used as defaults and examples"""
def random_initialization(self, ga):
"""Takes the initialization inputs and choregraphs them to output the type of population
with the given parameters."""
"""Takes the initialization inputs and choregraphs them to output the type of population with the given parameters."""
# Create the population object
population = create_population()

View File

@ -3,9 +3,9 @@ class Population:
# fitness = Empty; population = [chromosome, chromosome, etc.]
def __init__(self, chromosomes = None):
if chromosomes is None:
self.chromosomes = []
self.chromosome_list = []
else:
self.chromosomes = chromosomes
self.chromosome_list = chromosomes
self.fitness = None
def get_closet_fitness(self,value):
@ -14,46 +14,38 @@ class Population:
def add_chromosome(self, chromosome, index = -1):
if index == -1:
index = len(self.chromosomes)
self.chromosomes.insert(index, chromosome)
index = len(self.chromosome_list)
self.chromosome_list.insert(index, chromosome)
def remove_chromosome(self, index):
del self.chromosomes[index]
del self.chromosome_list[index]
def get_all_chromosomes(self):
"""returns all chromosomes in the population"""
return self.chromosomes
return self.chromosome_list
def get_fitness(self):
return self.fitness
def set_all_chromosomes(self, chromosomes):
self.chromosomes = chromosomes
self.chromosome_list = chromosomes
def set_chromosome(self, chromosome, index = -1):
if index == -1:
index = len(self.chromosomes)-1
self.chromosomes[index] = chromosome
self.chromosome_list[index] = chromosome
def set_fitness(self, fitness):
self.fitness = fitness
def __repr__(self):
for index in range(len(self.chromosomes)):
return f'{self.chromosomes[index]}'
return f'{self.chromosome_list[index]}'
def print_all(self):
# Ex .Current population
# Chromosome 1 - [gene][gene][gene][.etc] / Chromosome fitness - #
print("Current population:")
for index in range(len(self.chromosomes)):
print(f'Chromosome - {index} {self.chromosomes[index]}', end = "")
print(f' / Fitness = {self.chromosomes[index].fitness}')
def generate_first_chromosomes(self, chromosome_count, chromosome_length, gene_lower_bound, gene_upper_bound):
#Creating the chromosomes with Genes of random size
for x in range(chromosome_count):
chromosome = Chromosome(chromosome_length)
for y in range(chromosome_length):
chromosome.gene_set[y] = Gene(random.randint(gene_lower_bound[y], gene_upper_bound[y]))
self.chromosome_set.append(chromosome)
for index in range(len(self.chromosome_list)):
print(f'Chromosome - {index} {self.chromosome_list[index]}', end = "")
print(f' / Fitness = {self.chromosome_list[index].fitness}')

View File

@ -1,31 +0,0 @@
# Import the data structure
from .population_structure.population import population as create_population
from .chromosome_structure.chromosome import chromosome as create_chromosome
from .gene_structure.gene import gene as create_gene
from .gene_function.gene_random import random_gene as random_gene
def random_initialization(chromosome_length,population_size,gene_function,gene_input,gene_input_type):
if gene_function == random_gene:
# Create the population object
population = create_population()
# Fill the population with chromosomes
for i in range(population_size):
chromosome = create_chromosome()
#Fill the Chromosome with genes
for j in range(chromosome_length):
chromosome.add_gene(create_gene(gene_function(gene_input, gene_input_type, j)))
population.add_chromosome(chromosome)
return population
else: #For user input gene-function, don't do anything with gene_input parameter
# Create the population object
population = create_population()
# Fill the population with chromosomes
for i in range(population_size):
chromosome = create_chromosome()
#Fill the Chromosome with genes
for j in range(chromosome_length):
chromosome.add_gene(create_gene(gene_function()))
population.add_chromosome(chromosome)
return population

View File

View File

@ -1,2 +1,2 @@
# FROM (. means local) file_name IMPORT function_name
from .mutation_types import Mutation_Types
from .mutation_methods import Mutation_Methods

View File

@ -1,6 +1,6 @@
import random
class Mutation_Types:
class Mutation_Methods:
def __init__(self):
pass

View File

View File

@ -5,8 +5,7 @@ import random
# Create the Genetic algorithm
ga = EasyGA.GA()
#def random_parent_selection(population):
#while ()
ga.gene_impl = [random.randrange,1,100]

View File

@ -1,2 +1,2 @@
# FROM (. means local) file_name IMPORT function_name
from .selection_types import Selection_Types
from .selection_methods import Selection_Methods

View File

@ -4,7 +4,7 @@ from initialization.gene_structure.gene import Gene as create_gene
from initialization.population_structure.population import Population
from initialization.chromosome_structure.chromosome import Chromosome
class Selection_Types:
class Selection_Methods:
"""Selection is the process by which chromosomes are selected for crossover and eventually, influence the next generation of chromosomes."""
def __init__(self):
pass
@ -68,8 +68,8 @@ class Selection_Types:
break
class Survivor_Selection:
def repeated_crossover(self, ga, next_population):
while len(next_population.chromosomes) < ga.population_size:
def repeated_crossover(self, ga, next_population): #Might be cheating? I don't know honestly - RG
while len(next_population.get_all_chromosomes()) < ga.population_size:
crossover_pool = []
for i in range(ga.population_size):
if ga.population.get_all_chromosomes()[i].selected:
@ -90,10 +90,31 @@ class Selection_Types:
for i in range(len(chromosome_list)):
next_population.add_chromosome(chromosome_list[i])
if len(next_population.chromosomes) >= ga.population_size:
if len(next_population.get_all_chromosomes()) >= ga.population_size:
break
return next_population
def remove_two_worst(self, ga, next_population):
#Bubble sorting by highest fitness
temp_population = ga.population
not_sorted_check = 0
while (not_sorted_check != len(temp_population.get_all_chromosomes())):
not_sorted_check = 0
for i in range(len(temp_population.get_all_chromosomes())):
if ((i + 1 < len(temp_population.get_all_chromosomes())) and (temp_population.get_all_chromosomes()[i + 1].fitness > temp_population.get_all_chromosomes()[i].fitness)):
temp = temp_population.get_all_chromosomes()[i]
temp_population.get_all_chromosomes()[i] = ga.population.get_all_chromosomes()[i + 1]
temp_population.get_all_chromosomes()[i + 1] = temp
else:
not_sorted_check += 1
iterator = 0
while len(next_population.get_all_chromosomes()) < ga.population_size:
next_population.add_chromosome(temp_population.get_all_chromosomes()[iterator])
iterator += 1
return next_population
def roulette_selection(self, ga):
"""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

View File

View File

@ -1,2 +1,2 @@
# FROM (. means local) file_name IMPORT class name
from .termination_types import Termination_Types
from .termination_methods import Termination_Methods

View File

@ -1,16 +1,16 @@
class Termination_Types:
class Termination_Methods:
"""Example functions that can be used to terminate the the algorithms loop"""
def fitness_based(self, ga):
"""Fitness based approach to terminate when the goal fitness has been reached"""
continue_status = True
status = True
if(ga.current_fitness > ga.fitness_goal):
continue_status = False
return continue_status
status = False
return status
def generation_based(self, ga):
"""Generation based approach to terminate when the goal generation has been reached"""
continue_status = True
if(ga.current_generation > ga.generation_goal-1):
continue_status = False
return continue_status
status = True
if(ga.current_generation > ga.generation_goal):
status = False
return status

View File