@@ -144,7 +144,7 @@ function _contract_state_expr(rowrange, colrange, cartesian_inds=nothing)
144144 physicallabel(:O, side, inds_id)
145145 end
146146 return tensorexpr(
147- :(bra [mod1($ (rmin + i - 1 ), end ), mod1($ (cmin + j - 1 ), end )]),
147+ :($ (side) [mod1($ (rmin + i - 1 ), end ), mod1($ (cmin + j - 1 ), end )]),
148148 (physical_label,),
149149 (
150150 if i == 1
212212 )
213213
214214 returnex = quote
215- @autoopt @tensor opt = $ multiplication_ex
215+ @autoopt @tensor $ multiplication_ex
216216 end
217217 return macroexpand(@__MODULE__, returnex)
218218end
@@ -266,7 +266,226 @@ end
266266 )
267267
268268 returnex = quote
269- @autoopt @tensor opt = $ multiplication_ex
269+ @autoopt @tensor $ multiplication_ex
270270 end
271271 return macroexpand(@__MODULE__, returnex)
272272end
273+
274+ """
275+ $(SIGNATURES)
276+
277+ Construct the reduced density matrix `ρ` of the PEPS `peps` with open indices `inds` using the environment `env`.
278+
279+ This works by generating the appropriate contraction on a rectangular patch with its corners
280+ specified by `inds`. The result is normalized such that `tr(ρ) = 1`.
281+ """
282+ function reduced_densitymatrix(
283+ inds:: NTuple{N,CartesianIndex{2}} , ket:: InfinitePEPS , bra:: InfinitePEPS , env:: CTMRGEnv
284+ ) where {N}
285+ static_inds = Val.(inds)
286+ return _contract_densitymatrix(static_inds, ket, bra, env)
287+ end
288+ function reduced_densitymatrix(
289+ inds:: NTuple{N,Tuple{Int,Int}} , ket:: InfinitePEPS , bra:: InfinitePEPS , env:: CTMRGEnv
290+ ) where {N}
291+ return reduced_densitymatrix(CartesianIndex.(inds), ket, bra, env)
292+ end
293+ function reduced_densitymatrix(inds, ket:: InfinitePEPS , env:: CTMRGEnv )
294+ return reduced_densitymatrix(inds, ket, ket, env)
295+ end
296+
297+ # Special case 1x1 density matrix:
298+ # Keep contraction order but try to optimize intermediate permutations:
299+ # EE_SWA is largest object so keep largest legs to the front there
300+ function reduced_densitymatrix(
301+ inds:: Tuple{CartesianIndex{2}} , ket:: InfinitePEPS , bra:: InfinitePEPS , env:: CTMRGEnv
302+ )
303+ row, col = Tuple(inds[1 ])
304+
305+ # Unpack variables and absorb corners
306+ A = ket[mod1(row, end ), mod1(col, end )]
307+ Ā = bra[mod1(row, end ), mod1(col, end )]
308+
309+ E_north =
310+ env. edges[NORTH, mod1(row - 1 , end ), mod1(col, end )] *
311+ twistdual(env. corners[NORTHEAST, mod1(row - 1 , end ), mod1(col + 1 , end )], 1 )
312+ E_east =
313+ env. edges[EAST, mod1(row, end ), mod1(col + 1 , end )] *
314+ twistdual(env. corners[SOUTHEAST, mod1(row + 1 , end ), mod1(col + 1 , end )], 1 )
315+ E_south =
316+ env. edges[SOUTH, mod1(row + 1 , end ), mod1(col, end )] *
317+ twistdual(env. corners[SOUTHWEST, mod1(row + 1 , end ), mod1(col - 1 , end )], 1 )
318+ E_west =
319+ env. edges[WEST, mod1(row, end ), mod1(col - 1 , end )] *
320+ twistdual(env. corners[NORTHWEST, mod1(row - 1 , end ), mod1(col - 1 , end )], 1 )
321+
322+ @tensor EE_SW[χSE χNW DSb DWb; DSt DWt] :=
323+ E_south[χSE DSt DSb; χSW] * E_west[χSW DWt DWb; χNW]
324+
325+ @tensor EE_SWA[χSE χNW DNt DEt; dt DSb DWb] :=
326+ EE_SW[χSE χNW DSb DWb; DSt DWt] * A[dt; DNt DEt DSt DWt]
327+
328+ @tensor EE_NE[DNb DEb; χSE χNW DNt DEt] :=
329+ E_north[χNW DNt DNb; χNE] * E_east[χNE DEt DEb; χSE]
330+
331+ @tensor EEAEE[dt; DNb DEb DSb DWb] :=
332+ EE_NE[DNb DEb; χSE χNW DNt DEt] * EE_SWA[χSE χNW DNt DEt; dt DSb DWb]
333+
334+ @tensor ρ[dt; db] := EEAEE[dt; DNb DEb DSb DWb] * conj(Ā[db; DNb DEb DSb DWb])
335+
336+ return ρ / str(ρ)
337+ end
338+
339+ function reduced_densitymatrix(
340+ inds:: NTuple{2,CartesianIndex{2}} , ket:: InfinitePEPS , bra:: InfinitePEPS , env:: CTMRGEnv
341+ )
342+ if inds[2 ] - inds[1 ] == CartesianIndex(1 , 0 )
343+ return reduced_densitymatrix2x1(inds[1 ], ket, bra, env)
344+ elseif inds[2 ] - inds[1 ] == CartesianIndex(0 , 1 )
345+ return reduced_densitymatrix1x2(inds[1 ], ket, bra, env)
346+ else
347+ static_inds = Val.(inds)
348+ return _contract_densitymatrix(static_inds, ket, bra, env)
349+ end
350+ end
351+
352+ # Special case 2x1 density matrix:
353+ # Keep contraction order but try to optimize intermediate permutations:
354+ function reduced_densitymatrix2x1(
355+ ind:: CartesianIndex , ket:: InfinitePEPS , bra:: InfinitePEPS , env:: CTMRGEnv
356+ )
357+ row, col = Tuple(ind)
358+
359+ # Unpack variables and absorb corners
360+ A_north = ket[mod1(row, end ), mod1(col, end )]
361+ Ā_north = bra[mod1(row, end ), mod1(col, end )]
362+ A_south = ket[mod1(row + 1 , end ), mod1(col, end )]
363+ Ā_south = bra[mod1(row + 1 , end ), mod1(col, end )]
364+
365+ E_north =
366+ env. edges[NORTH, mod1(row - 1 , end ), mod1(col, end )] *
367+ twistdual(env. corners[NORTHEAST, mod1(row - 1 , end ), mod1(col + 1 , end )], 1 )
368+ E_northeast = env. edges[EAST, mod1(row, end ), mod1(col + 1 , end )]
369+ E_southeast =
370+ env. edges[EAST, mod1(row + 1 , end ), mod1(col + 1 , end )] *
371+ twistdual(env. corners[SOUTHEAST, mod1(row + 2 , end ), mod1(col + 1 , end )], 1 )
372+ E_south =
373+ env. edges[SOUTH, mod1(row + 2 , end ), mod1(col, end )] *
374+ twistdual(env. corners[SOUTHWEST, mod1(row + 2 , end ), mod1(col - 1 , end )], 1 )
375+ E_southwest = env. edges[WEST, mod1(row + 1 , end ), mod1(col - 1 , end )]
376+ E_northwest =
377+ env. edges[WEST, mod1(row, end ), mod1(col - 1 , end )] *
378+ twistdual(env. corners[NORTHWEST, mod1(row - 1 , end ), mod1(col - 1 , end )], 1 )
379+
380+ @tensor EE_NW[χW χNE DNWt DNt; DNWb DNb] :=
381+ E_northwest[χW DNWt DNWb; χNW] * E_north[χNW DNt DNb; χNE]
382+ @tensor EEA_NW[χW DMb dNb χNE DNEb; DNWt DNt] :=
383+ EE_NW[χW χNE DNWt DNt; DNWb DNb] * conj(Ā_north[dNb; DNb DNEb DMb DNWb])
384+ @tensor EEAA_NW[χW DMb dNb dNt DMt; χNE DNEt DNEb] :=
385+ EEA_NW[χW DMb dNb χNE DNEb; DNWt DNt] * A_north[dNt; DNt DNEt DMt DNWt]
386+ @tensor EEEAA_N[dNt dNb; χW DMt DMb χE] :=
387+ EEAA_NW[χW DMb dNb dNt DMt; χNE DNEt DNEb] * E_northeast[χNE DNEt DNEb; χE]
388+
389+ @tensor EE_SE[χE χSW DSEt DSt; DSEb DSb] :=
390+ E_southeast[χE DSEt DSEb; χSE] * E_south[χSE DSt DSb; χSW]
391+ @tensor EEA_SE[χE DMb dSb χSW DSWb; DSEt DSt] :=
392+ EE_SE[χE χSW DSEt DSt; DSEb DSb] * conj(Ā_south[dSb; DMb DSEb DSb DSWb])
393+ @tensor EEAA_SE[χE DMb dSb dSt DMt; χSW DSWt DSWb] :=
394+ EEA_SE[χE DMb dSb χSW DSWb; DSEt DSt] * A_south[dSt; DMt DSEt DSt DSWt]
395+ @tensor EEEAA_S[χW DMt DMb χE; dSt dSb] :=
396+ EEAA_SE[χE DMb dSb dSt DMt; χSW DSWt DSWb] * E_southwest[χSW DSWt DSWb; χW]
397+
398+ @tensor ρ[dNt dSt; dNb dSb] :=
399+ EEEAA_N[dNt dNb; χW DMt DMb χE] * EEEAA_S[χW DMt DMb χE; dSt dSb]
400+
401+ return ρ / str(ρ)
402+ end
403+
404+ function reduced_densitymatrix1x2(
405+ ind:: CartesianIndex , ket:: InfinitePEPS , bra:: InfinitePEPS , env:: CTMRGEnv
406+ )
407+ row, col = Tuple(ind)
408+
409+ # Unpack variables and absorb corners
410+ A_west = ket[mod1(row, end ), mod1(col, end )]
411+ Ā_west = bra[mod1(row, end ), mod1(col, end )]
412+ A_east = ket[mod1(row, end ), mod1(col + 1 , end )]
413+ Ā_east = bra[mod1(row, end ), mod1(col + 1 , end )]
414+
415+ E_northwest = env. edges[NORTH, mod1(row - 1 , end ), mod1(col, end )]
416+ E_northeast =
417+ env. edges[NORTH, mod1(row - 1 , end ), mod1(col + 1 , end )] *
418+ twistdual(env. corners[NORTHEAST, mod1(row - 1 , end ), mod1(col + 2 , end )], 1 )
419+ E_east =
420+ env. edges[EAST, mod1(row, end ), mod1(col + 2 , end )] *
421+ twistdual(env. corners[SOUTHEAST, mod1(row + 1 , end ), mod1(col + 2 , end )], 1 )
422+ E_southeast = env. edges[SOUTH, mod1(row + 1 , end ), mod1(col + 1 , end )]
423+ E_southwest =
424+ env. edges[SOUTH, mod1(row + 1 , end ), mod1(col, end )] *
425+ twistdual(env. corners[SOUTHWEST, mod1(row + 1 , end ), mod1(col - 1 , end )], 1 )
426+ E_west =
427+ env. edges[WEST, mod1(row, end ), mod1(col - 1 , end )] *
428+ twistdual(env. corners[NORTHWEST, mod1(row - 1 , end ), mod1(col - 1 , end )], 1 )
429+
430+ @tensor EE_SW[χS χNW DSWt DWt; DSWb DWb] :=
431+ E_southwest[χS DSWt DSWb; χSW] * E_west[χSW DWt DWb; χNW]
432+ @tensor EEA_SW[χS DMb dWb χNW DNWb; DSWt DWt] :=
433+ EE_SW[χS χNW DSWt DWt; DSWb DWb] * conj(Ā_west[dWb; DNWb DMb DSWb DWb])
434+ @tensor EEAA_SW[χS DMb dWb dWt DMt; χNW DNWt DNWb] :=
435+ EEA_SW[χS DMb dWb χNW DNWb; DSWt DWt] * A_west[dWt; DNWt DMt DSWt DWt]
436+ @tensor EEEAA_W[dWt dWb; χS DMt DMb χN] :=
437+ EEAA_SW[χS DMb dWb dWt DMt; χNW DNWt DNWb] * E_northwest[χNW DNWt DNWb; χN]
438+
439+ @tensor EE_NE[χN χSE DNEt DEt; DNEb DEb] :=
440+ E_northeast[χN DNEt DNEb; χNE] * E_east[χNE DEt DEb; χSE]
441+ @tensor EEA_NE[χN DMb dEb χSE DSEb; DNEt DEt] :=
442+ EE_NE[χN χSE DNEt DEt; DNEb DEb] * conj(Ā_east[dEb; DNEb DEb DSEb DMb])
443+ @tensor EEAA_NE[χN DMb dEb dEt DMt; χSE DSEt DSEb] :=
444+ EEA_NE[χN DMb dEb χSE DSEb; DNEt DEt] * A_east[dEt; DNEt DEt DSEt DMt]
445+ @tensor EEEAA_E[χS DMt DMb χN; dEt dEb] :=
446+ EEAA_NE[χN DMb dEb dEt DMt; χSE DSEt DSEb] * E_southeast[χSE DSEt DSEb; χS]
447+
448+ @tensor ρ[dWt dEt; dWb dEb] :=
449+ EEEAA_W[dWt dWb; χS DMt DMb χN] * EEEAA_E[χS DMt DMb χN; dEt dEb]
450+
451+ return ρ / str(ρ)
452+ end
453+
454+ @generated function _contract_densitymatrix(
455+ inds:: NTuple{N,Val} , ket:: InfinitePEPS , bra:: InfinitePEPS , env:: CTMRGEnv
456+ ) where {N}
457+ cartesian_inds = collect(CartesianIndex{2 }, map(x -> x. parameters[1 ], inds. parameters)) # weird hack to extract information from Val
458+ allunique(cartesian_inds) ||
459+ throw(ArgumentError(" Indices should not overlap: $cartesian_inds ." ))
460+ rowrange = getindex.(cartesian_inds, 1 )
461+ colrange = getindex.(cartesian_inds, 2 )
462+
463+ corner_NW, corner_NE, corner_SE, corner_SW = _contract_corner_expr(rowrange, colrange)
464+ edges_N, edges_E, edges_S, edges_W = _contract_edge_expr(rowrange, colrange)
465+ result = tensorexpr(
466+ :ρ,
467+ ntuple(i -> physicallabel(:O, :ket, i), N),
468+ ntuple(i -> physicallabel(:O, :bra, i), N),
469+ )
470+ bra, ket = _contract_state_expr(rowrange, colrange, cartesian_inds)
471+
472+ multiplication_ex = Expr(
473+ :call,
474+ :* ,
475+ corner_NW,
476+ corner_NE,
477+ corner_SE,
478+ corner_SW,
479+ edges_N... ,
480+ edges_E... ,
481+ edges_S... ,
482+ edges_W... ,
483+ ket... ,
484+ map(x -> Expr(:call, :conj, x), bra). .. ,
485+ )
486+ multex = :(@autoopt @tensor $ result := $ multiplication_ex)
487+ return quote
488+ $ (macroexpand(@__MODULE__, multex))
489+ return ρ / str(ρ)
490+ end
491+ end
0 commit comments