Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LinearInterpolation handles collect(x) but not CubicSplineInterplation #383

Open
Jovansam opened this issue Oct 5, 2020 · 8 comments
Open

Comments

@Jovansam
Copy link

Jovansam commented Oct 5, 2020

CubicSplineInterpolation does not handle collect(), Yet LinearInterpolation does --- see minimal example below. Any suggestions on how to address this?

x = collect(1:0.1:5)
y = rand(length(x))
itp1 = LinearInterpolation(x, y; extrapolation_bc=Flat())
@show itp1(4)
@show itp1(6)
itp2 = CubicSplineInterpolation(x, y; extrapolation_bc=Flat())
@show itp2(4)
@show itp2(6)
@Jovansam Jovansam changed the title LinearInterpolation handles collected (x,y) but not CubicSplineInterplation LinearInterpolation handles collect(x) but not CubicSplineInterplation Oct 5, 2020
@JeffreySarnoff
Copy link
Member

The difficulty appears to be in convenience-constructors.jl,
where LinearInterpolation has these two signatures (and other[s])

LinearInterpolation(range::AbstractRange, vs::AbstractVector; _)
LinearInterpolation(range::AbstractVector, vs::AbstractVector; _)

CubicSplineInterpolation has only one of those signatures

CubicSplineInterpolation(::AbstractRange, ::AbstractVector; _)

Also providing QuadraticSplineInterpolation may make sense.

@mkitti
Copy link
Collaborator

mkitti commented Oct 5, 2020

New maintainer here. Part of the reason for this is that CubicSplineInterpolation requires a regular grid and having the AbstractRange guarantees that regularity.

Now we might be able to do something where we check to see if your AbstractVector can be transformed into a regular grid expressible as an AbstractRange, which would incur a performance penalty and may not be exact. It is usually much better if you the user do that transformation.

I just want to be clear on your needs though. Is the AbstractVector always going to be collected from an AbstractRange or is there a situation where the AbstractVector might actually be irregular?

@JeffreySarnoff
Copy link
Member

Speaking for myself, it is almost certain that AbstractVector will be irregular (nonuniformly spaced) some of the time. [glad to see you picking this up ⛵ ]

@mkitti
Copy link
Collaborator

mkitti commented Oct 5, 2020

If it is irregular, then it is not immediately clear what to do. In that case, this is a duplicate of #131 .

@Jovansam
Copy link
Author

Jovansam commented Oct 6, 2020

@mkitti thanks for picking this up. For now, my AbstractVector is from an AbstractRange.

@mkitti
Copy link
Collaborator

mkitti commented Oct 6, 2020

Here is the function to convert an AbstractVector to an AbstractRange:

using Statistics

function vector2range(r::AbstractVector)
    r_diff = @view(r[2:end]) .- @view(r[1:end-1])
    r_diff_mean = mean(r_diff)
    @assert all( r_diff .≈ r_diff_mean ) "Step between vector elements must be consistent"
    return range(r[1], step = r_diff_mean, stop = r[end])
end

Here's the usage:

julia> vector2range( [1, 2, 5, 9] )
ERROR: AssertionError: Step between vector elements must be consistent
Stacktrace:
 [1] vector2range(::Array{Int64,1}) at .\REPL[142]:4
 [2] top-level scope at REPL[143]:1

julia> vector2range( collect(3:0.5:353) )
3.0:0.5:353.0

@Jovansam
Copy link
Author

Jovansam commented Oct 6, 2020

Awesome! I was looking for something like this. Works great.

Alternatively, r_diff_mean = sum(r_diff)/length(r_diff) instead of pulling in Statistics

@mkitti
Copy link
Collaborator

mkitti commented Oct 6, 2020

Here are the extended methods:

julia> using Interpolations

julia> import Interpolations: CubicSplineInterpolation

julia> CubicSplineInterpolation(range::AbstractVector, vs::AbstractVector; kwargs...) =
           CubicSplineInterpolation(vector2range(range), vs ; kwargs...)
CubicSplineInterpolation (generic function with 4 methods)

julia> CubicSplineInterpolation(ranges::NTuple{N,AbstractVector}, vs::AbstractArray{T,N}; kwargs...) where {N,T} =
           CubicSplineInterpolation(vector2range.(ranges), vs ; kwargs...)
CubicSplineInterpolation (generic function with 4 methods)

and the usage:

julia> v = 1:0.1:10
1.0:0.1:10.0

julia> cv = collect(v);

julia> CubicSplineInterpolation( v, v .+ 1);

julia> CubicSplineInterpolation( cv, v .+ 1);

julia> CubicSplineInterpolation( (v,v) , v*v' );

julia> CubicSplineInterpolation( (cv,cv) , v*v' );

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants