Skip to main content

knn/
lib.rs

1#![warn(rust_2018_idioms)]
2#![warn(missing_docs)]
3
4//! # KNN
5//!
6//! `knn` provides for fast method of finding exact k nearest neighbours
7//! for higher dimensional data. Also supports custom distance function.
8
9mod heap;
10
11#[derive(Clone)]
12/// The core datastructure of the package.
13/// Stores the points and the distance function.
14pub struct PointCloud<'a, T> {
15    // stores all points
16    points: Vec<&'a T>,
17
18    // return the distance given 2 ponints
19    dist_fn: fn(&T, &T) -> f64,
20}
21
22impl<'a, T> PointCloud<'a, T> {
23    /// Constructs a new `PointCloud<T>`.
24    ///
25    /// It accepts a function to compute distance between any 2 objects.
26    ///
27    /// # Examples
28    /// ```
29    /// extern crate knn;
30    /// use knn::PointCloud;
31    /// let manhattan_dist = |p: &[f64;2], q: &[f64;2]| -> f64 {(p[0] - q[0]).abs() + (p[1] - q[1]).abs()};
32    /// let pc = PointCloud::new(manhattan_dist);
33    /// ```
34    pub fn new(dist_fn: fn(&T, &T) -> f64) -> Self {
35        Self {
36            points: Vec::new(),
37            dist_fn: dist_fn,
38        }
39    }
40
41    /// Adds a point to the PointCloud.
42    ///
43    /// It accepts a reference to an object.
44    ///
45    /// # Examples
46    /// ```
47    /// extern crate knn;
48    /// use knn::PointCloud;
49    /// let dummy_dist = |p: &[f64;2], q: &[f64;2]| -> f64 {0.0};
50    /// let mut pc = PointCloud::new(dummy_dist);
51    /// let p = [1.89, 5.63];
52    /// pc.add_point(&p);
53    /// ```
54    pub fn add_point(&mut self, p: &'a T) {
55        self.points.push(p)
56    }
57
58    /// Gets the k nearest neighbours of an object.
59    ///
60    /// It accepts a reference to the object and how many neighbours to return.
61    ///
62    /// # Example
63    /// ```
64    /// extern crate knn;
65    /// use knn::PointCloud;
66    /// let manhattan_dist = |p: &[f64;2], q: &[f64;2]| -> f64 {(p[0] - q[0]).abs() + (p[1] - q[1]).abs()};
67    /// let mut pc = PointCloud::new(manhattan_dist);
68    /// let points = vec![[1.0, 1.0], [2.0, 2.0], [3.0, 2.0]];
69    /// for p in &points {
70    ///     pc.add_point(&p);
71    /// }
72    /// let q = [0.5, 0.5];
73    /// pc.get_nearest_k(&q, 2);
74    ///
75    /// ```
76    pub fn get_nearest_k(&self, p: &T, k: usize) -> Vec<(f64, &T)> {
77        let mut h = heap::Heap::new(k);
78        for i in 0..self.points.len() {
79            let d = (self.dist_fn)(self.points[i], p);
80            h.insert(d, &self.points[i]);
81        }
82        let mut knn = Vec::new();
83        for i in h.get_elements() {
84            knn.push((i.0, *i.1));
85        }
86        knn
87    }
88
89    /// Get the len / number of objects in PointCloud
90    /// Example:
91    /// ```
92    /// extern crate knn;
93    /// use knn::PointCloud;
94    /// let manhattan_dist = |p: &[f64;2], q: &[f64;2]| -> f64 {(p[0] - q[0]).abs() + (p[1] - q[1]).abs()};
95    /// let mut pc = PointCloud::new(manhattan_dist);
96    /// let points = vec![[1.0, 1.0], [2.0, 2.0], [3.0, 2.0]];
97    /// for p in &points {
98    ///     pc.add_point(&p);
99    /// }
100    /// pc.len();
101    /// ```
102    pub fn len(&self) -> usize {
103        self.points.len()
104    }
105}