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())
}
fn apply_w(a: &mut [C; 2], theta: f64, phi: f64) {
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);
a[0] = r0.mul(expi(-phi * 0.5));
a[1] = r1.mul(expi(phi * 0.5));
}
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));
}
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]);
(a[0].re * a[0].re + a[0].im * a[0].im) - (a[1].re * a[1].re + a[1].im * a[1].im)
}
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()
}
pub fn phasor_value(x: f64, coeffs: &[(f64, f64)]) -> f64 {
let mut acc = coeffs[0].0; 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); }
acc
}
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)
}
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()
}
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() {
for (r, seed) in [(2usize, 1u64), (3, 7), (4, 11), (5, 3)] {
let params = random_params(r, seed);
let (_, _, _, maxerr) = compare(r, ¶ms, 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() {
let r = 4;
let params = random_params(r, 5);
let coeffs = spectrum(r, ¶ms);
assert_eq!(coeffs.len(), r + 1);
assert!(coeffs[0].1.abs() < 1e-9, "c_0 must be real");
for j in 0..50 {
let v = model_value(j as f64 * 0.1, r, ¶ms);
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, ¶ms);
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());
}
}