4242Convert an ODESystem representing an optimal control system into a JuMP model
4343for solving using optimization. Must provide either `dt`, the timestep between collocation
4444points (which, along with the timespan, determines the number of points), or directly
45- provide the number of points as `nsteps `.
45+ provide the number of points as `steps `.
4646
4747The optimization variables:
4848- a vector-of-vectors U representing the unknowns as an interpolation array
@@ -61,7 +61,7 @@ function MTK.JuMPDynamicOptProblem(sys::ODESystem, u0map, tspan, pmap;
6161 f, u0, p = MTK. process_SciMLProblem (ODEInputFunction, sys, _u0map, pmap;
6262 t = tspan != = nothing ? tspan[1 ] : tspan, kwargs... )
6363
64- pmap = MTK . todict (pmap)
64+ pmap = Dict {Any, Any} (pmap)
6565 steps, is_free_t = MTK. process_tspan (tspan, dt, steps)
6666 model = init_model (sys, tspan, steps, u0map, pmap, u0; is_free_t)
6767
@@ -87,7 +87,7 @@ function MTK.InfiniteOptDynamicOptProblem(sys::ODESystem, u0map, tspan, pmap;
8787 f, u0, p = MTK. process_SciMLProblem (ODEInputFunction, sys, _u0map, pmap;
8888 t = tspan != = nothing ? tspan[1 ] : tspan, kwargs... )
8989
90- pmap = MTK . todict (pmap)
90+ pmap = Dict {Any, Any} (pmap)
9191 steps, is_free_t = MTK. process_tspan (tspan, dt, steps)
9292 model = init_model (sys, tspan, steps, u0map, pmap, u0; is_free_t)
9393
@@ -103,21 +103,25 @@ function init_model(sys, tspan, steps, u0map, pmap, u0; is_free_t = false)
103103
104104 if is_free_t
105105 (ts_sym, te_sym) = tspan
106+ MTK. symbolic_type (ts_sym) != = MTK. NotSymbolic () && error (" Free initial time problems are not currently supported." )
106107 @variable (model, tf, start= pmap[te_sym])
108+ set_lower_bound (tf, ts_sym)
107109 hasbounds (te_sym) && begin
108110 lo, hi = getbounds (te_sym)
109111 set_lower_bound (tf, lo)
110112 set_upper_bound (tf, hi)
111113 end
112- pmap[ts_sym] = 0
113- pmap[te_sym] = 1
114+ pmap[te_sym] = model[:tf ]
114115 tspan = (0 , 1 )
115116 end
116117
117118 @infinite_parameter (model, t in [tspan[1 ], tspan[2 ]], num_supports= steps)
118119 @variable (model, U[i = 1 : length (states)], Infinite (t), start= u0[i])
119120 c0 = MTK. value .([pmap[c] for c in ctrls])
120121 @variable (model, V[i = 1 : length (ctrls)], Infinite (t), start= c0[i])
122+ for (i, ct) in enumerate (ctrls)
123+ pmap[ct] = model[:V ][i]
124+ end
121125
122126 set_jump_bounds! (model, sys, pmap)
123127 add_jump_cost_function! (model, sys, (tspan[1 ], tspan[2 ]), pmap; is_free_t)
@@ -131,6 +135,13 @@ function init_model(sys, tspan, steps, u0map, pmap, u0; is_free_t = false)
131135 return model
132136end
133137
138+ """
139+ Modify the pmap by replacing controls with V[i](t), and tf with the model's final time variable for free final time problems.
140+ """
141+ function modified_pmap (model, sys, pmap)
142+ pmap = Dict {Any, Any} (pmap)
143+ end
144+
134145function set_jump_bounds! (model, sys, pmap)
135146 U = model[:U ]
136147 for (i, u) in enumerate (unknowns (sys))
@@ -158,7 +169,7 @@ function add_jump_cost_function!(model::InfiniteModel, sys, tspan, pmap; is_free
158169 @objective (model, Min, 0 )
159170 return
160171 end
161- jcosts = substitute_jump_vars (model, sys, pmap, jcosts)
172+ jcosts = substitute_jump_vars (model, sys, pmap, jcosts; is_free_t )
162173 tₛ = is_free_t ? model[:tf ] : 1
163174
164175 # Substitute integral
@@ -186,13 +197,14 @@ function add_user_constraints!(model::InfiniteModel, sys, pmap; is_free_t = fals
186197 for u in MTK. get_unknowns (conssys)
187198 x = MTK. operation (u)
188199 t = only (arguments (u))
189- MTK. symbolic_type (t) === NotSymbolic () &&
190- error (" Provided specific time constraint in a free final time problem. This is not supported by the JuMP/InfiniteOpt collocation solvers. The offending variable is $u ." )
200+ if (MTK. symbolic_type (t) === MTK. NotSymbolic ())
201+ error (" Provided specific time constraint in a free final time problem. This is not supported by the JuMP/InfiniteOpt collocation solvers. The offending variable is $u . Specific-time constraints can only be specified at the beginning or end of the timespan." )
202+ end
191203 end
192204 end
193205
194206 auxmap = Dict ([u => MTK. default_toterm (MTK. value (u)) for u in unknowns (conssys)])
195- jconstraints = substitute_jump_vars (model, sys, pmap, jconstraints; auxmap)
207+ jconstraints = substitute_jump_vars (model, sys, pmap, jconstraints; auxmap, is_free_t )
196208
197209 # Substitute to-term'd variables
198210 for (i, cons) in enumerate (jconstraints)
@@ -211,28 +223,33 @@ function add_initial_constraints!(model::InfiniteModel, u0, u0_idxs, ts)
211223 @constraint (model, initial[i in u0_idxs], U[i](ts)== u0[i])
212224end
213225
214- function substitute_jump_vars (model, sys, pmap, exprs; auxmap = Dict ())
226+ function substitute_jump_vars (model, sys, pmap, exprs; auxmap = Dict (), is_free_t = false )
215227 iv = MTK. get_iv (sys)
216228 sts = unknowns (sys)
217229 cts = MTK. unbound_inputs (sys)
218230 U = model[:U ]
219231 V = model[:V ]
232+ x_ops = [MTK. operation (MTK. unwrap (st)) for st in sts]
233+ c_ops = [MTK. operation (MTK. unwrap (ct)) for ct in cts]
234+
220235 exprs = map (c -> Symbolics. fixpoint_sub (c, auxmap), exprs)
236+ exprs = map (c -> Symbolics. fixpoint_sub (c, Dict (pmap)), exprs)
237+ if is_free_t
238+ tf = model[:tf ]
239+ free_t_map = Dict ([[x (tf) => U[i](1 ) for (i, x) in enumerate (x_ops)]; [c (tf) => V[i](1 ) for (i, c) in enumerate (c_ops)]])
240+ exprs = map (c -> Symbolics. fixpoint_sub (c, free_t_map), exprs)
241+ end
221242
222243 # for variables like x(t)
223244 whole_interval_map = Dict ([[v => U[i] for (i, v) in enumerate (sts)];
224245 [v => V[i] for (i, v) in enumerate (cts)]])
225246 exprs = map (c -> Symbolics. fixpoint_sub (c, whole_interval_map), exprs)
226247
227248 # for variables like x(1.0)
228- x_ops = [MTK. operation (MTK. unwrap (st)) for st in sts]
229- c_ops = [MTK. operation (MTK. unwrap (ct)) for ct in cts]
230249 fixed_t_map = Dict ([[x_ops[i] => U[i] for i in 1 : length (U)];
231250 [c_ops[i] => V[i] for i in 1 : length (V)]])
232251
233252 exprs = map (c -> Symbolics. fixpoint_sub (c, fixed_t_map), exprs)
234-
235- exprs = map (c -> Symbolics. fixpoint_sub (c, Dict (pmap)), exprs)
236253 exprs
237254end
238255
@@ -246,8 +263,12 @@ function add_infopt_solve_constraints!(model::InfiniteModel, sys, pmap; is_free_
246263 diffsubmap = Dict ([D (U[i]) => ∂ (U[i], t) for i in 1 : length (U)])
247264 tₛ = is_free_t ? model[:tf ] : 1
248265
266+ @show diff_equations (sys)
267+ @show pmap
249268 diff_eqs = substitute_jump_vars (model, sys, pmap, diff_equations (sys))
269+ @show diff_eqs
250270 diff_eqs = map (e -> Symbolics. substitute (e, diffsubmap), diff_eqs)
271+ @show diff_eqs
251272 @constraint (model, D[i = 1 : length (diff_eqs)], diff_eqs[i]. lhs== tₛ * diff_eqs[i]. rhs)
252273
253274 # Algebraic equations
0 commit comments