Skip to content

Commit 63f1b79

Browse files
committed
Re-enable commented-out tests and fix issues
1 parent 69dc2c5 commit 63f1b79

25 files changed

+519
-666
lines changed

src/Interpolations.jl

Lines changed: 56 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export
2020
Natural,
2121
InPlace,
2222
InPlaceQ,
23+
Throw,
2324

2425
LinearInterpolation,
2526
CubicSplineInterpolation
@@ -199,7 +200,50 @@ weights(wi::WeightedIndex) = wi.weights
199200
indexes(wi::WeightedAdjIndex) = wi.istart
200201
indexes(wi::WeightedArbIndex) = wi.indexes
201202

203+
# Make them iterable just like numbers are
204+
Base.iterate(x::WeightedIndex) = (x, nothing)
205+
Base.iterate(x::WeightedIndex, ::Any) = nothing
206+
Base.isempty(x::WeightedIndex) = false
207+
Base.length(x::WeightedIndex) = 1
208+
209+
### Indexing with WeightedIndex
210+
211+
# We inject indexing with `WeightedIndex` at a non-exported point in the dispatch heirarchy.
212+
# This is to avoid ambiguities with methods that specialize on the array type rather than
213+
# the index type.
214+
Base.to_indices(A, I::Tuple{Vararg{Union{Int,WeightedIndex}}}) = I
215+
@propagate_inbounds Base._getindex(::IndexLinear, A::AbstractVector, i::Int) = getindex(A, i) # ambiguity resolution
216+
@inline function Base._getindex(::IndexStyle, A::AbstractArray{T,N}, I::Vararg{Union{Int,WeightedIndex},N}) where {T,N}
217+
interp_getindex(A, I)
218+
end
202219

220+
# This follows a "move processed indexes to the back" strategy, so J contains the yet-to-be-processed
221+
# indexes and I all the processed indexes.
222+
interp_getindex(A::AbstractArray{T,N}, J::Tuple{Int,Vararg{Any,L}}, I::Vararg{Int,M}) where {T,N,L,M} =
223+
interp_getindex(A, Base.tail(J), I..., J[1])
224+
function interp_getindex(A::AbstractArray{T,N}, J::Tuple{WeightedIndex,Vararg{Any,L}}, I::Vararg{Int,M}) where {T,N,L,M}
225+
wi = J[1]
226+
_interp_getindex(A, indexes(wi), weights(wi), Base.tail(J), I...)
227+
end
228+
interp_getindex(A::AbstractArray{T,N}, ::Tuple{}, I::Vararg{Int,N}) where {T,N} = # termination
229+
@inbounds A[I...] # all bounds-checks have already happened
230+
231+
## Handle expansion of a single dimension
232+
# version for WeightedAdjIndex
233+
@inline _interp_getindex(A, i::Int, weights::NTuple{K,Number}, rest, I::Vararg{Int,M}) where {M,K} =
234+
weights[1] * interp_getindex(A, rest, I..., i) + _interp_getindex(A, i+1, Base.tail(weights), rest, I...)
235+
@inline _interp_getindex(A, i::Int, weights::Tuple{Number}, rest, I::Vararg{Int,M}) where M =
236+
weights[1] * interp_getindex(A, rest, I..., i)
237+
_interp_getindex(A, i::Int, weights::Tuple{}, rest, I::Vararg{Int,M}) where M =
238+
error("exhausted weights, this should never happen") # helps inference
239+
240+
# version for WeightedArbIndex
241+
@inline _interp_getindex(A, indexes::NTuple{K,Int}, weights::NTuple{K,Number}, rest, I::Vararg{Int,M}) where {M,K} =
242+
weights[1] * interp_getindex(A, rest, I..., indexes[1]) + _interp_getindex(A, Base.tail(indexes), Base.tail(weights), rest, I...)
243+
@inline _interp_getindex(A, indexes::Tuple{Int}, weights::Tuple{Number}, rest, I::Vararg{Int,M}) where M =
244+
weights[1] * interp_getindex(A, rest, I..., indexes[1])
245+
_interp_getindex(A, indexes::Tuple{}, weights::Tuple{}, rest, I::Vararg{Int,M}) where M =
246+
error("exhausted weights and indexes, this should never happen")
203247

204248
"""
205249
w = value_weights(degree, δx)
@@ -268,7 +312,9 @@ Base.to_index(::AbstractInterpolation, x::Number) = x
268312
# itp(to_indices(itp, x)...)
269313
# end
270314
function gradient(itp::AbstractInterpolation, x::Vararg{UnexpandedIndexTypes})
271-
gradient(itp, to_indices(itp, x)...)
315+
xi = to_indices(itp, x)
316+
xi == x && error("gradient of $itp not supported for position $x")
317+
gradient(itp, xi...)
272318
end
273319
function gradient!(dest, itp::AbstractInterpolation, x::Vararg{UnexpandedIndexTypes})
274320
gradient!(dest, itp, to_indices(itp, x)...)
@@ -283,12 +329,15 @@ end
283329
# @inline function (itp::AbstractInterpolation)(x::Vararg{ExpandedIndexTypes})
284330
# itp.(Iterators.product(x...))
285331
# end
286-
function gradient(itp::AbstractInterpolation, x::Vararg{ExpandedIndexTypes})
287-
map(y->gradient(itp, y), Iterators.product(x...))
288-
end
289-
function hessian(itp::AbstractInterpolation, x::Vararg{ExpandedIndexTypes})
290-
map(y->hessian(itp, y), Iterators.product(x...))
291-
end
332+
# function gradient(itp::AbstractInterpolation, x::Vararg{ExpandedIndexTypes})
333+
# map(y->tgradient(itp, y), Iterators.product(x...))
334+
# end
335+
# function hessian(itp::AbstractInterpolation, x::Vararg{ExpandedIndexTypes})
336+
# map(y->thessian(itp, y), Iterators.product(x...))
337+
# end
338+
#
339+
# tgradient(itp, y) = gradient(itp, y...)
340+
# thessian(itp, y) = hessian(itp, y...)
292341

293342
# getindex is supported only for Integer indices (deliberately)
294343
import Base: getindex

src/b-splines/indexing.jl

Lines changed: 13 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,3 @@
1-
### Indexing with WeightedIndex
2-
3-
# We inject indexing with `WeightedIndex` at a non-exported point in the dispatch heirarchy.
4-
# This is to avoid ambiguities with methods that specialize on the array type rather than
5-
# the index type.
6-
Base.to_indices(A, I::Tuple{Vararg{Union{Int,WeightedIndex}}}) = I
7-
@propagate_inbounds Base._getindex(::IndexLinear, A::AbstractVector, i::Int) = getindex(A, i) # ambiguity resolution
8-
@inline function Base._getindex(::IndexStyle, A::AbstractArray{T,N}, I::Vararg{Union{Int,WeightedIndex},N}) where {T,N}
9-
interp_getindex(A, I)
10-
end
11-
12-
# This follows a "move processed indexes to the back" strategy, so J contains the yet-to-be-processed
13-
# indexes and I all the processed indexes.
14-
interp_getindex(A::AbstractArray{T,N}, J::Tuple{Int,Vararg{Any,L}}, I::Vararg{Int,M}) where {T,N,L,M} =
15-
interp_getindex(A, Base.tail(J), I..., J[1])
16-
function interp_getindex(A::AbstractArray{T,N}, J::Tuple{WeightedIndex,Vararg{Any,L}}, I::Vararg{Int,M}) where {T,N,L,M}
17-
wi = J[1]
18-
_interp_getindex(A, indexes(wi), weights(wi), Base.tail(J), I...)
19-
end
20-
interp_getindex(A::AbstractArray{T,N}, ::Tuple{}, I::Vararg{Int,N}) where {T,N} = # termination
21-
@inbounds A[I...] # all bounds-checks have already happened
22-
23-
# version for WeightedAdjIndex
24-
_interp_getindex(A, i::Int, weights::NTuple{K,Number}, rest, I::Vararg{Int,M}) where {M,K} =
25-
weights[1] * interp_getindex(A, rest, I..., i) + _interp_getindex(A, i+1, Base.tail(weights), rest, I...)
26-
_interp_getindex(A, i::Int, weights::Tuple{Number}, rest, I::Vararg{Int,M}) where M =
27-
weights[1] * interp_getindex(A, rest, I..., i)
28-
_interp_getindex(A, i::Int, weights::Tuple{}, rest, I::Vararg{Int,M}) where M =
29-
error("exhausted weights, this should never happen") # helps inference
30-
31-
# version for WeightedArbIndex
32-
_interp_getindex(A, indexes::NTuple{K,Int}, weights::NTuple{K,Number}, rest, I::Vararg{Int,M}) where {M,K} =
33-
weights[1] * interp_getindex(A, rest, I..., indexes[1]) + _interp_getindex(A, Base.tail(indexes), Base.tail(weights), rest, I...)
34-
_interp_getindex(A, indexes::Tuple{Int}, weights::Tuple{Number}, rest, I::Vararg{Int,M}) where M =
35-
weights[1] * interp_getindex(A, rest, I..., indexes[1])
36-
_interp_getindex(A, indexes::Tuple{}, weights::Tuple{}, rest, I::Vararg{Int,M}) where M =
37-
error("exhausted weights and indexes, this should never happen")
38-
39-
401
### Primary evaluation entry points (itp(x...), gradient(itp, x...), and hessian(itp, x...))
412

423
itpinfo(itp) = (tcollect(itpflag, itp), axes(itp))
@@ -52,6 +13,14 @@ end
5213
@assert length(inds) == N
5314
itp(inds...)
5415
end
16+
@inline function (itp::BSplineInterpolation{T,N})(x::Vararg{Union{Number,AbstractVector},N}) where {T,N}
17+
@boundscheck (checkbounds(Bool, itp, x...) || Base.throw_boundserror(itp, x))
18+
itps = tcollect(itpflag, itp)
19+
wis = dimension_wis(value_weights, itps, axes(itp), x)
20+
coefs = coefficients(itp)
21+
ret = [coefs[i...] for i in Iterators.product(wis...)]
22+
reshape(ret, shape(wis...))
23+
end
5524

5625
@inline function gradient(itp::BSplineInterpolation{T,N}, x::Vararg{Number,N}) where {T,N}
5726
@boundscheck checkbounds(Bool, itp, x...) || Base.throw_boundserror(itp, x)
@@ -71,12 +40,14 @@ end
7140
dest .= hessian(itp, x...)
7241
end
7342

74-
checkbounds(::Type{Bool}, itp::AbstractInterpolation, x::Vararg{Number,N}) where N =
43+
checkbounds(::Type{Bool}, itp::AbstractInterpolation, x::Vararg{ExpandedIndexTypes,N}) where N =
7544
checklubounds(lbounds(itp), ubounds(itp), x)
7645

7746
checklubounds(ls, us, xs) = _checklubounds(true, ls, us, xs)
78-
_checklubounds(tf::Bool, ls, us, xs) = _checklubounds(tf & (ls[1] <= xs[1] <= us[1]),
79-
Base.tail(ls), Base.tail(us), Base.tail(xs))
47+
_checklubounds(tf::Bool, ls, us, xs::Tuple{Number, Vararg{Any}}) =
48+
_checklubounds(tf & (ls[1] <= xs[1] <= us[1]), Base.tail(ls), Base.tail(us), Base.tail(xs))
49+
_checklubounds(tf::Bool, ls, us, xs::Tuple{AbstractVector, Vararg{Any}}) =
50+
_checklubounds(tf & all(ls[1] .<= xs[1] .<= us[1]), Base.tail(ls), Base.tail(us), Base.tail(xs))
8051
_checklubounds(tf::Bool, ::Tuple{}, ::Tuple{}, ::Tuple{}) = tf
8152

8253
# Leftovers from AbstractInterpolation

src/extrapolation/extrapolation.jl

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,29 @@ count_interp_dims(::Type{<:Extrapolation{T,N,ITPT}}, n) where {T,N,ITPT} = count
3939
itp = parent(etp)
4040
eflag = etpflag(etp)
4141
xs = inbounds_position(eflag, bounds(itp), x, etp, x)
42-
extrapolate_value(eflag, x, xs, Tuple(gradient(itp, xs...)), itp(xs...))
42+
extrapolate_value(eflag, skip_flagged_nointerp(itp, x), skip_flagged_nointerp(itp, xs), Tuple(gradient(itp, xs...)), itp(xs...))
43+
end
44+
@inline function (etp::Extrapolation{T,N})(x::Vararg{Union{Number,AbstractVector},N}) where {T,N}
45+
itp = parent(etp)
46+
Tret = typeof(lispyprod(zero(T), x...))
47+
ret = zeros(Tret, shape(x...))
48+
for (i, y) in zip(eachindex(ret), Iterators.product(x...))
49+
ret[i] = etp(y...)
50+
end
51+
return ret
52+
end
53+
54+
@inline function gradient(etp::AbstractExtrapolation{T,N}, x::Vararg{Number,N}) where {T,N}
55+
itp = parent(etp)
56+
if checkbounds(Bool, itp, x...)
57+
gradient(itp, x...)
58+
else
59+
eflag = tcollect(etpflag, etp)
60+
xs = inbounds_position(eflag, bounds(itp), x, etp, x)
61+
g = gradient(itp, xs...)
62+
skipni = t->skip_flagged_nointerp(itp, t)
63+
SVector(extrapolate_gradient.(skipni(eflag), skipni(x), skipni(xs), Tuple(g)))
64+
end
4365
end
4466

4567
checkbounds(::Bool, ::AbstractExtrapolation, I...) = true

src/extrapolation/filled.jl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,16 @@ end
3333
@assert length(inds) == N
3434
etp(inds...)
3535
end
36+
@inline function (etp::FilledExtrapolation{T,N})(x::Vararg{Union{Number,AbstractVector},N}) where {T,N}
37+
itp = parent(etp)
38+
Tret = typeof(lispyprod(zero(T), x...))
39+
ret = fill(convert(Tret, etp.fillvalue), shape(x...))
40+
axsib = inbounds(itp, x...)
41+
any(isempty, axsib) && return ret
42+
xib = getindex.(x, axsib)
43+
getindex!(view(ret, keepvectors(axsib...)...), itp, xib...)
44+
return ret
45+
end
3646

3747
expand_index_resid_etp(deg, fillvalue, (l, u), x, etp::FilledExtrapolation, xN) =
3848
(l <= x <= u || Base.throw_boundserror(etp, xN))

src/gridded/gridded.jl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ struct Gridded{D<:Degree} <: InterpolationType
44
degree::D
55
end
66

7+
function Base.show(io::IO, g::Gridded)
8+
print(io, "Gridded(")
9+
show(io, degree(g))
10+
print(io, ')')
11+
end
12+
713
const GridIndex{T} = Union{AbstractVector{T}, Tuple}
814

915
struct GriddedInterpolation{T,N,TCoefs,IT<:DimSpec{Gridded},K<:Tuple{Vararg{AbstractVector}}} <: AbstractInterpolation{T,N,IT}

src/gridded/indexing.jl

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,15 @@ end
88
itp(to_indices(itp, x)...)
99
end
1010

11+
@inline function gradient(itp::GriddedInterpolation{T,N}, x::Vararg{Number,N}) where {T,N}
12+
@boundscheck (checkbounds(Bool, itp, x...) || Base.throw_boundserror(itp, x))
13+
wis = weightedindexes((value_weights, gradient_weights), itpinfo(itp)..., x)
14+
SVector(map(inds->coefficients(itp)[inds...], wis))
15+
end
16+
@propagate_inbounds function gradient!(dest, itp::GriddedInterpolation{T,N}, x::Vararg{Number,N}) where {T,N}
17+
dest .= gradient(itp, x...)
18+
end
19+
1120
itpinfo(itp::GriddedInterpolation) = (tcollect(itpflag, itp), itp.knots)
1221

1322
weightedindex_parts(fs::F, itpflag::Gridded, ax, x) where F =
@@ -45,15 +54,23 @@ end
4554
function weightedindex(fs::F, deg::Degree, knotvec, x, iclamp) where F
4655
@inbounds l, u = knotvec[iclamp], knotvec[iclamp+1]
4756
δx = (x - l)/(u - l)
48-
(position=iclamp, coefs=fmap(fs, deg, δx))
57+
(position=iclamp, coefs=rescale_gridded(fs, fmap(fs, deg, δx), u-l))
4958
end
5059

60+
rescale_gridded(fs::F, coefs, Δx) where F =
61+
(rescale_gridded(fs[1], coefs[1], Δx), rescale_gridded(Base.tail(fs), Base.tail(coefs), Δx)...)
62+
rescale_gridded(::Tuple{}, ::Tuple{}, Δx) = ()
63+
rescale_gridded(::typeof(value_weights), coefs, Δx) = coefs
64+
rescale_gridded(::typeof(gradient_weights), coefs, Δx) = coefs./Δx
65+
rescale_gridded(::typeof(hessian_weights), coefs, Δx) = coefs./Δx.^2
66+
5167
@inline function (itp::GriddedInterpolation{T,N})(x::Vararg{Union{Number,AbstractVector},N}) where {T,N}
5268
@boundscheck (checkbounds(Bool, itp, x...) || Base.throw_boundserror(itp, x))
5369
itps = tcollect(itpflag, itp)
5470
wis = dimension_wis(value_weights, itps, itp.knots, x)
5571
coefs = coefficients(itp)
56-
[coefs[i...] for i in Iterators.product(wis...)]
72+
ret = [coefs[i...] for i in Iterators.product(wis...)]
73+
reshape(ret, shape(wis...))
5774
end
5875

5976
function dimension_wis(f::F, itps, knots, xs) where F

src/io.jl

Lines changed: 40 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
function Base.showarg(io::IO, A::BSplineInterpolation{T,N,TW,ST,GT}, toplevel) where {T,N,TW,ST,GT}
1+
function Base.showarg(io::IO, A::BSplineInterpolation{T,N,TW,ST}, toplevel) where {T,N,TW,ST}
22
print(io, "interpolate(")
33
Base.showarg(io, A.coefs, false)
44
print(io, ", ")
@@ -10,19 +10,19 @@ function Base.showarg(io::IO, A::BSplineInterpolation{T,N,TW,ST,GT}, toplevel) w
1010
end
1111
end
1212

13-
# function Base.showarg(io::IO, A::GriddedInterpolation{T,N,TC,ST,K}, toplevel) where {T,N,TC,ST,K}
14-
# print(io, "interpolate(")
15-
# _showknots(io, A.knots)
16-
# print(io, ", ")
17-
# Base.showarg(io, A.coefs, false)
18-
# print(io, ", ")
19-
# _showtypeparam(io, ST)
20-
# if toplevel
21-
# print(io, ") with element type ",T)
22-
# else
23-
# print(io, ')')
24-
# end
25-
# end
13+
function Base.showarg(io::IO, A::GriddedInterpolation{T,N,TC,ST,K}, toplevel) where {T,N,TC,ST,K}
14+
print(io, "interpolate(")
15+
_showknots(io, A.knots)
16+
print(io, ", ")
17+
Base.showarg(io, A.coefs, false)
18+
print(io, ", ")
19+
show(io, itpflag(A))
20+
if toplevel
21+
print(io, ") with element type ",T)
22+
else
23+
print(io, ')')
24+
end
25+
end
2626

2727
_showknots(io, A) = Base.showarg(io, A, false)
2828
function _showknots(io, tup::NTuple{N,Any}) where N
@@ -35,31 +35,31 @@ function _showknots(io, tup::NTuple{N,Any}) where N
3535
print(io, ')')
3636
end
3737

38-
# function Base.showarg(io::IO, A::ScaledInterpolation{T}, toplevel) where {T}
39-
# print(io, "scale(")
40-
# Base.showarg(io, A.itp, false)
41-
# print(io, ", ", A.ranges, ')')
42-
# if toplevel
43-
# print(io, " with element type ",T)
44-
# end
45-
# end
38+
function Base.showarg(io::IO, A::ScaledInterpolation{T}, toplevel) where {T}
39+
print(io, "scale(")
40+
Base.showarg(io, A.itp, false)
41+
print(io, ", ", A.ranges, ')')
42+
if toplevel
43+
print(io, " with element type ",T)
44+
end
45+
end
4646

47-
# function Base.showarg(io::IO, A::Extrapolation{T,N,TI,IT,GT,ET}, toplevel) where {T,N,TI,IT,GT,ET}
48-
# print(io, "extrapolate(")
49-
# Base.showarg(io, A.itp, false)
50-
# print(io, ", ")
51-
# _showtypeparam(io, ET)
52-
# print(io, ')')
53-
# if toplevel
54-
# print(io, " with element type ",T)
55-
# end
56-
# end
47+
function Base.showarg(io::IO, A::Extrapolation{T,N,TI,IT,ET}, toplevel) where {T,N,TI,IT,ET}
48+
print(io, "extrapolate(")
49+
Base.showarg(io, A.itp, false)
50+
print(io, ", ")
51+
show(io, etpflag(A))
52+
print(io, ')')
53+
if toplevel
54+
print(io, " with element type ",T)
55+
end
56+
end
5757

58-
# function Base.showarg(io::IO, A::FilledExtrapolation{T,N,TI,IT,GT}, toplevel) where {T,N,TI,IT,GT}
59-
# print(io, "extrapolate(")
60-
# Base.showarg(io, A.itp, false)
61-
# print(io, ", ", A.fillvalue, ')')
62-
# if toplevel
63-
# print(io, " with element type ",T)
64-
# end
65-
# end
58+
function Base.showarg(io::IO, A::FilledExtrapolation{T,N,TI,IT}, toplevel) where {T,N,TI,IT}
59+
print(io, "extrapolate(")
60+
Base.showarg(io, A.itp, false)
61+
print(io, ", ", A.fillvalue, ')')
62+
if toplevel
63+
print(io, " with element type ",T)
64+
end
65+
end

0 commit comments

Comments
 (0)