Skip to content

Commit 24145b1

Browse files
committed
Add NTU tests
1 parent 2540e48 commit 24145b1

4 files changed

Lines changed: 201 additions & 35 deletions

File tree

test/bondenv/benv_ntu.jl

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
using Test
2+
using TensorKit
3+
using PEPSKit
4+
using LinearAlgebra
5+
using KrylovKit
6+
using Random
7+
8+
Nr, Nc = 2, 2
9+
Random.seed!(20)
10+
11+
function test_ntu_env(
12+
state::Union{InfinitePEPS, InfinitePEPO}, env_alg::Alg
13+
) where {Alg <: PEPSKit.NeighbourEnv}
14+
@info "Testing $(typeof(env_alg))"
15+
for row in 1:Nr, col in 1:Nc
16+
cp1 = PEPSKit._next(col, Nc)
17+
A, B = state.A[row, col], state.A[row, cp1]
18+
X, a, b, Y = PEPSKit._qr_bond(A, B)
19+
@tensor ab[DX DY; da db] := a[DX da D] * b[D db DY]
20+
benv = PEPSKit.bondenv_ntu(row, col, X, Y, state, env_alg)
21+
# this is a result of `_qr_bond`
22+
@assert [isdual(space(benv, ax)) for ax in 1:numind(benv)] == [0, 0, 1, 1]
23+
# NTU bond environments are exact and should be positive definite
24+
@test benv' benv
25+
benv = project_hermitian(benv)
26+
nrm1 = PEPSKit.inner_prod(benv, ab, ab)
27+
@test nrm1 real(nrm1)
28+
D, U = eigh_full(benv)
29+
@test minimum(D.data) >= 0
30+
# gauge fixing
31+
Z = PEPSKit.sdiag_pow(D, 0.5) * U'
32+
@assert benv Z' * Z
33+
Z2, a2, b2, (Linv, Rinv) = PEPSKit.fixgauge_benv(Z, a, b)
34+
benv2 = Z2' * Z2
35+
# gauge fixing should reduce condition number
36+
cond = LinearAlgebra.cond(benv)
37+
cond2 = LinearAlgebra.cond(benv2)
38+
@test cond2 <= cond
39+
@info "benv cond number: (gauge-fixed) $(cond2)$(cond) (initial)"
40+
# verify gauge transformation of X, Y
41+
@tensor a2b2[DX DY; da db] := a2[DX da D] * b2[D db DY]
42+
nrm2 = PEPSKit.inner_prod(benv2, a2b2, a2b2)
43+
X2, Y2 = PEPSKit._fixgauge_benvXY(X, Y, Linv, Rinv)
44+
benv3 = PEPSKit.bondenv_ntu(row, col, X2, Y2, state, env_alg)
45+
benv3 *= norm(benv2, Inf)
46+
nrm3 = PEPSKit.inner_prod(benv3, a2b2, a2b2)
47+
@test benv2 benv3
48+
@test nrm1 nrm2 nrm3
49+
end
50+
return
51+
end
52+
53+
@testset "NTU bond environment ($(sym))" for sym in [U1Irrep, FermionParity]
54+
Pspace = Vect[sym](0 => 1, 1 => 1)
55+
V2 = Vect[sym](0 => 4, 1 => 1)
56+
V3 = Vect[sym](0 => 3, 1 => 2)
57+
V4 = Vect[sym](0 => 2, 1 => 2)
58+
V5 = Vect[sym](0 => 2, 1 => 3)
59+
Pspaces = fill(Pspace, (Nr, Nc))
60+
Nspaces = [V2 V2; V4 V4]
61+
Espaces = [V3 V5; V5 V3]
62+
63+
for state in [
64+
InfinitePEPS(randn, ComplexF64, Pspaces, Nspaces, Espaces),
65+
InfinitePEPO(randn, ComplexF64, Pspaces, Nspaces, Espaces),
66+
]
67+
normalize!.(state.A, Inf)
68+
for env_alg in (NNEnv(), NNpEnv(), NNNEnv())
69+
test_ntu_env(state, env_alg)
70+
end
71+
end
72+
end

test/runtests.jl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ end
9090
@time @safetestset "Gauge fixing" begin
9191
include("bondenv/benv_gaugefix.jl")
9292
end
93+
@time @safetestset "Exact NTU bond environments" begin
94+
include("bondenv/benv_ntu.jl")
95+
end
9396
@time @safetestset "Full update bond environment" begin
9497
include("bondenv/benv_ctm.jl")
9598
end
@@ -110,6 +113,9 @@ end
110113
@time @safetestset "J1-J2 model at finite temperature" begin
111114
include("timeevol/j1j2_finiteT.jl")
112115
end
116+
@time @safetestset "Transverse Field Ising model real-time evolution" begin
117+
include("timeevol/tf_ising_realtime.jl")
118+
end
113119
end
114120
if GROUP == "ALL" || GROUP == "TOOLBOX"
115121
@time @safetestset "Density matrix from double-layer PEPO" begin

test/timeevol/j1j2_finiteT.jl

Lines changed: 33 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,8 @@ import MPSKitModels: σˣ, σᶻ
55
using PEPSKit
66

77
# Benchmark energy from high-temperature expansion
8-
# at β = 0.3, 0.6
9-
# Physical Review B 86, 045139 (2012) Fig. 15-16
10-
bm = [-0.1235, -0.213]
8+
const βs = [0.2, 0.4, 0.6]
9+
const bm = [-0.08624893, -0.15688984, -0.21300888]
1110

1211
function converge_env(state, χ::Int)
1312
trunc1 = truncrank(χ) & truncerror(; atol = 1.0e-12)
@@ -23,37 +22,36 @@ ham = j1_j2_model(
2322
)
2423
pepo0 = PEPSKit.infinite_temperature_density_matrix(ham)
2524
wts0 = SUWeight(pepo0)
26-
# 7 = 1 (spin-0) + 2 x 3 (spin-1)
27-
trunc_pepo = truncrank(7) & truncerror(; atol = 1.0e-12)
28-
check_interval = 100
29-
dt, nstep = 1.0e-3, 600
25+
dt, nstep, check_interval = 5.0e-3, 40, 40
3026

31-
# PEPO approach
32-
alg = SimpleUpdate(; trunc = trunc_pepo, purified = false)
33-
evolver = TimeEvolver(pepo0, ham, dt, nstep, alg, wts0)
34-
pepo, wts, info = time_evolve(evolver; check_interval)
35-
env = converge_env(InfinitePartitionFunction(pepo), 16)
36-
energy = expectation_value(pepo, ham, env) / (Nr * Nc)
37-
@info "β = $(dt * nstep): tr(ρH) = $(energy)"
38-
@test dt * nstep info.t
39-
@test energy bm[2] atol = 5.0e-3
40-
41-
# PEPS (purified PEPO) approach
42-
alg = SimpleUpdate(; trunc = trunc_pepo, purified = true)
43-
evolver = TimeEvolver(pepo0, ham, dt, nstep, alg, wts0)
44-
pepo, wts, info = time_evolve(evolver; check_interval)
45-
env = converge_env(InfinitePartitionFunction(pepo), 16)
46-
energy = expectation_value(pepo, ham, env) / (Nr * Nc)
47-
@info "β = $(dt * nstep) / 2: tr(ρH) = $(energy)"
48-
@test energy bm[1] atol = 5.0e-3
49-
50-
# test BP gauge fixing for purified iPEPO
51-
bp_alg = BeliefPropagation(; maxiter = 100, tol = 1.0e-9)
52-
bp_env, = leading_boundary(BPEnv(ones, Float64, pepo), pepo, bp_alg)
53-
pepo, = gauge_fix(pepo, BPGauge(), bp_env)
27+
@testset "Simple update" begin
28+
# 7 = 1 (spin-0) + 2 x 3 (spin-1)
29+
trunc_pepo = truncrank(7) & truncerror(; atol = 1.0e-12)
30+
alg = SimpleUpdate(; trunc = trunc_pepo, purified = true)
31+
pepo, wts = deepcopy(pepo0), deepcopy(wts0)
32+
for (β, bme) in zip(βs, bm)
33+
t0 = β - βs[1]
34+
pepo, wts, info = time_evolve(pepo, ham, dt, nstep, alg, wts; t0, check_interval)
35+
# measure energy
36+
env = converge_env(InfinitePEPS(pepo), 16)
37+
energy = expectation_value(pepo, ham, pepo, env) / (Nr * Nc)
38+
@info "β = $(info.t): ⟨ρ|H|ρ⟩ = $(energy)"
39+
@test energy bme atol = 5.0e-3
40+
end
41+
end
5442

55-
env = converge_env(InfinitePEPS(pepo), 16)
56-
energy = expectation_value(pepo, ham, pepo, env) / (Nr * Nc)
57-
@info "β = $(dt * nstep): ⟨ρ|H|ρ⟩ = $(energy)"
58-
@test dt * nstep info.t
59-
@test energy bm[2] atol = 5.0e-3
43+
@testset "Neighbourhood tensor update" begin
44+
trunc_pepo = truncrank(4) & truncerror(; atol = 1.0e-12)
45+
opt_alg = ALSTruncation(; trunc = trunc_pepo, tol = 1.0e-10)
46+
alg = NeighbourUpdate(; opt_alg, bondenv_alg = NNEnv())
47+
pepo = deepcopy(pepo0)
48+
for (β, bme) in zip(βs, bm)
49+
t0 = β - βs[1]
50+
pepo, info = time_evolve(pepo, ham, dt, nstep, alg; t0, check_interval)
51+
# measure energy
52+
env = converge_env(InfinitePEPS(pepo), 16)
53+
energy = expectation_value(pepo, ham, pepo, env) / (Nr * Nc)
54+
@info "β = $(info.t): ⟨ρ|H|ρ⟩ = $(energy)"
55+
@test energy bme atol = 2.0e-2
56+
end
57+
end

test/timeevol/tf_ising_realtime.jl

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
using Test
2+
using TensorKit
3+
import MPSKitModels: S_zz, σˣ
4+
using PEPSKit
5+
using Printf
6+
using Accessors: @set
7+
8+
const hc = 3.044382
9+
const formatter = Printf.Format("t = %.2f, ⟨σˣ⟩ = %.7e + %.7e im.")
10+
# real time evolution of ⟨σx⟩
11+
# benchmark data from Physical Review B 104, 094411 (2021)
12+
# Figure 6(a) calculated with D = 8 and χ = 32
13+
const data = [
14+
# 0.01 9.9920027e-1
15+
0.06 9.7274912e-1
16+
0.11 9.1973182e-1
17+
0.16 8.6230618e-1
18+
0.21 8.1894325e-1
19+
0.26 8.0003708e-1
20+
0.31 8.0081082e-1
21+
0.36 8.0979257e-1
22+
# 0.41 8.1559623e-1
23+
# 0.46 8.1541661e-1
24+
# 0.51 8.1274128e-1
25+
]
26+
27+
# the fully polarized state
28+
peps0 = InfinitePEPS(zeros, ComplexF64, ℂ^2, ℂ^1; unitcell = (2, 2))
29+
for t in peps0.A
30+
t[1, 1, 1, 1, 1] = 1.0
31+
t[2, 1, 1, 1, 1] = 1.0
32+
end
33+
lattice = collect(space(t, 1) for t in peps0.A)
34+
35+
# Hamiltonian
36+
op = LocalOperator(lattice, ((1, 1),) => σˣ())
37+
ham = transverse_field_ising(ComplexF64, Trivial, InfiniteSquare(2, 2); J = 1.0, g = hc)
38+
39+
# truncation strategy
40+
Dcut, chi = 4, 16
41+
trunc_peps = truncerror(; atol = 1.0e-10) & truncrank(Dcut)
42+
trunc_env = truncerror(; atol = 1.0e-10) & truncrank(chi)
43+
44+
ctm_alg = SequentialCTMRG(;
45+
tol = 1.0e-8, maxiter = 50, verbosity = 2,
46+
trunc = trunc_env, projector_alg = :fullinfinite
47+
)
48+
49+
interval = 5
50+
ntu_alg = NeighbourUpdate(;
51+
opt_alg = FullEnvTruncation(; trunc = trunc_peps, tol = 1.0e-10),
52+
bondenv_alg = NNEnv(), imaginary_time = false
53+
)
54+
55+
# do one step of NTU to match benchmark data
56+
peps0, = time_evolve(peps0, ham, 0.01, 6, ntu_alg)
57+
@info "Space of `peps0[1, 1]` = $(space(peps0[1, 1]))."
58+
env0 = CTMRGEnv(ones, ComplexF64, peps0, ℂ^1)
59+
env0, = leading_boundary(env0, peps0, ctm_alg)
60+
# measure magnetization
61+
magx = expectation_value(peps0, op, env0)
62+
@info Printf.format(formatter, 0.06, real(magx), imag(magx))
63+
@test isapprox(magx, data[1, 2]; atol = 0.005)
64+
65+
@testset "Neigborhood tensor update" begin
66+
peps, env = deepcopy(peps0), deepcopy(env0)
67+
count = 2
68+
evolver = TimeEvolver(peps, ham, 0.01, 30, ntu_alg; t0 = 0.06)
69+
spaces0 = collect(space(t) for t in peps.A)
70+
for (peps, info) in evolver
71+
!(evolver.state.iter % interval == 0) && continue
72+
spaces = collect(space(t) for t in peps.A)
73+
if spaces0 == spaces
74+
env, = leading_boundary(env, peps, ctm_alg)
75+
else
76+
env = complex(CTMRGEnv(info.wts))
77+
env, = leading_boundary(env, peps, ctm_alg)
78+
end
79+
# monitor the growth of env dimension
80+
corner = env.corners[1, 1, 1]
81+
corner_dim = dim.(space(corner, ax) for ax in 1:numind(corner))
82+
@info "Dimension of env.corner[1, 1, 1] = $(corner_dim)."
83+
# measure magnetization
84+
magx = expectation_value(peps, op, env)
85+
@info Printf.format(formatter, info.t, real(magx), imag(magx))
86+
@test isapprox(magx, data[count, 2]; atol = 0.005)
87+
count += 1
88+
spaces0 = spaces
89+
end
90+
end

0 commit comments

Comments
 (0)