kdtree-rust 0.1.2

Rust implementation of KDTree
Documentation
use std::ops::{Add, Mul, Sub};
use rand::Rng;
use kdtree_rust::{EuclideanDistance, KDTree};

fn nearest<'a,const D:usize,P>(p:&'a [P;D],positions:&'a [[P;D]]) -> &'a [P;D]
    where P: PartialOrd + Mul + Add + Sub + Default,
          &'a [P;D]: EuclideanDistance<&'a [P;D], Output = P> + 'a {
    let s = &positions[0];
    let mut r = s;

    let mut distance = p.euclidean_distance(r);

    for pt in positions.iter().skip(1) {
        let d = p.euclidean_distance(pt);

        if d <= distance {
            r = pt;
            distance = d;
        }
    }

    r
}
#[test]
fn small_2d() {
    const COUNT:usize = 100;

    let mut kdt = KDTree::<2,f64,()>::new();

    let mut rng = rand::thread_rng();

    let mut positions:Vec<[f64;2]> = vec![];

    for _ in 0..COUNT {
        let mut pn = [0f64;2];

        for i in 0..2 {
            let mut p:f64 = rng.gen_range(-100000.0..100000.0);
            let pi:u8 = rng.gen_range(0..10);

            if let Some(last) = positions.last() {
                if pi == 0 {
                    p = last[i];
                }
            }

            pn[i] = p;
        }

        positions.push(pn.clone());
        kdt.insert(pn,());
    }

    let mut success = 0;

    for _ in 0..COUNT {
        let x:f64 = rng.gen_range(-100000.0..100000.0);
        let y:f64 = rng.gen_range(-100000.0..100000.0);

        let p = [x,y];
        let expected = nearest(&p,&positions);
        let actual = kdt.nearest_position(&p);

        if (p.euclidean_distance(expected) - p.euclidean_distance(&actual.unwrap())) < 1. {
            success += 1;
        } else {
            dbg!(expected,actual.unwrap(),p.euclidean_distance(expected),p.euclidean_distance(&actual.unwrap()));
        }
    }

    println!("正答率 {}%",success as f64 / COUNT as f64 * 100.);
}
#[test]
fn small_3d() {
    const COUNT:usize = 100;

    let mut kdt = KDTree::<3,f64,()>::new();

    let mut rng = rand::thread_rng();

    let mut positions:Vec<[f64;3]> = vec![];

    for _ in 0..COUNT {
        let mut pn = [0f64;3];

        for i in 0..3 {
            let mut p:f64 = rng.gen_range(-100000.0..100000.0);
            let pi:u8 = rng.gen_range(0..10);

            if let Some(last) = positions.last() {
                if pi == 0 {
                    p = last[i];
                }
            }

            pn[i] = p;
        }

        positions.push(pn.clone());
        kdt.insert(pn,());
    }

    let mut success = 0;

    for _ in 0..COUNT {
        let x:f64 = rng.gen_range(-100000.0..100000.0);
        let y:f64 = rng.gen_range(-100000.0..100000.0);
        let z:f64 = rng.gen_range(-100000.0..100000.0);

        let p = [x,y,z];
        let expected = nearest(&p,&positions);
        let actual = kdt.nearest_position(&p);

        if (p.euclidean_distance(expected) - p.euclidean_distance(&actual.unwrap())) < 1. {
            success += 1;
        } else {
            dbg!(expected,actual.unwrap(),p.euclidean_distance(expected),p.euclidean_distance(&actual.unwrap()));
        }
    }

    println!("正答率 {}%",success as f64 / COUNT as f64 * 100.);
}
#[test]
fn small_2d_unbalance() {
    const COUNT:usize = 100;

    let mut kdt = KDTree::<2,f64,()>::new();

    let mut rng = rand::thread_rng();

    let mut positions:Vec<[f64;2]> = vec![];

    for _ in 0..COUNT {
        let mut pn = [0f64;2];

        for i in 0..2 {
            let mut p:f64 = rng.gen_range(-100000.0..100000.0);
            let pi:u8 = rng.gen_range(0..10);

            if let Some(last) = positions.last() {
                if pi == 0 {
                    p = last[i];
                }
            }

            pn[i] = p;
        }

        positions.push(pn.clone());
    }

    positions.sort_by(|a,b| a[0].partial_cmp(&b[0]).unwrap().then(a[1].partial_cmp(&b[1]).unwrap()) );

    for p in &positions {
        kdt.insert(p.clone(),());
    }

    let mut success = 0;

    for _ in 0..COUNT {
        let x:f64 = rng.gen_range(-100000.0..100000.0);
        let y:f64 = rng.gen_range(-100000.0..100000.0);

        let p = [x,y];
        let expected = nearest(&p,&positions);
        let actual = kdt.nearest_position(&p);

        if (p.euclidean_distance(expected) - p.euclidean_distance(&actual.unwrap())) < 1. {
            success += 1;
        } else {
            dbg!(expected,actual.unwrap(),p.euclidean_distance(expected),p.euclidean_distance(&actual.unwrap()));
        }
    }

    println!("正答率 {}%",success as f64 / COUNT as f64 * 100.);
}
#[test]
fn large_2d() {
    const COUNT:usize = 1000;

    let mut kdt = KDTree::<2,f64,()>::new();

    let mut rng = rand::thread_rng();

    let mut positions:Vec<[f64;2]> = vec![];

    for _ in 0..100000 {
        let mut pn = [0f64;2];

        for i in 0..2 {
            let mut p:f64 = rng.gen_range(-100000.0..100000.0);
            let pi:u8 = rng.gen_range(0..10);

            if let Some(last) = positions.last() {
                if pi == 0 {
                    p = last[i];
                }
            }

            pn[i] = p;
        }

        positions.push(pn.clone());
        kdt.insert(pn,());
    }

    for _ in 0..COUNT {
        let x:f64 = rng.gen_range(-100000.0..100000.0);
        let y:f64 = rng.gen_range(-100000.0..100000.0);

        let p = [x,y];
        let _ = kdt.nearest_position(&p);
    }
}
#[test]
fn large_3d() {
    const COUNT:usize = 1000;

    let mut kdt = KDTree::<3,f64,()>::new();

    let mut rng = rand::thread_rng();

    let mut positions:Vec<[f64;3]> = vec![];

    for _ in 0..100000 {
        let mut pn = [0f64;3];

        for i in 0..3 {
            let mut p:f64 = rng.gen_range(-100000.0..100000.0);
            let pi:u8 = rng.gen_range(0..10);

            if let Some(last) = positions.last() {
                if pi == 0 {
                    p = last[i];
                }
            }

            pn[i] = p;
        }

        positions.push(pn.clone());
        kdt.insert(pn,());
    }

    for _ in 0..COUNT {
        let x:f64 = rng.gen_range(-100000.0..100000.0);
        let y:f64 = rng.gen_range(-100000.0..100000.0);
        let z:f64 = rng.gen_range(-100000.0..100000.0);

        let p = [x,y,z];
        let _ = kdt.nearest_position(&p);
    }
}
#[test]
fn large_2d_unbalance() {
    const COUNT:usize = 1000;

    let mut kdt = KDTree::<2,f64,()>::new();

    let mut rng = rand::thread_rng();

    let mut positions:Vec<[f64;2]> = vec![];

    for _ in 0..100000 {
        let mut pn = [0f64;2];

        for i in 0..2 {
            let mut p:f64 = rng.gen_range(-100000.0..100000.0);
            let pi:u8 = rng.gen_range(0..10);

            if let Some(last) = positions.last() {
                if pi == 0 {
                    p = last[i];
                }
            }

            pn[i] = p;
        }

        positions.push(pn.clone());
    }

    positions.sort_by(|a,b| a[0].partial_cmp(&b[0]).unwrap().then(a[1].partial_cmp(&b[1]).unwrap()) );

    for p in &positions {
        kdt.insert(p.clone(),());
    }

    for _ in 0..COUNT {
        let x:f64 = rng.gen_range(-100000.0..100000.0);
        let y:f64 = rng.gen_range(-100000.0..100000.0);

        let p = [x,y];
        let _ = kdt.nearest_position(&p);
    }
}