Removed unnecessary code and decorator naming
This commit is contained in:
@ -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:
|
||||
|
||||
@ -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."""
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
|
||||
@ -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"""
|
||||
|
||||
Reference in New Issue
Block a user