Source code for scm.glompo.stoppers.bestfunctionvalueunmoving

from .basestopper import BaseStopper
from ..core.optimizerlogger import BaseLogger
from ...plams.core.settings import Settings

__all__ = ("BestFunctionValueUnmoving",)


[docs]class BestFunctionValueUnmoving(BaseStopper): """Considers the lowest function value seen by the optimizer thus far. Returns ``True`` if the tested optimizer's best value has not changed significantly in a given amount of time. :Parameters: calls Number of function evaluations between comparison points. tol Tolerance fraction between 0 and 1. :Returns: bool ``True`` if:: abs(latest_f_value - f_value_calls_ago) <= abs(f_value_calls_ago * self.tol) """ def __init__(self, calls: int, tol: float = 0): super().__init__() self.calls = calls self.tol = tol def __call__(self, log: BaseLogger, best_opt_id: int, tested_opt_id: int) -> bool: vals = log.get_history(tested_opt_id, "fx") fcalls = log.len(tested_opt_id) if fcalls <= self.calls: # If there are insufficient iterations the stopper will return False self.last_result = False return self.last_result best_at_calls = min(vals[: -self.calls]) best_at_end = min(vals) self.last_result = abs(best_at_end - best_at_calls) <= abs(best_at_calls * self.tol) return self.last_result def __amssettings__(self, s: Settings) -> Settings: s.input.ams.Stopper.Type = "BestFunctionValueUnmoving" s.input.ams.Stopper.BestFunctionValueUnmoving.NumberOfFunctionCalls = self.calls s.input.ams.Stopper.BestFunctionValueUnmoving.Tolerance = self.tol return s