Skip to content

Fix Zygote sol[:, j] (getindex ::Colon, ::Integer) returning zero gradient#1415

Merged
ChrisRackauckas merged 1 commit into
SciML:masterfrom
ChrisRackauckas-Claude:claude/zygote-getindex-colon-int
Jul 2, 2026
Merged

Fix Zygote sol[:, j] (getindex ::Colon, ::Integer) returning zero gradient#1415
ChrisRackauckas merged 1 commit into
SciML:masterfrom
ChrisRackauckas-Claude:claude/zygote-getindex-colon-int

Conversation

@ChrisRackauckas-Claude

Copy link
Copy Markdown
Contributor

Ignore until reviewed by @ChrisRackauckas.

Under RecursiveArrayTools v4, AbstractVectorOfArray getindex adjoints are inherited from Zygote's generic AbstractArray rules, so sol[:, j] (whole state at timestep j) had no VectorOfArray-specific adjoint and fell through to ChainRules' generic ∇getindex — whose cotangent the solve reverse pass reads as zero. So Zygote.gradient of e.g. sum(sol[:, end]) came back all zeros (silently wrong), while sol[i], sol[:, :], and sol.u[end] were fine.

Adds an @adjoint getindex(::ODESolution, ::Colon, ::Integer) that scatters the cotangent into the j-th slot of a per-timestep cotangent, mirroring the existing sol[i::Integer] rule. ::Colon is more specific than the existing (sym, j::Integer) method, so sol[:, j] dispatches here.

Verified (Julia 1.10.11): Zygote.gradient of sum(solve(prob; p)[:, end]) and [:, 2] now match ForwardDiff.gradient (were [0,0,0,0]); sol[:, :]/sol.u[end] unchanged. Fixes SciMLSensitivity #1522 (the Core1 "VecOfArray - Zygote" failure) — same family as #1410.

🤖 Generated with Claude Code

…dient

Under RecursiveArrayTools v4, `AbstractVectorOfArray` getindex adjoints are
inherited from Zygote's generic AbstractArray rules, so `sol[:, j]` (whole state
at timestep j) had no VectorOfArray-specific adjoint and fell through to
ChainRules' generic `∇getindex`, whose cotangent the solve reverse pass reads as
zero. `Zygote.gradient` of e.g. `sum(sol[:, end])` therefore came back all zeros
(silently wrong), while `sol[i]`, `sol[:, :]` and `sol.u[end]` were fine.

Add an `@adjoint getindex(::ODESolution, ::Colon, ::Integer)` that scatters the
cotangent into the j-th slot of a per-timestep cotangent, mirroring the existing
`sol[i::Integer]` rule. The `::Colon` method is more specific than the existing
`(sym, j::Integer)` method, so `sol[:, j]` dispatches to it.

Verified (Julia 1.10.11): Zygote.gradient of `sum(solve(prob;p)[:, end])` and
`[:, 2]` now match ForwardDiff (were `[0,0,0,0]`). Fixes the SciMLSensitivity
Core1 "VecOfArray - Zygote" failure (SciMLSensitivity#1522).

Co-Authored-By: Chris Rackauckas <accounts@chrisrackauckas.com>
@ChrisRackauckas ChrisRackauckas marked this pull request as ready for review July 2, 2026 16:54
@ChrisRackauckas ChrisRackauckas merged commit bc6bad4 into SciML:master Jul 2, 2026
36 of 63 checks passed
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