ForwardDiff.gradient of function with nested functions calls

I’m trying to get gradient of function that calls another one.

using ForwardDiff, BenchmarkTools

const f_l, f_r = 0.0,0.0;
function J(f::AbstractArray, α::AbstractArray, mesh::AbstractArray)
    J = 0.0;
    N = length(f);

    for i = 2:N - 1
        J += ( (f[i+1] - f[i])/mesh[i] - α[i] )^2 ;
    end

    norm = x -> sobolev_1_1_norm(x,mesh);
    J += norm(f);
    return J
end
function sobolev_1_1_norm(f::AbstractArray,mesh::AbstractArray)
    out = 0.0;
    N = length(f);
    for i = 1:N-1
        out += f[i] + ((f[i+1] - f[i])/mesh[i])^2;
    end
    out += f[end] + ((f[end ] - f[end - 1])/mesh[end])^2;
end
∇J(z,α,mesh)  = ForwardDiff.gradient( x -> J(x, α, mesh), α, mesh);

size = 50;
α = rand(-pi:0.01:pi, size);
mesh = fill(0.2, size);
f = rand(size);


@btime J(f,α,mesh)
@btime ∇J(f,α,mesh)

results in

julia> @btime J(f,α,mesh)

  556.403 ns (1 allocation: 16 bytes)
678.466801231054

julia> @btime ∇J(f,α,mesh)

ERROR: MethodError: no method matching gradient(::getfield(Main, Symbol("##15#16")){Array{Float64,1},Array{Float64,1}}, ::Array{Float64,1}, ::Array{Float64,1})
Closest candidates are:
  gradient(::Any, ::AbstractArray) at /Users/user/.julia/packages/ForwardDiff/hnKaN/src/gradient.jl:15
  gradient(::Any, ::AbstractArray, ::ForwardDiff.GradientConfig{T,V,N,D} where D where N where V) where T at /Users/user/.julia/packages/ForwardDiff/hnKaN/src/gradient.jl:15
  gradient(::Any, ::AbstractArray, ::ForwardDiff.GradientConfig{T,V,N,D} where D where N where V, ::Val{CHK}) where {T, CHK} at /Users/user/.julia/packages/ForwardDiff/hnKaN/src/gradient.jl:15
  ...
Stacktrace:
 [1] ∇J(::Array{Float64,1}, ::Array{Float64,1}, ::Array{Float64,1}) at ./REPL[26]:1
 [2] ##core#404() at /Users/user/.julia/packages/BenchmarkTools/dtwnm/src/execution.jl:293
 [3] ##sample#405(::BenchmarkTools.Parameters) at /Users/user/.julia/packages/BenchmarkTools/dtwnm/src/execution.jl:299
 [4] #_run#18(::Bool, ::String, ::Base.Iterators.Pairs{Symbol,Integer,NTuple{4,Symbol},NamedTuple{(:samples, :evals, :gctrial, :gcsample),Tuple{Int64,Int64,Bool,Bool}}}, ::Function, ::BenchmarkTools.Benchmark{Symbol("##benchmark#403")}, ::BenchmarkTools.Parameters) at /Users/user/.julia/packages/BenchmarkTools/dtwnm/src/execution.jl:327
 [5] (::getfield(Base, Symbol("#inner#2")){Base.Iterators.Pairs{Symbol,Integer,NTuple{5,Symbol},NamedTuple{(:verbose, :samples, :evals, :gctrial, :gcsample),Tuple{Bool,Int64,Int64,Bool,Bool}}},typeof(BenchmarkTools._run),Tuple{BenchmarkTools.Benchmark{Symbol("##benchmark#403")},BenchmarkTools.Parameters}})() at ./none:0
 [6] #invokelatest#1 at ./essentials.jl:690 [inlined]
 [7] #invokelatest at ./none:0 [inlined]
 [8] #run_result#16 at /Users/user/.julia/packages/BenchmarkTools/dtwnm/src/execution.jl:32 [inlined]
 [9] #run_result at ./none:0 [inlined]
 [10] #run#18(::Base.Iterators.Pairs{Symbol,Integer,NTuple{5,Symbol},NamedTuple{(:verbose, :samples, :evals, :gctrial, :gcsample),Tuple{Bool,Int64,Int64,Bool,Bool}}}, ::Function, ::BenchmarkTools.Benchmark{Symbol("##benchmark#403")}, ::BenchmarkTools.Parameters) at /Users/user/.julia/packages/BenchmarkTools/dtwnm/src/execution.jl:46
 [11] #run at ./none:0 [inlined] (repeats 2 times)
 [12] #warmup#21 at /Users/user/.julia/packages/BenchmarkTools/dtwnm/src/execution.jl:79 [inlined]
 [13] warmup(::BenchmarkTools.Benchmark{Symbol("##benchmark#403")}) at /Users/user/.julia/packages/BenchmarkTools/dtwnm/src/execution.jl:79
 [14] top-level scope at /Users/user/.julia/packages/BenchmarkTools/dtwnm/src/execution.jl:387

What I’m missing?

∇J(z,α,mesh)  = ForwardDiff.gradient( x -> J(x, α, mesh), α, mesh);

z is unused and you are giving two arguments to gradient after the function.

Did you mean

julia> ∇J(z,α,mesh)  = ForwardDiff.gradient( x -> J(x, α, mesh), z);

julia> @btime ∇J(f,α,mesh)
  14.267 μs (4 allocations: 5.88 KiB)

?

3 Likes

Yeah, that is what i mean and the answer.

Thx!