Skip to content

Commit 434761b

Browse files
committed
integrate CTBase update
1 parent d6263aa commit 434761b

10 files changed

+336
-124
lines changed

Project.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "OptimalControl"
22
uuid = "5f98b655-cc9a-415a-b60e-744165666948"
33
authors = ["Olivier Cots <[email protected]>"]
4-
version = "0.2.2"
4+
version = "0.3.0"
55

66
[deps]
77
CTBase = "54762871-cc72-4466-b8e8-f6c8b58076cd"
@@ -11,7 +11,7 @@ HamiltonianFlows = "5fb78580-10a0-4606-82bc-07a60f425ab3"
1111
Reexport = "189a3867-3050-52da-a836-e630ba90ab69"
1212

1313
[compat]
14-
CTBase = "0.2"
14+
CTBase = "0.4"
1515
CTDirect = "0.1"
1616
CTDirectShooting = "0.1"
1717
HamiltonianFlows = "1.0"

examples/basic_f.ipynb

+36-16
Large diffs are not rendered by default.

examples/callbacks-print.jl

+3-3
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ A = [ 0 1
1818
0 0 ]
1919
B = [ 0
2020
1 ]
21-
constraint!(ocp, :dynamics, (x, u) -> A*x + B*u[1])
22-
objective!(ocp, :lagrange, (x, u) -> 0.5u[1]^2)
21+
constraint!(ocp, :dynamics, (x, u) -> A*x + B*u)
22+
objective!(ocp, :lagrange, (x, u) -> 0.5u^2)
2323

2424
# replace default callback
2525
function myprint(i, sᵢ, dᵢ, Uᵢ, gᵢ, fᵢ)
@@ -52,4 +52,4 @@ function myprint3(i, sᵢ, dᵢ, xᵢ, gᵢ, fᵢ)
5252
old_f = fᵢ
5353
end
5454
cbs = (PrintCallback(myprint3, priority=0),)
55-
sol = solve(ocp, :direct, :shooting, callbacks=cbs);
55+
sol = solve(ocp, :direct, :shooting, callbacks=cbs)

examples/callbacks-stop.jl

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ A = [ 0 1
1818
0 0 ]
1919
B = [ 0
2020
1 ]
21-
constraint!(ocp, :dynamics, (x, u) -> A*x + B*u[1])
22-
objective!(ocp, :lagrange, (x, u) -> 0.5u[1]^2)
21+
constraint!(ocp, :dynamics, (x, u) -> A*x + B*u)
22+
objective!(ocp, :lagrange, (x, u) -> 0.5u^2)
2323

2424
# replace default stop callbacks
2525
function mystop(i, sᵢ, dᵢ, xᵢ, gᵢ, fᵢ, ng₀, oTol, aTol, sTol, iterations)

examples/direct-shooting.jl

+3-3
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ A = [ 0 1
1616
0 0 ]
1717
B = [ 0
1818
1 ]
19-
constraint!(ocp, :dynamics, (x, u) -> A*x + B*u[1])
20-
objective!(ocp, :lagrange, (x, u) -> 0.5u[1]^2)
19+
constraint!(ocp, :dynamics, (x, u) -> A*x + B*u)
20+
objective!(ocp, :lagrange, (x, u) -> 0.5u^2)
2121

2222
# initial iterate
2323
u_sol(t) = 6.0-12.0*t # solution
@@ -34,4 +34,4 @@ ps = plot(sol, size=(800, 400))
3434
# plot target
3535
point_style = (color=:black, seriestype=:scatter, markersize=3, markerstrokewidth=0, label="")
3636
plot!(ps[1], [tf], [xf[1]]; point_style...)
37-
plot!(ps[1], [tf], [xf[2]]; point_style...)
37+
plot!(ps[2], [tf], [xf[2]]; point_style...)

examples/goddard.jl

+35-36
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
### Goddard
22

33
## Direct solve
4-
54
using OptimalControl
65
using Plots
7-
unicodeplots()
6+
#unicodeplots()
87

98
# Parameters
109
const Cd = 310
@@ -46,37 +45,36 @@ function F1(x)
4645
return F
4746
end
4847

49-
f(x, u) = F0(x) + u[1]*F1(x)
48+
f(x, u) = F0(x) + u*F1(x)
5049

5150
constraint!(ocp, :dynamics, f)
5251

5352
# Solve
54-
sol = solve(ocp)
55-
plot(sol)
53+
direct_sol = solve(ocp)
54+
plot(direct_sol)
5655

5756
## Indirect solve
58-
5957
using MINPACK
6058

6159
# Bang controls
62-
u0(x, p) = [0.]
63-
u1(x, p) = [1.]
60+
u0(x, p) = 0.
61+
u1(x, p) = 1.
6462

6563
# Computation of singular control of order 1
6664
H0(x, p) = p' * F0(x)
6765
H1(x, p) = p' * F1(x)
6866
H01 = Poisson(H0, H1)
6967
H001 = Poisson(H0, H01)
7068
H101 = Poisson(H1, H01)
71-
us(x, p) = [-H001(x, p) / H101(x, p)]
69+
us(x, p) = -H001(x, p) / H101(x, p)
7270

7371
# Computation of boundary control
7472
remove_constraint!(ocp, :eq1)
7573
remove_constraint!(ocp, :eq3)
7674
constraint!(ocp, :boundary, (t0, x0, tf, xf) -> xf[3], mf, :eq4) # one value => equality (not boxed inequality); changed to equality constraint for shooting
7775
#
7876
g(x) = constraint(ocp, :eq2, :upper)(x, 0) # g(x, u) ≥ 0 (cf. nonnegative multiplier)
79-
ub(x, _) = [-Ad(F0, g)(x) / Ad(F1, g)(x)]
77+
ub(x, _) = -Ad(F0, g)(x) / Ad(F1, g)(x)
8078
μb(x, p) = H01(x, p) / Ad(F1, g)(x)
8179

8280
f0 = Flow(ocp, u0)
@@ -101,20 +99,21 @@ function shoot!(s, p0, t1, t2, t3, tf) # B+ S C B0 structure
10199
end
102100

103101
# Initialisation from direct solution
104-
t = sol.T; t = (t[1:end-1] + t[2:end]) / 2
105-
x = [ sol.X[i, 1:3] for i 1:N+1 ]; x = (x[1:end-1] + x[2:end]) / 2
106-
u = [ sol.U[i, 1 ] for i 1:N+1 ]; u = (u[1:end-1] + u[2:end]) / 2
107-
p = [ sol.P[i, 1:3] for i 1:N ]
102+
t = direct_sol.times
103+
x = direct_sol.state
104+
u = direct_sol.control
105+
p = direct_sol.adjoint
106+
φ(t) = H1(x(t), p(t))
108107

109-
u_plot = plot(t, u, xlabel = "t", ylabel = "u", legend = false)
110-
H1_plot = plot(t, H1.(x, p), xlabel = "t", ylabel = "H1", legend = false)
111-
g_plot = plot(t, g.(x), xlabel = "t", ylabel = "g", legend = false)
112-
display(plot(u_plot, H1_plot, g_plot, layout=(3,1), size=(800,600)))
108+
u_plot = plot(t, t -> u(t)[1], xlabel = "t", ylabel = "u", legend = false)
109+
H1_plot = plot(t, φ, xlabel = "t", ylabel = "H1", legend = false)
110+
g_plot = plot(t, gx, xlabel = "t", ylabel = "g", legend = false)
111+
display(plot(u_plot, H1_plot, g_plot, layout=(3,1), size=(400,300)))
113112

114113
η = 1e-3
115-
t13 = t[ abs.(H1.(x, p)) .≤ η ]
116-
t23 = t[ 0 .≤ g.(x) .≤ η ]
117-
p0 = p[1]
114+
t13 = t[ abs.(φ.(t)) .≤ η ]
115+
t23 = t[ 0 .≤ (gx).(t) .≤ η ]
116+
p0 = p(t0)
118117
t1 = min(t13...)
119118
t2 = min(t23...)
120119
t3 = max(t23...)
@@ -125,22 +124,22 @@ println("Initial guess:\n", ξ)
125124

126125
# Solve
127126
nle = (s, ξ) -> shoot!(s, ξ[1:3], ξ[4], ξ[5], ξ[6], ξ[7])
128-
sol = fsolve(nle, ξ, show_trace=true)
129-
println(sol)
127+
indirect_sol = fsolve(nle, ξ, show_trace=true)
128+
println(indirect_sol)
130129

131130
# Plots
132-
p0 = sol.x[1:3]
133-
t1 = sol.x[4]
134-
t2 = sol.x[5]
135-
t3 = sol.x[6]
136-
tf = sol.x[7]
131+
p0 = indirect_sol.x[1:3]
132+
t1 = indirect_sol.x[4]
133+
t2 = indirect_sol.x[5]
134+
t3 = indirect_sol.x[6]
135+
tf = indirect_sol.x[7]
137136

138137
f1sb0 = f1 * (t1, fs) * (t2, fb) * (t3, f0) # concatenation of the Hamiltonian flows
139-
sol = f1sb0((t0, tf), x0, p0)
140-
r_plot = plot(sol, idxs=(0, 1), xlabel="t", label="r")
141-
v_plot = plot(sol, idxs=(0, 2), xlabel="t", label="v")
142-
m_plot = plot(sol, idxs=(0, 3), xlabel="t", label="m")
143-
pr_plot = plot(sol, idxs=(0, 4), xlabel="t", label="p_r")
144-
pv_plot = plot(sol, idxs=(0, 5), xlabel="t", label="p_v")
145-
pm_plot = plot(sol, idxs=(0, 6), xlabel="t", label="p_m")
146-
plot(r_plot, pr_plot, v_plot, pv_plot, m_plot, pv_plot, layout=(3, 2))
138+
flow_sol = f1sb0((t0, tf), x0, p0)
139+
r_plot = plot(flow_sol, idxs=(0, 1), xlabel="t", label="r")
140+
v_plot = plot(flow_sol, idxs=(0, 2), xlabel="t", label="v")
141+
m_plot = plot(flow_sol, idxs=(0, 3), xlabel="t", label="m")
142+
pr_plot = plot(flow_sol, idxs=(0, 4), xlabel="t", label="p_r")
143+
pv_plot = plot(flow_sol, idxs=(0, 5), xlabel="t", label="p_v")
144+
pm_plot = plot(flow_sol, idxs=(0, 6), xlabel="t", label="p_m")
145+
plot(r_plot, pr_plot, v_plot, pv_plot, m_plot, pv_plot, layout=(3, 2), size=(600, 300))

examples/goddard_f.ipynb

+229-41
Large diffs are not rendered by default.

examples/initialization.jl

+15-14
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ using OptimalControl
22
#
33
using Printf
44
using LinearAlgebra
5+
#
56

67
# description of the optimal control problem
78
t0 = 0
@@ -20,8 +21,8 @@ A = [ 0 1
2021
0 0 ]
2122
B = [ 0
2223
1 ]
23-
constraint!(ocp, :dynamics, (x, u) -> A*x + B*u[1])
24-
objective!(ocp, :lagrange, (x, u) -> 0.5u[1]^2)
24+
constraint!(ocp, :dynamics, (x, u) -> A*x + B*u)
25+
objective!(ocp, :lagrange, (x, u) -> 0.5u^2)
2526

2627
# solution
2728
u_sol(t) = 6.0-12.0*t # solution
@@ -57,19 +58,19 @@ end
5758
# --------------------------------------------------------------------------------------------------
5859
# resolution
5960

60-
T_default = OptimalControl.__grid(t0, tf)
61+
T_default = range(t0, tf, CTBase.__grid_size_direct_shooting())
6162

6263
# init=nothing, grid=nothing
6364
sol = solve(ocp, :direct, :shooting, callbacks=(PrintCallback(my_cb_print(T_default)),))
6465
sol_1 = sol
65-
println(sol.T)
66+
println(time_steps(sol))
6667

6768
# init=nothing, grid=T
6869
# the grid T may be non uniform
6970
N = 101
7071
T = range(t0, tf, N)
7172
sol = solve(ocp, :direct, :shooting, grid=T, callbacks=(PrintCallback(my_cb_print(T)),))
72-
println(sol.T)
73+
println(time_steps(sol))
7374

7475
# init=U, grid=nothing
7576
# we assume U is given on a uniform grid
@@ -78,15 +79,15 @@ N = 101
7879
T = range(t0, tf, N)
7980
U = [[u_sol(T[i])-1.0] for i = 1:N-1]
8081
sol = solve(ocp, :direct, :shooting, init=U, callbacks=(PrintCallback(my_cb_print(T_default)),))
81-
println(sol.T)
82+
println(time_steps(sol))
8283

8384
# init=U, grid=T
8485
# the grid T may be non uniform
8586
N = 101
8687
T = range(t0, tf, N)
8788
U = [[u_sol(T[i])-1.0] for i = 1:N-1]
8889
sol = solve(ocp, :direct, :shooting, init=U, grid=T, callbacks=(PrintCallback(my_cb_print(T)),))
89-
println(sol.T)
90+
println(time_steps(sol))
9091

9192
# init=(T,U), grid=nothing
9293
# if U is not given on a uniform grid, you must give the grid
@@ -96,7 +97,7 @@ T = range(t0, tf, N)
9697
T = T.^2 # t0 = 0 and tf = 1 so it is ok
9798
U = [[u_sol(T[i])-1.0] for i = 1:N-1]
9899
sol = solve(ocp, :direct, :shooting, init=(T, U), callbacks=(PrintCallback(my_cb_print(T_default)),))
99-
println(sol.T)
100+
println(time_steps(sol))
100101

101102
# init=(T,U), grid=T_
102103
# if U is not given on a uniform grid, you must give the grid
@@ -106,33 +107,33 @@ T = T.^2 # t0 = 0 and tf = 1 so it is ok
106107
U = [[u_sol(T[i])-1.0] for i = 1:N-1]
107108
T_ = range(t0, tf, 301)
108109
sol = solve(ocp, :direct, :shooting, init=(T, U), grid=T_, callbacks=(PrintCallback(my_cb_print(T_)),))
109-
println(sol.T)
110+
println(time_steps(sol))
110111

111112
# init=t->u(t), grid=nothing
112113
u(t) = [u_sol(t)-1.0]
113114
sol = solve(ocp, :direct, :shooting, init=u, callbacks=(PrintCallback(my_cb_print(T_default)),))
114-
println(sol.T)
115+
println(time_steps(sol))
115116

116117
# init=t->u(t), grid=T
117118
N = 101
118119
T = range(t0, tf, N)
119120
u(t) = [u_sol(t)-1.0]
120121
sol = solve(ocp, :direct, :shooting, init=u, grid=T, callbacks=(PrintCallback(my_cb_print(T)),))
121-
println(sol.T)
122+
println(time_steps(sol))
122123

123124
# init=sol, grid=nothing
124125
sol = solve(ocp, :direct, :shooting, init=sol_1, callbacks=(PrintCallback(my_cb_print(T_default)),))
125-
println(sol.T)
126+
println(time_steps(sol))
126127

127128
# init=sol, grid=T
128129
N = 101
129130
T = range(t0, tf, N)
130131
sol = solve(ocp, :direct, :shooting, init=sol_1, grid=T, callbacks=(PrintCallback(my_cb_print(T)),))
131-
println(sol.T)
132+
println(time_steps(sol))
132133

133134
# make direct solve to init a direct shooting
134135
N = 201
135136
T = range(t0, tf, N)
136137
sol = solve(ocp, :direct, grid_size=N)
137138
sol = solve(ocp, :direct, :shooting, init=sol, grid=T, callbacks=(PrintCallback(my_cb_print(T)),))
138-
println(sol.T)
139+
println(time_steps(sol))

src/OptimalControl.jl

+5-1
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,13 @@ const __display = CTBase.__display
1919
include("flows.jl")
2020
include("solve.jl")
2121

22+
# ----------------------------------------
23+
# to remove when put in the right package
24+
include("CTBase.jl")
25+
# ----------------------------------------
26+
2227
# export functions only for user
2328
export solve
24-
export plot, plot!
2529
export Flow
2630

2731
end

test/test_goddard_indirect.jl

+6-6
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ time!(ocp, :initial, t0) # if not provided, final time is free
1717
state!(ocp, 3) # state dim
1818
control!(ocp, 1) # control dim
1919
constraint!(ocp, :initial, x0)
20-
constraint!(ocp, :control, u -> u[1], 0., 1.)
20+
constraint!(ocp, :control, u -> u, 0., 1.)
2121
constraint!(ocp, :mixed, (x, u) -> x[1], r0, Inf, :state_con1)
2222
constraint!(ocp, :mixed, (x, u) -> x[2], 0., vmax, :state_con2)
2323
constraint!(ocp, :mixed, (x, u) -> x[3], m0, mf, :state_con3)
@@ -27,31 +27,31 @@ objective!(ocp, :mayer, (t0, x0, tf, xf) -> xf[1], :max)
2727
D(x) = Cd * x[2]^2 * exp(-β*(x[1]-1))
2828
F0(x) = [ x[2], -D(x)/x[3]-1/x[1]^2, 0 ]
2929
F1(x) = [ 0, Tmax/x[3], -b*Tmax ]
30-
f(x, u) = F0(x) + u[1]*F1(x)
30+
f(x, u) = F0(x) + u*F1(x)
3131
constraint!(ocp, :dynamics, f)
3232

3333
# --------------------------------------------------------
3434
# Indirect
3535

3636
# Bang controls
37-
u0(x, p) = [0.]
38-
u1(x, p) = [1.]
37+
u0(x, p) = 0.
38+
u1(x, p) = 1.
3939

4040
# Computation of singular control of order 1
4141
H0(x, p) = p' * F0(x)
4242
H1(x, p) = p' * F1(x)
4343
H01 = Poisson(H0, H1)
4444
H001 = Poisson(H0, H01)
4545
H101 = Poisson(H1, H01)
46-
us(x, p) = [-H001(x, p) / H101(x, p)]
46+
us(x, p) = -H001(x, p) / H101(x, p)
4747

4848
# Computation of boundary control
4949
remove_constraint!(ocp, :state_con1)
5050
remove_constraint!(ocp, :state_con3)
5151
constraint!(ocp, :boundary, (t0, x0, tf, xf) -> xf[3], mf, :final_con) # one value => equality (not boxed inequality)
5252

5353
g(x) = constraint(ocp, :state_con2, :upper)(x, 0.0) # g(x, u) ≥ 0 (cf. nonnegative multiplier)
54-
ub(x, _) = [-Ad(F0, g)(x) / Ad(F1, g)(x)]
54+
ub(x, _) = -Ad(F0, g)(x) / Ad(F1, g)(x)
5555
μb(x, p) = H01(x, p) / Ad(F1, g)(x)
5656

5757
f0 = Flow(ocp, u0)

0 commit comments

Comments
 (0)