Updated GA attribute structure, separated selection file structure
Updated GA attribute structure, separated selection file structure
This commit is contained in:
@ -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):
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
@ -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)
|
||||
|
||||
|
||||
@ -1,2 +1,2 @@
|
||||
# FROM (. means local) file_name IMPORT function_name
|
||||
from .methods import Parent_methods
|
||||
from .parent_selection import Parent_Selection
|
||||
|
||||
@ -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
|
||||
59
src/parent_selection/parent_selection.py
Normal file
59
src/parent_selection/parent_selection.py
Normal 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
|
||||
@ -1,2 +0,0 @@
|
||||
# FROM (. means local) file_name IMPORT function_name
|
||||
from .selection_methods import Selection_Methods
|
||||
@ -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
|
||||
@ -1,2 +1,2 @@
|
||||
# FROM (. means local) file_name IMPORT function_name
|
||||
from .methods import Survivor_methods
|
||||
from .survivor_selection import Survivor_Selection
|
||||
|
||||
@ -1,8 +0,0 @@
|
||||
class Survivor_methods:
|
||||
"""Survivor methods defintion here"""
|
||||
|
||||
def elitism():
|
||||
pass
|
||||
|
||||
def remove_two_worst():
|
||||
pass
|
||||
36
src/survivor_selection/survivor_selection.py
Normal file
36
src/survivor_selection/survivor_selection.py
Normal 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
|
||||
@ -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):
|
||||
|
||||
Reference in New Issue
Block a user