Skip to content

Commit 27734f5

Browse files
committed
Add double-layer-pepo reduced densitymatrix
1 parent df7a2c5 commit 27734f5

1 file changed

Lines changed: 100 additions & 2 deletions

File tree

src/algorithms/contractions/localoperator.jl

Lines changed: 100 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,58 @@ function _contract_state_expr(rowrange, colrange, cartesian_inds = nothing)
171171
end
172172
end
173173

174+
function _contract_pepo_state_expr(rowrange, colrange, cartesian_inds = nothing)
175+
rmin, rmax = extrema(rowrange)
176+
cmin, cmax = extrema(colrange)
177+
gridsize = (rmax - rmin + 1, cmax - cmin + 1)
178+
179+
return map((:bra, :ket)) do side
180+
return map(Iterators.product(1:gridsize[1], 1:gridsize[2])) do (i, j)
181+
inds_id = if isnothing(cartesian_inds)
182+
nothing
183+
else
184+
findfirst(==(CartesianIndex(rmin + i - 1, cmin + j - 1)), cartesian_inds)
185+
end
186+
physical_label_in = if isnothing(inds_id)
187+
physicallabel(side === :bra ? :in : :out, i, j)
188+
else
189+
physicallabel(:Oopen, inds_id)
190+
end
191+
physical_label_out = if isnothing(inds_id)
192+
physicallabel(side === :bra ? :in : :out, i, j)
193+
else
194+
physicallabel(:O, side, inds_id)
195+
end
196+
return tensorexpr(
197+
:($(side)[mod1($(rmin + i - 1), end), mod1($(cmin + j - 1), end)]),
198+
(physical_label_out, physical_label_in),
199+
(
200+
if i == 1
201+
virtuallabel(NORTH, side, j)
202+
else
203+
virtuallabel(:vertical, side, i - 1, j)
204+
end,
205+
if j == gridsize[2]
206+
virtuallabel(EAST, side, i)
207+
else
208+
virtuallabel(:horizontal, side, i, j)
209+
end,
210+
if i == gridsize[1]
211+
virtuallabel(SOUTH, side, j)
212+
else
213+
virtuallabel(:vertical, side, i, j)
214+
end,
215+
if j == 1
216+
virtuallabel(WEST, side, i)
217+
else
218+
virtuallabel(:horizontal, side, i, j - 1)
219+
end,
220+
),
221+
)
222+
end
223+
end
224+
end
225+
174226
@generated function _contract_local_operator(
175227
inds::NTuple{N, Val},
176228
O::AbstractTensorMap{T, S, N, N},
@@ -251,25 +303,40 @@ end
251303
return macroexpand(@__MODULE__, returnex)
252304
end
253305

254-
"""
306+
@doc """
255307
$(SIGNATURES)
256308
257309
Construct the reduced density matrix `ρ` of the PEPS `peps` with open indices `inds` using the environment `env`.
310+
Alternatively, construct the reduced density matrix `ρ` of a full density matrix PEPO with open indices `inds` using the environment `env`.
258311
259312
This works by generating the appropriate contraction on a rectangular patch with its corners
260313
specified by `inds`. The result is normalized such that `tr(ρ) = 1`.
261-
"""
314+
""" reduced_densitymatrix
315+
262316
function reduced_densitymatrix(
263317
inds::NTuple{N, CartesianIndex{2}}, ket::InfinitePEPS, bra::InfinitePEPS, env::CTMRGEnv
264318
) where {N}
265319
static_inds = Val.(inds)
266320
return _contract_densitymatrix(static_inds, ket, bra, env)
267321
end
322+
function reduced_densitymatrix(
323+
inds::NTuple{N, CartesianIndex{2}}, ket::InfinitePEPO, bra::InfinitePEPO, env::CTMRGEnv
324+
) where {N}
325+
size(ket) == size(bra) || throw(DimensionMismatch("incompatible bra and ket dimensions"))
326+
size(ket, 3) == 1 || throw(DimensionMismatch("only single-layer densitymatrices are supported"))
327+
static_inds = Val.(inds)
328+
return _contract_densitymatrix(static_inds, ket, bra, env)
329+
end
268330
function reduced_densitymatrix(
269331
inds::NTuple{N, Tuple{Int, Int}}, ket::InfinitePEPS, bra::InfinitePEPS, env::CTMRGEnv
270332
) where {N}
271333
return reduced_densitymatrix(CartesianIndex.(inds), ket, bra, env)
272334
end
335+
function reduced_densitymatrix(
336+
inds::NTuple{N, Tuple{Int, Int}}, ket::InfinitePEPO, bra::InfinitePEPO, env::CTMRGEnv
337+
) where {N}
338+
return reduced_densitymatrix(CartesianIndex.(inds), ket, bra, env)
339+
end
273340
function reduced_densitymatrix(inds, ket::InfinitePEPS, env::CTMRGEnv)
274341
return reduced_densitymatrix(inds, ket, ket, env)
275342
end
@@ -461,3 +528,34 @@ end
461528
return ρ / str(ρ)
462529
end
463530
end
531+
532+
@generated function _contract_densitymatrix(
533+
inds::NTuple{N, Val}, ket::InfinitePEPO, bra::InfinitePEPO, env::CTMRGEnv
534+
) where {N}
535+
cartesian_inds = collect(CartesianIndex{2}, map(x -> x.parameters[1], inds.parameters)) # weird hack to extract information from Val
536+
allunique(cartesian_inds) ||
537+
throw(ArgumentError("Indices should not overlap: $cartesian_inds."))
538+
rowrange = getindex.(cartesian_inds, 1)
539+
colrange = getindex.(cartesian_inds, 2)
540+
541+
corner_NW, corner_NE, corner_SE, corner_SW = _contract_corner_expr(rowrange, colrange)
542+
edges_N, edges_E, edges_S, edges_W = _contract_edge_expr(rowrange, colrange)
543+
result = tensorexpr(
544+
,
545+
ntuple(i -> physicallabel(:O, :ket, i), N),
546+
ntuple(i -> physicallabel(:O, :bra, i), N),
547+
)
548+
bra, ket = _contract_pepo_state_expr(rowrange, colrange, cartesian_inds)
549+
550+
multiplication_ex = Expr(
551+
:call, :*,
552+
corner_NW, corner_NE, corner_SE, corner_SW,
553+
edges_N..., edges_E..., edges_S..., edges_W...,
554+
ket..., map(x -> Expr(:call, :conj, x), bra)...,
555+
)
556+
multex = :(@autoopt @tensor contractcheck = true $result := $multiplication_ex)
557+
return quote
558+
$(macroexpand(@__MODULE__, multex))
559+
return ρ / str(ρ)
560+
end
561+
end

0 commit comments

Comments
 (0)