Files
EasyGA/src/parent_selection/parent_selection_methods.py

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)