Representation-agnostic parent selection.
Selection operators work on {chromosome, fitness} pairs. One module
serves all chromosome types.
select/3 draws population_size parents from the current population;
select/4 draws an explicit count. Higher fitness = more likely to be
selected.
Summary
Functions
Rank-based selection. Sorts the population by fitness and assigns selection probability by rank (not raw fitness value).
Fitness-proportional (roulette wheel) selection.
Dispatches to the named selection operator.
Selects exactly count parents from the population.
Stochastic Universal Sampling. Places population_size equally-spaced
pointers on the roulette wheel.
Tournament selection. Picks tournament_size random individuals and
returns the fittest. Repeat population_size times.
Functions
Rank-based selection. Sorts the population by fitness and assigns selection probability by rank (not raw fitness value).
Resistant to outliers — a chromosome with 100× the fitness of the rest won't dominate the selection pool.
Fitness-proportional (roulette wheel) selection.
Each individual's selection probability is proportional to its fitness.
Raises when total fitness is zero after normalization.
Dispatches to the named selection operator.
Valid operators: :tournament, :roulette, :rank, :sus.
The config keyword list must contain :population_size. Tournament selection
also reads :tournament_size (defaults to 3).
Example
iex> pop = [
...> {%Petri.Chromosome.Binary{genes: [0, 0, 1]}, 1.0},
...> {%Petri.Chromosome.Binary{genes: [1, 1, 0]}, 2.0},
...> {%Petri.Chromosome.Binary{genes: [1, 1, 1]}, 3.0}
...> ]
iex> parents = Petri.Selection.select(:tournament, pop, [population_size: 2, tournament_size: 2])
iex> length(parents)
2
Selects exactly count parents from the population.
Same dispatch as select/3, with the number of picks explicit instead of
read from :population_size in the config. Steady-state replacement uses
this to draw just the two parents it needs.
Example
iex> pop = [
...> {%Petri.Chromosome.Binary{genes: [0, 0, 1]}, 1.0},
...> {%Petri.Chromosome.Binary{genes: [1, 1, 0]}, 2.0},
...> {%Petri.Chromosome.Binary{genes: [1, 1, 1]}, 3.0}
...> ]
iex> parents = Petri.Selection.select(:tournament, pop, [tournament_size: 2], 2)
iex> length(parents)
2
Stochastic Universal Sampling. Places population_size equally-spaced
pointers on the roulette wheel.
Guarantees that very fit individuals are selected at least floor(p_i * n) times, giving lower variance than repeated roulette spins.
Negative fitness values are shifted via windowing so the minimum becomes a small positive value, preserving relative differences.
Tournament selection. Picks tournament_size random individuals and
returns the fittest. Repeat population_size times.
Contestants are drawn independently, so an individual can be picked more than once per tournament.
Fast, works with negative fitness, and doesn't require fitness scaling.