Skip to content

Commit 4876b97

Browse files
committed
chebyshev: Implement Chebyshev distance
1 parent 5deaaf8 commit 4876b97

2 files changed

Lines changed: 121 additions & 0 deletions

File tree

src/chebyshev.rs

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
//! Chebyshev distance.
2+
3+
use crate::coords::{Coordinates, CoordinateMetric, CoordinateProximity};
4+
use crate::distance::{Metric, Proximity};
5+
6+
use num_traits::{zero, Signed};
7+
8+
/// A point in Chebyshev space.
9+
///
10+
/// This wrapper equips any [coordinate space] with the [Chebyshev distance] metric.
11+
///
12+
/// [coordinate space]: [Coordinates]
13+
/// [Chebyshev distance]: https://en.wikipedia.org/wiki/Chebyshev_distance
14+
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
15+
pub struct Chebyshev<T>(pub T);
16+
17+
impl<T> Chebyshev<T> {
18+
/// Wrap a point.
19+
pub fn new(point: T) -> Self {
20+
Self(point)
21+
}
22+
23+
/// Unwrap a point.
24+
pub fn inner(&self) -> &T {
25+
&self.0
26+
}
27+
28+
/// Unwrap a point.
29+
pub fn into_inner(self) -> T {
30+
self.0
31+
}
32+
}
33+
34+
impl<T: Coordinates> Coordinates for Chebyshev<T> {
35+
type Value = T::Value;
36+
37+
fn dims(&self) -> usize {
38+
self.0.dims()
39+
}
40+
41+
fn coord(&self, i: usize) -> Self::Value {
42+
self.0.coord(i)
43+
}
44+
}
45+
46+
/// Compute the Chebyshev distance between two points.
47+
pub fn chebyshev_distance<T, U>(x: T, y: U) -> T::Value
48+
where
49+
T: Coordinates,
50+
U: Coordinates<Value = T::Value>,
51+
{
52+
debug_assert!(x.dims() == y.dims());
53+
54+
let mut max = zero();
55+
56+
for i in 0..x.dims() {
57+
let diff = (x.coord(i) - y.coord(i)).abs();
58+
if diff > max {
59+
max = diff;
60+
}
61+
}
62+
63+
max
64+
}
65+
66+
/// The Chebyshev distance function.
67+
impl<T: Coordinates> Proximity for Chebyshev<T> {
68+
type Distance = T::Value;
69+
70+
fn distance(&self, other: &Self) -> Self::Distance {
71+
chebyshev_distance(self, other)
72+
}
73+
}
74+
75+
impl<T: Coordinates> Proximity<T> for Chebyshev<T> {
76+
type Distance = T::Value;
77+
78+
fn distance(&self, other: &T) -> Self::Distance {
79+
chebyshev_distance(self, other)
80+
}
81+
}
82+
83+
impl<T: Coordinates> Proximity<Chebyshev<T>> for T {
84+
type Distance = T::Value;
85+
86+
fn distance(&self, other: &Chebyshev<T>) -> Self::Distance {
87+
chebyshev_distance(self, other)
88+
}
89+
}
90+
91+
/// Chebyshev distance is a metric.
92+
impl<T: Coordinates> Metric for Chebyshev<T> {}
93+
94+
impl<T: Coordinates> Metric<T> for Chebyshev<T> {}
95+
96+
impl<T: Coordinates> Metric<Chebyshev<T>> for T {}
97+
98+
impl<T: Coordinates> CoordinateProximity<T::Value> for Chebyshev<T> {
99+
type Distance = T::Value;
100+
101+
fn distance_to_coords(&self, coords: &[T::Value]) -> Self::Distance {
102+
chebyshev_distance(self, coords)
103+
}
104+
}
105+
106+
impl<T: Coordinates> CoordinateMetric<T::Value> for Chebyshev<T> {}
107+
108+
#[cfg(test)]
109+
mod tests {
110+
use super::*;
111+
112+
#[test]
113+
fn test_distance() {
114+
assert_eq!(chebyshev_distance(&[-3, 4], &[4, -3]), 7);
115+
116+
assert_eq!(Chebyshev([-3, 4]).distance(&Chebyshev([4, -3])), 7);
117+
assert_eq!(Chebyshev([-3, 4]).distance(&[4, -3]), 7);
118+
assert_eq!([-3, 4].distance(&Chebyshev([4, -3])), 7);
119+
}
120+
}

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@
9090
//! [`nearest_within()`]: NearestNeighbors#method.nearest_within
9191
//! [`k_nearest_within()`]: NearestNeighbors#method.k_nearest_within
9292
93+
pub mod chebyshev;
9394
pub mod coords;
9495
pub mod distance;
9596
pub mod euclid;

0 commit comments

Comments
 (0)