From 5d6d67bac95282e3bc90bb690ddda484151e62bd Mon Sep 17 00:00:00 2001 From: Vinzent Steinberg Date: Sun, 25 Jun 2017 14:39:23 +0200 Subject: [PATCH] Move `add` and `merge` to trait This should make it possible to write more generic code. --- src/lib.rs | 2 +- src/macros.rs | 6 +- src/minmax.rs | 125 +++++++++++++++++++++++----------------- src/moments/kurtosis.rs | 30 ++++++---- src/moments/mean.rs | 47 ++++++++------- src/moments/mod.rs | 6 ++ src/moments/skewness.rs | 35 +++++++---- src/moments/variance.rs | 43 ++++++++------ src/quantile.rs | 119 ++++++++++++++++++++------------------ src/reduce.rs | 33 +++++++---- src/weighted_mean.rs | 72 +++++++++++++---------- tests/kurtosis.rs | 2 +- tests/macros.rs | 2 + tests/max.rs | 2 +- tests/mean.rs | 2 +- tests/min.rs | 2 +- tests/random.rs | 2 +- tests/skewness.rs | 2 +- tests/weighted_mean.rs | 2 +- 19 files changed, 310 insertions(+), 224 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index e03a323..ac2860b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,7 +19,7 @@ //! ### Example //! //! ``` -//! use average::MeanWithError; +//! use average::{MeanWithError, Estimate}; //! //! let mut a: MeanWithError = (1..6).map(Into::into).collect(); //! a.add(42.); diff --git a/src/macros.rs b/src/macros.rs index 74efa95..c4a09ff 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -40,7 +40,7 @@ macro_rules! assert_almost_eq { /// # extern crate core; /// # #[macro_use] extern crate average; /// # fn main() { -/// use average::{Min, Max}; +/// use average::{Min, Max, Estimate}; /// /// concatenate!(MinMax, [Min, min], [Max, max]); /// @@ -54,7 +54,7 @@ macro_rules! assert_almost_eq { /// The generated code looks roughly like this: /// /// ``` -/// # use average::{Min, Max}; +/// # use average::{Min, Max, Estimate}; /// # /// struct MinMax { /// min: Min, @@ -88,7 +88,7 @@ macro_rules! assert_almost_eq { /// # extern crate core; /// # #[macro_use] extern crate average; /// # fn main() { -/// use average::{Variance, Quantile}; +/// use average::{Variance, Quantile, Estimate}; /// /// concatenate!(Estimator, /// [Variance, variance, mean, sample_variance], diff --git a/src/minmax.rs b/src/minmax.rs index 5791756..3052d44 100644 --- a/src/minmax.rs +++ b/src/minmax.rs @@ -1,6 +1,7 @@ use core; use super::reduce::Reduce; +use super::{Estimate, Merge}; /// Calculate the minimum of `a` and `b`. fn min(a: f64, b: f64) -> f64 { @@ -43,38 +44,11 @@ impl Min { Min::from_value(::core::f64::INFINITY) } - /// Add an observation sampled from the population. - #[inline] - pub fn add(&mut self, x: f64) { - self.r.add(x); - } - /// Estimate the minium of the population. #[inline] pub fn min(&self) -> f64 { self.r.reduction() } - - /// Merge another sample into this one. - /// - /// - /// ## Example - /// - /// ``` - /// use average::Min; - /// - /// let sequence: &[f64] = &[1., 2., 3., 4., 5., 6., 7., 8., 9.]; - /// let (left, right) = sequence.split_at(3); - /// let min_total: Min = sequence.iter().map(|x| *x).collect(); - /// let mut min_left: Min = left.iter().map(|x| *x).collect(); - /// let min_right: Min = right.iter().map(|x| *x).collect(); - /// min_left.merge(&min_right); - /// assert_eq!(min_total.min(), min_left.min()); - /// ``` - #[inline] - pub fn merge(&mut self, other: &Min) { - self.r.merge(&other.r); - } } impl core::default::Default for Min { @@ -85,6 +59,41 @@ impl core::default::Default for Min { impl_from_iterator!(Min); +impl Estimate for Min { + #[inline] + fn add(&mut self, x: f64) { + self.r.add(x); + } + + #[inline] + fn estimate(&self) -> f64 { + self.min() + } +} + +impl Merge for Min { + /// Merge another sample into this one. + /// + /// + /// ## Example + /// + /// ``` + /// use average::{Min, Merge}; + /// + /// let sequence: &[f64] = &[1., 2., 3., 4., 5., 6., 7., 8., 9.]; + /// let (left, right) = sequence.split_at(3); + /// let min_total: Min = sequence.iter().map(|x| *x).collect(); + /// let mut min_left: Min = left.iter().map(|x| *x).collect(); + /// let min_right: Min = right.iter().map(|x| *x).collect(); + /// min_left.merge(&min_right); + /// assert_eq!(min_total.min(), min_left.min()); + /// ``` + #[inline] + fn merge(&mut self, other: &Min) { + self.r.merge(&other.r); + } +} + /// Estimate the maximum of a sequence of numbers ("population"). /// /// @@ -116,38 +125,11 @@ impl Max { Max::from_value(::core::f64::NEG_INFINITY) } - /// Add an observation sampled from the population. - #[inline] - pub fn add(&mut self, x: f64) { - self.r.add(x); - } - /// Estimate the maxium of the population. #[inline] pub fn max(&self) -> f64 { self.r.reduction() } - - /// Merge another sample into this one. - /// - /// - /// ## Example - /// - /// ``` - /// use average::Max; - /// - /// let sequence: &[f64] = &[1., 2., 3., 4., 5., 6., 7., 8., 9.]; - /// let (left, right) = sequence.split_at(3); - /// let max_total: Max = sequence.iter().map(|x| *x).collect(); - /// let mut max_left: Max = left.iter().map(|x| *x).collect(); - /// let max_right: Max = right.iter().map(|x| *x).collect(); - /// max_left.merge(&max_right); - /// assert_eq!(max_total.max(), max_left.max()); - /// ``` - #[inline] - pub fn merge(&mut self, other: &Max) { - self.r.merge(&other.r); - } } impl core::default::Default for Max { @@ -157,3 +139,38 @@ impl core::default::Default for Max { } impl_from_iterator!(Max); + +impl Estimate for Max { + #[inline] + fn add(&mut self, x: f64) { + self.r.add(x); + } + + #[inline] + fn estimate(&self) -> f64 { + self.max() + } +} + +impl Merge for Max { + /// Merge another sample into this one. + /// + /// + /// ## Example + /// + /// ``` + /// use average::{Max, Merge}; + /// + /// let sequence: &[f64] = &[1., 2., 3., 4., 5., 6., 7., 8., 9.]; + /// let (left, right) = sequence.split_at(3); + /// let max_total: Max = sequence.iter().map(|x| *x).collect(); + /// let mut max_left: Max = left.iter().map(|x| *x).collect(); + /// let max_right: Max = right.iter().map(|x| *x).collect(); + /// max_left.merge(&max_right); + /// assert_eq!(max_total.max(), max_left.max()); + /// ``` + #[inline] + fn merge(&mut self, other: &Max) { + self.r.merge(&other.r); + } +} diff --git a/src/moments/kurtosis.rs b/src/moments/kurtosis.rs index 7d3cfcd..ffba1aa 100644 --- a/src/moments/kurtosis.rs +++ b/src/moments/kurtosis.rs @@ -20,15 +20,6 @@ impl Kurtosis { } } - /// Add an observation sampled from the population. - #[inline] - pub fn add(&mut self, x: f64) { - let delta = x - self.mean(); - self.increment(); - let n = f64::approx_from(self.len()).unwrap(); - self.add_inner(delta, delta/n); - } - /// Increment the sample size. /// /// This does not update anything else. @@ -114,9 +105,26 @@ impl Kurtosis { n * self.sum_4 / (self.avg.avg.sum_2 * self.avg.avg.sum_2) - 3. } - /// Merge another sample into this one. +} + +impl Estimate for Kurtosis { #[inline] - pub fn merge(&mut self, other: &Kurtosis) { + fn add(&mut self, x: f64) { + let delta = x - self.mean(); + self.increment(); + let n = f64::approx_from(self.len()).unwrap(); + self.add_inner(delta, delta/n); + } + + #[inline] + fn estimate(&self) -> f64 { + self.kurtosis() + } +} + +impl Merge for Kurtosis { + #[inline] + fn merge(&mut self, other: &Kurtosis) { let len_self = f64::approx_from(self.len()).unwrap(); let len_other = f64::approx_from(other.len()).unwrap(); let len_total = len_self + len_other; diff --git a/src/moments/mean.rs b/src/moments/mean.rs index cde4519..7aba367 100644 --- a/src/moments/mean.rs +++ b/src/moments/mean.rs @@ -1,8 +1,3 @@ -use core; - -use conv::ApproxFrom; - - /// Estimate the arithmetic mean of a sequence of numbers ("population"). /// /// @@ -29,15 +24,6 @@ impl Mean { Mean { avg: 0., n: 0 } } - /// Add an observation sampled from the population. - #[inline] - pub fn add(&mut self, sample: f64) { - self.increment(); - let delta_n = (sample - self.avg) - / f64::approx_from(self.n).unwrap(); - self.add_inner(delta_n); - } - /// Increment the sample size. /// /// This does not update anything else. @@ -80,13 +66,36 @@ impl Mean { self.n } +} + +impl core::default::Default for Mean { + fn default() -> Mean { + Mean::new() + } +} + +impl Estimate for Mean { + #[inline] + fn add(&mut self, sample: f64) { + self.increment(); + let delta_n = (sample - self.avg) + / f64::approx_from(self.n).unwrap(); + self.add_inner(delta_n); + } + + fn estimate(&self) -> f64 { + self.mean() + } +} + +impl Merge for Mean { /// Merge another sample into this one. /// /// /// ## Example /// /// ``` - /// use average::Mean; + /// use average::{Mean, Merge}; /// /// let sequence: &[f64] = &[1., 2., 3., 4., 5., 6., 7., 8., 9.]; /// let (left, right) = sequence.split_at(3); @@ -97,7 +106,7 @@ impl Mean { /// assert_eq!(avg_total.mean(), avg_left.mean()); /// ``` #[inline] - pub fn merge(&mut self, other: &Mean) { + fn merge(&mut self, other: &Mean) { // This algorithm was proposed by Chan et al. in 1979. // // See https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance. @@ -114,10 +123,4 @@ impl Mean { } } -impl core::default::Default for Mean { - fn default() -> Mean { - Mean::new() - } -} - impl_from_iterator!(Mean); diff --git a/src/moments/mod.rs b/src/moments/mod.rs index 687d169..2596224 100644 --- a/src/moments/mod.rs +++ b/src/moments/mod.rs @@ -1,3 +1,9 @@ +use core; + +use conv::ApproxFrom; + +use super::{Estimate, Merge}; + include!("mean.rs"); include!("variance.rs"); include!("skewness.rs"); diff --git a/src/moments/skewness.rs b/src/moments/skewness.rs index 04dfc68..b6aee19 100644 --- a/src/moments/skewness.rs +++ b/src/moments/skewness.rs @@ -20,15 +20,6 @@ impl Skewness { } } - /// Add an observation sampled from the population. - #[inline] - pub fn add(&mut self, x: f64) { - let delta = x - self.mean(); - self.increment(); - let n = f64::approx_from(self.len()).unwrap(); - self.add_inner(delta, delta/n); - } - /// Increment the sample size. /// /// This does not update anything else. @@ -107,10 +98,32 @@ impl Skewness { debug_assert_ne!(sum_2, 0.); n.sqrt() * self.sum_3 / (sum_2*sum_2*sum_2).sqrt() } +} - /// Merge another sample into this one. +impl Default for Skewness { + fn default() -> Skewness { + Skewness::new() + } +} + +impl Estimate for Skewness { #[inline] - pub fn merge(&mut self, other: &Skewness) { + fn add(&mut self, x: f64) { + let delta = x - self.mean(); + self.increment(); + let n = f64::approx_from(self.len()).unwrap(); + self.add_inner(delta, delta/n); + } + + #[inline] + fn estimate(&self) -> f64 { + self.skewness() + } +} + +impl Merge for Skewness { + #[inline] + fn merge(&mut self, other: &Skewness) { let len_self = f64::approx_from(self.len()).unwrap(); let len_other = f64::approx_from(other.len()).unwrap(); let len_total = len_self + len_other; diff --git a/src/moments/variance.rs b/src/moments/variance.rs index c1adc7b..f600f2d 100644 --- a/src/moments/variance.rs +++ b/src/moments/variance.rs @@ -27,15 +27,6 @@ impl Variance { Variance { avg: Mean::new(), sum_2: 0. } } - /// Add an observation sampled from the population. - #[inline] - pub fn add(&mut self, sample: f64) { - self.increment(); - let delta_n = (sample - self.avg.mean()) - / f64::approx_from(self.len()).unwrap(); - self.add_inner(delta_n); - } - /// Increment the sample size. /// /// This does not update anything else. @@ -113,13 +104,37 @@ impl Variance { (self.sample_variance() / f64::approx_from(n).unwrap()).sqrt() } +} + +impl core::default::Default for Variance { + fn default() -> Variance { + Variance::new() + } +} + +impl Estimate for Variance { + #[inline] + fn add(&mut self, sample: f64) { + self.increment(); + let delta_n = (sample - self.avg.mean()) + / f64::approx_from(self.len()).unwrap(); + self.add_inner(delta_n); + } + + #[inline] + fn estimate(&self) -> f64 { + self.population_variance() + } +} + +impl Merge for Variance { /// Merge another sample into this one. /// /// /// ## Example /// /// ``` - /// use average::Variance; + /// use average::{Variance, Merge}; /// /// let sequence: &[f64] = &[1., 2., 3., 4., 5., 6., 7., 8., 9.]; /// let (left, right) = sequence.split_at(3); @@ -131,7 +146,7 @@ impl Variance { /// assert_eq!(avg_total.sample_variance(), avg_left.sample_variance()); /// ``` #[inline] - pub fn merge(&mut self, other: &Variance) { + fn merge(&mut self, other: &Variance) { // This algorithm was proposed by Chan et al. in 1979. // // See https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance. @@ -144,10 +159,4 @@ impl Variance { } } -impl core::default::Default for Variance { - fn default() -> Variance { - Variance::new() - } -} - impl_from_iterator!(Variance); diff --git a/src/quantile.rs b/src/quantile.rs index 505e2df..3c00e38 100644 --- a/src/quantile.rs +++ b/src/quantile.rs @@ -4,6 +4,8 @@ use core::cmp::min; use conv::{ApproxFrom, ConvAsUtil, ValueFrom}; use quickersort::sort_floats; +use super::Estimate; + /// Estimate the p-quantile of a sequence of numbers ("population"). #[derive(Debug, Clone)] pub struct Quantile { @@ -38,62 +40,6 @@ impl Quantile { self.dm[2] } - /// Add an observation sampled from the population. - #[inline] - pub fn add(&mut self, x: f64) { - // n[4] is the sample size. - if self.n[4] < 5 { - self.q[usize::value_from(self.n[4]).unwrap()] = x; // n[4] < 5 - self.n[4] += 1; - if self.n[4] == 5 { - sort_floats(&mut self.q); - } - return; - } - - // Find cell k. - let mut k: usize; - if x < self.q[0] { - self.q[0] = x; - k = 0; - } else { - k = 4; - for i in 1..5 { - if x < self.q[i] { - k = i; - break; - } - } - if self.q[4] < x { - self.q[4] = x; - } - }; - - // Increment all positions greater than k. - for i in k..5 { - self.n[i] += 1; - } - for i in 0..5 { - self.m[i] += self.dm[i]; - } - - // Adjust height of markers. - for i in 1..4 { - let d: f64 = self.m[i] - f64::approx_from(self.n[i]).unwrap(); - if d >= 1. && self.n[i + 1] - self.n[i] > 1 || - d <= -1. && self.n[i - 1] - self.n[i] < -1 { - let d = d.signum(); - let q_new = self.parabolic(i, d); - if self.q[i - 1] < q_new && q_new < self.q[i + 1] { - self.q[i] = q_new; - } else { - self.q[i] = self.linear(i, d); - } - self.n[i] += d.approx().unwrap(); // d == +-1 - } - } - } - /// Parabolic prediction for marker height. #[inline] fn parabolic(&self, i: usize, d: f64) -> f64 { @@ -171,6 +117,67 @@ impl core::default::Default for Quantile { } } +impl Estimate for Quantile { + #[inline] + fn add(&mut self, x: f64) { + // n[4] is the sample size. + if self.n[4] < 5 { + self.q[usize::value_from(self.n[4]).unwrap()] = x; // n[4] < 5 + self.n[4] += 1; + if self.n[4] == 5 { + sort_floats(&mut self.q); + } + return; + } + + // Find cell k. + let mut k: usize; + if x < self.q[0] { + self.q[0] = x; + k = 0; + } else { + k = 4; + for i in 1..5 { + if x < self.q[i] { + k = i; + break; + } + } + if self.q[4] < x { + self.q[4] = x; + } + }; + + // Increment all positions greater than k. + for i in k..5 { + self.n[i] += 1; + } + for i in 0..5 { + self.m[i] += self.dm[i]; + } + + // Adjust height of markers. + for i in 1..4 { + let d: f64 = self.m[i] - f64::approx_from(self.n[i]).unwrap(); + if d >= 1. && self.n[i + 1] - self.n[i] > 1 || + d <= -1. && self.n[i - 1] - self.n[i] < -1 { + let d = d.signum(); + let q_new = self.parabolic(i, d); + if self.q[i - 1] < q_new && q_new < self.q[i + 1] { + self.q[i] = q_new; + } else { + self.q[i] = self.linear(i, d); + } + self.n[i] += d.approx().unwrap(); // d == +-1 + } + } + } + + fn estimate(&self) -> f64 { + self.quantile() + } +} + #[test] fn reference() { let observations = [ diff --git a/src/reduce.rs b/src/reduce.rs index 3fd5345..0036c65 100644 --- a/src/reduce.rs +++ b/src/reduce.rs @@ -1,3 +1,5 @@ +use super::{Estimate, Merge}; + /// Estimate the reduction of a sequence of numbers ("population"). /// /// The reduction is a given function `Fn(f64, f64) -> f64`. @@ -10,30 +12,41 @@ pub struct Reduce { reduce: F, } -impl Reduce - where F: Fn(f64, f64) -> f64 -{ +impl Reduce { /// Create a new reduction estimator given an initial value and a reduction. #[inline] pub fn from_value_and_fn(x: f64, f: F) -> Reduce { Reduce { x: x, reduce: f } } - /// Add an element sampled from the population. - #[inline] - pub fn add(&mut self, x: f64) { - self.x = (self.reduce)(self.x, x); - } - /// Estimate the reduction of the population. #[inline] pub fn reduction(&self) -> f64 { self.x } +} + +impl Estimate for Reduce + where F: Fn(f64, f64) -> f64, +{ + #[inline] + fn add(&mut self, x: f64) { + self.x = (self.reduce)(self.x, x); + } + + #[inline] + fn estimate(&self) -> f64 { + self.reduction() + } +} + +impl Merge for Reduce + where F: Fn(f64, f64) -> f64, +{ /// Merge another sample into this one. #[inline] - pub fn merge(&mut self, other: &Reduce) { + fn merge(&mut self, other: &Reduce) { self.add(other.x); } } diff --git a/src/weighted_mean.rs b/src/weighted_mean.rs index dc4dfb3..38c5ed5 100644 --- a/src/weighted_mean.rs +++ b/src/weighted_mean.rs @@ -1,6 +1,6 @@ use core; -use super::MeanWithError; +use super::{MeanWithError, Estimate, Merge}; /// Estimate the weighted and unweighted arithmetic mean of a sequence of @@ -32,7 +32,7 @@ impl WeightedMean { } } - /// Add a weighted observation sampled from the population. + /// Add an observation sampled from the population. #[inline] pub fn add(&mut self, sample: f64, weight: f64) { // The algorithm for the unweighted mean was suggested by Welford in 1962. @@ -70,33 +70,6 @@ impl WeightedMean { pub fn mean(&self) -> f64 { self.weighted_avg } - - /// Merge another sample into this one. - /// - /// - /// ## Example - /// - /// ``` - /// use average::WeightedMean; - /// - /// let weighted_sequence: &[(f64, f64)] = &[ - /// (1., 0.1), (2., 0.2), (3., 0.3), (4., 0.4), (5., 0.5), - /// (6., 0.6), (7., 0.7), (8., 0.8), (9., 0.9)]; - /// let (left, right) = weighted_sequence.split_at(3); - /// let avg_total: WeightedMean = weighted_sequence.iter().map(|&x| x).collect(); - /// let mut avg_left: WeightedMean = left.iter().map(|&x| x).collect(); - /// let avg_right: WeightedMean = right.iter().map(|&x| x).collect(); - /// avg_left.merge(&avg_right); - /// assert!((avg_total.mean() - avg_left.mean()).abs() < 1e-15); - /// ``` - #[inline] - pub fn merge(&mut self, other: &WeightedMean) { - let total_weight_sum = self.weight_sum + other.weight_sum; - self.weighted_avg = (self.weight_sum * self.weighted_avg - + other.weight_sum * other.weighted_avg) - / total_weight_sum; - self.weight_sum = total_weight_sum; - } } impl core::default::Default for WeightedMean { @@ -117,6 +90,35 @@ impl core::iter::FromIterator<(f64, f64)> for WeightedMean { } } +impl Merge for WeightedMean { + /// Merge another sample into this one. + /// + /// + /// ## Example + /// + /// ``` + /// use average::{WeightedMean, Merge}; + /// + /// let weighted_sequence: &[(f64, f64)] = &[ + /// (1., 0.1), (2., 0.2), (3., 0.3), (4., 0.4), (5., 0.5), + /// (6., 0.6), (7., 0.7), (8., 0.8), (9., 0.9)]; + /// let (left, right) = weighted_sequence.split_at(3); + /// let avg_total: WeightedMean = weighted_sequence.iter().map(|&x| x).collect(); + /// let mut avg_left: WeightedMean = left.iter().map(|&x| x).collect(); + /// let avg_right: WeightedMean = right.iter().map(|&x| x).collect(); + /// avg_left.merge(&avg_right); + /// assert!((avg_total.mean() - avg_left.mean()).abs() < 1e-15); + /// ``` + #[inline] + fn merge(&mut self, other: &WeightedMean) { + let total_weight_sum = self.weight_sum + other.weight_sum; + self.weighted_avg = (self.weight_sum * self.weighted_avg + + other.weight_sum * other.weighted_avg) + / total_weight_sum; + self.weight_sum = total_weight_sum; + } +} + /// Estimate the weighted and unweighted arithmetic mean and the unweighted /// variance of a sequence of numbers ("population"). /// @@ -153,7 +155,7 @@ impl WeightedMeanWithError { } } - /// Add a weighted observation sampled from the population. + /// Add an observation sampled from the population. #[inline] pub fn add(&mut self, sample: f64, weight: f64) { // The algorithm for the unweighted mean was suggested by Welford in 1962. @@ -225,6 +227,7 @@ impl WeightedMeanWithError { /// Calculate the *unweighted* population variance of the sample. /// /// This is a biased estimator of the variance of the population. + #[inline] pub fn population_variance(&self) -> f64 { self.unweighted_avg.population_variance() } @@ -232,6 +235,7 @@ impl WeightedMeanWithError { /// Calculate the *unweighted* sample variance. /// /// This is an unbiased estimator of the variance of the population. + #[inline] pub fn sample_variance(&self) -> f64 { self.unweighted_avg.sample_variance() } @@ -242,6 +246,7 @@ impl WeightedMeanWithError { /// /// This unbiased estimator assumes that the samples were independently /// drawn from the same population with constant variance. + #[inline] pub fn error(&self) -> f64 { // This uses the same estimate as WinCross, which should provide better // results than the ones used by SPSS or Mentor. @@ -254,14 +259,16 @@ impl WeightedMeanWithError { let inv_effective_len = self.weight_sum_sq / (weight_sum * weight_sum); (self.sample_variance() * inv_effective_len).sqrt() } +} +impl Merge for WeightedMeanWithError { /// Merge another sample into this one. /// /// /// ## Example /// /// ``` - /// use average::WeightedMeanWithError; + /// use average::{WeightedMeanWithError, Merge}; /// /// let weighted_sequence: &[(f64, f64)] = &[ /// (1., 0.1), (2., 0.2), (3., 0.3), (4., 0.4), (5., 0.5), @@ -274,7 +281,8 @@ impl WeightedMeanWithError { /// assert!((avg_total.weighted_mean() - avg_left.weighted_mean()).abs() < 1e-15); /// assert!((avg_total.error() - avg_left.error()).abs() < 1e-15); /// ``` - pub fn merge(&mut self, other: &WeightedMeanWithError) { + #[inline] + fn merge(&mut self, other: &WeightedMeanWithError) { self.weight_sum_sq += other.weight_sum_sq; self.weighted_avg.merge(&other.weighted_avg); self.unweighted_avg.merge(&other.unweighted_avg); diff --git a/tests/kurtosis.rs b/tests/kurtosis.rs index 85dd591..3d908c2 100644 --- a/tests/kurtosis.rs +++ b/tests/kurtosis.rs @@ -6,7 +6,7 @@ extern crate core; use core::iter::Iterator; -use average::Kurtosis; +use average::{Kurtosis, Estimate, Merge}; #[test] fn trivial() { diff --git a/tests/macros.rs b/tests/macros.rs index 8f81f94..777198e 100644 --- a/tests/macros.rs +++ b/tests/macros.rs @@ -2,6 +2,8 @@ extern crate core; +use average::Estimate; + #[test] fn concatenate_simple() { use average::{Min, Max}; diff --git a/tests/max.rs b/tests/max.rs index 95a294e..87bbb43 100644 --- a/tests/max.rs +++ b/tests/max.rs @@ -6,7 +6,7 @@ extern crate core; use core::iter::Iterator; -use average::Max; +use average::{Max, Estimate, Merge}; #[test] fn trivial() { diff --git a/tests/mean.rs b/tests/mean.rs index 8184841..e5143d0 100644 --- a/tests/mean.rs +++ b/tests/mean.rs @@ -6,7 +6,7 @@ extern crate core; use core::iter::Iterator; -use average::MeanWithError; +use average::{MeanWithError, Estimate, Merge}; #[test] fn trivial() { diff --git a/tests/min.rs b/tests/min.rs index 0b85d7e..d7fe3ec 100644 --- a/tests/min.rs +++ b/tests/min.rs @@ -6,7 +6,7 @@ extern crate core; use core::iter::Iterator; -use average::Min; +use average::{Min, Estimate, Merge}; #[test] fn trivial() { diff --git a/tests/random.rs b/tests/random.rs index 2e4674b..33326d8 100644 --- a/tests/random.rs +++ b/tests/random.rs @@ -4,7 +4,7 @@ extern crate rand; -use average::Kurtosis; +use average::{Kurtosis, Estimate}; #[test] fn normal_distribution() { diff --git a/tests/skewness.rs b/tests/skewness.rs index 6e9b810..d523803 100644 --- a/tests/skewness.rs +++ b/tests/skewness.rs @@ -6,7 +6,7 @@ extern crate core; use core::iter::Iterator; -use average::Skewness; +use average::{Skewness, Estimate, Merge}; #[test] fn trivial() { diff --git a/tests/weighted_mean.rs b/tests/weighted_mean.rs index 53004af..141445f 100644 --- a/tests/weighted_mean.rs +++ b/tests/weighted_mean.rs @@ -6,7 +6,7 @@ extern crate core; use core::iter::Iterator; -use average::WeightedMeanWithError; +use average::{WeightedMeanWithError, Merge}; #[test] fn trivial() {