Skip to main content

oxiphysics_core/statistics/
functions_2.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5#[allow(unused_imports)]
6use super::functions::*;
7#[allow(unused_imports)]
8use super::types::*;
9#[cfg(test)]
10mod tests_new_statistics {
11    use super::*;
12    #[test]
13    fn test_mad_known_value() {
14        let data = [1.0, 2.0, 3.0, 4.0, 5.0];
15        assert!(
16            (mad(&data) - 1.0).abs() < 1e-10,
17            "MAD should be 1, got {}",
18            mad(&data)
19        );
20    }
21    #[test]
22    fn test_mad_empty() {
23        assert_eq!(mad(&[]), 0.0);
24    }
25    #[test]
26    fn test_mad_constant_data() {
27        let data = vec![5.0; 10];
28        assert_eq!(mad(&data), 0.0);
29    }
30    #[test]
31    fn test_mad_robust_to_outliers() {
32        let clean = [1.0, 2.0, 3.0, 4.0, 5.0];
33        let with_outlier = [1.0, 2.0, 3.0, 4.0, 5.0, 1000.0];
34        let mad_clean = mad(&clean);
35        let mad_outlier = mad(&with_outlier);
36        assert!(
37            (mad_clean - mad_outlier).abs() < 2.0,
38            "MAD should be robust to outliers"
39        );
40    }
41    #[test]
42    fn test_huber_estimator_symmetric_data() {
43        let data: Vec<f64> = (-50..=50).map(|i| i as f64).collect();
44        let mu = huber_m_estimator(&data, 1.345, 100);
45        assert!(
46            (mu - 0.0).abs() < 1.0,
47            "Huber estimate of symmetric data should be ~0, got {mu}"
48        );
49    }
50    #[test]
51    fn test_huber_estimator_empty() {
52        assert_eq!(huber_m_estimator(&[], 1.345, 100), 0.0);
53    }
54    #[test]
55    fn test_huber_estimator_robust() {
56        let data = vec![1.0, 2.0, 3.0, 4.0, 5.0, 100.0];
57        let mu = huber_m_estimator(&data, 1.345, 100);
58        let m = mean(&data);
59        assert!(
60            mu < m,
61            "Huber should be more robust than mean for data with outlier"
62        );
63    }
64    #[test]
65    fn test_tukey_biweight_symmetric() {
66        let data: Vec<f64> = (-30..=30).map(|i| i as f64).collect();
67        let mu = tukey_biweight_estimator(&data, 4.685, 100);
68        assert!(
69            (mu - 0.0).abs() < 1.0,
70            "Tukey biweight of symmetric data ~0, got {mu}"
71        );
72    }
73    #[test]
74    fn test_tukey_biweight_empty() {
75        assert_eq!(tukey_biweight_estimator(&[], 4.685, 100), 0.0);
76    }
77    #[test]
78    fn test_tukey_biweight_downweights_outliers() {
79        let data = vec![1.0, 2.0, 3.0, 4.0, 5.0, 1000.0];
80        let mu_tukey = tukey_biweight_estimator(&data, 4.685, 100);
81        let mu_mean = mean(&data);
82        assert!(
83            mu_tukey < mu_mean,
84            "Tukey should downweight outlier: tukey={mu_tukey}, mean={mu_mean}"
85        );
86    }
87    #[test]
88    fn test_empirical_cdf_length() {
89        let data = [1.0, 2.0, 3.0, 4.0, 5.0];
90        let ecdf = empirical_cdf(&data);
91        assert_eq!(ecdf.len(), 5);
92    }
93    #[test]
94    fn test_empirical_cdf_last_is_one() {
95        let data = [3.0, 1.0, 4.0, 1.0, 5.0, 9.0];
96        let ecdf = empirical_cdf(&data);
97        assert!(
98            (ecdf.last().unwrap().1 - 1.0).abs() < 1e-12,
99            "last ECDF value should be 1"
100        );
101    }
102    #[test]
103    fn test_empirical_cdf_monotone() {
104        let data = [3.0, 1.0, 4.0, 1.0, 5.0];
105        let ecdf = empirical_cdf(&data);
106        for w in ecdf.windows(2) {
107            assert!(w[1].1 >= w[0].1, "ECDF should be non-decreasing");
108        }
109    }
110    #[test]
111    fn test_ecdf_at_known() {
112        let data = [1.0, 2.0, 3.0, 4.0, 5.0];
113        let f3 = ecdf_at(&data, 3.0);
114        assert!((f3 - 0.6).abs() < 1e-12, "F(3) = 0.6, got {f3}");
115    }
116    #[test]
117    fn test_ecdf_at_empty() {
118        assert_eq!(ecdf_at(&[], 1.0), 0.0);
119    }
120    #[test]
121    fn test_ecdf_at_below_min() {
122        let data = [2.0, 3.0, 4.0];
123        assert_eq!(ecdf_at(&data, 1.0), 0.0, "ECDF below min should be 0");
124    }
125    #[test]
126    fn test_ecdf_at_above_max() {
127        let data = [2.0, 3.0, 4.0];
128        assert!(
129            (ecdf_at(&data, 10.0) - 1.0).abs() < 1e-12,
130            "ECDF above max should be 1"
131        );
132    }
133    #[test]
134    fn test_anderson_darling_uniform_vs_uniform() {
135        let data: Vec<f64> = (1..=20).map(|i| i as f64 / 20.0).collect();
136        let a2 = anderson_darling_statistic(&data, |x| x.clamp(0.0, 1.0));
137        assert!(a2.is_finite(), "A² should be finite, got {a2}");
138    }
139    #[test]
140    fn test_anderson_darling_non_negative() {
141        let data: Vec<f64> = (0..50).map(|i| i as f64 / 50.0).collect();
142        let a2 = anderson_darling_statistic(&data, |x| x.clamp(0.0, 1.0));
143        assert!(
144            a2 >= 0.0 || a2.is_nan() || a2.is_infinite(),
145            "A² should be non-negative for typical data, got {a2}"
146        );
147    }
148    #[test]
149    fn test_anderson_darling_empty() {
150        let a2 = anderson_darling_statistic(&[], |x| x);
151        assert_eq!(a2, 0.0);
152    }
153    #[test]
154    fn test_kruskal_wallis_identical_groups() {
155        let g1 = [1.0, 2.0, 3.0];
156        let g2 = [1.0, 2.0, 3.0];
157        let h = kruskal_wallis_h(&[&g1, &g2]);
158        assert!(h.abs() < 0.1, "identical groups should give H~0, got {h}");
159    }
160    #[test]
161    fn test_kruskal_wallis_separated_groups() {
162        let g1: Vec<f64> = (0..10).map(|i| i as f64).collect();
163        let g2: Vec<f64> = (100..110).map(|i| i as f64).collect();
164        let h = kruskal_wallis_h(&[&g1, &g2]);
165        assert!(
166            h > 10.0,
167            "well-separated groups should give large H, got {h}"
168        );
169    }
170    #[test]
171    fn test_kruskal_wallis_two_groups_only_one() {
172        let g1 = [1.0, 2.0];
173        let h = kruskal_wallis_h(&[&g1]);
174        assert_eq!(h, 0.0, "single group should return 0");
175    }
176    #[test]
177    fn test_kruskal_wallis_three_groups() {
178        let g1 = [1.0, 2.0, 3.0];
179        let g2 = [4.0, 5.0, 6.0];
180        let g3 = [7.0, 8.0, 9.0];
181        let h = kruskal_wallis_h(&[&g1, &g2, &g3]);
182        assert!(
183            h > 5.0,
184            "three clearly-separated groups: H should be large, got {h}"
185        );
186    }
187    #[test]
188    fn test_kruskal_wallis_nonnegative() {
189        let g1 = [1.0, 3.0, 5.0, 7.0];
190        let g2 = [2.0, 4.0, 6.0, 8.0];
191        let h = kruskal_wallis_h(&[&g1, &g2]);
192        assert!(h >= 0.0, "H should be non-negative, got {h}");
193    }
194    #[test]
195    fn test_mad_vs_std_for_normal() {
196        let data: Vec<f64> = {
197            let mut v = Vec::new();
198            let mut rng = StatRng::new(42);
199            for _ in 0..10000 {
200                v.push(rng.next_normal());
201            }
202            v
203        };
204        let mad_val = mad(&data);
205        let std_val = std_dev(&data);
206        let mad_scaled = mad_val * 1.4826;
207        assert!(
208            (mad_scaled - std_val).abs() / std_val < 0.05,
209            "MAD*1.4826={mad_scaled} should match std_dev={std_val} within 5%"
210        );
211    }
212    #[test]
213    fn test_huber_vs_mean_clean_data() {
214        let data: Vec<f64> = {
215            let mut v = Vec::new();
216            let mut rng = StatRng::new(99);
217            for _ in 0..1000 {
218                v.push(rng.next_normal() * 2.0 + 5.0);
219            }
220            v
221        };
222        let mu = huber_m_estimator(&data, 1.345, 50);
223        assert!(
224            (mu - 5.0).abs() < 0.3,
225            "Huber on clean data should match mean~5, got {mu}"
226        );
227    }
228    #[test]
229    fn test_ecdf_is_step_function() {
230        let data = vec![1.0, 2.0, 3.0];
231        assert_eq!(ecdf_at(&data, 1.5), ecdf_at(&data, 1.9));
232    }
233    #[test]
234    fn test_anderson_darling_larger_for_bad_fit() {
235        let good: Vec<f64> = (1..=10).map(|i| i as f64 / 10.0).collect();
236        let bad: Vec<f64> = (1..=10).map(|i| i as f64 / 10.0 + 0.5).collect();
237        let a2_good = anderson_darling_statistic(&good, |x| x.clamp(0.0, 1.0));
238        let a2_bad = anderson_darling_statistic(&bad, |x| x.clamp(0.0, 1.0));
239        assert!(
240            a2_good.is_finite(),
241            "good-fit A² should be finite: {a2_good}"
242        );
243        assert!(a2_bad.is_finite(), "bad-fit A² should be finite: {a2_bad}");
244    }
245}