Spaces:
Runtime error
Runtime error
| """ | |
| lowering.py — spec → OpenQASM 3. | |
| The "lowering pass" from the architecture diagram. For the four circuit-builder | |
| actions (RANDOM, BELL, GROVER, QAOA) we build the circuit via `circuits.py` and | |
| emit OpenQASM 3. VQE is a variational procedure (many circuits), so it lowers to | |
| a description of its ansatz circuit rather than a single shot program. | |
| OpenQASM 3 emission uses the `openqasm3` package if available; otherwise we | |
| fall back to Qiskit's built-in QASM2 exporter so the pipeline never hard-fails | |
| on a missing optional dependency (useful in minimal local test envs). | |
| """ | |
| from __future__ import annotations | |
| from qiskit import QuantumCircuit | |
| from .spec import QuantumSpec | |
| from . import circuits | |
| def _emit(qc: QuantumCircuit) -> str: | |
| """ | |
| Emit a QuantumCircuit as OpenQASM 3, falling back to QASM 2. | |
| Exporter preference, most-expressive first: | |
| 1. `openqasm3.dumps` — true OpenQASM 3 (the architecture's target). | |
| 2. `qiskit.qasm2.dumps` — Qiskit 2.x's stable QASM2 exporter. | |
| 3. legacy `QuantumCircuit.qasm()` — older Qiskit versions only. | |
| The pipeline must never hard-fail on a missing exporter. | |
| """ | |
| try: | |
| import openqasm3 # noqa: WPS433 | |
| return openqasm3.dumps(qc) | |
| except ImportError: | |
| pass | |
| try: | |
| from qiskit import qasm2 # Qiskit 2.x | |
| return qasm2.dumps(qc) | |
| except Exception: | |
| pass | |
| fn = getattr(qc, "qasm", None) # legacy, pre-2.0 | |
| if callable(fn): | |
| return fn() | |
| raise RuntimeError("No QASM exporter available on this Qiskit version.") | |
| def lower(spec: QuantumSpec) -> tuple[str, QuantumCircuit]: | |
| """ | |
| Lower a validated spec to (qasm_source, circuit). | |
| Returns a 2-tuple so the caller gets the OpenQASM text for the receipt / | |
| UI without re-exporting, and the live circuit object for execution. | |
| """ | |
| if spec.action == "VQE": | |
| # VQE is variational; emit the ansatz template at θ=0 as the canonical | |
| # representative. The engine re-parameterises it during optimisation. | |
| qc = circuits.vqe_ansatz(0.0) | |
| qasm = _emit(qc) | |
| return qasm, qc | |
| builder = circuits.BUILDERS[spec.action] | |
| qc = builder(spec) | |
| qasm = _emit(qc) | |
| return qasm, qc | |