Skip to content

Add Symbolics.jl extension for ModelingToolkit.jl compatibility#51

Merged
mgyoo86 merged 6 commits intoProjectTorreyPines:masterfrom
ChrisRackauckas-Claude:symbolics-registration
Mar 1, 2026
Merged

Add Symbolics.jl extension for ModelingToolkit.jl compatibility#51
mgyoo86 merged 6 commits intoProjectTorreyPines:masterfrom
ChrisRackauckas-Claude:symbolics-registration

Conversation

@ChrisRackauckas-Claude
Copy link
Contributor

Summary

  • Adds a Symbolics.jl package extension (FastInterpolationsSymbolicsExt) that registers all FastInterpolations interpolant types with Symbolics.jl, enabling use in ModelingToolkit.jl symbolic contexts
  • Supports both 1D (AbstractInterpolant) and ND (AbstractInterpolantND) interpolants with symbolic calling and derivative chain rules
  • Adds exported derivative(itp, t, order) function wrapping the deriv=DerivOp(order) keyword API

1D Support

  • Symbolic calling via @register_symbolic wrapper function (avoids method ambiguity with concrete types)
  • Derivative chain rules via @register_derivative: d/dt itp(t) → derivative(itp, t, 1), d/dt derivative(itp, t, n) → derivative(itp, t, n+1)
  • Works with all 4 concrete types: LinearInterpolant, CubicInterpolant, QuadraticInterpolant, ConstantInterpolant

ND Support

  • Symbolic calling via SymbolicUtils.term for all concrete ND types
  • Partial derivative chain rules via @register_derivative with DifferentiatedInterpolantND wrapper for accumulating per-axis derivative orders
  • Numeric varargs bridge methods for build_function compiled code compatibility
  • Works with all 4 concrete ND types: LinearInterpolantND, CubicInterpolantND, QuadraticInterpolantND, ConstantInterpolantND

Design Decisions

  • Uses wrapper function _fast_interp_eval for 1D rather than registering on AbstractInterpolant directly, to avoid method ambiguity with concrete types that have untyped xq parameter
  • Uses SymbolicUtils.term manually for ND (not @register_symbolic) because ND interpolants are callable structs with variable arity
  • Compatible with Symbolics.jl v7 and SymbolicUtils v3-4

Test plan

  • 1D symbolic calling: all 4 interpolant types create Num expressions and round-trip through build_function
  • 1D symbolic derivatives: expand_derivatives + build_function match numeric derivative() for 1st and 2nd order
  • derivative() function: matches itp(t; deriv=DerivOp(n)) for orders 1-3
  • ND symbolic calling: creates Num expressions and round-trips through build_function
  • ND symbolic derivatives: partial derivatives via expand_derivatives match numeric itp((u,v); deriv=DerivOp(1,0)) and DerivOp(0,1)
  • Full test suite passes (all existing tests + 22 new symbolics tests)

Closes #50

🤖 Generated with Claude Code

Implements Symbolics.jl registration for all FastInterpolations interpolant
types (1D and ND), enabling use in ModelingToolkit.jl symbolic contexts.

1D interpolants (AbstractInterpolant):
- Symbolic calling via @register_symbolic wrapper function
- Derivative chain rules via @register_derivative
- Supports higher-order derivatives (d/dt → derivative(itp, t, 1), etc.)

ND interpolants (AbstractInterpolantND):
- Symbolic calling via SymbolicUtils.term for all concrete ND types
- Partial derivative chain rules via @register_derivative
- DifferentiatedInterpolantND wrapper for accumulating per-axis derivative orders
- Numeric varargs bridge for build_function compiled code

Also adds exported `derivative(itp, t, order)` function wrapping the
`deriv=DerivOp(order)` keyword API for Symbolics chain rule compatibility.

Closes ProjectTorreyPines#50

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
@codecov
Copy link

codecov bot commented Feb 28, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.68%. Comparing base (911b783) to head (49c1e5c).
⚠️ Report is 3 commits behind head on master.

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##           master      #51   +/-   ##
=======================================
  Coverage   97.68%   97.68%           
=======================================
  Files          72       72           
  Lines        5781     5781           
=======================================
  Hits         5647     5647           
  Misses        134      134           
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@mgyoo86 mgyoo86 mentioned this pull request Mar 1, 2026
@mgyoo86
Copy link
Collaborator

mgyoo86 commented Mar 1, 2026

@ChrisRackauckas Thanks for this PR! The Symbolics integration looks great overall.

One suggestion:
I think we don't need to add derivative to the FastInterpolations core API just yet — we already have established derivative APIs that cover the current use cases. The name is also quite generic and could potentially clash with AD packages (ForwardDiff, ChainRules, etc.), so a fully general derivative interface is something we could revisit in the future with more careful consideration.

Since this function only serves as glue between our kwargs API and Symbolics' positional-args requirement, it could live entirely in FastInterpolationsSymbolicsExt, something like the following (naming of this wrapper function is totally up to you):

_derivative_symbolic(itp::AbstractInterpolant, t, order::Integer) = itp(t; deriv=DerivOp(order))

Would you mind replacing the derivative references in the extension with something like this (register, chain rules, promote_symtype, etc.) and removing src/symbolic_derivative.jl + export derivative?

I'm also happy to push these changes to your branch if that's easier — just let me know!

@ChrisRackauckas
Copy link
Contributor

That's fine.

ChrisRackauckas and others added 5 commits March 1, 2026 02:08
Per review feedback, removes `derivative` from the core API to avoid
potential name clashes with AD packages. The function now lives entirely
in FastInterpolationsSymbolicsExt as `_derivative_symbolic`, which is
only used as glue between the kwargs API and Symbolics' positional-args
requirement.

- Remove src/symbolic_derivative.jl and export derivative
- Replace all derivative references in extension with _derivative_symbolic
- Update tests to use itp(t; deriv=DerivOp(n)) directly

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions
Copy link
Contributor

github-actions bot commented Mar 1, 2026

FastInterpolations.jl Benchmarks

Details
Benchmark suite Current: 49c1e5c Previous Ratio
10_nd_construct/bicubic_2d 60423.0 ns 60955 ns .99
10_nd_construct/bilinear_2d 1724.42 ns 1889.76 ns .91
10_nd_construct/tricubic_3d 393805.0 ns 416972 ns .94
10_nd_construct/trilinear_3d 4113.68 ns 4081.46 ns 1.00
11_nd_eval/bicubic_2d_batch 1785.3 ns 1841.5 ns .96
11_nd_eval/bicubic_2d_scalar 32.76 ns 33.36 ns .98
11_nd_eval/bilinear_2d_scalar 27.45 ns 28.16 ns .97
11_nd_eval/tricubic_3d_batch 3901.3 ns 4028.5 ns .96
11_nd_eval/tricubic_3d_scalar 56.51 ns 58.61 ns .96
11_nd_eval/trilinear_3d_scalar 32.27 ns 31.86 ns 1.01
12_cubic_eval_gridquery/range_random 4526.64 ns 4523.28 ns 1.00
12_cubic_eval_gridquery/range_sorted 4516.04 ns 4511.06 ns 1.00
12_cubic_eval_gridquery/vec_random 10484.16 ns 10239 ns 1.02
12_cubic_eval_gridquery/vec_sorted 3282.32 ns 3299.58 ns .99
1_cubic_oneshot/q00001 575.68 ns 580.48 ns .99
1_cubic_oneshot/q10000 64394.1 ns 64381.7 ns 1.00
2_cubic_construct/g0100 1529.04 ns 1514.64 ns 1.00
2_cubic_construct/g1000 15220.4 ns 15064.2 ns 1.01
3_cubic_eval/q00001 40.07 ns 38.87 ns 1.03
3_cubic_eval/q00100 509.96 ns 506.36 ns 1.00
3_cubic_eval/q10000 45365.6 ns 45566.5 ns .99
4_linear_oneshot/q00001 45.58 ns 44.08 ns 1.03
4_linear_oneshot/q10000 36881.8 ns 36862.2 ns 1.00
5_linear_construct/g0100 14.43 ns 13.73 ns 1.05
5_linear_construct/g1000 14.13 ns 13.82 ns 1.02
6_linear_eval/q00001 21.44 ns 21.14 ns 1.01
6_linear_eval/q00100 408.96 ns 401.96 ns 1.01
6_linear_eval/q10000 35976.2 ns 36320.1 ns .99
7_cubic_range/scalar_query 26.45 ns 26.74 ns .98
7_cubic_vec/scalar_query 18.84 ns 18.03 ns 1.04
8_cubic_multi/construct_s001_q100 1416.86 ns 1455.72 ns .97
8_cubic_multi/construct_s010_q100 6730.16 ns 6529.04 ns 1.03
8_cubic_multi/construct_s100_q100 50038.1 ns 49256.4 ns 1.01
8_cubic_multi/eval_s001_q100 2113.14 ns 2137.22 ns .98
8_cubic_multi/eval_s010_q100 3513.96 ns 3309.8 ns 1.06
8_cubic_multi/eval_s010_q100_scalar_loop 3649.2 ns 3656.04 ns .99
8_cubic_multi/eval_s100_q100 16426.6 ns 15921.9 ns 1.03
8_cubic_multi/eval_s100_q100_scalar_loop 5056.4 ns 4965.3 ns 1.01
9_nd_oneshot/bicubic_2d 42999.2 ns 44288 ns .97
9_nd_oneshot/bilinear_2d 1697.98 ns 1711.42 ns .99
9_nd_oneshot/tricubic_3d 374196.1 ns 381473.1 ns .98
9_nd_oneshot/trilinear_3d 3393.3 ns 3461.5 ns .98

This comment was automatically generated by Benchmark workflow.

@mgyoo86 mgyoo86 merged commit cbac5e1 into ProjectTorreyPines:master Mar 1, 2026
8 checks passed
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.

Symbolics registration

3 participants