Chapter 6 — Key Takeaways (OpenQASM)
The serialization page. Consult it whenever a circuit crosses a boundary.
What QASM is for
APPLICATION → ALGORITHM → CIRCUIT → [OpenQASM] → TRANSPILER → PULSE → QPU
- A common target. Turns $N$ frameworks × $M$ devices into $N + M$. Same argument as LLVM IR.
- A stable boundary. A specification moves slower than a framework, so it is what you write to disk.
- Where the truth is written down. A
QuantumCircuitis a Python object; QASM has a grammar. - Readable at the right level — low enough to show what runs, high enough to read. Pulse schedules are neither.
OpenQASM 3, minimal
OPENQASM 3.0;
include "stdgates.inc";
bit[2] c;
qubit[2] q;
h q[0];
cx q[0], q[1];
c[0] = measure q[0]; // measurement is an ASSIGNMENT
c = measure q; // whole-register form
// and /* */ comments · free-form whitespace · semicolons · lowercase gate names.
The API
from qiskit import qasm2, qasm3
qasm3.dumps(qc) # -> str ✓
qasm3.loads(text) # str -> circuit ✓
qasm2.dumps(qc) / qasm2.loads(text)
qc.qasm() # ✗ REMOVED in Qiskit 1.0
⚠️
dumpandloadare not symmetric.qasm3.dump(circuit, stream)takes a file object;qasm3.load(filename)takes a path. Passing an open file toloadraises aTypeErrorthat reads like a broken handle.Habit that sidesteps it: use
dumps/loadswith strings and do your own file I/O. You also control the encoding and can prepend a comment line.
★ Reading transpiled QASM
gate ecr _gate_q_0, _gate_q_1 { s _gate_q_0; sx _gate_q_1; cx _gate_q_0, _gate_q_1; x _gate_q_0; }
bit[2] c;
rz(-pi) $0; sx $0; rz(-pi/2) $1; sx $1; rz(-pi) $1;
ecr $1, $0;
rz(-pi/2) $0; sx $0; rz(pi/2) $0; rz(pi/2) $1; sx $1; rz(pi/2) $1;
c[0] = measure $0; c[1] = measure $1;
| Feature | Meaning |
|---|---|
$0`, `$1 |
physical qubits — the layout decision, written down. Record it with every result |
gate ecr ... { } |
ecr is not in stdgates.inc, so it is defined in terms of gates you know |
no h, no cx |
they do not exist on this device |
7 × rz |
virtual — zero duration, zero error |
Real cost: 4 sx + 1 ecr = five operations out of twelve instructions.
Instruction count is not cost.
Extract four numbers from any transpiled circuit:
| Number | From | Tells you |
|---|---|---|
| physical qubits | the $n identifiers |
which layout |
| two-qubit gate count | count ecr/cz/cx |
whether SWAPs were inserted (compare to what you wrote) |
| real pulses | count sx + x |
true single-qubit cost |
| depth | isa.depth() |
coherence budget consumed |
Diff the QASM at two optimization levels — a precise record of every compiler decision:
difflib.unified_diff(qasm_at(qc, 0), qasm_at(qc, 3), "level 0", "level 3", lineterm="")
An empty diff is informative: it rules out compilation as the cause of a problem.
★ What a round trip loses
| Preserved? | |
|---|---|
| unitary (up to phase) | ✓ |
| custom gates, as named gates | ✓ |
| gate counts | ✓ |
| global phase | ✗ — silently |
| parameter names | ✗ — theta[0] → _theta_0_ |
| gate names | ✗ — a custom h returns as h_0 |
| layout | ✗ — a 127-qubit ISA circuit returns as 2 qubits |
All four losses share one property (§6.6): none is visible to count_ops, and none is visible to
Operator.equiv. Each is a property of the circuit that is not a gate, and both checks are
gate-level. Enumerate them; do not test for them.
Global phase. Harmless except under control, where it becomes a relative phase — phase
kickback. Measured: controlled-original → {'1': 1757}, controlled-archived → {'0': 1758}. The
answer inverted.
Why every plausible test misses it:
| Test | Result | Why blind |
|---|---|---|
Operator.equiv |
passes | compares up to global phase, by design |
| gate counts | passes | a phase is not a gate |
| measurement statistics | passes | the distributions are genuinely identical |
| QASM round-trips to a fixed point | passes | idempotent ≠ lossless |
A property unobservable in isolation can be load-bearing in composition. Test the composition.
Parameter names. [ and ] are illegal in an OpenQASM identifier. Fails loudly with a
KeyError, and a ParameterVector no longer round-trips as a vector.
Do not reproduce the exporter's mangling rule — it is an implementation detail. Normalize both sides by stripping non-alphanumerics:
theta[0]and_theta_0_both →theta0.
The fix — record out-of-band in comments (parsers ignore them; the file stays portable):
PHASE_COMMENT = "// vqelab: global_phase = "
PARAMS_COMMENT = "// vqelab: parameters = "
Or better, fail loudly at the boundary: raise rather than silently archive information the format cannot carry.
QASM 2 vs QASM 3
| QASM 2 | QASM 3 | |
|---|---|---|
| registers | qreg q[2]; creg c[2]; |
qubit[2] q; bit[2] c; |
| measurement | measure q[0] -> c[0]; |
c[0] = measure q[0]; |
| include | qelib1.inc |
stdgates.inc |
| free parameters | ✗ QASM2ExportError |
✓ input float[64] theta; |
| classical control | register equality only | ✓ full if/else, loops |
| physical qubits | ✗ | ✓ $0 |
| timing | ✗ | ✓ duration, delay |
QASM 2 is a circuit format; QASM 3 is a program format. Use QASM 2 for maximum interchange compatibility on static bound circuits; QASM 3 for anything with parameters, control flow, or timing.
QASM vs QPY
| QASM 3 | QPY | |
|---|---|---|
| cross-framework | ✓ | ✗ |
| human-readable | ✓ | ✗ |
| stable across versions | ✓ (a spec) | ✗ (Qiskit-versioned) |
| preserves global phase | ✗ | ✓ |
| preserves every Qiskit detail | ✗ | ✓ |
Use QASM to communicate and archive. Use QPY to checkpoint within one Qiskit version. Save both.
Common pitfalls
- Using
qc.qasm()from an old tutorial. - Passing an open file to
qasm3.load(). - Trusting
equivin a round-trip test when the phase matters. - Assuming specification-valid QASM 3 is accepted by every tool that claims QASM 3 support — test against the tool, not the spec.
- Editing QASM by hand as your primary workflow. Keep the source of truth in the framework; regenerate.
- Counting
rzas cost.
Project piece added this chapter
vqelab/qasm.py — to_qasm, from_qasm, archive, restore, check_round_trip.
Records both the global phase and the original parameter names as comments, so an archived
ansatz restores with theta[0]…theta[3] intact and its phase recovered. Chapter 22's QPE circuits
will be used as controlled operations, and the habit has to be in place before it is needed.