Repository: quantumlib/Qualtran

Issue:
Nightly tests are failing
https://github.com/quantumlib/Qualtran/actions/runs/12927816318 (jan 23)

cc @NoureldinYosri looks like the mod-sub classical action test is failing after #1518

Discussion:
@NoureldinYosri: the tests pass locally 

```sh
$ pytest qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py -k modsub_classical_action -v
qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_modsub_classical_action[13-4-QUInt] PASSED                                                                                                                                                                                                     [  3%]
qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_modsub_classical_action[13-4-QMontgomeryUInt] PASSED                                                                                                                                                                                           [  6%]
qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_modsub_classical_action[13-5-QUInt] PASSED                                                                                                                                                                                                     [ 10%]
qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_modsub_classical_action[13-5-QMontgomeryUInt] PASSED                                                                                                                                                                                           [ 13%]
qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_modsub_classical_action[17-5-QUInt] PASSED                                                                                                                                                                                                     [ 16%]
qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_modsub_classical_action[17-5-QMontgomeryUInt] PASSED                                                                                                                                                                                           [ 20%]
qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_modsub_classical_action[23-5-QUInt] PASSED                                                                                                                                                                                                     [ 23%]
qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_modsub_classical_action[23-5-QMontgomeryUInt] PASSED                                                                                                                                                                                           [ 26%]
qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_modsub_classical_action_large[32-1000000007] PASSED                                                                                                                                                                                            [ 30%]
qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_modsub_classical_action_large[32-1000000009] PASSED                                                                                                                                                                                            [ 33%]
qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_modsub_classical_action_large[33-1000000007] PASSED                                                                                                                                                                                            [ 36%]
qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_modsub_classical_action_large[33-1000000009] PASSED                                                                                                                                                                                            [ 40%]
qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_modsub_classical_action_fast PASSED                                                                                                                                                                                                            [ 43%]
qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_cmodsub_classical_action[13-4-QUInt-0] PASSED                                                                                                                                                                                                  [ 46%]
qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_cmodsub_classical_action[13-4-QUInt-1] PASSED                                                                                                                                                                                                  [ 50%]
qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_cmodsub_classical_action[13-4-QMontgomeryUInt-0] PASSED                                                                                                                                                                                        [ 53%]
qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_cmodsub_classical_action[13-4-QMontgomeryUInt-1] PASSED                                                                                                                                                                                        [ 56%]
qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_cmodsub_classical_action[13-5-QUInt-0] PASSED                                                                                                                                                                                                  [ 60%]
qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_cmodsub_classical_action[13-5-QUInt-1] PASSED                                                                                                                                                                                                  [ 63%]
qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_cmodsub_classical_action[13-5-QMontgomeryUInt-0] PASSED                                                                                                                                                                                        [ 66%]
qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_cmodsub_classical_action[13-5-QMontgomeryUInt-1] PASSED                                                                                                                                                                                        [ 70%]
qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_cmodsub_classical_action[17-5-QUInt-0] PASSED                                                                                                                                                                                                  [ 73%]
qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_cmodsub_classical_action[17-5-QUInt-1] PASSED                                                                                                                                                                                                  [ 76%]
qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_cmodsub_classical_action[17-5-QMontgomeryUInt-0] PASSED                                                                                                                                                                                        [ 80%]
qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_cmodsub_classical_action[17-5-QMontgomeryUInt-1] PASSED                                                                                                                                                                                        [ 83%]
qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_cmodsub_classical_action_large[32-1000000007] PASSED                                                                                                                                                                                           [ 86%]
qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_cmodsub_classical_action_large[32-1000000009] PASSED                                                                                                                                                                                           [ 90%]
qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_cmodsub_classical_action_large[33-1000000007] PASSED                                                                                                                                                                                           [ 93%]
qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_cmodsub_classical_action_large[33-1000000009] PASSED                                                                                                                                                                                           [ 96%]
qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_cmodsub_classical_action_fast PASSED                                                                                                                                                                                                           [100%]

================================================================================================================================= 30 passed, 402 deselected in 116.37s (0:01:56) =================================================================================================================================
```

and they don't call the bloqs with those inputs ... their input range is `range(prime)`  
https://github.com/quantumlib/Qualtran/blob/123b83aa0d3c1ea09c62ab6b77400501cb790a10/qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py#L173-L174

but the error says they called with `x=prime`

```sh
FAILED qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_modsub_classical_action[13-4-QUInt] - ValueError: x=13 is outside the valid interval for modular addition [0, 13)
FAILED qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_modsub_classical_action[13-4-QMontgomeryUInt] - ValueError: x=13 is outside the valid interval for modular addition [0, 13)
FAILED qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_modsub_classical_action[13-5-QUInt] - ValueError: x=13 is outside the valid interval for modular addition [0, 13)
FAILED qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_modsub_classical_action[13-5-QMontgomeryUInt] - ValueError: x=13 is outside the valid interval for modular addition [0, 13)
FAILED qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_modsub_classical_action[17-5-QUInt] - ValueError: x=17 is outside the valid interval for modular addition [0, 17)
FAILED qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_modsub_classical_action[17-5-QMontgomeryUInt] - ValueError: x=17 is outside the valid interval for modular addition [0, 17)
FAILED qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_modsub_classical_action[23-5-QUInt] - ValueError: x=23 is outside the valid interval for modular addition [0, 23)
FAILED qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_modsub_classical_action[23-5-QMontgomeryUInt] - ValueError: x=23 is outside the valid interval for modular addition [0, 23)
FAILED qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_cmodsub_classical_action[13-4-QUInt-0] - ValueError: x=13 is outside the valid interval for modular addition [0, 13)
FAILED qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_cmodsub_classical_action[13-4-QUInt-1] - ValueError: x=13 is outside the valid interval for modular addition [0, 13)
FAILED qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_cmodsub_classical_action[13-4-QMontgomeryUInt-0] - ValueError: x=13 is outside the valid interval for modular addition [0, 13)
FAILED qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_cmodsub_classical_action[13-4-QMontgomeryUInt-1] - ValueError: x=13 is outside the valid interval for modular addition [0, 13)
FAILED qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_cmodsub_classical_action[13-5-QUInt-0] - ValueError: x=13 is outside the valid interval for modular addition [0, 13)
FAILED qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_cmodsub_classical_action[13-5-QUInt-1] - ValueError: x=13 is outside the valid interval for modular addition [0, 13)
FAILED qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_cmodsub_classical_action[13-5-QMontgomeryUInt-0] - ValueError: x=13 is outside the valid interval for modular addition [0, 13)
FAILED qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_cmodsub_classical_action[13-5-QMontgomeryUInt-1] - ValueError: x=13 is outside the valid interval for modular addition [0, 13)
FAILED qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_cmodsub_classical_action[17-5-QUInt-0] - ValueError: x=17 is outside the valid interval for modular addition [0, 17)
FAILED qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_cmodsub_classical_action[17-5-QUInt-1] - ValueError: x=17 is outside the valid interval for modular addition [0, 17)
FAILED qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_cmodsub_classical_action[17-5-QMontgomeryUInt-0] - ValueError: x=17 is outside the valid interval for modular addition [0, 17)
FAILED qualtran/bloqs/mod_arithmetic/mod_subtraction_test.py::test_cmodsub_classical_action[17-5-QMontgomeryUInt-1] - ValueError: x=17 is outside the valid interval for modular addition [0, 17)
```

---

something is weired with the nightly run@mpharrigan: fwiw the tests fail for me if I run `check/pytest` @mpharrigan: > and they don't call the bloqs with those inputs ... their input range is range(prime)


The error arises when calling via the decomposition. `x=0` gets turned into `x=13` in the call to `ModAdd`@NoureldinYosri: yup. looks like when I ran the tests locally I had an old version of the repo somehow. This fixes it https://github.com/quantumlib/Qualtran/pull/1537

Solution patch:
diff --git a/qualtran/bloqs/mod_arithmetic/mod_addition.py b/qualtran/bloqs/mod_arithmetic/mod_addition.py
index db4fe7db..b165a394 100644
--- a/qualtran/bloqs/mod_arithmetic/mod_addition.py
+++ b/qualtran/bloqs/mod_arithmetic/mod_addition.py
@@ -87,13 +87,15 @@ class ModAdd(Bloq):
     def on_classical_vals(
         self, x: 'ClassicalValT', y: 'ClassicalValT'
     ) -> Dict[str, 'ClassicalValT']:
-        if not (0 <= x < self.mod):
+        # The construction still works when at most one of inputs equals `mod`.
+        special_case = (x == self.mod) ^ (y == self.mod)
+        if not (0 <= x < self.mod or special_case):
             raise ValueError(
-                f'{x=} is outside the valid interval for modular addition [0, {self.mod})'
+                f'{x=} is outside the valid interval for modular addition [0, {self.mod}]'
             )
-        if not (0 <= y < self.mod):
+        if not (0 <= y < self.mod or special_case):
             raise ValueError(
-                f'{y=} is outside the valid interval for modular addition [0, {self.mod})'
+                f'{y=} is outside the valid interval for modular addition [0, {self.mod}]'
             )
 
         y = (x + y) % self.mod
@@ -320,7 +322,7 @@ class CModAddK(Bloq):
 
         if not (0 <= x < self.mod):
             raise ValueError(
-                f'{x=} is outside the valid interval for modular addition [0, {self.mod})'
+                f'{x=} is outside the valid interval for modular addition [0, {self.mod}]'
             )
 
         x = (x + self.k) % self.mod
@@ -508,13 +510,15 @@ class CModAdd(Bloq):
         if ctrl != self.cv:
             return {'ctrl': ctrl, 'x': x, 'y': y}
 
-        if not (0 <= x < self.mod):
+        # The construction still works when at most one of inputs equals `mod`.
+        special_case = (x == self.mod) ^ (y == self.mod)
+        if not (0 <= x < self.mod or special_case):
             raise ValueError(
-                f'{x=} is outside the valid interval for modular addition [0, {self.mod})'
+                f'{x=} is outside the valid interval for modular addition [0, {self.mod}]'
             )
-        if not (0 <= y < self.mod):
+        if not (0 <= y < self.mod or special_case):
             raise ValueError(
-                f'{y=} is outside the valid interval for modular addition [0, {self.mod})'
+                f'{y=} is outside the valid interval for modular addition [0, {self.mod}]'
             )
 
         y = (x + y) % self.mod


Test patch:
diff --git a/qualtran/bloqs/mod_arithmetic/mod_addition_test.py b/qualtran/bloqs/mod_arithmetic/mod_addition_test.py
index bd5a11f4..7786a0ce 100644
--- a/qualtran/bloqs/mod_arithmetic/mod_addition_test.py
+++ b/qualtran/bloqs/mod_arithmetic/mod_addition_test.py
@@ -131,9 +131,8 @@ def test_classical_action_mod_add(prime, bitsize):
 def test_classical_action_cmodadd(control, prime, dtype, bitsize):
     b = CModAdd(dtype(bitsize), mod=prime, cv=control)
     cb = b.decompose_bloq()
-    valid_range = range(prime)
     for c in range(2):
-        for x, y in itertools.product(valid_range, repeat=2):
+        for x, y in itertools.product(range(prime + 1), range(prime)):
             assert b.call_classically(ctrl=c, x=x, y=y) == cb.call_classically(ctrl=c, x=x, y=y)
 
 
@@ -207,7 +206,7 @@ def test_cmod_add_complexity_vs_ref():
 @pytest.mark.parametrize(['prime', 'bitsize'], [(p, bitsize) for p in [5, 7] for bitsize in (5, 6)])
 def test_mod_add_classical_action(bitsize, prime):
     b = ModAdd(bitsize, prime)
-    assert_consistent_classical_action(b, x=range(prime), y=range(prime))
+    assert_consistent_classical_action(b, x=range(prime + 1), y=range(prime))
 
 
 def test_cmodadd_tensor():