Skip to content

Commit

Permalink
Merge pull request #323 from control-toolbox/322-dev-compat-update
Browse files Browse the repository at this point in the history
up compat
  • Loading branch information
ocots authored Aug 27, 2024
2 parents 33d0b8c + 7d65575 commit 68bd783
Show file tree
Hide file tree
Showing 18 changed files with 106 additions and 83 deletions.
6 changes: 3 additions & 3 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ CommonSolve = "38540f10-b2f7-11e9-35d8-d573e4eb0ff2"
DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"

[compat]
CTBase = "0.12"
CTDirect = "0.11"
CTFlows = "0.5"
CTBase = "0.13"
CTDirect = "0.12"
CTFlows = "0.6"
CommonSolve = "0.2"
DocStringExtensions = "0.9"
julia = "1.10"
17 changes: 17 additions & 0 deletions docs/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,22 @@ Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
Roots = "f2b01f46-fcfa-551c-844a-d8ac1e96c665"

[compat]
BenchmarkTools = "1.5"
CTBase = "0.13"
CTDirect = "0.12"
CTFlows = "0.6"
CommonSolve = "0.2"
DifferentiationInterface = "0.5"
Documenter = "1.6"
DocumenterMermaid = "0.1"
ForwardDiff = "0.10"
Interpolations = "0.15"
JLD2 = "0.4"
JSON3 = "1.14"
MINPACK = "1.3"
MadNLP = "0.8"
NLPModelsIpopt = "0.10"
Percival = "0.7"
Plots = "1.40"
Roots = "2.1"
julia = "1.10"
2 changes: 1 addition & 1 deletion docs/src/tutorial-basic-example.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ println("Objective from loaded solution: ", sol_reloaded.objective)
# JSON export / read
export_ocp_solution(sol, filename_prefix="my_solution")
sol_json = import_ocp_solution("my_solution")
sol_json = import_ocp_solution(ocp, filename_prefix="my_solution")
println("Objective from JSON discrete solution: ", sol_json.objective)
```

6 changes: 3 additions & 3 deletions docs/src/tutorial-continuation.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ objective!(ocp, :mayer, (x0, xf, v) -> xf[1], :max)
dynamics!(ocp, (x, u, v) -> F0(x) + u*F1(x) )
sol0 = solve(ocp; display=false)
@printf("Objective for reference solution %.6f\n", sol0.objective)
@printf("Objective for reference solution %.6f\n", objective(sol0))
```

Then we perform the continuation on the maximal thrust.
Expand All @@ -115,9 +115,9 @@ obj_list = []
for Tmax_local=3.5:-0.5:1
global Tmax = Tmax_local
global sol = solve(ocp; display=false, init=sol)
@printf("Tmax %.2f objective %.6f iterations %d\n", Tmax, sol.objective, sol.iterations)
@printf("Tmax %.2f objective %.6f iterations %d\n", Tmax, objective(sol), iterations(sol))
push!(Tmax_list, Tmax)
push!(obj_list, sol.objective)
push!(obj_list, objective(sol))
end
```

Expand Down
2 changes: 1 addition & 1 deletion docs/src/tutorial-flow.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ plot(sol)
You can notice from the graph of `v` that the integrator has made very few steps:

```@example main
sol.times
time_grid(sol)
```

To have a better visualisation (the accuracy won't change), you can provide a fine grid.
Expand Down
8 changes: 4 additions & 4 deletions docs/src/tutorial-goddard.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,10 @@ arc is with zero control. Note that the switching function vanishes along the si
boundary arcs.

```@example main
t = direct_sol.times
x = direct_sol.state
u = direct_sol.control
p = direct_sol.costate
t = time_grid(direct_sol)
x = state(direct_sol)
u = control(direct_sol)
p = costate(direct_sol)
H1 = Lift(F1) # H1(x, p) = p' * F1(x)
φ(t) = H1(x(t), p(t)) # switching function
Expand Down
34 changes: 17 additions & 17 deletions docs/src/tutorial-initial-guess.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ This will default to initialize all variables to 0.1.
```@example main
# solve the optimal control problem without initial guess
sol = solve(ocp; display=false)
println("Number of iterations: ", sol.iterations)
println("Number of iterations: ", iterations(sol))
nothing # hide
```

Expand All @@ -57,10 +57,10 @@ Note that the following formulations are equivalent to not giving an initial gue

```@example main
sol = solve(ocp; init=nothing, display=false)
println("Number of iterations: ", sol.iterations)
println("Number of iterations: ", iterations(sol))
sol = solve(ocp; init=(), display=false)
println("Number of iterations: ", sol.iterations)
println("Number of iterations: ", iterations(sol))
nothing # hide
```

Expand All @@ -74,23 +74,23 @@ We first illustrate the constant initial guess, using vectors or scalars accordi
```@example main
# solve the optimal control problem with initial guess with constant values
sol = solve(ocp; init=(state=[-0.2, 0.1], control=-0.2, variable=0.05), display=false)
println("Number of iterations: ", sol.iterations)
println("Number of iterations: ", iterations(sol))
nothing # hide
```

Partial initializations are also valid, as shown below. Note the ending comma when a single argument is passed (tuple).
```@example main
# initialisation only on the state
sol = solve(ocp; init=(state=[-0.2, 0.1],), display=false)
println("Number of iterations: ", sol.iterations)
println("Number of iterations: ", iterations(sol))
# initialisation only on the control
sol = solve(ocp; init=(control=-0.2,), display=false)
println("Number of iterations: ", sol.iterations)
println("Number of iterations: ", iterations(sol))
# initialisation only on the state and the variable
sol = solve(ocp; init=(state=[-0.2, 0.1], variable=0.05), display=false)
println("Number of iterations: ", sol.iterations)
println("Number of iterations: ", iterations(sol))
nothing # hide
```

Expand All @@ -103,7 +103,7 @@ x(t) = [ -0.2t, 0.1t ]
u(t) = -0.2t
sol = solve(ocp; init=(state=x, control=u, variable=0.05), display=false)
println("Number of iterations: ", sol.iterations)
println("Number of iterations: ", iterations(sol))
nothing # hide
```

Expand All @@ -120,7 +120,7 @@ x_vec = [[0, 0], [-0.1, 0.3], [-0.15,0.4], [-0.3, 0.5]]
u_vec = [0, -0.8, -0.3, 0]
sol = solve(ocp; init=(time=t_vec, state=x_vec, control=u_vec, variable=0.05), display=false)
println("Number of iterations: ", sol.iterations)
println("Number of iterations: ", iterations(sol))
nothing # hide
```

Expand All @@ -133,11 +133,11 @@ The constant, functional and vector initializations can be mixed, for instance a
```@example main
# we can mix constant values with functions of time
sol = solve(ocp; init=(state=[-0.2, 0.1], control=u, variable=0.05), display=false)
println("Number of iterations: ", sol.iterations)
println("Number of iterations: ", iterations(sol))
# wa can mix every possibility
sol = solve(ocp; init=(time=t_vec, state=x_vec, control=u, variable=0.05), display=false)
println("Number of iterations: ", sol.iterations)
println("Number of iterations: ", iterations(sol))
nothing # hide
```

Expand All @@ -153,24 +153,24 @@ sol_init = solve(ocp; display=false)
# solve the problem using solution as initial guess
sol = solve(ocp; init=sol_init, display=false)
println("Number of iterations: ", sol.iterations)
println("Number of iterations: ", iterations(sol))
nothing # hide
```

Note that you can also manually pick and choose which data to reuse from a solution, by recovering the
functions ```sol.state```, ```sol.control``` and the values ```sol.variable```.
functions ```state(sol)```, ```control(sol)``` and the values ```variable(sol)```.
For instance the following formulation is equivalent to the ```init=sol``` one.

```@example main
# use a previous solution to initialise picking data
sol = solve(ocp;
init = (
state = sol.state,
control = sol.control,
variable = sol.variable
state = state(sol),
control = control(sol),
variable = variable(sol)
),
display=false)
println("Number of iterations: ", sol.iterations)
println("Number of iterations: ", iterations(sol))
nothing # hide
```

Expand Down
24 changes: 12 additions & 12 deletions docs/src/tutorial-iss.md
Original file line number Diff line number Diff line change
Expand Up @@ -284,8 +284,8 @@ function pretty_plot(S, p0; Np0=20, kwargs...)
p0s = range(p0_min, p0_max, length=Np0)
for i ∈ eachindex(p0s)
sol = exp(p0s[i])
x = [sol.state(t) for t ∈ sol.times]
p = [sol.costate(t) for t ∈ sol.times]
x = [state(sol)(t) for t ∈ time_grid(sol)]
p = [costate(sol)(t) for t ∈ time_grid(sol)]
label = i==1 ? "extremals" : false
plot!(plt_flow, x, p, color=:blue, label=label)
end
Expand All @@ -296,8 +296,8 @@ function pretty_plot(S, p0; Np0=20, kwargs...)
ps = zeros(length(p0s), length(times))
for i ∈ eachindex(p0s)
sol = exp(p0s[i], saveat=times)
xs[i, :] .= sol.state.(times)
ps[i, :] .= sol.costate.(times)
xs[i, :] .= state(sol).(times)
ps[i, :] .= costate(sol).(times)
end
for j ∈ eachindex(times)
label = j==1 ? "flow at times" : false
Expand All @@ -310,8 +310,8 @@ function pretty_plot(S, p0; Np0=20, kwargs...)
# solution
sol = exp(p0_sol)
x = [sol.state(t) for t ∈ sol.times]
p = [sol.costate(t) for t ∈ sol.times]
x = [state(sol)(t) for t ∈ time_grid(sol)]
p = [costate(sol)(t) for t ∈ time_grid(sol)]
plot!(plt_flow, x, p, color=:red, linewidth=2, label="extremal solution")
plot!(plt_flow, [x[end]], [p[end]], seriestype=:scatter, color=:green, label=false)
Expand Down Expand Up @@ -347,8 +347,8 @@ function pretty_plot(S, p0; Np0=20, kwargs...) # hide
p0s = range(p0_min, p0_max, length=Np0) # hide
for i ∈ eachindex(p0s) # hide
sol = exp(p0s[i]) # hide
x = [sol.state(t) for t ∈ sol.times] # hide
p = [sol.costate(t) for t ∈ sol.times] # hide
x = [state(sol)(t) for t ∈ time_grid(sol)] # hide
p = [costate(sol)(t) for t ∈ time_grid(sol)] # hide
label = i==1 ? "extremals" : false # hide
plot!(plt_flow, x, p, color=:blue, label=label) # hide
end # hide
Expand All @@ -359,8 +359,8 @@ function pretty_plot(S, p0; Np0=20, kwargs...) # hide
ps = zeros(length(p0s), length(times)) # hide
for i ∈ eachindex(p0s) # hide
sol = exp(p0s[i], saveat=times) # hide
xs[i, :] .= sol.state.(times) # hide
ps[i, :] .= sol.costate.(times) # hide
xs[i, :] .= state(sol).(times) # hide
ps[i, :] .= costate(sol).(times) # hide
end # hide
for j ∈ eachindex(times) # hide
label = j==1 ? "flow at times" : false # hide
Expand All @@ -373,8 +373,8 @@ function pretty_plot(S, p0; Np0=20, kwargs...) # hide
# hide
# solution # hide
sol = exp(p0_sol) # hide
x = [sol.state(t) for t ∈ sol.times] # hide
p = [sol.costate(t) for t ∈ sol.times] # hide
x = [state(sol)(t) for t ∈ time_grid(sol)] # hide
p = [costate(sol)(t) for t ∈ time_grid(sol)] # hide
plot!(plt_flow, x, p, color=:red, linewidth=2, label="extremal solution") # hide
plot!(plt_flow, [x[end]], [p[end]], seriestype=:scatter, color=:green, label=false) # hide
# hide
Expand Down
12 changes: 6 additions & 6 deletions docs/src/tutorial-plot.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ optimal control problem.
t0 = 0
tf = 1
x0 = [ -1, 0 ]
p0 = sol.costate(t0)
p0 = costate(sol)(t0)
f = Flow(ocp, (x, p) -> p[2])
sol_flow = f( (t0, tf), x0, p0 )
plot(sol_flow)
Expand Down Expand Up @@ -152,18 +152,18 @@ You can of course create your own plots by getting the `state`, `costate` and `c

```@example main
using LinearAlgebra
t = sol.times
x = sol.state
p = sol.costate
u = sol.control
t = time_grid(sol)
x = state(sol)
p = costate(sol)
u = control(sol)
plot(t, norm∘u; label="‖u‖")
```

!!! note "Nota bene"

- The `norm` function is from `LinearAlgebra.jl`.
- The `∘` operator is the composition operator. Hence, `norm∘u` is the function `t -> norm(u(t))`.
- The `sol.state`, `sol.costate` and `sol.control` are functions that return the state, costate and control trajectories at a given time.
- The `state(sol)`, `costate(sol)` and `control(sol)` are functions that return the state, costate and control trajectories at a given time.


## Normalized time
Expand Down
4 changes: 2 additions & 2 deletions docs/src/tutorial-solve.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,14 +153,14 @@ There are `init`, `grid_size` and `time_grid`.

```@example main
sol = solve(ocp; grid_size=10, display=false)
sol.times
time_grid(sol)
```

Or with MadNLP.jl:

```@example main
sol = solve(ocp, :madnlp; grid_size=10, display=false)
sol.times
time_grid(sol)
```

### NLPModelsIpopt
Expand Down
7 changes: 4 additions & 3 deletions src/OptimalControl.jl
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,10 @@ export OptimalControlModel, OptimalControlSolution
export Autonomous, NonAutonomous
export NonFixed, Fixed
export Model, __OCPModel
export variable!,
time!, constraint!, dynamics!, objective!, state!, control!, remove_constraint!, constraint
#export is_time_independent, is_time_dependent, is_min, is_max, is_variable_dependent, is_variable_independent
export variable!, time!, constraint!, dynamics!, objective!, state!, control!, remove_constraint!
export constraint
export time_grid, control, state, variable, costate, objective
export iterations, stopping, message, infos
export Lie, @Lie, Poisson, Lift, , ∂ₜ
export @def
export ct_repl, ct_repl_update_model
Expand Down
5 changes: 5 additions & 0 deletions test/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,9 @@ SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[compat]
CTDirect = "0.12"
NLPModelsIpopt = "0.10"
NonlinearSolve = "3.14"
OrdinaryDiffEq = "6.88"
SciMLBase = "2.48"
julia = "1.10"
2 changes: 1 addition & 1 deletion test/test_basic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ function test_basic()
end

sol = solve(ocp; display = false)
@test sol.objective 6 atol = 1e-2
@test objective(sol) 6 atol = 1e-2
end
6 changes: 3 additions & 3 deletions test/test_continuation.jl
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ function test_continuation()
ocp = ocp_T(T)
sol = solve(ocp, print_level = 0, init = init)
init = sol
push!(obj_list, sol.objective)
push!(obj_list, objective(sol))
end
@test obj_list [12, 1.5, 0.44, 0.19, 0.096] rtol = 1e-2
end
Expand Down Expand Up @@ -69,7 +69,7 @@ function test_continuation()
ocp = myocp(ρ)
sol = solve(ocp, print_level = 0, init = init)
init = sol
push!(obj_list, sol.objective)
push!(obj_list, objective(sol))
end
@test obj_list [-0.034, -1.7, -6.2, -35, -148] rtol = 1e-2
end
Expand All @@ -86,7 +86,7 @@ function test_continuation()
for Tmax = 3.5:-0.5:1
sol = solve(goddard(Tmax = Tmax).ocp, print_level = 0, init = sol)
push!(Tmax_list, Tmax)
push!(obj_list, sol.objective)
push!(obj_list, objective(sol))
end
@test obj_list [1.0125, 1.0124, 1.0120, 1.0112, 1.0092, 1.0036] rtol = 1e-2

Expand Down
4 changes: 2 additions & 2 deletions test/test_goddard_direct.jl
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
function test_goddard_direct()

# goddard with state constraint - maximize altitude
ocp, objective = Goddard()
ocp, obj = Goddard()

# initial guess (constant state and control functions)
init = (state = [1.01, 0.05, 0.8], control = 0.1, variable = 0.2)
sol = solve(ocp; grid_size = 10, display = false, init = init)
@test sol.objective objective atol = 5e-3
@test objective(sol) obj atol = 5e-3
end
Loading

0 comments on commit 68bd783

Please sign in to comment.