FiniteDifferences.jl
FiniteDifferences.jl copied to clipboard
Type Conversion Error with Measurements
using FiniteDifferences
using Measurements
f(x) = cos(x + (1.0 ± 0.1)*sin(x))
m = central_fdm(5,1)
m(f, 0.0)
MethodError: no method matching Float64(::Measurement{Float64})
Closest candidates are:
(::Type{T})(::Real, ::RoundingMode) where T<:AbstractFloat at rounding.jl:200
(::Type{T})(::T) where T<:Number at boot.jl:772
(::Type{T})(::AbstractChar) where T<:Union{AbstractChar, Number} at char.jl:50
...
Stacktrace:
[1] _eval_function(m::FiniteDifferences.AdaptedFiniteDifferenceMethod{5, 1, FiniteDifferences.UnadaptedFiniteDifferenceMethod{7, 5}}, f::typeof(f), x::Float64, step::Measurement{Float64})
@ FiniteDifferences ~/.julia/packages/FiniteDifferences/8zye5/src/methods.jl:249
[2] (::FiniteDifferences.AdaptedFiniteDifferenceMethod{5, 1, FiniteDifferences.UnadaptedFiniteDifferenceMethod{7, 5}})(f::typeof(f), x::Float64, step::Measurement{Float64})
@ FiniteDifferences ~/.julia/packages/FiniteDifferences/8zye5/src/methods.jl:240
[3] (::FiniteDifferences.AdaptedFiniteDifferenceMethod{5, 1, FiniteDifferences.UnadaptedFiniteDifferenceMethod{7, 5}})(f::typeof(f), x::Float64)
@ FiniteDifferences ~/.julia/packages/FiniteDifferences/8zye5/src/methods.jl:194
[4] top-level scope
@ In[6]:7
[5] eval
@ ./boot.jl:368 [inlined]
[6] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String)
@ Base ./loading.jl:1428
Quick workaround: turn-off adaption.
julia> m2 = central_fdm(5, 1; adapt=0);
julia> m2(f, 0.0)
0.0 ± 0.00014
There are a few places in the code, namely
https://github.com/JuliaDiff/FiniteDifferences.jl/blob/93cd547363ab182ea42ddff7c112824d147d923c/src/methods.jl#L246-L250 and https://github.com/JuliaDiff/FiniteDifferences.jl/blob/93cd547363ab182ea42ddff7c112824d147d923c/src/methods.jl#L263
where we use T(step) to convert the step into the same type as the primal value x.
This was done when chasing down allocations from type-instabilities.
Mathematically, I don't think this is required.
We just need x+step to be the same type as x.
However, I don't thing step::Measurement{Float64} satisfies that: x + step gives a result that is a Measurement{Float64}.
But the question then is where is our step coming from?
That is coming out of FiniteDifferences.estimate_step
julia> FiniteDifferences.estimate_step(m, f, 0.0)
(0.00097 ± 2500.0, 4.3e-13 ± 1.1e-6)
Something is off somewhere in the adaption logic of https://github.com/JuliaDiff/FiniteDifferences.jl/blob/93cd547363ab182ea42ddff7c112824d147d923c/src/methods.jl#L362-L426
because it is yielding a step that is of the same type as f(x) rather than the type of x.
@wesselb might have ideas
but otherwise this is going to take a fair bit of digging to uncover.