304 lines
10 KiB
Julia
304 lines
10 KiB
Julia
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||
|
||
using Base.Test
|
||
|
||
srand(101)
|
||
debug = false #Turn on for more debugging info
|
||
|
||
#Pauli σ-matrices
|
||
for σ in map(Hermitian, Any[ eye(2), [0 1; 1 0], [0 -im; im 0], [1 0; 0 -1] ])
|
||
@test ishermitian(σ)
|
||
end
|
||
|
||
# Hermitian matrix exponential/log
|
||
let A1 = randn(4,4) + im*randn(4,4)
|
||
A2 = A1 + A1'
|
||
@test expm(A2) ≈ expm(Hermitian(A2))
|
||
@test logm(A2) ≈ logm(Hermitian(A2))
|
||
A3 = A1 * A1' # posdef
|
||
@test expm(A3) ≈ expm(Hermitian(A3))
|
||
@test logm(A3) ≈ logm(Hermitian(A3))
|
||
end
|
||
|
||
let A1 = randn(4,4)
|
||
A3 = A1 * A1'
|
||
A4 = A1 + A1.'
|
||
@test expm(A4) ≈ expm(Symmetric(A4))
|
||
@test logm(A3) ≈ logm(Symmetric(A3))
|
||
@test logm(A3) ≈ logm(Hermitian(A3))
|
||
end
|
||
|
||
let n=10
|
||
areal = randn(n,n)/2
|
||
aimg = randn(n,n)/2
|
||
debug && println("symmetric eigendecomposition")
|
||
for eltya in (Float32, Float64, Complex64, Complex128, BigFloat, Int)
|
||
a = eltya == Int ? rand(1:7, n, n) : convert(Matrix{eltya}, eltya <: Complex ? complex.(areal, aimg) : areal)
|
||
asym = a'+a # symmetric indefinite
|
||
ε = εa = eps(abs(float(one(eltya))))
|
||
|
||
x = randn(n)
|
||
y = randn(n)
|
||
b = randn(n,n)/2
|
||
x = eltya == Int ? rand(1:7, n) : convert(Vector{eltya}, eltya <: Complex ? complex.(x, zeros(n)) : x)
|
||
y = eltya == Int ? rand(1:7, n) : convert(Vector{eltya}, eltya <: Complex ? complex.(y, zeros(n)) : y)
|
||
b = eltya == Int ? rand(1:7, n, n) : convert(Matrix{eltya}, eltya <: Complex ? complex.(b, zeros(n,n)) : b)
|
||
|
||
debug && println("\ntype of a: ", eltya, "\n")
|
||
|
||
# constructor
|
||
@test Symmetric(Symmetric(asym, :U)) === Symmetric(asym, :U)
|
||
@test Hermitian(Hermitian(asym, :U)) === Hermitian(asym, :U)
|
||
@test Symmetric(Symmetric(asym, :U), :U) === Symmetric(asym, :U)
|
||
@test Hermitian(Hermitian(asym, :U), :U) === Hermitian(asym, :U)
|
||
@test_throws ArgumentError Symmetric(Symmetric(asym, :U), :L)
|
||
@test_throws ArgumentError Hermitian(Hermitian(asym, :U), :L)
|
||
|
||
# similar
|
||
@test isa(similar(Symmetric(asym)), Symmetric{eltya})
|
||
@test isa(similar(Hermitian(asym)), Hermitian{eltya})
|
||
@test isa(similar(Symmetric(asym), Int), Symmetric{Int})
|
||
@test isa(similar(Hermitian(asym), Int), Hermitian{Int})
|
||
@test isa(similar(Symmetric(asym), (3,2)), Matrix{eltya})
|
||
@test isa(similar(Hermitian(asym), (3,2)), Matrix{eltya})
|
||
@test isa(similar(Symmetric(asym), Int, (3,2)), Matrix{Int})
|
||
@test isa(similar(Hermitian(asym), Int, (3,2)), Matrix{Int})
|
||
|
||
# full
|
||
@test asym == full(Hermitian(asym))
|
||
|
||
# parent
|
||
@test asym == parent(Hermitian(asym))
|
||
|
||
# getindex
|
||
@test asym[1,1] == Hermitian(asym)[1,1]
|
||
@test asym[1,1] == Symmetric(asym)[1,1]
|
||
|
||
#trace
|
||
@test trace(asym) == trace(Hermitian(asym))
|
||
|
||
# issymmetric, ishermitian
|
||
if eltya <: Real
|
||
@test issymmetric(Symmetric(asym))
|
||
@test ishermitian(Symmetric(asym))
|
||
end
|
||
if eltya <: Complex
|
||
@test ishermitian(Symmetric(b + b'))
|
||
end
|
||
|
||
#transpose, ctranspose
|
||
if eltya <: Real
|
||
@test transpose(Symmetric(asym)) == asym
|
||
else
|
||
@test transpose(Hermitian(asym)) == transpose(asym)
|
||
end
|
||
@test ctranspose(Symmetric(asym)) == Symmetric(conj(asym))
|
||
@test ctranspose(Hermitian(asym)) == asym
|
||
|
||
#tril/triu
|
||
for di in -n:n
|
||
@test triu(Symmetric(a+a.'),di) == triu(a+a.',di)
|
||
@test tril(Symmetric(a+a.'),di) == tril(a+a.',di)
|
||
@test triu(Hermitian(asym),di) == triu(asym,di)
|
||
@test tril(Hermitian(asym),di) == tril(asym,di)
|
||
@test triu(Symmetric(a+a.',:L),di) == triu(a+a.',di)
|
||
@test tril(Symmetric(a+a.',:L),di) == tril(a+a.',di)
|
||
@test triu(Hermitian(asym,:L),di) == triu(asym,di)
|
||
@test tril(Hermitian(asym,:L),di) == tril(asym,di)
|
||
end
|
||
|
||
eltya == BigFloat && continue # Revisit when implemented in julia
|
||
d, v = eig(asym)
|
||
@test asym*v[:,1] ≈ d[1]*v[:,1]
|
||
@test v*Diagonal(d)*v' ≈ asym
|
||
@test isequal(eigvals(asym[1]), eigvals(asym[1:1,1:1]))
|
||
@test abs.(eigfact(Hermitian(asym), 1:2)[:vectors]'v[:,1:2]) ≈ eye(eltya, 2)
|
||
eig(Hermitian(asym), 1:2) # same result, but checks that method works
|
||
@test abs.(eigfact(Hermitian(asym), d[1] - 1, (d[2] + d[3])/2)[:vectors]'v[:,1:2]) ≈ eye(eltya, 2)
|
||
eig(Hermitian(asym), d[1] - 1, (d[2] + d[3])/2) # same result, but checks that method works
|
||
@test eigvals(Hermitian(asym), 1:2) ≈ d[1:2]
|
||
@test eigvals(Hermitian(asym), d[1] - 1, (d[2] + d[3])/2) ≈ d[1:2]
|
||
@test full(eigfact(asym)) ≈ asym
|
||
@test eigvecs(Hermitian(asym)) ≈ eigvecs(asym)
|
||
|
||
# relation to svdvals
|
||
@test sum(sort(abs.(eigvals(Hermitian(asym))))) == sum(sort(svdvals(Hermitian(asym))))
|
||
|
||
# cond
|
||
@test cond(Hermitian(asym)) ≈ cond(asym)
|
||
|
||
# det
|
||
@test det(asym) ≈ det(Hermitian(asym, :U))
|
||
@test det(asym) ≈ det(Hermitian(asym, :L))
|
||
if eltya <: Real
|
||
@test det(asym) ≈ det(Symmetric(asym, :U))
|
||
@test det(asym) ≈ det(Symmetric(asym, :L))
|
||
end
|
||
@test det(a + a.') ≈ det(Symmetric(a + a.', :U))
|
||
@test det(a + a.') ≈ det(Symmetric(a + a.', :L))
|
||
|
||
# isposdef[!]
|
||
@test isposdef(Symmetric(asym)) == isposdef(full(Symmetric(asym)))
|
||
@test isposdef(Hermitian(asym)) == isposdef(full(Hermitian(asym)))
|
||
if eltya != Int
|
||
@test isposdef!(Symmetric(copy(asym))) == isposdef(full(Symmetric(asym)))
|
||
@test isposdef!(Hermitian(copy(asym))) == isposdef(full(Hermitian(asym)))
|
||
end
|
||
|
||
# rank
|
||
let A = a[:,1:5]*a[:,1:5]'
|
||
# Make sure A is Hermitian even in the present of rounding error
|
||
# xianyi/OpenBLAS#729
|
||
A = (A' + A) / 2
|
||
@test rank(A) == rank(Hermitian(A))
|
||
end
|
||
|
||
# mat * vec
|
||
if eltya <: Complex
|
||
@test Hermitian(asym)*x+y ≈ asym*x+y
|
||
end
|
||
if eltya <: Real && eltya != Int
|
||
@test Symmetric(asym)*x+y ≈ asym*x+y
|
||
end
|
||
|
||
C = zeros(eltya,n,n)
|
||
# mat * mat
|
||
if eltya <: Complex
|
||
@test Hermitian(asym) * a ≈ asym * a
|
||
@test a * Hermitian(asym) ≈ a * asym
|
||
@test Hermitian(asym) * Hermitian(asym) ≈ asym*asym
|
||
@test_throws DimensionMismatch Hermitian(asym) * ones(eltya,n+1)
|
||
Base.LinAlg.A_mul_B!(C,a,Hermitian(asym))
|
||
@test C ≈ a*asym
|
||
end
|
||
if eltya <: Real && eltya != Int
|
||
@test Symmetric(asym) * Symmetric(asym) ≈ asym*asym
|
||
@test Symmetric(asym) * a ≈ asym * a
|
||
@test a * Symmetric(asym) ≈ a * asym
|
||
@test_throws DimensionMismatch Symmetric(asym) * ones(eltya,n+1)
|
||
Base.LinAlg.A_mul_B!(C,a,Symmetric(asym))
|
||
@test C ≈ a*asym
|
||
end
|
||
|
||
# solver
|
||
@test Hermitian(asym)\x ≈ asym\x
|
||
if eltya <: Real
|
||
@test Symmetric(asym)\x ≈ asym\x
|
||
end
|
||
|
||
#inversion
|
||
@test inv(Hermitian(asym)) ≈ inv(asym)
|
||
if eltya <: Real && eltya != Int
|
||
@test inv(Symmetric(asym)) ≈ inv(asym)
|
||
@test inv(Hermitian(a)) ≈ inv(full(Hermitian(a)))
|
||
@test inv(Symmetric(a)) ≈ inv(full(Symmetric(a)))
|
||
end
|
||
|
||
# conversion
|
||
@test Symmetric(asym) == convert(Symmetric,Symmetric(asym))
|
||
if eltya <: Real && eltya != Int
|
||
typs = [Float16,Float32,Float64]
|
||
for typ in typs
|
||
@test Symmetric(convert(Matrix{typ},asym)) == convert(Symmetric{typ,Matrix{typ}},Symmetric(asym))
|
||
end
|
||
end
|
||
if eltya <: Complex && eltya != Int
|
||
typs = [Complex64,Complex128]
|
||
for typ in typs
|
||
@test Hermitian(convert(Matrix{typ},asym)) == convert(Hermitian{typ,Matrix{typ}},Hermitian(asym))
|
||
end
|
||
end
|
||
|
||
#unsafe_getindex
|
||
if eltya <: Real
|
||
@test Symmetric(asym)[1:2,1:2] == asym[1:2,1:2]
|
||
end
|
||
@test Hermitian(asym)[1:2,1:2] == asym[1:2,1:2]
|
||
end
|
||
end
|
||
|
||
#Issue #7647: test xsyevr, xheevr, xstevr drivers
|
||
for Mi7647 in (Symmetric(diagm(1.0:3.0)),
|
||
Hermitian(diagm(1.0:3.0)),
|
||
Hermitian(diagm(complex(1.0:3.0))),
|
||
SymTridiagonal([1.0:3.0;], zeros(2)))
|
||
debug && println("Eigenvalues in interval for $(typeof(Mi7647))")
|
||
@test eigmin(Mi7647) == eigvals(Mi7647, 0.5, 1.5)[1] == 1.0
|
||
@test eigmax(Mi7647) == eigvals(Mi7647, 2.5, 3.5)[1] == 3.0
|
||
@test eigvals(Mi7647) == eigvals(Mi7647, 0.5, 3.5) == [1.0:3.0;]
|
||
end
|
||
|
||
#Issue #7933
|
||
let A7933 = [1 2; 3 4]
|
||
B7933 = copy(A7933)
|
||
C7933 = full(Symmetric(A7933))
|
||
@test A7933 == B7933
|
||
end
|
||
|
||
# Issues #8057 and #8058
|
||
for f in (eigfact, eigvals, eig)
|
||
for A in (Symmetric([0 1; 1 0]), Hermitian([0 im; -im 0]))
|
||
@test_throws ArgumentError f(A, 3, 2)
|
||
@test_throws ArgumentError f(A, 1:4)
|
||
end
|
||
end
|
||
|
||
#Issue 10671
|
||
let A = [1.0+im 2.0; 2.0 0.0]
|
||
@test !ishermitian(A)
|
||
@test_throws ArgumentError Hermitian(A)
|
||
end
|
||
|
||
# Unary minus for Symmetric matrices
|
||
let A = Symmetric(randn(5,5))
|
||
B = -A
|
||
@test A + B ≈ zeros(5,5)
|
||
end
|
||
|
||
# 17780
|
||
let a = randn(2,2)
|
||
a = a'a
|
||
b = complex.(a,a)
|
||
c = Symmetric(b)
|
||
@test conj(c) == conj(Array(c))
|
||
cc = copy(c)
|
||
@test conj!(c) == conj(Array(cc))
|
||
c = Hermitian(b + b')
|
||
@test conj(c) == conj(Array(c))
|
||
cc = copy(c)
|
||
@test conj!(c) == conj(Array(c))
|
||
end
|
||
|
||
# 19225
|
||
let X = [1 -1; -1 1]
|
||
for T in (Symmetric, Hermitian)
|
||
Y = T(copy(X))
|
||
_Y = similar(Y)
|
||
copy!(_Y, Y)
|
||
@test _Y == Y
|
||
|
||
W = T(copy(X), :L)
|
||
copy!(W, Y)
|
||
@test W.data == Y.data
|
||
@test W.uplo != Y.uplo
|
||
|
||
W[1,1] = 4
|
||
@test W == T([4 -1; -1 1])
|
||
@test_throws ArgumentError (W[1,2] = 2)
|
||
|
||
@test Y + I == T([2 -1; -1 2])
|
||
@test Y - I == T([0 -1; -1 0])
|
||
@test Y * I == Y
|
||
|
||
@test Y + 1 == T([2 0; 0 2])
|
||
@test Y - 1 == T([0 -2; -2 0])
|
||
@test Y * 2 == T([2 -2; -2 2])
|
||
@test Y / 1 == Y
|
||
|
||
@test T([true false; false true]) + true == T([2 1; 1 2])
|
||
end
|
||
|
||
@test_throws ArgumentError Hermitian(X) + 2im*I
|
||
@test_throws ArgumentError Hermitian(X) - 2im*I
|
||
end
|