Failure of Zygote.jl on function with integration by HCubature.jl

I need to perform automatic differentiation on a function constructed by numerical integration. I choose HCubature.jl on integral and Zygote.jl on AD. However, there is an error as following:

using HCubature,Zygote

const kb::Float64=1;

const tem::Float64=1/9600;

nf(e,tem)=inv(expm1(e/(kb*tem))+2.0)

spinonenergy(kx,ky,h,mu)=(-2*(cos(kx)+cos(ky)))-h-mu

SD_spinon(omega,kx,ky,h,mu)=
-1/pi*imag(inv(omega+1e-2*im-spinonenergy(kx,ky,h,mu)))

function GSE(mu,h)
        integrand_spinon(omega,kx,ky)=
        omega*SD_spinon(omega,kx,ky,h,mu)*nf(omega,tem)

        int_spinon=hcubature(x->integrand_spinon(x[1],x[2],x[3]), (-5,-pi,-pi), (5,pi,pi),maxevals=Int(2e+7),rtol=1e-4, atol=1e-4)[1]

        return 1/(2*pi)^2*(int_spinon)
end

let
energy(x) = GSE(-0.5,x[1])

Zygote.gradient(energy,[1.0])[1]

end

ArgumentError: new: too few arguments (expected 1)

What cause this error and how could I fix it?

If I turn to use Cubature, the error would become to

using Cubature, Zygote
#Everything is the same as above mentioned
let
energy(x) = GSE(-0.5,x)

Zygote.gradient(energy,1.0)[1]

end
Compiling Tuple{typeof(Cubature.integrands), Cubature.IntegrandData{var"#3#5"{var"#integrand_spinon#4"{Float64, Float64}}}, Bool, Bool, Bool}: UndefVarError: `spvals` not defined

For this sort of thing, I would recommend using HCubature via Integrals.jl, which provides a wrapper that has AD chain rules written for it, so that Zygote does not try to differentiate through it “manually”.

Thx for your reply.
I rewrite the function with integration into Integrals.jl, however there is still a problem in Zygote.jl

using Integrals,Zygote
function GSE(mu,h)
    integrand_spinon(u,p)=
    u[1]*SD_spinon(u[1],u[2],u[3],h,mu)*nf(u[1],tem)

    int_spinon = IntegralProblem(integrand_spinon, (-5.0,-pi*1,-pi*1), (5.0,pi*1,pi*1))
    
    sol_spinon = solve(int_spinon, HCubatureJL(); reltol = 1e-3, abstol = 1e-3)
    
    return 1/(2*pi)^2*(sol_spinon.u)
end

let
energy(x) = GSE(-0.5,x)

Zygote.gradient(energy,1.0)[1]

end
MethodError: no method matching length(::SciMLBase.NullParameters)
An arithmetic operation was performed on a NullParameters object. This means no parameters were passed
into the AbstractSciMLProblem (e.x.: ODEProblem) but the parameters object `p` was used in an arithmetic
expression. Two common reasons for this issue are:

1. Forgetting to pass parameters into the problem constructor. For example, `ODEProblem(f,u0,tspan)` should
be `ODEProblem(f,u0,tspan,p)` in order to use parameters.

2. Using the wrong function signature. For example, with `ODEProblem`s the function signature is always
`f(du,u,p,t)` for the in-place form or `f(u,p,t)` for the out-of-place form. Note that the `p` argument
will always be in the function signature reguardless of if the problem is defined with parameters!

BTW, functions by Integrals.jl support ForwardDiff.jl and the results are correct. Actually, my final goal is minimize the function GSE through Optim.jl with some derivative dependent algorithms, but only errors I received.

I think you might have some errors in the way parameters are handled (see this tutorial). The following should work but I’m missing some functions so I can’t test:

using Integrals, Zygote

function integrand_spinon(u, p)
    mu, h = p[1], p[2]
    return u[1]*SD_spinon(u[1],u[2],u[3],h,mu)*nf(u[1],tem)
end

function GSE(mu, h)
    lb = (-5.0,-pi*1,-pi*1)
    ub = (5.0,pi*1,pi*1)
    p = [mu, h]
    int_spinon = IntegralProblem(integrand_spinon, lb, ub, p)
    sol_spinon = solve(int_spinon, HCubatureJL(); reltol = 1e-3, abstol = 1e-3)
    return 1/(2*pi)^2*(sol_spinon.u)
end

energy(x) = GSE(-0.5, x)
Zygote.gradient(energy, 1.0)[1]

However the tutorial says Zygote is broken, not sure what’s going on there