use std::f64;
use std::fmt;
use std::result;
use super::data::StatData;
use super::sampling::SamplingStats;
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
pub struct TimingStats<T> {
pub count: usize,
pub min: T,
pub max: T,
pub last: T,
pub min_time: f64,
pub max_time: f64,
pub start_time: f64,
pub last_time: f64,
pub sum: f64,
pub sum2: f64
}
impl<T> TimingStats<T> where T: Copy + PartialOrd + StatData {
#[inline]
pub fn from_sample(t: f64, sample: T) -> Self {
TimingStats {
count: 1,
min: sample,
max: sample,
last: sample,
min_time: t,
max_time: t,
start_time: t,
last_time: t,
sum: 0.0,
sum2: 0.0
}
}
#[inline]
pub fn empty() -> Self {
TimingStats {
count: 0,
min: <T as StatData>::max(),
max: <T as StatData>::min(),
last: <T as StatData>::any(),
min_time: f64::INFINITY,
max_time: f64::NEG_INFINITY,
start_time: f64::INFINITY,
last_time: f64::NEG_INFINITY,
sum: f64::NAN,
sum2: f64::NAN
}
}
pub fn add(&self, t: f64, sample: T) -> Self {
if t < self.last_time {
panic!("The current time cannot be less than the previous one")
} else {
let x: f64 = <T as StatData>::into_f64(sample);
if f64::is_nan(x) {
*self
} else if self.count == 0 {
Self::from_sample(t, sample)
} else {
let count = 1 + self.count;
let x0 = <T as StatData>::into_f64(self.last);
let min = if sample < self.min { sample } else { self.min };
let max = if sample > self.max { sample } else { self.max };
let min_time = if sample < self.min { t } else { self.min_time };
let max_time = if sample > self.max { t } else { self.max_time };
let sum = self.sum + (t - self.last_time) * x0;
let sum2 = self.sum2 + (t - self.last_time) * x0 * x0;
TimingStats {
count: count,
min: min,
max: max,
last: sample,
min_time: min_time,
max_time: max_time,
start_time: self.start_time,
last_time: t,
sum: sum,
sum2: sum2
}
}
}
}
#[inline]
pub fn mean(&self) -> f64 {
if self.count == 0 {
f64::NAN
} else if self.last_time <= self.start_time {
<T as StatData>::into_f64(self.min)
} else {
self.sum / (self.last_time - self.start_time)
}
}
#[inline]
pub fn mean2(&self) -> f64 {
if self.count == 0 {
f64::NAN
} else if self.last_time <= self.start_time {
let x = <T as StatData>::into_f64(self.min);
x * x
} else {
self.sum2 / (self.last_time - self.start_time)
}
}
#[inline]
pub fn variance(&self) -> f64 {
let e = self.mean();
let e2 = self.mean2();
e2 - e * e
}
#[inline]
pub fn deviation(&self) -> f64 {
f64::sqrt(self.variance())
}
#[inline]
pub fn norm(&self, count: usize) -> SamplingStats<T> {
SamplingStats {
count: count,
min: self.min,
max: self.max,
mean: self.mean(),
mean2: self.mean2()
}
}
}
impl<T> fmt::Display for TimingStats<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 = {} (t = {}), max = {} (t = {}), t in [{}, {}] }}",
self.count, self.mean(), self.deviation(), self.min, self.min_time, self.max, self.max_time, self.start_time, self.last_time)
}
}
impl From<TimingStats<i32>> for TimingStats<f32> {
fn from(stats: TimingStats<i32>) -> Self {
TimingStats {
count: stats.count,
min: stats.min as f32,
max: stats.max as f32,
last: stats.last as f32,
min_time: stats.min_time,
max_time: stats.max_time,
start_time: stats.start_time,
last_time: stats.last_time,
sum: stats.sum,
sum2: stats.sum2
}
}
}
impl From<TimingStats<i32>> for TimingStats<f64> {
fn from(stats: TimingStats<i32>) -> Self {
TimingStats {
count: stats.count,
min: stats.min as f64,
max: stats.max as f64,
last: stats.last as f64,
min_time: stats.min_time,
max_time: stats.max_time,
start_time: stats.start_time,
last_time: stats.last_time,
sum: stats.sum,
sum2: stats.sum2
}
}
}
impl From<TimingStats<i64>> for TimingStats<f32> {
fn from(stats: TimingStats<i64>) -> Self {
TimingStats {
count: stats.count,
min: stats.min as f32,
max: stats.max as f32,
last: stats.last as f32,
min_time: stats.min_time,
max_time: stats.max_time,
start_time: stats.start_time,
last_time: stats.last_time,
sum: stats.sum,
sum2: stats.sum2
}
}
}
impl From<TimingStats<i64>> for TimingStats<f64> {
fn from(stats: TimingStats<i64>) -> Self {
TimingStats {
count: stats.count,
min: stats.min as f64,
max: stats.max as f64,
last: stats.last as f64,
min_time: stats.min_time,
max_time: stats.max_time,
start_time: stats.start_time,
last_time: stats.last_time,
sum: stats.sum,
sum2: stats.sum2
}
}
}
impl From<TimingStats<isize>> for TimingStats<f32> {
fn from(stats: TimingStats<isize>) -> Self {
TimingStats {
count: stats.count,
min: stats.min as f32,
max: stats.max as f32,
last: stats.last as f32,
min_time: stats.min_time,
max_time: stats.max_time,
start_time: stats.start_time,
last_time: stats.last_time,
sum: stats.sum,
sum2: stats.sum2
}
}
}
impl From<TimingStats<isize>> for TimingStats<f64> {
fn from(stats: TimingStats<isize>) -> Self {
TimingStats {
count: stats.count,
min: stats.min as f64,
max: stats.max as f64,
last: stats.last as f64,
min_time: stats.min_time,
max_time: stats.max_time,
start_time: stats.start_time,
last_time: stats.last_time,
sum: stats.sum,
sum2: stats.sum2
}
}
}