148 lines
5.3 KiB
Python
148 lines
5.3 KiB
Python
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)]
|
|
)
|
|
|
|
|
|
def genes_to_chromosome(crossover_method):
|
|
"""Converts a collection of genes into a chromosome."""
|
|
return lambda ga, parent_1, parent_2:\
|
|
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:\
|
|
(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):
|
|
return values_to_chromosome(crossover_method)
|
|
def __values_to_genes(crossover_method):
|
|
return values_to_genes(crossover_method)
|
|
|
|
|
|
class Population:
|
|
"""Methods for selecting chromosomes to crossover."""
|
|
|
|
|
|
@append_children_from_mating_pool
|
|
def sequential_selection(ga, mating_pool):
|
|
"""Select sequential pairs from the mating pool.
|
|
Every parent is paired with the previous parent.
|
|
The first parent is paired with the last parent.
|
|
"""
|
|
|
|
for index in range(len(mating_pool)): # for each parent in the mating pool
|
|
yield ga.crossover_individual_impl( # apply crossover to
|
|
ga, #
|
|
mating_pool[index], # the parent and
|
|
mating_pool[index-1] # the previous parent
|
|
)
|
|
|
|
|
|
@append_children_from_mating_pool
|
|
def random_selection(ga, mating_pool):
|
|
"""Select random pairs from the mating pool.
|
|
Every parent is paired with a random parent.
|
|
"""
|
|
|
|
for parent in mating_pool: # for each parent in the mating pool
|
|
yield ga.crossover_individual_impl( # apply crossover to
|
|
ga, #
|
|
parent, # the parent and
|
|
random.choice(mating_pool) # a random parent
|
|
)
|
|
|
|
|
|
class Individual:
|
|
"""Methods for crossing parents."""
|
|
|
|
|
|
@genes_to_chromosome
|
|
def single_point(ga, parent_1, parent_2):
|
|
"""Cross two parents by swapping genes at one random point."""
|
|
|
|
swap_index = random.randrange(len(parent_1))
|
|
return parent_1[:swap_index] + parent_2[swap_index:]
|
|
|
|
|
|
@genes_to_chromosome
|
|
def multi_point(ga, parent_1, parent_2):
|
|
"""Cross two parents by swapping genes at multiple points."""
|
|
pass
|
|
|
|
|
|
@genes_to_chromosome
|
|
def uniform(ga, parent_1, parent_2):
|
|
"""Cross two parents by swapping all genes randomly."""
|
|
|
|
for gene_pair in zip(parent_1, parent_2):
|
|
yield random.choice(gene_pair)
|
|
|
|
|
|
class Arithmetic:
|
|
"""Crossover methods for numerical genes."""
|
|
|
|
@genes_to_chromosome
|
|
@values_to_genes
|
|
def int_random(ga, parent_1, parent_2):
|
|
"""Cross two parents by taking a random integer value between each of the genes."""
|
|
|
|
value_list_1 = parent_1.gene_value_list
|
|
value_list_2 = parent_2.gene_value_list
|
|
|
|
for value_1, value_2 in zip(value_list_1, value_list_2):
|
|
yield random.randint(*sorted([value_1, value_2]))
|
|
|
|
|
|
@genes_to_chromosome
|
|
@values_to_genes
|
|
def int_weighted(ga, parent_1, parent_2):
|
|
"""Cross two parents by taking a a weighted average of the genes."""
|
|
|
|
# the percentage of genes taken from the first gene
|
|
weight = 0.25
|
|
|
|
value_list_1 = parent_1.gene_value_list
|
|
value_list_2 = parent_2.gene_value_list
|
|
|
|
for value_1, value_2 in zip(value_list_1, value_list_2):
|
|
yield int(weight*value_1+(1-weight)*value_2)
|
|
|
|
|
|
@genes_to_chromosome
|
|
@values_to_genes
|
|
def float_random(ga, parent_one, parent_two):
|
|
"""Cross two parents by taking a random numeric value between each of the genes."""
|
|
|
|
value_list_1 = parent_1.gene_value_list
|
|
value_list_2 = parent_2.gene_value_list
|
|
|
|
for value_1, value_2 in zip(value_list_1, value_list_2):
|
|
yield random.uniform([value_1, value_2])
|
|
|
|
|
|
@genes_to_chromosome
|
|
@values_to_genes
|
|
def float_weighted(ga, parent_one, parent_two):
|
|
"""Cross two parents by taking a a weighted average of the genes."""
|
|
|
|
# the percentage of genes taken from the first gene
|
|
weight = 0.25
|
|
|
|
value_list_1 = parent_1.gene_value_list
|
|
value_list_2 = parent_2.gene_value_list
|
|
|
|
for value_1, value_2 in zip(value_list_1, value_list_2):
|
|
yield weight*value_1+(1-weight)*value_2
|