Source code for pyhf.optimize.opt_scipy

"""SciPy Optimizer Class."""

import scipy

from pyhf import exceptions
from pyhf.optimize.mixins import OptimizerMixin


class scipy_optimizer(OptimizerMixin):
    """
    Optimizer that uses :func:`scipy.optimize.minimize`.
    """

    __slots__ = ["name", "solver_options", "tolerance"]

[docs] def __init__(self, *args, **kwargs): """ Initialize the scipy_optimizer. See :class:`pyhf.optimize.mixins.OptimizerMixin` for other configuration options. Args: tolerance (:obj:`float`): Tolerance for termination. See specific optimizer for detailed meaning. Default is ``None``. solver_options (:obj:`dict`): additional solver options. See :func:`scipy.optimize.show_options` for additional options of optimization solvers. """ self.name = "scipy" self.tolerance = kwargs.pop("tolerance", None) self.solver_options = kwargs.pop("solver_options", {}) super().__init__(*args, **kwargs)
[docs] def _get_minimizer( self, objective_and_grad, # noqa: ARG002 init_pars, # noqa: ARG002 init_bounds, # noqa: ARG002 fixed_vals=None, # noqa: ARG002 do_grad=False, # noqa: ARG002 par_names=None, # noqa: ARG002 ): return scipy.optimize.minimize
[docs] def _minimize( self, minimizer, func, x0, do_grad=False, bounds=None, fixed_vals=None, options=None, ): """ Same signature as :func:`scipy.optimize.minimize`. Minimizer Options: * maxiter (:obj:`int`): Maximum number of iterations. Default is ``100000``. * verbose (:obj:`bool`): Print verbose output during minimization. Default is ``False``. * method (:obj:`str`): Minimization routine. Default is ``'SLSQP'``. * tolerance (:obj:`float`): Tolerance for termination. See specific optimizer for detailed meaning. Default is ``None``. * solver_options (:obj:`dict`): additional solver options. See :func:`scipy.optimize.show_options` for additional options of optimization solvers. Returns: fitresult (scipy.optimize.OptimizeResult): the fit result """ if options is None: options = {} maxiter = options.pop("maxiter", self.maxiter) verbose = options.pop("verbose", self.verbose) method = options.pop("method", "SLSQP") tolerance = options.pop("tolerance", self.tolerance) solver_options = options.pop("solver_options", self.solver_options) if options: msg = f"Unsupported options were passed in: {list(options)}." raise exceptions.Unsupported(msg) fixed_vals = fixed_vals or [] indices = [i for i, _ in fixed_vals] values = [v for _, v in fixed_vals] if fixed_vals: constraints = [{"type": "eq", "fun": lambda v: v[indices] - values}] # update the initial values to the fixed value for any fixed parameter for idx, fixed_val in fixed_vals: x0[idx] = fixed_val else: constraints = [] return minimizer( func, x0, method=method, jac=do_grad, bounds=bounds, constraints=constraints, tol=tolerance, options=dict(maxiter=maxiter, disp=bool(verbose), **solver_options), )