use std::f64;
use std::fmt;
use std::result;
use std::borrow::Borrow;
use super::data::StatData;
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
pub struct SamplingStats<T> {
pub count: usize,
pub min: T,
pub max: T,
pub mean: f64,
pub mean2: f64
}
impl<T> SamplingStats<T> where T: Copy + PartialOrd + StatData {
#[inline]
pub fn from_sample(sample: T) -> Self {
let x: f64 = <T as StatData>::into_f64(sample);
SamplingStats {
count: 1,
min: sample,
max: sample,
mean: x,
mean2: x * x
}
}
#[inline]
pub fn from_samples<I, Q>(samples: I) -> Self
where I: IntoIterator<Item = Q>,
Q: Borrow<T>
{
samples.into_iter().fold(Self::empty(), |acc, x| acc.add(*x.borrow()))
}
#[inline]
pub fn empty() -> Self {
SamplingStats {
count: 0,
min: <T as StatData>::max(),
max: <T as StatData>::min(),
mean: f64::NAN,
mean2: f64::NAN
}
}
pub fn add(&self, sample: T) -> Self {
let x: f64 = <T as StatData>::into_f64(sample);
if f64::is_nan(x) {
*self
} else if self.count == 0 {
Self::from_sample(sample)
} else {
let count = 1 + self.count;
let n: f64 = count as f64;
let k1 = 1.0 / n;
let k2 = (n - 1.0) / n;
let min = if sample < self.min { sample } else { self.min };
let max = if sample > self.max { sample } else { self.max };
let mean = k1 * x + k2 * self.mean;
let mean2 = k1 * x * x + k2 * self.mean2;
SamplingStats {
count: count,
min: min,
max: max,
mean: mean,
mean2: mean2
}
}
}
#[inline]
pub fn combine(&self, other: &Self) -> Self {
let c1 = self.count;
let c2 = other.count;
if c1 == 0 {
*other
} else if c2 == 0 {
*self
} else {
let count = c1 + c2;
let n1 = c1 as f64;
let n2 = c2 as f64;
let n = n1 + n2;
let k1 = n1 / n;
let k2 = n2 / n;
let min = if self.min < other.min { self.min } else { other.min };
let max = if self.max > other.max { self.max } else { other.max };
let mean = k1 * self.mean + k2 * other.mean;
let mean2 = k1 * self.mean2 + k2 * other.mean2;
SamplingStats {
count: count,
min: min,
max: max,
mean: mean,
mean2: mean2
}
}
}
#[inline]
pub fn variance(&self) -> f64 {
if self.count == 1 {
0.0
} else {
let n = self.count as f64;
(self.mean2 - self.mean * self.mean) * (n / (n - 1.0))
}
}
#[inline]
pub fn deviation(&self) -> f64 {
f64::sqrt(self.variance())
}
}
impl<T> fmt::Display for SamplingStats<T>
where T: fmt::Display + Copy + PartialOrd + StatData
{
fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
write!(f, "{{ count = {}, mean = {}, std = {}, min = {}, max = {} }}",
self.count, self.mean, self.deviation(), self.min, self.max)
}
}
impl From<SamplingStats<i32>> for SamplingStats<f32> {
fn from(stats: SamplingStats<i32>) -> Self {
SamplingStats {
count: stats.count,
min: stats.min as f32,
max: stats.max as f32,
mean: stats.mean,
mean2: stats.mean2
}
}
}
impl From<SamplingStats<i32>> for SamplingStats<f64> {
fn from(stats: SamplingStats<i32>) -> Self {
SamplingStats {
count: stats.count,
min: stats.min as f64,
max: stats.max as f64,
mean: stats.mean,
mean2: stats.mean2
}
}
}
impl From<SamplingStats<i64>> for SamplingStats<f32> {
fn from(stats: SamplingStats<i64>) -> Self {
SamplingStats {
count: stats.count,
min: stats.min as f32,
max: stats.max as f32,
mean: stats.mean,
mean2: stats.mean2
}
}
}
impl From<SamplingStats<i64>> for SamplingStats<f64> {
fn from(stats: SamplingStats<i64>) -> Self {
SamplingStats {
count: stats.count,
min: stats.min as f64,
max: stats.max as f64,
mean: stats.mean,
mean2: stats.mean2
}
}
}
impl From<SamplingStats<isize>> for SamplingStats<f32> {
fn from(stats: SamplingStats<isize>) -> Self {
SamplingStats {
count: stats.count,
min: stats.min as f32,
max: stats.max as f32,
mean: stats.mean,
mean2: stats.mean2
}
}
}
impl From<SamplingStats<isize>> for SamplingStats<f64> {
fn from(stats: SamplingStats<isize>) -> Self {
SamplingStats {
count: stats.count,
min: stats.min as f64,
max: stats.max as f64,
mean: stats.mean,
mean2: stats.mean2
}
}
}