131 lines
6.2 KiB
Python
131 lines
6.2 KiB
Python
import random
|
|
|
|
class Parent_Selection:
|
|
|
|
class Rank:
|
|
|
|
def tournament(ga):
|
|
"""
|
|
Will make tournaments of size tournament_size and choose the winner (best fitness)
|
|
from the tournament and use it as a parent for the next generation. The total number
|
|
of parents selected is determined by parent_ratio, an attribute to the GA object.
|
|
"""
|
|
|
|
# Error if can't select parents
|
|
if ga.selection_probability <= 0:
|
|
print("Selection probability must be greater than 0 to select parents.")
|
|
return
|
|
|
|
# Make sure the population is sorted by fitness
|
|
ga.population.sort_by_best_fitness(ga)
|
|
|
|
# Choose the tournament size.
|
|
# Use no less than 5 chromosomes per tournament.
|
|
tournament_size = int(ga.population.size()*ga.tournament_size_ratio)
|
|
if tournament_size < 5:
|
|
tournament_size = 5
|
|
|
|
# Repeat tournaments until the mating pool is large enough.
|
|
while (len(ga.population.get_mating_pool()) < ga.population.size()*ga.parent_ratio):
|
|
|
|
# Generate a random tournament group and sort by fitness.
|
|
tournament_group = sorted([random.randint(0, ga.population.size()-1) for n in range(tournament_size)])
|
|
|
|
# For each chromosome, add it to the mating pool based on its rank in the tournament.
|
|
for index in range(tournament_size):
|
|
|
|
# Probability required is selection_probability * (1-selection_probability) ^ index
|
|
# e.g. top ranked fitness has probability: selection_probability
|
|
# second ranked fitness has probability: selection_probability * (1-selection_probability)
|
|
# third ranked fitness has probability: selection_probability * (1-selection_probability)^2
|
|
# etc.
|
|
if random.uniform(0, 1) < ga.selection_probability * pow(1-ga.selection_probability, index):
|
|
ga.population.set_parent(tournament_group[index])
|
|
|
|
# Stop if parent ratio reached
|
|
if len(ga.population.get_mating_pool()) >= ga.population.size()*ga.parent_ratio:
|
|
break
|
|
|
|
|
|
class Fitness:
|
|
|
|
def roulette(ga):
|
|
"""Roulette selection works based off of how strong the fitness is of the
|
|
chromosomes in the population. The stronger the fitness the higher the probability
|
|
that it will be selected. Using the example of a casino roulette wheel.
|
|
Where the chromosomes are the numbers to be selected and the board size for
|
|
those numbers are directly proportional to the chromosome's current fitness. Where
|
|
the ball falls is a randomly generated number between 0 and 1."""
|
|
|
|
# Make sure the population is sorted by fitness
|
|
ga.population.sort_by_best_fitness(ga)
|
|
|
|
# Error if can't select parents
|
|
if ga.selection_probability <= 0:
|
|
print("Selection probability must be greater than 0 to select parents.")
|
|
return
|
|
|
|
# Error if not all chromosomes has positive fitness
|
|
if (ga.get_chromosome_fitness(0) == 0 or ga.get_chromosome_fitness(-1) < 0):
|
|
print("Error using roulette selection, all fitnesses must be positive.")
|
|
print("Consider using stockastic roulette selection or tournament selection.")
|
|
return
|
|
|
|
# The sum of all the fitnessess in a population
|
|
fitness_sum = sum(ga.get_chromosome_fitness(index) for index in range(ga.population.size()))
|
|
|
|
# A list of ranges that represent the probability of a chromosome getting chosen
|
|
probability = [ga.selection_probability]
|
|
|
|
# The chance of being selected increases incrementally
|
|
for index in range(ga.population.size()):
|
|
probability.append(probability[-1]+ga.get_chromosome_fitness(index)/fitness_sum)
|
|
|
|
probability = probability[1:]
|
|
|
|
# Loops until it reaches a desired mating pool size
|
|
while (len(ga.population.get_mating_pool()) < ga.population.size()*ga.parent_ratio):
|
|
|
|
# Spin the roulette
|
|
rand_number = random.random()
|
|
|
|
# Find where the roulette landed.
|
|
for index in range(len(probability)):
|
|
if (probability[index] >= rand_number):
|
|
ga.population.set_parent(index)
|
|
break
|
|
|
|
|
|
def stochastic(ga):
|
|
"""Stochastic roulette selection works based off of how strong the fitness is of the
|
|
chromosomes in the population. The stronger the fitness the higher the probability
|
|
that it will be selected. Instead of dividing the fitness by the sum of all fitnesses
|
|
and incrementally increasing the chance something is selected, the stochastic method
|
|
just divides by the highest fitness and selects randomly."""
|
|
|
|
# Make sure the population is sorted by fitness
|
|
ga.population.sort_by_best_fitness(ga)
|
|
|
|
# Error if can't select parents
|
|
if ga.selection_probability <= 0 or ga.selection_probability >= 1:
|
|
print("Selection probability must be between 0 and 1 to select parents.")
|
|
return
|
|
|
|
max_fitness = ga.get_chromosome_fitness(0)
|
|
|
|
# Error if the highest fitness is not positive
|
|
if max_fitness <= 0:
|
|
print("Error using stochastic roulette selection, best fitness must be positive.")
|
|
print("Consider using tournament selection.")
|
|
return
|
|
|
|
# Loops until it reaches a desired mating pool size
|
|
while (len(ga.population.get_mating_pool()) < ga.population.size()*ga.parent_ratio):
|
|
|
|
# Selected chromosome
|
|
index = random.randint(0, ga.population.size()-1)
|
|
|
|
# Probability of becoming a parent is fitness/max_fitness
|
|
if random.uniform(ga.selection_probability, 1) < ga.get_chromosome_fitness(index)/max_fitness:
|
|
ga.population.set_parent(index)
|