Updated GA attribute structure, separated selection file structure

Updated GA attribute structure, separated selection file structure
This commit is contained in:
RyleyGG
2020-10-06 22:11:40 -04:00
parent 7e8c81c03d
commit 3649293133
16 changed files with 116 additions and 195 deletions

View File

@ -8,7 +8,8 @@ from fitness_function import Fitness_Examples
from initialization import Initialization_Methods
from termination_point import Termination_Methods
# Population Methods
from selection import Selection_Methods
from survivor_selection import Survivor_Selection
from parent_selection import Parent_Selection
# Manipulation Methods
from mutation import Mutation_Methods
from crossover import Crossover_Methods
@ -27,7 +28,7 @@ class GA:
# Selection variables
self.parent_ratio = 0.1
self.selection_probablity = 0.95
self.selection_probability = 0.95
# Termination variables
self.current_generation = 0
@ -41,16 +42,16 @@ class GA:
self.mutation_rate = 0.10
# Default EasyGA implimentation structure
self.initialization_impl = Initialization_Methods().random_initialization
self.fitness_function_impl = Fitness_Examples().index_dependent_values
self.initialization_impl = Initialization_Methods.random_initialization
self.fitness_function_impl = Fitness_Examples.index_dependent_values
# Selects which chromosomes should be automaticly moved to the next population
self.survivor_selection_impl = Selection_Methods().Survivor_Selection().remove_two_worst
self.survivor_selection_impl = Survivor_Selection.remove_two_worst
# Methods for accomplishing parent-selection -> Crossover -> Mutation
self.parent_selection_impl = Selection_Methods().Parent_Selection().Roulette().roulette_selection
self.crossover_impl = Crossover_Methods().single_point_crossover
self.mutation_impl = Mutation_Methods().per_gene_mutation
self.parent_selection_impl = 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
self.termination_impl = Termination_Methods.generation_based
def evolve_generation(self, number_of_generations = 1, consider_termination = True):

View File

@ -10,7 +10,7 @@ class Crossover_Methods:
def __init__(self):
pass
def single_point_crossover(self, ga):
def single_point_crossover(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"""
@ -31,7 +31,7 @@ class Crossover_Methods:
return new_population
def multi_point_crossover(self, ga,number_of_points = 2):
def multi_point_crossover(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

View File

@ -1,6 +1,6 @@
class Fitness_Examples:
"""Fitness function examples used"""
def is_it_5(self, chromosome):
def is_it_5(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
@ -15,7 +15,7 @@ class Fitness_Examples:
return fitness
def index_dependent_values(self, chromosome):
def index_dependent_values(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

View File

@ -6,7 +6,7 @@ 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):
def random_initialization(ga):
"""Takes the initialization inputs and choregraphs them to output the type of population with the given parameters."""
# Create the population object

View File

@ -1,33 +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
class Initialization_methods:
"""Initialization examples that are used as defaults and examples"""
def random_initialization(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:
# gene_impl = [range function,lowerbound,upperbound]
function = ga.gene_impl[0]
chromosome.add_gene(create_gene(function(*ga.gene_impl[1:])))
else:
#Exit because either were not specified
print("Your domain or range were not specified")
population.add_chromosome(chromosome)
return population

View File

@ -5,7 +5,7 @@ class Mutation_Methods:
def __init__(self):
pass
def random_mutation(self, ga, chromosome_set = None):
def random_mutation(ga, chromosome_set = None):
if chromosome_set == None:
chromosome_set = ga.population.get_all_chromosomes()
@ -19,7 +19,7 @@ class Mutation_Methods:
return chromosome_set
def per_gene_mutation(self, ga, chromosome_set = None, gene_mutate_count = 1):
def per_gene_mutation(ga, chromosome_set = None, gene_mutate_count = 1):
gene_mutate_count_static = int(gene_mutate_count)

View File

@ -1,2 +1,2 @@
# FROM (. means local) file_name IMPORT function_name
from .methods import Parent_methods
from .parent_selection import Parent_Selection

View File

@ -1,37 +0,0 @@
class Parent_methods:
"""Selection defintion here"""
def tournament_selection(ga,matchs):
"""Tournament selection involves running several "tournaments" among a
few individuals (or "chromosomes")chosen at random from the population.
The winner of each tournament (the one with the best fitness) is selected
for crossover.
Ex
Chromsome 1----1 wins ------
Chromsome 2---- - --1 wins----
- -
Chromsome 3----3 wins ------ -- 5 Wins --->Chromosome 5 becomes Parent
Chromsome 4---- -
-
Chromsome 5----5 wins ---------5 wins----
Chromsome 6----
^--Matchs--^
"""
def small_tournament(ga):
""" Small tournament is only one round of tournament. Beat the other
randomly selected chromosome and your are selected as a parent.
Chromosome 1----
-- 1 wins -> Becomes selected for crossover.
Chromosome 2----
"""
pass
def roulette_selection(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"""
pass

View File

@ -0,0 +1,59 @@
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 Parent_Selection:
class Tournament:
def with_replacement(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(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

View File

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

View File

@ -1,95 +0,0 @@
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

View File

@ -1,2 +1,2 @@
# FROM (. means local) file_name IMPORT function_name
from .methods import Survivor_methods
from .survivor_selection import Survivor_Selection

View File

@ -1,8 +0,0 @@
class Survivor_methods:
"""Survivor methods defintion here"""
def elitism():
pass
def remove_two_worst():
pass

View File

@ -0,0 +1,36 @@
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 Survivor_Selection:
def repeated_crossover(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(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

View File

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