|
14 | 14 |
|
15 | 15 | """Quantum gates that phase with respect to product-of-pauli observables."""
|
16 | 16 |
|
17 |
| -from typing import Any, Dict, List, Optional, Tuple, Union, TYPE_CHECKING |
| 17 | +from typing import Any, Dict, List, Optional, Tuple, Union, TYPE_CHECKING, Sequence |
18 | 18 | from typing_extensions import Self
|
19 | 19 |
|
20 | 20 | import numpy as np
|
21 | 21 |
|
22 | 22 | from cirq import protocols, value
|
23 | 23 | from cirq._compat import proper_repr
|
24 | 24 | from cirq._doc import document
|
25 |
| -from cirq.ops import gate_features, eigen_gate, common_gates, pauli_gates |
| 25 | +from cirq.ops import ( |
| 26 | + gate_features, |
| 27 | + eigen_gate, |
| 28 | + common_gates, |
| 29 | + pauli_gates, |
| 30 | + clifford_gate, |
| 31 | + pauli_interaction_gate, |
| 32 | +) |
| 33 | + |
26 | 34 |
|
27 | 35 | if TYPE_CHECKING:
|
28 | 36 | import cirq
|
@@ -87,25 +95,29 @@ def _trace_distance_bound_(self) -> Optional[float]:
|
87 | 95 | return abs(np.sin(self._exponent * 0.5 * np.pi))
|
88 | 96 |
|
89 | 97 | def _decompose_into_clifford_with_qubits_(self, qubits):
|
90 |
| - from cirq.ops.clifford_gate import SingleQubitCliffordGate |
91 |
| - from cirq.ops.pauli_interaction_gate import PauliInteractionGate |
92 |
| - |
93 | 98 | if self.exponent % 2 == 0:
|
94 | 99 | return []
|
95 | 100 | if self.exponent % 2 == 0.5:
|
96 | 101 | return [
|
97 |
| - PauliInteractionGate(pauli_gates.X, False, pauli_gates.X, False).on(*qubits), |
98 |
| - SingleQubitCliffordGate.X_sqrt.on_each(*qubits), |
| 102 | + pauli_interaction_gate.PauliInteractionGate( |
| 103 | + pauli_gates.X, False, pauli_gates.X, False |
| 104 | + ).on(*qubits), |
| 105 | + clifford_gate.SingleQubitCliffordGate.X_sqrt.on_each(*qubits), |
99 | 106 | ]
|
100 | 107 | if self.exponent % 2 == 1:
|
101 |
| - return [SingleQubitCliffordGate.X.on_each(*qubits)] |
| 108 | + return [clifford_gate.SingleQubitCliffordGate.X.on_each(*qubits)] |
102 | 109 | if self.exponent % 2 == 1.5:
|
103 | 110 | return [
|
104 |
| - PauliInteractionGate(pauli_gates.X, False, pauli_gates.X, False).on(*qubits), |
105 |
| - SingleQubitCliffordGate.X_nsqrt.on_each(*qubits), |
| 111 | + pauli_interaction_gate.PauliInteractionGate( |
| 112 | + pauli_gates.X, False, pauli_gates.X, False |
| 113 | + ).on(*qubits), |
| 114 | + clifford_gate.SingleQubitCliffordGate.X_nsqrt.on_each(*qubits), |
106 | 115 | ]
|
107 | 116 | return NotImplemented
|
108 | 117 |
|
| 118 | + def _has_stabilizer_effect_(self) -> bool: |
| 119 | + return self.exponent % 2 in (0, 0.5, 1, 1.5) |
| 120 | + |
109 | 121 | def _decompose_(self, qubits: Tuple['cirq.Qid', ...]) -> 'cirq.OP_TREE':
|
110 | 122 | yield common_gates.YPowGate(exponent=-0.5).on_each(*qubits)
|
111 | 123 | yield ZZPowGate(exponent=self.exponent, global_shift=self.global_shift)(*qubits)
|
@@ -192,25 +204,29 @@ def _trace_distance_bound_(self) -> Optional[float]:
|
192 | 204 | return abs(np.sin(self._exponent * 0.5 * np.pi))
|
193 | 205 |
|
194 | 206 | def _decompose_into_clifford_with_qubits_(self, qubits):
|
195 |
| - from cirq.ops.clifford_gate import SingleQubitCliffordGate |
196 |
| - from cirq.ops.pauli_interaction_gate import PauliInteractionGate |
197 |
| - |
198 | 207 | if self.exponent % 2 == 0:
|
199 | 208 | return []
|
200 | 209 | if self.exponent % 2 == 0.5:
|
201 | 210 | return [
|
202 |
| - PauliInteractionGate(pauli_gates.Y, False, pauli_gates.Y, False).on(*qubits), |
203 |
| - SingleQubitCliffordGate.Y_sqrt.on_each(*qubits), |
| 211 | + pauli_interaction_gate.PauliInteractionGate( |
| 212 | + pauli_gates.Y, False, pauli_gates.Y, False |
| 213 | + ).on(*qubits), |
| 214 | + clifford_gate.SingleQubitCliffordGate.Y_sqrt.on_each(*qubits), |
204 | 215 | ]
|
205 | 216 | if self.exponent % 2 == 1:
|
206 |
| - return [SingleQubitCliffordGate.Y.on_each(*qubits)] |
| 217 | + return [clifford_gate.SingleQubitCliffordGate.Y.on_each(*qubits)] |
207 | 218 | if self.exponent % 2 == 1.5:
|
208 | 219 | return [
|
209 |
| - PauliInteractionGate(pauli_gates.Y, False, pauli_gates.Y, False).on(*qubits), |
210 |
| - SingleQubitCliffordGate.Y_nsqrt.on_each(*qubits), |
| 220 | + pauli_interaction_gate.PauliInteractionGate( |
| 221 | + pauli_gates.Y, False, pauli_gates.Y, False |
| 222 | + ).on(*qubits), |
| 223 | + clifford_gate.SingleQubitCliffordGate.Y_nsqrt.on_each(*qubits), |
211 | 224 | ]
|
212 | 225 | return NotImplemented
|
213 | 226 |
|
| 227 | + def _has_stabilizer_effect_(self) -> bool: |
| 228 | + return self.exponent % 2 in (0, 0.5, 1, 1.5) |
| 229 | + |
214 | 230 | def _decompose_(self, qubits: Tuple['cirq.Qid', ...]) -> 'cirq.OP_TREE':
|
215 | 231 | yield common_gates.XPowGate(exponent=0.5).on_each(*qubits)
|
216 | 232 | yield ZZPowGate(exponent=self.exponent, global_shift=self.global_shift)(*qubits)
|
@@ -265,6 +281,34 @@ def _decompose_(self, qubits):
|
265 | 281 | exponent=-2 * self.exponent, global_shift=-self.global_shift / 2
|
266 | 282 | )(qubits[0], qubits[1])
|
267 | 283 |
|
| 284 | + def _decompose_into_clifford_with_qubits_( |
| 285 | + self, qubits: Sequence['cirq.Qid'] |
| 286 | + ) -> Sequence[Union['cirq.Operation', Sequence['cirq.Operation']]]: |
| 287 | + if not self._has_stabilizer_effect_(): |
| 288 | + return NotImplemented |
| 289 | + if self.exponent % 2 == 0: |
| 290 | + return [] |
| 291 | + if self.exponent % 2 == 1: |
| 292 | + return clifford_gate.SingleQubitCliffordGate.Z.on_each(*qubits) |
| 293 | + |
| 294 | + if self.exponent % 2 == 0.5: |
| 295 | + return [ |
| 296 | + pauli_interaction_gate.PauliInteractionGate( |
| 297 | + pauli_gates.Z, False, pauli_gates.Z, False |
| 298 | + ).on(*qubits), |
| 299 | + clifford_gate.SingleQubitCliffordGate.Z_sqrt.on_each(*qubits), |
| 300 | + ] |
| 301 | + else: |
| 302 | + return [ |
| 303 | + pauli_interaction_gate.PauliInteractionGate( |
| 304 | + pauli_gates.Z, False, pauli_gates.Z, False |
| 305 | + ).on(*qubits), |
| 306 | + clifford_gate.SingleQubitCliffordGate.Z_nsqrt.on_each(*qubits), |
| 307 | + ] |
| 308 | + |
| 309 | + def _has_stabilizer_effect_(self) -> bool: |
| 310 | + return self.exponent % 2 in (0, 0.5, 1, 1.5) |
| 311 | + |
268 | 312 | def _eigen_components(self) -> List[Tuple[float, np.ndarray]]:
|
269 | 313 | return [(0, np.diag([1, 0, 0, 1])), (1, np.diag([0, 1, 1, 0]))]
|
270 | 314 |
|
|
0 commit comments