pub trait Point {
fn dist(&self, other: &Self) -> f64;
#[allow(unused_variables)]
fn dist_lower_bound(&self, other: &Self) -> f64 {
::std::f64::NEG_INFINITY
}
}
pub trait Points {
type Point;
}
pub trait RegionQuery: Points {
type Neighbours: Iterator<Item = Self::Point>;
fn neighbours(&self, point: &Self::Point, epsilon: f64) -> Self::Neighbours;
}
pub trait ListPoints: Points {
type AllPoints: Iterator<Item = Self::Point>;
fn all_points(&self) -> Self::AllPoints;
}
use std::ops::Range;
use std::slice::Iter;
use std::iter::Enumerate;
pub struct BruteScan<'a, P: Point + 'a> {
points: &'a [P]
}
impl<'a, P: Point> BruteScan<'a, P> {
pub fn new(p: &'a [P]) -> BruteScan<'a, P> {
BruteScan { points: p }
}
}
impl<'a,P: Point> Points for BruteScan<'a, P> {
type Point = usize;
}
impl<'a,P: Point> ListPoints for BruteScan<'a, P> {
type AllPoints = Range<usize>;
fn all_points(&self) -> Range<usize> {
0..self.points.len()
}
}
impl<'a, P: Point> RegionQuery for BruteScan<'a, P> {
type Neighbours = BruteScanNeighbours<'a, P>;
fn neighbours(&self, point: &usize, eps: f64) -> BruteScanNeighbours<'a, P> {
BruteScanNeighbours {
points: self.points.iter().enumerate(),
point: &self.points[*point],
eps: eps
}
}
}
pub struct BruteScanNeighbours<'a, P: Point + 'a> {
points: Enumerate<Iter<'a, P>>,
point: &'a P,
eps: f64,
}
impl<'a,P: Point> Iterator for BruteScanNeighbours<'a, P> {
type Item = usize;
fn next(&mut self) -> Option<usize> {
let BruteScanNeighbours { ref mut points, ref point, eps } = *self;
points.find(|&(_, p)| {
point.dist_lower_bound(p) <= eps
&& point.dist(p) <= eps
}).map(|(i, _)| i)
}
}
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
pub struct Euclid<T>(pub T);
macro_rules! euclidean_points {
($($e: expr),*) => {
$(
impl Point for Euclid<[f64; $e]> {
fn dist(&self, other: &Euclid<[f64; $e]>) -> f64 {
self.0.iter().zip(other.0.iter())
.map(|(a, b)| {
let d = *a - *b;
d * d
})
.fold(0.0, |a, b| a + b)
.sqrt()
}
fn dist_lower_bound(&self, other: &Euclid<[f64; $e]>) -> f64 {
(self.0[0] - other.0[0]).abs()
}
}
)*
}
}
euclidean_points!(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn euclid() {
let p1 = Euclid([0.0, 1.0]);
let p2 = Euclid([1.0, 0.0]);
assert!((p1.dist(&p2) - 2f64.sqrt()).abs() < 1e-10);
}
#[test]
fn naive_neigbours() {
let points = [Euclid([0.0]), Euclid([10.0]), Euclid([5.0]), Euclid([2.5])];
let points = BruteScan::new(&points);
assert_eq!(points.neighbours(&0, 1.0).collect::<Vec<_>>(),
[0]);
assert_eq!(points.neighbours(&0, 3.0).collect::<Vec<_>>(),
[0, 3]);
assert_eq!(points.neighbours(&1, 3.0).collect::<Vec<_>>(),
[1]);
assert_eq!(points.neighbours(&1, 10.0).collect::<Vec<_>>(),
[0, 1, 2, 3]);
assert_eq!(points.neighbours(&3, 3.0).collect::<Vec<_>>(),
[0, 2, 3]);
}
}