pub fn add_f32(a: &[f32], b: &[f32]) -> Vec<f32> {
a.iter().zip(b).map(|(x, y)| x + y).collect()
}
pub fn sub_f32(a: &[f32], b: &[f32]) -> Vec<f32> {
a.iter().zip(b).map(|(x, y)| x - y).collect()
}
pub fn mul_f32(a: &[f32], b: &[f32]) -> Vec<f32> {
a.iter().zip(b).map(|(x, y)| x * y).collect()
}
pub fn dot_f32(a: &[f32], b: &[f32]) -> f32 {
a.iter().zip(b).map(|(x, y)| x * y).sum()
}
pub fn cosine_distance_f32(a: &[f32], b: &[f32]) -> f32 {
let dot = dot_f32(a, b);
let norm_a = norm_f32(a);
let norm_b = norm_f32(b);
if norm_a == 0.0 || norm_b == 0.0 {
1.0
} else {
1.0 - (dot / (norm_a * norm_b))
}
}
pub fn euclidean_distance_f32(a: &[f32], b: &[f32]) -> f32 {
a.iter()
.zip(b)
.map(|(x, y)| (x - y).powi(2))
.sum::<f32>()
.sqrt()
}
pub fn manhattan_distance_f32(a: &[f32], b: &[f32]) -> f32 {
a.iter().zip(b).map(|(x, y)| (x - y).abs()).sum()
}
pub fn norm_f32(a: &[f32]) -> f32 {
a.iter().map(|x| x * x).sum::<f32>().sqrt()
}
pub fn sum_f32(a: &[f32]) -> f32 {
a.iter().sum()
}
pub fn add_f64(a: &[f64], b: &[f64]) -> Vec<f64> {
a.iter().zip(b).map(|(x, y)| x + y).collect()
}
pub fn sub_f64(a: &[f64], b: &[f64]) -> Vec<f64> {
a.iter().zip(b).map(|(x, y)| x - y).collect()
}
pub fn mul_f64(a: &[f64], b: &[f64]) -> Vec<f64> {
a.iter().zip(b).map(|(x, y)| x * y).collect()
}
pub fn dot_f64(a: &[f64], b: &[f64]) -> f64 {
a.iter().zip(b).map(|(x, y)| x * y).sum()
}
pub fn cosine_distance_f64(a: &[f64], b: &[f64]) -> f64 {
let dot = dot_f64(a, b);
let norm_a = norm_f64(a);
let norm_b = norm_f64(b);
if norm_a == 0.0 || norm_b == 0.0 {
1.0
} else {
1.0 - (dot / (norm_a * norm_b))
}
}
pub fn euclidean_distance_f64(a: &[f64], b: &[f64]) -> f64 {
a.iter()
.zip(b)
.map(|(x, y)| (x - y).powi(2))
.sum::<f64>()
.sqrt()
}
pub fn manhattan_distance_f64(a: &[f64], b: &[f64]) -> f64 {
a.iter().zip(b).map(|(x, y)| (x - y).abs()).sum()
}
pub fn norm_f64(a: &[f64]) -> f64 {
a.iter().map(|x| x * x).sum::<f64>().sqrt()
}
pub fn sum_f64(a: &[f64]) -> f64 {
a.iter().sum()
}