simplebench_runtime/
statistics.rs

1//! Statistical functions for baseline comparison and regression detection
2//!
3//! This module provides core statistical operations used by both the statistical
4//! window approach and Bayesian change point detection.
5
6/// Calculate the arithmetic mean of a slice of values
7pub fn mean(values: &[f64]) -> f64 {
8    if values.is_empty() {
9        return 0.0;
10    }
11    values.iter().sum::<f64>() / values.len() as f64
12}
13
14/// Calculate the variance of a slice of values
15pub fn variance(values: &[f64]) -> f64 {
16    if values.len() < 2 {
17        return 0.0;
18    }
19
20    let m = mean(values);
21    values.iter().map(|&x| (x - m).powi(2)).sum::<f64>() / values.len() as f64
22}
23
24/// Calculate the standard deviation of a slice of values
25pub fn standard_deviation(values: &[f64]) -> f64 {
26    variance(values).sqrt()
27}
28
29/// Calculate the z-score: how many standard deviations a value is from the mean
30pub fn z_score(value: f64, mean: f64, stddev: f64) -> f64 {
31    if stddev < 1e-10 {
32        // Avoid division by zero for very low variance
33        return 0.0;
34    }
35    (value - mean) / stddev
36}
37
38/// Calculate confidence interval bounds
39///
40/// Returns (lower_bound, upper_bound) for the given confidence level.
41/// Common confidence levels:
42/// - 0.90 = 90% confidence (z = 1.645 one-tailed, 1.96 two-tailed)
43/// - 0.95 = 95% confidence (z = 1.645 one-tailed, 1.96 two-tailed)
44/// - 0.99 = 99% confidence (z = 2.326 one-tailed, 2.576 two-tailed)
45pub fn confidence_interval(mean: f64, stddev: f64, confidence_level: f64) -> (f64, f64) {
46    // Map confidence level to z-critical value (one-tailed for regression detection)
47    let z_critical = if (confidence_level - 0.90).abs() < 0.01 {
48        1.282 // 90% one-tailed
49    } else if (confidence_level - 0.95).abs() < 0.01 {
50        1.645 // 95% one-tailed
51    } else if (confidence_level - 0.99).abs() < 0.01 {
52        2.326 // 99% one-tailed
53    } else {
54        // Default to 95% two-tailed for other values
55        1.96
56    };
57
58    let margin = z_critical * stddev;
59    (mean - margin, mean + margin)
60}
61
62#[cfg(test)]
63mod tests {
64    use super::*;
65
66    #[test]
67    fn test_mean() {
68        let values = vec![1.0, 2.0, 3.0, 4.0, 5.0];
69        assert_eq!(mean(&values), 3.0);
70
71        let empty: Vec<f64> = vec![];
72        assert_eq!(mean(&empty), 0.0);
73    }
74
75    #[test]
76    fn test_variance() {
77        let values = vec![2.0, 4.0, 4.0, 4.0, 5.0, 5.0, 7.0, 9.0];
78        let var = variance(&values);
79        // Expected variance: 4.0
80        assert!((var - 4.0).abs() < 0.01);
81    }
82
83    #[test]
84    fn test_standard_deviation() {
85        let values = vec![2.0, 4.0, 4.0, 4.0, 5.0, 5.0, 7.0, 9.0];
86        let std = standard_deviation(&values);
87        // Expected stddev: 2.0
88        assert!((std - 2.0).abs() < 0.01);
89    }
90
91    #[test]
92    fn test_z_score() {
93        let z = z_score(10.0, 5.0, 2.0);
94        assert_eq!(z, 2.5);
95
96        // Test with zero stddev (edge case)
97        let z_zero = z_score(10.0, 5.0, 0.0);
98        assert_eq!(z_zero, 0.0);
99    }
100
101    #[test]
102    fn test_confidence_interval() {
103        let (lower, upper) = confidence_interval(100.0, 10.0, 0.95);
104        // 95% CI should be approximately [83.55, 116.45] for one-tailed
105        assert!((lower - 83.55).abs() < 1.0);
106        assert!((upper - 116.45).abs() < 1.0);
107    }
108}