sdd / kiddo

Kiddo
Apache License 2.0
79 stars 13 forks source link

Kiddo

A high-performance, flexible, ergonomic k-d tree library. Possibly the fastest k-d tree library in the world? See for yourself.

Kiddo is ideal for super-fast spatial / geospatial lookups and nearest-neighbour / KNN queries for low-ish numbers of dimensions, where you want to ask questions such as:

Kiddo provides:

Usage

Add kiddo to Cargo.toml

[dependencies]
kiddo = "4.2.0"

Add points to kdtree and query nearest n points with distance function

use kiddo::{KdTree, SquaredEuclidean};

let entries = vec![
    [0f64, 0f64],
    [1f64, 1f64],
    [2f64, 2f64],
    [3f64, 3f64]
];

// use the kiddo::KdTree type to get up and running quickly with default settings
let mut tree: KdTree<_, 2> = (&entries).into();

// How many items are in tree?
assert_eq!(tree.size(), 4);

// find the nearest item to [0f64, 0f64].
// returns an instance of kiddo::NearestNeighbour
let nearest = tree.nearest_one::<SquaredEuclidean>(&[0f64, 0f64]);
assert_eq!(nearest.distance, 0f64);
assert_eq!(nearest.item, 0);

// find the nearest 3 items to [0f64, 0f64]
// // returns an Vec of kiddo::NearestNeighbour
let nearest_n: Vec<_> = tree.nearest_n::<SquaredEuclidean>(&[0f64, 0f64], 3);
assert_eq!(
    nearest_n.iter().map(|x|(x.distance, x.item)).collect::<Vec<_>>(),
    vec![(0f64, 0), (2f64, 1), (8f64, 2)]
);

See the examples documentation for some more detailed examples.

Optional Features

The Kiddo crate exposes the following features. Any labelled as (NIGHTLY) are not available on stable Rust as they require some unstable features. You'll need to build with nightly in order to user them.

v3.x

Version 3.x changed the distance metrics syntax, switching from function pointers to a trait-based approach that permitted some ergonomics and performance improvements. This is a breaking change though: whereas prior to v3, you may have had queries that look like this:

use kiddo::distance::squared_euclidean;
let result = kdtree.nearest_one(&[0f64, 0f64], &squared_euclidean);

Now for v3 onwards, you'll need to switch to this syntax:

use kiddo::SquaredEuclidean;
let result = kdtree.nearest_one::<SquaredEuclidean>(&[0f64, 0f64]);

V3 also introduces the ImmutableKdTree variant. Designed for use cases where all the points that you need to add to the tree are known up-front, and no modifications need to be made after the tree is initially populated. ImmutableKdTree balances and optimises the tree at construction time, ensuring much more efficient memory usage (and a correspondingly smaller size on-disk for serialized trees). Since the interior nodes of the ImmutableKdTree also take up less space in memory, more of them can fit in the CPU cache, potentially improving performance in some cases.

v2.x

Version 2.x was a complete rewrite, providing:

Benchmarks

The results of all the below benchmarks are viewable in an interactive webapp over at https://sdd.github.io/kd-tree-comparison-webapp/.

The comparative benchmark suite is located in another project, https://github.com/sdd/kd-tree-comparison.

Criterion was used to perform a series of benchmarks. We compare Kiddo v3 to:

The following activities are benchmarked (where implemented):

The benchmarks are repeated against 2d, 3d and 4d trees, as well as with points that are both of type f32 and of type f64, as well as a 16-bit fixed point use case for Kiddo v2.

The trees are populated with random source data whose points are all on a unit sphere. This use case is representative of common kd-tree usages in geospatial and astronomical contexts.

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.