ForwardDiff.jl
ForwardDiff.jl copied to clipboard
Using ArbFloat fails at subtraction / addition of Dual and ArbFloat
Hello, I cannot use jacobian with ArbFloat type. The following code runs when T = Float64
using ArbFloats
using ForwardDiff
T = Float64 # ArbFloat
M = 3
F = [T(0.0) for i in 1:M]
x0 = [T(-1.0) for i in 1:M]
function f!(F,x)
for i in eachindex(F)
F[i] = x[i] - T(1.0)
end
end
ForwardDiff.jacobian(f!,F,x0)
but fails when I set T = ArbFloat with the following error:
ERROR: LoadError: MethodError: +(::ForwardDiff.Dual{ForwardDiff.Tag{#f!,ArbFloats.ArbFloat{116}},ArbFloats.ArbFloat{116},3}, ::ArbFloats.ArbFloat{116}) is ambiguous. Candidates:
+(x::ForwardDiff.Dual{Tx,V,N} where N where V<:Real, y::AbstractFloat) where Tx in ForwardDiff at /home/gluon/.julia/v0.6/ForwardDiff/src/dual.jl:103
+(x::ForwardDiff.Dual{Tx,V,N} where N where V<:Real, y::Real) where Tx in ForwardDiff at /home/gluon/.julia/v0.6/ForwardDiff/src/dual.jl:103
+(x::R, y::T) where {T<:ArbFloats.ArbFloat, R<:Real} in ArbFloats at /home/gluon/.julia/v0.6/ArbFloats/src/math/arith.jl:60
Possible fix, define
+(::ForwardDiff.Dual{Tx,V,N} where N where V<:Real, ::T<:ArbFloats.ArbFloat)
Stacktrace:
[1] (::Atom.##110#114{String,String})() at /home/gluon/.julia/v0.6/Atom/src/eval.jl:104
[2] withpath(::Atom.##110#114{String,String}, ::String) at /home/gluon/.julia/v0.6/CodeTools/src/utils.jl:30
[3] withpath(::Function, ::String) at /home/gluon/.julia/v0.6/Atom/src/eval.jl:38
[4] didWriteToREPL(::Atom.##109#113{String,String}) at /home/gluon/.julia/v0.6/Atom/src/repl.jl:129
[5] hideprompt(::Atom.##109#113{String,String}) at /home/gluon/.julia/v0.6/Atom/src/repl.jl:65
[6] macro expansion at /home/gluon/.julia/v0.6/Atom/src/eval.jl:99 [inlined]
[7] (::Atom.##108#112{Dict{String,Any}})() at ./task.jl:80
while loading /media/DATA/PhD/code/sandbox/sandbox.jl, in expression starting on line 57
This is just a test code which I produced to show the error, the actual code is different but leads to same kind of errors. Can someone say me what is going on here and how to fix this? Thanks.
Congratulations! You have discovered one of the more complicated issues with multiple dispatch: method ambiguity. Here's what's happening:
ForwardDiff has defined +(x::Real, y::DualNumber). and ArbFloats has defined+(x::ArbFloat, y::Real). Since both DualNumbers and ArbFloats are of type Real, either of these methods apply to the call +(ArbFloat(), DualNumber()) and neither of these methods is more specific than the other, there is no way to decide which method should be applied.
Julia is asking you the following: "Should + of ArbFloat and DualNumber result in a DualNumber of ArbFloat or should it be handled by ArbFloat?"
Lets assume that we want this to be handled by DualNumbers. We can make the choice (globally) that this method is handled by DualNumbers by defining something like (I didn't have time to test this code)
+(x::ForwardDiff.Dual{Tx,V,N} where N where V<:Real, y::T<:ArbFloats.ArbFloat) = invoke(+,(ForwardDiff.Dual{Tx,V,N}, Real), x, y)
Which defines a more specific method than either of our two ambiguous methods above that simply chooses one of the two.
If you want a more general framework for resolving method ambiguities globally (A system to handle these redefinitions on concrete types for multiple methods), you can check out my package Hyperspecialize.jl.
If you want a method to choose different ambiguity resolutions in different contexts (and not just choose one globally), you might want to check out Cassette.jl
!! excellent explaination
Ok, thank you for the explanation. I will try it with Hyperspecialize.jl.
However, in this special case of this two packages: ArbFloats and ForwardDiff I would think, that a solution on the package side would be a good improvement since it is a very common issue to rely on both packages at the same time in numeric sciences.
Any chance that this could be involved in ForwardDiff?
(ArbFloats is undergoing rewrite -- I will keep this in mind)
@peterahrens Do you know why DualNumber <: Real? Only the real part of a dual number is Real.
Only the real part of a dual number is Real.
Subtyping relations in Julia should not be confused with the relations of the number sets themselves. Subtyping in Julia determines what methods will match a certain type and methods that can take Reals should have no problems with Duals.