Skip to content

Commit fe935e7

Browse files
authored
Merge pull request #187 from JuliaControl/test_alloc
Test: added allocations tests for types that are known to be allocation-free (SKIP THEM FOR NOW)
2 parents a8b8c9b + a412fcf commit fe935e7

File tree

5 files changed

+127
-64
lines changed

5 files changed

+127
-64
lines changed

.github/workflows/CI.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ jobs:
1717
permissions: # needed for julia-actions/cache delete old caches that it has created
1818
actions: write
1919
contents: read
20-
continue-on-error: ${{ matrix.version == 'nightly' }}
20+
continue-on-error: ${{ matrix.version == 'nightly' || matrix.version == 'pre' }}
2121
strategy:
2222
fail-fast: false
2323
matrix:

src/model/linearization.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,8 @@ julia> linearize!(linmodel, model, x=[20.0], u=[0.0]); linmodel.A
155155
```
156156
"""
157157
function linearize!(
158-
linmodel::LinModel{NT}, model::SimModel; x=model.x0+model.xop, u=model.uop, d=model.dop
158+
linmodel::LinModel{NT}, model::SimModel;
159+
x=(model.buffer.x.=model.x0.+model.xop), u=model.uop, d=model.dop
159160
) where NT<:Real
160161
nonlinmodel = model
161162
buffer = nonlinmodel.buffer

test/1_test_sim_model.jl

Lines changed: 41 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -100,11 +100,14 @@ end
100100
@testitem "LinModel sim methods" setup=[SetupMPCtests] begin
101101
using .SetupMPCtests, ControlSystemsBase
102102
linmodel1 = setop!(LinModel(Gss), uop=[10,50], yop=[50,30])
103-
@test updatestate!(linmodel1, [10, 50]) zeros(2)
104-
@test updatestate!(linmodel1, [10, 50], Float64[]) zeros(2)
103+
u, d = [10, 50], Float64[]
104+
@test updatestate!(linmodel1, u) zeros(2)
105+
@test updatestate!(linmodel1, u, d) zeros(2)
106+
@test_skip @allocations(updatestate!(linmodel1, u)) == 0
105107
@test linmodel1.x0 zeros(2)
106108
@test evaloutput(linmodel1) linmodel1() [50,30]
107109
@test evaloutput(linmodel1, Float64[]) linmodel1(Float64[]) [50,30]
110+
@test_skip @allocations(evaloutput(linmodel1)) == 0
108111
x = initstate!(linmodel1, [10, 60])
109112
@test evaloutput(linmodel1) [50 + 19.0, 30 + 7.4]
110113
@test preparestate!(linmodel1) x # new method
@@ -155,9 +158,9 @@ end
155158
using DifferentiationInterface
156159
import FiniteDiff
157160
linmodel1 = LinModel(sys,Ts,i_u=[1,2])
158-
f1(x,u,_,model) = model.A*x + model.Bu*u
159-
h1(x,_,model) = model.C*x
160-
nonlinmodel1 = NonLinModel(f1,h1,Ts,2,2,2,solver=nothing,p=linmodel1)
161+
f1!(x,u,_,model) = model.A*x + model.Bu*u
162+
h1!(x,_,model) = model.C*x
163+
nonlinmodel1 = NonLinModel(f1!,h1!,Ts,2,2,2,solver=nothing,p=linmodel1)
161164
@test nonlinmodel1.nx == 2
162165
@test nonlinmodel1.nu == 2
163166
@test nonlinmodel1.nd == 0
@@ -265,15 +268,21 @@ end
265268
@testitem "NonLinModel sim methods" setup=[SetupMPCtests] begin
266269
using .SetupMPCtests, ControlSystemsBase, LinearAlgebra
267270
linmodel1 = LinModel(sys,Ts,i_u=[1,2])
268-
f1(x,u,_,model) = model.A*x + model.Bu*u
269-
h1(x,_,model) = model.C*x
270-
nonlinmodel = NonLinModel(f1,h1,Ts,2,2,2,p=linmodel1,solver=nothing)
271+
function f1!(xnext, x, u, _ , model)
272+
mul!(xnext, model.A, x)
273+
mul!(xnext, model.Bu, u, 1, 1)
274+
end
275+
h1!(y, x , _ , model) = mul!(y, model.C, x)
276+
nonlinmodel = NonLinModel(f1!,h1!,Ts,2,2,2,p=linmodel1,solver=nothing)
271277

272-
@test updatestate!(nonlinmodel, zeros(2,)) zeros(2)
273-
@test updatestate!(nonlinmodel, zeros(2,), Float64[]) zeros(2)
278+
u, d = zeros(2), Float64[]
279+
@test updatestate!(nonlinmodel, u) zeros(2)
280+
@test updatestate!(nonlinmodel, u, d) zeros(2)
281+
@test_skip @allocations(updatestate!(nonlinmodel, u)) == 0
274282
@test nonlinmodel.x0 zeros(2)
275283
@test evaloutput(nonlinmodel) nonlinmodel() zeros(2)
276-
@test evaloutput(nonlinmodel, Float64[]) nonlinmodel(Float64[]) zeros(2)
284+
@test evaloutput(nonlinmodel, d) nonlinmodel(Float64[]) zeros(2)
285+
@test_skip @allocations(evaloutput(nonlinmodel)) == 0
277286

278287
x = initstate!(nonlinmodel, [0, 10]) # do nothing for NonLinModel
279288
@test evaloutput(nonlinmodel) [0, 0]
@@ -287,9 +296,9 @@ end
287296
using DifferentiationInterface
288297
import ForwardDiff, FiniteDiff
289298
Ts = 1.0
290-
f1(x,u,d,_) = x.^5 .+ u.^4 .+ d.^3
291-
h1(x,d,_) = x.^2 .+ d
292-
nonlinmodel1 = NonLinModel(f1,h1,Ts,1,1,1,1,solver=nothing)
299+
f1!(x,u,d,_) = x.^5 .+ u.^4 .+ d.^3
300+
h1!(x,d,_) = x.^2 .+ d
301+
nonlinmodel1 = NonLinModel(f1!,h1!,Ts,1,1,1,1,solver=nothing)
293302
x, u, d = [2.0], [3.0], [4.0]
294303
linmodel1 = linearize(nonlinmodel1; x, u, d)
295304
@test linmodel1.A 5*x.^4
@@ -302,9 +311,9 @@ end
302311
@test linmodel1.Bu linmodel1b.Bu
303312
@test linmodel1.Bd linmodel1b.Bd
304313
@test linmodel1.C linmodel1b.C
305-
@test linmodel1.Dd linmodel1b.Dd
314+
@test linmodel1.Dd linmodel1b.Dd
306315

307-
nonlinmodel2 = NonLinModel(f1,h1,Ts,1,1,1,1,solver=nothing, jacobian=AutoFiniteDiff())
316+
nonlinmodel2 = NonLinModel(f1!,h1!,Ts,1,1,1,1,solver=nothing, jacobian=AutoFiniteDiff())
308317
linmodel2 = linearize(nonlinmodel2; x, u, d)
309318
@test linmodel2.A 5*x.^4 atol=1e-3
310319
@test linmodel2.Bu 4*u.^3 atol=1e-3
@@ -334,7 +343,7 @@ end
334343
@test linmodel3.Bd Bd
335344
@test linmodel3.C C
336345
@test linmodel3.Dd Dd
337-
346+
338347
# test `linearize` at a non-equilibrium point:
339348
Ynl, Yl = let nonlinmodel3=nonlinmodel3
340349
N = 5
@@ -348,18 +357,32 @@ end
348357
yl = linmodel3(d)
349358
Ynl[i] = ynl[1]
350359
Yl[i] = yl[1]
351-
linmodel3 = linearize(nonlinmodel3; u, d)
360+
linearize!(linmodel3, nonlinmodel3; u, d)
352361
updatestate!(nonlinmodel3, u, d)
353362
updatestate!(linmodel3, u, d)
354363
end
355364
Ynl, Yl
356365
end
357366
@test all(isapprox.(Ynl, Yl, atol=1e-6))
358367

368+
# test nd==0 also works with AutoFiniteDiff (does not support empty matrices):
359369
f2!(xnext, x, u, _, _) = (xnext .= x .+ u)
360370
h2!(y, x, _, _) = (y .= x)
361371
nonlinmodel4 = NonLinModel(f2!,h2!,Ts,1,1,1,0,solver=nothing,jacobian=AutoFiniteDiff())
362372
@test_nowarn linearize(nonlinmodel4, x=[1], u=[2])
373+
374+
function f3!(xnext, x, u, d, _)
375+
xnext .= x.*u .+ x.*d
376+
end
377+
function h3!(y, x, d, _)
378+
y .= x.*d
379+
end
380+
nonlinmodel4 = NonLinModel(f3!, h3!, Ts, 1, 1, 1, 1, solver=nothing)
381+
linmodel4 = linearize(nonlinmodel4; x, u, d)
382+
# return nothing (see this issue : https://github.com/JuliaLang/julia/issues/51112):
383+
linearize2!(linmodel, model) = (linearize!(linmodel, model); nothing)
384+
linearize2!(linmodel4, nonlinmodel4)
385+
@test_skip @allocations(linearize2!(linmodel4, nonlinmodel4)) == 0
363386
end
364387

365388
@testitem "NonLinModel real time simulations" setup=[SetupMPCtests] begin

test/2_test_state_estim.jl

Lines changed: 80 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -65,14 +65,18 @@ end
6565
using .SetupMPCtests, ControlSystemsBase, LinearAlgebra
6666
linmodel1 = setop!(LinModel(sys,Ts,i_u=[1,2]), uop=[10,50], yop=[50,30])
6767
skalmanfilter1 = SteadyKalmanFilter(linmodel1, nint_ym=[1, 1])
68-
preparestate!(skalmanfilter1, [50, 30])
69-
@test updatestate!(skalmanfilter1, [10, 50], [50, 30]) zeros(4)
70-
preparestate!(skalmanfilter1, [50, 30])
71-
@test updatestate!(skalmanfilter1, [10, 50], [50, 30], Float64[]) zeros(4)
68+
u, y, d = [10, 50], [50, 30], Float64[]
69+
preparestate!(skalmanfilter1, y)
70+
@test updatestate!(skalmanfilter1, u, y) zeros(4)
71+
preparestate!(skalmanfilter1, y)
72+
@test updatestate!(skalmanfilter1, u, y, d) zeros(4)
7273
@test skalmanfilter1.x̂0 zeros(4)
73-
preparestate!(skalmanfilter1, [50, 30])
74+
@test_skip @allocations(preparestate!(skalmanfilter1, y)) == 0
75+
@test_skip @allocations(updatestate!(skalmanfilter1, u, y)) == 0
76+
preparestate!(skalmanfilter1, y)
7477
@test evaloutput(skalmanfilter1) skalmanfilter1() [50, 30]
75-
@test evaloutput(skalmanfilter1, Float64[]) skalmanfilter1(Float64[]) [50, 30]
78+
@test evaloutput(skalmanfilter1, d) skalmanfilter1(d) [50, 30]
79+
@test_skip @allocations(evaloutput(skalmanfilter1, d)) == 0
7680
@test initstate!(skalmanfilter1, [10, 50], [50, 30+1]) [zeros(3); [1]]
7781
linmodel2 = LinModel(append(tf(1, [1, 0]), tf(2, [10, 1])), 1.0)
7882
skalmanfilter2 = SteadyKalmanFilter(linmodel2, nint_u=[1, 1], direct=false)
@@ -194,14 +198,18 @@ end
194198
using .SetupMPCtests, ControlSystemsBase, LinearAlgebra
195199
linmodel1 = setop!(LinModel(sys,Ts,i_u=[1,2]), uop=[10,50], yop=[50,30])
196200
kalmanfilter1 = KalmanFilter(linmodel1)
197-
preparestate!(kalmanfilter1, [50, 30])
198-
@test updatestate!(kalmanfilter1, [10, 50], [50, 30]) zeros(4)
199-
preparestate!(kalmanfilter1, [50, 30])
200-
@test updatestate!(kalmanfilter1, [10, 50], [50, 30], Float64[]) zeros(4)
201+
u, y, d = [10, 50], [50, 30], Float64[]
202+
preparestate!(kalmanfilter1, y)
203+
@test updatestate!(kalmanfilter1, u, y) zeros(4)
204+
preparestate!(kalmanfilter1, y)
205+
@test updatestate!(kalmanfilter1, u, y, d) zeros(4)
201206
@test kalmanfilter1.x̂0 zeros(4)
202-
preparestate!(kalmanfilter1, [50, 30])
207+
@test_skip @allocations(preparestate!(kalmanfilter1, y)) == 0
208+
@test_skip @allocations(updatestate!(kalmanfilter1, u, y)) == 0
209+
preparestate!(kalmanfilter1, y)
203210
@test evaloutput(kalmanfilter1) kalmanfilter1() [50, 30]
204-
@test evaloutput(kalmanfilter1, Float64[]) kalmanfilter1(Float64[]) [50, 30]
211+
@test evaloutput(kalmanfilter1, d) kalmanfilter1(d) [50, 30]
212+
@test_skip @allocations(evaloutput(kalmanfilter1, d)) == 0
205213
@test initstate!(kalmanfilter1, [10, 50], [50, 30+1]) [zeros(3); [1]]
206214
setstate!(kalmanfilter1, [1,2,3,4])
207215
@test kalmanfilter1.x̂0 [1,2,3,4]
@@ -311,14 +319,18 @@ end
311319
using .SetupMPCtests, ControlSystemsBase, LinearAlgebra
312320
linmodel1 = setop!(LinModel(sys,Ts,i_u=[1,2]), uop=[10,50], yop=[50,30])
313321
lo1 = Luenberger(linmodel1, nint_ym=[1, 1])
314-
preparestate!(lo1, [50, 30])
315-
@test updatestate!(lo1, [10, 50], [50, 30]) zeros(4)
316-
preparestate!(lo1, [50, 30])
317-
@test updatestate!(lo1, [10, 50], [50, 30], Float64[]) zeros(4)
322+
u, y, d = [10, 50], [50, 30], Float64[]
323+
preparestate!(lo1, y)
324+
@test updatestate!(lo1, u, y) zeros(4)
325+
preparestate!(lo1, y)
326+
@test updatestate!(lo1, u, y, d) zeros(4)
318327
@test lo1.x̂0 zeros(4)
319-
preparestate!(lo1, [50, 30])
328+
@test_skip @allocations(preparestate!(lo1, y)) == 0
329+
@test_skip @allocations(updatestate!(lo1, u, y)) == 0
330+
preparestate!(lo1, y)
320331
@test evaloutput(lo1) lo1() [50, 30]
321-
@test evaloutput(lo1, Float64[]) lo1(Float64[]) [50, 30]
332+
@test evaloutput(lo1, d) lo1(d) [50, 30]
333+
@test_skip @allocations(evaloutput(lo1, d)) == 0
322334
@test initstate!(lo1, [10, 50], [50, 30+1]) [zeros(3); [1]]
323335
setstate!(lo1, [1,2,3,4])
324336
@test lo1.x̂0 [1,2,3,4]
@@ -436,14 +448,18 @@ end
436448
using .SetupMPCtests, ControlSystemsBase, LinearAlgebra
437449
linmodel1 = setop!(LinModel(sys,Ts,i_u=[1,2]) , uop=[10,50], yop=[50,30])
438450
internalmodel1 = InternalModel(linmodel1)
439-
preparestate!(internalmodel1, [50, 30] .+ 1)
440-
@test updatestate!(internalmodel1, [10, 50], [50, 30] .+ 1) zeros(2)
441-
preparestate!(internalmodel1, [50, 30] .+ 1)
442-
@test updatestate!(internalmodel1, [10, 50], [50, 30] .+ 1, Float64[]) zeros(2)
451+
u, y, d = [10, 50], [50, 30] .+ 1, Float64[]
452+
preparestate!(internalmodel1, y)
453+
@test updatestate!(internalmodel1, u, y) zeros(2)
454+
preparestate!(internalmodel1, y)
455+
@test updatestate!(internalmodel1, u, y, d) zeros(2)
443456
@test internalmodel1.x̂d internalmodel1.x̂0 zeros(2)
444457
@test internalmodel1.x̂s ones(2)
445-
preparestate!(internalmodel1, [51, 31])
446-
@test evaloutput(internalmodel1, Float64[]) [51,31]
458+
@test_skip @allocations(preparestate!(internalmodel1, y)) == 0
459+
@test_skip @allocations(updatestate!(internalmodel1, u, y)) == 0
460+
preparestate!(internalmodel1, y)
461+
@test evaloutput(internalmodel1, d) [51,31]
462+
@test_skip @allocations(evaloutput(internalmodel1, d)) == 0
447463
@test initstate!(internalmodel1, [10, 50], [50, 30]) zeros(2)
448464
@test internalmodel1.x̂s zeros(2)
449465
setstate!(internalmodel1, [1,2])
@@ -557,19 +573,30 @@ end
557573
@testitem "UnscentedKalmanFilter estimator methods" setup=[SetupMPCtests] begin
558574
using .SetupMPCtests, ControlSystemsBase, LinearAlgebra
559575
linmodel1 = LinModel(sys,Ts,i_u=[1,2])
560-
f(x,u,_,model) = model.A*x + model.Bu*u
561-
h(x,_,model) = model.C*x
562-
nonlinmodel = NonLinModel(f, h, Ts, 2, 2, 2, solver=nothing, p=linmodel1)
576+
function f!(xnext, x,u,_,model)
577+
mul!(xnext, model.A, x)
578+
mul!(xnext, model.Bu, u, 1, 1)
579+
return nothing
580+
end
581+
function h!(y, x,_,model)
582+
mul!(y, model.C, x)
583+
return nothing
584+
end
585+
nonlinmodel = NonLinModel(f!, h!, Ts, 2, 2, 2, solver=nothing, p=linmodel1)
563586
nonlinmodel = setop!(nonlinmodel, uop=[10,50], yop=[50,30])
564587
ukf1 = UnscentedKalmanFilter(nonlinmodel)
565-
preparestate!(ukf1, [50, 30])
566-
@test updatestate!(ukf1, [10, 50], [50, 30]) zeros(4) atol=1e-9
567-
preparestate!(ukf1, [50, 30])
568-
@test updatestate!(ukf1, [10, 50], [50, 30], Float64[]) zeros(4) atol=1e-9
588+
u, y, d = [10, 50], [50, 30], Float64[]
589+
preparestate!(ukf1, y)
590+
@test updatestate!(ukf1, u, y) zeros(4) atol=1e-9
591+
preparestate!(ukf1, y)
592+
@test updatestate!(ukf1, u, y, d) zeros(4) atol=1e-9
569593
@test ukf1.x̂0 zeros(4) atol=1e-9
570-
preparestate!(ukf1, [50, 30])
594+
@test_skip @allocations(preparestate!(ukf1, y)) == 0
595+
@test_skip @allocations(updatestate!(ukf1, u, y)) == 0
596+
preparestate!(ukf1, y)
571597
@test evaloutput(ukf1) ukf1() [50, 30]
572-
@test evaloutput(ukf1, Float64[]) ukf1(Float64[]) [50, 30]
598+
@test evaloutput(ukf1, d) ukf1(d) [50, 30]
599+
@test_skip @allocations(evaloutput(ukf1, d)) == 0
573600
@test initstate!(ukf1, [10, 50], [50, 30+1]) zeros(4) atol=1e-9
574601
setstate!(ukf1, [1,2,3,4])
575602
@test ukf1.x̂0 [1,2,3,4]
@@ -705,19 +732,30 @@ end
705732
using DifferentiationInterface
706733
import FiniteDiff
707734
linmodel1 = LinModel(sys,Ts,i_u=[1,2])
708-
f(x,u,_,model) = model.A*x + model.Bu*u
709-
h(x,_,model) = model.C*x
710-
nonlinmodel = NonLinModel(f, h, Ts, 2, 2, 2, solver=nothing, p=linmodel1)
735+
function f!(xnext, x,u,_,model)
736+
mul!(xnext, model.A, x)
737+
mul!(xnext, model.Bu, u, 1, 1)
738+
return nothing
739+
end
740+
function h!(y, x,_,model)
741+
mul!(y, model.C, x)
742+
return nothing
743+
end
744+
nonlinmodel = NonLinModel(f!, h!, Ts, 2, 2, 2, solver=nothing, p=linmodel1)
711745
nonlinmodel = setop!(nonlinmodel, uop=[10,50], yop=[50,30])
712746
ekf1 = ExtendedKalmanFilter(nonlinmodel)
713-
preparestate!(ekf1, [50, 30])
714-
@test updatestate!(ekf1, [10, 50], [50, 30]) zeros(4) atol=1e-9
715-
preparestate!(ekf1, [50, 30])
716-
@test updatestate!(ekf1, [10, 50], [50, 30], Float64[]) zeros(4) atol=1e-9
747+
u, y, d = [10, 50], [50, 30], Float64[]
748+
preparestate!(ekf1, y)
749+
@test updatestate!(ekf1, u, y) zeros(4) atol=1e-9
750+
preparestate!(ekf1, y)
751+
@test updatestate!(ekf1, u, y, d) zeros(4) atol=1e-9
717752
@test ekf1.x̂0 zeros(4) atol=1e-9
718-
preparestate!(ekf1, [50, 30])
753+
@test_skip @allocations(preparestate!(ekf1, y)) == 0
754+
@test_skip @allocations(updatestate!(ekf1, u, y)) == 0
755+
preparestate!(ekf1, y)
719756
@test evaloutput(ekf1) ekf1() [50, 30]
720-
@test evaloutput(ekf1, Float64[]) ekf1(Float64[]) [50, 30]
757+
@test evaloutput(ekf1, d) ekf1(d) [50, 30]
758+
@test_skip @allocations(evaloutput(ekf1, d)) == 0
721759
@test initstate!(ekf1, [10, 50], [50, 30+1]) zeros(4);
722760
setstate!(ekf1, [1,2,3,4])
723761
@test ekf1.x̂0 [1,2,3,4]

test/3_test_predictive_control.jl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -425,12 +425,13 @@ end
425425
@testitem "ExplicitMPC moves and getinfo" setup=[SetupMPCtests] begin
426426
using .SetupMPCtests, ControlSystemsBase, LinearAlgebra
427427
mpc1 = ExplicitMPC(LinModel(tf(5, [2, 1]), 3), Nwt=[0], Hp=1000, Hc=1)
428-
r = [5]
429-
preparestate!(mpc1, [0])
428+
r, y = [5], [0]
429+
preparestate!(mpc1, y)
430430
u = moveinput!(mpc1, r)
431431
@test u [1] atol=1e-2
432432
u = mpc1(r)
433433
@test u [1] atol=1e-2
434+
@test_skip @allocations(moveinput!(mpc1, r)) == 0
434435
info = getinfo(mpc1)
435436
@test info[:u] u
436437
@test info[:Ŷ][end] r[1] atol=1e-2

0 commit comments

Comments
 (0)