use std::{ sync::{Arc, RwLock}, thread, }; struct Point2d { x: f64, y: f64, } #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] struct PointRef2d { x: usize, y: usize, } #[derive(Debug, Default, Clone, Copy)] struct PVal { point: usize, val: f64, } impl PartialEq for PVal { fn eq(&self, other: &Self) -> bool { self.val == other.val } } impl Eq for PVal {} impl PartialOrd for PVal { fn partial_cmp(&self, other: &Self) -> Option { self.val.partial_cmp(&other.val) } } impl Ord for PVal { fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.partial_cmp(other).unwrap() } } struct Spindex2d { points: Arc>>, xs: Arc>>>, ys: Arc>>>, } impl Spindex2d { pub fn new(points: &[Point2d]) -> Self { let mut ps = Vec::with_capacity(points.len()); let mut xs = Vec::with_capacity(points.len()); let mut ys = Vec::with_capacity(points.len()); for (i, point) in points.iter().enumerate() { let x = PVal { point: i, val: point.x, }; xs.push(x.into()); let y = PVal { point: i, val: point.y, }; ys.push(y.into()); let p = PointRef2d { x: i, y: i }; ps.push(p.into()); } let index = Self { points: ps.into(), xs: Arc::new(RwLock::new(xs)), ys: Arc::new(RwLock::new(ys)), }; index.sort(); index } /// 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 /// original points. pub fn update(&self, points: &[Point2d]) { todo!() } fn sort(&self) { let xs = self.xs.clone(); let xhandle = thread::spawn(move || { let mut xs = xs.write().unwrap(); xs.sort_unstable_by(|a, b| { let a = a.read().unwrap(); let b = b.read().unwrap(); a.cmp(&b) }); }); let ys = self.ys.clone(); let yhandle = thread::spawn(move || { let mut ys = ys.write().unwrap(); ys.sort_unstable_by(|a, b| { let a = a.read().unwrap(); let b = b.read().unwrap(); a.cmp(&b) }); }); xhandle.join().unwrap(); yhandle.join().unwrap(); let xs = self.xs.clone(); let points = self.points.clone(); let xhandle = thread::spawn(move || { let xs = xs.read().unwrap(); for (i, x) in xs.iter().enumerate() { let x = x.read().unwrap(); let p = x.point; points[p].write().unwrap().x = i; } }); let ys = self.ys.clone(); let points = self.points.clone(); let yhandle = thread::spawn(move || { let ys = ys.read().unwrap(); for (i, y) in ys.iter().enumerate() { let y = y.read().unwrap(); let p = y.point; points[p].write().unwrap().y = i; } }); xhandle.join().unwrap(); yhandle.join().unwrap(); } } use rand::{Rng, SeedableRng}; use rand_hc::Hc128Rng; fn create_random_points(num_points: usize, seed: &[u8; 32]) -> Vec<[f64; 2]> { let mut rng = Hc128Rng::from_seed(*seed); (0..num_points).map(|_| rng.random()).collect() } use criterion::Criterion; use criterion::{criterion_group, criterion_main}; const SEED_1: &[u8; 32] = b"Gv0aHMtHkBGsUXNspGU9fLRuCWkZWHZx"; // const SEED_2: &[u8; 32] = b"km7DO4GeaFZfTcDXVpnO7ZJlgUY7hZiS"; const DEFAULT_NUM_POINTS: usize = 1_000_000; fn new_index(c: &mut Criterion) { c.bench_function("new index", move |b| { let points: Vec<_> = create_random_points(DEFAULT_NUM_POINTS, SEED_1) .into_iter() .map(|[x, y]| Point2d { x, y }) .collect(); b.iter(|| { Spindex2d::new(&points); }); }); } fn update_positions(c: &mut Criterion) { c.bench_function("update positions", move |b| { let points: Vec<_> = create_random_points(DEFAULT_NUM_POINTS, SEED_1) .into_iter() .map(|[x, y]| Point2d { x, y }) .collect(); let mut rng = Hc128Rng::from_seed(*SEED_1); let jitters: Vec<_> = points .iter() .map(|p| { let x = p.x + rng.random_range(-5.0..=5.0); let y = p.y + rng.random_range(-5.0..=5.0); Point2d { x, y } }) .collect(); let index = Spindex2d::new(&points); let mut round = 0; b.iter(|| todo!()); }); } //fn reuse_index(_c: &mut Criterion) {} criterion_group!(benches, new_index); criterion_main!(benches);