Solving an optimal control problem with JuMP

This post is meant to provide some summary about the things that have helped so far.

Indeed, the error of the forward differentiation I got was fixed by transforming things to abstract type. As @ChrisRackauckas wrote:

this helped me in changing the type of the initial conditions of the ODE solver from Float64 to abstract type.

Then I had to do more changes in the code to make sure everything gets abstract types.

Now, when I run optimize I don’t get the error, but the differentiation takes a long time (the code is running for more than 15 hours, without any output so far).

In the meantime I am trying to solve the problem using Optim.jl and BlackBoxOptim.jl. See this post for more information.

There is still a chance that NLOptControl.jl will be helpful, but I am not sure yet about it.

Update - automatic differentiation (ForwardDiff.jl) returns Nan

My optimization function needs to calculate elliptic integrals. After converting the code in Elliptic.jl to be able to work with automatic differentiation, I get that the derivative of the complete elliptic integral of the 1st kind is NaN. The derivative is actually given by other elliptic integrals (as can be seen in the last link at the end of the section).

Here’s the minimal code (note that the credit to the code of calculating the elliptic integral belongs to nolta’s package Elliptic.jl):

julia> function DRF(X::Real, Y::Real, Z::Real)
           D1MACH1 = typeof(X)(1e-308)
           D1MACH2 = typeof(X)(1e308)
           D1MACH3 = typeof(X)(5e-16)/typeof(X)(2.0)
           D1MACH4 = typeof(X)(5e-16)
           D1MACH5 = log10(typeof(X)(2.))

           ERRTOL = (typeof(X)(4.0)*D1MACH3)^typeof(X)(1.0/6.0)
           LOLIM  = typeof(X)(5.0) * D1MACH1
           UPLIM  = D1MACH2/typeof(X)(5.0)
           C1 = typeof(X)(1.0/24.0)
           C2 = typeof(X)(3.0/44.0)
           C3 = typeof(X)(1.0/14.0)

           ans = zero(X)
           if min(X,Y,Z) < zero(X)
               return ans, one(X)
           end

           if max(X,Y,Z) > UPLIM
               return ans, typeof(X)(3)
           end

           if min(X+Y,X+Z,Y+Z) < LOLIM
               return ans, typeof(X)(2.0)
           end

           XN = X
           YN = Y
           ZN = Z
           MU = zero(X)
           XNDEV = zero(X)
           YNDEV = zero(X)
           ZNDEV = zero(X)

           while true
               MU = (XN+YN+ZN)/typeof(X)(3.0)
               XNDEV = typeof(X)(2.0) - (MU+XN)/MU
               YNDEV = typeof(X)(2.0) - (MU+YN)/MU
               ZNDEV = typeof(X)(2.0) - (MU+ZN)/MU
               EPSLON = max(abs(XNDEV),abs(YNDEV),abs(ZNDEV))
               if (EPSLON < ERRTOL) break end
               XNROOT = sqrt(XN)
               YNROOT = sqrt(YN)
               ZNROOT = sqrt(ZN)
               LAMDA = XNROOT*(YNROOT+ZNROOT) + YNROOT*ZNROOT
               XN = (XN+LAMDA)*typeof(X)(0.250)
               YN = (YN+LAMDA)*typeof(X)(0.250)
               ZN = (ZN+LAMDA)*typeof(X)(0.250)
           end

           E2 = XNDEV*YNDEV - ZNDEV*ZNDEV
           E3 = XNDEV*YNDEV*ZNDEV
           S  = typeof(X)(1.0) + (C1*E2-typeof(X)(0.10)-C2*E3)*E2 + C3*E3
           ans = S/sqrt(MU)

           return ans, typeof(X)(0)
       end
DRF (generic function with 1 method)

julia> function Kdiff(m::Real)
           if m < one(m)
               drf,ierr = DRF(zero(m), one(m) - m, one(m))
               @assert ierr == zero(m)
               return drf
           elseif m == one(m)
               return Inf
           elseif isnan(m)
               return NaN
           else
               throw(DomainError(m, "argument m not <= 1"))
           end
       end
Kdiff (generic function with 1 method)

julia> Kdiff(0.5)
1.854074677301372

julia> using ForwardDiff
  
julia> ForwardDiff.derivative(Kdiff, 0.5)
NaN

Is there a way to fix this Nan issue? or to provide somehow the derivative only to this part of the code? (I mean that my fitness function needs to calculate the elliptic integral at some point, but I do not know the derivatives of other parts of the fitness function).

In the meantime, I gave this fitness function to JuMP and it runs. I get some results which I try to compare to other algorithm, and they seem for now to make sense.
But, shouldn’t it be a problem that the derivative is Nan? In what way does it affect the solver (I am using Ipopt).