JuliaDiff / FiniteDifferences.jl

High accuracy derivatives, estimated via numerical finite differences (formerly FDM.jl)
MIT License
298 stars 26 forks source link

max_range for single variables in multivariate functions #210

Closed paulc-git closed 1 year ago

paulc-git commented 1 year ago

Hi,

I stumbled upon a problem where I wanted to calculate a finite difference jacobian of a multivariate function. One parameter is around 1e-9 while the other parameters are all around 1. When calculating the derivative with respect to the small parameter the function errors, because it is not defined far away from 1e-9.

Now I can set a limit on the amount of variation that is done to e.g. 1e-9. Then, the derivative w.r.t. the small parameter works, but w.r.t. the other parameters it does not, because the variation is to small (i.e. the resulting derivative is just wrong for the "large" parameters).

Is there a way to set a max_range only for a single parameter?

PS: This is the first issue I post, so don't hesitate to correct me if I did something wrong.

wesselb commented 1 year ago

Hey @paulc-git! Thanks for opening an issue. :)

I think you're right that there is currently no way to set a different max_range for each input variable. However, there might be a simple workaround. Namely, you could define a new function which rescales the small parameters to also be on the order of one. Afterwards, you just need to appropriately adjust the Jacobian. Here's an example:

julia> f(x) = [sin(123456x[1]), sin(x[2])];  # `x[1]` must be very small!

julia> m = central_fdm(5, 1);

julia> x = [0.0, 0.0];

julia> jacobian(m, f, x)[1]   # Ouch, not accurate!

2×2 Matrix{Float64}:
 1.11107e5  0.0
 0.0        1.0

julia> f_rescaled(x) = f([x[1] / 1e6, x[2]]);  # Fix scale of first variable.

julia> jac = jacobian(m, f_rescaled, x)[1];

julia> jac[1, :] *= 1e6; # Undo the rescaling

julia> jac  # This is now what we are after
2×2 Matrix{Float64}:
 123456.0  0.0
      0.0  1.0
paulc-git commented 1 year ago

Hey @wesselb. Thanks for the quick reply!

I also thought about rescaling, but I forgot to scale the jacobian back afterwards... Of course it did not work then.

So this is an easy workaround. Thanks for taking the time to reply!

wesselb commented 1 year ago

No problem at all! I’m glad to hear that this workaround suffices. :) I’m closing the issue now, but feel free to reopen it should you run into further issues!