From ea743a31f05f1eb5c1e7d30151d4ced9d54b6dbe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Apr 2023 11:06:56 +0200 Subject: [PATCH 1/5] Bump actions/cache from 1 to 3 (#643) Bumps [actions/cache](https://github.com/actions/cache) from 1 to 3. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/v1...v3) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a7536455..7a6dd8c5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,7 +32,7 @@ jobs: with: version: ${{ matrix.version }} arch: ${{ matrix.arch }} - - uses: actions/cache@v1 + - uses: actions/cache@v3 env: cache-name: cache-artifacts with: From 4447f47b9810357ee18cecd974dd5c93e389a62b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20M=C3=BCller-Widmann?= Date: Tue, 9 Sep 2025 14:47:54 +0000 Subject: [PATCH 2/5] Fix tests by using tag types instead of instances (#768) --- test/DualTest.jl | 304 +++++++++++++++++++++++------------------------ test/MiscTest.jl | 2 +- 2 files changed, 153 insertions(+), 153 deletions(-) diff --git a/test/DualTest.jl b/test/DualTest.jl index 786d3bda..3bba824b 100644 --- a/test/DualTest.jl +++ b/test/DualTest.jl @@ -25,8 +25,8 @@ dual_isapprox(a, b) = isapprox(a, b) dual_isapprox(a::Dual{T,T1,T2}, b::Dual{T,T3,T4}) where {T,T1,T2,T3,T4} = isapprox(value(a), value(b)) && isapprox(partials(a), partials(b)) dual_isapprox(a::Dual{T,T1,T2}, b::Dual{T3,T4,T5}) where {T,T1,T2,T3,T4,T5} = error("Tags don't match") -ForwardDiff.:≺(::Type{TestTag()}, ::Int) = true -ForwardDiff.:≺(::Int, ::Type{TestTag()}) = false +ForwardDiff.:≺(::Type{TestTag}, ::Int) = true +ForwardDiff.:≺(::Int, ::Type{TestTag}) = false ForwardDiff.:≺(::Type{TestTag}, ::Type{OuterTestTag}) = true ForwardDiff.:≺(::Type{OuterTestTag}, ::Type{TestTag}) = false @@ -34,36 +34,36 @@ ForwardDiff.:≺(::Type{OuterTestTag}, ::Type{TestTag}) = false PARTIALS = Partials{N,V}(ntuple(n -> intrand(V), N)) PRIMAL = intrand(V) - FDNUM = Dual{TestTag()}(PRIMAL, PARTIALS) + FDNUM = Dual{TestTag}(PRIMAL, PARTIALS) PARTIALS2 = Partials{N,V}(ntuple(n -> intrand(V), N)) PRIMAL2 = intrand(V) - FDNUM2 = Dual{TestTag()}(PRIMAL2, PARTIALS2) + FDNUM2 = Dual{TestTag}(PRIMAL2, PARTIALS2) PARTIALS3 = Partials{N,V}(ntuple(n -> intrand(V), N)) PRIMAL3 = intrand(V) - FDNUM3 = Dual{TestTag()}(PRIMAL3, PARTIALS3) + FDNUM3 = Dual{TestTag}(PRIMAL3, PARTIALS3) M_PARTIALS = Partials{M,V}(ntuple(m -> intrand(V), M)) - NESTED_PARTIALS = convert(Partials{N,Dual{TestTag(),V,M}}, PARTIALS) - NESTED_FDNUM = Dual{TestTag()}(Dual{TestTag()}(PRIMAL, M_PARTIALS), NESTED_PARTIALS) + NESTED_PARTIALS = convert(Partials{N,Dual{TestTag,V,M}}, PARTIALS) + NESTED_FDNUM = Dual{TestTag}(Dual{TestTag}(PRIMAL, M_PARTIALS), NESTED_PARTIALS) M_PARTIALS2 = Partials{M,V}(ntuple(m -> intrand(V), M)) - NESTED_PARTIALS2 = convert(Partials{N,Dual{TestTag(),V,M}}, PARTIALS2) - NESTED_FDNUM2 = Dual{TestTag()}(Dual{TestTag()}(PRIMAL2, M_PARTIALS2), NESTED_PARTIALS2) + NESTED_PARTIALS2 = convert(Partials{N,Dual{TestTag,V,M}}, PARTIALS2) + NESTED_FDNUM2 = Dual{TestTag}(Dual{TestTag}(PRIMAL2, M_PARTIALS2), NESTED_PARTIALS2) ################ # Constructors # ################ - @test Dual{TestTag()}(PRIMAL, PARTIALS...) === FDNUM + @test Dual{TestTag}(PRIMAL, PARTIALS...) === FDNUM @test Dual(PRIMAL, PARTIALS...) === Dual{Nothing}(PRIMAL, PARTIALS...) @test Dual(PRIMAL) === Dual{Nothing}(PRIMAL) - @test typeof(Dual{TestTag()}(widen(V)(PRIMAL), PARTIALS)) === Dual{TestTag(),widen(V),N} - @test typeof(Dual{TestTag()}(widen(V)(PRIMAL), PARTIALS.values)) === Dual{TestTag(),widen(V),N} - @test typeof(Dual{TestTag()}(widen(V)(PRIMAL), PARTIALS...)) === Dual{TestTag(),widen(V),N} - @test typeof(NESTED_FDNUM) == Dual{TestTag(),Dual{TestTag(),V,M},N} + @test typeof(Dual{TestTag}(widen(V)(PRIMAL), PARTIALS)) === Dual{TestTag,widen(V),N} + @test typeof(Dual{TestTag}(widen(V)(PRIMAL), PARTIALS.values)) === Dual{TestTag,widen(V),N} + @test typeof(Dual{TestTag}(widen(V)(PRIMAL), PARTIALS...)) === Dual{TestTag,widen(V),N} + @test typeof(NESTED_FDNUM) == Dual{TestTag,Dual{TestTag,V,M},N} ############# # Accessors # @@ -71,7 +71,7 @@ ForwardDiff.:≺(::Type{OuterTestTag}, ::Type{TestTag}) = false @test value(PRIMAL) == PRIMAL @test value(FDNUM) == PRIMAL - @test value(NESTED_FDNUM) === Dual{TestTag()}(PRIMAL, M_PARTIALS) + @test value(NESTED_FDNUM) === Dual{TestTag}(PRIMAL, M_PARTIALS) @test partials(PRIMAL) == Partials{0,V}(tuple()) @test partials(FDNUM) == PARTIALS @@ -91,8 +91,8 @@ ForwardDiff.:≺(::Type{OuterTestTag}, ::Type{TestTag}) = false @test ForwardDiff.valtype(FDNUM) == V @test ForwardDiff.valtype(typeof(FDNUM)) == V - @test ForwardDiff.valtype(NESTED_FDNUM) == Dual{TestTag(),V,M} - @test ForwardDiff.valtype(typeof(NESTED_FDNUM)) == Dual{TestTag(),V,M} + @test ForwardDiff.valtype(NESTED_FDNUM) == Dual{TestTag,V,M} + @test ForwardDiff.valtype(typeof(NESTED_FDNUM)) == Dual{TestTag,V,M} ##################### # Generic Functions # @@ -176,7 +176,7 @@ ForwardDiff.:≺(::Type{OuterTestTag}, ::Type{TestTag}) = false end @test Base.rtoldefault(typeof(FDNUM)) ≡ Base.rtoldefault(typeof(PRIMAL)) - @test Dual{TestTag()}(PRIMAL-eps(V), PARTIALS) ≈ FDNUM + @test Dual{TestTag}(PRIMAL-eps(V), PARTIALS) ≈ FDNUM @test Base.rtoldefault(typeof(NESTED_FDNUM)) ≡ Base.rtoldefault(typeof(PRIMAL)) end @@ -199,28 +199,28 @@ ForwardDiff.:≺(::Type{OuterTestTag}, ::Type{TestTag}) = false @test read(TMPIO, typeof(NESTED_FDNUM)) === NESTED_FDNUM close(TMPIO) - @test zero(FDNUM) === Dual{TestTag()}(zero(PRIMAL), zero(PARTIALS)) - @test zero(typeof(FDNUM)) === Dual{TestTag()}(zero(V), zero(Partials{N,V})) - @test zero(NESTED_FDNUM) === Dual{TestTag()}(Dual{TestTag()}(zero(PRIMAL), zero(M_PARTIALS)), zero(NESTED_PARTIALS)) - @test zero(typeof(NESTED_FDNUM)) === Dual{TestTag()}(Dual{TestTag()}(zero(V), zero(Partials{M,V})), zero(Partials{N,Dual{TestTag(),V,M}})) + @test zero(FDNUM) === Dual{TestTag}(zero(PRIMAL), zero(PARTIALS)) + @test zero(typeof(FDNUM)) === Dual{TestTag}(zero(V), zero(Partials{N,V})) + @test zero(NESTED_FDNUM) === Dual{TestTag}(Dual{TestTag}(zero(PRIMAL), zero(M_PARTIALS)), zero(NESTED_PARTIALS)) + @test zero(typeof(NESTED_FDNUM)) === Dual{TestTag}(Dual{TestTag}(zero(V), zero(Partials{M,V})), zero(Partials{N,Dual{TestTag,V,M}})) - @test one(FDNUM) === Dual{TestTag()}(one(PRIMAL), zero(PARTIALS)) - @test one(typeof(FDNUM)) === Dual{TestTag()}(one(V), zero(Partials{N,V})) - @test one(NESTED_FDNUM) === Dual{TestTag()}(Dual{TestTag()}(one(PRIMAL), zero(M_PARTIALS)), zero(NESTED_PARTIALS)) - @test one(typeof(NESTED_FDNUM)) === Dual{TestTag()}(Dual{TestTag()}(one(V), zero(Partials{M,V})), zero(Partials{N,Dual{TestTag(),V,M}})) + @test one(FDNUM) === Dual{TestTag}(one(PRIMAL), zero(PARTIALS)) + @test one(typeof(FDNUM)) === Dual{TestTag}(one(V), zero(Partials{N,V})) + @test one(NESTED_FDNUM) === Dual{TestTag}(Dual{TestTag}(one(PRIMAL), zero(M_PARTIALS)), zero(NESTED_PARTIALS)) + @test one(typeof(NESTED_FDNUM)) === Dual{TestTag}(Dual{TestTag}(one(V), zero(Partials{M,V})), zero(Partials{N,Dual{TestTag,V,M}})) if V <: Integer @test rand(samerng(), FDNUM) == rand(samerng(), value(FDNUM)) @test rand(samerng(), NESTED_FDNUM) == rand(samerng(), value(NESTED_FDNUM)) elseif V <: AbstractFloat - @test rand(samerng(), typeof(FDNUM)) === Dual{TestTag()}(rand(samerng(), V), zero(Partials{N,V})) - @test rand(samerng(), typeof(NESTED_FDNUM)) === Dual{TestTag()}(Dual{TestTag()}(rand(samerng(), V), zero(Partials{M,V})), zero(Partials{N,Dual{TestTag(),V,M}})) - @test randn(samerng(), typeof(FDNUM)) === Dual{TestTag()}(randn(samerng(), V), zero(Partials{N,V})) - @test randn(samerng(), typeof(NESTED_FDNUM)) === Dual{TestTag()}(Dual{TestTag()}(randn(samerng(), V), zero(Partials{M,V})), - zero(Partials{N,Dual{TestTag(),V,M}})) - @test randexp(samerng(), typeof(FDNUM)) === Dual{TestTag()}(randexp(samerng(), V), zero(Partials{N,V})) - @test randexp(samerng(), typeof(NESTED_FDNUM)) === Dual{TestTag()}(Dual{TestTag()}(randexp(samerng(), V), zero(Partials{M,V})), - zero(Partials{N,Dual{TestTag(),V,M}})) + @test rand(samerng(), typeof(FDNUM)) === Dual{TestTag}(rand(samerng(), V), zero(Partials{N,V})) + @test rand(samerng(), typeof(NESTED_FDNUM)) === Dual{TestTag}(Dual{TestTag}(rand(samerng(), V), zero(Partials{M,V})), zero(Partials{N,Dual{TestTag,V,M}})) + @test randn(samerng(), typeof(FDNUM)) === Dual{TestTag}(randn(samerng(), V), zero(Partials{N,V})) + @test randn(samerng(), typeof(NESTED_FDNUM)) === Dual{TestTag}(Dual{TestTag}(randn(samerng(), V), zero(Partials{M,V})), + zero(Partials{N,Dual{TestTag,V,M}})) + @test randexp(samerng(), typeof(FDNUM)) === Dual{TestTag}(randexp(samerng(), V), zero(Partials{N,V})) + @test randexp(samerng(), typeof(NESTED_FDNUM)) === Dual{TestTag}(Dual{TestTag}(randexp(samerng(), V), zero(Partials{M,V})), + zero(Partials{N,Dual{TestTag,V,M}})) end # Predicates # @@ -234,94 +234,94 @@ ForwardDiff.:≺(::Type{OuterTestTag}, ::Type{TestTag}) = false @test ForwardDiff.isconstant(one(NESTED_FDNUM)) @test ForwardDiff.isconstant(NESTED_FDNUM) == (N == 0) - @test isequal(FDNUM, Dual{TestTag()}(PRIMAL, PARTIALS2)) + @test isequal(FDNUM, Dual{TestTag}(PRIMAL, PARTIALS2)) @test isequal(PRIMAL, PRIMAL2) == isequal(FDNUM, FDNUM2) - @test isequal(NESTED_FDNUM, Dual{TestTag()}(Dual{TestTag()}(PRIMAL, M_PARTIALS2), NESTED_PARTIALS2)) + @test isequal(NESTED_FDNUM, Dual{TestTag}(Dual{TestTag}(PRIMAL, M_PARTIALS2), NESTED_PARTIALS2)) @test isequal(PRIMAL, PRIMAL2) == isequal(NESTED_FDNUM, NESTED_FDNUM2) - @test FDNUM == Dual{TestTag()}(PRIMAL, PARTIALS2) + @test FDNUM == Dual{TestTag}(PRIMAL, PARTIALS2) @test (PRIMAL == PRIMAL2) == (FDNUM == FDNUM2) @test (PRIMAL == PRIMAL2) == (NESTED_FDNUM == NESTED_FDNUM2) - @test isless(Dual{TestTag()}(1, PARTIALS), Dual{TestTag()}(2, PARTIALS2)) - @test !(isless(Dual{TestTag()}(1, PARTIALS), Dual{TestTag()}(1, PARTIALS2))) - @test !(isless(Dual{TestTag()}(2, PARTIALS), Dual{TestTag()}(1, PARTIALS2))) + @test isless(Dual{TestTag}(1, PARTIALS), Dual{TestTag}(2, PARTIALS2)) + @test !(isless(Dual{TestTag}(1, PARTIALS), Dual{TestTag}(1, PARTIALS2))) + @test !(isless(Dual{TestTag}(2, PARTIALS), Dual{TestTag}(1, PARTIALS2))) - @test isless(Dual{TestTag()}(Dual{TestTag()}(1, M_PARTIALS), NESTED_PARTIALS), Dual{TestTag()}(Dual{TestTag()}(2, M_PARTIALS2), NESTED_PARTIALS2)) - @test !(isless(Dual{TestTag()}(Dual{TestTag()}(1, M_PARTIALS), NESTED_PARTIALS), Dual{TestTag()}(Dual{TestTag()}(1, M_PARTIALS2), NESTED_PARTIALS2))) - @test !(isless(Dual{TestTag()}(Dual{TestTag()}(2, M_PARTIALS), NESTED_PARTIALS), Dual{TestTag()}(Dual{TestTag()}(1, M_PARTIALS2), NESTED_PARTIALS2))) + @test isless(Dual{TestTag}(Dual{TestTag}(1, M_PARTIALS), NESTED_PARTIALS), Dual{TestTag}(Dual{TestTag}(2, M_PARTIALS2), NESTED_PARTIALS2)) + @test !(isless(Dual{TestTag}(Dual{TestTag}(1, M_PARTIALS), NESTED_PARTIALS), Dual{TestTag}(Dual{TestTag}(1, M_PARTIALS2), NESTED_PARTIALS2))) + @test !(isless(Dual{TestTag}(Dual{TestTag}(2, M_PARTIALS), NESTED_PARTIALS), Dual{TestTag}(Dual{TestTag}(1, M_PARTIALS2), NESTED_PARTIALS2))) - @test Dual{TestTag()}(1, PARTIALS) < Dual{TestTag()}(2, PARTIALS2) - @test !(Dual{TestTag()}(1, PARTIALS) < Dual{TestTag()}(1, PARTIALS2)) - @test !(Dual{TestTag()}(2, PARTIALS) < Dual{TestTag()}(1, PARTIALS2)) + @test Dual{TestTag}(1, PARTIALS) < Dual{TestTag}(2, PARTIALS2) + @test !(Dual{TestTag}(1, PARTIALS) < Dual{TestTag}(1, PARTIALS2)) + @test !(Dual{TestTag}(2, PARTIALS) < Dual{TestTag}(1, PARTIALS2)) - @test Dual{TestTag()}(Dual{TestTag()}(1, M_PARTIALS), NESTED_PARTIALS) < Dual{TestTag()}(Dual{TestTag()}(2, M_PARTIALS2), NESTED_PARTIALS2) - @test !(Dual{TestTag()}(Dual{TestTag()}(1, M_PARTIALS), NESTED_PARTIALS) < Dual{TestTag()}(Dual{TestTag()}(1, M_PARTIALS2), NESTED_PARTIALS2)) - @test !(Dual{TestTag()}(Dual{TestTag()}(2, M_PARTIALS), NESTED_PARTIALS) < Dual{TestTag()}(Dual{TestTag()}(1, M_PARTIALS2), NESTED_PARTIALS2)) + @test Dual{TestTag}(Dual{TestTag}(1, M_PARTIALS), NESTED_PARTIALS) < Dual{TestTag}(Dual{TestTag}(2, M_PARTIALS2), NESTED_PARTIALS2) + @test !(Dual{TestTag}(Dual{TestTag}(1, M_PARTIALS), NESTED_PARTIALS) < Dual{TestTag}(Dual{TestTag}(1, M_PARTIALS2), NESTED_PARTIALS2)) + @test !(Dual{TestTag}(Dual{TestTag}(2, M_PARTIALS), NESTED_PARTIALS) < Dual{TestTag}(Dual{TestTag}(1, M_PARTIALS2), NESTED_PARTIALS2)) - @test Dual{TestTag()}(1, PARTIALS) <= Dual{TestTag()}(2, PARTIALS2) - @test Dual{TestTag()}(1, PARTIALS) <= Dual{TestTag()}(1, PARTIALS2) - @test !(Dual{TestTag()}(2, PARTIALS) <= Dual{TestTag()}(1, PARTIALS2)) + @test Dual{TestTag}(1, PARTIALS) <= Dual{TestTag}(2, PARTIALS2) + @test Dual{TestTag}(1, PARTIALS) <= Dual{TestTag}(1, PARTIALS2) + @test !(Dual{TestTag}(2, PARTIALS) <= Dual{TestTag}(1, PARTIALS2)) - @test Dual{TestTag()}(Dual{TestTag()}(1, M_PARTIALS), NESTED_PARTIALS) <= Dual{TestTag()}(Dual{TestTag()}(2, M_PARTIALS2), NESTED_PARTIALS2) - @test Dual{TestTag()}(Dual{TestTag()}(1, M_PARTIALS), NESTED_PARTIALS) <= Dual{TestTag()}(Dual{TestTag()}(1, M_PARTIALS2), NESTED_PARTIALS2) - @test !(Dual{TestTag()}(Dual{TestTag()}(2, M_PARTIALS), NESTED_PARTIALS) <= Dual{TestTag()}(Dual{TestTag()}(1, M_PARTIALS2), NESTED_PARTIALS2)) + @test Dual{TestTag}(Dual{TestTag}(1, M_PARTIALS), NESTED_PARTIALS) <= Dual{TestTag}(Dual{TestTag}(2, M_PARTIALS2), NESTED_PARTIALS2) + @test Dual{TestTag}(Dual{TestTag}(1, M_PARTIALS), NESTED_PARTIALS) <= Dual{TestTag}(Dual{TestTag}(1, M_PARTIALS2), NESTED_PARTIALS2) + @test !(Dual{TestTag}(Dual{TestTag}(2, M_PARTIALS), NESTED_PARTIALS) <= Dual{TestTag}(Dual{TestTag}(1, M_PARTIALS2), NESTED_PARTIALS2)) - @test Dual{TestTag()}(2, PARTIALS) > Dual{TestTag()}(1, PARTIALS2) - @test !(Dual{TestTag()}(1, PARTIALS) > Dual{TestTag()}(1, PARTIALS2)) - @test !(Dual{TestTag()}(1, PARTIALS) > Dual{TestTag()}(2, PARTIALS2)) + @test Dual{TestTag}(2, PARTIALS) > Dual{TestTag}(1, PARTIALS2) + @test !(Dual{TestTag}(1, PARTIALS) > Dual{TestTag}(1, PARTIALS2)) + @test !(Dual{TestTag}(1, PARTIALS) > Dual{TestTag}(2, PARTIALS2)) - @test Dual{TestTag()}(Dual{TestTag()}(2, M_PARTIALS), NESTED_PARTIALS) > Dual{TestTag()}(Dual{TestTag()}(1, M_PARTIALS2), NESTED_PARTIALS2) - @test !(Dual{TestTag()}(Dual{TestTag()}(1, M_PARTIALS), NESTED_PARTIALS) > Dual{TestTag()}(Dual{TestTag()}(1, M_PARTIALS2), NESTED_PARTIALS2)) - @test !(Dual{TestTag()}(Dual{TestTag()}(1, M_PARTIALS), NESTED_PARTIALS) > Dual{TestTag()}(Dual{TestTag()}(2, M_PARTIALS2), NESTED_PARTIALS2)) + @test Dual{TestTag}(Dual{TestTag}(2, M_PARTIALS), NESTED_PARTIALS) > Dual{TestTag}(Dual{TestTag}(1, M_PARTIALS2), NESTED_PARTIALS2) + @test !(Dual{TestTag}(Dual{TestTag}(1, M_PARTIALS), NESTED_PARTIALS) > Dual{TestTag}(Dual{TestTag}(1, M_PARTIALS2), NESTED_PARTIALS2)) + @test !(Dual{TestTag}(Dual{TestTag}(1, M_PARTIALS), NESTED_PARTIALS) > Dual{TestTag}(Dual{TestTag}(2, M_PARTIALS2), NESTED_PARTIALS2)) - @test Dual{TestTag()}(2, PARTIALS) >= Dual{TestTag()}(1, PARTIALS2) - @test Dual{TestTag()}(1, PARTIALS) >= Dual{TestTag()}(1, PARTIALS2) - @test !(Dual{TestTag()}(1, PARTIALS) >= Dual{TestTag()}(2, PARTIALS2)) + @test Dual{TestTag}(2, PARTIALS) >= Dual{TestTag}(1, PARTIALS2) + @test Dual{TestTag}(1, PARTIALS) >= Dual{TestTag}(1, PARTIALS2) + @test !(Dual{TestTag}(1, PARTIALS) >= Dual{TestTag}(2, PARTIALS2)) - @test Dual{TestTag()}(Dual{TestTag()}(2, M_PARTIALS), NESTED_PARTIALS) >= Dual{TestTag()}(Dual{TestTag()}(1, M_PARTIALS2), NESTED_PARTIALS2) - @test Dual{TestTag()}(Dual{TestTag()}(1, M_PARTIALS), NESTED_PARTIALS) >= Dual{TestTag()}(Dual{TestTag()}(1, M_PARTIALS2), NESTED_PARTIALS2) - @test !(Dual{TestTag()}(Dual{TestTag()}(1, M_PARTIALS), NESTED_PARTIALS) >= Dual{TestTag()}(Dual{TestTag()}(2, M_PARTIALS2), NESTED_PARTIALS2)) + @test Dual{TestTag}(Dual{TestTag}(2, M_PARTIALS), NESTED_PARTIALS) >= Dual{TestTag}(Dual{TestTag}(1, M_PARTIALS2), NESTED_PARTIALS2) + @test Dual{TestTag}(Dual{TestTag}(1, M_PARTIALS), NESTED_PARTIALS) >= Dual{TestTag}(Dual{TestTag}(1, M_PARTIALS2), NESTED_PARTIALS2) + @test !(Dual{TestTag}(Dual{TestTag}(1, M_PARTIALS), NESTED_PARTIALS) >= Dual{TestTag}(Dual{TestTag}(2, M_PARTIALS2), NESTED_PARTIALS2)) - @test isnan(Dual{TestTag()}(NaN, PARTIALS)) + @test isnan(Dual{TestTag}(NaN, PARTIALS)) @test !(isnan(FDNUM)) - @test isnan(Dual{TestTag()}(Dual{TestTag()}(NaN, M_PARTIALS), NESTED_PARTIALS)) + @test isnan(Dual{TestTag}(Dual{TestTag}(NaN, M_PARTIALS), NESTED_PARTIALS)) @test !(isnan(NESTED_FDNUM)) @test isfinite(FDNUM) - @test !(isfinite(Dual{TestTag()}(Inf, PARTIALS))) + @test !(isfinite(Dual{TestTag}(Inf, PARTIALS))) @test isfinite(NESTED_FDNUM) - @test !(isfinite(Dual{TestTag()}(Dual{TestTag()}(NaN, M_PARTIALS), NESTED_PARTIALS))) + @test !(isfinite(Dual{TestTag}(Dual{TestTag}(NaN, M_PARTIALS), NESTED_PARTIALS))) - @test isinf(Dual{TestTag()}(Inf, PARTIALS)) + @test isinf(Dual{TestTag}(Inf, PARTIALS)) @test !(isinf(FDNUM)) - @test isinf(Dual{TestTag()}(Dual{TestTag()}(Inf, M_PARTIALS), NESTED_PARTIALS)) + @test isinf(Dual{TestTag}(Dual{TestTag}(Inf, M_PARTIALS), NESTED_PARTIALS)) @test !(isinf(NESTED_FDNUM)) @test isreal(FDNUM) @test isreal(NESTED_FDNUM) - @test isinteger(Dual{TestTag()}(1.0, PARTIALS)) + @test isinteger(Dual{TestTag}(1.0, PARTIALS)) @test isinteger(FDNUM) == (V == Int) - @test isinteger(Dual{TestTag()}(Dual{TestTag()}(1.0, M_PARTIALS), NESTED_PARTIALS)) + @test isinteger(Dual{TestTag}(Dual{TestTag}(1.0, M_PARTIALS), NESTED_PARTIALS)) @test isinteger(NESTED_FDNUM) == (V == Int) - @test iseven(Dual{TestTag()}(2)) - @test !(iseven(Dual{TestTag()}(1))) + @test iseven(Dual{TestTag}(2)) + @test !(iseven(Dual{TestTag}(1))) - @test iseven(Dual{TestTag()}(Dual{TestTag()}(2))) - @test !(iseven(Dual{TestTag()}(Dual{TestTag()}(1)))) + @test iseven(Dual{TestTag}(Dual{TestTag}(2))) + @test !(iseven(Dual{TestTag}(Dual{TestTag}(1)))) - @test isodd(Dual{TestTag()}(1)) - @test !(isodd(Dual{TestTag()}(2))) + @test isodd(Dual{TestTag}(1)) + @test !(isodd(Dual{TestTag}(2))) - @test isodd(Dual{TestTag()}(Dual{TestTag()}(1))) - @test !(isodd(Dual{TestTag()}(Dual{TestTag()}(2)))) + @test isodd(Dual{TestTag}(Dual{TestTag}(1))) + @test !(isodd(Dual{TestTag}(Dual{TestTag}(2)))) ######################## # Promotion/Conversion # @@ -329,34 +329,34 @@ ForwardDiff.:≺(::Type{OuterTestTag}, ::Type{TestTag}) = false WIDE_T = widen(V) - @test promote_type(Dual{TestTag(),V,N}, V) == Dual{TestTag(),V,N} - @test promote_type(Dual{TestTag(),V,N}, WIDE_T) == Dual{TestTag(),WIDE_T,N} - @test promote_type(Dual{TestTag(),WIDE_T,N}, V) == Dual{TestTag(),WIDE_T,N} - @test promote_type(Dual{TestTag(),V,N}, Dual{TestTag(),V,N}) == Dual{TestTag(),V,N} - @test promote_type(Dual{TestTag(),V,N}, Dual{TestTag(),WIDE_T,N}) == Dual{TestTag(),WIDE_T,N} - @test promote_type(Dual{TestTag(),WIDE_T,N}, Dual{TestTag(),Dual{TestTag(),V,M},N}) == Dual{TestTag(),Dual{TestTag(),WIDE_T,M},N} + @test promote_type(Dual{TestTag,V,N}, V) == Dual{TestTag,V,N} + @test promote_type(Dual{TestTag,V,N}, WIDE_T) == Dual{TestTag,WIDE_T,N} + @test promote_type(Dual{TestTag,WIDE_T,N}, V) == Dual{TestTag,WIDE_T,N} + @test promote_type(Dual{TestTag,V,N}, Dual{TestTag,V,N}) == Dual{TestTag,V,N} + @test promote_type(Dual{TestTag,V,N}, Dual{TestTag,WIDE_T,N}) == Dual{TestTag,WIDE_T,N} + @test promote_type(Dual{TestTag,WIDE_T,N}, Dual{TestTag,Dual{TestTag,V,M},N}) == Dual{TestTag,Dual{TestTag,WIDE_T,M},N} # issue #322 - @test promote_type(Bool, Dual{TestTag(),V,N}) == Dual{TestTag(),promote_type(Bool, V),N} - @test promote_type(BigFloat, Dual{TestTag(),V,N}) == Dual{TestTag(),promote_type(BigFloat, V),N} + @test promote_type(Bool, Dual{TestTag,V,N}) == Dual{TestTag,promote_type(Bool, V),N} + @test promote_type(BigFloat, Dual{TestTag,V,N}) == Dual{TestTag,promote_type(BigFloat, V),N} - WIDE_FDNUM = convert(Dual{TestTag(),WIDE_T,N}, FDNUM) - WIDE_NESTED_FDNUM = convert(Dual{TestTag(),Dual{TestTag(),WIDE_T,M},N}, NESTED_FDNUM) + WIDE_FDNUM = convert(Dual{TestTag,WIDE_T,N}, FDNUM) + WIDE_NESTED_FDNUM = convert(Dual{TestTag,Dual{TestTag,WIDE_T,M},N}, NESTED_FDNUM) - @test typeof(WIDE_FDNUM) === Dual{TestTag(),WIDE_T,N} - @test typeof(WIDE_NESTED_FDNUM) === Dual{TestTag(),Dual{TestTag(),WIDE_T,M},N} + @test typeof(WIDE_FDNUM) === Dual{TestTag,WIDE_T,N} + @test typeof(WIDE_NESTED_FDNUM) === Dual{TestTag,Dual{TestTag,WIDE_T,M},N} @test value(WIDE_FDNUM) == PRIMAL @test value(WIDE_NESTED_FDNUM) == PRIMAL @test convert(Dual, FDNUM) === FDNUM @test convert(Dual, NESTED_FDNUM) === NESTED_FDNUM - @test convert(Dual{TestTag(),V,N}, FDNUM) === FDNUM - @test convert(Dual{TestTag(),Dual{TestTag(),V,M},N}, NESTED_FDNUM) === NESTED_FDNUM - @test convert(Dual{TestTag(),WIDE_T,N}, PRIMAL) === Dual{TestTag()}(WIDE_T(PRIMAL), zero(Partials{N,WIDE_T})) - @test convert(Dual{TestTag(),Dual{TestTag(),WIDE_T,M},N}, PRIMAL) === Dual{TestTag()}(Dual{TestTag()}(WIDE_T(PRIMAL), zero(Partials{M,WIDE_T})), zero(Partials{N,Dual{TestTag(),V,M}})) - @test convert(Dual{TestTag(),Dual{TestTag(),V,M},N}, FDNUM) === Dual{TestTag()}(convert(Dual{TestTag(),V,M}, PRIMAL), convert(Partials{N,Dual{TestTag(),V,M}}, PARTIALS)) - @test convert(Dual{TestTag(),Dual{TestTag(),WIDE_T,M},N}, FDNUM) === Dual{TestTag()}(convert(Dual{TestTag(),WIDE_T,M}, PRIMAL), convert(Partials{N,Dual{TestTag(),WIDE_T,M}}, PARTIALS)) + @test convert(Dual{TestTag,V,N}, FDNUM) === FDNUM + @test convert(Dual{TestTag,Dual{TestTag,V,M},N}, NESTED_FDNUM) === NESTED_FDNUM + @test convert(Dual{TestTag,WIDE_T,N}, PRIMAL) === Dual{TestTag}(WIDE_T(PRIMAL), zero(Partials{N,WIDE_T})) + @test convert(Dual{TestTag,Dual{TestTag,WIDE_T,M},N}, PRIMAL) === Dual{TestTag}(Dual{TestTag}(WIDE_T(PRIMAL), zero(Partials{M,WIDE_T})), zero(Partials{N,Dual{TestTag,V,M}})) + @test convert(Dual{TestTag,Dual{TestTag,V,M},N}, FDNUM) === Dual{TestTag}(convert(Dual{TestTag,V,M}, PRIMAL), convert(Partials{N,Dual{TestTag,V,M}}, PARTIALS)) + @test convert(Dual{TestTag,Dual{TestTag,WIDE_T,M},N}, FDNUM) === Dual{TestTag}(convert(Dual{TestTag,WIDE_T,M}, PRIMAL), convert(Partials{N,Dual{TestTag,WIDE_T,M}}, PARTIALS)) ############## # Arithmetic # @@ -365,34 +365,34 @@ ForwardDiff.:≺(::Type{OuterTestTag}, ::Type{TestTag}) = false # Addition/Subtraction # #----------------------# - @test FDNUM + FDNUM2 === Dual{TestTag()}(value(FDNUM) + value(FDNUM2), partials(FDNUM) + partials(FDNUM2)) - @test FDNUM + PRIMAL === Dual{TestTag()}(value(FDNUM) + PRIMAL, partials(FDNUM)) - @test PRIMAL + FDNUM === Dual{TestTag()}(value(FDNUM) + PRIMAL, partials(FDNUM)) + @test FDNUM + FDNUM2 === Dual{TestTag}(value(FDNUM) + value(FDNUM2), partials(FDNUM) + partials(FDNUM2)) + @test FDNUM + PRIMAL === Dual{TestTag}(value(FDNUM) + PRIMAL, partials(FDNUM)) + @test PRIMAL + FDNUM === Dual{TestTag}(value(FDNUM) + PRIMAL, partials(FDNUM)) - @test NESTED_FDNUM + NESTED_FDNUM2 === Dual{TestTag()}(value(NESTED_FDNUM) + value(NESTED_FDNUM2), partials(NESTED_FDNUM) + partials(NESTED_FDNUM2)) - @test NESTED_FDNUM + PRIMAL === Dual{TestTag()}(value(NESTED_FDNUM) + PRIMAL, partials(NESTED_FDNUM)) - @test PRIMAL + NESTED_FDNUM === Dual{TestTag()}(value(NESTED_FDNUM) + PRIMAL, partials(NESTED_FDNUM)) + @test NESTED_FDNUM + NESTED_FDNUM2 === Dual{TestTag}(value(NESTED_FDNUM) + value(NESTED_FDNUM2), partials(NESTED_FDNUM) + partials(NESTED_FDNUM2)) + @test NESTED_FDNUM + PRIMAL === Dual{TestTag}(value(NESTED_FDNUM) + PRIMAL, partials(NESTED_FDNUM)) + @test PRIMAL + NESTED_FDNUM === Dual{TestTag}(value(NESTED_FDNUM) + PRIMAL, partials(NESTED_FDNUM)) - @test FDNUM - FDNUM2 === Dual{TestTag()}(value(FDNUM) - value(FDNUM2), partials(FDNUM) - partials(FDNUM2)) - @test FDNUM - PRIMAL === Dual{TestTag()}(value(FDNUM) - PRIMAL, partials(FDNUM)) - @test PRIMAL - FDNUM === Dual{TestTag()}(PRIMAL - value(FDNUM), -(partials(FDNUM))) - @test -(FDNUM) === Dual{TestTag()}(-(value(FDNUM)), -(partials(FDNUM))) + @test FDNUM - FDNUM2 === Dual{TestTag}(value(FDNUM) - value(FDNUM2), partials(FDNUM) - partials(FDNUM2)) + @test FDNUM - PRIMAL === Dual{TestTag}(value(FDNUM) - PRIMAL, partials(FDNUM)) + @test PRIMAL - FDNUM === Dual{TestTag}(PRIMAL - value(FDNUM), -(partials(FDNUM))) + @test -(FDNUM) === Dual{TestTag}(-(value(FDNUM)), -(partials(FDNUM))) - @test NESTED_FDNUM - NESTED_FDNUM2 === Dual{TestTag()}(value(NESTED_FDNUM) - value(NESTED_FDNUM2), partials(NESTED_FDNUM) - partials(NESTED_FDNUM2)) - @test NESTED_FDNUM - PRIMAL === Dual{TestTag()}(value(NESTED_FDNUM) - PRIMAL, partials(NESTED_FDNUM)) - @test PRIMAL - NESTED_FDNUM === Dual{TestTag()}(PRIMAL - value(NESTED_FDNUM), -(partials(NESTED_FDNUM))) - @test -(NESTED_FDNUM) === Dual{TestTag()}(-(value(NESTED_FDNUM)), -(partials(NESTED_FDNUM))) + @test NESTED_FDNUM - NESTED_FDNUM2 === Dual{TestTag}(value(NESTED_FDNUM) - value(NESTED_FDNUM2), partials(NESTED_FDNUM) - partials(NESTED_FDNUM2)) + @test NESTED_FDNUM - PRIMAL === Dual{TestTag}(value(NESTED_FDNUM) - PRIMAL, partials(NESTED_FDNUM)) + @test PRIMAL - NESTED_FDNUM === Dual{TestTag}(PRIMAL - value(NESTED_FDNUM), -(partials(NESTED_FDNUM))) + @test -(NESTED_FDNUM) === Dual{TestTag}(-(value(NESTED_FDNUM)), -(partials(NESTED_FDNUM))) # Multiplication # #----------------# - @test FDNUM * FDNUM2 === Dual{TestTag()}(value(FDNUM) * value(FDNUM2), ForwardDiff._mul_partials(partials(FDNUM), partials(FDNUM2), value(FDNUM2), value(FDNUM))) - @test FDNUM * PRIMAL === Dual{TestTag()}(value(FDNUM) * PRIMAL, partials(FDNUM) * PRIMAL) - @test PRIMAL * FDNUM === Dual{TestTag()}(value(FDNUM) * PRIMAL, partials(FDNUM) * PRIMAL) + @test FDNUM * FDNUM2 === Dual{TestTag}(value(FDNUM) * value(FDNUM2), ForwardDiff._mul_partials(partials(FDNUM), partials(FDNUM2), value(FDNUM2), value(FDNUM))) + @test FDNUM * PRIMAL === Dual{TestTag}(value(FDNUM) * PRIMAL, partials(FDNUM) * PRIMAL) + @test PRIMAL * FDNUM === Dual{TestTag}(value(FDNUM) * PRIMAL, partials(FDNUM) * PRIMAL) - @test NESTED_FDNUM * NESTED_FDNUM2 === Dual{TestTag()}(value(NESTED_FDNUM) * value(NESTED_FDNUM2), ForwardDiff._mul_partials(partials(NESTED_FDNUM), partials(NESTED_FDNUM2), value(NESTED_FDNUM2), value(NESTED_FDNUM))) - @test NESTED_FDNUM * PRIMAL === Dual{TestTag()}(value(NESTED_FDNUM) * PRIMAL, partials(NESTED_FDNUM) * PRIMAL) - @test PRIMAL * NESTED_FDNUM === Dual{TestTag()}(value(NESTED_FDNUM) * PRIMAL, partials(NESTED_FDNUM) * PRIMAL) + @test NESTED_FDNUM * NESTED_FDNUM2 === Dual{TestTag}(value(NESTED_FDNUM) * value(NESTED_FDNUM2), ForwardDiff._mul_partials(partials(NESTED_FDNUM), partials(NESTED_FDNUM2), value(NESTED_FDNUM2), value(NESTED_FDNUM))) + @test NESTED_FDNUM * PRIMAL === Dual{TestTag}(value(NESTED_FDNUM) * PRIMAL, partials(NESTED_FDNUM) * PRIMAL) + @test PRIMAL * NESTED_FDNUM === Dual{TestTag}(value(NESTED_FDNUM) * PRIMAL, partials(NESTED_FDNUM) * PRIMAL) # Division # #----------# @@ -400,19 +400,19 @@ ForwardDiff.:≺(::Type{OuterTestTag}, ::Type{TestTag}) = false if M > 0 && N > 0 @test Dual{1}(FDNUM) / Dual{1}(PRIMAL) === Dual{1}(FDNUM / PRIMAL) @test Dual{1}(PRIMAL) / Dual{1}(FDNUM) === Dual{1}(PRIMAL / FDNUM) - @test_broken Dual{1}(FDNUM) / FDNUM2 === Dual{1}(FDNUM / FDNUM2) - @test_broken FDNUM / Dual{1}(FDNUM2) === Dual{1}(FDNUM / FDNUM2) + @test Dual{1}(FDNUM) / FDNUM2 === Dual{1}(FDNUM / FDNUM2) + @test FDNUM / Dual{1}(FDNUM2) === Dual{1}(FDNUM / FDNUM2) # following may not be exact, see #264 @test Dual{1}(FDNUM / PRIMAL, FDNUM2 / PRIMAL) ≈ Dual{1}(FDNUM, FDNUM2) / PRIMAL end - @test dual_isapprox(FDNUM / FDNUM2, Dual{TestTag()}(value(FDNUM) / value(FDNUM2), ForwardDiff._div_partials(partials(FDNUM), partials(FDNUM2), value(FDNUM), value(FDNUM2)))) - @test dual_isapprox(FDNUM / PRIMAL, Dual{TestTag()}(value(FDNUM) / PRIMAL, partials(FDNUM) / PRIMAL)) - @test dual_isapprox(PRIMAL / FDNUM, Dual{TestTag()}(PRIMAL / value(FDNUM), (-(PRIMAL) / value(FDNUM)^2) * partials(FDNUM))) + @test dual_isapprox(FDNUM / FDNUM2, Dual{TestTag}(value(FDNUM) / value(FDNUM2), ForwardDiff._div_partials(partials(FDNUM), partials(FDNUM2), value(FDNUM), value(FDNUM2)))) + @test dual_isapprox(FDNUM / PRIMAL, Dual{TestTag}(value(FDNUM) / PRIMAL, partials(FDNUM) / PRIMAL)) + @test dual_isapprox(PRIMAL / FDNUM, Dual{TestTag}(PRIMAL / value(FDNUM), (-(PRIMAL) / value(FDNUM)^2) * partials(FDNUM))) - @test dual_isapprox(NESTED_FDNUM / NESTED_FDNUM2, Dual{TestTag()}(value(NESTED_FDNUM) / value(NESTED_FDNUM2), ForwardDiff._div_partials(partials(NESTED_FDNUM), partials(NESTED_FDNUM2), value(NESTED_FDNUM), value(NESTED_FDNUM2)))) - @test dual_isapprox(NESTED_FDNUM / PRIMAL, Dual{TestTag()}(value(NESTED_FDNUM) / PRIMAL, partials(NESTED_FDNUM) / PRIMAL)) - @test dual_isapprox(PRIMAL / NESTED_FDNUM, Dual{TestTag()}(PRIMAL / value(NESTED_FDNUM), (-(PRIMAL) / value(NESTED_FDNUM)^2) * partials(NESTED_FDNUM))) + @test dual_isapprox(NESTED_FDNUM / NESTED_FDNUM2, Dual{TestTag}(value(NESTED_FDNUM) / value(NESTED_FDNUM2), ForwardDiff._div_partials(partials(NESTED_FDNUM), partials(NESTED_FDNUM2), value(NESTED_FDNUM), value(NESTED_FDNUM2)))) + @test dual_isapprox(NESTED_FDNUM / PRIMAL, Dual{TestTag}(value(NESTED_FDNUM) / PRIMAL, partials(NESTED_FDNUM) / PRIMAL)) + @test dual_isapprox(PRIMAL / NESTED_FDNUM, Dual{TestTag}(PRIMAL / value(NESTED_FDNUM), (-(PRIMAL) / value(NESTED_FDNUM)^2) * partials(NESTED_FDNUM))) # Exponentiation # #----------------# @@ -427,7 +427,7 @@ ForwardDiff.:≺(::Type{OuterTestTag}, ::Type{TestTag}) = false @test dual_isapprox(1.0 * NESTED_FDNUM^PRIMAL, exp(PRIMAL * log(NESTED_FDNUM))) @test dual_isapprox(1.0 * PRIMAL^NESTED_FDNUM, exp(NESTED_FDNUM * log(PRIMAL))) - @test partials(NaNMath.pow(Dual{TestTag()}(-2.0, 1.0), Dual{TestTag()}(2.0, 0.0)), 1) == -4.0 + @test partials(NaNMath.pow(Dual{TestTag}(-2.0, 1.0), Dual{TestTag}(2.0, 0.0)), 1) == -4.0 ################################### # General Mathematical Operations # @@ -462,15 +462,15 @@ ForwardDiff.:≺(::Type{OuterTestTag}, ::Type{TestTag}) = false end @eval begin x = rand() + $modifier - dx = @inferred $M.$f(Dual{TestTag()}(x, one(x))) + dx = @inferred $M.$f(Dual{TestTag}(x, one(x))) actualval = $M.$f(x) @assert actualval isa Real || actualval isa Complex if actualval isa Real - @test dx isa Dual{TestTag()} + @test dx isa Dual{TestTag} @test value(dx) == actualval @test partials(dx, 1) == $deriv else - @test dx isa Complex{<:Dual{TestTag()}} + @test dx isa Complex{<:Dual{TestTag}} @test value(real(dx)) == real(actualval) @test value(imag(dx)) == imag(actualval) @test partials(real(dx), 1) == real($deriv) @@ -488,22 +488,22 @@ ForwardDiff.:≺(::Type{OuterTestTag}, ::Type{TestTag}) = false end @eval begin x, y = $x, $y - dx = @inferred $M.$f(Dual{TestTag()}(x, one(x)), y) - dy = @inferred $M.$f(x, Dual{TestTag()}(y, one(y))) + dx = @inferred $M.$f(Dual{TestTag}(x, one(x)), y) + dy = @inferred $M.$f(x, Dual{TestTag}(y, one(y))) actualdx = $(derivs[1]) actualdy = $(derivs[2]) actualval = $M.$f(x, y) @assert actualval isa Real || actualval isa Complex if actualval isa Real - @test dx isa Dual{TestTag()} - @test dy isa Dual{TestTag()} + @test dx isa Dual{TestTag} + @test dy isa Dual{TestTag} @test value(dx) == actualval @test value(dy) == actualval @test partials(dx, 1) ≈ actualdx nans=true @test partials(dy, 1) ≈ actualdy nans=true else - @test dx isa Complex{<:Dual{TestTag()}} - @test dy isa Complex{<:Dual{TestTag()}} + @test dx isa Complex{<:Dual{TestTag}} + @test dy isa Complex{<:Dual{TestTag}} @test real(value(dx)) == real(actualval) @test real(value(dy)) == real(actualval) @test imag(value(dx)) == imag(actualval) @@ -521,8 +521,8 @@ ForwardDiff.:≺(::Type{OuterTestTag}, ::Type{TestTag}) = false # Special Cases # #---------------# - @test_broken dual_isapprox(hypot(FDNUM, FDNUM2, FDNUM), sqrt(2*(FDNUM^2) + FDNUM2^2)) - @test_broken dual_isapprox(hypot(FDNUM, FDNUM2, FDNUM3), sqrt(FDNUM^2 + FDNUM2^2 + FDNUM3^2)) + @test dual_isapprox(hypot(FDNUM, FDNUM2, FDNUM), sqrt(2*(FDNUM^2) + FDNUM2^2)) + @test dual_isapprox(hypot(FDNUM, FDNUM2, FDNUM3), sqrt(FDNUM^2 + FDNUM2^2 + FDNUM3^2)) @test all(map(dual_isapprox, ForwardDiff.sincos(FDNUM), (sin(FDNUM), cos(FDNUM)))) @@ -536,13 +536,13 @@ ForwardDiff.:≺(::Type{OuterTestTag}, ::Type{TestTag}) = false end for f in (fma, muladd) - @test dual_isapprox(f(FDNUM, FDNUM2, FDNUM3), Dual{TestTag()}(f(PRIMAL, PRIMAL2, PRIMAL3), PRIMAL*PARTIALS2 + PRIMAL2*PARTIALS + PARTIALS3)) - @test dual_isapprox(f(FDNUM, FDNUM2, PRIMAL3), Dual{TestTag()}(f(PRIMAL, PRIMAL2, PRIMAL3), PRIMAL*PARTIALS2 + PRIMAL2*PARTIALS)) - @test dual_isapprox(f(PRIMAL, FDNUM2, FDNUM3), Dual{TestTag()}(f(PRIMAL, PRIMAL2, PRIMAL3), PRIMAL*PARTIALS2 + PARTIALS3)) - @test dual_isapprox(f(PRIMAL, FDNUM2, PRIMAL3), Dual{TestTag()}(f(PRIMAL, PRIMAL2, PRIMAL3), PRIMAL*PARTIALS2)) - @test dual_isapprox(f(FDNUM, PRIMAL2, FDNUM3), Dual{TestTag()}(f(PRIMAL, PRIMAL2, PRIMAL3), PRIMAL2*PARTIALS + PARTIALS3)) - @test dual_isapprox(f(FDNUM, PRIMAL2, PRIMAL3), Dual{TestTag()}(f(PRIMAL, PRIMAL2, PRIMAL3), PRIMAL2*PARTIALS)) - @test dual_isapprox(f(PRIMAL, PRIMAL2, FDNUM3), Dual{TestTag()}(f(PRIMAL, PRIMAL2, PRIMAL3), PARTIALS3)) + @test dual_isapprox(f(FDNUM, FDNUM2, FDNUM3), Dual{TestTag}(f(PRIMAL, PRIMAL2, PRIMAL3), PRIMAL*PARTIALS2 + PRIMAL2*PARTIALS + PARTIALS3)) + @test dual_isapprox(f(FDNUM, FDNUM2, PRIMAL3), Dual{TestTag}(f(PRIMAL, PRIMAL2, PRIMAL3), PRIMAL*PARTIALS2 + PRIMAL2*PARTIALS)) + @test dual_isapprox(f(PRIMAL, FDNUM2, FDNUM3), Dual{TestTag}(f(PRIMAL, PRIMAL2, PRIMAL3), PRIMAL*PARTIALS2 + PARTIALS3)) + @test dual_isapprox(f(PRIMAL, FDNUM2, PRIMAL3), Dual{TestTag}(f(PRIMAL, PRIMAL2, PRIMAL3), PRIMAL*PARTIALS2)) + @test dual_isapprox(f(FDNUM, PRIMAL2, FDNUM3), Dual{TestTag}(f(PRIMAL, PRIMAL2, PRIMAL3), PRIMAL2*PARTIALS + PARTIALS3)) + @test dual_isapprox(f(FDNUM, PRIMAL2, PRIMAL3), Dual{TestTag}(f(PRIMAL, PRIMAL2, PRIMAL3), PRIMAL2*PARTIALS)) + @test dual_isapprox(f(PRIMAL, PRIMAL2, FDNUM3), Dual{TestTag}(f(PRIMAL, PRIMAL2, PRIMAL3), PARTIALS3)) end # Functions in Specialfunctions that return tuples and @@ -551,14 +551,14 @@ ForwardDiff.:≺(::Type{OuterTestTag}, ::Type{TestTag}) = false @test dual_isapprox(logabsgamma(FDNUM)[2], sign(gamma(FDNUM))) a = rand(float(V)) - fdnum = Dual{TestTag()}(1 + PRIMAL, PARTIALS) # 1 + PRIMAL avoids issues with finite differencing close to 0 + fdnum = Dual{TestTag}(1 + PRIMAL, PARTIALS) # 1 + PRIMAL avoids issues with finite differencing close to 0 for ind in ((), (0,), (1,), (2,)) # Only test if primal method exists # (e.g., older versions of SpecialFunctions don't define `gamma_inc(a, x)` but only `gamma_inc(a, x, ind)` hasmethod(gamma_inc, typeof((a, 1 + PRIMAL, ind...))) || continue pq = gamma_inc(a, fdnum, ind...) - @test pq isa Tuple{Dual{TestTag()},Dual{TestTag()}} + @test pq isa Tuple{Dual{TestTag},Dual{TestTag}} # We have to adjust tolerances if lower accuracy is requested # Therefore we don't use `dual_isapprox` tol = V === Float32 ? 5f-4 : 1e-6 @@ -579,8 +579,8 @@ end @test pow(x3, 2) === x3^2 === x3 * x3 @test pow(x2, 1) === x2^1 === x2 @test pow(x1, 0) === x1^0 === Dual{:t1}(1.0, 0.0) - y = Dual{typeof(TestTag())}(1.0, 0.0, 1.0); - x = Dual{typeof(OuterTestTag())}(0*y, 0*y); + y = Dual{TestTag}(1.0, 0.0, 1.0); + x = Dual{OuterTestTag}(0*y, 0*y); @test iszero(ForwardDiff.partials(ForwardDiff.partials(x^y)[1])) end diff --git a/test/MiscTest.jl b/test/MiscTest.jl index 96971560..a11bc59f 100644 --- a/test/MiscTest.jl +++ b/test/MiscTest.jl @@ -152,7 +152,7 @@ intrand(V) = V == Int ? rand(2:10) : rand(V) for N in (0,3), V in (Int, Float32), I in (Irrational, AbstractIrrational) PARTIALS = ForwardDiff.Partials{N,V}(ntuple(n -> intrand(V), N)) PRIMAL = intrand(V) - FDNUM = ForwardDiff.Dual{TestTag()}(PRIMAL, PARTIALS) + FDNUM = ForwardDiff.Dual{TestTag}(PRIMAL, PARTIALS) @test promote_rule(typeof(FDNUM), I) == promote_rule(I, typeof(FDNUM)) # π::Irrational, twoπ::AbstractIrrational From ac86cac57df22316af16f4cb0168e91f2e14aaa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20M=C3=BCller-Widmann?= Date: Fri, 12 Sep 2025 13:56:07 +0000 Subject: [PATCH 3/5] Fix gradient and Jacobian for functions with `Dual` output (#770) * Fix gradient and Jacobian for functions with `Dual` output * Bump version from 1.2.0 to 1.2.1 --- ext/ForwardDiffStaticArraysExt.jl | 6 +++--- src/dual.jl | 11 +++++++++++ src/gradient.jl | 4 ++-- src/jacobian.jl | 4 ++-- test/DualTest.jl | 15 +++++++++++++++ test/GradientTest.jl | 31 +++++++++++++++++++++++++++++++ test/JacobianTest.jl | 31 +++++++++++++++++++++++++++++++ 7 files changed, 95 insertions(+), 7 deletions(-) diff --git a/ext/ForwardDiffStaticArraysExt.jl b/ext/ForwardDiffStaticArraysExt.jl index 25b73fb8..615293fa 100644 --- a/ext/ForwardDiffStaticArraysExt.jl +++ b/ext/ForwardDiffStaticArraysExt.jl @@ -47,7 +47,7 @@ ForwardDiff._lyap_div!!(A::StaticArrays.MMatrix, λ::AbstractVector) = ForwardDi result = Expr(:tuple, [:(partials(T, y, $i)) for i in 1:length(x)]...) return quote $(Expr(:meta, :inline)) - V = StaticArrays.similar_type(S, valtype($y)) + V = StaticArrays.similar_type(S, valtype(T, $y)) return V($result) end end @@ -76,13 +76,13 @@ end result = Expr(:tuple, [:(partials(T, ydual[$i], $j)) for i in 1:M, j in 1:N]...) return quote $(Expr(:meta, :inline)) - V = StaticArrays.similar_type(S, valtype(eltype($ydual)), Size($M, $N)) + V = StaticArrays.similar_type(S, valtype(T, eltype($ydual)), Size($M, $N)) return V($result) end end function extract_jacobian(::Type{T}, ydual::AbstractArray, x::StaticArray) where T - result = similar(ydual, valtype(eltype(ydual)), length(ydual), length(x)) + result = similar(ydual, valtype(T, eltype(ydual)), length(ydual), length(x)) return extract_jacobian!(T, result, ydual, length(x)) end diff --git a/src/dual.jl b/src/dual.jl index 58390c5c..b7b83e0a 100644 --- a/src/dual.jl +++ b/src/dual.jl @@ -128,6 +128,17 @@ end @inline valtype(::Dual{T,V,N}) where {T,V,N} = V @inline valtype(::Type{Dual{T,V,N}}) where {T,V,N} = V +@inline valtype(::Type{T}, ::V) where {T,V} = valtype(T, V) +@inline valtype(::Type, ::Type{V}) where {V} = V +@inline valtype(::Type{T}, ::Type{Dual{T,V,N}}) where {T,V,N} = V +@inline function valtype(::Type{T}, ::Type{Dual{S,V,N}}) where {T,S,V,N} + if S ≺ T + Dual{S,V,N} + else + throw(DualMismatchError(T,S)) + end +end + @inline tagtype(::V) where {V} = Nothing @inline tagtype(::Type{V}) where {V} = Nothing @inline tagtype(::Dual{T,V,N}) where {T,V,N} = T diff --git a/src/gradient.jl b/src/gradient.jl index 6d4cc791..ba455317 100644 --- a/src/gradient.jl +++ b/src/gradient.jl @@ -90,7 +90,7 @@ const GRAD_ERROR = DimensionMismatch("gradient(f, x) expects that f(x) is a real function vector_mode_gradient(f::F, x, cfg::GradientConfig{T}) where {T, F} ydual = vector_mode_dual_eval!(f, cfg, x) ydual isa Real || throw(GRAD_ERROR) - result = similar(x, valtype(ydual)) + result = similar(x, valtype(T, ydual)) return extract_gradient!(T, result, ydual) end @@ -149,7 +149,7 @@ function chunk_mode_gradient_expr(result_definition::Expr) end @eval function chunk_mode_gradient(f::F, x, cfg::GradientConfig{T,V,N}) where {F,T,V,N} - $(chunk_mode_gradient_expr(:(result = similar(x, valtype(ydual))))) + $(chunk_mode_gradient_expr(:(result = similar(x, valtype(T, ydual))))) end @eval function chunk_mode_gradient!(result, f::F, x, cfg::GradientConfig{T,V,N}) where {F,T,V,N} diff --git a/src/jacobian.jl b/src/jacobian.jl index e7ca96f5..385d484d 100644 --- a/src/jacobian.jl +++ b/src/jacobian.jl @@ -128,7 +128,7 @@ function vector_mode_jacobian(f::F, x, cfg::JacobianConfig{T}) where {F,T} N = chunksize(cfg) ydual = vector_mode_dual_eval!(f, cfg, x) ydual isa AbstractArray || throw(JACOBIAN_ERROR) - result = similar(ydual, valtype(eltype(ydual)), length(ydual), N) + result = similar(ydual, valtype(T, eltype(ydual)), length(ydual), N) extract_jacobian!(T, result, ydual, N) extract_value!(T, result, ydual) return result @@ -217,7 +217,7 @@ end seed!(xdual, x) end, :(ydual = f(xdual)), - :(result = similar(ydual, valtype(eltype(ydual)), length(ydual), xlen)), + :(result = similar(ydual, valtype(T, eltype(ydual)), length(ydual), xlen)), :())) end diff --git a/test/DualTest.jl b/test/DualTest.jl index 3bba824b..df79c825 100644 --- a/test/DualTest.jl +++ b/test/DualTest.jl @@ -94,6 +94,21 @@ ForwardDiff.:≺(::Type{OuterTestTag}, ::Type{TestTag}) = false @test ForwardDiff.valtype(NESTED_FDNUM) == Dual{TestTag,V,M} @test ForwardDiff.valtype(typeof(NESTED_FDNUM)) == Dual{TestTag,V,M} + @test ForwardDiff.valtype(TestTag, FDNUM) == V + @test ForwardDiff.valtype(TestTag, typeof(FDNUM)) == V + @test ForwardDiff.valtype(TestTag, NESTED_FDNUM) == Dual{TestTag,V,M} + @test ForwardDiff.valtype(TestTag, typeof(NESTED_FDNUM)) == Dual{TestTag,V,M} + + @test ForwardDiff.valtype(OuterTestTag, FDNUM) == Dual{TestTag,V,N} + @test ForwardDiff.valtype(OuterTestTag, typeof(FDNUM)) == Dual{TestTag,V,N} + @test ForwardDiff.valtype(OuterTestTag, NESTED_FDNUM) == Dual{TestTag,Dual{TestTag,V,M},N} + @test ForwardDiff.valtype(OuterTestTag, typeof(NESTED_FDNUM)) == Dual{TestTag,Dual{TestTag,V,M},N} + + @test_throws ForwardDiff.DualMismatchError(TestTag, OuterTestTag) ForwardDiff.valtype(TestTag, Dual{OuterTestTag}(PRIMAL, PARTIALS)) + @test_throws ForwardDiff.DualMismatchError(TestTag, OuterTestTag) ForwardDiff.valtype(TestTag, typeof(Dual{OuterTestTag}(PRIMAL, PARTIALS))) + @test_throws ForwardDiff.DualMismatchError(TestTag, OuterTestTag) ForwardDiff.valtype(TestTag, Dual{OuterTestTag}(Dual{TestTag}(PRIMAL, M_PARTIALS), NESTED_PARTIALS)) + @test_throws ForwardDiff.DualMismatchError(TestTag, OuterTestTag) ForwardDiff.valtype(TestTag, typeof(Dual{OuterTestTag}(Dual{TestTag}(PRIMAL, M_PARTIALS), NESTED_PARTIALS))) + ##################### # Generic Functions # ##################### diff --git a/test/GradientTest.jl b/test/GradientTest.jl index d85cb145..ff490d94 100644 --- a/test/GradientTest.jl +++ b/test/GradientTest.jl @@ -11,6 +11,11 @@ using DiffTests include(joinpath(dirname(@__FILE__), "utils.jl")) +struct TestTag end +struct OuterTestTag end +ForwardDiff.:≺(::Type{TestTag}, ::Type{OuterTestTag}) = true +ForwardDiff.:≺(::Type{OuterTestTag}, ::Type{<:Tag}) = true + ################## # hardcoded test # ################## @@ -179,4 +184,30 @@ end @test_throws DomainError ForwardDiff.gradient(x -> x[1]^x[2], [-1.0, 0.5]) end +# issue #769 +@testset "functions with `Dual` output" begin + x = [Dual{OuterTestTag}(Dual{TestTag}(1.3, 2.1), Dual{TestTag}(0.3, -2.4))] + f(x) = sum(ForwardDiff.value, x) + der = ForwardDiff.derivative(ForwardDiff.value, only(x)) + + # Vector mode + grad = ForwardDiff.gradient(f, x) + @test grad isa Vector{typeof(der)} + @test grad == [der] + grad = ForwardDiff.gradient(f, SVector{1}(x)) + @test grad isa SVector{1,typeof(der)} + @test grad == SVector{1}(der) + + # Chunk mode + y = repeat(x, 3) + cfg = ForwardDiff.GradientConfig(f, y, ForwardDiff.Chunk{2}()) + grad = ForwardDiff.gradient(f, y, cfg) + @test grad isa Vector{typeof(der)} + @test grad == [der, der, der] + cfg = ForwardDiff.GradientConfig(f, SVector{3}(y), ForwardDiff.Chunk{2}()) + grad = ForwardDiff.gradient(f, SVector{3}(y), cfg) + @test grad isa SVector{3,typeof(der)} + @test grad == SVector{3}(der, der, der) +end + end # module diff --git a/test/JacobianTest.jl b/test/JacobianTest.jl index 0c24b018..07544a0d 100644 --- a/test/JacobianTest.jl +++ b/test/JacobianTest.jl @@ -11,6 +11,11 @@ using LinearAlgebra include(joinpath(dirname(@__FILE__), "utils.jl")) +struct TestTag end +struct OuterTestTag end +ForwardDiff.:≺(::Type{TestTag}, ::Type{OuterTestTag}) = true +ForwardDiff.:≺(::Type{OuterTestTag}, ::Type{<:Tag}) = true + ################## # hardcoded test # ################## @@ -255,4 +260,30 @@ end @inferred ForwardDiff.jacobian(g!, [1.0], [0.0]) end +# issue #769 +@testset "functions with `Dual` output" begin + x = [Dual{OuterTestTag}(Dual{TestTag}(1.3, 2.1), Dual{TestTag}(0.3, -2.4))] + f(x) = map(ForwardDiff.value, x) + der = ForwardDiff.derivative(ForwardDiff.value, only(x)) + + # Vector mode + jac = ForwardDiff.jacobian(f, x) + @test jac isa Matrix{typeof(der)} + @test jac == [der;;] + jac = ForwardDiff.jacobian(f, SVector{1}(x)) + @test jac isa SMatrix{1,1,typeof(der)} + @test jac == SMatrix{1,1}(der) + + # Chunk mode + y = repeat(x, 3) + cfg = ForwardDiff.JacobianConfig(f, y, ForwardDiff.Chunk{2}()) + jac = ForwardDiff.jacobian(f, y, cfg) + @test jac isa Matrix{typeof(der)} + @test jac == Diagonal([der, der, der]) + cfg = ForwardDiff.JacobianConfig(f, SVector{3}(y), ForwardDiff.Chunk{2}()) + jac = ForwardDiff.jacobian(f, SVector{3}(y), cfg) + @test jac isa SMatrix{3,3,typeof(der)} + @test jac == Diagonal([der, der, der]) +end + end # module From 169b7f0fb6a90163bdb6b43aa0400f26294dec47 Mon Sep 17 00:00:00 2001 From: David Widmann Date: Sat, 13 Sep 2025 22:33:39 +0200 Subject: [PATCH 4/5] Make tests compatible with Julia 1.0 and 1.6 --- test/GradientTest.jl | 2 +- test/JacobianTest.jl | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/GradientTest.jl b/test/GradientTest.jl index ff490d94..9e4da333 100644 --- a/test/GradientTest.jl +++ b/test/GradientTest.jl @@ -188,7 +188,7 @@ end @testset "functions with `Dual` output" begin x = [Dual{OuterTestTag}(Dual{TestTag}(1.3, 2.1), Dual{TestTag}(0.3, -2.4))] f(x) = sum(ForwardDiff.value, x) - der = ForwardDiff.derivative(ForwardDiff.value, only(x)) + der = ForwardDiff.derivative(ForwardDiff.value, first(x)) # Vector mode grad = ForwardDiff.gradient(f, x) diff --git a/test/JacobianTest.jl b/test/JacobianTest.jl index 07544a0d..6828a0d3 100644 --- a/test/JacobianTest.jl +++ b/test/JacobianTest.jl @@ -264,12 +264,12 @@ end @testset "functions with `Dual` output" begin x = [Dual{OuterTestTag}(Dual{TestTag}(1.3, 2.1), Dual{TestTag}(0.3, -2.4))] f(x) = map(ForwardDiff.value, x) - der = ForwardDiff.derivative(ForwardDiff.value, only(x)) + der = ForwardDiff.derivative(ForwardDiff.value, first(x)) # Vector mode jac = ForwardDiff.jacobian(f, x) @test jac isa Matrix{typeof(der)} - @test jac == [der;;] + @test jac == fill(der, 1, 1) jac = ForwardDiff.jacobian(f, SVector{1}(x)) @test jac isa SMatrix{1,1,typeof(der)} @test jac == SMatrix{1,1}(der) From 55ba55d104c0890e098b2e7cfe37a50dbbc5e26f Mon Sep 17 00:00:00 2001 From: David Widmann Date: Fri, 12 Sep 2025 16:20:59 +0200 Subject: [PATCH 5/5] Bump version to 0.10.39 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 7d1d9e6a..66ea19ba 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "ForwardDiff" uuid = "f6369f11-7733-5829-9624-2563aa707210" -version = "0.10.38" +version = "0.10.39" [deps] CommonSubexpressions = "bbf7d656-a473-5ed7-a52c-81e309532950"