pub fn adaptive_simpson<F: Fn(f64) -> f64>(
f: &F,
a: f64,
b: f64,
tol: f64,
max_depth: usize,
) -> f64 {
let mid = 0.5 * (a + b);
let whole = simpson_rule(f, a, b);
let left = simpson_rule(f, a, mid);
let right = simpson_rule(f, mid, b);
adaptive_step(f, a, b, tol, whole, left, right, max_depth)
}
fn simpson_rule<F: Fn(f64) -> f64>(f: &F, a: f64, b: f64) -> f64 {
let h = b - a;
(h / 6.0) * (f(a) + 4.0 * f(0.5 * (a + b)) + f(b))
}
fn adaptive_step<F: Fn(f64) -> f64>(
f: &F,
a: f64,
b: f64,
tol: f64,
whole: f64,
left: f64,
right: f64,
depth: usize,
) -> f64 {
let sum = left + right;
let err = (sum - whole) / 15.0;
if depth == 0 || err.abs() < tol {
return sum + err; }
let mid = 0.5 * (a + b);
let half_tol = 0.5 * tol;
let ml = 0.5 * (a + mid);
let mr = 0.5 * (mid + b);
let left_left = simpson_rule(f, a, ml);
let left_right = simpson_rule(f, ml, mid);
let right_left = simpson_rule(f, mid, mr);
let right_right = simpson_rule(f, mr, b);
adaptive_step(f, a, mid, half_tol, left, left_left, left_right, depth - 1)
+ adaptive_step(
f,
mid,
b,
half_tol,
right,
right_left,
right_right,
depth - 1,
)
}
pub fn conditional_mean_gap<F: Fn(f64) -> f64>(
mu: f64,
kernel_integrated_intensity: F,
tol: f64,
) -> f64 {
if mu <= 0.0 || !mu.is_finite() {
return f64::INFINITY;
}
let x_max = 40.0_f64;
let inv_mu = 1.0 / mu;
let integrand = |x: f64| -> f64 {
let s = x * inv_mu;
let k = kernel_integrated_intensity(s);
(-x - k).exp()
};
inv_mu * adaptive_simpson(&integrand, 0.0, x_max, tol, 20)
}