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