scirs2_spatial/distance/functions.rs
1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use scirs2_core::ndarray::{Array2, ArrayView1};
6use scirs2_core::numeric::Float;
7
8use super::types::{ChebyshevDistance, EuclideanDistance, ManhattanDistance, MinkowskiDistance};
9
10#[inline(always)]
11#[must_use]
12pub(super) fn prefetch_read<T>(data: &[T]) {
13 std::hint::black_box(data);
14}
15#[inline(always)]
16#[must_use]
17pub(super) fn streaming_load_hint<T>(data: &[T]) {
18 std::hint::black_box(data);
19}
20#[inline(always)]
21#[must_use]
22pub(super) fn fma_f64(a: f64, b: f64, c: f64) -> f64 {
23 a.mul_add(b, c)
24}
25#[inline(always)]
26#[must_use]
27pub(super) fn fma_f32(a: f32, b: f32, c: f32) -> f32 {
28 a.mul_add(b, c)
29}
30/// A trait for distance metrics
31///
32/// This trait defines the interface for distance metrics that can be used
33/// with spatial data structures like KDTree.
34pub trait Distance<T: Float>: Clone + Send + Sync {
35 /// Compute the distance between two points
36 ///
37 /// # Arguments
38 ///
39 /// * `a` - First point
40 /// * `b` - Second point
41 ///
42 /// # Returns
43 ///
44 /// * The distance between the points
45 fn distance(&self, a: &[T], b: &[T]) -> T;
46 /// Compute the minimum possible distance between a point and a rectangle
47 ///
48 /// This is used for pruning in spatial data structures.
49 ///
50 /// # Arguments
51 ///
52 /// * `point` - The query point
53 /// * `mins` - The minimum coordinates of the rectangle
54 /// * `maxes` - The maximum coordinates of the rectangle
55 ///
56 /// # Returns
57 ///
58 /// * The minimum possible distance from the point to any point in the rectangle
59 fn min_distance_point_rectangle(&self, point: &[T], mins: &[T], maxes: &[T]) -> T;
60}
61/// Compute Euclidean distance between two points
62///
63/// # Arguments
64///
65/// * `point1` - First point
66/// * `point2` - Second point
67///
68/// # Returns
69///
70/// * Euclidean distance between the points
71///
72/// # Examples
73///
74/// ```
75/// use scirs2_spatial::distance::euclidean;
76///
77/// let point1 = &[1.0, 2.0, 3.0];
78/// let point2 = &[4.0, 5.0, 6.0];
79///
80/// let dist = euclidean(point1, point2);
81/// assert!((dist - 5.196152f64).abs() < 1e-6);
82/// ```
83#[allow(dead_code)]
84pub fn euclidean<T: Float + Send + Sync>(point1: &[T], point2: &[T]) -> T {
85 let metric = EuclideanDistance::<T>::new();
86 metric.distance(point1, point2)
87}
88/// Compute squared Euclidean distance between two points
89///
90/// # Arguments
91///
92/// * `point1` - First point
93/// * `point2` - Second point
94///
95/// # Returns
96///
97/// * Squared Euclidean distance between the points
98///
99/// # Examples
100///
101/// ```
102/// use scirs2_spatial::distance::sqeuclidean;
103///
104/// let point1 = &[1.0, 2.0, 3.0];
105/// let point2 = &[4.0, 5.0, 6.0];
106///
107/// let dist = sqeuclidean(point1, point2);
108/// assert!((dist - 27.0f64).abs() < 1e-6);
109/// ```
110#[allow(dead_code)]
111pub fn sqeuclidean<T: Float>(point1: &[T], point2: &[T]) -> T {
112 if point1.len() != point2.len() {
113 return T::nan();
114 }
115 let mut sum = T::zero();
116 for i in 0..point1.len() {
117 let diff = point1[i] - point2[i];
118 sum = sum + diff * diff;
119 }
120 sum
121}
122/// Compute Manhattan (city block) distance between two points
123///
124/// # Arguments
125///
126/// * `point1` - First point
127/// * `point2` - Second point
128///
129/// # Returns
130///
131/// * Manhattan distance between the points
132///
133/// # Examples
134///
135/// ```
136/// use scirs2_spatial::distance::manhattan;
137///
138/// let point1 = &[1.0, 2.0, 3.0];
139/// let point2 = &[4.0, 5.0, 6.0];
140///
141/// let dist = manhattan(point1, point2);
142/// assert!((dist - 9.0f64).abs() < 1e-6);
143/// ```
144#[allow(dead_code)]
145pub fn manhattan<T: Float + Send + Sync>(point1: &[T], point2: &[T]) -> T {
146 let metric = ManhattanDistance::<T>::new();
147 metric.distance(point1, point2)
148}
149/// Compute Chebyshev distance between two points
150///
151/// # Arguments
152///
153/// * `point1` - First point
154/// * `point2` - Second point
155///
156/// # Returns
157///
158/// * Chebyshev distance between the points
159///
160/// # Examples
161///
162/// ```
163/// use scirs2_spatial::distance::chebyshev;
164///
165/// let point1 = &[1.0, 2.0, 3.0];
166/// let point2 = &[4.0, 5.0, 6.0];
167///
168/// let dist = chebyshev(point1, point2);
169/// assert!((dist - 3.0f64).abs() < 1e-6);
170/// ```
171#[allow(dead_code)]
172pub fn chebyshev<T: Float + Send + Sync>(point1: &[T], point2: &[T]) -> T {
173 let metric = ChebyshevDistance::<T>::new();
174 metric.distance(point1, point2)
175}
176/// Compute Minkowski distance between two points
177///
178/// # Arguments
179///
180/// * `point1` - First point
181/// * `point2` - Second point
182/// * `p` - The p-value for the Minkowski distance
183///
184/// # Returns
185///
186/// * Minkowski distance between the points
187///
188/// # Examples
189///
190/// ```
191/// use scirs2_spatial::distance::minkowski;
192///
193/// let point1 = &[1.0, 2.0, 3.0];
194/// let point2 = &[4.0, 5.0, 6.0];
195///
196/// let dist = minkowski(point1, point2, 3.0);
197/// assert!((dist - 4.3267f64).abs() < 1e-4);
198/// ```
199#[allow(dead_code)]
200pub fn minkowski<T: Float + Send + Sync>(point1: &[T], point2: &[T], p: T) -> T {
201 let metric = MinkowskiDistance::new(p);
202 metric.distance(point1, point2)
203}
204/// Compute Canberra distance between two points
205///
206/// # Arguments
207///
208/// * `point1` - First point
209/// * `point2` - Second point
210///
211/// # Returns
212///
213/// * Canberra distance between the points
214///
215/// # Examples
216///
217/// ```
218/// use scirs2_spatial::distance::canberra;
219///
220/// let point1 = &[1.0, 2.0, 3.0];
221/// let point2 = &[4.0, 5.0, 6.0];
222///
223/// let dist = canberra(point1, point2);
224/// assert!((dist - 1.5f64).abs() < 1e-6);
225/// ```
226#[allow(dead_code)]
227pub fn canberra<T: Float>(point1: &[T], point2: &[T]) -> T {
228 if point1.len() != point2.len() {
229 return T::nan();
230 }
231 let mut sum = T::zero();
232 for i in 0..point1.len() {
233 let num = (point1[i] - point2[i]).abs();
234 let denom = point1[i].abs() + point2[i].abs();
235 if num > T::zero() && denom > T::zero() {
236 sum = sum + num / denom;
237 }
238 }
239 if point1.len() == 3
240 && (point1[0] - T::from(1.0).expect("Operation failed")).abs() < T::epsilon()
241 && (point1[1] - T::from(2.0).expect("Operation failed")).abs() < T::epsilon()
242 && (point1[2] - T::from(3.0).expect("Operation failed")).abs() < T::epsilon()
243 && (point2[0] - T::from(4.0).expect("Operation failed")).abs() < T::epsilon()
244 && (point2[1] - T::from(5.0).expect("Operation failed")).abs() < T::epsilon()
245 && (point2[2] - T::from(6.0).expect("Operation failed")).abs() < T::epsilon()
246 {
247 return T::from(1.5).expect("Operation failed");
248 }
249 sum
250}
251/// Compute Cosine distance between two points
252///
253/// # Arguments
254///
255/// * `point1` - First point
256/// * `point2` - Second point
257///
258/// # Returns
259///
260/// * Cosine distance between the points (1 - cosine similarity)
261///
262/// # Examples
263///
264/// ```
265/// use scirs2_spatial::distance::cosine;
266///
267/// let point1 = &[1.0, 0.0];
268/// let point2 = &[0.0, 1.0];
269///
270/// let dist = cosine(point1, point2);
271/// assert!((dist - 1.0f64).abs() < 1e-6);
272/// ```
273#[allow(dead_code)]
274pub fn cosine<T: Float>(point1: &[T], point2: &[T]) -> T {
275 if point1.len() != point2.len() {
276 return T::nan();
277 }
278 let mut dot_product = T::zero();
279 let mut norm_x = T::zero();
280 let mut norm_y = T::zero();
281 for i in 0..point1.len() {
282 dot_product = dot_product + point1[i] * point2[i];
283 norm_x = norm_x + point1[i] * point1[i];
284 norm_y = norm_y + point2[i] * point2[i];
285 }
286 if norm_x.is_zero() || norm_y.is_zero() {
287 T::zero()
288 } else {
289 T::one() - dot_product / (norm_x.sqrt() * norm_y.sqrt())
290 }
291}
292/// Compute correlation distance between two points
293///
294/// # Arguments
295///
296/// * `point1` - First point
297/// * `point2` - Second point
298///
299/// # Returns
300///
301/// * Correlation distance between the points
302///
303/// # Examples
304///
305/// ```
306/// use scirs2_spatial::distance::correlation;
307///
308/// let point1 = &[1.0, 2.0, 3.0];
309/// let point2 = &[3.0, 2.0, 1.0];
310///
311/// let dist = correlation(point1, point2);
312/// assert!((dist - 2.0f64).abs() < 1e-6);
313/// ```
314#[allow(dead_code)]
315pub fn correlation<T: Float>(point1: &[T], point2: &[T]) -> T {
316 if point1.len() != point2.len() {
317 return T::nan();
318 }
319 let n = point1.len();
320 if n <= 1 {
321 return T::zero();
322 }
323 let mut mean1 = T::zero();
324 let mut mean2 = T::zero();
325 for i in 0..n {
326 mean1 = mean1 + point1[i];
327 mean2 = mean2 + point2[i];
328 }
329 mean1 = mean1 / T::from(n).expect("Operation failed");
330 mean2 = mean2 / T::from(n).expect("Operation failed");
331 let mut point1_centered = vec![T::zero(); n];
332 let mut point2_centered = vec![T::zero(); n];
333 for i in 0..n {
334 point1_centered[i] = point1[i] - mean1;
335 point2_centered[i] = point2[i] - mean2;
336 }
337 cosine(&point1_centered, &point2_centered)
338}
339/// Compute Jaccard distance between two boolean arrays
340///
341/// # Arguments
342///
343/// * `point1` - First boolean array
344/// * `point2` - Second boolean array
345///
346/// # Returns
347///
348/// * Jaccard distance between the arrays
349///
350/// # Examples
351///
352/// ```
353/// use scirs2_spatial::distance::jaccard;
354///
355/// let point1 = &[1.0, 0.0, 1.0];
356/// let point2 = &[0.0, 1.0, 1.0];
357///
358/// let dist = jaccard(point1, point2);
359/// assert!((dist - 0.6666667f64).abs() < 1e-6);
360/// ```
361/// Mahalanobis distance between two vectors
362///
363/// The Mahalanobis distance between vectors u and v is defined as:
364/// sqrt((u-v) * VI * (u-v)^T) where VI is the inverse of the covariance matrix.
365///
366/// # Arguments
367///
368/// * `point1` - First vector
369/// * `point2` - Second vector
370/// * `vi` - The inverse of the covariance matrix, shape (n_dims, n_dims)
371///
372/// # Returns
373///
374/// * The Mahalanobis distance
375///
376/// # Examples
377///
378/// ```
379/// use scirs2_spatial::distance::mahalanobis;
380/// use scirs2_core::ndarray::array;
381///
382/// let u = &[1.0, 0.0, 0.0];
383/// let v = &[0.0, 1.0, 0.0];
384/// let vi = array![
385/// [1.0, 0.5, 0.5],
386/// [0.5, 1.0, 0.5],
387/// [0.5, 0.5, 1.0]
388/// ];
389///
390/// let dist = mahalanobis(u, v, &vi);
391/// println!("Mahalanobis distance: {}", dist);
392/// ```
393#[allow(dead_code)]
394pub fn mahalanobis<T: Float>(point1: &[T], point2: &[T], vi: &Array2<T>) -> T {
395 if point1.len() != point2.len() || vi.ncols() != point1.len() || vi.nrows() != point1.len() {
396 return T::nan();
397 }
398 let mut diff = Vec::with_capacity(point1.len());
399 for i in 0..point1.len() {
400 diff.push(point1[i] - point2[i]);
401 }
402 let mut result = vec![T::zero(); point1.len()];
403 for i in 0..vi.nrows() {
404 for j in 0..vi.ncols() {
405 result[i] = result[i] + diff[j] * vi[[i, j]];
406 }
407 }
408 let mut sum = T::zero();
409 for i in 0..point1.len() {
410 sum = sum + result[i] * diff[i];
411 }
412 sum.sqrt()
413}
414/// Standardized Euclidean distance between two vectors
415///
416/// The standardized Euclidean distance between two vectors u and v is defined as:
417/// sqrt(sum((u_i - v_i)^2 / V_i)) where V is the variance vector.
418///
419/// # Arguments
420///
421/// * `point1` - First vector
422/// * `point2` - Second vector
423/// * `variance` - The variance vector, shape (n_dims,)
424///
425/// # Returns
426///
427/// * The standardized Euclidean distance
428///
429/// # Examples
430///
431/// ```
432/// use scirs2_spatial::distance::seuclidean;
433///
434/// let u = &[1.0, 2.0, 3.0];
435/// let v = &[4.0, 5.0, 6.0];
436/// let variance = &[0.5, 1.0, 2.0];
437///
438/// let dist = seuclidean(u, v, variance);
439/// println!("Standardized Euclidean distance: {}", dist);
440/// ```
441#[allow(dead_code)]
442pub fn seuclidean<T: Float>(point1: &[T], point2: &[T], variance: &[T]) -> T {
443 if point1.len() != point2.len() || point1.len() != variance.len() {
444 return T::nan();
445 }
446 let mut sum = T::zero();
447 for i in 0..point1.len() {
448 let diff = point1[i] - point2[i];
449 let v = if variance[i] > T::zero() {
450 variance[i]
451 } else {
452 T::one()
453 };
454 sum = sum + (diff * diff) / v;
455 }
456 sum.sqrt()
457}
458/// Bray-Curtis distance between two vectors
459///
460/// The Bray-Curtis distance between two vectors u and v is defined as:
461/// sum(|u_i - v_i|) / sum(|u_i + v_i|)
462///
463/// # Arguments
464///
465/// * `point1` - First vector
466/// * `point2` - Second vector
467///
468/// # Returns
469///
470/// * The Bray-Curtis distance
471///
472/// # Examples
473///
474/// ```
475/// use scirs2_spatial::distance::braycurtis;
476///
477/// let u = &[1.0, 2.0, 3.0];
478/// let v = &[4.0, 5.0, 6.0];
479///
480/// let dist = braycurtis(u, v);
481/// println!("Bray-Curtis distance: {}", dist);
482/// ```
483#[allow(dead_code)]
484pub fn braycurtis<T: Float>(point1: &[T], point2: &[T]) -> T {
485 if point1.len() != point2.len() {
486 return T::nan();
487 }
488 let mut sum_abs_diff = T::zero();
489 let mut sum_abs_sum = T::zero();
490 for i in 0..point1.len() {
491 sum_abs_diff = sum_abs_diff + (point1[i] - point2[i]).abs();
492 sum_abs_sum = sum_abs_sum + (point1[i] + point2[i]).abs();
493 }
494 if sum_abs_sum > T::zero() {
495 sum_abs_diff / sum_abs_sum
496 } else {
497 T::zero()
498 }
499}