Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

stdlib: make dot product of Hermitian matrices real #52318

Merged
merged 6 commits into from
Feb 3, 2024
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions stdlib/LinearAlgebra/src/symmetric.jl
Original file line number Diff line number Diff line change
Expand Up @@ -453,25 +453,28 @@ function triu(A::Symmetric, k::Integer=0)
end
end

for (T, trans, real) in [(:Symmetric, :transpose, :identity), (:Hermitian, :adjoint, :real)]
for (T, trans, real) in [
(:Symmetric, :transpose, :identity),
(:(Hermitian{<:Union{Real,Complex}}), :adjoint, :real),
Copy link
Contributor

@mikmoore mikmoore Nov 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's slightly unfortunate that this specialization prevents this from being applicable to e.g. Hermitian{<:AbstractMatrix{<:Union{Real,Complex}}}. Although I'm not sure how we might engineer a definition that's robust through multiple levels of nested AbstractMatrix so it would probably be hard to do something about this right now.

I'll also remark that this specialization should also be suitable for dot(::Symmetric{<:Real},::Hermitian{<:Complex}}, although currently it appears we miss this case. Would LinearAlgebra.RealHermSymComplexHerm be suitable here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a design flaw of LinearAlgebra. Symmetric should have been defined as real symmetric, and should be made a subtype of Hermitian, as mathematically a real symmetric matrix is just a particular case of a complex Hermitian matrix, and we'd get for free all of these particular cases without having to write a method for each specifically. Then one could also have a GenericSymmetric to deal with the more exotic cases if anyone needed them.

FWIW I did think about mixing real symmetric and complex Hermitian, but I decided against adding additional methods that were going to be rarely used. Of course, I know my opinion counts for very little here.

]
@eval begin
function dot(A::$T, B::$T)
n = size(A, 2)
if n != size(B, 2)
throw(DimensionMismatch("A has dimensions $(size(A)) but B has dimensions $(size(B))"))
end

dotprod = zero(dot(first(A), first(B)))
dotprod = $real(zero(dot(first(A), first(B))))
@inbounds if A.uplo == 'U' && B.uplo == 'U'
for j in 1:n
for i in 1:(j - 1)
dotprod += 2 * $real(dot(A.data[i, j], B.data[i, j]))
end
dotprod += dot(A[j, j], B[j, j])
dotprod += $real(dot(A[j, j], B[j, j]))
end
elseif A.uplo == 'L' && B.uplo == 'L'
for j in 1:n
dotprod += dot(A[j, j], B[j, j])
dotprod += $real(dot(A[j, j], B[j, j]))
for i in (j + 1):n
dotprod += 2 * $real(dot(A.data[i, j], B.data[i, j]))
end
Expand All @@ -481,11 +484,11 @@ for (T, trans, real) in [(:Symmetric, :transpose, :identity), (:Hermitian, :adjo
for i in 1:(j - 1)
dotprod += 2 * $real(dot(A.data[i, j], $trans(B.data[j, i])))
end
dotprod += dot(A[j, j], B[j, j])
dotprod += $real(dot(A[j, j], B[j, j]))
end
else
for j in 1:n
dotprod += dot(A[j, j], B[j, j])
dotprod += $real(dot(A[j, j], B[j, j]))
for i in (j + 1):n
dotprod += 2 * $real(dot(A.data[i, j], $trans(B.data[j, i])))
end
Expand Down