Skip to content

Commit 16956d5

Browse files
Add correlation functions (#210)
--------- Co-authored-by: Lukas Devos <ldevos98@gmail.com>
1 parent 37ace4c commit 16956d5

4 files changed

Lines changed: 275 additions & 7 deletions

File tree

src/PEPSKit.jl

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,14 @@ using LinearAlgebra, Statistics, Base.Threads, Base.Iterators, Printf
44
using Compat
55
using Accessors: @set, @reset
66
using VectorInterface
7-
using TensorKit, KrylovKit, MPSKit, OptimKit, TensorOperations
7+
using TensorKit, KrylovKit, OptimKit, TensorOperations
88
using ChainRulesCore, Zygote
99
using LoggingExtras
10+
11+
using MPSKit
12+
using MPSKit: MPOTensor, GenericMPSTensor, MPSBondTensor, TransferMatrix
1013
import MPSKit: leading_boundary, loginit!, logiter!, logfinish!, logcancel!, physicalspace
14+
1115
using MPSKitModels
1216
using FiniteDifferences
1317
using OhMyThreads: tmap
@@ -65,6 +69,7 @@ include("algorithms/time_evolution/simpleupdate.jl")
6569
include("algorithms/time_evolution/simpleupdate3site.jl")
6670

6771
include("algorithms/toolbox.jl")
72+
include("algorithms/correlators.jl")
6873

6974
include("utility/symmetrization.jl")
7075

@@ -80,6 +85,7 @@ export CTMRGEnv, SequentialCTMRG, SimultaneousCTMRG
8085
export FixedSpaceTruncation, HalfInfiniteProjector, FullInfiniteProjector
8186
export LocalOperator, physicalspace
8287
export expectation_value, cost_function, product_peps, correlation_length, network_value
88+
export correlator
8389
export leading_boundary
8490
export PEPSOptimize, GeomSum, ManualIter, LinSolver, EigSolver
8591
export fixedpoint

src/algorithms/contractions/vumps_contractions.jl

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
using MPSKit: GenericMPSTensor, MPSBondTensor
2-
31
#
42
# Environment transfer functions
53
#
@@ -40,6 +38,21 @@ function _transfer_left(
4038
A[χ_NW D_N_above D_N_below; χ_NE]
4139
end
4240

41+
# transfer with excited GL
42+
function MPSKit.transfer_left(
43+
GL::GenericMPSTensor{S,4},
44+
O::PEPSSandwich,
45+
A::GenericMPSTensor{S,3},
46+
::GenericMPSTensor{S,3},
47+
) where {S}
48+
@autoopt @tensor GL′[χ_SE D_E_above d_string D_E_below; χ_NE] :=
49+
GL[χ_SW D_W_above d_string D_W_below; χ_NW] *
50+
conj(Ā[χ_SW D_S_above D_S_below; χ_SE]) *
51+
ket(O)[d; D_N_above D_E_above D_S_above D_W_above] *
52+
conj(bra(O)[d; D_N_below D_E_below D_S_below D_W_below]) *
53+
A[χ_NW D_N_above D_N_below; χ_NE]
54+
end
55+
4356
function _transfer_right(
4457
GR::GenericMPSTensor{S,3},
4558
O::PEPSSandwich,

src/algorithms/correlators.jl

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
function correlator_horizontal(
2+
bra::InfinitePEPS,
3+
operator,
4+
i::CartesianIndex{2},
5+
js::AbstractVector{CartesianIndex{2}},
6+
ket::InfinitePEPS,
7+
env::CTMRGEnv,
8+
)
9+
size(ket) == size(bra) ||
10+
throw(DimensionMismatch("The ket and bra must have the same unit cell."))
11+
all(==(i[1]) first Tuple, js) ||
12+
throw(ArgumentError("Not a horizontal correlation function"))
13+
issorted(vcat(i, js); by=last Tuple) ||
14+
throw(ArgumentError("Not an increasing sequence of coordinates"))
15+
16+
O = FiniteMPO(operator)
17+
length(O) == 2 || throw(ArgumentError("Operator must act on two sites"))
18+
19+
# preallocate with correct scalartype
20+
G = similar(
21+
js,
22+
TensorOperations.promote_contract(
23+
scalartype(bra), scalartype(ket), scalartype(env), scalartype.(O)...
24+
),
25+
)
26+
27+
# left start for operator and norm contractions
28+
Vn, Vo = start_correlator(i, bra, O[1], ket, env)
29+
i += CartesianIndex(0, 1)
30+
31+
for (k, j) in enumerate(js)
32+
# transfer until left of site j
33+
while j > i
34+
Atop = env.edges[NORTH, _prev(i[1], end), mod1(i[2], end)]
35+
Abot = env.edges[SOUTH, _next(i[1], end), mod1(i[2], end)]
36+
sandwich = (
37+
ket[mod1(i[1], end), mod1(i[2], end)], bra[mod1(i[1], end), mod1(i[2], end)]
38+
)
39+
T = TransferMatrix(Atop, sandwich, _dag(Abot))
40+
Vo = Vo * T
41+
Vn = Vn * T
42+
i += CartesianIndex(0, 1)
43+
end
44+
45+
# compute overlap with operator
46+
numerator = end_correlator_numerator(j, Vo, bra, O[2], ket, env)
47+
48+
# transfer right of site j
49+
Atop = env.edges[NORTH, _prev(i[1], end), mod1(i[2], end)]
50+
Abot = env.edges[SOUTH, _next(i[1], end), mod1(i[2], end)]
51+
sandwich = (
52+
ket[mod1(i[1], end), mod1(i[2], end)], bra[mod1(i[1], end), mod1(i[2], end)]
53+
)
54+
T = TransferMatrix(Atop, sandwich, _dag(Abot))
55+
Vo = Vo * T
56+
Vn = Vn * T
57+
i += CartesianIndex(0, 1)
58+
59+
# compute overlap without operator
60+
denominator = end_correlator_denominator(j, Vn, env)
61+
62+
G[k] = numerator / denominator
63+
end
64+
65+
return G
66+
end
67+
68+
function start_correlator(
69+
i::CartesianIndex{2},
70+
below::InfinitePEPS,
71+
O::MPOTensor,
72+
above::InfinitePEPS,
73+
env::CTMRGEnv,
74+
)
75+
r, c = Tuple(i)
76+
E_north = env.edges[NORTH, _prev(r, end), mod1(c, end)]
77+
E_south = env.edges[SOUTH, _next(r, end), mod1(c, end)]
78+
E_west = env.edges[WEST, mod1(r, end), _prev(c, end)]
79+
C_northwest = env.corners[NORTHWEST, _prev(r, end), _prev(c, end)]
80+
C_southwest = env.corners[SOUTHWEST, _next(r, end), _prev(c, end)]
81+
sandwich = (below[mod1(r, end), mod1(c, end)], above[mod1(r, end), mod1(c, end)])
82+
83+
# TODO: part of these contractions is duplicated between the two output tensors,
84+
# so could be optimized further
85+
@autoopt @tensor Vn[χSE Detop Debot; χNE] :=
86+
E_south[χSE Dstop Dsbot; χSW2] *
87+
C_southwest[χSW2; χSW] *
88+
E_west[χSW Dwtop Dwbot; χNW] *
89+
C_northwest[χNW; χN] *
90+
conj(bra(sandwich)[d; Dnbot Debot Dsbot Dwbot]) *
91+
ket(sandwich)[d; Dntop Detop Dstop Dwtop] *
92+
E_north[χN Dntop Dnbot; χNE]
93+
94+
@autoopt @tensor Vo[χSE Detop dstring Debot; χNE] :=
95+
E_south[χSE Dstop Dsbot; χSW2] *
96+
C_southwest[χSW2; χSW] *
97+
E_west[χSW Dwtop Dwbot; χNW] *
98+
C_northwest[χNW; χN] *
99+
conj(bra(sandwich)[d1; Dnbot Debot Dsbot Dwbot]) *
100+
removeunit(O, 1)[d1; d2 dstring] *
101+
ket(sandwich)[d2; Dntop Detop Dstop Dwtop] *
102+
E_north[χN Dntop Dnbot; χNE]
103+
104+
return Vn, Vo
105+
end
106+
107+
function end_correlator_numerator(
108+
j::CartesianIndex{2},
109+
V,
110+
above::InfinitePEPS,
111+
O::MPOTensor,
112+
below::InfinitePEPS,
113+
env::CTMRGEnv,
114+
)
115+
r, c = Tuple(j)
116+
E_north = env.edges[NORTH, _prev(r, end), mod1(c, end)]
117+
E_east = env.edges[EAST, mod1(r, end), _next(c, end)]
118+
E_south = env.edges[SOUTH, _next(r, end), mod1(c, end)]
119+
C_northeast = env.corners[NORTHEAST, _prev(r, end), _next(c, end)]
120+
C_southeast = env.corners[SOUTHEAST, _next(r, end), _next(c, end)]
121+
sandwich = (above[mod1(r, end), mod1(c, end)], below[mod1(r, end), mod1(c, end)])
122+
123+
return @autoopt @tensor contractcheck = true V[χSW DWt dstring DWb; χNW] *
124+
E_south[χSSE DSt DSb; χSW] *
125+
E_east[χNEE DEt DEb; χSEE] *
126+
E_north[χNW DNt DNb; χNNE] *
127+
C_northeast[χNNE; χNEE] *
128+
C_southeast[χSEE; χSSE] *
129+
conj(bra(sandwich)[db; DNb DEb DSb DWb]) *
130+
ket(sandwich)[dt; DNt DEt DSt DWt] *
131+
removeunit(O, 4)[dstring db; dt]
132+
end
133+
134+
function end_correlator_denominator(j::CartesianIndex{2}, V, env::CTMRGEnv)
135+
r, c = Tuple(j)
136+
C_northeast = env.corners[NORTHEAST, _prev(r, end), _next(c, end)]
137+
E_east = env.edges[EAST, mod1(r, end), _next(c, end)]
138+
C_southeast = env.corners[SOUTHEAST, _next(r, end), _next(c, end)]
139+
140+
return @autoopt @tensor V[χS DEt DEb; χN] *
141+
C_northeast[χN; χNE] *
142+
E_east[χNE DEt DEb; χSE] *
143+
C_southeast[χSE; χS]
144+
end
145+
146+
function correlator_vertical(
147+
bra::InfinitePEPS,
148+
O,
149+
i::CartesianIndex{2},
150+
js::AbstractVector{CartesianIndex{2}},
151+
ket::InfinitePEPS,
152+
env::CTMRGEnv,
153+
)
154+
rotated_bra = rotl90(bra)
155+
rotated_ket = bra === ket ? rotated_bra : rotl90(ket)
156+
157+
rotated_i = rotl90(i)
158+
rotated_j = map(rotl90, js)
159+
160+
return correlator_horizontal(
161+
rotated_bra, O, rotated_i, rotated_j, rotated_ket, rotl90(env)
162+
)
163+
end
164+
165+
const CoordCollection{N} = Union{AbstractVector{CartesianIndex{N}},CartesianIndices{N}}
166+
167+
function MPSKit.correlator(
168+
bra::InfinitePEPS,
169+
O,
170+
i::CartesianIndex{2},
171+
js::CoordCollection{2},
172+
ket::InfinitePEPS,
173+
env::CTMRGEnv,
174+
)
175+
js = vec(js) # map CartesianIndices to actual Vector instead of Matrix
176+
177+
if all(==(i[1]) first Tuple, js)
178+
return correlator_horizontal(bra, O, i, js, ket, env)
179+
elseif all(==(i[2]) last Tuple, js)
180+
return correlator_vertical(bra, O, i, js, ket, env)
181+
else
182+
error("Only horizontal or vertical correlators are implemented")
183+
end
184+
end
185+
186+
function MPSKit.correlator(
187+
bra::InfinitePEPS,
188+
O,
189+
i::CartesianIndex{2},
190+
j::CartesianIndex{2},
191+
ket::InfinitePEPS,
192+
env::CTMRGEnv,
193+
)
194+
return only(correlator(bra, O, i, j:j, ket, env))
195+
end
196+
197+
function MPSKit.correlator(state::InfinitePEPS, O, i::CartesianIndex{2}, j, env::CTMRGEnv)
198+
return MPSKit.correlator(state, O, i, j, state, env)
199+
end

test/examples/tf_ising.jl

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,62 @@ peps, env, E, = fixedpoint(H, peps₀, env₀; tol=gradtol)
3333

3434
# compute magnetization
3535
σx = TensorMap(scalartype(peps₀)[0 1; 1 0], ℂ^2, ℂ^2)
36-
M = LocalOperator(physicalspace(H), (CartesianIndex(1, 1),) => σx)
37-
magn = expectation_value(peps, M, env)
36+
σz = TensorMap(scalartype(peps₀)[1 0; 0 -1], ℂ^2, ℂ^2)
37+
Mx = LocalOperator(physicalspace(H), (CartesianIndex(1, 1),) => σx)
38+
Mz = LocalOperator(physicalspace(H), (CartesianIndex(1, 1),) => σz)
39+
magnx = expectation_value(peps, Mx, env)
40+
magnz = expectation_value(peps, Mz, env)
3841

3942
@test E e atol = 1e-2
40-
@test imag(magn) 0 atol = 1e-6
41-
@test abs(magn) mˣ atol = 5e-2
43+
@test imag(magnx) 0 atol = 1e-6
44+
@test abs(magnx) mˣ atol = 5e-2
45+
46+
# compute connected correlation functions
47+
corrh =
48+
correlator(
49+
peps, σz σz, CartesianIndex(1, 1), CartesianIndex(1, 2):CartesianIndex(1, 21), env
50+
) .- magnz^2
51+
corrv =
52+
correlator(
53+
peps, σz σz, CartesianIndex(1, 1), CartesianIndex(2, 1):CartesianIndex(21, 1), env
54+
) .- magnz^2
55+
56+
@test corrh[end] 0.0 atol = 1e-5
57+
@test 1 / log(corrh[18] / corrh[19]) ξ_h[1] atol = 2e-2 # test correlation length far away from short-range effects
58+
@test corrv[end] 0.0 atol = 1e-5
59+
@test 1 / log(corrv[18] / corrv[19]) ξ_v[1] atol = 3e-2 # test correlation length far away from short-range effects
60+
@test corrv corrh rtol = 1e-2
61+
62+
# compute weird geometries
63+
corrh_2 =
64+
correlator(
65+
peps,
66+
σz σz,
67+
CartesianIndex(3, 2),
68+
CartesianIndex(3, 3):CartesianIndex(1, 2):CartesianIndex(3, 7),
69+
env,
70+
) .- magnz^2
71+
@test corrh_2 corrh[1:2:5]
72+
corrv_2 =
73+
correlator(
74+
peps,
75+
σz σz,
76+
CartesianIndex(2, 3),
77+
CartesianIndex(3, 3):CartesianIndex(2, 1):CartesianIndex(7, 3),
78+
env,
79+
) .- magnz^2
80+
@test corrv_2 corrv[1:2:5]
81+
82+
# Change from specific values and distances to a range
83+
corrh_int =
84+
correlator(peps, σz σz, CartesianIndex(1, 1), CartesianIndex(1, 21), env) - magnz^2
85+
corrv_int =
86+
correlator(peps, σz σz, CartesianIndex(1, 1), CartesianIndex(21, 1), env) - magnz^2
87+
88+
@test corrh_int corrh[20]
89+
@test corrv_int corrv[20]
90+
91+
@test_broken correlator(peps, σz σz, CartesianIndex(1, 1), CartesianIndex(2, 2), env)
4292

4393
# find fixedpoint in polarized phase and compute correlations lengths
4494
H_polar = transverse_field_ising(InfiniteSquare(); g=4.5)

0 commit comments

Comments
 (0)