use crate::{
error::MathError,
integer::Z,
rational::Q,
utils::sample::discrete_gauss::{DiscreteGaussianIntegerSampler, LookupTableSetting, TAILCUT},
};
impl Z {
pub fn sample_discrete_gauss(center: impl Into<Q>, s: impl Into<Q>) -> Result<Self, MathError> {
let center: Q = center.into();
let s: Q = s.into();
let mut dgis = DiscreteGaussianIntegerSampler::init(
¢er,
&s,
unsafe { TAILCUT },
LookupTableSetting::NoLookup,
)?;
Ok(dgis.sample_z())
}
}
#[cfg(test)]
mod test_sample_discrete_gauss {
use crate::{integer::Z, rational::Q};
#[test]
fn availability() {
let z = Z::from(2);
let q = Q::from(2);
let _ = Z::sample_discrete_gauss(7u8, 1u16);
let _ = Z::sample_discrete_gauss(7u16, 1u8);
let _ = Z::sample_discrete_gauss(7u32, 1u32);
let _ = Z::sample_discrete_gauss(7u64, 1u64);
let _ = Z::sample_discrete_gauss(7i8, 1i64);
let _ = Z::sample_discrete_gauss(7i16, 1i32);
let _ = Z::sample_discrete_gauss(7i32, 1i16);
let _ = Z::sample_discrete_gauss(7i64, 1i8);
let _ = Z::sample_discrete_gauss(&q, 1i64);
let _ = Z::sample_discrete_gauss(0i8, &z);
let _ = Z::sample_discrete_gauss(&z, &q);
let _ = Z::sample_discrete_gauss(1f32, 1f64);
let _ = Z::sample_discrete_gauss(1f64, 1f32);
}
#[test]
fn distribution() {
let mut counts = [0; 20];
for _ in 0..200 {
let sample = Z::sample_discrete_gauss(10, 2).unwrap();
let sample_int = i64::try_from(&sample).unwrap() as usize;
counts[sample_int] += 1;
}
let expl_text = String::from("This test can fail with probability close to 0.
It fails if the sampled occurrences do not look like a typical discrete Gaussian random distribution.
If this happens, rerun the tests several times and check whether this issue comes up again.");
assert!(counts[10] > 70, "{expl_text}");
assert!(counts[10] < 130, "{expl_text}");
assert!(counts[9] > 20, "{expl_text}");
assert!(counts[9] < 70, "{expl_text}");
assert!(counts[11] > 20, "{expl_text}");
assert!(counts[11] < 70, "{expl_text}");
assert!(counts[8] < 20, "{expl_text}");
assert!(counts[12] < 20, "{expl_text}");
for count in counts.iter().take(8) {
assert!(count < &10, "{expl_text}");
}
for count in counts.iter().skip(13) {
assert!(count < &10, "{expl_text}");
}
}
}