Skip to content

feat: Add reverse/forward counterparts#1036

Open
rsenne wants to merge 3 commits into
JuliaDiff:mainfrom
rsenne:forward-reverse-helpers
Open

feat: Add reverse/forward counterparts#1036
rsenne wants to merge 3 commits into
JuliaDiff:mainfrom
rsenne:forward-reverse-helpers

Conversation

@rsenne

@rsenne rsenne commented Jun 30, 2026

Copy link
Copy Markdown

PR to add the forward/backward counterparts discussed. I wasn't sure if for a generic backend if there was no reasonable counterpart to return e.g., if one did reverse_counterpart(AutoForwardDiff) if the code should throw an ArgumentError or if it should just return the backend. I opted for the former

Resolves #1025.

@rsenne rsenne requested a review from gdalle as a code owner June 30, 2026 02:01
@rsenne rsenne changed the title Add reverse/forward counterparts feat: Add reverse/forward counterparts Jun 30, 2026
@codecov

codecov Bot commented Jun 30, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.29630% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 93.92%. Comparing base (5572e56) to head (1b158a4).

Files with missing lines Patch % Lines
DifferentiationInterface/src/misc/zero_backends.jl 0.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1036      +/-   ##
==========================================
- Coverage   98.21%   93.92%   -4.29%     
==========================================
  Files         138      115      -23     
  Lines        8131     5947    -2184     
==========================================
- Hits         7986     5586    -2400     
- Misses        145      361     +216     
Flag Coverage Δ
DI 93.92% <96.29%> (-5.04%) ⬇️
DIT ?

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@gdalle gdalle left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for getting this started!
Most test failures are a red herring (test CI runs by forcing the highest possible version of each package, which here leads to incompatibilities between the recent OrderedCollections v2.0 and the not-yet-updated DataFrames)

Comment thread DifferentiationInterface/ext/DifferentiationInterfaceEnzymeExt/counterparts.jl Outdated
Comment thread DifferentiationInterface/src/utils/counterparts.jl Outdated
Comment thread DifferentiationInterface/src/utils/counterparts.jl Outdated
Comment thread DifferentiationInterface/test/Core/Internals/backends.jl
Comment thread DifferentiationInterface/test/Back/Mooncake/test.jl
Comment thread DifferentiationInterface/test/Back/Enzyme/test.jl
@rsenne

rsenne commented Jun 30, 2026

Copy link
Copy Markdown
Author

I think I addressed everything:

  • We now emit a warning (and return the backend unchanged) instead of throwing an error
  • Added a testing recipe (test_counterparts) in DIT that I now call in each backend's tests
  • Moved the Mooncake counterparts into the extension
  • Tested that the Mooncake config is carried over to the counterpart
  • Tested that the Enzyme mode attributes are preserved across the flip, plus the <:ReverseMode signature so extra type params won't break DI
  • Generic fallbacks now also cover ForwardOrReverseMode and SymbolicMode

Let me know if anything needs further adjustment!

@gdalle gdalle left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Almost there!

Comment thread DifferentiationInterface/src/utils/counterparts.jl Outdated
Comment thread DifferentiationInterface/src/utils/counterparts.jl Outdated
Comment on lines +35 to +36
# Backend-specific counterparts (e.g., for AutoMooncake and AutoEnzyme) are defined in the
# corresponding package extensions.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are a few more counterparts we need to implement and test in DI core:

  • ADTypes.NoAutoDiff => handled correctly by the defaults above
  • ADTypes.AutoSparse => grab dense_backend, apply counterpart and rewrap?
  • DI.SecondOrder => no idea, cause applying the counterpart to both inner and outer doesn't mean much. Maybe best to error here
  • DI.MixedMode => do nothing
  • DI.AutoForwardFromPrimitive => DI.AutoReverseFromPrimitive (and apply counterpart inside? not sure)
  • DI.AutoReverseFromPrimitive =>DI.AutoForwardFromPrimitive (and apply counterpart inside? not sure)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I basically went with your judgement on everything here as I don;t know the functionality enough to have strong opinions. That said -- your suggestions all made sense to me FWIW

Comment thread DifferentiationInterface/test/Core/Internals/backends.jl Outdated
Comment thread DifferentiationInterfaceTest/src/tests/counterparts.jl
Comment thread DifferentiationInterfaceTest/src/DifferentiationInterfaceTest.jl
@rsenne rsenne requested a review from gdalle July 3, 2026 00:19
@rsenne

rsenne commented Jul 3, 2026

Copy link
Copy Markdown
Author

okay think i got everything again

@gdalle gdalle left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM except

  • the warnings to remove
  • the test failures for Zygote and ReverseDiff
  • the missing coverage

"""
function forward_counterpart(backend::AbstractADType)
if !(mode(backend) isa Union{ForwardMode, ForwardOrReverseMode, SymbolicMode})
@warn "The forward-mode counterpart of `$backend` is itself, returning it unchanged." maxlog =

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, warnings will get annoying quickly, let's get rid of them

"""
function reverse_counterpart(backend::AbstractADType)
if !(mode(backend) isa Union{ReverseMode, ForwardOrReverseMode, SymbolicMode})
@warn "The reverse-mode counterpart of `$backend` is itself, returning it unchanged." maxlog =

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above

Comment on lines +12 to +13
test_counterparts(AutoZeroForward())
test_counterparts(AutoZeroReverse())

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why doesn't this show up in code coverage?

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.

Backend counterparts

2 participants