Coverage for moptipy / algorithms / so / fitnesses / rank.py: 100%

18 statements  

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

1""" 

2A fitness representing the rank of a solution based on its quality. 

3 

4First, all solutions are sorted based on their objective values. Then, they 

5receive their rank, i.e., index+1 in the sorted list, as fitness. If two 

6elements have the same objective value, they also receive the same rank. 

7This rank will be the index+1 of the first element. 

8 

9>>> # The first value in FRecord(x, y) is the solution, which is not matter 

10>>> # here. The second value is the objective value used for ranking. 

11>>> l = [FRecord(1, 10), FRecord(2, 3), FRecord(3, 3), FRecord(4, 2)] 

12>>> from numpy.random import default_rng 

13>>> Rank().assign_fitness(l, default_rng()) 

14>>> for z in l: 

15... print(f"x={z.x}, fitness={z.fitness}") 

16x=4, fitness=1 

17x=2, fitness=2 

18x=3, fitness=2 

19x=1, fitness=4 

20 

21Together with fitness proportionate selection (:class:`~moptipy.algorithms.\ 

22modules.selections.fitness_proportionate_sus.FitnessProportionateSUS`), it 

23works very similar to linear ranking selection in an EA 

24(:class:`~moptipy.algorithms.so.general_ea.GeneralEA`). 

25 

261. L. Darrell Whitley. The GENITOR Algorithm and Selection Pressure: Why 

27 Rank-Based Allocation of Reproductive Trials is Best. In J. David Schaffer, 

28 ed., Proceedings of the 3rd International Conference on Genetic Algorithms 

29 (ICGA'89), June 4-7, 1989, Fairfax, VA, USA, pages 116-121. San Francisco, 

30 CA, USA: Morgan Kaufmann Publishers Inc. ISBN: 1-55860-066-3 

31 https://www.researchgate.net/publication/2527551 

322. Tobias Blickle and Lothar Thiele. A Comparison of Selection Schemes used in 

33 Genetic Algorithms. Second edition, December 1995. TIK-Report 11 from the 

34 Eidgenössische Technische Hochschule (ETH) Zürich, Department of Electrical 

35 Engineering, Computer Engineering and Networks Laboratory (TIK), Zürich, 

36 Switzerland. ftp://ftp.tik.ee.ethz.ch/pub/publications/TIK-Report11.ps 

37""" 

38 

39from math import inf 

40 

41from numpy.random import Generator 

42 

43from moptipy.algorithms.so.fitness import Fitness, FRecord 

44 

45 

46# start book 

47class Rank(Fitness): 

48 """A fitness computing the rank of an individual based on its quality.""" 

49 

50 def assign_fitness(self, p: list[FRecord], random: Generator) -> None: 

51 """ 

52 Assign the rank as fitness. 

53 

54 :param p: the list of records 

55 :param random: ignored 

56 

57 >>> l = [FRecord(0, 10), FRecord(1, 5), FRecord(2, 5), FRecord(3, -1)] 

58 >>> from numpy.random import default_rng 

59 >>> Rank().assign_fitness(l, default_rng()) 

60 >>> l[0].x 

61 3 

62 >>> l[0].fitness 

63 1 

64 >>> l[1].x 

65 1 

66 >>> l[1].fitness 

67 2 

68 >>> l[2].x 

69 2 

70 >>> l[2].fitness 

71 2 

72 >>> l[3].x 

73 0 

74 >>> l[3].fitness 

75 4 

76 """ 

77 for rec in p: # first copy rec.f to rec.fitness 

78 rec.fitness = rec.f # because then we can easily sort 

79 p.sort() # sort based on objective values 

80 

81 rank: int = -1 # the variable for storing the current rank 

82 last_f: int | float = -inf # the previous objective value 

83 for i, rec in enumerate(p): # iterate over list 

84 v = rec.fitness # get the current objective value 

85 if v > last_f: # only increase rank if objective f changes 

86 rank = i + 1 # +1 so smallest-possible fitness is 1 

87 last_f = v # remember objective value for comparison 

88 rec.fitness = rank # assign the rank (same f = same rank) 

89# end book 

90 

91 def __str__(self): 

92 """ 

93 Get the name of this rank-based fitness assignment. 

94 

95 :return: the name of this fitness assignment strategy 

96 :retval "rank": always 

97 """ 

98 return "rank"