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
 |