bloqade-circuit 0.7.12__py3-none-any.whl → 0.8.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of bloqade-circuit might be problematic. Click here for more details.
- bloqade/analysis/address/__init__.py +8 -4
- bloqade/analysis/address/analysis.py +119 -29
- bloqade/analysis/address/impls.py +290 -87
- bloqade/analysis/address/lattice.py +209 -24
- bloqade/analysis/fidelity/analysis.py +2 -2
- bloqade/analysis/measure_id/impls.py +3 -27
- bloqade/cirq_utils/__init__.py +3 -1
- bloqade/cirq_utils/emit/__init__.py +3 -0
- bloqade/cirq_utils/emit/base.py +243 -0
- bloqade/cirq_utils/emit/gate.py +104 -0
- bloqade/cirq_utils/emit/noise.py +90 -0
- bloqade/cirq_utils/emit/qubit.py +35 -0
- bloqade/cirq_utils/lowering.py +664 -0
- bloqade/native/__init__.py +0 -1
- bloqade/native/_prelude.py +3 -3
- bloqade/native/dialects/gate/__init__.py +2 -0
- bloqade/native/dialects/gate/_dialect.py +3 -0
- bloqade/native/dialects/{gates → gate}/_interface.py +5 -5
- bloqade/native/dialects/{gates → gate}/stmts.py +5 -5
- bloqade/native/stdlib/broadcast.py +19 -19
- bloqade/native/stdlib/simple.py +14 -13
- bloqade/native/upstream/__init__.py +5 -0
- bloqade/native/upstream/squin2native.py +136 -0
- bloqade/pyqrack/__init__.py +1 -2
- bloqade/pyqrack/device.py +6 -17
- bloqade/pyqrack/native.py +17 -17
- bloqade/pyqrack/reg.py +1 -6
- bloqade/pyqrack/squin/gate/__init__.py +1 -0
- bloqade/pyqrack/squin/gate/gate.py +136 -0
- bloqade/pyqrack/squin/noise/native.py +120 -54
- bloqade/pyqrack/squin/qubit.py +25 -41
- bloqade/pyqrack/target.py +2 -2
- bloqade/qasm2/dialects/core/address.py +21 -12
- bloqade/qasm2/dialects/noise/fidelity.py +2 -6
- bloqade/qasm2/dialects/noise/model.py +2 -1
- bloqade/qasm2/passes/parallel.py +3 -1
- bloqade/qasm2/rewrite/__init__.py +0 -1
- bloqade/qasm2/rewrite/noise/heuristic_noise.py +7 -17
- bloqade/qasm2/rewrite/parallel_to_glob.py +28 -15
- bloqade/qasm2/rewrite/parallel_to_uop.py +2 -8
- bloqade/qubit/__init__.py +12 -0
- bloqade/qubit/_dialect.py +3 -0
- bloqade/qubit/_interface.py +49 -0
- bloqade/qubit/_prelude.py +45 -0
- bloqade/qubit/analysis/__init__.py +1 -0
- bloqade/qubit/analysis/address_impl.py +40 -0
- bloqade/qubit/stdlib/__init__.py +2 -0
- bloqade/qubit/stdlib/_new.py +34 -0
- bloqade/qubit/stdlib/broadcast.py +62 -0
- bloqade/qubit/stdlib/simple.py +59 -0
- bloqade/qubit/stmts.py +60 -0
- bloqade/rewrite/passes/aggressive_unroll.py +2 -1
- bloqade/squin/__init__.py +44 -17
- bloqade/squin/analysis/__init__.py +0 -1
- bloqade/squin/analysis/schedule.py +2 -2
- bloqade/squin/gate/__init__.py +2 -0
- bloqade/squin/gate/_dialect.py +3 -0
- bloqade/squin/gate/_interface.py +98 -0
- bloqade/squin/gate/stmts.py +119 -0
- bloqade/squin/groups.py +4 -21
- bloqade/squin/noise/__init__.py +1 -9
- bloqade/squin/noise/_dialect.py +1 -1
- bloqade/squin/noise/_interface.py +45 -0
- bloqade/squin/noise/stmts.py +65 -29
- bloqade/squin/rewrite/U3_to_clifford.py +70 -51
- bloqade/squin/rewrite/__init__.py +0 -2
- bloqade/squin/rewrite/remove_dangling_qubits.py +2 -2
- bloqade/squin/rewrite/wrap_analysis.py +4 -35
- bloqade/squin/stdlib/broadcast/__init__.py +34 -0
- bloqade/squin/stdlib/broadcast/_qubit.py +4 -0
- bloqade/squin/stdlib/broadcast/gate.py +260 -0
- bloqade/squin/stdlib/broadcast/noise.py +144 -0
- bloqade/squin/stdlib/simple/__init__.py +33 -0
- bloqade/squin/stdlib/simple/gate.py +242 -0
- bloqade/squin/stdlib/simple/noise.py +126 -0
- bloqade/stim/__init__.py +1 -0
- bloqade/stim/_wrappers.py +6 -0
- bloqade/stim/dialects/noise/emit.py +6 -1
- bloqade/stim/dialects/noise/stmts.py +5 -3
- bloqade/stim/emit/stim_str.py +2 -0
- bloqade/stim/parse/lowering.py +12 -17
- bloqade/stim/passes/__init__.py +0 -1
- bloqade/stim/passes/flatten.py +26 -0
- bloqade/stim/passes/simplify_ifs.py +6 -1
- bloqade/stim/passes/squin_to_stim.py +4 -70
- bloqade/stim/rewrite/__init__.py +0 -4
- bloqade/stim/rewrite/ifs_to_stim.py +23 -29
- bloqade/stim/rewrite/qubit_to_stim.py +90 -41
- bloqade/stim/rewrite/squin_measure.py +9 -18
- bloqade/stim/rewrite/squin_noise.py +132 -108
- bloqade/stim/rewrite/util.py +5 -204
- bloqade/types.py +10 -0
- {bloqade_circuit-0.7.12.dist-info → bloqade_circuit-0.8.0.dist-info}/METADATA +2 -2
- {bloqade_circuit-0.7.12.dist-info → bloqade_circuit-0.8.0.dist-info}/RECORD +96 -100
- bloqade/native/dialects/gates/__init__.py +0 -3
- bloqade/native/dialects/gates/_dialect.py +0 -3
- bloqade/pyqrack/squin/op.py +0 -180
- bloqade/pyqrack/squin/runtime.py +0 -543
- bloqade/pyqrack/squin/wire.py +0 -51
- bloqade/squin/_typeinfer.py +0 -20
- bloqade/squin/analysis/address_impl.py +0 -71
- bloqade/squin/analysis/nsites/__init__.py +0 -9
- bloqade/squin/analysis/nsites/analysis.py +0 -50
- bloqade/squin/analysis/nsites/impls.py +0 -99
- bloqade/squin/analysis/nsites/lattice.py +0 -49
- bloqade/squin/cirq/__init__.py +0 -306
- bloqade/squin/cirq/emit/emit_circuit.py +0 -129
- bloqade/squin/cirq/emit/noise.py +0 -49
- bloqade/squin/cirq/emit/op.py +0 -176
- bloqade/squin/cirq/emit/qubit.py +0 -58
- bloqade/squin/cirq/emit/runtime.py +0 -242
- bloqade/squin/cirq/lowering.py +0 -439
- bloqade/squin/lowering.py +0 -80
- bloqade/squin/noise/_wrapper.py +0 -36
- bloqade/squin/noise/rewrite.py +0 -129
- bloqade/squin/op/__init__.py +0 -41
- bloqade/squin/op/_dialect.py +0 -3
- bloqade/squin/op/_wrapper.py +0 -121
- bloqade/squin/op/number.py +0 -5
- bloqade/squin/op/rewrite.py +0 -46
- bloqade/squin/op/stdlib.py +0 -62
- bloqade/squin/op/stmts.py +0 -300
- bloqade/squin/op/traits.py +0 -43
- bloqade/squin/op/types.py +0 -128
- bloqade/squin/parallel.py +0 -200
- bloqade/squin/qubit.py +0 -194
- bloqade/squin/rewrite/canonicalize.py +0 -60
- bloqade/squin/rewrite/desugar.py +0 -102
- bloqade/squin/stdlib/channel.py +0 -86
- bloqade/squin/stdlib/gate.py +0 -201
- bloqade/squin/types.py +0 -8
- bloqade/squin/wire.py +0 -201
- bloqade/stim/rewrite/wire_identity_elimination.py +0 -24
- bloqade/stim/rewrite/wire_to_stim.py +0 -57
- {bloqade_circuit-0.7.12.dist-info → bloqade_circuit-0.8.0.dist-info}/WHEEL +0 -0
- {bloqade_circuit-0.7.12.dist-info → bloqade_circuit-0.8.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import math
|
|
2
|
+
from typing import Any, TypeVar
|
|
3
|
+
|
|
4
|
+
from kirin.dialects import ilist
|
|
5
|
+
|
|
6
|
+
from bloqade.types import Qubit
|
|
7
|
+
|
|
8
|
+
from ...gate import _interface as gate
|
|
9
|
+
from ...groups import kernel
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@kernel
|
|
13
|
+
def _radian_to_turn(angle: float) -> float:
|
|
14
|
+
"""Convert an angle from radians to turns.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
angle (float): Angle in radians.
|
|
18
|
+
Returns:
|
|
19
|
+
float: Equivalent angle in turns.
|
|
20
|
+
"""
|
|
21
|
+
return angle / (2 * math.pi)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@kernel
|
|
25
|
+
def x(qubits: ilist.IList[Qubit, Any]) -> None:
|
|
26
|
+
"""Apply a Pauli-X gate to a group of qubits.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
qubits (ilist.IList[Qubit, Any]): Target qubits.
|
|
30
|
+
"""
|
|
31
|
+
gate.x(qubits)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@kernel
|
|
35
|
+
def y(qubits: ilist.IList[Qubit, Any]) -> None:
|
|
36
|
+
"""Apply a Pauli-Y gate to a group of qubits.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
qubits (ilist.IList[Qubit, Any]): Target qubits.
|
|
40
|
+
"""
|
|
41
|
+
gate.y(qubits)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@kernel
|
|
45
|
+
def z(qubits: ilist.IList[Qubit, Any]) -> None:
|
|
46
|
+
"""Apply a Pauli-Z gate to a group of qubits.
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
qubits (ilist.IList[Qubit, Any]): Target qubits.
|
|
50
|
+
"""
|
|
51
|
+
gate.z(qubits)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@kernel
|
|
55
|
+
def h(qubits: ilist.IList[Qubit, Any]) -> None:
|
|
56
|
+
"""Apply a Hadamard gate to a group of qubits.
|
|
57
|
+
|
|
58
|
+
Args:
|
|
59
|
+
qubits (ilist.IList[Qubit, Any]): Target qubits.
|
|
60
|
+
"""
|
|
61
|
+
gate.h(qubits)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
@kernel
|
|
65
|
+
def t(qubits: ilist.IList[Qubit, Any]) -> None:
|
|
66
|
+
"""Apply a T gate to a group of qubits.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
qubits (ilist.IList[Qubit, Any]): Target qubits.
|
|
70
|
+
"""
|
|
71
|
+
gate.t(qubits, adjoint=False)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@kernel
|
|
75
|
+
def s(qubits: ilist.IList[Qubit, Any]) -> None:
|
|
76
|
+
"""Apply an S gate to a group of qubits.
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
qubits (ilist.IList[Qubit, Any]): Target qubits.
|
|
80
|
+
"""
|
|
81
|
+
gate.s(qubits, adjoint=False)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
@kernel
|
|
85
|
+
def sqrt_x(qubits: ilist.IList[Qubit, Any]) -> None:
|
|
86
|
+
"""Apply a Sqrt(X) gate to a group of qubits.
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
qubits (ilist.IList[Qubit, Any]): Target qubits.
|
|
90
|
+
"""
|
|
91
|
+
gate.sqrt_x(qubits, adjoint=False)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
@kernel
|
|
95
|
+
def sqrt_y(qubits: ilist.IList[Qubit, Any]) -> None:
|
|
96
|
+
"""Apply a sqrt(Y) gate to a group of qubits.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
qubits (ilist.IList[Qubit, Any]): Target qubits.
|
|
100
|
+
"""
|
|
101
|
+
gate.sqrt_y(qubits, adjoint=False)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
@kernel
|
|
105
|
+
def sqrt_z(qubits: ilist.IList[Qubit, Any]) -> None:
|
|
106
|
+
"""Apply a Sqrt(Z) gate to a group of qubits.
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
qubits (ilist.IList[Qubit, Any]): Target qubits.
|
|
110
|
+
"""
|
|
111
|
+
gate.s(qubits, adjoint=False)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
@kernel
|
|
115
|
+
def t_adj(qubits: ilist.IList[Qubit, Any]) -> None:
|
|
116
|
+
"""Apply the adjoint of a T gate to a group of qubits.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
qubits (ilist.IList[Qubit, Any]): Target qubits.
|
|
120
|
+
"""
|
|
121
|
+
gate.t(qubits, adjoint=True)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
@kernel
|
|
125
|
+
def s_adj(qubits: ilist.IList[Qubit, Any]) -> None:
|
|
126
|
+
"""Apply the adjoint of an S gate to a group of qubits.
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
qubits (ilist.IList[Qubit, Any]): Target qubits.
|
|
130
|
+
"""
|
|
131
|
+
gate.s(qubits, adjoint=True)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
@kernel
|
|
135
|
+
def sqrt_x_adj(qubits: ilist.IList[Qubit, Any]) -> None:
|
|
136
|
+
"""Apply the adjoint of a Sqrt(X) gate to a group of qubits.
|
|
137
|
+
|
|
138
|
+
Args:
|
|
139
|
+
qubits (ilist.IList[Qubit, Any]): Target qubits.
|
|
140
|
+
"""
|
|
141
|
+
gate.sqrt_x(qubits, adjoint=True)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
@kernel
|
|
145
|
+
def sqrt_y_adj(qubits: ilist.IList[Qubit, Any]) -> None:
|
|
146
|
+
"""Apply the adjoint of a Sqrt(Y) gate to a group of qubits.
|
|
147
|
+
|
|
148
|
+
Args:
|
|
149
|
+
qubits (ilist.IList[Qubit, Any]): Target qubits.
|
|
150
|
+
"""
|
|
151
|
+
gate.sqrt_y(qubits, adjoint=True)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
@kernel
|
|
155
|
+
def sqrt_z_adj(qubits: ilist.IList[Qubit, Any]) -> None:
|
|
156
|
+
"""Apply the adjoint of a Sqrt(Z) gate to a group of qubits.
|
|
157
|
+
|
|
158
|
+
Args:
|
|
159
|
+
qubits (ilist.IList[Qubit, Any]): Target qubits.
|
|
160
|
+
"""
|
|
161
|
+
gate.s(qubits, adjoint=True)
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
@kernel
|
|
165
|
+
def rx(angle: float, qubits: ilist.IList[Qubit, Any]) -> None:
|
|
166
|
+
"""Apply an RX rotation gate to a group of qubits.
|
|
167
|
+
|
|
168
|
+
Args:
|
|
169
|
+
angle (float): Rotation angle in radians.
|
|
170
|
+
qubits (ilist.IList[Qubit, Any]): Target qubits.
|
|
171
|
+
"""
|
|
172
|
+
gate.rx(_radian_to_turn(angle), qubits)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
@kernel
|
|
176
|
+
def ry(angle: float, qubits: ilist.IList[Qubit, Any]) -> None:
|
|
177
|
+
"""Apply an RY rotation gate to a group of qubits.
|
|
178
|
+
|
|
179
|
+
Args:
|
|
180
|
+
angle (float): Rotation angle in radians.
|
|
181
|
+
qubits (ilist.IList[Qubit, Any]): Target qubits.
|
|
182
|
+
"""
|
|
183
|
+
gate.ry(_radian_to_turn(angle), qubits)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
@kernel
|
|
187
|
+
def rz(angle: float, qubits: ilist.IList[Qubit, Any]) -> None:
|
|
188
|
+
"""Apply an RZ rotation gate to a group of qubits.
|
|
189
|
+
|
|
190
|
+
Args:
|
|
191
|
+
angle (float): Rotation angle in radians.
|
|
192
|
+
qubits (ilist.IList[Qubit, Any]): Target qubits.
|
|
193
|
+
"""
|
|
194
|
+
gate.rz(_radian_to_turn(angle), qubits)
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
Len = TypeVar("Len", bound=int)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
@kernel
|
|
201
|
+
def cx(controls: ilist.IList[Qubit, Len], targets: ilist.IList[Qubit, Len]) -> None:
|
|
202
|
+
"""Apply a controlled-X gate to pairs of qubits.
|
|
203
|
+
|
|
204
|
+
Args:
|
|
205
|
+
controls (ilist.IList[Qubit, N]): Control qubits.
|
|
206
|
+
targets (ilist.IList[Qubit, N]): Target qubits.
|
|
207
|
+
"""
|
|
208
|
+
gate.cx(controls, targets)
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
@kernel
|
|
212
|
+
def cy(controls: ilist.IList[Qubit, Len], targets: ilist.IList[Qubit, Len]) -> None:
|
|
213
|
+
"""Apply a controlled-Y gate to pairs of qubits.
|
|
214
|
+
|
|
215
|
+
Args:
|
|
216
|
+
controls (ilist.IList[Qubit, N]): Control qubits.
|
|
217
|
+
targets (ilist.IList[Qubit, N]): Target qubits.
|
|
218
|
+
"""
|
|
219
|
+
gate.cy(controls, targets)
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
@kernel
|
|
223
|
+
def cz(controls: ilist.IList[Qubit, Len], targets: ilist.IList[Qubit, Len]) -> None:
|
|
224
|
+
"""Apply a controlled-Z gate to pairs of qubits.
|
|
225
|
+
|
|
226
|
+
Args:
|
|
227
|
+
controls (ilist.IList[Qubit, N]): Control qubits.
|
|
228
|
+
targets (ilist.IList[Qubit, N]): Target qubits.
|
|
229
|
+
"""
|
|
230
|
+
gate.cz(controls, targets)
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
@kernel
|
|
234
|
+
def u3(theta: float, phi: float, lam: float, qubits: ilist.IList[Qubit, Any]):
|
|
235
|
+
"""Apply the U3 gate to a group of qubits.
|
|
236
|
+
|
|
237
|
+
The applied gate is represented by the unitary matrix given by:
|
|
238
|
+
|
|
239
|
+
$$ U3(\\theta, \\phi, \\lambda) = R_z(\\phi)R_y(\\theta)R_z(\\lambda) $$
|
|
240
|
+
|
|
241
|
+
Args:
|
|
242
|
+
theta (float): Rotation around Y axis (radians).
|
|
243
|
+
phi (float): Global phase shift component (radians).
|
|
244
|
+
lam (float): Z rotations in decomposition (radians).
|
|
245
|
+
qubits (ilist.IList[qubit.Qubit, Any]): Target qubits.
|
|
246
|
+
"""
|
|
247
|
+
gate.u3(_radian_to_turn(theta), _radian_to_turn(phi), _radian_to_turn(lam), qubits)
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
# NOTE: stdlib not wrapping statements starts here
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
@kernel
|
|
254
|
+
def shift(angle: float, qubits: ilist.IList[Qubit, Any]) -> None:
|
|
255
|
+
"""Apply a phase shift to the |1> state to a group of qubits.
|
|
256
|
+
Args:
|
|
257
|
+
angle (float): Phase shift angle in radians.
|
|
258
|
+
qubits (ilist.IList[qubit.Qubit, Any]): Target qubits.
|
|
259
|
+
"""
|
|
260
|
+
rz(angle / 2.0, qubits)
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
from typing import Any, Literal, TypeVar
|
|
2
|
+
|
|
3
|
+
from kirin.dialects import ilist
|
|
4
|
+
|
|
5
|
+
from bloqade.types import Qubit
|
|
6
|
+
|
|
7
|
+
from ...noise import _interface as noise
|
|
8
|
+
from ...groups import kernel
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@kernel
|
|
12
|
+
def depolarize(p: float, qubits: ilist.IList[Qubit, Any]) -> None:
|
|
13
|
+
"""
|
|
14
|
+
Apply a depolarizing noise channel to a list of qubits with probability `p`.
|
|
15
|
+
|
|
16
|
+
For each qubit, this will randomly select one of the Pauli operators X, Y, Z
|
|
17
|
+
with a probability `p / 3` and apply it to the qubit. No operator is applied
|
|
18
|
+
with a probability of `1 - p`.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
p (float): The probability with which a Pauli operator is applied.
|
|
22
|
+
qubits (IList[Qubit, Any]): The list of qubits to which the noise channel is applied.
|
|
23
|
+
"""
|
|
24
|
+
noise.depolarize(p, qubits)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
N = TypeVar("N", bound=int)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@kernel
|
|
31
|
+
def depolarize2(
|
|
32
|
+
p: float, controls: ilist.IList[Qubit, N], targets: ilist.IList[Qubit, N]
|
|
33
|
+
) -> None:
|
|
34
|
+
"""
|
|
35
|
+
Symmetric two-qubit depolarization channel applied to a set of control and target qubits.
|
|
36
|
+
|
|
37
|
+
For each pair of qubits from the `controls` and `targets` lists, this will randomly select one
|
|
38
|
+
of the pauli products
|
|
39
|
+
|
|
40
|
+
`{IX, IY, IZ, XI, XX, XY, XZ, YI, YX, YY, YZ, ZI, ZX, ZY, ZZ}`
|
|
41
|
+
|
|
42
|
+
each with a probability `p / 15`. No noise is applied with a probability of `1 - p`.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
p (float): The probability with which a Pauli product is applied.
|
|
46
|
+
controls (IList[Qubit, N]): The list of control qubits.
|
|
47
|
+
targets (IList[Qubit, N]): The list of target qubits.
|
|
48
|
+
"""
|
|
49
|
+
noise.depolarize2(p, controls, targets)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@kernel
|
|
53
|
+
def single_qubit_pauli_channel(
|
|
54
|
+
px: float, py: float, pz: float, qubits: ilist.IList[Qubit, Any]
|
|
55
|
+
) -> None:
|
|
56
|
+
"""
|
|
57
|
+
Apply a Pauli error channel with weighted `px, py, pz`. No error is applied with a probability
|
|
58
|
+
`1 - (px + py + pz)`.
|
|
59
|
+
|
|
60
|
+
This randomly selects one of the three Pauli operators X, Y, Z, weighted with the given probabilities in that order.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
probabilities (IList[float, Literal[3]]): A list of 3 probabilities corresponding to the probabilities `(p_x, p_y, p_z)` in that order.
|
|
64
|
+
qubits (IList[Qubit, Any]): The list of qubits to which the noise channel is applied.
|
|
65
|
+
"""
|
|
66
|
+
noise.single_qubit_pauli_channel(px, py, pz, qubits)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@kernel
|
|
70
|
+
def two_qubit_pauli_channel(
|
|
71
|
+
probabilities: ilist.IList[float, Literal[15]],
|
|
72
|
+
controls: ilist.IList[Qubit, N],
|
|
73
|
+
targets: ilist.IList[Qubit, N],
|
|
74
|
+
) -> None:
|
|
75
|
+
"""
|
|
76
|
+
Apply a Pauli product error with weighted `probabilities` to the set of control and target qubits.
|
|
77
|
+
|
|
78
|
+
No error is applied with the probability `1 - sum(probabilities)`.
|
|
79
|
+
|
|
80
|
+
For each pair of qubits from the `controls` and `targets` lists, this will randomly select one
|
|
81
|
+
of the pauli products
|
|
82
|
+
|
|
83
|
+
`{IX, IY, IZ, XI, XX, XY, XZ, YI, YX, YY, YZ, ZI, ZX, ZY, ZZ}`
|
|
84
|
+
|
|
85
|
+
weighted with the corresponding list of probabilities.
|
|
86
|
+
|
|
87
|
+
**NOTE**: The order of the given probabilities must match the order of the list of Pauli products above!
|
|
88
|
+
"""
|
|
89
|
+
noise.two_qubit_pauli_channel(probabilities, controls, targets)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
@kernel
|
|
93
|
+
def qubit_loss(p: float, qubits: ilist.IList[Qubit, Any]) -> None:
|
|
94
|
+
"""
|
|
95
|
+
Apply a qubit loss channel to each of the qubits in the given list.
|
|
96
|
+
|
|
97
|
+
Each qubit in the list is lost with a probability `p`.
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
p (float): Probability of the atom being lost.
|
|
101
|
+
qubits (IList[Qubit, Any]): The list of qubits to which the noise channel is applied.
|
|
102
|
+
"""
|
|
103
|
+
noise.qubit_loss(p, qubits)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
@kernel
|
|
107
|
+
def correlated_qubit_loss(
|
|
108
|
+
p: float, qubits: ilist.IList[ilist.IList[Qubit, N], Any]
|
|
109
|
+
) -> None:
|
|
110
|
+
"""
|
|
111
|
+
Apply correlated qubit loss channels to groups of qubits.
|
|
112
|
+
|
|
113
|
+
For each group of qubits, applies a correlated loss channel where all qubits
|
|
114
|
+
within the group are lost together with probability `p`. Loss events are independent
|
|
115
|
+
between different groups.
|
|
116
|
+
|
|
117
|
+
Args:
|
|
118
|
+
p (float): Loss probability for each group.
|
|
119
|
+
qubits (IList[IList[Qubit, N], Any]): List of qubit groups. Each sublist
|
|
120
|
+
represents a group of qubits to which a correlated loss channel is applied.
|
|
121
|
+
|
|
122
|
+
Example:
|
|
123
|
+
>>> q1 = squin.qalloc(3) # First group: qubits 0, 1, 2
|
|
124
|
+
>>> q2 = squin.qalloc(3) # Second group: qubits 3, 4, 5
|
|
125
|
+
>>> squin.broadcast.correlated_qubit_loss(0.5, [q1, q2])
|
|
126
|
+
# Each group has 50% chance: either all qubits lost or none lost.
|
|
127
|
+
# Group 1 and Group 2 outcomes are independent.
|
|
128
|
+
"""
|
|
129
|
+
noise.correlated_qubit_loss(p, qubits)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
# NOTE: actual stdlib that doesn't wrap statements starts here
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
@kernel
|
|
136
|
+
def bit_flip(p: float, qubits: ilist.IList[Qubit, Any]) -> None:
|
|
137
|
+
"""
|
|
138
|
+
Apply a bit flip error channel to the qubits in the given list with probability `p`.
|
|
139
|
+
|
|
140
|
+
Args:
|
|
141
|
+
p (float): Probability of a bit flip error being applied.
|
|
142
|
+
qubits (IList[Qubit, Any]): The list of qubits to which the noise channel is applied.
|
|
143
|
+
"""
|
|
144
|
+
single_qubit_pauli_channel(p, 0, 0, qubits)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from .gate import (
|
|
2
|
+
h as h,
|
|
3
|
+
s as s,
|
|
4
|
+
t as t,
|
|
5
|
+
x as x,
|
|
6
|
+
y as y,
|
|
7
|
+
z as z,
|
|
8
|
+
cx as cx,
|
|
9
|
+
cy as cy,
|
|
10
|
+
cz as cz,
|
|
11
|
+
rx as rx,
|
|
12
|
+
ry as ry,
|
|
13
|
+
rz as rz,
|
|
14
|
+
u3 as u3,
|
|
15
|
+
s_adj as s_adj,
|
|
16
|
+
shift as shift,
|
|
17
|
+
t_adj as t_adj,
|
|
18
|
+
sqrt_x as sqrt_x,
|
|
19
|
+
sqrt_y as sqrt_y,
|
|
20
|
+
sqrt_z as sqrt_z,
|
|
21
|
+
sqrt_x_adj as sqrt_x_adj,
|
|
22
|
+
sqrt_y_adj as sqrt_y_adj,
|
|
23
|
+
sqrt_z_adj as sqrt_z_adj,
|
|
24
|
+
)
|
|
25
|
+
from .noise import (
|
|
26
|
+
bit_flip as bit_flip,
|
|
27
|
+
depolarize as depolarize,
|
|
28
|
+
qubit_loss as qubit_loss,
|
|
29
|
+
depolarize2 as depolarize2,
|
|
30
|
+
correlated_qubit_loss as correlated_qubit_loss,
|
|
31
|
+
two_qubit_pauli_channel as two_qubit_pauli_channel,
|
|
32
|
+
single_qubit_pauli_channel as single_qubit_pauli_channel,
|
|
33
|
+
)
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
from kirin.dialects import ilist
|
|
2
|
+
|
|
3
|
+
from bloqade.types import Qubit
|
|
4
|
+
|
|
5
|
+
from .. import broadcast
|
|
6
|
+
from ...groups import kernel
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@kernel
|
|
10
|
+
def x(qubit: Qubit) -> None:
|
|
11
|
+
"""Apply a Pauli-X gate to a qubit.
|
|
12
|
+
|
|
13
|
+
Args:
|
|
14
|
+
qubit (Qubit): Target qubit.
|
|
15
|
+
"""
|
|
16
|
+
broadcast.x(ilist.IList([qubit]))
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@kernel
|
|
20
|
+
def y(qubit: Qubit) -> None:
|
|
21
|
+
"""Apply a Pauli-Y gate to a qubit.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
qubit (Qubit): Target qubit.
|
|
25
|
+
"""
|
|
26
|
+
broadcast.y(ilist.IList([qubit]))
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@kernel
|
|
30
|
+
def z(qubit: Qubit) -> None:
|
|
31
|
+
"""Apply a Pauli-Z gate to a qubit.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
qubit (Qubit): Target qubit.
|
|
35
|
+
"""
|
|
36
|
+
broadcast.z(ilist.IList([qubit]))
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@kernel
|
|
40
|
+
def h(qubit: Qubit) -> None:
|
|
41
|
+
"""Apply a Hadamard gate to a qubit.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
qubit (Qubit): Target qubit.
|
|
45
|
+
"""
|
|
46
|
+
broadcast.h(ilist.IList([qubit]))
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@kernel
|
|
50
|
+
def t(qubit: Qubit) -> None:
|
|
51
|
+
"""Apply a T gate to a qubit.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
qubit (Qubit): Target qubit.
|
|
55
|
+
"""
|
|
56
|
+
broadcast.t(ilist.IList([qubit]))
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@kernel
|
|
60
|
+
def s(qubit: Qubit) -> None:
|
|
61
|
+
"""Apply an S gate to a qubit.
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
qubit (Qubit): Target qubit.
|
|
65
|
+
"""
|
|
66
|
+
broadcast.s(ilist.IList([qubit]))
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@kernel
|
|
70
|
+
def sqrt_x(qubit: Qubit) -> None:
|
|
71
|
+
"""Apply a Sqrt(X) gate to a qubit.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
qubit (Qubit): Target qubit.
|
|
75
|
+
"""
|
|
76
|
+
broadcast.sqrt_x(ilist.IList([qubit]))
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
@kernel
|
|
80
|
+
def sqrt_y(qubit: Qubit) -> None:
|
|
81
|
+
"""Apply a Sqrt(Y) gate to a qubit.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
qubit (Qubit): Target qubit.
|
|
85
|
+
"""
|
|
86
|
+
broadcast.sqrt_y(ilist.IList([qubit]))
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@kernel
|
|
90
|
+
def sqrt_z(qubit: Qubit) -> None:
|
|
91
|
+
"""Apply a Sqrt(Z) gate to a qubit.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
qubit (Qubit): Target qubit.
|
|
95
|
+
"""
|
|
96
|
+
broadcast.s(ilist.IList([qubit]))
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
@kernel
|
|
100
|
+
def t_adj(qubit: Qubit) -> None:
|
|
101
|
+
"""Apply the adjoint of a T gate to a qubit.
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
qubit (Qubit): Target qubit.
|
|
105
|
+
"""
|
|
106
|
+
broadcast.t_adj(ilist.IList([qubit]))
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
@kernel
|
|
110
|
+
def s_adj(qubit: Qubit) -> None:
|
|
111
|
+
"""Apply the adjoint of an S gate to a qubit.
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
qubit (Qubit): Target qubit.
|
|
115
|
+
"""
|
|
116
|
+
broadcast.s_adj(ilist.IList([qubit]))
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
@kernel
|
|
120
|
+
def sqrt_x_adj(qubit: Qubit) -> None:
|
|
121
|
+
"""Apply the adjoint of a Sqrt(X) gate to a qubit.
|
|
122
|
+
|
|
123
|
+
Args:
|
|
124
|
+
qubit (Qubit): Target qubit.
|
|
125
|
+
"""
|
|
126
|
+
broadcast.sqrt_x_adj(ilist.IList([qubit]))
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
@kernel
|
|
130
|
+
def sqrt_y_adj(qubit: Qubit) -> None:
|
|
131
|
+
"""Apply the adjoint of a Sqrt(Y) gate to a qubit.
|
|
132
|
+
|
|
133
|
+
Args:
|
|
134
|
+
qubit (Qubit): Target qubit.
|
|
135
|
+
"""
|
|
136
|
+
broadcast.sqrt_y_adj(ilist.IList([qubit]))
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
@kernel
|
|
140
|
+
def sqrt_z_adj(qubit: Qubit) -> None:
|
|
141
|
+
"""Apply the adjoint of a Sqrt(Z) gate to a qubit.
|
|
142
|
+
|
|
143
|
+
Args:
|
|
144
|
+
qubit (Qubit): Target qubit.
|
|
145
|
+
"""
|
|
146
|
+
broadcast.s_adj(ilist.IList([qubit]))
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
@kernel
|
|
150
|
+
def rx(angle: float, qubit: Qubit) -> None:
|
|
151
|
+
"""Apply an RX rotation gate to a qubit.
|
|
152
|
+
|
|
153
|
+
Args:
|
|
154
|
+
angle (float): Rotation angle in radians.
|
|
155
|
+
qubit (Qubit): Target qubit.
|
|
156
|
+
"""
|
|
157
|
+
broadcast.rx(angle, ilist.IList([qubit]))
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
@kernel
|
|
161
|
+
def ry(angle: float, qubit: Qubit) -> None:
|
|
162
|
+
"""Apply an RY rotation gate to a qubit.
|
|
163
|
+
|
|
164
|
+
Args:
|
|
165
|
+
angle (float): Rotation angle in radians.
|
|
166
|
+
qubit (Qubit): Target qubit.
|
|
167
|
+
"""
|
|
168
|
+
broadcast.ry(angle, ilist.IList([qubit]))
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
@kernel
|
|
172
|
+
def rz(angle: float, qubit: Qubit) -> None:
|
|
173
|
+
"""Apply an RZ rotation gate to a qubit.
|
|
174
|
+
|
|
175
|
+
Args:
|
|
176
|
+
angle (float): Rotation angle in radians.
|
|
177
|
+
qubit (Qubit): Target qubit.
|
|
178
|
+
"""
|
|
179
|
+
broadcast.rz(angle, ilist.IList([qubit]))
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
@kernel
|
|
183
|
+
def cx(control: Qubit, target: Qubit) -> None:
|
|
184
|
+
"""Apply a controlled-X gate to a pair of qubits.
|
|
185
|
+
|
|
186
|
+
Args:
|
|
187
|
+
controls (Qubit): Control qubit.
|
|
188
|
+
targets (Qubit): Target qubit.
|
|
189
|
+
"""
|
|
190
|
+
broadcast.cx(ilist.IList([control]), ilist.IList([target]))
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
@kernel
|
|
194
|
+
def cy(control: Qubit, target: Qubit) -> None:
|
|
195
|
+
"""Apply a controlled-Y gate to a pair of qubits.
|
|
196
|
+
|
|
197
|
+
Args:
|
|
198
|
+
controls (Qubit): Control qubit.
|
|
199
|
+
targets (Qubit): Target qubit.
|
|
200
|
+
"""
|
|
201
|
+
broadcast.cy(ilist.IList([control]), ilist.IList([target]))
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
@kernel
|
|
205
|
+
def cz(control: Qubit, target: Qubit) -> None:
|
|
206
|
+
"""Apply a controlled-Z gate to a pair of qubits.
|
|
207
|
+
|
|
208
|
+
Args:
|
|
209
|
+
controls (Qubit): Control qubit.
|
|
210
|
+
targets (Qubit): Target qubit.
|
|
211
|
+
"""
|
|
212
|
+
broadcast.cz(ilist.IList([control]), ilist.IList([target]))
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
@kernel
|
|
216
|
+
def u3(theta: float, phi: float, lam: float, qubit: Qubit):
|
|
217
|
+
"""Apply the U3 gate of a qubit.
|
|
218
|
+
|
|
219
|
+
The applied gate is represented by the unitary matrix given by:
|
|
220
|
+
|
|
221
|
+
$$ U3(\\theta, \\phi, \\lambda) = R_z(\\phi)R_y(\\theta)R_z(\\lambda) $$
|
|
222
|
+
|
|
223
|
+
Args:
|
|
224
|
+
theta (float): Rotation around Y axis (radians).
|
|
225
|
+
phi (float): Global phase shift component (radians).
|
|
226
|
+
lam (float): Z rotations in decomposition (radians).
|
|
227
|
+
qubit (Qubit): Target qubit.
|
|
228
|
+
"""
|
|
229
|
+
broadcast.u3(theta, phi, lam, ilist.IList([qubit]))
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
# NOTE: stdlib not wrapping statements starts here
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
@kernel
|
|
236
|
+
def shift(angle: float, qubit: Qubit) -> None:
|
|
237
|
+
"""Apply a phase shift to the |1> state of a qubit.
|
|
238
|
+
Args:
|
|
239
|
+
angle (float): Phase shift angle in radians.
|
|
240
|
+
qubit (Qubit): Target qubit.
|
|
241
|
+
"""
|
|
242
|
+
broadcast.shift(angle, ilist.IList([qubit]))
|