Skip to content

Commit 4a3274c

Browse files
authored
Move to method dispatch using act_on for CliffordState, Tableau and ChForm (#3456)
Delete all the now-unneeded methods. Remaining work: refactor the measurement code #2948 #2423
1 parent 4676aa9 commit 4a3274c

File tree

4 files changed

+28
-176
lines changed

4 files changed

+28
-176
lines changed

cirq/sim/clifford/__init__.py

+10-10
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,3 @@
1-
from cirq.sim.clifford.clifford_simulator import (
2-
CliffordSimulator,
3-
CliffordState,
4-
CliffordTrialResult,
5-
CliffordSimulatorStepResult,
6-
)
7-
81
from cirq.sim.clifford.clifford_tableau import (
92
CliffordTableau,)
103

@@ -14,8 +7,15 @@
147
from cirq.sim.clifford.act_on_stabilizer_ch_form_args import (
158
ActOnStabilizerCHFormArgs,)
169

17-
from cirq.sim.clifford.stabilizer_sampler import (
18-
StabilizerSampler,)
19-
2010
from cirq.sim.clifford.stabilizer_state_ch_form import (
2111
StabilizerStateChForm,)
12+
13+
from cirq.sim.clifford.clifford_simulator import (
14+
CliffordSimulator,
15+
CliffordState,
16+
CliffordTrialResult,
17+
CliffordSimulatorStepResult,
18+
)
19+
20+
from cirq.sim.clifford.stabilizer_sampler import (
21+
StabilizerSampler,)

cirq/sim/clifford/clifford_simulator.py

+14-93
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,10 @@
3737

3838
import cirq
3939
from cirq import circuits, study, ops, protocols, value
40-
from cirq.ops import pauli_gates
4140
from cirq.ops.clifford_gate import SingleQubitCliffordGate
4241
from cirq.ops.dense_pauli_string import DensePauliString
43-
from cirq.protocols import unitary
44-
from cirq.sim import simulator
45-
from cirq.sim.clifford import clifford_tableau, stabilizer_state_ch_form
42+
from cirq.protocols import act_on, unitary
43+
from cirq.sim import clifford, simulator
4644
from cirq._compat import deprecated, deprecated_parameter
4745

4846

@@ -277,9 +275,8 @@ def __init__(self, qubit_map, initial_state=0):
277275
self.qubit_map = qubit_map
278276
self.n = len(qubit_map)
279277

280-
self.tableau = clifford_tableau.CliffordTableau(self.n, initial_state)
281-
self.ch_form = stabilizer_state_ch_form.StabilizerStateChForm(
282-
self.n, initial_state)
278+
self.tableau = clifford.CliffordTableau(self.n, initial_state)
279+
self.ch_form = clifford.StabilizerStateChForm(self.n, initial_state)
283280

284281
def _json_dict_(self):
285282
return {
@@ -336,94 +333,18 @@ def wave_function(self):
336333
return self.state_vector()
337334

338335
def apply_unitary(self, op: 'cirq.Operation'):
339-
if len(op.qubits) == 1:
340-
self.apply_single_qubit_unitary(op)
341-
elif isinstance(op, GlobalPhaseOperation):
342-
self.ch_form.omega *= op.coefficient
343-
elif op.gate == cirq.CNOT:
344-
self.tableau._CNOT(self.qubit_map[op.qubits[0]],
345-
self.qubit_map[op.qubits[1]])
346-
self.ch_form._CNOT(self.qubit_map[op.qubits[0]],
347-
self.qubit_map[op.qubits[1]])
348-
elif op.gate == cirq.CZ:
349-
self.tableau._CZ(self.qubit_map[op.qubits[0]],
350-
self.qubit_map[op.qubits[1]])
351-
self.ch_form._CZ(self.qubit_map[op.qubits[0]],
352-
self.qubit_map[op.qubits[1]])
353-
else:
336+
tableau_args = clifford.ActOnCliffordTableauArgs(
337+
self.tableau, [self.qubit_map[i] for i in op.qubits],
338+
np.random.RandomState(), {})
339+
ch_form_args = clifford.ActOnStabilizerCHFormArgs(
340+
self.ch_form, [self.qubit_map[i] for i in op.qubits])
341+
try:
342+
act_on(op, tableau_args)
343+
act_on(op, ch_form_args)
344+
except TypeError:
354345
raise ValueError('%s cannot be run with Clifford simulator.' %
355346
str(op.gate)) # type: ignore
356-
357-
def apply_single_qubit_unitary(self, op: 'cirq.Operation'):
358-
qubit = self.qubit_map[op.qubits[0]]
359-
if op.gate == cirq.I:
360-
return
361-
362-
if op.gate == cirq.X:
363-
self._apply_X(qubit)
364-
return
365-
366-
if op.gate == cirq.Y:
367-
self._apply_Y(qubit)
368-
return
369-
370-
if op.gate == cirq.Z:
371-
self._apply_Z(qubit)
372-
return
373-
374-
if op.gate == cirq.H:
375-
self._apply_H(qubit)
376-
return
377-
378-
u = unitary(op)
379-
clifford_gate = SingleQubitCliffordGate.from_unitary(u)
380-
if clifford_gate is None:
381-
raise ValueError('%s cannot be run with Clifford simulator.' %
382-
str(op.gate))
383-
384-
h = unitary(ops.H)
385-
s = unitary(ops.S)
386-
applied_unitary = np.eye(2)
387-
for axis, quarter_turns in clifford_gate.decompose_rotation():
388-
for _ in range(quarter_turns % 4):
389-
if axis == pauli_gates.X:
390-
self._apply_H(qubit)
391-
self._apply_S(qubit)
392-
self._apply_H(qubit)
393-
applied_unitary = h @ s @ h @ applied_unitary
394-
elif axis == pauli_gates.Y:
395-
self._apply_S(qubit)
396-
self._apply_S(qubit)
397-
self._apply_H(qubit)
398-
applied_unitary = h @ s @ s @ applied_unitary
399-
else:
400-
assert axis == pauli_gates.Z
401-
self._apply_S(qubit)
402-
applied_unitary = s @ applied_unitary
403-
404-
max_idx = max(np.ndindex(*u.shape), key=lambda t: abs(u[t]))
405-
phase_shift = u[max_idx] / applied_unitary[max_idx]
406-
self.ch_form.omega *= phase_shift
407-
408-
def _apply_H(self, qubit: int):
409-
self.tableau._H(qubit)
410-
self.ch_form._H(qubit)
411-
412-
def _apply_S(self, qubit: int):
413-
self.tableau._S(qubit)
414-
self.ch_form._S(qubit)
415-
416-
def _apply_X(self, qubit: int):
417-
self.tableau._X(qubit)
418-
self.ch_form._X(qubit)
419-
420-
def _apply_Z(self, qubit: int):
421-
self.tableau._Z(qubit)
422-
self.ch_form._Z(qubit)
423-
424-
def _apply_Y(self, qubit: int):
425-
self.tableau._Y(qubit)
426-
self.ch_form._Y(qubit)
347+
return
427348

428349
@deprecated_parameter(
429350
deadline='v0.10.0',

cirq/sim/clifford/clifford_tableau.py

-29
Original file line numberDiff line numberDiff line change
@@ -136,35 +136,6 @@ def _str_full_(self) -> str:
136136

137137
return string
138138

139-
def _CZ(self, q, r):
140-
self._H(r)
141-
self._CNOT(q, r)
142-
self._H(r)
143-
144-
def _X(self, q):
145-
self.rs[:] ^= self.zs[:, q]
146-
147-
def _Y(self, q):
148-
self.rs[:] ^= self.xs[:, q] ^ self.zs[:, q]
149-
150-
def _Z(self, q):
151-
self.rs[:] ^= self.xs[:, q]
152-
153-
def _S(self, q):
154-
self.rs[:] ^= (self.xs[:, q] & self.zs[:, q])
155-
self.zs[:, q] ^= self.xs[:, q]
156-
157-
def _H(self, q):
158-
(self.xs[:, q], self.zs[:, q]) = (self.zs[:, q].copy(),
159-
self.xs[:, q].copy())
160-
self.rs[:] ^= (self.xs[:, q] & self.zs[:, q])
161-
162-
def _CNOT(self, q1, q2):
163-
self.rs[:] ^= self.xs[:,q1] & self.zs[:,q2] & \
164-
(~(self.xs[:,q2] ^ self.zs[:,q1]))
165-
self.xs[:, q2] ^= self.xs[:, q1]
166-
self.zs[:, q1] ^= self.zs[:, q2]
167-
168139
def _rowsum(self, q1, q2):
169140
"""Implements the "rowsum" routine defined by
170141
Aaronson and Gottesman.

cirq/sim/clifford/stabilizer_state_ch_form.py

+4-44
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
import cirq
1919
from cirq import protocols, value
20+
from cirq.ops import pauli_gates
21+
from cirq.sim import clifford
2022
from cirq.value import big_endian_int_to_digits
2123
from cirq._compat import deprecated
2224

@@ -60,7 +62,8 @@ def __init__(self, num_qubits: int, initial_state: int = 0) -> None:
6062
digit_count=num_qubits,
6163
base=2)):
6264
if val:
63-
self._X(i)
65+
protocols.act_on(pauli_gates.X,
66+
clifford.ActOnStabilizerCHFormArgs(self, [i]))
6467

6568
def _json_dict_(self) -> Dict[str, Any]:
6669
return protocols.obj_to_dict_helper(
@@ -133,66 +136,23 @@ def state_vector(self) -> np.ndarray:
133136
def wave_function(self) -> np.ndarray:
134137
return self.state_vector()
135138

136-
def _S(self, q):
137-
self.M[q, :] ^= self.G[q, :]
138-
self.gamma[q] = (self.gamma[q] - 1) % 4
139-
140139
def _S_right(self, q):
141140
r"""Right multiplication version of S gate."""
142141
self.M[:, q] ^= self.F[:, q]
143142
self.gamma[:] = (self.gamma[:] - self.F[:, q]) % 4
144143

145-
def _Z(self, q):
146-
self._S(q)
147-
self._S(q)
148-
149-
def _X(self, q):
150-
self._H(q)
151-
self._Z(q)
152-
self._H(q)
153-
154-
def _Y(self, q):
155-
self._Z(q)
156-
self._X(q)
157-
self.omega *= 1j
158-
159-
def _CZ(self, q, r):
160-
self.M[q, :] ^= self.G[r, :]
161-
self.M[r, :] ^= self.G[q, :]
162-
163144
def _CZ_right(self, q, r):
164145
r"""Right multiplication version of CZ gate."""
165146
self.M[:, q] ^= self.F[:, r]
166147
self.M[:, r] ^= self.F[:, q]
167148
self.gamma[:] = (self.gamma[:] + 2 * self.F[:, q] * self.F[:, r]) % 4
168149

169-
def _CNOT(self, q, r):
170-
self.gamma[q] = (self.gamma[q] + self.gamma[r] + 2 *
171-
(sum(self.M[q, :] & self.F[r, :]) % 2)) % 4
172-
self.G[r, :] ^= self.G[q, :]
173-
self.F[q, :] ^= self.F[r, :]
174-
self.M[q, :] ^= self.M[r, :]
175-
176150
def _CNOT_right(self, q, r):
177151
r"""Right multiplication version of CNOT gate."""
178152
self.G[:, q] ^= self.G[:, r]
179153
self.F[:, r] ^= self.F[:, q]
180154
self.M[:, q] ^= self.M[:, r]
181155

182-
def _H(self, p):
183-
t = self.s ^ (self.G[p, :] & self.v)
184-
u = self.s ^ (self.F[p, :] & (~self.v)) ^ (self.M[p, :] & self.v)
185-
186-
alpha = sum(self.G[p, :] & (~self.v) & self.s) % 2
187-
beta = sum(self.M[p, :] & (~self.v) & self.s)
188-
beta += sum(self.F[p, :] & self.v & self.M[p, :])
189-
beta += sum(self.F[p, :] & self.v & self.s)
190-
beta %= 2
191-
192-
delta = (self.gamma[p] + 2 * (alpha + beta)) % 4
193-
194-
self.update_sum(t, u, delta=delta, alpha=alpha)
195-
196156
def update_sum(self, t, u, delta=0, alpha=0):
197157
""" Implements the transformation (Proposition 4 in Bravyi et al)
198158

0 commit comments

Comments
 (0)