Skip to content

Commit 4c645f3

Browse files
committed
custom nonlinear constraint starting to work yay!
1 parent 2410fb9 commit 4c645f3

File tree

2 files changed

+75
-41
lines changed

2 files changed

+75
-41
lines changed

src/controller/construct.jl

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,8 @@ function setconstraint!(
148148
C_Δumin = C_Deltaumin, C_Δumax = C_Deltaumax,
149149
)
150150
model, con, optim = mpc.estim.model, mpc.con, mpc.optim
151-
nu, ny, nx̂, Hp, Hc, nϵ = model.nu, model.ny, mpc.estim.nx̂, mpc.Hp, mpc.Hc, mpc.
151+
nu, ny, nx̂, Hp, Hc = model.nu, model.ny, mpc.estim.nx̂, mpc.Hp, mpc.Hc
152+
nϵ, nc = mpc.nϵ, con.nc
152153
notSolvedYet = (JuMP.termination_status(optim) == JuMP.OPTIMIZE_NOT_CALLED)
153154
if isnothing(Umin) && !isnothing(umin)
154155
size(umin) == (nu,) || throw(ArgumentError("umin size must be $((nu,))"))
@@ -277,7 +278,8 @@ function setconstraint!(
277278
i_Ymin, i_Ymax = .!isinf.(con.Y0min), .!isinf.(con.Y0max)
278279
i_x̂min, i_x̂max = .!isinf.(con.x̂0min), .!isinf.(con.x̂0max)
279280
if notSolvedYet
280-
con.i_b[:], con.i_g[:], con.A[:] = init_matconstraint_mpc(model,
281+
con.i_b[:], con.i_g[:], con.A[:] = init_matconstraint_mpc(
282+
model, nc,
281283
i_Umin, i_Umax, i_ΔŨmin, i_ΔŨmax,
282284
i_Ymin, i_Ymax, i_x̂min, i_x̂max,
283285
con.A_Umin, con.A_Umax, con.A_ΔŨmin, con.A_ΔŨmax,
@@ -291,7 +293,8 @@ function setconstraint!(
291293
@constraint(optim, linconstraint, A*ΔŨvar .≤ b)
292294
setnonlincon!(mpc, model, optim)
293295
else
294-
i_b, i_g = init_matconstraint_mpc(model,
296+
i_b, i_g = init_matconstraint_mpc(
297+
model, nc,
295298
i_Umin, i_Umax, i_ΔŨmin, i_ΔŨmax,
296299
i_Ymin, i_Ymax, i_x̂min, i_x̂max
297300
)
@@ -304,8 +307,10 @@ end
304307

305308

306309
@doc raw"""
307-
init_matconstraint_mpc(model::LinModel,
308-
i_Umin, i_Umax, i_ΔŨmin, i_ΔŨmax, i_Ymin, i_Ymax, i_x̂min, i_x̂max, args...
310+
init_matconstraint_mpc(
311+
model::LinModel, nc::Int,
312+
i_Umin, i_Umax, i_ΔŨmin, i_ΔŨmax, i_Ymin, i_Ymax, i_x̂min, i_x̂max,
313+
args...
309314
) -> i_b, i_g, A
310315
311316
Init `i_b`, `i_g` and `A` matrices for the linear and nonlinear inequality constraints.
@@ -317,17 +322,20 @@ The linear and nonlinear inequality constraints are respectively defined as:
317322
\mathbf{g(ΔŨ)} &≤ \mathbf{0}
318323
\end{aligned}
319324
```
320-
`i_b` is a `BitVector` including the indices of ``\mathbf{b}`` that are finite numbers.
321-
`i_g` is a similar vector but for the indices of ``\mathbf{g}`` (empty if `model` is a
322-
[`LinModel`](@ref)). The method also returns the ``\mathbf{A}`` matrix if `args` is
323-
provided. In such a case, `args` needs to contain all the inequality constraint matrices:
325+
The argument `nc` is the number of custom nonlinear constraints in ``\mathbf{g_c}``. `i_b`
326+
is a `BitVector` including the indices of ``\mathbf{b}`` that are finite numbers. `i_g` is a
327+
similar vector but for the indices of ``\mathbf{g}``. The method also returns the
328+
``\mathbf{A}`` matrix if `args` is provided. In such a case, `args` needs to contain all
329+
the inequality constraint matrices:
324330
`A_Umin, A_Umax, A_ΔŨmin, A_ΔŨmax, A_Ymin, A_Ymax, A_x̂min, A_x̂max`.
325331
"""
326-
function init_matconstraint_mpc(::LinModel{NT},
327-
i_Umin, i_Umax, i_ΔŨmin, i_ΔŨmax, i_Ymin, i_Ymax, i_x̂min, i_x̂max, args...
332+
function init_matconstraint_mpc(
333+
::LinModel{NT}, nc::Int,
334+
i_Umin, i_Umax, i_ΔŨmin, i_ΔŨmax, i_Ymin, i_Ymax, i_x̂min, i_x̂max,
335+
args...
328336
) where {NT<:Real}
329337
i_b = [i_Umin; i_Umax; i_ΔŨmin; i_ΔŨmax; i_Ymin; i_Ymax; i_x̂min; i_x̂max]
330-
i_g = BitVector()
338+
i_g = trues(nc)
331339
if isempty(args)
332340
A = nothing
333341
else
@@ -338,11 +346,13 @@ function init_matconstraint_mpc(::LinModel{NT},
338346
end
339347

340348
"Init `i_b, A` without outputs and terminal constraints if `model` is not a [`LinModel`](@ref)."
341-
function init_matconstraint_mpc(::SimModel{NT},
342-
i_Umin, i_Umax, i_ΔŨmin, i_ΔŨmax, i_Ymin, i_Ymax, i_x̂min, i_x̂max, args...
349+
function init_matconstraint_mpc(
350+
::SimModel{NT}, nc::Int,
351+
i_Umin, i_Umax, i_ΔŨmin, i_ΔŨmax, i_Ymin, i_Ymax, i_x̂min, i_x̂max,
352+
args...
343353
) where {NT<:Real}
344354
i_b = [i_Umin; i_Umax; i_ΔŨmin; i_ΔŨmax]
345-
i_g = [i_Ymin; i_Ymax; i_x̂min; i_x̂max]
355+
i_g = [i_Ymin; i_Ymax; i_x̂min; i_x̂max; trues(nc)]
346356
if isempty(args)
347357
A = nothing
348358
else
@@ -667,7 +677,7 @@ function init_defaultcon_mpc(
667677
i_Ymin, i_Ymax = .!isinf.(Y0min), .!isinf.(Y0max)
668678
i_x̂min, i_x̂max = .!isinf.(x̂0min), .!isinf.(x̂0max)
669679
i_b, i_g, A = init_matconstraint_mpc(
670-
model,
680+
model, nc,
671681
i_Umin, i_Umax, i_ΔŨmin, i_ΔŨmax, i_Ymin, i_Ymax, i_x̂min, i_x̂max,
672682
A_Umin, A_Umax, A_ΔŨmin, A_ΔŨmax, A_Ymin, A_Ymax, A_x̂max, A_x̂min
673683
)

src/controller/nonlinmpc.jl

Lines changed: 49 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,7 @@ function get_mutating_gc(NT, gc)
384384
end
385385

386386
function test_custom_functions(JE, gc!, uop; Uop, dop, Dop, ΔŨ, p)
387-
# TODO: contunue here (important to guide the users, sim! can be used on NonLinModel
387+
# TODO: contunue here (important to guide the user, sim! can be used on NonLinModel,
388388
# but there is no similar function for the custom functions of NonLinMPC)
389389
Ue = [Uop; uop]
390390
D̂e = [dop; Dop]
@@ -458,6 +458,11 @@ function init_optimization!(mpc::NonLinMPC, model::SimModel, optim)
458458
name = Symbol("g_x̂0max_$i")
459459
optim[name] = JuMP.add_nonlinear_operator(optim, nΔŨ, gfunc[i_end_x̂min+i]; name)
460460
end
461+
i_end_x̂max = 2Hp*ny + 2nx̂
462+
for i in 1:con.nc
463+
name = Symbol("g_c_$i")
464+
optim[name] = JuMP.add_nonlinear_operator(optim, nΔŨ, gfunc[i_end_x̂max+i]; name)
465+
end
461466
end
462467
return nothing
463468
end
@@ -471,20 +476,21 @@ Inspired from: [User-defined operators with vector outputs](https://jump.dev/JuM
471476
"""
472477
function get_optim_functions(mpc::NonLinMPC, ::JuMP.GenericModel{JNT}) where JNT<:Real
473478
model = mpc.estim.model
474-
nu, ny, nx̂, Hp = model.nu, model.ny, mpc.estim.nx̂, mpc.Hp
475-
ng, nΔŨ, nU, nŶ = length(mpc.con.i_g), length(mpc.ΔŨ), Hp*nu, Hp*ny
479+
nu, ny, nx̂, nϵ, Hp = model.nu, model.ny, mpc.estim.nx̂, mpc., mpc.Hp
480+
ng, nc, nΔŨ, nU, nŶ = length(mpc.con.i_g), mpc.con.nc, length(mpc.ΔŨ), Hp*nu, Hp*ny
476481
nUe, nŶe = nU + nu, nŶ + ny
477-
Nc = nΔŨ + 3
478-
ΔŨ_cache::DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache(zeros(JNT, nΔŨ), Nc)
479-
Ŷe_cache::DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache(zeros(JNT, nŶe), Nc)
480-
Ue_cache::DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache(zeros(JNT, nUe), Nc)
481-
Ȳ_cache::DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache(zeros(JNT, nŶ), Nc)
482-
Ū_cache::DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache(zeros(JNT, nU), Nc)
483-
x̂0_cache::DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache(zeros(JNT, nx̂), Nc)
484-
x̂0next_cache::DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache(zeros(JNT, nx̂), Nc)
485-
u0_cache::DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache(zeros(JNT, nu), Nc)
486-
û0_cache::DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache(zeros(JNT, nu), Nc)
487-
g_cache::DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache(zeros(JNT, ng), Nc)
482+
Ncache = nΔŨ + 3
483+
ΔŨ_cache::DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache(zeros(JNT, nΔŨ), Ncache)
484+
Ŷe_cache::DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache(zeros(JNT, nŶe), Ncache)
485+
Ue_cache::DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache(zeros(JNT, nUe), Ncache)
486+
Ȳ_cache::DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache(zeros(JNT, nŶ), Ncache)
487+
Ū_cache::DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache(zeros(JNT, nU), Ncache)
488+
x̂0_cache::DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache(zeros(JNT, nx̂), Ncache)
489+
x̂0next_cache::DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache(zeros(JNT, nx̂), Ncache)
490+
u0_cache::DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache(zeros(JNT, nu), Ncache)
491+
û0_cache::DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache(zeros(JNT, nu), Ncache)
492+
g_cache::DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache(zeros(JNT, ng), Ncache)
493+
gc_cache::DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache(zeros(JNT, nc), Ncache)
488494
function Jfunc(ΔŨtup::T...) where T<:Real
489495
ΔŨ1 = ΔŨtup[begin]
490496
ΔŨ, g = get_tmp(ΔŨ_cache, ΔŨ1), get_tmp(g_cache, ΔŨ1)
@@ -495,10 +501,12 @@ function get_optim_functions(mpc::NonLinMPC, ::JuMP.GenericModel{JNT}) where JNT
495501
Ȳ, Ū = get_tmp(Ȳ_cache, ΔŨ1), get_tmp(Ū_cache, ΔŨ1)
496502
x̂0, x̂0next = get_tmp(x̂0_cache, ΔŨ1), get_tmp(x̂0next_cache, ΔŨ1)
497503
u0, û0 = get_tmp(u0_cache, ΔŨ1), get_tmp(û0_cache, ΔŨ1)
498-
g = get_tmp(g_cache, ΔŨ1)
504+
g, gc = get_tmp(g_cache, ΔŨ1), get_tmp(gc_cache, ΔŨ1)
499505
Ŷ0, x̂0end = predict!(Ȳ, x̂0, x̂0next, u0, û0, mpc, model, ΔŨ)
500506
Ŷe, Ue = extended_predictions!(Ŷe, Ue, Ū, mpc, model, Ŷ0, ΔŨ)
501-
g = con_nonlinprog!(g, mpc, model, x̂0end, Ŷ0, ΔŨ)
507+
ϵ = (nϵ == 1) ? ΔŨ[end] : zero(JNT) # ϵ = 0 if nϵ == 0 (meaning no relaxation)
508+
mpc.con.gc!(gc, Ue, Ŷe, mpc.D̂e, mpc.p, ϵ)
509+
g = con_nonlinprog!(g, mpc, model, x̂0end, gc, Ŷ0, ΔŨ, ϵ)
502510
return obj_nonlinprog!(Ȳ, Ū, mpc, model, Ŷe, Ue, ΔŨ)::T
503511
end
504512
function gfunc_i(i, ΔŨtup::NTuple{N, T}) where {N, T<:Real}
@@ -512,10 +520,12 @@ function get_optim_functions(mpc::NonLinMPC, ::JuMP.GenericModel{JNT}) where JNT
512520
Ȳ, Ū = get_tmp(Ȳ_cache, ΔŨ1), get_tmp(Ū_cache, ΔŨ1)
513521
x̂0, x̂0next = get_tmp(x̂0_cache, ΔŨ1), get_tmp(x̂0next_cache, ΔŨ1)
514522
u0, û0 = get_tmp(u0_cache, ΔŨ1), get_tmp(û0_cache, ΔŨ1)
515-
g = get_tmp(g_cache, ΔŨ1)
523+
g, gc = get_tmp(g_cache, ΔŨ1), get_tmp(gc_cache, ΔŨ1)
516524
Ŷ0, x̂0end = predict!(Ȳ, x̂0, x̂0next, u0, û0, mpc, model, ΔŨ)
517525
Ŷe, Ue = extended_predictions!(Ŷe, Ue, Ū, mpc, model, Ŷ0, ΔŨ)
518-
g = con_nonlinprog!(g, mpc, model, x̂0end, Ŷ0, ΔŨ)
526+
ϵ = (nϵ == 1) ? ΔŨ[end] : zero(JNT) # ϵ = 0 if nϵ == 0 (meaning no relaxation)
527+
mpc.con.gc!(gc, Ue, Ŷe, mpc.D̂e, mpc.p, ϵ)
528+
g = con_nonlinprog!(g, mpc, model, x̂0end, gc, Ŷ0, ΔŨ, ϵ)
519529
end
520530
return g[i]::T
521531
end
@@ -568,19 +578,29 @@ function setnonlincon!(
568578
gfunc_i = optim[Symbol("g_x̂0max_$(i)")]
569579
@constraint(optim, gfunc_i(ΔŨvar...) <= 0)
570580
end
581+
for i in 1:con.nc
582+
gfunc_i = optim[Symbol("g_c_$i")]
583+
@constraint(optim, gfunc_i(ΔŨvar...) <= 0)
584+
end
585+
return nothing
586+
end
587+
588+
# TODO: MODIF THE FOLLOWING METHOD!
589+
function setnonlincon!(
590+
mpc::NonLinMPC, ::LinModel, optim::JuMP.GenericModel{JNT}
591+
) where JNT<:Real
571592
return nothing
572593
end
573594

574595
"""
575-
con_nonlinprog!(g, mpc::NonLinMPC, model::SimModel, x̂end, Ŷ, ΔŨ) -> g
596+
con_nonlinprog!(g, mpc::NonLinMPC, model::SimModel, x̂end, gc, Ŷ0, ΔŨ, ϵ) -> g
576597
577598
Nonlinear constrains for [`NonLinMPC`](@ref) when `model` is not a [`LinModel`](@ref).
578599
579-
The method mutates the `g` vector in argument and returns it.
600+
The method mutates the `g` and `gc` vectors in argument.
580601
"""
581-
function con_nonlinprog!(g, mpc::NonLinMPC, ::SimModel, x̂0end, Ŷ0, ΔŨ)
582-
nx̂, nŶ = mpc.estim.nx̂, length(Ŷ0)
583-
ϵ = mpc.== 1 ? ΔŨ[end] : 0 # ϵ = 0 if Cwt=Inf (meaning: no relaxation)
602+
function con_nonlinprog!(g, mpc::NonLinMPC, ::SimModel, x̂0end, gc, Ŷ0, ΔŨ, ϵ)
603+
nx̂, nŶ = length(x̂0end), length(Ŷ0)
584604
for i in eachindex(g)
585605
mpc.con.i_g[i] || continue
586606
if i nŶ
@@ -592,16 +612,20 @@ function con_nonlinprog!(g, mpc::NonLinMPC, ::SimModel, x̂0end, Ŷ0, ΔŨ)
592612
elseif i 2nŶ + nx̂
593613
j = i - 2nŶ
594614
g[i] = (mpc.con.x̂0min[j] - x̂0end[j]) - ϵ*mpc.con.c_x̂min[j]
595-
else
615+
elseif i 2nŶ + 2nx̂
596616
j = i - 2nŶ - nx̂
597617
g[i] = (x̂0end[j] - mpc.con.x̂0max[j]) - ϵ*mpc.con.c_x̂max[j]
618+
else
619+
j = i - 2nŶ - 2nx̂
620+
g[i] = gc[j]
598621
end
599622
end
600623
return g
601624
end
602625

626+
#TODO: MODIF THE FOLLOWING METHOD!
603627
"No nonlinear constraints if `model` is a [`LinModel`](@ref), return `g` unchanged."
604-
con_nonlinprog!(g, ::NonLinMPC, ::LinModel, _ , _ , _ ) = g
628+
con_nonlinprog!(g, ::NonLinMPC, ::LinModel, _ , _ , _ , _ , _ ) = g
605629

606630
"Evaluate the economic term `E*JE` of the objective function for [`NonLinMPC`](@ref)."
607631
function obj_econ!(Ue, Ŷe, mpc::NonLinMPC, model::SimModel)

0 commit comments

Comments
 (0)