Source code for zfit_physics.pyhf.loss
from __future__ import annotations
import numpy as np
import zfit
from zfit.util.container import convert_to_container
[docs]
def nll_from_pyhf(data, pdf, *, params=None, init_pars=None, par_bounds=None, fixed_params=None, errordef=None):
"""Create a zfit loss function from a pyhf pdf and data.
Args:
data: Data to be used in the negative log-likelihood (NLL) calculation.
pdf: Probability density function model.
params: Optional; Model parameters for the fit. If None, initial parameters, bounds, and fixed status are recommended by the pdf.
init_pars: Optional; Initial parameter values. Ignored if params is provided.
par_bounds: Optional; Parameter bounds. Ignored if params is provided.
fixed_params: Optional; Boolean indicators of parameter fixed statuses. Ignored if params is provided.
errordef: Optional; Error definition, by default set to 0.5.
"""
if params is None:
init_pars = init_pars or pdf.config.suggested_init()
par_bounds = par_bounds or pdf.config.suggested_bounds()
fixed_params = fixed_params or pdf.config.suggested_fixed()
from pyhf.infer import mle
mle._validate_fit_inputs(init_pars, par_bounds, fixed_params)
params = [
zfit.Parameter(f"param_{i}", init, bound[0], bound[1], floating=not is_fixed)
for i, (init, is_fixed, bound) in enumerate(zip(init_pars, fixed_params, par_bounds, strict=False))
]
else:
if init_pars is not None or par_bounds is not None or fixed_params is not None:
msg = "If `params` are given, `init_pars`, `par_bounds` and `fixed_params` must be None."
raise ValueError(msg)
params = convert_to_container(params)
if errordef is None:
errordef = 0.5
def nll_func(params, *, data=data, pdf=pdf, errordef=errordef):
params = np.asarray(params)
return mle.twice_nll(params, data, pdf) * errordef
return zfit.loss.SimpleLoss(func=nll_func, params=params, errordef=errordef, gradient="num", jit=False)