There are a couple of issues in here, but they’re related in how I discovered them.
In attempting to test Enzyme on some basic vector operations, I came across a problem with derivatives of the addition function. In particular, this example with LabelledArrays doesn’t work because there is no one
method for SLArray
:
using Random, LabelledArrays, Enzyme
SLV = @SLVector Float64 (:a, :b, :c);
u = SLV(rand(3));
v = SLV(rand(3));
du = zero(u);
dv = zero(v);
@show autodiff(Reverse, +, Active, Active(u), Active(v))
OUTPUT:
ERROR: LoadError: MethodError: no method matching one(::Type{SLArray{Tuple{3}, Float64, 1, 3, (:a, :b, :c)}})
Closest candidates are:
one(::Type{Union{}}, Any...)
@ Base number.jl:349
one(::Type{Missing})
@ Base missing.jl:104
one(::BitMatrix)
@ Base bitarray.jl:426
...
Stacktrace:
[1] autodiff(::ReverseMode{false, FFIABI}, ::Const{typeof(+)}, ::Type{Active}, ::Active{SLArray{Tuple{3}, Float64, 1, 3, (:a, :b, :c)}}, ::Vararg{Active{SLArray{Tuple{3}, Float64, 1, 3, (:a, :b, :c)}}})
@ Enzyme ~/.julia/packages/Enzyme/jOGYG/src/Enzyme.jl:213
[2] autodiff(::ReverseMode{false, FFIABI}, ::typeof(+), ::Type, ::Active{SLArray{Tuple{3}, Float64, 1, 3, (:a, :b, :c)}}, ::Vararg{Active{SLArray{Tuple{3}, Float64, 1, 3, (:a, :b, :c)}}})
@ Enzyme ~/.julia/packages/Enzyme/jOGYG/src/Enzyme.jl:224
[3] macro expansion
@ show.jl:1181 [inlined]
[4] top-level scope
@ ~/software/julia/enzyme/slarray-one-mwe.jl:10
[5] include(fname::String)
@ Base.MainInclude ./client.jl:489
[6] top-level scope
@ REPL[8]:1
I understand why you might not have a method for one
because the multiplicative identity is a different type than the input (matrix vs vector, e.g.). It made me think of Vector
, which also doesn’t have a one
method. It looks like enzyme doesn’t handle vector addition in the way I would expect:
using Random, Enzyme
x = rand(3); y = rand(3); dx = zero(x); dy = zero(y)
autodiff(Reverse, +, Active, Duplicated(x, dx), Duplicated(y, dy))
ERROR: Enzyme Mutability Error: Cannot add one in place to immutable value [0.0, 0.0, 0.0]
Stacktrace:
[1] add_one_in_place
@ ~/.julia/packages/Enzyme/jOGYG/src/compiler.jl:4979 [inlined]
[2] augmented_julia___2562wrap
@ ./arraymath.jl:0
[3] macro expansion
@ Enzyme.Compiler ~/.julia/packages/Enzyme/jOGYG/src/compiler.jl:5306 [inlined]
[4] enzyme_call(::Val{false}, ::Ptr{Nothing}, ::Type{Enzyme.Compiler.AugmentedForwardThunk}, ::Type{Val{1}}, ::Val{false}, ::Type{Tuple{Duplicated{Vector{Float64}}, Duplicated{Vector{Float64}}}}, ::Type{Duplicated{Vector{Float64}}}, ::Const{typeof(+)}, ::Type{@NamedTuple{1, 2, 3, 4, 5, 6::Bool, 7::Bool, 8::Bool, 9, 10::Bool, 11::UInt64, 12::UInt64}}, ::Duplicated{Vector{Float64}}, ::Duplicated{Vector{Float64}})
@ Enzyme.Compiler ~/.julia/packages/Enzyme/jOGYG/src/compiler.jl:4984
[5] (::Enzyme.Compiler.AugmentedForwardThunk{Ptr{Nothing}, Const{typeof(+)}, Duplicated{Vector{Float64}}, Tuple{Duplicated{Vector{Float64}}, Duplicated{Vector{Float64}}}, Val{1}, Val{false}(), @NamedTuple{1, 2, 3, 4, 5, 6::Bool, 7::Bool, 8::Bool, 9, 10::Bool, 11::UInt64, 12::UInt64}})(::Const{typeof(+)}, ::Duplicated{Vector{Float64}}, ::Vararg{Duplicated{Vector{Float64}}})
@ Enzyme.Compiler ~/.julia/packages/Enzyme/jOGYG/src/compiler.jl:4937
[6] autodiff(::ReverseMode{false, FFIABI}, ::Const{typeof(+)}, ::Type{Active}, ::Duplicated{Vector{Float64}}, ::Vararg{Duplicated{Vector{Float64}}})
@ Enzyme ~/.julia/packages/Enzyme/jOGYG/src/Enzyme.jl:198
[7] autodiff(::ReverseMode{false, FFIABI}, ::typeof(+), ::Type, ::Duplicated{Vector{Float64}}, ::Vararg{Duplicated{Vector{Float64}}})
@ Enzyme ~/.julia/packages/Enzyme/jOGYG/src/Enzyme.jl:224
[8] top-level scope
@ REPL[6]:1
I would expect the answer to be that dx = ones(3)
. Is this unsupported by Enzyme currently (but with plans to support it in the future)? Is this custom rules territory?