histogram: Implement iteration of bin widths and normalized bins

This commit is contained in:
Vinzent Steinberg 2018-03-06 18:11:27 +01:00
parent c64544baa8
commit 86a411143e
2 changed files with 76 additions and 1 deletions

View File

@ -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<Item = ((f64, f64), u64)>
{
/// 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<T>
where T: Iterator<Item = ((f64, f64), u64)>
{
histogram_iter: T,
}
impl<T> Iterator for IterNormalized<T>
where T: Iterator<Item = ((f64, f64), u64)>
{
type Item = f64;
#[inline]
fn next(&mut self) -> Option<f64> {
self.histogram_iter.next().map(|((a, b), count)| (count as f64) / (b - a))
}
}
/// Iterate over the widths of the bins.
pub struct IterWidths<T>
where T: Iterator<Item = ((f64, f64), u64)>
{
histogram_iter: T,
}
impl<T> Iterator for IterWidths<T>
where T: Iterator<Item = ((f64, f64), u64)>
{
type Item = f64;
#[inline]
fn next(&mut self) -> Option<f64> {
self.histogram_iter.next().map(|((a, b), _)| b - a)
}
}

View File

@ -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<f64> = 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<f64> = 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;