pub fn autocorr_ess(x: &[f64]) -> f64 {
let n = x.len();
if n <= 1 {
return n as f64;
}
let mean = x.iter().sum::<f64>() / n as f64;
let var = x.iter().map(|v| (v - mean) * (v - mean)).sum::<f64>() / n as f64;
if var <= 0.0 {
return n as f64;
}
let lag_cap = (n as f64).sqrt() as usize;
let mut rho_sum = 0.0;
for lag in 1..=lag_cap.max(1).min(n - 1) {
let mut cov = 0.0;
for i in lag..n {
cov += (x[i] - mean) * (x[i - lag] - mean);
}
cov /= (n - lag) as f64;
let rho = cov / var;
if rho <= 0.0 || !rho.is_finite() {
break;
}
rho_sum += rho;
}
(n as f64 / (1.0 + 2.0 * rho_sum)).max(1.0)
}
pub fn newey_west_se(x: &[f64]) -> f64 {
let n = x.len();
if n <= 1 {
return f64::INFINITY;
}
let mean = x.iter().sum::<f64>() / n as f64;
let lag_cap = (n as f64).sqrt() as usize;
let mut gamma0 = 0.0;
for v in x {
gamma0 += (v - mean) * (v - mean);
}
gamma0 /= n as f64;
let mut var = gamma0;
for lag in 1..=lag_cap.max(1).min(n - 1) {
let mut gamma = 0.0;
for i in lag..n {
gamma += (x[i] - mean) * (x[i - lag] - mean);
}
gamma /= n as f64;
let w = 1.0 - lag as f64 / (lag_cap as f64 + 1.0);
var += 2.0 * w * gamma;
}
(var.max(0.0) / n as f64).sqrt()
}