Skip to content

Commit

Permalink
Merge pull request #888 from dhardy/master
Browse files Browse the repository at this point in the history
Add value-stability tests
  • Loading branch information
dhardy committed Sep 16, 2019
2 parents 9f1efff + 5ac4cbd commit 249ebfc
Show file tree
Hide file tree
Showing 20 changed files with 513 additions and 59 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Expand Up @@ -8,6 +8,13 @@ A [separate changelog is kept for rand_core](rand_core/CHANGELOG.md).

You may also find the [Upgrade Guide](https://rust-random.github.io/book/update.html) useful.

## [0.7.2] - 2019-09-16
### Fixes
- Fix dependency on `rand_core` 0.5.1 (#890)

### Additions
- Unit tests for value stability of distributions added (#888)

## [0.7.1] - 2019-09-13
### Fixes
- Fix `no_std` behaviour, appropriately enable c2-chacha's `std` feature (#844)
Expand Down
6 changes: 4 additions & 2 deletions Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "rand"
version = "0.7.1"
version = "0.7.2"
authors = ["The Rand Project Developers", "The Rust Project Developers"]
license = "MIT OR Apache-2.0"
readme = "README.md"
Expand Down Expand Up @@ -30,6 +30,8 @@ serde1 = [] # does nothing, deprecated
std = ["rand_core/std", "rand_chacha/std", "alloc", "getrandom"]
alloc = ["rand_core/alloc"] # enables Vec and Box support (without std)
# re-export optional WASM dependencies to avoid breakage:
# Warning: wasm-bindgen and stdweb features will be removed in rand 0.8;
# recommended to activate via the getrandom crate instead.
wasm-bindgen = ["getrandom_package/wasm-bindgen"]
stdweb = ["getrandom_package/stdweb"]
getrandom = ["getrandom_package", "rand_core/getrandom"]
Expand All @@ -54,7 +56,7 @@ members = [
]

[dependencies]
rand_core = { path = "rand_core", version = "0.5" }
rand_core = { path = "rand_core", version = "0.5.1" }
rand_pcg = { path = "rand_pcg", version = "0.2", optional = true }
# Do not depend on 'getrandom_package' directly; use the 'getrandom' feature!
# This is a dependency because: we forward wasm feature flags
Expand Down
2 changes: 2 additions & 0 deletions README.md
Expand Up @@ -93,8 +93,10 @@ Optionally, the following dependencies can be enabled:
- `log` enables logging via the `log` crate
- `stdweb` implies `getrandom/stdweb` to enable
`getrandom` support on `wasm32-unknown-unknown`
(will be removed in rand 0.8; activate via `getrandom` crate instead)
- `wasm-bindgen` implies `getrandom/wasm-bindgen` to enable
`getrandom` support on `wasm32-unknown-unknown`
(will be removed in rand 0.8; activate via `getrandom` crate instead)

Additionally, these features configure Rand:

Expand Down
18 changes: 18 additions & 0 deletions rand_distr/src/binomial.rs
Expand Up @@ -326,4 +326,22 @@ mod test {
fn test_binomial_invalid_lambda_neg() {
Binomial::new(20, -10.0).unwrap();
}

#[test]
fn value_stability() {
fn test_samples(n: u64, p: f64, expected: &[u64]) {
let distr = Binomial::new(n, p).unwrap();
let mut rng = crate::test::rng(353);
let mut buf = [0; 4];
for x in &mut buf {
*x = rng.sample(&distr);
}
assert_eq!(buf, expected);
}

// We have multiple code paths: np < 10, p > 0.5
test_samples(2, 0.7, &[1, 1, 2, 1]);
test_samples(20, 0.3, &[7, 7, 5, 7]);
test_samples(2000, 0.6, &[1194, 1208, 1192, 1210]);
}
}
24 changes: 22 additions & 2 deletions rand_distr/src/cauchy.rs
Expand Up @@ -72,8 +72,7 @@ where Standard: Distribution<N>

#[cfg(test)]
mod test {
use crate::Distribution;
use super::Cauchy;
use super::*;

fn median(mut numbers: &mut [f64]) -> f64 {
sort(&mut numbers);
Expand Down Expand Up @@ -117,4 +116,25 @@ mod test {
fn test_cauchy_invalid_scale_neg() {
Cauchy::new(0.0, -10.0).unwrap();
}

#[test]
fn value_stability() {
fn test_samples<N: Float + core::fmt::Debug>(m: N, s: N, expected: &[N])
where Standard: Distribution<N> {
let distr = Cauchy::new(m, s).unwrap();
let mut rng = crate::test::rng(353);
let mut buf = [m; 4];
for x in &mut buf {
*x = rng.sample(&distr);
}
assert_eq!(buf, expected);
}

// Warning: in a few cases, results vary slightly between different
// platforms, presumably due to differences in precision of system impls
// of the tan function. We work around this by avoiding these values.
test_samples(100f64, 10.0, &[77.93369152808678, 90.1606912098641,
125.31516221323625, 86.10217834773925]);
test_samples(10f32, 7.0, &[15.023088, -5.446413, 3.7092876, 3.112482]);
}
}
13 changes: 11 additions & 2 deletions rand_distr/src/dirichlet.rs
Expand Up @@ -107,8 +107,7 @@ where StandardNormal: Distribution<N>, Exp1: Distribution<N>, Open01: Distributi

#[cfg(test)]
mod test {
use super::Dirichlet;
use crate::Distribution;
use super::*;

#[test]
fn test_dirichlet() {
Expand Down Expand Up @@ -151,4 +150,14 @@ mod test {
fn test_dirichlet_invalid_alpha() {
Dirichlet::new_with_size(0.0f64, 2).unwrap();
}

#[test]
fn value_stability() {
let mut rng = crate::test::rng(223);
assert_eq!(rng.sample(Dirichlet::new(vec![1.0, 2.0, 3.0]).unwrap()),
vec![0.12941567177708177, 0.4702121891675036, 0.4003721390554146]);
assert_eq!(rng.sample(Dirichlet::new_with_size(8.0, 5).unwrap()),
vec![0.17684200044809556, 0.29915953935953055,
0.1832858056608014, 0.1425623503573967, 0.19815030417417595]);
}
}
27 changes: 25 additions & 2 deletions rand_distr/src/exponential.rs
Expand Up @@ -121,8 +121,7 @@ where Exp1: Distribution<N>

#[cfg(test)]
mod test {
use crate::Distribution;
use super::Exp;
use super::*;

#[test]
fn test_exp() {
Expand All @@ -142,4 +141,28 @@ mod test {
fn test_exp_invalid_lambda_neg() {
Exp::new(-10.0).unwrap();
}

#[test]
fn value_stability() {
fn test_samples<N: Float + core::fmt::Debug, D: Distribution<N>>
(distr: D, zero: N, expected: &[N])
{
let mut rng = crate::test::rng(223);
let mut buf = [zero; 4];
for x in &mut buf {
*x = rng.sample(&distr);
}
assert_eq!(buf, expected);
}

test_samples(Exp1, 0f32, &[1.079617, 1.8325565, 0.04601166, 0.34471703]);
test_samples(Exp1, 0f64, &[1.0796170642388276, 1.8325565304274,
0.04601166186842716, 0.3447170217100157]);

test_samples(Exp::new(2.0).unwrap(), 0f32,
&[0.5398085, 0.91627824, 0.02300583, 0.17235851]);
test_samples(Exp::new(1.0).unwrap(), 0f64, &[
1.0796170642388276, 1.8325565304274,
0.04601166186842716, 0.3447170217100157]);
}
}
59 changes: 57 additions & 2 deletions rand_distr/src/gamma.rs
Expand Up @@ -417,8 +417,7 @@ where StandardNormal: Distribution<N>, Exp1: Distribution<N>, Open01: Distributi

#[cfg(test)]
mod test {
use crate::Distribution;
use super::{Beta, ChiSquared, StudentT, FisherF};
use super::*;

#[test]
fn test_chi_squared_one() {
Expand Down Expand Up @@ -482,4 +481,60 @@ mod test {
fn test_beta_invalid_dof() {
Beta::new(0., 0.).unwrap();
}

#[test]
fn value_stability() {
fn test_samples<N: Float + core::fmt::Debug, D: Distribution<N>>
(distr: D, zero: N, expected: &[N])
{
let mut rng = crate::test::rng(223);
let mut buf = [zero; 4];
for x in &mut buf {
*x = rng.sample(&distr);
}
assert_eq!(buf, expected);
}

// Gamma has 3 cases: shape == 1, shape < 1, shape > 1
test_samples(Gamma::new(1.0, 5.0).unwrap(), 0f32,
&[5.398085, 9.162783, 0.2300583, 1.7235851]);
test_samples(Gamma::new(0.8, 5.0).unwrap(), 0f32,
&[0.5051203, 0.9048302, 3.095812, 1.8566116]);
test_samples(Gamma::new(1.1, 5.0).unwrap(), 0f64, &[
7.783878094584059, 1.4939528171618057,
8.638017638857592, 3.0949337228829004]);

// ChiSquared has 2 cases: k == 1, k != 1
test_samples(ChiSquared::new(1.0).unwrap(), 0f64, &[
0.4893526200348249, 1.635249736808788,
0.5013580219361969, 0.1457735613733489]);
test_samples(ChiSquared::new(0.1).unwrap(), 0f64, &[
0.014824404726978617, 0.021602123937134326,
0.0000003431429746851693, 0.00000002291755769542258]);
test_samples(ChiSquared::new(10.0).unwrap(), 0f32,
&[12.693656, 6.812016, 11.082001, 12.436167]);

// FisherF has same special cases as ChiSquared on each param
test_samples(FisherF::new(1.0, 13.5).unwrap(), 0f32,
&[0.32283646, 0.048049655, 0.0788893, 1.817178]);
test_samples(FisherF::new(1.0, 1.0).unwrap(), 0f32,
&[0.29925257, 3.4392934, 9.567652, 0.020074]);
test_samples(FisherF::new(0.7, 13.5).unwrap(), 0f64, &[
3.3196593155045124, 0.3409169916262829,
0.03377989856426519, 0.00004041672861036937]);

// StudentT has same special cases as ChiSquared
test_samples(StudentT::new(1.0).unwrap(), 0f32,
&[0.54703987, -1.8545331, 3.093162, -0.14168274]);
test_samples(StudentT::new(1.1).unwrap(), 0f64, &[
0.7729195887949754, 1.2606210611616204,
-1.7553606501113175, -2.377641221169782]);

// Beta has same special cases as Gamma on each param
test_samples(Beta::new(1.0, 0.8).unwrap(), 0f32,
&[0.6444564, 0.357635, 0.4110078, 0.7347192]);
test_samples(Beta::new(0.7, 1.2).unwrap(), 0f64, &[
0.6433129944095513, 0.5373371199711573,
0.10313293199269491, 0.002472280249144378]);
}
}
35 changes: 33 additions & 2 deletions rand_distr/src/normal.rs
Expand Up @@ -185,8 +185,7 @@ where StandardNormal: Distribution<N>

#[cfg(test)]
mod tests {
use crate::Distribution;
use super::{Normal, LogNormal};
use super::*;

#[test]
fn test_normal() {
Expand Down Expand Up @@ -216,4 +215,36 @@ mod tests {
fn test_log_normal_invalid_sd() {
LogNormal::new(10.0, -1.0).unwrap();
}

#[test]
fn value_stability() {
fn test_samples<N: Float + core::fmt::Debug, D: Distribution<N>>
(distr: D, zero: N, expected: &[N])
{
let mut rng = crate::test::rng(213);
let mut buf = [zero; 4];
for x in &mut buf {
*x = rng.sample(&distr);
}
assert_eq!(buf, expected);
}

test_samples(StandardNormal, 0f32,
&[-0.11844189, 0.781378, 0.06563994, -1.1932899]);
test_samples(StandardNormal, 0f64, &[
-0.11844188827977231, 0.7813779637772346,
0.06563993969580051, -1.1932899004186373]);

test_samples(Normal::new(0.0, 1.0).unwrap(), 0f32,
&[-0.11844189, 0.781378, 0.06563994, -1.1932899]);
test_samples(Normal::new(2.0, 0.5).unwrap(), 0f64, &[
1.940779055860114, 2.3906889818886174,
2.0328199698479, 1.4033550497906813]);

test_samples(LogNormal::new(0.0, 1.0).unwrap(), 0f32,
&[0.88830346, 2.1844804, 1.0678421, 0.30322206]);
test_samples(LogNormal::new(2.0, 0.5).unwrap(), 0f64, &[
6.964174338639032, 10.921015733601452,
7.6355881556915906, 4.068828213584092]);
}
}
23 changes: 21 additions & 2 deletions rand_distr/src/pareto.rs
Expand Up @@ -66,8 +66,7 @@ where OpenClosed01: Distribution<N>

#[cfg(test)]
mod tests {
use crate::Distribution;
use super::Pareto;
use super::*;

#[test]
#[should_panic]
Expand All @@ -86,4 +85,24 @@ mod tests {
assert!(r >= scale);
}
}

#[test]
fn value_stability() {
fn test_samples<N: Float + core::fmt::Debug, D: Distribution<N>>
(distr: D, zero: N, expected: &[N])
{
let mut rng = crate::test::rng(213);
let mut buf = [zero; 4];
for x in &mut buf {
*x = rng.sample(&distr);
}
assert_eq!(buf, expected);
}

test_samples(Pareto::new(1.0, 1.0).unwrap(), 0f32,
&[1.0423688, 2.1235929, 4.132709, 1.4679428]);
test_samples(Pareto::new(2.0, 0.5).unwrap(), 0f64, &[
9.019295276219136, 4.3097126018270595,
6.837815045397157, 105.8826669383772]);
}
}
22 changes: 20 additions & 2 deletions rand_distr/src/poisson.rs
Expand Up @@ -134,8 +134,7 @@ where Standard: Distribution<N>

#[cfg(test)]
mod test {
use crate::Distribution;
use super::Poisson;
use super::*;

#[test]
fn test_poisson_10() {
Expand Down Expand Up @@ -230,4 +229,23 @@ mod test {
fn test_poisson_invalid_lambda_neg() {
Poisson::new(-10.0).unwrap();
}

#[test]
fn value_stability() {
fn test_samples<N: Float + core::fmt::Debug, D: Distribution<N>>
(distr: D, zero: N, expected: &[N])
{
let mut rng = crate::test::rng(223);
let mut buf = [zero; 4];
for x in &mut buf {
*x = rng.sample(&distr);
}
assert_eq!(buf, expected);
}

// Special cases: < 12, >= 12
test_samples(Poisson::new(7.0).unwrap(), 0f32, &[5.0, 11.0, 6.0, 5.0]);
test_samples(Poisson::new(7.0).unwrap(), 0f64, &[9.0, 5.0, 7.0, 6.0]);
test_samples(Poisson::new(27.0).unwrap(), 0f32, &[28.0, 32.0, 36.0, 36.0]);
}
}
23 changes: 21 additions & 2 deletions rand_distr/src/weibull.rs
Expand Up @@ -63,8 +63,7 @@ where OpenClosed01: Distribution<N>

#[cfg(test)]
mod tests {
use crate::Distribution;
use super::Weibull;
use super::*;

#[test]
#[should_panic]
Expand All @@ -83,4 +82,24 @@ mod tests {
assert!(r >= 0.);
}
}

#[test]
fn value_stability() {
fn test_samples<N: Float + core::fmt::Debug, D: Distribution<N>>
(distr: D, zero: N, expected: &[N])
{
let mut rng = crate::test::rng(213);
let mut buf = [zero; 4];
for x in &mut buf {
*x = rng.sample(&distr);
}
assert_eq!(buf, expected);
}

test_samples(Weibull::new(1.0, 1.0).unwrap(), 0f32,
&[0.041495778, 0.7531094, 1.4189332, 0.38386202]);
test_samples(Weibull::new(2.0, 0.5).unwrap(), 0f64, &[
1.1343478702739669, 0.29470010050655226,
0.7556151370284702, 7.877212340241561]);
}
}

0 comments on commit 249ebfc

Please sign in to comment.