diff --git a/Project.toml b/Project.toml index a56827cad..30a618092 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "ChainRulesCore" uuid = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" -version = "1.26.6" +version = "1.26.7" [deps] LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" diff --git a/src/projection.jl b/src/projection.jl index 7ddadf11a..ddc797bd5 100644 --- a/src/projection.jl +++ b/src/projection.jl @@ -483,10 +483,20 @@ for (SymHerm, chk, fun) in sub_one = ProjectTo{project_type(sub)}(; element=sub.element, axes=(sub.axes[1],) ) - return Diagonal(sub_one(dx.diag)) + return Diagonal(_project_diag(project, sub_one, dx.diag)) end end end +_project_diag(::ProjectTo{Symmetric}, sub_one, diag) = sub_one(diag) +function _project_diag(::ProjectTo{Hermitian}, sub_one, diag) + dy = sub_one(diag) + # The diagonal of a Hermitian matrix is real + if eltype(diag) <: Real || eltype(dy) <: Real + return dy + else + return map(y -> oftype(y, real(y)), dy) + end +end # Triangular for UL in (:UpperTriangular, :LowerTriangular, :UnitUpperTriangular, :UnitLowerTriangular) # UpperHessenberg diff --git a/test/projection.jl b/test/projection.jl index d77788b71..dee6ef146 100644 --- a/test/projection.jl +++ b/test/projection.jl @@ -314,6 +314,23 @@ struct NoSuperType end # an experiment with allowing subspaces which aren't subtypes @test psymm(Diagonal([1, 2, 3])) isa Diagonal{Float64} @test pupp(Diagonal([1, 2, 3 + 4im])) isa Diagonal{Float64} + + @testset "Diagonal input to Hermitian has real diagonal" begin + dx = Diagonal([1 + 2im, 3im, 4.0]) + @test @inferred(pherm(dx)) == Diagonal([1.0, 0.0, 4.0]) + @test pherm(dx) isa Diagonal{ComplexF64} + @test pherm(dx) == pherm(Matrix(dx)) + @test @inferred(pherm(Diagonal([1.0, 2.0, 3.0]))) == Diagonal([1.0, 2.0, 3.0]) + @test pherm(Diagonal([1.0, 2.0, 3.0])) isa Diagonal{ComplexF64} + pherm32 = ProjectTo(Hermitian(rand(ComplexF32, 3, 3))) + @test @inferred(pherm32(dx)) isa Diagonal{ComplexF32} + @test @inferred(ProjectTo(Hermitian(rand(3, 3)))(dx)) == + Diagonal([1.0, 0.0, 4.0]) + @test_throws DimensionMismatch pherm(Diagonal(rand(ComplexF64, 2))) + + # Symmetric keeps a complex diagonal + @test @inferred(ProjectTo(Symmetric(rand(ComplexF64, 3, 3)))(dx)) == dx + end end @testset "LinearAlgebra: sparse structured matrices" begin @@ -499,6 +516,14 @@ struct NoSuperType end psymm = ProjectTo(Symmetric(rand(10^3, 10^3))) @test 0 == @ballocated $psymm(dx) setup = (dx = Symmetric(rand(10^3, 10^3))) + + pherm = ProjectTo(Hermitian(rand(10^3, 10^3))) + @test 0 == @ballocated $pherm(dx) setup = (dx = Diagonal(rand(10^3))) + + # a real tangent onto complex Hermitian is copied only once + pherm_c = ProjectTo(Hermitian(rand(ComplexF64, 10^3, 10^3))) + @test 2 * sizeof(ComplexF64) * 10^3 > + @ballocated $pherm_c(dx) setup = (dx = Diagonal(rand(10^3))) end @testset "#407" begin