bloqade-circuit 0.6.2__py3-none-any.whl → 0.6.4__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.
- bloqade/analysis/measure_id/__init__.py +4 -1
- bloqade/analysis/measure_id/analysis.py +13 -2
- bloqade/analysis/measure_id/impls.py +41 -2
- bloqade/pyqrack/device.py +14 -2
- bloqade/pyqrack/squin/op.py +14 -0
- bloqade/squin/cirq/__init__.py +19 -4
- bloqade/stim/passes/__init__.py +5 -1
- bloqade/stim/passes/simplify_ifs.py +10 -1
- bloqade/stim/passes/squin_to_stim.py +54 -21
- bloqade/stim/rewrite/__init__.py +1 -0
- bloqade/stim/rewrite/ifs_to_stim.py +5 -6
- bloqade/stim/rewrite/squin_measure.py +2 -61
- {bloqade_circuit-0.6.2.dist-info → bloqade_circuit-0.6.4.dist-info}/METADATA +1 -1
- {bloqade_circuit-0.6.2.dist-info → bloqade_circuit-0.6.4.dist-info}/RECORD +16 -16
- {bloqade_circuit-0.6.2.dist-info → bloqade_circuit-0.6.4.dist-info}/WHEEL +0 -0
- {bloqade_circuit-0.6.2.dist-info → bloqade_circuit-0.6.4.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
from typing import TypeVar
|
|
2
|
+
from dataclasses import field, dataclass
|
|
2
3
|
|
|
3
4
|
from kirin import ir, interp
|
|
4
|
-
from kirin.analysis import
|
|
5
|
+
from kirin.analysis import ForwardExtra, const
|
|
5
6
|
from kirin.analysis.forward import ForwardFrame
|
|
6
7
|
|
|
7
8
|
from .lattice import MeasureId, NotMeasureId
|
|
8
9
|
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
@dataclass
|
|
12
|
+
class MeasureIDFrame(ForwardFrame[MeasureId]):
|
|
13
|
+
num_measures_at_stmt: dict[ir.Statement, int] = field(default_factory=dict)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class MeasurementIDAnalysis(ForwardExtra[MeasureIDFrame, MeasureId]):
|
|
11
17
|
|
|
12
18
|
keys = ["measure_id"]
|
|
13
19
|
lattice = MeasureId
|
|
@@ -15,6 +21,11 @@ class MeasurementIDAnalysis(Forward[MeasureId]):
|
|
|
15
21
|
# then use this to generate the negative values for target rec indices
|
|
16
22
|
measure_count = 0
|
|
17
23
|
|
|
24
|
+
def initialize_frame(
|
|
25
|
+
self, code: ir.Statement, *, has_parent_access: bool = False
|
|
26
|
+
) -> MeasureIDFrame:
|
|
27
|
+
return MeasureIDFrame(code, has_parent_access=has_parent_access)
|
|
28
|
+
|
|
18
29
|
# Still default to bottom,
|
|
19
30
|
# but let constants return the softer "NoMeasureId" type from impl
|
|
20
31
|
def eval_stmt_fallback(
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from kirin import types as kirin_types, interp
|
|
2
|
+
from kirin.analysis import const
|
|
2
3
|
from kirin.dialects import py, scf, func, ilist
|
|
3
4
|
|
|
4
5
|
from bloqade.squin import wire, qubit
|
|
@@ -10,7 +11,7 @@ from .lattice import (
|
|
|
10
11
|
MeasureIdTuple,
|
|
11
12
|
InvalidMeasureId,
|
|
12
13
|
)
|
|
13
|
-
from .analysis import MeasurementIDAnalysis
|
|
14
|
+
from .analysis import MeasureIDFrame, MeasurementIDAnalysis
|
|
14
15
|
|
|
15
16
|
## Can't do wire right now because of
|
|
16
17
|
## unresolved RFC on return type
|
|
@@ -113,6 +114,15 @@ class PyIndexing(interp.MethodTable):
|
|
|
113
114
|
return (InvalidMeasureId(),)
|
|
114
115
|
|
|
115
116
|
|
|
117
|
+
@py.assign.dialect.register(key="measure_id")
|
|
118
|
+
class PyAssign(interp.MethodTable):
|
|
119
|
+
@interp.impl(py.Alias)
|
|
120
|
+
def alias(
|
|
121
|
+
self, interp: MeasurementIDAnalysis, frame: interp.Frame, stmt: py.assign.Alias
|
|
122
|
+
):
|
|
123
|
+
return (frame.get(stmt.value),)
|
|
124
|
+
|
|
125
|
+
|
|
116
126
|
@py.binop.dialect.register(key="measure_id")
|
|
117
127
|
class PyBinOp(interp.MethodTable):
|
|
118
128
|
@interp.impl(py.Add)
|
|
@@ -152,4 +162,33 @@ class Func(interp.MethodTable):
|
|
|
152
162
|
# scf, particularly IfElse
|
|
153
163
|
@scf.dialect.register(key="measure_id")
|
|
154
164
|
class Scf(scf.absint.Methods):
|
|
155
|
-
|
|
165
|
+
|
|
166
|
+
@interp.impl(scf.IfElse)
|
|
167
|
+
def if_else(
|
|
168
|
+
self,
|
|
169
|
+
interp_: MeasurementIDAnalysis,
|
|
170
|
+
frame: MeasureIDFrame,
|
|
171
|
+
stmt: scf.IfElse,
|
|
172
|
+
):
|
|
173
|
+
|
|
174
|
+
frame.num_measures_at_stmt[stmt] = interp_.measure_count
|
|
175
|
+
|
|
176
|
+
# rest of the code taken directly from scf.absint.Methods base implementation
|
|
177
|
+
|
|
178
|
+
if isinstance(hint := stmt.cond.hints.get("const"), const.Value):
|
|
179
|
+
if hint.data:
|
|
180
|
+
return self._infer_if_else_cond(interp_, frame, stmt, stmt.then_body)
|
|
181
|
+
else:
|
|
182
|
+
return self._infer_if_else_cond(interp_, frame, stmt, stmt.else_body)
|
|
183
|
+
then_results = self._infer_if_else_cond(interp_, frame, stmt, stmt.then_body)
|
|
184
|
+
else_results = self._infer_if_else_cond(interp_, frame, stmt, stmt.else_body)
|
|
185
|
+
|
|
186
|
+
match (then_results, else_results):
|
|
187
|
+
case (interp.ReturnValue(then_value), interp.ReturnValue(else_value)):
|
|
188
|
+
return interp.ReturnValue(then_value.join(else_value))
|
|
189
|
+
case (interp.ReturnValue(then_value), _):
|
|
190
|
+
return then_results
|
|
191
|
+
case (_, interp.ReturnValue(else_value)):
|
|
192
|
+
return else_results
|
|
193
|
+
case _:
|
|
194
|
+
return interp_.join_results(then_results, else_results)
|
bloqade/pyqrack/device.py
CHANGED
|
@@ -3,7 +3,9 @@ from dataclasses import field, dataclass
|
|
|
3
3
|
|
|
4
4
|
import numpy as np
|
|
5
5
|
from kirin import ir
|
|
6
|
+
from kirin.passes import fold
|
|
6
7
|
|
|
8
|
+
from bloqade.squin import noise as squin_noise
|
|
7
9
|
from pyqrack.pauli import Pauli
|
|
8
10
|
from bloqade.device import AbstractSimulatorDevice
|
|
9
11
|
from bloqade.pyqrack.reg import Measurement, PyQrackQubit
|
|
@@ -16,6 +18,7 @@ from bloqade.pyqrack.base import (
|
|
|
16
18
|
_default_pyqrack_args,
|
|
17
19
|
)
|
|
18
20
|
from bloqade.pyqrack.task import PyQrackSimulatorTask
|
|
21
|
+
from bloqade.squin.noise.rewrite import RewriteNoiseStmts
|
|
19
22
|
from bloqade.analysis.address.lattice import AnyAddress
|
|
20
23
|
from bloqade.analysis.address.analysis import AddressAnalysis
|
|
21
24
|
|
|
@@ -47,14 +50,23 @@ class PyQrackSimulatorBase(AbstractSimulatorDevice[PyQrackSimulatorTask]):
|
|
|
47
50
|
kwargs: dict[str, Any],
|
|
48
51
|
memory: MemoryType,
|
|
49
52
|
) -> PyQrackSimulatorTask[Params, RetType, MemoryType]:
|
|
53
|
+
|
|
54
|
+
if squin_noise in mt.dialects:
|
|
55
|
+
# NOTE: rewrite noise statements
|
|
56
|
+
mt_ = mt.similar(mt.dialects)
|
|
57
|
+
RewriteNoiseStmts(mt_.dialects)(mt_)
|
|
58
|
+
fold.Fold(mt_.dialects)(mt_)
|
|
59
|
+
else:
|
|
60
|
+
mt_ = mt
|
|
61
|
+
|
|
50
62
|
interp = PyQrackInterpreter(
|
|
51
|
-
|
|
63
|
+
mt_.dialects,
|
|
52
64
|
memory=memory,
|
|
53
65
|
rng_state=self.rng_state,
|
|
54
66
|
loss_m_result=self.loss_m_result,
|
|
55
67
|
)
|
|
56
68
|
return PyQrackSimulatorTask(
|
|
57
|
-
kernel=
|
|
69
|
+
kernel=mt_, args=args, kwargs=kwargs, pyqrack_interp=interp
|
|
58
70
|
)
|
|
59
71
|
|
|
60
72
|
def state_vector(
|
bloqade/pyqrack/squin/op.py
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import math
|
|
2
|
+
|
|
1
3
|
from kirin import interp
|
|
2
4
|
|
|
3
5
|
from bloqade.squin import op
|
|
@@ -122,6 +124,18 @@ class PyQrackMethods(interp.MethodTable):
|
|
|
122
124
|
) -> tuple[OperatorRuntimeABC]:
|
|
123
125
|
return (OperatorRuntime(method_name=stmt.name.lower()),)
|
|
124
126
|
|
|
127
|
+
@interp.impl(op.stmts.SqrtX)
|
|
128
|
+
@interp.impl(op.stmts.SqrtY)
|
|
129
|
+
def sqrt(
|
|
130
|
+
self,
|
|
131
|
+
interp: PyQrackInterpreter,
|
|
132
|
+
frame: interp.Frame,
|
|
133
|
+
stmt: op.stmts.SqrtX | op.stmts.SqrtY,
|
|
134
|
+
):
|
|
135
|
+
axis_name = "x" if isinstance(stmt, op.stmts.SqrtX) else "y"
|
|
136
|
+
axis = OperatorRuntime(method_name=axis_name)
|
|
137
|
+
return (RotRuntime(axis=axis, angle=-0.5 * math.pi),)
|
|
138
|
+
|
|
125
139
|
@interp.impl(op.stmts.P0)
|
|
126
140
|
@interp.impl(op.stmts.P1)
|
|
127
141
|
def projector(
|
bloqade/squin/cirq/__init__.py
CHANGED
|
@@ -157,6 +157,7 @@ def load_circuit(
|
|
|
157
157
|
def emit_circuit(
|
|
158
158
|
mt: ir.Method,
|
|
159
159
|
qubits: Sequence[cirq.Qid] | None = None,
|
|
160
|
+
ignore_returns: bool = False,
|
|
160
161
|
) -> cirq.Circuit:
|
|
161
162
|
"""Converts a squin.kernel method to a cirq.Circuit object.
|
|
162
163
|
|
|
@@ -170,6 +171,9 @@ def emit_circuit(
|
|
|
170
171
|
statement in the order they appear inside the kernel.
|
|
171
172
|
**Note**: If a list of qubits is provided, make sure that there is a sufficient
|
|
172
173
|
number of qubits for the resulting circuit.
|
|
174
|
+
ignore_returns (bool):
|
|
175
|
+
If `False`, emitting a circuit from a kernel that returns a value will error.
|
|
176
|
+
Set it to `True` in order to ignore the return value(s). Defaults to `False`.
|
|
173
177
|
|
|
174
178
|
## Examples:
|
|
175
179
|
|
|
@@ -228,11 +232,14 @@ def emit_circuit(
|
|
|
228
232
|
and manipulate the qubits in other circuits directly written in cirq as well.
|
|
229
233
|
"""
|
|
230
234
|
|
|
231
|
-
if
|
|
232
|
-
|
|
235
|
+
if (
|
|
236
|
+
not ignore_returns
|
|
237
|
+
and isinstance(mt.code, func.Function)
|
|
238
|
+
and not mt.code.signature.output.is_subseteq(types.NoneType)
|
|
233
239
|
):
|
|
234
240
|
raise EmitError(
|
|
235
241
|
"The method you are trying to convert to a circuit has a return value, but returning from a circuit is not supported."
|
|
242
|
+
" Set `ignore_returns = True` in order to simply ignore the return values and emit a circuit."
|
|
236
243
|
)
|
|
237
244
|
|
|
238
245
|
emitter = EmitCirq(qubits=qubits)
|
|
@@ -244,7 +251,12 @@ def emit_circuit(
|
|
|
244
251
|
return emitter.run(mt_, args=())
|
|
245
252
|
|
|
246
253
|
|
|
247
|
-
def dump_circuit(
|
|
254
|
+
def dump_circuit(
|
|
255
|
+
mt: ir.Method,
|
|
256
|
+
qubits: Sequence[cirq.Qid] | None = None,
|
|
257
|
+
ignore_returns: bool = False,
|
|
258
|
+
**kwargs,
|
|
259
|
+
):
|
|
248
260
|
"""Converts a squin.kernel method to a cirq.Circuit object and dumps it as JSON.
|
|
249
261
|
|
|
250
262
|
This just runs `emit_circuit` and calls the `cirq.to_json` function to emit a JSON.
|
|
@@ -259,7 +271,10 @@ def dump_circuit(mt: ir.Method, qubits: Sequence[cirq.Qid] | None = None, **kwar
|
|
|
259
271
|
statement in the order they appear inside the kernel.
|
|
260
272
|
**Note**: If a list of qubits is provided, make sure that there is a sufficient
|
|
261
273
|
number of qubits for the resulting circuit.
|
|
274
|
+
ignore_returns (bool):
|
|
275
|
+
If `False`, emitting a circuit from a kernel that returns a value will error.
|
|
276
|
+
Set it to `True` in order to ignore the return value(s). Defaults to `False`.
|
|
262
277
|
|
|
263
278
|
"""
|
|
264
|
-
circuit = emit_circuit(mt, qubits=qubits)
|
|
279
|
+
circuit = emit_circuit(mt, qubits=qubits, ignore_returns=ignore_returns)
|
|
265
280
|
return cirq.to_json(circuit, **kwargs)
|
bloqade/stim/passes/__init__.py
CHANGED
|
@@ -9,6 +9,7 @@ from kirin.rewrite import (
|
|
|
9
9
|
ConstantFold,
|
|
10
10
|
CommonSubexpressionElimination,
|
|
11
11
|
)
|
|
12
|
+
from kirin.dialects.ilist.passes import ConstList2IList
|
|
12
13
|
|
|
13
14
|
from ..rewrite.ifs_to_stim import StimLiftThenBody, StimSplitIfStmts
|
|
14
15
|
|
|
@@ -23,8 +24,16 @@ class StimSimplifyIfs(Pass):
|
|
|
23
24
|
Walk(StimSplitIfStmts()),
|
|
24
25
|
).rewrite(mt.code)
|
|
25
26
|
|
|
27
|
+
# because nested python lists don't have their
|
|
28
|
+
# member lists converted to ILists, ConstantFold
|
|
29
|
+
# can add python lists that can't be hashed, causing
|
|
30
|
+
# issues with CSE. ConstList2IList remedies that problem here.
|
|
26
31
|
result = (
|
|
27
|
-
|
|
32
|
+
Chain(
|
|
33
|
+
Fixpoint(Walk(ConstantFold())),
|
|
34
|
+
Walk(ConstList2IList()),
|
|
35
|
+
Walk(CommonSubexpressionElimination()),
|
|
36
|
+
)
|
|
28
37
|
.rewrite(mt.code)
|
|
29
38
|
.join(result)
|
|
30
39
|
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from dataclasses import dataclass
|
|
2
2
|
|
|
3
|
-
from kirin.passes import Fold
|
|
3
|
+
from kirin.passes import Fold, HintConst, TypeInfer
|
|
4
4
|
from kirin.rewrite import (
|
|
5
5
|
Walk,
|
|
6
6
|
Chain,
|
|
@@ -16,6 +16,7 @@ from kirin.ir.method import Method
|
|
|
16
16
|
from kirin.passes.abc import Pass
|
|
17
17
|
from kirin.rewrite.abc import RewriteResult
|
|
18
18
|
from kirin.passes.inline import InlinePass
|
|
19
|
+
from kirin.rewrite.alias import InlineAlias
|
|
19
20
|
|
|
20
21
|
from bloqade.stim.rewrite import (
|
|
21
22
|
SquinWireToStim,
|
|
@@ -33,11 +34,43 @@ from bloqade.squin.rewrite import (
|
|
|
33
34
|
from bloqade.rewrite.passes import CanonicalizeIList
|
|
34
35
|
from bloqade.analysis.address import AddressAnalysis
|
|
35
36
|
from bloqade.analysis.measure_id import MeasurementIDAnalysis
|
|
37
|
+
from bloqade.squin.rewrite.desugar import ApplyDesugarRule
|
|
36
38
|
|
|
37
39
|
from .simplify_ifs import StimSimplifyIfs
|
|
38
40
|
from ..rewrite.ifs_to_stim import IfToStim
|
|
39
41
|
|
|
40
42
|
|
|
43
|
+
@dataclass
|
|
44
|
+
class AggressiveForLoopUnroll(Pass):
|
|
45
|
+
"""
|
|
46
|
+
Aggressive unrolling of for loops, addresses cases where unroll
|
|
47
|
+
does not successfully handle nested loops because of a lack of constprop.
|
|
48
|
+
|
|
49
|
+
This should be invoked via fixpoint to let this be repeatedly applied until
|
|
50
|
+
no further rewrites are possible.
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
def unsafe_run(self, mt: Method) -> RewriteResult:
|
|
54
|
+
rule = Chain(
|
|
55
|
+
InlineGetField(),
|
|
56
|
+
InlineGetItem(),
|
|
57
|
+
scf.unroll.ForLoop(),
|
|
58
|
+
scf.trim.UnusedYield(),
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
# Intentionally only walk ONCE, let fixpoint happen with the WHOLE pass
|
|
62
|
+
# so that HintConst gets run right after, allowing subsequent unrolls to happen
|
|
63
|
+
rewrite_result = Walk(rule).rewrite(mt.code)
|
|
64
|
+
|
|
65
|
+
rewrite_result = (
|
|
66
|
+
HintConst(dialects=mt.dialects, no_raise=self.no_raise)
|
|
67
|
+
.unsafe_run(mt)
|
|
68
|
+
.join(rewrite_result)
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
return rewrite_result
|
|
72
|
+
|
|
73
|
+
|
|
41
74
|
@dataclass
|
|
42
75
|
class SquinToStimPass(Pass):
|
|
43
76
|
|
|
@@ -48,27 +81,24 @@ class SquinToStimPass(Pass):
|
|
|
48
81
|
dialects=mt.dialects, no_raise=self.no_raise
|
|
49
82
|
).unsafe_run(mt)
|
|
50
83
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
scf.trim.UnusedYield(),
|
|
84
|
+
rewrite_result = (
|
|
85
|
+
AggressiveForLoopUnroll(dialects=mt.dialects, no_raise=self.no_raise)
|
|
86
|
+
.fixpoint(mt)
|
|
87
|
+
.join(rewrite_result)
|
|
56
88
|
)
|
|
57
|
-
|
|
58
|
-
# fold_pass = Fold(mt.dialects, no_raise=self.no_raise)
|
|
59
|
-
# rewrite_result = fold_pass(mt)
|
|
89
|
+
|
|
60
90
|
rewrite_result = (
|
|
61
91
|
Walk(Fixpoint(CFGCompactify())).rewrite(mt.code).join(rewrite_result)
|
|
62
92
|
)
|
|
93
|
+
|
|
94
|
+
Walk(InlineAlias()).rewrite(mt.code).join(rewrite_result)
|
|
95
|
+
|
|
63
96
|
rewrite_result = (
|
|
64
97
|
StimSimplifyIfs(mt.dialects, no_raise=self.no_raise)
|
|
65
98
|
.unsafe_run(mt)
|
|
66
99
|
.join(rewrite_result)
|
|
67
100
|
)
|
|
68
101
|
|
|
69
|
-
# run typeinfer again after unroll etc. because we now insert
|
|
70
|
-
# a lot of new nodes, which might have more precise types
|
|
71
|
-
# self.typeinfer.unsafe_run(mt)
|
|
72
102
|
rewrite_result = (
|
|
73
103
|
Walk(Chain(ilist.rewrite.ConstList2IList(), ilist.rewrite.Unroll()))
|
|
74
104
|
.rewrite(mt.code)
|
|
@@ -82,6 +112,9 @@ class SquinToStimPass(Pass):
|
|
|
82
112
|
.join(rewrite_result)
|
|
83
113
|
)
|
|
84
114
|
|
|
115
|
+
TypeInfer(dialects=mt.dialects, no_raise=self.no_raise).unsafe_run(mt)
|
|
116
|
+
Walk(ApplyDesugarRule()).rewrite(mt.code)
|
|
117
|
+
|
|
85
118
|
# after this the program should be in a state where it is analyzable
|
|
86
119
|
# -------------------------------------------------------------------
|
|
87
120
|
|
|
@@ -99,12 +132,14 @@ class SquinToStimPass(Pass):
|
|
|
99
132
|
)
|
|
100
133
|
|
|
101
134
|
# 2. rewrite
|
|
135
|
+
## Invoke DCE afterwards to eliminate any GetItems
|
|
136
|
+
## that are no longer being used. This allows for
|
|
137
|
+
## SquinMeasureToStim to safely eliminate
|
|
138
|
+
## unused measure statements.
|
|
102
139
|
rewrite_result = (
|
|
103
|
-
|
|
104
|
-
IfToStim(
|
|
105
|
-
|
|
106
|
-
measure_count=mia.measure_count,
|
|
107
|
-
)
|
|
140
|
+
Chain(
|
|
141
|
+
Walk(IfToStim(measure_frame=meas_analysis_frame)),
|
|
142
|
+
Fixpoint(Walk(DeadCodeElimination())),
|
|
108
143
|
)
|
|
109
144
|
.rewrite(mt.code)
|
|
110
145
|
.join(rewrite_result)
|
|
@@ -120,17 +155,15 @@ class SquinToStimPass(Pass):
|
|
|
120
155
|
Walk(
|
|
121
156
|
Chain(
|
|
122
157
|
SquinQubitToStim(),
|
|
158
|
+
SquinMeasureToStim(),
|
|
123
159
|
SquinWireToStim(),
|
|
124
|
-
SquinMeasureToStim(
|
|
125
|
-
measure_id_result=meas_analysis_frame.entries,
|
|
126
|
-
total_measure_count=mia.measure_count,
|
|
127
|
-
), # reduce duplicated logic, can split out even more rules later
|
|
128
160
|
SquinWireIdentityElimination(),
|
|
129
161
|
)
|
|
130
162
|
)
|
|
131
163
|
.rewrite(mt.code)
|
|
132
164
|
.join(rewrite_result)
|
|
133
165
|
)
|
|
166
|
+
|
|
134
167
|
rewrite_result = (
|
|
135
168
|
CanonicalizeIList(dialects=mt.dialects, no_raise=self.no_raise)
|
|
136
169
|
.unsafe_run(mt)
|
bloqade/stim/rewrite/__init__.py
CHANGED
|
@@ -11,9 +11,9 @@ from bloqade.stim.rewrite.util import (
|
|
|
11
11
|
SQUIN_STIM_CONTROL_GATE_MAPPING,
|
|
12
12
|
insert_qubit_idx_from_address,
|
|
13
13
|
)
|
|
14
|
+
from bloqade.analysis.measure_id import MeasureIDFrame
|
|
14
15
|
from bloqade.stim.dialects.auxiliary import GetRecord
|
|
15
16
|
from bloqade.analysis.measure_id.lattice import (
|
|
16
|
-
MeasureId,
|
|
17
17
|
MeasureIdBool,
|
|
18
18
|
)
|
|
19
19
|
|
|
@@ -127,8 +127,7 @@ class IfToStim(IfElseSimplification, RewriteRule):
|
|
|
127
127
|
Rewrite if statements to stim equivalent statements.
|
|
128
128
|
"""
|
|
129
129
|
|
|
130
|
-
|
|
131
|
-
measure_count: int
|
|
130
|
+
measure_frame: MeasureIDFrame
|
|
132
131
|
|
|
133
132
|
def rewrite_Statement(self, node: ir.Statement) -> RewriteResult:
|
|
134
133
|
|
|
@@ -140,7 +139,7 @@ class IfToStim(IfElseSimplification, RewriteRule):
|
|
|
140
139
|
|
|
141
140
|
def rewrite_IfElse(self, stmt: scf.IfElse) -> RewriteResult:
|
|
142
141
|
|
|
143
|
-
if not isinstance(self.
|
|
142
|
+
if not isinstance(self.measure_frame.entries[stmt.cond], MeasureIdBool):
|
|
144
143
|
return RewriteResult()
|
|
145
144
|
|
|
146
145
|
# check that there is only qubit.Apply in the then-body,
|
|
@@ -161,12 +160,12 @@ class IfToStim(IfElseSimplification, RewriteRule):
|
|
|
161
160
|
return RewriteResult()
|
|
162
161
|
|
|
163
162
|
# get necessary measurement ID type from analysis
|
|
164
|
-
measure_id_bool = self.
|
|
163
|
+
measure_id_bool = self.measure_frame.entries[stmt.cond]
|
|
165
164
|
assert isinstance(measure_id_bool, MeasureIdBool)
|
|
166
165
|
|
|
167
166
|
# generate get record statement
|
|
168
167
|
measure_id_idx_stmt = py.Constant(
|
|
169
|
-
(measure_id_bool.idx - 1) - self.
|
|
168
|
+
(measure_id_bool.idx - 1) - self.measure_frame.num_measures_at_stmt[stmt]
|
|
170
169
|
)
|
|
171
170
|
get_record_stmt = GetRecord(id=measure_id_idx_stmt.result) # noqa: F841
|
|
172
171
|
|
|
@@ -2,47 +2,16 @@
|
|
|
2
2
|
from dataclasses import dataclass
|
|
3
3
|
|
|
4
4
|
from kirin import ir
|
|
5
|
-
from kirin.dialects import py
|
|
5
|
+
from kirin.dialects import py
|
|
6
6
|
from kirin.rewrite.abc import RewriteRule, RewriteResult
|
|
7
7
|
|
|
8
8
|
from bloqade.squin import wire, qubit
|
|
9
9
|
from bloqade.squin.rewrite import AddressAttribute
|
|
10
|
-
from bloqade.stim.dialects import collapse
|
|
10
|
+
from bloqade.stim.dialects import collapse
|
|
11
11
|
from bloqade.stim.rewrite.util import (
|
|
12
12
|
is_measure_result_used,
|
|
13
13
|
insert_qubit_idx_from_address,
|
|
14
14
|
)
|
|
15
|
-
from bloqade.analysis.measure_id.lattice import MeasureId, MeasureIdBool, MeasureIdTuple
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
def replace_get_record(
|
|
19
|
-
node: ir.Statement, measure_id_bool: MeasureIdBool, meas_count: int
|
|
20
|
-
):
|
|
21
|
-
assert isinstance(measure_id_bool, MeasureIdBool)
|
|
22
|
-
target_rec_idx = (measure_id_bool.idx - 1) - meas_count
|
|
23
|
-
idx_stmt = py.constant.Constant(target_rec_idx)
|
|
24
|
-
idx_stmt.insert_before(node)
|
|
25
|
-
get_record_stmt = auxiliary.GetRecord(idx_stmt.result)
|
|
26
|
-
node.replace_by(get_record_stmt)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
def insert_get_record_list(
|
|
30
|
-
node: ir.Statement, measure_id_tuple: MeasureIdTuple, meas_count: int
|
|
31
|
-
):
|
|
32
|
-
"""
|
|
33
|
-
Insert GetRecord statements before the given node
|
|
34
|
-
"""
|
|
35
|
-
get_record_ssas = []
|
|
36
|
-
for measure_id_bool in measure_id_tuple.data:
|
|
37
|
-
assert isinstance(measure_id_bool, MeasureIdBool)
|
|
38
|
-
target_rec_idx = (measure_id_bool.idx - 1) - meas_count
|
|
39
|
-
idx_stmt = py.constant.Constant(target_rec_idx)
|
|
40
|
-
idx_stmt.insert_before(node)
|
|
41
|
-
get_record_stmt = auxiliary.GetRecord(idx_stmt.result)
|
|
42
|
-
get_record_stmt.insert_before(node)
|
|
43
|
-
get_record_ssas.append(get_record_stmt.result)
|
|
44
|
-
|
|
45
|
-
node.replace_by(ilist.New(values=get_record_ssas))
|
|
46
15
|
|
|
47
16
|
|
|
48
17
|
@dataclass
|
|
@@ -51,9 +20,6 @@ class SquinMeasureToStim(RewriteRule):
|
|
|
51
20
|
Rewrite squin measure-related statements to stim statements.
|
|
52
21
|
"""
|
|
53
22
|
|
|
54
|
-
measure_id_result: dict[ir.SSAValue, MeasureId]
|
|
55
|
-
total_measure_count: int
|
|
56
|
-
|
|
57
23
|
def rewrite_Statement(self, node: ir.Statement) -> RewriteResult:
|
|
58
24
|
|
|
59
25
|
match node:
|
|
@@ -70,10 +36,6 @@ class SquinMeasureToStim(RewriteRule):
|
|
|
70
36
|
if qubit_idx_ssas is None:
|
|
71
37
|
return RewriteResult()
|
|
72
38
|
|
|
73
|
-
measure_id = self.measure_id_result[measure_stmt.result]
|
|
74
|
-
if not isinstance(measure_id, (MeasureIdBool, MeasureIdTuple)):
|
|
75
|
-
return RewriteResult()
|
|
76
|
-
|
|
77
39
|
prob_noise_stmt = py.constant.Constant(0.0)
|
|
78
40
|
stim_measure_stmt = collapse.MZ(
|
|
79
41
|
p=prob_noise_stmt.result,
|
|
@@ -84,27 +46,6 @@ class SquinMeasureToStim(RewriteRule):
|
|
|
84
46
|
|
|
85
47
|
if not is_measure_result_used(measure_stmt):
|
|
86
48
|
measure_stmt.delete()
|
|
87
|
-
return RewriteResult(has_done_something=True)
|
|
88
|
-
|
|
89
|
-
# replace dataflow with new stmt!
|
|
90
|
-
measure_id = self.measure_id_result[measure_stmt.result]
|
|
91
|
-
if isinstance(measure_id, MeasureIdBool):
|
|
92
|
-
replace_get_record(
|
|
93
|
-
node=measure_stmt,
|
|
94
|
-
measure_id_bool=measure_id,
|
|
95
|
-
meas_count=self.total_measure_count,
|
|
96
|
-
)
|
|
97
|
-
elif isinstance(measure_id, MeasureIdTuple):
|
|
98
|
-
insert_get_record_list(
|
|
99
|
-
node=measure_stmt,
|
|
100
|
-
measure_id_tuple=measure_id,
|
|
101
|
-
meas_count=self.total_measure_count,
|
|
102
|
-
)
|
|
103
|
-
else:
|
|
104
|
-
# already checked before, so this should not happen
|
|
105
|
-
raise ValueError(
|
|
106
|
-
f"Unexpected measure ID type: {type(measure_id)} for measure statement {measure_stmt}"
|
|
107
|
-
)
|
|
108
49
|
|
|
109
50
|
return RewriteResult(has_done_something=True)
|
|
110
51
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: bloqade-circuit
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.4
|
|
4
4
|
Summary: The software development toolkit for neutral atom arrays.
|
|
5
5
|
Author-email: Roger-luo <rluo@quera.com>, kaihsin <khwu@quera.com>, weinbe58 <pweinberg@quera.com>, johnzl-777 <jlong@quera.com>
|
|
6
6
|
License-File: LICENSE
|
|
@@ -9,9 +9,9 @@ bloqade/analysis/address/impls.py,sha256=cWdq1CNV6HVDECtIgl9ogUa8nvFZm_Sy5Wcfk1f
|
|
|
9
9
|
bloqade/analysis/address/lattice.py,sha256=dUq999feqPoBYkqEXe1hjHOn4TP_bkvKip8fyWQ-2-8,1755
|
|
10
10
|
bloqade/analysis/fidelity/__init__.py,sha256=iJkhoHvCMU9bKxQqgxIWKQWvpqNFRgNBI5DK8-4RAB8,59
|
|
11
11
|
bloqade/analysis/fidelity/analysis.py,sha256=G6JEYc8eeWJ9mwsbUAIzXuU2nrnTU4te41c04xE71gM,3218
|
|
12
|
-
bloqade/analysis/measure_id/__init__.py,sha256=
|
|
13
|
-
bloqade/analysis/measure_id/analysis.py,sha256=
|
|
14
|
-
bloqade/analysis/measure_id/impls.py,sha256=
|
|
12
|
+
bloqade/analysis/measure_id/__init__.py,sha256=r_R_br1e3H7ZzwkeQw4TnDAP4M_bUaRlRb7ZRdowvNI,145
|
|
13
|
+
bloqade/analysis/measure_id/analysis.py,sha256=F22mLWeOLH_QHm25_4DZLLse4ljsiZr7UNThaIy4pzA,2149
|
|
14
|
+
bloqade/analysis/measure_id/impls.py,sha256=ojFSQrrqj-jdcBklaLa3HHojHvw59Z7Dl2iNdfSuP1w,6376
|
|
15
15
|
bloqade/analysis/measure_id/lattice.py,sha256=WPrn0R79umCH909BFWsUJ64qx9n_3KYimIW5UaXNuGU,1891
|
|
16
16
|
bloqade/cirq_utils/__init__.py,sha256=1DRDCF3PpgJCOr0z7iULdrn3dqm7GLpRGs9AlqE7XA8,280
|
|
17
17
|
bloqade/cirq_utils/lineprog.py,sha256=JosrhfeOHI9FycUT_sYFj8TBzLpo97TL8zK-Ap2U4eQ,11021
|
|
@@ -23,7 +23,7 @@ bloqade/cirq_utils/noise/model.py,sha256=06Y_BLChOA-PhhAJcWLSgLVAAJoNjOrAujL1YCw
|
|
|
23
23
|
bloqade/cirq_utils/noise/transform.py,sha256=tvDt4WMLM8dKPME51y0_peSZk2-jKmjq0urOxm0lWuQ,2309
|
|
24
24
|
bloqade/pyqrack/__init__.py,sha256=lonTS-luJkTVujCCtgdZRC12V7FQdoFcozAI-byXwN0,810
|
|
25
25
|
bloqade/pyqrack/base.py,sha256=9z61PaaAFqCBBwkgsDZSr-qr9IQ5OJ_JUvltmJ7Bgls,4407
|
|
26
|
-
bloqade/pyqrack/device.py,sha256=
|
|
26
|
+
bloqade/pyqrack/device.py,sha256=40vduanEgA26GAW3buHoRpyqPA0xUt2tONY3w5JeH5s,7524
|
|
27
27
|
bloqade/pyqrack/reg.py,sha256=uTL07CT1R0xUsInLmwU9YuuNdV6lV0lCs1zhdUz1qIs,1660
|
|
28
28
|
bloqade/pyqrack/target.py,sha256=c78VtLWAiDNp_0sXwvVzhaEoeFsr1fUVsupxWuo6p3s,3661
|
|
29
29
|
bloqade/pyqrack/task.py,sha256=ydVso4wZQ1iIzgSBG0lDxClPTLcsZfkbnZk_1qFV95o,991
|
|
@@ -35,7 +35,7 @@ bloqade/pyqrack/qasm2/glob.py,sha256=EGe7sh9SuvpRW4V4rFcX6Gf7ot8iyThYbsdPeEBKzYM
|
|
|
35
35
|
bloqade/pyqrack/qasm2/parallel.py,sha256=ITetuXOH2KUDpDOBuFnJoz2DhduvyBC72cOAOOixTaM,1606
|
|
36
36
|
bloqade/pyqrack/qasm2/uop.py,sha256=bLZONsEK15ymFGIQwy7muQv-TX0mvLrECuMp1Y3XTfA,8612
|
|
37
37
|
bloqade/pyqrack/squin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
38
|
-
bloqade/pyqrack/squin/op.py,sha256=
|
|
38
|
+
bloqade/pyqrack/squin/op.py,sha256=m9QiQgQnKy1tYvrieU6MjXf_b9i2fovj4r2novcQwIc,5535
|
|
39
39
|
bloqade/pyqrack/squin/qubit.py,sha256=svQMbsLxv3yjiFMSRc4C7QGllzjtmlSWOsMY1mjTI8Q,2223
|
|
40
40
|
bloqade/pyqrack/squin/runtime.py,sha256=BM_xRoTpsRipL_Vt-N5UO-x2Nsgiafw3nwiqiuOeH68,15401
|
|
41
41
|
bloqade/pyqrack/squin/wire.py,sha256=rqlAeU-r_EHOwJMqHrEAxpZ_rKsvUpwGG7MP4BW75Nw,1658
|
|
@@ -139,7 +139,7 @@ bloqade/squin/analysis/nsites/__init__.py,sha256=RlQg7ivczXCXG5lMeL3ipYKj2oJKC4T
|
|
|
139
139
|
bloqade/squin/analysis/nsites/analysis.py,sha256=rIe1RU1MZRItcE2aB8DYahLrv73HfD3IHCX3E_EGQ1c,1773
|
|
140
140
|
bloqade/squin/analysis/nsites/impls.py,sha256=bVqO4E2hDzfYWwSG0pfj2j8oT1m0C3b42LdSHr4HQlo,2874
|
|
141
141
|
bloqade/squin/analysis/nsites/lattice.py,sha256=ruh0808SHtj3ecuT-C3AZTsLY2j3DRhtezGiTZvcuVs,942
|
|
142
|
-
bloqade/squin/cirq/__init__.py,sha256=
|
|
142
|
+
bloqade/squin/cirq/__init__.py,sha256=qGTrEzDEHqIMOh031y23-Y1NsyKew3QCrBYD9P_i63E,9236
|
|
143
143
|
bloqade/squin/cirq/lowering.py,sha256=F0_skv9lORxUFrhbNaN2ZQpqGnhPyslHt5E92uta5BQ,17959
|
|
144
144
|
bloqade/squin/cirq/emit/emit_circuit.py,sha256=7puJ3eCFwE9VdPb9NAiSdyRNkoQPwo_uVykz9Yv7c14,3761
|
|
145
145
|
bloqade/squin/cirq/emit/noise.py,sha256=rESjGC_66s2Y4FwwYda4rY3mYHYjbqLlKE_vnqpZDYI,1534
|
|
@@ -203,14 +203,14 @@ bloqade/stim/emit/__init__.py,sha256=N2dPQY7OyqPwHAStDeOgYg2yfxqxMOz-N7pD5Z4JwlI
|
|
|
203
203
|
bloqade/stim/emit/stim_str.py,sha256=JyEBoIhLQASogZcUWHI9tMD4JoXYrEqUr2qaZ30gZdc,1491
|
|
204
204
|
bloqade/stim/parse/__init__.py,sha256=l2DjReB2KkgrDjP_4nP6RnoziiOewoSeZfTno1sVYTw,59
|
|
205
205
|
bloqade/stim/parse/lowering.py,sha256=L-IcR_exlxsTVv4SQ0bhzIF4_L82P-GEdK6qRd6B86Y,23723
|
|
206
|
-
bloqade/stim/passes/__init__.py,sha256=
|
|
207
|
-
bloqade/stim/passes/simplify_ifs.py,sha256=
|
|
208
|
-
bloqade/stim/passes/squin_to_stim.py,sha256=
|
|
209
|
-
bloqade/stim/rewrite/__init__.py,sha256=
|
|
210
|
-
bloqade/stim/rewrite/ifs_to_stim.py,sha256=
|
|
206
|
+
bloqade/stim/passes/__init__.py,sha256=aysjOZyn0IrJQCQBEqiz8pwZ5u5t2s9TmEzA9Y9KG9w,167
|
|
207
|
+
bloqade/stim/passes/simplify_ifs.py,sha256=zicqggWu_yzfrf2a7uUCt-ZenbYSEnFsyGxDfKw72qQ,1084
|
|
208
|
+
bloqade/stim/passes/squin_to_stim.py,sha256=6TpnpvA6JA3dQyH6mxNpGn9-__sPlSmyUBIdThn9xVg,6018
|
|
209
|
+
bloqade/stim/rewrite/__init__.py,sha256=zL5G73JEsXkehN7gCtUgGnmC2BJ3vKihOd1ohVwM68E,480
|
|
210
|
+
bloqade/stim/rewrite/ifs_to_stim.py,sha256=jmCb6AwNqGXWuLR8BkAYIVvAlOptQzVPHWv52_v-Vsw,6755
|
|
211
211
|
bloqade/stim/rewrite/py_constant_to_stim.py,sha256=PV8bHvn759-d_0JW4akaGSORW_oxigrlUBhAC51PJAU,1354
|
|
212
212
|
bloqade/stim/rewrite/qubit_to_stim.py,sha256=oiKmi8BlBwXJq-8kGhN1nXgyxJ2UIt_9uouNkU1J8vs,2624
|
|
213
|
-
bloqade/stim/rewrite/squin_measure.py,sha256=
|
|
213
|
+
bloqade/stim/rewrite/squin_measure.py,sha256=1zuILosGACN7rPYA87MYVwv0M4pPTala1YTe9owbhkw,2519
|
|
214
214
|
bloqade/stim/rewrite/squin_noise.py,sha256=NafmAiByT4Y5895fZM4Od8arKjsJuW6F5wvRpAFFo70,6240
|
|
215
215
|
bloqade/stim/rewrite/util.py,sha256=xnLDiEj45CBoG3mpG-ywE1Jjh1k_OVP4iI1A75VR6sw,7257
|
|
216
216
|
bloqade/stim/rewrite/wire_identity_elimination.py,sha256=Cscu8yaSslPuW04HvbXx4HJ3JzdUZNUMyFqcvuc4sxY,795
|
|
@@ -228,7 +228,7 @@ bloqade/visual/animation/runtime/atoms.py,sha256=EmjxhujLiHHPS_HtH_B-7TiqeHgvW5u
|
|
|
228
228
|
bloqade/visual/animation/runtime/ppoly.py,sha256=JB9IP53N1w6adBJEue6J5Nmj818Id9JvrlgrmiQTU1I,1385
|
|
229
229
|
bloqade/visual/animation/runtime/qpustate.py,sha256=rlmxQeJSvaohXrTpXQL5y-NJcpvfW33xPaYM1slv7cc,4270
|
|
230
230
|
bloqade/visual/animation/runtime/utils.py,sha256=ju9IzOWX-vKwfpqUjlUKu3Ssr_UFPFFq-tzH_Nqyo_c,1212
|
|
231
|
-
bloqade_circuit-0.6.
|
|
232
|
-
bloqade_circuit-0.6.
|
|
233
|
-
bloqade_circuit-0.6.
|
|
234
|
-
bloqade_circuit-0.6.
|
|
231
|
+
bloqade_circuit-0.6.4.dist-info/METADATA,sha256=DXODLKpcteMafxszRYcrC1WliONCL2gKY-9F-g4WftQ,3849
|
|
232
|
+
bloqade_circuit-0.6.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
233
|
+
bloqade_circuit-0.6.4.dist-info/licenses/LICENSE,sha256=S5GIJwR6QCixPA9wryYb44ZEek0Nz4rt_zLUqP05UbU,13160
|
|
234
|
+
bloqade_circuit-0.6.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|