Enzyme.jl icon indicating copy to clipboard operation
Enzyme.jl copied to clipboard

Bounds error when analyzing typeunstablerules.jl

Open ptiede opened this issue 1 year ago • 1 comments

I found a strange bug that appears to be in the Enzyme-type unstable rules for Julia. Here is a somewhat MWE I constructed from some stripped down code.

using Enzyme
Enzyme.API.runtimeActivity!(true) #Otherwise Enzyme complains about ProductDist

struct Uniform{T}
    a::T
    b::T
end
logpdf(d::Uniform, ::Real) = -log(d.b - d.a)

struct Normal{T}
    μ::T
    σ::T
end
logpdf(d::Normal, x::Real) = -(x - d.μ)^2 / (2 * d.σ^2)

struct ProductDist{V}
    dists::V
end
function logpdf(d::ProductDist, x::Vector)
    dists = d.dists
    s = zero(eltype(x))
    for i in eachindex(x)
        s += logpdf(dists[i], x[i])
    end
    return s
end

struct NamedDist{Names, D<:NamedTuple{Names}}
    dists::D
end

function logpdf(d::NamedDist{N}, x::NamedTuple{N}) where {N}
    vt = values(x)
    dists = d.dists
    return mapreduce((dist, acc) -> logpdf(dist, acc), +, dists, vt)
end


d = NamedDist((;a = Normal(0.0, 1.0), b = ProductDist([Uniform(0.0, 1.0), Uniform(0.0, 1.0)])))
p = (a = 1.0, b = [0.5, 0.5])
dp = Enzyme.make_zero(p)
logpdf(d, p)
autodiff(Reverse, logpdf, Active, Const(d), Duplicated(p, dp))

The stacktrace on my machine is

ERROR: BoundsError: attempt to access Base.RefValue{@NamedTuple{a::Normal{Float64}, b::ProductDist{Vector{Uniform{Float64}}}}} at index [2]
Stacktrace:
  [1] getfield_idx
    @ ~/.julia/packages/Enzyme/qRjan/src/rules/typeunstablerules.jl:228 [inlined]
  [2] idx_jl_getfield_aug(::Base.RefValue{@NamedTuple{a::Normal{…}, b::ProductDist{…}}}, ::Type{Val{1}}, ::Val{false})
    @ Enzyme.Compiler ~/.julia/packages/Enzyme/qRjan/src/rules/typeunstablerules.jl:250
  [3] iterate
    @ ./namedtuple.jl:165 [inlined]
  [4] _zip_iterate_some
    @ ./iterators.jl:428 [inlined]
  [5] _zip_iterate_all
    @ ./iterators.jl:420 [inlined]
  [6] iterate
    @ ./iterators.jl:411 [inlined]
  [7] _foldl_impl
    @ ./reduce.jl:60
  [8] foldl_impl
    @ ./reduce.jl:48 [inlined]
  [9] mapfoldl_impl
    @ ./reduce.jl:44 [inlined]
 [10] mapfoldl
    @ ./reduce.jl:175 [inlined]
 [11] mapreduce
    @ ./reduce.jl:307 [inlined]
 [12] reduce
    @ ./reduce.jl:490 [inlined]
 [13] mapreduce
    @ ./reduce.jl:308 [inlined]
 [14] logpdf
    @ ~/.julia/dev/VLBIImagePriors/enzyme_test.jl:35 [inlined]
 [15] logpdf
    @ ~/.julia/dev/VLBIImagePriors/enzyme_test.jl:0 [inlined]
 [16] diffejulia_logpdf_4733_inner_1wrap
    @ ~/.julia/dev/VLBIImagePriors/enzyme_test.jl:0
 [17] macro expansion
    @ ~/.julia/packages/Enzyme/qRjan/src/compiler.jl:5377 [inlined]
 [18] enzyme_call(::Val{…}, ::Ptr{…}, ::Type{…}, ::Type{…}, ::Val{…}, ::Type{…}, ::Type{…}, ::Const{…}, ::Type{…}, ::Const{…}, ::Duplicated{…}, ::Float64)
    @ Enzyme.Compiler ~/.julia/packages/Enzyme/qRjan/src/compiler.jl:5055
 [19] (::Enzyme.Compiler.CombinedAdjointThunk{…})(::Const{…}, ::Const{…}, ::Vararg{…})
    @ Enzyme.Compiler ~/.julia/packages/Enzyme/qRjan/src/compiler.jl:4997
 [20] autodiff(::ReverseMode{false, FFIABI}, ::Const{typeof(logpdf)}, ::Type{Active}, ::Const{NamedDist{…}}, ::Vararg{Any})
    @ Enzyme ~/.julia/packages/Enzyme/qRjan/src/Enzyme.jl:215
 [21] autodiff(::ReverseMode{false, FFIABI}, ::typeof(logpdf), ::Type, ::Const{NamedDist{…}}, ::Vararg{Any})
    @ Enzyme ~/.julia/packages/Enzyme/qRjan/src/Enzyme.jl:224
 [22] top-level scope

I am on Julia 1.10.1 and using [email protected]

ptiede avatar Feb 29 '24 16:02 ptiede

Ah so this one shouldn’t be bad, in essence that code should check if the value is a ref, deref and update the value, then store it back

On Thu, Feb 29, 2024 at 8:28 AM Paul Tiede @.***> wrote:

I found a strange bug that appears to be in the Enzyme-type unstable rules for Julia. Here is a somewhat MWE I constructed from some stripped down code.

using Enzyme Enzyme.API.runtimeActivity!(true) #Otherwise Enzyme complains about ProductDist struct Uniform{T} a::T b::Tendlogpdf(d::Uniform, ::Real) = -log(d.b - d.a) struct Normal{T} μ::T σ::Tendlogpdf(d::Normal, x::Real) = -(x - d.μ)^2 / (2 * d.σ^2) struct ProductDist{V} dists::Vendfunction logpdf(d::ProductDist, x::Vector) dists = d.dists s = zero(eltype(x)) for i in eachindex(x) s += logpdf(dists[i], x[i]) end return send struct NamedDist{Names, D<:NamedTuple{Names}} dists::Dend function logpdf(d::NamedDist{N}, x::NamedTuple{N}) where {N} vt = values(x) dists = d.dists return mapreduce((dist, acc) -> logpdf(dist, acc), +, dists, vt)end

d = NamedDist((;a = Normal(0.0, 1.0), b = ProductDist([Uniform(0.0, 1.0), Uniform(0.0, 1.0)]))) p = (a = 1.0, b = [0.5, 0.5]) dp = Enzyme.make_zero(p)logpdf(d, p)autodiff(Reverse, logpdf, Active, Const(d), Duplicated(p, dp))

The stacktrace on my machine is

ERROR: BoundsError: attempt to access @.{a::Normal{Float64}, b::ProductDist{Vector{Uniform{Float64}}}}} at index [2] Stacktrace: [1] getfield_idx @ ~/.julia/packages/Enzyme/qRjan/src/rules/typeunstablerules.jl:228 [inlined] [2] @.{a::Normal{…}, b::ProductDist{…}}}, ::Type{Val{1}}, ::Val{false}) @ Enzyme.Compiler ~/.julia/packages/Enzyme/qRjan/src/rules/typeunstablerules.jl:250 [3] iterate @ ./namedtuple.jl:165 [inlined] [4] _zip_iterate_some @ ./iterators.jl:428 [inlined] [5] _zip_iterate_all @ ./iterators.jl:420 [inlined] [6] iterate @ ./iterators.jl:411 [inlined] [7] _foldl_impl @ ./reduce.jl:60 [8] foldl_impl @ ./reduce.jl:48 [inlined] [9] mapfoldl_impl @ ./reduce.jl:44 [inlined] [10] mapfoldl @ ./reduce.jl:175 [inlined] [11] mapreduce @ ./reduce.jl:307 [inlined] [12] reduce @ ./reduce.jl:490 [inlined] [13] mapreduce @ ./reduce.jl:308 [inlined] [14] logpdf @ ~/.julia/dev/VLBIImagePriors/enzyme_test.jl:35 [inlined] [15] logpdf @ ~/.julia/dev/VLBIImagePriors/enzyme_test.jl:0 [inlined] [16] diffejulia_logpdf_4733_inner_1wrap @ ~/.julia/dev/VLBIImagePriors/enzyme_test.jl:0 [17] macro expansion @ ~/.julia/packages/Enzyme/qRjan/src/compiler.jl:5377 [inlined] [18] enzyme_call(::Val{…}, ::Ptr{…}, ::Type{…}, ::Type{…}, ::Val{…}, ::Type{…}, ::Type{…}, ::Const{…}, ::Type{…}, ::Const{…}, ::Duplicated{…}, ::Float64) @ Enzyme.Compiler ~/.julia/packages/Enzyme/qRjan/src/compiler.jl:5055 [19] (::Enzyme.Compiler.CombinedAdjointThunk{…})(::Const{…}, ::Const{…}, ::Vararg{…}) @ Enzyme.Compiler ~/.julia/packages/Enzyme/qRjan/src/compiler.jl:4997 [20] autodiff(::ReverseMode{false, FFIABI}, ::Const{typeof(logpdf)}, ::Type{Active}, ::Const{NamedDist{…}}, ::Vararg{Any}) @ Enzyme ~/.julia/packages/Enzyme/qRjan/src/Enzyme.jl:215 [21] autodiff(::ReverseMode{false, FFIABI}, ::typeof(logpdf), ::Type, ::Const{NamedDist{…}}, ::Vararg{Any}) @ Enzyme ~/.julia/packages/Enzyme/qRjan/src/Enzyme.jl:224 [22] top-level scope

I am on Julia 1.10.1 and using @.***

— Reply to this email directly, view it on GitHub https://github.com/EnzymeAD/Enzyme.jl/issues/1317, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAJTUXHARHCHUCZ4CAPEPN3YV5LLTAVCNFSM6AAAAABEAIC7V2VHI2DSMVQWIX3LMV43ASLTON2WKOZSGE3DCNRUGQ4TSMA . You are receiving this because you are subscribed to this thread.Message ID: @.***>

wsmoses avatar Feb 29 '24 16:02 wsmoses

should be fixed by https://github.com/EnzymeAD/Enzyme.jl/pull/1430

wsmoses avatar May 11 '24 19:05 wsmoses