Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,9 @@ cubic_interp(x, y, 5.0; deriv=2) # 2nd derivative at x=5.0
cubic_interp(x, y, 5.0; deriv=3) # 3rd derivative at x=5.0

# Constant interpolation — choose which side to sample
constant_interp(x, y, xq; side=:nearest) # nearest neighbor (default)
constant_interp(x, y, xq; side=:left) # left-continuous
constant_interp(x, y, xq; side=:right) # right-continuous
constant_interp(x, y, xq; side=NearestSide()) # nearest neighbor (default)
constant_interp(x, y, xq; side=LeftSide()) # left-continuous
constant_interp(x, y, xq; side=RightSide()) # right-continuous

# Quadratic boundary condition — single endpoint constraint
quadratic_interp(x, y, xq; bc=Left(Deriv1(0.0))) # S'(left) = 0
Expand All @@ -154,9 +154,9 @@ cubic_interp(x, y, xq; bc=BCPair(Deriv1(2.0), Deriv2(-5.0))) # custom (left, ri
cubic_interp(x, y, xq; bc=CubicFit()) # Estimate derivatives using 4-point fit at both ends

# Extrapolation modes — all methods support these
linear_interp(x, y, xq; extrap=:constant) # clamp to boundary values
quadratic_interp(x, y, xq; extrap=:wrap) # wrap around (periodic data)
cubic_interp(x, y, xq; extrap=:extension) # extend boundary polynomial
linear_interp(x, y, xq; extrap=ConstExtrap()) # clamp to boundary values
quadratic_interp(x, y, xq; extrap=WrapExtrap()) # wrap around (periodic data)
cubic_interp(x, y, xq; extrap=ExtendExtrap()) # extend boundary polynomial
```

## Documentation
Expand Down
13 changes: 11 additions & 2 deletions docs/src/api/constant.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
| Function | Description |
|----------|-------------|
| `constant_interp(x, y, xq)` | Constant interpolation at point(s) `xq` |
| `constant_interp(x, y, xq; side=:left)` | With side mode (`:nearest`, `:left`, `:right`) |
| `constant_interp(x, y, xq; side=LeftSide())` | With side mode (`NearestSide()`, `LeftSide()`, `RightSide()`) |
| `constant_interp!(out, x, y, xq)` | In-place constant interpolation |
| `constant_interp!(out, x, y, xq; side)` | In-place with side mode |

Expand All @@ -16,7 +16,7 @@
| Function | Description |
|----------|-------------|
| `itp = constant_interp(x, y)` | Create constant interpolant |
| `itp = constant_interp(x, y; side=:left)` | Create with side mode |
| `itp = constant_interp(x, y; side=LeftSide())` | Create with side mode |
| `itp(xq)` | Evaluate at point(s) `xq` |
| `itp(out, xq)` | Evaluate at `xq`, store result in `out` |

Expand Down Expand Up @@ -46,6 +46,15 @@ ConstantInterpolant
ConstantInterpolantND
```

## Side Selection Types

```@docs
AbstractSide
NearestSide
LeftSide
RightSide
```

## Derivative Views

See [Derivatives](../interpolation/derivatives.md) for `deriv1`, `deriv2`, `deriv3` API reference.
20 changes: 11 additions & 9 deletions docs/src/interpolation/constant.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

Step function interpolation that returns values from neighboring data points without blending.

**Key Feature**: The `side` keyword controls which neighbor to sample.
**Key Feature**: The `side` keyword controls which neighbor to sample using [`AbstractSide`](@ref) types.

| Mode | Behavior |
|------|----------|
| `:nearest` | Nearest neighbor — **default** |
| `:left` | Left-continuous (use left neighbor) |
| `:right` | Right-continuous (use right neighbor) |
| `NearestSide()` | Nearest neighbor — **default** |
| `LeftSide()` | Left-continuous (use left neighbor) |
| `RightSide()` | Right-continuous (use right neighbor) |

---

Expand All @@ -22,11 +22,11 @@ y = [1.0, 3.0, 2.0, 4.0, 1.5]

# One-shot evaluation
constant_interp(x, y, 1.5) # → 3.0 (nearest neighbor)
constant_interp(x, y, 1.5; side=:left) # → 3.0 (left neighbor)
constant_interp(x, y, 1.5; side=:right) # → 2.0 (right neighbor)
constant_interp(x, y, 1.5; side=LeftSide()) # → 3.0 (left neighbor)
constant_interp(x, y, 1.5; side=RightSide()) # → 2.0 (right neighbor)

# Create reusable interpolant
itp = constant_interp(x, y; side=:nearest)
itp = constant_interp(x, y; side=NearestSide())
itp(1.5) # single point
itp([1.0, 2.0]) # multiple points

Expand Down Expand Up @@ -55,12 +55,14 @@ x = [0.0, 1.0, 2.5, 4.0, 5.0]
y = [1.0, 3.0, 2.0, 4.0, 1.5]
xq = range(x[1], x[end], 100)

sides = [NearestSide(), LeftSide(), RightSide()]
labels = ["NearestSide()", "LeftSide()", "RightSide()"]
p = plot(layout=(1,3), size=(900, 280), legend=:topright)
for (i, side) in enumerate([:nearest, :left, :right])
for (i, (side, lbl)) in enumerate(zip(sides, labels))
yq = constant_interp(x, y, xq; side=side)
plot!(p[i], xq, yq, label="spline", linewidth=2)
scatter!(p[i], x, y, label="data", markersize=7, color=:black)
title!(p[i], "side=:$side")
title!(p[i], "side=$lbl")
end
p
```
Expand Down
3 changes: 3 additions & 0 deletions src/FastInterpolations.jl
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ export AbstractEvalOp, EvalValue, EvalDeriv1, EvalDeriv2, EvalDeriv3
# Extrapolation mode types (typed API for ND extrap)
export AbstractExtrap, NoExtrap, ConstExtrap, ExtendExtrap, WrapExtrap

# Side selection types (constant interpolation)
export AbstractSide, NearestSide, LeftSide, RightSide

# Integration
export integrate, cumulative_integrate

Expand Down
6 changes: 3 additions & 3 deletions src/constant/constant_interpolant.jl
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,15 @@ end
# ========================================

"""
constant_interp(x, y; extrap=NoExtrap(), side=:nearest, search=Binary()) -> ConstantInterpolant
constant_interp(x, y; extrap=NoExtrap(), side=NearestSide(), search=Binary()) -> ConstantInterpolant

Create a callable interpolant for broadcast fusion and reuse.

# Arguments
- `x::AbstractVector`: x-coordinates (sorted, length ≥ 2)
- `y::AbstractVector`: y-values (can be Real or Complex)
- `extrap::AbstractExtrap`: `NoExtrap()` (default), `ConstExtrap()`, `ExtendExtrap()`, or `WrapExtrap()`
- `side::Symbol`: Side selection
- `side::AbstractSide`: Side selection (NearestSide(), LeftSide(), RightSide())
- `search::AbstractSearchPolicy`: Default search policy (default: `Binary()`)

# Returns
Expand Down Expand Up @@ -114,7 +114,7 @@ end
x::AbstractVector{TX},
y::AbstractVector{TY};
extrap::AbstractExtrap=NoExtrap(),
side::Symbol=:nearest,
side::AbstractSide=NearestSide(),
search::AbstractSearchPolicy=Binary()
) where {TX<:Real, TY}
x_p, y_p = _promote_itp_inputs(x, y)
Expand Down
20 changes: 10 additions & 10 deletions src/constant/constant_kernels.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
# - h = x_{i+1} - x_i (interval width, Tg)
# - dL = xq - x_i (offset from left boundary, can be Dual for AD)
# - y_left, y_right = values (Tv, can be Complex)
# - side = Val(:nearest) | Val(:left) | Val(:right)
# - side = NearestSide() | LeftSide() | RightSide()
#
# Type parameters:
# - Tg<:AbstractFloat: Grid type (geometry)
Expand All @@ -23,37 +23,37 @@
# all side modes return y_left (the value at that grid point).

"""
_constant_kernel(::EvalValue, y_left, y_right, h, dL, ::Val{:left})
_constant_kernel(::EvalValue, y_left, y_right, h, dL, ::LeftSide)

Constant interpolation with left-continuous (floor) convention.
Always returns the left boundary value `y_left`.
dL can be any Real (including ForwardDiff.Dual for AD).
"""
@inline function _constant_kernel(::EvalValue, y_left::Tv, ::Tv, ::Tg, dL::Td, ::Val{:left}) where {Tv, Tg<:AbstractFloat, Td<:Real}
@inline function _constant_kernel(::EvalValue, y_left::Tv, ::Tv, ::Tg, dL::Td, ::LeftSide) where {Tv, Tg<:AbstractFloat, Td<:Real}
return y_left
end

"""
_constant_kernel(::EvalValue, y_left, y_right, h, dL, ::Val{:right})
_constant_kernel(::EvalValue, y_left, y_right, h, dL, ::RightSide)

Constant interpolation with right-continuous (ceiling) convention.
Returns `y_left` at grid point (dL == 0), `y_right` otherwise.
dL can be any Real (including ForwardDiff.Dual for AD).
"""
@inline function _constant_kernel(::EvalValue, y_left::Tv, y_right::Tv, ::Tg, dL::Td, ::Val{:right}) where {Tv, Tg<:AbstractFloat, Td<:Real}
@inline function _constant_kernel(::EvalValue, y_left::Tv, y_right::Tv, ::Tg, dL::Td, ::RightSide) where {Tv, Tg<:AbstractFloat, Td<:Real}
# Use primal value for comparison (supports ForwardDiff.Dual)
dL_primal = _extract_primal(dL)
return iszero(dL_primal) ? y_left : y_right
end

"""
_constant_kernel(::EvalValue, y_left, y_right, h, dL, ::Val{:nearest})
_constant_kernel(::EvalValue, y_left, y_right, h, dL, ::NearestSide)

Constant interpolation with nearest-neighbor convention and left tie-breaking.
Returns `y_left` if dL <= h/2 (including midpoint), `y_right` otherwise.
dL can be any Real (including ForwardDiff.Dual for AD).
"""
@inline function _constant_kernel(::EvalValue, y_left::Tv, y_right::Tv, h::Tg, dL::Td, ::Val{:nearest}) where {Tv, Tg<:AbstractFloat, Td<:Real}
@inline function _constant_kernel(::EvalValue, y_left::Tv, y_right::Tv, h::Tg, dL::Td, ::NearestSide) where {Tv, Tg<:AbstractFloat, Td<:Real}
# Use primal value for comparison (supports ForwardDiff.Dual)
dL_primal = _extract_primal(dL)
return dL_primal <= h / 2 ? y_left : y_right
Expand All @@ -67,7 +67,7 @@ Always returns zero (constant function has no slope).
Returns `zero(Tv)` to preserve Complex type when applicable.
dL can be any Real (including ForwardDiff.Dual for AD).
"""
@inline function _constant_kernel(::EvalDeriv1, y_left::Tv, ::Tv, ::Tg, dL::Td, ::SideVal) where {Tv, Tg<:AbstractFloat, Td<:Real}
@inline function _constant_kernel(::EvalDeriv1, y_left::Tv, ::Tv, ::Tg, dL::Td, ::AbstractSide) where {Tv, Tg<:AbstractFloat, Td<:Real}
return zero(Tv)
end

Expand All @@ -79,7 +79,7 @@ Always returns zero (constant function has no curvature).
Returns `zero(Tv)` to preserve Complex type when applicable.
dL can be any Real (including ForwardDiff.Dual for AD).
"""
@inline function _constant_kernel(::EvalDeriv2, y_left::Tv, ::Tv, ::Tg, dL::Td, ::SideVal) where {Tv, Tg<:AbstractFloat, Td<:Real}
@inline function _constant_kernel(::EvalDeriv2, y_left::Tv, ::Tv, ::Tg, dL::Td, ::AbstractSide) where {Tv, Tg<:AbstractFloat, Td<:Real}
return zero(Tv)
end

Expand All @@ -91,6 +91,6 @@ Constant functions have all derivatives equal to zero.
Returns `zero(Tv)` to preserve Complex type when applicable.
dL can be any Real (including ForwardDiff.Dual for AD).
"""
@inline function _constant_kernel(::EvalDeriv3, y_left::Tv, ::Tv, ::Tg, dL::Td, ::SideVal) where {Tv, Tg<:AbstractFloat, Td<:Real}
@inline function _constant_kernel(::EvalDeriv3, y_left::Tv, ::Tv, ::Tg, dL::Td, ::AbstractSide) where {Tv, Tg<:AbstractFloat, Td<:Real}
return zero(Tv)
end
Loading