Changed for more general usage and cleaned up previous push

This commit is contained in:
SimpleArt
2020-12-30 09:08:43 -05:00
parent 0c59c429eb
commit 21c12c2bcd

View File

@ -6,20 +6,6 @@ import random
randround = lambda x: int(x + random.random()) randround = lambda x: int(x + random.random())
@function_info
def _append_to_next_population(population_method):
"""Appends the new chromosomes to the next population.
Also modifies the input to include the mating pool.
"""
def new_method(ga):
ga.population.append_children(
population_method(ga, ga.population.mating_pool)
)
return new_method
@function_info @function_info
def _check_weight(individual_method): def _check_weight(individual_method):
"""Checks if the weight is between 0 and 1 before running. """Checks if the weight is between 0 and 1 before running.
@ -30,9 +16,9 @@ def _check_weight(individual_method):
def new_method(ga, parent_1, parent_2, *, weight = individual_method.__kwdefaults__.get('weight', None)): def new_method(ga, parent_1, parent_2, *, weight = individual_method.__kwdefaults__.get('weight', None)):
if weight is None: if weight is None:
return individual_method(ga, parent_1, parent_2) individual_method(ga, parent_1, parent_2)
elif 0 < weight < 1: elif 0 < weight < 1:
return individual_method(ga, parent_1, parent_2, weight = weight) individual_method(ga, parent_1, parent_2, weight = weight)
else: else:
raise ValueError(f"Weight must be between 0 and 1 when using {individual_method.__name__}.") raise ValueError(f"Weight must be between 0 and 1 when using {individual_method.__name__}.")
@ -41,27 +27,17 @@ def _check_weight(individual_method):
@function_info @function_info
def _gene_by_gene(individual_method): def _gene_by_gene(individual_method):
"""Perform crossover by making a single new chromosome """Perform crossover by making a single new chromosome by combining each gene by gene."""
by combining each gene by gene.
"""
def new_method(ga, parent_1, parent_2, *, weight = individual_method.__kwdefaults__.get('weight', None)): def new_method(ga, parent_1, parent_2, *, weight = individual_method.__kwdefaults__.get('weight', 'None')):
# Without any weight ga.population.add_child(
if weight is None: individual_method(ga, value_1, value_2)
yield ( if weight == 'None' else
individual_method(ga, value_1, value_2) individual_method(ga, value_1, value_2, weight = weight)
for value_1, value_2 for value_1, value_2
in zip(parent_1.gene_value_iter, parent_2.gene_value_iter) in zip(parent_1.gene_value_iter, parent_2.gene_value_iter)
) )
# With a weight
else:
yield (
individual_method(ga, value_1, value_2, weight = weight)
for value_1, value_2
in zip(parent_1.gene_value_iter, parent_2.gene_value_iter)
)
return new_method return new_method
@ -69,7 +45,6 @@ def _gene_by_gene(individual_method):
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
_check_weight = _check_weight _check_weight = _check_weight
_gene_by_gene = _gene_by_gene _gene_by_gene = _gene_by_gene
@ -78,30 +53,28 @@ class Crossover_Methods:
"""Methods for selecting chromosomes to crossover.""" """Methods for selecting chromosomes to crossover."""
@_append_to_next_population
def sequential_selection(ga, mating_pool): def sequential_selection(ga, mating_pool):
"""Select sequential pairs from the mating pool. """Select sequential pairs from the mating pool.
Every parent is paired with the previous parent. Every parent is paired with the previous parent.
The first parent is paired with the last parent. The first parent is paired with the last parent.
""" """
for index in range(len(mating_pool)): # for each parent in the mating pool for index in range(len(mating_pool)): # for each parent in the mating pool
yield from ga.crossover_individual_impl( # apply crossover to ga.crossover_individual_impl( # apply crossover to
mating_pool[index], # the parent and mating_pool[index], # the parent and
mating_pool[index-1], # the previous parent mating_pool[index-1], # the previous parent
) )
@_append_to_next_population
def random_selection(ga, mating_pool): def random_selection(ga, mating_pool):
"""Select random pairs from the mating pool. """Select random pairs from the mating pool.
Every parent is paired with a random parent. Every parent is paired with a random parent.
""" """
for parent in mating_pool: # for each parent in the mating pool for parent in mating_pool: # for each parent in the mating pool
yield from ga.crossover_individual_impl( # apply crossover to ga.crossover_individual_impl( # apply crossover to
parent, # the parent and parent, # the parent and
random.choice(mating_pool), # a random parent random.choice(mating_pool), # a random parent
) )
@ -118,8 +91,8 @@ class Crossover_Methods:
# Weighted random integer from 0 to minimum parent length - 1 # Weighted random integer from 0 to minimum parent length - 1
swap_index = int(ga.weighted_random(weight) * minimum_parent_length) swap_index = int(ga.weighted_random(weight) * minimum_parent_length)
yield parent_1[:swap_index] + parent_2[swap_index:] ga.population.add_child(parent_1[:swap_index] + parent_2[swap_index:])
yield parent_2[:swap_index] + parent_1[swap_index:] ga.population.add_child(parent_2[:swap_index] + parent_1[swap_index:])
@_check_weight @_check_weight
@ -174,7 +147,7 @@ class Crossover_Methods:
if type(value_1) == type(value_2) == int: if type(value_1) == type(value_2) == int:
value = randround(value) value = randround(value)
yield value return value
class Permutation: class Permutation:
@ -222,7 +195,7 @@ class Crossover_Methods:
gene_list_1[input_index] = gene_list_2.pop(-1) gene_list_1[input_index] = gene_list_2.pop(-1)
input_index += 1 input_index += 1
yield gene_list_1 ga.population.add_child(gene_list_1)
@_check_weight @_check_weight
@ -282,4 +255,4 @@ class Crossover_Methods:
gene_list_1[input_index] = gene_list_2.pop(-1) gene_list_1[input_index] = gene_list_2.pop(-1)
input_index += 1 input_index += 1
yield gene_list_1 ga.population.add_child(gene_list_1)