From adab92216f55464411146a876d560bd5211cde6e Mon Sep 17 00:00:00 2001 From: SimpleArt <71458112+SimpleArt@users.noreply.github.com> Date: Mon, 21 Dec 2020 09:56:56 -0500 Subject: [PATCH] Removed unnecessary code and decorator naming --- src/crossover/crossover_methods.py | 44 ++---------------- src/mutation/mutation_methods.py | 46 +++++++++---------- .../parent_selection_methods.py | 4 ++ .../survivor_selection_methods.py | 5 +- 4 files changed, 35 insertions(+), 64 deletions(-) diff --git a/src/crossover/crossover_methods.py b/src/crossover/crossover_methods.py index ba4babb..42a6744 100644 --- a/src/crossover/crossover_methods.py +++ b/src/crossover/crossover_methods.py @@ -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: diff --git a/src/mutation/mutation_methods.py b/src/mutation/mutation_methods.py index 5a5111e..45906e7 100644 --- a/src/mutation/mutation_methods.py +++ b/src/mutation/mutation_methods.py @@ -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.""" diff --git a/src/parent_selection/parent_selection_methods.py b/src/parent_selection/parent_selection_methods.py index 513a7be..287e057 100644 --- a/src/parent_selection/parent_selection_methods.py +++ b/src/parent_selection/parent_selection_methods.py @@ -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 diff --git a/src/survivor_selection/survivor_selection_methods.py b/src/survivor_selection/survivor_selection_methods.py index 2ba1972..72a3c19 100644 --- a/src/survivor_selection/survivor_selection_methods.py +++ b/src/survivor_selection/survivor_selection_methods.py @@ -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"""