Skip to content

Commit 12eb073

Browse files
committed
Add matrix symmetrizing functions
This adds functions `symmetrize` and `symmetrize!`, which produce symmetric matrices based on the input `X` via efficient computation of `(X + X') / 2`.
1 parent 93c9ae4 commit 12eb073

File tree

5 files changed

+62
-0
lines changed

5 files changed

+62
-0
lines changed

NEWS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ Standard library changes
2929
#### LinearAlgebra
3030

3131
* `diagm` and `spdiagm` now accept optional `m,n` initial arguments to specify a size ([#31654]).
32+
* New functions `symmetrize` and `symmetrize!` for constructing symmetric matrices ([#TODO]).
3233

3334
#### SparseArrays
3435

stdlib/LinearAlgebra/docs/src/index.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,8 @@ Base.copy(::Union{Transpose,Adjoint})
430430
LinearAlgebra.stride1
431431
LinearAlgebra.checksquare
432432
LinearAlgebra.peakflops
433+
LinearAlgebra.symmetrize
434+
LinearAlgebra.symmetrize!
433435
```
434436

435437
## Low-level matrix operations

stdlib/LinearAlgebra/src/LinearAlgebra.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ export
130130
svdvals!,
131131
svdvals,
132132
sylvester,
133+
symmetrize,
134+
symmetrize!,
133135
tr,
134136
transpose,
135137
transpose!,

stdlib/LinearAlgebra/src/symmetric.jl

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -890,3 +890,38 @@ end
890890
*(A::Adjoint{<:Any,<:RealHermSymComplexHerm}, B::Transpose{<:Any,<:AbstractTriangular}) = A.parent * B
891891
*(A::Transpose{<:Any,<:RealHermSymComplexSym}, B::Adjoint{<:Any,<:AbstractTriangular}) = A.parent * B
892892
*(A::Transpose{<:Any,<:RealHermSymComplexSym}, B::Transpose{<:Any,<:AbstractTriangular}) = A.parent * B
893+
894+
"""
895+
symmetrize!(X::AbstractMatrix{<:AbstractFloat})
896+
897+
Make the matrix `X` symmetric in-place using the formula `(X + X') / 2`.
898+
899+
See also: [`symmetrize`](@ref)
900+
901+
!!! compat "Julia 1.3"
902+
This function requires Julia 1.3 or later.
903+
"""
904+
function symmetrize!(X::AbstractMatrix{<:AbstractFloat})
905+
require_one_based_indexing(X)
906+
n = checksquare(X)
907+
@inbounds for j = 2:n, i = 1:j-1
908+
X[i,j] = (X[i,j] + X[j,i]) / 2
909+
X[j,i] = X[i,j]
910+
end
911+
X
912+
end
913+
914+
"""
915+
symmetrize(X::AbstractMatrix)
916+
917+
Construct a symmetric matrix based on `X` using the formula `(X + X') / 2`.
918+
This function is a no-op for [`Symmetric`](@ref)-wrapped matrices.
919+
920+
See also: [`symmetrize!`](@ref)
921+
922+
!!! compat "Julia 1.3"
923+
This function requires Julia 1.3 or later.
924+
"""
925+
symmetrize(X::AbstractMatrix{<:AbstractFloat}) = symmetrize!(copy(X))
926+
symmetrize(X::AbstractMatrix{<:Real}) = symmetrize!(float(X))
927+
symmetrize(X::Symmetric) = X

stdlib/LinearAlgebra/test/symmetric.jl

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,4 +603,26 @@ end
603603
@test LinearAlgebra.hermitian_type(Int) == Int
604604
end
605605

606+
@testset "symmetrize" begin
607+
@testset "in-place" begin
608+
X = rand(Float32, 4, 4)
609+
Y = copy(X)
610+
symmetrize!(X)
611+
@test X (Y + Y') / 2
612+
@test issymmetric(X)
613+
end
614+
@testset "out-of-place" begin
615+
X = randn(Float32, 4, 4)
616+
Y = symmetrize(X)
617+
@test Y (X + X') / 2
618+
@test issymmetric(Y)
619+
X = Int32[1 2 3; 4 5 6; 7 8 9]
620+
@test symmetrize(X) Float32[1 3 5; 3 5 7; 5 7 9]
621+
end
622+
@testset "Symmetric" begin
623+
S = Symmetric([1 2; 2 1])
624+
@test symmetrize(S) === S
625+
end
626+
end
627+
606628
end # module TestSymmetric

0 commit comments

Comments
 (0)