diff --git a/cirq/sim/clifford/clifford_simulator.py b/cirq/sim/clifford/clifford_simulator.py index 549a77c8edb..88a19e895a3 100644 --- a/cirq/sim/clifford/clifford_simulator.py +++ b/cirq/sim/clifford/clifford_simulator.py @@ -106,8 +106,7 @@ def _base_iterator( for op in moment: if isinstance(op.gate, ops.MeasurementGate): - key = protocols.measurement_key(op) - measurements[key].extend(state.perform_measurement(op.qubits, self._prng)) + state.apply_measurement(op, measurements, self._prng) elif protocols.has_unitary(op): state.apply_unitary(op) else: @@ -245,16 +244,17 @@ def sample( seed: 'cirq.RANDOM_STATE_OR_SEED_LIKE' = None, ) -> np.ndarray: - measurements = [] + measurements = {} # type: Dict[str, List[np.ndarray]] - for _ in range(repetitions): - measurements.append( - self.state.perform_measurement( - qubits, value.parse_random_state(seed), collapse_state_vector=False - ) + for i in range(repetitions): + self.state.apply_measurement( + cirq.measure(*qubits, key=str(i)), + measurements, + value.parse_random_state(seed), + collapse_state_vector=False, ) - return np.array(measurements, dtype=bool) + return np.array(list(measurements.values()), dtype=bool) @value.value_equality @@ -312,11 +312,13 @@ def __str__(self) -> str: def to_numpy(self) -> np.ndarray: return self.ch_form.to_state_vector() + @deprecated(deadline='v0.11.0', fix='use CliffordTableau instead') def stabilizers(self) -> List[DensePauliString]: """Returns the stabilizer generators of the state. These are n operators {S_1,S_2,...,S_n} such that S_i |psi> = |psi>""" return self.tableau.stabilizers() + @deprecated(deadline='v0.11.0', fix='use CliffordTableau instead') def destabilizers(self) -> List[DensePauliString]: """Returns the destabilizer generators of the state. These are n operators {S_1,S_2,...,S_n} such that along with the stabilizer @@ -331,14 +333,10 @@ def wave_function(self): return self.state_vector() def apply_unitary(self, op: 'cirq.Operation'): - tableau_args = clifford.ActOnCliffordTableauArgs( - self.tableau, [self.qubit_map[i] for i in op.qubits], np.random.RandomState(), {} - ) ch_form_args = clifford.ActOnStabilizerCHFormArgs( self.ch_form, [self.qubit_map[i] for i in op.qubits], np.random.RandomState(), {} ) try: - act_on(op, tableau_args) act_on(op, ch_form_args) except TypeError: raise ValueError( @@ -346,6 +344,29 @@ def apply_unitary(self, op: 'cirq.Operation'): ) # type: ignore return + def apply_measurement( + self, + op: 'cirq.Operation', + measurements: Dict[str, List[np.ndarray]], + prng: np.random.RandomState, + collapse_state_vector=True, + ): + if not isinstance(op.gate, cirq.MeasurementGate): + raise TypeError( + 'apply_measurement only supports cirq.MeasurementGate operations. Found %s instead.' + % str(op.gate) + ) + + if collapse_state_vector: + state = self + else: + state = self.copy() + + qids = [self.qubit_map[i] for i in op.qubits] + + ch_form_args = clifford.ActOnStabilizerCHFormArgs(state.ch_form, qids, prng, measurements) + act_on(op, ch_form_args) + @deprecated_parameter( deadline='v0.10.0', fix='Use collapse_state_vector instead.', @@ -359,6 +380,7 @@ def apply_unitary(self, op: 'cirq.Operation'): }, ), ) + @deprecated(deadline='v0.11.0', fix='Use the apply_measurement instead') def perform_measurement( self, qubits: Sequence[ops.Qid], prng: np.random.RandomState, collapse_state_vector=True ): diff --git a/cirq/sim/clifford/clifford_simulator_test.py b/cirq/sim/clifford/clifford_simulator_test.py index 2aa08e1088b..8e246800629 100644 --- a/cirq/sim/clifford/clifford_simulator_test.py +++ b/cirq/sim/clifford/clifford_simulator_test.py @@ -248,18 +248,6 @@ def test_clifford_state_str(): assert str(state) == "|00⟩" -def test_clifford_state_stabilizers(): - (q0, q1, q2) = (cirq.LineQubit(0), cirq.LineQubit(1), cirq.LineQubit(2)) - state = cirq.CliffordState(qubit_map={q0: 0, q1: 1, q2: 2}) - state.apply_unitary(cirq.H(q0)) - state.apply_unitary(cirq.H(q1)) - state.apply_unitary(cirq.S(q1)) - - f = cirq.DensePauliString - assert state.stabilizers() == [f('XII'), f('IYI'), f('IIZ')] - assert state.destabilizers() == [f('ZII'), f('IZI'), f('IIX')] - - def test_clifford_state_state_vector(): (q0, q1) = (cirq.LineQubit(0), cirq.LineQubit(1)) state = cirq.CliffordState(qubit_map={q0: 0, q1: 1}) @@ -267,37 +255,6 @@ def test_clifford_state_state_vector(): np.testing.assert_equal(state.state_vector(), [1.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j]) -def test_clifford_tableau_str(): - (q0, q1, q2) = (cirq.LineQubit(0), cirq.LineQubit(1), cirq.LineQubit(2)) - state = cirq.CliffordState(qubit_map={q0: 0, q1: 1, q2: 2}) - state.apply_unitary(cirq.H(q0)) - state.apply_unitary(cirq.H(q1)) - state.apply_unitary(cirq.S(q1)) - - assert str(state.tableau) == "+ X I I \n+ I Y I \n+ I I Z " - - -def test_clifford_tableau_repr(): - (q0, q1) = (cirq.LineQubit(0), cirq.LineQubit(1)) - state = cirq.CliffordState(qubit_map={q0: 0, q1: 1}) - f = cirq.DensePauliString - assert repr(state.tableau) == "stabilizers: [{!r}, {!r}]".format(f("ZI"), f("IZ")) - - -def test_clifford_tableau_str_full(): - (q0, q1) = (cirq.LineQubit(0), cirq.LineQubit(1)) - state = cirq.CliffordState(qubit_map={q0: 0, q1: 1}) - state.apply_unitary(cirq.H(q0)) - state.apply_unitary(cirq.S(q0)) - - assert ( - state.tableau._str_full_() == "stable | destable\n" - "-------+----------\n" - "+ Y0 | + Z0 \n" - "+ Z1 | + X1\n" - ) - - def test_stabilizerStateChForm_H(): (q0, q1) = (cirq.LineQubit(0), cirq.LineQubit(1)) state = cirq.CliffordState(qubit_map={q0: 0, q1: 1}) @@ -533,12 +490,37 @@ def test_json_roundtrip(): assert np.allclose(state.ch_form.state_vector(), state_roundtrip.ch_form.state_vector()) +def test_invalid_apply_measurement(): + q0 = cirq.LineQubit(0) + state = cirq.CliffordState(qubit_map={q0: 0}) + measurements = {} + with pytest.raises(TypeError, match='only supports cirq.MeasurementGate'): + _ = state.apply_measurement(cirq.H(q0), measurements, np.random.RandomState()) + assert measurements == {} + + +def test_valid_apply_measurement(): + q0 = cirq.LineQubit(0) + state = cirq.CliffordState(qubit_map={q0: 0}, initial_state=1) + measurements = {} + _ = state.apply_measurement(cirq.measure(q0), measurements, np.random.RandomState()) + assert measurements == {'0': [1]} + + def test_deprecated(): q = cirq.LineQubit(0) clifford_state = cirq.CliffordState({q: 0}) with cirq.testing.assert_logs('wave_function', 'state_vector', 'deprecated'): _ = clifford_state.wave_function() - with cirq.testing.assert_logs('collapse_wavefunction', 'collapse_state_vector', 'deprecated'): + with cirq.testing.assert_logs('stabilizers', 'CliffordTableau', 'deprecated'): + _ = clifford_state.stabilizers() + + with cirq.testing.assert_logs('destabilizers', 'CliffordTableau', 'deprecated'): + _ = clifford_state.destabilizers() + + with cirq.testing.assert_logs( + 'collapse_wavefunction', 'collapse_state_vector', 'apply_measurement', 'deprecated', count=2 + ): # pylint: disable=unexpected-keyword-arg,no-value-for-parameter _ = clifford_state.perform_measurement([q], prng=0, collapse_wavefunction=True)