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

gen_iter() for distributions? #58

Closed
JP-Ellis opened this issue Jul 14, 2015 · 9 comments
Closed

gen_iter() for distributions? #58

JP-Ellis opened this issue Jul 14, 2015 · 9 comments
Labels
E-easy Participation: easy job F-new-int Functionality: new, within Rand

Comments

@JP-Ellis
Copy link

The Rng trait has the gen_iter() function which creates an iterator producing an infinite numbers of random numbers. It is then easy to manipulate the the iterator and generate vectors of random numbers.

Is there a reason why the various distributions do not implement this? In my particular case, I am needing to create vectors of numbers distributed normally and there is no easy way of doing that. One can't use vec![normal.ind_sample(rng); len]; because it evaluates the function once and then clones the result.

I am quite happy to implement this in this crate (if people are interested). I was thinking of maybe adding gen_iter<R: Rng>(&mut self, rng: &mut R) and gen_ind_iter<R: Rng>(&mut self, rng: &mut R) under Sample and IndependentSample respectively.

@shepmaster
Copy link
Contributor

In my case, I'd like to have Rng::gen_range_iter. A quick substitute for this is:

(0..).map(|_| rng.gen_range(low, high))...;

@JP-Ellis
Copy link
Author

What you're asking would be encompassed by my feature request. You could have a uniform distribution with the specified minimum and maximum value, and then run gen_iter() on it.

@shepmaster
Copy link
Contributor

would be encompassed by my feature request

Oh, certainly. I was just dropping that little snippet as a way for future people to get something today, but also adding an implicit +1.

@alexcrichton alexcrichton added the F-new-int Functionality: new, within Rand label Jun 14, 2017
@dhardy
Copy link
Member

dhardy commented Mar 4, 2018

Please see #275 which I think implements what was asked here. As pointed out it's not really necessary so we need to decide what to do here.

@pitdicker
Copy link
Contributor

Rng::gen_iter was deprecated with #286.
The reason is that rng.iter().map(|rng| rng.gen()) is a nice alternative. This method can also be used with distributions.

But @burdges came up with a method that me be useful:

You could always add some convenience method in the future, so roughly like:

pub trait Rng: RngCore + Sized {
   ...
   fn samples_iter<T,D: Distribution<T>>(&mut self,dist: D) -> impl Iterator<item=T> {
       ::std::iter::repeat(()).map(|()| self.sample(&dist))
   }

I wrote &dist to avoid D: Copy or whatever. I'd imagine multiple reference layers get optimized into one reference, but not sure.

@dhardy dhardy added X-enhancement E-easy Participation: easy job labels Mar 19, 2018
@pitdicker
Copy link
Contributor

Would adding an iterator method to the distribution trait like this have disadvantages?

pub trait Distribution<T> {
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> T;

    fn iter<'r, R: Rng>(self, rng: &'r mut R) -> DistIter<'r, Self, R, T>
        where Self: Sized
    {
        DistIter {
            distr: self,
            rng: rng,
            phantom: ::core::marker::PhantomData,
        }
    }
}

#[derive(Debug)]
pub struct DistIter<'a, D, R, T> where D: Distribution<T>, R: Rng + 'a {
    distr: D,
    rng: &'a mut R,
    phantom: ::core::marker::PhantomData<T>,
}

impl<'a, D, R, T> Iterator for DistIter<'a, D, R, T>
    where D: Distribution<T>, R: Rng + 'a
{
    type Item = T;

    fn next(&mut self) -> Option<T> {
        Some(self.rng.sample(&self.distr))
    }
}

It can be used like this:

use distributions::Normal;
let mut rng = thread_rng();
let distr = Normal::new(10.0, 10.0);
let results: Vec<_> = distr.iter(&mut rng).take(100).collect();

@dhardy
Copy link
Member

dhardy commented Mar 31, 2018

Sounds good, but we probably don't want both rng.sample_iter(distr) and distr.iter(rng). Which is nicer to use?

@pitdicker
Copy link
Contributor

I don't think there is a real difference, as both need the same arguments and both would produce the same sort of iterator.

@pitdicker
Copy link
Contributor

Now available as Rng::sample_iter(&distribution) and Distributions::sample_iter(&mut rng).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
E-easy Participation: easy job F-new-int Functionality: new, within Rand
Projects
None yet
Development

No branches or pull requests

5 participants