-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
add rand dispatch for tuple types #50251
Conversation
I doubt those build failures are related to this change |
I'm not a fan of using broadcast for the implementation. Performance-wise, we should try to not be too far-off from RandomExtensions.jl:
|
ok, should match performance now (at least locally for me) |
g2g? is this functionality desired |
given that this won't be in 1.10 either way and can sit on master for a while, I added in support also for sampling from |
marking for triage as suggested here, both PR could probably be triaged at the same time |
I'm in favor of merging this PR as is, although there is room for optimization for some niche cases. Essentially, this implementation doesn't use the 2-staged random generation, i.e. the fact that in a call to struct ZZ{N}
x::Char
end
function Random.Sampler(::Type{RNG}, ::Type{ZZ{N}}, nn::Random.Repetition) where {N, RNG<:AbstractRNG}
Random.SamplerSimple(ZZ{N}('a'), Random.Sampler(RNG, String(N), nn))
# note: passing `ZZ{N}('a')` is somewhat artificial here, using SamplerTag would be better but i believe it's undocumented
end
Random.rand(rng::AbstractRNG, sp::Random.SamplerSimple{ZZ{N}}) where {N} = ZZ{N}(rand(rng, sp.data)) Then creating an array of such values wrapped in a tuple has significant overhead compared to raw values, unlike the no-overhead approach of RandomExtensions: julia> @btime rand(ZZ{:asd}, 1000);
2.712 μs (3 allocations: 4.16 KiB)
julia> @btime rand(Tuple{ZZ{:asd}}, 1000); # This PR
17.623 μs (1001 allocations: 27.50 KiB)
julia> @btime rand(Tuple{ZZ{:asd}}, 1000); # Using instead `RandomExtensions`
2.678 μs (3 allocations: 4.16 KiB) But I think this optimization can be added later if anyone finds the motivation. |
Triage agrees with adding this 👍 The docs should also clarify what is supported, i.e. basically only concrete tuple types? Or maybe say fixed-length tuples of sample-able types? |
The possibility of |
thank you for the comments. I am happy to give it a shot to get the performance of long arrays of custom struct types performant compared to also, I did not know |
Nope! Types and You can also do silly things like |
please let me know if the latest revision addresses all comments. the benchmarks I see are now
so still slightly worse on the very wide tuple case, but I'm not sure how to avoid that without more involved changes. I believe this would be a pretty rare use case either way---the extra allocations occur past length On reflection, I believe |
58c160e
to
9e58e6e
Compare
@rfourquet could you possibly review the latest updates? |
I think it would be fair to merge this so that things move forward, but it's up to triage... If this version is merged, I will have to update RandomExtensions before the 1.11 release, and in the process I will probably be able to extract from it a reasonable (not too complex) implementation which could supersede this PR; then I hope there won't be much opposition to such an update. An alternative would be for you or me to directly pull RandomExtensions's implementation. |
do note that since this was last evaluated on triage, the update has now matched performance with given that this is kind of a more fundamental limitation to the performance of |
Does this support |
intentionally not supported to both. I'll go ahead and add tests and make the docs more clear on that |
ef15e41
to
9702348
Compare
green! |
9499d39
to
e89dd56
Compare
EDIT: this was also implemented in #50251, which is now merged, so merge this now for the added tests, and the added feature of `rand(Tuple{})`. This allows e.g `rand(NTuple{5,Int})` to sample a tuple of 5 `Int`s. The implementation simply assembles a tuple by calling `rand` on the corresponding type parameters of the tuple type. A generated function is used to ensure type stability.
as suggested by #50236 @rfourquet