Skip to content

Perform CliffordState measurements via method dispatch #3503

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

Merged
merged 10 commits into from
Jan 7, 2021
48 changes: 35 additions & 13 deletions cirq/sim/clifford/clifford_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -331,21 +333,40 @@ 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(
'%s cannot be run with Clifford simulator.' % str(op.gate)
) # 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(
Copy link
Collaborator Author

@smitsanghavi smitsanghavi Nov 16, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that the whole function is deprecated now, should I remove the param deprecation annotation?

deadline='v0.10.0',
fix='Use collapse_state_vector instead.',
Expand All @@ -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
):
Expand Down
70 changes: 26 additions & 44 deletions cirq/sim/clifford/clifford_simulator_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,56 +248,13 @@ 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})

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})
Expand Down Expand Up @@ -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)