JuliaDiff / ForwardDiff.jl

Forward Mode Automatic Differentiation for Julia
Other
892 stars 145 forks source link

AD in-place instead of broadcast #645

Closed b-fg closed 1 year ago

b-fg commented 1 year ago

I am sure this is covered somewhere and https://github.com/JuliaDiff/ForwardDiff.jl/issues/136#issuecomment-237941790 is very much related, but I am struggling to understand why does this MWE work

addX!(a, x) = sum(a .+ x)
a = ones(10)
∂addX(a, x) = ForwardDiff.derivative(x -> addX!(a, x), x)
∂addX(a, 1.0)

but not this one:

function addX!(a, x)
    for i ∈ axes(a)
        a[i] += x
    end
    sum(a)
end

a = ones(10)
∂addX(a, x) = ForwardDiff.derivative(x -> addX!(a, x), x)
∂addX(a, 1.0)

With error: ERROR: MethodError: no method matching +(::Vector{Float64}, ::ForwardDiff.Dual{ForwardDiff.Tag{var"#5#6"{Vector{Float64}}, Float64}, Float64, 1})

What is special about broadcasting instead of explicitly writing the loop? Thanks!

mcabbott commented 1 year ago

The broadcasting function does not mutate a. To be equivalent to the loop it would be addX!(a, x) = sum(a .= a .+ x), which gives the same error.

In general you will need to make arrays of the right type to store Dual numbers, e.g. using similar(x).