Skip to main content

wai_quantum/
quantum.rs

1//! Deterministic quantum-circuit **simulation** as transportable, receiptable
2//! content — `wai.quantum.circuit2` and the frozen `wai.quantum.circuit`
3//! (extensions/quantum-sim).
4//!
5//! The framing first: WAI's core property is *determinism* — byte-identical
6//! reconstruction on every machine, "conformance is a hash". Real quantum
7//! HARDWARE is the natural enemy of that (NISQ noise + stochastic measurement are
8//! not reproducible across devices). So quantum does NOT enter WAI as a hardware
9//! dependency and gives NO quantum speedup here. It enters exactly as worlds,
10//! films and scores do (lever 3, *instructions-at-the-sink*): the wire carries a
11//! compact **circuit** (a gate op-log), the sink CLASSICALLY simulates it, and the
12//! reconstructed statevector hashes identically everywhere.
13//!
14//! The reconstruction runs in a fixed-point complex floor (`wai.det.amp64`, the
15//! arithmetic a circuit/1 contract calls `wai.det.fixed64`): every amplitude is
16//! an [`Amp`] — real and imaginary parts as `i64` at scale `2^FRAC` — and every
17//! gate is an integer fixed-point matrix–vector update with a pinned rounding
18//! rule and a *stated error bound* versus the ideal unitary (the same contract
19//! as the WAI integer transform floor). No float anywhere on the decode, so:
20//!
21//! - **statevector-equivalence** — the whole amplitude vector is byte-identical on
22//!   every machine (a portable statevector hash), and
23//! - **shot-histogram-equivalence** — measurement is sampled by the pinned
24//!   `splitmix64` PRNG (the same fixed-point sampler the WAI deterministic generator uses), so
25//!   a shot histogram at a pinned `(seed, shots)` is byte-identical too.
26//!
27//! The transportable artifact is the *circuit* (kilobytes, linear in gate count);
28//! the reconstruction is the *statevector* (`2^n` amplitudes — exponential). That
29//! gap is the point: a tiny circuit reconstructs to a gigabyte statevector, and
30//! because the reconstruction cost is exponential the joules-accounted receipt
31//! (§ extension) is a genuinely novel artifact — an energy-metered, byte-exact,
32//! signable record of a quantum computation.
33//!
34//! Gate set: a *controlled-1-qubit-gate* IR over Clifford+T + dyadic phase
35//! (`I,X,Y,Z,H,S,S†,T,T†,P(k)` with any number of controls). Clifford+T is dense
36//! in `SU(2^n)`, so this is universal. The dyadic phase `P(k) = e^{2πi/2^k}` is
37//! read from the circuit's [`Gateset`] table:
38//!
39//! - [`Gateset::V2`] (`wai.quantum.circuit2`, magic `WQC2`) holds the integers
40//!   nearest to each phase, so its controlled-phase ladder gives the **QFT**
41//!   ("quantum FFT"), transported as a circuit and reconstructed byte-exact.
42//!   Circuits built in code are V2 unless built otherwise.
43//! - [`Gateset::V1`] (`wai.quantum.circuit`, magic `WQC1`) is frozen so that
44//!   every circuit/1 file, hash and receipt reproduces. Its `P(k)` deviates from
45//!   the ideal phase for `k ≥ 8` and applies none for `k ≥ 19`.
46//!
47//! A circuit decoded from a container takes the container's gateset, and its
48//! [`circuit_hash`] names the capability. Pure i64, no float, no `ort`;
49//! compiles to wasm32.
50//!
51//! Out of scope (and honestly so): variational-quantum-circuit / "quantum AI"
52//! priors whose measurement is stochastic — those are at best a float/behavioral
53//! capability that can never back `intent=replicate`, so they do not belong in
54//! this exact-reconstruction extension. [`StateVector::fidelity_fx`] is provided as the
55//! quantum-information-theoretic conformance metric such a future path would use.
56
57use crate::ijson::{self, Json, RANGE_LIMIT};
58
59/// Fractional bits of the fixed-point amplitude floor. Amplitudes live in
60/// `[-1, 1]`, so `2^FRAC` (≈ `1.07e9` at 30) is the unit and the i128 products in
61/// [`Amp::mul`] stay far inside range.
62pub const FRAC: u32 = 30;
63/// The fixed-point unit `1.0`.
64pub const ONE: i64 = 1 << FRAC;
65const ROUND: i128 = 1 << (FRAC - 1);
66/// Largest `k` for which `P(k) = e^{2πi/2^k}` is tabulated: [`PHASE_V1`] and
67/// [`PHASE_V2`] each hold `P(1..=DYADIC_MAX)`.
68pub const DYADIC_MAX: usize = 32;
69
70/// Domain separators for the conformance hashes (the WAI discipline).
71const DOMAIN_STATEVECTOR: &[u8] = b"wai:quantum-statevector\x01";
72const DOMAIN_CIRCUIT: &[u8] = b"wai:quantum-circuit\x01";
73const DOMAIN_HISTOGRAM: &[u8] = b"wai:quantum-histogram\x01";
74
75// ---------------------------------------------------------------------------
76// Fixed-point complex amplitude
77// ---------------------------------------------------------------------------
78
79/// A complex amplitude in the fixed-point floor: `re, im` are `i64` at scale
80/// `2^FRAC`. Byte-exact by construction — `Eq` is total (no float), so two
81/// statevectors compare and hash identically iff every amplitude matches.
82#[derive(Clone, Copy, Debug, PartialEq, Eq)]
83pub struct Amp {
84    pub re: i64,
85    pub im: i64,
86}
87
88/// Fixed-point multiply with a pinned round-half-up rule. `i128` intermediate so
89/// the `i64·i64` product never overflows; the `+ROUND` then arithmetic shift is
90/// identical on every machine (the determinism the whole floor rests on).
91#[inline]
92pub fn fxmul(a: i64, b: i64) -> i64 {
93    ((a as i128 * b as i128 + ROUND) >> FRAC) as i64
94}
95
96/// Fixed-point square root: `v` is at `2^FRAC`, result at `2^FRAC`
97/// (`sqrt(v/ONE)·ONE = isqrt(v·ONE)`). Integer `isqrt`, no float; negatives
98/// (never produced by the half-angle recurrence) clamp to 0.
99#[inline]
100pub fn sqrt_fx(v: i64) -> i64 {
101    if v <= 0 {
102        return 0;
103    }
104    (((v as u128) << FRAC).isqrt()) as i64
105}
106
107impl Amp {
108    /// `0 + 0i`.
109    pub const ZERO: Amp = Amp { re: 0, im: 0 };
110    /// `1 + 0i` (the fixed-point unit).
111    pub const ONE: Amp = Amp { re: ONE, im: 0 };
112
113    #[inline]
114    pub fn add(self, o: Amp) -> Amp {
115        Amp { re: self.re + o.re, im: self.im + o.im }
116    }
117
118    /// Complex fixed-point multiply: `(a+bi)(c+di) = (ac−bd) + (ad+bc)i`.
119    #[inline]
120    pub fn mul(self, o: Amp) -> Amp {
121        Amp {
122            re: fxmul(self.re, o.re) - fxmul(self.im, o.im),
123            im: fxmul(self.re, o.im) + fxmul(self.im, o.re),
124        }
125    }
126
127    /// Complex conjugate.
128    #[inline]
129    pub fn conj(self) -> Amp {
130        Amp { re: self.re, im: -self.im }
131    }
132
133    /// `|amp|^2` at scale `2^(2·FRAC)`, in `i128` (the un-shifted probability
134    /// weight — summed and sampled without a divide).
135    #[inline]
136    pub fn norm2(self) -> i128 {
137        self.re as i128 * self.re as i128 + self.im as i128 * self.im as i128
138    }
139}
140
141// ---------------------------------------------------------------------------
142// Dyadic phase tables — P(k) = e^{2πi / 2^k} at scale 2^FRAC, one per gateset.
143// Literal constants: no float and no recurrence runs on the decode path.
144// ---------------------------------------------------------------------------
145
146/// The `wai.quantum.circuit` phase table, frozen bit for bit.
147///
148/// Index `k` holds `P(k) = e^{2πi/2^k}` as `(re, im)` at scale `2^FRAC`, for
149/// `1 ≤ k ≤ DYADIC_MAX`; index 0 is unused and holds [`Amp::ZERO`].
150///
151/// These are the values of the integer half-angle recurrence every circuit/1
152/// artefact was made with: `P(1) = (−2^30, 0)`, `P(2) = (0, 2^30)`, and for
153/// `k ≥ 3`, with `c = P(k−1).re`,
154/// `re = isqrt(⌊(2^30 + c)/2⌋·2^30)` and `im = isqrt(⌊(2^30 − c)/2⌋·2^30)`,
155/// where `isqrt` is the floor square root. The floors compound: from `P(8)` on
156/// the imaginary part is too large, by up to 7032 units at `P(18)`, and
157/// `P(19..=32)` apply no phase at all. The table is kept exactly as it is so that
158/// every circuit/1 file, hash and receipt reproduces. [`PHASE_V2`] is the
159/// correctly rounded table. The extension states this table in its §3.1 and
160/// Appendix B.1, rendered from this constant.
161pub const PHASE_V1: [Amp; 33] = [
162    Amp::ZERO,
163    Amp { re: -1073741824, im: 0 },         // k = 1
164    Amp { re: 0, im: 1073741824 },          // k = 2
165    Amp { re: 759250124, im: 759250124 },   // k = 3
166    Amp { re: 992008094, im: 410903207 },   // k = 4
167    Amp { re: 1053110175, im: 209476638 },  // k = 5
168    Amp { re: 1068571463, im: 105245102 },  // k = 6
169    Amp { re: 1072448454, im: 52686012 },   // k = 7
170    Amp { re: 1073418432, im: 26350953 },   // k = 8
171    Amp { re: 1073660972, im: 13176485 },   // k = 9
172    Amp { re: 1073721610, im: 6588405 },    // k = 10
173    Amp { re: 1073736770, im: 3294284 },    // k = 11
174    Amp { re: 1073740560, im: 1647223 },    // k = 12
175    Amp { re: 1073741507, im: 823774 },     // k = 13
176    Amp { re: 1073741744, im: 411887 },     // k = 14
177    Amp { re: 1073741803, im: 207243 },     // k = 15
178    Amp { re: 1073741818, im: 103621 },     // k = 16
179    Amp { re: 1073741822, im: 56755 },      // k = 17
180    Amp { re: 1073741823, im: 32768 },      // k = 18
181    Amp { re: 1073741823, im: 0 },          // k = 19
182    Amp { re: 1073741823, im: 0 },          // k = 20
183    Amp { re: 1073741823, im: 0 },          // k = 21
184    Amp { re: 1073741823, im: 0 },          // k = 22
185    Amp { re: 1073741823, im: 0 },          // k = 23
186    Amp { re: 1073741823, im: 0 },          // k = 24
187    Amp { re: 1073741823, im: 0 },          // k = 25
188    Amp { re: 1073741823, im: 0 },          // k = 26
189    Amp { re: 1073741823, im: 0 },          // k = 27
190    Amp { re: 1073741823, im: 0 },          // k = 28
191    Amp { re: 1073741823, im: 0 },          // k = 29
192    Amp { re: 1073741823, im: 0 },          // k = 30
193    Amp { re: 1073741823, im: 0 },          // k = 31
194    Amp { re: 1073741823, im: 0 },          // k = 32
195];
196
197/// The `wai.quantum.circuit2` phase table: each entry is the integer nearest to
198/// `2^30·cos(2π/2^k)` and to `2^30·sin(2π/2^k)`.
199///
200/// Index `k` holds `P(k)` as `(re, im)` at scale `2^FRAC`, for
201/// `1 ≤ k ≤ DYADIC_MAX`; index 0 is unused and holds [`Amp::ZERO`]. `P(1)` and
202/// `P(2)` are exact. For `k ≥ 3` every true value is irrational, so none is a
203/// half-integer and the nearest integer is unique; the closest any comes to a
204/// tie is 0.00456 unit, at the imaginary part of `P(22)`. Every component is
205/// within ½ unit of the ideal, which the crate's tests prove with integer
206/// interval arithmetic. The literal values are normative: the extension
207/// states them in its §3.2 and Appendix B.2, rendered from this constant.
208///
209/// `re P(3) == im P(3)`, so `T` keeps `re == im`. The resolution of `2^-30` is a
210/// floor no rounding removes: `P(26..=32)` carry imaginary parts of 101 down to
211/// 2, so the smallest angles are correct to the nearest unit and no further.
212pub const PHASE_V2: [Amp; 33] = [
213    Amp::ZERO,
214    Amp { re: -1073741824, im: 0 },         // k = 1
215    Amp { re: 0, im: 1073741824 },          // k = 2
216    Amp { re: 759250125, im: 759250125 },   // k = 3
217    Amp { re: 992008094, im: 410903207 },   // k = 4
218    Amp { re: 1053110176, im: 209476638 },  // k = 5
219    Amp { re: 1068571464, im: 105245103 },  // k = 6
220    Amp { re: 1072448455, im: 52686014 },   // k = 7
221    Amp { re: 1073418433, im: 26350943 },   // k = 8
222    Amp { re: 1073660973, im: 13176464 },   // k = 9
223    Amp { re: 1073721611, im: 6588356 },    // k = 10
224    Amp { re: 1073736771, im: 3294193 },    // k = 11
225    Amp { re: 1073740561, im: 1647099 },    // k = 12
226    Amp { re: 1073741508, im: 823550 },     // k = 13
227    Amp { re: 1073741745, im: 411775 },     // k = 14
228    Amp { re: 1073741804, im: 205887 },     // k = 15
229    Amp { re: 1073741819, im: 102944 },     // k = 16
230    Amp { re: 1073741823, im: 51472 },      // k = 17
231    Amp { re: 1073741824, im: 25736 },      // k = 18
232    Amp { re: 1073741824, im: 12868 },      // k = 19
233    Amp { re: 1073741824, im: 6434 },       // k = 20
234    Amp { re: 1073741824, im: 3217 },       // k = 21
235    Amp { re: 1073741824, im: 1608 },       // k = 22
236    Amp { re: 1073741824, im: 804 },        // k = 23
237    Amp { re: 1073741824, im: 402 },        // k = 24
238    Amp { re: 1073741824, im: 201 },        // k = 25
239    Amp { re: 1073741824, im: 101 },        // k = 26
240    Amp { re: 1073741824, im: 50 },         // k = 27
241    Amp { re: 1073741824, im: 25 },         // k = 28
242    Amp { re: 1073741824, im: 13 },         // k = 29
243    Amp { re: 1073741824, im: 6 },          // k = 30
244    Amp { re: 1073741824, im: 3 },          // k = 31
245    Amp { re: 1073741824, im: 2 },          // k = 32
246];
247
248/// Which phase table a circuit is reconstructed with, and so which capability
249/// carries it.
250///
251/// Both gatesets share the arithmetic, the gate matrices and the container
252/// layout. They differ only in the phase table, which `H`, `T`, `T†` and `P(k)`
253/// read (`H` uses `re P(3)` as `1/√2`).
254///
255/// - [`Gateset::V1`] is `wai.quantum.circuit` (magic `WQC1`), frozen so that
256///   existing content reproduces bit for bit.
257/// - [`Gateset::V2`] is `wai.quantum.circuit2` (magic `WQC2`), with the correctly
258///   rounded table. It is the default.
259#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
260#[non_exhaustive]
261pub enum Gateset {
262    /// `wai.quantum.circuit`, with the frozen [`PHASE_V1`] table.
263    V1,
264    /// `wai.quantum.circuit2`, with the correctly rounded [`PHASE_V2`] table.
265    #[default]
266    V2,
267}
268
269impl Gateset {
270    /// Every gateset, oldest first.
271    pub const ALL: [Gateset; 2] = [Gateset::V1, Gateset::V2];
272
273    /// The capability string: `wai.quantum.circuit` or `wai.quantum.circuit2`.
274    pub const fn capability(self) -> &'static str {
275        match self {
276            Gateset::V1 => "wai.quantum.circuit",
277            Gateset::V2 => "wai.quantum.circuit2",
278        }
279    }
280
281    /// The container magic: `WQC1` or `WQC2`.
282    pub const fn magic(self) -> [u8; 4] {
283        match self {
284            Gateset::V1 => *b"WQC1",
285            Gateset::V2 => *b"WQC2",
286        }
287    }
288
289    /// The contract's `ext`: `<capability>/<contract revision>`, so
290    /// `wai.quantum.circuit2/1` is revision 1 of the circuit2 capability.
291    pub const fn ext(self) -> &'static str {
292        match self {
293            Gateset::V1 => "wai.quantum.circuit/1",
294            Gateset::V2 => "wai.quantum.circuit2/1",
295        }
296    }
297
298    /// The contract's `numeric` identifier.
299    pub const fn numeric(self) -> &'static str {
300        match self {
301            Gateset::V1 => "wai.det.fixed64",
302            Gateset::V2 => "wai.det.amp64",
303        }
304    }
305
306    /// The contract's `gateset` string, which names the reconstruction's gate
307    /// algebra and so differs wherever its constants differ.
308    pub const fn name(self) -> &'static str {
309        match self {
310            Gateset::V1 => "cliffordT+dyadicP",
311            Gateset::V2 => "cliffordT+dyadicP.rn",
312        }
313    }
314
315    /// The phase table: [`PHASE_V1`] or [`PHASE_V2`].
316    pub const fn table(self) -> &'static [Amp; 33] {
317        match self {
318            Gateset::V1 => &PHASE_V1,
319            Gateset::V2 => &PHASE_V2,
320        }
321    }
322
323    /// `P(k) = e^{2πi/2^k}` from this gateset's table. `validate` guarantees
324    /// `1 ≤ k ≤ DYADIC_MAX` for every `P` in a circuit.
325    #[inline]
326    pub fn phase(self, k: usize) -> Amp {
327        self.table()[k]
328    }
329
330    /// `1/√2` in this gateset: `re P(3)`, the single source of the one irrational
331    /// the Clifford+T set needs. 759250124 in V1, 759250125 in V2.
332    #[inline]
333    pub fn inv_sqrt2(self) -> i64 {
334        self.table()[3].re
335    }
336
337    /// The canonical contract bytes for an `n_qubits` circuit: no whitespace,
338    /// members in a fixed order, rendered directly rather than through a JSON
339    /// serializer so that no serializer setting can change them.
340    pub fn contract_bytes(self, n_qubits: u8) -> Vec<u8> {
341        format!(
342            "{{\"ext\":\"{}\",\"n_qubits\":{},\"numeric\":\"{}\",\"frac\":{},\"gateset\":\"{}\"}}",
343            self.ext(),
344            n_qubits,
345            self.numeric(),
346            FRAC,
347            self.name(),
348        )
349        .into_bytes()
350    }
351
352    /// BLAKE3 of the table: `i64le(re) ‖ i64le(im)` for `k = 1..=DYADIC_MAX`,
353    /// 512 bytes, with no domain prefix.
354    pub fn table_digest(self) -> [u8; 32] {
355        let mut h = blake3::Hasher::new();
356        for a in &self.table()[1..] {
357            h.update(&a.re.to_le_bytes());
358            h.update(&a.im.to_le_bytes());
359        }
360        *h.finalize().as_bytes()
361    }
362
363    /// The gateset a container magic names, or `None` for any other bytes.
364    pub fn from_magic(m: &[u8]) -> Option<Gateset> {
365        Gateset::ALL.into_iter().find(|g| m == g.magic().as_slice())
366    }
367
368    /// The gateset a capability string names, or `None` for any other string.
369    pub fn from_capability(s: &str) -> Option<Gateset> {
370        Gateset::ALL.into_iter().find(|g| s == g.capability())
371    }
372}
373
374// ---------------------------------------------------------------------------
375// Gates — a controlled-1-qubit-gate IR
376// ---------------------------------------------------------------------------
377
378/// The 1-qubit base gates. `P` carries a dyadic index in [`Gate::param`].
379#[derive(Clone, Copy, Debug, PartialEq, Eq)]
380pub enum BaseGate {
381    I,
382    X,
383    Y,
384    Z,
385    H,
386    S,
387    Sdg,
388    T,
389    Tdg,
390    /// `P(k) = diag(1, e^{2πi/2^k})`.
391    P,
392}
393
394impl BaseGate {
395    pub(crate) fn opcode(self) -> u8 {
396        match self {
397            BaseGate::I => 0,
398            BaseGate::X => 1,
399            BaseGate::Y => 2,
400            BaseGate::Z => 3,
401            BaseGate::H => 4,
402            BaseGate::S => 5,
403            BaseGate::Sdg => 6,
404            BaseGate::T => 7,
405            BaseGate::Tdg => 8,
406            BaseGate::P => 9,
407        }
408    }
409    fn from_opcode(b: u8) -> Option<BaseGate> {
410        Some(match b {
411            0 => BaseGate::I,
412            1 => BaseGate::X,
413            2 => BaseGate::Y,
414            3 => BaseGate::Z,
415            4 => BaseGate::H,
416            5 => BaseGate::S,
417            6 => BaseGate::Sdg,
418            7 => BaseGate::T,
419            8 => BaseGate::Tdg,
420            9 => BaseGate::P,
421            _ => return None,
422        })
423    }
424
425    /// The 2×2 fixed-point matrix `[[m00,m01],[m10,m11]]` for this gate in the
426    /// gateset `gs`, whose table `H` (`re P(3)` as `1/√2`), `T`, `T†` and `P`
427    /// read. `param` must be in `1..=DYADIC_MAX` for `P`, as `validate` ensures.
428    pub(crate) fn matrix(self, param: u16, gs: Gateset) -> [[Amp; 2]; 2] {
429        let z = Amp::ZERO;
430        let one = Amp::ONE;
431        let i = Amp { re: 0, im: ONE };
432        let neg_i = Amp { re: 0, im: -ONE };
433        let s = Amp { re: gs.inv_sqrt2(), im: 0 };
434        let neg_s = Amp { re: -gs.inv_sqrt2(), im: 0 };
435        let neg_one = Amp { re: -ONE, im: 0 };
436        match self {
437            BaseGate::I => [[one, z], [z, one]],
438            BaseGate::X => [[z, one], [one, z]],
439            BaseGate::Y => [[z, neg_i], [i, z]],
440            BaseGate::Z => [[one, z], [z, neg_one]],
441            BaseGate::H => [[s, s], [s, neg_s]],
442            BaseGate::S => [[one, z], [z, i]],
443            BaseGate::Sdg => [[one, z], [z, neg_i]],
444            BaseGate::T => [[one, z], [z, gs.phase(3)]],
445            BaseGate::Tdg => [[one, z], [z, gs.phase(3).conj()]],
446            BaseGate::P => [[one, z], [z, gs.phase(param as usize)]],
447        }
448    }
449}
450
451/// One instruction: a base gate on `target`, applied only when every qubit in
452/// `controls` is set. `controls = []` is a plain 1-qubit gate; one control gives
453/// CX/CZ/CP; two gives Toffoli-class; etc.
454#[derive(Clone, Debug, PartialEq, Eq)]
455pub struct Gate {
456    pub base: BaseGate,
457    pub controls: Vec<u8>,
458    pub target: u8,
459    pub param: u16,
460}
461
462// ---------------------------------------------------------------------------
463// Circuit
464// ---------------------------------------------------------------------------
465
466/// A quantum circuit: `n_qubits`, an ordered op-log, and the [`Gateset`] it is
467/// reconstructed with. This is the transportable object — compact, linear in
468/// gate count.
469///
470/// The gateset is part of the circuit: two circuits with the same ops and
471/// different gatesets are different circuits, and compare unequal.
472/// [`Circuit::new`] gives [`Gateset::V2`]; a circuit decoded from a container
473/// takes the container's; a circuit derived from another keeps the other's
474/// ([`Circuit::empty_like`]). The fields stay public, so a circuit/1 build is
475/// `let mut c = Circuit::qft(n); c.gateset = Gateset::V1;`.
476#[derive(Clone, Debug, PartialEq, Eq)]
477#[non_exhaustive]
478pub struct Circuit {
479    pub n_qubits: u8,
480    pub ops: Vec<Gate>,
481    pub gateset: Gateset,
482}
483
484/// Errors from parsing a `WQC` container or building an out-of-range circuit.
485#[derive(Debug, PartialEq, Eq)]
486#[non_exhaustive]
487pub enum QuantumError {
488    /// A container whose structure is broken: a bad magic, a section out of
489    /// bounds, repeated or missing, an `n_qubits` that is not an integer in
490    /// `0..=255`, a malformed op-log, or a measurement that is not I-JSON. In
491    /// `WQC2`, also bytes after the last op or a measurement that is not the
492    /// canonical bytes.
493    Malformed(String),
494    /// A circuit its gateset does not allow: a qubit index ≥ `n_qubits`, a
495    /// control equal to the target, more than 255 controls, more than
496    /// `u32::MAX` ops, a `P(k)` with `k` outside `1..=DYADIC_MAX`, or, in
497    /// [`Gateset::V2`], a repeated control or a parameter on a gate other than
498    /// `P`. Also a circuit too large for a container's `u32` section sizes.
499    Invalid(String),
500    /// A container's contract section does not declare the capability its
501    /// magic names: it is not a JSON object carrying that capability's values,
502    /// or, in `WQC2`, it is not the canonical bytes.
503    Contract(String),
504    /// `n_qubits` exceeds what this build will materialize (`2^n` amplitudes).
505    TooManyQubits(u8),
506}
507
508impl QuantumError {
509    /// The error's class, as the conformance corpus names it: `"malformed"`,
510    /// `"invalid"`, `"contract"` or `"too-many-qubits"`.
511    pub fn kind(&self) -> &'static str {
512        match self {
513            QuantumError::Malformed(_) => "malformed",
514            QuantumError::Invalid(_) => "invalid",
515            QuantumError::Contract(_) => "contract",
516            QuantumError::TooManyQubits(_) => "too-many-qubits",
517        }
518    }
519}
520
521impl std::fmt::Display for QuantumError {
522    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
523        match self {
524            QuantumError::Malformed(e) => write!(f, "malformed WQC: {e}"),
525            QuantumError::Invalid(e) => write!(f, "invalid circuit: {e}"),
526            QuantumError::Contract(e) => write!(f, "contract mismatch: {e}"),
527            QuantumError::TooManyQubits(n) => write!(f, "too many qubits: {n}"),
528        }
529    }
530}
531impl std::error::Error for QuantumError {}
532
533/// The largest circuit this build will simulate (a state vector is `2^n`
534/// amplitudes × 16 bytes; 26 qubits ≈ 1 GiB). The *format* supports more — this
535/// is a materialization guard, not a spec limit.
536pub const MAX_QUBITS: u8 = 26;
537
538impl Circuit {
539    /// An empty circuit on `n_qubits` in [`Gateset::V2`], `wai.quantum.circuit2`.
540    pub fn new(n_qubits: u8) -> Self {
541        Circuit::with_gateset(n_qubits, Gateset::V2)
542    }
543
544    /// An empty circuit on `n_qubits` in the gateset `gateset`.
545    pub fn with_gateset(n_qubits: u8, gateset: Gateset) -> Self {
546        Circuit { n_qubits, ops: Vec::new(), gateset }
547    }
548
549    /// An empty circuit with this one's qubit count and gateset, for building a
550    /// circuit derived from it without resetting its gateset.
551    pub fn empty_like(&self) -> Self {
552        Circuit::with_gateset(self.n_qubits, self.gateset)
553    }
554
555    fn push(&mut self, base: BaseGate, controls: Vec<u8>, target: u8, param: u16) -> &mut Self {
556        self.ops.push(Gate { base, controls, target, param });
557        self
558    }
559
560    // Ergonomic builders (used by the QFT constructor and the tests/vectors).
561    pub fn x(&mut self, q: u8) -> &mut Self { self.push(BaseGate::X, vec![], q, 0) }
562    pub fn y(&mut self, q: u8) -> &mut Self { self.push(BaseGate::Y, vec![], q, 0) }
563    pub fn z(&mut self, q: u8) -> &mut Self { self.push(BaseGate::Z, vec![], q, 0) }
564    pub fn h(&mut self, q: u8) -> &mut Self { self.push(BaseGate::H, vec![], q, 0) }
565    pub fn s(&mut self, q: u8) -> &mut Self { self.push(BaseGate::S, vec![], q, 0) }
566    pub fn t(&mut self, q: u8) -> &mut Self { self.push(BaseGate::T, vec![], q, 0) }
567    /// `P(k) = diag(1, e^{2πi/2^k})` on qubit `q`.
568    pub fn p(&mut self, k: u16, q: u8) -> &mut Self { self.push(BaseGate::P, vec![], q, k) }
569    pub fn cx(&mut self, c: u8, t: u8) -> &mut Self { self.push(BaseGate::X, vec![c], t, 0) }
570    pub fn cz(&mut self, c: u8, t: u8) -> &mut Self { self.push(BaseGate::Z, vec![c], t, 0) }
571    /// Controlled `P(k)` — the QFT's rotation gate.
572    pub fn cp(&mut self, k: u16, c: u8, t: u8) -> &mut Self { self.push(BaseGate::P, vec![c], t, k) }
573    /// Toffoli (`CCX`).
574    pub fn ccx(&mut self, c0: u8, c1: u8, t: u8) -> &mut Self {
575        self.push(BaseGate::X, vec![c0, c1], t, 0)
576    }
577    /// `SWAP(a,b)` as three CX (kept in the op-log as gates, not a new opcode).
578    pub fn swap(&mut self, a: u8, b: u8) -> &mut Self {
579        self.cx(a, b).cx(b, a).cx(a, b)
580    }
581
582    /// The **Quantum Fourier Transform** over all `n` qubits — the "quantum FFT",
583    /// transported as a circuit (Hadamard + controlled-phase ladder + bit-reversal
584    /// swaps) and reconstructed byte-exact. Built with [`Circuit::new`], so in
585    /// [`Gateset::V2`], whose table gives every phase the ladder needs.
586    pub fn qft(n: u8) -> Circuit {
587        let mut c = Circuit::new(n);
588        for j in 0..n {
589            c.h(j);
590            for l in (j + 1)..n {
591                // controlled R_m between control l and target j, m = l−j+1
592                let m = (l - j + 1) as u16;
593                c.cp(m, l, j);
594            }
595        }
596        for j in 0..(n / 2) {
597            c.swap(j, n - 1 - j);
598        }
599        c
600    }
601
602    /// Check the circuit against its gateset's rules.
603    ///
604    /// In both gatesets every target and control is a qubit of the circuit, no
605    /// control equals its target, a gate has at most 255 controls (the op-log
606    /// counts them in a `u8`), and `P(k)` has `1 ≤ k ≤ DYADIC_MAX`. The circuit
607    /// has at most `u32::MAX` ops, since the op-log counts them in a `u32`.
608    /// [`Gateset::V2`] also requires a gate's controls to be pairwise distinct,
609    /// so at most 254, and the parameter of every gate other than `P` to be 0.
610    pub fn validate(&self) -> Result<(), QuantumError> {
611        let n = self.n_qubits;
612        let strict = match self.gateset {
613            Gateset::V1 => false,
614            Gateset::V2 => true,
615        };
616        if u32::try_from(self.ops.len()).is_err() {
617            return Err(QuantumError::Invalid(format!("{} ops, more than u32::MAX", self.ops.len())));
618        }
619        for g in &self.ops {
620            if g.target >= n {
621                return Err(QuantumError::Invalid(format!("target {} ≥ n_qubits {}", g.target, n)));
622            }
623            if g.controls.len() > usize::from(u8::MAX) {
624                return Err(QuantumError::Invalid(format!("{} controls, more than 255", g.controls.len())));
625            }
626            // One bit per qubit index, for the distinct-controls rule.
627            let mut seen = [0u64; 4];
628            for &c in &g.controls {
629                if c >= n {
630                    return Err(QuantumError::Invalid(format!("control {c} ≥ n_qubits {n}")));
631                }
632                if c == g.target {
633                    return Err(QuantumError::Invalid(format!("control {c} equals target")));
634                }
635                if strict {
636                    let (word, bit) = (usize::from(c >> 6), 1u64 << (c & 63));
637                    if seen[word] & bit != 0 {
638                        return Err(QuantumError::Invalid(format!("control {c} repeated")));
639                    }
640                    seen[word] |= bit;
641                }
642            }
643            if g.base == BaseGate::P {
644                let k = g.param as usize;
645                if k < 1 || k > DYADIC_MAX {
646                    return Err(QuantumError::Invalid(format!("P(k) with k={k} out of 1..={DYADIC_MAX}")));
647                }
648            } else if strict && g.param != 0 {
649                return Err(QuantumError::Invalid(format!("{:?} with param {}; only P takes one", g.base, g.param)));
650            }
651        }
652        Ok(())
653    }
654
655    /// Classically simulate the circuit from `|0…0⟩` with its gateset's table,
656    /// returning the fixed-point state vector. Pure i64: byte-identical on every
657    /// machine.
658    pub fn simulate(&self) -> Result<StateVector, QuantumError> {
659        self.simulate_from(0)
660    }
661
662    /// Simulate starting from computational basis state `|start⟩`.
663    pub fn simulate_from(&self, start: usize) -> Result<StateVector, QuantumError> {
664        self.validate()?;
665        if self.n_qubits > MAX_QUBITS {
666            return Err(QuantumError::TooManyQubits(self.n_qubits));
667        }
668        let dim = 1usize << self.n_qubits;
669        let mut amps = vec![Amp::ZERO; dim];
670        amps[start % dim] = Amp::ONE;
671        for g in &self.ops {
672            apply(&mut amps, self.n_qubits, g, self.gateset);
673        }
674        Ok(StateVector { n_qubits: self.n_qubits, amps })
675    }
676}
677
678/// Apply one controlled-1-qubit gate in place. Iterates the amplitude pairs that
679/// differ only in the target bit, updating those whose control bits are all set.
680/// Apply one gate in place.
681///
682/// The obvious implementation walks every index and multiplies a 2x2 matrix into
683/// each pair. Most gates do not need that. `fxmul(ONE, x) == x` and
684/// `fxmul(0, x) == 0` hold exactly in this fixed point — `ROUND` is `1 << (FRAC-1)`,
685/// so the rounded product of an integer with one is that integer — which makes the
686/// shortcuts below **bit-identical to the general path by construction**, not merely
687/// close. Byte-exactness is the contract here; a faster simulator that changed a
688/// single amplitude would be a broken one.
689///
690/// - identity does nothing at all;
691/// - a **diagonal** gate (`Z S S† T T† P`, and their controlled forms) only phases
692///   the `|1⟩` half, so it touches half the amplitudes with one multiply instead of
693///   four plus two adds — and a phase of exactly `-1` is a negation, with none;
694/// - an **antidiagonal** gate is two multiplies, and `X` (hence `CX`, the most
695///   common two-qubit gate there is) is a pure swap with no arithmetic whatsoever;
696/// - an all-**real** matrix (`H`, and any real rotation) halves the multiplies,
697///   since the imaginary cross terms are multiplications by zero.
698///
699/// Measured at 20 qubits against the previous implementation, interleaved in one
700/// process: `Z` 8.9x, `X` 7.1x, `CZ` 4.6x, `CX` 4.3x, `T` 3.4x, `S` 3.1x, `Y` 1.9x,
701/// `H` 1.8x.
702///
703/// The loop shape is deliberately left alone. Blocking it, and indexing the pairs
704/// by bit-insertion, were both tried and both came out slower than the plain scan:
705/// the arithmetic is what costs here, not the iteration.
706///
707/// The shortcuts read only the matrix, so they hold for either gateset's table:
708/// circuit2's `P(k ≥ 18)` has `re == ONE` and `im ≠ 0`, which is the diagonal
709/// path, and only an exact `(−ONE, 0)` takes the negation.
710fn apply(amps: &mut [Amp], n: u8, g: &Gate, gs: Gateset) {
711    if matches!(g.base, BaseGate::I) {
712        return;
713    }
714    let m = g.base.matrix(g.param, gs);
715    let tbit = 1usize << g.target;
716    let ctrl_mask: usize = g.controls.iter().fold(0usize, |acc, &c| acc | (1usize << c));
717    let dim = 1usize << n;
718
719    let is_zero = |a: Amp| a.re == 0 && a.im == 0;
720    let is_one = |a: Amp| a.re == ONE && a.im == 0;
721
722    // diag(1, phase): the |0> half is untouched, so walk only the |1> half and do
723    // one multiply instead of four and two adds. A phase of exactly -1 negates.
724    if is_one(m[0][0]) && is_zero(m[0][1]) && is_zero(m[1][0]) {
725        let ph = m[1][1];
726        let negate = ph.re == -ONE && ph.im == 0;
727        let mut i = 0usize;
728        while i < dim {
729            if i & tbit != 0 && (i & ctrl_mask) == ctrl_mask {
730                amps[i] = if negate {
731                    Amp { re: -amps[i].re, im: -amps[i].im }
732                } else {
733                    ph.mul(amps[i])
734                };
735            }
736            i += 1;
737        }
738        return;
739    }
740
741    // antidiagonal: the halves exchange. X (so CX) is an exact swap, no arithmetic.
742    if is_zero(m[0][0]) && is_zero(m[1][1]) {
743        let (a01, a10) = (m[0][1], m[1][0]);
744        let plain_swap = is_one(a01) && is_one(a10);
745        let mut i = 0usize;
746        while i < dim {
747            if i & tbit == 0 && (i & ctrl_mask) == ctrl_mask {
748                let j = i | tbit;
749                if plain_swap {
750                    amps.swap(i, j);
751                } else {
752                    let (a0, a1) = (amps[i], amps[j]);
753                    amps[i] = a01.mul(a1);
754                    amps[j] = a10.mul(a0);
755                }
756            }
757            i += 1;
758        }
759        return;
760    }
761
762    // All four entries real — H, and any real rotation. A complex multiply by a
763    // real scalar is two fxmuls rather than four plus a subtract, because the
764    // imaginary cross terms are `fxmul(0, x)`, which is exactly zero. Same
765    // products, same order, half the multiplies.
766    if m[0][0].im == 0 && m[0][1].im == 0 && m[1][0].im == 0 && m[1][1].im == 0 {
767        let (p00, p01) = (m[0][0].re, m[0][1].re);
768        let (p10, p11) = (m[1][0].re, m[1][1].re);
769        let mut i = 0usize;
770        while i < dim {
771            if i & tbit == 0 && (i & ctrl_mask) == ctrl_mask {
772                let j = i | tbit;
773                let a0 = amps[i];
774                let a1 = amps[j];
775                amps[i] = Amp {
776                    re: fxmul(p00, a0.re) + fxmul(p01, a1.re),
777                    im: fxmul(p00, a0.im) + fxmul(p01, a1.im),
778                };
779                amps[j] = Amp {
780                    re: fxmul(p10, a0.re) + fxmul(p11, a1.re),
781                    im: fxmul(p10, a0.im) + fxmul(p11, a1.im),
782                };
783            }
784            i += 1;
785        }
786        return;
787    }
788
789    let mut i = 0usize;
790    while i < dim {
791        if i & tbit == 0 && (i & ctrl_mask) == ctrl_mask {
792            let j = i | tbit;
793            let a0 = amps[i];
794            let a1 = amps[j];
795            amps[i] = m[0][0].mul(a0).add(m[0][1].mul(a1));
796            amps[j] = m[1][0].mul(a0).add(m[1][1].mul(a1));
797        }
798        i += 1;
799    }
800}
801
802// ---------------------------------------------------------------------------
803// State vector + conformance
804// ---------------------------------------------------------------------------
805
806/// A reconstructed fixed-point state vector — the hashed quantity.
807#[derive(Clone, Debug, PartialEq, Eq)]
808pub struct StateVector {
809    pub n_qubits: u8,
810    pub amps: Vec<Amp>,
811}
812
813/// `splitmix64` — the pinned integer PRNG shared with the WAI deterministic generator; the
814/// fixed-point sampler the shot-histogram determinism requires.
815fn splitmix64(s: &mut u64) -> u64 {
816    *s = s.wrapping_add(0x9E37_79B9_7F4A_7C15);
817    let mut z = *s;
818    z = (z ^ (z >> 30)).wrapping_mul(0xBF58_476D_1CE4_E5B9);
819    z = (z ^ (z >> 27)).wrapping_mul(0x94D0_49BB_1331_11EB);
820    z ^ (z >> 31)
821}
822
823impl StateVector {
824    /// The `|k⟩` computational basis state on `n` qubits.
825    pub fn basis(n: u8, k: usize) -> StateVector {
826        let dim = 1usize << n;
827        let mut amps = vec![Amp::ZERO; dim];
828        amps[k % dim] = Amp::ONE;
829        StateVector { n_qubits: n, amps }
830    }
831
832    /// Canonical serialization of the amplitudes: `re_le(i64) ‖ im_le(i64)` per
833    /// amplitude, in index order — the bytes the statevector hash covers.
834    pub fn canonical_bytes(&self) -> Vec<u8> {
835        let mut out = Vec::with_capacity(self.amps.len() * 16);
836        for a in &self.amps {
837            out.extend_from_slice(&a.re.to_le_bytes());
838            out.extend_from_slice(&a.im.to_le_bytes());
839        }
840        out
841    }
842
843    /// **statevector-equivalence** — the portable BLAKE3 identity of the whole
844    /// reconstructed vector. Two conforming sinks agree on this iff every amplitude
845    /// is byte-identical, on every machine, with no tolerance parameter.
846    pub fn statevector_hash(&self) -> [u8; 32] {
847        let mut h = blake3::Hasher::new();
848        h.update(DOMAIN_STATEVECTOR);
849        h.update(&[self.n_qubits]);
850        h.update(&FRAC.to_le_bytes());
851        h.update(&self.canonical_bytes());
852        *h.finalize().as_bytes()
853    }
854
855    /// Per-basis-state probability weights `|amp|^2` at scale `2^(2·FRAC)`, `i128`
856    /// (un-normalized; summing gives ≈ `2^(2·FRAC)`). No divide — the sampler walks
857    /// these directly.
858    pub fn prob_weights(&self) -> Vec<i128> {
859        self.amps.iter().map(|a| a.norm2()).collect()
860    }
861
862    /// Sample `shots` computational-basis measurements with the pinned
863    /// `splitmix64` seeded by `seed`; returns a per-basis-state count vector.
864    /// Deterministic on every machine.
865    pub fn sample_shots(&self, seed: u64, shots: u64) -> Vec<u64> {
866        let weights = self.prob_weights();
867        // prefix sums in i128; total ≈ 2^(2·FRAC)
868        let mut cum = Vec::with_capacity(weights.len());
869        let mut total: i128 = 0;
870        for w in &weights {
871            total += *w;
872            cum.push(total);
873        }
874        let mut counts = vec![0u64; self.amps.len()];
875        if total <= 0 {
876            return counts;
877        }
878        let mut state = seed;
879        for _ in 0..shots {
880            let r = (splitmix64(&mut state) as u128 % total as u128) as i128;
881            // first index whose prefix sum strictly exceeds r
882            let idx = match cum.binary_search_by(|c| {
883                if *c <= r { std::cmp::Ordering::Less } else { std::cmp::Ordering::Greater }
884            }) {
885                Ok(i) | Err(i) => i,
886            };
887            let slot = idx.min(counts.len() - 1);
888            counts[slot] += 1;
889        }
890        counts
891    }
892
893    /// **shot-histogram-equivalence** — the portable BLAKE3 identity of a shot
894    /// histogram at a pinned `(seed, shots)`.
895    pub fn histogram_hash(&self, seed: u64, shots: u64) -> [u8; 32] {
896        let counts = self.sample_shots(seed, shots);
897        let mut h = blake3::Hasher::new();
898        h.update(DOMAIN_HISTOGRAM);
899        h.update(&[self.n_qubits]);
900        h.update(&seed.to_le_bytes());
901        h.update(&shots.to_le_bytes());
902        for c in &counts {
903            h.update(&c.to_le_bytes());
904        }
905        *h.finalize().as_bytes()
906    }
907
908    /// State **fidelity** `|⟨self|other⟩|^2` in the fixed-point floor (result at
909    /// `2^FRAC`) — the quantum-information-theoretic similarity metric. For two
910    /// exactly-reconstructed vectors it is a *diagnostic* (identical states give
911    /// ≈ `ONE`); it is the metric a future float/behavioral quantum prior — which
912    /// cannot back `intent=replicate` — would conform against. `i128` accumulation
913    /// so the overlap sum never overflows.
914    pub fn fidelity_fx(&self, other: &StateVector) -> i64 {
915        assert_eq!(self.amps.len(), other.amps.len(), "fidelity needs equal dimension");
916        let mut re: i128 = 0;
917        let mut im: i128 = 0;
918        for (a, b) in self.amps.iter().zip(&other.amps) {
919            // ⟨a|b⟩ = Σ conj(a)·b
920            let p = a.conj().mul(*b);
921            re += p.re as i128;
922            im += p.im as i128;
923        }
924        // |overlap|^2 at 2^FRAC: (re^2 + im^2) >> FRAC, re/im already at 2^FRAC
925        ((re * re + im * im) >> FRAC) as i64
926    }
927}
928
929// ---------------------------------------------------------------------------
930// WQC container (magic "WQC1" or "WQC2"): the on-wire circuit object
931// ---------------------------------------------------------------------------
932
933/// A pinned measurement request carried in a `WQC` (section `0x03`), so a file can
934/// declare "conform on the shot histogram at this `(seed, shots)`".
935#[derive(Clone, Copy, Debug, PartialEq, Eq)]
936pub struct Measure {
937    pub seed: u64,
938    pub shots: u64,
939}
940
941const SECT_CONTRACT: u8 = 0x01;
942const SECT_OPLOG: u8 = 0x02;
943const SECT_MEASURE: u8 = 0x03;
944
945/// The canonical measurement bytes, `{"seed":S,"shots":N,"basis":"computational"}`,
946/// rendered directly, as the contract is.
947fn measure_bytes(m: Measure) -> Vec<u8> {
948    format!("{{\"seed\":{},\"shots\":{},\"basis\":\"computational\"}}", m.seed, m.shots).into_bytes()
949}
950
951/// The op-log of a circuit that passed `validate`: `u32le n_ops`, then per op
952/// `u8 opcode | u8 n_ctrl | u8 target | u16le param | n_ctrl × u8`. `validate`
953/// bounds both counts, so neither conversion can fail.
954fn oplog_bytes(c: &Circuit) -> Vec<u8> {
955    let n_ops = u32::try_from(c.ops.len()).expect("validate bounds the op count by u32::MAX");
956    let mut out = Vec::new();
957    out.extend_from_slice(&n_ops.to_le_bytes());
958    for g in &c.ops {
959        out.push(g.base.opcode());
960        out.push(u8::try_from(g.controls.len()).expect("validate bounds a gate's controls by 255"));
961        out.push(g.target);
962        out.extend_from_slice(&g.param.to_le_bytes());
963        out.extend_from_slice(&g.controls);
964    }
965    out
966}
967
968/// How many ops to reserve for an op-log of `len` bytes that claims `n_ops`.
969/// The count is the file's claim, so it never sizes an allocation alone: every
970/// op takes at least 5 bytes, so the section holds at most `(len − 4) / 5`.
971fn oplog_capacity(n_ops: u32, len: usize) -> usize {
972    usize::try_from(n_ops).unwrap_or(usize::MAX).min(len.saturating_sub(4) / 5)
973}
974
975/// Read an op-log: the ops, and how many bytes they took. Every op is
976/// bounds-checked, and an opcode above 9 is malformed. Bytes after the last op
977/// are the caller's to judge.
978fn parse_oplog(b: &[u8]) -> Result<(Vec<Gate>, usize), QuantumError> {
979    if b.len() < 4 {
980        return Err(QuantumError::Malformed("oplog header".into()));
981    }
982    let n_ops = u32::from_le_bytes([b[0], b[1], b[2], b[3]]);
983    let mut ops = Vec::with_capacity(oplog_capacity(n_ops, b.len()));
984    let mut pos = 4;
985    for _ in 0..n_ops {
986        if b.len() - pos < 5 {
987            return Err(QuantumError::Malformed("op header".into()));
988        }
989        let base = BaseGate::from_opcode(b[pos])
990            .ok_or_else(|| QuantumError::Malformed(format!("opcode {}", b[pos])))?;
991        let n_ctrl = usize::from(b[pos + 1]);
992        let target = b[pos + 2];
993        let param = u16::from_le_bytes([b[pos + 3], b[pos + 4]]);
994        pos += 5;
995        if b.len() - pos < n_ctrl {
996            return Err(QuantumError::Malformed("op controls".into()));
997        }
998        let controls = b[pos..pos + n_ctrl].to_vec();
999        pos += n_ctrl;
1000        ops.push(Gate { base, controls, target, param });
1001    }
1002    Ok((ops, pos))
1003}
1004
1005/// The byte range of a section, `blob_start + off` for `len` bytes, or `None`
1006/// if it runs past `total` or its arithmetic overflows. Checked, so that it
1007/// cannot wrap where `usize` is 32 bits.
1008fn section_range(blob_start: usize, off: u32, len: u32, total: usize) -> Option<std::ops::Range<usize>> {
1009    let start = blob_start.checked_add(usize::try_from(off).ok()?)?;
1010    let end = start.checked_add(usize::try_from(len).ok()?)?;
1011    (end <= total).then_some(start..end)
1012}
1013
1014/// How a member of a contract or measurement object reads in an error: its
1015/// JSON, cut at 64 characters, since it comes from an untrusted file.
1016fn shown(v: Option<&Json>) -> String {
1017    let Some(v) = v else {
1018        return "missing".to_string();
1019    };
1020    let s = v.to_string();
1021    match s.char_indices().nth(64) {
1022        Some((cut, _)) => format!("{}…", &s[..cut]),
1023        None => s,
1024    }
1025}
1026
1027/// Read a contract section under the gateset its container's magic names, and
1028/// return its `n_qubits`.
1029///
1030/// The section must be an I-JSON object (extensions/quantum-sim §2, read by
1031/// [`ijson::parse`]), or it is a contract mismatch, and `n_qubits` must be an
1032/// unsigned JSON integer of at most 255, or the container is malformed. circuit/1 requires `ext`, `numeric`, `frac` (the integer 30)
1033/// and `gateset` to carry its values, and leaves member order, whitespace and
1034/// other members free. circuit2 requires the canonical bytes exactly.
1035fn read_contract(gateset: Gateset, raw: &[u8]) -> Result<u8, QuantumError> {
1036    let obj = ijson::parse(raw).map_err(|e| QuantumError::Contract(format!("the contract is not I-JSON: {e}")))?;
1037    if !matches!(obj, Json::Object(_)) {
1038        return Err(QuantumError::Contract(format!("the contract is not a JSON object: {}", shown(Some(&obj)))));
1039    }
1040    let n_qubits = || {
1041        obj.get("n_qubits")
1042            .and_then(Json::as_u64)
1043            .and_then(|n| u8::try_from(n).ok())
1044            .ok_or_else(|| {
1045                QuantumError::Malformed(format!("n_qubits {} is not an integer in 0..=255", shown(obj.get("n_qubits"))))
1046            })
1047    };
1048    match gateset {
1049        Gateset::V1 => {
1050            let text = |key: &str, value: &str| {
1051                if obj.get(key).and_then(Json::as_str) == Some(value) {
1052                    Ok(())
1053                } else {
1054                    Err(QuantumError::Contract(format!("{key} is {}, not {value:?}", shown(obj.get(key)))))
1055                }
1056            };
1057            text("ext", gateset.ext())?;
1058            text("numeric", gateset.numeric())?;
1059            if obj.get("frac").and_then(Json::as_u64) != Some(u64::from(FRAC)) {
1060                return Err(QuantumError::Contract(format!("frac is {}, not {FRAC}", shown(obj.get("frac")))));
1061            }
1062            text("gateset", gateset.name())?;
1063            n_qubits()
1064        }
1065        Gateset::V2 => {
1066            let n = n_qubits()?;
1067            if raw != gateset.contract_bytes(n).as_slice() {
1068                return Err(QuantumError::Contract(format!(
1069                    "not the canonical {} contract for {n} qubits",
1070                    gateset.capability()
1071                )));
1072            }
1073            Ok(n)
1074        }
1075    }
1076}
1077
1078/// Read a measurement section. It must be I-JSON ([`ijson::parse`]). circuit/1 then
1079/// reads it as it always has: a missing or non-integer `seed` or `shots` reads
1080/// as 0.
1081/// circuit2 requires a `u64` `seed` and `shots` and the canonical bytes for
1082/// them, which fixes the basis as `computational`.
1083fn read_measure(gateset: Gateset, raw: &[u8]) -> Result<Measure, QuantumError> {
1084    let mv = ijson::parse(raw).map_err(|e| QuantumError::Malformed(format!("the measurement is not I-JSON: {e}")))?;
1085    let field = |key: &str| mv.get(key).and_then(Json::as_u64);
1086    match gateset {
1087        Gateset::V1 => Ok(Measure { seed: field("seed").unwrap_or(0), shots: field("shots").unwrap_or(0) }),
1088        Gateset::V2 => {
1089            let u64_field = |key: &str| {
1090                field(key).ok_or_else(|| QuantumError::Malformed(format!("measure {key} is {}, not a u64", shown(mv.get(key)))))
1091            };
1092            let m = Measure { seed: u64_field("seed")?, shots: u64_field("shots")? };
1093            if raw != measure_bytes(m).as_slice() {
1094                return Err(QuantumError::Malformed("not the canonical measure bytes".into()));
1095            }
1096            Ok(m)
1097        }
1098    }
1099}
1100
1101/// Serialize a circuit, and optionally a measurement, to the container its
1102/// gateset names: `WQC1` for [`Gateset::V1`], `WQC2` for [`Gateset::V2`].
1103///
1104/// The layout is the same for both: the magic, `u16le` section count, a table
1105/// of `(u8 kind, u32le offset, u32le len)` with offsets relative to the end of
1106/// the table, then the contract (`0x01`), the op-log (`0x02`) and the
1107/// measurement (`0x03`). A circuit/1 circuit is written byte for byte as every
1108/// earlier release wrote it.
1109///
1110/// Fails, with the error `validate` gives, on a circuit its gateset does not
1111/// allow. A circuit that has simulated cannot fail here, unless its op-log runs
1112/// past what a `u32` section length can address.
1113pub fn to_wqc(c: &Circuit, measure: Option<Measure>) -> Result<Vec<u8>, QuantumError> {
1114    c.validate()?;
1115    let mut sections = vec![(SECT_CONTRACT, c.gateset.contract_bytes(c.n_qubits)), (SECT_OPLOG, oplog_bytes(c))];
1116    if let Some(m) = measure {
1117        sections.push((SECT_MEASURE, measure_bytes(m)));
1118    }
1119
1120    let mut out = Vec::new();
1121    out.extend_from_slice(&c.gateset.magic());
1122    // At most three sections.
1123    out.extend_from_slice(&(sections.len() as u16).to_le_bytes());
1124    let mut off: u64 = 0;
1125    for (kind, data) in &sections {
1126        let (Ok(off32), Ok(len32)) = (u32::try_from(off), u32::try_from(data.len())) else {
1127            return Err(QuantumError::Invalid(format!(
1128                "section {kind:#04x}, {} bytes at offset {off}, does not fit the container's u32 offsets",
1129                data.len()
1130            )));
1131        };
1132        out.push(*kind);
1133        out.extend_from_slice(&off32.to_le_bytes());
1134        out.extend_from_slice(&len32.to_le_bytes());
1135        off += u64::from(len32);
1136    }
1137    for (_, data) in &sections {
1138        out.extend_from_slice(data);
1139    }
1140    Ok(out)
1141}
1142
1143/// Parse a `WQC1` or `WQC2` container into a circuit, in the gateset its magic
1144/// names, and its optional measurement.
1145///
1146/// The checks run in this order, and the first to fail is the error:
1147///
1148/// 1. The magic is `WQC1` or `WQC2`, else malformed.
1149/// 2. Every section lies inside the file, with arithmetic that cannot wrap; no
1150///    known section (`0x01`, `0x02`, `0x03`) appears twice; the contract and
1151///    op-log are present. Unknown sections are ignored. Else malformed.
1152/// 3. The contract declares the capability the magic names. In `WQC1` it must
1153///    be an I-JSON object carrying circuit/1's `ext`, `numeric`, `frac` and
1154///    `gateset`, in any formatting; in `WQC2` it must be the canonical bytes.
1155///    Else a contract mismatch, except that an `n_qubits` that is not an
1156///    unsigned JSON integer in `0..=255` is malformed.
1157/// 4. The op-log parses within its section: every op lies inside it and has
1158///    an opcode of at most 9. In `WQC2` it must end exactly after its last op;
1159///    in `WQC1` any bytes after it are ignored. Else malformed.
1160/// 5. The circuit passes `validate` under its gateset, else invalid.
1161/// 6. The measurement, if present, is I-JSON, and in `WQC2` it is the
1162///    canonical bytes. Else malformed.
1163///
1164/// I-JSON is extensions/quantum-sim §2's reading of a section: UTF-8, no
1165/// member name twice in one object, no surrogate or noncharacter, no number of
1166/// magnitude 2^1024 − 2^970 or more, and at most 127 nested arrays and
1167/// objects, each decided from the section's text. [`reject_corpus`] holds a
1168/// payload for each refusal, and [`accept_corpus`] payloads at the edges of
1169/// the rules that must be read.
1170pub fn from_wqc(bytes: &[u8]) -> Result<(Circuit, Option<Measure>), QuantumError> {
1171    if bytes.len() < 6 {
1172        return Err(QuantumError::Malformed("magic".into()));
1173    }
1174    let gateset = Gateset::from_magic(&bytes[0..4]).ok_or_else(|| QuantumError::Malformed("magic".into()))?;
1175    let strict = match gateset {
1176        Gateset::V1 => false,
1177        Gateset::V2 => true,
1178    };
1179
1180    let n_sections = usize::from(u16::from_le_bytes([bytes[4], bytes[5]]));
1181    let table_start = 6;
1182    let blob_start = n_sections
1183        .checked_mul(9)
1184        .and_then(|len| len.checked_add(table_start))
1185        .filter(|&end| end <= bytes.len())
1186        .ok_or_else(|| QuantumError::Malformed("section table".into()))?;
1187    let u32_at = |p: usize| u32::from_le_bytes([bytes[p], bytes[p + 1], bytes[p + 2], bytes[p + 3]]);
1188    let mut contract: Option<&[u8]> = None;
1189    let mut oplog: Option<&[u8]> = None;
1190    let mut measure_raw: Option<&[u8]> = None;
1191    for s in 0..n_sections {
1192        // Inside the table, which ends at blob_start ≤ bytes.len().
1193        let p = table_start + s * 9;
1194        let kind = bytes[p];
1195        let range = section_range(blob_start, u32_at(p + 1), u32_at(p + 5), bytes.len())
1196            .ok_or_else(|| QuantumError::Malformed(format!("section {kind:#04x} bounds")))?;
1197        let slot = match kind {
1198            SECT_CONTRACT => &mut contract,
1199            SECT_OPLOG => &mut oplog,
1200            SECT_MEASURE => &mut measure_raw,
1201            _ => continue, // unknown section: ignore (forward-compatible)
1202        };
1203        if slot.replace(&bytes[range]).is_some() {
1204            return Err(QuantumError::Malformed(format!("duplicate section {kind:#04x}")));
1205        }
1206    }
1207    let contract = contract.ok_or_else(|| QuantumError::Malformed("missing contract".into()))?;
1208    let oplog = oplog.ok_or_else(|| QuantumError::Malformed("missing oplog".into()))?;
1209
1210    let n_qubits = read_contract(gateset, contract)?;
1211
1212    let (ops, used) = parse_oplog(oplog)?;
1213    if strict && used != oplog.len() {
1214        return Err(QuantumError::Malformed(format!("{} bytes after the last op", oplog.len() - used)));
1215    }
1216
1217    let circuit = Circuit { n_qubits, ops, gateset };
1218    circuit.validate()?;
1219
1220    let measure = measure_raw.map(|raw| read_measure(gateset, raw)).transpose()?;
1221    Ok((circuit, measure))
1222}
1223
1224/// **circuit-equivalence** — the portable BLAKE3 identity of a circuit:
1225/// `BLAKE3("wai:quantum-circuit\x01" ‖ contract ‖ op-log)`, over the canonical
1226/// contract bytes of its gateset and its op-log. The contract names the
1227/// capability, so the hash binds the gateset and its table: the same ops in
1228/// circuit/1 and circuit2 are different circuits. The receipt binds this
1229/// alongside the statevector hash.
1230///
1231/// Fails, as [`to_wqc`] does, on a circuit its gateset does not allow; a
1232/// circuit that has simulated cannot fail.
1233pub fn circuit_hash(c: &Circuit) -> Result<[u8; 32], QuantumError> {
1234    c.validate()?;
1235    let mut h = blake3::Hasher::new();
1236    h.update(DOMAIN_CIRCUIT);
1237    h.update(&c.gateset.contract_bytes(c.n_qubits));
1238    h.update(&oplog_bytes(c));
1239    Ok(*h.finalize().as_bytes())
1240}
1241
1242// ---- The reject corpus ---------------------------------------------------------
1243
1244/// A container from raw section-table entries `(kind, offset, len)` and a blob.
1245fn wqc_table(magic: &[u8; 4], table: &[(u8, u32, u32)], blob: &[u8]) -> Vec<u8> {
1246    let mut out = magic.to_vec();
1247    out.extend_from_slice(&u16::try_from(table.len()).expect("a short table").to_le_bytes());
1248    for &(kind, off, len) in table {
1249        out.push(kind);
1250        out.extend_from_slice(&off.to_le_bytes());
1251        out.extend_from_slice(&len.to_le_bytes());
1252    }
1253    out.extend_from_slice(blob);
1254    out
1255}
1256
1257/// A container holding `sections` in order, each table entry pointing at its
1258/// own bytes.
1259fn wqc_raw(magic: &[u8; 4], sections: &[(u8, &[u8])]) -> Vec<u8> {
1260    let (mut table, mut blob) = (Vec::new(), Vec::new());
1261    for &(kind, data) in sections {
1262        let at = |n: usize| u32::try_from(n).expect("a small section");
1263        table.push((kind, at(blob.len()), at(data.len())));
1264        blob.extend_from_slice(data);
1265    }
1266    wqc_table(magic, &table, &blob)
1267}
1268
1269/// One op-log entry, as the wire has it.
1270fn op(opcode: u8, controls: &[u8], target: u8, param: u16) -> Vec<u8> {
1271    let mut out = vec![opcode, u8::try_from(controls.len()).expect("a few controls"), target];
1272    out.extend_from_slice(&param.to_le_bytes());
1273    out.extend_from_slice(controls);
1274    out
1275}
1276
1277/// An op-log holding `ops`.
1278fn oplog_of(ops: &[Vec<u8>]) -> Vec<u8> {
1279    let mut out = u32::try_from(ops.len()).expect("a few ops").to_le_bytes().to_vec();
1280    for o in ops {
1281        out.extend_from_slice(o);
1282    }
1283    out
1284}
1285
1286
1287/// `contract`, an object, with `members` added at its end.
1288fn with_members(contract: &[u8], members: &[u8]) -> Vec<u8> {
1289    let (body, close) = contract.split_at(contract.len() - 1);
1290    assert_eq!(close, b"}", "a contract is an object");
1291    [body, b",", members, b"}"].concat()
1292}
1293
1294/// `bytes` with the first `from` replaced by `to`; `from` must be there.
1295fn swap(bytes: &[u8], from: &str, to: &str) -> Vec<u8> {
1296    let s = std::str::from_utf8(bytes).expect("a contract is text");
1297    assert!(s.contains(from), "{from:?} is not in {s}");
1298    s.replacen(from, to, 1).into_bytes()
1299}
1300
1301/// The reject corpus of extensions/quantum-sim §2, as `(name, payload, class)`:
1302/// payloads a reader must refuse, each with the class [`QuantumError::kind`]
1303/// gives it. Each breaks one rule and keeps every rule checked before it, so
1304/// the check order of [`from_wqc`] decides the class; most are a two-qubit Bell
1305/// container with that one thing broken. The conformance corpus's `reject/`
1306/// tree is written from this list.
1307pub fn reject_corpus() -> Vec<(&'static str, Vec<u8>, &'static str)> {
1308    let bell = oplog_of(&[op(4, &[], 0, 0), op(1, &[0], 1, 0)]);
1309    let canon1 = Gateset::V1.contract_bytes(2);
1310    let canon2 = Gateset::V2.contract_bytes(2);
1311    let v1 = |contract: &[u8]| wqc_raw(b"WQC1", &[(SECT_CONTRACT, contract), (SECT_OPLOG, &bell)]);
1312    let v1_oplog = |oplog: &[u8]| wqc_raw(b"WQC1", &[(SECT_CONTRACT, &canon1), (SECT_OPLOG, oplog)]);
1313    let v2 = |contract: &[u8], oplog: &[u8], measure: Option<&[u8]>| {
1314        let mut sections = vec![(SECT_CONTRACT, contract), (SECT_OPLOG, oplog)];
1315        sections.extend(measure.map(|m| (SECT_MEASURE, m)));
1316        wqc_raw(b"WQC2", &sections)
1317    };
1318    let v2_contract = |contract: &[u8]| v2(contract, &bell, None);
1319    let v2_oplog = |oplog: &[u8]| v2(&canon2, oplog, None);
1320    let v2_measure = |measure: &[u8]| v2(&canon2, &bell, Some(measure));
1321    let mut magic_wqc3 = v2_contract(&canon2);
1322    magic_wqc3[0..4].copy_from_slice(b"WQC3");
1323    // An op-log of 9 bytes that claims u32::MAX ops.
1324    let n_ops_u32max = [u32::MAX.to_le_bytes().as_slice(), &op(4, &[], 0, 0)].concat();
1325    // An op-log section whose offset plus length wraps a u32.
1326    let wrap = wqc_table(
1327        b"WQC1",
1328        &[(SECT_CONTRACT, 0, u32::try_from(canon1.len()).expect("a short contract")), (SECT_OPLOG, 0xFFFF_FFF0, 0x20)],
1329        &[canon1.as_slice(), &bell].concat(),
1330    );
1331    // The Bell container cut off inside its section table: two entries claimed, one present.
1332    let mut table_past_end = v1(&canon1);
1333    table_past_end.truncate(6 + 9);
1334    let at = |n: usize| u32::try_from(n).expect("a short section");
1335    let (c1, b1) = (at(canon1.len()), at(bell.len()));
1336    let both = [canon1.as_slice(), &bell].concat();
1337    // A contract whose last member's string holds the byte 0xFF.
1338    let not_utf8 = [&canon1[..canon1.len() - 1], b",\"note\":\"\xff\"}"].concat();
1339    // An op that names two controls where the section holds one.
1340    let truncated_controls = [1u32.to_le_bytes().as_slice(), &[1, 2, 1, 0, 0, 0]].concat();
1341    let measure = b"{\"seed\":1,\"shots\":10,\"basis\":\"computational\"}";
1342    // A circuit/1 contract nesting 127 arrays inside its object: 128 levels,
1343    // one past what §2 allows.
1344    let deep = [&canon1[..canon1.len() - 1], b",\"x\":", &b"[".repeat(127), &b"]".repeat(127), b"}"].concat();
1345    let reordered2 = format!(
1346        r#"{{"n_qubits":2,"ext":"{}","numeric":"{}","frac":30,"gateset":"{}"}}"#,
1347        Gateset::V2.ext(),
1348        Gateset::V2.numeric(),
1349        Gateset::V2.name()
1350    );
1351    vec![
1352        ("magic_wqc3", magic_wqc3, "malformed"),
1353        ("v1_ext_other", v1(&swap(&canon1, "circuit/1", "circuit/2")), "contract"),
1354        ("v1_numeric_other", v1(&swap(&canon1, "wai.det.fixed64", "wai.det.amp64")), "contract"),
1355        ("v1_frac_31", v1(&swap(&canon1, "\"frac\":30", "\"frac\":31")), "contract"),
1356        ("v1_frac_float", v1(&swap(&canon1, "\"frac\":30", "\"frac\":30.0")), "contract"),
1357        ("v1_gateset_rn", v1(&swap(&canon1, "dyadicP\"", "dyadicP.rn\"")), "contract"),
1358        ("v1_contract2_in_wqc1", v1(&canon2), "contract"),
1359        ("v1_fields_missing", v1(br#"{"n_qubits":3}"#), "contract"),
1360        ("v1_contract_not_object", v1(&[b"[".as_slice(), &canon1, b"]"].concat()), "contract"),
1361        ("v1_n_qubits_256", v1(&swap(&canon1, "\"n_qubits\":2", "\"n_qubits\":256")), "malformed"),
1362        ("v1_n_qubits_258", v1(&swap(&canon1, "\"n_qubits\":2", "\"n_qubits\":258")), "malformed"),
1363        (
1364            "v1_contract_twice",
1365            wqc_raw(b"WQC1", &[(SECT_CONTRACT, &canon1), (SECT_OPLOG, &bell), (SECT_CONTRACT, &Gateset::V1.contract_bytes(3))]),
1366            "malformed",
1367        ),
1368        (
1369            "v1_oplog_twice",
1370            wqc_raw(b"WQC1", &[(SECT_CONTRACT, &canon1), (SECT_OPLOG, &bell), (SECT_OPLOG, &oplog_of(&[op(1, &[], 0, 0)]))]),
1371            "malformed",
1372        ),
1373        // §2.1: the contract is I-JSON.
1374        ("v1_contract_duplicate_member", v1(&swap(&canon1, "\"frac\":30", "\"frac\":30,\"frac\":30")), "contract"),
1375        ("v1_contract_lone_surrogate", v1(&swap(&canon1, "}", ",\"note\":\"\\ud800\"}")), "contract"),
1376        ("v1_contract_too_deep", v1(&deep), "contract"),
1377        ("v1_n_qubits_minus0", v1(&swap(&canon1, "\"n_qubits\":2", "\"n_qubits\":-0")), "malformed"),
1378        ("v1_contract_lone_low_surrogate", v1(&with_members(&canon1, br#""note":"\udc00""#)), "contract"),
1379        ("v1_contract_noncharacter", v1(&with_members(&canon1, br#""note":"\ufdd0""#)), "contract"),
1380        ("v1_contract_raw_noncharacter", v1(&with_members(&canon1, "\"note\":\"\u{ffff}\"".as_bytes())), "contract"),
1381        (
1382            "v1_contract_integer_rounds_to_infinity",
1383            v1(&with_members(&canon1, format!("\"x\":{RANGE_LIMIT}").as_bytes())),
1384            "contract",
1385        ),
1386        ("v1_contract_number_rounds_to_infinity", v1(&with_members(&canon1, br#""x":1.7976931348623159e308"#)), "contract"),
1387        // 10^309, written with a run of zeros its exponent offsets.
1388        (
1389            "v1_contract_long_literal",
1390            v1(&with_members(&canon1, format!("\"x\":0.{}1e655669", "0".repeat(655_359)).as_bytes())),
1391            "contract",
1392        ),
1393        ("v1_contract_bom", v1(&[b"\xef\xbb\xbf".as_slice(), &canon1].concat()), "contract"),
1394        ("v1_contract_nan", v1(&with_members(&canon1, br#""x":NaN"#)), "contract"),
1395        ("v1_contract_control_character", v1(&with_members(&canon1, b"\"note\":\"a\x01b\"")), "contract"),
1396        // §2.3: so is the measurement.
1397        (
1398            "v1_measure_duplicate_member",
1399            wqc_raw(b"WQC1", &[(SECT_CONTRACT, &canon1), (SECT_OPLOG, &bell), (SECT_MEASURE, br#"{"seed":1,"seed":2,"shots":10}"#)]),
1400            "malformed",
1401        ),
1402        ("v1_contract_not_utf8", v1(&not_utf8), "contract"),
1403        ("v1_contract_number_out_of_range", v1(&swap(&canon1, "}", ",\"x\":1e400}")), "contract"),
1404        ("v1_n_qubits_fraction", v1(&swap(&canon1, "\"n_qubits\":2", "\"n_qubits\":2.0")), "malformed"),
1405        ("v1_n_qubits_missing", v1(&swap(&canon1, "\"n_qubits\":2,", "")), "malformed"),
1406        (
1407            "v1_measure_not_json",
1408            wqc_raw(b"WQC1", &[(SECT_CONTRACT, &canon1), (SECT_OPLOG, &bell), (SECT_MEASURE, br#"{"seed":1,"#)]),
1409            "malformed",
1410        ),
1411        // §2: the payload, its table and its sections.
1412        ("short_payload", b"WQC2\x00".to_vec(), "malformed"),
1413        ("table_past_end", table_past_end, "malformed"),
1414        ("section_past_end", wqc_table(b"WQC1", &[(SECT_CONTRACT, 0, c1), (SECT_OPLOG, c1, b1 + 1)], &both), "malformed"),
1415        (
1416            "unknown_section_past_end",
1417            wqc_table(b"WQC1", &[(SECT_CONTRACT, 0, c1), (SECT_OPLOG, c1, b1), (0x7F, c1 + b1, 1)], &both),
1418            "malformed",
1419        ),
1420        ("no_contract", wqc_raw(b"WQC1", &[(SECT_OPLOG, &bell)]), "malformed"),
1421        ("no_oplog", wqc_raw(b"WQC1", &[(SECT_CONTRACT, &canon1)]), "malformed"),
1422        // §2.2: the op-log parses, and the circuit keeps its rules.
1423        ("v1_oplog_short", v1_oplog(&[0, 0, 0]), "malformed"),
1424        ("v1_op_truncated_controls", v1_oplog(&truncated_controls), "malformed"),
1425        ("v1_opcode_10", v1_oplog(&oplog_of(&[op(10, &[], 0, 0)])), "malformed"),
1426        ("v1_target_out_of_range", v1_oplog(&oplog_of(&[op(4, &[], 2, 0)])), "invalid"),
1427        ("v1_control_out_of_range", v1_oplog(&oplog_of(&[op(1, &[2], 1, 0)])), "invalid"),
1428        ("v1_control_is_target", v1_oplog(&oplog_of(&[op(1, &[1], 1, 0)])), "invalid"),
1429        ("v1_phase_0", v1_oplog(&oplog_of(&[op(9, &[], 0, 0)])), "invalid"),
1430        ("v1_phase_33", v1_oplog(&oplog_of(&[op(9, &[], 0, 33)])), "invalid"),
1431        ("v1_n_ops_u32max", v1_oplog(&n_ops_u32max), "malformed"),
1432        ("v1_offset_wrap", wrap, "malformed"),
1433        ("v2_contract_whitespace", v2_contract(&swap(&canon2, "\"n_qubits\":2", "\"n_qubits\": 2")), "contract"),
1434        ("v2_contract_key_order", v2_contract(reordered2.as_bytes()), "contract"),
1435        ("v2_contract_extra_member", v2_contract(&swap(&canon2, "}", ",\"note\":\"x\"}")), "contract"),
1436        ("v2_contract1_in_wqc2", v2_contract(&canon1), "contract"),
1437        ("v2_n_qubits_256", v2_contract(&swap(&canon2, "\"n_qubits\":2", "\"n_qubits\":256")), "malformed"),
1438        ("v2_contract_not_object", v2_contract(&[b"[".as_slice(), &canon2, b"]"].concat()), "contract"),
1439        // The I-JSON rules come before n_qubits: out of range is a contract
1440        // refusal, in range but not an integer a malformed one.
1441        (
1442            "v2_n_qubits_rounds_to_infinity",
1443            v2_contract(&swap(&canon2, "\"n_qubits\":2", "\"n_qubits\":1.7976931348623159e308")),
1444            "contract",
1445        ),
1446        (
1447            "v2_n_qubits_largest_finite",
1448            v2_contract(&swap(&canon2, "\"n_qubits\":2", "\"n_qubits\":1.7976931348623158e308")),
1449            "malformed",
1450        ),
1451        ("v2_phase_0", v2_oplog(&oplog_of(&[op(9, &[], 0, 0)])), "invalid"),
1452        (
1453            "v2_measure_twice",
1454            wqc_raw(b"WQC2", &[(SECT_CONTRACT, &canon2), (SECT_OPLOG, &bell), (SECT_MEASURE, measure), (SECT_MEASURE, measure)]),
1455            "malformed",
1456        ),
1457        ("v2_measure_seed_signed", v2_measure(br#"{"seed":-1,"shots":10,"basis":"computational"}"#), "malformed"),
1458        (
1459            "v2_duplicate_controls",
1460            v2(&Gateset::V2.contract_bytes(3), &oplog_of(&[op(1, &[0, 0], 2, 0)]), None),
1461            "invalid",
1462        ),
1463        ("v2_param_on_h", v2_oplog(&oplog_of(&[op(4, &[], 0, 7), op(1, &[0], 1, 0)])), "invalid"),
1464        ("v2_oplog_trailing_byte", v2_oplog(&[bell.as_slice(), &[0]].concat()), "malformed"),
1465        ("v2_opcode_10", v2_oplog(&oplog_of(&[op(10, &[], 0, 0)])), "malformed"),
1466        ("v2_measure_spaced", v2_measure(br#"{"seed": 1, "shots": 10, "basis": "computational"}"#), "malformed"),
1467        ("v2_measure_no_shots", v2_measure(br#"{"seed":1,"basis":"computational"}"#), "malformed"),
1468        ("v2_measure_basis_x", v2_measure(br#"{"seed":1,"shots":10,"basis":"x"}"#), "malformed"),
1469    ]
1470}
1471
1472/// The accept corpus of extensions/quantum-sim §2, as `(name, payload, circuit,
1473/// measurement)`: payloads a reader must accept, each with the circuit and the
1474/// measurement it reads as. They sit at the edges the reject corpus does not
1475/// reach from the other side: circuit/1's free formatting and further members,
1476/// every I-JSON rule at its limit, circuit/1's lax measurement, op-log bytes
1477/// after the last op, unknown sections, and the widest `n_qubits` and `u64`
1478/// values. The conformance corpus's `accept/` tree is written from this list.
1479pub fn accept_corpus() -> Vec<(&'static str, Vec<u8>, Circuit, Option<Measure>)> {
1480    let bell_ops = |gateset| Circuit {
1481        n_qubits: 2,
1482        ops: vec![
1483            Gate { base: BaseGate::H, controls: vec![], target: 0, param: 0 },
1484            Gate { base: BaseGate::X, controls: vec![0], target: 1, param: 0 },
1485        ],
1486        gateset,
1487    };
1488    let (bell1, bell2) = (bell_ops(Gateset::V1), bell_ops(Gateset::V2));
1489    let wide = |c: &Circuit| Circuit { n_qubits: 255, ..c.clone() };
1490    let bell = oplog_of(&[op(4, &[], 0, 0), op(1, &[0], 1, 0)]);
1491    let canon1 = Gateset::V1.contract_bytes(2);
1492    let canon2 = Gateset::V2.contract_bytes(2);
1493    let v1 = |contract: &[u8]| wqc_raw(b"WQC1", &[(SECT_CONTRACT, contract), (SECT_OPLOG, &bell)]);
1494    let v1_measure = |measure: &[u8]| wqc_raw(b"WQC1", &[(SECT_CONTRACT, &canon1), (SECT_OPLOG, &bell), (SECT_MEASURE, measure)]);
1495    let m = |seed, shots| Some(Measure { seed, shots });
1496    let reordered = format!(
1497        r#"{{"gateset":"{}","frac":30,"numeric":"{}","n_qubits":2,"ext":"{}"}}"#,
1498        Gateset::V1.name(),
1499        Gateset::V1.numeric(),
1500        Gateset::V1.ext()
1501    );
1502    let spaced = String::from_utf8(canon1.clone()).expect("a contract is text").replace(':', " : ").replace(',', " ,\n\t");
1503    let spaced = format!(" \r\n{spaced}\r\n ");
1504    let depth = format!(r#""x":{}{}"#, "[".repeat(126), "]".repeat(126));
1505    let largest_integer = format!("{}1", &RANGE_LIMIT[..RANGE_LIMIT.len() - 1]);
1506    let unknown = |magic: &[u8; 4], contract: &[u8]| {
1507        wqc_raw(magic, &[(0x7F, b"later"), (SECT_CONTRACT, contract), (SECT_OPLOG, &bell), (0x04, b"")])
1508    };
1509    let mut param_on_h = bell1.clone();
1510    param_on_h.ops[0].param = 7;
1511    let mut repeated_control = bell1.clone();
1512    repeated_control.ops[1].controls = vec![0, 0];
1513    vec![
1514        ("v1_members_reordered", v1(reordered.as_bytes()), bell1.clone(), None),
1515        ("v1_whitespace", v1(spaced.as_bytes()), bell1.clone(), None),
1516        (
1517            "v1_further_members",
1518            v1(&with_members(&canon1, br#""note":"x","list":[0,-1,2.5,-3e-2,1E+2,true,false,null,{},[]],"obj":{"a":{"b":[]}},"again":{"note":1}"#)),
1519            bell1.clone(),
1520            None,
1521        ),
1522        (
1523            "v1_escapes_and_characters",
1524            v1(&with_members(&canon1, "\"note\":\"\\\"\\\\\\/\\b\\f\\n\\r\\t\\u00e9\\ud83d\\ude00\\udbff\\udffd\u{e9}\u{fdcf}\u{fdf0}\u{fffd}\u{10fffd}\"".as_bytes())),
1525            bell1.clone(),
1526            None,
1527        ),
1528        ("v1_depth_127", v1(&with_members(&canon1, depth.as_bytes())), bell1.clone(), None),
1529        (
1530            "v1_numbers_largest_finite",
1531            v1(&with_members(&canon1, format!(r#""x":1.7976931348623158e308,"y":-1.7976931348623157e308,"z":{largest_integer},"w":-{largest_integer}"#).as_bytes())),
1532            bell1.clone(),
1533            None,
1534        ),
1535        // Exactly 1 and exactly 10, written long: a run of zeros the exponent
1536        // offsets, and an exponent with leading zeros.
1537        (
1538            "v1_numbers_long_literals",
1539            v1(&with_members(&canon1, format!("\"x\":1{}e-655360,\"y\":1e{}1", "0".repeat(655_360), "0".repeat(4300)).as_bytes())),
1540            bell1.clone(),
1541            None,
1542        ),
1543        (
1544            "v1_numbers_toward_zero",
1545            v1(&with_members(&canon1, br#""x":1e-400,"y":-0,"z":0e99999999999999999999,"w":-0.0E-0"#)),
1546            bell1.clone(),
1547            None,
1548        ),
1549        ("v1_n_qubits_255", v1(&Gateset::V1.contract_bytes(255)), wide(&bell1), None),
1550        ("v1_measure_lax", v1_measure(br#" { "basis" : "x" , "shots" : 10 , "seed" : 1 } "#), bell1.clone(), m(1, 10)),
1551        ("v1_measure_missing_shots", v1_measure(br#"{"seed":1,"basis":"computational"}"#), bell1.clone(), m(1, 0)),
1552        (
1553            "v1_measure_u64_max",
1554            v1_measure(br#"{"seed":18446744073709551615,"shots":18446744073709551615}"#),
1555            bell1.clone(),
1556            m(u64::MAX, u64::MAX),
1557        ),
1558        (
1559            "v1_measure_not_u64",
1560            v1_measure(br#"{"seed":18446744073709551616,"shots":-0,"x":2.5}"#),
1561            bell1.clone(),
1562            m(0, 0),
1563        ),
1564        ("v1_measure_other_types", v1_measure(br#"{"seed":"1","shots":1e1,"basis":null}"#), bell1.clone(), m(0, 0)),
1565        ("v1_measure_not_object", v1_measure(b"[1,2]"), bell1.clone(), m(0, 0)),
1566        (
1567            "v1_oplog_trailing_bytes",
1568            wqc_raw(b"WQC1", &[(SECT_CONTRACT, &canon1), (SECT_OPLOG, &[bell.as_slice(), &[0, 1, 2]].concat())]),
1569            bell1.clone(),
1570            None,
1571        ),
1572        (
1573            "v1_param_on_h",
1574            wqc_raw(b"WQC1", &[(SECT_CONTRACT, &canon1), (SECT_OPLOG, &oplog_of(&[op(4, &[], 0, 7), op(1, &[0], 1, 0)]))]),
1575            param_on_h,
1576            None,
1577        ),
1578        (
1579            "v1_repeated_control",
1580            wqc_raw(b"WQC1", &[(SECT_CONTRACT, &canon1), (SECT_OPLOG, &oplog_of(&[op(4, &[], 0, 0), op(1, &[0, 0], 1, 0)]))]),
1581            repeated_control,
1582            None,
1583        ),
1584        ("v1_unknown_sections", unknown(b"WQC1", &canon1), bell1.clone(), None),
1585        ("v2_unknown_sections", unknown(b"WQC2", &canon2), bell2.clone(), None),
1586        (
1587            "v2_n_qubits_255",
1588            wqc_raw(b"WQC2", &[(SECT_CONTRACT, &Gateset::V2.contract_bytes(255)), (SECT_OPLOG, &bell)]),
1589            wide(&bell2),
1590            None,
1591        ),
1592        (
1593            "v2_measure_u64_max",
1594            wqc_raw(
1595                b"WQC2",
1596                &[
1597                    (SECT_CONTRACT, &canon2),
1598                    (SECT_OPLOG, &bell),
1599                    (SECT_MEASURE, br#"{"seed":18446744073709551615,"shots":18446744073709551615,"basis":"computational"}"#),
1600                ],
1601            ),
1602            bell2,
1603            m(u64::MAX, u64::MAX),
1604        ),
1605    ]
1606}
1607
1608#[cfg(test)]
1609mod tests {
1610    use super::*;
1611    /// The pre-optimisation `apply`, kept verbatim as an oracle. The fast paths
1612    /// are justified by an argument (`fxmul(ONE,x) == x`, `fxmul(0,x) == 0`), and
1613    /// an argument about fixed-point rounding is exactly the kind that is
1614    /// convincing and wrong, so it is checked against the code it replaced.
1615    fn apply_reference(amps: &mut [Amp], n: u8, g: &Gate, gs: Gateset) {
1616        let m = g.base.matrix(g.param, gs);
1617        let tbit = 1usize << g.target;
1618        let ctrl_mask: usize = g.controls.iter().fold(0usize, |acc, &c| acc | (1usize << c));
1619        let dim = 1usize << n;
1620        let mut i = 0usize;
1621        while i < dim {
1622            if i & tbit == 0 && (i & ctrl_mask) == ctrl_mask {
1623                let j = i | tbit;
1624                let a0 = amps[i];
1625                let a1 = amps[j];
1626                amps[i] = m[0][0].mul(a0).add(m[0][1].mul(a1));
1627                amps[j] = m[1][0].mul(a0).add(m[1][1].mul(a1));
1628            }
1629            i += 1;
1630        }
1631    }
1632
1633
1634    /// Optimised `apply` against the pre-optimisation oracle, in one process,
1635    /// interleaved, best-of-N. Comparing separate runs on a busy machine produced
1636    /// swings big enough to invent speedups and regressions that were not there —
1637    /// including an apparent slowdown in a code path that had not changed.
1638    #[test]
1639    #[ignore]
1640    fn probe_apply_speedup() {
1641        use std::time::Instant;
1642        let n = 20u8;
1643        let dim = 1usize << n;
1644        let reps = 5;
1645        let gates = 60;
1646        println!("\\n  n={n}  best of {reps}, interleaved");
1647        println!("  gate   reference     optimised     speedup");
1648        for kind in ["h", "t", "z", "s", "x", "cx", "cz", "y"] {
1649            let mut ops: Vec<Gate> = Vec::new();
1650            for i in 0..gates {
1651                let q = (i % n as usize) as u8;
1652                let o = (q + 1) % n;
1653                ops.push(match kind {
1654                    "h" => Gate { base: BaseGate::H, controls: vec![], target: q, param: 0 },
1655                    "t" => Gate { base: BaseGate::T, controls: vec![], target: q, param: 0 },
1656                    "z" => Gate { base: BaseGate::Z, controls: vec![], target: q, param: 0 },
1657                    "s" => Gate { base: BaseGate::S, controls: vec![], target: q, param: 0 },
1658                    "x" => Gate { base: BaseGate::X, controls: vec![], target: q, param: 0 },
1659                    "y" => Gate { base: BaseGate::Y, controls: vec![], target: q, param: 0 },
1660                    "cx" => Gate { base: BaseGate::X, controls: vec![o], target: q, param: 0 },
1661                    _ => Gate { base: BaseGate::Z, controls: vec![o], target: q, param: 0 },
1662                });
1663            }
1664            let (mut best_ref, mut best_opt) = (u128::MAX, u128::MAX);
1665            for _ in 0..reps {
1666                let mut a = vec![Amp::ZERO; dim];
1667                a[0] = Amp::ONE;
1668                let t0 = Instant::now();
1669                for g in &ops { apply_reference(&mut a, n, g, Gateset::V2); }
1670                best_ref = best_ref.min(t0.elapsed().as_nanos());
1671                std::hint::black_box(&a);
1672
1673                let mut b = vec![Amp::ZERO; dim];
1674                b[0] = Amp::ONE;
1675                let t1 = Instant::now();
1676                for g in &ops { apply(&mut b, n, g, Gateset::V2); }
1677                best_opt = best_opt.min(t1.elapsed().as_nanos());
1678                std::hint::black_box(&b);
1679            }
1680            let (r, o) = (best_ref as f64 / gates as f64, best_opt as f64 / gates as f64);
1681            println!("  {kind:<5} {r:>10.0} ns {o:>10.0} ns {:>9.2}x", r / o);
1682        }
1683    }
1684
1685    /// Every amplitude, not just the hash: random circuits over the whole gate set
1686    /// must come out of the optimised path bit-for-bit as they came out of the old
1687    /// one. A faster simulator that moved one low bit would have broken every
1688    /// receipt this crate has ever signed. Both tables, and every `P(k)`: in
1689    /// circuit2, `P(k ≥ 18)` has `re == ONE` with `im ≠ 0`, which must take the
1690    /// diagonal path and nothing else.
1691    #[test]
1692    fn optimised_apply_is_bit_identical_to_the_general_path() {
1693        let mut st = 0x1234_5678_9ABC_DEF0u64;
1694        let mut rnd = |m: usize| {
1695            st = st.wrapping_mul(6364136223846793005).wrapping_add(1442695040888963407);
1696            ((st >> 33) as usize) % m.max(1)
1697        };
1698        for (case, gs) in Gateset::ALL.into_iter().flat_map(|gs| std::iter::repeat_n(gs, 300)).enumerate() {
1699            let n = 3 + rnd(3) as u8;
1700            let dim = 1usize << n;
1701            let mut c = Circuit::with_gateset(n, gs);
1702            for _ in 0..24 {
1703                let t = rnd(n as usize) as u8;
1704                let mut other = rnd(n as usize) as u8;
1705                if other == t {
1706                    other = (t + 1) % n;
1707                }
1708                match rnd(13) {
1709                    0 => { c.x(t); }
1710                    1 => { c.y(t); }
1711                    2 => { c.z(t); }
1712                    3 => { c.h(t); }
1713                    4 => { c.s(t); }
1714                    5 => { c.t(t); }
1715                    6 => { c.p(1 + rnd(DYADIC_MAX) as u16, t); }
1716                    7 => { c.cx(other, t); }
1717                    8 => { c.cz(other, t); }
1718                    9 => { c.cp(1 + rnd(DYADIC_MAX) as u16, other, t); }
1719                    10 => c.ops.push(Gate { base: BaseGate::Sdg, controls: vec![], target: t, param: 0 }),
1720                    11 => c.ops.push(Gate { base: BaseGate::Tdg, controls: vec![], target: t, param: 0 }),
1721                    _ => c.ops.push(Gate { base: BaseGate::I, controls: vec![], target: t, param: 0 }),
1722                }
1723            }
1724            // controlled-Y and Toffoli too, which exercise the antidiagonal and
1725            // multi-control paths
1726            if n >= 3 {
1727                c.ops.push(Gate { base: BaseGate::Y, controls: vec![0], target: n - 1, param: 0 });
1728                c.ccx(0, 1, n - 1);
1729            }
1730
1731            let mut want = vec![Amp::ZERO; dim];
1732            want[0] = Amp::ONE;
1733            for g in &c.ops {
1734                apply_reference(&mut want, n, g, gs);
1735            }
1736            let got = c.simulate().unwrap();
1737            assert_eq!(got.amps, want, "case {case}: optimised apply diverged on {} gates, n={n}, {gs:?}", c.ops.len());
1738        }
1739    }
1740
1741
1742    /// Tolerance for "≈ 1.0" checks — fixed-point rounding accumulates a little,
1743    /// but determinism (not accuracy) is the contract. ~1e-4 of ONE.
1744    const TOL: i64 = ONE / 10_000;
1745
1746    fn approx(a: i64, b: i64, tol: i64) -> bool {
1747        (a - b).abs() <= tol
1748    }
1749
1750    fn hx(b: &[u8]) -> String {
1751        b.iter().map(|x| format!("{x:02x}")).collect()
1752    }
1753
1754    /// The conformance corpus's `dyadic_ladder`: X(0); then Y, Z, S, S†, T, T†
1755    /// and I on qubit 1; then CP(k; control 0, target 1) for k = 1..=32, twice.
1756    /// Every table entry multiplies a nonzero amplitude, so a change of one unit
1757    /// in any entry moves the statevector hash.
1758    fn dyadic_ladder(gs: Gateset) -> Circuit {
1759        let mut c = Circuit::with_gateset(2, gs);
1760        c.x(0).y(1).z(1).s(1);
1761        c.push(BaseGate::Sdg, vec![], 1, 0);
1762        c.t(1);
1763        c.push(BaseGate::Tdg, vec![], 1, 0);
1764        c.push(BaseGate::I, vec![], 1, 0);
1765        for _ in 0..2 {
1766            for k in 1..=DYADIC_MAX as u16 {
1767                c.cp(k, 0, 1);
1768            }
1769        }
1770        c
1771    }
1772
1773    /// circuit/1's table is the recurrence its artefacts were made with, and
1774    /// stays that way. The defect is pinned on purpose, so that nobody repairs
1775    /// circuit/1 in place: a repaired table would stop every circuit/1 file and
1776    /// receipt from reproducing. The repair is circuit2.
1777    #[test]
1778    fn phase_table_v1_is_frozen() {
1779        // The recurrence: truncating halving, floor square root. Both halves are
1780        // non-negative, so truncating division is floor division.
1781        let mut t = [Amp::ZERO; DYADIC_MAX + 1];
1782        t[1] = Amp { re: -ONE, im: 0 };
1783        t[2] = Amp { re: 0, im: ONE };
1784        for k in 3..=DYADIC_MAX {
1785            let c = t[k - 1].re;
1786            t[k] = Amp { re: sqrt_fx((ONE + c) / 2), im: sqrt_fx((ONE - c) / 2) };
1787        }
1788        assert_eq!(t, PHASE_V1, "PHASE_V1 is not the circuit/1 recurrence");
1789        assert_eq!(
1790            hx(&Gateset::V1.table_digest()),
1791            "3fa9805ff96feb819a1cf371fedcd3b5228f93eddf933d0edcf401cbf8c28466"
1792        );
1793        // From k = 19 on, circuit/1 applies no phase at all.
1794        for k in 19..=DYADIC_MAX {
1795            assert_eq!(PHASE_V1[k], Amp { re: ONE - 1, im: 0 }, "PHASE_V1[{k}]");
1796        }
1797        assert_eq!(Gateset::V1.inv_sqrt2(), 759_250_124);
1798        // End to end, so the unit suite alone catches circuit/1 drift: the ladder
1799        // reproduces its circuit/1 corpus hash.
1800        let sv = dyadic_ladder(Gateset::V1).simulate().unwrap();
1801        assert_eq!(
1802            hx(&sv.statevector_hash()),
1803            "9754af24edd026601297a0f3334eb7171174978841a2938c9b372db942a3851d"
1804        );
1805    }
1806
1807    /// Every circuit2 entry is the nearest integer, proved with integers alone.
1808    ///
1809    /// Enclose `2^62·cos(2π/2^k)` and `2^62·sin(2π/2^k)` between integer bounds,
1810    /// starting exactly at `k = 2`, and halve the angle with rounding chosen to
1811    /// keep each bound on its side: `cos(θ/2) = √((1 + cos θ)/2)` and
1812    /// `sin(θ/2) = sin θ / (2 cos(θ/2))`, a quotient, so nothing cancels. If both
1813    /// ends of an enclosure round to the same integer at `2^-30`, the true value
1814    /// does too, and that integer is within ½ unit of it. Every endpoint is also
1815    /// required to sit more than `2^20` ulps from a tie.
1816    #[test]
1817    fn phase_table_v2_is_certified_nearest() {
1818        const S: u128 = 1 << 62;
1819        let mul = |a: u128, b: u128| a.checked_mul(b).expect("the enclosure overflowed u128");
1820        let ceil_isqrt = |x: u128| {
1821            let r = x.isqrt();
1822            if r * r == x { r } else { r + 1 }
1823        };
1824        // Round half up from 2^-62 to 2^-30.
1825        let r = |x: u128| ((x + (1 << 31)) >> 32) as i64;
1826        let far_from_tie = |x: u128| ((x & 0xFFFF_FFFF) as i128 - (1i128 << 31)).abs() > 1 << 20;
1827
1828        // (cos, sin)(π/2) = (0, 1), exactly.
1829        let (mut c_lo, mut c_hi, mut s_lo, mut s_hi) = (0u128, 0u128, S, S);
1830        for k in 3..=DYADIC_MAX {
1831            let c_lo2 = (mul(S + c_lo, S) >> 1).isqrt();
1832            let c_hi2 = ceil_isqrt(mul(S + c_hi, S).div_ceil(2));
1833            let s_lo2 = mul(s_lo, S) / (2 * c_hi2);
1834            let s_hi2 = mul(s_hi, S).div_ceil(2 * c_lo2);
1835            assert!(c_lo2 <= c_hi2 && s_lo2 <= s_hi2, "P({k}): an empty enclosure");
1836            let want = PHASE_V2[k];
1837            assert_eq!((r(c_lo2), r(c_hi2)), (want.re, want.re), "re P({k}) is not certified");
1838            assert_eq!((r(s_lo2), r(s_hi2)), (want.im, want.im), "im P({k}) is not certified");
1839            for x in [c_lo2, c_hi2, s_lo2, s_hi2] {
1840                assert!(far_from_tie(x), "P({k}): an endpoint lies within 2^20 ulps of a tie");
1841            }
1842            (c_lo, c_hi, s_lo, s_hi) = (c_lo2, c_hi2, s_lo2, s_hi2);
1843        }
1844        assert_eq!(PHASE_V2[0], Amp::ZERO);
1845        assert_eq!(PHASE_V2[1], Amp { re: -ONE, im: 0 });
1846        assert_eq!(PHASE_V2[2], Amp { re: 0, im: ONE });
1847        assert_eq!(
1848            hx(&Gateset::V2.table_digest()),
1849            "d34cb793715348e7c92db027c0bc3dddb6008f5730470bafaed978ea7fb23510"
1850        );
1851        assert_eq!(Gateset::V2.inv_sqrt2(), 759_250_125);
1852    }
1853
1854    /// Every circuit2 component is within one unit of the ideal, against an
1855    /// independent floating-point reference, and the same check fails on
1856    /// circuit/1, so it can tell a good table from a bad one.
1857    ///
1858    /// The reference is the crate's own `sin_cos`, which gives the same bits on
1859    /// every IEEE platform and is within an ulp; it is compiled under these
1860    /// features, all of which `full` enables.
1861    #[cfg(any(
1862        feature = "quantum_spd",
1863        feature = "quantum_pauli",
1864        feature = "quantum_mps",
1865        feature = "quantum_vml",
1866        feature = "quantum_phasor",
1867        feature = "quantum_kernel",
1868        feature = "quantum_tn",
1869        feature = "quantum_sv",
1870        feature = "quantum_tdvp",
1871        feature = "quantum_nqs"
1872    ))]
1873    #[test]
1874    fn every_v2_phase_is_within_one_unit_of_ideal() {
1875        // ½ unit, plus slack for the reference's own error (about 1e-7 unit).
1876        const BOUND: f64 = 0.5 + 1e-6;
1877        // The largest deviation of each entry from 2^30·(cos, sin)(2π/2^k).
1878        let deviation = |t: &[Amp; 33]| -> Vec<(usize, f64)> {
1879            (1..=DYADIC_MAX)
1880                .map(|k| {
1881                    let (s, c) = crate::repro::sin_cos(std::f64::consts::TAU / (1u64 << k) as f64);
1882                    let one = ONE as f64;
1883                    let dre = (t[k].re as f64 - c * one).abs();
1884                    let dim = (t[k].im as f64 - s * one).abs();
1885                    (k, dre.max(dim))
1886                })
1887                .collect()
1888        };
1889        let mut worst = 0.0f64;
1890        for (k, d) in deviation(&PHASE_V2) {
1891            assert!(d <= BOUND, "PHASE_V2[{k}] is {d} units from the ideal");
1892            worst = worst.max(d);
1893        }
1894        assert!(worst < 1.0);
1895        // Negative control: circuit/1 fails the same check from k = 8 on (its
1896        // P(8) imaginary part is 9.52 units high).
1897        let v1_bad: Vec<usize> =
1898            deviation(&PHASE_V1).into_iter().filter(|&(_, d)| d > BOUND).map(|(k, _)| k).collect();
1899        assert!(v1_bad.contains(&8), "the check passed circuit/1's P(8): {v1_bad:?}");
1900        assert!((8..=DYADIC_MAX).all(|k| v1_bad.contains(&k)), "circuit/1 failures: {v1_bad:?}");
1901    }
1902
1903    /// The identities each table must keep: `P(1) = −1` and `P(2) = i` exactly,
1904    /// `T = e^{iπ/4}` with `re == im == 1/√2`, and `|P(k)|² = 1` to within one
1905    /// unit in circuit2 and three in circuit/1.
1906    #[test]
1907    fn table_identities_per_gateset() {
1908        for gs in Gateset::ALL {
1909            assert_eq!(gs.phase(1), Amp { re: -ONE, im: 0 }, "{gs:?} P(1)");
1910            assert_eq!(gs.phase(2), Amp { re: 0, im: ONE }, "{gs:?} P(2)");
1911            assert_eq!(gs.phase(3).re, gs.phase(3).im, "{gs:?} T");
1912            assert_eq!(gs.phase(3).re, gs.inv_sqrt2(), "{gs:?} 1/√2");
1913            assert_eq!(gs.table()[0], Amp::ZERO, "{gs:?} index 0");
1914            let units: i128 = match gs {
1915                Gateset::V1 => 3,
1916                Gateset::V2 => 1,
1917            };
1918            for k in 1..=DYADIC_MAX {
1919                // |P|² − 1 at scale 2^60, exactly.
1920                let d = gs.phase(k).norm2() - (ONE as i128) * (ONE as i128);
1921                assert!(
1922                    d.abs() <= units << FRAC,
1923                    "{gs:?}: |P({k})|² − 1 = {} units",
1924                    d as f64 / ONE as f64
1925                );
1926            }
1927        }
1928    }
1929
1930    /// The identifiers each gateset names map back to it, and its contract bytes
1931    /// are the canonical template. circuit/1's must equal the serializer render
1932    /// every existing circuit hash was taken over (`serde_contract_v1`).
1933    #[test]
1934    fn gateset_identifiers_are_consistent() {
1935        assert_eq!(Gateset::default(), Gateset::V2);
1936        for gs in Gateset::ALL {
1937            assert_eq!(Gateset::from_magic(&gs.magic()), Some(gs));
1938            assert_eq!(Gateset::from_capability(gs.capability()), Some(gs));
1939            assert_eq!(gs.ext(), format!("{}/1", gs.capability()));
1940        }
1941        assert_eq!(Gateset::from_magic(b"WQC3"), None);
1942        assert_eq!(Gateset::from_magic(b"WQC"), None);
1943        assert_eq!(Gateset::from_magic(b"WQC1\0"), None);
1944        assert_eq!(Gateset::from_capability("wai.quantum.circuit/1"), None);
1945        assert_eq!(Gateset::from_capability("wai.quantum.circuit3"), None);
1946        assert_eq!(
1947            Gateset::V1.contract_bytes(5),
1948            br#"{"ext":"wai.quantum.circuit/1","n_qubits":5,"numeric":"wai.det.fixed64","frac":30,"gateset":"cliffordT+dyadicP"}"#
1949        );
1950        assert_eq!(
1951            Gateset::V2.contract_bytes(5),
1952            br#"{"ext":"wai.quantum.circuit2/1","n_qubits":5,"numeric":"wai.det.amp64","frac":30,"gateset":"cliffordT+dyadicP.rn"}"#
1953        );
1954        assert_eq!((Gateset::V1.contract_bytes(5).len(), Gateset::V2.contract_bytes(5).len()), (112, 114));
1955        for n in 0..=u8::MAX {
1956            assert_eq!(Gateset::V1.contract_bytes(n), serde_contract_v1(n), "n_qubits {n}");
1957        }
1958    }
1959
1960    /// circuit/1's contract as 0.3.x rendered it, through the serializer with
1961    /// member order preserved. Every circuit/1 hash and file was taken over
1962    /// these bytes.
1963    fn serde_contract_v1(n_qubits: u8) -> Vec<u8> {
1964        serde_json::to_vec(&serde_json::json!({
1965            "ext": "wai.quantum.circuit/1",
1966            "n_qubits": n_qubits,
1967            "numeric": "wai.det.fixed64",
1968            "frac": FRAC,
1969            "gateset": "cliffordT+dyadicP",
1970        }))
1971        .unwrap()
1972    }
1973
1974    /// The measurement section as 0.3.x rendered it, through the serializer.
1975    fn serde_measure(m: Measure) -> Vec<u8> {
1976        serde_json::to_vec(&serde_json::json!({ "seed": m.seed, "shots": m.shots, "basis": "computational" })).unwrap()
1977    }
1978
1979    #[test]
1980    fn simulation_is_deterministic_byte_for_byte() {
1981        // The core claim: same circuit → identical amplitudes, twice.
1982        let c = Circuit::qft(6);
1983        let a = c.simulate().unwrap();
1984        let b = c.simulate().unwrap();
1985        assert_eq!(a.amps, b.amps, "quantum sim must be byte-exact reproducible");
1986        assert_eq!(a.statevector_hash(), b.statevector_hash());
1987    }
1988
1989    #[test]
1990    fn bell_state() {
1991        // H(0); CX(0,1) → (|00⟩ + |11⟩)/√2
1992        let mut c = Circuit::new(2);
1993        c.h(0).cx(0, 1);
1994        let sv = c.simulate().unwrap();
1995        let s = c.gateset.inv_sqrt2();
1996        assert!(approx(sv.amps[0b00].re, s, TOL));
1997        assert_eq!(sv.amps[0b01], Amp::ZERO);
1998        assert_eq!(sv.amps[0b10], Amp::ZERO);
1999        assert!(approx(sv.amps[0b11].re, s, TOL));
2000        // fidelity with itself ≈ 1
2001        assert!(approx(sv.fidelity_fx(&sv), ONE, TOL));
2002    }
2003
2004    #[test]
2005    fn ghz_state() {
2006        // H(0); CX(0,1); CX(1,2) → (|000⟩ + |111⟩)/√2
2007        let mut c = Circuit::new(3);
2008        c.h(0).cx(0, 1).cx(1, 2);
2009        let sv = c.simulate().unwrap();
2010        let s = c.gateset.inv_sqrt2();
2011        assert!(approx(sv.amps[0b000].re, s, TOL));
2012        assert!(approx(sv.amps[0b111].re, s, TOL));
2013        for k in 1..7 {
2014            assert_eq!(sv.amps[k], Amp::ZERO, "index {k} should be empty");
2015        }
2016    }
2017
2018    #[test]
2019    fn qft_of_zero_is_uniform_superposition() {
2020        // QFT|0…0⟩ = (1/√N) Σ|k⟩ — every amplitude has magnitude 1/√N.
2021        let n = 4u8;
2022        let dim = 1usize << n;
2023        let sv = Circuit::qft(n).simulate().unwrap();
2024        // |amp|^2 = 1/N; norm2() is at 2^(2·FRAC), so (norm2 >> FRAC) is at 2^FRAC,
2025        // i.e. the expected value is ONE/N.
2026        let want2 = ONE / dim as i64;
2027        for k in 0..dim {
2028            let mag2 = ((sv.amps[k].norm2()) >> FRAC) as i64;
2029            assert!(approx(mag2, want2, ONE / 1000), "amp {k} magnitude^2 {mag2} != {want2}");
2030        }
2031    }
2032
2033    #[test]
2034    fn orthogonal_states_have_zero_fidelity() {
2035        let a = StateVector::basis(3, 0b000);
2036        let b = StateVector::basis(3, 0b111);
2037        assert_eq!(a.fidelity_fx(&b), 0);
2038        assert!(approx(a.fidelity_fx(&a), ONE, 1));
2039    }
2040
2041    #[test]
2042    fn shot_histogram_is_deterministic() {
2043        // Bell state: shots concentrate on |00⟩ and |11⟩, reproducibly.
2044        let mut c = Circuit::new(2);
2045        c.h(0).cx(0, 1);
2046        let sv = c.simulate().unwrap();
2047        let h1 = sv.histogram_hash(0xC0FFEE, 10_000);
2048        let h2 = sv.histogram_hash(0xC0FFEE, 10_000);
2049        assert_eq!(h1, h2, "pinned-seed histogram must be reproducible");
2050        let counts = sv.sample_shots(0xC0FFEE, 10_000);
2051        assert_eq!(counts[0b01], 0);
2052        assert_eq!(counts[0b10], 0);
2053        assert!(counts[0b00] > 4000 && counts[0b00] < 6000, "≈ half on |00⟩: {}", counts[0b00]);
2054        assert_eq!(counts[0b00] + counts[0b11], 10_000);
2055    }
2056
2057    /// The four circuits of the circuit/1 corpus, built in `gs`: bell, with
2058    /// the corpus measurement, then ghz3, qft3 and qft5.
2059    fn corpus_circuits(gs: Gateset) -> [(&'static str, Circuit, Option<Measure>); 4] {
2060        let mut bell = Circuit::with_gateset(2, gs);
2061        bell.h(0).cx(0, 1);
2062        let mut ghz3 = Circuit::with_gateset(3, gs);
2063        ghz3.h(0).cx(0, 1).cx(1, 2);
2064        let qft = |n| {
2065            let mut c = Circuit::qft(n);
2066            c.gateset = gs;
2067            c
2068        };
2069        [
2070            ("bell", bell, Some(Measure { seed: 12_648_430, shots: 100_000 })),
2071            ("ghz3", ghz3, None),
2072            ("qft3", qft(3), None),
2073            ("qft5", qft(5), None),
2074        ]
2075    }
2076
2077    /// A circuit/1 container is written byte for byte as 0.3.x wrote it: the
2078    /// four corpus files reproduce, and so do their manifest circuit hashes.
2079    /// The measurement, now rendered directly, matches the serializer's render.
2080    #[test]
2081    fn circuit1_files_are_written_as_before() {
2082        // (file, bytes, BLAKE3 of the file, manifest circuit_hash)
2083        let want = [
2084            ("bell", 216, "97b294a85afe628060a51f12e7f9c2104ebc0b7d04ef36ff15b154ed1c54728e",
2085             "894d9a9582b19f27b8d08d06938357237fc00f7f30bf4bfc2be0c04fa5e47a4e"),
2086            ("ghz3", 157, "8f2d924416a19bc96407f36669ca3f55bcd6a57b3256bd16a669dc96bd3fb490",
2087             "34e44f7d68037cbb3aee677f56b894dc48df6d408aa068a16d3b18076e5e7c5c"),
2088            ("qft3", 191, "e1a7e49e2804130d802d8e927f63d6633b966c8e6b7cd3eb7278e01fd1f884c5",
2089             "7e8414be4410557a05b52bcc1084e1c5f93b6caa0f28fa45f4d2ab661efd2a60"),
2090            ("qft5", 261, "92b4e1497f52109922a0f2ea7ec8de2b1d9e92f155dafbf6e5f69eca4427878c",
2091             "f36a9af99a251cae6f42144b2be3c57523f15e1e2ab3492cf15cac709fc048be"),
2092        ];
2093        for ((name, c, m), (file, len, digest, hash)) in corpus_circuits(Gateset::V1).into_iter().zip(want) {
2094            assert_eq!(name, file);
2095            let bytes = to_wqc(&c, m).unwrap();
2096            assert_eq!(bytes.len(), len, "{name}.wqc");
2097            assert_eq!(hx(blake3::hash(&bytes).as_bytes()), digest, "{name}.wqc");
2098            assert_eq!(hx(&circuit_hash(&c).unwrap()), hash, "{name}");
2099        }
2100        let values = [0, 1, 42, 1024, 100_000, 12_648_430, u64::from(u32::MAX), u64::MAX];
2101        for seed in values {
2102            for shots in values {
2103                let m = Measure { seed, shots };
2104                assert_eq!(measure_bytes(m), serde_measure(m), "{m:?}");
2105            }
2106        }
2107    }
2108
2109    /// Every hash of both conformance corpora, reproduced from code, so the
2110    /// unit suite alone catches a drift in either gateset. The circuit/1 rows
2111    /// for bell, ghz3, qft3 and qft5 are the manifest of the files 0.3.x
2112    /// wrote, nine hashes in all; the other rows were computed by an
2113    /// integer-only implementation that shares no code with this crate. None
2114    /// of these values may be edited to make this test pass.
2115    #[test]
2116    fn the_conformance_corpora_are_pinned() {
2117        // (file, bytes, n_ops, circuit_hash, statevector_hash)
2118        type Row = (&'static str, usize, usize, &'static str, &'static str);
2119        let v1: [Row; 7] = [
2120            ("bell", 216, 2, "894d9a9582b19f27b8d08d06938357237fc00f7f30bf4bfc2be0c04fa5e47a4e",
2121             "bd5df69662f4e61878d17baee1f3cf5705c3726d6740d1a4bf7be5133c099efb"),
2122            ("ghz3", 157, 3, "34e44f7d68037cbb3aee677f56b894dc48df6d408aa068a16d3b18076e5e7c5c",
2123             "08c5e6fb50b91a00d28795506cc5d99ce1e9a3a8b4c41e4bfd05f5d829af9542"),
2124            ("qft3", 191, 9, "7e8414be4410557a05b52bcc1084e1c5f93b6caa0f28fa45f4d2ab661efd2a60",
2125             "0fe1e5b8e2ac8e9afbfa926b3877967ebfead92efb7ed8e1ff6b117668926d6e"),
2126            ("qft5", 261, 21, "f36a9af99a251cae6f42144b2be3c57523f15e1e2ab3492cf15cac709fc048be",
2127             "c268d77f2ddf84fecb028e80ce989123912870f04e5b9a1e3d885c9ce235c27d"),
2128            ("qft5_x22", 276, 24, "40c847fe9f85b6d79d245b6e65420197e6bbedb9c0b1ab77baaf1cfe077ff4f5",
2129             "95a2d2fd41f6a13c19562729a4b553ee12db6adfaa361b5061c16d801354d0cd"),
2130            ("dyadic_ladder", 564, 72, "2fa5b02c952dcaf55ab4cfd2ea5b3fae999ac912a32a4e06dd2b6ee96bb58d4f",
2131             "9754af24edd026601297a0f3334eb7171174978841a2938c9b372db942a3851d"),
2132            ("qft8_ones", 460, 56, "5ca94d3a960b8ec65a1eb802699f1ed8e20f00e7fbd9297849f0c60047404a1a",
2133             "fd683498744552e9e2e8657a2bdc244e4f03d4ee4dd292c9705ba38b19fb709c"),
2134        ];
2135        let v2: [Row; 7] = [
2136            ("bell", 218, 2, "6f6199943059fc4d90554d7c33f1ac69723603f5128962a6e3cac9c765484d2b",
2137             "db68a50b08a8c2eabc89a881db9fcb130fff89dc36182d4c7f90da5bf4720b15"),
2138            ("ghz3", 159, 3, "c5911b898a899c999ce01730bb825c84678569493ac513760e15dcbccd84227f",
2139             "51850f28817200e9e03980b60f34879c7bd0147a07b0c1746528b801cae2e2f8"),
2140            ("qft3", 193, 9, "c23a1b1e31b87705999cbc54866f4c9e3e4c4d2b274d6260672121abb5ca89b8",
2141             "70fe25ec22008f86076328b2c0908ede778e6d8227e563e8c7dcd89f7e844bf2"),
2142            ("qft5", 263, 21, "8559c83769ac8c0cb3aabc64672233aa569cd4ce92aa6545f1449982b9aa8b8c",
2143             "50b01fab0bfee966e553a947aea6aa09cebf8f21ba201cd548d703048d66f2ba"),
2144            ("qft5_x22", 278, 24, "c126604030b16f4f1e88e6683894f9316262f49b3419be06ab74c7dbd2441651",
2145             "5def2fca1d29e9e2b9ca2020cd2fa2dc056d07ce2e21b6e101b6116a03efd61c"),
2146            ("dyadic_ladder", 566, 72, "8a6dcf0d41ecefd1a9761fef49b385d7dffe7543a9382efda02bfe4f7a0896fe",
2147             "28bdb7265c10d798012ac78b604327700acd8cdac0e1f88ed4045f8b0b78bc7c"),
2148            ("qft8_ones", 462, 56, "286f044750b19937f6e7bf6f534053aa74a21777516c773dbd7c254df7301b34",
2149             "e059d43a574780d819a872f7904bf96918ba5880e1c7c32b38159306acd559fe"),
2150        ];
2151        for (gs, rows) in [(Gateset::V1, v1), (Gateset::V2, v2)] {
2152            // The four originals, then the three table-sensitive vectors.
2153            let x_then_qft = |n: u8, xs: &[u8]| {
2154                let mut c = Circuit::with_gateset(n, gs);
2155                for &q in xs {
2156                    c.x(q);
2157                }
2158                c.ops.extend(Circuit::qft(n).ops);
2159                c
2160            };
2161            let mut vectors: Vec<(&str, Circuit, Option<Measure>)> = corpus_circuits(gs).into();
2162            vectors.push(("qft5_x22", x_then_qft(5, &[1, 2, 4]), None));
2163            vectors.push(("dyadic_ladder", dyadic_ladder(gs), None));
2164            vectors.push(("qft8_ones", x_then_qft(8, &[0, 1, 2, 3, 4, 5, 6, 7]), None));
2165            for ((name, c, m), (file, len, n_ops, circuit, statevector)) in vectors.into_iter().zip(rows) {
2166                assert_eq!(name, file);
2167                assert_eq!(c.gateset, gs, "{name}");
2168                assert_eq!(to_wqc(&c, m).unwrap().len(), len, "{gs:?} {name}.wqc");
2169                assert_eq!(c.ops.len(), n_ops, "{gs:?} {name}");
2170                assert_eq!(hx(&circuit_hash(&c).unwrap()), circuit, "{gs:?} {name}");
2171                let sv = c.simulate().unwrap();
2172                assert_eq!(hx(&sv.statevector_hash()), statevector, "{gs:?} {name}");
2173                // Bell is the measured vector. Its sampled outcomes do not
2174                // move between the tables, so neither does its histogram.
2175                if let Some(Measure { seed, shots }) = m {
2176                    assert_eq!(name, "bell");
2177                    assert_eq!(
2178                        hx(&sv.histogram_hash(seed, shots)),
2179                        "0893f48ef32ca9f2865f6617537f0a4a5334f67e3c944bba845beb2f377acdb3",
2180                        "{gs:?} {name}"
2181                    );
2182                }
2183            }
2184        }
2185    }
2186
2187    /// Both containers round-trip: the magic names the gateset, and the
2188    /// decoded circuit equals the written one, gateset included, with the same
2189    /// hash and state. circuit2's corpus circuits have the plan's sizes and
2190    /// circuit hashes. circuit/1 keeps reading what it always read: its
2191    /// contract in any member order, whitespace or with extra members, hashed
2192    /// as the canonical one; bytes after the op-log; a measurement that is
2193    /// spaced or lacks `shots`. Unknown sections are ignored in both.
2194    #[test]
2195    fn wqc_round_trips() {
2196        for gs in Gateset::ALL {
2197            for (name, c, m) in corpus_circuits(gs) {
2198                for m in [None, m.or(Some(Measure { seed: 42, shots: 1024 }))] {
2199                    let bytes = to_wqc(&c, m).unwrap();
2200                    assert_eq!(bytes[0..4], gs.magic(), "{gs:?} {name}");
2201                    let (c2, m2) = from_wqc(&bytes).unwrap();
2202                    assert_eq!((&c2, m2), (&c, m), "{gs:?} {name}");
2203                    assert_eq!(circuit_hash(&c2).unwrap(), circuit_hash(&c).unwrap(), "{gs:?} {name}");
2204                    assert_eq!(c2.simulate().unwrap(), c.simulate().unwrap(), "{gs:?} {name}");
2205                }
2206            }
2207        }
2208        // circuit2's four: (file, bytes, circuit_hash). QFT-5 is 263 bytes
2209        // here and 261 in circuit/1.
2210        let want = [
2211            ("bell", 218, "6f6199943059fc4d90554d7c33f1ac69723603f5128962a6e3cac9c765484d2b"),
2212            ("ghz3", 159, "c5911b898a899c999ce01730bb825c84678569493ac513760e15dcbccd84227f"),
2213            ("qft3", 193, "c23a1b1e31b87705999cbc54866f4c9e3e4c4d2b274d6260672121abb5ca89b8"),
2214            ("qft5", 263, "8559c83769ac8c0cb3aabc64672233aa569cd4ce92aa6545f1449982b9aa8b8c"),
2215        ];
2216        for ((name, c, m), (file, len, hash)) in corpus_circuits(Gateset::V2).into_iter().zip(want) {
2217            assert_eq!(name, file);
2218            assert_eq!(to_wqc(&c, m).unwrap().len(), len, "circuit2 {name}.wqc");
2219            assert_eq!(hx(&circuit_hash(&c).unwrap()), hash, "circuit2 {name}");
2220        }
2221
2222        // The accept corpus reads as it says, and its Bell circuit is the
2223        // vectors' bell.
2224        let [(_, bell, _), ..] = corpus_circuits(Gateset::V1);
2225        let accepted = accept_corpus();
2226        assert_eq!(accepted[0].2, bell);
2227        let names: std::collections::BTreeSet<_> = accepted.iter().map(|c| c.0).collect();
2228        assert_eq!(names.len(), accepted.len(), "case names repeat");
2229        for (name, file, circuit, measure) in accepted {
2230            let (back, m) = from_wqc(&file).unwrap_or_else(|e| panic!("{name}: {e}"));
2231            assert_eq!((&back, m), (&circuit, measure), "{name}");
2232        }
2233    }
2234
2235    /// Every case of the reject corpus fails with its class; so do the
2236    /// structural edge cases; the rules apply in the order the spec gives.
2237    /// More than 255 controls is refused everywhere a circuit is checked, and
2238    /// the widest circuit2 gate round-trips. An op-log that claims `u32::MAX`
2239    /// ops reserves for the ops its bytes can hold, not for the claim, and no
2240    /// section range can wrap.
2241    #[test]
2242    fn container_rejects() {
2243        let bell = oplog_of(&[op(4, &[], 0, 0), op(1, &[0], 1, 0)]);
2244        let (canon1, canon2) = (Gateset::V1.contract_bytes(2), Gateset::V2.contract_bytes(2));
2245        let measure = measure_bytes(Measure { seed: 1, shots: 10 });
2246        // The bases the cases are built from are accepted.
2247        for file in [
2248            wqc_raw(b"WQC1", &[(SECT_CONTRACT, &canon1), (SECT_OPLOG, &bell)]),
2249            wqc_raw(b"WQC2", &[(SECT_CONTRACT, &canon2), (SECT_OPLOG, &bell)]),
2250            wqc_raw(b"WQC2", &[(SECT_CONTRACT, &canon2), (SECT_OPLOG, &bell), (SECT_MEASURE, &measure)]),
2251        ] {
2252            from_wqc(&file).unwrap();
2253        }
2254
2255        let cases = reject_corpus();
2256        let names: std::collections::BTreeSet<_> = cases.iter().map(|c| c.0).collect();
2257        assert_eq!(names.len(), cases.len(), "case names repeat");
2258        let kinds: std::collections::BTreeSet<_> = cases.iter().map(|c| c.2).collect();
2259        assert_eq!(kinds, std::collections::BTreeSet::from(["contract", "invalid", "malformed"]));
2260        for (name, file, kind) in &cases {
2261            match from_wqc(file) {
2262                Ok(c) => panic!("{name} was accepted: {c:?}"),
2263                Err(e) => assert_eq!(e.kind(), *kind, "{name}: {e}"),
2264            }
2265        }
2266        // The I-JSON cases are refused by the rule their names give.
2267        for (name, rule) in [
2268            ("v1_contract_duplicate_member", "duplicate member"),
2269            ("v1_contract_lone_surrogate", "surrogate"),
2270            ("v1_contract_lone_low_surrogate", "surrogate"),
2271            ("v1_contract_too_deep", "depth"),
2272            ("v1_contract_not_utf8", "utf-8"),
2273            ("v1_contract_number_out_of_range", "number range"),
2274            ("v1_contract_integer_rounds_to_infinity", "number range"),
2275            ("v1_contract_number_rounds_to_infinity", "number range"),
2276            ("v1_contract_noncharacter", "noncharacter"),
2277            ("v1_contract_raw_noncharacter", "noncharacter"),
2278            ("v1_contract_bom", "syntax"),
2279            ("v1_contract_nan", "syntax"),
2280            ("v1_contract_control_character", "syntax"),
2281            ("v2_n_qubits_rounds_to_infinity", "number range"),
2282            ("v1_contract_long_literal", "number range"),
2283            ("v1_measure_duplicate_member", "duplicate member"),
2284            ("v1_measure_not_json", "syntax"),
2285        ] {
2286            let (_, file, _) = cases.iter().find(|c| c.0 == name).unwrap_or_else(|| panic!("no case {name}"));
2287            let e = from_wqc(file).unwrap_err().to_string();
2288            assert!(e.contains(&format!("I-JSON: {rule} at byte")), "{name}: {e}");
2289        }
2290
2291        // Structure, beyond the corpus.
2292        let structural: [(&str, Vec<u8>, &str); 9] = [
2293            ("short", b"WQC1\x00".to_vec(), "malformed"),
2294            ("table_cut", wqc_raw(b"WQC1", &[(SECT_CONTRACT, &canon1), (SECT_OPLOG, &bell)])[..20].to_vec(), "malformed"),
2295            ("no_contract", wqc_raw(b"WQC2", &[(SECT_OPLOG, &bell)]), "malformed"),
2296            ("no_oplog", wqc_raw(b"WQC2", &[(SECT_CONTRACT, &canon2)]), "malformed"),
2297            ("past_end", wqc_table(b"WQC1", &[(SECT_CONTRACT, 0, 112), (SECT_OPLOG, 112, 16)], &[canon1.as_slice(), &bell].concat()), "malformed"),
2298            ("contract_not_json", wqc_raw(b"WQC1", &[(SECT_CONTRACT, b"{\"ext\":"), (SECT_OPLOG, &bell)]), "contract"),
2299            (
2300                "v2_n_qubits_256",
2301                wqc_raw(b"WQC2", &[(SECT_CONTRACT, &swap(&canon2, "\"n_qubits\":2", "\"n_qubits\":256")), (SECT_OPLOG, &bell)]),
2302                "malformed",
2303            ),
2304            (
2305                "v1_n_qubits_negative",
2306                wqc_raw(b"WQC1", &[(SECT_CONTRACT, &swap(&canon1, "\"n_qubits\":2", "\"n_qubits\":-2")), (SECT_OPLOG, &bell)]),
2307                "malformed",
2308            ),
2309            (
2310                "v1_measure_not_json",
2311                wqc_raw(b"WQC1", &[(SECT_CONTRACT, &canon1), (SECT_OPLOG, &bell), (SECT_MEASURE, b"seed=1")]),
2312                "malformed",
2313            ),
2314        ];
2315        for (name, file, kind) in &structural {
2316            assert_eq!(from_wqc(file).map(|_| ()).unwrap_err().kind(), *kind, "{name}");
2317        }
2318        // An error quotes at most 64 characters of what the file holds.
2319        let long = swap(&canon1, "wai.quantum.circuit/1", &"é".repeat(10_000));
2320        let e = from_wqc(&wqc_raw(b"WQC1", &[(SECT_CONTRACT, &long), (SECT_OPLOG, &bell)])).unwrap_err();
2321        assert_eq!(e.kind(), "contract");
2322        assert!(e.to_string().chars().count() < 160, "{e}");
2323
2324        // The order: a repeated section before the contract, the contract
2325        // before the op-log, the op-log before validation, validation before
2326        // the measurement.
2327        let first = |sections: &[(u8, &[u8])]| from_wqc(&wqc_raw(b"WQC2", sections)).unwrap_err().kind();
2328        let canon3 = Gateset::V2.contract_bytes(3);
2329        let spaced = swap(&canon3, ":3", ": 3");
2330        let repeats = oplog_of(&[op(1, &[0, 0], 2, 0)]);
2331        assert_eq!(first(&[(SECT_CONTRACT, &spaced), (SECT_OPLOG, &repeats), (SECT_OPLOG, &repeats)]), "malformed");
2332        assert_eq!(first(&[(SECT_CONTRACT, &spaced), (SECT_OPLOG, &[0, 0])]), "contract");
2333        assert_eq!(first(&[(SECT_CONTRACT, &canon3), (SECT_OPLOG, &[repeats.as_slice(), &[0]].concat())]), "malformed");
2334        assert_eq!(first(&[(SECT_CONTRACT, &canon3), (SECT_OPLOG, &repeats), (SECT_MEASURE, b"[]")]), "invalid");
2335
2336        // More than 255 controls: refused by validate, to_wqc and circuit_hash
2337        // alike, in both gatesets.
2338        for gs in Gateset::ALL {
2339            let mut c = Circuit::with_gateset(2, gs);
2340            c.ops.push(Gate { base: BaseGate::X, controls: vec![0; 256], target: 1, param: 0 });
2341            let e = c.validate().unwrap_err();
2342            assert_eq!(e.kind(), "invalid", "{gs:?}");
2343            assert_eq!(to_wqc(&c, None).unwrap_err(), e, "{gs:?}");
2344            assert_eq!(circuit_hash(&c).unwrap_err(), e, "{gs:?}");
2345        }
2346        // 254 distinct controls on 255 qubits is the widest circuit2 gate.
2347        let mut wide = Circuit::with_gateset(255, Gateset::V2);
2348        wide.ops.push(Gate { base: BaseGate::X, controls: (0..254).collect(), target: 254, param: 0 });
2349        let bytes = to_wqc(&wide, None).unwrap();
2350        let (back, _) = from_wqc(&bytes).unwrap();
2351        assert_eq!(back, wide);
2352        assert_eq!(circuit_hash(&back).unwrap(), circuit_hash(&wide).unwrap());
2353
2354        // A 9-byte op-log claiming u32::MAX ops: the reservation is what 9
2355        // bytes can hold, one op, and the decode is malformed at the second.
2356        assert_eq!(oplog_capacity(u32::MAX, 9), 1);
2357        assert_eq!(oplog_capacity(u32::MAX, 3), 0);
2358        assert_eq!(oplog_capacity(3, 1 << 20), 3);
2359        let n_ops_u32max = [u32::MAX.to_le_bytes().as_slice(), &op(4, &[], 0, 0)].concat();
2360        assert_eq!(parse_oplog(&n_ops_u32max).unwrap_err(), QuantumError::Malformed("op header".into()));
2361
2362        // Section ranges are checked, so an offset that would wrap a 32-bit
2363        // usize is out of bounds there, as it is here.
2364        assert_eq!(section_range(24, 0, 112, 136), Some(24..136));
2365        assert_eq!(section_range(24, 0, 113, 136), None);
2366        assert_eq!(section_range(usize::MAX - 8, 0xFFFF_FFF0, 0x20, usize::MAX), None);
2367        assert_eq!(section_range(usize::MAX - 0x10, 0x8, 0x20, usize::MAX), None);
2368        assert_eq!(section_range(usize::MAX - 0x40, 0x10, 0x20, usize::MAX), Some(usize::MAX - 0x30..usize::MAX - 0x10));
2369    }
2370
2371
2372    #[test]
2373    fn validation_rejects_bad_indices() {
2374        let mut c = Circuit::new(2);
2375        c.push(BaseGate::X, vec![], 5, 0); // target out of range
2376        assert!(matches!(c.validate(), Err(QuantumError::Invalid(_))));
2377
2378        let mut c = Circuit::new(2);
2379        c.push(BaseGate::X, vec![1], 1, 0); // control == target
2380        assert!(matches!(c.validate(), Err(QuantumError::Invalid(_))));
2381
2382        let mut c = Circuit::new(1);
2383        c.push(BaseGate::P, vec![], 0, 999); // P(k) out of dyadic range
2384        assert!(matches!(c.validate(), Err(QuantumError::Invalid(_))));
2385
2386        // The op-log counts controls in a u8: 256 is too many in either
2387        // gateset, and circuit/1, which allows repeats, takes 255.
2388        for gs in Gateset::ALL {
2389            let mut c = Circuit::with_gateset(2, gs);
2390            c.push(BaseGate::X, vec![0; 256], 1, 0);
2391            assert!(matches!(c.validate(), Err(QuantumError::Invalid(_))), "{gs:?}");
2392        }
2393        let mut c = Circuit::with_gateset(2, Gateset::V1);
2394        c.push(BaseGate::X, vec![0; 255], 1, 0);
2395        assert_eq!(c.validate(), Ok(()));
2396    }
2397
2398    /// A circuit carries its gateset, and a circuit compares unequal to the same
2399    /// ops in the other one.
2400    #[test]
2401    fn circuits_carry_their_gateset() {
2402        assert_eq!(Circuit::new(3).gateset, Gateset::V2);
2403        assert_eq!(Circuit::qft(3).gateset, Gateset::V2);
2404        for gs in Gateset::ALL {
2405            let mut c = Circuit::with_gateset(3, gs);
2406            assert_eq!((c.n_qubits, c.gateset), (3, gs));
2407            c.h(0).cx(0, 1);
2408            let e = c.empty_like();
2409            assert_eq!((e.n_qubits, e.gateset, e.ops.len()), (3, gs, 0));
2410        }
2411        let v2 = Circuit::qft(3);
2412        let mut v1 = v2.clone();
2413        v1.gateset = Gateset::V1;
2414        assert_ne!(v1, v2);
2415        assert_ne!(v1.simulate().unwrap(), v2.simulate().unwrap());
2416    }
2417
2418    #[test]
2419    fn error_kinds_name_their_class() {
2420        let cases = [
2421            (QuantumError::Malformed("m".into()), "malformed", "malformed WQC: m"),
2422            (QuantumError::Invalid("i".into()), "invalid", "invalid circuit: i"),
2423            (QuantumError::Contract("c".into()), "contract", "contract mismatch: c"),
2424            (QuantumError::TooManyQubits(27), "too-many-qubits", "too many qubits: 27"),
2425        ];
2426        for (e, kind, shown) in cases {
2427            assert_eq!((e.kind(), e.to_string().as_str()), (kind, shown));
2428        }
2429    }
2430
2431    /// `P(k)` on `|1⟩` lands on the table entry itself, bit for bit, in both
2432    /// gatesets, plain and controlled: `fxmul` by `ONE` is exact.
2433    #[test]
2434    fn phase_is_copied_exactly() {
2435        for gs in Gateset::ALL {
2436            for k in 1..=DYADIC_MAX as u16 {
2437                let mut c = Circuit::with_gateset(1, gs);
2438                c.x(0).p(k, 0);
2439                assert_eq!(c.simulate().unwrap().amps, [Amp::ZERO, gs.phase(k.into())], "{gs:?} P({k})");
2440                let mut c = Circuit::with_gateset(2, gs);
2441                c.x(0).x(1).cp(k, 0, 1);
2442                let amps = c.simulate().unwrap().amps;
2443                assert_eq!(amps[0b11], gs.phase(k.into()), "{gs:?} CP({k})");
2444                assert!(amps[..0b11].iter().all(|a| *a == Amp::ZERO), "{gs:?} CP({k})");
2445            }
2446        }
2447    }
2448
2449    /// A small phase applied many times. `P(19)` applied 2^18 times to `|1⟩` is
2450    /// a rotation by π. circuit2 gets there. circuit/1's `P(19)` is
2451    /// `(2^30 − 1, 0)`: it never rotates, and each application loses one unit.
2452    #[test]
2453    fn repeated_small_phase() {
2454        let reps = 1usize << 18;
2455        let run = |gs| {
2456            let mut c = Circuit::with_gateset(1, gs);
2457            c.x(0);
2458            c.ops.extend(std::iter::repeat_n(Gate { base: BaseGate::P, controls: vec![], target: 0, param: 19 }, reps));
2459            let amps = c.simulate().unwrap().amps;
2460            assert_eq!(amps[0], Amp::ZERO);
2461            amps[1]
2462        };
2463        assert_eq!(run(Gateset::V1), Amp { re: 1_073_479_680, im: 0 });
2464        assert_eq!(run(Gateset::V1).re, ONE - reps as i64);
2465        let v2 = run(Gateset::V2);
2466        let angle = (v2.im as f64).atan2(v2.re as f64);
2467        assert!((angle.abs() - std::f64::consts::PI).abs() < 1e-4, "circuit2 turned {angle} rad, not π");
2468        // The norm drifts as slowly as the rounding allows (1.0000189 here).
2469        let norm = (v2.norm2() as f64).sqrt() / ONE as f64;
2470        assert!((norm - 1.0).abs() < 1e-4, "|amp| = {norm}");
2471    }
2472
2473    /// circuit2 is strict where circuit/1 is not: a repeated control and a
2474    /// parameter on a gate that takes none are circuit/1 circuits, and are not
2475    /// circuit2 ones.
2476    #[test]
2477    fn v2_rejects_what_v1_tolerates() {
2478        let use_gate = |gs, n, g: Gate| {
2479            let mut c = Circuit::with_gateset(n, gs);
2480            c.ops.push(g);
2481            c
2482        };
2483        let mut lax = vec![Gate { base: BaseGate::X, controls: vec![0, 0], target: 1, param: 0 }];
2484        for base in [BaseGate::I, BaseGate::X, BaseGate::Y, BaseGate::Z, BaseGate::H, BaseGate::S, BaseGate::Sdg, BaseGate::T, BaseGate::Tdg] {
2485            lax.push(Gate { base, controls: vec![], target: 0, param: 1 });
2486        }
2487        lax.push(Gate { base: BaseGate::H, controls: vec![], target: 0, param: u16::MAX });
2488        for g in lax {
2489            let v1 = use_gate(Gateset::V1, 2, g.clone());
2490            assert_eq!(v1.validate(), Ok(()), "{g:?}");
2491            assert!(v1.simulate().is_ok(), "{g:?}");
2492            let v2 = use_gate(Gateset::V2, 2, g.clone());
2493            let e = v2.validate().unwrap_err();
2494            assert_eq!(e.kind(), "invalid", "{g:?}");
2495            assert_eq!(v2.simulate().unwrap_err(), e, "{g:?}");
2496        }
2497        // The parameter rule spares P, whose parameter is its k.
2498        let mut p = Circuit::new(1);
2499        p.p(5, 0);
2500        assert_eq!(p.validate(), Ok(()));
2501        // Distinct controls: 254 on 255 qubits is the most circuit2 can hold.
2502        let all: Vec<u8> = (0..254).collect();
2503        assert_eq!(use_gate(Gateset::V2, 255, Gate { base: BaseGate::X, controls: all.clone(), target: 254, param: 0 }).validate(), Ok(()));
2504        let mut repeat = all.clone();
2505        repeat.push(253);
2506        let g = Gate { base: BaseGate::X, controls: repeat, target: 254, param: 0 };
2507        assert_eq!(use_gate(Gateset::V1, 255, g.clone()).validate(), Ok(()));
2508        assert!(matches!(use_gate(Gateset::V2, 255, g).validate(), Err(QuantumError::Invalid(_))));
2509    }
2510
2511    /// Accuracy against the ideal, by floating-point references whose phases
2512    /// come from the crate's own `sin_cos`, compiled under these features, all
2513    /// of which `full` enables.
2514    #[cfg(any(
2515        feature = "quantum_spd",
2516        feature = "quantum_pauli",
2517        feature = "quantum_mps",
2518        feature = "quantum_vml",
2519        feature = "quantum_phasor",
2520        feature = "quantum_kernel",
2521        feature = "quantum_tn",
2522        feature = "quantum_sv",
2523        feature = "quantum_tdvp",
2524        feature = "quantum_nqs"
2525    ))]
2526    mod against_ideal {
2527        use super::*;
2528
2529        type C = (f64, f64);
2530
2531        fn cmul(a: C, b: C) -> C {
2532            (a.0 * b.0 - a.1 * b.1, a.0 * b.1 + a.1 * b.0)
2533        }
2534
2535        fn cadd(a: C, b: C) -> C {
2536            (a.0 + b.0, a.1 + b.1)
2537        }
2538
2539        /// `e^{2πi/2^k}`.
2540        fn root(k: u16) -> C {
2541            let (s, c) = crate::repro::sin_cos(std::f64::consts::TAU / (1u64 << k) as f64);
2542            (c, s)
2543        }
2544
2545        /// The ideal matrix of a base gate.
2546        fn matrix(base: BaseGate, param: u16) -> [[C; 2]; 2] {
2547            let (z, one, i, neg_i) = ((0.0, 0.0), (1.0, 0.0), (0.0, 1.0), (0.0, -1.0));
2548            let h = std::f64::consts::FRAC_1_SQRT_2;
2549            let t = root(3);
2550            match base {
2551                BaseGate::I => [[one, z], [z, one]],
2552                BaseGate::X => [[z, one], [one, z]],
2553                BaseGate::Y => [[z, neg_i], [i, z]],
2554                BaseGate::Z => [[one, z], [z, (-1.0, 0.0)]],
2555                BaseGate::H => [[(h, 0.0), (h, 0.0)], [(h, 0.0), (-h, 0.0)]],
2556                BaseGate::S => [[one, z], [z, i]],
2557                BaseGate::Sdg => [[one, z], [z, neg_i]],
2558                BaseGate::T => [[one, z], [z, t]],
2559                BaseGate::Tdg => [[one, z], [z, (t.0, -t.1)]],
2560                BaseGate::P => [[one, z], [z, root(param)]],
2561            }
2562        }
2563
2564        /// The circuit's ideal state from `|0…0⟩`, gate by gate.
2565        fn simulate(c: &Circuit) -> Vec<C> {
2566            let dim = 1usize << c.n_qubits;
2567            let mut a = vec![(0.0, 0.0); dim];
2568            a[0] = (1.0, 0.0);
2569            for g in &c.ops {
2570                let m = matrix(g.base, g.param);
2571                let tbit = 1usize << g.target;
2572                let mask = g.controls.iter().fold(0usize, |acc, &q| acc | (1usize << q));
2573                for i in 0..dim {
2574                    if i & tbit == 0 && i & mask == mask {
2575                        let j = i | tbit;
2576                        let (a0, a1) = (a[i], a[j]);
2577                        a[i] = cadd(cmul(m[0][0], a0), cmul(m[0][1], a1));
2578                        a[j] = cadd(cmul(m[1][0], a0), cmul(m[1][1], a1));
2579                    }
2580                }
2581            }
2582            a
2583        }
2584
2585        /// QFT-14 of `|1…1⟩`, whose ladder multiplies nonzero amplitudes by every
2586        /// `P(2..=14)`. circuit2 stays within 3 units of the ideal amplitude
2587        /// (2.0 measured); circuit/1 is off by more than 8 (14.4 measured).
2588        #[test]
2589        fn qft14_accuracy() {
2590            let n = 14u8;
2591            let mut c = Circuit::new(n);
2592            for q in 0..n {
2593                c.x(q);
2594            }
2595            c.ops.extend(Circuit::qft(n).ops);
2596            let want = simulate(&c);
2597            let error = |gs| {
2598                let mut c = c.clone();
2599                c.gateset = gs;
2600                let one = ONE as f64;
2601                c.simulate()
2602                    .unwrap()
2603                    .amps
2604                    .iter()
2605                    .zip(&want)
2606                    .map(|(a, w)| {
2607                        let (dre, dim) = (a.re as f64 - w.0 * one, a.im as f64 - w.1 * one);
2608                        (dre * dre + dim * dim).sqrt()
2609                    })
2610                    .fold(0.0f64, f64::max)
2611            };
2612            let (v2, v1) = (error(Gateset::V2), error(Gateset::V1));
2613            assert!(v2 <= 3.0, "circuit2 QFT-14 is {v2} units from the ideal");
2614            assert!(v1 > 8.0, "circuit/1 QFT-14 is only {v1} units from the ideal");
2615        }
2616
2617        /// One circuit2 gate on a normalised pair moves each component at most
2618        /// 2 units from the ideal (1.43 measured): ½ unit per table entry and ½
2619        /// per rounded product. `H`, `T`, `T†` and every `P(k)`, 400 seeded pairs
2620        /// each, through the simulator's own `apply`. circuit/1 fails the same
2621        /// check.
2622        #[test]
2623        fn one_v2_gate_is_within_two_units() {
2624            let mut gates = vec![(BaseGate::H, 0u16), (BaseGate::T, 0), (BaseGate::Tdg, 0)];
2625            gates.extend((1..=DYADIC_MAX as u16).map(|k| (BaseGate::P, k)));
2626            let worst = |gs| {
2627                let mut s = 0x5EED_0000_0000_0008u64;
2628                let mut uniform = || (splitmix64(&mut s) >> 11) as f64 / (1u64 << 53) as f64 * 2.0 - 1.0;
2629                let one = ONE as f64;
2630                let mut worst = 0.0f64;
2631                for &(base, param) in &gates {
2632                    let m = matrix(base, param);
2633                    for _ in 0..400 {
2634                        let z = [uniform(), uniform(), uniform(), uniform()];
2635                        let norm = z.iter().map(|x| x * x).sum::<f64>().sqrt();
2636                        let fixed = |x: f64| (x / norm * one) as i64;
2637                        let a = [Amp { re: fixed(z[0]), im: fixed(z[1]) }, Amp { re: fixed(z[2]), im: fixed(z[3]) }];
2638                        let mut got = a;
2639                        apply(&mut got, 1, &Gate { base, controls: vec![], target: 0, param }, gs);
2640                        let af = a.map(|x| (x.re as f64 / one, x.im as f64 / one));
2641                        for r in 0..2 {
2642                            let w = cadd(cmul(m[r][0], af[0]), cmul(m[r][1], af[1]));
2643                            worst = worst.max((got[r].re as f64 - w.0 * one).abs()).max((got[r].im as f64 - w.1 * one).abs());
2644                        }
2645                    }
2646                }
2647                worst
2648            };
2649            assert_eq!(gates.len() * 400, 14_000);
2650            let v2 = worst(Gateset::V2);
2651            assert!(v2 <= 2.0, "a circuit2 gate is {v2} units from the ideal");
2652            let v1 = worst(Gateset::V1);
2653            assert!(v1 > 2.0, "the check passed circuit/1: {v1}");
2654        }
2655    }
2656}