Skip to content

Commit e4522fc

Browse files
authored
Merge pull request #132 from JuliaControl/reduce_alloc_nmpc
Added: `iszero_W` field in for the 4 weights in `ControllerWeights` struct
2 parents a934f8e + 0e05920 commit e4522fc

File tree

3 files changed

+67
-31
lines changed

3 files changed

+67
-31
lines changed

src/controller/construct.jl

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ struct ControllerWeights{NT<:Real}
44
Ñ_Hc::Hermitian{NT, Matrix{NT}}
55
L_Hp::Hermitian{NT, Matrix{NT}}
66
E ::NT
7+
iszero_M_Hp::Vector{Bool}
8+
iszero_Ñ_Hc::Vector{Bool}
9+
iszero_L_Hp::Vector{Bool}
10+
iszero_E::Bool
711
function ControllerWeights{NT}(
812
model, Hp, Hc, M_Hp, N_Hc, L_Hp, Cwt=Inf, Ewt=0
913
) where NT<:Real
@@ -21,8 +25,12 @@ struct ControllerWeights{NT<:Real}
2125
# ΔŨ = ΔU (only hard constraints)
2226
Ñ_Hc = N_Hc
2327
end
24-
E = Ewt
25-
return new{NT}(M_Hp, Ñ_Hc, L_Hp, E)
28+
E = Ewt
29+
iszero_M_Hp = [iszero(M_Hp)]
30+
iszero_Ñ_Hc = [iszero(Ñ_Hc)]
31+
iszero_L_Hp = [iszero(L_Hp)]
32+
iszero_E = iszero(E)
33+
return new{NT}(M_Hp, Ñ_Hc, L_Hp, E, iszero_M_Hp, iszero_Ñ_Hc, iszero_L_Hp, iszero_E)
2634
end
2735
end
2836

src/controller/execute.jl

Lines changed: 51 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ They are computed with these equations using in-place operations:
179179
\begin{aligned}
180180
\mathbf{F} &= \mathbf{G d_0}(k) + \mathbf{J D̂_0} + \mathbf{K x̂_0}(k)
181181
+ \mathbf{V u_0}(k-1) + \mathbf{B} + \mathbf{Ŷ_s} \\
182-
\mathbf{C_y} &= \mathbf{F} - (\mathbf{R̂_y - Y_{op}}) \\
182+
\mathbf{C_y} &= \mathbf{F} - (\mathbf{R̂_y - Y_{op}}) \\
183183
\mathbf{C_u} &= \mathbf{T} \mathbf{u_0}(k-1) - (\mathbf{R̂_u - U_{op}}) \\
184184
\mathbf{q̃} &= 2[(\mathbf{M}_{H_p} \mathbf{Ẽ})' \mathbf{C_y}
185185
+ (\mathbf{L}_{H_p} \mathbf{S̃})' \mathbf{C_u}] \\
@@ -193,32 +193,38 @@ function initpred!(mpc::PredictiveController, model::LinModel, d, D̂, R̂y, R̂
193193
ŷ, F, q̃, r = mpc.ŷ, mpc.F, mpc.q̃, mpc.r
194194
Cy, Cu, M_Hp_Ẽ, L_Hp_S̃ = mpc.buffer.Ŷ, mpc.buffer.U, mpc.buffer.Ẽ, mpc.buffer.
195195
ŷ .= evaloutput(mpc.estim, d)
196-
predictstoch!(mpc, mpc.estim) # init F with Ŷs for InternalModel
197-
F .+= mpc.B # F = F + B
198-
mul!(F, mpc.K, mpc.estim.x̂0, 1, 1) # F = F + K*x̂0
199-
mul!(F, mpc.V, mpc.estim.lastu0, 1, 1) # F = F + V*lastu0
196+
predictstoch!(mpc, mpc.estim) # init F with Ŷs for InternalModel
197+
F .+= mpc.B # F = F + B
198+
mul!(F, mpc.K, mpc.estim.x̂0, 1, 1) # F = F + K*x̂0
199+
mul!(F, mpc.V, mpc.estim.lastu0, 1, 1) # F = F + V*lastu0
200200
if model.nd 0
201201
mpc.d0 .= d .- model.dop
202202
mpc.D̂0 .=.- mpc.Dop
203203
mpc.D̂e[1:model.nd] .= d
204204
mpc.D̂e[model.nd+1:end] .=
205-
mul!(F, mpc.G, mpc.d0, 1, 1) # F = F + G*d0
206-
mul!(F, mpc.J, mpc.D̂0, 1, 1) # F = F + J*D̂0
205+
mul!(F, mpc.G, mpc.d0, 1, 1) # F = F + G*d0
206+
mul!(F, mpc.J, mpc.D̂0, 1, 1) # F = F + J*D̂0
207207
end
208+
q̃ .= 0
209+
r .= 0
208210
# --- output setpoint tracking term ---
209211
mpc.R̂y .= R̂y
210-
Cy .= F .- (R̂y .- mpc.Yop)
211-
mul!(M_Hp_Ẽ, mpc.weights.M_Hp, mpc.Ẽ)
212-
mul!(q̃, M_Hp_Ẽ', Cy) # q̃ = M_Hp*Ẽ'*Cy
213-
r .= dot(Cy, mpc.weights.M_Hp, Cy)
212+
if !mpc.weights.iszero_M_Hp[]
213+
Cy .= F .- (R̂y .- mpc.Yop)
214+
mul!(M_Hp_Ẽ, mpc.weights.M_Hp, mpc.Ẽ)
215+
mul!(q̃, M_Hp_Ẽ', Cy, 1, 1) # q̃ = q̃ + M_Hp*Ẽ'*Cy
216+
r .+= dot(Cy, mpc.weights.M_Hp, Cy) # r = r + Cy'*M_Hp*Cy
217+
end
214218
# --- input setpoint tracking term ---
215219
mpc.R̂u .= R̂u
216-
Cu .= mpc.T_lastu0 .- (R̂u .- mpc.Uop)
217-
mul!(L_Hp_S̃, mpc.weights.L_Hp, mpc.S̃)
218-
mul!(q̃, L_Hp_S̃', Cu, 1, 1) # q̃ = q̃ + L_Hp*S̃'*Cu
219-
r .+= dot(Cu, mpc.weights.L_Hp, Cu)
220+
if !mpc.weights.iszero_L_Hp[]
221+
Cu .= mpc.T_lastu0 .- (R̂u .- mpc.Uop)
222+
mul!(L_Hp_S̃, mpc.weights.L_Hp, mpc.S̃)
223+
mul!(q̃, L_Hp_S̃', Cu, 1, 1) # q̃ = q̃ + L_Hp*S̃'*Cu
224+
r .+= dot(Cu, mpc.weights.L_Hp, Cu) # r = r + Cu'*L_Hp*Cu
225+
end
220226
# --- finalize ---
221-
lmul!(2, q̃) # q̃ = 2*q̃
227+
lmul!(2, q̃) # q̃ = 2*q̃
222228
return nothing
223229
end
224230

@@ -230,7 +236,7 @@ Init `ŷ, F, d0, D̂0, D̂e, R̂y, R̂u` vectors when model is not a [`LinModel
230236
function initpred!(mpc::PredictiveController, model::SimModel, d, D̂, R̂y, R̂u)
231237
mul!(mpc.T_lastu0, mpc.T, mpc.estim.lastu0)
232238
mpc.ŷ .= evaloutput(mpc.estim, d)
233-
predictstoch!(mpc, mpc.estim) # init F with Ŷs for InternalModel
239+
predictstoch!(mpc, mpc.estim) # init F with Ŷs for InternalModel
234240
if model.nd 0
235241
mpc.d0 .= d .- model.dop
236242
mpc.D̂0 .=.- mpc.Dop
@@ -412,22 +418,36 @@ function obj_nonlinprog!(
412418
) where NT<:Real
413419
nu, ny = model.nu, model.ny
414420
# --- output setpoint tracking term ---
415-
Ȳ .= @views Ŷe[ny+1:end]
416-
Ȳ .= mpc.R̂y .-
417-
JR̂y = dot(Ȳ, mpc.weights.M_Hp, Ȳ)
421+
if mpc.weights.iszero_M_Hp[]
422+
JR̂y = zero(NT)
423+
else
424+
Ȳ .= @views Ŷe[ny+1:end]
425+
Ȳ .= mpc.R̂y .-
426+
JR̂y = dot(Ȳ, mpc.weights.M_Hp, Ȳ)
427+
end
418428
# --- move suppression and slack variable term ---
419-
JΔŨ = dot(ΔŨ, mpc.weights.Ñ_Hc, ΔŨ)
429+
if mpc.weights.iszero_Ñ_Hc[]
430+
JΔŨ = zero(NT)
431+
else
432+
JΔŨ = dot(ΔŨ, mpc.weights.Ñ_Hc, ΔŨ)
433+
end
420434
# --- input setpoint tracking term ---
421-
Ū .= @views Ue[1:end-nu]
422-
Ū .= mpc.R̂u .-
423-
JR̂u = dot(Ū, mpc.weights.L_Hp, Ū)
435+
if mpc.weights.iszero_L_Hp[]
436+
JR̂u = zero(NT)
437+
else
438+
Ū .= @views Ue[1:end-nu]
439+
Ū .= mpc.R̂u .-
440+
JR̂u = dot(Ū, mpc.weights.L_Hp, Ū)
441+
end
424442
# --- economic term ---
425443
E_JE = obj_econ(mpc, model, Ue, Ŷe)
426444
return JR̂y + JΔŨ + JR̂u + E_JE
427445
end
428446

429447
"By default, the economic term is zero."
430-
obj_econ(::PredictiveController, ::SimModel, _ , _ ) = 0.0
448+
function obj_econ(::PredictiveController, ::SimModel, _ , ::AbstractVector{NT}) where NT
449+
return zero(NT)
450+
end
431451

432452
@doc raw"""
433453
optim_objective!(mpc::PredictiveController) -> ΔŨ
@@ -615,35 +635,41 @@ function setmodel!(
615635
for i=1:ny*Hp
616636
mpc.weights.M_Hp[i, i] = Mwt[(i-1) % ny + 1]
617637
end
638+
mpc.weights.iszero_M_Hp[] = iszero(mpc.weights.M_Hp)
618639
elseif !isnothing(M_Hp)
619640
M_Hp = to_hermitian(M_Hp)
620641
nŶ = ny*Hp
621642
size(M_Hp) == (nŶ, nŶ) || throw(ArgumentError("M_Hp size should be ($nŶ, $nŶ)"))
622643
mpc.weights.M_Hp .= M_Hp
644+
mpc.weights.iszero_M_Hp[] = iszero(mpc.weights.M_Hp)
623645
end
624646
if isnothing(Ñ_Hc) && !isnothing(Nwt)
625647
size(Nwt) == (nu,) || throw(ArgumentError("Nwt should be a vector of length $nu"))
626648
any(x -> x < 0, Nwt) && throw(ArgumentError("Nwt values should be nonnegative"))
627649
for i=1:nu*Hc
628650
mpc.weights.Ñ_Hc[i, i] = Nwt[(i-1) % nu + 1]
629651
end
652+
mpc.weights.iszero_Ñ_Hc[] = iszero(mpc.weights.Ñ_Hc)
630653
elseif !isnothing(Ñ_Hc)
631654
Ñ_Hc = to_hermitian(Ñ_Hc)
632655
nΔŨ = nu*Hc+
633656
size(Ñ_Hc) == (nΔŨ, nΔŨ) || throw(ArgumentError("Ñ_Hc size should be ($nΔŨ, $nΔŨ)"))
634657
mpc.weights.Ñ_Hc .= Ñ_Hc
658+
mpc.weights.iszero_Ñ_Hc[] = iszero(mpc.weights.Ñ_Hc)
635659
end
636660
if isnothing(L_Hp) && !isnothing(Lwt)
637661
size(Lwt) == (nu,) || throw(ArgumentError("Lwt should be a vector of length $nu"))
638662
any(x -> x < 0, Lwt) && throw(ArgumentError("Lwt values should be nonnegative"))
639663
for i=1:nu*Hp
640664
mpc.weights.L_Hp[i, i] = Lwt[(i-1) % nu + 1]
641665
end
666+
mpc.weights.iszero_L_Hp[] = iszero(mpc.weights.L_Hp)
642667
elseif !isnothing(L_Hp)
643668
L_Hp = to_hermitian(L_Hp)
644669
nU = nu*Hp
645670
size(L_Hp) == (nU, nU) || throw(ArgumentError("L_Hp size should be ($nU, $nU)"))
646671
mpc.weights.L_Hp .= L_Hp
672+
mpc.weights.iszero_L_Hp[] = iszero(mpc.weights.L_Hp)
647673
end
648674
setmodel_controller!(mpc, x̂op_old)
649675
return mpc

src/controller/nonlinmpc.jl

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -525,7 +525,7 @@ function get_optim_functions(mpc::NonLinMPC, ::JuMP.GenericModel{JNT}) where JNT
525525
gc = get_tmp(gc_cache, ΔŨ1)
526526
Ŷ0, x̂0end = predict!(Ȳ, x̂0, x̂0next, u0, û0, mpc, model, ΔŨ)
527527
Ue, Ŷe = extended_predictions!(Ue, Ŷe, Ū, mpc, model, Ŷ0, ΔŨ)
528-
ϵ = (nϵ 0) ? ΔŨ[end] : 0 # ϵ = 0 if nϵ == 0 (meaning no relaxation)
528+
ϵ = (nϵ 0) ? ΔŨ[end] : zero(T) # ϵ = 0 if nϵ == 0 (meaning no relaxation)
529529
mpc.con.gc!(gc, Ue, Ŷe, mpc.D̂e, mpc.p, ϵ)
530530
g = con_nonlinprog!(g, mpc, model, x̂0end, Ŷ0, gc, ϵ)
531531
return obj_nonlinprog!(Ȳ, Ū, mpc, model, Ue, Ŷe, ΔŨ)::T
@@ -544,7 +544,7 @@ function get_optim_functions(mpc::NonLinMPC, ::JuMP.GenericModel{JNT}) where JNT
544544
gc = get_tmp(gc_cache, ΔŨ1)
545545
Ŷ0, x̂0end = predict!(Ȳ, x̂0, x̂0next, u0, û0, mpc, model, ΔŨ)
546546
Ue, Ŷe = extended_predictions!(Ue, Ŷe, Ū, mpc, model, Ŷ0, ΔŨ)
547-
ϵ = (nϵ 0) ? ΔŨ[end] : 0 # ϵ = 0 if nϵ == 0 (meaning no relaxation)
547+
ϵ = (nϵ 0) ? ΔŨ[end] : zero(T) # ϵ = 0 if nϵ == 0 (meaning no relaxation)
548548
mpc.con.gc!(gc, Ue, Ŷe, mpc.D̂e, mpc.p, ϵ)
549549
g = con_nonlinprog!(g, mpc, model, x̂0end, Ŷ0, gc, ϵ)
550550
end
@@ -702,7 +702,9 @@ function con_nonlinprog!(g, mpc::NonLinMPC, ::SimModel, x̂0end, Ŷ0, gc, ϵ)
702702
end
703703

704704
"Evaluate the economic term `E*JE` of the objective function for [`NonLinMPC`](@ref)."
705-
function obj_econ(mpc::NonLinMPC, model::SimModel, Ue, Ŷe)
706-
E_JE = iszero(mpc.weights.E) ? 0.0 : mpc.weights.E*mpc.JE(Ue, Ŷe, mpc.D̂e, mpc.p)
705+
function obj_econ(
706+
mpc::NonLinMPC, model::SimModel, Ue, Ŷe::AbstractVector{NT}
707+
) where NT<:Real
708+
E_JE = mpc.weights.iszero_E ? zero(NT) : mpc.weights.E*mpc.JE(Ue, Ŷe, mpc.D̂e, mpc.p)
707709
return E_JE
708710
end

0 commit comments

Comments
 (0)