Skip to content

Commit 9631026

Browse files
authored
A method to compute the conformal spin up to 10 (#74)
* Added functions to compress the tensor network in a single direction * Added function to calculate conformal spin * format * Added generic QR_R,L and the function to calculate spin up to 8 * format * Deleted junction, added conformal dimension * changed the corresponding dependent function in symmetric loop tnr * Deleted garbages * Format * Trying to add the loop optimization to transfer MPO * It seems that preserving translational symmetry is very important. So it may be better to only performing loop in a unit cell... * The planar_opt is still the best * format * The 1x4 case is extremely precise The loop optimization of the transfer MPO can indeed reduce the truncation error by 1/10, however, the final spectrum becomes worse when loop is added. Still need to find the reason * Reorganized some functions in cft_data * back truncation of the virtual bond * Change back * Changed another configuration Now the cost decreases to O(D^6) and can calculate spins from -5 to 5 now! * Deleted garbage * Deleted some export
1 parent fef8f49 commit 9631026

6 files changed

Lines changed: 317 additions & 218 deletions

File tree

Project.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,13 @@ Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f"
1616

1717
[compat]
1818
DocStringExtensions = "0.9.4"
19-
julia = "1.10"
2019
KrylovKit = "0.9.5"
20+
LoggingExtras = "~1.0"
2121
OptimKit = "0.4.0"
2222
PEPSKit = "0.5.0"
2323
TensorKit = "0.14"
2424
Zygote = "0.7.7"
25-
LoggingExtras = "~1.0"
25+
julia = "1.10"
2626

2727
[extras]
2828
QuadGK = "1fd47b50-473d-5c70-9696-f719f8f3bcdc"

src/TNRKit.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ export finalize!, finalize_two_by_two!, finalize_cftdata!, finalize_central_char
7676
include("utility/cdl.jl")
7777
export cdl_tensor
7878

79+
include("utility/projectors.jl")
80+
7981
include("utility/blocking.jl")
8082
export block_tensors
8183
end

src/schemes/looptnr.jl

Lines changed: 45 additions & 190 deletions
Original file line numberDiff line numberDiff line change
@@ -43,189 +43,25 @@ function Ψ_A(scheme::LoopTNR)
4343
return psi
4444
end
4545

46-
#Utility functions for QR decomp
47-
48-
# A single step of the QR decomposition from the left with 3 in-coming legs
49-
# | |
50-
# 2 3
51-
# v v
52-
# --L-1-<--T--<-4-----
53-
# =
54-
# | |
55-
# 2 3
56-
# v v
57-
# ----1-<--Q--<-4--Rt-
58-
59-
function QR_L(L::TensorMap, T::AbstractTensorMap{E,S,1,3}) where {E,S}
60-
@planar LT[-1; -2 -3 -4] := L[-1; 1] * T[1; -2 -3 -4]
61-
temp = transpose(LT, (3, 2, 1), (4,); copy=true)
62-
_, Rt = leftorth(temp)
63-
return Rt / norm(Rt, Inf)
64-
end
65-
66-
# A single step of the QR decomposition from the right with 3 in-coming legs
67-
# | |
68-
# 2 3
69-
# v v
70-
# -----1-<--T--<-4-R--
71-
# =
72-
# | |
73-
# 2 3
74-
# v v
75-
# -Lt--1-<--Q--<-4----
76-
77-
function QR_R(R::TensorMap, T::AbstractTensorMap{E,S,1,3}) where {E,S}
78-
@planar TR[-1; -2 -3 -4] := T[-1; -2 -3 1] * R[1; -4]
79-
Lt, _ = rightorth(TR)
80-
return Lt / norm(Lt, Inf)
81-
end
82-
83-
# A single step of the QR decomposition from the left with 2 in-coming legs
84-
# |
85-
# 2
86-
# v
87-
# --L-1-<--T--<-3----
88-
# =
89-
# |
90-
# 2
91-
# v
92-
# ----1-<--Q--<-3--Rt-
93-
94-
function QR_L(L::TensorMap, T::AbstractTensorMap{E,S,1,2}) where {E,S}
95-
@planar LT[-1; -2 -3] := L[-1; 1] * T[1; -2 -3]
96-
temp = transpose(LT, (2, 1), (3,); copy=true)
97-
_, Rt = leftorth(temp)
98-
return Rt / norm(Rt, Inf)
99-
end
100-
101-
# A single step of the QR decomposition from the right with 2 in-coming legs
102-
# |
103-
# 2
104-
# v
105-
# -----1-<--T--<-3-R--
106-
# =
107-
# |
108-
# 2
109-
# v
110-
# -Lt--1-<--Q--<-3----
111-
function QR_R(R::TensorMap, T::AbstractTensorMap{E,S,1,2}) where {E,S}
112-
@planar TR[-1; -2 -3] := T[-1; -2 1] * R[1; -3]
113-
Lt, _ = rightorth(TR)
114-
return Lt / norm(Lt, Inf)
115-
end
116-
117-
# Functions to find the left and right projectors
118-
119-
# Function to find the list of left projectors L_list
120-
function find_L(psi::Array, entanglement_criterion::stopcrit)
121-
type = eltype(psi[1])
122-
n = length(psi)
123-
L_list = map(x -> id(type, codomain(psi[x])[1]), 1:n)
124-
crit = true
125-
steps = 0
126-
error = [Inf]
127-
running_pos = 1
128-
while crit
129-
pos_next = mod(running_pos, n) + 1
130-
L_last_time = L_list[pos_next]
131-
L_list[pos_next] = QR_L(L_list[running_pos], psi[running_pos])
132-
133-
if space(L_list[pos_next]) == space(L_last_time)
134-
push!(error, abs(norm(L_list[pos_next] - L_last_time)))
135-
end
136-
137-
running_pos = pos_next
138-
steps += 1
139-
crit = entanglement_criterion(steps, error)
140-
end
141-
142-
return L_list
143-
end
144-
145-
# Function to find the list of right projectors R_list
146-
function find_R(psi::Array, entanglement_criterion::stopcrit)
147-
type = eltype(psi[1])
148-
n = length(psi)
149-
R_list = map(x -> id(type, domain(psi[x]).spaces[end]), 1:n)
150-
crit = true
151-
steps = 0
152-
error = [Inf]
153-
154-
running_pos = n
155-
while crit
156-
pos_last = mod(running_pos - 2, n) + 1
157-
R_last_time = R_list[pos_last]
158-
R_list[pos_last] = QR_R(R_list[running_pos], psi[running_pos])
159-
160-
if space(R_list[pos_last]) == space(R_last_time)
161-
push!(error, abs(norm(R_list[pos_last] - R_last_time)))
162-
end
163-
164-
running_pos = pos_last
165-
steps += 1
166-
crit = entanglement_criterion(steps, error)
167-
end
168-
169-
return R_list
170-
end
171-
172-
# Function to find the projector P_L and P_R
173-
function P_decomp(R::TensorMap, L::TensorMap, trunc::TensorKit.TruncationScheme)
174-
U, S, V, _ = tsvd(L * R; trunc=trunc, alg=TensorKit.SVD())
175-
re_sq = pseudopow(S, -0.5)
176-
PR = R * V' * re_sq
177-
PL = re_sq * U' * L
178-
return PR, PL
179-
end
180-
181-
# Function to find the list of projectors
182-
function find_projectors(psi::Array, entanglement_criterion::stopcrit,
183-
trunc::TensorKit.TruncationScheme)
184-
PR_list = []
185-
PL_list = []
186-
187-
n = length(psi)
188-
L_list = find_L(psi, entanglement_criterion)
189-
R_list = find_R(psi, entanglement_criterion)
190-
for i in 1:n
191-
pr, pl = P_decomp(R_list[mod(i - 2, n) + 1], L_list[i], trunc)
192-
193-
push!(PR_list, pr)
194-
push!(PL_list, pl)
195-
end
196-
return PR_list, PL_list
197-
end
198-
199-
function SVD12(T::AbstractTensorMap{E,S,1,3}, trunc::TensorKit.TruncationScheme) where {E,S}
200-
T_trans = transpose(T, (2, 1), (3, 4); copy=true)
201-
U, s, V, _ = tsvd(T_trans; trunc=trunc, alg=TensorKit.SVD())
202-
@planar S1[-1; -2 -3] := U[-2 -1; 1] * sqrt(s)[1; -3]
203-
@planar S2[-1; -2 -3] := sqrt(s)[-1; 1] * V[1; -2 -3]
204-
return S1, S2
205-
end
206-
20746
# Function to construct MPS Ψ_B from MPS Ψ_A. Using a large cut-off dimension in SVD but a small cut-off dimension in loop to increase the precision of initialization.
20847
function Ψ_B(ΨA, trunc::TensorKit.TruncationScheme,
20948
truncentanglement::TensorKit.TruncationScheme)
49+
NA = length(ΨA)
21050
ΨB = []
211-
212-
for i in 1:4
51+
for i in 1:NA
21352
s1, s2 = SVD12(ΨA[i], truncdim(trunc.dim * 2))
21453
push!(ΨB, s1)
21554
push!(ΨB, s2)
21655
end
21756

21857
ΨB_function(steps, data) = abs(data[end])
21958
criterion = maxiter(10) & convcrit(1e-12, ΨB_function)
220-
PR_list, PL_list = find_projectors(ΨB, criterion, trunc & truncentanglement)
221-
222-
ΨB_disentangled = []
223-
for i in 1:8
224-
@planar B1[-1; -2 -3] := PL_list[i][-1; 1] * ΨB[i][1; -2 2] *
225-
PR_list[mod(i, 8) + 1][2; -3]
226-
push!(ΨB_disentangled, B1)
227-
end
228-
return ΨB_disentangled
59+
in_inds = ones(Int, 2*NA)
60+
out_inds = 2*ones(Int, 2*NA)
61+
PR_list, PL_list = find_projectors(ΨB, in_inds, out_inds, criterion,
62+
trunc & truncentanglement)
63+
MPO_disentangled!(ΨB, in_inds, out_inds, PR_list, PL_list)
64+
return ΨB
22965
end
23066

23167
# Construct the list of transfer matrices for ΨAΨA
@@ -235,8 +71,9 @@ end
23571
# | |
23672
# ---2'--A--4'---
23773
function ΨAΨA(psiA)
74+
NA = length(psiA)
23875
ΨAΨA_list = []
239-
for i in 1:4
76+
for i in 1:NA
24077
@planar tmp[-1 -2; -3 -4] := psiA[i][-2; 1 2 -4] * psiA[i]'[1 2 -3; -1]
24178
push!(ΨAΨA_list, tmp)
24279
end
@@ -251,8 +88,9 @@ end
25188
# ---2'--B--4'---
25289

25390
function ΨBΨB(psiB)
91+
NB = length(psiB)
25492
ΨBΨB_list = []
255-
for i in 1:8
93+
for i in 1:NB
25694
@planar tmp[-1 -2; -3 -4] := psiB[i][-2; 1 -4] * psiB[i]'[1 -3; -1]
25795
push!(ΨBΨB_list, tmp)
25896
end
@@ -267,8 +105,9 @@ end
267105
# ---2'----A----4'---
268106

269107
function ΨBΨA(psiB, psiA)
108+
NA = length(psiA)
270109
ΨBΨA_list = []
271-
for i in 1:4
110+
for i in 1:NA
272111
@planar temp[-1 -2; -3 -4] := psiB[2 * i - 1]'[1 3; -1] * psiA[i][-2; 1 2 -4] *
273112
psiB[2 * i]'[2 -3; 3]
274113
push!(ΨBΨA_list, temp)
@@ -295,7 +134,8 @@ loop_criterion = maxiter(50) & convcrit(1e-8, entanglement_function)
295134
function entanglement_filtering!(scheme::LoopTNR, entanglement_criterion::stopcrit,
296135
trunc::TensorKit.TruncationScheme)
297136
ΨA = Ψ_A(scheme)
298-
PR_list, PL_list = find_projectors(ΨA, entanglement_criterion, trunc)
137+
PR_list, PL_list = find_projectors(ΨA, [1, 1, 1, 1], [3, 3, 3, 3],
138+
entanglement_criterion, trunc)
299139

300140
TA = copy(scheme.TA)
301141
TB = copy(scheme.TB)
@@ -387,20 +227,20 @@ function right_cache(tensor_list)
387227
return cache
388228
end
389229

390-
# Function to perform the optimization loop for the LoopTNR scheme. Sweeping from left to right, we optimize the tensors in the loop by minimizing the cost function.
230+
# A general function to optimize the truncation error of an MPS on a ring.
231+
# Sweeping from left to right, we optimize the tensors in the loop by minimizing the cost function.
391232
# Here cache of right-half-chain is used to minimize the number of multiplications to accelerate the sweeping.
392233
# The transfer matrix on the left is updated after each optimization step.
393234
# The cache technique is from Chenfeng Bao's thesis, see http://hdl.handle.net/10012/14674.
394-
function loop_opt!(scheme::LoopTNR, loop_criterion::stopcrit,
395-
trunc::TensorKit.TruncationScheme,
396-
truncentanglement::TensorKit.TruncationScheme, verbosity::Int)
397-
psiA = Ψ_A(scheme)
235+
function loop_opt(psiA::Array, loop_criterion::stopcrit,
236+
trunc::TensorKit.TruncationScheme,
237+
truncentanglement::TensorKit.TruncationScheme, verbosity::Int)
398238
psiB = Ψ_B(psiA, trunc, truncentanglement)
239+
NB = length(psiB) # Number of tensors in the MPS Ψ_B
399240
psiBpsiB = ΨBΨB(psiB)
400241
psiBpsiA = ΨBΨA(psiB, psiA)
401242
psiApsiA = ΨAΨA(psiA)
402243
C = to_number(psiApsiA) # Since C is not changed during the optimization, we can compute it once and use it in the cost function.
403-
404244
cost = Float64[Inf]
405245
sweep = 0
406246
crit = true
@@ -411,7 +251,19 @@ function loop_opt!(scheme::LoopTNR, loop_criterion::stopcrit,
411251
left_BA = id(codomain(psiBpsiA[1])) # Initialize the left transfer matrix for ΨBΨA
412252

413253
t_start = time()
414-
for pos_psiB in 1:8
254+
255+
if sweep == 0
256+
tNt = tr(psiBpsiB[1]*right_cache_BB[1])
257+
tdw = tr(psiBpsiA[1]*right_cache_BA[1])
258+
wdt = conj(tdw)
259+
cost_this = real((C + tNt - wdt - tdw) / C)
260+
if verbosity > 1
261+
@infov 3 "Initial cost: $cost_this"
262+
end
263+
push!(cost, cost_this)
264+
end
265+
266+
for pos_psiB in 1:NB
415267
pos_psiA = (pos_psiB - 1) ÷ 2 + 1 # Position in the MPS Ψ_A
416268

417269
N = tN(left_BB, right_cache_BB[pos_psiB]) # Compute the half of the matrix N for the current position in the loop, right cache is used to minimize the number of multiplications
@@ -434,31 +286,34 @@ function loop_opt!(scheme::LoopTNR, loop_criterion::stopcrit,
434286
end
435287
end
436288
sweep += 1
437-
crit = loop_criterion(sweep, cost)
438289

439290
tNt = tr(left_BB)
440291
tdw = tr(left_BA)
441292
wdt = conj(tdw)
442293
cost_this = real((C + tNt - wdt - tdw) / C)
443294
push!(cost, cost_this)
444-
295+
crit = loop_criterion(sweep, cost)
445296
if verbosity > 1
446297
@infov 3 "Sweep: $sweep, Cost: $(cost[end]), Time: $(time() - t_start)s" # Included the time taken for the sweep
447298
end
448299
end
449300

301+
return psiB
302+
end
303+
304+
function loop_opt!(scheme::LoopTNR, loop_criterion::stopcrit,
305+
trunc::TensorKit.TruncationScheme,
306+
truncentanglement::TensorKit.TruncationScheme,
307+
verbosity::Int)
308+
psiA = Ψ_A(scheme)
309+
psiB = loop_opt(psiA, loop_criterion, trunc, truncentanglement, verbosity)
450310
@planar scheme.TB[-1 -2; -3 -4] := psiB[1][1; 2 -2] * psiB[4][-4; 2 3] *
451311
psiB[5][3; 4 -3] * psiB[8][-1; 4 1]
452312
@planar scheme.TA[-1 -2; -3 -4] := psiB[6][-2; 1 2] * psiB[7][2; 3 -4] *
453313
psiB[2][-3; 3 4] * psiB[3][4; 1 -1]
454314
return scheme
455315
end
456316

457-
function loop_opt!(scheme::LoopTNR, trunc::TensorKit.TruncationScheme,
458-
verbosity::Int)
459-
return loop_opt!(scheme, loop_criterion, trunc, verbosity)
460-
end
461-
462317
function step!(scheme::LoopTNR, trunc::TensorKit.TruncationScheme,
463318
truncentanglement::TensorKit.TruncationScheme,
464319
entanglement_criterion::stopcrit,

src/schemes/symmetric_looptnr.jl

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,11 +126,14 @@ function entanglement_filtering(T; trunc=truncbelow(1e-12))
126126
psi_center = Ψ_center(T)
127127
psi_corner = Ψ_corner(T)
128128

129-
PR_list, PL_list = TNRKit.find_projectors(psi_center, entanglement_criterion, trunc)
129+
PR_list, PL_list = TNRKit.find_projectors(psi_center, [1, 1, 1, 1], [3, 3, 3, 3],
130+
entanglement_criterion, trunc)
130131
P_bottom = PL_list[1]
131132
P_right = PL_list[1]
132133

133-
PR_list, PL_list = TNRKit.find_projectors(psi_corner, entanglement_criterion, trunc)
134+
PR_list, PL_list = TNRKit.find_projectors(psi_corner,
135+
[1, 1, 1, 1], [3, 3, 3, 3],
136+
entanglement_criterion, trunc)
134137
P_top = PL_list[3]
135138
P_left = PL_list[3]
136139

@@ -157,7 +160,8 @@ function ef_oneloop(T, trunc::TensorKit.TruncationScheme)
157160

158161
ΨB_function(steps, data) = abs(data[end])
159162
criterion = maxiter(100) & convcrit(1e-12, ΨB_function)
160-
PR_list, _ = find_projectors(ΨB, criterion, trunc)
163+
PR_list, _ = find_projectors(ΨB, [1, 1, 1, 1, 1, 1, 1, 1], [2, 2, 2, 2, 2, 2, 2, 2],
164+
criterion, trunc)
161165

162166
ΨB_disentangled = []
163167
for i in 1:1

0 commit comments

Comments
 (0)