Skip to content

Commit 3858472

Browse files
aaowenstimholy
authored andcommitted
Use more efficient searchsorted when inputs are sorted for Gridded (#324)
1 parent 739c4cb commit 3858472

File tree

1 file changed

+54
-1
lines changed

1 file changed

+54
-1
lines changed

src/gridded/indexing.jl

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,14 @@ function gridded_floorbounds(x, knotvec::AbstractVector)
4141
end
4242

4343
@inline find_knot_index(knotv, x) = searchsortedfirst(knotv, x, Base.Order.ForwardOrdering()) - 1
44+
@inline find_knot_index(knotv, x::AbstractVector) = searchsortedfirst_vec(knotv, x) .- 1
4445

4546
@inline function weightedindex_parts(fs::F, mode::Gridded, knotvec::AbstractVector, x) where F
4647
i = find_knot_index(knotvec, x)
48+
weightedindex_parts2(fs, mode, knotvec, x, i)
49+
end
50+
51+
@inline function weightedindex_parts2(fs::F, mode::Gridded, knotvec::AbstractVector, x, i) where F
4752
ax1 = axes1(knotvec)
4853
iclamp = clamp(i, first(ax1), last(ax1)-1)
4954
weightedindex(fs, degree(mode), knotvec, x, iclamp)
@@ -69,7 +74,11 @@ rescale_gridded(::typeof(hessian_weights), coefs, Δx) = coefs./Δx.^2
6974
@inline function (itp::GriddedInterpolation{T,N})(x::Vararg{Union{Number,AbstractVector},N}) where {T,N}
7075
@boundscheck (checkbounds(Bool, itp, x...) || Base.throw_boundserror(itp, x))
7176
itps = tcollect(itpflag, itp)
72-
wis = dimension_wis(value_weights, itps, itp.knots, x)
77+
if x[1] isa AbstractVector
78+
wis = dimension_wis_vec(value_weights, itps, itp.knots, x)
79+
else
80+
wis = dimension_wis(value_weights, itps, itp.knots, x)
81+
end
7382
coefs = coefficients(itp)
7483
ret = [coefs[i...] for i in Iterators.product(wis...)]
7584
reshape(ret, shape(wis...))
@@ -83,6 +92,17 @@ function dimension_wis(f::F, itps, knots, xs) where F
8392
end
8493
(makewi.(x), dimension_wis(f, Base.tail(itps), Base.tail(knots), Base.tail(xs))...)
8594
end
95+
96+
function dimension_wis_vec(f::F, itps, knots, xs) where F
97+
itpflag, knotvec, x = itps[1], knots[1], xs[1]
98+
ivec = find_knot_index(knotvec, x)
99+
function makewi(y, i)
100+
pos, coefs = weightedindex_parts2((f,), itpflag, knotvec, y, i)
101+
maybe_weightedindex(pos, coefs[1])
102+
end
103+
(makewi.(x, ivec), dimension_wis(f, Base.tail(itps), Base.tail(knots), Base.tail(xs))...)
104+
end
105+
86106
function dimension_wis(f::F, itps::Tuple{NoInterp,Vararg{Any}}, knots, xs) where F
87107
(Int.(xs[1]), dimension_wis(f, Base.tail(itps), Base.tail(knots), Base.tail(xs))...)
88108
end
@@ -96,3 +116,36 @@ function getindex_return_type(::Type{GriddedInterpolation{T,N,TCoefs,IT,K}}, arg
96116
end
97117
Tret
98118
end
119+
120+
Base.@propagate_inbounds function searchsortedfirst_exp_left(v, xx, lo, hi)
121+
for i in 0:4
122+
ind = lo + i
123+
ind > hi && return ind
124+
xx <= v[ind] && return ind
125+
end
126+
n = 3
127+
tn2 = 2^n
128+
tn2m1 = 2^(n-1)
129+
ind = lo + tn2
130+
while ind <= hi
131+
xx <= v[ind] && return searchsortedfirst(v, xx, lo + tn2 - tn2m1, ind, Base.Order.Forward)
132+
tn2 *= 2
133+
tn2m1 *= 2
134+
ind = lo + tn2
135+
end
136+
return searchsortedfirst(v, xx, lo + tn2 - tn2m1, hi, Base.Order.Forward)
137+
end
138+
139+
function searchsortedfirst_vec(v::AbstractVector, x::AbstractVector)
140+
issorted(x) || return searchsortedfirst.(Ref(v), x)
141+
out = zeros(Int, length(x))
142+
lo = 1
143+
hi = length(v)
144+
@inbounds for i in 1:length(x)
145+
xx = x[i]
146+
y = searchsortedfirst_exp_left(v, xx, lo, hi)
147+
out[i] = y
148+
lo = min(y, hi)
149+
end
150+
return out
151+
end

0 commit comments

Comments
 (0)