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
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]>
298 lines
25 KiB
Markdown
298 lines
25 KiB
Markdown
# 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).
|