526526"""
527527 addinfo!(info, mpc::NonLinMPC) -> info
528528
529- For [`NonLinMPC`](@ref), add `:sol` and the optimal economic cost `:JE`.
529+ For [`NonLinMPC`](@ref), add `:sol`, the custom nonlinear objective `:JE`, the custom
530+ constraint `:gc`, and the various derivatives.
530531"""
531532function addinfo! (info, mpc:: NonLinMPC{NT} ) where NT<: Real
533+ # --- variables specific to NonLinMPC ---
532534 U, Ŷ, D̂, ŷ, d, ϵ = info[:U ], info[:Ŷ ], info[:D̂ ], info[:ŷ ], info[:d ], info[:ϵ ]
533535 Ue = [U; U[(end - mpc. estim. model. nu + 1 ): end ]]
534536 Ŷe = [ŷ; Ŷ]
@@ -539,6 +541,118 @@ function addinfo!(info, mpc::NonLinMPC{NT}) where NT<:Real
539541 info[:JE ] = JE
540542 info[:gc ] = LHS
541543 info[:sol ] = JuMP. solution_summary (mpc. optim, verbose= true )
544+ # --- objective derivatives ---
545+ model, optim, con = mpc. estim. model, mpc. optim, mpc. con
546+ transcription = mpc. transcription
547+ nu, ny, nx̂, nϵ = model. nu, model. ny, mpc. estim. nx̂, mpc. nϵ
548+ nk = get_nk (model, transcription)
549+ Hp, Hc = mpc. Hp, mpc. Hc
550+ ng = length (con. i_g)
551+ nc, neq = con. nc, con. neq
552+ nU, nŶ, nX̂, nK = mpc. Hp* nu, Hp* ny, Hp* nx̂, Hp* nk
553+ nΔŨ, nUe, nŶe = nu* Hc + nϵ, nU + nu, nŶ + ny
554+ ΔŨ = zeros (NT, nΔŨ)
555+ x̂0end = zeros (NT, nx̂)
556+ K0 = zeros (NT, nK)
557+ Ue, Ŷe = zeros (NT, nUe), zeros (NT, nŶe)
558+ U0, Ŷ0 = zeros (NT, nU), zeros (NT, nŶ)
559+ Û0, X̂0 = zeros (NT, nU), zeros (NT, nX̂)
560+ gc, g = zeros (NT, nc), zeros (NT, ng)
561+ geq = zeros (NT, neq)
562+ J_cache = (
563+ Cache (ΔŨ), Cache (x̂0end), Cache (Ue), Cache (Ŷe), Cache (U0), Cache (Ŷ0),
564+ Cache (Û0), Cache (K0), Cache (X̂0),
565+ Cache (gc), Cache (g), Cache (geq),
566+ )
567+ function J! (Z̃, ΔŨ, x̂0end, Ue, Ŷe, U0, Ŷ0, Û0, K0, X̂0, gc, g, geq)
568+ update_predictions! (ΔŨ, x̂0end, Ue, Ŷe, U0, Ŷ0, Û0, K0, X̂0, gc, g, geq, mpc, Z̃)
569+ return obj_nonlinprog! (Ŷ0, U0, mpc, model, Ue, Ŷe, ΔŨ)
570+ end
571+ if ! isnothing (mpc. hessian)
572+ _, ∇J, ∇²J = value_gradient_and_hessian (J!, mpc. hessian, mpc. Z̃, J_cache... )
573+ else
574+ ∇J, ∇²J = gradient (J!, mpc. gradient, mpc. Z̃, J_cache... ), nothing
575+ end
576+ # --- inequality constraint derivatives ---
577+ old_i_g = copy (con. i_g)
578+ con. i_g .= 1 # temporarily set all constraints as finite so g is entirely computed
579+ ∇g_cache = (
580+ Cache (ΔŨ), Cache (x̂0end), Cache (Ue), Cache (Ŷe), Cache (U0), Cache (Ŷ0),
581+ Cache (Û0), Cache (K0), Cache (X̂0),
582+ Cache (gc), Cache (geq),
583+ )
584+ function g! (g, Z̃, ΔŨ, x̂0end, Ue, Ŷe, U0, Ŷ0, Û0, K0, X̂0, gc, geq)
585+ update_predictions! (ΔŨ, x̂0end, Ue, Ŷe, U0, Ŷ0, Û0, K0, X̂0, gc, g, geq, mpc, Z̃)
586+ return nothing
587+ end
588+ ∇g = jacobian (g!, g, mpc. jacobian, mpc. Z̃, ∇g_cache... )
589+ if ! isnothing (mpc. hessian) && any (old_i_g)
590+ @warn (
591+ " Retrieving optimal Hessian of the Lagrangian is not fully supported yet.\n " *
592+ " Its nonzero coefficients are random values for now." , maxlog= 1
593+ )
594+ function ℓ_g (Z̃, λ, ΔŨ, x̂0end, Ue, Ŷe, U0, Ŷ0, Û0, K0, X̂0, gc, geq, g)
595+ update_predictions! (ΔŨ, x̂0end, Ue, Ŷe, U0, Ŷ0, Û0, K0, X̂0, gc, g, geq, mpc, Z̃)
596+ return dot (λ, g)
597+ end
598+ ∇²g_cache = (
599+ Cache (ΔŨ), Cache (x̂0end), Cache (Ue), Cache (Ŷe), Cache (U0), Cache (Ŷ0),
600+ Cache (Û0), Cache (K0), Cache (X̂0),
601+ Cache (gc), Cache (geq), Cache (g)
602+ )
603+ nonlincon = optim[:nonlinconstraint ]
604+ λ = JuMP. dual .(nonlincon) # FIXME : does not work for now
605+ λ = rand (NT, ng)
606+ ∇²ℓg = hessian (ℓ_g, mpc. hessian, mpc. Z̃, Constant (λ), ∇²g_cache... )
607+ else
608+ ∇²ℓg = nothing
609+ end
610+ con. i_g .= old_i_g # restore original finite/infinite constraint indices
611+ # --- equality constraint derivatives ---
612+ geq_cache = (
613+ Cache (ΔŨ), Cache (x̂0end), Cache (Ue), Cache (Ŷe), Cache (U0), Cache (Ŷ0),
614+ Cache (Û0), Cache (K0), Cache (X̂0),
615+ Cache (gc), Cache (g)
616+ )
617+ function geq! (geq, Z̃, ΔŨ, x̂0end, Ue, Ŷe, U0, Ŷ0, Û0, K0, X̂0, gc, g)
618+ update_predictions! (ΔŨ, x̂0end, Ue, Ŷe, U0, Ŷ0, Û0, K0, X̂0, gc, g, geq, mpc, Z̃)
619+ return nothing
620+ end
621+ ∇geq = jacobian (geq!, geq, mpc. jacobian, mpc. Z̃, geq_cache... )
622+ if ! isnothing (mpc. hessian) && con. neq > 0
623+ @warn (
624+ " Retrieving optimal Hessian of the Lagrangian is not fully supported yet.\n " *
625+ " Its nonzero coefficients are random values for now." , maxlog= 1
626+ )
627+ ∇²geq_cache = (
628+ Cache (ΔŨ), Cache (x̂0end), Cache (Ue), Cache (Ŷe), Cache (U0), Cache (Ŷ0),
629+ Cache (Û0), Cache (K0), Cache (X̂0),
630+ Cache (gc), Cache (geq), Cache (g)
631+ )
632+ function ℓ_geq (Z̃, λeq, ΔŨ, x̂0end, Ue, Ŷe, U0, Ŷ0, Û0, K0, X̂0, gc, geq, g)
633+ update_predictions! (ΔŨ, x̂0end, Ue, Ŷe, U0, Ŷ0, Û0, K0, X̂0, gc, g, geq, mpc, Z̃)
634+ return dot (λeq, geq)
635+ end
636+ nonlinconeq = optim[:nonlinconstrainteq ]
637+ λeq = JuMP. dual .(nonlinconeq) # FIXME : does not work for now
638+ λeq = ones (NT, neq)
639+ ∇²ℓgeq = hessian (ℓ_geq, mpc. hessian, mpc. Z̃, Constant (λeq), ∇²geq_cache... )
640+ else
641+ ∇²ℓgeq = nothing
642+ end
643+ info[:∇J ] = ∇J
644+ info[:∇²J ] = ∇²J
645+ info[:∇g ] = ∇g
646+ info[:∇²ℓg ] = ∇²ℓg
647+ info[:∇geq ] = ∇geq
648+ info[:∇²ℓgeq ] = ∇²ℓgeq
649+ # --- non-Unicode fields ---
650+ info[:nablaJ ] = ∇J
651+ info[:nabla2J ] = ∇²J
652+ info[:nablag ] = ∇g
653+ info[:nabla2lg ] = ∇²ℓg
654+ info[:nablageq ] = ∇geq
655+ info[:nabla2lgeq ] = ∇²ℓgeq
542656 return info
543657end
544658
@@ -942,10 +1056,10 @@ function set_nonlincon!(
9421056 optim, JuMP. Vector{JuMP. VariableRef}, MOI. VectorNonlinearOracle{JNT}
9431057 )
9441058 map (con_ref -> JuMP. delete (optim, con_ref), nonlin_constraints)
945- optim[ :g_oracle ] = g_oracle
946- optim[ :geq_oracle ] = geq_oracle
947- any (mpc. con. i_g) && @constraint (optim, Z̃var in g_oracle)
948- mpc. con. neq > 0 && @constraint (optim, Z̃var in geq_oracle)
1059+ JuMP . unregister ( optim, :nonlinconstraint )
1060+ JuMP . unregister ( optim, :nonlinconstrainteq )
1061+ any (mpc. con. i_g) && @constraint (optim, nonlinconstraint, Z̃var in g_oracle)
1062+ mpc. con. neq > 0 && @constraint (optim, nonlinconstrainteq, Z̃var in geq_oracle)
9491063 return nothing
9501064end
9511065
0 commit comments