Skip to content

Commit 8e76b12

Browse files
Sparse addition of Symmetric and Hermitian matrices (#35325)
Co-authored-by: MasonProtter <mason.protter@gmail.com> Co-authored-by: Daniel Karrasch <daniel.karrasch@posteo.de>
1 parent f7e5f3e commit 8e76b12

File tree

3 files changed

+67
-5
lines changed

3 files changed

+67
-5
lines changed

stdlib/LinearAlgebra/src/symmetric.jl

+18-4
Original file line numberDiff line numberDiff line change
@@ -461,11 +461,25 @@ end
461461
(-)(A::Hermitian) = Hermitian(-A.data, sym_uplo(A.uplo))
462462

463463
## Addition/subtraction
464+
for f (:+, :-), (Wrapper, conjugation) ((:Hermitian, :adjoint), (:Symmetric, :transpose))
465+
@eval begin
466+
function $f(A::$Wrapper, B::$Wrapper)
467+
if A.uplo == B.uplo
468+
return $Wrapper($f(parent(A), parent(B)), sym_uplo(A.uplo))
469+
elseif A.uplo == 'U'
470+
return $Wrapper($f(parent(A), $conjugation(parent(B))), :U)
471+
else
472+
return $Wrapper($f($conjugation(parent(A)), parent(B)), :U)
473+
end
474+
end
475+
end
476+
end
477+
464478
for f in (:+, :-)
465-
@eval $f(A::Symmetric, B::Symmetric) = Symmetric($f(A.data, B), sym_uplo(A.uplo))
466-
@eval $f(A::Hermitian, B::Hermitian) = Hermitian($f(A.data, B), sym_uplo(A.uplo))
467-
@eval $f(A::Hermitian, B::Symmetric{<:Real}) = Hermitian($f(A.data, B), sym_uplo(A.uplo))
468-
@eval $f(A::Symmetric{<:Real}, B::Hermitian) = Hermitian($f(A.data, B), sym_uplo(A.uplo))
479+
@eval begin
480+
$f(A::Hermitian, B::Symmetric{<:Real}) = $f(A, Hermitian(parent(B), sym_uplo(B.uplo)))
481+
$f(A::Symmetric{<:Real}, B::Hermitian) = $f(Hermitian(parent(A), sym_uplo(A.uplo)), B)
482+
end
469483
end
470484

471485
## Matvec

stdlib/SparseArrays/src/linalg.jl

+19-1
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,30 @@
11
# This file is a part of Julia. License is MIT: https://julialang.org/license
22

3-
import LinearAlgebra: checksquare
3+
import LinearAlgebra: checksquare, sym_uplo
44
using Random: rand!
55

66
# In matrix-vector multiplication, the correct orientation of the vector is assumed.
77
const StridedOrTriangularMatrix{T} = Union{StridedMatrix{T}, LowerTriangular{T}, UnitLowerTriangular{T}, UpperTriangular{T}, UnitUpperTriangular{T}}
88
const AdjOrTransStridedOrTriangularMatrix{T} = Union{StridedOrTriangularMatrix{T},Adjoint{<:Any,<:StridedOrTriangularMatrix{T}},Transpose{<:Any,<:StridedOrTriangularMatrix{T}}}
99

10+
for op (:+, :-), Wrapper (:Hermitian, :Symmetric)
11+
@eval begin
12+
$op(A::AbstractSparseMatrix, B::$Wrapper{<:Any,<:AbstractSparseMatrix}) = $op(A, sparse(B))
13+
$op(A::$Wrapper{<:Any,<:AbstractSparseMatrix}, B::AbstractSparseMatrix) = $op(sparse(A), B)
14+
15+
$op(A::AbstractSparseMatrix, B::$Wrapper) = $op(A, collect(B))
16+
$op(A::$Wrapper, B::AbstractSparseMatrix) = $op(collect(A), B)
17+
end
18+
end
19+
for op (:+, :-)
20+
@eval begin
21+
$op(A::Symmetric{<:Any, <:AbstractSparseMatrix}, B::Hermitian{<:Any, <:AbstractSparseMatrix}) = $op(sparse(A), sparse(B))
22+
$op(A::Hermitian{<:Any, <:AbstractSparseMatrix}, B::Symmetric{<:Any, <:AbstractSparseMatrix}) = $op(sparse(A), sparse(B))
23+
$op(A::Symmetric{<:Real, <:AbstractSparseMatrix}, B::Hermitian{<:Any, <:AbstractSparseMatrix}) = $op(Hermitian(parent(A), sym_uplo(A.uplo)), B)
24+
$op(A::Hermitian{<:Any, <:AbstractSparseMatrix}, B::Symmetric{<:Real, <:AbstractSparseMatrix}) = $op(A, Hermitian(parent(B), sym_uplo(B.uplo)))
25+
end
26+
end
27+
1028
function mul!(C::StridedVecOrMat, A::AbstractSparseMatrixCSC, B::Union{StridedVector,AdjOrTransStridedOrTriangularMatrix}, α::Number, β::Number)
1129
size(A, 2) == size(B, 1) || throw(DimensionMismatch())
1230
size(A, 1) == size(C, 1) || throw(DimensionMismatch())

stdlib/SparseArrays/test/sparse.jl

+30
Original file line numberDiff line numberDiff line change
@@ -2906,4 +2906,34 @@ end
29062906
@test B mapreduce(identity, +, Matrix(A), dims=2)
29072907
end
29082908

2909+
@testset "Symmetric and Hermitian #35325" begin
2910+
A = sprandn(ComplexF64, 10, 10, 0.1)
2911+
B = sprandn(ComplexF64, 10, 10, 0.1)
2912+
2913+
@test Symmetric(real(A)) + Hermitian(B) isa Hermitian{ComplexF64, <:SparseMatrixCSC}
2914+
@test Hermitian(A) + Symmetric(real(B)) isa Hermitian{ComplexF64, <:SparseMatrixCSC}
2915+
@test Hermitian(A) + Symmetric(B) isa SparseMatrixCSC
2916+
@testset "$Wrapper $op" for op (+, -), Wrapper (Hermitian, Symmetric)
2917+
AWU = Wrapper(A, :U)
2918+
AWL = Wrapper(A, :L)
2919+
BWU = Wrapper(B, :U)
2920+
BWL = Wrapper(B, :L)
2921+
2922+
@test op(AWU, B) isa SparseMatrixCSC
2923+
@test op(A, BWL) isa SparseMatrixCSC
2924+
2925+
@test op(AWU, B) op(collect(AWU), B)
2926+
@test op(AWL, B) op(collect(AWL), B)
2927+
@test op(A, BWU) op(A, collect(BWU))
2928+
@test op(A, BWL) op(A, collect(BWL))
2929+
2930+
@test op(AWU, BWL) isa Wrapper{ComplexF64, <:SparseMatrixCSC}
2931+
2932+
@test op(AWU, BWU) op(collect(AWU), collect(BWU))
2933+
@test op(AWU, BWL) op(collect(AWU), collect(BWL))
2934+
@test op(AWL, BWU) op(collect(AWL), collect(BWU))
2935+
@test op(AWL, BWL) op(collect(AWL), collect(BWL))
2936+
end
2937+
end
2938+
29092939
end # module

0 commit comments

Comments
 (0)