Skip to content

Commit 6e44268

Browse files
authored
Merge pull request #77 from JuliaControl/online_weigts_adapt
Added: online modification of weights and covariances
2 parents bd928b4 + 4a688ee commit 6e44268

20 files changed

+351
-173
lines changed

README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,10 @@ for more detailed examples.
8585
- [x] input setpoint tracking
8686
- [x] terminal costs
8787
- [x] economic costs (economic model predictive control)
88-
- [ ] adaptive linear model predictive controller
88+
- [x] adaptive linear model predictive controller
8989
- [x] manual model modification
9090
- [x] automatic successive linearization of a nonlinear model
91-
- [ ] objective function weights modification
91+
- [x] objective function weights and covariance matrices modification
9292
- [x] explicit predictive controller for problems without constraint
9393
- [x] online-tunable soft and hard constraints on:
9494
- [x] output predictions
@@ -126,7 +126,9 @@ for more detailed examples.
126126
- [x] manipulated inputs
127127
- [x] measured outputs
128128
- [x] bumpless manual to automatic transfer for control with a proper initial estimate
129-
- [x] observers in predictor form to ease control applications
129+
- [ ] estimators in two possible forms:
130+
- [x] predictor (or delayed) form to reduce computational load
131+
- [ ] filter (or current) form to improve accuracy and robustness
130132
- [x] moving horizon estimator in two formulations:
131133
- [x] linear plant models (quadratic optimization)
132134
- [x] nonlinear plant models (nonlinear optimization)

docs/src/manual/nonlinmpc.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ old_logger = global_logger(); global_logger(errlogger);
1212
## Nonlinear Model
1313

1414
In this example, the goal is to control the angular position ``θ`` of a pendulum
15-
attached to a motor. Knowing that the manipulated input is the motor torque ``τ``, the I/O
16-
vectors are:
15+
attached to a motor. Knowing that the manipulated input is the motor torque ``τ`` in Nm, the
16+
I/O vectors are:
1717

1818
```math
1919
\begin{aligned}
@@ -49,7 +49,7 @@ using ModelPredictiveControl
4949
function pendulum(par, x, u)
5050
g, L, K, m = par # [m/s²], [m], [kg/s], [kg]
5151
θ, ω = x[1], x[2] # [rad], [rad/s]
52-
τ = u[1] # [N m]
52+
τ = u[1] # [Nm]
5353
dθ = ω
5454
dω = -g/L*sin(θ) - K/m*ω + τ/m/L^2
5555
return [dθ, dω]
@@ -59,7 +59,7 @@ const par = (9.8, 0.4, 1.2, 0.3)
5959
f(x, u, _ ) = pendulum(par, x, u)
6060
h(x, _ ) = [180/π*x[1]] # [°]
6161
nu, nx, ny, Ts = 1, 2, 1, 0.1
62-
vu, vx, vy = ["\$τ\$ (N m)"], ["\$θ\$ (rad)", "\$ω\$ (rad/s)"], ["\$θ\$ (°)"]
62+
vu, vx, vy = ["\$τ\$ (Nm)"], ["\$θ\$ (rad)", "\$ω\$ (rad/s)"], ["\$θ\$ (°)"]
6363
model = setname!(NonLinModel(f, h, Ts, nu, nx, ny); u=vu, x=vx, y=vy)
6464
```
6565

docs/src/public/generic_func.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ initstate!
3737
setstate!
3838
```
3939

40-
## Set Plant Model
40+
## Set Model and Weights
4141

4242
```@docs
4343
setmodel!

src/controller/construct.jl

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -144,9 +144,8 @@ function setconstraint!(
144144
C_Δumin = C_Deltaumin, C_Δumax = C_Deltaumax,
145145
)
146146
model, con, optim = mpc.estim.model, mpc.con, mpc.optim
147-
nu, ny, nx̂, Hp, Hc = model.nu, model.ny, mpc.estim.nx̂, mpc.Hp, mpc.Hc
147+
nu, ny, nx̂, Hp, Hc, nϵ = model.nu, model.ny, mpc.estim.nx̂, mpc.Hp, mpc.Hc, mpc.
148148
notSolvedYet = (JuMP.termination_status(optim) == JuMP.OPTIMIZE_NOT_CALLED)
149-
C = mpc.C
150149
isnothing(Umin) && !isnothing(umin) && (Umin = repeat(umin, Hp))
151150
isnothing(Umax) && !isnothing(umax) && (Umax = repeat(umax, Hp))
152151
isnothing(ΔUmin) && !isnothing(Δumin) && (ΔUmin = repeat(Δumin, Hc))
@@ -160,7 +159,7 @@ function setconstraint!(
160159
isnothing(C_ymin) && !isnothing(c_ymin) && (C_ymin = repeat(c_ymin, Hp))
161160
isnothing(C_ymax) && !isnothing(c_ymax) && (C_ymax = repeat(c_ymax, Hp))
162161
if !all(isnothing.((C_umin, C_umax, C_Δumin, C_Δumax, C_ymin, C_ymax, c_x̂min, c_x̂max)))
163-
!isinf(C) || throw(ArgumentError("Slack variable weight Cwt must be finite to set softness parameters"))
162+
== 1 || throw(ArgumentError("Slack variable weight Cwt must be finite to set softness parameters"))
164163
notSolvedYet || error("Cannot set softness parameters after calling moveinput!")
165164
end
166165
if !isnothing(Umin)
@@ -605,6 +604,7 @@ function init_defaultcon_mpc(
605604
) where {NT<:Real}
606605
model = estim.model
607606
nu, ny, nx̂ = model.nu, model.ny, estim.nx̂
607+
= isinf(C) ? 0 : 1
608608
u0min, u0max = fill(convert(NT,-Inf), nu), fill(convert(NT,+Inf), nu)
609609
Δumin, Δumax = fill(convert(NT,-Inf), nu), fill(convert(NT,+Inf), nu)
610610
y0min, y0max = fill(convert(NT,-Inf), ny), fill(convert(NT,+Inf), ny)
@@ -617,12 +617,12 @@ function init_defaultcon_mpc(
617617
repeat_constraints(Hp, Hc, u0min, u0max, Δumin, Δumax, y0min, y0max)
618618
C_umin, C_umax, C_Δumin, C_Δumax, C_ymin, C_ymax =
619619
repeat_constraints(Hp, Hc, c_umin, c_umax, c_Δumin, c_Δumax, c_ymin, c_ymax)
620-
A_Umin, A_Umax, S̃ = relaxU(model, C, C_umin, C_umax, S)
620+
A_Umin, A_Umax, S̃ = relaxU(model, , C_umin, C_umax, S)
621621
A_ΔŨmin, A_ΔŨmax, ΔŨmin, ΔŨmax, Ñ_Hc = relaxΔU(
622-
model, C, C_Δumin, C_Δumax, ΔUmin, ΔUmax, N_Hc
622+
model, nϵ, C, C_Δumin, C_Δumax, ΔUmin, ΔUmax, N_Hc
623623
)
624-
A_Ymin, A_Ymax, Ẽ = relaxŶ(model, C, C_ymin, C_ymax, E)
625-
A_x̂min, A_x̂max, ẽx̂ = relaxterminal(model, C, c_x̂min, c_x̂max, ex̂)
624+
A_Ymin, A_Ymax, Ẽ = relaxŶ(model, , C_ymin, C_ymax, E)
625+
A_x̂min, A_x̂max, ẽx̂ = relaxterminal(model, , c_x̂min, c_x̂max, ex̂)
626626
i_Umin, i_Umax = .!isinf.(U0min), .!isinf.(U0max)
627627
i_ΔŨmin, i_ΔŨmax = .!isinf.(ΔŨmin), .!isinf.(ΔŨmax)
628628
i_Ymin, i_Ymax = .!isinf.(Y0min), .!isinf.(Y0max)
@@ -639,7 +639,7 @@ function init_defaultcon_mpc(
639639
A_Umin , A_Umax, A_ΔŨmin, A_ΔŨmax , A_Ymin , A_Ymax , A_x̂min , A_x̂max,
640640
A , b , i_b , C_ymin , C_ymax , c_x̂min , c_x̂max , i_g
641641
)
642-
return con, S̃, Ñ_Hc, Ẽ
642+
return con, nϵ, S̃, Ñ_Hc, Ẽ
643643
end
644644

645645
"Repeat predictive controller constraints over prediction `Hp` and control `Hc` horizons."
@@ -656,7 +656,7 @@ end
656656

657657

658658
@doc raw"""
659-
relaxU(model, C, C_umin, C_umax, S) -> A_Umin, A_Umax, S̃
659+
relaxU(model, , C_umin, C_umax, S) -> A_Umin, A_Umax, S̃
660660
661661
Augment manipulated inputs constraints with slack variable ϵ for softening.
662662
@@ -678,8 +678,8 @@ constraints:
678678
in which ``\mathbf{U_{min}, U_{max}}`` and ``\mathbf{U_{op}}`` vectors respectively contains
679679
``\mathbf{u_{min}, u_{max}}`` and ``\mathbf{u_{op}}`` repeated ``H_p`` times.
680680
"""
681-
function relaxU(::SimModel{NT}, C, C_umin, C_umax, S) where {NT<:Real}
682-
if !isinf(C) # ΔŨ = [ΔU; ϵ]
681+
function relaxU(::SimModel{NT}, , C_umin, C_umax, S) where NT<:Real
682+
if == 1 # ΔŨ = [ΔU; ϵ]
683683
# ϵ impacts ΔU → U conversion for constraint calculations:
684684
A_Umin, A_Umax = -[S C_umin], [S -C_umax]
685685
# ϵ has no impact on ΔU → U conversion for prediction calculations:
@@ -693,7 +693,7 @@ end
693693

694694
@doc raw"""
695695
relaxΔU(
696-
model, C, C_Δumin, C_Δumax, ΔUmin, ΔUmax, N_Hc
696+
model, nϵ, C, C_Δumin, C_Δumax, ΔUmin, ΔUmax, N_Hc
697697
) -> A_ΔŨmin, A_ΔŨmax, ΔŨmin, ΔŨmax, Ñ_Hc
698698
699699
Augment input increments constraints with slack variable ϵ for softening.
@@ -714,9 +714,9 @@ returns the augmented constraints ``\mathbf{ΔŨ_{min}}`` and ``\mathbf{ΔŨ_{
714714
\end{bmatrix}
715715
```
716716
"""
717-
function relaxΔU(::SimModel{NT}, C, C_Δumin, C_Δumax, ΔUmin, ΔUmax, N_Hc) where {NT<:Real}
717+
function relaxΔU(::SimModel{NT}, nϵ, C, C_Δumin, C_Δumax, ΔUmin, ΔUmax, N_Hc) where NT<:Real
718718
nΔU = size(N_Hc, 1)
719-
if !isinf(C) # ΔŨ = [ΔU; ϵ]
719+
if == 1 # ΔŨ = [ΔU; ϵ]
720720
# 0 ≤ ϵ ≤ ∞
721721
ΔŨmin, ΔŨmax = [ΔUmin; NT[0.0]], [ΔUmax; NT[Inf]]
722722
A_ϵ = [zeros(NT, 1, length(ΔUmin)) NT[1.0]]
@@ -732,7 +732,7 @@ function relaxΔU(::SimModel{NT}, C, C_Δumin, C_Δumax, ΔUmin, ΔUmax, N_Hc) w
732732
end
733733

734734
@doc raw"""
735-
relaxŶ(::LinModel, C, C_ymin, C_ymax, E) -> A_Ymin, A_Ymax, Ẽ
735+
relaxŶ(::LinModel, , C_ymin, C_ymax, E) -> A_Ymin, A_Ymax, Ẽ
736736
737737
Augment linear output prediction constraints with slack variable ϵ for softening.
738738
@@ -753,8 +753,8 @@ Denoting the input increments augmented with the slack variable
753753
in which ``\mathbf{Y_{min}, Y_{max}}`` and ``\mathbf{Y_{op}}`` vectors respectively contains
754754
``\mathbf{y_{min}, y_{max}}`` and ``\mathbf{y_{op}}`` repeated ``H_p`` times.
755755
"""
756-
function relaxŶ(::LinModel{NT}, C, C_ymin, C_ymax, E) where {NT<:Real}
757-
if !isinf(C) # ΔŨ = [ΔU; ϵ]
756+
function relaxŶ(::LinModel{NT}, , C_ymin, C_ymax, E) where NT<:Real
757+
if == 1 # ΔŨ = [ΔU; ϵ]
758758
# ϵ impacts predicted output constraint calculations:
759759
A_Ymin, A_Ymax = -[E C_ymin], [E -C_ymax]
760760
# ϵ has no impact on output predictions:
@@ -767,14 +767,14 @@ function relaxŶ(::LinModel{NT}, C, C_ymin, C_ymax, E) where {NT<:Real}
767767
end
768768

769769
"Return empty matrices if model is not a [`LinModel`](@ref)"
770-
function relaxŶ(::SimModel{NT}, C, C_ymin, C_ymax, E) where {NT<:Real}
771-
= !isinf(C) ? [E zeros(NT, 0, 1)] : E
770+
function relaxŶ(::SimModel{NT}, , C_ymin, C_ymax, E) where NT<:Real
771+
= [E zeros(NT, 0, nϵ)]
772772
A_Ymin, A_Ymax = -Ẽ, Ẽ
773773
return A_Ymin, A_Ymax, Ẽ
774774
end
775775

776776
@doc raw"""
777-
relaxterminal(::LinModel, C, c_x̂min, c_x̂max, ex̂) -> A_x̂min, A_x̂max, ẽx̂
777+
relaxterminal(::LinModel, , c_x̂min, c_x̂max, ex̂) -> A_x̂min, A_x̂max, ẽx̂
778778
779779
Augment terminal state constraints with slack variable ϵ for softening.
780780
@@ -794,8 +794,8 @@ the inequality constraints:
794794
\end{bmatrix}
795795
```
796796
"""
797-
function relaxterminal(::LinModel{NT}, C, c_x̂min, c_x̂max, ex̂) where {NT<:Real}
798-
if !isinf(C) # ΔŨ = [ΔU; ϵ]
797+
function relaxterminal(::LinModel{NT}, , c_x̂min, c_x̂max, ex̂) where {NT<:Real}
798+
if == 1 # ΔŨ = [ΔU; ϵ]
799799
# ϵ impacts terminal state constraint calculations:
800800
A_x̂min, A_x̂max = -[ex̂ c_x̂min], [ex̂ -c_x̂max]
801801
# ϵ has no impact on terminal state predictions:
@@ -808,8 +808,8 @@ function relaxterminal(::LinModel{NT}, C, c_x̂min, c_x̂max, ex̂) where {NT<:R
808808
end
809809

810810
"Return empty matrices if model is not a [`LinModel`](@ref)"
811-
function relaxterminal(::SimModel{NT}, C, c_x̂min, c_x̂max, ex̂) where {NT<:Real}
812-
ẽx̂ = !isinf(C) ? [ex̂ zeros(NT, 0, 1)] : ex̂
811+
function relaxterminal(::SimModel{NT}, , c_x̂min, c_x̂max, ex̂) where {NT<:Real}
812+
ẽx̂ = [ex̂ zeros(NT, 0, nϵ)]
813813
A_x̂min, A_x̂max = -ẽx̂, ẽx̂
814814
return A_x̂min, A_x̂max, ẽx̂
815815
end
@@ -853,7 +853,7 @@ function init_stochpred(estim::StateEstimator{NT}, _ ) where NT<:Real
853853
end
854854

855855
"Validate predictive controller weight and horizon specified values."
856-
function validate_weights(model, Hp, Hc, M_Hp, N_Hc, L_Hp, C, E=nothing)
856+
function validate_weights(model, Hp, Hc, M_Hp, N_Hc, L_Hp, C=Inf, E=nothing)
857857
nu, ny = model.nu, model.ny
858858
nM, nN, nL = ny*Hp, nu*Hc, nu*Hp
859859
Hp < 1 && throw(ArgumentError("Prediction horizon Hp should be ≥ 1"))

src/controller/execute.jl

Lines changed: 59 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ function getinfo(mpc::PredictiveController{NT}) where NT<:Real
127127
Ŷs .= mpc.F # predictstoch! init mpc.F with Ŷs value if estim is an InternalModel
128128
mpc.F .= oldF # restore old F value
129129
info[:ΔU] = mpc.ΔŨ[1:mpc.Hc*model.nu]
130-
info[] = isinf(mpc.C) ? NaN : mpc.ΔŨ[end]
130+
info[] = mpc.== 1 ? mpc.ΔŨ[end] : NaN
131131
info[:J] = J
132132
info[:U] = U0 + mpc.Uop
133133
info[:u] = info[:U][1:model.nu]
@@ -468,7 +468,7 @@ function optim_objective!(mpc::PredictiveController{NT}) where {NT<:Real}
468468
model = mpc.estim.model
469469
ΔŨvar::Vector{JuMP.VariableRef} = optim[:ΔŨvar]
470470
# initial ΔŨ (warm-start): [Δu_{k-1}(k); Δu_{k-1}(k+1); ... ; 0_{nu × 1}; ϵ_{k-1}]
471-
ϵ0 = !isinf(mpc.C) ? mpc.ΔŨ[end] : empty(mpc.ΔŨ)
471+
ϵ0 = (mpc.== 1) ? mpc.ΔŨ[end] : empty(mpc.ΔŨ)
472472
ΔŨ0 = [mpc.ΔŨ[(model.nu+1):(mpc.Hc*model.nu)]; zeros(NT, model.nu); ϵ0]
473473
JuMP.set_start_value.(ΔŨvar, ΔŨ0)
474474
set_objective_linear_coef!(mpc, ΔŨvar)
@@ -523,46 +523,70 @@ Set `mpc.estim.x̂0` to `x̂ - estim.x̂op` from the argument `x̂`.
523523
setstate!(mpc::PredictiveController, x̂) = (setstate!(mpc.estim, x̂); return mpc)
524524

525525

526-
"""
527-
setmodel!(mpc::PredictiveController, model::LinModel) -> mpc
526+
@doc raw"""
527+
setmodel!(mpc::PredictiveController, model=mpc.estim.model, <keyword arguments>) -> mpc
528+
529+
Set `model` and objective function weights of `mpc` [`PredictiveController`](@ref).
528530
529-
Set model and operating points of `mpc` [`PredictiveController`](@ref) to `model` values.
531+
Allows model adaptation of controllers based on [`LinModel`](@ref) at runtime. Modification
532+
of [`NonLinModel`](@ref) state-space functions is not supported. New weight matrices in the
533+
objective function can be specified with the keyword arguments (see [`LinMPC`](@ref) for the
534+
nomenclature). If `Cwt ≠ Inf`, the augmented move suppression weight is ``\mathbf{Ñ}_{H_c} =
535+
\mathrm{diag}(\mathbf{N}_{H_c}, C)``, else ``\mathbf{Ñ}_{H_c} = \mathbf{N}_{H_c}``. The
536+
[`StateEstimator`](@ref) `mpc.estim` cannot be a [`Luenberger`](@ref) observer or a
537+
[`SteadyKalmanFilter`](@ref) (the default estimator). Construct the `mpc` object with a
538+
time-varying [`KalmanFilter`](@ref) instead. Note that the model is constant over the
539+
prediction horizon ``H_p``.
530540
531-
Allows model adaptation of controllers based on [`LinModel`](@ref) at runtime ([`NonLinModel`](@ref)
532-
is not supported). The [`StateEstimator`](@ref) `mpc.estim` cannot be a [`Luenberger`](@ref)
533-
observer or a [`SteadyKalmanFilter`](@ref) (the default estimator). Construct the `mpc`
534-
object with a time-varying [`KalmanFilter`](@ref) instead. Note that the model is constant
535-
over the prediction horizon ``H_p``.
541+
# Arguments
542+
543+
- `mpc::PredictiveController` : controller to set model and weights.
544+
- `model=mpc.estim.model` : new plant model ([`NonLinModel`](@ref) not supported).
545+
- `M_Hp=mpc.M_Hp` : new ``\mathbf{M_{H_p}}`` weight matrix.
546+
- `Ñ_Hc=mpc.Ñ_Hc` : new ``\mathbf{Ñ_{H_c}}`` weight matrix (see definition above).
547+
- `L_Hp=mpc.L_Hp` : new ``\mathbf{L_{H_p}}`` weight matrix.
548+
- additional keyword arguments are passed to `setmodel!(::StateEstimator)`.
536549
537550
# Examples
538551
```jldoctest
539-
julia> kf = KalmanFilter(LinModel(ss(0.1, 0.5, 1, 0, 4.0)));
552+
julia> mpc = LinMPC(KalmanFilter(LinModel(ss(0.1, 0.5, 1, 0, 4.0)), σR=[√25]), Hp=1, Hc=1);
553+
554+
julia> mpc.estim.model.A[], mpc.estim.R̂[], mpc.M_Hp[]
555+
(0.1, 25.0, 1.0)
540556
541-
julia> mpc = LinMPC(kf); mpc.estim.model.A
542-
1×1 Matrix{Float64}:
543-
0.1
557+
julia> setmodel!(mpc, LinModel(ss(0.42, 0.5, 1, 0, 4.0)); R̂=[9], M_Hp=[0]);
544558
545-
julia> setmodel!(mpc, LinModel(ss(0.42, 0.5, 1, 0, 4.0))); mpc.estim.model.A
546-
1×1 Matrix{Float64}:
547-
0.42
559+
julia> mpc.estim.model.A[], mpc.estim.R̂[], mpc.M_Hp[]
560+
(0.42, 9.0, 0.0)
548561
```
549562
"""
550-
function setmodel!(mpc::PredictiveController, model::LinModel)
563+
function setmodel!(
564+
mpc::PredictiveController,
565+
model = mpc.estim.model;
566+
M_Hp = mpc.M_Hp,
567+
Ñ_Hc = mpc.Ñ_Hc,
568+
L_Hp = mpc.L_Hp,
569+
kwargs...
570+
)
551571
x̂op_old = copy(mpc.estim.x̂op)
552-
setmodel!(mpc.estim, model)
553-
setmodel_controller!(mpc, model, x̂op_old)
572+
nu, ny, Hp, Hc, nϵ = model.nu, model.ny, mpc.Hp, mpc.Hc, mpc.
573+
setmodel!(mpc.estim, model; kwargs...)
574+
mpc.M_Hp .= to_hermitian(M_Hp)
575+
mpc.Ñ_Hc .= to_hermitian(Ñ_Hc)
576+
mpc.L_Hp .= to_hermitian(L_Hp)
577+
setmodel_controller!(mpc, x̂op_old, M_Hp, Ñ_Hc, L_Hp)
554578
return mpc
555579
end
556580

557581
"Update the prediction matrices, linear constraints and JuMP optimization."
558-
function setmodel_controller!(mpc::PredictiveController, model::LinModel, x̂op_old)
559-
estim = mpc.estim
582+
function setmodel_controller!(mpc::PredictiveController, x̂op_old, M_Hp, Ñ_Hc, L_Hp)
583+
estim, model = mpc.estim, mpc.estim.model
560584
nu, ny, nd, Hp, Hc = model.nu, model.ny, model.nd, mpc.Hp, mpc.Hc
561585
optim, con = mpc.optim, mpc.con
562586
# --- predictions matrices ---
563587
E, G, J, K, V, B, ex̂, gx̂, jx̂, kx̂, vx̂, bx̂ = init_predmat(estim, model, Hp, Hc)
564-
A_Ymin, A_Ymax, Ẽ = relaxŶ(model, mpc.C, con.C_ymin, con.C_ymax, E)
565-
A_x̂min, A_x̂max, ẽx̂ = relaxterminal(model, mpc.C, con.c_x̂min, con.c_x̂max, ex̂)
588+
A_Ymin, A_Ymax, Ẽ = relaxŶ(model, mpc., con.C_ymin, con.C_ymax, E)
589+
A_x̂min, A_x̂max, ẽx̂ = relaxterminal(model, mpc., con.c_x̂min, con.c_x̂max, ex̂)
566590
mpc.Ẽ .=
567591
mpc.G .= G
568592
mpc.J .= J
@@ -598,11 +622,20 @@ function setmodel_controller!(mpc::PredictiveController, model::LinModel, x̂op_
598622
con.A_Ymax .= A_Ymax
599623
con.A_x̂min .= A_x̂min
600624
con.A_x̂max .= A_x̂max
601-
nUandΔŨ = length(con.U0min) + length(con.U0max) + length(con.ΔŨmin) + length(con.ΔŨmax)
602-
con.A[nUandΔŨ+1:end, :] = [con.A_Ymin; con.A_Ymax; con.A_x̂min; con.A_x̂max]
625+
con.A .= [
626+
con.A_Umin
627+
con.A_Umax
628+
con.A_ΔŨmin
629+
con.A_ΔŨmax
630+
con.A_Ymin
631+
con.A_Ymax
632+
con.A_x̂min
633+
con.A_x̂max
634+
]
603635
A = con.A[con.i_b, :]
604636
b = con.b[con.i_b]
605637
ΔŨvar::Vector{JuMP.VariableRef} = optim[:ΔŨvar]
638+
# deletion is required for sparse solvers like OSQP, when the sparsity pattern changes
606639
JuMP.delete(optim, optim[:linconstraint])
607640
JuMP.unregister(optim, :linconstraint)
608641
@constraint(optim, linconstraint, A*ΔŨvar .≤ b)

0 commit comments

Comments
 (0)