Skip to content

Commit 45220ba

Browse files
authored
Khwu/qasm2noise (#277)
This PR address #275. Deps #279
1 parent 11110b3 commit 45220ba

File tree

10 files changed

+281
-15
lines changed

10 files changed

+281
-15
lines changed

src/bloqade/noise/fidelity.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
from kirin import interp
22
from kirin.lattice import EmptyLattice
33

4+
from bloqade.analysis.address import AddressQubit, AddressTuple
45
from bloqade.analysis.fidelity import FidelityAnalysis
56

6-
from .native import dialect as native
7+
from .native import dialect
78
from .native.stmts import PauliChannel, CZPauliChannel, AtomLossChannel
8-
from ..analysis.address import AddressQubit, AddressTuple
99

1010

11-
@native.register(key="circuit.fidelity")
11+
@dialect.register(key="circuit.fidelity")
1212
class FidelityMethodTable(interp.MethodTable):
1313

1414
@interp.impl(PauliChannel)
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
from kirin import ir
22

3-
dialect = ir.Dialect("native")
3+
dialect = ir.Dialect("noise.native")

src/bloqade/noise/native/_wrappers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def pauli_channel(
3535
@wraps(native.CZPauliChannel)
3636
def cz_pauli_channel(
3737
ctrls: ilist.IList[Qubit, Any] | list,
38-
qarg2: ilist.IList[Qubit, Any] | list,
38+
qargs: ilist.IList[Qubit, Any] | list,
3939
*,
4040
px_ctrl: float,
4141
py_ctrl: float,

src/bloqade/noise/native/stmts.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from kirin.decl import info, statement
55
from kirin.dialects import ilist
66

7-
from bloqade.qasm2.types import QubitType
7+
from bloqade.types import QubitType
88

99
from ._dialect import dialect
1010

src/bloqade/qasm2/dialects/noise.py

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
from kirin import ir, types, lowering
1+
from kirin import ir, types, interp, lowering
22
from kirin.decl import info, statement
33

4+
from bloqade.qasm2.parse import ast
45
from bloqade.qasm2.types import QubitType
6+
from bloqade.qasm2.emit.gate import EmitQASM2Gate, EmitQASM2Frame
57

68
dialect = ir.Dialect("qasm2.noise")
79

@@ -14,3 +16,33 @@ class Pauli1(ir.Statement):
1416
py: ir.SSAValue = info.argument(types.Float)
1517
pz: ir.SSAValue = info.argument(types.Float)
1618
qarg: ir.SSAValue = info.argument(QubitType)
19+
20+
21+
@dialect.register(key="emit.qasm2.gate")
22+
class NoiseEmit(interp.MethodTable):
23+
24+
@interp.impl(Pauli1)
25+
def emit_pauli(
26+
self,
27+
emit: EmitQASM2Gate,
28+
frame: EmitQASM2Frame,
29+
stmt: Pauli1,
30+
):
31+
32+
px: ast.Number = frame.get(stmt.px)
33+
py: ast.Number = frame.get(stmt.py)
34+
pz: ast.Number = frame.get(stmt.pz)
35+
qarg: ast.Bit | ast.Name = frame.get(stmt.qarg)
36+
37+
qarg_str = (
38+
f"{qarg.name.id}[{qarg.addr}]"
39+
if isinstance(qarg, ast.Bit)
40+
else f"{qarg.id}"
41+
)
42+
43+
frame.body.append(
44+
ast.Comment(
45+
text=f"noise.Pauli1({px.value}, {py.value}, {pz.value}) {qarg_str}]"
46+
)
47+
)
48+
return ()
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from . import noise_native as noise_native
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
from typing import Any
2+
3+
from kirin import interp
4+
from kirin.dialects import ilist
5+
6+
from bloqade.noise import native
7+
from bloqade.qasm2.parse import ast
8+
from bloqade.qasm2.emit.gate import EmitQASM2Gate, EmitQASM2Frame
9+
10+
11+
@native.dialect.register(key="emit.qasm2.gate")
12+
class NativeNoise(interp.MethodTable):
13+
14+
def _convert(self, node: ast.Bit | ast.Name) -> str:
15+
if isinstance(node, ast.Bit):
16+
return f"{node.name.id}[{node.addr}]"
17+
else:
18+
return f"{node.id}"
19+
20+
@interp.impl(native.CZPauliChannel)
21+
def emit_czp(
22+
self,
23+
emit: EmitQASM2Gate,
24+
frame: EmitQASM2Frame,
25+
stmt: native.CZPauliChannel,
26+
):
27+
paired: bool = stmt.paired
28+
px_ctrl: float = stmt.px_ctrl
29+
py_ctrl: float = stmt.py_ctrl
30+
pz_ctrl: float = stmt.pz_ctrl
31+
px_qarg: float = stmt.pz_qarg
32+
py_qarg: float = stmt.py_qarg
33+
pz_qarg: float = stmt.pz_qarg
34+
ctrls: ilist.IList[ast.Bit, Any] = frame.get(stmt.ctrls)
35+
qargs: ilist.IList[ast.Bit, Any] = frame.get(stmt.qargs)
36+
frame.body.append(
37+
ast.Comment(
38+
text=f"native.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+
)
40+
)
41+
frame.body.append(
42+
ast.Comment(
43+
text=f" -: ctrls: {', '.join([self._convert(q) for q in ctrls])}"
44+
)
45+
)
46+
frame.body.append(
47+
ast.Comment(
48+
text=f" -: qargs: {', '.join([self._convert(q) for q in qargs])}"
49+
)
50+
)
51+
return ()
52+
53+
@interp.impl(native.AtomLossChannel)
54+
def emit_loss(
55+
self,
56+
emit: EmitQASM2Gate,
57+
frame: EmitQASM2Frame,
58+
stmt: native.AtomLossChannel,
59+
):
60+
prob: float = stmt.prob
61+
qargs: ilist.IList[ast.Bit, Any] = frame.get(stmt.qargs)
62+
frame.body.append(ast.Comment(text=f"native.Atomloss(p={prob})"))
63+
frame.body.append(
64+
ast.Comment(
65+
text=f" -: qargs: {', '.join([self._convert(q) for q in qargs])}"
66+
)
67+
)
68+
return ()
69+
70+
@interp.impl(native.PauliChannel)
71+
def emit_pauli(
72+
self,
73+
emit: EmitQASM2Gate,
74+
frame: EmitQASM2Frame,
75+
stmt: native.PauliChannel,
76+
):
77+
px: float = stmt.px
78+
py: float = stmt.py
79+
pz: float = stmt.pz
80+
qargs: ilist.IList[ast.Bit, Any] = frame.get(stmt.qargs)
81+
frame.body.append(
82+
ast.Comment(text=f"native.PauliChannel(px={px}, py={py}, pz={pz})")
83+
)
84+
frame.body.append(
85+
ast.Comment(
86+
text=f" -: qargs: {', '.join([self._convert(q) for q in qargs])}"
87+
)
88+
)
89+
return ()

src/bloqade/qasm2/emit/target.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from bloqade.qasm2.passes.py2qasm import Py2QASM
1212
from bloqade.qasm2.passes.parallel import ParallelToUOp
1313

14+
from . import impls as impls # register the tables
1415
from .gate import EmitQASM2Gate
1516
from .main import EmitQASM2Main
1617

@@ -28,6 +29,7 @@ def __init__(
2829
allow_global: bool = False,
2930
custom_gate: bool = True,
3031
unroll_ifs: bool = True,
32+
allow_noise: bool = True,
3133
) -> None:
3234
"""Initialize the QASM2 target.
3335
@@ -55,7 +57,7 @@ def __init__(
5557
5658
5759
"""
58-
from bloqade import qasm2
60+
from bloqade import noise, qasm2
5961

6062
self.main_target = qasm2.main
6163
self.gate_target = qasm2.gate
@@ -74,7 +76,11 @@ def __init__(
7476
self.main_target = self.main_target.add(qasm2.dialects.glob)
7577
self.gate_target = self.gate_target.add(qasm2.dialects.glob)
7678

77-
if allow_global or allow_parallel:
79+
if allow_noise:
80+
self.main_target = self.main_target.add(noise.native)
81+
self.gate_target = self.gate_target.add(noise.native)
82+
83+
if allow_global or allow_parallel or allow_noise:
7884
self.main_target = self.main_target.add(ilist)
7985
self.gate_target = self.gate_target.add(ilist)
8086

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
from bloqade import noise, qasm2
2+
3+
4+
def test_pauli_ch():
5+
6+
@qasm2.extended
7+
def main():
8+
qreg = qasm2.qreg(4)
9+
10+
qasm2.cx(qreg[0], qreg[1])
11+
qasm2.u(qreg[2], theta=0.1, phi=0.2, lam=0.3)
12+
13+
noise.native.pauli_channel(qargs=[qreg[0], qreg[1]], px=0.1, py=0.2, pz=0.3)
14+
15+
qasm2.u(qreg[2], theta=0.1, phi=0.2, lam=0.3)
16+
17+
main.print()
18+
19+
target = qasm2.emit.QASM2(allow_noise=True)
20+
out = target.emit_str(main)
21+
22+
expected = """OPENQASM 2.0;
23+
include "qelib1.inc";
24+
qreg qreg[4];
25+
CX qreg[0], qreg[1];
26+
U(0.1, 0.2, 0.3) qreg[2];
27+
// native.PauliChannel(px=0.1, py=0.2, pz=0.3)
28+
// -: qargs: qreg[0], qreg[1]
29+
U(0.1, 0.2, 0.3) qreg[2];
30+
"""
31+
32+
assert out == expected
33+
34+
35+
def test_pauli_ch_para():
36+
37+
@qasm2.extended
38+
def main():
39+
qreg = qasm2.qreg(4)
40+
41+
qasm2.cx(qreg[0], qreg[1])
42+
qasm2.parallel.u([qreg[2], qreg[3]], theta=0.1, phi=0.2, lam=0.3)
43+
44+
noise.native.pauli_channel(qargs=[qreg[0], qreg[1]], px=0.1, py=0.2, pz=0.3)
45+
46+
qasm2.u(qreg[2], theta=0.1, phi=0.2, lam=0.3)
47+
48+
main.print()
49+
50+
target = qasm2.emit.QASM2(allow_noise=True, allow_parallel=True)
51+
out = target.emit_str(main)
52+
expected = """KIRIN {func,lowering.call,lowering.func,noise.native,py.ilist,qasm2.core,qasm2.expr,qasm2.indexing,qasm2.parallel,qasm2.uop,scf};
53+
include "qelib1.inc";
54+
qreg qreg[4];
55+
CX qreg[0], qreg[1];
56+
parallel.U(0.1, 0.2, 0.3) {
57+
qreg[2];
58+
qreg[3];
59+
}
60+
// native.PauliChannel(px=0.1, py=0.2, pz=0.3)
61+
// -: qargs: qreg[0], qreg[1]
62+
U(0.1, 0.2, 0.3) qreg[2];
63+
"""
64+
65+
assert out == expected
66+
67+
68+
def test_loss():
69+
70+
@qasm2.extended
71+
def main():
72+
qreg = qasm2.qreg(4)
73+
74+
qasm2.cx(qreg[0], qreg[1])
75+
qasm2.u(qreg[2], theta=0.1, phi=0.2, lam=0.3)
76+
77+
noise.native.atom_loss_channel(qargs=[qreg[0], qreg[1]], prob=0.2)
78+
79+
qasm2.u(qreg[2], theta=0.1, phi=0.2, lam=0.3)
80+
81+
main.print()
82+
83+
target = qasm2.emit.QASM2(allow_noise=True)
84+
out = target.emit_str(main)
85+
86+
expected = """OPENQASM 2.0;
87+
include "qelib1.inc";
88+
qreg qreg[4];
89+
CX qreg[0], qreg[1];
90+
U(0.1, 0.2, 0.3) qreg[2];
91+
// native.Atomloss(p=0.2)
92+
// -: qargs: qreg[0], qreg[1]
93+
U(0.1, 0.2, 0.3) qreg[2];
94+
"""
95+
96+
assert out == expected
97+
98+
99+
def test_cz_noise():
100+
101+
@qasm2.extended
102+
def main():
103+
qreg = qasm2.qreg(4)
104+
105+
qasm2.cx(qreg[0], qreg[1])
106+
qasm2.u(qreg[2], theta=0.1, phi=0.2, lam=0.3)
107+
108+
noise.native.cz_pauli_channel(
109+
ctrls=[qreg[0], qreg[1]],
110+
qargs=[qreg[2], qreg[3]],
111+
px_ctrl=0.1,
112+
py_ctrl=0.2,
113+
pz_ctrl=0.3,
114+
px_qarg=0.4,
115+
py_qarg=0.5,
116+
pz_qarg=0.6,
117+
paired=True,
118+
)
119+
120+
qasm2.u(qreg[2], theta=0.1, phi=0.2, lam=0.3)
121+
122+
main.print()
123+
124+
target = qasm2.emit.QASM2(allow_noise=True)
125+
out = target.emit_str(main)
126+
print(out)
127+
expected = """OPENQASM 2.0;
128+
include "qelib1.inc";
129+
qreg qreg[4];
130+
CX qreg[0], qreg[1];
131+
U(0.1, 0.2, 0.3) qreg[2];
132+
// native.CZPauliChannel(paired=True, p_ctrl=[x:0.1, y:0.2, z:0.3], p_qarg[x:0.6, y:0.5, z:0.6])
133+
// -: ctrls: qreg[0], qreg[1]
134+
// -: qargs: qreg[2], qreg[3]
135+
U(0.1, 0.2, 0.3) qreg[2];
136+
"""
137+
138+
assert out == expected

0 commit comments

Comments
 (0)