use crate::numeric::Float;
use crate::simd_ops::{AutoOptimizer, SimdUnifiedOps};
use ::ndarray::{Array1, ArrayView1};
#[allow(dead_code)]
pub fn argmin_simd<F>(x: &ArrayView1<F>) -> Option<usize>
where
F: Float + SimdUnifiedOps,
{
if x.is_empty() {
return None;
}
let optimizer = AutoOptimizer::new();
if optimizer.should_use_simd(x.len()) {
return F::simd_argmin(x);
}
let mut min_idx = 0;
let mut min_val = x[0];
for (i, &val) in x.iter().enumerate().skip(1) {
if val < min_val {
min_idx = i;
min_val = val;
}
}
Some(min_idx)
}
#[allow(dead_code)]
pub fn argmax_simd<F>(x: &ArrayView1<F>) -> Option<usize>
where
F: Float + SimdUnifiedOps,
{
if x.is_empty() {
return None;
}
let optimizer = AutoOptimizer::new();
if optimizer.should_use_simd(x.len()) {
return F::simd_argmax(x);
}
let mut max_idx = 0;
let mut max_val = x[0];
for (i, &val) in x.iter().enumerate().skip(1) {
if val > max_val {
max_idx = i;
max_val = val;
}
}
Some(max_idx)
}
#[allow(dead_code)]
pub fn argmin_k<F>(x: &ArrayView1<F>, k: usize) -> Option<Array1<usize>>
where
F: Float + SimdUnifiedOps,
{
if x.is_empty() || k == 0 {
return None;
}
let k = k.min(x.len());
let mut indexed: Vec<(usize, F)> = x.iter().enumerate().map(|(i, &v)| (i, v)).collect();
indexed.select_nth_unstable_by(k - 1, |a, b| {
a.1.partial_cmp(&b.1).unwrap_or(std::cmp::Ordering::Equal)
});
let mut result: Vec<usize> = indexed[..k].iter().map(|(i, _)| *i).collect();
result.sort_unstable_by(|&a, &b| x[a].partial_cmp(&x[b]).unwrap_or(std::cmp::Ordering::Equal));
Some(Array1::from_vec(result))
}
#[allow(dead_code)]
pub fn argmax_k<F>(x: &ArrayView1<F>, k: usize) -> Option<Array1<usize>>
where
F: Float + SimdUnifiedOps,
{
if x.is_empty() || k == 0 {
return None;
}
let k = k.min(x.len());
let mut indexed: Vec<(usize, F)> = x.iter().enumerate().map(|(i, &v)| (i, v)).collect();
indexed.select_nth_unstable_by(k - 1, |a, b| {
b.1.partial_cmp(&a.1).unwrap_or(std::cmp::Ordering::Equal) });
let mut result: Vec<usize> = indexed[..k].iter().map(|(i, _)| *i).collect();
result.sort_unstable_by(|&a, &b| {
x[b].partial_cmp(&x[a]).unwrap_or(std::cmp::Ordering::Equal) });
Some(Array1::from_vec(result))
}
#[allow(dead_code)]
pub fn cumsum_simd<F>(x: &ArrayView1<F>) -> Array1<F>
where
F: Float + SimdUnifiedOps,
{
if x.is_empty() {
return Array1::zeros(0);
}
let optimizer = AutoOptimizer::new();
if optimizer.should_use_simd(x.len()) {
return F::simd_cumsum(x);
}
if x.is_empty() {
return Array1::zeros(0);
}
let mut cumsum = x[0];
let mut result = Array1::zeros(x.len());
result[0] = cumsum;
for i in 1..x.len() {
cumsum = cumsum + x[i];
result[i] = cumsum;
}
result
}
#[allow(dead_code)]
pub fn cumprod_simd<F>(x: &ArrayView1<F>) -> Array1<F>
where
F: Float + SimdUnifiedOps,
{
if x.is_empty() {
return Array1::zeros(0);
}
let optimizer = AutoOptimizer::new();
if optimizer.should_use_simd(x.len()) {
return F::simd_cumprod(x);
}
if x.is_empty() {
return Array1::zeros(0);
}
let mut cumprod = x[0];
let mut result = Array1::zeros(x.len());
result[0] = cumprod;
for i in 1..x.len() {
cumprod = cumprod * x[i];
result[i] = cumprod;
}
result
}
#[allow(dead_code)]
pub fn min_simd<F>(x: &ArrayView1<F>) -> Option<F>
where
F: Float + SimdUnifiedOps,
{
if x.is_empty() {
return None;
}
let optimizer = AutoOptimizer::new();
if optimizer.should_use_simd(x.len()) {
Some(F::simd_min_element(x))
} else {
let mut min_val = x[0];
for &val in x.iter().skip(1) {
if val < min_val {
min_val = val;
}
}
Some(min_val)
}
}
#[allow(dead_code)]
pub fn max_simd<F>(x: &ArrayView1<F>) -> Option<F>
where
F: Float + SimdUnifiedOps,
{
if x.is_empty() {
return None;
}
let optimizer = AutoOptimizer::new();
if optimizer.should_use_simd(x.len()) {
Some(F::simd_max_element(x))
} else {
let mut max_val = x[0];
for &val in x.iter().skip(1) {
if val > max_val {
max_val = val;
}
}
Some(max_val)
}
}
#[allow(dead_code)]
pub fn mean_simd<F>(x: &ArrayView1<F>) -> Option<F>
where
F: Float + SimdUnifiedOps,
{
if x.is_empty() {
return None;
}
Some(F::simd_mean(x))
}
#[allow(dead_code)]
pub fn variance_simd<F>(x: &ArrayView1<F>, ddof: usize) -> Option<F>
where
F: Float + SimdUnifiedOps,
{
let n = x.len();
if n == 0 || n <= ddof {
return None;
}
if ddof == 1 {
return Some(F::simd_variance(x));
}
let sample_var = F::simd_variance(x); let n_f = F::from(n).expect("Failed to convert to float");
let ddof_f = F::from(ddof).expect("Failed to convert to float");
Some(sample_var * (n_f - F::one()) / (n_f - ddof_f))
}
#[allow(dead_code)]
pub fn std_simd<F>(x: &ArrayView1<F>, ddof: usize) -> Option<F>
where
F: Float + SimdUnifiedOps,
{
variance_simd(x, ddof).map(|var| var.sqrt())
}
#[allow(dead_code)]
pub fn sum_simd<F>(x: &ArrayView1<F>) -> F
where
F: Float + SimdUnifiedOps,
{
if x.is_empty() {
return F::zero();
}
let optimizer = AutoOptimizer::new();
if optimizer.should_use_simd(x.len()) {
F::simd_sum(x)
} else {
x.iter().fold(F::zero(), |acc, &val| acc + val)
}
}
#[cfg(test)]
mod tests {
use super::*;
use ::ndarray::array;
#[test]
fn test_argmin_simd_f64_basic() {
let x = array![3.0f64, 1.0, 4.0, 1.0, 5.0, 9.0, 2.0];
let idx = argmin_simd(&x.view()).expect("Operation failed");
assert_eq!(idx, 1, "Should find first occurrence of minimum");
}
#[test]
fn test_argmin_simd_f32_basic() {
let x = array![3.0f32, 1.0, 4.0, 1.0, 5.0, 9.0, 2.0];
let idx = argmin_simd(&x.view()).expect("Operation failed");
assert_eq!(idx, 1, "Should find first occurrence of minimum");
}
#[test]
fn test_argmax_simd_f64_basic() {
let x = array![3.0f64, 1.0, 4.0, 1.0, 5.0, 9.0, 2.0];
let idx = argmax_simd(&x.view()).expect("Operation failed");
assert_eq!(idx, 5, "Should find maximum element");
}
#[test]
fn test_argmax_simd_f32_basic() {
let x = array![3.0f32, 1.0, 4.0, 1.0, 5.0, 9.0, 2.0];
let idx = argmax_simd(&x.view()).expect("Operation failed");
assert_eq!(idx, 5, "Should find maximum element");
}
#[test]
fn test_argmin_simd_empty() {
let x: Array1<f64> = array![];
assert_eq!(argmin_simd(&x.view()), None);
}
#[test]
fn test_argmax_simd_empty() {
let x: Array1<f64> = array![];
assert_eq!(argmax_simd(&x.view()), None);
}
#[test]
fn test_argmin_simd_single() {
let x = array![42.0f64];
assert_eq!(argmin_simd(&x.view()), Some(0));
}
#[test]
fn test_argmax_simd_single() {
let x = array![42.0f64];
assert_eq!(argmax_simd(&x.view()), Some(0));
}
#[test]
fn test_argmin_simd_negative() {
let x = array![1.0f64, -5.0, 3.0, -2.0];
assert_eq!(argmin_simd(&x.view()), Some(1));
}
#[test]
fn test_argmax_simd_negative() {
let x = array![-10.0f64, -5.0, -20.0, -2.0];
assert_eq!(argmax_simd(&x.view()), Some(3));
}
#[test]
fn test_argmin_simd_large_f32() {
let x: Array1<f32> = Array1::from_vec((0..10000).map(|i| (i as f32) % 100.0).collect());
assert_eq!(argmin_simd(&x.view()), Some(0));
}
#[test]
fn test_argmax_simd_large_f64() {
let x: Array1<f64> = Array1::from_vec((0..10000).map(|i| (i as f64) % 100.0).collect());
assert_eq!(argmax_simd(&x.view()), Some(99));
}
#[test]
fn test_argmin_k_basic() {
let x = array![3.0f32, 1.0, 4.0, 1.0, 5.0, 9.0, 2.0];
let indices = argmin_k(&x.view(), 3).expect("Operation failed");
assert_eq!(indices.len(), 3);
for &idx in indices.iter() {
assert!(x[idx] <= 2.0);
}
}
#[test]
fn test_argmax_k_basic() {
let x = array![3.0f32, 1.0, 4.0, 1.0, 5.0, 9.0, 2.0];
let indices = argmax_k(&x.view(), 3).expect("Operation failed");
assert_eq!(indices.len(), 3);
for &idx in indices.iter() {
assert!(x[idx] >= 4.0);
}
}
#[test]
fn test_argmin_k_empty() {
let x: Array1<f64> = array![];
assert_eq!(argmin_k(&x.view(), 3), None);
}
#[test]
fn test_argmax_k_zero() {
let x = array![1.0f64, 2.0, 3.0];
assert_eq!(argmax_k(&x.view(), 0), None);
}
#[test]
fn test_argmin_k_exceeds_length() {
let x = array![1.0f64, 2.0, 3.0];
let indices = argmin_k(&x.view(), 10).expect("Operation failed");
assert_eq!(indices.len(), 3); }
#[test]
fn test_min_simd_f64_basic() {
let x = array![3.0f64, 1.0, 4.0, 1.0, 5.0, 9.0, 2.0];
let min_val = min_simd(&x.view()).expect("Operation failed");
assert_eq!(min_val, 1.0);
}
#[test]
fn test_min_simd_f32_basic() {
let x = array![3.0f32, 1.0, 4.0, 1.0, 5.0, 9.0, 2.0];
let min_val = min_simd(&x.view()).expect("Operation failed");
assert_eq!(min_val, 1.0);
}
#[test]
fn test_max_simd_f64_basic() {
let x = array![3.0f64, 1.0, 4.0, 1.0, 5.0, 9.0, 2.0];
let max_val = max_simd(&x.view()).expect("Operation failed");
assert_eq!(max_val, 9.0);
}
#[test]
fn test_max_simd_f32_basic() {
let x = array![3.0f32, 1.0, 4.0, 1.0, 5.0, 9.0, 2.0];
let max_val = max_simd(&x.view()).expect("Operation failed");
assert_eq!(max_val, 9.0);
}
#[test]
fn test_min_simd_empty() {
let x: Array1<f64> = array![];
assert_eq!(min_simd(&x.view()), None);
}
#[test]
fn test_max_simd_empty() {
let x: Array1<f64> = array![];
assert_eq!(max_simd(&x.view()), None);
}
#[test]
fn test_min_simd_single() {
let x = array![42.0f64];
assert_eq!(min_simd(&x.view()), Some(42.0));
}
#[test]
fn test_max_simd_single() {
let x = array![42.0f64];
assert_eq!(max_simd(&x.view()), Some(42.0));
}
#[test]
fn test_min_simd_negative() {
let x = array![1.0f64, -5.0, 3.0, -2.0];
assert_eq!(min_simd(&x.view()), Some(-5.0));
}
#[test]
fn test_max_simd_negative() {
let x = array![-10.0f64, -5.0, -20.0, -2.0];
assert_eq!(max_simd(&x.view()), Some(-2.0));
}
#[test]
fn test_min_simd_large_f32() {
let x: Array1<f32> = Array1::from_vec((0..10000).map(|i| (i as f32) % 100.0).collect());
assert_eq!(min_simd(&x.view()), Some(0.0));
}
#[test]
fn test_max_simd_large_f64() {
let x: Array1<f64> = Array1::from_vec((0..10000).map(|i| (i as f64) % 100.0).collect());
assert_eq!(max_simd(&x.view()), Some(99.0));
}
#[test]
fn test_mean_simd_f64_basic() {
let x = array![1.0f64, 2.0, 3.0, 4.0, 5.0];
let mean = mean_simd(&x.view()).expect("Operation failed");
assert!((mean - 3.0).abs() < 1e-10);
}
#[test]
fn test_mean_simd_f32_basic() {
let x = array![1.0f32, 2.0, 3.0, 4.0, 5.0];
let mean = mean_simd(&x.view()).expect("Operation failed");
assert!((mean - 3.0).abs() < 1e-6);
}
#[test]
fn test_mean_simd_empty() {
let x: Array1<f64> = array![];
assert_eq!(mean_simd(&x.view()), None);
}
#[test]
fn test_mean_simd_single() {
let x = array![42.0f64];
assert_eq!(mean_simd(&x.view()), Some(42.0));
}
#[test]
fn test_mean_simd_negative() {
let x = array![-2.0f64, -4.0, -6.0, -8.0, -10.0];
let mean = mean_simd(&x.view()).expect("Operation failed");
assert!((mean - (-6.0)).abs() < 1e-10);
}
#[test]
fn test_mean_simd_large() {
let x: Array1<f64> = Array1::from_vec((1..=10000).map(|i| i as f64).collect());
let mean = mean_simd(&x.view()).expect("Operation failed");
let expected = 5000.5; assert!((mean - expected).abs() < 1e-6);
}
#[test]
fn test_variance_simd_f64_population() {
let x = array![1.0f64, 2.0, 3.0, 4.0, 5.0];
let var = variance_simd(&x.view(), 0).expect("Operation failed"); assert!((var - 2.0).abs() < 1e-10);
}
#[test]
fn test_variance_simd_f64_sample() {
let x = array![1.0f64, 2.0, 3.0, 4.0, 5.0];
let var = variance_simd(&x.view(), 1).expect("Operation failed"); assert!((var - 2.5).abs() < 1e-10);
}
#[test]
fn test_variance_simd_f32_population() {
let x = array![1.0f32, 2.0, 3.0, 4.0, 5.0];
let var = variance_simd(&x.view(), 0).expect("Operation failed");
assert!((var - 2.0).abs() < 1e-6);
}
#[test]
fn test_variance_simd_empty() {
let x: Array1<f64> = array![];
assert_eq!(variance_simd(&x.view(), 0), None);
}
#[test]
fn test_variance_simd_insufficient_data() {
let x = array![42.0f64];
assert_eq!(variance_simd(&x.view(), 1), None); assert!(variance_simd(&x.view(), 0).is_some()); }
#[test]
fn test_variance_simd_constant() {
let x = array![5.0f64, 5.0, 5.0, 5.0, 5.0];
let var = variance_simd(&x.view(), 0).expect("Operation failed");
assert!(var.abs() < 1e-10); }
#[test]
fn test_std_simd_f64_sample() {
let x = array![1.0f64, 2.0, 3.0, 4.0, 5.0];
let std = std_simd(&x.view(), 1).expect("Operation failed");
let expected = 2.5_f64.sqrt(); assert!((std - expected).abs() < 1e-10);
}
#[test]
fn test_std_simd_f32_sample() {
let x = array![1.0f32, 2.0, 3.0, 4.0, 5.0];
let std = std_simd(&x.view(), 1).expect("Operation failed");
let expected = 2.5_f32.sqrt();
assert!((std - expected).abs() < 1e-6);
}
#[test]
fn test_std_simd_empty() {
let x: Array1<f64> = array![];
assert_eq!(std_simd(&x.view(), 0), None);
}
#[test]
fn test_std_simd_constant() {
let x = array![7.0f64, 7.0, 7.0, 7.0, 7.0];
let std = std_simd(&x.view(), 0).expect("Operation failed");
assert!(std.abs() < 1e-10); }
#[test]
fn test_sum_simd_f64_basic() {
let x = array![1.0f64, 2.0, 3.0, 4.0, 5.0];
let sum = sum_simd(&x.view());
assert_eq!(sum, 15.0);
}
#[test]
fn test_sum_simd_f32_basic() {
let x = array![1.0f32, 2.0, 3.0, 4.0, 5.0];
let sum = sum_simd(&x.view());
assert_eq!(sum, 15.0);
}
#[test]
fn test_sum_simd_empty() {
let x: Array1<f64> = array![];
assert_eq!(sum_simd(&x.view()), 0.0);
}
#[test]
fn test_sum_simd_negative() {
let x = array![-1.0f64, -2.0, -3.0, -4.0, -5.0];
let sum = sum_simd(&x.view());
assert_eq!(sum, -15.0);
}
#[test]
fn test_sum_simd_large() {
let x: Array1<f64> = Array1::from_vec((1..=10000).map(|i| i as f64).collect());
let sum = sum_simd(&x.view());
let expected = 50005000.0; assert!((sum - expected).abs() < 1e-6);
}
}