Skip to main content

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}