Skip to content

Commit d6d98bd

Browse files
committed
Refactor Interpolation to use typed Interpolant structs
- Added Interpolant{Linear} and Interpolant{Constant} types - Implemented call methods for each type - Added display.jl with custom show methods - Updated docs to include types.jl and display.jl - Added type stability tests for interpolant calls
1 parent cebb4e3 commit d6d98bd

4 files changed

Lines changed: 70 additions & 38 deletions

File tree

docs/api_reference.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,14 @@ function generate_api_reference(src_dir::String)
3939
primary_modules=[
4040
CTBase.Interpolation => src(
4141
joinpath("Interpolation", "Interpolation.jl"),
42+
joinpath("Interpolation", "types.jl"),
4243
joinpath("Interpolation", "ctinterpolate.jl"),
44+
joinpath("Interpolation", "display.jl"),
4345
),
4446
],
4547
exclude=EXCLUDE_SYMBOLS,
4648
public=true,
47-
private=false,
49+
private=true,
4850
title="Interpolation",
4951
title_in_menu="Interpolation",
5052
filename="interpolation",

src/Interpolation/Interpolation.jl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,13 @@ Interpolation utilities for the Control Toolbox (CT) ecosystem.
99
"""
1010
module Interpolation
1111

12-
import DocStringExtensions: TYPEDSIGNATURES
12+
import DocStringExtensions: TYPEDEF, TYPEDSIGNATURES
1313

14+
include(joinpath(@__DIR__, "types.jl"))
1415
include(joinpath(@__DIR__, "ctinterpolate.jl"))
16+
include(joinpath(@__DIR__, "display.jl"))
1517

1618
export ctinterpolate, ctinterpolate_constant
19+
export Interpolant, LinearInterpolant, ConstantInterpolant
1720

1821
end # module Interpolation

src/Interpolation/ctinterpolate.jl

Lines changed: 43 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,52 @@
1+
# =============================================================================
2+
# Call methods
3+
# =============================================================================
4+
5+
# Linear interpolation with flat extrapolation outside [x[1], x[end]].
6+
function (interp::Interpolant{Linear})(t)
7+
x, f = interp.x, interp.f
8+
if t < x[1]
9+
return f[1]
10+
elseif t >= x[end]
11+
return f[end]
12+
else
13+
i = searchsortedlast(x, t)
14+
i == length(x) && return f[end]
15+
α = (t - x[i]) / (x[i + 1] - x[i])
16+
return f[i] + α * (f[i + 1] - f[i])
17+
end
18+
end
19+
20+
# Right-continuous piecewise-constant (steppost) interpolation.
21+
function (interp::Interpolant{Constant})(t)
22+
x, f = interp.x, interp.f
23+
if t < x[1]
24+
return f[1]
25+
elseif t >= x[end]
26+
return f[end]
27+
else
28+
return f[searchsortedlast(x, t)]
29+
end
30+
end
31+
32+
# =============================================================================
33+
# Factories (public API)
34+
# =============================================================================
35+
136
"""
237
$(TYPEDSIGNATURES)
338
439
Return a linear interpolation function for the data `f` defined at points `x`.
540
6-
This function creates a one-dimensional linear interpolant with flat extrapolation
7-
beyond the bounds of `x` (returns `f[1]` for `t < x[1]` and `f[end]` for `t >= x[end]`).
41+
This creates a one-dimensional linear [`Interpolant`](@ref) with flat extrapolation beyond
42+
the bounds of `x` (returns `f[1]` for `t < x[1]` and `f[end]` for `t >= x[end]`).
843
944
# Arguments
1045
- `x`: A vector of points at which the values `f` are defined.
1146
- `f`: A vector of values to interpolate.
1247
1348
# Returns
14-
A callable interpolation object that can be evaluated at new points.
49+
A callable [`LinearInterpolant`](@ref) that can be evaluated at new points.
1550
1651
# Example
1752
```julia-repl
@@ -23,31 +58,15 @@ julia> interp(-1.0) # Returns 1.0 (flat extrapolation)
2358
julia> interp(3.0) # Returns 3.0 (flat extrapolation)
2459
```
2560
"""
26-
function ctinterpolate(x, f)
27-
function linear_interp(t)
28-
if t < x[1]
29-
return f[1]
30-
elseif t >= x[end]
31-
return f[end]
32-
else
33-
i = searchsortedlast(x, t)
34-
if i == length(x)
35-
return f[end]
36-
end
37-
α = (t - x[i]) / (x[i + 1] - x[i])
38-
return f[i] + α * (f[i + 1] - f[i])
39-
end
40-
end
41-
return linear_interp
42-
end
61+
ctinterpolate(x, f) = Interpolant{Linear}(x, f)
4362

4463
"""
4564
$(TYPEDSIGNATURES)
4665
4766
Return a piecewise-constant interpolation function for the data `f` defined at points `x`.
4867
49-
This function creates a right-continuous piecewise constant interpolant:
50-
the value at knot `x[i]` is held constant on the interval `[x[i], x[i+1})`.
68+
This creates a right-continuous piecewise-constant [`Interpolant`](@ref): the value at knot
69+
`x[i]` is held constant on the interval `[x[i], x[i+1})`.
5170
5271
This implements the standard steppost behavior for optimal control:
5372
- `u(t_i) = u_i` (value at the knot)
@@ -59,7 +78,7 @@ This implements the standard steppost behavior for optimal control:
5978
- `f`: A vector of values to interpolate.
6079
6180
# Returns
62-
A callable interpolation object that can be evaluated at new points.
81+
A callable [`ConstantInterpolant`](@ref) that can be evaluated at new points.
6382
6483
# Example
6584
```julia-repl
@@ -72,16 +91,4 @@ julia> interp(1.0) # Returns 2.0 (value at x[2], right-continuous)
7291
julia> interp(1.5) # Returns 2.0 (held from x[2] on [1.0, 2.0))
7392
```
7493
"""
75-
function ctinterpolate_constant(x, f)
76-
function steppost_interp(t)
77-
if t < x[1]
78-
return f[1]
79-
elseif t >= x[end]
80-
return f[end]
81-
else
82-
i = searchsortedlast(x, t)
83-
return f[i]
84-
end
85-
end
86-
return steppost_interp
87-
end
94+
ctinterpolate_constant(x, f) = Interpolant{Constant}(x, f)

test/suite/interpolation/test_interpolation.jl

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,26 @@ function test_interpolation()
113113
Test.@test interp(5.0) 7.0
114114
end
115115

116+
Test.@testset "Interpolant type & show" begin
117+
interp = Interpolation.ctinterpolate([0.0, 1.0, 2.0], [0.0, 1.0, 0.0])
118+
Test.@test interp isa Function
119+
Test.@test interp isa Interpolation.Interpolant
120+
Test.@test interp isa Interpolation.LinearInterpolant
121+
Test.@test Interpolation.method(interp) === Interpolation.Linear
122+
Test.@test occursin("linear", sprint(show, interp))
123+
Test.@test occursin("3 nodes", sprint(show, interp))
124+
125+
c = Interpolation.ctinterpolate_constant([0.0, 1.0, 2.0], [1.0, 2.0, 3.0])
126+
Test.@test c isa Function
127+
Test.@test c isa Interpolation.ConstantInterpolant
128+
Test.@test Interpolation.method(c) === Interpolation.Constant
129+
Test.@test occursin("constant", sprint(show, c))
130+
131+
# type stability of the call (philosophy: @inferred on the call)
132+
Test.@test_nowarn Test.@inferred interp(0.5)
133+
Test.@test_nowarn Test.@inferred c(0.5)
134+
end
135+
116136
end
117137
return nothing
118138
end

0 commit comments

Comments
 (0)