Skip to content

Commit 908e8e2

Browse files
leburgellkdvos
andauthored
CTMRG support for PEPS-PEPO-PEPS networks (#134)
* Rough attempt at CTMRG for PEPO stacks * Fix typo * Actually add the test... * Remove deprecated enlarged corner methods * Remove one getindex layer * Fix merge conflict * Add a proper test and some corresponding fixes and additions * Format * One less duplicate contraction... * At least make it run * Test magnetization instead * Actually fill in test value... * Should run and test at the same temperature... * Needs more LBFGS iterations * Update test * Fix * Another fix * Update src/algorithms/contractions/ctmrg_contractions.jl Co-authored-by: Lukas Devos <ldevos98@gmail.com> * Update src/algorithms/contractions/ctmrg_contractions.jl Co-authored-by: Lukas Devos <ldevos98@gmail.com> * Apply review suggestions * Restore kwarg syntax for `classical_ising` * Fix(?) * Update retract and transport in PEPO test * Clean up some unused type parameters * Properly fix PEPO retract --------- Co-authored-by: Lukas Devos <ldevos98@gmail.com>
1 parent 135c5c1 commit 908e8e2

9 files changed

+1347
-434
lines changed

src/algorithms/contractions/ctmrg_contractions.jl

+977-124
Large diffs are not rendered by default.

src/algorithms/contractions/localoperator.jl

-35
Original file line numberDiff line numberDiff line change
@@ -262,38 +262,3 @@ end
262262
end
263263
return macroexpand(@__MODULE__, returnex)
264264
end
265-
266-
# Partition function contractions
267-
268-
"""
269-
contract_local_tensor(inds, O, env)
270-
271-
Contract a local tensor `O` inserted into a partition function `pf` at position `inds`,
272-
using the environment `env`.
273-
"""
274-
function contract_local_tensor(
275-
inds::Tuple{Int,Int},
276-
O::AbstractTensorMap{T,S,2,2},
277-
env::CTMRGEnv{C,<:CTMRG_PF_EdgeTensor},
278-
) where {T,S,C}
279-
r, c = inds
280-
return @autoopt @tensor env.corners[NORTHWEST, _prev(r, end), _prev(c, end)][
281-
χ_WNW
282-
χ_NNW
283-
] *
284-
env.edges[NORTH, _prev(r, end), c][χ_NNW D_N; χ_NNE] *
285-
env.corners[NORTHEAST, _prev(r, end), _next(c, end)][χ_NNE; χ_ENE] *
286-
env.edges[EAST, r, _next(c, end)][χ_ENE D_E; χ_ESE] *
287-
env.corners[SOUTHEAST, _next(r, end), _next(c, end)][χ_ESE; χ_SSE] *
288-
env.edges[SOUTH, _next(r, end), c][χ_SSE D_S; χ_SSW] *
289-
env.corners[SOUTHWEST, _next(r, end), _prev(c, end)][χ_SSW; χ_WSW] *
290-
env.edges[WEST, r, _prev(c, end)][χ_WSW D_W; χ_WNW] *
291-
O[D_W D_S; D_N D_E]
292-
end
293-
function contract_local_tensor(
294-
inds::CartesianIndex{2},
295-
O::AbstractTensorMap{T,S,2,2},
296-
env::CTMRGEnv{C,<:CTMRG_PF_EdgeTensor},
297-
) where {T,S,C}
298-
return contract_local_tensor(Tuple(inds), O, env)
299-
end

src/algorithms/contractions/vumps_contractions.jl

+20-174
Original file line numberDiff line numberDiff line change
@@ -36,95 +36,6 @@ end
3636

3737
## PEPO
3838

39-
# some plumbing for generic expressions...
40-
41-
# side=:W for argument, side=:E for output, PEPO height H
42-
function _pepo_leftenv_expr(envname, side::Symbol, H::Int)
43-
return tensorexpr(
44-
envname,
45-
(
46-
envlabel(:S, side),
47-
virtuallabel(side, :top),
48-
ntuple(i -> virtuallabel(side, :mid, i), H)...,
49-
virtuallabel(side, :bot),
50-
),
51-
(envlabel(:N, side),),
52-
)
53-
end
54-
55-
# side=:E for argument, side=:W for output, PEPO height H
56-
function _pepo_rightenv_expr(envname, side::Symbol, H::Int)
57-
return tensorexpr(
58-
envname,
59-
(
60-
envlabel(:N, side),
61-
virtuallabel(side, :top),
62-
ntuple(i -> virtuallabel(side, :mid, i), H)...,
63-
virtuallabel(side, :bot),
64-
),
65-
(envlabel(:S, side),),
66-
)
67-
end
68-
69-
# side=:N for ket MPS, side=:S for bra MPS, PEPO height H
70-
function _pepo_mpstensor_expr(tensorname, side::Symbol, H::Int)
71-
return tensorexpr(
72-
tensorname,
73-
(
74-
envlabel(side, :W),
75-
virtuallabel(side, :top),
76-
ntuple(i -> virtuallabel(side, :mid, i), H)...,
77-
virtuallabel(side, :bot),
78-
),
79-
(envlabel(side, :E),),
80-
)
81-
end
82-
83-
# layer=:top for ket PEPS, layer=:bot for bra PEPS, connects to PEPO slice H
84-
function _pepo_pepstensor_expr(tensorname, layer::Symbol, h::Int)
85-
return tensorexpr(
86-
tensorname,
87-
(physicallabel(h),),
88-
(
89-
virtuallabel(:N, layer),
90-
virtuallabel(:E, layer),
91-
virtuallabel(:S, layer),
92-
virtuallabel(:W, layer),
93-
),
94-
)
95-
end
96-
97-
# PEPO slice h
98-
function _pepo_pepotensor_expr(tensorname, h::Int)
99-
return tensorexpr(
100-
tensorname,
101-
(physicallabel(h + 1), physicallabel(h)),
102-
(
103-
virtuallabel(:N, :mid, h),
104-
virtuallabel(:E, :mid, h),
105-
virtuallabel(:S, :mid, h),
106-
virtuallabel(:W, :mid, h),
107-
),
108-
)
109-
end
110-
111-
# specialize simple case
112-
function MPSKit.transfer_left(
113-
GL::GenericMPSTensor{S,4},
114-
O::PEPOSandwich{1},
115-
A::GenericMPSTensor{S,4},
116-
::GenericMPSTensor{S,4},
117-
) where {S}
118-
return @autoopt @tensor GL′[χ_SE D_E_above D_E_mid D_E_below; χ_NE] :=
119-
GL[χ_SW D_W_above D_W_mid D_W_below; χ_NW] *
120-
conj(Ā[χ_SW D_S_above D_S_mid D_S_below; χ_SE]) *
121-
ket(O)[d_in; D_N_above D_E_above D_S_above D_W_above] *
122-
only(pepo(O))[d_out d_in; D_N_mid D_E_mid D_S_mid D_W_mid] *
123-
conj(bra(O)[d_out; D_N_below D_E_below D_S_below D_W_below]) *
124-
A[χ_NW D_N_above D_N_mid D_N_below; χ_NE]
125-
end
126-
127-
# general case
12839
@generated function MPSKit.transfer_left(
12940
GL::GenericMPSTensor{S,N},
13041
O::PEPOSandwich{H},
@@ -134,15 +45,11 @@ end
13445
# sanity check
13546
@assert H == N - 3
13647

137-
GL´_e = _pepo_leftenv_expr(:GL´, :E, H)
138-
GL_e = _pepo_leftenv_expr(:GL, :W, H)
139-
A_e = _pepo_mpstensor_expr(:A, :N, H)
140-
Ā_e = _pepo_mpstensor_expr(:Ā, :S, H)
141-
ket_e = _pepo_pepstensor_expr(:(ket(O)), :top, 1)
142-
bra_e = _pepo_pepstensor_expr(:(bra(O)), :bot, H + 1)
143-
pepo_es = map(1:H) do h
144-
return _pepo_pepotensor_expr(:(pepo(O)[$h]), h)
145-
end
48+
GL´_e = _pepo_edge_expr(:GL´, :SE, :NE, :E, H)
49+
GL_e = _pepo_edge_expr(:GL, :SW, :NW, :W, H)
50+
A_e = _pepo_edge_expr(:A, :NW, :NE, :N, H)
51+
Ā_e = _pepo_edge_expr(:Ā, :SW, :SE, :S, H)
52+
ket_e, bra_e, pepo_es = _pepo_sandwich_expr(:O, H)
14653

14754
rhs = Expr(
14855
:call,
@@ -158,23 +65,6 @@ end
15865
return macroexpand(@__MODULE__, :(return @autoopt @tensor $GL´_e := $rhs))
15966
end
16067

161-
# specialize simple case
162-
function MPSKit.transfer_right(
163-
GR::GenericMPSTensor{S,4},
164-
O::PEPOSandwich{1},
165-
A::GenericMPSTensor{S,4},
166-
::GenericMPSTensor{S,4},
167-
) where {S}
168-
return @tensor GR′[χ_NW D_W_above D_W_mid D_W_below; χ_SW] :=
169-
GR[χ_NE D_E_above D_E_mid D_E_below; χ_SE] *
170-
conj(Ā[χ_SW D_S_above D_S_mid D_S_below; χ_SE]) *
171-
ket(O)[d_in; D_N_above D_E_above D_S_above D_W_above] *
172-
only(pepo(O))[d_out d_in; D_N_mid D_E_mid D_S_mid D_W_mid] *
173-
conj(bra(O)[d_out; D_N_below D_E_below D_S_below D_W_below]) *
174-
A[χ_NW D_N_above D_N_mid D_N_below; χ_NE]
175-
end
176-
177-
# general case
17868
@generated function MPSKit.transfer_right(
17969
GR::GenericMPSTensor{S,N},
18070
O::PEPOSandwich{H},
@@ -184,15 +74,11 @@ end
18474
# sanity check
18575
@assert H == N - 3
18676

187-
GR´_e = _pepo_rightenv_expr(:GR´, :W, H)
188-
GR_e = _pepo_rightenv_expr(:GR, :E, H)
189-
A_e = _pepo_mpstensor_expr(:A, :N, H)
190-
Ā_e = _pepo_mpstensor_expr(:Ā, :S, H)
191-
ket_e = _pepo_pepstensor_expr(:(ket(O)), :top, 1)
192-
bra_e = _pepo_pepstensor_expr(:(bra(O)), :bot, H + 1)
193-
pepo_es = map(1:H) do h
194-
return _pepo_pepotensor_expr(:(pepo(O)[$h]), h)
195-
end
77+
GR´_e = _pepo_edge_expr(:GR´, :NW, :SW, :W, H)
78+
GR_e = _pepo_edge_expr(:GR, :NE, :SE, :E, H)
79+
A_e = _pepo_edge_expr(:A, :NW, :NE, :N, H)
80+
Ā_e = _pepo_edge_expr(:Ā, :SW, :SE, :S, H)
81+
ket_e, bra_e, pepo_es = _pepo_sandwich_expr(:O, H)
19682

19783
rhs = Expr(
19884
:call,
@@ -276,22 +162,6 @@ end
276162

277163
## PEPO
278164

279-
# specialize simple case
280-
function MPSKit.∂AC(
281-
AC::GenericMPSTensor{S,4},
282-
O::PEPOSandwich{1},
283-
GL::GenericMPSTensor{S,4},
284-
GR::GenericMPSTensor{S,4},
285-
) where {S}
286-
return @tensor AC′[χ_SW D_S_above D_S_mid D_S_below; χ_SE] :=
287-
GL[χ_SW D_W_above D_W_mid D_W_below; χ_NW] *
288-
AC[χ_NW D_N_above D_N_mid D_N_below; χ_NE] *
289-
GR[χ_NE D_E_above D_E_mid D_E_below; χ_SE] *
290-
ket(O)[d_in; D_N_above D_E_above D_S_above D_W_above] *
291-
only(pepo(O))[d_out d_in; D_N_mid D_E_mid D_S_mid D_W_mid] *
292-
conj(bra(O)[d_out; D_N_below D_E_below D_S_below D_W_below])
293-
end
294-
295165
@generated function MPSKit.∂AC(
296166
AC::GenericMPSTensor{S,N},
297167
O::PEPOSandwich{H},
@@ -301,15 +171,11 @@ end
301171
# sanity check
302172
@assert H == N - 3
303173

304-
AC´_e = _pepo_mpstensor_expr(:AC´, :S, H)
305-
AC_e = _pepo_mpstensor_expr(:AC, :N, H)
306-
GL_e = _pepo_leftenv_expr(:GL, :W, H)
307-
GR_e = _pepo_rightenv_expr(:GR, :E, H)
308-
ket_e = _pepo_pepstensor_expr(:(ket(O)), :top, 1)
309-
bra_e = _pepo_pepstensor_expr(:(bra(O)), :bot, H + 1)
310-
pepo_es = map(1:H) do h
311-
return _pepo_pepotensor_expr(:(pepo(O)[$h]), h)
312-
end
174+
AC´_e = _pepo_edge_expr(:AC´, :SW, :SE, :S, H)
175+
AC_e = _pepo_edge_expr(:AC, :NW, :NE, :N, H)
176+
GL_e = _pepo_edge_expr(:GL, :SW, :NW, :W, H)
177+
GR_e = _pepo_edge_expr(:GR, :NE, :SE, :E, H)
178+
ket_e, bra_e, pepo_es = _pepo_sandwich_expr(:O, H)
313179

314180
rhs = Expr(:call, :*, AC_e, GL_e, GR_e, ket_e, Expr(:call, :conj, bra_e), pepo_es...)
315181

@@ -324,23 +190,6 @@ ket(p::∂PEPOSandwich) = p[1]
324190
pepo(p::∂PEPOSandwich) = p[2:end]
325191
pepo(p::∂PEPOSandwich, i::Int) = p[1 + i]
326192

327-
# specialize simple case
328-
function ∂peps(
329-
AC::GenericMPSTensor{S,4},
330-
ĀC::GenericMPSTensor{S,4},
331-
O::∂PEPOSandwich{1},
332-
GL::GenericMPSTensor{S,4},
333-
GR::GenericMPSTensor{S,4},
334-
) where {S}
335-
return @tensor ∂p[d_out; D_N_below D_E_below D_S_below D_W_below] :=
336-
GL[χ_SW D_W_above D_W_mid D_W_below; χ_NW] *
337-
AC[χ_NW D_N_above D_N_mid D_N_below; χ_NE] *
338-
ket(O)[d_in; D_N_above D_E_above D_S_above D_W_above] *
339-
only(pepo(O))[d_out d_in; D_N_mid D_E_mid D_S_mid D_W_mid] *
340-
GR[χ_NE D_E_above D_E_mid D_E_below; χ_SE] *
341-
conj(ĀC[χ_SW D_S_above D_S_mid D_S_below; χ_SE])
342-
end
343-
344193
@generated function ∂peps(
345194
AC::GenericMPSTensor{S,N},
346195
ĀC::GenericMPSTensor{S,N},
@@ -352,14 +201,11 @@ end
352201
@assert H == N - 3
353202

354203
∂p_e = _pepo_pepstensor_expr(:∂p, :bot, H + 1)
355-
AC_e = _pepo_mpstensor_expr(:AC, :N, H)
356-
ĀC_e = _pepo_mpstensor_expr(:ĀC, :S, H)
357-
GL_e = _pepo_leftenv_expr(:GL, :W, H)
358-
GR_e = _pepo_rightenv_expr(:GR, :E, H)
359-
ket_e = _pepo_pepstensor_expr(:(ket(O)), :top, 1)
360-
pepo_es = map(1:H) do h
361-
return _pepo_pepotensor_expr(:(pepo(O, $h)), h)
362-
end
204+
AC_e = _pepo_edge_expr(:AC, :NW, :NE, :N, H)
205+
ĀC_e = _pepo_edge_expr(:ĀC, :SW, :SE, :S, H)
206+
GL_e = _pepo_edge_expr(:GL, :SW, :NW, :W, H)
207+
GR_e = _pepo_edge_expr(:GR, :NE, :SE, :E, H)
208+
ket_e, bra_e, pepo_es = _pepo_sandwich_expr(:O, H)
363209

364210
rhs = Expr(:call, :*, AC_e, Expr(:call, :conj, ĀC_e), GL_e, GR_e, ket_e, pepo_es...)
365211

src/algorithms/ctmrg/gaugefix.jl

+14-1
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,23 @@ end
5656

5757
# this is a bit of a hack to get the fixed point of the mixed transfer matrix
5858
# because MPSKit is not compatible with AD
59+
@generated function _transfer_right(
60+
v::AbstractTensorMap{<:Any,S,1,N₁},
61+
A::GenericMPSTensor{S,N₂},
62+
Abar::GenericMPSTensor{S,N₂},
63+
) where {S,N₁,N₂}
64+
t_out = tensorexpr(:v, -1, -(2:(N₁ + 1)))
65+
t_top = tensorexpr(:A, (-1, reverse(3:(N₂ + 1))...), 1)
66+
t_bot = tensorexpr(:Abar, (-(N₁ + 1), reverse(3:(N₂ + 1))...), 2)
67+
t_in = tensorexpr(:v, 1, (-(2:N₁)..., 2))
68+
return macroexpand(
69+
@__MODULE__, :(return @tensor $t_out := $t_top * conj($t_bot) * $t_in)
70+
)
71+
end
5972
function transfermatrix_fixedpoint(tops, bottoms, ρinit)
6073
_, vecs, info = eigsolve(ρinit, 1, :LM, Arnoldi()) do ρ
6174
return foldr(zip(tops, bottoms); init=ρ) do (top, bottom), ρ
62-
return @tensor ρ′[-1; -2] := top[-1 4 3; 1] * conj(bottom[-2 4 3; 2]) * ρ[1; 2]
75+
return _transfer_right(ρ, top, bottom)
6376
end
6477
end
6578
info.converged > 0 || @warn "eigsolve did not converge"

0 commit comments

Comments
 (0)