Source code for optilab.optimizers.cma_es

"""
CMA-ES optimizer: Covariance Matrix Adaptation Evolution Strategy.
"""

import cma

from ..data_classes import Bounds, PointList
from ..functions import ObjectiveFunction
from .optimizer import Optimizer


[docs] class CmaEs(Optimizer): """ CMA-ES optimizer: Covariance Matrix Adaptation Evolution Strategy. """
[docs] def __init__( self, population_size: int, sigma0: float, ): """ Class constructor. Args: population_size: Size of the population. sigma0: Starting value of the sigma, """ super().__init__( "cma-es", population_size, {"sigma0": sigma0}, )
[docs] @staticmethod def _stop_internal( es: cma.CMAEvolutionStrategy, ) -> bool: """ Check an instance of CMA-ES optimizer for internal stop criteria. Args: es: An instance of CMA-ES optimizer. Returns: If true, the internal stop criteria of CMA-ES have been reached and optimization should be ended. """ return es.stop()
[docs] @staticmethod def _spawn_cmaes( bounds: Bounds, dim: int, population_size: int, sigma0: float, ) -> cma.CMAEvolutionStrategy: """ Create a new instance of cma optimizer. Args: bounds: The bounds of the search area. dim: The dimensionality of the search area. Returns: A new cma optimizer instance. """ return cma.CMAEvolutionStrategy( bounds.random_point(dim).x, sigma0, { "popsize": population_size, "bounds": bounds.to_list(), "verbose": -9, }, )
[docs] def _stop( self, es: cma.CMAEvolutionStrategy, log: PointList, population_size: int, call_budget: int, target: float, tolerance: float, ) -> bool: """ Decide if the optimization should be stopped. Args: es: CMA-ES instance. log: Results log. population_size: The size of the population in one generation. call_budget: Maximum number of optimized function calls. target: Global minimum value of the optimized function. tolerance: Tolerated error value of the optimization. Returns: True if the optimization should be stopped. """ return self._stop_internal(es) or self._stop_external( log, population_size, call_budget, target, tolerance, )
[docs] def optimize( self, function: ObjectiveFunction, bounds: Bounds, call_budget: int, tolerance: float, target: float = 0.0, ) -> PointList: """ Run a single optimization of provided objective function. Args: function: Objective function to optimize. bounds: Search space of the function. call_budget: Max number of calls to the objective function. tolerance: Tolerance of y value to count a solution as acceptable. target: Objective function value target, default 0. Returns: Results log from the optimization. """ es = self._spawn_cmaes( bounds, function.metadata.dim, self.metadata.population_size, self.metadata.hyperparameters["sigma0"], ) res_log = PointList(points=[]) while not self._stop( es, res_log, self.metadata.population_size, call_budget, target, tolerance, ): solutions = PointList.from_list(es.ask()) results = PointList(points=[function(x) for x in solutions.points]) res_log.extend(results) x, y = results.pairs() es.tell(x, y) return res_log