Skip to content

Commit 0db3438

Browse files
committed
split up factorization tests
1 parent 38f39e6 commit 0db3438

4 files changed

Lines changed: 582 additions & 0 deletions

File tree

test/factorizations/eig.jl

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
using Test, TestExtras
2+
using TensorKit
3+
using LinearAlgebra: LinearAlgebra
4+
using MatrixAlgebraKit: diagview
5+
6+
7+
spacelist = if fast_tests
8+
(Vtr, Vℤ₃, VSU₂)
9+
elseif get(ENV, "CI", "false") == "true"
10+
println("Detected running on CI")
11+
if Sys.iswindows()
12+
(Vtr, Vℤ₃, VU₁, VfU₁, VCU₁, VSU₂, VIB_diag)
13+
elseif Sys.isapple()
14+
(Vtr, Vℤ₃, VfU₁, VfSU₂, VIB_M)
15+
else
16+
(Vtr, VU₁, VCU₁, VSU₂, VfSU₂, VIB_diag, VIB_M)
17+
end
18+
else
19+
(Vtr, Vℤ₃, VU₁, VfU₁, VCU₁, VSU₂, VfSU₂, VIB_diag, VIB_M)
20+
end
21+
22+
eltypes = (Float32, ComplexF64)
23+
24+
for V in spacelist
25+
I = sectortype(first(V))
26+
Istr = TensorKit.type_repr(I)
27+
println("---------------------------------------")
28+
println("Factorizations with symmetry: $Istr")
29+
println("---------------------------------------")
30+
@timedtestset "Factorizations with symmetry: $Istr" verbose = true begin
31+
V1, V2, V3, V4, V5 = V
32+
W = V1 V2
33+
@assert !isempty(blocksectors(W))
34+
@assert !isempty(intersect(blocksectors(V4), blocksectors(W)))
35+
36+
@testset "Eigenvalue decomposition" begin
37+
for T in eltypes,
38+
t in (
39+
rand(T, V1, V1), rand(T, W, W), rand(T, W, W)',
40+
DiagonalTensorMap(rand(T, reduceddim(V1)), V1),
41+
)
42+
43+
d, v = @constinferred eig_full(t)
44+
@test t * v v * d
45+
46+
d′ = @constinferred eig_vals(t)
47+
@test d′ diagview(d)
48+
@test d′ isa TensorKit.SectorVector
49+
50+
d2 = @constinferred DiagonalTensorMap(d′)
51+
@test d2 d
52+
53+
vdv = project_hermitian!(v' * v)
54+
@test @constinferred isposdef(vdv)
55+
t isa DiagonalTensorMap || @test !isposdef(t) # unlikely for non-hermitian map
56+
57+
nvals = round(Int, dim(domain(t)) / 2)
58+
d, v = @constinferred eig_trunc(t; trunc = truncrank(nvals))
59+
@test t * v v * d
60+
test_dim_isapprox(domain(d), nvals)
61+
62+
t2 = @constinferred project_hermitian(t)
63+
D, V = eigen(t2)
64+
@test isisometric(V)
65+
D̃, Ṽ = @constinferred eigh_full(t2)
66+
@test D
67+
@test V
68+
λ = minimum(real, diagview(D))
69+
@test cond(Ṽ) one(real(T))
70+
@test isposdef(t2) == isposdef(λ)
71+
@test isposdef(t2 - λ * one(t2) + 0.1 * one(t2))
72+
@test !isposdef(t2 - λ * one(t2) - 0.1 * one(t2))
73+
74+
d, v = @constinferred eigh_full(t2)
75+
@test t2 * v v * d
76+
@test isunitary(v)
77+
78+
d′ = @constinferred eigh_vals(t2)
79+
@test d′ diagview(d)
80+
@test d′ isa TensorKit.SectorVector
81+
82+
λ = minimum(real, diagview(d))
83+
@test cond(v) one(real(T))
84+
@test isposdef(t2) == isposdef(λ)
85+
@test isposdef(t2 - λ * one(t) + 0.1 * one(t2))
86+
@test !isposdef(t2 - λ * one(t) - 0.1 * one(t2))
87+
88+
d, v = @constinferred eigh_trunc(t2; trunc = truncrank(nvals))
89+
@test t2 * v v * d
90+
test_dim_isapprox(domain(d), nvals)
91+
end
92+
end
93+
end
94+
end

test/factorizations/ortho.jl

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
using Test, TestExtras
2+
using TensorKit
3+
using LinearAlgebra: LinearAlgebra
4+
using MatrixAlgebraKit: diagview
5+
6+
7+
spacelist = if fast_tests
8+
(Vtr, Vℤ₃, VSU₂)
9+
elseif get(ENV, "CI", "false") == "true"
10+
println("Detected running on CI")
11+
if Sys.iswindows()
12+
(Vtr, Vℤ₃, VU₁, VfU₁, VCU₁, VSU₂, VIB_diag)
13+
elseif Sys.isapple()
14+
(Vtr, Vℤ₃, VfU₁, VfSU₂, VIB_M)
15+
else
16+
(Vtr, VU₁, VCU₁, VSU₂, VfSU₂, VIB_diag, VIB_M)
17+
end
18+
else
19+
(Vtr, Vℤ₃, VU₁, VfU₁, VCU₁, VSU₂, VfSU₂, VIB_diag, VIB_M)
20+
end
21+
22+
eltypes = (Float32, ComplexF64)
23+
24+
for V in spacelist
25+
I = sectortype(first(V))
26+
Istr = TensorKit.type_repr(I)
27+
println("---------------------------------------")
28+
println("Factorizations with symmetry: $Istr")
29+
println("---------------------------------------")
30+
@timedtestset "Factorizations with symmetry: $Istr" verbose = true begin
31+
V1, V2, V3, V4, V5 = V
32+
W = V1 V2
33+
@assert !isempty(blocksectors(W))
34+
@assert !isempty(intersect(blocksectors(V4), blocksectors(W)))
35+
36+
@testset "QR decomposition" begin
37+
for T in eltypes,
38+
t in (
39+
rand(T, W, W), rand(T, W, W)', rand(T, W, V4), rand(T, V4, W)',
40+
DiagonalTensorMap(rand(T, reduceddim(V1)), V1),
41+
)
42+
43+
Q, R = @constinferred qr_full(t)
44+
@test Q * R t
45+
@test isunitary(Q)
46+
47+
Q, R = @constinferred qr_compact(t)
48+
@test Q * R t
49+
@test isisometric(Q)
50+
51+
Q, R = @constinferred left_orth(t)
52+
@test Q * R t
53+
@test isisometric(Q)
54+
55+
N = @constinferred qr_null(t)
56+
@test isisometric(N)
57+
@test norm(N' * t) 0 atol = 100 * eps(norm(t))
58+
59+
N = @constinferred left_null(t)
60+
@test isisometric(N)
61+
@test norm(N' * t) 0 atol = 100 * eps(norm(t))
62+
end
63+
64+
# empty tensor
65+
for T in eltypes
66+
t = rand(T, V1 V2, zerospace(V1))
67+
68+
Q, R = @constinferred qr_full(t)
69+
@test Q * R t
70+
@test isunitary(Q)
71+
@test dim(R) == dim(t) == 0
72+
73+
Q, R = @constinferred qr_compact(t)
74+
@test Q * R t
75+
@test isisometric(Q)
76+
@test dim(Q) == dim(R) == dim(t)
77+
78+
Q, R = @constinferred left_orth(t)
79+
@test Q * R t
80+
@test isisometric(Q)
81+
@test dim(Q) == dim(R) == dim(t)
82+
83+
N = @constinferred qr_null(t)
84+
@test isunitary(N)
85+
@test norm(N' * t) 0 atol = 100 * eps(norm(t))
86+
end
87+
end
88+
89+
@testset "LQ decomposition" begin
90+
for T in eltypes,
91+
t in (
92+
rand(T, W, W), rand(T, W, W)', rand(T, W, V4), rand(T, V4, W)',
93+
DiagonalTensorMap(rand(T, reduceddim(V1)), V1),
94+
)
95+
96+
L, Q = @constinferred lq_full(t)
97+
@test L * Q t
98+
@test isunitary(Q)
99+
100+
L, Q = @constinferred lq_compact(t)
101+
@test L * Q t
102+
@test isisometric(Q; side = :right)
103+
104+
L, Q = @constinferred right_orth(t)
105+
@test L * Q t
106+
@test isisometric(Q; side = :right)
107+
108+
Nᴴ = @constinferred lq_null(t)
109+
@test isisometric(Nᴴ; side = :right)
110+
@test norm(t * Nᴴ') 0 atol = 100 * eps(norm(t))
111+
end
112+
113+
for T in eltypes
114+
# empty tensor
115+
t = rand(T, zerospace(V1), V1 V2)
116+
117+
L, Q = @constinferred lq_full(t)
118+
@test L * Q t
119+
@test isunitary(Q)
120+
@test dim(L) == dim(t) == 0
121+
122+
L, Q = @constinferred lq_compact(t)
123+
@test L * Q t
124+
@test isisometric(Q; side = :right)
125+
@test dim(Q) == dim(L) == dim(t)
126+
127+
L, Q = @constinferred right_orth(t)
128+
@test L * Q t
129+
@test isisometric(Q; side = :right)
130+
@test dim(Q) == dim(L) == dim(t)
131+
132+
Nᴴ = @constinferred lq_null(t)
133+
@test isunitary(Nᴴ)
134+
@test norm(t * Nᴴ') 0 atol = 100 * eps(norm(t))
135+
end
136+
end
137+
end
138+
end

test/factorizations/projections.jl

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
using Test, TestExtras
2+
using TensorKit
3+
using LinearAlgebra: LinearAlgebra
4+
using MatrixAlgebraKit: diagview
5+
6+
7+
spacelist = if fast_tests
8+
(Vtr, Vℤ₃, VSU₂)
9+
elseif get(ENV, "CI", "false") == "true"
10+
println("Detected running on CI")
11+
if Sys.iswindows()
12+
(Vtr, Vℤ₃, VU₁, VfU₁, VCU₁, VSU₂, VIB_diag)
13+
elseif Sys.isapple()
14+
(Vtr, Vℤ₃, VfU₁, VfSU₂, VIB_M)
15+
else
16+
(Vtr, VU₁, VCU₁, VSU₂, VfSU₂, VIB_diag, VIB_M)
17+
end
18+
else
19+
(Vtr, Vℤ₃, VU₁, VfU₁, VCU₁, VSU₂, VfSU₂, VIB_diag, VIB_M)
20+
end
21+
22+
eltypes = (Float32, ComplexF64)
23+
24+
for V in spacelist
25+
I = sectortype(first(V))
26+
Istr = TensorKit.type_repr(I)
27+
println("---------------------------------------")
28+
println("Factorizations with symmetry: $Istr")
29+
println("---------------------------------------")
30+
@timedtestset "Factorizations with symmetry: $Istr" verbose = true begin
31+
V1, V2, V3, V4, V5 = V
32+
W = V1 V2
33+
@assert !isempty(blocksectors(W))
34+
@assert !isempty(intersect(blocksectors(V4), blocksectors(W)))
35+
36+
@testset "Condition number and rank" begin
37+
for T in eltypes,
38+
t in (
39+
rand(T, W, W), rand(T, W, W)',
40+
rand(T, W, V4), rand(T, V4, W),
41+
rand(T, W, V4)', rand(T, V4, W)',
42+
DiagonalTensorMap(rand(T, reduceddim(V1)), V1),
43+
)
44+
45+
d1, d2 = dim(codomain(t)), dim(domain(t))
46+
r = rank(t)
47+
@test r == min(d1, d2)
48+
@test typeof(r) == typeof(d1)
49+
M = left_null(t)
50+
@test @constinferred(rank(M)) + r d1
51+
Mᴴ = right_null(t)
52+
@test rank(Mᴴ) + r d2
53+
end
54+
for T in eltypes
55+
u = unitary(T, V1 V2, V1 V2)
56+
@test @constinferred(cond(u)) one(real(T))
57+
@test @constinferred(rank(u)) == dim(V1 V2)
58+
59+
t = rand(T, zerospace(V1), W)
60+
@test rank(t) == 0
61+
t2 = rand(T, zerospace(V1) * zerospace(V2), zerospace(V1) * zerospace(V2))
62+
@test rank(t2) == 0
63+
@test cond(t2) == 0.0
64+
end
65+
for T in eltypes, t in (rand(T, W, W), rand(T, W, W)')
66+
project_hermitian!(t)
67+
vals = @constinferred LinearAlgebra.eigvals(t)
68+
λmax = maximum(s -> maximum(abs, s), values(vals))
69+
λmin = minimum(s -> minimum(abs, s), values(vals))
70+
@test cond(t) λmax / λmin
71+
end
72+
end
73+
74+
@testset "Hermitian projections" begin
75+
for T in eltypes,
76+
t in (
77+
rand(T, V1, V1), rand(T, W, W), rand(T, W, W)',
78+
DiagonalTensorMap(rand(T, reduceddim(V1)), V1),
79+
)
80+
normalize!(t)
81+
noisefactor = eps(real(T))^(3 / 4)
82+
83+
th = (t + t') / 2
84+
ta = (t - t') / 2
85+
tc = copy(t)
86+
87+
th′ = @constinferred project_hermitian(t)
88+
@test ishermitian(th′)
89+
@test th′ th
90+
@test t == tc
91+
th_approx = th + noisefactor * ta
92+
@test !ishermitian(th_approx) || (T <: Real && t isa DiagonalTensorMap)
93+
@test ishermitian(th_approx; atol = 10 * noisefactor)
94+
95+
ta′ = project_antihermitian(t)
96+
@test isantihermitian(ta′)
97+
@test ta′ ta
98+
@test t == tc
99+
ta_approx = ta + noisefactor * th
100+
@test !isantihermitian(ta_approx)
101+
@test isantihermitian(ta_approx; atol = 10 * noisefactor) || (T <: Real && t isa DiagonalTensorMap)
102+
end
103+
end
104+
105+
@testset "Isometric projections" begin
106+
for T in eltypes,
107+
t in (
108+
randn(T, W, W), randn(T, W, W)',
109+
randn(T, W, V4), randn(T, V4, W)',
110+
)
111+
t2 = project_isometric(t)
112+
@test isisometric(t2)
113+
t3 = project_isometric(t2)
114+
@test t3 t2 # stability of the projection
115+
@test t2 * (t2' * t) t
116+
117+
tc = similar(t)
118+
t3 = @constinferred project_isometric!(copy!(tc, t), t2)
119+
@test t3 === t2
120+
@test isisometric(t2)
121+
122+
# test that t2 is closer to A then any other isometry
123+
for k in 1:10
124+
δt = randn!(similar(t))
125+
t3 = project_isometric(t + δt / 100)
126+
@test norm(t - t3) > norm(t - t2)
127+
end
128+
end
129+
end
130+
end
131+
end

0 commit comments

Comments
 (0)