From dabe50c19d1c5cf9b60021cf6bb971b49c44a599 Mon Sep 17 00:00:00 2001 From: Morgan Prior Date: Mon, 18 Sep 2023 07:45:23 -0400 Subject: [PATCH] added dot product distance --- src/vectors/angular.rs | 81 ++++++++++++++++++++++++++++++++++++++++++ src/vectors/mod.rs | 2 +- 2 files changed, 82 insertions(+), 1 deletion(-) diff --git a/src/vectors/angular.rs b/src/vectors/angular.rs index 5580e66..e35bb72 100644 --- a/src/vectors/angular.rs +++ b/src/vectors/angular.rs @@ -187,3 +187,84 @@ pub fn bray_curtis(x: &[T], y: &[T]) -> U { } } } + +/// Computes the dot product between two vectors. +/// +/// The dot product is defined as the sum of the products of the +/// corresponding entries of the two vectors. +/// +/// # Arguments +/// +/// * `x`: A slice of numbers. +/// * `y`: A slice of numbers. +/// +/// # Examples +/// +/// ``` +/// use distances::vectors::dot_product; +/// +/// let x: Vec = vec![1.0, 5.0, 4.0]; +/// let y: Vec = vec![2.5, 3.0, 0.5]; +/// +/// let distance: f32 = dot_product(&x, &y); +/// +/// assert!((distance - 19.5).abs() < f32::EPSILON); +/// ``` +/// +/// # References +/// +/// * [Dot product](https://en.wikipedia.org/wiki/Dot_product) +pub fn dot_product(x: &[T], y: &[T]) -> U { + let dot_product: T = x.iter().zip(y.iter()).map(|(&a, &b)| a * b).sum(); + + let dot_product: U = U::from(dot_product); + + if dot_product < U::epsilon() { + U::zero() + } else { + dot_product + } +} + +/// Computes a distance between two vectors using their dot product. +/// Vectors with greater dot products are considered more similar, +/// and hence have a smaller distance. +/// +/// The dot product is defined as the sum of the products of the +/// corresponding entries of the two vectors. +/// +/// Thia function is not stable. +/// +/// See the [`crate::vectors`] module documentation for information on this +/// function's potentially unexpected behaviors +/// +/// # Arguments +/// +/// * `x`: A slice of numbers. +/// * `y`: A slice of numbers. +/// +/// # Examples +/// +/// ``` +/// use distances::vectors::dot_product_distance; +/// +/// let x: Vec = vec![1.0, 5.0, 4.0]; +/// let y: Vec = vec![2.5, 3.0, 0.5]; +/// +/// let distance: f32 = dot_product_distance(&x, &y); +/// +/// assert!((distance - 0.05128205128).abs() < f32::EPSILON); +/// ``` +/// +/// # References +/// +/// * [Dot product](https://en.wikipedia.org/wiki/Dot_product) +pub fn dot_product_distance(x: &[T], y: &[T]) -> U { + let dot_product: U = dot_product(x, y); + + if dot_product < U::epsilon() { + dot_product + } else { + U::one() / dot_product + } +} diff --git a/src/vectors/mod.rs b/src/vectors/mod.rs index 3f015a4..be7ef6a 100644 --- a/src/vectors/mod.rs +++ b/src/vectors/mod.rs @@ -10,7 +10,7 @@ mod angular; mod lp_norms; pub(crate) mod utils; -pub use angular::{bray_curtis, canberra, cosine, hamming}; +pub use angular::{bray_curtis, canberra, cosine, dot_product_distance, hamming}; pub use lp_norms::{ chebyshev, euclidean, euclidean_sq, l3_norm, l4_norm, manhattan, minkowski, minkowski_p, };