All checks were successful
wai-quantum command line / does this change touch it (push) Successful in 27s
WAI breaking changes and the conformance runner / WAI breaking · does this change touch WAI (push) Successful in 11s
WAI breaking changes and the conformance runner / WAI breaking · wire, record and API against main · linux (push) Successful in 38s
wai-quantum command line / command line · linux (push) Successful in 35m51s
WAI breaking changes and the conformance runner / WAI breaking and conform · their tests, and the independent verifiers through wai conform · linux (push) Successful in 14m31s
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (push) Successful in 20m2s
wai-quantum command line / command line · macos (push) Successful in 5m23s
The committed runs, regenerated with the widened corpus at two jobs on each host, as the nightly run makes them: macOS on arm64 (M3 Ultra) pass 1973, known 16, not run 16, refused 11 as listed, in 66 minutes; Linux on x86_64 (32 threads) pass 1970, known 12, not run 17, refused 11 as listed, in 77 minutes. No check failed on either. The README's tables are written from them (tools/report.py). The single-precision finding at 20 qubits shows on macOS on arm64 only: on Linux on x86_64, with the same pinned versions, the distance is 5.5e-7 and the run records the listed disagreement as no longer showing. The finding says so. The nightly full tier's bound is 190 minutes, from these runs. Co-Authored-By: Claude Opus 5.5 <[email protected]>
922 lines
97 KiB
Markdown
922 lines
97 KiB
Markdown
# Cross-simulator conformance corpus
|
||
|
||
WAI Quantum's engine, run beside other simulators on a published set of circuits, every answer
|
||
held to a reference within a tolerance derived from the arithmetic that produced it. One
|
||
command regenerates every result here on a clean machine.
|
||
|
||
```sh
|
||
bash wai/quantum-cross-simulator/reproduce.sh --tier full # the whole corpus, nightly in CI
|
||
bash wai/quantum-cross-simulator/reproduce.sh # the CI tier, a few minutes
|
||
bash wai/quantum-cross-simulator/reproduce.sh --self-test # every injected fault must be caught
|
||
bash wai/quantum-cross-simulator/reproduce.sh --tier gpu # the GPU members, on a host with a GPU
|
||
bash wai/quantum-cross-simulator/reproduce.sh --perf --out perf.json
|
||
```
|
||
|
||
It needs macOS on arm64 or Linux on x86_64, `curl`, `tar`, a C compiler and rustup; no account
|
||
and no key. It fetches the pinned
|
||
uv release (by SHA-256), CPython 3.12.16 through it, and the engines of
|
||
[`env/requirements.lock`](env/requirements.lock), every wheel checked against its hash. It builds
|
||
the engine from this checkout with `--locked`, runs every check, prints each failure with its
|
||
measured value and tolerance, and ends with `PASS` or `FAIL` (exit 0 or 1). `QCORPUS_CACHE` says
|
||
where the downloads go.
|
||
|
||
## What is compared
|
||
|
||
| engine | version | methods compared here |
|
||
|---|---|---|
|
||
| wai-quantum (this repository) | the checkout | bit-exact fixed point (`exact`), double-precision state vector, stabilizer tableau, matrix product state, tensor network, density matrix, error-correction frames and models, and the whole job path with method `auto`; and, each against an exact reference of its own (below), Pauli propagation, the stabilizer-rank and cut-rank sums, trajectories, Pauli frames under noise, mitigation (`zne`, `vd`, `readout`), pulses, two decoders (exact matching, union-find), and on a GPU the fabric's members (WebGPU, Metal, CUDA) and the single-precision state vector and cut-rank table |
|
||
| Qiskit Aer <!-- allow-name: an open-source simulator compared, named as data --> | 0.18.2, with Qiskit 2.6.2 | state vector (built in code, and read from the published OpenQASM 3 text), stabilizer, matrix product state, density matrix |
|
||
| Stim <!-- allow-name: an open-source simulator compared, named as data --> | 1.16.0 | tableau, sampler, detector error models, the reference generator of the error-correction circuits |
|
||
| quimb <!-- allow-name: an open-source library compared, named as data --> | 1.15.0 | dense state, tensor network contracted, matrix product state |
|
||
| MQT DDSIM <!-- allow-name: an open-source simulator compared, named as data --> | 2.7.0, with mqt.core 3.11.0 | decision-diagram state vector and sampler |
|
||
| qsim <!-- allow-name: an open-source simulator compared, named as data --> | qsimcirq 0.22.1, with Cirq 1.7.0 | single-precision state vector and sampler |
|
||
|
||
Each engine runs every job in a process of its own ([`tools/engines.py`](tools/engines.py)). A
|
||
third-party engine takes each gate by its own name for it where it has one, so a gate it
|
||
defines differently shows; where it has none, the adapter says so in the result and gives it the
|
||
gate's matrix. The engine under test is driven through
|
||
[`wai-quantum-cli/examples/cross_simulator.rs`](../wai-quantum-cli/examples/cross_simulator.rs),
|
||
which calls what the command line and the job service call.
|
||
|
||
## The corpus
|
||
|
||
[`corpus/manifest.json`](corpus/manifest.json) lists every circuit with its parameters, the
|
||
reason it is there, what it is held to and the SHA-256 of its OpenQASM 3 text;
|
||
[`tools/corpus.py`](tools/corpus.py) writes it, and a run fails if the generator no longer gives
|
||
those bytes. Programs up to 16 KiB are committed in [`corpus/qasm/`](corpus/qasm/), and the
|
||
error-correction circuits, which are the pinned reference generator's, in
|
||
[`corpus/qec/`](corpus/qec/); a run checks that the generator still writes them. Random
|
||
circuits draw from SHA-256 in counter mode, and every angle is written exactly: `m/2^k` of a
|
||
turn, a rational fraction of a turn, or a decimal number of radians.
|
||
|
||
| family | what it exposes |
|
||
|---|---|
|
||
| bit order | which index an X on qubit 0 reads as; named classical bits out of order; a state whose every amplitude differs, so any exchange of qubits shows; an empty register; index bit 19 |
|
||
| GHZ, QFT, Grover, phase estimation | closed forms: two amplitudes of 1/√2; e^{2πixy/2^n}/2^(n/2) with every controlled phase to 2π/2^n; sin²((2k+1)θ); an outcome of probability 1, and for a phase of 1/3 the closed law, which the bit-exact method must refuse to round |
|
||
| random Clifford+T, dyadic, arbitrary angles | universal circuits in the table's gates, rotations that become many table phases in fixed point, and decimal angles no dyadic grid holds |
|
||
| mirror | U then U†, at widths past the integer reference: the answer is \|0…0⟩ exactly |
|
||
| small angles | phases of 2π/2^k for k up to 32, the table's last entry, and below it to k = 60, each with a check of whether the engine held the phase or dropped it; p(2π/2^19) applied 2^18 times (a half turn, whose fixed-point result the extension states) and 2^17 times (a quarter turn), each held to the state with its phase |
|
||
| gate conventions | every gate of OpenQASM 3's standard library, and modifiers, on a state with no symmetry; rotations by whole turns, whose sign is the convention; a controlled global phase |
|
||
| measurement in the middle | teleportation, reset of an entangled qubit, measuring twice, feedback, a GHZ state by fusion, repeat-until-success: exact laws from every branch |
|
||
| stabilizer circuits | GHZ and cluster states to 5000 qubits; random Clifford layers at 63, 64, 65, 127, 128 and 129 qubits (either side of a machine word) and to 2000; a Clifford circuit as a state vector and a tableau; outcomes at 40 qubits |
|
||
| noise | depolarizing channels after X and cx chains, whose expectation values are closed forms |
|
||
| wide circuits | GHZ to 100 qubits and the QFT at 30 and 40 by matrix product states and contraction, and at 30 at a bond far above what it reaches; a shallow brickwork at 26; a 40-qubit mirror |
|
||
| error correction | the rotated surface-code memory experiment in Z (d = 3 … 15) and X, the unrotated layout, repetition codes to d = 25, a noiseless run, a colour code whose cycle turns the axes with `C_XYZ`, and hand-written circuits for inverted targets, tags, flip noise, merging, Pauli observables, a correlated error, a general Pauli channel, and two circuits that must be refused |
|
||
| past 14 qubits | the QFT at 18, 20 and 22, Clifford+T at 16, decimal rotations at 18 and dyadic ones at 20, each held whole to the integer state |
|
||
| Pauli propagation | random rotations, Clifford+T, a kicked Ising chain and dyadic rotations, 6 to 12 qubits, with observables of weight 1 to 6 and a coefficient |
|
||
| stabilizer rank | Clifford+T circuits with 1 to 15 T gates (Toffoli and CCZ among them), summed exactly and sampled |
|
||
| cut rank | a Clifford circuit and a layer of `u` gates at decimal angles, 8 to 20 qubits, and the same sampled |
|
||
| noise | GHZ, decimal rotations and a Clifford circuit under depolarizing, dephasing, amplitude-damping and readout noise |
|
||
| mitigation | zero-noise extrapolation by folding, virtual distillation, readout inversion |
|
||
| pulses | a resonant drive, a drive 13 MHz off resonance, two drives about orthogonal axes, an envelope of explicit samples |
|
||
| decoders | the repetition code at d = 3 and the rotated surface code at d = 3 and 5: every single fault, pairs of faults, and seeded sets of two to six |
|
||
|
||
## How a result is judged
|
||
|
||
The references are exact or as good as exact, and share no code with any engine
|
||
([`tools/exact.py`](tools/exact.py), standard library only):
|
||
|
||
- **A state vector in integers.** Amplitudes are integers at scale 2^-256; sine and cosine come
|
||
from an integer π and an integer series. Every run checks that it gives the extension's phase
|
||
table, P(1) … P(32) rounded to the nearest 2^-30, entry for entry against the referee's, and
|
||
that its states meet the closed forms within 2^40 units of 2^-256: the QFT's amplitudes, GHZ's,
|
||
Grover's sin²((2k+1)θ) (computed in integers), phase estimation's outcome of probability 1, and
|
||
its law for a phase of 1/3.
|
||
- **Exact distributions.** A program that measures in the middle is walked branch by branch.
|
||
- **An integer stabilizer tableau**, and the reduced row echelon form of a group with its signs, so
|
||
that two descriptions of a stabilizer state compare as bytes.
|
||
- **The referee** ([`../quantum-conformance/tools/referee.py`](../quantum-conformance/tools/referee.py)) reruns the bit-exact method's
|
||
op-log in its own integer arithmetic and must give the engine's integers and hash, on every
|
||
circuit the method runs whose op-log is at most 2^30 amplitude updates (its length times 2^n,
|
||
a few minutes of the referee's time): every one to 14 qubits, and the shorter op-logs past it. Beside it, the op-log run in double precision must
|
||
give the circuit's exact state, modulo a global phase, within that run's rounding and the
|
||
distance the reader's rule moves angles: so the integers are tied to the op-log, and the op-log
|
||
to the circuit.
|
||
|
||
Each tolerance comes from [`tools/tolerance.py`](tools/tolerance.py), and none is fitted to a
|
||
result:
|
||
|
||
- **The bit-exact method**: the extension's published bound (quantum-sim.md §5, at most 1 + √2/2
|
||
units of 2^-30 per component per inexact gate), summed over the op-log the engine ran.
|
||
- **Floating point**: a gate of width w costs C(w)·u in the Euclidean norm, C(w) = (2√2 + (2^w − 1)
|
||
+ 2 + π)·2^(w/2), from the complex products, the row sum, the matrix entries and the angle's
|
||
rounding; u = 2^-53 in double and 2^-24 in single precision; widths are each engine's fusion.
|
||
Contractions, decision diagrams (whose merging tolerance, 2^-42, is read from mqt.core's header)
|
||
and matrix product states (with LAPACK's unstated SVD constant taken as 16·m, and the weight
|
||
their truncation can drop) are stated in the same file.
|
||
- **Matrix product states**: the rounding of each two-site update's SVD (a gate on qubits d apart
|
||
takes 2d − 1 of them, its routing swaps included), and 2√w for each truncation of weight w, as
|
||
each engine reports what it dropped: the engine under test its summed weight over its
|
||
truncations, Aer every truncation from its log, and quimb run with an absolute cutoff whose
|
||
most per update is known. A row whose bound is not below half the amplitudes it checks is
|
||
recorded and not judged.
|
||
- **Sampled counts**: every outcome's count against its exact probability by Bernstein's
|
||
inequality, and the whole distribution against the exact one in L1 distance, twice the total
|
||
variation (the bound of Weissman and others, 2003, which holds for any number of outcomes); an
|
||
outcome of probability 0
|
||
that appears at all fails. A Clifford circuit's outcomes at 40 qubits: every shot inside the
|
||
affine space its stabilizers fix, no outcome more often than its probability allows, and each
|
||
bit the space leaves free reading 1 half the time.
|
||
- **Error-correction models**: the same symptom sets, probabilities within 16u per noise site of
|
||
the circuit; detection rates against the rates the model gives, by Bernstein's inequality.
|
||
- Every sampled test of a run (counts, stabilizer outcomes, detection rates, and the estimates of
|
||
the methods below) takes a share of one family-wise error rate of 10^-6, a quarter to each kind,
|
||
so a correct engine fails a run on sampling with probability at most 10^-6.
|
||
|
||
### The engine's other methods
|
||
|
||
Each is held to an exact reference, and to the accuracy the method itself states: its bound where
|
||
it states one, the rounding of its arithmetic (derived in [`tools/tolerance.py`](tools/tolerance.py))
|
||
where it states exactness, and, for an estimate, a tail bound on its samples that needs no normal
|
||
approximation. Two more references serve them, standard library only: **an integer density
|
||
matrix** (`exact.Density`: ρ as a state of 2n qubits in integers at scale 2^-256, each channel a
|
||
sum of Kraus terms, the noise placed where the engine's model places it), and **the least-weight
|
||
correction of a syndrome, by exhaustion** ([`tools/decoding.py`](tools/decoding.py): shortest paths
|
||
for each observable mask, then every pairing of the fired detectors).
|
||
|
||
| method (engine) | reference | pass criterion |
|
||
|---|---|---|
|
||
| Pauli propagation (`wai.pauli`) | `<P>` of the integer state | at each threshold of its ladder (0, where only exact zeros drop, and 10^-5 or 10^-3 with the three decades above), \|value − exact\| ≤ the truncation bound it states + its rounding, \|coeff\|·√T·(16R + T)·u for T terms at the peak and at most R rotations (the coefficients' 2-norm is the observable's, and a rotation turns pairs of them); at threshold 0 the bound must be 0 |
|
||
| stabilizer rank, exact (`wai.stabrank`) | the integer state's amplitudes; `<P>` | the sum's one evaluation in double precision: (2t + 2n + 13)·u·sec(π/8)^t, with 2t T gates for an expectation value's sandwich |
|
||
| stabilizer rank, sampled | the integer state's amplitudes | each draw states a bound that holds with a stated confidence; over 10 seeds the bound may fail no more often than a binomial count at that confidence allows |
|
||
| cut rank (`wai.cutrank`) | the integer state's amplitudes (every one at 8 qubits, 256 chosen at 12, 64 at 16 and 20); the exact distribution | (11n + 2)·u·2^(n/2) per amplitude, √m of it over m amplitudes in the 2-norm modulo a global phase; counts as every sampler's |
|
||
| density matrix (`wai.density_matrix`), noisy | the integer density matrix: `<P>`, the law of the bits with readout flips | √(2^n)·16·C(4)·u per superoperator it applies; counts as every sampler's |
|
||
| trajectories (`wai.trajectories`), Pauli frames (`wai.stabilizer` with noise) | the same | the mean of N samples each in [−\|c\|, \|c\|] within Hoeffding's bound, \|c\|·√(2 ln(2/α)/N), and a trajectory's own rounding; counts as every sampler's |
|
||
| zero-noise extrapolation (`wai.mitigate`, `zne`) | each folded program's noisy value from the integer density matrix, and the Richardson extrapolation of those exact values | each scale's value from its shots within Hoeffding's bound; the extrapolation within Σ\|c_i\| times those bounds; the ideal value it states within the state vector's rounding |
|
||
| virtual distillation (`vd`) | Tr(ρ²) and Tr(ρ²P)/Tr(ρ²) from the integer density matrix | the purity it states within twice the density matrix's rounding; the ratio within what Hoeffding's bounds on its numerator and denominator allow |
|
||
| readout inversion (`readout`) | the law of the bits before the flips | every quasi-probability within Hoeffding's bound on its shots, each shot's share spanning (1 − 2p)^-k(1 − p)^(k−1) |
|
||
| pulses (`wai.pulse`) | the Rabi formula, r²/g²·sin²(πgt), in integers | P(0) and P(1) within the bound the run states (its series' truncation, proved, and its rounding, estimated) |
|
||
| exact matching (`wai.matching`) | the least weight of a correction for each observable mask | the prediction's least weight within the weights' rounding of the least of all: (detectors + 1)/16384 for each fired detector |
|
||
| union-find (`wai.union_find`) | the same | every single edge of the graph corrected exactly, as it states; how often it agrees with a least-weight correction is recorded, not judged (it states no least weight) |
|
||
| the fabric's members (`wai.fabric[…]`, gpu tier) | the CPU's bit-exact integers, which the state checks hold to the integer reference | the same integers and the same hash, bit for bit |
|
||
| single precision on the GPU (`wai.statevector_single`, `wai.cutrank_single`, gpu tier) | the integer state's amplitudes | the double-precision bounds with u = 2^-24 |
|
||
|
||
A state is held to its reference modulo a global phase, which no measurement sees; the
|
||
distance with the phase is recorded beside it (`strict`). Where the phase is the result (the
|
||
repeated phases), the verdict is the distance with it. The bounds are worst cases and so are
|
||
loose: each result records how far inside its bound an engine is, and the table below gives the
|
||
largest such ratio. Below an engine's bound a distance cannot tell a small-angle gate from its
|
||
absence, so each small-angle circuit also asks of every engine whether it held the gate's phase
|
||
or dropped it, exactly, in integers.
|
||
|
||
The engine under test is held to answering. A crash, a time-out, or a refusal that
|
||
[`corpus/expected-refusals.json`](corpus/expected-refusals.json) does not list for that circuit in
|
||
those words fails the run; an answer to a circuit that file says it must refuse fails it too. The
|
||
file lists the bit-exact method's refusals by its reader's rule (an angle no grid of 2^32 holds
|
||
within 10^-14 of a turn), computed from the circuits' exact angles, and four error-correction
|
||
circuits. Another engine's refusal or crash is recorded as `not run`, with its words.
|
||
|
||
A run can be seen to fail. `--self-test` runs one circuit for each fault `compare.py` can inject,
|
||
and passes only if each fails the run on the check it breaks, on the engine it was put into, and
|
||
on no other engine:
|
||
|
||
- an amplitude moved by 10^-9; the qubits of a state reversed; one fixed-point bit flipped; a
|
||
stabilizer's sign flipped; a mechanism's probability raised by one part in 10^6;
|
||
- 5% of an outcome's shots moved to another that can occur (caught by the per-outcome test, on a
|
||
distribution with variance); every outcome's count moved by a tenth of itself, up and down in
|
||
turn (caught only by the L1 distance); every shot of a 40-qubit Clifford sampler given to one
|
||
outcome; a detector's count raised by a quarter; a sampler's answer with no observable;
|
||
- a phase dropped from the bit-exact op-log, its integers and hash made again to match (caught
|
||
only by the op-log against the circuit); a small-angle gate dropped from a double-precision
|
||
state, inside its bound (caught only by the held-or-dropped check); a half turn on a repeated
|
||
phase (caught only by the distance with the phase); a global phase on the bit-exact state
|
||
(caught by the closed-form amplitudes, which it was once exempt from); a phase of 0.5 rad on a
|
||
matrix-product amplitude (caught by a bound charged what that engine truncated);
|
||
- the engine under test refusing, crashing on a job or on a model, hanging, taking an angle it
|
||
must refuse, or refusing in words no list holds, or in other words than its list's;
|
||
- Pauli propagation's values moved by twice their truncation bound (and 10^-9); an exact
|
||
stabilizer-rank amplitude moved by 10^-9; a cut-rank amplitude moved by 10^-8; trajectories'
|
||
means moved by 0.05; a noisy density matrix's values moved by 10^-8; Pauli frames' values
|
||
negated; an extrapolation replaced by its value at scale 1; readout's
|
||
quasi-probabilities replaced by the raw frequencies; the purity raised by 10^-6; a pulse's P(1)
|
||
moved by ten times its bound; every prediction of exact matching, and of union-find, flipped;
|
||
and in the gpu tier, one bit of each GPU member's state flipped.
|
||
|
||
## Results
|
||
|
||
The committed runs, one file per host, are in [`results/`](results/): every check with its
|
||
measured value and tolerance, the host and every version. Each file names the git trees of the
|
||
engine and of the tools that produced it, as they were on disk (`git rev-parse
|
||
<commit>:wai/wai-quantum` gives the same id for any commit holding the same engine). A cell
|
||
below is checks passed of those made, with the largest ratio of measured value to tolerance
|
||
among the passes in brackets.
|
||
|
||
### What agreed
|
||
|
||
On both hosts, every engine met its reference within its tolerance on every circuit it ran, with
|
||
the exceptions listed next. That covers the engine under test's bit-exact, double-precision,
|
||
stabilizer (tableau and Pauli frames), matrix-product, tensor-network, density-matrix,
|
||
error-correction, Pauli-propagation, stabilizer-rank, cut-rank, trajectory, mitigation (three
|
||
methods), pulse and decoding (two decoders) methods, and eleven methods of the others, on states
|
||
(held whole to the integer state to 22 qubits), sampled counts, stabilizer groups to 5000 qubits,
|
||
amplitudes to 100 qubits, noisy expectation values and laws under every channel of the noise
|
||
model, mitigated values, pulse populations, decoded syndromes to distance 5, and detector error
|
||
models and detection rates to distance 15. The engine under
|
||
test answered every circuit, and refused only those
|
||
[`corpus/expected-refusals.json`](corpus/expected-refusals.json) lists, in the words it lists.
|
||
|
||
The bit-exact method's integers were reproduced bit for bit by the referee on every circuit whose
|
||
op-log is at most 2^30 amplitude updates: every one to 14 qubits, the QFT at 18 and 20, Clifford+T
|
||
at 16 and the mirror at 16 (the 22-qubit QFT, the 20-qubit mirror and the 20-qubit dyadic
|
||
rotations are past it, and recorded as not rerun); its op-log, run in double precision, gave each
|
||
circuit's exact state; and its
|
||
distance from the ideal state stayed inside the extension's published bound everywhere. On
|
||
`repeated_phase_k19`, p(2π/2^19) applied 2^18 times to |1⟩, its amplitude ends with modulus
|
||
1.0000188705 and 8.99·10^-6 rad from the half turn (a distance of 2.09·10^-5 from −|1⟩), where the
|
||
extension states modulus 1.0000189 and within 10^-5 rad. These are integers, the same on both hosts.
|
||
|
||
### Disagreements with the references
|
||
|
||
- **The engine under test, wrong; fixed.** `quantum_frame::surface_code_memory` documents that
|
||
its text is the reference generator's, byte for byte. At p = 0 it was not: it wrote every noise
|
||
instruction with probability 0 and the first round's resets on two lines, where the reference
|
||
writes no noise instruction and one reset line (`surface_z_d5_noiseless`). The two circuits
|
||
meant the same, so models and samples agreed; the text did not. Fixed in the engine, with a
|
||
test against the reference's text (`wai-quantum/tests/frame_reference.rs`).
|
||
- **Another engine.** `ddsim.statevector` on `measure_twice` (h, then the same qubit measured
|
||
into two bits) returns 00 and 10, where a repeated measurement repeats: 00 and 11. On
|
||
`repeat_until_success` it raises an error and gives no counts. Each claim about it, with the
|
||
smaller programs that show what the error needs, is a case of a reproducer committed beside
|
||
[`corpus/known-disagreements.json`](corpus/known-disagreements.json)
|
||
([`corpus/reproducers/`](corpus/reproducers/)), which every run that holds the circuit reruns;
|
||
the two checks are reported as `known`. Only other engines may be listed there.
|
||
- **A single-precision engine, past its bound at 20 qubits, on one host.** On macOS on arm64, on
|
||
`dyadic_n20_k16` (148 rotations by m/2^16 of a turn and cz gates), the single-precision state
|
||
vector is 2.3·10^-4 from the integer state, past the 1.9·10^-4 that its gates allow
|
||
(tolerance.py), and nearly all of it is its norm, 1.00023; the circuit library's own complex64
|
||
simulator is as far there. The norm grows in runs of the whole circuit prefix, not in a gate
|
||
applied by hand in single precision to the state before it; the same construction at 16
|
||
qubits is within its bound; and on Linux on x86_64, with the same pinned versions, the
|
||
distance is 5.5·10^-7. Not yet explained; each claim is a case of a reproducer
|
||
(`corpus/reproducers/qsim_single_precision_norm.py`), and the check is reported as `known`
|
||
where it shows (on Linux the listed disagreement is recorded as no longer showing).
|
||
- **The reference, wrong once.** While this corpus was written, the integer reference's `ryy`
|
||
used the wrong fixed rotation. It showed as every engine agreeing with every other and none
|
||
with the reference, and was corrected before any result here was recorded. A reference is
|
||
examined first when that pattern appears.
|
||
|
||
### Conventions the corpus shows
|
||
|
||
- **Global phase.** Every engine keeps OpenQASM 3's global phases except the bit-exact method,
|
||
which lowers `rz`, `rx`, `ry` and `U` through phase gates and so differs from the standard's
|
||
matrices by a global phase (a `strict` distance of up to 1.97 on a rotation by a whole turn).
|
||
No measurement sees it, and under a control the method is right (`controlled_rz_full_turn`,
|
||
`gate_crz`, `gate_cu`). A result on this method states the phase (`accuracy.global_phase`,
|
||
exactly, in 2^33rds of a turn), and the corpus holds the method's state to the reference's with that
|
||
phase, nothing fitted.
|
||
- **Angles below the table.** The bit-exact method reads an angle within 10^-14 of a turn of a
|
||
dyadic one as that dyadic. A phase of 2π/2^k is therefore refused for k = 33 … 46 (`[Q500]`),
|
||
and for k ≥ 47 runs as no phase at all, labelled bit-exact: its op-log is the circuit's with the
|
||
angle moved by 2^-k of a turn, which the op-log check allows by the reader's rule, and its state
|
||
is within 2.3·10^-14 of the ideal one, far inside the method's resolution. The result and the
|
||
plan say so (`accuracy.below_table`, with how many and the largest), and an angle moved to a
|
||
dyadic neighbour other than zero is stated too (`accuracy.moved_angles`). Method `auto` sends
|
||
k = 33 … 46 to double precision.
|
||
- **Held or dropped.** Every double- and single-precision engine here held the phase at every k
|
||
where its answer can say. The decision-diagram engine dropped it at k = 47, 48, 52 and 60, each
|
||
an angle below its parameter tolerance of 10^-13 rad, and held it at k ≤ 40. At k = 60 the phase
|
||
moves the state by 2.7·10^-18, less than half of most answers' own rounding: those are recorded
|
||
as unable to say, and the single-precision engine's answer, whose rounding there was smaller,
|
||
held it.
|
||
- **Bit order.** Every engine's answers were brought to one convention (qubit 0 the lowest bit of
|
||
an index, classical bit 0 the last character of an outcome) by its adapter, and the bit-order
|
||
family holds each adapter to it; the self-test's reversed state fails there.
|
||
|
||
### Run time and memory
|
||
|
||
The performance tables below are one shared host each, on one day; read the Limits before any
|
||
figure. Each row is one engine on one case, as data:
|
||
|
||
- **threads**: what the engine was given. `all (32)` is every CPU the process may run on, which
|
||
the engine under test's state vector and tensor network use; `1 (no threads)` a method with no
|
||
threads of its own (the engine under test's bit-exact, stabilizer, matrix-product-state and
|
||
error-correction methods); a number, the count passed in the engine's own setting; `not set`,
|
||
an engine the adapter gives no thread setting; `1 (pinned)`, the process held to one CPU
|
||
(Linux only).
|
||
- **ops**: the operations the engine ran, where it reports them: the driver's count for the
|
||
engine under test, and the gates of Aer's circuit after its conversion.
|
||
- **seconds**: the engine's own call, the median of the runs with the minimum in brackets. The
|
||
list above each table says where each engine's timer starts and stops.
|
||
- **peak MiB**: the peak resident set of the process that ran the engine (the driver for the
|
||
engine under test; for another engine, its adapter, which holds the interpreter and its
|
||
packages), as the system counts it for that process alone; the baseline beside it is the same
|
||
measure given a two-qubit job.
|
||
|
||
The last table runs the same harness on the engine under test built before and after a gate
|
||
under many controls stood whole on its state vector, one build straight after the other on one
|
||
host; `ops` gives the operations each build ran. `wai.exact_whole` is the bit-exact method asked
|
||
to hold such a gate whole (`"options": {"controls": "whole"}`), which gives other bits than its
|
||
default; `wai.exact`, its default, runs standard gates and gives the bits it gave before. Past 16
|
||
controls the standard form refuses (`[Q208]`), so `grover_n20` has no "before".
|
||
|
||
<!-- results: written by tools/report.py from results/*.json; do not edit by hand -->
|
||
|
||
### `conformance-linux-x86_64.json`
|
||
|
||
Host: AMD RYZEN AI MAX+ 395 w/ Radeon 8060S, Ubuntu 26.04.1 LTS, 32 logical CPUs, 123 GiB, x86_64. Tier full, 4600.4 s. Checks: info 19, known 12, not run 17, pass 1970, refused 11.
|
||
|
||
| family | `wai.exact` | `wai.statevector` | `wai.stabilizer` | `wai.auto` | `wai.mps` | `wai.tensor_network` | `wai.density_matrix` | `wai.qec` | `wai.pauli` | `wai.stabrank` | `wai.cutrank` | `wai.trajectories` | `wai.mitigate` | `wai.pulse` | `wai.matching` | `wai.union_find` | `aer.statevector` | `aer.qasm_import` | `aer.stabilizer` | `aer.mps` | `aer.density_matrix` | `stim.tableau` | `quimb.dense` | `quimb.tensor_network` | `quimb.mps` | `ddsim.statevector` | `qsim.statevector` | `pairs and references` | `references` |
|
||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
||
| bit_order | 24/24 (0.068) | 8/8 (0.015) | 12/12 | 8/8 (0.0069) | | | | | | | | | | | | | 8/8 (0.016) | 6/6 (0.016) | 5/5 | | | 7/7 | 6/6 (0.019) | 6/6 (0.031) | | 8/8 (0.00015) | 8/8 (0.013) | 15/15 (0.0084) | 5/5 |
|
||
| clifford_large | 4/4 (0.012) | 1/1 (0.00077) | 34/34 (0.43) | 1/1 (7.8e-05) | | | | | | | | | | | | | 1/1 (0.00084) | 1/1 (0.00084) | 16/16 (0.51) | | | 19/19 (0.3) | 1/1 (0.0017) | 1/1 (4.4e-08) | | 1/1 (2.4e-07) | 1/1 (0.00052) | | 15/15 |
|
||
| cutrank | | | | | | | | | | | 6/6 (0.56) | | | | | | | | | | | | | | | | | | |
|
||
| decoders | | | | | | | | | | | | | | | 3/3 | 3/3 | | | | | | | | | | | | | |
|
||
| dynamic | | 12/12 (0.29) | 8/8 (0.21) | 12/12 (0.29) | | | | | | | | | | | | | 12/12 (0.36) | | | | | 8/8 (0.29) | | | | 8/8 (0.22) · 11 known | 6 not run | | |
|
||
| gate_conventions | 188/188 (0.069) | 47/47 (0.017) | | 47/47 (0.066) | | | | | | | | | | | | | 47/47 (0.018) | 47/47 (0.018) | | | | | 46/46 (0.017) · 1 not run | 46/46 (0.032) · 1 not run | | 47/47 (0.00015) | 46/46 (0.026) · 1 not run | | |
|
||
| ghz | 20/20 (0.042) | 7/7 (0.21) | 2/2 (0.022) | 7/7 (0.022) | | | | | | | | | | | | | 7/7 (0.058) | 5/5 (0.011) | | | | 2/2 (0.29) | 5/5 (0.0094) | 5/5 (0.041) | | 7/7 (0.017) | 7/7 (0.14) | | 5/5 |
|
||
| grover | 16/16 (0.029) | 6/6 (0.12) | | 6/6 (0.14) | | | | | | | | | | | | | 6/6 (0.25) | 4/4 (0.0043) | | | | | 4/4 (0.0079) | 4/4 (0.00031) | | 6/6 (0.16) | 6/6 (0.27) | | 4/4 |
|
||
| mirror | 8/8 (0.007) · 1 not run | 3/3 (0.00036) | | | | | | | | | | | | | | | 3/3 (0.00068) | | | | | | 3/3 (0.00036) | | | 2/2 (7e-05) · 1 not run | 3/3 (0.00057) | | |
|
||
| mitigation | | | | | | | | | | | | | 18/18 (0.23) | | | | | | | | | | | | | | | | |
|
||
| noise | | | | | | | 3/3 (0.00093) | | | | | | | | | | | | | | 3/3 (0.00093) | | | | | | | | |
|
||
| noisy | | | 11/11 (0.34) | | | | 16/16 (0.24) | | | | | 16/16 (0.41) | | | | | | | | | 3/3 (0.0003) | | | | | | | | |
|
||
| other | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 3/3 |
|
||
| pauli | | | | | | | | | 81/81 (0.11) | | | | | | | | | | | | | | | | | | | | |
|
||
| pulse | | | | | | | | | | | | | | 8/8 (0.0013) | | | | | | | | | | | | | | | |
|
||
| qec | | | | | | | | 29/29 (0.6) · 2 refused as listed | | | | | | | | | | | | | | 22/22 (0.53) · 2 not run | | | | | | 44/44 (0.016) | |
|
||
| qft | 36/36 (0.042) · 1 not run | 12/12 (0.58) | | 11/11 (0.66) | | | | | | | | | | | | | 12/12 (0.61) | 6/6 (0.009) | | | | | 10/10 (0.0062) | 5/5 (0.0057) | | 12/12 (0.64) | 12/12 (0.63) | 15/15 (0.0027) | 8/8 |
|
||
| qpe | 12/12 (0.017) · 2 refused as listed | 5/5 (0.0091) | | 5/5 (0.013) | | | | | | | | | | | | | 5/5 (0.0058) | 5/5 (0.0075) | | | | | 5/5 (0.0071) | 4/4 (0.0014) | | 5/5 (4.8e-06) | 5/5 (0.0034) | | 5/5 |
|
||
| random_clifford_t | 16/16 (0.039) | 4/4 (0.0047) | | 4/4 (0.017) | | | | | | | | | | | | | 4/4 (0.0042) | 3/3 (0.0042) | | | | | 4/4 (0.003) | 3/3 (0.00027) | | 4/4 (3e-05) | 4/4 (0.0023) | | |
|
||
| random_dyadic | 11/11 (0.0076) · 1 not run | 3/3 (0.0019) | | 3/3 (0.0016) | | | | | | | | | | | | | 3/3 (0.0027) | 2/2 (0.0036) | | | | | 3/3 (0.0019) | 2/2 (0.00016) | | 3/3 (6.8e-06) | 3/3 (0.004) · 1 known | | |
|
||
| random_rotations | 4 refused as listed | 6/6 (0.48) | | 6/6 (0.48) | | | | | | | | | | | | | 6/6 (0.49) | 3/3 (0.0034) | | | | | 4/4 (0.0021) | 3/3 (0.00014) | | 6/6 (0.55) · 1 not run | 6/6 (0.4) | 6/6 (0.0017) | |
|
||
| small_angle | 62/62 (0.9) · 3 refused as listed | 32/32 (0.016) | 2/2 | 18/18 (0.098) | | | | | | | | | | | | | 32/32 (0.018) | 29/29 (0.016) | 1/1 | | | 1/1 | 30/30 (0.019) | 29/29 (0.016) | | 29/29 (0.15) | 33/33 (0.0075) | | 1/1 |
|
||
| stabrank | | | | | | | | | | 9/9 (0.039) | | | | | | | | | | | | | | | | | | | |
|
||
| wide_mps | | | | | 6/6 (0.00017) | 5/5 (0.00057) | | | | | | | | | | | | | | 4/4 (0.00023) · 1 not run | | | | 5/5 (0.043) | 5/5 (7.3e-05) | | | | |
|
||
| wide_tn | | | | | 1/1 (0.00093) | 1/1 (6.4e-07) | | | | | | | | | | | | | | 1/1 (0.0021) | | | | 1/1 (0.02) | 1/1 (0.0011) | | | 21/21 (0.02) | |
|
||
|
||
Known disagreements of other engines with the exact reference (`corpus/known-disagreements.json`):
|
||
|
||
- `repeat_until_success`, `ddsim.statevector`: ValueError: [changePermutation] Target must be an injective mapping using only keys and logical qubits from the source permutation. | known: MQT DDSIM 2.7.0's qasm_simulator raises ValueError [changePermutation] on this program (two qubits; qubit 1 measured three times in the middle, with gates between and an x conditioned on each reading; four classical bits) and gives no counts. It raises the same without the conditioned x, and on qubit 1 measured, h, measured again, then qubit 0 measured into a third bit; with no third bit it gives counts. Each is a case of the reproducer.
|
||
- `measure_twice`, `ddsim.statevector`: 10: 49842 shots, probability 0; 11: 0 shots, expected 50000.0 ± 1095.4 | known: MQT DDSIM 2.7.0's qasm_simulator, given h q[0]; c[0] = measure q[0]; c[1] = measure q[0]; with nothing between the two measurements, returns 00 and 10: c[0] is never set. With x in place of h it gives 10 on every shot; with a barrier between the measurements, 00 and 11; with c[1] measured first and c[0] second, ValueError [changePermutation]. Each is a case of the reproducer, with the circuit built in Qiskit 2.6.2.
|
||
- `measure_twice`, `ddsim.statevector`: known: MQT DDSIM 2.7.0's qasm_simulator, given h q[0]; c[0] = measure q[0]; c[1] = measure q[0]; with nothing between the two measurements, returns 00 and 10: c[0] is never set. With x in place of h it gives 10 on every shot; with a barrier between the measurements, 00 and 11; with c[1] measured first and c[0] second, ValueError [changePermutation]. Each is a case of the reproducer, with the circuit built in Qiskit 2.6.2.
|
||
- `measure_twice`, `ddsim.statevector`, reproducer (corpus/reproducers/ddsim_repeated_measurement.py): h, then c[0] and c[1] measured from the qubit with nothing between: only 00 and 10 come — saw ['00', '10']
|
||
- `measure_twice`, `ddsim.statevector`, reproducer (corpus/reproducers/ddsim_repeated_measurement.py): x, then the same two measurements: 10 on every shot — saw ['10']
|
||
- `measure_twice`, `ddsim.statevector`, reproducer (corpus/reproducers/ddsim_repeated_measurement.py): h, the two measurements with a barrier between: 00 and 11 — saw ['00', '11']
|
||
- `measure_twice`, `ddsim.statevector`, reproducer (corpus/reproducers/ddsim_repeated_measurement.py): h, then c[1] measured first and c[0] second: an error naming changePermutation — saw ValueError: [changePermutation] Target must be an injective mapping using only keys and logical qubits from the source permutation.
|
||
- `repeat_until_success`, `ddsim.statevector`, reproducer (corpus/reproducers/ddsim_feedback_rounds.py): repeat_until_success: an error naming changePermutation, and no counts — saw ValueError: [changePermutation] Target must be an injective mapping using only keys and logical qubits from the source permutation.
|
||
- `repeat_until_success`, `ddsim.statevector`, reproducer (corpus/reproducers/ddsim_feedback_rounds.py): the same three rounds without the conditioned x: the same error — saw ValueError: [changePermutation] Target must be an injective mapping using only keys and logical qubits from the source permutation.
|
||
- `repeat_until_success`, `ddsim.statevector`, reproducer (corpus/reproducers/ddsim_feedback_rounds.py): qubit 1 measured, h, measured again, then qubit 0 measured into a third bit: the same error — saw ValueError: [changePermutation] Target must be an injective mapping using only keys and logical qubits from the source permutation.
|
||
- `repeat_until_success`, `ddsim.statevector`, reproducer (corpus/reproducers/ddsim_feedback_rounds.py): the same without qubit 0's measurement into a third bit: counts — saw counts over 4 outcomes
|
||
- `dyadic_n20_k16`, `qsim.statevector`, reproducer (corpus/reproducers/qsim_single_precision_norm.py): the same construction on 16 qubits stays within its bound — saw 6.33e-07
|
||
|
||
<details><summary>Refusals by the engine under test, each listed in <code>corpus/expected-refusals.json</code> with its words (11)</summary>
|
||
|
||
- `qpe_t6_third`, `wai.exact`: the angle 2.0943951023931953 is not a dyadic multiple of 2π (2πm/2^k, k ≤ 32) [Q500]
|
||
- `qpe_t10_third`, `wai.exact`: the angle 2.0943951023931953 is not a dyadic multiple of 2π (2πm/2^k, k ≤ 32) [Q500]
|
||
- `rotations_n6`, `wai.exact`: the angle 1.6459015101789476 is not a dyadic multiple of 2π (2πm/2^k, k ≤ 32) [Q500]
|
||
- `rotations_n10`, `wai.exact`: the angle 0.49840613019150304 is not a dyadic multiple of 2π (2πm/2^k, k ≤ 32) [Q500]
|
||
- `rotations_n12`, `wai.exact`: the angle 1.437905822610216 is not a dyadic multiple of 2π (2πm/2^k, k ≤ 32) [Q500]
|
||
- `below_grid_k33`, `wai.exact`: the angle 0.0000000007314590396335798 is not a dyadic multiple of 2π (2πm/2^k, k ≤ 32) [Q500]
|
||
- `below_grid_k40`, `wai.exact`: the angle 0.000000000005714523747137342 is not a dyadic multiple of 2π (2πm/2^k, k ≤ 32) [Q500]
|
||
- `tiny_radians`, `wai.exact`: the angle 0.000000000001 is not a dyadic multiple of 2π (2πm/2^k, k ≤ 32) [Q500]
|
||
- `rotations_n18`, `wai.exact`: the angle 1.586539928488264 is not a dyadic multiple of 2π (2πm/2^k, k ≤ 32) [Q500]
|
||
- `qec_refused_channel_with_no_independent_form`, `wai.qec`: line 2: PAULI_CHANNEL_1(0.1, 0.1, 0): its exclusive outcomes have no form as independent X, Y and Z flips, which this simulator and a detector error model both need
|
||
- `qec_refused_random_detector`, `wai.qec`: a detector or observable is not deterministic (it anticommutes with op 0)
|
||
|
||
</details>
|
||
|
||
<details><summary>Checks other engines did not make, and why (17)</summary>
|
||
|
||
- `rotations_wide_n20`, `ddsim.statevector`: did not finish within 900 s
|
||
- `mirror_n20`, `wai.exact`: not rerun: 8386 ops on 2^20 amplitudes is past the referee's 2^30 updates
|
||
- `mirror_n20`, `ddsim.statevector`: did not finish within 900 s
|
||
- `gate_gphase_controlled`, `quimb.dense`: no gate gphase
|
||
- `gate_gphase_controlled`, `quimb.tensor_network`: no gate gphase
|
||
- `gate_gphase_controlled`, `qsim.statevector`: a global phase gate
|
||
- `teleport`, `qsim.statevector`: measurement in the middle (or one qubit measured twice)
|
||
- `reset_after_superposition`, `qsim.statevector`: measurement in the middle (or one qubit measured twice)
|
||
- `measure_twice`, `qsim.statevector`: measurement in the middle (or one qubit measured twice)
|
||
- `feedback_flip`, `qsim.statevector`: measurement in the middle (or one qubit measured twice)
|
||
- `ghz_by_fusion`, `qsim.statevector`: measurement in the middle (or one qubit measured twice)
|
||
- `repeat_until_success`, `qsim.statevector`: measurement in the middle (or one qubit measured twice)
|
||
- `mps_ghz_n100`, `aer.mps`: CircuitTooWideForTarget: 'Number of qubits (100) in circuit-46 is greater than maximum (63) in the coupling_map'
|
||
- `qft_n22_x2796203`, `wai.exact`: not rerun: 298 ops on 2^22 amplitudes is past the referee's 2^30 updates
|
||
- `dyadic_n20_k16`, `wai.exact`: not rerun: 1038 ops on 2^20 amplitudes is past the referee's 2^30 updates
|
||
- `qec_refused_channel_with_no_independent_form`, `stim.tableau`: ValueError: Encountered the operation PAULI_CHANNEL_1 during error analysis, but this operation requires the `approximate_disjoint_errors` option to be enabled. If you're calling from python, using stim.Circuit.detector_error_model, you need to add the argument approximate_disjoint_errors=True. If
|
||
- `qec_refused_random_detector`, `stim.tableau`: ValueError: The circuit contains non-deterministic detectors. To make an SVG picture of the problem, you can use the python API like this: your_circuit.diagram('detslice-with-ops-svg', tick=range(0, 5), filter_coords=['D0', ]) or the command line API like this: stim diagram --in your_circui
|
||
|
||
</details>
|
||
|
||
<details><summary>Recorded and not judged (16)</summary>
|
||
|
||
- `below_grid_k47`, `ddsim.statevector`: holds the phase of its small-angle gate: the share of the step from the state without that gate to the ideal (1 holds it, 0 drops it) — measured -4.3e-78. drops it: the angle, 4.46e-14 rad, is below its parameter tolerance of 1e-13 rad, where it may read an angle as 0
|
||
- `below_grid_k48`, `ddsim.statevector`: holds the phase of its small-angle gate: the share of the step from the state without that gate to the ideal (1 holds it, 0 drops it) — measured -4.3e-78. drops it: the angle, 2.23e-14 rad, is below its parameter tolerance of 1e-13 rad, where it may read an angle as 0
|
||
- `below_grid_k52`, `ddsim.statevector`: holds the phase of its small-angle gate: the share of the step from the state without that gate to the ideal (1 holds it, 0 drops it) — measured -4.3e-78. drops it: the angle, 1.4e-15 rad, is below its parameter tolerance of 1e-13 rad, where it may read an angle as 0
|
||
- `below_grid_k60`, `wai.statevector`: holds the phase of its small-angle gate: the share of the step from the state without that gate to the ideal (1 holds it, 0 drops it) — measured 1. neither can be told: its distance from the ideal state, 2.22e-16, is more than half the gate's effect, 2.72e-18
|
||
- `below_grid_k60`, `aer.statevector`: holds the phase of its small-angle gate: the share of the step from the state without that gate to the ideal (1 holds it, 0 drops it) — measured -21. neither can be told: its distance from the ideal state, 6.12e-17, is more than half the gate's effect, 2.72e-18
|
||
- `below_grid_k60`, `aer.qasm_import`: holds the phase of its small-angle gate: the share of the step from the state without that gate to the ideal (1 holds it, 0 drops it) — measured -21. neither can be told: its distance from the ideal state, 6.12e-17, is more than half the gate's effect, 2.72e-18
|
||
- `below_grid_k60`, `quimb.dense`: holds the phase of its small-angle gate: the share of the step from the state without that gate to the ideal (1 holds it, 0 drops it) — measured 1. neither can be told: its distance from the ideal state, 2.22e-16, is more than half the gate's effect, 2.72e-18
|
||
- `below_grid_k60`, `quimb.tensor_network`: holds the phase of its small-angle gate: the share of the step from the state without that gate to the ideal (1 holds it, 0 drops it) — measured 1. neither can be told: its distance from the ideal state, 1.11e-16, is more than half the gate's effect, 2.72e-18
|
||
- `below_grid_k60`, `ddsim.statevector`: holds the phase of its small-angle gate: the share of the step from the state without that gate to the ideal (1 holds it, 0 drops it) — measured -4.3e-78. drops it: the angle, 5.45e-18 rad, is below its parameter tolerance of 1e-13 rad, where it may read an angle as 0
|
||
- `decode_repetition_d3`, `wai.union_find`: predictions that are a least-weight correction's, of 129 syndromes (no claim of least weight) — measured 129
|
||
- `decode_surface_z_d3`, `wai.union_find`: predictions that are a least-weight correction's, of 2494 syndromes (no claim of least weight) — measured 2434
|
||
- `decode_surface_z_d5`, `wai.union_find`: predictions that are a least-weight correction's, of 6492 syndromes (no claim of least weight) — measured 6485
|
||
- `dyadic_n20_k16`, `qsim.statevector`: a listed disagreement no longer shows — measured False. qsim 0.22.1 (single precision, gates fused to two qubits, one thread), on 148 rotations by m/2^16 of a turn and cz gates on 20 qubits, gives a state 2.3e-4 from the exact one, past the single-precision bound of 1.9e-4 that 148 gates allow (tools/tolerance.py), and almost all of it is the norm: 1.000
|
||
- `dyadic_n20_k16`, `qsim.statevector`: reproducer (corpus/reproducers/qsim_single_precision_norm.py): the state of all 148 gates is farther from the double-precision state than the single-precision bound of 0.000194, and its norm is past 1 by about as much — measured {'distance': 5.54e-07, 'norm_minus_1': 1e-08}. the claim no longer holds
|
||
- `dyadic_n20_k16`, `qsim.statevector`: reproducer (corpus/reproducers/qsim_single_precision_norm.py): its run of the first 60 gates has a norm larger than its run of 59 by more than 10^-5, where the 60th gate applied by hand in single precision to the 59 gates' state moves the norm by less than 10^-6 — measured {'run_60_minus_run_59': -1.8e-08, 'by_hand': 2.6774e-08}. the claim no longer holds
|
||
- `dyadic_n20_k16`, `qsim.statevector`: reproducer (corpus/reproducers/qsim_single_precision_norm.py): another single-precision state vector of the same circuit (the circuit library's own, complex64) is as far from the double-precision state, within 1% — measured 4.8e-07. the claim no longer holds
|
||
|
||
</details>
|
||
|
||
Versions: cirq-core 1.7.0, mqt.core 3.11.0, mqt.ddsim 2.7.0, numpy 2.5.4, python 3.12.16, qiskit 2.6.2, qiskit-aer 0.18.2, qsimcirq 0.22.1, quimb 1.15.0, scipy 1.18.1, stim 1.16.0.
|
||
|
||
### `conformance-macos-arm64.json`
|
||
|
||
Host: Apple M3 Ultra, macOS 27.2.1, 32 logical CPUs, 256 GiB, arm64. Tier full, 3936.0 s. Checks: info 15, known 16, not run 16, pass 1973, refused 11.
|
||
|
||
| family | `wai.exact` | `wai.statevector` | `wai.stabilizer` | `wai.auto` | `wai.mps` | `wai.tensor_network` | `wai.density_matrix` | `wai.qec` | `wai.pauli` | `wai.stabrank` | `wai.cutrank` | `wai.trajectories` | `wai.mitigate` | `wai.pulse` | `wai.matching` | `wai.union_find` | `aer.statevector` | `aer.qasm_import` | `aer.stabilizer` | `aer.mps` | `aer.density_matrix` | `stim.tableau` | `quimb.dense` | `quimb.tensor_network` | `quimb.mps` | `ddsim.statevector` | `qsim.statevector` | `pairs and references` | `references` |
|
||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
||
| bit_order | 24/24 (0.068) | 8/8 (0.015) | 12/12 | 8/8 (0.0069) | | | | | | | | | | | | | 8/8 (0.016) | 6/6 (0.016) | 5/5 | | | 7/7 | 6/6 (0.019) | 6/6 (0.031) | | 8/8 (0.00015) | 8/8 (0.013) | 15/15 (0.0084) | 5/5 |
|
||
| clifford_large | 4/4 (0.012) | 1/1 (0.00077) | 34/34 (0.43) | 1/1 (7.8e-05) | | | | | | | | | | | | | 1/1 (0.00084) | 1/1 (0.00084) | 16/16 (0.51) | | | 19/19 (0.34) | 1/1 (0.0017) | 1/1 (4.8e-08) | | 1/1 (2.4e-07) | 1/1 (0.0024) | | 15/15 |
|
||
| cutrank | | | | | | | | | | | 6/6 (0.56) | | | | | | | | | | | | | | | | | | |
|
||
| decoders | | | | | | | | | | | | | | | 3/3 | 3/3 | | | | | | | | | | | | | |
|
||
| dynamic | | 12/12 (0.29) | 8/8 (0.21) | 12/12 (0.29) | | | | | | | | | | | | | 12/12 (0.36) | | | | | 8/8 (0.31) | | | | 8/8 (0.25) · 11 known | 6 not run | | |
|
||
| gate_conventions | 188/188 (0.069) | 47/47 (0.017) | | 47/47 (0.066) | | | | | | | | | | | | | 47/47 (0.018) | 47/47 (0.018) | | | | | 46/46 (0.017) · 1 not run | 46/46 (0.032) · 1 not run | | 47/47 (0.00015) | 46/46 (0.026) · 1 not run | | |
|
||
| ghz | 20/20 (0.042) | 7/7 (0.21) | 2/2 (0.022) | 7/7 (0.022) | | | | | | | | | | | | | 7/7 (0.058) | 5/5 (0.011) | | | | 2/2 (0.29) | 5/5 (0.0094) | 5/5 (0.041) | | 7/7 (0.058) | 7/7 (0.14) | | 5/5 |
|
||
| grover | 16/16 (0.029) | 6/6 (0.12) | | 6/6 (0.14) | | | | | | | | | | | | | 6/6 (0.25) | 4/4 (0.0043) | | | | | 4/4 (0.0079) | 4/4 (0.00032) | | 6/6 (0.2) | 6/6 (0.27) | | 4/4 |
|
||
| mirror | 8/8 (0.007) · 1 not run | 3/3 (0.00036) | | | | | | | | | | | | | | | 3/3 (0.0011) | | | | | | 3/3 (0.00049) | | | 2/2 (0.00016) · 1 not run | 3/3 (0.00059) | | |
|
||
| mitigation | | | | | | | | | | | | | 18/18 (0.23) | | | | | | | | | | | | | | | | |
|
||
| noise | | | | | | | 3/3 (0.00093) | | | | | | | | | | | | | | 3/3 (0.00093) | | | | | | | | |
|
||
| noisy | | | 11/11 (0.34) | | | | 16/16 (0.24) | | | | | 16/16 (0.41) | | | | | | | | | 3/3 (0.0003) | | | | | | | | |
|
||
| other | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 3/3 |
|
||
| pauli | | | | | | | | | 81/81 (0.11) | | | | | | | | | | | | | | | | | | | | |
|
||
| pulse | | | | | | | | | | | | | | 8/8 (0.0013) | | | | | | | | | | | | | | | |
|
||
| qec | | | | | | | | 29/29 (0.6) · 2 refused as listed | | | | | | | | | | | | | | 22/22 (0.52) · 2 not run | | | | | | 44/44 (0.016) | |
|
||
| qft | 36/36 (0.042) · 1 not run | 12/12 (0.58) | | 11/11 (0.66) | | | | | | | | | | | | | 12/12 (0.61) | 6/6 (0.009) | | | | | 10/10 (0.0062) | 5/5 (0.0093) | | 12/12 (0.62) | 12/12 (0.63) | 15/15 (0.0027) | 8/8 |
|
||
| qpe | 12/12 (0.017) · 2 refused as listed | 5/5 (0.0091) | | 5/5 (0.013) | | | | | | | | | | | | | 5/5 (0.005) | 5/5 (0.0074) | | | | | 5/5 (0.0068) | 4/4 (0.0011) | | 5/5 (7e-06) | 5/5 (0.0037) | | 5/5 |
|
||
| random_clifford_t | 16/16 (0.039) | 4/4 (0.0047) | | 4/4 (0.017) | | | | | | | | | | | | | 4/4 (0.0042) | 3/3 (0.0042) | | | | | 4/4 (0.003) | 3/3 (0.00026) | | 4/4 (3.7e-05) | 4/4 (0.0022) | | |
|
||
| random_dyadic | 11/11 (0.008) · 1 not run | 3/3 (0.0019) | | 3/3 (0.0016) | | | | | | | | | | | | | 3/3 (0.0031) | 2/2 (0.0038) | | | | | 3/3 (0.0014) | 2/2 (0.00016) | | 3/3 (8e-06) | 2/2 (0.004) · 5 known | | |
|
||
| random_rotations | 4 refused as listed | 6/6 (0.48) | | 6/6 (0.48) | | | | | | | | | | | | | 6/6 (0.49) | 3/3 (0.0039) | | | | | 4/4 (0.0021) | 3/3 (0.00014) | | 6/6 (0.48) | 6/6 (0.4) | 10/10 (0.067) | |
|
||
| small_angle | 62/62 (0.9) · 3 refused as listed | 32/32 (0.016) | 2/2 | 18/18 (0.098) | | | | | | | | | | | | | 32/32 (0.018) | 29/29 (0.016) | 1/1 | | | 1/1 | 30/30 (0.019) | 29/29 (0.016) | | 29/29 (0.15) | 33/33 (0.0075) | | 1/1 |
|
||
| stabrank | | | | | | | | | | 9/9 (0.039) | | | | | | | | | | | | | | | | | | | |
|
||
| wide_mps | | | | | 6/6 (0.00017) | 5/5 (0.00057) | | | | | | | | | | | | | | 4/4 (0.00023) · 1 not run | | | | 5/5 (0.043) | 5/5 (7.3e-05) | | | | |
|
||
| wide_tn | | | | | 1/1 (0.00093) | 1/1 (6.4e-07) | | | | | | | | | | | | | | 1/1 (0.0033) | | | | 1/1 (0.019) | 1/1 (0.0006) | | | 21/21 (0.015) | |
|
||
|
||
Known disagreements of other engines with the exact reference (`corpus/known-disagreements.json`):
|
||
|
||
- `repeat_until_success`, `ddsim.statevector`: ValueError: [changePermutation] Target must be an injective mapping using only keys and logical qubits from the source permutation. | known: MQT DDSIM 2.7.0's qasm_simulator raises ValueError [changePermutation] on this program (two qubits; qubit 1 measured three times in the middle, with gates between and an x conditioned on each reading; four classical bits) and gives no counts. It raises the same without the conditioned x, and on qubit 1 measured, h, measured again, then qubit 0 measured into a third bit; with no third bit it gives counts. Each is a case of the reproducer.
|
||
- `dyadic_n20_k16`, `qsim.statevector`: single precision, fusion width 2 | known: qsim 0.22.1 (single precision, gates fused to two qubits, one thread), on 148 rotations by m/2^16 of a turn and cz gates on 20 qubits, gives a state 2.3e-4 from the exact one, past the single-precision bound of 1.9e-4 that 148 gates allow (tools/tolerance.py), and almost all of it is the norm: 1.00023. Its run of the first 60 gates has a norm larger than its run of 59 by 6e-5, where the 60th gate applied by hand in single precision to the 59 gates' state moves the norm by under 10^-6. Cirq 1.7.0's own complex64 simulator gives the same distance. On 16 qubits the same construction stays within its bound. Each is a case of the reproducer, which builds the circuit with the corpus's own adapter.
|
||
- `measure_twice`, `ddsim.statevector`: 10: 49817 shots, probability 0; 11: 0 shots, expected 50000.0 ± 1095.4 | known: MQT DDSIM 2.7.0's qasm_simulator, given h q[0]; c[0] = measure q[0]; c[1] = measure q[0]; with nothing between the two measurements, returns 00 and 10: c[0] is never set. With x in place of h it gives 10 on every shot; with a barrier between the measurements, 00 and 11; with c[1] measured first and c[0] second, ValueError [changePermutation]. Each is a case of the reproducer, with the circuit built in Qiskit 2.6.2.
|
||
- `measure_twice`, `ddsim.statevector`: known: MQT DDSIM 2.7.0's qasm_simulator, given h q[0]; c[0] = measure q[0]; c[1] = measure q[0]; with nothing between the two measurements, returns 00 and 10: c[0] is never set. With x in place of h it gives 10 on every shot; with a barrier between the measurements, 00 and 11; with c[1] measured first and c[0] second, ValueError [changePermutation]. Each is a case of the reproducer, with the circuit built in Qiskit 2.6.2.
|
||
- `measure_twice`, `ddsim.statevector`, reproducer (corpus/reproducers/ddsim_repeated_measurement.py): h, then c[0] and c[1] measured from the qubit with nothing between: only 00 and 10 come — saw ['00', '10']
|
||
- `measure_twice`, `ddsim.statevector`, reproducer (corpus/reproducers/ddsim_repeated_measurement.py): x, then the same two measurements: 10 on every shot — saw ['10']
|
||
- `measure_twice`, `ddsim.statevector`, reproducer (corpus/reproducers/ddsim_repeated_measurement.py): h, the two measurements with a barrier between: 00 and 11 — saw ['00', '11']
|
||
- `measure_twice`, `ddsim.statevector`, reproducer (corpus/reproducers/ddsim_repeated_measurement.py): h, then c[1] measured first and c[0] second: an error naming changePermutation — saw ValueError: [changePermutation] Target must be an injective mapping using only keys and logical qubits from the source permutation.
|
||
- `repeat_until_success`, `ddsim.statevector`, reproducer (corpus/reproducers/ddsim_feedback_rounds.py): repeat_until_success: an error naming changePermutation, and no counts — saw ValueError: [changePermutation] Target must be an injective mapping using only keys and logical qubits from the source permutation.
|
||
- `repeat_until_success`, `ddsim.statevector`, reproducer (corpus/reproducers/ddsim_feedback_rounds.py): the same three rounds without the conditioned x: the same error — saw ValueError: [changePermutation] Target must be an injective mapping using only keys and logical qubits from the source permutation.
|
||
- `repeat_until_success`, `ddsim.statevector`, reproducer (corpus/reproducers/ddsim_feedback_rounds.py): qubit 1 measured, h, measured again, then qubit 0 measured into a third bit: the same error — saw ValueError: [changePermutation] Target must be an injective mapping using only keys and logical qubits from the source permutation.
|
||
- `repeat_until_success`, `ddsim.statevector`, reproducer (corpus/reproducers/ddsim_feedback_rounds.py): the same without qubit 0's measurement into a third bit: counts — saw counts over 4 outcomes
|
||
- `dyadic_n20_k16`, `qsim.statevector`, reproducer (corpus/reproducers/qsim_single_precision_norm.py): the state of all 148 gates is farther from the double-precision state than the single-precision bound of 0.000194, and its norm is past 1 by about as much — saw {'distance': 0.000232443, 'norm_minus_1': 0.000232442}
|
||
- `dyadic_n20_k16`, `qsim.statevector`, reproducer (corpus/reproducers/qsim_single_precision_norm.py): the same construction on 16 qubits stays within its bound — saw 6.448e-06
|
||
- `dyadic_n20_k16`, `qsim.statevector`, reproducer (corpus/reproducers/qsim_single_precision_norm.py): its run of the first 60 gates has a norm larger than its run of 59 by more than 10^-5, where the 60th gate applied by hand in single precision to the 59 gates' state moves the norm by less than 10^-6 — saw {'run_60_minus_run_59': 6.0414e-05, 'by_hand': 2.6285e-08}
|
||
- `dyadic_n20_k16`, `qsim.statevector`, reproducer (corpus/reproducers/qsim_single_precision_norm.py): another single-precision state vector of the same circuit (the circuit library's own, complex64) is as far from the double-precision state, within 1% — saw 0.000232436
|
||
|
||
<details><summary>Refusals by the engine under test, each listed in <code>corpus/expected-refusals.json</code> with its words (11)</summary>
|
||
|
||
- `qpe_t6_third`, `wai.exact`: the angle 2.0943951023931953 is not a dyadic multiple of 2π (2πm/2^k, k ≤ 32) [Q500]
|
||
- `qpe_t10_third`, `wai.exact`: the angle 2.0943951023931953 is not a dyadic multiple of 2π (2πm/2^k, k ≤ 32) [Q500]
|
||
- `rotations_n6`, `wai.exact`: the angle 1.6459015101789476 is not a dyadic multiple of 2π (2πm/2^k, k ≤ 32) [Q500]
|
||
- `rotations_n10`, `wai.exact`: the angle 0.49840613019150304 is not a dyadic multiple of 2π (2πm/2^k, k ≤ 32) [Q500]
|
||
- `rotations_n12`, `wai.exact`: the angle 1.437905822610216 is not a dyadic multiple of 2π (2πm/2^k, k ≤ 32) [Q500]
|
||
- `below_grid_k33`, `wai.exact`: the angle 0.0000000007314590396335798 is not a dyadic multiple of 2π (2πm/2^k, k ≤ 32) [Q500]
|
||
- `below_grid_k40`, `wai.exact`: the angle 0.000000000005714523747137342 is not a dyadic multiple of 2π (2πm/2^k, k ≤ 32) [Q500]
|
||
- `tiny_radians`, `wai.exact`: the angle 0.000000000001 is not a dyadic multiple of 2π (2πm/2^k, k ≤ 32) [Q500]
|
||
- `rotations_n18`, `wai.exact`: the angle 1.586539928488264 is not a dyadic multiple of 2π (2πm/2^k, k ≤ 32) [Q500]
|
||
- `qec_refused_channel_with_no_independent_form`, `wai.qec`: line 2: PAULI_CHANNEL_1(0.1, 0.1, 0): its exclusive outcomes have no form as independent X, Y and Z flips, which this simulator and a detector error model both need
|
||
- `qec_refused_random_detector`, `wai.qec`: a detector or observable is not deterministic (it anticommutes with op 0)
|
||
|
||
</details>
|
||
|
||
<details><summary>Checks other engines did not make, and why (16)</summary>
|
||
|
||
- `mirror_n20`, `wai.exact`: not rerun: 8386 ops on 2^20 amplitudes is past the referee's 2^30 updates
|
||
- `mirror_n20`, `ddsim.statevector`: did not finish within 900 s
|
||
- `gate_gphase_controlled`, `quimb.dense`: no gate gphase
|
||
- `gate_gphase_controlled`, `quimb.tensor_network`: no gate gphase
|
||
- `gate_gphase_controlled`, `qsim.statevector`: a global phase gate
|
||
- `teleport`, `qsim.statevector`: measurement in the middle (or one qubit measured twice)
|
||
- `reset_after_superposition`, `qsim.statevector`: measurement in the middle (or one qubit measured twice)
|
||
- `measure_twice`, `qsim.statevector`: measurement in the middle (or one qubit measured twice)
|
||
- `feedback_flip`, `qsim.statevector`: measurement in the middle (or one qubit measured twice)
|
||
- `ghz_by_fusion`, `qsim.statevector`: measurement in the middle (or one qubit measured twice)
|
||
- `repeat_until_success`, `qsim.statevector`: measurement in the middle (or one qubit measured twice)
|
||
- `mps_ghz_n100`, `aer.mps`: CircuitTooWideForTarget: 'Number of qubits (100) in circuit-46 is greater than maximum (63) in the coupling_map'
|
||
- `qft_n22_x2796203`, `wai.exact`: not rerun: 298 ops on 2^22 amplitudes is past the referee's 2^30 updates
|
||
- `dyadic_n20_k16`, `wai.exact`: not rerun: 1038 ops on 2^20 amplitudes is past the referee's 2^30 updates
|
||
- `qec_refused_channel_with_no_independent_form`, `stim.tableau`: ValueError: Encountered the operation PAULI_CHANNEL_1 during error analysis, but this operation requires the `approximate_disjoint_errors` option to be enabled. If you're calling from python, using stim.Circuit.detector_error_model, you need to add the argument approximate_disjoint_errors=True. If
|
||
- `qec_refused_random_detector`, `stim.tableau`: ValueError: The circuit contains non-deterministic detectors. To make an SVG picture of the problem, you can use the python API like this: your_circuit.diagram('detslice-with-ops-svg', tick=range(0, 5), filter_coords=['D0', ]) or the command line API like this: stim diagram --in your_circui
|
||
|
||
</details>
|
||
|
||
<details><summary>Recorded and not judged (12)</summary>
|
||
|
||
- `below_grid_k47`, `ddsim.statevector`: holds the phase of its small-angle gate: the share of the step from the state without that gate to the ideal (1 holds it, 0 drops it) — measured -4.3e-78. drops it: the angle, 4.46e-14 rad, is below its parameter tolerance of 1e-13 rad, where it may read an angle as 0
|
||
- `below_grid_k48`, `ddsim.statevector`: holds the phase of its small-angle gate: the share of the step from the state without that gate to the ideal (1 holds it, 0 drops it) — measured -4.3e-78. drops it: the angle, 2.23e-14 rad, is below its parameter tolerance of 1e-13 rad, where it may read an angle as 0
|
||
- `below_grid_k52`, `ddsim.statevector`: holds the phase of its small-angle gate: the share of the step from the state without that gate to the ideal (1 holds it, 0 drops it) — measured -4.3e-78. drops it: the angle, 1.4e-15 rad, is below its parameter tolerance of 1e-13 rad, where it may read an angle as 0
|
||
- `below_grid_k60`, `wai.statevector`: holds the phase of its small-angle gate: the share of the step from the state without that gate to the ideal (1 holds it, 0 drops it) — measured 1. neither can be told: its distance from the ideal state, 2.22e-16, is more than half the gate's effect, 2.72e-18
|
||
- `below_grid_k60`, `aer.statevector`: holds the phase of its small-angle gate: the share of the step from the state without that gate to the ideal (1 holds it, 0 drops it) — measured -21. neither can be told: its distance from the ideal state, 6.12e-17, is more than half the gate's effect, 2.72e-18
|
||
- `below_grid_k60`, `aer.qasm_import`: holds the phase of its small-angle gate: the share of the step from the state without that gate to the ideal (1 holds it, 0 drops it) — measured -21. neither can be told: its distance from the ideal state, 6.12e-17, is more than half the gate's effect, 2.72e-18
|
||
- `below_grid_k60`, `quimb.dense`: holds the phase of its small-angle gate: the share of the step from the state without that gate to the ideal (1 holds it, 0 drops it) — measured 1. neither can be told: its distance from the ideal state, 2.22e-16, is more than half the gate's effect, 2.72e-18
|
||
- `below_grid_k60`, `quimb.tensor_network`: holds the phase of its small-angle gate: the share of the step from the state without that gate to the ideal (1 holds it, 0 drops it) — measured 1. neither can be told: its distance from the ideal state, 1.11e-16, is more than half the gate's effect, 2.72e-18
|
||
- `below_grid_k60`, `ddsim.statevector`: holds the phase of its small-angle gate: the share of the step from the state without that gate to the ideal (1 holds it, 0 drops it) — measured -4.3e-78. drops it: the angle, 5.45e-18 rad, is below its parameter tolerance of 1e-13 rad, where it may read an angle as 0
|
||
- `decode_repetition_d3`, `wai.union_find`: predictions that are a least-weight correction's, of 129 syndromes (no claim of least weight) — measured 129
|
||
- `decode_surface_z_d3`, `wai.union_find`: predictions that are a least-weight correction's, of 2494 syndromes (no claim of least weight) — measured 2434
|
||
- `decode_surface_z_d5`, `wai.union_find`: predictions that are a least-weight correction's, of 6492 syndromes (no claim of least weight) — measured 6485
|
||
|
||
</details>
|
||
|
||
Versions: cirq-core 1.7.0, mqt.core 3.11.0, mqt.ddsim 2.7.0, numpy 2.5.4, python 3.12.16, qiskit 2.6.2, qiskit-aer 0.18.2, qsimcirq 0.22.1, quimb 1.15.0, scipy 1.18.1, stim 1.16.0.
|
||
|
||
### `performance-linux-x86_64.json`
|
||
|
||
Host: AMD RYZEN AI MAX+ 395 w/ Radeon 8060S, Ubuntu 26.04.1 LTS, 32 logical CPUs, 123 GiB, x86_64. Each figure is the engine's own call, the median of 5 runs (the minimum in brackets). Memory is the peak resident set of the process that ran the engine, and the baseline the same given a two-qubit job. Ops are the operations the engine ran, where it reports them.
|
||
|
||
- `aer.*` seconds: the simulator's own time for the experiment, as its result states it (time_taken); the conversion of the circuit to its own form is outside it.
|
||
- `ddsim.*` seconds: the run call, which converts the circuit to its own form inside it.
|
||
- `qsim.*` seconds: the simulate call, which converts the circuit to its own form inside it.
|
||
- `quimb.*` seconds: the building of the circuit object, which applies each gate as it is added, and the read-out.
|
||
- `stim.*` seconds: the tableau's or sampler's run, after the circuit text is parsed.
|
||
- `wai.*` seconds: the engine's run, after the program is read and lowered (the driver's own clock).
|
||
|
||
| case | engine | threads | ops | seconds, median (min) | peak MiB (baseline) | load average before → after |
|
||
|---|---|---|---|---|---|---|
|
||
| qft_n20 | `wai.statevector` | all (32) | 230 | 0.0363 (0.0347) | 26 (5) | 13.9 → 13.9 |
|
||
| qft_n20 | `aer.statevector` | 32 | 231 | 0.819 (0.737) | 116 (100) | 13.9 → 13.7 |
|
||
| qft_n20 | `qsim.statevector` | 32 | | 4.78 (3.16) | 196 (188) | 14.6 → 28.9 |
|
||
| qft_n20 | `ddsim.statevector` | not set | | 0.349 (0.329) | 132 (99) | 28.0 → 28.0 |
|
||
| qft_n20 | `wai.exact` | 1 (no threads) | 250 | 0.27 (0.26) | 38 (5) | 28.0 → 27.2 |
|
||
| qft_n20 | `quimb.dense` | not set | | 4.92 (3.99) | 291 (195) | 27.2 → 31.9 |
|
||
| qft_n20 | `wai.statevector` | 1 (pinned) | 230 | 0.372 (0.352) | 23 (5) | 31.9 → 31.2 |
|
||
| qft_n20 | `aer.statevector` | 1 (pinned) | 231 | 0.445 (0.294) | 116 (100) | 31.2 → 31.4 |
|
||
| qft_n20 | `qsim.statevector` | 1 (pinned) | | 0.0454 (0.0434) | 195 (188) | 31.4 → 29.3 |
|
||
| qft_n20 | `ddsim.statevector` | 1 (pinned) | | 0.562 (0.5) | 132 (99) | 29.3 → 27.7 |
|
||
| qft_n20 | `wai.exact` | 1 (pinned) | 250 | 0.393 (0.349) | 38 (5) | 27.7 → 27.7 |
|
||
| qft_n20 | `quimb.dense` | 1 (pinned) | | 1.37 (1.26) | 276 (195) | 27.7 → 25.0 |
|
||
| qft_n24 | `wai.statevector` | all (32) | 324 | 0.45 (0.441) | 279 (5) | 25.0 → 26.2 |
|
||
| qft_n24 | `aer.statevector` | 32 | 325 | 3.9 (1.6) | 356 (100) | 26.2 → 29.5 |
|
||
| qft_n24 | `qsim.statevector` | 32 | | 2.56 (1.91) | 315 (188) | 29.5 → 30.9 |
|
||
| qft_n24 | `ddsim.statevector` | not set | | 6.22 (5.34) | 612 (99) | 30.9 → 25.7 |
|
||
| qft_n24 | `wai.exact` | 1 (no threads) | 348 | 6.6 (6.48) | 518 (5) | 25.7 → 18.8 |
|
||
| qft_n24 | `wai.statevector` | 1 (pinned) | 324 | 5.82 (5.35) | 263 (5) | 18.8 → 20.5 |
|
||
| qft_n24 | `aer.statevector` | 1 (pinned) | 325 | 8.17 (6.6) | 356 (100) | 20.5 → 21.2 |
|
||
| qft_n24 | `qsim.statevector` | 1 (pinned) | | 1.9 (1.63) | 315 (188) | 21.2 → 19.6 |
|
||
| qft_n24 | `ddsim.statevector` | 1 (pinned) | | 7.36 (6.23) | 612 (99) | 19.6 → 18.5 |
|
||
| qft_n24 | `wai.exact` | 1 (pinned) | 348 | 7.8 (7) | 518 (5) | 18.5 → 14.9 |
|
||
| qft_n26 | `wai.statevector` | all (32) | 377 | 2.14 (2.05) | 1047 (5) | 14.9 → 19.9 |
|
||
| qft_n26 | `aer.statevector` | 32 | 378 | 3.97 (3.7) | 1124 (100) | 19.9 → 23.6 |
|
||
| qft_n26 | `qsim.statevector` | 32 | | 5.62 (3.93) | 700 (188) | 23.6 → 31.5 |
|
||
| qft_n28 | `wai.statevector` | all (32) | 434 | 14.2 (12.4) | 4118 (5) | 31.5 → 44.7 |
|
||
| qft_n28 | `aer.statevector` | 32 | 435 | 16.8 (15.3) | 4198 (100) | 44.7 → 41.8 |
|
||
| qft_n28 | `qsim.statevector` | 32 | | 12.7 (11.9) | 2234 (188) | 41.8 → 38.5 |
|
||
| rotations_n20 | `wai.statevector` | all (32) | 590 | 0.0963 (0.0761) | 27 (5) | 38.5 → 38.5 |
|
||
| rotations_n20 | `aer.statevector` | 32 | 591 | 1.36 (1.06) | 120 (100) | 38.5 → 40.0 |
|
||
| rotations_n20 | `qsim.statevector` | 32 | | 1.42 (1.22) | 195 (188) | 40.0 → 38.4 |
|
||
| rotations_n20 | `quimb.dense` | not set | | 15.7 (9.5) | 290 (195) | 38.4 → 54.5 |
|
||
| rotations_n20 | `wai.statevector` | 1 (pinned) | 590 | 0.613 (0.481) | 23 (5) | 54.5 → 52.2 |
|
||
| rotations_n20 | `aer.statevector` | 1 (pinned) | 591 | 0.876 (0.709) | 120 (100) | 52.2 → 50.1 |
|
||
| rotations_n20 | `qsim.statevector` | 1 (pinned) | | 0.0458 (0.0437) | 196 (188) | 50.1 → 45.3 |
|
||
| rotations_n20 | `quimb.dense` | 1 (pinned) | | 2.25 (2.2) | 276 (195) | 45.3 → 38.4 |
|
||
| rotations_n24 | `wai.statevector` | all (32) | 710 | 0.892 (0.869) | 282 (5) | 38.4 → 37.3 |
|
||
| rotations_n24 | `aer.statevector` | 32 | 711 | 2.65 (2.44) | 356 (100) | 37.3 → 38.9 |
|
||
| rotations_n24 | `qsim.statevector` | 32 | | 1.71 (1.52) | 315 (188) | 38.9 → 38.1 |
|
||
| rotations_n24 | `wai.statevector` | 1 (pinned) | 710 | 10.4 (9.72) | 263 (5) | 38.1 → 21.1 |
|
||
| rotations_n24 | `aer.statevector` | 1 (pinned) | 711 | 15.1 (13.3) | 356 (100) | 21.1 → 13.5 |
|
||
| rotations_n24 | `qsim.statevector` | 1 (pinned) | | 1.54 (1.52) | 316 (188) | 13.5 → 13.6 |
|
||
| rotations_n26 | `wai.statevector` | all (32) | 770 | 4.12 (3.94) | 1050 (5) | 13.6 → 23.3 |
|
||
| rotations_n26 | `aer.statevector` | 32 | 771 | 8.7 (8) | 1123 (100) | 23.3 → 33.4 |
|
||
| rotations_n26 | `qsim.statevector` | 32 | | 4.15 (4.07) | 700 (188) | 33.4 → 35.5 |
|
||
| grover_n10 | `wai.statevector` | all (32) | 114 | 0.000998 (0.000871) | 6 (5) | 35.5 → 35.5 |
|
||
| grover_n10 | `wai.exact` | 1 (no threads) | 26686 | 0.0363 (0.0331) | 17 (5) | 35.5 → 35.5 |
|
||
| grover_n10 | `wai.exact_whole` | 1 (no threads) | 114 | 0.000195 (0.000162) | 6 (5) | 35.5 → 35.5 |
|
||
| grover_n10 | `aer.statevector` | 32 | 123 | 0.000298 (0.000293) | 100 (100) | 35.5 → 35.5 |
|
||
| grover_n10 | `qsim.statevector` | 32 | | 0.0014 (0.00129) | 188 (188) | 35.5 → 33.5 |
|
||
| grover_n10 | `ddsim.statevector` | not set | | 0.00883 (0.00609) | 100 (99) | 33.5 → 33.5 |
|
||
| grover_n10 | `wai.statevector` | 1 (pinned) | 114 | 0.000446 (0.000321) | 6 (5) | 33.5 → 33.5 |
|
||
| grover_n10 | `wai.exact` | 1 (pinned) | 26686 | 0.0507 (0.0317) | 17 (5) | 33.5 → 33.5 |
|
||
| grover_n10 | `wai.exact_whole` | 1 (pinned) | 114 | 0.000273 (0.000271) | 6 (5) | 33.5 → 31.6 |
|
||
| grover_n10 | `aer.statevector` | 1 (pinned) | 123 | 0.000298 (0.000289) | 100 (100) | 31.6 → 31.6 |
|
||
| grover_n10 | `qsim.statevector` | 1 (pinned) | | 0.00137 (0.00128) | 187 (188) | 31.6 → 29.7 |
|
||
| grover_n10 | `ddsim.statevector` | 1 (pinned) | | 0.00742 (0.0058) | 100 (99) | 29.7 → 27.8 |
|
||
| grover_n14 | `wai.statevector` | all (32) | 158 | 0.00241 (0.00227) | 6 (5) | 27.8 → 27.8 |
|
||
| grover_n14 | `wai.exact` | 1 (no threads) | 557146 | 11.4 (10.6) | 242 (5) | 27.8 → 14.9 |
|
||
| grover_n14 | `wai.exact_whole` | 1 (no threads) | 158 | 0.00354 (0.00352) | 6 (5) | 14.9 → 14.9 |
|
||
| grover_n14 | `aer.statevector` | 32 | 167 | 0.00298 (0.00286) | 100 (100) | 14.9 → 14.9 |
|
||
| grover_n14 | `qsim.statevector` | 32 | | 0.0773 (0.0661) | 188 (188) | 14.9 → 14.7 |
|
||
| grover_n14 | `ddsim.statevector` | not set | | 0.00672 (0.0066) | 99 (99) | 14.7 → 14.7 |
|
||
| grover_n14 | `wai.statevector` | 1 (pinned) | 158 | 0.00225 (0.00156) | 6 (5) | 14.7 → 14.7 |
|
||
| grover_n14 | `wai.exact` | 1 (pinned) | 557146 | 17.4 (13.8) | 242 (5) | 14.7 → 12.9 |
|
||
| grover_n14 | `wai.exact_whole` | 1 (pinned) | 158 | 0.00343 (0.0034) | 6 (5) | 12.9 → 12.9 |
|
||
| grover_n14 | `aer.statevector` | 1 (pinned) | 167 | 0.00296 (0.00281) | 100 (100) | 12.9 → 12.9 |
|
||
| grover_n14 | `qsim.statevector` | 1 (pinned) | | 0.0018 (0.0018) | 187 (188) | 12.9 → 12.7 |
|
||
| grover_n14 | `ddsim.statevector` | 1 (pinned) | | 0.0073 (0.00706) | 100 (99) | 12.7 → 12.7 |
|
||
| grover_n16 | `wai.statevector` | all (32) | 180 | 0.00857 (0.0083) | 7 (5) | 12.7 → 12.7 |
|
||
| grover_n16 | `wai.exact_whole` | 1 (no threads) | 180 | 0.0169 (0.0162) | 7 (5) | 12.7 → 12.7 |
|
||
| grover_n16 | `aer.statevector` | 32 | 189 | 0.462 (0.437) | 101 (100) | 12.7 → 15.2 |
|
||
| grover_n16 | `qsim.statevector` | 32 | | 0.328 (0.288) | 189 (188) | 15.2 → 15.1 |
|
||
| grover_n16 | `ddsim.statevector` | not set | | 0.00875 (0.0085) | 101 (99) | 15.1 → 15.1 |
|
||
| grover_n16 | `wai.statevector` | 1 (pinned) | 180 | 0.00965 (0.0096) | 7 (5) | 15.1 → 15.1 |
|
||
| grover_n16 | `wai.exact_whole` | 1 (pinned) | 180 | 0.0281 (0.0269) | 8 (5) | 15.1 → 15.1 |
|
||
| grover_n16 | `aer.statevector` | 1 (pinned) | 189 | 0.0186 (0.0182) | 101 (100) | 15.1 → 14.6 |
|
||
| grover_n16 | `qsim.statevector` | 1 (pinned) | | 0.00342 (0.00234) | 188 (188) | 14.6 → 14.4 |
|
||
| grover_n16 | `ddsim.statevector` | 1 (pinned) | | 0.0115 (0.0113) | 102 (99) | 14.4 → 14.2 |
|
||
| grover_n20 | `wai.statevector` | all (32) | 224 | 0.0268 (0.0259) | 25 (5) | 14.2 → 14.2 |
|
||
| grover_n20 | `wai.exact_whole` | 1 (no threads) | 224 | 0.34 (0.339) | 38 (5) | 14.2 → 14.2 |
|
||
| grover_n20 | `aer.statevector` | 32 | 233 | 0.72 (0.61) | 124 (100) | 14.2 → 16.7 |
|
||
| grover_n20 | `qsim.statevector` | 32 | | 0.429 (0.316) | 195 (188) | 16.7 → 16.6 |
|
||
| grover_n20 | `ddsim.statevector` | not set | | 0.0332 (0.0325) | 132 (99) | 16.6 → 16.5 |
|
||
| grover_n20 | `wai.statevector` | 1 (pinned) | 224 | 0.204 (0.204) | 22 (5) | 16.5 → 16.5 |
|
||
| grover_n20 | `wai.exact_whole` | 1 (pinned) | 224 | 0.586 (0.583) | 38 (5) | 16.5 → 16.5 |
|
||
| grover_n20 | `aer.statevector` | 1 (pinned) | 233 | 0.35 (0.35) | 124 (100) | 16.5 → 16.2 |
|
||
| grover_n20 | `qsim.statevector` | 1 (pinned) | | 0.0161 (0.0133) | 195 (188) | 16.2 → 15.5 |
|
||
| grover_n20 | `ddsim.statevector` | 1 (pinned) | | 0.0423 (0.032) | 132 (99) | 15.5 → 15.5 |
|
||
| clifford_n1000 | `wai.stabilizer` | 1 (no threads) | 35082 | 0.000968 (0.000961) | 90 (5) | 15.5 → 15.6 |
|
||
| clifford_n1000 | `stim.tableau` | not set | | 0.002 (0.00126) | 40 (24) | 15.6 → 15.6 |
|
||
| clifford_n1000 | `aer.stabilizer` | 32 | 35083 | 0.0184 (0.0161) | 207 (121) | 15.6 → 15.7 |
|
||
| clifford_n5000 | `wai.stabilizer` | 1 (no threads) | 58265 | 0.00666 (0.00655) | 142 (5) | 15.9 → 15.6 |
|
||
| clifford_n5000 | `stim.tableau` | not set | | 0.00839 (0.00829) | 65 (24) | 15.6 → 15.6 |
|
||
| surface_z_d5_sample | `wai.qec` | 1 (no threads) | | 0.0762 (0.0737) | 19 (4) | 15.6 → 15.7 |
|
||
| surface_z_d5_sample | `stim.tableau` | not set | | 0.348 (0.337) | 160 (38) | 15.7 → 15.7 |
|
||
| surface_z_d5_sample | `wai.qec` | 1 (pinned) | | 0.0949 (0.0812) | 19 (4) | 15.7 → 15.7 |
|
||
| surface_z_d5_sample | `stim.tableau` | 1 (pinned) | | 0.292 (0.273) | 160 (38) | 15.7 → 15.5 |
|
||
| surface_z_d5_model | `wai.qec` | 1 (no threads) | | 0.00185 (0.00182) | 7 (5) | 15.5 → 15.5 |
|
||
| surface_z_d5_model | `stim.tableau` | not set | | 0.00321 (0.00319) | 26 (25) | 15.5 → 15.5 |
|
||
| surface_z_d11_sample | `wai.qec` | 1 (no threads) | | 0.817 (0.811) | 163 (4) | 15.5 → 15.5 |
|
||
| surface_z_d11_sample | `stim.tableau` | not set | | 3.19 (3.05) | 853 (38) | 15.5 → 16.8 |
|
||
| surface_z_d11_sample | `wai.qec` | 1 (pinned) | | 1.06 (1.06) | 163 (4) | 16.8 → 16.8 |
|
||
| surface_z_d11_sample | `stim.tableau` | 1 (pinned) | | 4.05 (3.33) | 853 (38) | 16.8 → 16.8 |
|
||
| surface_z_d11_model | `wai.qec` | 1 (no threads) | | 0.0442 (0.0373) | 26 (5) | 16.8 → 16.8 |
|
||
| surface_z_d11_model | `stim.tableau` | not set | | 0.0542 (0.0509) | 40 (25) | 16.8 → 16.8 |
|
||
| qft_n40_amplitudes | `wai.mps` | 1 (no threads) | | 0.0114 (0.0107) | 11 (7) | 16.8 → 16.8 |
|
||
| qft_n40_amplitudes | `aer.mps` | 32 | 861 | 0.00371 (0.00352) | 105 (99) | 16.8 → 16.6 |
|
||
| qft_n40_amplitudes | `quimb.mps` | not set | | 1.98 (1.91) | 206 (200) | 16.6 → 18.2 |
|
||
| qft_n40_amplitudes | `wai.tensor_network` | all (32) | | 0.155 (0.15) | 12 (7) | 18.2 → 17.9 |
|
||
| qft_n40_amplitudes | `quimb.tensor_network` | not set | | 1.08 (0.961) | 220 (205) | 17.9 → 17.8 |
|
||
|
||
### `performance-macos-arm64.json`
|
||
|
||
Host: Apple M3 Ultra, macOS 27.2, 32 logical CPUs, 256 GiB, arm64. Each figure is the engine's own call, the median of 5 runs (the minimum in brackets). Memory is the peak resident set of the process that ran the engine, and the baseline the same given a two-qubit job. Ops are the operations the engine ran, where it reports them.
|
||
|
||
- `aer.*` seconds: the simulator's own time for the experiment, as its result states it (time_taken); the conversion of the circuit to its own form is outside it.
|
||
- `ddsim.*` seconds: the run call, which converts the circuit to its own form inside it.
|
||
- `qsim.*` seconds: the simulate call, which converts the circuit to its own form inside it.
|
||
- `quimb.*` seconds: the building of the circuit object, which applies each gate as it is added, and the read-out.
|
||
- `stim.*` seconds: the tableau's or sampler's run, after the circuit text is parsed.
|
||
- `wai.*` seconds: the engine's run, after the program is read and lowered (the driver's own clock).
|
||
|
||
| case | engine | threads | ops | seconds, median (min) | peak MiB (baseline) | load average before → after |
|
||
|---|---|---|---|---|---|---|
|
||
| qft_n20 | `wai.statevector` | all (32) | 230 | 0.0326 (0.0307) | 28 (4) | 84.8 → 84.9 |
|
||
| qft_n20 | `aer.statevector` | 32 | 231 | 0.0841 (0.0824) | 101 (83) | 84.9 → 84.9 |
|
||
| qft_n20 | `qsim.statevector` | 32 | | 0.0905 (0.0771) | 197 (188) | 84.9 → 90.7 |
|
||
| qft_n20 | `ddsim.statevector` | not set | | 0.145 (0.142) | 119 (86) | 89.8 → 89.8 |
|
||
| qft_n20 | `wai.exact` | 1 (no threads) | 250 | 0.242 (0.231) | 37 (3) | 89.8 → 89.8 |
|
||
| qft_n20 | `quimb.dense` | not set | | 1.6 (1.49) | 256 (158) | 89.8 → 87.8 |
|
||
| qft_n24 | `wai.statevector` | all (32) | 324 | 0.585 (0.54) | 308 (4) | 87.8 → 88.6 |
|
||
| qft_n24 | `aer.statevector` | 32 | 325 | 1.02 (0.944) | 341 (83) | 88.6 → 88.7 |
|
||
| qft_n24 | `qsim.statevector` | 32 | | 0.825 (0.777) | 317 (188) | 88.7 → 89.6 |
|
||
| qft_n24 | `ddsim.statevector` | not set | | 2.24 (2.2) | 599 (86) | 89.6 → 87.0 |
|
||
| qft_n24 | `wai.exact` | 1 (no threads) | 348 | 5.76 (5.49) | 518 (3) | 87.0 → 91.1 |
|
||
| qft_n26 | `wai.statevector` | all (32) | 377 | 2.66 (2.16) | 1070 (4) | 91.1 → 107.2 |
|
||
| qft_n26 | `aer.statevector` | 32 | 378 | 2.28 (2.08) | 1109 (83) | 107.2 → 108.9 |
|
||
| qft_n26 | `qsim.statevector` | 32 | | 2.77 (2.72) | 701 (188) | 108.9 → 108.4 |
|
||
| qft_n28 | `wai.statevector` | all (32) | 434 | 10.2 (10.2) | 4143 (4) | 108.4 → 129.7 |
|
||
| qft_n28 | `aer.statevector` | 32 | 435 | 7.04 (7.02) | 4181 (83) | 129.7 → 133.5 |
|
||
| qft_n28 | `qsim.statevector` | 32 | | 9.45 (9.41) | 2238 (188) | 133.5 → 107.2 |
|
||
| rotations_n20 | `wai.statevector` | all (32) | 590 | 0.0699 (0.0663) | 29 (4) | 107.2 → 107.2 |
|
||
| rotations_n20 | `aer.statevector` | 32 | 591 | 0.195 (0.166) | 102 (83) | 107.2 → 107.1 |
|
||
| rotations_n20 | `qsim.statevector` | 32 | | 0.143 (0.0835) | 199 (188) | 107.1 → 100.2 |
|
||
| rotations_n20 | `quimb.dense` | not set | | 2.84 (2.82) | 236 (158) | 100.2 → 99.3 |
|
||
| rotations_n24 | `wai.statevector` | all (32) | 710 | 0.925 (0.901) | 303 (4) | 99.3 → 102.6 |
|
||
| rotations_n24 | `aer.statevector` | 32 | 711 | 1.58 (1.51) | 342 (83) | 102.6 → 102.4 |
|
||
| rotations_n24 | `qsim.statevector` | 32 | | 0.601 (0.585) | 318 (188) | 102.4 → 100.1 |
|
||
| rotations_n26 | `wai.statevector` | all (32) | 770 | 2.36 (2.3) | 1074 (4) | 100.1 → 98.1 |
|
||
| rotations_n26 | `aer.statevector` | 32 | 771 | 3.89 (3.83) | 1110 (83) | 98.1 → 94.5 |
|
||
| rotations_n26 | `qsim.statevector` | 32 | | 1.99 (1.98) | 702 (188) | 94.5 → 91.2 |
|
||
| grover_n10 | `wai.statevector` | all (32) | 114 | 0.000183 (0.000175) | 4 (4) | 91.2 → 91.2 |
|
||
| grover_n10 | `wai.exact` | 1 (no threads) | 26686 | 0.0264 (0.0264) | 17 (3) | 91.2 → 91.2 |
|
||
| grover_n10 | `wai.exact_whole` | 1 (no threads) | 114 | 0.00015 (0.00015) | 4 (3) | 91.2 → 91.2 |
|
||
| grover_n10 | `aer.statevector` | 32 | 123 | 0.000252 (0.000226) | 84 (83) | 91.2 → 89.9 |
|
||
| grover_n10 | `qsim.statevector` | 32 | | 0.00337 (0.00307) | 189 (188) | 89.9 → 88.5 |
|
||
| grover_n10 | `ddsim.statevector` | not set | | 0.00703 (0.00571) | 87 (86) | 88.5 → 88.5 |
|
||
| grover_n14 | `wai.statevector` | all (32) | 158 | 0.00223 (0.00221) | 4 (4) | 88.5 → 88.5 |
|
||
| grover_n14 | `wai.exact` | 1 (no threads) | 557146 | 9.18 (9.1) | 261 (3) | 88.5 → 73.9 |
|
||
| grover_n14 | `wai.exact_whole` | 1 (no threads) | 158 | 0.00322 (0.0032) | 4 (3) | 73.9 → 73.9 |
|
||
| grover_n14 | `aer.statevector` | 32 | 167 | 0.00316 (0.00313) | 84 (83) | 73.9 → 75.7 |
|
||
| grover_n14 | `qsim.statevector` | 32 | | 0.0138 (0.0123) | 189 (188) | 75.7 → 71.6 |
|
||
| grover_n14 | `ddsim.statevector` | not set | | 0.00643 (0.00622) | 88 (86) | 71.6 → 71.6 |
|
||
| grover_n16 | `wai.statevector` | all (32) | 180 | 0.011 (0.0106) | 7 (4) | 71.6 → 71.6 |
|
||
| grover_n16 | `wai.exact_whole` | 1 (no threads) | 180 | 0.0148 (0.0146) | 6 (3) | 71.6 → 71.6 |
|
||
| grover_n16 | `aer.statevector` | 32 | 189 | 0.0194 (0.016) | 86 (83) | 71.6 → 73.7 |
|
||
| grover_n16 | `qsim.statevector` | 32 | | 0.0151 (0.0134) | 189 (188) | 73.7 → 73.4 |
|
||
| grover_n16 | `ddsim.statevector` | not set | | 0.00702 (0.00667) | 89 (86) | 73.4 → 73.4 |
|
||
| grover_n20 | `wai.statevector` | all (32) | 224 | 0.0301 (0.0286) | 28 (4) | 73.4 → 79.4 |
|
||
| grover_n20 | `wai.exact_whole` | 1 (no threads) | 224 | 0.322 (0.319) | 36 (3) | 79.4 → 79.4 |
|
||
| grover_n20 | `aer.statevector` | 32 | 233 | 0.0588 (0.0546) | 108 (83) | 79.4 → 79.4 |
|
||
| grover_n20 | `qsim.statevector` | 32 | | 0.0254 (0.0247) | 197 (188) | 79.4 → 74.8 |
|
||
| grover_n20 | `ddsim.statevector` | not set | | 0.0159 (0.0157) | 119 (86) | 74.8 → 74.8 |
|
||
| clifford_n1000 | `wai.stabilizer` | 1 (no threads) | 35082 | 0.00106 (0.00103) | 95 (3) | 74.8 → 74.8 |
|
||
| clifford_n1000 | `stim.tableau` | not set | | 0.0017 (0.00163) | 46 (27) | 74.8 → 74.8 |
|
||
| clifford_n1000 | `aer.stabilizer` | 32 | 35083 | 0.00963 (0.00854) | 193 (99) | 74.8 → 69.7 |
|
||
| clifford_n5000 | `wai.stabilizer` | 1 (no threads) | 58265 | 0.0127 (0.0123) | 168 (3) | 77.3 → 77.3 |
|
||
| clifford_n5000 | `stim.tableau` | not set | | 0.0441 (0.0331) | 74 (27) | 77.3 → 77.3 |
|
||
| surface_z_d5_sample | `wai.qec` | 1 (no threads) | | 0.0897 (0.0872) | 18 (3) | 77.3 → 76.9 |
|
||
| surface_z_d5_sample | `stim.tableau` | not set | | 0.224 (0.219) | 123 (38) | 76.9 → 76.9 |
|
||
| surface_z_d5_model | `wai.qec` | 1 (no threads) | | 0.00231 (0.00226) | 6 (3) | 76.9 → 76.9 |
|
||
| surface_z_d5_model | `stim.tableau` | not set | | 0.00279 (0.00269) | 28 (28) | 76.9 → 76.9 |
|
||
| surface_z_d11_sample | `wai.qec` | 1 (no threads) | | 0.997 (0.981) | 163 (3) | 76.9 → 77.1 |
|
||
| surface_z_d11_sample | `stim.tableau` | not set | | 2.18 (2.18) | 938 (38) | 77.1 → 75.9 |
|
||
| surface_z_d11_model | `wai.qec` | 1 (no threads) | | 0.0264 (0.0243) | 33 (3) | 75.9 → 74.7 |
|
||
| surface_z_d11_model | `stim.tableau` | not set | | 0.04 (0.0399) | 47 (28) | 74.7 → 74.7 |
|
||
| qft_n40_amplitudes | `wai.mps` | 1 (no threads) | | 0.0167 (0.0159) | 10 (5) | 74.7 → 74.7 |
|
||
| qft_n40_amplitudes | `aer.mps` | 32 | 861 | 0.00552 (0.00523) | 86 (83) | 74.7 → 74.7 |
|
||
| qft_n40_amplitudes | `quimb.mps` | not set | | 1.93 (1.92) | 167 (160) | 74.7 → 64.9 |
|
||
| qft_n40_amplitudes | `wai.tensor_network` | all (32) | | 0.197 (0.194) | 12 (5) | 65.7 → 65.7 |
|
||
| qft_n40_amplitudes | `quimb.tensor_network` | not set | | 0.934 (0.916) | 180 (167) | 65.7 → 70.7 |
|
||
|
||
### `before-after-macos-arm64.json`
|
||
|
||
Host: Apple M3 Ultra, macOS 27.2, 32 logical CPUs, 256 GiB, arm64. The same harness and circuits, with the engine under test built before and after a gate under many controls stood whole on its state vector, one build straight after the other: each figure is the engine's own call, the median of 5 runs (the minimum in brackets), and ops are the operations it ran.
|
||
|
||
`wai.exact_whole`'s before rows ran a build with no such option, so they are standard gates, as their ops show. The last column is the one-minute load as each build's row began.
|
||
|
||
| case | engine | threads | before: ops | before: seconds, median (min) | after: ops | after: seconds, median (min) | load average, before build → after build |
|
||
|---|---|---|---|---|---|---|---|
|
||
| qft_n20 | `wai.statevector` | all (32) | 230 | 0.0227 (0.0223) | 230 | 0.0326 (0.0307) | 30.9 → 84.8 |
|
||
| qft_n20 | `aer.statevector` | 32 | 231 | 0.0708 (0.0672) | 231 | 0.0841 (0.0824) | 30.9 → 84.9 |
|
||
| qft_n20 | `qsim.statevector` | 32 | | 0.0564 (0.0557) | | 0.0905 (0.0771) | 30.9 → 84.9 |
|
||
| qft_n20 | `ddsim.statevector` | not set | | 0.14 (0.14) | | 0.145 (0.142) | 29.4 → 89.8 |
|
||
| qft_n20 | `wai.exact` | 1 (no threads) | 250 | 0.22 (0.214) | 250 | 0.242 (0.231) | 32.9 → 89.8 |
|
||
| qft_n20 | `quimb.dense` | not set | | 1.41 (1.38) | | 1.6 (1.49) | 32.9 → 89.8 |
|
||
| qft_n24 | `wai.statevector` | all (32) | 324 | 0.474 (0.468) | 324 | 0.585 (0.54) | 32.5 → 87.8 |
|
||
| qft_n24 | `aer.statevector` | 32 | 325 | 0.565 (0.532) | 325 | 1.02 (0.944) | 32.5 → 88.6 |
|
||
| qft_n24 | `qsim.statevector` | 32 | | 0.555 (0.528) | | 0.825 (0.777) | 33.5 → 88.7 |
|
||
| qft_n24 | `ddsim.statevector` | not set | | 2.12 (2.12) | | 2.24 (2.2) | 39.0 → 89.6 |
|
||
| qft_n24 | `wai.exact` | 1 (no threads) | 348 | 5.01 (5) | 348 | 5.76 (5.49) | 38.2 → 87.0 |
|
||
| qft_n26 | `wai.statevector` | all (32) | 377 | 2.1 (2.06) | 377 | 2.66 (2.16) | 42.0 → 91.1 |
|
||
| qft_n26 | `aer.statevector` | 32 | 378 | 1.84 (1.76) | 378 | 2.28 (2.08) | 48.6 → 107.2 |
|
||
| qft_n26 | `qsim.statevector` | 32 | | 2.11 (2.09) | | 2.77 (2.72) | 51.3 → 108.9 |
|
||
| qft_n28 | `wai.statevector` | all (32) | 434 | 9.44 (9.32) | 434 | 10.2 (10.2) | 44.6 → 108.4 |
|
||
| qft_n28 | `aer.statevector` | 32 | 435 | 6.72 (6.58) | 435 | 7.04 (7.02) | 57.7 → 129.7 |
|
||
| qft_n28 | `qsim.statevector` | 32 | | 8.98 (8.9) | | 9.45 (9.41) | 63.9 → 133.5 |
|
||
| rotations_n20 | `wai.statevector` | all (32) | 590 | 0.0619 (0.0609) | 590 | 0.0699 (0.0663) | 55.2 → 107.2 |
|
||
| rotations_n20 | `aer.statevector` | 32 | 591 | 0.13 (0.123) | 591 | 0.195 (0.166) | 55.2 → 107.2 |
|
||
| rotations_n20 | `qsim.statevector` | 32 | | 0.0568 (0.0534) | | 0.143 (0.0835) | 55.2 → 107.1 |
|
||
| rotations_n20 | `quimb.dense` | not set | | 2.61 (2.6) | | 2.84 (2.82) | 53.9 → 100.2 |
|
||
| rotations_n24 | `wai.statevector` | all (32) | 710 | 0.982 (0.909) | 710 | 0.925 (0.901) | 53.7 → 99.3 |
|
||
| rotations_n24 | `aer.statevector` | 32 | 711 | 1.3 (1.17) | 711 | 1.58 (1.51) | 59.2 → 102.6 |
|
||
| rotations_n24 | `qsim.statevector` | 32 | | 0.526 (0.463) | | 0.601 (0.585) | 59.4 → 102.4 |
|
||
| rotations_n26 | `wai.statevector` | all (32) | 770 | 2.32 (2.3) | 770 | 2.36 (2.3) | 53.0 → 100.1 |
|
||
| rotations_n26 | `aer.statevector` | 32 | 771 | 3.92 (3.63) | 771 | 3.89 (3.83) | 55.1 → 98.1 |
|
||
| rotations_n26 | `qsim.statevector` | 32 | | 1.77 (1.66) | | 1.99 (1.98) | 57.8 → 94.5 |
|
||
| grover_n10 | `wai.statevector` | all (32) | 8290 | 0.0156 (0.0152) | 114 | 0.000183 (0.000175) | 49.9 → 91.2 |
|
||
| grover_n10 | `wai.exact` | 1 (no threads) | 26686 | 0.0251 (0.0247) | 26686 | 0.0264 (0.0264) | 49.9 → 91.2 |
|
||
| grover_n10 | `wai.exact_whole` | 1 (no threads) | 26686 | 0.0249 (0.0248) | 114 | 0.00015 (0.00015) | 49.9 → 91.2 |
|
||
| grover_n10 | `aer.statevector` | 32 | 123 | 0.000224 (0.000219) | 123 | 0.000252 (0.000226) | 47.0 → 91.2 |
|
||
| grover_n10 | `qsim.statevector` | 32 | | 0.00315 (0.00293) | | 0.00337 (0.00307) | 47.0 → 89.9 |
|
||
| grover_n10 | `ddsim.statevector` | not set | | 0.0054 (0.00457) | | 0.00703 (0.00571) | 44.2 → 88.5 |
|
||
| grover_n14 | `wai.statevector` | all (32) | 131214 | 3 (2.97) | 158 | 0.00223 (0.00221) | 44.2 → 88.5 |
|
||
| grover_n14 | `wai.exact` | 1 (no threads) | 557146 | 8.48 (8.39) | 557146 | 9.18 (9.1) | 46.0 → 88.5 |
|
||
| grover_n14 | `wai.exact_whole` | 1 (no threads) | 557146 | 8.45 (8.37) | 158 | 0.00322 (0.0032) | 35.3 → 73.9 |
|
||
| grover_n14 | `aer.statevector` | 32 | 167 | 0.00318 (0.00303) | 167 | 0.00316 (0.00313) | 35.0 → 73.9 |
|
||
| grover_n14 | `qsim.statevector` | 32 | | 0.0114 (0.0102) | | 0.0138 (0.0123) | 34.7 → 75.7 |
|
||
| grover_n14 | `ddsim.statevector` | not set | | 0.0059 (0.00558) | | 0.00643 (0.00622) | 34.6 → 71.6 |
|
||
| grover_n16 | `wai.statevector` | all (32) | 524452 | 16.3 (15.5) | 180 | 0.011 (0.0106) | 34.6 → 71.6 |
|
||
| grover_n16 | `wai.exact_whole` | 1 (no threads) | 2490472 | 151 (151) | 180 | 0.0148 (0.0146) | 35.1 → 71.6 |
|
||
| grover_n16 | `aer.statevector` | 32 | 189 | 0.0168 (0.0137) | 189 | 0.0194 (0.016) | 66.7 → 71.6 |
|
||
| grover_n16 | `qsim.statevector` | 32 | | 0.0174 (0.0158) | | 0.0151 (0.0134) | 66.7 → 73.7 |
|
||
| grover_n16 | `ddsim.statevector` | not set | | 0.00663 (0.00625) | | 0.00702 (0.00667) | 70.6 → 73.4 |
|
||
| grover_n20 | `wai.statevector` | all (32) | | not run: line 34: modifiers add at most 16 controls here [Q208] | 224 | 0.0301 (0.0286) | 70.6 → 73.4 |
|
||
| grover_n20 | `wai.exact_whole` | 1 (no threads) | | not run: line 34: modifiers add at most 16 controls here [Q208] | 224 | 0.322 (0.319) | 70.6 → 79.4 |
|
||
| grover_n20 | `aer.statevector` | 32 | 233 | 0.063 (0.0566) | 233 | 0.0588 (0.0546) | 70.6 → 79.4 |
|
||
| grover_n20 | `qsim.statevector` | 32 | | 0.032 (0.0248) | | 0.0254 (0.0247) | 70.6 → 79.4 |
|
||
| grover_n20 | `ddsim.statevector` | not set | | 0.0179 (0.0166) | | 0.0159 (0.0157) | 74.4 → 74.8 |
|
||
| clifford_n1000 | `wai.stabilizer` | 1 (no threads) | 35082 | 0.00102 (0.00101) | 35082 | 0.00106 (0.00103) | 78.1 → 74.8 |
|
||
| clifford_n1000 | `stim.tableau` | not set | | 0.00163 (0.0016) | | 0.0017 (0.00163) | 78.1 → 74.8 |
|
||
| clifford_n1000 | `aer.stabilizer` | 32 | 35083 | 0.0088 (0.00803) | 35083 | 0.00963 (0.00854) | 78.1 → 74.8 |
|
||
| clifford_n5000 | `wai.stabilizer` | 1 (no threads) | 58265 | 0.0124 (0.0112) | 58265 | 0.0127 (0.0123) | 85.1 → 77.3 |
|
||
| clifford_n5000 | `stim.tableau` | not set | | 0.0389 (0.0299) | | 0.0441 (0.0331) | 85.6 → 77.3 |
|
||
| surface_z_d5_sample | `wai.qec` | 1 (no threads) | | 0.0913 (0.0879) | | 0.0897 (0.0872) | 85.6 → 77.3 |
|
||
| surface_z_d5_sample | `stim.tableau` | not set | | 0.228 (0.222) | | 0.224 (0.219) | 85.6 → 76.9 |
|
||
| surface_z_d5_model | `wai.qec` | 1 (no threads) | | 0.00231 (0.00223) | | 0.00231 (0.00226) | 86.8 → 76.9 |
|
||
| surface_z_d5_model | `stim.tableau` | not set | | 0.00329 (0.00271) | | 0.00279 (0.00269) | 86.8 → 76.9 |
|
||
| surface_z_d11_sample | `wai.qec` | 1 (no threads) | | 0.968 (0.962) | | 0.997 (0.981) | 86.8 → 76.9 |
|
||
| surface_z_d11_sample | `stim.tableau` | not set | | 2.21 (2.19) | | 2.18 (2.18) | 88.7 → 77.1 |
|
||
| surface_z_d11_model | `wai.qec` | 1 (no threads) | | 0.0251 (0.0245) | | 0.0264 (0.0243) | 87.2 → 75.9 |
|
||
| surface_z_d11_model | `stim.tableau` | not set | | 0.0443 (0.0405) | | 0.04 (0.0399) | 87.2 → 74.7 |
|
||
| qft_n40_amplitudes | `wai.mps` | 1 (no threads) | | 0.0163 (0.0161) | | 0.0167 (0.0159) | 89.1 → 74.7 |
|
||
| qft_n40_amplitudes | `aer.mps` | 32 | 861 | 0.00552 (0.00538) | 861 | 0.00552 (0.00523) | 89.1 → 74.7 |
|
||
| qft_n40_amplitudes | `quimb.mps` | not set | | 1.96 (1.93) | | 1.93 (1.92) | 89.1 → 74.7 |
|
||
| qft_n40_amplitudes | `wai.tensor_network` | all (32) | | 0.188 (0.187) | | 0.197 (0.194) | 86.7 → 65.7 |
|
||
| qft_n40_amplitudes | `quimb.tensor_network` | not set | | 0.985 (0.972) | | 0.934 (0.916) | 85.4 → 65.7 |
|
||
|
||
<!-- end of results -->
|
||
|
||
## Limits
|
||
|
||
- **The bounds are loose.** They are worst cases, so an error smaller than a bound passes, and
|
||
a double-precision engine usually measures a hundred times or more below its bound. The
|
||
ratios in the tables say how much room each check left. The sharp checks are the exact ones:
|
||
the referee's bit-for-bit rerun, the bit-exact op-log against the circuit, the held-or-dropped
|
||
check of each small-angle gate, stabilizer groups as bytes, outcomes of probability 0, and
|
||
symptom sets.
|
||
- **The integer state reference stops at 22 qubits**, in the full tier, and time stops it, not
|
||
memory. On the build host (one core of an M3 Ultra) one circuit's reference took 34 s and
|
||
0.25 GiB for the QFT at 20 qubits (231 gates), 81 s for 148 dyadic rotations at 20, and 146 s
|
||
and 0.94 GiB for the QFT at 22; each two qubits more take four to five times as long, so 26
|
||
qubits would fit in about 15 GiB and take hours a circuit. Wider circuits are held to closed
|
||
forms (QFT, GHZ), to mirror circuits, and to each other. The referee reruns the bit-exact
|
||
method's op-log where that is at most 2^30 amplitude updates; a longer one is recorded as not
|
||
rerun, with its length.
|
||
- **Sampling is checked by marginals and by L1 distance.** Each outcome's count is held to its
|
||
probability, and the whole distribution to the exact one; the independence of shots is not
|
||
tested. At the family-wise rate of 10^-6 a test fails on a deviation of about six standard
|
||
deviations: on 100,000 shots of a fair outcome, about 1,000 shots, and in L1 distance about
|
||
0.02, or 0.045 over 257 outcomes at 200,000 shots. A smaller fault passes; each check records its
|
||
bound. At 40 qubits a sampler confined to a smaller space inside the right one, with every bit
|
||
still free, is not seen.
|
||
- **Not compared yet:** mitigation by `pea`, `pec` and `cdr` (their values rest on a learned
|
||
noise model or a fitted line: no exact value holds them, beyond the ideal each states); the
|
||
decoders but exact matching and union-find (correlated matching, BP-OSD, the sliding window, the
|
||
code-capacity decoders), and union-find's logical rate beside matching's (recorded, not
|
||
judged); pulses with decay, three levels or couplings (the Rabi formula covers one undamped
|
||
qubit on two levels); the fabric's members other than the GPU ones (the neural, tensor,
|
||
dataflow, FPGA, DSP and vector members), the `statevector` and `pauli` methods placed on an
|
||
accelerator (no host here has a member certified for the dense f64 state), and the CUDA member
|
||
(no nightly host has the device); single-precision GPU state vectors of the other engines.
|
||
- **What the engine under test refuses** is listed in
|
||
[`corpus/expected-refusals.json`](corpus/expected-refusals.json), with the words it must give.
|
||
Its frame simulator refuses a Pauli channel whose exclusive outcomes no independent flips can
|
||
give (`PAULI_CHANNEL_1(0.1, 0.1, 0)`, whose Z would need a rate below zero), with its line: a
|
||
detector error model of independent mechanisms cannot state it either. A general Pauli channel
|
||
it can take (`qec_pauli_channel`) it writes as the independent flips with the channel's law, and
|
||
its model matches the other engine's mechanism by mechanism. A job
|
||
naming method `mps` runs under a meter of the bonds it holds (`mps_qft_n30_bond256`) and stops
|
||
with `[J011]` if those pass one job's work; one naming `auto` keeps to the estimate at the bond
|
||
asked for.
|
||
- **What the adapters do not drive.** The qsim adapter runs no measurement in the middle of a
|
||
circuit, so those entries are `not run` for it; that is this adapter's limit. `aer.mps` is
|
||
not run at 100 qubits: its target holds 63. An engine that has not answered a circuit within
|
||
900 s is stopped, with every process it started, and is recorded as not run for it, or as a
|
||
failure when it is the engine under test.
|
||
- **Platforms.** The pinned wheels exist together for macOS on arm64 and Linux on x86_64 only.
|
||
- **Performance** is one shared host a file, on one day. Other work on the host moves a timing
|
||
by several times; the load average before and after each case is beside it. Timers do not all
|
||
cover the same work: the list above each table says what each covers.
|
||
- **One author** wrote the adapters, the references and the tolerances. A reproduction by
|
||
someone else, and adapters reviewed by each engine's own users, are what this page still needs.
|
||
|
||
## A provider of the open protocol
|
||
|
||
[`provider/seeded_statevector_provider.py`](provider/seeded_statevector_provider.py) wraps a
|
||
third-party state-vector simulator as a `process` provider of `wai.quantum.provider/1`
|
||
([the extension](../extensions/quantum-providers.md)). It is also the template for a device of
|
||
your own: replace the `Device` class's `run` with a call to your device.
|
||
|
||
```sh
|
||
wai-quantum providers add sim --kind process -- python3 -I provider/seeded_statevector_provider.py
|
||
wai-quantum providers test sim # the protocol's conformance vectors
|
||
wai-quantum run bell.qasm --provider sim --shots 1000 --json > job.json
|
||
wai-quantum verify job.json
|
||
```
|
||
|
||
[`provider/test.sh`](provider/test.sh) does exactly that in a directory of its own, as part of
|
||
`reproduce.sh` and of CI: every conformance vector passes, the counts are sealed as `measured` on a
|
||
`simulator`, the receipt verifies, and the same job gives the same counts twice (the device is
|
||
seeded; on the two hosts here it gave the same counts, too).
|
||
|
||
## CI
|
||
|
||
`.github/workflows/wai-quantum-cli.yml` runs the CI tier on Linux (the circuits marked `ci` in the
|
||
manifest: every kind of check but the pairwise comparison of wide circuits), the self-test, the
|
||
provider template, and `tools/report.py --check`, which holds this page's results section to
|
||
`results/`, on every change.
|
||
|
||
`.github/workflows/wai-quantum-cross-simulator.yml` runs the rest every night, with no person:
|
||
the full tier on Linux, each job stopped at 900 s or when its processes hold more than 10 GiB
|
||
(`--memory-gb`), the whole run at 190 minutes (at two jobs the full tier took 66 minutes on the
|
||
build host and 77 on the Linux host of the results above), then the self-test; and the gpu tier on the macOS
|
||
host (WebGPU on Metal, the Metal member, the single-precision methods) and on the Linux host with
|
||
an integrated GPU (WebGPU on each Vulkan adapter, the GPU's and the software driver's). Each host
|
||
declares the members it must have (`QCORPUS_GPU_EXPECT`), and a declared member that ran no check
|
||
fails the run; a member it lacks is recorded as not run, with why; then the tier's fault must be
|
||
caught. The integer reference and the referee run in the harness's own process, outside the
|
||
guard: it held 7.6 GB at its peak on the build host, with the 22-qubit QFT.
|
||
|
||
## Files
|
||
|
||
| path | what |
|
||
|---|---|
|
||
| `reproduce.sh` | the one command |
|
||
| `env/requirements.in`, `env/requirements.lock` | the pinned engines, and every wheel's hash for macOS and Linux |
|
||
| `corpus/` | the manifest, the committed programs and error-correction circuits, the hand-written ones, the refusals the engine under test may give, and the known disagreements with their reproducers |
|
||
| `tools/corpus.py` | the circuits |
|
||
| `tools/exact.py` | the references: the integer state vector and stabilizer tableau, the integer density matrix, Pauli expectation values, the Rabi formula |
|
||
| `tools/decoding.py` | the decoders' reference: the least-weight correction of a syndrome, by exhaustion |
|
||
| `tools/tolerance.py` | every tolerance and where it comes from |
|
||
| `tools/engines.py` | one adapter per engine and method |
|
||
| `tools/compare.py` | the run: references, tolerances, injected faults, the results file |
|
||
| `tools/perf.py` | run time and peak memory |
|
||
| `tools/report.py` | this page's results section |
|
||
| `tools/before_after.py` | one host's timings of two builds side by side, from `tools/perf.py` run on each |
|
||
| `provider/` | the provider template and its test |
|
||
| [`../wai-quantum/examples/fabric_state.rs`](../wai-quantum/examples/fabric_state.rs) | the gpu tier's driver: a program's bit-exact state on the CPU and on every GPU member a build finds |
|
||
| `results/` | the committed runs |
|