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
« 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.
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.
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
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`).
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"""
39from math import inf
41from numpy.random import Generator
43from moptipy.algorithms.so.fitness import Fitness, FRecord
46# start book
47class Rank(Fitness):
48 """A fitness computing the rank of an individual based on its quality."""
50 def assign_fitness(self, p: list[FRecord], random: Generator) -> None:
51 """
52 Assign the rank as fitness.
54 :param p: the list of records
55 :param random: ignored
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
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
91 def __str__(self):
92 """
93 Get the name of this rank-based fitness assignment.
95 :return: the name of this fitness assignment strategy
96 :retval "rank": always
97 """
98 return "rank"