Coverage for moptipy / evaluation / ertecdf.py: 91%
22 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"""
2Approximate the ECDF over the ERT to reach certain goals.
4The empirical cumulative distribution function (ECDF, see
5:mod:`~moptipy.evaluation.ecdf`) is a function that shows the fraction of runs
6that were successful in attaining a certain goal objective value over the
7time. The (empirically estimated) Expected Running Time (ERT, see
8:mod:`~moptipy.evaluation.ert`) is a function that tries to give an estimate
9how long a given algorithm setup will need (y-axis) to achieve given solution
10qualities (x-axis). It uses a set of runs of the algorithm on the problem to
11make this estimate under the assumption of independent restarts.
13Now in the ERT-ECDF we combine both concepts to join several different
14optimization problems or problem instances into one plot. The goal becomes
15"solving the problem". For each problem instance, we compute the ERT, i.e.,
16estimate how long a given algorithm will need to reach the goal. This becomes
17the time axis. Over this time axis, the ERT-ECDF displays the fraction of
18instances that were solved.
201. Thomas Weise, Zhize Wu, Xinlu Li, and Yan Chen. Frequency Fitness
21 Assignment: Making Optimization Algorithms Invariant under Bijective
22 Transformations of the Objective Function Value. *IEEE Transactions on
23 Evolutionary Computation* 25(2):307-319. April 2021. Preprint available at
24 arXiv:2001.01416v5 [cs.NE] 15 Oct 2020. http://arxiv.org/abs/2001.01416.
25 doi: https://doi.org/10.1109/TEVC.2020.3032090
26"""
28from dataclasses import dataclass
29from typing import Any, Callable, Iterable
31from moptipy.evaluation.ecdf import Ecdf
32from moptipy.evaluation.ert import compute_single_ert
33from moptipy.evaluation.progress import Progress
36@dataclass(frozen=True, init=False, order=False, eq=False)
37class ErtEcdf(Ecdf):
38 """The ERT-ECDF."""
40 def time_label(self) -> str:
41 """
42 Get the time axis label.
44 :return: the time key
45 """
46 return f"ERT\u2009[{self.time_unit}]"
48 def _time_key(self) -> str:
49 """
50 Get the time key.
52 :return: the time key
53 """
54 return f"ert[{super()._time_key()}]"
56 @staticmethod
57 def _compute_times(source: list[Progress],
58 goal: int | float) -> list[float]:
59 """
60 Compute the times for the given goals.
62 Warning: `source` must only contain progress objects that contain
63 monotonously improving points. It must not contain runs that may get
64 worse over time.
66 :param source: the source array
67 :param goal: the goal value
68 :return: a list of times
69 """
70 return [compute_single_ert(source, goal)]
72 # noinspection PyUnusedLocal
73 @staticmethod
74 def _get_div(n: int, n_insts: int) -> int:
75 """
76 Get the divisor.
78 :param n: the number of runs
79 :param n_insts: the number of instances
80 :return: the divisor
81 """
82 del n
83 return n_insts
86def create(source: Iterable[Progress],
87 goal_f: int | float | Callable[[str], int | float] | None = None,
88 use_default_goal_f: bool = True) -> Ecdf:
89 """
90 Create one single Ert-Ecdf record from an iterable of Progress records.
92 :param source: the set of progress instances
93 :param goal_f: the goal objective value
94 :param use_default_goal_f: should we use the default lower bounds as
95 goals?
96 :return: the Ert-Ecdf record
97 """
98 return ErtEcdf._create(source, goal_f, use_default_goal_f)
101def from_progresses(
102 source: Iterable[Progress], consumer: Callable[[Ecdf], Any],
103 f_goal: int | float | Callable[[str], int | float]
104 | Iterable[int | float | Callable] | None = None,
105 join_all_algorithms: bool = False,
106 join_all_objectives: bool = False,
107 join_all_encodings: bool = False) -> None:
108 """
109 Compute one or multiple Ert-ECDFs from a stream of end results.
111 :param source: the set of progress instances
112 :param f_goal: one or multiple goal values
113 :param consumer: the destination to which the new records will be
114 passed, can be the `append` method of a :class:`list`
115 :param join_all_algorithms: should the Ecdf be aggregated over all
116 algorithms
117 :param join_all_objectives: should the Ecdf be aggregated over all
118 objective functions
119 :param join_all_encodings: should the Ecdf be aggregated over all
120 encodings
121 """
122 return ErtEcdf._from_progresses(
123 source, consumer, f_goal, join_all_algorithms,
124 join_all_objectives, join_all_encodings)