Define VJP and JVP for numpy.flip - #797
Open
Mohit-Ak wants to merge 1 commit into
Open
Conversation
flipud, fliplr and rot90 all have derivative rules registered, but flip does not, so differentiating through it raises NotImplementedError. Register the rules for flip alongside its siblings: the reverse-mode rule flips the cotangent back along the same axes, and forward mode is a plain 'same' rule since flip is a linear reindexing. Fixes HIPS#725
Mohit-Ak
marked this pull request as ready for review
August 3, 2026 02:30
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.
numpy.fliphas no derivative rule registered, so any function that uses it dies atgradient time:
This is inconsistent rather than intentional:
flipud,fliplrandrot90— theother members of the same reversal family, sitting on adjacent lines in
numpy_vjps.py/numpy_jvps.py— all have rules.flipis the general-axisversion of exactly those functions, so it just looks like it was missed.
The fix
Two lines, registered next to their siblings:
flipis a permutation of the input, so it is its own adjoint —flipping the cotangent back along the same axes gives the gradient.
Passing
axisstraight through covers all the forms numpy accepts (None,an int, or a tuple of ints).
"same", matchingflipud/fliplr/rot90, sinceflipis alinear reindexing.
I registered the JVP as well as the VJP because
check_gradsexercises bothdirections, and leaving forward mode out would have left
fliphalf-broken inthe same way.
Testing
Added
test_flip,test_flip_axisandtest_flip_axis_tupletotests/test_numpy.py, directly alongside the existingtest_flipud/test_fliplr/test_rot90and following the samecheck_gradspattern. Theycover the default (all-axes) case, a single named axis, and a tuple of axes on a
3-D array.
All three fail on
masterwithNotImplementedError: JVP of flip wrt argnums (0,) not definedand pass with the change.Full suite on the branch:
(The 13 skips are the
xarray-dependent tests intest_ufunc_dispatch.py;xarrayisn't installed in my env. Nothing else changed status.)Linting with the version pinned in
.pre-commit-config.yaml(ruff 0.15.22):I also checked the gradient values themselves rather than relying on
check_gradsalone — comparing against central finite differences for shapes
(5,),(4,5)and
(3,4,5)acrossaxis=None/0/1/(0,2)agrees to ~1e-8, andflip(x, 0)/flip(x, 1)produce gradients identical to the existingflipud/fliplrrules.Fixes #725