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