Skip to content

Commit 9333844

Browse files
authored
Merge pull request #267 from JuliaControl/VectorNonLinOracle_trunk
changed: differentiating only the non-`Inf` constraints in `NonLinMPC`
2 parents 5389a4a + d244194 commit 9333844

File tree

1 file changed

+47
-53
lines changed

1 file changed

+47
-53
lines changed

src/controller/nonlinmpc.jl

Lines changed: 47 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -729,73 +729,69 @@ function get_optim_functions(mpc::NonLinMPC, ::JuMP.GenericModel{JNT}) where JNT
729729
end
730730

731731
# TODO: move docstring of method above here an re-work it
732-
function get_nonlinops(mpc::NonLinMPC, optim::JuMP.GenericModel{JNT}) where JNT<:Real
732+
function get_nonlinops(mpc::NonLinMPC, ::JuMP.GenericModel{JNT}) where JNT<:Real
733733
# ----------- common cache for all functions ----------------------------------------
734734
model = mpc.estim.model
735735
transcription = mpc.transcription
736736
grad, jac = mpc.gradient, mpc.jacobian
737737
nu, ny, nx̂, nϵ = model.nu, model.ny, mpc.estim.nx̂, mpc.
738738
nk = get_nk(model, transcription)
739739
Hp, Hc = mpc.Hp, mpc.Hc
740-
ng, nc, neq = length(mpc.con.i_g), mpc.con.nc, mpc.con.neq
740+
i_g = findall(mpc.con.i_g) # convert to non-logical indices for non-allocating @views
741+
ng, ngi = length(mpc.con.i_g), sum(mpc.con.i_g)
742+
nc, neq = mpc.con.nc, mpc.con.neq
741743
nZ̃, nU, nŶ, nX̂, nK = length(mpc.Z̃), Hp*nu, Hp*ny, Hp*nx̂, Hp*nk
742744
nΔŨ, nUe, nŶe = nu*Hc + nϵ, nU + nu, nŶ + ny
743745
strict = Val(true)
744-
myNaN, myInf = convert(JNT, NaN), convert(JNT, Inf)
745-
J::Vector{JNT} = zeros(JNT, 1)
746-
ΔŨ::Vector{JNT} = zeros(JNT, nΔŨ)
747-
x̂0end::Vector{JNT} = zeros(JNT, nx̂)
748-
K0::Vector{JNT} = zeros(JNT, nK)
749-
Ue::Vector{JNT}, Ŷe::Vector{JNT} = zeros(JNT, nUe), zeros(JNT, nŶe)
750-
U0::Vector{JNT}, Ŷ0::Vector{JNT} = zeros(JNT, nU), zeros(JNT, nŶ)
751-
Û0::Vector{JNT}, X̂0::Vector{JNT} = zeros(JNT, nU), zeros(JNT, nX̂)
752-
gc::Vector{JNT}, g::Vector{JNT} = zeros(JNT, nc), zeros(JNT, ng)
753-
geq::Vector{JNT} = zeros(JNT, neq)
746+
myNaN, myInf = convert(JNT, NaN), convert(JNT, Inf)
747+
J::Vector{JNT} = zeros(JNT, 1)
748+
ΔŨ::Vector{JNT} = zeros(JNT, nΔŨ)
749+
x̂0end::Vector{JNT} = zeros(JNT, nx̂)
750+
K0::Vector{JNT} = zeros(JNT, nK)
751+
Ue::Vector{JNT}, Ŷe::Vector{JNT} = zeros(JNT, nUe), zeros(JNT, nŶe)
752+
U0::Vector{JNT}, Ŷ0::Vector{JNT} = zeros(JNT, nU), zeros(JNT, nŶ)
753+
Û0::Vector{JNT}, X̂0::Vector{JNT} = zeros(JNT, nU), zeros(JNT, nX̂)
754+
gc::Vector{JNT}, g::Vector{JNT} = zeros(JNT, nc), zeros(JNT, ng)
755+
gi::Vector{JNT}, geq::Vector{JNT} = zeros(JNT, ngi), zeros(JNT, neq)
754756
# -------------- inequality constraint: nonlinear oracle -----------------------------
755-
function g!(g, Z̃, ΔŨ, x̂0end, Ue, Ŷe, U0, Ŷ0, Û0, K0, X̂0, gc, geq)
757+
function gi!(gi, Z̃, ΔŨ, x̂0end, Ue, Ŷe, U0, Ŷ0, Û0, K0, X̂0, gc, geq, g)
756758
update_predictions!(ΔŨ, x̂0end, Ue, Ŷe, U0, Ŷ0, Û0, K0, X̂0, gc, g, geq, mpc, Z̃)
759+
gi .= @views g[i_g]
757760
return nothing
758761
end
759-
Z̃_∇g = fill(myNaN, nZ̃) # NaN to force update_predictions! at first call
760-
g_context = (
762+
Z̃_∇gi = fill(myNaN, nZ̃) # NaN to force update_predictions! at first call
763+
gi_context = (
761764
Cache(ΔŨ), Cache(x̂0end), Cache(Ue), Cache(Ŷe), Cache(U0), Cache(Ŷ0),
762765
Cache(Û0), Cache(K0), Cache(X̂0),
763-
Cache(gc), Cache(geq),
766+
Cache(gc), Cache(geq), Cache(g)
764767
)
765-
## temporarily enable all the inequality constraints for sparsity detection:
766-
# mpc.con.i_g[1:end-nc] .= true
767-
∇g_prep = prepare_jacobian(g!, g, jac, Z̃_∇g, ∇g_context...; strict)
768-
# mpc.con.i_g[1:end-nc] .= false
769-
∇g = init_diffmat(JNT, jac, ∇g_prep, nZ̃, ng)
770-
function update_con!(g, ∇g, Z̃_∇g, Z̃_arg)
771-
if isdifferent(Z̃_arg, Z̃_∇g)
772-
Z̃_∇g .= Z̃_arg
773-
value_and_jacobian!(g!, g, ∇g, ∇g_prep, jac, Z̃_∇g, ∇g_context...)
768+
∇gi_prep = prepare_jacobian(gi!, gi, jac, Z̃_∇gi, ∇gi_context...; strict)
769+
∇gi = init_diffmat(JNT, jac, ∇gi_prep, nZ̃, ngi)
770+
function update_con!(gi, ∇gi, Z̃_∇gi, Z̃_arg)
771+
if isdifferent(Z̃_arg, Z̃_∇gi)
772+
Z̃_∇gi .= Z̃_arg
773+
value_and_jacobian!(gi!, gi, ∇gi, ∇gi_prep, jac, Z̃_∇gi, ∇gi_context...)
774774
end
775775
return nothing
776776
end
777-
function gfunc_oracle!(g_arg, Z̃_arg)
778-
update_con!(g, ∇g, Z̃_∇g, Z̃_arg)
779-
g_arg .= @views g[mpc.con.i_g]
780-
return nothing
777+
function gi_func!(gi_vec, Z̃_arg)
778+
update_con!(gi, ∇gi, Z̃_∇gi, Z̃_arg)
779+
return gi_vec .= gi
781780
end
782-
∇g_i_g = ∇g[mpc.con.i_g, :]
783-
function ∇gfunc_oracle!(∇g_arg, Z̃_arg)
784-
update_con!(g, ∇g, Z̃_∇g, Z̃_arg)
785-
∇g_i_g .= @views ∇g[mpc.con.i_g, :]
786-
diffmat2vec!(∇g_arg, ∇g_i_g)
787-
return nothing
781+
function ∇gi_func!(∇gi_vec, Z̃_arg)
782+
update_con!(gi, ∇gi, Z̃_∇gi, Z̃_arg)
783+
return diffmat2vec!(∇gi_vec, ∇gi)
788784
end
789-
g_min = fill(-myInf, sum(mpc.con.i_g))
790-
g_max = zeros(JNT, sum(mpc.con.i_g))
791-
g_structure = init_diffstructure(∇g[mpc.con.i_g, :])
785+
gi_min = fill(-myInf, ngi)
786+
gi_max = zeros(JNT, ngi)
787+
gi_structure = init_diffstructure(∇gi)
792788
g_oracle = Ipopt._VectorNonlinearOracle(;
793789
dimension = nZ̃,
794-
l = g_min,
795-
u = g_max,
796-
eval_f = gfunc_oracle!,
797-
jacobian_structure =g_structure,
798-
eval_jacobian =gfunc_oracle!
790+
l = gi_min,
791+
u = gi_max,
792+
eval_f = gi_func!,
793+
jacobian_structure =gi_structure,
794+
eval_jacobian =gi_func!
799795
)
800796
# ------------- equality constraints : nonlinear oracle ------------------------------
801797
function geq!(geq, Z̃, ΔŨ, x̂0end, Ue, Ŷe, U0, Ŷ0, Û0, K0, X̂0, gc, g)
@@ -817,25 +813,23 @@ function get_nonlinops(mpc::NonLinMPC, optim::JuMP.GenericModel{JNT}) where JNT<
817813
end
818814
return nothing
819815
end
820-
function geq_oracle!(geq_arg, Z̃_arg)
816+
function geq_func!(geq_vec, Z̃_arg)
821817
update_con_eq!(geq, ∇geq, Z̃_∇geq, Z̃_arg)
822-
geq_arg .= geq
823-
return nothing
818+
return geq_vec .= geq
824819
end
825-
function geq_oracle!(∇geq_arg, Z̃_arg)
820+
function geq_func!(∇geq_vec, Z̃_arg)
826821
update_con_eq!(geq, ∇geq, Z̃_∇geq, Z̃_arg)
827-
diffmat2vec!(∇geq_arg, ∇geq)
828-
return nothing
822+
return diffmat2vec!(∇geq_vec, ∇geq)
829823
end
830824
geq_min = geq_max = zeros(JNT, neq)
831825
∇geq_structure = init_diffstructure(∇geq)
832826
geq_oracle = Ipopt._VectorNonlinearOracle(;
833827
dimension = nZ̃,
834828
l = geq_min,
835829
u = geq_max,
836-
eval_f = geq_oracle!,
830+
eval_f = geq_func!,
837831
jacobian_structure = ∇geq_structure,
838-
eval_jacobian =geq_oracle!
832+
eval_jacobian =geq_func!
839833
)
840834
# ------------- objective function: splatting syntax ---------------------------------
841835
function J!(Z̃, ΔŨ, x̂0end, Ue, Ŷe, U0, Ŷ0, Û0, K0, X̂0, gc, g, geq)
@@ -909,8 +903,8 @@ function set_nonlincon_exp!(
909903
optim, JuMP.Vector{JuMP.VariableRef}, Ipopt._VectorNonlinearOracle
910904
)
911905
map(con_ref -> JuMP.delete(optim, con_ref), nonlin_constraints)
912-
@constraint(optim, Z̃var in g_oracle)
913-
mpc.con.neq > 0 && @constraint(optim, Z̃var in geq_oracle)
906+
any(mpc.con.i_g) && @constraint(optim, Z̃var in g_oracle)
907+
mpc.con.neq > 0 && @constraint(optim, Z̃var in geq_oracle)
914908
return nothing
915909
end
916910

0 commit comments

Comments
 (0)