Fixed method names and added some crossover methods and tests for floats
This commit is contained in:
@ -6,22 +6,23 @@ from structure import Chromosome as create_chromosome
|
|||||||
from structure import Gene as create_gene
|
from structure import Gene as create_gene
|
||||||
|
|
||||||
# Structure Methods
|
# Structure Methods
|
||||||
from fitness_function import Fitness_Examples
|
from fitness_function import Fitness_Examples
|
||||||
from initialization import Initialization_Methods
|
from initialization import Initialization_Methods
|
||||||
from termination_point import Termination_Methods
|
from termination_point import Termination_Methods
|
||||||
|
|
||||||
# Parent/Survivor Selection Methods
|
# Parent/Survivor Selection Methods
|
||||||
from parent_selection import Parent_Selection
|
from parent_selection import Parent_Selection
|
||||||
from survivor_selection import Survivor_Selection
|
from survivor_selection import Survivor_Selection
|
||||||
|
|
||||||
# Genetic Operator Methods
|
# Genetic Operator Methods
|
||||||
from mutation import Mutation_Methods
|
from mutation import Mutation_Methods
|
||||||
from crossover import Crossover_Methods
|
from crossover import Crossover_Methods
|
||||||
|
|
||||||
class GA:
|
class GA:
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
"""Initialize the GA."""
|
"""Initialize the GA."""
|
||||||
|
|
||||||
# Initilization variables
|
# Initilization variables
|
||||||
self.chromosome_length = 10
|
self.chromosome_length = 10
|
||||||
self.population_size = 10
|
self.population_size = 10
|
||||||
@ -33,7 +34,7 @@ class GA:
|
|||||||
|
|
||||||
# Selection variables
|
# Selection variables
|
||||||
self.parent_ratio = 0.1
|
self.parent_ratio = 0.1
|
||||||
self.selection_probability = 0.95
|
self.selection_probability = 0.75
|
||||||
self.tournament_size_ratio = 0.1
|
self.tournament_size_ratio = 0.1
|
||||||
|
|
||||||
# Termination variables
|
# Termination variables
|
||||||
@ -54,7 +55,7 @@ class GA:
|
|||||||
|
|
||||||
# Methods for accomplishing Parent-Selection -> Crossover -> Survivor_Selection -> Mutation
|
# Methods for accomplishing Parent-Selection -> Crossover -> Survivor_Selection -> Mutation
|
||||||
self.parent_selection_impl = Parent_Selection.Tournament.with_replacement
|
self.parent_selection_impl = Parent_Selection.Tournament.with_replacement
|
||||||
self.crossover_individual_impl = Crossover_Methods.Individual.single_point_crossover
|
self.crossover_individual_impl = Crossover_Methods.Individual.single_point
|
||||||
self.crossover_population_impl = Crossover_Methods.Population.random_selection
|
self.crossover_population_impl = Crossover_Methods.Population.random_selection
|
||||||
self.survivor_selection_impl = Survivor_Selection.fill_in_best
|
self.survivor_selection_impl = Survivor_Selection.fill_in_best
|
||||||
self.mutation_individual_impl = Mutation_Methods.Individual.single_gene
|
self.mutation_individual_impl = Mutation_Methods.Individual.single_gene
|
||||||
@ -82,7 +83,7 @@ class GA:
|
|||||||
else:
|
else:
|
||||||
self.population.reset_mating_pool()
|
self.population.reset_mating_pool()
|
||||||
self.set_all_fitness()
|
self.set_all_fitness()
|
||||||
self.population.set_all_chromosomes(self.sort_by_best_fitness(self.population.get_all_chromosomes()))
|
self.population.sort_by_best_fitness(self)
|
||||||
self.parent_selection_impl(self)
|
self.parent_selection_impl(self)
|
||||||
next_population = self.crossover_population_impl(self)
|
next_population = self.crossover_population_impl(self)
|
||||||
self.survivor_selection_impl(self, next_population)
|
self.survivor_selection_impl(self, next_population)
|
||||||
@ -119,7 +120,7 @@ class GA:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
# Check each chromosome
|
# Check each chromosome
|
||||||
for chromosome in self.population.get_all_chromosomes():
|
for chromosome in self.population.get_chromosome_list():
|
||||||
|
|
||||||
# Update fitness if needed or asked by the user
|
# Update fitness if needed or asked by the user
|
||||||
if(chromosome.get_fitness() is None or self.update_fitness):
|
if(chromosome.get_fitness() is None or self.update_fitness):
|
||||||
|
|||||||
@ -27,13 +27,56 @@ class Crossover_Methods:
|
|||||||
class Individual:
|
class Individual:
|
||||||
"""Methods for crossing parents"""
|
"""Methods for crossing parents"""
|
||||||
|
|
||||||
def single_point_crossover(ga, parent_one, parent_two):
|
def single_point(ga, parent_one, parent_two):
|
||||||
"""Cross two parents by swapping genes at one random point"""
|
"""Cross two parents by swapping genes at one random point"""
|
||||||
|
|
||||||
index = random.randint(0, parent_one.size()-1)
|
index = random.randint(0, parent_one.size()-1)
|
||||||
return ga.make_chromosome(parent_one.get_gene_list()[:index] + parent_two.get_gene_list()[index:])
|
return ga.make_chromosome(parent_one.get_gene_list()[:index] + parent_two.get_gene_list()[index:])
|
||||||
|
|
||||||
|
|
||||||
def multi_point_crossover(ga, parent_one, parent_two):
|
def multi_point(ga, parent_one, parent_two):
|
||||||
"""Cross two parents by swapping genes at multiple points"""
|
"""Cross two parents by swapping genes at multiple points"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def uniform(ga, parent_one, parent_two):
|
||||||
|
"""Cross two parents by swapping all genes randomly"""
|
||||||
|
return ga.make_chromosome([
|
||||||
|
random.choice([parent_one.get_gene(i), parent_two.get_gene(i)])
|
||||||
|
for i in range(parent_one.size())])
|
||||||
|
|
||||||
|
class Arithmetic:
|
||||||
|
"""Crossover methods for numerical genes"""
|
||||||
|
|
||||||
|
def int_random(ga, parent_one, parent_two):
|
||||||
|
"""Cross two parents by taking a random integer value between each of the genes"""
|
||||||
|
return ga.make_chromosome([
|
||||||
|
ga.make_gene(random.randint(*sorted([parent_one.get_gene(i).get_value(), parent_two.get_gene(i).get_value()])))
|
||||||
|
for i in range(parent_one.size())])
|
||||||
|
|
||||||
|
|
||||||
|
def int_weighted(ga, parent_one, parent_two):
|
||||||
|
"""Cross two parents by taking a a weighted average of the genes"""
|
||||||
|
|
||||||
|
# the percentage of genes taken from the first gene
|
||||||
|
weight = 0.25
|
||||||
|
return ga.make_chromosome([
|
||||||
|
ga.make_gene(int(weight*parent_one.get_gene(i).get_value()+(1-weight)*parent_two.get_gene(i).get_value()))
|
||||||
|
for i in range(parent_one.size())])
|
||||||
|
|
||||||
|
|
||||||
|
def float_random(ga, parent_one, parent_two):
|
||||||
|
"""Cross two parents by taking a random numeric value between each of the genes"""
|
||||||
|
return ga.make_chromosome([
|
||||||
|
ga.make_gene(random.uniform(parent_one.get_gene(i).get_value(), parent_two.get_gene(i).get_value()))
|
||||||
|
for i in range(parent_one.size())])
|
||||||
|
|
||||||
|
|
||||||
|
def float_weighted(ga, parent_one, parent_two):
|
||||||
|
"""Cross two parents by taking a a weighted average of the genes"""
|
||||||
|
|
||||||
|
# the percentage of genes taken from the first gene
|
||||||
|
weight = 0.25
|
||||||
|
return ga.make_chromosome([
|
||||||
|
ga.make_gene(weight*parent_one.get_gene(i).get_value()+(1-weight)*parent_two.get_gene(i).get_value())
|
||||||
|
for i in range(parent_one.size())])
|
||||||
|
|||||||
@ -17,6 +17,13 @@ class Fitness_Examples:
|
|||||||
return fitness
|
return fitness
|
||||||
|
|
||||||
|
|
||||||
|
def near_5(chromosome):
|
||||||
|
"""Test's the GA's ability to handle floats.
|
||||||
|
Computes how close each gene is to 5.
|
||||||
|
"""
|
||||||
|
return sum([1-pow(1-gene.get_value()/5, 2) for gene in chromosome.get_gene_list()])
|
||||||
|
|
||||||
|
|
||||||
def index_dependent_values(chromosome):
|
def index_dependent_values(chromosome):
|
||||||
"""Test of the GA's ability to improve fitness when the value is index-dependent.
|
"""Test of the GA's ability to improve fitness when the value is index-dependent.
|
||||||
If a gene is equal to its index in the chromosome + 1, fitness is incremented.
|
If a gene is equal to its index in the chromosome + 1, fitness is incremented.
|
||||||
|
|||||||
@ -3,15 +3,19 @@ import EasyGA
|
|||||||
|
|
||||||
# Create the Genetic algorithm
|
# Create the Genetic algorithm
|
||||||
ga = EasyGA.GA()
|
ga = EasyGA.GA()
|
||||||
ga.population_size = 100
|
ga.population_size = 25
|
||||||
ga.generation_goal = 200
|
ga.generation_goal = 100
|
||||||
|
ga.gene_impl = [random.randint,0,10]
|
||||||
|
ga.selection_probability = 0.5
|
||||||
|
ga.fitness_function_impl = EasyGA.Fitness_Examples.near_5
|
||||||
ga.parent_selection_impl = EasyGA.Parent_Selection.Roulette.stochastic_selection
|
ga.parent_selection_impl = EasyGA.Parent_Selection.Roulette.stochastic_selection
|
||||||
ga.crossover_population_impl = EasyGA.Crossover_Methods.Population.sequential_selection
|
ga.crossover_population_impl = EasyGA.Crossover_Methods.Population.sequential_selection
|
||||||
ga.survivor_selection_impl = EasyGA.Survivor_Selection.fill_in_parents_then_random
|
ga.crossover_individual_impl = EasyGA.Crossover_Methods.Individual.Arithmetic.int_random
|
||||||
|
ga.survivor_selection_impl = EasyGA.Survivor_Selection.fill_in_best
|
||||||
|
|
||||||
ga.evolve()
|
ga.evolve()
|
||||||
ga.set_all_fitness()
|
ga.set_all_fitness()
|
||||||
ga.population.set_all_chromosomes(ga.sort_by_best_fitness(ga.population.get_all_chromosomes()))
|
ga.population.sort_by_best_fitness(ga)
|
||||||
|
|
||||||
print(f"Current Generation: {ga.current_generation}")
|
print(f"Current Generation: {ga.current_generation}")
|
||||||
ga.population.print_all()
|
ga.population.print_all()
|
||||||
|
|||||||
@ -7,8 +7,6 @@ class Chromosome:
|
|||||||
self.gene_list = gene_list
|
self.gene_list = gene_list
|
||||||
|
|
||||||
self.fitness = None
|
self.fitness = None
|
||||||
# If the chromosome has been selected then the flag would switch to true
|
|
||||||
self.selected = False
|
|
||||||
|
|
||||||
|
|
||||||
def size(self):
|
def size(self):
|
||||||
@ -16,10 +14,10 @@ class Chromosome:
|
|||||||
return len(self.gene_list)
|
return len(self.gene_list)
|
||||||
|
|
||||||
|
|
||||||
def add_gene(self, gene, index = -1):
|
def add_gene(self, gene, index = None):
|
||||||
"""Add a gene to the chromosome at the specified index, defaulted to end of the chromosome"""
|
"""Add a gene to the chromosome at the specified index, defaulted to end of the chromosome"""
|
||||||
if index == -1:
|
if index is None:
|
||||||
index = len(self.gene_list)
|
index = self.size()
|
||||||
self.gene_list.insert(index, gene)
|
self.gene_list.insert(index, gene)
|
||||||
|
|
||||||
|
|
||||||
@ -30,7 +28,7 @@ class Chromosome:
|
|||||||
|
|
||||||
def get_gene(self, index):
|
def get_gene(self, index):
|
||||||
"""Returns the gene at the given index"""
|
"""Returns the gene at the given index"""
|
||||||
return gene_list[index]
|
return self.gene_list[index]
|
||||||
|
|
||||||
|
|
||||||
def get_gene_list(self):
|
def get_gene_list(self):
|
||||||
|
|||||||
@ -14,7 +14,7 @@ class Population:
|
|||||||
|
|
||||||
def sort_by_best_fitness(self, ga):
|
def sort_by_best_fitness(self, ga):
|
||||||
"""Sorts the population by fitness"""
|
"""Sorts the population by fitness"""
|
||||||
self.set_all_chromosomes(ga.sort_by_best_fitness(self.chromosome_list))
|
self.set_chromosome_list(ga.sort_by_best_fitness(self.chromosome_list))
|
||||||
|
|
||||||
|
|
||||||
def size(self):
|
def size(self):
|
||||||
@ -27,10 +27,10 @@ class Population:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def add_chromosome(self, chromosome, index = -1):
|
def add_chromosome(self, chromosome, index = None):
|
||||||
"""Adds a chromosome to the population at the input index, defaulted to the end of the chromosome set"""
|
"""Adds a chromosome to the population at the input index, defaulted to the end of the chromosome set"""
|
||||||
if index == -1:
|
if index is None:
|
||||||
index = len(self.chromosome_list)
|
index = self.size()
|
||||||
self.chromosome_list.insert(index, chromosome)
|
self.chromosome_list.insert(index, chromosome)
|
||||||
|
|
||||||
|
|
||||||
@ -64,7 +64,7 @@ class Population:
|
|||||||
return self.mating_pool[index]
|
return self.mating_pool[index]
|
||||||
|
|
||||||
|
|
||||||
def get_all_chromosomes(self):
|
def get_chromosome_list(self):
|
||||||
"""Returns all chromosomes in the population"""
|
"""Returns all chromosomes in the population"""
|
||||||
return self.chromosome_list
|
return self.chromosome_list
|
||||||
|
|
||||||
@ -80,11 +80,11 @@ class Population:
|
|||||||
|
|
||||||
|
|
||||||
def set_parent(self, index):
|
def set_parent(self, index):
|
||||||
"""Sets the index chromosome from the population as a parent"""
|
"""Sets the indexed chromosome from the population as a parent"""
|
||||||
self.add_parent(self.get_chromosome(index))
|
self.add_parent(self.get_chromosome(index))
|
||||||
|
|
||||||
|
|
||||||
def set_all_chromosomes(self, chromosome_list):
|
def set_chromosome_list(self, chromosome_list):
|
||||||
"""Sets the chromosome list"""
|
"""Sets the chromosome list"""
|
||||||
self.chromosome_list = chromosome_list
|
self.chromosome_list = chromosome_list
|
||||||
|
|
||||||
@ -120,5 +120,5 @@ class Population:
|
|||||||
print("Current population:")
|
print("Current population:")
|
||||||
|
|
||||||
for index in range(self.size()):
|
for index in range(self.size()):
|
||||||
print(f'Chromosome - {index} {self.chromosome_list[index]}', end = "")
|
print(f'Chromosome - {index} {self.get_chromosome(index)}', end = "")
|
||||||
print(f' / Fitness = {self.chromosome_list[index].get_fitness()}')
|
print(f' / Fitness = {self.get_chromosome(index).get_fitness()}')
|
||||||
|
|||||||
@ -6,22 +6,22 @@ class Survivor_Selection:
|
|||||||
def fill_in_best(ga, next_population):
|
def fill_in_best(ga, next_population):
|
||||||
"""Fills in the next population with the best chromosomes from the last population"""
|
"""Fills in the next population with the best chromosomes from the last population"""
|
||||||
|
|
||||||
ga.population.set_all_chromosomes(ga.population.get_all_chromosomes()[:ga.population.size()-next_population.size()] + next_population.get_all_chromosomes())
|
ga.population.set_chromosome_list(ga.population.get_chromosome_list()[:ga.population.size()-next_population.size()] + next_population.get_chromosome_list())
|
||||||
|
|
||||||
|
|
||||||
def fill_in_random(ga, next_population):
|
def fill_in_random(ga, next_population):
|
||||||
"""Fills in the next population with random chromosomes from the last population"""
|
"""Fills in the next population with random chromosomes from the last population"""
|
||||||
|
|
||||||
ga.population.set_all_chromosomes([
|
ga.population.set_chromosome_list([
|
||||||
random.choice(ga.population.get_all_chromosomes())
|
random.choice(ga.population.get_chromosome_list())
|
||||||
for n in range(ga.population.size()-next_population.size())]
|
for n in range(ga.population.size()-next_population.size())]
|
||||||
+ next_population.get_all_chromosomes())
|
+ next_population.get_chromosome_list())
|
||||||
|
|
||||||
|
|
||||||
def fill_in_parents_then_random(ga, next_population):
|
def fill_in_parents_then_random(ga, next_population):
|
||||||
"""Fills in the next population with all parents followed by random chromosomes from the last population"""
|
"""Fills in the next population with all parents followed by random chromosomes from the last population"""
|
||||||
|
|
||||||
ga.population.set_all_chromosomes([
|
ga.population.set_chromosome_list([
|
||||||
random.choice(ga.population.get_all_chromosomes())
|
random.choice(ga.population.get_chromosome_list())
|
||||||
for n in range(ga.population.size()-len(ga.population.get_mating_pool())-next_population.size())]
|
for n in range(ga.population.size()-len(ga.population.get_mating_pool())-next_population.size())]
|
||||||
+ ga.population.get_mating_pool() + next_population.get_all_chromosomes())
|
+ ga.population.get_mating_pool() + next_population.get_chromosome_list())
|
||||||
|
|||||||
Reference in New Issue
Block a user