std::rand: Add a trait for seeding RNGs: SeedableRng.

This provides 2 methods: .reseed() and ::from_seed that modify and
create respecitively.

Implement this trait for the RNGs in the stdlib for which this makes
sense.
This commit is contained in:
Huon Wilson 2013-09-30 01:29:28 +10:00
parent 0223cf65e4
commit 92725ae765
8 changed files with 231 additions and 112 deletions

View File

@ -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]

View File

@ -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 {

View File

@ -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::<u32>(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::<u64>(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::<u32>(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::<u64>(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]);
}
}

View File

@ -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<Seed>: 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::<f64>());
/// rng.reseed([5, 6, 7, 8]);
/// println!("{}", rng.gen::<f64>());
/// }
/// ```
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::<f64>());
/// }
/// ```
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<T: Clone>(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
}

View File

@ -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) {

View File

@ -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)]

View File

@ -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();

View File

@ -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<uint> = 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<uint> = 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);