# Other formats: QIR and jeff The engine reads programs in two formats beside OpenQASM and writes them (`wai_quantum::engine::formats`). A reader gives the program as OpenQASM 3, which the one reader every surface uses then reads, so a program from any format plans, runs, checks and draws as one written in OpenQASM. A construct a reader cannot hold exactly is refused with a code (`Q700` to `Q721`, in [the table of codes](qasm-diagnostics.md)) and where it stands: a line of a QIR module, or a function and an operation of a jeff module. | Format | Read | Written | |---|---|---| | QIR, LLVM text | 1.x (typed pointers) and 2.x (opaque pointers), under the base and adaptive profiles | 2.0, opaque pointers: the base profile, or the adaptive profile for a program that measures in the middle, resets or branches | | jeff, its Cap'n Proto message | 0.2 and 0.3 | 0.3.1 | ## Converting ```sh runnable wai-quantum convert prog.qasm --to qir > prog.ll # QIR 2.0, base profile wai-quantum convert teleport.qasm --to qir > teleport.ll # it branches: the adaptive profile wai-quantum convert prog.ll --to jeff -o prog.jeff # the format read is found from the file wai-quantum convert prog.jeff --to qasm # as OpenQASM 3 wai-quantum convert prog.jeff --to qasm --json > back.json # with the notes, what was read and the check wai-quantum run prog.ll --shots 1000 # every verb that reads a program reads these cp prog.jeff prog.bin wai-quantum lint --from jeff prog.bin # a name the extension does not give ``` Every conversion is checked. What is written is read back and held to the program read by the equivalence ladder (a tableau, every basis state at up to 8 qubits, rewrites, random product states, or unchecked with the reason). A program read from QIR or jeff is written back to its format and read again, and the two readings are held to each other the same way. A program that measures in the middle or branches is held step for step, and where its steps differ (a condition on several bits written as one branch per bit, say) by the probability of every outcome, branch by branch with its weight, which is evidence and says so. The same conversion is the MCP tool `convert_program` on both servers, the job service's `POST /v1/convert`, and `engine_convert` in the browser engine. A job may carry its program in another format: `{"source": {"format": "qir", "program": "…"}}` in place of `"qasm"` (`"program_base64"` for jeff); it is read before anything else reads the job, and the request keeps its source. ## QIR **Profiles.** The entry point's `qir_profiles` names the profile, and the module is held to it: - **base**: gates, then measurements, then output records. A branch, a classical instruction, reading a result, or a gate or reset on a qubit after its measurement is what the profile forbids (`Q704`). - **adaptive**: measurements anywhere; results read as booleans (`__quantum__rt__read_result`, or QIR 1's `__quantum__rt__result_equal` with `result_get_one`) and branched on, forward; `i1` logic (`and`, `or`, `xor`, `icmp eq` and `ne`, `select`). An optional capability its module flags do not declare is forbidden (`Q704`). Integer and float computation the flags declare is computed on reading where its operands are known (an angle computed from constants); computation on a measurement anywhere but a condition, loops, `switch`, `phi`, IR-defined functions, dynamic qubits or results and arrays are not taken here, though declared (`Q705`). A module that names no profile is read under the profile its instructions need, and one that leaves out the version flags or the qubit and result counts is read from what it holds; each says so (`Q702`). A profile other than these two is refused (`Q703`), as is a major version other than 1 or 2 (`Q701`). **The program.** Qubit `i` is `q[i]` and result `r` is `c[r]`; the control flow, a tree of forward branches, is written as nested `if` and `else`, each branch running to the block where its paths meet again. A result read, measured again and only then branched on is refused (`Q708`): the text would read the later measurement. Output records are listed in what was read (`recorded`); classical values recorded as output are not carried (`Q721`). **Intrinsics read.** `__quantum__qis____body`, and `__adj` for the inverse: | Intrinsic | OpenQASM | Intrinsic | OpenQASM | |---|---|---|---| | `x` `y` `z` `h` | `x` `y` `z` `h` | `cnot`, `cx` | `cx` | | `s`, `s__adj` | `s`, `sdg` | `cy` `cz` `swap` | `cy` `cz` `swap` | | `t`, `t__adj` | `t`, `tdg` | `ccx` | `ccx` | | `sx` | `sx` | `ccz` | `ctrl(2) @ z` | | `rx` `ry` `rz` (angle first) | `rx` `ry` `rz` | `rxx` `ryy` `rzz` | their basis changes, two `cx` and one `rz` | | `r1` | `p` | `mz`, `m`, `mresetz`, `reset`, `barrier` | `measure`, `reset`; a barrier is left out | A module of up to 16 MiB is read; its branches nest at most 64 deep, and are written out to at most 1 048 576 statements, 4 194 304 instructions run over every path and a bounded copy of each path's state (`Q705`). A condition holds at most 1 024 terms, nested at most 32 deep once written. Any other intrinsic is refused (`Q706`), and so is a `__ctl` form, whose controls come in an array (`Q705`). Angles are read at their exact doubles, LLVM's hex form (`double 0x400921FB54442D18`) or decimal. A Clifford+T module stays Clifford+T and runs on the bit-exact method; a rotation at an angle that is not a dyadic multiple of 2π reads with a note (`Q709`): the double-precision methods take it, the bit-exact method refuses it. **Writing.** QIR 2.0 with opaque pointers, the four mandatory module flags (and, under the adaptive profile, `ir_functions`, `backwards_branching`, `multiple_target_branching` and `multiple_return_points`, each off), one `array_record_output` and a `result_record_output` for every bit. The base profile's four blocks; under the adaptive profile, one block per step a branch reaches, a condition on several bits read bit by bit with `__quantum__rt__read_result` and `br` alone. Gates are written as the intrinsics above where one exists; the others are lowered exactly, up to a global phase (`U` as `rz ry rz`, `cp` and the controlled rotations by their standard identities, `ch`, `cu`, `iswap` and `cswap` by theirs), and a phase at a multiple of π/4 is written as `z`, `s` and `t`, so a Clifford+T program stays Clifford+T. Every angle is written as its exact hex double. A program whose steps jump backwards is refused (`Q720`), as is a program that branches when the base profile is asked for. ## jeff **The module.** A list of functions, each a dataflow graph of operations over values a qubit uses exactly once. The reader runs the entry point's graph in an order its values allow: - **Qubits**: each `alloc` is a new qubit, in the order the reader reaches it; a register (`qureg`) of a size known on reading is its qubits, extracted, inserted, sliced, split and joined by index. An entry point that takes qubits takes them as the program's first qubits, from `|0⟩`, and returns them unmeasured (`Q716`). - **Gates**: the well-known gates (`x y z s t h`, `i` as `id`, `r1` as `p`, `rx ry rz`, `u` as `U`, `swap`, `gphase`), with their control qubits given after their targets, as the schema says, and `adjoint` and `power` (0 and 1 both apply the gate once) as `ctrl @`, `inv @` and `pow @`. A Pauli-product rotation is `exp(iθP)`, as the schema defines it, lowered exactly to basis changes, a parity ladder and one `rz` (`Q712`). A custom gate is read only when its name is a gate of the standard library, in any case, with that gate's qubits and parameters, and says so (`Q711`); any other is refused (`Q710`). - **Measurement**: `measure` and `measureNd` each write a new bit, in the order the reader reaches them; when the entry point returns its bits (one-bit integers, or arrays of them), the program's bits are those, in that order. `reset` resets. - **Classical values** known on reading are computed then, the same bits on every platform: integers at their width, floats through the crate's own functions. A measured bit may be negated, combined with `and`, `or`, `xor`, `eq` and `select`, widened, and branched on; other arithmetic on it is refused (`Q714`). - **Control flow** (`Q715`): a `for` whose bounds are known, and a `while` whose condition is, unrolled; a `switch` on a known value decided; a `switch` on a measured bit written as `if … else`, a bit set on one side joined with the other side's as a condition; and a call of a function the module defines inlined, up to 32 deep. A value used twice, before it is defined or as the wrong type is refused (`Q713`); a value the reader needs on reading and cannot know is refused (`Q714`), as is a qubit the two sides of a branch leave in different places (`Q708`). Metadata is not read. The reader takes modules of up to 16 MiB, runs up to 4 194 304 operations (`Q312`), writes up to 1 048 576 gates (`Q210`) and 65 536 qubits (`Q111`, a register's size checked before it is made), and holds up to 65 536 elements in one array and 4 194 304 registers' slots, array elements, values and condition terms in all (`Q714`). **The wire format.** A Cap'n Proto message, read and written by a reader and writer of its own (no dependency): segments, far pointers and every element size, each pointer bounds-checked in 64 bits, at most 4 Mi words visited (a list of values counting each element) and 64 pointers deep, so a message that points many times at one object, loops, or states a size past its end does no more work than that. **Writing.** One function, `main`: every qubit allocated in order, each gate a well-known gate, exactly, global phase included (controlled gates with their control qubits, `sx` as `rx(π/2)` and a global phase, `rxx`, `ryy` and `rzz` as Pauli-product rotations, `iswap` by its Clifford identity, `cu` as a controlled `u` and the phase on its control), each measurement written into a bit array at its bit's index, which `main` returns, and every qubit not measured last freed. A program that branches on what it measured is refused (`Q720`); one that measures in the middle or resets is written with `measureNd` and `reset`. ## Hostile input Every reader refuses rather than allocates what a file's sizes ask for: each size, count, index and bound is held to a cap before anything is made from it, and every list a message holds counts against the words it may visit. The check a conversion runs is bounded too: past 262 144 gates applied or 4·10⁹ amplitudes touched it is not run, and the answer says `unchecked` with the reason (`wai-quantum equivalent` runs it on its own). `tests/formats_mutation.rs` holds every file of the conformance set, mutated by a seeded generator, to that: each input converts or is refused with a code, within its time and memory, natively and under wasm32-wasip2. ## Conformance `wai/quantum-conformance/formats/` holds a module in each format for each construct, with the program it must read to, the checks that hold it (the same circuit by the ladder, the same counts, a round trip, the notes it gives) and the refusals with their codes and places; CI runs it natively and under wasm32-wasip2 (`wai-quantum-formats.yml`).