Skip to content
Open
Show file tree
Hide file tree
Changes from 6 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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ A [separate changelog is kept for rand_core](rand_core/CHANGELOG.md).

You may also find the [Upgrade Guide](https://rust-random.github.io/book/update.html) useful.

## [Unreleased]
### Changes
- Rename fns `IndexedRandom::choose_multiple` -> `sample`, `choose_multiple_array` -> `sample_array`, `choose_multiple_weighted` -> `sample_weighted`, struct `SliceChooseIter` -> `IndexedSamples` and fns `IteratorRandom::choose_multiple` -> `sample`, `choose_multiple_fill` -> `sample_fill` (#1632)

### Additions
- Add fns `IndexedRandom::choose_iter`, `choose_weighted_iter` (#1632)

## [0.9.1] - 2025-04-17
### Security and unsafe
- Revise "not a crypto library" policy again (#1565)
Expand Down
16 changes: 8 additions & 8 deletions benches/benches/seq_choose.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ pub fn bench(c: &mut Criterion) {

let lens = [(1, 1000), (950, 1000), (10, 100), (90, 100)];
for (amount, len) in lens {
let name = format!("seq_slice_choose_multiple_{}_of_{}", amount, len);
let name = format!("seq_slice_sample_{}_of_{}", amount, len);
c.bench_function(name.as_str(), |b| {
let mut rng = Pcg32::from_rng(&mut rand::rng());
let mut buf = [0i32; 1000];
Expand All @@ -44,7 +44,7 @@ pub fn bench(c: &mut Criterion) {
b.iter(|| {
// Collect full result to prevent unwanted shortcuts getting
// first element (in case sample_indices returns an iterator).
for (slot, sample) in y.iter_mut().zip(x.choose_multiple(&mut rng, amount)) {
for (slot, sample) in y.iter_mut().zip(x.sample(&mut rng, amount)) {
*slot = *sample;
}
y[amount - 1]
Expand All @@ -54,7 +54,7 @@ pub fn bench(c: &mut Criterion) {

let lens = [(1, 1000), (950, 1000), (10, 100), (90, 100)];
for (amount, len) in lens {
let name = format!("seq_slice_choose_multiple_weighted_{}_of_{}", amount, len);
let name = format!("seq_slice_sample_weighted_{}_of_{}", amount, len);
c.bench_function(name.as_str(), |b| {
let mut rng = Pcg32::from_rng(&mut rand::rng());
let mut buf = [0i32; 1000];
Expand All @@ -68,7 +68,7 @@ pub fn bench(c: &mut Criterion) {
b.iter(|| {
// Collect full result to prevent unwanted shortcuts getting
// first element (in case sample_indices returns an iterator).
let samples_iter = x.choose_multiple_weighted(&mut rng, amount, |_| 1.0).unwrap();
let samples_iter = x.sample_weighted(&mut rng, amount, |_| 1.0).unwrap();
for (slot, sample) in y.iter_mut().zip(samples_iter) {
*slot = *sample;
}
Expand All @@ -77,21 +77,21 @@ pub fn bench(c: &mut Criterion) {
});
}

c.bench_function("seq_iter_choose_multiple_10_of_100", |b| {
c.bench_function("seq_iter_sample_10_of_100", |b| {
let mut rng = Pcg32::from_rng(&mut rand::rng());
let mut buf = [0i32; 100];
rng.fill(&mut buf);
let x = black_box(&buf);
b.iter(|| x.iter().cloned().choose_multiple(&mut rng, 10))
b.iter(|| x.iter().cloned().sample(&mut rng, 10))
});

c.bench_function("seq_iter_choose_multiple_fill_10_of_100", |b| {
c.bench_function("seq_iter_sample_fill_10_of_100", |b| {
let mut rng = Pcg32::from_rng(&mut rand::rng());
let mut buf = [0i32; 100];
rng.fill(&mut buf);
let x = black_box(&buf);
let mut buf = [0; 10];
b.iter(|| x.iter().cloned().choose_multiple_fill(&mut rng, &mut buf))
b.iter(|| x.iter().cloned().sample_fill(&mut rng, &mut buf))
});

bench_rng::<rand_chacha::ChaCha20Rng>(c, "ChaCha20");
Expand Down
42 changes: 29 additions & 13 deletions src/seq/iterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,8 +195,8 @@ pub trait IteratorRandom: Iterator + Sized {
/// case this equals the number of elements available.
///
/// Complexity is `O(n)` where `n` is the length of the iterator.
/// For slices, prefer [`IndexedRandom::choose_multiple`].
fn choose_multiple_fill<R>(mut self, rng: &mut R, buf: &mut [Self::Item]) -> usize
/// For slices, prefer [`IndexedRandom::sample`].
fn sample_fill<R>(mut self, rng: &mut R, buf: &mut [Self::Item]) -> usize
where
R: Rng + ?Sized,
{
Expand Down Expand Up @@ -224,7 +224,7 @@ pub trait IteratorRandom: Iterator + Sized {

/// Uniformly sample `amount` distinct elements into a [`Vec`]
///
/// This is equivalent to `choose_multiple_fill` except for the result type.
/// This is equivalent to `sample_fill` except for the result type.
///
/// Although the elements are selected randomly, the order of elements in
/// the buffer is neither stable nor fully random. If random ordering is
Expand All @@ -235,9 +235,9 @@ pub trait IteratorRandom: Iterator + Sized {
/// elements available.
///
/// Complexity is `O(n)` where `n` is the length of the iterator.
/// For slices, prefer [`IndexedRandom::choose_multiple`].
/// For slices, prefer [`IndexedRandom::sample`].
#[cfg(feature = "alloc")]
fn choose_multiple<R>(mut self, rng: &mut R, amount: usize) -> Vec<Self::Item>
fn sample<R>(mut self, rng: &mut R, amount: usize) -> Vec<Self::Item>
where
R: Rng + ?Sized,
{
Expand All @@ -262,6 +262,25 @@ pub trait IteratorRandom: Iterator + Sized {
}
reservoir
}

/// Deprecated: use [`Self::sample_fill`] instead
#[deprecated(since = "0.9.2", note = "Renamed to `sample_fill`")]
fn choose_multiple_fill<R>(self, rng: &mut R, buf: &mut [Self::Item]) -> usize
where
R: Rng + ?Sized,
{
self.sample_fill(rng, buf)
}

/// Deprecated: use [`Self::sample`] instead
#[cfg(feature = "alloc")]
#[deprecated(since = "0.9.2", note = "Renamed to `sample`")]
fn choose_multiple<R>(self, rng: &mut R, amount: usize) -> Vec<Self::Item>
where
R: Rng + ?Sized,
{
self.sample(rng, amount)
}
}

impl<I> IteratorRandom for I where I: Iterator + Sized {}
Expand Down Expand Up @@ -538,8 +557,8 @@ mod test {

let mut r = crate::test::rng(401);
let vals = (min_val..max_val).collect::<Vec<i32>>();
let small_sample = vals.iter().choose_multiple(&mut r, 5);
let large_sample = vals.iter().choose_multiple(&mut r, vals.len() + 5);
let small_sample = vals.iter().sample(&mut r, 5);
let large_sample = vals.iter().sample(&mut r, vals.len() + 5);

assert_eq!(small_sample.len(), 5);
assert_eq!(large_sample.len(), vals.len());
Expand Down Expand Up @@ -644,20 +663,17 @@ mod test {
}

#[test]
fn value_stability_choose_multiple() {
fn value_stability_sample() {
fn do_test<I: Clone + Iterator<Item = u32>>(iter: I, v: &[u32]) {
let mut rng = crate::test::rng(412);
let mut buf = [0u32; 8];
assert_eq!(
iter.clone().choose_multiple_fill(&mut rng, &mut buf),
v.len()
);
assert_eq!(iter.clone().sample_fill(&mut rng, &mut buf), v.len());
assert_eq!(&buf[0..v.len()], v);

#[cfg(feature = "alloc")]
{
let mut rng = crate::test::rng(412);
assert_eq!(iter.choose_multiple(&mut rng, v.len()), v);
assert_eq!(iter.sample(&mut rng, v.len()), v);
}
}

Expand Down
3 changes: 3 additions & 0 deletions src/seq/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ mod index_;
pub use crate::distr::weighted::Error as WeightError;
pub use iterator::IteratorRandom;
#[cfg(feature = "alloc")]
pub use slice::IndexedSamples;
#[allow(deprecated)]
#[cfg(feature = "alloc")]
pub use slice::SliceChooseIter;
pub use slice::{IndexedMutRandom, IndexedRandom, SliceRandom};

Expand Down
Loading