Allow cirq.resolve_parameter compatible with t-units
Is your feature request related to a use case or problem? Please explain
Minimal example:
import cirq
import cirq_google as cg
import tunits as tu
import sympy
q = cirq.q(0, 0)
c = cirq.Circuit(cirq.X(q)** sympy.Symbol("a"))
# !!!!! I know this is not a valid usage case. The point is just for showing the error.!!!
cirq.resolve_parameters(c, {"a": 10*tu.ns})
We will get the following error see that line f = lambda x: x if symbolic(x) else float(x)
File ~/.virtualenvs/pyle3/lib/python3.12/site-packages/cirq/ops/eigen_gate.py:316, in EigenGate._value_equality_values_.<locals>.<lambda>(x)
307 """The phases by which we multiply the eigenspaces.
308
309 The default implementation assumes that the eigenspaces are constant
(...)
313 fields that affect the eigenspaces.
314 """
315 symbolic = lambda x: isinstance(x, sympy.Expr) and x.free_symbols
--> 316 f = lambda x: x if symbolic(x) else float(x)
317 shifts = (f(self._exponent) * f(self._global_shift + e) for e in self._eigen_shifts())
318 return tuple(s if symbolic(s) else value.PeriodicValue(f(s), 2) for s in shifts)
File ~/.virtualenvs/pyle3/lib/python3.12/site-packages/tunits/core/cython/with_unit.pyx:399, in tunits_core.WithUnit.__float__()
UnitMismatchError: '10 ns' can't be stripped into a float; not dimensionless.
Describe the solution you would prefer
Is that possible that we can avoid this casting to float and allow tunit.Value as another possible case? This can unblock lots of internal gate usages.
How urgent is this for you? Is it blocking important work?
P2 – we should do it in the next couple of quarters
In the example you gave, the problem is not with cirq.resolve_parameters, rather the issue is that EigenGate can't be exponentiated with a time (just doing X**(10 * tu.ns) with no paramount resolution will show the same issue). Do you have a case where a tunits value is allowed if used directly, but fails with parameter resolution?
Yeah, that is not a good example. Let's use the wait gate as example:
https://github.com/quantumlib/Cirq/blob/17c4e95dae4eedb8ea22bc8abee3e03c6fbef4ca/cirq-google/cirq_google/ops/wait_gate.py#L60-L66
Let we replace the line 64 as _duration = cirq.resolve_parameters(self._duration, resolver) instead, running the test, we will encounter the following error:
def test_wait_gate_with_units_resolving() -> None:
gate = wg.WaitGateWithUnit(sympy.Symbol("d"))
> resolved_gate = cirq.resolve_parameters(gate, {"d": 10 * tu.ns})
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
cirq-google/cirq_google/ops/wait_gate_test.py:45:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
../.virtualenvs/cirq-py3/lib/python3.12/site-packages/cirq/protocols/resolve_parameters.py:190: in resolve_parameters
result = getter(param_resolver, recursive)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
cirq-google/cirq_google/ops/wait_gate.py:64: in _resolve_parameters_
_duration = cirq.resolve_parameters(self._duration, resolver)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../.virtualenvs/cirq-py3/lib/python3.12/site-packages/cirq/protocols/resolve_parameters.py:176: in resolve_parameters
return cast(T, param_resolver.value_of(val, recursive))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
../.virtualenvs/cirq-py3/lib/python3.12/site-packages/cirq/study/resolver.py:133: in value_of
v = _resolve_value(param_value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
../.virtualenvs/cirq-py3/lib/python3.12/site-packages/cirq/study/resolver.py:288: in _resolve_value
if val == sympy.pi:
^^^^^^^^^^^^^^^
../.virtualenvs/cirq-py3/lib/python3.12/site-packages/sympy/core/numbers.py:3458: in __eq__
other = _sympify(other)
^^^^^^^^^^^^^^^
../.virtualenvs/cirq-py3/lib/python3.12/site-packages/sympy/core/sympify.py:505: in _sympify
return sympify(a, strict=True)
^^^^^^^^^^^^^^^^^^^^^^^
../.virtualenvs/cirq-py3/lib/python3.12/site-packages/sympy/core/sympify.py:428: in sympify
return sympify(coerce(a))
^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
> ???
E tunits_core.UnitMismatchError: '10 ns' can't be stripped into a float; not dimensionless.
tunits/core/cython/with_unit.pyx:399: UnitMismatchError
One potential issue is that we would need to add tunits as a dependency for cirq-core. I am reluctant to allow more dependencies that are largely Google-specific to cirq-core.
Discussed in cirq cync: we do not want to add this dependency to cirq-core if we can avoid it, since this will include compiled code and cython dependencies for all cirq users. If there is a way to duck-type it without importing, we could consider a change to cirq-core.
This issue has been automatically labeled as stale because 90 days have passed without comments or other activity. If no further activity occurs on this issue and the status/stale label is not removed by a maintainer within 60 days, this issue will be closed. If you would like to restore its status, please leave a comment here; doing so will cause the staleness handler to remove the label.
If you have questions or feedback about this process, we welcome your input. You can open a new issue to let us know (please also reference this issue there, for continuity), or reach out to the project maintainers at [email protected].