diff --git a/src/pyqasm/modules/base.py b/src/pyqasm/modules/base.py index 07d77f64..5b6890cb 100644 --- a/src/pyqasm/modules/base.py +++ b/src/pyqasm/modules/base.py @@ -518,7 +518,23 @@ def validate(self): self._validated_program = True def unroll(self, **kwargs): - """Unroll the module into basic qasm operations""" + """Unroll the module into basic qasm operations. + + Args: + **kwargs: Additional arguments to pass to the QasmVisitor. + external_gates (list[str]): List of gates that should not be unrolled. + unroll_barriers (bool): If True, barriers will be unrolled. Defaults to True. + check_only (bool): If True, only check the program without executing it. + Defaults to False. + + Raises: + ValidationError: If the module fails validation during unrolling. + UnrollError: If an error occurs during the unrolling process. + + Notes: + This method resets the module's qubit and classical bit counts before unrolling, + and sets them to -1 if an error occurs during unrolling. + """ if not kwargs: kwargs = {} try: diff --git a/src/pyqasm/visitor.py b/src/pyqasm/visitor.py index 6dce1837..4c9ec5c9 100644 --- a/src/pyqasm/visitor.py +++ b/src/pyqasm/visitor.py @@ -55,9 +55,17 @@ class QasmVisitor: initialize_runtime (bool): If True, quantum runtime will be initialized. Defaults to True. record_output (bool): If True, output of the circuit will be recorded. Defaults to True. external_gates (list[str]): List of gates that should not be unrolled. + unroll_barriers (bool): If True, barriers will be unrolled. Defaults to True. + check_only (bool): If True, only check the program without executing it. Defaults to False. """ - def __init__(self, module, check_only: bool = False, external_gates: list[str] | None = None): + def __init__( + self, + module, + check_only: bool = False, + external_gates: list[str] | None = None, + unroll_barriers: bool = True, + ): self._module = module self._scope: deque = deque([{}]) self._context: deque = deque([Context.GLOBAL]) @@ -74,6 +82,7 @@ def __init__(self, module, check_only: bool = False, external_gates: list[str] | self._external_gates: list[str] = [] if external_gates is None else external_gates self._subroutine_defns: dict[str, qasm3_ast.SubroutineDefinition] = {} self._check_only: bool = check_only + self._unroll_barriers: bool = unroll_barriers self._curr_scope: int = 0 self._label_scope_level: dict[int, set] = {self._curr_scope: set()} @@ -597,6 +606,9 @@ def _visit_barrier(self, barrier: qasm3_ast.QuantumBarrier) -> list[qasm3_ast.Qu if self._check_only: return [] + if not self._unroll_barriers: + return [barrier] + return unrolled_barriers def _get_op_parameters(self, operation: qasm3_ast.QuantumGate) -> list[float]: diff --git a/tests/qasm3/test_barrier.py b/tests/qasm3/test_barrier.py index 654d0ed8..7d122bd0 100644 --- a/tests/qasm3/test_barrier.py +++ b/tests/qasm3/test_barrier.py @@ -125,6 +125,36 @@ def test_remove_barriers(): check_unrolled_qasm(dumps(module), expected_qasm) +def test_unroll_barrier(): + qasm_str = """ + OPENQASM 3.0; + include "stdgates.inc"; + + qubit[2] q1; + qubit[3] q2; + qubit q3; + + // barriers + barrier q1, q2, q3; + barrier q2[:3]; + barrier q3[0]; + """ + expected_qasm = """OPENQASM 3.0; + include "stdgates.inc"; + qubit[2] q1; + qubit[3] q2; + qubit[1] q3; + barrier q1, q2, q3; + barrier q2[:3]; + barrier q3[0]; + """ + module = loads(qasm_str) + assert module.has_barriers() is True + module.unroll(unroll_barriers=False) + assert module.has_barriers() is True + check_unrolled_qasm(dumps(module), expected_qasm) + + def test_incorrect_barrier(): undeclared = """