Skip to content

Commit bc93b8f

Browse files
committed
reduce allocation MovingHorizonEstimator
1 parent aa2f818 commit bc93b8f

File tree

7 files changed

+201
-137
lines changed

7 files changed

+201
-137
lines changed

.github/workflows/TagBot.yml

+19-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,22 @@ on:
44
types:
55
- created
66
workflow_dispatch:
7+
inputs:
8+
lookback:
9+
default: 3
10+
permissions:
11+
actions: read
12+
checks: read
13+
contents: write
14+
deployments: read
15+
issues: read
16+
discussions: read
17+
packages: read
18+
pages: read
19+
pull-requests: read
20+
repository-projects: read
21+
security-events: read
22+
statuses: read
723
jobs:
824
TagBot:
925
if: github.event_name == 'workflow_dispatch' || github.actor == 'JuliaTagBot'
@@ -12,4 +28,6 @@ jobs:
1228
- uses: JuliaRegistries/TagBot@v1
1329
with:
1430
token: ${{ secrets.GITHUB_TOKEN }}
15-
ssh: ${{ secrets.DOCUMENTER_KEY }}
31+
# Edit the following line to reflect the actual name of the GitHub Secret containing your private key
32+
ssh: ${{ secrets.DOCUMENTER_KEY }}
33+
# ssh: ${{ secrets.NAME_OF_MY_SSH_PRIVATE_KEY_SECRET }}

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ for more detailed examples.
105105
- [x] quickly compare multiple optimizers
106106
- [x] nonlinear solvers relying on automatic differentiation (exact derivative)
107107
- [x] additional information about the optimum to ease troubleshooting
108+
- [x] implementation that carefully limits allocations for real-time applications
108109

109110
### State Estimation Features
110111

src/controller/construct.jl

+20-20
Original file line numberDiff line numberDiff line change
@@ -149,79 +149,79 @@ function setconstraint!(
149149
end
150150
if !isnothing(Umin)
151151
size(Umin) == (nu*Hp,) || throw(ArgumentError("Umin size must be $((nu*Hp,))"))
152-
con.Umin[:] = Umin
152+
con.Umin .= Umin
153153
end
154154
if !isnothing(Umax)
155155
size(Umax) == (nu*Hp,) || throw(ArgumentError("Umax size must be $((nu*Hp,))"))
156-
con.Umax[:] = Umax
156+
con.Umax .= Umax
157157
end
158158
if !isnothing(ΔUmin)
159159
size(ΔUmin) == (nu*Hc,) || throw(ArgumentError("ΔUmin size must be $((nu*Hc,))"))
160-
con.ΔŨmin[1:nu*Hc] = ΔUmin
160+
con.ΔŨmin[1:nu*Hc] .= ΔUmin
161161
end
162162
if !isnothing(ΔUmax)
163163
size(ΔUmax) == (nu*Hc,) || throw(ArgumentError("ΔUmax size must be $((nu*Hc,))"))
164-
con.ΔŨmax[1:nu*Hc] = ΔUmax
164+
con.ΔŨmax[1:nu*Hc] .= ΔUmax
165165
end
166166
if !isnothing(Ymin)
167167
size(Ymin) == (ny*Hp,) || throw(ArgumentError("Ymin size must be $((ny*Hp,))"))
168-
con.Ymin[:] = Ymin
168+
con.Ymin .= Ymin
169169
end
170170
if !isnothing(Ymax)
171171
size(Ymax) == (ny*Hp,) || throw(ArgumentError("Ymax size must be $((ny*Hp,))"))
172-
con.Ymax[:] = Ymax
172+
con.Ymax .= Ymax
173173
end
174174
if !isnothing(x̂min)
175175
size(x̂min) == (nx̂,) || throw(ArgumentError("x̂min size must be $((nx̂,))"))
176-
con.x̂min[:] = x̂min
176+
con.x̂min .= x̂min
177177
end
178178
if !isnothing(x̂max)
179179
size(x̂max) == (nx̂,) || throw(ArgumentError("x̂max size must be $((nx̂,))"))
180-
con.x̂max[:] = x̂max
180+
con.x̂max .= x̂max
181181
end
182182
if !isnothing(C_umin)
183183
size(C_umin) == (nu*Hp,) || throw(ArgumentError("C_umin size must be $((nu*Hp,))"))
184184
any(C_umin .< 0) && error("C_umin weights should be non-negative")
185-
con.A_Umin[:, end] = -C_umin
185+
con.A_Umin[:, end] .= -C_umin
186186
end
187187
if !isnothing(C_umax)
188188
size(C_umax) == (nu*Hp,) || throw(ArgumentError("C_umax size must be $((nu*Hp,))"))
189189
any(C_umax .< 0) && error("C_umax weights should be non-negative")
190-
con.A_Umax[:, end] = -C_umax
190+
con.A_Umax[:, end] .= -C_umax
191191
end
192192
if !isnothing(C_Δumin)
193193
size(C_Δumin) == (nu*Hc,) || throw(ArgumentError("C_Δumin size must be $((nu*Hc,))"))
194194
any(C_Δumin .< 0) && error("C_Δumin weights should be non-negative")
195-
con.A_ΔŨmin[1:end-1, end] = -C_Δumin
195+
con.A_ΔŨmin[1:end-1, end] .= -C_Δumin
196196
end
197197
if !isnothing(C_Δumax)
198198
size(C_Δumax) == (nu*Hc,) || throw(ArgumentError("C_Δumax size must be $((nu*Hc,))"))
199199
any(C_Δumax .< 0) && error("C_Δumax weights should be non-negative")
200-
con.A_ΔŨmax[1:end-1, end] = -C_Δumax
200+
con.A_ΔŨmax[1:end-1, end] .= -C_Δumax
201201
end
202202
if !isnothing(C_ymin)
203203
size(C_ymin) == (ny*Hp,) || throw(ArgumentError("C_ymin size must be $((ny*Hp,))"))
204204
any(C_ymin .< 0) && error("C_ymin weights should be non-negative")
205-
con.C_ymin[:] = C_ymin
206-
size(con.A_Ymin, 1) 0 && (con.A_Ymin[:, end] = -con.C_ymin) # for LinModel
205+
con.C_ymin .= C_ymin
206+
size(con.A_Ymin, 1) 0 && (con.A_Ymin[:, end] .= -con.C_ymin) # for LinModel
207207
end
208208
if !isnothing(C_ymax)
209209
size(C_ymax) == (ny*Hp,) || throw(ArgumentError("C_ymax size must be $((ny*Hp,))"))
210210
any(C_ymax .< 0) && error("C_ymax weights should be non-negative")
211-
con.C_ymax[:] = C_ymax
212-
size(con.A_Ymax, 1) 0 && (con.A_Ymax[:, end] = -con.C_ymax) # for LinModel
211+
con.C_ymax .= C_ymax
212+
size(con.A_Ymax, 1) 0 && (con.A_Ymax[:, end] .= -con.C_ymax) # for LinModel
213213
end
214214
if !isnothing(c_x̂min)
215215
size(c_x̂min) == (nx̂,) || throw(ArgumentError("c_x̂min size must be $((nx̂,))"))
216216
any(c_x̂min .< 0) && error("c_x̂min weights should be non-negative")
217-
con.c_x̂min[:] = c_x̂min
218-
size(con.A_x̂min, 1) 0 && (con.A_x̂min[:, end] = -con.c_x̂min) # for LinModel
217+
con.c_x̂min .= c_x̂min
218+
size(con.A_x̂min, 1) 0 && (con.A_x̂min[:, end] .= -con.c_x̂min) # for LinModel
219219
end
220220
if !isnothing(c_x̂max)
221221
size(c_x̂max) == (nx̂,) || throw(ArgumentError("c_x̂max size must be $((nx̂,))"))
222222
any(c_x̂max .< 0) && error("c_x̂max weights should be non-negative")
223-
con.c_x̂max[:] = c_x̂max
224-
size(con.A_x̂max, 1) 0 && (con.A_x̂max[:, end] = -con.c_x̂max) # for LinModel
223+
con.c_x̂max .= c_x̂max
224+
size(con.A_x̂max, 1) 0 && (con.A_x̂max[:, end] .= -con.c_x̂max) # for LinModel
225225
end
226226
i_Umin, i_Umax = .!isinf.(con.Umin), .!isinf.(con.Umax)
227227
i_ΔŨmin, i_ΔŨmax = .!isinf.(con.ΔŨmin), .!isinf.(con.ΔŨmin)

src/controller/execute.jl

+31-20
Original file line numberDiff line numberDiff line change
@@ -225,15 +225,15 @@ function predictstoch!(
225225
) where {NT<:Real}
226226
isnothing(ym) && error("Predictive controllers with InternalModel need the measured "*
227227
"outputs ym in keyword argument to compute control actions u")
228-
Ŷop = mpc.Ŷop
228+
Ŷop, ny, yop = mpc.Ŷop, estim.model.ny, estim.model.yop
229229
ŷd = h(estim.model, estim.x̂d, d - estim.model.dop) .+ estim.model.yop
230230
ŷs = zeros(NT, estim.model.ny)
231231
ŷs[estim.i_ym] .= @views ym .- ŷd[estim.i_ym] # ŷs=0 for unmeasured outputs
232232
Ŷop_LHS = similar(Ŷop)
233233
Ŷop .= mul!(Ŷop_LHS, mpc.Ks, estim.x̂s)
234234
Ŷop .+= mul!(Ŷop_LHS, mpc.Ps, ŷs)
235235
for j=1:mpc.Hp
236-
Ŷop[(1 + estim.model.ny*(j-1)):(estim.model.ny*j)] .+= estim.model.yop
236+
Ŷop[(1 + ny*(j-1)):(ny*j)] .+= yop
237237
end
238238
return nothing
239239
end
@@ -249,6 +249,8 @@ Also init ``\mathbf{f_x̂} = \mathbf{g_x̂ d}(k) + \mathbf{j_x̂ D̂} + \mathbf{
249249
vector for the terminal constraints, see [`init_predmat`](@ref).
250250
"""
251251
function linconstraint!(mpc::PredictiveController, model::LinModel)
252+
nU, nΔŨ, nY = length(mpc.con.Umin), length(mpc.con.ΔŨmin), length(mpc.con.Ymin)
253+
nx̂ = mpc.estim.nx̂
252254
fx̂ = mpc.con.fx̂
253255
fx̂_LHS = similar(fx̂)
254256
fx̂ .= mul!(fx̂_LHS, mpc.con.kx̂, mpc.estim.x̂)
@@ -257,28 +259,37 @@ function linconstraint!(mpc::PredictiveController, model::LinModel)
257259
fx̂ .+= mul!(fx̂_LHS, mpc.con.gx̂, mpc.d0)
258260
fx̂ .+= mul!(fx̂_LHS, mpc.con.jx̂, mpc.D̂0)
259261
end
260-
mpc.con.b .= [
261-
-mpc.con.Umin + mpc.T_lastu
262-
+mpc.con.Umax - mpc.T_lastu
263-
-mpc.con.ΔŨmin
264-
+mpc.con.ΔŨmax
265-
-mpc.con.Ymin + mpc.F
266-
+mpc.con.Ymax - mpc.F
267-
-mpc.con.x̂min + mpc.con.fx̂
268-
+mpc.con.x̂max - mpc.con.fx̂
269-
]
262+
n = 0
263+
mpc.con.b[(n+1):(n+nU)] .= @. -mpc.con.Umin + mpc.T_lastu
264+
n += nU
265+
mpc.con.b[(n+1):(n+nU)] .= @. +mpc.con.Umax - mpc.T_lastu
266+
n += nU
267+
mpc.con.b[(n+1):(n+nΔŨ)] .= @. -mpc.con.ΔŨmin
268+
n += nΔŨ
269+
mpc.con.b[(n+1):(n+nΔŨ)] .= @. +mpc.con.ΔŨmax
270+
n += nΔŨ
271+
mpc.con.b[(n+1):(n+nY)] .= @. -mpc.con.Ymin + mpc.F
272+
n += nY
273+
mpc.con.b[(n+1):(n+nY)] .= @. +mpc.con.Ymax - mpc.F
274+
n += nY
275+
mpc.con.b[(n+1):(n+nx̂)] .= @. -mpc.con.x̂min + fx̂
276+
n += nx̂
277+
mpc.con.b[(n+1):(n+nx̂)] .= @. +mpc.con.x̂max - fx̂
270278
lincon = mpc.optim[:linconstraint]
271279
set_normalized_rhs.(lincon, mpc.con.b[mpc.con.i_b])
272280
end
273281

274282
"Set `b` excluding predicted output constraints when `model` is not a [`LinModel`](@ref)."
275-
function linconstraint!(mpc::PredictiveController, model::SimModel)
276-
mpc.con.b .= [
277-
-mpc.con.Umin + mpc.T_lastu
278-
+mpc.con.Umax - mpc.T_lastu
279-
-mpc.con.ΔŨmin
280-
+mpc.con.ΔŨmax
281-
]
283+
function linconstraint!(mpc::PredictiveController, ::SimModel)
284+
nU, nΔŨ = length(mpc.con.Umin), length(mpc.con.ΔŨmin)
285+
n = 0
286+
mpc.con.b[(n+1):(n+nU)] .= @. -mpc.con.Umin + mpc.T_lastu
287+
n += nU
288+
mpc.con.b[(n+1):(n+nU)] .= @. +mpc.con.Umax - mpc.T_lastu
289+
n += nU
290+
mpc.con.b[(n+1):(n+nΔŨ)] .= @. -mpc.con.ΔŨmin
291+
n += nΔŨ
292+
mpc.con.b[(n+1):(n+nΔŨ)] .= @. +mpc.con.ΔŨmax
282293
lincon = mpc.optim[:linconstraint]
283294
set_normalized_rhs.(lincon, mpc.con.b[mpc.con.i_b])
284295
end
@@ -442,7 +453,7 @@ function optim_objective!(mpc::PredictiveController{NT}) where {NT<:Real}
442453
end
443454
@debug solution_summary(optim, verbose=true)
444455
end
445-
mpc.ΔŨ[:] = iserror(optim) ? ΔŨlast : ΔŨcurr
456+
mpc.ΔŨ .= iserror(optim) ? ΔŨlast : ΔŨcurr
446457
return mpc.ΔŨ
447458
end
448459

src/estimator/kalman.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -752,7 +752,7 @@ automatically computes the Jacobians:
752752
```math
753753
\begin{aligned}
754754
\mathbf{F̂}(k) &= \left. \frac{∂\mathbf{f̂}(\mathbf{x̂}, \mathbf{u}, \mathbf{d})}{∂\mathbf{x̂}} \right|_{\mathbf{x̂ = x̂}_{k-1}(k),\, \mathbf{u = u}(k),\, \mathbf{d = d}(k)} \\
755-
\mathbf{Ĥ}(k) &= \left. \frac{∂\mathbf{ĥ}(\mathbf{x̂}, \mathbf{d})}{∂\mathbf{x̂}} \right|_{\mathbf{x = x̂}_{k-1}(k),\, \mathbf{d = d}(k)}
755+
\mathbf{Ĥ}(k) &= \left. \frac{∂\mathbf{ĥ}(\mathbf{x̂}, \mathbf{d})}{∂\mathbf{x̂}} \right|_{\mathbf{ = x̂}_{k-1}(k),\, \mathbf{d = d}(k)}
756756
\end{aligned}
757757
```
758758
The matrix ``\mathbf{Ĥ^m}`` is the rows of ``\mathbf{Ĥ}`` that are measured outputs.

src/estimator/mhe/construct.jl

+38-29
Original file line numberDiff line numberDiff line change
@@ -418,63 +418,65 @@ function setconstraint!(
418418
if !isnothing(X̂min)
419419
size(X̂min) == (nX̂con,) || throw(ArgumentError("X̂min size must be $((nX̂con,))"))
420420
con.x̃min[end-nx̂+1:end] = X̂min[1:nx̂] # if C is finite : x̃ = [ϵ; x̂]
421-
con.X̂min[:] = X̂min[nx̂+1:end]
421+
con.X̂min .= X̂min[nx̂+1:end]
422422
end
423423
if !isnothing(X̂max)
424424
size(X̂max) == (nX̂con,) || throw(ArgumentError("X̂max size must be $((nX̂con,))"))
425425
con.x̃max[end-nx̂+1:end] = X̂max[1:nx̂] # if C is finite : x̃ = [ϵ; x̂]
426-
con.X̂max[:] = X̂max[nx̂+1:end]
426+
con.X̂max .= X̂max[nx̂+1:end]
427427
end
428428
if !isnothing(Ŵmin)
429429
size(Ŵmin) == (nŵ*He,) || throw(ArgumentError("Ŵmin size must be $((nŵ*He,))"))
430-
con.Ŵmin[:] = Ŵmin
430+
con.Ŵmin .= Ŵmin
431431
end
432432
if !isnothing(Ŵmax)
433433
size(Ŵmax) == (nŵ*He,) || throw(ArgumentError("Ŵmax size must be $((nŵ*He,))"))
434-
con.Ŵmax[:] = Ŵmax
434+
con.Ŵmax .= Ŵmax
435435
end
436436
if !isnothing(V̂min)
437437
size(V̂min) == (nym*He,) || throw(ArgumentError("V̂min size must be $((nym*He,))"))
438-
con.V̂min[:] = V̂min
438+
con.V̂min .= V̂min
439439
end
440440
if !isnothing(V̂max)
441441
size(V̂max) == (nym*He,) || throw(ArgumentError("V̂max size must be $((nym*He,))"))
442-
con.V̂max[:] = V̂max
442+
con.V̂max .= V̂max
443443
end
444444
if !isnothing(C_x̂min)
445445
size(C_x̂min) == (nX̂con,) || throw(ArgumentError("C_x̂min size must be $((nX̂con,))"))
446446
any(C_x̂min .< 0) && error("C_x̂min weights should be non-negative")
447-
con.A_x̃min[end-nx̂+1:end, end] = -C_x̂min[1:nx̂] # if C is finite : x̃ = [ϵ; x̂]
448-
con.C_x̂min[:] = C_x̂min[nx̂+1:end]
447+
# if C is finite : x̃ = [ϵ; x̂]
448+
con.A_x̃min[end-nx̂+1:end, end] .= @views -C_x̂min[1:nx̂]
449+
con.C_x̂min .= @views C_x̂min[nx̂+1:end]
449450
size(con.A_X̂min, 1) 0 && (con.A_X̂min[:, end] = -con.C_x̂min) # for LinModel
450451
end
451452
if !isnothing(C_x̂max)
452453
size(C_x̂max) == (nX̂con,) || throw(ArgumentError("C_x̂max size must be $((nX̂con,))"))
453454
any(C_x̂max .< 0) && error("C_x̂max weights should be non-negative")
454-
con.A_x̃max[end-nx̂+1:end, end] = -C_x̂max[1:nx̂] # if C is finite : x̃ = [ϵ; x̂]
455-
con.C_x̂max[:] = C_x̂max[nx̂+1:end]
455+
# if C is finite : x̃ = [ϵ; x̂] :
456+
con.A_x̃max[end-nx̂+1:end, end] .= @views -C_x̂max[1:nx̂]
457+
con.C_x̂max .= @views C_x̂max[nx̂+1:end]
456458
size(con.A_X̂max, 1) 0 && (con.A_X̂max[:, end] = -con.C_x̂max) # for LinModel
457459
end
458460
if !isnothing(C_ŵmin)
459461
size(C_ŵmin) == (nŵ*He,) || throw(ArgumentError("C_ŵmin size must be $((nŵ*He,))"))
460462
any(C_ŵmin .< 0) && error("C_ŵmin weights should be non-negative")
461-
con.A_Ŵmin[:, end] = -C_ŵmin
463+
con.A_Ŵmin[:, end] .= -C_ŵmin
462464
end
463465
if !isnothing(C_ŵmax)
464466
size(C_ŵmax) == (nŵ*He,) || throw(ArgumentError("C_ŵmax size must be $((nŵ*He,))"))
465467
any(C_ŵmax .< 0) && error("C_ŵmax weights should be non-negative")
466-
con.A_Ŵmax[:, end] = -C_ŵmax
468+
con.A_Ŵmax[:, end] .= -C_ŵmax
467469
end
468470
if !isnothing(C_v̂min)
469471
size(C_v̂min) == (nym*He,) || throw(ArgumentError("C_v̂min size must be $((nym*He,))"))
470472
any(C_v̂min .< 0) && error("C_v̂min weights should be non-negative")
471-
con.C_v̂min[:] = C_v̂min
473+
con.C_v̂min .= C_v̂min
472474
size(con.A_V̂min, 1) 0 && (con.A_V̂min[:, end] = -con.C_v̂min) # for LinModel
473475
end
474476
if !isnothing(C_v̂max)
475477
size(C_v̂max) == (nym*He,) || throw(ArgumentError("C_v̂max size must be $((nym*He,))"))
476478
any(C_v̂max .< 0) && error("C_v̂max weights should be non-negative")
477-
con.C_v̂max[:] = C_v̂max
479+
con.C_v̂max .= C_v̂max
478480
size(con.A_V̂max, 1) 0 && (con.A_V̂max[:, end] = -con.C_v̂max) # for LinModel
479481
end
480482
i_x̃min, i_x̃max = .!isinf.(con.x̃min) , .!isinf.(con.x̃max)
@@ -989,40 +991,46 @@ function init_optimization!(
989991
He = estim.He
990992
nV̂, nX̂, ng = He*estim.nym, He*estim.nx̂, length(con.i_g)
991993
# see init_optimization!(mpc::NonLinMPC, optim) for details on the inspiration
992-
Jfunc, gfunc = let estim=estim, model=model, nZ̃=nZ̃ , nV̂=nV̂, nX̂=nX̂, ng=ng
994+
Jfunc, gfunc = let estim=estim, model=model, nZ̃=nZ̃ , nV̂=nV̂, nX̂=nX̂, ng=ng, nx̂=estim.nx̂
993995
last_Z̃tup_float, last_Z̃tup_dual = nothing, nothing
994996
V̂_cache::DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache(zeros(JNT, nV̂), nZ̃ + 3)
995997
g_cache::DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache(zeros(JNT, ng), nZ̃ + 3)
996998
X̂_cache::DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache(zeros(JNT, nX̂), nZ̃ + 3)
999+
x̄_cache::DiffCache{Vector{JNT}, Vector{JNT}} = DiffCache(zeros(JNT, nx̂), nZ̃ + 3)
9971000
function Jfunc(Z̃tup::JNT...)
998-
= get_tmp(V̂_cache, Z̃tup[1])
1001+
Z̃1 = Z̃tup[begin]
1002+
= get_tmp(V̂_cache, Z̃1)
9991003
= collect(Z̃tup)
10001004
if Z̃tup !== last_Z̃tup_float
1001-
g = get_tmp(g_cache, Z̃tup[1])
1002-
= get_tmp(X̂_cache, Z̃tup[1])
1005+
g = get_tmp(g_cache, Z̃1)
1006+
= get_tmp(X̂_cache, Z̃1)
10031007
V̂, X̂ = predict!(V̂, X̂, estim, model, Z̃)
10041008
g = con_nonlinprog!(g, estim, model, X̂, V̂, Z̃)
10051009
last_Z̃tup_float = Z̃tup
10061010
end
1007-
return obj_nonlinprog(estim, model, V̂, Z̃)
1011+
= get_tmp(x̄_cache, Z̃1)
1012+
return obj_nonlinprog!(x̄, estim, model, V̂, Z̃)
10081013
end
10091014
function Jfunc(Z̃tup::ForwardDiff.Dual...)
1010-
= get_tmp(V̂_cache, Z̃tup[1])
1015+
Z̃1 = Z̃tup[begin]
1016+
= get_tmp(V̂_cache, Z̃1)
10111017
= collect(Z̃tup)
10121018
if Z̃tup !== last_Z̃tup_dual
1013-
g = get_tmp(g_cache, Z̃tup[1])
1014-
= get_tmp(X̂_cache, Z̃tup[1])
1019+
g = get_tmp(g_cache, Z̃1)
1020+
= get_tmp(X̂_cache, Z̃1)
10151021
V̂, X̂ = predict!(V̂, X̂, estim, model, Z̃)
10161022
g = con_nonlinprog!(g, estim, model, X̂, V̂, Z̃)
10171023
last_Z̃tup_dual = Z̃tup
10181024
end
1019-
return obj_nonlinprog(estim, model, V̂, Z̃)
1025+
= get_tmp(x̄_cache, Z̃1)
1026+
return obj_nonlinprog!(x̄, estim, model, V̂, Z̃)
10201027
end
10211028
function gfunc_i(i, Z̃tup::NTuple{N, JNT}) where N
1022-
g = get_tmp(g_cache, Z̃tup[1])
1029+
Z̃1 = Z̃tup[begin]
1030+
g = get_tmp(g_cache, Z̃1)
10231031
if Z̃tup !== last_Z̃tup_float
1024-
= get_tmp(V̂_cache, Z̃tup[1])
1025-
= get_tmp(X̂_cache, Z̃tup[1])
1032+
= get_tmp(V̂_cache, Z̃1)
1033+
= get_tmp(X̂_cache, Z̃1)
10261034
= collect(Z̃tup)
10271035
V̂, X̂ = predict!(V̂, X̂, estim, model, Z̃)
10281036
g = con_nonlinprog!(g, estim, model, X̂, V̂, Z̃)
@@ -1031,10 +1039,11 @@ function init_optimization!(
10311039
return g[i]
10321040
end
10331041
function gfunc_i(i, Z̃tup::NTuple{N, ForwardDiff.Dual}) where N
1034-
g = get_tmp(g_cache, Z̃tup[1])
1042+
Z̃1 = Z̃tup[begin]
1043+
g = get_tmp(g_cache, Z̃1)
10351044
if Z̃tup !== last_Z̃tup_dual
1036-
= get_tmp(V̂_cache, Z̃tup[1])
1037-
= get_tmp(X̂_cache, Z̃tup[1])
1045+
= get_tmp(V̂_cache, Z̃1)
1046+
= get_tmp(X̂_cache, Z̃1)
10381047
= collect(Z̃tup)
10391048
V̂, X̂ = predict!(V̂, X̂, estim, model, Z̃)
10401049
g = con_nonlinprog!(g, estim, model, X̂, V̂, Z̃)

0 commit comments

Comments
 (0)