#![allow(clippy::pedantic, clippy::all)]
use std::time::Instant;
use resq_dsa::bloom::BloomFilter;
use resq_dsa::count_min::CountMinSketch;
use resq_dsa::graph::Graph;
use resq_dsa::heap::BoundedHeap;
use resq_dsa::trie::Trie;
const TRIALS: usize = 7;
fn measure_median_ns<F: FnMut()>(mut f: F) -> f64 {
f();
let mut times = Vec::with_capacity(TRIALS);
for _ in 0..TRIALS {
let start = Instant::now();
f();
times.push(start.elapsed().as_nanos() as f64);
}
times.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
times[TRIALS / 2]
}
fn assert_not_quadratic(name: &str, t_n: f64, t_4n: f64, max_ratio_4x: f64) {
let ratio = t_4n / t_n;
assert!(
ratio <= max_ratio_4x,
"{name}: T(4N)/T(N) = {ratio:.2} exceeds max allowed {max_ratio_4x:.1} \
(t_n={t_n:.0}ns, t_4n={t_4n:.0}ns) -- possible worse-than-expected complexity"
);
}
#[test]
#[ignore] fn bloom_filter_insert_linear_scaling() {
let n = 20_000_usize;
let t_n = measure_median_ns(|| {
let mut bf = BloomFilter::new(n, 0.01);
for i in 0..n {
bf.add(i.to_string());
}
});
let t_4n = measure_median_ns(|| {
let mut bf = BloomFilter::new(4 * n, 0.01);
for i in 0..(4 * n) {
bf.add(i.to_string());
}
});
assert_not_quadratic("BloomFilter::add", t_n, t_4n, 10.0);
}
#[test]
#[ignore] fn bloom_filter_lookup_linear_scaling() {
let n = 20_000_usize;
let mut bf_n = BloomFilter::new(n, 0.01);
for i in 0..n {
bf_n.add(i.to_string());
}
let mut bf_4n = BloomFilter::new(4 * n, 0.01);
for i in 0..(4 * n) {
bf_4n.add(i.to_string());
}
let t_n = measure_median_ns(|| {
for i in 0..n {
std::hint::black_box(bf_n.has(i.to_string()));
}
});
let t_4n = measure_median_ns(|| {
for i in 0..(4 * n) {
std::hint::black_box(bf_4n.has(i.to_string()));
}
});
assert_not_quadratic("BloomFilter::has", t_n, t_4n, 10.0);
}
#[test]
#[ignore] fn bounded_heap_insert_nlogn_scaling() {
let n = 20_000_usize;
let t_n = measure_median_ns(|| {
let mut heap = BoundedHeap::new(n, |x: &f64| *x);
for i in 0..n {
heap.insert(i as f64);
}
});
let t_4n = measure_median_ns(|| {
let mut heap = BoundedHeap::new(4 * n, |x: &f64| *x);
for i in 0..(4 * n) {
heap.insert(i as f64);
}
});
assert_not_quadratic("BoundedHeap::insert", t_n, t_4n, 12.0);
}
#[test]
#[ignore] fn graph_dijkstra_nlogn_scaling() {
let n = 2_000_usize;
let build_chain = |size: usize| -> Graph<usize> {
let mut g = Graph::new();
for i in 0..(size - 1) {
g.add_edge(i, i + 1, 1);
}
g
};
let g_n = build_chain(n);
let g_4n = build_chain(4 * n);
let t_n = measure_median_ns(|| {
std::hint::black_box(g_n.dijkstra(&0, &(n - 1)));
});
let t_4n = measure_median_ns(|| {
std::hint::black_box(g_4n.dijkstra(&0, &(4 * n - 1)));
});
assert_not_quadratic("Graph::dijkstra", t_n, t_4n, 12.0);
}
#[test]
#[ignore] fn graph_bfs_linear_scaling() {
let n = 2_000_usize;
let build_chain = |size: usize| -> Graph<usize> {
let mut g = Graph::new();
for i in 0..(size - 1) {
g.add_edge(i, i + 1, 1);
}
g
};
let g_n = build_chain(n);
let g_4n = build_chain(4 * n);
let t_n = measure_median_ns(|| {
std::hint::black_box(g_n.bfs(&0));
});
let t_4n = measure_median_ns(|| {
std::hint::black_box(g_4n.bfs(&0));
});
assert_not_quadratic("Graph::bfs", t_n, t_4n, 12.0);
}
#[test]
#[ignore] fn trie_insert_linear_scaling() {
let n = 20_000_usize;
let t_n = measure_median_ns(|| {
let mut trie = Trie::new();
for i in 0..n {
trie.insert(&format!("key-{i:08}"));
}
});
let t_4n = measure_median_ns(|| {
let mut trie = Trie::new();
for i in 0..(4 * n) {
trie.insert(&format!("key-{i:08}"));
}
});
assert_not_quadratic("Trie::insert", t_n, t_4n, 10.0);
}
#[test]
#[ignore] fn trie_search_linear_scaling() {
let n = 20_000_usize;
let mut trie_n = Trie::new();
for i in 0..n {
trie_n.insert(&format!("key-{i:08}"));
}
let mut trie_4n = Trie::new();
for i in 0..(4 * n) {
trie_4n.insert(&format!("key-{i:08}"));
}
let t_n = measure_median_ns(|| {
for i in 0..n {
std::hint::black_box(trie_n.search(&format!("key-{i:08}")));
}
});
let t_4n = measure_median_ns(|| {
for i in 0..(4 * n) {
std::hint::black_box(trie_4n.search(&format!("key-{i:08}")));
}
});
assert_not_quadratic("Trie::search", t_n, t_4n, 10.0);
}
#[test]
#[ignore] fn count_min_increment_linear_scaling() {
let n = 20_000_usize;
let t_n = measure_median_ns(|| {
let mut cms = CountMinSketch::new(0.01, 0.01);
for i in 0..n {
cms.increment(i.to_string(), 1);
}
});
let t_4n = measure_median_ns(|| {
let mut cms = CountMinSketch::new(0.01, 0.01);
for i in 0..(4 * n) {
cms.increment(i.to_string(), 1);
}
});
assert_not_quadratic("CountMinSketch::increment", t_n, t_4n, 10.0);
}
#[test]
#[ignore] fn count_min_estimate_linear_scaling() {
let n = 20_000_usize;
let mut cms_n = CountMinSketch::new(0.01, 0.01);
for i in 0..n {
cms_n.increment(i.to_string(), 1);
}
let mut cms_4n = CountMinSketch::new(0.01, 0.01);
for i in 0..(4 * n) {
cms_4n.increment(i.to_string(), 1);
}
let t_n = measure_median_ns(|| {
for i in 0..n {
std::hint::black_box(cms_n.estimate(i.to_string()));
}
});
let t_4n = measure_median_ns(|| {
for i in 0..(4 * n) {
std::hint::black_box(cms_4n.estimate(i.to_string()));
}
});
assert_not_quadratic("CountMinSketch::estimate", t_n, t_4n, 10.0);
}