bloqade-circuit 0.1.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/__init__.py +0 -0
- bloqade/analysis/address/__init__.py +11 -0
- bloqade/analysis/address/analysis.py +60 -0
- bloqade/analysis/address/impls.py +228 -0
- bloqade/analysis/address/lattice.py +85 -0
- bloqade/noise/__init__.py +1 -0
- bloqade/noise/native/__init__.py +20 -0
- bloqade/noise/native/_dialect.py +3 -0
- bloqade/noise/native/_wrappers.py +34 -0
- bloqade/noise/native/model.py +347 -0
- bloqade/noise/native/rewrite.py +35 -0
- bloqade/noise/native/stmts.py +46 -0
- bloqade/pyqrack/__init__.py +18 -0
- bloqade/pyqrack/base.py +131 -0
- bloqade/pyqrack/noise/__init__.py +0 -0
- bloqade/pyqrack/noise/native.py +100 -0
- bloqade/pyqrack/qasm2/__init__.py +0 -0
- bloqade/pyqrack/qasm2/core.py +79 -0
- bloqade/pyqrack/qasm2/parallel.py +46 -0
- bloqade/pyqrack/qasm2/uop.py +247 -0
- bloqade/pyqrack/reg.py +109 -0
- bloqade/pyqrack/target.py +112 -0
- bloqade/qasm2/__init__.py +19 -0
- bloqade/qasm2/_wrappers.py +674 -0
- bloqade/qasm2/dialects/__init__.py +10 -0
- bloqade/qasm2/dialects/core/__init__.py +3 -0
- bloqade/qasm2/dialects/core/_dialect.py +3 -0
- bloqade/qasm2/dialects/core/_emit.py +68 -0
- bloqade/qasm2/dialects/core/_typeinfer.py +23 -0
- bloqade/qasm2/dialects/core/address.py +38 -0
- bloqade/qasm2/dialects/core/stmts.py +94 -0
- bloqade/qasm2/dialects/expr/__init__.py +3 -0
- bloqade/qasm2/dialects/expr/_dialect.py +3 -0
- bloqade/qasm2/dialects/expr/_emit.py +103 -0
- bloqade/qasm2/dialects/expr/_from_python.py +86 -0
- bloqade/qasm2/dialects/expr/_interp.py +75 -0
- bloqade/qasm2/dialects/expr/stmts.py +262 -0
- bloqade/qasm2/dialects/glob.py +45 -0
- bloqade/qasm2/dialects/indexing.py +64 -0
- bloqade/qasm2/dialects/inline.py +76 -0
- bloqade/qasm2/dialects/noise.py +16 -0
- bloqade/qasm2/dialects/parallel.py +110 -0
- bloqade/qasm2/dialects/uop/__init__.py +4 -0
- bloqade/qasm2/dialects/uop/_dialect.py +3 -0
- bloqade/qasm2/dialects/uop/_emit.py +211 -0
- bloqade/qasm2/dialects/uop/schedule.py +89 -0
- bloqade/qasm2/dialects/uop/stmts.py +325 -0
- bloqade/qasm2/emit/__init__.py +1 -0
- bloqade/qasm2/emit/base.py +72 -0
- bloqade/qasm2/emit/gate.py +102 -0
- bloqade/qasm2/emit/main.py +106 -0
- bloqade/qasm2/emit/target.py +165 -0
- bloqade/qasm2/glob.py +24 -0
- bloqade/qasm2/groups.py +120 -0
- bloqade/qasm2/parallel.py +48 -0
- bloqade/qasm2/parse/__init__.py +37 -0
- bloqade/qasm2/parse/ast.py +235 -0
- bloqade/qasm2/parse/build.py +289 -0
- bloqade/qasm2/parse/lowering.py +553 -0
- bloqade/qasm2/parse/parser.py +5 -0
- bloqade/qasm2/parse/print.py +293 -0
- bloqade/qasm2/parse/qasm2.lark +75 -0
- bloqade/qasm2/parse/visitor.py +16 -0
- bloqade/qasm2/parse/visitor.pyi +39 -0
- bloqade/qasm2/passes/__init__.py +5 -0
- bloqade/qasm2/passes/fold.py +94 -0
- bloqade/qasm2/passes/glob.py +119 -0
- bloqade/qasm2/passes/noise.py +61 -0
- bloqade/qasm2/passes/parallel.py +176 -0
- bloqade/qasm2/passes/py2qasm.py +63 -0
- bloqade/qasm2/passes/qasm2py.py +61 -0
- bloqade/qasm2/rewrite/__init__.py +12 -0
- bloqade/qasm2/rewrite/desugar.py +28 -0
- bloqade/qasm2/rewrite/glob.py +103 -0
- bloqade/qasm2/rewrite/heuristic_noise.py +247 -0
- bloqade/qasm2/rewrite/native_gates.py +447 -0
- bloqade/qasm2/rewrite/parallel_to_uop.py +83 -0
- bloqade/qasm2/rewrite/register.py +45 -0
- bloqade/qasm2/rewrite/uop_to_parallel.py +395 -0
- bloqade/qasm2/types.py +39 -0
- bloqade/qbraid/__init__.py +2 -0
- bloqade/qbraid/lowering.py +324 -0
- bloqade/qbraid/schema.py +252 -0
- bloqade/qbraid/simulation_result.py +99 -0
- bloqade/qbraid/target.py +86 -0
- bloqade/squin/__init__.py +2 -0
- bloqade/squin/analysis/__init__.py +0 -0
- bloqade/squin/analysis/nsites/__init__.py +8 -0
- bloqade/squin/analysis/nsites/analysis.py +52 -0
- bloqade/squin/analysis/nsites/impls.py +69 -0
- bloqade/squin/analysis/nsites/lattice.py +49 -0
- bloqade/squin/analysis/schedule.py +244 -0
- bloqade/squin/groups.py +38 -0
- bloqade/squin/op/__init__.py +132 -0
- bloqade/squin/op/_dialect.py +3 -0
- bloqade/squin/op/complex.py +6 -0
- bloqade/squin/op/stmts.py +220 -0
- bloqade/squin/op/traits.py +43 -0
- bloqade/squin/op/types.py +10 -0
- bloqade/squin/qubit.py +118 -0
- bloqade/squin/wire.py +103 -0
- bloqade/stim/__init__.py +6 -0
- bloqade/stim/_wrappers.py +186 -0
- bloqade/stim/dialects/__init__.py +5 -0
- bloqade/stim/dialects/aux/__init__.py +11 -0
- bloqade/stim/dialects/aux/_dialect.py +3 -0
- bloqade/stim/dialects/aux/emit.py +102 -0
- bloqade/stim/dialects/aux/interp.py +39 -0
- bloqade/stim/dialects/aux/lowering.py +40 -0
- bloqade/stim/dialects/aux/stmts/__init__.py +14 -0
- bloqade/stim/dialects/aux/stmts/annotate.py +47 -0
- bloqade/stim/dialects/aux/stmts/const.py +95 -0
- bloqade/stim/dialects/aux/types.py +19 -0
- bloqade/stim/dialects/collapse/__init__.py +3 -0
- bloqade/stim/dialects/collapse/_dialect.py +3 -0
- bloqade/stim/dialects/collapse/emit.py +68 -0
- bloqade/stim/dialects/collapse/stmts/__init__.py +3 -0
- bloqade/stim/dialects/collapse/stmts/measure.py +45 -0
- bloqade/stim/dialects/collapse/stmts/pp_measure.py +14 -0
- bloqade/stim/dialects/collapse/stmts/reset.py +26 -0
- bloqade/stim/dialects/gate/__init__.py +3 -0
- bloqade/stim/dialects/gate/_dialect.py +3 -0
- bloqade/stim/dialects/gate/emit.py +87 -0
- bloqade/stim/dialects/gate/stmts/__init__.py +14 -0
- bloqade/stim/dialects/gate/stmts/base.py +31 -0
- bloqade/stim/dialects/gate/stmts/clifford_1q.py +53 -0
- bloqade/stim/dialects/gate/stmts/clifford_2q.py +11 -0
- bloqade/stim/dialects/gate/stmts/control_2q.py +21 -0
- bloqade/stim/dialects/gate/stmts/pp.py +15 -0
- bloqade/stim/dialects/noise/__init__.py +3 -0
- bloqade/stim/dialects/noise/_dialect.py +3 -0
- bloqade/stim/dialects/noise/emit.py +66 -0
- bloqade/stim/dialects/noise/stmts.py +77 -0
- bloqade/stim/emit/__init__.py +1 -0
- bloqade/stim/emit/stim.py +54 -0
- bloqade/stim/groups.py +26 -0
- bloqade/test_utils.py +35 -0
- bloqade/types.py +24 -0
- bloqade/visual/__init__.py +1 -0
- bloqade/visual/animation/__init__.py +0 -0
- bloqade/visual/animation/animate.py +267 -0
- bloqade/visual/animation/base.py +346 -0
- bloqade/visual/animation/gate_event.py +24 -0
- bloqade/visual/animation/runtime/__init__.py +0 -0
- bloqade/visual/animation/runtime/aod.py +36 -0
- bloqade/visual/animation/runtime/atoms.py +55 -0
- bloqade/visual/animation/runtime/ppoly.py +50 -0
- bloqade/visual/animation/runtime/qpustate.py +119 -0
- bloqade/visual/animation/runtime/utils.py +43 -0
- bloqade_circuit-0.1.0.dist-info/METADATA +70 -0
- bloqade_circuit-0.1.0.dist-info/RECORD +153 -0
- bloqade_circuit-0.1.0.dist-info/WHEEL +4 -0
- bloqade_circuit-0.1.0.dist-info/licenses/LICENSE +234 -0
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
from kirin import ir, types, lowering
|
|
2
|
+
from kirin.decl import info, statement
|
|
3
|
+
|
|
4
|
+
from .types import OpType
|
|
5
|
+
from .traits import Unitary, HasSites, FixedSites, MaybeUnitary
|
|
6
|
+
from .complex import Complex
|
|
7
|
+
from ._dialect import dialect
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@statement
|
|
11
|
+
class Operator(ir.Statement):
|
|
12
|
+
pass
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@statement
|
|
16
|
+
class PrimitiveOp(Operator):
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@statement
|
|
21
|
+
class CompositeOp(Operator):
|
|
22
|
+
pass
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@statement
|
|
26
|
+
class BinaryOp(CompositeOp):
|
|
27
|
+
lhs: ir.SSAValue = info.argument(OpType)
|
|
28
|
+
rhs: ir.SSAValue = info.argument(OpType)
|
|
29
|
+
result: ir.ResultValue = info.result(OpType)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@statement(dialect=dialect)
|
|
33
|
+
class Kron(BinaryOp):
|
|
34
|
+
traits = frozenset({ir.Pure(), lowering.FromPythonCall(), MaybeUnitary()})
|
|
35
|
+
is_unitary: bool = info.attribute(default=False)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@statement(dialect=dialect)
|
|
39
|
+
class Mult(BinaryOp):
|
|
40
|
+
traits = frozenset({ir.Pure(), lowering.FromPythonCall(), MaybeUnitary()})
|
|
41
|
+
is_unitary: bool = info.attribute(default=False)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@statement(dialect=dialect)
|
|
45
|
+
class Adjoint(CompositeOp):
|
|
46
|
+
traits = frozenset({ir.Pure(), lowering.FromPythonCall(), MaybeUnitary()})
|
|
47
|
+
is_unitary: bool = info.attribute(default=False)
|
|
48
|
+
op: ir.SSAValue = info.argument(OpType)
|
|
49
|
+
result: ir.ResultValue = info.result(OpType)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@statement(dialect=dialect)
|
|
53
|
+
class Scale(CompositeOp):
|
|
54
|
+
traits = frozenset({ir.Pure(), lowering.FromPythonCall(), MaybeUnitary()})
|
|
55
|
+
is_unitary: bool = info.attribute(default=False)
|
|
56
|
+
op: ir.SSAValue = info.argument(OpType)
|
|
57
|
+
factor: ir.SSAValue = info.argument(Complex)
|
|
58
|
+
result: ir.ResultValue = info.result(OpType)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@statement(dialect=dialect)
|
|
62
|
+
class Control(CompositeOp):
|
|
63
|
+
traits = frozenset({ir.Pure(), lowering.FromPythonCall(), MaybeUnitary()})
|
|
64
|
+
is_unitary: bool = info.attribute(default=False)
|
|
65
|
+
op: ir.SSAValue = info.argument(OpType)
|
|
66
|
+
n_controls: int = info.attribute()
|
|
67
|
+
result: ir.ResultValue = info.result(OpType)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@statement(dialect=dialect)
|
|
71
|
+
class Rot(CompositeOp):
|
|
72
|
+
traits = frozenset({ir.Pure(), lowering.FromPythonCall(), Unitary()})
|
|
73
|
+
axis: ir.SSAValue = info.argument(OpType)
|
|
74
|
+
angle: ir.SSAValue = info.argument(types.Float)
|
|
75
|
+
result: ir.ResultValue = info.result(OpType)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@statement(dialect=dialect)
|
|
79
|
+
class Identity(CompositeOp):
|
|
80
|
+
traits = frozenset({ir.Pure(), lowering.FromPythonCall(), Unitary(), HasSites()})
|
|
81
|
+
sites: int = info.attribute()
|
|
82
|
+
result: ir.ResultValue = info.result(OpType)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
@statement
|
|
86
|
+
class ConstantOp(PrimitiveOp):
|
|
87
|
+
traits = frozenset(
|
|
88
|
+
{ir.Pure(), lowering.FromPythonCall(), ir.ConstantLike(), FixedSites(1)}
|
|
89
|
+
)
|
|
90
|
+
result: ir.ResultValue = info.result(OpType)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
@statement
|
|
94
|
+
class ConstantUnitary(ConstantOp):
|
|
95
|
+
traits = frozenset(
|
|
96
|
+
{
|
|
97
|
+
ir.Pure(),
|
|
98
|
+
lowering.FromPythonCall(),
|
|
99
|
+
ir.ConstantLike(),
|
|
100
|
+
Unitary(),
|
|
101
|
+
FixedSites(1),
|
|
102
|
+
}
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
@statement(dialect=dialect)
|
|
107
|
+
class PhaseOp(PrimitiveOp):
|
|
108
|
+
"""
|
|
109
|
+
A phase operator.
|
|
110
|
+
|
|
111
|
+
$$
|
|
112
|
+
PhaseOp(theta) = e^{i \theta} I
|
|
113
|
+
$$
|
|
114
|
+
"""
|
|
115
|
+
|
|
116
|
+
traits = frozenset({ir.Pure(), lowering.FromPythonCall(), Unitary(), FixedSites(1)})
|
|
117
|
+
theta: ir.SSAValue = info.argument(types.Float)
|
|
118
|
+
result: ir.ResultValue = info.result(OpType)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
@statement(dialect=dialect)
|
|
122
|
+
class ShiftOp(PrimitiveOp):
|
|
123
|
+
"""
|
|
124
|
+
A phase shift operator.
|
|
125
|
+
|
|
126
|
+
$$
|
|
127
|
+
Shift(theta) = \\begin{bmatrix} 1 & 0 \\\\ 0 & e^{i \\theta} \\end{bmatrix}
|
|
128
|
+
$$
|
|
129
|
+
"""
|
|
130
|
+
|
|
131
|
+
traits = frozenset({ir.Pure(), lowering.FromPythonCall(), Unitary(), FixedSites(1)})
|
|
132
|
+
theta: ir.SSAValue = info.argument(types.Float)
|
|
133
|
+
result: ir.ResultValue = info.result(OpType)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
@statement
|
|
137
|
+
class PauliOp(ConstantUnitary):
|
|
138
|
+
pass
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
@statement(dialect=dialect)
|
|
142
|
+
class X(PauliOp):
|
|
143
|
+
pass
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
@statement(dialect=dialect)
|
|
147
|
+
class Y(PauliOp):
|
|
148
|
+
pass
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
@statement(dialect=dialect)
|
|
152
|
+
class Z(PauliOp):
|
|
153
|
+
pass
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
@statement(dialect=dialect)
|
|
157
|
+
class H(ConstantUnitary):
|
|
158
|
+
pass
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
@statement(dialect=dialect)
|
|
162
|
+
class S(ConstantUnitary):
|
|
163
|
+
pass
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
@statement(dialect=dialect)
|
|
167
|
+
class T(ConstantUnitary):
|
|
168
|
+
pass
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
@statement(dialect=dialect)
|
|
172
|
+
class P0(ConstantOp):
|
|
173
|
+
"""
|
|
174
|
+
The $P_0$ projection operator.
|
|
175
|
+
|
|
176
|
+
$$
|
|
177
|
+
P0 = \\begin{bmatrix} 1 & 0 \\\\ 0 & 0 \\end{bmatrix}
|
|
178
|
+
$$
|
|
179
|
+
"""
|
|
180
|
+
|
|
181
|
+
pass
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
@statement(dialect=dialect)
|
|
185
|
+
class P1(ConstantOp):
|
|
186
|
+
"""
|
|
187
|
+
The $P_1$ projection operator.
|
|
188
|
+
|
|
189
|
+
$$
|
|
190
|
+
P1 = \\begin{bmatrix} 0 & 0 \\\\ 0 & 1 \\end{bmatrix}
|
|
191
|
+
$$
|
|
192
|
+
"""
|
|
193
|
+
|
|
194
|
+
pass
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
@statement(dialect=dialect)
|
|
198
|
+
class Sn(ConstantOp):
|
|
199
|
+
"""
|
|
200
|
+
$S_{-}$ operator.
|
|
201
|
+
|
|
202
|
+
$$
|
|
203
|
+
Sn = \\frac{1}{2} (S_x - i S_y) = \\frac{1}{2} \\begin{bmatrix} 0 & 0 \\\\ 1 & 0 \\end{bmatrix}
|
|
204
|
+
$$
|
|
205
|
+
"""
|
|
206
|
+
|
|
207
|
+
pass
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
@statement(dialect=dialect)
|
|
211
|
+
class Sp(ConstantOp):
|
|
212
|
+
"""
|
|
213
|
+
$S_{+}$ operator.
|
|
214
|
+
|
|
215
|
+
$$
|
|
216
|
+
Sp = \\frac{1}{2} (S_x + i S_y) = \\frac{1}{2}\\begin{bmatrix} 0 & 1 \\\\ 0 & 0 \\end{bmatrix}
|
|
217
|
+
$$
|
|
218
|
+
"""
|
|
219
|
+
|
|
220
|
+
pass
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
from typing import cast
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
|
|
4
|
+
from kirin import ir
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass(frozen=True)
|
|
8
|
+
class FixedSites(ir.StmtTrait):
|
|
9
|
+
data: int
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass(frozen=True)
|
|
13
|
+
class HasSites(ir.StmtTrait):
|
|
14
|
+
"""An operator with a `sites` attribute."""
|
|
15
|
+
|
|
16
|
+
def get_sites(self, stmt: ir.Statement):
|
|
17
|
+
attr = stmt.get_attr_or_prop("sites")
|
|
18
|
+
if attr is None:
|
|
19
|
+
raise ValueError(f"Missing sites attribute in {stmt}")
|
|
20
|
+
return cast(ir.PyAttr[int], attr).data
|
|
21
|
+
|
|
22
|
+
def set_sites(self, stmt: ir.Statement, value: int):
|
|
23
|
+
stmt.attributes["sites"] = ir.PyAttr(value)
|
|
24
|
+
return
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass(frozen=True)
|
|
28
|
+
class Unitary(ir.StmtTrait):
|
|
29
|
+
pass
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@dataclass(frozen=True)
|
|
33
|
+
class MaybeUnitary(ir.StmtTrait):
|
|
34
|
+
|
|
35
|
+
def is_unitary(self, stmt: ir.Statement):
|
|
36
|
+
attr = stmt.get_attr_or_prop("is_unitary")
|
|
37
|
+
if attr is None:
|
|
38
|
+
return False
|
|
39
|
+
return cast(ir.PyAttr[bool], attr).data
|
|
40
|
+
|
|
41
|
+
def set_unitary(self, stmt: ir.Statement, value: bool):
|
|
42
|
+
stmt.attributes["is_unitary"] = ir.PyAttr(value)
|
|
43
|
+
return
|
bloqade/squin/qubit.py
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
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
|
|
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
|
+
dialect = ir.Dialect("squin.qubit")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@statement(dialect=dialect)
|
|
24
|
+
class New(ir.Statement):
|
|
25
|
+
traits = frozenset({lowering.FromPythonCall()})
|
|
26
|
+
n_qubits: ir.SSAValue = info.argument(types.Int)
|
|
27
|
+
result: ir.ResultValue = info.result(ilist.IListType[QubitType, types.Any])
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@statement(dialect=dialect)
|
|
31
|
+
class Apply(ir.Statement):
|
|
32
|
+
traits = frozenset({lowering.FromPythonCall()})
|
|
33
|
+
operator: ir.SSAValue = info.argument(OpType)
|
|
34
|
+
qubits: ir.SSAValue = info.argument(ilist.IListType[QubitType])
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@statement(dialect=dialect)
|
|
38
|
+
class Measure(ir.Statement):
|
|
39
|
+
traits = frozenset({lowering.FromPythonCall()})
|
|
40
|
+
qubits: ir.SSAValue = info.argument(ilist.IListType[QubitType])
|
|
41
|
+
result: ir.ResultValue = info.result(types.Int)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@statement(dialect=dialect)
|
|
45
|
+
class MeasureAndReset(ir.Statement):
|
|
46
|
+
traits = frozenset({lowering.FromPythonCall()})
|
|
47
|
+
qubits: ir.SSAValue = info.argument(ilist.IListType[QubitType])
|
|
48
|
+
result: ir.ResultValue = info.result(types.Int)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@statement(dialect=dialect)
|
|
52
|
+
class Reset(ir.Statement):
|
|
53
|
+
qubits: ir.SSAValue = info.argument(ilist.IListType[QubitType])
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
# NOTE: no dependent types in Python, so we have to mark it Any...
|
|
57
|
+
@wraps(New)
|
|
58
|
+
def new(n_qubits: int) -> ilist.IList[Qubit, Any]:
|
|
59
|
+
"""Create a new list of qubits.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
n_qubits(int): The number of qubits to create.
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
(ilist.IList[Qubit, n_qubits]) A list of qubits.
|
|
66
|
+
"""
|
|
67
|
+
...
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@wraps(Apply)
|
|
71
|
+
def apply(operator: Op, qubits: ilist.IList[Qubit, Any] | list[Qubit]) -> None:
|
|
72
|
+
"""Apply an operator to a list of qubits.
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
operator: The operator to apply.
|
|
76
|
+
qubits: The list of qubits to apply the operator to. The size of the list
|
|
77
|
+
must be inferable and match the number of qubits expected by the operator.
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
None
|
|
81
|
+
"""
|
|
82
|
+
...
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
@wraps(Measure)
|
|
86
|
+
def measure(qubits: ilist.IList[Qubit, Any]) -> int:
|
|
87
|
+
"""Measure the qubits in the list."
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
qubits: The list of qubits to measure.
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
int: The result of the measurement.
|
|
94
|
+
"""
|
|
95
|
+
...
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
@wraps(MeasureAndReset)
|
|
99
|
+
def measure_and_reset(qubits: ilist.IList[Qubit, Any]) -> int:
|
|
100
|
+
"""Measure the qubits in the list and reset them."
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
qubits: The list of qubits to measure and reset.
|
|
104
|
+
|
|
105
|
+
Returns:
|
|
106
|
+
int: The result of the measurement.
|
|
107
|
+
"""
|
|
108
|
+
...
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
@wraps(Reset)
|
|
112
|
+
def reset(qubits: ilist.IList[Qubit, Any]) -> None:
|
|
113
|
+
"""Reset the qubits in the list."
|
|
114
|
+
|
|
115
|
+
Args:
|
|
116
|
+
qubits: The list of qubits to reset.
|
|
117
|
+
"""
|
|
118
|
+
...
|
bloqade/squin/wire.py
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"""A NVIDIA QUAKE-like wire dialect.
|
|
2
|
+
|
|
3
|
+
This dialect is expected to be used in combination with the operator dialect
|
|
4
|
+
as an intermediate representation for analysis and optimization of quantum
|
|
5
|
+
circuits. Thus we do not define wrapping functions for the statements in this
|
|
6
|
+
dialect.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from kirin import ir, types, interp, lowering
|
|
10
|
+
from kirin.decl import info, statement
|
|
11
|
+
|
|
12
|
+
from bloqade.types import QubitType
|
|
13
|
+
|
|
14
|
+
from .op.types import OpType
|
|
15
|
+
|
|
16
|
+
# from kirin.lowering import wraps
|
|
17
|
+
|
|
18
|
+
# from .op.types import Op, OpType
|
|
19
|
+
|
|
20
|
+
dialect = ir.Dialect("squin.wire")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class WireTerminator(ir.StmtTrait):
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class Wire:
|
|
28
|
+
pass
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
WireType = types.PyClass(Wire)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# no return value for `wrap`
|
|
35
|
+
@statement(dialect=dialect)
|
|
36
|
+
class Wrap(ir.Statement):
|
|
37
|
+
traits = frozenset({lowering.FromPythonCall(), WireTerminator()})
|
|
38
|
+
wire: ir.SSAValue = info.argument(WireType)
|
|
39
|
+
qubit: ir.SSAValue = info.argument(QubitType)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
# "Unwrap the quantum references to expose wires" -> From Quake Dialect documentation
|
|
43
|
+
# Unwrap(Qubit) -> Wire
|
|
44
|
+
@statement(dialect=dialect)
|
|
45
|
+
class Unwrap(ir.Statement):
|
|
46
|
+
traits = frozenset({lowering.FromPythonCall(), ir.Pure()})
|
|
47
|
+
qubit: ir.SSAValue = info.argument(QubitType)
|
|
48
|
+
result: ir.ResultValue = info.result(WireType)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
# In Quake, you put a wire in and get a wire out when you "apply" an operator
|
|
52
|
+
# In this case though we just need to indicate that an operator is applied to list[wires]
|
|
53
|
+
@statement(dialect=dialect)
|
|
54
|
+
class Apply(ir.Statement): # apply(op, w1, w2, ...)
|
|
55
|
+
traits = frozenset({lowering.FromPythonCall(), ir.Pure()})
|
|
56
|
+
operator: ir.SSAValue = info.argument(OpType)
|
|
57
|
+
inputs: tuple[ir.SSAValue, ...] = info.argument(WireType)
|
|
58
|
+
|
|
59
|
+
def __init__(self, operator: ir.SSAValue, *args: ir.SSAValue):
|
|
60
|
+
result_types = tuple(WireType for _ in args)
|
|
61
|
+
super().__init__(
|
|
62
|
+
args=(operator,) + args,
|
|
63
|
+
result_types=result_types, # result types of the Apply statement, should all be WireTypes
|
|
64
|
+
args_slice={
|
|
65
|
+
"operator": 0,
|
|
66
|
+
"inputs": slice(1, None),
|
|
67
|
+
}, # pretty printing + syntax sugar
|
|
68
|
+
) # custom lowering required for wrapper to work here
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
# NOTE: measurement cannot be pure because they will collapse the state
|
|
72
|
+
# of the qubit. The state is a hidden state that is not visible to
|
|
73
|
+
# the user in the wire dialect.
|
|
74
|
+
@statement(dialect=dialect)
|
|
75
|
+
class Measure(ir.Statement):
|
|
76
|
+
traits = frozenset({lowering.FromPythonCall(), WireTerminator()})
|
|
77
|
+
wire: ir.SSAValue = info.argument(WireType)
|
|
78
|
+
result: ir.ResultValue = info.result(types.Int)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@statement(dialect=dialect)
|
|
82
|
+
class MeasureAndReset(ir.Statement):
|
|
83
|
+
traits = frozenset({lowering.FromPythonCall(), WireTerminator()})
|
|
84
|
+
wire: ir.SSAValue = info.argument(WireType)
|
|
85
|
+
result: ir.ResultValue = info.result(types.Int)
|
|
86
|
+
out_wire: ir.ResultValue = info.result(WireType)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@statement(dialect=dialect)
|
|
90
|
+
class Reset(ir.Statement):
|
|
91
|
+
traits = frozenset({lowering.FromPythonCall(), WireTerminator()})
|
|
92
|
+
wire: ir.SSAValue = info.argument(WireType)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
# Issue where constant propagation can't handle
|
|
96
|
+
# multiple return values from Apply properly
|
|
97
|
+
@dialect.register(key="constprop")
|
|
98
|
+
class ConstPropWire(interp.MethodTable):
|
|
99
|
+
|
|
100
|
+
@interp.impl(Apply)
|
|
101
|
+
def apply(self, interp, frame, stmt: Apply):
|
|
102
|
+
|
|
103
|
+
return frame.get_values(stmt.inputs)
|
bloqade/stim/__init__.py
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
from typing import Union
|
|
2
|
+
|
|
3
|
+
from kirin.lowering import wraps
|
|
4
|
+
|
|
5
|
+
from .dialects import aux, gate, noise, collapse
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# dialect:: gate
|
|
9
|
+
## 1q
|
|
10
|
+
@wraps(gate.X)
|
|
11
|
+
def x(targets: tuple[int, ...], dagger: bool = False) -> None: ...
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@wraps(gate.Y)
|
|
15
|
+
def y(targets: tuple[int, ...], dagger: bool = False) -> None: ...
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@wraps(gate.Z)
|
|
19
|
+
def z(targets: tuple[int, ...], dagger: bool = False) -> None: ...
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@wraps(gate.Identity)
|
|
23
|
+
def identity(targets: tuple[int, ...], dagger: bool = False) -> None: ...
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@wraps(gate.H)
|
|
27
|
+
def h(targets: tuple[int, ...], dagger: bool = False) -> None: ...
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@wraps(gate.S)
|
|
31
|
+
def s(targets: tuple[int, ...], dagger: bool = False) -> None: ...
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@wraps(gate.SqrtX)
|
|
35
|
+
def sqrt_x(targets: tuple[int, ...], dagger: bool = False) -> None: ...
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@wraps(gate.SqrtY)
|
|
39
|
+
def sqrt_y(targets: tuple[int, ...], dagger: bool = False) -> None: ...
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@wraps(gate.SqrtZ)
|
|
43
|
+
def sqrt_z(targets: tuple[int, ...], dagger: bool = False) -> None: ...
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
## clif 2q
|
|
47
|
+
@wraps(gate.Swap)
|
|
48
|
+
def swap(targets: tuple[int, ...], dagger: bool = False) -> None: ...
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
## ctrl 2q
|
|
52
|
+
@wraps(gate.CX)
|
|
53
|
+
def cx(
|
|
54
|
+
controls: tuple[int, ...], targets: tuple[int, ...], dagger: bool = False
|
|
55
|
+
) -> None: ...
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@wraps(gate.CY)
|
|
59
|
+
def cy(
|
|
60
|
+
controls: tuple[int, ...], targets: tuple[int, ...], dagger: bool = False
|
|
61
|
+
) -> None: ...
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
@wraps(gate.CZ)
|
|
65
|
+
def cz(
|
|
66
|
+
controls: tuple[int, ...], targets: tuple[int, ...], dagger: bool = False
|
|
67
|
+
) -> None: ...
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
## pp
|
|
71
|
+
@wraps(gate.SPP)
|
|
72
|
+
def spp(targets: tuple[aux.PauliString, ...], dagger=False) -> None: ...
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
# dialect:: aux
|
|
76
|
+
@wraps(aux.GetRecord)
|
|
77
|
+
def rec(id: int) -> aux.RecordResult: ...
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
@wraps(aux.Detector)
|
|
81
|
+
def detector(
|
|
82
|
+
coord: tuple[Union[int, float], ...], targets: tuple[aux.RecordResult, ...]
|
|
83
|
+
) -> None: ...
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
@wraps(aux.ObservableInclude)
|
|
87
|
+
def observable_include(idx: int, targets: tuple[aux.RecordResult, ...]) -> None: ...
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
@wraps(aux.Tick)
|
|
91
|
+
def tick() -> None: ...
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
@wraps(aux.NewPauliString)
|
|
95
|
+
def pauli_string(
|
|
96
|
+
string: tuple[str, ...], flipped: tuple[bool, ...], targets: tuple[int, ...]
|
|
97
|
+
) -> aux.PauliString: ...
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
# dialect:: collapse
|
|
101
|
+
@wraps(collapse.MZ)
|
|
102
|
+
def mz(p: float, targets: tuple[int, ...]) -> None: ...
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
@wraps(collapse.MY)
|
|
106
|
+
def my(p: float, targets: tuple[int, ...]) -> None: ...
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
@wraps(collapse.MX)
|
|
110
|
+
def mx(p: float, targets: tuple[int, ...]) -> None: ...
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
@wraps(collapse.MZZ)
|
|
114
|
+
def mzz(p: float, targets: tuple[int, ...]) -> None: ...
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
@wraps(collapse.MYY)
|
|
118
|
+
def myy(p: float, targets: tuple[int, ...]) -> None: ...
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
@wraps(collapse.MXX)
|
|
122
|
+
def mxx(p: float, targets: tuple[int, ...]) -> None: ...
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
@wraps(collapse.PPMeasurement)
|
|
126
|
+
def mpp(p: float, targets: tuple[aux.PauliString, ...]) -> None: ...
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
@wraps(collapse.RZ)
|
|
130
|
+
def rz(targets: tuple[int, ...]) -> None: ...
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
@wraps(collapse.RY)
|
|
134
|
+
def ry(targets: tuple[int, ...]) -> None: ...
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
@wraps(collapse.RX)
|
|
138
|
+
def rx(targets: tuple[int, ...]) -> None: ...
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
# dialect:: noise
|
|
142
|
+
@wraps(noise.Depolarize1)
|
|
143
|
+
def depolarize1(p: float, targets: tuple[int, ...]) -> None: ...
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
@wraps(noise.Depolarize2)
|
|
147
|
+
def depolarize2(p: float, targets: tuple[int, ...]) -> None: ...
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
@wraps(noise.PauliChannel1)
|
|
151
|
+
def pauli_channel1(
|
|
152
|
+
px: float, py: float, pz: float, targets: tuple[int, ...]
|
|
153
|
+
) -> None: ...
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
@wraps(noise.PauliChannel2)
|
|
157
|
+
def pauli_channel2(
|
|
158
|
+
pix: float,
|
|
159
|
+
piy: float,
|
|
160
|
+
piz: float,
|
|
161
|
+
pxi: float,
|
|
162
|
+
pxx: float,
|
|
163
|
+
pxy: float,
|
|
164
|
+
pxz: float,
|
|
165
|
+
pyi: float,
|
|
166
|
+
pyx: float,
|
|
167
|
+
pyy: float,
|
|
168
|
+
pyz: float,
|
|
169
|
+
pzi: float,
|
|
170
|
+
pzx: float,
|
|
171
|
+
pzy: float,
|
|
172
|
+
pzz: float,
|
|
173
|
+
targets: tuple[int, ...],
|
|
174
|
+
) -> None: ...
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
@wraps(noise.XError)
|
|
178
|
+
def x_error(p: float, targets: tuple[int, ...]) -> None: ...
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
@wraps(noise.YError)
|
|
182
|
+
def y_error(p: float, targets: tuple[int, ...]) -> None: ...
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
@wraps(noise.ZError)
|
|
186
|
+
def z_error(p: float, targets: tuple[int, ...]) -> None: ...
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from . import lowering as lowering
|
|
2
|
+
from .emit import EmitStimAuxMethods as EmitStimAuxMethods
|
|
3
|
+
from .stmts import * # noqa F403
|
|
4
|
+
from .types import (
|
|
5
|
+
RecordType as RecordType,
|
|
6
|
+
PauliString as PauliString,
|
|
7
|
+
RecordResult as RecordResult,
|
|
8
|
+
PauliStringType as PauliStringType,
|
|
9
|
+
)
|
|
10
|
+
from .interp import StimAuxMethods as StimAuxMethods
|
|
11
|
+
from ._dialect import dialect as dialect
|