open-standards/wai/wai-quantum/docs/qasm-feature-matrix.md
Transaction Science 92988ee70a
Some checks failed
WAI operation catalogue / does this change touch it (push) Successful in 13s
wai-quantum contract / does this change touch it (push) Successful in 24s
wai-audit collector and player integration / does this change touch it (push) Successful in 29s
wai-quantum command line / does this change touch it (push) Successful in 26s
wai-quantum resource estimation / does this change touch it (push) Successful in 23s
wai-quantum other formats / does this change touch it (push) Successful in 19s
wai-quantum pulse and dynamics / does this change touch it (push) Successful in 14s
wai-quantum editors / does this change touch it (push) Successful in 42s
wai-quantum error correction and mitigation / does this change touch it (push) Successful in 15s
wai-quantum for JavaScript / does this change touch it (push) Successful in 45s
wai-quantum docs, course and locales / does this change touch it (push) Successful in 58s
wai-quantum OpenQASM reader / does this change touch it (push) Successful in 44s
wai-quantum for Python / does this change touch it (push) Successful in 41s
wai-quantum verdicts and repairs / does this change touch it (push) Successful in 16s
wai-quantum views in agent hosts / does this change touch it (push) Successful in 16s
wai-sink-android native sink library / does this change touch it (push) Successful in 17s
wai-sink-swift native sink package / does this change touch it (push) Successful in 16s
wai-quantum variational and algorithm library / does this change touch it (push) Successful in 43s
WAI Studio / does this change touch it (push) Successful in 38s
wai-quantum studio and desktop / does this change touch it (push) Successful in 1m10s
wai-quantum service / does this change touch it (push) Successful in 1m12s
wai-quantum extension points / does this change touch it (push) Successful in 1m20s
wai-quantum service / service energy · linux packages (push) Successful in 2m14s
wai-quantum variational and algorithm library / parameters, gradients, optimisers, VQE, QAOA and builders · linux-arm64, release (push) Successful in 2m37s
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (push) Successful in 5m11s
wai-quantum pulse and dynamics / the same bits · linux-arm64 (push) Successful in 3m58s
wai-sink-android native sink library / the JNI layer and the platform-free half on the host JVM · linux-arm64 (push) Successful in 5m21s
wai-quantum extension points / the registry and the example · linux-arm64 (push) Successful in 6m18s
WAI breaking changes and the conformance runner / WAI breaking · does this change touch WAI (push) Successful in 13s
wai-quantum contract / the policy is linked, and the deprecations page reads (push) Successful in 14s
wai-quantum wasmQ / does this change touch it (push) Successful in 19s
wai-quantum contract / API compatibility · linux (push) Successful in 5m15s
wai-quantum other formats / the set under wasm32-wasip2 (wasmtime) (push) Successful in 2m56s
wai-quantum pulse and dynamics / reader, simulator and pulse jobs under wasm32-wasip2 (wasmtime) (push) Successful in 1m44s
wai-audit collector and player integration / collector · linux (push) Successful in 5m35s
wai-quantum other formats / readers, writers and the set · linux (push) Successful in 4m39s
wai-quantum docs, course and locales / the Studio's words in every locale · linux (push) Successful in 18s
wai-quantum pulse and dynamics / reader, simulator and pulse jobs · linux, release (push) Successful in 4m5s
wai-quantum editors / editors · linux (push) Successful in 3m23s
WAI operation catalogue / the catalogue and every door · linux (push) Successful in 10m7s
wai-quantum OpenQASM reader / corpus under wasm32-wasip2 (wasmtime) (push) Successful in 1m2s
wai-quantum for JavaScript / javascript · linux (push) Successful in 3m54s
wai-quantum for Python / python · linux (push) Successful in 4m10s
wai-quantum verdicts and repairs / the intent set and the verdict under wasm32-wasip2 (wasmtime) (push) Successful in 1m47s
wai-quantum verdicts and repairs / verdicts, repairs and the intent set · linux (push) Successful in 2m33s
wai-quantum resource estimation / estimation and calibration · linux, release (push) Successful in 11m12s
wai-quantum docs, course and locales / the course and the command line's languages · linux (push) Successful in 6m33s
wai-quantum OpenQASM reader / reader and corpus · linux (push) Successful in 5m0s
wai-quantum error correction and mitigation / codes, decoders, texts and mitigation · linux, release (push) Successful in 7m55s
WAI Studio / the catalogue's actions, the unit tests and the core · linux (push) Successful in 1m1s
wai-quantum variational and algorithm library / parameters, gradients, optimisers, VQE, QAOA and builders · linux, release (push) Successful in 2m14s
wai-quantum contract / schemas and the committed tool lists · linux (push) Successful in 14m42s
wai-quantum views in agent hosts / views · the page and its engine (push) Successful in 4m29s
wai-quantum extension points / the registry under wasm32-wasip2 (wasmtime) (push) Successful in 2m10s
wai-quantum views in agent hosts / views · a scripted host (push) Successful in 4m21s
wai-quantum extension points / the registry and the example · linux (push) Successful in 6m25s
wai-quantum studio and desktop / studio · browser (push) Successful in 6m12s
wai-quantum service / service · linux (push) Successful in 8m55s
wai-quantum studio and desktop / desktop app · linux (push) Successful in 12m2s
wai-quantum docs, course and locales / every command and snippet in the docs · linux (push) Successful in 24m28s
wai-audit collector and player integration / collector, player integration and the browser end to end · macos (push) Successful in 3m14s
wai-quantum pulse and dynamics / the same bits · macos (push) Successful in 1m28s
wai-quantum command line / command line · macos (push) Successful in 2m16s
wai-quantum editors / editors · macos (push) Successful in 1m54s
wai-quantum for Python / python · macos (push) Successful in 3m12s
WAI Studio / Studio in WebKit · linux (push) Successful in 29m22s
WAI breaking changes and the conformance runner / WAI breaking · wire, record and API against main · linux (push) Failing after 1m52s
wai-sink-android native sink library / every ABI, the AAR, and the instrumented tests in a headless emulator · macos (push) Successful in 5m17s
wai-quantum studio and desktop / desktop app · windows (push) Successful in 10m14s
wai-quantum wasmQ / the reference modules rebuild to their modules of record · linux (push) Failing after 32s
wai-quantum studio and desktop / desktop app · macos (push) Successful in 5m50s
WAI Studio / Studio in Chromium and Firefox · macos (push) Successful in 8m5s
wai-quantum wasmQ / profile, engines, reference modules, adversarial, vectors · linux (push) Successful in 4m5s
wai-quantum service / service · macos (push) Successful in 6m20s
wai-quantum wasmQ / interpreter and vectors under wasm32-wasip2 (wasmtime) (push) Successful in 5m13s
WAI breaking changes and the conformance runner / WAI breaking and conform · their tests, and the independent verifiers through wai conform · linux (push) Successful in 9m42s
wai-quantum command line / command line · linux (push) Successful in 53m22s
wai-sink-swift native sink package / libwai slices, desktop tests, simulator tests · macos (push) Successful in 17m49s
wai-quantum wasmQ / profile, engines, reference modules, adversarial, vectors · macos (push) Successful in 2m6s
wai-quantum: qelib1.inc's remaining gates, and an import corpus of exported programs with their outcome probabilities
qelib1.inc's gates past the table of standard gates (u0, csx, c3x, c3sqrtx,
c4x, rccx, rc3x), which OpenQASM 2 programs call without defining, were
refused as unknown (Q103). They are built in as qelib1.inc defines them: u0
an idle; csx, c3x, c3sqrtx and c4x sx and x under that many controls; rccx
and rc3x the relative-phase Toffoli gates by their definitions, each
u2(0,π) there a Hadamard. A program's own definition of one still runs
instead. qasm::spec_tests::qelib1_s_gates_past_the_table_are_its_gates holds
each to its gate (rccx entry by entry; rc3x to c3x's moves).

quantum-conformance/qasm3/import/: 13 programs written as the common
toolkits export them (generated gate definitions, physical qubits, if and
switch blocks on measured bits, untyped loop variables, OpenQASM 2 with
qelib1.inc) and textbook algorithms (phase estimation through
ctrl @ pow(2 ** j) @ and inv @ on the program's own gates,
Bernstein-Vazirani through a subroutine, Grover, teleportation, repeat until
success, stdgates.inc's definitions written out under ctrl @), each with
its outcome probabilities derived by hand in its comments and its bit-exact
expectation; and 8 refusal vectors with their codes. The corpus goes from
59 cases to 80. Its runner now holds a program that branches on what it
measured to a distribution too, following every branch of every
measurement and reset with its probability.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-10 14:34:21 -05:00

298 lines
25 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# OpenQASM 3.1: what the reader does with each construct
The reader (`wai_quantum::qasm`) is the one grammar every surface takes: the job
service, the command line, both MCP servers, the Studio, the desktop app, the
edge component and the in-browser IDE. This page lists every construct of
OpenQASM 3.1, and the OpenQASM 2 forms in common use, with what the reader does
with it, what the bit-exact path does with it, and the diagnostic code each
gives (`qasm-diagnostics.md` has the table of codes).
What the reader does (the **Status** column):
- **supported**: read as the language defines it.
- **lowered**: read and lowered exactly to the engine's gates and steps.
- **carried**: kept in the program as written (timing, outputs); it changes
nothing a method computes, and the result says so where it matters.
- **preserved**: kept verbatim for export, never executed.
- **refused**: the program is not read: the refusal names the line, says what
to write instead, and ends with its code.
A program read is one program for every method. Its classical values are worked
out on reading in the reader's own arithmetic, the same bits on every platform:
integers, bits and sized angles exactly, floats as IEEE doubles rounded to their
declared width, the built-in functions by the crate's own functions. Its gates'
angles are doubles. A method then runs it at the accuracy it states (the
methods resource gives each one's class): `exact` bit-exact, `statevector` in
double precision, and so on.
What the bit-exact path does (the **Bit-exact** column) is the method `exact`,
`qasm::exact_circuit`, `qasm::dyadic_circuit` (the in-browser IDE) and
`quantum_toolchain::from_qasm`. It takes the program the reader gives, under its
own restriction, refusing with a code what it cannot hold exactly and never
rounding it:
- **same**: it runs what the reader read, to the bit.
- **dyadic**: it runs it when every angle is a dyadic multiple of 2π
(`2πm/2^k`, `k ≤ 32`: `pi/4`, `3*pi/8`, an `angle[n]` with `n ≤ 32`), and
refuses any other angle (Q500); the double-precision methods take it.
- **Q502**: a program that measures a qubit and then acts on it, resets one
after its first gate, or acts on measured bits; `statevector` and
`stabilizer` run it.
- It holds at most 255 qubits (Q501).
The conformance corpus (`wai/quantum-conformance/qasm3/`) holds the
specification's example programs, a program for each construct below, and
programs written as the common toolkits export them, each with what the reader
must do with it (outcome probabilities among them); CI runs it natively, under
wasm32-wasip2 and in the browser build.
## One reader
There is one front end. Text becomes tokens (`qasm::lex`), the tokens
statements (`qasm::parse`), and the statements one program (`qasm::elab`):
its gates, which bit each measurement writes, its steps where it branches, and
what it carries (outputs, timing, calibrations). Every entry point runs those
three stages: `read` and `read_with` (every surface), `read_whole` (a gate under
many controls held as one op), `read_callouts` (the hybrid profile's `extern`
calls as steps), `tangents` (each gate's derivative by the program's
parameters), and `parse`, `parse_with` and `parse_lines`, which give the same
reading with a string for its refusal.
Each method lowers that one program: `Program::matrices` and `sv_ops` for the
methods in double precision, `local_matrices` for `mps`, `rotations` for
`pauli`, `clifford` and `clifford_t` for `stabilizer` and `stabilizer_rank`,
and `dyadic` and `dyadic_native` for the bit-exact method. The bit-exact path
is a lowering of the reader's program, not a second reader. A job that names no
method is planned: `auto` tries `exact` among the first for counts and
expectation values, and a program it refuses (an angle not dyadic, Q500; a
measurement in the middle, Q502) goes to the next method, the plan saying why
and the result naming the method and its accuracy class. A job that names
`exact` for such a program is refused with that code, never run another way.
## Program structure
| Construct | Status | Codes | Bit-exact |
|---|---|---|---|
| `OPENQASM 3.1;`, `OPENQASM 3;`, `OPENQASM 2.0;`, or none | supported; another version is read as OpenQASM 3 | Q010 | same |
| `include "stdgates.inc"`, `include "qelib1.inc"` | supported: the libraries are built in | Q012 | same |
| `include` of any other file | warned: its definitions are not read | Q011 | same |
| Comments `//` and `/* */` | supported; an unclosed block comment is refused | Q003 | same |
| Identifiers, Unicode letters included (`θ`, `π`) | supported | | same |
| Statements and blocks `{ }`, scopes | supported; qubits, gates, subroutines and externs are declared at the top level | Q105 | same |
| Nesting: statements in blocks and bodies, parentheses, operators, brackets, calls, casts and types | supported to 64 levels together in the text (a statement, each enclosing statement, and each level of its expressions' trees count one). A run of operators of one precedence (`a + b - c`, `c[0] && c[1] && …`) is one level, and an `else if` chain one level, at any length: both are read and run in loops, left to right. Deeper is refused, never read by a recursion that could run out of stack; an array has at most 7 dimensions | Q006 | same |
| Nesting in all, through the gates and subroutines a program calls | supported to 256 levels (each statement, expression and call the reader runs counts one), and calls 32 deep; deeper is refused. Both hold: a recursive subroutine whose body nests more than about seven levels reaches 256 before 32 calls | Q006, Q209 | same |
| What a program holds on reading: its classical values, gates, steps, measurements and timing | supported to 64 MiB for one value (an array or a bit register, each element counted at its width) and 512 MiB in all; more is refused before it is made. Making or copying a value counts toward the reader's 20 000 000 steps at one step for every 128 bytes, and an element read from an array copies the element alone | Q130, Q312 | same |
| `pragma …`, `#pragma …`, annotations `@keyword …` | warned: kept, not applied; `@wai.max_iterations N` bounds the `while` after it | Q013 | same |
## Literals
| Construct | Status | Codes | Bit-exact |
|---|---|---|---|
| Integers: decimal, `0x`, `0o`, `0b`, with `_` | supported | Q002 | same |
| Floats, exponents, `.5` | supported | Q002 | dyadic |
| Imaginary `2.5im` | supported | | same |
| `true`, `false` | supported | | same |
| Bit strings `"0101"` (the first character the highest bit) | supported | Q110 | same |
| Durations `ns`, `us`, `µs`, `ms`, `s`, `dt` | supported | Q406 | same |
| `pi` `π`, `tau` `τ`, `euler` `ℯ` | supported; not redeclarable | Q106 | dyadic |
## Declarations and types
| Construct | Status | Codes | Bit-exact |
|---|---|---|---|
| `qubit q;`, `qubit[n] q;`, `qreg q[n];` | supported (at most 65 536 qubits) | Q101, Q105, Q111 | same, at most 255 qubits (Q501) |
| Physical qubits `$0`, `$1` | supported, in a program that declares none | Q124 | same |
| `bit c;`, `bit[n] c;`, `creg c[n];` | supported: written by measurement; a value known on reading (`bit[2] f = "11";`) is held until a measurement writes the bit, and a bit that still holds 1 at the end with no measurement writing it is refused, since the results carry what measurement writes | Q319 | same |
| A bit declared inside a block or a subroutine | lowered: a bit of its own, which the steps read and the results do not show | Q322 | Q502 where the steps read it |
| `int`, `int[n]`, `uint`, `uint[n]` (n ≤ 64) | supported; range-checked: arithmetic that leaves the type's range is refused, never wrapped; `~` and `<<` on a `uint[n]` act on its n bits, a bit shifted past the highest gone | Q112, Q122 | same |
| `float`, `float[16]`, `float[32]`, `float[64]` | supported, rounded to the width as defined; `float[128]` refused | Q121, Q122 | dyadic |
| `angle`, `angle[n]` (n ≤ 64) | supported: `angle[n]` holds n bits of a turn; a float cast to it rounds to the nearest, a tie to the even one; `+`, `-`, `*` and `/` by an integer wrap as the language defines; an `angle[n]` divided by an `angle[n]` is the `uint[n]` quotient of their bits | Q121 | same for `n ≤ 32`; a finer angle dyadic |
| `complex`, `complex[float[n]]` | supported; a complex gate parameter is refused | Q110 | same |
| `bool` | supported | | same |
| `duration` | supported: SI units and `dt`, not mixed | Q406 | same |
| `stretch` | carried by name, or as the expression that holds it, for a scheduler | Q403 | same |
| `array[T, d1, d2, …]`, nested values, `sizeof` | supported | Q107, Q110 | same |
| `const` | supported: known on reading; not assignable | Q127 | same |
| `input int n;`, `input uint n;` | supported: given when the program is read (a generator) | Q114 | same |
| `input float theta;`, `input angle phi;` | a parameter: a job's `params` binds it as a `const` at exactly the double given before the program is read (left without a value, the job is refused with Q114 and J050); the reader alone gives it no value | Q115 | dyadic, once bound |
| a parameter followed into a gradient | supported through arithmetic, the built-in functions, loops and gate definitions into gates' arguments; refused under a modifier, in a classical variable, a condition, an index, a size, a loop's range, a subroutine, or a type that rounds it | Q129 | not used |
| `output` | carried into the result: a bit register's places in each outcome, or a value | Q600, Q601 | same |
| `let a = q[0:2] ++ r;` | supported; a `let` that reuses an enclosing scope's name is refused | Q101 | same |
| `extern f(…) -> T;` | supported as a declaration; a call is refused (the hybrid profile runs it, extensions/quantum-wasmq.md) | Q125 | same |
## Indexing
| Construct | Status | Codes | Bit-exact |
|---|---|---|---|
| `q[i]`, negative `q[-1]` | supported | Q107 | same |
| Slices `q[a:b]`, `q[a:s:b]`, `q[a:]`, `q[:]`, both ends included | supported | Q107, Q313 | same |
| Index sets `q[{0, 2, 5}]` | supported | Q107 | same |
| Multi-dimensional `m[i, j]`, `m[i][j]`, array slices and slice assignment | supported | Q107, Q110 | same |
| An integer's bits `k[i]` | supported | | same |
## Expressions
| Construct | Status | Codes | Bit-exact |
|---|---|---|---|
| `+ - * / % **`, unary `-`, with the specification's precedence (`-2**2` is −4, `**` right to left) | supported; integer division truncates toward zero; integer overflow refused | Q112, Q113 | same |
| Integer division with a remainder used as a real (`1/2` in a gate) | refused: OpenQASM 3 truncates it, OpenQASM 2 does not; in a program that says `OPENQASM 2` it is 0.5 | Q118 | same |
| `& \| ~ << >>` | supported on integers and bits, on a `uint[n]` its n bits (`~` of a `uint[4]` 3 is 12); on angles refused | Q110 | same |
| `^` | exclusive or in an OpenQASM 3 program; a power in OpenQASM 2; between integers with no version stated it is refused, between reals read as a power with a warning | Q119, Q120 | same |
| `== != < <= > >=`, `&& \|\| !` | supported | | same |
| Casts `int[8](x)`, `float(x)`, `angle[n](b)`, `bit[n](i)`, `bool(x)` | supported (a cast to `int` truncates; bits to a signed integer of their width read as two's complement) | Q123 | same |
| `sin cos tan arcsin arccos arctan exp log ln sqrt ceiling floor mod pow popcount rotl rotr real imag sizeof` | supported, computed with the crate's own functions, the same bits on every platform | Q104 | dyadic where they give an angle |
| `durationof({ … })` | refused: it needs gate durations the program does not give | Q405 | same |
| Arithmetic on measured bits at run time (`int k = c;`) | refused: the steps branch on bits and hold no other run-time value | Q306 | same |
| A value that depends on a measurement where one is needed on reading | refused | Q116 | same |
| `++` between arrays outside a `let` | refused | Q004 | same |
## Gates
| Construct | Status | Codes | Bit-exact |
|---|---|---|---|
| `U(θ, φ, λ)`, `gphase(θ)` | supported as the specification defines them: `U` is `e^{iθ/2}` times OpenQASM 2's matrix, a phase a control sees (`ctrl @ U(θ, φ, λ)` is `cu(θ, φ, λ, θ/2)`); a global phase is dropped, and under controls is a phase on the controls. In a program that says `OPENQASM 2`, `U` is OpenQASM 2's (`u3`) | Q206 | dyadic |
| The standard library: `p x y z h s sdg t tdg sx rx ry rz cx cy cz cp crx cry crz ch swap ccx cswap cu CX phase cphase id u1 u2 u3`, and `sxdg iswap rxx ryy rzz ccz cnot toffoli fredkin u cu1 cu3` | supported, each checked against its definition in `U`, `gphase` and `CX`, global phase included (`cu(θ, φ, λ, γ)` is controlled `e^{iγ}` times OpenQASM 2's `U`; `u3` and `u2` are OpenQASM 2's `U`, `e^{−i(θ+φ+λ)/2} U(θ, φ, λ)`; `CX` is `cx`, as the specification names it) | Q012 | dyadic |
| `gate name(params) qubits { … }` | lowered: inlined at each call | Q200, Q212 | dyadic |
| A `gate` under a name the reader has built in (`gate h a { … }`, `gate iswap a, b { … }`) | lowered: the program's own definition is the gate it runs, noted, unless it is the built-in gate exactly, global phase included (up to a global phase in a program that says `OPENQASM 2`), when the built-in gate stands in its place; `U` and `gphase` are the language's and cannot be defined | Q213, Q106 | dyadic |
| `opaque` gates | refused at a call: no matrix | Q126 | same |
| A call on whole registers (broadcast) | supported | Q108 | same |
| A gate's duration `x[20ns] q;` | carried in the timing | Q407 | same |
| Wrong parameters or qubits, a qubit named twice, an unknown gate | refused | Q103, Q104, Q109 | same |
| A gate body that indexes its qubit argument (`a[0]`) | read: the argument is one qubit, and `a[0]` is that qubit (the specification forbids the form) | | same |
## Modifiers
| Construct | Status | Codes | Bit-exact |
|---|---|---|---|
| `ctrl @`, `ctrl(n) @`, `negctrl @`, `negctrl(n) @` on any gate, user gates included | lowered exactly, the global phases its gates carry made phases on the controls (a negative control is a control between two `x`); at most 16 added controls in standard gates. A job on `statevector` holds a gate whose standard gates would double as one operation, under as many as 255, and lowers it only where a method needs standard gates (`qasm::read_whole`); `exact` does so only when asked (`"options": {"controls": "whole"}`), since its bits are those of the gates it applies. Those gates are `x`, `y`, `z` and `h` under three or more controls and `s`, `sdg`, `t`, `tdg`, `p`, `rx`, `ry`, `rz`, `u`, `sx` and `sxdg` under two or more, each lowered to the method's gates under its controls (`sx` as `h s h`, `ry` as `sdg h rz h s`), and not `p(pi)`, which is `z`. A job with an `intent` is held to 16: an intent is checked in standard gates, while a verdict with none reads the program as it ran | Q201, Q207, Q208 | dyadic; a controlled gate held whole under all its controls |
| `inv @` on any gate | lowered exactly: each gate's inverse, in reverse order, `gphase(a)` as `gphase(−a)` | Q202 | dyadic |
| `pow(k) @`, `k` a whole number | lowered exactly: angles scaled or the gate repeated; negative `k` repeats the inverse | Q203 | dyadic |
| `pow(r) @`, `r` fractional | lowered where an exact principal root exists (`pow(1/2) @ x` is `sx`; rotations by less than 2π; phases; controlled forms; one such gate written in `U` with global phases that cancel, as the libraries write `x` and `rx`); refused otherwise (`u`, `cu`, user gates of several gates) | Q204, Q205 | dyadic |
| A modifier on a subroutine, or nested as deep as 32 | refused | Q211, Q209 | same |
| A chain of modifiers (`inv @ inv @ …`) | read at any length: a list, not a nesting | | same |
## Measurement and reset
| Construct | Status | Codes | Bit-exact |
|---|---|---|---|
| `c = measure q;`, `c[0] = measure q[0];`, `bit c = measure q;` | supported | Q321 | same, at the end |
| `measure q -> c;` | supported | Q321 | same, at the end |
| `measure q;` | supported where no bit register is declared, and refused in a program that calls externs | Q320, Q324 | same, at the end |
| Mid-circuit measurement, measurement again, a gate after it | lowered: the program runs as steps (counts by shot splitting, exact expectation values) | | Q502 |
| `reset q;` | supported: before a qubit's first gate it changes nothing; after it, the program runs as steps | | same before the first gate; Q502 after |
| `barrier`, `barrier q;` | carried in the timing | Q404 | same |
## Classical control
| Construct | Status | Codes | Bit-exact |
|---|---|---|---|
| `if`/`else` known on reading | decided on reading | Q300 | same |
| `if`/`else` on measured bits: `c[0]`, `c == 3`, `c >= 2`, `int[2](c) != 0`, with `&&`, `\|\|`, `!` | lowered: steps that branch forward | Q301, Q302, Q304, Q305, Q307 | Q502 |
| A bit register of several bits as a condition (`if (c)`) | refused: compare it with a number | Q303 | same |
| `for` over a range (both ends included), a set or an array | lowered: unrolled | Q308, Q313, Q312 | same |
| `while` known on reading | lowered: unrolled until it fails (at most 1 000 000 times) | Q309, Q312 | same |
| `while` on measured bits | lowered under `@wai.max_iterations N`, with a warning that runs still meeting the condition stop there; refused with no bound | Q310, Q311 | Q502 |
| `switch` / `case` / `default` | decided on reading, or a chain of conditions on measured bits | Q317 | same, or Q502 on measured bits |
| `break`, `continue` | supported; under a condition on measured bits, jumps forward | Q316, Q314 | same, or Q502 on measured bits |
| `end` | supported | Q316 | same |
## Subroutines
| Construct | Status | Codes | Bit-exact |
|---|---|---|---|
| `def f(T x, qubit q, qubit[n] r) -> T { … }` | lowered: inlined, classical arguments by value, qubits by reference | Q318, Q104 | same |
| `return v;`, `return measure q;` | supported; a returned measurement writes the caller's bit | Q315 | same, or Q502 |
| `readonly` / `mutable` array arguments, `#dim` | supported as references: a `mutable` one writes back to the array it was given, a slice or row of one included; a `readonly` one is not written | Q131, Q127 | same |
| Bits declared in a subroutine | lowered: bits of its own, fed forward | Q322 | Q502 where the steps read them |
| A subroutine called as a gate (`f(1) q, r;`) | supported | | same |
| Recursion | refused past 32 calls deep | Q209 | same |
## Timing
| Construct | Status | Codes | Bit-exact |
|---|---|---|---|
| `delay[d] q;` | carried | Q401 | same |
| `box`, `box [d]` | carried, around the gates it holds | Q402 | same |
| `stretch` | carried | Q403 | same |
| Durations in a result | no method applies them; a result of a program that states durations says so (`timing.applied: false`) | Q400 | same |
## Calibration (OpenPulse)
| Construct | Status | Codes | Bit-exact |
|---|---|---|---|
| `defcalgrammar "openpulse";` | preserved; in a pulse run, read (another grammar is refused) | Q452, Q454 | same |
| `cal { … }` | preserved, never run by the circuit methods; in a pulse run, read as OpenPulse and run in order | Q451, Q453 | same |
| `defcal …` | preserved, never run by the circuit methods; the gate's matrix comes from its definition or the library. In a pulse run, read as OpenPulse and run at each call on its physical qubits | Q450, Q126, Q453, Q459 | same |
| Ports, frames, waveforms (`constant`, `gaussian`, `sech`, `gaussian_square`, `drag`, `sine`, explicit samples) | in a pulse run, lowered to the schedule | Q453, Q455 to Q458 | not used |
| `play`, `delay`, `shift_phase`, `set_phase`, `shift_frequency`, `set_frequency`, `capture_v0` to `capture_v4`, `barrier` | in a pulse run, lowered to the schedule on frames | Q453, Q457, Q458, Q461 | not used |
| Plays on a measurement port | in a pulse run, scheduled and timed; the readout is not simulated | Q462 | not used |
A pulse run is the job method `pulse`; [the pulse page](pulse.md) gives the
model, the bound and the options.
## OpenQASM 2
| Construct | Status | Codes | Bit-exact |
|---|---|---|---|
| `U(θ, φ, λ)` and `CX` with no include | supported: OpenQASM 2's `U`, and `cx` | | dyadic |
| `qreg`, `creg`, `measure q -> c;`, `if (c == n) …;` on a whole register | supported | Q321 | same, or Q502 |
| qelib1.inc's gates | supported as built in: those the table of standard gates names, and `u0` (an idle), `csx`, `c3x`, `c3sqrtx` and `c4x` (`sx` and `x` under that many controls) and `rccx` and `rc3x` (the relative-phase Toffoli gates, by qelib1.inc's definitions, each `u2(0,π)` there a Hadamard); a program's own definition of one is the one that runs | Q012 | dyadic |
| `opaque` | supported as a declaration; a call is refused | Q126 | same |
| `1/2` as a real, `^` as a power | supported | | dyadic |
## What was read wrong, and is no longer
A program read to something other than what the specification says, with no
word of it, is the worst thing a reader can do: a method would run it and seal
the wrong answer in a receipt. These were found on 2026-11-10 by holding the
reader to the specification's text construct by construct, and each was fixed
with a test that failed first (`qasm::spec_tests`, which names each).
| Construct | Read before | Read now |
|---|---|---|
| `ctrl @ U(θ, φ, λ)` (and `negctrl @`, and under `inv @` or `pow @`) | controlled OpenQASM 2 `U`, missing the `e^{iθ/2}` OpenQASM 3's `U` carries: a phase `θ/2` short on the control | `cu(θ, φ, λ, θ/2)`, as the specification defines `U` |
| `ctrl @ u3(θ, φ, λ)`, `ctrl @ u2(φ, λ)` | controlled OpenQASM 2 `U`, with no phase | controlled `e^{−i(θ+φ+λ)/2} U(θ, φ, λ)`, as standard_library.rst defines them |
| A program's own gate written in `U` and `gphase`, under a control (stdgates.inc's text for `x`, `h`, `rx`, `ry`, copied into a program) | wrong by the phase of each `U`: stdgates.inc's own `x` written out, under `ctrl @`, was `cx` followed by `sdg` on the control (overlap 0.71) | the library's gate, phase included |
| A `gate` under a name the reader has built in (`gate h a { x a; }` in a program with no include; `gate iswap`, `gate sxdg` in an exported program) | the definition dropped and the built-in gate run instead | the program's own gate, noted with Q213, unless it is the built-in gate exactly |
| A `mutable` array argument given a slice or a row (`f(aa[1:3])`, the specification's own example) | the subroutine's writes dropped | written back to the slice or row |
| A write to a `readonly` array argument | read, the write kept inside the subroutine | refused (Q131) |
| `angle[n] / angle[n]` | the ratio of the angles as a float (`(5π/4) / (3π/8)` was 3.33…) | the `uint[n]` quotient of their bits (3), as classical.rst defines it |
| A float cast to `angle[n]` exactly halfway between two angles | rounded away from zero | rounded to the even one, as types.rst defines it |
| `~` and `<<` on a `uint[n]` (`uint[4] u = 3; ~u == 12`, `uint[8] b = 143; (b << 1) == 30`) | worked out at any width: `~u` was −4 and `b << 1` 286, so both conditions were false | its n bits, as classical.rst defines the bitwise operators on `uint` |
The conformance case `lang/ctrl_user.qasm` held `ctrl @ U(0.1, 0.2, 0.3)` to
`cu(0.1, 0.2, 0.3, 0)`, the first of these; its reference now reads
`cu(0.1, 0.2, 0.3, 0.05)`.
## What is refused, and why
Every construct the specification defines is read, or refused with a code
that says why; none is dropped. What is refused is refused because running it
would need something the program does not give, or would mean holding a value
the engine's steps do not hold:
- **Values known only at run time** (Q306, Q116): the steps branch on measured
bits and hold no other run-time value, so arithmetic on measured values, and
a measured value used as a gate's angle, an index or a size, are refused.
Conditions on measured bits, `switch` on them and bounded `while` loops on
them run.
- **A `while` on measured bits with no bound** (Q310): it would not be known to
end; `@wai.max_iterations N` bounds it, with a warning (Q311).
- **`durationof`** (Q405): it needs gate durations, which a program does not
give a simulator.
- **A call of an `extern`** (Q125): its body is outside the program; the hybrid
profile (extensions/quantum-wasmq.md) runs such calls.
- **`opaque` gates and gates with only a calibration** (Q126): their matrix is
not known.
- **Integer arithmetic that overflows** (Q112): refused rather than wrapped, so
an overflow is seen.
- **A bit that holds 1 at the end with no measurement writing it** (Q319): the
results carry what measurement writes.
- **A fractional power with no exact gate here** (Q205), **`1/2` where a real is
wanted in a program that does not say its version** (Q118), and **`^`
between integers with no version stated** (Q119): the reader does not guess
between two readings.
- **Widths past what the reader holds** (Q122): `float[128]`, integers and
angles wider than 64 bits.
- **Bitwise operations on angles, `++` between arrays outside a `let`, and a
bit register of several bits as a condition** (Q110, Q004, Q303).