cogset 0.2.0

Generic implementations of clustering algorithms. Includes k-means, DBSCAN and OPTICS.
Documentation
use test::Bencher;
use {Euclid, Points, RegionQuery, ListPoints};
use std::slice::Iter;
use std::ops::{RangeFrom, Range};
use std::iter::{Enumerate, Zip};
use rand::{XorShiftRng, Rng};

type E = Euclid<[f64; 1]>;
pub struct SortedScan<'a> {
    x: &'a [E]
}
impl<'a> Points for SortedScan<'a> {
    type Point = usize;
}
impl<'a> RegionQuery for SortedScan<'a> {
    type Neighbours = Neighbours<'a>;
    fn neighbours(&self, &point: &usize, eps: f64) -> Neighbours<'a> {
        Neighbours {
            this: self.x[point].0[0],
            eps: eps,
            backward: self.x[..point].iter().enumerate(),
            forward: (point..).zip(self.x[point..].iter())
        }
    }
}
struct Neighbours<'a> {
    this: f64,
    eps: f64,
    backward: Enumerate<Iter<'a, E>>,
    forward: Zip<RangeFrom<usize>, Iter<'a, E>>,
}
impl<'a> Iterator for Neighbours<'a> {
    type Item = (f64, usize);
    fn next(&mut self) -> Option<(f64, usize)> {
        if let Some((i, p)) = self.backward.next_back() {
            let dist = (p.0[0] - self.this).abs();
            if dist <= self.eps {
                return Some((dist, i))
            }

            self.backward = (&[]).iter().enumerate()
        }
        self.forward.next()
                    .and_then(|(i, p)| {
                        let dist = (p.0[0] - self.this).abs();
                        if dist <= self.eps {Some((dist, i))} else {None}
                    })
    }
}
impl<'a> ListPoints for SortedScan<'a> {
    type AllPoints = Range<usize>;
    fn all_points(&self) -> Range<usize> {
        0..self.x.len()
    }
}

pub fn run<T, F: FnMut(SortedScan, f64, usize) -> T>(b: &mut Bencher, n: usize, mut f: F) {
    let mut rng = XorShiftRng::new_unseeded();
    for _ in 0..100 { rng.gen::<u32>(); }
    let mut points = rng
        .gen_iter::<f64>()
        .take(n)
        .map(|f| Euclid([f]))
        .collect::<Vec<_>>();
    points.sort_by(|a, b| a.0[0].partial_cmp(&b.0[0]).unwrap());

    let eps = 2.0 / n as f64;
    let min_pts = 5;

    b.iter(|| f(SortedScan { x: &points }, eps, min_pts))
}
#[macro_export]
macro_rules! make_benches {
    ($e: expr) => {
        #[cfg(all(test, feature = "unstable"))]
        mod benches {
            use test::Bencher;
            #[bench]
            pub fn small(b: &mut Bencher) {
                ::benches::run(b, 30, $e)
            }
            #[bench]
            pub fn medium(b: &mut Bencher) {
                ::benches::run(b, 100, $e)
            }
            #[bench]
            pub fn large(b: &mut Bencher) {
                ::benches::run(b, 1_000, $e)
            }
            #[bench]
            pub fn huge(b: &mut Bencher) {
                ::benches::run(b, 10_000, $e)
            }
        }
    }
}