Added blank lines and fixed run_testing

This commit is contained in:
SimpleArt
2020-10-12 19:57:57 -04:00
parent 4770473825
commit 3424fd4da7
9 changed files with 86 additions and 18 deletions

View File

@ -1,20 +1,25 @@
import random import random
# Import all the data structure prebuilt modules # Import all the data structure prebuilt modules
from initialization import Population as create_population from initialization import Population as create_population
from initialization import Chromosome as create_chromosome from initialization import Chromosome as create_chromosome
from initialization import Gene as create_gene from initialization import Gene as create_gene
# Structure Methods # Structure Methods
from fitness_function import Fitness_Examples from fitness_function import Fitness_Examples
from initialization import Initialization_Methods from initialization import Initialization_Methods
from termination_point import Termination_Methods from termination_point import Termination_Methods
# Population Methods # Population Methods
from survivor_selection import Survivor_Selection from survivor_selection import Survivor_Selection
from parent_selection import Parent_Selection from parent_selection import Parent_Selection
# Manipulation Methods # Manipulation Methods
from mutation import Mutation_Methods from mutation import Mutation_Methods
from crossover import Crossover_Methods from crossover import Crossover_Methods
class GA: class GA:
def __init__(self): def __init__(self):
"""Initialize the GA.""" """Initialize the GA."""
# Initilization variables # Initilization variables
@ -44,12 +49,15 @@ class GA:
# Default EasyGA implimentation structure # Default EasyGA implimentation structure
self.initialization_impl = Initialization_Methods.random_initialization self.initialization_impl = Initialization_Methods.random_initialization
self.fitness_function_impl = Fitness_Examples.index_dependent_values self.fitness_function_impl = Fitness_Examples.index_dependent_values
# Selects which chromosomes should be automaticly moved to the next population # Selects which chromosomes should be automaticly moved to the next population
self.survivor_selection_impl = Survivor_Selection.fill_in_best self.survivor_selection_impl = Survivor_Selection.fill_in_best
# Methods for accomplishing parent-selection -> Crossover -> Mutation # Methods for accomplishing parent-selection -> Crossover -> Mutation
self.parent_selection_impl = Parent_Selection.Tournament.with_replacement self.parent_selection_impl = Parent_Selection.Tournament.with_replacement
self.crossover_impl = Crossover_Methods.single_point_crossover self.crossover_impl = Crossover_Methods.single_point_crossover
self.mutation_impl = Mutation_Methods.per_gene_mutation self.mutation_impl = Mutation_Methods.per_gene_mutation
# The type of termination to impliment # The type of termination to impliment
self.termination_impl = Termination_Methods.generation_based self.termination_impl = Termination_Methods.generation_based
@ -76,22 +84,26 @@ class GA:
self.current_generation += 1 self.current_generation += 1
def evolve(self): def evolve(self):
"""Runs the ga until the termination point has been satisfied.""" """Runs the ga until the termination point has been satisfied."""
# While the termination point hasnt been reached keep running # While the termination point hasnt been reached keep running
while(self.active()): while(self.active()):
self.evolve_generation() self.evolve_generation()
def active(self): def active(self):
"""Returns if the ga should terminate base on the termination implimented""" """Returns if the ga should terminate base on the termination implimented"""
# Send termination_impl the whole ga class # Send termination_impl the whole ga class
return self.termination_impl(self) return self.termination_impl(self)
def initialize_population(self): def initialize_population(self):
"""Initialize the population using the initialization """Initialize the population using the initialization
implimentation that is currently set""" implimentation that is currently set"""
self.population = self.initialization_impl(self) self.population = self.initialization_impl(self)
def set_all_fitness(self,chromosome_set): def set_all_fitness(self,chromosome_set):
"""Will get and set the fitness of each chromosome in the population. """Will get and set the fitness of each chromosome in the population.
If update_fitness is set then all fitness values are updated. If update_fitness is set then all fitness values are updated.
@ -104,6 +116,7 @@ class GA:
# Set the chromosomes fitness using the fitness function # Set the chromosomes fitness using the fitness function
chromosome.set_fitness(self.fitness_function_impl(chromosome)) chromosome.set_fitness(self.fitness_function_impl(chromosome))
def sort_by_best_fitness(self, chromosome_set): def sort_by_best_fitness(self, chromosome_set):
chromosome_set_temp = chromosome_set chromosome_set_temp = chromosome_set
@ -120,14 +133,17 @@ class GA:
return chromosome_set return chromosome_set
def make_gene(self,value): def make_gene(self,value):
"""Let's the user create a gene.""" """Let's the user create a gene."""
return create_gene(value) return create_gene(value)
def make_chromosome(self): def make_chromosome(self):
"""Let's the user create a chromosome.""" """Let's the user create a chromosome."""
return create_chromosome() return create_chromosome()
def make_population(self): def make_population(self):
"""Let's the user create a population.""" """Let's the user create a population."""
return create_population() return create_population()

View File

@ -1,5 +1,6 @@
class Fitness_Examples: class Fitness_Examples:
"""Fitness function examples used""" """Fitness function examples used"""
def is_it_5(chromosome): def is_it_5(chromosome):
"""A very simple case test function - If the chromosomes gene value is a 5 add one """A very simple case test function - If the chromosomes gene value is a 5 add one
to the chromosomes overall fitness value.""" to the chromosomes overall fitness value."""
@ -15,6 +16,7 @@ class Fitness_Examples:
return fitness return fitness
def index_dependent_values(chromosome): def index_dependent_values(chromosome):
"""Test of the GA's ability to improve fitness when the value is index-dependent""" """Test of the GA's ability to improve fitness when the value is index-dependent"""
"""If a gene is equal to its index in the chromosome + 1, fitness is incremented""" """If a gene is equal to its index in the chromosome + 1, fitness is incremented"""

View File

@ -1,4 +1,5 @@
class Chromosome: class Chromosome:
def __init__(self, gene_list = None): def __init__(self, gene_list = None):
if gene_list is None: if gene_list is None:
self.gene_list = [] self.gene_list = []
@ -9,36 +10,45 @@ class Chromosome:
# If the chromosome has been selected then the flag would switch to true # If the chromosome has been selected then the flag would switch to true
self.selected = False self.selected = False
def size(self): def size(self):
"""Returns the number of genes in the chromosome""" """Returns the number of genes in the chromosome"""
return len(self.gene_list) return len(self.gene_list)
def add_gene(self, gene, index = -1): def add_gene(self, gene, index = -1):
"""Add a gene to the chromosome at the specified index, defaulted to end of the chromosome""" """Add a gene to the chromosome at the specified index, defaulted to end of the chromosome"""
if index == -1: if index == -1:
index = len(self.gene_list) index = len(self.gene_list)
self.gene_list.insert(index, gene) self.gene_list.insert(index, gene)
def remove_gene(self, index): def remove_gene(self, index):
del self.gene_list[index] del self.gene_list[index]
def get_genes(self): def get_genes(self):
return self.gene_list return self.gene_list
def get_fitness(self): def get_fitness(self):
"""Return the fitness of the chromosome""" """Return the fitness of the chromosome"""
return self.fitness return self.fitness
def set_gene(self, gene, index): def set_gene(self, gene, index):
self.gene_list[index] = gene self.gene_list[index] = gene
def set_genes(self, genes): def set_genes(self, genes):
self.gene_list = genes self.gene_list = genes
def set_fitness(self, fitness): def set_fitness(self, fitness):
"""Set the fitness value of the chromosome""" """Set the fitness value of the chromosome"""
self.fitness = fitness self.fitness = fitness
def __repr__(self): def __repr__(self):
"""Format the repr() output for the chromosome""" """Format the repr() output for the chromosome"""
output_str = '' output_str = ''

View File

@ -3,6 +3,7 @@ def check_gene(value):
assert value != "" , "Gene can not be empty" assert value != "" , "Gene can not be empty"
return value return value
class Gene: class Gene:
def __init__(self, value): def __init__(self, value):
@ -10,22 +11,27 @@ class Gene:
self.fitness = None self.fitness = None
self.value = check_gene(value) self.value = check_gene(value)
def get_fitness(self): def get_fitness(self):
"""Return fitness of the gene""" """Return fitness of the gene"""
return self.fitness return self.fitness
def get_value(self): def get_value(self):
"""Return value of the gene""" """Return value of the gene"""
return self.value return self.value
def set_fitness(self, fitness): def set_fitness(self, fitness):
"""Set fitness of the gene""" """Set fitness of the gene"""
self.fitness = fitness self.fitness = fitness
def set_value(self, value): def set_value(self, value):
"""Set value of the gene""" """Set value of the gene"""
self.value = value self.value = value
def __repr__(self): def __repr__(self):
"""Format the repr() output value""" """Format the repr() output value"""
return f'[{self.value}]' return f'[{self.value}]'

View File

@ -5,7 +5,7 @@ from .gene_structure.gene import Gene as create_gene
class Initialization_Methods: class Initialization_Methods:
"""Initialization examples that are used as defaults and examples""" """Initialization examples that are used as defaults and examples"""
def random_initialization(ga): def random_initialization(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."""
@ -28,5 +28,6 @@ class Initialization_Methods:
else: else:
#Exit because either were not specified #Exit because either were not specified
print("You did not specify any initialization constraints.") print("You did not specify any initialization constraints.")
break
population.add_chromosome(chromosome) population.add_chromosome(chromosome)
return population return population

View File

@ -1,60 +1,79 @@
class Population: class Population:
def __init__(self, chromosome_list = None): def __init__(self, chromosome_list = None):
"""Intiialize the population with fitness of value None, and a set of chromosomes dependant on user-passed parameter""" """Intiialize the population with fitness of value None, and a set of chromosomes dependant on user-passed parameter"""
if chromosome_list is None: if chromosome_list is None:
self.chromosome_list = [] self.chromosome_list = []
else: else:
self.chromosome_list = chromosome_list self.chromosome_list = chromosome_list
self.fitness = None self.fitness = None
self.mating_pool = [] self.mating_pool = []
def size(self): def size(self):
"""Returns the size of the population""" """Returns the size of the population"""
return len(self.chromosome_list) return len(self.chromosome_list)
def get_closet_fitness(self,value): def get_closet_fitness(self,value):
"""Get the chomosome that has the closets fitness to the value defined""" """Get the chomosome that has the closets fitness to the value defined"""
pass pass
def add_chromosome(self, chromosome, index = -1): def add_chromosome(self, chromosome, index = -1):
"""Adds a chromosome to the population at the input index, defaulted to the end of the chromosome set""" """Adds a chromosome to the population at the input index, defaulted to the end of the chromosome set"""
if index == -1: if index == -1:
index = len(self.chromosome_list) index = len(self.chromosome_list)
self.chromosome_list.insert(index, chromosome) self.chromosome_list.insert(index, chromosome)
def remove_chromosome(self, index): def remove_chromosome(self, index):
"""removes a chromosome from the indicated index""" """removes a chromosome from the indicated index"""
del self.chromosome_list[index] del self.chromosome_list[index]
def get_all_chromosomes(self): def get_all_chromosomes(self):
"""returns all chromosomes in the population""" """returns all chromosomes in the population"""
return self.chromosome_list return self.chromosome_list
def get_fitness(self): def get_fitness(self):
"""returns the population's fitness""" """returns the population's fitness"""
return self.fitness return self.fitness
def set_all_chromosomes(self, chromosomes): def set_all_chromosomes(self, chromosomes):
self.chromosome_list = chromosomes self.chromosome_list = chromosomes
def set_chromosome(self, chromosome, index = -1): def set_chromosome(self, chromosome, index = -1):
if index == -1: if index == -1:
index = len(self.chromosomes)-1 index = len(self.chromosomes)-1
self.chromosome_list[index] = chromosome self.chromosome_list[index] = chromosome
def set_fitness(self, fitness): def set_fitness(self, fitness):
"""Sets the fitness value of the population""" """Sets the fitness value of the population"""
self.fitness = fitness self.fitness = fitness
def __repr__(self): def __repr__(self):
for index in range(len(self.chromosomes)): """Returns a string representation of the entire population"""
return f'{self.chromosome_list[index]}' pass
def print_all(self): def print_all(self):
"""Prints information about the population in the following format:""" """Prints information about the population in the following format:
"""Ex .Current population""" Current population
"""Chromosome 1 - [gene][gene][gene][.etc] / Chromosome fitness - """ Chromosome 1 - [gene][gene][gene][.etc] / Chromosome fitness -
Chromosome 2 - [gene][gene][gene][.etc] / Chromosome fitness -
etc.
"""
print("Current population:") print("Current population:")
for index in range(len(self.chromosome_list)):
for index in range(self.size()):
print(f'Chromosome - {index} {self.chromosome_list[index]}', end = "") print(f'Chromosome - {index} {self.chromosome_list[index]}', end = "")
print(f' / Fitness = {self.chromosome_list[index].fitness}') print(f' / Fitness = {self.chromosome_list[index].get_fitness()}')

View File

@ -5,7 +5,9 @@ from initialization.population_structure.population import Population
from initialization.chromosome_structure.chromosome import Chromosome from initialization.chromosome_structure.chromosome import Chromosome
class Parent_Selection: class Parent_Selection:
class Tournament: class Tournament:
def with_replacement(ga): def with_replacement(ga):
""" """
Will make tournaments of size tournament_size and choose the winner (best fitness) from the tournament and use it as a parent for the next generation Will make tournaments of size tournament_size and choose the winner (best fitness) from the tournament and use it as a parent for the next generation
@ -33,7 +35,9 @@ class Parent_Selection:
if random.uniform(0, 1) < selection_probability * pow(1-selection_probability, index): if random.uniform(0, 1) < selection_probability * pow(1-selection_probability, index):
ga.population.mating_pool.append(tournament_group[index]) ga.population.mating_pool.append(tournament_group[index])
class Roulette: class Roulette:
def roulette_selection(ga): def roulette_selection(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
@ -41,22 +45,23 @@ class Parent_Selection:
Where the chromosomes are the numbers to be selected and the board size for Where the chromosomes are the numbers to be selected and the board size for
those numbers are directly proportional to the chromosome's current fitness. Where those numbers are directly proportional to the chromosome's current fitness. Where
the ball falls is a randomly generated number between 0 and 1""" the ball falls is a randomly generated number between 0 and 1"""
total_fitness = sum(ga.population.chromosome_list[i].get_fitness() for i in range(ga.population.size())) total_fitness = sum(ga.population.chromosome_list[i].get_fitness() for i in range(ga.population.size()))
rel_fitnesses = [] rel_fitnesses = []
for chromosome in ga.population.chromosome_list: for chromosome in ga.population.chromosome_list:
if (total_fitness != 0): if (total_fitness != 0):
rel_fitnesses.append(float(chromosome.fitness)/total_fitness) rel_fitnesses.append(float(chromosome.fitness)/total_fitness)
probability = [sum(rel_fitnesses[:i+1]) for i in range(len(rel_fitnesses))] probability = [sum(rel_fitnesses[:i+1]) for i in range(len(rel_fitnesses))]
while (len(ga.population.mating_pool) < ga.population.size()*ga.parent_ratio): while (len(ga.population.mating_pool) < ga.population.size()*ga.parent_ratio):
rand_number = random.random() rand_number = random.random()
# Loop through the list of probabilities # Loop through the list of probabilities
for i in range(len(probability)): for i in range(len(probability)):
# If the probability is greater than the random_number, then select that chromosome # If the probability is greater than the random_number, then select that chromosome
if (probability[i] >= rand_number): if (probability[i] >= rand_number):
ga.population.mating_pool.append(ga.population.chromosome_list[i]) ga.population.mating_pool.append(ga.population.chromosome_list[i])
# print (f'Selected chromosome : {i}') # print (f'Selected chromosome : {i}')
break break

View File

@ -1,5 +1,5 @@
import EasyGA
import random import random
import EasyGA
# Create the Genetic algorithm # Create the Genetic algorithm
ga = EasyGA.GA() ga = EasyGA.GA()
@ -8,7 +8,8 @@ ga.population_size = 100
ga.chromosome_length = 10 ga.chromosome_length = 10
ga.generation_goal = 100 ga.generation_goal = 100
ga.gene_impl = [random.randint,1,10] ga.gene_impl = [random.randint,1,10]
ga.parent_selection_impl = EasyGA.Parent_Selection.Roulette.roulette_selection
ga.evolve() ga.evolve()
ga.population.print_all() ga.population.print_all()

View File

@ -3,15 +3,23 @@ class Termination_Methods:
def fitness_based(ga): def fitness_based(ga):
"""Fitness based approach to terminate when the goal fitness has been reached""" """Fitness based approach to terminate when the goal fitness has been reached"""
# Need to start the algorithm if the population is None
if ga.population == None: if ga.population == None:
return True return True
for i in range(ga.population.size()):
if(ga.population.get_all_chromosomes()[i].fitness >= ga.fitness_goal): # Check all chromosomes
for chromosome in ga.population.get_all_chromosomes():
# Stop if a chromosome has reached the fitness_goal
if(chromosome.fitness >= ga.fitness_goal):
return False return False
# Continue if no chromosomes have reached the fitness goal
return True return True
def generation_based(ga): def generation_based(ga):
"""Generation based approach to terminate when the goal generation has been reached""" """Generation based approach to terminate when the goal generation has been reached"""
return ga.current_generation < ga.generation_goal return ga.current_generation < ga.generation_goal