Skip to content

Commit 014e002

Browse files
committed
chore(core): update stats checking tools
- add arithmetic mean primitive - add variance confidence interval based on Chi Square test - add a test on the confidence interval taken from a web site giving examples of confidence intervals
1 parent 4284a2e commit 014e002

File tree

1 file changed

+94
-2
lines changed
  • tfhe/src/core_crypto/commons

1 file changed

+94
-2
lines changed

tfhe/src/core_crypto/commons/mod.rs

+94-2
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,13 @@ pub mod traits;
2626
#[cfg(test)]
2727
pub mod test_tools {
2828
use rand::Rng;
29+
use statrs::distribution::{ChiSquared, ContinuousCDF};
2930

3031
pub use crate::core_crypto::algorithms::misc::{
3132
modular_distance, modular_distance_custom_mod, torus_modular_diff,
3233
};
3334
use crate::core_crypto::commons::ciphertext_modulus::CiphertextModulus;
34-
use crate::core_crypto::commons::dispersion::{DispersionParameter, Variance};
35+
use crate::core_crypto::commons::dispersion::{DispersionParameter, StandardDev, Variance};
3536
use crate::core_crypto::commons::generators::{
3637
EncryptionRandomGenerator, SecretRandomGenerator,
3738
};
@@ -45,14 +46,64 @@ pub mod test_tools {
4546
use crate::core_crypto::commons::traits::*;
4647
use tfhe_csprng::seeders::Seed;
4748

49+
pub fn arithmetic_mean(samples: &[f64]) -> f64 {
50+
samples.iter().copied().sum::<f64>() / samples.len() as f64
51+
}
52+
4853
pub fn variance(samples: &[f64]) -> Variance {
4954
let num_samples = samples.len();
50-
let mean = samples.iter().sum::<f64>() / (num_samples as f64);
55+
let mean = arithmetic_mean(samples);
5156
Variance(
5257
samples.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / ((num_samples - 1) as f64),
5358
)
5459
}
5560

61+
#[derive(Debug, Clone, Copy)]
62+
pub struct VarianceConfidenceInterval {
63+
lower_bound: Variance,
64+
upper_bound: Variance,
65+
}
66+
67+
impl VarianceConfidenceInterval {
68+
pub fn variance_is_in_interval(&self, variance_to_check: Variance) -> bool {
69+
self.lower_bound <= variance_to_check && self.upper_bound >= variance_to_check
70+
}
71+
72+
pub fn lower_bound(&self) -> Variance {
73+
self.lower_bound
74+
}
75+
76+
pub fn upper_bound(&self) -> Variance {
77+
self.upper_bound
78+
}
79+
}
80+
81+
/// Note that the confidence_level is the probability to be in the interval to be computed.
82+
pub fn variance_confidence_interval(
83+
sample_count: f64,
84+
measured_variance: Variance,
85+
confidence_level: f64,
86+
) -> VarianceConfidenceInterval {
87+
assert!(confidence_level >= 0.0);
88+
assert!(confidence_level <= 1.0);
89+
let alpha = 1.0 - confidence_level;
90+
let degrees_of_freedom = sample_count - 1.0;
91+
let chi2 = ChiSquared::new(degrees_of_freedom).unwrap();
92+
let chi2_lower = chi2.inverse_cdf(alpha / 2.0);
93+
let chi2_upper = chi2.inverse_cdf(1.0 - alpha / 2.0);
94+
95+
// Lower bound is divided by chi2_upper, upper bound divided by chi2_lower
96+
let lower_bound = Variance(degrees_of_freedom * measured_variance.0 / chi2_upper);
97+
let upper_bound = Variance(degrees_of_freedom * measured_variance.0 / chi2_lower);
98+
99+
assert!(lower_bound <= upper_bound);
100+
101+
VarianceConfidenceInterval {
102+
lower_bound,
103+
upper_bound,
104+
}
105+
}
106+
56107
pub fn new_random_generator() -> RandomGenerator<DefaultRandomGenerator> {
57108
RandomGenerator::new(random_seed())
58109
}
@@ -346,4 +397,45 @@ pub mod test_tools {
346397
assert_eq!(distance, -0.25);
347398
}
348399
}
400+
401+
#[test]
402+
fn test_confidence_interval() {
403+
// https://stats.libretexts.org/Bookshelves/Introductory_Statistics/
404+
// Inferential_Statistics_and_Probability_-_A_Holistic_Approach_(Geraghty)/
405+
// 09%3A_Point_Estimation_and_Confidence_Intervals/9.03%3A_Confidence_Intervals
406+
407+
// In performance measurement of investments, standard deviation is a measure of volatility
408+
// or risk. Twenty monthly returns from a mutual fund show an average monthly return of
409+
// 1 percent and a sample standard deviation of 5 percent.
410+
// Find a 95% confidence interval for the monthly standard deviation of the mutual fund.
411+
412+
// The Chi‐square distribution will have 20‐1 =19 degrees of freedom. Using technology,
413+
// we find that the two critical values are chi2_left=8.90655
414+
// and chi2_right=32.8523
415+
// Formula for confidence interval for sigma
416+
// is: sqrt(19 * 5^2 / 32.8523) sqrt(19 * 5^2 / 8.90655) = (3.8,7.3)
417+
418+
// One can say with 95% confidence that the standard deviation for this mutual fund is
419+
// between 3.8 and 7.3 percent per month.
420+
421+
let measured_std_dev = StandardDev(0.05);
422+
let measured_variance = measured_std_dev.get_variance();
423+
424+
let confidence_level = 0.95;
425+
426+
let confidence_interval =
427+
variance_confidence_interval(20., measured_variance, confidence_level);
428+
429+
let lower_bound = confidence_interval.lower_bound();
430+
let upper_bound = confidence_interval.upper_bound();
431+
432+
let approx_expected_lower_bound = StandardDev(0.038).get_variance();
433+
let approx_expected_upper_bound = StandardDev(0.073).get_variance();
434+
435+
let lower_bound_abs_diff = (lower_bound.0 - approx_expected_lower_bound.0).abs();
436+
let upper_bound_abs_diff = (upper_bound.0 - approx_expected_upper_bound.0).abs();
437+
438+
assert!(lower_bound_abs_diff / approx_expected_lower_bound.0 < 0.01);
439+
assert!(upper_bound_abs_diff / approx_expected_upper_bound.0 < 0.01);
440+
}
349441
}

0 commit comments

Comments
 (0)