use crate::coords::Coordinates;
use crate::distance::{Metric, Proximity};
use crate::lp::Minkowski;
use num_traits::{zero, Signed};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Chebyshev<T>(pub T);
impl<T> Chebyshev<T> {
pub fn new(point: T) -> Self {
Self(point)
}
pub fn inner(&self) -> &T {
&self.0
}
pub fn into_inner(self) -> T {
self.0
}
}
impl<T: Coordinates> Coordinates for Chebyshev<T> {
type Value = T::Value;
fn dims(&self) -> usize {
self.0.dims()
}
fn coord(&self, i: usize) -> Self::Value {
self.0.coord(i)
}
}
pub fn chebyshev_distance<T, U>(x: T, y: U) -> T::Value
where
T: Coordinates,
U: Coordinates<Value = T::Value>,
{
debug_assert!(x.dims() == y.dims());
let mut max = zero();
for i in 0..x.dims() {
let diff = (x.coord(i) - y.coord(i)).abs();
if diff > max {
max = diff;
}
}
max
}
impl<T: Coordinates> Proximity for Chebyshev<T> {
type Distance = T::Value;
fn distance(&self, other: &Self) -> Self::Distance {
chebyshev_distance(self, other)
}
}
impl<T: Coordinates> Proximity<T> for Chebyshev<T> {
type Distance = T::Value;
fn distance(&self, other: &T) -> Self::Distance {
chebyshev_distance(self, other)
}
}
impl<T: Coordinates> Proximity<Chebyshev<T>> for T {
type Distance = T::Value;
fn distance(&self, other: &Chebyshev<T>) -> Self::Distance {
chebyshev_distance(self, other)
}
}
impl<T: Coordinates> Metric for Chebyshev<T> {}
impl<T: Coordinates> Metric<T> for Chebyshev<T> {}
impl<T: Coordinates> Metric<Chebyshev<T>> for T {}
impl<T: Coordinates> Minkowski for Chebyshev<T> {}
impl<T: Coordinates> Minkowski<T> for Chebyshev<T> {}
impl<T: Coordinates> Minkowski<Chebyshev<T>> for T {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_distance() {
assert_eq!(chebyshev_distance(&[-3, 4], &[4, -3]), 7);
assert_eq!(Chebyshev([-3, 4]).distance(&Chebyshev([4, -3])), 7);
assert_eq!(Chebyshev([-3, 4]).distance(&[4, -3]), 7);
assert_eq!([-3, 4].distance(&Chebyshev([4, -3])), 7);
}
}