Skip to content

Commit 563dbc8

Browse files
committed
clean metadata
1 parent 79bbf3a commit 563dbc8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+542
-639
lines changed

docs/problems.jl

Lines changed: 36 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,6 @@ function generate_documentation(PROBLEM::String, DESCRIPTION::String; draft::Uni
2828
DRAFT = draft_meta(draft)
2929
LEFT_MARGIN = get_left_margin(Symbol(PROBLEM))
3030

31-
VARIABLE_COMPONENTS = isnothing(OptimalControlProblems.metadata(Symbol(PROBLEM))[:variable_components]) ? "" :
32-
"""
33-
The variable components are named:
34-
35-
```@example main
36-
metadata(:$PROBLEM)[:variable_components]
37-
```
38-
"""
39-
4031
documentation=DRAFT * """
4132
# $TITLE
4233
@@ -78,20 +69,12 @@ function generate_documentation(PROBLEM::String, DESCRIPTION::String; draft::Uni
7869
7970
## Metadata
8071
81-
The state components are named:
82-
83-
```@example main
84-
metadata(:$PROBLEM)[:state_components]
85-
```
86-
87-
The control components are named:
72+
The default number of time steps is:
8873
8974
```@example main
90-
metadata(:$PROBLEM)[:control_components]
75+
metadata(:$PROBLEM)[:grid_size]
9176
```
9277
93-
$VARIABLE_COMPONENTS
94-
9578
The default values of the parameters are:
9679
9780
```@example main
@@ -120,25 +103,22 @@ function generate_documentation(PROBLEM::String, DESCRIPTION::String; draft::Uni
120103
```@example main
121104
function plot_initial_guess(problem)
122105
123-
# -----------------------------
124-
# Extract dimensions from metadata
125-
# -----------------------------
126-
x_vars = metadata(problem)[:state_components]
127-
u_vars = metadata(problem)[:control_components]
128-
n_states = length(x_vars)
129-
n_controls = length(u_vars)
130-
131106
# -----------------------------
132107
# Build OptimalControl problem
133108
# -----------------------------
134-
ocp_model = eval(problem)(OptimalControlBackend())
135-
nlp_oc = nlp_model(ocp_model)
109+
docp = eval(problem)(OptimalControlBackend())
110+
nlp_oc = nlp_model(docp)
111+
ocp_oc = ocp_model(docp)
136112
137113
# Solve NLP with zero iterations (initial guess)
138114
nlp_oc_sol = NLPModelsIpopt.ipopt(nlp_oc; max_iter=0)
139115
140116
# Build OptimalControl solution
141-
ocp_sol = build_ocp_solution(ocp_model, nlp_oc_sol)
117+
ocp_sol = build_ocp_solution(docp, nlp_oc_sol)
118+
119+
# get dimensions
120+
n = state_dimension(ocp_oc)
121+
m = control_dimension(ocp_oc)
142122
143123
# -----------------------------
144124
# Plot OptimalControl solution
@@ -150,13 +130,13 @@ function generate_documentation(PROBLEM::String, DESCRIPTION::String; draft::Uni
150130
control_style=(color=1, legend=:none),
151131
path_style=(color=1, legend=:none),
152132
dual_style=(color=1, legend=:none),
153-
size=(816, 220*(n_states+n_controls)),
133+
size=(816, 220*(n+m)),
154134
label="OptimalControl",
155135
leftmargin=$LEFT_MARGIN,
156136
)
157137
158138
# Hide legend for additional state plots
159-
for i in 2:n_states
139+
for i in 2:n
160140
plot!(plt[i]; legend=:none)
161141
end
162142
@@ -171,28 +151,28 @@ function generate_documentation(PROBLEM::String, DESCRIPTION::String; draft::Uni
171151
optimize!(nlp_jp)
172152
173153
# Extract trajectories
174-
t_grid = time_grid(problem, nlp_jp)
175-
x_fun = state(problem, nlp_jp)
176-
u_fun = control(problem, nlp_jp)
177-
p_fun = costate(problem, nlp_jp)
154+
t_grid = time_grid(nlp_jp)
155+
x_fun = state(nlp_jp)
156+
u_fun = control(nlp_jp)
157+
p_fun = costate(nlp_jp)
178158
179159
# -----------------------------
180160
# Plot JuMP solution on top
181161
# -----------------------------
182162
# States
183-
for i in 1:n_states
163+
for i in 1:n
184164
label = i == 1 ? "JuMP" : :none
185165
plot!(plt[i], t_grid, t -> x_fun(t)[i]; color=2, linestyle=:dash, label=label)
186166
end
187167
188168
# Costates
189-
for i in 1:n_states
190-
plot!(plt[n_states+i], t_grid, t -> -p_fun(t)[i]; color=2, linestyle=:dash, label=:none)
169+
for i in 1:n
170+
plot!(plt[n+i], t_grid, t -> -p_fun(t)[i]; color=2, linestyle=:dash, label=:none)
191171
end
192172
193173
# Controls
194-
for i in 1:n_controls
195-
plot!(plt[2*n_states+i], t_grid, t -> u_fun(t)[i]; color=2, linestyle=:dash, label=:none)
174+
for i in 1:m
175+
plot!(plt[2*n+i], t_grid, t -> u_fun(t)[i]; color=2, linestyle=:dash, label=:none)
196176
end
197177
198178
return plt
@@ -319,16 +299,16 @@ function generate_documentation(PROBLEM::String, DESCRIPTION::String; draft::Uni
319299
i_oc = iterations(ocp_sol)
320300
321301
# get relevant data from JuMP model
322-
t_jp = time_grid(problem, nlp_jp)
323-
x_jp = state(problem, nlp_jp).(t_jp)
324-
u_jp = control(problem, nlp_jp).(t_jp)
325-
o_jp = objective(problem, nlp_jp)
326-
v_jp = variable(problem, nlp_jp)
327-
i_jp = iterations(problem, nlp_jp)
302+
t_jp = time_grid(nlp_jp)
303+
x_jp = state(nlp_jp).(t_jp)
304+
u_jp = control(nlp_jp).(t_jp)
305+
o_jp = objective(nlp_jp)
306+
v_jp = variable(nlp_jp)
307+
i_jp = iterations(nlp_jp)
328308
329-
x_vars = metadata(problem)[:state_components]
330-
u_vars = metadata(problem)[:control_components]
331-
v_vars = metadata(problem)[:variable_components]
309+
x_vars = state_components(nlp_jp)
310+
u_vars = control_components(nlp_jp)
311+
v_vars = variable_components(nlp_jp)
332312
333313
println("┌─ ", string(problem))
334314
println("│")
@@ -397,8 +377,8 @@ function generate_documentation(PROBLEM::String, DESCRIPTION::String; draft::Uni
397377
ocp_sol = build_ocp_solution(docp, nlp_oc_sol)
398378
399379
# dimensions
400-
n = state_dimension(ocp_sol) # or length(metadata(:$PROBLEM)[:state_components])
401-
m = control_dimension(ocp_sol) # or length(metadata(:$PROBLEM)[:control_components])
380+
n = state_dimension(ocp_sol)
381+
m = control_dimension(ocp_sol)
402382
403383
# from OptimalControl solution
404384
plt = plot(
@@ -413,10 +393,10 @@ function generate_documentation(PROBLEM::String, DESCRIPTION::String; draft::Uni
413393
end
414394
415395
# from JuMP solution
416-
t = time_grid(:$PROBLEM, nlp_jp) # t0, ..., tN = tf
417-
x = state(:$PROBLEM, nlp_jp) # function of time
418-
u = control(:$PROBLEM, nlp_jp) # function of time
419-
p = costate(:$PROBLEM, nlp_jp) # function of time
396+
t = time_grid(nlp_jp) # t0, ..., tN = tf
397+
x = state(nlp_jp) # function of time
398+
u = control(nlp_jp) # function of time
399+
p = costate(nlp_jp) # function of time
420400
421401
for i in 1:n # state
422402
label = i == 1 ? "JuMP" : :none

docs/src/dev-add.md

Lines changed: 21 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,6 @@ To add a new problem to **OptimalControlProblems**, you must follow these steps:
77
```julia
88
new_problem_meta = OrderedDict(
99
:grid_size => 100, # Number of steps
10-
:state_components => ["x₁", "x₂"], # Names of the state components
11-
:costate_components => ["∂x₁", "∂x₂"], # Names of the dynamics constraints (for the costate)
12-
:control_components => ["u"], # Names of the control components
13-
:variable_components => ["v"], # Names of the optimisation variables
14-
:time_grid_names => Dict(
15-
:initial_time => "t0", # Name of the initial time
16-
:final_time => "tf", # Name of the final time
17-
:grid_size => "N", # Name of the grid size
18-
),
1910
:parameters => (
2011
t0 = 0, # Value of the initial time
2112
tf = 1, # Value of the final time
@@ -109,20 +100,27 @@ function OptimalControlProblems.new_problem(
109100
# model
110101
model = JuMP.Model(args...; kwargs...)
111102

112-
# ------------------------------------------------
113-
# expressions to get grid time infos
114-
@expressions(
103+
# metadata: required
104+
model[:time_grid] = () -> range(t0, tf, grid_size+1) # tf is a fixed
105+
model[:state_components] = ["x₁", "x₂"]
106+
model[:costate_components] = ["∂x₁", "∂x₂"]
107+
model[:control_components] = ["u"]
108+
model[:variable_components] = String[] # no variable
109+
110+
# N = grid_size
111+
@expression(model, N, grid_size)
112+
113+
# variables and initial guess
114+
@variables(
115115
model,
116116
begin
117-
t0, t0 # (required if the initial time is fixed)
118-
tf, tf # (required if the final time is fixed)
119-
N, grid_size # (required)
117+
x₁[0:N], (start = 0.5) # consistent with model[:state_components]
118+
x₂[0:N], (start = 0.1) # consistent with model[:state_components]
119+
u[0:N], (start = 0.1) # consistent with model[:control_components]
120120
end
121121
)
122-
# ------------------------------------------------
123-
124-
# define the problem
125-
# @variables, @constraints, @objective...
122+
123+
# @constraints, @objective...
126124

127125
return model
128126

@@ -131,14 +129,11 @@ end
131129

132130
!!! warning
133131

134-
The names `t0`, `tf` and `N` in `@expressions` command are the same as in the metadata:
135-
132+
- The metadata in JuMP are required and must be consistent with the other models.
133+
- If `tf` is free, then define:
134+
136135
```julia
137-
:time_grid_names => Dict(
138-
:initial_time => "t0",
139-
:final_time => "tf",
140-
:grid_size => "N",
141-
),
136+
model[:time_grid] = () -> range(t0, value(model[:tf]), grid_size+1) # tf is a free
142137
```
143138

144139
!!! tip

docs/src/tutorial-solve.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ From `ocp_sol` you can also plot the state, control, and costate trajectories. F
7878

7979
```@example main
8080
using Plots
81-
plt = plot(ocp_sol; color=1, size=(800, 700), control_style=(label="OptimalControl", ))
81+
plt = plot(ocp_sol; color=1, size=(700, 600), control_style=(label="OptimalControl", ))
8282
```
8383

8484
## Solving from a JuMP model
@@ -122,12 +122,12 @@ objective_value(nlp)
122122
To get the time grid, state, control, and costate, but also to retrieve the number of iterations and the objective value, OptimalControlProblems provides the following getters:
123123

124124
```@example main
125-
t = time_grid(:beam, nlp) # t0, ..., tN = tf
126-
x = state(:beam, nlp) # function of time
127-
u = control(:beam, nlp) # function of time
128-
p = costate(:beam, nlp) # function of time
129-
o = objective(:beam, nlp) # scalar objective value
130-
i = iterations(:beam, nlp) # number of iteration
125+
t = time_grid(nlp) # t0, ..., tN = tf
126+
x = state(nlp) # function of time
127+
u = control(nlp) # function of time
128+
p = costate(nlp) # function of time
129+
o = objective(nlp) # scalar objective value
130+
i = iterations(nlp) # number of iteration
131131
132132
tf = t[end]
133133
println("tf = ", tf)
@@ -142,14 +142,14 @@ println("iterations: ", i)
142142
If the `problem` includes additional optimisation variables, such as the final time, you can retrieve them with:
143143

144144
```julia
145-
v = variable(problem, nlp)
145+
v = variable(nlp)
146146
```
147147

148148
Now, we can add the state, costate, and control to the plot:
149149

150150
```@example main
151-
n = length(metadata(:beam)[:state_components]) # dimension of the state
152-
m = length(metadata(:beam)[:control_components]) # dimension of the control
151+
n = state_dimension(nlp)
152+
m = control_dimension(nlp)
153153
154154
for i in 1:n # state
155155
plot!(plt[i], t, t -> x(t)[i]; color=2, linestyle=:dash, label=:none)

0 commit comments

Comments
 (0)