Skip to content

Commit 406d18f

Browse files
committed
added: support for mutating or not gc
1 parent 8739705 commit 406d18f

File tree

4 files changed

+142
-63
lines changed

4 files changed

+142
-63
lines changed

docs/src/manual/nonlinmpc.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,9 +194,9 @@ output vector of `plant` argument corresponds to the model output vector in `mpc
194194
We can now define the ``J_E`` function and the `empc` controller:
195195

196196
```@example 1
197-
function JE(UE, ŶE, _ , p)
197+
function JE(Ue, Ŷe, _ , p)
198198
Ts = p
199-
τ, ω = UE[1:end-1], ŶE[2:2:end-1]
199+
τ, ω = Ue[1:end-1], Ŷe[2:2:end-1]
200200
return Ts*sum(τ.*ω)
201201
end
202202
empc = NonLinMPC(estim2; Hp, Hc, Nwt, Mwt=[0.5, 0], Cwt=Inf, Ewt=3.5e3, JE=JE, p=Ts)

src/controller/construct.jl

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"Include all the data for the constraints of [`PredictiveController`](@ref)"
2-
struct ControllerConstraint{NT<:Real, GEfunc<:Function}
2+
struct ControllerConstraint{NT<:Real, GCfunc<:Function}
33
ẽx̂ ::Matrix{NT}
44
fx̂ ::Vector{NT}
55
gx̂ ::Matrix{NT}
@@ -31,8 +31,8 @@ struct ControllerConstraint{NT<:Real, GEfunc<:Function}
3131
c_x̂min ::Vector{NT}
3232
c_x̂max ::Vector{NT}
3333
i_g ::BitVector
34-
gE ::GEfunc
35-
nE ::Int
34+
gc! ::GCfunc
35+
nc ::Int
3636
end
3737

3838
@doc raw"""
@@ -628,7 +628,8 @@ end
628628

629629
"""
630630
init_defaultcon_mpc(
631-
estim, C, S, N_Hc, E, ex̂, fx̂, gx̂, jx̂, kx̂, vx̂, gE=()->nothing, nE=0
631+
estim, C, S, N_Hc, E, ex̂, fx̂, gx̂, jx̂, kx̂, vx̂,
632+
gc!=(_,_,_,_,_,_)->nothing, nc=0
632633
) -> con, S̃, Ñ_Hc, Ẽ
633634
634635
Init `ControllerConstraint` struct with default parameters based on estimator `estim`.
@@ -637,8 +638,9 @@ Also return `S̃`, `Ñ_Hc` and `Ẽ` matrices for the the augmented decision ve
637638
"""
638639
function init_defaultcon_mpc(
639640
estim::StateEstimator{NT},
640-
Hp, Hc, C, S, N_Hc, E, ex̂, fx̂, gx̂, jx̂, kx̂, vx̂, bx̂, gE::GEfunc=()->nothing, nE=0
641-
) where {NT<:Real, GEfunc<:Function}
641+
Hp, Hc, C, S, N_Hc, E, ex̂, fx̂, gx̂, jx̂, kx̂, vx̂, bx̂,
642+
gc!::GCfunc=(_,_,_,_,_,_)->nothing, nc=0
643+
) where {NT<:Real, GCfunc<:Function}
642644
model = estim.model
643645
nu, ny, nx̂ = model.nu, model.ny, estim.nx̂
644646
= isinf(C) ? 0 : 1
@@ -670,12 +672,12 @@ function init_defaultcon_mpc(
670672
A_Umin, A_Umax, A_ΔŨmin, A_ΔŨmax, A_Ymin, A_Ymax, A_x̂max, A_x̂min
671673
)
672674
b = zeros(NT, size(A, 1)) # dummy b vector (updated just before optimization)
673-
con = ControllerConstraint{NT, GEfunc}(
675+
con = ControllerConstraint{NT, GCfunc}(
674676
ẽx̂ , fx̂ , gx̂ , jx̂ , kx̂ , vx̂ , bx̂ ,
675677
U0min , U0max , ΔŨmin , ΔŨmax , Y0min , Y0max , x̂0min , x̂0max,
676678
A_Umin , A_Umax, A_ΔŨmin, A_ΔŨmax , A_Ymin , A_Ymax , A_x̂min , A_x̂max,
677679
A , b , i_b , C_ymin , C_ymax , c_x̂min , c_x̂max , i_g,
678-
gE , nE
680+
gc! , nc
679681
)
680682
return con, nϵ, S̃, Ñ_Hc, Ẽ
681683
end

src/controller/nonlinmpc.jl

Lines changed: 94 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,13 @@ struct NonLinMPC{
4949
Dop::Vector{NT}
5050
buffer::PredictiveControllerBuffer{NT}
5151
function NonLinMPC{NT, SE, JM, JEfunc, P}(
52-
estim::SE, Hp, Hc, M_Hp, N_Hc, L_Hp, Cwt, Ewt, JE::JEfunc, gE, nE, p::P, optim::JM
52+
estim::SE, Hp, Hc, M_Hp, N_Hc, L_Hp, Cwt, Ewt, JE::JEfunc, gc, nc, p::P, optim::JM
5353
) where {NT<:Real, SE<:StateEstimator, JM<:JuMP.GenericModel, JEfunc<:Function, P<:Any}
5454
model = estim.model
5555
nu, ny, nd, nx̂ = model.nu, model.ny, model.nd, estim.nx̂
5656
= copy(model.yop) # dummy vals (updated just before optimization)
5757
validate_JE(NT, JE)
58+
gc! = get_mutating_gc(NT, gc)
5859
validate_weights(model, Hp, Hc, M_Hp, N_Hc, L_Hp, Cwt, Ewt)
5960
# convert `Diagonal` to normal `Matrix` if required:
6061
M_Hp = Hermitian(convert(Matrix{NT}, M_Hp), :L)
@@ -68,7 +69,7 @@ struct NonLinMPC{
6869
# dummy vals (updated just before optimization):
6970
F, fx̂ = zeros(NT, ny*Hp), zeros(NT, nx̂)
7071
con, nϵ, S̃, Ñ_Hc, Ẽ = init_defaultcon_mpc(
71-
estim, Hp, Hc, Cwt, S, N_Hc, E, ex̂, fx̂, gx̂, jx̂, kx̂, vx̂, bx̂, gE, nE
72+
estim, Hp, Hc, Cwt, S, N_Hc, E, ex̂, fx̂, gx̂, jx̂, kx̂, vx̂, bx̂, gc!, nc
7273
)
7374
= init_quadprog(model, Ẽ, S̃, M_Hp, Ñ_Hc, L_Hp)
7475
# dummy vals (updated just before optimization):
@@ -112,30 +113,32 @@ controller minimizes the following objective function at each discrete time ``k`
112113
+ \mathbf{(ΔU)}' \mathbf{N}_{H_c} \mathbf{(ΔU)} \\&
113114
+ \mathbf{(R̂_u - U)}' \mathbf{L}_{H_p} \mathbf{(R̂_u - U)}
114115
+ C ϵ^2
115-
+ E J_E(\mathbf{U}_E, \mathbf{Ŷ}_E, \mathbf{D̂}_E, \mathbf{p})
116+
+ E J_E(\mathbf{U_e}, \mathbf{Ŷ_e}, \mathbf{D̂_e}, \mathbf{p})
116117
\end{aligned}
117118
```
118-
subject to [`setconstraint!`](@ref) bounds, and the economic inequality constraints:
119+
subject to [`setconstraint!`](@ref) bounds, and the custom inequality constraints:
119120
```math
120-
\mathbf{g}_E(\mathbf{U}_E, \mathbf{Ŷ}_E, \mathbf{D̂}_E, ϵ, \mathbf{p}) ≤ \mathbf{0}
121+
\mathbf{g_c}\Big(\mathbf{U_e}, \mathbf{Ŷ_e}, \mathbf{D̂_e}, \mathbf{p}, ϵ(k)\Big) ≤ \mathbf{0}
121122
```
122123
The economic function ``J_E`` can penalizes solutions with high economic costs. Setting all
123-
the weights to 0 except ``E`` creates a pure economic model predictive controller (EMPC).
124-
The arguments of ``J_E`` and ``\mathbf{g}_E`` include the manipulated inputs, the predicted
125-
outputs and measured disturbances from ``k`` to ``k+H_p`` inclusively:
124+
the weights to 0 except ``E`` creates a pure economic model predictive controller (EMPC).
125+
As a matter of fact, ``J_E`` can be any nonlinear function to customize the objective, even
126+
if there is no economic interpretation to it. The arguments of ``J_E`` and ``\mathbf{g_c}``
127+
include the manipulated inputs, predicted outputs and measured disturbances, extended from
128+
``k`` to ``k + H_p`` (inclusively):
126129
```math
127-
\mathbf{U}_E = \begin{bmatrix} \mathbf{U} \\ \mathbf{u}(k+H_p-1) \end{bmatrix} , \quad
128-
\mathbf{Ŷ}_E = \begin{bmatrix} \mathbf{ŷ}(k) \\ \mathbf{Ŷ} \end{bmatrix} , \quad
129-
\mathbf{D̂}_E = \begin{bmatrix} \mathbf{d}(k) \\ \mathbf{D̂} \end{bmatrix}
130+
\mathbf{U_e} = \begin{bmatrix} \mathbf{U} \\ \mathbf{u}(k+H_p-1) \end{bmatrix} , \quad
131+
\mathbf{Ŷ_e} = \begin{bmatrix} \mathbf{ŷ}(k) \\ \mathbf{Ŷ} \end{bmatrix} , \quad
132+
\mathbf{D̂_e} = \begin{bmatrix} \mathbf{d}(k) \\ \mathbf{D̂} \end{bmatrix}
130133
```
131134
since ``H_c ≤ H_p`` implies that ``\mathbf{Δu}(k+H_p) = \mathbf{0}`` or ``\mathbf{u}(k+H_p)=
132-
\mathbf{u}(k+H_p-1)``. The vector ``\mathbf{D̂}`` includes the predicted measured disturbance
133-
over ``H_p``. The argument ``\mathbf{p}`` is a custom parameter object of any type but use a
134-
mutable one if you want to modify it later e.g.: a vector.
135+
\mathbf{u}(k+H_p-1)``. The vector ``\mathbf{D̂}`` comprises the measured disturbance
136+
predictions over ``H_p``. The argument ``\mathbf{p}`` is a custom parameter object of any
137+
type, but use a mutable one if you want to modify it later e.g.: a vector.
135138
136139
!!! tip
137-
Replace any of the arguments of ``J_E`` and ``\mathbf{g}_E`` functions with `_` if not
138-
needed (details in Extended Help).
140+
Replace any of the arguments of ``J_E`` and ``\mathbf{g_c}`` functions with `_` if not
141+
needed (see e.g. the default value of `JE` below).
139142
140143
See [`LinMPC`](@ref) for the definition of the other variables. This method uses the default
141144
state estimator :
@@ -159,12 +162,13 @@ state estimator :
159162
- `L_Hp=diagm(repeat(Lwt,Hp))` : positive semidefinite symmetric matrix ``\mathbf{L}_{H_p}``.
160163
- `Cwt=1e5` : slack variable weight ``C`` (scalar), use `Cwt=Inf` for hard constraints only.
161164
- `Ewt=0.0` : economic costs weight ``E`` (scalar).
162-
- `JE=(_,_,_,_)->0.0` : economic (or custom) cost function ``J_E(\mathbf{U}_E, \mathbf{Ŷ}_E,
163-
\mathbf{D̂}_E, \mathbf{p})`` (details in Extended Help).
164-
- `gE=(_,_,_,_,_,_)->nothing` : economic (or custom) constraint function ``\mathbf{g}_E(
165-
\mathbf{U}_E, \mathbf{Ŷ}_E, \mathbf{D̂}_E, ϵ, \mathbf{p})`` (details in Extended Help).
166-
- `nE=0` : number of economic constraints.
167-
- `p=model.p` : ``J_E`` and ``\mathbf{g}_E`` functions parameter ``\mathbf{p}`` (any type).
165+
- `JE=(_,_,_,_)->0.0` : economic or custom cost function ``J_E(\mathbf{U_e}, \mathbf{Ŷ_e},
166+
\mathbf{D̂_e}, \mathbf{p})``.
167+
- `gc=(_,_,_,_,_,_)->nothing` or `gc!` : custom inequality constraint function
168+
``\mathbf{g_c}(\mathbf{U_e}, \mathbf{Ŷ_e}, \mathbf{D̂_e}, \mathbf{p}, ϵ)`` (mutating or
169+
not, details in Extended Help).
170+
- `nc=0` : number of custom inequality constraints.
171+
- `p=model.p` : ``J_E`` and ``\mathbf{g_c}`` functions parameter ``\mathbf{p}`` (any type).
168172
- `optim=JuMP.Model(Ipopt.Optimizer)` : nonlinear optimizer used in the predictive
169173
controller, provided as a [`JuMP.Model`](https://jump.dev/JuMP.jl/stable/api/JuMP/#JuMP.Model)
170174
(default to [`Ipopt`](https://github.com/jump-dev/Ipopt.jl) optimizer).
@@ -193,22 +197,24 @@ NonLinMPC controller with a sample time Ts = 10.0 s, Ipopt optimizer, UnscentedK
193197
algebra instead of a `for` loop. This feature can accelerate the optimization, especially
194198
for the constraint handling, and is not available in any other package, to my knowledge.
195199
196-
The J
197-
198-
1. **Non-mutating functions** (out-of-place): define them as `f(x, u, d, p) -> ẋ` and
199-
`h(x, d, p) -> y`. This syntax is simple and intuitive but it allocates more memory.
200-
2. **Mutating functions** (in-place): define them as `f!(ẋ, x, u, d, p) -> nothing` and
201-
`h!(y, x, d, p) -> nothing`. This syntax reduces the allocations and potentially the
202-
computational burden as well.
203-
204-
205200
The optimization relies on [`JuMP`](https://github.com/jump-dev/JuMP.jl) automatic
206201
differentiation (AD) to compute the objective and constraint derivatives. Optimizers
207202
generally benefit from exact derivatives like AD. However, the [`NonLinModel`](@ref)
208203
state-space functions must be compatible with this feature. See [Automatic differentiation](https://jump.dev/JuMP.jl/stable/manual/nlp/#Automatic-differentiation)
209204
for common mistakes when writing these functions.
210205
211-
Note that if `Cwt≠Inf`, the attribute `nlp_scaling_max_gradient` of `Ipopt` is set to
206+
If `LHS` represents the result of the left-hand side in the inequality
207+
``\mathbf{g_c}(\mathbf{U_e}, \mathbf{Ŷ_e}, \mathbf{D̂_e}, \mathbf{p}, ϵ) ≤ \mathbf{0}``,
208+
the function `gc` can be implemented in two ways:
209+
210+
1. **Non-mutating function** (out-of-place): define it as `gc(Ue, Ŷe, D̂e, p, ϵ) -> LHS`.
211+
This syntax is simple and intuitive but it allocates more memory.
212+
2. **Mutating function** (in-place): define it as `gc!(LHS, Ue, Ŷe, D̂e, p, ϵ) -> nothing`.
213+
This syntax reduces the allocations and potentially the computational burden as well.
214+
215+
The keyword argument `nc` is the number of elements in the `LHS` vector, and `gc!`, an
216+
alias for the `gc` argument (both accepts non-mutating and mutating functions). Note
217+
that if `Cwt≠Inf`, the attribute `nlp_scaling_max_gradient` of `Ipopt` is set to
212218
`10/Cwt` (if not already set), to scale the small values of ``ϵ``.
213219
"""
214220
function NonLinMPC(
@@ -224,16 +230,17 @@ function NonLinMPC(
224230
Cwt = DEFAULT_CWT,
225231
Ewt = DEFAULT_EWT,
226232
JE::Function = (_,_,_,_) -> 0.0,
227-
gE::Function = (_,_,_,_,_,_) -> nothing,
228-
nE = 0,
233+
gc!::Function = (_,_,_,_,_,_) -> nothing,
234+
gc ::Function = gc!,
235+
nc::Int = 0,
229236
p = model.p,
230237
optim::JuMP.GenericModel = JuMP.Model(DEFAULT_NONLINMPC_OPTIMIZER, add_bridges=false),
231238
kwargs...
232239
)
233240
estim = UnscentedKalmanFilter(model; kwargs...)
234241
return NonLinMPC(
235242
estim;
236-
Hp, Hc, Mwt, Nwt, Lwt, Cwt, Ewt, JE, gE, nE, p, M_Hp, N_Hc, L_Hp, optim
243+
Hp, Hc, Mwt, Nwt, Lwt, Cwt, Ewt, JE, gc, nc, p, M_Hp, N_Hc, L_Hp, optim
237244
)
238245
end
239246

@@ -249,17 +256,18 @@ function NonLinMPC(
249256
L_Hp = diagm(repeat(Lwt, Hp)),
250257
Cwt = DEFAULT_CWT,
251258
Ewt = DEFAULT_EWT,
252-
JE::Function = (_,_,_,_) -> 0.0,
253-
gE::Function = (_,_,_,_,_,_) -> nothing,
254-
nE = 0,
259+
JE ::Function = (_,_,_,_) -> 0.0,
260+
gc!::Function = (_,_,_,_,_,_) -> nothing,
261+
gc ::Function = gc!,
262+
nc::Int = 0,
255263
p = model.p,
256264
optim::JuMP.GenericModel = JuMP.Model(DEFAULT_NONLINMPC_OPTIMIZER, add_bridges=false),
257265
kwargs...
258266
)
259267
estim = SteadyKalmanFilter(model; kwargs...)
260268
return NonLinMPC(
261269
estim;
262-
Hp, Hc, Mwt, Nwt, Lwt, Cwt, Ewt, JE, gE, nE, p, M_Hp, N_Hc, L_Hp, optim
270+
Hp, Hc, Mwt, Nwt, Lwt, Cwt, Ewt, JE, gc, nc, p, M_Hp, N_Hc, L_Hp, optim
263271
)
264272
end
265273

@@ -299,17 +307,17 @@ function NonLinMPC(
299307
L_Hp = diagm(repeat(Lwt, Hp)),
300308
Cwt = DEFAULT_CWT,
301309
Ewt = DEFAULT_EWT,
302-
JE::JEfunc = (_,_,_,_) -> 0.0,
303-
gE::GEfunc = (_,_,_,_,_,_) -> nothing,
304-
nE = 0,
310+
JE ::JEfunc = (_,_,_,_) -> 0.0,
311+
gc!::Function = (_,_,_,_,_,_) -> nothing,
312+
gc ::Function = gc!,
313+
nc = 0,
305314
p::P = estim.model.p,
306315
optim::JM = JuMP.Model(DEFAULT_NONLINMPC_OPTIMIZER, add_bridges=false),
307316
) where {
308317
NT<:Real,
309318
SE<:StateEstimator{NT},
310319
JM<:JuMP.GenericModel,
311-
JEfunc<:Function,
312-
GEfunc<:Function,
320+
JEfunc<:Function,
313321
P<:Any
314322
}
315323
nk = estimate_delays(estim.model)
@@ -318,7 +326,7 @@ function NonLinMPC(
318326
"($nk), the closed-loop system may be unstable or zero-gain (unresponsive)")
319327
end
320328
return NonLinMPC{NT, SE, JM, JEfunc, P}(
321-
estim, Hp, Hc, M_Hp, N_Hc, L_Hp, Cwt, Ewt, JE, gE, nE, p, optim
329+
estim, Hp, Hc, M_Hp, N_Hc, L_Hp, Cwt, Ewt, JE, gc, nc, p, optim
322330
)
323331
end
324332

@@ -328,15 +336,54 @@ end
328336
Validate `JE` function argument signature.
329337
"""
330338
function validate_JE(NT, JE)
339+
# Ue, Ŷe, D̂e, p
331340
if !hasmethod(JE, Tuple{Vector{NT}, Vector{NT}, Vector{NT}, Any})
332341
error(
333-
"the economic function has no method with type signature "*
334-
"JE(UE::Vector{$(NT)}, ŶE::Vector{$(NT)}, D̂E::Vector{$(NT)}, p::Any)"
342+
"the economic cost function has no method with type signature "*
343+
"JE(Ue::Vector{$(NT)}, Ŷe::Vector{$(NT)}, D̂e::Vector{$(NT)}, p::Any)"
335344
)
336345
end
337346
return nothing
338347
end
339348

349+
"Get mutating custom constraint function `gc!` from the provided function in argument."
350+
function get_mutating_gc(NT, gc)
351+
ismutating_gc = validate_gc(NT, gc)
352+
gc! = if ismutating_gc
353+
gc
354+
else
355+
function gc!(LHS, Ue, Ŷe, D̂e, p, ϵ)
356+
LHS .= gc(Ue, Ŷe, D̂e, p, ϵ)
357+
return nothing
358+
end
359+
end
360+
return gc!
361+
end
362+
363+
"""
364+
validate_gc(NT, gc) -> ismutating
365+
366+
Validate `gc` function argument signature and return `true` if it is mutating.
367+
"""
368+
function validate_gc(NT, gc)
369+
ismutating = hasmethod(
370+
gc,
371+
# LHS, Ue, Ŷe, D̂e, p, ϵ
372+
Tuple{Vector{NT}, Vector{NT}, Vector{NT}, Vector{NT}, Any, NT}
373+
)
374+
println(ismutating)
375+
# Ue, Ŷe, D̂e, p, ϵ
376+
if !(ismutating || hasmethod(gc, Tuple{Vector{NT}, Vector{NT}, Vector{NT}, Any, NT}))
377+
error(
378+
"the custom constraint function has no method with type signature "*
379+
"gc(UE::Vector{$(NT)}, ŶE::Vector{$(NT)}, D̂E::Vector{$(NT)}, p::Any, ϵ::$(NT)) "*
380+
"or mutating form gc!(LHS::Vector{$(NT)}, Ue::Vector{$(NT)}, Ŷe::Vector{$(NT)}, "*
381+
"D̂e::Vector{$(NT)}, p::Any, ϵ::$(NT))"
382+
)
383+
end
384+
return ismutating
385+
end
386+
340387
"""
341388
addinfo!(info, mpc::NonLinMPC) -> info
342389

src/model/nonlinmodel.jl

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -143,10 +143,7 @@ function NonLinModel{NT}(
143143
p=NT[], solver=RungeKutta(4)
144144
) where {NT<:Real}
145145
isnothing(solver) && (solver=EmptySolver())
146-
ismutating_f = validate_f(NT, f)
147-
ismutating_h = validate_h(NT, h)
148-
f! = ismutating_f ? f : f!(xnext, x, u, d, p) = (xnext .= f(x, u, d, p); nothing)
149-
h! = ismutating_h ? h : h!(y, x, d, p) = (y .= h(x, d, p); nothing)
146+
f!, h! = get_mutating_functions(NT, f, h)
150147
f!, h! = get_solver_functions(NT, solver, f!, h!, Ts, nu, nx, ny, nd)
151148
F, H, P, DS = get_types(f!, h!, p, solver)
152149
return NonLinModel{NT, F, H, P, DS}(f!, h!, Ts, nu, nx, ny, nd, p, solver)
@@ -159,6 +156,29 @@ function NonLinModel(
159156
return NonLinModel{Float64}(f, h, Ts, nu, nx, ny, nd; p, solver)
160157
end
161158

159+
"Get the mutating functions `f!` and `h!` from the provided functions in argument."
160+
function get_mutating_functions(NT, f, h)
161+
ismutating_f = validate_f(NT, f)
162+
f! = if ismutating_f
163+
f
164+
else
165+
function f!(xnext, x, u, d, p)
166+
xnext .= f(x, u, d, p)
167+
return nothing
168+
end
169+
end
170+
ismutating_h = validate_h(NT, h)
171+
h! = if ismutating_h
172+
h
173+
else
174+
function h!(y, x, d, p)
175+
y .= h(x, d, p)
176+
return nothing
177+
end
178+
end
179+
return f!, h!
180+
end
181+
162182
"Get the types of `f!`, `h!` and `solver` to construct a `NonLinModel`."
163183
function get_types(
164184
::F, ::H, ::P, ::DS
@@ -172,7 +192,12 @@ end
172192
Validate `f` function argument signature and return `true` if it is mutating.
173193
"""
174194
function validate_f(NT, f)
175-
ismutating = hasmethod(f, Tuple{Vector{NT}, Vector{NT}, Vector{NT}, Vector{NT}, Any})
195+
ismutating = hasmethod(
196+
f,
197+
# ẋ/xnext, x, u, d, p
198+
Tuple{ Vector{NT}, Vector{NT}, Vector{NT}, Vector{NT}, Any}
199+
)
200+
# x, u, d, p
176201
if !(ismutating || hasmethod(f, Tuple{Vector{NT}, Vector{NT}, Vector{NT}, Any}))
177202
error(
178203
"the state function has no method with type signature "*
@@ -190,7 +215,12 @@ end
190215
Validate `h` function argument signature and return `true` if it is mutating.
191216
"""
192217
function validate_h(NT, h)
193-
ismutating = hasmethod(h, Tuple{Vector{NT}, Vector{NT}, Vector{NT}, Any})
218+
ismutating = hasmethod(
219+
h,
220+
# y, x, d, p
221+
Tuple{Vector{NT}, Vector{NT}, Vector{NT}, Any}
222+
)
223+
# x, d, p
194224
if !(ismutating || hasmethod(h, Tuple{Vector{NT}, Vector{NT}, Any}))
195225
error(
196226
"the output function has no method with type signature "*

0 commit comments

Comments
 (0)