diff --git a/src/libextra/bitv.rs b/src/libextra/bitv.rs index 98f69425aee..4f8cd4d3308 100644 --- a/src/libextra/bitv.rs +++ b/src/libextra/bitv.rs @@ -1524,8 +1524,8 @@ mod tests { } fn rng() -> rand::IsaacRng { - let seed = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]; - rand::IsaacRng::new_seeded(seed) + let seed = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]; + rand::SeedableRng::from_seed(seed) } #[bench] diff --git a/src/libextra/treemap.rs b/src/libextra/treemap.rs index ee7ba4a888b..66e1fd0c2c3 100644 --- a/src/libextra/treemap.rs +++ b/src/libextra/treemap.rs @@ -1013,7 +1013,7 @@ mod test_treemap { check_equal(ctrl, &map); assert!(map.find(&5).is_none()); - let mut rng = rand::IsaacRng::new_seeded(&[42]); + let mut rng: rand::IsaacRng = rand::SeedableRng::from_seed(&[42]); do 3.times { do 90.times { diff --git a/src/libstd/rand/isaac.rs b/src/libstd/rand/isaac.rs index 534ebfb473b..6d338a922be 100644 --- a/src/libstd/rand/isaac.rs +++ b/src/libstd/rand/isaac.rs @@ -10,15 +10,10 @@ //! The ISAAC random number generator. -use rand::{seed, Rng}; -use iter::{Iterator, range, range_step}; +use rand::{seed, Rng, SeedableRng}; +use iter::{Iterator, range, range_step, Repeat}; use option::{None, Some}; -use cast; -use cmp; -use sys; -use vec; - static RAND_SIZE_LEN: u32 = 8; static RAND_SIZE: u32 = 1 << RAND_SIZE_LEN; @@ -38,30 +33,8 @@ pub struct IsaacRng { impl IsaacRng { /// Create an ISAAC random number generator with a random seed. pub fn new() -> IsaacRng { - IsaacRng::new_seeded(seed(RAND_SIZE as uint * 4)) - } - - /// Create an ISAAC random number generator with a seed. This can be any - /// length, although the maximum number of bytes used is 1024 and any more - /// will be silently ignored. A generator constructed with a given seed - /// will generate the same sequence of values as all other generators - /// constructed with the same seed. - pub fn new_seeded(seed: &[u8]) -> IsaacRng { - let mut rng = IsaacRng { - cnt: 0, - rsl: [0, .. RAND_SIZE], - mem: [0, .. RAND_SIZE], - a: 0, b: 0, c: 0 - }; - - let array_size = sys::size_of_val(&rng.rsl); - let copy_length = cmp::min(array_size, seed.len()); - - // manually create a &mut [u8] slice of randrsl to copy into. - let dest = unsafe { cast::transmute((&mut rng.rsl, array_size)) }; - vec::bytes::copy_memory(dest, seed, copy_length); - rng.init(true); - rng + let s = unsafe {seed::(RAND_SIZE as uint)}; + SeedableRng::from_seed(s.as_slice()) } /// Create an ISAAC random number generator using the default @@ -197,6 +170,43 @@ impl Rng for IsaacRng { } } +impl<'self> SeedableRng<&'self [u32]> for IsaacRng { + fn reseed(&mut self, seed: &'self [u32]) { + // make the seed into [seed[0], seed[1], ..., seed[seed.len() + // - 1], 0, 0, ...], to fill rng.rsl. + let seed_iter = seed.iter().map(|&x| x).chain(Repeat::new(0u32)); + + for (rsl_elem, seed_elem) in self.rsl.mut_iter().zip(seed_iter) { + *rsl_elem = seed_elem; + } + self.cnt = 0; + self.a = 0; + self.b = 0; + self.c = 0; + + self.init(true); + } + + /// Create an ISAAC random number generator with a seed. This can + /// be any length, although the maximum number of elements used is + /// 256 and any more will be silently ignored. A generator + /// constructed with a given seed will generate the same sequence + /// of values as all other generators constructed with that seed. + fn from_seed(seed: &'self [u32]) -> IsaacRng { + let mut rng = IsaacRng { + cnt: 0, + rsl: [0, .. RAND_SIZE], + mem: [0, .. RAND_SIZE], + a: 0, b: 0, c: 0 + }; + + rng.reseed(seed); + + rng + } +} + + static RAND_SIZE_64_LEN: uint = 8; static RAND_SIZE_64: uint = 1 << RAND_SIZE_64_LEN; @@ -218,31 +228,8 @@ impl Isaac64Rng { /// Create a 64-bit ISAAC random number generator with a random /// seed. pub fn new() -> Isaac64Rng { - Isaac64Rng::new_seeded(seed(RAND_SIZE_64 as uint * 8)) - } - - /// Create a 64-bit ISAAC random number generator with a - /// seed. This can be any length, although the maximum number of - /// bytes used is 2048 and any more will be silently ignored. A - /// generator constructed with a given seed will generate the same - /// sequence of values as all other generators constructed with - /// the same seed. - pub fn new_seeded(seed: &[u8]) -> Isaac64Rng { - let mut rng = Isaac64Rng { - cnt: 0, - rsl: [0, .. RAND_SIZE_64], - mem: [0, .. RAND_SIZE_64], - a: 0, b: 0, c: 0, - }; - - let array_size = sys::size_of_val(&rng.rsl); - let copy_length = cmp::min(array_size, seed.len()); - - // manually create a &mut [u8] slice of randrsl to copy into. - let dest = unsafe { cast::transmute((&mut rng.rsl, array_size)) }; - vec::bytes::copy_memory(dest, seed, copy_length); - rng.init(true); - rng + let s = unsafe {seed::(RAND_SIZE_64)}; + SeedableRng::from_seed(s.as_slice()) } /// Create a 64-bit ISAAC random number generator using the @@ -378,22 +365,58 @@ impl Rng for Isaac64Rng { } } +impl<'self> SeedableRng<&'self [u64]> for Isaac64Rng { + fn reseed(&mut self, seed: &'self [u64]) { + // make the seed into [seed[0], seed[1], ..., seed[seed.len() + // - 1], 0, 0, ...], to fill rng.rsl. + let seed_iter = seed.iter().map(|&x| x).chain(Repeat::new(0u64)); + + for (rsl_elem, seed_elem) in self.rsl.mut_iter().zip(seed_iter) { + *rsl_elem = seed_elem; + } + self.cnt = 0; + self.a = 0; + self.b = 0; + self.c = 0; + + self.init(true); + } + + /// Create an ISAAC random number generator with a seed. This can + /// be any length, although the maximum number of elements used is + /// 256 and any more will be silently ignored. A generator + /// constructed with a given seed will generate the same sequence + /// of values as all other generators constructed with that seed. + fn from_seed(seed: &'self [u64]) -> Isaac64Rng { + let mut rng = Isaac64Rng { + cnt: 0, + rsl: [0, .. RAND_SIZE_64], + mem: [0, .. RAND_SIZE_64], + a: 0, b: 0, c: 0, + }; + rng.reseed(seed); + rng + } +} + #[cfg(test)] mod test { use super::*; - use rand::{Rng, seed}; - use option::{Option, Some}; + use rand::{Rng, SeedableRng, seed}; + use option::Some; + use iter::range; + use vec; #[test] fn test_rng_seeded() { - let seed = seed(1024); - let mut ra = IsaacRng::new_seeded(seed); - let mut rb = IsaacRng::new_seeded(seed); + let s = unsafe {seed::(256)}; + let mut ra: IsaacRng = SeedableRng::from_seed(s.as_slice()); + let mut rb: IsaacRng = SeedableRng::from_seed(s.as_slice()); assert_eq!(ra.gen_ascii_str(100u), rb.gen_ascii_str(100u)); - let seed = seed(2048); - let mut ra = Isaac64Rng::new_seeded(seed); - let mut rb = Isaac64Rng::new_seeded(seed); + let s = unsafe {seed::(256)}; + let mut ra: Isaac64Rng = SeedableRng::from_seed(s.as_slice()); + let mut rb: Isaac64Rng = SeedableRng::from_seed(s.as_slice()); assert_eq!(ra.gen_ascii_str(100u), rb.gen_ascii_str(100u)); } @@ -401,29 +424,59 @@ mod test { fn test_rng_seeded_custom_seed() { // much shorter than generated seeds which are 1024 & 2048 // bytes resp. - let seed = [2u8, 32u8, 4u8, 32u8, 51u8]; - let mut ra = IsaacRng::new_seeded(seed); - let mut rb = IsaacRng::new_seeded(seed); + let seed = &[2, 32, 4, 32, 51]; + let mut ra: IsaacRng = SeedableRng::from_seed(seed); + let mut rb: IsaacRng = SeedableRng::from_seed(seed); assert_eq!(ra.gen_ascii_str(100u), rb.gen_ascii_str(100u)); - let mut ra = Isaac64Rng::new_seeded(seed); - let mut rb = Isaac64Rng::new_seeded(seed); + let seed = &[2, 32, 4, 32, 51]; + let mut ra: Isaac64Rng = SeedableRng::from_seed(seed); + let mut rb: Isaac64Rng = SeedableRng::from_seed(seed); assert_eq!(ra.gen_ascii_str(100u), rb.gen_ascii_str(100u)); } #[test] - fn test_rng_seeded_custom_seed2() { - let seed = [2u8, 32u8, 4u8, 32u8, 51u8]; - let mut ra = IsaacRng::new_seeded(seed); + fn test_rng_32_true_values() { + let seed = &[2, 32, 4, 32, 51]; + let mut ra: IsaacRng = SeedableRng::from_seed(seed); // Regression test that isaac is actually using the above vector - let r = ra.next_u32(); - error2!("{:?}", r); - assert_eq!(r, 2935188040u32); + let v = vec::from_fn(10, |_| ra.next_u32()); + assert_eq!(v, + ~[447462228, 2081944040, 3163797308, 2379916134, 2377489184, + 1132373754, 536342443, 2995223415, 1265094839, 345325140]); - let mut ra = Isaac64Rng::new_seeded(seed); + let seed = &[500, -4000, 123456, 9876543, 1, 1, 1, 1, 1]; + let mut rb: IsaacRng = SeedableRng::from_seed(seed); + // skip forward to the 10000th number + for _ in range(0, 10000) { rb.next_u32(); } + + let v = vec::from_fn(10, |_| rb.next_u32()); + assert_eq!(v, + ~[612373032, 292987903, 1819311337, 3141271980, 422447569, + 310096395, 1083172510, 867909094, 2478664230, 2073577855]); + } + #[test] + fn test_rng_64_true_values() { + let seed = &[2, 32, 4, 32, 51]; + let mut ra: Isaac64Rng = SeedableRng::from_seed(seed); // Regression test that isaac is actually using the above vector - let r = ra.next_u64(); - error2!("{:?}", r); - assert!(r == 0 && r == 1); // FIXME: find true value + let v = vec::from_fn(10, |_| ra.next_u64()); + assert_eq!(v, + ~[15015576812873463115, 12461067598045625862, 14818626436142668771, + 5562406406765984441, 11813289907965514161, 13443797187798420053, + 6935026941854944442, 7750800609318664042, 14428747036317928637, + 14028894460301215947]); + + let seed = &[500, -4000, 123456, 9876543, 1, 1, 1, 1, 1]; + let mut rb: Isaac64Rng = SeedableRng::from_seed(seed); + // skip forward to the 10000th number + for _ in range(0, 10000) { rb.next_u64(); } + + let v = vec::from_fn(10, |_| rb.next_u64()); + assert_eq!(v, + ~[13557216323596688637, 17060829581390442094, 4927582063811333743, + 2699639759356482270, 4819341314392384881, 6047100822963614452, + 11086255989965979163, 11901890363215659856, 5370800226050011580, + 16496463556025356451]); } } diff --git a/src/libstd/rand/mod.rs b/src/libstd/rand/mod.rs index 9fb6863692b..64f266d0045 100644 --- a/src/libstd/rand/mod.rs +++ b/src/libstd/rand/mod.rs @@ -638,6 +638,42 @@ pub trait Rng { } } +/// A random number generator that can be explicitly seeded to produce +/// the same stream of randomness multiple times. +pub trait SeedableRng: Rng { + /// Reseed an RNG with the given seed. + /// + /// # Example + /// + /// ```rust + /// use std::rand; + /// use std::rand::Rng; + /// + /// fn main() { + /// let mut rng: rand::XorShiftRng = rand::SeedableRng::from_seed(&[1, 2, 3, 4]); + /// println!("{}", rng.gen::()); + /// rng.reseed([5, 6, 7, 8]); + /// println!("{}", rng.gen::()); + /// } + /// ``` + fn reseed(&mut self, Seed); + + /// Create a new RNG with the given seed. + /// + /// # Example + /// + /// ```rust + /// use std::rand; + /// use std::rand::Rng; + /// + /// fn main() { + /// let mut rng: rand::XorShiftRng = rand::SeedableRng::from_seed(&[1, 2, 3, 4]); + /// println!("{}", rng.gen::()); + /// } + /// ``` + fn from_seed(seed: Seed) -> Self; +} + /// Create a random number generator with a default algorithm and seed. /// /// It returns the cryptographically-safest `Rng` algorithm currently @@ -686,6 +722,18 @@ impl Rng for StdRng { } } +impl<'self> SeedableRng<&'self [uint]> for StdRng { + fn reseed(&mut self, seed: &'self [uint]) { + // the internal RNG can just be seeded from the above + // randomness. + self.rng.reseed(unsafe {cast::transmute(seed)}) + } + + fn from_seed(seed: &'self [uint]) -> StdRng { + StdRng { rng: SeedableRng::from_seed(unsafe {cast::transmute(seed)}) } + } +} + /// Create a weak random number generator with a default algorithm and seed. /// /// It returns the fastest `Rng` algorithm currently available in Rust without @@ -723,11 +771,35 @@ impl Rng for XorShiftRng { } } +impl SeedableRng<[u32, .. 4]> for XorShiftRng { + /// Reseed an XorShiftRng. This will fail if `seed` is entirely 0. + fn reseed(&mut self, seed: [u32, .. 4]) { + assert!(!seed.iter().all(|&x| x == 0), + "XorShiftRng.reseed called with an all zero seed."); + + self.x = seed[0]; + self.y = seed[1]; + self.z = seed[2]; + self.w = seed[3]; + } + + /// Create a new XorShiftRng. This will fail if `seed` is entirely 0. + fn from_seed(seed: [u32, .. 4]) -> XorShiftRng { + assert!(!seed.iter().all(|&x| x == 0), + "XorShiftRng::from_seed called with an all zero seed."); + + XorShiftRng { + x: seed[0], + y: seed[1], + z: seed[2], + w: seed[3] + } + } +} + impl XorShiftRng { /// Create an xor shift random number generator with a random seed. pub fn new() -> XorShiftRng { - #[fixed_stack_segment]; #[inline(never)]; - // generate seeds the same way as seed(), except we have a // specific size, so we can just use a fixed buffer. let mut s = [0u8, ..16]; @@ -740,29 +812,21 @@ impl XorShiftRng { } } let s: &[u32, ..4] = unsafe { cast::transmute(&s) }; - XorShiftRng::new_seeded(s[0], s[1], s[2], s[3]) - } - - /** - * Create a random number generator using the specified seed. A generator - * constructed with a given seed will generate the same sequence of values - * as all other generators constructed with the same seed. - */ - pub fn new_seeded(x: u32, y: u32, z: u32, w: u32) -> XorShiftRng { - XorShiftRng { - x: x, - y: y, - z: z, - w: w, - } + SeedableRng::from_seed(*s) } } -/// Create a new random seed of length `n`. -pub fn seed(n: uint) -> ~[u8] { - let mut s = vec::from_elem(n as uint, 0_u8); +/// Create a new random seed of length `n`. This should only be used +/// to create types for which *any* bit pattern is valid. +pub unsafe fn seed(n: uint) -> ~[T] { + use unstable::intrinsics; + let mut s = vec::from_elem(n, intrinsics::init()); let mut r = OSRng::new(); - r.fill_bytes(s); + + { + let s_u8 = cast::transmute::<&mut [T], &mut [u8]>(s); + r.fill_bytes(s_u8); + } s } diff --git a/src/libstd/rand/reseeding.rs b/src/libstd/rand/reseeding.rs index d471a5e4e10..727efff0101 100644 --- a/src/libstd/rand/reseeding.rs +++ b/src/libstd/rand/reseeding.rs @@ -97,6 +97,8 @@ mod test { use super::*; use rand::Rng; use default::Default; + use iter::range; + use option::{None, Some}; struct Counter { i: u32 @@ -117,7 +119,7 @@ mod test { #[test] fn test_reseeding() { - let mut rs = ReseedingRng::from_options(Counter {i:0}, 100, ReseedWithDefault); + let mut rs = ReseedingRng::new(Counter {i:0}, 400, ReseedWithDefault); let mut i = 0; for _ in range(0, 1000) { diff --git a/src/libstd/rt/sched.rs b/src/libstd/rt/sched.rs index 004dab8d73a..c1ca484754d 100644 --- a/src/libstd/rt/sched.rs +++ b/src/libstd/rt/sched.rs @@ -26,7 +26,7 @@ use rt::local::Local; use rt::rtio::{RemoteCallback, PausibleIdleCallback}; use borrow::{to_uint}; use cell::Cell; -use rand::{XorShiftRng, Rng, Rand}; +use rand::{SeedableRng, XorShiftRng, Rng, Rand}; use iter::range; use vec::{OwnedVector}; @@ -895,7 +895,7 @@ fn new_sched_rng() -> XorShiftRng { // know that the only way that we can fail here is `abort`ing? unsafe {libc::fclose(file);} - XorShiftRng::new_seeded(seeds[0], seeds[1], seeds[2], seeds[3]) + SeedableRng::from_seed(seeds) } #[cfg(test)] diff --git a/src/test/bench/core-map.rs b/src/test/bench/core-map.rs index bec11ff3a7d..2d209e40e42 100644 --- a/src/test/bench/core-map.rs +++ b/src/test/bench/core-map.rs @@ -15,7 +15,7 @@ use extra::treemap::TreeMap; use std::hashmap::{HashMap, HashSet}; use std::io; use std::os; -use std::rand::Rng; +use std::rand::{Rng, IsaacRng, SeedableRng}; use std::trie::TrieMap; use std::uint; use std::vec; @@ -106,7 +106,7 @@ fn main() { let mut rand = vec::with_capacity(n_keys); { - let mut rng = std::rand::IsaacRng::new_seeded([1, 1, 1, 1, 1, 1, 1]); + let mut rng: IsaacRng = SeedableRng::from_seed(&[1, 1, 1, 1, 1, 1, 1]); let mut set = HashSet::new(); while set.len() != n_keys { let next = rng.gen(); diff --git a/src/test/bench/core-set.rs b/src/test/bench/core-set.rs index 36ebdc54922..b9a8e74668f 100644 --- a/src/test/bench/core-set.rs +++ b/src/test/bench/core-set.rs @@ -163,11 +163,11 @@ fn main() { } }; - let seed = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + let seed = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; let max = 200000; { - let mut rng = rand::IsaacRng::new_seeded(seed); + let mut rng: rand::IsaacRng = rand::SeedableRng::from_seed(seed); let mut results = empty_results(); results.bench_int(&mut rng, num_keys, max, || { let s: HashSet = HashSet::new(); @@ -181,7 +181,7 @@ fn main() { } { - let mut rng = rand::IsaacRng::new_seeded(seed); + let mut rng: rand::IsaacRng = rand::SeedableRng::from_seed(seed); let mut results = empty_results(); results.bench_int(&mut rng, num_keys, max, || { let s: TreeSet = TreeSet::new(); @@ -195,7 +195,7 @@ fn main() { } { - let mut rng = rand::IsaacRng::new_seeded(seed); + let mut rng: rand::IsaacRng = rand::SeedableRng::from_seed(seed); let mut results = empty_results(); results.bench_int(&mut rng, num_keys, max, || BitvSet::new()); write_results("extra::bitv::BitvSet", &results);