use std::f64::consts::{PI, SQRT_2};
pub const CHSH_CLASSICAL_BOUND: f64 = 2.0;
pub const CHSH_TSIRELSON_BOUND: f64 = 2.0 * SQRT_2;
pub const CHSH_DETECTION_THRESHOLD: f64 = 2.0 / (SQRT_2 + 1.0);
#[derive(Debug, Clone)]
pub struct ChshTest {
pub settings: [[f64; 2]; 2],
pub correlations: [[f64; 2]; 2],
}
impl ChshTest {
pub fn optimal_settings() -> Self {
let a = 0.0_f64;
let a2 = 45.0_f64;
let b = 22.5_f64;
let b2 = 67.5_f64;
let e = |alpha: f64, beta: f64| -> f64 { Self::quantum_correlation(alpha - beta) };
Self {
settings: [[a, a2], [b, b2]],
correlations: [[e(a, b), e(a, b2)], [e(a2, b), e(a2, b2)]],
}
}
pub fn from_correlations(e_ab: f64, e_ab2: f64, e_a2b: f64, e_a2b2: f64) -> Self {
Self {
settings: [[0.0, 45.0], [22.5, -22.5]],
correlations: [[e_ab, e_ab2], [e_a2b, e_a2b2]],
}
}
pub fn s_parameter(&self) -> f64 {
let e_ab = self.correlations[0][0];
let e_ab2 = self.correlations[0][1];
let e_a2b = self.correlations[1][0];
let e_a2b2 = self.correlations[1][1];
e_ab - e_ab2 + e_a2b + e_a2b2
}
pub fn violates_classical(&self) -> bool {
self.s_parameter().abs() > CHSH_CLASSICAL_BOUND
}
pub fn violation_sigmas(&self, n_measurements: usize) -> f64 {
if n_measurements == 0 {
return 0.0;
}
let sigma_s = 4.0 / (n_measurements as f64).sqrt();
let excess = self.s_parameter().abs() - CHSH_CLASSICAL_BOUND;
if sigma_s > 0.0 {
excess / sigma_s
} else {
0.0
}
}
pub fn quantum_correlation(angle_deg: f64) -> f64 {
let theta = angle_deg * PI / 180.0;
-(2.0 * theta).cos()
}
pub fn optimal_angles_for_state(fidelity: f64) -> [f64; 4] {
let _ = fidelity; [0.0, 45.0, 22.5, -22.5]
}
pub fn expected_s_for_fidelity(fidelity: f64) -> f64 {
CHSH_TSIRELSON_BOUND * fidelity.clamp(0.0, 1.0)
}
}
#[derive(Debug, Clone)]
pub struct ChTest {
pub n_coinc: [[f64; 2]; 2],
pub n_single_a: [f64; 2],
pub n_single_b: [f64; 2],
pub n_accidental: f64,
}
impl ChTest {
pub fn new(coinc: [[f64; 2]; 2], sing_a: [f64; 2], sing_b: [f64; 2]) -> Self {
Self {
n_coinc: coinc,
n_single_a: sing_a,
n_single_b: sing_b,
n_accidental: 0.0,
}
}
fn joint_prob(&self, i: usize, j: usize) -> f64 {
let n_a = self.n_single_a[i];
let n_b = self.n_single_b[j];
let denom = (n_a * n_b).max(1.0);
(self.n_coinc[i][j] - self.n_accidental).max(0.0) / denom
}
fn marginal_a(&self) -> f64 {
let max_s: f64 = self
.n_single_a
.iter()
.cloned()
.fold(f64::NEG_INFINITY, f64::max);
self.n_single_a[0] / max_s.max(1.0)
}
fn marginal_b(&self) -> f64 {
let max_s: f64 = self
.n_single_b
.iter()
.cloned()
.fold(f64::NEG_INFINITY, f64::max);
self.n_single_b[0] / max_s.max(1.0)
}
pub fn ch_parameter(&self) -> f64 {
self.joint_prob(0, 0) + self.joint_prob(0, 1) + self.joint_prob(1, 0)
- self.joint_prob(1, 1)
- self.marginal_a()
- self.marginal_b()
}
pub fn violates_classical(&self) -> bool {
self.ch_parameter() > 0.0
}
pub fn detection_efficiency_threshold(&self) -> f64 {
CHSH_DETECTION_THRESHOLD
}
pub fn effective_efficiency(&self) -> f64 {
let coinc = self.n_coinc[0][0].max(0.0);
let na = self.n_single_a[0];
let nb = self.n_single_b[0];
let denom = na + nb;
if denom > 0.0 {
2.0 * coinc / denom
} else {
0.0
}
}
}
#[derive(Debug, Clone)]
pub struct MerminTest {
pub n_parties: usize,
pub correlations: Vec<f64>,
}
impl MerminTest {
pub fn new_ghz() -> Self {
Self {
n_parties: 3,
correlations: vec![1.0, 1.0, 1.0, -1.0],
}
}
pub fn mermin_parameter(&self) -> f64 {
if self.correlations.len() < 4 {
return 0.0;
}
self.correlations[0] + self.correlations[1] + self.correlations[2] - self.correlations[3]
}
pub fn classical_bound(&self) -> f64 {
match self.n_parties {
3 => 2.0,
n => 2.0_f64.powi((n as i32) / 2), }
}
pub fn quantum_maximum(&self) -> f64 {
match self.n_parties {
3 => 4.0,
n => 2.0_f64.powi(((n + 1) as i32) / 2),
}
}
pub fn violation_ratio(&self) -> f64 {
self.mermin_parameter().abs() / self.classical_bound().max(1e-30)
}
pub fn violates_classical(&self) -> bool {
self.mermin_parameter().abs() > self.classical_bound()
}
}
#[derive(Debug, Clone)]
pub struct LoopholeFreeAnalysis {
pub detection_efficiency: f64,
pub locality_loophole_closed: bool,
pub freedom_of_choice: bool,
pub fair_sampling: bool,
}
impl LoopholeFreeAnalysis {
pub fn new(efficiency: f64) -> Self {
Self {
detection_efficiency: efficiency.clamp(0.0, 1.0),
locality_loophole_closed: false,
freedom_of_choice: false,
fair_sampling: false,
}
}
pub fn all_loopholes_closed(&self) -> bool {
let detection_closed = self.detection_efficiency >= self.required_efficiency();
detection_closed && self.locality_loophole_closed && self.freedom_of_choice
}
pub fn required_efficiency(&self) -> f64 {
CHSH_DETECTION_THRESHOLD
}
pub fn p_value(&self, s_param: f64, n_trials: usize) -> f64 {
if n_trials == 0 {
return 1.0;
}
let excess = s_param.abs() - CHSH_CLASSICAL_BOUND;
if excess <= 0.0 {
return 1.0; }
let exponent = -(n_trials as f64) * excess.powi(2) / 8.0;
exponent.exp().clamp(0.0, 1.0)
}
pub fn required_separation_km(coincidence_window_ns: f64) -> f64 {
let c = 3e8_f64; c * coincidence_window_ns * 1e-9 / 2.0 / 1e3 }
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_chsh_optimal_settings_tsirelson() {
let chsh = ChshTest::optimal_settings();
let s = chsh.s_parameter();
assert!(
(s.abs() - CHSH_TSIRELSON_BOUND).abs() < 1e-6,
"Optimal CHSH S should equal Tsirelson bound, got {s}"
);
}
#[test]
fn test_chsh_violates_classical() {
let chsh = ChshTest::optimal_settings();
assert!(
chsh.violates_classical(),
"Optimal CHSH settings should violate classical bound"
);
}
#[test]
fn test_chsh_no_violation() {
let chsh = ChshTest::from_correlations(0.5, 0.5, 0.5, 0.5);
let s = chsh.s_parameter();
assert!(
!chsh.violates_classical(),
"S={s} should not violate classical bound"
);
}
#[test]
fn test_chsh_quantum_correlation() {
let e0 = ChshTest::quantum_correlation(0.0);
assert!((e0 + 1.0).abs() < 1e-10, "E(0°) = -1");
let e45 = ChshTest::quantum_correlation(45.0);
assert!(e45.abs() < 1e-10, "E(45°) = 0");
let e225 = ChshTest::quantum_correlation(22.5);
assert!(
(e225 + 1.0 / std::f64::consts::SQRT_2).abs() < 1e-10,
"E(22.5°) = -1/√2"
);
}
#[test]
fn test_ch_efficiency_threshold() {
let ch = ChTest::new(
[[100.0, 80.0], [90.0, 85.0]],
[200.0, 195.0],
[200.0, 200.0],
);
let threshold = ch.detection_efficiency_threshold();
assert!(
(threshold - CHSH_DETECTION_THRESHOLD).abs() < 1e-6,
"Detection threshold = 2/(√2+1)"
);
}
#[test]
fn test_mermin_ghz_violation() {
let mermin = MerminTest::new_ghz();
assert_eq!(mermin.n_parties, 3);
let m = mermin.mermin_parameter();
assert!((m - 4.0).abs() < 1e-9, "GHZ Mermin parameter = 4, got {m}");
assert!(
mermin.violates_classical(),
"GHZ state should violate Mermin inequality"
);
let ratio = mermin.violation_ratio();
assert!((ratio - 2.0).abs() < 1e-9, "Violation ratio = 2 for GHZ");
}
#[test]
fn test_loophole_free_p_value() {
let analysis = LoopholeFreeAnalysis::new(0.90);
let p = analysis.p_value(CHSH_TSIRELSON_BOUND, 1_000_000);
assert!(
p < 1e-10,
"p-value for 10^6 trials and Tsirelson bound should be tiny, got {p}"
);
}
#[test]
fn test_loophole_free_detection_threshold() {
let mut analysis = LoopholeFreeAnalysis::new(0.90);
analysis.locality_loophole_closed = true;
analysis.freedom_of_choice = true;
assert!(
analysis.all_loopholes_closed(),
"90% efficiency should close detection loophole"
);
let analysis_low = LoopholeFreeAnalysis::new(0.70);
assert!(
!analysis_low.all_loopholes_closed(),
"70% efficiency is below threshold"
);
}
#[test]
fn test_chsh_violation_sigmas() {
let chsh = ChshTest::optimal_settings();
let sigmas = chsh.violation_sigmas(10_000);
assert!(sigmas > 10.0, "Should be highly significant, got {sigmas}σ");
}
}