diff --git a/cirq-core/cirq/ops/fsim_gate.py b/cirq-core/cirq/ops/fsim_gate.py index 99598101661..561fd38f2ed 100644 --- a/cirq-core/cirq/ops/fsim_gate.py +++ b/cirq-core/cirq/ops/fsim_gate.py @@ -23,18 +23,18 @@ import cmath import math -from typing import AbstractSet, Any, Dict, Optional, Tuple, Union +from typing import AbstractSet, Any, Dict, Optional, Tuple import numpy as np import sympy import cirq from cirq import protocols, value -from cirq._compat import proper_repr +from cirq._compat import deprecated, proper_repr from cirq.ops import gate_features, raw_types -def _canonicalize(value: Union[float, sympy.Basic]) -> Union[float, sympy.Basic]: +def _canonicalize(value: 'cirq.TParamVal') -> 'cirq.TParamVal': """Assumes value is 2π-periodic and shifts it into [-π, π).""" if protocols.is_parameterized(value): return value @@ -42,12 +42,12 @@ def _canonicalize(value: Union[float, sympy.Basic]) -> Union[float, sympy.Basic] return value - period * np.floor((value + np.pi) / period) -def _zero_mod_pi(param: Union[float, sympy.Basic]) -> bool: +def _zero_mod_pi(param: 'cirq.TParamVal') -> bool: """Returns True iff param, assumed to be in [-pi, pi), is 0 (mod pi).""" return param in (0.0, -np.pi, -sympy.pi) -def _half_pi_mod_pi(param: Union[float, sympy.Basic]) -> bool: +def _half_pi_mod_pi(param: 'cirq.TParamVal') -> bool: """Returns True iff param, assumed to be in [-pi, pi), is pi/2 (mod pi).""" return param in (-np.pi / 2, np.pi / 2, -sympy.pi / 2, sympy.pi / 2) @@ -78,7 +78,7 @@ class FSimGate(gate_features.InterchangeableQubitsGate, raw_types.Gate): FSimGate(θ, φ) = ISWAP**(-2θ/π) CZPowGate(exponent=-φ/π) """ - def __init__(self, theta: float, phi: float) -> None: + def __init__(self, theta: 'cirq.TParamVal', phi: 'cirq.TParamVal') -> None: """Inits FSimGate. Args: @@ -90,8 +90,32 @@ def __init__(self, theta: float, phi: float) -> None: ``|11⟩`` state is phased. Note: uses opposite sign convention to the CZPowGate. Maximum strength (full cz) is at pi. """ - self.theta = _canonicalize(theta) - self.phi = _canonicalize(phi) + self._theta = _canonicalize(theta) + self._phi = _canonicalize(phi) + + @property + def theta(self) -> 'cirq.TParamVal': + return self._theta + + @theta.setter # type: ignore + @deprecated( + deadline="v0.15", + fix="The mutators of this class are deprecated, instantiate a new object instead.", + ) + def theta(self, theta: 'cirq.TParamVal'): + self._theta = theta + + @property + def phi(self) -> 'cirq.TParamVal': + return self._phi + + @phi.setter # type: ignore + @deprecated( + deadline="v0.15", + fix="The mutators of this class are deprecated, instantiate a new object instead.", + ) + def phi(self, phi: 'cirq.TParamVal'): + self._phi = phi def _num_qubits_(self) -> int: return 2 @@ -249,11 +273,11 @@ class PhasedFSimGate(gate_features.InterchangeableQubitsGate, raw_types.Gate): def __init__( self, - theta: Union[float, sympy.Basic], - zeta: Union[float, sympy.Basic] = 0.0, - chi: Union[float, sympy.Basic] = 0.0, - gamma: Union[float, sympy.Basic] = 0.0, - phi: Union[float, sympy.Basic] = 0.0, + theta: 'cirq.TParamVal', + zeta: 'cirq.TParamVal' = 0.0, + chi: 'cirq.TParamVal' = 0.0, + gamma: 'cirq.TParamVal' = 0.0, + phi: 'cirq.TParamVal' = 0.0, ) -> None: """Inits PhasedFSimGate. @@ -269,18 +293,78 @@ def __init__( phi: Controlled phase angle, in radians. See class docstring above for details. """ - self.theta = _canonicalize(theta) - self.zeta = _canonicalize(zeta) - self.chi = _canonicalize(chi) - self.gamma = _canonicalize(gamma) - self.phi = _canonicalize(phi) + self._theta = _canonicalize(theta) + self._zeta = _canonicalize(zeta) + self._chi = _canonicalize(chi) + self._gamma = _canonicalize(gamma) + self._phi = _canonicalize(phi) + + @property + def theta(self) -> 'cirq.TParamVal': + return self._theta + + @theta.setter # type: ignore + @deprecated( + deadline="v0.15", + fix="The mutators of this class are deprecated, instantiate a new object instead.", + ) + def theta(self, theta: 'cirq.TParamVal'): + self._theta = theta + + @property + def zeta(self) -> 'cirq.TParamVal': + return self._zeta + + @zeta.setter # type: ignore + @deprecated( + deadline="v0.15", + fix="The mutators of this class are deprecated, instantiate a new object instead.", + ) + def zeta(self, zeta: 'cirq.TParamVal'): + self._zeta = zeta + + @property + def chi(self) -> 'cirq.TParamVal': + return self._chi + + @chi.setter # type: ignore + @deprecated( + deadline="v0.15", + fix="The mutators of this class are deprecated, instantiate a new object instead.", + ) + def chi(self, chi: 'cirq.TParamVal'): + self._chi = chi + + @property + def gamma(self) -> 'cirq.TParamVal': + return self._gamma + + @gamma.setter # type: ignore + @deprecated( + deadline="v0.15", + fix="The mutators of this class are deprecated, instantiate a new object instead.", + ) + def gamma(self, gamma: 'cirq.TParamVal'): + self._gamma = gamma + + @property + def phi(self) -> 'cirq.TParamVal': + return self._phi + + @phi.setter # type: ignore + @deprecated( + deadline="v0.15", + fix="The mutators of this class are deprecated, instantiate a new object instead.", + ) + def phi(self, phi: 'cirq.TParamVal'): + self._phi = phi @staticmethod def from_fsim_rz( - theta: Union[float, sympy.Basic], - phi: Union[float, sympy.Basic], - rz_angles_before: Tuple[Union[float, sympy.Basic], Union[float, sympy.Basic]], - rz_angles_after: Tuple[Union[float, sympy.Basic], Union[float, sympy.Basic]], + theta: 'cirq.TParamVal', + phi: 'cirq.TParamVal', + rz_angles_before: Tuple['cirq.TParamVal', 'cirq.TParamVal'], + rz_angles_after: Tuple['cirq.TParamVal', 'cirq.TParamVal'], ) -> 'PhasedFSimGate': """Creates PhasedFSimGate using an alternate parametrization. @@ -302,14 +386,14 @@ def from_fsim_rz( return PhasedFSimGate(theta, zeta, chi, gamma, phi) @property - def rz_angles_before(self) -> Tuple[Union[float, sympy.Basic], Union[float, sympy.Basic]]: + def rz_angles_before(self) -> Tuple['cirq.TParamVal', 'cirq.TParamVal']: """Returns 2-tuple of phase angles applied to qubits before FSimGate.""" b0 = (-self.gamma + self.zeta + self.chi) / 2.0 b1 = (-self.gamma - self.zeta - self.chi) / 2.0 return b0, b1 @property - def rz_angles_after(self) -> Tuple[Union[float, sympy.Basic], Union[float, sympy.Basic]]: + def rz_angles_after(self) -> Tuple['cirq.TParamVal', 'cirq.TParamVal']: """Returns 2-tuple of phase angles applied to qubits after FSimGate.""" a0 = (-self.gamma + self.zeta - self.chi) / 2.0 a1 = (-self.gamma - self.zeta + self.chi) / 2.0 @@ -413,7 +497,7 @@ def _decompose_(self, qubits) -> 'cirq.OP_TREE': makes the top left element of the matrix equal to 1. """ - def to_exponent(angle_rads: Union[float, sympy.Basic]) -> Union[float, sympy.Basic]: + def to_exponent(angle_rads: 'cirq.TParamVal') -> 'cirq.TParamVal': """Divides angle_rads by symbolic or numerical pi.""" pi = sympy.pi if protocols.is_parameterized(angle_rads) else np.pi return angle_rads / pi diff --git a/cirq-core/cirq/ops/fsim_gate_test.py b/cirq-core/cirq/ops/fsim_gate_test.py index b9e41b1a81b..2b0bd2a7f9c 100644 --- a/cirq-core/cirq/ops/fsim_gate_test.py +++ b/cirq-core/cirq/ops/fsim_gate_test.py @@ -804,3 +804,39 @@ def test_phased_fsim_json_dict(): 'gamma': 0.78, 'phi': 0.9, } + + +def test_setters_deprecated(): + gate = cirq.FSimGate(0.1, 0.1) + assert gate.theta == 0.1 + with cirq.testing.assert_deprecated('mutators', deadline='v0.15'): + gate.theta = 0.2 + assert gate.theta == 0.2 + assert gate.phi == 0.1 + with cirq.testing.assert_deprecated('mutators', deadline='v0.15'): + gate.phi = 0.2 + assert gate.phi == 0.2 + + +def test_phased_setters_deprecated(): + gate = cirq.PhasedFSimGate(0.1, 0.1, 0.1, 0.1, 0.1) + assert gate.theta == 0.1 + with cirq.testing.assert_deprecated('mutators', deadline='v0.15'): + gate.theta = 0.2 + assert gate.theta == 0.2 + assert gate.zeta == 0.1 + with cirq.testing.assert_deprecated('mutators', deadline='v0.15'): + gate.zeta = 0.2 + assert gate.zeta == 0.2 + assert gate.chi == 0.1 + with cirq.testing.assert_deprecated('mutators', deadline='v0.15'): + gate.chi = 0.2 + assert gate.chi == 0.2 + assert gate.gamma == 0.1 + with cirq.testing.assert_deprecated('mutators', deadline='v0.15'): + gate.gamma = 0.2 + assert gate.gamma == 0.2 + assert gate.phi == 0.1 + with cirq.testing.assert_deprecated('mutators', deadline='v0.15'): + gate.phi = 0.2 + assert gate.phi == 0.2