Skip to content

Commit

Permalink
Support inverting the integral of ConstantInterpolation
Browse files Browse the repository at this point in the history
  • Loading branch information
SouthEndMusic committed Jul 5, 2024
1 parent 3036d8c commit e568de7
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 8 deletions.
52 changes: 44 additions & 8 deletions src/integral_inverses.jl
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
abstract type AbstractIntegralInverseInterpolation{T} <: AbstractInterpolation{T} end

struct LinearInterpolationIntInv{tType, IType, itpType, T} <:
_integral(A::AbstractIntegralInverseInterpolation, idx, t) = throw(IntegralNotFoundError())
invert_integral(A::AbstractInterpolation) = throw(IntegralInverseNotFoundError())

struct LinearInterpolationIntInv{uType, tType, itpType, T} <:
AbstractIntegralInverseInterpolation{T}
u::tType
t::IType
u::uType
t::tType
extrapolate::Bool
idx_prev::Base.RefValue{Int}
itp::itpType
Expand All @@ -17,21 +20,54 @@ function invertible_integral(A::LinearInterpolation{<:AbstractVector{<:Number}})
return all(A.u .> 0)
end

invert_integral(A::AbstractInterpolation) = throw(IntegralInverseNotFoundError())

function invert_integral(A::LinearInterpolation{<:AbstractVector{<:Number}})
!invertible_integral(A) && throw(IntegralNotInvertibleError())
return LinearInterpolationIntInv(A.t, A.I, A)
end

function _interpolate(
A::LinearInterpolationIntInv{<:AbstractVector{<:Number}}, t::Number, iguess)
(; itp) = A
idx = get_idx(A.t, t, iguess)
Δt = t - A.t[idx]
# TODO: Get from parameter cache: itp.p.slope[idx]
slope = (itp.u[idx + 1] - itp.u[idx]) / (itp.t[idx + 1] - itp.t[idx])
x = itp.u[idx]
slope = (A.itp.u[idx + 1] - A.itp.u[idx]) / (A.itp.t[idx + 1] - A.itp.t[idx])
x = A.itp.u[idx]
u = A.u[idx] + 2Δt / (x + sqrt(x^2 + 2slope * Δt))
u, idx
end

struct ConstantInterpolationIntInv{uType, tType, itpType, T} <:
AbstractIntegralInverseInterpolation{T}
u::uType
t::tType
extrapolate::Bool
idx_prev::Base.RefValue{Int}
itp::itpType
function ConstantInterpolationIntInv(u, t, A)
new{typeof(u), typeof(t), typeof(A), eltype(u)}(
u, t, A.extrapolate, Ref(1), A
)
end
end

function invertible_integral(A::ConstantInterpolation{<:AbstractVector{<:Number}})
return all(A.u .> 0)
end

function invert_integral(A::ConstantInterpolation{<:AbstractVector{<:Number}})
!invertible_integral(A) && throw(IntegralNotInvertibleError())
return ConstantInterpolationIntInv(A.t, A.I, A)
end

function _interpolate(
A::ConstantInterpolationIntInv{<:AbstractVector{<:Number}}, t::Number, iguess)
idx = get_idx(A.t, t, iguess; ub_shift = 0)
if A.itp.dir === :left
# :left means that value to the left is used for interpolation
idx_ = get_idx(A.t, t, idx; lb = 1, ub_shift = 0)
else
# :right means that value to the right is used for interpolation
idx_ = get_idx(A.t, t, idx; side = :first, lb = 1, ub_shift = 0)
end
A.u[idx] + (t - A.t[idx]) / A.itp.u[idx_], idx
end
16 changes: 16 additions & 0 deletions test/integral_inverse_tests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,19 @@ end
A = LinearInterpolation(u, t)
@test_throws DataInterpolations.IntegralNotInvertibleError invert_integral(A)
end

@testset "Constant Interpolation" begin
t = collect(1:5)
u = [1.0, 1.0, 2.0, 4.0, 3.0]
test_integral_inverses(ConstantInterpolation; args = [u, t])
test_integral_inverses(ConstantInterpolation; args = [u, t], kwargs = [:dir => :right])

u = [1.0, -1.0, 2.0, 4.0, 3.0]
A = ConstantInterpolation(u, t)
@test_throws DataInterpolations.IntegralNotInvertibleError invert_integral(A)
end

t = collect(1:5)
u = [1.0, 1.0, 2.0, 4.0, 3.0]
A = QuadraticInterpolation(u, t)
@test_throws DataInterpolations.IntegralInverseNotFoundError invert_integral(A)

0 comments on commit e568de7

Please sign in to comment.