open-standards/wai/wai-quantum/src/quantum_phasor.rs
Transaction Science e531c2ddd7
Some checks failed
no-vanity-metrics / Scan committed Markdown for vanity metrics (push) Successful in 3s
standards workspaces build + test / aac-rs (push) Successful in 37s
standards workspaces build + test / joule-code-rs (push) Successful in 42s
standards workspaces build + test / eoc-rs (push) Successful in 1m47s
standards workspaces build + test / jcp-rs (push) Successful in 1m14s
standards workspaces build + test / proof-rs (push) Successful in 1m9s
standards workspaces build + test / jouleclaw-rs (push) Successful in 4m6s
standards workspaces build + test / joulecontract-rs (push) Successful in 38s
standards workspaces build + test / sandbox-rs (push) Successful in 2m1s
standards workspaces build + test / map-rs (push) Successful in 36s
standards workspaces build + test / mesh-rs (push) Successful in 34s
standards workspaces build + test / openpay (push) Successful in 1m23s
standards workspaces build + test / smart-byte-rs (push) Successful in 2m28s
WAI conformance / cargo-class corpora · linux-arm64 (push) Successful in 33s
WAI conformance / cargo-class corpora · linux (push) Successful in 28s
WAI conformance / cross-arch byte-equality · linux-arm64 (push) Successful in 17s
WAI conformance / cross-arch byte-equality · linux (push) Successful in 14s
standards workspaces build + test / arl-rs (push) Successful in 8m41s
standards workspaces build + test / joule-ui-rs (push) Successful in 7m56s
standards workspaces build + test / jouledesk-rs (push) Successful in 8m24s
standards workspaces build + test / joulehook-rs (push) Successful in 8m34s
standards workspaces build + test / sense-rs (push) Successful in 7m58s
WAI conformance / cargo-class corpora · macos (push) Successful in 1m4s
WAI conformance / cross-arch byte-equality · macos (push) Successful in 23s
WAI conformance / cargo-class corpora · windows (push) Has been cancelled
WAI conformance / cross-arch byte-equality · windows (push) Has been cancelled
wai: extract the quantum stack into a standalone wai-quantum crate
crates.io publish was blocked: the name `wai` is taken (an unrelated 2017 crate),
and `default = ["codecs"]` would make `cargo add` pull libjxl/libavif/opus/FLAC/
rav1e/dav1d system libraries — so most builds would fail for someone who only
wants quantum. Extracting the quantum stack solves both.

`wai-quantum` is dependency-light and pure Rust (blake3 + serde_json, with
ed25519-dalek only for the sealing features). No system libraries, so it builds
everywhere the stack already runs: native, browser wasm, and wasm32-wasip2.

The split follows the seam that was already there — 12,975 lines moved with only
four coupling points:
- `world:🧾:merkle_root` (used by 3 modules) is reproduced verbatim in
  `wai-quantum::merkle`, domain separators included, so every previously issued
  receipt and published conformance vector still verifies;
- `wrap_envelope` is a WAI-envelope concern, not a quantum one, so it stays in
  `wai` as `quantum_envelope` (it had no external callers).

`wai` keeps every quantum feature name and re-exports the modules unchanged, so
wai-web, wai-quantum-serve and the deployed site build without edits. Also
re-exports `ed25519_dalek` from wai-quantum: the sealing API takes a `SigningKey`,
and a consumer picking their own version could get an incompatible one.

Verified the extraction is observably a no-op — identical to the values recorded
before it:
  ghz -n 5      circuit-id 355d1166…  state-hash 0b5f4201…
  grover -n 4 -p 9            state-hash 25a7d930…
  receipt JSON sha256         117ff588…
208 tests pass (173 wai-quantum + 35 wai); wai-web and the WASI-HTTP component
build unchanged, and the edge endpoint still returns the identical hash.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-09-03 15:29:50 -04:00

234 lines
8.9 KiB
Rust
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! The phasor bridge — same interference, two substrates (`wai.quantum.phasor`).
//!
//! Schuld, Sweke & Meyer (2020) proved that a quantum model with data encoded by
//! Pauli-rotation gates is *exactly* a truncated Fourier series of phasors:
//!
//! ```text
//! f(x) = ⟨0| U†(x) M U(x) |0⟩ = Σ_{ω ∈ Ω} c_ω · e^{iωx}
//! ```
//!
//! where the encoding fixes the frequency set `Ω` and the trainable gates fix the
//! complex coefficients `c_ω`. That is the whole bridge: a **quantum feature map is
//! a phasor bank**, and phasor binding (complex multiplication = phase addition) is
//! *interference*. So the identical function can be computed two ways — on a
//! **quantum state vector**, or by a **classical phasor sum** (the FHRR / HDC
//! algebra) — and where the spectrum is compact (the common case, per the
//! dequantization theorems) the classical phasor substrate reproduces it with none
//! of the qubits. The **quantized-phase** variant is qFHRR: the same phasors at a
//! few bits of phase, the cheapest deployable realization of what the circuit
//! computes.
//!
//! This module builds a single-qubit **data-reuploading** model, extracts its
//! Fourier spectrum, and shows the phasor sum reproduces it exactly — the quantum
//! end and the deployable end computing one interference function. Deterministic
//! f64.
use std::f64::consts::PI;
#[derive(Clone, Copy)]
struct C {
re: f64,
im: f64,
}
impl C {
#[inline]
fn new(re: f64, im: f64) -> C {
C { re, im }
}
#[inline]
fn mul(self, o: C) -> C {
C { re: self.re * o.re - self.im * o.im, im: self.re * o.im + self.im * o.re }
}
#[inline]
fn add(self, o: C) -> C {
C { re: self.re + o.re, im: self.im + o.im }
}
}
#[inline]
fn expi(t: f64) -> C {
C::new(t.cos(), t.sin())
}
// ---------------------------------------------------------------------------
// The quantum model: single-qubit data reuploading ⟨Z⟩ = f(x)
// ---------------------------------------------------------------------------
/// Trainable block `W = RZ(φ)·RY(θ)` applied to a single-qubit amplitude pair.
fn apply_w(a: &mut [C; 2], theta: f64, phi: f64) {
// RY(θ)
let (c, s) = ((theta * 0.5).cos(), (theta * 0.5).sin());
let (a0, a1) = (a[0], a[1]);
let r0 = C::new(a0.re * c - a1.re * s, a0.im * c - a1.im * s);
let r1 = C::new(a0.re * s + a1.re * c, a0.im * s + a1.im * c);
// RZ(φ)
a[0] = r0.mul(expi(-phi * 0.5));
a[1] = r1.mul(expi(phi * 0.5));
}
/// Data-encoding gate `S(x) = RZ(x)` (Pauli-Z generator → integer frequencies).
fn apply_encode(a: &mut [C; 2], x: f64) {
a[0] = a[0].mul(expi(-x * 0.5));
a[1] = a[1].mul(expi(x * 0.5));
}
/// The single-qubit data-reuploading model with `r` encoding repetitions and
/// `params.len() == 2·(r+1)` trainable angles (θ,φ per block): `f(x) = ⟨Z⟩`, a real
/// trig polynomial of degree `r`.
pub fn model_value(x: f64, r: usize, params: &[f64]) -> f64 {
let mut a = [C::new(1.0, 0.0), C::new(0.0, 0.0)];
for i in 0..r {
apply_w(&mut a, params[2 * i], params[2 * i + 1]);
apply_encode(&mut a, x);
}
apply_w(&mut a, params[2 * r], params[2 * r + 1]);
// ⟨Z⟩ = |a0|² − |a1|²
(a[0].re * a[0].re + a[0].im * a[0].im) - (a[1].re * a[1].re + a[1].im * a[1].im)
}
// ---------------------------------------------------------------------------
// Spectrum extraction (the model IS a Fourier series) + phasor evaluation
// ---------------------------------------------------------------------------
/// Extract the Fourier coefficients `c_k` for `k = 0..=r` (the model has spectrum
/// `{−r..r}` with Hermitian symmetry `c_{−k} = c_k*`). Since `f` is a degree-`r`
/// trig polynomial, `2r+1` samples recover it exactly (a DFT).
pub fn spectrum(r: usize, params: &[f64]) -> Vec<(f64, f64)> {
let n = 2 * r + 1;
let samples: Vec<f64> = (0..n).map(|j| model_value(2.0 * PI * j as f64 / n as f64, r, params)).collect();
(0..=r)
.map(|k| {
let mut acc = C::new(0.0, 0.0);
for (j, &f) in samples.iter().enumerate() {
let ph = -(k as f64) * 2.0 * PI * j as f64 / n as f64;
acc = acc.add(C::new(f, 0.0).mul(expi(ph)));
}
(acc.re / n as f64, acc.im / n as f64)
})
.collect()
}
/// Evaluate the model as a **phasor sum** — the FHRR / HDC form — from its
/// coefficients: `f(x) = c_0 + 2·Σ_{k≥1} Re(c_k · e^{ikx})`. Pure classical
/// interference (complex phasor addition), no qubits.
pub fn phasor_value(x: f64, coeffs: &[(f64, f64)]) -> f64 {
let mut acc = coeffs[0].0; // c_0 (real)
for (k, &(re, im)) in coeffs.iter().enumerate().skip(1) {
let e = expi(k as f64 * x);
acc += 2.0 * (re * e.re - im * e.im); // 2·Re(c_k e^{ikx})
}
acc
}
/// The **qFHRR** form: the same phasor sum with each phase quantized to `bits`
/// bits (`2^bits` phase levels) — integer-native, the cheapest deployable
/// realization. Approximates [`phasor_value`] with an error bounded by the phase
/// resolution.
pub fn phasor_value_quantized(x: f64, coeffs: &[(f64, f64)], bits: u32) -> f64 {
let levels = (1u64 << bits) as f64;
let quant = |t: f64| -> f64 {
let frac = t / (2.0 * PI);
(frac * levels).round() / levels * 2.0 * PI
};
let mut acc = coeffs[0].0;
for (k, &(re, im)) in coeffs.iter().enumerate().skip(1) {
let e = expi(quant(k as f64 * x));
acc += 2.0 * (re * e.re - im * e.im);
}
acc
}
fn splitmix64(s: &mut u64) -> u64 {
*s = s.wrapping_add(0x9E37_79B9_7F4A_7C15);
let mut z = *s;
z = (z ^ (z >> 30)).wrapping_mul(0xBF58_476D_1CE4_E5B9);
z = (z ^ (z >> 27)).wrapping_mul(0x94D0_49BB_1331_11EB);
z ^ (z >> 31)
}
/// Deterministic random trainable params for a demo model of `r` reuploads.
pub fn random_params(r: usize, seed: u64) -> Vec<f64> {
let mut st = seed.wrapping_mul(0x2545_F491).wrapping_add(1);
(0..2 * (r + 1))
.map(|_| {
let u = (splitmix64(&mut st) >> 11) as f64 / (1u64 << 53) as f64;
(u * 2.0 - 1.0) * PI
})
.collect()
}
/// Sample the quantum model and the (full-precision) phasor model on a grid, plus
/// the max discrepancy — the proof they are one function.
pub fn compare(r: usize, params: &[f64], grid: usize) -> (Vec<f64>, Vec<f64>, Vec<f64>, f64) {
let coeffs = spectrum(r, params);
let mut xs = Vec::with_capacity(grid);
let mut q = Vec::with_capacity(grid);
let mut ph = Vec::with_capacity(grid);
let mut maxerr = 0.0f64;
for j in 0..grid {
let x = 2.0 * PI * j as f64 / grid as f64;
let qv = model_value(x, r, params);
let pv = phasor_value(x, &coeffs);
xs.push(x);
q.push(qv);
ph.push(pv);
maxerr = maxerr.max((qv - pv).abs());
}
(xs, q, ph, maxerr)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn phasor_sum_reproduces_the_quantum_model_exactly() {
// the core claim: the quantum feature map IS its Fourier/phasor series.
for (r, seed) in [(2usize, 1u64), (3, 7), (4, 11), (5, 3)] {
let params = random_params(r, seed);
let (_, _, _, maxerr) = compare(r, &params, 200);
assert!(maxerr < 1e-9, "r={r}: phasor sum must equal the quantum model, err={maxerr}");
}
}
#[test]
fn spectrum_is_compact_and_hermitian_real_output() {
// r reuploads → exactly r+1 stored coeffs (c_0..c_r); the output is real.
let r = 4;
let params = random_params(r, 5);
let coeffs = spectrum(r, &params);
assert_eq!(coeffs.len(), r + 1);
// c_0 is real (imag ~ 0) since f is real
assert!(coeffs[0].1.abs() < 1e-9, "c_0 must be real");
// model output is in [-1, 1] (it's ⟨Z⟩)
for j in 0..50 {
let v = model_value(j as f64 * 0.1, r, &params);
assert!(v <= 1.0 + 1e-9 && v >= -1.0 - 1e-9);
}
}
#[test]
fn qfhrr_quantized_phasors_approximate_with_bounded_error() {
let r = 3;
let params = random_params(r, 9);
let coeffs = spectrum(r, &params);
// more bits → smaller error, monotonically
let err = |bits: u32| {
let mut m = 0.0f64;
for j in 0..400 {
let x = 2.0 * PI * j as f64 / 400.0;
m = m.max((phasor_value(x, &coeffs) - phasor_value_quantized(x, &coeffs, bits)).abs());
}
m
};
let e3 = err(3);
let e6 = err(6);
assert!(e6 < e3, "more phase bits ⇒ smaller error: {e6} < {e3}");
assert!(e3 < 1.0, "even 3-bit qFHRR phases track the model: {e3}");
assert!(err(10) < 0.02, "10-bit qFHRR is essentially exact");
}
#[test]
fn deterministic() {
let a = compare(3, &random_params(3, 42), 64).3;
let b = compare(3, &random_params(3, 42), 64).3;
assert_eq!(a.to_bits(), b.to_bits());
}
}