Skip to content

Commit 29d040d

Browse files
authored
Merge pull request #589 from control-toolbox/537-doc-flow-manual
Flow documentation: jumps on the costate
2 parents 699a229 + 6eaa0f4 commit 29d040d

8 files changed

Lines changed: 205 additions & 131 deletions

File tree

Project.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,3 @@ CommonSolve = "0.2"
2525
DocStringExtensions = "0.9"
2626
ExaModels = "0.8"
2727
julia = "1.10"
28-

docs/Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ LinearAlgebra = "1"
4040
MadNLP = "0.8"
4141
NLPModelsIpopt = "0.10"
4242
NLPModelsKnitro = "0.9"
43-
OrdinaryDiffEq = "6.93"
43+
OrdinaryDiffEq = "6"
4444
Plots = "1.40"
4545
Suppressor = "0.2"
4646
julia = "1"

docs/make.jl

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,10 @@ for Module in Modules
104104
DocMeta.setdocmeta!(Module, :DocTestSetup, :(using $Module); recursive=true)
105105
end
106106

107-
mkpath("./docs/src/assets")
108-
cp("./docs/Manifest.toml", "./docs/src/assets/Manifest.toml"; force=true)
109-
cp("./docs/Project.toml", "./docs/src/assets/Project.toml"; force=true)
107+
# For reproducibility
108+
mkpath(joinpath(@__DIR__, "src", "assets"))
109+
cp(joinpath(@__DIR__, "Manifest.toml"), joinpath(@__DIR__, "src", "assets", "Manifest.toml"), force = true)
110+
cp(joinpath(@__DIR__, "Project.toml"), joinpath(@__DIR__, "src", "assets", "Project.toml"), force = true)
110111

111112
repo_url = "github.com/control-toolbox/OptimalControl.jl"
112113

docs/src/assets/Manifest.toml

Lines changed: 110 additions & 120 deletions
Large diffs are not rendered by default.

docs/src/assets/Project.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ DataFrames = "1"
3434
Documenter = "1.8"
3535
DocumenterInterLinks = "1"
3636
DocumenterMermaid = "0.2"
37+
ExaModels = "0.8"
3738
JLD2 = "0.5"
3839
JSON3 = "1.14"
3940
LinearAlgebra = "1"

docs/src/manual-flow-ocp.md

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -462,7 +462,7 @@ where $ p^0 = -1 $ since we are in the normal case, and where $c(x) = x - l_b$.
462462
u(x) = 0.
463463
```
464464

465-
From the maximizing condition, along a boundary arc, we have $p(t) = 0$. Differentiating, we obtain $\dot{p}(t) = 2 x(t) - \mu(t) = 0$. Hence, along a boundary arc, the dual variable $\mu$ is given in feedback form by:
465+
From the maximisation condition, along a boundary arc, we have $p(t) = 0$. Differentiating, we obtain $\dot{p}(t) = 2 x(t) - \mu(t) = 0$. Hence, along a boundary arc, the dual variable $\mu$ is given in feedback form by:
466466

467467
```math
468468
\mu(x) = 2x.
@@ -503,3 +503,85 @@ p0 = -0.982237546583301
503503
xf, pf = f(t0, x0, p0, tf)
504504
xf
505505
```
506+
507+
## Jump on the costate
508+
509+
Let consider the following problem:
510+
511+
```@example main
512+
t0=0
513+
tf=1
514+
x0=[0, 1]
515+
l = 1/9
516+
@def ocp begin
517+
t ∈ [ t0, tf ], time
518+
x ∈ R², state
519+
u ∈ R, control
520+
x(t0) == x0
521+
x(tf) == [0, -1]
522+
x₁(t) ≤ l, (x_con)
523+
ẋ(t) == [x₂(t), u(t)]
524+
0.5∫(u(t)^2) → min
525+
end
526+
nothing # hide
527+
```
528+
529+
The pseudo-Hamiltonian of this problem is
530+
531+
```math
532+
H(x, p, u, \mu) = p_1\, x_2 + p_2\, u + 0.5\, p^0 u^2 + \mu\, c(x),
533+
```
534+
535+
where $ p^0 = -1 $ since we are in the normal case, and where the constraint is $c(x) = l - x_1 \ge 0$. Along a boundary arc, when $c(x(t)) = 0$, we have $x_1(t) = l$, so $\dot{x}_1(t) = x_2(t) = 0$. Differentiating again, we obtain $\dot{x}_2(t) = u(t) = 0$ (the constraint is of order 2). Hence, along a boundary arc, the control in feedback form is:
536+
537+
538+
```math
539+
u(x, p) = 0.
540+
```
541+
542+
From the maximisation condition, along a boundary arc, we have $p_2(t) = 0$. Differentiating, we obtain $\dot{p}_2(t) = -p_1(t) = 0$. Differentiating again, we obtain $\dot{p}_1(t) = \mu(t) = 0$. Hence, along a boundary arc, the Lagrange multiplier $\mu$ is given in feedback form by:
543+
544+
```math
545+
\mu(x, p) = 0.
546+
```
547+
548+
Outside a boundary arc, the maximisation condition gives $u(x, p) = p_2$. A deeper analysis of the problem shows that the optimal solution has 3 arcs, the first and the third ones are interior to the constraint. The second arc is a boundary arc, that is $x_1(t) = l$ along the second arc. We denote by $t_1$ and $t_2$ the two switching times. We have $t_1 = 3l = 1/3$ and $t_2 = 1 - 3l = 2/3$, since $l=1/9$. The initial costate solution is $p(0) = [-18, -6]$.
549+
550+
!!! danger "Important"
551+
552+
The costate is discontinuous at $t_1$ and $t_2$ with a jump of $18$.
553+
554+
Let us compute the solution concatenating the flows with the jumps.
555+
556+
```@example main
557+
t1 = 3l
558+
t2 = 1 - 3l
559+
p0 = [-18, -6]
560+
561+
fs = Flow(ocp,
562+
(x, p) -> p[2] # control along regular arc
563+
)
564+
fc = Flow(ocp,
565+
(x, p) -> 0, # control along boundary arc
566+
(x, u) -> l-x[1], # state constraint
567+
(x, p) -> 0 # Lagrange multiplier
568+
)
569+
570+
ν = 18 # jump value of p1 at t1 and t2
571+
572+
f = fs * (t1, [ν, 0], fc) * (t2, [ν, 0], fs)
573+
574+
xf, pf = f(t0, x0, p0, tf) # xf should be [0, -1]
575+
```
576+
577+
Let us solve the problem with a direct method to compare with the solution from the flow.
578+
579+
```@example main
580+
using NLPModelsIpopt
581+
582+
direct_sol = solve(ocp)
583+
plot(direct_sol; label="direct", size=(800, 700))
584+
585+
flow_sol = f((t0, tf), x0, p0; saveat=range(t0, tf, 100))
586+
plot!(flow_sol; label="flow", state_style=(color=3,), linestyle=:dash)
587+
```

test/Project.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@ Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
1212

1313
[compat]
1414
CTModels = "0.6"
15-
DifferentiationInterface = "0.6"
16-
ForwardDiff = "0.10"
15+
DifferentiationInterface = "0.7"
16+
ForwardDiff = "0.10, 1.0"
1717
LinearAlgebra = "1"
1818
MINPACK = "1.3"
1919
MadNLP = "0.8"
2020
NLPModelsIpopt = "0.10"
21-
OrdinaryDiffEq = "6.93"
21+
OrdinaryDiffEq = "6"
2222
SplitApplyCombine = "1.2"
2323
Test = "1"
2424
julia = "1.10"

test/extras/ocp.jl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,18 @@ using ADNLPModels
1111
using NLPModelsIpopt
1212
using MadNLP
1313

14+
n=2
1415
@def ocp begin
1516
tf R, variable
1617
t [0, tf], time
17-
x R², state
18+
x R^n, state
1819
u R, control
1920
-1 u(t) 1
2021
x(0) == [0, 0]
2122
x(tf) == [1, 0]
2223
0.05 tf Inf
2324
(t) == [x₂(t), u(t)]
2425
tf min
25-
end
26+
end true
2627

2728
sol = solve(ocp, :adnlp, :ipopt; print_level=5);

0 commit comments

Comments
 (0)