1use crate::error::StatsResult;
8use crate::error_standardization::ErrorMessages;
9use scirs2_core::ndarray::{s, Array1, ArrayBase, Data, Ix1};
10use scirs2_core::numeric::{Float, NumCast};
11use scirs2_core::simd_ops::{AutoOptimizer, PlatformCapabilities, SimdUnifiedOps};
12
13#[allow(dead_code)]
39pub fn mean_enhanced<F, D>(x: &ArrayBase<D, Ix1>) -> StatsResult<F>
40where
41 F: Float + NumCast + SimdUnifiedOps + Copy + Send + Sync,
42 D: Data<Elem = F>,
43{
44 if x.is_empty() {
45 return Err(ErrorMessages::empty_array("x"));
46 }
47
48 let n = x.len();
49 let optimizer = AutoOptimizer::new();
50 let capabilities = PlatformCapabilities::detect();
51
52 let sum = if n < 16 {
54 x.iter().fold(F::zero(), |acc, &val| acc + val)
56 } else if n < 1024 || !capabilities.avx2_available {
57 F::simd_sum(&x.view())
59 } else {
60 compensated_simd_sum(x, &optimizer)
62 };
63
64 Ok(sum / F::from(n).expect("Failed to convert to float"))
65}
66
67#[allow(dead_code)]
81pub fn variance_enhanced<F, D>(x: &ArrayBase<D, Ix1>, ddof: usize) -> StatsResult<F>
82where
83 F: Float + NumCast + SimdUnifiedOps + Copy + Send + Sync + std::iter::Sum<F>,
84 D: Data<Elem = F>,
85{
86 let n = x.len();
87 if n == 0 {
88 return Err(ErrorMessages::empty_array("x"));
89 }
90 if n <= ddof {
91 return Err(ErrorMessages::insufficientdata(
92 "variance calculation",
93 ddof + 1,
94 n,
95 ));
96 }
97
98 let optimizer = AutoOptimizer::new();
99
100 if n > 1000 && optimizer.should_use_simd(n) {
102 welford_variance_simd(x, ddof)
103 } else {
104 let mean = mean_enhanced(x)?;
106 let sum_sq_dev = if optimizer.should_use_simd(n) {
107 simd_sum_squared_deviations(x, mean)
108 } else {
109 x.iter()
110 .map(|&val| {
111 let dev = val - mean;
112 dev * dev
113 })
114 .fold(F::zero(), |acc, val| acc + val)
115 };
116
117 Ok(sum_sq_dev / F::from(n - ddof).expect("Failed to convert to float"))
118 }
119}
120
121#[allow(dead_code)]
135pub fn correlation_simd_enhanced<F, D1, D2>(
136 x: &ArrayBase<D1, Ix1>,
137 y: &ArrayBase<D2, Ix1>,
138) -> StatsResult<F>
139where
140 F: Float + NumCast + SimdUnifiedOps + Copy + Send + Sync,
141 D1: Data<Elem = F>,
142 D2: Data<Elem = F>,
143{
144 if x.is_empty() {
145 return Err(ErrorMessages::empty_array("x"));
146 }
147 if y.is_empty() {
148 return Err(ErrorMessages::empty_array("y"));
149 }
150 if x.len() != y.len() {
151 return Err(ErrorMessages::length_mismatch("x", x.len(), "y", y.len()));
152 }
153
154 let n = x.len();
155 let optimizer = AutoOptimizer::new();
156
157 if optimizer.should_use_simd(n) {
158 simd_correlation_full(x, y)
160 } else {
161 scalar_correlation_optimized(x, y)
163 }
164}
165
166#[allow(dead_code)]
180pub fn comprehensive_stats_simd<F, D>(
181 x: &ArrayBase<D, Ix1>,
182 ddof: usize,
183) -> StatsResult<ComprehensiveStats<F>>
184where
185 F: Float + NumCast + SimdUnifiedOps + Copy + Send + Sync + std::fmt::Debug + std::iter::Sum<F>,
186 D: Data<Elem = F>,
187{
188 let n = x.len();
189 if n == 0 {
190 return Err(ErrorMessages::empty_array("x"));
191 }
192 if n <= ddof {
193 return Err(ErrorMessages::insufficientdata(
194 "comprehensive statistics",
195 ddof + 1,
196 n,
197 ));
198 }
199
200 let optimizer = AutoOptimizer::new();
201
202 if optimizer.should_use_simd(n) && n > 100 {
203 simd_comprehensive_single_pass(x, ddof)
204 } else {
205 let mean = mean_enhanced(x)?;
207 let variance = variance_enhanced(x, ddof)?;
208 let std = variance.sqrt();
209
210 Ok(ComprehensiveStats {
212 mean,
213 variance,
214 std,
215 skewness: F::zero(), kurtosis: F::zero(), count: n,
218 })
219 }
220}
221
222#[derive(Debug, Clone)]
224pub struct ComprehensiveStats<F> {
225 pub mean: F,
226 pub variance: F,
227 pub std: F,
228 pub skewness: F,
229 pub kurtosis: F,
230 pub count: usize,
231}
232
233#[allow(dead_code)]
237fn compensated_simd_sum<F, D>(x: &ArrayBase<D, Ix1>, optimizer: &AutoOptimizer) -> F
238where
239 F: Float + NumCast + SimdUnifiedOps + Copy,
240 D: Data<Elem = F>,
241{
242 const CHUNK_SIZE: usize = 8192; let mut sum = F::zero();
245 let mut compensation = F::zero();
246
247 let n = x.len();
249 let num_full_chunks = n / CHUNK_SIZE;
250 let remainder = n % CHUNK_SIZE;
251
252 for chunk in x.exact_chunks(CHUNK_SIZE) {
253 let chunk_sum = if optimizer.should_use_simd(chunk.len()) {
254 F::simd_sum(&chunk.view())
255 } else {
256 chunk.iter().fold(F::zero(), |acc, &val| acc + val)
257 };
258
259 let y = chunk_sum - compensation;
261 let t = sum + y;
262 compensation = (t - sum) - y;
263 sum = t;
264 }
265
266 if remainder > 0 {
268 let remainder_start = num_full_chunks * CHUNK_SIZE;
269 let remainder_slice = x.slice(s![remainder_start..]);
270 let remainder_sum = remainder_slice
271 .iter()
272 .fold(F::zero(), |acc, &val| acc + val);
273
274 let y = remainder_sum - compensation;
276 let t = sum + y;
277 sum = t;
278 }
279
280 sum
281}
282
283#[allow(dead_code)]
296pub fn mean_ultra_simd<F, D>(x: &ArrayBase<D, Ix1>) -> StatsResult<F>
297where
298 F: Float + NumCast + SimdUnifiedOps + Copy + Send + Sync,
299 D: Data<Elem = F>,
300{
301 if x.is_empty() {
302 return Err(ErrorMessages::empty_array("x"));
303 }
304
305 let n = x.len();
306 let capabilities = PlatformCapabilities::detect();
307
308 let sum = if n < 32 {
310 x.iter().fold(F::zero(), |acc, &val| acc + val)
312 } else if n < 64 || !capabilities.has_avx2() {
313 F::simd_sum(&x.view())
315 } else {
316 bandwidth_saturated_sum_ultra(x)
318 };
319
320 Ok(sum / F::from(n).expect("Failed to convert to float"))
321}
322
323#[allow(dead_code)]
328pub fn variance_ultra_simd<F, D>(x: &ArrayBase<D, Ix1>, ddof: usize) -> StatsResult<F>
329where
330 F: Float + NumCast + SimdUnifiedOps + Copy + Send + Sync + std::iter::Sum<F>,
331 D: Data<Elem = F>,
332{
333 let n = x.len();
334 if n == 0 {
335 return Err(ErrorMessages::empty_array("x"));
336 }
337 if n <= ddof {
338 return Err(ErrorMessages::insufficientdata(
339 "variance calculation",
340 ddof + 1,
341 n,
342 ));
343 }
344
345 let capabilities = PlatformCapabilities::detect();
346
347 if n >= 128 && capabilities.has_avx2() {
348 bandwidth_saturated_variance_ultra(x, ddof)
350 } else if n >= 64 {
351 let mean = mean_ultra_simd(x)?;
353 let sum_sq_dev = bandwidth_saturated_sum_squared_deviations_ultra(x, mean);
354 Ok(sum_sq_dev / F::from(n - ddof).expect("Failed to convert to float"))
355 } else {
356 variance_enhanced(x, ddof)
358 }
359}
360
361#[allow(dead_code)]
366pub fn correlation_ultra_simd<F, D1, D2>(
367 x: &ArrayBase<D1, Ix1>,
368 y: &ArrayBase<D2, Ix1>,
369) -> StatsResult<F>
370where
371 F: Float + NumCast + SimdUnifiedOps + Copy + Send + Sync,
372 D1: Data<Elem = F>,
373 D2: Data<Elem = F>,
374{
375 if x.is_empty() {
376 return Err(ErrorMessages::empty_array("x"));
377 }
378 if y.is_empty() {
379 return Err(ErrorMessages::empty_array("y"));
380 }
381 if x.len() != y.len() {
382 return Err(ErrorMessages::length_mismatch("x", x.len(), "y", y.len()));
383 }
384
385 let n = x.len();
386 let capabilities = PlatformCapabilities::detect();
387
388 if n >= 128 && capabilities.has_avx2() {
389 bandwidth_saturated_correlation_ultra(x, y)
391 } else if n >= 64 {
392 simd_correlation_full(x, y)
394 } else {
395 scalar_correlation_optimized(x, y)
397 }
398}
399
400#[allow(dead_code)]
405pub fn comprehensive_stats_ultra_simd<F, D>(
406 x: &ArrayBase<D, Ix1>,
407 ddof: usize,
408) -> StatsResult<ComprehensiveStats<F>>
409where
410 F: Float + NumCast + SimdUnifiedOps + Copy + Send + Sync + std::fmt::Debug + std::iter::Sum<F>,
411 D: Data<Elem = F>,
412{
413 let n = x.len();
414 if n == 0 {
415 return Err(ErrorMessages::empty_array("x"));
416 }
417 if n <= ddof {
418 return Err(ErrorMessages::insufficientdata(
419 "comprehensive statistics",
420 ddof + 1,
421 n,
422 ));
423 }
424
425 let capabilities = PlatformCapabilities::detect();
426
427 if n >= 256 && capabilities.has_avx2() {
428 bandwidth_saturated_comprehensive_ultra(x, ddof)
430 } else if n >= 64 {
431 simd_comprehensive_single_pass(x, ddof)
433 } else {
434 comprehensive_stats_simd(x, ddof)
436 }
437}
438
439#[allow(dead_code)]
443fn bandwidth_saturated_sum_ultra<F, D>(x: &ArrayBase<D, Ix1>) -> F
444where
445 F: Float + NumCast + SimdUnifiedOps + Copy,
446 D: Data<Elem = F>,
447{
448 let n = x.len();
449 let chunk_size = 16; let mut total_sum = F::zero();
452
453 for chunk_start in (0..n).step_by(chunk_size) {
455 let chunk_end = (chunk_start + chunk_size).min(n);
456 let chunk_len = chunk_end - chunk_start;
457
458 if chunk_len == chunk_size {
459 let chunk_data: Array1<f32> = x
461 .slice(scirs2_core::ndarray::s![chunk_start..chunk_end])
462 .iter()
463 .map(|&val| val.to_f64().expect("Operation failed") as f32)
464 .collect();
465
466 let chunk_sum = f32::simd_sum_f32_ultra(&chunk_data.view());
468 total_sum = total_sum + F::from(chunk_sum as f64).expect("Failed to convert to float");
469 } else {
470 for i in chunk_start..chunk_end {
472 total_sum = total_sum + x[i];
473 }
474 }
475 }
476
477 total_sum
478}
479
480#[allow(dead_code)]
482fn bandwidth_saturated_variance_ultra<F, D>(x: &ArrayBase<D, Ix1>, ddof: usize) -> StatsResult<F>
483where
484 F: Float + NumCast + SimdUnifiedOps + Copy,
485 D: Data<Elem = F>,
486{
487 let n = x.len();
488 let chunk_size = 16;
489
490 let mut sum = F::zero();
491 let mut sum_sq = F::zero();
492
493 for chunk_start in (0..n).step_by(chunk_size) {
495 let chunk_end = (chunk_start + chunk_size).min(n);
496 let chunk_len = chunk_end - chunk_start;
497
498 if chunk_len == chunk_size {
499 let chunk_data: Array1<f32> = x
501 .slice(scirs2_core::ndarray::s![chunk_start..chunk_end])
502 .iter()
503 .map(|&val| val.to_f64().expect("Operation failed") as f32)
504 .collect();
505
506 let chunk_sum = f32::simd_sum_f32_ultra(&chunk_data.view());
508
509 let mut chunk_squared: Array1<f32> = Array1::zeros(chunk_size);
511 f32::simd_mul_f32_ultra(
512 &chunk_data.view(),
513 &chunk_data.view(),
514 &mut chunk_squared.view_mut(),
515 );
516 let chunk_sum_sq = f32::simd_sum_f32_ultra(&chunk_squared.view());
517
518 sum = sum + F::from(chunk_sum as f64).expect("Failed to convert to float");
519 sum_sq = sum_sq + F::from(chunk_sum_sq as f64).expect("Failed to convert to float");
520 } else {
521 for i in chunk_start..chunk_end {
523 let val = x[i];
524 sum = sum + val;
525 sum_sq = sum_sq + val * val;
526 }
527 }
528 }
529
530 let n_f = F::from(n).expect("Failed to convert to float");
531 let mean = sum / n_f;
532 let variance =
533 (sum_sq - n_f * mean * mean) / F::from(n - ddof).expect("Failed to convert to float");
534
535 Ok(variance)
536}
537
538#[allow(dead_code)]
540fn bandwidth_saturated_sum_squared_deviations_ultra<F, D>(x: &ArrayBase<D, Ix1>, mean: F) -> F
541where
542 F: Float + NumCast + SimdUnifiedOps + Copy,
543 D: Data<Elem = F>,
544{
545 let n = x.len();
546 let chunk_size = 16;
547 let mean_f32 = mean.to_f64().expect("Operation failed") as f32;
548
549 let mut total_sum_sq_dev = F::zero();
550
551 for chunk_start in (0..n).step_by(chunk_size) {
552 let chunk_end = (chunk_start + chunk_size).min(n);
553 let chunk_len = chunk_end - chunk_start;
554
555 if chunk_len == chunk_size {
556 let chunk_data: Array1<f32> = x
558 .slice(scirs2_core::ndarray::s![chunk_start..chunk_end])
559 .iter()
560 .map(|&val| val.to_f64().expect("Operation failed") as f32)
561 .collect();
562
563 let mean_array: Array1<f32> = Array1::from_elem(chunk_size, mean_f32);
565 let mut deviations: Array1<f32> = Array1::zeros(chunk_size);
566 f32::simd_sub_f32_ultra(
567 &chunk_data.view(),
568 &mean_array.view(),
569 &mut deviations.view_mut(),
570 );
571
572 let mut squared_deviations: Array1<f32> = Array1::zeros(chunk_size);
574 f32::simd_mul_f32_ultra(
575 &deviations.view(),
576 &deviations.view(),
577 &mut squared_deviations.view_mut(),
578 );
579
580 let chunk_sum_sq_dev = f32::simd_sum_f32_ultra(&squared_deviations.view());
582 total_sum_sq_dev = total_sum_sq_dev
583 + F::from(chunk_sum_sq_dev as f64).expect("Failed to convert to float");
584 } else {
585 for i in chunk_start..chunk_end {
587 let dev = x[i] - mean;
588 total_sum_sq_dev = total_sum_sq_dev + dev * dev;
589 }
590 }
591 }
592
593 total_sum_sq_dev
594}
595
596#[allow(dead_code)]
598fn bandwidth_saturated_correlation_ultra<F, D1, D2>(
599 x: &ArrayBase<D1, Ix1>,
600 y: &ArrayBase<D2, Ix1>,
601) -> StatsResult<F>
602where
603 F: Float + NumCast + SimdUnifiedOps + Copy,
604 D1: Data<Elem = F>,
605 D2: Data<Elem = F>,
606{
607 let n = x.len();
608 let chunk_size = 16;
609
610 let mut sum_x = F::zero();
611 let mut sum_y = F::zero();
612 let mut sum_xy = F::zero();
613 let mut sum_x2 = F::zero();
614 let mut sum_y2 = F::zero();
615
616 for chunk_start in (0..n).step_by(chunk_size) {
618 let chunk_end = (chunk_start + chunk_size).min(n);
619 let chunk_len = chunk_end - chunk_start;
620
621 if chunk_len == chunk_size {
622 let x_chunk: Array1<f32> = x
624 .slice(scirs2_core::ndarray::s![chunk_start..chunk_end])
625 .iter()
626 .map(|&val| val.to_f64().expect("Operation failed") as f32)
627 .collect();
628 let y_chunk: Array1<f32> = y
629 .slice(scirs2_core::ndarray::s![chunk_start..chunk_end])
630 .iter()
631 .map(|&val| val.to_f64().expect("Operation failed") as f32)
632 .collect();
633
634 let chunk_sum_x = f32::simd_sum_f32_ultra(&x_chunk.view());
636 let chunk_sum_y = f32::simd_sum_f32_ultra(&y_chunk.view());
637
638 let mut xy_products: Array1<f32> = Array1::zeros(chunk_size);
640 let mut x_squared: Array1<f32> = Array1::zeros(chunk_size);
641 let mut y_squared: Array1<f32> = Array1::zeros(chunk_size);
642
643 f32::simd_mul_f32_ultra(
644 &x_chunk.view(),
645 &y_chunk.view(),
646 &mut xy_products.view_mut(),
647 );
648 f32::simd_mul_f32_ultra(&x_chunk.view(), &x_chunk.view(), &mut x_squared.view_mut());
649 f32::simd_mul_f32_ultra(&y_chunk.view(), &y_chunk.view(), &mut y_squared.view_mut());
650
651 let chunk_sum_xy = f32::simd_sum_f32_ultra(&xy_products.view());
652 let chunk_sum_x2 = f32::simd_sum_f32_ultra(&x_squared.view());
653 let chunk_sum_y2 = f32::simd_sum_f32_ultra(&y_squared.view());
654
655 sum_x = sum_x + F::from(chunk_sum_x as f64).expect("Failed to convert to float");
657 sum_y = sum_y + F::from(chunk_sum_y as f64).expect("Failed to convert to float");
658 sum_xy = sum_xy + F::from(chunk_sum_xy as f64).expect("Failed to convert to float");
659 sum_x2 = sum_x2 + F::from(chunk_sum_x2 as f64).expect("Failed to convert to float");
660 sum_y2 = sum_y2 + F::from(chunk_sum_y2 as f64).expect("Failed to convert to float");
661 } else {
662 for i in chunk_start..chunk_end {
664 let x_val = x[i];
665 let y_val = y[i];
666 sum_x = sum_x + x_val;
667 sum_y = sum_y + y_val;
668 sum_xy = sum_xy + x_val * y_val;
669 sum_x2 = sum_x2 + x_val * x_val;
670 sum_y2 = sum_y2 + y_val * y_val;
671 }
672 }
673 }
674
675 let n_f = F::from(n).expect("Failed to convert to float");
676 let mean_x = sum_x / n_f;
677 let mean_y = sum_y / n_f;
678
679 let numerator = sum_xy - n_f * mean_x * mean_y;
680 let denom_x = sum_x2 - n_f * mean_x * mean_x;
681 let denom_y = sum_y2 - n_f * mean_y * mean_y;
682
683 if denom_x <= F::epsilon() || denom_y <= F::epsilon() {
684 return Err(ErrorMessages::numerical_instability(
685 "correlation calculation",
686 "One or both variables have zero variance",
687 ));
688 }
689
690 Ok(numerator / (denom_x * denom_y).sqrt())
691}
692
693#[allow(dead_code)]
695fn bandwidth_saturated_comprehensive_ultra<F, D>(
696 x: &ArrayBase<D, Ix1>,
697 ddof: usize,
698) -> StatsResult<ComprehensiveStats<F>>
699where
700 F: Float + NumCast + SimdUnifiedOps + Copy + std::fmt::Debug,
701 D: Data<Elem = F>,
702{
703 let n = x.len();
704 let chunk_size = 16;
705
706 let mut sum = F::zero();
707 let mut sum_sq = F::zero();
708 let mut sum_cube = F::zero();
709 let mut sum_fourth = F::zero();
710
711 for chunk_start in (0..n).step_by(chunk_size) {
713 let chunk_end = (chunk_start + chunk_size).min(n);
714 let chunk_len = chunk_end - chunk_start;
715
716 if chunk_len == chunk_size {
717 let chunk_data: Array1<f32> = x
719 .slice(scirs2_core::ndarray::s![chunk_start..chunk_end])
720 .iter()
721 .map(|&val| val.to_f64().expect("Operation failed") as f32)
722 .collect();
723
724 let mut chunk_squared: Array1<f32> = Array1::zeros(chunk_size);
726 let mut chunk_cubed: Array1<f32> = Array1::zeros(chunk_size);
727 let mut chunk_fourth: Array1<f32> = Array1::zeros(chunk_size);
728
729 f32::simd_mul_f32_ultra(
730 &chunk_data.view(),
731 &chunk_data.view(),
732 &mut chunk_squared.view_mut(),
733 );
734 f32::simd_mul_f32_ultra(
735 &chunk_squared.view(),
736 &chunk_data.view(),
737 &mut chunk_cubed.view_mut(),
738 );
739 f32::simd_mul_f32_ultra(
740 &chunk_squared.view(),
741 &chunk_squared.view(),
742 &mut chunk_fourth.view_mut(),
743 );
744
745 let chunk_sum = f32::simd_sum_f32_ultra(&chunk_data.view());
747 let chunk_sum_sq = f32::simd_sum_f32_ultra(&chunk_squared.view());
748 let chunk_sum_cube = f32::simd_sum_f32_ultra(&chunk_cubed.view());
749 let chunk_sum_fourth = f32::simd_sum_f32_ultra(&chunk_fourth.view());
750
751 sum = sum + F::from(chunk_sum as f64).expect("Failed to convert to float");
753 sum_sq = sum_sq + F::from(chunk_sum_sq as f64).expect("Failed to convert to float");
754 sum_cube =
755 sum_cube + F::from(chunk_sum_cube as f64).expect("Failed to convert to float");
756 sum_fourth =
757 sum_fourth + F::from(chunk_sum_fourth as f64).expect("Failed to convert to float");
758 } else {
759 for i in chunk_start..chunk_end {
761 let val = x[i];
762 let val_sq = val * val;
763 sum = sum + val;
764 sum_sq = sum_sq + val_sq;
765 sum_cube = sum_cube + val_sq * val;
766 sum_fourth = sum_fourth + val_sq * val_sq;
767 }
768 }
769 }
770
771 let n_f = F::from(n).expect("Failed to convert to float");
772 let mean = sum / n_f;
773 let mean_sq = mean * mean;
774 let mean_cube = mean_sq * mean;
775 let mean_fourth = mean_sq * mean_sq;
776
777 let m2 = (sum_sq / n_f) - mean_sq;
779 let m3 = (sum_cube / n_f)
780 - F::from(3.0).expect("Failed to convert constant to float") * mean * m2
781 - mean_cube;
782 let m4 = (sum_fourth / n_f)
783 - F::from(4.0).expect("Failed to convert constant to float") * mean * m3
784 - F::from(6.0).expect("Failed to convert constant to float") * mean_sq * m2
785 - mean_fourth;
786
787 let variance = m2 * n_f / F::from(n - ddof).expect("Failed to convert to float");
788 let std = variance.sqrt();
789
790 let skewness = if m2 > F::epsilon() {
792 m3 / m2.powf(F::from(1.5).expect("Failed to convert constant to float"))
793 } else {
794 F::zero()
795 };
796
797 let kurtosis = if m2 > F::epsilon() {
798 (m4 / (m2 * m2)) - F::from(3.0).expect("Failed to convert constant to float")
799 } else {
800 F::zero()
801 };
802
803 Ok(ComprehensiveStats {
804 mean,
805 variance,
806 std,
807 skewness,
808 kurtosis,
809 count: n,
810 })
811}
812
813#[allow(dead_code)]
815fn welford_variance_simd<F, D>(x: &ArrayBase<D, Ix1>, ddof: usize) -> StatsResult<F>
816where
817 F: Float + NumCast + SimdUnifiedOps + Copy,
818 D: Data<Elem = F>,
819{
820 let n = x.len();
821 let mut mean = F::zero();
822 let mut m2 = F::zero();
823
824 const SIMD_CHUNK: usize = 8;
826 let full_chunks = n / SIMD_CHUNK;
827
828 for i in 0..full_chunks {
829 let start = i * SIMD_CHUNK;
830 let end = (i + 1) * SIMD_CHUNK;
831 let chunk = x.slice(scirs2_core::ndarray::s![start..end]);
832
833 for (j, &val) in chunk.iter().enumerate() {
835 let count = F::from(start + j + 1).expect("Failed to convert to float");
836 let delta = val - mean;
837 mean = mean + delta / count;
838 let delta2 = val - mean;
839 m2 = m2 + delta * delta2;
840 }
841 }
842
843 for (i, &val) in x.iter().enumerate().skip(full_chunks * SIMD_CHUNK) {
845 let count = F::from(i + 1).expect("Failed to convert to float");
846 let delta = val - mean;
847 mean = mean + delta / count;
848 let delta2 = val - mean;
849 m2 = m2 + delta * delta2;
850 }
851
852 Ok(m2 / F::from(n - ddof).expect("Failed to convert to float"))
853}
854
855#[allow(dead_code)]
857fn simd_sum_squared_deviations<F, D>(x: &ArrayBase<D, Ix1>, mean: F) -> F
858where
859 F: Float + NumCast + SimdUnifiedOps + Copy + std::iter::Sum<F>,
860 D: Data<Elem = F>,
861{
862 let mean_array = Array1::from_elem(x.len(), mean);
863 let deviations = F::simd_sub(&x.view(), &mean_array.view());
864 F::simd_mul(&deviations.view(), &deviations.view()).sum()
865}
866
867#[allow(dead_code)]
869fn simd_correlation_full<F, D1, D2>(
870 x: &ArrayBase<D1, Ix1>,
871 y: &ArrayBase<D2, Ix1>,
872) -> StatsResult<F>
873where
874 F: Float + NumCast + SimdUnifiedOps + Copy,
875 D1: Data<Elem = F>,
876 D2: Data<Elem = F>,
877{
878 let n = x.len();
879 let n_f = F::from(n).expect("Failed to convert to float");
880
881 let mean_x = F::simd_sum(&x.view()) / n_f;
883 let mean_y = F::simd_sum(&y.view()) / n_f;
884
885 let mean_x_array = Array1::from_elem(n, mean_x);
887 let mean_y_array = Array1::from_elem(n, mean_y);
888
889 let dev_x = F::simd_sub(&x.view(), &mean_x_array.view());
891 let dev_y = F::simd_sub(&y.view(), &mean_y_array.view());
892
893 let sum_xy = F::simd_mul(&dev_x.view(), &dev_y.view()).sum();
895 let sum_x2 = F::simd_mul(&dev_x.view(), &dev_x.view()).sum();
896 let sum_y2 = F::simd_mul(&dev_y.view(), &dev_y.view()).sum();
897
898 if sum_x2 <= F::epsilon() || sum_y2 <= F::epsilon() {
900 return Err(ErrorMessages::numerical_instability(
901 "correlation calculation",
902 "One or both variables have zero variance",
903 ));
904 }
905
906 Ok(sum_xy / (sum_x2 * sum_y2).sqrt())
907}
908
909#[allow(dead_code)]
911fn scalar_correlation_optimized<F, D1, D2>(
912 x: &ArrayBase<D1, Ix1>,
913 y: &ArrayBase<D2, Ix1>,
914) -> StatsResult<F>
915where
916 F: Float + NumCast + Copy,
917 D1: Data<Elem = F>,
918 D2: Data<Elem = F>,
919{
920 let n = x.len();
921 let n_f = F::from(n).expect("Failed to convert to float");
922
923 let mut sum_x = F::zero();
925 let mut sum_y = F::zero();
926 let mut sum_xy = F::zero();
927 let mut sum_x2 = F::zero();
928 let mut sum_y2 = F::zero();
929
930 for (x_val, y_val) in x.iter().zip(y.iter()) {
931 sum_x = sum_x + *x_val;
932 sum_y = sum_y + *y_val;
933 sum_xy = sum_xy + (*x_val) * (*y_val);
934 sum_x2 = sum_x2 + (*x_val) * (*x_val);
935 sum_y2 = sum_y2 + (*y_val) * (*y_val);
936 }
937
938 let mean_x = sum_x / n_f;
939 let mean_y = sum_y / n_f;
940
941 let numerator = sum_xy - n_f * mean_x * mean_y;
942 let denom_x = sum_x2 - n_f * mean_x * mean_x;
943 let denom_y = sum_y2 - n_f * mean_y * mean_y;
944
945 if denom_x <= F::epsilon() || denom_y <= F::epsilon() {
946 return Err(ErrorMessages::numerical_instability(
947 "correlation calculation",
948 "One or both variables have zero variance",
949 ));
950 }
951
952 Ok(numerator / (denom_x * denom_y).sqrt())
953}
954
955#[allow(dead_code)]
957fn simd_comprehensive_single_pass<F, D>(
958 x: &ArrayBase<D, Ix1>,
959 ddof: usize,
960) -> StatsResult<ComprehensiveStats<F>>
961where
962 F: Float + NumCast + SimdUnifiedOps + Copy + std::fmt::Debug,
963 D: Data<Elem = F>,
964{
965 let n = x.len();
966 let n_f = F::from(n).expect("Failed to convert to float");
967
968 let mean = F::simd_sum(&x.view()) / n_f;
970
971 let mean_array = Array1::from_elem(n, mean);
973 let deviations = F::simd_sub(&x.view(), &mean_array.view());
974
975 let dev_squared = F::simd_mul(&deviations.view(), &deviations.view());
977 let dev_cubed = F::simd_mul(&dev_squared.view(), &deviations.view());
978 let dev_fourth = F::simd_mul(&dev_squared.view(), &dev_squared.view());
979
980 let m2 = dev_squared.sum();
982 let m3 = dev_cubed.sum();
983 let m4 = dev_fourth.sum();
984
985 let variance = m2 / F::from(n - ddof).expect("Failed to convert to float");
986 let std = variance.sqrt();
987
988 let skewness = if variance > F::epsilon() {
990 (m3 / n_f) / variance.powf(F::from(1.5).expect("Failed to convert constant to float"))
991 } else {
992 F::zero()
993 };
994
995 let kurtosis = if variance > F::epsilon() {
996 (m4 / n_f) / (variance * variance)
997 - F::from(3.0).expect("Failed to convert constant to float")
998 } else {
999 F::zero()
1000 };
1001
1002 Ok(ComprehensiveStats {
1003 mean,
1004 variance,
1005 std,
1006 skewness,
1007 kurtosis,
1008 count: n,
1009 })
1010}