diff --git a/.github/workflows/Benchmark.yml b/.github/workflows/Benchmark.yml index 3cbb489c..68139983 100644 --- a/.github/workflows/Benchmark.yml +++ b/.github/workflows/Benchmark.yml @@ -41,9 +41,6 @@ jobs: - name: Cache Julia artifacts uses: julia-actions/cache@v2 - - name: Add FuseRegistry - run: julia -e 'using Pkg; Pkg.Registry.add(RegistrySpec(url="https://github.com/ProjectTorreyPines/FuseRegistry.jl.git")); Pkg.Registry.add("General"); Pkg.Registry.update()' - - name: Install dependencies run: julia --project=benchmark -e 'using Pkg; Pkg.instantiate()' diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index f3374061..bd88ed3a 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -36,9 +36,6 @@ jobs: - uses: julia-actions/cache@v2 - - name: Add FuseRegistry - run: julia -e 'using Pkg; Pkg.Registry.add(RegistrySpec(url="https://github.com/ProjectTorreyPines/FuseRegistry.jl.git")); Pkg.Registry.add("General"); Pkg.Registry.update()' - - uses: julia-actions/julia-buildpkg@v1 - uses: julia-actions/julia-runtest@v1 diff --git a/.github/workflows/Documentation.yml b/.github/workflows/Documentation.yml index 72a79793..cf3da8ec 100644 --- a/.github/workflows/Documentation.yml +++ b/.github/workflows/Documentation.yml @@ -57,15 +57,6 @@ jobs: - uses: julia-actions/cache@v2 - - name: Add FuseRegistry - run: | - rm -rf ~/.julia/registries/FuseRegistry - julia -e 'using Pkg; Pkg.Registry.add(RegistrySpec(url="https://github.com/ProjectTorreyPines/FuseRegistry.jl.git")); Pkg.Registry.add("General"); Pkg.Registry.update()' - - - name: Replace git@github.com with https in Package.toml files - run: | - find ~/.julia/registries/FuseRegistry -type f -name 'Package.toml' -exec sed -i 's|git@github.com:|https://project-torrey-pines:${{secrets.PTP_READ_TOKEN}}@github.com/|g' {} + - - name: Install dependencies run: | julia --project=docs -e ' diff --git a/.github/workflows/UpdateREADME.yml b/.github/workflows/UpdateREADME.yml index 7c827c71..62d592ae 100644 --- a/.github/workflows/UpdateREADME.yml +++ b/.github/workflows/UpdateREADME.yml @@ -42,13 +42,6 @@ jobs: # ────────────────────────────────────────────────────────────── # Benchmark Execution # ────────────────────────────────────────────────────────────── - - name: Add registries - run: | - julia -e 'using Pkg - Pkg.Registry.add(RegistrySpec(url="https://github.com/ProjectTorreyPines/FuseRegistry.jl.git")) - Pkg.Registry.add("General") - Pkg.Registry.update()' - - name: Install benchmark dependencies run: julia --project=benchmark -e 'using Pkg; Pkg.instantiate()' diff --git a/benchmark/integral_benchmark.jl b/benchmark/integral_benchmark.jl index 3fdaff69..19144caa 100644 --- a/benchmark/integral_benchmark.jl +++ b/benchmark/integral_benchmark.jl @@ -6,26 +6,26 @@ function run_integral_bench() y = @. sin(2pi*x) + 0.3x println("=== 1D Cubic Integration ===") - itp_cub = cubic_interp(x, y; extrap=:none) + itp_cub = cubic_interp(x, y; extrap=NoExtrap()) print(" full-domain: "); @btime integrate($itp_cub) print(" sub-range: "); @btime integrate($itp_cub, 0.13, 0.87) println("\n=== 1D Linear Integration ===") - itp_lin = linear_interp(x, y; extrap=:none) + itp_lin = linear_interp(x, y; extrap=NoExtrap()) print(" full-domain: "); @btime integrate($itp_lin) print(" sub-range: "); @btime integrate($itp_lin, 0.13, 0.87) println("\n=== 1D Quadratic Integration ===") - itp_quad = quadratic_interp(x, y; extrap=:none) + itp_quad = quadratic_interp(x, y; extrap=NoExtrap()) print(" full-domain: "); @btime integrate($itp_quad) print(" sub-range: "); @btime integrate($itp_quad, 0.13, 0.87) println("\n=== Extrap modes (cubic, sub-range) ===") - itp_const = cubic_interp(x, y; extrap=:constant) - itp_wrap = cubic_interp(x, y; extrap=:wrap) - print(" :none "); @btime integrate($itp_cub, 0.13, 0.87) - print(" :constant "); @btime integrate($itp_const, -0.2, 1.2) - print(" :wrap "); @btime integrate($itp_wrap, -0.2, 2.8) + itp_const = cubic_interp(x, y; extrap=ConstExtrap()) + itp_wrap = cubic_interp(x, y; extrap=WrapExtrap()) + print(" NoExtrap "); @btime integrate($itp_cub, 0.13, 0.87) + print(" ConstExtrap"); @btime integrate($itp_const, -0.2, 1.2) + print(" WrapExtrap "); @btime integrate($itp_wrap, -0.2, 2.8) println("\n=== 2D Cubic Integration ===") xg = collect(range(0.0, 1.0, length=51)) diff --git a/docs/src/api/types.md b/docs/src/api/types.md index 31207ffb..4260d940 100644 --- a/docs/src/api/types.md +++ b/docs/src/api/types.md @@ -77,7 +77,6 @@ PolyFit LinearFit QuadraticFit CubicFit -ParabolaFit ``` ### Endpoint Wrappers (Quadratic Splines) diff --git a/docs/src/boundary-conditions/overview.md b/docs/src/boundary-conditions/overview.md index 1feb6e2c..7718674c 100644 --- a/docs/src/boundary-conditions/overview.md +++ b/docs/src/boundary-conditions/overview.md @@ -116,6 +116,6 @@ PeriodicBC() # S(x) = S(x + τ) with C² continuity ## See Also - [PointBC Details](pointbc.md) — In-depth explanation of PolyFit with visualizations -- [PeriodicBC Details](periodicbc.md) — Inclusive vs exclusive endpoints, period inference, comparison with `extrap=:wrap` +- [PeriodicBC Details](periodicbc.md) — Inclusive vs exclusive endpoints, period inference, comparison with `WrapExtrap()` - [Quadratic Interpolation](../interpolation/quadratic.md) — BC examples in context - [Cubic Interpolation](../interpolation/cubic.md) — BCPair and PeriodicBC details diff --git a/docs/src/boundary-conditions/periodicbc.md b/docs/src/boundary-conditions/periodicbc.md index 069c8be6..d0e9dc41 100644 --- a/docs/src/boundary-conditions/periodicbc.md +++ b/docs/src/boundary-conditions/periodicbc.md @@ -4,11 +4,11 @@ True periodic boundary conditions for cubic splines, ensuring C² continuity (va --- -## PeriodicBC vs `extrap=:wrap` +## PeriodicBC vs `WrapExtrap()` These two features sound similar but solve fundamentally different problems: -| | `PeriodicBC()` | `extrap=:wrap` | +| | `PeriodicBC()` | `WrapExtrap()` | |---|---|---| | **What it does** | Solves a cyclic tridiagonal system (Sherman-Morrison) so the spline is **C² continuous** at the period boundary | Maps out-of-domain queries back into `[x₁, xₙ]` via modular arithmetic | | **Smoothness** | ``S, S', S''`` all match at the wrap point | No smoothness guarantee — may have jumps in value, slope, or curvature | @@ -17,7 +17,7 @@ These two features sound similar but solve fundamentally different problems: | **Use case** | Physically periodic signals (angles, phases, Fourier-sampled data) | Quick "repeat" behavior without physical periodicity | !!! tip "Rule of Thumb" - If your data is truly periodic (e.g., one full period of `sin(x)`), use `PeriodicBC`. If you just want out-of-domain queries to wrap around, use `extrap=:wrap`. + If your data is truly periodic (e.g., one full period of `sin(x)`), use `PeriodicBC`. If you just want out-of-domain queries to wrap around, use `extrap=WrapExtrap()`. --- diff --git a/docs/src/extrapolation.md b/docs/src/extrapolation.md index ffc619c7..a30483c3 100644 --- a/docs/src/extrapolation.md +++ b/docs/src/extrapolation.md @@ -4,26 +4,34 @@ Extrapolation controls behavior when query points fall outside the data domain ` ## Overview -Use the `extrap` keyword argument to specify extrapolation behavior: +All extrapolation modes are concrete subtypes of [`AbstractExtrap`](@ref). Pass them via the `extrap` keyword argument: ```julia-repl # One-shot: specify extrap per call -cubic_interp(x, y, xq; extrap=:constant) -linear_interp(x, y, xq; extrap=:extension) +cubic_interp(x, y, xq; extrap=ConstExtrap()) +linear_interp(x, y, xq; extrap=ExtendExtrap()) # Interpolant: extrap is fixed at creation -itp = cubic_interp(x, y; extrap=:extension) # all future calls use :extension -itp(xq) # uses :extension +itp = cubic_interp(x, y; extrap=ExtendExtrap()) # all future calls use ExtendExtrap +itp(xq) # uses ExtendExtrap ``` -Both `linear_interp` and `cubic_interp` support the same extrapolation modes. +All interpolation methods (`linear_interp`, `quadratic_interp`, `cubic_interp`, `constant_interp`) support the same extrapolation modes. -| Mode | Behavior | +| Type | Behavior | |------|----------| -| `:none` | Throws `DomainError` (default) | -| `:constant` | Returns boundary values | -| `:extension` | Extends boundary polynomial | -| `:wrap` | Wraps coordinates periodically (no smoothness enforced) | +| [`NoExtrap()`](@ref NoExtrap) | Throws `DomainError` (default) | +| [`ConstExtrap()`](@ref ConstExtrap) | Returns boundary values | +| [`ExtendExtrap()`](@ref ExtendExtrap) | Extends boundary polynomial | +| [`WrapExtrap()`](@ref WrapExtrap) | Wraps coordinates periodically (no smoothness enforced) | + +``` +AbstractExtrap +├── NoExtrap # DomainError on out-of-domain (default) +├── ConstExtrap # clamp to y[1] / y[end] +├── ExtendExtrap # continue boundary polynomial +└── WrapExtrap # modular coordinate mapping +``` ## Examples @@ -40,16 +48,16 @@ xq = range(x[1] - 1.5, x[end] + 1.5, 300) nothing # hide ``` -## `extrap=:none` (Default) +## `NoExtrap()` (Default) Throws `DomainError` for out-of-domain queries. Use when extrapolation is unexpected. ```julia -julia> cubic_interp(x, y, -1.0; extrap=:none) # scalar query outside domain +julia> cubic_interp(x, y, -1.0; extrap=NoExtrap()) # scalar query outside domain ERROR: DomainError with -1.0: query point outside interpolation domain [0.0, 6.0] -julia> cubic_interp(x, y, xq; extrap=:none) # vector query (xq includes out-of-domain points) +julia> cubic_interp(x, y, xq; extrap=NoExtrap()) # vector query (xq includes out-of-domain points) ERROR: DomainError with -1.5: query point outside interpolation domain [0.0, 6.0] ``` @@ -57,9 +65,9 @@ query point outside interpolation domain [0.0, 6.0] Only interior queries succeed: ```@example extrap -yq = cubic_interp(x, y, range(x[1], x[end], 200); extrap=:none) +yq = cubic_interp(x, y, range(x[1], x[end], 200); extrap=NoExtrap()) -plot(title="extrap=:none", xlabel="x", ylabel="y", legend=:topright, xlims=(x[1] - 1.5, x[end] + 1.5)) # hide +plot(title="NoExtrap()", xlabel="x", ylabel="y", legend=:topright, xlims=(x[1] - 1.5, x[end] + 1.5)) # hide vspan!([x[1] - 1.5, x[1]], alpha=0.1, color=:gray, label="out of domain") # hide vspan!([x[end], x[end] + 1.5], alpha=0.1, color=:gray, label=nothing) # hide plot!(range(x[1], x[end], 200), yq, label="spline", linewidth=2) # hide @@ -67,14 +75,14 @@ scatter!(x, y, label="data", markersize=7, color=:black) # hide vline!([x[1], x[end]], color=:gray, linestyle=:dot, alpha=0.5, label=nothing) # hide ``` -## `extrap=:constant` +## `ConstExtrap()` Returns boundary values: `y[1]` for left, `y[end]` for right. ```@example extrap -yq = cubic_interp(x, y, xq; extrap=:constant) +yq = cubic_interp(x, y, xq; extrap=ConstExtrap()) -plot(title="extrap=:constant", xlabel="x", ylabel="y", legend=:topright) # hide +plot(title="ConstExtrap()", xlabel="x", ylabel="y", legend=:topright) # hide vspan!([x[1] - 1.5, x[1]], alpha=0.1, color=:gray, label="out of domain") # hide vspan!([x[end], x[end] + 1.5], alpha=0.1, color=:gray, label=nothing) # hide plot!(xq, yq, label="spline", linewidth=2) # hide @@ -82,14 +90,14 @@ scatter!(x, y, label="data", markersize=7, color=:black) # hide vline!([x[1], x[end]], color=:gray, linestyle=:dot, alpha=0.5, label=nothing) # hide ``` -## `extrap=:extension` +## `ExtendExtrap()` Extends the boundary polynomial beyond the domain. ```@example extrap -yq = cubic_interp(x, y, xq; extrap=:extension) +yq = cubic_interp(x, y, xq; extrap=ExtendExtrap()) -plot(title="extrap=:extension", xlabel="x", ylabel="y", legend=:topright) # hide +plot(title="ExtendExtrap()", xlabel="x", ylabel="y", legend=:topright) # hide vspan!([x[1] - 1.5, x[1]], alpha=0.1, color=:gray, label="out of domain") # hide vspan!([x[end], x[end] + 1.5], alpha=0.1, color=:gray, label=nothing) # hide plot!(xq, yq, label="spline", linewidth=2) # hide @@ -97,7 +105,7 @@ scatter!(x, y, label="data", markersize=7, color=:black) # hide vline!([x[1], x[end]], color=:gray, linestyle=:dot, alpha=0.5, label=nothing) # hide ``` -## `extrap=:wrap` +## `WrapExtrap()` Wraps coordinates periodically: @@ -111,9 +119,9 @@ This is **purely coordinate mapping**—it does not enforce any physical conditi If you need C² continuity at the periodic boundary, use [`bc=PeriodicBC()`](interpolation/cubic.md) with `cubic_interp`. This enforces ``S(x_1) = S(x_{\text{end}})``, ``S'(x_1) = S'(x_{\text{end}})``, and ``S''(x_1) = S''(x_{\text{end}})``. ```@example extrap -yq = cubic_interp(x, y, xq; extrap=:wrap) +yq = cubic_interp(x, y, xq; extrap=WrapExtrap()) -plot(title="extrap=:wrap", xlabel="x", ylabel="y", legend=:topright) # hide +plot(title="WrapExtrap()", xlabel="x", ylabel="y", legend=:topright) # hide vspan!([x[1] - 1.5, x[1]], alpha=0.1, color=:gray, label="out of domain") # hide vspan!([x[end], x[end] + 1.5], alpha=0.1, color=:gray, label=nothing) # hide plot!(xq, yq, label="spline", linewidth=2) # hide @@ -125,16 +133,16 @@ vline!([x[1], x[end]], color=:gray, linestyle=:dot, alpha=0.5, label=nothing) # ```@example extrap # All three modes on same plot -y_const = cubic_interp(x, y, xq; extrap=:constant) -y_ext = cubic_interp(x, y, xq; extrap=:extension) -y_wrap = cubic_interp(x, y, xq; extrap=:wrap) +y_const = cubic_interp(x, y, xq; extrap=ConstExtrap()) +y_ext = cubic_interp(x, y, xq; extrap=ExtendExtrap()) +y_wrap = cubic_interp(x, y, xq; extrap=WrapExtrap()) plot(title="Extrapolation Comparison", xlabel="x", ylabel="y", legend=:topright, size=(700, 400)) # hide vspan!([x[1] - 1.5, x[1]], alpha=0.1, color=:gray, label=nothing) # hide vspan!([x[end], x[end] + 1.5], alpha=0.1, color=:gray, label=nothing) # hide -plot!(xq, y_const, label=":constant", linewidth=2) # hide -plot!(xq, y_ext, label=":extension", linewidth=2, linestyle=:dash) # hide -plot!(xq, y_wrap, label=":wrap", linewidth=2, linestyle=:dashdot) # hide +plot!(xq, y_const, label="ConstExtrap", linewidth=2) # hide +plot!(xq, y_ext, label="ExtendExtrap", linewidth=2, linestyle=:dash) # hide +plot!(xq, y_wrap, label="WrapExtrap", linewidth=2, linestyle=:dashdot) # hide scatter!(x, y, label="data", markersize=7, color=:black) # hide vline!([x[1], x[end]], color=:gray, linestyle=:dot, alpha=0.5, label=nothing) # hide ``` @@ -143,10 +151,10 @@ vline!([x[1], x[end]], color=:gray, linestyle=:dot, alpha=0.5, label=nothing) # | Mode | Behavior | Use Case | |------|----------|----------| -| `:none` | `DomainError` | Strict domain enforcement (default) | -| `:constant` | Returns boundary values | Physical constraints | -| `:extension` | Continues boundary polynomial | Smooth continuation | -| `:wrap` | Wraps coordinates (no smoothness) | Cyclic data (see [`PeriodicBC`](interpolation/cubic.md) for C² continuity) | +| `NoExtrap()` | `DomainError` | Strict domain enforcement (default) | +| `ConstExtrap()` | Returns boundary values | Physical constraints | +| `ExtendExtrap()` | Continues boundary polynomial | Smooth continuation | +| `WrapExtrap()` | Wraps coordinates (no smoothness) | Cyclic data (see [`PeriodicBC`](interpolation/cubic.md) for C² continuity) | ## See Also diff --git a/docs/src/guides/autodiff_support.md b/docs/src/guides/autodiff_support.md index 53c99a83..79c5485f 100644 --- a/docs/src/guides/autodiff_support.md +++ b/docs/src/guides/autodiff_support.md @@ -41,7 +41,7 @@ using ForwardDiff, FastInterpolations x = 0.0:0.5:5.0 y = sin.(x) -itp = cubic_interp(x, y; extrap=:extension) +itp = cubic_interp(x, y; extrap=ExtendExtrap()) # Compute derivative via AD grad = ForwardDiff.derivative(itp, 1.5) @@ -57,7 +57,7 @@ nothing #hide ```@example ad # Series interpolant support y1, y2 = sin.(x), cos.(x) -sitp = cubic_interp(x, [y1, y2]; extrap=:extension) +sitp = cubic_interp(x, [y1, y2]; extrap=ExtendExtrap()) grad_series = ForwardDiff.derivative(q -> sum(sitp(q)), 1.5) nothing #hide ``` @@ -85,7 +85,7 @@ using Zygote, FastInterpolations # Note: Use collect() to convert range to Vector for Zygote compatibility x = collect(0.0:0.5:5.0) y = 2.0 .* x .+ 1.0 -itp = linear_interp(x, y; extrap=:extension) +itp = linear_interp(x, y; extrap=ExtendExtrap()) # Single interpolant works grad = Zygote.gradient(itp, 1.5)[1] # Returns 2.0 @@ -97,7 +97,7 @@ nothing #hide - **Complex output**: Must use `real()` or `imag()` wrapper ```@example zygote y_complex = (2.0 + 1.0im) .* x - itp_complex = linear_interp(x, y_complex; extrap=:extension) + itp_complex = linear_interp(x, y_complex; extrap=ExtendExtrap()) # ❌ Zygote.gradient(itp_complex, 1.5) fails on complex output # ✅ Use this instead: @@ -117,7 +117,7 @@ using Enzyme, FastInterpolations x = 0.0:0.5:5.0 y = x .^ 2 -itp = quadratic_interp(x, y; extrap=:extension) +itp = quadratic_interp(x, y; extrap=ExtendExtrap()) # Use autodiff API f(xq) = itp(xq) diff --git a/docs/src/guides/optimization.md b/docs/src/guides/optimization.md index eb367660..c9b0d97f 100644 --- a/docs/src/guides/optimization.md +++ b/docs/src/guides/optimization.md @@ -18,12 +18,12 @@ xg = range(-0.7, 1.5, length=101) yg = range(-0.7, 1.5, length=101) zg = [rosenbrock(xi, yi) for xi in xg, yi in yg] -itp = cubic_interp((xg, yg), zg; extrap=:extension, bc=CubicFit()) +itp = cubic_interp((xg, yg), zg; extrap=ExtendExtrap(), bc=CubicFit()) ``` -!!! tip "Why `extrap=:extension`?" +!!! tip "Why `ExtendExtrap()`?" Trust-region and line-search methods may evaluate points outside the grid during - intermediate steps. `:extension` extrapolates smoothly from the boundary, preventing + intermediate steps. `ExtendExtrap()` extrapolates smoothly from the boundary, preventing errors without distorting the objective landscape near the boundary. ## Three Ways to Run Optimization diff --git a/docs/src/interpolation/cubic.md b/docs/src/interpolation/cubic.md index dcb29992..d9f3df43 100644 --- a/docs/src/interpolation/cubic.md +++ b/docs/src/interpolation/cubic.md @@ -67,7 +67,7 @@ PeriodicBC(endpoint=:exclusive, period=2π) # any grid → explicit period PeriodicBC uses the **Sherman-Morrison formula** to solve a cyclic tridiagonal system. This is fundamentally different from BCPair's standard tridiagonal solver. -👉 See [PeriodicBC Details](../boundary-conditions/periodicbc.md) for endpoint conventions, period inference, and comparison with `extrap=:wrap`. +👉 See [PeriodicBC Details](../boundary-conditions/periodicbc.md) for endpoint conventions, period inference, and comparison with `WrapExtrap()`. --- diff --git a/docs/src/interpolation/derivatives.md b/docs/src/interpolation/derivatives.md index 3acd4fc6..537a4c15 100644 --- a/docs/src/interpolation/derivatives.md +++ b/docs/src/interpolation/derivatives.md @@ -112,9 +112,9 @@ root = find_zero(d1, 0.5) # Find where derivative = 0 - **Extrapolation** settings are inherited by derivatives: ```julia -itp = cubic_interp(x, y; extrap=:extension) +itp = cubic_interp(x, y; extrap=ExtendExtrap()) d1 = deriv1(itp) -d1(-0.5) # Uses :extension extrapolation +d1(-0.5) # Uses ExtendExtrap extrapolation ``` ## API Summary diff --git a/docs/src/interpolation/integration.md b/docs/src/interpolation/integration.md index ef65f3fc..465c3726 100644 --- a/docs/src/interpolation/integration.md +++ b/docs/src/interpolation/integration.md @@ -98,7 +98,7 @@ x = range(0.0, 2π, 50) y = sin.(x) # Constant extrapolation means f(x) = f(x₁) for x < x₁ -itp_flat = cubic_interp(x, y; extrap=:constant) +itp_flat = cubic_interp(x, y; extrap=ConstExtrap()) # Integrates the constant value outside the domain integrate(itp_flat, -1.0, 10.0) @@ -107,10 +107,10 @@ nothing #hide | Mode | Effect on Integration | |------|-----------------------| -| `:none` | Error if bounds are outside domain. | -| `:constant` | Linearly adds area (value × distance). | -| `:extension` | Evaluation continues using the polynomial of the boundary cell. | -| `:wrap` | Periodic integration. | +| `NoExtrap()` | Error if bounds are outside domain. | +| `ConstExtrap()` | Linearly adds area (value × distance). | +| `ExtendExtrap()` | Evaluation continues using the polynomial of the boundary cell. | +| `WrapExtrap()` | Periodic integration. | --- diff --git a/docs/src/nd/boundary_conditions.md b/docs/src/nd/boundary_conditions.md index 0f4a7376..4e8bc3d0 100644 --- a/docs/src/nd/boundary_conditions.md +++ b/docs/src/nd/boundary_conditions.md @@ -48,7 +48,7 @@ bc = (NaturalBC(), PeriodicBC()) itp = cubic_interp((x, y), data2d; bc=bc) ``` !!! note "PeriodicBC + Extrapolation" - `PeriodicBC()` on an axis automatically forces `extrap=:wrap` on that axis. + `PeriodicBC()` on an axis automatically forces `WrapExtrap()` on that axis. ```@example nd_boundary # Custom: known slope at x-left, auto-fit in y diff --git a/docs/src/nd/extrapolation.md b/docs/src/nd/extrapolation.md index 46173629..6ce575fd 100644 --- a/docs/src/nd/extrapolation.md +++ b/docs/src/nd/extrapolation.md @@ -8,10 +8,10 @@ Extrapolation in ND works per-axis, using the same modes as [1D extrapolation](. | Mode | Behavior | |:-----|:---------| -| `:none` | `DomainError` (default) | -| `:constant` | Clamp to boundary value | -| `:extension` | Extend boundary polynomial | -| `:wrap` | Wrap coordinates periodically | +| `NoExtrap()` | `DomainError` (default) | +| `ConstExtrap()` | Clamp to boundary value | +| `ExtendExtrap()` | Extend boundary polynomial | +| `WrapExtrap()` | Wrap coordinates periodically | --- @@ -34,51 +34,51 @@ kw = (size=(480, 400), xlims=(-0.3,1.3), ylims=(-0.3,1.3)) nothing # hide ``` -### `extrap=:none` (Default) +### `NoExtrap()` (Default) Domain-only view — queries outside ``[0, 1]^2`` throw `DomainError`: ```@example nd_extrap -itp = cubic_interp((xs, ys), data; bc=CubicFit(), extrap=:none) +itp = cubic_interp((xs, ys), data; bc=CubicFit(), extrap=NoExtrap()) plot(itp; kw...) ``` -### `extrap=:constant` +### `ConstExtrap()` Boundary values are held constant — flat color bands extend from each edge: ```@example nd_extrap -itp = cubic_interp((xs, ys), data; bc=CubicFit(), extrap=:constant) +itp = cubic_interp((xs, ys), data; bc=CubicFit(), extrap=ConstExtrap()) plot(itp; kw...) ``` -### `extrap=:extension` +### `ExtendExtrap()` Boundary polynomials extend beyond the domain — the cubic pieces continue their natural curvature: ```@example nd_extrap -itp = cubic_interp((xs, ys), data; bc=CubicFit(), extrap=:extension) +itp = cubic_interp((xs, ys), data; bc=CubicFit(), extrap=ExtendExtrap()) plot(itp; kw...) ``` -### `extrap=:wrap` +### `WrapExtrap()` Coordinates wrap periodically. Since the data is not periodic, a visible **seam** appears at the boundaries: ```@example nd_extrap -itp = cubic_interp((xs, ys), data; bc=CubicFit(), extrap=:wrap) +itp = cubic_interp((xs, ys), data; bc=CubicFit(), extrap=WrapExtrap()) plot(itp; kw...) ``` !!! tip "Wrap vs Periodic — coordinate repetition is not periodic interpolation" - `:wrap` alone simply maps coordinates back into the domain via modular arithmetic. + `WrapExtrap()` simply maps coordinates back into the domain via modular arithmetic. The interpolant itself is **unaware** of periodicity, so a C⁰ seam (jump in derivatives) is expected at the boundary. For **true periodic interpolation**, use [`PeriodicBC()`](boundary_conditions.md) with cubic splines. `PeriodicBC()` enforces **C² continuity** at the wrap boundary — matching function value, first derivative, and second derivative across the period — producing a seamless, smooth result. - When `bc=PeriodicBC()` is set on an axis, `extrap=:wrap` is automatically applied for that axis. + When `bc=PeriodicBC()` is set on an axis, `WrapExtrap()` is automatically applied for that axis. --- @@ -87,7 +87,7 @@ plot(itp; kw...) Different extrapolation modes can be assigned independently to each axis via a tuple: ```julia -itp = cubic_interp((x, y), data; extrap=(:constant, :extension)) +itp = cubic_interp((x, y), data; extrap=(ConstExtrap(), ExtendExtrap())) ``` ### Constant × None @@ -95,7 +95,7 @@ itp = cubic_interp((x, y), data; extrap=(:constant, :extension)) Constant extrapolation on x₁, strict domain on x₂ — the heatmap extends **only horizontally**: ```@example nd_extrap -itp = cubic_interp((xs, ys), data; bc=CubicFit(), extrap=(:constant, :none)) +itp = cubic_interp((xs, ys), data; bc=CubicFit(), extrap=(ConstExtrap(), NoExtrap())) plot(itp; kw...) ``` @@ -104,7 +104,7 @@ plot(itp; kw...) Constant extrapolation on x₁, wrap periodically on x₂: ```@example nd_extrap -itp = cubic_interp((xs, ys), data; bc=CubicFit(), extrap=(:constant, :wrap)) +itp = cubic_interp((xs, ys), data; bc=CubicFit(), extrap=(ConstExtrap(), WrapExtrap())) plot(itp; kw...) ``` diff --git a/docs/src/nd/overview.md b/docs/src/nd/overview.md index 18c9902a..9c4c36ba 100644 --- a/docs/src/nd/overview.md +++ b/docs/src/nd/overview.md @@ -37,7 +37,7 @@ Every 1D argument becomes a Tuple in ND. This applies uniformly: | Query (scalar) | `xq` | `(xq, yq)` | | Query (batch) | `xqs::Vector` | `(xqs, yqs)` | | BC | `bc=NaturalBC()` | `bc=(NaturalBC(), PeriodicBC())` | -| Extrap | `extrap=:constant` | `extrap=(:constant, :wrap)` | +| Extrap | `extrap=ConstExtrap()` | `extrap=(ConstExtrap(), WrapExtrap())` | | Derivative | `deriv=1` | `deriv=(1, 0)` for ∂f/∂x | | Search | `search=Binary()` | `search=(Binary(), LinearBinary())` | diff --git a/docs/src/visualization.md b/docs/src/visualization.md index cc3a48ac..e9295e96 100644 --- a/docs/src/visualization.md +++ b/docs/src/visualization.md @@ -13,7 +13,7 @@ x = [0.0, 0.7, 1.5, 2.3, 3.0, 4.2, 5.0, 6.0] y = [0.2, 1.1, 0.6, 1.8, 1.2, 0.4, 1.5, 0.8] # Create interpolant and plot -itp = cubic_interp(x, y; extrap=:constant) +itp = cubic_interp(x, y; extrap=ConstExtrap()) plot(itp) ``` @@ -42,7 +42,7 @@ plot( x = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0] Y = [sin.(x) cos.(x) sin.(x .+ 1)] # 3 series -sitp = cubic_interp(x, Y; extrap=:extension) +sitp = cubic_interp(x, Y; extrap=ExtendExtrap()) plot(sitp, title="Multi-Series") ``` @@ -50,7 +50,7 @@ plot(sitp, title="Multi-Series") ```@example viz x = range(0, 2π, 15) -itp = cubic_interp(collect(x), sin.(x); extrap=:extension) +itp = cubic_interp(collect(x), sin.(x); extrap=ExtendExtrap()) plot( plot(itp, title="S(x)"), @@ -68,10 +68,10 @@ x = [0.0, 1.0, 2.0, 3.0, 4.0] y = sin.(x) plot( - plot(cubic_interp(x, y; extrap=:none), title="extrap=:none"), - plot(cubic_interp(x, y; extrap=:constant), title="extrap=:constant"), - plot(cubic_interp(x, y; extrap=:extension), title="extrap=:extension"), - plot(cubic_interp(x, y; extrap=:wrap), title="extrap=:wrap"), + plot(cubic_interp(x, y; extrap=NoExtrap()), title="extrap=NoExtrap()"), + plot(cubic_interp(x, y; extrap=ConstExtrap()), title="extrap=ConstExtrap()"), + plot(cubic_interp(x, y; extrap=ExtendExtrap()), title="extrap=ExtendExtrap()"), + plot(cubic_interp(x, y; extrap=WrapExtrap()), title="extrap=WrapExtrap()"), layout=(2, 2), size=(900, 600) ) ``` @@ -85,7 +85,7 @@ All standard Plots.jl attributes work alongside our custom recipe options. ```@example viz x = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0] y = [0.0, 0.8, 0.9, 0.4, 0.2, 0.6] -itp = cubic_interp(x, y; extrap=:constant) +itp = cubic_interp(x, y; extrap=ConstExtrap()) plot(itp; title="Styled Interpolant", @@ -129,7 +129,7 @@ For detailed usage, see [HelpPlots.jl](https://github.com/ProjectTorreyPines/Hel ### Customization Examples ```@example viz -itp = cubic_interp(x, y; extrap=:extension) +itp = cubic_interp(x, y; extrap=ExtendExtrap()) plot( plot(itp; show_data=false, show_bounds=false, show_outside=false, title="Curve only"), @@ -142,9 +142,9 @@ plot( ### Overlaying Interpolants ```@example viz -p = plot(constant_interp(x, y; extrap=:extension); color=:black, alpha=0.7, lw=2) -plot!(p, linear_interp(x, y; extrap=:extension); show_data=false, show_bounds=false, show_outside=false, color=:blue, alpha=0.7, lw=2) -plot!(p, cubic_interp(x, y; extrap=:extension); show_data=false, show_bounds=false, show_outside=false, color=:red, alpha=0.7, lw=2) +p = plot(constant_interp(x, y; extrap=ExtendExtrap()); color=:black, alpha=0.7, lw=2) +plot!(p, linear_interp(x, y; extrap=ExtendExtrap()); show_data=false, show_bounds=false, show_outside=false, color=:blue, alpha=0.7, lw=2) +plot!(p, cubic_interp(x, y; extrap=ExtendExtrap()); show_data=false, show_bounds=false, show_outside=false, color=:red, alpha=0.7, lw=2) plot!(p; title="Method Comparison", legend=:outertopright, xlims=(-1.5, 6.5), ylims=(-1.0, 2.0), size=(900,500)) ``` @@ -153,7 +153,7 @@ plot!(p; title="Method Comparison", legend=:outertopright, xlims=(-1.5, 6.5), yl ```@example viz x = range(0, 2π, 10) Y = [sin.(x) cos.(x) tan.(x) ./ 5] -sitp = cubic_interp(collect(x), Y; extrap=:extension) +sitp = cubic_interp(collect(x), Y; extrap=ExtendExtrap()) plot( plot(sitp; series_idx=:all, title="All series"), diff --git a/examples/rosenbrock_optim.jl b/examples/rosenbrock_optim.jl index db40253b..8771958b 100644 --- a/examples/rosenbrock_optim.jl +++ b/examples/rosenbrock_optim.jl @@ -25,8 +25,8 @@ xg = range(-0.7, 1.5, length=101) yg = range(-0.7, 1.5, length=101) zg = [rosenbrock(xi, yi) for xi in xg, yi in yg] -# extrap=:extension allows trust-region steps outside the grid without error -itp = cubic_interp((xg, yg), zg; extrap=:extension, bc=CubicFit()) +# ExtendExtrap() allows trust-region steps outside the grid without error +itp = cubic_interp((xg, yg), zg; extrap=ExtendExtrap(), bc=CubicFit()) x0 = [-0.15, 0.6] diff --git a/ext/FastInterpolationsForwardDiffExt.jl b/ext/FastInterpolationsForwardDiffExt.jl index 90a48520..948691d4 100644 --- a/ext/FastInterpolationsForwardDiffExt.jl +++ b/ext/FastInterpolationsForwardDiffExt.jl @@ -6,7 +6,7 @@ # # Usage: # using FastInterpolations, ForwardDiff -# itp = linear_interp(x, y; extrap=:extension) +# itp = linear_interp(x, y; extrap=ExtendExtrap()) # ForwardDiff.derivative(itp, 2.5) # AD through interpolation module FastInterpolationsForwardDiffExt diff --git a/ext/FastInterpolationsRecipesBaseExt.jl b/ext/FastInterpolationsRecipesBaseExt.jl index dd96e8f9..3fd5f630 100644 --- a/ext/FastInterpolationsRecipesBaseExt.jl +++ b/ext/FastInterpolationsRecipesBaseExt.jl @@ -6,7 +6,7 @@ # # Usage: # using FastInterpolations, Plots -# itp = cubic_interp(x, y; extrap=:constant) +# itp = cubic_interp(x, y; extrap=ConstExtrap()) # plot(itp) # automatic documentation-style visualization module FastInterpolationsRecipesBaseExt @@ -229,7 +229,7 @@ Generates multiple series: show_data = isnothing(show_data_opt) ? (n_data < SCATTER_THRESHOLD) : show_data_opt # Compute ylims based on extrapolation mode: - # - extrap=:none → use only original data (y_vec) + # - extrap=NoExtrap() → use only original data (y_vec) # - extrap enabled → use both data and extrapolated curve (yq) for balanced view # User-provided ylims override auto-computed limits if !isnothing(user_ylims) @@ -394,7 +394,7 @@ end yq_matrix = reduce(hcat, yq_all)' # n_samples x n_series # Compute ylims based on extrapolation mode: - # - extrap=:none → use only original data (Y) + # - extrap=NoExtrap() → use only original data (Y) # - extrap enabled → use both data and extrapolated curve for balanced view # User-provided ylims override auto-computed limits if !isnothing(user_ylims) @@ -713,7 +713,7 @@ _default_2d_margin(grid) = eltype(grid)(0.15) * (last(grid) - first(grid)) """ _has_extrap(itp::AbstractInterpolantND) -> Bool -Check if any axis of an ND interpolant has extrapolation enabled (not `:none`). +Check if any axis of an ND interpolant has extrapolation enabled (not `NoExtrap`). """ _has_extrap(itp::AbstractInterpolantND) = any(e -> !(e isa NoExtrap), itp.extraps) diff --git a/src/FastInterpolations.jl b/src/FastInterpolations.jl index 097074d7..442e10e1 100644 --- a/src/FastInterpolations.jl +++ b/src/FastInterpolations.jl @@ -48,7 +48,6 @@ export AbstractSearchPolicy, Binary, HintedBinary, Linear, LinearBinary export AbstractBC, PointBC, Deriv1, Deriv2, Deriv3, BCPair export NaturalBC, ClampedBC, PeriodicBC, MinCurvFit export PolyFit, LinearFit, QuadraticFit, CubicFit # Polynomial fitting BCs -export ParabolaFit # Deprecated alias of QuadraticFit export Left, Right # Derivative view functions and types diff --git a/src/constant/constant_anchor.jl b/src/constant/constant_anchor.jl index 25b3dd2c..eae6dd8f 100644 --- a/src/constant/constant_anchor.jl +++ b/src/constant/constant_anchor.jl @@ -66,7 +66,7 @@ Create an anchored query for ultra-fast constant interpolation at a fixed point. - `xq`: Query point (scalar) - `::Val{:constant}`: Type tag to distinguish from other anchor types - `wrap`: If true, wrap `xq` to domain [x[1], x[end]) before anchoring. - Used for `extrap=:wrap` mode. + Used for `extrap=WrapExtrap()` mode. # Returns `_ConstantAnchoredQuery{T}` with precomputed geometry. @@ -196,7 +196,7 @@ Internal implementation of _anchor_query for constant interpolation. ) where {T<:AbstractFloat, P<:Searcher} x_min, x_max = first(x), last(x) - # Handle wrapping (for extrap=:wrap mode) + # Handle wrapping (for extrap=WrapExtrap() mode) if wrap && (xq < x_min || xq >= x_max) xq = _wrap_to_domain(xq, x_min, x_max) end diff --git a/src/constant/constant_interpolant.jl b/src/constant/constant_interpolant.jl index e818b601..564dd296 100644 --- a/src/constant/constant_interpolant.jl +++ b/src/constant/constant_interpolant.jl @@ -64,7 +64,7 @@ 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()` (Symbol args deprecated) +- `extrap::AbstractExtrap`: `NoExtrap()` (default), `ConstExtrap()`, `ExtendExtrap()`, or `WrapExtrap()` - `side::Symbol`: Side selection - `search::AbstractSearchPolicy`: Default search policy (default: `Binary()`) @@ -113,7 +113,7 @@ end @inline function constant_interp( x::AbstractVector{TX}, y::AbstractVector{TY}; - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), side::Symbol=:nearest, search::AbstractSearchPolicy=Binary() ) where {TX<:Real, TY} diff --git a/src/constant/constant_oneshot.jl b/src/constant/constant_oneshot.jl index dd3636c7..43be6b2b 100644 --- a/src/constant/constant_oneshot.jl +++ b/src/constant/constant_oneshot.jl @@ -21,9 +21,9 @@ Handle extrapolation for constant interpolation. - EvalValue: returns boundary value (y[1] or y[end]) - EvalDeriv1/EvalDeriv2: returns zero (constant function) -Note: :none and :wrap modes never reach this function. -- :none throws DomainError via _check_domain -- :wrap is handled in _constant_eval_at_point before extrap check +Note: NoExtrap and WrapExtrap modes never reach this function. +- NoExtrap throws DomainError via _check_domain +- WrapExtrap is handled in _constant_eval_at_point before extrap check Type parameters: - Tg: Grid type (AbstractFloat) for xi, x_min, x_max @@ -61,7 +61,7 @@ end return zero(Tv) end -# :extension delegates to :constant (slope=0 for constant function) +# ExtendExtrap delegates to ConstExtrap (slope=0 for constant function) @inline function _constant_eval_extrap( y::AbstractVector{Tv}, xi::Tg, x_min::Tg, x_max::Tg, ::ExtendExtrap, side::SideVal, op::AbstractEvalOp @@ -76,8 +76,8 @@ end Core constant interpolation evaluation with search policy. Evaluation flow: -1. Domain check (:none mode → DomainError if outside) -2. :wrap mode → wrap to [x_min, x_max) and evaluate +1. Domain check (NoExtrap → DomainError if outside) +2. WrapExtrap → wrap to [x_min, x_max) and evaluate 3. Boundary check (xi == x_max → y[end] for non-wrap modes) 4. Extrapolation check (xi outside domain → extrap handling) 5. Interval search → kernel evaluation @@ -104,13 +104,13 @@ AD Support: xi_primal = _extract_primal(xi) xi_typed = Tg(xi_primal) - # Domain check for :none mode (throws DomainError) + # Domain check for NoExtrap mode (throws DomainError) @boundscheck _check_domain(x, xi_typed, extrap) x_min, x_max = first(x), last(x) - # :wrap mode handles all cases (inside and outside domain) - # For :wrap, the query is wrapped to domain, so use wrapped position for dL + # WrapExtrap mode handles all cases (inside and outside domain) + # For WrapExtrap, the query is wrapped to domain, so use wrapped position for dL # (AD derivative is zero for constant interp regardless) if extrap isa WrapExtrap xi_wrapped = _wrap_to_domain(xi_typed, x_min, x_max) @@ -126,7 +126,7 @@ AD Support: return op isa EvalValue ? (@inbounds y[end]) : zero(Tv) end - # Extrapolation handling (:constant, :extension) + # Extrapolation handling (ConstExtrap, ExtendExtrap) if xi_typed < x_min || xi_typed > x_max return _constant_eval_extrap(y, xi_typed, x_min, x_max, extrap, side, op) end @@ -157,7 +157,7 @@ Constant (step/piecewise constant) interpolation at a single point. - `x::AbstractVector`: x-coordinates (sorted, length ≥ 2) - `y::AbstractVector`: y-values (same length as x) - `xi::Real`: Query point -- `extrap::AbstractExtrap`: Extrapolation mode (Symbol args deprecated) +- `extrap::AbstractExtrap`: Extrapolation mode - `NoExtrap()` (default): throws DomainError if outside domain - `ConstExtrap()`: clamp to boundary values - `ExtendExtrap()`: same as ConstExtrap (slope=0) @@ -197,7 +197,7 @@ vals = constant_interp(x, y, sorted_queries; search=LinearBinary(linear_window=8 x::AbstractVector{Tg}, y::AbstractVector{Tv}, xi::Tq; - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), side::Symbol=:nearest, deriv::Int=0, search=Binary(), @@ -206,11 +206,9 @@ vals = constant_interp(x, y, sorted_queries; search=LinearBinary(linear_window=8 @boundscheck length(y) == length(x) || throw(ArgumentError("x and y must have same length")) searcher = _to_searcher(search, hint) - extrap isa Symbol && Base.depwarn(_EXTRAP_SYMBOL_DEPWARN, :constant_interp) - mode = extrap isa Symbol ? _symbol_to_extrap_mode(extrap) : extrap @_dispatch_deriv deriv => op begin @_dispatch_side side => sv begin - _constant_eval_at_point(x, y, xi, mode, sv, op, searcher) + _constant_eval_at_point(x, y, xi, extrap, sv, op, searcher) end end end @@ -220,7 +218,7 @@ end # ======================================== """ - constant_interp!(output, x, y, x_targets; extrap=:none, side=:nearest, deriv=0, search=Binary()) + constant_interp!(output, x, y, x_targets; extrap=NoExtrap(), side=:nearest, deriv=0, search=Binary()) Zero-allocation constant interpolation for multiple query points. @@ -249,7 +247,7 @@ function constant_interp!( x::AbstractVector{Tg}, y::AbstractVector{Tv}, x_targets::AbstractVector{Tg}; - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), side::Symbol=:nearest, deriv::Int=0, search::AbstractSearchPolicy=Binary() @@ -258,13 +256,11 @@ function constant_interp!( @assert length(output) == length(x_targets) "output must match x_targets length" searcher = _to_searcher(search) - extrap isa Symbol && Base.depwarn(_EXTRAP_SYMBOL_DEPWARN, :constant_interp!) - mode = extrap isa Symbol ? _symbol_to_extrap_mode(extrap) : extrap @_dispatch_deriv deriv => op begin @_dispatch_side side => sv begin - @boundscheck _check_domain(x, x_targets, mode) + @boundscheck _check_domain(x, x_targets, extrap) @inbounds for i in eachindex(x_targets, output) - output[i] = _constant_eval_at_point(x, y, x_targets[i], mode, sv, op, searcher) + output[i] = _constant_eval_at_point(x, y, x_targets[i], extrap, sv, op, searcher) end end end @@ -276,7 +272,7 @@ end # ======================================== """ - constant_interp(x, y, x_targets; extrap=:none, side=:nearest, deriv=0, search=Binary()) + constant_interp(x, y, x_targets; extrap=NoExtrap(), side=:nearest, deriv=0, search=Binary()) Constant interpolation for multiple query points (allocating version). @@ -296,7 +292,7 @@ function constant_interp( x::AbstractVector{Tg}, y::AbstractVector{Tv}, x_targets::AbstractVector{Tg}; - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), side::Symbol=:nearest, deriv::Int=0, search::AbstractSearchPolicy=Binary() @@ -323,7 +319,7 @@ end x::AbstractVector{Tg}, y::AbstractVector{Tv}, xi::Tq; - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), side::Symbol=:nearest, deriv::Int=0, search=Binary(), @@ -343,7 +339,7 @@ function constant_interp( x::AbstractVector{Tg}, y::AbstractVector{Tv}, x_targets::AbstractVector{Tq}; - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), side::Symbol=:nearest, deriv::Int=0, search::AbstractSearchPolicy=Binary() @@ -364,7 +360,7 @@ function constant_interp!( x::AbstractVector{Tg}, y::AbstractVector{Tv}, x_targets::AbstractVector{Tq}; - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), side::Symbol=:nearest, deriv::Int=0, search::AbstractSearchPolicy=Binary() diff --git a/src/constant/constant_series_interp.jl b/src/constant/constant_series_interp.jl index cda70ac1..d54b4925 100644 --- a/src/constant/constant_series_interp.jl +++ b/src/constant/constant_series_interp.jl @@ -311,7 +311,7 @@ Create a multi-Y constant interpolant for multiple y-data series sharing the sam - `x::AbstractVector`: x-coordinates (sorted, length ≥ 2) - `ys`: Vector of y-value vectors (all same length as x) - `side`: Side for discontinuities (:left, :right, :nearest) -- `extrap::AbstractExtrap`: `NoExtrap()`, `ConstExtrap()`, `ExtendExtrap()`, or `WrapExtrap()` (Symbol args deprecated) +- `extrap::AbstractExtrap`: `NoExtrap()`, `ConstExtrap()`, `ExtendExtrap()`, or `WrapExtrap()` # Returns `ConstantSeriesInterpolant` object with matrix storage. @@ -332,7 +332,7 @@ function constant_interp( x::AbstractVector{Tg}, ys::AbstractVector{<:AbstractVector{Tv}}; side::Symbol=:nearest, - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), search::P=Binary() ) where {Tg<:AbstractFloat, Tv, P<:AbstractSearchPolicy} # Check if Tv's float base requires grid widening (not for Int types) @@ -367,10 +367,8 @@ function constant_interp( y_mat[:, k] .= Tv_out.(ys[k]) end - extrap isa Symbol && Base.depwarn(_EXTRAP_SYMBOL_DEPWARN, :constant_interp) - mode = extrap isa Symbol ? _symbol_to_extrap_mode(extrap) : extrap @_dispatch_side side => side_val begin - return ConstantSeriesInterpolant(x, y_mat, mode, side_val, search) + return ConstantSeriesInterpolant(x, y_mat, extrap, side_val, search) end end @@ -397,7 +395,7 @@ function constant_interp( x::AbstractVector{Tg}, Y::AbstractMatrix{Tv}; side::Symbol=:nearest, - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), search::AbstractSearchPolicy=Binary() ) where {Tg<:AbstractFloat, Tv} # Check if Tv's float base requires grid widening @@ -421,10 +419,8 @@ function constant_interp( Tv_out = _value_type(Tv, Tg) y_mat = Tv_out === Tv ? copy(Y) : Tv_out.(Y) - extrap isa Symbol && Base.depwarn(_EXTRAP_SYMBOL_DEPWARN, :constant_interp) - mode = extrap isa Symbol ? _symbol_to_extrap_mode(extrap) : extrap @_dispatch_side side => side_val begin - return ConstantSeriesInterpolant(x, y_mat, mode, side_val, search) + return ConstantSeriesInterpolant(x, y_mat, extrap, side_val, search) end end @@ -438,7 +434,7 @@ function constant_interp( x::AbstractVector{Tg}, ys::AbstractVector{<:AbstractVector{Tv}}; side::Symbol=:nearest, - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), search::AbstractSearchPolicy=Binary() ) where {Tg<:Real, Tv} # Compute promoted grid type (Tg may be Int, promotes to Float) @@ -452,7 +448,7 @@ function constant_interp( x::AbstractVector{Tg}, Y::AbstractMatrix{Tv}; side::Symbol=:nearest, - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), search::AbstractSearchPolicy=Binary() ) where {Tg<:Real, Tv} Tg_float = float(promote_type(Tg, _real_eltype(Tv))) diff --git a/src/constant/constant_types.jl b/src/constant/constant_types.jl index 6089d28e..4670af11 100644 --- a/src/constant/constant_types.jl +++ b/src/constant/constant_types.jl @@ -68,7 +68,6 @@ end # ======================================== # Outer Constructor: typed inputs only # ======================================== -# - Symbol → Val dispatch # - Call inner constructor # # PERFORMANCE: Typed signature + @inline enables compile-time specialization. @@ -76,14 +75,12 @@ end @inline function ConstantInterpolant( x::X, y::Y; - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), side::Symbol=:nearest, search::P=Binary() ) where {Tg<:AbstractFloat, Tv, X<:AbstractVector{Tg}, Y<:AbstractVector{Tv}, P<:AbstractSearchPolicy} - extrap isa Symbol && Base.depwarn(_EXTRAP_SYMBOL_DEPWARN, :constant_interp) - mode = extrap isa Symbol ? _symbol_to_extrap_mode(extrap) : extrap - E = typeof(mode) + E = typeof(extrap) @_dispatch_side side => sv begin - return ConstantInterpolant{Tg,Tv,X,Y,E,P}(x, y, mode, sv, search) + return ConstantInterpolant{Tg,Tv,X,Y,E,P}(x, y, extrap, sv, search) end end diff --git a/src/constant/nd/constant_nd_interpolant.jl b/src/constant/nd/constant_nd_interpolant.jl index a8e22405..3390e4cc 100644 --- a/src/constant/nd/constant_nd_interpolant.jl +++ b/src/constant/nd/constant_nd_interpolant.jl @@ -20,7 +20,7 @@ Create an N-dimensional constant interpolant with tuple-grid API. # Keyword Arguments - `side=:nearest`: Side selection mode (`:nearest`, `:left`, `:right`) or per-axis tuple -- `extrap=:none`: Extrapolation mode (`:none`, `:constant`, `:extension`, `:wrap`) or per-axis tuple +- `extrap=NoExtrap()`: Extrapolation mode (`NoExtrap()`, `ConstExtrap()`, `ExtendExtrap()`, `WrapExtrap()`) or per-axis tuple - `search=Binary()`: Search policy or per-axis tuple # Returns @@ -41,7 +41,7 @@ vals = itp(points) # Batch AoS # Per-axis configuration itp = constant_interp((x, y), data; side=(:left, :right), - extrap=(:none, :wrap), + extrap=(NoExtrap(), WrapExtrap()), search=(Binary(), LinearBinary()) ) ``` @@ -50,7 +50,7 @@ function constant_interp( grids::NTuple{N, AbstractVector}, data::AbstractArray{Tv_raw, N}; side::Union{Symbol, NTuple{N, Symbol}} = :nearest, - extrap::Union{Symbol, NTuple{N, Symbol}, AbstractExtrap, NTuple{N, AbstractExtrap}} = NoExtrap(), + extrap::Union{AbstractExtrap, NTuple{N, AbstractExtrap}} = NoExtrap(), search::Union{AbstractSearchPolicy, NTuple{N, AbstractSearchPolicy}} = Binary() ) where {N, Tv_raw} # Validate grid dimensions @@ -74,25 +74,12 @@ function constant_interp( sides = _resolve_side_nd(side, Val(N)) searches = _resolve_search_nd(search, Val(N)) - if extrap isa AbstractExtrap || extrap isa Tuple{Vararg{AbstractExtrap}} - extrap_vals = _resolve_extrap_nd(extrap, nothing, Val(N)) - @_dispatch_side_nd sides => side_vals begin - return ConstantInterpolantND{Tg, Tv, N, - typeof(grids_typed), typeof(spacings), typeof(extrap_vals), typeof(side_vals), typeof(searches)}( - grids_typed, spacings, Array(data_typed), extrap_vals, side_vals, searches - ) - end - else - Base.depwarn(_EXTRAP_SYMBOL_DEPWARN, :constant_interp) - extraps = _resolve_extrap_nd(extrap, Val(N)) - @_dispatch_extrap_nd extraps nothing => extrap_vals begin - @_dispatch_side_nd sides => side_vals begin - return ConstantInterpolantND{Tg, Tv, N, - typeof(grids_typed), typeof(spacings), typeof(extrap_vals), typeof(side_vals), typeof(searches)}( - grids_typed, spacings, Array(data_typed), extrap_vals, side_vals, searches - ) - end - end + extrap_vals = _resolve_extrap_nd(extrap, nothing, Val(N)) + @_dispatch_side_nd sides => side_vals begin + return ConstantInterpolantND{Tg, Tv, N, + typeof(grids_typed), typeof(spacings), typeof(extrap_vals), typeof(side_vals), typeof(searches)}( + grids_typed, spacings, Array(data_typed), extrap_vals, side_vals, searches + ) end end diff --git a/src/constant/nd/constant_nd_oneshot.jl b/src/constant/nd/constant_nd_oneshot.jl index 19b0b8ac..2562536b 100644 --- a/src/constant/nd/constant_nd_oneshot.jl +++ b/src/constant/nd/constant_nd_oneshot.jl @@ -150,7 +150,7 @@ function constant_interp( data::AbstractArray{Tv, N}, query::Tuple{Vararg{Real, N}}; side::Union{Symbol, NTuple{N, Symbol}} = :nearest, - extrap::Union{Symbol, NTuple{N, Symbol}, AbstractExtrap, NTuple{N, AbstractExtrap}} = NoExtrap(), + extrap::Union{AbstractExtrap, NTuple{N, AbstractExtrap}} = NoExtrap(), search::Union{AbstractSearchPolicy, NTuple{N, AbstractSearchPolicy}} = Binary(), deriv::Union{Int, Val, NTuple{N,Int}} = 0 ) where {Tv, N} @@ -167,21 +167,10 @@ function constant_interp( sides = _resolve_side_nd(side, Val(N)) searches = _resolve_search_nd(search, Val(N)) - if extrap isa AbstractExtrap || extrap isa Tuple{Vararg{AbstractExtrap}} - extraps_val = _resolve_extrap_nd(extrap, nothing, Val(N)) - @_dispatch_side_nd sides => side_vals begin - return _constant_interp_nd_oneshot( - grids_typed, data, query, extraps_val, side_vals, searches)::Tv - end - else - Base.depwarn(_EXTRAP_SYMBOL_DEPWARN, :constant_interp) - extraps = _resolve_extrap_nd(extrap, Val(N)) - @_dispatch_extrap_nd extraps nothing => extraps_val begin - @_dispatch_side_nd sides => side_vals begin - return _constant_interp_nd_oneshot( - grids_typed, data, query, extraps_val, side_vals, searches)::Tv - end - end + extraps_val = _resolve_extrap_nd(extrap, nothing, Val(N)) + @_dispatch_side_nd sides => side_vals begin + return _constant_interp_nd_oneshot( + grids_typed, data, query, extraps_val, side_vals, searches)::Tv end end @@ -196,7 +185,7 @@ function constant_interp( data::AbstractArray{Tv, N}, queries::NTuple{N, AbstractVector{<:Real}}; side::Union{Symbol, NTuple{N, Symbol}} = :nearest, - extrap::Union{Symbol, NTuple{N, Symbol}, AbstractExtrap, NTuple{N, AbstractExtrap}} = NoExtrap(), + extrap::Union{AbstractExtrap, NTuple{N, AbstractExtrap}} = NoExtrap(), search::Union{AbstractSearchPolicy, NTuple{N, AbstractSearchPolicy}} = Binary(), deriv::Union{Int, Val, NTuple{N,Int}} = 0 ) where {Tv, N} @@ -213,21 +202,10 @@ function constant_interp( sides = _resolve_side_nd(side, Val(N)) searches = _resolve_search_nd(search, Val(N)) - if extrap isa AbstractExtrap || extrap isa Tuple{Vararg{AbstractExtrap}} - extraps_val = _resolve_extrap_nd(extrap, nothing, Val(N)) - @_dispatch_side_nd sides => side_vals begin - return _constant_interp_nd_oneshot_soa( - grids_typed, data, queries, extraps_val, side_vals, searches)::Vector{Tv} - end - else - Base.depwarn(_EXTRAP_SYMBOL_DEPWARN, :constant_interp) - extraps = _resolve_extrap_nd(extrap, Val(N)) - @_dispatch_extrap_nd extraps nothing => extraps_val begin - @_dispatch_side_nd sides => side_vals begin - return _constant_interp_nd_oneshot_soa( - grids_typed, data, queries, extraps_val, side_vals, searches)::Vector{Tv} - end - end + extraps_val = _resolve_extrap_nd(extrap, nothing, Val(N)) + @_dispatch_side_nd sides => side_vals begin + return _constant_interp_nd_oneshot_soa( + grids_typed, data, queries, extraps_val, side_vals, searches)::Vector{Tv} end end @@ -242,7 +220,7 @@ function constant_interp( data::AbstractArray{Tv, N}, queries::AbstractVector{<:Tuple{Vararg{Real, N}}}; side::Union{Symbol, NTuple{N, Symbol}} = :nearest, - extrap::Union{Symbol, NTuple{N, Symbol}, AbstractExtrap, NTuple{N, AbstractExtrap}} = NoExtrap(), + extrap::Union{AbstractExtrap, NTuple{N, AbstractExtrap}} = NoExtrap(), search::Union{AbstractSearchPolicy, NTuple{N, AbstractSearchPolicy}} = Binary(), deriv::Union{Int, Val, NTuple{N,Int}} = 0 ) where {Tv, N} @@ -259,21 +237,10 @@ function constant_interp( sides = _resolve_side_nd(side, Val(N)) searches = _resolve_search_nd(search, Val(N)) - if extrap isa AbstractExtrap || extrap isa Tuple{Vararg{AbstractExtrap}} - extraps_val = _resolve_extrap_nd(extrap, nothing, Val(N)) - @_dispatch_side_nd sides => side_vals begin - return _constant_interp_nd_oneshot_aos( - grids_typed, data, queries, extraps_val, side_vals, searches)::Vector{Tv} - end - else - Base.depwarn(_EXTRAP_SYMBOL_DEPWARN, :constant_interp) - extraps = _resolve_extrap_nd(extrap, Val(N)) - @_dispatch_extrap_nd extraps nothing => extraps_val begin - @_dispatch_side_nd sides => side_vals begin - return _constant_interp_nd_oneshot_aos( - grids_typed, data, queries, extraps_val, side_vals, searches)::Vector{Tv} - end - end + extraps_val = _resolve_extrap_nd(extrap, nothing, Val(N)) + @_dispatch_side_nd sides => side_vals begin + return _constant_interp_nd_oneshot_aos( + grids_typed, data, queries, extraps_val, side_vals, searches)::Vector{Tv} end end @@ -293,7 +260,7 @@ function constant_interp!( data::AbstractArray{Tv, N}, queries::NTuple{N, AbstractVector{<:Real}}; side::Union{Symbol, NTuple{N, Symbol}} = :nearest, - extrap::Union{Symbol, NTuple{N, Symbol}, AbstractExtrap, NTuple{N, AbstractExtrap}} = NoExtrap(), + extrap::Union{AbstractExtrap, NTuple{N, AbstractExtrap}} = NoExtrap(), search::Union{AbstractSearchPolicy, NTuple{N, AbstractSearchPolicy}} = Binary(), deriv::Union{Int, Val, NTuple{N,Int}} = 0 ) where {Tv, N} @@ -310,21 +277,10 @@ function constant_interp!( sides = _resolve_side_nd(side, Val(N)) searches = _resolve_search_nd(search, Val(N)) - if extrap isa AbstractExtrap || extrap isa Tuple{Vararg{AbstractExtrap}} - extraps_val = _resolve_extrap_nd(extrap, nothing, Val(N)) - @_dispatch_side_nd sides => side_vals begin - return _constant_interp_nd_oneshot_soa!( - output, grids_typed, data, queries, extraps_val, side_vals, searches) - end - else - Base.depwarn(_EXTRAP_SYMBOL_DEPWARN, :constant_interp!) - extraps = _resolve_extrap_nd(extrap, Val(N)) - @_dispatch_extrap_nd extraps nothing => extraps_val begin - @_dispatch_side_nd sides => side_vals begin - return _constant_interp_nd_oneshot_soa!( - output, grids_typed, data, queries, extraps_val, side_vals, searches) - end - end + extraps_val = _resolve_extrap_nd(extrap, nothing, Val(N)) + @_dispatch_side_nd sides => side_vals begin + return _constant_interp_nd_oneshot_soa!( + output, grids_typed, data, queries, extraps_val, side_vals, searches) end end @@ -340,7 +296,7 @@ function constant_interp!( data::AbstractArray{Tv, N}, queries::AbstractVector{<:Tuple{Vararg{Real, N}}}; side::Union{Symbol, NTuple{N, Symbol}} = :nearest, - extrap::Union{Symbol, NTuple{N, Symbol}, AbstractExtrap, NTuple{N, AbstractExtrap}} = NoExtrap(), + extrap::Union{AbstractExtrap, NTuple{N, AbstractExtrap}} = NoExtrap(), search::Union{AbstractSearchPolicy, NTuple{N, AbstractSearchPolicy}} = Binary(), deriv::Union{Int, Val, NTuple{N,Int}} = 0 ) where {Tv, N} @@ -357,20 +313,9 @@ function constant_interp!( sides = _resolve_side_nd(side, Val(N)) searches = _resolve_search_nd(search, Val(N)) - if extrap isa AbstractExtrap || extrap isa Tuple{Vararg{AbstractExtrap}} - extraps_val = _resolve_extrap_nd(extrap, nothing, Val(N)) - @_dispatch_side_nd sides => side_vals begin - return _constant_interp_nd_oneshot_aos!( - output, grids_typed, data, queries, extraps_val, side_vals, searches) - end - else - Base.depwarn(_EXTRAP_SYMBOL_DEPWARN, :constant_interp!) - extraps = _resolve_extrap_nd(extrap, Val(N)) - @_dispatch_extrap_nd extraps nothing => extraps_val begin - @_dispatch_side_nd sides => side_vals begin - return _constant_interp_nd_oneshot_aos!( - output, grids_typed, data, queries, extraps_val, side_vals, searches) - end - end + extraps_val = _resolve_extrap_nd(extrap, nothing, Val(N)) + @_dispatch_side_nd sides => side_vals begin + return _constant_interp_nd_oneshot_aos!( + output, grids_typed, data, queries, extraps_val, side_vals, searches) end end diff --git a/src/constant/nd/constant_nd_types.jl b/src/constant/nd/constant_nd_types.jl index 37c5ed7b..779469b5 100644 --- a/src/constant/nd/constant_nd_types.jl +++ b/src/constant/nd/constant_nd_types.jl @@ -35,14 +35,14 @@ x = [0.0, 1.0, 2.0] y = [0.0, 1.0, 2.0, 3.0] data = rand(3, 4) -itp = constant_interp((x, y), data) # Default: side=:nearest, extrap=:none +itp = constant_interp((x, y), data) # Default: side=:nearest, extrap=NoExtrap() val = itp((0.5, 1.5)) # Single query # With configuration -itp = constant_interp((x, y), data; side=:left, extrap=:constant) +itp = constant_interp((x, y), data; side=:left, extrap=ConstExtrap()) # Per-axis configuration -itp = constant_interp((x, y), data; side=(:left, :right), extrap=(:none, :wrap)) +itp = constant_interp((x, y), data; side=(:left, :right), extrap=(NoExtrap(), WrapExtrap())) ``` """ struct ConstantInterpolantND{ diff --git a/src/core/bc_types.jl b/src/core/bc_types.jl index e4d2faa1..896db019 100644 --- a/src/core/bc_types.jl +++ b/src/core/bc_types.jl @@ -396,15 +396,6 @@ itp = quadratic_interp(x, y; bc=Left(QuadraticFit())) """ const QuadraticFit = PolyFit{2} -""" - ParabolaFit - -Deprecated alias for [`QuadraticFit`](@ref). -""" -function ParabolaFit(args...) - Base.depwarn("ParabolaFit is deprecated and has been renamed to QuadraticFit; please use QuadraticFit instead.", :ParabolaFit) - QuadraticFit(args...) -end """ diff --git a/src/core/eval_ops.jl b/src/core/eval_ops.jl index 24300d0a..439ff3a4 100644 --- a/src/core/eval_ops.jl +++ b/src/core/eval_ops.jl @@ -57,32 +57,21 @@ interval endpoints, and h is the interval width. """ struct EvalDeriv3 <: AbstractEvalOp end -""" - ExtrapVal - -Union type for extrapolation mode values. -Using concrete Union enables Julia's union-splitting optimization. -""" -const ExtrapVal = Union{Val{:none}, Val{:constant}, Val{:extension}, Val{:wrap}} - # ======================================== # Typed Extrapolation Mode Tags # ======================================== # # Compile-time type tags for extrapolation mode selection. -# These replace runtime Symbol dispatch (:none, :constant, etc.) -# with zero-cost type dispatch at the API boundary. +# Zero-cost type dispatch at the API boundary. # # 1D: Structs store E<:AbstractExtrap, dispatch on concrete subtypes -# ND: Structs store NTuple{N,AbstractExtrap}; @_dispatch_extrap_nd resolves -# Symbol specs into concrete mode tuples at the API boundary +# ND: Structs store NTuple{N,AbstractExtrap}, resolved via _resolve_extrap_nd """ AbstractExtrap Abstract type for typed extrapolation mode specification. -Use concrete subtypes at the API boundary for compile-time dispatch -instead of runtime Symbol comparison. +Use concrete subtypes at the API boundary for compile-time dispatch. # Concrete subtypes - [`NoExtrap`](@ref): Throw `DomainError` for out-of-domain queries @@ -101,7 +90,6 @@ abstract type AbstractExtrap end NoExtrap <: AbstractExtrap No extrapolation — throws `DomainError` for out-of-domain queries. -Replaces `extrap=:none`. # Example ```julia @@ -114,7 +102,6 @@ struct NoExtrap <: AbstractExtrap end ConstExtrap <: AbstractExtrap Constant extrapolation — clamps queries to the nearest boundary value. -Replaces `extrap=:constant`. # Example ```julia @@ -127,7 +114,6 @@ struct ConstExtrap <: AbstractExtrap end ExtendExtrap <: AbstractExtrap Extension extrapolation — extends the interpolation polynomial beyond the domain. -Replaces `extrap=:extension`. # Example ```julia @@ -140,7 +126,7 @@ struct ExtendExtrap <: AbstractExtrap end WrapExtrap <: AbstractExtrap Wrap extrapolation — wraps queries into the domain using modular arithmetic. -For periodic data. Replaces `extrap=:wrap`. +For periodic data. # Example ```julia @@ -149,20 +135,6 @@ itp = cubic_interp((x, y), data; extrap=WrapExtrap()) """ struct WrapExtrap <: AbstractExtrap end -""" - _symbol_to_extrap_mode(extrap::Symbol) -> AbstractExtrap - -Convert a Symbol extrapolation specifier to the corresponding `AbstractExtrap` singleton. -Used in the legacy Symbol → Mode conversion path. -""" -@inline function _symbol_to_extrap_mode(extrap::Symbol) - extrap === :none && return NoExtrap() - extrap === :constant && return ConstExtrap() - extrap === :extension && return ExtendExtrap() - extrap === :wrap && return WrapExtrap() - throw(ArgumentError("`extrap` must be :none, :constant, :extension, or :wrap, got :$extrap")) -end - """ SideVal diff --git a/src/core/nd_utils.jl b/src/core/nd_utils.jl index 9c619e64..17da35fd 100644 --- a/src/core/nd_utils.jl +++ b/src/core/nd_utils.jl @@ -30,38 +30,9 @@ end # ======================================== # Extrapolation Resolution # ======================================== - -""" - _resolve_extrap_nd(extrap, Val(N)) -> NTuple{N, Symbol} - -Resolve extrapolation mode to canonical N-tuple. -- Single `Symbol` → broadcast to all N axes (validated) -- `NTuple{N, Symbol}` → validate each and passthrough -""" -@inline function _resolve_extrap_nd(extrap::Symbol, ::Val{N}) where {N} - _validate_extrap(extrap) - return ntuple(_ -> extrap, Val(N)) -end - -@inline function _resolve_extrap_nd(extrap::NTuple{N,Symbol}, ::Val{N}) where {N} - @inbounds for i in 1:N - _validate_extrap(extrap[i]) - end - return extrap -end - -@inline function _resolve_extrap_nd(extrap::Tuple{Vararg{Symbol}}, ::Val{N}) where {N} - throw(ArgumentError("extrap tuple must have $N elements to match grid dimensions, got $(length(extrap))")) -end - -# ======================================== -# Typed Extrap Resolution (3-arg form) -# ======================================== -# -# 3-arg _resolve_extrap_nd(extrap, bcs, Val(N)): -# - Mode types → NTuple{N, Val} directly (fast path, compile-time resolvable) -# - Symbol types → NTuple{N, Symbol} with Base.depwarn (legacy path) # +# _resolve_extrap_nd(extrap, bcs, Val(N)): +# Converts user-facing extrap input to NTuple{N, AbstractExtrap}. # The `bcs` argument enables periodic BC validation and override: # - `nothing` for constant/linear (no BCs) # - NTuple{N, AbstractBC} for quadratic/cubic @@ -142,9 +113,6 @@ end :(($(exprs...),)) end -# ── Legacy Symbol depwarn constant (used by public API functions) ────── - -const _EXTRAP_SYMBOL_DEPWARN = "Passing `extrap` as Symbol is deprecated. Use NoExtrap(), ConstExtrap(), ExtendExtrap(), or WrapExtrap() instead." # ======================================== # Search Policy Resolution @@ -213,20 +181,6 @@ end throw(ArgumentError("side tuple must have $N elements to match grid dimensions, got $(length(side))")) end -# ======================================== -# Symbol → Val Conversion -# ======================================== - -""" - _to_extrap_vals(extraps::NTuple{N, Symbol}) -> NTuple{N, Val} - -Convert extrapolation symbol tuple to Val tuple for type-stable dispatch. -Used by Interpolant constructors (linear, constant) that store extrap as Val types. -""" -@inline function _to_extrap_vals(extraps::NTuple{N, Symbol}) where {N} - return ntuple(i -> Val(extraps[i]), Val(N)) -end - # ======================================== # Derivative Order → EvalOp Conversion # ======================================== @@ -403,39 +357,6 @@ avoiding ntuple-closure boxing on heterogeneous tuple inputs. """ @inline _extrap_axis(q, grid, extrap) = @inbounds _handle_axis_extrap(q, grid, extrap) -@inline function _handle_all_extraps( - queries::Tuple{Vararg{Real,N}}, grids::Tuple{Vararg{AbstractVector,N}}, extraps::Tuple{Vararg{Val,N}} -) where {N} - map(_extrap_axis, queries, grids, extraps) -end - -# Extrapolation handlers for each mode -# Note: Preserve query type (don't convert to Tg) for AD support (ForwardDiff.Dual) - -@inline function _handle_axis_extrap(q, axis::AbstractVector, ::Val{:none}) - @boundscheck _check_domain(axis, q, Val(:none)) - return q # preserve original type for AD -end - -@inline function _handle_axis_extrap(q, axis::AbstractVector{Tg}, ::Val{:constant}) where {Tg} - # For AD: use primal for comparison, preserve type when in domain - q_primal = _extract_primal(q) - lo, hi = first(axis), last(axis) - q_primal < lo && return oftype(q, lo) # outside domain: return boundary - q_primal > hi && return oftype(q, hi) - return q # in domain: preserve original type for AD -end - -@inline function _handle_axis_extrap(q, axis::AbstractVector, ::Val{:extension}) - return q # Allow queries outside domain (for polynomial/constant extension) -end - -@inline function _handle_axis_extrap(q, axis::AbstractVector, ::Val{:wrap}) - return _wrap_to_domain(q, first(axis), last(axis)) # already handles AD via _extract_primal -end - -# ── AbstractExtrap dispatch (ND storage uses Mode types directly) ── - @inline function _handle_all_extraps( queries::Tuple{Vararg{Real,N}}, grids::Tuple{Vararg{AbstractVector,N}}, extraps::Tuple{Vararg{AbstractExtrap,N}} diff --git a/src/core/periodic.jl b/src/core/periodic.jl index 0952a5a3..0027dfe7 100644 --- a/src/core/periodic.jl +++ b/src/core/periodic.jl @@ -15,7 +15,7 @@ _wrap_to_domain(xi::FT, x_min::FT, x_max::FT) where {FT<:AbstractFloat} Wrap a query point `xi` to the domain [x_min, x_max). -Used for periodic boundary conditions and extrap=:wrap. +Used for periodic boundary conditions and extrap=WrapExtrap(). Optimized: skips expensive `mod()` when xi is already in domain. """ diff --git a/src/core/show.jl b/src/core/show.jl index 5f58565d..ff7b7299 100644 --- a/src/core/show.jl +++ b/src/core/show.jl @@ -12,7 +12,7 @@ # - Type param (Float64): light_blue # - Labels & box chars: light_black # - Values (Grid, Search, BC, etc.): default (terminal text color) -# - Symbols only (:none, :wrap, etc.): magenta +# - Extrap types (NoExtrap, WrapExtrap, etc.): magenta # ======================================== # Helper Functions @@ -102,17 +102,12 @@ function _show_grid_row(io::IO, is_last::Bool, x::AbstractVector) print(io, ", $n points ∈ [$x_min_str, $x_max_str]") end -"""Format extrapolation mode from AbstractExtrap or ExtrapVal.""" +"""Format extrapolation mode from AbstractExtrap.""" function _format_extrap(mode) mode isa NoExtrap && return "NoExtrap" mode isa ConstExtrap && return "ConstExtrap" mode isa ExtendExtrap && return "ExtendExtrap" mode isa WrapExtrap && return "WrapExtrap" - # Val fallback for legacy/internal callers - mode === Val(:none) && return "NoExtrap" - mode === Val(:constant) && return "ConstExtrap" - mode === Val(:extension) && return "ExtendExtrap" - mode === Val(:wrap) && return "WrapExtrap" return "unknown" end diff --git a/src/core/utils.jl b/src/core/utils.jl index ba3307ca..083cc7ce 100644 --- a/src/core/utils.jl +++ b/src/core/utils.jl @@ -273,60 +273,6 @@ _promote_for_anchor(dual, Float64) # → dual (preserved Dual type) # Domain Validation Helpers # ======================================== -""" - _check_domain(x, xi, ::Val{:none}) - -Check if scalar query point is within domain for `:none` extrapolation mode. -Throws `DomainError` if `xi` is outside `[first(x), last(x)]`. - -Type-relaxed: accepts any Real query type (Int, Float32, Float64, Dual, etc.) -to avoid unnecessary type conversions at call sites. - -Uses `@boundscheck` so it's skipped in `@inbounds` blocks for vector paths -that do a single upfront check via the vector dispatch. -""" -@inline function _check_domain(x::AbstractVector, xi::Real, ::Val{:none}) - x_min, x_max = first(x), last(x) - (xi < x_min || xi > x_max) && throw(DomainError(xi, "query point outside interpolation domain [$x_min, $x_max]")) - return nothing -end - -""" - _check_domain(x, xi, ::Val) - -No-op domain check for extrapolation modes other than `:none`. -""" -@inline _check_domain(::AbstractVector, ::Real, ::Val) = nothing - -""" - _check_domain(x, xi::AbstractVector, ::Val{:none}) - -Vector-level domain check using minimum/maximum (faster than extrema due to SIMD). -Called once before vector loop, then scalar `_check_domain` is skipped via `@inbounds`. - -Type-relaxed: accepts any Real element type to avoid unnecessary conversions. -""" -@inline function _check_domain(x::AbstractVector, xi::AbstractVector{<:Real}, ::Val{:none}) - x_min, x_max = first(x), last(x) - # NOTE: Using minimum/maximum for potential SIMD optimization over extrema - # extrema can be ~30x slower than minimum/maximum - xq_min, xq_max = minimum(xi), maximum(xi) - (xq_min < x_min || xq_max > x_max) && throw(DomainError( - xq_min < x_min ? xq_min : xq_max, - "query point outside interpolation domain [$x_min, $x_max]" - )) - return nothing -end - -""" - _check_domain(x, xi::AbstractVector, ::Val) - -No-op vector domain check for extrapolation modes other than `:none`. -""" -@inline _check_domain(::AbstractVector, ::AbstractVector{<:Real}, ::Val) = nothing - -# --- AbstractExtrap overloads (used by refactored 1D + ND code) --- - "Scalar domain check for NoExtrap: throws DomainError if out of domain." @inline function _check_domain(x::AbstractVector, xi::Real, ::NoExtrap) x_min, x_max = first(x), last(x) @@ -358,80 +304,12 @@ end # Centralized validation for keyword arguments. # @inline ensures zero overhead - compiler inlines the check. -""" - _validate_extrap(extrap::Symbol) -> Nothing - -Validate extrapolation mode symbol. Throws `ArgumentError` if invalid. - -Valid options: `:none`, `:constant`, `:extension`, `:wrap` -""" -@inline function _validate_extrap(extrap::Symbol) - extrap in (:none, :constant, :extension, :wrap) && return nothing - throw(ArgumentError("`extrap` must be :none, :constant, :extension, or :wrap, got :$extrap")) -end - # ======================================== # Dispatch Macros (Zero-Allocation Branching) # ======================================== # # These macros expand to manual if-elseif blocks that avoid union-splitting issues. -# Each branch calls with a concrete Val(:literal), ensuring zero-allocation dispatch. - -""" - @_dispatch_extrap sym => varname body - -Dispatch on runtime extrapolation symbol, executing body with concrete AbstractExtrap type. - -# Arguments -- `sym => varname`: Pair of symbol variable and binding name for AbstractExtrap -- `body`: Expression to execute with `varname` bound to concrete mode - -# Example -```julia -@_dispatch_extrap extrap => ev begin - _cubic_interp_impl!(output, cache, y, x_query, ev) -end -``` - -Expands to: -```julia -let _mode = extrap - if _mode === :none - ev = NoExtrap() - _cubic_interp_impl!(output, cache, y, x_query, ev) - elseif _mode === :constant - ... - end -end -``` -""" -macro _dispatch_extrap(pair, body) - # Parse pair: extrap => ev becomes Expr(:call, :(=>), :extrap, :ev) - pair.head === :call && pair.args[1] === :(=>) || - error("@_dispatch_extrap expects `sym => varname`, got: $pair") - sym = pair.args[2] - varname = pair.args[3] - evs = esc(varname) - quote - let _mode = $(esc(sym)) - if _mode === :none - $evs = NoExtrap() - $(esc(body)) - elseif _mode === :constant - $evs = ConstExtrap() - $(esc(body)) - elseif _mode === :extension - $evs = ExtendExtrap() - $(esc(body)) - elseif _mode === :wrap - $evs = WrapExtrap() - $(esc(body)) - else - throw(ArgumentError("`extrap` must be :none, :constant, :extension, or :wrap, got :$_mode")) - end - end - end -end +# Each branch calls with a concrete type, ensuring zero-allocation dispatch. """ @_dispatch_deriv deriv => op body @@ -603,203 +481,3 @@ macro _dispatch_side_nd(pair, body) end end -# ======================================== -# ND Extrap Dispatch Helpers -# ======================================== - -""" - _is_uniform_extrap_no_periodic(extraps, bcs) -> Bool - -Check if all extraps are the same symbol and no axes have periodic BCs. -Used by `@_dispatch_extrap_nd` for the zero-alloc fast path. -""" -@inline function _is_uniform_extrap_no_periodic( - extraps::NTuple{N, Symbol}, bcs::NTuple{N, AbstractBC} -) where {N} - for d in 1:N - _is_periodic_bc(bcs[d]) && return false - end - for d in 2:N - extraps[d] !== extraps[1] && return false - end - return true -end - -""" - _is_uniform_extrap(extraps) -> Bool - -Check if all extraps are the same symbol (ignoring BCs). -""" -@inline function _is_uniform_extrap(extraps::NTuple{N, Symbol}) where {N} - for d in 2:N - extraps[d] !== extraps[1] && return false - end - return true -end - -""" - _is_all_periodic(bcs) -> Bool - -Check if all axes have periodic BCs. -""" -@inline function _is_all_periodic(bcs::NTuple{N, AbstractBC}) where {N} - for d in 1:N - _is_periodic_bc(bcs[d]) || return false - end - return true -end - -# ── Nothing overloads for BC-free methods (linear, constant) ───────── -# Allows @_dispatch_extrap_nd to be reused with `nothing` as BCs. -# With nothing BCs, fast path 1 always fires for uniform extraps (>99% of cases). - -@inline _is_uniform_extrap_no_periodic(extraps::NTuple{N, Symbol}, ::Nothing) where {N} = - _is_uniform_extrap(extraps) - -@inline _is_all_periodic(::Nothing) = false - -@generated function _resolve_mixed_extrap_vals(extraps::NTuple{N, Symbol}, ::Nothing) where {N} - exprs = [:(FastInterpolations._symbol_to_extrap_mode(extraps[$d])) for d in 1:N] - :(($(exprs...),)) -end - -""" - _resolve_uniform_extrap_with_periodic(bcs, ::Val{S}) -> NTuple{N, AbstractExtrap} - -Zero-allocation per-axis extrap resolution for uniform extrap with mixed BCs. -Uses `@generated` to inspect BC types at compile time: -- Periodic axes → `WrapExtrap()` (hardcoded at compile time) -- Non-periodic axes → Mode type corresponding to `S` (known from static parameter) - -This avoids Union return types because both the BC type check and the extrap -symbol are resolved at compile time. -""" -@generated function _resolve_uniform_extrap_with_periodic( - bcs::B, ::Val{S} -) where {B<:Tuple{Vararg{AbstractBC}}, S} - N = fieldcount(B) - mode_expr = S === :none ? :(NoExtrap()) : - S === :constant ? :(ConstExtrap()) : - S === :extension ? :(ExtendExtrap()) : :(WrapExtrap()) - exprs = map(1:N) do d - if fieldtype(B, d) <: PeriodicBC - :(WrapExtrap()) - else - mode_expr - end - end - :(($(exprs...),)) -end - -""" - _resolve_mixed_extrap_vals(extraps, bcs) -> NTuple{N, AbstractExtrap} - -Per-axis extrap resolution for truly heterogeneous extraps (different Symbols per axis). -Falls back to runtime `_symbol_to_extrap_mode` which produces Union return types. -Only used when extraps are non-uniform (extremely rare in practice). -""" -@generated function _resolve_mixed_extrap_vals( - extraps::NTuple{N, Symbol}, bcs::NTuple{N, AbstractBC} -) where {N} - exprs = [:(FastInterpolations._is_periodic_bc(bcs[$d]) ? WrapExtrap() : FastInterpolations._symbol_to_extrap_mode(extraps[$d])) for d in 1:N] - :(($(exprs...),)) -end - -""" - @_dispatch_extrap_nd extraps bcs => ev body - -Dispatch extrap symbols to concrete `AbstractExtrap` tuples for type-stable ND evaluation. -Creates if/else branches, each with a concrete `ev` binding (similar to `@_dispatch_deriv`). - -This is the ND counterpart of `@_dispatch_extrap(sym => varname, body)` (1D). -The 1D version dispatches a single Symbol; this version dispatches `NTuple{N,Symbol}` + BCs. -`N` is derived automatically from `length(extraps)` (compile-time constant for NTuple). - -**Fast paths** (zero-alloc, covers >99% of use cases): -1. Uniform extrap + no periodic BCs → `ntuple(_ -> NoExtrap(), vn)` etc. -2. All periodic BCs → all axes `WrapExtrap()` -3. Uniform extrap + mixed BCs → `@generated` per-axis resolution using BC types - -**Fallback** (small alloc, extremely rare): -4. Non-uniform extraps + mixed BCs → runtime `_symbol_to_extrap_mode` (Union return) - -# Example -```julia -@_dispatch_extrap_nd extraps bcs => extraps_val begin - return _cubic_interp_nd_oneshot(grids, data, query, bcs, extraps_val, searches, ops) -end -``` -""" -macro _dispatch_extrap_nd(extraps_expr, pair, body) - # Parse pair: bcs => ev_sym - pair.head === :call && pair.args[1] === :(=>) || - error("@_dispatch_extrap_nd expects `bcs => binding`, got: $pair") - bcs_expr = pair.args[2] - ev_sym = pair.args[3] - - extraps_var = gensym(:extraps) - bcs_var = gensym(:bcs) - valn_var = gensym(:valn) - - quote - local $(extraps_var) = $(esc(extraps_expr)) - local $(bcs_var) = $(esc(bcs_expr)) - - if $(extraps_var) isa Tuple{Vararg{AbstractExtrap}} - # Fast path 0: pre-resolved Mode tuple (from typed AbstractExtrap path). - # _resolve_extrap_nd(::AbstractExtrap, bcs, Val(N)) returns Mode tuples directly, - # so we pass through without any Symbol dispatch. - let $(esc(ev_sym)) = $(extraps_var) - $(esc(body)) - end - else - # Symbol dispatch paths (legacy) - local $(valn_var) = Val(length($(extraps_var))) - - if _is_uniform_extrap_no_periodic($(extraps_var), $(bcs_var)) - # Fast path 1: uniform extrap, no periodic → concrete Mode tuple - if $(extraps_var)[1] === :none - let $(esc(ev_sym)) = ntuple(_ -> NoExtrap(), $(valn_var)) - $(esc(body)) - end - elseif $(extraps_var)[1] === :constant - let $(esc(ev_sym)) = ntuple(_ -> ConstExtrap(), $(valn_var)) - $(esc(body)) - end - elseif $(extraps_var)[1] === :extension - let $(esc(ev_sym)) = ntuple(_ -> ExtendExtrap(), $(valn_var)) - $(esc(body)) - end - else - let $(esc(ev_sym)) = ntuple(_ -> WrapExtrap(), $(valn_var)) - $(esc(body)) - end - end - elseif _is_all_periodic($(bcs_var)) - # Fast path 2: all periodic → all WrapExtrap() - let $(esc(ev_sym)) = ntuple(_ -> WrapExtrap(), $(valn_var)) - $(esc(body)) - end - elseif _is_uniform_extrap($(extraps_var)) - # Fast path 3: uniform extrap + mixed BCs (some periodic axes) → @generated per-axis - # BC types are known at compile time; extrap dispatched via Val(sym). - # Only :none and :wrap are valid here: _check_periodic_extrap ensures :constant/:extension - # cannot coexist with PeriodicBC (throws at construction), making those branches dead. - if $(extraps_var)[1] === :none - let $(esc(ev_sym)) = _resolve_uniform_extrap_with_periodic($(bcs_var), Val(:none)) - $(esc(body)) - end - else # :wrap (only other valid option with mixed periodic BCs) - let $(esc(ev_sym)) = _resolve_uniform_extrap_with_periodic($(bcs_var), Val(:wrap)) - $(esc(body)) - end - end - else - # Fallback: non-uniform extraps + mixed BCs (extremely rare) - let $(esc(ev_sym)) = _resolve_mixed_extrap_vals($(extraps_var), $(bcs_var)) - $(esc(body)) - end - end - end - end -end diff --git a/src/cubic/cubic_anchor.jl b/src/cubic/cubic_anchor.jl index b9d2887e..0396423a 100644 --- a/src/cubic/cubic_anchor.jl +++ b/src/cubic/cubic_anchor.jl @@ -165,7 +165,7 @@ Create an anchored query for ultra-fast cubic spline evaluation at a fixed point - `xq`: Query point (scalar, can be Float or ForwardDiff.Dual for AD) - `::Val{:cubic}`: Type tag to distinguish from other anchor types - `wrap`: If true, wrap `xq` to domain [x[1], x[end]) before anchoring. - Used for `extrap=:wrap` mode. Distinct from `PeriodicBC` (boundary condition). + Used for `extrap=WrapExtrap()` mode. Distinct from `PeriodicBC` (boundary condition). # Returns `_CubicAnchoredQuery{Tg, Tq}` with precomputed geometry weights for value and derivatives. @@ -216,7 +216,7 @@ the grid used for interpolant construction. - `xq`: Query points (any Real type, auto-promoted to T) - `::Val{:cubic}`: Type tag to distinguish from other anchor types - `wrap`: If true, wrap query points to domain [x[1], x[end]) before anchoring. - Used for `extrap=:wrap` mode. Distinct from `PeriodicBC` (boundary condition). + Used for `extrap=WrapExtrap()` mode. Distinct from `PeriodicBC` (boundary condition). # Example ```julia @@ -317,7 +317,7 @@ while preserving the full Dual value for weight computation. # Use primal value for comparisons (supports ForwardDiff.Dual) xq_primal = _extract_primal(xq) - # Handle wrapping (for extrap=:wrap mode) + # Handle wrapping (for extrap=WrapExtrap() mode) # Generic _wrap_to_domain handles AD primal extraction and returns Tg if wrap && (xq_primal < x_min || xq_primal >= x_max) xq = _wrap_to_domain(xq, x_min, x_max) diff --git a/src/cubic/cubic_eval.jl b/src/cubic/cubic_eval.jl index f14dc0d6..20a4fe97 100644 --- a/src/cubic/cubic_eval.jl +++ b/src/cubic/cubic_eval.jl @@ -271,7 +271,7 @@ Uses task-local pool for workspace allocation. cache::CubicSplineCache{Tg,X,F,BC,S}, y::AbstractVector{Tv}, x_query::Tg; - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), deriv::Int=0, search=Binary(), hint::Union{Nothing,Base.RefValue{Int}}=nothing @@ -281,11 +281,9 @@ Uses task-local pool for workspace allocation. z = similar!(pool, y) _solve_system!(z, cache, y, cache.bc_config) - extrap isa Symbol && Base.depwarn(_EXTRAP_SYMBOL_DEPWARN, :cubic_interp) - mode = extrap isa Symbol ? _symbol_to_extrap_mode(extrap) : extrap searcher = _to_searcher(search, hint) @_dispatch_deriv deriv => op begin - @boundscheck _check_domain(cache.x, x_query, mode) - _eval_with_bc(cache, y, z, x_query, mode, op, searcher) + @boundscheck _check_domain(cache.x, x_query, extrap) + _eval_with_bc(cache, y, z, x_query, extrap, op, searcher) end end diff --git a/src/cubic/cubic_interpolant.jl b/src/cubic/cubic_interpolant.jl index 9fcff97b..67e89131 100644 --- a/src/cubic/cubic_interpolant.jl +++ b/src/cubic/cubic_interpolant.jl @@ -206,7 +206,7 @@ Iterates through anchor vector, dispatching each to existing scalar kernels: - `_eval_anchored_kernel` for inside-domain (side == 0x00) - `_eval_anchored_extrap` for outside-domain (side != 0x00) -For extrap=:none, throws DomainError on first out-of-domain anchor. +For extrap=NoExtrap(), throws DomainError on first out-of-domain anchor. """ @inline function _eval_anchored_vector_loop!( output::AbstractVector{Tv}, @@ -220,7 +220,7 @@ For extrap=:none, throws DomainError on first out-of-domain anchor. # Fast path: inside domain output[k] = _eval_anchored_kernel(itp, aq_k, op) else - # Extrapolation path (may throw for :none) + # Extrapolation path (may throw for NoExtrap) output[k] = _eval_anchored_extrap(itp, aq_k, itp.extrap, op) end end @@ -233,10 +233,10 @@ end Evaluate cubic spline at multiple anchored query points (allocating). # Extrapolation Behavior -- `:none`: Throws `DomainError` on **first** out-of-domain anchor -- `:constant`: Returns boundary value (or zero for derivatives) -- `:extension`: Uses boundary polynomial extrapolation -- `:wrap`: Uses pre-wrapped coordinates from anchor construction +- `NoExtrap()`: Throws `DomainError` on **first** out-of-domain anchor +- `ConstExtrap()`: Returns boundary value (or zero for derivatives) +- `ExtendExtrap()`: Uses boundary polynomial extrapolation +- `WrapExtrap()`: Uses pre-wrapped coordinates from anchor construction # Example ```julia @@ -319,7 +319,7 @@ end _build_interpolant_periodic(x, y, autocache, search) -> CubicInterpolant Build a CubicInterpolant for PeriodicBC boundary conditions. -Periodic BC always uses :wrap extrapolation. +Periodic BC always uses WrapExtrap extrapolation. Tg = grid type, Tv = value type (can be Complex) # Thread-Safety @@ -374,7 +374,7 @@ enabling true zero-allocation scalar evaluations in broadcast operations. - `x::AbstractVector`: x-coordinates (must be sorted) - `y::AbstractVector`: y-values (can be Real or Complex) - `bc::AbstractBC`: Boundary condition (default: `NaturalBC()`) -- `extrap::AbstractExtrap`: `NoExtrap()` (default), `ConstExtrap()`, `ExtendExtrap()`, or `WrapExtrap()` (Symbol args deprecated) +- `extrap::AbstractExtrap`: `NoExtrap()` (default), `ConstExtrap()`, `ExtendExtrap()`, or `WrapExtrap()` - `autocache::Bool`: Enable automatic caching (default: `true`) - `search::AbstractSearchPolicy`: Default search policy (default: `Binary()`) @@ -403,17 +403,15 @@ val = itp(0.5) # returns ComplexF64 x::AbstractVector{Tg}, y::AbstractVector{Tv}, bc::AbstractBC, - extrap::Union{Symbol,AbstractExtrap}, + extrap::AbstractExtrap, autocache::Bool, search::P=Binary() ) where {Tg<:AbstractFloat, Tv, P<:AbstractSearchPolicy} if _is_periodic_bc(bc) return _build_interpolant_periodic(x, y, bc, autocache, search) else - extrap isa Symbol && Base.depwarn(_EXTRAP_SYMBOL_DEPWARN, :cubic_interp) - mode = extrap isa Symbol ? _symbol_to_extrap_mode(extrap) : extrap bc_pair = _normalize_bc(bc, Tv) - return _build_interpolant_bcpair(x, y, bc_pair, mode, autocache, search) + return _build_interpolant_bcpair(x, y, bc_pair, extrap, autocache, search) end end @@ -422,7 +420,7 @@ function cubic_interp( x::AbstractVector{Tg}, y::AbstractVector{Tv}; bc::AbstractBC=NaturalBC(), - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), autocache::Bool=true, search::P=Binary() ) where {Tg<:AbstractFloat, Tv, P<:AbstractSearchPolicy} @@ -454,7 +452,7 @@ so the pool memory can be safely reused after this function returns. @with_pool pool function cubic_interp( cache::CubicSplineCache{Tg}, y::AbstractVector{Tv}; - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), search::P=Binary() ) where {Tg<:AbstractFloat, Tv, P<:AbstractSearchPolicy} tmp_z = similar!(pool, y) @@ -466,9 +464,7 @@ so the pool memory can be safely reused after this function returns. end # cache.bc_config is BCPair - use it directly - extrap isa Symbol && Base.depwarn(_EXTRAP_SYMBOL_DEPWARN, :cubic_interp) - mode = extrap isa Symbol ? _symbol_to_extrap_mode(extrap) : extrap - return CubicInterpolant(cache, y, tmp_z, cache.bc_config, mode, search) + return CubicInterpolant(cache, y, tmp_z, cache.bc_config, extrap, search) end # Generic Real wrapper for 2-argument form (handles Integer grids, etc.) @@ -476,7 +472,7 @@ function cubic_interp( x::AbstractVector{TX}, y::AbstractVector{TY}; bc::AbstractBC=NaturalBC(), - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), autocache::Bool=true, search::P=Binary() ) where {TX<:Real, TY, P<:AbstractSearchPolicy} diff --git a/src/cubic/cubic_oneshot.jl b/src/cubic/cubic_oneshot.jl index 4a60f7bb..aee8cd0a 100644 --- a/src/cubic/cubic_oneshot.jl +++ b/src/cubic/cubic_oneshot.jl @@ -24,7 +24,7 @@ Thread-safe: workspaces allocated from task-local pool. - `cache::CubicSplineCache{T}`: Pre-computed cache with LU factorization - `y::AbstractVector{T}`: Function values at grid points - `x_query::AbstractVector{T}`: Query points -- `extrap::AbstractExtrap`: `NoExtrap()` (default), `ConstExtrap()`, `ExtendExtrap()`, or `WrapExtrap()` (Symbol args deprecated) +- `extrap::AbstractExtrap`: `NoExtrap()` (default), `ConstExtrap()`, `ExtendExtrap()`, or `WrapExtrap()` - `deriv::Int=0`: Derivative order (0=value, 1=first derivative, 2=second derivative) - `search::AbstractSearchPolicy=Binary()`: Search algorithm for interval finding """ @@ -33,7 +33,7 @@ Thread-safe: workspaces allocated from task-local pool. cache::CubicSplineCache{Tg,X,F,BC}, y::AbstractVector{Tv}, x_query::AbstractVector{Tg}; - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), deriv::Int=0, search::AbstractSearchPolicy=Binary() ) where {Tg<:AbstractFloat, Tv, X, F, BC} @@ -43,11 +43,9 @@ Thread-safe: workspaces allocated from task-local pool. z = similar!(pool, y) _solve_system!(z, cache, y, cache.bc_config) - extrap isa Symbol && Base.depwarn(_EXTRAP_SYMBOL_DEPWARN, :cubic_interp) - mode = extrap isa Symbol ? _symbol_to_extrap_mode(extrap) : extrap searcher = _to_searcher(search) @_dispatch_deriv deriv => op begin - _cubic_vector_loop!(output, cache, y, z, x_query, mode, op, searcher) + _cubic_vector_loop!(output, cache, y, z, x_query, extrap, op, searcher) end return output @@ -57,7 +55,7 @@ end # Core Fallback Functions (Type-Stable Dispatch) # ======================================== # -# These are the two core implementations that all Symbol-based APIs +# These are the two core implementations that all public APIs # dispatch to after normalizing BC to concrete types. # # Key insight: LU factorization depends only on BC **types** (Deriv1 vs Deriv2), @@ -230,14 +228,11 @@ In-place cubic spline interpolation with optional automatic caching. y::AbstractVector{Tv}, x_query::AbstractVector{Tg}; bc::AbstractBC=NaturalBC(), - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), autocache::Bool=true, deriv::Int=0, search::AbstractSearchPolicy=Binary() ) where {Tg<:AbstractFloat, Tv} - extrap isa Symbol && Base.depwarn(_EXTRAP_SYMBOL_DEPWARN, :cubic_interp!) - mode = extrap isa Symbol ? _symbol_to_extrap_mode(extrap) : extrap - searcher = _to_searcher(search) @_dispatch_deriv deriv => op begin # Periodic BC @@ -247,7 +242,7 @@ In-place cubic spline interpolation with optional automatic caching. # Normalize to BCPair and dispatch to core bc_pair = _normalize_bc(bc, Tv) - return _cubic_interp_bcpair!(output, x, y, x_query, bc_pair, mode, autocache, op, searcher) + return _cubic_interp_bcpair!(output, x, y, x_query, bc_pair, extrap, autocache, op, searcher) end end @@ -258,7 +253,7 @@ end cache::CubicSplineCache{Tg,X,F,BC}, y::AbstractVector{Tv}, x_query::Tg; - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), deriv::Int=0, search::AbstractSearchPolicy=Binary() ) where {Tg<:AbstractFloat, Tv, X, F, BC} @@ -273,7 +268,7 @@ end y::AbstractVector{Tv}, x_query::Tg; bc::AbstractBC=NaturalBC(), - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), autocache::Bool=true, deriv::Int=0, search::AbstractSearchPolicy=Binary() @@ -312,7 +307,7 @@ function cubic_interp( cache::CubicSplineCache{Tg}, y::AbstractVector{Tv}, x_query::AbstractVector{Tg}; - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), deriv::Int=0, search::AbstractSearchPolicy=Binary() ) where {Tg<:AbstractFloat, Tv} @@ -330,7 +325,7 @@ Cubic spline interpolation with optional automatic caching. - `deriv::Int=0`: Derivative order (0=value, 1=first derivative, 2=second derivative) - `search::AbstractSearchPolicy=Binary()`: Search algorithm for interval finding -# Extrapolation Modes (Symbol args deprecated) +# Extrapolation Modes - `NoExtrap()` (default): Throws DomainError if query point is outside domain - `ConstExtrap()`: Returns boundary values outside domain (0 for derivatives) - `ExtendExtrap()`: Extends boundary polynomial outside domain @@ -353,7 +348,7 @@ function cubic_interp( y::AbstractVector{Tv}, x_query::AbstractVector{Tg}; bc::AbstractBC=NaturalBC(), - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), autocache::Bool=true, deriv::Int=0, search::AbstractSearchPolicy=Binary() @@ -365,7 +360,7 @@ end # Scalar query - zero allocation cubic_interp(cache::CubicSplineCache{Tg}, y::AbstractVector{Tv}, - x_query::Tg; extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), deriv::Int=0, search=Binary(), hint::Union{Nothing,Base.RefValue{Int}}=nothing) where {Tg<:AbstractFloat, Tv} = + x_query::Tg; extrap::AbstractExtrap=NoExtrap(), deriv::Int=0, search=Binary(), hint::Union{Nothing,Base.RefValue{Int}}=nothing) where {Tg<:AbstractFloat, Tv} = cubic_interp_scalar(cache, y, x_query; extrap=extrap, deriv=deriv, search=search, hint=hint) # Primary scalar method - AD-compatible @@ -375,15 +370,12 @@ function cubic_interp( y::AbstractVector{Tv}, xq::Tq; # Accepts Tg, Real, or Dual for AD (Dual <: Real) bc::AbstractBC=NaturalBC(), - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), autocache::Bool=true, deriv::Int=0, search=Binary(), hint::Union{Nothing,Base.RefValue{Int}}=nothing ) where {Tg<:AbstractFloat, Tv, Tq<:Real} - extrap isa Symbol && Base.depwarn(_EXTRAP_SYMBOL_DEPWARN, :cubic_interp) - mode = extrap isa Symbol ? _symbol_to_extrap_mode(extrap) : extrap - searcher = _to_searcher(search, hint) @_dispatch_deriv deriv => op begin if _is_periodic_bc(bc) @@ -391,7 +383,7 @@ function cubic_interp( end bc_pair = _normalize_bc(bc, Tv) - return _cubic_interp_bcpair_scalar(x, y, xq, bc_pair, mode, autocache, op, searcher) + return _cubic_interp_bcpair_scalar(x, y, xq, bc_pair, extrap, autocache, op, searcher) end end @@ -409,7 +401,7 @@ function cubic_interp( y::AbstractVector{Tv}, x_query::AbstractVector{Tq}; bc::AbstractBC=NaturalBC(), - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), autocache::Bool=true, deriv::Int=0, search::AbstractSearchPolicy=Binary() @@ -425,7 +417,7 @@ function cubic_interp( y::AbstractVector{Tv}, xq::Tq; # Accepts Tg, Real, or Dual for AD (Dual <: Real) bc::AbstractBC=NaturalBC(), - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), autocache::Bool=true, deriv::Int=0, search=Binary(), @@ -443,7 +435,7 @@ function cubic_interp!( y::AbstractVector{Tv}, x_query::AbstractVector{Tq}; bc::AbstractBC=NaturalBC(), - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), autocache::Bool=true, deriv::Int=0, search::AbstractSearchPolicy=Binary() @@ -474,7 +466,7 @@ function cubic_interp!( y::AbstractVector{Tv}, x_query::Tq; bc::AbstractBC=NaturalBC(), - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), autocache::Bool=true, deriv::Int=0, search::AbstractSearchPolicy=Binary() diff --git a/src/cubic/cubic_series_interp.jl b/src/cubic/cubic_series_interp.jl index 1ddc9b62..ad793693 100644 --- a/src/cubic/cubic_series_interp.jl +++ b/src/cubic/cubic_series_interp.jl @@ -541,7 +541,7 @@ Create a multi-Y cubic spline interpolant for multiple y-data series sharing the - `x::AbstractVector`: x-coordinates (sorted, length ≥ 2) - `ys`: Vector of y-value vectors (all same length as x) - `bc`: Boundary condition (NaturalBC, ClampedBC, PeriodicBC, or Vector of BC for per-series) -- `extrap::AbstractExtrap`: `NoExtrap()`, `ConstExtrap()`, `ExtendExtrap()`, or `WrapExtrap()` (Symbol args deprecated) +- `extrap::AbstractExtrap`: `NoExtrap()`, `ConstExtrap()`, `ExtendExtrap()`, or `WrapExtrap()` - `autocache`: If true, reuse cached LU factorization (default: true) - `precompute_transpose`: If true, build point-contiguous layout immediately @@ -571,7 +571,7 @@ function cubic_interp( x::AbstractVector{Tg}, ys::AbstractVector{<:AbstractVector{Tv}}; bc::Union{AbstractBC, AbstractVector{<:AbstractBC}}=NaturalBC(), - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), autocache::Bool=true, precompute_transpose::Bool=false, search::P=Binary() @@ -622,11 +622,7 @@ function cubic_interp( bc_representative = bc_pair end - # Convert extrap symbol to mode - extrap isa Symbol && Base.depwarn(_EXTRAP_SYMBOL_DEPWARN, :cubic_interp) - mode = extrap isa Symbol ? _symbol_to_extrap_mode(extrap) : extrap - - sitp = CubicSeriesInterpolant(cache, bc_representative, y_mat, z_mat, mode, search) + sitp = CubicSeriesInterpolant(cache, bc_representative, y_mat, z_mat, extrap, search) if precompute_transpose _ensure_point_layout!(sitp) @@ -707,7 +703,7 @@ function cubic_interp( x::AbstractVector{Tg}, Y::AbstractMatrix{Tv}; bc::Union{AbstractBC, AbstractVector{<:AbstractBC}}=NaturalBC(), - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), autocache::Bool=true, precompute_transpose::Bool=false, search::AbstractSearchPolicy=Binary() @@ -751,11 +747,7 @@ function cubic_interp( bc_representative = bc_pair end - # Convert extrap symbol to mode - extrap isa Symbol && Base.depwarn(_EXTRAP_SYMBOL_DEPWARN, :cubic_interp) - mode = extrap isa Symbol ? _symbol_to_extrap_mode(extrap) : extrap - - sitp = CubicSeriesInterpolant(cache, bc_representative, y_mat, z_mat, mode, search) + sitp = CubicSeriesInterpolant(cache, bc_representative, y_mat, z_mat, extrap, search) if precompute_transpose _ensure_point_layout!(sitp) @@ -769,7 +761,7 @@ function cubic_interp( x::AbstractVector{Tg}, ys::AbstractVector{<:AbstractVector{Tv}}; bc::Union{AbstractBC, AbstractVector{<:AbstractBC}}=NaturalBC(), - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), autocache::Bool=true, precompute_transpose::Bool=false, search::AbstractSearchPolicy=Binary() @@ -787,7 +779,7 @@ function cubic_interp( x::AbstractVector{Tg}, Y::AbstractMatrix{Tv}; bc::Union{AbstractBC, AbstractVector{<:AbstractBC}}=NaturalBC(), - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), autocache::Bool=true, precompute_transpose::Bool=false, search::AbstractSearchPolicy=Binary() diff --git a/src/cubic/nd/cubic_nd_interpolant.jl b/src/cubic/nd/cubic_nd_interpolant.jl index 2b89a789..956e29d7 100644 --- a/src/cubic/nd/cubic_nd_interpolant.jl +++ b/src/cubic/nd/cubic_nd_interpolant.jl @@ -22,9 +22,9 @@ Create an N-dimensional cubic Hermite interpolant from grid vectors and data arr - `bc=NaturalBC()`: Boundary condition(s). Can be: - Single `AbstractBC`: Applied to all axes - `NTuple{N,AbstractBC}`: Per-axis BCs -- `extrap=:none`: Extrapolation mode(s). Can be: - - Single `Symbol`: Applied to all axes (`:none`, `:constant`, `:wrap`) - - `NTuple{N,Symbol}`: Per-axis modes +- `extrap=NoExtrap()`: Extrapolation mode(s). Can be: + - Single `AbstractExtrap`: Applied to all axes (`NoExtrap()`, `ConstExtrap()`, `WrapExtrap()`) + - `NTuple{N,AbstractExtrap}`: Per-axis modes - `search=Binary()`: Search policy(s). Can be: - Single `AbstractSearchPolicy`: Applied to all axes - `NTuple{N,AbstractSearchPolicy}`: Per-axis policies @@ -50,7 +50,7 @@ itp((1.0, 0.5, 0.3)) # Evaluate at (1.0, 0.5, 0.3) # With per-axis options itp = cubic_interp((x, y, z), data; bc=(NaturalBC(), PeriodicBC(), NaturalBC()), - extrap=(:none, :wrap, :constant)) + extrap=(NoExtrap(), WrapExtrap(), ConstExtrap())) # Complex-valued data data_c = [sin(xi) * cos(yj) * zk + im * cos(xi) for xi in x, yj in y, zk in z] @@ -61,7 +61,7 @@ function cubic_interp( grids::NTuple{N, AbstractVector}, data::AbstractArray{Tv_raw, N}; bc::Union{AbstractBC, NTuple{N,AbstractBC}}=NaturalBC(), - extrap::Union{Symbol, NTuple{N,Symbol}, AbstractExtrap, NTuple{N,AbstractExtrap}}=NoExtrap(), + extrap::Union{AbstractExtrap, NTuple{N,AbstractExtrap}}=NoExtrap(), search::Union{AbstractSearchPolicy, NTuple{N,AbstractSearchPolicy}}=Binary(), coeffs::AbstractCoeffStrategy=PreCompute() ) where {N, Tv_raw} @@ -82,17 +82,8 @@ function cubic_interp( bcs = _resolve_bcs_nd(bc, Val(N)) searches = _resolve_search_nd(search, Val(N)) - if extrap isa AbstractExtrap || extrap isa Tuple{Vararg{AbstractExtrap}} - extraps_val = _resolve_extrap_nd(extrap, bcs, Val(N)) - return _build_nd_interpolant(grids_typed, data, bcs, extraps_val, searches, coeffs) - else - Base.depwarn(_EXTRAP_SYMBOL_DEPWARN, :cubic_interp) - extraps = _resolve_extrap_nd(extrap, Val(N)) - _check_periodic_extrap(bcs, extraps, Val(N)) - @_dispatch_extrap_nd extraps bcs => extraps_val begin - return _build_nd_interpolant(grids_typed, data, bcs, extraps_val, searches, coeffs) - end - end + extraps_val = _resolve_extrap_nd(extrap, bcs, Val(N)) + return _build_nd_interpolant(grids_typed, data, bcs, extraps_val, searches, coeffs) end # ======================================== @@ -134,8 +125,8 @@ function _build_nd_interpolant( end end - # extraps_val already dispatched to concrete Val types at API boundary - # (via @_dispatch_extrap_nd in cubic_interp) + # extraps_val already resolved to concrete AbstractExtrap instances at API boundary + # (via _resolve_extrap_nd in cubic_interp) # Construct the interpolant NP1 = N + 1 @@ -146,32 +137,6 @@ function _build_nd_interpolant( }(grids, spacings, nodal_derivs, bcs_store, extraps_val, searches) end -# ======================================== -# ND Internal Helpers (Val-recursive) -# ======================================== - -@inline _check_periodic_extrap( - bcs::NTuple{N, AbstractBC}, - extraps::NTuple{N, Symbol}, - ::Val{N} -) where {N} = _check_periodic_extrap(bcs, extraps, Val(1), Val(N)) - -@inline function _check_periodic_extrap( - bcs::NTuple{N, AbstractBC}, - extraps::NTuple{N, Symbol}, - ::Val{D}, - ::Val{N} -) where {D, N} - is_periodic = _is_periodic_bc(bcs[D]) - if is_periodic && extraps[D] != :none && extraps[D] != :wrap - throw(ArgumentError("Periodic BC on dim $D only supports extrap=:none or :wrap, got :$(extraps[D])")) - end - if D < N - _check_periodic_extrap(bcs, extraps, Val(D + 1), Val(N)) - end - return nothing -end - """ _build_nd_interpolant(..., ::OnTheFly) diff --git a/src/cubic/nd/cubic_nd_oneshot.jl b/src/cubic/nd/cubic_nd_oneshot.jl index 86c028a0..557dc786 100644 --- a/src/cubic/nd/cubic_nd_oneshot.jl +++ b/src/cubic/nd/cubic_nd_oneshot.jl @@ -31,7 +31,7 @@ function cubic_interp( query::Tuple{Vararg{Real, N}}; deriv::Union{Int, Val, NTuple{N,Int}}=0, bc::Union{AbstractBC, NTuple{N,AbstractBC}}=NaturalBC(), - extrap::Union{Symbol, NTuple{N,Symbol}, AbstractExtrap, NTuple{N,AbstractExtrap}}=NoExtrap(), + extrap::Union{AbstractExtrap, NTuple{N,AbstractExtrap}}=NoExtrap(), search::Union{AbstractSearchPolicy, NTuple{N,AbstractSearchPolicy}}=Binary(), coeffs::AbstractCoeffStrategy=PreCompute() ) where {Tv, N} @@ -48,22 +48,9 @@ function cubic_interp( # Validate BC requirements (once, before dispatch). _validate_nd_bcs!(grids_typed, bcs, data, Val(N)) - if extrap isa AbstractExtrap || extrap isa Tuple{Vararg{AbstractExtrap}} - # ── Fast path: typed Extrap → direct Val tuple (zero-alloc) ── - extraps_val = _resolve_extrap_nd(extrap, bcs, Val(N)) - return _dispatch_deriv_nd(deriv, Val(N)) do ops - _cubic_interp_nd_oneshot(grids_typed, data, query, bcs, extraps_val, searches, ops)::Tr - end - else - # ── Legacy path: Symbol → macro dispatch (backward compat, may allocate) ── - Base.depwarn(_EXTRAP_SYMBOL_DEPWARN, :cubic_interp) - extraps = _resolve_extrap_nd(extrap, Val(N)) - _check_periodic_extrap(bcs, extraps, Val(N)) - @_dispatch_extrap_nd extraps bcs => extraps_val begin - return _dispatch_deriv_nd(deriv, Val(N)) do ops - _cubic_interp_nd_oneshot(grids_typed, data, query, bcs, extraps_val, searches, ops)::Tr - end - end + extraps_val = _resolve_extrap_nd(extrap, bcs, Val(N)) + return _dispatch_deriv_nd(deriv, Val(N)) do ops + _cubic_interp_nd_oneshot(grids_typed, data, query, bcs, extraps_val, searches, ops)::Tr end end @@ -79,7 +66,7 @@ function cubic_interp( queries::Tuple{Vararg{AbstractVector{<:Real}, N}}; deriv::Union{Int, Val, NTuple{N,Int}}=0, bc::Union{AbstractBC, NTuple{N,AbstractBC}}=NaturalBC(), - extrap::Union{Symbol, NTuple{N,Symbol}, AbstractExtrap, NTuple{N,AbstractExtrap}}=NoExtrap(), + extrap::Union{AbstractExtrap, NTuple{N,AbstractExtrap}}=NoExtrap(), search::Union{AbstractSearchPolicy, NTuple{N,AbstractSearchPolicy}}=Binary(), coeffs::AbstractCoeffStrategy=PreCompute() ) where {Tv, N} @@ -103,7 +90,7 @@ function cubic_interp( queries::AbstractVector{<:Tuple{Vararg{Real, N}}}; deriv::Union{Int, Val, NTuple{N,Int}}=0, bc::Union{AbstractBC, NTuple{N,AbstractBC}}=NaturalBC(), - extrap::Union{Symbol, NTuple{N,Symbol}, AbstractExtrap, NTuple{N,AbstractExtrap}}=NoExtrap(), + extrap::Union{AbstractExtrap, NTuple{N,AbstractExtrap}}=NoExtrap(), search::Union{AbstractSearchPolicy, NTuple{N,AbstractSearchPolicy}}=Binary(), coeffs::AbstractCoeffStrategy=PreCompute() ) where {Tv, N} @@ -133,8 +120,8 @@ Pool-based scalar one-shot ND cubic Hermite evaluation. Computes 2^N partial derivatives in a pool buffer and evaluates at a single point. Zero-allocation after warmup (pool reuse). -`extraps_val` must be a pre-resolved tuple of `Val` types (e.g., `(Val(:none), Val(:none))`), -computed via `@_dispatch_extrap_nd` in the API layer for type stability. +`extraps_val` must be a pre-resolved tuple of concrete `AbstractExtrap` instances +(e.g., `(NoExtrap(), ConstExtrap())`), computed via `_resolve_extrap_nd` in the API layer. """ @with_pool pool function _cubic_interp_nd_oneshot( grids::NTuple{N, AbstractVector{Tg}}, @@ -174,7 +161,7 @@ end Pool-based in-place SoA batch one-shot ND cubic Hermite evaluation. Computes partials ONCE, then evaluates at all query points into `output`. -`extraps_val` must be a pre-resolved tuple of `Val` types. +`extraps_val` must be a pre-resolved tuple of concrete `AbstractExtrap` instances. """ @with_pool pool function _cubic_interp_nd_oneshot_soa!( output::AbstractVector, @@ -220,7 +207,7 @@ end Pool-based in-place AoS batch one-shot ND cubic Hermite evaluation. Computes partials ONCE, then evaluates at all query points into `output`. -`extraps_val` must be a pre-resolved tuple of `Val` types. +`extraps_val` must be a pre-resolved tuple of concrete `AbstractExtrap` instances. """ @with_pool pool function _cubic_interp_nd_oneshot_aos!( output::AbstractVector, @@ -271,7 +258,7 @@ function cubic_interp!( queries::Tuple{Vararg{AbstractVector{<:Real}, N}}; deriv::Union{Int, Val, NTuple{N,Int}}=0, bc::Union{AbstractBC, NTuple{N,AbstractBC}}=NaturalBC(), - extrap::Union{Symbol, NTuple{N,Symbol}, AbstractExtrap, NTuple{N,AbstractExtrap}}=NoExtrap(), + extrap::Union{AbstractExtrap, NTuple{N,AbstractExtrap}}=NoExtrap(), search::Union{AbstractSearchPolicy, NTuple{N,AbstractSearchPolicy}}=Binary(), coeffs::AbstractCoeffStrategy=PreCompute() ) where {Tv, N} @@ -285,20 +272,9 @@ function cubic_interp!( _validate_nd_bcs!(grids_typed, bcs, data, Val(N)) - if extrap isa AbstractExtrap || extrap isa Tuple{Vararg{AbstractExtrap}} - extraps_val = _resolve_extrap_nd(extrap, bcs, Val(N)) - return _dispatch_deriv_nd(deriv, Val(N)) do ops - _cubic_interp_nd_oneshot_soa!(output, grids_typed, data, queries, bcs, extraps_val, searches, ops) - end - else - Base.depwarn(_EXTRAP_SYMBOL_DEPWARN, :cubic_interp!) - extraps = _resolve_extrap_nd(extrap, Val(N)) - _check_periodic_extrap(bcs, extraps, Val(N)) - @_dispatch_extrap_nd extraps bcs => extraps_val begin - return _dispatch_deriv_nd(deriv, Val(N)) do ops - _cubic_interp_nd_oneshot_soa!(output, grids_typed, data, queries, bcs, extraps_val, searches, ops) - end - end + extraps_val = _resolve_extrap_nd(extrap, bcs, Val(N)) + return _dispatch_deriv_nd(deriv, Val(N)) do ops + _cubic_interp_nd_oneshot_soa!(output, grids_typed, data, queries, bcs, extraps_val, searches, ops) end end @@ -315,7 +291,7 @@ function cubic_interp!( queries::AbstractVector{<:Tuple{Vararg{Real, N}}}; deriv::Union{Int, Val, NTuple{N,Int}}=0, bc::Union{AbstractBC, NTuple{N,AbstractBC}}=NaturalBC(), - extrap::Union{Symbol, NTuple{N,Symbol}, AbstractExtrap, NTuple{N,AbstractExtrap}}=NoExtrap(), + extrap::Union{AbstractExtrap, NTuple{N,AbstractExtrap}}=NoExtrap(), search::Union{AbstractSearchPolicy, NTuple{N,AbstractSearchPolicy}}=Binary(), coeffs::AbstractCoeffStrategy=PreCompute() ) where {Tv, N} @@ -329,19 +305,8 @@ function cubic_interp!( _validate_nd_bcs!(grids_typed, bcs, data, Val(N)) - if extrap isa AbstractExtrap || extrap isa Tuple{Vararg{AbstractExtrap}} - extraps_val = _resolve_extrap_nd(extrap, bcs, Val(N)) - return _dispatch_deriv_nd(deriv, Val(N)) do ops - _cubic_interp_nd_oneshot_aos!(output, grids_typed, data, queries, bcs, extraps_val, searches, ops) - end - else - Base.depwarn(_EXTRAP_SYMBOL_DEPWARN, :cubic_interp!) - extraps = _resolve_extrap_nd(extrap, Val(N)) - _check_periodic_extrap(bcs, extraps, Val(N)) - @_dispatch_extrap_nd extraps bcs => extraps_val begin - return _dispatch_deriv_nd(deriv, Val(N)) do ops - _cubic_interp_nd_oneshot_aos!(output, grids_typed, data, queries, bcs, extraps_val, searches, ops) - end - end + extraps_val = _resolve_extrap_nd(extrap, bcs, Val(N)) + return _dispatch_deriv_nd(deriv, Val(N)) do ops + _cubic_interp_nd_oneshot_aos!(output, grids_typed, data, queries, bcs, extraps_val, searches, ops) end end diff --git a/src/linear/linear_anchor.jl b/src/linear/linear_anchor.jl index 45e902a2..e6f79371 100644 --- a/src/linear/linear_anchor.jl +++ b/src/linear/linear_anchor.jl @@ -110,7 +110,7 @@ Create an anchored query for ultra-fast linear interpolation at a fixed point. - `xq`: Query point (scalar) - `::Val{:linear}`: Type tag to distinguish from cubic anchor - `wrap`: If true, wrap `xq` to domain [x[1], x[end]) before anchoring. - Used for `extrap=:wrap` mode. + Used for `extrap=WrapExtrap()` mode. # Returns `_LinearAnchoredQuery{T}` with precomputed geometry. @@ -246,7 +246,7 @@ in `xq` and `alpha` fields. The interval search uses `_extract_primal(xq)` for c # Use primal value for comparisons (supports ForwardDiff.Dual) xq_primal = _extract_primal(xq) - # Handle wrapping (for extrap=:wrap mode) + # Handle wrapping (for extrap=WrapExtrap() mode) if wrap && (xq_primal < x_min || xq_primal >= x_max) xq = _wrap_to_domain(xq, x_min, x_max) xq_primal = xq # xq is now Tg, no need for _extract_primal diff --git a/src/linear/linear_interpolant.jl b/src/linear/linear_interpolant.jl index 529906d1..919a5232 100644 --- a/src/linear/linear_interpolant.jl +++ b/src/linear/linear_interpolant.jl @@ -74,7 +74,7 @@ Create a callable interpolant for broadcast fusion and reuse. # Arguments - `x::AbstractVector`: x-coordinates (must be sorted) - `y::AbstractVector`: y-values (can be real or complex) -- `extrap::AbstractExtrap`: `NoExtrap()` (default), `ConstExtrap()`, `ExtendExtrap()`, or `WrapExtrap()` (Symbol args deprecated) +- `extrap::AbstractExtrap`: `NoExtrap()` (default), `ConstExtrap()`, `ExtendExtrap()`, or `WrapExtrap()` - `search::AbstractSearchPolicy`: Default search policy for interval lookup (default: `Binary()`) # Type Handling @@ -148,7 +148,7 @@ function linear_interp end @inline function linear_interp( x::AbstractVector{TX}, y::AbstractVector{TY}; - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), search::AbstractSearchPolicy=Binary() ) where {TX<:Real, TY} x_p, y_p = _promote_itp_inputs(x, y) diff --git a/src/linear/linear_oneshot.jl b/src/linear/linear_oneshot.jl index 29670587..46a6f396 100644 --- a/src/linear/linear_oneshot.jl +++ b/src/linear/linear_oneshot.jl @@ -24,7 +24,7 @@ Zero-allocation linear interpolation with automatic dispatch: # Arguments - `output`: Pre-allocated output vector (must be floating-point type) -- `extrap::AbstractExtrap`: `NoExtrap()` (default, throws DomainError), `ConstExtrap()`, `ExtendExtrap()`, or `WrapExtrap()` (Symbol args deprecated) +- `extrap::AbstractExtrap`: `NoExtrap()` (default, throws DomainError), `ConstExtrap()`, `ExtendExtrap()`, or `WrapExtrap()` - `deriv::Int`: Derivative order (0=value, 1=first derivative, 2=second derivative) - `search::AbstractSearchPolicy`: Search algorithm for interval finding - `Binary()` (default): O(log n) binary search, stateless @@ -60,7 +60,7 @@ function linear_interp!( x::AbstractVector{Tg}, y::AbstractVector{Tv}, x_targets::AbstractVector{Tg}; - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), deriv::Int=0, search::AbstractSearchPolicy=Binary() ) where {Tg<:AbstractFloat, Tv} @@ -68,11 +68,9 @@ function linear_interp!( @assert length(output) == length(x_targets) "output must match x_targets length" searcher = _to_searcher(search) - extrap isa Symbol && Base.depwarn(_EXTRAP_SYMBOL_DEPWARN, :linear_interp!) - mode = extrap isa Symbol ? _symbol_to_extrap_mode(extrap) : extrap @_dispatch_deriv deriv => op begin - @boundscheck _check_domain(x, x_targets, mode) - _linear_interp_loop!(output, x, y, x_targets, mode, op, searcher) + @boundscheck _check_domain(x, x_targets, extrap) + _linear_interp_loop!(output, x, y, x_targets, extrap, op, searcher) end end @@ -94,7 +92,7 @@ end end -# Optimized loop for :wrap - uses 2-stage strategy +# Optimized loop for WrapExtrap - uses 2-stage strategy # Stage 1: Check if ALL queries are inside domain (cheap: ~150ns for 1000 elements) # Stage 2: If all inside, use extension path (no wrap needed); otherwise per-element wrap @inline function _linear_interp_loop!( @@ -157,7 +155,7 @@ end x::AbstractRange{Tg}, y::AbstractVector{Tv}, x_targets::AbstractVector{Tg}; - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), deriv::Int=0, search::AbstractSearchPolicy=Binary() ) where {Tg<:AbstractFloat, Tv} @@ -165,11 +163,9 @@ end @assert length(output) == length(x_targets) "output must match x_targets length" searcher = _to_searcher(search) - extrap isa Symbol && Base.depwarn(_EXTRAP_SYMBOL_DEPWARN, :linear_interp!) - mode = extrap isa Symbol ? _symbol_to_extrap_mode(extrap) : extrap @_dispatch_deriv deriv => op begin - @boundscheck _check_domain(x, x_targets, mode) - _linear_interp_loop!(output, x, y, x_targets, mode, op, searcher) + @boundscheck _check_domain(x, x_targets, extrap) + _linear_interp_loop!(output, x, y, x_targets, extrap, op, searcher) end end @@ -186,7 +182,7 @@ Zero-allocation scalar linear interpolation with automatic dispatch: # Arguments - `xq::Real`: Single interpolation query point -- `extrap::AbstractExtrap`: `NoExtrap()` (default, throws DomainError), `ConstExtrap()`, `ExtendExtrap()`, or `WrapExtrap()` (Symbol args deprecated) +- `extrap::AbstractExtrap`: `NoExtrap()` (default, throws DomainError), `ConstExtrap()`, `ExtendExtrap()`, or `WrapExtrap()` - `deriv::Int`: Derivative order (0=value, 1=first derivative) - `search::AbstractSearchPolicy`: Search algorithm for interval finding - `Binary()` (default): O(log n) binary search, stateless @@ -383,7 +379,7 @@ end _linear_with_extrap(x, y, xq, extrap, op, searcher) end -# Public API - Symbol dispatch (converts to Val) +# Public API - AbstractExtrap dispatch # Unified for real and complex y via Tv parameter # AD Support: Tq can be Tg or Dual{Tg} (both are <:Real) # Note: Tq<:Real constraint resolves method ambiguity with the generic Real wrapper @@ -391,7 +387,7 @@ end x::AbstractVector{Tg}, y::AbstractVector{Tv}, xq::Tq; - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), deriv::Int=0, search=Binary(), hint::Union{Nothing,Base.RefValue{Int}}=nothing @@ -399,10 +395,8 @@ end @boundscheck length(y) == length(x) || throw(ArgumentError("x and y must have same length")) searcher = _to_searcher(search, hint) - extrap isa Symbol && Base.depwarn(_EXTRAP_SYMBOL_DEPWARN, :linear_interp) - mode = extrap isa Symbol ? _symbol_to_extrap_mode(extrap) : extrap @_dispatch_deriv deriv => op begin - linear_interp(x, y, xq, mode, op, searcher) + linear_interp(x, y, xq, extrap, op, searcher) end end @@ -422,7 +416,7 @@ function linear_interp( x::AbstractVector{Tg}, y::AbstractVector{Tv}, x_targets::AbstractVector{Tg}; - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), deriv::Int=0, search::AbstractSearchPolicy=Binary() ) where {Tg<:AbstractFloat, Tv} @@ -443,7 +437,7 @@ function linear_interp!( x::AbstractVector{Tg}, y::AbstractVector{Tv}, x_targets::AbstractVector{Tq}; - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), deriv::Int=0, search::AbstractSearchPolicy=Binary() ) where {Tg<:Real, Tv, Tq<:Real} @@ -475,7 +469,7 @@ end x::AbstractVector{Tg}, y::AbstractVector{Tv}, xq::Tq; - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), deriv::Int=0, search=Binary(), hint::Union{Nothing,Base.RefValue{Int}}=nothing @@ -493,7 +487,7 @@ function linear_interp( x::AbstractVector{Tg}, y::AbstractVector{Tv}, x_targets::AbstractVector{Tq}; - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), deriv::Int=0, search::AbstractSearchPolicy=Binary() ) where {Tg<:Real, Tv, Tq<:Real} diff --git a/src/linear/linear_series_interp.jl b/src/linear/linear_series_interp.jl index c451a8be..53b7079a 100644 --- a/src/linear/linear_series_interp.jl +++ b/src/linear/linear_series_interp.jl @@ -296,7 +296,7 @@ Create a multi-Y linear interpolant for multiple y-data series sharing the same # Arguments - `x::AbstractVector`: x-coordinates (sorted, length ≥ 2) - `ys`: Vector of y-value vectors (all same length as x) -- `extrap::AbstractExtrap`: `NoExtrap()`, `ConstExtrap()`, `ExtendExtrap()`, or `WrapExtrap()` (Symbol args deprecated) +- `extrap::AbstractExtrap`: `NoExtrap()`, `ConstExtrap()`, `ExtendExtrap()`, or `WrapExtrap()` # Returns `LinearSeriesInterpolant` object with matrix storage. @@ -320,7 +320,7 @@ sitp_complex = linear_interp(x, y_complex) function linear_interp( x::AbstractVector{Tg}, ys::AbstractVector{<:AbstractVector{Tv}}; - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), search::P=Binary() ) where {Tg<:AbstractFloat, Tv, P<:AbstractSearchPolicy} # Check if Tv's float base requires grid widening (not for Int types) @@ -355,9 +355,7 @@ function linear_interp( y_mat[:, k] .= Tv_out.(ys[k]) end - extrap isa Symbol && Base.depwarn(_EXTRAP_SYMBOL_DEPWARN, :linear_interp) - mode = extrap isa Symbol ? _symbol_to_extrap_mode(extrap) : extrap - return LinearSeriesInterpolant(x, y_mat, mode, search) + return LinearSeriesInterpolant(x, y_mat, extrap, search) end # Matrix input: columns as y-series @@ -386,7 +384,7 @@ sitp_complex = linear_interp(x, Y_complex) function linear_interp( x::AbstractVector{Tg}, Y::AbstractMatrix{Tv}; - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), search::AbstractSearchPolicy=Binary() ) where {Tg<:AbstractFloat, Tv} # Check if Tv's float base requires grid widening @@ -410,9 +408,7 @@ function linear_interp( Tv_out = _value_type(Tv, Tg) y_mat = Tv_out === Tv ? copy(Y) : Tv_out.(Y) - extrap isa Symbol && Base.depwarn(_EXTRAP_SYMBOL_DEPWARN, :linear_interp) - mode = extrap isa Symbol ? _symbol_to_extrap_mode(extrap) : extrap - return LinearSeriesInterpolant(x, y_mat, mode, search) + return LinearSeriesInterpolant(x, y_mat, extrap, search) end # ======================================== @@ -424,7 +420,7 @@ end function linear_interp( x::AbstractVector{Tg}, ys::AbstractVector{<:AbstractVector{Tv}}; - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), search::AbstractSearchPolicy=Binary() ) where {Tg<:Real, Tv} # Compute promoted grid type (Tg may be Int, promotes to Float) @@ -437,7 +433,7 @@ end function linear_interp( x::AbstractVector{Tg}, Y::AbstractMatrix{Tv}; - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), search::AbstractSearchPolicy=Binary() ) where {Tg<:Real, Tv} Tg_float = float(promote_type(Tg, _real_eltype(Tv))) diff --git a/src/linear/linear_types.jl b/src/linear/linear_types.jl index c3f4b615..130dc4cb 100644 --- a/src/linear/linear_types.jl +++ b/src/linear/linear_types.jl @@ -78,21 +78,17 @@ end # ======================================== # Outer Constructor: typed inputs only # ======================================== -# - Symbol → Val dispatch -# - Call inner constructor # # PERFORMANCE: Typed signature + @inline enables compile-time specialization. # Use linear_interp() for automatic type promotion from Real inputs. @inline function LinearInterpolant( x::X, y::Y; - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), search::P=Binary() ) where {Tg<:AbstractFloat, Tv, X<:AbstractVector{Tg}, Y<:AbstractVector{Tv}, P<:AbstractSearchPolicy} - extrap isa Symbol && Base.depwarn(_EXTRAP_SYMBOL_DEPWARN, :linear_interp) - mode = extrap isa Symbol ? _symbol_to_extrap_mode(extrap) : extrap - E = typeof(mode) - return LinearInterpolant{Tg,Tv,X,Y,E,P}(x, y, mode, search) + E = typeof(extrap) + return LinearInterpolant{Tg,Tv,X,Y,E,P}(x, y, extrap, search) end # ======================================== diff --git a/src/linear/nd/linear_nd_interpolant.jl b/src/linear/nd/linear_nd_interpolant.jl index 9ec0e65f..5f9c8047 100644 --- a/src/linear/nd/linear_nd_interpolant.jl +++ b/src/linear/nd/linear_nd_interpolant.jl @@ -22,7 +22,7 @@ The interpolation is exact at grid points and linearly blended between them. - `data`: N-dimensional data array where `size(data, d) == length(grids[d])` # Keyword Arguments -- `extrap=:none`: Extrapolation mode (`:none`, `:constant`, `:extension`, `:wrap`) or per-axis tuple +- `extrap=NoExtrap()`: Extrapolation mode (`NoExtrap()`, `ConstExtrap()`, `ExtendExtrap()`, `WrapExtrap()`) or per-axis tuple - `search=Binary()`: Search policy or per-axis tuple # Returns @@ -53,7 +53,7 @@ val3d = itp3d((0.5, 1.0, 0.3)) # Per-axis configuration itp = linear_interp((x, y), data; - extrap=(:none, :wrap), + extrap=(NoExtrap(), WrapExtrap()), search=(Binary(), LinearBinary()) ) ``` @@ -61,7 +61,7 @@ itp = linear_interp((x, y), data; function linear_interp( grids::NTuple{N, AbstractVector}, data::AbstractArray{Tv_raw, N}; - extrap::Union{Symbol, NTuple{N, Symbol}, AbstractExtrap, NTuple{N, AbstractExtrap}} = NoExtrap(), + extrap::Union{AbstractExtrap, NTuple{N, AbstractExtrap}} = NoExtrap(), search::Union{AbstractSearchPolicy, NTuple{N, AbstractSearchPolicy}} = Binary() ) where {N, Tv_raw} # Validate grid dimensions @@ -84,20 +84,9 @@ function linear_interp( # Resolve per-axis configuration searches = _resolve_search_nd(search, Val(N)) - if extrap isa AbstractExtrap || extrap isa Tuple{Vararg{AbstractExtrap}} - extrap_vals = _resolve_extrap_nd(extrap, nothing, Val(N)) - return LinearInterpolantND{Tg, Tv, N, - typeof(grids_typed), typeof(spacings), typeof(extrap_vals), typeof(searches)}( - grids_typed, spacings, Array(data_typed), extrap_vals, searches - ) - else - Base.depwarn(_EXTRAP_SYMBOL_DEPWARN, :linear_interp) - extraps = _resolve_extrap_nd(extrap, Val(N)) - @_dispatch_extrap_nd extraps nothing => extrap_vals begin - return LinearInterpolantND{Tg, Tv, N, - typeof(grids_typed), typeof(spacings), typeof(extrap_vals), typeof(searches)}( - grids_typed, spacings, Array(data_typed), extrap_vals, searches - ) - end - end + extrap_vals = _resolve_extrap_nd(extrap, nothing, Val(N)) + return LinearInterpolantND{Tg, Tv, N, + typeof(grids_typed), typeof(spacings), typeof(extrap_vals), typeof(searches)}( + grids_typed, spacings, Array(data_typed), extrap_vals, searches + ) end diff --git a/src/linear/nd/linear_nd_oneshot.jl b/src/linear/nd/linear_nd_oneshot.jl index 84d00498..4c8d77bb 100644 --- a/src/linear/nd/linear_nd_oneshot.jl +++ b/src/linear/nd/linear_nd_oneshot.jl @@ -111,7 +111,7 @@ function linear_interp( grids::NTuple{N, AbstractVector}, data::AbstractArray{Tv, N}, query::Tuple{Vararg{Real, N}}; - extrap::Union{Symbol, NTuple{N, Symbol}, AbstractExtrap, NTuple{N, AbstractExtrap}} = NoExtrap(), + extrap::Union{AbstractExtrap, NTuple{N, AbstractExtrap}} = NoExtrap(), search::Union{AbstractSearchPolicy, NTuple{N, AbstractSearchPolicy}} = Binary(), deriv::Union{Int, Val, NTuple{N,Int}} = 0 ) where {Tv, N} @@ -123,19 +123,9 @@ function linear_interp( searches = _resolve_search_nd(search, Val(N)) - if extrap isa AbstractExtrap || extrap isa Tuple{Vararg{AbstractExtrap}} - extraps_val = _resolve_extrap_nd(extrap, nothing, Val(N)) - return _dispatch_deriv_nd(deriv, Val(N)) do ops - _linear_interp_nd_oneshot(grids_typed, data, query, extraps_val, searches, ops)::Tr - end - else - Base.depwarn(_EXTRAP_SYMBOL_DEPWARN, :linear_interp) - extraps = _resolve_extrap_nd(extrap, Val(N)) - @_dispatch_extrap_nd extraps nothing => extraps_val begin - return _dispatch_deriv_nd(deriv, Val(N)) do ops - _linear_interp_nd_oneshot(grids_typed, data, query, extraps_val, searches, ops)::Tr - end - end + extraps_val = _resolve_extrap_nd(extrap, nothing, Val(N)) + return _dispatch_deriv_nd(deriv, Val(N)) do ops + _linear_interp_nd_oneshot(grids_typed, data, query, extraps_val, searches, ops)::Tr end end @@ -149,7 +139,7 @@ function linear_interp( grids::NTuple{N, AbstractVector}, data::AbstractArray{Tv, N}, queries::NTuple{N, AbstractVector{<:Real}}; - extrap::Union{Symbol, NTuple{N, Symbol}, AbstractExtrap, NTuple{N, AbstractExtrap}} = NoExtrap(), + extrap::Union{AbstractExtrap, NTuple{N, AbstractExtrap}} = NoExtrap(), search::Union{AbstractSearchPolicy, NTuple{N, AbstractSearchPolicy}} = Binary(), deriv::Union{Int, Val, NTuple{N,Int}} = 0 ) where {Tv, N} @@ -171,7 +161,7 @@ function linear_interp( grids::NTuple{N, AbstractVector}, data::AbstractArray{Tv, N}, queries::AbstractVector{<:Tuple{Vararg{Real, N}}}; - extrap::Union{Symbol, NTuple{N, Symbol}, AbstractExtrap, NTuple{N, AbstractExtrap}} = NoExtrap(), + extrap::Union{AbstractExtrap, NTuple{N, AbstractExtrap}} = NoExtrap(), search::Union{AbstractSearchPolicy, NTuple{N, AbstractSearchPolicy}} = Binary(), deriv::Union{Int, Val, NTuple{N,Int}} = 0 ) where {Tv, N} @@ -198,7 +188,7 @@ function linear_interp!( grids::NTuple{N, AbstractVector}, data::AbstractArray{Tv, N}, queries::NTuple{N, AbstractVector{<:Real}}; - extrap::Union{Symbol, NTuple{N, Symbol}, AbstractExtrap, NTuple{N, AbstractExtrap}} = NoExtrap(), + extrap::Union{AbstractExtrap, NTuple{N, AbstractExtrap}} = NoExtrap(), search::Union{AbstractSearchPolicy, NTuple{N, AbstractSearchPolicy}} = Binary(), deriv::Union{Int, Val, NTuple{N,Int}} = 0 ) where {Tv, N} @@ -209,19 +199,9 @@ function linear_interp!( searches = _resolve_search_nd(search, Val(N)) - if extrap isa AbstractExtrap || extrap isa Tuple{Vararg{AbstractExtrap}} - extraps_val = _resolve_extrap_nd(extrap, nothing, Val(N)) - return _dispatch_deriv_nd(deriv, Val(N)) do ops - _linear_interp_nd_oneshot_soa!(output, grids_typed, data, queries, extraps_val, searches, ops) - end - else - Base.depwarn(_EXTRAP_SYMBOL_DEPWARN, :linear_interp!) - extraps = _resolve_extrap_nd(extrap, Val(N)) - @_dispatch_extrap_nd extraps nothing => extraps_val begin - return _dispatch_deriv_nd(deriv, Val(N)) do ops - _linear_interp_nd_oneshot_soa!(output, grids_typed, data, queries, extraps_val, searches, ops) - end - end + extraps_val = _resolve_extrap_nd(extrap, nothing, Val(N)) + return _dispatch_deriv_nd(deriv, Val(N)) do ops + _linear_interp_nd_oneshot_soa!(output, grids_typed, data, queries, extraps_val, searches, ops) end end @@ -236,7 +216,7 @@ function linear_interp!( grids::NTuple{N, AbstractVector}, data::AbstractArray{Tv, N}, queries::AbstractVector{<:Tuple{Vararg{Real, N}}}; - extrap::Union{Symbol, NTuple{N, Symbol}, AbstractExtrap, NTuple{N, AbstractExtrap}} = NoExtrap(), + extrap::Union{AbstractExtrap, NTuple{N, AbstractExtrap}} = NoExtrap(), search::Union{AbstractSearchPolicy, NTuple{N, AbstractSearchPolicy}} = Binary(), deriv::Union{Int, Val, NTuple{N,Int}} = 0 ) where {Tv, N} @@ -247,18 +227,8 @@ function linear_interp!( searches = _resolve_search_nd(search, Val(N)) - if extrap isa AbstractExtrap || extrap isa Tuple{Vararg{AbstractExtrap}} - extraps_val = _resolve_extrap_nd(extrap, nothing, Val(N)) - return _dispatch_deriv_nd(deriv, Val(N)) do ops - _linear_interp_nd_oneshot_aos!(output, grids_typed, data, queries, extraps_val, searches, ops) - end - else - Base.depwarn(_EXTRAP_SYMBOL_DEPWARN, :linear_interp!) - extraps = _resolve_extrap_nd(extrap, Val(N)) - @_dispatch_extrap_nd extraps nothing => extraps_val begin - return _dispatch_deriv_nd(deriv, Val(N)) do ops - _linear_interp_nd_oneshot_aos!(output, grids_typed, data, queries, extraps_val, searches, ops) - end - end + extraps_val = _resolve_extrap_nd(extrap, nothing, Val(N)) + return _dispatch_deriv_nd(deriv, Val(N)) do ops + _linear_interp_nd_oneshot_aos!(output, grids_typed, data, queries, extraps_val, searches, ops) end end diff --git a/src/quadratic/nd/quadratic_nd_interpolant.jl b/src/quadratic/nd/quadratic_nd_interpolant.jl index dea2ddd3..cfcbd1fb 100644 --- a/src/quadratic/nd/quadratic_nd_interpolant.jl +++ b/src/quadratic/nd/quadratic_nd_interpolant.jl @@ -81,7 +81,7 @@ Create an N-dimensional quadratic interpolant from grid vectors and data array. - `bc=Left(QuadraticFit())`: Boundary condition(s). Can be: - Single BC: Applied to all axes - `NTuple{N}`: Per-axis BCs -- `extrap=:none`: Extrapolation mode(s) +- `extrap=NoExtrap()`: Extrapolation mode(s) - `search=Binary()`: Search policy(s) # Returns @@ -101,7 +101,7 @@ function quadratic_interp( grids::NTuple{N, AbstractVector}, data::AbstractArray{Tv_raw, N}; bc::Union{AbstractBC, NTuple{N,AbstractBC}}=Left(QuadraticFit()), - extrap::Union{Symbol, NTuple{N,Symbol}, AbstractExtrap, NTuple{N,AbstractExtrap}}=NoExtrap(), + extrap::Union{AbstractExtrap, NTuple{N,AbstractExtrap}}=NoExtrap(), search::Union{AbstractSearchPolicy, NTuple{N,AbstractSearchPolicy}}=Binary() ) where {N, Tv_raw} # Zero-allocation type promotion @@ -121,16 +121,8 @@ function quadratic_interp( bcs = _resolve_bcs_nd_quadratic(bc, Val(N)) searches = _resolve_search_nd(search, Val(N)) - if extrap isa AbstractExtrap || extrap isa Tuple{Vararg{AbstractExtrap}} - extraps_val = _resolve_extrap_nd(extrap, bcs, Val(N)) - return _build_nd_quadratic_interpolant(grids_typed, data, bcs, extraps_val, searches) - else - Base.depwarn(_EXTRAP_SYMBOL_DEPWARN, :quadratic_interp) - extraps = _resolve_extrap_nd(extrap, Val(N)) - @_dispatch_extrap_nd extraps bcs => extraps_val begin - return _build_nd_quadratic_interpolant(grids_typed, data, bcs, extraps_val, searches) - end - end + extraps_val = _resolve_extrap_nd(extrap, bcs, Val(N)) + return _build_nd_quadratic_interpolant(grids_typed, data, bcs, extraps_val, searches) end # ======================================== @@ -153,8 +145,7 @@ function _build_nd_quadratic_interpolant( # Store BCs as-is (already QuadraticBC) bcs_store = bcs - # extraps_val already dispatched to concrete Val types at API boundary - # (via @_dispatch_extrap_nd in quadratic_interp) + # extraps_val already resolved to concrete types at API boundary # Construct the interpolant NP1 = N + 1 diff --git a/src/quadratic/nd/quadratic_nd_oneshot.jl b/src/quadratic/nd/quadratic_nd_oneshot.jl index 5675c772..88480d26 100644 --- a/src/quadratic/nd/quadratic_nd_oneshot.jl +++ b/src/quadratic/nd/quadratic_nd_oneshot.jl @@ -143,7 +143,7 @@ function quadratic_interp( query::Tuple{Vararg{Real, N}}; deriv::Union{Int, Val, NTuple{N,Int}}=0, bc::Union{AbstractBC, NTuple{N,AbstractBC}}=Left(QuadraticFit()), - extrap::Union{Symbol, NTuple{N,Symbol}, AbstractExtrap, NTuple{N,AbstractExtrap}}=NoExtrap(), + extrap::Union{AbstractExtrap, NTuple{N,AbstractExtrap}}=NoExtrap(), search::Union{AbstractSearchPolicy, NTuple{N,AbstractSearchPolicy}}=Binary() ) where {Tv, N} Tg = _promote_grid_eltype(grids) @@ -155,21 +155,10 @@ function quadratic_interp( bcs = _resolve_bcs_nd_quadratic(bc, Val(N)) searches = _resolve_search_nd(search, Val(N)) - if extrap isa AbstractExtrap || extrap isa Tuple{Vararg{AbstractExtrap}} - extraps_val = _resolve_extrap_nd(extrap, bcs, Val(N)) - return _dispatch_deriv_nd(deriv, Val(N)) do ops - _quadratic_interp_nd_oneshot( - grids_typed, data, query, bcs, extraps_val, searches, ops)::Tr - end - else - Base.depwarn(_EXTRAP_SYMBOL_DEPWARN, :quadratic_interp) - extraps = _resolve_extrap_nd(extrap, Val(N)) - @_dispatch_extrap_nd extraps bcs => extraps_val begin - return _dispatch_deriv_nd(deriv, Val(N)) do ops - _quadratic_interp_nd_oneshot( - grids_typed, data, query, bcs, extraps_val, searches, ops)::Tr - end - end + extraps_val = _resolve_extrap_nd(extrap, bcs, Val(N)) + return _dispatch_deriv_nd(deriv, Val(N)) do ops + _quadratic_interp_nd_oneshot( + grids_typed, data, query, bcs, extraps_val, searches, ops)::Tr end end @@ -185,7 +174,7 @@ function quadratic_interp( queries::Tuple{Vararg{AbstractVector{<:Real}, N}}; deriv::Union{Int, Val, NTuple{N,Int}}=0, bc::Union{AbstractBC, NTuple{N,AbstractBC}}=Left(QuadraticFit()), - extrap::Union{Symbol, NTuple{N,Symbol}, AbstractExtrap, NTuple{N,AbstractExtrap}}=NoExtrap(), + extrap::Union{AbstractExtrap, NTuple{N,AbstractExtrap}}=NoExtrap(), search::Union{AbstractSearchPolicy, NTuple{N,AbstractSearchPolicy}}=Binary() ) where {Tv, N} Tg = _promote_grid_eltype(grids) @@ -208,7 +197,7 @@ function quadratic_interp( queries::AbstractVector{<:Tuple{Vararg{Real, N}}}; deriv::Union{Int, Val, NTuple{N,Int}}=0, bc::Union{AbstractBC, NTuple{N,AbstractBC}}=Left(QuadraticFit()), - extrap::Union{Symbol, NTuple{N,Symbol}, AbstractExtrap, NTuple{N,AbstractExtrap}}=NoExtrap(), + extrap::Union{AbstractExtrap, NTuple{N,AbstractExtrap}}=NoExtrap(), search::Union{AbstractSearchPolicy, NTuple{N,AbstractSearchPolicy}}=Binary() ) where {Tv, N} Tg = _promote_grid_eltype(grids) @@ -236,7 +225,7 @@ function quadratic_interp!( queries::Tuple{Vararg{AbstractVector{<:Real}, N}}; deriv::Union{Int, Val, NTuple{N,Int}}=0, bc::Union{AbstractBC, NTuple{N,AbstractBC}}=Left(QuadraticFit()), - extrap::Union{Symbol, NTuple{N,Symbol}, AbstractExtrap, NTuple{N,AbstractExtrap}}=NoExtrap(), + extrap::Union{AbstractExtrap, NTuple{N,AbstractExtrap}}=NoExtrap(), search::Union{AbstractSearchPolicy, NTuple{N,AbstractSearchPolicy}}=Binary() ) where {Tv, N} Tg = _promote_grid_eltype(grids) @@ -247,21 +236,10 @@ function quadratic_interp!( bcs = _resolve_bcs_nd_quadratic(bc, Val(N)) searches = _resolve_search_nd(search, Val(N)) - if extrap isa AbstractExtrap || extrap isa Tuple{Vararg{AbstractExtrap}} - extraps_val = _resolve_extrap_nd(extrap, bcs, Val(N)) - return _dispatch_deriv_nd(deriv, Val(N)) do ops - _quadratic_interp_nd_oneshot_soa!( - output, grids_typed, data, queries, bcs, extraps_val, searches, ops) - end - else - Base.depwarn(_EXTRAP_SYMBOL_DEPWARN, :quadratic_interp!) - extraps = _resolve_extrap_nd(extrap, Val(N)) - @_dispatch_extrap_nd extraps bcs => extraps_val begin - return _dispatch_deriv_nd(deriv, Val(N)) do ops - _quadratic_interp_nd_oneshot_soa!( - output, grids_typed, data, queries, bcs, extraps_val, searches, ops) - end - end + extraps_val = _resolve_extrap_nd(extrap, bcs, Val(N)) + return _dispatch_deriv_nd(deriv, Val(N)) do ops + _quadratic_interp_nd_oneshot_soa!( + output, grids_typed, data, queries, bcs, extraps_val, searches, ops) end end @@ -278,7 +256,7 @@ function quadratic_interp!( queries::AbstractVector{<:Tuple{Vararg{Real, N}}}; deriv::Union{Int, Val, NTuple{N,Int}}=0, bc::Union{AbstractBC, NTuple{N,AbstractBC}}=Left(QuadraticFit()), - extrap::Union{Symbol, NTuple{N,Symbol}, AbstractExtrap, NTuple{N,AbstractExtrap}}=NoExtrap(), + extrap::Union{AbstractExtrap, NTuple{N,AbstractExtrap}}=NoExtrap(), search::Union{AbstractSearchPolicy, NTuple{N,AbstractSearchPolicy}}=Binary() ) where {Tv, N} Tg = _promote_grid_eltype(grids) @@ -289,20 +267,9 @@ function quadratic_interp!( bcs = _resolve_bcs_nd_quadratic(bc, Val(N)) searches = _resolve_search_nd(search, Val(N)) - if extrap isa AbstractExtrap || extrap isa Tuple{Vararg{AbstractExtrap}} - extraps_val = _resolve_extrap_nd(extrap, bcs, Val(N)) - return _dispatch_deriv_nd(deriv, Val(N)) do ops - _quadratic_interp_nd_oneshot_aos!( - output, grids_typed, data, queries, bcs, extraps_val, searches, ops) - end - else - Base.depwarn(_EXTRAP_SYMBOL_DEPWARN, :quadratic_interp!) - extraps = _resolve_extrap_nd(extrap, Val(N)) - @_dispatch_extrap_nd extraps bcs => extraps_val begin - return _dispatch_deriv_nd(deriv, Val(N)) do ops - _quadratic_interp_nd_oneshot_aos!( - output, grids_typed, data, queries, bcs, extraps_val, searches, ops) - end - end + extraps_val = _resolve_extrap_nd(extrap, bcs, Val(N)) + return _dispatch_deriv_nd(deriv, Val(N)) do ops + _quadratic_interp_nd_oneshot_aos!( + output, grids_typed, data, queries, bcs, extraps_val, searches, ops) end end diff --git a/src/quadratic/quadratic_anchor.jl b/src/quadratic/quadratic_anchor.jl index a5075e72..be4e7a0f 100644 --- a/src/quadratic/quadratic_anchor.jl +++ b/src/quadratic/quadratic_anchor.jl @@ -70,7 +70,7 @@ Create an anchored query for ultra-fast quadratic interpolation at a fixed point - `xq`: Query point (scalar, can be Float or ForwardDiff.Dual for AD) - `::Val{:quadratic}`: Type tag to distinguish from other anchor types - `wrap`: If true, wrap `xq` to domain [x[1], x[end]) before anchoring. - Used for `extrap=:wrap` mode. + Used for `extrap=WrapExtrap()` mode. # Returns `_QuadraticAnchoredQuery{Tg, Tq}` with precomputed geometry. @@ -208,7 +208,7 @@ while preserving the full Dual value for `dL` computation. # Use primal value for comparisons (supports ForwardDiff.Dual) xq_primal = _extract_primal(xq) - # Handle wrapping (for extrap=:wrap mode) + # Handle wrapping (for extrap=WrapExtrap() mode) if wrap && (xq_primal < x_min || xq_primal >= x_max) xq = _wrap_to_domain(xq, x_min, x_max) xq_primal = xq # xq is now Tg, no need for _extract_primal diff --git a/src/quadratic/quadratic_interpolant.jl b/src/quadratic/quadratic_interpolant.jl index 6cf01575..2f4f8fa1 100644 --- a/src/quadratic/quadratic_interpolant.jl +++ b/src/quadratic/quadratic_interpolant.jl @@ -69,7 +69,7 @@ Create a callable interpolant for broadcast fusion and reuse. - `x::AbstractVector`: x-coordinates (sorted, length ≥ 2) - `y::AbstractVector`: y-values (can be Real or Complex) - `bc`: Boundary condition (Left, Right, MinCurvFit, or Left/Right with QuadraticFit) -- `extrap::AbstractExtrap`: `NoExtrap()` (default), `ConstExtrap()`, `ExtendExtrap()`, or `WrapExtrap()` (Symbol args deprecated) +- `extrap::AbstractExtrap`: `NoExtrap()` (default), `ConstExtrap()`, `ExtendExtrap()`, or `WrapExtrap()` - `search::AbstractSearchPolicy`: Default search policy (default: `Binary()`) # Returns @@ -120,7 +120,7 @@ end x::AbstractVector{TX}, y::AbstractVector{TY}; bc::QuadraticBC=Left(QuadraticFit()), - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), search::AbstractSearchPolicy=Binary() ) where {TX<:Real, TY} x_p, y_p = _promote_itp_inputs(x, y) diff --git a/src/quadratic/quadratic_oneshot.jl b/src/quadratic/quadratic_oneshot.jl index 0b44035b..f609dbc4 100644 --- a/src/quadratic/quadratic_oneshot.jl +++ b/src/quadratic/quadratic_oneshot.jl @@ -165,7 +165,7 @@ C1 piecewise quadratic spline interpolation at a single point. - `Right(Deriv1(v))`: First derivative = v at right endpoint - `Right(Deriv2(v))`: Second derivative = v at right endpoint - `MinCurvFit()`: Minimize total curvature (globally smooth) -- `extrap::AbstractExtrap`: Extrapolation mode (Symbol args deprecated) +- `extrap::AbstractExtrap`: Extrapolation mode - `NoExtrap()` (default): throws DomainError if outside domain - `ConstExtrap()`: clamp to boundary values - `ExtendExtrap()`: extend the boundary polynomial @@ -200,7 +200,7 @@ vals = quadratic_interp(x, y, sorted_queries; search=LinearBinary(linear_window= y::AbstractVector{Tv}, xq::Tq; # Accepts Tg, Real, or Dual for AD (Dual <: Real) bc::QuadraticBC=Left(QuadraticFit()), - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), deriv::Int=0, search=Binary(), hint::Union{Nothing,Base.RefValue{Int}}=nothing @@ -218,10 +218,8 @@ vals = quadratic_interp(x, y, sorted_queries; search=LinearBinary(linear_window= _compute_quadratic_coeffs!(h, d, a, x, y, bc_promoted) searcher = _to_searcher(search, hint) - extrap isa Symbol && Base.depwarn(_EXTRAP_SYMBOL_DEPWARN, :quadratic_interp) - mode = extrap isa Symbol ? _symbol_to_extrap_mode(extrap) : extrap @_dispatch_deriv deriv => op begin - _quadratic_eval_at_point(x, y, h, a, d, xq, mode, op, searcher) + _quadratic_eval_at_point(x, y, h, a, d, xq, extrap, op, searcher) end end @@ -258,7 +256,7 @@ quadratic_interp!(output, x, y, sorted_queries; search=LinearBinary(linear_windo y::AbstractVector{Tv}, x_targets::AbstractVector{Tg}; bc::QuadraticBC=Left(QuadraticFit()), - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), deriv::Int=0, search::AbstractSearchPolicy=Binary() ) where {Tg<:AbstractFloat, Tv} @@ -276,12 +274,10 @@ quadratic_interp!(output, x, y, sorted_queries; search=LinearBinary(linear_windo _compute_quadratic_coeffs!(h, d, a, x, y, bc_promoted) searcher = _to_searcher(search) - extrap isa Symbol && Base.depwarn(_EXTRAP_SYMBOL_DEPWARN, :quadratic_interp!) - mode = extrap isa Symbol ? _symbol_to_extrap_mode(extrap) : extrap @_dispatch_deriv deriv => op begin - @boundscheck _check_domain(x, x_targets, mode) + @boundscheck _check_domain(x, x_targets, extrap) @inbounds for i in eachindex(x_targets, output) - output[i] = _quadratic_eval_at_point(x, y, h, a, d, x_targets[i], mode, op, searcher) + output[i] = _quadratic_eval_at_point(x, y, h, a, d, x_targets[i], extrap, op, searcher) end end return output @@ -313,7 +309,7 @@ function quadratic_interp( y::AbstractVector{Tv}, x_targets::AbstractVector{Tg}; bc::QuadraticBC=Left(QuadraticFit()), - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), deriv::Int=0, search::AbstractSearchPolicy=Binary() ) where {Tg<:AbstractFloat, Tv} @@ -368,7 +364,7 @@ end y::AbstractVector{Tv}, xq::Tq; # Accepts Tg, Real, or Dual for AD (Dual <: Real) bc::QuadraticBC=Left(QuadraticFit()), - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), deriv::Int=0, search=Binary(), hint::Union{Nothing,Base.RefValue{Int}}=nothing @@ -390,7 +386,7 @@ function quadratic_interp( y::AbstractVector{Tv}, x_targets::AbstractVector{Tq}; bc::QuadraticBC=Left(QuadraticFit()), - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), deriv::Int=0, search::AbstractSearchPolicy=Binary() ) where {Tg<:Real, Tv, Tq<:Real} @@ -412,7 +408,7 @@ function quadratic_interp!( y::AbstractVector{Tv}, x_targets::AbstractVector{Tq}; bc::QuadraticBC=Left(QuadraticFit()), - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), deriv::Int=0, search::AbstractSearchPolicy=Binary() ) where {Tg<:Real, Tv, Tq<:Real} diff --git a/src/quadratic/quadratic_series_interp.jl b/src/quadratic/quadratic_series_interp.jl index c645add7..a9a9dde0 100644 --- a/src/quadratic/quadratic_series_interp.jl +++ b/src/quadratic/quadratic_series_interp.jl @@ -345,7 +345,7 @@ Create a multi-Y quadratic series interpolant for multiple y-data series sharing - `x::AbstractVector`: x-coordinates (sorted, length ≥ 2) - `ys`: Vector of y-value vectors (all same length as x) - `bc`: Boundary condition (Left/Right with QuadraticFit, Deriv1, Deriv2, MinCurvFit) -- `extrap::AbstractExtrap`: `NoExtrap()`, `ConstExtrap()`, or `ExtendExtrap()` (Symbol args deprecated) +- `extrap::AbstractExtrap`: `NoExtrap()`, `ConstExtrap()`, or `ExtendExtrap()` # Returns `QuadraticSeriesInterpolant` object with unified matrix storage. @@ -366,7 +366,7 @@ function quadratic_interp( x::AbstractVector{Tg}, ys::AbstractVector{<:AbstractVector{Tv}}; bc::QuadraticBC=Left(QuadraticFit()), - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), search::P=Binary() ) where {Tg<:AbstractFloat, Tv, P<:AbstractSearchPolicy} # Check if Tv's float base requires grid widening (not for Int types) @@ -422,9 +422,7 @@ function quadratic_interp( end end - extrap isa Symbol && Base.depwarn(_EXTRAP_SYMBOL_DEPWARN, :quadratic_interp) - mode = extrap isa Symbol ? _symbol_to_extrap_mode(extrap) : extrap - return QuadraticSeriesInterpolant(x, y_mat, a_mat, d_mat, h, mode, search) + return QuadraticSeriesInterpolant(x, y_mat, a_mat, d_mat, h, extrap, search) end # Matrix input: columns as y-series @@ -450,7 +448,7 @@ function quadratic_interp( x::AbstractVector{Tg}, Y::AbstractMatrix{Tv}; bc::QuadraticBC=Left(QuadraticFit()), - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), search::AbstractSearchPolicy=Binary() ) where {Tg<:AbstractFloat, Tv} ys = [Y[:, k] for k in axes(Y, 2)] @@ -467,7 +465,7 @@ function quadratic_interp( x::AbstractVector{Tg}, ys::AbstractVector{<:AbstractVector{Tv}}; bc=Left(QuadraticFit()), - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), search::AbstractSearchPolicy=Binary() ) where {Tg<:Real, Tv} # Compute promoted grid type (Tg may be Int, promotes to Float) @@ -482,7 +480,7 @@ function quadratic_interp( x::AbstractVector{Tg}, Y::AbstractMatrix{Tv}; bc=Left(QuadraticFit()), - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), search::AbstractSearchPolicy=Binary() ) where {Tg<:Real, Tv} Tg_float = float(promote_type(Tg, _real_eltype(Tv))) diff --git a/src/quadratic/quadratic_types.jl b/src/quadratic/quadratic_types.jl index 357197b0..067cc557 100644 --- a/src/quadratic/quadratic_types.jl +++ b/src/quadratic/quadratic_types.jl @@ -77,7 +77,6 @@ end # ======================================== # Outer Constructor: typed inputs only # ======================================== -# - Symbol → AbstractExtrap dispatch # - Call inner constructor # # PERFORMANCE: Typed signature + @inline enables compile-time specialization. @@ -88,11 +87,9 @@ end h::Vector{Tg}, a::Vector{Tv}, d::Vector{Tv}; - extrap::Union{Symbol,AbstractExtrap}=NoExtrap(), + extrap::AbstractExtrap=NoExtrap(), search::P=Binary() ) where {Tg<:AbstractFloat, Tv, X<:AbstractVector{Tg}, Y<:AbstractVector{Tv}, P<:AbstractSearchPolicy} - extrap isa Symbol && Base.depwarn(_EXTRAP_SYMBOL_DEPWARN, :quadratic_interp) - mode = extrap isa Symbol ? _symbol_to_extrap_mode(extrap) : extrap - E = typeof(mode) - return QuadraticInterpolant{Tg,Tv,X,Y,E,P}(x, y, h, a, d, mode, search) + E = typeof(extrap) + return QuadraticInterpolant{Tg,Tv,X,Y,E,P}(x, y, h, a, d, extrap, search) end diff --git a/test/test_autodiff_Enzyme.jl b/test/test_autodiff_Enzyme.jl index ed00d9d5..2e99d00b 100644 --- a/test/test_autodiff_Enzyme.jl +++ b/test/test_autodiff_Enzyme.jl @@ -57,7 +57,7 @@ else @testset "Enzyme Compatibility Status" begin x = collect(0.0:0.5:2.0) y = sin.(x) - itp = linear_interp(x, y; extrap=:extension) + itp = linear_interp(x, y; extrap=ExtendExtrap()) @testset "basic autodiff works" begin f(xq) = itp(xq) @@ -90,7 +90,7 @@ else y_linear = 2.0 .* x .+ 1.0 @testset "Single Interpolant - Real" begin - itp = linear_interp(x, y_linear; extrap=:extension) + itp = linear_interp(x, y_linear; extrap=ExtendExtrap()) f(xq) = itp(xq) result = Enzyme.autodiff(Enzyme.Reverse, f, Enzyme.Active, Enzyme.Active(2.25)) @@ -106,7 +106,7 @@ else @testset "Series Interpolant (broken - array mutation)" begin y1 = sin.(x) y2 = cos.(x) - sitp = linear_interp(x, [y1, y2]; extrap=:extension) + sitp = linear_interp(x, [y1, y2]; extrap=ExtendExtrap()) @test_broken begin f(xq) = sum(sitp(xq)) @@ -128,7 +128,7 @@ else y = [10.0, 20.0, 30.0, 40.0, 50.0, 60.0] @testset "Single Interpolant" begin - itp = constant_interp(x, y; side=:left, extrap=:extension) + itp = constant_interp(x, y; side=:left, extrap=ExtendExtrap()) f(xq) = itp(xq) result = Enzyme.autodiff(Enzyme.Reverse, f, Enzyme.Active, Enzyme.Active(2.5)) @@ -146,7 +146,7 @@ else y_quad = x .^ 2 @testset "Single Interpolant" begin - itp = quadratic_interp(x, y_quad; extrap=:extension) + itp = quadratic_interp(x, y_quad; extrap=ExtendExtrap()) f(xq) = itp(xq) xq = 2.25 @@ -164,7 +164,7 @@ else y_cubic = x .^ 3 @testset "Single Interpolant" begin - itp = cubic_interp(x, y_cubic; extrap=:extension) + itp = cubic_interp(x, y_cubic; extrap=ExtendExtrap()) f(xq) = itp(xq) xq = 2.25 @@ -183,7 +183,7 @@ else y_complex = (2.0 + 1.0im) .* x .+ (1.0 - 1.0im) @testset "Linear Complex (via real)" begin - itp = linear_interp(x, y_complex; extrap=:extension) + itp = linear_interp(x, y_complex; extrap=ExtendExtrap()) f(xq) = real(itp(xq)) result = Enzyme.autodiff(Enzyme.Reverse, f, Enzyme.Active, Enzyme.Active(2.25)) @@ -191,7 +191,7 @@ else end @testset "Linear Complex (via imag)" begin - itp = linear_interp(x, y_complex; extrap=:extension) + itp = linear_interp(x, y_complex; extrap=ExtendExtrap()) f(xq) = imag(itp(xq)) result = Enzyme.autodiff(Enzyme.Reverse, f, Enzyme.Active, Enzyme.Active(2.25)) @@ -208,7 +208,7 @@ else x = collect(0.0:0.5:5.0) y = sin.(x) - itp = cubic_interp(x, y; extrap=:extension) + itp = cubic_interp(x, y; extrap=ExtendExtrap()) @testset "Enzyme matches ForwardDiff" begin for xq in [0.5, 1.5, 2.5, 3.5] diff --git a/test/test_autodiff_ForwardDiff.jl b/test/test_autodiff_ForwardDiff.jl index 1e0c28a7..72f0489b 100644 --- a/test/test_autodiff_ForwardDiff.jl +++ b/test/test_autodiff_ForwardDiff.jl @@ -30,7 +30,7 @@ const FI = FastInterpolations x = collect(0.0:0.5:5.0) y = 2.0 .* x .+ 1.0 - itp = linear_interp(x, y; extrap=:extension) + itp = linear_interp(x, y; extrap=ExtendExtrap()) @testset "derivative matches analytical" begin test_points = [0.25, 1.0, 2.5, 3.75, 4.5] @@ -54,7 +54,7 @@ const FI = FastInterpolations @test fd_d2 ≈ 0.0 atol=1e-10 # Also cover Float32-grid interpolants (previously hit Float32(::Dual) errors). - itp32 = linear_interp(Float32.(x), Float32.(y); extrap=:extension) + itp32 = linear_interp(Float32.(x), Float32.(y); extrap=ExtendExtrap()) fd_d2_32 = ForwardDiff.derivative(q -> ForwardDiff.derivative(itp32, q), xq) @test fd_d2_32 ≈ 0.0 atol=1e-6 end @@ -73,7 +73,7 @@ const FI = FastInterpolations @testset "works with nonlinear data" begin # Quadratic data: y = x² y_quad = x .^ 2 - itp_quad = linear_interp(x, y_quad; extrap=:extension) + itp_quad = linear_interp(x, y_quad; extrap=ExtendExtrap()) # At x=2.0 (grid point), linear interp between x=1.5 and x=2.0 # or between x=2.0 and x=2.5 depending on interval @@ -108,7 +108,7 @@ const FI = FastInterpolations x = collect(range(0.0, 2π, 21)) y1 = sin.(x) y2 = cos.(x) - sitp = linear_interp(x, [y1, y2]; extrap=:extension) + sitp = linear_interp(x, [y1, y2]; extrap=ExtendExtrap()) @testset "derivative matches analytical (interior points)" begin # Test at interior points only (not at grid points) @@ -147,7 +147,7 @@ const FI = FastInterpolations x_lin = collect(0.0:0.5:5.0) y1_lin = 2.0 .* x_lin y2_lin = -x_lin .+ 5.0 - sitp_lin = linear_interp(x_lin, [y1_lin, y2_lin]; extrap=:extension) + sitp_lin = linear_interp(x_lin, [y1_lin, y2_lin]; extrap=ExtendExtrap()) xq = 2.25 fd_derivs = ForwardDiff.derivative(sitp_lin, xq) @@ -169,7 +169,7 @@ const FI = FastInterpolations # Imag part: x - 1, derivative = 1 y_complex = (2.0 + 1.0im) .* x .+ (1.0 - 1.0im) - itp = linear_interp(x, y_complex; extrap=:extension) + itp = linear_interp(x, y_complex; extrap=ExtendExtrap()) @testset "complex derivative" begin xq = 2.25 @@ -200,7 +200,7 @@ const FI = FastInterpolations @testset "type stability" begin x = collect(0.0:0.5:5.0) y = sin.(x) - itp = linear_interp(x, y; extrap=:extension) + itp = linear_interp(x, y; extrap=ExtendExtrap()) @testset "Dual output type for Dual input" begin xq = ForwardDiff.Dual(2.5, 1.0) @@ -227,7 +227,7 @@ const FI = FastInterpolations x = collect(0.0:0.5:5.0) y = x .^ 2 # y = x² - itp = linear_interp(x, y; extrap=:extension) + itp = linear_interp(x, y; extrap=ExtendExtrap()) @testset "ForwardDiff.gradient on function using interpolant" begin # Function that uses interpolation @@ -258,7 +258,7 @@ const FI = FastInterpolations x32 = Float32.(collect(0.0:0.5:5.0)) y32 = Float32.(2.0 .* x32 .+ 1.0) - itp32 = linear_interp(x32, y32; extrap=:extension) + itp32 = linear_interp(x32, y32; extrap=ExtendExtrap()) @testset "Float32 derivative" begin xq = 2.25f0 @@ -279,7 +279,7 @@ const FI = FastInterpolations y = [10.0, 20.0, 30.0, 40.0, 50.0, 60.0] @testset "interpolant callable AD - derivative is zero" begin - itp = constant_interp(x, y; side=:left, extrap=:extension) + itp = constant_interp(x, y; side=:left, extrap=ExtendExtrap()) # Constant interpolation derivative should be 0 (step function) for xq in [0.5, 1.5, 2.5, 3.5] @@ -298,7 +298,7 @@ const FI = FastInterpolations end @testset "value is preserved" begin - itp = constant_interp(x, y; side=:left, extrap=:extension) + itp = constant_interp(x, y; side=:left, extrap=ExtendExtrap()) test_points = [0.5, 1.5, 2.5, 3.5] for xq in test_points @@ -311,7 +311,7 @@ const FI = FastInterpolations @testset "side modes" begin # Test all side modes work with AD for side_mode in [:left, :right, :nearest] - itp = constant_interp(x, y; side=side_mode, extrap=:extension) + itp = constant_interp(x, y; side=side_mode, extrap=ExtendExtrap()) fd_deriv = ForwardDiff.derivative(itp, 2.5) @test fd_deriv ≈ 0.0 atol=1e-10 end @@ -326,7 +326,7 @@ const FI = FastInterpolations x = collect(0.0:1.0:5.0) y1 = [10.0, 20.0, 30.0, 40.0, 50.0, 60.0] y2 = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0] - sitp = constant_interp(x, [y1, y2]; side=:left, extrap=:extension) + sitp = constant_interp(x, [y1, y2]; side=:left, extrap=ExtendExtrap()) @testset "series derivative is zero" begin # ForwardDiff.derivative on series returns vector of derivatives @@ -356,7 +356,7 @@ const FI = FastInterpolations x = collect(0.0:1.0:5.0) y_complex = [10.0+1.0im, 20.0+2.0im, 30.0+3.0im, 40.0+4.0im, 50.0+5.0im, 60.0+6.0im] - itp = constant_interp(x, y_complex; side=:left, extrap=:extension) + itp = constant_interp(x, y_complex; side=:left, extrap=ExtendExtrap()) @testset "complex derivative" begin xq = 2.5 @@ -378,7 +378,7 @@ const FI = FastInterpolations @testset "Constant gradient composition" begin x = collect(0.0:1.0:5.0) y = [10.0, 20.0, 30.0, 40.0, 50.0, 60.0] - itp = constant_interp(x, y; side=:left, extrap=:extension) + itp = constant_interp(x, y; side=:left, extrap=ExtendExtrap()) @testset "gradient through loss function" begin function loss(params) @@ -402,7 +402,7 @@ const FI = FastInterpolations x = collect(0.0:0.5:5.0) y = x .^ 2 - itp = quadratic_interp(x, y; extrap=:extension) + itp = quadratic_interp(x, y; extrap=ExtendExtrap()) @testset "derivative matches analytical" begin test_points = [0.25, 1.0, 2.5, 3.75, 4.5] @@ -444,7 +444,7 @@ const FI = FastInterpolations @testset "works with cubic data" begin # Cubic data: y = x³ - piecewise quadratic won't be exact y_cubic = x .^ 3 - itp_cubic = quadratic_interp(x, y_cubic; extrap=:extension) + itp_cubic = quadratic_interp(x, y_cubic; extrap=ExtendExtrap()) xq = 2.25 @@ -464,7 +464,7 @@ const FI = FastInterpolations @testset "Float32 support" begin x32 = Float32.(collect(0.0:0.5:5.0)) y32 = x32 .^ 2 - itp32 = quadratic_interp(x32, y32; extrap=:extension) + itp32 = quadratic_interp(x32, y32; extrap=ExtendExtrap()) xq = 2.25f0 fd_deriv = ForwardDiff.derivative(itp32, xq) @@ -505,7 +505,7 @@ const FI = FastInterpolations # Complex quadratic: z = (1 + i)x² y_complex = (1.0 + 1.0im) .* x .^ 2 - itp = quadratic_interp(x, y_complex; extrap=:extension) + itp = quadratic_interp(x, y_complex; extrap=ExtendExtrap()) @testset "complex derivative" begin xq = 2.25 @@ -538,7 +538,7 @@ const FI = FastInterpolations x = collect(0.0:0.5:5.0) y = x .^ 3 - itp = cubic_interp(x, y; extrap=:extension) + itp = cubic_interp(x, y; extrap=ExtendExtrap()) @testset "derivative matches analytical" begin test_points = [0.25, 1.0, 2.5, 3.75, 4.5] @@ -581,7 +581,7 @@ const FI = FastInterpolations @testset "works with sine data" begin # Sin data: more realistic use case y_sin = sin.(x) - itp_sin = cubic_interp(x, y_sin; extrap=:extension) + itp_sin = cubic_interp(x, y_sin; extrap=ExtendExtrap()) xq = 1.5 @@ -603,7 +603,7 @@ const FI = FastInterpolations @testset "Float32 support" begin x32 = Float32.(collect(0.0:0.5:5.0)) y32 = x32 .^ 3 - itp32 = cubic_interp(x32, y32; extrap=:extension) + itp32 = cubic_interp(x32, y32; extrap=ExtendExtrap()) xq = 2.25f0 fd_deriv = ForwardDiff.derivative(itp32, xq) @@ -633,7 +633,7 @@ const FI = FastInterpolations @testset "different BC types" begin # Test different boundary conditions work with AD for bc in [NaturalBC(), ClampedBC()] - itp_bc = cubic_interp(x, y; bc=bc, extrap=:extension) + itp_bc = cubic_interp(x, y; bc=bc, extrap=ExtendExtrap()) xq = 2.25 fd_deriv = ForwardDiff.derivative(itp_bc, xq) @@ -657,7 +657,7 @@ const FI = FastInterpolations # Complex cubic: z = (1 + i)x³ y_complex = (1.0 + 1.0im) .* x .^ 3 - itp = cubic_interp(x, y_complex; extrap=:extension) + itp = cubic_interp(x, y_complex; extrap=ExtendExtrap()) @testset "complex derivative" begin xq = 2.25 @@ -690,7 +690,7 @@ const FI = FastInterpolations x = collect(range(0.0, 2π, 21)) y1 = sin.(x) y2 = cos.(x) - sitp = quadratic_interp(x, [y1, y2]; extrap=:extension) + sitp = quadratic_interp(x, [y1, y2]; extrap=ExtendExtrap()) @testset "derivative matches analytical (interior points)" begin # Test at interior points only (not at grid points) @@ -729,7 +729,7 @@ const FI = FastInterpolations x_quad = collect(0.0:0.5:5.0) y1_quad = x_quad .^ 2 y2_quad = 2.0 .* x_quad .^ 2 - sitp_quad = quadratic_interp(x_quad, [y1_quad, y2_quad]; extrap=:extension) + sitp_quad = quadratic_interp(x_quad, [y1_quad, y2_quad]; extrap=ExtendExtrap()) xq = 2.25 fd_derivs = ForwardDiff.derivative(sitp_quad, xq) @@ -744,7 +744,7 @@ const FI = FastInterpolations x32 = Float32.(collect(range(0.0, 2π, 21))) y1_32 = sin.(x32) y2_32 = cos.(x32) - sitp32 = quadratic_interp(x32, [y1_32, y2_32]; extrap=:extension) + sitp32 = quadratic_interp(x32, [y1_32, y2_32]; extrap=ExtendExtrap()) xq = 1.5f0 fd_derivs = ForwardDiff.derivative(sitp32, xq) @@ -779,7 +779,7 @@ const FI = FastInterpolations # Complex series y1_complex = (1.0 + 1.0im) .* sin.(x) y2_complex = (2.0 - 1.0im) .* cos.(x) - sitp = quadratic_interp(x, [y1_complex, y2_complex]; extrap=:extension) + sitp = quadratic_interp(x, [y1_complex, y2_complex]; extrap=ExtendExtrap()) @testset "complex derivative" begin xq = 1.5 @@ -808,7 +808,7 @@ const FI = FastInterpolations x = collect(range(0.0, 2π, 21)) y1 = sin.(x) y2 = cos.(x) - sitp = cubic_interp(x, [y1, y2]; extrap=:extension) + sitp = cubic_interp(x, [y1, y2]; extrap=ExtendExtrap()) @testset "derivative matches analytical (interior points)" begin # Test at interior points only (not at grid points) @@ -847,7 +847,7 @@ const FI = FastInterpolations x_cub = collect(0.0:0.5:5.0) y1_cub = x_cub .^ 3 y2_cub = 2.0 .* x_cub .^ 3 - sitp_cub = cubic_interp(x_cub, [y1_cub, y2_cub]; extrap=:extension, bc=CubicFit()) + sitp_cub = cubic_interp(x_cub, [y1_cub, y2_cub]; extrap=ExtendExtrap(), bc=CubicFit()) xq = 2.25 fd_derivs = ForwardDiff.derivative(sitp_cub, xq) @@ -862,7 +862,7 @@ const FI = FastInterpolations x32 = Float32.(collect(range(0.0, 2π, 21))) y1_32 = sin.(x32) y2_32 = cos.(x32) - sitp32 = cubic_interp(x32, [y1_32, y2_32]; extrap=:extension) + sitp32 = cubic_interp(x32, [y1_32, y2_32]; extrap=ExtendExtrap()) xq = 1.5f0 fd_derivs = ForwardDiff.derivative(sitp32, xq) @@ -897,7 +897,7 @@ const FI = FastInterpolations # Complex series y1_complex = (1.0 + 1.0im) .* sin.(x) y2_complex = (2.0 - 1.0im) .* cos.(x) - sitp = cubic_interp(x, [y1_complex, y2_complex]; extrap=:extension) + sitp = cubic_interp(x, [y1_complex, y2_complex]; extrap=ExtendExtrap()) @testset "complex derivative" begin xq = 1.5 @@ -932,8 +932,8 @@ const FI = FastInterpolations x = collect(0.0:0.5:5.0) y_quad = x .^ 2 # y = x², slope at interval [2.0,2.5] is (6.25-4)/0.5 = 4.5 - @testset "extrap=:extension" begin - itp = linear_interp(x, y_quad; extrap=:extension) + @testset "extrap=ExtendExtrap()" begin + itp = linear_interp(x, y_quad; extrap=ExtendExtrap()) # In-domain fd = ForwardDiff.derivative(itp, 2.25) @@ -946,8 +946,8 @@ const FI = FastInterpolations @test fd_out ≈ an_out atol=1e-10 end - @testset "extrap=:constant" begin - itp = linear_interp(x, y_quad; extrap=:constant) + @testset "extrap=ConstExtrap()" begin + itp = linear_interp(x, y_quad; extrap=ConstExtrap()) # In-domain fd = ForwardDiff.derivative(itp, 2.25) @@ -967,8 +967,8 @@ const FI = FastInterpolations @test fd_left ≈ an_left atol=1e-10 end - @testset "extrap=:wrap" begin - itp = linear_interp(x, y_quad; extrap=:wrap) + @testset "extrap=WrapExtrap()" begin + itp = linear_interp(x, y_quad; extrap=WrapExtrap()) # In-domain: AD must preserve Dual type fd_in = ForwardDiff.derivative(itp, 2.25) @@ -995,8 +995,8 @@ const FI = FastInterpolations x = collect(0.0:0.5:5.0) y_cubic = x .^ 3 - @testset "extrap=:extension" begin - itp = cubic_interp(x, y_cubic; extrap=:extension) + @testset "extrap=ExtendExtrap()" begin + itp = cubic_interp(x, y_cubic; extrap=ExtendExtrap()) fd = ForwardDiff.derivative(itp, 2.25) an = itp(2.25; deriv=1) @@ -1007,8 +1007,8 @@ const FI = FastInterpolations @test fd_out ≈ an_out atol=1e-10 end - @testset "extrap=:constant" begin - itp = cubic_interp(x, y_cubic; extrap=:constant) + @testset "extrap=ConstExtrap()" begin + itp = cubic_interp(x, y_cubic; extrap=ConstExtrap()) fd = ForwardDiff.derivative(itp, 2.25) an = itp(2.25; deriv=1) @@ -1026,8 +1026,8 @@ const FI = FastInterpolations @test fd_left ≈ an_left atol=1e-10 end - @testset "extrap=:wrap" begin - itp = cubic_interp(x, y_cubic; extrap=:wrap) + @testset "extrap=WrapExtrap()" begin + itp = cubic_interp(x, y_cubic; extrap=WrapExtrap()) # In-domain fd_in = ForwardDiff.derivative(itp, 2.25) @@ -1045,8 +1045,8 @@ const FI = FastInterpolations x = collect(0.0:0.5:5.0) y_quad = x .^ 2 - @testset "extrap=:extension" begin - itp = quadratic_interp(x, y_quad; extrap=:extension) + @testset "extrap=ExtendExtrap()" begin + itp = quadratic_interp(x, y_quad; extrap=ExtendExtrap()) fd = ForwardDiff.derivative(itp, 2.25) an = itp(2.25; deriv=1) @@ -1057,8 +1057,8 @@ const FI = FastInterpolations @test fd_out ≈ an_out atol=1e-10 end - @testset "extrap=:constant" begin - itp = quadratic_interp(x, y_quad; extrap=:constant) + @testset "extrap=ConstExtrap()" begin + itp = quadratic_interp(x, y_quad; extrap=ConstExtrap()) fd = ForwardDiff.derivative(itp, 2.25) an = itp(2.25; deriv=1) @@ -1076,8 +1076,8 @@ const FI = FastInterpolations @test fd_left ≈ an_left atol=1e-10 end - @testset "extrap=:wrap" begin - itp = quadratic_interp(x, y_quad; extrap=:wrap) + @testset "extrap=WrapExtrap()" begin + itp = quadratic_interp(x, y_quad; extrap=WrapExtrap()) # In-domain fd_in = ForwardDiff.derivative(itp, 2.25) @@ -1098,7 +1098,7 @@ const FI = FastInterpolations x = collect(0.0:1.0:10.0) y = 2.0 .* x .+ 1.0 # y = 2x + 1 - for ext in [:extension, :constant, :wrap] + for ext in (ExtendExtrap(), ConstExtrap(), WrapExtrap()) itp = linear_interp(x, y; extrap=ext) # In-domain value test @@ -1120,7 +1120,7 @@ const FI = FastInterpolations y = collect(range(0.0, 1.0, 6)) data = [xi + 2yi for xi in x, yi in y] # f(x,y) = x + 2y - itp = linear_interp((x, y), data; extrap=:extension) + itp = linear_interp((x, y), data; extrap=ExtendExtrap()) @testset "partial derivative via heterogeneous tuple" begin # (Dual, Float64) tuple — requires Tuple{Vararg{Real,N}} not NTuple{N,<:Real} @@ -1147,7 +1147,7 @@ const FI = FastInterpolations y = collect(range(0.0, 1.0, 6)) data = [xi + 2yi for xi in x, yi in y] - itp = constant_interp((x, y), data; extrap=:extension) + itp = constant_interp((x, y), data; extrap=ExtendExtrap()) @testset "partial derivative via heterogeneous tuple" begin # Constant interpolation derivative is 0 (step function) diff --git a/test/test_autodiff_Zygote.jl b/test/test_autodiff_Zygote.jl index 63fe3e77..35923407 100644 --- a/test/test_autodiff_Zygote.jl +++ b/test/test_autodiff_Zygote.jl @@ -42,7 +42,7 @@ end y_complex = (2.0 + 1.0im) .* x .+ (1.0 - 1.0im) @testset "Single Interpolant - Real" begin - itp = linear_interp(x, y_linear; extrap=:extension) + itp = linear_interp(x, y_linear; extrap=ExtendExtrap()) @testset "gradient matches ForwardDiff" begin for xq in [0.25, 1.0, 2.5, 3.75, 4.5] @@ -72,7 +72,7 @@ end @testset "Single Interpolant - Complex via real/imag" begin # Zygote doesn't support complex output directly # Must use real() or imag() for scalar output - itp = linear_interp(x, y_complex; extrap=:extension) + itp = linear_interp(x, y_complex; extrap=ExtendExtrap()) @testset "complex gradient via real/imag" begin xq = 2.25 @@ -93,7 +93,7 @@ end end @testset "Vector input gradient (broadcast)" begin - itp = linear_interp(x, y_sin; extrap=:extension) + itp = linear_interp(x, y_sin; extrap=ExtendExtrap()) xqv = [0.3, 0.8, 1.2] g(v) = sum(itp.(v)) @@ -124,7 +124,7 @@ end @testset "Series Interpolant (broken - array mutation)" begin y1 = sin.(x) y2 = cos.(x) - sitp = linear_interp(x, [y1, y2]; extrap=:extension) + sitp = linear_interp(x, [y1, y2]; extrap=ExtendExtrap()) @test_broken begin f(xq) = sum(sitp(xq)) @@ -144,7 +144,7 @@ end @testset "Single Interpolant - gradient is nothing (not 0)" begin # Zygote returns `nothing` for constant functions, not 0 - itp = constant_interp(x, y; side=:left, extrap=:extension) + itp = constant_interp(x, y; side=:left, extrap=ExtendExtrap()) for xq in [0.5, 1.5, 2.5, 3.5] zy_grad = Zygote.gradient(itp, xq)[1] @@ -155,7 +155,7 @@ end @testset "All side modes" begin for side_mode in [:left, :right, :nearest] - itp = constant_interp(x, y; side=side_mode, extrap=:extension) + itp = constant_interp(x, y; side=side_mode, extrap=ExtendExtrap()) zy_grad = Zygote.gradient(itp, 2.5)[1] @test (zy_grad === nothing) || isapprox(zy_grad, 0.0; atol=1e-10) end @@ -172,7 +172,7 @@ end y_complex = (1.0 + 1.0im) .* x .^ 2 @testset "Single Interpolant - Real" begin - itp = quadratic_interp(x, y_quad; extrap=:extension) + itp = quadratic_interp(x, y_quad; extrap=ExtendExtrap()) @testset "gradient matches ForwardDiff" begin for xq in [0.25, 1.0, 2.5, 3.75, 4.5] @@ -193,7 +193,7 @@ end end @testset "Single Interpolant - Complex via real/imag" begin - itp = quadratic_interp(x, y_complex; extrap=:extension) + itp = quadratic_interp(x, y_complex; extrap=ExtendExtrap()) xq = 2.25 zy_real = Zygote.gradient(q -> real(itp(q)), xq)[1] @@ -217,7 +217,7 @@ end @testset "Series Interpolant (broken - array mutation)" begin y1 = x .^ 2 y2 = 2.0 .* x .^ 2 - sitp = quadratic_interp(x, [y1, y2]; extrap=:extension) + sitp = quadratic_interp(x, [y1, y2]; extrap=ExtendExtrap()) @test_broken begin f(xq) = sum(sitp(xq)) @@ -238,7 +238,7 @@ end y_complex = (1.0 + 1.0im) .* x .^ 3 @testset "Single Interpolant - Real" begin - itp = cubic_interp(x, y_cubic; extrap=:extension) + itp = cubic_interp(x, y_cubic; extrap=ExtendExtrap()) @testset "gradient matches ForwardDiff" begin for xq in [0.25, 1.0, 2.5, 3.75, 4.5] @@ -259,14 +259,14 @@ end end @testset "Single Interpolant - Sine data" begin - itp = cubic_interp(x, y_sin; extrap=:extension) + itp = cubic_interp(x, y_sin; extrap=ExtendExtrap()) xq = 1.5 zy_grad = Zygote.gradient(itp, xq)[1] @test zy_grad ≈ cos(1.5) rtol=0.01 # d/dx(sin(x)) = cos(x) end @testset "Single Interpolant - Complex via real/imag" begin - itp = cubic_interp(x, y_complex; extrap=:extension) + itp = cubic_interp(x, y_complex; extrap=ExtendExtrap()) xq = 2.25 zy_real = Zygote.gradient(q -> real(itp(q)), xq)[1] @@ -282,7 +282,7 @@ end @testset "Different BC types" begin for bc in [NaturalBC(), ClampedBC()] - itp = cubic_interp(x, y_cubic; bc=bc, extrap=:extension) + itp = cubic_interp(x, y_cubic; bc=bc, extrap=ExtendExtrap()) xq = 2.25 zy_grad = Zygote.gradient(itp, xq)[1] fd_grad = ForwardDiff.derivative(itp, xq) @@ -301,7 +301,7 @@ end @testset "Series Interpolant (broken - array mutation)" begin y1 = sin.(x) y2 = cos.(x) - sitp = cubic_interp(x, [y1, y2]; extrap=:extension) + sitp = cubic_interp(x, [y1, y2]; extrap=ExtendExtrap()) @test_broken begin f(xq) = sum(sitp(xq)) @@ -320,7 +320,7 @@ end y = x .^ 2 @testset "Loss function gradient" begin - itp = linear_interp(x, y; extrap=:extension) + itp = linear_interp(x, y; extrap=ExtendExtrap()) function loss(params) xq = params[1] @@ -341,7 +341,7 @@ end end @testset "Vector input gradient" begin - itp = linear_interp(x, y; extrap=:extension) + itp = linear_interp(x, y; extrap=ExtendExtrap()) xqv = [0.3, 0.8, 1.2] g(v) = sum(itp.(v)) @@ -361,7 +361,7 @@ end y32 = 2.0f0 .* x32 .+ 1.0f0 @testset "Linear Float32" begin - itp = linear_interp(x32, y32; extrap=:extension) + itp = linear_interp(x32, y32; extrap=ExtendExtrap()) xq = 2.25f0 zy_grad = Zygote.gradient(itp, xq)[1] @test zy_grad ≈ 2.0f0 atol=1e-5 @@ -370,7 +370,7 @@ end @testset "Quadratic Float32" begin y32_quad = x32 .^ 2 - itp = quadratic_interp(x32, y32_quad; extrap=:extension) + itp = quadratic_interp(x32, y32_quad; extrap=ExtendExtrap()) xq = 2.25f0 zy_grad = Zygote.gradient(itp, xq)[1] @test zy_grad ≈ 2.0f0 * xq atol=1e-4 @@ -379,7 +379,7 @@ end @testset "Cubic Float32" begin y32_cubic = x32 .^ 3 - itp = cubic_interp(x32, y32_cubic; extrap=:extension) + itp = cubic_interp(x32, y32_cubic; extrap=ExtendExtrap()) xq = 2.25f0 zy_grad = Zygote.gradient(itp, xq)[1] expected = 3.0f0 * xq^2 diff --git a/test/test_complex_constant.jl b/test/test_complex_constant.jl index ef984012..6fa06d05 100644 --- a/test/test_complex_constant.jl +++ b/test/test_complex_constant.jl @@ -134,17 +134,17 @@ using FastInterpolations y = [1.0+1.0im, 2.0+2.0im, 3.0+3.0im, 4.0+4.0im] # :constant mode - itp_const = constant_interp(x, y; extrap=:constant) + itp_const = constant_interp(x, y; extrap=ConstExtrap()) @test itp_const(-1.0) == 1.0+1.0im # Clamped to first @test itp_const(5.0) == 4.0+4.0im # Clamped to last # :extension mode (same as constant for step functions) - itp_ext = constant_interp(x, y; extrap=:extension) + itp_ext = constant_interp(x, y; extrap=ExtendExtrap()) @test itp_ext(-1.0) == 1.0+1.0im @test itp_ext(5.0) == 4.0+4.0im # :wrap mode - itp_wrap = constant_interp(x, y; extrap=:wrap) + itp_wrap = constant_interp(x, y; extrap=WrapExtrap()) val_wrap = itp_wrap(4.5) @test val_wrap isa ComplexF64 end diff --git a/test/test_complex_constant_series.jl b/test/test_complex_constant_series.jl index 8cd2932c..b23c7420 100644 --- a/test/test_complex_constant_series.jl +++ b/test/test_complex_constant_series.jl @@ -183,12 +183,12 @@ using FastInterpolations y2 = (2.0 - 1.0im) .* collect(x) # Extension mode - sitp_ext = constant_interp(x, [y1, y2]; extrap=:extension) + sitp_ext = constant_interp(x, [y1, y2]; extrap=ExtendExtrap()) vals_ext = sitp_ext(1.5) # Beyond domain @test vals_ext isa Vector{ComplexF64} # Constant mode - sitp_const = constant_interp(x, [y1, y2]; extrap=:constant) + sitp_const = constant_interp(x, [y1, y2]; extrap=ConstExtrap()) vals_const = sitp_const(1.5) # Beyond domain @test vals_const isa Vector{ComplexF64} @test isapprox(vals_const[1], y1[end], rtol=1e-10) diff --git a/test/test_complex_cubic.jl b/test/test_complex_cubic.jl index 2a2a3315..9b057907 100644 --- a/test/test_complex_cubic.jl +++ b/test/test_complex_cubic.jl @@ -152,13 +152,13 @@ using FastInterpolations x = [0.0, 1.0, 2.0, 3.0, 4.0] y = [1.0+2.0im, 3.0+4.0im, 5.0+6.0im, 7.0+8.0im, 9.0+10.0im] - # :constant extrapolation - itp_const = cubic_interp(x, y; extrap=:constant) + # ConstExtrap() extrapolation + itp_const = cubic_interp(x, y; extrap=ConstExtrap()) @test itp_const(-0.5) == y[1] @test itp_const(4.5) == y[end] - # :extension extrapolation - itp_ext = cubic_interp(x, y; extrap=:extension) + # ExtendExtrap() extrapolation + itp_ext = cubic_interp(x, y; extrap=ExtendExtrap()) @test itp_ext(-0.5) isa ComplexF64 @test itp_ext(4.5) isa ComplexF64 end diff --git a/test/test_complex_cubic_series.jl b/test/test_complex_cubic_series.jl index 687e40eb..6b7d59fb 100644 --- a/test/test_complex_cubic_series.jl +++ b/test/test_complex_cubic_series.jl @@ -180,14 +180,14 @@ using FastInterpolations y2 = (2.0 - 1.0im) .* collect(x) # Extension mode - sitp_ext = cubic_interp(x, [y1, y2]; extrap=:extension) + sitp_ext = cubic_interp(x, [y1, y2]; extrap=ExtendExtrap()) vals_ext = sitp_ext(1.5) # Beyond domain @test vals_ext isa Vector{ComplexF64} # Linear function extended by cubic spline @test isapprox(vals_ext[1], (1.0 + 2.0im) * 1.5, rtol=1e-10) # Constant mode - sitp_const = cubic_interp(x, [y1, y2]; extrap=:constant) + sitp_const = cubic_interp(x, [y1, y2]; extrap=ConstExtrap()) vals_const = sitp_const(1.5) # Beyond domain @test vals_const isa Vector{ComplexF64} @test isapprox(vals_const[1], y1[end], rtol=1e-10) diff --git a/test/test_complex_linear.jl b/test/test_complex_linear.jl index 8539f245..15354ca3 100644 --- a/test/test_complex_linear.jl +++ b/test/test_complex_linear.jl @@ -146,19 +146,19 @@ using FastInterpolations y = (1.0 + 2.0im) .* x # Extension mode - itp_ext = linear_interp(x, y; extrap=:extension) + itp_ext = linear_interp(x, y; extrap=ExtendExtrap()) val_ext = itp_ext(1.5) # Beyond domain @test val_ext isa ComplexF64 @test isapprox(val_ext, (1.0 + 2.0im) * 1.5, rtol=1e-10) # Constant mode - itp_const = linear_interp(x, y; extrap=:constant) + itp_const = linear_interp(x, y; extrap=ConstExtrap()) val_const = itp_const(1.5) # Beyond domain @test val_const isa ComplexF64 @test isapprox(val_const, y[end], rtol=1e-10) # Wrap mode - itp_wrap = linear_interp(x, y; extrap=:wrap) + itp_wrap = linear_interp(x, y; extrap=WrapExtrap()) val_wrap = itp_wrap(1.5) # Should wrap to 0.5 @test val_wrap isa ComplexF64 end diff --git a/test/test_complex_linear_series.jl b/test/test_complex_linear_series.jl index a85bf4f6..d9f646ab 100644 --- a/test/test_complex_linear_series.jl +++ b/test/test_complex_linear_series.jl @@ -181,13 +181,13 @@ using FastInterpolations y2 = (2.0 - 1.0im) .* collect(x) # Extension mode - sitp_ext = linear_interp(x, [y1, y2]; extrap=:extension) + sitp_ext = linear_interp(x, [y1, y2]; extrap=ExtendExtrap()) vals_ext = sitp_ext(1.5) # Beyond domain @test vals_ext isa Vector{ComplexF64} @test isapprox(vals_ext[1], (1.0 + 2.0im) * 1.5, rtol=1e-10) # Constant mode - sitp_const = linear_interp(x, [y1, y2]; extrap=:constant) + sitp_const = linear_interp(x, [y1, y2]; extrap=ConstExtrap()) vals_const = sitp_const(1.5) # Beyond domain @test vals_const isa Vector{ComplexF64} @test isapprox(vals_const[1], y1[end], rtol=1e-10) diff --git a/test/test_complex_quadratic.jl b/test/test_complex_quadratic.jl index af99ac1f..b603f500 100644 --- a/test/test_complex_quadratic.jl +++ b/test/test_complex_quadratic.jl @@ -158,12 +158,12 @@ using FastInterpolations y = [1.0+1.0im, 2.0+2.0im, 3.0+3.0im, 4.0+4.0im] # :constant mode - itp_const = quadratic_interp(x, y; extrap=:constant) + itp_const = quadratic_interp(x, y; extrap=ConstExtrap()) @test itp_const(-1.0) == 1.0+1.0im # Clamped to first @test itp_const(5.0) == 4.0+4.0im # Clamped to last # :extension mode - itp_ext = quadratic_interp(x, y; extrap=:extension) + itp_ext = quadratic_interp(x, y; extrap=ExtendExtrap()) val_ext = itp_ext(-1.0) @test val_ext isa ComplexF64 end diff --git a/test/test_complex_quadratic_series.jl b/test/test_complex_quadratic_series.jl index b3c28506..47f13e11 100644 --- a/test/test_complex_quadratic_series.jl +++ b/test/test_complex_quadratic_series.jl @@ -178,14 +178,14 @@ using FastInterpolations y2 = (2.0 - 1.0im) .* collect(x) # Extension mode - sitp_ext = quadratic_interp(x, [y1, y2]; extrap=:extension) + sitp_ext = quadratic_interp(x, [y1, y2]; extrap=ExtendExtrap()) vals_ext = sitp_ext(1.5) # Beyond domain @test vals_ext isa Vector{ComplexF64} # Linear function extended quadratically @test isapprox(vals_ext[1], (1.0 + 2.0im) * 1.5, rtol=1e-10) # Constant mode - sitp_const = quadratic_interp(x, [y1, y2]; extrap=:constant) + sitp_const = quadratic_interp(x, [y1, y2]; extrap=ConstExtrap()) vals_const = sitp_const(1.5) # Beyond domain @test vals_const isa Vector{ComplexF64} @test isapprox(vals_const[1], y1[end], rtol=1e-10) diff --git a/test/test_constant.jl b/test/test_constant.jl index 4fce17e4..f848a003 100644 --- a/test/test_constant.jl +++ b/test/test_constant.jl @@ -200,19 +200,19 @@ end end @testset "Extrapolation modes" begin - @test_throws DomainError constant_interp(x, y, -1.0; extrap=:none) - @test_throws DomainError constant_interp(x, y, 5.0; extrap=:none) + @test_throws DomainError constant_interp(x, y, -1.0; extrap=NoExtrap()) + @test_throws DomainError constant_interp(x, y, 5.0; extrap=NoExtrap()) - @test constant_interp(x, y, -1.0; extrap=:constant) == 10.0 - @test constant_interp(x, y, 5.0; extrap=:constant) == 50.0 + @test constant_interp(x, y, -1.0; extrap=ConstExtrap()) == 10.0 + @test constant_interp(x, y, 5.0; extrap=ConstExtrap()) == 50.0 - @test constant_interp(x, y, -1.0; extrap=:extension) == 10.0 - @test constant_interp(x, y, 5.0; extrap=:extension) == 50.0 + @test constant_interp(x, y, -1.0; extrap=ExtendExtrap()) == 10.0 + @test constant_interp(x, y, 5.0; extrap=ExtendExtrap()) == 50.0 - @test constant_interp(x, y, 4.0; extrap=:wrap) == 10.0 - @test constant_interp(x, y, 4.5; extrap=:wrap) == 10.0 + @test constant_interp(x, y, 4.0; extrap=WrapExtrap()) == 10.0 + @test constant_interp(x, y, 4.5; extrap=WrapExtrap()) == 10.0 - @test constant_interp(x, y, -1.0; extrap=:constant, deriv=1) == 0.0 + @test constant_interp(x, y, -1.0; extrap=ConstExtrap(), deriv=1) == 0.0 end @testset "Real type wrapper (Integer input)" begin @@ -264,18 +264,18 @@ end # Test options pass through the wrappers correctly @test constant_interp(x_int, y_int, 0; side=:right) == 10.0 @test constant_interp(x_int, y_int, 0; side=:left) == 10.0 - @test constant_interp(x_int, y_int, -1; extrap=:constant) == 10.0 - @test constant_interp(x_int, y_int, 5; extrap=:constant) == 50.0 + @test constant_interp(x_int, y_int, -1; extrap=ConstExtrap()) == 10.0 + @test constant_interp(x_int, y_int, 5; extrap=ConstExtrap()) == 50.0 # Test in-place wrapper with options out3 = zeros(2) - constant_interp!(out3, x_int, y_int, [-1, 5]; extrap=:constant) + constant_interp!(out3, x_int, y_int, [-1, 5]; extrap=ConstExtrap()) @test out3 ≈ [10.0, 50.0] # Test 2-arg callable with options itp_left = constant_interp(x_int, y_int; side=:left) @test itp_left(0.9) == 10.0 - itp_wrap = constant_interp(x_int, y_int; extrap=:wrap) + itp_wrap = constant_interp(x_int, y_int; extrap=WrapExtrap()) @test itp_wrap(4.0) == 10.0 end @@ -311,10 +311,10 @@ end end @testset "ConstantInterpolant - Options" begin - itp_wrap = constant_interp(x, y; extrap=:wrap) + itp_wrap = constant_interp(x, y; extrap=WrapExtrap()) @test itp_wrap(4.0) == 10.0 - itp_const = constant_interp(x, y; extrap=:constant) + itp_const = constant_interp(x, y; extrap=ConstExtrap()) @test itp_const(-1.0) == 10.0 @test itp_const(5.0) == 50.0 @@ -330,7 +330,7 @@ end @test @inferred(itp(0.5)) isa Float64 @test @inferred(constant_interp(x, y, 0.5)) isa Float64 @test @inferred(constant_interp(x, y, 0.5; side=:left)) isa Float64 - @test @inferred(constant_interp(x, y, 0.5; extrap=:constant)) isa Float64 + @test @inferred(constant_interp(x, y, 0.5; extrap=ConstExtrap())) isa Float64 @test @inferred(constant_interp(x, y, 0.5; deriv=1)) isa Float64 end @@ -400,8 +400,8 @@ end @test allocs <= ALLOC_THRESHOLD end - @testset "ConstantInterpolant with extrap=:wrap in-place" begin - itp = constant_interp(x, y; extrap=:wrap) + @testset "ConstantInterpolant with extrap=WrapExtrap() in-place" begin + itp = constant_interp(x, y; extrap=WrapExtrap()) out = zeros(5) xq = [0.1, 0.3, 0.5, 0.7, 0.9] itp(out, xq) @@ -504,12 +504,12 @@ end end @testset "DerivativeView - with options" begin - itp_const = constant_interp(x, y; extrap=:constant) + itp_const = constant_interp(x, y; extrap=ConstExtrap()) d1 = deriv1(itp_const) @test d1(-1.0) == 0.0 @test d1(5.0) == 0.0 - itp_wrap = constant_interp(x, y; extrap=:wrap) + itp_wrap = constant_interp(x, y; extrap=WrapExtrap()) d2 = deriv2(itp_wrap) @test d2(4.5) == 0.0 @@ -531,26 +531,26 @@ end end @testset "Edge: xi == x[end] with extrap modes" begin - @test constant_interp(x, y, 4.0; extrap=:none) == 50.0 - @test constant_interp(x, y, 4.0; extrap=:constant) == 50.0 - @test constant_interp(x, y, 4.0; extrap=:extension) == 50.0 - @test constant_interp(x, y, 4.0; extrap=:wrap) == 10.0 + @test constant_interp(x, y, 4.0; extrap=NoExtrap()) == 50.0 + @test constant_interp(x, y, 4.0; extrap=ConstExtrap()) == 50.0 + @test constant_interp(x, y, 4.0; extrap=ExtendExtrap()) == 50.0 + @test constant_interp(x, y, 4.0; extrap=WrapExtrap()) == 10.0 end @testset "Edge: Wrap boundary cases" begin - @test constant_interp(x, y, 4.0; extrap=:wrap, side=:left) == 10.0 - @test constant_interp(x, y, 4.0; extrap=:wrap, side=:right) == 10.0 - @test constant_interp(x, y, 4.0; extrap=:wrap, side=:nearest) == 10.0 - @test constant_interp(x, y, 4.5; extrap=:wrap, side=:nearest) == 10.0 - @test constant_interp(x, y, 5.0; extrap=:wrap, side=:nearest) == 20.0 + @test constant_interp(x, y, 4.0; extrap=WrapExtrap(), side=:left) == 10.0 + @test constant_interp(x, y, 4.0; extrap=WrapExtrap(), side=:right) == 10.0 + @test constant_interp(x, y, 4.0; extrap=WrapExtrap(), side=:nearest) == 10.0 + @test constant_interp(x, y, 4.5; extrap=WrapExtrap(), side=:nearest) == 10.0 + @test constant_interp(x, y, 5.0; extrap=WrapExtrap(), side=:nearest) == 20.0 end @testset "Edge: Extrapolation + deriv" begin - @test constant_interp(x, y, -1.0; extrap=:constant, deriv=1) == 0.0 - @test constant_interp(x, y, 5.0; extrap=:constant, deriv=2) == 0.0 - @test constant_interp(x, y, -1.0; extrap=:extension, deriv=1) == 0.0 - @test constant_interp(x, y, 5.0; extrap=:extension, deriv=2) == 0.0 - @test constant_interp(x, y, 4.5; extrap=:wrap, deriv=1) == 0.0 + @test constant_interp(x, y, -1.0; extrap=ConstExtrap(), deriv=1) == 0.0 + @test constant_interp(x, y, 5.0; extrap=ConstExtrap(), deriv=2) == 0.0 + @test constant_interp(x, y, -1.0; extrap=ExtendExtrap(), deriv=1) == 0.0 + @test constant_interp(x, y, 5.0; extrap=ExtendExtrap(), deriv=2) == 0.0 + @test constant_interp(x, y, 4.5; extrap=WrapExtrap(), deriv=1) == 0.0 end @testset "Edge: Midpoint tie-breaking" begin diff --git a/test/test_constant_anchor.jl b/test/test_constant_anchor.jl index 6f59254c..0a3a840d 100644 --- a/test/test_constant_anchor.jl +++ b/test/test_constant_anchor.jl @@ -79,7 +79,7 @@ using FastInterpolations @testset "itp(aq) for :nearest mode" begin x = collect(range(0.0, 1.0, 11)) y = collect(1.0:11.0) - itp = constant_interp(x, y; side=:nearest, extrap=:extension) + itp = constant_interp(x, y; side=:nearest, extrap=ExtendExtrap()) xq_points = [0.05, 0.15, 0.35, 0.65, 0.95] @@ -95,7 +95,7 @@ using FastInterpolations @testset "itp(aq) for :left mode" begin x = collect(range(0.0, 1.0, 11)) y = collect(1.0:11.0) - itp = constant_interp(x, y; side=:left, extrap=:extension) + itp = constant_interp(x, y; side=:left, extrap=ExtendExtrap()) xq_points = [0.05, 0.15, 0.35, 0.65, 0.95] @@ -111,7 +111,7 @@ using FastInterpolations @testset "itp(aq) for :right mode" begin x = collect(range(0.0, 1.0, 11)) y = collect(1.0:11.0) - itp = constant_interp(x, y; side=:right, extrap=:extension) + itp = constant_interp(x, y; side=:right, extrap=ExtendExtrap()) xq_points = [0.05, 0.15, 0.35, 0.65, 0.95] @@ -141,8 +141,8 @@ using FastInterpolations # Verify extrapolation works with anchors y = collect(1.0:11.0) - itp_ext = constant_interp(x, y; extrap=:extension) - itp_const = constant_interp(x, y; extrap=:constant) + itp_ext = constant_interp(x, y; extrap=ExtendExtrap()) + itp_const = constant_interp(x, y; extrap=ConstExtrap()) @test itp_ext(aq_below) ≈ itp_ext(-0.5) @test itp_ext(aq_above) ≈ itp_ext(1.5) @@ -156,7 +156,7 @@ using FastInterpolations @testset "wrap mode" begin x = collect(range(0.0, 1.0, 11)) y = collect(1.0:11.0) - itp = constant_interp(x, y; extrap=:wrap) + itp = constant_interp(x, y; extrap=WrapExtrap()) # Query outside domain with wrap=true aq_wrap = FastInterpolations._anchor_query(x, 1.5, Val(:constant); wrap=true) @@ -199,7 +199,7 @@ using FastInterpolations @testset "in-place vector evaluation with anchors" begin x = collect(range(0.0, 1.0, 11)) y = collect(1.0:11.0) - itp = constant_interp(x, y; extrap=:extension) + itp = constant_interp(x, y; extrap=ExtendExtrap()) xq_vec = [0.05, 0.15, 0.35, 0.65, 0.95] aq_vec = FastInterpolations._anchor_query(x, xq_vec, Val(:constant)) @@ -222,7 +222,7 @@ using FastInterpolations # Non-uniform grid x = [0.0, 0.1, 0.3, 0.6, 1.0] y = [10.0, 20.0, 30.0, 40.0, 50.0] - itp = constant_interp(x, y; extrap=:extension) + itp = constant_interp(x, y; extrap=ExtendExtrap()) xq = 0.45 # interval [0.3, 0.6] aq = FastInterpolations._anchor_query(x, xq, Val(:constant)) @@ -242,7 +242,7 @@ using FastInterpolations @testset "zero-allocation with pre-built anchors" begin x = collect(range(0.0, 1.0, 101)) y = sin.(x) - itp = constant_interp(x, y; extrap=:extension) + itp = constant_interp(x, y; extrap=ExtendExtrap()) xq_vec = collect(range(0.01, 0.99, 100)) aq_vec = FastInterpolations._anchor_query(x, xq_vec, Val(:constant)) @@ -257,12 +257,12 @@ using FastInterpolations end # ======================================== - # extrap=:none DomainError Tests + # extrap=NoExtrap() DomainError Tests # ======================================== - @testset "extrap=:none throws DomainError via anchor" begin + @testset "extrap=NoExtrap() throws DomainError via anchor" begin x = collect(range(0.0, 1.0, 11)) y = collect(1.0:11.0) - itp = constant_interp(x, y; extrap=:none) + itp = constant_interp(x, y; extrap=NoExtrap()) # Inside domain works aq_inside = FastInterpolations._anchor_query(x, 0.5, Val(:constant)) @@ -281,12 +281,12 @@ using FastInterpolations end # ======================================== - # extrap=:constant Tests + # extrap=ConstExtrap() Tests # ======================================== - @testset "extrap=:constant via anchor with boundary check" begin + @testset "extrap=ConstExtrap() via anchor with boundary check" begin x = collect(range(0.0, 1.0, 11)) y = collect(1.0:11.0) - itp = constant_interp(x, y; extrap=:constant) + itp = constant_interp(x, y; extrap=ConstExtrap()) # At exact right boundary aq_right = FastInterpolations._anchor_query(x, 1.0, Val(:constant)) @@ -308,7 +308,7 @@ using FastInterpolations x = collect(range(0.0, 1.0, 11)) y = collect(1.0:11.0) - for extrap in [:extension, :constant] + for extrap in [ExtendExtrap(), ConstExtrap()] itp = constant_interp(x, y; extrap=extrap) xq_vec = [-0.2, 0.3, 0.7, 1.2] # Mix of inside/outside aq_vec = FastInterpolations._anchor_query(x, xq_vec, Val(:constant)) @@ -325,7 +325,7 @@ using FastInterpolations @testset "in-place output length assertion" begin x = collect(range(0.0, 1.0, 11)) y = collect(1.0:11.0) - itp = constant_interp(x, y; extrap=:extension) + itp = constant_interp(x, y; extrap=ExtendExtrap()) xq_vec = [0.2, 0.5, 0.8] aq_vec = FastInterpolations._anchor_query(x, xq_vec, Val(:constant)) @@ -343,7 +343,7 @@ using FastInterpolations y = collect(1.0:11.0) # Test all modes at exact boundary - for mode in [:extension, :constant] + for mode in [ExtendExtrap(), ConstExtrap()] itp = constant_interp(x, y; extrap=mode) aq = FastInterpolations._anchor_query(x, 1.0, Val(:constant)) @test itp(aq) ≈ y[end] diff --git a/test/test_constant_series_interp.jl b/test/test_constant_series_interp.jl index 7ea0e560..c302bbcd 100644 --- a/test/test_constant_series_interp.jl +++ b/test/test_constant_series_interp.jl @@ -143,20 +143,20 @@ const FI = FastInterpolations x = collect(0.0:0.1:1.0) ys = [sin.(2π .* x)] - @testset "extrap=:none throws" begin - sitp = constant_interp(x, ys; extrap=:none) + @testset "extrap=NoExtrap() throws" begin + sitp = constant_interp(x, ys; extrap=NoExtrap()) @test_throws DomainError sitp(-0.1) @test_throws DomainError sitp(1.1) end - @testset "extrap=:constant returns boundary" begin - sitp = constant_interp(x, ys; extrap=:constant) + @testset "extrap=ConstExtrap() returns boundary" begin + sitp = constant_interp(x, ys; extrap=ConstExtrap()) @test sitp(-0.1)[1] ≈ sin(0.0) atol=1e-6 @test sitp(1.1)[1] ≈ sin(2π) atol=1e-6 end - @testset "extrap=:extension extrapolates" begin - sitp = constant_interp(x, ys; extrap=:extension) + @testset "extrap=ExtendExtrap() extrapolates" begin + sitp = constant_interp(x, ys; extrap=ExtendExtrap()) @test sitp(-0.1) isa Vector{Float64} @test sitp(1.1) isa Vector{Float64} end @@ -331,7 +331,7 @@ const FI = FastInterpolations @testset "derivative with extrapolation" begin x = [0.0, 1.0, 2.0] ys = [[1.0, 2.0, 3.0]] - sitp = constant_interp(x, ys; extrap=:constant) + sitp = constant_interp(x, ys; extrap=ConstExtrap()) @testset "outside boundaries derivative is zero" begin @test sitp(-0.5; deriv=1) == [0.0] @@ -453,15 +453,15 @@ const FI = FastInterpolations y1 = sin.(2π .* x) y2 = cos.(2π .* x) - @testset "vector :none extrapolation throws" begin - sitp = constant_interp(x, [y1, y2]; extrap=:none) + @testset "vector NoExtrap() extrapolation throws" begin + sitp = constant_interp(x, [y1, y2]; extrap=NoExtrap()) xq = [-0.1, 0.5, 1.1] @test_throws DomainError sitp(xq) end - @testset "vector :constant extrapolation" begin - sitp = constant_interp(x, [y1, y2]; extrap=:constant) + @testset "vector ConstExtrap() extrapolation" begin + sitp = constant_interp(x, [y1, y2]; extrap=ConstExtrap()) xq = [-0.1, 0.5, 1.1] outputs = [zeros(3), zeros(3)] @@ -472,8 +472,8 @@ const FI = FastInterpolations @test outputs[1][3] ≈ y1[end] atol=1e-10 end - @testset "vector :extension extrapolation" begin - sitp = constant_interp(x, [y1, y2]; extrap=:extension) + @testset "vector ExtendExtrap() extrapolation" begin + sitp = constant_interp(x, [y1, y2]; extrap=ExtendExtrap()) xq = [-0.1, 0.5, 1.1] outputs = [zeros(3), zeros(3)] @@ -483,8 +483,8 @@ const FI = FastInterpolations @test !any(isnan, outputs[2]) end - @testset "vector :constant extrapolation with derivatives" begin - sitp = constant_interp(x, [y1, y2]; extrap=:constant) + @testset "vector ConstExtrap() extrapolation with derivatives" begin + sitp = constant_interp(x, [y1, y2]; extrap=ConstExtrap()) xq = [-0.1, 0.5, 1.1] # deriv=1 outside domain should be zero for constant extrap diff --git a/test/test_cubic.jl b/test/test_cubic.jl index 45d07068..bcf10f44 100644 --- a/test/test_cubic.jl +++ b/test/test_cubic.jl @@ -79,7 +79,7 @@ x_query_small = [-0.5, 0.25, 0.75, 1.5] cache_small = CubicSplineCache(x_small) - result = cubic_interp(cache_small, y_small, x_query_small; extrap=:extension) + result = cubic_interp(cache_small, y_small, x_query_small; extrap=ExtendExtrap()) @test all(isfinite, result) # Query at grid points (should return close to exact values) @@ -100,13 +100,13 @@ x = collect(range(0.0, 1.0, 11)) y = sin.(2π .* x) - # Default extrapolation is :none, should throw DomainError + # Default extrapolation is NoExtrap(), should throw DomainError @test_throws DomainError cubic_interp(x, y, -0.1) @test_throws DomainError cubic_interp(x, y, 1.1) # Explicit :none also throws - @test_throws DomainError cubic_interp(x, y, -0.5; extrap=:none) - @test_throws DomainError cubic_interp(x, y, 1.5; extrap=:none) + @test_throws DomainError cubic_interp(x, y, -0.5; extrap=NoExtrap()) + @test_throws DomainError cubic_interp(x, y, 1.5; extrap=NoExtrap()) # Vector query - first out-of-domain point throws @test_throws DomainError cubic_interp(x, y, [-0.1, 0.5]) @@ -140,53 +140,31 @@ @test cubic_interp(x, y, 1.0) ≈ y[end] end - @testset "Invalid extrap symbol - ArgumentError" begin - x = collect(range(0.0, 1.0, 11)) - y = sin.(2π .* x) - - # Invalid extrap symbol should throw ArgumentError - @test_throws ArgumentError cubic_interp(x, y, 0.5; extrap=:invalid) - @test_throws ArgumentError cubic_interp(x, y, 0.5; extrap=:foo) - @test_throws ArgumentError cubic_interp(x, y, [0.5]; extrap=:invalid) - - # With cache - cache = CubicSplineCache(x) - @test_throws ArgumentError cubic_interp(cache, y, 0.5; extrap=:invalid) - @test_throws ArgumentError cubic_interp(cache, y, [0.5]; extrap=:invalid) - - # In-place version - output = zeros(1) - @test_throws ArgumentError cubic_interp!(output, x, y, [0.5]; extrap=:invalid) - @test_throws ArgumentError cubic_interp!(output, cache, y, [0.5]; extrap=:invalid) - - # Interpolant via cubic_interp(x, y) - @test_throws ArgumentError cubic_interp(x, y; extrap=:invalid) - end @testset "Extrapolation :constant" begin x = collect(range(0.0, 1.0, 11)) y = sin.(2π .* x) # Left boundary - returns y[1] - result_left = cubic_interp(x, y, -0.5; extrap=:constant) + result_left = cubic_interp(x, y, -0.5; extrap=ConstExtrap()) @test result_left ≈ y[1] # Right boundary - returns y[end] - result_right = cubic_interp(x, y, 1.5; extrap=:constant) + result_right = cubic_interp(x, y, 1.5; extrap=ConstExtrap()) @test result_right ≈ y[end] # Vector query - result = cubic_interp(x, y, [-0.5, 0.5, 1.5]; extrap=:constant) + result = cubic_interp(x, y, [-0.5, 0.5, 1.5]; extrap=ConstExtrap()) @test result[1] ≈ y[1] @test result[3] ≈ y[end] # With cache cache = CubicSplineCache(x) - @test cubic_interp(cache, y, -0.5; extrap=:constant) ≈ y[1] - @test cubic_interp(cache, y, 1.5; extrap=:constant) ≈ y[end] + @test cubic_interp(cache, y, -0.5; extrap=ConstExtrap()) ≈ y[1] + @test cubic_interp(cache, y, 1.5; extrap=ConstExtrap()) ≈ y[end] # Callable interpolant with :constant - itp = cubic_interp(x, y; extrap=:constant) + itp = cubic_interp(x, y; extrap=ConstExtrap()) @test itp(-0.5) ≈ y[1] @test itp(1.5) ≈ y[end] end @@ -404,14 +382,14 @@ end y_int = [sin(2π * i / 10) for i in x_int] x_extrap = [-1.0, 11.0] - result = cubic_interp(x_int, y_int, x_extrap; extrap=:extension) + result = cubic_interp(x_int, y_int, x_extrap; extrap=ExtendExtrap()) @test result isa Vector{Float64} @test all(isfinite, result) x_float = collect(Float64.(x_int)) y_float = Float64.(y_int) - result_ref = cubic_interp(x_float, y_float, x_extrap; extrap=:extension) + result_ref = cubic_interp(x_float, y_float, x_extrap; extrap=ExtendExtrap()) @test result == result_ref end @@ -482,13 +460,13 @@ end @test output[1] ≈ sin(π) atol=1e-6 # Test with different extrap modes - cubic_interp!(output, cache, y, 0.25; extrap=:none) + cubic_interp!(output, cache, y, 0.25; extrap=NoExtrap()) @test isfinite(output[1]) - cubic_interp!(output, cache, y, -0.1; extrap=:constant) + cubic_interp!(output, cache, y, -0.1; extrap=ConstExtrap()) @test output[1] ≈ y[1] - cubic_interp!(output, cache, y, 1.1; extrap=:extension) + cubic_interp!(output, cache, y, 1.1; extrap=ExtendExtrap()) @test isfinite(output[1]) end diff --git a/test/test_cubic_anchor.jl b/test/test_cubic_anchor.jl index 0c21e237..32902203 100644 --- a/test/test_cubic_anchor.jl +++ b/test/test_cubic_anchor.jl @@ -10,7 +10,7 @@ @testset "Anchored evaluation - exact agreement" begin x = collect(range(0.0, 1.0, 101)) y = sin.(2π .* x) - itp = cubic_interp(x, y; extrap=:extension) + itp = cubic_interp(x, y; extrap=ExtendExtrap()) # Test multiple query points for xq in [0.0, 0.15, 0.35, 0.5, 0.75, 0.99, 1.0] @@ -22,7 +22,7 @@ @testset "Anchored evaluation - derivatives" begin x = collect(range(0.0, 1.0, 101)) y = sin.(2π .* x) - itp = cubic_interp(x, y; extrap=:extension) + itp = cubic_interp(x, y; extrap=ExtendExtrap()) for xq in [0.15, 0.5, 0.85] aq = FI._anchor_query(x, xq, Val(:cubic)) @@ -36,10 +36,10 @@ end end - @testset "Anchored evaluation - extrap :none" begin + @testset "Anchored evaluation - extrap NoExtrap()" begin x = collect(range(0.0, 1.0, 101)) y = sin.(2π .* x) - itp = cubic_interp(x, y; extrap=:none) + itp = cubic_interp(x, y; extrap=NoExtrap()) # Inside domain should work aq_inside = FI._anchor_query(x, 0.5, Val(:cubic)) @@ -53,10 +53,10 @@ @test_throws DomainError itp(aq_above) end - @testset "Anchored evaluation - extrap :constant" begin + @testset "Anchored evaluation - extrap ConstExtrap()" begin x = collect(range(0.0, 1.0, 101)) y = sin.(2π .* x) - itp = cubic_interp(x, y; extrap=:constant) + itp = cubic_interp(x, y; extrap=ConstExtrap()) # Below domain returns y[1] aq_below = FI._anchor_query(x, -0.5, Val(:cubic)) @@ -71,10 +71,10 @@ @test itp(aq_above; deriv=2) == 0.0 end - @testset "Anchored evaluation - extrap :extension" begin + @testset "Anchored evaluation - extrap ExtendExtrap()" begin x = collect(range(0.0, 1.0, 101)) y = sin.(2π .* x) - itp = cubic_interp(x, y; extrap=:extension) + itp = cubic_interp(x, y; extrap=ExtendExtrap()) # Outside domain uses boundary polynomial aq_below = FI._anchor_query(x, -0.1, Val(:cubic)) @@ -84,10 +84,10 @@ @test itp(aq_above) ≈ itp(1.1) atol=1e-14 end - @testset "Anchored evaluation - extrap :wrap" begin + @testset "Anchored evaluation - extrap WrapExtrap()" begin x = collect(range(0.0, 1.0, 101)) y = sin.(2π .* x) - itp = cubic_interp(x, y; extrap=:wrap) + itp = cubic_interp(x, y; extrap=WrapExtrap()) # Wrap extrapolation - anchor must be created with wrap=true # to pre-wrap coordinates for :wrap mode @@ -102,7 +102,7 @@ y[end] = y[1] # Ensure periodic itp = cubic_interp(x, y; bc=PeriodicBC()) - # Wrap at anchor construction (for extrap=:wrap mode) + # Wrap at anchor construction (for extrap=WrapExtrap() mode) aq_wrapped = FI._anchor_query(x, 2π + 1.0, Val(:cubic); wrap=true) @test itp(aq_wrapped) ≈ itp(1.0) atol=1e-10 end @@ -110,7 +110,7 @@ @testset "Anchored evaluation - Float32" begin x32 = Float32.(collect(range(Float32(0), Float32(1), 101))) y32 = sin.(Float32(2π) .* x32) - itp = cubic_interp(x32, y32; extrap=:extension) + itp = cubic_interp(x32, y32; extrap=ExtendExtrap()) xq = Float32(0.35) aq = FI._anchor_query(x32, xq, Val(:cubic)) @@ -122,7 +122,7 @@ @testset "Anchored evaluation - zero allocation" begin x = collect(range(0.0, 1.0, 101)) y = sin.(2π .* x) - itp = cubic_interp(x, y; extrap=:extension) + itp = cubic_interp(x, y; extrap=ExtendExtrap()) aq = FI._anchor_query(x, 0.5, Val(:cubic)) # Warmup @@ -139,9 +139,9 @@ y2 = cos.(2π .* x) y3 = exp.(-3 .* x) - itp1 = cubic_interp(x, y1; extrap=:extension) - itp2 = cubic_interp(x, y2; extrap=:extension) - itp3 = cubic_interp(x, y3; extrap=:extension) + itp1 = cubic_interp(x, y1; extrap=ExtendExtrap()) + itp2 = cubic_interp(x, y2; extrap=ExtendExtrap()) + itp3 = cubic_interp(x, y3; extrap=ExtendExtrap()) # Create anchor once aq = FI._anchor_query(x, 0.35, Val(:cubic)) @@ -321,7 +321,7 @@ @testset "Vector evaluation - allocating" begin x = collect(range(0.0, 1.0, 101)) y = sin.(2π .* x) - itp = cubic_interp(x, y; extrap=:extension) + itp = cubic_interp(x, y; extrap=ExtendExtrap()) xq = [0.0, 0.15, 0.35, 0.5, 0.75, 0.99, 1.0] aq_vec = FI._anchor_query(x, xq, Val(:cubic)) @@ -333,9 +333,9 @@ end end - @testset "Vector evaluation - extrap :none" begin + @testset "Vector evaluation - extrap NoExtrap()" begin x = collect(range(0.0, 1.0, 101)) - itp = cubic_interp(x, sin.(x); extrap=:none) + itp = cubic_interp(x, sin.(x); extrap=NoExtrap()) xq = [-0.1, 0.5, 1.1] # First is out of domain aq_vec = FI._anchor_query(x, xq, Val(:cubic)) @@ -343,10 +343,10 @@ @test_throws DomainError itp(aq_vec) end - @testset "Vector evaluation - extrap :constant" begin + @testset "Vector evaluation - extrap ConstExtrap()" begin x = collect(range(0.0, 1.0, 101)) y = sin.(2π .* x) - itp = cubic_interp(x, y; extrap=:constant) + itp = cubic_interp(x, y; extrap=ConstExtrap()) xq = [-0.5, 0.5, 1.5] aq_vec = FI._anchor_query(x, xq, Val(:cubic)) @@ -357,10 +357,10 @@ @test vals[3] ≈ y[end] end - @testset "Vector evaluation - extrap :extension" begin + @testset "Vector evaluation - extrap ExtendExtrap()" begin x = collect(range(0.0, 1.0, 101)) y = sin.(2π .* x) - itp = cubic_interp(x, y; extrap=:extension) + itp = cubic_interp(x, y; extrap=ExtendExtrap()) xq = [-0.1, 0.5, 1.1] aq_vec = FI._anchor_query(x, xq, Val(:cubic)) @@ -374,7 +374,7 @@ @testset "Vector evaluation - in-place" begin x = collect(range(0.0, 1.0, 101)) y = sin.(2π .* x) - itp = cubic_interp(x, y; extrap=:extension) + itp = cubic_interp(x, y; extrap=ExtendExtrap()) xq = [0.15, 0.35, 0.5, 0.75] aq_vec = FI._anchor_query(x, xq, Val(:cubic)) @@ -391,7 +391,7 @@ @testset "Vector evaluation - derivatives" begin x = collect(range(0.0, 1.0, 101)) y = sin.(2π .* x) - itp = cubic_interp(x, y; extrap=:extension) + itp = cubic_interp(x, y; extrap=ExtendExtrap()) xq = [0.15, 0.5, 0.85] aq_vec = FI._anchor_query(x, xq, Val(:cubic)) @@ -414,10 +414,10 @@ @test_throws AssertionError itp(output, aq_vec) end - @testset "Vector evaluation - extrap :constant derivatives" begin + @testset "Vector evaluation - extrap ConstExtrap() derivatives" begin x = collect(range(0.0, 1.0, 101)) y = sin.(2π .* x) - itp = cubic_interp(x, y; extrap=:constant) + itp = cubic_interp(x, y; extrap=ConstExtrap()) xq = [-0.5, 0.5, 1.5] aq_vec = FI._anchor_query(x, xq, Val(:cubic)) @@ -460,7 +460,7 @@ @testset "Vector evaluation - wrap=true" begin x = collect(range(0.0, 1.0, 101)) y = sin.(2π .* x) - itp = cubic_interp(x, y; extrap=:wrap) + itp = cubic_interp(x, y; extrap=WrapExtrap()) xq = [-0.3, 1.3, 2.5] aq_vec = FI._anchor_query(x, xq, Val(:cubic); wrap=true) @@ -479,7 +479,7 @@ @testset "Scalar anchored derivatives - zero allocation" begin x = collect(range(0.0, 1.0, 101)) y = sin.(2π .* x) - itp = cubic_interp(x, y; extrap=:extension) + itp = cubic_interp(x, y; extrap=ExtendExtrap()) aq = FI._anchor_query(x, 0.5, Val(:cubic)) # Warmup all derivative orders @@ -503,7 +503,7 @@ @testset "Vector in-place derivatives - zero allocation" begin x = collect(range(0.0, 1.0, 101)) y = sin.(2π .* x) - itp = cubic_interp(x, y; extrap=:extension) + itp = cubic_interp(x, y; extrap=ExtendExtrap()) xq = collect(range(0.1, 0.9, 50)) aq_vec = FI._anchor_query(x, xq, Val(:cubic)) @@ -652,7 +652,7 @@ @testset "Deriv2/3 correctness with anchored query" begin x = collect(range(0.0, 1.0, 101)) y = sin.(2π .* x) - itp = cubic_interp(x, y; extrap=:extension) + itp = cubic_interp(x, y; extrap=ExtendExtrap()) # Test multiple query points including boundaries and interior test_points = [0.0, 0.15, 0.35, 0.5, 0.75, 0.99, 1.0] @@ -676,7 +676,7 @@ @testset "Type stability for deriv2/3" begin x = collect(range(0.0, 1.0, 101)) y = sin.(2π .* x) - itp = cubic_interp(x, y; extrap=:extension) + itp = cubic_interp(x, y; extrap=ExtendExtrap()) aq = FI._anchor_query(x, 0.5, Val(:cubic)) # Scalar anchored evaluation should be type-stable @@ -702,7 +702,7 @@ y = sin.(2π .* x) # Test :extension mode - itp_ext = cubic_interp(x, y; extrap=:extension) + itp_ext = cubic_interp(x, y; extrap=ExtendExtrap()) aq_below = FI._anchor_query(x, -0.1, Val(:cubic)) aq_above = FI._anchor_query(x, 1.1, Val(:cubic)) @@ -710,7 +710,7 @@ @test itp_ext(aq_above; deriv=3) ≈ itp_ext(1.1; deriv=3) atol=1e-12 # Test :constant mode (derivatives should be zero outside domain) - itp_const = cubic_interp(x, y; extrap=:constant) + itp_const = cubic_interp(x, y; extrap=ConstExtrap()) @test itp_const(aq_below; deriv=2) == 0.0 @test itp_const(aq_above; deriv=3) == 0.0 end @@ -719,7 +719,7 @@ @testset "Zero allocation for deriv2/3 anchored evaluation" begin x = collect(range(0.0, 1.0, 101)) y = sin.(2π .* x) - itp = cubic_interp(x, y; extrap=:extension) + itp = cubic_interp(x, y; extrap=ExtendExtrap()) aq = FI._anchor_query(x, 0.5, Val(:cubic)) # Warmup diff --git a/test/test_cubic_interpolant.jl b/test/test_cubic_interpolant.jl index 76719ea2..d70619cc 100644 --- a/test/test_cubic_interpolant.jl +++ b/test/test_cubic_interpolant.jl @@ -131,12 +131,12 @@ @test val == ref_val end - # Extrapolation (requires extrap=:extension) - itp_extrap = cubic_interp(x, y; autocache=false, extrap=:extension) + # Extrapolation (requires extrap=ExtendExtrap()) + itp_extrap = cubic_interp(x, y; autocache=false, extrap=ExtendExtrap()) val_left = itp_extrap(-0.1) val_right = itp_extrap(1.1) - ref_left = cubic_interp(x, y, -0.1; autocache=false, extrap=:extension) - ref_right = cubic_interp(x, y, 1.1; autocache=false, extrap=:extension) + ref_left = cubic_interp(x, y, -0.1; autocache=false, extrap=ExtendExtrap()) + ref_right = cubic_interp(x, y, 1.1; autocache=false, extrap=ExtendExtrap()) @test val_left == ref_left @test val_right == ref_right @test isfinite(val_left) diff --git a/test/test_cubic_nd.jl b/test/test_cubic_nd.jl index 3e19af29..12e8b155 100644 --- a/test/test_cubic_nd.jl +++ b/test/test_cubic_nd.jl @@ -146,12 +146,12 @@ end data = [xi * yj for xi in x, yj in y] # :none (default) - should throw outside domain - itp_none = cubic_interp((x, y), data; extrap=:none) + itp_none = cubic_interp((x, y), data; extrap=NoExtrap()) @test_throws DomainError itp_none((-0.1, 0.5)) @test_throws DomainError itp_none((0.5, -0.1)) # :constant - clamp to boundary - itp_const = cubic_interp((x, y), data; extrap=:constant) + itp_const = cubic_interp((x, y), data; extrap=ConstExtrap()) @test itp_const((-0.1, 0.5)) ≈ itp_const((0.0, 0.5)) @test itp_const((2.1, 0.5)) ≈ itp_const((2.0, 0.5)) end diff --git a/test/test_cubic_nd_oneshot.jl b/test/test_cubic_nd_oneshot.jl index b5e379fd..b20a3193 100644 --- a/test/test_cubic_nd_oneshot.jl +++ b/test/test_cubic_nd_oneshot.jl @@ -133,15 +133,15 @@ end x = range(0.0, 2.0, 15) y = range(0.0, 1.0, 10) data = [xi + yj for xi in x, yj in y] - itp_const = cubic_interp((x, y), data; extrap=:constant) - itp_ext = cubic_interp((x, y), data; extrap=:extension) + itp_const = cubic_interp((x, y), data; extrap=ConstExtrap()) + itp_ext = cubic_interp((x, y), data; extrap=ExtendExtrap()) # Constant extrap - @test cubic_interp((x, y), data, (1.0, 0.5); extrap=:constant) ≈ + @test cubic_interp((x, y), data, (1.0, 0.5); extrap=ConstExtrap()) ≈ itp_const((1.0, 0.5)) atol=1e-14 # Extension extrap - @test cubic_interp((x, y), data, (1.0, 0.5); extrap=:extension) ≈ + @test cubic_interp((x, y), data, (1.0, 0.5); extrap=ExtendExtrap()) ≈ itp_ext((1.0, 0.5)) atol=1e-14 end diff --git a/test/test_cubic_series_interp.jl b/test/test_cubic_series_interp.jl index ac9d1d0b..8053706f 100644 --- a/test/test_cubic_series_interp.jl +++ b/test/test_cubic_series_interp.jl @@ -105,10 +105,10 @@ end end @testset "Extrap is AbstractExtrap type" begin - mitp_ext = cubic_interp(x, [y1, y2]; extrap=:extension) + mitp_ext = cubic_interp(x, [y1, y2]; extrap=ExtendExtrap()) @test mitp_ext.extrap === ExtendExtrap() - mitp_const = cubic_interp(x, [y1, y2]; extrap=:constant) + mitp_const = cubic_interp(x, [y1, y2]; extrap=ConstExtrap()) @test mitp_const.extrap === ConstExtrap() end end @@ -197,15 +197,15 @@ end @test mitp.cache.x isa AbstractRange end - @testset "PeriodicBC forces :wrap extrap" begin + @testset "PeriodicBC forces WrapExtrap() extrap" begin # Create periodic data (endpoints match) y_periodic = sin.(2π .* x) # sin(0) = sin(2π) = 0 - mitp = cubic_interp(x, [y_periodic]; bc=PeriodicBC(), extrap=:none) + mitp = cubic_interp(x, [y_periodic]; bc=PeriodicBC(), extrap=NoExtrap()) @test mitp.extrap === WrapExtrap() # Even if user requests :extension, periodic BC should override to :wrap - mitp2 = cubic_interp(x, [y_periodic]; bc=PeriodicBC(), extrap=:extension) + mitp2 = cubic_interp(x, [y_periodic]; bc=PeriodicBC(), extrap=ExtendExtrap()) @test mitp2.extrap === WrapExtrap() end end @@ -431,7 +431,7 @@ end @test snap_after !== nothing end - @testset ":wrap extrapolation scalar SIMD path" begin + @testset "WrapExtrap() extrapolation scalar SIMD path" begin # Create periodic data (endpoints match) y_periodic = sin.(2π .* x) # sin(0) = sin(2π) = 0 y_periodic2 = cos.(2π .* x) # cos(0) = cos(2π) = 1 @@ -439,7 +439,7 @@ end mitp = cubic_interp(x, [y_periodic, y_periodic2]; bc=PeriodicBC()) - # Query outside domain triggers :wrap extrapolation + # Query outside domain triggers WrapExtrap() extrapolation out = zeros(2) mitp(out, -0.1) # Below domain @test !any(isnan, out) @@ -499,8 +499,8 @@ end @test_throws DimensionMismatch mitp(outputs_bad_len, aq_vec) end - @testset "Vector extrapolation :extension mode" begin - mitp = cubic_interp(x, [y1, y2]; extrap=:extension) + @testset "Vector extrapolation ExtendExtrap() mode" begin + mitp = cubic_interp(x, [y1, y2]; extrap=ExtendExtrap()) xq = [-0.1, 0.5, 1.1] # Include out-of-domain points outputs = [zeros(3), zeros(3)] @@ -510,8 +510,8 @@ end @test !any(isnan, outputs[2]) end - @testset "Vector extrapolation :constant mode" begin - mitp = cubic_interp(x, [y1, y2]; extrap=:constant) + @testset "Vector extrapolation ConstExtrap() mode" begin + mitp = cubic_interp(x, [y1, y2]; extrap=ConstExtrap()) xq = [-0.1, 0.5, 1.1] # Include out-of-domain points outputs = [zeros(3), zeros(3)] @@ -522,7 +522,7 @@ end @test outputs[1][3] ≈ y1[end] atol=1e-10 # Above domain → last value end - @testset "Vector extrapolation :wrap mode (periodic)" begin + @testset "Vector extrapolation WrapExtrap() mode (periodic)" begin y_periodic = sin.(2π .* x) y_periodic2 = cos.(2π .* x) y_periodic2[end] = y_periodic2[1] @@ -537,8 +537,8 @@ end @test !any(isnan, outputs[2]) end - @testset "Scalar extrapolation :constant with derivative" begin - mitp = cubic_interp(x, [y1, y2]; extrap=:constant) + @testset "Scalar extrapolation ConstExtrap() with derivative" begin + mitp = cubic_interp(x, [y1, y2]; extrap=ConstExtrap()) # First derivative outside domain should be zero out1 = zeros(2) @@ -567,8 +567,8 @@ end @test out_val[2] ≈ y2[1] atol=1e-10 end - @testset "Vector extrapolation :constant with derivative" begin - mitp = cubic_interp(x, [y1, y2]; extrap=:constant) + @testset "Vector extrapolation ConstExtrap() with derivative" begin + mitp = cubic_interp(x, [y1, y2]; extrap=ConstExtrap()) xq = [-0.1, 0.5, 1.1] # Include out-of-domain points outputs = [zeros(3), zeros(3)] @@ -580,7 +580,7 @@ end end @testset "DomainError message includes bounds" begin - mitp = cubic_interp(x, [y1, y2]; extrap=:none) + mitp = cubic_interp(x, [y1, y2]; extrap=NoExtrap()) # Scalar path err = try @@ -713,12 +713,9 @@ end end @testset "Extrap propagation" begin - expected = Dict(:none => NoExtrap(), :constant => ConstExtrap(), - :extension => ExtendExtrap(), :wrap => WrapExtrap()) - for extrap_mode in (:none, :constant, :extension, :wrap) + for extrap_mode in (NoExtrap(), ConstExtrap(), ExtendExtrap(), WrapExtrap()) mitp = cubic_interp(x, [y1, y2]; extrap=extrap_mode) - # Unified struct stores AbstractExtrap singleton - @test mitp.extrap === expected[extrap_mode] + @test mitp.extrap === extrap_mode end end end @@ -735,7 +732,7 @@ end y2 = cos.(2π .* x) y3 = exp.(-3 .* x) - mitp = cubic_interp(x, [y1, y2, y3]; extrap=:extension) + mitp = cubic_interp(x, [y1, y2, y3]; extrap=ExtendExtrap()) @testset "Returns Vector with correct values" begin result = mitp(0.35) @@ -743,9 +740,9 @@ end @test length(result) == 3 # Individual results match standalone interpolants - itp1 = cubic_interp(x, y1; extrap=:extension) - itp2 = cubic_interp(x, y2; extrap=:extension) - itp3 = cubic_interp(x, y3; extrap=:extension) + itp1 = cubic_interp(x, y1; extrap=ExtendExtrap()) + itp2 = cubic_interp(x, y2; extrap=ExtendExtrap()) + itp3 = cubic_interp(x, y3; extrap=ExtendExtrap()) @test result[1] ≈ itp1(0.35) atol=1e-14 @test result[2] ≈ itp2(0.35) atol=1e-14 @@ -753,9 +750,9 @@ end end @testset "Derivatives via deriv keyword" begin - itp1 = cubic_interp(x, y1; extrap=:extension) - itp2 = cubic_interp(x, y2; extrap=:extension) - itp3 = cubic_interp(x, y3; extrap=:extension) + itp1 = cubic_interp(x, y1; extrap=ExtendExtrap()) + itp2 = cubic_interp(x, y2; extrap=ExtendExtrap()) + itp3 = cubic_interp(x, y3; extrap=ExtendExtrap()) # First derivative d1 = mitp(0.5; deriv=1) @@ -786,7 +783,7 @@ end y2 = cos.(2π .* x) y3 = exp.(-3 .* x) - mitp = cubic_interp(x, [y1, y2, y3]; extrap=:extension) + mitp = cubic_interp(x, [y1, y2, y3]; extrap=ExtendExtrap()) @testset "Fills output correctly" begin output = Vector{Float64}(undef, 3) @@ -794,9 +791,9 @@ end @test result === output # Returns same reference - itp1 = cubic_interp(x, y1; extrap=:extension) - itp2 = cubic_interp(x, y2; extrap=:extension) - itp3 = cubic_interp(x, y3; extrap=:extension) + itp1 = cubic_interp(x, y1; extrap=ExtendExtrap()) + itp2 = cubic_interp(x, y2; extrap=ExtendExtrap()) + itp3 = cubic_interp(x, y3; extrap=ExtendExtrap()) @test output[1] ≈ itp1(0.35) atol=1e-14 @test output[2] ≈ itp2(0.35) atol=1e-14 @@ -812,7 +809,7 @@ end output = Vector{Float64}(undef, 3) mitp(output, 0.5; deriv=1) - itp1 = cubic_interp(x, y1; extrap=:extension) + itp1 = cubic_interp(x, y1; extrap=ExtendExtrap()) @test output[1] ≈ itp1(0.5; deriv=1) atol=1e-14 end end @@ -824,8 +821,8 @@ end y1 = sin.(2π .* x) y2 = cos.(2π .* x) - @testset "extrap=:none - throws DomainError" begin - mitp = cubic_interp(x, [y1, y2]; extrap=:none) + @testset "extrap=NoExtrap() - throws DomainError" begin + mitp = cubic_interp(x, [y1, y2]; extrap=NoExtrap()) # Inside domain works @test isfinite(mitp(0.5)[1]) @@ -835,8 +832,8 @@ end @test_throws DomainError mitp(1.1) end - @testset "extrap=:constant - boundary values" begin - mitp = cubic_interp(x, [y1, y2]; extrap=:constant) + @testset "extrap=ConstExtrap() - boundary values" begin + mitp = cubic_interp(x, [y1, y2]; extrap=ConstExtrap()) below = mitp(-0.5) @test below[1] ≈ y1[1] @@ -847,10 +844,10 @@ end @test above[2] ≈ y2[end] end - @testset "extrap=:extension - boundary polynomial" begin - mitp = cubic_interp(x, [y1, y2]; extrap=:extension) - itp1 = cubic_interp(x, y1; extrap=:extension) - itp2 = cubic_interp(x, y2; extrap=:extension) + @testset "extrap=ExtendExtrap() - boundary polynomial" begin + mitp = cubic_interp(x, [y1, y2]; extrap=ExtendExtrap()) + itp1 = cubic_interp(x, y1; extrap=ExtendExtrap()) + itp2 = cubic_interp(x, y2; extrap=ExtendExtrap()) below = mitp(-0.1) @test below[1] ≈ itp1(-0.1) atol=1e-14 @@ -861,13 +858,13 @@ end @test above[2] ≈ itp2(1.1) atol=1e-14 end - @testset "extrap=:wrap - wrapped coordinates" begin - mitp = cubic_interp(x, [y1, y2]; extrap=:wrap) + @testset "extrap=WrapExtrap() - wrapped coordinates" begin + mitp = cubic_interp(x, [y1, y2]; extrap=WrapExtrap()) # Query outside domain should wrap result = mitp(1.35) # wraps to 0.35 - expected1 = cubic_interp(x, y1; extrap=:wrap)(1.35) - expected2 = cubic_interp(x, y2; extrap=:wrap)(1.35) + expected1 = cubic_interp(x, y1; extrap=WrapExtrap())(1.35) + expected2 = cubic_interp(x, y2; extrap=WrapExtrap())(1.35) @test result[1] ≈ expected1 atol=1e-14 @test result[2] ≈ expected2 atol=1e-14 @@ -886,7 +883,7 @@ end y2 = cos.(2π .* x) y3 = exp.(-3 .* x) - mitp = cubic_interp(x, [y1, y2, y3]; extrap=:extension) + mitp = cubic_interp(x, [y1, y2, y3]; extrap=ExtendExtrap()) xq = [0.15, 0.35, 0.5, 0.75] @testset "Returns container of Vector{T}" begin @@ -900,9 +897,9 @@ end @testset "Results match individual interpolants" begin result = mitp(xq) - itp1 = cubic_interp(x, y1; extrap=:extension) - itp2 = cubic_interp(x, y2; extrap=:extension) - itp3 = cubic_interp(x, y3; extrap=:extension) + itp1 = cubic_interp(x, y1; extrap=ExtendExtrap()) + itp2 = cubic_interp(x, y2; extrap=ExtendExtrap()) + itp3 = cubic_interp(x, y3; extrap=ExtendExtrap()) @test result[1] ≈ itp1(xq) atol=1e-14 @test result[2] ≈ itp2(xq) atol=1e-14 @@ -910,10 +907,10 @@ end end @testset "Derivatives with vector queries" begin - itp1 = cubic_interp(x, y1; extrap=:extension) - itp2 = cubic_interp(x, y2; extrap=:extension) + itp1 = cubic_interp(x, y1; extrap=ExtendExtrap()) + itp2 = cubic_interp(x, y2; extrap=ExtendExtrap()) - mitp2 = cubic_interp(x, [y1, y2]; extrap=:extension) + mitp2 = cubic_interp(x, [y1, y2]; extrap=ExtendExtrap()) d1 = mitp2(xq; deriv=1) @test d1[1] ≈ itp1(xq; deriv=1) atol=1e-14 @@ -933,7 +930,7 @@ end y2 = cos.(2π .* x) y3 = exp.(-3 .* x) - mitp = cubic_interp(x, [y1, y2, y3]; extrap=:extension) + mitp = cubic_interp(x, [y1, y2, y3]; extrap=ExtendExtrap()) xq = collect(range(0.1, 0.9, 50)) @testset "Fills all buffers correctly" begin @@ -946,9 +943,9 @@ end @test result === outputs # Returns same reference - itp1 = cubic_interp(x, y1; extrap=:extension) - itp2 = cubic_interp(x, y2; extrap=:extension) - itp3 = cubic_interp(x, y3; extrap=:extension) + itp1 = cubic_interp(x, y1; extrap=ExtendExtrap()) + itp2 = cubic_interp(x, y2; extrap=ExtendExtrap()) + itp3 = cubic_interp(x, y3; extrap=ExtendExtrap()) @test out1 ≈ itp1(xq) atol=1e-14 @test out2 ≈ itp2(xq) atol=1e-14 @@ -994,7 +991,7 @@ end aq_vec = FI._anchor_query(x, xq, Val(:cubic)) mitp(outputs, aq_vec; deriv=1) - itp1 = cubic_interp(x, y1; extrap=:extension) + itp1 = cubic_interp(x, y1; extrap=ExtendExtrap()) # Use same anchored path for comparison expected = Vector{Float64}(undef, 50) itp1(expected, aq_vec; deriv=1) @@ -1009,15 +1006,15 @@ end y1 = sin.(2π .* x) y2 = cos.(2π .* x) - @testset "extrap=:none - throws on out-of-domain" begin - mitp = cubic_interp(x, [y1, y2]; extrap=:none) + @testset "extrap=NoExtrap() - throws on out-of-domain" begin + mitp = cubic_interp(x, [y1, y2]; extrap=NoExtrap()) xq_bad = [-0.1, 0.5, 1.1] @test_throws DomainError mitp(xq_bad) end @testset "All extrap modes work with vector" begin - for mode in (:constant, :extension, :wrap) + for mode in (ConstExtrap(), ExtendExtrap(), WrapExtrap()) mitp = cubic_interp(x, [y1, y2]; extrap=mode) xq = [0.15, 0.5, 0.85] result = mitp(xq) @@ -1220,7 +1217,7 @@ end y2 = cos.(2π .* x) y3 = exp.(-3 .* x) - mitp = cubic_interp(x, [y1, y2, y3]; extrap=:extension) + mitp = cubic_interp(x, [y1, y2, y3]; extrap=ExtendExtrap()) @testset "zero allocation after warmup (same size)" begin xq = collect(range(0.1, 0.9, 100)) @@ -1313,18 +1310,18 @@ end @testset "CubicSeriesInterpolant - Scalar Extension Extrapolation with Derivatives" begin FI = FastInterpolations - # Setup: create interpolant with :extension extrapolation + # Setup: create interpolant with ExtendExtrap() extrapolation x = collect(range(0.0, 1.0, 101)) y1 = sin.(2π .* x) y2 = cos.(2π .* x) y3 = x .^ 3 .- 2 .* x .^ 2 .+ x # polynomial for easy derivative verification - mitp = cubic_interp(x, [y1, y2, y3]; extrap=:extension) + mitp = cubic_interp(x, [y1, y2, y3]; extrap=ExtendExtrap()) # Create individual interpolants for reference comparison - itp1 = cubic_interp(x, y1; extrap=:extension) - itp2 = cubic_interp(x, y2; extrap=:extension) - itp3 = cubic_interp(x, y3; extrap=:extension) + itp1 = cubic_interp(x, y1; extrap=ExtendExtrap()) + itp2 = cubic_interp(x, y2; extrap=ExtendExtrap()) + itp3 = cubic_interp(x, y3; extrap=ExtendExtrap()) @testset "deriv=1 outside domain (left side, xq < 0)" begin xq = -0.15 # Outside domain on left @@ -1470,7 +1467,7 @@ end y2 = cos.(2π .* x) y3 = exp.(-3 .* x) - mitp = cubic_interp(x, [y1, y2, y3]; extrap=:extension) + mitp = cubic_interp(x, [y1, y2, y3]; extrap=ExtendExtrap()) xq = collect(range(0.1, 0.9, 50)) @testset "Container in-place with derivatives - zero allocation (deriv=1)" begin @@ -1519,9 +1516,9 @@ end mitp(outputs, aq_vec; deriv=1) # Compare with individual interpolants - itp1 = cubic_interp(x, y1; extrap=:extension) - itp2 = cubic_interp(x, y2; extrap=:extension) - itp3 = cubic_interp(x, y3; extrap=:extension) + itp1 = cubic_interp(x, y1; extrap=ExtendExtrap()) + itp2 = cubic_interp(x, y2; extrap=ExtendExtrap()) + itp3 = cubic_interp(x, y3; extrap=ExtendExtrap()) expected1 = Vector{Float64}(undef, 50) expected2 = Vector{Float64}(undef, 50) @@ -1899,7 +1896,7 @@ end xq_out = [-0.15, -0.05, 0.5, 1.05, 1.15] @testset ":extension mode with pre-built anchors" begin - mitp = cubic_interp(x, [y1, y2, y3]; extrap=:extension) + mitp = cubic_interp(x, [y1, y2, y3]; extrap=ExtendExtrap()) # Pre-build anchors (will have side != 0x00 for out-of-domain points) aq_vec = FI._anchor_query(x, xq_out, Val(:cubic)) @@ -1929,7 +1926,7 @@ end end @testset ":constant mode with pre-built anchors" begin - mitp = cubic_interp(x, [y1, y2, y3]; extrap=:constant) + mitp = cubic_interp(x, [y1, y2, y3]; extrap=ConstExtrap()) aq_vec = FI._anchor_query(x, xq_out, Val(:cubic)) outputs = [similar(xq_out) for _ in 1:3] @@ -1961,7 +1958,7 @@ end end @testset ":none mode with pre-built anchors throws DomainError" begin - mitp = cubic_interp(x, [y1, y2, y3]; extrap=:none) + mitp = cubic_interp(x, [y1, y2, y3]; extrap=NoExtrap()) aq_vec = FI._anchor_query(x, xq_out, Val(:cubic)) outputs = [similar(xq_out) for _ in 1:3] diff --git a/test/test_cumulative_integrate.jl b/test/test_cumulative_integrate.jl index 3e6ff07d..9155d33a 100644 --- a/test/test_cumulative_integrate.jl +++ b/test/test_cumulative_integrate.jl @@ -9,9 +9,9 @@ using FastInterpolations y_linear = @. 3x + 1 y_quad = @. 2x^2 - x + 4 - itp_c = cubic_interp(x, y_cubic; extrap=:none) - itp_l = linear_interp(x, y_linear; extrap=:none) - itp_q = quadratic_interp(x, y_quad; extrap=:none) + itp_c = cubic_interp(x, y_cubic; extrap=NoExtrap()) + itp_l = linear_interp(x, y_linear; extrap=NoExtrap()) + itp_q = quadratic_interp(x, y_quad; extrap=NoExtrap()) for (name, itp) in [("cubic", itp_c), ("linear", itp_l), ("quadratic", itp_q)] @testset "$name" begin @@ -29,7 +29,7 @@ using FastInterpolations @testset "constant" begin y_const = collect(1.0:length(x)) for side in (:left, :right, :nearest) - itp_k = constant_interp(x, y_const; side=side, extrap=:none) + itp_k = constant_interp(x, y_const; side=side, extrap=NoExtrap()) cum = cumulative_integrate(itp_k) @test cum[1] == 0.0 @test cum[end] ≈ integrate(itp_k) atol=1e-12 @@ -40,7 +40,7 @@ using FastInterpolations @testset "1D analytical" begin # f(x) = 3x + 1, F(x) = 1.5x² + x y_linear = @. 3x + 1 - itp_l = linear_interp(x, y_linear; extrap=:none) + itp_l = linear_interp(x, y_linear; extrap=NoExtrap()) cum = cumulative_integrate(itp_l) for (j, xj) in enumerate(x) expected = 1.5 * xj^2 + xj - (1.5 * first(x)^2 + first(x)) diff --git a/test/test_derivatives.jl b/test/test_derivatives.jl index e047f7b7..93b0e924 100644 --- a/test/test_derivatives.jl +++ b/test/test_derivatives.jl @@ -404,26 +404,26 @@ end # Derivative Kernels @testset "Constant extrapolation" begin # Left boundary constant extrap: returns y[1] for value, 0 for derivatives - @test cubic_interp(x, y, -0.5; bc=bc, extrap=:constant, deriv=0) ≈ 0.0 - @test cubic_interp(x, y, -0.5; bc=bc, extrap=:constant, deriv=1) ≈ 0.0 - @test cubic_interp(x, y, -0.5; bc=bc, extrap=:constant, deriv=2) ≈ 0.0 + @test cubic_interp(x, y, -0.5; bc=bc, extrap=ConstExtrap(), deriv=0) ≈ 0.0 + @test cubic_interp(x, y, -0.5; bc=bc, extrap=ConstExtrap(), deriv=1) ≈ 0.0 + @test cubic_interp(x, y, -0.5; bc=bc, extrap=ConstExtrap(), deriv=2) ≈ 0.0 # Right boundary - @test cubic_interp(x, y, 1.5; bc=bc, extrap=:constant, deriv=0) ≈ 1.0 - @test cubic_interp(x, y, 1.5; bc=bc, extrap=:constant, deriv=1) ≈ 0.0 - @test cubic_interp(x, y, 1.5; bc=bc, extrap=:constant, deriv=2) ≈ 0.0 + @test cubic_interp(x, y, 1.5; bc=bc, extrap=ConstExtrap(), deriv=0) ≈ 1.0 + @test cubic_interp(x, y, 1.5; bc=bc, extrap=ConstExtrap(), deriv=1) ≈ 0.0 + @test cubic_interp(x, y, 1.5; bc=bc, extrap=ConstExtrap(), deriv=2) ≈ 0.0 end @testset "Extension extrapolation" begin # Extension: continue boundary polynomial # For x², extension should give approximately correct derivatives - val = cubic_interp(x, y, 1.5; bc=bc, extrap=:extension, deriv=0) + val = cubic_interp(x, y, 1.5; bc=bc, extrap=ExtendExtrap(), deriv=0) @test val ≈ 2.25 atol=0.1 # (1.5)² ≈ 2.25 - deriv1 = cubic_interp(x, y, 1.5; bc=bc, extrap=:extension, deriv=1) + deriv1 = cubic_interp(x, y, 1.5; bc=bc, extrap=ExtendExtrap(), deriv=1) @test deriv1 ≈ 3.0 atol=0.2 # 2*1.5 ≈ 3.0 - deriv2 = cubic_interp(x, y, 1.5; bc=bc, extrap=:extension, deriv=2) + deriv2 = cubic_interp(x, y, 1.5; bc=bc, extrap=ExtendExtrap(), deriv=2) @test deriv2 ≈ 2.0 atol=0.1 # f''(x) = 2 end end @@ -665,33 +665,33 @@ end # Cubic Derivatives @testset "Constant extrapolation" begin # Left boundary: returns y[1], derivatives = 0 - @test linear_interp(x, y, -0.5; extrap=:constant, deriv=0) ≈ 0.0 - @test linear_interp(x, y, -0.5; extrap=:constant, deriv=1) ≈ 0.0 - @test linear_interp(x, y, -0.5; extrap=:constant, deriv=2) ≈ 0.0 + @test linear_interp(x, y, -0.5; extrap=ConstExtrap(), deriv=0) ≈ 0.0 + @test linear_interp(x, y, -0.5; extrap=ConstExtrap(), deriv=1) ≈ 0.0 + @test linear_interp(x, y, -0.5; extrap=ConstExtrap(), deriv=2) ≈ 0.0 # Right boundary: returns y[end], derivatives = 0 - @test linear_interp(x, y, 2.5; extrap=:constant, deriv=0) ≈ 6.0 - @test linear_interp(x, y, 2.5; extrap=:constant, deriv=1) ≈ 0.0 - @test linear_interp(x, y, 2.5; extrap=:constant, deriv=2) ≈ 0.0 + @test linear_interp(x, y, 2.5; extrap=ConstExtrap(), deriv=0) ≈ 6.0 + @test linear_interp(x, y, 2.5; extrap=ConstExtrap(), deriv=1) ≈ 0.0 + @test linear_interp(x, y, 2.5; extrap=ConstExtrap(), deriv=2) ≈ 0.0 end @testset "Extension extrapolation" begin # Left: extends first segment (slope 2.0) - @test linear_interp(x, y, -0.5; extrap=:extension, deriv=0) ≈ -1.0 - @test linear_interp(x, y, -0.5; extrap=:extension, deriv=1) ≈ 2.0 - @test linear_interp(x, y, -0.5; extrap=:extension, deriv=2) ≈ 0.0 + @test linear_interp(x, y, -0.5; extrap=ExtendExtrap(), deriv=0) ≈ -1.0 + @test linear_interp(x, y, -0.5; extrap=ExtendExtrap(), deriv=1) ≈ 2.0 + @test linear_interp(x, y, -0.5; extrap=ExtendExtrap(), deriv=2) ≈ 0.0 # Right: extends last segment (slope 4.0) - @test linear_interp(x, y, 2.5; extrap=:extension, deriv=0) ≈ 8.0 - @test linear_interp(x, y, 2.5; extrap=:extension, deriv=1) ≈ 4.0 - @test linear_interp(x, y, 2.5; extrap=:extension, deriv=2) ≈ 0.0 + @test linear_interp(x, y, 2.5; extrap=ExtendExtrap(), deriv=0) ≈ 8.0 + @test linear_interp(x, y, 2.5; extrap=ExtendExtrap(), deriv=1) ≈ 4.0 + @test linear_interp(x, y, 2.5; extrap=ExtendExtrap(), deriv=2) ≈ 0.0 end @testset "Wrap extrapolation" begin # Domain [0, 2), wrap 2.5 -> 0.5 (first segment) - @test linear_interp(x, y, 2.5; extrap=:wrap, deriv=0) ≈ 1.0 # same as 0.5 - @test linear_interp(x, y, 2.5; extrap=:wrap, deriv=1) ≈ 2.0 # first segment slope - @test linear_interp(x, y, 2.5; extrap=:wrap, deriv=2) ≈ 0.0 + @test linear_interp(x, y, 2.5; extrap=WrapExtrap(), deriv=0) ≈ 1.0 # same as 0.5 + @test linear_interp(x, y, 2.5; extrap=WrapExtrap(), deriv=1) ≈ 2.0 # first segment slope + @test linear_interp(x, y, 2.5; extrap=WrapExtrap(), deriv=2) ≈ 0.0 end end @@ -825,10 +825,10 @@ end # Cubic Derivatives x = [0.0, 1.0, 2.0] y = [0.0, 2.0, 6.0] # slopes: 2.0, 4.0 - extrap_modes = [:none, :constant, :extension, :wrap] + extrap_modes = [NoExtrap(), ConstExtrap(), ExtendExtrap(), WrapExtrap()] for mode in extrap_modes - mode == :none && continue # Skip :none for out-of-domain test + mode isa NoExtrap && continue # Skip NoExtrap for out-of-domain test litp = linear_interp(x, y; extrap=mode) @testset "extrap=$mode" begin @@ -1386,7 +1386,7 @@ end # Derivative Edge Cases x = collect(range(0.0, 1.0, 51)) y = x .^ 2 - for extrap in [:none, :constant, :extension] + for extrap in [NoExtrap(), ConstExtrap(), ExtendExtrap()] itp = cubic_interp(x, y; extrap=extrap) # Warmup @@ -1449,7 +1449,7 @@ end # Derivative Allocations (BCPair(Deriv1(0.5), Deriv2(2.0)), "Deriv1-Deriv2"), ] - extrap_modes = [:none, :constant, :extension] + extrap_modes = [NoExtrap(), ConstExtrap(), ExtendExtrap()] for (bc, bc_name) in bc_types for extrap in extrap_modes @@ -1493,7 +1493,7 @@ end # Derivative Allocations x = collect(range(0.0, 1.0, 51)) y = x .^ 2 - extrap_modes = [:none, :constant, :extension, :wrap] + extrap_modes = [NoExtrap(), ConstExtrap(), ExtendExtrap(), WrapExtrap()] for extrap in extrap_modes itp = linear_interp(x, y; extrap=extrap) @@ -1516,7 +1516,7 @@ end # Derivative Allocations x = 0.0:0.02:1.0 y = collect(x) .^ 2 - for extrap in [:none, :extension] + for extrap in [NoExtrap(), ExtendExtrap()] itp = linear_interp(x, y; extrap=extrap) # Warmup @@ -1924,18 +1924,18 @@ end # DerivativeView Wrapper y = x.^3 # Constant extrapolation - itp_const = cubic_interp(x, y; extrap=:constant) + itp_const = cubic_interp(x, y; extrap=ConstExtrap()) @test itp_const(-0.5; deriv=3) === 0.0 @test itp_const(1.5; deriv=3) === 0.0 # Extension extrapolation - itp_ext = cubic_interp(x, y; extrap=:extension) + itp_ext = cubic_interp(x, y; extrap=ExtendExtrap()) val_below = itp_ext(-0.5; deriv=3) val_first = itp_ext(0.05; deriv=3) @test val_below ≈ val_first # None throws - itp_none = cubic_interp(x, y; extrap=:none) + itp_none = cubic_interp(x, y; extrap=NoExtrap()) @test_throws DomainError itp_none(-0.5; deriv=3) end @@ -1946,13 +1946,13 @@ end # DerivativeView Wrapper y_linear = 2.0 .* x y_const = fill(5.0, length(x)) - # Linear interpolation: deriv=3 with :constant extrap outside domain - @test linear_interp(x, y_linear, -0.5; extrap=:constant, deriv=3) === 0.0 - @test linear_interp(x, y_linear, 1.5; extrap=:constant, deriv=3) === 0.0 + # Linear interpolation: deriv=3 with ConstExtrap() extrap outside domain + @test linear_interp(x, y_linear, -0.5; extrap=ConstExtrap(), deriv=3) === 0.0 + @test linear_interp(x, y_linear, 1.5; extrap=ConstExtrap(), deriv=3) === 0.0 - # Constant interpolation: deriv=3 with :constant extrap outside domain - @test constant_interp(x, y_const, -0.5; extrap=:constant, deriv=3) === 0.0 - @test constant_interp(x, y_const, 1.5; extrap=:constant, deriv=3) === 0.0 + # Constant interpolation: deriv=3 with ConstExtrap() extrap outside domain + @test constant_interp(x, y_const, -0.5; extrap=ConstExtrap(), deriv=3) === 0.0 + @test constant_interp(x, y_const, 1.5; extrap=ConstExtrap(), deriv=3) === 0.0 end @testset "Type stability for deriv=3" begin @@ -2156,7 +2156,7 @@ end # DerivativeView Vector Queries x = collect(range(0.0, 1.0, 11)) y1 = x.^3 y2 = x.^2 - sitp = cubic_interp(x, [y1, y2]; extrap=:constant) + sitp = cubic_interp(x, [y1, y2]; extrap=ConstExtrap()) # Outside domain with deriv=3 vals_below = sitp(-0.5; deriv=3) diff --git a/test/test_integral_1d.jl b/test/test_integral_1d.jl index 2e6c4fd9..fe510211 100644 --- a/test/test_integral_1d.jl +++ b/test/test_integral_1d.jl @@ -6,7 +6,7 @@ using FastInterpolations @testset "linear affine exact" begin y = @. 3x - 1 - itp = linear_interp(x, y; extrap=:none) + itp = linear_interp(x, y; extrap=NoExtrap()) a, b = 0.15, 0.85 expected = (1.5*b^2 - b) - (1.5*a^2 - a) @test integrate(itp, a, b) ≈ expected atol=1e-12 @@ -14,7 +14,7 @@ using FastInterpolations @testset "quadratic polynomial exact" begin y = @. 2x^2 - x + 4 - itp = quadratic_interp(x, y; extrap=:none) + itp = quadratic_interp(x, y; extrap=NoExtrap()) a, b = 0.1, 0.9 expected = ((2/3)*b^3 - 0.5*b^2 + 4b) - ((2/3)*a^3 - 0.5*a^2 + 4a) @test integrate(itp, a, b) ≈ expected atol=1e-10 @@ -23,7 +23,7 @@ using FastInterpolations @testset "constant finite by side mode" begin y = collect(1.0:length(x)) for side in (:left, :right, :nearest) - itp = constant_interp(x, y; side=side, extrap=:none) + itp = constant_interp(x, y; side=side, extrap=NoExtrap()) I = integrate(itp, 0.2, 0.7) @test isfinite(I) end diff --git a/test/test_integral_allocation.jl b/test/test_integral_allocation.jl index 37980c04..0dfaa603 100644 --- a/test/test_integral_allocation.jl +++ b/test/test_integral_allocation.jl @@ -12,7 +12,7 @@ using FastInterpolations @testset "linear 1D: zero allocation" begin x = collect(range(0.0, 1.0, length=21)) y = @. 3x - 1 - itp = linear_interp(x, y; extrap=:none) + itp = linear_interp(x, y; extrap=NoExtrap()) a, b = 0.15, 0.85 # Warmup @@ -30,7 +30,7 @@ using FastInterpolations @testset "quadratic 1D: zero allocation" begin x = collect(range(0.0, 1.0, length=21)) y = @. 2x^2 - x + 4 - itp = quadratic_interp(x, y; extrap=:none) + itp = quadratic_interp(x, y; extrap=NoExtrap()) a, b = 0.1, 0.9 # Warmup @@ -49,7 +49,7 @@ using FastInterpolations x = collect(range(0.0, 1.0, length=21)) y = collect(1.0:length(x)) for side in (:left, :right, :nearest) - itp = constant_interp(x, y; side=side, extrap=:none) + itp = constant_interp(x, y; side=side, extrap=NoExtrap()) a, b = 0.2, 0.7 # Warmup @@ -87,7 +87,7 @@ using FastInterpolations @testset "cubic 1D: zero allocation (baseline)" begin x = collect(range(0.0, 1.0, length=21)) y = sin.(2π .* x) - itp = cubic_interp(x, y; extrap=:none) + itp = cubic_interp(x, y; extrap=NoExtrap()) a, b = 0.15, 0.85 # Warmup diff --git a/test/test_integral_cubic_1d.jl b/test/test_integral_cubic_1d.jl index 00df9ab3..59eeba13 100644 --- a/test/test_integral_cubic_1d.jl +++ b/test/test_integral_cubic_1d.jl @@ -4,7 +4,7 @@ using FastInterpolations @testset "integrate cubic 1d in-domain" begin x = collect(range(0.0, 1.0, length=41)) y = @. x^3 - 2x + 1 - itp = cubic_interp(x, y; extrap=:none) + itp = cubic_interp(x, y; extrap=NoExtrap()) @testset "full-domain parity" begin @test integrate(itp) ≈ integrate(itp, first(x), last(x)) atol=1e-12 diff --git a/test/test_integral_extrap.jl b/test/test_integral_extrap.jl index ee86272a..31debb34 100644 --- a/test/test_integral_extrap.jl +++ b/test/test_integral_extrap.jl @@ -6,7 +6,7 @@ using FastInterpolations @testset ":none throws outside domain" begin y = @. sin(2pi*x) + 0.1x - itp = cubic_interp(x, y; extrap=:none) + itp = cubic_interp(x, y; extrap=NoExtrap()) @test_throws DomainError integrate(itp, -0.2, 0.3) @test_throws DomainError integrate(itp, 0.2, 1.2) # fully in-domain should still work @@ -15,58 +15,58 @@ using FastInterpolations @testset ":constant tails (linear)" begin y = @. x^2 + 1.0 # y[1] = 1.0, y[end] = 2.0 - itp = linear_interp(x, y; extrap=:constant) + itp = linear_interp(x, y; extrap=ConstExtrap()) # pure left tail @test integrate(itp, -0.4, 0.0) ≈ y[1] * 0.4 atol=1e-12 # pure right tail @test integrate(itp, 1.0, 1.6) ≈ y[end] * 0.6 atol=1e-12 # mixed: left tail + in-domain - in_part = integrate(linear_interp(x, y; extrap=:none), 0.0, 0.5) + in_part = integrate(linear_interp(x, y; extrap=NoExtrap()), 0.0, 0.5) @test integrate(itp, -0.3, 0.5) ≈ y[1] * 0.3 + in_part atol=1e-12 end @testset ":constant tails (cubic)" begin y = @. x^2 + 1.0 - itp = cubic_interp(x, y; extrap=:constant) + itp = cubic_interp(x, y; extrap=ConstExtrap()) @test integrate(itp, -0.5, 0.0) ≈ y[1] * 0.5 atol=1e-12 @test integrate(itp, 1.0, 1.3) ≈ y[end] * 0.3 atol=1e-12 end @testset ":constant tails (constant interp, side=:left)" begin # y[1]=1.0, y[2]≈1.001, y[end-1]≈1.999, y[end]=2.0 - # With side=:left, extrap=:constant must use y[1] (left) and y[end] (right) + # With side=:left, extrap=ConstExtrap() must use y[1] (left) and y[end] (right) y = @. x^2 + 1.0 - itp = constant_interp(x, y; side=:left, extrap=:constant) + itp = constant_interp(x, y; side=:left, extrap=ConstExtrap()) # pure left tail @test integrate(itp, -0.4, 0.0) ≈ y[1] * 0.4 atol=1e-12 # pure right tail @test integrate(itp, 1.0, 1.6) ≈ y[end] * 0.6 atol=1e-12 # mixed: left tail + in-domain - in_part = integrate(constant_interp(x, y; side=:left, extrap=:none), 0.0, 0.5) + in_part = integrate(constant_interp(x, y; side=:left, extrap=NoExtrap()), 0.0, 0.5) @test integrate(itp, -0.3, 0.5) ≈ y[1] * 0.3 + in_part atol=1e-12 end @testset ":constant tails (constant interp, side=:right)" begin y = @. x^2 + 1.0 - itp = constant_interp(x, y; side=:right, extrap=:constant) + itp = constant_interp(x, y; side=:right, extrap=ConstExtrap()) # pure left tail — must use y[1], NOT y[2] @test integrate(itp, -0.4, 0.0) ≈ y[1] * 0.4 atol=1e-12 # pure right tail — must use y[end], NOT y[end-1] @test integrate(itp, 1.0, 1.6) ≈ y[end] * 0.6 atol=1e-12 # mixed: right tail + in-domain - in_part = integrate(constant_interp(x, y; side=:right, extrap=:none), 0.5, 1.0) + in_part = integrate(constant_interp(x, y; side=:right, extrap=NoExtrap()), 0.5, 1.0) @test integrate(itp, 0.5, 1.3) ≈ in_part + y[end] * 0.3 atol=1e-12 end @testset ":constant signed orientation" begin y = @. x^2 + 1.0 - itp = linear_interp(x, y; extrap=:constant) + itp = linear_interp(x, y; extrap=ConstExtrap()) @test integrate(itp, 0.0, -0.4) ≈ -(y[1] * 0.4) atol=1e-12 end @testset ":wrap periodic consistency" begin y = @. sin(2pi*x) + 0.1x - itp = cubic_interp(x, y; extrap=:wrap) + itp = cubic_interp(x, y; extrap=WrapExtrap()) p = x[end] - x[1] Iperiod = integrate(itp, x[1], x[end]) Ilong = integrate(itp, -0.2, -0.2 + 3p) @@ -75,7 +75,7 @@ using FastInterpolations @testset ":wrap boundary crossing" begin y = @. sin(2pi*x) + 0.1x - itp = cubic_interp(x, y; extrap=:wrap) + itp = cubic_interp(x, y; extrap=WrapExtrap()) # crossing one boundary I1 = integrate(itp, 0.8, 1.0) I2 = integrate(itp, 0.0, 0.3) @@ -86,7 +86,7 @@ using FastInterpolations # For f(x) = 3x - 1 on [0,1], extension IS the same line, # so the integral over extended domain matches the analytical value. y = @. 3x - 1 - itp = linear_interp(x, y; extrap=:extension) + itp = linear_interp(x, y; extrap=ExtendExtrap()) a, b = -0.5, 1.6 expected = 1.5*b^2 - b - (1.5*a^2 - a) # ∫(3x-1)dx = 3x²/2 - x @test integrate(itp, a, b) ≈ expected atol=1e-12 @@ -96,7 +96,7 @@ using FastInterpolations # With CubicFit BC, cubic polynomial is reproduced exactly, # so the boundary polynomial IS the original function. y = @. x^3 - 2x + 1 - itp = cubic_interp(x, y; bc=CubicFit(), extrap=:extension) + itp = cubic_interp(x, y; bc=CubicFit(), extrap=ExtendExtrap()) a, b = -0.3, 1.4 expected = (b^4/4 - b^2 + b) - (a^4/4 - a^2 + a) # ∫(x³-2x+1)dx @test integrate(itp, a, b) ≈ expected atol=1e-8 @@ -104,7 +104,7 @@ using FastInterpolations @testset ":extension additivity across boundary" begin y = @. sin(2pi*x) + 0.1x - itp = cubic_interp(x, y; extrap=:extension) + itp = cubic_interp(x, y; extrap=ExtendExtrap()) # left boundary crossing @test integrate(itp, -0.3, 0.5) ≈ integrate(itp, -0.3, 0.0) + integrate(itp, 0.0, 0.5) atol=1e-12 @@ -115,14 +115,14 @@ using FastInterpolations @testset ":extension antisymmetry" begin y = @. sin(2pi*x) + 0.1x - itp = cubic_interp(x, y; extrap=:extension) + itp = cubic_interp(x, y; extrap=ExtendExtrap()) @test integrate(itp, -0.3, 1.4) ≈ -integrate(itp, 1.4, -0.3) atol=1e-12 end @testset ":extension agrees with :none in-domain" begin y = @. x^2 + 1.0 - itp_ext = cubic_interp(x, y; extrap=:extension) - itp_none = cubic_interp(x, y; extrap=:none) + itp_ext = cubic_interp(x, y; extrap=ExtendExtrap()) + itp_none = cubic_interp(x, y; extrap=NoExtrap()) @test integrate(itp_ext, 0.2, 0.8) ≈ integrate(itp_none, 0.2, 0.8) atol=1e-12 end end diff --git a/test/test_integral_fulldomain.jl b/test/test_integral_fulldomain.jl index bd1ee7f6..410c6889 100644 --- a/test/test_integral_fulldomain.jl +++ b/test/test_integral_fulldomain.jl @@ -10,28 +10,28 @@ using FastInterpolations y_quad = @. 2x^2 - x + 4 y_const = collect(1.0:length(x)) - itp_c = cubic_interp(x, y_cubic; extrap=:none) - itp_l = linear_interp(x, y_linear; extrap=:none) - itp_q = quadratic_interp(x, y_quad; extrap=:none) + itp_c = cubic_interp(x, y_cubic; extrap=NoExtrap()) + itp_l = linear_interp(x, y_linear; extrap=NoExtrap()) + itp_q = quadratic_interp(x, y_quad; extrap=NoExtrap()) @test integrate(itp_c) ≈ integrate(itp_c, first(x), last(x)) atol=1e-14 @test integrate(itp_l) ≈ integrate(itp_l, first(x), last(x)) atol=1e-14 @test integrate(itp_q) ≈ integrate(itp_q, first(x), last(x)) atol=1e-14 for side in (:left, :right, :nearest) - itp_k = constant_interp(x, y_const; side=side, extrap=:none) + itp_k = constant_interp(x, y_const; side=side, extrap=NoExtrap()) @test integrate(itp_k) ≈ integrate(itp_k, first(x), last(x)) atol=1e-14 end end @testset "1D analytical exactness" begin y_linear = @. 3x + 1 - itp_l = linear_interp(x, y_linear; extrap=:none) + itp_l = linear_interp(x, y_linear; extrap=NoExtrap()) expected_linear = 1.5 * last(x)^2 + last(x) - (1.5 * first(x)^2 + first(x)) @test integrate(itp_l) ≈ expected_linear atol=1e-12 y_cubic = @. x^3 - 2x + 1 - itp_c = cubic_interp(x, y_cubic; bc=CubicFit(), extrap=:none) + itp_c = cubic_interp(x, y_cubic; bc=CubicFit(), extrap=NoExtrap()) expected_cubic = (last(x)^4/4 - last(x)^2 + last(x)) - (first(x)^4/4 - first(x)^2 + first(x)) @test integrate(itp_c) ≈ expected_cubic atol=1e-10 end @@ -76,21 +76,21 @@ using FastInterpolations data_2d = [sin(xi) * cos(yj) for xi in xg, yj in yg] @testset "cubic ND" begin - itp = cubic_interp((xg, yg), data_2d; extrap=(:none, :none)) + itp = cubic_interp((xg, yg), data_2d; extrap=(NoExtrap(), NoExtrap())) lo = (first(xg), first(yg)) hi = (last(xg), last(yg)) @test integrate(itp) ≈ integrate(itp, lo, hi) atol=1e-10 end @testset "linear ND" begin - itp = linear_interp((xg, yg), data_2d; extrap=(:none, :none)) + itp = linear_interp((xg, yg), data_2d; extrap=(NoExtrap(), NoExtrap())) lo = (first(xg), first(yg)) hi = (last(xg), last(yg)) @test integrate(itp) ≈ integrate(itp, lo, hi) atol=1e-10 end @testset "quadratic ND" begin - itp = quadratic_interp((xg, yg), data_2d; extrap=(:none, :none)) + itp = quadratic_interp((xg, yg), data_2d; extrap=(NoExtrap(), NoExtrap())) lo = (first(xg), first(yg)) hi = (last(xg), last(yg)) @test integrate(itp) ≈ integrate(itp, lo, hi) atol=1e-10 @@ -98,7 +98,7 @@ using FastInterpolations @testset "constant ND" begin for side in ((:left, :left), (:right, :right), (:nearest, :nearest)) - itp = constant_interp((xg, yg), data_2d; side=side, extrap=(:none, :none)) + itp = constant_interp((xg, yg), data_2d; side=side, extrap=(NoExtrap(), NoExtrap())) lo = (first(xg), first(yg)) hi = (last(xg), last(yg)) @test integrate(itp) ≈ integrate(itp, lo, hi) atol=1e-10 @@ -108,13 +108,13 @@ using FastInterpolations @testset "1D zero-allocation" begin y = @. 3x + 1 - itp_l = linear_interp(x, y; extrap=:none) + itp_l = linear_interp(x, y; extrap=NoExtrap()) integrate(itp_l) # warmup alloc = @allocated integrate(itp_l) @test alloc <= ALLOC_THRESHOLD y_c = @. x^3 - 2x + 1 - itp_c = cubic_interp(x, y_c; extrap=:none) + itp_c = cubic_interp(x, y_c; extrap=NoExtrap()) integrate(itp_c) alloc_c = @allocated integrate(itp_c) @test alloc_c <= ALLOC_THRESHOLD diff --git a/test/test_integral_nd.jl b/test/test_integral_nd.jl index cde82785..330188af 100644 --- a/test/test_integral_nd.jl +++ b/test/test_integral_nd.jl @@ -7,7 +7,7 @@ using FastInterpolations @testset "linear nd exact on multilinear field" begin data = [2xi - 3yj + 1 for xi in x, yj in y] - itp = linear_interp((x, y), data; extrap=(:none, :none)) + itp = linear_interp((x, y), data; extrap=(NoExtrap(), NoExtrap())) lo, hi = (0.2, 0.3), (0.9, 1.4) expected = ((hi[1]^2 - lo[1]^2) * (hi[2] - lo[2])) - @@ -18,7 +18,7 @@ using FastInterpolations @testset "quadratic nd exact on separable field" begin data = [xi^2 + 2yj^2 for xi in x, yj in y] - itp = quadratic_interp((x, y), data; extrap=(:none, :none)) + itp = quadratic_interp((x, y), data; extrap=(NoExtrap(), NoExtrap())) lo, hi = (0.1, 0.4), (0.8, 1.6) expected = ((hi[1]^3 - lo[1]^3)/3) * (hi[2] - lo[2]) + @@ -29,7 +29,7 @@ using FastInterpolations @testset "constant nd finite by side mode" begin data = [sin(xi) + cos(yj) for xi in x, yj in y] for side in ((:left, :left), (:right, :right), (:nearest, :nearest)) - itp = constant_interp((x, y), data; side=side, extrap=(:none, :none)) + itp = constant_interp((x, y), data; side=side, extrap=(NoExtrap(), NoExtrap())) @test isfinite(integrate(itp, (0.2, 0.3), (0.8, 1.7))) end end diff --git a/test/test_integral_nd_cubic.jl b/test/test_integral_nd_cubic.jl index 402a7280..f1b7354b 100644 --- a/test/test_integral_nd_cubic.jl +++ b/test/test_integral_nd_cubic.jl @@ -5,7 +5,7 @@ using FastInterpolations x = collect(range(0.0, 2.0, length=31)) y = collect(range(-1.0, 1.0, length=29)) data = [sin(xi) * cos(yj) for xi in x, yj in y] - itp = cubic_interp((x, y), data; extrap=(:none, :none)) + itp = cubic_interp((x, y), data; extrap=(NoExtrap(), NoExtrap())) @testset "full-domain parity" begin lo = (first(x), first(y)) diff --git a/test/test_integral_nd_exactness.jl b/test/test_integral_nd_exactness.jl index 436d2c84..eaa3c3b2 100644 --- a/test/test_integral_nd_exactness.jl +++ b/test/test_integral_nd_exactness.jl @@ -19,7 +19,7 @@ using FastInterpolations x = collect(range(0.0, 2.0, length=21)) y = collect(range(0.0, 3.0, length=17)) data = [xi*yj + 2xi - 3yj + 5 for xi in x, yj in y] - itp = linear_interp((x, y), data; extrap=:none) + itp = linear_interp((x, y), data; extrap=NoExtrap()) lo, hi = (0.3, 0.5), (1.7, 2.4) X1 = hi[1] - lo[1]; X2 = (hi[1]^2 - lo[1]^2) / 2 @@ -33,7 +33,7 @@ using FastInterpolations x = collect(range(0.0, 2.0, length=21)) y = collect(range(0.0, 3.0, length=17)) data = [xi*yj + 2xi - 3yj + 5 for xi in x, yj in y] - itp = linear_interp((x, y), data; extrap=:none) + itp = linear_interp((x, y), data; extrap=NoExtrap()) lo = (first(x), first(y)) hi = (last(x), last(y)) @@ -47,7 +47,7 @@ using FastInterpolations x = collect(range(0.0, 2.0, length=31)) y = collect(range(0.0, 3.0, length=25)) data = [(xi^2 + 1) * (yj^2 + 1) for xi in x, yj in y] - itp = quadratic_interp((x, y), data; extrap=:none) + itp = quadratic_interp((x, y), data; extrap=NoExtrap()) lo, hi = (0.2, 0.4), (1.6, 2.5) Ix = (hi[1]^3 - lo[1]^3) / 3 + (hi[1] - lo[1]) @@ -60,7 +60,7 @@ using FastInterpolations x = collect(range(0.0, 2.0, length=31)) y = collect(range(0.0, 3.0, length=25)) data = [xi^2 + xi*yj + yj^2 for xi in x, yj in y] - itp = quadratic_interp((x, y), data; extrap=:none) + itp = quadratic_interp((x, y), data; extrap=NoExtrap()) lo, hi = (0.2, 0.4), (1.6, 2.5) X1 = hi[1] - lo[1]; X2 = (hi[1]^2 - lo[1]^2) / 2; X3 = (hi[1]^3 - lo[1]^3) / 3 @@ -74,7 +74,7 @@ using FastInterpolations x = collect(range(0.0, 2.0, length=41)) y = collect(range(0.0, 3.0, length=37)) data = [(xi^3 - xi) * (yj^3 - yj) for xi in x, yj in y] - itp = cubic_interp((x, y), data; bc=CubicFit(), extrap=:none) + itp = cubic_interp((x, y), data; bc=CubicFit(), extrap=NoExtrap()) lo, hi = (0.3, 0.4), (1.7, 2.6) Ix = (hi[1]^4 - lo[1]^4) / 4 - (hi[1]^2 - lo[1]^2) / 2 @@ -87,7 +87,7 @@ using FastInterpolations x = collect(range(0.0, 2.0, length=41)) y = collect(range(0.0, 3.0, length=37)) data = [xi^2*yj + xi*yj^2 + xi + yj for xi in x, yj in y] - itp = cubic_interp((x, y), data; bc=CubicFit(), extrap=:none) + itp = cubic_interp((x, y), data; bc=CubicFit(), extrap=NoExtrap()) lo, hi = (0.3, 0.4), (1.7, 2.6) X1 = hi[1] - lo[1]; X2 = (hi[1]^2 - lo[1]^2) / 2 @@ -103,7 +103,7 @@ using FastInterpolations x = collect(range(0.0, 2.0, length=51)) y = collect(range(0.0, 2.0, length=51)) data = [xi^3 * yj^3 for xi in x, yj in y] - itp = cubic_interp((x, y), data; bc=CubicFit(), extrap=:none) + itp = cubic_interp((x, y), data; bc=CubicFit(), extrap=NoExtrap()) lo, hi = (0.3, 0.3), (1.7, 1.7) X4 = (hi[1]^4 - lo[1]^4) / 4 @@ -121,7 +121,7 @@ using FastInterpolations y = collect(range(0.0, 3.0, length=13)) z = collect(range(0.0, 1.0, length=9)) data = [2xi + 3yj - zk + 4 for xi in x, yj in y, zk in z] - itp = linear_interp((x, y, z), data; extrap=:none) + itp = linear_interp((x, y, z), data; extrap=NoExtrap()) lo, hi = (0.3, 0.5, 0.1), (1.7, 2.4, 0.8) X1 = hi[1] - lo[1]; X2 = (hi[1]^2 - lo[1]^2) / 2 @@ -136,7 +136,7 @@ using FastInterpolations y = collect(range(0.0, 3.0, length=13)) z = collect(range(0.0, 1.0, length=9)) data = [xi*yj*zk + xi*yj + yj*zk + xi*zk for xi in x, yj in y, zk in z] - itp = linear_interp((x, y, z), data; extrap=:none) + itp = linear_interp((x, y, z), data; extrap=NoExtrap()) lo, hi = (0.3, 0.5, 0.1), (1.7, 2.4, 0.8) X1 = hi[1] - lo[1]; X2 = (hi[1]^2 - lo[1]^2) / 2 @@ -152,7 +152,7 @@ using FastInterpolations y = collect(range(0.0, 3.0, length=13)) z = collect(range(0.0, 1.0, length=9)) data = [2xi + 3yj - zk + 4 for xi in x, yj in y, zk in z] - itp = linear_interp((x, y, z), data; extrap=:none) + itp = linear_interp((x, y, z), data; extrap=NoExtrap()) lo = (first(x), first(y), first(z)) hi = (last(x), last(y), last(z)) @@ -168,7 +168,7 @@ using FastInterpolations y = collect(range(0.0, 3.0, length=15)) z = collect(range(0.0, 1.0, length=11)) data = [xi^2 + 2yj^2 + 3zk^2 for xi in x, yj in y, zk in z] - itp = quadratic_interp((x, y, z), data; extrap=:none) + itp = quadratic_interp((x, y, z), data; extrap=NoExtrap()) lo, hi = (0.2, 0.4, 0.1), (1.8, 2.5, 0.9) X1 = hi[1] - lo[1]; X3 = (hi[1]^3 - lo[1]^3) / 3 @@ -184,7 +184,7 @@ using FastInterpolations z = collect(range(0.0, 1.0, length=11)) data = [xi*yj + yj*zk + xi*zk + xi^2 + yj^2 + zk^2 for xi in x, yj in y, zk in z] - itp = quadratic_interp((x, y, z), data; extrap=:none) + itp = quadratic_interp((x, y, z), data; extrap=NoExtrap()) lo, hi = (0.2, 0.4, 0.1), (1.8, 2.5, 0.9) X1 = hi[1] - lo[1]; X2 = (hi[1]^2 - lo[1]^2) / 2; X3 = (hi[1]^3 - lo[1]^3) / 3 @@ -200,7 +200,7 @@ using FastInterpolations y = collect(range(0.0, 3.0, length=15)) z = collect(range(0.0, 1.0, length=11)) data = [xi^2 * yj^2 * zk^2 for xi in x, yj in y, zk in z] - itp = quadratic_interp((x, y, z), data; extrap=:none) + itp = quadratic_interp((x, y, z), data; extrap=NoExtrap()) lo, hi = (0.2, 0.4, 0.1), (1.8, 2.5, 0.9) X3 = (hi[1]^3 - lo[1]^3) / 3 @@ -215,7 +215,7 @@ using FastInterpolations y = collect(range(0.0, 2.0, length=21)) z = collect(range(0.0, 1.0, length=17)) data = [xi^3 + yj^3 + zk^3 for xi in x, yj in y, zk in z] - itp = cubic_interp((x, y, z), data; bc=CubicFit(), extrap=:none) + itp = cubic_interp((x, y, z), data; bc=CubicFit(), extrap=NoExtrap()) lo, hi = (0.2, 0.3, 0.1), (1.8, 1.7, 0.9) X1 = hi[1] - lo[1]; X4 = (hi[1]^4 - lo[1]^4) / 4 @@ -230,7 +230,7 @@ using FastInterpolations y = collect(range(0.0, 2.0, length=21)) z = collect(range(0.0, 1.0, length=17)) data = [xi^2*yj + yj^2*zk + zk^2*xi for xi in x, yj in y, zk in z] - itp = cubic_interp((x, y, z), data; bc=CubicFit(), extrap=:none) + itp = cubic_interp((x, y, z), data; bc=CubicFit(), extrap=NoExtrap()) lo, hi = (0.2, 0.3, 0.1), (1.8, 1.7, 0.9) X1 = hi[1] - lo[1]; X2 = (hi[1]^2 - lo[1]^2) / 2; X3 = (hi[1]^3 - lo[1]^3) / 3 @@ -246,7 +246,7 @@ using FastInterpolations y = collect(range(0.0, 2.0, length=25)) z = collect(range(0.0, 1.0, length=17)) data = [xi^2 * yj^2 * zk^2 for xi in x, yj in y, zk in z] - itp = cubic_interp((x, y, z), data; bc=CubicFit(), extrap=:none) + itp = cubic_interp((x, y, z), data; bc=CubicFit(), extrap=NoExtrap()) lo, hi = (0.2, 0.3, 0.1), (1.8, 1.7, 0.9) X3 = (hi[1]^3 - lo[1]^3) / 3 @@ -266,7 +266,7 @@ using FastInterpolations z = collect(range(0.0, 1.0, length=7)) data = fill(7.0, length(x), length(y), length(z)) for side in (:left, :right, :nearest) - itp = constant_interp((x, y, z), data; side=side, extrap=:none) + itp = constant_interp((x, y, z), data; side=side, extrap=NoExtrap()) lo, hi = (0.3, 0.5, 0.1), (1.7, 2.4, 0.8) expected = 7.0 * (hi[1]-lo[1]) * (hi[2]-lo[2]) * (hi[3]-lo[3]) @test integrate(itp, lo, hi) ≈ expected atol=1e-12 @@ -279,7 +279,7 @@ using FastInterpolations z = collect(range(0.0, 1.0, length=7)) data = [sin(xi) + cos(yj) + zk for xi in x, yj in y, zk in z] for side in (:left, :right, :nearest) - itp = constant_interp((x, y, z), data; side=side, extrap=:none) + itp = constant_interp((x, y, z), data; side=side, extrap=NoExtrap()) @test isfinite(integrate(itp, (0.3, 0.5, 0.1), (1.7, 2.4, 0.8))) end end @@ -293,7 +293,7 @@ using FastInterpolations y = collect(range(-1.0, 1.0, length=15)) z = collect(range(0.0, 1.5, length=13)) data = [sin(xi) * cos(yj) * exp(zk/2) for xi in x, yj in y, zk in z] - itp = cubic_interp((x, y, z), data; extrap=:none) + itp = cubic_interp((x, y, z), data; extrap=NoExtrap()) @testset "full-domain parity" begin lo = (first(x), first(y), first(z)) @@ -357,7 +357,7 @@ using FastInterpolations y = collect(range(0.0, 3.0, length=13)) z = collect(range(0.0, 1.0, length=9)) data = [sin(xi) * cos(yj) + zk^2 for xi in x, yj in y, zk in z] - itp = linear_interp((x, y, z), data; extrap=:none) + itp = linear_interp((x, y, z), data; extrap=NoExtrap()) @testset "antisymmetry" begin lo, hi = (0.3, 0.5, 0.1), (1.7, 2.4, 0.8) @@ -383,7 +383,7 @@ using FastInterpolations y = collect(range(0.0, 3.0, length=15)) z = collect(range(0.0, 1.0, length=11)) data = [sin(xi) * cos(yj) + zk^2 for xi in x, yj in y, zk in z] - itp = quadratic_interp((x, y, z), data; extrap=:none) + itp = quadratic_interp((x, y, z), data; extrap=NoExtrap()) @testset "antisymmetry" begin lo, hi = (0.2, 0.4, 0.1), (1.8, 2.5, 0.9) diff --git a/test/test_integral_series.jl b/test/test_integral_series.jl index d129b285..391109f7 100644 --- a/test/test_integral_series.jl +++ b/test/test_integral_series.jl @@ -113,43 +113,43 @@ using FastInterpolations y1 = sin.(x) y2 = cos.(x) - @testset "extrap=:none throws DomainError" begin - sitp = cubic_interp(x, [y1, y2]; extrap=:none) + @testset "extrap=NoExtrap() throws DomainError" begin + sitp = cubic_interp(x, [y1, y2]; extrap=NoExtrap()) @test_throws DomainError integrate(sitp, -0.1, 0.5) @test_throws DomainError integrate(sitp, 0.5, 1.1) end - @testset "extrap=:constant" begin - sitp = cubic_interp(x, [y1, y2]; extrap=:constant) - itp1 = cubic_interp(x, y1; extrap=:constant) - itp2 = cubic_interp(x, y2; extrap=:constant) + @testset "extrap=ConstExtrap()" begin + sitp = cubic_interp(x, [y1, y2]; extrap=ConstExtrap()) + itp1 = cubic_interp(x, y1; extrap=ConstExtrap()) + itp2 = cubic_interp(x, y2; extrap=ConstExtrap()) result = integrate(sitp, -0.5, 1.5) @test result[1] ≈ integrate(itp1, -0.5, 1.5) @test result[2] ≈ integrate(itp2, -0.5, 1.5) end - @testset "extrap=:extension" begin - sitp = cubic_interp(x, [y1, y2]; extrap=:extension) - itp1 = cubic_interp(x, y1; extrap=:extension) - itp2 = cubic_interp(x, y2; extrap=:extension) + @testset "extrap=ExtendExtrap()" begin + sitp = cubic_interp(x, [y1, y2]; extrap=ExtendExtrap()) + itp1 = cubic_interp(x, y1; extrap=ExtendExtrap()) + itp2 = cubic_interp(x, y2; extrap=ExtendExtrap()) result = integrate(sitp, -0.1, 1.1) @test result[1] ≈ integrate(itp1, -0.1, 1.1) @test result[2] ≈ integrate(itp2, -0.1, 1.1) end - @testset "extrap=:wrap" begin - sitp = cubic_interp(x, [y1, y2]; extrap=:wrap) - itp1 = cubic_interp(x, y1; extrap=:wrap) - itp2 = cubic_interp(x, y2; extrap=:wrap) + @testset "extrap=WrapExtrap()" begin + sitp = cubic_interp(x, [y1, y2]; extrap=WrapExtrap()) + itp1 = cubic_interp(x, y1; extrap=WrapExtrap()) + itp2 = cubic_interp(x, y2; extrap=WrapExtrap()) result = integrate(sitp, -0.5, 2.5) @test result[1] ≈ integrate(itp1, -0.5, 2.5) @test result[2] ≈ integrate(itp2, -0.5, 2.5) end - @testset "linear extrap=:constant" begin - sitp = linear_interp(x, [y1, y2]; extrap=:constant) - itp1 = linear_interp(x, y1; extrap=:constant) - itp2 = linear_interp(x, y2; extrap=:constant) + @testset "linear extrap=ConstExtrap()" begin + sitp = linear_interp(x, [y1, y2]; extrap=ConstExtrap()) + itp1 = linear_interp(x, y1; extrap=ConstExtrap()) + itp2 = linear_interp(x, y2; extrap=ConstExtrap()) result = integrate(sitp, -0.5, 1.5) @test result[1] ≈ integrate(itp1, -0.5, 1.5) @test result[2] ≈ integrate(itp2, -0.5, 1.5) diff --git a/test/test_linear.jl b/test/test_linear.jl index 5cd16b97..2ac156c0 100644 --- a/test/test_linear.jl +++ b/test/test_linear.jl @@ -24,7 +24,7 @@ y = 2.0 .* collect(x) .+ 1.0 # Linear function y = 2x + 1 x_targets = [-0.2, -0.1, 1.1, 1.2] - result = linear_interp(x, y, x_targets; extrap=:extension) + result = linear_interp(x, y, x_targets; extrap=ExtendExtrap()) # Verify linear extrapolation works correctly # For y = 2x + 1, extrapolated values should follow the same line @@ -39,7 +39,7 @@ y = sin.(x) x_targets = [-0.2, -0.1, 1.1, 1.2] - result = linear_interp(x, y, x_targets; extrap=:constant) + result = linear_interp(x, y, x_targets; extrap=ConstExtrap()) # For constant extrapolation, values outside bounds should match boundary values @test result[1] == y[1] @@ -74,7 +74,7 @@ y = 2x .+ 1 x_targets = [-0.25, 1.5] - result = linear_interp(x, y, x_targets; extrap=:extension) + result = linear_interp(x, y, x_targets; extrap=ExtendExtrap()) # Verify linear extrapolation @test result[1] ≈ 2.0 * (-0.25) + 1.0 @@ -86,7 +86,7 @@ y = [1.0, 3.0, 5.0] x_targets = [-0.25, 1.5] - result = linear_interp(x, y, x_targets; extrap=:constant) + result = linear_interp(x, y, x_targets; extrap=ConstExtrap()) # Constant extrapolation @test result[1] == y[1] @@ -97,13 +97,13 @@ x = [0.0, 0.5, 1.0] y = [1.0, 3.0, 5.0] - # Default extrapolation is :none, should throw DomainError + # Default extrapolation is NoExtrap(), should throw DomainError @test_throws DomainError linear_interp(x, y, -0.1) @test_throws DomainError linear_interp(x, y, 1.1) # Explicit :none also throws - @test_throws DomainError linear_interp(x, y, -0.5; extrap=:none) - @test_throws DomainError linear_interp(x, y, 1.5; extrap=:none) + @test_throws DomainError linear_interp(x, y, -0.5; extrap=NoExtrap()) + @test_throws DomainError linear_interp(x, y, 1.5; extrap=NoExtrap()) # Vector query - first out-of-domain point throws @test_throws DomainError linear_interp(x, y, [-0.1, 0.5]) @@ -128,22 +128,6 @@ @test linear_interp(x, y, 1.0) ≈ 5.0 end - @testset "Invalid extrap symbol - ArgumentError" begin - x = [0.0, 0.5, 1.0] - y = [1.0, 3.0, 5.0] - - # Invalid extrap symbol should throw ArgumentError - @test_throws ArgumentError linear_interp(x, y, 0.5; extrap=:invalid) - @test_throws ArgumentError linear_interp(x, y, 0.5; extrap=:foo) - @test_throws ArgumentError linear_interp(x, y, [0.5]; extrap=:invalid) - - # In-place version - output = zeros(1) - @test_throws ArgumentError linear_interp!(output, x, y, [0.5]; extrap=:invalid) - - # Interpolant via linear_interp(x, y) - @test_throws ArgumentError linear_interp(x, y; extrap=:invalid) - end @testset "Edge cases - Exact matches at grid points" begin x = 0.0:0.1:1.0 @@ -151,7 +135,7 @@ x_targets = [0.0, 0.3, 0.5, 0.7, 1.0] # Use :extension to allow boundary evaluation (1.0 may need slight extension) - result = linear_interp(x, y, x_targets; extrap=:extension) + result = linear_interp(x, y, x_targets; extrap=ExtendExtrap()) # Exact matches should give exact values @test result[1] ≈ 0.0^2 @@ -343,7 +327,7 @@ end y = sin.(x) # Use :extension to handle floating point boundary issues - itp = linear_interp(x, y; extrap=:extension) + itp = linear_interp(x, y; extrap=ExtendExtrap()) rho1 = [0.25, 0.5] rho2 = [0.75, 0.85] @@ -353,9 +337,9 @@ end result2 = itp.(rho2) result3 = itp(rho3) - @test result1 == linear_interp(x, y, rho1; extrap=:extension) - @test result2 == linear_interp(x, y, rho2; extrap=:extension) - @test result3 == linear_interp(x, y, rho3; extrap=:extension) + @test result1 == linear_interp(x, y, rho1; extrap=ExtendExtrap()) + @test result2 == linear_interp(x, y, rho2; extrap=ExtendExtrap()) + @test result3 == linear_interp(x, y, rho3; extrap=ExtendExtrap()) end @testset "Extrapolation :extension" begin @@ -363,13 +347,13 @@ end y = 2.0 .* x .+ 1.0 x_targets = [-0.25, 1.5] - itp = linear_interp(x, y; extrap=:extension) + itp = linear_interp(x, y; extrap=ExtendExtrap()) result = itp.(x_targets) @test result[1] ≈ 2.0 * (-0.25) + 1.0 @test result[2] ≈ 2.0 * 1.5 + 1.0 - expected = linear_interp(x, y, x_targets; extrap=:extension) + expected = linear_interp(x, y, x_targets; extrap=ExtendExtrap()) @test result == expected end @@ -378,13 +362,13 @@ end y = [1.0, 3.0, 5.0] x_targets = [-0.25, 1.5] - itp = linear_interp(x, y; extrap=:constant) + itp = linear_interp(x, y; extrap=ConstExtrap()) result = itp.(x_targets) @test result[1] == y[1] @test result[2] == y[end] - expected = linear_interp(x, y, x_targets; extrap=:constant) + expected = linear_interp(x, y, x_targets; extrap=ConstExtrap()) @test result == expected end @@ -520,12 +504,12 @@ end y_int = [2*i + 1 for i in x_int] x_targets = [-1.0, 6.0] - result_ext = linear_interp(x_int, y_int, x_targets; extrap=:extension) + result_ext = linear_interp(x_int, y_int, x_targets; extrap=ExtendExtrap()) @test result_ext isa Vector{Float64} @test result_ext[1] ≈ 2.0 * (-1.0) + 1.0 @test result_ext[2] ≈ 2.0 * 6.0 + 1.0 - result_const = linear_interp(x_int, y_int, x_targets; extrap=:constant) + result_const = linear_interp(x_int, y_int, x_targets; extrap=ConstExtrap()) @test result_const[1] ≈ y_int[1] @test result_const[2] ≈ y_int[end] end @@ -616,7 +600,7 @@ end @test output[2] ≈ 5.5^2 atol=1 # Test with constant extrapolation - linear_interp!(output, x, y, x_query; extrap=:constant) + linear_interp!(output, x, y, x_query; extrap=ConstExtrap()) @test length(output) == 3 end diff --git a/test/test_linear_anchor.jl b/test/test_linear_anchor.jl index 3dbd153e..5662e030 100644 --- a/test/test_linear_anchor.jl +++ b/test/test_linear_anchor.jl @@ -88,7 +88,7 @@ using FastInterpolations @testset "itp(aq) evaluation matches itp(xq)" begin x = collect(range(0.0, 2π, 101)) y = sin.(x) - itp = linear_interp(x, y; extrap=:extension) + itp = linear_interp(x, y; extrap=ExtendExtrap()) xq_points = [0.5, 1.0, 2.0, 3.0, 5.5] @@ -104,7 +104,7 @@ using FastInterpolations @testset "itp(aq; deriv=1) derivative evaluation" begin x = collect(range(0.0, 2π, 101)) y = sin.(x) - itp = linear_interp(x, y; extrap=:extension) + itp = linear_interp(x, y; extrap=ExtendExtrap()) xq_points = [0.5, 1.0, 2.0, 3.0, 5.5] @@ -117,7 +117,7 @@ using FastInterpolations # ======================================== # Wrap Mode Tests # ======================================== - @testset "wrap mode for extrap=:wrap" begin + @testset "wrap mode for extrap=WrapExtrap()" begin x = collect(range(0.0, 1.0, 11)) # domain [0, 1] # Query outside domain with wrap=true @@ -132,7 +132,7 @@ using FastInterpolations # Verify wrapped evaluation matches y = sin.(2π .* x) - itp = linear_interp(x, y; extrap=:wrap) + itp = linear_interp(x, y; extrap=WrapExtrap()) aq = FastInterpolations._anchor_query(x, 1.5, Val(:linear); wrap=true) @test itp(aq) ≈ itp(1.5) end @@ -194,7 +194,7 @@ using FastInterpolations @testset "in-place vector evaluation with anchors" begin x = collect(range(0.0, 2π, 101)) y = sin.(x) - itp = linear_interp(x, y; extrap=:extension) + itp = linear_interp(x, y; extrap=ExtendExtrap()) xq_vec = [0.5, 1.0, 2.0, 3.0, 5.5] aq_vec = FastInterpolations._anchor_query(x, xq_vec, Val(:linear)) @@ -217,7 +217,7 @@ using FastInterpolations # Non-uniform grid x = [0.0, 0.1, 0.3, 0.6, 1.0] y = x .^ 2 - itp = linear_interp(x, y; extrap=:extension) + itp = linear_interp(x, y; extrap=ExtendExtrap()) xq = 0.45 # interval [0.3, 0.6] aq = FastInterpolations._anchor_query(x, xq, Val(:linear)) @@ -237,7 +237,7 @@ using FastInterpolations @testset "zero-allocation with pre-built anchors" begin x = collect(range(0.0, 2π, 101)) y = sin.(x) - itp = linear_interp(x, y; extrap=:extension) + itp = linear_interp(x, y; extrap=ExtendExtrap()) xq_vec = collect(range(0.1, 6.0, 100)) aq_vec = FastInterpolations._anchor_query(x, xq_vec, Val(:linear)) @@ -252,12 +252,12 @@ using FastInterpolations end # ======================================== - # extrap=:none DomainError Tests + # extrap=NoExtrap() DomainError Tests # ======================================== - @testset "extrap=:none throws DomainError via anchor" begin + @testset "extrap=NoExtrap() throws DomainError via anchor" begin x = collect(range(0.0, 1.0, 11)) y = sin.(2π .* x) - itp = linear_interp(x, y; extrap=:none) + itp = linear_interp(x, y; extrap=NoExtrap()) # Inside domain works aq_inside = FastInterpolations._anchor_query(x, 0.5, Val(:linear)) @@ -276,12 +276,12 @@ using FastInterpolations end # ======================================== - # extrap=:constant Tests + # extrap=ConstExtrap() Tests # ======================================== - @testset "extrap=:constant via anchor" begin + @testset "extrap=ConstExtrap() via anchor" begin x = collect(range(0.0, 1.0, 11)) y = sin.(2π .* x) - itp = linear_interp(x, y; extrap=:constant) + itp = linear_interp(x, y; extrap=ConstExtrap()) # Below domain returns first y aq_below = FastInterpolations._anchor_query(x, -0.5, Val(:linear)) @@ -305,7 +305,7 @@ using FastInterpolations x = collect(range(0.0, 1.0, 11)) y = sin.(2π .* x) - for extrap in [:extension, :constant] + for extrap in [ExtendExtrap(), ConstExtrap()] itp = linear_interp(x, y; extrap=extrap) xq_vec = [-0.2, 0.3, 0.7, 1.2] # Mix of inside/outside aq_vec = FastInterpolations._anchor_query(x, xq_vec, Val(:linear)) @@ -322,7 +322,7 @@ using FastInterpolations @testset "in-place output length assertion" begin x = collect(range(0.0, 1.0, 11)) y = sin.(2π .* x) - itp = linear_interp(x, y; extrap=:extension) + itp = linear_interp(x, y; extrap=ExtendExtrap()) xq_vec = [0.2, 0.5, 0.8] aq_vec = FastInterpolations._anchor_query(x, xq_vec, Val(:linear)) @@ -338,7 +338,7 @@ using FastInterpolations @testset "zero-allocation with deriv=1" begin x = collect(range(0.0, 2π, 101)) y = sin.(x) - itp = linear_interp(x, y; extrap=:extension) + itp = linear_interp(x, y; extrap=ExtendExtrap()) xq_vec = collect(range(0.1, 6.0, 100)) aq_vec = FastInterpolations._anchor_query(x, xq_vec, Val(:linear)) diff --git a/test/test_linear_series_interp.jl b/test/test_linear_series_interp.jl index 02d399d5..9f17856f 100644 --- a/test/test_linear_series_interp.jl +++ b/test/test_linear_series_interp.jl @@ -128,20 +128,20 @@ const FI = FastInterpolations x = collect(0.0:0.1:1.0) ys = [sin.(2π .* x)] - @testset "extrap=:none throws" begin - sitp = linear_interp(x, ys; extrap=:none) + @testset "extrap=NoExtrap() throws" begin + sitp = linear_interp(x, ys; extrap=NoExtrap()) @test_throws DomainError sitp(-0.1) @test_throws DomainError sitp(1.1) end - @testset "extrap=:constant returns boundary" begin - sitp = linear_interp(x, ys; extrap=:constant) + @testset "extrap=ConstExtrap() returns boundary" begin + sitp = linear_interp(x, ys; extrap=ConstExtrap()) @test sitp(-0.1)[1] ≈ sin(0.0) atol=1e-6 @test sitp(1.1)[1] ≈ sin(2π) atol=1e-6 end - @testset "extrap=:extension extrapolates" begin - sitp = linear_interp(x, ys; extrap=:extension) + @testset "extrap=ExtendExtrap() extrapolates" begin + sitp = linear_interp(x, ys; extrap=ExtendExtrap()) @test sitp(-0.1) isa Vector{Float64} @test sitp(1.1) isa Vector{Float64} end @@ -368,15 +368,15 @@ const FI = FastInterpolations y1 = sin.(2π .* x) y2 = cos.(2π .* x) - @testset "vector :none extrapolation throws" begin - sitp = linear_interp(x, [y1, y2]; extrap=:none) + @testset "vector NoExtrap() extrapolation throws" begin + sitp = linear_interp(x, [y1, y2]; extrap=NoExtrap()) xq = [-0.1, 0.5, 1.1] @test_throws DomainError sitp(xq) end - @testset "vector :constant extrapolation" begin - sitp = linear_interp(x, [y1, y2]; extrap=:constant) + @testset "vector ConstExtrap() extrapolation" begin + sitp = linear_interp(x, [y1, y2]; extrap=ConstExtrap()) xq = [-0.1, 0.5, 1.1] outputs = [zeros(3), zeros(3)] @@ -387,8 +387,8 @@ const FI = FastInterpolations @test outputs[1][3] ≈ y1[end] atol=1e-10 end - @testset "vector :extension extrapolation" begin - sitp = linear_interp(x, [y1, y2]; extrap=:extension) + @testset "vector ExtendExtrap() extrapolation" begin + sitp = linear_interp(x, [y1, y2]; extrap=ExtendExtrap()) xq = [-0.1, 0.5, 1.1] outputs = [zeros(3), zeros(3)] @@ -398,8 +398,8 @@ const FI = FastInterpolations @test !any(isnan, outputs[2]) end - @testset "vector :constant extrapolation with derivatives" begin - sitp = linear_interp(x, [y1, y2]; extrap=:constant) + @testset "vector ConstExtrap() extrapolation with derivatives" begin + sitp = linear_interp(x, [y1, y2]; extrap=ConstExtrap()) xq = [-0.1, 0.5, 1.1] # deriv=1 outside domain should be zero for constant extrap diff --git a/test/test_nd_comprehensive.jl b/test/test_nd_comprehensive.jl index f75bb9be..b7e8a6da 100644 --- a/test/test_nd_comprehensive.jl +++ b/test/test_nd_comprehensive.jl @@ -240,8 +240,8 @@ using FastInterpolations y = range(0.0, 1.0, 6) data = [xi + yj for xi in x, yj in y] # Simple linear function - @testset ":constant extrapolation" begin - itp = cubic_interp((x, y), data; extrap=:constant) + @testset "ConstExtrap() extrapolation" begin + itp = cubic_interp((x, y), data; extrap=ConstExtrap()) # Left boundary clamp @test itp((-0.5, 0.5)) ≈ itp((0.0, 0.5)) @@ -257,7 +257,7 @@ using FastInterpolations @testset "Per-axis extrapolation" begin # :constant on x, :none on y - itp = cubic_interp((x, y), data; extrap=(:constant, :none)) + itp = cubic_interp((x, y), data; extrap=(ConstExtrap(), NoExtrap())) # x outside domain should clamp @test itp((-0.5, 0.5)) ≈ itp((0.0, 0.5)) @@ -265,7 +265,7 @@ using FastInterpolations @test_throws DomainError itp((1.0, 1.5)) end - @testset ":wrap extrapolation (with PeriodicBC)" begin + @testset "WrapExtrap() extrapolation (with PeriodicBC)" begin # Periodic data that wraps correctly x = range(0.0, 2π, 21) # First and last are same modulo 2π y = range(0.0, 2π, 21) @@ -273,7 +273,7 @@ using FastInterpolations # sin and cos are periodic data = [sin(xi) * cos(yj) for xi in x, yj in y] - itp = cubic_interp((x, y), data; bc=PeriodicBC(), extrap=:wrap) + itp = cubic_interp((x, y), data; bc=PeriodicBC(), extrap=WrapExtrap()) # Should wrap around xq = 2π + 0.5 # Past domain @@ -309,8 +309,8 @@ using FastInterpolations @testset "Extrap resolution error paths" begin # Wrong number of extrap modes - rejected by keyword type assertion - @test_throws TypeError cubic_interp((x, y), data; extrap=(:none,)) - @test_throws TypeError cubic_interp((x, y), data; extrap=(:none, :none, :none)) + @test_throws TypeError cubic_interp((x, y), data; extrap=(NoExtrap(),)) + @test_throws TypeError cubic_interp((x, y), data; extrap=(NoExtrap(), NoExtrap(), NoExtrap())) end @testset "Search resolution error paths" begin @@ -811,7 +811,7 @@ using FastInterpolations data = rand(11, 6) itp = cubic_interp((x, y), data) - @testset "Domain errors with :none extrap" begin + @testset "Domain errors with NoExtrap() extrap" begin @test_throws DomainError itp((-0.1, 0.5)) @test_throws DomainError itp((1.1, 0.5)) @test_throws DomainError itp((0.5, -0.1)) diff --git a/test/test_nd_constant.jl b/test/test_nd_constant.jl index c914e870..3226e3e3 100644 --- a/test/test_nd_constant.jl +++ b/test/test_nd_constant.jl @@ -203,8 +203,8 @@ end y = [0.0, 1.0, 2.0] data = [1.0 2.0 3.0; 4.0 5.0 6.0; 7.0 8.0 9.0] - @testset "extrap=:none (domain error)" begin - itp = constant_interp((x, y), data; extrap=:none) + @testset "extrap=NoExtrap() (domain error)" begin + itp = constant_interp((x, y), data; extrap=NoExtrap()) # In domain - OK @test itp((0.5, 0.5)) == 1.0 @@ -216,8 +216,8 @@ end @test_throws DomainError itp((0.5, 2.1)) end - @testset "extrap=:constant" begin - itp = constant_interp((x, y), data; extrap=:constant, side=:left) + @testset "extrap=ConstExtrap()" begin + itp = constant_interp((x, y), data; extrap=ConstExtrap(), side=:left) # In domain @test itp((0.5, 0.5)) == 1.0 @@ -233,8 +233,8 @@ end @test itp((0.5, 2.5)) == 2.0 # Clamp y to 2 → interval 2, data[1,2] end - @testset "extrap=:wrap" begin - itp = constant_interp((x, y), data; extrap=:wrap, side=:left) + @testset "extrap=WrapExtrap()" begin + itp = constant_interp((x, y), data; extrap=WrapExtrap(), side=:left) # In domain @test itp((0.5, 0.5)) == 1.0 @@ -245,8 +245,8 @@ end end @testset "per-axis extrap configuration" begin - # extrap=(:none, :constant) → strict on x, clamp on y - itp = constant_interp((x, y), data; extrap=(:none, :constant), side=:left) + # extrap=(NoExtrap(), ConstExtrap()) → strict on x, clamp on y + itp = constant_interp((x, y), data; extrap=(NoExtrap(), ConstExtrap()), side=:left) # y clamped to 2.0 → data[1, 2] = 2.0 @test itp((0.5, 2.5)) == 2.0 # y clamped to last interval @@ -478,7 +478,7 @@ end @test _alloc_test_constant_right() <= ND_ALLOC_THRESHOLD end - @testset "zero-alloc scalar (Range grids, extrap=:constant)" begin + @testset "zero-alloc scalar (Range grids, extrap=ConstExtrap())" begin @test _alloc_test_constant_extrap_constant() <= ND_ALLOC_THRESHOLD end diff --git a/test/test_nd_coverage.jl b/test/test_nd_coverage.jl index 98f41bc0..3345fff7 100644 --- a/test/test_nd_coverage.jl +++ b/test/test_nd_coverage.jl @@ -243,13 +243,13 @@ import FastInterpolations: @testset "nd_utils.jl" begin @testset "_resolve_extrap_nd wrong-sized tuple error" begin - # Correct size should work - @test _resolve_extrap_nd(:none, Val(2)) == (:none, :none) - @test _resolve_extrap_nd((:none, :constant), Val(2)) == (:none, :constant) + # Correct size should work (3-arg form: extrap, bcs, Val(N)) + @test _resolve_extrap_nd(NoExtrap(), nothing, Val(2)) == (NoExtrap(), NoExtrap()) + @test _resolve_extrap_nd((NoExtrap(), ConstExtrap()), nothing, Val(2)) == (NoExtrap(), ConstExtrap()) # Wrong size should throw - @test_throws ArgumentError _resolve_extrap_nd((:none,), Val(2)) # 1 element for 2D - @test_throws ArgumentError _resolve_extrap_nd((:none, :none, :none), Val(2)) # 3 for 2D + @test_throws ArgumentError _resolve_extrap_nd((NoExtrap(),), nothing, Val(2)) # 1 element for 2D + @test_throws ArgumentError _resolve_extrap_nd((NoExtrap(), NoExtrap(), NoExtrap()), nothing, Val(2)) # 3 for 2D end @testset "_resolve_search_nd wrong-sized tuple error" begin @@ -847,25 +847,25 @@ end end end -@testset "core/utils.jl — @_dispatch_extrap_nd paths" begin +@testset "ND extrapolation dispatch paths" begin grids = (collect(range(0.0, 1.0, 6)), collect(range(0.0, 1.0, 6))) data = [xi + yj for xi in grids[1], yj in grids[2]] - @testset "fast path 1: :wrap extrap with bcs=nothing (linear oneshot)" begin - # Exercises the `ntuple(_ -> Val(:wrap), valn)` branch (fast path 1 :wrap) - result = linear_interp(grids, data, (0.5, 0.5); extrap=:wrap) + @testset "fast path 1: WrapExtrap() extrap with bcs=nothing (linear oneshot)" begin + # Uniform WrapExtrap on all dims — exercises periodic wrap fast path + result = linear_interp(grids, data, (0.5, 0.5); extrap=WrapExtrap()) @test result ≈ 1.0 atol=1e-10 end @testset "fallback: non-uniform extraps with bcs=nothing (linear oneshot)" begin - # Exercises _resolve_mixed_extrap_vals(extraps, ::Nothing) + fallback path - result = linear_interp(grids, data, (0.5, 0.5); extrap=(:none, :constant)) + # Mixed extrap types per dim — exercises per-dim extrap dispatch fallback + result = linear_interp(grids, data, (0.5, 0.5); extrap=(NoExtrap(), ConstExtrap())) @test result ≈ 1.0 atol=1e-10 end - @testset "fast path 3: :wrap extrap with mixed BCs (cubic oneshot)" begin - # bc=(PeriodicBC(), NaturalBC()) + extrap=:wrap → fast path 3 :wrap branch - # (some periodic, not all → not fast path 2; uniform extrap → fast path 3) + @testset "fast path 3: WrapExtrap() extrap with mixed BCs (cubic oneshot)" begin + # bc=(PeriodicBC(), NaturalBC()) + extrap=WrapExtrap() + # Some periodic, not all → not fast path 2; uniform extrap → fast path 3 x = collect(range(0.0, 2π, 9)) y = collect(range(0.0, 1.0, 9)) data_p = [cos(xi) + yj for xi in x, yj in y] @@ -873,13 +873,13 @@ end # Query is interior: cos(π/2) + 0.5 ≈ 0.5 result = cubic_interp((x, y), data_p, (π/2, 0.5); - bc=(PeriodicBC(), NaturalBC()), extrap=:wrap) + bc=(PeriodicBC(), NaturalBC()), extrap=WrapExtrap()) @test result ≈ 0.5 atol=0.01 end @testset "fallback: non-uniform extraps with mixed BCs (cubic oneshot)" begin - # bc=(PeriodicBC(), NaturalBC()) + extrap=(:none,:constant) → fallback path - # Exercises _resolve_mixed_extrap_vals(extraps, bcs::NTuple{N,AbstractBC}) + # bc=(PeriodicBC(), NaturalBC()) + extrap=(NoExtrap(),ConstExtrap()) + # Mixed extrap types per dim — exercises per-dim extrap dispatch fallback x = collect(range(0.0, 2π, 9)) y = collect(range(0.0, 1.0, 9)) data_p = [cos(xi) + yj for xi in x, yj in y] @@ -887,7 +887,7 @@ end # Query is interior: cos(π/2) + 0.5 ≈ 0.5 (extrap mode doesn't affect interior) result = cubic_interp((x, y), data_p, (π/2, 0.5); - bc=(PeriodicBC(), NaturalBC()), extrap=(:none, :constant)) + bc=(PeriodicBC(), NaturalBC()), extrap=(NoExtrap(), ConstExtrap())) @test result ≈ 0.5 atol=0.01 end end diff --git a/test/test_nd_heterogeneous_grids.jl b/test/test_nd_heterogeneous_grids.jl index ac237302..301a4d49 100644 --- a/test/test_nd_heterogeneous_grids.jl +++ b/test/test_nd_heterogeneous_grids.jl @@ -332,7 +332,7 @@ using FastInterpolations itp = quadratic_interp((x_range, y_vec), data; bc=Right(QuadraticFit()), - extrap=(:constant, :extension)) + extrap=(ConstExtrap(), ExtendExtrap())) @test itp((1.0, 0.5)) ≈ f(1.0, 0.5) atol=1e-8 @test itp((-0.1, 0.5)) ≈ itp((0.0, 0.5)) rtol=1e-10 @test isfinite(itp((1.0, 1.5))) @@ -371,10 +371,10 @@ using FastInterpolations y_vec = [0.0, 0.3, 0.6, 0.8, 1.0] data = [f(xi, yj) for xi in x_range, yj in y_vec] - # Per-axis extrapolation: :constant on x, :extension on y + # Per-axis extrapolation: ConstExtrap() on x, ExtendExtrap() on y itp = cubic_interp((x_range, y_vec), data; bc=CubicFit(), - extrap=(:constant, :extension)) + extrap=(ConstExtrap(), ExtendExtrap())) # Interior should work normally @test itp((1.0, 0.5); deriv=(1, 0)) ≈ 0.5 atol=1e-6 diff --git a/test/test_nd_linear.jl b/test/test_nd_linear.jl index 2d44f024..7439b953 100644 --- a/test/test_nd_linear.jl +++ b/test/test_nd_linear.jl @@ -193,15 +193,15 @@ end y = [0.0, 1.0, 2.0] data = [xi + yj for xi in x, yj in y] - @testset "extrap=:none (domain error)" begin - itp = linear_interp((x, y), data; extrap=:none) + @testset "extrap=NoExtrap() (domain error)" begin + itp = linear_interp((x, y), data; extrap=NoExtrap()) @test_throws DomainError itp((-0.1, 0.5)) @test_throws DomainError itp((0.5, 2.1)) @test_throws DomainError itp((-0.1, -0.1)) end - @testset "extrap=:constant" begin - itp = linear_interp((x, y), data; extrap=:constant) + @testset "extrap=ConstExtrap()" begin + itp = linear_interp((x, y), data; extrap=ConstExtrap()) # Query beyond domain should clamp to boundary @test itp((-0.5, 0.5)) ≈ itp((0.0, 0.5)) @test itp((2.5, 0.5)) ≈ itp((2.0, 0.5)) @@ -209,21 +209,21 @@ end @test itp((0.5, 2.5)) ≈ itp((0.5, 2.0)) end - @testset "extrap=:extension" begin - itp = linear_interp((x, y), data; extrap=:extension) + @testset "extrap=ExtendExtrap()" begin + itp = linear_interp((x, y), data; extrap=ExtendExtrap()) # Linear extension beyond domain @test itp((-0.5, 0.5)) ≈ -0.5 + 0.5 # Linear extrapolation @test itp((2.5, 0.5)) ≈ 2.5 + 0.5 end - @testset "extrap=:wrap" begin - itp = linear_interp((x, y), data; extrap=:wrap) + @testset "extrap=WrapExtrap()" begin + itp = linear_interp((x, y), data; extrap=WrapExtrap()) # Wrapping should work @test itp((2.5, 0.5)) ≈ itp((0.5, 0.5)) # 2.5 wraps to 0.5 end @testset "per-axis extrap configuration" begin - itp = linear_interp((x, y), data; extrap=(:none, :constant)) + itp = linear_interp((x, y), data; extrap=(NoExtrap(), ConstExtrap())) # x has :none, y has :constant @test itp((0.5, 2.5)) == itp((0.5, 2.0)) # y clamped @test_throws DomainError itp((2.5, 0.5)) # x throws @@ -517,11 +517,11 @@ end @test _alloc_test_linear_deriv_val() <= ND_ALLOC_THRESHOLD end - @testset "zero-alloc scalar (Range grids, extrap=:constant)" begin + @testset "zero-alloc scalar (Range grids, extrap=ConstExtrap())" begin @test _alloc_test_linear_extrap_constant() <= ND_ALLOC_THRESHOLD end - @testset "zero-alloc scalar (Range grids, extrap=:extension)" begin + @testset "zero-alloc scalar (Range grids, extrap=ExtendExtrap())" begin @test _alloc_test_linear_extrap_extension() <= ND_ALLOC_THRESHOLD end diff --git a/test/test_nd_quadratic.jl b/test/test_nd_quadratic.jl index e978c02c..9b26d7f7 100644 --- a/test/test_nd_quadratic.jl +++ b/test/test_nd_quadratic.jl @@ -180,7 +180,7 @@ end f(xi, yi) = xi^2 + yi^2 data = [f(xi, yi) for xi in x, yi in y] - @testset "extrap=:none (default)" begin + @testset "extrap=NoExtrap() (default)" begin itp = quadratic_interp((x, y), data; bc=Right(QuadraticFit())) @test_throws DomainError itp((-0.1, 0.5)) @test_throws DomainError itp((0.5, -0.1)) @@ -188,18 +188,18 @@ end @test_throws DomainError itp((0.5, 1.1)) end - @testset "extrap=:constant" begin + @testset "extrap=ConstExtrap()" begin itp = quadratic_interp((x, y), data; - bc=Right(QuadraticFit()), extrap=:constant) + bc=Right(QuadraticFit()), extrap=ConstExtrap()) @test itp((-0.1, 0.5)) ≈ itp((0.0, 0.5)) @test itp((2.1, 0.5)) ≈ itp((2.0, 0.5)) @test itp((0.5, 1.1)) ≈ itp((0.5, 1.0)) @test itp((0.5, -0.1)) ≈ itp((0.5, 0.0)) end - @testset "extrap=:extension" begin + @testset "extrap=ExtendExtrap()" begin itp = quadratic_interp((x, y), data; - bc=Right(QuadraticFit()), extrap=:extension) + bc=Right(QuadraticFit()), extrap=ExtendExtrap()) @test isfinite(itp((-0.1, 0.5))) @test isfinite(itp((2.5, 1.5))) end @@ -207,7 +207,7 @@ end @testset "per-axis extrap" begin itp = quadratic_interp((x, y), data; bc=Right(QuadraticFit()), - extrap=(:constant, :extension)) + extrap=(ConstExtrap(), ExtendExtrap())) @test itp((-0.1, 0.5)) ≈ itp((0.0, 0.5)) rtol=1e-10 @test isfinite(itp((1.0, 1.5))) end @@ -586,7 +586,7 @@ end @test _alloc_test_quadratic_natural_bc() <= ND_ALLOC_THRESHOLD end - @testset "zero-alloc scalar (Range grids, extrap=:constant)" begin + @testset "zero-alloc scalar (Range grids, extrap=ConstExtrap())" begin @test _alloc_test_quadratic_extrap_constant() <= ND_ALLOC_THRESHOLD end diff --git a/test/test_nd_utils_shared.jl b/test/test_nd_utils_shared.jl index d6e6f9d8..856a918f 100644 --- a/test/test_nd_utils_shared.jl +++ b/test/test_nd_utils_shared.jl @@ -24,38 +24,10 @@ import FastInterpolations: _resolve_extrap_nd, _resolve_search_nd, _resolve_bcs_ # ======================================== # _resolve_extrap_nd # ======================================== - @testset "_resolve_extrap_nd" begin - @testset "broadcast single symbol to N-tuple" begin - # Single symbol should broadcast to all axes - result = _resolve_extrap_nd(:none, Val(3)) - @test result === (:none, :none, :none) - - result = _resolve_extrap_nd(:wrap, Val(2)) - @test result === (:wrap, :wrap) - - result = _resolve_extrap_nd(:constant, Val(4)) - @test result === (:constant, :constant, :constant, :constant) - end - - @testset "passthrough matching tuple" begin - # Matching N-tuple should pass through - result = _resolve_extrap_nd((:none, :wrap, :constant), Val(3)) - @test result === (:none, :wrap, :constant) - end - - @testset "reject wrong-length tuple" begin - # Wrong-length tuple should throw ArgumentError - @test_throws ArgumentError _resolve_extrap_nd((:none, :wrap), Val(3)) - @test_throws ArgumentError _resolve_extrap_nd((:none, :wrap, :constant, :extension), Val(3)) - @test_throws ArgumentError _resolve_extrap_nd((:none,), Val(2)) - end - - @testset "reject invalid symbol" begin - # Invalid symbol should throw ArgumentError - @test_throws ArgumentError _resolve_extrap_nd(:invalid, Val(2)) - @test_throws ArgumentError _resolve_extrap_nd((:none, :invalid), Val(2)) - end - end + # NOTE: Old 2-arg _resolve_extrap_nd(extrap, Val(N)) tests removed. + # Symbol-based extrap was removed in v0.3.0. + # The 3-arg form _resolve_extrap_nd(extrap, bcs, Val(N)) is tested below + # in "Typed Extrap resolution". # ======================================== # _resolve_search_nd @@ -322,9 +294,8 @@ import FastInterpolations: _resolve_extrap_nd, _resolve_search_nd, _resolve_bcs_ @test_throws ArgumentError _resolve_extrap_nd((NoExtrap(), ConstExtrap()), bcs, Val(2)) end - # Note: Symbol 3-arg _resolve_extrap_nd was removed in the fast/legacy refactor. - # Symbol dispatch now happens at the public API level (constructor/oneshot), - # which calls the 2-arg _resolve_extrap_nd(extrap, Val(N)) internally. + # Symbol-based extrap was fully removed in v0.3.0. + # Only AbstractExtrap types are accepted. @testset "_check_mode_periodic_compat" begin bcs = (NaturalBC(), PeriodicBC(), NaturalBC()) diff --git a/test/test_nonuniform_grid.jl b/test/test_nonuniform_grid.jl index 6ed7829f..5138d9da 100644 --- a/test/test_nonuniform_grid.jl +++ b/test/test_nonuniform_grid.jl @@ -149,13 +149,13 @@ const LINEAR = TestPolynomial{Float64}( @testset "extension" begin xi_extrap = [x_min - 1.0, x_max + 1.0] - result = linear_interp(x, y, xi_extrap; extrap=:extension) + result = linear_interp(x, y, xi_extrap; extrap=ExtendExtrap()) @test all(isfinite, result) end @testset "constant" begin xi_extrap = [x_min - 1.0, x_max + 1.0] - result = linear_interp(x, y, xi_extrap; extrap=:constant) + result = linear_interp(x, y, xi_extrap; extrap=ConstExtrap()) @test result[1] ≈ y[1] @test result[2] ≈ y[end] end @@ -456,7 +456,7 @@ end y = sin.(x) y[end] = y[1] - itp = cubic_interp(x, y; bc=PeriodicBC(), extrap=:wrap) + itp = cubic_interp(x, y; bc=PeriodicBC(), extrap=WrapExtrap()) # Query outside domain should wrap period = x[end] - x[1] diff --git a/test/test_packages_comparison.jl b/test/test_packages_comparison.jl index abd1afaa..81132e12 100644 --- a/test/test_packages_comparison.jl +++ b/test/test_packages_comparison.jl @@ -111,8 +111,8 @@ const APPROX_REL_TOLERANCCE = 1e-14 # Use linear function for predictable extrapolation y = target_f.(x) - # FastInterpolations (explicit extrap=:extension) - result_fast = linear_interp(x, y, xq_with_extrap; extrap=:extension) + # FastInterpolations (explicit extrap=ExtendExtrap()) + result_fast = linear_interp(x, y, xq_with_extrap; extrap=ExtendExtrap()) # DataInterpolations.jl with extrapolation itp = DI.LinearInterpolation(y, x; extrapolation=DI.ExtrapolationType.Extension) @@ -173,8 +173,8 @@ const APPROX_REL_TOLERANCCE = 1e-14 @testset "Grid: $grid_name" begin y = target_f.(x) - # FastInterpolations (explicit extrap=:extension) - result_fast = cubic_interp(x, y, xq_with_extrap; extrap=:extension) + # FastInterpolations (explicit extrap=ExtendExtrap()) + result_fast = cubic_interp(x, y, xq_with_extrap; extrap=ExtendExtrap()) # DataInterpolations.jl with extrapolation itp = DI.CubicSpline(y, x; extrapolation=DI.ExtrapolationType.Extension) diff --git a/test/test_periodic_bc.jl b/test/test_periodic_bc.jl index 46ccef17..cdaddb91 100644 --- a/test/test_periodic_bc.jl +++ b/test/test_periodic_bc.jl @@ -11,23 +11,23 @@ using FastInterpolations @testset "Basic wrapping" begin # Interior point - @test linear_interp(x, y, π/4; extrap=:wrap) ≈ sin(π/4) atol=1e-3 + @test linear_interp(x, y, π/4; extrap=WrapExtrap()) ≈ sin(π/4) atol=1e-3 # Outside domain - should wrap # xi = 2π + 0.5 wraps to 0.5 - @test linear_interp(x, y, 2π + 0.5; extrap=:wrap) ≈ linear_interp(x, y, 0.5; extrap=:wrap) atol=1e-10 + @test linear_interp(x, y, 2π + 0.5; extrap=WrapExtrap()) ≈ linear_interp(x, y, 0.5; extrap=WrapExtrap()) atol=1e-10 # Negative - should wrap # xi = -0.5 wraps to 2π - 0.5 - @test linear_interp(x, y, -0.5; extrap=:wrap) ≈ linear_interp(x, y, 2π - 0.5; extrap=:wrap) atol=1e-10 + @test linear_interp(x, y, -0.5; extrap=WrapExtrap()) ≈ linear_interp(x, y, 2π - 0.5; extrap=WrapExtrap()) atol=1e-10 # Multiple periods - @test linear_interp(x, y, 4π + 1.0; extrap=:wrap) ≈ linear_interp(x, y, 1.0; extrap=:wrap) atol=1e-10 + @test linear_interp(x, y, 4π + 1.0; extrap=WrapExtrap()) ≈ linear_interp(x, y, 1.0; extrap=WrapExtrap()) atol=1e-10 end @testset "Vector interface" begin x_query = [0.5, 2π + 0.5, -0.5, 4π + 1.0] - result = linear_interp(x, y, x_query; extrap=:wrap) + result = linear_interp(x, y, x_query; extrap=WrapExtrap()) @test result[1] ≈ sin(0.5) atol=1e-3 @test result[2] ≈ sin(0.5) atol=1e-3 # 2π + 0.5 wraps to 0.5 @@ -35,21 +35,21 @@ using FastInterpolations # Fast path: all queries inside domain [x_min, x_max) → uses extension path inside_query = [0.5, 1.0, 2.0] - inside_result = linear_interp(x, y, inside_query; extrap=:wrap) + inside_result = linear_interp(x, y, inside_query; extrap=WrapExtrap()) @test inside_result ≈ sin.(inside_query) atol=1e-3 end @testset "In-place interface" begin out = Vector{Float64}(undef, 3) x_query = [0.5, 2π + 0.5, -0.5] - linear_interp!(out, x, y, x_query; extrap=:wrap) + linear_interp!(out, x, y, x_query; extrap=WrapExtrap()) @test out[1] ≈ sin(0.5) atol=1e-3 @test out[2] ≈ out[1] atol=1e-10 # Wrapped to same position end @testset "LinearInterpolant with wrap extrap" begin - itp = linear_interp(x, y; extrap=:wrap) + itp = linear_interp(x, y; extrap=WrapExtrap()) # Test scalar calls @test itp(0.5) ≈ sin(0.5) atol=1e-3 @@ -63,8 +63,8 @@ using FastInterpolations @testset "Continuity at boundary" begin # Check values just before and after boundary ε = 1e-6 - val_before = linear_interp(x, y, 2π - ε; extrap=:wrap) - val_after = linear_interp(x, y, 0.0 + ε; extrap=:wrap) + val_before = linear_interp(x, y, 2π - ε; extrap=WrapExtrap()) + val_after = linear_interp(x, y, 0.0 + ε; extrap=WrapExtrap()) # For sin, both should be close to 0 @test abs(val_before) < 1e-3 @@ -73,7 +73,7 @@ using FastInterpolations end @testset "Cubic Natural BC with Wrap Extrapolation" begin - # bc=NaturalBC() uses natural BC coefficients, but extrap=:wrap wraps coordinates + # bc=NaturalBC() uses natural BC coefficients, but extrap=WrapExtrap() wraps coordinates # Unlike bc=PeriodicBC(), this does NOT check y[1] ≈ y[end] N = 101 @@ -82,25 +82,25 @@ using FastInterpolations @testset "Basic wrapping with natural BC" begin # Interior point - @test cubic_interp(x, y_sin, π/4; bc=NaturalBC(), extrap=:wrap) ≈ sin(π/4) atol=1e-4 + @test cubic_interp(x, y_sin, π/4; bc=NaturalBC(), extrap=WrapExtrap()) ≈ sin(π/4) atol=1e-4 # Outside domain - should wrap - val_in = cubic_interp(x, y_sin, 0.5; bc=NaturalBC(), extrap=:wrap) - val_wrapped = cubic_interp(x, y_sin, 2π + 0.5; bc=NaturalBC(), extrap=:wrap) + val_in = cubic_interp(x, y_sin, 0.5; bc=NaturalBC(), extrap=WrapExtrap()) + val_wrapped = cubic_interp(x, y_sin, 2π + 0.5; bc=NaturalBC(), extrap=WrapExtrap()) @test val_in ≈ val_wrapped atol=1e-10 # Negative - should wrap - val_neg = cubic_interp(x, y_sin, -0.5; bc=NaturalBC(), extrap=:wrap) - val_equiv = cubic_interp(x, y_sin, 2π - 0.5; bc=NaturalBC(), extrap=:wrap) + val_neg = cubic_interp(x, y_sin, -0.5; bc=NaturalBC(), extrap=WrapExtrap()) + val_equiv = cubic_interp(x, y_sin, 2π - 0.5; bc=NaturalBC(), extrap=WrapExtrap()) @test val_neg ≈ val_equiv atol=1e-10 # Multiple periods - @test cubic_interp(x, y_sin, 4π + 1.0; bc=NaturalBC(), extrap=:wrap) ≈ cubic_interp(x, y_sin, 1.0; bc=NaturalBC(), extrap=:wrap) atol=1e-10 + @test cubic_interp(x, y_sin, 4π + 1.0; bc=NaturalBC(), extrap=WrapExtrap()) ≈ cubic_interp(x, y_sin, 1.0; bc=NaturalBC(), extrap=WrapExtrap()) atol=1e-10 end @testset "Vector and in-place interface" begin x_query = [0.5, 2π + 0.5, -0.5, 4π + 1.0] - result = cubic_interp(x, y_sin, x_query; bc=NaturalBC(), extrap=:wrap) + result = cubic_interp(x, y_sin, x_query; bc=NaturalBC(), extrap=WrapExtrap()) @test result[1] ≈ sin(0.5) atol=1e-4 @test result[2] ≈ result[1] atol=1e-10 # 2π + 0.5 wraps to 0.5 @@ -108,12 +108,12 @@ using FastInterpolations # In-place cache = CubicSplineCache(x; bc=NaturalBC()) out = similar(result) - cubic_interp!(out, cache, collect(y_sin), x_query; extrap=:wrap) + cubic_interp!(out, cache, collect(y_sin), x_query; extrap=WrapExtrap()) @test out ≈ result atol=1e-10 end @testset "CubicInterpolant with wrap extrap" begin - itp = cubic_interp(x, y_sin; bc=NaturalBC(), extrap=:wrap) + itp = cubic_interp(x, y_sin; bc=NaturalBC(), extrap=WrapExtrap()) # Test scalar calls @test itp(π/4) ≈ sin(π/4) atol=1e-4 @@ -126,14 +126,14 @@ using FastInterpolations @testset "Sawtooth/triangle wave pattern (y[1] != y[end])" begin # Linear ramp: y[1] = 0, y[end] = 2π (NOT equal) - # This is the key use case for bc=NaturalBC() + extrap=:wrap + # This is the key use case for bc=NaturalBC() + extrap=WrapExtrap() x_ramp = range(0.0, 1.0, 51) y_ramp = collect(x_ramp) # [0, 0.02, ..., 1.0] @test y_ramp[1] != y_ramp[end] # Confirm endpoints differ # Should NOT throw (unlike bc=PeriodicBC() which requires y[1] ≈ y[end]) - itp = cubic_interp(x_ramp, y_ramp; bc=NaturalBC(), extrap=:wrap) + itp = cubic_interp(x_ramp, y_ramp; bc=NaturalBC(), extrap=WrapExtrap()) # Test wrap behavior @test itp(0.5) ≈ 0.5 atol=1e-4 @@ -154,7 +154,7 @@ using FastInterpolations # but they use DIFFERENT spline coefficients (different BC) # Create interpolants with different BCs - itp_nat = cubic_interp(x, y_sin; bc=NaturalBC(), extrap=:wrap) + itp_nat = cubic_interp(x, y_sin; bc=NaturalBC(), extrap=WrapExtrap()) itp_per = cubic_interp(x, y_sin; bc=PeriodicBC()) # Interior values are similar for periodic functions @@ -175,10 +175,10 @@ using FastInterpolations cache = CubicSplineCache(x; bc=PeriodicBC()) # All extrap values should give the same result - itp_none = cubic_interp(cache, collect(y_sin); extrap=:none) - itp_const = cubic_interp(cache, collect(y_sin); extrap=:constant) - itp_ext = cubic_interp(cache, collect(y_sin); extrap=:extension) - itp_wrap = cubic_interp(cache, collect(y_sin); extrap=:wrap) + itp_none = cubic_interp(cache, collect(y_sin); extrap=NoExtrap()) + itp_const = cubic_interp(cache, collect(y_sin); extrap=ConstExtrap()) + itp_ext = cubic_interp(cache, collect(y_sin); extrap=ExtendExtrap()) + itp_wrap = cubic_interp(cache, collect(y_sin); extrap=WrapExtrap()) # Test outside domain - all should wrap xi_outside = 2π + 0.5 @@ -353,7 +353,7 @@ using FastInterpolations y_base = sin.(x_base) # Linear wrap should still work - @test linear_interp(x_base, y_base, 2π + 0.5; extrap=:wrap) ≈ linear_interp(x_base, y_base, 0.5; extrap=:wrap) atol=1e-10 + @test linear_interp(x_base, y_base, 2π + 0.5; extrap=WrapExtrap()) ≈ linear_interp(x_base, y_base, 0.5; extrap=WrapExtrap()) atol=1e-10 # Cubic periodic should work with Vector grid cache = CubicSplineCache(collect(x_base); bc=PeriodicBC()) @@ -363,7 +363,7 @@ using FastInterpolations end @testset "_check_periodic_endpoints validation (Cubic only)" begin - # NOTE: Linear interpolation with extrap=:wrap does NOT check endpoints! + # NOTE: Linear interpolation with extrap=WrapExtrap() does NOT check endpoints! # Only cubic bc=PeriodicBC() checks that y[1] ≈ y[end] x = range(0.0, 2π, 101) @@ -373,19 +373,19 @@ using FastInterpolations @test y_sin[1] ≈ y_sin[end] atol=1e-12 # Confirm endpoints match # Linear wrap works regardless of endpoint matching - @test linear_interp(x, y_sin, 0.5; extrap=:wrap) isa Float64 + @test linear_interp(x, y_sin, 0.5; extrap=WrapExtrap()) isa Float64 # Cubic bc=PeriodicBC() should not throw for valid periodic data @test cubic_interp(x, y_sin, 0.5; bc=PeriodicBC()) isa Float64 # cos(0) = cos(2π) = 1 y_cos = cos.(x) - @test linear_interp(x, y_cos, 0.5; extrap=:wrap) isa Float64 + @test linear_interp(x, y_cos, 0.5; extrap=WrapExtrap()) isa Float64 # Exactly equal endpoints y_exact = collect(sin.(x)) y_exact[end] = y_exact[1] # Force exact equality - @test linear_interp(x, y_exact, 0.5; extrap=:wrap) isa Float64 + @test linear_interp(x, y_exact, 0.5; extrap=WrapExtrap()) isa Float64 end @testset "Valid periodic data (Float32)" begin @@ -396,7 +396,7 @@ using FastInterpolations @test abs(y_f32[1] - y_f32[end]) < 1f-6 # Should not throw - @test linear_interp(x_f32, y_f32, 0.5f0; extrap=:wrap) isa Float32 + @test linear_interp(x_f32, y_f32, 0.5f0; extrap=WrapExtrap()) isa Float32 @test cubic_interp(x_f32, y_f32, 0.5f0; bc=PeriodicBC()) isa Float32 end @@ -407,8 +407,8 @@ using FastInterpolations @test abs(y_invalid[1] - y_invalid[end]) > 1e-12 # Confirm mismatch # Linear wrap does NOT check endpoints - works fine (sawtooth pattern) - @test linear_interp(x, y_invalid, 0.5; extrap=:wrap) isa Float64 - @test LinearInterpolant(collect(x), y_invalid; extrap=:wrap) isa LinearInterpolant + @test linear_interp(x, y_invalid, 0.5; extrap=WrapExtrap()) isa Float64 + @test LinearInterpolant(collect(x), y_invalid; extrap=WrapExtrap()) isa LinearInterpolant # Cubic bc=PeriodicBC() DOES check endpoints - throws ArgumentError @test_throws ArgumentError cubic_interp(x, y_invalid, 0.5; bc=PeriodicBC()) diff --git a/test/test_polyfit_bc.jl b/test/test_polyfit_bc.jl index 8189a5a6..c19a2983 100644 --- a/test/test_polyfit_bc.jl +++ b/test/test_polyfit_bc.jl @@ -1895,14 +1895,7 @@ end end @testset "BC Types Coverage (bc_types.jl)" begin - # 1. ParabolaFit deprecation - # Check that it warns and returns a QuadraticFit - @test_logs (:warn, r"ParabolaFit is deprecated") begin - bc = FastInterpolations.ParabolaFit() - @test bc isa FastInterpolations.QuadraticFit - end - - # 2. _is_periodic_bc + # 1. _is_periodic_bc @test FastInterpolations._is_periodic_bc(PeriodicBC()) @test !FastInterpolations._is_periodic_bc(NaturalBC()) @test !FastInterpolations._is_periodic_bc(LinearFit()) diff --git a/test/test_precision_vector_queries.jl b/test/test_precision_vector_queries.jl index e4777e27..26a57dc2 100644 --- a/test/test_precision_vector_queries.jl +++ b/test/test_precision_vector_queries.jl @@ -270,7 +270,7 @@ end x = Float32.(collect(range(0.0, 1.0, 11))) y = Float32.(x .^ 2) - itp = linear_interp(x, y; extrap=:none) + itp = linear_interp(x, y; extrap=NoExtrap()) # Float64 query in domain xq_in = [0.1, 0.5, 0.9] diff --git a/test/test_quadratic.jl b/test/test_quadratic.jl index acc6f8b9..98c954f3 100644 --- a/test/test_quadratic.jl +++ b/test/test_quadratic.jl @@ -576,29 +576,29 @@ end @test_throws DomainError quadratic_interp(x, y, 2.5) # :constant - clamp to boundary values (outside domain) - @test quadratic_interp(x, y, -0.5; extrap=:constant) ≈ 0.0 - @test quadratic_interp(x, y, 2.5; extrap=:constant) ≈ 4.0 + @test quadratic_interp(x, y, -0.5; extrap=ConstExtrap()) ≈ 0.0 + @test quadratic_interp(x, y, 2.5; extrap=ConstExtrap()) ≈ 4.0 # :constant - inside domain should work normally (coverage for eval_core path) - @test quadratic_interp(x, y, 1.0; extrap=:constant) ≈ 1.0 + @test quadratic_interp(x, y, 1.0; extrap=ConstExtrap()) ≈ 1.0 # :constant - derivatives return zero outside domain - @test quadratic_interp(x, y, -0.5; extrap=:constant, deriv=1) ≈ 0.0 - @test quadratic_interp(x, y, 2.5; extrap=:constant, deriv=1) ≈ 0.0 - @test quadratic_interp(x, y, -0.5; extrap=:constant, deriv=2) ≈ 0.0 - @test quadratic_interp(x, y, 2.5; extrap=:constant, deriv=2) ≈ 0.0 + @test quadratic_interp(x, y, -0.5; extrap=ConstExtrap(), deriv=1) ≈ 0.0 + @test quadratic_interp(x, y, 2.5; extrap=ConstExtrap(), deriv=1) ≈ 0.0 + @test quadratic_interp(x, y, -0.5; extrap=ConstExtrap(), deriv=2) ≈ 0.0 + @test quadratic_interp(x, y, 2.5; extrap=ConstExtrap(), deriv=2) ≈ 0.0 # :extension - extend the polynomial (right side) - v_ext_right = quadratic_interp(x, y, 2.5; extrap=:extension) + v_ext_right = quadratic_interp(x, y, 2.5; extrap=ExtendExtrap()) @test isfinite(v_ext_right) # :extension - extend the polynomial (left side) - v_ext_left = quadratic_interp(x, y, -0.5; extrap=:extension) + v_ext_left = quadratic_interp(x, y, -0.5; extrap=ExtendExtrap()) @test isfinite(v_ext_left) # :extension derivatives - d1_left = quadratic_interp(x, y, -0.5; extrap=:extension, deriv=1) - d2_left = quadratic_interp(x, y, -0.5; extrap=:extension, deriv=2) + d1_left = quadratic_interp(x, y, -0.5; extrap=ExtendExtrap(), deriv=1) + d2_left = quadratic_interp(x, y, -0.5; extrap=ExtendExtrap(), deriv=2) @test isfinite(d1_left) @test isfinite(d2_left) end @@ -1340,35 +1340,35 @@ end @testset "$name - one-shot API" begin # Left extrapolation - value for xi in xq_left - result = quadratic_interp(x, y, xi; bc=bc, extrap=:extension) + result = quadratic_interp(x, y, xi; bc=bc, extrap=ExtendExtrap()) @test result ≈ f(xi) rtol=1e-12 atol=1e-14 end # Right extrapolation - value for xi in xq_right - result = quadratic_interp(x, y, xi; bc=bc, extrap=:extension) + result = quadratic_interp(x, y, xi; bc=bc, extrap=ExtendExtrap()) @test result ≈ f(xi) rtol=1e-12 atol=1e-14 end # Left extrapolation - derivatives for xi in xq_left - d1 = quadratic_interp(x, y, xi; bc=bc, extrap=:extension, deriv=1) - d2 = quadratic_interp(x, y, xi; bc=bc, extrap=:extension, deriv=2) + d1 = quadratic_interp(x, y, xi; bc=bc, extrap=ExtendExtrap(), deriv=1) + d2 = quadratic_interp(x, y, xi; bc=bc, extrap=ExtendExtrap(), deriv=2) @test d1 ≈ f_d1(xi) rtol=1e-12 atol=1e-14 @test d2 ≈ f_d2 rtol=1e-12 atol=1e-14 end # Right extrapolation - derivatives for xi in xq_right - d1 = quadratic_interp(x, y, xi; bc=bc, extrap=:extension, deriv=1) - d2 = quadratic_interp(x, y, xi; bc=bc, extrap=:extension, deriv=2) + d1 = quadratic_interp(x, y, xi; bc=bc, extrap=ExtendExtrap(), deriv=1) + d2 = quadratic_interp(x, y, xi; bc=bc, extrap=ExtendExtrap(), deriv=2) @test d1 ≈ f_d1(xi) rtol=1e-12 atol=1e-14 @test d2 ≈ f_d2 rtol=1e-12 atol=1e-14 end end @testset "$name - interpolant API" begin - itp = quadratic_interp(x, y; bc=bc, extrap=:extension) + itp = quadratic_interp(x, y; bc=bc, extrap=ExtendExtrap()) d1_view = deriv1(itp) d2_view = deriv2(itp) @@ -1398,12 +1398,12 @@ end # Value at boundary should match from both sides val_inside = quadratic_interp(x, y, 3.0; bc=bc) - val_outside = quadratic_interp(x, y, 3.0 + 1e-10; bc=bc, extrap=:extension) + val_outside = quadratic_interp(x, y, 3.0 + 1e-10; bc=bc, extrap=ExtendExtrap()) @test val_inside ≈ val_outside rtol=1e-8 # Left boundary (value is 0.0, so use atol instead of rtol) val_inside_left = quadratic_interp(x, y, 0.0; bc=bc) - val_outside_left = quadratic_interp(x, y, -1e-10; bc=bc, extrap=:extension) + val_outside_left = quadratic_interp(x, y, -1e-10; bc=bc, extrap=ExtendExtrap()) @test val_inside_left ≈ val_outside_left atol=1e-8 end @@ -1419,16 +1419,16 @@ end expected = f.(xq) # One-shot vector API - result = quadratic_interp(x, y, xq; bc=bc, extrap=:extension) + result = quadratic_interp(x, y, xq; bc=bc, extrap=ExtendExtrap()) @test result ≈ expected rtol=1e-12 # In-place API out = zeros(length(xq)) - quadratic_interp!(out, x, y, xq; bc=bc, extrap=:extension) + quadratic_interp!(out, x, y, xq; bc=bc, extrap=ExtendExtrap()) @test out ≈ expected rtol=1e-12 # Interpolant vector call - itp = quadratic_interp(x, y; bc=bc, extrap=:extension) + itp = quadratic_interp(x, y; bc=bc, extrap=ExtendExtrap()) @test itp(xq) ≈ expected rtol=1e-12 end @@ -1541,12 +1541,12 @@ end y = x.^2 # :extension mode - itp_ext = quadratic_interp(x, y; bc=MinCurvFit(), extrap=:extension) + itp_ext = quadratic_interp(x, y; bc=MinCurvFit(), extrap=ExtendExtrap()) @test isfinite(itp_ext(-0.5)) # outside left @test isfinite(itp_ext(3.5)) # outside right # :constant mode - itp_const = quadratic_interp(x, y; bc=MinCurvFit(), extrap=:constant) + itp_const = quadratic_interp(x, y; bc=MinCurvFit(), extrap=ConstExtrap()) @test itp_const(-0.5) ≈ 0.0 # clamps to y[1] @test itp_const(3.5) ≈ 9.0 # clamps to y[end] end diff --git a/test/test_quadratic_anchor.jl b/test/test_quadratic_anchor.jl index b705346e..8ef11151 100644 --- a/test/test_quadratic_anchor.jl +++ b/test/test_quadratic_anchor.jl @@ -79,7 +79,7 @@ using FastInterpolations @testset "itp(aq) evaluation matches itp(xq)" begin x = collect(range(0.0, 2π, 101)) y = sin.(x) - itp = quadratic_interp(x, y; extrap=:extension) + itp = quadratic_interp(x, y; extrap=ExtendExtrap()) xq_points = [0.5, 1.0, 2.0, 3.0, 5.5] @@ -95,7 +95,7 @@ using FastInterpolations @testset "itp(aq; deriv=1) derivative evaluation" begin x = collect(range(0.0, 2π, 101)) y = sin.(x) - itp = quadratic_interp(x, y; extrap=:extension) + itp = quadratic_interp(x, y; extrap=ExtendExtrap()) xq_points = [0.5, 1.0, 2.0, 3.0, 5.5] @@ -111,7 +111,7 @@ using FastInterpolations @testset "itp(aq; deriv=2) derivative evaluation" begin x = collect(range(0.0, 2π, 101)) y = sin.(x) - itp = quadratic_interp(x, y; extrap=:extension) + itp = quadratic_interp(x, y; extrap=ExtendExtrap()) xq_points = [0.5, 1.0, 2.0, 3.0, 5.5] @@ -129,7 +129,7 @@ using FastInterpolations y = x .^ 2 # Extension mode - itp_ext = quadratic_interp(x, y; extrap=:extension) + itp_ext = quadratic_interp(x, y; extrap=ExtendExtrap()) aq_below = FastInterpolations._anchor_query(x, -0.5, Val(:quadratic)) aq_above = FastInterpolations._anchor_query(x, 1.5, Val(:quadratic)) @@ -137,7 +137,7 @@ using FastInterpolations @test itp_ext(aq_above) ≈ itp_ext(1.5) # Constant mode - itp_const = quadratic_interp(x, y; extrap=:constant) + itp_const = quadratic_interp(x, y; extrap=ConstExtrap()) @test itp_const(aq_below) ≈ itp_const(-0.5) @test itp_const(aq_above) ≈ itp_const(1.5) end @@ -199,7 +199,7 @@ using FastInterpolations @testset "in-place vector evaluation with anchors" begin x = collect(range(0.0, 2π, 101)) y = sin.(x) - itp = quadratic_interp(x, y; extrap=:extension) + itp = quadratic_interp(x, y; extrap=ExtendExtrap()) xq_vec = [0.5, 1.0, 2.0, 3.0, 5.5] aq_vec = FastInterpolations._anchor_query(x, xq_vec, Val(:quadratic)) @@ -222,7 +222,7 @@ using FastInterpolations # Non-uniform grid x = [0.0, 0.1, 0.3, 0.6, 1.0] y = x .^ 2 - itp = quadratic_interp(x, y; extrap=:extension) + itp = quadratic_interp(x, y; extrap=ExtendExtrap()) xq = 0.45 # interval [0.3, 0.6] aq = FastInterpolations._anchor_query(x, xq, Val(:quadratic)) @@ -241,7 +241,7 @@ using FastInterpolations @testset "zero-allocation with pre-built anchors" begin x = collect(range(0.0, 2π, 101)) y = sin.(x) - itp = quadratic_interp(x, y; extrap=:extension) + itp = quadratic_interp(x, y; extrap=ExtendExtrap()) xq_vec = collect(range(0.1, 6.0, 100)) aq_vec = FastInterpolations._anchor_query(x, xq_vec, Val(:quadratic)) @@ -264,7 +264,7 @@ using FastInterpolations # Test with different BCs for bc in [Left(QuadraticFit()), Right(QuadraticFit()), MinCurvFit()] - itp = quadratic_interp(x, y; bc=bc, extrap=:extension) + itp = quadratic_interp(x, y; bc=bc, extrap=ExtendExtrap()) xq = 0.35 aq = FastInterpolations._anchor_query(x, xq, Val(:quadratic)) @test itp(aq) ≈ itp(xq) @@ -272,12 +272,12 @@ using FastInterpolations end # ======================================== - # extrap=:none DomainError Tests + # extrap=NoExtrap() DomainError Tests # ======================================== - @testset "extrap=:none throws DomainError via anchor" begin + @testset "extrap=NoExtrap() throws DomainError via anchor" begin x = collect(range(0.0, 1.0, 11)) y = x .^ 2 - itp = quadratic_interp(x, y; extrap=:none) + itp = quadratic_interp(x, y; extrap=NoExtrap()) # Inside domain works aq_inside = FastInterpolations._anchor_query(x, 0.5, Val(:quadratic)) @@ -296,12 +296,12 @@ using FastInterpolations end # ======================================== - # extrap=:constant Tests + # extrap=ConstExtrap() Tests # ======================================== - @testset "extrap=:constant via anchor" begin + @testset "extrap=ConstExtrap() via anchor" begin x = collect(range(0.0, 1.0, 11)) y = x .^ 2 - itp = quadratic_interp(x, y; extrap=:constant) + itp = quadratic_interp(x, y; extrap=ConstExtrap()) # Below domain returns first y aq_below = FastInterpolations._anchor_query(x, -0.5, Val(:quadratic)) @@ -323,7 +323,7 @@ using FastInterpolations x = collect(range(0.0, 1.0, 11)) y = x .^ 2 - for extrap in [:extension, :constant] + for extrap in [ExtendExtrap(), ConstExtrap()] itp = quadratic_interp(x, y; extrap=extrap) xq_vec = [-0.2, 0.3, 0.7, 1.2] # Mix of inside/outside aq_vec = FastInterpolations._anchor_query(x, xq_vec, Val(:quadratic)) @@ -340,7 +340,7 @@ using FastInterpolations @testset "in-place output length assertion" begin x = collect(range(0.0, 1.0, 11)) y = x .^ 2 - itp = quadratic_interp(x, y; extrap=:extension) + itp = quadratic_interp(x, y; extrap=ExtendExtrap()) xq_vec = [0.2, 0.5, 0.8] aq_vec = FastInterpolations._anchor_query(x, xq_vec, Val(:quadratic)) @@ -356,7 +356,7 @@ using FastInterpolations @testset "zero-allocation with deriv=1" begin x = collect(range(0.0, 2π, 101)) y = sin.(x) - itp = quadratic_interp(x, y; extrap=:extension) + itp = quadratic_interp(x, y; extrap=ExtendExtrap()) xq_vec = collect(range(0.1, 6.0, 100)) aq_vec = FastInterpolations._anchor_query(x, xq_vec, Val(:quadratic)) @@ -373,7 +373,7 @@ using FastInterpolations @testset "zero-allocation with deriv=2" begin x = collect(range(0.0, 2π, 101)) y = sin.(x) - itp = quadratic_interp(x, y; extrap=:extension) + itp = quadratic_interp(x, y; extrap=ExtendExtrap()) xq_vec = collect(range(0.1, 6.0, 100)) aq_vec = FastInterpolations._anchor_query(x, xq_vec, Val(:quadratic)) diff --git a/test/test_quadratic_series_interp.jl b/test/test_quadratic_series_interp.jl index cb74f118..d6451a00 100644 --- a/test/test_quadratic_series_interp.jl +++ b/test/test_quadratic_series_interp.jl @@ -136,14 +136,14 @@ const FI = FastInterpolations x = collect(0.0:0.1:1.0) ys = [sin.(2π .* x)] - @testset "extrap=:none throws" begin - sitp = quadratic_interp(x, ys; extrap=:none) + @testset "extrap=NoExtrap() throws" begin + sitp = quadratic_interp(x, ys; extrap=NoExtrap()) @test_throws DomainError sitp(-0.1) @test_throws DomainError sitp(1.1) end @testset "domain error message format" begin - sitp = quadratic_interp(x, ys; extrap=:none) + sitp = quadratic_interp(x, ys; extrap=NoExtrap()) err = try sitp(-0.5) nothing @@ -154,14 +154,14 @@ const FI = FastInterpolations @test occursin("outside domain", string(err)) end - @testset "extrap=:constant returns boundary" begin - sitp = quadratic_interp(x, ys; extrap=:constant) + @testset "extrap=ConstExtrap() returns boundary" begin + sitp = quadratic_interp(x, ys; extrap=ConstExtrap()) @test sitp(-0.1)[1] ≈ sin(0.0) atol=1e-6 @test sitp(1.1)[1] ≈ sin(2π) atol=1e-6 end - @testset "extrap=:extension extrapolates" begin - sitp = quadratic_interp(x, ys; extrap=:extension) + @testset "extrap=ExtendExtrap() extrapolates" begin + sitp = quadratic_interp(x, ys; extrap=ExtendExtrap()) @test sitp(-0.1) isa Vector{Float64} @test sitp(1.1) isa Vector{Float64} end @@ -394,15 +394,15 @@ const FI = FastInterpolations y1 = sin.(2π .* x) y2 = cos.(2π .* x) - @testset "vector :none extrapolation throws" begin - sitp = quadratic_interp(x, [y1, y2]; extrap=:none) + @testset "vector NoExtrap() extrapolation throws" begin + sitp = quadratic_interp(x, [y1, y2]; extrap=NoExtrap()) xq = [-0.1, 0.5, 1.1] @test_throws DomainError sitp(xq) end - @testset "vector :constant extrapolation" begin - sitp = quadratic_interp(x, [y1, y2]; extrap=:constant) + @testset "vector ConstExtrap() extrapolation" begin + sitp = quadratic_interp(x, [y1, y2]; extrap=ConstExtrap()) xq = [-0.1, 0.5, 1.1] outputs = [zeros(3), zeros(3)] @@ -413,8 +413,8 @@ const FI = FastInterpolations @test outputs[1][3] ≈ y1[end] atol=1e-10 end - @testset "vector :extension extrapolation" begin - sitp = quadratic_interp(x, [y1, y2]; extrap=:extension) + @testset "vector ExtendExtrap() extrapolation" begin + sitp = quadratic_interp(x, [y1, y2]; extrap=ExtendExtrap()) xq = [-0.1, 0.5, 1.1] outputs = [zeros(3), zeros(3)] @@ -424,8 +424,8 @@ const FI = FastInterpolations @test !any(isnan, outputs[2]) end - @testset "vector :constant extrapolation with derivatives" begin - sitp = quadratic_interp(x, [y1, y2]; extrap=:constant) + @testset "vector ConstExtrap() extrapolation with derivatives" begin + sitp = quadratic_interp(x, [y1, y2]; extrap=ConstExtrap()) xq = [-0.1, 0.5, 1.1] # deriv=1 outside domain should be zero for constant extrap @@ -447,20 +447,20 @@ const FI = FastInterpolations # ======================================== @testset "scalar constant extrap inside domain" begin - # Test that :constant extrap still works correctly inside domain + # Test that ConstExtrap() extrap still works correctly inside domain x = collect(0.0:0.1:1.0) y1 = sin.(2π .* x) y2 = cos.(2π .* x) - sitp_const = quadratic_interp(x, [y1, y2]; extrap=:constant) - sitp_none = quadratic_interp(x, [y1, y2]; extrap=:none) + sitp_const = quadratic_interp(x, [y1, y2]; extrap=ConstExtrap()) + sitp_none = quadratic_interp(x, [y1, y2]; extrap=NoExtrap()) - @testset "value inside domain same as :none extrap" begin + @testset "value inside domain same as NoExtrap() extrap" begin result_const = sitp_const(0.5) result_none = sitp_none(0.5) @test result_const ≈ result_none atol=1e-10 end - @testset "deriv inside domain same as :none extrap" begin + @testset "deriv inside domain same as NoExtrap() extrap" begin result_const = sitp_const(0.5; deriv=1) result_none = sitp_none(0.5; deriv=1) @test result_const ≈ result_none atol=1e-10 @@ -471,7 +471,7 @@ const FI = FastInterpolations x = collect(0.0:0.1:1.0) y1 = sin.(2π .* x) y2 = cos.(2π .* x) - sitp = quadratic_interp(x, [y1, y2]; extrap=:constant) + sitp = quadratic_interp(x, [y1, y2]; extrap=ConstExtrap()) @testset "deriv=1 outside domain returns zero" begin result_below = sitp(-0.1; deriv=1) diff --git a/test/test_random_grid.jl b/test/test_random_grid.jl index a3fb0614..ec6a17aa 100644 --- a/test/test_random_grid.jl +++ b/test/test_random_grid.jl @@ -43,11 +43,11 @@ x_extrap = [x_min - 1.0, x_max + 1.0] # Extension extrapolation (explicit mode) - result_ext = linear_interp(x_random, y, x_extrap; extrap=:extension) + result_ext = linear_interp(x_random, y, x_extrap; extrap=ExtendExtrap()) @test all(isfinite, result_ext) # Constant extrapolation - result_const = linear_interp(x_random, y, x_extrap; extrap=:constant) + result_const = linear_interp(x_random, y, x_extrap; extrap=ConstExtrap()) @test result_const[1] ≈ y[1] @test result_const[2] ≈ y[end] end diff --git a/test/test_recipes.jl b/test/test_recipes.jl index 179a8e32..37a17e88 100644 --- a/test/test_recipes.jl +++ b/test/test_recipes.jl @@ -48,7 +48,7 @@ using RecipesBase # Extrapolation Modes # ======================================== @testset "Extrapolation Modes" begin - for extrap in [:none, :constant, :extension, :wrap] + for extrap in [NoExtrap(), ConstExtrap(), ExtendExtrap(), WrapExtrap()] @testset "extrap=:$extrap" begin itp = cubic_interp(x, y; extrap=extrap) recipes = RecipesBase.apply_recipe(Dict{Symbol,Any}(), itp) @@ -278,7 +278,7 @@ using RecipesBase @testset "ND extrapolation extension" begin # extrap on both axes — should produce boundary rectangle series - itp_ext = linear_interp((x1, x2), data_2d; extrap=:extension) + itp_ext = linear_interp((x1, x2), data_2d; extrap=ExtendExtrap()) recipes = RecipesBase.apply_recipe(Dict{Symbol,Any}(), itp_ext) @test !isempty(recipes) @@ -306,8 +306,8 @@ using RecipesBase @test first(hm_x) < first(x1) # extended left @test last(hm_x) > last(x1) # extended right - # extrap=:none — should NOT produce boundary series - itp_none = linear_interp((x1, x2), data_2d; extrap=:none) + # extrap=NoExtrap() — should NOT produce boundary series + itp_none = linear_interp((x1, x2), data_2d; extrap=NoExtrap()) recipes_none = RecipesBase.apply_recipe(Dict{Symbol,Any}(), itp_none) boundary_none = filter(recipes_none) do r get(r.plotattributes, :seriestype, nothing) === :path && @@ -315,7 +315,7 @@ using RecipesBase end @test isempty(boundary_none) - # Heatmap should stay within domain when extrap=:none + # Heatmap should stay within domain when extrap=NoExtrap() hm_none = filter(recipes_none) do r get(r.plotattributes, :seriestype, nothing) === :heatmap end @@ -346,7 +346,7 @@ using RecipesBase end @testset "ND extrap with CubicInterpolantND" begin - itp_ext = cubic_interp((x1, x2), data_2d; extrap=:constant) + itp_ext = cubic_interp((x1, x2), data_2d; extrap=ConstExtrap()) recipes = RecipesBase.apply_recipe(Dict{Symbol,Any}(), itp_ext) @test !isempty(recipes) boundary_series = filter(recipes) do r diff --git a/test/test_series_range_grid.jl b/test/test_series_range_grid.jl index af5adc56..271f7a02 100644 --- a/test/test_series_range_grid.jl +++ b/test/test_series_range_grid.jl @@ -150,7 +150,7 @@ const FI = FastInterpolations # ======================================== @testset "extrapolation modes" begin - for extrap in [:constant, :extension] + for extrap in [ConstExtrap(), ExtendExtrap()] @testset "LinearSeriesInterpolant extrap=$extrap" begin sitp = linear_interp(x_range, ys; extrap=extrap) diff --git a/test/test_show.jl b/test/test_show.jl index 78c9175e..8b4896a1 100644 --- a/test/test_show.jl +++ b/test/test_show.jl @@ -218,10 +218,10 @@ end @testset "Extrapolation mode display" begin - itp_none = linear_interp(x, y; extrap=:none) - itp_const = linear_interp(x, y; extrap=:constant) - itp_ext = linear_interp(x, y; extrap=:extension) - itp_wrap = linear_interp(x, y; extrap=:wrap) + itp_none = linear_interp(x, y; extrap=NoExtrap()) + itp_const = linear_interp(x, y; extrap=ConstExtrap()) + itp_ext = linear_interp(x, y; extrap=ExtendExtrap()) + itp_wrap = linear_interp(x, y; extrap=WrapExtrap()) @test occursin("NoExtrap", sprint(show, MIME("text/plain"), itp_none)) @test occursin("ConstExtrap", sprint(show, MIME("text/plain"), itp_const)) @@ -625,7 +625,7 @@ f = [sin(2π * xi) * cos(π * xj) for xi in x1, xj in x2] # Different extrapolation modes per axis - itp_mixed_extrap = cubic_interp((x1, x2), f; extrap=(:none, :constant)) + itp_mixed_extrap = cubic_interp((x1, x2), f; extrap=(NoExtrap(), ConstExtrap())) # Verbose show should display tuple format for extrapolation verbose_str = sprint(show, MIME("text/plain"), itp_mixed_extrap) @@ -756,7 +756,7 @@ # Test with heterogeneous tuple (different values per axis) io = IOBuffer() - configs = (Val(:none), Val(:constant), Val(:extension)) + configs = (NoExtrap(), ConstExtrap(), ExtendExtrap()) FI._show_nd_config_row(io, false, "Extrap:", configs, FI._format_extrap) output = String(take!(io)) @@ -768,7 +768,7 @@ # Test with homogeneous tuple (same values) io2 = IOBuffer() - configs_same = (Val(:none), Val(:none)) + configs_same = (NoExtrap(), NoExtrap()) FI._show_nd_config_row(io2, true, "Extrap:", configs_same, FI._format_extrap) output2 = String(take!(io2)) @@ -866,7 +866,7 @@ x2 = range(0.0, 2.0, 15) data = [Float64(i + j) for i in 1:11, j in 1:15] - itp = constant_interp((x1, x2), data; extrap=(:none, :constant)) + itp = constant_interp((x1, x2), data; extrap=(NoExtrap(), ConstExtrap())) verbose_str = sprint(show, MIME("text/plain"), itp) @test occursin("Extrap:", verbose_str) diff --git a/test/test_type_stability.jl b/test/test_type_stability.jl index 7e5d56d5..be682872 100644 --- a/test/test_type_stability.jl +++ b/test/test_type_stability.jl @@ -366,13 +366,13 @@ using FastInterpolations: PolyFit, LinearFit, QuadraticFit, CubicFit itp_none = cubic_interp((x_nd, y_nd), data2d) @test itp_none isa CubicInterpolantND - itp_const = cubic_interp((x_nd, y_nd), data2d; extrap=:constant) + itp_const = cubic_interp((x_nd, y_nd), data2d; extrap=ConstExtrap()) @test itp_const isa CubicInterpolantND - itp_ext = cubic_interp((x_nd, y_nd), data2d; extrap=:extension) + itp_ext = cubic_interp((x_nd, y_nd), data2d; extrap=ExtendExtrap()) @test itp_ext isa CubicInterpolantND - itp_mixed = cubic_interp((x_nd, y_nd), data2d; extrap=(:none, :constant)) + itp_mixed = cubic_interp((x_nd, y_nd), data2d; extrap=(NoExtrap(), ConstExtrap())) @test itp_mixed isa CubicInterpolantND # E type parameter: different extrap → different concrete types @@ -395,7 +395,7 @@ using FastInterpolations: PolyFit, LinearFit, QuadraticFit, CubicFit data_p = [sin(xi) * cos(yj) for xi in x_periodic, yj in y_periodic] itp_mixed_bc = cubic_interp((x_periodic, y_periodic), data_p; - bc=(NaturalBC(), PeriodicBC()), extrap=(:extension, :wrap)) + bc=(NaturalBC(), PeriodicBC()), extrap=(ExtendExtrap(), WrapExtrap())) @test itp_mixed_bc isa CubicInterpolantND @test @inferred(itp_mixed_bc((1.0, 1.0))) isa Float64 @@ -444,10 +444,10 @@ using FastInterpolations: PolyFit, LinearFit, QuadraticFit, CubicFit itp_none = quadratic_interp((x_nd, y_nd), data2d) @test itp_none isa QuadraticInterpolantND - itp_const = quadratic_interp((x_nd, y_nd), data2d; extrap=:constant) + itp_const = quadratic_interp((x_nd, y_nd), data2d; extrap=ConstExtrap()) @test itp_const isa QuadraticInterpolantND - itp_mixed = quadratic_interp((x_nd, y_nd), data2d; extrap=(:none, :extension)) + itp_mixed = quadratic_interp((x_nd, y_nd), data2d; extrap=(NoExtrap(), ExtendExtrap())) @test itp_mixed isa QuadraticInterpolantND # E type parameter: different extrap → different concrete types @@ -464,10 +464,10 @@ using FastInterpolations: PolyFit, LinearFit, QuadraticFit, CubicFit itp_none = linear_interp((x_nd, y_nd), data2d) @test itp_none isa LinearInterpolantND - itp_const = linear_interp((x_nd, y_nd), data2d; extrap=:constant) + itp_const = linear_interp((x_nd, y_nd), data2d; extrap=ConstExtrap()) @test itp_const isa LinearInterpolantND - itp_mixed = linear_interp((x_nd, y_nd), data2d; extrap=(:none, :wrap)) + itp_mixed = linear_interp((x_nd, y_nd), data2d; extrap=(NoExtrap(), WrapExtrap())) @test itp_mixed isa LinearInterpolantND # E type parameter: different extrap → different concrete types @@ -484,10 +484,10 @@ using FastInterpolations: PolyFit, LinearFit, QuadraticFit, CubicFit itp_none = constant_interp((x_nd, y_nd), data2d) @test itp_none isa ConstantInterpolantND - itp_const = constant_interp((x_nd, y_nd), data2d; extrap=:constant) + itp_const = constant_interp((x_nd, y_nd), data2d; extrap=ConstExtrap()) @test itp_const isa ConstantInterpolantND - itp_mixed = constant_interp((x_nd, y_nd), data2d; extrap=(:none, :extension)) + itp_mixed = constant_interp((x_nd, y_nd), data2d; extrap=(NoExtrap(), ExtendExtrap())) @test itp_mixed isa ConstantInterpolantND # E type parameter: different extrap → different concrete types @@ -518,7 +518,7 @@ using FastInterpolations: PolyFit, LinearFit, QuadraticFit, CubicFit # Typed extrap produces identical struct to Symbol extrap itp_typed = cubic_interp((x_nd, y_nd), data2d; extrap=NoExtrap()) - itp_sym = cubic_interp((x_nd, y_nd), data2d; extrap=:none) + itp_sym = cubic_interp((x_nd, y_nd), data2d; extrap=NoExtrap()) @test typeof(itp_typed) === typeof(itp_sym) # Eval equivalence @@ -552,7 +552,7 @@ using FastInterpolations: PolyFit, LinearFit, QuadraticFit, CubicFit # Typed vs Symbol equivalence itp_typed = quadratic_interp((x_nd, y_nd), data2d; extrap=ExtendExtrap()) - itp_sym = quadratic_interp((x_nd, y_nd), data2d; extrap=:extension) + itp_sym = quadratic_interp((x_nd, y_nd), data2d; extrap=ExtendExtrap()) @test typeof(itp_typed) === typeof(itp_sym) @test @inferred(itp_typed((0.5, 1.0))) ≈ itp_sym((0.5, 1.0)) end @@ -567,7 +567,7 @@ using FastInterpolations: PolyFit, LinearFit, QuadraticFit, CubicFit # Typed vs Symbol equivalence itp_typed = linear_interp((x_nd, y_nd), data2d; extrap=ConstExtrap()) - itp_sym = linear_interp((x_nd, y_nd), data2d; extrap=:constant) + itp_sym = linear_interp((x_nd, y_nd), data2d; extrap=ConstExtrap()) @test typeof(itp_typed) === typeof(itp_sym) @test @inferred(itp_typed((0.5, 1.0))) ≈ itp_sym((0.5, 1.0)) end @@ -593,7 +593,7 @@ using FastInterpolations: PolyFit, LinearFit, QuadraticFit, CubicFit # Typed vs Symbol equivalence itp_typed = constant_interp((x_nd, y_nd), data2d; extrap=NoExtrap()) - itp_sym = constant_interp((x_nd, y_nd), data2d; extrap=:none) + itp_sym = constant_interp((x_nd, y_nd), data2d; extrap=NoExtrap()) @test typeof(itp_typed) === typeof(itp_sym) @test @inferred(itp_typed((0.5, 1.0))) ≈ itp_sym((0.5, 1.0)) end @@ -631,18 +631,18 @@ using FastInterpolations: PolyFit, LinearFit, QuadraticFit, CubicFit # Typed vs Symbol should produce identical results @test cubic_interp((x_nd, y_nd), data2d, q; extrap=NoExtrap()) ≈ - cubic_interp((x_nd, y_nd), data2d, q; extrap=:none) + cubic_interp((x_nd, y_nd), data2d, q; extrap=NoExtrap()) @test cubic_interp((x_nd, y_nd), data2d, q; extrap=ConstExtrap()) ≈ - cubic_interp((x_nd, y_nd), data2d, q; extrap=:constant) + cubic_interp((x_nd, y_nd), data2d, q; extrap=ConstExtrap()) @test quadratic_interp((x_nd, y_nd), data2d, q; extrap=ExtendExtrap()) ≈ - quadratic_interp((x_nd, y_nd), data2d, q; extrap=:extension) + quadratic_interp((x_nd, y_nd), data2d, q; extrap=ExtendExtrap()) @test linear_interp((x_nd, y_nd), data2d, q; extrap=WrapExtrap()) ≈ - linear_interp((x_nd, y_nd), data2d, q; extrap=:wrap) + linear_interp((x_nd, y_nd), data2d, q; extrap=WrapExtrap()) @test constant_interp((x_nd, y_nd), data2d, q; extrap=ConstExtrap()) ≈ - constant_interp((x_nd, y_nd), data2d, q; extrap=:constant) + constant_interp((x_nd, y_nd), data2d, q; extrap=ConstExtrap()) end @testset "ND oneshot typed extrap — per-axis mode tuple" begin @@ -660,11 +660,11 @@ using FastInterpolations: PolyFit, LinearFit, QuadraticFit, CubicFit # SoA batch with typed extrap result_typed = cubic_interp((x_nd, y_nd), data2d, qs; extrap=NoExtrap()) - result_sym = cubic_interp((x_nd, y_nd), data2d, qs; extrap=:none) + result_sym = cubic_interp((x_nd, y_nd), data2d, qs; extrap=NoExtrap()) @test result_typed ≈ result_sym result_typed = linear_interp((x_nd, y_nd), data2d, qs; extrap=ConstExtrap()) - result_sym = linear_interp((x_nd, y_nd), data2d, qs; extrap=:constant) + result_sym = linear_interp((x_nd, y_nd), data2d, qs; extrap=ConstExtrap()) @test result_typed ≈ result_sym end