diff options
author | Tavian Barnes <tavianator@tavianator.com> | 2020-06-24 11:03:31 -0400 |
---|---|---|
committer | Tavian Barnes <tavianator@tavianator.com> | 2020-06-24 11:03:31 -0400 |
commit | d30c8b9dd7524ad34892352617fd81ba4f8d10d6 (patch) | |
tree | 0f6e48e7d2b2d74eb5b1d2944db291d733fcc781 | |
parent | 73422e8221cd0334fb9fbf3f33059b9e531e1487 (diff) | |
download | acap-d30c8b9dd7524ad34892352617fd81ba4f8d10d6.tar.xz |
lp: Implement general L^p spaces
-rw-r--r-- | src/lib.rs | 1 | ||||
-rw-r--r-- | src/lp.rs | 58 |
2 files changed, 59 insertions, 0 deletions
@@ -97,6 +97,7 @@ pub mod euclid; pub mod exhaustive; pub mod hamming; pub mod kd; +pub mod lp; pub mod taxi; pub mod vp; diff --git a/src/lp.rs b/src/lp.rs new file mode 100644 index 0000000..cf65944 --- /dev/null +++ b/src/lp.rs @@ -0,0 +1,58 @@ +//! L<sup>p</sup> spaces. + +use crate::coords::Coordinates; + +use num_traits::real::Real; +use num_traits::zero; + +/// A point in L<sup>1</sup> space. +pub use crate::taxi::Taxicab as L1; + +/// Compute the L<sup>1</sup> distance between two points. +pub use crate::taxi::taxicab_distance as l1_distance; + +/// A point in L<sup>2</sup> space. +pub use crate::euclid::Euclidean as L2; +/// An L<sup>2</sup> distance. +pub use crate::euclid::EuclideanDistance as L2Distance; + +/// Compute the L<sup>2</sup> distance between two points. +pub use crate::euclid::euclidean_distance as l2_distance; + +/// A point in L<sup>∞</sup> space. +pub use crate::chebyshev::Chebyshev as Linf; + +/// Compute the L<sup>∞</sup> distance between two points. +pub use crate::chebyshev::chebyshev_distance as linf_distance; + +/// Compute the [L<sup>p</sup> distance] between two points. +/// +/// [L<sup>p</sup> distance]: https://en.wikipedia.org/wiki/Lp_space +pub fn lp_distance<T, U>(p: T::Value, x: T, y: U) -> T::Value +where + T: Coordinates, + U: Coordinates<Value = T::Value>, + 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); + } +} |