-
Notifications
You must be signed in to change notification settings - Fork 146
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Correctly forming nested dual numbers. #671
Comments
Update: For 4-element Vector{Dual{Nothing, Dual{Nothing, Float64, 1}, 1}}:
Dual{Nothing}(Dual{Nothing}(1.0,2.0),Dual{Nothing}(2.0,2.0))
Dual{Nothing}(Dual{Nothing}(4.0,4.0),Dual{Nothing}(4.0,2.0))
Dual{Nothing}(Dual{Nothing}(9.0,6.0),Dual{Nothing}(6.0,2.0))
Dual{Nothing}(Dual{Nothing}(16.0,8.0),Dual{Nothing}(8.0,2.0)) For julia> include("examples/burgers_fourier/visc_burg_param_ic/autodecode.jl")
4-element Vector{Dual{Nothing, Dual{Nothing, Float64, 1}, 1}}:
Dual{Nothing}(Dual{Nothing}(2.718281828459045,2.718281828459045),Dual{Nothing}(2.718281828459045,2.718281828459045))
Dual{Nothing}(Dual{Nothing}(7.38905609893065,7.38905609893065),Dual{Nothing}(7.38905609893065,7.38905609893065))
Dual{Nothing}(Dual{Nothing}(20.085536923187668,20.085536923187668),Dual{Nothing}(20.085536923187668,20.085536923187668))
Dual{Nothing}(Dual{Nothing}(54.598150033144236,54.598150033144236),Dual{Nothing}(54.598150033144236,54.598150033144236)) |
I think this is perturbation confusion. Making julia> ForwardDiff.derivative(x -> ForwardDiff.derivative(f, x), 3.0)
2.0
julia> ForwardDiff.derivative(x -> ForwardDiff.derivative(f, x), 4.0)
2.0 |
@mcabbott I am getting similar behavior with different tags. using ForwardDiff
using ForwardDiff: Dual, value, partials
f = x -> x .^ 2
x = [1.0, 2.0, 3.0, 4.0]
v = ones(4)
# 2st order
z = Dual{:FD_D2Tag}.(
Dual{:FD_D2TagInt}.(x, 1v),
Dual{:FD_D2TagInt}.(1v, 1v)
)
fz = f(z)
fx = value.(value.(fz))
df = value.(partials.(fz, 1))
d2f = partials.(partials.(fz, 1), 1)
display(fz) 4-element Vector{Dual{:FD_D2Tag, Dual{:FD_D2TagInt, Float64, 1}, 1}}:
Dual{:FD_D2Tag}(Dual{:FD_D2TagInt}(1.0,2.0),Dual{:FD_D2TagInt}(2.0,4.0))
Dual{:FD_D2Tag}(Dual{:FD_D2TagInt}(4.0,4.0),Dual{:FD_D2TagInt}(4.0,6.0))
Dual{:FD_D2Tag}(Dual{:FD_D2TagInt}(9.0,6.0),Dual{:FD_D2TagInt}(6.0,8.0))
Dual{:FD_D2Tag}(Dual{:FD_D2TagInt}(16.0,8.0),Dual{:FD_D2TagInt}(8.0,10.0))
|
Maybe it's not perturbation confusion, just wrong inputs? If you print out what the perturbations created by the user-facing function, you get this: julia> f(x) = x .^ 2; f(x::Real) = @show(x) ^ 2;
julia> ForwardDiff.derivative(x -> ForwardDiff.derivative(f, x), 3.0)
x = Dual{ForwardDiff.Tag{typeof(f), Dual{ForwardDiff.Tag{var"#41#42", Float64}, Float64, 1}}}(Dual{ForwardDiff.Tag{var"#41#42", Float64}}(3.0,1.0),Dual{ForwardDiff.Tag{var"#41#42", Float64}}(1.0,0.0))
2.0
julia> Dual{:b}.(Dual{:a}.(x, 1), Dual{:a}.(1, 0)) |> f
4-element Vector{Dual{:b, Dual{:a, Float64, 1}, 1}}:
Dual{:b}(Dual{:a}(1.0,2.0),Dual{:a}(2.0,2.0))
Dual{:b}(Dual{:a}(4.0,4.0),Dual{:a}(4.0,2.0))
Dual{:b}(Dual{:a}(9.0,6.0),Dual{:a}(6.0,2.0))
Dual{:b}(Dual{:a}(16.0,8.0),Dual{:a}(8.0,2.0))
julia> Dual.(Dual.(x, 1), 1) |> f
4-element Vector{Dual{Nothing, Dual{Nothing, Float64, 1}, 1}}:
Dual{Nothing}(Dual{Nothing}(1.0,2.0),Dual{Nothing}(2.0,2.0))
Dual{Nothing}(Dual{Nothing}(4.0,4.0),Dual{Nothing}(4.0,2.0))
Dual{Nothing}(Dual{Nothing}(9.0,6.0),Dual{Nothing}(6.0,2.0))
Dual{Nothing}(Dual{Nothing}(16.0,8.0),Dual{Nothing}(8.0,2.0)) |
I see. So I was forming julia> Dual.(Dual.(x, true), true) == Dual.(Dual.(x, v), Dual.(v, v))
true
julia> Dual.(Dual.(x, true), true)
4-element Vector{Dual{Nothing, Dual{Nothing, Float64, 1}, 1}}:
Dual{Nothing}(Dual{Nothing}(1.0,1.0),Dual{Nothing}(1.0,0.0))
Dual{Nothing}(Dual{Nothing}(2.0,1.0),Dual{Nothing}(1.0,0.0))
Dual{Nothing}(Dual{Nothing}(3.0,1.0),Dual{Nothing}(1.0,0.0))
Dual{Nothing}(Dual{Nothing}(4.0,1.0),Dual{Nothing}(1.0,0.0)) Thanks @mcabbott for figuring this out |
Adding code for forming nested duals in the docs so folks don't make the mistakes I made in JuliaDiff#671
made a PR to add docs describing how to form nested duals. |
No, this is not true. It's just that julia> Dual.(Dual.(x, true), true)
4-element Vector{Dual{Nothing, Dual{Nothing, Float64, 1}, 1}}:
Dual{Nothing}(Dual{Nothing}(1.0,1.0),Dual{Nothing}(1.0,0.0))
Dual{Nothing}(Dual{Nothing}(2.0,1.0),Dual{Nothing}(1.0,0.0))
Dual{Nothing}(Dual{Nothing}(3.0,1.0),Dual{Nothing}(1.0,0.0))
Dual{Nothing}(Dual{Nothing}(4.0,1.0),Dual{Nothing}(1.0,0.0))
julia> Dual.(Dual.(x, v), Dual.(v, v)) # original guess above
4-element Vector{Dual{Nothing, Dual{Nothing, Float64, 1}, 1}}:
Dual{Nothing}(Dual{Nothing}(1.0,1.0),Dual{Nothing}(1.0,1.0))
Dual{Nothing}(Dual{Nothing}(2.0,1.0),Dual{Nothing}(1.0,1.0))
Dual{Nothing}(Dual{Nothing}(3.0,1.0),Dual{Nothing}(1.0,1.0))
Dual{Nothing}(Dual{Nothing}(4.0,1.0),Dual{Nothing}(1.0,1.0))
julia> Dual.(Dual.(x, true), true) == Dual.(Dual.(x, v), Dual.(v, v)) # on master
false |
I see. I've changed my code to use |
MWE
Notice that the 2nd derivative (which should be [2.0, 2.0, 2.0, 2.0]
is off exactly by the first derivative.
I noticed this pattern in another function:
f = x -> exp.(x)
:The text was updated successfully, but these errors were encountered: