From 1d3a573ed4dfdd743f3cfb086d6ec45920fd2384 Mon Sep 17 00:00:00 2001 From: Yue Zhengyuan Date: Wed, 1 Jul 2026 12:02:03 +0800 Subject: [PATCH 01/13] Clean up correlators --- .../contractions/correlator/pepo_1layer.jl | 6 +- .../contractions/correlator/peps.jl | 6 +- src/algorithms/correlators.jl | 97 ++++++------------- src/algorithms/transfermatrix.jl | 21 +++- 4 files changed, 58 insertions(+), 72 deletions(-) diff --git a/src/algorithms/contractions/correlator/pepo_1layer.jl b/src/algorithms/contractions/correlator/pepo_1layer.jl index 580f271d7..6fcae3b4e 100644 --- a/src/algorithms/contractions/correlator/pepo_1layer.jl +++ b/src/algorithms/contractions/correlator/pepo_1layer.jl @@ -1,4 +1,4 @@ -function start_correlator( +function start_correlator_left( i::CartesianIndex{2}, ρ::InfinitePEPO, O::PFTensor, env::CTMRGEnv ) @@ -25,7 +25,7 @@ function start_correlator( return Vn, Vo end -function end_correlator_numerator( +function end_correlator_right_numerator( j::CartesianIndex{2}, V::CTMRGEdgeTensor{T, S, 3}, ρ::InfinitePEPO, O::PFTensor, env::CTMRGEnv ) where {T, S} @@ -44,7 +44,7 @@ function end_correlator_numerator( t[d1 d2; DN DE DS DW] * removeunit(O, 4)[dstring d2; d1] end -function end_correlator_denominator( +function end_correlator_right_denominator( j::CartesianIndex{2}, V::CTMRGEdgeTensor{T, S, 2}, env::CTMRGEnv ) where {T, S} r, c = Tuple(j) diff --git a/src/algorithms/contractions/correlator/peps.jl b/src/algorithms/contractions/correlator/peps.jl index fafdd938a..974d1ad2a 100644 --- a/src/algorithms/contractions/correlator/peps.jl +++ b/src/algorithms/contractions/correlator/peps.jl @@ -1,4 +1,4 @@ -function start_correlator( +function start_correlator_left( i::CartesianIndex{2}, below::InfinitePEPS, O::MPOTensor, @@ -37,7 +37,7 @@ function start_correlator( return Vn, Vo end -function end_correlator_numerator( +function end_correlator_right_numerator( j::CartesianIndex{2}, V::AbstractTensorMap{T, S, 4, 1}, above::InfinitePEPS, @@ -64,7 +64,7 @@ function end_correlator_numerator( removeunit(O, 4)[dstring db; dt] end -function end_correlator_denominator( +function end_correlator_right_denominator( j::CartesianIndex{2}, V::AbstractTensorMap{T, S, 3, 1}, env::CTMRGEnv ) where {T, S} diff --git a/src/algorithms/correlators.jl b/src/algorithms/correlators.jl index 0c95723b6..8ec7e5d0f 100644 --- a/src/algorithms/correlators.jl +++ b/src/algorithms/correlators.jl @@ -1,8 +1,6 @@ -const CoordCollection{N} = Union{AbstractVector{CartesianIndex{N}}, CartesianIndices{N}} - # Correlators in InfinitePEPS -function correlator_horizontal( +function _correlator_horizontal_pos( bra::InfinitePEPS, operator, i::CartesianIndex{2}, js::AbstractVector{CartesianIndex{2}}, @@ -11,52 +9,33 @@ function correlator_horizontal( ) size(ket) == size(bra) || throw(DimensionMismatch("The ket and bra must have the same unit cell.")) - all(==(i[1]) ∘ first ∘ Tuple, js) || - throw(ArgumentError("Not a horizontal correlation function")) - issorted(vcat(i, js); by = last ∘ Tuple) || - throw(ArgumentError("Not an increasing sequence of coordinates")) + _issorted_correlator_sites(i, js) O = FiniteMPO(operator) length(O) == 2 || throw(ArgumentError("Operator must act on two sites")) - # preallocate with correct scalartype - G = similar( - js, - TensorOperations.promote_contract( - scalartype(bra), scalartype(ket), scalartype(env), scalartype.(O)... - ), - ) # left start for operator and norm contractions - Vn, Vo = start_correlator(i, bra, O[1], ket, env) + Vn, Vo = start_correlator_left(i, bra, O[1], ket, env) i += CartesianIndex(0, 1) - for (k, j) in enumerate(js) + return map(enumerate(js)) do (k, j) # transfer until left of site j while j > i - Etop = edge(env, NORTH, i[1] - 1, i[2]) - Ebot = edge(env, SOUTH, i[1] + 1, i[2]) - sandwich = ( - ket[mod1(i[1], end), mod1(i[2], end)], bra[mod1(i[1], end), mod1(i[2], end)], - ) - T = edge_transfermatrix(Etop, sandwich, Ebot) + T = _edge_transfermatrix(i[1], i[2], bra, ket, env) Vo = Vo * T Vn = Vn * T i += CartesianIndex(0, 1) end # compute overlap with operator - numerator = end_correlator_numerator(j, Vo, bra, O[2], ket, env) + numerator = end_correlator_right_numerator(j, Vo, bra, O[2], ket, env) # transfer right of site j - Etop = edge(env, NORTH, i[1] - 1, i[2]) - Ebot = edge(env, SOUTH, i[1] + 1, i[2]) - sandwich = (ket[i[1], i[2]], bra[i[1], i[2]]) - T = edge_transfermatrix(Etop, sandwich, Ebot) + T = _edge_transfermatrix(i[1], i[2], bra, ket, env) if k < length(js) Vo = Vo * T end Vn = Vn * T i += CartesianIndex(0, 1) # compute overlap without operator - denominator = end_correlator_denominator(j, Vn, env) - G[k] = numerator / denominator + denominator = end_correlator_right_denominator(j, Vn, env) + return numerator / denominator end - return G end function correlator_vertical( @@ -70,7 +49,7 @@ function correlator_vertical( rotated_ket = bra === ket ? rotated_bra : rotl90(ket) rotated_i = siterotl90(i, size(bra)) rotated_js = map(j -> siterotl90(j, size(bra)), js) - return correlator_horizontal( + return _correlator_horizontal_pos( rotated_bra, operator, rotated_i, rotated_js, rotated_ket, rotl90(env) ) end @@ -78,14 +57,12 @@ end function MPSKit.correlator( bra::InfinitePEPS, O, - i::CartesianIndex{2}, js::CoordCollection{2}, + i::CartesianIndex{2}, js::AbstractVector{CartesianIndex{2}}, ket::InfinitePEPS, env::CTMRGEnv, ) - js = vec(js) # map CartesianIndices to actual Vector instead of Matrix - if all(==(i[1]) ∘ first ∘ Tuple, js) - return correlator_horizontal(bra, O, i, js, ket, env) + return _correlator_horizontal_pos(bra, O, i, js, ket, env) elseif all(==(i[2]) ∘ last ∘ Tuple, js) return correlator_vertical(bra, O, i, js, ket, env) else @@ -103,63 +80,47 @@ function MPSKit.correlator( return only(correlator(bra, O, i, j:j, ket, env)) end +## reserved for InfinitePEPS function MPSKit.correlator(state::InfinitePEPS, O, i::CartesianIndex{2}, j, env::CTMRGEnv) return MPSKit.correlator(state, O, i, j, state, env) end # Correlators in InfinitePEPO (tr(ρO)) -function correlator_horizontal( +function _correlator_horizontal_pos( ρ::InfinitePEPO, operator, i::CartesianIndex{2}, js::AbstractVector{CartesianIndex{2}}, env::CTMRGEnv ) (size(ρ, 3) == 1) || throw(ArgumentError("The input PEPO ρ must have only one layer.")) - all(==(i[1]) ∘ first ∘ Tuple, js) || - throw(ArgumentError("Not a horizontal correlation function")) - issorted(vcat(i, js); by = last ∘ Tuple) || - throw(ArgumentError("Not an increasing sequence of coordinates")) + _issorted_correlator_sites(i, js) O = FiniteMPO(operator) length(O) == 2 || throw(ArgumentError("Operator must act on two sites")) - # preallocate with correct scalartype - G = similar( - js, - TensorOperations.promote_contract( - scalartype(ρ), scalartype(env), scalartype.(O)... - ), - ) # left start for operator and norm contractions - Vn, Vo = start_correlator(i, ρ, O[1], env) + Vn, Vo = start_correlator_left(i, ρ, O[1], env) i += CartesianIndex(0, 1) - for (k, j) in enumerate(js) + return map(enumerate(js)) do (k, j) # transfer until left of site j while j > i - Etop = edge(env, NORTH, i[1] - 1, i[2]) - Omid = trace_physicalspaces(ρ[i[1], i[2]]) - Ebot = edge(env, SOUTH, i[1] + 1, i[2]) - T = edge_transfermatrix(Etop, Omid, Ebot) + T = _edge_transfermatrix(i[1], i[2], ρ, env) Vo = Vo * T Vn = Vn * T i += CartesianIndex(0, 1) end # compute overlap with operator - numerator = end_correlator_numerator(j, Vo, ρ, O[2], env) + numerator = end_correlator_right_numerator(j, Vo, ρ, O[2], env) # transfer right of site j - Etop = edge(env, NORTH, i[1] - 1, i[2]) - Omid = trace_physicalspaces(ρ[mod1(i[1], end), mod1(i[2], end)]) - Ebot = edge(env, SOUTH, i[1] + 1, i[2]) - T = edge_transfermatrix(Etop, Omid, Ebot) + T = _edge_transfermatrix(i[1], i[2], ρ, env) if k < length(js) Vo = Vo * T end Vn = Vn * T i += CartesianIndex(0, 1) # compute overlap without operator - denominator = end_correlator_denominator(j, Vn, env) - G[k] = numerator / denominator + denominator = end_correlator_right_denominator(j, Vn, env) + return numerator / denominator end - return G end function correlator_vertical( @@ -171,19 +132,18 @@ function correlator_vertical( unitcell = size(ρ)[1:2] rotated_i = siterotl90(i, unitcell) rotated_js = map(j -> siterotl90(j, unitcell), js) - return correlator_horizontal( + return _correlator_horizontal_pos( rotated_ρ, operator, rotated_i, rotated_js, rotl90(env) ) end function MPSKit.correlator( ρ::InfinitePEPO, O, - i::CartesianIndex{2}, js::CoordCollection{2}, + i::CartesianIndex{2}, js::AbstractVector{CartesianIndex{2}}, env::CTMRGEnv, ) - js = vec(js) # map CartesianIndices to Vector instead of Matrix if all(==(i[1]) ∘ first ∘ Tuple, js) - return correlator_horizontal(ρ, O, i, js, env) + return _correlator_horizontal_pos(ρ, O, i, js, env) elseif all(==(i[2]) ∘ last ∘ Tuple, js) return correlator_vertical(ρ, O, i, js, env) else @@ -200,3 +160,10 @@ function MPSKit.correlator( end # TODO: Correlators in InfinitePEPO (⟨ρ|O|ρ⟩) + +# utility functions + +function _issorted_correlator_sites(i::CartesianIndex{2}, js::AbstractVector{CartesianIndex{2}}) + return issorted(vcat(i, js); by = last ∘ Tuple) || + throw(ArgumentError("Not an increasing sequence of coordinates")) +end diff --git a/src/algorithms/transfermatrix.jl b/src/algorithms/transfermatrix.jl index 354d3fe73..2b1d0edd9 100644 --- a/src/algorithms/transfermatrix.jl +++ b/src/algorithms/transfermatrix.jl @@ -12,7 +12,7 @@ end Base.:*(tm1::T, tm2::T) where {T <: EdgeTransferMatrix} = ProductTransferMatrix([tm1, tm2]) -# TODO: really not sure it TensorKit.flip is the suitable method for this... +# TODO: really not sure if TensorKit.flip is the suitable method for this... function TensorKit.flip(tm::EdgeTransferMatrix) return EdgeTransferMatrix(tm.top, tm.mid, tm.bot, !tm.isflipped) end @@ -36,3 +36,22 @@ function edge_transfermatrix(a::AbstractVector, b, c::AbstractVector, isflipped tot = ProductTransferMatrix(convert(Vector, edge_transfermatrix.(a, b, c))) return isflipped ? flip(tot) : tot end + +function _edge_transfermatrix( + row::Int, col::Int, + bra::InfinitePEPS, ket::InfinitePEPS, env::CTMRGEnv + ) + Etop = edge(env, NORTH, row - 1, col) + Ebot = edge(env, SOUTH, row + 1, col) + sandwich = (ket[row, col], bra[row, col]) + return edge_transfermatrix(Etop, sandwich, Ebot) +end + +function _edge_transfermatrix( + row::Int, col::Int, ρ::InfinitePEPO, env::CTMRGEnv + ) + Etop = edge(env, NORTH, row - 1, col) + Ebot = edge(env, SOUTH, row + 1, col) + Omid = trace_physicalspaces(ρ[row, col]) + return edge_transfermatrix(Etop, Omid, Ebot) +end From 98e96386461b2feac1c8921261bb3bcc54526725 Mon Sep 17 00:00:00 2001 From: Yue Zhengyuan Date: Wed, 1 Jul 2026 13:37:44 +0800 Subject: [PATCH 02/13] Refactor correlator functions for improved clarity --- src/algorithms/correlators.jl | 54 ++++++++++++++--------------------- test/utility/correlator.jl | 5 ++-- 2 files changed, 24 insertions(+), 35 deletions(-) diff --git a/src/algorithms/correlators.jl b/src/algorithms/correlators.jl index 8ec7e5d0f..f0764e25b 100644 --- a/src/algorithms/correlators.jl +++ b/src/algorithms/correlators.jl @@ -13,25 +13,20 @@ function _correlator_horizontal_pos( O = FiniteMPO(operator) length(O) == 2 || throw(ArgumentError("Operator must act on two sites")) # left start for operator and norm contractions - Vn, Vo = start_correlator_left(i, bra, O[1], ket, env) - i += CartesianIndex(0, 1) + c = i # current column being handled + Vn, Vo = start_correlator_left(c, bra, O[1], ket, env) + j_last = last(js) return map(enumerate(js)) do (k, j) - # transfer until left of site j - while j > i - T = _edge_transfermatrix(i[1], i[2], bra, ket, env) - Vo = Vo * T + local numerator + while j > c + c += CartesianIndex(0, 1) + if c == j + numerator = end_correlator_right_numerator(j, Vo, bra, O[2], ket, env) + end + T = _edge_transfermatrix(c[1], c[2], bra, ket, env) + c != j_last && (Vo = Vo * T) Vn = Vn * T - i += CartesianIndex(0, 1) end - # compute overlap with operator - numerator = end_correlator_right_numerator(j, Vo, bra, O[2], ket, env) - # transfer right of site j - T = _edge_transfermatrix(i[1], i[2], bra, ket, env) - if k < length(js) - Vo = Vo * T - end - Vn = Vn * T - i += CartesianIndex(0, 1) # compute overlap without operator denominator = end_correlator_right_denominator(j, Vn, env) return numerator / denominator @@ -98,25 +93,20 @@ function _correlator_horizontal_pos( O = FiniteMPO(operator) length(O) == 2 || throw(ArgumentError("Operator must act on two sites")) # left start for operator and norm contractions - Vn, Vo = start_correlator_left(i, ρ, O[1], env) - i += CartesianIndex(0, 1) + c = i # current column being handled + Vn, Vo = start_correlator_left(c, ρ, O[1], env) + j_last = last(js) return map(enumerate(js)) do (k, j) - # transfer until left of site j - while j > i - T = _edge_transfermatrix(i[1], i[2], ρ, env) - Vo = Vo * T + local numerator + while j > c + c += CartesianIndex(0, 1) + if c == j + numerator = end_correlator_right_numerator(j, Vo, ρ, O[2], env) + end + T = _edge_transfermatrix(c[1], c[2], ρ, env) + c != j_last && (Vo = Vo * T) Vn = Vn * T - i += CartesianIndex(0, 1) - end - # compute overlap with operator - numerator = end_correlator_right_numerator(j, Vo, ρ, O[2], env) - # transfer right of site j - T = _edge_transfermatrix(i[1], i[2], ρ, env) - if k < length(js) - Vo = Vo * T end - Vn = Vn * T - i += CartesianIndex(0, 1) # compute overlap without operator denominator = end_correlator_right_denominator(j, Vn, env) return numerator / denominator diff --git a/test/utility/correlator.jl b/test/utility/correlator.jl index 766457c23..4fe8a958f 100644 --- a/test/utility/correlator.jl +++ b/test/utility/correlator.jl @@ -17,9 +17,8 @@ function get_spaces(sym::Type{<:Sector}) end site0 = CartesianIndex(1, 1) -maxsep = 6 -site1xs = collect(site0 + CartesianIndex(0, i) for i in 2:2:maxsep) -site1ys = collect(site0 + CartesianIndex(i, 0) for i in 2:2:maxsep) +site1xs = collect(site0 + CartesianIndex(0, i) for i in [1, 3, 4]) +site1ys = collect(site0 + CartesianIndex(i, 0) for i in [1, 3, 4]) @testset "Correlator in InfinitePEPS ($(sym))" for sym in syms Random.seed!(100) From 8eda2c7619c2c9286c3b25bdcf1c8735136fc905 Mon Sep 17 00:00:00 2001 From: Yue Zhengyuan Date: Wed, 1 Jul 2026 13:57:40 +0800 Subject: [PATCH 03/13] Remove unused variable --- src/algorithms/correlators.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/algorithms/correlators.jl b/src/algorithms/correlators.jl index f0764e25b..d3bbf06ae 100644 --- a/src/algorithms/correlators.jl +++ b/src/algorithms/correlators.jl @@ -16,7 +16,7 @@ function _correlator_horizontal_pos( c = i # current column being handled Vn, Vo = start_correlator_left(c, bra, O[1], ket, env) j_last = last(js) - return map(enumerate(js)) do (k, j) + return map(enumerate(js)) do (_, j) local numerator while j > c c += CartesianIndex(0, 1) @@ -96,7 +96,7 @@ function _correlator_horizontal_pos( c = i # current column being handled Vn, Vo = start_correlator_left(c, ρ, O[1], env) j_last = last(js) - return map(enumerate(js)) do (k, j) + return map(enumerate(js)) do (_, j) local numerator while j > c c += CartesianIndex(0, 1) From ade3d97d96e88ec0adc6328d980bd28dd87a34fa Mon Sep 17 00:00:00 2001 From: Yue Zhengyuan Date: Wed, 1 Jul 2026 14:27:03 +0800 Subject: [PATCH 04/13] Revert to pre-allocation approach --- src/algorithms/correlators.jl | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/algorithms/correlators.jl b/src/algorithms/correlators.jl index d3bbf06ae..5ef94dd00 100644 --- a/src/algorithms/correlators.jl +++ b/src/algorithms/correlators.jl @@ -12,11 +12,17 @@ function _correlator_horizontal_pos( _issorted_correlator_sites(i, js) O = FiniteMPO(operator) length(O) == 2 || throw(ArgumentError("Operator must act on two sites")) + # preallocate with correct scalartype + G = similar( + js, TensorOperations.promote_contract( + scalartype(bra), scalartype(ket), scalartype(env), scalartype.(O)... + ), + ) # left start for operator and norm contractions c = i # current column being handled Vn, Vo = start_correlator_left(c, bra, O[1], ket, env) j_last = last(js) - return map(enumerate(js)) do (_, j) + for (k, j) in enumerate(js) local numerator while j > c c += CartesianIndex(0, 1) @@ -29,8 +35,9 @@ function _correlator_horizontal_pos( end # compute overlap without operator denominator = end_correlator_right_denominator(j, Vn, env) - return numerator / denominator + G[k] = numerator / denominator end + return G end function correlator_vertical( @@ -92,11 +99,17 @@ function _correlator_horizontal_pos( _issorted_correlator_sites(i, js) O = FiniteMPO(operator) length(O) == 2 || throw(ArgumentError("Operator must act on two sites")) + # preallocate with correct scalartype + G = similar( + js, TensorOperations.promote_contract( + scalartype(ρ), scalartype(env), scalartype.(O)... + ), + ) # left start for operator and norm contractions c = i # current column being handled Vn, Vo = start_correlator_left(c, ρ, O[1], env) j_last = last(js) - return map(enumerate(js)) do (_, j) + for (k, j) in enumerate(js) local numerator while j > c c += CartesianIndex(0, 1) @@ -109,8 +122,9 @@ function _correlator_horizontal_pos( end # compute overlap without operator denominator = end_correlator_right_denominator(j, Vn, env) - return numerator / denominator + G[k] = numerator / denominator end + return G end function correlator_vertical( From f34032c9d74105d04767ed9e6bc7512219c726ea Mon Sep 17 00:00:00 2001 From: Yue Zhengyuan Date: Wed, 1 Jul 2026 17:02:15 +0800 Subject: [PATCH 05/13] Add correlator adapters to deduplicate --- src/PEPSKit.jl | 1 + src/algorithms/correlator_adapters.jl | 143 ++++++++++++++++++++++++++ src/algorithms/correlators.jl | 137 ++---------------------- 3 files changed, 150 insertions(+), 131 deletions(-) create mode 100644 src/algorithms/correlator_adapters.jl diff --git a/src/PEPSKit.jl b/src/PEPSKit.jl index a6e199c54..4035d099e 100644 --- a/src/PEPSKit.jl +++ b/src/PEPSKit.jl @@ -126,6 +126,7 @@ include("algorithms/bp/gaugefix.jl") include("algorithms/transfermatrix.jl") include("algorithms/toolbox.jl") +include("algorithms/correlator_adapters.jl") include("algorithms/correlators.jl") include("algorithms/optimization/fixed_point_differentiation.jl") diff --git a/src/algorithms/correlator_adapters.jl b/src/algorithms/correlator_adapters.jl new file mode 100644 index 000000000..fb3bba0a7 --- /dev/null +++ b/src/algorithms/correlator_adapters.jl @@ -0,0 +1,143 @@ +# Correlator adapters for InfinitePEPS / InfinitePEPO + +struct _PEPSCorrelator{B <: InfinitePEPS, K <: InfinitePEPS, E <: CTMRGEnv} + bra::B + ket::K + env::E + + function _PEPSCorrelator(bra::B, ket::K, env::E) where {B, K, E} + size(ket) == size(bra) || + throw(DimensionMismatch("The ket and bra must have the same unit cell.")) + return new{B, K, E}(bra, ket, env) + end +end + +struct _PEPOTraceCorrelator{P <: InfinitePEPO, E <: CTMRGEnv} + ρ::P + env::E + + function _PEPOTraceCorrelator(ρ::P, env::E) where {P, E} + (size(ρ, 3) == 1) || + throw(ArgumentError("The input PEPO ρ must have only one layer.")) + return new{P, E}(ρ, env) + end +end + +function _correlator_scalartype(context::_PEPSCorrelator, O::FiniteMPO) + return TensorOperations.promote_contract( + scalartype(context.bra), scalartype(context.ket), + scalartype(context.env), scalartype.(O)... + ) +end + +function _correlator_scalartype(context::_PEPOTraceCorrelator, O::FiniteMPO) + return TensorOperations.promote_contract( + scalartype(context.ρ), scalartype(context.env), scalartype.(O)... + ) +end + +_correlator_unitcell(context::_PEPSCorrelator) = size(context.bra) +_correlator_unitcell(context::_PEPOTraceCorrelator) = size(context.ρ)[1:2] + +function Base.rotl90(context::_PEPSCorrelator) + rotated_bra = rotl90(context.bra) + rotated_ket = context.bra === context.ket ? rotated_bra : rotl90(context.ket) + return _PEPSCorrelator(rotated_bra, rotated_ket, rotl90(context.env)) +end + +Base.rotl90(context::_PEPOTraceCorrelator) = + _PEPOTraceCorrelator(rotl90(context.ρ), rotl90(context.env)) + +function _start_correlator_left( + i::CartesianIndex{2}, context::_PEPSCorrelator, O::MPOTensor + ) + return start_correlator_left(i, context.bra, O, context.ket, context.env) +end + +function _start_correlator_left( + i::CartesianIndex{2}, context::_PEPOTraceCorrelator, O::PFTensor + ) + return start_correlator_left(i, context.ρ, O, context.env) +end + +function _end_correlator_right_numerator( + j::CartesianIndex{2}, + V::AbstractTensorMap{T, S, 4, 1}, + context::_PEPSCorrelator, + O::MPOTensor, + ) where {T, S} + return end_correlator_right_numerator(j, V, context.bra, O, context.ket, context.env) +end + +function _end_correlator_right_numerator( + j::CartesianIndex{2}, + V::CTMRGEdgeTensor{T, S, 3}, + context::_PEPOTraceCorrelator, + O::PFTensor, + ) where {T, S} + return end_correlator_right_numerator(j, V, context.ρ, O, context.env) +end + +function _edge_transfermatrix(row::Int, col::Int, context::_PEPSCorrelator) + return _edge_transfermatrix(row, col, context.bra, context.ket, context.env) +end + +function _edge_transfermatrix(row::Int, col::Int, context::_PEPOTraceCorrelator) + return _edge_transfermatrix(row, col, context.ρ, context.env) +end + +function _correlator_horizontal( + context, + operator, + i::CartesianIndex{2}, js::AbstractVector{CartesianIndex{2}}, + ) + _issorted_correlator_sites(i, js) + O = FiniteMPO(operator) + length(O) == 2 || throw(ArgumentError("Operator must act on two sites")) + # preallocate with correct scalartype + G = similar(js, _correlator_scalartype(context, O)) + # left start for operator and norm contractions + c = i # current column being handled + Vn, Vo = _start_correlator_left(c, context, O[1]) + j_last = last(js) + for (k, j) in enumerate(js) + local numerator + while j > c + c += CartesianIndex(0, 1) + if c == j + numerator = _end_correlator_right_numerator(j, Vo, context, O[2]) + end + T = _edge_transfermatrix(c[1], c[2], context) + c != j_last && (Vo = Vo * T) + Vn = Vn * T + end + # compute overlap without operator + denominator = end_correlator_right_denominator(j, Vn, context.env) + G[k] = numerator / denominator + end + return G +end + +function _correlator_vertical(context, operator, i::CartesianIndex{2}, js) + unitcell = _correlator_unitcell(context) + rotated_i = siterotl90(i, unitcell) + rotated_js = map(j -> siterotl90(j, unitcell), js) + return _correlator_horizontal(rotl90(context), operator, rotated_i, rotated_js) +end + +function _correlator( + context, O, i::CartesianIndex{2}, js::AbstractVector{CartesianIndex{2}} + ) + if all(==(i[1]) ∘ first ∘ Tuple, js) + return _correlator_horizontal(context, O, i, js) + elseif all(==(i[2]) ∘ last ∘ Tuple, js) + return _correlator_vertical(context, O, i, js) + else + error("Only horizontal or vertical correlators are implemented") + end +end + +function _issorted_correlator_sites(i::CartesianIndex{2}, js::AbstractVector{CartesianIndex{2}}) + return issorted(vcat(i, js); by = last ∘ Tuple) || + throw(ArgumentError("Not an increasing sequence of coordinates")) +end diff --git a/src/algorithms/correlators.jl b/src/algorithms/correlators.jl index 5ef94dd00..1b564e3d4 100644 --- a/src/algorithms/correlators.jl +++ b/src/algorithms/correlators.jl @@ -1,75 +1,15 @@ -# Correlators in InfinitePEPS - -function _correlator_horizontal_pos( - bra::InfinitePEPS, - operator, - i::CartesianIndex{2}, js::AbstractVector{CartesianIndex{2}}, - ket::InfinitePEPS, - env::CTMRGEnv, - ) - size(ket) == size(bra) || - throw(DimensionMismatch("The ket and bra must have the same unit cell.")) - _issorted_correlator_sites(i, js) - O = FiniteMPO(operator) - length(O) == 2 || throw(ArgumentError("Operator must act on two sites")) - # preallocate with correct scalartype - G = similar( - js, TensorOperations.promote_contract( - scalartype(bra), scalartype(ket), scalartype(env), scalartype.(O)... - ), - ) - # left start for operator and norm contractions - c = i # current column being handled - Vn, Vo = start_correlator_left(c, bra, O[1], ket, env) - j_last = last(js) - for (k, j) in enumerate(js) - local numerator - while j > c - c += CartesianIndex(0, 1) - if c == j - numerator = end_correlator_right_numerator(j, Vo, bra, O[2], ket, env) - end - T = _edge_transfermatrix(c[1], c[2], bra, ket, env) - c != j_last && (Vo = Vo * T) - Vn = Vn * T - end - # compute overlap without operator - denominator = end_correlator_right_denominator(j, Vn, env) - G[k] = numerator / denominator - end - return G -end +const CoordCollection{N} = Union{AbstractVector{CartesianIndex{N}}, CartesianIndices{N}} -function correlator_vertical( - bra::InfinitePEPS, - operator, - i::CartesianIndex{2}, js::AbstractVector{CartesianIndex{2}}, - ket::InfinitePEPS, - env::CTMRGEnv, - ) - rotated_bra = rotl90(bra) - rotated_ket = bra === ket ? rotated_bra : rotl90(ket) - rotated_i = siterotl90(i, size(bra)) - rotated_js = map(j -> siterotl90(j, size(bra)), js) - return _correlator_horizontal_pos( - rotated_bra, operator, rotated_i, rotated_js, rotated_ket, rotl90(env) - ) -end +# Correlators in InfinitePEPS function MPSKit.correlator( bra::InfinitePEPS, O, - i::CartesianIndex{2}, js::AbstractVector{CartesianIndex{2}}, + i::CartesianIndex{2}, js::CoordCollection{2}, ket::InfinitePEPS, env::CTMRGEnv, ) - if all(==(i[1]) ∘ first ∘ Tuple, js) - return _correlator_horizontal_pos(bra, O, i, js, ket, env) - elseif all(==(i[2]) ∘ last ∘ Tuple, js) - return correlator_vertical(bra, O, i, js, ket, env) - else - error("Only horizontal or vertical correlators are implemented") - end + return _correlator(_PEPSCorrelator(bra, ket, env), O, i, vec(js)) end function MPSKit.correlator( @@ -89,70 +29,12 @@ end # Correlators in InfinitePEPO (tr(ρO)) -function _correlator_horizontal_pos( - ρ::InfinitePEPO, operator, - i::CartesianIndex{2}, js::AbstractVector{CartesianIndex{2}}, - env::CTMRGEnv - ) - (size(ρ, 3) == 1) || - throw(ArgumentError("The input PEPO ρ must have only one layer.")) - _issorted_correlator_sites(i, js) - O = FiniteMPO(operator) - length(O) == 2 || throw(ArgumentError("Operator must act on two sites")) - # preallocate with correct scalartype - G = similar( - js, TensorOperations.promote_contract( - scalartype(ρ), scalartype(env), scalartype.(O)... - ), - ) - # left start for operator and norm contractions - c = i # current column being handled - Vn, Vo = start_correlator_left(c, ρ, O[1], env) - j_last = last(js) - for (k, j) in enumerate(js) - local numerator - while j > c - c += CartesianIndex(0, 1) - if c == j - numerator = end_correlator_right_numerator(j, Vo, ρ, O[2], env) - end - T = _edge_transfermatrix(c[1], c[2], ρ, env) - c != j_last && (Vo = Vo * T) - Vn = Vn * T - end - # compute overlap without operator - denominator = end_correlator_right_denominator(j, Vn, env) - G[k] = numerator / denominator - end - return G -end - -function correlator_vertical( - ρ::InfinitePEPO, operator, - i::CartesianIndex{2}, js::AbstractVector{CartesianIndex{2}}, - env::CTMRGEnv, - ) - rotated_ρ = rotl90(ρ) - unitcell = size(ρ)[1:2] - rotated_i = siterotl90(i, unitcell) - rotated_js = map(j -> siterotl90(j, unitcell), js) - return _correlator_horizontal_pos( - rotated_ρ, operator, rotated_i, rotated_js, rotl90(env) - ) -end - function MPSKit.correlator( ρ::InfinitePEPO, O, - i::CartesianIndex{2}, js::AbstractVector{CartesianIndex{2}}, + i::CartesianIndex{2}, js::CoordCollection{2}, env::CTMRGEnv, ) - if all(==(i[1]) ∘ first ∘ Tuple, js) - return _correlator_horizontal_pos(ρ, O, i, js, env) - elseif all(==(i[2]) ∘ last ∘ Tuple, js) - return correlator_vertical(ρ, O, i, js, env) - else - error("Only horizontal or vertical correlators are implemented") - end + return _correlator(_PEPOTraceCorrelator(ρ, env), O, i, vec(js)) end function MPSKit.correlator( @@ -164,10 +46,3 @@ function MPSKit.correlator( end # TODO: Correlators in InfinitePEPO (⟨ρ|O|ρ⟩) - -# utility functions - -function _issorted_correlator_sites(i::CartesianIndex{2}, js::AbstractVector{CartesianIndex{2}}) - return issorted(vcat(i, js); by = last ∘ Tuple) || - throw(ArgumentError("Not an increasing sequence of coordinates")) -end From fe7e649e95b78320c5f57f4a7e853cd8d7924013 Mon Sep 17 00:00:00 2001 From: Yue Zhengyuan Date: Wed, 1 Jul 2026 17:14:38 +0800 Subject: [PATCH 06/13] Remove unused transfer right --- src/algorithms/contractions/transfer.jl | 70 ------------------------- 1 file changed, 70 deletions(-) diff --git a/src/algorithms/contractions/transfer.jl b/src/algorithms/contractions/transfer.jl index 4a88cf0d0..14eec348d 100644 --- a/src/algorithms/contractions/transfer.jl +++ b/src/algorithms/contractions/transfer.jl @@ -3,7 +3,6 @@ # edge_transfer_left(v, ::Nothing, A, B) = edge_transfer_left(v, A, B) -edge_transfer_right(v, ::Nothing, A, B) = edge_transfer_right(v, A, B) """ edge_transfer_left(v, Et, Eb) @@ -30,32 +29,6 @@ Apply an edge transfer matrix to the left. ) end - -""" - edge_transfer_right(v, Et, Eb) - -Apply an edge transfer matrix to the right. - -``` -─Et─┐ - │ v- -─qƎ─┘ -``` -""" -@generated function edge_transfer_right( - v::AbstractTensorMap{<:Any, S, 1, N₁}, - Etop::CTMRGEdgeTensor{<:Any, S, N₂}, - Ebot::CTMRGEdgeTensor{<:Any, S, N₂} - ) where {S, N₁, N₂} - t_out = tensorexpr(:v, -1, -(2:(N₁ + 1))) - t_top = tensorexpr(:Etop, (-1, (3:(N₂ + 1))...), 1) - t_bot = tensorexpr(:Ebot, (2, (3:(N₂ + 1))...), -(N₁ + 1)) - t_in = tensorexpr(:v, 1, (-(2:N₁)..., 2)) - return macroexpand( - @__MODULE__, :(return @tensor $t_out := $t_top * $t_bot * $t_in) - ) -end - """ edge_transfer_left(v, O, Et, Eb) @@ -99,49 +72,6 @@ function edge_transfer_left( return v´ end -""" - transfer_right(v, Et, Eb) - -Apply an edge transfer matrix to the right. - -``` -──Et─┐ - │ │ -──O──v - │ │ -──qƎ─┘ -``` -""" -function edge_transfer_right( - v::CTMRGEdgeTensor{<:Any, S, 3}, - O::PEPSSandwich, - Etop::CTMRGEdgeTensor{<:Any, S, 3}, - Ebot::CTMRGEdgeTensor{<:Any, S, 3}, - ) where {S} - @autoopt @tensor v′[χ_NW D_W_above D_W_below; χ_SW] := - v[χ_NE D_E_above D_E_below; χ_SE] * - Etop[χ_NW D_N_above D_N_below; χ_NE] * - Ebot[χ_SE D_S_above D_S_below; χ_SW] * - ket(O)[d; D_N_above D_E_above D_S_above D_W_above] * - conj(bra(O)[d; D_N_below D_E_below D_S_below D_W_below]) - - return v′ -end -function edge_transfer_right( - v::CTMRGEdgeTensor{<:Any, S, 2}, - O::PFTensor, - Etop::CTMRGEdgeTensor{<:Any, S, 2}, - Ebot::CTMRGEdgeTensor{<:Any, S, 2}, - ) where {S} - return @autoopt @tensor v′[χ_NW D_W; χ_SW] := - v[χ_NE D_E; χ_SE] * - Etop[χ_NW D_N; χ_NE] * - Ebot[χ_SE D_S; χ_SW] * - O[D_W D_S; D_N D_E] - - return v′ -end - """ edge_transfer_left(v, O, Et, Eb) From 5f220c2ce50a214be420ebf793af915e85368309 Mon Sep 17 00:00:00 2001 From: Yue Zhengyuan Date: Wed, 1 Jul 2026 17:34:06 +0800 Subject: [PATCH 07/13] Undo some changes --- .../contractions/correlator/pepo_1layer.jl | 6 ++--- .../contractions/correlator/peps.jl | 6 ++--- src/algorithms/correlator_adapters.jl | 22 +++++++++---------- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/algorithms/contractions/correlator/pepo_1layer.jl b/src/algorithms/contractions/correlator/pepo_1layer.jl index 6fcae3b4e..580f271d7 100644 --- a/src/algorithms/contractions/correlator/pepo_1layer.jl +++ b/src/algorithms/contractions/correlator/pepo_1layer.jl @@ -1,4 +1,4 @@ -function start_correlator_left( +function start_correlator( i::CartesianIndex{2}, ρ::InfinitePEPO, O::PFTensor, env::CTMRGEnv ) @@ -25,7 +25,7 @@ function start_correlator_left( return Vn, Vo end -function end_correlator_right_numerator( +function end_correlator_numerator( j::CartesianIndex{2}, V::CTMRGEdgeTensor{T, S, 3}, ρ::InfinitePEPO, O::PFTensor, env::CTMRGEnv ) where {T, S} @@ -44,7 +44,7 @@ function end_correlator_right_numerator( t[d1 d2; DN DE DS DW] * removeunit(O, 4)[dstring d2; d1] end -function end_correlator_right_denominator( +function end_correlator_denominator( j::CartesianIndex{2}, V::CTMRGEdgeTensor{T, S, 2}, env::CTMRGEnv ) where {T, S} r, c = Tuple(j) diff --git a/src/algorithms/contractions/correlator/peps.jl b/src/algorithms/contractions/correlator/peps.jl index 974d1ad2a..fafdd938a 100644 --- a/src/algorithms/contractions/correlator/peps.jl +++ b/src/algorithms/contractions/correlator/peps.jl @@ -1,4 +1,4 @@ -function start_correlator_left( +function start_correlator( i::CartesianIndex{2}, below::InfinitePEPS, O::MPOTensor, @@ -37,7 +37,7 @@ function start_correlator_left( return Vn, Vo end -function end_correlator_right_numerator( +function end_correlator_numerator( j::CartesianIndex{2}, V::AbstractTensorMap{T, S, 4, 1}, above::InfinitePEPS, @@ -64,7 +64,7 @@ function end_correlator_right_numerator( removeunit(O, 4)[dstring db; dt] end -function end_correlator_right_denominator( +function end_correlator_denominator( j::CartesianIndex{2}, V::AbstractTensorMap{T, S, 3, 1}, env::CTMRGEnv ) where {T, S} diff --git a/src/algorithms/correlator_adapters.jl b/src/algorithms/correlator_adapters.jl index fb3bba0a7..56083306d 100644 --- a/src/algorithms/correlator_adapters.jl +++ b/src/algorithms/correlator_adapters.jl @@ -48,34 +48,34 @@ end Base.rotl90(context::_PEPOTraceCorrelator) = _PEPOTraceCorrelator(rotl90(context.ρ), rotl90(context.env)) -function _start_correlator_left( +function _start_correlator( i::CartesianIndex{2}, context::_PEPSCorrelator, O::MPOTensor ) - return start_correlator_left(i, context.bra, O, context.ket, context.env) + return start_correlator(i, context.bra, O, context.ket, context.env) end -function _start_correlator_left( +function _start_correlator( i::CartesianIndex{2}, context::_PEPOTraceCorrelator, O::PFTensor ) - return start_correlator_left(i, context.ρ, O, context.env) + return start_correlator(i, context.ρ, O, context.env) end -function _end_correlator_right_numerator( +function _end_correlator_numerator( j::CartesianIndex{2}, V::AbstractTensorMap{T, S, 4, 1}, context::_PEPSCorrelator, O::MPOTensor, ) where {T, S} - return end_correlator_right_numerator(j, V, context.bra, O, context.ket, context.env) + return end_correlator_numerator(j, V, context.bra, O, context.ket, context.env) end -function _end_correlator_right_numerator( +function _end_correlator_numerator( j::CartesianIndex{2}, V::CTMRGEdgeTensor{T, S, 3}, context::_PEPOTraceCorrelator, O::PFTensor, ) where {T, S} - return end_correlator_right_numerator(j, V, context.ρ, O, context.env) + return end_correlator_numerator(j, V, context.ρ, O, context.env) end function _edge_transfermatrix(row::Int, col::Int, context::_PEPSCorrelator) @@ -98,21 +98,21 @@ function _correlator_horizontal( G = similar(js, _correlator_scalartype(context, O)) # left start for operator and norm contractions c = i # current column being handled - Vn, Vo = _start_correlator_left(c, context, O[1]) + Vn, Vo = _start_correlator(c, context, O[1]) j_last = last(js) for (k, j) in enumerate(js) local numerator while j > c c += CartesianIndex(0, 1) if c == j - numerator = _end_correlator_right_numerator(j, Vo, context, O[2]) + numerator = _end_correlator_numerator(j, Vo, context, O[2]) end T = _edge_transfermatrix(c[1], c[2], context) c != j_last && (Vo = Vo * T) Vn = Vn * T end # compute overlap without operator - denominator = end_correlator_right_denominator(j, Vn, context.env) + denominator = end_correlator_denominator(j, Vn, context.env) G[k] = numerator / denominator end return G From 4d6c0984781f01b771c3bab34aaa733accfc850b Mon Sep 17 00:00:00 2001 From: Yue Zhengyuan Date: Wed, 1 Jul 2026 21:39:05 +0800 Subject: [PATCH 08/13] Correlator for purified iPEPO --- src/PEPSKit.jl | 1 + .../contractions/correlator/pepo_purified.jl | 65 +++++++++++++++++++ src/algorithms/contractions/transfer.jl | 30 +++++++++ src/algorithms/correlator_adapters.jl | 40 ++++++++++-- src/algorithms/correlators.jl | 18 +++-- src/algorithms/toolbox.jl | 5 +- src/algorithms/transfermatrix.jl | 5 +- src/networks/local_sandwich.jl | 5 +- test/utility/correlator.jl | 23 +++++++ 9 files changed, 168 insertions(+), 24 deletions(-) create mode 100644 src/algorithms/contractions/correlator/pepo_purified.jl diff --git a/src/PEPSKit.jl b/src/PEPSKit.jl index 4035d099e..86d478e4a 100644 --- a/src/PEPSKit.jl +++ b/src/PEPSKit.jl @@ -96,6 +96,7 @@ include("algorithms/contractions/bondenv/gaugefix.jl") include("algorithms/contractions/bondenv/als_solve.jl") include("algorithms/contractions/bondenv/benv_ctm.jl") include("algorithms/contractions/correlator/peps.jl") +include("algorithms/contractions/correlator/pepo_purified.jl") include("algorithms/contractions/correlator/pepo_1layer.jl") include("algorithms/ctmrg/sparse_environments.jl") diff --git a/src/algorithms/contractions/correlator/pepo_purified.jl b/src/algorithms/contractions/correlator/pepo_purified.jl new file mode 100644 index 000000000..18e78bdf3 --- /dev/null +++ b/src/algorithms/contractions/correlator/pepo_purified.jl @@ -0,0 +1,65 @@ +function start_correlator( + i::CartesianIndex{2}, + below::InfinitePEPO, + O::MPOTensor, + above::InfinitePEPO, + env::CTMRGEnv, + ) + r, c = Tuple(i) + E_north = edge(env, NORTH, r - 1, c) + E_south = edge(env, SOUTH, r + 1, c) + E_west = edge(env, WEST, r, c - 1) + C_northwest = corner(env, NORTHWEST, r - 1, c - 1) + C_southwest = corner(env, SOUTHWEST, r + 1, c - 1) + ket = twistdual(below[r, c], (1, 2)) + bra = above[r, c] + + @autoopt @tensor Vn[χSE Detop Debot; χNE] := + E_south[χSE Dstop Dsbot; χSW2] * + C_southwest[χSW2; χSW] * + E_west[χSW Dwtop Dwbot; χNW] * + C_northwest[χNW; χN] * + conj(bra[d a; Dnbot Debot Dsbot Dwbot]) * + ket[d a; Dntop Detop Dstop Dwtop] * + E_north[χN Dntop Dnbot; χNE] + + @autoopt @tensor Vo[χSE Detop dstring Debot; χNE] := + E_south[χSE Dstop Dsbot; χSW2] * + C_southwest[χSW2; χSW] * + E_west[χSW Dwtop Dwbot; χNW] * + C_northwest[χNW; χN] * + conj(bra[d1 a; Dnbot Debot Dsbot Dwbot]) * + removeunit(O, 1)[d1; d2 dstring] * + ket[d2 a; Dntop Detop Dstop Dwtop] * + E_north[χN Dntop Dnbot; χNE] + + return Vn, Vo +end + +function end_correlator_numerator( + j::CartesianIndex{2}, + V::AbstractTensorMap{T, S, 4, 1}, + above::InfinitePEPO, + O::MPOTensor, + below::InfinitePEPO, + env::CTMRGEnv, + ) where {T, S} + r, c = Tuple(j) + E_north = edge(env, NORTH, r - 1, c) + E_east = edge(env, EAST, r, c + 1) + E_south = edge(env, SOUTH, r + 1, c) + C_northeast = corner(env, NORTHEAST, r - 1, c + 1) + C_southeast = corner(env, SOUTHEAST, r + 1, c + 1) + ket = twistdual(above[r, c], (1, 2)) + bra = below[r, c] + + return @autoopt @tensor V[χSW DWt dstring DWb; χNW] * + E_south[χSSE DSt DSb; χSW] * + E_east[χNEE DEt DEb; χSEE] * + E_north[χNW DNt DNb; χNNE] * + C_northeast[χNNE; χNEE] * + C_southeast[χSEE; χSSE] * + conj(bra[db a; DNb DEb DSb DWb]) * + ket[dt a; DNt DEt DSt DWt] * + removeunit(O, 4)[dstring db; dt] +end diff --git a/src/algorithms/contractions/transfer.jl b/src/algorithms/contractions/transfer.jl index 14eec348d..df11a9188 100644 --- a/src/algorithms/contractions/transfer.jl +++ b/src/algorithms/contractions/transfer.jl @@ -57,6 +57,23 @@ function edge_transfer_left( return v´ end +function edge_transfer_left( + v::CTMRGEdgeTensor{<:Any, S, 3}, + O::PEPOPurifiedSandwich, + Etop::CTMRGEdgeTensor{<:Any, S, 3}, + Ebot::CTMRGEdgeTensor{<:Any, S, 3}, + ) where {S} + ket_tensor = twistdual(ket(O), (1, 2)) + bra_tensor = bra(O) + @autoopt @tensor v´[χ_SE D_E_above D_E_below; χ_NE] := + v[χ_SW D_W_above D_W_below; χ_NW] * + Etop[χ_NW D_N_above D_N_below; χ_NE] * + Ebot[χ_SE D_S_above D_S_below; χ_SW] * + ket_tensor[d a; D_N_above D_E_above D_S_above D_W_above] * + conj(bra_tensor[d a; D_N_below D_E_below D_S_below D_W_below]) + + return v´ +end function edge_transfer_left( v::CTMRGEdgeTensor{<:Any, S, 2}, O::PFTensor, @@ -96,6 +113,19 @@ function edge_transfer_left( ket(O)[d; D_N_above D_E_above D_S_above D_W_above] * conj(bra(O)[d; D_N_below D_E_below D_S_below D_W_below]) end +function edge_transfer_left( + v::CTMRGEdgeTensor{<:Any, S, 4}, O::PEPOPurifiedSandwich, + Etop::CTMRGEdgeTensor{<:Any, S, 3}, Ebot::CTMRGEdgeTensor{<:Any, S, 3}, + ) where {S} + ket_tensor = twistdual(ket(O), (1, 2)) + bra_tensor = bra(O) + return @autoopt @tensor v′[χ_SE D_E_above d_string D_E_below; χ_NE] := + v[χ_SW D_W_above d_string D_W_below; χ_NW] * + Etop[χ_NW D_N_above D_N_below; χ_NE] * + Ebot[χ_SE D_S_above D_S_below; χ_SW] * + ket_tensor[d a; D_N_above D_E_above D_S_above D_W_above] * + conj(bra_tensor[d a; D_N_below D_E_below D_S_below D_W_below]) +end function edge_transfer_left( v::CTMRGEdgeTensor{<:Any, S, 3}, O::PFTensor, Etop::CTMRGEdgeTensor{<:Any, S, 2}, Ebot::CTMRGEdgeTensor{<:Any, S, 2}, diff --git a/src/algorithms/correlator_adapters.jl b/src/algorithms/correlator_adapters.jl index 56083306d..13eb92fd1 100644 --- a/src/algorithms/correlator_adapters.jl +++ b/src/algorithms/correlator_adapters.jl @@ -12,6 +12,27 @@ struct _PEPSCorrelator{B <: InfinitePEPS, K <: InfinitePEPS, E <: CTMRGEnv} end end +struct _PEPOPurifiedCorrelator{B <: InfinitePEPO, K <: InfinitePEPO, E <: CTMRGEnv} + bra::B + ket::K + env::E + + function _PEPOPurifiedCorrelator(bra::B, ket::K, env::E) where {B, K, E} + size(ket) == size(bra) || + throw(DimensionMismatch("The ket and bra must have the same unit cell.")) + size(ket, 3) == size(bra, 3) == 1 || + throw(ArgumentError("Purified PEPO correlators require one-layer PEPOs.")) + return new{B, K, E}(bra, ket, env) + end +end + +const _BraketCorrelator = Union{_PEPSCorrelator, _PEPOPurifiedCorrelator} + +_braket_correlator(bra::InfinitePEPS, ket::InfinitePEPS, env::CTMRGEnv) = + _PEPSCorrelator(bra, ket, env) +_braket_correlator(bra::InfinitePEPO, ket::InfinitePEPO, env::CTMRGEnv) = + _PEPOPurifiedCorrelator(bra, ket, env) + struct _PEPOTraceCorrelator{P <: InfinitePEPO, E <: CTMRGEnv} ρ::P env::E @@ -23,7 +44,7 @@ struct _PEPOTraceCorrelator{P <: InfinitePEPO, E <: CTMRGEnv} end end -function _correlator_scalartype(context::_PEPSCorrelator, O::FiniteMPO) +function _correlator_scalartype(context::_BraketCorrelator, O::FiniteMPO) return TensorOperations.promote_contract( scalartype(context.bra), scalartype(context.ket), scalartype(context.env), scalartype.(O)... @@ -36,7 +57,7 @@ function _correlator_scalartype(context::_PEPOTraceCorrelator, O::FiniteMPO) ) end -_correlator_unitcell(context::_PEPSCorrelator) = size(context.bra) +_correlator_unitcell(context::_BraketCorrelator) = size(context.bra)[1:2] _correlator_unitcell(context::_PEPOTraceCorrelator) = size(context.ρ)[1:2] function Base.rotl90(context::_PEPSCorrelator) @@ -45,11 +66,17 @@ function Base.rotl90(context::_PEPSCorrelator) return _PEPSCorrelator(rotated_bra, rotated_ket, rotl90(context.env)) end +function Base.rotl90(context::_PEPOPurifiedCorrelator) + rotated_bra = rotl90(context.bra) + rotated_ket = context.bra === context.ket ? rotated_bra : rotl90(context.ket) + return _PEPOPurifiedCorrelator(rotated_bra, rotated_ket, rotl90(context.env)) +end + Base.rotl90(context::_PEPOTraceCorrelator) = _PEPOTraceCorrelator(rotl90(context.ρ), rotl90(context.env)) function _start_correlator( - i::CartesianIndex{2}, context::_PEPSCorrelator, O::MPOTensor + i::CartesianIndex{2}, context::_BraketCorrelator, O::MPOTensor ) return start_correlator(i, context.bra, O, context.ket, context.env) end @@ -63,7 +90,7 @@ end function _end_correlator_numerator( j::CartesianIndex{2}, V::AbstractTensorMap{T, S, 4, 1}, - context::_PEPSCorrelator, + context::_BraketCorrelator, O::MPOTensor, ) where {T, S} return end_correlator_numerator(j, V, context.bra, O, context.ket, context.env) @@ -78,7 +105,7 @@ function _end_correlator_numerator( return end_correlator_numerator(j, V, context.ρ, O, context.env) end -function _edge_transfermatrix(row::Int, col::Int, context::_PEPSCorrelator) +function _edge_transfermatrix(row::Int, col::Int, context::_BraketCorrelator) return _edge_transfermatrix(row, col, context.bra, context.ket, context.env) end @@ -87,8 +114,7 @@ function _edge_transfermatrix(row::Int, col::Int, context::_PEPOTraceCorrelator) end function _correlator_horizontal( - context, - operator, + context, operator, i::CartesianIndex{2}, js::AbstractVector{CartesianIndex{2}}, ) _issorted_correlator_sites(i, js) diff --git a/src/algorithms/correlators.jl b/src/algorithms/correlators.jl index 1b564e3d4..ab7c5641f 100644 --- a/src/algorithms/correlators.jl +++ b/src/algorithms/correlators.jl @@ -1,24 +1,24 @@ const CoordCollection{N} = Union{AbstractVector{CartesianIndex{N}}, CartesianIndices{N}} -# Correlators in InfinitePEPS +# Correlators in InfinitePEPS or purified InfinitePEPO function MPSKit.correlator( - bra::InfinitePEPS, + bra::S, O, i::CartesianIndex{2}, js::CoordCollection{2}, - ket::InfinitePEPS, + ket::S, env::CTMRGEnv, - ) - return _correlator(_PEPSCorrelator(bra, ket, env), O, i, vec(js)) + ) where {S <: InfiniteState} + return _correlator(_braket_correlator(bra, ket, env), O, i, vec(js)) end function MPSKit.correlator( - bra::InfinitePEPS, + bra::S, O, i::CartesianIndex{2}, j::CartesianIndex{2}, - ket::InfinitePEPS, + ket::S, env::CTMRGEnv, - ) + ) where {S <: InfiniteState} return only(correlator(bra, O, i, j:j, ket, env)) end @@ -44,5 +44,3 @@ function MPSKit.correlator( ) return only(correlator(ρ, O, i, j:j, env)) end - -# TODO: Correlators in InfinitePEPO (⟨ρ|O|ρ⟩) diff --git a/src/algorithms/toolbox.jl b/src/algorithms/toolbox.jl index c532d3e1d..b53e0f443 100644 --- a/src/algorithms/toolbox.jl +++ b/src/algorithms/toolbox.jl @@ -8,9 +8,8 @@ In the latter case the first signature corresponds to a single layer PEPO contra the second signature yields a bilayer contraction instead. """ function MPSKit.expectation_value( - bra::Union{InfinitePEPS, InfinitePEPO}, O::LocalOperator, - ket::Union{InfinitePEPS, InfinitePEPO}, env::CTMRGEnv - ) + bra::S, O::LocalOperator, ket::S, env::CTMRGEnv + ) where {S <: InfiniteState} checklattice(bra, O, ket) term_vals = dtmap(collect(O.terms)) do (inds, operator) # OhMyThreads can't iterate over O.terms directly ρ = reduced_densitymatrix(inds, ket, bra, env) diff --git a/src/algorithms/transfermatrix.jl b/src/algorithms/transfermatrix.jl index 2b1d0edd9..19e045e07 100644 --- a/src/algorithms/transfermatrix.jl +++ b/src/algorithms/transfermatrix.jl @@ -38,9 +38,8 @@ function edge_transfermatrix(a::AbstractVector, b, c::AbstractVector, isflipped end function _edge_transfermatrix( - row::Int, col::Int, - bra::InfinitePEPS, ket::InfinitePEPS, env::CTMRGEnv - ) + row::Int, col::Int, bra::S, ket::S, env::CTMRGEnv + ) where {S <: InfiniteState} Etop = edge(env, NORTH, row - 1, col) Ebot = edge(env, SOUTH, row + 1, col) sandwich = (ket[row, col], bra[row, col]) diff --git a/src/networks/local_sandwich.jl b/src/networks/local_sandwich.jl index 4c46cd9fe..90386e9fe 100644 --- a/src/networks/local_sandwich.jl +++ b/src/networks/local_sandwich.jl @@ -108,8 +108,11 @@ end ## PEPO -const PEPOSandwich{N, T <: PEPSTensor, P <: PEPOTensor} = Tuple{T, T, Vararg{P, N}} +const PEPOPurifiedSandwich{K <: PEPOTensor, B <: PEPOTensor} = Tuple{K, B} +ket(O::PEPOPurifiedSandwich) = O[1] +bra(O::PEPOPurifiedSandwich) = O[2] +const PEPOSandwich{N, T <: PEPSTensor, P <: PEPOTensor} = Tuple{T, T, Vararg{P, N}} ket(O::PEPOSandwich) = O[1] bra(O::PEPOSandwich) = O[2] pepo(O::PEPOSandwich) = O[3:end] diff --git a/test/utility/correlator.jl b/test/utility/correlator.jl index 4fe8a958f..c78148e12 100644 --- a/test/utility/correlator.jl +++ b/test/utility/correlator.jl @@ -64,3 +64,26 @@ end end end end + +@testset "Correlator in purified InfinitePEPO ($(sym))" for sym in syms + Random.seed!(100) + Vphy, Venv, Nspaces, Espaces = get_spaces(sym) + # TODO: test dual physical space + for Vp in [Vphy] + op = randn(ComplexF64, Vp ⊗ Vp → Vp ⊗ Vp) + Pspaces = fill(Vp, size(Nspaces)) + pepo = InfinitePEPO(randn, ComplexF64, Pspaces, Nspaces, Espaces) + peps = InfinitePEPS(pepo) + env = CTMRGEnv(randn, ComplexF64, peps, Venv) + for site1s in (site1xs, site1ys) + vals1 = correlator(pepo, op, site0, site1s, pepo, env) + vals2 = map(site1s) do site1 + O = LocalOperator(Pspaces, (site0, site1) => op) + return expectation_value(pepo, O, pepo, env) + end + @info vals1 + @info vals2 + @test vals1 ≈ vals2 + end + end +end From 7248dbba7441bbb43dec4a653d0e3f19f56935e2 Mon Sep 17 00:00:00 2001 From: Yue Zhengyuan Date: Wed, 1 Jul 2026 22:01:55 +0800 Subject: [PATCH 09/13] Record removal of edge_transfer_right in changelog --- docs/src/changelog.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/src/changelog.md b/docs/src/changelog.md index adc18395a..fed97b5a4 100644 --- a/docs/src/changelog.md +++ b/docs/src/changelog.md @@ -28,6 +28,8 @@ When releasing a new version, move the "Unreleased" changes to a new version sec ### Removed +- `edge_transfer_right` are not used anywhere and removed (#399) + ### Fixed ### Performance From 7dbe885b9aaea0de0c2f6073db65a79a6105b7be Mon Sep 17 00:00:00 2001 From: Yue Zhengyuan Date: Wed, 1 Jul 2026 22:12:43 +0800 Subject: [PATCH 10/13] Restore edge_transfer_right --- src/algorithms/contractions/transfer.jl | 72 ++++++++++++++++++++++--- 1 file changed, 64 insertions(+), 8 deletions(-) diff --git a/src/algorithms/contractions/transfer.jl b/src/algorithms/contractions/transfer.jl index df11a9188..c53bf98a9 100644 --- a/src/algorithms/contractions/transfer.jl +++ b/src/algorithms/contractions/transfer.jl @@ -3,6 +3,7 @@ # edge_transfer_left(v, ::Nothing, A, B) = edge_transfer_left(v, A, B) +edge_transfer_right(v, ::Nothing, A, B) = edge_transfer_right(v, A, B) """ edge_transfer_left(v, Et, Eb) @@ -29,6 +30,32 @@ Apply an edge transfer matrix to the left. ) end + +""" + edge_transfer_right(v, Et, Eb) + +Apply an edge transfer matrix to the right. + +``` +─Et─┐ + │ v- +─qƎ─┘ +``` +""" +@generated function edge_transfer_right( + v::AbstractTensorMap{<:Any, S, 1, N₁}, + Etop::CTMRGEdgeTensor{<:Any, S, N₂}, + Ebot::CTMRGEdgeTensor{<:Any, S, N₂} + ) where {S, N₁, N₂} + t_out = tensorexpr(:v, -1, -(2:(N₁ + 1))) + t_top = tensorexpr(:Etop, (-1, (3:(N₂ + 1))...), 1) + t_bot = tensorexpr(:Ebot, (2, (3:(N₂ + 1))...), -(N₁ + 1)) + t_in = tensorexpr(:v, 1, (-(2:N₁)..., 2)) + return macroexpand( + @__MODULE__, :(return @tensor $t_out := $t_top * $t_bot * $t_in) + ) +end + """ edge_transfer_left(v, O, Et, Eb) @@ -48,14 +75,12 @@ function edge_transfer_left( Etop::CTMRGEdgeTensor{<:Any, S, 3}, Ebot::CTMRGEdgeTensor{<:Any, S, 3}, ) where {S} - @autoopt @tensor v´[χ_SE D_E_above D_E_below; χ_NE] := + return @autoopt @tensor v´[χ_SE D_E_above D_E_below; χ_NE] := v[χ_SW D_W_above D_W_below; χ_NW] * Etop[χ_NW D_N_above D_N_below; χ_NE] * Ebot[χ_SE D_S_above D_S_below; χ_SW] * ket(O)[d; D_N_above D_E_above D_S_above D_W_above] * conj(bra(O)[d; D_N_below D_E_below D_S_below D_W_below]) - - return v´ end function edge_transfer_left( v::CTMRGEdgeTensor{<:Any, S, 3}, @@ -65,14 +90,12 @@ function edge_transfer_left( ) where {S} ket_tensor = twistdual(ket(O), (1, 2)) bra_tensor = bra(O) - @autoopt @tensor v´[χ_SE D_E_above D_E_below; χ_NE] := + return @autoopt @tensor v´[χ_SE D_E_above D_E_below; χ_NE] := v[χ_SW D_W_above D_W_below; χ_NW] * Etop[χ_NW D_N_above D_N_below; χ_NE] * Ebot[χ_SE D_S_above D_S_below; χ_SW] * ket_tensor[d a; D_N_above D_E_above D_S_above D_W_above] * conj(bra_tensor[d a; D_N_below D_E_below D_S_below D_W_below]) - - return v´ end function edge_transfer_left( v::CTMRGEdgeTensor{<:Any, S, 2}, @@ -80,13 +103,46 @@ function edge_transfer_left( Etop::CTMRGEdgeTensor{<:Any, S, 2}, Ebot::CTMRGEdgeTensor{<:Any, S, 2}, ) where {S} - @autoopt @tensor v´[χ_SE D_E; χ_NE] := + return @autoopt @tensor v´[χ_SE D_E; χ_NE] := v[χ_SW D_W; χ_NW] * Etop[χ_NW D_N; χ_NE] * Ebot[χ_SE D_S; χ_SW] * O[D_W D_S; D_N D_E] +end + +""" + transfer_right(v, Et, Eb) + +Apply an edge transfer matrix to the right. - return v´ +``` +──Et─┐ + │ │ +──O──v + │ │ +──qƎ─┘ +``` +""" +function edge_transfer_right( + v::CTMRGEdgeTensor{<:Any, S, 3}, O::PEPSSandwich, + Etop::CTMRGEdgeTensor{<:Any, S, 3}, Ebot::CTMRGEdgeTensor{<:Any, S, 3}, + ) where {S} + return @autoopt @tensor v′[χ_NW D_W_above D_W_below; χ_SW] := + v[χ_NE D_E_above D_E_below; χ_SE] * + Etop[χ_NW D_N_above D_N_below; χ_NE] * + Ebot[χ_SE D_S_above D_S_below; χ_SW] * + ket(O)[d; D_N_above D_E_above D_S_above D_W_above] * + conj(bra(O)[d; D_N_below D_E_below D_S_below D_W_below]) +end +function edge_transfer_right( + v::CTMRGEdgeTensor{<:Any, S, 2}, O::PFTensor, + Etop::CTMRGEdgeTensor{<:Any, S, 2}, Ebot::CTMRGEdgeTensor{<:Any, S, 2}, + ) where {S} + return @autoopt @tensor v′[χ_NW D_W; χ_SW] := + v[χ_NE D_E; χ_SE] * + Etop[χ_NW D_N; χ_NE] * + Ebot[χ_SE D_S; χ_SW] * + O[D_W D_S; D_N D_E] end """ From 743fac6cf8675453bd07563f2d0290b8a8d782d1 Mon Sep 17 00:00:00 2001 From: Yue Zhengyuan Date: Thu, 2 Jul 2026 09:39:23 +0800 Subject: [PATCH 11/13] Right-to-left correlator contraction --- .../contractions/correlator/pepo_1layer.jl | 67 +++++++- .../contractions/correlator/pepo_purified.jl | 74 +++++++- .../contractions/correlator/peps.jl | 89 +++++++++- src/algorithms/contractions/transfer.jl | 89 ++++++++-- src/algorithms/correlator_adapters.jl | 159 ++++++++++++++---- test/utility/correlator.jl | 27 +-- 6 files changed, 435 insertions(+), 70 deletions(-) diff --git a/src/algorithms/contractions/correlator/pepo_1layer.jl b/src/algorithms/contractions/correlator/pepo_1layer.jl index 580f271d7..0ab0f9b00 100644 --- a/src/algorithms/contractions/correlator/pepo_1layer.jl +++ b/src/algorithms/contractions/correlator/pepo_1layer.jl @@ -1,4 +1,6 @@ -function start_correlator( +# -------- For left-to-right correlator contraction -------- + +function start_correlator_left( i::CartesianIndex{2}, ρ::InfinitePEPO, O::PFTensor, env::CTMRGEnv ) @@ -25,7 +27,7 @@ function start_correlator( return Vn, Vo end -function end_correlator_numerator( +function end_correlator_right_numerator( j::CartesianIndex{2}, V::CTMRGEdgeTensor{T, S, 3}, ρ::InfinitePEPO, O::PFTensor, env::CTMRGEnv ) where {T, S} @@ -44,7 +46,7 @@ function end_correlator_numerator( t[d1 d2; DN DE DS DW] * removeunit(O, 4)[dstring d2; d1] end -function end_correlator_denominator( +function end_correlator_right_denominator( j::CartesianIndex{2}, V::CTMRGEdgeTensor{T, S, 2}, env::CTMRGEnv ) where {T, S} r, c = Tuple(j) @@ -54,3 +56,62 @@ function end_correlator_denominator( return @autoopt @tensor V[χS DE; χN] * C_northeast[χN; χNE] * E_east[χNE DE; χSE] * C_southeast[χSE; χS] end + +# -------- For right-to-left correlator contraction -------- + +function start_correlator_right( + i::CartesianIndex{2}, ρ::InfinitePEPO, + O::PFTensor, env::CTMRGEnv + ) + (size(ρ, 3) == 1) || + throw(ArgumentError("The input PEPO ρ must have only one layer.")) + r, c = Tuple(i) + E_north = edge(env, NORTH, r - 1, c) + E_east = edge(env, EAST, r, c + 1) + E_south = edge(env, SOUTH, r + 1, c) + C_northeast = corner(env, NORTHEAST, r - 1, c + 1) + C_southeast = corner(env, SOUTHEAST, r + 1, c + 1) + t = twistdual(ρ[r, c], 1:2) + @autoopt @tensor Vn[χNW DW; χSW] := + E_south[χSSE DS; χSW] * E_east[χNEE DE; χSEE] * + E_north[χNW DN; χNNE] * C_northeast[χNNE; χNEE] * + C_southeast[χSEE; χSSE] * t[d d; DN DE DS DW] + @autoopt @tensor Vo[χNW DW dstring; χSW] := + E_south[χSSE DS; χSW] * E_east[χNEE DE; χSEE] * + E_north[χNW DN; χNNE] * C_northeast[χNNE; χNEE] * + C_southeast[χSEE; χSSE] * + removeunit(O, 1)[d2; d1 dstring] * t[d1 d2; DN DE DS DW] + return Vn, Vo +end + + +function end_correlator_left_numerator( + j::CartesianIndex{2}, V::CTMRGEdgeTensor{T, S, 3}, + ρ::InfinitePEPO, O::PFTensor, env::CTMRGEnv + ) where {T, S} + (size(ρ, 3) == 1) || + throw(ArgumentError("The input PEPO ρ must have only one layer.")) + r, c = Tuple(j) + E_north = edge(env, NORTH, r - 1, c) + E_south = edge(env, SOUTH, r + 1, c) + E_west = edge(env, WEST, r, c - 1) + C_northwest = corner(env, NORTHWEST, r - 1, c - 1) + C_southwest = corner(env, SOUTHWEST, r + 1, c - 1) + t = twistdual(ρ[r, c], 1:2) + return @autoopt @tensor V[χNE DE dstring; χSE] * + E_south[χSE DS; χSW2] * C_southwest[χSW2; χSW] * + E_west[χSW DW; χNW] * C_northwest[χNW; χN] * + E_north[χN DN; χNE] * + t[d1 d2; DN DE DS DW] * removeunit(O, 4)[dstring d2; d1] +end + +function end_correlator_left_denominator( + j::CartesianIndex{2}, V::CTMRGEdgeTensor{T, S, 2}, env::CTMRGEnv + ) where {T, S} + r, c = Tuple(j) + C_northwest = corner(env, NORTHWEST, r - 1, c - 1) + E_west = edge(env, WEST, r, c - 1) + C_southwest = corner(env, SOUTHWEST, r + 1, c - 1) + return @autoopt @tensor V[χN DE; χS] * C_southwest[χS; χSW] * + E_west[χSW DE; χNW] * C_northwest[χNW; χN] +end diff --git a/src/algorithms/contractions/correlator/pepo_purified.jl b/src/algorithms/contractions/correlator/pepo_purified.jl index 18e78bdf3..362342b5f 100644 --- a/src/algorithms/contractions/correlator/pepo_purified.jl +++ b/src/algorithms/contractions/correlator/pepo_purified.jl @@ -1,4 +1,6 @@ -function start_correlator( +# -------- For left-to-right correlator contraction -------- + +function start_correlator_left( i::CartesianIndex{2}, below::InfinitePEPO, O::MPOTensor, @@ -36,7 +38,7 @@ function start_correlator( return Vn, Vo end -function end_correlator_numerator( +function end_correlator_right_numerator( j::CartesianIndex{2}, V::AbstractTensorMap{T, S, 4, 1}, above::InfinitePEPO, @@ -63,3 +65,71 @@ function end_correlator_numerator( ket[dt a; DNt DEt DSt DWt] * removeunit(O, 4)[dstring db; dt] end + +# -------- For right-to-left correlator contraction -------- + +function start_correlator_right( + i::CartesianIndex{2}, + below::InfinitePEPO, + O::MPOTensor, + above::InfinitePEPO, + env::CTMRGEnv, + ) + r, c = Tuple(i) + E_north = edge(env, NORTH, r - 1, c) + E_east = edge(env, EAST, r, c + 1) + E_south = edge(env, SOUTH, r + 1, c) + C_northeast = corner(env, NORTHEAST, r - 1, c + 1) + C_southeast = corner(env, SOUTHEAST, r + 1, c + 1) + ket = twistdual(below[r, c], (1, 2)) + bra = above[r, c] + + @autoopt @tensor Vn[χNW DWtop DWbot; χSW] := + E_south[χSSE Dstop Dsbot; χSW] * + E_east[χNEE Detop Debot; χSEE] * + E_north[χNW Dntop Dnbot; χNNE] * + C_northeast[χNNE; χNEE] * + C_southeast[χSEE; χSSE] * + conj(bra[d a; Dnbot Debot Dsbot DWbot]) * + ket[d a; Dntop Detop Dstop DWtop] + + @autoopt @tensor Vo[χNW DWtop dstring DWbot; χSW] := + E_south[χSSE Dstop Dsbot; χSW] * + E_east[χNEE Detop Debot; χSEE] * + E_north[χNW Dntop Dnbot; χNNE] * + C_northeast[χNNE; χNEE] * + C_southeast[χSEE; χSSE] * + conj(bra[d1 a; Dnbot Debot Dsbot DWbot]) * + removeunit(O, 1)[d1; d2 dstring] * + ket[d2 a; Dntop Detop Dstop DWtop] + + return Vn, Vo +end + +function end_correlator_left_numerator( + j::CartesianIndex{2}, + V::AbstractTensorMap{T, S, 4, 1}, + above::InfinitePEPO, + O::MPOTensor, + below::InfinitePEPO, + env::CTMRGEnv, + ) where {T, S} + r, c = Tuple(j) + E_north = edge(env, NORTH, r - 1, c) + E_south = edge(env, SOUTH, r + 1, c) + E_west = edge(env, WEST, r, c - 1) + C_northwest = corner(env, NORTHWEST, r - 1, c - 1) + C_southwest = corner(env, SOUTHWEST, r + 1, c - 1) + ket = twistdual(above[r, c], (1, 2)) + bra = below[r, c] + + return @autoopt @tensor V[χNE DEt dstring DEb; χSE] * + E_south[χSE DSt DSb; χSW2] * + C_southwest[χSW2; χSW] * + E_west[χSW DWt DWb; χNW] * + C_northwest[χNW; χN] * + E_north[χN DNt DNb; χNE] * + conj(bra[db a; DNb DEb DSb DWb]) * + ket[dt a; DNt DEt DSt DWt] * + removeunit(O, 4)[dstring db; dt] +end diff --git a/src/algorithms/contractions/correlator/peps.jl b/src/algorithms/contractions/correlator/peps.jl index fafdd938a..39392d709 100644 --- a/src/algorithms/contractions/correlator/peps.jl +++ b/src/algorithms/contractions/correlator/peps.jl @@ -1,4 +1,6 @@ -function start_correlator( +# -------- For left-to-right correlator contraction -------- + +function start_correlator_left( i::CartesianIndex{2}, below::InfinitePEPS, O::MPOTensor, @@ -37,7 +39,7 @@ function start_correlator( return Vn, Vo end -function end_correlator_numerator( +function end_correlator_right_numerator( j::CartesianIndex{2}, V::AbstractTensorMap{T, S, 4, 1}, above::InfinitePEPS, @@ -64,7 +66,7 @@ function end_correlator_numerator( removeunit(O, 4)[dstring db; dt] end -function end_correlator_denominator( +function end_correlator_right_denominator( j::CartesianIndex{2}, V::AbstractTensorMap{T, S, 3, 1}, env::CTMRGEnv ) where {T, S} @@ -78,3 +80,84 @@ function end_correlator_denominator( E_east[χNE DEt DEb; χSE] * C_southeast[χSE; χS] end + +# -------- For right-to-left correlator contraction -------- + +function start_correlator_right( + i::CartesianIndex{2}, + below::InfinitePEPS, + O::MPOTensor, + above::InfinitePEPS, + env::CTMRGEnv, + ) + r, c = Tuple(i) + E_north = edge(env, NORTH, r - 1, c) + E_east = edge(env, EAST, r, c + 1) + E_south = edge(env, SOUTH, r + 1, c) + C_northeast = corner(env, NORTHEAST, r - 1, c + 1) + C_southeast = corner(env, SOUTHEAST, r + 1, c + 1) + sandwich = (below[r, c], above[r, c]) + + @autoopt @tensor Vn[χNW DWtop DWbot; χSW] := + E_south[χSSE Dstop Dsbot; χSW] * + E_east[χNEE Detop Debot; χSEE] * + E_north[χNW Dntop Dnbot; χNNE] * + C_northeast[χNNE; χNEE] * + C_southeast[χSEE; χSSE] * + conj(bra(sandwich)[d; Dnbot Debot Dsbot DWbot]) * + ket(sandwich)[d; Dntop Detop Dstop DWtop] + + @autoopt @tensor Vo[χNW DWtop dstring DWbot; χSW] := + E_south[χSSE Dstop Dsbot; χSW] * + E_east[χNEE Detop Debot; χSEE] * + E_north[χNW Dntop Dnbot; χNNE] * + C_northeast[χNNE; χNEE] * + C_southeast[χSEE; χSSE] * + conj(bra(sandwich)[d1; Dnbot Debot Dsbot DWbot]) * + removeunit(O, 1)[d1; d2 dstring] * + ket(sandwich)[d2; Dntop Detop Dstop DWtop] + + return Vn, Vo +end + +function end_correlator_left_numerator( + j::CartesianIndex{2}, + V::AbstractTensorMap{T, S, 4, 1}, + above::InfinitePEPS, + O::MPOTensor, + below::InfinitePEPS, + env::CTMRGEnv, + ) where {T, S} + r, c = Tuple(j) + E_north = edge(env, NORTH, r - 1, c) + E_south = edge(env, SOUTH, r + 1, c) + E_west = edge(env, WEST, r, c - 1) + C_northwest = corner(env, NORTHWEST, r - 1, c - 1) + C_southwest = corner(env, SOUTHWEST, r + 1, c - 1) + sandwich = (above[r, c], below[r, c]) + + return @autoopt @tensor V[χNE DEt dstring DEb; χSE] * + E_south[χSE DSt DSb; χSW2] * + C_southwest[χSW2; χSW] * + E_west[χSW DWt DWb; χNW] * + C_northwest[χNW; χN] * + E_north[χN DNt DNb; χNE] * + conj(bra(sandwich)[db; DNb DEb DSb DWb]) * + ket(sandwich)[dt; DNt DEt DSt DWt] * + removeunit(O, 4)[dstring db; dt] +end + +function end_correlator_left_denominator( + j::CartesianIndex{2}, V::AbstractTensorMap{T, S, 3, 1}, + env::CTMRGEnv + ) where {T, S} + r, c = Tuple(j) + C_northwest = corner(env, NORTHWEST, r - 1, c - 1) + E_west = edge(env, WEST, r, c - 1) + C_southwest = corner(env, SOUTHWEST, r + 1, c - 1) + + return @autoopt @tensor V[χN DEt DEb; χS] * + C_southwest[χS; χSW] * + E_west[χSW DEt DEb; χNW] * + C_northwest[χNW; χN] +end diff --git a/src/algorithms/contractions/transfer.jl b/src/algorithms/contractions/transfer.jl index c53bf98a9..11deadeb1 100644 --- a/src/algorithms/contractions/transfer.jl +++ b/src/algorithms/contractions/transfer.jl @@ -21,7 +21,7 @@ Apply an edge transfer matrix to the left. Etop::CTMRGEdgeTensor{<:Any, S, N₂}, Ebot::CTMRGEdgeTensor{<:Any, S, N₂} ) where {S, N₁, N₂} - t_out = tensorexpr(:v, -1, -(2:(N₁ + 1))) + t_out = tensorexpr(:v′, -1, -(2:(N₁ + 1))) t_top = tensorexpr(:Etop, 2:(N₂ + 1), -(N₁ + 1)) t_bot = tensorexpr(:Ebot, (-1, (3:(N₂ + 1))...), 1) t_in = tensorexpr(:v, 1, (-(2:N₁)..., 2)) @@ -47,7 +47,7 @@ Apply an edge transfer matrix to the right. Etop::CTMRGEdgeTensor{<:Any, S, N₂}, Ebot::CTMRGEdgeTensor{<:Any, S, N₂} ) where {S, N₁, N₂} - t_out = tensorexpr(:v, -1, -(2:(N₁ + 1))) + t_out = tensorexpr(:v′, -1, -(2:(N₁ + 1))) t_top = tensorexpr(:Etop, (-1, (3:(N₂ + 1))...), 1) t_bot = tensorexpr(:Ebot, (2, (3:(N₂ + 1))...), -(N₁ + 1)) t_in = tensorexpr(:v, 1, (-(2:N₁)..., 2)) @@ -70,12 +70,10 @@ Apply an edge transfer matrix to the left. ``` """ function edge_transfer_left( - v::CTMRGEdgeTensor{<:Any, S, 3}, - O::PEPSSandwich, - Etop::CTMRGEdgeTensor{<:Any, S, 3}, - Ebot::CTMRGEdgeTensor{<:Any, S, 3}, + v::CTMRGEdgeTensor{<:Any, S, 3}, O::PEPSSandwich, + Etop::CTMRGEdgeTensor{<:Any, S, 3}, Ebot::CTMRGEdgeTensor{<:Any, S, 3}, ) where {S} - return @autoopt @tensor v´[χ_SE D_E_above D_E_below; χ_NE] := + return @autoopt @tensor v′[χ_SE D_E_above D_E_below; χ_NE] := v[χ_SW D_W_above D_W_below; χ_NW] * Etop[χ_NW D_N_above D_N_below; χ_NE] * Ebot[χ_SE D_S_above D_S_below; χ_SW] * @@ -83,14 +81,12 @@ function edge_transfer_left( conj(bra(O)[d; D_N_below D_E_below D_S_below D_W_below]) end function edge_transfer_left( - v::CTMRGEdgeTensor{<:Any, S, 3}, - O::PEPOPurifiedSandwich, - Etop::CTMRGEdgeTensor{<:Any, S, 3}, - Ebot::CTMRGEdgeTensor{<:Any, S, 3}, + v::CTMRGEdgeTensor{<:Any, S, 3}, O::PEPOPurifiedSandwich, + Etop::CTMRGEdgeTensor{<:Any, S, 3}, Ebot::CTMRGEdgeTensor{<:Any, S, 3}, ) where {S} ket_tensor = twistdual(ket(O), (1, 2)) bra_tensor = bra(O) - return @autoopt @tensor v´[χ_SE D_E_above D_E_below; χ_NE] := + return @autoopt @tensor v′[χ_SE D_E_above D_E_below; χ_NE] := v[χ_SW D_W_above D_W_below; χ_NW] * Etop[χ_NW D_N_above D_N_below; χ_NE] * Ebot[χ_SE D_S_above D_S_below; χ_SW] * @@ -98,12 +94,10 @@ function edge_transfer_left( conj(bra_tensor[d a; D_N_below D_E_below D_S_below D_W_below]) end function edge_transfer_left( - v::CTMRGEdgeTensor{<:Any, S, 2}, - O::PFTensor, - Etop::CTMRGEdgeTensor{<:Any, S, 2}, - Ebot::CTMRGEdgeTensor{<:Any, S, 2}, + v::CTMRGEdgeTensor{<:Any, S, 2}, O::PFTensor, + Etop::CTMRGEdgeTensor{<:Any, S, 2}, Ebot::CTMRGEdgeTensor{<:Any, S, 2}, ) where {S} - return @autoopt @tensor v´[χ_SE D_E; χ_NE] := + return @autoopt @tensor v′[χ_SE D_E; χ_NE] := v[χ_SW D_W; χ_NW] * Etop[χ_NW D_N; χ_NE] * Ebot[χ_SE D_S; χ_SW] * @@ -134,6 +128,19 @@ function edge_transfer_right( ket(O)[d; D_N_above D_E_above D_S_above D_W_above] * conj(bra(O)[d; D_N_below D_E_below D_S_below D_W_below]) end +function edge_transfer_right( + v::CTMRGEdgeTensor{<:Any, S, 3}, O::PEPOPurifiedSandwich, + Etop::CTMRGEdgeTensor{<:Any, S, 3}, Ebot::CTMRGEdgeTensor{<:Any, S, 3}, + ) where {S} + ket_tensor = twistdual(ket(O), (1, 2)) + bra_tensor = bra(O) + return @autoopt @tensor v′[χ_NW D_W_above D_W_below; χ_SW] := + v[χ_NE D_E_above D_E_below; χ_SE] * + Etop[χ_NW D_N_above D_N_below; χ_NE] * + Ebot[χ_SE D_S_above D_S_below; χ_SW] * + ket_tensor[d a; D_N_above D_E_above D_S_above D_W_above] * + conj(bra_tensor[d a; D_N_below D_E_below D_S_below D_W_below]) +end function edge_transfer_right( v::CTMRGEdgeTensor{<:Any, S, 2}, O::PFTensor, Etop::CTMRGEdgeTensor{<:Any, S, 2}, Ebot::CTMRGEdgeTensor{<:Any, S, 2}, @@ -192,3 +199,51 @@ function edge_transfer_left( Ebot[χ_SE D_S; χ_SW] * O[D_W D_S; D_N D_E] end + +""" + transfer_right(v, O, Et, Eb) + +Apply an edge transfer matrix to the right on an excited vector.. + +``` +──Et─┐ + │ │ +──O──v- + │ │ +──qƎ─┘ +``` +""" +function edge_transfer_right( + v::CTMRGEdgeTensor{<:Any, S, 4}, O::PEPSSandwich, + Etop::CTMRGEdgeTensor{<:Any, S, 3}, Ebot::CTMRGEdgeTensor{<:Any, S, 3}, + ) where {S} + return @autoopt @tensor v′[χ_NW D_W_above d_string D_W_below; χ_SW] := + v[χ_NE D_E_above d_string D_E_below; χ_SE] * + Etop[χ_NW D_N_above D_N_below; χ_NE] * + Ebot[χ_SE D_S_above D_S_below; χ_SW] * + ket(O)[d; D_N_above D_E_above D_S_above D_W_above] * + conj(bra(O)[d; D_N_below D_E_below D_S_below D_W_below]) +end +function edge_transfer_right( + v::CTMRGEdgeTensor{<:Any, S, 4}, O::PEPOPurifiedSandwich, + Etop::CTMRGEdgeTensor{<:Any, S, 3}, Ebot::CTMRGEdgeTensor{<:Any, S, 3}, + ) where {S} + ket_tensor = twistdual(ket(O), (1, 2)) + bra_tensor = bra(O) + return @autoopt @tensor v′[χ_NW D_W_above d_string D_W_below; χ_SW] := + v[χ_NE D_E_above d_string D_E_below; χ_SE] * + Etop[χ_NW D_N_above D_N_below; χ_NE] * + Ebot[χ_SE D_S_above D_S_below; χ_SW] * + ket_tensor[d a; D_N_above D_E_above D_S_above D_W_above] * + conj(bra_tensor[d a; D_N_below D_E_below D_S_below D_W_below]) +end +function edge_transfer_right( + v::CTMRGEdgeTensor{<:Any, S, 3}, O::PFTensor, + Etop::CTMRGEdgeTensor{<:Any, S, 2}, Ebot::CTMRGEdgeTensor{<:Any, S, 2}, + ) where {S} + return @autoopt @tensor v′[χ_NW D_W d_string; χ_SW] := + v[χ_NE D_E d_string; χ_SE] * + Etop[χ_NW D_N; χ_NE] * + Ebot[χ_SE D_S; χ_SW] * + O[D_W D_S; D_N D_E] +end diff --git a/src/algorithms/correlator_adapters.jl b/src/algorithms/correlator_adapters.jl index 13eb92fd1..f2e695e51 100644 --- a/src/algorithms/correlator_adapters.jl +++ b/src/algorithms/correlator_adapters.jl @@ -44,6 +44,14 @@ struct _PEPOTraceCorrelator{P <: InfinitePEPO, E <: CTMRGEnv} end end +function _edge_transfermatrix(row::Int, col::Int, context::_BraketCorrelator) + return _edge_transfermatrix(row, col, context.bra, context.ket, context.env) +end + +function _edge_transfermatrix(row::Int, col::Int, context::_PEPOTraceCorrelator) + return _edge_transfermatrix(row, col, context.ρ, context.env) +end + function _correlator_scalartype(context::_BraketCorrelator, O::FiniteMPO) return TensorOperations.promote_contract( scalartype(context.bra), scalartype(context.ket), @@ -75,75 +83,165 @@ end Base.rotl90(context::_PEPOTraceCorrelator) = _PEPOTraceCorrelator(rotl90(context.ρ), rotl90(context.env)) -function _start_correlator( +# -------- For left-to-right correlator contraction -------- + +function _start_correlator_left( i::CartesianIndex{2}, context::_BraketCorrelator, O::MPOTensor ) - return start_correlator(i, context.bra, O, context.ket, context.env) + return start_correlator_left(i, context.bra, O, context.ket, context.env) end -function _start_correlator( +function _start_correlator_left( i::CartesianIndex{2}, context::_PEPOTraceCorrelator, O::PFTensor ) - return start_correlator(i, context.ρ, O, context.env) + return start_correlator_left(i, context.ρ, O, context.env) end -function _end_correlator_numerator( +function _end_correlator_right_numerator( j::CartesianIndex{2}, V::AbstractTensorMap{T, S, 4, 1}, context::_BraketCorrelator, O::MPOTensor, ) where {T, S} - return end_correlator_numerator(j, V, context.bra, O, context.ket, context.env) + return end_correlator_right_numerator(j, V, context.bra, O, context.ket, context.env) end -function _end_correlator_numerator( +function _end_correlator_right_numerator( j::CartesianIndex{2}, V::CTMRGEdgeTensor{T, S, 3}, context::_PEPOTraceCorrelator, O::PFTensor, ) where {T, S} - return end_correlator_numerator(j, V, context.ρ, O, context.env) + return end_correlator_right_numerator(j, V, context.ρ, O, context.env) end -function _edge_transfermatrix(row::Int, col::Int, context::_BraketCorrelator) - return _edge_transfermatrix(row, col, context.bra, context.ket, context.env) -end - -function _edge_transfermatrix(row::Int, col::Int, context::_PEPOTraceCorrelator) - return _edge_transfermatrix(row, col, context.ρ, context.env) +function _end_correlator_right_denominator( + j::CartesianIndex{2}, V::AbstractTensorMap, context + ) + return end_correlator_right_denominator(j, V, context.env) end -function _correlator_horizontal( - context, operator, - i::CartesianIndex{2}, js::AbstractVector{CartesianIndex{2}}, - ) - _issorted_correlator_sites(i, js) - O = FiniteMPO(operator) - length(O) == 2 || throw(ArgumentError("Operator must act on two sites")) - # preallocate with correct scalartype - G = similar(js, _correlator_scalartype(context, O)) +function _correlator_horizontal_right!(G, targets, context, O::FiniteMPO, i::CartesianIndex{2}) # left start for operator and norm contractions c = i # current column being handled - Vn, Vo = _start_correlator(c, context, O[1]) - j_last = last(js) - for (k, j) in enumerate(js) + Vn, Vo = _start_correlator_left(c, context, O[1]) + j_last = last(targets)[2] + for (k, j) in targets local numerator while j > c c += CartesianIndex(0, 1) if c == j - numerator = _end_correlator_numerator(j, Vo, context, O[2]) + numerator = _end_correlator_right_numerator(j, Vo, context, O[2]) end T = _edge_transfermatrix(c[1], c[2], context) c != j_last && (Vo = Vo * T) Vn = Vn * T end # compute overlap without operator - denominator = end_correlator_denominator(j, Vn, context.env) + denominator = _end_correlator_right_denominator(j, Vn, context) G[k] = numerator / denominator end return G end +# -------- For right-to-left correlator contraction -------- + +function _start_correlator_right( + i::CartesianIndex{2}, context::_BraketCorrelator, O::MPOTensor + ) + return start_correlator_right(i, context.bra, O, context.ket, context.env) +end + +function _start_correlator_right( + i::CartesianIndex{2}, context::_PEPOTraceCorrelator, O::PFTensor + ) + return start_correlator_right(i, context.ρ, O, context.env) +end + +function _end_correlator_left_numerator( + j::CartesianIndex{2}, + V::AbstractTensorMap{T, S, 4, 1}, + context::_BraketCorrelator, + O::MPOTensor, + ) where {T, S} + return end_correlator_left_numerator(j, V, context.bra, O, context.ket, context.env) +end + +function _end_correlator_left_numerator( + j::CartesianIndex{2}, + V::CTMRGEdgeTensor{T, S, 3}, + context::_PEPOTraceCorrelator, + O::PFTensor, + ) where {T, S} + return end_correlator_left_numerator(j, V, context.ρ, O, context.env) +end + +function _end_correlator_left_denominator( + j::CartesianIndex{2}, V::AbstractTensorMap, context + ) + return end_correlator_left_denominator(j, V, context.env) +end + +function _correlator_horizontal_left!(G, targets, context, O::FiniteMPO, i::CartesianIndex{2}) + # right start for operator and norm contractions + c = i # current column being handled + Vn, Vo = _start_correlator_right(c, context, O[1]) + j_last = last(targets)[2] + for (k, j) in targets + local numerator + while j < c + c -= CartesianIndex(0, 1) + if c == j + numerator = _end_correlator_left_numerator(j, Vo, context, O[2]) + end + T = _edge_transfermatrix(c[1], c[2], context) + c != j_last && (Vo = T * Vo) + Vn = T * Vn + end + # compute overlap without operator + denominator = _end_correlator_left_denominator(j, Vn, context) + G[k] = numerator / denominator + end + return G +end + +# -------- main correlator implementation -------- + +function _check_horizontal_correlator_sites( + i::CartesianIndex{2}, js::AbstractVector{CartesianIndex{2}} + ) + all(==(i[1]) ∘ first ∘ Tuple, js) || + throw(ArgumentError("Not a horizontal correlation function")) + all(!=(i), js) || + throw(ArgumentError("Correlator target sites must differ from the reference site")) + allunique(js) || + throw(ArgumentError("Correlator target sites must be unique")) + return true +end + +function _correlator_horizontal( + context, operator, + i::CartesianIndex{2}, js::AbstractVector{CartesianIndex{2}}, + ) + _check_horizontal_correlator_sites(i, js) + O = FiniteMPO(operator) + length(O) == 2 || throw(ArgumentError("Operator must act on two sites")) + # preallocate with correct scalartype + G = similar(js, _correlator_scalartype(context, O)) + # calculate correlator on the right and left separately + right_targets = sort( + filter(((k, j),) -> j[2] > i[2], collect(enumerate(js))); + by = x -> x[2][2] + ) + left_targets = sort( + filter(((k, j),) -> j[2] < i[2], collect(enumerate(js))); + by = x -> x[2][2], rev = true, + ) + isempty(right_targets) || _correlator_horizontal_right!(G, right_targets, context, O, i) + isempty(left_targets) || _correlator_horizontal_left!(G, left_targets, context, O, i) + return G +end + function _correlator_vertical(context, operator, i::CartesianIndex{2}, js) unitcell = _correlator_unitcell(context) rotated_i = siterotl90(i, unitcell) @@ -162,8 +260,3 @@ function _correlator( error("Only horizontal or vertical correlators are implemented") end end - -function _issorted_correlator_sites(i::CartesianIndex{2}, js::AbstractVector{CartesianIndex{2}}) - return issorted(vcat(i, js); by = last ∘ Tuple) || - throw(ArgumentError("Not an increasing sequence of coordinates")) -end diff --git a/test/utility/correlator.jl b/test/utility/correlator.jl index c78148e12..e5d4d2306 100644 --- a/test/utility/correlator.jl +++ b/test/utility/correlator.jl @@ -17,8 +17,8 @@ function get_spaces(sym::Type{<:Sector}) end site0 = CartesianIndex(1, 1) -site1xs = collect(site0 + CartesianIndex(0, i) for i in [1, 3, 4]) -site1ys = collect(site0 + CartesianIndex(i, 0) for i in [1, 3, 4]) +site1xs = collect(site0 + CartesianIndex(0, i) for i in [1, -1, 3, -2]) +site1ys = collect(site0 + CartesianIndex(i, 0) for i in [1, -1, 3, -2]) @testset "Correlator in InfinitePEPS ($(sym))" for sym in syms Random.seed!(100) @@ -39,10 +39,11 @@ site1ys = collect(site0 + CartesianIndex(i, 0) for i in [1, 3, 4]) @info vals2 @test vals1 ≈ vals2 end + @test_throws ArgumentError correlator(peps, op, site0, site0, env) end end -@testset "Correlator in 1-layer InfinitePEPO ($(sym))" for sym in syms +@testset "Correlator in purified InfinitePEPO ($(sym))" for sym in syms Random.seed!(100) Vphy, Venv, Nspaces, Espaces = get_spaces(sym) # TODO: test dual physical space @@ -50,22 +51,23 @@ end op = randn(ComplexF64, Vp ⊗ Vp → Vp ⊗ Vp) Pspaces = fill(Vp, size(Nspaces)) pepo = InfinitePEPO(randn, ComplexF64, Pspaces, Nspaces, Espaces) - pf = InfinitePartitionFunction(pepo) - env = CTMRGEnv(randn, ComplexF64, pf, Venv) + peps = InfinitePEPS(pepo) + env = CTMRGEnv(randn, ComplexF64, peps, Venv) for site1s in (site1xs, site1ys) - vals1 = correlator(pepo, op, site0, site1s, env) + vals1 = correlator(pepo, op, site0, site1s, pepo, env) vals2 = map(site1s) do site1 O = LocalOperator(Pspaces, (site0, site1) => op) - return expectation_value(pepo, O, env) + return expectation_value(pepo, O, pepo, env) end @info vals1 @info vals2 @test vals1 ≈ vals2 end + @test_throws ArgumentError correlator(pepo, op, site0, site0, pepo, env) end end -@testset "Correlator in purified InfinitePEPO ($(sym))" for sym in syms +@testset "Correlator in 1-layer InfinitePEPO ($(sym))" for sym in syms Random.seed!(100) Vphy, Venv, Nspaces, Espaces = get_spaces(sym) # TODO: test dual physical space @@ -73,17 +75,18 @@ end op = randn(ComplexF64, Vp ⊗ Vp → Vp ⊗ Vp) Pspaces = fill(Vp, size(Nspaces)) pepo = InfinitePEPO(randn, ComplexF64, Pspaces, Nspaces, Espaces) - peps = InfinitePEPS(pepo) - env = CTMRGEnv(randn, ComplexF64, peps, Venv) + pf = InfinitePartitionFunction(pepo) + env = CTMRGEnv(randn, ComplexF64, pf, Venv) for site1s in (site1xs, site1ys) - vals1 = correlator(pepo, op, site0, site1s, pepo, env) + vals1 = correlator(pepo, op, site0, site1s, env) vals2 = map(site1s) do site1 O = LocalOperator(Pspaces, (site0, site1) => op) - return expectation_value(pepo, O, pepo, env) + return expectation_value(pepo, O, env) end @info vals1 @info vals2 @test vals1 ≈ vals2 end + @test_throws ArgumentError correlator(pepo, op, site0, site0, env) end end From c9b8cbf8b336ed7cea25cc513209ff05ca9cc98b Mon Sep 17 00:00:00 2001 From: Yue Zhengyuan Date: Thu, 2 Jul 2026 09:59:50 +0800 Subject: [PATCH 12/13] Rework type annotation for V (contracted correlator part) --- .../contractions/correlator/pepo_1layer.jl | 8 +++---- src/algorithms/contractions/transfer.jl | 24 +++++++++---------- src/algorithms/correlator_adapters.jl | 4 ++-- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/algorithms/contractions/correlator/pepo_1layer.jl b/src/algorithms/contractions/correlator/pepo_1layer.jl index 0ab0f9b00..83924ff35 100644 --- a/src/algorithms/contractions/correlator/pepo_1layer.jl +++ b/src/algorithms/contractions/correlator/pepo_1layer.jl @@ -28,7 +28,7 @@ function start_correlator_left( end function end_correlator_right_numerator( - j::CartesianIndex{2}, V::CTMRGEdgeTensor{T, S, 3}, + j::CartesianIndex{2}, V::AbstractTensorMap{T, S, 3, 1}, ρ::InfinitePEPO, O::PFTensor, env::CTMRGEnv ) where {T, S} (size(ρ, 3) == 1) || @@ -47,7 +47,7 @@ function end_correlator_right_numerator( end function end_correlator_right_denominator( - j::CartesianIndex{2}, V::CTMRGEdgeTensor{T, S, 2}, env::CTMRGEnv + j::CartesianIndex{2}, V::AbstractTensorMap{T, S, 2, 1}, env::CTMRGEnv ) where {T, S} r, c = Tuple(j) C_northeast = corner(env, NORTHEAST, r - 1, c + 1) @@ -86,7 +86,7 @@ end function end_correlator_left_numerator( - j::CartesianIndex{2}, V::CTMRGEdgeTensor{T, S, 3}, + j::CartesianIndex{2}, V::AbstractTensorMap{T, S, 3, 1}, ρ::InfinitePEPO, O::PFTensor, env::CTMRGEnv ) where {T, S} (size(ρ, 3) == 1) || @@ -106,7 +106,7 @@ function end_correlator_left_numerator( end function end_correlator_left_denominator( - j::CartesianIndex{2}, V::CTMRGEdgeTensor{T, S, 2}, env::CTMRGEnv + j::CartesianIndex{2}, V::AbstractTensorMap{T, S, 2, 1}, env::CTMRGEnv ) where {T, S} r, c = Tuple(j) C_northwest = corner(env, NORTHWEST, r - 1, c - 1) diff --git a/src/algorithms/contractions/transfer.jl b/src/algorithms/contractions/transfer.jl index 11deadeb1..d21241292 100644 --- a/src/algorithms/contractions/transfer.jl +++ b/src/algorithms/contractions/transfer.jl @@ -70,7 +70,7 @@ Apply an edge transfer matrix to the left. ``` """ function edge_transfer_left( - v::CTMRGEdgeTensor{<:Any, S, 3}, O::PEPSSandwich, + v::AbstractTensorMap{<:Any, S, 3, 1}, O::PEPSSandwich, Etop::CTMRGEdgeTensor{<:Any, S, 3}, Ebot::CTMRGEdgeTensor{<:Any, S, 3}, ) where {S} return @autoopt @tensor v′[χ_SE D_E_above D_E_below; χ_NE] := @@ -81,7 +81,7 @@ function edge_transfer_left( conj(bra(O)[d; D_N_below D_E_below D_S_below D_W_below]) end function edge_transfer_left( - v::CTMRGEdgeTensor{<:Any, S, 3}, O::PEPOPurifiedSandwich, + v::AbstractTensorMap{<:Any, S, 3, 1}, O::PEPOPurifiedSandwich, Etop::CTMRGEdgeTensor{<:Any, S, 3}, Ebot::CTMRGEdgeTensor{<:Any, S, 3}, ) where {S} ket_tensor = twistdual(ket(O), (1, 2)) @@ -94,7 +94,7 @@ function edge_transfer_left( conj(bra_tensor[d a; D_N_below D_E_below D_S_below D_W_below]) end function edge_transfer_left( - v::CTMRGEdgeTensor{<:Any, S, 2}, O::PFTensor, + v::AbstractTensorMap{<:Any, S, 2, 1}, O::PFTensor, Etop::CTMRGEdgeTensor{<:Any, S, 2}, Ebot::CTMRGEdgeTensor{<:Any, S, 2}, ) where {S} return @autoopt @tensor v′[χ_SE D_E; χ_NE] := @@ -118,7 +118,7 @@ Apply an edge transfer matrix to the right. ``` """ function edge_transfer_right( - v::CTMRGEdgeTensor{<:Any, S, 3}, O::PEPSSandwich, + v::AbstractTensorMap{<:Any, S, 3, 1}, O::PEPSSandwich, Etop::CTMRGEdgeTensor{<:Any, S, 3}, Ebot::CTMRGEdgeTensor{<:Any, S, 3}, ) where {S} return @autoopt @tensor v′[χ_NW D_W_above D_W_below; χ_SW] := @@ -129,7 +129,7 @@ function edge_transfer_right( conj(bra(O)[d; D_N_below D_E_below D_S_below D_W_below]) end function edge_transfer_right( - v::CTMRGEdgeTensor{<:Any, S, 3}, O::PEPOPurifiedSandwich, + v::AbstractTensorMap{<:Any, S, 3, 1}, O::PEPOPurifiedSandwich, Etop::CTMRGEdgeTensor{<:Any, S, 3}, Ebot::CTMRGEdgeTensor{<:Any, S, 3}, ) where {S} ket_tensor = twistdual(ket(O), (1, 2)) @@ -142,7 +142,7 @@ function edge_transfer_right( conj(bra_tensor[d a; D_N_below D_E_below D_S_below D_W_below]) end function edge_transfer_right( - v::CTMRGEdgeTensor{<:Any, S, 2}, O::PFTensor, + v::AbstractTensorMap{<:Any, S, 2, 1}, O::PFTensor, Etop::CTMRGEdgeTensor{<:Any, S, 2}, Ebot::CTMRGEdgeTensor{<:Any, S, 2}, ) where {S} return @autoopt @tensor v′[χ_NW D_W; χ_SW] := @@ -166,7 +166,7 @@ Apply an edge transfer matrix to the left on an excited vector. ``` """ function edge_transfer_left( - v::CTMRGEdgeTensor{<:Any, S, 4}, O::PEPSSandwich, + v::AbstractTensorMap{<:Any, S, 4, 1}, O::PEPSSandwich, Etop::CTMRGEdgeTensor{<:Any, S, 3}, Ebot::CTMRGEdgeTensor{<:Any, S, 3}, ) where {S} return @autoopt @tensor v′[χ_SE D_E_above d_string D_E_below; χ_NE] := @@ -177,7 +177,7 @@ function edge_transfer_left( conj(bra(O)[d; D_N_below D_E_below D_S_below D_W_below]) end function edge_transfer_left( - v::CTMRGEdgeTensor{<:Any, S, 4}, O::PEPOPurifiedSandwich, + v::AbstractTensorMap{<:Any, S, 4, 1}, O::PEPOPurifiedSandwich, Etop::CTMRGEdgeTensor{<:Any, S, 3}, Ebot::CTMRGEdgeTensor{<:Any, S, 3}, ) where {S} ket_tensor = twistdual(ket(O), (1, 2)) @@ -190,7 +190,7 @@ function edge_transfer_left( conj(bra_tensor[d a; D_N_below D_E_below D_S_below D_W_below]) end function edge_transfer_left( - v::CTMRGEdgeTensor{<:Any, S, 3}, O::PFTensor, + v::AbstractTensorMap{<:Any, S, 3, 1}, O::PFTensor, Etop::CTMRGEdgeTensor{<:Any, S, 2}, Ebot::CTMRGEdgeTensor{<:Any, S, 2}, ) where {S} return @autoopt @tensor v′[χ_SE D_E d_string; χ_NE] := @@ -214,7 +214,7 @@ Apply an edge transfer matrix to the right on an excited vector.. ``` """ function edge_transfer_right( - v::CTMRGEdgeTensor{<:Any, S, 4}, O::PEPSSandwich, + v::AbstractTensorMap{<:Any, S, 4, 1}, O::PEPSSandwich, Etop::CTMRGEdgeTensor{<:Any, S, 3}, Ebot::CTMRGEdgeTensor{<:Any, S, 3}, ) where {S} return @autoopt @tensor v′[χ_NW D_W_above d_string D_W_below; χ_SW] := @@ -225,7 +225,7 @@ function edge_transfer_right( conj(bra(O)[d; D_N_below D_E_below D_S_below D_W_below]) end function edge_transfer_right( - v::CTMRGEdgeTensor{<:Any, S, 4}, O::PEPOPurifiedSandwich, + v::AbstractTensorMap{<:Any, S, 4, 1}, O::PEPOPurifiedSandwich, Etop::CTMRGEdgeTensor{<:Any, S, 3}, Ebot::CTMRGEdgeTensor{<:Any, S, 3}, ) where {S} ket_tensor = twistdual(ket(O), (1, 2)) @@ -238,7 +238,7 @@ function edge_transfer_right( conj(bra_tensor[d a; D_N_below D_E_below D_S_below D_W_below]) end function edge_transfer_right( - v::CTMRGEdgeTensor{<:Any, S, 3}, O::PFTensor, + v::AbstractTensorMap{<:Any, S, 3, 1}, O::PFTensor, Etop::CTMRGEdgeTensor{<:Any, S, 2}, Ebot::CTMRGEdgeTensor{<:Any, S, 2}, ) where {S} return @autoopt @tensor v′[χ_NW D_W d_string; χ_SW] := diff --git a/src/algorithms/correlator_adapters.jl b/src/algorithms/correlator_adapters.jl index f2e695e51..44e5311dd 100644 --- a/src/algorithms/correlator_adapters.jl +++ b/src/algorithms/correlator_adapters.jl @@ -108,7 +108,7 @@ end function _end_correlator_right_numerator( j::CartesianIndex{2}, - V::CTMRGEdgeTensor{T, S, 3}, + V::AbstractTensorMap{T, S, 3, 1}, context::_PEPOTraceCorrelator, O::PFTensor, ) where {T, S} @@ -169,7 +169,7 @@ end function _end_correlator_left_numerator( j::CartesianIndex{2}, - V::CTMRGEdgeTensor{T, S, 3}, + V::AbstractTensorMap{T, S, 3, 1}, context::_PEPOTraceCorrelator, O::PFTensor, ) where {T, S} From b87d161f664457f5347513949554b0d77db7939c Mon Sep 17 00:00:00 2001 From: Yue Zhengyuan Date: Thu, 2 Jul 2026 10:10:46 +0800 Subject: [PATCH 13/13] Update changelog --- docs/src/changelog.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/changelog.md b/docs/src/changelog.md index fed97b5a4..406d85613 100644 --- a/docs/src/changelog.md +++ b/docs/src/changelog.md @@ -24,12 +24,12 @@ When releasing a new version, move the "Unreleased" changes to a new version sec ### Changed +- In `correlator`, sites `js` are allowed on either side of the reference site `i` by adding right-to-left contractions (#399) + ### Deprecated ### Removed -- `edge_transfer_right` are not used anywhere and removed (#399) - ### Fixed ### Performance