//! # Hamming Distance //! //! Hamming Distance measures the similarity between two integer-valued vectors of the same length. //! Given two vectors \\( x \in ℝ^n \\), \\( y \in ℝ^n \\) the hamming distance between \\( x \\) and \\( y \\), \\( d(x, y) \\), is the number of places where \\( x \\) and \\( y \\) differ. //! //! Example: //! //! ``` //! use smartcore::metrics::distance::Distance; //! use smartcore::metrics::distance::hamming::Hamming; //! //! let a = vec![1, 0, 0, 1, 0, 0, 1]; //! let b = vec![1, 1, 0, 0, 1, 0, 1]; //! //! let h: f64 = Hamming::new().distance(&a, &b); //! //! ``` //! //! //! #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use std::marker::PhantomData; use super::Distance; use crate::linalg::basic::arrays::ArrayView1; use crate::numbers::basenum::Number; /// While comparing two integer-valued vectors of equal length, Hamming distance is the number of bit positions in which the two bits are different #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Debug, Clone)] pub struct Hamming { _t: PhantomData, } impl Hamming { /// instatiate the initial structure pub fn new() -> Hamming { Hamming { _t: PhantomData } } } impl Default for Hamming { fn default() -> Self { Self::new() } } impl> Distance for Hamming { fn distance(&self, x: &A, y: &A) -> f64 { if x.shape() != y.shape() { panic!("Input vector sizes are different"); } let dist: usize = x .iterator(0) .zip(y.iterator(0)) .map(|(a, b)| match a != b { true => 1, false => 0, }) .sum(); dist as f64 / x.shape() as f64 } } #[cfg(test)] mod tests { use super::*; #[cfg_attr( all(target_arch = "wasm32", not(target_os = "wasi")), wasm_bindgen_test::wasm_bindgen_test )] #[test] fn hamming_distance() { let a = vec![1, 0, 0, 1, 0, 0, 1]; let b = vec![1, 1, 0, 0, 1, 0, 1]; let h: f64 = Hamming::new().distance(&a, &b); assert!((h - 0.42857142).abs() < 1e-8); } }