Merge pull request #13 from danielwilczak101/ryley_beta
Selection/Crossover/Mutation Framework Update
This commit is contained in:
118
src/EasyGA.py
118
src/EasyGA.py
@ -4,71 +4,75 @@ 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_methods
|
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_methods
|
from selection import Selection_Methods
|
||||||
# Manipulation Methods
|
# Manipulation Methods
|
||||||
from parent_selection import Parent_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
|
||||||
self.chromosome_length = 3
|
self.chromosome_length = 10
|
||||||
self.population_size = 5
|
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
|
self.target_fitness_type = 'maximum'
|
||||||
|
self.update_fitness = True
|
||||||
|
|
||||||
|
# Selection variables
|
||||||
|
self.parent_ratio = 0.1
|
||||||
|
self.selection_probablity = 0.95
|
||||||
|
|
||||||
|
# Termination variables
|
||||||
self.current_generation = 0
|
self.current_generation = 0
|
||||||
self.generation_goal = 3
|
self.generation_goal = 50
|
||||||
|
|
||||||
self.current_fitness = 0
|
self.current_fitness = 0
|
||||||
self.fitness_goal = 3
|
self.generation_goal = 250
|
||||||
|
self.fitness_goal = 9
|
||||||
|
|
||||||
# Mutation variables
|
# Mutation variables
|
||||||
self.mutation_rate = 0.03
|
self.mutation_rate = 0.10
|
||||||
|
|
||||||
# Rerun already computed fitness
|
# Default EasyGA implimentation structure
|
||||||
self.update_fitness = False
|
self.initialization_impl = Initialization_Methods().random_initialization
|
||||||
|
self.fitness_function_impl = Fitness_Examples().index_dependent_values
|
||||||
# Defualt EastGA implimentation structure
|
|
||||||
self.initialization_impl = Initialization_methods.random_initialization
|
|
||||||
self.fitness_funciton_impl = Fitness_methods.is_it_5
|
|
||||||
# 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_methods.
|
self.survivor_selection_impl = Selection_Methods().Survivor_Selection().remove_two_worst
|
||||||
# Methods for accomplishing parent-selection -> Crossover -> Mutation
|
# Methods for accomplishing parent-selection -> Crossover -> Mutation
|
||||||
# self.parent_selection_impl = Parent_methods.roulette_selection
|
self.parent_selection_impl = Selection_Methods().Parent_Selection().Roulette().roulette_selection
|
||||||
#self.crossover_impl = Crossover_methods.
|
self.crossover_impl = Crossover_Methods().single_point_crossover
|
||||||
#self.mutation_impl = Mutation_methods.
|
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
|
||||||
|
|
||||||
def evolve_generation(self, number_of_generations = 1):
|
|
||||||
|
def evolve_generation(self, number_of_generations = 1, consider_termination = True):
|
||||||
"""Evolves the ga the specified number of generations."""
|
"""Evolves the ga the specified number of generations."""
|
||||||
while(number_of_generations > 0):
|
while(number_of_generations > 0 and (consider_termination == False or self.termination_impl(self))):
|
||||||
# If its the first generation then initialize the population
|
# If its the first generation then initialize the population
|
||||||
if(self.current_generation == 0):
|
if self.current_generation == 0:
|
||||||
# Initialize the population
|
|
||||||
self.initialize_population()
|
self.initialize_population()
|
||||||
# First get the fitness of the population
|
self.set_all_fitness(self.population.chromosome_list)
|
||||||
self.get_population_fitness(self.population.chromosome_list)
|
self.population.set_all_chromosomes(self.sort_by_best_fitness())
|
||||||
# Selection - Triggers flags in the chromosome if its been selected
|
else:
|
||||||
# self.selection_impl(self)
|
self.parent_selection_impl(self)
|
||||||
# Crossover - Takes the flagged chromosome_list and crosses there genetic
|
next_population = self.crossover_impl(self)
|
||||||
# makup to make new offsprings.
|
next_population = self.survivor_selection_impl(self, next_population)
|
||||||
# self.crossover_impl(self)
|
next_population.set_all_chromosomes(self.mutation_impl(self, next_population.get_all_chromosomes()))
|
||||||
# Repopulate - Manipulates the population to some desired way
|
|
||||||
# self.repopulate_impl(self)
|
self.population = next_population
|
||||||
# Mutation - Manipulates the population very slightly
|
self.set_all_fitness(self.population.chromosome_list)
|
||||||
# self.mutation_impl(self)
|
self.population.set_all_chromosomes(self.sort_by_best_fitness())
|
||||||
# self.parent_selection_impl(self)
|
|
||||||
# Counter for the local number of generations in evolve_generation
|
|
||||||
number_of_generations -= 1
|
number_of_generations -= 1
|
||||||
# Add one to the current overall generation
|
|
||||||
self.current_generation += 1
|
self.current_generation += 1
|
||||||
|
|
||||||
def evolve(self):
|
def evolve(self):
|
||||||
@ -87,18 +91,38 @@ class GA:
|
|||||||
implimentation that is currently set"""
|
implimentation that is currently set"""
|
||||||
self.population = self.initialization_impl(self)
|
self.population = self.initialization_impl(self)
|
||||||
|
|
||||||
def get_population_fitness(self,population):
|
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.
|
||||||
Otherwise only fitness values set to None (i.e. uninitialized
|
Otherwise only fitness values set to None (i.e. uninitialized
|
||||||
fitness values) are updated."""
|
fitness values) are updated."""
|
||||||
# Get each chromosome in the population
|
# Get each chromosome in the population
|
||||||
for chromosome in population:
|
|
||||||
# If the fitness is not set then get its fitness or if allways getting
|
for chromosome in chromosome_set:
|
||||||
# fitness is turn on then always get the fitness of the chromosome.
|
|
||||||
if(chromosome.fitness == None or self.update_fitness == True):
|
if(chromosome.fitness == None or self.update_fitness == True):
|
||||||
# Set the chromosomes fitness using the fitness function
|
# Set the chromosomes fitness using the fitness function
|
||||||
chromosome.fitness = self.fitness_funciton_impl(chromosome)
|
chromosome.set_fitness(self.fitness_function_impl(chromosome))
|
||||||
|
|
||||||
|
def sort_by_best_fitness(self, chromosome_set = None):
|
||||||
|
|
||||||
|
if chromosome_set == None:
|
||||||
|
chromosome_set = self.population.get_all_chromosomes()
|
||||||
|
|
||||||
|
chromosome_set_temp = chromosome_set
|
||||||
|
not_sorted_check = 0
|
||||||
|
while (not_sorted_check != len(chromosome_set_temp)):
|
||||||
|
not_sorted_check = 0
|
||||||
|
for i in range(len(chromosome_set_temp)):
|
||||||
|
if ((i + 1 < len(chromosome_set_temp)) and (chromosome_set_temp[i + 1].fitness > chromosome_set_temp[i].fitness)):
|
||||||
|
temp = chromosome_set[i]
|
||||||
|
chromosome_set_temp[i] = chromosome_set[i + 1]
|
||||||
|
chromosome_set_temp[i + 1] = temp
|
||||||
|
else:
|
||||||
|
not_sorted_check += 1
|
||||||
|
|
||||||
|
chromosome_set = chromosome_set_temp
|
||||||
|
|
||||||
|
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."""
|
||||||
|
|||||||
@ -1,2 +1,2 @@
|
|||||||
# FROM (. means local) file_name IMPORT function_name
|
# FROM (. means local) file_name IMPORT function_name
|
||||||
from .methods import Crossover_methods
|
from .crossover_methods import Crossover_Methods
|
||||||
|
|||||||
37
src/crossover/crossover_methods.py
Normal file
37
src/crossover/crossover_methods.py
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import random
|
||||||
|
from initialization.chromosome_structure.chromosome import Chromosome
|
||||||
|
from initialization.population_structure.population import Population
|
||||||
|
|
||||||
|
class Crossover_Methods:
|
||||||
|
""" Crossover explination goes here.
|
||||||
|
|
||||||
|
Points - Defined as sections between the chromosomes genetic makeup
|
||||||
|
"""
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def single_point_crossover(self, ga):
|
||||||
|
"""Single point crossover is when a "point" is selected and the genetic
|
||||||
|
make up of the two parent chromosomes are "Crossed" or better known as swapped"""
|
||||||
|
|
||||||
|
crossover_pool = ga.population.mating_pool
|
||||||
|
|
||||||
|
new_population = Population()
|
||||||
|
for i in range(len(crossover_pool)):
|
||||||
|
if i + 1 < len(crossover_pool):
|
||||||
|
new_gene_set = []
|
||||||
|
parent_one = crossover_pool[i].get_genes()
|
||||||
|
parent_two = crossover_pool[i+1].get_genes()
|
||||||
|
#halfway_point = int(ga.chromosome_length/2)
|
||||||
|
split_point = random.randint(0,ga.chromosome_length)
|
||||||
|
new_gene_set.extend(parent_one[0:split_point])
|
||||||
|
new_gene_set.extend(parent_two[split_point:])
|
||||||
|
new_chromosome = Chromosome(new_gene_set)
|
||||||
|
new_population.add_chromosome(new_chromosome)
|
||||||
|
|
||||||
|
return new_population
|
||||||
|
|
||||||
|
def multi_point_crossover(self, ga,number_of_points = 2):
|
||||||
|
"""Multi point crossover is when a specific number (More then one) of
|
||||||
|
"points" are created to merge the genetic makup of the chromosomes."""
|
||||||
|
pass
|
||||||
0
src/crossover/test_examples.py
Normal file
0
src/crossover/test_examples.py
Normal file
@ -1,2 +1,2 @@
|
|||||||
# FROM (. means local) file_name IMPORT class name
|
# FROM (. means local) file_name IMPORT class name
|
||||||
from .methods import Fitness_methods
|
from .fitness_examples import Fitness_Examples
|
||||||
|
|||||||
28
src/fitness_function/fitness_examples.py
Normal file
28
src/fitness_function/fitness_examples.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
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.gene_list:
|
||||||
|
# Check if its value = 5
|
||||||
|
if(gene.value == 5):
|
||||||
|
# If its value is 5 then add one to
|
||||||
|
# the overal fitness of the chromosome.
|
||||||
|
fitness += 1
|
||||||
|
|
||||||
|
return fitness
|
||||||
|
|
||||||
|
def index_dependent_values(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 i in range(len(chromosome.gene_list)):
|
||||||
|
if (chromosome.gene_list[i].value == i+1):
|
||||||
|
fitness += 1
|
||||||
|
|
||||||
|
return fitness
|
||||||
12
src/fitness_function/test_examples.py
Normal file
12
src/fitness_function/test_examples.py
Normal 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
|
||||||
@ -1,5 +1,3 @@
|
|||||||
# FROM (. means local) file_name IMPORT function_name
|
# FROM (. means local) file_name IMPORT function_name
|
||||||
from .methods import Initialization_methods
|
from .initialization_methods import Initialization_Methods
|
||||||
from .population_structure.population import Population
|
|
||||||
from .chromosome_structure.chromosome import Chromosome
|
|
||||||
from .gene_structure.gene import Gene
|
|
||||||
|
|||||||
@ -1,12 +1,10 @@
|
|||||||
class Chromosome:
|
class Chromosome:
|
||||||
|
|
||||||
def __init__(self, gene_list = None):
|
def __init__(self, gene_list = None):
|
||||||
"""Initialize the chromosome based on input gene list, defaulted to an empty list"""
|
|
||||||
if gene_list is None:
|
if gene_list is None:
|
||||||
self.gene_list = []
|
self.gene_list = []
|
||||||
else:
|
else:
|
||||||
self.gene_list = gene_list
|
self.gene_list = genes
|
||||||
# The fitness of the overal chromosome
|
|
||||||
self.fitness = None
|
self.fitness = None
|
||||||
# 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
|
||||||
@ -18,11 +16,9 @@ class Chromosome:
|
|||||||
self.gene_list.insert(index, gene)
|
self.gene_list.insert(index, gene)
|
||||||
|
|
||||||
def remove_gene(self, index):
|
def remove_gene(self, index):
|
||||||
"""Remove a gene from the chromosome at the specified index"""
|
|
||||||
del self.gene_list[index]
|
del self.gene_list[index]
|
||||||
|
|
||||||
def get_genes(self):
|
def get_genes(self):
|
||||||
"""Return all genes in the chromosome"""
|
|
||||||
return self.gene_list
|
return self.gene_list
|
||||||
|
|
||||||
def get_fitness(self):
|
def get_fitness(self):
|
||||||
@ -30,12 +26,10 @@ class Chromosome:
|
|||||||
return self.fitness
|
return self.fitness
|
||||||
|
|
||||||
def set_gene(self, gene, index):
|
def set_gene(self, gene, index):
|
||||||
"""Set a gene at a specific index"""
|
|
||||||
self.gene_list[index] = gene
|
self.gene_list[index] = gene
|
||||||
|
|
||||||
def set_genes(self, gene_list):
|
def set_genes(self, genes):
|
||||||
"""Set the entire gene set of the chromosome"""
|
self.gene_list = genes
|
||||||
self.gene_list = gene_list
|
|
||||||
|
|
||||||
def set_fitness(self, fitness):
|
def set_fitness(self, fitness):
|
||||||
"""Set the fitness value of the chromosome"""
|
"""Set the fitness value of the chromosome"""
|
||||||
|
|||||||
13
src/initialization/gene_creation/gene_random.py
Normal file
13
src/initialization/gene_creation/gene_random.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# 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():
|
||||||
|
return random.randint(1,100)
|
||||||
@ -22,7 +22,7 @@ class Gene:
|
|||||||
"""Set fitness of the gene"""
|
"""Set fitness of the gene"""
|
||||||
self.fitness = fitness
|
self.fitness = fitness
|
||||||
|
|
||||||
def set_value(self):
|
def set_value(self, value):
|
||||||
"""Set value of the gene"""
|
"""Set value of the gene"""
|
||||||
self.value = value
|
self.value = value
|
||||||
|
|
||||||
|
|||||||
32
src/initialization/initialization_methods.py
Normal file
32
src/initialization/initialization_methods.py
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# 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
|
||||||
|
|
||||||
|
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."""
|
||||||
|
|
||||||
|
# Create the population object
|
||||||
|
population = create_population()
|
||||||
|
|
||||||
|
# Fill the population with chromosomes
|
||||||
|
for i in range(ga.population_size):
|
||||||
|
chromosome = create_chromosome()
|
||||||
|
#Fill the Chromosome with genes
|
||||||
|
for j in range(ga.chromosome_length):
|
||||||
|
# Using the chromosome_impl to set every index inside of the chromosome
|
||||||
|
if ga.chromosome_impl != None:
|
||||||
|
# Each chromosome location is specified with its own function
|
||||||
|
chromosome.add_gene(create_gene(ga.chromosome_impl(j)))
|
||||||
|
# Will break if chromosome_length != len(lists) in domain
|
||||||
|
elif ga.gene_impl != None:
|
||||||
|
function = ga.gene_impl[0]
|
||||||
|
chromosome.add_gene(create_gene(function(*ga.gene_impl[1:])))
|
||||||
|
else:
|
||||||
|
#Exit because either were not specified
|
||||||
|
print("You did not specify any initialization constraints.")
|
||||||
|
population.add_chromosome(chromosome)
|
||||||
|
return population
|
||||||
@ -1,5 +1,4 @@
|
|||||||
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:
|
||||||
@ -7,6 +6,7 @@ class Population:
|
|||||||
else:
|
else:
|
||||||
self.chromosome_list = chromosome_list
|
self.chromosome_list = chromosome_list
|
||||||
self.fitness = None
|
self.fitness = None
|
||||||
|
self.mating_pool = []
|
||||||
|
|
||||||
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"""
|
||||||
@ -24,18 +24,18 @@ class Population:
|
|||||||
|
|
||||||
def get_all_chromosomes(self):
|
def get_all_chromosomes(self):
|
||||||
"""returns all chromosomes in the population"""
|
"""returns all chromosomes in the population"""
|
||||||
return 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, chromosome_list):
|
def set_all_chromosomes(self, chromosomes):
|
||||||
"""sets the chromosome set of the population"""
|
self.chromosome_list = chromosomes
|
||||||
self.chromosome_list = chromosome_list
|
|
||||||
|
|
||||||
def set_chromosome(self, chromosome, index):
|
def set_chromosome(self, chromosome, index = -1):
|
||||||
"""sets a specific chromosome at a specific index"""
|
if index == -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):
|
||||||
@ -43,8 +43,8 @@ class Population:
|
|||||||
self.fitness = fitness
|
self.fitness = fitness
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
"""Sets the repr() output format"""
|
for index in range(len(self.chromosomes)):
|
||||||
return ''.join([chromosome.__repr__() for chromosome in self.chromosome_list])
|
return f'{self.chromosome_list[index]}'
|
||||||
|
|
||||||
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:"""
|
||||||
|
|||||||
0
src/initialization/test_examples.py
Normal file
0
src/initialization/test_examples.py
Normal file
@ -1,2 +1,2 @@
|
|||||||
# FROM (. means local) file_name IMPORT function_name
|
# FROM (. means local) file_name IMPORT function_name
|
||||||
from .methods import Mutation_methods
|
from .mutation_methods import Mutation_Methods
|
||||||
|
|||||||
42
src/mutation/mutation_methods.py
Normal file
42
src/mutation/mutation_methods.py
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import random
|
||||||
|
|
||||||
|
class Mutation_Methods:
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def random_mutation(self, ga, chromosome_set = None):
|
||||||
|
|
||||||
|
if chromosome_set == None:
|
||||||
|
chromosome_set = ga.population.get_all_chromosomes()
|
||||||
|
|
||||||
|
chromosome_mutate_num = int(len(chromosome_set)*ga.mutation_rate)
|
||||||
|
temp_population = ga.initialization_impl(ga)
|
||||||
|
|
||||||
|
while chromosome_mutate_num > 0:
|
||||||
|
chromosome_set[random.randint(0,ga.population_size-1)] = temp_population.get_all_chromosomes()[chromosome_mutate_num]
|
||||||
|
chromosome_mutate_num -= 1
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
0
src/mutation/test_examples.py
Normal file
0
src/mutation/test_examples.py
Normal file
36
src/new_initialization_method_testing.py
Normal file
36
src/new_initialization_method_testing.py
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import EasyGA
|
||||||
|
import random
|
||||||
|
|
||||||
|
#1. GA should take in range for gene input
|
||||||
|
#2. GA should take in index-dependent range for gene input
|
||||||
|
#3. GA should take in domain input
|
||||||
|
#4. GA should take in index-dependent domain for gene input
|
||||||
|
#5. GA should accept mix of range and domain for gene input
|
||||||
|
|
||||||
|
|
||||||
|
# Create the Genetic algorithm
|
||||||
|
ga = EasyGA.GA()
|
||||||
|
|
||||||
|
test_gene_input = [["left", "right"],[1,100],[5.0,10],[22,"up"]]
|
||||||
|
ga.gene_input_type[1] = "float-range"
|
||||||
|
ga.gene_input_type[2] = "domain"
|
||||||
|
|
||||||
|
ga.initialize(test_gene_input)
|
||||||
|
ga.population.print_all()
|
||||||
|
|
||||||
|
|
||||||
|
#Example tests
|
||||||
|
#Note, the following examples assume a chromosome length of 4.
|
||||||
|
#if the test_gene_input is longer than the chromosomes, it will get truncated at the length of the chromosome
|
||||||
|
#for example, for chromosomes with length 2, [["left", "right"],[1,100],[5.0,10],[22,"up"]] becomes [["left", "right"],[1,100]]
|
||||||
|
#if the test_gene_input is shorter than the chromosomes, the remaining elements will be populated with None
|
||||||
|
|
||||||
|
#test_gene_input = [1,100]
|
||||||
|
#test_gene_input = [["left", "right"],[1,100],[5.0,10],[22,"up"]]
|
||||||
|
#test_gene_input = ["left", "right", "up", "down"]
|
||||||
|
#test_gene_input = [[1,100],[0,1],[33,35],[5,6]]
|
||||||
|
#test_gene_input = [["left", "right"], ["up", "down"], ["left", "down"], ["down", "right"]]
|
||||||
|
|
||||||
|
#ga.gene_input_type = "float-range"
|
||||||
|
#ga.gene_input_type[1] = "domain"
|
||||||
|
#ga.gene_input_type[1] = "float-range"
|
||||||
@ -1,16 +1,15 @@
|
|||||||
import EasyGA
|
import EasyGA
|
||||||
import random
|
import random
|
||||||
|
|
||||||
|
|
||||||
# Create the Genetic algorithm
|
# Create the Genetic algorithm
|
||||||
ga = EasyGA.GA()
|
ga = EasyGA.GA()
|
||||||
|
|
||||||
ga.chromosome_length = 3
|
|
||||||
ga.max_generations = 5
|
|
||||||
# If the user wants to use a domain
|
|
||||||
ga.gene_impl = [random.randrange,1,10]
|
|
||||||
|
|
||||||
ga.generation = 36
|
|
||||||
|
|
||||||
# Run Everyhting
|
ga.gene_impl = [random.randrange,1,100]
|
||||||
|
|
||||||
|
# Run Everything
|
||||||
ga.evolve()
|
ga.evolve()
|
||||||
|
|
||||||
# Print the current population
|
# Print the current population
|
||||||
|
|||||||
2
src/selection/__init__.py
Normal file
2
src/selection/__init__.py
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# FROM (. means local) file_name IMPORT function_name
|
||||||
|
from .selection_methods import Selection_Methods
|
||||||
95
src/selection/selection_methods.py
Normal file
95
src/selection/selection_methods.py
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
import random
|
||||||
|
from initialization.chromosome_structure.chromosome import Chromosome as create_chromosome
|
||||||
|
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_Methods:
|
||||||
|
"""Selection is the process by which chromosomes are selected for crossover and eventually, influence the next generation of chromosomes."""
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class Parent_Selection:
|
||||||
|
class Tournament:
|
||||||
|
def with_replacement(self, ga):
|
||||||
|
tournament_size = int(len(ga.population.get_all_chromosomes())*ga.parent_ratio/10)
|
||||||
|
if tournament_size < 3:
|
||||||
|
tournament_size = int(len(ga.population.get_all_chromosomes())*ga.parent_ratio/3)
|
||||||
|
|
||||||
|
# Probability used for determining if a chromosome should enter the mating pool.
|
||||||
|
selection_probability = ga.selection_probability
|
||||||
|
|
||||||
|
# Repeat tournaments until the mating pool is large enough.
|
||||||
|
while (len(ga.population.mating_pool) < len(ga.population.get_all_chromosomes())*ga.parent_ratio):
|
||||||
|
|
||||||
|
# Generate a random tournament group and sort by fitness.
|
||||||
|
tournament_group = ga.sort_by_best_fitness([random.choice(ga.population.get_all_chromosomes()) for n in range(tournament_size)])
|
||||||
|
|
||||||
|
# For each chromosome, add it to the mating pool based on its rank in the tournament.
|
||||||
|
for index in range(tournament_size):
|
||||||
|
# Probability required is selection_probability * (1-selection_probability) ^ (tournament_size-index+1)
|
||||||
|
# e.g. top ranked fitness has probability: selection_probability
|
||||||
|
# second ranked fitness has probability: selection_probability * (1-selection_probability)
|
||||||
|
# third ranked fitness has probability: selection_probability * (1-selection_probability)^2
|
||||||
|
# etc.
|
||||||
|
if random.uniform(0, 1) < selection_probability * pow(1-selection_probability, index+1):
|
||||||
|
ga.population.mating_pool.append(tournament_group[index])
|
||||||
|
|
||||||
|
class Roulette:
|
||||||
|
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
|
||||||
|
that it will be selected. Using the example of a casino roulette wheel.
|
||||||
|
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
|
||||||
|
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(len(ga.population.chromosome_list)))
|
||||||
|
rel_fitnesses = []
|
||||||
|
|
||||||
|
for chromosome in ga.population.chromosome_list:
|
||||||
|
if (total_fitness != 0):
|
||||||
|
rel_fitnesses.append(float(chromosome.fitness)/total_fitness)
|
||||||
|
|
||||||
|
probability = [sum(rel_fitnesses[:i+1]) for i in range(len(rel_fitnesses))]
|
||||||
|
|
||||||
|
while (len(ga.population.mating_pool) < len(ga.population.get_all_chromosomes())*ga.parent_ratio):
|
||||||
|
rand_number = random.random()
|
||||||
|
|
||||||
|
# Loop through the list of probabilities
|
||||||
|
for i in range(len(probability)):
|
||||||
|
# If the probability is greater than the random_number, then select that chromosome
|
||||||
|
if (probability[i] >= rand_number):
|
||||||
|
ga.population.mating_pool.append(ga.population.chromosome_list[i])
|
||||||
|
# print (f'Selected chromosome : {i}')
|
||||||
|
break
|
||||||
|
|
||||||
|
class Survivor_Selection:
|
||||||
|
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 = ga.population.mating_pool
|
||||||
|
|
||||||
|
split_point = random.randint(0,ga.chromosome_length)
|
||||||
|
chromosome_list = []
|
||||||
|
for i in range(len(crossover_pool)):
|
||||||
|
if i + 1 < len(crossover_pool):
|
||||||
|
new_gene_set = []
|
||||||
|
parent_one = crossover_pool[i].get_genes()
|
||||||
|
parent_two = crossover_pool[i+1].get_genes()
|
||||||
|
new_gene_set.extend(parent_one[0:split_point])
|
||||||
|
new_gene_set.extend(parent_two[split_point:])
|
||||||
|
new_chromosome = create_chromosome(new_gene_set)
|
||||||
|
chromosome_list.append(new_chromosome)
|
||||||
|
|
||||||
|
|
||||||
|
for i in range(len(chromosome_list)):
|
||||||
|
next_population.add_chromosome(chromosome_list[i])
|
||||||
|
if len(next_population.get_all_chromosomes()) >= ga.population_size:
|
||||||
|
break
|
||||||
|
return next_population
|
||||||
|
|
||||||
|
def remove_two_worst(self, ga, next_population):
|
||||||
|
iterator = 0
|
||||||
|
while len(next_population.get_all_chromosomes()) < ga.population_size:
|
||||||
|
next_population.add_chromosome(ga.population.get_all_chromosomes()[iterator])
|
||||||
|
iterator += 1
|
||||||
|
return next_population
|
||||||
0
src/selection/test_examples.py
Normal file
0
src/selection/test_examples.py
Normal file
@ -1,2 +1,2 @@
|
|||||||
# FROM (. means local) file_name IMPORT class name
|
# FROM (. means local) file_name IMPORT class name
|
||||||
from .methods import Termination_methods
|
from .termination_methods import Termination_Methods
|
||||||
|
|||||||
21
src/termination_point/termination_methods.py
Normal file
21
src/termination_point/termination_methods.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
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"""
|
||||||
|
|
||||||
|
status = True
|
||||||
|
if ga.population == None:
|
||||||
|
return status
|
||||||
|
for i in range(len(ga.population.get_all_chromosomes())):
|
||||||
|
if(ga.population.get_all_chromosomes()[i].fitness >= ga.fitness_goal):
|
||||||
|
status = False
|
||||||
|
break
|
||||||
|
return status
|
||||||
|
|
||||||
|
def generation_based(self, ga):
|
||||||
|
"""Generation based approach to terminate when the goal generation has been reached"""
|
||||||
|
status = True
|
||||||
|
if(ga.current_generation > ga.generation_goal):
|
||||||
|
status = False
|
||||||
|
return status
|
||||||
0
src/termination_point/test_examples.py
Normal file
0
src/termination_point/test_examples.py
Normal file
Reference in New Issue
Block a user