From 86a411143e200c9a97b08b5c84ed51a4962bcf08 Mon Sep 17 00:00:00 2001 From: Vinzent Steinberg Date: Tue, 6 Mar 2018 18:11:27 +0100 Subject: [PATCH] histogram: Implement iteration of bin widths and normalized bins --- src/traits.rs | 50 +++++++++++++++++++++++++++++++++++++++++++++- tests/histogram.rs | 27 +++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/src/traits.rs b/src/traits.rs index 573e582..ab53d53 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -13,7 +13,55 @@ pub trait Merge { } /// Get the bins and ranges from a histogram. -pub trait Histogram { +pub trait Histogram: + where for<'a> &'a Self: IntoIterator +{ /// Return the bins of the histogram. fn bins(&self) -> &[u64]; + + /// Return an iterator over the bins normalized by the bin widths. + fn normalized_bins(&self) -> IterNormalized<<&Self as IntoIterator>::IntoIter> { + IterNormalized { histogram_iter: (&self).into_iter() } + } + + /// Return an iterator over the bin widths. + fn widths(&self) -> IterWidths<<&Self as IntoIterator>::IntoIter> { + IterWidths { histogram_iter: (&self).into_iter() } + } +} + +/// Iterate over the bins normalized by bin width. +pub struct IterNormalized + where T: Iterator +{ + histogram_iter: T, +} + +impl Iterator for IterNormalized + where T: Iterator +{ + type Item = f64; + + #[inline] + fn next(&mut self) -> Option { + self.histogram_iter.next().map(|((a, b), count)| (count as f64) / (b - a)) + } +} + +/// Iterate over the widths of the bins. +pub struct IterWidths + where T: Iterator +{ + histogram_iter: T, +} + +impl Iterator for IterWidths + where T: Iterator +{ + type Item = f64; + + #[inline] + fn next(&mut self) -> Option { + self.histogram_iter.next().map(|((a, b), _)| b - a) + } } diff --git a/tests/histogram.rs b/tests/histogram.rs index fc641ad..b4bbd15 100644 --- a/tests/histogram.rs +++ b/tests/histogram.rs @@ -42,6 +42,33 @@ fn iter() { ]); } +#[test] +fn normalized_bins() { + let inf = std::f64::INFINITY; + let mut h = Histogram10::from_ranges( + [-inf, 0.1, 0.2, 0.3, 0.4, 0.4, 0.7, 0.8, 0.9, 1.0, inf].iter().cloned()).unwrap(); + for &i in &[0.05, 0.1, 0.7, 1.0, 1.5] { + h.add(i).unwrap(); + } + let normalized: Vec = h.normalized_bins().collect(); + let expected = [0., 10., 0., 0., 0., 0., 10., 0., 0., 0.]; + for (a, b) in normalized.iter().zip(expected.iter()) { + assert_almost_eq!(a, b, 1e-14); + } +} + +#[test] +fn widths() { + let inf = std::f64::INFINITY; + let h = Histogram10::from_ranges( + [-inf, 0.1, 0.2, 0.3, 0.4, 0.4, 0.7, 0.8, 0.9, 1.0, inf].iter().cloned()).unwrap(); + let widths: Vec = h.widths().collect(); + let expected = [inf, 0.1, 0.1, 0.1, 0., 0.3, 0.1, 0.1, 0.1, inf]; + for (a, b) in widths.iter().zip(expected.iter()) { + assert_almost_eq!(a, b, 1e-14); + } +} + #[test] fn from_ranges_infinity() { let inf = std::f64::INFINITY;