Removed unnecessary code and decorator naming

This commit is contained in:
SimpleArt
2020-12-21 09:56:56 -05:00
parent c43eef38c4
commit adab92216f
4 changed files with 35 additions and 64 deletions

View File

@ -32,39 +32,11 @@ def _check_weight(individual_method):
return new_method
def _genes_to_chromosome(individual_method):
"""Converts a collection of genes into a chromosome.
Note: Will recreate the gene list if given gene list.
Built-in methods do not construct gene lists
and use yield for efficiency.
"""
return lambda ga, parent_1, parent_2, weight:\
ga.make_chromosome(
individual_method(ga, parent_1, parent_2, weight)
)
def _values_to_genes(individual_method):
"""Converts a collection of values into genes.
Returns a generator of genes to avoid storing a new list.
"""
return lambda ga, parent_1, parent_2, weight:\
(
ga.make_gene(value)
for value
in individual_method(ga, parent_1, parent_2, weight)
)
class Crossover_Methods:
# Allowing access to decorators when importing class
_append_to_next_population = _append_to_next_population
_check_weight = _check_weight
_genes_to_chromosome = _genes_to_chromosome
_values_to_genes = _values_to_genes
class Population:
@ -107,7 +79,6 @@ class Crossover_Methods:
@_check_weight
@_genes_to_chromosome
def single_point(ga, parent_1, parent_2, weight = 0.5):
"""Cross two parents by swapping genes at one random point."""
@ -134,14 +105,12 @@ class Crossover_Methods:
@_check_weight
@_genes_to_chromosome
def multi_point(ga, parent_1, parent_2, weight = 0.5):
"""Cross two parents by swapping genes at multiple points."""
pass
@_check_weight
@_genes_to_chromosome
def uniform(ga, parent_1, parent_2, weight = 0.5):
"""Cross two parents by swapping all genes randomly."""
@ -152,8 +121,6 @@ class Crossover_Methods:
class Arithmetic:
"""Crossover methods for numerical genes."""
@_genes_to_chromosome
@_values_to_genes
def average(ga, parent_1, parent_2, weight = 0.5):
"""Cross two parents by taking the average of the genes."""
@ -170,8 +137,6 @@ class Crossover_Methods:
yield value
@_genes_to_chromosome
@_values_to_genes
def extrapolate(ga, parent_1, parent_2, weight = 0.5):
"""Cross two parents by extrapolating towards the first parent.
@ -192,8 +157,6 @@ class Crossover_Methods:
@_check_weight
@_genes_to_chromosome
@_values_to_genes
def random(ga, parent_1, parent_2, weight = 0.5):
"""Cross two parents by taking a random integer or float value between each of the genes."""
@ -219,11 +182,11 @@ class Crossover_Methods:
yield value
class Permutation:
"""Crossover methods for permutation based chromosomes."""
@_check_weight
@_genes_to_chromosome
def ox1(ga, parent_1, parent_2, weight = 0.5):
"""Cross two parents by slicing out a random part of one parent
and then filling in the rest of the genes from the second parent."""
@ -269,11 +232,12 @@ class Crossover_Methods:
@_check_weight
@_genes_to_chromosome
def partially_mapped(ga, parent_1, parent_2, weight = 0.5):
"""Cross two parents by slicing out a random part of one parent
and then filling in the rest of the genes from the second parent,
preserving the ordering of genes wherever possible."""
preserving the ordering of genes wherever possible.
NOTE: Needs to be fixed."""
# Too small to cross
if len(parent_1) < 2:

View File

@ -15,6 +15,7 @@ def _check_chromosome_mutation_rate(population_method):
else:
raise ValueError("Chromosome mutation rate must be between 0 and 1.")
new_method.__name__ = population_method.__name__
return new_method
@ -26,12 +27,13 @@ def _check_gene_mutation_rate(individual_method):
if not isinstance(ga.gene_mutation_rate, float):
raise TypeError("Gene mutation rate must be a float.")
elif 0 < ga.gene_mutation_rate < 1:
elif 0 < ga.gene_mutation_rate <= 1:
individual_method(ga, index)
else:
raise ValueError("Gene mutation rate must be between 0 and 1.")
new_method.__name__ = individual_method.__name__
return new_method
@ -42,24 +44,7 @@ def _reset_fitness(individual_method):
chromosome.fitness = None
individual_method(ga, chromosome)
return new_method
def _loop_random_selections(population_method):
"""Runs the population method until enough chromosomes are mutated.
Provides the indexes of selected chromosomes to mutate using
random.sample to get all indexes fast.
"""
def new_method(ga):
sample_space = range(len(ga.population))
sample_size = ceil(len(ga.population)*ga.chromosome_mutation_rate)
# Loop the population method until enough chromosomes are mutated.
for index in random.sample(sample_space, sample_size):
population_method(ga, index)
new_method.__name__ = individual_method.__name__
return new_method
@ -78,6 +63,7 @@ def _loop_random_mutations(individual_method):
for index in random.sample(sample_space, sample_size):
individual_method(ga, chromosome, index)
new_method.__name__ = individual_method.__name__
return new_method
@ -86,7 +72,6 @@ class Mutation_Methods:
_check_chromosome_mutation_rate = _check_chromosome_mutation_rate
_check_gene_mutation_rate = _check_gene_mutation_rate
_reset_fitness = _reset_fitness
_loop_random_selections = _loop_random_selections
_loop_random_mutations = _loop_random_mutations
@ -94,11 +79,15 @@ class Mutation_Methods:
"""Methods for selecting chromosomes to mutate"""
@_check_chromosome_mutation_rate
@_loop_random_selections
def random_selection(ga, index):
def random_selection(ga):
"""Selects random chromosomes."""
ga.mutation_individual_impl(ga, ga.population[index])
sample_space = range(len(ga.population))
sample_size = ceil(len(ga.population)*ga.chromosome_mutation_rate)
# Loop the individual method until enough genes are mutated.
for index in random.sample(sample_space, sample_size):
ga.mutation_individual_impl(ga, ga.population[index])
@_check_chromosome_mutation_rate
@ -112,6 +101,17 @@ class Mutation_Methods:
ga.mutation_individual_impl(ga, ga.population[index])
@_check_chromosome_mutation_rate
def best_replace_worst(ga):
"""Selects the best chromosomes, copies them, and replaces the worst chromosomes."""
mutation_amount = ceil(ga.chromosome_mutation_rate*len(ga.population))
for i in range(mutation_amount):
ga.population[-i-1] = ga.make_chromosome(ga.population[i])
ga.mutation_individual_impl(ga, ga.population[-i-1])
class Individual:
"""Methods for mutating a single chromosome."""

View File

@ -12,6 +12,7 @@ def _check_selection_probability(selection_method):
else:
raise Exception("Selection probability must be between 0 and 1 to select parents.")
new_method.__name__ = selection_method.__name__
return new_method
@ -27,6 +28,7 @@ def _check_positive_fitness(selection_method):
else:
raise Exception("Converted fitness values can't have negative values or be all 0. Consider using rank selection or stochastic selection instead.")
new_method.__name__ = selection_method.__name__
return new_method
@ -39,6 +41,7 @@ def _ensure_sorted(selection_method):
ga.population.sort_by_best_fitness(ga)
selection_method(ga)
new_method.__name__ = selection_method.__name__
return new_method
@ -52,6 +55,7 @@ def _compute_parent_amount(selection_method):
parent_amount = max(2, round(len(ga.population)*ga.parent_ratio))
selection_method(ga, parent_amount)
new_method.__name__ = selection_method.__name__
return new_method

View File

@ -3,9 +3,12 @@ import random
def _append_to_next_population(survivor_method):
"""Appends the selected chromosomes to the next population."""
return lambda ga:\
def new_method(ga):
ga.population.append_children(survivor_method(ga))
new_method.__name__ = survivor_method.__name__
return new_method
class Survivor_Selection:
"""Survivor selection determines which individuals should be brought to the next generation"""