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

Add extrapolation types periodic and reflective #363

Open
wants to merge 22 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ uuid = "82cc6244-b520-54b8-b5a6-8a565e85f1d0"
version = "6.6.0"

[deps]
EnumX = "4e289a0a-7415-4d19-859d-a7e5c4648b56"
FindFirstFunctions = "64ca27bc-2ba2-4a57-88aa-44e436879224"
ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
Expand All @@ -27,6 +28,7 @@ DataInterpolationsSymbolicsExt = "Symbolics"
Aqua = "0.8"
BenchmarkTools = "1"
ChainRulesCore = "1.24"
EnumX = "1.0.4"
FindFirstFunctions = "1.3"
FiniteDifferences = "0.12.31"
ForwardDiff = "0.10.36"
Expand Down
3 changes: 2 additions & 1 deletion docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ makedocs(modules = [DataInterpolations],
linkcheck = true,
format = Documenter.HTML(assets = ["assets/favicon.ico"],
canonical = "https://docs.sciml.ai/DataInterpolations/stable/"),
pages = ["index.md", "Methods" => "methods.md",
pages = ["index.md", "Interpolation methods" => "methods.md",
"Extrapolation methods" => "extrapolation_methods.md",
"Interface" => "interface.md", "Using with Symbolics/ModelingToolkit" => "symbolics.md",
"Manual" => "manual.md", "Inverting Integrals" => "inverting_integrals.md"])

Expand Down
90 changes: 90 additions & 0 deletions docs/src/extrapolation_methods.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# Extrapolation methods

We will use the following interpolation to demonstrate the various extrapolation methods.

```@example tutorial
using DataInterpolations, Plots

u = [0.86, 0.65, 0.44, 0.76, 0.73]
t = [0.0022, 0.68, 1.41, 2.22, 2.46]
t_eval_left = range(-1, first(t), length = 25)
t_eval_right = range(last(t), 3.5, length = 25)
A = QuadraticSpline(u, t)
plot(A)
```

Extrapolation behavior can be set left and right of the data simultaneously with the `extension` keyword, or left and right separately with the `extrapolation_left` and `extrapolation_right` keywords respectively.

## `ExtrapolationType.None`

This extrapolation type will throw an error when the input `t` is beyond the data in the specified direction.

## `ExtrapolationType.Constant`

This extrapolation type extends the interpolation with the boundary values of the data `u`.

```@example tutorial
A = QuadraticSpline(u, t; extrapolation = ExtrapolationType.Constant)
plot(A)
plot!(t_eval_left, A.(t_eval_left); label = "extrapolation left")
plot!(t_eval_right, A.(t_eval_right); label = "extrapolation right")
```

## `ExtrapolationType.Linear`

This extrapolation type extends the interpolation with a linear continuation of the interpolation, making it $C^1$ smooth at the data boundaries.

```@example tutorial
A = QuadraticSpline(u, t; extrapolation = ExtrapolationType.Linear)
plot(A)
plot!(t_eval_left, A.(t_eval_left); label = "extrapolation left")
plot!(t_eval_right, A.(t_eval_right); label = "extrapolation right")
```

## `ExtrapolationType.Extension`

This extrapolation type extends the interpolation with a continuation of the expression for the interpolation at the boundary intervals for maximum smoothness.

```@example tutorial
A = QuadraticSpline(u, t; extrapolation = ExtrapolationType.Extension)
plot(A)
plot!(t_eval_left, A.(t_eval_left); label = "extrapolation down")
plot!(t_eval_right, A.(t_eval_right); label = "extrapolation up")
```

## `ExtrapolationType.Periodic`

this extrapolation type extends the interpolation such that `A(t + T) == A(t)` for all `t`, where the period is given by `T = last(A.t) - first(A.t)`.

```@example tutorial
T = last(A.t) - first(A.t)
t_eval_left = range(first(t) - 2T, first(t), length = 100)
t_eval_right = range(last(t), last(t) + 2T, length = 100)
A = QuadraticSpline(u, t; extrapolation = ExtrapolationType.Periodic)
plot(A)
plot!(t_eval_left, A.(t_eval_left); label = "extrapolation down")
plot!(t_eval_right, A.(t_eval_right); label = "extrapolation up")
```

## `ExtrapolationType.Reflective`

this extrapolation type extends the interpolation such that `A(t_ + t) == A(t_ - t)` for all `t_, t` such that `(t_ - first(A.t)) % T == 0` and `0 < t < T`, where `T = last(A.t) - first(A.t)`.

```@example tutorial
A = QuadraticSpline(u, t; extrapolation = ExtrapolationType.Reflective)
plot(A)
plot!(t_eval_left, A.(t_eval_left); label = "extrapolation down")
plot!(t_eval_right, A.(t_eval_right); label = "extrapolation up")
```

## Mixed extrapolation

You can also have different extrapolation types left and right of the data.

```@example tutorial
A = QuadraticSpline(u, t; extrapolation_left = ExtrapolationType.Reflective,
extrapolation_right = ExtrapolationType.Periodic)
plot(A)
plot!(t_eval_left, A.(t_eval_left); label = "extrapolation left")
plot!(t_eval_right, A.(t_eval_right); label = "extrapolation right")
```
4 changes: 2 additions & 2 deletions docs/src/interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ t = [0.0, 62.25, 109.66, 162.66, 205.8, 252.3]

All interpolation methods return an object from which we can compute the value of the dependent variable at any time point.

We will use the `CubicSpline` method for demonstration, but the API is the same for all the methods. We can also pass the `extrapolate = true` keyword if we want to allow the interpolation to go beyond the range of the timepoints. The default value is `extrapolate = false`.
We will use the `CubicSpline` method for demonstration, but the API is the same for all the methods. We can also pass the `extrapolation = ExtrapolationType.Extension` keyword if we want to allow the interpolation to go beyond the range of the timepoints in the positive `t` direction. The default value is `extrapolation = ExtrapolationType.None`. For more information on extrapolation see [Extrapolation methods](extrapolation_methods.md).

```@example interface
A1 = CubicSpline(u, t)

# For interpolation do, A(t)
A1(100.0)

A2 = CubicSpline(u, t; extrapolate = true)
A2 = CubicSpline(u, t; extrapolation = ExtrapolationType.Extension)

# Extrapolation
A2(300.0)
Expand Down
70 changes: 47 additions & 23 deletions ext/DataInterpolationsRegularizationToolsExt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,17 @@ A = RegularizationSmooth(u, t, t̂, wls, wr, d; λ = 1.0, alg = :gcv_svd)
"""
function RegularizationSmooth(u::AbstractVector, t::AbstractVector, t̂::AbstractVector,
wls::AbstractVector, wr::AbstractVector, d::Int = 2;
λ::Real = 1.0, alg::Symbol = :gcv_svd, extrapolate::Bool = false)
λ::Real = 1.0, alg::Symbol = :gcv_svd,
extrapolation_left::ExtrapolationType.T = ExtrapolationType.None,
extrapolation_right::ExtrapolationType.T = ExtrapolationType.None)
u, t = munge_data(u, t)
M = _mapping_matrix(t̂, t)
Wls½ = LA.diagm(sqrt.(wls))
Wr½ = LA.diagm(sqrt.(wr))
û, λ, Aitp = _reg_smooth_solve(u, t̂, d, M, Wls½, Wr½, λ, alg, extrapolate)
RegularizationSmooth(u, û, t, t̂, wls, wr, d, λ, alg, Aitp, extrapolate)
û, λ, Aitp = _reg_smooth_solve(
u, t̂, d, M, Wls½, Wr½, λ, alg, extrapolation_left, extrapolation_right)
RegularizationSmooth(
u, û, t, t̂, wls, wr, d, λ, alg, Aitp, extrapolation_left, extrapolation_right)
end
"""
Direct smoothing, no `t̂` or weights
Expand All @@ -86,14 +90,16 @@ A = RegularizationSmooth(u, t, d; λ = 1.0, alg = :gcv_svd, extrapolate = false)
"""
function RegularizationSmooth(u::AbstractVector, t::AbstractVector, d::Int = 2;
λ::Real = 1.0,
alg::Symbol = :gcv_svd, extrapolate::Bool = false)
alg::Symbol = :gcv_svd, extrapolation_left::ExtrapolationType.T = ExtrapolationType.None,
extrapolation_right::ExtrapolationType.T = ExtrapolationType.None)
u, t = munge_data(u, t)
t̂ = t
N = length(t)
M = Array{Float64}(LA.I, N, N)
Wls½ = Array{Float64}(LA.I, N, N)
Wr½ = Array{Float64}(LA.I, N - d, N - d)
û, λ, Aitp = _reg_smooth_solve(u, t̂, d, M, Wls½, Wr½, λ, alg, extrapolate)
û, λ, Aitp = _reg_smooth_solve(
u, t̂, d, M, Wls½, Wr½, λ, alg, extrapolation_left, extrapolation_right)
RegularizationSmooth(u,
û,
t,
Expand All @@ -104,7 +110,8 @@ function RegularizationSmooth(u::AbstractVector, t::AbstractVector, d::Int = 2;
λ,
alg,
Aitp,
extrapolate)
extrapolation_left,
extrapolation_right)
end
"""
`t̂` provided, no weights
Expand All @@ -115,13 +122,15 @@ A = RegularizationSmooth(u, t, t̂, d; λ = 1.0, alg = :gcv_svd, extrapolate = f
"""
function RegularizationSmooth(u::AbstractVector, t::AbstractVector, t̂::AbstractVector,
d::Int = 2; λ::Real = 1.0, alg::Symbol = :gcv_svd,
extrapolate::Bool = false)
extrapolation_left::ExtrapolationType.T = ExtrapolationType.None,
extrapolation_right::ExtrapolationType.T = ExtrapolationType.None)
u, t = munge_data(u, t)
N, N̂ = length(t), length(t̂)
M = _mapping_matrix(t̂, t)
Wls½ = Array{Float64}(LA.I, N, N)
Wr½ = Array{Float64}(LA.I, N̂ - d, N̂ - d)
û, λ, Aitp = _reg_smooth_solve(u, t̂, d, M, Wls½, Wr½, λ, alg, extrapolate)
û, λ, Aitp = _reg_smooth_solve(
u, t̂, d, M, Wls½, Wr½, λ, alg, extrapolation_left, extrapolation_right)
RegularizationSmooth(u,
û,
t,
Expand All @@ -132,7 +141,8 @@ function RegularizationSmooth(u::AbstractVector, t::AbstractVector, t̂::Abstrac
λ,
alg,
Aitp,
extrapolate)
extrapolation_left,
extrapolation_right)
end
"""
`t̂` and `wls` provided
Expand All @@ -143,13 +153,15 @@ A = RegularizationSmooth(u, t, t̂, wls, d; λ = 1.0, alg = :gcv_svd, extrapolat
"""
function RegularizationSmooth(u::AbstractVector, t::AbstractVector, t̂::AbstractVector,
wls::AbstractVector, d::Int = 2; λ::Real = 1.0,
alg::Symbol = :gcv_svd, extrapolate::Bool = false)
alg::Symbol = :gcv_svd, extrapolation_left::ExtrapolationType.T = ExtrapolationType.None,
extrapolation_right::ExtrapolationType.T = ExtrapolationType.None)
u, t = munge_data(u, t)
N, N̂ = length(t), length(t̂)
M = _mapping_matrix(t̂, t)
Wls½ = LA.diagm(sqrt.(wls))
Wr½ = Array{Float64}(LA.I, N̂ - d, N̂ - d)
û, λ, Aitp = _reg_smooth_solve(u, t̂, d, M, Wls½, Wr½, λ, alg, extrapolate)
û, λ, Aitp = _reg_smooth_solve(
u, t̂, d, M, Wls½, Wr½, λ, alg, extrapolation_left, extrapolation_right)
RegularizationSmooth(u,
û,
t,
Expand All @@ -160,7 +172,8 @@ function RegularizationSmooth(u::AbstractVector, t::AbstractVector, t̂::Abstrac
λ,
alg,
Aitp,
extrapolate)
extrapolation_left,
extrapolation_right)
end
"""
`wls` provided, no `t̂`
Expand All @@ -172,14 +185,16 @@ A = RegularizationSmooth(
"""
function RegularizationSmooth(u::AbstractVector, t::AbstractVector, t̂::Nothing,
wls::AbstractVector, d::Int = 2; λ::Real = 1.0,
alg::Symbol = :gcv_svd, extrapolate::Bool = false)
alg::Symbol = :gcv_svd, extrapolation_left::ExtrapolationType.T = ExtrapolationType.None,
extrapolation_right::ExtrapolationType.T = ExtrapolationType.None)
u, t = munge_data(u, t)
t̂ = t
N = length(t)
M = Array{Float64}(LA.I, N, N)
Wls½ = LA.diagm(sqrt.(wls))
Wr½ = Array{Float64}(LA.I, N - d, N - d)
û, λ, Aitp = _reg_smooth_solve(u, t̂, d, M, Wls½, Wr½, λ, alg, extrapolate)
û, λ, Aitp = _reg_smooth_solve(
u, t̂, d, M, Wls½, Wr½, λ, alg, extrapolation_left, extrapolation_right)
RegularizationSmooth(u,
û,
t,
Expand All @@ -190,7 +205,8 @@ function RegularizationSmooth(u::AbstractVector, t::AbstractVector, t̂::Nothing
λ,
alg,
Aitp,
extrapolate)
extrapolation_left,
extrapolation_right)
end
"""
`wls` and `wr` provided, no `t̂`
Expand All @@ -202,14 +218,17 @@ A = RegularizationSmooth(
"""
function RegularizationSmooth(u::AbstractVector, t::AbstractVector, t̂::Nothing,
wls::AbstractVector, wr::AbstractVector, d::Int = 2;
λ::Real = 1.0, alg::Symbol = :gcv_svd, extrapolate::Bool = false)
λ::Real = 1.0, alg::Symbol = :gcv_svd,
extrapolation_left::ExtrapolationType.T = ExtrapolationType.None,
extrapolation_right::ExtrapolationType.T = ExtrapolationType.None)
u, t = munge_data(u, t)
t̂ = t
N = length(t)
M = Array{Float64}(LA.I, N, N)
Wls½ = LA.diagm(sqrt.(wls))
Wr½ = LA.diagm(sqrt.(wr))
û, λ, Aitp = _reg_smooth_solve(u, t̂, d, M, Wls½, Wr½, λ, alg, extrapolate)
û, λ, Aitp = _reg_smooth_solve(
u, t̂, d, M, Wls½, Wr½, λ, alg, extrapolation_left, extrapolation_right)
RegularizationSmooth(u,
û,
t,
Expand All @@ -220,7 +239,8 @@ function RegularizationSmooth(u::AbstractVector, t::AbstractVector, t̂::Nothing
λ,
alg,
Aitp,
extrapolate)
extrapolation_left,
extrapolation_right)
end
"""
Keyword provided for `wls`, no `t̂`
Expand All @@ -232,15 +252,17 @@ A = RegularizationSmooth(
"""
function RegularizationSmooth(u::AbstractVector, t::AbstractVector, t̂::Nothing,
wls::Symbol, d::Int = 2; λ::Real = 1.0, alg::Symbol = :gcv_svd,
extrapolate::Bool = false)
extrapolation_left::ExtrapolationType.T = ExtrapolationType.None,
extrapolation_right::ExtrapolationType.T = ExtrapolationType.None)
u, t = munge_data(u, t)
t̂ = t
N = length(t)
M = Array{Float64}(LA.I, N, N)
wls, wr = _weighting_by_kw(t, d, wls)
Wls½ = LA.diagm(sqrt.(wls))
Wr½ = LA.diagm(sqrt.(wr))
û, λ, Aitp = _reg_smooth_solve(u, t̂, d, M, Wls½, Wr½, λ, alg, extrapolate)
û, λ, Aitp = _reg_smooth_solve(
u, t̂, d, M, Wls½, Wr½, λ, alg, extrapolation_left, extrapolation_right)
RegularizationSmooth(u,
û,
t,
Expand All @@ -251,7 +273,8 @@ function RegularizationSmooth(u::AbstractVector, t::AbstractVector, t̂::Nothing
λ,
alg,
Aitp,
extrapolate)
extrapolation_left,
extrapolation_right)
end
# """ t̂ provided and keyword for wls _TBD_ """
# function RegularizationSmooth(u::AbstractVector, t::AbstractVector, t̂::AbstractVector,
Expand All @@ -262,7 +285,8 @@ Solve for the smoothed dependent variables and create spline interpolator
"""
function _reg_smooth_solve(
u::AbstractVector, t̂::AbstractVector, d::Int, M::AbstractMatrix,
Wls½::AbstractMatrix, Wr½::AbstractMatrix, λ::Real, alg::Symbol, extrapolate::Bool)
Wls½::AbstractMatrix, Wr½::AbstractMatrix, λ::Real, alg::Symbol,
extrapolation_left::ExtrapolationType.T, extrapolation_right::ExtrapolationType.T)
λ = float(λ) # `float` expected by RT
D = _derivative_matrix(t̂, d)
Ψ = RT.setupRegularizationProblem(Wls½ * M, Wr½ * D)
Expand All @@ -279,7 +303,7 @@ function _reg_smooth_solve(
û = result.x
λ = result.λ
end
Aitp = CubicSpline(û, t̂; extrapolate)
Aitp = CubicSpline(û, t̂; extrapolation_left, extrapolation_right)
# It seems logical to use B-Spline of order d+1, but I am unsure if theory supports the
# extra computational cost, JJS 12/25/21
#Aitp = BSplineInterpolation(û,t̂,d+1,:ArcLen,:Average)
Expand Down
Loading
Loading