Skip to content

Commit

Permalink
fix: Guard against nan in test stat calculation (#1993)
Browse files Browse the repository at this point in the history
* Guard against nan from division by zero in pyhf.infer.calculators.AsymptoticCalculator.teststatistic.
* Add use of 'less than or equal to' to docs for tests stats to match equations 14
  and 16 of https://arxiv.org/abs/1007.1727.
* Add tests to ensure that nan conditions in Issue #529 and Issue #1992 are not possible.
  • Loading branch information
matthewfeickert authored Sep 9, 2022
1 parent 287bfae commit ee183eb
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 3 deletions.
3 changes: 2 additions & 1 deletion src/pyhf/infer/calculators.py
Original file line number Diff line number Diff line change
Expand Up @@ -418,8 +418,9 @@ def _false_case():
teststat = (qmu - qmu_A) / (2 * self.sqrtqmuA_v)
return teststat

# Use '<=' rather than '<' to avoid Issue #1992
teststat = tensorlib.conditional(
(sqrtqmu_v < self.sqrtqmuA_v), _true_case, _false_case
(sqrtqmu_v <= self.sqrtqmuA_v), _true_case, _false_case
)
return tensorlib.astensor(teststat)

Expand Down
4 changes: 2 additions & 2 deletions src/pyhf/infer/test_statistics.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def qmu(mu, data, pdf, init_pars, par_bounds, fixed_params, return_fitted_pars=F
\begin{equation}
q_{\mu} = \left\{\begin{array}{ll}
-2\ln\lambda\left(\mu\right), &\hat{\mu} < \mu,\\
-2\ln\lambda\left(\mu\right), &\hat{\mu} \leq \mu,\\
0, & \hat{\mu} > \mu
\end{array}\right.
\end{equation}
Expand Down Expand Up @@ -160,7 +160,7 @@ def qmu_tilde(
\begin{equation}
\tilde{q}_{\mu} = \left\{\begin{array}{ll}
-2\ln\tilde{\lambda}\left(\mu\right), &\hat{\mu} < \mu,\\
-2\ln\tilde{\lambda}\left(\mu\right), &\hat{\mu} \leq \mu,\\
0, & \hat{\mu} > \mu
\end{array}\right.
\end{equation}
Expand Down
34 changes: 34 additions & 0 deletions tests/test_infer.py
Original file line number Diff line number Diff line change
Expand Up @@ -476,3 +476,37 @@ def test_fixed_poi(tmpdir, hypotest_args):
pdf.config.param_set('mu').suggested_fixed = [True]
with pytest.raises(pyhf.exceptions.InvalidModel):
pyhf.infer.hypotest(*hypotest_args)


def test_teststat_nan_guard():
# Example from Issue #1992
model = pyhf.simplemodels.uncorrelated_background(
signal=[1.0], bkg=[1.0], bkg_uncertainty=[1.0]
)
observations = [2]
test_poi = 0.0
data = observations + model.config.auxdata
init_pars = model.config.suggested_init()
par_bounds = model.config.suggested_bounds()
fixed_params = model.config.suggested_fixed()

test_stat = pyhf.infer.test_statistics.qmu_tilde(
test_poi, data, model, init_pars, par_bounds, fixed_params
)
assert test_stat == pytest.approx(0.0)
asymptotic_calculator = pyhf.infer.calculators.AsymptoticCalculator(
data, model, test_stat="qtilde"
)
# ensure not nan
assert ~np.isnan(asymptotic_calculator.teststatistic(test_poi))
assert asymptotic_calculator.teststatistic(test_poi) == pytest.approx(0.0)

# Example from Issue #529
model = pyhf.simplemodels.uncorrelated_background([0.005], [28.0], [5.0])
test_poi = 1.0
data = [28.0] + model.config.auxdata

test_results = pyhf.infer.hypotest(
test_poi, data, model, test_stat="qtilde", return_expected=True
)
assert all(~np.isnan(result) for result in test_results)

0 comments on commit ee183eb

Please sign in to comment.