Skip to content
This repository was archived by the owner on Aug 20, 2026. It is now read-only.

pushpull: fix three zero-stub bugs in the linear grad_backward kernels - #45

Merged
balbasty merged 1 commit into
mainfrom
claude/pushpull-grid-backward
Jul 31, 2026
Merged

pushpull: fix three zero-stub bugs in the linear grad_backward kernels#45
balbasty merged 1 commit into
mainfrom
claude/pushpull-grid-backward

Conversation

@balbasty

Copy link
Copy Markdown
Collaborator

Part of the stack for fastfields-torch#16 (backpropagate through the pushpull sampling grid).

Stacked PR. Base is claude/cuda-pushpull-dynamic-spline (#44), not main — this builds on the spline::type::Dynamic work. Retarget to main once #44 merges.

What

grad_backward (the adjoint of the spatial-gradient sampler grad) had hard-coded zeros in the Linear specialisations, inherited verbatim from jitfields. Exposing the backward ops through the public ABI put them under a finite-difference oracle for the first time, and all three showed up as hard failures.

kernelwaswhy it is wrong
1D Lineard/d(inp) = 0grad is linear in inp with the location-independent weight pair (negate, +1); the adjoint is that same pair scattered back. (Its zero d/d(loc)is correct — a linear basis has a piecewise-constant derivative, whose own derivative vanishes.)
2D Lineard/d(grid) = 0Only the pure second derivatives vanish for a linear basis. The mixed one does not, and it is exactly what dL/d(loc) is made of here.
3D Lineard/d(grid) = 0Same, all three mixed terms.

The general-order kernels already get this right — they accumulate accxy/accxz/accyz from hindex. The Linear fast paths just dropped the cross terms. Restored with the same convention, so Linear now agrees with what the general-order path would compute for the same configuration.

Reading inp from the 2D/3D kernels makes their stride_inp argument live (3D's was even marked /* unused */). Input offsets are built beforeix/iy/iz are scaled in place by the output strides, since the two tensors need not share a layout.

Verification

6381/6381 finite-difference checks pass — ndim 1/2/3, orders 0–3, bounds DCT2/DST2, with and without a batch dimension. Before this fix the Linear cases failed 160 of them. The oracle itself lives in fastfields-cpu-lib (tests/test_pushpull_backward.cpp) since that is where these kernels are reachable from a test.

Workstream: claude-jitfields-to-fastfields

🤖 Generated with Claude Code


Generated by Claude Code

`grad_backward` (the adjoint of the spatial-gradient sampler `grad`) had
hard-coded zeros in the Linear specialisations, inherited verbatim from
jitfields. Exposing the backward ops through the public ABI put them under
a finite-difference oracle for the first time
(fastfields-cpu-lib/tests/test_pushpull_backward.cpp) and all three showed
up as hard failures:
* **1D Linear** returned a zero gradient wrt `inp`. `grad` is linear in
`inp` with the location-independent weight pair (negate, +1), so the
adjoint is that same pair scattered back -- definitely not zero. (Its
zero gradient wrt `loc` *is* correct: a linear basis has a piecewise
constant derivative, whose own derivative vanishes.)
* **2D and 3D Linear** returned a zero gradient wrt `grid`. Only the
*pure* second derivatives d2/dx2, d2/dy2, d2/dz2 vanish for a linear
basis; the *mixed* ones do not, and they are exactly what dL/d(loc)
is made of here. The general-order kernels already get this right (they
accumulate accxy/accxz/accyz from `hindex`); the Linear fast paths just
dropped the cross terms. Restored with the same convention, so Linear
now agrees with what the general-order path would compute.
Reading `inp` from the 2D/3D kernels means their `stride_inp` argument is
now live (3D's was even marked `/* unused */`); the input offsets are built
before ix/iy/iz are scaled in place by the *output* strides, since the two
tensors need not share a layout.
Verified: 6381/6381 finite-difference checks pass across ndim 1/2/3, orders
0-3, bounds DCT2/DST2, with and without a batch dimension. Before the fix,
the Linear cases failed 160 of them.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016AjQcY78NgbagPSbPJRr6Z
@balbasty

Copy link
Copy Markdown
CollaboratorAuthor

good to go

Base automatically changed from claude/cuda-pushpull-dynamic-spline to mainJuly 31, 2026 21:01
@balbasty
balbasty merged commit 15295c2 into mainJul 31, 2026
1 check passed
@balbasty
balbasty deleted the claude/pushpull-grid-backward branch July 31, 2026 21:02
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@balbasty@claude