Import and export restricted OpenQASM 3 circuits¶
Use import_program() and export_program() from cascaqit.interop to convert static digital circuits. The current parser accepts a defined subset of OpenQASM 3. A file’s version header does not guarantee that every statement can be converted.
Read a file into a string, then pass it to ProgramImportRequest(source_format="openqasm3", source=text). Check the returned program, diagnostics, unsupported_features and lossy_mappings before using the program. The default on_unsupported="diagnose" returns diagnostics; choose "raise" to request an exception.
Re-import the export and check a rejected statement¶
This example imports a rotation and controlled gate, exports the program and imports it again. It checks structure and the circuit’s local state probabilities, then replaces X with an unsupported reset to check rejection.
"""Check restricted OpenQASM conversion before using an imported program."""
from __future__ import annotations
import json
from cascaqit.digital import DigitalProgramIR
from cascaqit.interop import (
ProgramExportRequest,
ProgramImportRequest,
export_program,
import_program,
prove_openqasm3_round_trip,
)
from cascaqit.simulators import compare_digital_program_semantics
def main() -> None:
"""Inspect a valid conversion, a round trip and an unsupported reset."""
source = """
OPENQASM 3;
qubit[2] q;
bit[2] c;
ry(0.4) q[0];
cx q[0], q[1];
x q[1];
measure q[0] -> c[0];
measure q[1] -> c[1];
"""
imported = import_program(
ProgramImportRequest(source_format="openqasm3", source=source)
)
if (
not isinstance(imported.program, DigitalProgramIR)
or imported.unsupported_features
):
raise RuntimeError("The supported source did not produce a digital program.")
exported = export_program(
ProgramExportRequest(program=imported.program, target_format="openqasm3")
)
if not isinstance(exported.payload, str):
raise RuntimeError("The export did not produce OpenQASM source.")
restored = import_program(
ProgramImportRequest(source_format="openqasm3", source=exported.payload)
)
if not isinstance(restored.program, DigitalProgramIR):
raise RuntimeError("The exported source could not be imported again.")
structure = prove_openqasm3_round_trip(imported.program)
probabilities = compare_digital_program_semantics(
imported.program, restored.program
)
blocked = import_program(
ProgramImportRequest(
source_format="openqasm3", source=source.replace("x q[1];", "reset q[1];")
)
)
if (
structure.status != "passed"
or probabilities.status != "equivalent"
or blocked.program is not None
):
raise RuntimeError("The conversion checks did not match the supported subset.")
print(
json.dumps(
{
"exported_source": exported.payload,
"round_trip_status": structure.status,
"matched_fields": list(structure.matched_fields),
"probability_status": probabilities.status,
"maximum_probability_delta": probabilities.max_probability_delta,
"blocked_reset": blocked.program is None,
"reset_diagnostics": [item.code for item in blocked.diagnostics],
},
sort_keys=True,
)
)
if __name__ == "__main__":
main()
python examples/learning/guides/openqasm_interop_en.py
{
"blocked_reset": true,
"exported_source": "OPENQASM 3;\ninclude \"stdgates.inc\";\nqubit[2] q;\nbit[2] c;\nry(0.40000000000000002) q[0];\ncx q[0], q[1];\nx q[1];\nmeasure q[0] -> c[0];\nmeasure q[1] -> c[1];\n",
"matched_fields": [
"qubits",
"gates",
"measurements",
"bit_order",
"measurement_mapping"
],
"maximum_probability_delta": 0.0,
"probability_status": "equivalent",
"reset_diagnostics": [
"OPENQASM_RESET_UNSUPPORTED"
],
"round_trip_status": "passed"
}
Expect round_trip_status: passed; the checked fields include gates, measurements, bit order and classical-bit mapping. probability_status should be equivalent, with zero probability difference here. This compares computational-basis probabilities for this circuit, not full unitary equivalence on arbitrary input states.
Expect blocked_reset: true and OPENQASM_RESET_UNSUPPORTED. Returning a diagnostic does not remove reset or execute the remainder as a complete program.
Supported syntax and checks after conversion¶
| Content | Current treatment |
|---|---|
| Fixed-size qubit/bit arrays, numeric angles and terminal measurements | Accepted when written in the restricted syntax |
| I/X/Y/Z/H/S/SDG/T/TDG, RX/RY/RZ/P/U, CX/CY/CZ | Corresponding static gate statements are supported |
| SWAP export | Lowered to three CX gates; this does not imply support for importing a SWAP statement |
| Runtime conditions, loops, reset and intermediate measurements | Rejected or require external conversion first |
| Custom gates, defcal, delay, box and barrier | Outside the parser’s current subset |
| Arbitrary external SDK runtime objects | Not loaded or executed automatically |
The current measurement syntax is measure q[0] -> c[0];. Check parser results before relying on another equivalent spelling or expression. An export is ready to save as source only when payload contains a string; it is not a submitted device job.
Keep the original source, diagnostics, bit order and measurement mapping. Matching count strings alone cannot establish that gates, phases or ordering were preserved. See the bit-order lesson and package API map. When a format needs an adapter, the native SDK does not automatically import cascaqit-compat.