1use rstar::{Point as RPoint};
2
3#[derive(Clone,Copy,PartialEq,Debug)]
4pub struct CellIndexPoint<const D: usize>{
6 pub index: CellIndex<D>
7}
8
9impl <const D:usize> RPoint for CellIndexPoint<D>{
10
11 type Scalar = i64;
12 const DIMENSIONS: usize = D;
13
14 fn generate(generator: impl Fn(usize) -> Self::Scalar) -> Self
15 {
16 let mut r : CellIndexPoint<D> = CellIndexPoint{index: [0;D]};
17 for i in 0..D {
18 r.index[i] = generator(i);
19 }
20 r
21 }
22
23 fn nth(&self, index: usize) -> Self::Scalar{
24 if index < D {
25 self.index[index]
26 } else {
27 unreachable!()
28 }
29 }
30
31 fn nth_mut(&mut self, index: usize) -> &mut Self::Scalar
32 {
33 if index < D {
34 &mut self.index[index]
35 } else {
36 unreachable!()
37 }
38 }
39}
40
41pub struct DBSCANParams{
43 pub cardinality: usize,
45 pub dimensionality: u32,
47 pub epsilon: f64,
49 pub rho: f64,
51 pub min_pts: usize
53}
54
55#[derive(PartialEq, Debug)]
56pub enum IntersectionType{
58 FullyCovered,
59 Disjoint,
60 Intersecting
61}
62
63pub fn euclidean_distance<const D: usize>(p: &Point<D>, q: &Point<D>) -> f64 {
65 let mut sum : f64 = 0.0;
66 for i in 0..D{
67 sum += (p[i]-q[i]).powf(2_f64);
68 }
69 sum.sqrt()
70}
71
72pub fn determine_intersection<const D: usize>(q: &Point<D>, params: &DBSCANParams, index_c: &CellIndex<D>, side_size:f64) -> IntersectionType{
79 let n_corners = (2_usize.pow(D as u32)) as usize;
80 let mut cell_center : CellCenter<D> = [0.0;D];
81 for i in 0..D {
82 cell_center[i] = index_c[i] as f64 * side_size;
83 }
84 let corners = get_corners(&cell_center, side_size);
85 let appr_dist = (1.0 + params.rho) * params.epsilon;
86 let mut appr_in_count : usize = 0;
87 let mut out_count : usize = 0;
88 for corner in corners {
89 let dist = euclidean_distance(q, &corner);
90 if dist <= appr_dist {
91 appr_in_count += 1;
92 }
93 if dist >= params.epsilon {
94 out_count += 1;
95 }
96 }
97 if appr_in_count == n_corners{
98 return IntersectionType::FullyCovered
99 } else if out_count == n_corners{
100 return IntersectionType::Disjoint
101 }
102 IntersectionType::Intersecting
103}
104
105fn get_corners<const D: usize>(cell_center: &CellCenter<D>, side_size: f64) -> Vec<Point<D>>{
107 let dist = side_size/2.0;
108 let top = 2_usize.pow(D as u32);
112 let mut corners = Vec::with_capacity(top);
113 for bin_rep in 0..top {
114 let mut new_corner = cell_center.clone();
115 for bit_i in 0..D {
116 let mask = 1 << bit_i;
117 if bin_rep & mask == 0 {
118 new_corner[bit_i] -= dist;
119 } else {
120 new_corner[bit_i] += dist;
121 }
122 }
123 corners.push(new_corner);
124 }
125 corners
126}
127
128pub fn get_cell_index<const D: usize>(p: &Point<D>, side_size: f64) -> CellIndex<D>{
131 let mut new_index = [0;D];
132 let half_size = side_size/2.0;
133 for i in 0..p.len() {
134 if p[i] >= (-1.0 * half_size) && p[i] < half_size {
135 new_index[i] = 0;
136 } else if p[i] > 0.0 {
137 new_index[i] = ((p[i] - half_size) / side_size).ceil() as i64;
138 } else {
139 new_index[i] = -1 + ((p[i] + half_size) / side_size).ceil() as i64;
140 }
141 }
142 new_index
143}
144
145pub fn get_base_cell_index<const D: usize>(p: &Point<D>, params: &DBSCANParams) ->CellIndex<D>{
148 get_cell_index(p, params.epsilon/(params.dimensionality as f64).sqrt())
149}
150
151pub fn index_distance_sq<const D: usize>(i_1 : &CellIndex<D>, i_2: &CellIndex<D>) -> usize {
153 let mut dist : usize = 0;
154 for j in 0..i_1.len() {
155 dist += (i_1[j] - i_2[j]).pow(2) as usize;
156 }
157 dist
158}
159
160pub type CellIndex<const D: usize> = [i64;D];
163pub type CellCenter<const D: usize> = Point<D>;
165pub type Point<const D: usize> = [f64;D];
167pub type Cluster <const D: usize> = Vec<Point<D>>;
169pub type DBSCANResult <const D: usize> = Vec<Cluster<D>>;
172
173pub type VectorPoint = Vec<f64>;
177pub type VectorCluster = Vec<VectorPoint>;
180pub type VectorDBSCANResult = Vec<VectorCluster>;
183
184pub fn vector_input_to_array_input<const D: usize>(v_in: Vec<VectorPoint>) -> Vec<Point<D>> {
187 if v_in.len() == 0 {
188 panic!("Received an unexpected 0 length vector. This should not have happened");
189 }
190 let mut arr_in = Vec::with_capacity(v_in.len());
191 for i in 1..v_in.len() {
192 if v_in[i].len() != D {
193 panic!("DBSCAN: expected all points to have {} components, but point {} has {} components instead",D, i, v_in[i].len());
194 }
195 let mut arr_point = [0.0;D];
196 for j in 0..D {
197 arr_point[j] = v_in[i][j];
198 }
199 arr_in.push(arr_point);
200 }
201 arr_in
202}
203
204pub fn array_res_to_vector_res<const D: usize>(a_res: DBSCANResult<D>) -> VectorDBSCANResult {
207 let mut v_res : VectorDBSCANResult = Vec::with_capacity(a_res.len());
208 for i in 0..a_res.len() {
209 let mut v_cluster = Vec::with_capacity(a_res[i].len());
210 for a_point in &a_res[i] {
211 v_cluster.push(a_point.to_vec());
212 }
213 v_res.push(v_cluster);
214 }
215 v_res
216}
217
218#[cfg(test)]
219mod tests;