|
| 1 | +@testset "parameters_array" begin |
| 2 | + @testset "postive" begin |
| 3 | + @testset "$val" for val in [[5.0, 4.0], [0.001f0], fill(1e-7, 1, 2)] |
| 4 | + p = positive(val) |
| 5 | + test_parameter_interface(p) |
| 6 | + @test value(p) ≈ val |
| 7 | + @test typeof(value(p)) === typeof(val) |
| 8 | + end |
| 9 | + |
| 10 | + # Test edge cases around the size of the value relative to the error tol. |
| 11 | + @test_throws ArgumentError positive([-0.1, 0.1]) |
| 12 | + @test_throws ArgumentError positive(fill(1e-12, 1, 2, 3)) |
| 13 | + @test value(positive(fill(1e-11, 3, 2, 1), exp, 1e-12)) ≈ fill(1e-11, 3, 2, 1) |
| 14 | + |
| 15 | + # These tests assume that if the number of allocations is roughly constant in the |
| 16 | + # size of `x`, then performance is acceptable. This is demonstrated by requiring |
| 17 | + # that the number of allocations (100) is a lot smaller than the total length of |
| 18 | + # the array in question (1_000_000). The bound (100) is quite loose because there |
| 19 | + # are typically serveral 10s of allocations made by Zygote for book-keeping |
| 20 | + # purposes etc. |
| 21 | + @testset "zygote performance" begin |
| 22 | + x = rand(1000, 1000) .+ 0.1 |
| 23 | + flat_x, unflatten = value_flatten(positive(x)) |
| 24 | + |
| 25 | + # primal evaluation |
| 26 | + count_allocs(unflatten, flat_x) |
| 27 | + @test count_allocs(unflatten, flat_x) < 100 |
| 28 | + |
| 29 | + # forward evaluation |
| 30 | + count_allocs(Zygote.pullback, unflatten, flat_x) |
| 31 | + @test count_allocs(Zygote.pullback, unflatten, flat_x) < 100 |
| 32 | + |
| 33 | + # pullback |
| 34 | + out, pb = Zygote.pullback(unflatten, flat_x) |
| 35 | + count_allocs(pb, out) |
| 36 | + @test count_allocs(pb, out) < 100 |
| 37 | + end |
| 38 | + |
| 39 | + # Check that this optimisation is actually necessary -- i.e. that the performance |
| 40 | + # of the equivalent operation, `map(positive, x)`, is indeed poor, esp. with AD. |
| 41 | + # Poor performance is demonstrated by showing that there's at least one allocation |
| 42 | + # per element. A smaller array than the previous test set is used because it can |
| 43 | + # be _really_ slow for large arrays (several seconds), which is undesirable in |
| 44 | + # unit tests. |
| 45 | + @testset "zygote performance of scalar equivalent" begin |
| 46 | + x = rand(1000) .+ 0.1 |
| 47 | + flat_x, unflatten = value_flatten(map(positive, x)) |
| 48 | + |
| 49 | + # forward evaluation |
| 50 | + count_allocs(Zygote.pullback, unflatten, flat_x) |
| 51 | + count_allocs(Zygote.pullback, unflatten, flat_x) > 1000 |
| 52 | + end |
| 53 | + end |
| 54 | +end |
0 commit comments