@@ -77,7 +77,7 @@ struct NonLinMPC{
7777 d0, D̂0, D̂E,
7878 Ŷop, Dop,
7979 )
80- init_optimization! (mpc, optim)
80+ init_optimization! (mpc, model, optim)
8181 return mpc
8282 end
8383end
@@ -277,11 +277,11 @@ function addinfo!(info, mpc::NonLinMPC)
277277end
278278
279279"""
280- init_optimization!(mpc::NonLinMPC, optim::JuMP.GenericModel )
280+ init_optimization!(mpc::NonLinMPC, model::SimModel, optim )
281281
282282Init the nonlinear optimization for [`NonLinMPC`](@ref) controllers.
283283"""
284- function init_optimization! (mpc:: NonLinMPC , optim :: JuMP.GenericModel{JNT} ) where JNT <: Real
284+ function init_optimization! (mpc:: NonLinMPC , model :: SimModel , optim)
285285 # --- variables and linear constraints ---
286286 C, con = mpc. C, mpc. con
287287 nΔŨ = length (mpc. ΔŨ)
@@ -300,65 +300,11 @@ function init_optimization!(mpc::NonLinMPC, optim::JuMP.GenericModel{JNT}) where
300300 JuMP. set_attribute (optim, " nlp_scaling_max_gradient" , 10.0 / C)
301301 end
302302 end
303- model = mpc. estim. model
304- nu, ny, nx̂, Hp, ng = model. nu, model. ny, mpc. estim. nx̂, mpc. Hp, length (con. i_g)
305- # inspired from https://jump.dev/JuMP.jl/stable/tutorials/nonlinear/tips_and_tricks/#User-defined-operators-with-vector-outputs
306- Jfunc, gfunc = let mpc= mpc, model= model, ng= ng, nΔŨ= nΔŨ, nŶ= Hp* ny, nx̂= nx̂, nu= nu, nU= Hp* nu
307- Nc = nΔŨ + 3
308- last_ΔŨtup_float, last_ΔŨtup_dual = nothing , nothing
309- ΔŨ_cache:: DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache (zeros (JNT, nΔŨ), Nc)
310- Ŷ_cache:: DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache (zeros (JNT, nŶ), Nc)
311- U_cache:: DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache (zeros (JNT, nU), Nc)
312- g_cache:: DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache (zeros (JNT, ng), Nc)
313- x̂_cache:: DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache (zeros (JNT, nx̂), Nc)
314- x̂next_cache:: DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache (zeros (JNT, nx̂), Nc)
315- u_cache:: DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache (zeros (JNT, nu), Nc)
316- û_cache:: DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache (zeros (JNT, nu), Nc)
317- Ȳ_cache:: DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache (zeros (JNT, nŶ), Nc)
318- Ū_cache:: DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache (zeros (JNT, nU), Nc)
319- function Jfunc (ΔŨtup:: T... ):: T where {T <: Real }
320- ΔŨ1 = ΔŨtup[begin ]
321- if T == JNT
322- last_ΔŨtup_float = ΔŨtup
323- else
324- last_ΔŨtup_dual = ΔŨtup
325- end
326- ΔŨ, Ŷ = get_tmp (ΔŨ_cache, ΔŨ1), get_tmp (Ŷ_cache, ΔŨ1)
327- x̂, x̂next = get_tmp (x̂_cache, ΔŨ1), get_tmp (x̂next_cache, ΔŨ1)
328- u, û = get_tmp (u_cache, ΔŨ1), get_tmp (û_cache, ΔŨ1)
329- ΔŨ .= ΔŨtup
330- Ŷ, x̂end = predict! (Ŷ, x̂, x̂next, u, û, mpc, model, ΔŨ)
331- g = get_tmp (g_cache, ΔŨ1)
332- g = con_nonlinprog! (g, mpc, model, x̂end , Ŷ, ΔŨ)
333- U, Ȳ, Ū = get_tmp (U_cache, ΔŨ1), get_tmp (Ȳ_cache, ΔŨ1), get_tmp (Ū_cache, ΔŨ1)
334- return obj_nonlinprog! (U, Ȳ, Ū, mpc, model, Ŷ, ΔŨ):: T
335- end
336- function gfunc_i (i, ΔŨtup:: NTuple{N, T} ):: T where {N, T <: Real }
337- ΔŨ1 = ΔŨtup[begin ]
338- g = get_tmp (g_cache, ΔŨ1)
339- if T == JNT
340- isnewvalue = (ΔŨtup != = last_ΔŨtup_float)
341- isnewvalue && (last_ΔŨtup_float = ΔŨtup)
342- else
343- isnewvalue = (ΔŨtup != = last_ΔŨtup_dual)
344- isnewvalue && (last_ΔŨtup_dual = ΔŨtup)
345- end
346- if isnewvalue
347- ΔŨ, Ŷ = get_tmp (ΔŨ_cache, ΔŨ1), get_tmp (Ŷ_cache, ΔŨ1)
348- x̂, x̂next = get_tmp (x̂_cache, ΔŨ1), get_tmp (x̂next_cache, ΔŨ1)
349- u, û = get_tmp (u_cache, ΔŨ1), get_tmp (û_cache, ΔŨ1)
350- ΔŨ .= ΔŨtup
351- Ŷ, x̂end = predict! (Ŷ, x̂, x̂next, u, û, mpc, model, ΔŨ)
352- g = con_nonlinprog! (g, mpc, model, x̂end , Ŷ, ΔŨ)
353- end
354- return g[i]:: T
355- end
356- gfunc = [(ΔŨ... ) -> gfunc_i (i, ΔŨ) for i in 1 : ng]
357- (Jfunc, gfunc)
358- end
303+ Jfunc, gfunc = get_optim_functions (mpc, mpc. optim)
359304 register (optim, :Jfunc , nΔŨ, Jfunc, autodiff= true )
360305 @NLobjective (optim, Min, Jfunc (ΔŨvar... ))
361- if ng ≠ 0
306+ ny, nx̂, Hp = model. ny, mpc. estim. nx̂, mpc. Hp
307+ if length (con. i_g) ≠ 0
362308 for i in eachindex (con. Ymin)
363309 sym = Symbol (" g_Ymin_$i " )
364310 register (optim, sym, nΔŨ, gfunc[i], autodiff= true )
@@ -382,6 +328,62 @@ function init_optimization!(mpc::NonLinMPC, optim::JuMP.GenericModel{JNT}) where
382328 return nothing
383329end
384330
331+ """
332+ get_optim_functions(mpc::NonLinMPC, ::JuMP.GenericModel) -> Jfunc, gfunc
333+
334+ Get the objective `Jfunc` and constraints `gfunc` functions for [`NonLinMPC`](@ref).
335+
336+ Inspired from: [User-defined operators with vector outputs](https://jump.dev/JuMP.jl/stable/tutorials/nonlinear/tips_and_tricks/#User-defined-operators-with-vector-outputs)
337+ """
338+ function get_optim_functions (mpc:: NonLinMPC , :: JuMP.GenericModel{JNT} ) where JNT<: Real
339+ model = mpc. estim. model
340+ nu, ny, nx̂, Hp = model. nu, model. ny, mpc. estim. nx̂, mpc. Hp
341+ ng, nΔŨ, nU, nŶ = length (mpc. con. i_g), length (mpc. ΔŨ), Hp* nu, Hp* ny
342+ Nc = nΔŨ + 3
343+ ΔŨ_cache:: DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache (zeros (JNT, nΔŨ), Nc)
344+ Ŷ_cache:: DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache (zeros (JNT, nŶ), Nc)
345+ U_cache:: DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache (zeros (JNT, nU), Nc)
346+ g_cache:: DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache (zeros (JNT, ng), Nc)
347+ x̂_cache:: DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache (zeros (JNT, nx̂), Nc)
348+ x̂next_cache:: DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache (zeros (JNT, nx̂), Nc)
349+ u_cache:: DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache (zeros (JNT, nu), Nc)
350+ û_cache:: DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache (zeros (JNT, nu), Nc)
351+ Ȳ_cache:: DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache (zeros (JNT, nŶ), Nc)
352+ Ū_cache:: DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache (zeros (JNT, nU), Nc)
353+ function Jfunc (ΔŨtup:: T... ) where T<: Real
354+ ΔŨ1 = ΔŨtup[begin ]
355+ ΔŨ, g = get_tmp (ΔŨ_cache, ΔŨ1), get_tmp (g_cache, ΔŨ1)
356+ for i in eachindex (ΔŨtup)
357+ ΔŨ[i] = ΔŨtup[i] # ΔŨ .= ΔŨtup seems to produce a type instability
358+ end
359+ Ŷ = get_tmp (Ŷ_cache, ΔŨ1)
360+ x̂, x̂next = get_tmp (x̂_cache, ΔŨ1), get_tmp (x̂next_cache, ΔŨ1)
361+ u, û = get_tmp (u_cache, ΔŨ1), get_tmp (û_cache, ΔŨ1)
362+ Ŷ, x̂end = predict! (Ŷ, x̂, x̂next, u, û, mpc, model, ΔŨ)
363+ g = get_tmp (g_cache, ΔŨ1)
364+ g = con_nonlinprog! (g, mpc, model, x̂end , Ŷ, ΔŨ)
365+ U, Ȳ, Ū = get_tmp (U_cache, ΔŨ1), get_tmp (Ȳ_cache, ΔŨ1), get_tmp (Ū_cache, ΔŨ1)
366+ return obj_nonlinprog! (U, Ȳ, Ū, mpc, model, Ŷ, ΔŨ):: T
367+ end
368+ function gfunc_i (i, ΔŨtup:: NTuple{N, T} ) where {N, T<: Real }
369+ ΔŨ1 = ΔŨtup[begin ]
370+ ΔŨ, g = get_tmp (ΔŨ_cache, ΔŨ1), get_tmp (g_cache, ΔŨ1)
371+ if any (new != = old for (new, old) in zip (ΔŨtup, ΔŨ)) # new ΔŨtup, update predictions:
372+ for i in eachindex (ΔŨtup)
373+ ΔŨ[i] = ΔŨtup[i] # ΔŨ .= ΔŨtup seems to produce a type instability
374+ end
375+ Ŷ = get_tmp (Ŷ_cache, ΔŨ1)
376+ x̂, x̂next = get_tmp (x̂_cache, ΔŨ1), get_tmp (x̂next_cache, ΔŨ1)
377+ u, û = get_tmp (u_cache, ΔŨ1), get_tmp (û_cache, ΔŨ1)
378+ Ŷ, x̂end = predict! (Ŷ, x̂, x̂next, u, û, mpc, model, ΔŨ)
379+ g = con_nonlinprog! (g, mpc, model, x̂end , Ŷ, ΔŨ)
380+ end
381+ return g[i]:: T
382+ end
383+ gfunc = [(ΔŨ... ) -> gfunc_i (i, ΔŨ) for i in 1 : ng]
384+ return Jfunc, gfunc
385+ end
386+
385387" Set the nonlinear constraints on the output predictions `Ŷ` and terminal states `x̂end`."
386388function setnonlincon! (mpc:: NonLinMPC , :: NonLinModel )
387389 optim = mpc. optim
0 commit comments