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
bloqade/squin/op/types.py
DELETED
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
from typing import Generic, TypeVar, overload
|
|
2
|
-
|
|
3
|
-
from kirin import types
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class Op:
|
|
7
|
-
|
|
8
|
-
def __matmul__(self, other: "Op") -> "Op":
|
|
9
|
-
raise NotImplementedError("@ can only be used within a squin kernel program")
|
|
10
|
-
|
|
11
|
-
@overload
|
|
12
|
-
def __mul__(self, other: "Op") -> "Op": ...
|
|
13
|
-
|
|
14
|
-
@overload
|
|
15
|
-
def __mul__(self, other: complex) -> "Op": ...
|
|
16
|
-
|
|
17
|
-
def __mul__(self, other) -> "Op":
|
|
18
|
-
raise NotImplementedError("@ can only be used within a squin kernel program")
|
|
19
|
-
|
|
20
|
-
def __rmul__(self, other: complex) -> "Op":
|
|
21
|
-
raise NotImplementedError("@ can only be used within a squin kernel program")
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
OpType = types.PyClass(Op)
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
class CompositeOp(Op):
|
|
28
|
-
pass
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
CompositeOpType = types.PyClass(CompositeOp)
|
|
32
|
-
|
|
33
|
-
LhsType = TypeVar("LhsType", bound=Op)
|
|
34
|
-
RhsType = TypeVar("RhsType", bound=Op)
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
class BinaryOp(Op, Generic[LhsType, RhsType]):
|
|
38
|
-
lhs: LhsType
|
|
39
|
-
rhs: RhsType
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
BinaryOpType = types.Generic(BinaryOp, OpType, OpType)
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
class Mult(BinaryOp[LhsType, RhsType]):
|
|
46
|
-
pass
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
MultType = types.Generic(Mult, OpType, OpType)
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
class Kron(BinaryOp[LhsType, RhsType]):
|
|
53
|
-
pass
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
KronType = types.Generic(Kron, OpType, OpType)
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
class MultiQubitPauliOp(Op):
|
|
60
|
-
pass
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
MultiQubitPauliOpType = types.PyClass(MultiQubitPauliOp)
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
class PauliStringOp(MultiQubitPauliOp):
|
|
67
|
-
pass
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
PauliStringType = types.PyClass(PauliStringOp)
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
class PauliOp(MultiQubitPauliOp):
|
|
74
|
-
pass
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
PauliOpType = types.PyClass(PauliOp)
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
class XOp(PauliOp):
|
|
81
|
-
pass
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
XOpType = types.PyClass(XOp)
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
class YOp(PauliOp):
|
|
88
|
-
pass
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
YOpType = types.PyClass(YOp)
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
class ZOp(PauliOp):
|
|
95
|
-
pass
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
ZOpType = types.PyClass(ZOp)
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
ControlledOp = TypeVar("ControlledOp", bound=Op)
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
class ControlOp(CompositeOp, Generic[ControlledOp]):
|
|
105
|
-
op: ControlledOp
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
ControlledOpType = types.TypeVar("ControlledOp", bound=OpType)
|
|
109
|
-
ControlOpType = types.Generic(ControlOp, ControlledOpType)
|
|
110
|
-
CXOpType = ControlOpType[XOpType]
|
|
111
|
-
CYOpType = ControlOpType[YOpType]
|
|
112
|
-
CZOpType = ControlOpType[ZOpType]
|
|
113
|
-
|
|
114
|
-
RotationAxis = TypeVar("RotationAxis", bound=Op)
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
class ROp(CompositeOp, Generic[RotationAxis]):
|
|
118
|
-
axis: RotationAxis
|
|
119
|
-
angle: float
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
ROpType = types.Generic(ROp, OpType)
|
|
123
|
-
RxOpType = ROpType[XOpType]
|
|
124
|
-
RyOpType = ROpType[YOpType]
|
|
125
|
-
RzOpType = ROpType[ZOpType]
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
NumOperators = types.TypeVar("NumOperators", bound=types.Int)
|
bloqade/squin/parallel.py
DELETED
|
@@ -1,200 +0,0 @@
|
|
|
1
|
-
from typing import Any, TypeVar
|
|
2
|
-
|
|
3
|
-
from kirin.dialects import ilist
|
|
4
|
-
|
|
5
|
-
from bloqade.types import Qubit
|
|
6
|
-
|
|
7
|
-
from . import op as _op, qubit as _qubit
|
|
8
|
-
from .groups import kernel
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
@kernel
|
|
12
|
-
def x(qubits: ilist.IList[Qubit, Any]) -> None:
|
|
13
|
-
"""x gate applied to qubits in parallel."""
|
|
14
|
-
op = _op.x()
|
|
15
|
-
_qubit.broadcast(op, qubits)
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
@kernel
|
|
19
|
-
def y(qubits: ilist.IList[Qubit, Any]) -> None:
|
|
20
|
-
"""y gate applied to qubits in parallel."""
|
|
21
|
-
op = _op.y()
|
|
22
|
-
_qubit.broadcast(op, qubits)
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
@kernel
|
|
26
|
-
def z(qubits: ilist.IList[Qubit, Any]) -> None:
|
|
27
|
-
"""z gate applied to qubits in parallel."""
|
|
28
|
-
op = _op.z()
|
|
29
|
-
_qubit.broadcast(op, qubits)
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
@kernel
|
|
33
|
-
def sqrt_x(qubits: ilist.IList[Qubit, Any]) -> None:
|
|
34
|
-
"""Square root x gate applied to qubits in parallel."""
|
|
35
|
-
op = _op.sqrt_x()
|
|
36
|
-
_qubit.broadcast(op, qubits)
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
@kernel
|
|
40
|
-
def sqrt_y(qubits: ilist.IList[Qubit, Any]) -> None:
|
|
41
|
-
"""Square root y gate applied to qubits in parallel."""
|
|
42
|
-
op = _op.sqrt_y()
|
|
43
|
-
_qubit.broadcast(op, qubits)
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
@kernel
|
|
47
|
-
def sqrt_z(qubits: ilist.IList[Qubit, Any]) -> None:
|
|
48
|
-
"""Square root gate applied to qubits in parallel."""
|
|
49
|
-
op = _op.s()
|
|
50
|
-
_qubit.broadcast(op, qubits)
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
@kernel
|
|
54
|
-
def h(qubits: ilist.IList[Qubit, Any]) -> None:
|
|
55
|
-
"""Hadamard gate applied to qubits in parallel."""
|
|
56
|
-
op = _op.h()
|
|
57
|
-
_qubit.broadcast(op, qubits)
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
@kernel
|
|
61
|
-
def s(qubits: ilist.IList[Qubit, Any]) -> None:
|
|
62
|
-
"""s gate applied to qubits in parallel."""
|
|
63
|
-
op = _op.s()
|
|
64
|
-
_qubit.broadcast(op, qubits)
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
@kernel
|
|
68
|
-
def t(qubits: ilist.IList[Qubit, Any]) -> None:
|
|
69
|
-
"""t gate applied to qubits in parallel."""
|
|
70
|
-
op = _op.t()
|
|
71
|
-
_qubit.broadcast(op, qubits)
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
@kernel
|
|
75
|
-
def p0(qubits: ilist.IList[Qubit, Any]) -> None:
|
|
76
|
-
"""Projector on 0 applied to qubits in parallel."""
|
|
77
|
-
op = _op.p0()
|
|
78
|
-
_qubit.broadcast(op, qubits)
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
@kernel
|
|
82
|
-
def p1(qubits: ilist.IList[Qubit, Any]) -> None:
|
|
83
|
-
"""Projector on 1 applied to qubits in parallel."""
|
|
84
|
-
op = _op.p1()
|
|
85
|
-
_qubit.broadcast(op, qubits)
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
@kernel
|
|
89
|
-
def spin_n(qubits: ilist.IList[Qubit, Any]) -> None:
|
|
90
|
-
"""Spin lowering gate applied to qubits in parallel."""
|
|
91
|
-
op = _op.spin_n()
|
|
92
|
-
_qubit.broadcast(op, qubits)
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
@kernel
|
|
96
|
-
def spin_p(qubits: ilist.IList[Qubit, Any]) -> None:
|
|
97
|
-
"""Spin raising gate applied to qubits in parallel."""
|
|
98
|
-
op = _op.spin_p()
|
|
99
|
-
_qubit.broadcast(op, qubits)
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
@kernel
|
|
103
|
-
def reset(qubits: ilist.IList[Qubit, Any]) -> None:
|
|
104
|
-
"""Reset qubit to 0."""
|
|
105
|
-
op = _op.reset()
|
|
106
|
-
_qubit.broadcast(op, qubits)
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
N = TypeVar("N")
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
@kernel
|
|
113
|
-
def cx(controls: ilist.IList[Qubit, N], targets: ilist.IList[Qubit, N]) -> None:
|
|
114
|
-
"""Controlled x gate applied to controls and targets in parallel."""
|
|
115
|
-
op = _op.cx()
|
|
116
|
-
_qubit.broadcast(op, controls, targets)
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
@kernel
|
|
120
|
-
def cy(controls: ilist.IList[Qubit, N], targets: ilist.IList[Qubit, N]) -> None:
|
|
121
|
-
"""Controlled y gate applied to controls and targets in parallel."""
|
|
122
|
-
op = _op.cy()
|
|
123
|
-
_qubit.broadcast(op, controls, targets)
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
@kernel
|
|
127
|
-
def cz(controls: ilist.IList[Qubit, N], targets: ilist.IList[Qubit, N]) -> None:
|
|
128
|
-
"""Controlled z gate applied to controls and targets in parallel."""
|
|
129
|
-
op = _op.cz()
|
|
130
|
-
_qubit.broadcast(op, controls, targets)
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
@kernel
|
|
134
|
-
def ch(controls: ilist.IList[Qubit, N], targets: ilist.IList[Qubit, N]) -> None:
|
|
135
|
-
"""Controlled Hadamard gate applied to controls and targets in parallel."""
|
|
136
|
-
op = _op.ch()
|
|
137
|
-
_qubit.broadcast(op, controls, targets)
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
@kernel
|
|
141
|
-
def u(theta: float, phi: float, lam: float, qubits: ilist.IList[Qubit, Any]) -> None:
|
|
142
|
-
"""3D rotation gate applied to controls and targets in parallel."""
|
|
143
|
-
op = _op.u(theta, phi, lam)
|
|
144
|
-
_qubit.broadcast(op, qubits)
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
@kernel
|
|
148
|
-
def rx(theta: float, qubits: ilist.IList[Qubit, Any]) -> None:
|
|
149
|
-
"""Rotation X gate applied to qubits in parallel."""
|
|
150
|
-
op = _op.rot(_op.x(), theta)
|
|
151
|
-
_qubit.broadcast(op, qubits)
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
@kernel
|
|
155
|
-
def ry(theta: float, qubits: ilist.IList[Qubit, Any]) -> None:
|
|
156
|
-
"""Rotation Y gate applied to qubits in parallel."""
|
|
157
|
-
op = _op.rot(_op.y(), theta)
|
|
158
|
-
_qubit.broadcast(op, qubits)
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
@kernel
|
|
162
|
-
def rz(theta: float, qubits: ilist.IList[Qubit, Any]) -> None:
|
|
163
|
-
"""Rotation Z gate applied to qubits in parallel."""
|
|
164
|
-
op = _op.rot(_op.z(), theta)
|
|
165
|
-
_qubit.broadcast(op, qubits)
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
@kernel
|
|
169
|
-
def sqrt_x_adj(qubits: ilist.IList[Qubit, Any]) -> None:
|
|
170
|
-
"""Adjoint sqrt_x gate applied to qubits in parallel."""
|
|
171
|
-
op = _op.sqrt_x()
|
|
172
|
-
_qubit.broadcast(_op.adjoint(op), qubits)
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
@kernel
|
|
176
|
-
def sqrt_y_adj(qubits: ilist.IList[Qubit, Any]) -> None:
|
|
177
|
-
"""Adjoint sqrt_y gate applied to qubits in parallel."""
|
|
178
|
-
op = _op.sqrt_y()
|
|
179
|
-
_qubit.broadcast(_op.adjoint(op), qubits)
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
@kernel
|
|
183
|
-
def sqrt_z_adj(qubits: ilist.IList[Qubit, Any]) -> None:
|
|
184
|
-
"""Adjoint square root z gate applied to qubits in parallel."""
|
|
185
|
-
op = _op.s()
|
|
186
|
-
_qubit.broadcast(_op.adjoint(op), qubits)
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
@kernel
|
|
190
|
-
def s_adj(qubits: ilist.IList[Qubit, Any]) -> None:
|
|
191
|
-
"""Adjoint s gate applied to qubits in parallel."""
|
|
192
|
-
op = _op.s()
|
|
193
|
-
_qubit.broadcast(_op.adjoint(op), qubits)
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
@kernel
|
|
197
|
-
def t_adj(qubits: ilist.IList[Qubit, Any]) -> None:
|
|
198
|
-
"""Adjoint t gate applied to qubits in parallel."""
|
|
199
|
-
op = _op.t()
|
|
200
|
-
_qubit.broadcast(_op.adjoint(op), qubits)
|
bloqade/squin/qubit.py
DELETED
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
"""qubit dialect for squin language.
|
|
2
|
-
|
|
3
|
-
This dialect defines the operations that can be performed on qubits.
|
|
4
|
-
|
|
5
|
-
Depends on:
|
|
6
|
-
- `bloqade.squin.op`: provides the `OpType` type and semantics for operators applied to qubits.
|
|
7
|
-
- `kirin.dialects.ilist`: provides the `ilist.IListType` type for lists of qubits.
|
|
8
|
-
"""
|
|
9
|
-
|
|
10
|
-
from typing import Any, TypeVar, overload
|
|
11
|
-
|
|
12
|
-
from kirin import ir, types, lowering
|
|
13
|
-
from kirin.decl import info, statement
|
|
14
|
-
from kirin.dialects import ilist
|
|
15
|
-
from kirin.lowering import wraps
|
|
16
|
-
|
|
17
|
-
from bloqade.types import Qubit, QubitType
|
|
18
|
-
from bloqade.squin.op.types import Op, OpType
|
|
19
|
-
|
|
20
|
-
from .types import MeasurementResult, MeasurementResultType
|
|
21
|
-
from .lowering import ApplyAnyCallLowering, BroadcastCallLowering
|
|
22
|
-
|
|
23
|
-
dialect = ir.Dialect("squin.qubit")
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
@statement(dialect=dialect)
|
|
27
|
-
class New(ir.Statement):
|
|
28
|
-
traits = frozenset({lowering.FromPythonCall()})
|
|
29
|
-
n_qubits: ir.SSAValue = info.argument(types.Int)
|
|
30
|
-
result: ir.ResultValue = info.result(ilist.IListType[QubitType, types.Any])
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
@statement(dialect=dialect)
|
|
34
|
-
class Apply(ir.Statement):
|
|
35
|
-
traits = frozenset({lowering.FromPythonCall()})
|
|
36
|
-
operator: ir.SSAValue = info.argument(OpType)
|
|
37
|
-
qubits: tuple[ir.SSAValue, ...] = info.argument(QubitType)
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
@statement(dialect=dialect)
|
|
41
|
-
class ApplyAny(ir.Statement):
|
|
42
|
-
# NOTE: custom lowering to deal with vararg calls
|
|
43
|
-
traits = frozenset({ApplyAnyCallLowering()})
|
|
44
|
-
operator: ir.SSAValue = info.argument(OpType)
|
|
45
|
-
qubits: tuple[ir.SSAValue, ...] = info.argument()
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
@statement(dialect=dialect)
|
|
49
|
-
class Broadcast(ir.Statement):
|
|
50
|
-
traits = frozenset({BroadcastCallLowering()})
|
|
51
|
-
operator: ir.SSAValue = info.argument(OpType)
|
|
52
|
-
qubits: tuple[ir.SSAValue, ...] = info.argument(ilist.IListType[QubitType])
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
@statement(dialect=dialect)
|
|
56
|
-
class MeasureAny(ir.Statement):
|
|
57
|
-
name = "measure"
|
|
58
|
-
|
|
59
|
-
traits = frozenset({lowering.FromPythonCall()})
|
|
60
|
-
input: ir.SSAValue = info.argument(types.Any)
|
|
61
|
-
result: ir.ResultValue = info.result(types.Any)
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
@statement(dialect=dialect)
|
|
65
|
-
class MeasureQubit(ir.Statement):
|
|
66
|
-
name = "measure.qubit"
|
|
67
|
-
|
|
68
|
-
traits = frozenset({lowering.FromPythonCall()})
|
|
69
|
-
qubit: ir.SSAValue = info.argument(QubitType)
|
|
70
|
-
result: ir.ResultValue = info.result(MeasurementResultType)
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
@statement(dialect=dialect)
|
|
74
|
-
class MeasureQubitList(ir.Statement):
|
|
75
|
-
name = "measure.qubit.list"
|
|
76
|
-
|
|
77
|
-
traits = frozenset({lowering.FromPythonCall()})
|
|
78
|
-
qubits: ir.SSAValue = info.argument(ilist.IListType[QubitType])
|
|
79
|
-
result: ir.ResultValue = info.result(ilist.IListType[MeasurementResultType])
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
@statement(dialect=dialect)
|
|
83
|
-
class QubitId(ir.Statement):
|
|
84
|
-
traits = frozenset({lowering.FromPythonCall(), ir.Pure()})
|
|
85
|
-
qubit: ir.SSAValue = info.argument(QubitType)
|
|
86
|
-
result: ir.ResultValue = info.result(types.Int)
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
@statement(dialect=dialect)
|
|
90
|
-
class MeasurementId(ir.Statement):
|
|
91
|
-
traits = frozenset({lowering.FromPythonCall(), ir.Pure()})
|
|
92
|
-
measurement: ir.SSAValue = info.argument(MeasurementResultType)
|
|
93
|
-
result: ir.ResultValue = info.result(types.Int)
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
# NOTE: no dependent types in Python, so we have to mark it Any...
|
|
97
|
-
@wraps(New)
|
|
98
|
-
def new(n_qubits: int) -> ilist.IList[Qubit, Any]:
|
|
99
|
-
"""Create a new list of qubits.
|
|
100
|
-
|
|
101
|
-
Args:
|
|
102
|
-
n_qubits(int): The number of qubits to create.
|
|
103
|
-
|
|
104
|
-
Returns:
|
|
105
|
-
(ilist.IList[Qubit, n_qubits]) A list of qubits.
|
|
106
|
-
"""
|
|
107
|
-
...
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
@wraps(ApplyAny)
|
|
111
|
-
def apply(operator: Op, *qubits: Qubit) -> None:
|
|
112
|
-
"""Apply an operator to qubits. The number of qubit arguments must match the
|
|
113
|
-
size of the operator.
|
|
114
|
-
|
|
115
|
-
Note, that when considering atom loss, lost qubits will be skipped.
|
|
116
|
-
|
|
117
|
-
Args:
|
|
118
|
-
operator: The operator to apply.
|
|
119
|
-
*qubits: The qubits to apply the operator to. The number of qubits must
|
|
120
|
-
match the size of the operator.
|
|
121
|
-
|
|
122
|
-
Returns:
|
|
123
|
-
None
|
|
124
|
-
"""
|
|
125
|
-
...
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
@overload
|
|
129
|
-
def measure(input: Qubit) -> MeasurementResult: ...
|
|
130
|
-
@overload
|
|
131
|
-
def measure(
|
|
132
|
-
input: ilist.IList[Qubit, Any] | list[Qubit],
|
|
133
|
-
) -> ilist.IList[MeasurementResult, Any]: ...
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
@wraps(MeasureAny)
|
|
137
|
-
def measure(input: Any) -> Any:
|
|
138
|
-
"""Measure a qubit or qubits in the list.
|
|
139
|
-
|
|
140
|
-
Args:
|
|
141
|
-
input: A qubit or a list of qubits to measure.
|
|
142
|
-
|
|
143
|
-
Returns:
|
|
144
|
-
MeasurementResult | list[MeasurementResult]: The result of the measurement. If a single qubit is measured,
|
|
145
|
-
a single result is returned. If a list of qubits is measured, a list of results
|
|
146
|
-
is returned.
|
|
147
|
-
A MeasurementResult can represent both 0 and 1, but also atoms that are lost.
|
|
148
|
-
"""
|
|
149
|
-
...
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
OpSize = TypeVar("OpSize")
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
@wraps(Broadcast)
|
|
156
|
-
def broadcast(operator: Op, *qubits: ilist.IList[Qubit, OpSize] | list[Qubit]) -> None:
|
|
157
|
-
"""Broadcast and apply an operator to lists of qubits. The number of qubit lists must
|
|
158
|
-
match the size of the operator and the lists must be of same length. The operator is
|
|
159
|
-
then applied to the list elements similar to what python's map function does.
|
|
160
|
-
|
|
161
|
-
## Usage examples
|
|
162
|
-
|
|
163
|
-
```python
|
|
164
|
-
from bloqade import squin
|
|
165
|
-
|
|
166
|
-
@squin.kernel
|
|
167
|
-
def ghz():
|
|
168
|
-
controls = squin.qubit.new(4)
|
|
169
|
-
targets = squin.qubit.new(4)
|
|
170
|
-
|
|
171
|
-
h = squin.op.h()
|
|
172
|
-
squin.qubit.broadcast(h, controls)
|
|
173
|
-
|
|
174
|
-
cx = squin.op.cx()
|
|
175
|
-
squin.qubit.broadcast(cx, controls, targets)
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
Args:
|
|
179
|
-
operator: The operator to broadcast and apply.
|
|
180
|
-
qubits: The list of qubits to broadcast and apply the operator to. The size of the list
|
|
181
|
-
must be inferable and match the number of qubits expected by the operator.
|
|
182
|
-
|
|
183
|
-
Returns:
|
|
184
|
-
None
|
|
185
|
-
"""
|
|
186
|
-
...
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
@wraps(QubitId)
|
|
190
|
-
def get_qubit_id(qubit: Qubit) -> int: ...
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
@wraps(MeasurementId)
|
|
194
|
-
def get_measurement_id(measurement: MeasurementResult) -> int: ...
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
from typing import cast
|
|
2
|
-
|
|
3
|
-
from kirin import ir
|
|
4
|
-
from kirin.rewrite import abc
|
|
5
|
-
from kirin.dialects import cf
|
|
6
|
-
|
|
7
|
-
from .. import wire
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class CanonicalizeWired(abc.RewriteRule):
|
|
11
|
-
def rewrite_Statement(self, node: ir.Statement) -> abc.RewriteResult:
|
|
12
|
-
|
|
13
|
-
if (
|
|
14
|
-
not isinstance(node, wire.Wired)
|
|
15
|
-
or len(node.qubits) != 0
|
|
16
|
-
or (parent_region := node.parent_region) is None
|
|
17
|
-
):
|
|
18
|
-
return abc.RewriteResult()
|
|
19
|
-
|
|
20
|
-
parent_block = cast(ir.Block, node.parent_block)
|
|
21
|
-
|
|
22
|
-
# the body doesn't contain any quantum operations so we can safely inline the
|
|
23
|
-
# body into the parent block
|
|
24
|
-
|
|
25
|
-
# move all statements after `node` in the current block into another block
|
|
26
|
-
after_block = ir.Block()
|
|
27
|
-
|
|
28
|
-
stmt = node.next_stmt
|
|
29
|
-
while stmt is not None:
|
|
30
|
-
stmt.detach()
|
|
31
|
-
after_block.stmts.append(stmt)
|
|
32
|
-
stmt = node.next_stmt
|
|
33
|
-
|
|
34
|
-
# remap all results of the node to the arguments of the after_block
|
|
35
|
-
for result in node.results:
|
|
36
|
-
arg = after_block.args.append_from(result.type, result.name)
|
|
37
|
-
result.replace_by(arg)
|
|
38
|
-
|
|
39
|
-
parent_block_idx = parent_region._block_idx[parent_block]
|
|
40
|
-
# insert goto of parent block to the body block of the node.
|
|
41
|
-
parent_region.blocks.insert(parent_block_idx + 1, after_block)
|
|
42
|
-
# insert all blocks of the body of the node after the parent region
|
|
43
|
-
# making sure to convert any yield statements to jump statements to the after_block
|
|
44
|
-
parent_block.stmts.append(
|
|
45
|
-
cf.Branch(
|
|
46
|
-
arguments=(),
|
|
47
|
-
successor=node.body.blocks[0],
|
|
48
|
-
)
|
|
49
|
-
)
|
|
50
|
-
for block in reversed(node.body.blocks):
|
|
51
|
-
block.detach()
|
|
52
|
-
if isinstance((yield_stmt := block.last_stmt), wire.Yield):
|
|
53
|
-
yield_stmt.replace_by(
|
|
54
|
-
cf.Branch(yield_stmt.values, successor=after_block)
|
|
55
|
-
)
|
|
56
|
-
|
|
57
|
-
parent_region.blocks.insert(parent_block_idx + 1, block)
|
|
58
|
-
|
|
59
|
-
node.delete()
|
|
60
|
-
return abc.RewriteResult(has_done_something=True)
|
bloqade/squin/rewrite/desugar.py
DELETED
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
from warnings import warn
|
|
2
|
-
|
|
3
|
-
from kirin import ir, types
|
|
4
|
-
from kirin.dialects import py, ilist
|
|
5
|
-
from kirin.rewrite.abc import RewriteRule, RewriteResult
|
|
6
|
-
|
|
7
|
-
from bloqade.squin.qubit import (
|
|
8
|
-
Apply,
|
|
9
|
-
ApplyAny,
|
|
10
|
-
QubitType,
|
|
11
|
-
MeasureAny,
|
|
12
|
-
MeasureQubit,
|
|
13
|
-
MeasureQubitList,
|
|
14
|
-
)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class MeasureDesugarRule(RewriteRule):
|
|
18
|
-
"""
|
|
19
|
-
Desugar measure operations in the circuit.
|
|
20
|
-
"""
|
|
21
|
-
|
|
22
|
-
def rewrite_Statement(self, node: ir.Statement) -> RewriteResult:
|
|
23
|
-
|
|
24
|
-
if not isinstance(node, MeasureAny):
|
|
25
|
-
return RewriteResult()
|
|
26
|
-
|
|
27
|
-
if node.input.type.is_subseteq(QubitType):
|
|
28
|
-
node.replace_by(
|
|
29
|
-
MeasureQubit(
|
|
30
|
-
qubit=node.input,
|
|
31
|
-
)
|
|
32
|
-
)
|
|
33
|
-
return RewriteResult(has_done_something=True)
|
|
34
|
-
elif node.input.type.is_subseteq(ilist.IListType[QubitType, types.Any]):
|
|
35
|
-
node.replace_by(
|
|
36
|
-
MeasureQubitList(
|
|
37
|
-
qubits=node.input,
|
|
38
|
-
)
|
|
39
|
-
)
|
|
40
|
-
return RewriteResult(has_done_something=True)
|
|
41
|
-
|
|
42
|
-
return RewriteResult()
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
class ApplyDesugarRule(RewriteRule):
|
|
46
|
-
"""
|
|
47
|
-
Desugar apply operators in the kernel.
|
|
48
|
-
|
|
49
|
-
NOTE: this pass can be removed once we decide to disallow the syntax apply(op: Op, qubits: list)
|
|
50
|
-
"""
|
|
51
|
-
|
|
52
|
-
def rewrite_Statement(self, node: ir.Statement) -> RewriteResult:
|
|
53
|
-
|
|
54
|
-
if not isinstance(node, ApplyAny):
|
|
55
|
-
return RewriteResult()
|
|
56
|
-
|
|
57
|
-
op = node.operator
|
|
58
|
-
qubits = node.qubits
|
|
59
|
-
|
|
60
|
-
if len(qubits) == 0:
|
|
61
|
-
# NOTE: this is invalid syntax, but we don't error in rewrites
|
|
62
|
-
return RewriteResult()
|
|
63
|
-
|
|
64
|
-
if all(q.type.is_subseteq(QubitType) for q in qubits):
|
|
65
|
-
# NOTE: this is the syntax we want; the entire rewrite becomes unnecessary
|
|
66
|
-
# once we disallow the old syntax (just wrap Apply directly)
|
|
67
|
-
apply_stmt = Apply(op, qubits)
|
|
68
|
-
node.replace_by(apply_stmt)
|
|
69
|
-
return RewriteResult(has_done_something=True)
|
|
70
|
-
|
|
71
|
-
if len(qubits) > 1:
|
|
72
|
-
# NOTE: multiple arguments, that aren't qubits, let's bail
|
|
73
|
-
return RewriteResult()
|
|
74
|
-
|
|
75
|
-
qubit_type = qubits[0].type
|
|
76
|
-
is_qubit_list = qubit_type.is_subseteq(ilist.IListType[QubitType, types.Any])
|
|
77
|
-
|
|
78
|
-
if not is_qubit_list:
|
|
79
|
-
return RewriteResult()
|
|
80
|
-
|
|
81
|
-
# NOTE: deprecated syntax: we have a single list of qubits here
|
|
82
|
-
warn(
|
|
83
|
-
"The syntax `apply(operator: Op, qubits: list[Qubit])` is deprecated and may already lead to errors. Use `apply(operator: Op, *qubits: Qubit)` instead."
|
|
84
|
-
)
|
|
85
|
-
if not isinstance(qubit_type.vars[1], types.Literal):
|
|
86
|
-
# NOTE: unknown size, nothing we can do here, it will probably error down the road somewhere
|
|
87
|
-
return RewriteResult()
|
|
88
|
-
|
|
89
|
-
n = qubit_type.vars[1].data
|
|
90
|
-
if not isinstance(n, int):
|
|
91
|
-
# wat?
|
|
92
|
-
return RewriteResult()
|
|
93
|
-
|
|
94
|
-
qubits_rewrite = []
|
|
95
|
-
for i in range(n):
|
|
96
|
-
(idx := py.Constant(i)).insert_before(node)
|
|
97
|
-
(get_item := py.GetItem(qubits[0], idx.result)).insert_before(node)
|
|
98
|
-
qubits_rewrite.append(get_item.result)
|
|
99
|
-
|
|
100
|
-
apply_stmt = Apply(op, tuple(qubits_rewrite))
|
|
101
|
-
node.replace_by(apply_stmt)
|
|
102
|
-
return RewriteResult(has_done_something=True)
|