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,
)