Skip to content

Commit e33e6af

Browse files
authored
Raise error on invalid qasm2 if statement then body (#248)
1 parent 1d1c980 commit e33e6af

File tree

3 files changed

+91
-2
lines changed

3 files changed

+91
-2
lines changed

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ dependencies = [
1717
"rich>=13.9.4",
1818
"pydantic>=1.3.0,<2.11.0",
1919
"pandas>=2.2.3",
20-
"pyqrack>=1.38.2 ; sys_platform == 'darwin'",
21-
"pyqrack-cpu>=1.38.2 ; sys_platform != 'darwin'",
20+
"pyqrack>=1.38.2,<1.41; sys_platform == 'darwin'",
21+
"pyqrack-cpu>=1.38.2,<1.41 ; sys_platform != 'darwin'",
2222
]
2323

2424
[project.optional-dependencies]

src/bloqade/qasm2/emit/main.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@
55
from kirin.ir.dialect import Dialect as Dialect
66

77
from bloqade.qasm2.parse import ast
8+
from bloqade.qasm2.dialects.uop import SingleQubitGate, TwoQubitCtrlGate
9+
from bloqade.qasm2.dialects.expr import GateFunction
810

911
from .base import EmitQASM2Base, EmitQASM2Frame
12+
from ..dialects.core.stmts import Reset, Measure
1013

1114

1215
@dataclass
@@ -94,6 +97,24 @@ def emit_if_else(
9497

9598
cond = emit.assert_node(ast.Cmp, frame.get(stmt.cond))
9699

100+
# NOTE: we need exactly one of those in the then body in order to emit valid QASM2
101+
AllowedThenType = SingleQubitGate | TwoQubitCtrlGate | Measure | Reset
102+
103+
then_stmts = stmt.then_body.blocks[0].stmts
104+
uop_stmts = 0
105+
for s in then_stmts:
106+
if isinstance(s, AllowedThenType):
107+
uop_stmts += 1
108+
continue
109+
110+
if isinstance(s, func.Invoke):
111+
uop_stmts += isinstance(s.callee.code, GateFunction)
112+
113+
if uop_stmts != 1:
114+
raise interp.InterpreterError(
115+
"Cannot lower if-statement: QASM2 only allows exactly one quantum operation in the body."
116+
)
117+
97118
with emit.new_frame(stmt) as then_frame:
98119
then_frame.entries.update(frame.entries)
99120
emit.emit_block(then_frame, stmt.then_body.blocks[0])

test/qasm2/emit/test_qasm2_emit.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import pytest
2+
from kirin.interp import InterpreterError
3+
14
from bloqade import qasm2
25

36

@@ -221,3 +224,68 @@ def para_u():
221224
U(0.1, 0.2, 0.3) qreg[0];
222225
"""
223226
)
227+
228+
229+
def test_if():
230+
@qasm2.extended
231+
def non_empty_else():
232+
q = qasm2.qreg(1)
233+
c = qasm2.creg(1)
234+
qasm2.measure(q, c)
235+
236+
if c[0] == 1:
237+
qasm2.x(q[0])
238+
else:
239+
qasm2.y(q[0])
240+
241+
return q
242+
243+
target = qasm2.emit.QASM2()
244+
245+
with pytest.raises(InterpreterError):
246+
target.emit(non_empty_else)
247+
248+
@qasm2.extended
249+
def multiline_then():
250+
q = qasm2.qreg(1)
251+
c = qasm2.creg(1)
252+
qasm2.measure(q, c)
253+
254+
if c[0] == 1:
255+
qasm2.x(q[0])
256+
qasm2.y(q[0])
257+
258+
return q
259+
260+
target = qasm2.emit.QASM2()
261+
262+
with pytest.raises(InterpreterError):
263+
target.emit(multiline_then)
264+
265+
@qasm2.extended
266+
def valid_if():
267+
q = qasm2.qreg(1)
268+
c = qasm2.creg(1)
269+
qasm2.measure(q, c)
270+
271+
if c[0] == 0:
272+
qasm2.x(q[0])
273+
274+
return q
275+
276+
target = qasm2.emit.QASM2()
277+
target.emit(valid_if)
278+
279+
@qasm2.extended
280+
def nested_kernel():
281+
q = qasm2.qreg(1)
282+
c = qasm2.creg(1)
283+
qasm2.measure(q, c)
284+
285+
if c[0] == 0:
286+
valid_if()
287+
288+
return q
289+
290+
target = qasm2.emit.QASM2()
291+
target.emit(nested_kernel)

0 commit comments

Comments
 (0)