Skip to content

Commit 18a75ab

Browse files
committed
added: hessian kwarg in NonLinMPC
1 parent 531edb4 commit 18a75ab

File tree

1 file changed

+27
-15
lines changed

1 file changed

+27
-15
lines changed

src/controller/nonlinmpc.jl

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ struct NonLinMPC{
1414
TM<:TranscriptionMethod,
1515
JM<:JuMP.GenericModel,
1616
GB<:AbstractADType,
17-
JB<:AbstractADType,
17+
JB<:AbstractADType,
18+
HB<:Union{Nothing, AbstractADType},
1819
PT<:Any,
1920
JEfunc<:Function,
2021
GCfunc<:Function
@@ -27,6 +28,7 @@ struct NonLinMPC{
2728
con::ControllerConstraint{NT, GCfunc}
2829
gradient::GB
2930
jacobian::JB
31+
hessian::HB
3032
::Vector{NT}
3133
::Vector{NT}
3234
Hp::Int
@@ -63,14 +65,15 @@ struct NonLinMPC{
6365
function NonLinMPC{NT}(
6466
estim::SE,
6567
Hp, Hc, M_Hp, N_Hc, L_Hp, Cwt, Ewt, JE::JEfunc, gc!::GCfunc, nc, p::PT,
66-
transcription::TM, optim::JM, gradient::GB, jacobian::JB
68+
transcription::TM, optim::JM, gradient::GB, jacobian::JB, hessian::HB
6769
) where {
6870
NT<:Real,
6971
SE<:StateEstimator,
7072
TM<:TranscriptionMethod,
7173
JM<:JuMP.GenericModel,
7274
GB<:AbstractADType,
7375
JB<:AbstractADType,
76+
HB<:Union{Nothing, AbstractADType},
7477
PT<:Any,
7578
JEfunc<:Function,
7679
GCfunc<:Function,
@@ -107,9 +110,9 @@ struct NonLinMPC{
107110
nZ̃ = get_nZ(estim, transcription, Hp, Hc) +
108111
= zeros(NT, nZ̃)
109112
buffer = PredictiveControllerBuffer(estim, transcription, Hp, Hc, nϵ)
110-
mpc = new{NT, SE, TM, JM, GB, JB, PT, JEfunc, GCfunc}(
113+
mpc = new{NT, SE, TM, JM, GB, JB, HB, PT, JEfunc, GCfunc}(
111114
estim, transcription, optim, con,
112-
gradient, jacobian,
115+
gradient, jacobian, hessian,
113116
Z̃, ŷ,
114117
Hp, Hc, nϵ,
115118
weights,
@@ -206,6 +209,8 @@ This controller allocates memory at each time step for the optimization.
206209
function, see [`DifferentiationInterface` doc](@extref DifferentiationInterface List).
207210
- `jacobian=default_jacobian(transcription)` : an `AbstractADType` backend for the Jacobian
208211
of the nonlinear constraints, see `gradient` above for the options (default in Extended Help).
212+
- `hessian=nothing` : an `AbstractADType` backend for the Hessian of the objective function,
213+
see `gradient` above for the options, use `nothing` for the LBFGS approximation of `optim`.
209214
- additional keyword arguments are passed to [`UnscentedKalmanFilter`](@ref) constructor
210215
(or [`SteadyKalmanFilter`](@ref), for [`LinModel`](@ref)).
211216
@@ -265,8 +270,11 @@ NonLinMPC controller with a sample time Ts = 10.0 s, Ipopt optimizer, UnscentedK
265270
coloring_algorithm = GreedyColoringAlgorithm()
266271
)
267272
```
268-
Optimizers generally benefit from exact derivatives like AD. However, the [`NonLinModel`](@ref)
269-
state-space functions must be compatible with this feature. See [`JuMP` documentation](@extref JuMP Common-mistakes-when-writing-a-user-defined-operator)
273+
Also, the `hessian` argument defaults to `nothing` meaning the built-in second-order
274+
approximation of `solver`. Otherwise, a sparse backend like above is recommended to test
275+
different `hessian` methods. Optimizers generally benefit from exact derivatives like AD.
276+
However, the [`NonLinModel`](@ref) state-space functions must be compatible with this
277+
feature. See [`JuMP` documentation](@extref JuMP Common-mistakes-when-writing-a-user-defined-operator)
270278
for common mistakes when writing these functions.
271279
272280
Note that if `Cwt≠Inf`, the attribute `nlp_scaling_max_gradient` of `Ipopt` is set to
@@ -293,13 +301,14 @@ function NonLinMPC(
293301
optim::JuMP.GenericModel = JuMP.Model(DEFAULT_NONLINMPC_OPTIMIZER, add_bridges=false),
294302
gradient::AbstractADType = DEFAULT_NONLINMPC_GRADIENT,
295303
jacobian::AbstractADType = default_jacobian(transcription),
304+
hessian::Union{Nothing, AbstractADType} = nothing,
296305
kwargs...
297306
)
298307
estim = UnscentedKalmanFilter(model; kwargs...)
299308
return NonLinMPC(
300309
estim;
301310
Hp, Hc, Mwt, Nwt, Lwt, Cwt, Ewt, JE, gc, nc, p, M_Hp, N_Hc, L_Hp,
302-
transcription, optim, gradient, jacobian
311+
transcription, optim, gradient, jacobian, hessian
303312
)
304313
end
305314

@@ -324,13 +333,14 @@ function NonLinMPC(
324333
optim::JuMP.GenericModel = JuMP.Model(DEFAULT_NONLINMPC_OPTIMIZER, add_bridges=false),
325334
gradient::AbstractADType = DEFAULT_NONLINMPC_GRADIENT,
326335
jacobian::AbstractADType = default_jacobian(transcription),
336+
hessian::Union{Nothing, AbstractADType} = nothing,
327337
kwargs...
328338
)
329339
estim = SteadyKalmanFilter(model; kwargs...)
330340
return NonLinMPC(
331341
estim;
332342
Hp, Hc, Mwt, Nwt, Lwt, Cwt, Ewt, JE, gc, nc, p, M_Hp, N_Hc, L_Hp,
333-
transcription, optim, gradient, jacobian
343+
transcription, optim, gradient, jacobian, hessian
334344
)
335345
end
336346

@@ -379,6 +389,7 @@ function NonLinMPC(
379389
optim::JuMP.GenericModel = JuMP.Model(DEFAULT_NONLINMPC_OPTIMIZER, add_bridges=false),
380390
gradient::AbstractADType = DEFAULT_NONLINMPC_GRADIENT,
381391
jacobian::AbstractADType = default_jacobian(transcription),
392+
hessian::Union{Nothing, AbstractADType} = nothing,
382393
) where {
383394
NT<:Real,
384395
SE<:StateEstimator{NT}
@@ -392,7 +403,7 @@ function NonLinMPC(
392403
gc! = get_mutating_gc(NT, gc)
393404
return NonLinMPC{NT}(
394405
estim, Hp, Hc, M_Hp, N_Hc, L_Hp, Cwt, Ewt, JE, gc!, nc, p,
395-
transcription, optim, gradient, jacobian
406+
transcription, optim, gradient, jacobian, hessian
396407
)
397408
end
398409

@@ -540,7 +551,7 @@ function init_optimization!(mpc::NonLinMPC, model::SimModel, optim::JuMP.Generic
540551
JuMP.set_attribute(optim, "nlp_scaling_max_gradient", 10.0/C)
541552
end
542553
end
543-
Jfunc, ∇Jfunc!, gfuncs, ∇gfuncs!, geqfuncs, ∇geqfuncs! = get_optim_functions(
554+
Jfunc, ∇Jfunc!, ∇²Jfunc!, gfuncs, ∇gfuncs!, geqfuncs, ∇geqfuncs! = get_optim_functions(
544555
mpc, optim
545556
)
546557
@operator(optim, J, nZ̃, Jfunc, ∇Jfunc!)
@@ -553,14 +564,15 @@ end
553564
"""
554565
get_optim_functions(
555566
mpc::NonLinMPC, optim::JuMP.GenericModel
556-
) -> Jfunc, ∇Jfunc!, gfuncs, ∇gfuncs!, geqfuncs, ∇geqfuncs!
567+
) -> Jfunc, ∇Jfunc!, ∇J²Jfunc!, gfuncs, ∇gfuncs!, geqfuncs, ∇geqfuncs!
557568
558569
Return the functions for the nonlinear optimization of `mpc` [`NonLinMPC`](@ref) controller.
559570
560-
Return the nonlinear objective `Jfunc` function, and `∇Jfunc!`, to compute its gradient.
561-
Also return vectors with the nonlinear inequality constraint functions `gfuncs`, and
562-
`∇gfuncs!`, for the associated gradients. Lastly, also return vectors with the nonlinear
563-
equality constraint functions `geqfuncs` and gradients `∇geqfuncs!`.
571+
Return the nonlinear objective `Jfunc` function, and `∇Jfunc!` and `∇²Jfunc!`, to compute
572+
its gradient and hessian, respectively. Also return vectors with the nonlinear inequality
573+
constraint functions `gfuncs`, and `∇gfuncs!`, for the associated gradients. Lastly, also
574+
return vectors with the nonlinear equality constraint functions `geqfuncs` and gradients
575+
`∇geqfuncs!`.
564576
565577
This method is really intricate and I'm not proud of it. That's because of 3 elements:
566578

0 commit comments

Comments
 (0)