-
Notifications
You must be signed in to change notification settings - Fork 414
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
UPDATED: Multinomial distribution rand does not support Float32 probability vectors #1738
Conversation
Codecov ReportPatch coverage:
Additional details and impacted files@@ Coverage Diff @@
## master #1738 +/- ##
==========================================
- Coverage 85.91% 85.80% -0.12%
==========================================
Files 142 142
Lines 8568 8579 +11
==========================================
Hits 7361 7361
- Misses 1207 1218 +11
☔ View full report in Codecov by Sentry. |
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.
Thank you for the PR! I think it looks quite good but could be improved a bit. I made some comments below 🙂
@@ -1,4 +1,4 @@ | |||
function multinom_rand!(rng::AbstractRNG, n::Int, p::AbstractVector{Float64}, | |||
function multinom_rand!(rng::AbstractRNG, n::Int, p::AbstractVector{<:Real}, |
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.
AFAICT one has to update the body of the function as well to avoid type stability issues.
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.
More concretely, it must not contain any Float64 literals.
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.
Isn't is true that the output type of the function can only be x::AbstractVector{eltype(x)}
?
I'm adding the type stability tests and it looks ok but I wanted to make sure since I'm pretty new to Julia.
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.
There are internal type instabilities which can cause slow downs.
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.
For instance, rp
might change its type inside of the loop.
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.
I took care of this aspect.
While doing so I noticed that Binomial is restricted to using Float64, so it may be slower/more accurate than necessary.
This also would affect Multinomial.
This is not needed for me, but it can be a good addition in future.
test/multivariate/multinomial.jl
Outdated
@@ -1,6 +1,6 @@ | |||
# Tests for Multinomial | |||
|
|||
using Distributions, Random, StaticArrays | |||
using Distributions, Random, StaticArrays, ForwardDiff |
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.
Not needed for the changes below it seems:
using Distributions, Random, StaticArrays, ForwardDiff | |
using Distributions, Random, StaticArrays |
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.
I'll remove it happily, as I don't personally think it really belongs here.
But at least for completeness sake, here is the source of this addition:
#1033 (comment)
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.
It seems it was added because someone wanted dual numbers to be tested as well - but later it was figured out that for other reasons even with the changes in the PR they don't work and the tests were removed again.
So it seems fine to remove this import.
test/multivariate/multinomial.jl
Outdated
@test (rand(Multinomial(10, p)); true) | ||
@test (rand(Multinomial(10, convert.(Float32, p))); true) |
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.
Can we use better tests that test correctness instead of only "not erroring"? For instance by looping over Float64
and Float32
probabilities in the tests above?
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.
I'm not sure I follow.
What kind of correctness do you mean?
As for type stability, I'm looking at adding some @inferred
tests here for that.
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.
That the samples follow the desired distribution - basically, the same tests as for Float64.
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.
I'd prefer running the existing tests with Float32 as well over a few additional tests.
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.
took care of this ✔️
src/samplers/multinomial.jl
Outdated
i = 0 | ||
km1 = k - 1 | ||
|
||
while i < km1 && n > 0 | ||
i += 1 | ||
@inbounds pi = p[i] | ||
if pi < rp | ||
xi = rand(rng, Binomial(n, pi / rp)) | ||
xi = Tx(rand(rng, Binomial(n, Float64(pi / rp)))) |
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 is not needed, updating x[i]
in the line below will convert to the correct type anyway; additionally, the constructor of Binomial
(should) take care of promotions/conversions (and we just continue with using the type of p
/rp
):
xi = Tx(rand(rng, Binomial(n, Float64(pi / rp)))) | |
xi = rand(rng, Binomial(n, pi / rp)) |
@devmotion
Or the equivalent message using That was the reason I made the type conversion in As to preferring the implicit over explicit type conversions, I was thinking it would improve performance (saving the type check at run time) but I can also see the point of not using hard coded types when possible. The only objection I guess would be that in 32bit systems the user would not use Float64 to begin with, so that's not a real issue right? |
Type conversions implicitly at runtime covers more systems better Co-authored-by: David Widmann <devmotion@users.noreply.github.com>
@devmotion |
I'll have another look at the PR tomorrow 🙂 |
I tried to simplify the tests a bit (e.g., replaced hard-coded |
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.
Looks good to me, thank you!
I don't know if I'm wrong about this, but shouldn't the For example, if I do
I get a
I get a
I get an error
|
No, that would seem very surprising and unintended to me. Typically, This also explains the error you see: The constructor is only defined for |
I see; thank you very much for the clarification. I need to understand the differences better. Naively, I thought that working with 32-bit numbers would speed up my computations when doing something such as with |
Yes, probably you'll get a speedup from using |
See issue #1032
This is virtually a copy of #1033
I forked the code from @darsnack 's repositoty and rebased to master, and ran the tests.
Fixes #1032. Fixes #1733. Closes #1033.