@@ -192,22 +192,100 @@ function bracketstrictlymontonic(
192
192
end
193
193
194
194
"""
195
- searchsortedfirstcorrelated(v::AbstractVector{T}, x, guess )
195
+ looks_linear(v; threshold = 1e-2 )
196
196
197
- An accelerated `findfirst` on sorted vectors using a bracketed search. Requires a `guess::T`
197
+ Determine if the abscissae `v` are regularly distributed, taking the standard deviation of
198
+ the difference between the array of abscissae with respect to the straight line linking
199
+ its first and last elements, normalized by the range of `v`. If this standard deviation is
200
+ below the given `threshold`, the vector looks linear (return true). Internal function -
201
+ interface may change.
202
+ """
203
+ function looks_linear (v; threshold = 1e-2 )
204
+ length (v) <= 2 && return true
205
+ x_0, x_f = first (v), last (v)
206
+ N = length (v)
207
+ x_span = x_f - x_0
208
+ mean_x_dist = x_span / (N - 1 )
209
+ norm_var =
210
+ sum ((x_i - x_0 - (i - 1 ) * mean_x_dist)^ 2 for (i, x_i) in enumerate (v)) /
211
+ (N * x_span^ 2 )
212
+ norm_var < threshold^ 2
213
+ end
214
+
215
+ """
216
+ Guesser(v::AbstractVector; looks_linear_threshold = 1e-2)
217
+
218
+ Wrapper of the searched vector `v` which makes an informed guess
219
+ for `searchsorted*correlated` by either
220
+ - Exploiting that `v` is sufficiently evenly spaced
221
+ - Using the previous outcome of `searchsorted*correlated`
222
+ """
223
+ struct Guesser{T<: AbstractVector }
224
+ v:: T
225
+ idx_prev:: Base.RefValue{Int}
226
+ linear_lookup:: Bool
227
+ end
228
+
229
+ function Guesser (v:: AbstractVector ; looks_linear_threshold = 1e-2 )
230
+ Guesser (v, Ref (1 ), looks_linear (v; threshold = looks_linear_threshold))
231
+ end
232
+
233
+ function (g:: Guesser )(x)
234
+ (; v, idx_prev, linear_lookup) = g
235
+ if linear_lookup
236
+ f = (x - first (v)) / (last (v) - first (v))
237
+ if isinf (f)
238
+ f > 0 ? lastindex (v) : firstindex (v)
239
+ else
240
+ i_0, i_f = firstindex (v), lastindex (v)
241
+ round (typeof (firstindex (v)), f * (i_f - i_0) + i_0)
242
+ end
243
+ else
244
+ idx_prev[]
245
+ end
246
+ end
247
+
248
+ """
249
+ searchsortedfirstcorrelated(v::AbstractVector, x, guess)
250
+
251
+ An accelerated `findfirst` on sorted vectors using a bracketed search. Requires a `guess::Union{<:Integer, Guesser}`
198
252
to start the search from.
199
253
"""
200
- function searchsortedfirstcorrelated (v:: AbstractVector , x, guess)
254
+ function searchsortedfirstcorrelated (v:: AbstractVector , x, guess:: T ) where {T <: Integer }
201
255
lo, hi = bracketstrictlymontonic (v, x, guess, Base. Order. Forward)
202
256
searchsortedfirst (v, x, lo, hi, Base. Order. Forward)
203
257
end
204
258
205
- function searchsortedlastcorrelated (v:: AbstractVector , x, guess)
259
+ """
260
+ searchsortedlastcorrelated(v::AbstractVector{T}, x, guess)
261
+
262
+ An accelerated `findlast` on sorted vectors using a bracketed search. Requires a `guess::Union{<:Integer, Guesser}`
263
+ to start the search from.
264
+ """
265
+ function searchsortedlastcorrelated (v:: AbstractVector , x, guess:: T ) where {T<: Integer }
206
266
lo, hi = bracketstrictlymontonic (v, x, guess, Base. Order. Forward)
207
267
searchsortedlast (v, x, lo, hi, Base. Order. Forward)
208
268
end
209
269
210
- searchsortedfirstcorrelated (r:: AbstractRange , x, _) = searchsortedfirst (r, x)
211
- searchsortedlastcorrelated (r:: AbstractRange , x, _) = searchsortedlast (r, x)
270
+ searchsortedfirstcorrelated (r:: AbstractRange , x, :: Integer ) = searchsortedfirst (r, x)
271
+ searchsortedlastcorrelated (r:: AbstractRange , x, :: Integer ) = searchsortedlast (r, x)
272
+
273
+ function searchsortedfirstcorrelated (
274
+ v:: AbstractVector ,
275
+ x,
276
+ guess:: Guesser{T} ,
277
+ ) where {T<: AbstractVector }
278
+ @assert v === guess. v
279
+ out = searchsortedfirstcorrelated (v, x, guess (x))
280
+ guess. idx_prev[] = out
281
+ out
282
+ end
212
283
284
+ function searchsortedlastcorrelated (v:: T , x, guess:: Guesser{T} ) where {T<: AbstractVector }
285
+ @assert v === guess. v
286
+ out = searchsortedlastcorrelated (v, x, guess (x))
287
+ guess. idx_prev[] = out
288
+ out
213
289
end
290
+
291
+ end # module FindFirstFunctions
0 commit comments