### wai-quantum 0.6.4: noisy Clifford circuits by Pauli frames, the state vector on the GPU, and the density matrix by superoperators

Additive. Every pinned digest is unchanged.

- **`DensityMatrix::evolve`** (`quantum_noisy`): the exact noisy state on up to 16 qubits
  (`MAX_EVOLVE_QUBITS`), against 12 for `DensityMatrix::run`, which stays as the referee.
  - Each gate goes on `ρ`'s rows, its conjugate on the columns. Each channel becomes one
    superoperator `Σᵢ wᵢ Kᵢ ⊗ Kᵢ*` on its qubits' row and column bits, in `run`'s order.
  - A gate and its noise fuse into one gate on at most four of the vector's qubits, applied
    in the state vector's tiled passes. A gate therefore costs one pass and no copy of `ρ`.
  - **Checked:** against `run`, every entry within 10⁻¹² on circuits with every channel and
    a Toffoli. At 14 qubits, past `run`'s size, against branching trajectories within four
    standard errors.
  - **Measured** on a 16-core desktop processor: 12 qubits in 0.53 s against 158 s for
    `run`, and 10 qubits in 39 ms against 4.1 s. 15 qubits with 132 noisy gates take 49 s.
  - **The service's `density_matrix`** runs on it, up to 16 qubits within a job's memory and
    a work cap. `auto`, with noise, still tries it first.
- **`quantum_spd::expectation_capped`**: the sparse-Pauli engine held to a number of terms.
  Whenever a rotation leaves more, the threshold doubles and the sum is truncated again
  until it fits, and everything dropped that way joins the bound. A run that never reaches
  the cap is the uncapped run, bit for bit.
  - **Checked:** on the 127-qubit kicked-Ising circuit, a cap above the peak changes no bit.
    A cap a tenth of the peak stays within its bound of the uncapped value. On a small
    register, the bound covers the exact error.
  - **The service's `pauli`** holds as many terms as the job's memory allows (`max_terms`
    can lower it). A sum that would have outgrown the job now finishes at a coarser
    threshold, reported as `threshold_reached`, with its bound.
- **The tensor-network executor blocked and threaded** (`quantum_tn`). Each pairwise
  contraction is a complex matrix product blocked for the cache, its rows shared between
  threads. Slices running in parallel keep their contractions on one thread each. Every
  output adds its terms in the same order, so the result is the same bits (a test holds it
  to the plain loop's, and the pinned digests hold).
  - **Measured:** large products went from 2.0 to about 25 billion complex multiply-adds a
    second on a 16-core desktop processor (1024 × 1024 × 1024: 0.52 s → 0.043 s).
- **Faster state-vector kernels** (`quantum_sv`). Gates on two to five qubits run at
  compile-time sizes, several groups side by side, with groups of low strides gathered.
  Every output is the same sum in the same order, so the state is the same bits.
  - Measured in cache on one core of a desktop machine: two-qubit gates 280–345 → 400–460
    million amplitudes a second, and dense three- and four-qubit gates 10–25% faster.
  - On a 16-core desktop processor, dense three- to five-qubit gates are 35–50% faster.

- **`quantum_sv_metal`** (new feature, macOS): the dense state vector in single precision
  on the platform's GPU, in one buffer the GPU and the host share. Half the bytes of the
  double-precision state, so one more qubit fits.
  - Gates are fused as `quantum_sv` fuses them, then grouped into tile passes. Each
    threadgroup copies 4096 amplitudes into threadgroup memory, applies every gate of the
    pass there between barriers, and copies them back.
  - A kernel is built per group size, so each group stays in registers. The kernels are
    compiled with the platform's safe math mode. Norms, expectations and samples are summed
    on the host in double precision.
  - **Checked:**
    - Against the double-precision state vector on random circuits of 6 to 21 qubits at
      every fusion width: amplitudes within 2·10⁻⁶, expectations within 10⁻⁵.
    - Tiled and untiled runs are the same bits, and repeated runs are the same bits.
  - **Measured** on a desktop machine's GPU, with the machine heavily loaded by other work:
    a 30-qubit, depth-20 brickwork of 910 gates runs in about 4.2 s at fusion width 3 with
    tiles, against about 8 s gate by gate.
  - **The service** offers it as `statevector_single`, accuracy class `single`, where a GPU
    is present. `auto` tries it after the double-precision `statevector`, so it takes the
    circuits that one cannot hold: up to 33 qubits within a job's memory.
    - **Measured** through the public service, on a host under heavy load:
      - a 33-qubit job (a 64 GiB state, 97 gates, chosen by `auto`) in 70 s;
      - 31 qubits in 23.5 s;
      - 26 qubits in 2.1 s, against 10.1 s for the double-precision method. The expectation
        values agree to 10⁻⁸.

- **`quantum_tableau::frame_counts` and `frame_expectations`.** Clifford circuits under Pauli
  noise (`FrameStep`: depolarizing on one or two qubits, dephasing; readout flips), on up
  to 32768 qubits.
  - One noiseless outcome from the tableau is the reference. Each shot carries a Pauli
    frame, the difference its noise makes, 64 shots to a machine word.
  - Frames start with random Z bits. They leave `|0…0⟩` unchanged, and carried through the
    circuit they spread each shot uniformly over the noiseless outcomes.
  - Errors are placed by geometric gaps, with the crate's own logarithm.
  - An expectation value is the noiseless value times the frames' mean sign against the
    string, with its standard error.
  - Both readouts are the same bits at any thread count.
- **Checked:** on random Clifford circuits of 3 to 5 qubits with every channel, the counts
  (200,000 shots, with readout flips) and the expectation values agree with the exact
  density matrix within five standard errors. Two mutations are caught: dropping one qubit
  of the two-qubit channel, and dropping the random Z bits.
- **Measured** on a 16-core desktop processor: 100,000 full-width shots take 44 ms at 1,000
  qubits with 10,000 noisy gates, and 1.6 s at 10,000 qubits with 100,000.
- **The service's `stabilizer` method takes Pauli noise.** Each QASM gate gets its noise on
  the qubits it touched, as the other noisy methods apply it. Expectations are estimated
  from at least 10,000 shots unless `trajectories` says otherwise. Amplitude damping is not
  a Pauli channel and is refused. With noise, `auto` tries `density_matrix` (12 qubits,
  exact), then `stabilizer`, then `trajectories`.
- **The OpenQASM writer keeps every gate** (`quantum_toolchain::to_qasm`). A gate with
  three or more controls, such as Grover's oracle and diffusion past three qubits, was
  written as a comment, so the program written out was not the circuit. Every controlled
  gate without a standard name is now written in OpenQASM 3's modifier form,
  `ctrl(n) @ g`, and `from_qasm` reads `ctrl`, `ctrl(n)`, `negctrl` and `negctrl(n)` back.
  - **Checked:** each base gate under zero to five controls is read back op for op, and
    Grover's search on five and seven qubits keeps its state.
- **The service** (`wai-quantum-service`, not published):
  - It reads the control modifiers on `x y z h s sdg t tdg p` and on `cx cy cz ch cp ccx
    ccz`. A gate with a standard name is read as that gate, so a Clifford program keeps
    the stabilizer method. A phase on m qubits is written exactly with 2^m − 1 `cx` and
    as many `p`, its angles dyadic when the phase is. **Checked:** on a 6-qubit state,
    every amplitude against the gate applied directly where the controls hold, within
    10⁻¹², each test failing when the expansion's signs or its releases are broken.
  - Receipts sign the RFC 8785 canonical text of the request and the result, so a result
    verifies after any JSON reader has carried it, a browser's included. Its numbers are
    checked against a JavaScript engine on RFC 8785's appendix B and on 2 million random
    doubles. Receipts made before it still verify.
  - It reads numbers correctly rounded (serde_json's `float_roundtrip`). Before, a result
    could change in its last bit on its way from the job's process to the reply.
  - A job carries its request as submitted, so whoever holds its id can check its receipt.

