Skip to content

Commit 38531a8

Browse files
committed
added: similar refactoring for nonlinear equality constraints
1 parent 9f4c357 commit 38531a8

File tree

1 file changed

+51
-74
lines changed

1 file changed

+51
-74
lines changed

src/controller/nonlinmpc.jl

Lines changed: 51 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -508,7 +508,7 @@ function init_optimization!(mpc::NonLinMPC, model::SimModel, optim)
508508
Jfunc, ∇Jfunc!, gfuncs, geqfuncs, ∇geqfuncs! = get_optim_functions(mpc, optim)
509509
@operator(optim, J, nZ̃, Jfunc, ∇Jfunc!)
510510
@objective(optim, Min, J(Z̃var...))
511-
init_nonlincon!(mpc, model, transcription, gfuncs, geqfuncs)
511+
init_nonlincon!(mpc, model, transcription, gfuncs, geqfuncs, ∇geqfuncs!)
512512
set_nonlincon!(mpc, model, optim)
513513
return nothing
514514
end
@@ -541,6 +541,7 @@ function get_optim_functions(mpc::NonLinMPC, ::JuMP.GenericModel{JNT}) where JNT
541541
gc_cache::DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache(zeros(JNT, nc), Ncache)
542542
g_cache::DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache(zeros(JNT, ng), Ncache)
543543
geq_cache::DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache(zeros(JNT, neq), Ncache)
544+
# --------------------- update simulation function ------------------------------------
544545
function update_simulations!(
545546
Z̃arg::Union{NTuple{N, T}, AbstractVector{T}}, Z̃cache
546547
) where {N, T<:Real}
@@ -568,81 +569,30 @@ function get_optim_functions(mpc::NonLinMPC, ::JuMP.GenericModel{JNT}) where JNT
568569
end
569570
return nothing
570571
end
571-
# force specialization using Vararg, see https://docs.julialang.org/en/v1/manual/performance-tips/#Be-aware-of-when-Julia-avoids-specializing
572-
function Jfunc(Z̃arg::Vararg{T, N}) where {N, T<:Real}
573-
return Jfunc(Z̃arg, get_tmp(Z̃_cache, T))::T
574-
end
575-
# method with the additional cache argument:
576-
function Jfunc(Z̃arg::Union{NTuple{N, T}, AbstractVector{T}}, Z̃cache) where {N, T<:Real}
577-
update_simulations!(Z̃arg, Z̃cache)
572+
# --------------------- objective function --------------------------------------------
573+
function Jfunc(Z̃arg::Vararg{T, N}) where {N, T<:Real} # force specialization with Vararg, see https://docs.julialang.org/en/v1/manual/performance-tips/#Be-aware-of-when-Julia-avoids-specializing
574+
update_simulations!(Z̃arg, get_tmp(Z̃_cache, T))
578575
ΔŨ = get_tmp(ΔŨ_cache, T)
579576
Ue, Ŷe = get_tmp(Ue_cache, T), get_tmp(Ŷe_cache, T)
580577
U0, Ŷ0 = get_tmp(U0_cache, T), get_tmp(Ŷ0_cache, T)
581-
return obj_nonlinprog!(Ŷ0, U0, mpc, model, Ue, Ŷe, ΔŨ)
578+
return obj_nonlinprog!(Ŷ0, U0, mpc, model, Ue, Ŷe, ΔŨ)::T
582579
end
583-
Jfunc_vec(Z̃vec) = Jfunc(Z̃vec, get_tmp(Z̃_cache, Z̃vec[1]))
580+
function Jfunc_vec(Z̃arg::AbstractVector{T}) where T<:Real
581+
update_simulations!(Z̃arg, get_tmp(Z̃_cache, T))
582+
ΔŨ = get_tmp(ΔŨ_cache, T)
583+
Ue, Ŷe = get_tmp(Ue_cache, T), get_tmp(Ŷe_cache, T)
584+
U0, Ŷ0 = get_tmp(U0_cache, T), get_tmp(Ŷ0_cache, T)
585+
return obj_nonlinprog!(Ŷ0, U0, mpc, model, Ue, Ŷe, ΔŨ)::T
586+
end
584587
Z̃vec = Vector{JNT}(undef, nZ̃)
585588
∇Jbuffer = GradientBuffer(Jfunc_vec, Z̃vec)
586589
function ∇Jfunc!(∇J, Z̃arg::Vararg{T, N}) where {N, T<:Real}
587590
Z̃vec .= Z̃arg
588-
gradient!(∇J, ∇Jbuffer, Z̃vec)
589-
return nothing
590-
end
591-
592-
593-
function gfunceq_i(i, Z̃arg::NTuple{N, T}) where {N, T<:Real}
594-
update_simulations!(Z̃arg, get_tmp(Z̃_cache, T))
595-
geq = get_tmp(geq_cache, T)
596-
return geq[i]::T
597-
end
598-
geqfuncs = Vector{Function}(undef, neq)
599-
for i in 1:neq
600-
geqfuncs[i] = function (Z̃arg::Vararg{T, N}) where {N, T<:Real}
601-
return gfunceq_i(i, Z̃arg)
602-
end
603-
end
604-
605-
606-
∇geqfuncs! = nothing
607-
#=
608-
function geqfunc!(geq, Z̃)
609-
update_simulations!(Z̃, get_tmp(Z̃_cache, T))
610-
geq = get_tmp(geq_cache, T)
611-
return
612-
end
613-
=#
614-
615-
#=
616-
617-
618-
619-
∇geq = Matrix{JNT}(undef, neq, nZ̃) # Jacobian of geq
620-
function ∇geqfunc_vec!(∇geq, Z̃vec)
621-
update_simulations!(Z̃arg, get_tmp(Z̃_cache, T))
622-
return nothing
623-
end
624-
625-
626-
627-
628-
629-
function ∇geqfuncs_i!(∇geq_i, i, Z̃arg::NTuple{N, T}) where {N, T<:Real}
630-
Z̃arg_vec .= Z̃arg
631-
ForwardDiff
632-
633-
591+
return gradient!(∇J, ∇Jbuffer, Z̃vec)
634592
end
635-
636-
∇geqfuncs! = Vector{Function}(undef, neq)
637-
for i in 1:neq
638-
∇eqfuncs![i] = function (∇geq, Z̃arg::Vararg{T, N}) where {N, T<:Real}
639-
return ∇geqfuncs_i!(∇geq, i, Z̃arg)
640-
end
641-
end
642-
=#
643-
644-
593+
# --------------------- inequality constraint functions -------------------------------
645594
# TODO:re-déplacer en haut:
595+
# TODO: modifier pour combiner en 1 seule fonction comme pour geqfuncs
646596
function gfunc_i(i, Z̃arg::NTuple{N, T}) where {N, T<:Real}
647597
update_simulations!(Z̃arg, get_tmp(Z̃_cache, T))
648598
g = get_tmp(g_cache, T)
@@ -655,12 +605,38 @@ function get_optim_functions(mpc::NonLinMPC, ::JuMP.GenericModel{JNT}) where JNT
655605
return gfunc_i(i, Z̃arg)
656606
end
657607
end
608+
# --------------------- equality constraint functions ---------------------------------
609+
geqfuncs = Vector{Function}(undef, neq)
610+
for i in eachindex(geqfuncs)
611+
func_i = function (Z̃arg::Vararg{T, N}) where {N, T<:Real} # see comment above
612+
update_simulations!(Z̃arg, get_tmp(Z̃_cache, T))
613+
geq = get_tmp(geq_cache, T)
614+
return geq[i]::T
615+
end
616+
geqfuncs[i] = func_i
617+
end
618+
function geqfunc_vec!(geq, Z̃vec::AbstractVector{T}) where T<:Real
619+
update_simulations!(Z̃vec, get_tmp(Z̃_cache, T))
620+
geq .= get_tmp(geq_cache, T)
621+
return geq
622+
end
623+
∇geq = Matrix{JNT}(undef, neq, nZ̃) # Jacobian of geq
624+
geqvec = Vector{JNT}(undef, neq)
625+
∇geqfuncs! = Vector{Function}(undef, neq)
626+
for i in eachindex(∇geqfuncs!)
627+
∇geqfuncs![i] = function (∇geq_i, Z̃arg::Vararg{T, N}) where {N, T<:Real}
628+
Z̃vec .= Z̃arg
629+
ForwardDiff.jacobian!(∇geq, geqfunc_vec!, geqvec, Z̃vec)
630+
∇geq_i .= @views ∇geq[i, :]
631+
return ∇geq_i
632+
end
633+
end
658634
return Jfunc, ∇Jfunc!, gfuncs, geqfuncs, ∇geqfuncs!
659635
end
660636

661637
"""
662638
init_nonlincon!(
663-
mpc::NonLinMPC, model::LinModel, ::TranscriptionMethod, gfuncs, geqfuncs
639+
mpc::NonLinMPC, model::LinModel, ::TranscriptionMethod, gfuncs, geqfuncs, ∇geqfuncs!
664640
)
665641
666642
Init nonlinear constraints for [`LinModel`](@ref).
@@ -669,7 +645,7 @@ The only nonlinear constraints are the custom inequality constraints `gc`.
669645
"""
670646
function init_nonlincon!(
671647
mpc::NonLinMPC, ::LinModel, ::TranscriptionMethod,
672-
gfuncs::Vector{<:Function}, geqfuncs::Vector{<:Function}
648+
gfuncs::Vector{<:Function}, _ , _
673649
)
674650
optim, con = mpc.optim, mpc.con
675651
nZ̃ = length(mpc.Z̃)
@@ -685,7 +661,7 @@ end
685661

686662
"""
687663
init_nonlincon!(
688-
mpc::NonLinMPC, model::NonLinModel, ::MultipleShooting, gfuncs, geqfuncs
664+
mpc::NonLinMPC, model::NonLinModel, ::MultipleShooting, gfuncs, geqfuncs, ∇geqfuncs!
689665
)
690666
691667
Init nonlinear constraints for [`NonLinModel`](@ref) and [`MultipleShooting`](@ref).
@@ -695,7 +671,7 @@ constraints `gc` and all the nonlinear equality constraints `geq`.
695671
"""
696672
function init_nonlincon!(
697673
mpc::NonLinMPC, ::NonLinModel, ::MultipleShooting,
698-
gfuncs::Vector{<:Function}, geqfuncs::Vector{<:Function}
674+
gfuncs::Vector{<:Function}, geqfuncs::Vector{<:Function}, ∇geqfuncs!::Vector{<:Function}
699675
)
700676
optim, con = mpc.optim, mpc.con
701677
ny, nx̂, Hp, nZ̃ = mpc.estim.model.ny, mpc.estim.nx̂, mpc.Hp, length(mpc.Z̃)
@@ -719,9 +695,10 @@ function init_nonlincon!(
719695
end
720696
# --- nonlinear equality constraints ---
721697
Z̃var = optim[:Z̃var]
722-
for i in 1:con.neq
698+
for i in eachindex(geqfuncs)
723699
name = Symbol("geq_$i")
724-
geqfunc_i = optim[name] = JuMP.add_nonlinear_operator(optim, nZ̃, geqfuncs[i]; name)
700+
geqfunc_i = JuMP.add_nonlinear_operator(optim, nZ̃, geqfuncs[i], ∇geqfuncs![i]; name)
701+
optim[name] = geqfunc_i
725702
# set with @constrains here instead of set_nonlincon!, since the number of nonlinear
726703
# equality constraints is known and constant (±Inf are impossible):
727704
@constraint(optim, geqfunc_i(Z̃var...) == 0)
@@ -731,7 +708,7 @@ end
731708

732709
"""
733710
init_nonlincon!(
734-
mpc::NonLinMPC, model::NonLinModel, ::SingleShooting, gfuncs, geqfuncs
711+
mpc::NonLinMPC, model::NonLinModel, ::SingleShooting, gfuncs, geqfuncs, ∇geqfuncs!
735712
)
736713
737714
Init nonlinear constraints for [`NonLinModel`](@ref) and [`SingleShooting`](@ref).
@@ -741,7 +718,7 @@ prediction `Ŷ` bounds and the terminal state `x̂end` bounds.
741718
"""
742719
function init_nonlincon!(
743720
mpc::NonLinMPC, ::NonLinModel, ::SingleShooting,
744-
gfuncs::Vector{<:Function}, geqfuncs::Vector{<:Function}
721+
gfuncs::Vector{<:Function}, _ , _
745722
)
746723
optim, con = mpc.optim, mpc.con
747724
ny, nx̂, Hp, nZ̃ = mpc.estim.model.ny, mpc.estim.nx̂, mpc.Hp, length(mpc.Z̃)

0 commit comments

Comments
 (0)