use ndarray::Array1;
use num_complex::Complex;
use super::FMVol;
use crate::fourier_malliavin::coefficients::convolution_coefficients;
use crate::traits::FloatExt;
impl<T: FloatExt> FMVol<T> {
pub(super) fn resolve_m(&self, m: Option<usize>) -> usize {
m.unwrap_or((self.n_freq as f64).sqrt() as usize)
}
pub(super) fn resolve_m_volvol(&self, m: Option<usize>) -> usize {
m.unwrap_or((self.n_freq as f64).powf(0.4) as usize)
}
pub(super) fn resolve_m_volvol_bc(&self, m: Option<usize>) -> usize {
m.unwrap_or((self.n_freq as f64).powf(0.25).max(2.0) as usize)
}
pub(super) fn compute_bias_correction_constant(&self, big_m: usize) -> T {
let n_f = self.n as f64;
let n_freq_f = self.n_freq as f64;
let m_f = big_m as f64;
let a = 2.0 * n_freq_f / n_f;
let r = a - a.floor();
let eta = if a.abs() > 1e-12 {
r * (1.0 - r) / (2.0 * a * a)
} else {
0.0
};
let k = (m_f * m_f) / (3.0 * n_f) * (1.0 + 2.0 * eta);
T::from_f64_fast(k)
}
pub(super) fn center(&self) -> usize {
self.max_freq
}
pub(super) fn const_(&self) -> T {
T::from_f64_fast(std::f64::consts::TAU) / self.period
}
pub(super) fn vol_coeffs(&self, m: usize) -> Array1<Complex<T>> {
assert!(
self.n_freq + m <= self.max_freq,
"need max_freq ≥ N + M = {} but have {}",
self.n_freq + m,
self.max_freq
);
convolution_coefficients(&self.dx, &self.dx, self.period, self.n_freq, m)
}
}
pub(super) fn fejer_inversion<T: FloatExt>(
coeffs: &Array1<Complex<T>>,
m_freq: usize,
period: T,
tau: &[T],
fejer_denom: T,
) -> Array1<T> {
let const_ = T::from_f64_fast(std::f64::consts::TAU) / period;
let mut result = Array1::<T>::zeros(tau.len());
for (i, &t) in tau.iter().enumerate() {
let mut sum = Complex::<T>::new(T::zero(), T::zero());
for (j, k) in (-(m_freq as i64)..=(m_freq as i64)).enumerate() {
let k_t = T::from_f64_fast(k as f64);
let fejer = T::one() - T::from_usize_(k.unsigned_abs() as usize) / fejer_denom;
let phase = const_ * k_t * t;
sum = sum + coeffs[j] * Complex::new(phase.cos(), phase.sin()) * fejer;
}
result[i] = sum.re;
}
result
}