From 7fdc0b5a9ed008b0ccb98419ddbd2cb35ed3b233 Mon Sep 17 00:00:00 2001 From: daxfohl Date: Mon, 28 Mar 2022 11:57:44 -0700 Subject: [PATCH 1/6] Enforce state --- .../cirq/protocols/act_on_protocol_test.py | 11 +++---- cirq-core/cirq/sim/act_on_args.py | 18 ++++++++++- .../cirq/sim/act_on_args_container_test.py | 31 ++++++++++++++----- cirq-core/cirq/sim/act_on_args_test.py | 19 +++++++++--- 4 files changed, 59 insertions(+), 20 deletions(-) diff --git a/cirq-core/cirq/protocols/act_on_protocol_test.py b/cirq-core/cirq/protocols/act_on_protocol_test.py index 37dd7d392eb..0adec8cf3d0 100644 --- a/cirq-core/cirq/protocols/act_on_protocol_test.py +++ b/cirq-core/cirq/protocols/act_on_protocol_test.py @@ -28,9 +28,6 @@ def __init__(self, fallback_result: Any = NotImplemented, measurements=None): self.measurements = measurements self.fallback_result = fallback_result - def _perform_measurement(self, qubits): - return self.measurements # coverage: ignore - def _act_on_fallback_( self, action: Any, @@ -64,10 +61,10 @@ def test_act_on_errors(): class Op(cirq.Operation): @property def qubits(self) -> Tuple['cirq.Qid', ...]: - pass + return () def with_qubits(self: TSelf, *new_qubits: 'cirq.Qid') -> TSelf: - pass + return self def _act_on_(self, args): return False @@ -81,10 +78,10 @@ def test_qubits_not_allowed_for_operations(): class Op(cirq.Operation): @property def qubits(self) -> Tuple['cirq.Qid', ...]: - pass + return () def with_qubits(self: TSelf, *new_qubits: 'cirq.Qid') -> TSelf: - pass + return self args = DummyActOnArgs() with pytest.raises( diff --git a/cirq-core/cirq/sim/act_on_args.py b/cirq-core/cirq/sim/act_on_args.py index 9e64dd69493..28b5eae6003 100644 --- a/cirq-core/cirq/sim/act_on_args.py +++ b/cirq-core/cirq/sim/act_on_args.py @@ -30,7 +30,7 @@ import numpy as np from cirq import protocols, value -from cirq._compat import deprecated +from cirq._compat import _warn_or_error, deprecated from cirq.protocols.decompose_protocol import _try_decompose_into_operations_and_qubits from cirq.sim.operation_target import OperationTarget @@ -147,6 +147,10 @@ def copy(self: TSelf, deep_copy_buffers: bool = True) -> TSelf: if self._state is not None: args._state = self._state.copy(deep_copy_buffers=deep_copy_buffers) else: + _warn_or_error( + 'Pass a `QuantumStateRepresentation` into the `ActOnArgs` constructor. The `_on_\n' + 'overrides will be removed in cirq v0.16.\n' + ) self._on_copy(args, deep_copy_buffers) return args @@ -164,6 +168,10 @@ def kronecker_product(self: TSelf, other: TSelf, *, inplace=False) -> TSelf: if self._state is not None and other._state is not None: args._state = self._state.kron(other._state) else: + _warn_or_error( + 'Pass a `QuantumStateRepresentation` into the `ActOnArgs` constructor. The `_on_\n' + 'overrides will be removed in cirq v0.16.\n' + ) self._on_kronecker_product(other, args) args._set_qubits(self.qubits + other.qubits) return args @@ -204,6 +212,10 @@ def factor( extracted._state = e remainder._state = r else: + _warn_or_error( + 'Pass a `QuantumStateRepresentation` into the `ActOnArgs` constructor. The `_on_\n' + 'overrides will be removed in cirq v0.16.\n' + ) self._on_factor(qubits, extracted, remainder, validate, atol) extracted._set_qubits(qubits) remainder._set_qubits([q for q in self.qubits if q not in qubits]) @@ -247,6 +259,10 @@ def transpose_to_qubit_order( if self._state is not None: args._state = self._state.reindex(self.get_axes(qubits)) else: + _warn_or_error( + 'Pass a `QuantumStateRepresentation` into the `ActOnArgs` constructor. The `_on_\n' + 'overrides will be removed in cirq v0.16.\n' + ) self._on_transpose_to_qubit_order(qubits, args) args._set_qubits(qubits) return args diff --git a/cirq-core/cirq/sim/act_on_args_container_test.py b/cirq-core/cirq/sim/act_on_args_container_test.py index e0f004c7a74..c0fdcb82a5a 100644 --- a/cirq-core/cirq/sim/act_on_args_container_test.py +++ b/cirq-core/cirq/sim/act_on_args_container_test.py @@ -11,21 +11,40 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from typing import Any, Dict, List, Optional, Sequence +from typing import Any, Dict, Optional, Sequence import cirq +class EmptyQuantumState(cirq.QuantumStateRepresentation): + def copy(self, deep_copy_buffers=True): + return self + + def measure(self, axes, seed=None): + return [0] * len(axes) + + @property + def supports_factor(self): + return True + + def kron(self, other): + return self + + def factor(self, axes, *, validate=True, atol=1e-07): + return self, self + + def reindex(self, axes): + return self + + class EmptyActOnArgs(cirq.ActOnArgs): def __init__(self, qubits, classical_data): super().__init__( + state=EmptyQuantumState(), qubits=qubits, classical_data=classical_data, ) - def _perform_measurement(self, qubits: Sequence[cirq.Qid]) -> List[int]: - return [0] * len(qubits) - def _act_on_fallback_( self, action: Any, @@ -34,10 +53,6 @@ def _act_on_fallback_( ) -> bool: return True - @property - def allows_factoring(self): - return True - q0, q1, q2 = qs3 = cirq.LineQubit.range(3) qs2 = cirq.LineQubit.range(2) diff --git a/cirq-core/cirq/sim/act_on_args_test.py b/cirq-core/cirq/sim/act_on_args_test.py index a0cab8402e5..28b6dc3a8a4 100644 --- a/cirq-core/cirq/sim/act_on_args_test.py +++ b/cirq-core/cirq/sim/act_on_args_test.py @@ -20,13 +20,24 @@ from cirq.sim import act_on_args -class DummyArgs(cirq.ActOnArgs): - def __init__(self): - super().__init__(qubits=cirq.LineQubit.range(2)) +class DummyQuantumState(cirq.QuantumStateRepresentation): + def copy(self, deep_copy_buffers=True): + return self - def _perform_measurement(self, qubits): + def measure(self, axes, seed=None): return [5, 3] + def reindex(self, axes): + return self + + +class DummyArgs(cirq.ActOnArgs): + def __init__(self): + super().__init__( + state=DummyQuantumState(), + qubits=cirq.LineQubit.range(2) + ) + def _act_on_fallback_( self, action: Any, From 75466db3e5335c6317ac688277981f5c0788ef85 Mon Sep 17 00:00:00 2001 From: daxfohl Date: Mon, 28 Mar 2022 22:30:41 -0700 Subject: [PATCH 2/6] Test deprecations --- cirq-core/cirq/sim/act_on_args.py | 16 ++++++++ cirq-core/cirq/sim/act_on_args_test.py | 51 +++++++++++++++++++++++--- 2 files changed, 62 insertions(+), 5 deletions(-) diff --git a/cirq-core/cirq/sim/act_on_args.py b/cirq-core/cirq/sim/act_on_args.py index 28b5eae6003..9a4cf214060 100644 --- a/cirq-core/cirq/sim/act_on_args.py +++ b/cirq-core/cirq/sim/act_on_args.py @@ -154,6 +154,10 @@ def copy(self: TSelf, deep_copy_buffers: bool = True) -> TSelf: self._on_copy(args, deep_copy_buffers) return args + @deprecated( + deadline='v0.16', + fix='Pass a `QuantumStateRepresentation` into the `ActOnArgs` constructor.', + ) def _on_copy(self: TSelf, args: TSelf, deep_copy_buffers: bool = True): """Subclasses should implement this with any additional state copy functionality.""" @@ -176,6 +180,10 @@ def kronecker_product(self: TSelf, other: TSelf, *, inplace=False) -> TSelf: args._set_qubits(self.qubits + other.qubits) return args + @deprecated( + deadline='v0.16', + fix='Pass a `QuantumStateRepresentation` into the `ActOnArgs` constructor.', + ) def _on_kronecker_product(self: TSelf, other: TSelf, target: TSelf): """Subclasses should implement this with any additional state product functionality, if supported.""" @@ -226,6 +234,10 @@ def allows_factoring(self): """Subclasses that allow factorization should override this.""" return self._state.supports_factor if self._state is not None else False + @deprecated( + deadline='v0.16', + fix='Pass a `QuantumStateRepresentation` into the `ActOnArgs` constructor.', + ) def _on_factor( self: TSelf, qubits: Sequence['cirq.Qid'], @@ -267,6 +279,10 @@ def transpose_to_qubit_order( args._set_qubits(qubits) return args + @deprecated( + deadline='v0.16', + fix='Pass a `QuantumStateRepresentation` into the `ActOnArgs` constructor.', + ) def _on_transpose_to_qubit_order(self: TSelf, qubits: Sequence['cirq.Qid'], target: TSelf): """Subclasses should implement this with any additional state transpose functionality, if supported.""" diff --git a/cirq-core/cirq/sim/act_on_args_test.py b/cirq-core/cirq/sim/act_on_args_test.py index 28b6dc3a8a4..5af2d87c0f4 100644 --- a/cirq-core/cirq/sim/act_on_args_test.py +++ b/cirq-core/cirq/sim/act_on_args_test.py @@ -22,7 +22,7 @@ class DummyQuantumState(cirq.QuantumStateRepresentation): def copy(self, deep_copy_buffers=True): - return self + return self # coverage: ignore def measure(self, axes, seed=None): return [5, 3] @@ -33,10 +33,7 @@ def reindex(self, axes): class DummyArgs(cirq.ActOnArgs): def __init__(self): - super().__init__( - state=DummyQuantumState(), - qubits=cirq.LineQubit.range(2) - ) + super().__init__(state=DummyQuantumState(), qubits=cirq.LineQubit.range(2)) def _act_on_fallback_( self, @@ -106,3 +103,47 @@ def test_field_getters(): assert args.qubit_map == {q: i for i, q in enumerate(cirq.LineQubit.range(2))} with cirq.testing.assert_deprecated('always returns False', deadline='v0.16'): assert not args.ignore_measurement_results + + +def test_on_methods_deprecated(): + class OldStyleArgs(cirq.ActOnArgs): + def _act_on_fallback_(self, action, qubits, allow_decompose=True): + return True # coverage: ignore + + args = OldStyleArgs() + with cirq.testing.assert_deprecated('_on_', deadline='v0.16', count=2): + _ = args.copy() + with cirq.testing.assert_deprecated('_on_', deadline='v0.16', count=2): + _ = args.kronecker_product(args) + with cirq.testing.assert_deprecated('_on_', deadline='v0.16', count=2): + _ = args.factor([]) + with cirq.testing.assert_deprecated('_on_', deadline='v0.16', count=2): + _ = args.transpose_to_qubit_order([]) + + +def test_on_methods_deprecated_if_implemented(): + class OldStyleArgs(cirq.ActOnArgs): + def _act_on_fallback_(self, action, qubits, allow_decompose=True): + return True # coverage: ignore + + def _on_copy(self, args, deep_copy_buffers=True): + pass + + def _on_kronecker_product(self, other, target): + pass + + def _on_factor(self, qubits, extracted, remainder, validate=True, atol=1e-07): + pass + + def _on_transpose_to_qubit_order(self, qubits, target): + pass + + args = OldStyleArgs() + with cirq.testing.assert_deprecated('_on_', deadline='v0.16'): + _ = args.copy() + with cirq.testing.assert_deprecated('_on_', deadline='v0.16'): + _ = args.kronecker_product(args) + with cirq.testing.assert_deprecated('_on_', deadline='v0.16'): + _ = args.factor([]) + with cirq.testing.assert_deprecated('_on_', deadline='v0.16'): + _ = args.transpose_to_qubit_order([]) From de1e37141cf69ceddc4767b1d0988e79db794ff9 Mon Sep 17 00:00:00 2001 From: daxfohl Date: Mon, 28 Mar 2022 22:35:01 -0700 Subject: [PATCH 3/6] Require state --- cirq-core/cirq/sim/act_on_args.py | 2 ++ cirq-core/cirq/sim/act_on_args_test.py | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/cirq-core/cirq/sim/act_on_args.py b/cirq-core/cirq/sim/act_on_args.py index 9a4cf214060..70f8cc465e2 100644 --- a/cirq-core/cirq/sim/act_on_args.py +++ b/cirq-core/cirq/sim/act_on_args.py @@ -78,6 +78,8 @@ def __init__( } ) self._state = state + if state is None: + _warn_or_error('This function will require a valid `state` input in cirq v0.16.') @property def prng(self) -> np.random.RandomState: diff --git a/cirq-core/cirq/sim/act_on_args_test.py b/cirq-core/cirq/sim/act_on_args_test.py index 5af2d87c0f4..b09283c4987 100644 --- a/cirq-core/cirq/sim/act_on_args_test.py +++ b/cirq-core/cirq/sim/act_on_args_test.py @@ -110,7 +110,8 @@ class OldStyleArgs(cirq.ActOnArgs): def _act_on_fallback_(self, action, qubits, allow_decompose=True): return True # coverage: ignore - args = OldStyleArgs() + with cirq.testing.assert_deprecated('state', deadline='v0.16'): + args = OldStyleArgs() with cirq.testing.assert_deprecated('_on_', deadline='v0.16', count=2): _ = args.copy() with cirq.testing.assert_deprecated('_on_', deadline='v0.16', count=2): @@ -138,7 +139,8 @@ def _on_factor(self, qubits, extracted, remainder, validate=True, atol=1e-07): def _on_transpose_to_qubit_order(self, qubits, target): pass - args = OldStyleArgs() + with cirq.testing.assert_deprecated('state', deadline='v0.16'): + args = OldStyleArgs() with cirq.testing.assert_deprecated('_on_', deadline='v0.16'): _ = args.copy() with cirq.testing.assert_deprecated('_on_', deadline='v0.16'): From 56a3b606d3fb07f44efa4805a3785c1799494f80 Mon Sep 17 00:00:00 2001 From: daxfohl Date: Mon, 28 Mar 2022 22:43:16 -0700 Subject: [PATCH 4/6] Fix protocol test --- .../cirq/protocols/act_on_protocol_test.py | 23 +++++++++++-------- cirq-core/cirq/sim/act_on_args_test.py | 6 ++--- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/cirq-core/cirq/protocols/act_on_protocol_test.py b/cirq-core/cirq/protocols/act_on_protocol_test.py index 0adec8cf3d0..5278c69e2ab 100644 --- a/cirq-core/cirq/protocols/act_on_protocol_test.py +++ b/cirq-core/cirq/protocols/act_on_protocol_test.py @@ -20,12 +20,17 @@ from cirq.ops.raw_types import TSelf +class DummyQuantumState(cirq.QuantumStateRepresentation): + def copy(self, deep_copy_buffers=True): + pass + + def measure(self, axes, seed=None): + pass + + class DummyActOnArgs(cirq.ActOnArgs): - def __init__(self, fallback_result: Any = NotImplemented, measurements=None): - super().__init__(np.random.RandomState()) - if measurements is None: - measurements = [] - self.measurements = measurements + def __init__(self, fallback_result: Any = NotImplemented): + super().__init__(np.random.RandomState(), state=DummyQuantumState()) self.fallback_result = fallback_result def _act_on_fallback_( @@ -61,10 +66,10 @@ def test_act_on_errors(): class Op(cirq.Operation): @property def qubits(self) -> Tuple['cirq.Qid', ...]: - return () + pass def with_qubits(self: TSelf, *new_qubits: 'cirq.Qid') -> TSelf: - return self + pass def _act_on_(self, args): return False @@ -78,10 +83,10 @@ def test_qubits_not_allowed_for_operations(): class Op(cirq.Operation): @property def qubits(self) -> Tuple['cirq.Qid', ...]: - return () + pass def with_qubits(self: TSelf, *new_qubits: 'cirq.Qid') -> TSelf: - return self + pass args = DummyActOnArgs() with pytest.raises( diff --git a/cirq-core/cirq/sim/act_on_args_test.py b/cirq-core/cirq/sim/act_on_args_test.py index b09283c4987..c115745d1cf 100644 --- a/cirq-core/cirq/sim/act_on_args_test.py +++ b/cirq-core/cirq/sim/act_on_args_test.py @@ -22,7 +22,7 @@ class DummyQuantumState(cirq.QuantumStateRepresentation): def copy(self, deep_copy_buffers=True): - return self # coverage: ignore + pass def measure(self, axes, seed=None): return [5, 3] @@ -108,7 +108,7 @@ def test_field_getters(): def test_on_methods_deprecated(): class OldStyleArgs(cirq.ActOnArgs): def _act_on_fallback_(self, action, qubits, allow_decompose=True): - return True # coverage: ignore + pass with cirq.testing.assert_deprecated('state', deadline='v0.16'): args = OldStyleArgs() @@ -125,7 +125,7 @@ def _act_on_fallback_(self, action, qubits, allow_decompose=True): def test_on_methods_deprecated_if_implemented(): class OldStyleArgs(cirq.ActOnArgs): def _act_on_fallback_(self, action, qubits, allow_decompose=True): - return True # coverage: ignore + pass def _on_copy(self, args, deep_copy_buffers=True): pass From 39dacd4f59b86756fd65acbc5f44b532371b0394 Mon Sep 17 00:00:00 2001 From: daxfohl Date: Thu, 7 Apr 2022 22:08:33 -0700 Subject: [PATCH 5/6] remove extra linefeeds --- cirq-core/cirq/sim/act_on_args.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cirq-core/cirq/sim/act_on_args.py b/cirq-core/cirq/sim/act_on_args.py index 70f8cc465e2..82bb668109b 100644 --- a/cirq-core/cirq/sim/act_on_args.py +++ b/cirq-core/cirq/sim/act_on_args.py @@ -151,7 +151,7 @@ def copy(self: TSelf, deep_copy_buffers: bool = True) -> TSelf: else: _warn_or_error( 'Pass a `QuantumStateRepresentation` into the `ActOnArgs` constructor. The `_on_\n' - 'overrides will be removed in cirq v0.16.\n' + 'overrides will be removed in cirq v0.16.' ) self._on_copy(args, deep_copy_buffers) return args @@ -176,7 +176,7 @@ def kronecker_product(self: TSelf, other: TSelf, *, inplace=False) -> TSelf: else: _warn_or_error( 'Pass a `QuantumStateRepresentation` into the `ActOnArgs` constructor. The `_on_\n' - 'overrides will be removed in cirq v0.16.\n' + 'overrides will be removed in cirq v0.16.' ) self._on_kronecker_product(other, args) args._set_qubits(self.qubits + other.qubits) @@ -224,7 +224,7 @@ def factor( else: _warn_or_error( 'Pass a `QuantumStateRepresentation` into the `ActOnArgs` constructor. The `_on_\n' - 'overrides will be removed in cirq v0.16.\n' + 'overrides will be removed in cirq v0.16.' ) self._on_factor(qubits, extracted, remainder, validate, atol) extracted._set_qubits(qubits) @@ -275,7 +275,7 @@ def transpose_to_qubit_order( else: _warn_or_error( 'Pass a `QuantumStateRepresentation` into the `ActOnArgs` constructor. The `_on_\n' - 'overrides will be removed in cirq v0.16.\n' + 'overrides will be removed in cirq v0.16.' ) self._on_transpose_to_qubit_order(qubits, args) args._set_qubits(qubits) From 2b3696aa36a3e9a60aa0b2bb7e40fd4e42d780d0 Mon Sep 17 00:00:00 2001 From: daxfohl Date: Thu, 7 Apr 2022 22:10:58 -0700 Subject: [PATCH 6/6] format warning msg --- cirq-core/cirq/sim/act_on_args.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/cirq-core/cirq/sim/act_on_args.py b/cirq-core/cirq/sim/act_on_args.py index 82bb668109b..8f1e10db6d1 100644 --- a/cirq-core/cirq/sim/act_on_args.py +++ b/cirq-core/cirq/sim/act_on_args.py @@ -150,8 +150,8 @@ def copy(self: TSelf, deep_copy_buffers: bool = True) -> TSelf: args._state = self._state.copy(deep_copy_buffers=deep_copy_buffers) else: _warn_or_error( - 'Pass a `QuantumStateRepresentation` into the `ActOnArgs` constructor. The `_on_\n' - 'overrides will be removed in cirq v0.16.' + 'Pass a `QuantumStateRepresentation` into the `ActOnArgs` constructor. The `_on_`' + ' overrides will be removed in cirq v0.16.' ) self._on_copy(args, deep_copy_buffers) return args @@ -175,8 +175,8 @@ def kronecker_product(self: TSelf, other: TSelf, *, inplace=False) -> TSelf: args._state = self._state.kron(other._state) else: _warn_or_error( - 'Pass a `QuantumStateRepresentation` into the `ActOnArgs` constructor. The `_on_\n' - 'overrides will be removed in cirq v0.16.' + 'Pass a `QuantumStateRepresentation` into the `ActOnArgs` constructor. The `_on_`' + ' overrides will be removed in cirq v0.16.' ) self._on_kronecker_product(other, args) args._set_qubits(self.qubits + other.qubits) @@ -223,8 +223,8 @@ def factor( remainder._state = r else: _warn_or_error( - 'Pass a `QuantumStateRepresentation` into the `ActOnArgs` constructor. The `_on_\n' - 'overrides will be removed in cirq v0.16.' + 'Pass a `QuantumStateRepresentation` into the `ActOnArgs` constructor. The `_on_`' + ' overrides will be removed in cirq v0.16.' ) self._on_factor(qubits, extracted, remainder, validate, atol) extracted._set_qubits(qubits) @@ -274,8 +274,8 @@ def transpose_to_qubit_order( args._state = self._state.reindex(self.get_axes(qubits)) else: _warn_or_error( - 'Pass a `QuantumStateRepresentation` into the `ActOnArgs` constructor. The `_on_\n' - 'overrides will be removed in cirq v0.16.' + 'Pass a `QuantumStateRepresentation` into the `ActOnArgs` constructor. The `_on_`' + ' overrides will be removed in cirq v0.16.' ) self._on_transpose_to_qubit_order(qubits, args) args._set_qubits(qubits)