Source code for moptipy.tests.fitness
"""Test fitness assignment processes."""
from math import inf, isfinite
from typing import Final, cast
from numpy.random import Generator, default_rng
from pycommons.types import type_error
from moptipy.algorithms.so.fitness import Fitness, FRecord, check_fitness
from moptipy.api.objective import Objective
from moptipy.api.operators import Op0
from moptipy.api.space import Space
from moptipy.tests.component import validate_component
from moptipy.utils.nputils import rand_seed_generate
class _FRecord(FRecord):
"""The internal F-record."""
def __init__(self, x, z):
"""Initialize."""
super().__init__(x, inf)
#: the internal id
self.z: Final[int] = z
[docs]
def validate_fitness(fitness: Fitness, objective: Objective, space: Space,
op0: Op0) -> None:
"""
Validate a fitness assignment process on a given problem.
:param fitness: the fitness assignment process
:param objective: the objective function
:param space: the space of solutions
:param op0: the nullary operator
"""
if not isinstance(fitness, Fitness):
raise type_error(fitness, "fitness", Fitness)
check_fitness(fitness)
validate_component(fitness)
random: Final[Generator] = default_rng()
pop1: Final[list[_FRecord]] = []
pop2: Final[list[_FRecord]] = []
pop3: Final[list[_FRecord]] = []
ps: Final[int] = int(1 + random.integers(48))
for i in range(ps):
fr: _FRecord = _FRecord(space.create(), i)
op0.op0(random, fr.x)
fr.f = objective.evaluate(fr.x)
fr.it = int(random.integers(1, 20))
if fr.fitness != inf:
raise ValueError(f"v = {fr.fitness}, should be inf")
pop1.append(fr)
fr2: _FRecord = _FRecord(fr.x, fr.z)
fr2.f = fr.f
fr2.it = fr.it
pop2.append(fr2)
fr2 = _FRecord(fr.x, fr.z)
fr2.f = fr.f
fr2.it = fr.it
pop3.append(fr2)
for k in range(6):
if k >= 3:
# make all records identical
fr0 = pop1[0]
for i in range(ps):
fr = _FRecord(fr0.x, i)
fr.f = fr0.f
fr.it = fr0.it
fr.fitness = fr0.fitness
pop1[i] = fr
fr = _FRecord(fr0.x, i)
fr.f = fr0.f
fr.it = fr0.it
fr.fitness = fr0.fitness
pop2[i] = fr
fr = _FRecord(fr0.x, i)
fr.f = fr0.f
fr.it = fr0.it
fr.fitness = fr0.fitness
pop3[i] = fr
if k in (2, 4):
for fr in pop1:
if random.integers(2) <= 0:
fr.fitness = inf if random.integers(2) <= 0 else -inf
seed: int = rand_seed_generate()
fitness.initialize()
fitness.assign_fitness(cast(list[FRecord], pop1), default_rng(seed))
fitness.initialize()
fitness.assign_fitness(cast(list[FRecord], pop3), default_rng(seed))
pop1.sort(key=lambda r: r.z)
pop3.sort(key=lambda r: r.z)
for i, fr in enumerate(pop1):
if not isinstance(fr, _FRecord):
raise type_error(fr, f"pop[{i}]", _FRecord)
fr2 = pop2[i]
if fr.x is not fr2.x:
raise ValueError("fitness assignment changed x reference!")
if fr.it is not fr2.it:
raise ValueError(
f"fitness assignment assigned rec.it to {fr.it}!")
if fr.f is not fr2.f:
raise ValueError(
f"fitness assignment assigned rec.f to {fr.f}!")
if not isinstance(fr.fitness, int | float):
raise type_error(fr.fitness, "rec.fitness", (int, float))
if not isfinite(fr.fitness):
raise ValueError(
f"rec.fitness should be finite, but is {fr.fitness}")
fr2 = pop3[i]
if (fr2.fitness != fr.fitness) or (fr2.f is not fr.f) or \
(fr2.it is not fr.it) or (fr2.x is not fr.x):
raise ValueError(f"inconsistency detected when repeating "
f"fitness assignment: {str(fr2)!r} != "
f"{str(fr)!r} at index {i} of population "
f"of length {len(pop1)}.")