Skip to content

Commit 1d95d57

Browse files
lkdvosleburgel
andauthored
Add missing fermionic parity matrices (#174)
* Fix supertrace to trace in norm * Add `twistdual` * Fix fermionic boundarymps contractions * Add peps sandwich to mpo converter * Replace trace with planar contraction * Fix `@tensor` call * Generalize twist handling in VUMPS contractions a bit more * Avoid type piracy * Remove sandwich alias, just hardcode union * Add test --------- Co-authored-by: leburgel <lander.burgelman@ugent.be>
1 parent 962d7e0 commit 1d95d57

5 files changed

Lines changed: 135 additions & 13 deletions

File tree

src/algorithms/contractions/vumps_contractions.jl

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,29 @@ using MPSKit: GenericMPSTensor, MPSBondTensor
44
# Environment transfer functions
55
#
66

7+
function MPSKit.transfer_left(
8+
GL::GenericMPSTensor{S,N},
9+
O::Union{PEPSSandwich,PEPOSandwich},
10+
A::GenericMPSTensor{S,N},
11+
::GenericMPSTensor{S,N},
12+
) where {S,N}
13+
= twistdual(Ā, 2:N)
14+
return _transfer_left(GL, O, A, Ā)
15+
end
16+
17+
function MPSKit.transfer_right(
18+
GR::GenericMPSTensor{S,N},
19+
O::Union{PEPSSandwich,PEPOSandwich},
20+
A::GenericMPSTensor{S,N},
21+
::GenericMPSTensor{S,N},
22+
) where {S,N}
23+
= twistdual(Ā, 2:N)
24+
return _transfer_right(GR, O, A, Ā)
25+
end
26+
727
## PEPS
828

9-
function MPSKit.transfer_left(
29+
function _transfer_left(
1030
GL::GenericMPSTensor{S,3},
1131
O::PEPSSandwich,
1232
A::GenericMPSTensor{S,3},
@@ -20,7 +40,7 @@ function MPSKit.transfer_left(
2040
A[χ_NW D_N_above D_N_below; χ_NE]
2141
end
2242

23-
function MPSKit.transfer_right(
43+
function _transfer_right(
2444
GR::GenericMPSTensor{S,3},
2545
O::PEPSSandwich,
2646
A::GenericMPSTensor{S,3},
@@ -36,7 +56,7 @@ end
3656

3757
## PEPO
3858

39-
@generated function MPSKit.transfer_left(
59+
@generated function _transfer_left(
4060
GL::GenericMPSTensor{S,N},
4161
O::PEPOSandwich{H},
4262
A::GenericMPSTensor{S,N},
@@ -65,7 +85,7 @@ end
6585
return macroexpand(@__MODULE__, :(return @autoopt @tensor $GL´_e := $rhs))
6686
end
6787

68-
@generated function MPSKit.transfer_right(
88+
@generated function _transfer_right(
6989
GR::GenericMPSTensor{S,N},
7090
O::PEPOSandwich{H},
7191
A::GenericMPSTensor{S,N},
@@ -118,7 +138,14 @@ end
118138
# Derivative contractions
119139
#
120140

121-
@generated function MPSKit.∂C(
141+
function MPSKit.∂C(
142+
C::MPSBondTensor{S}, GL::GenericMPSTensor{S,N}, GR::GenericMPSTensor{S,N}
143+
) where {S,N}
144+
GL = twistdual(GL, 1)
145+
GR = twistdual(GR, numind(GR))
146+
return _∂C(C, GL, GR)
147+
end
148+
@generated function _∂C(
122149
C::MPSBondTensor{S}, GL::GenericMPSTensor{S,N}, GR::GenericMPSTensor{S,N}
123150
) where {S,N}
124151
C´_e = tensorexpr(:C´, -1, -2)
@@ -128,9 +155,20 @@ end
128155
return macroexpand(@__MODULE__, :(return @tensor $C´_e := $GL_e * $C_e * $GR_e))
129156
end
130157

158+
function MPSKit.∂AC(
159+
AC::GenericMPSTensor{S,N},
160+
O::Union{PEPSSandwich,PEPOSandwich},
161+
GL::GenericMPSTensor{S,N},
162+
GR::GenericMPSTensor{S,N},
163+
) where {S,N}
164+
GL = twistdual(GL, 1)
165+
GR = twistdual(GR, numind(GR))
166+
return _∂AC(AC, O, GL, GR)
167+
end
168+
131169
## PEPS
132170

133-
function MPSKit.∂AC(
171+
function _∂AC(
134172
AC::GenericMPSTensor{S,3},
135173
O::PEPSSandwich,
136174
GL::GenericMPSTensor{S,3},
@@ -162,7 +200,7 @@ end
162200

163201
## PEPO
164202

165-
@generated function MPSKit.∂AC(
203+
@generated function _∂AC(
166204
AC::GenericMPSTensor{S,N},
167205
O::PEPOSandwich{H},
168206
GL::GenericMPSTensor{S,N},

src/algorithms/toolbox.jl

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -142,12 +142,11 @@ environment `env`.
142142
"""
143143
function _contract_corners(ind::Tuple{Int,Int}, env::CTMRGEnv)
144144
r, c = ind
145-
return tr(
146-
env.corners[NORTHWEST, _prev(r, end), _prev(c, end)] *
147-
env.corners[NORTHEAST, _prev(r, end), c] *
148-
env.corners[SOUTHEAST, r, c] *
149-
env.corners[SOUTHWEST, r, _prev(c, end)],
150-
)
145+
C_NW = env.corners[NORTHWEST, _prev(r, end), _prev(c, end)]
146+
C_NE = env.corners[NORTHEAST, _prev(r, end), c]
147+
C_SE = env.corners[SOUTHEAST, r, c]
148+
C_SW = env.corners[SOUTHWEST, r, _prev(c, end)]
149+
return @tensor C_NW[1; 2] * C_NE[2; 3] * C_SE[3; 4] * C_SW[4; 1]
151150
end
152151

153152
"""

src/networks/local_sandwich.jl

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,39 @@ function virtualspace(O::PEPSSandwich, dir)
5555
return virtualspace(ket(O), dir) virtualspace(bra(O), dir)'
5656
end
5757

58+
# not overloading MPOTensor because that defines AbstractTensorMap{<:Any,S,2,2}(::PEPSTensor, ::PEPSTensor)
59+
# ie type piracy
60+
mpotensor(top::PEPSTensor) = mpotensor((top, top))
61+
function mpotensor((top, bot)::PEPSSandwich)
62+
@assert virtualspace(top, NORTH) == dual(virtualspace(top, SOUTH)) &&
63+
virtualspace(bot, NORTH) == dual(virtualspace(bot, SOUTH)) &&
64+
virtualspace(top, EAST) == dual(virtualspace(top, WEST)) &&
65+
virtualspace(bot, EAST) == dual(virtualspace(bot, WEST)) &&
66+
isdual(virtualspace(top, NORTH)) &&
67+
isdual(virtualspace(bot, NORTH)) &&
68+
isdual(virtualspace(top, EAST)) &&
69+
isdual(virtualspace(bot, EAST)) "Method not yet implemented for given virtual spaces"
70+
71+
F_west = isomorphism(
72+
storagetype(top),
73+
fuse(virtualspace(top, WEST), virtualspace(bot, WEST)'),
74+
virtualspace(top, WEST) virtualspace(bot, WEST)',
75+
)
76+
F_south = isomorphism(
77+
storagetype(top),
78+
fuse(virtualspace(top, SOUTH), virtualspace(bot, SOUTH)'),
79+
virtualspace(top, SOUTH) virtualspace(bot, SOUTH)',
80+
)
81+
@tensor O[west south; north east] :=
82+
top[phys; top_north top_east top_south top_west] *
83+
conj(bot[phys; bot_north bot_east bot_south bot_west]) *
84+
twist(F_west, 3)[west; top_west bot_west] *
85+
twist(F_south, 3)[south; top_south bot_south] *
86+
conj(F_west[east; top_east bot_east]) *
87+
conj(F_south[north; top_north bot_north])
88+
return O
89+
end
90+
5891
## PEPO
5992

6093
const PEPOSandwich{N,T<:PEPSTensor,P<:PEPOTensor} = Tuple{T,T,Vararg{P,N}}

src/utility/util.jl

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,22 @@ function absorb_s(u::AbstractTensorMap, s::DiagonalTensorMap, vh::AbstractTensor
102102
return u * sqrt_s, sqrt_s * vh
103103
end
104104

105+
"""
106+
twistdual(t::AbstractTensorMap, i)
107+
twistdual!(t::AbstractTensorMap, i)
108+
109+
Twist the i-th leg of a tensor `t` if it represents a dual space.
110+
"""
111+
function twistdual!(t::AbstractTensorMap, i::Int)
112+
isdual(space(t, i)) || return t
113+
return twist!(t, i)
114+
end
115+
function twistdual!(t::AbstractTensorMap, is)
116+
is′ = filter(i -> isdual(space(t, i)), is)
117+
return twist!(t, is′)
118+
end
119+
twistdual(t::AbstractTensorMap, is) = twistdual!(copy(t), is)
120+
105121
# Check whether diagonals contain degenerate values up to absolute or relative tolerance
106122
function is_degenerate_spectrum(
107123
S; atol::Real=0, rtol::Real=atol > 0 ? 0 : sqrt(eps(scalartype(S)))

test/boundarymps/vumps.jl

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ using LinearAlgebra
88
Random.seed!(29384293742893)
99

1010
const vumps_alg = VUMPS(; alg_eigsolve=MPSKit.Defaults.alg_eigsolve(; ishermitian=false))
11+
1112
@testset "(1, 1) PEPS" begin
1213
psi = InfinitePEPS(ComplexSpace(2), ComplexSpace(2))
1314

@@ -37,6 +38,41 @@ end
3738
@test N N´ rtol = 1e-2
3839
end
3940

41+
@testset "Fermionic PEPS" begin
42+
D = Vect[fℤ₂](0 => 1, 1 => 1)
43+
d = Vect[fℤ₂](0 => 1, 1 => 1)
44+
χ = Vect[fℤ₂](0 => 10, 1 => 10)
45+
46+
psi = InfinitePEPS(D, d; unitcell=(1, 1))
47+
n = InfiniteSquareNetwork(psi)
48+
T = PEPSKit.InfiniteTransferPEPS(psi, 1, 1)
49+
50+
# compare boundary MPS contraction to CTMRG contraction
51+
mps = PEPSKit.initializeMPS(T, [χ])
52+
mps, env, ϵ = leading_boundary(mps, T, vumps_alg)
53+
N_vumps = abs(prod(expectation_value(mps, T)))
54+
55+
ctm, = leading_boundary(CTMRGEnv(psi, χ), psi)
56+
N_ctm = abs(norm(psi, ctm))
57+
58+
@test N_vumps N_ctm rtol = 1e-2
59+
60+
# and again after blocking the local sandwiches
61+
= InfiniteSquareNetwork(map(PEPSKit.mpotensor, PEPSKit.unitcell(n)))
62+
= InfiniteMPO(map(PEPSKit.mpotensor, T.O))
63+
64+
mps´ = InfiniteMPS(randn, ComplexF64, [physicalspace(T´, 1)], [χ])
65+
mps´, env´, ϵ = leading_boundary(mps´, T´, vumps_alg)
66+
N_vumps´ = abs(prod(expectation_value(mps´, T´)))
67+
68+
ctm´, = leading_boundary(CTMRGEnv(n´, χ), n´)
69+
N_ctm´ = abs(network_value(n´, ctm´))
70+
71+
@show N_vumps´
72+
@test N_vumps´ N_vumps rtol = 1e-2
73+
@test N_vumps´ N_ctm´ rtol = 1e-2
74+
end
75+
4076
@testset "PEPO runthrough" begin
4177
function ising_pepo(beta; unitcell=(1, 1, 1))
4278
t = ComplexF64[exp(beta) exp(-beta); exp(-beta) exp(beta)]

0 commit comments

Comments
 (0)