Skip to content

Fix matrix-function primal type for Hermitian{<:Real} on Julia 1.12#840

Open
CarloLucibello wants to merge 1 commit into
JuliaDiff:mainfrom
CarloLucibello:cl/matfun-hermitian-1.12
Open

Fix matrix-function primal type for Hermitian{<:Real} on Julia 1.12#840
CarloLucibello wants to merge 1 commit into
JuliaDiff:mainfrom
CarloLucibello:cl/matfun-hermitian-1.12

Conversation

@CarloLucibello

Copy link
Copy Markdown
Contributor

Summary

Julia 1.12 changed real-valued matrix functions of Hermitian{<:Real} (e.g. exp, log, sqrt, cos, sin, ...) to return Hermitian instead of Symmetric:

julia> exp(Hermitian(ones(2,2))) |> typeof
Hermitian{Float64, Matrix{Float64}}   # was Symmetric on Julia ≤ 1.11

_matfun unconditionally wrapped the real-eltype result as Symmetric, so the rrule/frule primal no longer matched f(A). This surfaced as a type mismatch downstream — see FluxML/Zygote.jl#1592:

julia> Zygote.pullback(exp, Hermitian(ones(2,2)))[1] |> typeof
Symmetric{Float64, Matrix{Float64}}   # should be Hermitian

Fix

In _matfun, when the input is real, wrap the result in the same Symmetric/Hermitian type as the input when the output is real. The complex-valued case (e.g. acosh of eigenvalues < 1) is still wrapped as Symmetric, which is what Julia returns for both real Symmetric and Hermitian inputs. Behavior on Julia < 1.12 is unchanged (always Symmetric).

The inference assertions in the matrix-function tests are updated to expect the input wrapper type on 1.12+.

Testing

Pkg.test(test_args=["symmetric"]) passes on Julia 1.12 (5499 tests, 0 errors).

🤖 Generated with Claude Code

Julia 1.12 changed real-valued matrix functions of `Hermitian{<:Real}`
(e.g. `exp`, `log`, `sqrt`, `cos`) to return `Hermitian` instead of
`Symmetric`. `_matfun` unconditionally wrapped the real-eltype result as
`Symmetric`, so the rrule/frule primal no longer matched `f(A)`
(FluxML/Zygote.jl#1592).

Wrap the result in the same type as the input when the output is real,
keeping `Symmetric` for the complex-valued case (e.g. `acosh` of
eigenvalues < 1), which Julia still returns as `Symmetric` for both
`Symmetric` and `Hermitian` real inputs. The behavior is unchanged on
Julia < 1.12. The inference assertions in the matrix-function tests are
updated accordingly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@devmotion

Copy link
Copy Markdown
Member

Ref #833

As mentioned in #833 (comment), AD doesn't guarantee that primal values are exactly identical to the values obtained without AD. So it's unclear why Hermitian{<:Real} would be better than Symmetric{<:Real}.

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