Interpolations.jl icon indicating copy to clipboard operation
Interpolations.jl copied to clipboard

Weight computation for scaled interpolation

Open DylanMMarques opened this issue 3 years ago • 11 comments

Hello,

I am working with Interpolations.jl and I am using the weight computation feature. However, the results are not what I was expecting. This code works fine if the interpolation is not scaled but it is not correct due to the scale step. Is it possible to calculate the weight for a scaled interpolation? Or does the weight calculation interface works differently than this with a scaled interpolation?

using Interpolations
x_X = range(0, 100., length = 10)
y = 1:length(x_X)
itp = interpolate(y, BSpline(Linear()))
itp_scaled = scale(itp, (x_X))

wis = Interpolations.weightedindexes((Interpolations.value_weights,), Interpolations.itpinfo(itp_scale)..., (2.5,))
y[wis[1]] # 2.5

itp_scaled(2.5) # 1.225

Thanks

DylanMMarques avatar Jan 16 '22 18:01 DylanMMarques

All scale interpolation does is scale the input: https://github.com/JuliaMath/Interpolations.jl/blob/af35e779a7c39e540555d2c35bc1b2ccde242bc2/src/scaling/scaling.jl#L102-L108

It does not change the weights.

mkitti avatar Jan 16 '22 21:01 mkitti

The scale function stretch the x-axis of the interpolation. Therefore, the weights are dependent on the scale because the weights are dependent on the x-axis of the interpolated function. The output of the function:

wis = Interpolations.weightedindexes((Interpolations.value_weights,), Interpolations.itpinfo(itp_scale)..., (2.5,))
# wis = (Interpolations.WeightedAdjIndex{2, Float64}(2, (0.5, 0.5)),)

The itp_scale is: f(0) = y[1] and f(x_X[1]) = y[2], so the weights of x = 2.5 should be between y[1] and y[2], not y[2] and y[3] as the value of wis is.

DylanMMarques avatar Jan 17 '22 21:01 DylanMMarques

Are you asking how it currently works or are you suggesting an improvement? Interpolations.weightedindexes is not meant as a public interface.

mkitti avatar Jan 18 '22 08:01 mkitti

I am tying to confirm that I understand how it works because, to me, it doesn't seem to work properly with an itp scaled by a StepRangeLength (the function is probably not meant for that). I analysed the code with more detail and this makes sense as Interpolation.itpinfo removes any reference about the scaling part.

If you agree with this, I would ask if there is any way of computing the weighted indexes of a scaled interpolation. If not, I am suggesting an improvement.

DylanMMarques avatar Jan 18 '22 09:01 DylanMMarques

Correct. The underlying Interpolation has no idea it is being scaled. What you would want to do is implement additional methods on ScaledInterpolation directly.

mkitti avatar Jan 18 '22 13:01 mkitti

I am interested on the weights as I need to calculate an interpolation based on a (very sparse) matrix. This matrix is constructed based on the weights. For my application, it would be good to have a public interface of the weights that would work for any interpolation. Do you feel that such interface could be useful to more people? Or do you feel that the application of such interface is too small and might not be worth?

DylanMMarques avatar Jan 20 '22 20:01 DylanMMarques

It is possible. What would be the most consistent way to calculate the scaled weights from non-scaled weights? Would you be interested in submitting a pull request to implement Interpolations.weightedindexes on ScaledInterpolation?

mkitti avatar Jan 21 '22 00:01 mkitti

Sure, I think that something like this should work nicely:

using Interpolations
x1 = range(0, 20, length = 11)
x2 = range(0, 20, length = 11)
y = x1 .+ x2'
itp = interpolate(y, BSpline(Linear()))
itp = scale(itp, x1, x2)

function weightedindexes(arg, scaleditp::ScaledInterpolation, x::NTuple{N}) where {N}
    ind = ntuple(i-> (x[i] - first(scaleditp.ranges[i])) / step(scaleditp.ranges[i]) + 1, N)
    return Interpolations.weightedindexes(arg, Interpolations.itpinfo(scaleditp)..., ind)
end

x = (5.4, 5.4)
wis = weightedindexes((Interpolations.value_weights,), itp, x)
y[wis...] == itp(x...) 

What do you think?

DylanMMarques avatar Jan 21 '22 19:01 DylanMMarques

This roughly looks fine to me. Could you turn this into a pull request?

mkitti avatar Jan 24 '22 07:01 mkitti

I ran a few tests for the algorithm and it does not work for Interpolations.gradient_weights. For the gradients, the weight must be divided by step(scaleditp.ranges). I tried to do this but I am not very familiar with Interpolations.jl internal interface unfortunately, so it is quite challenging to me doing that. Do you think that you could update the code to return the correct values for the Interpolations.gradient_weights?

DylanMMarques avatar Jan 30 '22 18:01 DylanMMarques

I would be interested in this as well. My use case is that I want to find the contributing points and their weights, so I don't need gradient_weights. Maybe I find time to make a PR

koehlerson avatar Apr 12 '22 08:04 koehlerson