Comments updated
This commit is contained in:
@ -47,7 +47,11 @@ class GA(Attributes):
|
||||
|
||||
while cond1() and cond3():
|
||||
|
||||
# If its the first generation
|
||||
# Create the initial population if necessary.
|
||||
if self.population is None:
|
||||
self.initialize_population()
|
||||
|
||||
# If its the first generation, setup the database.
|
||||
if self.current_generation == 0:
|
||||
|
||||
# Create the database here to allow the user to change the
|
||||
@ -57,11 +61,7 @@ class GA(Attributes):
|
||||
# Add the current configuration to the config table
|
||||
self.database.insert_config(self)
|
||||
|
||||
# Create the initial population
|
||||
if self.population is None:
|
||||
self.initialize_population()
|
||||
|
||||
# Otherwise evolve the population
|
||||
# Otherwise evolve the population.
|
||||
else:
|
||||
self.parent_selection_impl(self)
|
||||
self.crossover_population_impl(self)
|
||||
@ -107,7 +107,7 @@ class GA(Attributes):
|
||||
"""
|
||||
|
||||
# Check each chromosome
|
||||
for chromosome in self.population.get_chromosome_list():
|
||||
for chromosome in self.population:
|
||||
|
||||
# Update fitness if needed or asked by the user
|
||||
if chromosome.fitness is None or self.update_fitness:
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import random
|
||||
|
||||
def append_children_from_mating_pool(crossover_method):
|
||||
"""Appends the new chromosomes to the next population."""
|
||||
return lambda ga:\
|
||||
ga.population.append_children(
|
||||
[chromosome for chromosome in crossover_method(ga, ga.population.mating_pool)]
|
||||
@ -8,17 +9,20 @@ def append_children_from_mating_pool(crossover_method):
|
||||
|
||||
|
||||
def genes_to_chromosome(crossover_method):
|
||||
"""Converts a collection of genes into a chromosome."""
|
||||
return lambda ga, parent_1, parent_2:\
|
||||
return ga.make_chromosome(crossover_method(ga, parent_1, parent_2))
|
||||
|
||||
|
||||
def values_to_genes(crossover_method):
|
||||
"""Converts a collection of values into genes."""
|
||||
return lambda ga, parent_1, parent_2:\
|
||||
return (ga.make_gene(value) for value in crossover_method(ga, parent_1, parent_2))
|
||||
|
||||
|
||||
class Crossover_Methods:
|
||||
|
||||
# Private method decorators, see above.
|
||||
def __append_children_from_mating_pool(crossover_method):
|
||||
return append_children_from_mating_pool(crossover_method)
|
||||
def __genes_to_chromosome(crossover_method):
|
||||
|
||||
@ -1,16 +1,20 @@
|
||||
def chromosomes_to_population(initialize):
|
||||
"""Makes a population from chromosomes."""
|
||||
return lambda ga: ga.make_population([initialize(ga) for _ in range(ga.population_size)])
|
||||
|
||||
def genes_to_chromosome(initialize):
|
||||
"""Converts a collection of genes to a chromosome."""
|
||||
return lambda ga: ga.make_chromosome([genes for genes in initialize(ga)])
|
||||
|
||||
def value_to_gene(initialize):
|
||||
"""Converts a collection of values to genes."""
|
||||
return lambda ga: (ga.make_gene(value) for value in initialize(ga))
|
||||
|
||||
|
||||
class Initialization_Methods:
|
||||
"""Initialization examples that are used as defaults and examples"""
|
||||
|
||||
# Private method decorators, see above.
|
||||
def __chromosomes_to_population(initialize):
|
||||
return chromosomes_to_population(initialize)
|
||||
def __genes_to_chromosome(initialize):
|
||||
@ -23,10 +27,8 @@ class Initialization_Methods:
|
||||
@genes_to_chromosome
|
||||
@value_to_gene
|
||||
def random_initialization(ga):
|
||||
"""Takes the initialization inputs and
|
||||
- return a new population
|
||||
- filled with chromosomes
|
||||
- filled with genes
|
||||
"""Takes the initialization inputs and returns a collection of values.
|
||||
Method decorators convert them to a GA population object.
|
||||
"""
|
||||
|
||||
# Using the chromosome_impl to set every index inside of the chromosome
|
||||
|
||||
@ -2,18 +2,18 @@ import random
|
||||
from math import ceil
|
||||
|
||||
def loop_selections(selection_method):
|
||||
"""Runs the selection method until enough chromosomes are mutated."""
|
||||
def helper(ga):
|
||||
# Loop until enough mutations occur
|
||||
for n in range(ceil(len(ga.population)*ga.chromosome_mutation_rate)):
|
||||
selection_method(ga)
|
||||
return helper
|
||||
|
||||
|
||||
def loop_mutations(mutation_method):
|
||||
"""Runs the mutation method until enough genes are mutated."""
|
||||
def helper(ga, old_chromosome):
|
||||
chromosome = ga.make_chromosome(list(old_chromosome))
|
||||
|
||||
# Loops until enough mutations occur
|
||||
for n in range(ceil(len(chromosome)*ga.gene_mutation_rate)):
|
||||
mutation_method(ga, chromosome)
|
||||
|
||||
@ -23,6 +23,7 @@ def loop_mutations(mutation_method):
|
||||
|
||||
class Mutation_Methods:
|
||||
|
||||
# Private method decorators, see above.
|
||||
def __loop_selections(selection_method):
|
||||
return loop_selections(selection_method)
|
||||
def __loop_mutations(mutation_method):
|
||||
@ -32,10 +33,9 @@ class Mutation_Methods:
|
||||
class Population:
|
||||
"""Methods for selecting chromosomes to mutate"""
|
||||
|
||||
|
||||
@loop_selections
|
||||
def random_selection(ga):
|
||||
"""Selects random chromosomes"""
|
||||
"""Selects random chromosomes."""
|
||||
|
||||
index = random.randint(0, len(ga.population)-1)
|
||||
ga.population[index] = ga.mutation_individual_impl(ga, ga.population[index])
|
||||
@ -43,7 +43,7 @@ class Mutation_Methods:
|
||||
|
||||
@loop_selections
|
||||
def random_selection_then_cross(ga):
|
||||
"""Selects random chromosomes and self-crosses with parent"""
|
||||
"""Selects random chromosomes and self-crosses with parent."""
|
||||
|
||||
index = random.randint(0, len(ga.population)-1)
|
||||
chromosome = ga.population[index]
|
||||
@ -51,12 +51,11 @@ class Mutation_Methods:
|
||||
|
||||
|
||||
class Individual:
|
||||
"""Methods for mutating a single chromosome"""
|
||||
|
||||
"""Methods for mutating a single chromosome."""
|
||||
|
||||
@loop_mutations
|
||||
def individual_genes(ga, chromosome):
|
||||
"""Mutates a random gene in the chromosome and resets the fitness."""
|
||||
"""Mutates a random gene in the chromosome."""
|
||||
index = random.randint(0, len(chromosome)-1)
|
||||
|
||||
# Using the chromosome_impl
|
||||
@ -72,15 +71,15 @@ class Mutation_Methods:
|
||||
raise Exception("Did not specify any initialization constraints.")
|
||||
|
||||
|
||||
class Permutation:
|
||||
"""Methods for mutating a chromosome
|
||||
by changing the order of the genes."""
|
||||
class Permutation:
|
||||
"""Methods for mutating a chromosome
|
||||
by changing the order of the genes."""
|
||||
|
||||
@loop_mutations
|
||||
def swap_genes(ga, chromosome):
|
||||
"""Mutates a random gene in the chromosome and resets the fitness."""
|
||||
@loop_mutations
|
||||
def swap_genes(ga, chromosome):
|
||||
"""Swaps two random genes in the chromosome."""
|
||||
|
||||
index_one = random.randint(0, len(chromosome)-1)
|
||||
index_two = random.randint(0, len(chromosome)-1)
|
||||
index_one = random.randint(0, len(chromosome)-1)
|
||||
index_two = random.randint(0, len(chromosome)-1)
|
||||
|
||||
chromosome[index_one], chromosome[index_two] = chromosome[index_two], chromosome[index_one]
|
||||
chromosome[index_one], chromosome[index_two] = chromosome[index_two], chromosome[index_one]
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
import random
|
||||
|
||||
def check_selection_probability(selection_method):
|
||||
"""Raises an exception if the selection_probability
|
||||
is not between 0 and 1. Otherwise runs the selection
|
||||
method.
|
||||
"""
|
||||
def helper(ga):
|
||||
if 0 < ga.selection_probability < 1:
|
||||
selection_method(ga)
|
||||
@ -10,6 +14,10 @@ def check_selection_probability(selection_method):
|
||||
|
||||
|
||||
def check_positive_fitness(selection_method):
|
||||
"""Raises an exception if the population contains a
|
||||
chromosome with negative fitness. Otherwise runs
|
||||
the selection method.
|
||||
"""
|
||||
def helper(ga):
|
||||
if ga.get_chromosome_fitness(0) > 0 and ga.get_chromosome_fitness(-1) >= 0:
|
||||
selection_method(ga)
|
||||
@ -19,6 +27,9 @@ def check_positive_fitness(selection_method):
|
||||
|
||||
|
||||
def ensure_sorted(selection_method):
|
||||
"""Sorts the population by fitness
|
||||
and then runs the selection method.
|
||||
"""
|
||||
def helper(ga):
|
||||
ga.population.sort_by_best_fitness(ga)
|
||||
selection_method(ga)
|
||||
@ -27,6 +38,7 @@ def ensure_sorted(selection_method):
|
||||
|
||||
class Parent_Selection:
|
||||
|
||||
# Private method decorators, see above.
|
||||
def __check_selection_probability(selection_method):
|
||||
return check_selection_probability(selection_method)
|
||||
def __check_positive_fitness(selection_method):
|
||||
|
||||
@ -56,43 +56,81 @@ class Chromosome:
|
||||
|
||||
|
||||
def __iter__(self):
|
||||
"""Returns an iterable of the gene list"""
|
||||
"""
|
||||
Allows the user to use
|
||||
|
||||
iter(chromosome)
|
||||
list(chromosome) == chromosome.gene_list
|
||||
tuple(chromosome)
|
||||
for gene in chromosome
|
||||
|
||||
to loop through the chromosome.
|
||||
"""
|
||||
return iter(self.gene_list)
|
||||
|
||||
|
||||
def __getitem__(self, index):
|
||||
"""Returns the indexed gene"""
|
||||
"""
|
||||
Allows the user to use
|
||||
gene = chromosome[index]
|
||||
to get the indexed gene.
|
||||
"""
|
||||
return self.gene_list[index]
|
||||
|
||||
|
||||
def __setitem__(self, index, gene):
|
||||
"""Sets the indexed gene value"""
|
||||
"""
|
||||
Allows the user to use
|
||||
chromosome[index] = gene
|
||||
to set the indexed gene.
|
||||
"""
|
||||
self.gene_list[index] = gene
|
||||
|
||||
|
||||
def __len__(self):
|
||||
"""Returns the number of genes in the chromosome"""
|
||||
"""
|
||||
Allows the user to use
|
||||
size = len(chromosome)
|
||||
to get the length of the chromosome.
|
||||
"""
|
||||
return len(self.gene_list)
|
||||
|
||||
|
||||
def __contains__(self, searched_gene):
|
||||
"""Returns True if the chromosome contains the gene and False otherwise.
|
||||
Ex. if chromosome in ga.population: ..."""
|
||||
|
||||
"""
|
||||
Allows the user to use
|
||||
if gene in chromosome
|
||||
to check if a gene is in the chromosome.
|
||||
"""
|
||||
return (searched_gene in self.gene_list)
|
||||
|
||||
|
||||
def index_of(self, searched_gene):
|
||||
"""Returns the index of the gene in the current chromosome."""
|
||||
|
||||
"""
|
||||
Allows the user to use
|
||||
index = chromosome.index_of(gene)
|
||||
to find the index of a gene in the chromosome.
|
||||
Be sure to check if the chromosome contains the gene
|
||||
first, or to catch an exception if the gene is not
|
||||
in the chromosome.
|
||||
"""
|
||||
return self.gene_list.index(searched_gene)
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
"""Create a backend string of the chromosome. Ex '1, 2, 3'."""
|
||||
"""
|
||||
Allows the user to use
|
||||
repr(chromosome)
|
||||
to get a backend representation of the chromosome.
|
||||
"""
|
||||
return ', '.join(repr(gene) for gene in self)
|
||||
|
||||
|
||||
def __str__(self):
|
||||
"""Create a printable string of the chromosome. Ex '[1][2][3]'."""
|
||||
"""
|
||||
Allows the user to use
|
||||
str(chromosome)
|
||||
print(chromosome)
|
||||
to get a frontend representation of the chromosome.
|
||||
"""
|
||||
return ''.join(str(gene) for gene in self)
|
||||
|
||||
@ -29,10 +29,19 @@ class Gene:
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
"""Create a backend string of the chromosome. Ex '1'."""
|
||||
"""
|
||||
Allows the user to use
|
||||
repr(gene)
|
||||
to get a backend representation of the gene.
|
||||
"""
|
||||
return str(self.value)
|
||||
|
||||
|
||||
def __str__(self):
|
||||
"""Create a printable string of the chromosome. Ex '[1]'."""
|
||||
"""
|
||||
Allows the user to use
|
||||
str(gene)
|
||||
print(gene)
|
||||
to get a frontend representation of the gene.
|
||||
"""
|
||||
return f'[{str(self.value)}]'
|
||||
|
||||
@ -152,41 +152,75 @@ class Population:
|
||||
|
||||
|
||||
def __iter__(self):
|
||||
"""Returns an iterable of chromosomes"""
|
||||
"""
|
||||
Allows the user to use
|
||||
|
||||
iter(population)
|
||||
list(population) == population.chromosome_list
|
||||
tuple(population)
|
||||
for chromosome in population
|
||||
|
||||
to loop through the population.
|
||||
"""
|
||||
return iter(self.chromosome_list)
|
||||
|
||||
|
||||
def __getitem__(self, index):
|
||||
"""Returns the indexed chromosome"""
|
||||
"""
|
||||
Allows the user to use
|
||||
chromosome = population[index]
|
||||
to get the indexed chromosome.
|
||||
"""
|
||||
return self.chromosome_list[index]
|
||||
|
||||
|
||||
def __setitem__(self, index, chromosome):
|
||||
"""Sets the indexed chromosome"""
|
||||
"""
|
||||
Allows the user to use
|
||||
population[index] = chromosome
|
||||
to set the indexed chromosome.
|
||||
"""
|
||||
self.chromosome_list[index] = chromosome
|
||||
|
||||
|
||||
def __len__(self):
|
||||
"""Returns the number of chromosomes in the current population"""
|
||||
"""
|
||||
Allows the user to use
|
||||
size = len(population)
|
||||
to get the length of the population.
|
||||
"""
|
||||
return len(self.chromosome_list)
|
||||
|
||||
|
||||
def __contains__(self, searched_chromosome):
|
||||
"""Returns True if the current population contains the chromosome and False otherwise.
|
||||
Ex. if chromosome in ga.population: ..."""
|
||||
|
||||
"""
|
||||
Allows the user to use
|
||||
if chromosome in population
|
||||
to check if a chromosome is in the population.
|
||||
"""
|
||||
return (searched_chromosome in self.chromosome_list)
|
||||
|
||||
|
||||
def index_of(self, searched_chromosome):
|
||||
"""Returns the index of the chromosome in the current population."""
|
||||
|
||||
"""
|
||||
Allows the user to use
|
||||
index = population.index_of(chromosome)
|
||||
to find the index of a chromosome in the population.
|
||||
Be sure to check if the population contains the chromosome
|
||||
first, or to catch an exception if the chromosome is not
|
||||
in the population.
|
||||
"""
|
||||
return self.chromosome_list.index(searched_chromosome)
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
"""Returns a backend string representation of the entire population"""
|
||||
|
||||
"""
|
||||
Allows the user to use
|
||||
repr(population)
|
||||
str(population)
|
||||
print(population)
|
||||
to get a backend representation of the population.
|
||||
"""
|
||||
return ''.join(
|
||||
f'Chromosome - {index} {chromosome} ' +
|
||||
f'/ Fitness = {chromosome.fitness}\n'
|
||||
|
||||
@ -1,12 +1,14 @@
|
||||
import random
|
||||
|
||||
def append_to_next_population(survivor_method):
|
||||
"""Appends the selected chromosomes to the next population."""
|
||||
return lambda ga: ga.population.append_children(survivor_method(ga))
|
||||
|
||||
|
||||
class Survivor_Selection:
|
||||
"""Survivor selection determines which individuals should be brought to the next generation"""
|
||||
|
||||
# Private method decorator, see above.
|
||||
def __append_to_next_population(survivor_method):
|
||||
return append_to_next_population(survivor_method)
|
||||
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
def add_by_fitness_goal(termination_impl):
|
||||
"""Adds termination by fitness goal to the method."""
|
||||
|
||||
def helper(ga):
|
||||
|
||||
# If fitness goal is set, check it.
|
||||
@ -18,6 +20,8 @@ def add_by_fitness_goal(termination_impl):
|
||||
|
||||
|
||||
def add_by_generation_goal(termination_impl):
|
||||
"""Adds termination by generation goal to the method."""
|
||||
|
||||
def helper(ga):
|
||||
|
||||
# If generation goal is set, check it.
|
||||
@ -30,6 +34,8 @@ def add_by_generation_goal(termination_impl):
|
||||
|
||||
|
||||
def add_by_tolerance_goal(termination_impl):
|
||||
"""Adds termination by tolerance goal to the method."""
|
||||
|
||||
def helper(ga):
|
||||
|
||||
# If tolerance is set, check it.
|
||||
@ -50,6 +56,7 @@ def add_by_tolerance_goal(termination_impl):
|
||||
class Termination_Methods:
|
||||
"""Example functions that can be used to terminate the the algorithms loop"""
|
||||
|
||||
# Private method decorators, see above.
|
||||
def __add_by_fitness_goal(termination_impl):
|
||||
return add_by_fitness_goal(termination_impl)
|
||||
def __add_by_generation_goal(termination_impl):
|
||||
|
||||
Reference in New Issue
Block a user