Skip to content

Migrating from v2.0 ​

OptimalControl.jl v2.1.0-beta reorganised the ecosystem so that every name has exactly one owner. Most of the changes are mechanical: a Lie becomes an ad, a success becomes a successful, and the old spelling fails with a message naming its replacement. A few changes are semantic and do not announce themselves; they get their own warnings below.

The messages need 2.2.0-beta or newer

The old spellings stopped working in v2.1.0-beta. The messages that name their replacements (What you get instead of an error) came in 2.2.0-beta. With exactly v2.1.0-beta, the same mistakes give a bare UndefVarError or MethodError.

The full record of the breaking changes, with the reasons, is BREAKING.md in the repository; this page says what to change in a script.

Start here: Flow needs an integrator ​

This is the most common first failure. The ODE integrators are no longer a dependency of the package: load one before building a flow.

julia
using OptimalControl
using OrdinaryDiffEqTsit5   # required before any Flow(...)

f = Flow(ocp, (x, p) -> p[2])

Without it, Flow fails with an ExtensionError that names the package to load. The direct method, solve, does not need it. See Installation and Flows overview.

What was renamed ​

v2.0NowNotes
OptimalControl.VectorField, OptimalControl.Hamiltonian, …VectorField, Hamiltonian, …exported; the qualified form still works
Lie(X, f)ad(X, f)Lie throws, naming ad
X ⋅ fad(X, f)no operator; X ⋅ f throws, naming ad, when X is a VectorField
HamiltonianLiftLift(f) to build; OptimalControl.LiftedHamiltonianFunction to name the typerenamed and re-parented, see What changed meaning silently
autonomous=, variable=, inplace= (constructor keywords)is_autonomous=, is_variable=, is_inplace=on VectorField, Hamiltonian, @Lie, and the other constructors
Flow(f) with f::FunctionFlow(VectorField(f)), Flow(Hamiltonian(f)), Flow(HamiltonianVectorField(f))a function alone does not say which flow to build
Flow(ocp, u, g, μ)Flow(ocp, u; constraint=g, multiplier=μ)two keywords, given together
f(t0, x0, p0, tf, λ), f(t0, x0, tf, λ)f(t0, x0, p0, tf; variable=λ), f(t0, x0, tf; variable=λ)variable= is a keyword, required on a problem with a variable
augment=truevariable_costate=truereturns (xf, pf, pvf)
CTSolvers.Modelers.ADNLP(), CTDirect.Collocation()OptimalControl.ADNLP(), OptimalControl.Collocation()the modules CTSolvers and CTDirect are not exported
time(ocp), time(sol)times(ocp), time_grid(sol)time is Base.time
success(sol)successful(sol)success is Base.success

What changed shape ​

The flow call. The variable is passed by keyword, never by position:

julia
f(t0, x0, p0, tf, λ)                                  
f(t0, x0, p0, tf; augment=true)                       
f(t0, x0, p0, tf; variable=λ)                         
f(t0, x0, p0, tf; variable=λ, variable_costate=true)  

On a problem with a variable, variable= is required: without it, the call throws, saying what to pass. The call also accepts unsafe=true, which does not check the return code of the integrator: inside a shooting function, a failed integration then shows in the residual instead of stopping the solver (see Shooting). The integrator options (saveat=, abstol=, reltol=, alg=, …) are no longer accepted by the call. Pass them when the flow is built:

julia
f = Flow(ocp, (x, p) -> p[2]; abstol=1e-8)
f(t0, x0, p0, tf)

Constrained flows. The constraint and the multiplier are keywords, given together:

julia
fb = Flow(ocp, u, g, μ)                         
fb = Flow(ocp, u; constraint=g, multiplier=μ)   

One without the other is an IncorrectArgument. constraint= accepts a function, a typed constraint, or a Symbol naming a path constraint of the problem, constraint=:vmax. The Symbol form uses the constraint function stored in the problem, without its bound: see the caveat on Constrained arcs.

Constructor keywords take an is_ prefix, on VectorField, Hamiltonian, @Lie, and the other constructors:

julia
VectorField(f; autonomous=false, variable=true)        
@Lie [X, Y] autonomous=false
VectorField(f; is_autonomous=false, is_variable=true)   
@Lie [X, Y] is_autonomous=false

The old keyword on @Lie raises an IncorrectArgument that lists the accepted keywords. On VectorField and Hamiltonian, it raises a MethodError, "got unsupported keyword argument".

What changed meaning silently ​

Three changes do not raise an error.

Lift(f::Function) is no longer an AbstractHamiltonian

In v2.0, lifting a plain function and lifting a VectorField gave the same kind of object. Now, the lift of a function is a function, OptimalControl.LiftedHamiltonianFunction:

julia
H = Lift(f)                  # f::Function
H isa AbstractHamiltonian    # false now, true in v2.0

A test isa AbstractHamiltonian on it is now false. The lift of a VectorField is still a Hamiltonian. See Lift.

OpenLoop checks the arity of the law when the flow runs

An open-loop control is a function of time, u(t), or u(t, v) with a variable. A function without argument is accepted when the law is built, and fails only when the flow runs, with a MethodError far from the mistake (CTBase#570):

julia
bad_law = OpenLoop(() -> 1.0)                          # accepted
Flow(ControlledVectorField(fc), bad_law)(t0, x0, tf)   # MethodError here

See Simulation.

The old state-flow call runs on a flow with a costate

In v2.0, a flow of the state was called f(t0, x0, tf, λ), with the variable in the 4th position. The flow of a problem without a variable is called f(t0, x0, p0, tf), also with four arguments. Called the old way, it runs, with the arguments shifted: tf is taken as p0, and λ as tf.

julia
f(t0, x0, tf, λ)   # runs as f(t0, x0, p0=tf, tf=λ)

It fails only when the shapes do not match. Check these calls by hand.

What you get instead of an error ​

The removed spellings throw a PreconditionError naming their replacement. With a problem ocp with a variable, its solution sol, a vector field X and a function f:

julia
julia> Lie(X, f)
PreconditionError → Lie, deprecated.jl:52
│
│  `Lie(X, f) / Lie(X, Y)` is deprecated
│
│  Reason  this spelling was removed in v2.1.0-beta
│
│  Hint    use ad(X, f) or ad(X, Y)
└─
julia
julia> X ⋅ f
PreconditionError → dot, deprecated.jl:62
│
│  `X \cdot f` is deprecated
│
│  Reason  this spelling was removed in v2.1.0-beta
│
│  Hint    use ad(X, f)
└─
julia
julia> HamiltonianLift(f)
PreconditionError → HamiltonianLift, deprecated.jl:72
│
│  `HamiltonianLift` is deprecated
│
│  Reason  this spelling was removed in v2.1.0-beta
│
│  Hint    use Lift(f) for a plain function, or CTLie.LiftedHamiltonianFunction
└─
julia
julia> time(ocp)
PreconditionError → time, deprecated.jl:82
│
│  `time(ocp)` is deprecated
│
│  Reason  this spelling was removed in v2.1.0-beta
│
│  Hint    use times(ocp)
└─
julia
julia> time(sol)
PreconditionError → time, deprecated.jl:84
│
│  `time(sol)` is deprecated
│
│  Reason  this spelling was removed in v2.1.0-beta
│
│  Hint    use time_grid(sol)
└─
julia
julia> success(sol)
PreconditionError → success, deprecated.jl:86
│
│  `success(sol)` is deprecated
│
│  Reason  this spelling was removed in v2.1.0-beta
│
│  Hint    use successful(sol)
└─
julia
julia> Flow(f)
PreconditionError → Flow, deprecated.jl:91
│
│  `Flow(f::Function)` is deprecated
│
│  Reason  this spelling was removed in v2.1.0-beta
│
│  Hint    use Flow(VectorField(f)), Flow(Hamiltonian(f)), or Flow(HamiltonianVectorField(f))
└─
julia
julia> Flow(ocp, (x, p, v) -> 0, g, μ)
PreconditionError → top-level scope, REPL[1]:2
│
│  Flow(ocp, …) with extra positional arguments is not supported
│
│  Reason   passing a control law, state constraint or multiplier as a positional argument is not handled by the OCP flow constructor
│
│  Context  Flow(ocp::CTModels.Models.Model) — positional-argument guard
│  Hint     Flow(ocp, u) takes the control law positionally; pass constraint/multiplier as keywords: Flow(ocp, u; constraint=g, multiplier=μ)
└─

On the flow fh of the problem, and on the flow fs of a state with a variable:

julia
julia> fh(t0, x0, p0, tf, λ)
PreconditionError → AbstractFlow, deprecated.jl:102
│
│  `f(t0, x0, p0, tf, lambda)` is deprecated
│
│  Reason  this spelling was removed in v2.1.0-beta
│
│  Hint    use f(t0, x0, p0, tf; variable=lambda)
└─
julia
julia> fs(t0, 1.0, tf, λ)
PreconditionError → AbstractFlow, deprecated.jl:108
│
│  `f(t0, x0, tf, lambda)` is deprecated
│
│  Reason  this spelling was removed in v2.1.0-beta
│
│  Hint    use f(t0, x0, tf; variable=lambda)
└─
julia
julia> fh(t0, x0, p0, tf; variable=λ, augment=true)
PreconditionError → top-level scope, REPL[1]:2
│
│  augment=true is not supported (removed in v2.1.0-beta)
│
│  Reason   the `augment` keyword was renamed to `variable_costate`, with the same behaviour
│
│  Context  OptimalControlFlow point evaluation — deprecated `augment` keyword guard
│  Hint     use variable_costate=true instead of augment=true
└─

X ⋅ f is caught when X is a VectorField. With a plain function X, as in v2.0, it raises a MethodError about iterate.

What raises another error ​

SpellingWhat happensWrite instead
f(t0, x0, p0, tf; saveat=…), and the other integrator options on a callMethodError, "unsupported keyword argument"Flow(…; saveat=…), when the flow is built
CTSolvers.Modelers.ADNLP(), CTDirect.Collocation()UndefVarError on CTSolvers or CTDirectOptimalControl.ADNLP(), OptimalControl.Collocation()
@Lie [X, Y] autonomous=falseIncorrectArgument, with the accepted keywords@Lie [X, Y] is_autonomous=false
VectorField(f; autonomous=false), Hamiltonian(h; variable=true)MethodError, "unsupported keyword argument"is_autonomous=, is_variable=

Initial guesses as named tuples ​

@init is the recommended way to write an initial guess. The named tuple of v2.0 still works, with the fields state, control and variable (see Initial guess), and also with the labels of the components:

julia
sol = solve(ocp; init=(state=[-0.2, 0.1], control=-0.2))
sol = solve(ocp; init=(q=-1.0, v=0.0, u=0.1, tf=2.0))

@init checks the labels against the problem. In both forms, the costate and the multipliers cannot be given a guess.

From v1.x to v2.0 ​

For the older migration from v1.x to v2.0 (the direct-mode API, option routing, the methods), see the second section of BREAKING.md.