use crate::Float;
#[derive(Clone, Debug)]
pub struct EstimatorResult<F> {
pub value: F,
pub estimate: F,
pub sample_variance: F,
pub standard_error: F,
pub num_samples: usize,
}
#[derive(Clone, Debug)]
pub struct DivergenceResult<F> {
pub values: Vec<F>,
pub estimate: F,
pub sample_variance: F,
pub standard_error: F,
pub num_samples: usize,
}
pub(crate) struct WelfordAccumulator<F> {
mean: F,
m2: F,
count: usize,
}
impl<F: Float> WelfordAccumulator<F> {
pub(crate) fn new() -> Self {
Self {
mean: F::zero(),
m2: F::zero(),
count: 0,
}
}
pub(crate) fn update(&mut self, sample: F) {
if !sample.is_finite() {
return;
}
self.count += 1;
let k1 = F::from(self.count).unwrap();
let delta = sample - self.mean;
self.mean = self.mean + delta / k1;
let delta2 = sample - self.mean;
self.m2 = self.m2 + delta * delta2;
}
pub(crate) fn contributing(&self) -> usize {
self.count
}
pub(crate) fn into_result(self, value: F) -> EstimatorResult<F> {
let (estimate, sample_variance, standard_error) = self.finalize();
EstimatorResult {
value,
estimate,
sample_variance,
standard_error,
num_samples: self.contributing(),
}
}
pub(crate) fn finalize(&self) -> (F, F, F) {
if self.count == 0 {
return (F::nan(), F::zero(), F::zero());
}
let nf = F::from(self.count).unwrap();
if self.count > 1 {
let var = (self.m2 / (nf - F::one())).max(F::zero());
(self.mean, var, (var / nf).sqrt())
} else {
(self.mean, F::zero(), F::zero())
}
}
}