Source code for moptipy.algorithms.modules.selection
"""
Selection algorithms are common modules that choose `n` out of `N` objects.
Selection algorithms are modules of the fully-configurable Evolutionary
Algorithm :class:`~moptipy.algorithms.so.general_ea.GeneralEA`. They can
utilize fitness values computed by the fitness assignment processes
(:class:`~moptipy.algorithms.so.fitness.Fitness`). Of course, they can
also be applied in different contexts and are not bound to single-objective
optimization.
:class:`~moptipy.algorithms.modules.selection.Selection` is especially
important in Evolutionary Algorithms
(`~moptipy.algorithms.so.general_ea.GeneralEA`), where it is used in two
places: As *survival selection*, it chooses which points will be allowed to
remain in the population and, hence, survive into the mating pool for the next
generation. As *mating selection* methods, they choose the inputs of the
search operations from the mating pool.
:class:`~moptipy.algorithms.modules.selection.Selection` algorithms must
*only* use the
:attr:`~moptipy.algorithms.modules.selection.FitnessRecord.fitness` of a
solution record (and random numbers) to make their decisions. These fitness
values are subject to minimization. They can equal to the objective values in
optimization or stem from a :class:`~moptipy.algorithms.so.fitness.Fitness`
Assignment Process.
The following selection algorithms have currently been implemented:
- :class:`~moptipy.algorithms.modules.selections.best.Best` selection
selects the best `n` solutions without replacement. This is a common
strategy for survival selection, especially in (mu+lambda) EAs
(compatible to :class:`~moptipy.algorithms.so.ea.EA`).
- :class:`~moptipy.algorithms.modules.selections.random_without_repl\
.RandomWithoutReplacement` selects random solutions without replacement. It is
a common strategy for mating selection.
- :class:`~moptipy.algorithms.modules.selections.fitness_proportionate_sus\
.FitnessProportionateSUS` performs fitness proportionate selection for
minimization using stochastic uniform sampling and, optionally, a minimum
selection probability threshold. It is the classic survival selection
algorithm in Genetic Algorithm.
- :class:`~moptipy.algorithms.modules.selections.tournament_with_repl.\
TournamentWithReplacement`
performs tournament selection with a specified tournament size with
replacement.
- :class:`~moptipy.algorithms.modules.selections.tournament_without_repl.\
TournamentWithoutReplacement`
performs tournament selection with a specified tournament size without
replacement.
"""
from typing import Any, Callable, Protocol
from numpy.random import Generator
from pycommons.types import type_error
from moptipy.api.component import Component
# start book
[docs]
class FitnessRecord(Protocol):
"""A fitness record stores data together with a fitness."""
# end book
#: the fitness value, which can either be an integer or a float and
#: is the only criterion to be used by a selection
#: algorithm (besides random numbers)
fitness: float
def __lt__(self, other) -> bool:
"""
Compare the fitness of this record with the fitness of another one.
:param other: the other fitness record
"""
return self.fitness < other.fitness
# start book
[docs]
class Selection(Component):
"""The base class for selections algorithms."""
[docs]
def select(self, source: list[FitnessRecord],
dest: Callable[[FitnessRecord], Any],
n: int, random: Generator) -> None: # pylint: disable=W0613
"""
Select `n` records from `source` and pass them to `dest`.
When choosing the `n` records from `source` to be passed to
`dest`, only the :attr:`~FitnessRecord.fitness` attribute of
the records and the random numbers from `random` must be used
as decision criteria.
:param source: the list with the records to select from
:param dest: the destination collector Callable to invoke for
each selected record, can be :class:`list`.`append`.
:param n: the number of records to select
:param random: the random number generator
"""
# end book
[docs]
def check_selection(selection: Selection) -> Selection:
"""
Check whether an object is a valid instance of :class:`Selection`.
:param selection: the Selection object
:return: the object
:raises TypeError: if `selections` is not an instance of
:class:`Selection` or if it is an instance of the abstract base
class
"""
if not isinstance(selection, Selection):
raise type_error(selection, "selections", Selection)
if selection.__class__ is Selection:
raise TypeError("cannot use abstract class 'Selection' directly")
return selection