-
Notifications
You must be signed in to change notification settings - Fork 432
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
Replace the Sample
and IndependentSample
traits with Distribution
.
#27
Replace the Sample
and IndependentSample
traits with Distribution
.
#27
Conversation
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @huonw (or someone else) soon. If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. The way Github handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes. Please see CONTRIBUTING.md for more information. |
Thanks for the pull request! I'm definitely unhappy with the design of I'll sleep on it. |
I figure we have two things here: "random distributions", which is what was called All of these generate a stream of values, and could be replaced with the An alternative approach would be to implement a method for random distributions / processes that consumes an How about: trait RandomProcess<Support> {
type ProcessIterator : Iterator<Item=Support>;
fn iter<R: Rng>(&self, rng: R) -> ProcessIterator;
} or perhaps we should be adding a new method on trait Rng {
fn gen_distribution_iter<'a, D, T>(&'a mut self, distribution: &'a D) -> Iterator<Item=T>
where D: RandomDistribution<T> { ... }
fn gen_process_iter<'a, P, T>(&'a mut self, process: &'a mut P) -> Iterator<Item=T>
where P: RandomProcess<T> { ... }
} We could then provide a blanket impl for |
106ad0e
to
d1b3a18
Compare
I've just pushed a bunch of commits for feedback. I need to update the documentation, but let me know if you're OK with this approach. I've replaced I've added I can't implement |
d1b3a18
to
38259ee
Compare
Sample
trait with IndependentSample
.Sample
and IndependentSample
traits with Distribution
.
I've just a change to make |
type Output = T; | ||
|
||
fn sample<R: Rng>(&self, _: &mut R) -> T { | ||
let ConstantDistribution(ref value) = *self; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be self.0.clone()
: the fields of tuple structs (and tuples) can be accessed positionally.
I like the changes (and agree wrt to the distinction between distributions and processes). There's one slight sticking point, though. We're planning to pull parts of I'm very interested to hear whatever thoughts you have though (even if you can't make complete sense of the links above, since it was written as part of an ongoing discussion). |
Unfortunately, I'm not going to be able to do this tonight: still working on a more detail sketch of the proposal in @aturon's gist. |
(Oh, I forgot to link to https://gist.github.com/huonw/98252a92111c27d7e3e2 also.) |
Thanks for the feedback, I have to head off to work, I'll try to take a look at this this evening. |
baea54a
to
c73ab02
Compare
I've pushed an updated which removes the changes to I still haven't had a chance to read through the design for |
I'm not sure the best place to comment on your proposals, but how about this: /// Type that can be used to create a random instance of `Output`.
///
/// Since no state is recorded, each sample is (statistically)
/// independent of all others, assuming the `Rng` used has this
/// property.
pub trait Distribution {
type Output;
/// Generate a random value of `Output`, using `rng` as the
/// source of randomness.
fn sample<R: Rng>(&self, rng: &mut R) -> <Self as Distribution>::Output;
}
/// This, together with `NewRandom` below is the replacement trait for `Rand`. Instead of having `Rand::rand(&mut rng) -> T`, you now call
/// `T::default_distribution().sample(&mut rng)`. This can be simplified to `NewRandom::rand(&mut rng) -> T`.
pub trait DefaultDistribution {
type OutputDistribution: Distribution<Output=Self>;
fn default_distribution() -> <Self as DefaultDistribution>::OutputDistribution;
}
pub trait NewRandom {
fn rand<R: Rng>(rng: &mut R) -> Self;
}
impl <T> NewRandom for T where T: DefaultDistribution
{
fn rand<R: Rng>(rng: &mut R) -> Self {
T::default_distribution().sample(rng)
}
}
/// An example implementation of DefaultDistribution that uses the existing `Rand` trait via the `RandDistribution` struct.
impl <T: Rand> DefaultDistribution for T {
type OutputDistribution = RandDistribution<T>;
fn default_distribution() -> RandDistribution<T> {
RandDistribution::new()
}
} This allows you to precompute constants for generating values in a range, by just having the existing trait Rng {
fn gen<D: Distribution>(&mut self, distribution: &D) -> <D as Distribution>::Output;
fn gen_iter<D: Distribution>(&mut self, distribution: &D) -> GenIter<'a, Self, D>;
} If you want to be able to call The advantage of explicitly generating |
(Ping @huonw) |
c73ab02
to
6a6be06
Compare
@GrahamDennis interestingly, I think that is quite similar to @aturon's stream proposal (https://gist.github.com/aturon/d53613d1c0cce1297bf1). I also think some of the differences are valuable improvements (particularly using an associated type for Thanks for taking the time to take a look! (It's late here, so I'll take a (hopefully) final look at this particular patch tomorrow.) |
6a6be06
to
b892802
Compare
Ping @huonw! I've rebased my work on the latest master. I'm also keen to be involved in the redesign of You can see a basic implementation of what I'm thinking of here: GrahamDennis/rand@master...GrahamDennis:feature/random-experiment It lets you do |
b892802
to
7336ee7
Compare
Also removed the `Sample` trait. `IndependentSample` is really a probability distribution of values, and hence renamed to `Distribution`, but with an associated `Output` type instead of being generic over a type. The `Sample` trait is a state-mutating version of `IndependentSample` and is really a random process. A random process can be infinite (e.g. a random walk) or finite (e.g. drawing from a bag without replacement). So really, a random process is best represented by an `Iterator`. Additionally all previous implementations of `Sample` simply called through to `IndependentSample.ind_sample`, so `Sample` has simply been removed. The related trait `SampleRange` has been renamed to `RangeDistribution`.
7336ee7
to
e6e78bd
Compare
@huonw @alexcrichton what's the story on this? Random numbers are quite an important library feature, and this issue has gone two years without comment. I would be happy to help on this, but it looks like @GrahamDennis has already proposed several good changes. Specifically, I agree with Graham that random walks and the tetris sampler are not distributions, thus there is no real need for a mutating sampler. (A random walk at its simplest is adding an independent sample to a position variable, with variations such as Lévy flight; the tetris sampler is really just randomly sorting a list, popping elements, then repeating. I don't see why such things deserve an implementation here.) I'm not sure whether pulling RNGs into |
Closing in favour of #256. |
This is heavily inspired by #27 by @GrahamDennis but simpler trait and maintains backwards compatibility with deprecations.
This is heavily inspired by #27 by @GrahamDennis but simpler trait and maintains backwards compatibility with deprecations.
The
Sample
trait was always being implemented by calling through toIndependentSample.ind_sample
, so no replacement for the state-mutating trait (formerly known asSample
) has been provided.The only situation I can imagine needing a state-mutating trait like the old
Sample
is if you are simulating drawing objects from a bag without replacement.This is a breaking change for users of this library.