use crate::VecLike;
use std::simd::Simd;
use std::simd::num::SimdFloat;
pub const SIMD_LANECOUNT: usize = 8;
pub type SimdUnit = Simd<f32, SIMD_LANECOUNT>;
impl VecLike for [f32] {
type Owned = Vec<f32>;
#[inline]
fn l2_dist_squared(&self, othr: &Self) -> f32 {
debug_assert!(self.len() == othr.len());
debug_assert!(self.len() % SIMD_LANECOUNT == 0);
let mut intermediate_sum_x8 = SimdUnit::splat(0.0);
let self_chunks = self.chunks_exact(SIMD_LANECOUNT);
let othr_chunks = othr.chunks_exact(SIMD_LANECOUNT);
for (slice_self, slice_othr) in self_chunks.zip(othr_chunks) {
let f32x8_slf = SimdUnit::from_slice(slice_self);
let f32x8_oth = SimdUnit::from_slice(slice_othr);
let diff = f32x8_slf - f32x8_oth;
intermediate_sum_x8 += diff * diff;
}
intermediate_sum_x8.reduce_sum() }
#[inline]
fn dot(&self, othr: &Self) -> f32 {
debug_assert!(self.len() == othr.len());
debug_assert!(self.len() % SIMD_LANECOUNT == 0);
let mut accumulated = SimdUnit::splat(0.0);
let self_chunks = self.chunks_exact(SIMD_LANECOUNT);
let othr_chunks = othr.chunks_exact(SIMD_LANECOUNT);
for (slice_self, slice_othr) in self_chunks.zip(othr_chunks) {
let vx = SimdUnit::from_slice(slice_self);
let vy = SimdUnit::from_slice(slice_othr);
accumulated += vx * vy;
}
accumulated.reduce_sum()
}
#[inline]
fn normalized(&self) -> Self::Owned {
let norm = self.dot(self).sqrt();
if norm == 0.0 {
return vec![0.0; self.len()];
}
let inv_norm = SimdUnit::splat(1.0 / norm);
let mut out = Vec::with_capacity(self.len());
for chunk in self.chunks_exact(SIMD_LANECOUNT) {
let v = SimdUnit::from_slice(chunk);
let scaled = v * inv_norm;
out.extend_from_slice(&scaled.to_array());
}
out
}
}