Coverage for moptipy / algorithms / modules / selection.py: 88%

16 statements  

« prev     ^ index     » next       coverage.py v7.12.0, created at 2025-11-24 08:49 +0000

1""" 

2Selection algorithms are common modules that choose `n` out of `N` objects. 

3 

4Selection algorithms are modules of the fully-configurable Evolutionary 

5Algorithm :class:`~moptipy.algorithms.so.general_ea.GeneralEA`. They can 

6utilize fitness values computed by the fitness assignment processes 

7(:class:`~moptipy.algorithms.so.fitness.Fitness`). Of course, they can 

8also be applied in different contexts and are not bound to single-objective 

9optimization. 

10 

11:class:`~moptipy.algorithms.modules.selection.Selection` is especially 

12important in Evolutionary Algorithms 

13(`~moptipy.algorithms.so.general_ea.GeneralEA`), where it is used in two 

14places: As *survival selection*, it chooses which points will be allowed to 

15remain in the population and, hence, survive into the mating pool for the next 

16generation. As *mating selection* methods, they choose the inputs of the 

17search operations from the mating pool. 

18 

19:class:`~moptipy.algorithms.modules.selection.Selection` algorithms must 

20*only* use the 

21:attr:`~moptipy.algorithms.modules.selection.FitnessRecord.fitness` of a 

22solution record (and random numbers) to make their decisions. These fitness 

23values are subject to minimization. They can equal to the objective values in 

24optimization or stem from a :class:`~moptipy.algorithms.so.fitness.Fitness` 

25Assignment Process. 

26 

27The following selection algorithms have currently been implemented: 

28 

29- :class:`~moptipy.algorithms.modules.selections.best.Best` selection 

30 selects the best `n` solutions without replacement. This is a common 

31 strategy for survival selection, especially in (mu+lambda) EAs 

32 (compatible to :class:`~moptipy.algorithms.so.ea.EA`). 

33- :class:`~moptipy.algorithms.modules.selections.random_without_repl\ 

34.RandomWithoutReplacement` selects random solutions without replacement. It is 

35 a common strategy for mating selection. 

36- :class:`~moptipy.algorithms.modules.selections.fitness_proportionate_sus\ 

37.FitnessProportionateSUS` performs fitness proportionate selection for 

38 minimization using stochastic uniform sampling and, optionally, a minimum 

39 selection probability threshold. It is the classic survival selection 

40 algorithm in Genetic Algorithm. 

41- :class:`~moptipy.algorithms.modules.selections.tournament_with_repl.\ 

42TournamentWithReplacement` 

43 performs tournament selection with a specified tournament size with 

44 replacement. 

45- :class:`~moptipy.algorithms.modules.selections.tournament_without_repl.\ 

46TournamentWithoutReplacement` 

47 performs tournament selection with a specified tournament size without 

48 replacement. 

49""" 

50from typing import Any, Callable, Protocol 

51 

52from numpy.random import Generator 

53from pycommons.types import type_error 

54 

55from moptipy.api.component import Component 

56 

57 

58# start book 

59class FitnessRecord(Protocol): 

60 """A fitness record stores data together with a fitness.""" 

61 

62# end book 

63 #: the fitness value, which can either be an integer or a float and 

64 #: is the only criterion to be used by a selection 

65 #: algorithm (besides random numbers) 

66 fitness: float 

67 

68 def __lt__(self, other) -> bool: 

69 """ 

70 Compare the fitness of this record with the fitness of another one. 

71 

72 :param other: the other fitness record 

73 """ 

74 return self.fitness < other.fitness 

75# start book 

76 

77 

78class Selection(Component): 

79 """The base class for selections algorithms.""" 

80 

81 def select(self, source: list[FitnessRecord], 

82 dest: Callable[[FitnessRecord], Any], 

83 n: int, random: Generator) -> None: # pylint: disable=W0613 

84 """ 

85 Select `n` records from `source` and pass them to `dest`. 

86 

87 When choosing the `n` records from `source` to be passed to 

88 `dest`, only the :attr:`~FitnessRecord.fitness` attribute of 

89 the records and the random numbers from `random` must be used 

90 as decision criteria. 

91 

92 :param source: the list with the records to select from 

93 :param dest: the destination collector Callable to invoke for 

94 each selected record, can be :class:`list`.`append`. 

95 :param n: the number of records to select 

96 :param random: the random number generator 

97 """ 

98# end book 

99 

100 

101def check_selection(selection: Selection) -> Selection: 

102 """ 

103 Check whether an object is a valid instance of :class:`Selection`. 

104 

105 :param selection: the Selection object 

106 :return: the object 

107 :raises TypeError: if `selections` is not an instance of 

108 :class:`Selection` or if it is an instance of the abstract base 

109 class 

110 """ 

111 if not isinstance(selection, Selection): 

112 raise type_error(selection, "selections", Selection) 

113 if selection.__class__ is Selection: 

114 raise TypeError("cannot use abstract class 'Selection' directly") 

115 return selection