From fd50cd418a6f1022c4ad7fb5b6871b18b9cfc13c Mon Sep 17 00:00:00 2001 From: Vinzent Steinberg Date: Fri, 7 May 2021 17:44:08 -0300 Subject: [PATCH 01/14] Update dependency --- rand_distr/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rand_distr/Cargo.toml b/rand_distr/Cargo.toml index 5f0f4c8fca4..b923297bca2 100644 --- a/rand_distr/Cargo.toml +++ b/rand_distr/Cargo.toml @@ -30,4 +30,4 @@ rand_pcg = { version = "0.3.0", path = "../rand_pcg" } # For inline examples rand = { path = "..", version = "0.8.0", default-features = false, features = ["std_rng", "std"] } # Histogram implementation for testing uniformity -average = { version = "0.12", features = [ "std" ] } +average = { version = "0.13", features = [ "std" ] } From 0eb245415f4c24c7716a88db4d97f1eb29b0ae17 Mon Sep 17 00:00:00 2001 From: Vinzent Steinberg Date: Fri, 7 May 2021 17:44:47 -0300 Subject: [PATCH 02/14] Implement sparklines Those will only be used for testing distributions. --- rand_distr/tests/sparkline.rs | 118 ++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 rand_distr/tests/sparkline.rs diff --git a/rand_distr/tests/sparkline.rs b/rand_distr/tests/sparkline.rs new file mode 100644 index 00000000000..32ac18073b7 --- /dev/null +++ b/rand_distr/tests/sparkline.rs @@ -0,0 +1,118 @@ +/// Number of ticks. +const N: usize = 8; +/// Ticks used for the sparkline. +static TICKS: [char; N] = ['▁', '▂', '▃', '▄', '▅', '▆', '▇', '█']; + +/// Render a sparkline of `data` into `buffer`. +pub fn render_u64(data: &[u64], buffer: &mut String) { + match data.len() { + 0 => { + return; + }, + 1 => { + if data[0] == 0 { + buffer.push(TICKS[0]); + } else { + buffer.push(TICKS[N - 1]); + } + return; + }, + _ => {}, + } + let max = data.iter().max().unwrap(); + let min = data.iter().min().unwrap(); + let scale = ((N - 1) as f64) / ((max - min) as f64); + for i in data { + let tick = (((i - min) as f64) * scale) as usize; + buffer.push(TICKS[tick]); + } +} + +/// Calculate the required capacity for the sparkline, given the length of the +/// input data. +pub fn required_capacity(len: usize) -> usize { + len * TICKS[0].len_utf8() +} + +/// Render a sparkline of `data` into a newly allocated string. +pub fn render_u64_as_string(data: &[u64]) -> String { + let cap = required_capacity(data.len()); + let mut s = String::with_capacity(cap); + render_u64(data, &mut s); + debug_assert_eq!(s.capacity(), cap); + s +} + +/// Render a sparkline of `data` into `buffer`. +pub fn render_f64(data: &[f64], buffer: &mut String) { + match data.len() { + 0 => { + return; + }, + 1 => { + if data[0] == 0. { + buffer.push(TICKS[0]); + } else { + buffer.push(TICKS[N - 1]); + } + return; + }, + _ => {}, + } + for x in data { + assert!(x.is_finite(), "can only render finite values"); + } + let max = data.iter().fold(f64::NEG_INFINITY, |a, &b| a.max(b)); + let min = data.iter().fold(f64::INFINITY, |a, &b| a.min(b)); + let scale = ((N - 1) as f64) / (max - min); + for x in data { + let tick = ((x - min) * scale) as usize; + buffer.push(TICKS[tick]); + } +} + +/// Render a sparkline of `data` into a newly allocated string. +pub fn render_f64_as_string(data: &[f64]) -> String { + let cap = required_capacity(data.len()); + let mut s = String::with_capacity(cap); + render_f64(data, &mut s); + debug_assert_eq!(s.capacity(), cap); + s +} + +#[cfg(test)] +mod tests { + #[test] + fn render_u64() { + let data = [2, 250, 670, 890, 2, 430, 11, 908, 123, 57]; + let mut s = String::with_capacity(super::required_capacity(data.len())); + super::render_u64(&data, &mut s); + println!("{}", s); + assert_eq!("▁▂▆▇▁▄▁█▁▁", &s); + } + + #[test] + fn render_u64_as_string() { + let data = [2, 250, 670, 890, 2, 430, 11, 908, 123, 57]; + let s = super::render_u64_as_string(&data); + println!("{}", s); + assert_eq!("▁▂▆▇▁▄▁█▁▁", &s); + } + + #[test] + fn render_f64() { + let data = [2., 250., 670., 890., 2., 430., 11., 908., 123., 57.]; + let mut s = String::with_capacity(super::required_capacity(data.len())); + super::render_f64(&data, &mut s); + println!("{}", s); + assert_eq!("▁▂▆▇▁▄▁█▁▁", &s); + } + + #[test] + fn render_f64_as_string() { + let data = [2., 250., 670., 890., 2., 430., 11., 908., 123., 57.]; + let s = super::render_f64_as_string(&data); + println!("{}", s); + assert_eq!("▁▂▆▇▁▄▁█▁▁", &s); + } +} From c8561f4d94a72fd68320d70ea6f7cc777eea8ad2 Mon Sep 17 00:00:00 2001 From: Vinzent Steinberg Date: Fri, 7 May 2021 17:47:40 -0300 Subject: [PATCH 03/14] rand_distr: Test normal distribution `Normal` is sampled many times into a histogram, which is then compared to the expected probability density function. To make debugging easier, sparklines of the expected distribution, the histogram, and their difference are printed. Currently, the test fails if the difference is significantly larger than the expected error of the histogram bin. However, the error estimate does not take the error in the normalization due to the finite width of the histogram into account. This should not be a problem, as long as the distribution is almost zero outside the range covered by the histogram. In principle, this approach can be generalized to other distributions. --- rand_distr/Cargo.toml | 2 +- rand_distr/tests/pdf.rs | 74 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 rand_distr/tests/pdf.rs diff --git a/rand_distr/Cargo.toml b/rand_distr/Cargo.toml index b923297bca2..38f5adfb820 100644 --- a/rand_distr/Cargo.toml +++ b/rand_distr/Cargo.toml @@ -28,6 +28,6 @@ std_math = ["num-traits/std"] [dev-dependencies] rand_pcg = { version = "0.3.0", path = "../rand_pcg" } # For inline examples -rand = { path = "..", version = "0.8.0", default-features = false, features = ["std_rng", "std"] } +rand = { path = "..", version = "0.8.0", default-features = false, features = ["std_rng", "std", "small_rng"] } # Histogram implementation for testing uniformity average = { version = "0.13", features = [ "std" ] } diff --git a/rand_distr/tests/pdf.rs b/rand_distr/tests/pdf.rs new file mode 100644 index 00000000000..4a6634d61b9 --- /dev/null +++ b/rand_distr/tests/pdf.rs @@ -0,0 +1,74 @@ +use average::Histogram; +use rand::{Rng, SeedableRng}; +use rand_distr::Normal; + +average::define_histogram!(hist, 100); +use hist::Histogram as Histogram100; + +mod sparkline; + +#[test] +fn normal() { + const N_SAMPLES: u64 = 1_000_000; + const MEAN: f64 = 2.; + const STD_DEV: f64 = 0.5; + const MIN_X: f64 = -1.; + const MAX_X: f64 = 5.; + + let dist = Normal::new(MEAN, STD_DEV).unwrap(); + let mut hist = Histogram100::with_const_width(MIN_X,MAX_X); + let mut rng = rand::rngs::SmallRng::seed_from_u64(1); + + for _ in 0..N_SAMPLES { + let _ = hist.add(rng.sample(dist)); // Ignore out-of-range values + } + + println!("Sampled normal distribution:\n{}", + sparkline::render_u64_as_string(hist.bins())); + + fn pdf(x: f64) -> f64 { + (-0.5 * ((x - MEAN) / STD_DEV).powi(2)).exp() / + (STD_DEV * (2. * core::f64::consts::PI).sqrt()) + } + + let mut bin_centers = hist.centers(); + let mut expected = [0.; 100]; + for e in &mut expected { + *e = pdf(bin_centers.next().unwrap()); + } + + println!("Expected normal distribution:\n{}", + sparkline::render_u64_as_string(hist.bins())); + + let mut normalized_bins= hist.normalized_bins(); + let mut diff = [0.; 100]; + for i in 0..100 { + let bin = (normalized_bins.next().unwrap() as f64) / (N_SAMPLES as f64) ; + diff[i] = (bin - expected[i]).abs(); + } + + println!("Difference:\n{}", + sparkline::render_f64_as_string(&diff[..])); + println!("max diff: {:?}", diff.iter().fold(f64::NEG_INFINITY, |a, &b| a.max(b))); + + // Check that the differences are significantly smaller than the expected error. + let mut expected_error = [0.; 100]; + // Calculate error from histogram + for (err, var) in expected_error.iter_mut().zip(hist.variances()) { + *err = var.sqrt() / (N_SAMPLES as f64); + } + // Normalize error by bin width + for (err, width) in expected_error.iter_mut().zip(hist.widths()) { + *err /= width; + } + // TODO: Calculate error from distribution cutoff / normalization + + println!("max expected_error: {:?}", expected_error.iter().fold(f64::NEG_INFINITY, |a, &b| a.max(b))); + for (&d, &e) in diff.iter().zip(expected_error.iter()) { + // Difference larger than 3 standard deviations or cutoff + let tol = (3. * e).max(1e-4); + if d > tol { + panic!("Difference = {} * tol", d / tol); + } + } +} \ No newline at end of file From e8329a2d018d2bbe3c7f6624aaac2784f7ecba3f Mon Sep 17 00:00:00 2001 From: Vinzent Steinberg Date: Fri, 7 May 2021 18:46:27 -0300 Subject: [PATCH 04/14] Fix tests for old Rust versions --- rand_distr/tests/pdf.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/rand_distr/tests/pdf.rs b/rand_distr/tests/pdf.rs index 4a6634d61b9..05896e996dc 100644 --- a/rand_distr/tests/pdf.rs +++ b/rand_distr/tests/pdf.rs @@ -49,7 +49,8 @@ fn normal() { println!("Difference:\n{}", sparkline::render_f64_as_string(&diff[..])); - println!("max diff: {:?}", diff.iter().fold(f64::NEG_INFINITY, |a, &b| a.max(b))); + println!("max diff: {:?}", diff.iter().fold( + core::f64::NEG_INFINITY, |a, &b| a.max(b))); // Check that the differences are significantly smaller than the expected error. let mut expected_error = [0.; 100]; @@ -63,7 +64,8 @@ fn normal() { } // TODO: Calculate error from distribution cutoff / normalization - println!("max expected_error: {:?}", expected_error.iter().fold(f64::NEG_INFINITY, |a, &b| a.max(b))); + println!("max expected_error: {:?}", expected_error.iter().fold( + core::f64::NEG_INFINITY, |a, &b| a.max(b))); for (&d, &e) in diff.iter().zip(expected_error.iter()) { // Difference larger than 3 standard deviations or cutoff let tol = (3. * e).max(1e-4); From da94e878193f9f142bf138e178143f3d2753fee5 Mon Sep 17 00:00:00 2001 From: Vinzent Steinberg Date: Sat, 8 May 2021 20:21:26 -0300 Subject: [PATCH 05/14] More fixes for old Rust versions --- rand_distr/tests/sparkline.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/rand_distr/tests/sparkline.rs b/rand_distr/tests/sparkline.rs index 32ac18073b7..a49d57030df 100644 --- a/rand_distr/tests/sparkline.rs +++ b/rand_distr/tests/sparkline.rs @@ -62,8 +62,10 @@ pub fn render_f64(data: &[f64], buffer: &mut String) { for x in data { assert!(x.is_finite(), "can only render finite values"); } - let max = data.iter().fold(f64::NEG_INFINITY, |a, &b| a.max(b)); - let min = data.iter().fold(f64::INFINITY, |a, &b| a.min(b)); + let max = data.iter().fold( + core::f64::NEG_INFINITY, |a, &b| a.max(b)); + let min = data.iter().fold( + core::f64::INFINITY, |a, &b| a.min(b)); let scale = ((N - 1) as f64) / (max - min); for x in data { let tick = ((x - min) * scale) as usize; From 70efd2e180e2ca5d45ac156bf481ff3f1e018669 Mon Sep 17 00:00:00 2001 From: Vinzent Steinberg Date: Sat, 8 May 2021 20:33:46 -0300 Subject: [PATCH 06/14] Another fix for old Rust --- rand_distr/tests/pdf.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rand_distr/tests/pdf.rs b/rand_distr/tests/pdf.rs index 05896e996dc..62562527cd9 100644 --- a/rand_distr/tests/pdf.rs +++ b/rand_distr/tests/pdf.rs @@ -33,7 +33,7 @@ fn normal() { let mut bin_centers = hist.centers(); let mut expected = [0.; 100]; - for e in &mut expected { + for e in &mut expected[..] { *e = pdf(bin_centers.next().unwrap()); } From 0cde3bf20c70c34dbc04d14f04123a3fa6becc6f Mon Sep 17 00:00:00 2001 From: Vinzent Steinberg Date: Sat, 8 May 2021 21:05:49 -0300 Subject: [PATCH 07/14] rand_distr: Fix clippy warnings --- rand_distr/benches/distributions.rs | 3 ++- rand_distr/src/cauchy.rs | 6 +++--- rand_distr/src/gamma.rs | 4 ++++ rand_distr/src/hypergeometric.rs | 2 +- rand_distr/src/weighted_alias.rs | 2 +- rand_distr/tests/pdf.rs | 2 ++ rand_distr/tests/uniformity.rs | 2 ++ 7 files changed, 15 insertions(+), 6 deletions(-) diff --git a/rand_distr/benches/distributions.rs b/rand_distr/benches/distributions.rs index 31e7e2fc716..e53a7b0310e 100644 --- a/rand_distr/benches/distributions.rs +++ b/rand_distr/benches/distributions.rs @@ -144,6 +144,7 @@ distr_int!(distr_geometric, u64, Geometric::new(0.5).unwrap()); distr_int!(distr_standard_geometric, u64, StandardGeometric); #[bench] +#[allow(clippy::approx_constant)] fn dist_iter(b: &mut Bencher) { let mut rng = Pcg64Mcg::from_entropy(); let distr = Normal::new(-2.71828, 3.14159).unwrap(); @@ -177,4 +178,4 @@ sample_binomial!(misc_binomial_1, 1, 0.9); sample_binomial!(misc_binomial_10, 10, 0.9); sample_binomial!(misc_binomial_100, 100, 0.99); sample_binomial!(misc_binomial_1000, 1000, 0.01); -sample_binomial!(misc_binomial_1e12, 1000_000_000_000, 0.2); +sample_binomial!(misc_binomial_1e12, 1_000_000_000_000, 0.2); diff --git a/rand_distr/src/cauchy.rs b/rand_distr/src/cauchy.rs index a68e12f7796..66dc09b3e7b 100644 --- a/rand_distr/src/cauchy.rs +++ b/rand_distr/src/cauchy.rs @@ -107,9 +107,9 @@ mod test { let mut rng = crate::test::rng(123); let mut numbers: [f64; 1000] = [0.0; 1000]; let mut sum = 0.0; - for i in 0..1000 { - numbers[i] = cauchy.sample(&mut rng); - sum += numbers[i]; + for number in &mut numbers[..] { + *number = cauchy.sample(&mut rng); + sum += *number; } let median = median(&mut numbers); #[cfg(feature = "std")] diff --git a/rand_distr/src/gamma.rs b/rand_distr/src/gamma.rs index 0d2d87db9f0..45181b9204c 100644 --- a/rand_distr/src/gamma.rs +++ b/rand_distr/src/gamma.rs @@ -9,6 +9,10 @@ //! The Gamma and derived distributions. +// We use the variable names from the published reference, therefore this +// warning is not helpful. +#![allow(clippy::many_single_char_names)] + use self::ChiSquaredRepr::*; use self::GammaRepr::*; diff --git a/rand_distr/src/hypergeometric.rs b/rand_distr/src/hypergeometric.rs index 406e97ea88a..512dd34c19b 100644 --- a/rand_distr/src/hypergeometric.rs +++ b/rand_distr/src/hypergeometric.rs @@ -221,7 +221,7 @@ impl Hypergeometric { } }; - Ok(Hypergeometric { n1, n2, k, sign_x, offset_x, sampling_method }) + Ok(Hypergeometric { n1, n2, k, offset_x, sign_x, sampling_method }) } } diff --git a/rand_distr/src/weighted_alias.rs b/rand_distr/src/weighted_alias.rs index 1b07229be8c..53a9c2713d4 100644 --- a/rand_distr/src/weighted_alias.rs +++ b/rand_distr/src/weighted_alias.rs @@ -466,7 +466,7 @@ mod test { weights[ZERO_WEIGHT_INDEX as usize] = W::ZERO; weights }; - let weight_sum = weights.iter().map(|w| *w).sum::(); + let weight_sum = weights.iter().copied().sum::(); let expected_counts = weights .iter() .map(|&w| w_to_f64(w) / w_to_f64(weight_sum) * NUM_SAMPLES as f64) diff --git a/rand_distr/tests/pdf.rs b/rand_distr/tests/pdf.rs index 62562527cd9..1dc6c7cae0e 100644 --- a/rand_distr/tests/pdf.rs +++ b/rand_distr/tests/pdf.rs @@ -1,3 +1,5 @@ +#![allow(clippy::float_cmp)] + use average::Histogram; use rand::{Rng, SeedableRng}; use rand_distr::Normal; diff --git a/rand_distr/tests/uniformity.rs b/rand_distr/tests/uniformity.rs index 7d359c7d733..4a64babdc76 100644 --- a/rand_distr/tests/uniformity.rs +++ b/rand_distr/tests/uniformity.rs @@ -6,6 +6,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(clippy::float_cmp)] + use average::Histogram; use rand::prelude::*; From 67f491a7a5ff65071a13f54d04d1de4b3d8e2df5 Mon Sep 17 00:00:00 2001 From: Vinzent Steinberg Date: Sat, 8 May 2021 21:35:09 -0300 Subject: [PATCH 08/14] rand_core: Fix clippy warnings --- rand_core/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rand_core/src/lib.rs b/rand_core/src/lib.rs index c53d3195b21..bc24270771b 100644 --- a/rand_core/src/lib.rs +++ b/rand_core/src/lib.rs @@ -485,7 +485,7 @@ mod test { // This is the binomial distribution B(64, 0.5), so chance of // weight < 20 is binocdf(19, 64, 0.5) = 7.8e-4, and same for // weight > 44. - assert!(weight >= 20 && weight <= 44); + assert!((20..=44).contains(&weight)); for (i2, r2) in results.iter().enumerate() { if i1 == i2 { From aee00443d4cb6bbceea7c48aa31126add959ec24 Mon Sep 17 00:00:00 2001 From: Vinzent Steinberg Date: Sat, 8 May 2021 21:36:12 -0300 Subject: [PATCH 09/14] rand_hc: Fix clippy warnings --- rand_hc/src/hc128.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/rand_hc/src/hc128.rs b/rand_hc/src/hc128.rs index 94d75778f75..cedd2cb6ba8 100644 --- a/rand_hc/src/hc128.rs +++ b/rand_hc/src/hc128.rs @@ -6,6 +6,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// Disable some noisy clippy lints. +#![allow(clippy::many_single_char_names)] +#![allow(clippy::identity_op)] +// Disable a lint that cannot be fixed without increasing the MSRV +#![allow(clippy::op_ref)] + //! The HC-128 random number generator. use core::fmt; From 1b8eaf23eac5a9f149599f895132c71d500ea7b8 Mon Sep 17 00:00:00 2001 From: Vinzent Steinberg Date: Sat, 8 May 2021 21:37:15 -0300 Subject: [PATCH 10/14] rand: Fix clippy warnings --- benches/seq.rs | 28 ++++++++++++++-------------- src/distributions/bernoulli.rs | 5 ++++- src/distributions/mod.rs | 8 ++++---- src/distributions/other.rs | 10 +++++----- src/distributions/uniform.rs | 2 +- src/distributions/utils.rs | 2 ++ src/lib.rs | 2 +- src/rng.rs | 22 +++++++++++++--------- src/rngs/adapter/reseeding.rs | 2 ++ src/seq/index.rs | 6 +++--- src/seq/mod.rs | 4 ++-- 11 files changed, 51 insertions(+), 40 deletions(-) diff --git a/benches/seq.rs b/benches/seq.rs index 5b6fccf51ee..a9bd88ff882 100644 --- a/benches/seq.rs +++ b/benches/seq.rs @@ -37,8 +37,8 @@ fn seq_shuffle_100(b: &mut Bencher) { fn seq_slice_choose_1_of_1000(b: &mut Bencher) { let mut rng = SmallRng::from_rng(thread_rng()).unwrap(); let x: &mut [usize] = &mut [1; 1000]; - for i in 0..1000 { - x[i] = i; + for (i, r) in x.iter_mut().enumerate() { + *r = i; } b.iter(|| { let mut s = 0; @@ -78,8 +78,8 @@ seq_slice_choose_multiple!(seq_slice_choose_multiple_90_of_100, 90, 100); fn seq_iter_choose_from_1000(b: &mut Bencher) { let mut rng = SmallRng::from_rng(thread_rng()).unwrap(); let x: &mut [usize] = &mut [1; 1000]; - for i in 0..1000 { - x[i] = i; + for (i, r) in x.iter_mut().enumerate() { + *r = i; } b.iter(|| { let mut s = 0; @@ -172,11 +172,11 @@ macro_rules! sample_indices { sample_indices!(misc_sample_indices_1_of_1k, sample, 1, 1000); sample_indices!(misc_sample_indices_10_of_1k, sample, 10, 1000); sample_indices!(misc_sample_indices_100_of_1k, sample, 100, 1000); -sample_indices!(misc_sample_indices_100_of_1M, sample, 100, 1000_000); -sample_indices!(misc_sample_indices_100_of_1G, sample, 100, 1000_000_000); -sample_indices!(misc_sample_indices_200_of_1G, sample, 200, 1000_000_000); -sample_indices!(misc_sample_indices_400_of_1G, sample, 400, 1000_000_000); -sample_indices!(misc_sample_indices_600_of_1G, sample, 600, 1000_000_000); +sample_indices!(misc_sample_indices_100_of_1M, sample, 100, 1_000_000); +sample_indices!(misc_sample_indices_100_of_1G, sample, 100, 1_000_000_000); +sample_indices!(misc_sample_indices_200_of_1G, sample, 200, 1_000_000_000); +sample_indices!(misc_sample_indices_400_of_1G, sample, 400, 1_000_000_000); +sample_indices!(misc_sample_indices_600_of_1G, sample, 600, 1_000_000_000); macro_rules! sample_indices_rand_weights { ($name:ident, $amount:expr, $length:expr) => { @@ -193,8 +193,8 @@ macro_rules! sample_indices_rand_weights { sample_indices_rand_weights!(misc_sample_weighted_indices_1_of_1k, 1, 1000); sample_indices_rand_weights!(misc_sample_weighted_indices_10_of_1k, 10, 1000); sample_indices_rand_weights!(misc_sample_weighted_indices_100_of_1k, 100, 1000); -sample_indices_rand_weights!(misc_sample_weighted_indices_100_of_1M, 100, 1000_000); -sample_indices_rand_weights!(misc_sample_weighted_indices_200_of_1M, 200, 1000_000); -sample_indices_rand_weights!(misc_sample_weighted_indices_400_of_1M, 400, 1000_000); -sample_indices_rand_weights!(misc_sample_weighted_indices_600_of_1M, 600, 1000_000); -sample_indices_rand_weights!(misc_sample_weighted_indices_1k_of_1M, 1000, 1000_000); +sample_indices_rand_weights!(misc_sample_weighted_indices_100_of_1M, 100, 1_000_000); +sample_indices_rand_weights!(misc_sample_weighted_indices_200_of_1M, 200, 1_000_000); +sample_indices_rand_weights!(misc_sample_weighted_indices_400_of_1M, 400, 1_000_000); +sample_indices_rand_weights!(misc_sample_weighted_indices_600_of_1M, 600, 1_000_000); +sample_indices_rand_weights!(misc_sample_weighted_indices_1k_of_1M, 1000, 1_000_000); diff --git a/src/distributions/bernoulli.rs b/src/distributions/bernoulli.rs index b968ca046ed..d54d5992c48 100644 --- a/src/distributions/bernoulli.rs +++ b/src/distributions/bernoulli.rs @@ -96,7 +96,7 @@ impl Bernoulli { /// 2-64 in `[0, 1]` can be represented as a `f64`.) #[inline] pub fn new(p: f64) -> Result { - if !(p >= 0.0 && p < 1.0) { + if !(0.0..1.0).contains(&p) { if p == 1.0 { return Ok(Bernoulli { p_int: ALWAYS_TRUE }); } @@ -157,6 +157,9 @@ mod test { #[test] fn test_trivial() { + // We prefer to be explicit here. + #![allow(clippy::bool_assert_comparison)] + let mut r = crate::test::rng(1); let always_false = Bernoulli::new(0.0).unwrap(); let always_true = Bernoulli::new(1.0).unwrap(); diff --git a/src/distributions/mod.rs b/src/distributions/mod.rs index 911d1604aae..ddf4f4fbc2c 100644 --- a/src/distributions/mod.rs +++ b/src/distributions/mod.rs @@ -358,9 +358,9 @@ mod tests { #[test] fn test_make_an_iter() { - fn ten_dice_rolls_other_than_five<'a, R: Rng>( - rng: &'a mut R, - ) -> impl Iterator + 'a { + fn ten_dice_rolls_other_than_five( + rng: &mut R, + ) -> impl Iterator + '_ { Uniform::new_inclusive(1, 6) .sample_iter(rng) .filter(|x| *x != 5) @@ -370,7 +370,7 @@ mod tests { let mut rng = crate::test::rng(211); let mut count = 0; for val in ten_dice_rolls_other_than_five(&mut rng) { - assert!(val >= 1 && val <= 6 && val != 5); + assert!((1..=6).contains(&val) && val != 5); count += 1; } assert_eq!(count, 10); diff --git a/src/distributions/other.rs b/src/distributions/other.rs index 16b352ac382..9e58afd46e0 100644 --- a/src/distributions/other.rs +++ b/src/distributions/other.rs @@ -249,7 +249,7 @@ mod tests { .map(|()| rng.gen::()) .take(1000) .collect(); - assert!(word.len() != 0); + assert!(!word.is_empty()); } #[test] @@ -261,11 +261,11 @@ mod tests { let mut incorrect = false; for _ in 0..100 { let c: char = rng.sample(Alphanumeric).into(); - incorrect |= !((c >= '0' && c <= '9') || - (c >= 'A' && c <= 'Z') || - (c >= 'a' && c <= 'z') ); + incorrect |= !(('0'..='9').contains(&c) || + ('A'..='Z').contains(&c) || + ('a'..='z').contains(&c) ); } - assert!(incorrect == false); + assert!(!incorrect); } #[test] diff --git a/src/distributions/uniform.rs b/src/distributions/uniform.rs index 57934838ae8..fb898370329 100644 --- a/src/distributions/uniform.rs +++ b/src/distributions/uniform.rs @@ -1316,7 +1316,7 @@ mod tests { let mut max = core::char::from_u32(0).unwrap(); for _ in 0..100 { let c = rng.gen_range('A'..='Z'); - assert!('A' <= c && c <= 'Z'); + assert!(('A'..='Z').contains(&c)); max = max.max(c); } assert_eq!(max, 'Z'); diff --git a/src/distributions/utils.rs b/src/distributions/utils.rs index e3bceb8a96c..f8fb1cb1115 100644 --- a/src/distributions/utils.rs +++ b/src/distributions/utils.rs @@ -236,6 +236,8 @@ pub(crate) trait FloatSIMDUtils { /// Implement functions available in std builds but missing from core primitives #[cfg(not(std))] pub(crate) trait Float: Sized { + // False positive: We are following `std` here. + #![allow(clippy::wrong_self_convention)] fn is_nan(self) -> bool; fn is_infinite(self) -> bool; fn is_finite(self) -> bool; diff --git a/src/lib.rs b/src/lib.rs index 8bf7a9df126..6f8665a2d17 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -201,10 +201,10 @@ mod test { #[test] #[cfg(all(feature = "std", feature = "std_rng"))] fn test_random() { - // not sure how to test this aside from just getting some values let _n: usize = random(); let _f: f32 = random(); let _o: Option> = random(); + #[allow(clippy::type_complexity)] let _many: ( (), (usize, isize, Option<(u32, (bool,))>), diff --git a/src/rng.rs b/src/rng.rs index f555a68586d..07643c55958 100644 --- a/src/rng.rs +++ b/src/rng.rs @@ -501,15 +501,15 @@ mod test { let mut r = rng(101); for _ in 0..1000 { let a = r.gen_range(-4711..17); - assert!(a >= -4711 && a < 17); - let a = r.gen_range(-3i8..42); - assert!(a >= -3i8 && a < 42i8); + assert!((-4711..17).contains(&a)); + let a: i8 = r.gen_range(-3..42); + assert!((-3..42).contains(&a)); let a: u16 = r.gen_range(10..99); - assert!(a >= 10u16 && a < 99u16); - let a = r.gen_range(-100i32..2000); - assert!(a >= -100i32 && a < 2000i32); + assert!((10..99).contains(&a)); + let a: i32 = r.gen_range(-100..2000); + assert!((-100..2000).contains(&a)); let a: u32 = r.gen_range(12..=24); - assert!(a >= 12u32 && a <= 24u32); + assert!((12..=24).contains(&a)); assert_eq!(r.gen_range(0u32..1), 0u32); assert_eq!(r.gen_range(-12i64..-11), -12i64); @@ -522,9 +522,9 @@ mod test { let mut r = rng(101); for _ in 0..1000 { let a = r.gen_range(-4.5..1.7); - assert!(a >= -4.5 && a < 1.7); + assert!((-4.5..1.7).contains(&a)); let a = r.gen_range(-1.1..=-0.3); - assert!(a >= -1.1 && a <= -0.3); + assert!((-1.1..=-0.3).contains(&a)); assert_eq!(r.gen_range(0.0f32..=0.0), 0.); assert_eq!(r.gen_range(-11.0..=-11.0), -11.); @@ -535,6 +535,7 @@ mod test { #[test] #[should_panic] fn test_gen_range_panic_int() { + #![allow(clippy::reversed_empty_ranges)] let mut r = rng(102); r.gen_range(5..-2); } @@ -542,12 +543,15 @@ mod test { #[test] #[should_panic] fn test_gen_range_panic_usize() { + #![allow(clippy::reversed_empty_ranges)] let mut r = rng(103); r.gen_range(5..2); } #[test] fn test_gen_bool() { + #![allow(clippy::bool_assert_comparison)] + let mut r = rng(105); for _ in 0..5 { assert_eq!(r.gen_bool(0.0), false); diff --git a/src/rngs/adapter/reseeding.rs b/src/rngs/adapter/reseeding.rs index 1977cb31906..70b0b82307f 100644 --- a/src/rngs/adapter/reseeding.rs +++ b/src/rngs/adapter/reseeding.rs @@ -355,6 +355,8 @@ mod test { #[test] fn test_clone_reseeding() { + #![allow(clippy::redundant_clone)] + let mut zero = StepRng::new(0, 0); let rng = Core::from_rng(&mut zero).unwrap(); let mut rng1 = ReseedingRng::new(rng, 32 * 4, zero); diff --git a/src/seq/index.rs b/src/seq/index.rs index 8b155e1f1e1..ae36c323708 100644 --- a/src/seq/index.rs +++ b/src/seq/index.rs @@ -630,7 +630,7 @@ mod test { match v { IndexVec::U32(mut indices) => { assert_eq!(indices.len(), amount); - indices.sort(); + indices.sort_unstable(); indices.dedup(); assert_eq!(indices.len(), amount); for &i in &indices { @@ -668,10 +668,10 @@ mod test { do_test(300, 80, &[31, 289, 248, 154, 5, 78, 19, 286]); // inplace do_test(300, 180, &[31, 289, 248, 154, 5, 78, 19, 286]); // inplace - do_test(1000_000, 8, &[ + do_test(1_000_000, 8, &[ 103717, 963485, 826422, 509101, 736394, 807035, 5327, 632573, ]); // floyd - do_test(1000_000, 180, &[ + do_test(1_000_000, 180, &[ 103718, 963490, 826426, 509103, 736396, 807036, 5327, 632573, ]); // rejection } diff --git a/src/seq/mod.rs b/src/seq/mod.rs index 4375fa1ccc6..9eeb77749c9 100644 --- a/src/seq/mod.rs +++ b/src/seq/mod.rs @@ -991,8 +991,8 @@ mod test { move_last(&mut arr, pos); assert_eq!(arr[3], i); } - for i in 0..4 { - assert_eq!(arr[i], i); + for (i, &a) in arr.iter().enumerate() { + assert_eq!(a, i); } counts[permutation] += 1; } From ab6f3dd5cd22146a778c1c6a1cc9376a058d0ac6 Mon Sep 17 00:00:00 2001 From: Vinzent Steinberg Date: Sat, 8 May 2021 21:39:31 -0300 Subject: [PATCH 11/14] Add missing copyright headers --- rand_distr/tests/pdf.rs | 8 ++++++++ rand_distr/tests/sparkline.rs | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/rand_distr/tests/pdf.rs b/rand_distr/tests/pdf.rs index 1dc6c7cae0e..185c7577acd 100644 --- a/rand_distr/tests/pdf.rs +++ b/rand_distr/tests/pdf.rs @@ -1,3 +1,11 @@ +// Copyright 2021 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + #![allow(clippy::float_cmp)] use average::Histogram; diff --git a/rand_distr/tests/sparkline.rs b/rand_distr/tests/sparkline.rs index a49d57030df..6ba48ba886e 100644 --- a/rand_distr/tests/sparkline.rs +++ b/rand_distr/tests/sparkline.rs @@ -1,3 +1,11 @@ +// Copyright 2021 Developers of the Rand project. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + /// Number of ticks. const N: usize = 8; /// Ticks used for the sparkline. From 8dac1dcb8244f85e52ee7e711de225bb23baad79 Mon Sep 17 00:00:00 2001 From: Vinzent Steinberg Date: Sat, 8 May 2021 21:46:02 -0300 Subject: [PATCH 12/14] Fix Rust 1.36 compatibility --- src/distributions/utils.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/distributions/utils.rs b/src/distributions/utils.rs index f8fb1cb1115..b11f602004e 100644 --- a/src/distributions/utils.rs +++ b/src/distributions/utils.rs @@ -235,9 +235,9 @@ pub(crate) trait FloatSIMDUtils { /// Implement functions available in std builds but missing from core primitives #[cfg(not(std))] +// False positive: We are following `std` here. +#[allow(clippy::wrong_self_convention)] pub(crate) trait Float: Sized { - // False positive: We are following `std` here. - #![allow(clippy::wrong_self_convention)] fn is_nan(self) -> bool; fn is_infinite(self) -> bool; fn is_finite(self) -> bool; From 76a7305f22ebd892e37ac58f6ab74e18d7a0eceb Mon Sep 17 00:00:00 2001 From: Vinzent Steinberg Date: Sun, 9 May 2021 14:45:09 -0300 Subject: [PATCH 13/14] Define constant for histogram size --- rand_distr/tests/pdf.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/rand_distr/tests/pdf.rs b/rand_distr/tests/pdf.rs index 185c7577acd..d5ab177d98a 100644 --- a/rand_distr/tests/pdf.rs +++ b/rand_distr/tests/pdf.rs @@ -12,7 +12,8 @@ use average::Histogram; use rand::{Rng, SeedableRng}; use rand_distr::Normal; -average::define_histogram!(hist, 100); +const HIST_LEN: usize = 100; +average::define_histogram!(hist, crate::HIST_LEN); use hist::Histogram as Histogram100; mod sparkline; @@ -42,7 +43,7 @@ fn normal() { } let mut bin_centers = hist.centers(); - let mut expected = [0.; 100]; + let mut expected = [0.; HIST_LEN]; for e in &mut expected[..] { *e = pdf(bin_centers.next().unwrap()); } @@ -51,8 +52,8 @@ fn normal() { sparkline::render_u64_as_string(hist.bins())); let mut normalized_bins= hist.normalized_bins(); - let mut diff = [0.; 100]; - for i in 0..100 { + let mut diff = [0.; HIST_LEN]; + for i in 0..HIST_LEN { let bin = (normalized_bins.next().unwrap() as f64) / (N_SAMPLES as f64) ; diff[i] = (bin - expected[i]).abs(); } @@ -63,7 +64,7 @@ fn normal() { core::f64::NEG_INFINITY, |a, &b| a.max(b))); // Check that the differences are significantly smaller than the expected error. - let mut expected_error = [0.; 100]; + let mut expected_error = [0.; HIST_LEN]; // Calculate error from histogram for (err, var) in expected_error.iter_mut().zip(hist.variances()) { *err = var.sqrt() / (N_SAMPLES as f64); From 66da6e633a0de4a963f3c5a0c2f8d6b8bbe8e47c Mon Sep 17 00:00:00 2001 From: Vinzent Steinberg Date: Sun, 9 May 2021 14:55:35 -0300 Subject: [PATCH 14/14] Simplify loop --- rand_distr/tests/pdf.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/rand_distr/tests/pdf.rs b/rand_distr/tests/pdf.rs index d5ab177d98a..b1d1aa28174 100644 --- a/rand_distr/tests/pdf.rs +++ b/rand_distr/tests/pdf.rs @@ -51,10 +51,9 @@ fn normal() { println!("Expected normal distribution:\n{}", sparkline::render_u64_as_string(hist.bins())); - let mut normalized_bins= hist.normalized_bins(); let mut diff = [0.; HIST_LEN]; - for i in 0..HIST_LEN { - let bin = (normalized_bins.next().unwrap() as f64) / (N_SAMPLES as f64) ; + for (i, n) in hist.normalized_bins().enumerate() { + let bin = (n as f64) / (N_SAMPLES as f64) ; diff[i] = (bin - expected[i]).abs(); }