JuliaPhysics / Measurements.jl

Error propagation calculator and library for physical measurements. It supports real and complex numbers with uncertainty, arbitrary precision calculations, operations with arrays, and numerical integration.
https://juliaphysics.github.io/Measurements.jl/stable/
MIT License
486 stars 37 forks source link

Is there an autodiff package that is compatible? #154

Open timholy opened 12 months ago

timholy commented 12 months ago

I'd like to compute up to third-order derivatives with respect to a scalar (non-measurement) of a measurement-valued function. Something along the lines of this demo:

julia> using Measurements

julia> c, w = π/4, 0.1    # could alternatively be AbstractVectors
(0.7853981633974483, 0.1)

julia> f = sin   # could be anything
sin (generic function with 15 methods)

julia> ϕ(t) = f(c ± (1 + t)*w)       # evaluates f over a Measurement
ϕ (generic function with 1 method)

julia> ϕ(0.1)
0.707 ± 0.078

I've tried ForwardDiff (I saw #100):

julia> using ForwardDiff

julia> ForwardDiff.derivative(ϕ, 0.0)
ERROR: StackOverflowError:
Stacktrace:
 [1] measurement(val::ForwardDiff.Dual{ForwardDiff.Tag{typeof(ϕ), Float64}, Float64, 1}, err::ForwardDiff.Dual{ForwardDiff.Tag{typeof(ϕ), Float64}, Float64, 1}) (repeats 79984 times)
   @ Measurements ~/.julia/packages/Measurements/hcRfF/src/Measurements.jl:93

and TaylorDiff:

julia> TaylorDiff.derivative(ϕ, 0.0, 1)
ERROR: MethodError: no method matching measurement(::Float64, ::TaylorScalar{Float64, 2})

Closest candidates are:
  measurement(::T) where T<:AbstractFloat
   @ Measurements ~/.julia/packages/Measurements/hcRfF/src/Measurements.jl:82
  measurement(::Real)
   @ Measurements ~/.julia/packages/Measurements/hcRfF/src/Measurements.jl:83
  measurement(::T, ::T) where T<:AbstractFloat
   @ Measurements ~/.julia/packages/Measurements/hcRfF/src/Measurements.jl:84
  ...

Stacktrace:
 [1] ϕ(t::TaylorScalar{Float64, 2})
   @ Main ./REPL[100]:1
 [2] derivative(f::typeof(ϕ), x::Float64, ::Val{2})
   @ TaylorDiff ~/.julia/packages/TaylorDiff/zNnz2/src/derivative.jl:28
 [3] derivative(f::Function, x::Float64, order::Int64)
   @ TaylorDiff ~/.julia/packages/TaylorDiff/zNnz2/src/derivative.jl:18
 [4] top-level scope
   @ REPL[107]:1

and TaylorSeries:

julia> using TaylorSeries
WARNING: using TaylorSeries.derivative in module Main conflicts with an existing identifier.

julia> tt = Taylor1(3)
 1.0 t + 𝒪(t⁴)

julia> ϕ(0.0 + tt)
ERROR: MethodError: no method matching measurement(::Float64, ::Taylor1{Float64})

Closest candidates are:
  measurement(::T) where T<:AbstractFloat
   @ Measurements ~/.julia/packages/Measurements/hcRfF/src/Measurements.jl:82
  measurement(::Real)
   @ Measurements ~/.julia/packages/Measurements/hcRfF/src/Measurements.jl:83
  measurement(::T, ::T) where T<:AbstractFloat
   @ Measurements ~/.julia/packages/Measurements/hcRfF/src/Measurements.jl:84
  ...

Stacktrace:
 [1] ϕ(t::Taylor1{Float64})
   @ Main ./REPL[100]:1
 [2] top-level scope
   @ REPL[111]:1

I haven't yet tried Diffractor (the docs are not fully fleshed out).

longemen3000 commented 12 months ago

can you try with ForwardDiffOverMeasurements.jl? (adds ForwardDiff overloads to measurements)

timholy commented 12 months ago

With that example, I still get

julia> ForwardDiff.derivative(ϕ, 0.0)
ERROR: StackOverflowError:
Stacktrace:
 [1] measurement(val::ForwardDiff.Dual{…}, err::ForwardDiff.Dual{…}) (repeats 79984 times)
   @ Measurements ~/.julia/packages/Measurements/hcRfF/src/Measurements.jl:93
Some type information was truncated. Use `show(err)` to see complete types.

This is with Measurements 2.10.0, ForwardDiff 0.10.36, and ForwardDiffOverMeasurements 0.1.0. Might the difference from the examples you show is that the variable I'm differentiating is a mapping Float64 -> Measurement{Float64} rather than a Measurement{Float64} -> Measurement{Float64}?

longemen3000 commented 12 months ago

A method measurement(val, err::Dual{T, V})::Dual{T, Measurement{T}} is needed.