From 6fb3685ae37c3c6375c6b0c8f110a0001b6c411f Mon Sep 17 00:00:00 2001 From: daxfohl Date: Fri, 17 Dec 2021 09:42:25 -0800 Subject: [PATCH 1/2] Fix ignore_measurement_results=True for subcircuits --- cirq-core/cirq/sim/act_on_args.py | 21 ++++++++++++++-- .../cirq/sim/act_on_density_matrix_args.py | 7 +++++- .../cirq/sim/density_matrix_simulator.py | 1 + .../cirq/sim/density_matrix_simulator_test.py | 25 +++++++++++++++++++ cirq-core/cirq/sim/simulator_base.py | 5 ---- 5 files changed, 51 insertions(+), 8 deletions(-) diff --git a/cirq-core/cirq/sim/act_on_args.py b/cirq-core/cirq/sim/act_on_args.py index d28cda196f8..7cba1d876fd 100644 --- a/cirq-core/cirq/sim/act_on_args.py +++ b/cirq-core/cirq/sim/act_on_args.py @@ -29,7 +29,7 @@ import numpy as np -from cirq import protocols +from cirq import protocols, ops from cirq.protocols.decompose_protocol import _try_decompose_into_operations_and_qubits from cirq.sim.operation_target import OperationTarget @@ -47,6 +47,7 @@ def __init__( prng: np.random.RandomState = None, qubits: Sequence['cirq.Qid'] = None, log_of_measurement_results: Dict[str, List[int]] = None, + ignore_measurement_results: bool = False, ): """Inits ActOnArgs. @@ -58,6 +59,10 @@ def __init__( ordering of the computational basis states. log_of_measurement_results: A mutable object that measurements are being recorded into. + ignore_measurement_results: If True, then the simulation + will treat measurement as dephasing instead of collapsing + process. This is only applicable to simulators that can + model dephasing. """ if prng is None: prng = cast(np.random.RandomState, np.random) @@ -68,13 +73,18 @@ def __init__( self._set_qubits(qubits) self.prng = prng self._log_of_measurement_results = log_of_measurement_results + self._ignore_measurement_results = ignore_measurement_results def _set_qubits(self, qubits: Sequence['cirq.Qid']): self._qubits = tuple(qubits) self.qubit_map = {q: i for i, q in enumerate(self.qubits)} def measure(self, qubits: Sequence['cirq.Qid'], key: str, invert_mask: Sequence[bool]): - """Adds a measurement result to the log. + """Measures the qubits and records to `log_of_measurement_results`. + + Any bitmasks will be applied to the measurement record. If + `self._ignore_measurement_results` is set, it dephases instead of + measuring. Args: qubits: The qubits to measure. @@ -86,6 +96,9 @@ def measure(self, qubits: Sequence['cirq.Qid'], key: str, invert_mask: Sequence[ Raises: ValueError: If a measurement key has already been logged to a key. """ + if self.ignore_measurement_results: + self._act_on_fallback_(ops.phase_damp(1), qubits) + return bits = self._perform_measurement(qubits) corrected = [bit ^ (bit < 2 and mask) for bit, mask in zip(bits, invert_mask)] if key in self._log_of_measurement_results: @@ -184,6 +197,10 @@ def _on_transpose_to_qubit_order(self: TSelf, qubits: Sequence['cirq.Qid'], targ def log_of_measurement_results(self) -> Dict[str, List[int]]: return self._log_of_measurement_results + @property + def ignore_measurement_results(self) -> bool: + return self._ignore_measurement_results + @property def qubits(self) -> Tuple['cirq.Qid', ...]: return self._qubits diff --git a/cirq-core/cirq/sim/act_on_density_matrix_args.py b/cirq-core/cirq/sim/act_on_density_matrix_args.py index d1b529d87a9..56f59389d52 100644 --- a/cirq-core/cirq/sim/act_on_density_matrix_args.py +++ b/cirq-core/cirq/sim/act_on_density_matrix_args.py @@ -40,6 +40,7 @@ def __init__( prng: np.random.RandomState, log_of_measurement_results: Dict[str, Any], qubits: Sequence['cirq.Qid'] = None, + ignore_measurement_results: bool = False, ): """Inits ActOnDensityMatrixArgs. @@ -59,8 +60,12 @@ def __init__( effects. log_of_measurement_results: A mutable object that measurements are being recorded into. + ignore_measurement_results: If True, then the simulation + will treat measurement as dephasing instead of collapsing + process. This is only applicable to simulators that can + model dephasing. """ - super().__init__(prng, qubits, log_of_measurement_results) + super().__init__(prng, qubits, log_of_measurement_results, ignore_measurement_results) self.target_tensor = target_tensor self.available_buffer = available_buffer self.qid_shape = qid_shape diff --git a/cirq-core/cirq/sim/density_matrix_simulator.py b/cirq-core/cirq/sim/density_matrix_simulator.py index bad0553f0df..2cb83c3d83d 100644 --- a/cirq-core/cirq/sim/density_matrix_simulator.py +++ b/cirq-core/cirq/sim/density_matrix_simulator.py @@ -208,6 +208,7 @@ def _create_partial_act_on_args( qid_shape=qid_shape, prng=self._prng, log_of_measurement_results=logs, + ignore_measurement_results=self._ignore_measurement_results, ) def _can_be_in_run_prefix(self, val: Any): diff --git a/cirq-core/cirq/sim/density_matrix_simulator_test.py b/cirq-core/cirq/sim/density_matrix_simulator_test.py index 213932eb408..75d2148f7f8 100644 --- a/cirq-core/cirq/sim/density_matrix_simulator_test.py +++ b/cirq-core/cirq/sim/density_matrix_simulator_test.py @@ -514,6 +514,31 @@ def test_simulate(dtype: Type[np.number], split: bool): assert len(result.measurements) == 0 +@pytest.mark.parametrize('split', [True, False]) +def test_simulate_ignore_measurements(split: bool): + q0 = cirq.LineQubit(0) + simulator = cirq.DensityMatrixSimulator( + split_untangled_states=split, ignore_measurement_results=True + ) + circuit = cirq.Circuit(cirq.H(q0), cirq.measure(q0)) + result = simulator.simulate(circuit) + np.testing.assert_almost_equal(result.final_density_matrix, np.eye(2) * 0.5) + assert len(result.measurements) == 0 + + +@pytest.mark.parametrize('split', [True, False]) +def test_simulate_ignore_measurements_subcircuits(split: bool): + q0 = cirq.LineQubit(0) + simulator = cirq.DensityMatrixSimulator( + split_untangled_states=split, ignore_measurement_results=True + ) + circuit = cirq.Circuit(cirq.H(q0), cirq.measure(q0)) + circuit = cirq.Circuit(cirq.CircuitOperation(circuit.freeze())) + result = simulator.simulate(circuit) + np.testing.assert_almost_equal(result.final_density_matrix, np.eye(2) * 0.5) + assert len(result.measurements) == 0 + + @pytest.mark.parametrize('dtype', [np.complex64, np.complex128]) @pytest.mark.parametrize('split', [True, False]) def test_simulate_qudits(dtype: Type[np.number], split: bool): diff --git a/cirq-core/cirq/sim/simulator_base.py b/cirq-core/cirq/sim/simulator_base.py index 7d017b20a79..9c708c65bac 100644 --- a/cirq-core/cirq/sim/simulator_base.py +++ b/cirq-core/cirq/sim/simulator_base.py @@ -206,9 +206,6 @@ def _core_iterator( for moment in noisy_moments: for op in ops.flatten_to_ops(moment): try: - # TODO: support more general measurements. - # Github issue: https://github.com/quantumlib/Cirq/issues/3566 - # Preprocess measurements if all_measurements_are_terminal and measured[op.qubits]: continue @@ -216,8 +213,6 @@ def _core_iterator( measured[op.qubits] = True if all_measurements_are_terminal: continue - if self._ignore_measurement_results: - op = ops.phase_damp(1).on(*op.qubits) # Simulate the operation protocols.act_on(op, sim_state) From dbbf2e11e1d5c01a4516fe5bb2fd7fb6d966d7e3 Mon Sep 17 00:00:00 2001 From: daxfohl Date: Thu, 23 Dec 2021 14:17:55 -0800 Subject: [PATCH 2/2] Note that result of dephase is not logged --- cirq-core/cirq/sim/act_on_args.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cirq-core/cirq/sim/act_on_args.py b/cirq-core/cirq/sim/act_on_args.py index 7cba1d876fd..8538ee80a52 100644 --- a/cirq-core/cirq/sim/act_on_args.py +++ b/cirq-core/cirq/sim/act_on_args.py @@ -61,8 +61,8 @@ def __init__( being recorded into. ignore_measurement_results: If True, then the simulation will treat measurement as dephasing instead of collapsing - process. This is only applicable to simulators that can - model dephasing. + process, and not log the result. This is only applicable to + simulators that can represent mixed states. """ if prng is None: prng = cast(np.random.RandomState, np.random) @@ -84,7 +84,7 @@ def measure(self, qubits: Sequence['cirq.Qid'], key: str, invert_mask: Sequence[ Any bitmasks will be applied to the measurement record. If `self._ignore_measurement_results` is set, it dephases instead of - measuring. + measuring, and no measurement result will be logged. Args: qubits: The qubits to measure.