Skip to content

DiffEqBaseEnzymeExt: accept any sensealg Annotation (unblocks SciMLSensitivity #1456)#3679

Draft
ChrisRackauckas-Claude wants to merge 1 commit into
SciML:masterfrom
ChrisRackauckas-Claude:enzyme-loosen-sensealg-annotation
Draft

DiffEqBaseEnzymeExt: accept any sensealg Annotation (unblocks SciMLSensitivity #1456)#3679
ChrisRackauckas-Claude wants to merge 1 commit into
SciML:masterfrom
ChrisRackauckas-Claude:enzyme-loosen-sensealg-annotation

Conversation

@ChrisRackauckas-Claude
Copy link
Copy Markdown
Contributor

[DRAFT — please ignore until reviewed by @ChrisRackauckas]

Summary

DiffEqBaseEnzymeExt.augmented_primal / reverse rules on DiffEqBase.solve_up were signed for sensealg::Union{Const{Nothing}, Const{<:AbstractSensitivityAlgorithm}}. That signature was too narrow: under Enzyme.set_runtime_activity(Reverse), Enzyme can promote a module-level const _MTK_SENSEALG = GaussAdjoint(...) reference — or any sensealg captured in an ODEProblem field — to Duplicated{<:AbstractSensitivityAlgorithm} before the rule is matched. The rule then failed to dispatch and Enzyme fell back to native reverse, producing a MethodError.

This loosens both rules to accept any Enzyme.Annotation on sensealg (Const / Duplicated / MixedDuplicated / Active) and reads only sensealg.val inside; the shadow on sensealg has no semantic meaning because an AbstractSensitivityAlgorithm is a configuration token, not a derivative-carrying value.

Why this is safe

SciMLBase already declares EnzymeRules.inactive_type(::Type{<:AbstractSensitivityAlgorithm}) = true, expressing the same semantic. The narrow Const-only signature was an unnecessary additional restriction. The body of both rules now skips sensealg's slot when accumulating cotangents, regardless of which annotation it arrived under.

Reproducer

The @test_broken Enzyme block in SciML/SciMLSensitivity.jl test/mtk.jl calls solve(prob, Rodas5P(); sensealg = _MTK_SENSEALG, ...) under Enzyme.autodiff(set_runtime_activity(Reverse), ..., Duplicated(prob, diprob)). Before this PR, it failed with MethodError on the solve_up rule's sensealg signature.

After this PR, the rule dispatches and execution proceeds into _solve_adjoint. It then hits a separate downstream MethodError inside Enzyme's runtime_generic_augfwd trying to construct MixedDuplicated(::ODESolution, ...) without the required Base.RefValue{T1} second argument — the MTK runtime-activity wrapping issue tracked in SciMLSensitivity.jl#1359 / EnzymeAD/Enzyme.jl#3117. That is out of scope here, so the @test_broken in #1456 stays broken pending the upstream Enzyme fix.

Bumps

DiffEqBase 7.5.1 → 7.5.2.

Test plan

  • CI green
  • Confirms solve_up Enzyme rule still dispatches under plain Reverse (sanity, all existing tests)
  • Manual: focused MWE shows MethodError moves from rule dispatch to downstream MTK wrapping (documented above)

Linked: SciML/SciMLSensitivity.jl#1456

`sensealg` is a configuration token whose tangent has no semantic
meaning, so its annotation should not constrain rule dispatch. But
Enzyme's `set_runtime_activity(Reverse)` mode can promote a
module-level `const _SENSEALG = GaussAdjoint(...)` reference (or any
sensealg captured in an `ODEProblem` field) to
`Duplicated{<:AbstractSensitivityAlgorithm}` before the rule is
matched. The previous `sensealg::Union{Const{Nothing}, Const{<:AbstractSensitivityAlgorithm}}`
signature then failed to dispatch and Enzyme fell back to native
reverse, producing a `MethodError`.

Accept any `Enzyme.Annotation` here and read only `sensealg.val`; the
shadow has no semantic meaning. Defensive type check inside the body
guards against accidental misuse.

Unblocks the `@test_broken` Enzyme block in SciML/SciMLSensitivity.jl
`test/mtk.jl` (SciML#1456).

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.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