Source code for scm.glompo.stoppers.minstepsize
import logging
from typing import Sequence, Tuple
import numpy as np
from .basestopper import BaseStopper
from ..common.helpers import distance, is_bounds_valid
from ..core.optimizerlogger import BaseLogger
from ...plams.core.settings import Settings
__all__ = ("MinStepSize",)
[docs]class MinStepSize(BaseStopper):
"""Monitors distance in parameter space between function evaluations.
This stopper will stop an optimizer that is excessively focused on one area of parameter space.
:Parameters:
bounds
Bounds of each parameter.
calls
Number of function evaluations over which to perform the averaging.
relative_tol
Fraction (between 0 and 1) of the maximum distance in the space (from the point at all lower bounds to the point
at all upper bounds) below which the optimizers are deemed too close and the tested optimizer will be stopped.
:Returns:
bool
``True`` if the tested optimizer's average step size over the last ``calls`` function evaluations is less than::
relative_tol * maximum_parameter_space_distance
"""
def __init__(self, bounds: Sequence[Tuple[float, float]], calls: int, relative_tol: float = 0.05):
super().__init__()
self.calls = calls
self.tol = relative_tol
if is_bounds_valid(bounds):
lower_pt, upper_pt = tuple(np.transpose(bounds))
self.trans_space_dist = distance(lower_pt, upper_pt)
def __call__(self, log: BaseLogger, best_opt_id: int, tested_opt_id: int) -> bool:
trials = log.get_history(tested_opt_id, "x")[-self.calls :]
self.last_result = False
if len(trials) >= self.calls:
dists = map(distance, trials[1:], trials[:-1])
mean_dist = np.mean([*dists])
self.last_result = mean_dist <= self.tol * self.trans_space_dist
if self.logger.isEnabledFor(logging.DEBUG):
self.logger.debug(
f"{best_opt_id} -> {tested_opt_id}\n"
f"Mean: {mean_dist}\n"
f"Maximum Trans Space Distance: {self.trans_space_dist}\n"
f"Returning: {self.last_result}"
)
return self.last_result
def __amssettings__(self, s: Settings) -> Settings:
s.input.ams.Stopper.Type = "MinStepSize"
s.input.ams.Stopper.MinStepSize.NumberOfFunctionCalls = self.calls
s.input.ams.Stopper.MinStepSize.Tolerance = self.tol
return s