From d8f9bd268fb0d2f318189cd6d0f03f7b3be56423 Mon Sep 17 00:00:00 2001 From: Bomen Derick Date: Fri, 4 Oct 2024 01:48:35 +0100 Subject: [PATCH 1/6] kd-tree implementation in Rust --- src/data_structures/kd_tree.rs | 386 +++++++++++++++++++++++++++++++++ 1 file changed, 386 insertions(+) create mode 100644 src/data_structures/kd_tree.rs diff --git a/src/data_structures/kd_tree.rs b/src/data_structures/kd_tree.rs new file mode 100644 index 00000000000..4ab83ec7369 --- /dev/null +++ b/src/data_structures/kd_tree.rs @@ -0,0 +1,386 @@ +use std::iter::Sum; +use num_traits::{abs, real::Real, Signed}; + +#[derive(Debug, Clone, PartialEq)] +struct KDNode { + point: [T; K], + left: Option>>, + right: Option>> +} + +impl KDNode { + fn new(point: [T; K]) -> Self { + KDNode { + point, + left: None, + right: None + } + } + +} + +#[derive(Debug)] +struct KDTree { + root: Option>>, + size: usize +} + +impl KDTree { + // Create and empty kd-tree + pub fn new() -> Self { + KDTree { + root: None, + size: 0 + } + } + + // Returns true if point found, false otherwise + pub fn search(&self, point: &[T; K]) -> bool { + search_rec(&self.root, point, 0) + } + + // Returns true if successfully delete a point, false otherwise + pub fn insert(&mut self, point: [T; K]) -> bool { + let inserted: bool = insert_rec(&mut self.root, point, 0); + if inserted { + self.size += 1; + } + inserted + } + + // Returns true if successfully delete a point + pub fn delete(&mut self, point: &[T; K]) -> bool { + let deleted = delete_rec(&mut self.root, point, 0); + if deleted { + self.size -= 1; + } + deleted + } + + // Returns the nearest neighbors of a given point with their respective disatances + pub fn nearest_neighbors(&self, point: &[T; K], n: usize) -> Vec<(T, [T; K])> + where + T: Sum + Signed + Real + { + let mut neighbors: Vec<(T, [T; K])> = Vec::new(); + n_nearest_neighbors(&self.root, point, n, 0, &mut neighbors); + neighbors.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap()); + neighbors + } + + // Returns the number of points in a kd-tree + pub fn len(&self) -> usize { + self.size + } + + // Returns the depth a kd-tree + pub fn depth(&self) -> usize { + depth_rec(&self.root, 0, 0) + } + + // Determine whether there exist points in a kd-tree or not + pub fn is_empty(&self) -> bool { + self.root.is_none() + } + + // Returns a kd-tree built from a vector points + pub fn build(points: Vec<[T; K]>) -> KDTree { + let mut tree = KDTree::new(); + if points.is_empty() { + tree + } else { + tree.size = points.len(); + tree.root = build_rec(points, 0); + + tree + } + } + + // Merging two KDTrees by collecting points and rebuilding + pub fn merge(&mut self, other: &mut Self) -> Self { + let mut points: Vec<[T; K]> = Vec::new(); + collect_points(&self.root, &mut points); + collect_points(&other.root, &mut points); + KDTree::build(points) + } +} + +// Helper functions ............................................................................ + +// Recursively insert a point in a kd-tree +fn insert_rec(kd_tree: &mut Option>>, point: [T; K], depth: usize) -> bool { + if let Some(ref mut kd_node) = kd_tree { + let axis: usize = depth % K; + if point[axis] < kd_node.point[axis] { + insert_rec(&mut kd_node.left, point, depth + 1) + } else if point == kd_node.point { + false + } else { + insert_rec(&mut kd_node.right, point, depth + 1) + } + } else { + *kd_tree = Some(Box::new(KDNode::new(point))); + true + } +} + +// Recursively search for a given point in a kd-tree +fn search_rec(kd_tree: &Option>>, point: &[T; K], depth: usize) -> bool { + if let Some(kd_node) = kd_tree { + if point == &kd_node.point { + true + } else { + let axis: usize = depth % K; + if point[axis] < kd_node.point[axis] { + search_rec(&kd_node.left, point, depth + 1) + } else { + search_rec(&kd_node.right, point, depth + 1) + } + } + } else { + false + } +} + +// Recursively delete a point from a kd-tree +fn delete_rec(kd_node: &mut Option>>, point: &[T; K], depth: usize) -> bool { + if let Some(current_node) = kd_node { + let axis: usize = depth % K; + if current_node.point == *point { + if current_node.right.is_some() { + // safe to use `unwrap()` since we know for sure there exist a node + let min_point = min_node(current_node.right.as_ref(), axis, 0).unwrap().point; + + current_node.point = min_point; + delete_rec(&mut current_node.right, ¤t_node.point, depth + 1) + } else if current_node.left.is_some() { + let min_point: [T; K] = min_node(current_node.left.as_ref(), axis, 0).unwrap().point; + + current_node.point = min_point; + current_node.right = current_node.left.take(); + delete_rec(&mut current_node.right, ¤t_node.point, depth + 1) + }else { + *kd_node = None; + true + } + } else if point[axis].lt(¤t_node.point[axis]) { + delete_rec(&mut current_node.left, point, depth + 1) + } else { + delete_rec(&mut current_node.right, point, depth + 1) + } + } else { + false + } +} + +/// Recursively build a kd-tree from a vector of points by taking the median of a sorted +/// vector of points as the root to maintain a balance kd-tree +fn build_rec(mut points: Vec<[T; K]>, depth: usize) -> Option>> { + if points.is_empty() { + None + } else { + let axis = depth % K; + points.sort_by(|a, b| a[axis].partial_cmp(&b[axis]).unwrap_or(std::cmp::Ordering::Equal)); + + let median: usize = points.len() / 2; + let mut node: KDNode = KDNode::new(points[median]); + + node.left = build_rec(points[..median].to_vec(), depth + 1); + node.right = build_rec(points[median + 1..].to_vec(), depth + 1); + + Some(Box::new(node)) + } +} + +// Returns the depth of the deepest branch of a kd-tree. +fn depth_rec(kd_tree: &Option>>, left_depth: usize, right_depth: usize) -> usize { + if let Some(kd_node) = kd_tree { + match (&kd_node.left, &kd_node.right) { + (None, None) => left_depth.max(right_depth), + (None, Some(_)) => depth_rec(&kd_node.left, left_depth + 1, right_depth), + (Some(_), None) => depth_rec(&kd_node.right, left_depth, right_depth + 1), + (Some(_), Some(_)) => depth_rec(&kd_node.left, left_depth + 1, right_depth).max(depth_rec(&kd_node.right, left_depth, right_depth + 1)), + } + } else { + left_depth.max(right_depth) + } +} + +// Collect all points from a given KDTree into a vector +fn collect_points(kd_node: &Option>>, points: &mut Vec<[T; K]>) { + if let Some(current_node) = kd_node { + points.push(current_node.point); + collect_points(¤t_node.left, points); + collect_points(¤t_node.right, points); + } +} + +// Calculate the distance between two points +fn distance(point_1: &[T; K], point_2: &[T; K]) -> T +where + T: PartialOrd + Copy + Sum + Real +{ + point_1 + .iter() + .zip(point_2.iter()) + .map(|(&a, &b)| { + let diff: T = a - b; + diff * diff + }) + .sum::() + .sqrt() +} + +// Returns the minimum nodes among three kd-nodes on a given axis +fn min_node_on_axis<'a, T: PartialOrd + Copy, const K: usize>(kd_node: &'a KDNode, left: Option<&'a KDNode>, right: Option<&'a KDNode>, axis: usize) -> &'a KDNode { + let mut current_min_node = kd_node; + if let Some(left_node) = left { + if left_node.point[axis].lt(¤t_min_node.point[axis]) { + current_min_node = left_node; + } + } + if let Some(right_node) = right { + if right_node.point[axis].lt(¤t_min_node.point[axis]) { + current_min_node = right_node; + } + } + current_min_node +} + +// Returns the minimum node of a kd-tree with respect to an axis +fn min_node(kd_node: Option<&Box>>, axis: usize, depth: usize) -> Option<&KDNode> { + if let Some(current_node) = kd_node { + let current_axis = depth % K; + if current_axis == axis { + if current_node.left.is_some() { + min_node(current_node.left.as_ref(), axis, depth + 1) + } else { + Some(current_node) + } + } else { + let (left_min, right_min): (Option<&KDNode>, Option<&KDNode>) = ( + min_node(current_node.left.as_ref(), axis, depth + 1), + min_node(current_node.right.as_ref(), axis, depth + 1) + ); + Some(min_node_on_axis(current_node, left_min, right_min, axis)) + } + } else { + None + } +} + +// Find the nearest neighbors of a given point. The number neighbors is determine by the variable `n`. +fn n_nearest_neighbors(kd_tree: &Option>>, point: &[T; K], n: usize, depth: usize, neighbors: &mut Vec<(T, [T; K])>) +where + T: PartialOrd + Copy + Sum + Real + Signed +{ + if let Some(kd_node) = kd_tree { + let distance: T = distance(&kd_node.point, point); + if neighbors.len() < n { + neighbors.push((distance, kd_node.point)); + } else { + // safe to call unwrap() since we know our neighbors is ont empty in this scope + let max_distance = neighbors.iter().max_by(|a, b| a.0.partial_cmp(&b.0).unwrap()).unwrap().0; + if distance < max_distance { + if let Some(pos) = neighbors.iter().position(|x| x.0 == max_distance) { + neighbors[pos] = (distance, kd_node.point); + } + } + } + + let axis: usize = depth % K; + let target_axis: T = point[axis]; + let split_axis: T = kd_node.point[axis]; + + let (look_first, look_second) = if target_axis < split_axis { + (&kd_node.left, &kd_node.right) + } else { + (&kd_node.right, &kd_node.left) + }; + + if look_first.is_some() { + n_nearest_neighbors(&look_first, point, n, depth + 1, neighbors); + } + + // Check if it's necessary to look on the other branch by computing the distance between our current point with the nearest point on the other branch + if look_second.is_some() { + let max_distance = neighbors.iter().max_by(|a, b| a.0.partial_cmp(&b.0).unwrap()).unwrap().0; + if neighbors.len() < n || abs(target_axis - split_axis) < max_distance { + n_nearest_neighbors(&look_second, point, n, depth + 1, neighbors); + } + } + } +} + + +#[cfg(test)] +mod test { + use super::KDTree; + + #[test] + fn insert() { + let mut kd_tree: KDTree = KDTree::new(); + assert_eq!(kd_tree.insert([2.0, 3.0]), true); + // Cannot insert the same point again + assert_eq!(kd_tree.insert([2.0, 3.0]), false); + assert_eq!(kd_tree.insert([2.0, 3.1]), true); + } + + #[test] + fn contains() { + let points = vec![[2.0, 3.0], [5.0, 4.0], [9.0, 6.0], [4.0, 7.0]]; + let kd_tree = KDTree::build(points); + assert_eq!(kd_tree.search(&[5.0, 4.0]), true); + assert_eq!(kd_tree.search(&[5.0, 4.1]), false); + } + + #[test] + fn remove() { + let points = vec![[2.0, 3.0], [5.0, 4.0], [9.0, 6.0], [4.0, 7.0]]; + let mut kd_tree = KDTree::build(points); + assert_eq!(kd_tree.delete(&[5.0, 4.0]), true); + // Cannot remove twice + assert_eq!(kd_tree.delete(&[5.0, 4.0]), false); + assert_eq!(kd_tree.search(&[5.0, 4.0]), false); + } + + #[test] + fn nearest_neighbors() { + let points = vec![[2.0, 3.0], [5.0, 4.0], [9.0, 6.0], [4.0, 7.0], [8.0, 1.0], [7.0, 2.0]]; + let kd_tree = KDTree::build(points); + // for the point [5.0, 3.0] it's obvious that [5.0, 4.0] is one of its closest neighbor with a distance of 1.0 + assert!(kd_tree.nearest_neighbors(&[5.0, 3.0], 2).contains(&(1.0, [5.0, 4.0]))); + } + + #[test] + fn is_empty() { + let mut kd_tree = KDTree::new(); + assert_eq!(kd_tree.is_empty(), true); + kd_tree.insert([1.5, 3.0]); + assert_eq!(kd_tree.is_empty(), false); + } + + #[test] + fn len_and_depth() { + let points = vec![[2.0, 3.0], [5.0, 4.0], [9.0, 6.0], [4.0, 7.0], [8.0, 1.0], [7.0, 2.0]]; + let size = points.len(); + let tree = KDTree::build(points); + assert_eq!(tree.len(), size); + assert_eq!(tree.depth(), 2); + } + + #[test] + fn merge() { + let points_1 = vec![[2.0, 3.0], [5.0, 4.0], [9.0, 6.0]]; + let points_2 = vec![[4.0, 7.0], [8.0, 1.0], [7.0, 2.0]]; + + let mut kd_tree_1 = KDTree::build(points_1); + let mut kd_tree_2 = KDTree::build(points_2); + + let kd_tree_3 = kd_tree_1.merge(&mut kd_tree_2); + + // Making sure the resulted kd-tree contains points from both kd-trees + assert!(kd_tree_3.search(&[9.0, 6.0])); + assert!(kd_tree_3.search(&[8.0, 1.0])); + } +} From e413665c48d71e30f10be4ea5898a3d47c6d3d9e Mon Sep 17 00:00:00 2001 From: Bomen Derick Date: Fri, 4 Oct 2024 15:28:13 +0100 Subject: [PATCH 2/6] Follow contribution guidelines --- DIRECTORY.md | 1 + src/data_structures/kd_tree.rs | 206 +++++++++++++++++++++++---------- src/data_structures/mod.rs | 2 + 3 files changed, 148 insertions(+), 61 deletions(-) diff --git a/DIRECTORY.md b/DIRECTORY.md index 1dd188f69a8..e3dc50e16da 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -64,6 +64,7 @@ * [Graph](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/graph.rs) * [Hash Table](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/hash_table.rs) * [Heap](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/heap.rs) + * [KD Tree](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/kd_tree.rs) * [Lazy Segment Tree](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/lazy_segment_tree.rs) * [Linked List](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/linked_list.rs) * Probabilistic diff --git a/src/data_structures/kd_tree.rs b/src/data_structures/kd_tree.rs index 4ab83ec7369..a57366aedb3 100644 --- a/src/data_structures/kd_tree.rs +++ b/src/data_structures/kd_tree.rs @@ -1,41 +1,51 @@ -use std::iter::Sum; use num_traits::{abs, real::Real, Signed}; +use std::iter::Sum; -#[derive(Debug, Clone, PartialEq)] +/// Internal node of a `KDTree` +/// +/// `point` contains the data of the node +/// `left` and `right` for branching struct KDNode { point: [T; K], left: Option>>, - right: Option>> + right: Option>>, } impl KDNode { + // Create a new node `KDNode` from a given point fn new(point: [T; K]) -> Self { KDNode { point, left: None, - right: None + right: None, } } - } -#[derive(Debug)] -struct KDTree { +// A `KDTree` with a `root` node and a `size` to represent the number of points in the kd-tree +pub struct KDTree { root: Option>>, - size: usize + size: usize, +} + +impl Default for KDTree { + fn default() -> Self { + Self::new() + } } impl KDTree { // Create and empty kd-tree + // #[must_use] pub fn new() -> Self { KDTree { root: None, - size: 0 + size: 0, } } // Returns true if point found, false otherwise - pub fn search(&self, point: &[T; K]) -> bool { + pub fn contains(&self, point: &[T; K]) -> bool { search_rec(&self.root, point, 0) } @@ -57,35 +67,38 @@ impl KDTree { deleted } - // Returns the nearest neighbors of a given point with their respective disatances - pub fn nearest_neighbors(&self, point: &[T; K], n: usize) -> Vec<(T, [T; K])> + // Returns the nearest neighbors of a given point with their respective distances + pub fn nearest_neighbors(&self, point: &[T; K], n: usize) -> Vec<(T, [T; K])> where - T: Sum + Signed + Real + T: Sum + Signed + Real, { let mut neighbors: Vec<(T, [T; K])> = Vec::new(); n_nearest_neighbors(&self.root, point, n, 0, &mut neighbors); - neighbors.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap()); neighbors } // Returns the number of points in a kd-tree + // #[must_use] pub fn len(&self) -> usize { self.size } // Returns the depth a kd-tree + // #[must_use] pub fn depth(&self) -> usize { depth_rec(&self.root, 0, 0) } // Determine whether there exist points in a kd-tree or not + // #[must_use] pub fn is_empty(&self) -> bool { self.root.is_none() } // Returns a kd-tree built from a vector points + // #[must_use] pub fn build(points: Vec<[T; K]>) -> KDTree { - let mut tree = KDTree::new(); + let mut tree: KDTree = KDTree::new(); if points.is_empty() { tree } else { @@ -96,7 +109,9 @@ impl KDTree { } } - // Merging two KDTrees by collecting points and rebuilding + /// Returns a `KDTree` containing both trees + /// Merging two KDTrees by collecting points and rebuilding + // #[must_use] pub fn merge(&mut self, other: &mut Self) -> Self { let mut points: Vec<[T; K]> = Vec::new(); collect_points(&self.root, &mut points); @@ -108,7 +123,11 @@ impl KDTree { // Helper functions ............................................................................ // Recursively insert a point in a kd-tree -fn insert_rec(kd_tree: &mut Option>>, point: [T; K], depth: usize) -> bool { +fn insert_rec( + kd_tree: &mut Option>>, + point: [T; K], + depth: usize, +) -> bool { if let Some(ref mut kd_node) = kd_tree { let axis: usize = depth % K; if point[axis] < kd_node.point[axis] { @@ -119,13 +138,18 @@ fn insert_rec(kd_tree: &mut Option = KDNode::new(point); + *kd_tree = Some(Box::new(nde)); true } } // Recursively search for a given point in a kd-tree -fn search_rec(kd_tree: &Option>>, point: &[T; K], depth: usize) -> bool { +fn search_rec( + kd_tree: &Option>>, + point: &[T; K], + depth: usize, +) -> bool { if let Some(kd_node) = kd_tree { if point == &kd_node.point { true @@ -143,23 +167,31 @@ fn search_rec(kd_tree: &Option(kd_node: &mut Option>>, point: &[T; K], depth: usize) -> bool { +fn delete_rec( + kd_node: &mut Option>>, + point: &[T; K], + depth: usize, +) -> bool { if let Some(current_node) = kd_node { let axis: usize = depth % K; if current_node.point == *point { if current_node.right.is_some() { // safe to use `unwrap()` since we know for sure there exist a node - let min_point = min_node(current_node.right.as_ref(), axis, 0).unwrap().point; - + let min_point = min_node(current_node.right.as_deref(), axis, 0) + .unwrap() + .point; + current_node.point = min_point; delete_rec(&mut current_node.right, ¤t_node.point, depth + 1) } else if current_node.left.is_some() { - let min_point: [T; K] = min_node(current_node.left.as_ref(), axis, 0).unwrap().point; - + let min_point: [T; K] = min_node(current_node.left.as_deref(), axis, 0) + .unwrap() + .point; + current_node.point = min_point; current_node.right = current_node.left.take(); delete_rec(&mut current_node.right, ¤t_node.point, depth + 1) - }else { + } else { *kd_node = None; true } @@ -173,14 +205,21 @@ fn delete_rec(kd_node: &mut Option(mut points: Vec<[T; K]>, depth: usize) -> Option>> { +fn build_rec( + mut points: Vec<[T; K]>, + depth: usize, +) -> Option>> { if points.is_empty() { None } else { let axis = depth % K; - points.sort_by(|a, b| a[axis].partial_cmp(&b[axis]).unwrap_or(std::cmp::Ordering::Equal)); + points.sort_by(|a, b| { + a[axis] + .partial_cmp(&b[axis]) + .unwrap_or(std::cmp::Ordering::Equal) + }); let median: usize = points.len() / 2; let mut node: KDNode = KDNode::new(points[median]); @@ -193,21 +232,29 @@ fn build_rec(mut points: Vec<[T; K]>, dept } // Returns the depth of the deepest branch of a kd-tree. -fn depth_rec(kd_tree: &Option>>, left_depth: usize, right_depth: usize) -> usize { +fn depth_rec( + kd_tree: &Option>>, + left_depth: usize, + right_depth: usize, +) -> usize { if let Some(kd_node) = kd_tree { match (&kd_node.left, &kd_node.right) { (None, None) => left_depth.max(right_depth), (None, Some(_)) => depth_rec(&kd_node.left, left_depth + 1, right_depth), (Some(_), None) => depth_rec(&kd_node.right, left_depth, right_depth + 1), - (Some(_), Some(_)) => depth_rec(&kd_node.left, left_depth + 1, right_depth).max(depth_rec(&kd_node.right, left_depth, right_depth + 1)), + (Some(_), Some(_)) => depth_rec(&kd_node.left, left_depth + 1, right_depth) + .max(depth_rec(&kd_node.right, left_depth, right_depth + 1)), } } else { left_depth.max(right_depth) } } -// Collect all points from a given KDTree into a vector -fn collect_points(kd_node: &Option>>, points: &mut Vec<[T; K]>) { +// Collect all points from a given `KDTree` into a vector +fn collect_points( + kd_node: &Option>>, + points: &mut Vec<[T; K]>, +) { if let Some(current_node) = kd_node { points.push(current_node.point); collect_points(¤t_node.left, points); @@ -216,13 +263,13 @@ fn collect_points(kd_node: &Option(point_1: &[T; K], point_2: &[T; K]) -> T -where - T: PartialOrd + Copy + Sum + Real +fn distance(point_1: &[T; K], point_2: &[T; K]) -> T +where + T: PartialOrd + Copy + Sum + Real, { point_1 .iter() - .zip(point_2.iter()) + .zip(point_2.iter()) .map(|(&a, &b)| { let diff: T = a - b; diff * diff @@ -232,7 +279,12 @@ where } // Returns the minimum nodes among three kd-nodes on a given axis -fn min_node_on_axis<'a, T: PartialOrd + Copy, const K: usize>(kd_node: &'a KDNode, left: Option<&'a KDNode>, right: Option<&'a KDNode>, axis: usize) -> &'a KDNode { +fn min_node_on_axis<'a, T: PartialOrd + Copy, const K: usize>( + kd_node: &'a KDNode, + left: Option<&'a KDNode>, + right: Option<&'a KDNode>, + axis: usize, +) -> &'a KDNode { let mut current_min_node = kd_node; if let Some(left_node) = left { if left_node.point[axis].lt(¤t_min_node.point[axis]) { @@ -247,20 +299,24 @@ fn min_node_on_axis<'a, T: PartialOrd + Copy, const K: usize>(kd_node: &'a KDNod current_min_node } -// Returns the minimum node of a kd-tree with respect to an axis -fn min_node(kd_node: Option<&Box>>, axis: usize, depth: usize) -> Option<&KDNode> { +// Returns the minimum node of a kd-tree with respect to an axis +fn min_node( + kd_node: Option<&KDNode>, + axis: usize, + depth: usize, +) -> Option<&KDNode> { if let Some(current_node) = kd_node { let current_axis = depth % K; if current_axis == axis { if current_node.left.is_some() { - min_node(current_node.left.as_ref(), axis, depth + 1) + min_node(current_node.left.as_deref(), axis, depth + 1) } else { Some(current_node) } } else { let (left_min, right_min): (Option<&KDNode>, Option<&KDNode>) = ( - min_node(current_node.left.as_ref(), axis, depth + 1), - min_node(current_node.right.as_ref(), axis, depth + 1) + min_node(current_node.left.as_deref(), axis, depth + 1), + min_node(current_node.right.as_deref(), axis, depth + 1), ); Some(min_node_on_axis(current_node, left_min, right_min, axis)) } @@ -270,9 +326,14 @@ fn min_node(kd_node: Option<&Box(kd_tree: &Option>>, point: &[T; K], n: usize, depth: usize, neighbors: &mut Vec<(T, [T; K])>) -where - T: PartialOrd + Copy + Sum + Real + Signed +fn n_nearest_neighbors( + kd_tree: &Option>>, + point: &[T; K], + n: usize, + depth: usize, + neighbors: &mut Vec<(T, [T; K])>, +) where + T: PartialOrd + Copy + Sum + Real + Signed, { if let Some(kd_node) = kd_tree { let distance: T = distance(&kd_node.point, point); @@ -280,7 +341,11 @@ where neighbors.push((distance, kd_node.point)); } else { // safe to call unwrap() since we know our neighbors is ont empty in this scope - let max_distance = neighbors.iter().max_by(|a, b| a.0.partial_cmp(&b.0).unwrap()).unwrap().0; + let max_distance = neighbors + .iter() + .max_by(|a, b| a.0.partial_cmp(&b.0).unwrap()) + .unwrap() + .0; if distance < max_distance { if let Some(pos) = neighbors.iter().position(|x| x.0 == max_distance) { neighbors[pos] = (distance, kd_node.point); @@ -292,27 +357,30 @@ where let target_axis: T = point[axis]; let split_axis: T = kd_node.point[axis]; - let (look_first, look_second) = if target_axis < split_axis { + let (look_first, look_second) = if target_axis < split_axis { (&kd_node.left, &kd_node.right) } else { (&kd_node.right, &kd_node.left) }; if look_first.is_some() { - n_nearest_neighbors(&look_first, point, n, depth + 1, neighbors); + n_nearest_neighbors(look_first, point, n, depth + 1, neighbors); } // Check if it's necessary to look on the other branch by computing the distance between our current point with the nearest point on the other branch if look_second.is_some() { - let max_distance = neighbors.iter().max_by(|a, b| a.0.partial_cmp(&b.0).unwrap()).unwrap().0; + let max_distance = neighbors + .iter() + .max_by(|a, b| a.0.partial_cmp(&b.0).unwrap()) + .unwrap() + .0; if neighbors.len() < n || abs(target_axis - split_axis) < max_distance { - n_nearest_neighbors(&look_second, point, n, depth + 1, neighbors); + n_nearest_neighbors(look_second, point, n, depth + 1, neighbors); } } - } + } } - #[cfg(test)] mod test { use super::KDTree; @@ -330,8 +398,8 @@ mod test { fn contains() { let points = vec![[2.0, 3.0], [5.0, 4.0], [9.0, 6.0], [4.0, 7.0]]; let kd_tree = KDTree::build(points); - assert_eq!(kd_tree.search(&[5.0, 4.0]), true); - assert_eq!(kd_tree.search(&[5.0, 4.1]), false); + assert_eq!(kd_tree.contains(&[5.0, 4.0]), true); + assert_eq!(kd_tree.contains(&[5.0, 4.1]), false); } #[test] @@ -341,15 +409,24 @@ mod test { assert_eq!(kd_tree.delete(&[5.0, 4.0]), true); // Cannot remove twice assert_eq!(kd_tree.delete(&[5.0, 4.0]), false); - assert_eq!(kd_tree.search(&[5.0, 4.0]), false); + assert_eq!(kd_tree.contains(&[5.0, 4.0]), false); } #[test] fn nearest_neighbors() { - let points = vec![[2.0, 3.0], [5.0, 4.0], [9.0, 6.0], [4.0, 7.0], [8.0, 1.0], [7.0, 2.0]]; + let points = vec![ + [2.0, 3.0], + [5.0, 4.0], + [9.0, 6.0], + [4.0, 7.0], + [8.0, 1.0], + [7.0, 2.0], + ]; let kd_tree = KDTree::build(points); // for the point [5.0, 3.0] it's obvious that [5.0, 4.0] is one of its closest neighbor with a distance of 1.0 - assert!(kd_tree.nearest_neighbors(&[5.0, 3.0], 2).contains(&(1.0, [5.0, 4.0]))); + assert!(kd_tree + .nearest_neighbors(&[5.0, 3.0], 2) + .contains(&(1.0, [5.0, 4.0]))); } #[test] @@ -362,7 +439,14 @@ mod test { #[test] fn len_and_depth() { - let points = vec![[2.0, 3.0], [5.0, 4.0], [9.0, 6.0], [4.0, 7.0], [8.0, 1.0], [7.0, 2.0]]; + let points = vec![ + [2.0, 3.0], + [5.0, 4.0], + [9.0, 6.0], + [4.0, 7.0], + [8.0, 1.0], + [7.0, 2.0], + ]; let size = points.len(); let tree = KDTree::build(points); assert_eq!(tree.len(), size); @@ -373,14 +457,14 @@ mod test { fn merge() { let points_1 = vec![[2.0, 3.0], [5.0, 4.0], [9.0, 6.0]]; let points_2 = vec![[4.0, 7.0], [8.0, 1.0], [7.0, 2.0]]; - + let mut kd_tree_1 = KDTree::build(points_1); let mut kd_tree_2 = KDTree::build(points_2); let kd_tree_3 = kd_tree_1.merge(&mut kd_tree_2); // Making sure the resulted kd-tree contains points from both kd-trees - assert!(kd_tree_3.search(&[9.0, 6.0])); - assert!(kd_tree_3.search(&[8.0, 1.0])); + assert!(kd_tree_3.contains(&[9.0, 6.0])); + assert!(kd_tree_3.contains(&[8.0, 1.0])); } } diff --git a/src/data_structures/mod.rs b/src/data_structures/mod.rs index 621ff290360..2570c94de23 100644 --- a/src/data_structures/mod.rs +++ b/src/data_structures/mod.rs @@ -6,6 +6,7 @@ mod floyds_algorithm; pub mod graph; mod hash_table; mod heap; +mod kd_tree; mod lazy_segment_tree; mod linked_list; mod probabilistic; @@ -29,6 +30,7 @@ pub use self::graph::DirectedGraph; pub use self::graph::UndirectedGraph; pub use self::hash_table::HashTable; pub use self::heap::Heap; +pub use self::kd_tree::KDTree; pub use self::lazy_segment_tree::LazySegmentTree; pub use self::linked_list::LinkedList; pub use self::probabilistic::bloom_filter; From 1ee041f61c9de59be884902cc1517f50f6a1d6e0 Mon Sep 17 00:00:00 2001 From: Bomen Derick Date: Fri, 4 Oct 2024 16:44:13 +0100 Subject: [PATCH 3/6] review test module --- src/data_structures/kd_tree.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/data_structures/kd_tree.rs b/src/data_structures/kd_tree.rs index a57366aedb3..0721ad5e664 100644 --- a/src/data_structures/kd_tree.rs +++ b/src/data_structures/kd_tree.rs @@ -388,28 +388,28 @@ mod test { #[test] fn insert() { let mut kd_tree: KDTree = KDTree::new(); - assert_eq!(kd_tree.insert([2.0, 3.0]), true); + assert!(kd_tree.insert([2.0, 3.0])); // Cannot insert the same point again - assert_eq!(kd_tree.insert([2.0, 3.0]), false); - assert_eq!(kd_tree.insert([2.0, 3.1]), true); + assert!(!kd_tree.insert([2.0, 3.0])); + assert!(kd_tree.insert([2.0, 3.1])); } #[test] fn contains() { let points = vec![[2.0, 3.0], [5.0, 4.0], [9.0, 6.0], [4.0, 7.0]]; let kd_tree = KDTree::build(points); - assert_eq!(kd_tree.contains(&[5.0, 4.0]), true); - assert_eq!(kd_tree.contains(&[5.0, 4.1]), false); + assert!(kd_tree.contains(&[5.0, 4.0])); + assert!(!kd_tree.contains(&[5.0, 4.1])); } #[test] fn remove() { let points = vec![[2.0, 3.0], [5.0, 4.0], [9.0, 6.0], [4.0, 7.0]]; let mut kd_tree = KDTree::build(points); - assert_eq!(kd_tree.delete(&[5.0, 4.0]), true); + assert!(kd_tree.delete(&[5.0, 4.0])); // Cannot remove twice - assert_eq!(kd_tree.delete(&[5.0, 4.0]), false); - assert_eq!(kd_tree.contains(&[5.0, 4.0]), false); + assert!(!kd_tree.delete(&[5.0, 4.0])); + assert!(!kd_tree.contains(&[5.0, 4.0])); } #[test] @@ -432,9 +432,9 @@ mod test { #[test] fn is_empty() { let mut kd_tree = KDTree::new(); - assert_eq!(kd_tree.is_empty(), true); + assert!(kd_tree.is_empty()); kd_tree.insert([1.5, 3.0]); - assert_eq!(kd_tree.is_empty(), false); + assert!(!kd_tree.is_empty()); } #[test] From 89e10634e76ac8ba3ee684f65832a7bd77219310 Mon Sep 17 00:00:00 2001 From: Bomen Derick Date: Thu, 10 Oct 2024 07:16:34 +0100 Subject: [PATCH 4/6] Update kd_tree.rs --- src/data_structures/kd_tree.rs | 211 ++++++++++++++++----------------- 1 file changed, 104 insertions(+), 107 deletions(-) diff --git a/src/data_structures/kd_tree.rs b/src/data_structures/kd_tree.rs index 0721ad5e664..5e123cb2dff 100644 --- a/src/data_structures/kd_tree.rs +++ b/src/data_structures/kd_tree.rs @@ -1,3 +1,27 @@ + +/// A k-d tree implementation supporting the following operations: +/// +/// Main functions: +/// +/// new() -> Create an empty k-d tree +/// build() -> Generate a balance k-d tree from a vector of points +/// insert() -> Add a point to a k-d tree +/// delete() -> Remove a point from a k-d tree +/// contains() -> Search for a point in a k-d tree +/// n_nearest_neighbors -> Search the nearest neighbors of a given point from a k-d tree with their respective distances +/// len() -> Determine the number of points stored in a kd-tree +/// is_empty() -> Determine whether or not there are points in a k-d tree +/// +/// Helper functions: +/// +/// distance() -> Calculate the Euclidean distance between two points +/// min_node() -> Determine the minimum node from a given k-d tree with respect to a given axis +/// min_node_on_axis() -> Determine the minimum node among three nodes on a given axis +/// +/// Check each function's definition for more details +/// +/// TODO: Implement a `range_search` function to return a set of points found within a given boundary + use num_traits::{abs, real::Real, Signed}; use std::iter::Sum; @@ -36,7 +60,6 @@ impl Default for KDTree { impl KDTree { // Create and empty kd-tree - // #[must_use] pub fn new() -> Self { KDTree { root: None, @@ -49,7 +72,7 @@ impl KDTree { search_rec(&self.root, point, 0) } - // Returns true if successfully delete a point, false otherwise + // Returns true if successfully insert a point, false otherwise pub fn insert(&mut self, point: [T; K]) -> bool { let inserted: bool = insert_rec(&mut self.root, point, 0); if inserted { @@ -58,7 +81,7 @@ impl KDTree { inserted } - // Returns true if successfully delete a point + // Returns true if successfully delete a point, false otherwise pub fn delete(&mut self, point: &[T; K]) -> bool { let deleted = delete_rec(&mut self.root, point, 0); if deleted { @@ -78,25 +101,16 @@ impl KDTree { } // Returns the number of points in a kd-tree - // #[must_use] pub fn len(&self) -> usize { self.size } - // Returns the depth a kd-tree - // #[must_use] - pub fn depth(&self) -> usize { - depth_rec(&self.root, 0, 0) - } - // Determine whether there exist points in a kd-tree or not - // #[must_use] pub fn is_empty(&self) -> bool { self.root.is_none() } // Returns a kd-tree built from a vector points - // #[must_use] pub fn build(points: Vec<[T; K]>) -> KDTree { let mut tree: KDTree = KDTree::new(); if points.is_empty() { @@ -109,15 +123,6 @@ impl KDTree { } } - /// Returns a `KDTree` containing both trees - /// Merging two KDTrees by collecting points and rebuilding - // #[must_use] - pub fn merge(&mut self, other: &mut Self) -> Self { - let mut points: Vec<[T; K]> = Vec::new(); - collect_points(&self.root, &mut points); - collect_points(&other.root, &mut points); - KDTree::build(points) - } } // Helper functions ............................................................................ @@ -231,37 +236,6 @@ fn build_rec( } } -// Returns the depth of the deepest branch of a kd-tree. -fn depth_rec( - kd_tree: &Option>>, - left_depth: usize, - right_depth: usize, -) -> usize { - if let Some(kd_node) = kd_tree { - match (&kd_node.left, &kd_node.right) { - (None, None) => left_depth.max(right_depth), - (None, Some(_)) => depth_rec(&kd_node.left, left_depth + 1, right_depth), - (Some(_), None) => depth_rec(&kd_node.right, left_depth, right_depth + 1), - (Some(_), Some(_)) => depth_rec(&kd_node.left, left_depth + 1, right_depth) - .max(depth_rec(&kd_node.right, left_depth, right_depth + 1)), - } - } else { - left_depth.max(right_depth) - } -} - -// Collect all points from a given `KDTree` into a vector -fn collect_points( - kd_node: &Option>>, - points: &mut Vec<[T; K]>, -) { - if let Some(current_node) = kd_node { - points.push(current_node.point); - collect_points(¤t_node.left, points); - collect_points(¤t_node.right, points); - } -} - // Calculate the distance between two points fn distance(point_1: &[T; K], point_2: &[T; K]) -> T where @@ -383,88 +357,111 @@ fn n_nearest_neighbors( #[cfg(test)] mod test { + /// Tests for the following operations: + /// + /// insert(), contains(), delete(), n_nearest_neighbors(), len(), is_empty() + /// This test uses a 2-Dimensional point + /// + /// TODO: Create a global constant(K for example) to hold the dimension to be tested and adjust each test case to make use of K for points allocation. + use super::KDTree; #[test] fn insert() { - let mut kd_tree: KDTree = KDTree::new(); - assert!(kd_tree.insert([2.0, 3.0])); - // Cannot insert the same point again - assert!(!kd_tree.insert([2.0, 3.0])); - assert!(kd_tree.insert([2.0, 3.1])); + let points = (0..100).map(|_| { + [(rand::random::() * 1000.0).round() / 10.0, (rand::random::() * 1000.0).round() / 10.0] + }).collect::>(); + let mut kd_tree = KDTree::build(points); + let point = [(rand::random::() * 1000.0).round() / 10.0, (rand::random::() * 1000.0).round() / 10.0]; + + assert!(kd_tree.insert(point)); + // Cannot insert twice + assert!(!kd_tree.insert(point)); } #[test] fn contains() { - let points = vec![[2.0, 3.0], [5.0, 4.0], [9.0, 6.0], [4.0, 7.0]]; - let kd_tree = KDTree::build(points); - assert!(kd_tree.contains(&[5.0, 4.0])); - assert!(!kd_tree.contains(&[5.0, 4.1])); + let points = (0..100).map(|_| { + [(rand::random::() * 1000.0).round() / 10.0, (rand::random::() * 1000.0).round() / 10.0] + }).collect::>(); + let mut kd_tree = KDTree::build(points); + let point = [(rand::random::() * 1000.0).round() / 10.0, (rand::random::() * 1000.0).round() / 10.0]; + kd_tree.insert(point); + + assert!(kd_tree.contains(&point)); } #[test] - fn remove() { - let points = vec![[2.0, 3.0], [5.0, 4.0], [9.0, 6.0], [4.0, 7.0]]; + fn delete() { + let points = (0..100).map(|_| { + [(rand::random::() * 1000.0).round() / 10.0, (rand::random::() * 1000.0).round() / 10.0] + }).collect::>(); + let point = points[(rand::random::() * 100.0).round() as usize].clone(); let mut kd_tree = KDTree::build(points); - assert!(kd_tree.delete(&[5.0, 4.0])); - // Cannot remove twice - assert!(!kd_tree.delete(&[5.0, 4.0])); - assert!(!kd_tree.contains(&[5.0, 4.0])); + + assert!(kd_tree.delete(&point)); + // Cannot delete twice + assert!(!kd_tree.delete(&point)); + // Ensure point is no longer present in k-d tree + assert!(!kd_tree.contains(&point)); } #[test] fn nearest_neighbors() { - let points = vec![ - [2.0, 3.0], - [5.0, 4.0], - [9.0, 6.0], - [4.0, 7.0], - [8.0, 1.0], - [7.0, 2.0], + // Test with large data set + let points_1 = (0..1000).map(|_| { + [(rand::random::() * 1000.0).round() / 10.0, (rand::random::() * 1000.0).round() / 10.0] + }).collect::>(); + let kd_tree_1 = KDTree::build(points_1); + let target = [50.0, 50.0]; + let neighbors_1 = kd_tree_1.nearest_neighbors(&target, 10); + + // Confirm we have exactly 10 nearest neighbors + assert_eq!(neighbors_1.len(), 10); + + // `14.14` is the approximate distance between [40.0, 40.0] and [50.0, 50.0] & + // [50.0, 50.0] and [60.0, 60.0] + // so our closest neighbors are expected to be found between the bounding box [40.0, 40.0] - [60.0, 60.0] + // with a distance from [50.0, 50.0] less than or equal 14.14 + for neighbor in neighbors_1 { + assert!(neighbor.0 <= 14.14); + } + + // Test with small data set + let points_2 = vec![[2.0, 3.0],[5.0, 4.0],[9.0, 6.0],[4.0, 7.0],[8.0, 1.0], +[7.0, 2.0], ]; - let kd_tree = KDTree::build(points); - // for the point [5.0, 3.0] it's obvious that [5.0, 4.0] is one of its closest neighbor with a distance of 1.0 - assert!(kd_tree - .nearest_neighbors(&[5.0, 3.0], 2) - .contains(&(1.0, [5.0, 4.0]))); + let kd_tree_2 = KDTree::build(points_2); + let neighbors_2 = kd_tree_2.nearest_neighbors(&[6.0, 3.0], 3); + let expected_neighbors = vec![[7.0, 2.0], [5.0, 4.0], [8.0, 1.0]]; + let neighbors = neighbors_2.iter().map(|a| a.1).collect::>(); + + // Confirm we have exactly 10 nearest neighbors + assert_eq!(neighbors.len(), 3); + + // With a small set of data, we can manually calculate our 3 nearest neighbors + // and compare with those obtained from our method + assert_eq!(neighbors, expected_neighbors); } #[test] fn is_empty() { let mut kd_tree = KDTree::new(); + assert!(kd_tree.is_empty()); + kd_tree.insert([1.5, 3.0]); - assert!(!kd_tree.is_empty()); - } - #[test] - fn len_and_depth() { - let points = vec![ - [2.0, 3.0], - [5.0, 4.0], - [9.0, 6.0], - [4.0, 7.0], - [8.0, 1.0], - [7.0, 2.0], - ]; - let size = points.len(); - let tree = KDTree::build(points); - assert_eq!(tree.len(), size); - assert_eq!(tree.depth(), 2); + assert!(!kd_tree.is_empty()); } #[test] - fn merge() { - let points_1 = vec![[2.0, 3.0], [5.0, 4.0], [9.0, 6.0]]; - let points_2 = vec![[4.0, 7.0], [8.0, 1.0], [7.0, 2.0]]; - - let mut kd_tree_1 = KDTree::build(points_1); - let mut kd_tree_2 = KDTree::build(points_2); - - let kd_tree_3 = kd_tree_1.merge(&mut kd_tree_2); - - // Making sure the resulted kd-tree contains points from both kd-trees - assert!(kd_tree_3.contains(&[9.0, 6.0])); - assert!(kd_tree_3.contains(&[8.0, 1.0])); + fn len() { + let points = (0..1000).map(|_| { + [(rand::random::() * 1000.0).round() / 10.0, (rand::random::() * 1000.0).round() / 10.0] + }).collect::>(); + let kd_tree = KDTree::build(points); + + assert_eq!(kd_tree.len(), 1000); } } From 8f06c40b14aa94dc442a53ea42bf3bacc01b1a76 Mon Sep 17 00:00:00 2001 From: Bomen Derick Date: Thu, 10 Oct 2024 16:07:12 +0100 Subject: [PATCH 5/6] Update kd_tree.rs --- src/data_structures/kd_tree.rs | 110 +++++++++++++++++++++------------ 1 file changed, 71 insertions(+), 39 deletions(-) diff --git a/src/data_structures/kd_tree.rs b/src/data_structures/kd_tree.rs index 5e123cb2dff..47af9676797 100644 --- a/src/data_structures/kd_tree.rs +++ b/src/data_structures/kd_tree.rs @@ -1,9 +1,8 @@ - /// A k-d tree implementation supporting the following operations: -/// +/// /// Main functions: -/// -/// new() -> Create an empty k-d tree +/// +/// new() -> Create an empty k-d tree /// build() -> Generate a balance k-d tree from a vector of points /// insert() -> Add a point to a k-d tree /// delete() -> Remove a point from a k-d tree @@ -11,17 +10,16 @@ /// n_nearest_neighbors -> Search the nearest neighbors of a given point from a k-d tree with their respective distances /// len() -> Determine the number of points stored in a kd-tree /// is_empty() -> Determine whether or not there are points in a k-d tree -/// +/// /// Helper functions: -/// +/// /// distance() -> Calculate the Euclidean distance between two points /// min_node() -> Determine the minimum node from a given k-d tree with respect to a given axis /// min_node_on_axis() -> Determine the minimum node among three nodes on a given axis -/// +/// /// Check each function's definition for more details -/// +/// /// TODO: Implement a `range_search` function to return a set of points found within a given boundary - use num_traits::{abs, real::Real, Signed}; use std::iter::Sum; @@ -122,7 +120,6 @@ impl KDTree { tree } } - } // Helper functions ............................................................................ @@ -358,21 +355,28 @@ fn n_nearest_neighbors( #[cfg(test)] mod test { /// Tests for the following operations: - /// + /// /// insert(), contains(), delete(), n_nearest_neighbors(), len(), is_empty() /// This test uses a 2-Dimensional point - /// - /// TODO: Create a global constant(K for example) to hold the dimension to be tested and adjust each test case to make use of K for points allocation. - + /// + /// TODO: Create a global constant(K for example) to hold the dimension to be tested and adjust each test case to make use of K for points allocation. use super::KDTree; #[test] fn insert() { - let points = (0..100).map(|_| { - [(rand::random::() * 1000.0).round() / 10.0, (rand::random::() * 1000.0).round() / 10.0] - }).collect::>(); + let points = (0..100) + .map(|_| { + [ + (rand::random::() * 1000.0).round() / 10.0, + (rand::random::() * 1000.0).round() / 10.0, + ] + }) + .collect::>(); let mut kd_tree = KDTree::build(points); - let point = [(rand::random::() * 1000.0).round() / 10.0, (rand::random::() * 1000.0).round() / 10.0]; + let point = [ + (rand::random::() * 1000.0).round() / 10.0, + (rand::random::() * 1000.0).round() / 10.0, + ]; assert!(kd_tree.insert(point)); // Cannot insert twice @@ -381,11 +385,19 @@ mod test { #[test] fn contains() { - let points = (0..100).map(|_| { - [(rand::random::() * 1000.0).round() / 10.0, (rand::random::() * 1000.0).round() / 10.0] - }).collect::>(); + let points = (0..100) + .map(|_| { + [ + (rand::random::() * 1000.0).round() / 10.0, + (rand::random::() * 1000.0).round() / 10.0, + ] + }) + .collect::>(); let mut kd_tree = KDTree::build(points); - let point = [(rand::random::() * 1000.0).round() / 10.0, (rand::random::() * 1000.0).round() / 10.0]; + let point = [ + (rand::random::() * 1000.0).round() / 10.0, + (rand::random::() * 1000.0).round() / 10.0, + ]; kd_tree.insert(point); assert!(kd_tree.contains(&point)); @@ -393,10 +405,15 @@ mod test { #[test] fn delete() { - let points = (0..100).map(|_| { - [(rand::random::() * 1000.0).round() / 10.0, (rand::random::() * 1000.0).round() / 10.0] - }).collect::>(); - let point = points[(rand::random::() * 100.0).round() as usize].clone(); + let points = (0..100) + .map(|_| { + [ + (rand::random::() * 1000.0).round() / 10.0, + (rand::random::() * 1000.0).round() / 10.0, + ] + }) + .collect::>(); + let point = points[(rand::random::() * 100.0).round() as usize]; let mut kd_tree = KDTree::build(points); assert!(kd_tree.delete(&point)); @@ -409,27 +426,37 @@ mod test { #[test] fn nearest_neighbors() { // Test with large data set - let points_1 = (0..1000).map(|_| { - [(rand::random::() * 1000.0).round() / 10.0, (rand::random::() * 1000.0).round() / 10.0] - }).collect::>(); + let points_1 = (0..1000) + .map(|_| { + [ + (rand::random::() * 1000.0).round() / 10.0, + (rand::random::() * 1000.0).round() / 10.0, + ] + }) + .collect::>(); let kd_tree_1 = KDTree::build(points_1); let target = [50.0, 50.0]; let neighbors_1 = kd_tree_1.nearest_neighbors(&target, 10); - + // Confirm we have exactly 10 nearest neighbors assert_eq!(neighbors_1.len(), 10); - // `14.14` is the approximate distance between [40.0, 40.0] and [50.0, 50.0] & - // [50.0, 50.0] and [60.0, 60.0] - // so our closest neighbors are expected to be found between the bounding box [40.0, 40.0] - [60.0, 60.0] + // `14.14` is the approximate distance between [40.0, 40.0] and [50.0, 50.0] & + // [50.0, 50.0] and [60.0, 60.0] + // so our closest neighbors are expected to be found between the bounding box [40.0, 40.0] - [60.0, 60.0] // with a distance from [50.0, 50.0] less than or equal 14.14 for neighbor in neighbors_1 { assert!(neighbor.0 <= 14.14); } // Test with small data set - let points_2 = vec![[2.0, 3.0],[5.0, 4.0],[9.0, 6.0],[4.0, 7.0],[8.0, 1.0], -[7.0, 2.0], + let points_2 = vec![ + [2.0, 3.0], + [5.0, 4.0], + [9.0, 6.0], + [4.0, 7.0], + [8.0, 1.0], + [7.0, 2.0], ]; let kd_tree_2 = KDTree::build(points_2); let neighbors_2 = kd_tree_2.nearest_neighbors(&[6.0, 3.0], 3); @@ -457,11 +484,16 @@ mod test { #[test] fn len() { - let points = (0..1000).map(|_| { - [(rand::random::() * 1000.0).round() / 10.0, (rand::random::() * 1000.0).round() / 10.0] - }).collect::>(); + let points = (0..1000) + .map(|_| { + [ + (rand::random::() * 1000.0).round() / 10.0, + (rand::random::() * 1000.0).round() / 10.0, + ] + }) + .collect::>(); let kd_tree = KDTree::build(points); - + assert_eq!(kd_tree.len(), 1000); } } From bf5be5cc6e660d8c06e1f23812f863429d85a3ed Mon Sep 17 00:00:00 2001 From: Bomen Derick Date: Wed, 20 Nov 2024 23:40:00 +0100 Subject: [PATCH 6/6] Update kd_tree.rs --- src/data_structures/kd_tree.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/data_structures/kd_tree.rs b/src/data_structures/kd_tree.rs index 47af9676797..c11b665fe55 100644 --- a/src/data_structures/kd_tree.rs +++ b/src/data_structures/kd_tree.rs @@ -364,7 +364,7 @@ mod test { #[test] fn insert() { - let points = (0..100) + let points: Vec<[f64; 2]> = (0..100) .map(|_| { [ (rand::random::() * 1000.0).round() / 10.0, @@ -385,7 +385,7 @@ mod test { #[test] fn contains() { - let points = (0..100) + let points: Vec<[f64; 2]> = (0..100) .map(|_| { [ (rand::random::() * 1000.0).round() / 10.0, @@ -405,7 +405,7 @@ mod test { #[test] fn delete() { - let points = (0..100) + let points: Vec<[f64; 2]> = (0..100) .map(|_| { [ (rand::random::() * 1000.0).round() / 10.0, @@ -426,7 +426,7 @@ mod test { #[test] fn nearest_neighbors() { // Test with large data set - let points_1 = (0..1000) + let points_1: Vec<[f64; 2]> = (0..1000) .map(|_| { [ (rand::random::() * 1000.0).round() / 10.0, @@ -450,7 +450,7 @@ mod test { } // Test with small data set - let points_2 = vec![ + let points_2: Vec<[f64; 2]> = vec![ [2.0, 3.0], [5.0, 4.0], [9.0, 6.0], @@ -473,7 +473,7 @@ mod test { #[test] fn is_empty() { - let mut kd_tree = KDTree::new(); + let mut kd_tree: KDTree = KDTree::new(); assert!(kd_tree.is_empty()); @@ -484,7 +484,7 @@ mod test { #[test] fn len() { - let points = (0..1000) + let points: Vec<[f64; 2]> = (0..1000) .map(|_| { [ (rand::random::() * 1000.0).round() / 10.0,