Added comments & fixed small bug

Mostly added comments, but also fixed a small bug in parent selection where the tournament size would be much smaller than it should be.
This commit is contained in:
RyleyGG
2020-10-12 09:23:41 -04:00
parent c3d9ef8bd1
commit 94d7c52666
7 changed files with 50 additions and 46 deletions

View File

@ -45,7 +45,7 @@ class GA:
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 = Survivor_Selection.remove_two_worst
self.survivor_selection_impl = Survivor_Selection.remove_worst
# Methods for accomplishing parent-selection -> Crossover -> Mutation
self.parent_selection_impl = Parent_Selection.Tournament.with_replacement
self.crossover_impl = Crossover_Methods.single_point_crossover

View File

@ -3,19 +3,13 @@ from initialization.chromosome_structure.chromosome import Chromosome
from initialization.population_structure.population import Population
class Crossover_Methods:
""" Crossover explination goes here.
Points - Defined as sections between the chromosomes genetic makeup
"""
def __init__(self):
pass
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"""
make up of the two parent chromosomes are swapped at that point"""
crossover_pool = ga.population.mating_pool
"""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):

View File

@ -16,11 +16,9 @@ class Fitness_Examples:
return fitness
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
"""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"""
fitness = 0
# For each gene in the chromosome
for i in range(len(chromosome.gene_list)):
if (chromosome.gene_list[i].value == i+1):
fitness += 1

View File

@ -6,13 +6,16 @@ class Mutation_Methods:
pass
def random_mutation(ga, chromosome_set = None):
"""Will take the input population and randomly reset entire chromosomes based on the GA's mutation rate"""
"""Defaulting to the GA's current population if no input is explicitly given"""
if chromosome_set == None:
chromosome_set = ga.population.get_all_chromosomes()
chromosome_mutate_num = int(len(chromosome_set)*ga.mutation_rate)
temp_population = ga.initialization_impl(ga)
"""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
@ -20,6 +23,7 @@ class Mutation_Methods:
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)
@ -29,10 +33,12 @@ class Mutation_Methods:
for i in range(len(chromosome_set)):
random_num = random.uniform(0,1)
"""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)

View File

@ -7,7 +7,7 @@ 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*ga.tournament_size_ratio)
tournament_size = int(len(ga.population.get_all_chromosomes())*ga.tournament_size_ratio)
if tournament_size < 5:
tournament_size = 5
# Probability used for determining if a chromosome should enter the mating pool.

View File

@ -4,7 +4,7 @@ import random
# Create the Genetic algorithm
ga = EasyGA.GA()
ga.population_size = 15
ga.population_size = 100
ga.chromosome_length = 10
ga.generation_goal = 100
ga.gene_impl = [random.randint,1,10]

View File

@ -5,7 +5,10 @@ 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
"""Survivor selection determines which individuals should be brought to the next generation"""
""" Pretty sure this isn't actually survivor selection - seems like its 'cheating'
def repeated_crossover(ga, next_population):
while len(next_population.get_all_chromosomes()) < ga.population_size:
crossover_pool = ga.population.mating_pool
@ -27,8 +30,11 @@ class Survivor_Selection:
if len(next_population.get_all_chromosomes()) >= ga.population_size:
break
return next_population
"""
def remove_two_worst(ga, next_population):
"""Will bring all but the worst-performing chromosomes from the current generation"""
"""The exact number of chromosomes removed depends on how many offspring were generated by parent selection"""
def remove_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])