# How to use ForwardDiff with NLopt?

**URL:** <https://discourse.julialang.org/t/how-to-use-forwarddiff-with-nlopt/53368>\
**Category:** Optimization (Mathematical)\
**Tags:** optimization, forwarddiff\
**Created:** [January 14, 2021, 11:51pm UTC](https://discourse.julialang.org/t/how-to-use-forwarddiff-with-nlopt/53368 "2021-01-14T23:51:11Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![Michael\_Barmann](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/michael_barmann/32/20389_2.png) [@Michael\_Barmann](https://discourse.julialang.org/u/Michael_Barmann)\
**Post date:** [January 14, 2021, 11:51pm UTC](https://discourse.julialang.org/t/how-to-use-forwarddiff-with-nlopt/53368/1 "2021-01-14T23:51:11Z")

</div>

I’m working on an optimization problem, and I’m trying to make use of the gradient-based algorithms in the `NLopt` library (specifically `LD_SLSQP`). The objective function which I am trying to minimize does not have an analytic form (evaluating it involves computing the numerical solution of a system of ODEs), so the gradient must be computed numerically.

I’d like to compute the gradient using automatic differentiation with the `ForwardDiff` package, but I’m not sure exactly how to do this. My question is: what is the correct way to supply a gradient to an NLopt algorithm which is computed via `ForwardDiff`?

In this tutorial [JuliaOpt/NLopt.jl](https://github.com/JuliaOpt/NLopt.jl), it says the gradient must be modified _in place_, e.g.

```julia
using NLopt

function myfunc(x::Vector, grad::Vector)
    if length(grad) > 0
        grad[1] = 0
        grad[2] = 0.5/sqrt(x[2])
    end
    return sqrt(x[2])
end

```

But ForwardDiff needs to evaluate `myfunc` in order to calculate `grad`, so I don’t see how this would work using in place modification. Also, the FD documentation here [ForwardDiff.jl/stable/user/limitations/](http://www.juliadiff.org/ForwardDiff.jl/stable/user/limitations/) says that the target function must be unary (only one argument), while `NLopt` requires that `myfunc()` have two: `x` and `grad`.

Is there a way to make this work? Or do I need to use a different optimization algorithm/different AD algorithm?

---

<div class="post-metadata">

**Author:** ![thorek1](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/thorek1/32/20989_2.png) [@thorek1](https://discourse.julialang.org/u/thorek1)\
**Post date:** [January 15, 2021, 12:04am UTC](https://discourse.julialang.org/t/how-to-use-forwarddiff-with-nlopt/53368/2 "2021-01-15T00:04:19Z")

</div>

I think the JuMP interface does not require you to explicitly calculate derivatives. You set up the problem, select NLopt as the backend and JuMP does the job / derivatives for you.

---

<div class="post-metadata">

**Author:** ![mcabbott](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mcabbott/32/6603_2.png) [@mcabbott](https://discourse.julialang.org/u/mcabbott)\
**Post date:** [January 15, 2021, 12:07am UTC](https://discourse.julialang.org/t/how-to-use-forwarddiff-with-nlopt/53368/3 "2021-01-15T00:07:04Z")

</div>

You can wrap your function in one which NLopt will like, something like this:

```julia
function nlfunc(vec, grad)
    if length(grad) != 0
        ForwardDiff.gradient!(grad, myfun, vec)
    end
    myfun(vec)
end
nlname = NLopt.Opt(opt, length(start_vec))
min_objective!(nlname, nlfunc)

```

You could use DiffResult things so as not to repeat the forward evaluation when it’s already been done for the gradient.

---

<div class="post-metadata">

**Author:** ![apo383](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/apo383/32/11272_2.png) [@apo383](https://discourse.julialang.org/u/apo383)\
**Post date:** [January 15, 2021, 1:42am UTC](https://discourse.julialang.org/t/how-to-use-forwarddiff-with-nlopt/53368/4 "2021-01-15T01:42:23Z")

</div>

Are you sure about this?

> [@Michael\_Barmann](#):
>
> …trying to minimize does not have an analytic form (evaluating it involves computing the numerical solution of a system of ODEs), so the gradient must be computed numerically

[DifferentialEquations.jl](https://diffeq.sciml.ai/stable/) has long been AD friendly, and for many ODEs even implements adjoint sensitivity methods that should be faster than AD. At this point, the capabilities cover a huge array of problems, so I’d be surprised if your problem is so hairy you need to supply a gradient yourself.

Also see [DiffEqFlux.jl](https://diffeqflux.sciml.ai/stable/), which lets (EDIT:) you throw ODEs into optimization, even if they’re chained with neural nets and stuff. Often you just set how you want your sensitivities with a `sensealg` parameter, e.g. AD backprop or adjoints computed within the ODE solver. For your particular problem, maybe you only need to specify `ForwardDiffSensitivity` and you’re done. Or if you really want to supply everything manually, you might only need the vector-Jacobian product, which is also automatic by default but can be supplied manually.

---

<div class="post-metadata">

**Author:** ![Michael\_Barmann](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/michael_barmann/32/20389_2.png) [@Michael\_Barmann](https://discourse.julialang.org/u/Michael_Barmann)\
**Post date:** [January 15, 2021, 9:02pm UTC](https://discourse.julialang.org/t/how-to-use-forwarddiff-with-nlopt/53368/5 "2021-01-15T21:02:32Z")

</div>

Thanks for the suggestion, though unfortunately this didn’t work–the algorithm stopped after the first iteration.

Actually I’m confused as to how this could work; since the `grad` argument is not initialized, it would have a length of 0 to begin with, and so `ForwardDiff.gradient!` would never get called. Or am I misunderstanding?

---

<div class="post-metadata">

**Author:** ![mcabbott](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mcabbott/32/6603_2.png) [@mcabbott](https://discourse.julialang.org/u/mcabbott)\
**Post date:** [January 15, 2021, 9:47pm UTC](https://discourse.julialang.org/t/how-to-use-forwarddiff-with-nlopt/53368/6 "2021-01-15T21:47:12Z")

</div>

It is entirely possible I messed it up, but the rough idea is like that. NLopt will create an array and pass it to `nlfunc`, which must write the gradient into it. It may choose not to pass this at every step. I think it also creates `vec`, rather than re-using the `start_vec` you pass to `NLopt.optimize(nlname, start_vec)`. Here `myfun` is the function you are actually minimising. Perhaps `grad .= ForwardDiff.gradient(myfun, vec)` is simpler.

Optim handles more of this for you, but not sure it has the same algorithm:

```julia
od = OnceDifferentiable(myfun, start_vec, autodiff=:forward)
Optim.optimize(od, start_vec, LBFGS())

```

---

<div class="post-metadata">

**Author:** ![Michael\_Barmann](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/michael_barmann/32/20389_2.png) [@Michael\_Barmann](https://discourse.julialang.org/u/Michael_Barmann)\
**Post date:** [January 15, 2021, 11:06pm UTC](https://discourse.julialang.org/t/how-to-use-forwarddiff-with-nlopt/53368/7 "2021-01-15T23:06:13Z")

</div>

Thanks for your help! It turns out I made a mistake: I forgot to remove the `grad` argument from `my_func`. After fixing this, I tried it again with the `SLSQP` it works! There is one minor issue though: I’m printing the objective function value every 20 or so iterations to display the progress, but it prints all this junk each time:

Dual{ForwardDiff.Tag{var"#objective#101"{typeof(One\_Age\_Model\_1eta),typeof(f\_ICs),typeof(norm1),DataFrame,Array{String,1},Array{String,1},Array{Float64,1},Array{Union{Missing, Float64},1},Array{Union{Missing, Float64},1},Array{Float64,1},Array{Float64,1},Array{Int64,1},Array{Int64,1},Array{Int64,1},Array{Int64,1},Int64,Int64,Int64},Float64}}(1.196920482884103e-5,-1.4501145807288991e-5,-2.06553122073125e-5,-6.317391855162725e-7,1.4807120422188783e-7,5.411123230817588e-6,5.823810564322322e-6,3.606300957515629e-7,-3.351628923995338e-6,-2.757480190291689e-6,2.4292065517195563e-6)  
2.7133331996873755e-5

Is there a way to suppress this?

Edit: I read the docs and learned of the `show_trace` option, so I resolved the above issue!

---

<div class="post-metadata">

**Author:** ![Michael\_Barmann](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/michael_barmann/32/20389_2.png) [@Michael\_Barmann](https://discourse.julialang.org/u/Michael_Barmann)\
**Post date:** [January 18, 2021, 11:14pm UTC](https://discourse.julialang.org/t/how-to-use-forwarddiff-with-nlopt/53368/8 "2021-01-18T23:14:38Z")

</div>

Hi, thanks a lot for your reply. I am brand new to AD so I never knew about these tools–they look extremely cool! I will look into them more, as I’m sure they would be useful for my code.

---

<div class="post-metadata">

**Author:** ![Annabelle\_Farnworth](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/annabelle_farnworth/32/36274_2.png) [@Annabelle\_Farnworth](https://discourse.julialang.org/u/Annabelle_Farnworth)\
**Post date:** [May 15, 2022, 7:00am UTC](https://discourse.julialang.org/t/how-to-use-forwarddiff-with-nlopt/53368/9 "2022-05-15T07:00:58Z")

</div>

Hi Michael! I have the same problem as you in that I am using autodiff::foward and SLSQP to some a complex minimization problem. In my situation it is also getting stuck after the first iteration and not giving a result, but never moving on from there. You refer to removing the grad argument from my\_func, what do you mean by this? Also did you have to have a constraint for this to work. Thank you so much for your help, I am really struggling which this.

---

<div class="post-metadata">

**Author:** ![odow](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/odow/32/28685_2.png) [@odow](https://discourse.julialang.org/u/odow)\
**Post date:** [May 15, 2022, 9:06pm UTC](https://discourse.julialang.org/t/how-to-use-forwarddiff-with-nlopt/53368/10 "2022-05-15T21:06:14Z")

</div>

Hi @annabelle_Farnworth, can you please make a new topic with a reproducible example of your problem? We try to avoid posting on older threads after they’ve been solved.

p.s. If you haven’t already, take a read of [Please read: make it easier to help you](https://discourse.julialang.org/t/please-read-make-it-easier-to-help-you/14757)
