#[allow(unused_imports)]
use crate::math::FloatMath;
pub fn euclidean_distance_f32(a: &[f32], b: &[f32]) -> f32 {
let len = a.len().min(b.len());
let mut sum_sq = 0.0f32;
for i in 0..len {
let diff = a[i] - b[i];
sum_sq += diff * diff;
}
sum_sq.sqrt()
}
pub fn cosine_distance_f32(a: &[f32], b: &[f32]) -> f32 {
let len = a.len().min(b.len());
let mut dot = 0.0f32;
let mut norm_a = 0.0f32;
let mut norm_b = 0.0f32;
for i in 0..len {
dot += a[i] * b[i];
norm_a += a[i] * a[i];
norm_b += b[i] * b[i];
}
let denom = norm_a.sqrt() * norm_b.sqrt();
if denom != 0.0 {
1.0 - (dot / denom)
} else {
1.0
}
}
pub fn chebyshev_distance_f32(a: &[f32], b: &[f32]) -> f32 {
let len = a.len().min(b.len());
let mut max_diff = 0.0f32;
for i in 0..len {
let diff = (a[i] - b[i]).abs();
if diff > max_diff {
max_diff = diff;
}
}
max_diff
}
pub fn manhattan_distance_f32(a: &[f32], b: &[f32]) -> f32 {
let len = a.len().min(b.len());
let mut sum = 0.0f32;
for i in 0..len {
sum += (a[i] - b[i]).abs();
}
sum
}
pub fn minkowski_distance_f32(a: &[f32], b: &[f32], p: f32) -> f32 {
let len = a.len().min(b.len());
let mut sum = 0.0f32;
for i in 0..len {
let diff = (a[i] - b[i]).abs();
sum += diff.powf(p);
}
sum.powf(1.0 / p)
}
pub fn jaccard_distance_f32(a: &[f32], b: &[f32]) -> f32 {
let len = a.len().min(b.len());
let mut tf = 0.0f32;
let mut tt = 0.0f32;
for i in 0..len {
let a_bool = a[i] != 0.0;
let b_bool = b[i] != 0.0;
if a_bool && b_bool {
tt += 1.0;
} else if a_bool || b_bool {
tf += 1.0;
}
}
if tt + tf > 0.0 { tf / (tt + tf) } else { 0.0 }
}
pub fn hamming_distance_f32(a: &[f32], b: &[f32]) -> f32 {
let len = a.len().min(b.len());
let mut diff_count = 0.0f32;
for i in 0..len {
if a[i] != b[i] {
diff_count += 1.0;
}
}
diff_count
}
pub fn canberra_distance_f32(a: &[f32], b: &[f32]) -> f32 {
let len = a.len().min(b.len());
let mut sum = 0.0f32;
for i in 0..len {
let num = (a[i] - b[i]).abs();
let denom = a[i].abs() + b[i].abs();
if denom != 0.0 {
sum += num / denom;
}
}
sum
}
pub fn bray_curtis_distance_f32(a: &[f32], b: &[f32]) -> f32 {
let len = a.len().min(b.len());
let mut num = 0.0f32;
let mut denom = 0.0f32;
for i in 0..len {
num += (a[i] - b[i]).abs();
denom += (a[i] + b[i]).abs();
}
if denom != 0.0 { num / denom } else { 0.0 }
}
use crate::types::{q15, q31, q63};
pub fn euclidean_distance_q15(a: &[q15], b: &[q15]) -> q15 {
let len = a.len().min(b.len());
if len == 0 {
return q15::ZERO;
}
let mut sum_sq: q63 = 0;
for i in 0..len {
let diff = (a[i].to_bits() as i32) - (b[i].to_bits() as i32);
sum_sq += (diff * diff) as q63;
}
let mean_sq = (sum_sq / (len as q63)) as i32;
let scaled_mean = q15::from_bits((mean_sq >> 17).clamp(0, i16::MAX as i32) as i16);
let mut root = q15::ZERO;
let _ = crate::fast_math::sqrt_q15(scaled_mean, &mut root);
root.saturating_add(root)
}
pub fn euclidean_distance_q31(a: &[q31], b: &[q31]) -> q31 {
let len = a.len().min(b.len());
if len == 0 {
return q31::ZERO;
}
let mut sum_sq: i128 = 0;
for i in 0..len {
let diff = (a[i].to_bits() as i64) - (b[i].to_bits() as i64);
sum_sq += (diff * diff) as i128;
}
let mean_sq = (sum_sq / (len as i128)) as i64;
let scaled_mean = q31::from_bits((mean_sq >> 33).clamp(0, i32::MAX as i64) as i32);
let mut root = q31::ZERO;
let _ = crate::fast_math::sqrt_q31(scaled_mean, &mut root);
root.saturating_add(root)
}
pub fn chebyshev_distance_q15(a: &[q15], b: &[q15]) -> q15 {
let len = a.len().min(b.len());
let mut max_diff: i32 = 0;
for i in 0..len {
let diff = ((a[i].to_bits() as i32) - (b[i].to_bits() as i32)).abs();
if diff > max_diff {
max_diff = diff;
}
}
q15::from_bits(max_diff.clamp(0, i16::MAX as i32) as i16)
}
pub fn chebyshev_distance_q31(a: &[q31], b: &[q31]) -> q31 {
let len = a.len().min(b.len());
let mut max_diff: i64 = 0;
for i in 0..len {
let diff = ((a[i].to_bits() as i64) - (b[i].to_bits() as i64)).abs();
if diff > max_diff {
max_diff = diff;
}
}
q31::from_bits(max_diff.clamp(0, i32::MAX as i64) as i32)
}
pub fn manhattan_distance_q15(a: &[q15], b: &[q15]) -> q31 {
let len = a.len().min(b.len());
let mut sum = q31::ZERO;
for i in 0..len {
let diff = ((a[i].to_bits() as i32) - (b[i].to_bits() as i32)).abs();
sum = sum.saturating_add(q31::from_bits(diff));
}
sum
}
pub fn manhattan_distance_q31(a: &[q31], b: &[q31]) -> q63 {
let len = a.len().min(b.len());
let mut sum: q63 = 0;
for i in 0..len {
let diff = ((a[i].to_bits() as i64) - (b[i].to_bits() as i64)).abs();
sum = sum.saturating_add(diff);
}
sum
}
pub fn cosine_distance_q15(a: &[q15], b: &[q15]) -> q15 {
let len = a.len().min(b.len());
if len == 0 {
return q15::ZERO;
}
let mut dot: i64 = 0;
let mut norm_a_sq: i64 = 0;
let mut norm_b_sq: i64 = 0;
for i in 0..len {
let ai = a[i].to_bits() as i64;
let bi = b[i].to_bits() as i64;
dot += ai * bi;
norm_a_sq += ai * ai;
norm_b_sq += bi * bi;
}
if norm_a_sq == 0 || norm_b_sq == 0 {
return q15::from_bits(32767); }
let norm_a_mean = (norm_a_sq / len as i64).clamp(0, i32::MAX as i64) as i32;
let norm_b_mean = (norm_b_sq / len as i64).clamp(0, i32::MAX as i64) as i32;
let mut norm_a = q15::ZERO;
let mut norm_b = q15::ZERO;
let _ = crate::fast_math::sqrt_q15(
q15::from_bits((norm_a_mean >> 15).clamp(0, i16::MAX as i32) as i16),
&mut norm_a,
);
let _ = crate::fast_math::sqrt_q15(
q15::from_bits((norm_b_mean >> 15).clamp(0, i16::MAX as i32) as i16),
&mut norm_b,
);
let denom = (norm_a.to_bits() as i64 * norm_b.to_bits() as i64) * len as i64;
if denom == 0 {
return q15::from_bits(32767);
}
let sim = (dot << 15) / denom;
let sim_clamped = sim.clamp(-32768, 32767) as i32;
q15::from_bits((32767 - sim_clamped).clamp(0, 32767) as i16)
}
pub fn cosine_distance_q31(a: &[q31], b: &[q31]) -> q31 {
let len = a.len().min(b.len());
if len == 0 {
return q31::ZERO;
}
let mut dot: i128 = 0;
let mut norm_a_sq: i128 = 0;
let mut norm_b_sq: i128 = 0;
for i in 0..len {
let ai = a[i].to_bits() as i128;
let bi = b[i].to_bits() as i128;
dot += ai * bi;
norm_a_sq += ai * ai;
norm_b_sq += bi * bi;
}
if norm_a_sq == 0 || norm_b_sq == 0 {
return q31::from_bits(i32::MAX);
}
let norm_a_mean = (norm_a_sq / len as i128) as i64;
let norm_b_mean = (norm_b_sq / len as i128) as i64;
let mut norm_a = q31::ZERO;
let mut norm_b = q31::ZERO;
let _ = crate::fast_math::sqrt_q31(
q31::from_bits((norm_a_mean >> 31).clamp(0, i32::MAX as i64) as i32),
&mut norm_a,
);
let _ = crate::fast_math::sqrt_q31(
q31::from_bits((norm_b_mean >> 31).clamp(0, i32::MAX as i64) as i32),
&mut norm_b,
);
let denom = (norm_a.to_bits() as i128 * norm_b.to_bits() as i128) * len as i128;
if denom == 0 {
return q31::from_bits(i32::MAX);
}
let sim = (dot << 31) / denom;
let sim_clamped = sim.clamp(i32::MIN as i128, i32::MAX as i128) as i64;
q31::from_bits((i32::MAX as i64 - sim_clamped).clamp(0, i32::MAX as i64) as i32)
}
pub fn hamming_distance_q15(a: &[q15], b: &[q15]) -> usize {
let len = a.len().min(b.len());
let mut diff = 0;
for i in 0..len {
if a[i] != b[i] {
diff += 1;
}
}
diff
}
pub fn hamming_distance_q31(a: &[q31], b: &[q31]) -> usize {
let len = a.len().min(b.len());
let mut diff = 0;
for i in 0..len {
if a[i] != b[i] {
diff += 1;
}
}
diff
}
pub fn canberra_distance_q15(a: &[q15], b: &[q15]) -> q15 {
let len = a.len().min(b.len());
if len == 0 {
return q15::ZERO;
}
let mut sum_q15: i64 = 0;
for i in 0..len {
let (ai, bi) = (a[i].to_bits() as i32, b[i].to_bits() as i32);
let num = (ai - bi).abs();
let denom = ai.abs() + bi.abs();
if denom != 0 {
let term = ((num as i64) << 15) / (denom as i64);
sum_q15 += term;
}
}
q15::from_bits((sum_q15 / len as i64).clamp(0, 32767) as i16)
}
pub fn bray_curtis_distance_q15(a: &[q15], b: &[q15]) -> q15 {
let len = a.len().min(b.len());
if len == 0 {
return q15::ZERO;
}
let mut num: i64 = 0;
let mut denom: i64 = 0;
for i in 0..len {
let (ai, bi) = (a[i].to_bits() as i32, b[i].to_bits() as i32);
num += (ai - bi).abs() as i64;
denom += (ai + bi).abs() as i64;
}
if denom == 0 {
q15::ZERO
} else {
q15::from_bits(((num << 15) / denom).clamp(0, 32767) as i16)
}
}