Source code for spey.optimizer.core

import logging
from typing import Callable, Dict, List, Optional, Tuple

import numpy as np

from spey.base.model_config import ModelConfig

from .scipy_tools import minimize

# pylint: disable=W1203

log = logging.getLogger("Spey")


[docs] def fit( func: Callable[[np.ndarray], np.ndarray], model_configuration: ModelConfig, do_grad: bool = False, hessian: Optional[Callable[[np.ndarray], np.ndarray]] = None, initial_parameters: Optional[np.ndarray] = None, bounds: Optional[List[Tuple[float, float]]] = None, fixed_poi_value: Optional[float] = None, logpdf: Optional[Callable[[List[float]], float]] = None, constraints: Optional[List[Dict]] = None, **options, ) -> Tuple[float, np.ndarray]: """ Operating the fitting of the given function. Args: func (``Callable[[np.ndarray], np.ndarray]``): Function to be optimised. If `do_grad=True`, function is expected to return `Tuple[np.ndarray, np.ndarray]` where first is the value of the function and the second is gradients with respect to the nuisance parameters. model_configuration (``~spey.base.model_config.ModelConfig``): Model configuration. do_grad (``bool``, default ``False``): boolean to set gradient on or off. hessian (``Optional[Callable[[np.ndarray], np.ndarray]]``, default ``None``): hessian of the function with respect to variational parameters. Currently not used. initial_parameters (``Optional[np.ndarray]``, default ``None``): Initial guess for the variational parameters. bounds (``Optional[List[Tuple[float, float]]]``, default ``None``): Bounds for the variational parameters each item has to have a lower and upper bound definition `(<lower>, <upper>)` in case of open boundary input can be `None`. Number of boundaries has to match with the number of parameters. They will match with respect to the index within the list. fixed_poi_value (``Optional[float]``, default ``None``): If `float` the poi index will be fixed. logpdf (``Optional[Callable[[List[float]], float]]``, default ``None``): If provided, log-probability distribution will be computed once the parameters are fitted. If not, the result of the ``func`` input will be returned. constraints (``Optional[List[Dict]]``, default ``None``): Constraints of the model. see scipy for details. options (``Dict``): extra options for the optimiser. see scipy minimiser for details. Returns: ``Tuple[float, np.ndarray]``: value and the parameters. log-probability value will be returned if `logpdf` argument is provided. """ init_pars = [*(initial_parameters or model_configuration.suggested_init)] par_bounds = [*(bounds or model_configuration.fixed_poi_bounds(fixed_poi_value))] def make_constraint(index: int, value: float) -> Callable[[np.ndarray], float]: def func(vector: np.ndarray) -> float: return vector[index] - value return func constraints = [] if constraints is None else constraints if fixed_poi_value is not None: init_pars[model_configuration.poi_index] = fixed_poi_value log.debug( f"Fixing POI index at: {model_configuration.poi_index} to value {fixed_poi_value}" ) constraints.append( { "type": "eq", "fun": make_constraint(model_configuration.poi_index, fixed_poi_value), } ) if model_configuration.suggested_fixed is not None: for idx, isfixed in enumerate(model_configuration.suggested_fixed): if isfixed: log.debug(f"Constraining {idx} to value {init_pars[idx]}") constraints.append( { "type": "eq", "fun": make_constraint(idx, init_pars[idx]), } ) options.update({"poi_index": model_configuration.poi_index}) fun, x = minimize( func=func, init_pars=init_pars, do_grad=do_grad, hessian=hessian, bounds=par_bounds, constraints=constraints, **options, ) return fun if logpdf is None else logpdf(x), x