Hi,
I'm integrating the changes in v0.4.10 in my package. During the upgrades, I noticed that I need a type piracy currently as a workaround to handle derivatives:
# Workaround for FastInterpolations v0.4.10 type promotion limitation with SVector and ForwardDiff.Dual
@inline function FastInterpolations._output_eltype(::Type{SVector{N, T}}, types::Type...) where {N, T}
return SVector{N, promote_type(T, types...)}
end
Probably it's better to fix it in FastInterpolations.jl directly.
Description
When attempting to run automatic differentiation via ForwardDiff.jl on a vector-valued interpolant (using StaticArrays.SVector), evaluation throws a MethodError. This occurs due to new type promotion/conversion constraints introduced in FastInterpolations.jl v0.4.10.
Minimal Working Example (MWE)
using FastInterpolations, StaticArrays, ForwardDiff
x = 1.0:10.0
y = [SA[1.0, 2.0, 3.0] for _ in 1:10]
itp = linear_interp(x, y)
# Evaluating the derivative of itp(t)[1] at t = 2.0 throws a MethodError
ForwardDiff.derivative(t -> itp(t)[1], 2.0)
Root Cause Analysis
- In
src/core/interpolant_protocol.jl (line 58), the interpolant call protocol attempts to convert the evaluation result val to _output_eltype(itp, typeof(xq)):
val = _itp_eval_scalar(itp, xq, extrap, deriv, searcher)
return convert(_output_eltype(itp, typeof(xq)), val)
-
The trait method _output_eltype(::Type{Tv}, types::Type...) (defined in src/core/utils.jl, line 145) calls promote_type(Tv, types...) to compute the promoted return type. In this scenario:
Tv is SVector{3, Float64}.
types... contains Float64 (grid element type) and ForwardDiff.Dual (query point type).
-
Since SVector{3, Float64} is a vector and ForwardDiff.Dual is a scalar, promote_type has no standard promotion rules defined between them and falls back to returning Any.
-
Due to the fallback logic in _output_eltype:
Tr = promote_type(Tv, types...)
Tc = isconcretetype(Tr) ? Tr : Tv # Returns SVector{3, Float64} because Any is not concrete
The expected output type is resolved to SVector{3, Float64}.
- The actual calculated evaluation
val produces SVector{3, ForwardDiff.Dual} carrying the derivatives. FastInterpolations tries to perform:
convert(SVector{3, Float64}, val)
This fails with a MethodError: no method matching Float64(::ForwardDiff.Dual...) because dual numbers cannot be converted back to standard floats without discarding derivative information.
Hi,
I'm integrating the changes in v0.4.10 in my package. During the upgrades, I noticed that I need a type piracy currently as a workaround to handle derivatives:
Probably it's better to fix it in FastInterpolations.jl directly.
Description
When attempting to run automatic differentiation via
ForwardDiff.jlon a vector-valued interpolant (usingStaticArrays.SVector), evaluation throws aMethodError. This occurs due to new type promotion/conversion constraints introduced inFastInterpolations.jlv0.4.10.Minimal Working Example (MWE)
Root Cause Analysis
src/core/interpolant_protocol.jl(line 58), the interpolant call protocol attempts to convert the evaluation resultvalto_output_eltype(itp, typeof(xq)):The trait method
_output_eltype(::Type{Tv}, types::Type...)(defined insrc/core/utils.jl, line 145) callspromote_type(Tv, types...)to compute the promoted return type. In this scenario:TvisSVector{3, Float64}.types...containsFloat64(grid element type) andForwardDiff.Dual(query point type).Since
SVector{3, Float64}is a vector andForwardDiff.Dualis a scalar,promote_typehas no standard promotion rules defined between them and falls back to returningAny.Due to the fallback logic in
_output_eltype:The expected output type is resolved to
SVector{3, Float64}.valproducesSVector{3, ForwardDiff.Dual}carrying the derivatives.FastInterpolationstries to perform:This fails with a
MethodError: no method matching Float64(::ForwardDiff.Dual...)because dual numbers cannot be converted back to standard floats without discarding derivative information.