Skip to content

Add DEIIPFunctionWrapper structs to reduce stack trace length#1285

Open
ChrisRackauckas-Claude wants to merge 3 commits intoSciML:masterfrom
ChrisRackauckas-Claude:iip-function-wrapper-aliases
Open

Add DEIIPFunctionWrapper structs to reduce stack trace length#1285
ChrisRackauckas-Claude wants to merge 3 commits intoSciML:masterfrom
ChrisRackauckas-Claude:iip-function-wrapper-aliases

Conversation

@ChrisRackauckas-Claude
Copy link
Contributor

@ChrisRackauckas-Claude ChrisRackauckas-Claude commented Feb 21, 2026

Summary

Addresses part of SciML/DifferentialEquations.jl#1128 (FunctionWrappersWrapper bloat in stack traces).

Introduces wrapper structs (not type aliases) around FunctionWrappersWrapper to dramatically shorten type strings in stack traces:

  • 1-wrapper (non-ForwardDiff): ~170 chars → ~90 chars (47% reduction)
  • 4-wrapper (ForwardDiff): ~1,077 chars → ~350 chars (67% reduction)

Key insight: const Foo{T} = Bar{T} type aliases do NOT change how typeof(x) prints in Julia — only new struct types reduce the printed representation.

New structs (defined in DiffEqBase, exported)

  • DEIIPFunctionWrapper{duType, uType, pType, tType} — wraps a FunctionWrappersWrapper with 1 FunctionWrapper for solvers that don't use ForwardDiff (e.g. Tsit5, Verner)
  • DEIIPFunctionWrapperForwardDiff{T1, T2, T3, T4, dT1, dT2, dT4} — wraps a FunctionWrappersWrapper with 4 FunctionWrapper entries covering base/dual-state/dual-time/dual-both argument combinations
  • AnyFunctionWrapperUnion{FunctionWrappersWrapper, DEIIPFunctionWrapper, DEIIPFunctionWrapperForwardDiff} for isa checks
  • DEIIPFunctionWrapperVF64{pType} — VF64-specialized alias for DEIIPFunctionWrapper
  • wrapfun_iip_simple(ff, du, u, p, t) — constructor that always creates a 1-wrapper, avoiding ForwardDiff extension backedges

In ForwardDiff extension (access via Base.get_extension)

  • DEIIPFunctionWrapperForwardDiffVF64{pType} — VF64-specialized alias
  • ODEDualTagForwardDiff.Tag{OrdinaryDiffEqTag, Float64}
  • ODEDualTypeForwardDiff.Dual{ODEDualTag, Float64, 1}

Changes to existing code

  • solve.jl: Uses AnyFunctionWrapper instead of FunctionWrappersWrappers.FunctionWrappersWrapper for isa checks; uses wrapfun_iip_simple for the non-ForwardDiff path
  • ForwardDiff extension's wrapfun_iip(ff, inputs::Tuple{T1,T2,T3,T4}) now returns DEIIPFunctionWrapperForwardDiff(inner) instead of raw FunctionWrappersWrapper
  • Both structs delegate calls via (f::DEIIPFunctionWrapper)(args...) = f.fw(args...)
  • Both support isfunctionwrapper and unwrapped_f

Usage example (downstream package)

using DiffEqBase: DEIIPFunctionWrapperVF64

# ForwardDiff-specific aliases from the extension
const FDExt = Base.get_extension(DiffEqBase, :DiffEqBaseForwardDiffExt)
const DEIIPFWForwardDiffVF64 = FDExt.DEIIPFunctionWrapperForwardDiffVF64

# Use in struct field annotations
mutable struct ODEIntegratorVF64{pType, ...}
    f_simple::DEIIPFunctionWrapperVF64{pType}
    # or for stiff solvers:
    f_dual::DEIIPFWForwardDiffVF64{pType}
end

Test plan

  • New function_wrapper_aliases.jl test file (27 tests) verifying:
    • DEIIPFunctionWrapper struct creation and type matching
    • DEIIPFunctionWrapperVF64 alias with both Vector{Float64} and NullParameters
    • ODEDualTag and ODEDualType equal the expected ForwardDiff types
    • DEIIPFunctionWrapperForwardDiff struct from wrapfun_iip
    • DEIIPFunctionWrapperForwardDiffVF64 alias
    • AnyFunctionWrapper union matching
    • Call operator, isfunctionwrapper
    • Type string does NOT contain "FunctionWrappersWrapper" (key stack trace test)
    • wrapfun_iip_simple always produces 1-wrapper even with ForwardDiff loaded
    • 7-wrapper default does NOT match 4-wrapper struct
  • Full Pkg.test() passes (all existing tests unaffected)

🤖 Generated with Claude Code

…ngth

Replace type aliases with actual wrapper structs that hide the verbose
FunctionWrappersWrapper type parameters from stack traces.

Before (1,077 chars for ForwardDiff wrapper):
  FunctionWrappersWrappers.FunctionWrappersWrapper{Tuple{FunctionWrappers.FunctionWrapper{Nothing, Tuple{...}}, ...}, false}

After (~350 chars):
  DiffEqBase.DEIIPFunctionWrapperForwardDiff{Vector{Float64}, Vector{Float64}, Vector{Float64}, Float64, Vector{Dual{...}}, Vector{Dual{...}}, Dual{...}}

New types (exported from DiffEqBase):
- DEIIPFunctionWrapper{duType, uType, pType, tType}: 1-wrapper struct
  for solvers without ForwardDiff (e.g. Tsit5, Verner)
- DEIIPFunctionWrapperVF64{pType}: VF64-specialized alias
- DEIIPFunctionWrapperForwardDiff{T1,T2,T3,T4,dT1,dT2,dT4}: 4-wrapper
  struct for ForwardDiff-aware solvers (Rosenbrock, implicit methods)
- AnyFunctionWrapper: Union type for isa checks
- wrapfun_iip_simple(ff, du, u, p, t): constructor that avoids
  ForwardDiff extension backedges

ForwardDiff extension provides:
- DEIIPFunctionWrapperForwardDiffVF64{pType}: VF64-specialized alias
- ODEDualTag, ODEDualType: named aliases for ODE dual types

Addresses DifferentialEquations.jl#1128.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@ChrisRackauckas-Claude ChrisRackauckas-Claude changed the title Add simpler type aliases and constructors for IIP FunctionWrappers Add DEIIPFunctionWrapper structs to reduce stack trace length Feb 21, 2026
ChrisRackauckas and others added 2 commits February 21, 2026 14:02
Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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