Source code for zfit.minimizers.minimizer_nlopt

#  Copyright (c) 2024 zfit

from __future__ import annotations

import collections
import copy
import importlib
import math
from collections.abc import Callable, Mapping

from ..util.checks import RuntimeDependency

try:
    import nlopt
except ImportError as error:
    nlopt = RuntimeDependency("nlopt", error_msg=str(error))


import numpy as np

from ..core.parameter import assign_values
from ..util.exception import MaximumIterationReached
from .baseminimizer import (
    NOT_SUPPORTED,
    BaseMinimizer,
    minimize_supports,
    print_minimization_status,
)
from .fitresult import FitResult
from .strategy import ZfitStrategy
from .termination import CRITERION_NOT_AVAILABLE, EDM, ConvergenceCriterion


class NLoptBaseMinimizerV1(BaseMinimizer):
    _ALL_NLOPT_TOL = (
        # 'fatol',
        "ftol",
        "xatol",
        "xtol",
    )

    def __init__(
        self,
        algorithm: int,
        tol: float | None = None,
        gradient: Callable | str | NOT_SUPPORTED | None = NOT_SUPPORTED,
        hessian: Callable | str | NOT_SUPPORTED | None = NOT_SUPPORTED,
        maxiter: int | str | None = None,
        minimizer_options: Mapping[str, object] | None = None,
        internal_tols: Mapping[str, float | None] | None = None,
        verbosity: int | None = None,
        strategy: ZfitStrategy | None = None,
        criterion: ConvergenceCriterion | None = None,
        name: str = "NLopt Base Minimizer V1",
    ):
        """NLopt is a library that contains multiple different optimization algorithms.

         |@doc:minimizer.nlopt.info| More information on the algorithm can be found
        `here <https://nlopt.readthedocs.io/en/latest/NLopt_Algorithms/>`_.

        This implenemtation uses internally the
        `NLopt library <https://nlopt.readthedocs.io/en/latest/>`_.
        It is a
        free/open-source library for nonlinear optimization,
        providing a common interface for a number of
        different free optimization routines available online as well as
        original implementations of various other algorithms. |@docend:minimizer.nlopt.info|

         Args:

             algorithm: Define which algorithm to be used. These are taken from `nlopt.ALGORITHM` (where `ALGORITHM` is
                 the actual algorithm). A comprehensive list and description of all implemented algorithms is
                 available `here <https://nlopt.readthedocs.io/en/latest/NLopt_Algorithms/>`_.
                 The wrapper is optimized for Local gradient-based optimization and may break with
                 others. However, please post a feature request in case other algorithms are requested.

                 The naming of the algorithm starts with either L/G (Local/Global)
                  and N/D (derivative-free/derivative-based).

                 Local optimizer options include (but are not limited to)

                 Derivative free:
                 - LN_NELDERMEAD: The Nelder Mead Simplex algorithm, which seems to perform not so well, but can be used
                   to narrow down a minimum.
                 - LN_SBPLX: SubPlex is an improved version of the Simplex algorithms and usually performs better.

                 With derivative:
                 - LD_MMA: Method of Moving Asymptotes, an improved CCSA
                   ("conservative convex separable approximation") variant of the original MMA algorithm
                 - LD_SLSQP: this is a sequential quadratic programming (SQP) algorithm for (nonlinearly constrained)
                   gradient-based optimization
                 - LD_LBFGS: version of the famous low-storage BFGS algorithm, an approximate Newton method. The same as
                   the Minuit algorithm is built on.
                 - LD_TNEWTON_PRECOND_RESTART, LD_TNEWTON_PRECOND, LD_TNEWTON_RESTART, LD_TNEWTON: a preconditioned
                   inexact truncated Newton algorithm. Multiple variations, with and without preconditioning and/or
                   restart are provided.
                 - LD_VAR1, LD_VAR2: a shifted limited-memory variable-metric algorithm, either using a rank 1 or rank 2
                   method.

             tol: |@doc:minimizer.tol| Termination value for the
                   convergence/stopping criterion of the algorithm
                   in order to determine if the minimum has
                   been found. Defaults to 1e-3. |@docend:minimizer.tol|
             gradient: Gradient that will be given to the minimizer if supported.
             hessian: Hessian that will be given to the minimizer if supported.
             internal_tols: Tolerances for the minimizer. Has to contain possible tolerance criteria.
             verbosity: |@doc:minimizer.verbosity| Verbosity of the minimizer. Has to be between 0 and 10.
              The verbosity has the meaning:

               - a value of 0 means quiet and no output
               - above 0 up to 5, information that is good to know but without
                 flooding the user, corresponding to a "INFO" level.
               - A value above 5 starts printing out considerably more and
                 is used more for debugging purposes.
               - Setting the verbosity to 10 will print out every
                 evaluation of the loss function and gradient.

               Some minimizers offer additional output which is also
               distributed as above but may duplicate certain printed values. |@docend:minimizer.verbosity|
             criterion: |@doc:minimizer.criterion| Criterion of the minimum. This is an
                   estimated measure for the distance to the
                   minimum and can include the relative
                   or absolute changes of the parameters,
                   function value, gradients and more.
                   If the value of the criterion is smaller
                   than ``loss.errordef * tol``, the algorithm
                   stopps and it is assumed that the minimum
                   has been found. |@docend:minimizer.criterion|
             strategy: |@doc:minimizer.strategy| A class of type ``ZfitStrategy`` that takes no
                   input arguments in the init. Determines the behavior of the minimizer in
                   certain situations, most notably when encountering
                   NaNs. It can also implement a callback function. |@docend:minimizer.strategy|
             maxiter: |@doc:minimizer.maxiter| Approximate number of iterations.
                   This corresponds to roughly the maximum number of
                   evaluations of the ``value``, 'gradient`` or ``hessian``. |@docend:minimizer.maxiter|
             minimizer_options: Additional options that will be set in the minimizer.
             name: |@doc:minimizer.name| Human-readable name of the minimizer. |@docend:minimizer.name|
        """

        if importlib.util.find_spec("nlopt") is None:
            msg = (
                "nlopt is not installed. This is an optional dependency. To include it,you"
                " can install zfit with `pip install zfit[nlopt]` or `pip install zfit[all]`."
            )
            raise ImportError(msg)
        self._algorithm = algorithm
        if minimizer_options is None:
            minimizer_options = {}
        minimizer_options = copy.copy(minimizer_options)

        if gradient is not NOT_SUPPORTED:
            if gradient is False:
                msg = "grad cannot be False for NLopt minimizer."
                raise ValueError(msg)
            minimizer_options["gradient"] = gradient
        if hessian is not NOT_SUPPORTED:
            minimizer_options["hessian"] = hessian

        internal_tols = {} if internal_tols is None else copy.copy(internal_tols)
        for nlopt_tol in self._ALL_NLOPT_TOL:
            if nlopt_tol not in internal_tols:
                internal_tols[nlopt_tol] = None
        self._internal_tols = internal_tols

        # private kept variables
        self._internal_maxiter = 20
        self._nrandom_max = 5

        super().__init__(
            name=name,
            tol=tol,
            verbosity=verbosity,
            minimizer_options=minimizer_options,
            strategy=strategy,
            criterion=criterion,
            maxiter=maxiter,
        )

    @minimize_supports(init=True)
    def _minimize(self, loss, params, init):
        previous_result = init
        if init:
            assign_values(params=params, values=init)
        evaluator = self.create_evaluator(loss, params)

        # create minimizer instance
        minimizer = nlopt.opt(nlopt.LD_LBFGS, len(params))

        # initial values as array
        xvalues = initial_xvalues = np.asarray(params)

        # get and set the limits
        lower = np.array([p.lower for p in params])
        upper = np.array([p.upper for p in params])
        minimizer.set_lower_bounds(lower)
        minimizer.set_upper_bounds(upper)

        # create and set objective function. Either returns only the value or the value
        # and sets the gradient in-place
        def obj_func(x, grad):
            if grad.size > 0:
                value, gradients = evaluator.value_gradient(x)
                grad[:] = np.asarray(gradients)
            else:
                value = evaluator.value(x)

            return float(value)

        minimizer.set_min_objective(obj_func)

        # set maximum number of iterations, also set in evaluator
        minimizer.set_maxeval(self.get_maxiter(len(params)))

        minimizer_options = self.minimizer_options.copy()
        local_minimizer = None
        local_minimizer_options = minimizer_options.pop("local_minimizer_options", None)
        if local_minimizer_options is not None:
            local_minimizer = nlopt.opt(nlopt.LD_LBFGS, len(params))
            local_minimizer.set_lower_bounds(lower)
            local_minimizer.set_upper_bounds(upper)

        if (maxcor := minimizer_options.pop("maxcor", None)) is not None:
            minimizer.set_vector_storage(maxcor)

        if (population := minimizer_options.pop("population", None)) is not None:
            minimizer.set_population(population)

        for name, value in minimizer_options.items():
            minimizer.set_param(name, value)

        minimizer.set_param("verbosity", max(0, self.verbosity - 6))

        criterion = self.criterion(tol=self.tol, loss=loss, params=params)
        init_tol = min([math.sqrt(loss.errordef * self.tol), loss.errordef * self.tol * 1e3])
        # init_tol *= 10
        internal_tol = self._internal_tols
        internal_tol = {tol: init_tol if init is None else init for tol, init in internal_tol.items()}
        if "xtol" in internal_tol:
            internal_tol["xtol"] **= 0.5
        if "ftol" in internal_tol:
            internal_tol["ftol"] **= 0.5

        valid = None
        edm = None
        criterion_value = None
        maxiter_reached = False
        valid_message = ""
        result_prelim = previous_result
        nrandom = 0
        for i in range(self._internal_maxiter):
            init_scale = []
            approx_step_sizes = {}
            if result_prelim:
                approx_step_sizes = result_prelim.hesse(params=params, method="approx", name="approx")
            empty_dict = {}
            for param in params:
                step_size = approx_step_sizes.get(param, empty_dict).get("error")
                if step_size is None and param.has_step_size:
                    step_size = param.step_size
                init_scale.append(step_size)
            minimizer.set_initial_step(init_scale)

            self._set_tols_inplace(
                minimizer=minimizer,
                internal_tol=internal_tol,
                criterion_value=criterion_value,
            )

            # some (global) optimizers use a local minimizer, set that here
            if local_minimizer is not None:
                self._set_tols_inplace(
                    minimizer=local_minimizer,
                    internal_tol=internal_tol,
                    criterion_value=criterion_value,
                )

                minimizer.set_local_optimizer(local_minimizer)

            # run the minimization
            try:
                xvalues = minimizer.optimize(xvalues)
            except MaximumIterationReached:
                maxiter_reached = True
                valid = False
                valid_message = "Maxiter reached, terminated without convergence"
            except RuntimeError:
                if self.verbosity > 3:
                    pass
                if nrandom < self._nrandom_max:  # in order not to start too close
                    init_scale_isnot_none = np.asarray([scale is not None for scale in init_scale], dtype=bool)
                    init_scale = np.where(
                        init_scale_isnot_none,
                        init_scale,
                        np.ones_like(init_scale, dtype=np.float64),
                    )

                    init_scale_no_nan = np.nan_to_num(init_scale, nan=1.0)
                    init_scale_no_nan = init_scale_no_nan.astype(np.float64)
                    upper_random = np.minimum(initial_xvalues + init_scale_no_nan / 2, upper)
                    lower_random = np.maximum(initial_xvalues - init_scale_no_nan / 2, lower)
                    initial_xvalues = np.random.uniform(low=lower_random, high=upper_random)

                    nrandom += 1
            else:
                maxiter_reached = evaluator.niter > evaluator.maxiter

            assign_values(params, xvalues)
            fmin = minimizer.last_optimum_value()  # TODO: what happens if minimization terminated?
            with evaluator.ignore_maxiter():
                result_prelim = FitResult.from_nlopt(
                    loss,
                    minimizer=self,
                    opt=minimizer,
                    edm=CRITERION_NOT_AVAILABLE,
                    niter=evaluator.nfunc_eval,
                    params=params,
                    evaluator=evaluator,
                    criterion=None,
                    values=xvalues,
                    valid=valid,
                    message=valid_message,
                )
                converged = criterion.converged(result_prelim)
                valid = converged
            criterion_value = criterion.last_value
            edm = criterion.last_value if isinstance(criterion, EDM) else CRITERION_NOT_AVAILABLE

            if self.verbosity > 5:
                print_minimization_status(
                    converged=converged,
                    criterion=criterion,
                    evaluator=evaluator,
                    i=i,
                    fminopt=fmin,
                    internal_tol=internal_tol,
                )

            if converged or maxiter_reached:
                break

            # update the tols
            self._update_tol_inplace(criterion_value=criterion_value, internal_tol=internal_tol)

        else:
            valid = False
            valid_message = f"Invalid, criterion {criterion.name} is {criterion_value}, target {self.tol} not reached."

        return FitResult.from_nlopt(
            loss,
            minimizer=self.copy(),
            opt=minimizer,
            edm=edm,
            niter=evaluator.niter,
            params=params,
            evaluator=evaluator,
            values=xvalues,
            valid=valid,
            criterion=criterion,
            message=valid_message,
        )

    def _set_tols_inplace(self, minimizer, internal_tol, criterion_value):
        # set all the tolerances
        if (fatol := internal_tol.get("fatol")) is not None:
            minimizer.set_ftol_abs(fatol**0.5)
        if (xatol := internal_tol.get("xatol")) is not None:
            # minimizer.set_xtol_abs([xatol] * len(params))
            minimizer.set_xtol_abs(xatol)
        # set relative tolerances later as it can be unstable. Just use them when approaching
        if criterion_value is not None:
            tol_factor_full = self.tol / criterion_value
            if tol_factor_full < 1e-8:
                ftol = internal_tol.get("ftol")
                if ftol is not None:
                    minimizer.set_ftol_rel(ftol)

                xtol = internal_tol.get("xtol")
                if xtol is not None:
                    # minimizer.set_xtol_rel([xtol] * len(params))  # TODO: one value or vector?
                    minimizer.set_xtol_rel(xtol)  # TODO: one value or vector?


[docs] class NLoptLBFGSV1(NLoptBaseMinimizerV1): def __init__( self, tol: float | None = None, maxcor: int | None = None, verbosity: int | None = None, maxiter: int | str | None = None, strategy: ZfitStrategy | None = None, criterion: ConvergenceCriterion | None = None, name: str = "NLopt L-BFGS V1", ) -> None: """Local, gradient-based quasi-Newton minimizer using the low storage BFGS Hessian approximation. This is most probably the most popular algorithm for gradient based local minimum searches and also the underlying algorithm in the `Minuit <https://www.sciencedirect.com/science/article/abs/pii/0010465575900399>`_ minimizer that is also available as :class:`~zfit.minimize.Minuit`. This algorithm is based on a Fortran implementation of the low-storage BFGS algorithm written by Prof. Ladislav Luksan, and graciously posted online under the GNU LGPL at: - <http://www.uivt.cas.cz/~luksan/subroutines.html> The original L-BFGS algorithm, based on variable-metric updates via Strang recurrences, was described by the papers: - J. Nocedal, "Updating quasi-Newton matrices with limited storage," *Math. Comput.* **35**, 773-782 (1980). - D. C. Liu and J. Nocedal, "On the limited memory BFGS method for large scale optimization," ''Math. Programming' **45**, p. 503-528 (1989). |@doc:minimizer.nlopt.info| More information on the algorithm can be found `here <https://nlopt.readthedocs.io/en/latest/NLopt_Algorithms/>`_. This implenemtation uses internally the `NLopt library <https://nlopt.readthedocs.io/en/latest/>`_. It is a free/open-source library for nonlinear optimization, providing a common interface for a number of different free optimization routines available online as well as original implementations of various other algorithms. |@docend:minimizer.nlopt.info| Args: tol: |@doc:minimizer.tol| Termination value for the convergence/stopping criterion of the algorithm in order to determine if the minimum has been found. Defaults to 1e-3. |@docend:minimizer.tol| maxcor: |@doc:minimizer.maxcor| Maximum number of memory history to keep when using a quasi-Newton update formula such as BFGS. It is the number of gradients to “remember” from previous optimization steps: increasing it increases the memory requirements but may speed up the convergence. |@docend:minimizer.maxcor| verbosity: |@doc:minimizer.verbosity| Verbosity of the minimizer. Has to be between 0 and 10. The verbosity has the meaning: - a value of 0 means quiet and no output - above 0 up to 5, information that is good to know but without flooding the user, corresponding to a "INFO" level. - A value above 5 starts printing out considerably more and is used more for debugging purposes. - Setting the verbosity to 10 will print out every evaluation of the loss function and gradient. Some minimizers offer additional output which is also distributed as above but may duplicate certain printed values. |@docend:minimizer.verbosity| maxiter: |@doc:minimizer.maxiter| Approximate number of iterations. This corresponds to roughly the maximum number of evaluations of the ``value``, 'gradient`` or ``hessian``. |@docend:minimizer.maxiter| strategy: |@doc:minimizer.strategy| A class of type ``ZfitStrategy`` that takes no input arguments in the init. Determines the behavior of the minimizer in certain situations, most notably when encountering NaNs. It can also implement a callback function. |@docend:minimizer.strategy| criterion: |@doc:minimizer.criterion| Criterion of the minimum. This is an estimated measure for the distance to the minimum and can include the relative or absolute changes of the parameters, function value, gradients and more. If the value of the criterion is smaller than ``loss.errordef * tol``, the algorithm stopps and it is assumed that the minimum has been found. |@docend:minimizer.criterion| name: |@doc:minimizer.name| Human-readable name of the minimizer. |@docend:minimizer.name| """ super().__init__( name=name, algorithm=nlopt.LD_LBFGS, tol=tol, gradient=NOT_SUPPORTED, hessian=NOT_SUPPORTED, criterion=criterion, verbosity=verbosity, minimizer_options={"maxcor": maxcor}, strategy=strategy, maxiter=maxiter, ) @property def maxcor(self): return self.minimizer_options.get("maxcor")
[docs] class NLoptShiftVarV1(NLoptBaseMinimizerV1): def __init__( self, tol: float | None = None, maxcor: int | None = None, rank: int | None = None, verbosity: int | None = None, maxiter: int | str | None = None, strategy: ZfitStrategy | None = None, criterion: ConvergenceCriterion | None = None, name="NLopt Shifted Variable Memory", ) -> None: """Local, gradient-based minimizer using a shifted limited-memory variable-metric. This algorithm is based on a Fortran implementation of a shifted limited-memory variable-metric algorithm by Prof. Ladislav Luksan, and graciously posted online under the GNU LGPL at: - <http://www.uivt.cas.cz/~luksan/subroutines.html> There are two variations of this algorithm: either using a rank-2 method or a rank-1 method. The algorithms are based on the ones described by: - J. Vlcek and L. Luksan, "Shifted limited-memory variable metric methods for large-scale unconstrained minimization," *J. Computational Appl. Math.* **186**, p. 365-390 (2006). |@doc:minimizer.nlopt.info| More information on the algorithm can be found `here <https://nlopt.readthedocs.io/en/latest/NLopt_Algorithms/>`_. This implenemtation uses internally the `NLopt library <https://nlopt.readthedocs.io/en/latest/>`_. It is a free/open-source library for nonlinear optimization, providing a common interface for a number of different free optimization routines available online as well as original implementations of various other algorithms. |@docend:minimizer.nlopt.info| Args: tol: |@doc:minimizer.tol| Termination value for the convergence/stopping criterion of the algorithm in order to determine if the minimum has been found. Defaults to 1e-3. |@docend:minimizer.tol| maxcor: |@doc:minimizer.maxcor| Maximum number of memory history to keep when using a quasi-Newton update formula such as BFGS. It is the number of gradients to “remember” from previous optimization steps: increasing it increases the memory requirements but may speed up the convergence. |@docend:minimizer.maxcor| rank: Rank of the algorithm used, either 1 or 2. Defaults to 2. verbosity: |@doc:minimizer.verbosity| Verbosity of the minimizer. Has to be between 0 and 10. The verbosity has the meaning: - a value of 0 means quiet and no output - above 0 up to 5, information that is good to know but without flooding the user, corresponding to a "INFO" level. - A value above 5 starts printing out considerably more and is used more for debugging purposes. - Setting the verbosity to 10 will print out every evaluation of the loss function and gradient. Some minimizers offer additional output which is also distributed as above but may duplicate certain printed values. |@docend:minimizer.verbosity| maxiter: |@doc:minimizer.maxiter| Approximate number of iterations. This corresponds to roughly the maximum number of evaluations of the ``value``, 'gradient`` or ``hessian``. |@docend:minimizer.maxiter| strategy: |@doc:minimizer.strategy| A class of type ``ZfitStrategy`` that takes no input arguments in the init. Determines the behavior of the minimizer in certain situations, most notably when encountering NaNs. It can also implement a callback function. |@docend:minimizer.strategy| criterion: |@doc:minimizer.criterion| Criterion of the minimum. This is an estimated measure for the distance to the minimum and can include the relative or absolute changes of the parameters, function value, gradients and more. If the value of the criterion is smaller than ``loss.errordef * tol``, the algorithm stopps and it is assumed that the minimum has been found. |@docend:minimizer.criterion| name: |@doc:minimizer.name| Human-readable name of the minimizer. |@docend:minimizer.name| """ if rank is None: rank = 2 if rank == 1: algorithm = nlopt.LD_VAR1 elif rank == 2: algorithm = nlopt.LD_VAR2 else: msg = f"rank has to be either 1 or 2, not {rank}" raise ValueError(msg) self._rank = rank super().__init__( name=name, algorithm=algorithm, tol=tol, gradient=NOT_SUPPORTED, hessian=NOT_SUPPORTED, criterion=criterion, verbosity=verbosity, minimizer_options={"maxcor": maxcor}, strategy=strategy, maxiter=maxiter, ) @property def rank(self): return self._rank @property def maxcor(self): return self.minimizer_options.get("maxcor")
[docs] class NLoptTruncNewtonV1(NLoptBaseMinimizerV1): def __init__( self, tol: float | None = None, maxcor: int | None = None, verbosity: int | None = None, maxiter: int | str | None = None, strategy: ZfitStrategy | None = None, criterion: ConvergenceCriterion | None = None, name="NLopt Truncated Newton", ) -> None: """Local, gradient-based truncated Newton minimizer using an inexact algorithm. This algorithm is based on a Fortran implementation of a preconditioned inexact truncated Newton algorithm written by Prof. Ladislav Luksan, and graciously posted online under the GNU LGPL at: - http://www.uivt.cas.cz/~luksan/subroutines.html The algorithms is based on the ones described by: - R. S. Dembo and T. Steihaug, “Truncated Newton algorithms for large-scale optimization,” *Math. Programming* **26**, p. 190-212 (1983) http://doi.org/10.1007/BF02592055. |@doc:minimizer.nlopt.info| More information on the algorithm can be found `here <https://nlopt.readthedocs.io/en/latest/NLopt_Algorithms/>`_. This implenemtation uses internally the `NLopt library <https://nlopt.readthedocs.io/en/latest/>`_. It is a free/open-source library for nonlinear optimization, providing a common interface for a number of different free optimization routines available online as well as original implementations of various other algorithms. |@docend:minimizer.nlopt.info| Args: tol: |@doc:minimizer.tol| Termination value for the convergence/stopping criterion of the algorithm in order to determine if the minimum has been found. Defaults to 1e-3. |@docend:minimizer.tol| maxcor: |@doc:minimizer.maxcor| Maximum number of memory history to keep when using a quasi-Newton update formula such as BFGS. It is the number of gradients to “remember” from previous optimization steps: increasing it increases the memory requirements but may speed up the convergence. |@docend:minimizer.maxcor| verbosity: |@doc:minimizer.verbosity| Verbosity of the minimizer. Has to be between 0 and 10. The verbosity has the meaning: - a value of 0 means quiet and no output - above 0 up to 5, information that is good to know but without flooding the user, corresponding to a "INFO" level. - A value above 5 starts printing out considerably more and is used more for debugging purposes. - Setting the verbosity to 10 will print out every evaluation of the loss function and gradient. Some minimizers offer additional output which is also distributed as above but may duplicate certain printed values. |@docend:minimizer.verbosity| maxiter: |@doc:minimizer.maxiter| Approximate number of iterations. This corresponds to roughly the maximum number of evaluations of the ``value``, 'gradient`` or ``hessian``. |@docend:minimizer.maxiter| strategy: |@doc:minimizer.strategy| A class of type ``ZfitStrategy`` that takes no input arguments in the init. Determines the behavior of the minimizer in certain situations, most notably when encountering NaNs. It can also implement a callback function. |@docend:minimizer.strategy| criterion: |@doc:minimizer.criterion| Criterion of the minimum. This is an estimated measure for the distance to the minimum and can include the relative or absolute changes of the parameters, function value, gradients and more. If the value of the criterion is smaller than ``loss.errordef * tol``, the algorithm stopps and it is assumed that the minimum has been found. |@docend:minimizer.criterion| name: |@doc:minimizer.name| Human-readable name of the minimizer. |@docend:minimizer.name| """ super().__init__( name=name, algorithm=nlopt.LD_TNEWTON_PRECOND_RESTART, tol=tol, gradient=NOT_SUPPORTED, hessian=NOT_SUPPORTED, criterion=criterion, verbosity=verbosity, minimizer_options={"maxcor": maxcor}, strategy=strategy, maxiter=maxiter, ) @property def maxcor(self): return self.minimizer_options.get("maxcor")
[docs] class NLoptSLSQPV1(NLoptBaseMinimizerV1): def __init__( self, tol: float | None = None, verbosity: int | None = None, maxiter: int | str | None = None, strategy: ZfitStrategy | None = None, criterion: ConvergenceCriterion | None = None, name: str = "NLopt SLSQP", ) -> None: r"""Local gradient based minimizer using a sequential quadratic programming. This is a sequential quadratic programming (SQP) algorithm for non-linearly gradient-based optimization based on the implementation by Dieter Kraft and described in: - Dieter Kraft, “A software package for sequential quadratic programming”, Technical Report DFVLR-FB 88-28, Institut für Dynamik der Flugsysteme, Oberpfaffenhofen, July 1988. - Dieter Kraft, “Algorithm 733: TOMP-Fortran modules for optimal control calculations,” *ACM Transactions on Mathematical Software*, vol. 20, no. 3, pp. 262-281 (1994). The algorithm optimizes successive second-order (quadratic/least-squares) approximations of the objective function (via BFGS updates), with first-order (affine) approximations of the constraints. The Fortran code was obtained from the SciPy project, who are responsible for `obtaining permission`_ to distribute it under a free-software (3-clause BSD) license. The code was modified for inclusion in NLopt by S. G. Johnson in 2010, with the following changes. The code was converted to C and manually cleaned up. It was modified to be re-entrant (preserving the reverse-communication interface but explicitly saving the state in a data structure). The inexact line search was modified to evaluate the functions including gradients for the first step, since this removes the need to evaluate the function+gradient a second time for the same point in the common case when the inexact line search concludes after a single step. **Note:** Because the SLSQP code uses dense-matrix methods (ordinary BFGS, not low-storage BFGS), it requires *O*\ (*n*\ 2) storage and *O*\ (*n*\ 3) time in *n* dimensions, which makes it less practical for optimizing more than a few thousand parameters. .. _obtaining permission: http://permalink.gmane.org/gmane.comp.python.scientific.devel/6725 |@doc:minimizer.nlopt.info| More information on the algorithm can be found `here <https://nlopt.readthedocs.io/en/latest/NLopt_Algorithms/>`_. This implenemtation uses internally the `NLopt library <https://nlopt.readthedocs.io/en/latest/>`_. It is a free/open-source library for nonlinear optimization, providing a common interface for a number of different free optimization routines available online as well as original implementations of various other algorithms. |@docend:minimizer.nlopt.info| Args: tol: |@doc:minimizer.tol| Termination value for the convergence/stopping criterion of the algorithm in order to determine if the minimum has been found. Defaults to 1e-3. |@docend:minimizer.tol| verbosity: |@doc:minimizer.verbosity| Verbosity of the minimizer. Has to be between 0 and 10. The verbosity has the meaning: - a value of 0 means quiet and no output - above 0 up to 5, information that is good to know but without flooding the user, corresponding to a "INFO" level. - A value above 5 starts printing out considerably more and is used more for debugging purposes. - Setting the verbosity to 10 will print out every evaluation of the loss function and gradient. Some minimizers offer additional output which is also distributed as above but may duplicate certain printed values. |@docend:minimizer.verbosity| maxiter: |@doc:minimizer.maxiter| Approximate number of iterations. This corresponds to roughly the maximum number of evaluations of the ``value``, 'gradient`` or ``hessian``. |@docend:minimizer.maxiter| strategy: |@doc:minimizer.strategy| A class of type ``ZfitStrategy`` that takes no input arguments in the init. Determines the behavior of the minimizer in certain situations, most notably when encountering NaNs. It can also implement a callback function. |@docend:minimizer.strategy| criterion: |@doc:minimizer.criterion| Criterion of the minimum. This is an estimated measure for the distance to the minimum and can include the relative or absolute changes of the parameters, function value, gradients and more. If the value of the criterion is smaller than ``loss.errordef * tol``, the algorithm stopps and it is assumed that the minimum has been found. |@docend:minimizer.criterion| name: |@doc:minimizer.name| Human-readable name of the minimizer. |@docend:minimizer.name| """ super().__init__( name=name, algorithm=nlopt.LD_SLSQP, tol=tol, gradient=NOT_SUPPORTED, hessian=NOT_SUPPORTED, criterion=criterion, verbosity=verbosity, minimizer_options={}, strategy=strategy, maxiter=maxiter, )
[docs] class NLoptBOBYQAV1(NLoptBaseMinimizerV1): def __init__( self, tol: float | None = None, verbosity: int | None = None, maxiter: int | str | None = None, strategy: ZfitStrategy | None = None, criterion: ConvergenceCriterion | None = None, name: str = "NLopt BOBYQA", ) -> None: """Derivative-free local minimizer that iteratively constructed quadratic approximation for the loss. This is an algorithm derived from the `BOBYQA subroutine`_ of M. J. D. Powell, converted to C and modified for the NLopt stopping criteria. BOBYQA performs derivative-free bound-constrained optimization using an iteratively constructed quadratic approximation for the objective function. See: - M. J. D. Powell, “`The BOBYQA algorithm for bound constrained optimization without derivatives`_,” Department of Applied Mathematics and Theoretical Physics, Cambridge England, technical report NA2009/06 (2009). (Because BOBYQA constructs a quadratic approximation of the objective, it may perform poorly for objective functions that are not twice-differentiable.) This algorithm largely supersedes the NEWUOA algorithm, which is an earlier version of the same idea by Powell. .. _BOBYQA subroutine: http://plato.asu.edu/ftp/other_software/bobyqa.zip .. _The BOBYQA algorithm for bound constrained optimization without derivatives: http://www.damtp.cam.ac.uk/user/na/NA_papers/NA2009_06.pdf |@doc:minimizer.nlopt.info| More information on the algorithm can be found `here <https://nlopt.readthedocs.io/en/latest/NLopt_Algorithms/>`_. This implenemtation uses internally the `NLopt library <https://nlopt.readthedocs.io/en/latest/>`_. It is a free/open-source library for nonlinear optimization, providing a common interface for a number of different free optimization routines available online as well as original implementations of various other algorithms. |@docend:minimizer.nlopt.info| Args: tol: |@doc:minimizer.tol| Termination value for the convergence/stopping criterion of the algorithm in order to determine if the minimum has been found. Defaults to 1e-3. |@docend:minimizer.tol| verbosity: |@doc:minimizer.verbosity| Verbosity of the minimizer. Has to be between 0 and 10. The verbosity has the meaning: - a value of 0 means quiet and no output - above 0 up to 5, information that is good to know but without flooding the user, corresponding to a "INFO" level. - A value above 5 starts printing out considerably more and is used more for debugging purposes. - Setting the verbosity to 10 will print out every evaluation of the loss function and gradient. Some minimizers offer additional output which is also distributed as above but may duplicate certain printed values. |@docend:minimizer.verbosity| maxiter: |@doc:minimizer.maxiter| Approximate number of iterations. This corresponds to roughly the maximum number of evaluations of the ``value``, 'gradient`` or ``hessian``. |@docend:minimizer.maxiter| strategy: |@doc:minimizer.strategy| A class of type ``ZfitStrategy`` that takes no input arguments in the init. Determines the behavior of the minimizer in certain situations, most notably when encountering NaNs. It can also implement a callback function. |@docend:minimizer.strategy| criterion: |@doc:minimizer.criterion| Criterion of the minimum. This is an estimated measure for the distance to the minimum and can include the relative or absolute changes of the parameters, function value, gradients and more. If the value of the criterion is smaller than ``loss.errordef * tol``, the algorithm stopps and it is assumed that the minimum has been found. |@docend:minimizer.criterion| name: |@doc:minimizer.name| Human-readable name of the minimizer. |@docend:minimizer.name| """ super().__init__( name=name, algorithm=nlopt.LN_BOBYQA, tol=tol, gradient=NOT_SUPPORTED, hessian=NOT_SUPPORTED, criterion=criterion, verbosity=verbosity, minimizer_options={}, strategy=strategy, maxiter=maxiter, )
[docs] class NLoptMMAV1(NLoptBaseMinimizerV1): def __init__( self, tol: float | None = None, verbosity: int | None = None, maxiter: int | str | None = None, strategy: ZfitStrategy | None = None, criterion: ConvergenceCriterion | None = None, name: str = "NLopt MMA", ): """Method-of-moving-asymptotes for gradient-based local minimization. Globally-convergent method-of-moving-asymptotes (MMA) for gradient-based local minimization. The algorithm is described in: - Krister Svanberg, “`A class of globally convergent optimization methods based on conservative convex separable approximations`_,” *SIAM J. Optim.* **12** (2), p. 555-573 (2002). This is an improved CCSA (“conservative convex separable approximation”) variant of the original MMA algorithm published by Svanberg in 1987, which has become popular for topology optimization. (*Note:* “globally convergent” does *not* mean that this algorithm converges to the global optimum; it means that it is guaranteed to converge to *some* local minimum from any feasible starting point.) At each point **x**, MMA forms a local approximation using the gradient of *f* and the constraint functions, plus a quadratic “penalty” term to make the approximations “conservative” (upper bounds for the exact functions). The precise approximation MMA forms is difficult to describe in a few words, because it includes nonlinear terms consisting of a poles at some distance from *x* (outside of the current trust region), almost a kind of Padé approximant. The main point is that the approximation is both convex and separable, making it trivial to solve the approximate optimization by a dual method. Optimizing the approximation leads to a new candidate point **x**. The objective and constraints are evaluated at the candidate point. If the approximations were indeed conservative (upper bounds for the actual functions at the candidate point), then the process is restarted at the new **x**. Otherwise, the approximations are made more conservative (by increasing the penalty term) and re-optimized. .. _A class of globally convergent optimization methods based on conservative convex separable approximations: http://citeseer.ist.psu.edu/viewdoc/summary?doi=10.1.1.146.5196 .. _Professor Svanberg: http://researchprojects.kth.se/index.php/kb_7902/pb_2085/pb.html Args: tol: |@doc:minimizer.tol| Termination value for the convergence/stopping criterion of the algorithm in order to determine if the minimum has been found. Defaults to 1e-3. |@docend:minimizer.tol| verbosity: |@doc:minimizer.verbosity| Verbosity of the minimizer. Has to be between 0 and 10. The verbosity has the meaning: - a value of 0 means quiet and no output - above 0 up to 5, information that is good to know but without flooding the user, corresponding to a "INFO" level. - A value above 5 starts printing out considerably more and is used more for debugging purposes. - Setting the verbosity to 10 will print out every evaluation of the loss function and gradient. Some minimizers offer additional output which is also distributed as above but may duplicate certain printed values. |@docend:minimizer.verbosity| maxiter: |@doc:minimizer.maxiter| Approximate number of iterations. This corresponds to roughly the maximum number of evaluations of the ``value``, 'gradient`` or ``hessian``. |@docend:minimizer.maxiter| strategy: |@doc:minimizer.strategy| A class of type ``ZfitStrategy`` that takes no input arguments in the init. Determines the behavior of the minimizer in certain situations, most notably when encountering NaNs. It can also implement a callback function. |@docend:minimizer.strategy| criterion: |@doc:minimizer.criterion| Criterion of the minimum. This is an estimated measure for the distance to the minimum and can include the relative or absolute changes of the parameters, function value, gradients and more. If the value of the criterion is smaller than ``loss.errordef * tol``, the algorithm stopps and it is assumed that the minimum has been found. |@docend:minimizer.criterion| name: |@doc:minimizer.name| Human-readable name of the minimizer. |@docend:minimizer.name| """ super().__init__( name=name, algorithm=nlopt.LD_MMA, tol=tol, gradient=NOT_SUPPORTED, hessian=NOT_SUPPORTED, criterion=criterion, verbosity=verbosity, minimizer_options={}, strategy=strategy, maxiter=maxiter, )
[docs] class NLoptCCSAQV1(NLoptBaseMinimizerV1): def __init__( self, tol: float | None = None, verbosity: int | None = None, maxiter: int | str | None = None, strategy: ZfitStrategy | None = None, criterion: ConvergenceCriterion | None = None, name: str = "NLopt CCSAQ", ): """MMA-like minimizer with simpler, quadratic local approximations. CCSA is an algorithm from the same paper as MMA as described in: - Krister Svanberg, “`A class of globally convergent optimization methods based on conservative convex separable approximations`_,” *SIAM J. Optim.* **12** (2), p. 555-573 (2002). CCSA has the following differences: instead of constructing local MMA approximations, it constructs simple quadratic approximations (or rather, affine approximations plus a quadratic penalty term to stay conservative). This is the ccsa_quadratic code. It seems to have similar convergence rates to MMA for most problems, which is not surprising as they are both essentially similar. |@doc:minimizer.nlopt.info| More information on the algorithm can be found `here <https://nlopt.readthedocs.io/en/latest/NLopt_Algorithms/>`_. This implenemtation uses internally the `NLopt library <https://nlopt.readthedocs.io/en/latest/>`_. It is a free/open-source library for nonlinear optimization, providing a common interface for a number of different free optimization routines available online as well as original implementations of various other algorithms. |@docend:minimizer.nlopt.info| Args: tol: |@doc:minimizer.tol| Termination value for the convergence/stopping criterion of the algorithm in order to determine if the minimum has been found. Defaults to 1e-3. |@docend:minimizer.tol| verbosity: |@doc:minimizer.verbosity| Verbosity of the minimizer. Has to be between 0 and 10. The verbosity has the meaning: - a value of 0 means quiet and no output - above 0 up to 5, information that is good to know but without flooding the user, corresponding to a "INFO" level. - A value above 5 starts printing out considerably more and is used more for debugging purposes. - Setting the verbosity to 10 will print out every evaluation of the loss function and gradient. Some minimizers offer additional output which is also distributed as above but may duplicate certain printed values. |@docend:minimizer.verbosity| maxiter: |@doc:minimizer.maxiter| Approximate number of iterations. This corresponds to roughly the maximum number of evaluations of the ``value``, 'gradient`` or ``hessian``. |@docend:minimizer.maxiter| strategy: |@doc:minimizer.strategy| A class of type ``ZfitStrategy`` that takes no input arguments in the init. Determines the behavior of the minimizer in certain situations, most notably when encountering NaNs. It can also implement a callback function. |@docend:minimizer.strategy| criterion: |@doc:minimizer.criterion| Criterion of the minimum. This is an estimated measure for the distance to the minimum and can include the relative or absolute changes of the parameters, function value, gradients and more. If the value of the criterion is smaller than ``loss.errordef * tol``, the algorithm stopps and it is assumed that the minimum has been found. |@docend:minimizer.criterion| name: |@doc:minimizer.name| Human-readable name of the minimizer. |@docend:minimizer.name| """ super().__init__( name=name, algorithm=nlopt.LD_CCSAQ, tol=tol, gradient=NOT_SUPPORTED, hessian=NOT_SUPPORTED, criterion=criterion, verbosity=verbosity, minimizer_options={}, strategy=strategy, maxiter=maxiter, )
[docs] class NLoptCOBYLAV1(NLoptBaseMinimizerV1): def __init__( self, tol: float | None = None, verbosity: int | None = None, maxiter: int | str | None = None, strategy: ZfitStrategy | None = None, criterion: ConvergenceCriterion | None = None, name: str = "NLopt COBYLA", ): r"""Derivative free simplex minimizer using a linear approximation with trust region steps. COBYLA (Constrained Optimization BY Linear Approximations) constructs successive linear approximations of the objective function and constraints via a simplex of n+1 points (in n dimensions), and optimizes these approximations in a trust region at each step. This is a derivative of Powell's implementation of the COBYLA algorithm for derivative-free optimization by M. J. D. Powell described in: - M. J. D. Powell, “A direct search optimization method that models the objective and constraint functions by linear interpolation,” in *Advances in Optimization and Numerical Analysis*, eds. S. Gomez and J.-P. Hennart (Kluwer Academic: Dordrecht, 1994), p. 51-67. and reviewed in: - M. J. D. Powell, “Direct search algorithms for optimization calculations,” *Acta Numerica* **7**, 287-336 (1998). It constructs successive linear approximations of the objective function and constraints via a simplex of *n*\ +1 points (in *n* dimensions), and optimizes these approximations in a trust region at each step. The original code itself was written in Fortran by Powell and was converted to C in 2004 by Jean-Sebastien Roy (js@jeannot.org) for the SciPy project. The version in NLopt was based on Roy's C version and offers a few improvements over the original code: - `COBYLA` can increase the trust-region radius if the predicted improvement was approximately right and the simplex is OK - pseudo-randomization of the simplex steps in the COBYLA algorithm improve the robustness by avoiding accidentally taking steps that don't improve conditioning. |@doc:minimizer.nlopt.info| More information on the algorithm can be found `here <https://nlopt.readthedocs.io/en/latest/NLopt_Algorithms/>`_. This implenemtation uses internally the `NLopt library <https://nlopt.readthedocs.io/en/latest/>`_. It is a free/open-source library for nonlinear optimization, providing a common interface for a number of different free optimization routines available online as well as original implementations of various other algorithms. |@docend:minimizer.nlopt.info| |@doc:minimizer.nlopt.info| More information on the algorithm can be found `here <https://nlopt.readthedocs.io/en/latest/NLopt_Algorithms/>`_. This implenemtation uses internally the `NLopt library <https://nlopt.readthedocs.io/en/latest/>`_. It is a free/open-source library for nonlinear optimization, providing a common interface for a number of different free optimization routines available online as well as original implementations of various other algorithms. |@docend:minimizer.nlopt.info| Args: tol: |@doc:minimizer.tol| Termination value for the convergence/stopping criterion of the algorithm in order to determine if the minimum has been found. Defaults to 1e-3. |@docend:minimizer.tol| verbosity: |@doc:minimizer.verbosity| Verbosity of the minimizer. Has to be between 0 and 10. The verbosity has the meaning: - a value of 0 means quiet and no output - above 0 up to 5, information that is good to know but without flooding the user, corresponding to a "INFO" level. - A value above 5 starts printing out considerably more and is used more for debugging purposes. - Setting the verbosity to 10 will print out every evaluation of the loss function and gradient. Some minimizers offer additional output which is also distributed as above but may duplicate certain printed values. |@docend:minimizer.verbosity| maxiter: |@doc:minimizer.maxiter| Approximate number of iterations. This corresponds to roughly the maximum number of evaluations of the ``value``, 'gradient`` or ``hessian``. |@docend:minimizer.maxiter| strategy: |@doc:minimizer.strategy| A class of type ``ZfitStrategy`` that takes no input arguments in the init. Determines the behavior of the minimizer in certain situations, most notably when encountering NaNs. It can also implement a callback function. |@docend:minimizer.strategy| criterion: |@doc:minimizer.criterion| Criterion of the minimum. This is an estimated measure for the distance to the minimum and can include the relative or absolute changes of the parameters, function value, gradients and more. If the value of the criterion is smaller than ``loss.errordef * tol``, the algorithm stopps and it is assumed that the minimum has been found. |@docend:minimizer.criterion| name: |@doc:minimizer.name| Human-readable name of the minimizer. |@docend:minimizer.name| """ super().__init__( name=name, algorithm=nlopt.LN_COBYLA, tol=tol, gradient=NOT_SUPPORTED, hessian=NOT_SUPPORTED, criterion=criterion, verbosity=verbosity, minimizer_options={}, strategy=strategy, maxiter=maxiter, )
[docs] class NLoptSubplexV1(NLoptBaseMinimizerV1): def __init__( self, tol: float | None = None, verbosity: int | None = None, maxiter: int | str | None = None, strategy: ZfitStrategy | None = None, criterion: ConvergenceCriterion | None = None, name: str = "NLopt Subplex", ): """Local derivative free minimizer which improves on the Nealder-Mead algorithm. This is a re-implementation of Tom Rowan's “Subplex” algorithm. Subplex (a variant of Nelder-Mead that uses Nelder-Mead on a sequence of subspaces) is claimed to be much more efficient and robust than the original Nelder-Mead, while retaining the latter's facility with discontinuous objectives. The description of Rowan's algorithm in his PhD thesis is used: - T. Rowan, “Functional Stability Analysis of Numerical Algorithms”, Ph.D. thesis, Department of Computer Sciences, University of Texas at Austin, 1990. |@doc:minimizer.nlopt.info| More information on the algorithm can be found `here <https://nlopt.readthedocs.io/en/latest/NLopt_Algorithms/>`_. This implenemtation uses internally the `NLopt library <https://nlopt.readthedocs.io/en/latest/>`_. It is a free/open-source library for nonlinear optimization, providing a common interface for a number of different free optimization routines available online as well as original implementations of various other algorithms. |@docend:minimizer.nlopt.info| |@doc:minimizer.nlopt.info| More information on the algorithm can be found `here <https://nlopt.readthedocs.io/en/latest/NLopt_Algorithms/>`_. This implenemtation uses internally the `NLopt library <https://nlopt.readthedocs.io/en/latest/>`_. It is a free/open-source library for nonlinear optimization, providing a common interface for a number of different free optimization routines available online as well as original implementations of various other algorithms. |@docend:minimizer.nlopt.info| Args: tol: |@doc:minimizer.tol| Termination value for the convergence/stopping criterion of the algorithm in order to determine if the minimum has been found. Defaults to 1e-3. |@docend:minimizer.tol| verbosity: |@doc:minimizer.verbosity| Verbosity of the minimizer. Has to be between 0 and 10. The verbosity has the meaning: - a value of 0 means quiet and no output - above 0 up to 5, information that is good to know but without flooding the user, corresponding to a "INFO" level. - A value above 5 starts printing out considerably more and is used more for debugging purposes. - Setting the verbosity to 10 will print out every evaluation of the loss function and gradient. Some minimizers offer additional output which is also distributed as above but may duplicate certain printed values. |@docend:minimizer.verbosity| maxiter: |@doc:minimizer.maxiter| Approximate number of iterations. This corresponds to roughly the maximum number of evaluations of the ``value``, 'gradient`` or ``hessian``. |@docend:minimizer.maxiter| strategy: |@doc:minimizer.strategy| A class of type ``ZfitStrategy`` that takes no input arguments in the init. Determines the behavior of the minimizer in certain situations, most notably when encountering NaNs. It can also implement a callback function. |@docend:minimizer.strategy| criterion: |@doc:minimizer.criterion| Criterion of the minimum. This is an estimated measure for the distance to the minimum and can include the relative or absolute changes of the parameters, function value, gradients and more. If the value of the criterion is smaller than ``loss.errordef * tol``, the algorithm stopps and it is assumed that the minimum has been found. |@docend:minimizer.criterion| name: |@doc:minimizer.name| Human-readable name of the minimizer. |@docend:minimizer.name| """ super().__init__( name=name, algorithm=nlopt.LN_SBPLX, tol=tol, gradient=NOT_SUPPORTED, hessian=NOT_SUPPORTED, criterion=criterion, verbosity=verbosity, minimizer_options={}, strategy=strategy, maxiter=maxiter, )
[docs] class NLoptMLSLV1(NLoptBaseMinimizerV1): def __init__( self, tol: float | None = None, population: int | None = None, randomized: bool | None = None, local_minimizer: int | Mapping[str, object] | None = None, verbosity: int | None = None, maxiter: int | str | None = None, strategy: ZfitStrategy | None = None, criterion: ConvergenceCriterion | None = None, name: str = "NLopt MLSL", ) -> None: """Global minimizer using local optimization by randomly selecting points. “Multi-Level Single-Linkage” (MLSL) is an algorithm for global optimization by a sequence of local optimizations from random starting points, proposed by: - A. H. G. Rinnooy Kan and G. T. Timmer, “Stochastic global optimization methods,” *Mathematical Programming*, vol. 39, p. 27-78 (1987). (Actually 2 papers — part I: clustering methods, p. 27, then part II: multilevel methods, p. 57.) We also include a modification of MLSL use a Sobol' `low-discrepancy sequence`_ (LDS), also used in so-called `quasi Monte Carlo methods <https://en.wikipedia.org/wiki/Quasi-Monte_Carlo_method>`_ that can be invoked by setting *randomized* to False (as it is now *quasi*randomized) instead of pseudorandom numbers, which was argued to improve the convergence rate by: - Sergei Kucherenko and Yury Sytsko, “Application of deterministic low-discrepancy sequences in global optimization,” *Computational Optimization and Applications*, vol. 30, p. 297-318 (2005). In either case, MLSL is a “multistart” algorithm: it works by doing a sequence of local optimizations (using some other local optimization algorithm) from random or low-discrepancy starting points. MLSL is distinguished, however by a “clustering” heuristic that helps it to avoid repeated searches of the same local optima, and has some theoretical guarantees of finding all local optima in a finite number of local minimizations. The local-search portion of MLSL can use any of the other algorithms in NLopt. The local search uses the derivative/nonderivative algorithm set by the *local_minimizer* argument. .. _low-discrepancy sequence: https://en.wikipedia.org/wiki/Low-discrepancy_sequence .. _local optimization: NLopt_Reference#localsubsidiary-optimization-algorithm |@doc:minimizer.nlopt.info| More information on the algorithm can be found `here <https://nlopt.readthedocs.io/en/latest/NLopt_Algorithms/>`_. This implenemtation uses internally the `NLopt library <https://nlopt.readthedocs.io/en/latest/>`_. It is a free/open-source library for nonlinear optimization, providing a common interface for a number of different free optimization routines available online as well as original implementations of various other algorithms. |@docend:minimizer.nlopt.info| Args: tol: |@doc:minimizer.tol| Termination value for the convergence/stopping criterion of the algorithm in order to determine if the minimum has been found. Defaults to 1e-3. |@docend:minimizer.tol| population: |@doc:minimizer.nlopt.population| The population size for the evolutionary algorithm. |@docend:minimizer.nlopt.population| By default, each iteration of MLSL samples 4 random new trial points. randomized: If True, uses the randomized version 'GD_MLSL_LDS' instead of 'GD_MLSL' local_minimizer: Configuration for the local minimizer. Defaults to L-BFGS. verbosity: |@doc:minimizer.verbosity| Verbosity of the minimizer. Has to be between 0 and 10. The verbosity has the meaning: - a value of 0 means quiet and no output - above 0 up to 5, information that is good to know but without flooding the user, corresponding to a "INFO" level. - A value above 5 starts printing out considerably more and is used more for debugging purposes. - Setting the verbosity to 10 will print out every evaluation of the loss function and gradient. Some minimizers offer additional output which is also distributed as above but may duplicate certain printed values. |@docend:minimizer.verbosity| maxiter: |@doc:minimizer.maxiter| Approximate number of iterations. This corresponds to roughly the maximum number of evaluations of the ``value``, 'gradient`` or ``hessian``. |@docend:minimizer.maxiter| strategy: |@doc:minimizer.strategy| A class of type ``ZfitStrategy`` that takes no input arguments in the init. Determines the behavior of the minimizer in certain situations, most notably when encountering NaNs. It can also implement a callback function. |@docend:minimizer.strategy| criterion: |@doc:minimizer.criterion| Criterion of the minimum. This is an estimated measure for the distance to the minimum and can include the relative or absolute changes of the parameters, function value, gradients and more. If the value of the criterion is smaller than ``loss.errordef * tol``, the algorithm stopps and it is assumed that the minimum has been found. |@docend:minimizer.criterion| name: |@doc:minimizer.name| Human-readable name of the minimizer. |@docend:minimizer.name| """ if randomized is None: randomized = False algorithm = nlopt.GD_MLSL if randomized else nlopt.GD_MLSL_LDS local_minimizer = nlopt.LD_LBFGS if local_minimizer is None else local_minimizer if not isinstance(local_minimizer, collections.abc.Mapping): local_minimizer = {"algorithm": local_minimizer} if "algorithm" not in local_minimizer: msg = "algorithm needs to be specified in local_minimizer" raise ValueError(msg) minimizer_options = {"local_minimizer_options": local_minimizer} if population is not None: minimizer_options["population"] = population super().__init__( name=name, algorithm=algorithm, tol=tol, gradient=NOT_SUPPORTED, hessian=NOT_SUPPORTED, criterion=criterion, verbosity=verbosity, minimizer_options=minimizer_options, strategy=strategy, maxiter=maxiter, )
[docs] class NLoptStoGOV1(NLoptBaseMinimizerV1): def __init__( self, tol: float | None = None, randomized: bool | None = None, verbosity: int | None = None, maxiter: int | str | None = None, strategy: ZfitStrategy | None = None, criterion: ConvergenceCriterion | None = None, name: str = "NLopt MLSL", ): """Global minimizer which divides the space into smaller rectangles and uses a local BFGS variant inside. StoGO is a global optimization algorithm that works by systematically dividing the search space (which must be bound-constrained) into smaller hyper-rectangles via a branch-and-bound technique, and searching them by a gradient-based local-search algorithm (a BFGS variant), optionally including some randomness (hence the “Sto”, which stands for “stochastic” I believe). Some references on StoGO are: - S. Gudmundsson, “Parallel Global Optimization,” M.Sc. Thesis, IMM, Technical University of Denmark, 1998. - K. Madsen, S. Zertchaninov, and A. Zilinskas, “Global Optimization using Branch-and-Bound,” unpublished (1998). A preprint of this paper is included in the ``stogo`` subdirectory of NLopt as ``paper.pdf``. - S. Zertchaninov and K. Madsen, “A C++ Programme for Global Optimization,” IMM-REP-1998-04, Department of Mathematical Modelling, Technical University of Denmark, DK-2800 Lyngby, Denmark, 1998. A copy of this report is included in the ``stogo`` subdirectory of NLopt as ``techreport.pdf``. |@doc:minimizer.nlopt.info| More information on the algorithm can be found `here <https://nlopt.readthedocs.io/en/latest/NLopt_Algorithms/>`_. This implenemtation uses internally the `NLopt library <https://nlopt.readthedocs.io/en/latest/>`_. It is a free/open-source library for nonlinear optimization, providing a common interface for a number of different free optimization routines available online as well as original implementations of various other algorithms. |@docend:minimizer.nlopt.info| Args: tol: |@doc:minimizer.tol| Termination value for the convergence/stopping criterion of the algorithm in order to determine if the minimum has been found. Defaults to 1e-3. |@docend:minimizer.tol| randomized: If True, uses the randomized version 'GD_STOGO_RAND' instead of 'GD_STOGO' verbosity: |@doc:minimizer.verbosity| Verbosity of the minimizer. Has to be between 0 and 10. The verbosity has the meaning: - a value of 0 means quiet and no output - above 0 up to 5, information that is good to know but without flooding the user, corresponding to a "INFO" level. - A value above 5 starts printing out considerably more and is used more for debugging purposes. - Setting the verbosity to 10 will print out every evaluation of the loss function and gradient. Some minimizers offer additional output which is also distributed as above but may duplicate certain printed values. |@docend:minimizer.verbosity| maxiter: |@doc:minimizer.maxiter| Approximate number of iterations. This corresponds to roughly the maximum number of evaluations of the ``value``, 'gradient`` or ``hessian``. |@docend:minimizer.maxiter| strategy: |@doc:minimizer.strategy| A class of type ``ZfitStrategy`` that takes no input arguments in the init. Determines the behavior of the minimizer in certain situations, most notably when encountering NaNs. It can also implement a callback function. |@docend:minimizer.strategy| criterion: |@doc:minimizer.criterion| Criterion of the minimum. This is an estimated measure for the distance to the minimum and can include the relative or absolute changes of the parameters, function value, gradients and more. If the value of the criterion is smaller than ``loss.errordef * tol``, the algorithm stopps and it is assumed that the minimum has been found. |@docend:minimizer.criterion| name: |@doc:minimizer.name| Human-readable name of the minimizer. |@docend:minimizer.name| """ if randomized is None: randomized = False algorithm = nlopt.GD_STOGO_RAND if randomized else nlopt.GD_STOGO super().__init__( name=name, algorithm=algorithm, tol=tol, gradient=NOT_SUPPORTED, hessian=NOT_SUPPORTED, criterion=criterion, verbosity=verbosity, minimizer_options=None, strategy=strategy, maxiter=maxiter, )
[docs] class NLoptESCHV1(NLoptBaseMinimizerV1): def __init__( self, tol: float | None = None, verbosity: int | None = None, maxiter: int | str | None = None, strategy: ZfitStrategy | None = None, criterion: ConvergenceCriterion | None = None, name: str = "NLopt ESCH", ): """Global minimizer using an evolutionary algorithm. This is a modified Evolutionary Algorithm for global optimization, developed by Carlos Henrique da Silva Santos's and described in the following paper and Ph.D thesis: - C. H. da Silva Santos, M. S. Gonçalves, and H. E. Hernandez-Figueroa, “Designing Novel Photonic Devices by Bio-Inspired Computing,” *IEEE Photonics Technology Letters* **22** (15), pp. 1177-1179 (2010). .. raw:: html <!-- --> - C. H. da Silva Santos, “`Parallel and Bio-Inspired Computing Applied to Analyze Microwave and Photonic Metamaterial Strucutures`_,” Ph.D. thesis, University of Campinas, (2010). The algorithm is adapted from ideas described in: - H.-G. Beyer and H.-P. Schwefel, “Evolution Strategies: A Comprehensive Introduction,” *Journal Natural Computing*, **1** (1), pp. 3-52 (2002_. .. raw:: html <!-- --> - Ingo Rechenberg, “Evolutionsstrategie - Optimierung technischer Systeme nach Prinzipien der biologischen Evolution,” Ph.D. thesis (1971), Reprinted by Fromman-Holzboog (1973). .. _Parallel and Bio-Inspired Computing Applied to Analyze Microwave and Photonic Metamaterial Strucutures: http://www.bibliotecadigital.unicamp.br/document/?code=000767537&opt=4&lg=en_US |@doc:minimizer.nlopt.info| More information on the algorithm can be found `here <https://nlopt.readthedocs.io/en/latest/NLopt_Algorithms/>`_. This implenemtation uses internally the `NLopt library <https://nlopt.readthedocs.io/en/latest/>`_. It is a free/open-source library for nonlinear optimization, providing a common interface for a number of different free optimization routines available online as well as original implementations of various other algorithms. |@docend:minimizer.nlopt.info| Args: tol: |@doc:minimizer.tol| Termination value for the convergence/stopping criterion of the algorithm in order to determine if the minimum has been found. Defaults to 1e-3. |@docend:minimizer.tol| verbosity: |@doc:minimizer.verbosity| Verbosity of the minimizer. Has to be between 0 and 10. The verbosity has the meaning: - a value of 0 means quiet and no output - above 0 up to 5, information that is good to know but without flooding the user, corresponding to a "INFO" level. - A value above 5 starts printing out considerably more and is used more for debugging purposes. - Setting the verbosity to 10 will print out every evaluation of the loss function and gradient. Some minimizers offer additional output which is also distributed as above but may duplicate certain printed values. |@docend:minimizer.verbosity| maxiter: |@doc:minimizer.maxiter| Approximate number of iterations. This corresponds to roughly the maximum number of evaluations of the ``value``, 'gradient`` or ``hessian``. |@docend:minimizer.maxiter| strategy: |@doc:minimizer.strategy| A class of type ``ZfitStrategy`` that takes no input arguments in the init. Determines the behavior of the minimizer in certain situations, most notably when encountering NaNs. It can also implement a callback function. |@docend:minimizer.strategy| criterion: |@doc:minimizer.criterion| Criterion of the minimum. This is an estimated measure for the distance to the minimum and can include the relative or absolute changes of the parameters, function value, gradients and more. If the value of the criterion is smaller than ``loss.errordef * tol``, the algorithm stopps and it is assumed that the minimum has been found. |@docend:minimizer.criterion| name: |@doc:minimizer.name| Human-readable name of the minimizer. |@docend:minimizer.name| """ algorithm = nlopt.GN_ESCH super().__init__( name=name, algorithm=algorithm, tol=tol, gradient=NOT_SUPPORTED, hessian=NOT_SUPPORTED, criterion=criterion, verbosity=verbosity, minimizer_options=None, strategy=strategy, maxiter=maxiter, )
[docs] class NLoptISRESV1(NLoptBaseMinimizerV1): def __init__( self, tol: float | None = None, population: int | None = None, verbosity: int | None = None, maxiter: int | str | None = None, strategy: ZfitStrategy | None = None, criterion: ConvergenceCriterion | None = None, name: str = "NLopt ISRES", ): """Improved Stochastic Ranking Evolution Strategy using a mutation rule and differential variation. The evolution strategy is based on a combination of a mutation rule (with a log-normal step-size update and exponential smoothing) and differential variation (a Nelder-Mead-like update rule). The fitness ranking is simply via the objective function for problems without nonlinear constraints, but when nonlinear constraints are included the stochastic ranking proposed by Runarsson and Yao is employed. The NLopt implementation is based on the method described in: - Thomas Philip Runarsson and Xin Yao, `"Search biases in constrained evolutionary optimization <http://www3.hi.is/~tpr/papers/RuYa05.pdf>"`_, *IEEE Trans. on Systems, Man, and Cybernetics Part C: Applications and Reviews*, vol. 35 (no. 2), pp. 233-243 (2005). It is a refinement of an earlier method described in: - Thomas P. Runarsson and Xin Yao, `"Stochastic ranking for constrained evolutionary optimization <http://www3.hi.is/~tpr/software/sres/Tec311r.pdf>"`_, *IEEE Trans. Evolutionary Computation*, vol. 4 (no. 3), pp. 284-294 (2000). The actual implementation is independent provided by S. G. Johnson (2009) based on the papers above. Runarsson also has his own Matlab implemention available from `his web page <http://www3.hi.is/~tpr>`_. |@doc:minimizer.nlopt.info| More information on the algorithm can be found `here <https://nlopt.readthedocs.io/en/latest/NLopt_Algorithms/>`_. This implenemtation uses internally the `NLopt library <https://nlopt.readthedocs.io/en/latest/>`_. It is a free/open-source library for nonlinear optimization, providing a common interface for a number of different free optimization routines available online as well as original implementations of various other algorithms. |@docend:minimizer.nlopt.info| Args: tol: |@doc:minimizer.tol| Termination value for the convergence/stopping criterion of the algorithm in order to determine if the minimum has been found. Defaults to 1e-3. |@docend:minimizer.tol| population: |@doc:minimizer.nlopt.population| The population size for the evolutionary algorithm. |@docend:minimizer.nlopt.population| Defaults to :math:`20 * (n+1)` in n dimensions. verbosity: |@doc:minimizer.verbosity| Verbosity of the minimizer. Has to be between 0 and 10. The verbosity has the meaning: - a value of 0 means quiet and no output - above 0 up to 5, information that is good to know but without flooding the user, corresponding to a "INFO" level. - A value above 5 starts printing out considerably more and is used more for debugging purposes. - Setting the verbosity to 10 will print out every evaluation of the loss function and gradient. Some minimizers offer additional output which is also distributed as above but may duplicate certain printed values. |@docend:minimizer.verbosity| maxiter: |@doc:minimizer.maxiter| Approximate number of iterations. This corresponds to roughly the maximum number of evaluations of the ``value``, 'gradient`` or ``hessian``. |@docend:minimizer.maxiter| strategy: |@doc:minimizer.strategy| A class of type ``ZfitStrategy`` that takes no input arguments in the init. Determines the behavior of the minimizer in certain situations, most notably when encountering NaNs. It can also implement a callback function. |@docend:minimizer.strategy| criterion: |@doc:minimizer.criterion| Criterion of the minimum. This is an estimated measure for the distance to the minimum and can include the relative or absolute changes of the parameters, function value, gradients and more. If the value of the criterion is smaller than ``loss.errordef * tol``, the algorithm stopps and it is assumed that the minimum has been found. |@docend:minimizer.criterion| name: |@doc:minimizer.name| Human-readable name of the minimizer. |@docend:minimizer.name| """ algorithm = nlopt.GN_ISRES minimizer_options = {"population": population} if population is not None else None super().__init__( name=name, algorithm=algorithm, tol=tol, gradient=NOT_SUPPORTED, hessian=NOT_SUPPORTED, criterion=criterion, verbosity=verbosity, minimizer_options=minimizer_options, strategy=strategy, maxiter=maxiter, )