//! Axis 3 — the Information Coefficient as a pure library call //! (`aura_measurement::information_coefficient`), including its permutation-null //! deflation (the returned `overfit_probability`). No data archive, no `aura` //! binary: just two in-memory (timestamp, value) series a downstream measurement //! World program would hold. Runs an *informed* signal (correlated with the //! forward return) against a *noise* signal to show the deflation discriminates. use aura_core::Timestamp; use aura_measurement::information_coefficient; const N: usize = 400; const HORIZON: usize = 1; const PERMUTATIONS: usize = 500; const SEED: u64 = 12_345; // A tiny deterministic LCG so the fixture is reproducible without an rng dep. struct Lcg(u64); impl Lcg { fn next_unit(&mut self) -> f64 { self.0 = self.0.wrapping_mul(6_364_136_223_846_793_005).wrapping_add(1_442_695_040_888_963_407); // top 53 bits -> [0,1) ((self.0 >> 11) as f64) / ((1u64 << 53) as f64) } fn next_signed(&mut self) -> f64 { self.next_unit() * 2.0 - 1.0 } } fn main() { let mut rng = Lcg(0x1234_5678_9abc_def0); // A random-walk price and its forward one-step return. let mut price = Vec::with_capacity(N); let mut level = 100.0f64; for _ in 0..N { level += rng.next_signed(); price.push(level); } let price_series: Vec<(Timestamp, f64)> = price.iter().enumerate().map(|(i, &p)| (Timestamp(i as i64 * 60_000), p)).collect(); // Informed signal: the forward return plus noise (so it genuinely forecasts). let mut informed = Vec::with_capacity(N); for i in 0..N { let fwd = if i + HORIZON < N { price[i + HORIZON] - price[i] } else { 0.0 }; informed.push(fwd + 0.5 * rng.next_signed()); } let informed_series: Vec<(Timestamp, f64)> = informed.iter().enumerate().map(|(i, &s)| (Timestamp(i as i64 * 60_000), s)).collect(); // Noise signal: uncorrelated with the forward return. let noise_series: Vec<(Timestamp, f64)> = (0..N).map(|i| (Timestamp(i as i64 * 60_000), rng.next_signed())).collect(); let informed_ic = information_coefficient(&informed_series, &price_series, HORIZON, PERMUTATIONS, SEED); let noise_ic = information_coefficient(&noise_series, &price_series, HORIZON, PERMUTATIONS, SEED); println!("informed signal:"); println!(" information_coefficient = {:.4}", informed_ic.information_coefficient); println!(" overfit_probability = {:.4}", informed_ic.overfit_probability); println!(" n_pairs = {}", informed_ic.n_pairs); println!("noise signal:"); println!(" information_coefficient = {:.4}", noise_ic.information_coefficient); println!(" overfit_probability = {:.4}", noise_ic.overfit_probability); println!(" n_pairs = {}", noise_ic.n_pairs); // Determinism check (C1/C18 for a measurement): same inputs -> same bytes. let again = information_coefficient(&informed_series, &price_series, HORIZON, PERMUTATIONS, SEED); let deterministic = again.information_coefficient == informed_ic.information_coefficient && again.overfit_probability == informed_ic.overfit_probability; println!("deterministic re-run identical: {deterministic}"); }