From 7a6734cd4dd35a9f00f0543766f1648cf293e6d5 Mon Sep 17 00:00:00 2001 From: Olek Date: Mon, 26 Dec 2016 14:47:59 +0100 Subject: [PATCH] Added benches, lookup remaining --- Cargo.toml | 10 +++++ src/bench.rs | 46 ++++++++++++++++++++++ src/kdtree/bounds.rs | 33 +++++++++++++--- src/kdtree/mod.rs | 84 ++++++++++++++++++++++++++++++++--------- src/kdtree/partition.rs | 11 ++++-- 5 files changed, 157 insertions(+), 27 deletions(-) create mode 100644 src/bench.rs diff --git a/Cargo.toml b/Cargo.toml index 623ff09..1cffd2a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,8 +3,18 @@ name = "kdtree-rust" version = "0.1.0" authors = ["Aleksander Fular "] +[lib] +name = "kdtree" +path = "src//lib.rs" +bench = false + +[[bench]] +name = "bench" +harness = false + [dependencies] rand = "*" +bencher = "*" [dev-dependencies] quickcheck = "0.3" \ No newline at end of file diff --git a/src/bench.rs b/src/bench.rs new file mode 100644 index 0000000..719a15d --- /dev/null +++ b/src/bench.rs @@ -0,0 +1,46 @@ +#[macro_use] +extern crate bencher; +extern crate kdtree; +extern crate rand; + +use bencher::Bencher; + + +#[derive(Copy, Clone, PartialEq)] +pub struct Point2WithId { + dims: [f64; 2], + pub id: i32, +} + +impl Point2WithId { + pub fn new(id: i32, x: f64, y: f64) -> Point2WithId { + Point2WithId { + dims: [x, y], + id: id, + } + } +} + +impl kdtree::kdtree::KdtreePointTrait for Point2WithId { + fn dims(&self) -> &[f64] { + return &self.dims; + } +} + +fn a(b: &mut Bencher) { + let len = 1000usize; + let mut points : Vec = vec![]; + //let mut kdtree = KdTree::new_with_capacity(3, 16); + for id in 0..len { + let x : f64 = rand::random(); + points.push(Point2WithId::new(id as i32, x, x)); + // points.push(rand_data()); + } + + b.iter(|| { + let tree = kdtree::kdtree::Kdtree::new(points.clone()); + }); +} + +benchmark_group!(benches, a); +benchmark_main!(benches); \ No newline at end of file diff --git a/src/kdtree/bounds.rs b/src/kdtree/bounds.rs index e37d24e..1b68296 100644 --- a/src/kdtree/bounds.rs +++ b/src/kdtree/bounds.rs @@ -1,4 +1,3 @@ - use ::kdtree::*; pub struct Bounds { @@ -11,7 +10,7 @@ impl Bounds { bounds: vec![], }; - bounds.bounds.resize(points[0].dims().len(), (0.,0.)); + bounds.bounds.resize(points[0].dims().len(), (0., 0.)); for i in 0..points[0].dims().len() { bounds.bounds[i].0 = points[0].dims()[i]; @@ -43,6 +42,28 @@ impl Bounds { widest_dimension } + + pub fn get_midvalue_of_widest_dim(&self) -> f64 { + (self.bounds[self.get_widest_dim()].0 + self.bounds[self.get_widest_dim()].1) / 2.0 + } + + pub fn clone_moving_max(&self, value: f64, dimension: usize) -> Bounds { + let mut cloned = Bounds { + bounds: self.bounds.clone() + }; + cloned.bounds[dimension].1 = value; + + cloned + } + + pub fn clone_moving_min(&self, value: f64, dimension: usize) -> Bounds { + let mut cloned = Bounds { + bounds: self.bounds.clone() + }; + cloned.bounds[dimension].0 = value; + + cloned + } } @@ -53,9 +74,10 @@ mod tests { #[test] fn bounds_test() { - let p1 = Point2WithId::new(1,1.0,0.5); - let p2 = Point2WithId::new(1,3.0,4.0); - let v = vec![p1,p2]; + let p1 = Point2WithId::new(1, 1.0, 0.5); + let p2 = Point2WithId::new(1, 3.0, 4.0); + let v = vec![p1, p2]; + let bounds = Bounds::new_from_points(&v); @@ -63,6 +85,5 @@ mod tests { assert_eq!((0.5, 4.0), bounds.bounds[1]); assert_eq!(1, bounds.get_widest_dim()); - } } \ No newline at end of file diff --git a/src/kdtree/mod.rs b/src/kdtree/mod.rs index 6fcb26e..20d36fb 100644 --- a/src/kdtree/mod.rs +++ b/src/kdtree/mod.rs @@ -13,32 +13,50 @@ pub struct Kdtree { nodes: Vec>, } -impl Kdtree { - pub fn new(points: Vec) -> Kdtree { +impl Kdtree { + pub fn new(mut points: Vec) -> Kdtree { if points.len() == 0 { panic!("empty vector point not allowed"); } let rect = Bounds::new_from_points(&points); - Kdtree { + let mut tree = Kdtree { nodes: vec![], - } + }; + + tree.build_tree(&mut points, &rect); + + tree } - fn add_node(&mut self, p: T) { + fn add_node(&mut self, p: T) -> usize { let node = KdtreeNode::new(p); self.nodes.push(node); + self.nodes.len() - 1 } - fn add_left_node(&mut self, for_node: usize, ) { - { - let len = self.nodes.len(); - let node = self.nodes.get_mut(for_node).unwrap(); - node.left_node = Some(len); + fn build_tree(&mut self, nodes: &mut [T], bounds: &Bounds) -> usize { + let (splitting_index, pivot_value) = partition::partition_sliding_midpoint(nodes, bounds.get_midvalue_of_widest_dim(), bounds.get_widest_dim()); + + let node_id = self.add_node(nodes[splitting_index]); + let nodes_len = nodes.len(); + + if splitting_index > 0 { + let left_rect = bounds.clone_moving_max(bounds.get_midvalue_of_widest_dim(), bounds.get_widest_dim()); + let left_child_id = self.build_tree(&mut nodes[0..splitting_index], &left_rect); + self.nodes[node_id].left_node = Some(left_child_id); } - //self.nodes.push(KdtreeNode::new()); + + if splitting_index < nodes.len() - 1 { + let right_rect = bounds.clone_moving_min(bounds.get_midvalue_of_widest_dim(), bounds.get_widest_dim()); + + let right_child_id = self.build_tree(&mut nodes[splitting_index + 1..nodes_len], &right_rect); + self.nodes[node_id].right_node = Some(right_child_id); + } + + node_id } } @@ -74,12 +92,44 @@ mod tests { Kdtree::new(empty_vec); } - #[test] - fn test2() { - let p1 = Point2WithId::new(1, 1., 2.); - let p2 = Point2WithId::new(1, 1., 2.); - let vec = vec![p1, p2]; + quickcheck! { + fn tree_build_creates_tree_with_as_many_leafs_as_there_is_points(xs : Vec) -> bool { + if(xs.len() == 0) { + return true; + } + let mut vec : Vec = vec![]; + for i in 0 .. xs.len() { + let p = Point2WithId::new(i as i32, xs[i], xs[i]); - Kdtree::new(vec); + vec.push(p); + } + + let tree = Kdtree::new(vec); + + let mut to_iterate : Vec = vec![]; + to_iterate.push(0); + + let mut str = String::new(); + + while to_iterate.len() > 0 { + let last_index = to_iterate.last().unwrap().clone(); + let ref x = tree.nodes.get(last_index).unwrap(); + to_iterate.pop(); + if x.left_node.is_some() { + to_iterate.push(x.left_node.unwrap()); + } + if x.right_node.is_some() { + to_iterate.push(x.right_node.unwrap()); + } + + str.push_str(&format!("Index: {} has ln {} has rn {} \n", last_index, x.left_node.is_some(), x.right_node.is_some())); + + + } + + // println!("str is: {}", str); + + xs.len() == tree.nodes.len() + } } } \ No newline at end of file diff --git a/src/kdtree/partition.rs b/src/kdtree/partition.rs index 5a5035c..c9fde9f 100644 --- a/src/kdtree/partition.rs +++ b/src/kdtree/partition.rs @@ -12,7 +12,7 @@ struct PartitionPointHelper { index_of_splitter: usize, } -fn partition_sliding_midpoint_helper(vec: &mut Vec, midpoint_value: f64, partition_on_dimension: usize) -> PartitionPointHelper { +fn partition_sliding_midpoint_helper(vec: &mut [T], midpoint_value: f64, partition_on_dimension: usize) -> PartitionPointHelper { let mut closest_index = 0; let mut closest_distance = (vec[0].dims()[partition_on_dimension] - midpoint_value).abs(); @@ -51,10 +51,13 @@ fn partition_sliding_midpoint_helper(vec: &mut Vec, midp } } -pub fn partition_sliding_midpoint(vec: &mut Vec, midpoint_value: f64, partition_on_dimension: usize) -> (usize, f64) { +pub fn partition_sliding_midpoint(vec: &mut [T], midpoint_value: f64, partition_on_dimension: usize) -> (usize, f64) { let vec_len = vec.len(); debug_assert!(vec[0].dims().len() > partition_on_dimension); - debug_assert!(vec.len() > 1); + + if vec.len() == 1 { + return (0, vec[0].dims()[partition_on_dimension]); + } let partition_point_data = partition_sliding_midpoint_helper(vec, midpoint_value, partition_on_dimension); @@ -74,7 +77,7 @@ pub fn partition_sliding_midpoint(vec: &mut Vec, midpoin } } -fn partition_kdtree(vec: &mut Vec, index_of_splitting_point: usize, partition_on_dimension: usize) -> usize { +fn partition_kdtree(vec: &mut [T], index_of_splitting_point: usize, partition_on_dimension: usize) -> usize { if vec.len() == 1 { return 0; }