I believe that only storing the upper triangular elements of PSD variables is the way to go.
This would result in a smaller linear system. Furthermore, converting a vector that stores the upper triangular elements of a symmetric matrix to a symmetric matrix is faster than performing (A + A')/2
, thus I don't see any reason not to go for it. Indeed running:
using LinearAlgebra
using BenchmarkTools
function vector_to_symmatrix!(A::Array{Float64, 2}, a::Array{Float64, 1})
# Indexing as seen on https://github.com/JuliaLang/julia/blob/870f99568aab0847962e453abb1c4b29d6906fe7/stdlib/LinearAlgebra/src/triangular.jl#L250-L252
n = size(A, 1)
@inbounds @simd for j in 1:n
@inbounds @simd for i in 1:j
idx = Int(j*(j-1)/2) + i
A[i,j] = a[idx]
end
end
# The matrix would passed to the eigensolver as Symmetric(A)
end
function make_symmetric_loop!(A::Array{Float64, 2})
n = size(A, 1)
@inbounds @simd for j in 1:n
@inbounds @simd for i in 1:j
A[j,i] = (A[j,i] + A[i,j])/2
end
end
end
n = 1000;
# Convert a vector to symmetric matrix
a = randn(Int(n*(n+1)/2));
A = zeros(n, n)
@btime vector_to_symmatrix!(A, a)
# Try two different versions of (A + A')/2
A = randn(n, n)
@btime @. A = (A + A')/2
@btime make_symmetric_loop!(A)
578.334 μs (1 allocation: 32 bytes)
4.528 ms (7 allocations: 7.63 MiB)
1.393 ms (0 allocations: 0 bytes)