Skip to content

NonlinearSolveBase: unwrap FunctionWrappersWrapper on the EnzymeOriginator adjoint path (MTK DAE init) - #946

Merged
ChrisRackauckas merged 1 commit into
SciML:masterfrom
ChrisRackauckas-Claude:claude/enzyme-init-unwrap-functionwrapper
May 31, 2026
Merged

ChrisRackauckas merged 1 commit into
SciML:masterfrom
ChrisRackauckas-Claude:claude/enzyme-init-unwrap-functionwrapper

Conversation

@ChrisRackauckas-Claude

Copy link
Copy Markdown
Member

Please ignore until reviewed by @ChrisRackauckas.

Summary

Follow-up to #944 (which fixed the solve_up Enzyme rule plumbing). With that landed, Enzyme reverse-mode through an MTK DAE solve gets into the initialization NonlinearProblem solve and then fails with:

EnzymeRuntimeException: Enzyme execution failed.
Expected return type of primal to be SciMLBase.NonlinearSolution{...} but did not find a value of that type
  get_initial_values  (the OverrideInit init solve, under Enzyme reverse)

Root cause — a FunctionWrappersWrapper type-instability:

  • The custom solve_up rule re-runs the solve via _solve_adjoint → get_concrete_problem, which maybe_wrap_nonlinear_f-wraps the IIP function in AutoSpecializeCallable{FunctionWrappersWrapper} (confirmed by instrumenting typeof(res[1])).
  • That wrapping is type-unstable. Enzyme's traced forward unwraps it via maybe_unwrap_prob_for_enzyme (Skip FunctionWrappersWrapper in maybe_wrap_nonlinear_f under Enzyme AD #940), so the return type Enzyme infers carries the bare GeneratedFunctionWrapper; the adjoint re-wraps it, so the rule's primal type no longer matches → Enzyme aborts.
  • maybe_unwrap_prob_for_enzyme keys off the solver's own autodiff, which for an MTK DAE init is ForwardDiff even when the outer differentiation is Enzyme — so it doesn't fire here.

Fix: key off the originator instead — unwrap _prob.f.f via get_raw_f when originator isa EnzymeOriginator, so the adjoint primal matches the (unwrapped) type Enzyme's traced forward produces. No-op for non-Enzyme originators and for already-unwrapped functions.

Verification status (please read)

  • The fix is a 13-line addition; the edit is confirmed sound (the stack loads and forward-solves with retcode = Success).
  • Strong evidence it clears the error, but not yet a completed end-to-end gradient check. Pre-fix, the MTK-init Enzyme reverse threw the EnzymeRuntimeException ~21 min into compilation; with the fix, the run reached ~26 min in the full reverse compile with no such error before the process was OOM-killed.
  • The completed correct-gradient comparison (vs ForwardDiff) is pending: the test machine is under heavy multi-agent load and repeatedly system-OOM-kills this ~26-min Enzyme compile (oom_kill 77 on the session cgroup). I'll post the gradient comparison once it completes in a less-contended window / via CI.

Companion to SciML/SciMLSensitivity#1463; built on #944 (merged) and DiffEqBase 7.5.4 / OrdinaryDiffEq#3700 (merged).

🤖 Generated with Claude Code

…nator adjoint path

Follow-up to SciML#944. When Enzyme reverse-mode differentiates through an MTK DAE
solve, the initialization solves a `NonlinearProblem` via `solve_up`. The custom
`solve_up` Enzyme rule re-runs the solve through `_solve_adjoint` ->
`get_concrete_problem`, which `maybe_wrap_nonlinear_f`-wraps the IIP function in a
`FunctionWrappersWrapper` (`AutoSpecializeCallable`). That wrapping is type-unstable:
Enzyme's traced forward solve unwraps it (`maybe_unwrap_prob_for_enzyme`, SciML#940) so
its inferred return type carries the bare function, but the adjoint re-wraps it, so
the rule's returned primal type no longer matches and Enzyme aborts with
`EnzymeRuntimeException: Expected return type of primal to be NonlinearSolution{...}`.

`maybe_unwrap_prob_for_enzyme` keys off the solver's own autodiff, which for an MTK
DAE init is ForwardDiff even when the outer differentiation is Enzyme, so it does not
fire on this path. Key off the originator instead: unwrap `_prob.f.f` via `get_raw_f`
when `originator isa EnzymeOriginator`, matching the (unwrapped) type Enzyme's traced
forward produces.

Companion to SciML/SciMLSensitivity#1463.

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ChrisRackauckas
ChrisRackauckas marked this pull request as ready for review May 31, 2026 02:55
@ChrisRackauckas
ChrisRackauckas merged commit 7dd7436 into SciML:master May 31, 2026
87 of 121 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.

2 participants