-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathroulette_wheel_selector.py
More file actions
76 lines (59 loc) · 3.06 KB
/
roulette_wheel_selector.py
File metadata and controls
76 lines (59 loc) · 3.06 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
from math import fsum, isclose
from pygenalgo.genome.chromosome import Chromosome
from pygenalgo.operators.genetic_operator import increase_counter
from pygenalgo.operators.selection.select_operator import (SelectionOperator,
ensure_positive_fitness)
class RouletteWheelSelector(SelectionOperator):
"""
Description:
Roulette Wheel Selection employs a probabilistic mechanism where individuals are
selected based on their fitness relative to the entire population. Each individual
receives a slice of a wheel proportional to its fitness, similar to a casino roulette,
where a random number determines the selected individual. This method encourages selection
of fitter individuals while allowing lower-fitness individuals a chance to contribute.
While effective, it can lead to premature convergence if the population's fitness is skewed,
often referred to as the "selection pressure."
"""
def __init__(self, select_probability: float = 1.0) -> None:
"""
Construct a 'RouletteWheelSelector' object with a given probability value.
:param select_probability: (float) in [0, 1].
"""
# Call the super constructor with the provided probability value.
super().__init__(select_probability)
# _end_def_
@increase_counter
def select(self, population: list[Chromosome]) -> list[Chromosome]:
"""
Select the individuals, from the input population, that will be
passed on to the next genetic operations of crossover and mutation
to form the new population of solutions.
:param population: a list of chromosomes to select the parents from.
:return: the selected parents population (as list of chromosomes).
"""
# Get the population size.
pop_size = len(population)
# Extract the (positive) fitness values from the chromosomes.
all_fitness: list[float] = ensure_positive_fitness(population)
# Calculate sum of all fitness.
sum_fitness = fsum(all_fitness)
# If total fitness is zero (or effectively zero),
# fall back to uniform random selection so every
# individual has equal chance.
if isclose(sum_fitness, 0.0):
# Select the new individuals with equal probability.
safe_index = self.rng.choice(pop_size, size=pop_size,
replace=True, shuffle=False)
# Return the new parents to a list.
return [population[i] for i in safe_index]
# _end_if_
# Calculate the "selection probabilities" of each member
# in the population.
selection_probs = [f / sum_fitness for f in all_fitness]
# Select the new individuals (indexes).
index = self.rng.choice(pop_size, size=pop_size, p=selection_probs,
replace=True, shuffle=False)
# Return the new parents (individuals).
return [population[i] for i in index]
# _end_def_
# _end_class_