summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@tavianator.com>2020-06-24 11:03:31 -0400
committerTavian Barnes <tavianator@tavianator.com>2020-06-24 11:03:31 -0400
commitd30c8b9dd7524ad34892352617fd81ba4f8d10d6 (patch)
tree0f6e48e7d2b2d74eb5b1d2944db291d733fcc781
parent73422e8221cd0334fb9fbf3f33059b9e531e1487 (diff)
downloadacap-d30c8b9dd7524ad34892352617fd81ba4f8d10d6.tar.xz
lp: Implement general L^p spaces
-rw-r--r--src/lib.rs1
-rw-r--r--src/lp.rs58
2 files changed, 59 insertions, 0 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 0bbd835..43d9bf1 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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);
+ }
+}