diff --git a/docs/api.rst b/docs/api.rst index b87af15e13..8c823d8b75 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -155,6 +155,7 @@ Fits and Tests mle.fixed_poi_fit hypotest intervals.upperlimit + utils.all_pois_floating Exceptions ---------- diff --git a/src/pyhf/infer/__init__.py b/src/pyhf/infer/__init__.py index e89169eb60..debc828e30 100644 --- a/src/pyhf/infer/__init__.py +++ b/src/pyhf/infer/__init__.py @@ -2,6 +2,19 @@ from . import utils from .. import get_backend +from .. import exceptions + + +def _check_hypotest_prerequisites(pdf, data, init_pars, par_bounds, fixed_params): + if pdf.config.poi_index is None: + raise exceptions.UnspecifiedPOI( + 'No POI is defined. A POI is required to run a hypothesis test.' + ) + + if not utils.all_pois_floating(pdf, fixed_params): + raise exceptions.InvalidModel( + f'POI at index [{pdf.config.poi_index}] is set as fixed, which makes inference impossible. Please unfix the POI to continue.' + ) def hypotest( @@ -131,6 +144,8 @@ def hypotest( par_bounds = par_bounds or pdf.config.suggested_bounds() fixed_params = fixed_params or pdf.config.suggested_fixed() + _check_hypotest_prerequisites(pdf, data, init_pars, par_bounds, fixed_params) + calc = utils.create_calculator( calctype, data, diff --git a/src/pyhf/infer/utils.py b/src/pyhf/infer/utils.py index 15c0d9dacf..2b2d2775c9 100644 --- a/src/pyhf/infer/utils.py +++ b/src/pyhf/infer/utils.py @@ -9,6 +9,24 @@ log = logging.getLogger(__name__) +def all_pois_floating(pdf, fixed_params): + r""" + Check whether all POI(s) are floating (i.e. not within the fixed set). + + Args: + pdf (~pyhf.pdf.Model): The statistical model adhering to the schema + ``model.json``. + fixed_params (:obj:`list` or `tensor` of :obj:`bool`): Array of + :obj:`bool` indicating if model parameters are fixed. + + Returns: + :obj:`bool`: The result whether all POIs are floating. + """ + + poi_fixed = fixed_params[pdf.config.poi_index] + return not poi_fixed + + def create_calculator(calctype, *args, **kwargs): """ Creates a calculator object of the specified `calctype`. diff --git a/tests/test_infer.py b/tests/test_infer.py index cffdcc8b73..53d5e9ea2a 100644 --- a/tests/test_infer.py +++ b/tests/test_infer.py @@ -395,3 +395,15 @@ def test_toy_calculator(tmpdir, hypotest_args): assert toy_calculator_qtilde_mu.teststatistic(mu_test) == pytest.approx( 3.938244920380498, 1e-07 ) + + +def test_fixed_poi(tmpdir, hypotest_args): + """ + Check that the return structure of pyhf.infer.hypotest with the + additon of the return_expected keyword arg is as expected + """ + + _, _, pdf = hypotest_args + pdf.config.param_set('mu').suggested_fixed = [True] + with pytest.raises(pyhf.exceptions.InvalidModel): + pyhf.infer.hypotest(*hypotest_args)