Source code for pytest_quantum.assertions.qasm

"""OpenQASM round-trip assertions."""

from __future__ import annotations


[docs] def assert_qasm2_roundtrip( circuit: object, *, atol: float = 1e-6, allow_global_phase: bool = True, ) -> None: """Assert a Qiskit circuit survives an OpenQASM 2.0 export/import round-trip. Exports the circuit via ``qiskit.qasm2.dumps`` and re-imports it via ``qiskit.qasm2.loads``, then compares unitaries. Note: QASM 2.0 has limited gate support. Circuits with custom/parametrised gates that lack QASM 2 definitions may fail — use ``assert_qasm_roundtrip`` (QASM 3) for those circuits. Args: circuit: Qiskit QuantumCircuit. atol: Tolerance for unitary comparison (default 1e-6). allow_global_phase: Ignore global phase in comparison (default True). Raises: AssertionError: If re-imported circuit has a different unitary. NotImplementedError: For non-Qiskit circuits. ImportError: If qiskit is not installed. Example:: from qiskit import QuantumCircuit from pytest_quantum import assert_qasm2_roundtrip qc = QuantumCircuit(2) qc.h(0) qc.cx(0, 1) assert_qasm2_roundtrip(qc) """ module = type(circuit).__module__ if not module.startswith("qiskit"): raise NotImplementedError( f"assert_qasm2_roundtrip only supports Qiskit QuantumCircuit; got {module!r}.\n" "For Cirq, use assert_qasm_roundtrip (QASM 3 / JSON round-trip)." ) try: from qiskit import qasm2 from pytest_quantum.assertions.unitary import assert_unitary from pytest_quantum.converters.to_unitary import to_unitary original_U = to_unitary(circuit) qasm_str = qasm2.dumps(circuit) reimported = qasm2.loads(qasm_str) except ImportError as exc: raise ImportError( "qiskit is required for assert_qasm2_roundtrip: pip install qiskit" ) from exc assert_unitary( reimported, original_U, atol=atol, allow_global_phase=allow_global_phase, )
[docs] def assert_qasm_roundtrip( circuit: object, *, atol: float = 1e-6, allow_global_phase: bool = True, ) -> None: """Assert that a circuit survives an export/import round-trip. For Qiskit: uses OpenQASM 3 (``qiskit.qasm3.dumps`` / ``qasm3.loads``). For Cirq: uses Cirq's native JSON serialisation (``cirq.to_json`` / ``cirq.read_json``), which provides an exact identity round-trip for all standard Cirq circuits. Args: circuit: Qiskit QuantumCircuit or cirq.Circuit. atol: Tolerance for unitary comparison (default 1e-6). allow_global_phase: Ignore global phase in comparison (default True). Raises: AssertionError: If re-imported circuit has a different unitary. NotImplementedError: For unsupported frameworks. ImportError: If the required package is missing. """ module = type(circuit).__module__ if module.startswith("qiskit"): try: from qiskit import qasm3 from pytest_quantum.converters.to_unitary import to_unitary original_U = to_unitary(circuit) qasm_str = qasm3.dumps(circuit) reimported = qasm3.loads(qasm_str) except ImportError as exc: raise ImportError( "qiskit-qasm3-import is required for QASM round-trip: " "pip install qiskit-qasm3-import" ) from exc elif module.startswith("cirq"): try: import cirq from pytest_quantum.converters.to_unitary import to_unitary original_U = to_unitary(circuit) # Use Cirq's native JSON serialisation for a true identity round-trip. # cirq.contrib.qasm_import is not available in modern Cirq. json_str = cirq.to_json(circuit) reimported = cirq.read_json(json_text=json_str) except ImportError as exc: raise ImportError( "cirq is required for Cirq round-trip: pip install cirq" ) from exc else: raise NotImplementedError( f"assert_qasm_roundtrip supports Qiskit and Cirq; got {module!r}. " "For Braket, use circuit.to_unitary() manually." ) # Compare unitaries using the existing assert_unitary helper from pytest_quantum.assertions.unitary import assert_unitary assert_unitary( reimported, original_U, atol=atol, allow_global_phase=allow_global_phase, )