mod common;
mod iterator;
mod no_sum_sma;
mod ring_buffer;
mod single_sum_sma;
mod sma;
mod sum_tree;
mod sum_tree_sma;
pub use crate::iterator::Iter;
pub use crate::no_sum_sma::NoSumSMA;
pub use crate::single_sum_sma::SingleSumSMA;
pub use crate::sma::SMA;
pub use crate::sum_tree_sma::SumTreeSMA;
#[cfg(test)]
mod tests {
use crate::{NoSumSMA, SingleSumSMA, SumTreeSMA, SMA};
macro_rules! get_sma_impls {
(
$divisor_type:ty, $window_size:expr, $ctor:ident $(, $zero:expr)?
) => {{
let ma_impls: [Box<dyn SMA<_, $divisor_type, $window_size>>; 3] = [
Box::new(SingleSumSMA::<_, _, $window_size>::$ctor($($zero ,)?)),
Box::new(SumTreeSMA::<_, _, $window_size>::$ctor($($zero ,)?)),
Box::new(NoSumSMA::<_, _, $window_size>::$ctor($($zero ,)?)),
];
ma_impls
}};
}
#[test]
fn f32_samples() {
for sma in &mut get_sma_impls!(f32, 3, new) {
assert_eq!(sma.get_average(), 0.0);
assert_eq!(sma.get_num_samples(), 0);
sma.add_sample(4.0);
assert_eq!(sma.get_average(), 4.0);
assert_eq!(sma.get_num_samples(), 1);
sma.add_sample(8.0);
assert_eq!(sma.get_average(), 6.0);
assert_eq!(sma.get_num_samples(), 2);
sma.add_sample(3.0);
assert_eq!(sma.get_average(), 5.0);
assert_eq!(sma.get_num_samples(), 3);
sma.add_sample(7.0);
assert_eq!(sma.get_average(), 6.0);
assert_eq!(sma.get_num_samples(), 3);
sma.add_sample(11.0);
assert_eq!(sma.get_average(), 7.0);
assert_eq!(sma.get_num_samples(), 3);
sma.add_sample(0.0);
assert_eq!(sma.get_average(), 6.0);
assert_eq!(sma.get_num_samples(), 3);
sma.add_sample(-23.0);
assert_eq!(sma.get_average(), -4.0);
assert_eq!(sma.get_num_samples(), 3);
}
}
#[test]
fn u32_samples() {
for sma in &mut get_sma_impls!(u32, 3, new) {
assert_eq!(sma.get_average(), 0);
sma.add_sample(4);
assert_eq!(sma.get_average(), 4);
sma.add_sample(8);
assert_eq!(sma.get_average(), 6);
sma.add_sample(3);
assert_eq!(sma.get_average(), 5);
sma.add_sample(7);
assert_eq!(sma.get_average(), 6);
sma.add_sample(11);
assert_eq!(sma.get_average(), 7);
sma.add_sample(0);
assert_eq!(sma.get_average(), 6);
}
}
#[test]
fn u32_samples_2() {
for sma in &mut get_sma_impls!(u32, 3, new) {
sma.add_sample(1);
assert_eq!(sma.get_average(), 1);
sma.add_sample(2);
assert_eq!(sma.get_average(), 1);
sma.add_sample(3);
assert_eq!(sma.get_average(), 2);
sma.add_sample(4);
assert_eq!(sma.get_average(), 3);
sma.add_sample(10);
assert_eq!(sma.get_average(), 5);
}
}
#[test]
fn nalgebra_vector2_f32_samples() {
use nalgebra::Vector2;
for sma in &mut get_sma_impls!(f32, 3, new) {
assert_eq!(sma.get_average(), Vector2::new(0.0, 0.0));
sma.add_sample(Vector2::new(4.0, 8.0));
assert_eq!(sma.get_average(), Vector2::new(4.0, 8.0));
sma.add_sample(Vector2::new(6.0, 0.0));
assert_eq!(sma.get_average(), Vector2::new(5.0, 4.0));
sma.add_sample(Vector2::new(2.0, 10.0));
assert_eq!(sma.get_average(), Vector2::new(4.0, 6.0));
sma.add_sample(Vector2::new(-17.0, 20.0));
assert_eq!(sma.get_average(), Vector2::new(-3.0, 10.0));
sma.add_sample(Vector2::new(0.0, -21.0));
assert_eq!(sma.get_average(), Vector2::new(-5.0, 3.0));
}
}
#[test]
fn euclid_vector2_f32_samples() {
use euclid::default::Vector2D;
for sma in &mut get_sma_impls!(f32, 3, from_zero, Vector2D::zero()) {
assert_eq!(sma.get_average(), Vector2D::new(0.0, 0.0));
sma.add_sample(Vector2D::new(4.0, 8.0));
assert_eq!(sma.get_average(), Vector2D::new(4.0, 8.0));
sma.add_sample(Vector2D::new(6.0, 0.0));
assert_eq!(sma.get_average(), Vector2D::new(5.0, 4.0));
sma.add_sample(Vector2D::new(2.0, 10.0));
assert_eq!(sma.get_average(), Vector2D::new(4.0, 6.0));
sma.add_sample(Vector2D::new(-17.0, 20.0));
assert_eq!(sma.get_average(), Vector2D::new(-3.0, 10.0));
sma.add_sample(Vector2D::new(0.0, -21.0));
assert_eq!(sma.get_average(), Vector2D::new(-5.0, 3.0));
}
}
#[test]
fn cgmath_vector2_f32_samples() {
use cgmath::Vector2;
for sma in &mut get_sma_impls!(f32, 3, new) {
assert_eq!(sma.get_average(), Vector2::new(0.0, 0.0));
sma.add_sample(Vector2::new(4.0, 8.0));
assert_eq!(sma.get_average(), Vector2::new(4.0, 8.0));
sma.add_sample(Vector2::new(6.0, 0.0));
assert_eq!(sma.get_average(), Vector2::new(5.0, 4.0));
sma.add_sample(Vector2::new(2.0, 10.0));
assert_eq!(sma.get_average(), Vector2::new(4.0, 6.0));
sma.add_sample(Vector2::new(-17.0, 20.0));
assert_eq!(sma.get_average(), Vector2::new(-3.0, 10.0));
sma.add_sample(Vector2::new(0.0, -21.0));
assert_eq!(sma.get_average(), Vector2::new(-5.0, 3.0));
}
}
#[test]
fn duration_samples() {
use std::time::Duration;
for sma in &mut get_sma_impls!(u32, 3, from_zero, Duration::ZERO) {
assert_eq!(sma.get_average(), Duration::from_secs(0));
sma.add_sample(Duration::from_secs(10));
assert_eq!(sma.get_average(), Duration::from_secs(10));
sma.add_sample(Duration::from_secs(20));
assert_eq!(sma.get_average(), Duration::from_secs(15));
sma.add_sample(Duration::from_secs(30));
assert_eq!(sma.get_average(), Duration::from_secs(20));
sma.add_sample(Duration::from_secs(1));
assert_eq!(sma.get_average(), Duration::from_secs(17));
sma.add_sample(Duration::from_secs(32));
assert_eq!(sma.get_average(), Duration::from_secs(21));
}
}
#[test]
fn edge_case_zero_sized() {
for sma in &mut get_sma_impls!(u32, 0, new) {
assert_eq!(sma.get_average(), 0);
assert_eq!(sma.get_num_samples(), 0);
sma.add_sample(16);
assert_eq!(sma.get_average(), 0);
assert_eq!(sma.get_num_samples(), 0);
}
}
#[test]
fn misc_getters() {
for sma in &mut get_sma_impls!(u32, 5, new) {
assert_eq!(sma.get_average(), 0);
assert_eq!(sma.get_sample_window_size(), 5);
assert_eq!(sma.get_num_samples(), 0);
assert_eq!(sma.get_most_recent_sample(), None);
assert_eq!(sma.get_sample_window_iter().collect::<Vec<&u32>>().len(), 0);
sma.add_sample(13);
assert_eq!(sma.get_average(), 13);
assert_eq!(sma.get_sample_window_size(), 5);
assert_eq!(sma.get_num_samples(), 1);
assert_eq!(sma.get_most_recent_sample(), Some(13));
assert_eq!(
sma.get_sample_window_iter().collect::<Vec<&u32>>(),
vec![&13]
);
sma.add_sample(37);
assert_eq!(sma.get_average(), 25);
assert_eq!(sma.get_sample_window_size(), 5);
assert_eq!(sma.get_num_samples(), 2);
assert_eq!(sma.get_most_recent_sample(), Some(37));
assert_eq!(
sma.get_sample_window_iter().collect::<Vec<&u32>>(),
vec![&13, &37]
);
}
}
#[test]
fn f32_random_samples_max_algorithm_diffs() {
use rand::{distributions::Uniform, rngs::SmallRng, Rng, SeedableRng};
use rayon::prelude::*;
const WINDOW_SIZE: usize = 10;
const VALUE_RANGES: [(usize, usize); 6] = [
(0, 10),
(10, 100),
(100, 1000),
(1000, 10000),
(10000, 100000),
(100000, 1000000),
];
let seeds: Vec<u64> = SmallRng::seed_from_u64(0xCAFEBABE)
.sample_iter(&Uniform::from(0..u64::MAX))
.take(100)
.collect();
let averages_array_vec: Vec<[[f32; 3]; VALUE_RANGES.len()]> = seeds
.par_iter()
.map(|seed| {
let random_values: Vec<f32> = SmallRng::seed_from_u64(*seed)
.sample_iter(&Uniform::from(-100.0..100.0))
.take(1000000)
.collect();
let mut single_sum_sma = SingleSumSMA::<_, f32, WINDOW_SIZE>::new();
let mut sum_tree_sma = SumTreeSMA::<_, f32, WINDOW_SIZE>::new();
let mut no_sum_sma = NoSumSMA::<_, f32, WINDOW_SIZE>::new();
VALUE_RANGES.map(|value_range| {
for random_value in &random_values[value_range.0..value_range.1] {
single_sum_sma.add_sample(*random_value);
sum_tree_sma.add_sample(*random_value);
no_sum_sma.add_sample(*random_value);
}
[
single_sum_sma.get_average(),
sum_tree_sma.get_average(),
no_sum_sma.get_average(),
]
})
})
.collect();
let mut maximum_absolute_diffs_array = [[0.0f32; VALUE_RANGES.len()]; 2];
for averages_array in averages_array_vec {
for (idx, averages) in averages_array.iter().enumerate() {
for i in 0..2 {
let abs_diff = (averages[i] - averages[2]).abs();
if maximum_absolute_diffs_array[i][idx] < abs_diff {
maximum_absolute_diffs_array[i][idx] = abs_diff;
}
}
}
}
let [single_sum_maximum_absolute_diff, sum_tree_maximum_absolute_diff]: [f32; 2] =
maximum_absolute_diffs_array.map(|maximum_absolute_diffs| {
*maximum_absolute_diffs
.iter()
.max_by(|a, b| a.abs().partial_cmp(&b.abs()).unwrap())
.unwrap()
});
assert!(single_sum_maximum_absolute_diff < 0.002);
assert!(sum_tree_maximum_absolute_diff < 0.000006);
}
}