Repository: scikit-hep/pyhf

Issue:
Fix `1bin_lumi` test
# Description

This popped up as part of #553. The `1bin_lumi` validation model is buggy. The JSON spec is 2-bin, but the passed in data is 1-bin. We did not catch this before, but the test should be fixed and validation data updated.

See fix in 839ac67bd5aa4bbc2ef166191250f2dcba4dc872

# Expected Behavior

Describe what you thought should have happened

# Actual Behavior

Describe what did happen

# Steps to Reproduce

Detail your environment and `pyhf.__version__` and the commands that you are executing to generate the bug. If you have a large program please make a [Gist](https://gist.github.com/) and link it here. Additionally attach any screen shots as needed.

# Checklist

- [ ] Run `git fetch` to get the most up to date version of `master`
- [ ] Searched through existing Issues to confirm this is not a duplicate issue
- [ ] Filled out the Description, Expected Behavior, Actual Behavior, and Steps to Reproduce sections above or have edited/removed them in a way that fully describes the issue



Discussion:

Resolving patch:
diff --git a/src/pyhf/exceptions/__init__.py b/src/pyhf/exceptions/__init__.py
--- a/src/pyhf/exceptions/__init__.py
+++ b/src/pyhf/exceptions/__init__.py
@@ -68,3 +68,15 @@ class InvalidOptimizer(Exception):
     """
     InvalidOptimizer is raised when trying to set using an optimizer that does not exist.
     """
+
+
+class InvalidPdfParameters(Exception):
+    """
+    InvalidPdfParameters is raised when trying to evaluate a pdf with invalid parameters.
+    """
+
+
+class InvalidPdfData(Exception):
+    """
+    InvalidPdfData is raised when trying to evaluate a pdf with invalid data.
+    """
diff --git a/src/pyhf/pdf.py b/src/pyhf/pdf.py
--- a/src/pyhf/pdf.py
+++ b/src/pyhf/pdf.py
@@ -538,6 +538,23 @@ def logpdf(self, pars, data):
         try:
             tensorlib, _ = get_backend()
             pars, data = tensorlib.astensor(pars), tensorlib.astensor(data)
+            # Verify parameter and data shapes
+            if pars.shape[-1] != len(self.config.suggested_init()):
+                raise exceptions.InvalidPdfParameters(
+                    'eval failed as pars has len {} but {} was expected'.format(
+                        pars.shape[-1], len(self.config.suggested_init())
+                    )
+                )
+
+            if data.shape[-1] != self.nominal_rates.shape[-1] + len(
+                self.config.auxdata
+            ):
+                raise exceptions.InvalidPdfData(
+                    'eval failed as data has len {} but {} was expected'.format(
+                        data.shape[-1],
+                        self.nominal_rates.shape[-1] + len(self.config.auxdata),
+                    )
+                )
 
             actual_data = self.main_model._dataprojection(data)
             aux_data = self.constraint_model._dataprojection(data)


Test patch:
diff --git a/tests/test_pdf.py b/tests/test_pdf.py
--- a/tests/test_pdf.py
+++ b/tests/test_pdf.py
@@ -29,6 +29,38 @@ def test_pdf_inputs(backend):
     )
 
 
+def test_invalid_pdf_pars():
+    source = {
+        "binning": [2, -0.5, 1.5],
+        "bindata": {"data": [55.0], "bkg": [50.0], "bkgerr": [7.0], "sig": [10.0]},
+    }
+    pdf = pyhf.simplemodels.hepdata_like(
+        source['bindata']['sig'], source['bindata']['bkg'], source['bindata']['bkgerr']
+    )
+
+    pars = pdf.config.suggested_init() + [1.0]
+    data = source['bindata']['data'] + pdf.config.auxdata
+
+    with pytest.raises(pyhf.exceptions.InvalidPdfParameters):
+        pdf.logpdf(pars, data)
+
+
+def test_invalid_pdf_data():
+    source = {
+        "binning": [2, -0.5, 1.5],
+        "bindata": {"data": [55.0], "bkg": [50.0], "bkgerr": [7.0], "sig": [10.0]},
+    }
+    pdf = pyhf.simplemodels.hepdata_like(
+        source['bindata']['sig'], source['bindata']['bkg'], source['bindata']['bkgerr']
+    )
+
+    pars = pdf.config.suggested_init()
+    data = source['bindata']['data'] + [10.0] + pdf.config.auxdata
+
+    with pytest.raises(pyhf.exceptions.InvalidPdfData):
+        pdf.logpdf(pars, data)
+
+
 @pytest.mark.fail_mxnet
 def test_pdf_basicapi_tests(backend):
     source = {
diff --git a/tests/test_validation.py b/tests/test_validation.py
--- a/tests/test_validation.py
+++ b/tests/test_validation.py
@@ -77,26 +77,26 @@ def setup_1bin_shapesys(
 
 
 @pytest.fixture(scope='module')
-def spec_1bin_lumi(source=source_1bin_example1()):
+def spec_1bin_lumi():
     spec = {
         "channels": [
             {
                 "name": "channel1",
                 "samples": [
                     {
-                        "data": [20.0, 10.0],
+                        "data": [20.0],
                         "modifiers": [
                             {"data": None, "name": "mu", "type": "normfactor"}
                         ],
                         "name": "signal",
                     },
                     {
-                        "data": [100.0, 0.0],
+                        "data": [100.0],
                         "modifiers": [{"data": None, "name": "lumi", "type": "lumi"}],
                         "name": "background1",
                     },
                     {
-                        "data": [0.0, 100.0],
+                        "data": [0.0],
                         "modifiers": [{"data": None, "name": "lumi", "type": "lumi"}],
                         "name": "background2",
                     },
@@ -120,8 +120,8 @@ def spec_1bin_lumi(source=source_1bin_example1()):
 def expected_result_1bin_lumi(mu=1.0):
     if mu == 1:
         expected_result = {
-            "exp": [0.00905976, 0.0357287, 0.12548957, 0.35338293, 0.69589171],
-            "obs": 0.00941757,
+            "exp": [0.01060338, 0.04022273, 0.13614217, 0.37078321, 0.71104119],
+            "obs": 0.01047275,
         }
     return expected_result
 
@@ -129,7 +129,7 @@ def expected_result_1bin_lumi(mu=1.0):
 @pytest.fixture(scope='module')
 def setup_1bin_lumi(
     source=source_1bin_example1(),
-    spec=spec_1bin_lumi(source_1bin_example1()),
+    spec=spec_1bin_lumi(),
     mu=1,
     expected_result=expected_result_1bin_lumi(1.0),
     config={'init_pars': 2, 'par_bounds': 2},