//! [`$L^p$` spaces](https://en.wikipedia.org/wiki/Lp_space). use crate::coords::Coordinates; use num_traits::real::Real; use num_traits::zero; /// A point in L1 space. pub use crate::taxi::Taxicab as L1; /// Compute the L1 distance between two points. pub use crate::taxi::taxicab_distance as l1_distance; /// A point in L2 space. pub use crate::euclid::Euclidean as L2; /// An L2 distance. pub use crate::euclid::EuclideanDistance as L2Distance; /// Compute the L2 distance between two points. pub use crate::euclid::euclidean_distance as l2_distance; /// A point in L space. pub use crate::chebyshev::Chebyshev as Linf; /// Compute the L distance between two points. pub use crate::chebyshev::chebyshev_distance as linf_distance; /// Compute the [`$L^p$` distance] between two points. /// /// ```math /// \begin{aligned} /// \mathrm{lp\_distance}(p, x, y) &= \|x - y\|_p \\ /// &= \left( \sum_i |x_i - y_i|^p \right)^{1/p} /// \end{aligned} /// ``` /// /// [`$L^p$` distance]: https://en.wikipedia.org/wiki/Lp_space pub fn lp_distance(p: T::Value, x: T, y: U) -> T::Value where T: Coordinates, U: Coordinates, T::Value: Real, { debug_assert!(x.dims() == y.dims()); let mut sum: T::Value = zero(); for i in 0..x.dims() { sum += (x.coord(i) - y.coord(i)).abs().powf(p); } sum.powf(p.recip()) } #[cfg(test)] mod tests { use super::*; #[test] fn test_lp_distance() { assert_eq!(l1_distance(&[0.0, 0.0], &[3.0, 4.0]), 7.0); assert_eq!(l2_distance(&[0.0, 0.0], &[3.0, 4.0]), 5.0); assert!(lp_distance(3.0, &[0.0, 0.0], &[3.0, 4.0]) < 5.0); assert_eq!(linf_distance(&[0.0, 0.0], &[3.0, 4.0]), 4.0); } }