Skip to content

Commit a05870f

Browse files
authored
Add ActOnCliffordTableauArgs. Support it in _act_on_ for common gates and measurements. (quantumlib#3063)
quantumlib#2948 quantumlib#2423
1 parent 9a5dcd9 commit a05870f

16 files changed

+823
-35
lines changed

cirq/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,7 @@
327327
)
328328

329329
from cirq.sim import (
330+
ActOnCliffordTableauArgs,
330331
ActOnStateVectorArgs,
331332
StabilizerStateChForm,
332333
CIRCUIT_LIKE,

cirq/ops/common_gates.py

Lines changed: 126 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,27 @@ def _apply_unitary_(self, args: 'protocols.ApplyUnitaryArgs'
8484
args.available_buffer *= p
8585
return args.available_buffer
8686

87+
def _act_on_(self, args: Any):
88+
from cirq.sim import clifford
89+
90+
if isinstance(args, clifford.ActOnCliffordTableauArgs):
91+
if protocols.is_parameterized(self) or self.exponent % 0.5 != 0:
92+
return NotImplemented
93+
tableau = args.tableau
94+
q = args.axes[0]
95+
effective_exponent = self._exponent % 2
96+
if effective_exponent == 0.5:
97+
tableau.xs[:, q] ^= tableau.zs[:, q]
98+
tableau.rs[:] ^= (tableau.xs[:, q] & tableau.zs[:, q])
99+
elif effective_exponent == 1:
100+
tableau.rs[:] ^= tableau.zs[:, q]
101+
elif effective_exponent == 1.5:
102+
tableau.rs[:] ^= tableau.xs[:, q] & tableau.zs[:, q]
103+
tableau.xs[:, q] ^= tableau.zs[:, q]
104+
return True
105+
106+
return NotImplemented
107+
87108
def in_su2(self) -> 'XPowGate':
88109
"""Returns an equal-up-global-phase gate from the group SU2."""
89110
return XPowGate(exponent=self._exponent, global_shift=-0.5)
@@ -279,6 +300,29 @@ def _apply_unitary_(self, args: 'protocols.ApplyUnitaryArgs'
279300
args.available_buffer *= p
280301
return args.available_buffer
281302

303+
def _act_on_(self, args: Any):
304+
from cirq.sim import clifford
305+
306+
if isinstance(args, clifford.ActOnCliffordTableauArgs):
307+
if protocols.is_parameterized(self) or self.exponent % 0.5 != 0:
308+
return NotImplemented
309+
tableau = args.tableau
310+
q = args.axes[0]
311+
effective_exponent = self._exponent % 2
312+
if effective_exponent == 0.5:
313+
tableau.rs[:] ^= (tableau.xs[:, q] & (~tableau.zs[:, q]))
314+
(tableau.xs[:, q], tableau.zs[:, q]) = (tableau.zs[:, q].copy(),
315+
tableau.xs[:, q].copy())
316+
elif effective_exponent == 1:
317+
tableau.rs[:] ^= tableau.xs[:, q] ^ tableau.zs[:, q]
318+
elif effective_exponent == 1.5:
319+
tableau.rs[:] ^= (~(tableau.xs[:, q]) & tableau.zs[:, q])
320+
(tableau.xs[:, q], tableau.zs[:, q]) = (tableau.zs[:, q].copy(),
321+
tableau.xs[:, q].copy())
322+
return True
323+
324+
return NotImplemented
325+
282326
def in_su2(self) -> 'YPowGate':
283327
"""Returns an equal-up-global-phase gate from the group SU2."""
284328
return YPowGate(exponent=self._exponent, global_shift=-0.5)
@@ -425,6 +469,27 @@ def _apply_unitary_(self, args: 'protocols.ApplyUnitaryArgs'
425469
args.target_tensor *= p
426470
return args.target_tensor
427471

472+
def _act_on_(self, args: Any):
473+
from cirq.sim import clifford
474+
475+
if isinstance(args, clifford.ActOnCliffordTableauArgs):
476+
if protocols.is_parameterized(self) or self.exponent % 0.5 != 0:
477+
return NotImplemented
478+
tableau = args.tableau
479+
q = args.axes[0]
480+
effective_exponent = self._exponent % 2
481+
if effective_exponent == 0.5:
482+
tableau.rs[:] ^= (tableau.xs[:, q] & tableau.zs[:, q])
483+
tableau.zs[:, q] ^= tableau.xs[:, q]
484+
elif effective_exponent == 1:
485+
tableau.rs[:] ^= tableau.xs[:, q]
486+
elif effective_exponent == 1.5:
487+
tableau.rs[:] ^= tableau.xs[:, q] & (~tableau.zs[:, q])
488+
tableau.zs[:, q] ^= tableau.xs[:, q]
489+
return True
490+
491+
return NotImplemented
492+
428493
def _decompose_into_clifford_with_qubits_(self, qubits):
429494
from cirq.ops.clifford_gate import SingleQubitCliffordGate
430495
if self.exponent % 2 == 0:
@@ -685,6 +750,24 @@ def _apply_unitary_(self, args: 'protocols.ApplyUnitaryArgs'
685750
args.target_tensor *= np.sqrt(2) * p
686751
return args.target_tensor
687752

753+
def _act_on_(self, args: Any):
754+
from cirq.sim import clifford
755+
756+
if isinstance(args, clifford.ActOnCliffordTableauArgs):
757+
if protocols.is_parameterized(self) or self.exponent % 0.5 != 0:
758+
return NotImplemented
759+
tableau = args.tableau
760+
q = args.axes[0]
761+
if self._exponent % 1 != 0:
762+
return NotImplemented
763+
if self._exponent % 2 == 1:
764+
(tableau.xs[:, q], tableau.zs[:, q]) = (tableau.zs[:, q].copy(),
765+
tableau.xs[:, q].copy())
766+
tableau.rs[:] ^= (tableau.xs[:, q] & tableau.zs[:, q])
767+
return True
768+
769+
return NotImplemented
770+
688771
def _decompose_(self, qubits):
689772
q = qubits[0]
690773

@@ -792,6 +875,30 @@ def _apply_unitary_(self, args: 'protocols.ApplyUnitaryArgs'
792875
args.target_tensor *= p
793876
return args.target_tensor
794877

878+
def _act_on_(self, args: Any):
879+
from cirq.sim import clifford
880+
881+
if isinstance(args, clifford.ActOnCliffordTableauArgs):
882+
if protocols.is_parameterized(self) or self.exponent % 1 != 0:
883+
return NotImplemented
884+
tableau = args.tableau
885+
q1 = args.axes[0]
886+
q2 = args.axes[1]
887+
if self._exponent % 2 == 1:
888+
(tableau.xs[:, q2], tableau.zs[:, q2]) = \
889+
(tableau.zs[:, q2].copy(), tableau.xs[:, q2].copy())
890+
tableau.rs[:] ^= tableau.xs[:,q1] & tableau.zs[:,q2] & \
891+
(tableau.xs[:,q2] ^ tableau.zs[:,q1])
892+
tableau.xs[:, q2] ^= tableau.xs[:, q1]
893+
tableau.zs[:, q1] ^= tableau.zs[:, q2]
894+
(tableau.xs[:, q2],
895+
tableau.zs[:, q2]) = (tableau.zs[:, q2].copy(),
896+
tableau.xs[:, q2].copy())
897+
tableau.rs[:] ^= (tableau.xs[:, q2] & tableau.zs[:, q2])
898+
return True
899+
900+
return NotImplemented
901+
795902
def _pauli_expansion_(self) -> value.LinearDict[str]:
796903
if protocols.is_parameterized(self):
797904
return NotImplemented
@@ -858,8 +965,7 @@ def controlled(self,
858965
def _circuit_diagram_info_(self, args: 'cirq.CircuitDiagramInfoArgs'
859966
) -> 'cirq.CircuitDiagramInfo':
860967
return protocols.CircuitDiagramInfo(
861-
wire_symbols=('@', '@'),
862-
exponent=self._diagram_exponent(args))
968+
wire_symbols=('@', '@'), exponent=self._diagram_exponent(args))
863969

864970
def _qasm_(self, args: 'cirq.QasmArgs',
865971
qubits: Tuple['cirq.Qid', ...]) -> Optional[str]:
@@ -973,6 +1079,24 @@ def _apply_unitary_(self, args: 'protocols.ApplyUnitaryArgs'
9731079
args.target_tensor *= p
9741080
return args.target_tensor
9751081

1082+
def _act_on_(self, args: Any):
1083+
from cirq.sim import clifford
1084+
1085+
if isinstance(args, clifford.ActOnCliffordTableauArgs):
1086+
if protocols.is_parameterized(self) or self.exponent % 1 != 0:
1087+
return NotImplemented
1088+
tableau = args.tableau
1089+
q1 = args.axes[0]
1090+
q2 = args.axes[1]
1091+
if self._exponent % 2 == 1:
1092+
tableau.rs[:] ^= (tableau.xs[:, q1] & tableau.zs[:, q2] &
1093+
(~(tableau.xs[:, q2] ^ tableau.zs[:, q1])))
1094+
tableau.xs[:, q2] ^= tableau.xs[:, q1]
1095+
tableau.zs[:, q1] ^= tableau.zs[:, q2]
1096+
return True
1097+
1098+
return NotImplemented
1099+
9761100
def _pauli_expansion_(self) -> value.LinearDict[str]:
9771101
if protocols.is_parameterized(self):
9781102
return NotImplemented

0 commit comments

Comments
 (0)