Skip to content

refactor(basis): replace operator closures with functor types#64

Merged
kylebeggs merged 10 commits intomainfrom
refactor/issue-62-functor-operators
Jan 8, 2026
Merged

refactor(basis): replace operator closures with functor types#64
kylebeggs merged 10 commits intomainfrom
refactor/issue-62-functor-operators

Conversation

@kylebeggs
Copy link
Member

@kylebeggs kylebeggs commented Jan 5, 2026

Summary

This PR addresses both Issue #62 and Issue #63.

Issue #62: Functor pattern for RBF operators

  • Add , , ∂², ∇², D, callable structs in basis.jl
  • Replace closure-returning functions with call methods for all RBF types
  • Update PHS1/3/5/7, Gaussian, IMQ implementations
  • Use D functor in assembly.jl instead of dot(n, ∇(...))

Issue #63: Unified operator construction

  • Add unified RadialBasisOperator(ℒ, data; eval_points, basis, k, adjl, hermite) constructor
  • Refactor all operator files to use thin wrappers delegating to unified constructor
  • Add hermite keyword argument as NamedTuple alternative
  • Maintain full backward compatibility

Benefits:

  • Proper Julia multiple dispatch instead of runtime branching
  • Better type inference and potential performance improvements
  • Reduced code duplication across operator files
  • More idiomatic Julia code

Closes #62
Closes #63

Test plan

  • All existing tests pass
  • New tests for D functor added (PHS, Gaussian, IMQ)
  • 460 total tests passing

🤖 Generated with Claude Code

kylebeggs and others added 4 commits January 5, 2026 07:57
This refactoring addresses Issue #63 by introducing a unified constructor
for RadialBasisOperator that uses keyword arguments, reducing code
duplication across operator files.

Changes:
- Add unified `RadialBasisOperator(ℒ, data; eval_points, basis, k, adjl, hermite)`
  constructor in operators.jl
- Refactor all operator files (laplacian, partial, custom, jacobian,
  gradient, directional, regridding) to use thin wrappers
- Old positional constructors now delegate to the unified constructor
- Maintain full backward compatibility with existing API
- Add hermite keyword argument as NamedTuple alternative to positional args
- Improve documentation with examples

The new keyword-based API is now the primary interface:
```julia
op = laplacian(data; basis=PHS(5), k=30)
op = jacobian(data; eval_points=pts, hermite=(is_boundary=..., bc=..., normals=...))
```

Closes #63

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add ∂, ∇, ∂², ∇², D, D² functor structs in basis.jl
- Replace closure-returning functions with callable structs
- Update PHS, Gaussian, IMQ implementations
- Use D functor in assembly.jl instead of dot(n, ∇(...))

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@codecov
Copy link

codecov bot commented Jan 5, 2026

Codecov Report

❌ Patch coverage is 99.14530% with 4 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/operators/gradient.jl 60.00% 2 Missing ⚠️
src/operators/monomial/partial.jl 96.66% 1 Missing ⚠️
src/utils.jl 66.66% 1 Missing ⚠️
Files with missing lines Coverage Δ
src/RadialBasisFunctions.jl 100.00% <ø> (ø)
src/basis/basis.jl 100.00% <100.00%> (ø)
src/basis/gaussian.jl 100.00% <100.00%> (ø)
src/basis/inverse_multiquadric.jl 100.00% <100.00%> (ø)
src/basis/monomial.jl 100.00% <100.00%> (ø)
src/basis/polyharmonic_spline.jl 100.00% <100.00%> (ø)
src/interpolation.jl 100.00% <100.00%> (ø)
src/operators/custom.jl 100.00% <100.00%> (+66.66%) ⬆️
src/operators/directional.jl 100.00% <100.00%> (ø)
src/operators/jacobian.jl 100.00% <100.00%> (ø)
... and 14 more
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions
Copy link
Contributor

github-actions bot commented Jan 5, 2026

Benchmark Results

main f675246... main / f675246...
Directional 2.42 ± 0.14 ms 2.42 ± 0.09 ms 1 ± 0.069
Directional (per point) 2.42 ± 0.13 ms 2.4 ± 0.094 ms 1.01 ± 0.067
Gradient 8.16 ± 0.43 ms 8.29 ± 0.31 ms 0.984 ± 0.064
MonomialBasis/dim=1/deg=0 0.0469 ± 0.012 μs 0.0457 ± 0.012 μs 1.03 ± 0.38
MonomialBasis/dim=1/deg=1 0.0753 ± 0.012 μs 0.075 ± 0.0099 μs 1 ± 0.21
MonomialBasis/dim=1/deg=2 0.0856 ± 0.013 μs 0.0851 ± 0.019 μs 1.01 ± 0.27
MonomialBasis/dim=2/deg=0 0.035 ± 0.012 μs 0.0363 ± 0.011 μs 0.965 ± 0.43
MonomialBasis/dim=2/deg=1 0.0356 ± 0.012 μs 0.037 ± 0.012 μs 0.962 ± 0.46
MonomialBasis/dim=2/deg=2 0.0424 ± 0.011 μs 0.0425 ± 0.011 μs 0.997 ± 0.37
MonomialBasis/dim=3/deg=0 0.0364 ± 0.012 μs 0.034 ± 0.011 μs 1.07 ± 0.5
MonomialBasis/dim=3/deg=1 0.0424 ± 0.011 μs 0.0428 ± 0.012 μs 0.99 ± 0.39
MonomialBasis/dim=3/deg=2 0.0487 ± 0.011 μs 0.0484 ± 0.011 μs 1.01 ± 0.33
Partial 2.43 ± 0.14 ms 2.36 ± 0.086 ms 1.03 ± 0.07
RBF/Gaussian, exp(-(ε*r)²)
├─Shape factor: ε = 1
└─Polynomial augmentation: degree 0/0/∂ 10.1 ± 0.09 ns 10.1 ± 0.11 ns 1 ± 0.014
RBF/Gaussian, exp(-(ε*r)²)
├─Shape factor: ε = 1
└─Polynomial augmentation: degree 0/0/∂² 10.6 ± 0.091 ns 10.5 ± 0.16 ns 1.01 ± 0.018
RBF/Gaussian, exp(-(ε*r)²)
├─Shape factor: ε = 1
└─Polynomial augmentation: degree 0/0/∇ 17.3 ± 0.06 ns 17.3 ± 0.06 ns 1 ± 0.0049
RBF/Gaussian, exp(-(ε*r)²)
├─Shape factor: ε = 1
└─Polynomial augmentation: degree 0/0/∇² 18.3 ± 0.09 ns 18.2 ± 0.081 ns 1 ± 0.0067
RBF/Gaussian, exp(-(ε*r)²)
├─Shape factor: ε = 1
└─Polynomial augmentation: degree 1/1/∂ 10.1 ± 0.09 ns 10.1 ± 0.09 ns 0.999 ± 0.013
RBF/Gaussian, exp(-(ε*r)²)
├─Shape factor: ε = 1
└─Polynomial augmentation: degree 1/1/∂² 10.6 ± 0.08 ns 10.5 ± 0.19 ns 1.01 ± 0.02
RBF/Gaussian, exp(-(ε*r)²)
├─Shape factor: ε = 1
└─Polynomial augmentation: degree 1/1/∇ 17.3 ± 0.06 ns 17.3 ± 0.06 ns 1 ± 0.0049
RBF/Gaussian, exp(-(ε*r)²)
├─Shape factor: ε = 1
└─Polynomial augmentation: degree 1/1/∇² 18.3 ± 0.08 ns 18.2 ± 0.08 ns 1 ± 0.0062
RBF/Gaussian, exp(-(ε*r)²)
├─Shape factor: ε = 1
└─Polynomial augmentation: degree 2/2/∂ 10.1 ± 0.1 ns 10.1 ± 0.11 ns 1 ± 0.015
RBF/Gaussian, exp(-(ε*r)²)
├─Shape factor: ε = 1
└─Polynomial augmentation: degree 2/2/∂² 10.6 ± 0.1 ns 10.6 ± 0.11 ns 1 ± 0.014
RBF/Gaussian, exp(-(ε*r)²)
├─Shape factor: ε = 1
└─Polynomial augmentation: degree 2/2/∇ 17.3 ± 0.06 ns 17.3 ± 0.06 ns 1 ± 0.0049
RBF/Gaussian, exp(-(ε*r)²)
├─Shape factor: ε = 1
└─Polynomial augmentation: degree 2/2/∇² 18.2 ± 0.071 ns 18.2 ± 0.072 ns 1 ± 0.0056
RBF/Inverse Multiquadrics, 1/sqrt((r*ε)²+1)
├─Shape factor: ε = 1
└─Polynomial augmentation: degree 0/0/∂ 6.32 ± 0.011 ns 6.73 ± 0.14 ns 0.939 ± 0.02
RBF/Inverse Multiquadrics, 1/sqrt((r*ε)²+1)
├─Shape factor: ε = 1
└─Polynomial augmentation: degree 0/0/∂² 14.1 ± 0.029 ns 14.1 ± 0.2 ns 1 ± 0.014
RBF/Inverse Multiquadrics, 1/sqrt((r*ε)²+1)
├─Shape factor: ε = 1
└─Polynomial augmentation: degree 0/0/∇ 8.64 ± 0.05 ns 8.53 ± 0.26 ns 1.01 ± 0.031
RBF/Inverse Multiquadrics, 1/sqrt((r*ε)²+1)
├─Shape factor: ε = 1
└─Polynomial augmentation: degree 0/0/∇² 16.3 ± 0.06 ns 16.4 ± 0.081 ns 0.996 ± 0.0062
RBF/Inverse Multiquadrics, 1/sqrt((r*ε)²+1)
├─Shape factor: ε = 1
└─Polynomial augmentation: degree 1/1/∂ 6.32 ± 0.011 ns 6.8 ± 0.15 ns 0.929 ± 0.021
RBF/Inverse Multiquadrics, 1/sqrt((r*ε)²+1)
├─Shape factor: ε = 1
└─Polynomial augmentation: degree 1/1/∂² 14.1 ± 0.02 ns 14.1 ± 0.23 ns 1 ± 0.017
RBF/Inverse Multiquadrics, 1/sqrt((r*ε)²+1)
├─Shape factor: ε = 1
└─Polynomial augmentation: degree 1/1/∇ 8.65 ± 0.03 ns 8.53 ± 0.26 ns 1.01 ± 0.031
RBF/Inverse Multiquadrics, 1/sqrt((r*ε)²+1)
├─Shape factor: ε = 1
└─Polynomial augmentation: degree 1/1/∇² 16.3 ± 0.06 ns 16.4 ± 0.081 ns 0.994 ± 0.0061
RBF/Inverse Multiquadrics, 1/sqrt((r*ε)²+1)
├─Shape factor: ε = 1
└─Polynomial augmentation: degree 2/2/∂ 6.32 ± 0.011 ns 6.8 ± 0.09 ns 0.929 ± 0.012
RBF/Inverse Multiquadrics, 1/sqrt((r*ε)²+1)
├─Shape factor: ε = 1
└─Polynomial augmentation: degree 2/2/∂² 14.1 ± 0.02 ns 14.1 ± 0.23 ns 1 ± 0.016
RBF/Inverse Multiquadrics, 1/sqrt((r*ε)²+1)
├─Shape factor: ε = 1
└─Polynomial augmentation: degree 2/2/∇ 8.65 ± 0.039 ns 8.62 ± 0.15 ns 1 ± 0.018
RBF/Inverse Multiquadrics, 1/sqrt((r*ε)²+1)
├─Shape factor: ε = 1
└─Polynomial augmentation: degree 2/2/∇² 16.3 ± 0.06 ns 16.4 ± 0.081 ns 0.996 ± 0.0062
RBF/Polyharmonic spline (r³)
└─Polynomial augmentation: degree 0/0/∂ 3.42 ± 0.001 ns 3.42 ± 0.001 ns 1 ± 0.00041
RBF/Polyharmonic spline (r³)
└─Polynomial augmentation: degree 0/0/∂² 4.7 ± 0.011 ns 4.7 ± 0.01 ns 1 ± 0.0032
RBF/Polyharmonic spline (r³)
└─Polynomial augmentation: degree 0/0/∇ 5.43 ± 0.02 ns 5.59 ± 0.05 ns 0.971 ± 0.0094
RBF/Polyharmonic spline (r³)
└─Polynomial augmentation: degree 0/0/∇² 3.11 ± 0 ns 3.11 ± 0.001 ns 1 ± 0.00032
RBF/Polyharmonic spline (r³)
└─Polynomial augmentation: degree 1/1/∂ 3.42 ± 0.001 ns 3.42 ± 0.001 ns 1 ± 0.00041
RBF/Polyharmonic spline (r³)
└─Polynomial augmentation: degree 1/1/∂² 4.7 ± 0.02 ns 4.7 ± 0.01 ns 1 ± 0.0048
RBF/Polyharmonic spline (r³)
└─Polynomial augmentation: degree 1/1/∇ 5.43 ± 0.021 ns 5.59 ± 0.079 ns 0.971 ± 0.014
RBF/Polyharmonic spline (r³)
└─Polynomial augmentation: degree 1/1/∇² 3.11 ± 0 ns 3.11 ± 0.001 ns 1 ± 0.00032
RBF/Polyharmonic spline (r³)
└─Polynomial augmentation: degree 2/2/∂ 3.42 ± 0.001 ns 3.42 ± 0.001 ns 1 ± 0.00041
RBF/Polyharmonic spline (r³)
└─Polynomial augmentation: degree 2/2/∂² 4.7 ± 0.14 ns 4.7 ± 0.01 ns 1 ± 0.03
RBF/Polyharmonic spline (r³)
└─Polynomial augmentation: degree 2/2/∇ 5.43 ± 0.021 ns 5.59 ± 0.06 ns 0.971 ± 0.011
RBF/Polyharmonic spline (r³)
└─Polynomial augmentation: degree 2/2/∇² 3.11 ± 0 ns 3.11 ± 0.001 ns 1 ± 0.00032
RBF/Polyharmonic spline (r¹)
└─Polynomial augmentation: degree 0/0/∂ 4.27 ± 0.01 ns 4.27 ± 0.01 ns 1 ± 0.0033
RBF/Polyharmonic spline (r¹)
└─Polynomial augmentation: degree 0/0/∂² 5.78 ± 0.01 ns 5.82 ± 0.011 ns 0.993 ± 0.0025
RBF/Polyharmonic spline (r¹)
└─Polynomial augmentation: degree 0/0/∇ 6.78 ± 0.02 ns 7.27 ± 0.031 ns 0.932 ± 0.0048
RBF/Polyharmonic spline (r¹)
└─Polynomial augmentation: degree 0/0/∇² 4.52 ± 0.01 ns 4.27 ± 0.01 ns 1.06 ± 0.0034
RBF/Polyharmonic spline (r¹)
└─Polynomial augmentation: degree 1/1/∂ 4.27 ± 0.01 ns 4.27 ± 0.01 ns 1 ± 0.0033
RBF/Polyharmonic spline (r¹)
└─Polynomial augmentation: degree 1/1/∂² 5.77 ± 0.4 ns 5.82 ± 0.021 ns 0.991 ± 0.069
RBF/Polyharmonic spline (r¹)
└─Polynomial augmentation: degree 1/1/∇ 6.78 ± 0.02 ns 7.27 ± 0.021 ns 0.932 ± 0.0038
RBF/Polyharmonic spline (r¹)
└─Polynomial augmentation: degree 1/1/∇² 4.52 ± 0.01 ns 4.27 ± 0.01 ns 1.06 ± 0.0034
RBF/Polyharmonic spline (r¹)
└─Polynomial augmentation: degree 2/2/∂ 4.27 ± 0.01 ns 4.27 ± 0.01 ns 1 ± 0.0033
RBF/Polyharmonic spline (r¹)
└─Polynomial augmentation: degree 2/2/∂² 5.78 ± 0.011 ns 5.82 ± 0.02 ns 0.993 ± 0.0039
RBF/Polyharmonic spline (r¹)
└─Polynomial augmentation: degree 2/2/∇ 6.78 ± 0.021 ns 7.27 ± 0.051 ns 0.933 ± 0.0071
RBF/Polyharmonic spline (r¹)
└─Polynomial augmentation: degree 2/2/∇² 4.52 ± 0.01 ns 4.27 ± 0.01 ns 1.06 ± 0.0034
RBF/Polyharmonic spline (r⁵)
└─Polynomial augmentation: degree 0/0/∂ 5.26 ± 0.01 ns 5.26 ± 0.01 ns 1 ± 0.0027
RBF/Polyharmonic spline (r⁵)
└─Polynomial augmentation: degree 0/0/∂² 4.96 ± 0.01 ns 4.96 ± 0.01 ns 1 ± 0.0029
RBF/Polyharmonic spline (r⁵)
└─Polynomial augmentation: degree 0/0/∇ 6.03 ± 0.09 ns 6.23 ± 0.09 ns 0.968 ± 0.02
RBF/Polyharmonic spline (r⁵)
└─Polynomial augmentation: degree 0/0/∇² 3.73 ± 0.01 ns 3.42 ± 0.001 ns 1.09 ± 0.0029
RBF/Polyharmonic spline (r⁵)
└─Polynomial augmentation: degree 1/1/∂ 5.26 ± 0.01 ns 5.26 ± 0.01 ns 1 ± 0.0027
RBF/Polyharmonic spline (r⁵)
└─Polynomial augmentation: degree 1/1/∂² 4.96 ± 0.01 ns 4.96 ± 0.01 ns 1 ± 0.0029
RBF/Polyharmonic spline (r⁵)
└─Polynomial augmentation: degree 1/1/∇ 6.04 ± 0.09 ns 6.23 ± 0.089 ns 0.97 ± 0.02
RBF/Polyharmonic spline (r⁵)
└─Polynomial augmentation: degree 1/1/∇² 3.73 ± 0.01 ns 3.42 ± 0.001 ns 1.09 ± 0.0029
RBF/Polyharmonic spline (r⁵)
└─Polynomial augmentation: degree 2/2/∂ 5.26 ± 0.01 ns 5.26 ± 0.01 ns 1 ± 0.0027
RBF/Polyharmonic spline (r⁵)
└─Polynomial augmentation: degree 2/2/∂² 4.96 ± 0.01 ns 4.96 ± 0.01 ns 1 ± 0.0029
RBF/Polyharmonic spline (r⁵)
└─Polynomial augmentation: degree 2/2/∇ 6.03 ± 0.081 ns 6.22 ± 0.081 ns 0.97 ± 0.018
RBF/Polyharmonic spline (r⁵)
└─Polynomial augmentation: degree 2/2/∇² 3.73 ± 0.01 ns 3.42 ± 0.001 ns 1.09 ± 0.0029
RBF/Polyharmonic spline (r⁷)
└─Polynomial augmentation: degree 0/0/∂ 10.6 ± 0.11 ns 10.1 ± 0.21 ns 1.04 ± 0.024
RBF/Polyharmonic spline (r⁷)
└─Polynomial augmentation: degree 0/0/∂² 5.27 ± 0.01 ns 4.96 ± 0.01 ns 1.06 ± 0.0029
RBF/Polyharmonic spline (r⁷)
└─Polynomial augmentation: degree 0/0/∇ 12.4 ± 0.06 ns 12.8 ± 0.18 ns 0.967 ± 0.014
RBF/Polyharmonic spline (r⁷)
└─Polynomial augmentation: degree 0/0/∇² 8.12 ± 0.11 ns 8.4 ± 0.03 ns 0.967 ± 0.014
RBF/Polyharmonic spline (r⁷)
└─Polynomial augmentation: degree 1/1/∂ 10.6 ± 0.16 ns 10.2 ± 0.2 ns 1.04 ± 0.026
RBF/Polyharmonic spline (r⁷)
└─Polynomial augmentation: degree 1/1/∂² 5.27 ± 0.01 ns 4.96 ± 0.01 ns 1.06 ± 0.0029
RBF/Polyharmonic spline (r⁷)
└─Polynomial augmentation: degree 1/1/∇ 12.4 ± 0.06 ns 12.8 ± 0.19 ns 0.968 ± 0.015
RBF/Polyharmonic spline (r⁷)
└─Polynomial augmentation: degree 1/1/∇² 8.12 ± 0.11 ns 8.4 ± 0.03 ns 0.967 ± 0.014
RBF/Polyharmonic spline (r⁷)
└─Polynomial augmentation: degree 2/2/∂ 10.6 ± 0.02 ns 10.1 ± 0.16 ns 1.05 ± 0.017
RBF/Polyharmonic spline (r⁷)
└─Polynomial augmentation: degree 2/2/∂² 5.27 ± 0.01 ns 4.96 ± 0.01 ns 1.06 ± 0.0029
RBF/Polyharmonic spline (r⁷)
└─Polynomial augmentation: degree 2/2/∇ 12.4 ± 0.061 ns 12.8 ± 0.18 ns 0.968 ± 0.014
RBF/Polyharmonic spline (r⁷)
└─Polynomial augmentation: degree 2/2/∇² 8.12 ± 0.11 ns 8.4 ± 0.03 ns 0.967 ± 0.014
time_to_load 0.605 ± 0.0021 s 0.61 ± 0.0053 s 0.992 ± 0.0092

Benchmark Plots

A plot of the benchmark results have been uploaded as an artifact to the workflow run for this PR.
Go to "Actions"->"Benchmark a pull request"->[the most recent run]->"Artifacts" (at the bottom).

kylebeggs and others added 5 commits January 5, 2026 18:27
Add H (Hessian) functor for all basis types to enable pre-construction
of derivative operators outside hot loops in Hermite interpolation.

Changes:
- Add H struct to basis.jl for Hessian matrix computation
- Implement H for PHS1, PHS3, PHS5, PHS7, Gaussian, IMQ
- Add D² (directional second derivative) for Gaussian and IMQ
- Add BasisOperators wrapper to bundle φ, ∇φ, Hφ operators
- Update hermite_rbf_dispatch to use dot(n, ∇φ) and dot(ni, Hφ*nj)
- Construct BasisOperators once before loop in _build_collocation_matrix!

Performance: Avoids constructing D/D² functors per point pair in hot loop.
Instead pre-constructs gradient and Hessian operators once and computes
directional derivatives via dot products.

Tests: Add Hessian and D² tests for all basis types verified against
ForwardDiff.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@kylebeggs kylebeggs force-pushed the refactor/issue-62-functor-operators branch from f789293 to f675246 Compare January 8, 2026 03:35
@kylebeggs kylebeggs merged commit aa67750 into main Jan 8, 2026
32 of 51 checks passed
@kylebeggs kylebeggs deleted the refactor/issue-62-functor-operators branch January 8, 2026 03:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Removal of repeated code in src/operators Refactor RBF operators to use functor pattern for proper multiple dispatch

1 participant