Skip to content

QASM2 boolean operation on measurement results fails code-gen #155

Open
@cduck

Description

@cduck

Bug report by https://github.com/randyshee/yquantum/blob/main/2025/team_solutions/charlie_and_delta/bug_report.ipynb

QASM2 supports a measurement operation followed by classical conditional logic on those measurement results. Bloqade fails to lower this logic if there is a boolean operation as seen in the if-statement below.

from bloqade import qasm2
from bloqade.qasm2.emit import QASM2 # the QASM2 target
from bloqade.qasm2.parse import pprint # the QASM2 pretty printer

@qasm2.extended
def circ_bool():
    qr = qasm2.qreg(4)
    cr = qasm2.creg(4)

    qasm2.measure(qr, cr)

    cond = cr[0] == 0 and cr[1] == 1  # Fails to lower boolean operation on measurement results
    if cond:
        qasm2.x(qr[3])

    # But this works instead
    #if cr[0] == 0:
    #    qasm2.creg(0)  # Dummy line to try to fix issue #157
    #    if cr[1] == 1:
    #        qasm2.x(qr[3])

    return qr


target = QASM2()
ast = target.emit(circ_bool)
pprint(ast)

Error:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[1], line 29
     25     return qr
     28 target = QASM2()
---> 29 ast = target.emit(circ_bool)
     30 pprint(ast)

File .../.venv/lib/python3.12/site-packages/bloqade/qasm2/emit/target.py:103, in QASM2.emit(self, entry)
    101 Py2QASM(entry.dialects)(entry)
    102 target_main = EmitQASM2Main(self.main_target)
--> 103 target_main.run(
    104     entry, tuple(ast.Name(name) for name in entry.arg_names[1:])
    105 ).expect()
    107 main_program = target_main.output
    108 assert main_program is not None, f"failed to emit {entry.sym_name}"

File .../.venv/lib/python3.12/site-packages/kirin/interp/base.py:146, in BaseInterpreter.run(self, mt, args, kwargs)
    144 args = self.get_args(mt.arg_names[len(args) + 1 :], args, kwargs)
    145 try:
--> 146     _, results = self.run_method(mt, args)
    147 except InterpreterError as e:
    148     # NOTE: initialize will create new State
    149     # so we don't need to copy the frames.
    150     return Err(e, self.state.frames)

File .../.venv/lib/python3.12/site-packages/bloqade/qasm2/emit/base.py:44, in EmitQASM2Base.run_method(self, method, args)
     41 def run_method(
     42     self, method: ir.Method, args: tuple[ast.Node | None, ...]
     43 ) -> tuple[EmitQASM2Frame[StmtType], ast.Node | None]:
---> 44     return self.run_callable(method.code, (ast.Name(method.sym_name),) + args)

File .../.venv/lib/python3.12/site-packages/kirin/interp/base.py:220, in BaseInterpreter.run_callable(self, code, args)
    218     return self.state.pop_frame(), self.void
    219 frame.set_values(body.blocks[0].args, args)
--> 220 results = self.run_callable_region(frame, code, body)
    221 return self.state.pop_frame(), results

File .../.venv/lib/python3.12/site-packages/kirin/emit/abc.py:26, in EmitABC.run_callable_region(self, frame, code, region)
     23 def run_callable_region(
     24     self, frame: FrameType, code: ir.Statement, region: ir.Region
     25 ) -> ValueType:
---> 26     results = self.eval_stmt(frame, code)
     27     if isinstance(results, tuple):
     28         if len(results) == 0:

File .../.venv/lib/python3.12/site-packages/kirin/interp/base.py:335, in BaseInterpreter.eval_stmt(self, frame, stmt)
    333 method = self.lookup_registry(frame, stmt)
    334 if method is not None:
--> 335     results = method(self, frame, stmt)
    336     if self.debug and not isinstance(results, (tuple, SpecialValue)):
    337         raise InterpreterError(
    338             f"method must return tuple or SpecialResult, got {results}"
    339         )

File .../.venv/lib/python3.12/site-packages/kirin/registry.py:19, in StatementImpl.__call__(self, interp, frame, stmt)
     18 def __call__(self, interp, frame, stmt: "Statement"):
---> 19     return self.impl(self.parent, interp, frame, stmt)

File .../.venv/lib/python3.12/site-packages/bloqade/qasm2/emit/main.py:26, in Func.emit_func(self, emit, frame, stmt)
     20 @interp.impl(func.Function)
     21 def emit_func(
     22     self, emit: EmitQASM2Main, frame: EmitQASM2Frame, stmt: func.Function
     23 ):
     24     from bloqade.qasm2.dialects import glob, noise, parallel
---> 26     emit.run_ssacfg_region(frame, stmt.body)
     27     if emit.dialects.data.intersection(
     28         (parallel.dialect, glob.dialect, noise.dialect)
     29     ):
     30         header = ast.Kirin([dialect.name for dialect in emit.dialects])

File .../.venv/lib/python3.12/site-packages/kirin/emit/abc.py:41, in EmitABC.run_ssacfg_region(self, frame, region)
     37 frame.worklist.append(
     38     interp.Successor(region.blocks[0], frame.get_values(region.blocks[0].args))
     39 )
     40 while (succ := frame.worklist.pop()) is not None:
---> 41     block_header = self.emit_block(frame, succ.block)
     42     frame.block_ref[succ.block] = block_header
     43 return ()

File .../.venv/lib/python3.12/site-packages/bloqade/qasm2/emit/base.py:48, in EmitQASM2Base.emit_block(self, frame, block)
     46 def emit_block(self, frame: EmitQASM2Frame, block: ir.Block) -> ast.Node | None:
     47     for stmt in block.stmts:
---> 48         result = self.eval_stmt(frame, stmt)
     49         if isinstance(result, tuple):
     50             frame.set_values(stmt.results, result)

File .../.venv/lib/python3.12/site-packages/kirin/interp/base.py:345, in BaseInterpreter.eval_stmt(self, frame, stmt)
    341 elif stmt.dialect not in self.dialects:
    342     # NOTE: we should terminate the interpreter because this is a
    343     # deveoper error, not a user error.
    344     name = stmt.dialect.name if stmt.dialect else "None"
--> 345     raise ValueError(f"dialect {name} is not supported by {self.dialects}")
    347 return self.eval_stmt_fallback(frame, stmt)

ValueError: dialect py.boolop is not supported by DialectGroup([func, scf, qasm2.uop, qasm2.indexing, qasm2.core, lowering.func, lowering.call, qasm2.expr])

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingloweringqasm2qasm2 related issues

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions