From f92fd3f9c1303d2c2b2a24149ab57160b91753fa Mon Sep 17 00:00:00 2001 From: Gulshan Kumar Date: Tue, 6 May 2025 08:17:38 +0530 Subject: [PATCH 01/16] Inspiration from merged commit --- src/optimagic/algorithms.py | 34 ++++- .../optimizers/nevergrad_optimizers.py | 126 +++++++++++++++++- 2 files changed, 158 insertions(+), 2 deletions(-) diff --git a/src/optimagic/algorithms.py b/src/optimagic/algorithms.py index 588514e95..3dec5cd63 100644 --- a/src/optimagic/algorithms.py +++ b/src/optimagic/algorithms.py @@ -18,7 +18,7 @@ from optimagic.optimizers.ipopt import Ipopt from optimagic.optimizers.nag_optimizers import NagDFOLS, NagPyBOBYQA from optimagic.optimizers.neldermead import NelderMeadParallel -from optimagic.optimizers.nevergrad_optimizers import NevergradPSO +from optimagic.optimizers.nevergrad_optimizers import NevergradOnePlusOne, NevergradPSO from optimagic.optimizers.nlopt_optimizers import ( NloptBOBYQA, NloptCCSAQ, @@ -207,6 +207,7 @@ class BoundedGradientFreeLocalNonlinearConstrainedScalarAlgorithms(AlgoSelection @dataclass(frozen=True) class BoundedGradientFreeLocalParallelScalarAlgorithms(AlgoSelection): + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne tranquilo: Type[Tranquilo] = Tranquilo @@ -493,6 +494,7 @@ def Scalar(self) -> BoundedGradientFreeLocalNonlinearConstrainedScalarAlgorithms @dataclass(frozen=True) class BoundedGradientFreeLocalScalarAlgorithms(AlgoSelection): nag_pybobyqa: Type[NagPyBOBYQA] = NagPyBOBYQA + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nlopt_bobyqa: Type[NloptBOBYQA] = NloptBOBYQA nlopt_cobyla: Type[NloptCOBYLA] = NloptCOBYLA nlopt_newuoa: Type[NloptNEWUOA] = NloptNEWUOA @@ -527,6 +529,7 @@ def Parallel(self) -> BoundedGradientFreeLeastSquaresLocalParallelAlgorithms: @dataclass(frozen=True) class BoundedGradientFreeLocalParallelAlgorithms(AlgoSelection): + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne pounders: Type[Pounders] = Pounders tranquilo: Type[Tranquilo] = Tranquilo tranquilo_ls: Type[TranquiloLS] = TranquiloLS @@ -553,6 +556,7 @@ def Bounded(self) -> BoundedGradientFreeLocalNonlinearConstrainedScalarAlgorithm @dataclass(frozen=True) class GradientFreeLocalParallelScalarAlgorithms(AlgoSelection): neldermead_parallel: Type[NelderMeadParallel] = NelderMeadParallel + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne tranquilo: Type[Tranquilo] = Tranquilo @property @@ -610,6 +614,7 @@ def Scalar(self) -> BoundedGradientFreeNonlinearConstrainedParallelScalarAlgorit @dataclass(frozen=True) class BoundedGradientFreeParallelScalarAlgorithms(AlgoSelection): + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nevergrad_pso: Type[NevergradPSO] = NevergradPSO pygmo_gaco: Type[PygmoGaco] = PygmoGaco pygmo_pso_gen: Type[PygmoPsoGen] = PygmoPsoGen @@ -765,6 +770,7 @@ def GradientFree( @dataclass(frozen=True) class BoundedLocalParallelScalarAlgorithms(AlgoSelection): + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne tranquilo: Type[Tranquilo] = Tranquilo @property @@ -1167,6 +1173,7 @@ def Scalar(self) -> GlobalGradientFreeParallelScalarAlgorithms: class BoundedGradientFreeLocalAlgorithms(AlgoSelection): nag_dfols: Type[NagDFOLS] = NagDFOLS nag_pybobyqa: Type[NagPyBOBYQA] = NagPyBOBYQA + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nlopt_bobyqa: Type[NloptBOBYQA] = NloptBOBYQA nlopt_cobyla: Type[NloptCOBYLA] = NloptCOBYLA nlopt_newuoa: Type[NloptNEWUOA] = NloptNEWUOA @@ -1216,6 +1223,7 @@ def Scalar(self) -> GradientFreeLocalNonlinearConstrainedScalarAlgorithms: class GradientFreeLocalScalarAlgorithms(AlgoSelection): nag_pybobyqa: Type[NagPyBOBYQA] = NagPyBOBYQA neldermead_parallel: Type[NelderMeadParallel] = NelderMeadParallel + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nlopt_bobyqa: Type[NloptBOBYQA] = NloptBOBYQA nlopt_cobyla: Type[NloptCOBYLA] = NloptCOBYLA nlopt_newuoa: Type[NloptNEWUOA] = NloptNEWUOA @@ -1261,6 +1269,7 @@ def Parallel(self) -> GradientFreeLeastSquaresLocalParallelAlgorithms: @dataclass(frozen=True) class GradientFreeLocalParallelAlgorithms(AlgoSelection): neldermead_parallel: Type[NelderMeadParallel] = NelderMeadParallel + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne pounders: Type[Pounders] = Pounders tranquilo: Type[Tranquilo] = Tranquilo tranquilo_ls: Type[TranquiloLS] = TranquiloLS @@ -1306,6 +1315,7 @@ def Scalar(self) -> BoundedGradientFreeNonlinearConstrainedScalarAlgorithms: @dataclass(frozen=True) class BoundedGradientFreeScalarAlgorithms(AlgoSelection): nag_pybobyqa: Type[NagPyBOBYQA] = NagPyBOBYQA + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nevergrad_pso: Type[NevergradPSO] = NevergradPSO nlopt_bobyqa: Type[NloptBOBYQA] = NloptBOBYQA nlopt_cobyla: Type[NloptCOBYLA] = NloptCOBYLA @@ -1378,6 +1388,7 @@ def Parallel(self) -> BoundedGradientFreeLeastSquaresParallelAlgorithms: @dataclass(frozen=True) class BoundedGradientFreeParallelAlgorithms(AlgoSelection): + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nevergrad_pso: Type[NevergradPSO] = NevergradPSO pounders: Type[Pounders] = Pounders pygmo_gaco: Type[PygmoGaco] = PygmoGaco @@ -1460,6 +1471,7 @@ def Scalar(self) -> GradientFreeNonlinearConstrainedParallelScalarAlgorithms: @dataclass(frozen=True) class GradientFreeParallelScalarAlgorithms(AlgoSelection): neldermead_parallel: Type[NelderMeadParallel] = NelderMeadParallel + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nevergrad_pso: Type[NevergradPSO] = NevergradPSO pygmo_gaco: Type[PygmoGaco] = PygmoGaco pygmo_pso_gen: Type[PygmoPsoGen] = PygmoPsoGen @@ -1698,6 +1710,7 @@ class BoundedLocalScalarAlgorithms(AlgoSelection): iminuit_migrad: Type[IminuitMigrad] = IminuitMigrad ipopt: Type[Ipopt] = Ipopt nag_pybobyqa: Type[NagPyBOBYQA] = NagPyBOBYQA + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nlopt_bobyqa: Type[NloptBOBYQA] = NloptBOBYQA nlopt_ccsaq: Type[NloptCCSAQ] = NloptCCSAQ nlopt_cobyla: Type[NloptCOBYLA] = NloptCOBYLA @@ -1758,6 +1771,7 @@ def Parallel(self) -> BoundedLeastSquaresLocalParallelAlgorithms: @dataclass(frozen=True) class BoundedLocalParallelAlgorithms(AlgoSelection): + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne pounders: Type[Pounders] = Pounders tranquilo: Type[Tranquilo] = Tranquilo tranquilo_ls: Type[TranquiloLS] = TranquiloLS @@ -1801,6 +1815,7 @@ def GradientFree(self) -> GradientFreeLocalNonlinearConstrainedScalarAlgorithms: @dataclass(frozen=True) class LocalParallelScalarAlgorithms(AlgoSelection): neldermead_parallel: Type[NelderMeadParallel] = NelderMeadParallel + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne tranquilo: Type[Tranquilo] = Tranquilo @property @@ -1882,6 +1897,7 @@ def Scalar(self) -> BoundedNonlinearConstrainedParallelScalarAlgorithms: @dataclass(frozen=True) class BoundedParallelScalarAlgorithms(AlgoSelection): + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nevergrad_pso: Type[NevergradPSO] = NevergradPSO pygmo_gaco: Type[PygmoGaco] = PygmoGaco pygmo_pso_gen: Type[PygmoPsoGen] = PygmoPsoGen @@ -2190,6 +2206,7 @@ class GradientFreeLocalAlgorithms(AlgoSelection): nag_dfols: Type[NagDFOLS] = NagDFOLS nag_pybobyqa: Type[NagPyBOBYQA] = NagPyBOBYQA neldermead_parallel: Type[NelderMeadParallel] = NelderMeadParallel + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nlopt_bobyqa: Type[NloptBOBYQA] = NloptBOBYQA nlopt_cobyla: Type[NloptCOBYLA] = NloptCOBYLA nlopt_newuoa: Type[NloptNEWUOA] = NloptNEWUOA @@ -2229,6 +2246,7 @@ def Scalar(self) -> GradientFreeLocalScalarAlgorithms: class BoundedGradientFreeAlgorithms(AlgoSelection): nag_dfols: Type[NagDFOLS] = NagDFOLS nag_pybobyqa: Type[NagPyBOBYQA] = NagPyBOBYQA + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nevergrad_pso: Type[NevergradPSO] = NevergradPSO nlopt_bobyqa: Type[NloptBOBYQA] = NloptBOBYQA nlopt_cobyla: Type[NloptCOBYLA] = NloptCOBYLA @@ -2326,6 +2344,7 @@ def Scalar(self) -> GradientFreeNonlinearConstrainedScalarAlgorithms: class GradientFreeScalarAlgorithms(AlgoSelection): nag_pybobyqa: Type[NagPyBOBYQA] = NagPyBOBYQA neldermead_parallel: Type[NelderMeadParallel] = NelderMeadParallel + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nevergrad_pso: Type[NevergradPSO] = NevergradPSO nlopt_bobyqa: Type[NloptBOBYQA] = NloptBOBYQA nlopt_cobyla: Type[NloptCOBYLA] = NloptCOBYLA @@ -2407,6 +2426,7 @@ def Parallel(self) -> GradientFreeLeastSquaresParallelAlgorithms: @dataclass(frozen=True) class GradientFreeParallelAlgorithms(AlgoSelection): neldermead_parallel: Type[NelderMeadParallel] = NelderMeadParallel + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nevergrad_pso: Type[NevergradPSO] = NevergradPSO pounders: Type[Pounders] = Pounders pygmo_gaco: Type[PygmoGaco] = PygmoGaco @@ -2614,6 +2634,7 @@ class BoundedLocalAlgorithms(AlgoSelection): ipopt: Type[Ipopt] = Ipopt nag_dfols: Type[NagDFOLS] = NagDFOLS nag_pybobyqa: Type[NagPyBOBYQA] = NagPyBOBYQA + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nlopt_bobyqa: Type[NloptBOBYQA] = NloptBOBYQA nlopt_ccsaq: Type[NloptCCSAQ] = NloptCCSAQ nlopt_cobyla: Type[NloptCOBYLA] = NloptCOBYLA @@ -2697,6 +2718,7 @@ class LocalScalarAlgorithms(AlgoSelection): ipopt: Type[Ipopt] = Ipopt nag_pybobyqa: Type[NagPyBOBYQA] = NagPyBOBYQA neldermead_parallel: Type[NelderMeadParallel] = NelderMeadParallel + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nlopt_bobyqa: Type[NloptBOBYQA] = NloptBOBYQA nlopt_ccsaq: Type[NloptCCSAQ] = NloptCCSAQ nlopt_cobyla: Type[NloptCOBYLA] = NloptCOBYLA @@ -2781,6 +2803,7 @@ def GradientBased(self) -> GradientBasedLikelihoodLocalAlgorithms: @dataclass(frozen=True) class LocalParallelAlgorithms(AlgoSelection): neldermead_parallel: Type[NelderMeadParallel] = NelderMeadParallel + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne pounders: Type[Pounders] = Pounders tranquilo: Type[Tranquilo] = Tranquilo tranquilo_ls: Type[TranquiloLS] = TranquiloLS @@ -2847,6 +2870,7 @@ class BoundedScalarAlgorithms(AlgoSelection): iminuit_migrad: Type[IminuitMigrad] = IminuitMigrad ipopt: Type[Ipopt] = Ipopt nag_pybobyqa: Type[NagPyBOBYQA] = NagPyBOBYQA + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nevergrad_pso: Type[NevergradPSO] = NevergradPSO nlopt_bobyqa: Type[NloptBOBYQA] = NloptBOBYQA nlopt_ccsaq: Type[NloptCCSAQ] = NloptCCSAQ @@ -2948,6 +2972,7 @@ def Parallel(self) -> BoundedLeastSquaresParallelAlgorithms: @dataclass(frozen=True) class BoundedParallelAlgorithms(AlgoSelection): + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nevergrad_pso: Type[NevergradPSO] = NevergradPSO pounders: Type[Pounders] = Pounders pygmo_gaco: Type[PygmoGaco] = PygmoGaco @@ -3050,6 +3075,7 @@ def Scalar(self) -> NonlinearConstrainedParallelScalarAlgorithms: @dataclass(frozen=True) class ParallelScalarAlgorithms(AlgoSelection): neldermead_parallel: Type[NelderMeadParallel] = NelderMeadParallel + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nevergrad_pso: Type[NevergradPSO] = NevergradPSO pygmo_gaco: Type[PygmoGaco] = PygmoGaco pygmo_pso_gen: Type[PygmoPsoGen] = PygmoPsoGen @@ -3158,6 +3184,7 @@ class GradientFreeAlgorithms(AlgoSelection): nag_dfols: Type[NagDFOLS] = NagDFOLS nag_pybobyqa: Type[NagPyBOBYQA] = NagPyBOBYQA neldermead_parallel: Type[NelderMeadParallel] = NelderMeadParallel + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nevergrad_pso: Type[NevergradPSO] = NevergradPSO nlopt_bobyqa: Type[NloptBOBYQA] = NloptBOBYQA nlopt_cobyla: Type[NloptCOBYLA] = NloptCOBYLA @@ -3293,6 +3320,7 @@ class LocalAlgorithms(AlgoSelection): nag_dfols: Type[NagDFOLS] = NagDFOLS nag_pybobyqa: Type[NagPyBOBYQA] = NagPyBOBYQA neldermead_parallel: Type[NelderMeadParallel] = NelderMeadParallel + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nlopt_bobyqa: Type[NloptBOBYQA] = NloptBOBYQA nlopt_ccsaq: Type[NloptCCSAQ] = NloptCCSAQ nlopt_cobyla: Type[NloptCOBYLA] = NloptCOBYLA @@ -3363,6 +3391,7 @@ class BoundedAlgorithms(AlgoSelection): ipopt: Type[Ipopt] = Ipopt nag_dfols: Type[NagDFOLS] = NagDFOLS nag_pybobyqa: Type[NagPyBOBYQA] = NagPyBOBYQA + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nevergrad_pso: Type[NevergradPSO] = NevergradPSO nlopt_bobyqa: Type[NloptBOBYQA] = NloptBOBYQA nlopt_ccsaq: Type[NloptCCSAQ] = NloptCCSAQ @@ -3500,6 +3529,7 @@ class ScalarAlgorithms(AlgoSelection): ipopt: Type[Ipopt] = Ipopt nag_pybobyqa: Type[NagPyBOBYQA] = NagPyBOBYQA neldermead_parallel: Type[NelderMeadParallel] = NelderMeadParallel + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nevergrad_pso: Type[NevergradPSO] = NevergradPSO nlopt_bobyqa: Type[NloptBOBYQA] = NloptBOBYQA nlopt_ccsaq: Type[NloptCCSAQ] = NloptCCSAQ @@ -3629,6 +3659,7 @@ def Local(self) -> LikelihoodLocalAlgorithms: @dataclass(frozen=True) class ParallelAlgorithms(AlgoSelection): neldermead_parallel: Type[NelderMeadParallel] = NelderMeadParallel + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nevergrad_pso: Type[NevergradPSO] = NevergradPSO pounders: Type[Pounders] = Pounders pygmo_gaco: Type[PygmoGaco] = PygmoGaco @@ -3678,6 +3709,7 @@ class Algorithms(AlgoSelection): nag_dfols: Type[NagDFOLS] = NagDFOLS nag_pybobyqa: Type[NagPyBOBYQA] = NagPyBOBYQA neldermead_parallel: Type[NelderMeadParallel] = NelderMeadParallel + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nevergrad_pso: Type[NevergradPSO] = NevergradPSO nlopt_bobyqa: Type[NloptBOBYQA] = NloptBOBYQA nlopt_ccsaq: Type[NloptCCSAQ] = NloptCCSAQ diff --git a/src/optimagic/optimizers/nevergrad_optimizers.py b/src/optimagic/optimizers/nevergrad_optimizers.py index 5ec0023bf..5b73fa31f 100644 --- a/src/optimagic/optimizers/nevergrad_optimizers.py +++ b/src/optimagic/optimizers/nevergrad_optimizers.py @@ -2,7 +2,7 @@ import math from dataclasses import dataclass -from typing import Literal +from typing import Literal, Tuple import numpy as np from numpy.typing import NDArray @@ -108,3 +108,127 @@ def _solve_internal_problem( ) return result + + +@mark.minimizer( + name="nevergrad_oneplusone", + solver_type=AggregationLevel.SCALAR, + is_available=IS_NEVERGRAD_INSTALLED, + is_global=False, + needs_jac=False, + needs_hess=False, + supports_parallelism=True, + supports_bounds=True, + supports_linear_constraints=False, + supports_nonlinear_constraints=False, + disable_history=False, +) +@dataclass(frozen=True) +class NevergradOnePlusOne(Algorithm): + noise_handling: str | Tuple[str, float] | None = None + mutation: Literal[ + "gaussian", + "cauchy", + "discrete", + "fastga", + "rls", + "doublefastga", + "adaptive", + "coordinatewise_adaptive", + "portfolio", + "discreteBSO", + "lengler", + "lengler2", + "lengler3", + "lenglerhalf", + "lenglerfourth", + "doerr", + "lognormal", + "xlognormal", + "xsmalllognormal", + "tinylognormal", + "lognormal", + "smalllognormal", + "biglognormal", + "hugelognormal", + ] = "gaussian" + annealing: Literal[ + "none", "Exp0.9", "Exp0.99", "Exp0.9Auto", "Lin100.0", "Lin1.0", "LinAuto" + ] = "none" + sparse: bool | int = False + super_radii: bool = False + smoother: bool = False + roulette_size: int = 2 + antismooth: int = 55 + crossover: bool = False + crossover_type: Literal["none", "rand", "max", "min", "onepoint", "twopoint"] = ( + "none" + ) + tabu_length: int = 0 + rotation: bool = False + seed: int | None = None + + stopping_maxfun: PositiveInt = STOPPING_MAXFUN_GLOBAL + n_cores: PositiveInt = 1 + + def _solve_internal_problem( + self, problem: InternalOptimizationProblem, x0: NDArray[np.float64] + ) -> InternalOptimizeResult: + if not IS_NEVERGRAD_INSTALLED: + raise NotInstalledError( + "The nevergrad_pso optimizer requires the 'nevergrad' package to be " + "installed. You can install it with `pip install nevergrad`. " + "Visit https://facebookresearch.github.io/nevergrad/getting_started.html" + " for more detailed installation instructions." + ) + + instrum = ng.p.Instrumentation( + ng.p.Array(init=x0, lower=problem.bounds.lower, upper=problem.bounds.upper) + ) + if self.seed is not None: + instrum.random_state.seed(self.seed) + + optimizer = ng.optimizers.ParametrizedOnePlusOne( + noise_handling=self.noise_handling, + tabu_length=self.tabu_length, + mutation=self.mutation, + crossover=self.crossover, + rotation=self.rotation, + annealing=self.annealing, + sparse=self.sparse, + smoother=self.smoother, + super_radii=self.super_radii, + roulette_size=self.roulette_size, + antismooth=self.antismooth, + crossover_type=self.crossover_type, + )( + parametrization=instrum, + budget=self.stopping_maxfun, + num_workers=self.n_cores, + ) + + while optimizer.num_ask < self.stopping_maxfun: + x_list = [ + optimizer.ask() + for _ in range( + min(self.n_cores, self.stopping_maxfun - optimizer.num_ask) + ) + ] + losses = problem.batch_fun( + [x.value[0][0] for x in x_list], n_cores=self.n_cores + ) + for x, loss in zip(x_list, losses, strict=True): + optimizer.tell(x, loss) + + recommendation = optimizer.provide_recommendation() + + result = InternalOptimizeResult( + x=recommendation.value[0][0], + fun=recommendation.loss, + success=True, + n_fun_evals=optimizer.num_ask, + n_jac_evals=0, + n_hess_evals=0, + ) + + return result From 7c9e0ab1ea131fc38756eb7fedec8275c28a4e98 Mon Sep 17 00:00:00 2001 From: Gulshan Kumar Date: Tue, 6 May 2025 08:37:34 +0530 Subject: [PATCH 02/16] changed bound setting method to avoid nan and inf --- src/optimagic/optimizers/nevergrad_optimizers.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/optimagic/optimizers/nevergrad_optimizers.py b/src/optimagic/optimizers/nevergrad_optimizers.py index 5b73fa31f..90d28a4bd 100644 --- a/src/optimagic/optimizers/nevergrad_optimizers.py +++ b/src/optimagic/optimizers/nevergrad_optimizers.py @@ -182,9 +182,11 @@ def _solve_internal_problem( " for more detailed installation instructions." ) - instrum = ng.p.Instrumentation( - ng.p.Array(init=x0, lower=problem.bounds.lower, upper=problem.bounds.upper) + instrum = ng.p.Array(init=x0).set_bounds( + lower=problem.bounds.lower, upper=problem.bounds.upper ) + instrum = ng.p.Instrumentation(instrum) + if self.seed is not None: instrum.random_state.seed(self.seed) From 940f18f60f2165052420f7cf0acbea3452c05081 Mon Sep 17 00:00:00 2001 From: Gulshan Kumar Date: Tue, 6 May 2025 10:30:10 +0530 Subject: [PATCH 03/16] Mutation added to avoid looking at inf, some parameter tuning --- src/optimagic/optimizers/nevergrad_optimizers.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/optimagic/optimizers/nevergrad_optimizers.py b/src/optimagic/optimizers/nevergrad_optimizers.py index 90d28a4bd..ace9552e5 100644 --- a/src/optimagic/optimizers/nevergrad_optimizers.py +++ b/src/optimagic/optimizers/nevergrad_optimizers.py @@ -151,20 +151,20 @@ class NevergradOnePlusOne(Algorithm): "smalllognormal", "biglognormal", "hugelognormal", - ] = "gaussian" + ] = "cauchy" annealing: Literal[ "none", "Exp0.9", "Exp0.99", "Exp0.9Auto", "Lin100.0", "Lin1.0", "LinAuto" ] = "none" sparse: bool | int = False super_radii: bool = False smoother: bool = False - roulette_size: int = 2 - antismooth: int = 55 + roulette_size: int = 64 + antismooth: int = 10 crossover: bool = False crossover_type: Literal["none", "rand", "max", "min", "onepoint", "twopoint"] = ( "none" ) - tabu_length: int = 0 + tabu_length: int = 10000 rotation: bool = False seed: int | None = None @@ -182,9 +182,10 @@ def _solve_internal_problem( " for more detailed installation instructions." ) - instrum = ng.p.Array(init=x0).set_bounds( - lower=problem.bounds.lower, upper=problem.bounds.upper - ) + instrum = ng.p.Array( + init=x0, lower=problem.bounds.lower, upper=problem.bounds.upper + ).set_mutation(sigma=1.0 + 1e-7) + instrum.specify_tabu_length(tabu_length=self.tabu_length) instrum = ng.p.Instrumentation(instrum) if self.seed is not None: @@ -192,7 +193,6 @@ def _solve_internal_problem( optimizer = ng.optimizers.ParametrizedOnePlusOne( noise_handling=self.noise_handling, - tabu_length=self.tabu_length, mutation=self.mutation, crossover=self.crossover, rotation=self.rotation, From 80c7e632419a451508fc830b091f9092ef11116a Mon Sep 17 00:00:00 2001 From: Gulshan Kumar Date: Sun, 25 May 2025 10:49:13 +0530 Subject: [PATCH 04/16] is global=true and default gaussian --- src/optimagic/optimizers/nevergrad_optimizers.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/optimagic/optimizers/nevergrad_optimizers.py b/src/optimagic/optimizers/nevergrad_optimizers.py index 3c48aa8d5..438a1317b 100644 --- a/src/optimagic/optimizers/nevergrad_optimizers.py +++ b/src/optimagic/optimizers/nevergrad_optimizers.py @@ -114,7 +114,7 @@ def _solve_internal_problem( name="nevergrad_oneplusone", solver_type=AggregationLevel.SCALAR, is_available=IS_NEVERGRAD_INSTALLED, - is_global=False, + is_global=True, needs_jac=False, needs_hess=False, supports_parallelism=True, @@ -151,7 +151,7 @@ class NevergradOnePlusOne(Algorithm): "smalllognormal", "biglognormal", "hugelognormal", - ] = "cauchy" + ] = "gaussian" annealing: Literal[ "none", "Exp0.9", "Exp0.99", "Exp0.9Auto", "Lin100.0", "Lin1.0", "LinAuto" ] = "none" @@ -184,7 +184,7 @@ def _solve_internal_problem( instrum = ng.p.Array( init=x0, lower=problem.bounds.lower, upper=problem.bounds.upper - ).set_mutation(sigma=1.0 + 1e-7) + ) instrum.specify_tabu_length(tabu_length=self.tabu_length) instrum = ng.p.Instrumentation(instrum) From 4fd75fef3d1b19456a211bac1b37cea95b0caddb Mon Sep 17 00:00:00 2001 From: Gulshan Kumar Date: Sun, 25 May 2025 10:52:52 +0530 Subject: [PATCH 05/16] Finalise documentation with suggestions fixed added docs Docs success build updated docs done with suggestions --- docs/source/algorithms.md | 81 +++++++++++++++++++ docs/source/refs.bib | 51 ++++++++++++ src/optimagic/algorithms.py | 32 ++++---- .../optimizers/nevergrad_optimizers.py | 8 +- 4 files changed, 152 insertions(+), 20 deletions(-) diff --git a/docs/source/algorithms.md b/docs/source/algorithms.md index d9e43a004..cc2173cbe 100644 --- a/docs/source/algorithms.md +++ b/docs/source/algorithms.md @@ -4043,6 +4043,87 @@ these optimizers, you need to have initialization for speed. Default is False. ``` +```{eval-rst} +.. dropdown:: nevergrad_oneplusone + + .. code-block:: + + "nevergrad_oneplusone" + + Minimize a scalar function using the One Plus One algorithm. + + The One Plus One algorithm was originally proposed by + :cite:`Rechenberg1973`. The implementation in Nevergrad is based on + the one-fifth adaptation rule, going back to :cite:`Schumer1968`, discovered independently by :cite:`devroye1972` and :cite:`Rechenberg1973`. + + An One Plus One evolutionary algorithm iterates to find a set of parameters that + produce the best possible registration result. It does this by + perturbing, or mutating, the parameters from the last iteration (the + parent). If the new (child) parameters yield a better result, then + the child becomes the new parent whose parameters are perturbed, + perhaps more aggressively. If the parent yields a better result, it + remains the parent and the next perturbation is less aggressive. + + - **noise\_handling** (str or Tuple\[str, float] or None): Method for handling the noise. The name can be (Default: `None`). + - `"random"`: A random point is reevaluated regularly using the one-fifth adaptation rule. + - `"optimistic"`: The best optimistic point is reevaluated regularly, embracing optimism in the face of uncertainty. + - A float coefficient can be provided to tune the regularity of these reevaluations (default is 0.05). Eg: with 0.05, each evaluation has a 5% chance (i.e., 1 in 20) of being repeated (i.e., the same candidate solution is reevaluated to better estimate its performance). + + - **n_cores** (int): Number of cores to use. + - **stopping.maxfun** (int): Maximum number of function evaluations. + + - **mutation** (str): Type of mutation to apply. Available options are (Default: `"gaussian"`) + - `"gaussian"`: Standard mutation by adding a Gaussian random variable (with progressive widening) to the best pessimistic point. + - `"cauchy"`: Same as Gaussian but using a Cauchy distribution. + - `"discrete"`: Mutates a randomly drawn variable (mutation occurs with probability 1/d in d dimensions, hence \~1 variable per mutation). + - `"discreteBSO"`: Follows brainstorm optimization by gradually decreasing mutation rate from 1 to 1/d. + - `"fastga"`: Fast Genetic Algorithm mutations from the current best. + - `"doublefastga"`: Double-FastGA mutations from the current best :cite:`doerr2017`. + - `"rls"`: Randomized Local Search — mutates one and only one variable. + - `"portfolio"`: Random number of mutated bits, known as uniform mixing :cite:`dang2016`. + - `"lengler"`: Mutation rate is a function of dimension and iteration index. + - `"lengler{2|3|half|fourth}"`: Variants of the Lengler mutation rate adaptation. + + - **crossover** (bool): Whether to include a genetic crossover step every other iteration. Default is `False`. + + - **use\_pareto** (bool): Whether to restart from a random Pareto-optimal element in multi-objective mode, instead of the last one added. Default is `False`. + + - **sparse** (bool): Whether to apply random mutations that set variables to zero. Default is `False`. + + - **smoother** (bool): Whether to suggest smooth mutations. Default is `False`. + + - **annealing** (`str`): Annealing schedule to apply to mutation amplitude or temperature-based control. Options are: + + - `"none"`: No annealing is applied. + - `"Exp0.9"`: Exponential decay with rate 0.9. + - `"Exp0.99"`: Exponential decay with rate 0.99. + - `"Exp0.9Auto"`: Exponential decay with rate 0.9, auto-scaled based on problem horizon. + - `"Lin100.0"`: Linear decay from 1 to 0 over 100 iterations. + - `"Lin1.0"`: Linear decay from 1 to 0 over 1 iteration. + - `"LinAuto"`: Linearly decaying annealing automatically scaled to the problem horizon. + Default is `"none"`. + + - **super\_radii** (`bool`): Whether to apply extended radii beyond standard bounds for candidate generation, enabling broader exploration. + Default is `False`. + + - **roulette\_size** (`int`): Size of the roulette wheel used for selection in the evolutionary process. Affects the sampling diversity from past candidates. (Default: `64`) + + - **antismooth** (`int`): Degree of anti-smoothing applied to prevent premature convergence in smooth landscapes. This alters the landscape by penalizing overly smooth improvements. (Default: `4`) + + - **crossover\_type** (`str`): Method used for genetic crossover between individuals in the population. Available options (Default: `"none"`): + - `"none"`: No crossover is applied. + - `"rand"`: Randomized selection of crossover point. + - `"max"`: Crossover at the point with maximum fitness gain. + - `"min"`: Crossover at the point with minimum fitness gain. + - `"onepoint"`: One-point crossover, splitting the genome at a single random point. + - `"twopoint"`: Two-point crossover, splitting the genome at two points and exchanging the middle section. + + - **tabu\_length** (`int`): Length of the tabu list used to prevent revisiting recently evaluated candidates in local search strategies. Helps in escaping local minima. (Default: `1000`) + + - **rotation** (`bool`): Whether to apply rotational transformations to the search space, promoting invariance to axis-aligned structures and enhancing search performance in rotated coordinate systems. (Deafult: `False`) + +``` + ## References ```{eval-rst} diff --git a/docs/source/refs.bib b/docs/source/refs.bib index 6a52fc279..a3c3a9a5b 100644 --- a/docs/source/refs.bib +++ b/docs/source/refs.bib @@ -927,4 +927,55 @@ @InProceedings{Zambrano2013 doi = {10.1109/CEC.2013.6557848}, } +@book{Rechenberg1973, + author = {Rechenberg, Ingo}, + title = {Evolutionsstrategie: Optimierung technischer Systeme nach Prinzipien der biologischen Evolution}, + publisher = {Frommann-Holzboog Verlag}, + year = {1973}, + url = {https://gwern.net/doc/reinforcement-learning/exploration/1973-rechenberg.pdf}, + address = {Stuttgart}, + note = {[Evolution Strategy: Optimization of Technical Systems According to the Principles of Biological Evolution]} +} + +@article{Schumer1968, + author={Schumer, M. and Steiglitz, K.}, + journal={IEEE Transactions on Automatic Control}, + title={Adaptive step size random search}, + year={1968}, + volume={13}, + number={3}, + pages={270-276}, + keywords={Minimization methods;Gradient methods;Search methods;Adaptive control;Communication systems;Q measurement;Cost function;Newton method;Military computing}, + doi={10.1109/TAC.1968.1098903} +} + +@misc{doerr2017, + title={Fast Genetic Algorithms}, + author={Benjamin Doerr and Huu Phuoc Le and Régis Makhmara and Ta Duy Nguyen}, + year={2017}, + eprint={1703.03334}, + archivePrefix={arXiv}, + primaryClass={cs.NE}, + url={https://arxiv.org/abs/1703.03334}, +} + +@misc{dang2016, + title={Self-adaptation of Mutation Rates in Non-elitist Populations}, + author={Duc-Cuong Dang and Per Kristian Lehre}, + year={2016}, + eprint={1606.05551}, + archivePrefix={arXiv}, + primaryClass={cs.NE}, + url={https://arxiv.org/abs/1606.05551}, +} + +@inproceedings{devroye1972, + author = {Luc Devroye}, + title = {The compound random search algorithm}, + booktitle = {Proceedings of the International Symposium on Systems Engineering}, + pages = {105--110}, + year = {1972}, + url = {https://luc.devroye.org/devroye-crsa1972.pdf} +} + @Comment{jabref-meta: databaseType:bibtex;} diff --git a/src/optimagic/algorithms.py b/src/optimagic/algorithms.py index 3dec5cd63..002b59c1b 100644 --- a/src/optimagic/algorithms.py +++ b/src/optimagic/algorithms.py @@ -172,6 +172,7 @@ def Scalar( @dataclass(frozen=True) class BoundedGlobalGradientFreeParallelScalarAlgorithms(AlgoSelection): + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nevergrad_pso: Type[NevergradPSO] = NevergradPSO pygmo_gaco: Type[PygmoGaco] = PygmoGaco pygmo_pso_gen: Type[PygmoPsoGen] = PygmoPsoGen @@ -207,7 +208,6 @@ class BoundedGradientFreeLocalNonlinearConstrainedScalarAlgorithms(AlgoSelection @dataclass(frozen=True) class BoundedGradientFreeLocalParallelScalarAlgorithms(AlgoSelection): - nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne tranquilo: Type[Tranquilo] = Tranquilo @@ -367,6 +367,7 @@ def Scalar(self) -> BoundedGlobalGradientFreeNonlinearConstrainedScalarAlgorithm @dataclass(frozen=True) class BoundedGlobalGradientFreeScalarAlgorithms(AlgoSelection): + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nevergrad_pso: Type[NevergradPSO] = NevergradPSO nlopt_crs2_lm: Type[NloptCRS2LM] = NloptCRS2LM nlopt_direct: Type[NloptDirect] = NloptDirect @@ -407,6 +408,7 @@ def Parallel(self) -> BoundedGlobalGradientFreeParallelScalarAlgorithms: @dataclass(frozen=True) class BoundedGlobalGradientFreeParallelAlgorithms(AlgoSelection): + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nevergrad_pso: Type[NevergradPSO] = NevergradPSO pygmo_gaco: Type[PygmoGaco] = PygmoGaco pygmo_pso_gen: Type[PygmoPsoGen] = PygmoPsoGen @@ -463,6 +465,7 @@ def Scalar(self) -> GlobalGradientFreeNonlinearConstrainedParallelScalarAlgorith @dataclass(frozen=True) class GlobalGradientFreeParallelScalarAlgorithms(AlgoSelection): + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nevergrad_pso: Type[NevergradPSO] = NevergradPSO pygmo_gaco: Type[PygmoGaco] = PygmoGaco pygmo_pso_gen: Type[PygmoPsoGen] = PygmoPsoGen @@ -494,7 +497,6 @@ def Scalar(self) -> BoundedGradientFreeLocalNonlinearConstrainedScalarAlgorithms @dataclass(frozen=True) class BoundedGradientFreeLocalScalarAlgorithms(AlgoSelection): nag_pybobyqa: Type[NagPyBOBYQA] = NagPyBOBYQA - nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nlopt_bobyqa: Type[NloptBOBYQA] = NloptBOBYQA nlopt_cobyla: Type[NloptCOBYLA] = NloptCOBYLA nlopt_newuoa: Type[NloptNEWUOA] = NloptNEWUOA @@ -529,7 +531,6 @@ def Parallel(self) -> BoundedGradientFreeLeastSquaresLocalParallelAlgorithms: @dataclass(frozen=True) class BoundedGradientFreeLocalParallelAlgorithms(AlgoSelection): - nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne pounders: Type[Pounders] = Pounders tranquilo: Type[Tranquilo] = Tranquilo tranquilo_ls: Type[TranquiloLS] = TranquiloLS @@ -556,7 +557,6 @@ def Bounded(self) -> BoundedGradientFreeLocalNonlinearConstrainedScalarAlgorithm @dataclass(frozen=True) class GradientFreeLocalParallelScalarAlgorithms(AlgoSelection): neldermead_parallel: Type[NelderMeadParallel] = NelderMeadParallel - nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne tranquilo: Type[Tranquilo] = Tranquilo @property @@ -710,6 +710,7 @@ def Scalar(self) -> BoundedGlobalNonlinearConstrainedParallelScalarAlgorithms: @dataclass(frozen=True) class BoundedGlobalParallelScalarAlgorithms(AlgoSelection): + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nevergrad_pso: Type[NevergradPSO] = NevergradPSO pygmo_gaco: Type[PygmoGaco] = PygmoGaco pygmo_pso_gen: Type[PygmoPsoGen] = PygmoPsoGen @@ -770,7 +771,6 @@ def GradientFree( @dataclass(frozen=True) class BoundedLocalParallelScalarAlgorithms(AlgoSelection): - nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne tranquilo: Type[Tranquilo] = Tranquilo @property @@ -1038,6 +1038,7 @@ def Local(self) -> GradientBasedLocalNonlinearConstrainedScalarAlgorithms: @dataclass(frozen=True) class BoundedGlobalGradientFreeAlgorithms(AlgoSelection): + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nevergrad_pso: Type[NevergradPSO] = NevergradPSO nlopt_crs2_lm: Type[NloptCRS2LM] = NloptCRS2LM nlopt_direct: Type[NloptDirect] = NloptDirect @@ -1102,6 +1103,7 @@ def Scalar(self) -> GlobalGradientFreeNonlinearConstrainedScalarAlgorithms: @dataclass(frozen=True) class GlobalGradientFreeScalarAlgorithms(AlgoSelection): + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nevergrad_pso: Type[NevergradPSO] = NevergradPSO nlopt_crs2_lm: Type[NloptCRS2LM] = NloptCRS2LM nlopt_direct: Type[NloptDirect] = NloptDirect @@ -1146,6 +1148,7 @@ def Parallel(self) -> GlobalGradientFreeParallelScalarAlgorithms: @dataclass(frozen=True) class GlobalGradientFreeParallelAlgorithms(AlgoSelection): + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nevergrad_pso: Type[NevergradPSO] = NevergradPSO pygmo_gaco: Type[PygmoGaco] = PygmoGaco pygmo_pso_gen: Type[PygmoPsoGen] = PygmoPsoGen @@ -1173,7 +1176,6 @@ def Scalar(self) -> GlobalGradientFreeParallelScalarAlgorithms: class BoundedGradientFreeLocalAlgorithms(AlgoSelection): nag_dfols: Type[NagDFOLS] = NagDFOLS nag_pybobyqa: Type[NagPyBOBYQA] = NagPyBOBYQA - nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nlopt_bobyqa: Type[NloptBOBYQA] = NloptBOBYQA nlopt_cobyla: Type[NloptCOBYLA] = NloptCOBYLA nlopt_newuoa: Type[NloptNEWUOA] = NloptNEWUOA @@ -1223,7 +1225,6 @@ def Scalar(self) -> GradientFreeLocalNonlinearConstrainedScalarAlgorithms: class GradientFreeLocalScalarAlgorithms(AlgoSelection): nag_pybobyqa: Type[NagPyBOBYQA] = NagPyBOBYQA neldermead_parallel: Type[NelderMeadParallel] = NelderMeadParallel - nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nlopt_bobyqa: Type[NloptBOBYQA] = NloptBOBYQA nlopt_cobyla: Type[NloptCOBYLA] = NloptCOBYLA nlopt_newuoa: Type[NloptNEWUOA] = NloptNEWUOA @@ -1269,7 +1270,6 @@ def Parallel(self) -> GradientFreeLeastSquaresLocalParallelAlgorithms: @dataclass(frozen=True) class GradientFreeLocalParallelAlgorithms(AlgoSelection): neldermead_parallel: Type[NelderMeadParallel] = NelderMeadParallel - nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne pounders: Type[Pounders] = Pounders tranquilo: Type[Tranquilo] = Tranquilo tranquilo_ls: Type[TranquiloLS] = TranquiloLS @@ -1541,6 +1541,7 @@ def Scalar(self) -> BoundedGlobalNonlinearConstrainedScalarAlgorithms: @dataclass(frozen=True) class BoundedGlobalScalarAlgorithms(AlgoSelection): + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nevergrad_pso: Type[NevergradPSO] = NevergradPSO nlopt_crs2_lm: Type[NloptCRS2LM] = NloptCRS2LM nlopt_direct: Type[NloptDirect] = NloptDirect @@ -1590,6 +1591,7 @@ def Parallel(self) -> BoundedGlobalParallelScalarAlgorithms: @dataclass(frozen=True) class BoundedGlobalParallelAlgorithms(AlgoSelection): + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nevergrad_pso: Type[NevergradPSO] = NevergradPSO pygmo_gaco: Type[PygmoGaco] = PygmoGaco pygmo_pso_gen: Type[PygmoPsoGen] = PygmoPsoGen @@ -1659,6 +1661,7 @@ def Scalar(self) -> GlobalNonlinearConstrainedParallelScalarAlgorithms: @dataclass(frozen=True) class GlobalParallelScalarAlgorithms(AlgoSelection): + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nevergrad_pso: Type[NevergradPSO] = NevergradPSO pygmo_gaco: Type[PygmoGaco] = PygmoGaco pygmo_pso_gen: Type[PygmoPsoGen] = PygmoPsoGen @@ -1710,7 +1713,6 @@ class BoundedLocalScalarAlgorithms(AlgoSelection): iminuit_migrad: Type[IminuitMigrad] = IminuitMigrad ipopt: Type[Ipopt] = Ipopt nag_pybobyqa: Type[NagPyBOBYQA] = NagPyBOBYQA - nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nlopt_bobyqa: Type[NloptBOBYQA] = NloptBOBYQA nlopt_ccsaq: Type[NloptCCSAQ] = NloptCCSAQ nlopt_cobyla: Type[NloptCOBYLA] = NloptCOBYLA @@ -1771,7 +1773,6 @@ def Parallel(self) -> BoundedLeastSquaresLocalParallelAlgorithms: @dataclass(frozen=True) class BoundedLocalParallelAlgorithms(AlgoSelection): - nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne pounders: Type[Pounders] = Pounders tranquilo: Type[Tranquilo] = Tranquilo tranquilo_ls: Type[TranquiloLS] = TranquiloLS @@ -1815,7 +1816,6 @@ def GradientFree(self) -> GradientFreeLocalNonlinearConstrainedScalarAlgorithms: @dataclass(frozen=True) class LocalParallelScalarAlgorithms(AlgoSelection): neldermead_parallel: Type[NelderMeadParallel] = NelderMeadParallel - nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne tranquilo: Type[Tranquilo] = Tranquilo @property @@ -2157,6 +2157,7 @@ def Local(self) -> GradientBasedLikelihoodLocalAlgorithms: @dataclass(frozen=True) class GlobalGradientFreeAlgorithms(AlgoSelection): + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nevergrad_pso: Type[NevergradPSO] = NevergradPSO nlopt_crs2_lm: Type[NloptCRS2LM] = NloptCRS2LM nlopt_direct: Type[NloptDirect] = NloptDirect @@ -2206,7 +2207,6 @@ class GradientFreeLocalAlgorithms(AlgoSelection): nag_dfols: Type[NagDFOLS] = NagDFOLS nag_pybobyqa: Type[NagPyBOBYQA] = NagPyBOBYQA neldermead_parallel: Type[NelderMeadParallel] = NelderMeadParallel - nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nlopt_bobyqa: Type[NloptBOBYQA] = NloptBOBYQA nlopt_cobyla: Type[NloptCOBYLA] = NloptCOBYLA nlopt_newuoa: Type[NloptNEWUOA] = NloptNEWUOA @@ -2467,6 +2467,7 @@ def Scalar(self) -> GradientFreeParallelScalarAlgorithms: @dataclass(frozen=True) class BoundedGlobalAlgorithms(AlgoSelection): + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nevergrad_pso: Type[NevergradPSO] = NevergradPSO nlopt_crs2_lm: Type[NloptCRS2LM] = NloptCRS2LM nlopt_direct: Type[NloptDirect] = NloptDirect @@ -2549,6 +2550,7 @@ def Scalar(self) -> GlobalNonlinearConstrainedScalarAlgorithms: @dataclass(frozen=True) class GlobalScalarAlgorithms(AlgoSelection): + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nevergrad_pso: Type[NevergradPSO] = NevergradPSO nlopt_crs2_lm: Type[NloptCRS2LM] = NloptCRS2LM nlopt_direct: Type[NloptDirect] = NloptDirect @@ -2602,6 +2604,7 @@ def Parallel(self) -> GlobalParallelScalarAlgorithms: @dataclass(frozen=True) class GlobalParallelAlgorithms(AlgoSelection): + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nevergrad_pso: Type[NevergradPSO] = NevergradPSO pygmo_gaco: Type[PygmoGaco] = PygmoGaco pygmo_pso_gen: Type[PygmoPsoGen] = PygmoPsoGen @@ -2634,7 +2637,6 @@ class BoundedLocalAlgorithms(AlgoSelection): ipopt: Type[Ipopt] = Ipopt nag_dfols: Type[NagDFOLS] = NagDFOLS nag_pybobyqa: Type[NagPyBOBYQA] = NagPyBOBYQA - nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nlopt_bobyqa: Type[NloptBOBYQA] = NloptBOBYQA nlopt_ccsaq: Type[NloptCCSAQ] = NloptCCSAQ nlopt_cobyla: Type[NloptCOBYLA] = NloptCOBYLA @@ -2718,7 +2720,6 @@ class LocalScalarAlgorithms(AlgoSelection): ipopt: Type[Ipopt] = Ipopt nag_pybobyqa: Type[NagPyBOBYQA] = NagPyBOBYQA neldermead_parallel: Type[NelderMeadParallel] = NelderMeadParallel - nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nlopt_bobyqa: Type[NloptBOBYQA] = NloptBOBYQA nlopt_ccsaq: Type[NloptCCSAQ] = NloptCCSAQ nlopt_cobyla: Type[NloptCOBYLA] = NloptCOBYLA @@ -2803,7 +2804,6 @@ def GradientBased(self) -> GradientBasedLikelihoodLocalAlgorithms: @dataclass(frozen=True) class LocalParallelAlgorithms(AlgoSelection): neldermead_parallel: Type[NelderMeadParallel] = NelderMeadParallel - nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne pounders: Type[Pounders] = Pounders tranquilo: Type[Tranquilo] = Tranquilo tranquilo_ls: Type[TranquiloLS] = TranquiloLS @@ -3256,6 +3256,7 @@ def Scalar(self) -> GradientFreeScalarAlgorithms: @dataclass(frozen=True) class GlobalAlgorithms(AlgoSelection): + nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nevergrad_pso: Type[NevergradPSO] = NevergradPSO nlopt_crs2_lm: Type[NloptCRS2LM] = NloptCRS2LM nlopt_direct: Type[NloptDirect] = NloptDirect @@ -3320,7 +3321,6 @@ class LocalAlgorithms(AlgoSelection): nag_dfols: Type[NagDFOLS] = NagDFOLS nag_pybobyqa: Type[NagPyBOBYQA] = NagPyBOBYQA neldermead_parallel: Type[NelderMeadParallel] = NelderMeadParallel - nevergrad_oneplusone: Type[NevergradOnePlusOne] = NevergradOnePlusOne nlopt_bobyqa: Type[NloptBOBYQA] = NloptBOBYQA nlopt_ccsaq: Type[NloptCCSAQ] = NloptCCSAQ nlopt_cobyla: Type[NloptCOBYLA] = NloptCOBYLA diff --git a/src/optimagic/optimizers/nevergrad_optimizers.py b/src/optimagic/optimizers/nevergrad_optimizers.py index 438a1317b..e2b008410 100644 --- a/src/optimagic/optimizers/nevergrad_optimizers.py +++ b/src/optimagic/optimizers/nevergrad_optimizers.py @@ -159,12 +159,12 @@ class NevergradOnePlusOne(Algorithm): super_radii: bool = False smoother: bool = False roulette_size: int = 64 - antismooth: int = 10 + antismooth: int = 4 crossover: bool = False crossover_type: Literal["none", "rand", "max", "min", "onepoint", "twopoint"] = ( "none" ) - tabu_length: int = 10000 + tabu_length: int = 1000 rotation: bool = False seed: int | None = None @@ -176,8 +176,8 @@ def _solve_internal_problem( ) -> InternalOptimizeResult: if not IS_NEVERGRAD_INSTALLED: raise NotInstalledError( - "The nevergrad_pso optimizer requires the 'nevergrad' package to be " - "installed. You can install it with `pip install nevergrad`. " + "The nevergrad_oneplusone optimizer requires the 'nevergrad' package " + "to be installed. You can install it with `pip install nevergrad`. " "Visit https://facebookresearch.github.io/nevergrad/getting_started.html" " for more detailed installation instructions." ) From b662d8cc922655ad3029d1da00b8f52fb97c2dc9 Mon Sep 17 00:00:00 2001 From: Gulshan Kumar Date: Mon, 26 May 2025 22:44:24 +0530 Subject: [PATCH 06/16] added docs clarification and improve typehinting --- docs/source/algorithms.md | 3 ++- src/optimagic/optimizers/nevergrad_optimizers.py | 10 +++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/source/algorithms.md b/docs/source/algorithms.md index cc2173cbe..5a59520ce 100644 --- a/docs/source/algorithms.md +++ b/docs/source/algorithms.md @@ -4057,7 +4057,7 @@ these optimizers, you need to have the one-fifth adaptation rule, going back to :cite:`Schumer1968`, discovered independently by :cite:`devroye1972` and :cite:`Rechenberg1973`. An One Plus One evolutionary algorithm iterates to find a set of parameters that - produce the best possible registration result. It does this by + minimizes the loss function. It does this by perturbing, or mutating, the parameters from the last iteration (the parent). If the new (child) parameters yield a better result, then the child becomes the new parent whose parameters are perturbed, @@ -4067,6 +4067,7 @@ these optimizers, you need to have - **noise\_handling** (str or Tuple\[str, float] or None): Method for handling the noise. The name can be (Default: `None`). - `"random"`: A random point is reevaluated regularly using the one-fifth adaptation rule. - `"optimistic"`: The best optimistic point is reevaluated regularly, embracing optimism in the face of uncertainty. + - `"none"`: In this case, the algorithm assumes the function is deterministic. - A float coefficient can be provided to tune the regularity of these reevaluations (default is 0.05). Eg: with 0.05, each evaluation has a 5% chance (i.e., 1 in 20) of being repeated (i.e., the same candidate solution is reevaluated to better estimate its performance). - **n_cores** (int): Number of cores to use. diff --git a/src/optimagic/optimizers/nevergrad_optimizers.py b/src/optimagic/optimizers/nevergrad_optimizers.py index e2b008410..a8594cac1 100644 --- a/src/optimagic/optimizers/nevergrad_optimizers.py +++ b/src/optimagic/optimizers/nevergrad_optimizers.py @@ -15,7 +15,7 @@ from optimagic.optimization.internal_optimization_problem import ( InternalOptimizationProblem, ) -from optimagic.typing import AggregationLevel, PositiveInt +from optimagic.typing import AggregationLevel, NonNegativeInt, PositiveInt if IS_NEVERGRAD_INSTALLED: import nevergrad as ng @@ -155,16 +155,16 @@ class NevergradOnePlusOne(Algorithm): annealing: Literal[ "none", "Exp0.9", "Exp0.99", "Exp0.9Auto", "Lin100.0", "Lin1.0", "LinAuto" ] = "none" - sparse: bool | int = False + sparse: bool = False super_radii: bool = False smoother: bool = False - roulette_size: int = 64 - antismooth: int = 4 + roulette_size: PositiveInt = 64 + antismooth: NonNegativeInt = 4 crossover: bool = False crossover_type: Literal["none", "rand", "max", "min", "onepoint", "twopoint"] = ( "none" ) - tabu_length: int = 1000 + tabu_length: NonNegativeInt = 1000 rotation: bool = False seed: int | None = None From 95a671ced2e845f724600a96068bf4d7958c76a1 Mon Sep 17 00:00:00 2001 From: gauravmanmode Date: Mon, 23 Jun 2025 21:18:41 +0530 Subject: [PATCH 07/16] Update algorithms.md --- docs/source/algorithms.md | 82 --------------------------------------- 1 file changed, 82 deletions(-) diff --git a/docs/source/algorithms.md b/docs/source/algorithms.md index 5a59520ce..d9e43a004 100644 --- a/docs/source/algorithms.md +++ b/docs/source/algorithms.md @@ -4043,88 +4043,6 @@ these optimizers, you need to have initialization for speed. Default is False. ``` -```{eval-rst} -.. dropdown:: nevergrad_oneplusone - - .. code-block:: - - "nevergrad_oneplusone" - - Minimize a scalar function using the One Plus One algorithm. - - The One Plus One algorithm was originally proposed by - :cite:`Rechenberg1973`. The implementation in Nevergrad is based on - the one-fifth adaptation rule, going back to :cite:`Schumer1968`, discovered independently by :cite:`devroye1972` and :cite:`Rechenberg1973`. - - An One Plus One evolutionary algorithm iterates to find a set of parameters that - minimizes the loss function. It does this by - perturbing, or mutating, the parameters from the last iteration (the - parent). If the new (child) parameters yield a better result, then - the child becomes the new parent whose parameters are perturbed, - perhaps more aggressively. If the parent yields a better result, it - remains the parent and the next perturbation is less aggressive. - - - **noise\_handling** (str or Tuple\[str, float] or None): Method for handling the noise. The name can be (Default: `None`). - - `"random"`: A random point is reevaluated regularly using the one-fifth adaptation rule. - - `"optimistic"`: The best optimistic point is reevaluated regularly, embracing optimism in the face of uncertainty. - - `"none"`: In this case, the algorithm assumes the function is deterministic. - - A float coefficient can be provided to tune the regularity of these reevaluations (default is 0.05). Eg: with 0.05, each evaluation has a 5% chance (i.e., 1 in 20) of being repeated (i.e., the same candidate solution is reevaluated to better estimate its performance). - - - **n_cores** (int): Number of cores to use. - - **stopping.maxfun** (int): Maximum number of function evaluations. - - - **mutation** (str): Type of mutation to apply. Available options are (Default: `"gaussian"`) - - `"gaussian"`: Standard mutation by adding a Gaussian random variable (with progressive widening) to the best pessimistic point. - - `"cauchy"`: Same as Gaussian but using a Cauchy distribution. - - `"discrete"`: Mutates a randomly drawn variable (mutation occurs with probability 1/d in d dimensions, hence \~1 variable per mutation). - - `"discreteBSO"`: Follows brainstorm optimization by gradually decreasing mutation rate from 1 to 1/d. - - `"fastga"`: Fast Genetic Algorithm mutations from the current best. - - `"doublefastga"`: Double-FastGA mutations from the current best :cite:`doerr2017`. - - `"rls"`: Randomized Local Search — mutates one and only one variable. - - `"portfolio"`: Random number of mutated bits, known as uniform mixing :cite:`dang2016`. - - `"lengler"`: Mutation rate is a function of dimension and iteration index. - - `"lengler{2|3|half|fourth}"`: Variants of the Lengler mutation rate adaptation. - - - **crossover** (bool): Whether to include a genetic crossover step every other iteration. Default is `False`. - - - **use\_pareto** (bool): Whether to restart from a random Pareto-optimal element in multi-objective mode, instead of the last one added. Default is `False`. - - - **sparse** (bool): Whether to apply random mutations that set variables to zero. Default is `False`. - - - **smoother** (bool): Whether to suggest smooth mutations. Default is `False`. - - - **annealing** (`str`): Annealing schedule to apply to mutation amplitude or temperature-based control. Options are: - - - `"none"`: No annealing is applied. - - `"Exp0.9"`: Exponential decay with rate 0.9. - - `"Exp0.99"`: Exponential decay with rate 0.99. - - `"Exp0.9Auto"`: Exponential decay with rate 0.9, auto-scaled based on problem horizon. - - `"Lin100.0"`: Linear decay from 1 to 0 over 100 iterations. - - `"Lin1.0"`: Linear decay from 1 to 0 over 1 iteration. - - `"LinAuto"`: Linearly decaying annealing automatically scaled to the problem horizon. - Default is `"none"`. - - - **super\_radii** (`bool`): Whether to apply extended radii beyond standard bounds for candidate generation, enabling broader exploration. - Default is `False`. - - - **roulette\_size** (`int`): Size of the roulette wheel used for selection in the evolutionary process. Affects the sampling diversity from past candidates. (Default: `64`) - - - **antismooth** (`int`): Degree of anti-smoothing applied to prevent premature convergence in smooth landscapes. This alters the landscape by penalizing overly smooth improvements. (Default: `4`) - - - **crossover\_type** (`str`): Method used for genetic crossover between individuals in the population. Available options (Default: `"none"`): - - `"none"`: No crossover is applied. - - `"rand"`: Randomized selection of crossover point. - - `"max"`: Crossover at the point with maximum fitness gain. - - `"min"`: Crossover at the point with minimum fitness gain. - - `"onepoint"`: One-point crossover, splitting the genome at a single random point. - - `"twopoint"`: Two-point crossover, splitting the genome at two points and exchanging the middle section. - - - **tabu\_length** (`int`): Length of the tabu list used to prevent revisiting recently evaluated candidates in local search strategies. Helps in escaping local minima. (Default: `1000`) - - - **rotation** (`bool`): Whether to apply rotational transformations to the search space, promoting invariance to axis-aligned structures and enhancing search performance in rotated coordinate systems. (Deafult: `False`) - -``` - ## References ```{eval-rst} From d263653795c0e90986abea13779057ff99011216 Mon Sep 17 00:00:00 2001 From: gauravmanmode Date: Mon, 23 Jun 2025 21:53:25 +0530 Subject: [PATCH 08/16] Move documentation to docstring and fixes --- .../optimizers/nevergrad_optimizers.py | 92 ++++++++++++++++++- 1 file changed, 89 insertions(+), 3 deletions(-) diff --git a/src/optimagic/optimizers/nevergrad_optimizers.py b/src/optimagic/optimizers/nevergrad_optimizers.py index a8594cac1..748e6d212 100644 --- a/src/optimagic/optimizers/nevergrad_optimizers.py +++ b/src/optimagic/optimizers/nevergrad_optimizers.py @@ -125,7 +125,94 @@ def _solve_internal_problem( ) @dataclass(frozen=True) class NevergradOnePlusOne(Algorithm): - noise_handling: str | Tuple[str, float] | None = None + """ + One Plus One Evolutionary algorithm from Nevergrad. + + +Args: + noise_handling: Method for handling the noise. The name can be (Default: `None`). + - "random": A random point is reevaluated regularly using the one-fifth + adaptation rule. + - "optimistic": The best optimistic point is reevaluated regularly, embracing + optimism in the face of uncertainty. + - A float coefficient can be provided to tune the regularity of these + reevaluations (default is 0.05). Eg: with 0.05, each evaluation has a 5% + chance (i.e., 1 in 20) of being repeated (i.e., the same candidate solution + is reevaluated to better estimate its performance). + + n_cores: Number of cores to use. + + stopping.maxfun: Maximum number of function evaluations. + + mutation: Type of mutation to apply. Available options are (Default: `"gaussian"`). + - "gaussian": Standard mutation by adding a Gaussian random variable (with + progressive widening) to the best pessimistic point. + - "cauchy": Same as Gaussian but using a Cauchy distribution. + - "discrete": Mutates a randomly drawn variable (mutation occurs with + probability 1/d in d dimensions, hence ~1 variable per mutation). + - "discreteBSO": Follows brainstorm optimization by gradually decreasing + mutation rate from 1 to 1/d. + - "fastga": Fast Genetic Algorithm mutations from the current best. + - "doublefastga": Double-FastGA mutations from the current best + :cite:`doerr2017`. + - "rls": Randomized Local Search — mutates one and only one variable. + - "portfolio": Random number of mutated bits, known as uniform mixing + :cite:`dang2016`. + - "lengler": Mutation rate is a function of dimension and iteration index. + - "lengler{2|3|half|fourth}": Variants of the Lengler mutation rate adaptation. + + sparse: Whether to apply random mutations that set variables to zero. Default is + `False`. + + smoother: Whether to suggest smooth mutations. Default is `False`. + + annealing: Annealing schedule to apply to mutation amplitude or temperature-based + control. Options are: + - "none": No annealing is applied. + - "Exp0.9": Exponential decay with rate 0.9. + - "Exp0.99": Exponential decay with rate 0.99. + - "Exp0.9Auto": Exponential decay with rate 0.9, auto-scaled based on problem + horizon. + - "Lin100.0": Linear decay from 1 to 0 over 100 iterations. + - "Lin1.0": Linear decay from 1 to 0 over 1 iteration. + - "LinAuto": Linearly decaying annealing automatically scaled to the problem + horizon. Default is `"none"`. + + super_radii: Whether to apply extended radii beyond standard bounds for candidate + generation, enabling broader exploration. Default is `False`. + + roulette_size: Size of the roulette wheel used for selection in the evolutionary + process. Affects the sampling diversity from past candidates. (Default: `64`) + + antismooth: Degree of anti-smoothing applied to prevent premature convergence in + smooth landscapes. This alters the landscape by penalizing overly smooth + improvements. (Default: `4`) + + crossover: Whether to include a genetic crossover step every other iteration. + Default is `False`. + + crossover_type: Method used for genetic crossover between individuals in the + population. Available options (Default: `"none"`): + - "none": No crossover is applied. + - "rand": Randomized selection of crossover point. + - "max": Crossover at the point with maximum fitness gain. + - "min": Crossover at the point with minimum fitness gain. + - "onepoint": One-point crossover, splitting the genome at a single random + point. + - "twopoint": Two-point crossover, splitting the genome at two points and + exchanging the middle section. + + tabu_length: Length of the tabu list used to prevent revisiting recently evaluated + candidates in local search strategies. Helps in escaping local minima. + (Default: `1000`) + + rotation: Whether to apply rotational transformations to the search space, + promoting invariance to axis-aligned structures and enhancing search + performance in rotated coordinate systems. (Default: `False`) + """ + + noise_handling: Literal["random", "optimistic"] | tuple[ + Literal["random", "optimistic"], float] | None = None mutation: Literal[ "gaussian", "cauchy", @@ -147,7 +234,6 @@ class NevergradOnePlusOne(Algorithm): "xlognormal", "xsmalllognormal", "tinylognormal", - "lognormal", "smalllognormal", "biglognormal", "hugelognormal", @@ -167,7 +253,6 @@ class NevergradOnePlusOne(Algorithm): tabu_length: NonNegativeInt = 1000 rotation: bool = False seed: int | None = None - stopping_maxfun: PositiveInt = STOPPING_MAXFUN_GLOBAL n_cores: PositiveInt = 1 @@ -185,6 +270,7 @@ def _solve_internal_problem( instrum = ng.p.Array( init=x0, lower=problem.bounds.lower, upper=problem.bounds.upper ) + instrum.specify_tabu_length(tabu_length=self.tabu_length) instrum = ng.p.Instrumentation(instrum) From 739574297ece83e70164d0213acc566828745e93 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 16:23:57 +0000 Subject: [PATCH 09/16] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .../optimizers/nevergrad_optimizers.py | 178 +++++++++--------- 1 file changed, 90 insertions(+), 88 deletions(-) diff --git a/src/optimagic/optimizers/nevergrad_optimizers.py b/src/optimagic/optimizers/nevergrad_optimizers.py index 748e6d212..4c347d419 100644 --- a/src/optimagic/optimizers/nevergrad_optimizers.py +++ b/src/optimagic/optimizers/nevergrad_optimizers.py @@ -2,7 +2,7 @@ import math from dataclasses import dataclass -from typing import Literal, Tuple +from typing import Literal import numpy as np from numpy.typing import NDArray @@ -125,94 +125,96 @@ def _solve_internal_problem( ) @dataclass(frozen=True) class NevergradOnePlusOne(Algorithm): + """One Plus One Evolutionary algorithm from Nevergrad. + + Args: + noise_handling: Method for handling the noise. The name can be (Default: `None`). + - "random": A random point is reevaluated regularly using the one-fifth + adaptation rule. + - "optimistic": The best optimistic point is reevaluated regularly, embracing + optimism in the face of uncertainty. + - A float coefficient can be provided to tune the regularity of these + reevaluations (default is 0.05). Eg: with 0.05, each evaluation has a 5% + chance (i.e., 1 in 20) of being repeated (i.e., the same candidate solution + is reevaluated to better estimate its performance). + + n_cores: Number of cores to use. + + stopping.maxfun: Maximum number of function evaluations. + + mutation: Type of mutation to apply. Available options are (Default: `"gaussian"`). + - "gaussian": Standard mutation by adding a Gaussian random variable (with + progressive widening) to the best pessimistic point. + - "cauchy": Same as Gaussian but using a Cauchy distribution. + - "discrete": Mutates a randomly drawn variable (mutation occurs with + probability 1/d in d dimensions, hence ~1 variable per mutation). + - "discreteBSO": Follows brainstorm optimization by gradually decreasing + mutation rate from 1 to 1/d. + - "fastga": Fast Genetic Algorithm mutations from the current best. + - "doublefastga": Double-FastGA mutations from the current best + :cite:`doerr2017`. + - "rls": Randomized Local Search — mutates one and only one variable. + - "portfolio": Random number of mutated bits, known as uniform mixing + :cite:`dang2016`. + - "lengler": Mutation rate is a function of dimension and iteration index. + - "lengler{2|3|half|fourth}": Variants of the Lengler mutation rate adaptation. + + sparse: Whether to apply random mutations that set variables to zero. Default is + `False`. + + smoother: Whether to suggest smooth mutations. Default is `False`. + + annealing: Annealing schedule to apply to mutation amplitude or temperature-based + control. Options are: + - "none": No annealing is applied. + - "Exp0.9": Exponential decay with rate 0.9. + - "Exp0.99": Exponential decay with rate 0.99. + - "Exp0.9Auto": Exponential decay with rate 0.9, auto-scaled based on problem + horizon. + - "Lin100.0": Linear decay from 1 to 0 over 100 iterations. + - "Lin1.0": Linear decay from 1 to 0 over 1 iteration. + - "LinAuto": Linearly decaying annealing automatically scaled to the problem + horizon. Default is `"none"`. + + super_radii: Whether to apply extended radii beyond standard bounds for candidate + generation, enabling broader exploration. Default is `False`. + + roulette_size: Size of the roulette wheel used for selection in the evolutionary + process. Affects the sampling diversity from past candidates. (Default: `64`) + + antismooth: Degree of anti-smoothing applied to prevent premature convergence in + smooth landscapes. This alters the landscape by penalizing overly smooth + improvements. (Default: `4`) + + crossover: Whether to include a genetic crossover step every other iteration. + Default is `False`. + + crossover_type: Method used for genetic crossover between individuals in the + population. Available options (Default: `"none"`): + - "none": No crossover is applied. + - "rand": Randomized selection of crossover point. + - "max": Crossover at the point with maximum fitness gain. + - "min": Crossover at the point with minimum fitness gain. + - "onepoint": One-point crossover, splitting the genome at a single random + point. + - "twopoint": Two-point crossover, splitting the genome at two points and + exchanging the middle section. + + tabu_length: Length of the tabu list used to prevent revisiting recently evaluated + candidates in local search strategies. Helps in escaping local minima. + (Default: `1000`) + + rotation: Whether to apply rotational transformations to the search space, + promoting invariance to axis-aligned structures and enhancing search + performance in rotated coordinate systems. (Default: `False`) + """ - One Plus One Evolutionary algorithm from Nevergrad. - - -Args: - noise_handling: Method for handling the noise. The name can be (Default: `None`). - - "random": A random point is reevaluated regularly using the one-fifth - adaptation rule. - - "optimistic": The best optimistic point is reevaluated regularly, embracing - optimism in the face of uncertainty. - - A float coefficient can be provided to tune the regularity of these - reevaluations (default is 0.05). Eg: with 0.05, each evaluation has a 5% - chance (i.e., 1 in 20) of being repeated (i.e., the same candidate solution - is reevaluated to better estimate its performance). - - n_cores: Number of cores to use. - - stopping.maxfun: Maximum number of function evaluations. - - mutation: Type of mutation to apply. Available options are (Default: `"gaussian"`). - - "gaussian": Standard mutation by adding a Gaussian random variable (with - progressive widening) to the best pessimistic point. - - "cauchy": Same as Gaussian but using a Cauchy distribution. - - "discrete": Mutates a randomly drawn variable (mutation occurs with - probability 1/d in d dimensions, hence ~1 variable per mutation). - - "discreteBSO": Follows brainstorm optimization by gradually decreasing - mutation rate from 1 to 1/d. - - "fastga": Fast Genetic Algorithm mutations from the current best. - - "doublefastga": Double-FastGA mutations from the current best - :cite:`doerr2017`. - - "rls": Randomized Local Search — mutates one and only one variable. - - "portfolio": Random number of mutated bits, known as uniform mixing - :cite:`dang2016`. - - "lengler": Mutation rate is a function of dimension and iteration index. - - "lengler{2|3|half|fourth}": Variants of the Lengler mutation rate adaptation. - - sparse: Whether to apply random mutations that set variables to zero. Default is - `False`. - - smoother: Whether to suggest smooth mutations. Default is `False`. - - annealing: Annealing schedule to apply to mutation amplitude or temperature-based - control. Options are: - - "none": No annealing is applied. - - "Exp0.9": Exponential decay with rate 0.9. - - "Exp0.99": Exponential decay with rate 0.99. - - "Exp0.9Auto": Exponential decay with rate 0.9, auto-scaled based on problem - horizon. - - "Lin100.0": Linear decay from 1 to 0 over 100 iterations. - - "Lin1.0": Linear decay from 1 to 0 over 1 iteration. - - "LinAuto": Linearly decaying annealing automatically scaled to the problem - horizon. Default is `"none"`. - - super_radii: Whether to apply extended radii beyond standard bounds for candidate - generation, enabling broader exploration. Default is `False`. - - roulette_size: Size of the roulette wheel used for selection in the evolutionary - process. Affects the sampling diversity from past candidates. (Default: `64`) - - antismooth: Degree of anti-smoothing applied to prevent premature convergence in - smooth landscapes. This alters the landscape by penalizing overly smooth - improvements. (Default: `4`) - - crossover: Whether to include a genetic crossover step every other iteration. - Default is `False`. - - crossover_type: Method used for genetic crossover between individuals in the - population. Available options (Default: `"none"`): - - "none": No crossover is applied. - - "rand": Randomized selection of crossover point. - - "max": Crossover at the point with maximum fitness gain. - - "min": Crossover at the point with minimum fitness gain. - - "onepoint": One-point crossover, splitting the genome at a single random - point. - - "twopoint": Two-point crossover, splitting the genome at two points and - exchanging the middle section. - - tabu_length: Length of the tabu list used to prevent revisiting recently evaluated - candidates in local search strategies. Helps in escaping local minima. - (Default: `1000`) - - rotation: Whether to apply rotational transformations to the search space, - promoting invariance to axis-aligned structures and enhancing search - performance in rotated coordinate systems. (Default: `False`) - """ - - noise_handling: Literal["random", "optimistic"] | tuple[ - Literal["random", "optimistic"], float] | None = None + + noise_handling: ( + Literal["random", "optimistic"] + | tuple[Literal["random", "optimistic"], float] + | None + ) = None mutation: Literal[ "gaussian", "cauchy", From 91110f5f4446e7bb333e1974b69f973ba1d1476c Mon Sep 17 00:00:00 2001 From: gauravmanmode Date: Mon, 23 Jun 2025 21:54:42 +0530 Subject: [PATCH 10/16] Update refs.bib --- docs/source/refs.bib | 8 -------- 1 file changed, 8 deletions(-) diff --git a/docs/source/refs.bib b/docs/source/refs.bib index a3c3a9a5b..2edf8f0a0 100644 --- a/docs/source/refs.bib +++ b/docs/source/refs.bib @@ -969,13 +969,5 @@ @misc{dang2016 url={https://arxiv.org/abs/1606.05551}, } -@inproceedings{devroye1972, - author = {Luc Devroye}, - title = {The compound random search algorithm}, - booktitle = {Proceedings of the International Symposium on Systems Engineering}, - pages = {105--110}, - year = {1972}, - url = {https://luc.devroye.org/devroye-crsa1972.pdf} -} @Comment{jabref-meta: databaseType:bibtex;} From e6959105900b395e26e0e535e793015d0bb2c211 Mon Sep 17 00:00:00 2001 From: gauravmanmode Date: Mon, 23 Jun 2025 22:19:58 +0530 Subject: [PATCH 11/16] Update nevergrad_optimizers.py --- .../optimizers/nevergrad_optimizers.py | 91 ++++++++++--------- 1 file changed, 47 insertions(+), 44 deletions(-) diff --git a/src/optimagic/optimizers/nevergrad_optimizers.py b/src/optimagic/optimizers/nevergrad_optimizers.py index 4c347d419..b4a7172c9 100644 --- a/src/optimagic/optimizers/nevergrad_optimizers.py +++ b/src/optimagic/optimizers/nevergrad_optimizers.py @@ -125,26 +125,29 @@ def _solve_internal_problem( ) @dataclass(frozen=True) class NevergradOnePlusOne(Algorithm): - """One Plus One Evolutionary algorithm from Nevergrad. + """ + One Plus One Evolutionary algorithm from Nevergrad. Args: - noise_handling: Method for handling the noise. The name can be (Default: `None`). + noise_handling: Method for handling the noise, can be - "random": A random point is reevaluated regularly using the one-fifth adaptation rule. - - "optimistic": The best optimistic point is reevaluated regularly, embracing - optimism in the face of uncertainty. + - "optimistic": The best optimistic point is reevaluated regularly, + embracing optimism in the face of uncertainty. - A float coefficient can be provided to tune the regularity of these reevaluations (default is 0.05). Eg: with 0.05, each evaluation has a 5% - chance (i.e., 1 in 20) of being repeated (i.e., the same candidate solution - is reevaluated to better estimate its performance). - + chance (i.e., 1 in 20) of being repeated (i.e., the same candidate + solution is reevaluated to better estimate its performance). + (Default: `None`). + n_cores: Number of cores to use. stopping.maxfun: Maximum number of function evaluations. - mutation: Type of mutation to apply. Available options are (Default: `"gaussian"`). - - "gaussian": Standard mutation by adding a Gaussian random variable (with - progressive widening) to the best pessimistic point. + mutation: Type of mutation to apply. Available options are (Default: + `"gaussian"`). + - "gaussian": Standard mutation by adding a Gaussian random variable + (with progressive widening) to the best pessimistic point. - "cauchy": Same as Gaussian but using a Cauchy distribution. - "discrete": Mutates a randomly drawn variable (mutation occurs with probability 1/d in d dimensions, hence ~1 variable per mutation). @@ -157,59 +160,59 @@ class NevergradOnePlusOne(Algorithm): - "portfolio": Random number of mutated bits, known as uniform mixing :cite:`dang2016`. - "lengler": Mutation rate is a function of dimension and iteration index. - - "lengler{2|3|half|fourth}": Variants of the Lengler mutation rate adaptation. + - "lengler{2|3|half|fourth}": Variants of the Lengler mutation rate + adaptation. - sparse: Whether to apply random mutations that set variables to zero. Default is - `False`. + sparse: Whether to apply random mutations that set variables to zero. + Default is `False`. smoother: Whether to suggest smooth mutations. Default is `False`. - annealing: Annealing schedule to apply to mutation amplitude or temperature-based - control. Options are: + annealing: Annealing schedule to apply to mutation amplitude or + temperature-based control. Options are: - "none": No annealing is applied. - "Exp0.9": Exponential decay with rate 0.9. - "Exp0.99": Exponential decay with rate 0.99. - - "Exp0.9Auto": Exponential decay with rate 0.9, auto-scaled based on problem - horizon. + - "Exp0.9Auto": Exponential decay with rate 0.9, auto-scaled based on + problem horizon. - "Lin100.0": Linear decay from 1 to 0 over 100 iterations. - "Lin1.0": Linear decay from 1 to 0 over 1 iteration. - - "LinAuto": Linearly decaying annealing automatically scaled to the problem - horizon. Default is `"none"`. + - "LinAuto": Linearly decaying annealing automatically scaled to the + problem horizon. Default is `"none"`. - super_radii: Whether to apply extended radii beyond standard bounds for candidate - generation, enabling broader exploration. Default is `False`. + super_radii: Whether to apply extended radii beyond standard bounds for + candidate generation, enabling broader exploration. Default is `False`. - roulette_size: Size of the roulette wheel used for selection in the evolutionary - process. Affects the sampling diversity from past candidates. (Default: `64`) + roulette_size: Size of the roulette wheel used for selection in the + evolutionary process. Affects the sampling diversity from past + candidates. (Default: `64`) - antismooth: Degree of anti-smoothing applied to prevent premature convergence in - smooth landscapes. This alters the landscape by penalizing overly smooth - improvements. (Default: `4`) + antismooth: Degree of anti-smoothing applied to prevent premature + convergence in smooth landscapes. This alters the landscape by + penalizing overly smooth improvements. (Default: `4`) - crossover: Whether to include a genetic crossover step every other iteration. - Default is `False`. + crossover: Whether to include a genetic crossover step every other + iteration. Default is `False`. - crossover_type: Method used for genetic crossover between individuals in the - population. Available options (Default: `"none"`): + crossover_type: Method used for genetic crossover between individuals in + the population. Available options (Default: `"none"`): - "none": No crossover is applied. - "rand": Randomized selection of crossover point. - "max": Crossover at the point with maximum fitness gain. - "min": Crossover at the point with minimum fitness gain. - - "onepoint": One-point crossover, splitting the genome at a single random - point. - - "twopoint": Two-point crossover, splitting the genome at two points and - exchanging the middle section. - - tabu_length: Length of the tabu list used to prevent revisiting recently evaluated - candidates in local search strategies. Helps in escaping local minima. - (Default: `1000`) - - rotation: Whether to apply rotational transformations to the search space, - promoting invariance to axis-aligned structures and enhancing search - performance in rotated coordinate systems. (Default: `False`) - + - "onepoint": One-point crossover, splitting the genome at a single + random point. + - "twopoint": Two-point crossover, splitting the genome at two points + and exchanging the middle section. + + tabu_length: Length of the tabu list used to prevent revisiting recently + evaluated candidates in local search strategies. Helps in escaping + local minima. (Default: `1000`) + + rotation: Whether to apply rotational transformations to the search + space, promoting invariance to axis-aligned structures and enhancing + search performance in rotated coordinate systems. (Default: `False`) """ - noise_handling: ( Literal["random", "optimistic"] | tuple[Literal["random", "optimistic"], float] From 89d760f20c41574c7c357b12e7206686ef426096 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 23 Jun 2025 16:50:29 +0000 Subject: [PATCH 12/16] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/optimagic/optimizers/nevergrad_optimizers.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/optimagic/optimizers/nevergrad_optimizers.py b/src/optimagic/optimizers/nevergrad_optimizers.py index b4a7172c9..91273f357 100644 --- a/src/optimagic/optimizers/nevergrad_optimizers.py +++ b/src/optimagic/optimizers/nevergrad_optimizers.py @@ -125,11 +125,10 @@ def _solve_internal_problem( ) @dataclass(frozen=True) class NevergradOnePlusOne(Algorithm): - """ - One Plus One Evolutionary algorithm from Nevergrad. + """One Plus One Evolutionary algorithm from Nevergrad. Args: - noise_handling: Method for handling the noise, can be + noise_handling: Method for handling the noise, can be - "random": A random point is reevaluated regularly using the one-fifth adaptation rule. - "optimistic": The best optimistic point is reevaluated regularly, @@ -139,7 +138,7 @@ class NevergradOnePlusOne(Algorithm): chance (i.e., 1 in 20) of being repeated (i.e., the same candidate solution is reevaluated to better estimate its performance). (Default: `None`). - + n_cores: Number of cores to use. stopping.maxfun: Maximum number of function evaluations. @@ -212,7 +211,9 @@ class NevergradOnePlusOne(Algorithm): rotation: Whether to apply rotational transformations to the search space, promoting invariance to axis-aligned structures and enhancing search performance in rotated coordinate systems. (Default: `False`) + """ + noise_handling: ( Literal["random", "optimistic"] | tuple[Literal["random", "optimistic"], float] From 4c9d284098c2e5242efb6addc439e02948399075 Mon Sep 17 00:00:00 2001 From: gauravmanmode Date: Wed, 2 Jul 2025 22:55:24 +0530 Subject: [PATCH 13/16] support both None and "none" --- src/optimagic/optimizers/nevergrad_optimizers.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/optimagic/optimizers/nevergrad_optimizers.py b/src/optimagic/optimizers/nevergrad_optimizers.py index 91273f357..2d7646a68 100644 --- a/src/optimagic/optimizers/nevergrad_optimizers.py +++ b/src/optimagic/optimizers/nevergrad_optimizers.py @@ -246,16 +246,14 @@ class NevergradOnePlusOne(Algorithm): ] = "gaussian" annealing: Literal[ "none", "Exp0.9", "Exp0.99", "Exp0.9Auto", "Lin100.0", "Lin1.0", "LinAuto" - ] = "none" + ] | None = None sparse: bool = False super_radii: bool = False smoother: bool = False roulette_size: PositiveInt = 64 antismooth: NonNegativeInt = 4 crossover: bool = False - crossover_type: Literal["none", "rand", "max", "min", "onepoint", "twopoint"] = ( - "none" - ) + crossover_type: Literal["none", "rand", "max", "min", "onepoint", "twopoint"] | None = None tabu_length: NonNegativeInt = 1000 rotation: bool = False seed: int | None = None @@ -280,6 +278,10 @@ def _solve_internal_problem( instrum.specify_tabu_length(tabu_length=self.tabu_length) instrum = ng.p.Instrumentation(instrum) + if self.annealing is None: + self.annealing = "none" + if self.crossover_type is None: + self.crossover_type = "none" if self.seed is not None: instrum.random_state.seed(self.seed) From cde30307460b9586506fd0270ba03fe92ee4c475 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 2 Jul 2025 17:27:45 +0000 Subject: [PATCH 14/16] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/optimagic/optimizers/nevergrad_optimizers.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/optimagic/optimizers/nevergrad_optimizers.py b/src/optimagic/optimizers/nevergrad_optimizers.py index 2d7646a68..429d3a207 100644 --- a/src/optimagic/optimizers/nevergrad_optimizers.py +++ b/src/optimagic/optimizers/nevergrad_optimizers.py @@ -244,16 +244,21 @@ class NevergradOnePlusOne(Algorithm): "biglognormal", "hugelognormal", ] = "gaussian" - annealing: Literal[ - "none", "Exp0.9", "Exp0.99", "Exp0.9Auto", "Lin100.0", "Lin1.0", "LinAuto" - ] | None = None + annealing: ( + Literal[ + "none", "Exp0.9", "Exp0.99", "Exp0.9Auto", "Lin100.0", "Lin1.0", "LinAuto" + ] + | None + ) = None sparse: bool = False super_radii: bool = False smoother: bool = False roulette_size: PositiveInt = 64 antismooth: NonNegativeInt = 4 crossover: bool = False - crossover_type: Literal["none", "rand", "max", "min", "onepoint", "twopoint"] | None = None + crossover_type: ( + Literal["none", "rand", "max", "min", "onepoint", "twopoint"] | None + ) = None tabu_length: NonNegativeInt = 1000 rotation: bool = False seed: int | None = None From b08d370cfe289089ba23cb5724cb4a1e1ee8a825 Mon Sep 17 00:00:00 2001 From: gauravmanmode Date: Wed, 2 Jul 2025 23:12:37 +0530 Subject: [PATCH 15/16] Update nevergrad_optimizers.py --- src/optimagic/optimizers/nevergrad_optimizers.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/optimagic/optimizers/nevergrad_optimizers.py b/src/optimagic/optimizers/nevergrad_optimizers.py index 429d3a207..8c5136acc 100644 --- a/src/optimagic/optimizers/nevergrad_optimizers.py +++ b/src/optimagic/optimizers/nevergrad_optimizers.py @@ -283,10 +283,6 @@ def _solve_internal_problem( instrum.specify_tabu_length(tabu_length=self.tabu_length) instrum = ng.p.Instrumentation(instrum) - if self.annealing is None: - self.annealing = "none" - if self.crossover_type is None: - self.crossover_type = "none" if self.seed is not None: instrum.random_state.seed(self.seed) @@ -295,13 +291,13 @@ def _solve_internal_problem( mutation=self.mutation, crossover=self.crossover, rotation=self.rotation, - annealing=self.annealing, + annealing=self.annealing or "none", sparse=self.sparse, smoother=self.smoother, super_radii=self.super_radii, roulette_size=self.roulette_size, antismooth=self.antismooth, - crossover_type=self.crossover_type, + crossover_type=self.crossover_type or "none", )( parametrization=instrum, budget=self.stopping_maxfun, From e7619bc539180af5a0bd8c643058b1633f0156d9 Mon Sep 17 00:00:00 2001 From: gaurav Date: Sat, 19 Jul 2025 20:32:07 +0530 Subject: [PATCH 16/16] add decorator fields, move docstring to docs --- docs/source/algorithms.md | 74 +++++++++++++++ .../optimizers/nevergrad_optimizers.py | 91 +------------------ 2 files changed, 76 insertions(+), 89 deletions(-) diff --git a/docs/source/algorithms.md b/docs/source/algorithms.md index ad355a0af..d96de704f 100644 --- a/docs/source/algorithms.md +++ b/docs/source/algorithms.md @@ -4124,6 +4124,80 @@ package. To use it, you need to have - **n_restarts** (int): Number of times to restart the optimizer. Default is 1. ``` +```{eval-rst} +.. dropdown:: nevergrad_oneplusone + + .. code-block:: + + "nevergrad_oneplusone" + + Minimize a scalar function using the One Plus One Evolutionary algorithm from Nevergrad. + + THe One Plus One evolutionary algorithm iterates to find a set of parameters that minimizes the loss + function. It does this by perturbing, or mutating, the parameters from the last iteration (the + parent). If the new (child) parameters yield a better result, then the child becomes the new parent + whose parameters are perturbed, perhaps more aggressively. If the parent yields a better result, it + remains the parent and the next perturbation is less aggressive. Originally proposed by + :cite:`Rechenberg1973`. The implementation in Nevergrad is based on the one-fifth adaptation rule, + going back to :cite:`Schumer1968. + + - **noise\_handling**: Method for handling the noise, can be + - "random": A random point is reevaluated regularly using the one-fifth adaptation rule. + - "optimistic": The best optimistic point is reevaluated regularly, embracing optimism in the face of uncertainty. + - A float coefficient can be provided to tune the regularity of these reevaluations (default is 0.05). Eg: with 0.05, each evaluation has a 5% chance (i.e., 1 in 20) of being repeated (i.e., the same candidate solution is reevaluated to better estimate its performance). (Default: `None`). + - **n\_cores**: Number of cores to use. + + - **stopping.maxfun**: Maximum number of function evaluations. + - **mutation**: Type of mutation to apply. Available options are (Default: `"gaussian"`). + - "gaussian": Standard mutation by adding a Gaussian random variable (with progressive widening) to the best pessimistic point. + - "cauchy": Same as Gaussian but using a Cauchy distribution. + - "discrete": Mutates a randomly drawn variable (mutation occurs with probability 1/d in d dimensions, hence ~1 variable per mutation). + - "discreteBSO": Follows brainstorm optimization by gradually decreasing mutation rate from 1 to 1/d. + - "fastga": Fast Genetic Algorithm mutations from the current best. + - "doublefastga": Double-FastGA mutations from the current best :cite:`doerr2017`. + - "rls": Randomized Local Search — mutates one and only one variable. + - "portfolio": Random number of mutated bits, known as uniform mixing :cite:`dang2016`. + - "lengler": Mutation rate is a function of dimension and iteration index. + - "lengler{2|3|half|fourth}": Variants of the Lengler mutation rate adaptation. + - **sparse**: Whether to apply random mutations that set variables to zero. Default is `False`. + - **smoother**: Whether to suggest smooth mutations. Default is `False`. + - **annealing**: + Annealing schedule to apply to mutation amplitude or temperature-based control. Options are: + - "none": No annealing is applied. + - "Exp0.9": Exponential decay with rate 0.9. + - "Exp0.99": Exponential decay with rate 0.99. + - "Exp0.9Auto": Exponential decay with rate 0.9, auto-scaled based on problem horizon. + - "Lin100.0": Linear decay from 1 to 0 over 100 iterations. + - "Lin1.0": Linear decay from 1 to 0 over 1 iteration. + - "LinAuto": Linearly decaying annealing automatically scaled to the problem horizon. Default is `"none"`. + - **super\_radii**: + Whether to apply extended radii beyond standard bounds for candidate generation, enabling broader + exploration. Default is `False`. + - **roulette\_size**: + Size of the roulette wheel used for selection in the evolutionary process. Affects the sampling + diversity from past candidates. (Default: `64`) + - **antismooth**: + Degree of anti-smoothing applied to prevent premature convergence in smooth landscapes. This alters + the landscape by penalizing overly smooth improvements. (Default: `4`) + - **crossover**: Whether to include a genetic crossover step every other iteration. Default is `False`. + - **crossover\_type**: + Method used for genetic crossover between individuals in the population. Available options (Default: `"none"`): + - "none": No crossover is applied. + - "rand": Randomized selection of crossover point. + - "max": Crossover at the point with maximum fitness gain. + - "min": Crossover at the point with minimum fitness gain. + - "onepoint": One-point crossover, splitting the genome at a single random point. + - "twopoint": Two-point crossover, splitting the genome at two points and exchanging the middle section. + - **tabu\_length**: + Length of the tabu list used to prevent revisiting recently evaluated candidates in local search + strategies. Helps in escaping local minima. (Default: `1000`) + - **rotation**: + Whether to apply rotational transformations to the search space, promoting invariance to axis- + aligned structures and enhancing search performance in rotated coordinate systems. (Default: + `False`) + - **seed**: Seed for the random number generator for reproducibility. +``` + ## References ```{eval-rst} diff --git a/src/optimagic/optimizers/nevergrad_optimizers.py b/src/optimagic/optimizers/nevergrad_optimizers.py index 2583288d1..720115038 100644 --- a/src/optimagic/optimizers/nevergrad_optimizers.py +++ b/src/optimagic/optimizers/nevergrad_optimizers.py @@ -119,103 +119,16 @@ def _solve_internal_problem( is_global=True, needs_jac=False, needs_hess=False, + needs_bounds=False, supports_parallelism=True, supports_bounds=True, + supports_infinite_bounds=False, supports_linear_constraints=False, supports_nonlinear_constraints=False, disable_history=False, ) @dataclass(frozen=True) class NevergradOnePlusOne(Algorithm): - """One Plus One Evolutionary algorithm from Nevergrad. - - Args: - noise_handling: Method for handling the noise, can be - - "random": A random point is reevaluated regularly using the one-fifth - adaptation rule. - - "optimistic": The best optimistic point is reevaluated regularly, - embracing optimism in the face of uncertainty. - - A float coefficient can be provided to tune the regularity of these - reevaluations (default is 0.05). Eg: with 0.05, each evaluation has a 5% - chance (i.e., 1 in 20) of being repeated (i.e., the same candidate - solution is reevaluated to better estimate its performance). - (Default: `None`). - - n_cores: Number of cores to use. - - stopping.maxfun: Maximum number of function evaluations. - - mutation: Type of mutation to apply. Available options are (Default: - `"gaussian"`). - - "gaussian": Standard mutation by adding a Gaussian random variable - (with progressive widening) to the best pessimistic point. - - "cauchy": Same as Gaussian but using a Cauchy distribution. - - "discrete": Mutates a randomly drawn variable (mutation occurs with - probability 1/d in d dimensions, hence ~1 variable per mutation). - - "discreteBSO": Follows brainstorm optimization by gradually decreasing - mutation rate from 1 to 1/d. - - "fastga": Fast Genetic Algorithm mutations from the current best. - - "doublefastga": Double-FastGA mutations from the current best - :cite:`doerr2017`. - - "rls": Randomized Local Search — mutates one and only one variable. - - "portfolio": Random number of mutated bits, known as uniform mixing - :cite:`dang2016`. - - "lengler": Mutation rate is a function of dimension and iteration index. - - "lengler{2|3|half|fourth}": Variants of the Lengler mutation rate - adaptation. - - sparse: Whether to apply random mutations that set variables to zero. - Default is `False`. - - smoother: Whether to suggest smooth mutations. Default is `False`. - - annealing: Annealing schedule to apply to mutation amplitude or - temperature-based control. Options are: - - "none": No annealing is applied. - - "Exp0.9": Exponential decay with rate 0.9. - - "Exp0.99": Exponential decay with rate 0.99. - - "Exp0.9Auto": Exponential decay with rate 0.9, auto-scaled based on - problem horizon. - - "Lin100.0": Linear decay from 1 to 0 over 100 iterations. - - "Lin1.0": Linear decay from 1 to 0 over 1 iteration. - - "LinAuto": Linearly decaying annealing automatically scaled to the - problem horizon. Default is `"none"`. - - super_radii: Whether to apply extended radii beyond standard bounds for - candidate generation, enabling broader exploration. Default is `False`. - - roulette_size: Size of the roulette wheel used for selection in the - evolutionary process. Affects the sampling diversity from past - candidates. (Default: `64`) - - antismooth: Degree of anti-smoothing applied to prevent premature - convergence in smooth landscapes. This alters the landscape by - penalizing overly smooth improvements. (Default: `4`) - - crossover: Whether to include a genetic crossover step every other - iteration. Default is `False`. - - crossover_type: Method used for genetic crossover between individuals in - the population. Available options (Default: `"none"`): - - "none": No crossover is applied. - - "rand": Randomized selection of crossover point. - - "max": Crossover at the point with maximum fitness gain. - - "min": Crossover at the point with minimum fitness gain. - - "onepoint": One-point crossover, splitting the genome at a single - random point. - - "twopoint": Two-point crossover, splitting the genome at two points - and exchanging the middle section. - - tabu_length: Length of the tabu list used to prevent revisiting recently - evaluated candidates in local search strategies. Helps in escaping - local minima. (Default: `1000`) - - rotation: Whether to apply rotational transformations to the search - space, promoting invariance to axis-aligned structures and enhancing - search performance in rotated coordinate systems. (Default: `False`) - - """ - noise_handling: ( Literal["random", "optimistic"] | tuple[Literal["random", "optimistic"], float]