Skip to content

Commit 8365f23

Browse files
committed
reduce allocations for NonLinMPC
in-place `predict!` and `con_nonlinprog!` methods
1 parent 640d7f6 commit 8365f23

File tree

2 files changed

+37
-39
lines changed

2 files changed

+37
-39
lines changed

src/controller/nonlinmpc.jl

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -269,8 +269,8 @@ function init_optimization!(mpc::NonLinMPC)
269269
ΔŨ = collect(ΔŨtup)
270270
if ΔŨtup != last_ΔŨtup_float
271271
C = get_tmp(C_cache, ΔŨtup[1])
272-
Ŷ[:] = predict(mpc, model, ΔŨ)
273-
C[:] = con_nonlinprog(mpc, model, Ŷ, ΔŨ)
272+
predict!(Ŷ, mpc, model, ΔŨ)
273+
con_nonlinprog!(C, mpc, model, Ŷ, ΔŨ)
274274
last_ΔŨtup_float = ΔŨtup
275275
end
276276
return obj_nonlinprog(mpc, model, Ŷ, ΔŨ)
@@ -280,8 +280,8 @@ function init_optimization!(mpc::NonLinMPC)
280280
ΔŨ = collect(ΔŨtup)
281281
if ΔŨtup != last_ΔŨtup_dual
282282
C = get_tmp(C_cache, ΔŨtup[1])
283-
Ŷ[:] = predict(mpc, model, ΔŨ)
284-
C[:] = con_nonlinprog(mpc, model, Ŷ, ΔŨ)
283+
predict!(Ŷ, mpc, model, ΔŨ)
284+
con_nonlinprog!(C, mpc, model, Ŷ, ΔŨ)
285285
last_ΔŨtup_dual = ΔŨtup
286286
end
287287
return obj_nonlinprog(mpc, model, Ŷ, ΔŨ)
@@ -291,8 +291,8 @@ function init_optimization!(mpc::NonLinMPC)
291291
if ΔŨtup != last_ΔŨtup_float
292292
= get_tmp(Ŷ_cache, ΔŨtup[1])
293293
ΔŨ = collect(ΔŨtup)
294-
Ŷ[:] = predict(mpc, model, ΔŨ)
295-
C[:] = con_nonlinprog(mpc, model, Ŷ, ΔŨ)
294+
predict!(Ŷ, mpc, model, ΔŨ)
295+
con_nonlinprog!(C, mpc, model, Ŷ, ΔŨ)
296296
last_ΔŨtup_float = ΔŨtup
297297
end
298298
return C[i]
@@ -302,8 +302,8 @@ function init_optimization!(mpc::NonLinMPC)
302302
if ΔŨtup != last_ΔŨtup_dual
303303
= get_tmp(Ŷ_cache, ΔŨtup[1])
304304
ΔŨ = collect(ΔŨtup)
305-
Ŷ[:] = predict(mpc, model, ΔŨ)
306-
C[:] = con_nonlinprog(mpc, model, Ŷ, ΔŨ)
305+
predict!(Ŷ, mpc, model, ΔŨ)
306+
con_nonlinprog!(C, mpc, model, Ŷ, ΔŨ)
307307
last_ΔŨtup_dual = ΔŨtup
308308
end
309309
return C[i]
@@ -351,30 +351,28 @@ end
351351

352352

353353
"""
354-
con_nonlinprog(mpc::NonLinMPC, ::LinModel, ΔŨ::Vector{Real})
354+
con_nonlinprog!(C, mpc::NonLinMPC, model::LinModel, ΔŨ::Vector{Real})
355355
356356
Nonlinear constraints for [`NonLinMPC`](@ref) when `model` is a [`LinModel`](@ref).
357357
"""
358-
function con_nonlinprog(mpc::NonLinMPC, model::LinModel, _, ΔŨ::Vector{T}) where {T<:Real}
359-
return zeros(T, 0)
358+
function con_nonlinprog!(C, ::NonLinMPC, ::LinModel, _ , ::Vector{T}) where {T<:Real}
359+
return C
360360
end
361361
"""
362-
con_nonlinprog(mpc::NonLinMPC, model::NonLinModel, ΔŨ::Vector{Real})
362+
con_nonlinprog!(C, mpc::NonLinMPC, model::NonLinModel, ΔŨ::Vector{Real})
363363
364364
Nonlinear constrains for [`NonLinMPC`](@ref) when `model` is not a [`LinModel`](@ref).
365365
"""
366-
function con_nonlinprog(mpc::NonLinMPC, ::SimModel, Ŷ, ΔŨ::Vector{T}) where {T<:Real}
366+
function con_nonlinprog!(C, mpc::NonLinMPC, model::SimModel, Ŷ, ΔŨ::Vector{T}) where {T<:Real}
367+
ny, Hp = model.ny, mpc.Hp
367368
if !isinf(mpc.C) # constraint softening activated :
368369
ϵ = ΔŨ[end]
369-
C_Ymin = (mpc.con.Ymin - Ŷ) - ϵ*mpc.con.c_Ymin
370-
C_Ymax = (Ŷ - mpc.con.Ymax) - ϵ*mpc.con.c_Ymax
370+
C[begin:(Hp*ny)] = (mpc.con.Ymin - Ŷ) - ϵ*mpc.con.c_Ymin
371+
C[(Hp*ny+1):end] = (Ŷ - mpc.con.Ymax) - ϵ*mpc.con.c_Ymax
371372
else # no constraint softening :
372-
C_Ymin = (mpc.con.Ymin - Ŷ)
373-
C_Ymax = (Ŷ - mpc.con.Ymax)
373+
C[begin:(Hp*ny)] = (mpc.con.Ymin - Ŷ)
374+
C[(Hp*ny+1):end] = (Ŷ - mpc.con.Ymax)
374375
end
375-
# replace -Inf with 0 to avoid INVALID_MODEL error :
376-
C_Ymin[isinf.(C_Ymin)] .= 0
377-
C_Ymax[isinf.(C_Ymax)] .= 0
378-
C = [C_Ymin; C_Ymax]
376+
C[isinf.(C)] .= 0 # replace ±Inf with 0 to avoid INVALID_MODEL error
379377
return C
380378
end

src/predictive_control.jl

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -334,8 +334,8 @@ julia> sol_summary, info = getinfo(mpc); round.(info[:Ŷ], digits=3)
334334
```
335335
"""
336336
function getinfo(mpc::PredictiveController)
337-
sol_summary = get_summary(mpc)
338-
= predict(mpc, mpc.estim.model, mpc.ΔŨ)
337+
sol_summary = get_summary(mpc)
338+
= similar(mpc.Ŷop)
339339
info = Dict{Symbol, InfoDictType}()
340340
info[:ΔU] = mpc.ΔŨ[1:mpc.Hc*mpc.estim.model.nu]
341341
info[] = isinf(mpc.C) ? NaN : mpc.ΔŨ[end]
@@ -345,7 +345,7 @@ function getinfo(mpc::PredictiveController)
345345
info[:d] = mpc.d
346346
info[:D̂] = mpc.
347347
info[:ŷ] = mpc.
348-
info[:Ŷ] =
348+
info[:Ŷ] = predict!(Ŷ, mpc, mpc.estim.model, mpc.ΔŨ)
349349
info[:Ŷs] = mpc.Ŷop - repeat(mpc.estim.model.yop, mpc.Hp) # Ŷop = Ŷs + Yop
350350
info[:R̂y] = mpc.R̂y
351351
info[:R̂u] = mpc.R̂u
@@ -461,34 +461,34 @@ end
461461
predictstoch!(mpc, estim::StateEstimator, _ , _ ) = nothing
462462

463463
@doc raw"""
464-
predict(mpc::PredictiveController, model::LinModel, ΔŨ)
464+
predict!(Ŷ, mpc::PredictiveController, model::LinModel, ΔŨ) -> Ŷ
465465
466466
Evaluate the outputs predictions ``\mathbf{Ŷ}`` when `model` is a [`LinModel`](@ref).
467467
"""
468-
function predict(mpc::PredictiveController, ::LinModel, ΔŨ::Vector{T}) where {T<:Real}
469-
return mpc.*ΔŨ + mpc.F
468+
function predict!(Ŷ, mpc::PredictiveController, ::LinModel, ΔŨ::Vector{T}) where {T<:Real}
469+
Ŷ[:] = mpc.*ΔŨ + mpc.F
470+
return
470471
end
471472

472-
# TODO: remplacer S_p et T_Hp par un if pour éviter les allocs
473473
@doc raw"""
474-
predict(mpc::PredictiveController, model::SimModel, ΔŨ)
474+
predict!(Ŷ, mpc::PredictiveController, model::SimModel, ΔŨ) -> Ŷ
475475
476476
Evaluate ``\mathbf{Ŷ}`` when `model` is not a [`LinModel`](@ref).
477477
"""
478-
function predict(mpc::PredictiveController, model::SimModel, ΔŨ::Vector{T}) where {T<:Real}
479-
nu, ny, nd, Hp = model.nu, model.ny, model.nd, mpc.Hp
480-
yop, dop = model.yop, model.dop
481-
U0 = mpc.S̃_Hp*ΔŨ + mpc.T_Hp*mpc.estim.lastu0
482-
::Vector{T} = copy(mpc.Ŷop) # Ŷop = Ŷs + Yop
483-
u0::Vector{T} = Vector{T}(undef, nu)
478+
function predict!(Ŷ, mpc::PredictiveController, model::SimModel, ΔŨ::Vector{T}) where {T<:Real}
479+
nu, ny, nd, Hp, Hc = model.nu, model.ny, model.nd, mpc.Hp, mpc.Hc
484480
::Vector{T} = copy(mpc.estim.x̂)
485-
d0 = mpc.d - dop
481+
u0::Vector{T} = copy(mpc.estim.lastu0)
482+
d0 = mpc.d - model.dop
486483
for j=1:Hp
487-
u0[:] = @views U0[(1 + nu*(j-1)):(nu*j)]
484+
if j Hc
485+
u0[:] += @views ΔŨ[(1 + nu*(j-1)):(nu*j)]
486+
end
488487
x̂[:] = (mpc.estim, x̂, u0, d0)
489-
d0[:] = @views mpc.D̂[(1 + nd*(j-1)):(nd*j)] - dop
490-
Ŷ[(1 + ny*(j-1)):(ny*j)] += (mpc.estim, x̂, d0)
488+
d0[:] = @views mpc.D̂[(1 + nd*(j-1)):(nd*j)] - model.dop
489+
Ŷ[(1 + ny*(j-1)):(ny*j)] = (mpc.estim, x̂, d0)
491490
end
491+
Ŷ[:] += mpc.Ŷop # Ŷop = Ŷs + Yop, and Ŷs=0 if mpc.estim is not an InternalModel
492492
return
493493
end
494494

0 commit comments

Comments
 (0)