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
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
from kirin import ir
|
|
2
2
|
from kirin.rewrite.abc import RewriteRule, RewriteResult
|
|
3
3
|
|
|
4
|
-
from bloqade
|
|
4
|
+
from bloqade import qubit
|
|
5
|
+
from bloqade.squin import gate
|
|
5
6
|
from bloqade.squin.rewrite import AddressAttribute
|
|
6
|
-
from bloqade.stim.dialects import gate
|
|
7
|
+
from bloqade.stim.dialects import gate as stim_gate, collapse as stim_collapse
|
|
7
8
|
from bloqade.stim.rewrite.util import (
|
|
8
|
-
SQUIN_STIM_OP_MAPPING,
|
|
9
|
-
rewrite_Control,
|
|
10
|
-
rewrite_QubitLoss,
|
|
11
9
|
insert_qubit_idx_from_address,
|
|
12
10
|
)
|
|
13
11
|
|
|
@@ -20,64 +18,115 @@ class SquinQubitToStim(RewriteRule):
|
|
|
20
18
|
def rewrite_Statement(self, node: ir.Statement) -> RewriteResult:
|
|
21
19
|
|
|
22
20
|
match node:
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
# not supported by Stim
|
|
22
|
+
case gate.stmts.T() | gate.stmts.RotationGate():
|
|
23
|
+
return RewriteResult()
|
|
24
|
+
# If you've reached this point all gates have stim equivalents
|
|
25
|
+
case qubit.stmts.Reset():
|
|
26
|
+
return self.rewrite_Reset(node)
|
|
27
|
+
case gate.stmts.SingleQubitGate():
|
|
28
|
+
return self.rewrite_SingleQubitGate(node)
|
|
29
|
+
case gate.stmts.ControlledGate():
|
|
30
|
+
return self.rewrite_ControlledGate(node)
|
|
25
31
|
case _:
|
|
26
32
|
return RewriteResult()
|
|
27
33
|
|
|
28
|
-
def
|
|
29
|
-
self, stmt: qubit.Apply | qubit.Broadcast
|
|
30
|
-
) -> RewriteResult:
|
|
31
|
-
"""
|
|
32
|
-
Rewrite Apply and Broadcast nodes to their stim equivalent statements.
|
|
33
|
-
"""
|
|
34
|
-
|
|
35
|
-
# this is an SSAValue, need it to be the actual operator
|
|
36
|
-
applied_op = stmt.operator.owner
|
|
34
|
+
def rewrite_Reset(self, stmt: qubit.stmts.Reset) -> RewriteResult:
|
|
37
35
|
|
|
38
|
-
|
|
39
|
-
return rewrite_QubitLoss(stmt)
|
|
36
|
+
qubit_addr_attr = stmt.qubits.hints.get("address", None)
|
|
40
37
|
|
|
41
|
-
|
|
38
|
+
if qubit_addr_attr is None:
|
|
39
|
+
return RewriteResult()
|
|
42
40
|
|
|
43
|
-
|
|
44
|
-
return rewrite_Control(stmt)
|
|
41
|
+
assert isinstance(qubit_addr_attr, AddressAttribute)
|
|
45
42
|
|
|
46
|
-
|
|
43
|
+
qubit_idx_ssas = insert_qubit_idx_from_address(
|
|
44
|
+
address=qubit_addr_attr, stmt_to_insert_before=stmt
|
|
45
|
+
)
|
|
47
46
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
if isinstance(applied_op, op.stmts.Adjoint):
|
|
51
|
-
if not applied_op.is_unitary:
|
|
52
|
-
return RewriteResult()
|
|
47
|
+
if qubit_idx_ssas is None:
|
|
48
|
+
return RewriteResult()
|
|
53
49
|
|
|
54
|
-
|
|
55
|
-
|
|
50
|
+
stim_stmt = stim_collapse.RZ(targets=tuple(qubit_idx_ssas))
|
|
51
|
+
stmt.replace_by(stim_stmt)
|
|
56
52
|
|
|
57
|
-
|
|
58
|
-
if stim_1q_op is None:
|
|
59
|
-
return RewriteResult()
|
|
53
|
+
return RewriteResult(has_done_something=True)
|
|
60
54
|
|
|
61
|
-
|
|
55
|
+
def rewrite_SingleQubitGate(
|
|
56
|
+
self, stmt: gate.stmts.SingleQubitGate
|
|
57
|
+
) -> RewriteResult:
|
|
58
|
+
"""
|
|
59
|
+
Rewrite single qubit gate nodes to their stim equivalent statements.
|
|
60
|
+
Address Analysis should have been run along with Wrap Analysis before this rewrite is applied.
|
|
61
|
+
"""
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
qubit_addr_attr = stmt.qubits.hints.get("address", None)
|
|
64
|
+
if qubit_addr_attr is None:
|
|
64
65
|
return RewriteResult()
|
|
65
66
|
|
|
66
|
-
assert isinstance(
|
|
67
|
+
assert isinstance(qubit_addr_attr, AddressAttribute)
|
|
68
|
+
|
|
67
69
|
qubit_idx_ssas = insert_qubit_idx_from_address(
|
|
68
|
-
address=
|
|
70
|
+
address=qubit_addr_attr, stmt_to_insert_before=stmt
|
|
69
71
|
)
|
|
70
72
|
|
|
71
73
|
if qubit_idx_ssas is None:
|
|
72
74
|
return RewriteResult()
|
|
73
75
|
|
|
74
|
-
if
|
|
75
|
-
|
|
76
|
+
# Get the name of the inputted stmt and see if there is an
|
|
77
|
+
# equivalently named statement in stim,
|
|
78
|
+
# then create an instance of that stim statement
|
|
79
|
+
stmt_name = type(stmt).__name__
|
|
80
|
+
stim_stmt_cls = getattr(stim_gate.stmts, stmt_name, None)
|
|
81
|
+
if stim_stmt_cls is None:
|
|
82
|
+
return RewriteResult()
|
|
83
|
+
|
|
84
|
+
if isinstance(stmt, gate.stmts.SingleQubitNonHermitianGate):
|
|
85
|
+
stim_stmt = stim_stmt_cls(
|
|
86
|
+
targets=tuple(qubit_idx_ssas), dagger=stmt.adjoint
|
|
87
|
+
)
|
|
76
88
|
else:
|
|
77
|
-
|
|
78
|
-
stmt.replace_by(
|
|
89
|
+
stim_stmt = stim_stmt_cls(targets=tuple(qubit_idx_ssas))
|
|
90
|
+
stmt.replace_by(stim_stmt)
|
|
79
91
|
|
|
80
92
|
return RewriteResult(has_done_something=True)
|
|
81
93
|
|
|
94
|
+
def rewrite_ControlledGate(self, stmt: gate.stmts.ControlledGate) -> RewriteResult:
|
|
95
|
+
"""
|
|
96
|
+
Rewrite controlled gate nodes to their stim equivalent statements.
|
|
97
|
+
Address Analysis should have been run along with Wrap Analysis before this rewrite is applied.
|
|
98
|
+
"""
|
|
82
99
|
|
|
83
|
-
|
|
100
|
+
controls_addr_attr = stmt.controls.hints.get("address", None)
|
|
101
|
+
targets_addr_attr = stmt.targets.hints.get("address", None)
|
|
102
|
+
|
|
103
|
+
if controls_addr_attr is None or targets_addr_attr is None:
|
|
104
|
+
return RewriteResult()
|
|
105
|
+
|
|
106
|
+
assert isinstance(controls_addr_attr, AddressAttribute)
|
|
107
|
+
assert isinstance(targets_addr_attr, AddressAttribute)
|
|
108
|
+
|
|
109
|
+
controls_idx_ssas = insert_qubit_idx_from_address(
|
|
110
|
+
address=controls_addr_attr, stmt_to_insert_before=stmt
|
|
111
|
+
)
|
|
112
|
+
targets_idx_ssas = insert_qubit_idx_from_address(
|
|
113
|
+
address=targets_addr_attr, stmt_to_insert_before=stmt
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
if controls_idx_ssas is None or targets_idx_ssas is None:
|
|
117
|
+
return RewriteResult()
|
|
118
|
+
|
|
119
|
+
# Get the name of the inputted stmt and see if there is an
|
|
120
|
+
# equivalently named statement in stim,
|
|
121
|
+
# then create an instance of that stim statement
|
|
122
|
+
stmt_name = type(stmt).__name__
|
|
123
|
+
stim_stmt_cls = getattr(stim_gate.stmts, stmt_name, None)
|
|
124
|
+
if stim_stmt_cls is None:
|
|
125
|
+
return RewriteResult()
|
|
126
|
+
|
|
127
|
+
stim_stmt = stim_stmt_cls(
|
|
128
|
+
targets=tuple(targets_idx_ssas), controls=tuple(controls_idx_ssas)
|
|
129
|
+
)
|
|
130
|
+
stmt.replace_by(stim_stmt)
|
|
131
|
+
|
|
132
|
+
return RewriteResult(has_done_something=True)
|
|
@@ -5,11 +5,10 @@ from kirin import ir
|
|
|
5
5
|
from kirin.dialects import py
|
|
6
6
|
from kirin.rewrite.abc import RewriteRule, RewriteResult
|
|
7
7
|
|
|
8
|
-
from bloqade
|
|
8
|
+
from bloqade import qubit
|
|
9
9
|
from bloqade.squin.rewrite import AddressAttribute
|
|
10
10
|
from bloqade.stim.dialects import collapse
|
|
11
11
|
from bloqade.stim.rewrite.util import (
|
|
12
|
-
is_measure_result_used,
|
|
13
12
|
insert_qubit_idx_from_address,
|
|
14
13
|
)
|
|
15
14
|
|
|
@@ -23,14 +22,12 @@ class SquinMeasureToStim(RewriteRule):
|
|
|
23
22
|
def rewrite_Statement(self, node: ir.Statement) -> RewriteResult:
|
|
24
23
|
|
|
25
24
|
match node:
|
|
26
|
-
case qubit.
|
|
25
|
+
case qubit.stmts.Measure():
|
|
27
26
|
return self.rewrite_Measure(node)
|
|
28
27
|
case _:
|
|
29
28
|
return RewriteResult()
|
|
30
29
|
|
|
31
|
-
def rewrite_Measure(
|
|
32
|
-
self, measure_stmt: qubit.MeasureQubit | qubit.MeasureQubitList | wire.Measure
|
|
33
|
-
) -> RewriteResult:
|
|
30
|
+
def rewrite_Measure(self, measure_stmt: qubit.stmts.Measure) -> RewriteResult:
|
|
34
31
|
|
|
35
32
|
qubit_idx_ssas = self.get_qubit_idx_ssas(measure_stmt)
|
|
36
33
|
if qubit_idx_ssas is None:
|
|
@@ -44,27 +41,21 @@ class SquinMeasureToStim(RewriteRule):
|
|
|
44
41
|
prob_noise_stmt.insert_before(measure_stmt)
|
|
45
42
|
stim_measure_stmt.insert_before(measure_stmt)
|
|
46
43
|
|
|
47
|
-
if not
|
|
44
|
+
# if the measurement is not being used anywhere
|
|
45
|
+
# we can safely get rid of it. Measure cannot be DCE'd because
|
|
46
|
+
# it is not pure.
|
|
47
|
+
if not bool(measure_stmt.result.uses):
|
|
48
48
|
measure_stmt.delete()
|
|
49
49
|
|
|
50
50
|
return RewriteResult(has_done_something=True)
|
|
51
51
|
|
|
52
52
|
def get_qubit_idx_ssas(
|
|
53
|
-
self, measure_stmt: qubit.
|
|
53
|
+
self, measure_stmt: qubit.stmts.Measure
|
|
54
54
|
) -> tuple[ir.SSAValue, ...] | None:
|
|
55
55
|
"""
|
|
56
56
|
Extract the address attribute and insert qubit indices for the given measure statement.
|
|
57
57
|
"""
|
|
58
|
-
|
|
59
|
-
case qubit.MeasureQubit():
|
|
60
|
-
address_attr = measure_stmt.qubit.hints.get("address")
|
|
61
|
-
case qubit.MeasureQubitList():
|
|
62
|
-
address_attr = measure_stmt.qubits.hints.get("address")
|
|
63
|
-
case wire.Measure():
|
|
64
|
-
address_attr = measure_stmt.wire.hints.get("address")
|
|
65
|
-
case _:
|
|
66
|
-
return None
|
|
67
|
-
|
|
58
|
+
address_attr = measure_stmt.qubits.hints.get("address")
|
|
68
59
|
if address_attr is None:
|
|
69
60
|
return None
|
|
70
61
|
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
+
import itertools
|
|
1
2
|
from typing import Tuple
|
|
2
3
|
from dataclasses import dataclass
|
|
3
4
|
|
|
5
|
+
from kirin import types
|
|
4
6
|
from kirin.ir import SSAValue, Statement
|
|
5
|
-
from kirin.dialects import py
|
|
7
|
+
from kirin.dialects import py
|
|
6
8
|
from kirin.rewrite.abc import RewriteRule, RewriteResult
|
|
7
9
|
|
|
8
|
-
from bloqade.squin import
|
|
10
|
+
from bloqade.squin import noise as squin_noise
|
|
9
11
|
from bloqade.stim.dialects import noise as stim_noise
|
|
10
|
-
from bloqade.stim.rewrite.util import
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
insert_qubit_idx_after_apply,
|
|
14
|
-
)
|
|
12
|
+
from bloqade.stim.rewrite.util import insert_qubit_idx_from_address
|
|
13
|
+
from bloqade.analysis.address.lattice import AddressReg, PartialIList
|
|
14
|
+
from bloqade.squin.rewrite.wrap_analysis import AddressAttribute
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
@dataclass
|
|
@@ -19,159 +19,183 @@ class SquinNoiseToStim(RewriteRule):
|
|
|
19
19
|
|
|
20
20
|
def rewrite_Statement(self, node: Statement) -> RewriteResult:
|
|
21
21
|
match node:
|
|
22
|
-
case
|
|
23
|
-
return self.
|
|
22
|
+
case squin_noise.stmts.NoiseChannel():
|
|
23
|
+
return self.rewrite_NoiseChannel(node)
|
|
24
24
|
case _:
|
|
25
25
|
return RewriteResult()
|
|
26
26
|
|
|
27
|
-
def
|
|
28
|
-
self, stmt:
|
|
27
|
+
def rewrite_NoiseChannel(
|
|
28
|
+
self, stmt: squin_noise.stmts.NoiseChannel
|
|
29
29
|
) -> RewriteResult:
|
|
30
|
-
"""Rewrite
|
|
30
|
+
"""Rewrite NoiseChannel statements to their stim equivalents."""
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
applied_op = stmt.operator.owner
|
|
32
|
+
rewrite_method = getattr(self, f"rewrite_{type(stmt).__name__}", None)
|
|
34
33
|
|
|
35
|
-
|
|
34
|
+
# No rewrite method exists and the rewrite should stop
|
|
35
|
+
if rewrite_method is None:
|
|
36
36
|
return RewriteResult()
|
|
37
|
+
if isinstance(stmt, squin_noise.stmts.CorrelatedQubitLoss):
|
|
38
|
+
# CorrelatedQubitLoss represents a broadcast operation, but Stim does not
|
|
39
|
+
# support broadcasting for multi-qubit noise channels.
|
|
40
|
+
# Therefore, we must expand the broadcast into individual stim statements.
|
|
41
|
+
qubit_address_attr = stmt.qubits.hints.get("address", None)
|
|
37
42
|
|
|
38
|
-
|
|
43
|
+
if not isinstance(qubit_address_attr, AddressAttribute):
|
|
44
|
+
return RewriteResult()
|
|
39
45
|
|
|
40
|
-
|
|
41
|
-
# No rewrite method exists and the rewrite should stop
|
|
42
|
-
if rewrite_method is None:
|
|
46
|
+
if not isinstance(address := qubit_address_attr.address, PartialIList):
|
|
43
47
|
return RewriteResult()
|
|
44
48
|
|
|
45
|
-
|
|
46
|
-
if qubit_idx_ssas is None:
|
|
49
|
+
if not types.is_tuple_of(data := address.data, AddressReg):
|
|
47
50
|
return RewriteResult()
|
|
48
51
|
|
|
49
|
-
|
|
52
|
+
for address_reg in data:
|
|
53
|
+
|
|
54
|
+
qubit_idx_ssas = insert_qubit_idx_from_address(
|
|
55
|
+
AddressAttribute(address_reg), stmt
|
|
56
|
+
)
|
|
50
57
|
|
|
51
|
-
|
|
52
|
-
|
|
58
|
+
stim_stmt = rewrite_method(stmt, qubit_idx_ssas)
|
|
59
|
+
stim_stmt.insert_before(stmt)
|
|
53
60
|
|
|
54
|
-
|
|
55
|
-
stmt.replace_by(stim_stmt)
|
|
61
|
+
stmt.delete()
|
|
56
62
|
|
|
57
63
|
return RewriteResult(has_done_something=True)
|
|
58
|
-
return RewriteResult()
|
|
59
64
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
65
|
+
if isinstance(stmt, squin_noise.stmts.SingleQubitNoiseChannel):
|
|
66
|
+
qubit_address_attr = stmt.qubits.hints.get("address", None)
|
|
67
|
+
if qubit_address_attr is None:
|
|
68
|
+
return RewriteResult()
|
|
69
|
+
qubit_idx_ssas = insert_qubit_idx_from_address(qubit_address_attr, stmt)
|
|
70
|
+
|
|
71
|
+
elif isinstance(stmt, squin_noise.stmts.TwoQubitNoiseChannel):
|
|
72
|
+
control_address_attr = stmt.controls.hints.get("address", None)
|
|
73
|
+
target_address_attr = stmt.targets.hints.get("address", None)
|
|
74
|
+
if control_address_attr is None or target_address_attr is None:
|
|
75
|
+
return RewriteResult()
|
|
76
|
+
control_qubit_idx_ssas = insert_qubit_idx_from_address(
|
|
77
|
+
control_address_attr, stmt
|
|
78
|
+
)
|
|
79
|
+
target_qubit_idx_ssas = insert_qubit_idx_from_address(
|
|
80
|
+
target_address_attr, stmt
|
|
81
|
+
)
|
|
82
|
+
if control_qubit_idx_ssas is None or target_qubit_idx_ssas is None:
|
|
83
|
+
return RewriteResult()
|
|
84
|
+
|
|
85
|
+
# For stim statements you want to interleave the control and target qubit indices:
|
|
86
|
+
# ex: CX controls = (0,1) targets = (2,3) in stim is: CX 0 2 1 3
|
|
87
|
+
qubit_idx_ssas = list(
|
|
88
|
+
itertools.chain.from_iterable(
|
|
89
|
+
zip(control_qubit_idx_ssas, target_qubit_idx_ssas)
|
|
90
|
+
)
|
|
91
|
+
)
|
|
79
92
|
else:
|
|
80
|
-
|
|
81
|
-
|
|
93
|
+
return RewriteResult()
|
|
94
|
+
|
|
95
|
+
# guaranteed that you have a valid stim_stmt to plug in
|
|
96
|
+
stim_stmt = rewrite_method(stmt, tuple(qubit_idx_ssas))
|
|
97
|
+
stmt.replace_by(stim_stmt)
|
|
98
|
+
|
|
99
|
+
return RewriteResult(has_done_something=True)
|
|
82
100
|
|
|
83
101
|
def rewrite_SingleQubitPauliChannel(
|
|
84
102
|
self,
|
|
85
|
-
stmt:
|
|
103
|
+
stmt: squin_noise.stmts.SingleQubitPauliChannel,
|
|
86
104
|
qubit_idx_ssas: Tuple[SSAValue],
|
|
87
105
|
) -> Statement:
|
|
88
106
|
"""Rewrite squin.noise.SingleQubitPauliChannel to stim.PauliChannel1."""
|
|
89
107
|
|
|
90
|
-
squin_channel = stmt.operator.owner
|
|
91
|
-
assert isinstance(squin_channel, squin_noise.stmts.SingleQubitPauliChannel)
|
|
92
|
-
|
|
93
|
-
params = get_const_value(ilist.IList, squin_channel.params)
|
|
94
|
-
new_stmts = [
|
|
95
|
-
p_x := py.Constant(params[0]),
|
|
96
|
-
p_y := py.Constant(params[1]),
|
|
97
|
-
p_z := py.Constant(params[2]),
|
|
98
|
-
]
|
|
99
|
-
for new_stmt in new_stmts:
|
|
100
|
-
new_stmt.insert_before(stmt)
|
|
101
|
-
|
|
102
108
|
stim_stmt = stim_noise.PauliChannel1(
|
|
103
109
|
targets=qubit_idx_ssas,
|
|
104
|
-
px=
|
|
105
|
-
py=
|
|
106
|
-
pz=
|
|
110
|
+
px=stmt.px,
|
|
111
|
+
py=stmt.py,
|
|
112
|
+
pz=stmt.pz,
|
|
107
113
|
)
|
|
108
114
|
return stim_stmt
|
|
109
115
|
|
|
110
|
-
def
|
|
116
|
+
def rewrite_QubitLoss(
|
|
111
117
|
self,
|
|
112
|
-
stmt:
|
|
118
|
+
stmt: squin_noise.stmts.QubitLoss,
|
|
113
119
|
qubit_idx_ssas: Tuple[SSAValue],
|
|
114
120
|
) -> Statement:
|
|
115
|
-
"""Rewrite squin.noise.
|
|
121
|
+
"""Rewrite squin.noise.QubitLoss to stim.TrivialError."""
|
|
116
122
|
|
|
117
|
-
|
|
118
|
-
|
|
123
|
+
stim_stmt = stim_noise.QubitLoss(
|
|
124
|
+
targets=qubit_idx_ssas,
|
|
125
|
+
probs=(stmt.p,),
|
|
126
|
+
)
|
|
119
127
|
|
|
120
|
-
|
|
121
|
-
param_stmts = [py.Constant(p) for p in params]
|
|
122
|
-
for param_stmt in param_stmts:
|
|
123
|
-
param_stmt.insert_before(stmt)
|
|
128
|
+
return stim_stmt
|
|
124
129
|
|
|
125
|
-
|
|
130
|
+
def rewrite_CorrelatedQubitLoss(
|
|
131
|
+
self,
|
|
132
|
+
stmt: squin_noise.stmts.CorrelatedQubitLoss,
|
|
133
|
+
qubit_idx_ssas: Tuple[SSAValue],
|
|
134
|
+
) -> Statement:
|
|
135
|
+
"""Rewrite squin.noise.CorrelatedQubitLoss to stim.CorrelatedQubitLoss."""
|
|
136
|
+
stim_stmt = stim_noise.CorrelatedQubitLoss(
|
|
126
137
|
targets=qubit_idx_ssas,
|
|
127
|
-
|
|
128
|
-
piy=param_stmts[1].result,
|
|
129
|
-
piz=param_stmts[2].result,
|
|
130
|
-
pxi=param_stmts[3].result,
|
|
131
|
-
pxx=param_stmts[4].result,
|
|
132
|
-
pxy=param_stmts[5].result,
|
|
133
|
-
pxz=param_stmts[6].result,
|
|
134
|
-
pyi=param_stmts[7].result,
|
|
135
|
-
pyx=param_stmts[8].result,
|
|
136
|
-
pyy=param_stmts[9].result,
|
|
137
|
-
pyz=param_stmts[10].result,
|
|
138
|
-
pzi=param_stmts[11].result,
|
|
139
|
-
pzx=param_stmts[12].result,
|
|
140
|
-
pzy=param_stmts[13].result,
|
|
141
|
-
pzz=param_stmts[14].result,
|
|
138
|
+
probs=(stmt.p,),
|
|
142
139
|
)
|
|
140
|
+
|
|
143
141
|
return stim_stmt
|
|
144
142
|
|
|
145
|
-
def
|
|
143
|
+
def rewrite_Depolarize(
|
|
146
144
|
self,
|
|
147
|
-
stmt:
|
|
145
|
+
stmt: squin_noise.stmts.Depolarize,
|
|
148
146
|
qubit_idx_ssas: Tuple[SSAValue],
|
|
149
147
|
) -> Statement:
|
|
150
|
-
"""Rewrite squin.noise.
|
|
151
|
-
|
|
152
|
-
squin_channel = stmt.operator.owner
|
|
153
|
-
assert isinstance(squin_channel, squin_noise.stmts.Depolarize2)
|
|
148
|
+
"""Rewrite squin.noise.Depolarize to stim.Depolarize1."""
|
|
154
149
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
150
|
+
stim_stmt = stim_noise.Depolarize1(
|
|
151
|
+
targets=qubit_idx_ssas,
|
|
152
|
+
p=stmt.p,
|
|
153
|
+
)
|
|
158
154
|
|
|
159
|
-
stim_stmt = stim_noise.Depolarize2(targets=qubit_idx_ssas, p=p_stmt.result)
|
|
160
155
|
return stim_stmt
|
|
161
156
|
|
|
162
|
-
def
|
|
157
|
+
def rewrite_TwoQubitPauliChannel(
|
|
163
158
|
self,
|
|
164
|
-
stmt:
|
|
159
|
+
stmt: squin_noise.stmts.TwoQubitPauliChannel,
|
|
165
160
|
qubit_idx_ssas: Tuple[SSAValue],
|
|
166
161
|
) -> Statement:
|
|
167
|
-
"""Rewrite squin.noise.
|
|
162
|
+
"""Rewrite squin.noise.TwoQubitPauliChannel to stim.PauliChannel2."""
|
|
163
|
+
|
|
164
|
+
params = stmt.probabilities
|
|
165
|
+
prob_ssas = []
|
|
166
|
+
for idx in range(15):
|
|
167
|
+
idx_stmt = py.Constant(value=idx)
|
|
168
|
+
idx_stmt.insert_before(stmt)
|
|
169
|
+
getitem_stmt = py.GetItem(obj=params, index=idx_stmt.result)
|
|
170
|
+
getitem_stmt.insert_before(stmt)
|
|
171
|
+
prob_ssas.append(getitem_stmt.result)
|
|
168
172
|
|
|
169
|
-
|
|
170
|
-
|
|
173
|
+
stim_stmt = stim_noise.PauliChannel2(
|
|
174
|
+
targets=qubit_idx_ssas,
|
|
175
|
+
pix=prob_ssas[0],
|
|
176
|
+
piy=prob_ssas[1],
|
|
177
|
+
piz=prob_ssas[2],
|
|
178
|
+
pxi=prob_ssas[3],
|
|
179
|
+
pxx=prob_ssas[4],
|
|
180
|
+
pxy=prob_ssas[5],
|
|
181
|
+
pxz=prob_ssas[6],
|
|
182
|
+
pyi=prob_ssas[7],
|
|
183
|
+
pyx=prob_ssas[8],
|
|
184
|
+
pyy=prob_ssas[9],
|
|
185
|
+
pyz=prob_ssas[10],
|
|
186
|
+
pzi=prob_ssas[11],
|
|
187
|
+
pzx=prob_ssas[12],
|
|
188
|
+
pzy=prob_ssas[13],
|
|
189
|
+
pzz=prob_ssas[14],
|
|
190
|
+
)
|
|
191
|
+
return stim_stmt
|
|
171
192
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
193
|
+
def rewrite_Depolarize2(
|
|
194
|
+
self,
|
|
195
|
+
stmt: squin_noise.stmts.Depolarize2,
|
|
196
|
+
qubit_idx_ssas: Tuple[SSAValue],
|
|
197
|
+
) -> Statement:
|
|
198
|
+
"""Rewrite squin.noise.Depolarize2 to stim.Depolarize2."""
|
|
175
199
|
|
|
176
|
-
stim_stmt = stim_noise.
|
|
200
|
+
stim_stmt = stim_noise.Depolarize2(targets=qubit_idx_ssas, p=stmt.p)
|
|
177
201
|
return stim_stmt
|