Skip to main content

bench_loc/
bench_loc.rs

1//! Bench + golden digest for Series::loc(&[IndexLabel]) (series.loc[[...]]).
2//!
3//! Run: cargo run -p fp-frame --example bench_loc --release
4//!
5//! loc scanned the whole index once PER requested label = O(m·n). A
6//! label->positions multimap built once makes it O(m+n). Duplicate index
7//! labels return all matches in ascending index order; selector order and
8//! duplicate selectors are preserved; a missing label fails closed.
9
10use std::time::Instant;
11
12use fp_frame::Series;
13use fp_index::IndexLabel;
14use fp_types::Scalar;
15
16fn s_from(labels: Vec<i64>, vals: Vec<i64>) -> Series {
17    let idx: Vec<IndexLabel> = labels.into_iter().map(IndexLabel::Int64).collect();
18    let sc: Vec<Scalar> = vals.into_iter().map(Scalar::Int64).collect();
19    Series::from_values("s", idx, sc).unwrap()
20}
21
22fn golden() -> String {
23    let mut out = String::new();
24    // Duplicate index label 10 at positions 0 and 2.
25    let s = s_from(vec![10, 20, 10, 30], vec![100, 200, 300, 400]);
26    // Selector order [10, 30, 20]; 10 returns both matches (asc position).
27    let r = s
28        .loc(&[
29            IndexLabel::Int64(10),
30            IndexLabel::Int64(30),
31            IndexLabel::Int64(20),
32        ])
33        .unwrap();
34    out.push_str(&format!("labels={:?}\n", r.index().labels()));
35    out.push_str(&format!("values={:?}\n", r.values()));
36    // Duplicate selector entries preserved.
37    let r2 = s
38        .loc(&[IndexLabel::Int64(20), IndexLabel::Int64(20)])
39        .unwrap();
40    out.push_str(&format!("dup_sel_values={:?}\n", r2.values()));
41    // Missing label fails closed.
42    let err = s.loc(&[IndexLabel::Int64(99)]);
43    out.push_str(&format!("missing_is_err={}\n", err.is_err()));
44    out
45}
46
47fn main() {
48    let g = golden();
49    print!("GOLDEN_BEGIN\n{g}GOLDEN_END\n");
50
51    let n: usize = 60_000;
52    let labels: Vec<i64> = (0..n as i64).collect();
53    let vals: Vec<i64> = (0..n as i64).map(|v| v * 2).collect();
54    let s = s_from(labels.clone(), vals);
55    let selector: Vec<IndexLabel> = (0..n as i64).map(IndexLabel::Int64).collect();
56
57    let t = Instant::now();
58    let r = s.loc(&selector).unwrap();
59    let d = t.elapsed();
60    assert_eq!(r.len(), n);
61
62    println!("TIMING n={n} m={n} loc={:.3}ms", d.as_secs_f64() * 1e3);
63}