22Very heavily inspired by Calculus.jl, but with an emphasis on performance and DiffEq API convenience.
33=#
44
5- #=
6- Compute the finite difference interval epsilon.
5+ """
6+ compute_epsilon(::Val{:forward}, x::T, relstep::Real, absstep::Real, dir::Real) where T<:Number
7+
8+ Compute the finite difference step size (epsilon) for forward finite differences.
9+
10+ The step size is computed as `max(relstep*abs(x), absstep)*dir`, which ensures
11+ numerical stability by using a relative step scaled by the magnitude of `x`
12+ when `x` is large, and an absolute step when `x` is small.
13+
14+ # Arguments
15+ - `::Val{:forward}`: Finite difference type indicator for forward differences
16+ - `x::T`: Point at which to compute the step size
17+ - `relstep::Real`: Relative step size factor
18+ - `absstep::Real`: Absolute step size fallback
19+ - `dir::Real`: Direction multiplier (typically ±1)
20+
21+ # Returns
22+ - Step size `ϵ` for forward finite difference: `f(x + ϵ)`
23+
724Reference: Numerical Recipes, chapter 5.7.
8- =#
25+ """
926@inline function compute_epsilon (:: Val{:forward} , x:: T , relstep:: Real , absstep:: Real , dir:: Real ) where T<: Number
1027 return max (relstep* abs (x), absstep)* dir
1128end
1229
30+ """
31+ compute_epsilon(::Val{:central}, x::T, relstep::Real, absstep::Real, dir=nothing) where T<:Number
32+
33+ Compute the finite difference step size (epsilon) for central finite differences.
34+
35+ The step size is computed as `max(relstep*abs(x), absstep)`, which ensures
36+ numerical stability by using a relative step scaled by the magnitude of `x`
37+ when `x` is large, and an absolute step when `x` is small.
38+
39+ # Arguments
40+ - `::Val{:central}`: Finite difference type indicator for central differences
41+ - `x::T`: Point at which to compute the step size
42+ - `relstep::Real`: Relative step size factor
43+ - `absstep::Real`: Absolute step size fallback
44+ - `dir`: Direction parameter (unused for central differences)
45+
46+ # Returns
47+ - Step size `ϵ` for central finite difference: `(f(x + ϵ) - f(x - ϵ)) / (2ϵ)`
48+ """
1349@inline function compute_epsilon (:: Val{:central} , x:: T , relstep:: Real , absstep:: Real , dir= nothing ) where T<: Number
1450 return max (relstep* abs (x), absstep)
1551end
1652
53+ """
54+ compute_epsilon(::Val{:hcentral}, x::T, relstep::Real, absstep::Real, dir=nothing) where T<:Number
55+
56+ Compute the finite difference step size (epsilon) for central finite differences in Hessian computations.
57+
58+ The step size is computed as `max(relstep*abs(x), absstep)`, which ensures
59+ numerical stability by using a relative step scaled by the magnitude of `x`
60+ when `x` is large, and an absolute step when `x` is small.
61+
62+ # Arguments
63+ - `::Val{:hcentral}`: Finite difference type indicator for Hessian central differences
64+ - `x::T`: Point at which to compute the step size
65+ - `relstep::Real`: Relative step size factor
66+ - `absstep::Real`: Absolute step size fallback
67+ - `dir`: Direction parameter (unused for central differences)
68+
69+ # Returns
70+ - Step size `ϵ` for Hessian central finite differences
71+ """
1772@inline function compute_epsilon (:: Val{:hcentral} , x:: T , relstep:: Real , absstep:: Real , dir= nothing ) where T<: Number
1873 return max (relstep* abs (x), absstep)
1974end
2075
76+ """
77+ compute_epsilon(::Val{:complex}, x::T, ::Union{Nothing,T}=nothing, ::Union{Nothing,T}=nothing, dir=nothing) where T<:Real
78+
79+ Compute the finite difference step size (epsilon) for complex step differentiation.
80+
81+ For complex step differentiation, the step size is simply the machine epsilon `eps(T)`,
82+ which provides optimal accuracy since complex step differentiation doesn't suffer from
83+ subtractive cancellation errors.
84+
85+ # Arguments
86+ - `::Val{:complex}`: Finite difference type indicator for complex step differentiation
87+ - `x::T`: Point at which to compute the step size (unused, type determines epsilon)
88+ - Additional arguments are unused for complex step differentiation
89+
90+ # Returns
91+ - Machine epsilon `eps(T)` for complex step differentiation: `imag(f(x + iϵ)) / ϵ`
92+
93+ # Notes
94+ Complex step differentiation computes derivatives as `imag(f(x + iϵ)) / ϵ` where `ϵ = eps(T)`.
95+ This method provides machine precision accuracy without subtractive cancellation.
96+ """
2197@inline function compute_epsilon (:: Val{:complex} , x:: T , :: Union{Nothing,T} = nothing , :: Union{Nothing,T} = nothing , dir= nothing ) where T<: Real
2298 return eps (T)
2399end
24100
101+ """
102+ default_relstep(fdtype, ::Type{T}) where T<:Number
103+
104+ Compute the default relative step size for finite difference approximations.
105+
106+ Returns optimal default step sizes based on the finite difference method and
107+ numerical type, balancing truncation error and round-off error.
108+
109+ # Arguments
110+ - `fdtype`: Finite difference type (`Val(:forward)`, `Val(:central)`, `Val(:hcentral)`, etc.)
111+ - `::Type{T}`: Numerical type for which to compute the step size
112+
113+ # Returns
114+ - `sqrt(eps(real(T)))` for forward differences
115+ - `cbrt(eps(real(T)))` for central differences
116+ - `eps(T)^(1/4)` for Hessian central differences
117+ - `one(real(T))` for other types
118+
119+ # Notes
120+ These step sizes minimize the total error (truncation + round-off) for each method:
121+ - Forward differences have O(h) truncation error, optimal h ~ sqrt(eps)
122+ - Central differences have O(h²) truncation error, optimal h ~ eps^(1/3)
123+ - Hessian methods have O(h²) truncation error but involve more operations
124+ """
25125default_relstep (:: Type{V} , T) where V = default_relstep (V (), T)
26126@inline function default_relstep (:: Val{fdtype} , :: Type{T} ) where {fdtype,T<: Number }
27127 if fdtype== :forward
@@ -35,6 +135,19 @@ default_relstep(::Type{V}, T) where V = default_relstep(V(), T)
35135 end
36136end
37137
138+ """
139+ fdtype_error(::Type{T}=Float64) where T
140+
141+ Throw an informative error for unsupported finite difference type combinations.
142+
143+ # Arguments
144+ - `::Type{T}`: Return type of the function being differentiated
145+
146+ # Errors
147+ - For `Real` return types: suggests `Val{:forward}`, `Val{:central}`, `Val{:complex}`
148+ - For `Complex` return types: suggests `Val{:forward}`, `Val{:central}` (no complex step)
149+ - For other types: suggests the return type should be Real or Complex subtype
150+ """
38151function fdtype_error (:: Type{T} = Float64) where T
39152 if T<: Real
40153 error (" Unrecognized fdtype: valid values are Val{:forward}, Val{:central} and Val{:complex}." )
0 commit comments