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

@ -47,16 +47,21 @@ class GA:
self.mutation_rate = 0.10 self.mutation_rate = 0.10
# 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"""
pass
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

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

View File

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