Cleaned up alighnment

This commit is contained in:
SimpleArt
2020-12-31 11:54:22 -05:00
parent 827d86e3b1
commit 46ef4e818d
2 changed files with 149 additions and 120 deletions

View File

@ -31,12 +31,12 @@ from fitness_examples import Fitness_Examples
from termination import Termination from termination import Termination
# Parent/Survivor Selection Methods # Parent/Survivor Selection Methods
from parent import Parent from parent import Parent
from survivor import Survivor from survivor import Survivor
# Genetic Operator Methods # Genetic Operator Methods
from crossover import Crossover from crossover import Crossover
from mutation import Mutation from mutation import Mutation
# Default Attributes for the GA # Default Attributes for the GA
from attributes import Attributes from attributes import Attributes
@ -107,7 +107,7 @@ class GA(Attributes):
if int(adapt_counter) < int(adapt_counter + self.adapt_rate): if int(adapt_counter) < int(adapt_counter + self.adapt_rate):
self.adapt() self.adapt()
number_of_generations -= 1 number_of_generations -= 1
self.current_generation += 1 self.current_generation += 1
@ -143,33 +143,39 @@ class GA(Attributes):
population gradually approaches the solution. population gradually approaches the solution.
""" """
# Determines how much to adapt by
weight = self.adapt_probability_rate
# Don't adapt # Don't adapt
if self.adapt_probability_rate is None or self.adapt_probability_rate <= 0: if weight is None or weight <= 0:
return return
# Amount of the population desired to converge (default 50%) # Amount of the population desired to converge (default 50%)
amount_converged = round(self.percent_converged*len(self.population)) amount_converged = round(self.percent_converged * len(self.population))
# Difference between best and i-th chromosomes # Difference between best and i-th chromosomes
best_chromosome = self.population[0] best_chromosome = self.population[0]
tol = lambda i: self.dist(best_chromosome, self.population[i]) tol = lambda i: self.dist(best_chromosome, self.population[i])
# Weighted averaging
average = lambda x, y: self.adapt_probability_rate * x + (1-self.adapt_probability_rate) * y
# Too few converged: cross more and mutate less # Too few converged: cross more and mutate less
if tol(amount_converged//2) > tol(amount_converged//4)*2: if tol(amount_converged//2) > tol(amount_converged//4)*2:
bounds = (self.max_selection_probability,
self.selection_probability = average(self.max_selection_probability , self.selection_probability) self.min_chromosome_mutation_rate,
self.chromosome_mutation_rate = average(self.min_chromosome_mutation_rate, self.chromosome_mutation_rate) self.min_gene_mutation_rate)
self.gene_mutation_rate = average(self.min_gene_mutation_rate , self.gene_mutation_rate)
# Too many converged: cross less and mutate more # Too many converged: cross less and mutate more
else: else:
bounds = (self.min_selection_probability,
self.max_chromosome_mutation_rate,
self.max_gene_mutation_rate)
self.selection_probability = average(self.min_selection_probability , self.selection_probability) # Weighted average of x and y
self.chromosome_mutation_rate = average(self.max_chromosome_mutation_rate, self.chromosome_mutation_rate) average = lambda x, y: weight * x + (1-weight) * y
self.gene_mutation_rate = average(self.max_gene_mutation_rate , self.gene_mutation_rate)
# Adjust rates towards the bounds
self.selection_probability = average(bounds[0], self.selection_probability)
self.chromosome_mutation_rate = average(bounds[1], self.chromosome_mutation_rate)
self.gene_mutation_rate = average(bounds[2], self.gene_mutation_rate)
def adapt_population(self): def adapt_population(self):
@ -208,7 +214,6 @@ class GA(Attributes):
# May reject negative weight or division by 0 # May reject negative weight or division by 0
try: try:
self.population[n] = self.crossover_individual_impl( self.population[n] = self.crossover_individual_impl(
self,
self.population[n], self.population[n],
best_chromosome, best_chromosome,
weight = min(0.25, 2 * tol_j / (tol(n) - tol_j)) weight = min(0.25, 2 * tol_j / (tol(n) - tol_j))
@ -218,7 +223,6 @@ class GA(Attributes):
# Cross with j-th chromosome instead # Cross with j-th chromosome instead
except: except:
self.population[n] = self.crossover_individual_impl( self.population[n] = self.crossover_individual_impl(
self,
self.population[n], self.population[n],
self.population[j], self.population[j],
weight = 0.75 weight = 0.75
@ -228,13 +232,11 @@ class GA(Attributes):
self.population[n].fitness = self.fitness_function_impl(self.population[n]) self.population[n].fitness = self.fitness_function_impl(self.population[n])
# Update best chromosome # Update best chromosome
if self.target_fitness_type == 'max': if any((all((self.target_fitness_type == 'max',
cond = (self.population[n].fitness > best_chromosome.fitness) self.population[n].fitness > best_chromosome.fitness)),
all((self.target_fitness_type == 'min',
if self.target_fitness_type == 'min': self.population[n].fitness < best_chromosome.fitness))
cond = (self.population[n].fitness < best_chromosome.fitness) )):
if cond:
tol_j = tol(j) tol_j = tol(j)
best_chromosome = self.population[n] best_chromosome = self.population[n]
@ -256,7 +258,7 @@ class GA(Attributes):
self.population = self.make_population( self.population = self.make_population(
( (
self.gene_impl() self.gene_impl()
for _ for __
in range(self.chromosome_length) in range(self.chromosome_length)
) )
for _ for _
@ -316,9 +318,7 @@ class GA(Attributes):
on the target fitness type. on the target fitness type.
""" """
return self.convert_fitness( return self.convert_fitness(self.population[index].fitness)
self.population[index].fitness
)
def convert_fitness(self, fitness_value): def convert_fitness(self, fitness_value):

View File

@ -18,12 +18,12 @@ from fitness_examples import Fitness_Examples
from termination import Termination from termination import Termination
# Parent/Survivor Selection Methods # Parent/Survivor Selection Methods
from parent import Parent from parent import Parent
from survivor import Survivor from survivor import Survivor
# Genetic Operator Methods # Genetic Operator Methods
from crossover import Crossover from crossover import Crossover
from mutation import Mutation from mutation import Mutation
# Database class # Database class
from database import sql_database from database import sql_database
@ -46,111 +46,126 @@ class Attributes:
def __init__( def __init__(
self, self,
*, *,
run = 0, # Attributes must be passed in using kwargs
chromosome_length = 10,
population_size = 10, run = 0,
chromosome_impl = None,
gene_impl = None, chromosome_length = 10,
population = None, population_size = 10,
target_fitness_type = 'max', chromosome_impl = None,
update_fitness = False, gene_impl = None,
parent_ratio = 0.10, population = None,
selection_probability = 0.50, target_fitness_type = 'max',
tournament_size_ratio = 0.10, update_fitness = False,
current_generation = 0,
current_fitness = 0, parent_ratio = 0.10,
generation_goal = 100, selection_probability = 0.50,
fitness_goal = None, tournament_size_ratio = 0.10,
tolerance_goal = None,
percent_converged = 0.50, current_generation = 0,
chromosome_mutation_rate = 0.15, current_fitness = 0,
gene_mutation_rate = 0.05,
adapt_rate = 0.05, generation_goal = 100,
adapt_probability_rate = 0.05, fitness_goal = None,
adapt_population_flag = True, tolerance_goal = None,
max_selection_probability = 0.75, percent_converged = 0.50,
min_selection_probability = 0.25,
chromosome_mutation_rate = 0.15,
gene_mutation_rate = 0.05,
adapt_rate = 0.05,
adapt_probability_rate = 0.05,
adapt_population_flag = True,
max_selection_probability = 0.75,
min_selection_probability = 0.25,
max_chromosome_mutation_rate = None, max_chromosome_mutation_rate = None,
min_chromosome_mutation_rate = None, min_chromosome_mutation_rate = None,
max_gene_mutation_rate = 0.15, max_gene_mutation_rate = 0.15,
min_gene_mutation_rate = 0.01, min_gene_mutation_rate = 0.01,
dist = None,
fitness_function_impl = None, dist = None,
make_population = make_population, fitness_function_impl = None,
make_chromosome = make_chromosome,
make_gene = make_gene, make_population = make_population,
parent_selection_impl = None, make_chromosome = make_chromosome,
crossover_individual_impl = None, make_gene = make_gene,
crossover_population_impl = None,
survivor_selection_impl = None, parent_selection_impl = None,
mutation_individual_impl = None, crossover_individual_impl = None,
mutation_population_impl = None, crossover_population_impl = None,
termination_impl = None, survivor_selection_impl = None,
Database = sql_database.SQL_Database, mutation_individual_impl = None,
database_name = 'database.db', mutation_population_impl = None,
sql_create_data_structure = """CREATE TABLE IF NOT EXISTS data (
id INTEGER PRIMARY KEY, termination_impl = None,
config_id INTEGER DEFAULT NULL,
generation INTEGER NOT NULL, Database = sql_database.SQL_Database,
fitness REAL, database_name = 'database.db',
chromosome TEXT sql_create_data_structure = """CREATE TABLE IF NOT EXISTS data (
); """, id INTEGER PRIMARY KEY,
Graph = matplotlib_graph.Matplotlib_Graph config_id INTEGER DEFAULT NULL,
generation INTEGER NOT NULL,
fitness REAL,
chromosome TEXT
); """,
Graph = matplotlib_graph.Matplotlib_Graph
): ):
# Keep track of the current run # Keep track of the current run
self.run = run self.run = run
# Initilization variables # Initilization variables
self.chromosome_length = chromosome_length self.chromosome_length = chromosome_length
self.population_size = population_size self.population_size = population_size
self.chromosome_impl = chromosome_impl self.chromosome_impl = chromosome_impl
self.gene_impl = gene_impl self.gene_impl = gene_impl
self.population = population self.population = population
self.target_fitness_type = target_fitness_type self.target_fitness_type = target_fitness_type
self.update_fitness = update_fitness self.update_fitness = update_fitness
# Selection variables # Selection variables
self.parent_ratio = parent_ratio self.parent_ratio = parent_ratio
self.selection_probability = selection_probability self.selection_probability = selection_probability
self.tournament_size_ratio = tournament_size_ratio self.tournament_size_ratio = tournament_size_ratio
# Termination variables # Termination variables
self.current_generation = current_generation self.current_generation = current_generation
self.current_fitness = current_fitness self.current_fitness = current_fitness
self.generation_goal = generation_goal self.generation_goal = generation_goal
self.fitness_goal = fitness_goal self.fitness_goal = fitness_goal
self.tolerance_goal = tolerance_goal self.tolerance_goal = tolerance_goal
self.percent_converged = percent_converged self.percent_converged = percent_converged
# Mutation variables # Mutation variables
self.chromosome_mutation_rate = chromosome_mutation_rate self.chromosome_mutation_rate = chromosome_mutation_rate
self.gene_mutation_rate = gene_mutation_rate self.gene_mutation_rate = gene_mutation_rate
# Adapt variables # Adapt variables
self.adapt_rate = adapt_rate self.adapt_rate = adapt_rate
self.adapt_probability_rate = adapt_probability_rate self.adapt_probability_rate = adapt_probability_rate
self.adapt_population_flag = adapt_population_flag self.adapt_population_flag = adapt_population_flag
# Bounds on probabilities when adapting # Bounds on probabilities when adapting
self.max_selection_probability = max_selection_probability self.max_selection_probability = max_selection_probability
self.min_selection_probability = min_selection_probability self.min_selection_probability = min_selection_probability
self.max_chromosome_mutation_rate = max_chromosome_mutation_rate self.max_chromosome_mutation_rate = max_chromosome_mutation_rate
self.min_chromosome_mutation_rate = min_chromosome_mutation_rate self.min_chromosome_mutation_rate = min_chromosome_mutation_rate
self.max_gene_mutation_rate = max_gene_mutation_rate self.max_gene_mutation_rate = max_gene_mutation_rate
self.min_gene_mutation_rate = min_gene_mutation_rate self.min_gene_mutation_rate = min_gene_mutation_rate
# Distance between two chromosomes # Distance between two chromosomes
self.dist = dist self.dist = dist
# Default EasyGA implimentation structure # Default EasyGA implimentation structure
self.fitness_function_impl = fitness_function_impl self.fitness_function_impl = fitness_function_impl
self.make_population = make_population self.make_population = make_population
self.make_chromosome = make_chromosome self.make_chromosome = make_chromosome
self.make_gene = make_gene self.make_gene = make_gene
# Methods for accomplishing Parent-Selection -> Crossover -> Survivor_Selection -> Mutation # Methods for accomplishing Parent-Selection -> Crossover -> Survivor_Selection -> Mutation
self.parent_selection_impl = parent_selection_impl self.parent_selection_impl = parent_selection_impl
self.crossover_individual_impl = crossover_individual_impl self.crossover_individual_impl = crossover_individual_impl
self.crossover_population_impl = crossover_population_impl self.crossover_population_impl = crossover_population_impl
self.survivor_selection_impl = survivor_selection_impl self.survivor_selection_impl = survivor_selection_impl
@ -360,6 +375,22 @@ class Attributes:
self._run = value self._run = value
@property
def current_generation(self):
"""Getter function for the current generation."""
return self._current_generation
@current_generation.setter
def current_generation(self, generation):
"""Setter function for the current generation."""
if not isinstance(generation, int) or generation < 0:
raise ValueError("ga.current_generation must be an integer greater than or equal to 0")
self._current_generation = generation
@property @property
def chromosome_length(self): def chromosome_length(self):
"""Getter function for chromosome length""" """Getter function for chromosome length"""
@ -367,14 +398,13 @@ class Attributes:
@chromosome_length.setter @chromosome_length.setter
def chromosome_length(self, value_input): def chromosome_length(self, length):
"""Setter function with error checking for chromosome length""" """Setter function with error checking for chromosome length"""
# If the chromosome length is less then or equal 0 throw error if(not isinstance(length, int) or length <= 0):
if(not isinstance(value_input, int) or value_input <= 0): raise ValueError("Chromosome length must be integer greater than 0")
raise ValueError("Chromosome length must be integer greater then 0")
self._chromosome_length = value_input self._chromosome_length = length
@property @property
@ -385,14 +415,13 @@ class Attributes:
@population_size.setter @population_size.setter
def population_size(self, value_input): def population_size(self, size):
"""Setter function with error checking for population size""" """Setter function with error checking for population size"""
# If the population size is less then or equal 0 throw error if(not isinstance(size, int) or size <= 0):
if(not isinstance(value_input, int) or value_input <= 0): raise ValueError("Population size must be integer greater than 0")
raise ValueError("Population length must be integer greater then 0")
self._population_size = value_input self._population_size = size
@property @property
@ -403,10 +432,10 @@ class Attributes:
@target_fitness_type.setter @target_fitness_type.setter
def target_fitness_type(self, value_input): def target_fitness_type(self, target_fitness_type):
"""Setter function for target fitness type.""" """Setter function for target fitness type."""
self._target_fitness_type = value_input self._target_fitness_type = target_fitness_type
@property @property
@ -417,16 +446,16 @@ class Attributes:
@max_chromosome_mutation_rate.setter @max_chromosome_mutation_rate.setter
def max_chromosome_mutation_rate(self, value_input): def max_chromosome_mutation_rate(self, rate):
"""Setter function with error checking and default value for max chromosome mutation rate""" """Setter function with error checking and default value for max chromosome mutation rate"""
# Default value # Default value
if value_input is None: if rate is None:
self._max_chromosome_mutation_rate = min(self.chromosome_mutation_rate*2, (1+self.chromosome_mutation_rate)/2) self._max_chromosome_mutation_rate = min(self.chromosome_mutation_rate*2, (1+self.chromosome_mutation_rate)/2)
# Otherwise check value # Otherwise check value
elif 0 <= value_input <= 1: elif 0 <= rate <= 1:
self._max_chromosome_mutation_rate = value_input self._max_chromosome_mutation_rate = rate
# Throw error # Throw error
else: else:
@ -441,16 +470,16 @@ class Attributes:
@min_chromosome_mutation_rate.setter @min_chromosome_mutation_rate.setter
def min_chromosome_mutation_rate(self, value_input): def min_chromosome_mutation_rate(self, rate):
"""Setter function with error checking and default value for min chromosome mutation rate""" """Setter function with error checking and default value for min chromosome mutation rate"""
# Default value # Default value
if value_input is None: if rate is None:
self._min_chromosome_mutation_rate = self.chromosome_mutation_rate/2 self._min_chromosome_mutation_rate = self.chromosome_mutation_rate/2
# Otherwise check value # Otherwise check value
elif 0 <= value_input <= 1: elif 0 <= rate <= 1:
self._min_chromosome_mutation_rate = value_input self._min_chromosome_mutation_rate = rate
# Throw error # Throw error
else: else: