From 2c3a91c1863d32c09bb9119151381662cedbe9b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1s=20Lob=C3=A3o=20de=20Almeida?= Date: Wed, 14 Dec 2022 13:14:03 +0000 Subject: [PATCH 1/3] Make duals' operations through steprange use linrange instead --- src/dual.jl | 11 +++++++++++ test/DualTest.jl | 9 +++++++++ 2 files changed, 20 insertions(+) diff --git a/src/dual.jl b/src/dual.jl index 4315e322..32dc7918 100644 --- a/src/dual.jl +++ b/src/dual.jl @@ -775,6 +775,17 @@ function LinearAlgebra.eigen(A::SymTridiagonal{<:Dual{Tg,T,N}}) where {Tg,T<:Rea Eigen(λ,Dual{Tg}.(Q, tuple.(parts...))) end +# StepRange - default to operate with LinRange to avoid TwicePrecision # +#----------------------------------------------------------------------# + +Base.:*(x::Dual, r::StepRangeLen{<:Real,<:Base.TwicePrecision}) = + LinRange(x * first(r), x * last(r), length(r)) + +Base.:/(r::StepRangeLen{<:Real,<:Base.TwicePrecision}, x::Dual) = + LinRange(first(r) / x, last(r) / x, length(r)) + +Base.:(:)(start::T, step::Dual, stop::T) where {T<:Real} = range(start, step, stop) + # Functions in SpecialFunctions which return tuples # # Their derivatives are not defined in DiffRules # #---------------------------------------------------# diff --git a/test/DualTest.jl b/test/DualTest.jl index 938cd0e6..a9f52d43 100644 --- a/test/DualTest.jl +++ b/test/DualTest.jl @@ -659,4 +659,13 @@ end @test ForwardDiff.derivative(float, 1)::Float64 === 1.0 end +@testset "steprange" begin # issue #380 + @test Dual(1,1) * (0:0.1:1) isa LinRange{Dual{Nothing, Float64, 1}, Int64} + @test (0:0.1:1) / Dual(1,1) isa LinRange{Dual{Nothing, Float64, 1}, Int64} + @test 0:Dual(1,1):2 isa LinRange{Dual{Nothing, Float64, 1}, Int64} +end + + + + end # module From a3212378582fe6bac971482d96ff349406902a43 Mon Sep 17 00:00:00 2001 From: tom-plaa <93333887+tom-plaa@users.noreply.github.com> Date: Wed, 14 Dec 2022 14:51:29 +0000 Subject: [PATCH 2/3] Update test/DualTest.jl Co-authored-by: Michael Abbott <32575566+mcabbott@users.noreply.github.com> --- test/DualTest.jl | 56 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 51 insertions(+), 5 deletions(-) diff --git a/test/DualTest.jl b/test/DualTest.jl index a9f52d43..2b5b4be2 100644 --- a/test/DualTest.jl +++ b/test/DualTest.jl @@ -659,13 +659,59 @@ end @test ForwardDiff.derivative(float, 1)::Float64 === 1.0 end -@testset "steprange" begin # issue #380 - @test Dual(1,1) * (0:0.1:1) isa LinRange{Dual{Nothing, Float64, 1}, Int64} - @test (0:0.1:1) / Dual(1,1) isa LinRange{Dual{Nothing, Float64, 1}, Int64} - @test 0:Dual(1,1):2 isa LinRange{Dual{Nothing, Float64, 1}, Int64} +function deriv_check(f, x::Real; kw...) + fdual = f(ForwardDiff.Dual(x,1)) + ty = fdual isa AbstractRange || !(f(x) isa AbstractRange) + t0 = isapprox(f(x), ForwardDiff.value.(fdual); kw...) + t1 = isapprox(ForwardDiff.derivative(f, x), + Calculus.derivative(f, x); kw...) + t1i = isapprox(ForwardDiff.derivative(x -> f(x)[1+end÷2], x), + Calculus.derivative(x -> f(x)[1+end÷2], x); kw...) + ty && t0 && t1 && t1i end - +@testset "ranges + Calculus" begin + # op(Dual, StepRangeLen) was broken, issue #380 + @test (0:0.1:1) isa StepRangeLen + + @test deriv_check(x -> (0:0.1:1) * x, 1.0) + @test deriv_check(x -> (0:0.1:1) .* x, 1.0) + @test deriv_check(x -> x * (0:0.1:1), 1.0) + @test deriv_check(x -> x .* (0:0.1:1), 1.0) + + @test deriv_check(x -> (0:0.1:1) / x, 1.0) # makes a LinRange, after PR#618 + @test deriv_check(x -> (0:0.1:1) ./ x, 1.0) # different path, at present a StepRangeLen + + @test deriv_check(x -> (0:0.1:1) .+ x, 1.0) + @test deriv_check(x -> x .+ (0:0.1:1), 1.0) + @test deriv_check(x -> (0:0.1:1) .- x, 1.0) + @test deriv_check(x -> x .- (0:0.1:1), 1.0) + + # op(Dual, StepRange) was never a problem + @test (2:3:11) isa StepRange + + @test deriv_check(x -> (2:3:11) * x, 1.0) + @test deriv_check(x -> (2:3:11) / x, 1.0) + @test deriv_check(x -> (2:3:11) .+ x, 1.0) + + # op(Dual, LinRange) was never a problem + @test deriv_check(x -> LinRange(1,2,3) * x, 1.0) + @test deriv_check(x -> LinRange(1,2,3) / x, 1.0) + @test deriv_check(x -> LinRange(1,2,3) .+ x, 1.0) + + # Construction + @test deriv_check(x -> range(x, 3, length=5), 1.0) + @test deriv_check(x -> range(x, 3x, length=5), 1.0) + @test deriv_check(x -> range(x, step=2, length=5), 1.0) + @test deriv_check(x -> range(x, step=2x, length=5), 1.0) + @test deriv_check(x -> range(1, step=x, length=5), 1.0) + + @test deriv_check(x -> x:2:6, 1.0) # perturbing x does not change the length + @test deriv_check(x -> 0.5:x:5, 1.0) + @test deriv_check(x -> 1:x:6, 2) # perturbing x does not change the length + @test deriv_check(x -> 1:2:x, 6) # perturbing x has no effect + @test deriv_check(x -> 1:2:x, 6.0) # perturbing x has no effect +end end # module From 3319d5e8c2c5b09e6e792256663547f37f57483e Mon Sep 17 00:00:00 2001 From: tom-plaa <93333887+tom-plaa@users.noreply.github.com> Date: Tue, 3 Jan 2023 15:19:40 +0000 Subject: [PATCH 3/3] Remove construction using Duals and (:) operator --- src/dual.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/dual.jl b/src/dual.jl index 32dc7918..a55bf139 100644 --- a/src/dual.jl +++ b/src/dual.jl @@ -784,7 +784,6 @@ Base.:*(x::Dual, r::StepRangeLen{<:Real,<:Base.TwicePrecision}) = Base.:/(r::StepRangeLen{<:Real,<:Base.TwicePrecision}, x::Dual) = LinRange(first(r) / x, last(r) / x, length(r)) -Base.:(:)(start::T, step::Dual, stop::T) where {T<:Real} = range(start, step, stop) # Functions in SpecialFunctions which return tuples # # Their derivatives are not defined in DiffRules #