add tweakable horizon and benchmark

This commit is contained in:
Joe 2025-10-18 14:22:28 -07:00
parent 54655dd971
commit 0ecee89421
2 changed files with 44 additions and 14 deletions

View file

@ -14,7 +14,7 @@ use criterion::{criterion_group, criterion_main};
const SEED_1: &[u8; 32] = b"Gv0aHMtHkBGsUXNspGU9fLRuCWkZWHZx"; const SEED_1: &[u8; 32] = b"Gv0aHMtHkBGsUXNspGU9fLRuCWkZWHZx";
// const SEED_2: &[u8; 32] = b"km7DO4GeaFZfTcDXVpnO7ZJlgUY7hZiS"; // const SEED_2: &[u8; 32] = b"km7DO4GeaFZfTcDXVpnO7ZJlgUY7hZiS";
const DEFAULT_NUM_POINTS: usize = 1_000_000; const DEFAULT_NUM_POINTS: usize = 100_000;
fn new_index(c: &mut Criterion) { fn new_index(c: &mut Criterion) {
c.bench_function("new index", move |b| { c.bench_function("new index", move |b| {
@ -60,8 +60,8 @@ fn update_positions(c: &mut Criterion) {
}); });
} }
fn nearest(c: &mut Criterion) { fn nearest_default_horizon(c: &mut Criterion) {
c.bench_function("nearst point", move |b| { c.bench_function("nearst point with default horizon", move |b| {
let points: Vec<_> = create_random_points(DEFAULT_NUM_POINTS, SEED_1) let points: Vec<_> = create_random_points(DEFAULT_NUM_POINTS, SEED_1)
.into_iter() .into_iter()
.map(|[x, y]| Point2d { x, y }) .map(|[x, y]| Point2d { x, y })
@ -71,11 +71,34 @@ fn nearest(c: &mut Criterion) {
let mut i = 0; let mut i = 0;
b.iter(|| { b.iter(|| {
index.nearest(&points[i]);
i += 1; i += 1;
index.nearest(&points[i - 1]).is_some()
}); });
}); });
} }
criterion_group!(benches, new_index, update_positions, nearest); fn nearest_short_horizon(c: &mut Criterion) {
c.bench_function("nearst point with short horizon", move |b| {
let points: Vec<_> = create_random_points(DEFAULT_NUM_POINTS, SEED_1)
.into_iter()
.map(|[x, y]| Point2d { x, y })
.collect();
let index = Spindex2d::new(&points).with_horizon(20);
let mut i = 0;
b.iter(|| {
i += 1;
index.nearest(&points[i - 1]).is_some()
});
});
}
criterion_group!(
benches,
new_index,
update_positions,
nearest_default_horizon,
nearest_short_horizon
);
criterion_main!(benches); criterion_main!(benches);

View file

@ -67,7 +67,7 @@ impl PVal {
pub struct Spindex2d { pub struct Spindex2d {
pub xs: RwLock<Vec<PVal>>, pub xs: RwLock<Vec<PVal>>,
pub ys: RwLock<Vec<PVal>>, pub ys: RwLock<Vec<PVal>>,
len: usize, horizon: usize,
} }
impl Spindex2d { impl Spindex2d {
@ -92,10 +92,11 @@ impl Spindex2d {
}); });
}); });
let horizon = (len / (10usize.pow(len.ilog10() / 2))).max(50);
let index = Self { let index = Self {
xs: xs.into(), xs: xs.into(),
ys: ys.into(), ys: ys.into(),
len, horizon,
}; };
index.sort(); index.sort();
@ -103,6 +104,10 @@ impl Spindex2d {
index index
} }
pub fn with_horizon(self, horizon: usize) -> Self {
Self { horizon, ..self }
}
/// This method assumes that the points have the same cardinality and order as the points used /// This method assumes that the points have the same cardinality and order as the points used
/// when constructing this index. May panic if the updated points argument is longer than the /// when constructing this index. May panic if the updated points argument is longer than the
/// original points. /// original points.
@ -148,16 +153,18 @@ impl Spindex2d {
let xs = self.xs.read().unwrap(); let xs = self.xs.read().unwrap();
let ys = self.ys.read().unwrap(); let ys = self.ys.read().unwrap();
let mut nxs = HashMap::with_capacity(100); let len = xs.len();
let mut nys = HashMap::with_capacity(100); let horizon = self.horizon;
let mut nxs = HashMap::with_capacity(horizon * 2);
let mut nys = HashMap::with_capacity(horizon * 2);
thread::scope(|s| { thread::scope(|s| {
s.spawn(|| { s.spawn(|| {
let p = PVal::new(0, x); let p = PVal::new(0, x);
let nx = match xs.binary_search(&p) { let nx = match xs.binary_search(&p) {
Ok(i) | Err(i) => i, Ok(i) | Err(i) => i,
}; };
let start = nx.saturating_sub(50); let start = nx.saturating_sub(horizon);
let end = (nx + (50)).min(self.len); let end = (nx + horizon).min(len);
for p in xs[start..end].iter() { for p in xs[start..end].iter() {
nxs.insert(p.point_index(), p.val()); nxs.insert(p.point_index(), p.val());
} }
@ -168,14 +175,14 @@ impl Spindex2d {
let ny = match ys.binary_search(&p) { let ny = match ys.binary_search(&p) {
Ok(i) | Err(i) => i, Ok(i) | Err(i) => i,
}; };
let start = ny.saturating_sub(50); let start = ny.saturating_sub(horizon);
let end = (ny + 50).min(self.len); let end = (ny + horizon).min(len);
for p in ys[start..end].iter() { for p in ys[start..end].iter() {
nys.insert(p.point_index(), p.val()); nys.insert(p.point_index(), p.val());
} }
}); });
}); });
let mut points = Vec::with_capacity(100); let mut points = Vec::with_capacity(horizon * 2);
for (id, xval) in nxs.into_iter() { for (id, xval) in nxs.into_iter() {
if let Some(&yval) = nys.get(&id) { if let Some(&yval) = nys.get(&id) {
points.push(Point2d::new(xval, yval)); points.push(Point2d::new(xval, yval));