#[cfg(target_arch = "x86_64")]
use crate::backends::avx2::Avx2Backend;
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
use crate::backends::neon::NeonBackend;
use crate::backends::scalar::ScalarBackend;
#[cfg(target_arch = "x86_64")]
use crate::backends::sse2::Sse2Backend;
#[cfg(target_arch = "wasm32")]
use crate::backends::wasm::WasmBackend;
use crate::backends::VectorBackend;
use crate::vector::Vector;
use crate::{Backend, Result, TruenoError};
impl Vector<f32> {
pub fn sum_kahan(&self) -> Result<f32> {
if self.data.is_empty() {
return Ok(0.0);
}
let result = unsafe {
match self.backend {
Backend::Scalar => ScalarBackend::sum_kahan(&self.data),
#[cfg(target_arch = "x86_64")]
Backend::SSE2 | Backend::AVX => Sse2Backend::sum_kahan(&self.data),
#[cfg(target_arch = "x86_64")]
Backend::AVX2 | Backend::AVX512 => Avx2Backend::sum_kahan(&self.data),
#[cfg(not(target_arch = "x86_64"))]
Backend::SSE2 | Backend::AVX | Backend::AVX2 | Backend::AVX512 => {
ScalarBackend::sum_kahan(&self.data)
}
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
Backend::NEON => NeonBackend::sum_kahan(&self.data),
#[cfg(not(any(target_arch = "aarch64", target_arch = "arm")))]
Backend::NEON => ScalarBackend::sum_kahan(&self.data),
#[cfg(target_arch = "wasm32")]
Backend::WasmSIMD => WasmBackend::sum_kahan(&self.data),
#[cfg(not(target_arch = "wasm32"))]
Backend::WasmSIMD => ScalarBackend::sum_kahan(&self.data),
Backend::GPU | Backend::Auto => ScalarBackend::sum_kahan(&self.data),
}
};
Ok(result)
}
pub fn sum_of_squares(&self) -> Result<f32> {
if self.data.is_empty() {
return Ok(0.0);
}
self.dot(self)
}
pub fn mean(&self) -> Result<f32> {
if self.data.is_empty() {
return Err(TruenoError::EmptyVector);
}
let total = self.sum()?;
Ok(total / self.len() as f32)
}
pub fn variance(&self) -> Result<f32> {
if self.data.is_empty() {
return Err(TruenoError::EmptyVector);
}
let mean_val = self.mean()?;
let sum_sq = self.sum_of_squares()?;
let mean_sq = sum_sq / self.len() as f32;
Ok(mean_sq - mean_val * mean_val)
}
pub fn stddev(&self) -> Result<f32> {
let var = self.variance()?;
Ok(var.sqrt())
}
pub fn covariance(&self, other: &Self) -> Result<f32> {
if self.data.is_empty() {
return Err(TruenoError::EmptyVector);
}
if self.len() != other.len() {
return Err(TruenoError::SizeMismatch { expected: self.len(), actual: other.len() });
}
let mean_x = self.mean()?;
let mean_y = other.mean()?;
let dot_xy = self.dot(other)?;
let mean_xy = dot_xy / self.len().max(1) as f32;
Ok(mean_xy - mean_x * mean_y)
}
pub fn correlation(&self, other: &Self) -> Result<f32> {
let cov = self.covariance(other)?;
let std_x = self.stddev()?;
let std_y = other.stddev()?;
if std_x.abs() < 1e-10 || std_y.abs() < 1e-10 {
return Err(TruenoError::DivisionByZero);
}
let corr = cov / (std_x * std_y);
Ok(corr.clamp(-1.0, 1.0))
}
}