Skip to content

Handle AD-valued interpolation knots#557

Draft
ChrisRackauckas-Claude wants to merge 1 commit into
SciML:masterfrom
ChrisRackauckas-Claude:agent/fix-dual-search-properties
Draft

Handle AD-valued interpolation knots#557
ChrisRackauckas-Claude wants to merge 1 commit into
SciML:masterfrom
ChrisRackauckas-Claude:agent/fix-dual-search-properties

Conversation

@ChrisRackauckas-Claude

Copy link
Copy Markdown
Contributor

Please ignore this PR until reviewed by @ChrisRackauckas.

Summary

  • avoid probing FindFirstFunctions.SearchProperties with AD-valued knot vectors
  • preserve cached search properties for primitive integer and floating-point knots
  • use FindFirstFunctions' public empty SearchProperties() sentinel for number wrappers, selecting the correct binary-search fallback
  • apply the shared private helper across interpolation and integral-inverse constructors
  • add a 15-knot ForwardDiff regression that differentiates through values and knots together

Root cause

Reconstructing an interpolation inside ForwardDiff can promote both the interpolation values and knot vector to ForwardDiff.Dual. For vectors with at least 11 knots, SearchProperties(t) runs the sampled linear-fit probe. FindFirstFunctions._sampled_linear_err then attempts a Float64(::ForwardDiff.Dual) conversion and throws before interpolation evaluation.

The existing four-knot ForwardDiff coverage from #510 / #513 does not enter that sampled probe.

The constructor pattern

something(search_properties, FindFirstFunctions.SearchProperties(t))

also evaluates the default probe eagerly even when callers supply search properties. The private dispatch helper in this PR avoids that eager evaluation.

Primitive Integer and AbstractFloat knots still receive populated properties and retain the fast path. Other number wrappers receive the documented zero-information sentinel and use binary search. This uses only public FindFirstFunctions APIs and introduces no new public DataInterpolations API.

Regression boundary

I reproduced the same 15-knot combined value/knot gradient at adjacent DataInterpolations commits:

  • 9ad45d3426c19c38c6a0da93eedb971b04087fbc (Migrate to FindFirstFunctions 2.0 strategy API): passes
  • e22f5d6a6fa8d72079b33209b910b9504c4cadde (Cache SearchProperties per interpolation to skip per-call Auto probes): fails with Float64(::ForwardDiff.Dual)

There is exactly one commit between those endpoints, so e22f5d6 is the first bad commit. It first shipped in DataInterpolations v9.0.0; v8.10.0 does not contain it.

Related history: #229 / #230 added ForwardDiff support, while #510 / #513 added differentiation-through-knots coverage with only four knots.

Downstream classification

ModelingToolkitStandardLibrary currently supports DataInterpolations 8.x, not 9.x. The exact combined 15-knot MRE passes under its supported versions:

DataInterpolations=8.10.0
FindFirstFunctions=1.8.0
ForwardDiff=1.4.1
value=3.5
gradient_length=30
gradient_sum=0.0

An unmodified current-main MTKStandardLibrary test/sources.jl run was independently blocked before its interpolation assertions by fntype_X_Y(::Type{Real}). That clean-main callable-symtype defect is fixed and tracked separately in ModelingToolkitStandardLibrary.jl#480.

With #480's commit applied while retaining the supported DataInterpolations 8.10.0 environment:

ParametrizedInterpolation | 10 passed, 1 pre-existing broken, 11 total
initial_retcode=Success
ones_retcode=Success
zeros_retcode=Success
gradient_length=15

Therefore this PR fixes the DataInterpolations 9 regression; it does not alter MTKStandardLibrary compatibility or code.

Local verification

Julia 1.12.6:

  • GROUP=Core julia +1.12 --project -e 'using Pkg; Pkg.test()'
    • 17,567 passed
    • 5 pre-existing broken
    • Testing DataInterpolations tests passed
  • GROUP=Methods julia +1.12 --project -e 'using Pkg; Pkg.test()'
    • derivative: 34,479 / 34,479
    • integral inverse: 317 / 317
    • integral: 6,591 / 6,591
    • online: 30 / 30
    • thread safety: 21 / 21
    • aggregate: 41,438 / 41,438
    • Testing DataInterpolations tests passed
  • patched DataInterpolations 9.0.2 / FindFirstFunctions 3.1.0 / ForwardDiff 1.4.1 exact MRE:
    • value 3.5
    • 30-element gradient
    • gradient sum 0.0
    • exact expected nonzeros [3 => 0.5, 4 => 0.5, 18 => -0.5, 19 => -0.5]
  • whole-repository Runic: Runic.main(["--check", "."]) exited 0
  • git diff --check passed

Investigation and implementation record

  1. inspected the downstream failure and existing interpolation/ForwardDiff history
  2. reproduced supported DataInterpolations 8.10.0 and failing 9.0.2 environments independently
  3. reduced the trigger to combined differentiation through 15 values and 15 knots
  4. bisected to adjacent commits 9ad45d3 and e22f5d6
  5. verified the sampled search-property probe is only reached for the longer knot vector
  6. implemented one shared private fallback using public FindFirstFunctions constructors
  7. added exact regression coverage without skipping, silencing, or weakening any assertion
  8. ran the focused MRE, Core, Methods, Runic, and supported-downstream controls locally

Copy link
Copy Markdown
Contributor Author

Commit 9faed1f44b339d77a99f4f744192423b5af04369 implements the shared AD-knot search-property fallback and exact 15-knot regression.

Local evidence for this commit:

  • DataInterpolations Core: 17,567 passed, 5 pre-existing broken
  • DataInterpolations Methods: 41,438 / 41,438 passed
  • patched 9.0.2 combined value/knot MRE: exact 30-element gradient, sum 0.0
  • supported 8.10.0 control: same exact gradient already passes
  • MTKStandardLibrary supported-8 control after independent refactor: retain compatibility for PrettyTables@2.4 #480 blocker: ParametrizedInterpolation 10 passed, 1 pre-existing broken
  • whole-repository Runic and git diff --check: clean

The branch is based on current upstream master at b181e3b; no rebase is currently needed.

@ChrisRackauckas-Claude

Copy link
Copy Markdown
Contributor Author

Post-timer CI check: all 18 reported checks are green, including Core on Julia lts/1/pre, Methods on Julia lts/1/pre, Extensions on Julia lts/1, Misc on Julia lts/1/pre, QA, Downgrade, documentation, Runic, and spelling.

Reconstructing an interpolation inside ForwardDiff promotes both the values
and the knot vector to `ForwardDiff.Dual`. On FindFirstFunctions < 3.2 the
`SearchProperties` linearity probe attempted an invalid `Float64(::Dual)`
conversion, breaking `LinearInterpolation` (and the other constructors) for
11+ knots — the v9.0.0 regression.

FindFirstFunctions 3.2 fixes the probe upstream (SciML/FindFirstFunctions.jl#100),
so no local opt-out shim is needed: bump the compat lower bound to `3.2` and
keep using `something(search_properties, FindFirstFunctions.SearchProperties(t))`
directly. Adds a regression test differentiating through both values and knots
across 15 knots.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FvBXVKGujjeaCB3iLwsDeG
@ChrisRackauckas-Claude ChrisRackauckas-Claude force-pushed the agent/fix-dual-search-properties branch from 90b22a0 to 13dff09 Compare July 13, 2026 20:38
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.

2 participants