Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge 0.5 #599

Merged
merged 6 commits into from
Sep 24, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions benches/seq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ impl<I: ExactSizeIterator + Iterator + Clone> Iterator for WindowHintedIterator<
}

#[bench]
fn seq_iter_unhinted_choose_from_100(b: &mut Bencher) {
fn seq_iter_unhinted_choose_from_1000(b: &mut Bencher) {
let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
let x : &[usize] = &[1; 1000];
b.iter(|| {
Expand All @@ -125,9 +125,9 @@ fn seq_iter_unhinted_choose_from_100(b: &mut Bencher) {
}

#[bench]
fn seq_iter_window_hinted_choose_from_100(b: &mut Bencher) {
fn seq_iter_window_hinted_choose_from_1000(b: &mut Bencher) {
let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
let x : &[usize] = &[1; 100];
let x : &[usize] = &[1; 1000];
b.iter(|| {
WindowHintedIterator { iter: x.iter(), window_size: 7 }.choose(&mut rng)
})
Expand Down
8 changes: 8 additions & 0 deletions rand_core/src/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,10 @@ impl<R: BlockRngCore + SeedableRng> SeedableRng for BlockRng<R> {
Self::new(R::from_seed(seed))
}

fn seed_from_u64(seed: u64) -> Self {
Self::new(R::seed_from_u64(seed))
}

fn from_rng<S: RngCore>(rng: S) -> Result<Self, Error> {
Ok(Self::new(R::from_rng(rng)?))
}
Expand Down Expand Up @@ -492,6 +496,10 @@ impl<R: BlockRngCore + SeedableRng> SeedableRng for BlockRng64<R> {
Self::new(R::from_seed(seed))
}

fn seed_from_u64(seed: u64) -> Self {
Self::new(R::seed_from_u64(seed))
}

fn from_rng<S: RngCore>(rng: S) -> Result<Self, Error> {
Ok(Self::new(R::from_rng(rng)?))
}
Expand Down
85 changes: 84 additions & 1 deletion rand_core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@

use core::default::Default;
use core::convert::AsMut;
use core::ptr::copy_nonoverlapping;

#[cfg(all(feature="alloc", not(feature="std")))] use alloc::boxed::Box;

Expand Down Expand Up @@ -296,7 +297,46 @@ pub trait SeedableRng: Sized {
/// for example `0xBAD5EEDu32` or `0x0DDB1A5E5BAD5EEDu64` ("odd biases? bad
/// seed"). This is assuming only a small number of values must be rejected.
fn from_seed(seed: Self::Seed) -> Self;


/// Create a new PRNG using a `u64` seed.
///
/// This is a convenience-wrapper around `from_seed` to allow construction
/// of any `SeedableRng` from a simple `u64` value. It is designed such that
/// low Hamming Weight numbers like 0 and 1 can be used and should still
/// result in good, independent seeds to the PRNG which is returned.
///
/// This **is not suitable for cryptography**, as should be clear given that
/// the input size is only 64 bits.
///
/// Implementations for PRNGs *may* provide their own implementations of
/// this function, but the default implementation should be good enough for
/// all purposes. *Changing* the implementation of this function should be
/// considered a value-breaking change.
fn seed_from_u64(mut state: u64) -> Self {
// We use PCG32 to generate a u32 sequence, and copy to the seed
const MUL: u64 = 6364136223846793005;
const INC: u64 = 11634580027462260723;

let mut seed = Self::Seed::default();
for chunk in seed.as_mut().chunks_mut(4) {
// We advance the state first (to get away from the input value,
// in case it has low Hamming Weight).
state = state.wrapping_mul(MUL).wrapping_add(INC);

// Use PCG output function with to_le to generate x:
let xorshifted = (((state >> 18) ^ state) >> 27) as u32;
let rot = (state >> 59) as u32;
let x = xorshifted.rotate_right(rot).to_le();

unsafe {
let p = &x as *const u32 as *const u8;
copy_nonoverlapping(p, chunk.as_mut_ptr(), chunk.len());
}
}

Self::from_seed(seed)
}

/// Create a new PRNG seeded from another `Rng`.
///
/// This is the recommended way to initialize PRNGs with fresh entropy. The
Expand Down Expand Up @@ -401,3 +441,46 @@ impl<'a, R: CryptoRng + ?Sized> CryptoRng for &'a mut R {}
// Implement `CryptoRng` for boxed references to an `CryptoRng`.
#[cfg(feature="alloc")]
impl<R: CryptoRng + ?Sized> CryptoRng for Box<R> {}

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

#[test]
fn test_seed_from_u64() {
struct SeedableNum(u64);
impl SeedableRng for SeedableNum {
type Seed = [u8; 8];
fn from_seed(seed: Self::Seed) -> Self {
let mut x = [0u64; 1];
le::read_u64_into(&seed, &mut x);
SeedableNum(x[0])
}
}

const N: usize = 8;
const SEEDS: [u64; N] = [0u64, 1, 2, 3, 4, 8, 16, -1i64 as u64];
let mut results = [0u64; N];
for (i, seed) in SEEDS.iter().enumerate() {
let SeedableNum(x) = SeedableNum::seed_from_u64(*seed);
results[i] = x;
}

for (i1, r1) in results.iter().enumerate() {
let weight = r1.count_ones();
// 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);

for (i2, r2) in results.iter().enumerate() {
if i1 == i2 { continue; }
let diff_weight = (r1 ^ r2).count_ones();
assert!(diff_weight >= 20);
}
}

// value-breakage test:
assert_eq!(results[0], 5029875928683246316);
}
}
46 changes: 27 additions & 19 deletions rand_isaac/src/isaac.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,13 @@ impl SeedableRng for IsaacRng {
fn from_seed(seed: Self::Seed) -> Self {
IsaacRng(BlockRng::<IsaacCore>::from_seed(seed))
}

/// Create an ISAAC random number generator using an `u64` as seed.
/// If `seed == 0` this will produce the same stream of random numbers as
/// the reference implementation when used unseeded.
fn seed_from_u64(seed: u64) -> Self {
IsaacRng(BlockRng::<IsaacCore>::seed_from_u64(seed))
}

fn from_rng<S: RngCore>(rng: S) -> Result<Self, Error> {
BlockRng::<IsaacCore>::from_rng(rng).map(|rng| IsaacRng(rng))
Expand All @@ -128,8 +135,9 @@ impl IsaacRng {
/// Create an ISAAC random number generator using an `u64` as seed.
/// If `seed == 0` this will produce the same stream of random numbers as
/// the reference implementation when used unseeded.
#[deprecated(since="0.6.0", note="use SeedableRng::seed_from_u64 instead")]
pub fn new_from_u64(seed: u64) -> Self {
IsaacRng(BlockRng::new(IsaacCore::new_from_u64(seed)))
Self::seed_from_u64(seed)
}
}

Expand Down Expand Up @@ -300,22 +308,6 @@ impl IsaacCore {

Self { mem, a: w(0), b: w(0), c: w(0) }
}

/// Create an ISAAC random number generator using an `u64` as seed.
/// If `seed == 0` this will produce the same stream of random numbers as
/// the reference implementation when used unseeded.
fn new_from_u64(seed: u64) -> Self {
let mut key = [w(0); RAND_SIZE];
key[0] = w(seed as u32);
key[1] = w((seed >> 32) as u32);
// Initialize with only one pass.
// A second pass does not improve the quality here, because all of the
// seed was already available in the first round.
// Not doing the second pass has the small advantage that if
// `seed == 0` this method produces exactly the same state as the
// reference implementation when used unseeded.
Self::init(key, 1)
}
}

impl SeedableRng for IsaacCore {
Expand All @@ -331,6 +323,22 @@ impl SeedableRng for IsaacCore {
}
Self::init(seed_extended, 2)
}

/// Create an ISAAC random number generator using an `u64` as seed.
/// If `seed == 0` this will produce the same stream of random numbers as
/// the reference implementation when used unseeded.
fn seed_from_u64(seed: u64) -> Self {
let mut key = [w(0); RAND_SIZE];
key[0] = w(seed as u32);
key[1] = w((seed >> 32) as u32);
// Initialize with only one pass.
// A second pass does not improve the quality here, because all of the
// seed was already available in the first round.
// Not doing the second pass has the small advantage that if
// `seed == 0` this method produces exactly the same state as the
// reference implementation when used unseeded.
Self::init(key, 1)
}

fn from_rng<R: RngCore>(mut rng: R) -> Result<Self, Error> {
// Custom `from_rng` implementation that fills a seed with the same size
Expand Down Expand Up @@ -424,11 +432,11 @@ mod test {
#[test]
fn test_isaac_new_uninitialized() {
// Compare the results from initializing `IsaacRng` with
// `new_from_u64(0)`, to make sure it is the same as the reference
// `seed_from_u64(0)`, to make sure it is the same as the reference
// implementation when used uninitialized.
// Note: We only test the first 16 integers, not the full 256 of the
// first block.
let mut rng = IsaacRng::new_from_u64(0);
let mut rng = IsaacRng::seed_from_u64(0);
let mut results = [0u32; 16];
for i in results.iter_mut() { *i = rng.next_u32(); }
let expected: [u32; 16] = [
Expand Down
37 changes: 25 additions & 12 deletions rand_isaac/src/isaac64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,13 @@ impl SeedableRng for Isaac64Rng {
Isaac64Rng(BlockRng64::<Isaac64Core>::from_seed(seed))
}

/// Create an ISAAC random number generator using an `u64` as seed.
/// If `seed == 0` this will produce the same stream of random numbers as
/// the reference implementation when used unseeded.
fn seed_from_u64(seed: u64) -> Self {
Isaac64Rng(BlockRng64::<Isaac64Core>::seed_from_u64(seed))
}

fn from_rng<S: RngCore>(rng: S) -> Result<Self, Error> {
BlockRng64::<Isaac64Core>::from_rng(rng).map(|rng| Isaac64Rng(rng))
}
Expand All @@ -118,8 +125,9 @@ impl Isaac64Rng {
/// Create an ISAAC-64 random number generator using an `u64` as seed.
/// If `seed == 0` this will produce the same stream of random numbers as
/// the reference implementation when used unseeded.
#[deprecated(since="0.6.0", note="use SeedableRng::seed_from_u64 instead")]
pub fn new_from_u64(seed: u64) -> Self {
Isaac64Rng(BlockRng64::new(Isaac64Core::new_from_u64(seed)))
Self::seed_from_u64(seed)
}
}

Expand Down Expand Up @@ -269,16 +277,9 @@ impl Isaac64Core {
/// Create an ISAAC-64 random number generator using an `u64` as seed.
/// If `seed == 0` this will produce the same stream of random numbers as
/// the reference implementation when used unseeded.
#[deprecated(since="0.6.0", note="use SeedableRng::seed_from_u64 instead")]
pub fn new_from_u64(seed: u64) -> Self {
let mut key = [w(0); RAND_SIZE];
key[0] = w(seed);
// Initialize with only one pass.
// A second pass does not improve the quality here, because all of the
// seed was already available in the first round.
// Not doing the second pass has the small advantage that if
// `seed == 0` this method produces exactly the same state as the
// reference implementation when used unseeded.
Self::init(key, 1)
Self::seed_from_u64(seed)
}
}

Expand All @@ -295,6 +296,18 @@ impl SeedableRng for Isaac64Core {
}
Self::init(seed_extended, 2)
}

fn seed_from_u64(seed: u64) -> Self {
let mut key = [w(0); RAND_SIZE];
key[0] = w(seed);
// Initialize with only one pass.
// A second pass does not improve the quality here, because all of the
// seed was already available in the first round.
// Not doing the second pass has the small advantage that if
// `seed == 0` this method produces exactly the same state as the
// reference implementation when used unseeded.
Self::init(key, 1)
}

fn from_rng<R: RngCore>(mut rng: R) -> Result<Self, Error> {
// Custom `from_rng` implementation that fills a seed with the same size
Expand Down Expand Up @@ -414,11 +427,11 @@ mod test {
#[test]
fn test_isaac64_new_uninitialized() {
// Compare the results from initializing `IsaacRng` with
// `new_from_u64(0)`, to make sure it is the same as the reference
// `seed_from_u64(0)`, to make sure it is the same as the reference
// implementation when used uninitialized.
// Note: We only test the first 16 integers, not the full 256 of the
// first block.
let mut rng = Isaac64Rng::new_from_u64(0);
let mut rng = Isaac64Rng::seed_from_u64(0);
let mut results = [0u64; 16];
for i in results.iter_mut() { *i = rng.next_u64(); }
let expected: [u64; 16] = [
Expand Down
6 changes: 3 additions & 3 deletions src/distributions/unit_circle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,8 @@ mod tests {
fn value_stability() {
let mut rng = ::test::rng(2);
let dist = UnitCircle::new();
assert_eq!(dist.sample(&mut rng), [-0.8150602311723979, 0.5793762331690843]);
assert_eq!(dist.sample(&mut rng), [-0.056204569973983196, 0.998419273809375]);
assert_eq!(dist.sample(&mut rng), [0.7761923749562624, -0.630496151502733]);
assert_eq!(dist.sample(&mut rng), [-0.8032118336637037, 0.5956935036263119]);
assert_eq!(dist.sample(&mut rng), [-0.4742919588505423, -0.880367615130018]);
assert_eq!(dist.sample(&mut rng), [0.9297328981467168, 0.368234623716601]);
}
}
6 changes: 3 additions & 3 deletions src/distributions/unit_sphere.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,10 @@ mod tests {
let mut rng = ::test::rng(2);
let dist = UnitSphereSurface::new();
assert_eq!(dist.sample(&mut rng),
[0.1660727273690104, 0.5202698793511903, 0.8376986939610902]);
[-0.24950027180862533, -0.7552572587896719, 0.6060825747478084]);
assert_eq!(dist.sample(&mut rng),
[0.40052443371799834, 0.4237054996596154, -0.812436968356975]);
[0.47604534507233487, -0.797200864987207, -0.3712837328763685]);
assert_eq!(dist.sample(&mut rng),
[0.9209910250970449, -0.32692477745072107, 0.21188610520628948]);
[0.9795722330927367, 0.18692349236651176, 0.07414747571708524]);
}
}
21 changes: 4 additions & 17 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -957,21 +957,7 @@ mod test {
}

pub fn rng(seed: u64) -> TestRng<StdRng> {
// TODO: use from_hashable
let mut state = seed;
let mut seed = <StdRng as SeedableRng>::Seed::default();
for x in seed.iter_mut() {
// PCG algorithm
const MUL: u64 = 6364136223846793005;
const INC: u64 = 11634580027462260723;
let oldstate = state;
state = oldstate.wrapping_mul(MUL).wrapping_add(INC);

let xorshifted = (((oldstate >> 18) ^ oldstate) >> 27) as u32;
let rot = (oldstate >> 59) as u32;
*x = xorshifted.rotate_right(rot) as u8;
}
TestRng { inner: StdRng::from_seed(seed) }
TestRng { inner: StdRng::seed_from_u64(seed) }
}

#[test]
Expand Down Expand Up @@ -1116,7 +1102,8 @@ mod test {
sum += 1;
}
}
let avg = (sum as f64) / (N as f64);
assert!((avg - (NUM as f64)/(DENOM as f64)).abs() < 1e-3);
// Have Binomial(N, NUM/DENOM) distribution
let expected = (NUM * N) / DENOM; // exact integer
assert!(((sum - expected) as i32).abs() < 500);
}
}
Loading