Turnpike (bang–singular–bang)
A scalar system,
using OptimalControl
using NLPModelsIpopt
using OrdinaryDiffEqTsit5
using NonlinearSolve
using PlotsThe problem
State
Definition
t0, tf = 0.0, 2.0
x0, xf = 1.0, 0.5
ocp = @def begin
t ∈ [t0, tf], time
x ∈ R, state
u ∈ R, control
-1 ≤ u(t) ≤ 1
x(t0) == x0
x(tf) == xf
ẋ(t) == u(t)
∫(x(t)^2) → min
endAbstract definition:
t ∈ [t0, tf], time
x ∈ R, state
u ∈ R, control
-1 ≤ u(t) ≤ 1
x(t0) == x0
x(tf) == xf
ẋ(t) == u(t)
∫(x(t) ^ 2) → min
The (autonomous) optimal control problem is of the form:
minimize J(x, u) = ∫ f⁰(x(t), u(t)) dt, over [0.0, 2.0]
subject to
ẋ(t) = f(x(t), u(t)), t in [0.0, 2.0] a.e.,
ϕ₋ ≤ ϕ(x(0.0), x(2.0)) ≤ ϕ₊,
u₋ ≤ u(t) ≤ u₊,
where x(t) ∈ R and u(t) ∈ R.Direct solution
direct_sol = solve(ocp; grid_size=100, display=false)
plt = plot(direct_sol, :state, :control; label="Direct")The state slides down to the origin, holds there, then climbs to the target. The flat middle stretch — the turnpike — is the singular arc, where
The singular control
The pseudo-Hamiltonian
The whole extremal is therefore bang–singular–bang:
| arc | interval | ||
|---|---|---|---|
| bang down | |||
| singular | |||
| bang up |
with
Indirect solution
Three constant-control flows, one per arc:
f_minus = Flow(ocp, (x, p) -> -1.0)
f_sing = Flow(ocp, (x, p) -> 0.0)
f_plus = Flow(ocp, (x, p) -> +1.0)OptimalControlFlow
├─ system: HamiltonianSystem
│ ├─ time_dependence: Autonomous
│ ├─ variable_dependence: Fixed
│ ├─ ComposedHamiltonian: autonomous, fixed (no variable)
│ │ natural call: h(x, p)
│ │ uniform call: h(t, x, p, v)
│ └─ backend: DifferentiationInterface{CPU}(ad_backend=AutoForwardDiff)
└─ integrator: SciML{CPU} (instance, id=:sciml)
├─ internalnorm = real_norm [default]
├─ alg = Tsit5 [default]
├─ reltol = 1.0e-8 [default]
├─ save_everystep = auto [default]
├─ abstol = 1.0e-8 [default]
├─ save_start = auto [default]
└─ dense = auto [default]
Tip: use describe(SciML{CPU}) to see all available options.The unknowns are the initial costate
function shoot!(s, ξ)
p0, t1, t2 = ξ[1], ξ[2], ξ[3]
x1, p1 = f_minus(t0, x0, p0, t1)
x2, p2 = f_sing(t1, x1, p1, t2)
xf_, _ = f_plus(t2, x2, p2, tf)
s[1] = x1 # enter the singular arc at x = 0
s[2] = p1 # switching function vanishes there
s[3] = xf_ - xf # hit the target
return nothing
endshoot! (generic function with 1 method)For a starting point, solve the same problem directly first, then read the singular arc off that solution. The switching function here is just the costate (
t = time_grid(direct_sol)
p = costate(direct_sol)
φ(τ) = p(τ) # switching function ≡ costate
η = 1e-3
t12 = t[abs.(φ.(t)) .≤ η] # grid points on the singular arc
p0_guess = p(t0)
t1_guess = minimum(t12)
t2_guess = maximum(t12)
(p0_guess, t1_guess, t2_guess)(-0.9801999456479715, 0.96, 1.52)nle!(s, ξ, _) = shoot!(s, ξ)
prob = NonlinearProblem(nle!, [p0_guess, t1_guess, t2_guess])
shooting_sol = NonlinearSolve.solve(prob; show_trace=Val(false))
p0_sol, t1_sol, t2_sol = shooting_sol.u3-element Vector{Float64}:
-1.0000000000000036
1.0000000000000002
1.4999999999999998s = zeros(3)
shoot!(s, shooting_sol.u)
s3-element Vector{Float64}:
8.034495536742733e-17
4.696458266519542e-16
1.1102230246251565e-16The solver lands on
Comparison
Concatenating the three constant-control flows at the solved switching times rebuilds the whole trajectory:
φ_bsb = f_minus * (t1_sol, f_sing) * (t2_sol, f_plus)
indirect_sol = φ_bsb((t0, tf), x0, p0_sol)
plot!(plt, indirect_sol, :state, :control;
label="Indirect", linestyle=:dash)The two curves overlap, and the objective is the expected
objective(direct_sol)0.3749500107307793See also
Singular control — a 2-D drift system where the singular control does need the
Lift/@LiePoisson-bracket chain.Shooting — the shooting method in general; this page is a worked case of switching times as unknowns.
Time minimisation (bang–bang) — the bang arcs on their own, with no singular arc between them.
Multi-phase flows — concatenating arc flows with
*.Goddard problem — the same direct-then-indirect workflow on a harder instance: a singular arc and a state-constraint boundary arc.