Skip to content

Commit b63f25d

Browse files
authored
Adding AkimaMonotonicInterpolation (#522)
* Adding AkimaMonotonicInterpolation Using `eachindex` for the for-loops and getting rid of an unnecessary variable. Changing version to 0.14.6
1 parent bc83f78 commit b63f25d

File tree

6 files changed

+81
-41
lines changed

6 files changed

+81
-41
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "Interpolations"
22
uuid = "a98d9a8b-a2ab-59e6-89dd-64a1c18fca59"
3-
version = "0.14.5"
3+
version = "0.14.6"
44

55
[deps]
66
Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e"

src/monotonic/monotonic.jl

Lines changed: 76 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,14 @@
99
"Cardinal" cubic cardinal splines, uses tension parameter which must be between [0,1]
1010
cubin cardinal splines can overshoot for non-monotonic data
1111
(increasing tension decreases overshoot)
12+
"Akima" monotonic - tangents are determined at each given point locally,
13+
the curve obtained is close to a manually drawn curve, can overshoot for non-monotonic data
1214
"FritschCarlson" monotonic - tangents are first initialized, then adjusted if they are not monotonic
1315
can overshoot for non-monotonic data
1416
"FritschButland" monotonic - faster algorithm (only requires one pass) but somewhat higher apparent "tension"
1517
"Steffen" monotonic - also only one pass, results usually between FritschCarlson and FritschButland
1618
Sources:
19+
Akima (1970), "A New Method of Interpolation and Smooth Curve Fitting Based on Local Procedures", doi:10.1145/321607.321609
1720
Fritsch & Carlson (1980), "Monotone Piecewise Cubic Interpolation", doi:10.1137/0717021.
1821
Fritsch & Butland (1984), "A Method for Constructing Local Monotone Piecewise Cubic Interpolants", doi:10.1137/0905021.
1922
Steffen (1990), "A Simple Method for Monotonic Interpolation in One Dimension", http://adsabs.harvard.edu/abs/1990A%26A...239..443S
@@ -25,6 +28,7 @@ export
2528
LinearMonotonicInterpolation,
2629
FiniteDifferenceMonotonicInterpolation,
2730
CardinalMonotonicInterpolation,
31+
AkimaMonotonicInterpolation,
2832
FritschCarlsonMonotonicInterpolation,
2933
FritschButlandMonotonicInterpolation,
3034
SteffenMonotonicInterpolation
@@ -64,6 +68,19 @@ struct CardinalMonotonicInterpolation{TTension<:Number} <: MonotonicInterpolatio
6468
tension :: TTension # must be in [0, 1]
6569
end
6670

71+
"""
72+
AkimaMonotonicInterpolation
73+
74+
Monotonic interpolation based on Akima (1970),
75+
"A New Method of Interpolation and Smooth Curve Fitting Based on Local Procedures",
76+
doi:10.1145/321607.321609.
77+
78+
Tagents are dertermined at each given point locally,
79+
results are close to manual drawn curves
80+
"""
81+
struct AkimaMonotonicInterpolation <: MonotonicInterpolationType
82+
end
83+
6784
"""
6885
FritschCarlsonMonotonicInterpolation
6986
@@ -161,7 +178,7 @@ function interpolate(::Type{TWeights}, ::Type{TCoeffs1},::Type{TCoeffs2},::Type{
161178
m, Δ = calcTangents(TCoeffs1, knots, A, it)
162179
c = Vector{TCoeffs2}(undef, n-1)
163180
d = Vector{TCoeffs3}(undef, n-1)
164-
for k 1:n-1
181+
for k eachindex(c)
165182
if TInterpolationType == LinearMonotonicInterpolation
166183
c[k] = zero(TCoeffs2)
167184
d[k] = zero(TCoeffs3)
@@ -232,10 +249,9 @@ function calcTangents(::Type{TCoeffs}, x::AbstractVector{<:Number},
232249
n = length(x)
233250
Δ = Vector{TCoeffs}(undef, n-1)
234251
m = Vector{TCoeffs}(undef, n)
235-
for k in 1:n-1
236-
Δk = (y[k+1] - y[k]) / (x[k+1] - x[k])
237-
Δ[k] = Δk
238-
m[k] = Δk
252+
for k eachindex(Δ)
253+
Δ[k] = (y[k+1] - y[k]) / (x[k+1] - x[k])
254+
m[k] = Δ[k]
239255
end
240256
m[n] = Δ[n-1]
241257
return (m, Δ)
@@ -247,13 +263,12 @@ function calcTangents(::Type{TCoeffs}, x::AbstractVector{<:Number},
247263
n = length(x)
248264
Δ = Vector{TCoeffs}(undef, n-1)
249265
m = Vector{TCoeffs}(undef, n)
250-
for k in 1:n-1
251-
Δk = (y[k+1] - y[k]) / (x[k+1] - x[k])
252-
Δ[k] = Δk
266+
for k eachindex(Δ)
267+
Δ[k] = (y[k+1] - y[k]) / (x[k+1] - x[k])
253268
if k == 1 # left endpoint
254-
m[k] = Δk
269+
m[k] = Δ[k]
255270
else
256-
m[k] = (Δ[k-1] + Δk) / 2
271+
m[k] = (Δ[k-1] + Δ[k]) / 2
257272
end
258273
end
259274
m[n] = Δ[n-1]
@@ -266,11 +281,10 @@ function calcTangents(::Type{TCoeffs}, x::AbstractVector{<:Number},
266281
n = length(x)
267282
Δ = Vector{TCoeffs}(undef, n-1)
268283
m = Vector{TCoeffs}(undef, n)
269-
for k in 1:n-1
270-
Δk = (y[k+1] - y[k]) / (x[k+1] - x[k])
271-
Δ[k] = Δk
284+
for k eachindex(Δ)
285+
Δ[k] = (y[k+1] - y[k]) / (x[k+1] - x[k])
272286
if k == 1 # left endpoint
273-
m[k] = Δk
287+
m[k] = Δ[k]
274288
else
275289
m[k] = (oneunit(TTension) - method.tension) * (y[k+1] - y[k-1]) / (x[k+1] - x[k-1])
276290
end
@@ -279,25 +293,50 @@ function calcTangents(::Type{TCoeffs}, x::AbstractVector{<:Number},
279293
return (m, Δ)
280294
end
281295

296+
function calcTangents(::Type{TCoeffs}, x::AbstractVector{<:Number},
297+
y::AbstractVector{TEl}, method::AkimaMonotonicInterpolation) where {TCoeffs, TEl}
298+
299+
# based on Akima (1970),
300+
# "A New Method of Interpolation and Smooth Curve Fitting Based on Local Procedures",
301+
# doi:10.1145/321607.321609.
302+
303+
n = length(x)
304+
Δ = Vector{TCoeffs}(undef, n-1)
305+
m = Vector{TCoeffs}(undef, n)
306+
for k eachindex(Δ)
307+
Δ[k] = (y[k+1] - y[k]) / (x[k+1] - x[k])
308+
end
309+
Γ = [3Δ[1] - 2Δ[2]; 2Δ[1] - Δ[2]; Δ; 2Δ[n-1] - Δ[n-2]; 3Δ[n-1] - 2Δ[n-2]]
310+
for k eachindex(m)
311+
δ = abs(Γ[k+3] - Γ[k+2]) + abs(Γ[k+1] - Γ[k])
312+
if δ > zero(δ)
313+
α = abs(Γ[k+1] - Γ[k]) / δ
314+
m[k] = (1-α) * Γ[k+1] + α * Γ[k+2]
315+
else
316+
m[k] = 0.5 * Γ[k+1] + 0.5 * Γ[k+2]
317+
end
318+
end
319+
return (m, Δ)
320+
end
321+
282322
function calcTangents(::Type{TCoeffs}, x::AbstractVector{<:Number},
283323
y::AbstractVector{TEl}, method::FritschCarlsonMonotonicInterpolation) where {TCoeffs, TEl}
284324

285325
n = length(x)
286326
Δ = Vector{TCoeffs}(undef, n-1)
287327
m = Vector{TCoeffs}(undef, n)
288328
buff = Vector{typeof(first(Δ)^2)}(undef, n)
289-
for k in 1:n-1
290-
Δk = (y[k+1] - y[k]) / (x[k+1] - x[k])
291-
Δ[k] = Δk
329+
for k eachindex(Δ)
330+
Δ[k] = (y[k+1] - y[k]) / (x[k+1] - x[k])
292331
if k == 1 # left endpoint
293-
m[k] = Δk
332+
m[k] = Δ[k]
294333
else
295334
# If any consecutive secant lines change sign (i.e. curve changes direction), initialize the tangent to zero.
296335
# This is needed to make the interpolation monotonic. Otherwise set tangent to the average of the secants.
297-
if Δ[k-1] * Δk <= zero(Δk^2)
336+
if Δ[k-1] * Δ[k] <= zero(Δ[k]^2)
298337
m[k] = zero(TCoeffs)
299338
else
300-
m[k] = (Δ[k-1] + Δk) / 2.0
339+
m[k] = (Δ[k-1] + Δ[k]) / 2.0
301340
end
302341
end
303342
end
@@ -312,19 +351,18 @@ function calcTangents(::Type{TCoeffs}, x::AbstractVector{<:Number},
312351
=#
313352

314353
# Second pass of FritschCarlson: adjust any non-monotonic tangents.
315-
for k in 1:n-1
316-
Δk = Δ[k]
317-
if Δk == zero(TCoeffs)
354+
for k eachindex(Δ)
355+
if Δ[k] == zero(TCoeffs)
318356
m[k] = zero(TCoeffs)
319357
m[k+1] = zero(TCoeffs)
320358
continue
321359
end
322-
α = m[k] / Δk
323-
β = m[k+1] / Δk
360+
α = m[k] / Δ[k]
361+
β = m[k+1] / Δ[k]
324362
τ = 3.0 * oneunit(α) / sqrt^2 + β^2)
325363
if τ < 1.0 # if we're outside the circle with radius 3 then move onto the circle
326-
m[k] = τ * α * Δk
327-
m[k+1] = τ * β * Δk
364+
m[k] = τ * α * Δ[k]
365+
m[k+1] = τ * β * Δ[k]
328366
end
329367
end
330368
return (m, Δ)
@@ -340,16 +378,15 @@ function calcTangents(::Type{TCoeffs}, x::AbstractVector{<:Number},
340378
n = length(x)
341379
Δ = Vector{TCoeffs}(undef, n-1)
342380
m = Vector{TCoeffs}(undef, n)
343-
for k in 1:n-1
344-
Δk = (y[k+1] - y[k]) / (x[k+1] - x[k])
345-
Δ[k] = Δk
381+
for k eachindex(Δ)
382+
Δ[k] = (y[k+1] - y[k]) / (x[k+1] - x[k])
346383
if k == 1 # left endpoint
347-
m[k] = Δk
348-
elseif Δ[k-1] * Δk <= zero(Δk^2)
384+
m[k] = Δ[k]
385+
elseif Δ[k-1] * Δ[k] <= zero(Δ[k]^2)
349386
m[k] = zero(TCoeffs)
350387
else
351388
α = (1.0 + (x[k+1] - x[k]) / (x[k+1] - x[k-1])) / 3.0
352-
m[k] = Δ[k-1] * Δk /*Δk + (1.0 - α)*Δ[k-1])
389+
m[k] = Δ[k-1] * Δ[k] /*Δ[k] + (1.0 - α)*Δ[k-1])
353390
end
354391
end
355392
m[n] = Δ[n-1]
@@ -366,15 +403,14 @@ function calcTangents(::Type{TCoeffs}, x::AbstractVector{<:Number},
366403
n = length(x)
367404
Δ = Vector{TCoeffs}(undef, n-1)
368405
m = Vector{TCoeffs}(undef, n)
369-
for k in 1:n-1
370-
Δk = (y[k+1] - y[k]) / (x[k+1] - x[k])
371-
Δ[k] = Δk
406+
for k eachindex(Δ)
407+
Δ[k] = (y[k+1] - y[k]) / (x[k+1] - x[k])
372408
if k == 1 # left endpoint
373-
m[k] = Δk
409+
m[k] = Δ[k]
374410
else
375-
p = ((x[k+1] - x[k]) * Δ[k-1] + (x[k] - x[k-1]) * Δk) / (x[k+1] - x[k-1])
376-
m[k] = (sign(Δ[k-1]) + sign(Δk)) *
377-
min(abs(Δ[k-1]), abs(Δk), 0.5*abs(p))
411+
p = ((x[k+1] - x[k]) * Δ[k-1] + (x[k] - x[k-1]) * Δ[k]) / (x[k+1] - x[k-1])
412+
m[k] = (sign(Δ[k-1]) + sign(Δ[k])) *
413+
min(abs(Δ[k-1]), abs(Δ[k]), 0.5*abs(p))
378414
end
379415
end
380416
m[n] = Δ[n-1]

test/gradient.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ using ColorVectorSpace: RGB, Gray, N0f8, Colorant
185185
CardinalMonotonicInterpolation(0.0),
186186
CardinalMonotonicInterpolation(0.5),
187187
CardinalMonotonicInterpolation(1.0),
188+
AkimaMonotonicInterpolation(),
188189
FritschCarlsonMonotonicInterpolation(),
189190
FritschButlandMonotonicInterpolation(),
190191
SteffenMonotonicInterpolation()]

test/hessian.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ using Test, Interpolations, LinearAlgebra, ForwardDiff
5656
CardinalMonotonicInterpolation(0.0),
5757
CardinalMonotonicInterpolation(0.5),
5858
CardinalMonotonicInterpolation(1.0),
59+
AkimaMonotonicInterpolation(),
5960
FritschCarlsonMonotonicInterpolation(),
6061
FritschButlandMonotonicInterpolation(),
6162
SteffenMonotonicInterpolation()]

test/monotonic/runtests.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ using Unitful
1717
(CardinalMonotonicInterpolation(0.0), true),
1818
(CardinalMonotonicInterpolation(0.5), true),
1919
(CardinalMonotonicInterpolation(1.0), false),
20+
(AkimaMonotonicInterpolation(), true),
2021
(FritschCarlsonMonotonicInterpolation(), true),
2122
(FritschButlandMonotonicInterpolation(), false),
2223
(SteffenMonotonicInterpolation(), false)]

test/plots/monotonic/sanity.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ itypes = [LinearMonotonicInterpolation(),
1212
CardinalMonotonicInterpolation(0.0),
1313
CardinalMonotonicInterpolation(0.5),
1414
CardinalMonotonicInterpolation(1.0),
15+
AkimaMonotonicInterpolation(),
1516
FritschCarlsonMonotonicInterpolation(),
1617
FritschButlandMonotonicInterpolation(),
1718
SteffenMonotonicInterpolation()

0 commit comments

Comments
 (0)