mod stats;
#[cfg(test)]
mod tests;
#[cfg(target_arch = "x86_64")]
use crate::backends::avx2::Avx2Backend;
#[cfg(target_arch = "x86_64")]
use crate::backends::avx512::Avx512Backend;
#[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::{dispatch_reduction, Backend, Result, TruenoError};
impl Vector<f32> {
pub fn dot(&self, other: &Self) -> Result<f32> {
if self.len() != other.len() {
return Err(TruenoError::SizeMismatch { expected: self.len(), actual: other.len() });
}
let result = unsafe {
match self.backend {
Backend::Scalar => ScalarBackend::dot(&self.data, &other.data),
#[cfg(target_arch = "x86_64")]
Backend::SSE2 | Backend::AVX => Sse2Backend::dot(&self.data, &other.data),
#[cfg(target_arch = "x86_64")]
Backend::AVX2 => Avx2Backend::dot(&self.data, &other.data),
#[cfg(target_arch = "x86_64")]
Backend::AVX512 => Avx512Backend::dot(&self.data, &other.data),
#[cfg(not(target_arch = "x86_64"))]
Backend::SSE2 | Backend::AVX | Backend::AVX2 | Backend::AVX512 => {
ScalarBackend::dot(&self.data, &other.data)
}
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
Backend::NEON => NeonBackend::dot(&self.data, &other.data),
#[cfg(not(any(target_arch = "aarch64", target_arch = "arm")))]
Backend::NEON => ScalarBackend::dot(&self.data, &other.data),
#[cfg(target_arch = "wasm32")]
Backend::WasmSIMD => WasmBackend::dot(&self.data, &other.data),
#[cfg(not(target_arch = "wasm32"))]
Backend::WasmSIMD => ScalarBackend::dot(&self.data, &other.data),
Backend::GPU | Backend::Auto => ScalarBackend::dot(&self.data, &other.data),
}
};
Ok(result)
}
pub fn sum(&self) -> Result<f32> {
Ok(dispatch_reduction!(self.backend, sum, &self.data))
}
pub fn max(&self) -> Result<f32> {
if self.data.is_empty() {
return Err(TruenoError::InvalidInput("Empty vector".to_string()));
}
let result = unsafe {
match self.backend {
Backend::Scalar => ScalarBackend::max(&self.data),
#[cfg(target_arch = "x86_64")]
Backend::SSE2 | Backend::AVX => Sse2Backend::max(&self.data),
#[cfg(target_arch = "x86_64")]
Backend::AVX2 | Backend::AVX512 => Avx2Backend::max(&self.data),
#[cfg(not(target_arch = "x86_64"))]
Backend::SSE2 | Backend::AVX | Backend::AVX2 | Backend::AVX512 => {
ScalarBackend::max(&self.data)
}
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
Backend::NEON => NeonBackend::max(&self.data),
#[cfg(not(any(target_arch = "aarch64", target_arch = "arm")))]
Backend::NEON => ScalarBackend::max(&self.data),
#[cfg(target_arch = "wasm32")]
Backend::WasmSIMD => WasmBackend::max(&self.data),
#[cfg(not(target_arch = "wasm32"))]
Backend::WasmSIMD => ScalarBackend::max(&self.data),
Backend::GPU | Backend::Auto => ScalarBackend::max(&self.data),
}
};
Ok(result)
}
pub fn min(&self) -> Result<f32> {
if self.data.is_empty() {
return Err(TruenoError::InvalidInput("Empty vector".to_string()));
}
let result = unsafe {
match self.backend {
Backend::Scalar => ScalarBackend::min(&self.data),
#[cfg(target_arch = "x86_64")]
Backend::SSE2 | Backend::AVX => Sse2Backend::min(&self.data),
#[cfg(target_arch = "x86_64")]
Backend::AVX2 | Backend::AVX512 => Avx2Backend::min(&self.data),
#[cfg(not(target_arch = "x86_64"))]
Backend::SSE2 | Backend::AVX | Backend::AVX2 | Backend::AVX512 => {
ScalarBackend::min(&self.data)
}
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
Backend::NEON => NeonBackend::min(&self.data),
#[cfg(not(any(target_arch = "aarch64", target_arch = "arm")))]
Backend::NEON => ScalarBackend::min(&self.data),
#[cfg(target_arch = "wasm32")]
Backend::WasmSIMD => WasmBackend::min(&self.data),
#[cfg(not(target_arch = "wasm32"))]
Backend::WasmSIMD => ScalarBackend::min(&self.data),
Backend::GPU | Backend::Auto => ScalarBackend::min(&self.data),
}
};
Ok(result)
}
pub fn argmax(&self) -> Result<usize> {
if self.data.is_empty() {
return Err(TruenoError::InvalidInput("Empty vector".to_string()));
}
let result = unsafe {
match self.backend {
Backend::Scalar => ScalarBackend::argmax(&self.data),
#[cfg(target_arch = "x86_64")]
Backend::SSE2 | Backend::AVX => Sse2Backend::argmax(&self.data),
#[cfg(target_arch = "x86_64")]
Backend::AVX2 | Backend::AVX512 => Avx2Backend::argmax(&self.data),
#[cfg(not(target_arch = "x86_64"))]
Backend::SSE2 | Backend::AVX | Backend::AVX2 | Backend::AVX512 => {
ScalarBackend::argmax(&self.data)
}
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
Backend::NEON => NeonBackend::argmax(&self.data),
#[cfg(not(any(target_arch = "aarch64", target_arch = "arm")))]
Backend::NEON => ScalarBackend::argmax(&self.data),
#[cfg(target_arch = "wasm32")]
Backend::WasmSIMD => WasmBackend::argmax(&self.data),
#[cfg(not(target_arch = "wasm32"))]
Backend::WasmSIMD => ScalarBackend::argmax(&self.data),
Backend::GPU | Backend::Auto => ScalarBackend::argmax(&self.data),
}
};
Ok(result)
}
pub fn argmin(&self) -> Result<usize> {
if self.data.is_empty() {
return Err(TruenoError::InvalidInput("Empty vector".to_string()));
}
let result = unsafe {
match self.backend {
Backend::Scalar => ScalarBackend::argmin(&self.data),
#[cfg(target_arch = "x86_64")]
Backend::SSE2 | Backend::AVX => Sse2Backend::argmin(&self.data),
#[cfg(target_arch = "x86_64")]
Backend::AVX2 | Backend::AVX512 => Avx2Backend::argmin(&self.data),
#[cfg(not(target_arch = "x86_64"))]
Backend::SSE2 | Backend::AVX | Backend::AVX2 | Backend::AVX512 => {
ScalarBackend::argmin(&self.data)
}
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
Backend::NEON => NeonBackend::argmin(&self.data),
#[cfg(not(any(target_arch = "aarch64", target_arch = "arm")))]
Backend::NEON => ScalarBackend::argmin(&self.data),
#[cfg(target_arch = "wasm32")]
Backend::WasmSIMD => WasmBackend::argmin(&self.data),
#[cfg(not(target_arch = "wasm32"))]
Backend::WasmSIMD => ScalarBackend::argmin(&self.data),
Backend::GPU | Backend::Auto => ScalarBackend::argmin(&self.data),
}
};
Ok(result)
}
}