Removed unnecessary code and decorator naming
This commit is contained in:
@ -32,39 +32,11 @@ def _check_weight(individual_method):
|
|||||||
return new_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:
|
class Crossover_Methods:
|
||||||
|
|
||||||
# Allowing access to decorators when importing class
|
# Allowing access to decorators when importing class
|
||||||
_append_to_next_population = _append_to_next_population
|
_append_to_next_population = _append_to_next_population
|
||||||
_check_weight = _check_weight
|
_check_weight = _check_weight
|
||||||
_genes_to_chromosome = _genes_to_chromosome
|
|
||||||
_values_to_genes = _values_to_genes
|
|
||||||
|
|
||||||
|
|
||||||
class Population:
|
class Population:
|
||||||
@ -107,7 +79,6 @@ class Crossover_Methods:
|
|||||||
|
|
||||||
|
|
||||||
@_check_weight
|
@_check_weight
|
||||||
@_genes_to_chromosome
|
|
||||||
def single_point(ga, parent_1, parent_2, weight = 0.5):
|
def single_point(ga, parent_1, parent_2, weight = 0.5):
|
||||||
"""Cross two parents by swapping genes at one random point."""
|
"""Cross two parents by swapping genes at one random point."""
|
||||||
|
|
||||||
@ -134,14 +105,12 @@ class Crossover_Methods:
|
|||||||
|
|
||||||
|
|
||||||
@_check_weight
|
@_check_weight
|
||||||
@_genes_to_chromosome
|
|
||||||
def multi_point(ga, parent_1, parent_2, weight = 0.5):
|
def multi_point(ga, parent_1, parent_2, weight = 0.5):
|
||||||
"""Cross two parents by swapping genes at multiple points."""
|
"""Cross two parents by swapping genes at multiple points."""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@_check_weight
|
@_check_weight
|
||||||
@_genes_to_chromosome
|
|
||||||
def uniform(ga, parent_1, parent_2, weight = 0.5):
|
def uniform(ga, parent_1, parent_2, weight = 0.5):
|
||||||
"""Cross two parents by swapping all genes randomly."""
|
"""Cross two parents by swapping all genes randomly."""
|
||||||
|
|
||||||
@ -152,8 +121,6 @@ class Crossover_Methods:
|
|||||||
class Arithmetic:
|
class Arithmetic:
|
||||||
"""Crossover methods for numerical genes."""
|
"""Crossover methods for numerical genes."""
|
||||||
|
|
||||||
@_genes_to_chromosome
|
|
||||||
@_values_to_genes
|
|
||||||
def average(ga, parent_1, parent_2, weight = 0.5):
|
def average(ga, parent_1, parent_2, weight = 0.5):
|
||||||
"""Cross two parents by taking the average of the genes."""
|
"""Cross two parents by taking the average of the genes."""
|
||||||
|
|
||||||
@ -170,8 +137,6 @@ class Crossover_Methods:
|
|||||||
yield value
|
yield value
|
||||||
|
|
||||||
|
|
||||||
@_genes_to_chromosome
|
|
||||||
@_values_to_genes
|
|
||||||
def extrapolate(ga, parent_1, parent_2, weight = 0.5):
|
def extrapolate(ga, parent_1, parent_2, weight = 0.5):
|
||||||
|
|
||||||
"""Cross two parents by extrapolating towards the first parent.
|
"""Cross two parents by extrapolating towards the first parent.
|
||||||
@ -192,8 +157,6 @@ class Crossover_Methods:
|
|||||||
|
|
||||||
|
|
||||||
@_check_weight
|
@_check_weight
|
||||||
@_genes_to_chromosome
|
|
||||||
@_values_to_genes
|
|
||||||
def random(ga, parent_1, parent_2, weight = 0.5):
|
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."""
|
"""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
|
yield value
|
||||||
|
|
||||||
|
|
||||||
class Permutation:
|
class Permutation:
|
||||||
"""Crossover methods for permutation based chromosomes."""
|
"""Crossover methods for permutation based chromosomes."""
|
||||||
|
|
||||||
@_check_weight
|
@_check_weight
|
||||||
@_genes_to_chromosome
|
|
||||||
def ox1(ga, parent_1, parent_2, weight = 0.5):
|
def ox1(ga, parent_1, parent_2, weight = 0.5):
|
||||||
"""Cross two parents by slicing out a random part of one parent
|
"""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."""
|
and then filling in the rest of the genes from the second parent."""
|
||||||
@ -269,11 +232,12 @@ class Crossover_Methods:
|
|||||||
|
|
||||||
|
|
||||||
@_check_weight
|
@_check_weight
|
||||||
@_genes_to_chromosome
|
|
||||||
def partially_mapped(ga, parent_1, parent_2, weight = 0.5):
|
def partially_mapped(ga, parent_1, parent_2, weight = 0.5):
|
||||||
"""Cross two parents by slicing out a random part of one parent
|
"""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,
|
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
|
# Too small to cross
|
||||||
if len(parent_1) < 2:
|
if len(parent_1) < 2:
|
||||||
|
|||||||
@ -15,6 +15,7 @@ def _check_chromosome_mutation_rate(population_method):
|
|||||||
else:
|
else:
|
||||||
raise ValueError("Chromosome mutation rate must be between 0 and 1.")
|
raise ValueError("Chromosome mutation rate must be between 0 and 1.")
|
||||||
|
|
||||||
|
new_method.__name__ = population_method.__name__
|
||||||
return new_method
|
return new_method
|
||||||
|
|
||||||
|
|
||||||
@ -26,12 +27,13 @@ def _check_gene_mutation_rate(individual_method):
|
|||||||
if not isinstance(ga.gene_mutation_rate, float):
|
if not isinstance(ga.gene_mutation_rate, float):
|
||||||
raise TypeError("Gene mutation rate must be a 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)
|
individual_method(ga, index)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise ValueError("Gene mutation rate must be between 0 and 1.")
|
raise ValueError("Gene mutation rate must be between 0 and 1.")
|
||||||
|
|
||||||
|
new_method.__name__ = individual_method.__name__
|
||||||
return new_method
|
return new_method
|
||||||
|
|
||||||
|
|
||||||
@ -42,24 +44,7 @@ def _reset_fitness(individual_method):
|
|||||||
chromosome.fitness = None
|
chromosome.fitness = None
|
||||||
individual_method(ga, chromosome)
|
individual_method(ga, chromosome)
|
||||||
|
|
||||||
return new_method
|
new_method.__name__ = individual_method.__name__
|
||||||
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
return new_method
|
return new_method
|
||||||
|
|
||||||
|
|
||||||
@ -78,6 +63,7 @@ def _loop_random_mutations(individual_method):
|
|||||||
for index in random.sample(sample_space, sample_size):
|
for index in random.sample(sample_space, sample_size):
|
||||||
individual_method(ga, chromosome, index)
|
individual_method(ga, chromosome, index)
|
||||||
|
|
||||||
|
new_method.__name__ = individual_method.__name__
|
||||||
return new_method
|
return new_method
|
||||||
|
|
||||||
|
|
||||||
@ -86,7 +72,6 @@ class Mutation_Methods:
|
|||||||
_check_chromosome_mutation_rate = _check_chromosome_mutation_rate
|
_check_chromosome_mutation_rate = _check_chromosome_mutation_rate
|
||||||
_check_gene_mutation_rate = _check_gene_mutation_rate
|
_check_gene_mutation_rate = _check_gene_mutation_rate
|
||||||
_reset_fitness = _reset_fitness
|
_reset_fitness = _reset_fitness
|
||||||
_loop_random_selections = _loop_random_selections
|
|
||||||
_loop_random_mutations = _loop_random_mutations
|
_loop_random_mutations = _loop_random_mutations
|
||||||
|
|
||||||
|
|
||||||
@ -94,10 +79,14 @@ class Mutation_Methods:
|
|||||||
"""Methods for selecting chromosomes to mutate"""
|
"""Methods for selecting chromosomes to mutate"""
|
||||||
|
|
||||||
@_check_chromosome_mutation_rate
|
@_check_chromosome_mutation_rate
|
||||||
@_loop_random_selections
|
def random_selection(ga):
|
||||||
def random_selection(ga, index):
|
|
||||||
"""Selects random chromosomes."""
|
"""Selects random chromosomes."""
|
||||||
|
|
||||||
|
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])
|
ga.mutation_individual_impl(ga, ga.population[index])
|
||||||
|
|
||||||
|
|
||||||
@ -112,6 +101,17 @@ class Mutation_Methods:
|
|||||||
ga.mutation_individual_impl(ga, ga.population[index])
|
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:
|
class Individual:
|
||||||
"""Methods for mutating a single chromosome."""
|
"""Methods for mutating a single chromosome."""
|
||||||
|
|
||||||
|
|||||||
@ -12,6 +12,7 @@ def _check_selection_probability(selection_method):
|
|||||||
else:
|
else:
|
||||||
raise Exception("Selection probability must be between 0 and 1 to select parents.")
|
raise Exception("Selection probability must be between 0 and 1 to select parents.")
|
||||||
|
|
||||||
|
new_method.__name__ = selection_method.__name__
|
||||||
return new_method
|
return new_method
|
||||||
|
|
||||||
|
|
||||||
@ -27,6 +28,7 @@ def _check_positive_fitness(selection_method):
|
|||||||
else:
|
else:
|
||||||
raise Exception("Converted fitness values can't have negative values or be all 0. Consider using rank selection or stochastic selection instead.")
|
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
|
return new_method
|
||||||
|
|
||||||
|
|
||||||
@ -39,6 +41,7 @@ def _ensure_sorted(selection_method):
|
|||||||
ga.population.sort_by_best_fitness(ga)
|
ga.population.sort_by_best_fitness(ga)
|
||||||
selection_method(ga)
|
selection_method(ga)
|
||||||
|
|
||||||
|
new_method.__name__ = selection_method.__name__
|
||||||
return new_method
|
return new_method
|
||||||
|
|
||||||
|
|
||||||
@ -52,6 +55,7 @@ def _compute_parent_amount(selection_method):
|
|||||||
parent_amount = max(2, round(len(ga.population)*ga.parent_ratio))
|
parent_amount = max(2, round(len(ga.population)*ga.parent_ratio))
|
||||||
selection_method(ga, parent_amount)
|
selection_method(ga, parent_amount)
|
||||||
|
|
||||||
|
new_method.__name__ = selection_method.__name__
|
||||||
return new_method
|
return new_method
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -3,9 +3,12 @@ import random
|
|||||||
def _append_to_next_population(survivor_method):
|
def _append_to_next_population(survivor_method):
|
||||||
"""Appends the selected chromosomes to the next population."""
|
"""Appends the selected chromosomes to the next population."""
|
||||||
|
|
||||||
return lambda ga:\
|
def new_method(ga):
|
||||||
ga.population.append_children(survivor_method(ga))
|
ga.population.append_children(survivor_method(ga))
|
||||||
|
|
||||||
|
new_method.__name__ = survivor_method.__name__
|
||||||
|
return new_method
|
||||||
|
|
||||||
|
|
||||||
class Survivor_Selection:
|
class Survivor_Selection:
|
||||||
"""Survivor selection determines which individuals should be brought to the next generation"""
|
"""Survivor selection determines which individuals should be brought to the next generation"""
|
||||||
|
|||||||
Reference in New Issue
Block a user