decent_bench.metrics.utils#

decent_bench.metrics.utils.x_mean(agents: tuple[AgentMetricsView, ...], iteration: int = -1) Array[source]#

Calculate the mean x at iteration (or using the agents’ final x if iteration is -1).

Agents that did not reach iteration are disregarded.

Raises:

ValueError – if no agent reached iteration

decent_bench.metrics.utils.all_sorted_iterations(agents: Sequence[AgentMetricsView]) list[int][source]#

Get a sorted list of all iterations reached by any agent in agents.

Parameters:

agents – sequence of agents to get the iterations from

Returns:

sorted list of iterations reached by any agent

decent_bench.metrics.utils.linear_convergence_rate(y: Sequence[float]) float[source]#

Compute the linear (a.k.a. exponential or geometric) convergence rate from a given trajectory.

Fits a piecewise linear model to the log10-scaled trajectory to identify the transitory phase and extract its slope. The convergence rate is then computed as \(10^{\text{slope}}\), giving the multiplicative factor by which the error decreases per iteration during the transitory phase. A convergence rate below \(1\) indicates convergence, while above \(1\) indicates divergence. The smaller the convergence rate, the faster the convergence.

Parameters:

y – sequence of error values from optimization trajectory (assumed to be positive)

Returns:

the convergence rate (multiplicative factor per iteration)

Example

>>> print("Convergence rate of:")
>>> for alg, results in metric_results.plot_results.items():
>>>     for metric, stat_results in results.items():
>>>         if type(metric) == metric_library.GradientNorm:
>>>             print(f"\t- {alg.name}: {utils.linear_convergence_rate(stat_results[1])}")
decent_bench.metrics.utils.fit_elbow_curve(y: ndarray[tuple[Any, ...], dtype[float64]], max_trials: int = 10, tol: float = 1e-5, num_grid_points: int = 10) tuple[float, float, int][source]#

Fit a piecewise linear “elbow curve” to data.

Fits two connected line segments to the input data: one with a slope for the transitory phase and one horizontal for the steady-state phase. Formally, the elbow curve is defined as

\[\begin{split}f(x) = \begin{cases} s x + y_0 & \text{if } x \leq b \\ s b + y_0 & \text{if } x > b \end{cases}\end{split}\]

where \(s\) is the slope, \(y_0\) is the intercept, \(b\) the breakpoint. The parameters \(s\), \(y_0\), and \(b\) are fitted to the input data using linear regression with an analytical solution (for efficiency), and grid search to find the optimal breakpoint.

Parameters:
  • y – 1D array of data points to fit

  • max_trials – maximum number of refinement iterations for grid search

  • tol – grid search stops when fit of residual is less than this value

  • num_grid_points – number of candidate breakpoints to evaluate in each grid search iteration

Returns:

the intercept, slope, and breakpoint fitted to the data

Note

A large value of max_trials, a small value of tol, a large value of num_grid_points will increase the accuracy of the fit, but will require longer computational time.

Note

numpy.nan, numpy.inf or -numpy.inf values in y are disregarded during the fit. These values might occur in case of divergence (there is only a transient phase, with positive slope), and discarding them allows to still fit the slope.

Raises:

ValueError – if the input arguments are invalid