371 lines
12 KiB
Julia
371 lines
12 KiB
Julia
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
|
|
|
using Base.Test
|
|
import Base.LinAlg: BlasFloat, BlasComplex, SingularException
|
|
|
|
n=12 #Size of matrix problem to test
|
|
srand(1)
|
|
|
|
@testset for relty in (Float32, Float64, BigFloat), elty in (relty, Complex{relty})
|
|
d=convert(Vector{elty}, randn(n))
|
|
v=convert(Vector{elty}, randn(n))
|
|
U=convert(Matrix{elty}, randn(n,n))
|
|
if elty <: Complex
|
|
d+=im*convert(Vector{elty}, randn(n))
|
|
v+=im*convert(Vector{elty}, randn(n))
|
|
U+=im*convert(Matrix{elty}, randn(n,n))
|
|
end
|
|
D = Diagonal(d)
|
|
DM = diagm(d)
|
|
@testset "Basic properties" begin
|
|
@test eye(Diagonal{elty},n) == Diagonal(ones(elty,n))
|
|
@test_throws ArgumentError size(D,0)
|
|
@test typeof(convert(Diagonal{Complex64},D)) == Diagonal{Complex64}
|
|
@test typeof(convert(AbstractMatrix{Complex64},D)) == Diagonal{Complex64}
|
|
|
|
@test Array(real(D)) == real(DM)
|
|
@test Array(abs.(D)) == abs.(DM)
|
|
@test Array(imag(D)) == imag(DM)
|
|
|
|
@test parent(D) == d
|
|
@test diag(D) == d
|
|
@test D[1,1] == d[1]
|
|
@test D[1,2] == 0
|
|
|
|
@test issymmetric(D)
|
|
@test istriu(D)
|
|
@test istril(D)
|
|
if elty <: Real
|
|
@test ishermitian(D)
|
|
end
|
|
end
|
|
|
|
@testset "Simple unary functions" begin
|
|
for op in (-,)
|
|
@test op(D)==op(DM)
|
|
end
|
|
|
|
for func in (det, trace)
|
|
@test func(D) ≈ func(DM) atol=n^2*eps(relty)*(1+(elty<:Complex))
|
|
end
|
|
if relty <: BlasFloat
|
|
for func in (expm,)
|
|
@test func(D) ≈ func(DM) atol=n^3*eps(relty)
|
|
end
|
|
@test logm(Diagonal(abs.(D.diag))) ≈ logm(abs.(DM)) atol=n^3*eps(relty)
|
|
end
|
|
if elty <: BlasComplex
|
|
for func in (logdet, sqrtm)
|
|
@test func(D) ≈ func(DM) atol=n^2*eps(relty)*2
|
|
end
|
|
end
|
|
end
|
|
|
|
@testset "Linear solve" begin
|
|
let vv = v, UU = U
|
|
@testset for atype in ("Array", "SubArray")
|
|
if atype == "Array"
|
|
v = vv
|
|
U = UU
|
|
else
|
|
v = view(vv, 1:n)
|
|
U = view(UU, 1:n, 1:2)
|
|
end
|
|
|
|
@test D*v ≈ DM*v atol=n*eps(relty)*(1+(elty<:Complex))
|
|
@test D*U ≈ DM*U atol=n^2*eps(relty)*(1+(elty<:Complex))
|
|
|
|
@test U.'*D ≈ U.'*Array(D)
|
|
@test U'*D ≈ U'*Array(D)
|
|
|
|
if relty != BigFloat
|
|
@test D\v ≈ DM\v atol=2n^2*eps(relty)*(1+(elty<:Complex))
|
|
@test D\U ≈ DM\U atol=2n^3*eps(relty)*(1+(elty<:Complex))
|
|
@test A_ldiv_B!(D,copy(v)) ≈ DM\v atol=2n^2*eps(relty)*(1+(elty<:Complex))
|
|
@test A_ldiv_B!(D,copy(U)) ≈ DM\U atol=2n^3*eps(relty)*(1+(elty<:Complex))
|
|
@test A_ldiv_B!(D,eye(D)) ≈ D\eye(D) atol=2n^3*eps(relty)*(1+(elty<:Complex))
|
|
@test_throws DimensionMismatch A_ldiv_B!(D, ones(elty, n + 1))
|
|
@test_throws SingularException A_ldiv_B!(Diagonal(zeros(relty,n)),copy(v))
|
|
b = rand(elty,n,n)
|
|
b = sparse(b)
|
|
@test A_ldiv_B!(D,copy(b)) ≈ Array(D)\Array(b)
|
|
@test_throws SingularException A_ldiv_B!(Diagonal(zeros(elty,n)),copy(b))
|
|
b = view(rand(elty,n),collect(1:n))
|
|
b2 = copy(b)
|
|
c = A_ldiv_B!(D,b)
|
|
d = Array(D)\b2
|
|
for i in 1:n
|
|
@test c[i] ≈ d[i]
|
|
end
|
|
@test_throws SingularException A_ldiv_B!(Diagonal(zeros(elty,n)),b)
|
|
b = rand(elty,n+1,n+1)
|
|
b = sparse(b)
|
|
@test_throws DimensionMismatch A_ldiv_B!(D,copy(b))
|
|
b = view(rand(elty,n+1),collect(1:n+1))
|
|
@test_throws DimensionMismatch A_ldiv_B!(D,b)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
d = convert(Vector{elty}, randn(n))
|
|
D2 = Diagonal(d)
|
|
DM2= diagm(d)
|
|
@testset "Binary operations" begin
|
|
for op in (+, -, *)
|
|
@test Array(op(D, D2)) ≈ op(DM, DM2)
|
|
end
|
|
@testset "with plain numbers" begin
|
|
a = rand()
|
|
@test Array(a*D) ≈ a*DM
|
|
@test Array(D*a) ≈ DM*a
|
|
@test Array(D/a) ≈ DM/a
|
|
if relty <: BlasFloat
|
|
b = rand(elty,n,n)
|
|
b = sparse(b)
|
|
@test A_mul_B!(copy(D), copy(b)) ≈ Array(D)*Array(b)
|
|
@test At_mul_B!(copy(D), copy(b)) ≈ Array(D).'*Array(b)
|
|
@test Ac_mul_B!(copy(D), copy(b)) ≈ Array(D)'*Array(b)
|
|
end
|
|
end
|
|
|
|
#a few missing mults
|
|
bd = Bidiagonal(D2)
|
|
@test D*D2.' ≈ Array(D)*Array(D2).'
|
|
@test D2*D.' ≈ Array(D2)*Array(D).'
|
|
@test D2*D' ≈ Array(D2)*Array(D)'
|
|
|
|
#division of two Diagonals
|
|
@test D/D2 ≈ Diagonal(D.diag./D2.diag)
|
|
@test D\D2 ≈ Diagonal(D2.diag./D.diag)
|
|
|
|
# Performance specialisations for A*_mul_B!
|
|
vv = similar(v)
|
|
@test (r = full(D) * v ; A_mul_B!(vv, D, v) ≈ r ≈ vv)
|
|
@test (r = full(D)' * v ; Ac_mul_B!(vv, D, v) ≈ r ≈ vv)
|
|
@test (r = full(D).' * v ; At_mul_B!(vv, D, v) ≈ r ≈ vv)
|
|
|
|
UU = similar(U)
|
|
@test (r = full(D) * U ; A_mul_B!(UU, D, U) ≈ r ≈ UU)
|
|
@test (r = full(D)' * U ; Ac_mul_B!(UU, D, U) ≈ r ≈ UU)
|
|
@test (r = full(D).' * U ; At_mul_B!(UU, D, U) ≈ r ≈ UU)
|
|
end
|
|
@testset "triu/tril" begin
|
|
@test istriu(D)
|
|
@test istril(D)
|
|
@test triu(D,1) == zeros(D)
|
|
@test triu(D,0) == D
|
|
@test triu(D,-1) == D
|
|
@test tril(D,1) == D
|
|
@test tril(D,-1) == zeros(D)
|
|
@test tril(D,0) == D
|
|
@test_throws ArgumentError tril(D,n+1)
|
|
@test_throws ArgumentError triu(D,n+1)
|
|
end
|
|
|
|
# factorize
|
|
@test factorize(D) == D
|
|
|
|
@testset "Eigensystem" begin
|
|
eigD = eigfact(D)
|
|
@test Diagonal(eigD[:values]) ≈ D
|
|
@test eigD[:vectors] == eye(D)
|
|
end
|
|
|
|
@testset "ldiv" begin
|
|
v = rand(n + 1)
|
|
@test_throws DimensionMismatch D\v
|
|
v = rand(n)
|
|
@test D\v ≈ DM\v
|
|
V = rand(n + 1, n)
|
|
@test_throws DimensionMismatch D\V
|
|
V = rand(n, n)
|
|
@test D\V ≈ DM\V
|
|
end
|
|
|
|
@testset "conj and transpose" begin
|
|
@test transpose(D) == D
|
|
if elty <: BlasComplex
|
|
@test Array(conj(D)) ≈ conj(DM)
|
|
@test ctranspose(D) == conj(D)
|
|
end
|
|
# Translates to Ac/t_mul_B, which is specialized after issue 21286
|
|
@test(D' * v == conj(D) * v)
|
|
@test(D.' * v == D * v)
|
|
end
|
|
|
|
#logdet
|
|
if relty <: Real
|
|
ld=convert(Vector{relty},rand(n))
|
|
@test logdet(Diagonal(ld)) ≈ logdet(diagm(ld))
|
|
end
|
|
|
|
@testset "similar" begin
|
|
@test isa(similar(D), Diagonal{elty})
|
|
@test isa(similar(D, Int), Diagonal{Int})
|
|
@test isa(similar(D, (3,2)), Matrix{elty})
|
|
@test isa(similar(D, Int, (3,2)), Matrix{Int})
|
|
end
|
|
|
|
# Issue number 10036
|
|
# make sure issymmetric/ishermitian work for
|
|
# non-real diagonal matrices
|
|
@testset "issymmetric/hermitian for complex Diagonal" begin
|
|
@test issymmetric(D2)
|
|
@test ishermitian(D2)
|
|
if elty <: Complex
|
|
dc = d + im*convert(Vector{elty}, ones(n))
|
|
D3 = Diagonal(dc)
|
|
@test issymmetric(D3)
|
|
@test !ishermitian(D3)
|
|
end
|
|
end
|
|
|
|
@testset "svd (#11120/#11247)" begin
|
|
U, s, V = svd(D)
|
|
@test (U*Diagonal(s))*V' ≈ D
|
|
@test svdvals(D) == s
|
|
@test svdfact(D)[:V] == V
|
|
end
|
|
end
|
|
|
|
@testset "svdvals and eigvals (#11120/#11247)" begin
|
|
D = Diagonal(Matrix{Float64}[randn(3,3), randn(2,2)])
|
|
@test sort([svdvals(D)...;], rev = true) ≈ svdvals([D.diag[1] zeros(3,2); zeros(2,3) D.diag[2]])
|
|
@test [eigvals(D)...;] ≈ eigvals([D.diag[1] zeros(3,2); zeros(2,3) D.diag[2]])
|
|
end
|
|
|
|
@testset "isposdef" begin
|
|
@test !isposdef(Diagonal(-1.0 * rand(n)))
|
|
end
|
|
|
|
@testset "getindex" begin
|
|
d = randn(n)
|
|
D = Diagonal(d)
|
|
# getindex bounds checking
|
|
@test_throws BoundsError D[0, 0]
|
|
@test_throws BoundsError D[-1, -2]
|
|
@test_throws BoundsError D[n, n + 1]
|
|
@test_throws BoundsError D[n + 1, n]
|
|
@test_throws BoundsError D[n + 1, n + 1]
|
|
# getindex on and off the diagonal
|
|
for i in 1:n, j in 1:n
|
|
@test D[i, j] == (i == j ? d[i] : 0)
|
|
end
|
|
end
|
|
|
|
@testset "setindex!" begin
|
|
d = randn(n)
|
|
D = Diagonal(d)
|
|
# setindex! bounds checking
|
|
@test_throws BoundsError D[0, 0] = 0
|
|
@test_throws BoundsError D[-1 , -2] = 0
|
|
@test_throws BoundsError D[n, n + 1] = 0
|
|
@test_throws BoundsError D[n + 1, n] = 0
|
|
@test_throws BoundsError D[n + 1, n + 1] = 0
|
|
for i in 1:n, j in 1:n
|
|
if i == j
|
|
# setindex on! the diagonal
|
|
@test ((D[i, j] = i) == i; D[i, j] == i)
|
|
else
|
|
# setindex! off the diagonal
|
|
@test ((D[i, j] = 0) == 0; iszero(D[i, j]))
|
|
@test_throws ArgumentError D[i, j] = 1
|
|
end
|
|
end
|
|
end
|
|
|
|
@testset "inverse" begin
|
|
for d in (randn(n), [1, 2, 3], [1im, 2im, 3im])
|
|
D = Diagonal(d)
|
|
@test inv(D) ≈ inv(Array(D))
|
|
end
|
|
@test_throws SingularException inv(Diagonal(zeros(n)))
|
|
@test_throws SingularException inv(Diagonal([0, 1, 2]))
|
|
@test_throws SingularException inv(Diagonal([0im, 1im, 2im]))
|
|
end
|
|
|
|
# allow construct from range
|
|
@test Diagonal(linspace(1,3,3)) == Diagonal([1.,2.,3.])
|
|
|
|
# Issue 12803
|
|
for t in (Float32, Float64, Int, Complex{Float64}, Rational{Int})
|
|
@test Diagonal(Matrix{t}[ones(t, 2, 2), ones(t, 3, 3)])[2,1] == zeros(t, 3, 2)
|
|
end
|
|
|
|
# Issue 15401
|
|
@test eye(5) \ Diagonal(ones(5)) == eye(5)
|
|
|
|
@testset "Triangular and Diagonal" begin
|
|
for T in (LowerTriangular(randn(5,5)), LinAlg.UnitLowerTriangular(randn(5,5)))
|
|
D = Diagonal(randn(5))
|
|
@test T*D == Array(T)*Array(D)
|
|
@test T'D == Array(T)'*Array(D)
|
|
@test T.'D == Array(T).'*Array(D)
|
|
@test D*T' == Array(D)*Array(T)'
|
|
@test D*T.' == Array(D)*Array(T).'
|
|
@test D*T == Array(D)*Array(T)
|
|
end
|
|
end
|
|
|
|
let D1 = Diagonal(rand(5)), D2 = Diagonal(rand(5))
|
|
@test_throws MethodError A_mul_B!(D1,D2)
|
|
@test_throws MethodError At_mul_B!(D1,D2)
|
|
@test_throws MethodError Ac_mul_B!(D1,D2)
|
|
end
|
|
|
|
@testset "multiplication of QR Q-factor and Diagonal (#16615 spot test)" begin
|
|
D = Diagonal(randn(5))
|
|
Q = qrfact(randn(5, 5))[:Q]
|
|
@test D * Q' == Array(D) * Q'
|
|
end
|
|
|
|
@testset "block diagonal matrices" begin
|
|
D = Diagonal([[1 2; 3 4], [1 2; 3 4]])
|
|
Dherm = Diagonal([[1 1+im; 1-im 1], [1 1+im; 1-im 1]])
|
|
Dsym = Diagonal([[1 1+im; 1+im 1], [1 1+im; 1+im 1]])
|
|
@test D' == Diagonal([[1 3; 2 4], [1 3; 2 4]])
|
|
@test D.' == Diagonal([[1 3; 2 4], [1 3; 2 4]])
|
|
@test Dherm' == Dherm
|
|
@test Dherm.' == Diagonal([[1 1-im; 1+im 1], [1 1-im; 1+im 1]])
|
|
@test Dsym' == Diagonal([[1 1-im; 1-im 1], [1 1-im; 1-im 1]])
|
|
@test Dsym.' == Dsym
|
|
|
|
v = [[1, 2], [3, 4]]
|
|
@test Dherm' * v == Dherm * v
|
|
@test D.' * v == [[7, 10], [15, 22]]
|
|
|
|
@test issymmetric(D) == false
|
|
@test issymmetric(Dherm) == false
|
|
@test issymmetric(Dsym) == true
|
|
|
|
@test ishermitian(D) == false
|
|
@test ishermitian(Dherm) == true
|
|
@test ishermitian(Dsym) == false
|
|
|
|
@test expm(D) == Diagonal([expm([1 2; 3 4]), expm([1 2; 3 4])])
|
|
@test logm(D) == Diagonal([logm([1 2; 3 4]), logm([1 2; 3 4])])
|
|
@test sqrtm(D) == Diagonal([sqrtm([1 2; 3 4]), sqrtm([1 2; 3 4])])
|
|
end
|
|
|
|
@testset "multiplication with Symmetric/Hermitian" begin
|
|
for T in (Float64, Complex128)
|
|
if T <: Complex
|
|
R = Float64
|
|
D = Diagonal(complex.(randn(R, n), randn(R, n)))
|
|
A = complex.(randn(R, n, n), randn(R, n, n))
|
|
else
|
|
D = Diagonal(randn(T, n))
|
|
A = randn(T, n, n)
|
|
end
|
|
A = A'A
|
|
S = Symmetric(A)
|
|
H = Hermitian(A)
|
|
for f in (*, Ac_mul_B, A_mul_Bc, Ac_mul_Bc, At_mul_B, A_mul_Bt, At_mul_Bt)
|
|
@test f(D, S) ≈ f(Matrix(D), Matrix(S))
|
|
@test f(D, H) ≈ f(Matrix(D), Matrix(H))
|
|
@test f(S, D) ≈ f(Matrix(S), Matrix(D))
|
|
@test f(S, H) ≈ f(Matrix(S), Matrix(H))
|
|
end
|
|
end
|
|
end
|