@@ -5,32 +5,37 @@ using DiffEqDevTools, DiffEqBase, SciMLBase
5
5
using LinearAlgebra
6
6
const MTK = ModelingToolkit
7
7
8
- abstract type AbstractOptimalControlProblem{uType, tType, isinplace} <: SciMLBase.AbstractODEProblem{uType, tType, isinplace} end
9
-
10
- struct JuMPControlProblem{uType, tType, isinplace, P, F, K} <: AbstractOptimalControlProblem{uType, tType, isinplace}
11
- f:: F
12
- u0:: uType
13
- tspan:: tType
14
- p:: P
15
- model:: InfiniteModel
16
- kwargs:: K
17
-
18
- function JuMPControlProblem (f, u0, tspan, p, model; kwargs... )
19
- new {typeof(u0), typeof(tspan), SciMLBase.isinplace(f), typeof(p), typeof(f), typeof(kwargs)} (f, u0, tspan, p, model, kwargs)
20
- end
8
+ abstract type AbstractOptimalControlProblem{uType, tType, isinplace} < :
9
+ SciMLBase. AbstractODEProblem{uType, tType, isinplace} end
10
+
11
+ struct JuMPControlProblem{uType, tType, isinplace, P, F, K} < :
12
+ AbstractOptimalControlProblem{uType, tType, isinplace}
13
+ f:: F
14
+ u0:: uType
15
+ tspan:: tType
16
+ p:: P
17
+ model:: InfiniteModel
18
+ kwargs:: K
19
+
20
+ function JuMPControlProblem (f, u0, tspan, p, model; kwargs... )
21
+ new{typeof (u0), typeof (tspan), SciMLBase. isinplace (f),
22
+ typeof (p), typeof (f), typeof (kwargs)}(f, u0, tspan, p, model, kwargs)
23
+ end
21
24
end
22
25
23
- struct InfiniteOptControlProblem{uType, tType, isinplace, P, F, K} <: AbstractOptimalControlProblem{uType, tType, isinplace}
24
- f:: F
25
- u0:: uType
26
- tspan:: tType
27
- p:: P
28
- model:: InfiniteModel
29
- kwargs:: K
30
-
31
- function InfiniteOptControlProblem (f, u0, tspan, p, model; kwargs... )
32
- new {typeof(u0), typeof(tspan), SciMLBase.isinplace(f), typeof(p), typeof(f), typeof(kwargs)} (f, u0, tspan, p, model, kwargs)
33
- end
26
+ struct InfiniteOptControlProblem{uType, tType, isinplace, P, F, K} < :
27
+ AbstractOptimalControlProblem{uType, tType, isinplace}
28
+ f:: F
29
+ u0:: uType
30
+ tspan:: tType
31
+ p:: P
32
+ model:: InfiniteModel
33
+ kwargs:: K
34
+
35
+ function InfiniteOptControlProblem (f, u0, tspan, p, model; kwargs... )
36
+ new{typeof (u0), typeof (tspan), SciMLBase. isinplace (f),
37
+ typeof (p), typeof (f), typeof (kwargs)}(f, u0, tspan, p, model, kwargs)
38
+ end
34
39
end
35
40
36
41
"""
@@ -48,7 +53,9 @@ The constraints are:
48
53
- The set of user constraints passed to the ODESystem via `constraints`
49
54
- The solver constraints that encode the time-stepping used by the solver
50
55
"""
51
- function MTK. JuMPControlProblem (sys:: ODESystem , u0map, tspan, pmap; dt = error (" dt must be provided for JuMPControlProblem." ), guesses = Dict (), kwargs... )
56
+ function MTK. JuMPControlProblem (sys:: ODESystem , u0map, tspan, pmap;
57
+ dt = error (" dt must be provided for JuMPControlProblem." ),
58
+ guesses = Dict (), kwargs... )
52
59
_u0map = has_alg_eqs (sys) ? u0map : merge (Dict (u0map), Dict (guesses))
53
60
f, u0, p = MTK. process_SciMLProblem (ODEFunction, sys, _u0map, pmap;
54
61
t = tspan != = nothing ? tspan[1 ] : tspan, kwargs... )
@@ -67,7 +74,9 @@ of the interpolation arrays.
67
74
Related to `JuMPControlProblem`, but directly adds the differential equations
68
75
of the system as derivative constraints, rather than using a solver tableau.
69
76
"""
70
- function MTK. InfiniteOptControlProblem (sys:: ODESystem , u0map, tspan, pmap; dt = error (" dt must be provided for InfiniteOptControlProblem." ), guesses = Dict (), kwargs... )
77
+ function MTK. InfiniteOptControlProblem (sys:: ODESystem , u0map, tspan, pmap;
78
+ dt = error (" dt must be provided for InfiniteOptControlProblem." ),
79
+ guesses = Dict (), kwargs... )
71
80
_u0map = has_alg_eqs (sys) ? u0map : merge (Dict (u0map), Dict (guesses))
72
81
f, u0, p = MTK. process_SciMLProblem (ODEFunction, sys, _u0map, pmap;
73
82
t = tspan != = nothing ? tspan[1 ] : tspan, kwargs... )
@@ -87,15 +96,16 @@ function init_model(sys, tsteps, u0map, u0)
87
96
ctrls = controls (sys)
88
97
states = unknowns (sys)
89
98
model = InfiniteModel ()
90
- @infinite_parameter (model, t in [tsteps[1 ], tsteps[end ]], num_supports = length (tsteps))
99
+ @infinite_parameter (model, t in [tsteps[1 ], tsteps[end ]], num_supports= length (tsteps))
91
100
@variable (model, U[i = 1 : length (states)], Infinite (t))
92
101
@variable (model, V[1 : length (ctrls)], Infinite (t))
93
102
94
103
add_jump_cost_function! (model, sys)
95
104
add_user_constraints! (model, sys)
96
105
97
106
stidxmap = Dict ([v => i for (i, v) in enumerate (states)])
98
- u0_idxs = has_alg_eqs (sys) ? collect (1 : length (states)) : [stidxmap[k] for (k, v) in u0map]
107
+ u0_idxs = has_alg_eqs (sys) ? collect (1 : length (states)) :
108
+ [stidxmap[k] for (k, v) in u0map]
99
109
add_initial_constraints! (model, u0, u0_idxs, tsteps[1 ])
100
110
return model
101
111
end
@@ -119,15 +129,15 @@ function add_jump_cost_function!(model, sys)
119
129
subval = isequal (t, iv) ? model[:U ][idx] : model[:U ][idx](t)
120
130
jcosts = map (c -> Symbolics. substitute (c, Dict (x (t) => subval)), jcosts)
121
131
end
122
-
132
+
123
133
for ct in controls (sys)
124
134
p = operation (ct)
125
135
t = only (arguments (ct))
126
136
idx = cidxmap[p (iv)]
127
137
subval = isequal (t, iv) ? model[:V ][idx] : model[:V ][idx](t)
128
138
jcosts = map (c -> Symbolics. substitute (c, Dict (p (t) => subval)), jcosts)
129
139
end
130
-
140
+
131
141
@objective (model, Min, consolidate (jcosts))
132
142
end
133
143
@@ -153,23 +163,24 @@ function add_user_constraints!(model, sys)
153
163
t = only (arguments (ct))
154
164
idx = cidxmap[p (iv)]
155
165
subval = isequal (t, iv) ? model[:V ][idx] : model[:V ][idx](t)
156
- jconstraints = map (c -> Symbolics. substitute (jconstraints, Dict (p (t) => subval)), jconstriants)
166
+ jconstraints = map (
167
+ c -> Symbolics. substitute (jconstraints, Dict (p (t) => subval)), jconstriants)
157
168
end
158
169
159
170
for (i, cons) in enumerate (jconstraints)
160
171
if cons isa Equation
161
- @constraint (model, cons. lhs - cons. rhs == 0 , base_name = " user[$i ]" )
162
- elseif cons. relational_op === Symbolics. geq
163
- @constraint (model, cons. lhs - cons. rhs ≥ 0 , base_name = " user[$i ]" )
172
+ @constraint (model, cons. lhs - cons. rhs== 0 , base_name= " user[$i ]" )
173
+ elseif cons. relational_op === Symbolics. geq
174
+ @constraint (model, cons. lhs - cons. rhs≥ 0 , base_name= " user[$i ]" )
164
175
else
165
- @constraint (model, cons. lhs - cons. rhs ≤ 0 , base_name = " user[$i ]" )
176
+ @constraint (model, cons. lhs - cons. rhs≤ 0 , base_name= " user[$i ]" )
166
177
end
167
178
end
168
179
end
169
180
170
181
function add_initial_constraints! (model, u0, u0_idxs, ts)
171
182
U = model[:U ]
172
- @constraint (model, initial[i in u0_idxs], U[i](ts) == u0[i])
183
+ @constraint (model, initial[i in u0_idxs], U[i](ts)== u0[i])
173
184
end
174
185
175
186
is_explicit (tableau) = tableau isa DiffEqDevTools. ExplicitRKTableau
@@ -193,12 +204,12 @@ function add_infopt_solve_constraints!(model, sys, pmap)
193
204
diff_eqs = map (e -> Symbolics. substitute (e, submap), diff_eqs)
194
205
diff_eqs = map (e -> Symbolics. substitute (e, diffsubmap), diff_eqs)
195
206
end
196
- @constraint (model, D[i = 1 : length (diff_eqs)], diff_eqs[i]. lhs == diff_eqs[i]. rhs)
207
+ @constraint (model, D[i = 1 : length (diff_eqs)], diff_eqs[i]. lhs== diff_eqs[i]. rhs)
197
208
198
209
# Algebraic equations
199
210
alg_eqs = alg_equations (sys)
200
211
alg_eqs = map (e -> Symbolics. substitute (e, submap), alg_eqs)
201
- @constraint (model, A[i = 1 : length (alg_eqs)], alg_eqs[i]. lhs == alg_eqs[i]. rhs)
212
+ @constraint (model, A[i = 1 : length (alg_eqs)], alg_eqs[i]. lhs== alg_eqs[i]. rhs)
202
213
end
203
214
204
215
function add_jump_solve_constraints! (prob, tableau)
@@ -219,26 +230,29 @@ function add_jump_solve_constraints!(prob, tableau)
219
230
K = Any[]
220
231
for τ in tsteps
221
232
for (i, h) in enumerate (c)
222
- ΔU = sum ([A[i, j] * K[j] for j in 1 : i - 1 ], init = zeros (nᵤ))
223
- Uₙ = [U[i](τ) + ΔU[i]* dt for i in 1 : nᵤ]
224
- Kₙ = f (Uₙ, p, τ + h* dt)
233
+ ΔU = sum ([A[i, j] * K[j] for j in 1 : (i - 1 ) ], init = zeros (nᵤ))
234
+ Uₙ = [U[i](τ) + ΔU[i] * dt for i in 1 : nᵤ]
235
+ Kₙ = f (Uₙ, p, τ + h * dt)
225
236
push! (K, Kₙ)
226
237
end
227
- ΔU = dt* sum ([α[i] * K[i] for i in 1 : length (α)])
228
- @constraint (model, [n = 1 : nᵤ], U[n](τ) + ΔU[n] == U[n](τ + dt), base_name = " solve_time_$τ " )
238
+ ΔU = dt * sum ([α[i] * K[i] for i in 1 : length (α)])
239
+ @constraint (model, [n = 1 : nᵤ], U[n](τ) + ΔU[n]== U[n](τ + dt),
240
+ base_name= " solve_time_$τ " )
229
241
empty! (K)
230
242
end
231
243
else
232
- @variable (model, K[1 : length (α), 1 : nᵤ], Infinite (t), start = tsteps[1 ])
244
+ @variable (model, K[1 : length (α), 1 : nᵤ], Infinite (t), start= tsteps[1 ])
233
245
for τ in tsteps
234
246
ΔUs = A * K
235
247
for (i, h) in enumerate (c)
236
248
ΔU = ΔUs[i, :]
237
- Uₙ = [U[j] + ΔU[j]* dt for j in 1 : nᵤ]
238
- @constraint (model, [j in 1 : nᵤ], K[i, j] == f (Uₙ, p, τ + h* dt)[j], DomainRestrictions (t => τ), base_name = " solve_K($τ )" )
249
+ Uₙ = [U[j] + ΔU[j] * dt for j in 1 : nᵤ]
250
+ @constraint (model, [j in 1 : nᵤ], K[i, j]== f (Uₙ, p, τ + h * dt)[j],
251
+ DomainRestrictions (t => τ), base_name= " solve_K($τ )" )
239
252
end
240
- ΔU = dt* sum ([α[i] * K[i, :] for i in 1 : length (α)])
241
- @constraint (model, [n = 1 : nᵤ], U[n] + ΔU[n] == U[n](τ + dt), DomainRestrictions (t => τ), base_name = " solve_U($τ )" )
253
+ ΔU = dt * sum ([α[i] * K[i, :] for i in 1 : length (α)])
254
+ @constraint (model, [n = 1 : nᵤ], U[n] + ΔU[n]== U[n](τ + dt),
255
+ DomainRestrictions (t => τ), base_name= " solve_U($τ )" )
242
256
end
243
257
end
244
258
end
@@ -271,7 +285,7 @@ function DiffEqBase.solve(prob::JuMPControlProblem, jump_solver, ode_solver::Sym
271
285
delete (model, con)
272
286
end
273
287
end
274
- unregister (model, :K )
288
+ unregister (model, :K )
275
289
for var in all_variables (model)
276
290
if occursin (" K" , JuMP. name (var))
277
291
delete (model, var)
284
298
"""
285
299
`derivative_method` kwarg refers to the method used by InfiniteOpt to compute derivatives. The list of possible options can be found at https://infiniteopt.github.io/InfiniteOpt.jl/stable/guide/derivative/. Defaults to FiniteDifference(Backward()).
286
300
"""
287
- function DiffEqBase. solve (prob:: InfiniteOptControlProblem , jump_solver; derivative_method = InfiniteOpt. FiniteDifference (Backward ()))
301
+ function DiffEqBase. solve (prob:: InfiniteOptControlProblem , jump_solver;
302
+ derivative_method = InfiniteOpt. FiniteDifference (Backward ()))
288
303
set_derivative_method (prob. model[:t ], derivative_method)
289
304
_solve (prob, jump_solver, derivative_method)
290
305
end
@@ -296,7 +311,8 @@ function _solve(prob::AbstractOptimalControlProblem, jump_solver, solver)
296
311
297
312
tstatus = termination_status (model)
298
313
pstatus = primal_status (model)
299
- ! has_values (model) && error (" Model not solvable; please report this to github.com/SciML/ModelingToolkit.jl." )
314
+ ! has_values (model) &&
315
+ error (" Model not solvable; please report this to github.com/SciML/ModelingToolkit.jl." )
300
316
301
317
ts = supports (model[:t ])
302
318
U_vals = value .(model[:U ])
@@ -310,9 +326,12 @@ function _solve(prob::AbstractOptimalControlProblem, jump_solver, solver)
310
326
input_sol = DiffEqBase. build_solution (prob, solver, ts, V_vals)
311
327
end
312
328
313
- if ! (pstatus === FEASIBLE_POINT && (tstatus === OPTIMAL || tstatus === LOCALLY_SOLVED || tstatus === ALMOST_OPTIMAL || tstatus === ALMOST_LOCALLY_SOLVED))
329
+ if ! (pstatus === FEASIBLE_POINT &&
330
+ (tstatus === OPTIMAL || tstatus === LOCALLY_SOLVED || tstatus === ALMOST_OPTIMAL ||
331
+ tstatus === ALMOST_LOCALLY_SOLVED))
314
332
sol = SciMLBase. solution_new_retcode (sol, SciMLBase. ReturnCode. ConvergenceFailure)
315
- ! isnothing (input_sol) && (input_sol = SciMLBase. solution_new_retcode (input_sol, SciMLBase. ReturnCode. ConvergenceFailure))
333
+ ! isnothing (input_sol) && (input_sol = SciMLBase. solution_new_retcode (
334
+ input_sol, SciMLBase. ReturnCode. ConvergenceFailure))
316
335
end
317
336
318
337
JuMPControlSolution (model, sol, input_sol)
0 commit comments