Skip to content

Commit 5fb5a19

Browse files
committed
split up tensor tests
1 parent d8110c5 commit 5fb5a19

5 files changed

Lines changed: 778 additions & 681 deletions

File tree

test/tensors/construction.jl

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
using Test, TestExtras
2+
using TensorKit
3+
using TensorKit: type_repr
4+
5+
6+
spacelist = if fast_tests
7+
(Vtr, Vℤ₃, VSU₂)
8+
elseif get(ENV, "CI", "false") == "true"
9+
println("Detected running on CI")
10+
if Sys.iswindows()
11+
(Vtr, Vℤ₂, Vfℤ₂, Vℤ₃, VU₁, VfU₁, VCU₁, VSU₂, VIB_diag)
12+
elseif Sys.isapple()
13+
(Vtr, Vℤ₂, Vfℤ₂, Vℤ₃, VfU₁, VfSU₂, VSU₂U₁, VIB_M) #, VSU₃)
14+
else
15+
(Vtr, Vℤ₂, Vfℤ₂, VU₁, VCU₁, VSU₂, VfSU₂, VSU₂U₁, VIB_diag, VIB_M) #, VSU₃)
16+
end
17+
else
18+
(Vtr, Vℤ₂, Vfℤ₂, Vℤ₃, VU₁, VfU₁, VCU₁, VSU₂, VfSU₂, VSU₂U₁, VIB_diag, VIB_M) #, VSU₃)
19+
end
20+
21+
for V in spacelist
22+
I = sectortype(first(V))
23+
Istr = type_repr(I)
24+
println("---------------------------------------")
25+
println("Tensors with symmetry: $Istr")
26+
println("---------------------------------------")
27+
@timedtestset "Tensors with symmetry: $Istr" verbose = true begin
28+
V1, V2, V3, V4, V5 = V
29+
@timedtestset "Basic tensor properties" begin
30+
W = V1 V2 V3 V4 V5
31+
for T in (fast_tests ? (Float64, ComplexF64) : (Int, Float32, Float64, ComplexF32, ComplexF64, BigFloat))
32+
t = @constinferred zeros(T, W)
33+
@test @constinferred(hash(t)) == hash(deepcopy(t))
34+
@test scalartype(t) == T
35+
@test norm(t) == 0
36+
@test codomain(t) == W
37+
@test space(t) == (W one(W))
38+
@test domain(t) == one(W)
39+
@test typeof(t) == TensorMap{T, spacetype(t), 5, 0, Vector{T}}
40+
# Array type input
41+
t = @constinferred zeros(Vector{T}, W)
42+
@test @constinferred(hash(t)) == hash(deepcopy(t))
43+
@test scalartype(t) == T
44+
@test norm(t) == 0
45+
@test codomain(t) == W
46+
@test space(t) == (W one(W))
47+
@test domain(t) == one(W)
48+
@test typeof(t) == TensorMap{T, spacetype(t), 5, 0, Vector{T}}
49+
# blocks
50+
bs = @constinferred blocks(t)
51+
if !isempty(blocksectors(t)) # multifusion space ending on module gives empty data
52+
(c, b1), state = @constinferred Nothing iterate(bs)
53+
@test c == first(blocksectors(W))
54+
next = @constinferred Nothing iterate(bs, state)
55+
b2 = @constinferred block(t, first(blocksectors(t)))
56+
@test b1 == b2
57+
@test eltype(bs) === Pair{typeof(c), typeof(b1)}
58+
@test typeof(b1) === TensorKit.blocktype(t)
59+
@test typeof(c) === sectortype(t)
60+
end
61+
end
62+
end
63+
@timedtestset "Tensor Dict conversion" begin
64+
W = V1 V2 V3 V4 V5
65+
for T in (Int, Float32, ComplexF64)
66+
t = @constinferred rand(T, W)
67+
d = convert(Dict, t)
68+
@test t == convert(TensorMap, d)
69+
end
70+
end
71+
if hasfusiontensor(I) || I == Trivial
72+
@timedtestset "Tensor Array conversion" begin
73+
W1 = V1 one(V1)
74+
W2 = one(V2) V2
75+
W3 = V1 V2 one(V1)
76+
W4 = V1 V2
77+
W5 = one(V1) V1 V2
78+
W6 = V1 V2 V3 V4 V5
79+
for W in (W1, W2, W3, W4, W5, W6)
80+
for T in (Int, Float32, ComplexF64)
81+
if T == Int
82+
t = TensorMap{T}(undef, W)
83+
for (_, b) in blocks(t)
84+
rand!(b, -20:20)
85+
end
86+
else
87+
t = @constinferred randn(T, W)
88+
end
89+
a = @constinferred convert(Array, t)
90+
b = reshape(a, dim(codomain(W)), dim(domain(W)))
91+
@test t @constinferred TensorMap(a, W)
92+
@test t @constinferred TensorMap(b, W)
93+
@test t === @constinferred TensorMap(t.data, W)
94+
end
95+
end
96+
for T in (Int, Float32, ComplexF64)
97+
t = randn(T, V1 V2 zerospace(V1))
98+
a = convert(Array, t)
99+
@test norm(a) == 0
100+
end
101+
end
102+
end
103+
if hasfusiontensor(I)
104+
@timedtestset "Real and imaginary parts" begin
105+
W = V1 V2
106+
for T in (Float64, ComplexF64, ComplexF32)
107+
t = @constinferred randn(T, W, W)
108+
109+
tr = @constinferred real(t)
110+
@test scalartype(tr) <: Real
111+
@test real(convert(Array, t)) == convert(Array, tr)
112+
113+
ti = @constinferred imag(t)
114+
@test scalartype(ti) <: Real
115+
@test imag(convert(Array, t)) == convert(Array, ti)
116+
117+
tc = @inferred complex(t)
118+
@test scalartype(tc) <: Complex
119+
@test complex(convert(Array, t)) == convert(Array, tc)
120+
121+
tc2 = @inferred complex(tr, ti)
122+
@test tc2 tc
123+
end
124+
end
125+
end
126+
@timedtestset "Tensor conversion" begin
127+
W = V1 V2
128+
t = @constinferred randn(W W)
129+
@test typeof(convert(TensorMap, t')) == typeof(t)
130+
tc = complex(t)
131+
@test convert(typeof(tc), t) == tc
132+
@test typeof(convert(typeof(tc), t)) == typeof(tc)
133+
@test typeof(convert(typeof(tc), t')) == typeof(tc)
134+
@test Base.promote_typeof(t, tc) == typeof(tc)
135+
@test Base.promote_typeof(tc, t) == typeof(tc + t)
136+
end
137+
end
138+
TensorKit.empty_globalcaches!()
139+
end
140+
141+
@timedtestset "show tensors" begin
142+
for V in (ℂ^2, Z2Space(0 => 2, 1 => 2), SU2Space(0 => 2, 1 => 2))
143+
t1 = ones(Float32, V V, V)
144+
t2 = randn(ComplexF64, V V V)
145+
t3 = randn(Float64, zero(V), zero(V))
146+
# test unlimited output
147+
for t in (t1, t2, t1', t2', t3)
148+
output = IOBuffer()
149+
summary(output, t)
150+
print(output, ":\n codomain: ")
151+
show(output, MIME("text/plain"), codomain(t))
152+
print(output, "\n domain: ")
153+
show(output, MIME("text/plain"), domain(t))
154+
print(output, "\n blocks: \n")
155+
first = true
156+
for (c, b) in blocks(t)
157+
first || print(output, "\n\n")
158+
print(output, " * ")
159+
show(output, MIME("text/plain"), c)
160+
print(output, " => ")
161+
show(output, MIME("text/plain"), b)
162+
first = false
163+
end
164+
outputstr = String(take!(output))
165+
@test outputstr == sprint(show, MIME("text/plain"), t)
166+
end
167+
168+
# test limited output with a single block
169+
t = randn(Float64, V V, V)' # we know there is a single space in the codomain, so that blocks have 2 rows
170+
output = IOBuffer()
171+
summary(output, t)
172+
print(output, ":\n codomain: ")
173+
show(output, MIME("text/plain"), codomain(t))
174+
print(output, "\n domain: ")
175+
show(output, MIME("text/plain"), domain(t))
176+
print(output, "\n blocks: \n")
177+
c = unit(sectortype(t))
178+
b = block(t, c)
179+
print(output, " * ")
180+
show(output, MIME("text/plain"), c)
181+
print(output, " => ")
182+
show(output, MIME("text/plain"), b)
183+
if length(blocks(t)) > 1
184+
print(output, "\n\n * … [output of 1 more block(s) truncated]")
185+
end
186+
outputstr = String(take!(output))
187+
@test outputstr == sprint(show, MIME("text/plain"), t; context = (:limit => true, :displaysize => (12, 100)))
188+
end
189+
end

test/tensors/contractions.jl

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
using Test, TestExtras
2+
using TensorKit
3+
using TensorKit: type_repr
4+
5+
6+
spacelist = if fast_tests
7+
(Vtr, Vℤ₃, VSU₂)
8+
elseif get(ENV, "CI", "false") == "true"
9+
println("Detected running on CI")
10+
if Sys.iswindows()
11+
(Vtr, Vℤ₂, Vfℤ₂, Vℤ₃, VU₁, VfU₁, VCU₁, VSU₂, VIB_diag)
12+
elseif Sys.isapple()
13+
(Vtr, Vℤ₂, Vfℤ₂, Vℤ₃, VfU₁, VfSU₂, VSU₂U₁, VIB_M) #, VSU₃)
14+
else
15+
(Vtr, Vℤ₂, Vfℤ₂, VU₁, VCU₁, VSU₂, VfSU₂, VSU₂U₁, VIB_diag, VIB_M) #, VSU₃)
16+
end
17+
else
18+
(Vtr, Vℤ₂, Vfℤ₂, Vℤ₃, VU₁, VfU₁, VCU₁, VSU₂, VfSU₂, VSU₂U₁, VIB_diag, VIB_M) #, VSU₃)
19+
end
20+
21+
for V in spacelist
22+
I = sectortype(first(V))
23+
Istr = type_repr(I)
24+
symmetricbraiding = BraidingStyle(I) isa SymmetricBraiding
25+
println("---------------------------------------")
26+
println("Tensors with symmetry: $Istr")
27+
println("---------------------------------------")
28+
@timedtestset "Tensors with symmetry: $Istr" verbose = true begin
29+
V1, V2, V3, V4, V5 = V
30+
@timedtestset "Full trace: test self-consistency" begin
31+
if symmetricbraiding
32+
t = rand(ComplexF64, V1 V2' V2 V1')
33+
t2 = permute(t, ((1, 2), (4, 3)))
34+
s = @constinferred tr(t2)
35+
@test conj(s) tr(t2')
36+
if !isdual(V1)
37+
t2 = twist!(t2, 1)
38+
end
39+
if isdual(V2)
40+
t2 = twist!(t2, 2)
41+
end
42+
ss = tr(t2)
43+
@tensor s2 = t[a, b, b, a]
44+
@tensor t3[a, b] := t[a, c, c, b]
45+
@tensor s3 = t3[a, a]
46+
@test ss s2
47+
@test ss s3
48+
end
49+
t = rand(ComplexF64, V1 V2 V1 V2) # avoid permutes
50+
ss = @constinferred tr(t)
51+
@test conj(ss) tr(t')
52+
@planar s2 = t[a b; a b]
53+
@planar t3[a; b] := t[a c; b c]
54+
@planar s3 = t3[a; a]
55+
56+
@test ss s2
57+
@test ss s3
58+
end
59+
@timedtestset "Partial trace: test self-consistency" begin
60+
if symmetricbraiding
61+
t = rand(ComplexF64, V1 V2 V3 V1 V2 V3)
62+
@tensor t2[a; b] := t[c d b; c d a]
63+
@tensor t4[a b; c d] := t[e d c; e b a]
64+
@tensor t5[a; b] := t4[a c; b c]
65+
@test t2 t5
66+
end
67+
t = rand(ComplexF64, V3 V4 V5 V3 V4 V5) # compatible with module fusion
68+
@planar t2[a; b] := t[c a d; c b d]
69+
@planar t4[a b; c d] := t[e a b; e c d]
70+
@planar t5[a; b] := t4[a c; b c]
71+
@test t2 t5
72+
end
73+
if BraidingStyle(I) isa Bosonic && hasfusiontensor(I)
74+
@timedtestset "Trace: test via conversion" begin
75+
t = rand(ComplexF64, V1 V2' V3 V2 V1' V3')
76+
@tensor t2[a, b] := t[c, d, b, d, c, a]
77+
@tensor t3[a, b] := convert(Array, t)[c, d, b, d, c, a]
78+
@test t3 convert(Array, t2)
79+
end
80+
end
81+
#TODO: find version that works for all multifusion cases
82+
symmetricbraiding && @timedtestset "Trace and contraction" begin
83+
t1 = rand(ComplexF64, V1 V2 V3)
84+
t2 = rand(ComplexF64, V2' V4 V1')
85+
t3 = t1 t2
86+
@tensor ta[a, b] := t1[x, y, a] * t2[y, b, x]
87+
@tensor tb[a, b] := t3[x, y, a, y, b, x]
88+
@test ta tb
89+
end
90+
if BraidingStyle(I) isa Bosonic && hasfusiontensor(I)
91+
@timedtestset "Tensor contraction: test via conversion" begin
92+
A1 = randn(ComplexF64, V1' * V2', V3')
93+
A2 = randn(ComplexF64, V3 * V4, V5)
94+
rhoL = randn(ComplexF64, V1, V1)
95+
rhoR = randn(ComplexF64, V5, V5)' # test adjoint tensor
96+
H = randn(ComplexF64, V2 * V4, V2 * V4)
97+
@tensor HrA12[a, s1, s2, c] := rhoL[a, a'] * conj(A1[a', t1, b]) *
98+
A2[b, t2, c'] * rhoR[c', c] * H[s1, s2, t1, t2]
99+
100+
@tensor HrA12array[a, s1, s2, c] := convert(Array, rhoL)[a, a'] *
101+
conj(convert(Array, A1)[a', t1, b]) * convert(Array, A2)[b, t2, c'] *
102+
convert(Array, rhoR)[c', c] * convert(Array, H)[s1, s2, t1, t2]
103+
104+
@test HrA12array convert(Array, HrA12)
105+
end
106+
end
107+
@timedtestset "Tensor product: test via norm preservation" begin
108+
for T in (Float32, ComplexF64)
109+
if UnitStyle(I) isa SimpleUnit || !isempty(blocksectors(V2 V1))
110+
t1 = rand(T, V2 V3 V1, V1 V2)
111+
t2 = rand(T, V2 V1 V3, V1 V1)
112+
else
113+
t1 = rand(T, V3 V4 V5, V1 V2)
114+
t2 = rand(T, V5' V4' V3', V2' V1')
115+
end
116+
t = @constinferred (t1 t2)
117+
@test norm(t) norm(t1) * norm(t2)
118+
end
119+
end
120+
if BraidingStyle(I) isa Bosonic && hasfusiontensor(I)
121+
@timedtestset "Tensor product: test via conversion" begin
122+
for T in (Float32, ComplexF64)
123+
t1 = rand(T, V2 V3 V1, V1)
124+
t2 = rand(T, V2 V1 V3, V2)
125+
t = @constinferred (t1 t2)
126+
d1 = dim(codomain(t1))
127+
d2 = dim(codomain(t2))
128+
d3 = dim(domain(t1))
129+
d4 = dim(domain(t2))
130+
At = convert(Array, t)
131+
@test reshape(At, (d1, d2, d3, d4))
132+
reshape(convert(Array, t1), (d1, 1, d3, 1)) .*
133+
reshape(convert(Array, t2), (1, d2, 1, d4))
134+
end
135+
end
136+
end
137+
symmetricbraiding && @timedtestset "Tensor product: test via tensor contraction" begin
138+
for T in (Float32, ComplexF64)
139+
t1 = rand(T, V2 V3 V1)
140+
t2 = rand(T, V2 V1 V3)
141+
t = @constinferred (t1 t2)
142+
@tensor t′[1, 2, 3, 4, 5, 6] := t1[1, 2, 3] * t2[4, 5, 6]
143+
@test t t′
144+
end
145+
end
146+
@timedtestset "Tensor absorption" begin
147+
# absorbing small into large
148+
if UnitStyle(I) isa SimpleUnit || !isempty(blocksectors(V2 V3))
149+
t1 = zeros(V1 V1, V2 V3)
150+
t2 = rand(V1, V2 V3)
151+
else
152+
t1 = zeros(V1 V2, V3 V4 V5)
153+
t2 = rand(V1, V3 V4 V5)
154+
end
155+
t3 = @constinferred absorb(t1, t2)
156+
@test norm(t3) norm(t2)
157+
@test norm(t1) == 0
158+
t4 = @constinferred absorb!(t1, t2)
159+
@test t1 === t4
160+
@test t3 t4
161+
162+
# absorbing large into small
163+
if UnitStyle(I) isa SimpleUnit || !isempty(blocksectors(V2 V3))
164+
t1 = rand(V1 V1, V2 V3)
165+
t2 = zeros(V1, V2 V3)
166+
else
167+
t1 = rand(V1 V2, V3 V4 V5)
168+
t2 = zeros(V1, V3 V4 V5)
169+
end
170+
t3 = @constinferred absorb(t2, t1)
171+
@test norm(t3) < norm(t1)
172+
@test norm(t2) == 0
173+
t4 = @constinferred absorb!(t2, t1)
174+
@test t2 === t4
175+
@test t3 t4
176+
end
177+
end
178+
TensorKit.empty_globalcaches!()
179+
end
180+
181+
@timedtestset "Deligne tensor product: test via conversion" begin
182+
@testset for Vlist1 in (Vtr, VSU₂), Vlist2 in (Vtr, Vℤ₂)
183+
V1, V2, V3, V4, V5 = Vlist1
184+
W1, W2, W3, W4, W5 = Vlist2
185+
for T in (Float32, ComplexF64)
186+
t1 = rand(T, V1 V2, V3' V4)
187+
t2 = rand(T, W2, W1 W1')
188+
t = @constinferred (t1 t2)
189+
d1 = dim(codomain(t1))
190+
d2 = dim(codomain(t2))
191+
d3 = dim(domain(t1))
192+
d4 = dim(domain(t2))
193+
At = convert(Array, t)
194+
@test reshape(At, (d1, d2, d3, d4))
195+
reshape(convert(Array, t1), (d1, 1, d3, 1)) .*
196+
reshape(convert(Array, t2), (1, d2, 1, d4))
197+
end
198+
end
199+
end

0 commit comments

Comments
 (0)