#![doc = include_str!("bench_intel_2014.md")]
#![doc = include_str!("bench_amd_2021.md")]
pub trait CumulFreqTable<F: From<u8> = usize> {
fn new(len: usize) -> Self;
fn with_freq(len: usize, init: F) -> Self
where
usize: TryInto<F>,
<usize as TryInto<F>>::Error: std::fmt::Debug,
F: std::fmt::Debug;
fn len(&self) -> usize;
fn add(&mut self, pos: usize, val: F);
fn sub(&mut self, pos: usize, val: F);
fn inc(&mut self, pos: usize) {
self.add(pos, 1.into());
}
fn dec(&mut self, pos: usize) {
self.sub(pos, 1.into());
}
fn sum(&self, pos: usize) -> F;
fn total(&self) -> F;
fn freq(&self, pos: usize) -> F;
fn find_by_sum(&self, sum: F) -> usize;
fn scale<C: Fn(F) -> F>(&mut self, scale_freq: C);
}
pub mod binary_indexed_tree;
pub mod cumulfreq_array;
pub mod freq_array;
use std::convert::From;
pub use binary_indexed_tree::CumulFreqTable as BinaryIndexedTree;
pub use freq_array::FreqTable;
#[cfg(test)]
mod tests {
use super::*;
use std::convert::From;
use std::fmt::Debug;
use std::ops::{Add, Div, Mul, Sub};
#[test]
fn long_test_usize() {
long_test::<usize>();
}
#[test]
fn long_test_i16() {
long_test::<i16>();
}
#[test]
fn long_test_u16() {
long_test::<u16>();
}
fn long_test<F>()
where
F: Copy
+ Debug
+ 'static
+ From<u8>
+ Add<Output = F>
+ Sub<Output = F>
+ Mul<Output = F>
+ Div<Output = F>
+ PartialEq,
usize: TryInto<F>,
<usize as TryInto<F>>::Error: std::fmt::Debug,
freq_array::FreqTable<F>: CumulFreqTable<F>,
cumulfreq_array::CumulFreqTable<F>: CumulFreqTable<F>,
binary_indexed_tree::CumulFreqTable<F>: CumulFreqTable<F>,
{
for len in 1..=32 {
long_test_impl::<F, freq_array::FreqTable<F>>(len);
long_test_impl::<F, cumulfreq_array::CumulFreqTable<F>>(len);
long_test_impl::<F, binary_indexed_tree::CumulFreqTable<F>>(len);
}
}
fn long_test_impl<F, T>(len: usize)
where
F: Copy
+ Debug
+ From<u8>
+ Add<Output = F>
+ Sub<Output = F>
+ Mul<Output = F>
+ Div<Output = F>
+ PartialEq,
usize: TryInto<F>,
<usize as TryInto<F>>::Error: std::fmt::Debug,
T: CumulFreqTable<F> + Debug + 'static,
{
let flen: F = (len as u8).into();
let f0: F = 0_u8.into();
let f1: F = 1_u8.into();
let f2: F = 2_u8.into();
let f3: F = 3_u8.into();
let f42: F = 42_u8.into();
let mut table: T = T::with_freq(len, f1);
assert_eq!(table.len(), len);
assert_eq!(table.total(), flen);
for i in 0..len {
assert_eq!(table.freq(i), f1);
assert_eq!(table.sum(i), F::from(i as u8) + f1);
}
for i in 0..len {
table.dec(i);
}
assert_eq!(table.total(), f0);
for i in 0..len {
assert_eq!(table.freq(i), f0);
assert_eq!(table.sum(i), f0);
}
assert_eq!(table.total(), f0);
for i in 0..len {
table.inc(i);
assert_eq!(table.freq(i), f1);
assert_eq!(table.sum(i), F::from(i as u8) + f1);
}
assert_eq!(table.total(), flen);
for i in 0..len {
table.add(i, 2_u8.into());
assert_eq!(table.freq(i), f3);
assert_eq!(table.sum(i), (F::from(i as u8) + f1) * f3);
}
assert_eq!(table.total(), flen * f3);
for i in 0..len {
assert_eq!(table.freq(i), f3);
assert_eq!(table.sum(i), (F::from(i as u8) + f1) * f3);
}
for i in 0..len {
assert_eq!(table.find_by_sum((F::from(i as u8) + f1) * f3), i);
}
table.scale(|x| x / f2);
assert_eq!(table.total(), flen);
for i in 0..len {
assert_eq!(table.freq(i), f3 / f2);
assert_eq!(table.sum(i), F::from(i as u8) + f1);
}
for i in (0..len).step_by(2) {
table.add(i, f42 - f1);
}
assert_eq!(
table.total(),
(F::from(len as u8) - F::from(len as u8) / f2) * f42 + (F::from(len as u8) / f2)
);
for i in 0..len {
if i % 2 == 0 {
assert_eq!(table.freq(i), f42);
} else {
assert_eq!(table.freq(i), f1);
}
assert_eq!(
table.sum(i),
((F::from(i as u8) + f2) / f2 * f42) + ((F::from(i as u8) + f1) / f2)
);
}
}
#[test]
fn scale_test() {
type F = usize;
for len in 1..=32 {
scale_test_impl::<F, freq_array::FreqTable<F>>(len);
scale_test_impl::<F, cumulfreq_array::CumulFreqTable<F>>(len);
scale_test_impl::<F, binary_indexed_tree::CumulFreqTable<F>>(len);
}
}
fn scale_test_impl<F, T>(len: usize)
where
F: Copy
+ Debug
+ From<u8>
+ Add<Output = F>
+ Sub<Output = F>
+ Mul<Output = F>
+ Div<Output = F>
+ PartialEq,
usize: TryInto<F>,
<usize as TryInto<F>>::Error: std::fmt::Debug,
T: CumulFreqTable<F> + Debug + 'static + Clone,
{
let mut table = T::with_freq(len, 1.into());
for i in 0..len {
assert_eq!(table.freq(i), 1.into());
}
table.scale(|x| x * 2.into());
for i in 0..len {
assert_eq!(table.freq(i), 2.into());
}
table.scale(|x| (x + 1.into()) / 2.into());
for i in 0..len {
assert_eq!(table.freq(i), 1.into());
}
table.scale(|x| x * 42.into());
for i in 0..len {
assert_eq!(table.freq(i), 42.into());
}
let mut a = table.clone();
let mut b = table.clone();
a.scale(|x| x / 5.into());
b.scale(|x| (x + 1.into()) / 5.into());
for i in 0..len {
assert_eq!(a.freq(i), 8.into());
}
for i in 0..len {
assert_eq!(b.freq(i), 8.into());
}
a.scale(|x| x / 9.into());
b.scale(|x| (x + 1.into()) / 9.into());
for i in 0..len {
assert_eq!(a.freq(i), 0.into());
}
for i in 0..len {
assert_eq!(b.freq(i), 1.into());
}
}
}