diff --git a/cirq-core/cirq/ops/controlled_gate.py b/cirq-core/cirq/ops/controlled_gate.py index 776f472b09b..615cf94abae 100644 --- a/cirq-core/cirq/ops/controlled_gate.py +++ b/cirq-core/cirq/ops/controlled_gate.py @@ -18,6 +18,7 @@ import cirq from cirq import protocols, value +from cirq._compat import deprecated from cirq.ops import raw_types, controlled_operation as cop from cirq.type_workarounds import NotImplementedType @@ -73,10 +74,10 @@ def __init__( control_qid_shape = (2,) * num_controls if num_controls != len(control_qid_shape): raise ValueError('len(control_qid_shape) != num_controls') - self.control_qid_shape = tuple(control_qid_shape) + self._control_qid_shape = tuple(control_qid_shape) # Convert to sorted tuples - self.control_values = cast( + self._control_values = cast( Tuple[Tuple[int, ...], ...], tuple((val,) if isinstance(val, int) else tuple(sorted(val)) for val in control_values), ) @@ -90,11 +91,47 @@ def __init__( # Flatten nested ControlledGates. if isinstance(sub_gate, ControlledGate): - self.sub_gate = sub_gate.sub_gate # type: ignore - self.control_values += sub_gate.control_values - self.control_qid_shape += sub_gate.control_qid_shape + self._sub_gate = sub_gate.sub_gate # type: ignore + self._control_values += sub_gate.control_values + self._control_qid_shape += sub_gate.control_qid_shape else: - self.sub_gate = sub_gate + self._sub_gate = sub_gate + + @property + def control_qid_shape(self) -> Tuple[int, ...]: + return self._control_qid_shape + + @control_qid_shape.setter # type: ignore + @deprecated( + deadline="v0.15", + fix="The mutators of this class are deprecated, instantiate a new object instead.", + ) + def control_qid_shape(self, control_qid_shape: Tuple[int, ...]): + self._control_qid_shape = control_qid_shape + + @property + def control_values(self) -> Tuple[Tuple[int, ...], ...]: + return self._control_values + + @control_values.setter # type: ignore + @deprecated( + deadline="v0.15", + fix="The mutators of this class are deprecated, instantiate a new object instead.", + ) + def control_values(self, control_values: Tuple[Tuple[int, ...], ...]): + self._control_values = control_values + + @property + def sub_gate(self) -> 'cirq.Gate': + return self._sub_gate + + @sub_gate.setter # type: ignore + @deprecated( + deadline="v0.15", + fix="The mutators of this class are deprecated, instantiate a new object instead.", + ) + def sub_gate(self, sub_gate: 'cirq.Gate'): + self._sub_gate = sub_gate def num_controls(self) -> int: return len(self.control_qid_shape) diff --git a/cirq-core/cirq/ops/controlled_gate_test.py b/cirq-core/cirq/ops/controlled_gate_test.py index 596ebb8147d..b0545b9de5c 100644 --- a/cirq-core/cirq/ops/controlled_gate_test.py +++ b/cirq-core/cirq/ops/controlled_gate_test.py @@ -555,3 +555,16 @@ def num_qubits(self) -> int: (0.25, cirq.unitary(cirq.CZ)), ], ) + + +def test_setters_deprecated(): + gate = cirq.ControlledGate(cirq.Z) + with cirq.testing.assert_deprecated('mutators', deadline='v0.15'): + gate.sub_gate = cirq.X + assert gate.sub_gate == cirq.X + with cirq.testing.assert_deprecated('mutators', deadline='v0.15'): + gate.control_qid_shape = (3, 3) + assert gate.control_qid_shape == (3, 3) + with cirq.testing.assert_deprecated('mutators', deadline='v0.15'): + gate.control_values = ((3,), (3,)) + assert gate.control_values == ((3,), (3,)) diff --git a/cirq-core/cirq/ops/controlled_operation.py b/cirq-core/cirq/ops/controlled_operation.py index 151eff60874..1fb2dca8475 100644 --- a/cirq-core/cirq/ops/controlled_operation.py +++ b/cirq-core/cirq/ops/controlled_operation.py @@ -29,6 +29,7 @@ import numpy as np from cirq import protocols, qis, value +from cirq._compat import deprecated from cirq.ops import raw_types, gate_operation, controlled_gate from cirq.type_workarounds import NotImplementedType @@ -54,7 +55,7 @@ def __init__( if len(control_values) != len(controls): raise ValueError('len(control_values) != len(controls)') # Convert to sorted tuples - self.control_values = cast( + self._control_values = cast( Tuple[Tuple[int, ...], ...], tuple((val,) if isinstance(val, int) else tuple(sorted(val)) for val in control_values), ) @@ -64,13 +65,49 @@ def __init__( raise ValueError(f'Control values <{val!r}> outside of range for qubit <{q!r}>.') if not isinstance(sub_operation, ControlledOperation): - self.controls = tuple(controls) - self.sub_operation = sub_operation + self._controls = tuple(controls) + self._sub_operation = sub_operation else: # Auto-flatten nested controlled operations. - self.controls = tuple(controls) + sub_operation.controls - self.sub_operation = sub_operation.sub_operation - self.control_values += sub_operation.control_values + self._controls = tuple(controls) + sub_operation.controls + self._sub_operation = sub_operation.sub_operation + self._control_values += sub_operation.control_values + + @property + def controls(self) -> Tuple['cirq.Qid', ...]: + return self._controls + + @controls.setter # type: ignore + @deprecated( + deadline="v0.15", + fix="The mutators of this class are deprecated, instantiate a new object instead.", + ) + def controls(self, controls: Tuple['cirq.Qid', ...]): + self._controls = controls + + @property + def control_values(self) -> Tuple[Tuple[int, ...], ...]: + return self._control_values + + @control_values.setter # type: ignore + @deprecated( + deadline="v0.15", + fix="The mutators of this class are deprecated, instantiate a new object instead.", + ) + def control_values(self, control_values: Tuple[Tuple[int, ...], ...]): + self._control_values = control_values + + @property + def sub_operation(self) -> 'cirq.Operation': + return self._sub_operation + + @sub_operation.setter # type: ignore + @deprecated( + deadline="v0.15", + fix="The mutators of this class are deprecated, instantiate a new object instead.", + ) + def sub_operation(self, sub_operation: 'cirq.Operation'): + self._sub_operation = sub_operation @property def gate(self) -> Optional['cirq.ControlledGate']: diff --git a/cirq-core/cirq/ops/controlled_operation_test.py b/cirq-core/cirq/ops/controlled_operation_test.py index 8ce6be78dc5..16c314b45fb 100644 --- a/cirq-core/cirq/ops/controlled_operation_test.py +++ b/cirq-core/cirq/ops/controlled_operation_test.py @@ -397,3 +397,17 @@ def with_qubits(self, *new_qubits): (0.25, cirq.unitary(cirq.CZ)), ], ) + + +def test_setters_deprecated(): + q0, q1, q2 = cirq.LineQubit.range(3) + op = cirq.ControlledOperation([q1], cirq.Z(q0)) + with cirq.testing.assert_deprecated('mutators', deadline='v0.15'): + op.sub_operation = cirq.X(q0) + assert op.sub_operation == cirq.X(q0) + with cirq.testing.assert_deprecated('mutators', deadline='v0.15'): + op.controls = (q2,) + assert op.controls == (q2,) + with cirq.testing.assert_deprecated('mutators', deadline='v0.15'): + op.control_values = ((3,), (3,)) + assert op.control_values == ((3,), (3,)) diff --git a/cirq-core/cirq/ops/measurement_gate.py b/cirq-core/cirq/ops/measurement_gate.py index edd209905ff..2c01abc48b0 100644 --- a/cirq-core/cirq/ops/measurement_gate.py +++ b/cirq-core/cirq/ops/measurement_gate.py @@ -17,6 +17,7 @@ import numpy as np from cirq import protocols, value +from cirq._compat import deprecated from cirq.ops import raw_types if TYPE_CHECKING: @@ -65,8 +66,10 @@ def __init__( self._qid_shape = qid_shape if len(self._qid_shape) != num_qubits: raise ValueError('len(qid_shape) != num_qubits') - self.key = key # type: ignore - self.invert_mask = invert_mask or () + self._mkey = ( + key if isinstance(key, value.MeasurementKey) else value.MeasurementKey(name=key) + ) + self._invert_mask = invert_mask or () if self.invert_mask is not None and len(self.invert_mask) > self.num_qubits(): raise ValueError('len(invert_mask) > num_qubits') @@ -74,12 +77,40 @@ def __init__( def key(self) -> str: return str(self.mkey) - @key.setter + @key.setter # type: ignore + @deprecated( + deadline="v0.15", + fix="The mutators of this class are deprecated, instantiate a new object instead.", + ) def key(self, key: Union[str, 'cirq.MeasurementKey']): if isinstance(key, value.MeasurementKey): - self.mkey = key + self._mkey = key else: - self.mkey = value.MeasurementKey(name=key) + self._mkey = value.MeasurementKey(name=key) + + @property + def mkey(self) -> 'cirq.MeasurementKey': + return self._mkey + + @mkey.setter # type: ignore + @deprecated( + deadline="v0.15", + fix="The mutators of this class are deprecated, instantiate a new object instead.", + ) + def mkey(self, mkey: 'cirq.MeasurementKey'): + self._mkey = mkey + + @property + def invert_mask(self) -> Tuple[bool, ...]: + return self._invert_mask + + @invert_mask.setter # type: ignore + @deprecated( + deadline="v0.15", + fix="The mutators of this class are deprecated, instantiate a new object instead.", + ) + def invert_mask(self, invert_mask: Tuple[bool, ...]): + self._invert_mask = invert_mask def _qid_shape_(self) -> Tuple[int, ...]: return self._qid_shape diff --git a/cirq-core/cirq/ops/measurement_gate_test.py b/cirq-core/cirq/ops/measurement_gate_test.py index bdcfa2a8bac..731ef914459 100644 --- a/cirq-core/cirq/ops/measurement_gate_test.py +++ b/cirq-core/cirq/ops/measurement_gate_test.py @@ -462,3 +462,22 @@ def test_act_on_qutrit(): ) cirq.act_on(m, args) assert args.log_of_measurement_results == {'out': [0, 2]} + + +def test_setters_deprecated(): + gate = cirq.MeasurementGate(1, key='m', invert_mask=(False,)) + with cirq.testing.assert_deprecated('mutators', deadline='v0.15'): + gate.key = 'n' + assert gate.key == 'n' + assert gate.mkey == cirq.MeasurementKey('n') + with cirq.testing.assert_deprecated('mutators', deadline='v0.15'): + gate.key = cirq.MeasurementKey('o') + assert gate.key == 'o' + assert gate.mkey == cirq.MeasurementKey('o') + with cirq.testing.assert_deprecated('mutators', deadline='v0.15'): + gate.mkey = cirq.MeasurementKey('p') + assert gate.key == 'p' + assert gate.mkey == cirq.MeasurementKey('p') + with cirq.testing.assert_deprecated('mutators', deadline='v0.15'): + gate.invert_mask = (True,) + assert gate.invert_mask == (True,)