Several Changes

Crossover/Mutation:
- Split into individual and population subclasses.
- Added sequential population crossover selection.
- Renamed and reimplemented mutation methods.

EasyGA:
- Improved make_obj methods for the chromosomes and populations to take arguments.

Initialization:
- Improved to shorter code.
- Fixed repeated error messages

Chromosome:
- Changed get/set_genes to get/set_gene_list.
This commit is contained in:
SimpleArt
2020-10-12 21:39:17 -04:00
parent 55c92d920f
commit b6ae77c7ea
5 changed files with 114 additions and 103 deletions

View File

@ -49,14 +49,19 @@ 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
self.make_population = create_population
self.make_chromosome = create_chromosome
self.make_gene = create_gene
# 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_individual_impl = Crossover_Methods.Individual.single_point_crossover
self.mutation_impl = Mutation_Methods.per_gene_mutation self.crossover_population_impl = Crossover_Methods.Population.random_selection
self.mutation_individual_impl = Mutation_Methods.Individual.single_gene
self.mutation_population_impl = Mutation_Methods.Population.random_selection
# 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
@ -72,11 +77,10 @@ class GA:
self.population.set_all_chromosomes(self.sort_by_best_fitness(self.population.get_all_chromosomes())) self.population.set_all_chromosomes(self.sort_by_best_fitness(self.population.get_all_chromosomes()))
else: else:
self.parent_selection_impl(self) self.parent_selection_impl(self)
next_population = self.crossover_impl(self) next_population = self.crossover_population_impl(self)
next_population = self.survivor_selection_impl(self, next_population) 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.population = next_population
self.mutation_population_impl(self)
self.set_all_fitness(self.population.chromosome_list) self.set_all_fitness(self.population.chromosome_list)
self.population.set_all_chromosomes(self.sort_by_best_fitness(self.population.get_all_chromosomes())) self.population.set_all_chromosomes(self.sort_by_best_fitness(self.population.get_all_chromosomes()))
@ -100,7 +104,8 @@ class GA:
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)
@ -132,18 +137,3 @@ class GA:
chromosome_set = chromosome_set_temp chromosome_set = chromosome_set_temp
return chromosome_set return chromosome_set
def make_gene(self,value):
"""Let's the user create a gene."""
return create_gene(value)
def make_chromosome(self):
"""Let's the user create a chromosome."""
return create_chromosome()
def make_population(self):
"""Let's the user create a population."""
return create_population()

View File

@ -3,29 +3,34 @@ from initialization.chromosome_structure.chromosome import Chromosome
from initialization.population_structure.population import Population from initialization.population_structure.population import Population
class Crossover_Methods: class Crossover_Methods:
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 swapped at that point"""
crossover_pool = ga.population.mating_pool class Population:
"""Methods for selecting chromosomes to crossover"""
"""The structure of GA requires that the crossover method return a population strictly with offspring chromosomes""" def sequential_selection(ga):
new_population = Population() """Select sequential pairs from the mating pool"""
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 mating_pool = ga.population.mating_pool
return Population([ga.crossover_individual_impl(mating_pool[index], mating_pool[index+1]) for index in range(len(mating_pool)-1)])
def multi_point_crossover(ga, number_of_points = 2):
"""Multi point crossover is when a specific number (More then one) of def random_selection(ga):
"points" are created to merge the genetic makup of the chromosomes.""" """Select random pairs from the mating pool"""
mating_pool = ga.population.mating_pool
return Population([ga.crossover_individual_impl(random.choice(mating_pool), random.choice(mating_pool)) for n in mating_pool])
class Individual:
"""Methods for crossing parents"""
def single_point_crossover(parent_one, parent_two):
"""Cross two parents by swapping genes at one random point"""
index = random.randint(0, parent_one.size()-1)
return Chromosome(parent_one.get_gene_list()[:index] + parent_two.get_gene_list()[index:])
def multi_point_crossover(parent_one, parent_two):
"""Cross two parents by swapping genes at multiple points"""
pass pass

View File

@ -27,7 +27,7 @@ class Chromosome:
del self.gene_list[index] del self.gene_list[index]
def get_genes(self): def get_gene_list(self):
return self.gene_list return self.gene_list
@ -40,7 +40,7 @@ class Chromosome:
self.gene_list[index] = gene self.gene_list[index] = gene
def set_genes(self, genes): def set_gene_list(self, genes):
self.gene_list = genes self.gene_list = genes

View File

@ -7,27 +7,26 @@ 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 returns a 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 # Using the chromosome_impl to set every index inside of the chromosome
if ga.chromosome_impl != None: if ga.chromosome_impl != None:
# Each chromosome location is specified with its own function return create_population([
chromosome.add_gene(create_gene(ga.chromosome_impl(j))) create_chromosome([
# Will break if chromosome_length != len(lists) in domain create_gene(ga.chromosome_impl(j))
for j in range(ga.chromosome_length)])
for i in range(ga.population_size)])
# Using the gene_impl to set every gene to be the same
elif ga.gene_impl != None: elif ga.gene_impl != None:
function = ga.gene_impl[0] function = ga.gene_impl[0]
chromosome.add_gene(create_gene(function(*ga.gene_impl[1:]))) return create_population([
create_chromosome([
create_gene(function(*ga.gene_impl[1:]))
for j in range(ga.chromosome_length)])
for i in range(ga.population_size)])
# Exit because no gene creation method specified
else: else:
#Exit because either were not specified
print("You did not specify any initialization constraints.") print("You did not specify any initialization constraints.")
break return None
population.add_chromosome(chromosome)
return population

View File

@ -2,45 +2,62 @@ import random
class Mutation_Methods: class Mutation_Methods:
def __init__(self): class Population:
pass """Methods for selecting chromosomes to mutate"""
def random_mutation(ga, chromosome_set = None): def random_selection(ga):
"""Will take the input population and randomly reset entire chromosomes based on the GA's mutation rate""" """Selects random chromosomes"""
"""Defaulting to the GA's current population if no input is explicitly given""" # Loop through the population
if chromosome_set == None: for index in range(ga.population.size()):
chromosome_set = ga.population.get_all_chromosomes()
chromosome_mutate_num = int(len(chromosome_set)*ga.mutation_rate) # Randomly apply mutations
temp_population = ga.initialization_impl(ga) if random.uniform(0, 1) < ga.mutation_rate:
ga.population.set_chromosome(ga.mutation_individual_impl(ga, ga.population.get_all_chromosomes()[index]), index)
"""While more chromosomes need to be mutated, grab a random chromosome and re-initialize it entirely"""
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 class Individual:
"""Methods for mutating a single chromosome"""
def per_gene_mutation(ga, chromosome_set = None, gene_mutate_count = 1): def whole_chromosome(ga, chromosome):
"""Will iterate through all chromosomes, and if its selected, will randomly replace one of its genes based on initialization values""" """Makes a completely random chromosome"""
gene_mutate_count_static = int(gene_mutate_count) # Using the chromosome_impl to set every index inside of the chromosome
if ga.chromosome_impl != None:
return ga.make_chromosome([
ga.make_gene(ga.chromosome_impl(j))
for j in range(chromosome.size())])
if chromosome_set == None: # Using the gene_impl
chromosome_set = ga.population.get_all_chromosomes() elif ga.gene_impl != None:
function = ga.gene_impl[0]
return ga.make_chromosome([
ga.make_gene(function(*ga.gene_impl[1:]))
for j in range(chromosome.size())])
for i in range(len(chromosome_set)): # Exit because no gene creation method specified
random_num = random.uniform(0,1) else:
print("You did not specify any initialization constraints.")
return None
"""If a chromosome was selected to be mutated"""
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)
"""Replaces a random gene in the actual chromosome with a gene from a newly initialized chromosome"""
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 def single_gene(ga, chromosome):
"""Makes a completely random chromosome"""
chromosome.set_fitness(None)
# Using the chromosome_impl
if ga.chromosome_impl != None:
index = random.randint(0, chromosome.size()-1)
chromosome.set_gene(ga.make_gene(ga.chromosome_impl(index)), index)
# Using the gene_impl
elif ga.gene_impl != None:
function = ga.gene_impl[0]
index = random.randint(0, chromosome.size()-1)
chromosome.set_gene(ga.make_gene(function(*ga.gene_impl[1:])), index)
# Exit because no gene creation method specified
else:
print("You did not specify any initialization constraints.")
return chromosome