Skip to content

Commit 3f4af69

Browse files
committed
debug: terminal constraint now works with MultipleShooting + NonLinModel
1 parent 31cac69 commit 3f4af69

File tree

4 files changed

+134
-66
lines changed

4 files changed

+134
-66
lines changed

src/controller/construct.jl

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,7 @@ function setconstraint!(
386386
JuMP.delete(optim, optim[:linconstraint])
387387
JuMP.unregister(optim, :linconstraint)
388388
@constraint(optim, linconstraint, A*Z̃var .≤ b)
389-
set_nonlincon!(mpc, model, optim)
389+
set_nonlincon!(mpc, model, optim, transcription)
390390
else
391391
i_b, i_g = init_matconstraint_mpc(
392392
model, transcription, nc,
@@ -484,10 +484,6 @@ function init_matconstraint_mpc(
484484
return i_b, i_g, A, Aeq, neq
485485
end
486486

487-
488-
"By default, there is no nonlinear constraint, thus do nothing."
489-
set_nonlincon!(::PredictiveController, ::SimModel, ::JuMP.GenericModel) = nothing
490-
491487
"""
492488
default_Hp(model::LinModel)
493489

src/controller/nonlinmpc.jl

Lines changed: 1 addition & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -509,7 +509,7 @@ function init_optimization!(mpc::NonLinMPC, model::SimModel, optim)
509509
@operator(optim, J, nZ̃, Jfunc, ∇Jfunc!)
510510
@objective(optim, Min, J(Z̃var...))
511511
init_nonlincon!(mpc, model, transcription, gfuncs, ∇gfuncs!, geqfuncs, ∇geqfuncs!)
512-
set_nonlincon!(mpc, model, optim)
512+
set_nonlincon!(mpc, model, optim, transcription)
513513
return nothing
514514
end
515515

@@ -692,60 +692,6 @@ function get_optim_functions(mpc::NonLinMPC, ::JuMP.GenericModel{JNT}) where JNT
692692
return Jfunc, ∇Jfunc!, gfuncs, ∇gfuncs!, geqfuncs, ∇geqfuncs!
693693
end
694694

695-
"""
696-
set_nonlincon!(mpc::NonLinMPC, ::LinModel, optim)
697-
698-
Set the custom nonlinear inequality constraints for `LinModel`.
699-
"""
700-
function set_nonlincon!(
701-
mpc::NonLinMPC, ::LinModel, optim::JuMP.GenericModel{JNT}
702-
) where JNT<:Real
703-
Z̃var = optim[:Z̃var]
704-
con = mpc.con
705-
nonlin_constraints = JuMP.all_constraints(optim, JuMP.NonlinearExpr, MOI.LessThan{JNT})
706-
map(con_ref -> JuMP.delete(optim, con_ref), nonlin_constraints)
707-
for i in 1:con.nc
708-
gfunc_i = optim[Symbol("g_c_$i")]
709-
@constraint(optim, gfunc_i(Z̃var...) <= 0)
710-
end
711-
return nothing
712-
end
713-
714-
"""
715-
set_nonlincon!(mpc::NonLinMPC, ::NonLinModel, optim)
716-
717-
Also set output prediction `Ŷ` and terminal state `x̂end` constraints when not a `LinModel`.
718-
"""
719-
function set_nonlincon!(
720-
mpc::NonLinMPC, ::SimModel, optim::JuMP.GenericModel{JNT}
721-
) where JNT<:Real
722-
Z̃var = optim[:Z̃var]
723-
con = mpc.con
724-
nonlin_constraints = JuMP.all_constraints(optim, JuMP.NonlinearExpr, MOI.LessThan{JNT})
725-
map(con_ref -> JuMP.delete(optim, con_ref), nonlin_constraints)
726-
for i in findall(.!isinf.(con.Y0min))
727-
gfunc_i = optim[Symbol("g_Y0min_$(i)")]
728-
@constraint(optim, gfunc_i(Z̃var...) <= 0)
729-
end
730-
for i in findall(.!isinf.(con.Y0max))
731-
gfunc_i = optim[Symbol("g_Y0max_$(i)")]
732-
@constraint(optim, gfunc_i(Z̃var...) <= 0)
733-
end
734-
for i in findall(.!isinf.(con.x̂0min))
735-
gfunc_i = optim[Symbol("g_x̂0min_$(i)")]
736-
@constraint(optim, gfunc_i(Z̃var...) <= 0)
737-
end
738-
for i in findall(.!isinf.(con.x̂0max))
739-
gfunc_i = optim[Symbol("g_x̂0max_$(i)")]
740-
@constraint(optim, gfunc_i(Z̃var...) <= 0)
741-
end
742-
for i in 1:con.nc
743-
gfunc_i = optim[Symbol("g_c_$i")]
744-
@constraint(optim, gfunc_i(Z̃var...) <= 0)
745-
end
746-
return nothing
747-
end
748-
749695
"""
750696
con_nonlinprog!(g, mpc::NonLinMPC, model::LinModel, _ , _ , gc, ϵ) -> g
751697

src/controller/transcription.jl

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,95 @@ function init_nonlincon!(
650650
return nothing
651651
end
652652

653+
654+
"By default, there is no nonlinear constraint, thus do nothing."
655+
function set_nonlincon!(
656+
::PredictiveController, ::SimModel, ::JuMP.GenericModel, ::TranscriptionMethod
657+
)
658+
return nothing
659+
end
660+
661+
"""
662+
set_nonlincon!(mpc::NonLinMPC, ::LinModel, ::TranscriptionMethod, optim)
663+
664+
Set the custom nonlinear inequality constraints for `LinModel`.
665+
"""
666+
function set_nonlincon!(
667+
mpc::NonLinMPC, ::LinModel, ::TranscriptionMethod, optim::JuMP.GenericModel{JNT}
668+
) where JNT<:Real
669+
Z̃var = optim[:Z̃var]
670+
con = mpc.con
671+
nonlin_constraints = JuMP.all_constraints(optim, JuMP.NonlinearExpr, MOI.LessThan{JNT})
672+
map(con_ref -> JuMP.delete(optim, con_ref), nonlin_constraints)
673+
for i in 1:con.nc
674+
gfunc_i = optim[Symbol("g_c_$i")]
675+
@constraint(optim, gfunc_i(Z̃var...) <= 0)
676+
end
677+
return nothing
678+
end
679+
680+
"""
681+
set_nonlincon!(mpc::NonLinMPC, ::NonLinModel, ::MultipleShooting, optim)
682+
683+
Also set output prediction `Ŷ` constraints for `NonLinModel` and `MultipleShooting`.
684+
"""
685+
function set_nonlincon!(
686+
mpc::NonLinMPC, ::SimModel, ::MultipleShooting, optim::JuMP.GenericModel{JNT}
687+
) where JNT<:Real
688+
Z̃var = optim[:Z̃var]
689+
con = mpc.con
690+
nonlin_constraints = JuMP.all_constraints(optim, JuMP.NonlinearExpr, MOI.LessThan{JNT})
691+
map(con_ref -> JuMP.delete(optim, con_ref), nonlin_constraints)
692+
for i in findall(.!isinf.(con.Y0min))
693+
gfunc_i = optim[Symbol("g_Y0min_$(i)")]
694+
@constraint(optim, gfunc_i(Z̃var...) <= 0)
695+
end
696+
for i in findall(.!isinf.(con.Y0max))
697+
gfunc_i = optim[Symbol("g_Y0max_$(i)")]
698+
@constraint(optim, gfunc_i(Z̃var...) <= 0)
699+
end
700+
for i in 1:con.nc
701+
gfunc_i = optim[Symbol("g_c_$i")]
702+
@constraint(optim, gfunc_i(Z̃var...) <= 0)
703+
end
704+
return nothing
705+
end
706+
707+
"""
708+
set_nonlincon!(mpc::NonLinMPC, ::NonLinModel, ::SingleShooting, optim)
709+
710+
Also set output prediction `Ŷ` and terminal state `x̂end` constraint for `SingleShooting`.
711+
"""
712+
function set_nonlincon!(
713+
mpc::NonLinMPC, ::NonLinModel, ::SingleShooting, optim::JuMP.GenericModel{JNT}
714+
) where JNT<:Real
715+
Z̃var = optim[:Z̃var]
716+
con = mpc.con
717+
nonlin_constraints = JuMP.all_constraints(optim, JuMP.NonlinearExpr, MOI.LessThan{JNT})
718+
map(con_ref -> JuMP.delete(optim, con_ref), nonlin_constraints)
719+
for i in findall(.!isinf.(con.Y0min))
720+
gfunc_i = optim[Symbol("g_Y0min_$(i)")]
721+
@constraint(optim, gfunc_i(Z̃var...) <= 0)
722+
end
723+
for i in findall(.!isinf.(con.Y0max))
724+
gfunc_i = optim[Symbol("g_Y0max_$(i)")]
725+
@constraint(optim, gfunc_i(Z̃var...) <= 0)
726+
end
727+
for i in findall(.!isinf.(con.x̂0min))
728+
gfunc_i = optim[Symbol("g_x̂0min_$(i)")]
729+
@constraint(optim, gfunc_i(Z̃var...) <= 0)
730+
end
731+
for i in findall(.!isinf.(con.x̂0max))
732+
gfunc_i = optim[Symbol("g_x̂0max_$(i)")]
733+
@constraint(optim, gfunc_i(Z̃var...) <= 0)
734+
end
735+
for i in 1:con.nc
736+
gfunc_i = optim[Symbol("g_c_$i")]
737+
@constraint(optim, gfunc_i(Z̃var...) <= 0)
738+
end
739+
return nothing
740+
end
741+
653742
@doc raw"""
654743
linconstrainteq!(
655744
mpc::PredictiveController, model::LinModel, transcription::MultipleShooting

test/3_test_predictive_control.jl

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -794,7 +794,17 @@ end
794794
setconstraint!(nmpc_lin, ymin=[5,10],ymax=[55, 35])
795795
@test all((nmpc_lin.con.Y0min, nmpc_lin.con.Y0max) .≈ ([5,10], [55,35]))
796796
setconstraint!(nmpc_lin, c_ymin=[1.0,1.1], c_ymax=[1.2,1.3])
797-
@test all((-nmpc_lin.con.A_Ymin[:, end], -nmpc_lin.con.A_Ymax[:, end]) .≈ ([1.0,1.1], [1.2,1.3]))
797+
@test all((-nmpc_lin.con.A_Ymin[:, end], -nmpc_lin.con.A_Ymax[:, end]) .≈
798+
([1.0,1.1], [1.2,1.3]))
799+
setconstraint!(nmpc_lin, x̂min=[-21,-22,-23,-24,-25,-26], x̂max=[21,22,23,24,25,26])
800+
@test all((nmpc_lin.con.x̂0min, nmpc_lin.con.x̂0max) .≈
801+
([-21,-22,-23,-24,-25,-26], [21,22,23,24,25,26]))
802+
setconstraint!(nmpc_lin,
803+
c_x̂min=[0.21,0.22,0.23,0.24,0.25,0.26],
804+
c_x̂max=[0.31,0.32,0.33,0.34,0.35,0.36]
805+
)
806+
@test all((-nmpc_lin.con.A_x̂min[:, end], -nmpc_lin.con.A_x̂max[:, end]) .≈
807+
([0.21,0.22,0.23,0.24,0.25,0.26], [0.31,0.32,0.33,0.34,0.35,0.36]))
798808

799809
f = (x,u,d,_) -> linmodel1.A*x + linmodel1.Bu*u + linmodel1.Bd*d
800810
h = (x,d,_) -> linmodel1.C*x + linmodel1.Dd*d
@@ -808,17 +818,44 @@ end
808818
setconstraint!(nmpc, ymin=[-6, -11],ymax=[55, 35])
809819
@test all((nmpc.con.Y0min, nmpc.con.Y0max) .≈ ([-6,-11], [55,35]))
810820
setconstraint!(nmpc, x̂min=[-21,-22,-23,-24,-25,-26], x̂max=[21,22,23,24,25,26])
811-
@test all((nmpc.con.x̂0min, nmpc.con.x̂0max) .≈ ([-21,-22,-23,-24,-25,-26], [21,22,23,24,25,26]))
821+
@test all((nmpc.con.x̂0min, nmpc.con.x̂0max) .≈
822+
([-21,-22,-23,-24,-25,-26], [21,22,23,24,25,26]))
812823

813824
setconstraint!(nmpc, c_umin=[0.01,0.02], c_umax=[0.03,0.04])
814-
@test all((-nmpc.con.A_Umin[:, end], -nmpc.con.A_Umax[:, end]) .≈ ([0.01,0.02], [0.03,0.04]))
825+
@test all((-nmpc.con.A_Umin[:, end], -nmpc.con.A_Umax[:, end]) .≈
826+
([0.01,0.02], [0.03,0.04]))
815827
setconstraint!(nmpc, c_Δumin=[0.05,0.06], c_Δumax=[0.07,0.08])
816-
@test all((-nmpc.con.A_ΔŨmin[1:end-1, end], -nmpc.con.A_ΔŨmax[1:end-1, end]) .≈ ([0.05,0.06], [0.07,0.08]))
828+
@test all((-nmpc.con.A_ΔŨmin[1:end-1, end], -nmpc.con.A_ΔŨmax[1:end-1, end]) .≈
829+
([0.05,0.06], [0.07,0.08]))
817830
setconstraint!(nmpc, c_ymin=[1.00,1.01], c_ymax=[1.02,1.03])
818831
@test all((-nmpc.con.A_Ymin, -nmpc.con.A_Ymax) .≈ (zeros(0,3), zeros(0,3)))
819832
@test all((nmpc.con.C_ymin, nmpc.con.C_ymax) .≈ ([1.00,1.01], [1.02,1.03]))
820-
setconstraint!(nmpc, c_x̂min=[0.21,0.22,0.23,0.24,0.25,0.26], c_x̂max=[0.31,0.32,0.33,0.34,0.35,0.36])
821-
@test all((nmpc.con.c_x̂min, nmpc.con.c_x̂max) .≈ ([0.21,0.22,0.23,0.24,0.25,0.26], [0.31,0.32,0.33,0.34,0.35,0.36]))
833+
setconstraint!(nmpc,
834+
c_x̂min=[0.21,0.22,0.23,0.24,0.25,0.26],
835+
c_x̂max=[0.31,0.32,0.33,0.34,0.35,0.36]
836+
)
837+
@test all((nmpc.con.c_x̂min, nmpc.con.c_x̂max) .≈
838+
([0.21,0.22,0.23,0.24,0.25,0.26], [0.31,0.32,0.33,0.34,0.35,0.36]))
839+
840+
nmpc_ms = NonLinMPC(nonlinmodel, Hp=1, Hc=1, transcription=MultipleShooting())
841+
842+
setconstraint!(nmpc_ms, ymin=[-6, -11],ymax=[55, 35])
843+
@test all((nmpc_ms.con.Y0min, nmpc_ms.con.Y0max) .≈ ([-6,-11], [55,35]))
844+
setconstraint!(nmpc_ms, x̂min=[-21,-22,-23,-24,-25,-26], x̂max=[21,22,23,24,25,26])
845+
@test all((nmpc_ms.con.x̂0min, nmpc_ms.con.x̂0max) .≈
846+
([-21,-22,-23,-24,-25,-26], [21,22,23,24,25,26]))
847+
848+
setconstraint!(nmpc_ms, c_ymin=[1.00,1.01], c_ymax=[1.02,1.03])
849+
@test all((-nmpc_ms.con.A_Ymin, -nmpc_ms.con.A_Ymax) .≈ (zeros(0,9), zeros(0,9)))
850+
@test all((nmpc_ms.con.C_ymin, nmpc_ms.con.C_ymax) .≈ ([1.00,1.01], [1.02,1.03]))
851+
setconstraint!(nmpc_ms,
852+
c_x̂min=[0.21,0.22,0.23,0.24,0.25,0.26],
853+
c_x̂max=[0.31,0.32,0.33,0.34,0.35,0.36]
854+
)
855+
@test all((-nmpc_lin.con.A_x̂min[:, end], -nmpc_lin.con.A_x̂max[:, end]) .≈
856+
([0.21,0.22,0.23,0.24,0.25,0.26], [0.31,0.32,0.33,0.34,0.35,0.36]))
857+
@test all((nmpc_ms.con.c_x̂min, nmpc_ms.con.c_x̂max) .≈
858+
([0.21,0.22,0.23,0.24,0.25,0.26], [0.31,0.32,0.33,0.34,0.35,0.36]))
822859

823860
end
824861

0 commit comments

Comments
 (0)