2x faster than rtree

This commit is contained in:
Joe 2025-10-16 16:48:14 -07:00
parent 36c1a64e54
commit 4ca8e55dab

View file

@ -1,5 +1,8 @@
use std::{ use std::{
sync::{Arc, RwLock}, sync::{
atomic::{AtomicU64, AtomicUsize, Ordering::Relaxed},
Arc, RwLock,
},
thread, thread,
}; };
@ -8,21 +11,15 @@ struct Point2d {
y: f64, y: f64,
} }
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Default)]
struct PointRef2d {
x: usize,
y: usize,
}
#[derive(Debug, Default, Clone, Copy)]
struct PVal { struct PVal {
point: usize, point: usize,
val: f64, val: AtomicU64,
} }
impl PartialEq for PVal { impl PartialEq for PVal {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
self.val == other.val self.val.load(Relaxed) == other.val.load(Relaxed)
} }
} }
@ -30,7 +27,9 @@ impl Eq for PVal {}
impl PartialOrd for PVal { impl PartialOrd for PVal {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
self.val.partial_cmp(&other.val) let a = f64::from_bits(self.val.load(Relaxed));
let b = f64::from_bits(other.val.load(Relaxed));
a.partial_cmp(&b)
} }
} }
@ -41,33 +40,37 @@ impl Ord for PVal {
} }
struct Spindex2d { struct Spindex2d {
points: Arc<Vec<RwLock<PointRef2d>>>, xpoints: Arc<Vec<AtomicUsize>>,
xs: Arc<RwLock<Vec<RwLock<PVal>>>>, ypoints: Arc<Vec<AtomicUsize>>,
ys: Arc<RwLock<Vec<RwLock<PVal>>>>, xs: Arc<RwLock<Vec<PVal>>>,
ys: Arc<RwLock<Vec<PVal>>>,
} }
impl Spindex2d { impl Spindex2d {
pub fn new(points: &[Point2d]) -> Self { pub fn new(points: &[Point2d]) -> Self {
let mut ps = Vec::with_capacity(points.len()); let mut xpoints = Vec::with_capacity(points.len());
let mut ypoints = Vec::with_capacity(points.len());
let mut xs = Vec::with_capacity(points.len()); let mut xs = Vec::with_capacity(points.len());
let mut ys = Vec::with_capacity(points.len()); let mut ys = Vec::with_capacity(points.len());
for (i, point) in points.iter().enumerate() { for (i, point) in points.iter().enumerate() {
let x = PVal { let x = PVal {
point: i, point: i,
val: point.x, val: AtomicU64::new(point.x.to_bits()),
}; };
xs.push(x.into()); xs.push(x);
let y = PVal { let y = PVal {
point: i, point: i,
val: point.y, val: AtomicU64::new(point.y.to_bits()),
}; };
ys.push(y.into()); ys.push(y);
let p = PointRef2d { x: i, y: i };
ps.push(p.into()); xpoints.push(AtomicUsize::new(i));
ypoints.push(AtomicUsize::new(i));
} }
let index = Self { let index = Self {
points: ps.into(), xpoints: xpoints.into(),
ypoints: ypoints.into(),
xs: Arc::new(RwLock::new(xs)), xs: Arc::new(RwLock::new(xs)),
ys: Arc::new(RwLock::new(ys)), ys: Arc::new(RwLock::new(ys)),
}; };
@ -81,53 +84,48 @@ impl Spindex2d {
/// 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.
pub fn update(&self, points: &[Point2d]) { pub fn update(&self, points: &[Point2d]) {
todo!() let mut xs = self.xs.write().unwrap();
let mut ys = self.ys.write().unwrap();
for (i, point) in points.iter().enumerate() {
let xi = self.xpoints[i].load(Relaxed);
let yi = self.ypoints[i].load(Relaxed);
let x = point.x.to_bits();
let x = PVal {
point: i,
val: x.into(),
};
xs[xi] = x;
let y = point.y.to_bits();
let y = PVal {
point: i,
val: y.into(),
};
ys[yi] = y;
}
self.sort();
} }
fn sort(&self) { fn sort(&self) {
let xs = self.xs.clone(); let xs = self.xs.clone();
let points = self.xpoints.clone();
let xhandle = thread::spawn(move || { let xhandle = thread::spawn(move || {
let mut xs = xs.write().unwrap(); let mut xs = xs.write().unwrap();
xs.sort_unstable_by(|a, b| { xs.sort_unstable();
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() { for (i, x) in xs.iter().enumerate() {
let x = x.read().unwrap();
let p = x.point; let p = x.point;
points[p].write().unwrap().x = i; points[p].store(i, Relaxed);
} }
}); });
let ys = self.ys.clone(); let ys = self.ys.clone();
let points = self.points.clone(); let points = self.ypoints.clone();
let yhandle = thread::spawn(move || { let yhandle = thread::spawn(move || {
let ys = ys.read().unwrap(); let mut ys = ys.write().unwrap();
ys.sort_unstable();
for (i, y) in ys.iter().enumerate() { for (i, y) in ys.iter().enumerate() {
let y = y.read().unwrap();
let p = y.point; let p = y.point;
points[p].write().unwrap().y = i; points[p].store(i, Relaxed);
} }
}); });
@ -185,11 +183,16 @@ fn update_positions(c: &mut Criterion) {
let index = Spindex2d::new(&points); let index = Spindex2d::new(&points);
let mut round = 0; let mut round = 0;
b.iter(|| todo!()); b.iter(|| {
if round % 2 == 0 {
index.update(&jitters);
} else {
index.update(&points);
}
round += 1;
});
}); });
} }
//fn reuse_index(_c: &mut Criterion) {}
criterion_group!(benches, new_index); criterion_group!(benches, new_index);
criterion_main!(benches); criterion_main!(benches);