Repository navigation
Conversation
to_vec(::HermOrSym) rebuilt the matrix from one triangle of the dense vector, so cotangents computed by j′vp and grad had their off-diagonals doubled. Rebuilding from the symmetric/hermitian part instead gives the natural cotangent and still round-trips primals exactly. Fixes #164. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
I am tossing up, is this the right way or should we be actually slicing out just one triangle. (and flip rather than |
|
That was my first thought as well (see also #164 and #132). The problem is that Example: for a 2×2 For
That's what this PR does. |
Fixes #164.
to_vec(::HermOrSym)vectorizes the dense matrix, but itsfrom_vecrebuilt the result from only one triangle. For primals that's fine, because both triangles agree. For cotangents (j′vp,grad) each off-diagonal entry collects contributions from both triangles, so the result had its off-diagonals doubled:from_vecnow rebuilds from the symmetric part(X + transpose(X)) / 2, or the hermitian part(X + X') / 2. That gives the natural cotangent, i.e. all ones above. It also matchesChainRulesCore.ProjectTo(::Symmetric), and primals still round-trip exactly.Behaviour change:
j′vp,gradandjacobianwith respect toSymmetric/Hermitianinputs return different (correct) values. For example, the rawjacobian(fdm, sum, Symmetric(A))changes from[1 0 2 1]to[1 1 1 1], with the two triangles now sharing the derivative. ChainRules.jl has rules and tests that compensate for the old double counting, for examplerrule(::Type{<:Matrix}, ::HermOrSym). They will fail once this is released, so I'll open a ChainRules.jl PR that switches them to natural tangents and requires FiniteDifferences 0.12.35. Please coordinate the release with that PR. This change came up via JuliaDiff/ChainRules.jl#783.Tests: new
jvp/j′vptestset forSymmetric/Hermitian×Float64/ComplexF64× bothuplo. It fails on main (off-diagonals 2×) and passes here. Bumps the version to 0.12.35.🤖 Generated with Claude Code