bloqade-circuit 0.3.0__py3-none-any.whl → 0.4.1__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/address/impls.py +3 -16
- bloqade/pyqrack/__init__.py +1 -1
- bloqade/pyqrack/noise/native.py +8 -8
- bloqade/pyqrack/squin/noise/__init__.py +1 -0
- bloqade/pyqrack/squin/noise/native.py +72 -0
- bloqade/pyqrack/squin/op.py +7 -0
- bloqade/pyqrack/squin/qubit.py +0 -29
- bloqade/pyqrack/squin/runtime.py +18 -0
- bloqade/pyqrack/squin/wire.py +0 -36
- bloqade/{noise/native → qasm2/dialects/noise}/__init__.py +1 -7
- bloqade/qasm2/dialects/noise/_dialect.py +3 -0
- bloqade/{noise → qasm2/dialects/noise}/fidelity.py +2 -2
- bloqade/qasm2/dialects/noise/model.py +278 -0
- bloqade/qasm2/emit/impls/__init__.py +1 -1
- bloqade/qasm2/emit/impls/{noise_native.py → noise.py} +11 -11
- bloqade/qasm2/emit/main.py +2 -4
- bloqade/qasm2/emit/target.py +3 -3
- bloqade/qasm2/groups.py +0 -2
- bloqade/{noise/native/_wrappers.py → qasm2/noise.py} +9 -5
- bloqade/qasm2/passes/glob.py +12 -8
- bloqade/qasm2/passes/noise.py +5 -14
- bloqade/qasm2/rewrite/__init__.py +2 -0
- bloqade/qasm2/rewrite/noise/__init__.py +0 -0
- bloqade/qasm2/rewrite/{heuristic_noise.py → noise/heuristic_noise.py} +31 -53
- bloqade/{noise/native/rewrite.py → qasm2/rewrite/noise/remove_noise.py} +2 -2
- bloqade/qbraid/lowering.py +8 -8
- bloqade/squin/__init__.py +16 -1
- bloqade/squin/analysis/nsites/impls.py +0 -9
- bloqade/squin/cirq/__init__.py +89 -0
- bloqade/squin/cirq/lowering.py +303 -0
- bloqade/squin/groups.py +7 -7
- bloqade/squin/lowering.py +27 -0
- bloqade/squin/noise/__init__.py +3 -1
- bloqade/squin/noise/_wrapper.py +7 -3
- bloqade/squin/noise/rewrite.py +111 -0
- bloqade/squin/noise/stmts.py +21 -16
- bloqade/squin/op/__init__.py +1 -0
- bloqade/squin/op/_wrapper.py +4 -0
- bloqade/squin/op/stmts.py +10 -11
- bloqade/squin/op/types.py +2 -0
- bloqade/squin/qubit.py +32 -37
- bloqade/squin/rewrite/desugar.py +65 -0
- bloqade/squin/rewrite/qubit_to_stim.py +0 -23
- bloqade/squin/rewrite/squin_measure.py +2 -27
- bloqade/squin/rewrite/stim_rewrite_util.py +3 -8
- bloqade/squin/rewrite/wire_to_stim.py +0 -21
- bloqade/squin/wire.py +4 -9
- bloqade/stim/__init__.py +2 -1
- bloqade/stim/_wrappers.py +4 -0
- bloqade/stim/dialects/auxiliary/__init__.py +1 -0
- bloqade/stim/dialects/auxiliary/emit.py +17 -2
- bloqade/stim/dialects/auxiliary/stmts/__init__.py +1 -0
- bloqade/stim/dialects/auxiliary/stmts/annotate.py +8 -0
- bloqade/stim/dialects/collapse/emit_str.py +3 -1
- bloqade/stim/dialects/gate/emit.py +9 -2
- bloqade/stim/dialects/noise/emit.py +32 -1
- bloqade/stim/dialects/noise/stmts.py +29 -0
- bloqade/stim/parse/__init__.py +1 -0
- bloqade/stim/parse/lowering.py +686 -0
- {bloqade_circuit-0.3.0.dist-info → bloqade_circuit-0.4.1.dist-info}/METADATA +3 -1
- {bloqade_circuit-0.3.0.dist-info → bloqade_circuit-0.4.1.dist-info}/RECORD +64 -57
- bloqade/noise/__init__.py +0 -2
- bloqade/noise/native/_dialect.py +0 -3
- bloqade/noise/native/model.py +0 -346
- bloqade/qasm2/dialects/noise.py +0 -48
- bloqade/squin/rewrite/measure_desugar.py +0 -33
- /bloqade/{noise/native → qasm2/dialects/noise}/stmts.py +0 -0
- {bloqade_circuit-0.3.0.dist-info → bloqade_circuit-0.4.1.dist-info}/WHEEL +0 -0
- {bloqade_circuit-0.3.0.dist-info → bloqade_circuit-0.4.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -3,12 +3,12 @@ from typing import Any
|
|
|
3
3
|
from kirin import interp
|
|
4
4
|
from kirin.dialects import ilist
|
|
5
5
|
|
|
6
|
-
from bloqade.noise import native
|
|
7
6
|
from bloqade.qasm2.parse import ast
|
|
7
|
+
from bloqade.qasm2.dialects import noise
|
|
8
8
|
from bloqade.qasm2.emit.gate import EmitQASM2Gate, EmitQASM2Frame
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
@
|
|
11
|
+
@noise.dialect.register(key="emit.qasm2.gate")
|
|
12
12
|
class NativeNoise(interp.MethodTable):
|
|
13
13
|
|
|
14
14
|
def _convert(self, node: ast.Bit | ast.Name) -> str:
|
|
@@ -17,12 +17,12 @@ class NativeNoise(interp.MethodTable):
|
|
|
17
17
|
else:
|
|
18
18
|
return f"{node.id}"
|
|
19
19
|
|
|
20
|
-
@interp.impl(
|
|
20
|
+
@interp.impl(noise.CZPauliChannel)
|
|
21
21
|
def emit_czp(
|
|
22
22
|
self,
|
|
23
23
|
emit: EmitQASM2Gate,
|
|
24
24
|
frame: EmitQASM2Frame,
|
|
25
|
-
stmt:
|
|
25
|
+
stmt: noise.CZPauliChannel,
|
|
26
26
|
):
|
|
27
27
|
paired: bool = stmt.paired
|
|
28
28
|
px_ctrl: float = stmt.px_ctrl
|
|
@@ -35,7 +35,7 @@ class NativeNoise(interp.MethodTable):
|
|
|
35
35
|
qargs: ilist.IList[ast.Bit, Any] = frame.get(stmt.qargs)
|
|
36
36
|
frame.body.append(
|
|
37
37
|
ast.Comment(
|
|
38
|
-
text=f"
|
|
38
|
+
text=f"noise.CZPauliChannel(paired={paired}, p_ctrl=[x:{px_ctrl}, y:{py_ctrl}, z:{pz_ctrl}], p_qarg[x:{px_qarg}, y:{py_qarg}, z:{pz_qarg}])"
|
|
39
39
|
)
|
|
40
40
|
)
|
|
41
41
|
frame.body.append(
|
|
@@ -50,16 +50,16 @@ class NativeNoise(interp.MethodTable):
|
|
|
50
50
|
)
|
|
51
51
|
return ()
|
|
52
52
|
|
|
53
|
-
@interp.impl(
|
|
53
|
+
@interp.impl(noise.AtomLossChannel)
|
|
54
54
|
def emit_loss(
|
|
55
55
|
self,
|
|
56
56
|
emit: EmitQASM2Gate,
|
|
57
57
|
frame: EmitQASM2Frame,
|
|
58
|
-
stmt:
|
|
58
|
+
stmt: noise.AtomLossChannel,
|
|
59
59
|
):
|
|
60
60
|
prob: float = stmt.prob
|
|
61
61
|
qargs: ilist.IList[ast.Bit, Any] = frame.get(stmt.qargs)
|
|
62
|
-
frame.body.append(ast.Comment(text=f"
|
|
62
|
+
frame.body.append(ast.Comment(text=f"noise.Atomloss(p={prob})"))
|
|
63
63
|
frame.body.append(
|
|
64
64
|
ast.Comment(
|
|
65
65
|
text=f" -: qargs: {', '.join([self._convert(q) for q in qargs])}"
|
|
@@ -67,19 +67,19 @@ class NativeNoise(interp.MethodTable):
|
|
|
67
67
|
)
|
|
68
68
|
return ()
|
|
69
69
|
|
|
70
|
-
@interp.impl(
|
|
70
|
+
@interp.impl(noise.PauliChannel)
|
|
71
71
|
def emit_pauli(
|
|
72
72
|
self,
|
|
73
73
|
emit: EmitQASM2Gate,
|
|
74
74
|
frame: EmitQASM2Frame,
|
|
75
|
-
stmt:
|
|
75
|
+
stmt: noise.PauliChannel,
|
|
76
76
|
):
|
|
77
77
|
px: float = stmt.px
|
|
78
78
|
py: float = stmt.py
|
|
79
79
|
pz: float = stmt.pz
|
|
80
80
|
qargs: ilist.IList[ast.Bit, Any] = frame.get(stmt.qargs)
|
|
81
81
|
frame.body.append(
|
|
82
|
-
ast.Comment(text=f"
|
|
82
|
+
ast.Comment(text=f"noise.PauliChannel(px={px}, py={py}, pz={pz})")
|
|
83
83
|
)
|
|
84
84
|
frame.body.append(
|
|
85
85
|
ast.Comment(
|
bloqade/qasm2/emit/main.py
CHANGED
|
@@ -25,12 +25,10 @@ class Func(interp.MethodTable):
|
|
|
25
25
|
def emit_func(
|
|
26
26
|
self, emit: EmitQASM2Main, frame: EmitQASM2Frame, stmt: func.Function
|
|
27
27
|
):
|
|
28
|
-
from bloqade.qasm2.dialects import glob,
|
|
28
|
+
from bloqade.qasm2.dialects import glob, parallel
|
|
29
29
|
|
|
30
30
|
emit.run_ssacfg_region(frame, stmt.body, ())
|
|
31
|
-
if emit.dialects.data.intersection(
|
|
32
|
-
(parallel.dialect, glob.dialect, noise.dialect)
|
|
33
|
-
):
|
|
31
|
+
if emit.dialects.data.intersection((parallel.dialect, glob.dialect)):
|
|
34
32
|
header = ast.Kirin([dialect.name for dialect in emit.dialects])
|
|
35
33
|
else:
|
|
36
34
|
header = ast.OPENQASM(ast.Version(2, 0))
|
bloqade/qasm2/emit/target.py
CHANGED
|
@@ -57,7 +57,7 @@ class QASM2:
|
|
|
57
57
|
|
|
58
58
|
|
|
59
59
|
"""
|
|
60
|
-
from bloqade import
|
|
60
|
+
from bloqade import qasm2
|
|
61
61
|
|
|
62
62
|
self.main_target = qasm2.main
|
|
63
63
|
self.gate_target = qasm2.gate
|
|
@@ -77,8 +77,8 @@ class QASM2:
|
|
|
77
77
|
self.gate_target = self.gate_target.add(qasm2.dialects.glob)
|
|
78
78
|
|
|
79
79
|
if allow_noise:
|
|
80
|
-
self.main_target = self.main_target.add(noise
|
|
81
|
-
self.gate_target = self.gate_target.add(noise
|
|
80
|
+
self.main_target = self.main_target.add(qasm2.dialects.noise)
|
|
81
|
+
self.gate_target = self.gate_target.add(qasm2.dialects.noise)
|
|
82
82
|
|
|
83
83
|
if allow_global or allow_parallel or allow_noise:
|
|
84
84
|
self.main_target = self.main_target.add(ilist)
|
bloqade/qasm2/groups.py
CHANGED
|
@@ -2,7 +2,6 @@ from kirin import ir, passes
|
|
|
2
2
|
from kirin.prelude import structural_no_opt
|
|
3
3
|
from kirin.dialects import scf, func, ilist, lowering
|
|
4
4
|
|
|
5
|
-
from bloqade.noise import native
|
|
6
5
|
from bloqade.qasm2.dialects import (
|
|
7
6
|
uop,
|
|
8
7
|
core,
|
|
@@ -91,7 +90,6 @@ def main(self):
|
|
|
91
90
|
noise,
|
|
92
91
|
parallel,
|
|
93
92
|
core,
|
|
94
|
-
native,
|
|
95
93
|
]
|
|
96
94
|
)
|
|
97
95
|
)
|
|
@@ -3,11 +3,15 @@ from typing import Any
|
|
|
3
3
|
from kirin.dialects import ilist
|
|
4
4
|
from kirin.lowering import wraps
|
|
5
5
|
|
|
6
|
-
from
|
|
7
|
-
from
|
|
6
|
+
from .types import Qubit
|
|
7
|
+
from .dialects import noise
|
|
8
|
+
from .dialects.noise import (
|
|
9
|
+
TwoRowZoneModel as TwoRowZoneModel,
|
|
10
|
+
MoveNoiseModelABC as MoveNoiseModelABC,
|
|
11
|
+
)
|
|
8
12
|
|
|
9
13
|
|
|
10
|
-
@wraps(
|
|
14
|
+
@wraps(noise.AtomLossChannel)
|
|
11
15
|
def atom_loss_channel(qargs: ilist.IList[Qubit, Any] | list, *, prob: float) -> None:
|
|
12
16
|
"""Apply an atom loss channel to a list of qubits.
|
|
13
17
|
|
|
@@ -18,7 +22,7 @@ def atom_loss_channel(qargs: ilist.IList[Qubit, Any] | list, *, prob: float) ->
|
|
|
18
22
|
...
|
|
19
23
|
|
|
20
24
|
|
|
21
|
-
@wraps(
|
|
25
|
+
@wraps(noise.PauliChannel)
|
|
22
26
|
def pauli_channel(
|
|
23
27
|
qargs: ilist.IList[Qubit, Any] | list, *, px: float, py: float, pz: float
|
|
24
28
|
) -> None:
|
|
@@ -32,7 +36,7 @@ def pauli_channel(
|
|
|
32
36
|
"""
|
|
33
37
|
|
|
34
38
|
|
|
35
|
-
@wraps(
|
|
39
|
+
@wraps(noise.CZPauliChannel)
|
|
36
40
|
def cz_pauli_channel(
|
|
37
41
|
ctrls: ilist.IList[Qubit, Any] | list,
|
|
38
42
|
qargs: ilist.IList[Qubit, Any] | list,
|
bloqade/qasm2/passes/glob.py
CHANGED
|
@@ -58,13 +58,15 @@ class GlobalToUOP(Pass):
|
|
|
58
58
|
rewriter = walk.Walk(self.generate_rule(mt))
|
|
59
59
|
result = rewriter.rewrite(mt.code)
|
|
60
60
|
|
|
61
|
-
result = walk.Walk(dce.DeadCodeElimination()).rewrite(mt.code)
|
|
62
|
-
result =
|
|
63
|
-
|
|
61
|
+
result = walk.Walk(dce.DeadCodeElimination()).rewrite(mt.code).join(result)
|
|
62
|
+
result = (
|
|
63
|
+
Fixpoint(walk.Walk(rule=cse.CommonSubexpressionElimination()))
|
|
64
|
+
.rewrite(mt.code)
|
|
65
|
+
.join(result)
|
|
64
66
|
)
|
|
65
67
|
|
|
66
68
|
# do fold again to get proper hint for inserted const
|
|
67
|
-
result = Fold(mt.dialects)(mt)
|
|
69
|
+
result = Fold(mt.dialects)(mt).join(result)
|
|
68
70
|
return result
|
|
69
71
|
|
|
70
72
|
|
|
@@ -110,10 +112,12 @@ class GlobalToParallel(Pass):
|
|
|
110
112
|
rewriter = walk.Walk(self.generate_rule(mt))
|
|
111
113
|
result = rewriter.rewrite(mt.code)
|
|
112
114
|
|
|
113
|
-
result = walk.Walk(dce.DeadCodeElimination()).rewrite(mt.code)
|
|
114
|
-
result =
|
|
115
|
-
|
|
115
|
+
result = walk.Walk(dce.DeadCodeElimination()).rewrite(mt.code).join(result)
|
|
116
|
+
result = (
|
|
117
|
+
Fixpoint(walk.Walk(rule=cse.CommonSubexpressionElimination()))
|
|
118
|
+
.rewrite(mt.code)
|
|
119
|
+
.join(result)
|
|
116
120
|
)
|
|
117
121
|
# do fold again to get proper hint
|
|
118
|
-
result = Fold(mt.dialects)(mt)
|
|
122
|
+
result = Fold(mt.dialects)(mt).join(result)
|
|
119
123
|
return result
|
bloqade/qasm2/passes/noise.py
CHANGED
|
@@ -8,10 +8,10 @@ from kirin.rewrite import (
|
|
|
8
8
|
DeadCodeElimination,
|
|
9
9
|
)
|
|
10
10
|
|
|
11
|
-
from bloqade.
|
|
11
|
+
from bloqade.qasm2 import noise
|
|
12
12
|
from bloqade.analysis import address
|
|
13
|
+
from bloqade.qasm2.rewrite import NoiseRewriteRule
|
|
13
14
|
from bloqade.qasm2.passes.lift_qubits import LiftQubits
|
|
14
|
-
from bloqade.qasm2.rewrite.heuristic_noise import NoiseRewriteRule
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
@dataclass
|
|
@@ -25,12 +25,9 @@ class NoisePass(Pass):
|
|
|
25
25
|
|
|
26
26
|
```
|
|
27
27
|
from bloqade import qasm2
|
|
28
|
-
from bloqade.
|
|
29
|
-
from bloqade.qasm2.passes.noise import NoisePass
|
|
28
|
+
from bloqade.qasm2.passes import NoisePass
|
|
30
29
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
@noise_main
|
|
30
|
+
@qasm2.extended
|
|
34
31
|
def main():
|
|
35
32
|
q = qasm2.qreg(2)
|
|
36
33
|
qasm2.h(q[0])
|
|
@@ -51,12 +48,7 @@ class NoisePass(Pass):
|
|
|
51
48
|
|
|
52
49
|
"""
|
|
53
50
|
|
|
54
|
-
noise_model:
|
|
55
|
-
default_factory=native.TwoRowZoneModel
|
|
56
|
-
)
|
|
57
|
-
gate_noise_params: native.GateNoiseParams = field(
|
|
58
|
-
default_factory=native.GateNoiseParams
|
|
59
|
-
)
|
|
51
|
+
noise_model: noise.MoveNoiseModelABC = field(default_factory=noise.TwoRowZoneModel)
|
|
60
52
|
address_analysis: address.AddressAnalysis = field(init=False)
|
|
61
53
|
|
|
62
54
|
def __post_init__(self):
|
|
@@ -89,7 +81,6 @@ class NoisePass(Pass):
|
|
|
89
81
|
qubit_ssa_value=qubit_ssa_value,
|
|
90
82
|
address_analysis=address_analysis,
|
|
91
83
|
noise_model=self.noise_model,
|
|
92
|
-
gate_noise_params=self.gate_noise_params,
|
|
93
84
|
),
|
|
94
85
|
reverse=True,
|
|
95
86
|
)
|
|
@@ -11,3 +11,5 @@ from .uop_to_parallel import (
|
|
|
11
11
|
SimpleGreedyMergePolicy as SimpleGreedyMergePolicy,
|
|
12
12
|
SimpleOptimalMergePolicy as SimpleOptimalMergePolicy,
|
|
13
13
|
)
|
|
14
|
+
from .noise.remove_noise import RemoveNoisePass as RemoveNoisePass
|
|
15
|
+
from .noise.heuristic_noise import NoiseRewriteRule as NoiseRewriteRule
|
|
File without changes
|
|
@@ -5,9 +5,8 @@ from kirin import ir
|
|
|
5
5
|
from kirin.rewrite import abc as rewrite_abc
|
|
6
6
|
from kirin.dialects import ilist
|
|
7
7
|
|
|
8
|
-
from bloqade.noise import native
|
|
9
8
|
from bloqade.analysis import address
|
|
10
|
-
from bloqade.qasm2.dialects import uop, glob, parallel
|
|
9
|
+
from bloqade.qasm2.dialects import uop, glob, noise, parallel
|
|
11
10
|
|
|
12
11
|
|
|
13
12
|
@dataclass
|
|
@@ -19,12 +18,7 @@ class NoiseRewriteRule(rewrite_abc.RewriteRule):
|
|
|
19
18
|
|
|
20
19
|
address_analysis: Dict[ir.SSAValue, address.Address]
|
|
21
20
|
qubit_ssa_value: Dict[int, ir.SSAValue]
|
|
22
|
-
|
|
23
|
-
default_factory=native.GateNoiseParams
|
|
24
|
-
)
|
|
25
|
-
noise_model: native.MoveNoiseModelABC = field(
|
|
26
|
-
default_factory=native.TwoRowZoneModel
|
|
27
|
-
)
|
|
21
|
+
noise_model: noise.MoveNoiseModelABC = field(default_factory=noise.TwoRowZoneModel)
|
|
28
22
|
|
|
29
23
|
def rewrite_Statement(self, node: ir.Statement) -> rewrite_abc.RewriteResult:
|
|
30
24
|
if isinstance(node, uop.SingleQubitGate):
|
|
@@ -46,22 +40,18 @@ class NoiseRewriteRule(rewrite_abc.RewriteRule):
|
|
|
46
40
|
qargs: ir.SSAValue,
|
|
47
41
|
probs: Tuple[float, float, float, float],
|
|
48
42
|
):
|
|
49
|
-
|
|
43
|
+
noise.PauliChannel(qargs, px=probs[0], py=probs[1], pz=probs[2]).insert_before(
|
|
50
44
|
node
|
|
51
45
|
)
|
|
52
|
-
|
|
46
|
+
noise.AtomLossChannel(qargs, prob=probs[3]).insert_before(node)
|
|
53
47
|
|
|
54
48
|
return rewrite_abc.RewriteResult(has_done_something=True)
|
|
55
49
|
|
|
56
50
|
def rewrite_single_qubit_gate(self, node: uop.SingleQubitGate):
|
|
57
|
-
probs = (
|
|
58
|
-
self.gate_noise_params.local_px,
|
|
59
|
-
self.gate_noise_params.local_py,
|
|
60
|
-
self.gate_noise_params.local_pz,
|
|
61
|
-
self.gate_noise_params.local_loss_prob,
|
|
62
|
-
)
|
|
63
51
|
(qargs := ilist.New(values=(node.qarg,))).insert_before(node)
|
|
64
|
-
return self.insert_single_qubit_noise(
|
|
52
|
+
return self.insert_single_qubit_noise(
|
|
53
|
+
node, qargs.result, self.noise_model.local_errors
|
|
54
|
+
)
|
|
65
55
|
|
|
66
56
|
def rewrite_global_single_qubit_gate(self, node: glob.UGate):
|
|
67
57
|
addrs = self.address_analysis[node.registers]
|
|
@@ -77,14 +67,10 @@ class NoiseRewriteRule(rewrite_abc.RewriteRule):
|
|
|
77
67
|
for qid in addr.data:
|
|
78
68
|
qargs.append(self.qubit_ssa_value[qid])
|
|
79
69
|
|
|
80
|
-
probs = (
|
|
81
|
-
self.gate_noise_params.global_px,
|
|
82
|
-
self.gate_noise_params.global_py,
|
|
83
|
-
self.gate_noise_params.global_pz,
|
|
84
|
-
self.gate_noise_params.global_loss_prob,
|
|
85
|
-
)
|
|
86
70
|
(qargs := ilist.New(values=tuple(qargs))).insert_before(node)
|
|
87
|
-
return self.insert_single_qubit_noise(
|
|
71
|
+
return self.insert_single_qubit_noise(
|
|
72
|
+
node, qargs.result, self.noise_model.global_errors
|
|
73
|
+
)
|
|
88
74
|
|
|
89
75
|
def rewrite_parallel_single_qubit_gate(self, node: parallel.RZ | parallel.UGate):
|
|
90
76
|
addrs = self.address_analysis[node.qargs]
|
|
@@ -94,15 +80,11 @@ class NoiseRewriteRule(rewrite_abc.RewriteRule):
|
|
|
94
80
|
if not all(isinstance(addr, address.AddressQubit) for addr in addrs.data):
|
|
95
81
|
return rewrite_abc.RewriteResult()
|
|
96
82
|
|
|
97
|
-
probs = (
|
|
98
|
-
self.gate_noise_params.local_px,
|
|
99
|
-
self.gate_noise_params.local_py,
|
|
100
|
-
self.gate_noise_params.local_pz,
|
|
101
|
-
self.gate_noise_params.local_loss_prob,
|
|
102
|
-
)
|
|
103
83
|
assert isinstance(node.qargs, ir.ResultValue)
|
|
104
84
|
assert isinstance(node.qargs.stmt, ilist.New)
|
|
105
|
-
return self.insert_single_qubit_noise(
|
|
85
|
+
return self.insert_single_qubit_noise(
|
|
86
|
+
node, node.qargs, self.noise_model.local_errors
|
|
87
|
+
)
|
|
106
88
|
|
|
107
89
|
def move_noise_stmts(
|
|
108
90
|
self,
|
|
@@ -118,9 +100,9 @@ class NoiseRewriteRule(rewrite_abc.RewriteRule):
|
|
|
118
100
|
nodes.append(
|
|
119
101
|
qargs := ilist.New(tuple(self.qubit_ssa_value[q] for q in qubits))
|
|
120
102
|
)
|
|
121
|
-
nodes.append(
|
|
103
|
+
nodes.append(noise.AtomLossChannel(qargs.result, prob=probs[3]))
|
|
122
104
|
nodes.append(
|
|
123
|
-
|
|
105
|
+
noise.PauliChannel(qargs.result, px=probs[0], py=probs[1], pz=probs[2])
|
|
124
106
|
)
|
|
125
107
|
|
|
126
108
|
return nodes
|
|
@@ -131,34 +113,30 @@ class NoiseRewriteRule(rewrite_abc.RewriteRule):
|
|
|
131
113
|
qargs: ir.SSAValue,
|
|
132
114
|
) -> list[ir.Statement]:
|
|
133
115
|
return [
|
|
134
|
-
|
|
116
|
+
noise.CZPauliChannel(
|
|
135
117
|
ctrls,
|
|
136
118
|
qargs,
|
|
137
|
-
px_ctrl=self.
|
|
138
|
-
py_ctrl=self.
|
|
139
|
-
pz_ctrl=self.
|
|
140
|
-
px_qarg=self.
|
|
141
|
-
py_qarg=self.
|
|
142
|
-
pz_qarg=self.
|
|
119
|
+
px_ctrl=self.noise_model.cz_paired_gate_px,
|
|
120
|
+
py_ctrl=self.noise_model.cz_paired_gate_py,
|
|
121
|
+
pz_ctrl=self.noise_model.cz_paired_gate_pz,
|
|
122
|
+
px_qarg=self.noise_model.cz_paired_gate_px,
|
|
123
|
+
py_qarg=self.noise_model.cz_paired_gate_py,
|
|
124
|
+
pz_qarg=self.noise_model.cz_paired_gate_pz,
|
|
143
125
|
paired=True,
|
|
144
126
|
),
|
|
145
|
-
|
|
127
|
+
noise.CZPauliChannel(
|
|
146
128
|
ctrls,
|
|
147
129
|
qargs,
|
|
148
|
-
px_ctrl=self.
|
|
149
|
-
py_ctrl=self.
|
|
150
|
-
pz_ctrl=self.
|
|
151
|
-
px_qarg=self.
|
|
152
|
-
py_qarg=self.
|
|
153
|
-
pz_qarg=self.
|
|
130
|
+
px_ctrl=self.noise_model.cz_unpaired_gate_px,
|
|
131
|
+
py_ctrl=self.noise_model.cz_unpaired_gate_py,
|
|
132
|
+
pz_ctrl=self.noise_model.cz_unpaired_gate_pz,
|
|
133
|
+
px_qarg=self.noise_model.cz_unpaired_gate_px,
|
|
134
|
+
py_qarg=self.noise_model.cz_unpaired_gate_py,
|
|
135
|
+
pz_qarg=self.noise_model.cz_unpaired_gate_pz,
|
|
154
136
|
paired=False,
|
|
155
137
|
),
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
),
|
|
159
|
-
native.AtomLossChannel(
|
|
160
|
-
qargs, prob=self.gate_noise_params.cz_gate_loss_prob
|
|
161
|
-
),
|
|
138
|
+
noise.AtomLossChannel(ctrls, prob=self.noise_model.cz_gate_loss_prob),
|
|
139
|
+
noise.AtomLossChannel(qargs, prob=self.noise_model.cz_gate_loss_prob),
|
|
162
140
|
]
|
|
163
141
|
|
|
164
142
|
def rewrite_cz_gate(self, node: uop.CZ):
|
|
@@ -4,8 +4,8 @@ from kirin import ir
|
|
|
4
4
|
from kirin.rewrite import abc, dce, walk, fixpoint
|
|
5
5
|
from kirin.passes.abc import Pass
|
|
6
6
|
|
|
7
|
-
from .stmts import PauliChannel, CZPauliChannel, AtomLossChannel
|
|
8
|
-
from ._dialect import dialect
|
|
7
|
+
from ...dialects.noise.stmts import PauliChannel, CZPauliChannel, AtomLossChannel
|
|
8
|
+
from ...dialects.noise._dialect import dialect
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
class RemoveNoiseRewrite(abc.RewriteRule):
|
bloqade/qbraid/lowering.py
CHANGED
|
@@ -4,13 +4,13 @@ from dataclasses import field, dataclass
|
|
|
4
4
|
from kirin import ir, types, passes
|
|
5
5
|
from kirin.dialects import func, ilist
|
|
6
6
|
|
|
7
|
-
from bloqade import
|
|
7
|
+
from bloqade import qasm2
|
|
8
8
|
from bloqade.qbraid import schema
|
|
9
|
-
from bloqade.qasm2.dialects import glob, parallel
|
|
9
|
+
from bloqade.qasm2.dialects import glob, noise, parallel
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
@ir.dialect_group(
|
|
13
|
-
[func, qasm2.core, qasm2.uop, parallel, glob, qasm2.expr, noise
|
|
13
|
+
[func, qasm2.core, qasm2.uop, parallel, glob, qasm2.expr, noise, ilist]
|
|
14
14
|
)
|
|
15
15
|
def qbraid_noise(
|
|
16
16
|
self,
|
|
@@ -192,7 +192,7 @@ class Lowering:
|
|
|
192
192
|
qargs := ilist.New(values=tuple(self.qubit_id_map[q] for q in qubits))
|
|
193
193
|
)
|
|
194
194
|
self.block_list.append(
|
|
195
|
-
noise.
|
|
195
|
+
noise.PauliChannel(px=px, py=py, pz=pz, qargs=qargs.result)
|
|
196
196
|
)
|
|
197
197
|
|
|
198
198
|
for (p_ctrl, p_qarg), qubits in paired_layers.items():
|
|
@@ -204,7 +204,7 @@ class Lowering:
|
|
|
204
204
|
qargs := ilist.New(values=tuple(self.qubit_id_map[q] for q in qargs))
|
|
205
205
|
)
|
|
206
206
|
self.block_list.append(
|
|
207
|
-
noise.
|
|
207
|
+
noise.CZPauliChannel(
|
|
208
208
|
paired=True,
|
|
209
209
|
px_ctrl=p_ctrl[0],
|
|
210
210
|
py_ctrl=p_ctrl[1],
|
|
@@ -226,7 +226,7 @@ class Lowering:
|
|
|
226
226
|
qargs := ilist.New(values=tuple(self.qubit_id_map[q] for q in qargs))
|
|
227
227
|
)
|
|
228
228
|
self.block_list.append(
|
|
229
|
-
noise.
|
|
229
|
+
noise.CZPauliChannel(
|
|
230
230
|
paired=False,
|
|
231
231
|
px_ctrl=p_ctrl[0],
|
|
232
232
|
py_ctrl=p_ctrl[1],
|
|
@@ -285,7 +285,7 @@ class Lowering:
|
|
|
285
285
|
qargs := ilist.New(values=tuple(self.qubit_id_map[q] for q in qubits))
|
|
286
286
|
)
|
|
287
287
|
self.block_list.append(
|
|
288
|
-
noise.
|
|
288
|
+
noise.PauliChannel(px=px, py=py, pz=pz, qargs=qargs.result)
|
|
289
289
|
)
|
|
290
290
|
|
|
291
291
|
def lower_measurement(self, operation: schema.Measurement):
|
|
@@ -303,7 +303,7 @@ class Lowering:
|
|
|
303
303
|
for survival_prob, qubits in layers.items():
|
|
304
304
|
self.block_list.append(qargs := ilist.New(values=qubits))
|
|
305
305
|
self.block_list.append(
|
|
306
|
-
noise.
|
|
306
|
+
noise.AtomLossChannel(prob=survival_prob, qargs=qargs.result)
|
|
307
307
|
)
|
|
308
308
|
|
|
309
309
|
def lower_number(self, value: float | int) -> ir.SSAValue:
|
bloqade/squin/__init__.py
CHANGED
|
@@ -1,2 +1,17 @@
|
|
|
1
|
-
from . import
|
|
1
|
+
from . import (
|
|
2
|
+
op as op,
|
|
3
|
+
wire as wire,
|
|
4
|
+
noise as noise,
|
|
5
|
+
qubit as qubit,
|
|
6
|
+
lowering as lowering,
|
|
7
|
+
)
|
|
2
8
|
from .groups import wired as wired, kernel as kernel
|
|
9
|
+
|
|
10
|
+
try:
|
|
11
|
+
# NOTE: make sure optional cirq dependency is installed
|
|
12
|
+
import cirq as cirq_package # noqa: F401
|
|
13
|
+
except ImportError:
|
|
14
|
+
pass
|
|
15
|
+
else:
|
|
16
|
+
from . import cirq as cirq
|
|
17
|
+
from .cirq import load_circuit as load_circuit
|
|
@@ -23,15 +23,6 @@ class SquinWire(interp.MethodTable):
|
|
|
23
23
|
|
|
24
24
|
return tuple(frame.get(input) for input in stmt.inputs)
|
|
25
25
|
|
|
26
|
-
@interp.impl(wire.MeasureAndReset)
|
|
27
|
-
def measure_and_reset(
|
|
28
|
-
self, interp: NSitesAnalysis, frame: interp.Frame, stmt: wire.MeasureAndReset
|
|
29
|
-
):
|
|
30
|
-
|
|
31
|
-
# MeasureAndReset produces both a new wire
|
|
32
|
-
# and an integer which don't have any sites at all
|
|
33
|
-
return (NoSites(), NoSites())
|
|
34
|
-
|
|
35
26
|
|
|
36
27
|
@op.dialect.register(key="op.nsites")
|
|
37
28
|
class SquinOp(interp.MethodTable):
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
import cirq
|
|
4
|
+
from kirin import ir, types
|
|
5
|
+
from kirin.dialects import func
|
|
6
|
+
|
|
7
|
+
from . import lowering as lowering
|
|
8
|
+
from .. import kernel
|
|
9
|
+
from .lowering import Squin
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def load_circuit(
|
|
13
|
+
circuit: cirq.Circuit,
|
|
14
|
+
kernel_name: str = "main",
|
|
15
|
+
dialects: ir.DialectGroup = kernel,
|
|
16
|
+
globals: dict[str, Any] | None = None,
|
|
17
|
+
file: str | None = None,
|
|
18
|
+
lineno_offset: int = 0,
|
|
19
|
+
col_offset: int = 0,
|
|
20
|
+
compactify: bool = True,
|
|
21
|
+
):
|
|
22
|
+
"""Converts a cirq.Circuit object into a squin kernel.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
circuit (cirq.Circuit): The circuit to load.
|
|
26
|
+
|
|
27
|
+
Keyword Args:
|
|
28
|
+
kernel_name (str): The name of the kernel to load. Defaults to "main".
|
|
29
|
+
dialects (ir.DialectGroup | None): The dialects to use. Defaults to `squin.kernel`.
|
|
30
|
+
globals (dict[str, Any] | None): The global variables to use. Defaults to None.
|
|
31
|
+
file (str | None): The file name for error reporting. Defaults to None.
|
|
32
|
+
lineno_offset (int): The line number offset for error reporting. Defaults to 0.
|
|
33
|
+
col_offset (int): The column number offset for error reporting. Defaults to 0.
|
|
34
|
+
compactify (bool): Whether to compactify the output. Defaults to True.
|
|
35
|
+
|
|
36
|
+
Example:
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
# from cirq's "hello qubit" example
|
|
40
|
+
import cirq
|
|
41
|
+
from bloqade import squin
|
|
42
|
+
|
|
43
|
+
# Pick a qubit.
|
|
44
|
+
qubit = cirq.GridQubit(0, 0)
|
|
45
|
+
|
|
46
|
+
# Create a circuit.
|
|
47
|
+
circuit = cirq.Circuit(
|
|
48
|
+
cirq.X(qubit)**0.5, # Square root of NOT.
|
|
49
|
+
cirq.measure(qubit, key='m') # Measurement.
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
# load the circuit as squin
|
|
53
|
+
main = squin.load_circuit(circuit)
|
|
54
|
+
|
|
55
|
+
# print the resulting IR
|
|
56
|
+
main.print()
|
|
57
|
+
```
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
target = Squin(dialects=dialects, circuit=circuit)
|
|
61
|
+
body = target.run(
|
|
62
|
+
circuit,
|
|
63
|
+
source=str(circuit), # TODO: proper source string
|
|
64
|
+
file=file,
|
|
65
|
+
globals=globals,
|
|
66
|
+
lineno_offset=lineno_offset,
|
|
67
|
+
col_offset=col_offset,
|
|
68
|
+
compactify=compactify,
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
# NOTE: no return value
|
|
72
|
+
return_value = func.ConstantNone()
|
|
73
|
+
body.blocks[0].stmts.append(return_value)
|
|
74
|
+
body.blocks[0].stmts.append(func.Return(value_or_stmt=return_value))
|
|
75
|
+
|
|
76
|
+
code = func.Function(
|
|
77
|
+
sym_name=kernel_name,
|
|
78
|
+
signature=func.Signature((), types.NoneType),
|
|
79
|
+
body=body,
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
return ir.Method(
|
|
83
|
+
mod=None,
|
|
84
|
+
py_func=None,
|
|
85
|
+
sym_name=kernel_name,
|
|
86
|
+
arg_names=[],
|
|
87
|
+
dialects=dialects,
|
|
88
|
+
code=code,
|
|
89
|
+
)
|