# The solve function

In this tutorial, we explain the `solve`

function from OptimalControl.jl package.

## Basic usage

Les 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
```

Let us try to solve the problem:

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

As you can see, an error occured since we need the package NLPModelsIpopt.jl.

Actually, the default solving method is what we call a direct method. In a direct method, 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. \]

OptimalControl.jl package makes the transcription but it needs a package to modelise the NLP problem and another one to solve it. NLPModelsIpopt.jl package provides an interface to the well-known solver Ipopt that can be used to solve general nonlinear programming problems.

```
using NLPModelsIpopt
solve(ocp)
```

```
This is Ipopt version 3.14.16, 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.030
EXIT: Optimal Solution Found.
```

## Solvers

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)
```

Each line is a method. The priority is given from top to bottom. This means that

`solve(ocp)`

is equivalent to

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

Let us detail the three symbols. As you can see, there are only direct methods. The symbol `:adnlp`

is for the choice of modeler. As said before, the NLP problem needs to be modelised in Julia code. We use ADNLPModels.jl which provides automatic differentiation (AD)-based model implementations that conform to the NLPModels.jl API.

The last symbol is what distinguish the two available methods. It corresponds to the NLP solver. By default, we use the NLPModelsIpopt.jl package but you can choose MadNLP.jl which is an open-source nonlinear programming solver, purely implemented in Julia and which implements a filter line-search interior-point algorithm, as used in Ipopt.

Note that you are not compelled to provide the full description of the method to use it. A partial description, if not ambiguous, will work. Just remember that if several full descriptions contain the partial one, then, 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)
```

Let us try MadNLP.jl.

```
using MadNLP
solve(ocp, :direct, :adnlp, :madnlp; display=true)
```

```
The options set during resolve may not have an effect
This is MadNLP version v0.8.4, 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.) = 1.626
Total wall-clock secs in linear solver = 0.004
Total wall-clock secs in NLP function evaluations = 0.007
Total wall-clock secs = 1.637
EXIT: Optimal Solution Found (tol = 1.0e-08).
```

Again, there are several equivalent manners to use MadNLP.jl.

```
solve(ocp, :madnlp)
solve(ocp, :direct, :madnlp)
solve(ocp, :adnlp, :madnlp)
solve(ocp, :direct, :adnlp, :madnlp)
```

## Options

### Direct method

The options common to all the direct methods may be seen directly in the `direct_solve`

keywords. There are `init`

, `grid_size`

and `time_grid`

.

- The
`init`

option can be used to set an initial guess for the solver. See the initial guess tutorial. - The
`grid_size`

option corresponds to the size of the (uniform) time discretization grid. More precisely, it is the number of 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`

- The
`time_grid`

option is the grid of times:`t0, t1, ..., tf`

. If the initial and/or the final times are free, then you can provide a normalised grid between 0 and 1. Note that you can set either`grid_size`

or`time_grid`

but not both.

```
sol = solve(ocp; grid_size=10, display=false)
time_grid(sol)
```

```
11-element Vector{Float64}:
0.0
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
1.0
```

Or with MadNLP.jl:

```
sol = solve(ocp, :madnlp; grid_size=10, display=false)
time_grid(sol)
```

```
11-element Vector{Float64}:
0.0
0.1
0.2
0.3
0.4
0.5
0.6
0.7
0.8
0.9
1.0
```

### NLPModelsIpopt

You can provide any option of NLPModelsIpopt.jl or Ipopt with a pair `keyword=value`

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

`solve(ocp, :ipopt; max_iter=0)`

```
This is Ipopt version 3.14.16, 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.006
EXIT: Maximum Number of Iterations Exceeded.
```

### MadNLP

If you use the MadNLP.jl solver, then you can provide any option of it. Please check the MadNLP.jl documentation and the list of MadNLP.jl options.

`solve(ocp, :madnlp; max_iter=1, display=true)`

```
The options set during resolve may not have an effect
This is MadNLP version v0.8.4, 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
Number of Iterations....: 1
(scaled) (unscaled)
Objective...............: -4.9999999999990191e-03 -4.9999999999990191e-03
Dual infeasibility......: 3.4621194799910882e-12 3.4621194799910882e-12
Constraint violation....: 7.3553711558341242e-02 7.3553711558341242e-02
Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00
Overall NLP error.......: 7.3553711558341242e-02 7.3553711558341242e-02
Number of objective function evaluations = 2
Number of objective gradient evaluations = 2
Number of constraint evaluations = 2
Number of constraint Jacobian evaluations = 2
Number of Lagrangian Hessian evaluations = 1
Total wall-clock secs in solver (w/o fun. eval./lin. alg.) = 0.004
Total wall-clock secs in linear solver = 0.003
Total wall-clock secs in NLP function evaluations = 0.005
Total wall-clock secs = 0.011
EXIT: Maximum Number of Iterations Exceeded.
```