Skip to content

debug: support Hermitian weights in PredictiveController #215

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions src/controller/construct.jl
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,13 @@ struct ControllerWeights{
iszero_E::Bool
isinf_C ::Bool
function ControllerWeights{NT}(
model, Hp, Hc, M_Hp::MW, N_Hc::NW, L_Hp::LW, Cwt=Inf, Ewt=0
M_Hp::MW, N_Hc::NW, L_Hp::LW, Cwt, Ewt
) where {
NT<:Real,
MW<:AbstractMatrix{NT},
NW<:AbstractMatrix{NT},
LW<:AbstractMatrix{NT}
}
validate_weights(model, Hp, Hc, M_Hp, N_Hc, L_Hp, Cwt, Ewt)
nΔU = size(N_Hc, 1)
C = Cwt
isinf_C = isinf(C)
Expand All @@ -87,11 +86,12 @@ struct ControllerWeights{
end
end

"Outer constructor to convert weight matrix number type to `NT` if necessary."
function ControllerWeights{NT}(
model, Hp, Hc, M_Hp::MW, N_Hc::NW, L_Hp::LW, Cwt=Inf, Ewt=0
) where {NT<:Real, MW<:AbstractMatrix, NW<:AbstractMatrix, LW<:AbstractMatrix}
return ControllerWeights{NT}(model, Hp, Hc, NT.(M_Hp), NT.(N_Hc), NT.(L_Hp), Cwt, Ewt)
"Outer constructor to validate and convert weight matrices if necessary."
function ControllerWeights(
model::SimModel{NT}, Hp, Hc, M_Hp, N_Hc, L_Hp, Cwt=Inf, Ewt=0
) where {NT<:Real}
validate_weights(model, Hp, Hc, M_Hp, N_Hc, L_Hp, Cwt, Ewt)
return ControllerWeights{NT}(NT.(M_Hp), NT.(N_Hc), NT.(L_Hp), Cwt, Ewt)
end

"Include all the data for the constraints of [`PredictiveController`](@ref)"
Expand Down
2 changes: 1 addition & 1 deletion src/controller/explicitmpc.jl
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ function ExplicitMPC(
end
nb = move_blocking(Hp, Hc)
Hc = get_Hc(nb)
weights = ControllerWeights{NT}(estim.model, Hp, Hc, M_Hp, N_Hc, L_Hp)
weights = ControllerWeights(estim.model, Hp, Hc, M_Hp, N_Hc, L_Hp)
return ExplicitMPC{NT}(estim, Hp, Hc, nb, weights)
end

Expand Down
2 changes: 1 addition & 1 deletion src/controller/linmpc.jl
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ function LinMPC(
end
nb = move_blocking(Hp, Hc)
Hc = get_Hc(nb)
weights = ControllerWeights{NT}(estim.model, Hp, Hc, M_Hp, N_Hc, L_Hp, Cwt)
weights = ControllerWeights(estim.model, Hp, Hc, M_Hp, N_Hc, L_Hp, Cwt)
return LinMPC{NT}(estim, Hp, Hc, nb, weights, transcription, optim)
end

Expand Down
2 changes: 1 addition & 1 deletion src/controller/nonlinmpc.jl
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ function NonLinMPC(
Hc = get_Hc(nb)
validate_JE(NT, JE)
gc! = get_mutating_gc(NT, gc)
weights = ControllerWeights{NT}(estim.model, Hp, Hc, M_Hp, N_Hc, L_Hp, Cwt, Ewt)
weights = ControllerWeights(estim.model, Hp, Hc, M_Hp, N_Hc, L_Hp, Cwt, Ewt)
return NonLinMPC{NT}(
estim, Hp, Hc, nb, weights, JE, gc!, nc, p, transcription, optim, gradient, jacobian
)
Expand Down
3 changes: 3 additions & 0 deletions src/general.jl
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ isdifferent(x, y) = any(xi !== yi for (xi, yi) in zip(x, y))

"Generate a block diagonal matrix repeating `n` times the matrix `A`."
repeatdiag(A, n::Int) = kron(I(n), A)
function repeatdiag(A::Hermitian{NT, Diagonal{NT, Vector{NT}}}, n::Int) where {NT<:Real}
return Hermitian(repeatdiag(A.data, n), :L) # to return hermitian of a `Diagonal`
end

"In-place version of `repeat` but for vectors only."
function repeat!(Y::Vector, a::Vector, n::Int)
Expand Down
30 changes: 15 additions & 15 deletions test/3_test_predictive_control.jl
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@
mpc9 = LinMPC(model, nint_u=[1, 1], nint_ym=[0, 0])
@test mpc9.estim.nint_u == [1, 1]
@test mpc9.estim.nint_ym == [0, 0]
mpc10 = LinMPC(model, M_Hp=diagm(collect(1.01:0.01:1.2)))
@test mpc10.weights.M_Hp ≈ diagm(collect(1.01:0.01:1.2))
mpc10 = LinMPC(model, M_Hp=Hermitian(diagm(1.01:0.01:1.2), :L))
@test mpc10.weights.M_Hp ≈ diagm(1.01:0.01:1.2)
@test mpc10.weights.M_Hp isa Hermitian{Float64, Matrix{Float64}}
mpc11 = LinMPC(model, N_Hc=diagm([0.1,0.11,0.12,0.13]), Cwt=Inf)
mpc11 = LinMPC(model, N_Hc=Hermitian(diagm([0.1,0.11,0.12,0.13]), :L), Cwt=Inf)
@test mpc11.weights.Ñ_Hc ≈ diagm([0.1,0.11,0.12,0.13])
@test mpc11.weights.Ñ_Hc isa Hermitian{Float64, Matrix{Float64}}
mcp12 = LinMPC(model, L_Hp=diagm(collect(0.001:0.001:0.02)))
@test mcp12.weights.L_Hp ≈ diagm(collect(0.001:0.001:0.02))
mcp12 = LinMPC(model, L_Hp=Hermitian(diagm(0.001:0.001:0.02), :L))
@test mcp12.weights.L_Hp ≈ diagm(0.001:0.001:0.02)
@test mcp12.weights.L_Hp isa Hermitian{Float64, Matrix{Float64}}
model2 = LinModel{Float32}(0.5*ones(1,1), ones(1,1), ones(1,1), zeros(1,0), zeros(1,0), 1.0)
mpc13 = LinMPC(model2)
Expand Down Expand Up @@ -463,14 +463,14 @@ end
mpc9 = ExplicitMPC(model, nint_u=[1, 1], nint_ym=[0, 0])
@test mpc9.estim.nint_u == [1, 1]
@test mpc9.estim.nint_ym == [0, 0]
mpc10 = ExplicitMPC(model, M_Hp=diagm(collect(1.01:0.01:1.2)))
@test mpc10.weights.M_Hp ≈ diagm(collect(1.01:0.01:1.2))
mpc10 = ExplicitMPC(model, M_Hp=Hermitian(diagm(1.01:0.01:1.2), :L))
@test mpc10.weights.M_Hp ≈ diagm(1.01:0.01:1.2)
@test mpc10.weights.M_Hp isa Hermitian{Float64, Matrix{Float64}}
mpc11 = ExplicitMPC(model, N_Hc=diagm([0.1,0.11,0.12,0.13]))
mpc11 = ExplicitMPC(model, N_Hc=Hermitian(diagm([0.1,0.11,0.12,0.13]), :L))
@test mpc11.weights.Ñ_Hc ≈ diagm([0.1,0.11,0.12,0.13])
@test mpc11.weights.Ñ_Hc isa Hermitian{Float64, Matrix{Float64}}
mcp12 = ExplicitMPC(model, L_Hp=diagm(collect(0.001:0.001:0.02)))
@test mcp12.weights.L_Hp ≈ diagm(collect(0.001:0.001:0.02))
mcp12 = ExplicitMPC(model, L_Hp=Hermitian(diagm(0.001:0.001:0.02), :L))
@test mcp12.weights.L_Hp ≈ diagm(0.001:0.001:0.02)
@test mcp12.weights.L_Hp isa Hermitian{Float64, Matrix{Float64}}
model2 = LinModel{Float32}(0.5*ones(1,1), ones(1,1), ones(1,1), zeros(1,0), zeros(1,0), 1.0)
mpc13 = ExplicitMPC(model2)
Expand Down Expand Up @@ -671,14 +671,14 @@ end
nmpc11 = NonLinMPC(nonlinmodel, Hp=15, nint_u=[1, 1], nint_ym=[0, 0])
@test nmpc11.estim.nint_u == [1, 1]
@test nmpc11.estim.nint_ym == [0, 0]
nmpc12 = NonLinMPC(nonlinmodel, Hp=10, M_Hp=diagm(collect(1.01:0.01:1.2)))
@test nmpc12.weights.M_Hp ≈ diagm(collect(1.01:0.01:1.2))
nmpc12 = NonLinMPC(nonlinmodel, Hp=10, M_Hp=Hermitian(diagm(1.01:0.01:1.2), :L))
@test nmpc12.weights.M_Hp ≈ diagm(1.01:0.01:1.2)
@test nmpc12.weights.M_Hp isa Hermitian{Float64, Matrix{Float64}}
nmpc13 = NonLinMPC(nonlinmodel, Hp=10, N_Hc=diagm([0.1,0.11,0.12,0.13]), Cwt=Inf)
nmpc13 = NonLinMPC(nonlinmodel, Hp=10, N_Hc=Hermitian(diagm([0.1,0.11,0.12,0.13]), :L), Cwt=Inf)
@test nmpc13.weights.Ñ_Hc ≈ diagm([0.1,0.11,0.12,0.13])
@test nmpc13.weights.Ñ_Hc isa Hermitian{Float64, Matrix{Float64}}
nmcp14 = NonLinMPC(nonlinmodel, Hp=10, L_Hp=diagm(collect(0.001:0.001:0.02)))
@test nmcp14.weights.L_Hp ≈ diagm(collect(0.001:0.001:0.02))
nmcp14 = NonLinMPC(nonlinmodel, Hp=10, L_Hp=Hermitian(diagm(0.001:0.001:0.02), :L))
@test nmcp14.weights.L_Hp ≈ diagm(0.001:0.001:0.02)
@test nmcp14.weights.L_Hp isa Hermitian{Float64, Matrix{Float64}}
nmpc15 = NonLinMPC(nonlinmodel, Hp=10, gc=(Ue,Ŷe,D̂e,p,ϵ)-> [p*dot(Ue,Ŷe)+sum(D̂e)+ϵ], nc=1, p=10)
LHS = zeros(1)
Expand Down