diff --git a/Cargo.toml b/Cargo.toml index 41ddde39..e445a013 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,7 @@ path = "src/lib.rs" [features] default = [ "std" ] -std = [ "matrixmultiply", "rand/std", "alga/std" ] +std = [ "matrixmultiply", "rand/std", "alga/std", "rand_distr" ] stdweb = [ "rand/stdweb" ] arbitrary = [ "quickcheck" ] serde-serialize = [ "serde", "serde_derive", "num-complex/serde" ] @@ -34,7 +34,8 @@ io = [ "pest", "pest_derive" ] [dependencies] typenum = "1.10" generic-array = "0.12" -rand = { version = "0.6", default-features = false } +rand = { version = "0.7", default-features = false } +rand_distr = { version = "0.2", optional = true } num-traits = { version = "0.2", default-features = false } num-complex = { version = "0.2", default-features = false } num-rational = { version = "0.2", default-features = false } @@ -54,7 +55,9 @@ pest_derive = { version = "2.0", optional = true } [dev-dependencies] serde_json = "1.0" -rand_xorshift = "0.1" +rand = { version = "0.7", features = ["small_rng"] } +# IsaacRng is used by benches; keep for reproducibility? +rand_isaac = "0.2" ### Uncomment this line before running benchmarks. ### We can't just let this uncommented because that would break ### compilation for #[no-std] because of the terrible Cargo bug diff --git a/benches/core/matrix.rs b/benches/core/matrix.rs index 12fb836d..ea46e57b 100644 --- a/benches/core/matrix.rs +++ b/benches/core/matrix.rs @@ -1,5 +1,4 @@ use na::{DMatrix, DVector, Matrix2, Matrix3, Matrix4, MatrixN, Vector2, Vector3, Vector4, U10}; -use rand::{IsaacRng, Rng}; use std::ops::{Add, Div, Mul, Sub}; #[path = "../common/macros.rs"] diff --git a/benches/core/vector.rs b/benches/core/vector.rs index 7d3237e8..7a4cd8ea 100644 --- a/benches/core/vector.rs +++ b/benches/core/vector.rs @@ -1,5 +1,6 @@ use na::{DVector, Vector2, Vector3, Vector4, VectorN}; -use rand::{IsaacRng, Rng}; +use rand::{Rng, SeedableRng}; +use rand_isaac::IsaacRng; use std::ops::{Add, Div, Mul, Sub}; use typenum::U10000; @@ -48,7 +49,6 @@ bench_binop_ref!(vec10000_dot_f64, VectorN, VectorN, d bench_binop_ref!(vec10000_dot_f32, VectorN, VectorN, dot); fn vec10000_axpy_f64(bh: &mut criterion::Criterion) { - use rand::SeedableRng; let mut rng = IsaacRng::seed_from_u64(0); let mut a = DVector::new_random(10000); let b = DVector::new_random(10000); @@ -58,7 +58,6 @@ fn vec10000_axpy_f64(bh: &mut criterion::Criterion) { } fn vec10000_axpy_beta_f64(bh: &mut criterion::Criterion) { - use rand::SeedableRng; let mut rng = IsaacRng::seed_from_u64(0); let mut a = DVector::new_random(10000); let b = DVector::new_random(10000); @@ -69,7 +68,6 @@ fn vec10000_axpy_beta_f64(bh: &mut criterion::Criterion) { } fn vec10000_axpy_f64_slice(bh: &mut criterion::Criterion) { - use rand::SeedableRng; let mut rng = IsaacRng::seed_from_u64(0); let mut a = DVector::new_random(10000); let b = DVector::new_random(10000); @@ -84,7 +82,6 @@ fn vec10000_axpy_f64_slice(bh: &mut criterion::Criterion) { } fn vec10000_axpy_f64_static(bh: &mut criterion::Criterion) { - use rand::SeedableRng; let mut rng = IsaacRng::seed_from_u64(0); let mut a = VectorN::::new_random(); let b = VectorN::::new_random(); @@ -95,7 +92,6 @@ fn vec10000_axpy_f64_static(bh: &mut criterion::Criterion) { } fn vec10000_axpy_f32(bh: &mut criterion::Criterion) { - use rand::SeedableRng; let mut rng = IsaacRng::seed_from_u64(0); let mut a = DVector::new_random(10000); let b = DVector::new_random(10000); @@ -105,7 +101,6 @@ fn vec10000_axpy_f32(bh: &mut criterion::Criterion) { } fn vec10000_axpy_beta_f32(bh: &mut criterion::Criterion) { - use rand::SeedableRng; let mut rng = IsaacRng::seed_from_u64(0); let mut a = DVector::new_random(10000); let b = DVector::new_random(10000); diff --git a/benches/geometry/quaternion.rs b/benches/geometry/quaternion.rs index dd079aac..ff9baee1 100644 --- a/benches/geometry/quaternion.rs +++ b/benches/geometry/quaternion.rs @@ -1,5 +1,4 @@ use na::{Quaternion, UnitQuaternion, Vector3}; -use rand::{IsaacRng, Rng}; use std::ops::{Add, Div, Mul, Sub}; #[path = "../common/macros.rs"] diff --git a/benches/lib.rs b/benches/lib.rs index d5333542..377cd04f 100644 --- a/benches/lib.rs +++ b/benches/lib.rs @@ -10,15 +10,14 @@ extern crate typenum; extern crate criterion; use na::DMatrix; -use rand::{IsaacRng, Rng}; +use rand::{Rng, SeedableRng}; pub mod core; pub mod geometry; pub mod linalg; fn reproductible_dmatrix(nrows: usize, ncols: usize) -> DMatrix { - use rand::SeedableRng; - let mut rng = IsaacRng::seed_from_u64(0); + let mut rng = rand_isaac::IsaacRng::seed_from_u64(0); DMatrix::::from_fn(nrows, ncols, |_, _| rng.gen()) } diff --git a/ci/build.sh b/ci/build.sh index 550c9a69..b84100ad 100755 --- a/ci/build.sh +++ b/ci/build.sh @@ -4,6 +4,7 @@ set -ev if [ -z "$NO_STD" ]; then if [ -z "$LAPACK" ]; then + cargo build --verbose -p nalgebra --no-default-features --lib; cargo build --verbose -p nalgebra; cargo build --verbose -p nalgebra --features "arbitrary"; cargo build --verbose -p nalgebra --features "mint"; diff --git a/ci/test.sh b/ci/test.sh index a3a27fb2..233961f3 100755 --- a/ci/test.sh +++ b/ci/test.sh @@ -4,6 +4,7 @@ set -ev if [ -z "$NO_STD" ]; then if [ -z "$LAPACK" ]; then + cargo test --verbose --no-default-features --lib; cargo test --verbose; cargo test --verbose "arbitrary"; cargo test --verbose --all-features; diff --git a/nalgebra-lapack/Cargo.toml b/nalgebra-lapack/Cargo.toml index 9d392712..7f632869 100644 --- a/nalgebra-lapack/Cargo.toml +++ b/nalgebra-lapack/Cargo.toml @@ -37,4 +37,4 @@ lapack-src = { version = "0.2", default-features = false } nalgebra = { version = "0.18", path = "..", features = [ "arbitrary" ] } quickcheck = "0.8" approx = "0.3" -rand = "0.6" +rand = "0.7" diff --git a/src/base/construction.rs b/src/base/construction.rs index 5eace4bb..91f454b3 100644 --- a/src/base/construction.rs +++ b/src/base/construction.rs @@ -7,7 +7,7 @@ use num::{Bounded, One, Zero}; use rand::distributions::{Distribution, Standard}; use rand::Rng; #[cfg(feature = "std")] -use rand::{self, distributions::StandardNormal}; +use rand_distr::StandardNormal; use std::iter; use typenum::{self, Cmp, Greater}; @@ -243,7 +243,8 @@ where DefaultAllocator: Allocator #[cfg(feature = "std")] pub fn new_random_generic(nrows: R, ncols: C) -> Self where Standard: Distribution { - Self::from_fn_generic(nrows, ncols, |_, _| rand::random()) + let mut rng = rand::thread_rng(); + Self::from_fn_generic(nrows, ncols, |_, _| rng.gen()) } /// Creates a matrix filled with random values from the given distribution. @@ -794,6 +795,7 @@ where } } +// TODO(specialization): faster impls possible for D≤4 (see rand_distr::{UnitCircle, UnitSphere}) #[cfg(feature = "std")] impl Distribution>> for Standard where diff --git a/src/geometry/orthographic.rs b/src/geometry/orthographic.rs index 2c713118..22bd05ef 100644 --- a/src/geometry/orthographic.rs +++ b/src/geometry/orthographic.rs @@ -681,6 +681,7 @@ impl Orthographic3 { impl Distribution> for Standard where Standard: Distribution { + /// Generate an arbitrary random variate for testing purposes. fn sample(&self, r: &mut R) -> Orthographic3 { let left = r.gen(); let right = helper::reject_rand(r, |x: &N| *x > left); diff --git a/src/geometry/perspective.rs b/src/geometry/perspective.rs index 8020c0cf..ae47ed00 100644 --- a/src/geometry/perspective.rs +++ b/src/geometry/perspective.rs @@ -264,6 +264,7 @@ impl Perspective3 { impl Distribution> for Standard where Standard: Distribution { + /// Generate an arbitrary random variate for testing purposes. fn sample<'a, R: Rng + ?Sized>(&self, r: &'a mut R) -> Perspective3 { let znear = r.gen(); let zfar = helper::reject_rand(r, |&x: &N| !(x - znear).is_zero()); diff --git a/src/geometry/point_construction.rs b/src/geometry/point_construction.rs index 2fac11d4..6ad321dc 100644 --- a/src/geometry/point_construction.rs +++ b/src/geometry/point_construction.rs @@ -131,6 +131,7 @@ where DefaultAllocator: Allocator, Standard: Distribution, { + /// Generates a `Point` where each coordinate is an independent variate from `[0, 1)`. #[inline] fn sample<'a, G: Rng + ?Sized>(&self, rng: &mut G) -> Point { Point::from(rng.gen::>()) diff --git a/src/geometry/quaternion_construction.rs b/src/geometry/quaternion_construction.rs index 893fdb6a..d9ed0c2b 100644 --- a/src/geometry/quaternion_construction.rs +++ b/src/geometry/quaternion_construction.rs @@ -724,13 +724,12 @@ where #[cfg(test)] mod tests { - extern crate rand_xorshift; use super::*; - use rand::SeedableRng; + use rand::{SeedableRng, rngs::SmallRng}; #[test] fn random_unit_quats_are_unit() { - let mut rng = rand_xorshift::XorShiftRng::from_seed([0xAB; 16]); + let mut rng = SmallRng::seed_from_u64(2); for _ in 0..1000 { let x = rng.gen::>(); assert!(relative_eq!(x.into_inner().norm(), 1.0)) diff --git a/src/geometry/rotation_specialization.rs b/src/geometry/rotation_specialization.rs index 4baec27c..493a1c12 100644 --- a/src/geometry/rotation_specialization.rs +++ b/src/geometry/rotation_specialization.rs @@ -5,7 +5,7 @@ use quickcheck::{Arbitrary, Gen}; use alga::general::RealField; use num::Zero; -use rand::distributions::{Distribution, OpenClosed01, Standard}; +use rand::distributions::{Distribution, OpenClosed01, Standard, uniform::SampleUniform}; use rand::Rng; use std::ops::Neg; @@ -231,12 +231,12 @@ impl Rotation2 { } impl Distribution> for Standard -where OpenClosed01: Distribution +where N: SampleUniform { /// Generate a uniformly distributed random rotation. #[inline] fn sample<'a, R: Rng + ?Sized>(&self, rng: &'a mut R) -> Rotation2 { - Rotation2::new(rng.sample(OpenClosed01) * N::two_pi()) + Rotation2::new(rng.gen_range(N::zero(), N::two_pi())) } } @@ -818,7 +818,7 @@ impl Rotation3 { } impl Distribution> for Standard -where OpenClosed01: Distribution +where OpenClosed01: Distribution, N: SampleUniform { /// Generate a uniformly distributed random rotation. #[inline] @@ -828,7 +828,7 @@ where OpenClosed01: Distribution // In D. Kirk, editor, Graphics Gems III, pages 117-120. Academic, New York, 1992. // Compute a random rotation around Z - let theta = N::two_pi() * rng.sample(OpenClosed01); + let theta = rng.gen_range(N::zero(), N::two_pi()); let (ts, tc) = theta.sin_cos(); let a = MatrixN::::new( tc, @@ -843,7 +843,7 @@ where OpenClosed01: Distribution ); // Compute a random rotation *of* Z - let phi = N::two_pi() * rng.sample(OpenClosed01); + let phi = rng.gen_range(N::zero(), N::two_pi()); let z = rng.sample(OpenClosed01); let (ps, pc) = phi.sin_cos(); let sqrt_z = z.sqrt(); diff --git a/src/geometry/similarity_construction.rs b/src/geometry/similarity_construction.rs index a3722ba9..53ec0d76 100644 --- a/src/geometry/similarity_construction.rs +++ b/src/geometry/similarity_construction.rs @@ -63,6 +63,7 @@ where DefaultAllocator: Allocator, Standard: Distribution + Distribution, { + /// Generate an arbitrary random variate for testing purposes. #[inline] fn sample<'a, G: Rng + ?Sized>(&self, rng: &mut G) -> Similarity { let mut s = rng.gen(); diff --git a/src/geometry/translation_construction.rs b/src/geometry/translation_construction.rs index 339bdd2a..e366bba3 100644 --- a/src/geometry/translation_construction.rs +++ b/src/geometry/translation_construction.rs @@ -52,6 +52,7 @@ where DefaultAllocator: Allocator, Standard: Distribution, { + /// Generate an arbitrary random variate for testing purposes. #[inline] fn sample<'a, G: Rng + ?Sized>(&self, rng: &'a mut G) -> Translation { Translation::from(rng.gen::>()) diff --git a/src/geometry/unit_complex_construction.rs b/src/geometry/unit_complex_construction.rs index 046142c8..32bb1252 100644 --- a/src/geometry/unit_complex_construction.rs +++ b/src/geometry/unit_complex_construction.rs @@ -3,7 +3,7 @@ use quickcheck::{Arbitrary, Gen}; use num::One; use num_complex::Complex; -use rand::distributions::{Distribution, OpenClosed01, Standard}; +use rand::distributions::{Distribution, Standard, uniform::SampleUniform}; use rand::Rng; use alga::general::RealField; @@ -276,12 +276,12 @@ impl One for UnitComplex { } impl Distribution> for Standard -where OpenClosed01: Distribution +where N: SampleUniform { /// Generate a uniformly distributed random `UnitComplex`. #[inline] fn sample<'a, R: Rng + ?Sized>(&self, rng: &mut R) -> UnitComplex { - UnitComplex::from_angle(rng.sample(OpenClosed01) * N::two_pi()) + UnitComplex::from_angle(rng.gen_range(N::zero(), N::two_pi())) } } diff --git a/src/linalg/symmetric_eigen.rs b/src/linalg/symmetric_eigen.rs index fc493dca..2a7bb992 100644 --- a/src/linalg/symmetric_eigen.rs +++ b/src/linalg/symmetric_eigen.rs @@ -354,6 +354,7 @@ mod test { } } + #[cfg(feature = "std")] #[test] fn wilkinson_shift_random() { for _ in 0..1000 { diff --git a/tests/core/helper.rs b/tests/core/helper.rs index 625a4a46..bbece569 100644 --- a/tests/core/helper.rs +++ b/tests/core/helper.rs @@ -33,6 +33,7 @@ impl Distribution> for Standard // This is a wrapper similar to RandComplex, but for non-complex. // This exists only to make generic tests easier to write. +// Generates variates in the range [0, 1). Do we want this? E.g. we could use standard normal samples instead. #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct RandScalar(pub N);