Repository: quantumlib/Cirq

Issue:
Sympy Division by Integer in Exponent or Radians throws and error
**Description of the issue**
When using sympy to define a circuit, a ValueError exception might be thrown by NumPy
(ValueError: Integers to negative integer powers are not allowed.)

This happens when there is some division in the exponent by some integer and an attempt to resolve the parameters of the gate/circuit is made.

A simple example of this issue is given below.

**How to reproduce the issue**

```

import cirq
import sympy

Rx_gate = cirq.rx(rads=sympy.Symbol('a')/sympy.Symbol('b'))
cirq.resolve_parameters(Rx_gate,{'a':1, 'b':2})

```

<details>

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-101-ef0861896379> in <module>
----> 1 cirq.resolve_parameters(Rx_1,{'a':a, 'b':b, 't':t, 'm':m})

~/anaconda3/envs/quantum/lib/python3.8/site-packages/cirq/protocols/resolve_parameters.py in resolve_parameters(val, param_resolver, recursive)
    182         result = NotImplemented
    183     else:
--> 184         result = getter(param_resolver, recursive)
    185 
    186     if result is not NotImplemented:

~/anaconda3/envs/quantum/lib/python3.8/site-packages/cirq/ops/eigen_gate.py in _resolve_parameters_(self, resolver, recursive)
    354 
    355     def _resolve_parameters_(self, resolver: 'cirq.ParamResolver', recursive: bool) -> 'EigenGate':
--> 356         return self._with_exponent(exponent=resolver.value_of(self._exponent, recursive))
    357 
    358     def _equal_up_to_global_phase_(self, other, atol):

~/anaconda3/envs/quantum/lib/python3.8/site-packages/cirq/study/resolver.py in value_of(self, value, recursive)
    141             product = self.value_of(value.args[0], recursive)
    142             for factor in value.args[1:]:
--> 143                 product *= self.value_of(factor, recursive)
    144             return product
    145         if isinstance(value, sympy.Pow) and len(value.args) == 2:

~/anaconda3/envs/quantum/lib/python3.8/site-packages/cirq/study/resolver.py in value_of(self, value, recursive)
    144             return product
    145         if isinstance(value, sympy.Pow) and len(value.args) == 2:
--> 146             return np.power(
    147                 self.value_of(value.args[0], recursive), self.value_of(value.args[1], recursive)
    148             )

ValueError: Integers to negative integer powers are not allowed.


</details>

**Cirq version**
0.11.1




Discussion:
@osamarais The following does work:
```
Rx_gate = cirq.rx(rads=sympy.Symbol('a')/sympy.Symbol('b'))
cirq.resolve_parameters(Rx_gate,{'a':1, 'b':2.})
```

The reason why your choice of parameters fails is that internally it evaluates to `np.power(2, -1)`. In math `2^(-1)` is 0.5, but that is not a valid in `int` (the type of both 2 and 1).

A possible solution would be to automatically case `b` to a `float` internally.

Resolving patch:
diff --git a/cirq-core/cirq/study/resolver.py b/cirq-core/cirq/study/resolver.py
--- a/cirq-core/cirq/study/resolver.py
+++ b/cirq-core/cirq/study/resolver.py
@@ -143,9 +143,11 @@ def value_of(
                 product *= self.value_of(factor, recursive)
             return product
         if isinstance(value, sympy.Pow) and len(value.args) == 2:
-            return np.power(
-                self.value_of(value.args[0], recursive), self.value_of(value.args[1], recursive)
-            )
+            base = self.value_of(value.args[0], recursive)
+            exponent = self.value_of(value.args[1], recursive)
+            if isinstance(base, numbers.Number):
+                return np.float_power(base, exponent)
+            return np.power(base, exponent)
 
         if not isinstance(value, sympy.Basic):
             # No known way to resolve this variable, return unchanged.


Test patch:
diff --git a/cirq-core/cirq/study/resolver_test.py b/cirq-core/cirq/study/resolver_test.py
--- a/cirq-core/cirq/study/resolver_test.py
+++ b/cirq-core/cirq/study/resolver_test.py
@@ -128,6 +128,19 @@ def test_value_of_calculations():
     assert r.value_of(sympy.Symbol('b') / 0.1 - sympy.Symbol('a')) == 0.5
 
 
+def test_resolve_integer_division():
+    r = cirq.ParamResolver({'a': 1, 'b': 2})
+    resolved = r.value_of(sympy.Symbol('a') / sympy.Symbol('b'))
+    assert resolved == 0.5
+
+
+def test_resolve_symbol_division():
+    B = sympy.Symbol('B')
+    r = cirq.ParamResolver({'a': 1, 'b': B})
+    resolved = r.value_of(sympy.Symbol('a') / sympy.Symbol('b'))
+    assert resolved == sympy.core.power.Pow(B, -1)
+
+
 def test_param_dict():
     r = cirq.ParamResolver({'a': 0.5, 'b': 0.1})
     r2 = cirq.ParamResolver(r)