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

Implement various choose() methods #490

Closed
wants to merge 15 commits into from
Closed
54 changes: 0 additions & 54 deletions benches/misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ const RAND_BENCH_N: u64 = 1000;
use test::Bencher;

use rand::prelude::*;
use rand::seq::*;

#[bench]
fn misc_gen_bool_const(b: &mut Bencher) {
Expand Down Expand Up @@ -108,59 +107,6 @@ 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);

#[bench]
fn misc_shuffle_100(b: &mut Bencher) {
let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
let x : &mut [usize] = &mut [1; 100];
b.iter(|| {
rng.shuffle(x);
x[0]
})
}

#[bench]
fn misc_sample_iter_10_of_100(b: &mut Bencher) {
let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
let x : &[usize] = &[1; 100];
b.iter(|| {
sample_iter(&mut rng, x, 10).unwrap_or_else(|e| e)
})
}

#[bench]
fn misc_sample_slice_10_of_100(b: &mut Bencher) {
let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
let x : &[usize] = &[1; 100];
b.iter(|| {
sample_slice(&mut rng, x, 10)
})
}

#[bench]
fn misc_sample_slice_ref_10_of_100(b: &mut Bencher) {
let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
let x : &[usize] = &[1; 100];
b.iter(|| {
sample_slice_ref(&mut rng, x, 10)
})
}

macro_rules! sample_indices {
($name:ident, $amount:expr, $length:expr) => {
#[bench]
fn $name(b: &mut Bencher) {
let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
b.iter(|| {
sample_indices(&mut rng, $length, $amount)
})
}
}
}

sample_indices!(misc_sample_indices_10_of_1k, 10, 1000);
sample_indices!(misc_sample_indices_50_of_1k, 50, 1000);
sample_indices!(misc_sample_indices_100_of_1k, 100, 1000);

#[bench]
fn gen_1k_iter_repeat(b: &mut Bencher) {
use std::iter;
Expand Down
76 changes: 76 additions & 0 deletions benches/seq.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#![feature(test)]

extern crate test;
extern crate rand;

use test::Bencher;

use rand::prelude::*;
use rand::seq::*;

#[bench]
fn seq_shuffle_100(b: &mut Bencher) {
let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
let x : &mut [usize] = &mut [1; 100];
b.iter(|| {
x.shuffle(&mut rng);
x[0]
})
}

#[bench]
fn seq_slice_sample_10_of_100(b: &mut Bencher) {
let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
let x : &[usize] = &[1; 100];
let mut buf = [0; 10];
b.iter(|| {
for (v, slot) in x.sample(&mut rng, buf.len()).zip(buf.iter_mut()) {
*slot = *v;
}
buf
})
}

#[bench]
fn seq_iter_choose_from_100(b: &mut Bencher) {
let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
let x : &[usize] = &[1; 100];
b.iter(|| {
x.iter().cloned().choose(&mut rng)
})
}

#[bench]
fn seq_iter_sample_10_of_100(b: &mut Bencher) {
let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
let x : &[usize] = &[1; 100];
b.iter(|| {
x.iter().cloned().sample(&mut rng, 10) /*.unwrap_or_else(|e| e)*/
})
}

#[bench]
fn seq_iter_sample_fill_10_of_100(b: &mut Bencher) {
let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
let x : &[usize] = &[1; 100];
let mut buf = [0; 10];
b.iter(|| {
x.iter().cloned().sample_fill(&mut rng, &mut buf)
})
}

macro_rules! sample_indices {
($name:ident, $amount:expr, $length:expr) => {
#[bench]
fn $name(b: &mut Bencher) {
let mut rng = SmallRng::from_rng(thread_rng()).unwrap();
b.iter(|| {
sample_indices(&mut rng, $length, $amount)
})
}
}
}

sample_indices!(seq_sample_indices_10_of_1k, 10, 1000);
sample_indices!(seq_sample_indices_50_of_1k, 50, 1000);
sample_indices!(seq_sample_indices_100_of_1k, 100, 1000);
4 changes: 2 additions & 2 deletions examples/monty-hall.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ fn simulate<R: Rng>(random_door: &Uniform<u32>, rng: &mut R)
// Returns the door the game host opens given our choice and knowledge of
// where the car is. The game host will never open the door with the car.
fn game_host_open<R: Rng>(car: u32, choice: u32, rng: &mut R) -> u32 {
let choices = free_doors(&[car, choice]);
rand::seq::sample_slice(rng, &choices, 1)[0]
use rand::seq::SliceRandom;
*free_doors(&[car, choice]).choose(rng).unwrap()
}

// Returns the door we switch to, given our current choice and
Expand Down
104 changes: 19 additions & 85 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ pub mod distributions;
pub mod prelude;
pub mod prng;
pub mod rngs;
#[cfg(feature = "alloc")] pub mod seq;
pub mod seq;

////////////////////////////////////////////////////////////////////////////////
// Compatibility re-exports. Documentation is hidden; will be removed eventually.
Expand Down Expand Up @@ -563,64 +563,35 @@ pub trait Rng: RngCore {

/// Return a random element from `values`.
///
/// Return `None` if `values` is empty.
///
/// # Example
///
/// ```
/// use rand::{thread_rng, Rng};
///
/// let choices = [1, 2, 4, 8, 16, 32];
/// let mut rng = thread_rng();
/// println!("{:?}", rng.choose(&choices));
/// assert_eq!(rng.choose(&choices[..0]), None);
/// ```
/// Deprecated: use [`SliceRandom::choose`] instead.
///
/// [`SliceRandom::choose`]: seq/trait.SliceRandom.html#method.choose
#[deprecated(since="0.6.0", note="use SliceRandom::choose instead")]
fn choose<'a, T>(&mut self, values: &'a [T]) -> Option<&'a T> {
if values.is_empty() {
None
} else {
Some(&values[self.gen_range(0, values.len())])
}
use seq::SliceRandom;
values.choose(self)
}

/// Return a mutable pointer to a random element from `values`.
///
/// Return `None` if `values` is empty.
/// Deprecated: use [`SliceRandom::choose_mut`] instead.
///
/// [`SliceRandom::choose_mut`]: seq/trait.SliceRandom.html#method.choose_mut
#[deprecated(since="0.6.0", note="use SliceRandom::choose_mut instead")]
fn choose_mut<'a, T>(&mut self, values: &'a mut [T]) -> Option<&'a mut T> {
if values.is_empty() {
None
} else {
let len = values.len();
Some(&mut values[self.gen_range(0, len)])
}
use seq::SliceRandom;
values.choose_mut(self)
}

/// Shuffle a mutable slice in place.
///
/// This applies Durstenfeld's algorithm for the [Fisher–Yates shuffle](
/// https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_modern_algorithm)
/// which produces an unbiased permutation.
///
/// # Example
///
/// ```
/// use rand::{thread_rng, Rng};
///
/// let mut rng = thread_rng();
/// let mut y = [1, 2, 3];
/// rng.shuffle(&mut y);
/// println!("{:?}", y);
/// rng.shuffle(&mut y);
/// println!("{:?}", y);
/// ```
/// Deprecated: use [`SliceRandom::shuffle`] instead.
///
/// [`SliceRandom::shuffle`]: seq/trait.SliceRandom.html#method.shuffle
#[deprecated(since="0.6.0", note="use SliceRandom::shuffle instead")]
fn shuffle<T>(&mut self, values: &mut [T]) {
let mut i = values.len();
while i >= 2 {
// invariant: elements with index >= i have been locked in place.
i -= 1;
// lock element i in place.
values.swap(i, self.gen_range(0, i + 1));
}
use seq::SliceRandom;
values.shuffle(self)
}
}

Expand Down Expand Up @@ -973,46 +944,13 @@ mod test {
}
}

#[test]
fn test_choose() {
let mut r = rng(107);
assert_eq!(r.choose(&[1, 1, 1]).map(|&x|x), Some(1));

let v: &[isize] = &[];
assert_eq!(r.choose(v), None);
}

#[test]
fn test_shuffle() {
let mut r = rng(108);
let empty: &mut [isize] = &mut [];
r.shuffle(empty);
let mut one = [1];
r.shuffle(&mut one);
let b: &[_] = &[1];
assert_eq!(one, b);

let mut two = [1, 2];
r.shuffle(&mut two);
assert!(two == [1, 2] || two == [2, 1]);

let mut x = [1, 1, 1];
r.shuffle(&mut x);
let b: &[_] = &[1, 1, 1];
assert_eq!(x, b);
}

#[test]
fn test_rng_trait_object() {
use distributions::{Distribution, Standard};
let mut rng = rng(109);
let mut r = &mut rng as &mut RngCore;
r.next_u32();
r.gen::<i32>();
let mut v = [1, 1, 1];
r.shuffle(&mut v);
let b: &[_] = &[1, 1, 1];
assert_eq!(v, b);
assert_eq!(r.gen_range(0, 1), 0);
let _c: u8 = Standard.sample(&mut r);
}
Expand All @@ -1025,10 +963,6 @@ mod test {
let mut r = Box::new(rng) as Box<RngCore>;
r.next_u32();
r.gen::<i32>();
let mut v = [1, 1, 1];
r.shuffle(&mut v);
let b: &[_] = &[1, 1, 1];
assert_eq!(v, b);
assert_eq!(r.gen_range(0, 1), 0);
let _c: u8 = Standard.sample(&mut r);
}
Expand Down
1 change: 1 addition & 0 deletions src/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@
#[doc(no_inline)] #[cfg(feature="std")] pub use rngs::ThreadRng;
#[doc(no_inline)] pub use {Rng, RngCore, CryptoRng, SeedableRng};
#[doc(no_inline)] #[cfg(feature="std")] pub use {FromEntropy, random, thread_rng};
#[doc(no_inline)] pub use seq::{SliceRandom, IteratorRandom};
4 changes: 0 additions & 4 deletions src/rngs/thread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,10 +132,6 @@ mod test {
use Rng;
let mut r = ::thread_rng();
r.gen::<i32>();
let mut v = [1, 1, 1];
r.shuffle(&mut v);
let b: &[_] = &[1, 1, 1];
assert_eq!(v, b);
assert_eq!(r.gen_range(0, 1), 0);
}
}