Source code for spey.base.model_config

"""Configuration class for Statistical Models"""

import copy
from dataclasses import dataclass
from typing import List, Optional, Text, Tuple


[docs] @dataclass class ModelConfig: r""" Container to hold certain properties of the backend and statistical model. This will ensure the consistency of the computation through out the package. Args: poi_index (:obj:`int`): index of the parameter of interest within the parameter list. minimum_poi (:obj:`float`): minimum value parameter of interest can take to ensure :math:`N^{\rm bkg}+\mu N^{\rm sig}\geq0`. This value can be set to :math:`-\infty` but note that optimiser will take it as a lower bound so such low value might effect the convergence of the optimisation algorithm especially for relatively flat objective surfaceses. Hence we suggest setting the minimum value to .. math:: \mu_{\rm min} = - \min\left( \frac{N^{\rm bkg}_i}{N^{\rm sig}_i} \right)\ ,\ i\in {\rm bins} suggested_init (:obj:`List[float]`): suggested initial parameters for the optimiser. suggested_bounds (:obj:`List[Tuple[float, float]]`): suggested parameter bounds for the optimiser. Returns: :obj:~spey.base.model_config.ModelConfig: Model configuration container for optimiser. """ poi_index: int """Index of the parameter of interest wihin the parameter list""" minimum_poi: float r""" minimum value parameter of interest can take to ensure :math:`N^{\rm bkg}+\mu N^{\rm sig}\geq0`. This value can be set to :math:`-\infty` but note that optimiser will take it as a lower bound so such low value might effect the convergence of the optimisation algorithm especially for relatively flat objective surfaceses. Hence we suggest setting the minimum value to .. math:: \mu_{\rm min} = - \min\left( \frac{N^{\rm bkg}_i}{N^{\rm sig}_i} \right)\ ,\ i\in {\rm bins} """ suggested_init: List[float] """Suggested initialisation for parameters""" suggested_bounds: List[Tuple[float, float]] """Suggested upper and lower bounds for parameters""" parameter_names: Optional[List[str]] = None """Names of the parameters""" suggested_fixed: Optional[List[bool]] = None """Suggested fixed values""" @property def npar(self) -> int: """Number of parameters""" return len(self.suggested_init)
[docs] def fixed_poi_bounds( self, poi_value: Optional[float] = None ) -> List[Tuple[float, float]]: r""" Adjust the bounds for the parameter of interest for fixed POI fit. Args: poi_value (:obj:`Optional[float]`, default :obj:`None`): parameter of interest, :math:`\mu`. Returns: :obj:`List[Tuple[float, float]]`: Updated bounds. """ if poi_value is None: return self.suggested_bounds bounds = copy.deepcopy(self.suggested_bounds) if any(b is None for b in bounds[self.poi_index]): return bounds if not bounds[self.poi_index][0] < poi_value < bounds[self.poi_index][1]: bounds[self.poi_index] = ( self.minimum_poi if poi_value < 0.0 else 0.0, poi_value + 1, ) return bounds
[docs] def rescale_poi_bounds( self, allow_negative_signal: bool = True, poi_upper_bound: Optional[float] = None ) -> List[Tuple[float, float]]: r""" Rescale bounds for POI. Args: allow_negative_signal (:obj:`bool`, default :obj:`True`): If :obj:`True` :math:`\hat\mu` value will be allowed to be negative. poi_upper_bound (:obj:`float`, default :obj:`None`): Maximum value POI can take during optimisation. Returns: :obj:`List[Tuple[float, float]]`: Updated bounds. """ bounds = copy.deepcopy(self.suggested_bounds) if poi_upper_bound: bounds[self.poi_index] = ( self.minimum_poi if allow_negative_signal else 0.0, poi_upper_bound, ) else: bounds[self.poi_index] = ( self.minimum_poi if allow_negative_signal else 0.0, bounds[self.poi_index], ) return bounds