Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove public fields for measurement and controlled ops #5061

Merged
merged 2 commits into from
Mar 13, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 43 additions & 6 deletions cirq-core/cirq/ops/controlled_gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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),
)
Expand All @@ -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)
Expand Down
13 changes: 13 additions & 0 deletions cirq-core/cirq/ops/controlled_gate_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,))
49 changes: 43 additions & 6 deletions cirq-core/cirq/ops/controlled_operation.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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),
)
Expand All @@ -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']:
Expand Down
14 changes: 14 additions & 0 deletions cirq-core/cirq/ops/controlled_operation_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,))
41 changes: 36 additions & 5 deletions cirq-core/cirq/ops/measurement_gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -65,21 +66,51 @@ 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')

@property
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
Expand Down
19 changes: 19 additions & 0 deletions cirq-core/cirq/ops/measurement_gate_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,)