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
# 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.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
self.survivor_selection_impl = Survivor_Selection.fill_in_best
# Methods for accomplishing parent-selection -> Crossover -> 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
self.parent_selection_impl = Parent_Selection.Tournament.with_replacement
self.crossover_individual_impl = Crossover_Methods.Individual.single_point_crossover
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
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()))
else:
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.set_all_chromosomes(self.mutation_impl(self, next_population.get_all_chromosomes()))
self.population = next_population
self.mutation_population_impl(self)
self.set_all_fitness(self.population.chromosome_list)
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):
"""Initialize the population using the initialization
implimentation that is currently set"""
implimentation that is currently set
"""
self.population = self.initialization_impl(self)
@ -132,18 +137,3 @@ class GA:
chromosome_set = chromosome_set_temp
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
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"""
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)
def sequential_selection(ga):
"""Select sequential pairs from the mating pool"""
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
"points" are created to merge the genetic makup of the chromosomes."""
pass
def random_selection(ga):
"""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

View File

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

View File

@ -7,27 +7,26 @@ 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."""
"""Takes the initialization inputs and returns a population with the given parameters."""
# Create the population object
population = create_population()
# Using the chromosome_impl to set every index inside of the chromosome
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
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.")
break
population.add_chromosome(chromosome)
return population
# Using the gene_impl to set every gene to be the same
elif ga.gene_impl != None:
function = ga.gene_impl[0]
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:
print("You did not specify any initialization constraints.")
return None

View File

@ -2,45 +2,62 @@ import random
class Mutation_Methods:
def __init__(self):
pass
class Population:
"""Methods for selecting chromosomes to mutate"""
def random_mutation(ga, chromosome_set = None):
"""Will take the input population and randomly reset entire chromosomes based on the GA's mutation rate"""
def random_selection(ga):
"""Selects random chromosomes"""
"""Defaulting to the GA's current population if no input is explicitly given"""
if chromosome_set == None:
chromosome_set = ga.population.get_all_chromosomes()
# Loop through the population
for index in range(ga.population.size()):
chromosome_mutate_num = int(len(chromosome_set)*ga.mutation_rate)
temp_population = ga.initialization_impl(ga)
# Randomly apply mutations
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):
"""Will iterate through all chromosomes, and if its selected, will randomly replace one of its genes based on initialization values"""
def whole_chromosome(ga, chromosome):
"""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:
chromosome_set = ga.population.get_all_chromosomes()
# 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())])
for i in range(len(chromosome_set)):
random_num = random.uniform(0,1)
# Exit because no gene creation method specified
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