Repository navigation
Restrict non-differentiable rand rules to data-free and integer samplers - #855
Merged
Merged
Conversation
`@non_differentiable rand(::AbstractRNG, ::Random.Sampler)` matched every sampler, including the ones that sample from arrays, tuples, non-integer ranges and dictionaries. Zygote therefore silently returned `nothing` for e.g. `gradient(x -> rand([x]), 1.0)` instead of 1.0. The rule now only covers samplers whose output does not depend on any differentiable data (types, float intervals, BigFloat, Base strings and Char arrays) and samplers for ranges of Base integer types, for both `rand` and `rand!`. The latter fixes #854 without reintroducing the over-wide `rand!` rules removed in #604. The forwarding rules for `rand`/`rand!` and `Random.randexp(::AbstractRNG)` are removed: they are reached via the sampler rules or subsumed by `randexp(::Any...)`. `randstring` is extended to all argument types since its output is always a `String`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #855 +/- ##
==========================================
- Coverage 96.57% 96.57% -0.01%
==========================================
Files 28 28
Lines 3618 3616 -2
==========================================
- Hits 3494 3492 -2
Misses 124 124 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
devmotion
marked this pull request as ready for review
October 24, 2026 22:47
Member
|
This seems wide enough, thanks! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #854 without reverting #604, and removes the remaining silently-incorrect
randrule.Problem
@non_differentiable rand(::AbstractRNG, ::Random.Sampler)matches every sampler, including the ones that sample from collections of differentiable values (SamplerSimple{<:Array},SamplerTrivial{<:Tuple},SamplerSimple{<:LinRange},SamplerSimple{<:Dict},SamplerTag{<:Set}, ...). Hence, e.g., on ChainRules 1.74.3At the same time, #604 removed the over-wide
rand!rules (which caused the same problem for e.g.sum(rand([x], 3))), which maderand(1:4, 5)error in Zygote (#854).Changes
rand(::AbstractRNG, sp)andrand!(::AbstractRNG, ::AbstractArray, sp)are only non-differentiable for samplers whose output does not depend on any differentiable data or that sample from ranges of Base integer types:SamplerType,SamplerTrivial{<:FloatInterval},SamplerBigFloatSamplerSimpleforString,SubString{String}andAbstractArray{Char}SamplerRangeInt{<:BitInteger},SamplerRangeFast,SamplerRangeNDL{<:Any,<:BitInteger},SamplerBigIntrand!rule fixesrand(1:n, k)inside a Zygote gradient errors since 1.74.3 #854 (rand(1:4, 5),rand!(rng, A, 1:4)).rand(::Integer...),rand(::Type{<:Real}, ...),rand(::AbstractRNG, ::Integer...),rand!(::AbstractArray),rand!(::AbstractRNG, ::AbstractArray),rand!(::AbstractRNG, ::AbstractArray, ::Type): these calls reach the sampler rules above.Random.randexp(::AbstractRNG): subsumed byrandexp(::Any...).randstring(::AbstractRNG)→randstring(::Any...)(output is always aString);randstring()andrandstring(rng, n)errored in Zygote before.Zygote results (Julia 1.10.12 and 1.13.1)
rand(rng, [x]),rand(rng, (x,)),rand(rng, (x, x))nothing❌rand(rng, LinRange(x, x + 1, 2)),Dict,Setnothing❌sum(x .* rand(rng, 1:4, 5))(#854)x * rand(rng, 1:4),UInt128rangesrand(rng),rand(rng, 3),rand!(rng, zeros(3)),rand(Float32, 2, 2),rand(Int),BigFloat,'a':'z',randstring(rng), ...Proper (gather/scatter) rules for sampling from collections of differentiable values can be added in a follow-up PR.
Notes
rrule/frulecalled directly on the removed forwarders (e.g.rrule(rand, 2, 2)) now returnnothing; AD systems reach the sampler rules instead. I checked Zygote but not Diffractor.BigIntranges (rand(rng, big(1):big(4))) still error in Zygote, as on 1.74.3: Zygote fails in the construction of the sampler, before therandrule applies.🤖 Generated with Claude Code