Accept Annotation{<:FunctionWrappersWrapper} in Enzyme rules (closes #48)#49
Merged
ChrisRackauckas merged 1 commit intoMay 21, 2026
Conversation
Relaxes the `func` argument type in the forward, augmented_primal, and
reverse rules from `Const{<:FunctionWrappersWrapper}` to
`Annotation{<:FunctionWrappersWrapper}` so that callers passing
`Duplicated{<:FunctionWrappersWrapper}` also dispatch through these rules
instead of falling off to a MethodError.
Closes SciML#48.
Why this is safe: a `FunctionWrappersWrapper` only carries
`FunctionWrapper`s plus cache storage; none of those fields have a
meaningful tangent. The function shadow is therefore ignored — `func.val`
(the primal wrapper) is unwrapped and the inner `Enzyme.autodiff` call
delegates with `Const(f_orig)` exactly as in the previous `Const`-only
path. Enzyme drives the rule with a `Duplicated` function annotation
when the outer `autodiff` call is differentiating through a closure that
captures an FWW — the SciML `NonlinearSolve` + `SciMLSensitivity` path
in the issue is one such case.
Adds four testsets that drive each forward / augmented_primal / reverse
rule with `Duplicated(fww, fww)` to lock in the broader dispatch.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #48 (
Missing EnzymeRule—MethodError: no method matching forward(...::Duplicated{FunctionWrappersWrapper...}...)).The existing forward / augmented_primal / reverse rules in
FunctionWrappersWrappersEnzymeExtdispatched only onfunc::Const{<:FunctionWrappersWrapper}. Issue #48's repro (NonlinearSolve + SciMLSensitivity + Enzyme.Forward) drives the rule withfunc::Duplicated{<:FunctionWrappersWrapper}instead, which fell off tocustom_rule_method_error.This PR relaxes the
funcargument type toAnnotation{<:FunctionWrappersWrapper}across every rule (4 forward × 4 reverse), soDuplicated/BatchDuplicatedfunction annotations dispatch through the same code path asConst.Why is this safe?
A
FunctionWrappersWrapperonly carriesFunctionWrappers plus cache storage — none of those fields have a meaningful tangent. The function shadow is therefore ignored: we still unwrapfunc.val(the primal wrapper) and delegate toEnzyme.autodiff(..., Const(f_orig), ...)exactly as the previousConst-only path did. The argument shadows, the return shadow, and the runtime-activity / strong-zero flags continue to flow through unchanged.Enzyme drives the rule with a
Duplicatedfunction annotation when the outerautodiffcall is differentiating through a closure that captures an FWW — Issue #48's repro is one such case.Reproduction (minimal)
Before:
MethodError: no method matching forward(::FwdConfigWidth{1,...}, ::Duplicated{FunctionWrappersWrapper{...}}, ::Type{Const{Nothing}}, ...)After:
residual=[3.0],dresidual=[4.0]— primal and shadow propagate correctly.Tests
Adds four new testsets exercising each rule branch with
Duplicated(fww, fww):Enzyme forward, Duplicated FWW annotation — IIP Const return(the issue's failing pattern)Enzyme forward, Duplicated FWW annotation — shadow-only return({false, true} rule)Enzyme forward, Duplicated FWW annotation — primal + shadow return({true, true} rule)Enzyme reverse, Duplicated FWW annotation — Const return IIPLocal test results on Julia 1.11 (Enzyme v0.13.147):
The 1 pre-existing failure (
Enzyme batch forward mode (width > 1)—TypeError: in typeassert, expected Tuple{Float64,Float64}, got @NamedTuple{1::Float64, 2::Float64}inside Enzyme'senzyme_call) reproduces on unmodifiedmainand is unrelated to this change — looks like an Enzyme upstream issue with BatchDuplicated tuple shadows; investigating separately.Note on the full SciML repro
Issue #48's
NonlinearSolve+SciMLSensitivityrepro will still hit a different (deeper) Enzyme runtime error after this fix — but that error is no longer thecustom_rule_method_errorthe issue reports. The specificMethodErrorforforward(...::Duplicated{FunctionWrappersWrapper}...)is what's closed here; remaining downstream issues belong inNonlinearSolveBase/SciMLSensitivityand aren't fixable in this package.Test plan
Enzyme batch forward (width > 1)failure reproduces identically onmain(not caused by this PR)🤖 Generated with Claude Code