The solve function

In this tutorial, we explain the solve function from OptimalControl.jl package.

Basic usage

Let us define a basic optimal control problem.

using OptimalControl

t0 = 0
tf = 1
x0 = [-1, 0]

ocp = @def begin

    t ∈ [ t0, tf ], time
    x = (q, v) ∈ R², state
    u ∈ R, control

    x(t0) == x0
    x(tf) == [ 0, 0 ]

    ẋ(t)  == [ v(t), u(t) ]

    ∫( 0.5u(t)^2 ) → min

end

We can now solve the problem:

using NLPModelsIpopt

solve(ocp)
This is Ipopt version 3.14.17, running with linear solver MUMPS 5.7.3.

Number of nonzeros in equality constraint Jacobian...:     3005
Number of nonzeros in inequality constraint Jacobian.:        0
Number of nonzeros in Lagrangian Hessian.............:      251

Total number of variables............................:     1004
                     variables with only lower bounds:        0
                variables with lower and upper bounds:        0
                     variables with only upper bounds:        0
Total number of equality constraints.................:      755
Total number of inequality constraints...............:        0
        inequality constraints with only lower bounds:        0
   inequality constraints with lower and upper bounds:        0
        inequality constraints with only upper bounds:        0

iter    objective    inf_pr   inf_du lg(mu)  ||d||  lg(rg) alpha_du alpha_pr  ls
   0  1.0000000e-01 1.10e+00 1.99e-14   0.0 0.00e+00    -  0.00e+00 0.00e+00   0
   1 -5.0000000e-03 7.36e-02 2.66e-15 -11.0 6.08e+00    -  1.00e+00 1.00e+00h  1
   2  6.0003829e+00 8.88e-16 1.78e-15 -11.0 6.01e+00    -  1.00e+00 1.00e+00h  1

Number of Iterations....: 2

                                   (scaled)                 (unscaled)
Objective...............:   6.0003828724303254e+00    6.0003828724303254e+00
Dual infeasibility......:   1.7763568394002505e-15    1.7763568394002505e-15
Constraint violation....:   8.8817841970012523e-16    8.8817841970012523e-16
Variable bound violation:   0.0000000000000000e+00    0.0000000000000000e+00
Complementarity.........:   0.0000000000000000e+00    0.0000000000000000e+00
Overall NLP error.......:   1.7763568394002505e-15    1.7763568394002505e-15


Number of objective function evaluations             = 3
Number of objective gradient evaluations             = 3
Number of equality constraint evaluations            = 3
Number of inequality constraint evaluations          = 0
Number of equality constraint Jacobian evaluations   = 3
Number of inequality constraint Jacobian evaluations = 0
Number of Lagrangian Hessian evaluations             = 2
Total seconds in IPOPT                               = 0.112

EXIT: Optimal Solution Found.

Notice that we need to load the NLPModelsIpopt package before calling solve. This is because the method currently implements a direct approach, where the optimal control problem is transcribed to a nonlinear optimization problem (NLP) of the form

\[\text{minimize}\quad F(y), \quad\text{subject to the constraints}\quad g(y)=0, \quad h(y)\le 0. \]

Note: calling solve without loading a NLP solver package first will notify the user:

julia> solve(ocp)
ERROR: ExtensionError. Please make: julia> using NLPModelsIpopt

See below for the NLP solver options.

Options

Methods

OptimalControl.jl offers a list of methods to solve your optimal control problem. To get the list of methods, simply call available_methods.

available_methods()
(:direct, :adnlp, :ipopt)
(:direct, :adnlp, :madnlp)
(:direct, :adnlp, :knitro)

Each line is a method, with priority going from top to bottom. This means that

solve(ocp)

is equivalent to

solve(ocp, :direct, :adnlp, :ipopt)

The first symbol :direct refers to the general class of method, with only the so-called direct approach currently implemented. Direct methods discretize the original optimal control problem and solve the resulting NLP problem. The second symbol :adnlp is for the choice of NLP modeler. We currently use ADNLPModels.jl which provides an automatic differentiation (AD)-based model implementations that conform to the NLPModels.jl API. The third symbol corresponds to the NLP solver, with the possible values:

  • :ipopt (default value) for Ipopt (via the NLPModelsIpopt.jl package).
  • :madnlp is MadNLP.jl, an open-source nonlinear programming solver purely implemented in Julia, which implements a filter line-search interior-point algorithm, as the one in Ipopt.
  • :knitro for the Knitro solver (requires a license).

For instance, let us try MadNLP.jl.

using MadNLP

solve(ocp, :madnlp)
This is MadNLP version v0.8.5, running with umfpack

Number of nonzeros in constraint Jacobian............:     3005
Number of nonzeros in Lagrangian Hessian.............:      251

Total number of variables............................:     1004
                     variables with only lower bounds:        0
                variables with lower and upper bounds:        0
                     variables with only upper bounds:        0
Total number of equality constraints.................:      755
Total number of inequality constraints...............:        0
        inequality constraints with only lower bounds:        0
   inequality constraints with lower and upper bounds:        0
        inequality constraints with only upper bounds:        0

iter    objective    inf_pr   inf_du lg(mu)  ||d||  lg(rg) alpha_du alpha_pr  ls
   0  1.0000000e-01 1.10e+00 2.45e-13  -1.0 0.00e+00    -  0.00e+00 0.00e+00   0
   1 -5.0000000e-03 7.36e-02 3.46e-12  -1.0 6.08e+00    -  1.00e+00 1.00e+00h  1
   2  6.0003829e+00 1.78e-15 2.66e-15  -2.5 6.01e+00    -  1.00e+00 1.00e+00h  1

Number of Iterations....: 2

                                   (scaled)                 (unscaled)
Objective...............:   6.0003828724303387e+00    6.0003828724303387e+00
Dual infeasibility......:   2.6645352591003757e-15    2.6645352591003757e-15
Constraint violation....:   1.7763568394002505e-15    1.7763568394002505e-15
Complementarity.........:   0.0000000000000000e+00    0.0000000000000000e+00
Overall NLP error.......:   2.6645352591003757e-15    2.6645352591003757e-15

Number of objective function evaluations             = 3
Number of objective gradient evaluations             = 3
Number of constraint evaluations                     = 3
Number of constraint Jacobian evaluations            = 3
Number of Lagrangian Hessian evaluations             = 2
Total wall-clock secs in solver (w/o fun. eval./lin. alg.)  =  0.001
Total wall-clock secs in linear solver                      =  0.004
Total wall-clock secs in NLP function evaluations           =  0.002
Total wall-clock secs                                       =  0.008

EXIT: Optimal Solution Found (tol = 1.0e-06).

Note that you can provide a partial description. If several full descriptions contain it, the priority is given to first one in the list. Hence, these calls are all equivalent:

solve(ocp)
solve(ocp, :direct                )
solve(ocp,          :adnlp        )
solve(ocp,                  :ipopt)
solve(ocp, :direct, :adnlp        )
solve(ocp, :direct,         :ipopt)
solve(ocp, :direct, :adnlp, :ipopt)

Direct method

The options for the direct method are listed in the direct_solve keywords. The main options, with their [default values], are:

  • display ([true], false): setting display to false will disable output
  • grid_size ([250]): size of the (uniform) time discretization grid. More precisely, it is the number of time steps, that is if N = grid_size and if the initial and final times are denoted respectively t0 and tf, then we have Δt = (tf - t0) / N
  • disc_method ([:trapeze], :midpoint, :gauss_legendre_2): see discretisation methods
  • init: info for the starting guess, which can be provided as numerical values, functions, or an existing solution. See initial guess tutorial.

For examples of more advanced use, see

NLP solver specific options

In addition to these options, all remaining keyword arguments passed to solve will be transmitted to the NLP solver used.

Please check the list of Ipopt options and the NLPModelsIpopt.jl documentation.

solve(ocp; max_iter=0)
This is Ipopt version 3.14.17, running with linear solver MUMPS 5.7.3.

Number of nonzeros in equality constraint Jacobian...:     3005
Number of nonzeros in inequality constraint Jacobian.:        0
Number of nonzeros in Lagrangian Hessian.............:      251

Total number of variables............................:     1004
                     variables with only lower bounds:        0
                variables with lower and upper bounds:        0
                     variables with only upper bounds:        0
Total number of equality constraints.................:      755
Total number of inequality constraints...............:        0
        inequality constraints with only lower bounds:        0
   inequality constraints with lower and upper bounds:        0
        inequality constraints with only upper bounds:        0

iter    objective    inf_pr   inf_du lg(mu)  ||d||  lg(rg) alpha_du alpha_pr  ls
   0  1.0000000e-01 1.10e+00 1.99e-14   0.0 0.00e+00    -  0.00e+00 0.00e+00   0

Number of Iterations....: 0

                                   (scaled)                 (unscaled)
Objective...............:   1.0000000000000001e-01    1.0000000000000001e-01
Dual infeasibility......:   1.9885771589406212e-14    1.9885771589406212e-14
Constraint violation....:   1.1000000000000001e+00    1.1000000000000001e+00
Variable bound violation:   0.0000000000000000e+00    0.0000000000000000e+00
Complementarity.........:   0.0000000000000000e+00    0.0000000000000000e+00
Overall NLP error.......:   1.1000000000000001e+00    1.1000000000000001e+00


Number of objective function evaluations             = 1
Number of objective gradient evaluations             = 1
Number of equality constraint evaluations            = 1
Number of inequality constraint evaluations          = 0
Number of equality constraint Jacobian evaluations   = 1
Number of inequality constraint Jacobian evaluations = 0
Number of Lagrangian Hessian evaluations             = 0
Total seconds in IPOPT                               = 0.003

EXIT: Maximum Number of Iterations Exceeded.

Similarly, please check the MadNLP.jl documentation and the list of MadNLP.jl options.

solve(ocp, :madnlp; max_iter=0)
This is MadNLP version v0.8.5, running with umfpack

Number of nonzeros in constraint Jacobian............:     3005
Number of nonzeros in Lagrangian Hessian.............:      251

Total number of variables............................:     1004
                     variables with only lower bounds:        0
                variables with lower and upper bounds:        0
                     variables with only upper bounds:        0
Total number of equality constraints.................:      755
Total number of inequality constraints...............:        0
        inequality constraints with only lower bounds:        0
   inequality constraints with lower and upper bounds:        0
        inequality constraints with only upper bounds:        0

iter    objective    inf_pr   inf_du lg(mu)  ||d||  lg(rg) alpha_du alpha_pr  ls
   0  1.0000000e-01 1.10e+00 2.45e-13  -1.0 0.00e+00    -  0.00e+00 0.00e+00   0

Number of Iterations....: 0

                                   (scaled)                 (unscaled)
Objective...............:   1.0000000000000001e-01    1.0000000000000001e-01
Dual infeasibility......:   2.4462294465047466e-13    2.4462294465047466e-13
Constraint violation....:   1.1000000000000001e+00    1.1000000000000001e+00
Complementarity.........:   0.0000000000000000e+00    0.0000000000000000e+00
Overall NLP error.......:   1.1000000000000001e+00    1.1000000000000001e+00

Number of objective function evaluations             = 1
Number of objective gradient evaluations             = 1
Number of constraint evaluations                     = 1
Number of constraint Jacobian evaluations            = 1
Number of Lagrangian Hessian evaluations             = 1
Total wall-clock secs in solver (w/o fun. eval./lin. alg.)  =  0.001
Total wall-clock secs in linear solver                      =  0.002
Total wall-clock secs in NLP function evaluations           =  0.001
Total wall-clock secs                                       =  0.004

EXIT: Maximum Number of Iterations Exceeded.