From 11f5c41dbab36ccdf4396d3009ce5b3762403c24 Mon Sep 17 00:00:00 2001 From: leburgel Date: Fri, 3 Jan 2025 16:21:51 +0100 Subject: [PATCH 01/47] Add CTMRG support for regular 2D partition functions --- .DS_Store | Bin 6148 -> 0 bytes Project.toml | 3 +- src/PEPSKit.jl | 2 + .../contractions/ctmrg_contractions.jl | 456 ++++++++++++++++-- src/algorithms/ctmrg/ctmrg.jl | 27 ++ src/algorithms/ctmrg/sparse_environments.jl | 182 ++++++- src/algorithms/toolbox.jl | 40 ++ src/environments/ctmrg_environments.jl | 235 +++++++-- src/states/abstractpeps.jl | 14 +- src/states/infinitepartitionfunction.jl | 221 +++++++++ test/ctmrg/partition_function.jl | 134 +++++ test/runtests.jl | 3 + 12 files changed, 1233 insertions(+), 84 deletions(-) delete mode 100644 .DS_Store create mode 100644 src/states/infinitepartitionfunction.jl create mode 100644 test/ctmrg/partition_function.jl diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 900f40f7ff956b21d24f23dbfe96eca4e4dda795..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKyG|QH6g`7C!U~NGM?xr(_6wZ&4;JKfG(eZi@go?;)>^hfNHqHaDL_I3iH0(D zr2Im@0KOohr=#WEnaO&_YrC`%nk&tm)qU(edv!ha^O5zK_oYK7ZH#>;A1~dQ%VGCNu1Q|& zsxdF__q~~b6g&yUpbG$xm-TW@_b&Ogjb38W`wq$`S$97is4@K$j^v60KDlr)5pg>T-S3tgKX%*T3`AxIv z|6eDCDJT#Wc%2HUsBzHP;kDVlwQ!ZP*Tx)84l&8g4C)e2c01MwvK4P~Xk#pv17cz^ SGe{3Dd adjoint.(x)).(circshift(Ds_north, (-1, 0))) + Ds_west = (x -> adjoint.(x)).(circshift(Ds_east, (0, 1))) # do the whole thing + N = length(first(Ds_north)) st = _spacetype(first(Ds_north)) C_type = tensormaptype(st, 1, 1, T) - T_type = tensormaptype(st, 3, 1, T) + T_type = tensormaptype(st, N + 1, 1, T) # First index is direction corners = Array{C_type}(undef, 4, size(Ds_north)...) @@ -112,7 +129,6 @@ function CTMRGEnv( T, chis_north[r, _prev(c, end)], Ds_north[_next(r, end), c], - Ds_north[_next(r, end), c], chis_north[r, c], ) edges[EAST, r, c] = _edge_tensor( @@ -120,7 +136,6 @@ function CTMRGEnv( T, chis_east[r, c], Ds_east[r, _prev(c, end)], - Ds_east[r, _prev(c, end)], chis_east[_next(r, end), c], ) edges[SOUTH, r, c] = _edge_tensor( @@ -128,7 +143,6 @@ function CTMRGEnv( T, chis_south[r, c], Ds_south[_prev(r, end), c], - Ds_south[_prev(r, end), c], chis_south[r, _prev(c, end)], ) edges[WEST, r, c] = _edge_tensor( @@ -136,7 +150,6 @@ function CTMRGEnv( T, chis_west[_next(r, end), c], Ds_west[r, _next(c, end)], - Ds_west[r, _next(c, end)], chis_west[r, c], ) @@ -154,14 +167,13 @@ function CTMRGEnv( corners[:, :, :] ./= norm.(corners[:, :, :]) edges[:, :, :] ./= norm.(edges[:, :, :]) - return CTMRGEnv(corners, edges) end """ CTMRGEnv( - [f=randn, ComplexF64], D_north::S, D_east::S, chi_north::S, [chi_east::S], [chi_south::S], [chi_west::S]; unitcell::Tuple{Int,Int}=(1, 1), - ) where {S<:Union{Int,ElementarySpace}} + [f=randn, ComplexF64], D_north::P, D_east::P, chi_north::S, [chi_east::S], [chi_south::S], [chi_west::S]; unitcell::Tuple{Int,Int}=(1, 1), + ) where {P<:ProductSpaceLike,S<:ElementarySpaceLike} Construct a CTMRG environment by specifying the north and east virtual spaces of the corresponding [`InfinitePEPS`](@ref) and the north, east, south and west virtual spaces of @@ -172,14 +184,14 @@ The environment virtual spaces for each site correspond to virtual space of the corresponding edge tensor for each direction. """ function CTMRGEnv( - D_north::S, - D_east::S, + D_north::P, + D_east::P, chi_north::S, chi_east::S=chi_north, chi_south::S=chi_north, chi_west::S=chi_north; - unitcell::Tuple{Int,Int}=(1, 1), -) where {S<:Union{Int,ElementarySpace}} + unitcell::Tuple{Int,Int}=(1, 1) +) where {P<:ProductSpaceLike,S<:Union{Int,ElementarySpace}} return CTMRGEnv( randn, ComplexF64, @@ -194,23 +206,24 @@ end function CTMRGEnv( f, T, - D_north::S, - D_east::S, + D_north::P, + D_east::P, chi_north::S, chi_east::S=chi_north, chi_south::S=chi_north, chi_west::S=chi_north; unitcell::Tuple{Int,Int}=(1, 1), -) where {S<:Union{Int,ElementarySpace}} + ) where {P<:ProductSpaceLike,S<:Union{Int,ElementarySpace}} return CTMRGEnv( f, T, + N, fill(D_north, unitcell), fill(D_east, unitcell), fill(chi_north, unitcell), fill(chi_east, unitcell), fill(chi_south, unitcell), - fill(chi_west, unitcell), + fill(chi_west, unitcell) ) end @@ -237,12 +250,12 @@ function CTMRGEnv( chis_east::A=chis_north, chis_south::A=chis_north, chis_west::A=chis_north, -) where {A<:AbstractMatrix{<:Union{Int,ElementarySpace}}} +) where {A<:AbstractMatrix{<:ElementarySpaceLike}} Ds_north = map(peps.A) do t - return adjoint(space(t, 2)) + return (adjoint(space(t, 2)), space(t, 2)) end Ds_east = map(peps.A) do t - return adjoint(space(t, 3)) + return (adjoint(space(t, 3)), space(t, 3)) end return CTMRGEnv( randn, @@ -262,17 +275,86 @@ function CTMRGEnv( chis_north::A, chis_east::A=chis_north, chis_south::A=chis_north, - chis_west::A=chis_north, -) where {A<:AbstractMatrix{<:Union{Int,ElementarySpace}}} + chis_west::A=chis_north +) where {A<:AbstractMatrix{<:ElementarySpaceLike}} Ds_north = map(peps.A) do t - return adjoint(space(t, 2)) + return (adjoint(space(t, 2)), space(t, 2)) end Ds_east = map(peps.A) do t - return adjoint(space(t, 3)) + return (adjoint(space(t, 3)), space(t, 3)) + end + return CTMRGEnv( + f, + T, + Ds_north, + Ds_east, + _to_space.(chis_north), + _to_space.(chis_east), + _to_space.(chis_south), + _to_space.(chis_west), + ) +end + +""" + CTMRGEnv( + [f=randn, T=ComplexF64], partfunc::InfinitePartitionFunction, chis_north::A, [chis_east::A], [chis_south::A], [chis_west::A] + ) where {A<:AbstractMatrix{<:Union{Int,ElementarySpace}}} + +Construct a CTMRG environment by specifying a corresponding +[`InfinitePartitionFunction`](@ref), and the north, east, south and west virtual spaces of +the environment as matrices. Each respective matrix entry corresponds to a site in the unit +cell. By default, the virtual spaces for all directions are taken to be the same. + +The environment virtual spaces for each site correspond to the north or east virtual space +of the corresponding edge tensor for each direction. Specifically, for a given site +`(r, c)`, `chis_north[r, c]` corresponds to the east space of the north edge tensor, +`chis_east[r, c]` corresponds to the north space of the east edge tensor, +`chis_south[r, c]` corresponds to the east space of the south edge tensor, and +`chis_west[r, c]` corresponds to the north space of the west edge tensor. +""" +function CTMRGEnv( + partfunc::InfinitePartitionFunction, + chis_north::A, + chis_east::A=chis_north, + chis_south::A=chis_north, + chis_west::A=chis_north, +) where {A<:AbstractMatrix{<:ElementarySpaceLike}} + Ds_north = map(partfunc.A) do t + return (adjoint(space(t, 1)),) + end + Ds_east = map(partfunc.A) do t + return (adjoint(space(t, 2)),) + end + return CTMRGEnv( + randn, + ComplexF64, + Ds_north, + Ds_east, + _to_space.(chis_north), + _to_space.(chis_east), + _to_space.(chis_south), + _to_space.(chis_west), + ) +end +function CTMRGEnv( + f, + T, + partfunc::InfinitePartitionFunction, + chis_north::A, + chis_east::A=chis_north, + chis_south::A=chis_north, + chis_west::A=chis_north +) where {A<:AbstractMatrix{<:ElementarySpaceLike}} + Ds_north = map(partfunc.A) do t + return (adjoint(space(t, 1)),) + end + Ds_east = map(partfunc.A) do t + return (adjoint(space(t, 2)),) end return CTMRGEnv( f, T, + N, Ds_north, Ds_east, _to_space.(chis_north), @@ -300,7 +382,7 @@ function CTMRGEnv( chi_east::S=chi_north, chi_south::S=chi_north, chi_west::S=chi_north, -) where {S<:Union{Int,ElementarySpace}} +) where {S<:ElementarySpaceLike} return CTMRGEnv( peps, fill(chi_north, size(peps)), @@ -317,7 +399,7 @@ function CTMRGEnv( chi_east::S=chi_north, chi_south::S=chi_north, chi_west::S=chi_north, -) where {S<:Union{Int,ElementarySpace}} +) where {S<:ElementarySpaceLike} return CTMRGEnv( f, T, @@ -328,7 +410,56 @@ function CTMRGEnv( fill(chi_west, size(peps)), ) end + +""" + CTMRGEnv( + peps::InfinitePartitionFunction, chi_north::S, [chi_east::S], [chi_south::S], [chi_west::S], + ) where {S<:ElementarySpaceLike + +Construct a CTMRG environment by specifying a corresponding +[`InfinitePartitionFunction`](@ref), and the north, east, south and west virtual spaces of +the environment. By default, the virtual spaces for all directions are taken to be the same. + +The environment virtual spaces for each site correspond to virtual space of the +corresponding edge tensor for each direction. +""" +function CTMRGEnv( + partfunc::InfinitePartitionFunction, + chi_north::S, + chi_east::S=chi_north, + chi_south::S=chi_north, + chi_west::S=chi_north, +) where {S<:ElementarySpaceLike} + return CTMRGEnv( + partfunc, + fill(chi_north, size(partfunc)), + fill(chi_east, size(partfunc)), + fill(chi_south, size(partfunc)), + fill(chi_west, size(partfunc)), + ) +end +function CTMRGEnv( + f, + T, + partfunc::InfinitePartitionFunction, + chi_north::S, + chi_east::S=chi_north, + chi_south::S=chi_north, + chi_west::S=chi_north, +) where {S<:ElementarySpaceLike} + return CTMRGEnv( + f, + T, + partfunc, + fill(chi_north, size(partfunc)), + fill(chi_east, size(partfunc)), + fill(chi_south, size(partfunc)), + fill(chi_west, size(partfunc)), + ) +end + @non_differentiable CTMRGEnv(peps::InfinitePEPS, args...) +@non_differentiable CTMRGEnv(peps::InfinitePartitionFunction, args...) # Custom adjoint for CTMRGEnv constructor, needed for fixed-point differentiation function ChainRulesCore.rrule(::Type{CTMRGEnv}, corners, edges) diff --git a/src/states/abstractpeps.jl b/src/states/abstractpeps.jl index 93a27142..58413b83 100644 --- a/src/states/abstractpeps.jl +++ b/src/states/abstractpeps.jl @@ -6,6 +6,7 @@ conventionally ordered as: ``T : P ← N ⊗ E ⊗ S ⊗ W``. Here, ``P``, ``N`` ``W`` denote the physics, north, east, south and west spaces, respectively. """ const PEPSTensor{S} = AbstractTensorMap{S,1,4} where {S<:ElementarySpace} +const PartitionFunction{S} = AbstractTensorMap{S,2,2} where {S<:ElementarySpace} """ PEPSTensor(f, ::Type{T}, Pspace::S, Nspace::S, @@ -48,6 +49,13 @@ virtual indices, conventionally ordered as: O : P ⊗ P' ← N ⊗ E ⊗ S ⊗ W """ const PEPOTensor{S} = AbstractTensorMap{S,2,4} where {S<:ElementarySpace} +""" + abstract type AbstractPartitionFunction end + +Abstract supertype for a 2D projected entangled-pair state. +""" +abstract type AbstractPartitionFunction end + """ abstract type AbstractPEPS end @@ -63,10 +71,14 @@ Abstract supertype for a 2D projected entangled-pair operator. abstract type AbstractPEPO end # Rotations +Base.rotl90(t::PartitionFunction) = permute(t, ((2, 3), (1, 2))) +Base.rotr90(t::PartitionFunction) = permute(t, ((4, 1), (2, 3))) +Base.rot180(t::PartitionFunction) = permute(t, ((3, 4), (1, 2))) + Base.rotl90(t::PEPSTensor) = permute(t, ((1,), (3, 4, 5, 2))) Base.rotr90(t::PEPSTensor) = permute(t, ((1,), (5, 2, 3, 4))) Base.rot180(t::PEPSTensor) = permute(t, ((1,), (4, 5, 2, 3))) Base.rotl90(t::PEPOTensor) = permute(t, ((1, 2), (4, 5, 6, 3))) Base.rotr90(t::PEPOTensor) = permute(t, ((1, 2), (6, 3, 4, 5))) -Base.rot180(t::PEPOTensor) = permute(t, ((1, 2), (5, 6, 3, 4))) +Base.rot180(t::PEPOTensor) = permute(t, ((1, 2), (5, 6, 3, 4))) \ No newline at end of file diff --git a/src/states/infinitepartitionfunction.jl b/src/states/infinitepartitionfunction.jl new file mode 100644 index 00000000..5436806e --- /dev/null +++ b/src/states/infinitepartitionfunction.jl @@ -0,0 +1,221 @@ +""" + struct InfinitePartitionFunction{T<:PartitionFunction} + +Represents an infinite projected entangled-pair state on a 2D square lattice. +""" +struct InfinitePartitionFunction{T<:PartitionFunction} <: AbstractPartitionFunction + A::Matrix{T} + InfinitePartitionFunction{T}(A::Matrix{T}) where {T<:PartitionFunction} = new{T}(A) + function InfinitePartitionFunction(A::Array{T,2}) where {T<:PartitionFunction} + for (d, w) in Tuple.(CartesianIndices(A)) + space(A[d, w], 1) == space(A[_prev(d, end), w], 3)' || throw( + SpaceMismatch("North virtual space at site $((d, w)) does not match.") + ) + space(A[d, w], 2) == space(A[d, _next(w, end)], 4)' || + throw(SpaceMismatch("East virtual space at site $((d, w)) does not match.")) + dim(space(A[d, w])) > 0 || @warn "no fusion channels at site ($d, $w)" + end + return new{T}(A) + end +end + +## Constructors +""" + InfinitePartitionFunction(A::AbstractMatrix{T}) + +Create an `InfinitePartitionFunction` by specifying a matrix containing the PEPS tensors at each site in +the unit cell. +""" +function InfinitePartitionFunction(A::AbstractMatrix{T}) where {T<:PartitionFunction} + return InfinitePartitionFunction(Array(deepcopy(A))) # TODO: find better way to copy +end + +""" + InfinitePartitionFunction( + f=randn, T=ComplexF64, Pspaces::A, Nspaces::A, [Espaces::A] + ) where {A<:AbstractMatrix{<:Union{Int,ElementarySpace}}} + +Create an `InfinitePartitionFunction` by specifying the physical, north virtual and east virtual spaces +of the PEPS tensor at each site in the unit cell as a matrix. Each individual space can be +specified as either an `Int` or an `ElementarySpace`. +""" +function InfinitePartitionFunction( + Nspaces::A, Espaces::A +) where {A<:AbstractMatrix{<:Union{Int,ElementarySpace}}} + return InfinitePartitionFunction(randn, ComplexF64, Nspaces, Espaces) +end +function InfinitePartitionFunction( + f, T, Nspaces::M, Espaces::M=Nspaces +) where {M<:AbstractMatrix{<:Union{Int,ElementarySpace}}} + size(Nspaces) == size(Espaces) || + throw(ArgumentError("Input spaces should have equal sizes.")) + + Sspaces = adjoint.(circshift(Nspaces, (-1, 0))) + Wspaces = adjoint.(circshift(Espaces, (0, 1))) + + A = map(Nspaces, Espaces, Sspaces, Wspaces) do P, N, E, S, W + return PartitionFunction(f, T, N, E, S, W) + end + + return InfinitePartitionFunction(A) +end + +""" + InfinitePartitionFunction(A; unitcell=(1, 1)) + +Create an `InfinitePartitionFunction` by specifying a tensor and unit cell. + +The unit cell is labeled as a matrix which means that any tensor in the unit cell, +regardless if PEPS tensor or environment tensor, is obtained by shifting the row +and column index `[r, c]` by one, respectively: +``` + | | | +---C[r-1,c-1]---T[r-1,c]---T[r-1,c+1]--- + | || || +---T[r,c-1]=====AA[r,c]====AA[r,c+1]==== + | || || +---T[r+1,c-1]===AA[r+1,c]==AA[r+1,c+1]== + | || || +``` +The unit cell has periodic boundary conditions, so `[r, c]` is indexed modulo the +size of the unit cell. +""" +function InfinitePartitionFunction(A::T; unitcell::Tuple{Int,Int}=(1, 1)) where {T<:PartitionFunction} + return InfinitePartitionFunction(fill(A, unitcell)) +end + +""" + InfinitePartitionFunction(f=randn, T=ComplexF64, Pspace, Nspace, [Espace]; unitcell=(1,1)) + +Create an InfinitePartitionFunction by specifying its physical, north and east spaces and unit cell. +Spaces can be specified either via `Int` or via `ElementarySpace`. +""" +function InfinitePartitionFunction( + Nspace::S, Espace::S=Nspace; unitcell::Tuple{Int,Int}=(1, 1) +) where {S<:Union{ElementarySpace,Int}} + return InfinitePartitionFunction( + randn, + ComplexF64, + fill(Nspace, unitcell), + fill(Espace, unitcell), + ) +end +function InfinitePartitionFunction( + f, T, Nspace::S, Espace::S=Nspace; unitcell::Tuple{Int,Int}=(1, 1) +) where {S<:Union{ElementarySpace,Int}} + return InfinitePartitionFunction( + f, T, fill(Nspace, unitcell), fill(Espace, unitcell) + ) +end + +## Shape and size +Base.size(T::InfinitePartitionFunction) = size(T.A) +Base.size(T::InfinitePartitionFunction, i) = size(T.A, i) +Base.length(T::InfinitePartitionFunction) = length(T.A) +Base.eltype(T::InfinitePartitionFunction) = eltype(typeof(T)) +Base.eltype(::Type{<:InfinitePartitionFunction{T}}) where {T} = T +VectorInterface.scalartype(::Type{T}) where {T<:InfinitePartitionFunction} = scalartype(eltype(T)) + +## Copy +Base.copy(T::InfinitePartitionFunction) = InfinitePartitionFunction(copy(T.A)) +Base.similar(T::InfinitePartitionFunction, args...) = InfinitePartitionFunction(similar(T.A, args...)) +Base.repeat(T::InfinitePartitionFunction, counts...) = InfinitePartitionFunction(repeat(T.A, counts...)) + +Base.getindex(T::InfinitePartitionFunction, args...) = Base.getindex(T.A, args...) +Base.setindex!(T::InfinitePartitionFunction, args...) = (Base.setindex!(T.A, args...); T) +Base.axes(T::InfinitePartitionFunction, args...) = axes(T.A, args...) +function eachcoordinate(x::InfinitePartitionFunction) + return collect(Iterators.product(axes(x)...)) +end +function eachcoordinate(x::InfinitePartitionFunction, dirs) + return collect(Iterators.product(dirs, axes(x, 1), axes(x, 2))) +end +TensorKit.space(t::InfinitePartitionFunction, i, j) = space(t[i, j], 1) + +## Math +Base.:+(ψ₁::InfinitePartitionFunction, ψ₂::InfinitePartitionFunction) = InfinitePartitionFunction(ψ₁.A + ψ₂.A) +Base.:-(ψ₁::InfinitePartitionFunction, ψ₂::InfinitePartitionFunction) = InfinitePartitionFunction(ψ₁.A - ψ₂.A) +Base.:*(α::Number, ψ::InfinitePartitionFunction) = InfinitePartitionFunction(α * ψ.A) +Base.:/(ψ::InfinitePartitionFunction, α::Number) = InfinitePartitionFunction(ψ.A / α) +LinearAlgebra.dot(ψ₁::InfinitePartitionFunction, ψ₂::InfinitePartitionFunction) = dot(ψ₁.A, ψ₂.A) +LinearAlgebra.norm(ψ::InfinitePartitionFunction) = norm(ψ.A) + +## (Approximate) equality +function Base.:(==)(ψ₁::InfinitePartitionFunction, ψ₂::InfinitePartitionFunction) + return all(zip(ψ₁.A, ψ₂.A)) do (p₁, p₂) + return p₁ == p₂ + end +end +function Base.isapprox(ψ₁::InfinitePartitionFunction, ψ₂::InfinitePartitionFunction; kwargs...) + return all(zip(ψ₁.A, ψ₂.A)) do (p₁, p₂) + return isapprox(p₁, p₂; kwargs...) + end +end + +# Used in _scale during OptimKit.optimize +function LinearAlgebra.rmul!(ψ::InfinitePartitionFunction, α::Number) + rmul!(ψ.A, α) + return ψ +end + +# Used in _add during OptimKit.optimize +function LinearAlgebra.axpy!(α::Number, ψ₁::InfinitePartitionFunction, ψ₂::InfinitePartitionFunction) + ψ₂.A .+= α * ψ₁.A + return ψ₂ +end + +# VectorInterface +VectorInterface.zerovector(x::InfinitePartitionFunction) = InfinitePartitionFunction(zerovector(x.A)) + +# Rotations +Base.rotl90(t::InfinitePartitionFunction) = InfinitePartitionFunction(rotl90(rotl90.(t.A))) +Base.rotr90(t::InfinitePartitionFunction) = InfinitePartitionFunction(rotr90(rotr90.(t.A))) +Base.rot180(t::InfinitePartitionFunction) = InfinitePartitionFunction(rot180(rot180.(t.A))) + +# Chainrules +function ChainRulesCore.rrule( + ::typeof(Base.getindex), state::InfinitePartitionFunction, row::Int, col::Int +) + PartitionFunction = state[row, col] + + function getindex_pullback(ΔPartitionFunction) + Δstate = zerovector(state) + Δstate[row, col] = ΔPartitionFunction + return NoTangent(), Δstate, NoTangent(), NoTangent() + end + return PartitionFunction, getindex_pullback +end + +function ChainRulesCore.rrule(::Type{<:InfinitePartitionFunction}, A::Matrix{T}) where {T<:PartitionFunction} + peps = InfinitePartitionFunction(A) + function InfinitePartitionFunction_pullback(Δpeps) + return NoTangent(), Δpeps.A + end + return peps, InfinitePartitionFunction_pullback +end + +function ChainRulesCore.rrule(::typeof(rotl90), peps::InfinitePartitionFunction) + peps′ = rotl90(peps) + function rotl90_pullback(Δpeps) + return NoTangent(), rotr90(Δpeps) + end + return peps′, rotl90_pullback +end + +function ChainRulesCore.rrule(::typeof(rotr90), peps::InfinitePartitionFunction) + peps′ = rotr90(peps) + function rotr90_pullback(Δpeps) + return NoTangent(), rotl90(Δpeps) + end + return peps′, rotr90_pullback +end + +# FiniteDifferences +# Makes use of tensors already having a to_vec method +function FiniteDifferences.to_vec(state::InfinitePartitionFunction) + vec, back = FiniteDifferences.to_vec(state.A) + function state_from_vec(vec) + return InfinitePartitionFunction(back(vec)) + end + return vec, state_from_vec +end \ No newline at end of file diff --git a/test/ctmrg/partition_function.jl b/test/ctmrg/partition_function.jl new file mode 100644 index 00000000..500cada2 --- /dev/null +++ b/test/ctmrg/partition_function.jl @@ -0,0 +1,134 @@ +using Test +using PEPSKit +using TensorKit +using LinearAlgebra +using QuadGK +using MPSKit + +using PEPSKit: @autoopt, CTMRGEdgeTensor, NORTHWEST, NORTHEAST, SOUTHEAST, SOUTHWEST, WEST, EAST, NORTH, SOUTH + +## Setup + +""" + ising_exact(beta, J) + +[Exact Onsager solution](https://en.wikipedia.org/wiki/Square_lattice_Ising_model#Exact_solution) +for the 2D classical Ising Model with partition function + +```math +\\mathcal{Z}(\\beta) = \\sum_{\\{s\\}} \\exp(-\\beta H(s)) \\text{ with } H(s) = -J \\sum_{\\langle i, j \\rangle} s_i s_j +``` +""" +function classical_ising_exact(; beta=log(1 + sqrt(2)) / 2, J=1.0) + K = beta * J + + k = 1 / sinh(2 * K)^2 + F = quadgk(theta -> log(cosh(2 * K)^2 + 1 / k * sqrt(1 + k^2 - 2 * k * cos(2 * theta))), 0, pi)[1] + f = -1 / beta * (log(2) / 2 + 1 / (2 * pi) * F) + + m = 1 - (sinh(2 * K))^(-4) > 0 ? (1 - (sinh(2 * K))^(-4))^(1/8) : 0 + + E = quadgk(theta -> 1 / sqrt(1 - (4 * k) * (1 + k)^(-2) * sin(theta)^2), 0, pi/2)[1] + e = -J * cosh(2 * K) / sinh(2 * K) * (1 + 2 / pi * (2 * tanh(2 * K)^2 - 1) * E) + + return f, m, e +end + +""" + classical_ising(; beta=log(1 + sqrt(2)) / 2) + +Implements the 2D classical Ising model with partition function + +```math +\\mathcal{Z}(\\beta) = \\sum_{\\{s\\}} \\exp(-\\beta H(s)) \\text{ with } H(s) = -J \\sum_{\\langle i, j \\rangle} s_i s_j +``` +""" +function classical_ising(; beta=log(1 + sqrt(2)) / 2, J=1.0) + K = beta * J + # Boltzmann weights + t = ComplexF64[exp(K) exp(-K); exp(-K) exp(K)] + r = eigen(t) + nt = r.vectors * sqrt(LinearAlgebra.Diagonal(r.values)) * r.vectors + + # local partition function tensor + O = zeros(2, 2, 2, 2) + O[1, 1, 1, 1] = 1 + O[2, 2, 2, 2] = 1 + @tensor o[-1 -2; -3 -4] := O[1 2; 3 4] * nt[-1; 1] * nt[-2; 2] * nt[-3; 3] * nt[-4; 4] + + # magnetization tensor + M = copy(O) + M[2, 2, 2, 2] *= -1 + @tensor m[-1 -2; -3 -4] := M[1 2; 3 4] * nt[-1; 1] * nt[-2; 2] * nt[-3; 3] * nt[-4; 4] + + # bond interaction tensor and energy-per-site tensor + e = ComplexF64[-J J; J -J] .* nt + @tensor e_hor[-1 -2; -3 -4] := O[1 2; 3 4] * nt[-1; 1] * nt[-2; 2] * nt[-3; 3] * e[-4; 4] + @tensor e_vert[-1 -2; -3 -4] := O[1 2; 3 4] * nt[-1; 1] * nt[-2; 2] * e[-3; 3] * nt[-4; 4] + e = e_hor + e_vert + + # fixed tensor map space for all three + TMS = ℂ^2 ⊗ ℂ^2 ← ℂ^2 ⊗ ℂ^2 + + return TensorMap(o, TMS), TensorMap(m, TMS), TensorMap(e, TMS) +end + +""" +Contract a local rank-4 tensor with a given partition function environment. +""" +function local_contraction( + O::AbstractTensorMap{S,2,2}, + env::CTMRGEnv{C,<:CTMRGEdgeTensor{S,2}}, +) where {S,C} + return @autoopt @tensor env.corners[NORTHWEST, 1, 1][C_WNW; C_NNW] * + env.edges[NORTH, 1, 1][C_NNW D_N; C_NNE] * + env.corners[NORTHEAST, 1, 1][C_NNE; C_ENE] * + env.edges[EAST, 1, 1][C_ENE D_E; C_ESE] * + env.corners[SOUTHEAST, 1, 1][C_ESE; C_SSE] * + env.edges[SOUTH, 1, 1][C_SSE D_S; C_SSW] * + env.corners[SOUTHWEST, 1, 1][C_SSW; C_WSW] * + env.edges[WEST, 1, 1][C_WSW D_W; C_WNW] * + O[D_N D_E; D_S D_W] + # O[D_W D_S; D_N D_E] # TODO: switch to this convention +end + +## Test + +# initialize + +beta = 0.5 +O, M, E = classical_ising(; beta) +Z = InfinitePartitionFunction(O) + +# contract + +χenv = ℂ^12 +env0 = CTMRGEnv(Z, χenv) + +ctm_alg = CTMRG(; + tol=1e-10, + miniter=4, + maxiter=100, + verbosity=2, + ctmrgscheme=:simultaneous, +) + +env = leading_boundary(env0, Z, ctm_alg) + +# check observables + +λ = norm(Z, env) +m = local_contraction(M, env) / local_contraction(O, env) +e = local_contraction(E, env) / local_contraction(O, env) + +f_exact, m_exact, e_exact = classical_ising_exact(; beta) + +# should be real-ish +@test abs(imag(λ)) < 1e-4 +@test abs(imag(m)) < 1e-4 +@test abs(imag(e)) < 1e-4 + +# should match exact solution +@test -log(λ) / beta ≈ f_exact rtol = 1e-5 +@test abs(m) ≈ abs(m_exact) rtol = 1e-5 +@test e ≈ e_exact rtol = 1e-2 diff --git a/test/runtests.jl b/test/runtests.jl index c80a4b43..f520e3fe 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -29,6 +29,9 @@ end @time @safetestset "Flavors" begin include("ctmrg/flavors.jl") end + @time @safetestset "Partition function" begin + include("ctmrg/partition_function.jl") + end end if GROUP == "ALL" || GROUP == "BOUNDARYMPS" @time @safetestset "VUMPS" begin From 7a710951f5d7ea2a461cb1e181e60dc29a33339e Mon Sep 17 00:00:00 2001 From: leburgel Date: Fri, 3 Jan 2025 17:11:07 +0100 Subject: [PATCH 02/47] Format --- .../contractions/ctmrg_contractions.jl | 94 ++++++------------- src/algorithms/ctmrg/ctmrg.jl | 4 +- src/algorithms/ctmrg/sparse_environments.jl | 42 +++------ src/environments/ctmrg_environments.jl | 52 ++++------ src/states/abstractpeps.jl | 2 +- src/states/infinitepartitionfunction.jl | 55 +++++++---- test/ctmrg/partition_function.jl | 55 ++++++----- test/runtests.jl | 2 +- 8 files changed, 132 insertions(+), 174 deletions(-) diff --git a/src/algorithms/contractions/ctmrg_contractions.jl b/src/algorithms/contractions/ctmrg_contractions.jl index f6d9d79e..5200cedb 100644 --- a/src/algorithms/contractions/ctmrg_contractions.jl +++ b/src/algorithms/contractions/ctmrg_contractions.jl @@ -49,15 +49,13 @@ function enlarge_northwest_corner( E_west = envs.edges[WEST, row, _prev(col, end)] C_northwest = envs.corners[NORTHWEST, _prev(row, end), _prev(col, end)] E_north = envs.edges[NORTH, _prev(row, end), col] - return enlarge_northwest_corner( - E_west, C_northwest, E_north, partfunc[row, col] - ) + return enlarge_northwest_corner(E_west, C_northwest, E_north, partfunc[row, col]) end function enlarge_northwest_corner( E_west::CTMRGEdgeTensor{S,2}, C_northwest::CTMRGCornerTensor, E_north::CTMRGEdgeTensor{S,2}, - partfunc::PartitionFunction + partfunc::PartitionFunction, ) where {S} return @autoopt @tensor corner[χ_S D_S; χ_E D_E] := E_west[χ_S D1; χ1] * @@ -111,15 +109,13 @@ function enlarge_northeast_corner( E_north = envs.edges[NORTH, _prev(row, end), col] C_northeast = envs.corners[NORTHEAST, _prev(row, end), _next(col, end)] E_east = envs.edges[EAST, row, _next(col, end)] - return enlarge_northeast_corner( - E_north, C_northeast, E_east, partfunc[row, col] - ) + return enlarge_northeast_corner(E_north, C_northeast, E_east, partfunc[row, col]) end function enlarge_northeast_corner( E_north::CTMRGEdgeTensor{S,2}, C_northeast::CTMRGCornerTensor, E_east::CTMRGEdgeTensor{S,2}, - partfunc::PartitionFunction + partfunc::PartitionFunction, ) where {S} return @autoopt @tensor corner[χ_W D_W; χ_S D_S] := E_north[χ_W D1; χ1] * @@ -173,15 +169,13 @@ function enlarge_southeast_corner( E_east = envs.edges[EAST, row, _next(col, end)] C_southeast = envs.corners[SOUTHEAST, _next(row, end), _next(col, end)] E_south = envs.edges[SOUTH, _next(row, end), col] - return enlarge_southeast_corner( - E_east, C_southeast, E_south, partfunc[row, col] - ) + return enlarge_southeast_corner(E_east, C_southeast, E_south, partfunc[row, col]) end function enlarge_southeast_corner( E_east::CTMRGEdgeTensor{S,2}, C_southeast::CTMRGCornerTensor, E_south::CTMRGEdgeTensor{S,2}, - partfunc::PartitionFunction + partfunc::PartitionFunction, ) where {S} return @autoopt @tensor corner[χ_N D_N; χ_W D_W] := E_east[χ_N D1; χ1] * @@ -235,15 +229,13 @@ function enlarge_southwest_corner( E_south = envs.edges[SOUTH, _next(row, end), col] C_southwest = envs.corners[SOUTHWEST, _next(row, end), _prev(col, end)] E_west = envs.edges[WEST, row, _prev(col, end)] - return enlarge_southwest_corner( - E_south, C_southwest, E_west, partfunc[row, col] - ) + return enlarge_southwest_corner(E_south, C_southwest, E_west, partfunc[row, col]) end function enlarge_southwest_corner( E_south::CTMRGEdgeTensor{S,2}, C_southwest::CTMRGCornerTensor, E_west::CTMRGEdgeTensor{S,2}, - partfunc::PartitionFunction + partfunc::PartitionFunction, ) where {S} return @autoopt @tensor corner[χ_E D_E; χ_N D_N] := E_south[χ_E D1; χ1] * @@ -280,12 +272,9 @@ end function left_projector(E_1, C, E_2, V, isqS, partfunc::PartitionFunction) return @autoopt @tensor P_left[χ_in D_in; χ_out] := - E_1[χ_in D1; χ1] * - C[χ1; χ2] * - E_2[χ2 D2; χ3] * - partfunc[D2 D3; D_in D1] - conj(V[χ4; χ3 D3]) - isqS[χ4; χ_out] + E_1[χ_in D1; χ1] * C[χ1; χ2] * E_2[χ2 D2; χ3] * partfunc[D2 D3; D_in D1] + conj(V[χ4; χ3 D3]) + return isqS[χ4; χ_out] end """ @@ -313,12 +302,8 @@ end function right_projector(E_1, C, E_2, U, isqS, partfunc::PartitionFunction) return @autoopt @tensor P_right[χ_in; χ_out D_out] := - isqS[χ_in; χ1] * - conj(U[χ1; χ2 D1]) * - partfunc[D2 D3; D_out D1] - E_2[χ2 D2; χ3] * - C[χ3; χ4] * - E_1[χ4 D3; χ_out] + isqS[χ_in; χ1] * conj(U[χ1; χ2 D1]) * partfunc[D2 D3; D_out D1] + return E_2[χ2 D2; χ3] * C[χ3; χ4] * E_1[χ4 D3; χ_out] end """ @@ -399,8 +384,7 @@ function halfinfinite_environment( quadrant1::AbstractTensorMap{S,2,2}, quadrant2::AbstractTensorMap{S,2,2} ) where {S} return @autoopt @tensor env[χ_in D_in; χ_out D_out] := - quadrant1[χ_in D_in; χ D1] * - quadrant2[χ D1; χ_out D_out] + quadrant1[χ_in D_in; χ D1] * quadrant2[χ D1; χ_out D_out] end function halfinfinite_environment( @@ -461,15 +445,7 @@ function halfinfinite_environment( end function halfinfinite_environment( - C_1, - C_2, - E_1, - E_2, - E_3, - E_4, - x::AbstractTensor{S,2}, - partfunc_1::P, - partfunc_2::P, + C_1, C_2, E_1, E_2, E_3, E_4, x::AbstractTensor{S,2}, partfunc_1::P, partfunc_2::P ) where {S,P<:PartitionFunction} return @autoopt @tensor env_x[χ_in D_in] := E_1[χ_in D1; χ1] * @@ -739,15 +715,7 @@ function full_infinite_environment( end function halfinfinite_environment( - x::AbstractTensor{S,2}, - C_1, - C_2, - E_1, - E_2, - E_3, - E_4, - partfunc_1::P, - partfunc_2::P, + x::AbstractTensor{S,2}, C_1, C_2, E_1, E_2, E_3, E_4, partfunc_1::P, partfunc_2::P ) where {S,P<:PartitionFunction} return @autoopt @tensor env_x[χ_in D_in] := x[χ1 D1 D2] * @@ -1049,14 +1017,18 @@ Apply bottom projector to southwest corner and south edge. C -- E -- in ``` """ -function renormalize_bottom_corner((row, col), envs::CTMRGEnv{C,<:CTMRGEdgeTensor{S,3}}, projectors) where {C,S} +function renormalize_bottom_corner( + (row, col), envs::CTMRGEnv{C,<:CTMRGEdgeTensor{S,3}}, projectors +) where {C,S} C_southwest = envs.corners[SOUTHWEST, row, _prev(col, end)] E_south = envs.edges[SOUTH, row, col] P_bottom = projectors[1][row] return @autoopt @tensor corner[χ_in; χ_out] := E_south[χ_in D1 D2; χ1] * C_southwest[χ1; χ2] * P_bottom[χ2 D1 D2; χ_out] end -function renormalize_bottom_corner((row, col), envs::CTMRGEnv{C,<:CTMRGEdgeTensor{S,2}}, projectors) where {C,S} +function renormalize_bottom_corner( + (row, col), envs::CTMRGEnv{C,<:CTMRGEdgeTensor{S,2}}, projectors +) where {C,S} C_southwest = envs.corners[SOUTHWEST, row, _prev(col, end)] E_south = envs.edges[SOUTH, row, col] P_bottom = projectors[1][row] @@ -1081,15 +1053,11 @@ function renormalize_top_corner((row, col), envs::CTMRGEnv, projectors) P_top = projectors[2][_next(row, end)] return renormalize_top_corner(C_northwest, E_north, P_top) end -function renormalize_top_corner( - C_northwest, E_north::CTMRGEdgeTensor{S,3}, P_top, -) where {S} +function renormalize_top_corner(C_northwest, E_north::CTMRGEdgeTensor{S,3}, P_top) where {S} return @autoopt @tensor corner[χ_in; χ_out] := P_top[χ_in; χ1 D1 D2] * C_northwest[χ1; χ2] * E_north[χ2 D1 D2; χ_out] end -function renormalize_top_corner( - C_northwest, E_north::CTMRGEdgeTensor{S,2}, P_top, -) where {S} +function renormalize_top_corner(C_northwest, E_north::CTMRGEdgeTensor{S,2}, P_top) where {S} return @autoopt @tensor corner[χ_in; χ_out] := P_top[χ_in; χ1 D1] * C_northwest[χ1; χ2] * E_north[χ2 D1; χ_out] end @@ -1199,7 +1167,7 @@ function renormalize_east_edge( envs.edges[EAST, row, _next(col, end)], P_bottom[EAST, row, col, end], P_top[EAST, _prev(row, end), col], - partfunc[row, col] + partfunc[row, col], ) end @@ -1256,7 +1224,7 @@ function renormalize_south_edge( envs.edges[SOUTH, _next(row, end), col], P_left[SOUTH, row, col], P_right[SOUTH, row, _next(col, end)], - partfunc[row, col] + partfunc[row, col], ) end @@ -1270,7 +1238,6 @@ function renormalize_south_edge( P_right[χ_E; χ1 D5] end - """ renormalize_west_edge((row, col), envs, P_top, P_bottom, ket, bra) renormalize_west_edge(E_west, P_top, P_bottom, ket, bra) @@ -1329,32 +1296,31 @@ function renormalize_west_edge( P_top[χ_S; χ1 D5 D6] end - function renormalize_west_edge( # For simultaneous CTMRG scheme (row, col), envs::CTMRGEnv, P_bottom::Array{Pb,3}, P_top::Array{Pt,3}, - partfunc::InfinitePartitionFunction + partfunc::InfinitePartitionFunction, ) where {Pt,Pb} return renormalize_west_edge( envs.edges[WEST, row, _prev(col, end)], P_bottom[WEST, row, col], P_top[WEST, _next(row, end), col], - partfunc[row, col] + partfunc[row, col], ) end function renormalize_west_edge( # For sequential CTMRG scheme (row, col), envs::CTMRGEnv, projectors, - partfunc::InfinitePartitionFunction + partfunc::InfinitePartitionFunction, ) return renormalize_west_edge( envs.edges[WEST, row, _prev(col, end)], projectors[1][row], projectors[2][_next(row, end)], - partfunc[row, col] + partfunc[row, col], ) end function renormalize_west_edge( diff --git a/src/algorithms/ctmrg/ctmrg.jl b/src/algorithms/ctmrg/ctmrg.jl index 6e2484c3..8e47d14f 100644 --- a/src/algorithms/ctmrg/ctmrg.jl +++ b/src/algorithms/ctmrg/ctmrg.jl @@ -113,9 +113,7 @@ function build_projectors( ) where {E<:ElementarySpace} isqS = sdiag_pow(S, -0.5) P_left = left_projector(Q.E_1, Q.C, Q.E_2, V, isqS, Q.partfunc) - P_right = right_projector( - Q_next.E_1, Q_next.C, Q_next.E_2, U, isqS, Q_next.partfunc - ) + P_right = right_projector(Q_next.E_1, Q_next.C, Q_next.E_2, U, isqS, Q_next.partfunc) return P_left, P_right end diff --git a/src/algorithms/ctmrg/sparse_environments.jl b/src/algorithms/ctmrg/sparse_environments.jl index 95654679..5e372e51 100644 --- a/src/algorithms/ctmrg/sparse_environments.jl +++ b/src/algorithms/ctmrg/sparse_environments.jl @@ -149,24 +149,16 @@ function renormalize_southwest_corner(ec::EnlargedCorner, P_left, P_right) ) end function renormalize_northwest_corner(ec::EnlargedPartitionFunctionCorner, P_left, P_right) - return renormalize_northwest_corner( - ec.E_1, ec.C, ec.E_2, P_left, P_right, ec.partfunc - ) + return renormalize_northwest_corner(ec.E_1, ec.C, ec.E_2, P_left, P_right, ec.partfunc) end function renormalize_northeast_corner(ec::EnlargedPartitionFunctionCorner, P_left, P_right) - return renormalize_northeast_corner( - ec.E_1, ec.C, ec.E_2, P_left, P_right, ec.partfunc - ) + return renormalize_northeast_corner(ec.E_1, ec.C, ec.E_2, P_left, P_right, ec.partfunc) end function renormalize_southeast_corner(ec::EnlargedPartitionFunctionCorner, P_left, P_right) - return renormalize_southeast_corner( - ec.E_1, ec.C, ec.E_2, P_left, P_right, ec.partfunc - ) + return renormalize_southeast_corner(ec.E_1, ec.C, ec.E_2, P_left, P_right, ec.partfunc) end function renormalize_southwest_corner(ec::EnlargedPartitionFunctionCorner, P_left, P_right) - return renormalize_southwest_corner( - ec.E_1, ec.C, ec.E_2, P_left, P_right, ec.partfunc - ) + return renormalize_southwest_corner(ec.E_1, ec.C, ec.E_2, P_left, P_right, ec.partfunc) end # Wrapper around half_infinite_environment contraction using EnlargedCorners (used in ctmrg_projectors) @@ -234,7 +226,9 @@ struct HalfInfinitePartitionFunctionEnv{C,E,A,A′} # TODO: subtype as Abstract end # Construct environment from two enlarged corners -function HalfInfinitePartitionFunctionEnv(quadrant1::EnlargedPartitionFunctionCorner, quadrant2::EnlargedPartitionFunctionCorner) +function HalfInfinitePartitionFunctionEnv( + quadrant1::EnlargedPartitionFunctionCorner, quadrant2::EnlargedPartitionFunctionCorner +) return HalfInfinitePartitionFunctionEnv( quadrant1.C, quadrant2.C, @@ -269,14 +263,7 @@ end function TensorKit.TensorMap(env::HalfInfinitePartitionFunctionEnv) # Dense operator return halfinfinite_environment( - env.C_1, - env.C_2, - env.E_1, - env.E_2, - env.E_3, - env.E_4, - env.partfunc_1, - env.partfunc_2, + env.C_1, env.C_2, env.E_1, env.E_2, env.E_3, env.E_4, env.partfunc_1, env.partfunc_2 ) end @@ -362,16 +349,11 @@ function (env::HalfInfinitePartitionFunctionEnv)(x, ::Val{true}) # Adjoint line end # Wrapper around halfinfinite_environment contraction using EnlargedCorners (used in ctmrg_projectors) -function halfinfinite_partitionfunction_environment(ec_1::EnlargedPartitionFunctionCorner, ec_2::EnlargedPartitionFunctionCorner) +function halfinfinite_partitionfunction_environment( + ec_1::EnlargedPartitionFunctionCorner, ec_2::EnlargedPartitionFunctionCorner +) return HalfInfiniteEnv( - ec_1.C, - ec_2.C, - ec_1.E_1, - ec_1.E_2, - ec_2.E_1, - ec_2.E_2, - ec_1.partfunc, - ec_2.partfunc, + ec_1.C, ec_2.C, ec_1.E_1, ec_1.E_2, ec_2.E_1, ec_2.E_2, ec_1.partfunc, ec_2.partfunc ) end diff --git a/src/environments/ctmrg_environments.jl b/src/environments/ctmrg_environments.jl index 08f56efc..87dab522 100644 --- a/src/environments/ctmrg_environments.jl +++ b/src/environments/ctmrg_environments.jl @@ -48,11 +48,7 @@ function _corner_tensor( end function _edge_tensor( - f, - ::Type{T}, - left_vspace::S, - pspaces::P, - right_vspace::S=left_vspace, + f, ::Type{T}, left_vspace::S, pspaces::P, right_vspace::S=left_vspace ) where {T,S<:ElementarySpaceLike,P<:ProductSpaceLike} return TensorMap( f, @@ -95,7 +91,15 @@ function CTMRGEnv( chis_west::B=chis_north, ) where {A<:AbstractMatrix{<:ProductSpaceLike},B<:AbstractMatrix{<:ElementarySpaceLike}} return CTMRGEnv( - randn, ComplexF64, N, Ds_north, Ds_east, chis_north, chis_east, chis_south, chis_west + randn, + ComplexF64, + N, + Ds_north, + Ds_east, + chis_north, + chis_east, + chis_south, + chis_west, ) end function CTMRGEnv( @@ -106,7 +110,7 @@ function CTMRGEnv( chis_north::B, chis_east::B=chis_north, chis_south::B=chis_north, - chis_west::B=chis_north + chis_west::B=chis_north, ) where {A<:AbstractMatrix{<:ProductSpaceLike},B<:AbstractMatrix{<:ElementarySpaceLike}} # no recursive broadcasting? Ds_south = (x -> adjoint.(x)).(circshift(Ds_north, (-1, 0))) @@ -125,32 +129,16 @@ function CTMRGEnv( for I in CartesianIndices(Ds_north) r, c = I.I edges[NORTH, r, c] = _edge_tensor( - f, - T, - chis_north[r, _prev(c, end)], - Ds_north[_next(r, end), c], - chis_north[r, c], + f, T, chis_north[r, _prev(c, end)], Ds_north[_next(r, end), c], chis_north[r, c] ) edges[EAST, r, c] = _edge_tensor( - f, - T, - chis_east[r, c], - Ds_east[r, _prev(c, end)], - chis_east[_next(r, end), c], + f, T, chis_east[r, c], Ds_east[r, _prev(c, end)], chis_east[_next(r, end), c] ) edges[SOUTH, r, c] = _edge_tensor( - f, - T, - chis_south[r, c], - Ds_south[_prev(r, end), c], - chis_south[r, _prev(c, end)], + f, T, chis_south[r, c], Ds_south[_prev(r, end), c], chis_south[r, _prev(c, end)] ) edges[WEST, r, c] = _edge_tensor( - f, - T, - chis_west[_next(r, end), c], - Ds_west[r, _next(c, end)], - chis_west[r, c], + f, T, chis_west[_next(r, end), c], Ds_west[r, _next(c, end)], chis_west[r, c] ) corners[NORTHWEST, r, c] = _corner_tensor( @@ -190,7 +178,7 @@ function CTMRGEnv( chi_east::S=chi_north, chi_south::S=chi_north, chi_west::S=chi_north; - unitcell::Tuple{Int,Int}=(1, 1) + unitcell::Tuple{Int,Int}=(1, 1), ) where {P<:ProductSpaceLike,S<:Union{Int,ElementarySpace}} return CTMRGEnv( randn, @@ -213,7 +201,7 @@ function CTMRGEnv( chi_south::S=chi_north, chi_west::S=chi_north; unitcell::Tuple{Int,Int}=(1, 1), - ) where {P<:ProductSpaceLike,S<:Union{Int,ElementarySpace}} +) where {P<:ProductSpaceLike,S<:Union{Int,ElementarySpace}} return CTMRGEnv( f, T, @@ -223,7 +211,7 @@ function CTMRGEnv( fill(chi_north, unitcell), fill(chi_east, unitcell), fill(chi_south, unitcell), - fill(chi_west, unitcell) + fill(chi_west, unitcell), ) end @@ -275,7 +263,7 @@ function CTMRGEnv( chis_north::A, chis_east::A=chis_north, chis_south::A=chis_north, - chis_west::A=chis_north + chis_west::A=chis_north, ) where {A<:AbstractMatrix{<:ElementarySpaceLike}} Ds_north = map(peps.A) do t return (adjoint(space(t, 2)), space(t, 2)) @@ -343,7 +331,7 @@ function CTMRGEnv( chis_north::A, chis_east::A=chis_north, chis_south::A=chis_north, - chis_west::A=chis_north + chis_west::A=chis_north, ) where {A<:AbstractMatrix{<:ElementarySpaceLike}} Ds_north = map(partfunc.A) do t return (adjoint(space(t, 1)),) diff --git a/src/states/abstractpeps.jl b/src/states/abstractpeps.jl index 58413b83..6c3c577a 100644 --- a/src/states/abstractpeps.jl +++ b/src/states/abstractpeps.jl @@ -81,4 +81,4 @@ Base.rot180(t::PEPSTensor) = permute(t, ((1,), (4, 5, 2, 3))) Base.rotl90(t::PEPOTensor) = permute(t, ((1, 2), (4, 5, 6, 3))) Base.rotr90(t::PEPOTensor) = permute(t, ((1, 2), (6, 3, 4, 5))) -Base.rot180(t::PEPOTensor) = permute(t, ((1, 2), (5, 6, 3, 4))) \ No newline at end of file +Base.rot180(t::PEPOTensor) = permute(t, ((1, 2), (5, 6, 3, 4))) diff --git a/src/states/infinitepartitionfunction.jl b/src/states/infinitepartitionfunction.jl index 5436806e..3ec2a5b6 100644 --- a/src/states/infinitepartitionfunction.jl +++ b/src/states/infinitepartitionfunction.jl @@ -80,7 +80,9 @@ and column index `[r, c]` by one, respectively: The unit cell has periodic boundary conditions, so `[r, c]` is indexed modulo the size of the unit cell. """ -function InfinitePartitionFunction(A::T; unitcell::Tuple{Int,Int}=(1, 1)) where {T<:PartitionFunction} +function InfinitePartitionFunction( + A::T; unitcell::Tuple{Int,Int}=(1, 1) +) where {T<:PartitionFunction} return InfinitePartitionFunction(fill(A, unitcell)) end @@ -94,18 +96,13 @@ function InfinitePartitionFunction( Nspace::S, Espace::S=Nspace; unitcell::Tuple{Int,Int}=(1, 1) ) where {S<:Union{ElementarySpace,Int}} return InfinitePartitionFunction( - randn, - ComplexF64, - fill(Nspace, unitcell), - fill(Espace, unitcell), + randn, ComplexF64, fill(Nspace, unitcell), fill(Espace, unitcell) ) end function InfinitePartitionFunction( f, T, Nspace::S, Espace::S=Nspace; unitcell::Tuple{Int,Int}=(1, 1) ) where {S<:Union{ElementarySpace,Int}} - return InfinitePartitionFunction( - f, T, fill(Nspace, unitcell), fill(Espace, unitcell) - ) + return InfinitePartitionFunction(f, T, fill(Nspace, unitcell), fill(Espace, unitcell)) end ## Shape and size @@ -114,12 +111,18 @@ Base.size(T::InfinitePartitionFunction, i) = size(T.A, i) Base.length(T::InfinitePartitionFunction) = length(T.A) Base.eltype(T::InfinitePartitionFunction) = eltype(typeof(T)) Base.eltype(::Type{<:InfinitePartitionFunction{T}}) where {T} = T -VectorInterface.scalartype(::Type{T}) where {T<:InfinitePartitionFunction} = scalartype(eltype(T)) +function VectorInterface.scalartype(::Type{T}) where {T<:InfinitePartitionFunction} + return scalartype(eltype(T)) +end ## Copy Base.copy(T::InfinitePartitionFunction) = InfinitePartitionFunction(copy(T.A)) -Base.similar(T::InfinitePartitionFunction, args...) = InfinitePartitionFunction(similar(T.A, args...)) -Base.repeat(T::InfinitePartitionFunction, counts...) = InfinitePartitionFunction(repeat(T.A, counts...)) +function Base.similar(T::InfinitePartitionFunction, args...) + return InfinitePartitionFunction(similar(T.A, args...)) +end +function Base.repeat(T::InfinitePartitionFunction, counts...) + return InfinitePartitionFunction(repeat(T.A, counts...)) +end Base.getindex(T::InfinitePartitionFunction, args...) = Base.getindex(T.A, args...) Base.setindex!(T::InfinitePartitionFunction, args...) = (Base.setindex!(T.A, args...); T) @@ -133,11 +136,17 @@ end TensorKit.space(t::InfinitePartitionFunction, i, j) = space(t[i, j], 1) ## Math -Base.:+(ψ₁::InfinitePartitionFunction, ψ₂::InfinitePartitionFunction) = InfinitePartitionFunction(ψ₁.A + ψ₂.A) -Base.:-(ψ₁::InfinitePartitionFunction, ψ₂::InfinitePartitionFunction) = InfinitePartitionFunction(ψ₁.A - ψ₂.A) +function Base.:+(ψ₁::InfinitePartitionFunction, ψ₂::InfinitePartitionFunction) + return InfinitePartitionFunction(ψ₁.A + ψ₂.A) +end +function Base.:-(ψ₁::InfinitePartitionFunction, ψ₂::InfinitePartitionFunction) + return InfinitePartitionFunction(ψ₁.A - ψ₂.A) +end Base.:*(α::Number, ψ::InfinitePartitionFunction) = InfinitePartitionFunction(α * ψ.A) Base.:/(ψ::InfinitePartitionFunction, α::Number) = InfinitePartitionFunction(ψ.A / α) -LinearAlgebra.dot(ψ₁::InfinitePartitionFunction, ψ₂::InfinitePartitionFunction) = dot(ψ₁.A, ψ₂.A) +function LinearAlgebra.dot(ψ₁::InfinitePartitionFunction, ψ₂::InfinitePartitionFunction) + return dot(ψ₁.A, ψ₂.A) +end LinearAlgebra.norm(ψ::InfinitePartitionFunction) = norm(ψ.A) ## (Approximate) equality @@ -146,7 +155,9 @@ function Base.:(==)(ψ₁::InfinitePartitionFunction, ψ₂::InfinitePartitionFu return p₁ == p₂ end end -function Base.isapprox(ψ₁::InfinitePartitionFunction, ψ₂::InfinitePartitionFunction; kwargs...) +function Base.isapprox( + ψ₁::InfinitePartitionFunction, ψ₂::InfinitePartitionFunction; kwargs... +) return all(zip(ψ₁.A, ψ₂.A)) do (p₁, p₂) return isapprox(p₁, p₂; kwargs...) end @@ -159,13 +170,17 @@ function LinearAlgebra.rmul!(ψ::InfinitePartitionFunction, α::Number) end # Used in _add during OptimKit.optimize -function LinearAlgebra.axpy!(α::Number, ψ₁::InfinitePartitionFunction, ψ₂::InfinitePartitionFunction) +function LinearAlgebra.axpy!( + α::Number, ψ₁::InfinitePartitionFunction, ψ₂::InfinitePartitionFunction +) ψ₂.A .+= α * ψ₁.A return ψ₂ end # VectorInterface -VectorInterface.zerovector(x::InfinitePartitionFunction) = InfinitePartitionFunction(zerovector(x.A)) +function VectorInterface.zerovector(x::InfinitePartitionFunction) + return InfinitePartitionFunction(zerovector(x.A)) +end # Rotations Base.rotl90(t::InfinitePartitionFunction) = InfinitePartitionFunction(rotl90(rotl90.(t.A))) @@ -186,7 +201,9 @@ function ChainRulesCore.rrule( return PartitionFunction, getindex_pullback end -function ChainRulesCore.rrule(::Type{<:InfinitePartitionFunction}, A::Matrix{T}) where {T<:PartitionFunction} +function ChainRulesCore.rrule( + ::Type{<:InfinitePartitionFunction}, A::Matrix{T} +) where {T<:PartitionFunction} peps = InfinitePartitionFunction(A) function InfinitePartitionFunction_pullback(Δpeps) return NoTangent(), Δpeps.A @@ -218,4 +235,4 @@ function FiniteDifferences.to_vec(state::InfinitePartitionFunction) return InfinitePartitionFunction(back(vec)) end return vec, state_from_vec -end \ No newline at end of file +end diff --git a/test/ctmrg/partition_function.jl b/test/ctmrg/partition_function.jl index 500cada2..3e5ebe82 100644 --- a/test/ctmrg/partition_function.jl +++ b/test/ctmrg/partition_function.jl @@ -5,7 +5,17 @@ using LinearAlgebra using QuadGK using MPSKit -using PEPSKit: @autoopt, CTMRGEdgeTensor, NORTHWEST, NORTHEAST, SOUTHEAST, SOUTHWEST, WEST, EAST, NORTH, SOUTH +using PEPSKit: + @autoopt, + CTMRGEdgeTensor, + NORTHWEST, + NORTHEAST, + SOUTHEAST, + SOUTHWEST, + WEST, + EAST, + NORTH, + SOUTH ## Setup @@ -23,12 +33,14 @@ function classical_ising_exact(; beta=log(1 + sqrt(2)) / 2, J=1.0) K = beta * J k = 1 / sinh(2 * K)^2 - F = quadgk(theta -> log(cosh(2 * K)^2 + 1 / k * sqrt(1 + k^2 - 2 * k * cos(2 * theta))), 0, pi)[1] + F = quadgk( + theta -> log(cosh(2 * K)^2 + 1 / k * sqrt(1 + k^2 - 2 * k * cos(2 * theta))), 0, pi + )[1] f = -1 / beta * (log(2) / 2 + 1 / (2 * pi) * F) - m = 1 - (sinh(2 * K))^(-4) > 0 ? (1 - (sinh(2 * K))^(-4))^(1/8) : 0 + m = 1 - (sinh(2 * K))^(-4) > 0 ? (1 - (sinh(2 * K))^(-4))^(1 / 8) : 0 - E = quadgk(theta -> 1 / sqrt(1 - (4 * k) * (1 + k)^(-2) * sin(theta)^2), 0, pi/2)[1] + E = quadgk(theta -> 1 / sqrt(1 - (4 * k) * (1 + k)^(-2) * sin(theta)^2), 0, pi / 2)[1] e = -J * cosh(2 * K) / sinh(2 * K) * (1 + 2 / pi * (2 * tanh(2 * K)^2 - 1) * E) return f, m, e @@ -63,8 +75,10 @@ function classical_ising(; beta=log(1 + sqrt(2)) / 2, J=1.0) # bond interaction tensor and energy-per-site tensor e = ComplexF64[-J J; J -J] .* nt - @tensor e_hor[-1 -2; -3 -4] := O[1 2; 3 4] * nt[-1; 1] * nt[-2; 2] * nt[-3; 3] * e[-4; 4] - @tensor e_vert[-1 -2; -3 -4] := O[1 2; 3 4] * nt[-1; 1] * nt[-2; 2] * e[-3; 3] * nt[-4; 4] + @tensor e_hor[-1 -2; -3 -4] := + O[1 2; 3 4] * nt[-1; 1] * nt[-2; 2] * nt[-3; 3] * e[-4; 4] + @tensor e_vert[-1 -2; -3 -4] := + O[1 2; 3 4] * nt[-1; 1] * nt[-2; 2] * e[-3; 3] * nt[-4; 4] e = e_hor + e_vert # fixed tensor map space for all three @@ -77,19 +91,18 @@ end Contract a local rank-4 tensor with a given partition function environment. """ function local_contraction( - O::AbstractTensorMap{S,2,2}, - env::CTMRGEnv{C,<:CTMRGEdgeTensor{S,2}}, + O::AbstractTensorMap{S,2,2}, env::CTMRGEnv{C,<:CTMRGEdgeTensor{S,2}} ) where {S,C} return @autoopt @tensor env.corners[NORTHWEST, 1, 1][C_WNW; C_NNW] * - env.edges[NORTH, 1, 1][C_NNW D_N; C_NNE] * - env.corners[NORTHEAST, 1, 1][C_NNE; C_ENE] * - env.edges[EAST, 1, 1][C_ENE D_E; C_ESE] * - env.corners[SOUTHEAST, 1, 1][C_ESE; C_SSE] * - env.edges[SOUTH, 1, 1][C_SSE D_S; C_SSW] * - env.corners[SOUTHWEST, 1, 1][C_SSW; C_WSW] * - env.edges[WEST, 1, 1][C_WSW D_W; C_WNW] * - O[D_N D_E; D_S D_W] - # O[D_W D_S; D_N D_E] # TODO: switch to this convention + env.edges[NORTH, 1, 1][C_NNW D_N; C_NNE] * + env.corners[NORTHEAST, 1, 1][C_NNE; C_ENE] * + env.edges[EAST, 1, 1][C_ENE D_E; C_ESE] * + env.corners[SOUTHEAST, 1, 1][C_ESE; C_SSE] * + env.edges[SOUTH, 1, 1][C_SSE D_S; C_SSW] * + env.corners[SOUTHWEST, 1, 1][C_SSW; C_WSW] * + env.edges[WEST, 1, 1][C_WSW D_W; C_WNW] * + O[D_N D_E; D_S D_W] + # O[D_W D_S; D_N D_E] # TODO: switch to this convention end ## Test @@ -105,13 +118,7 @@ Z = InfinitePartitionFunction(O) χenv = ℂ^12 env0 = CTMRGEnv(Z, χenv) -ctm_alg = CTMRG(; - tol=1e-10, - miniter=4, - maxiter=100, - verbosity=2, - ctmrgscheme=:simultaneous, -) +ctm_alg = CTMRG(; tol=1e-10, miniter=4, maxiter=100, verbosity=2, ctmrgscheme=:simultaneous) env = leading_boundary(env0, Z, ctm_alg) diff --git a/test/runtests.jl b/test/runtests.jl index f520e3fe..b8e3ac97 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -31,7 +31,7 @@ end end @time @safetestset "Partition function" begin include("ctmrg/partition_function.jl") - end + end end if GROUP == "ALL" || GROUP == "BOUNDARYMPS" @time @safetestset "VUMPS" begin From 1286788c556abb19d5d74187d205315e9775cb98 Mon Sep 17 00:00:00 2001 From: leburgel Date: Fri, 3 Jan 2025 17:14:19 +0100 Subject: [PATCH 03/47] Update for new CTMRG flavor specification --- test/ctmrg/partition_function.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/ctmrg/partition_function.jl b/test/ctmrg/partition_function.jl index 3e5ebe82..f6d8bcad 100644 --- a/test/ctmrg/partition_function.jl +++ b/test/ctmrg/partition_function.jl @@ -118,7 +118,7 @@ Z = InfinitePartitionFunction(O) χenv = ℂ^12 env0 = CTMRGEnv(Z, χenv) -ctm_alg = CTMRG(; tol=1e-10, miniter=4, maxiter=100, verbosity=2, ctmrgscheme=:simultaneous) +ctm_alg = SimultaneousCTMRG(; tol=1e-10, miniter=4, maxiter=100, verbosity=2) env = leading_boundary(env0, Z, ctm_alg) From 911a415546956c71f062ab319b576282756331c3 Mon Sep 17 00:00:00 2001 From: leburgel Date: Fri, 3 Jan 2025 17:53:20 +0100 Subject: [PATCH 04/47] Fix typo --- src/algorithms/contractions/ctmrg_contractions.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algorithms/contractions/ctmrg_contractions.jl b/src/algorithms/contractions/ctmrg_contractions.jl index 5200cedb..fdb03097 100644 --- a/src/algorithms/contractions/ctmrg_contractions.jl +++ b/src/algorithms/contractions/ctmrg_contractions.jl @@ -380,7 +380,7 @@ function half_infinite_environment( quadrant2[χ D1 D2; χ_out D_outabove D_outbelow] end -function halfinfinite_environment( +function half_infinite_environment( quadrant1::AbstractTensorMap{S,2,2}, quadrant2::AbstractTensorMap{S,2,2} ) where {S} return @autoopt @tensor env[χ_in D_in; χ_out D_out] := From 5262256d85be76ace60672e827e69d598889ff7b Mon Sep 17 00:00:00 2001 From: leburgel Date: Mon, 6 Jan 2025 09:42:21 +0100 Subject: [PATCH 05/47] Rename `PartitionFunction` -> `PartitionFunctionTensor` --- .../contractions/ctmrg_contractions.jl | 34 +++++++++---------- src/states/abstractpeps.jl | 8 ++--- src/states/infinitepartitionfunction.jl | 20 +++++------ 3 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/algorithms/contractions/ctmrg_contractions.jl b/src/algorithms/contractions/ctmrg_contractions.jl index fdb03097..3f5f27e1 100644 --- a/src/algorithms/contractions/ctmrg_contractions.jl +++ b/src/algorithms/contractions/ctmrg_contractions.jl @@ -55,7 +55,7 @@ function enlarge_northwest_corner( E_west::CTMRGEdgeTensor{S,2}, C_northwest::CTMRGCornerTensor, E_north::CTMRGEdgeTensor{S,2}, - partfunc::PartitionFunction, + partfunc::PartitionFunctionTensor, ) where {S} return @autoopt @tensor corner[χ_S D_S; χ_E D_E] := E_west[χ_S D1; χ1] * @@ -115,7 +115,7 @@ function enlarge_northeast_corner( E_north::CTMRGEdgeTensor{S,2}, C_northeast::CTMRGCornerTensor, E_east::CTMRGEdgeTensor{S,2}, - partfunc::PartitionFunction, + partfunc::PartitionFunctionTensor, ) where {S} return @autoopt @tensor corner[χ_W D_W; χ_S D_S] := E_north[χ_W D1; χ1] * @@ -175,7 +175,7 @@ function enlarge_southeast_corner( E_east::CTMRGEdgeTensor{S,2}, C_southeast::CTMRGCornerTensor, E_south::CTMRGEdgeTensor{S,2}, - partfunc::PartitionFunction, + partfunc::PartitionFunctionTensor, ) where {S} return @autoopt @tensor corner[χ_N D_N; χ_W D_W] := E_east[χ_N D1; χ1] * @@ -235,7 +235,7 @@ function enlarge_southwest_corner( E_south::CTMRGEdgeTensor{S,2}, C_southwest::CTMRGCornerTensor, E_west::CTMRGEdgeTensor{S,2}, - partfunc::PartitionFunction, + partfunc::PartitionFunctionTensor, ) where {S} return @autoopt @tensor corner[χ_E D_E; χ_N D_N] := E_south[χ_E D1; χ1] * @@ -270,7 +270,7 @@ function left_projector(E_1, C, E_2, V, isqS, ket::PEPSTensor, bra::PEPSTensor=k isqS[χ4; χ_out] end -function left_projector(E_1, C, E_2, V, isqS, partfunc::PartitionFunction) +function left_projector(E_1, C, E_2, V, isqS, partfunc::PartitionFunctionTensor) return @autoopt @tensor P_left[χ_in D_in; χ_out] := E_1[χ_in D1; χ1] * C[χ1; χ2] * E_2[χ2 D2; χ3] * partfunc[D2 D3; D_in D1] conj(V[χ4; χ3 D3]) @@ -300,7 +300,7 @@ function right_projector(E_1, C, E_2, U, isqS, ket::PEPSTensor, bra::PEPSTensor= E_1[χ4 D5 D6; χ_out] end -function right_projector(E_1, C, E_2, U, isqS, partfunc::PartitionFunction) +function right_projector(E_1, C, E_2, U, isqS, partfunc::PartitionFunctionTensor) return @autoopt @tensor P_right[χ_in; χ_out D_out] := isqS[χ_in; χ1] * conj(U[χ1; χ2 D1]) * partfunc[D2 D3; D_out D1] return E_2[χ2 D2; χ3] * C[χ3; χ4] * E_1[χ4 D3; χ_out] @@ -405,7 +405,7 @@ end function halfinfinite_environment( C_1, C_2, E_1, E_2, E_3, E_4, partfunc_1::P, partfunc_2::P -) where {P<:PartitionFunction} +) where {P<:PartitionFunctionTensor} return @autoopt @tensor env[χ_in D_in; χ_out D_out] := E_1[χ_in D1; χ1] * C_1[χ1; χ2] * @@ -446,7 +446,7 @@ end function halfinfinite_environment( C_1, C_2, E_1, E_2, E_3, E_4, x::AbstractTensor{S,2}, partfunc_1::P, partfunc_2::P -) where {S,P<:PartitionFunction} +) where {S,P<:PartitionFunctionTensor} return @autoopt @tensor env_x[χ_in D_in] := E_1[χ_in D1; χ1] * C_1[χ1; χ2] * @@ -716,7 +716,7 @@ end function halfinfinite_environment( x::AbstractTensor{S,2}, C_1, C_2, E_1, E_2, E_3, E_4, partfunc_1::P, partfunc_2::P -) where {S,P<:PartitionFunction} +) where {S,P<:PartitionFunctionTensor} return @autoopt @tensor env_x[χ_in D_in] := x[χ1 D1 D2] * conj(E_1[χ1 D3; χ2]) * @@ -809,7 +809,7 @@ function renormalize_northwest_corner( end function renormalize_northwest_corner( - E_west, C_northwest, E_north, P_left, P_right, partfunc::PartitionFunction + E_west, C_northwest, E_north, P_left, P_right, partfunc::PartitionFunctionTensor ) return @autoopt @tensor corner[χ_in; χ_out] := P_right[χ_in; χ1 D1] * @@ -871,7 +871,7 @@ function renormalize_northeast_corner( end function renormalize_northeast_corner( - E_north, C_northeast, E_east, P_left, P_right, partfunc::PartitionFunction + E_north, C_northeast, E_east, P_left, P_right, partfunc::PartitionFunctionTensor ) return @autoopt @tensor corner[χ_in; χ_out] := P_right[χ_in; χ1 D1] * @@ -933,7 +933,7 @@ function renormalize_southeast_corner( end function renormalize_southeast_corner( - E_east, C_southeast, E_south, P_left, P_right, partfunc::PartitionFunction + E_east, C_southeast, E_south, P_left, P_right, partfunc::PartitionFunctionTensor ) return @autoopt @tensor corner[χ_in; χ_out] := P_right[χ_in; χ1 D1] * @@ -995,7 +995,7 @@ function renormalize_southwest_corner( end function renormalize_southwest_corner( - E_south, C_southwest, E_west, P_left, P_right, partfunc::PartitionFunction + E_south, C_southwest, E_west, P_left, P_right, partfunc::PartitionFunctionTensor ) return @autoopt @tensor corner[χ_in; χ_out] := P_right[χ_in; χ1 D1] * @@ -1112,7 +1112,7 @@ function renormalize_north_edge( end function renormalize_north_edge( - E_north::CTMRGEdgeTensor{S,2}, P_left, P_right, partfunc::PartitionFunction + E_north::CTMRGEdgeTensor{S,2}, P_left, P_right, partfunc::PartitionFunctionTensor ) where {S} return @autoopt @tensor edge[χ_W D_S; χ_E] := E_north[χ1 D1; χ2] * @@ -1172,7 +1172,7 @@ function renormalize_east_edge( end function renormalize_east_edge( - E_east::CTMRGEdgeTensor{S,2}, P_bottom, P_top, partfunc::PartitionFunction + E_east::CTMRGEdgeTensor{S,2}, P_bottom, P_top, partfunc::PartitionFunctionTensor ) where {S} return @autoopt @tensor edge[χ_N D_W; χ_S] := E_east[χ1 D1; χ2] * @@ -1229,7 +1229,7 @@ function renormalize_south_edge( end function renormalize_south_edge( - E_south::CTMRGEdgeTensor{S,2}, P_left, P_right, partfunc::PartitionFunction + E_south::CTMRGEdgeTensor{S,2}, P_left, P_right, partfunc::PartitionFunctionTensor ) where {S} return @autoopt @tensor edge[χ_E D_N; χ_W] := E_south[χ1 D1; χ2] * @@ -1324,7 +1324,7 @@ function renormalize_west_edge( # For sequential CTMRG scheme ) end function renormalize_west_edge( - E_west::CTMRGEdgeTensor{S,2}, P_bottom, P_top, partfunc::PartitionFunction + E_west::CTMRGEdgeTensor{S,2}, P_bottom, P_top, partfunc::PartitionFunctionTensor ) where {S} return @autoopt @tensor edge[χ_S D_E; χ_N] := E_west[χ1 D1; χ2] * diff --git a/src/states/abstractpeps.jl b/src/states/abstractpeps.jl index 6c3c577a..81fc8196 100644 --- a/src/states/abstractpeps.jl +++ b/src/states/abstractpeps.jl @@ -6,7 +6,7 @@ conventionally ordered as: ``T : P ← N ⊗ E ⊗ S ⊗ W``. Here, ``P``, ``N`` ``W`` denote the physics, north, east, south and west spaces, respectively. """ const PEPSTensor{S} = AbstractTensorMap{S,1,4} where {S<:ElementarySpace} -const PartitionFunction{S} = AbstractTensorMap{S,2,2} where {S<:ElementarySpace} +const PartitionFunctionTensor{S} = AbstractTensorMap{S,2,2} where {S<:ElementarySpace} """ PEPSTensor(f, ::Type{T}, Pspace::S, Nspace::S, @@ -71,9 +71,9 @@ Abstract supertype for a 2D projected entangled-pair operator. abstract type AbstractPEPO end # Rotations -Base.rotl90(t::PartitionFunction) = permute(t, ((2, 3), (1, 2))) -Base.rotr90(t::PartitionFunction) = permute(t, ((4, 1), (2, 3))) -Base.rot180(t::PartitionFunction) = permute(t, ((3, 4), (1, 2))) +Base.rotl90(t::PartitionFunctionTensor) = permute(t, ((2, 3), (1, 2))) +Base.rotr90(t::PartitionFunctionTensor) = permute(t, ((4, 1), (2, 3))) +Base.rot180(t::PartitionFunctionTensor) = permute(t, ((3, 4), (1, 2))) Base.rotl90(t::PEPSTensor) = permute(t, ((1,), (3, 4, 5, 2))) Base.rotr90(t::PEPSTensor) = permute(t, ((1,), (5, 2, 3, 4))) diff --git a/src/states/infinitepartitionfunction.jl b/src/states/infinitepartitionfunction.jl index 3ec2a5b6..dae55b22 100644 --- a/src/states/infinitepartitionfunction.jl +++ b/src/states/infinitepartitionfunction.jl @@ -1,12 +1,12 @@ """ - struct InfinitePartitionFunction{T<:PartitionFunction} + struct InfinitePartitionFunction{T<:PartitionFunctionTensor} Represents an infinite projected entangled-pair state on a 2D square lattice. """ -struct InfinitePartitionFunction{T<:PartitionFunction} <: AbstractPartitionFunction +struct InfinitePartitionFunction{T<:PartitionFunctionTensor} <: AbstractPartitionFunction A::Matrix{T} - InfinitePartitionFunction{T}(A::Matrix{T}) where {T<:PartitionFunction} = new{T}(A) - function InfinitePartitionFunction(A::Array{T,2}) where {T<:PartitionFunction} + InfinitePartitionFunction{T}(A::Matrix{T}) where {T<:PartitionFunctionTensor} = new{T}(A) + function InfinitePartitionFunction(A::Array{T,2}) where {T<:PartitionFunctionTensor} for (d, w) in Tuple.(CartesianIndices(A)) space(A[d, w], 1) == space(A[_prev(d, end), w], 3)' || throw( SpaceMismatch("North virtual space at site $((d, w)) does not match.") @@ -26,7 +26,7 @@ end Create an `InfinitePartitionFunction` by specifying a matrix containing the PEPS tensors at each site in the unit cell. """ -function InfinitePartitionFunction(A::AbstractMatrix{T}) where {T<:PartitionFunction} +function InfinitePartitionFunction(A::AbstractMatrix{T}) where {T<:PartitionFunctionTensor} return InfinitePartitionFunction(Array(deepcopy(A))) # TODO: find better way to copy end @@ -54,7 +54,7 @@ function InfinitePartitionFunction( Wspaces = adjoint.(circshift(Espaces, (0, 1))) A = map(Nspaces, Espaces, Sspaces, Wspaces) do P, N, E, S, W - return PartitionFunction(f, T, N, E, S, W) + return PartitionFunctionTensor(f, T, N, E, S, W) end return InfinitePartitionFunction(A) @@ -82,7 +82,7 @@ size of the unit cell. """ function InfinitePartitionFunction( A::T; unitcell::Tuple{Int,Int}=(1, 1) -) where {T<:PartitionFunction} +) where {T<:PartitionFunctionTensor} return InfinitePartitionFunction(fill(A, unitcell)) end @@ -191,19 +191,19 @@ Base.rot180(t::InfinitePartitionFunction) = InfinitePartitionFunction(rot180(rot function ChainRulesCore.rrule( ::typeof(Base.getindex), state::InfinitePartitionFunction, row::Int, col::Int ) - PartitionFunction = state[row, col] + PartitionFunctionTensor = state[row, col] function getindex_pullback(ΔPartitionFunction) Δstate = zerovector(state) Δstate[row, col] = ΔPartitionFunction return NoTangent(), Δstate, NoTangent(), NoTangent() end - return PartitionFunction, getindex_pullback + return PartitionFunctionTensor, getindex_pullback end function ChainRulesCore.rrule( ::Type{<:InfinitePartitionFunction}, A::Matrix{T} -) where {T<:PartitionFunction} +) where {T<:PartitionFunctionTensor} peps = InfinitePartitionFunction(A) function InfinitePartitionFunction_pullback(Δpeps) return NoTangent(), Δpeps.A From 9e88c56fed5bec57be29381abe06694b69094926 Mon Sep 17 00:00:00 2001 From: sanderdemeyer Date: Mon, 6 Jan 2025 10:48:51 +0100 Subject: [PATCH 06/47] Add documentation --- .../contractions/ctmrg_contractions.jl | 462 +++++++++++++++--- src/states/abstractpeps.jl | 8 + src/states/infinitepartitionfunction.jl | 12 +- 3 files changed, 397 insertions(+), 85 deletions(-) diff --git a/src/algorithms/contractions/ctmrg_contractions.jl b/src/algorithms/contractions/ctmrg_contractions.jl index 3f5f27e1..702ccd6d 100644 --- a/src/algorithms/contractions/ctmrg_contractions.jl +++ b/src/algorithms/contractions/ctmrg_contractions.jl @@ -43,6 +43,21 @@ function enlarge_northwest_corner( conj(bra[d; D4 D_Ebelow D_Sbelow D2]) end +""" + enlarge_northwest_corner((row, col), envs, partfunc) + enlarge_northwest_corner(E_west, C_northwest, E_north, partfunc) + +Contract the enlarged northwest corner of the CTMRG environment, either by specifying the +coordinates, environments and state, or by directly providing the tensors. + +``` + C_northwest -- E_north -- + | | + E_west -- ket-bra -- + | | +``` +""" + function enlarge_northwest_corner( (row, col), envs::CTMRGEnv, partfunc::InfinitePartitionFunction ) @@ -103,6 +118,21 @@ function enlarge_northeast_corner( conj(bra[d; D2 D4 D_Sbelow D_Wbelow]) end +""" + enlarge_northeast_corner((row, col), envs, partfunc) + enlarge_northeast_corner(E_north, C_northeast, E_east, partfunc) + +Contract the enlarged northeast corner of the CTMRG environment, either by specifying the +coordinates, environments and state, or by directly providing the tensors. + +``` + -- E_north -- C_northeast + | | + -- ket-bra -- E_east + | | +``` +""" + function enlarge_northeast_corner( (row, col), envs::CTMRGEnv, partfunc::InfinitePartitionFunction ) @@ -163,6 +193,21 @@ function enlarge_southeast_corner( conj(bra[d; D_Nbelow D2 D4 D_Wbelow]) end +""" + enlarge_southeast_corner((row, col), envs, partfunc) + enlarge_southeast_corner(E_east, C_southeast, E_south, partfunc) + +Contract the enlarged southeast corner of the CTMRG environment, either by specifying the +coordinates, environments and state, or by directly providing the tensors. + +``` + | | + -- ket-bra -- E_east + | | + -- E_south -- C_southeast +``` +""" + function enlarge_southeast_corner( (row, col), envs::CTMRGEnv, partfunc::InfinitePartitionFunction ) @@ -223,6 +268,21 @@ function enlarge_southwest_corner( conj(bra[d; D_Nbelow D_Ebelow D2 D4]) end +""" + enlarge_southwest_corner((row, col), envs, partfunc) + enlarge_southwest_corner(E_south, C_southwest, E_west, partfunc) + +Contract the enlarged southwest corner of the CTMRG environment, either by specifying the +coordinates, environments and state, or by directly providing the tensors. + +``` + | | + E_west -- ket-bra -- + | | + C_southwest -- E_south -- +``` +""" + function enlarge_southwest_corner( (row, col), envs::CTMRGEnv, partfunc::InfinitePartitionFunction ) @@ -270,6 +330,19 @@ function left_projector(E_1, C, E_2, V, isqS, ket::PEPSTensor, bra::PEPSTensor=k isqS[χ4; χ_out] end +""" + left_projector(E_1, C, E_2, V, isqS, partfunc::PartitionFunctionTensor) + +Contract the CTMRG left projector with the higher-dimensional subspace facing to the left. + +``` + C -- E_2 -- |~~| + | | |V'| -- isqS -- + E_1 -- ket-bra -- |~~| + | | +``` +""" + function left_projector(E_1, C, E_2, V, isqS, partfunc::PartitionFunctionTensor) return @autoopt @tensor P_left[χ_in D_in; χ_out] := E_1[χ_in D1; χ1] * C[χ1; χ2] * E_2[χ2 D2; χ3] * partfunc[D2 D3; D_in D1] @@ -300,6 +373,19 @@ function right_projector(E_1, C, E_2, U, isqS, ket::PEPSTensor, bra::PEPSTensor= E_1[χ4 D5 D6; χ_out] end +""" + right_projector(E_1, C, E_2, U, isqS, partfunc::PartitionFunctionTensor) + +Contract the CTMRG right projector with the higher-dimensional subspace facing to the right. + +``` + |~~| -- E_2 -- C + -- isqS -- |U'| | | + |~~| -- ket-bra -- E_1 + | | +``` +""" + function right_projector(E_1, C, E_2, U, isqS, partfunc::PartitionFunctionTensor) return @autoopt @tensor P_right[χ_in; χ_out D_out] := isqS[χ_in; χ1] * conj(U[χ1; χ2 D1]) * partfunc[D2 D3; D_out D1] @@ -312,6 +398,7 @@ end Compute projectors based on a SVD of `Q * Q_next`, where the inverse square root `isqS` of the singular values is computed. +For the case of a PEPSTensor: Left projector: ``` -- |~~~~~~| -- |~~| @@ -325,6 +412,21 @@ Right projector: -- isqS -- |U'| | Q | |~~| == |~~~| == ``` + +For the case of a PartitionFunctionTensor: +Left projector: +``` + -- |~~~~~~| -- |~~| + |Q_next| |V'| -- isqS -- + -- |~~~~~~| -- |~~| +``` + +Right projector: +``` + |~~| -- |~~~| -- + -- isqS -- |U'| | Q | + |~~| -- |~~~| -- +``` """ function contract_projectors(U, S, V, Q, Q_next) isqS = sdiag_pow(S, -0.5) @@ -380,13 +482,6 @@ function half_infinite_environment( quadrant2[χ D1 D2; χ_out D_outabove D_outbelow] end -function half_infinite_environment( - quadrant1::AbstractTensorMap{S,2,2}, quadrant2::AbstractTensorMap{S,2,2} -) where {S} - return @autoopt @tensor env[χ_in D_in; χ_out D_out] := - quadrant1[χ_in D_in; χ D1] * quadrant2[χ D1; χ_out D_out] -end - function halfinfinite_environment( C_1, C_2, E_1, E_2, E_3, E_4, ket_1::P, ket_2::P, bra_1::P=ket_1, bra_2::P=ket_2 ) where {P<:PEPSTensor} @@ -403,20 +498,6 @@ function halfinfinite_environment( E_4[χ5 D7 D8; χ_out] end -function halfinfinite_environment( - C_1, C_2, E_1, E_2, E_3, E_4, partfunc_1::P, partfunc_2::P -) where {P<:PartitionFunctionTensor} - return @autoopt @tensor env[χ_in D_in; χ_out D_out] := - E_1[χ_in D1; χ1] * - C_1[χ1; χ2] * - E_2[χ2 D3; χ3] * - partfunc_1[D3 D9; D_in D1] * - partfunc_2[D5 D7; D_out D9] * - E_3[χ3 D5; χ4] * - C_2[χ4; χ5] * - E_4[χ5 D7; χ_out] -end - function halfinfinite_environment( C_1, C_2, @@ -444,21 +525,6 @@ function halfinfinite_environment( x[χ6 D11 D12] end -function halfinfinite_environment( - C_1, C_2, E_1, E_2, E_3, E_4, x::AbstractTensor{S,2}, partfunc_1::P, partfunc_2::P -) where {S,P<:PartitionFunctionTensor} - return @autoopt @tensor env_x[χ_in D_in] := - E_1[χ_in D1; χ1] * - C_1[χ1; χ2] * - E_2[χ2 D3; χ3] * - partfunc_1[D3 D9; D_in D1] * - partfunc_2[D5 D7; D11 D9] * - E_3[χ3 D5; χ4] * - C_2[χ4; χ5] * - E_4[χ5 D7; χ6] * - x[χ6 D11] -end - function halfinfinite_environment( x::AbstractTensor{S,3}, C_1, @@ -486,6 +552,97 @@ function halfinfinite_environment( conj(E_4[χ6 D9 D10; χ_in]) end +""" + half_infinite_environment(quadrant1::AbstractTensorMap{S,2,2}, quadrant2::AbstractTensorMap{S,2,2}) + half_infinite_environment(C_1, C_2, E_1, E_2, E_3, E_4, + partfunc_1::P, partfunc_2::P) where {P<:PartitionFunctionTensor} + half_infinite_environment(C_1, C_2, E_1, E_2, E_3, E_4, x, + partfunc_1::P, partfunc_2::P) where {P<:PartitionFunctionTensor} + half_infinite_environment(x, C_1, C_2, E_1, E_2, E_3, E_4, + partfunc_1::P, partfunc_2::P) where {P<:PartitionFunctionTensor} + +Contract two quadrants (enlarged corners) to form a half-infinite environment. + +``` + |~~~~~~~~~| -- |~~~~~~~~~| + |quadrant1| |quadrant2| + |~~~~~~~~~| == |~~~~~~~~~| + | | | | +``` + +The environment can also be contracted directly from all its constituent tensors. + +``` + C_1 -- E_2 -- E_3 -- C_2 + | | | | + E_1 -- ket_bra_1 -- ket_bra_2 -- E_4 + | | | | +``` + +Alternatively, contract the environment with a vector `x` acting on it + +``` + C_1 -- E_2 -- E_3 -- C_2 + | | | | + E_1 -- ket_bra_1 -- ket_bra_2 -- E_4 + | | | | + [~~~~~~x~~~~~~] +``` + +or contract the adjoint environment with `x`, e.g. as needed for iterative solvers. +""" + +function half_infinite_environment( + quadrant1::AbstractTensorMap{S,2,2}, quadrant2::AbstractTensorMap{S,2,2} +) where {S} + return @autoopt @tensor env[χ_in D_in; χ_out D_out] := + quadrant1[χ_in D_in; χ D1] * quadrant2[χ D1; χ_out D_out] +end + +function halfinfinite_environment( + C_1, C_2, E_1, E_2, E_3, E_4, partfunc_1::P, partfunc_2::P +) where {P<:PartitionFunctionTensor} + return @autoopt @tensor env[χ_in D_in; χ_out D_out] := + E_1[χ_in D1; χ1] * + C_1[χ1; χ2] * + E_2[χ2 D3; χ3] * + partfunc_1[D3 D9; D_in D1] * + partfunc_2[D5 D7; D_out D9] * + E_3[χ3 D5; χ4] * + C_2[χ4; χ5] * + E_4[χ5 D7; χ_out] +end + +function halfinfinite_environment( + C_1, C_2, E_1, E_2, E_3, E_4, x::AbstractTensor{S,2}, partfunc_1::P, partfunc_2::P +) where {S,P<:PartitionFunctionTensor} + return @autoopt @tensor env_x[χ_in D_in] := + E_1[χ_in D1; χ1] * + C_1[χ1; χ2] * + E_2[χ2 D3; χ3] * + partfunc_1[D3 D9; D_in D1] * + partfunc_2[D5 D7; D11 D9] * + E_3[χ3 D5; χ4] * + C_2[χ4; χ5] * + E_4[χ5 D7; χ6] * + x[χ6 D11] +end + +function halfinfinite_environment( + x::AbstractTensor{S,2}, C_1, C_2, E_1, E_2, E_3, E_4, partfunc_1::P, partfunc_2::P +) where {S,P<:PartitionFunctionTensor} + return @autoopt @tensor env_x[χ_in D_in] := + x[χ1 D1 D2] * + conj(E_1[χ1 D3; χ2]) * + conj(C_1[χ2; χ3]) * + conj(E_2[χ3 D5; χ4]) * + conj(partfunc_1[D5 D11; D1 D3]) * + conj(partfunc_2[D7 D9; D_in D11]) * + conj(E_3[χ4 D7; χ5]) * + conj(C_2[χ5; χ6]) * + conj(E_4[χ6 D9; χ_in]) +end + """ full_infinite_environment( quadrant1::T, quadrant2::T, quadrant3::T, quadrant4::T @@ -714,21 +871,6 @@ function full_infinite_environment( E_8[χ11 D21 D22; χ_in] end -function halfinfinite_environment( - x::AbstractTensor{S,2}, C_1, C_2, E_1, E_2, E_3, E_4, partfunc_1::P, partfunc_2::P -) where {S,P<:PartitionFunctionTensor} - return @autoopt @tensor env_x[χ_in D_in] := - x[χ1 D1 D2] * - conj(E_1[χ1 D3; χ2]) * - conj(C_1[χ2; χ3]) * - conj(E_2[χ3 D5; χ4]) * - conj(partfunc_1[D5 D11; D1 D3]) * - conj(partfunc_2[D7 D9; D_in D11]) * - conj(E_3[χ4 D7; χ5]) * - conj(C_2[χ5; χ6]) * - conj(E_4[χ6 D9; χ_in]) -end - # Renormalization contractions # ---------------------------- @@ -753,6 +895,21 @@ function renormalize_corner(quadrant::AbstractTensorMap{S,3,3}, P_left, P_right) P_right[χ_in; χ1 D1 D2] * quadrant[χ1 D1 D2; χ2 D3 D4] * P_left[χ2 D3 D4; χ_out] end +""" + renormalize_corner(quadrant::AbstractTensorMap{S,2,2}, P_left, P_right) + +Apply projectors to each side of a quadrant. + +``` + |~~~~~~~~| -- |~~~~~~| + |quadrant| |P_left| -- + |~~~~~~~~| -- |~~~~~~| + | | + [P_right] + | +``` +""" + function renormalize_corner(quadrant::AbstractTensorMap{S,2,2}, P_left, P_right) where {S} return @autoopt @tensor corner[χ_in; χ_out] := P_right[χ_in; χ1 D1] * quadrant[χ1 D1; χ2 D3] * P_left[χ2 D3; χ_out] @@ -769,7 +926,7 @@ Alternatively, provide the constituent tensors and perform the complete contract ``` C_northwest -- E_north -- |~~~~~~| | || |P_left| -- - E_west= == ket-bra == |~~~~~~| + E_west == ket-bra == |~~~~~~| | || [~~~~~P_right~~~~~] | @@ -789,12 +946,6 @@ function renormalize_northwest_corner( return renormalize_corner(quadrant, P_left, P_right) end -function renormalize_northwest_corner( - quadrant::AbstractTensorMap{S,2,2}, P_left, P_right -) where {S} - return renormalize_corner(quadrant, P_left, P_right) -end - function renormalize_northwest_corner( E_west, C_northwest, E_north, P_left, P_right, ket::PEPSTensor, bra::PEPSTensor=ket ) @@ -808,6 +959,29 @@ function renormalize_northwest_corner( P_left[χ4 D7 D8; χ_out] end +""" + renormalize_northwest_corner(quadrant::AbstractTensorMap{S,2,2}, P_left, P_right) where {S} + renormalize_northwest_corner(E_west, C_northwest, E_north, P_left, P_right, partfunc::PartitionFunctionTensor) + +Apply `renormalize_corner` to the enlarged northwest corner. +Alternatively, provide the constituent tensors and perform the complete contraction. + +``` + C_northwest -- E_north -- |~~~~~~| + | | |P_left| -- + E_west -- ket-bra -- |~~~~~~| + | | + [~~~~~P_right~~~~~] + | +``` +""" + +function renormalize_northwest_corner( + quadrant::AbstractTensorMap{S,2,2}, P_left, P_right +) where {S} + return renormalize_corner(quadrant, P_left, P_right) +end + function renormalize_northwest_corner( E_west, C_northwest, E_north, P_left, P_right, partfunc::PartitionFunctionTensor ) @@ -851,12 +1025,6 @@ function renormalize_northeast_corner( return renormalize_corner(quadrant, P_left, P_right) end -function renormalize_northeast_corner( - quadrant::AbstractTensorMap{S,2,2}, P_left, P_right -) where {S} - return renormalize_corner(quadrant, P_left, P_right) -end - function renormalize_northeast_corner( E_north, C_northeast, E_east, P_left, P_right, ket::PEPSTensor, bra::PEPSTensor=ket ) @@ -870,6 +1038,29 @@ function renormalize_northeast_corner( P_left[χ4 D7 D8; χ_out] end +""" + renormalize_northwest_corner(quadrant::AbstractTensorMap{S,2,2}, P_left, P_right) where {S} + renormalize_northeast_corner(E_north, C_northeast, E_east, P_left, P_right, partfunc::PartitionFunctionTensor) + +Apply `renormalize_corner` to the enlarged northeast corner. +Alternatively, provide the constituent tensors and perform the complete contraction. + +``` + |~~~~~~~| -- E_north -- C_northeast + -- |P_right| | | + |~~~~~~~| -- ket-bra -- E_east + | | + [~~~~~~P_left~~~~~~] + | +``` +""" + +function renormalize_northeast_corner( + quadrant::AbstractTensorMap{S,2,2}, P_left, P_right +) where {S} + return renormalize_corner(quadrant, P_left, P_right) +end + function renormalize_northeast_corner( E_north, C_northeast, E_east, P_left, P_right, partfunc::PartitionFunctionTensor ) @@ -913,12 +1104,6 @@ function renormalize_southeast_corner( return renormalize_corner(quadrant, P_left, P_right) end -function renormalize_southeast_corner( - quadrant::AbstractTensorMap{S,2,2}, P_left, P_right -) where {S} - return renormalize_corner(quadrant, P_left, P_right) -end - function renormalize_southeast_corner( E_east, C_southeast, E_south, P_left, P_right, ket::PEPSTensor, bra::PEPSTensor=ket ) @@ -932,6 +1117,29 @@ function renormalize_southeast_corner( P_left[χ4 D7 D8; χ_out] end +""" + renormalize_southeast_corner(quadrant::AbstractTensorMap{S,2,2}, P_left, P_right) where {S} + renormalize_southeast_corner(E_east, C_southeast, E_south, P_left, P_right, partfunc::PartitionFunctionTensor) + +Apply `renormalize_corner` to the enlarged southeast corner. +Alternatively, provide the constituent tensors and perform the complete contraction. + +``` + | + [~~~~~P_right~~~~~] + | | + |~~~~~~| -- ket-bra -- E_east + -- |P_left| | | + |~~~~~~| -- E_south -- C_southeast +``` +""" + +function renormalize_southeast_corner( + quadrant::AbstractTensorMap{S,2,2}, P_left, P_right +) where {S} + return renormalize_corner(quadrant, P_left, P_right) +end + function renormalize_southeast_corner( E_east, C_southeast, E_south, P_left, P_right, partfunc::PartitionFunctionTensor ) @@ -955,7 +1163,7 @@ Alternatively, provide the constituent tensors and perform the complete contract ``` | [~~~~~P_right~~~~~] - || || + | || E_west == ket-bra == |~~~~~~| | || |P_left| -- C_southwest -- E_south -- |~~~~~~| @@ -975,12 +1183,6 @@ function renormalize_southwest_corner( return renormalize_southwest_corner(quadrant, P_left, P_right) end -function renormalize_southwest_corner( - quadrant::AbstractTensorMap{S,2,2}, P_left, P_right -) where {S} - return renormalize_southwest_corner(quadrant, P_left, P_right) -end - function renormalize_southwest_corner( E_south, C_southwest, E_west, P_left, P_right, ket::PEPSTensor, bra::PEPSTensor=ket ) @@ -994,6 +1196,29 @@ function renormalize_southwest_corner( P_left[χ4 D7 D8; χ_out] end +""" + renormalize_southwest_corner(quadrant::AbstractTensorMap{S,2,2}, P_left, P_right) where {S} + renormalize_southwest_corner(E_south, C_southwest, E_west, P_left, P_right, partfunc::PartitionFunctionTensor) + +Apply `renormalize_corner` to the enlarged southwest corner. +Alternatively, provide the constituent tensors and perform the complete contraction. + +``` + | + [~~~~~P_right~~~~~] + | | + E_west -- ket-bra -- |~~~~~~| + | | |P_left| -- + C_southwest -- E_south -- |~~~~~~| +``` +""" + +function renormalize_southwest_corner( + quadrant::AbstractTensorMap{S,2,2}, P_left, P_right +) where {S} + return renormalize_southwest_corner(quadrant, P_left, P_right) +end + function renormalize_southwest_corner( E_south, C_southwest, E_west, P_left, P_right, partfunc::PartitionFunctionTensor ) @@ -1010,12 +1235,20 @@ end renormalize_bottom_corner((r, c), envs, projectors) Apply bottom projector to southwest corner and south edge. +For the case of a PEPSTensor: ``` | [P_bottom] | || C -- E -- in ``` +For the case of a PartitionFunctionTensor: +``` + | + [P_bottom] + | | + C -- E -- in +``` """ function renormalize_bottom_corner( (row, col), envs::CTMRGEnv{C,<:CTMRGEdgeTensor{S,3}}, projectors @@ -1040,12 +1273,20 @@ end renormalize_top_corner((row, col), envs::CTMRGEnv, projectors) Apply top projector to northwest corner and north edge. +For the case of a PEPSTensor: ``` C -- E -- | || [~P_top~] | ``` +For the case of a PartitionFunctionTensor: +``` + C -- E -- + | | + [~P_top~] + | +``` """ function renormalize_top_corner((row, col), envs::CTMRGEnv, projectors) C_northwest = envs.corners[NORTHWEST, row, _prev(col, end)] @@ -1100,6 +1341,20 @@ function renormalize_north_edge( P_right[χ_W; χ1 D5 D6] end +""" + renormalize_north_edge((row, col), envs, P_left, P_right, partfunc) + renormalize_north_edge(E_north, P_left, P_right, partfunc) + +Absorb a bra-ket pair into the north edge using the given projectors and environment tensors. + +``` + |~~~~~~| -- E_north -- |~~~~~~~| + -- |P_left| | |P_right| -- + |~~~~~~| -- ket-bra -- |~~~~~~~| + | +``` +""" + function renormalize_north_edge( (row, col), envs::CTMRGEnv, P_left, P_right, partfunc::InfinitePartitionFunction ) @@ -1131,7 +1386,7 @@ Absorb a bra-ket pair into the east edge using the given projectors and environm | [~~P_bottom~~] | || - E_east == ket-bra + E_east == ket-bra == | || [~~~~P_top~~~] | @@ -1160,6 +1415,23 @@ function renormalize_east_edge( P_top[χ_N; χ1 D5 D6] end +""" + renormalize_east_edge((row, col), envs, P_top, P_bottom, partfunc) + renormalize_east_edge(E_east, P_top, P_bottom, partfunc) + +Absorb a bra-ket pair into the east edge using the given projectors and environment tensors. + +``` + | + [~~P_bottom~~] + | | + E_east -- ket-bra -- + | | + [~~~~P_top~~~] + | +``` +""" + function renormalize_east_edge( (row, col), envs::CTMRGEnv, P_bottom, P_top, partfunc::InfinitePartitionFunction ) @@ -1192,6 +1464,7 @@ Absorb a bra-ket pair into the south edge using the given projectors and environ |~~~~~~~| == ket-bra == |~~~~~~| -- |P_right| || |P_left| -- |~~~~~~~| -- E_south -- |~~~~~~| + || ``` """ function renormalize_south_edge( @@ -1217,6 +1490,20 @@ function renormalize_south_edge( P_right[χ_E; χ1 D5 D6] end +""" + renormalize_south_edge((row, col), envs, P_left, P_right, partfunc) + renormalize_south_edge(E_south, P_left, P_right, partfunc) + +Absorb a bra-ket pair into the south edge using the given projectors and environment tensors. + +``` + | + |~~~~~~~| -- ket-bra -- |~~~~~~| + -- |P_right| | |P_left| -- + |~~~~~~~| -- E_south -- |~~~~~~| +``` | +""" + function renormalize_south_edge( (row, col), envs::CTMRGEnv, P_left, P_right, partfunc::InfinitePartitionFunction ) @@ -1248,7 +1535,7 @@ Absorb a bra-ket pair into the west edge using the given projectors and environm | [~~P_bottom~~] | || - E_west == ket-bra + E_west == ket-bra == | || [~~~~P_top~~~] | @@ -1296,6 +1583,23 @@ function renormalize_west_edge( P_top[χ_S; χ1 D5 D6] end +""" + renormalize_west_edge((row, col), envs, P_top, P_bottom, partfunc) + renormalize_west_edge(E_west, P_top, P_bottom, partfunc) + +Absorb a bra-ket pair into the west edge using the given projectors and environment tensors. + +``` + | + [~~P_bottom~~] + | | + E_west -- ket-bra -- + | | + [~~~~P_top~~~] + | +``` +""" + function renormalize_west_edge( # For simultaneous CTMRG scheme (row, col), envs::CTMRGEnv, diff --git a/src/states/abstractpeps.jl b/src/states/abstractpeps.jl index 81fc8196..84be177d 100644 --- a/src/states/abstractpeps.jl +++ b/src/states/abstractpeps.jl @@ -6,6 +6,14 @@ conventionally ordered as: ``T : P ← N ⊗ E ⊗ S ⊗ W``. Here, ``P``, ``N`` ``W`` denote the physics, north, east, south and west spaces, respectively. """ const PEPSTensor{S} = AbstractTensorMap{S,1,4} where {S<:ElementarySpace} + +""" + const PartitionFunctionTensor{S} + +Default type for partition function tensors with 4 virtual indices, +conventionally ordered as: ``T : W ⊗ S ← N ⊗ E``. Here, ``N``, ``E``, ``S`` and +``W`` denote the north, east, south and west spaces, respectively. +""" const PartitionFunctionTensor{S} = AbstractTensorMap{S,2,2} where {S<:ElementarySpace} """ diff --git a/src/states/infinitepartitionfunction.jl b/src/states/infinitepartitionfunction.jl index dae55b22..64d71cdf 100644 --- a/src/states/infinitepartitionfunction.jl +++ b/src/states/infinitepartitionfunction.jl @@ -66,16 +66,16 @@ end Create an `InfinitePartitionFunction` by specifying a tensor and unit cell. The unit cell is labeled as a matrix which means that any tensor in the unit cell, -regardless if PEPS tensor or environment tensor, is obtained by shifting the row +regardless if partition function tensor or environment tensor, is obtained by shifting the row and column index `[r, c]` by one, respectively: ``` | | | ---C[r-1,c-1]---T[r-1,c]---T[r-1,c+1]--- - | || || ----T[r,c-1]=====AA[r,c]====AA[r,c+1]==== - | || || ----T[r+1,c-1]===AA[r+1,c]==AA[r+1,c+1]== - | || || + | | | +---T[r,c-1]-----AA[r,c]----AA[r,c+1]---- + | | | +---T[r+1,c-1]---AA[r+1,c]--AA[r+1,c+1]-- + | | | ``` The unit cell has periodic boundary conditions, so `[r, c]` is indexed modulo the size of the unit cell. From 7049b2dc9316fff03b80e335623961efb4853bec Mon Sep 17 00:00:00 2001 From: sanderdemeyer Date: Mon, 6 Jan 2025 14:19:00 +0100 Subject: [PATCH 07/47] change convention of PartitionFuntionTensor --- .../contractions/ctmrg_contractions.jl | 42 +++++++++---------- src/algorithms/toolbox.jl | 2 +- src/environments/ctmrg_environments.jl | 8 ++-- src/states/abstractpeps.jl | 6 +-- test/ctmrg/partition_function.jl | 5 +-- 5 files changed, 31 insertions(+), 32 deletions(-) diff --git a/src/algorithms/contractions/ctmrg_contractions.jl b/src/algorithms/contractions/ctmrg_contractions.jl index 702ccd6d..1dc6475d 100644 --- a/src/algorithms/contractions/ctmrg_contractions.jl +++ b/src/algorithms/contractions/ctmrg_contractions.jl @@ -76,7 +76,7 @@ function enlarge_northwest_corner( E_west[χ_S D1; χ1] * C_northwest[χ1; χ2] * E_north[χ2 D2; χ_E] * - partfunc[D2 D_E; D_S D1] + partfunc[D1 D_S; D2 D_E] end """ @@ -151,7 +151,7 @@ function enlarge_northeast_corner( E_north[χ_W D1; χ1] * C_northeast[χ1; χ2] * E_east[χ2 D2; χ_S] * - partfunc[D1 D2; D_S D_W] + partfunc[D_W D_S; D1 D2] end """ @@ -226,7 +226,7 @@ function enlarge_southeast_corner( E_east[χ_N D1; χ1] * C_southeast[χ1; χ2] * E_south[χ2 D2; χ_W] * - partfunc[D_N D1; D2 D_W] + partfunc[D_W D2; D_N D1] end """ @@ -301,7 +301,7 @@ function enlarge_southwest_corner( E_south[χ_E D1; χ1] * C_southwest[χ1; χ2] * E_west[χ2 D2; χ_N] * - partfunc[D_N D_E; D1 D2] + partfunc[D2 D1; D_N D_E] end # Projector contractions @@ -345,7 +345,7 @@ Contract the CTMRG left projector with the higher-dimensional subspace facing to function left_projector(E_1, C, E_2, V, isqS, partfunc::PartitionFunctionTensor) return @autoopt @tensor P_left[χ_in D_in; χ_out] := - E_1[χ_in D1; χ1] * C[χ1; χ2] * E_2[χ2 D2; χ3] * partfunc[D2 D3; D_in D1] + E_1[χ_in D1; χ1] * C[χ1; χ2] * E_2[χ2 D2; χ3] * partfunc[D1 D_in; D2 D3] conj(V[χ4; χ3 D3]) return isqS[χ4; χ_out] end @@ -388,7 +388,7 @@ Contract the CTMRG right projector with the higher-dimensional subspace facing t function right_projector(E_1, C, E_2, U, isqS, partfunc::PartitionFunctionTensor) return @autoopt @tensor P_right[χ_in; χ_out D_out] := - isqS[χ_in; χ1] * conj(U[χ1; χ2 D1]) * partfunc[D2 D3; D_out D1] + isqS[χ_in; χ1] * conj(U[χ1; χ2 D1]) * partfunc[D1 D_out; D2 D3] return E_2[χ2 D2; χ3] * C[χ3; χ4] * E_1[χ4 D3; χ_out] end @@ -566,7 +566,7 @@ Contract two quadrants (enlarged corners) to form a half-infinite environment. ``` |~~~~~~~~~| -- |~~~~~~~~~| |quadrant1| |quadrant2| - |~~~~~~~~~| == |~~~~~~~~~| + |~~~~~~~~~| -- |~~~~~~~~~| | | | | ``` @@ -606,8 +606,8 @@ function halfinfinite_environment( E_1[χ_in D1; χ1] * C_1[χ1; χ2] * E_2[χ2 D3; χ3] * - partfunc_1[D3 D9; D_in D1] * - partfunc_2[D5 D7; D_out D9] * + partfunc_1[D1 D_in; D3 D9] * + partfunc_2[D9 D_out; D5 D7] * E_3[χ3 D5; χ4] * C_2[χ4; χ5] * E_4[χ5 D7; χ_out] @@ -620,8 +620,8 @@ function halfinfinite_environment( E_1[χ_in D1; χ1] * C_1[χ1; χ2] * E_2[χ2 D3; χ3] * - partfunc_1[D3 D9; D_in D1] * - partfunc_2[D5 D7; D11 D9] * + partfunc_1[D1 D_in; D3 D9] * + partfunc_2[D9 D11; D5 D7] * E_3[χ3 D5; χ4] * C_2[χ4; χ5] * E_4[χ5 D7; χ6] * @@ -636,8 +636,8 @@ function halfinfinite_environment( conj(E_1[χ1 D3; χ2]) * conj(C_1[χ2; χ3]) * conj(E_2[χ3 D5; χ4]) * - conj(partfunc_1[D5 D11; D1 D3]) * - conj(partfunc_2[D7 D9; D_in D11]) * + conj(partfunc_1[D3 D1; D5 D11]) * + conj(partfunc_2[D11 D_in; D7 D9]) * conj(E_3[χ4 D7; χ5]) * conj(C_2[χ5; χ6]) * conj(E_4[χ6 D9; χ_in]) @@ -990,7 +990,7 @@ function renormalize_northwest_corner( E_west[χ1 D3; χ2] * C_northwest[χ2; χ3] * E_north[χ3 D5; χ4] * - partfunc[D5 D7; D1 D3] * + partfunc[D3 D1; D5 D7] * P_left[χ4 D7; χ_out] end @@ -1069,7 +1069,7 @@ function renormalize_northeast_corner( E_north[χ1 D3; χ2] * C_northeast[χ2; χ3] * E_east[χ3 D5; χ4] * - partfunc[D3 D5; D7 D1] * + partfunc[D1 D7; D3 D5] * P_left[χ4 D7; χ_out] end @@ -1148,7 +1148,7 @@ function renormalize_southeast_corner( E_east[χ1 D3; χ2] * C_southeast[χ2; χ3] * E_south[χ3 D5; χ4] * - partfunc[D1 D3; D5 D7] * + partfunc[D7 D5; D1 D3] * P_left[χ4 D7; χ_out] end @@ -1227,7 +1227,7 @@ function renormalize_southwest_corner( E_south[χ1 D3; χ2] * C_southwest[χ2; χ3] * E_west[χ3 D5; χ4] * - partfunc[D7 D1; D3 D5] * + partfunc[D5 D3; D7 D1] * P_left[χ4 D7; χ_out] end @@ -1371,7 +1371,7 @@ function renormalize_north_edge( ) where {S} return @autoopt @tensor edge[χ_W D_S; χ_E] := E_north[χ1 D1; χ2] * - partfunc[D1 D3; D_S D5] * + partfunc[D5 D_S; D1 D3] * P_left[χ2 D3; χ_E] * P_right[χ_W; χ1 D5] end @@ -1448,7 +1448,7 @@ function renormalize_east_edge( ) where {S} return @autoopt @tensor edge[χ_N D_W; χ_S] := E_east[χ1 D1; χ2] * - partfunc[D5 D1; D3 D_W] * + partfunc[D_W D3; D5 D1] * P_bottom[χ2 D3; χ_S] * P_top[χ_N; χ1 D5] end @@ -1520,7 +1520,7 @@ function renormalize_south_edge( ) where {S} return @autoopt @tensor edge[χ_E D_N; χ_W] := E_south[χ1 D1; χ2] * - partfunc[D_N D5; D1 D3] * + partfunc[D3 D1; D_N D5] * P_left[χ2 D3; χ_W] * P_right[χ_E; χ1 D5] end @@ -1632,7 +1632,7 @@ function renormalize_west_edge( ) where {S} return @autoopt @tensor edge[χ_S D_E; χ_N] := E_west[χ1 D1; χ2] * - partfunc[D3 D_E; D5 D1] * + partfunc[D1 D5; D3 D_E] * P_bottom[χ2 D3; χ_N] * P_top[χ_S; χ1 D5] end diff --git a/src/algorithms/toolbox.jl b/src/algorithms/toolbox.jl index 8146b50e..bea0f5fb 100644 --- a/src/algorithms/toolbox.jl +++ b/src/algorithms/toolbox.jl @@ -73,7 +73,7 @@ function LinearAlgebra.norm(partfunc::InfinitePartitionFunction, env::CTMRGEnv) env.corners[SOUTHEAST, rnext, cnext][χ6; χ7] * env.edges[SOUTH, rnext, c][χ7 D7; χ8] * env.corners[SOUTHWEST, rnext, cprev][χ8; χ1] * - partfunc[r, c][D3 D5; D7 D1] + partfunc[r, c][D1 D7; D3 D5] total *= tr( env.corners[NORTHWEST, rprev, cprev] * env.corners[NORTHEAST, rprev, c] * diff --git a/src/environments/ctmrg_environments.jl b/src/environments/ctmrg_environments.jl index 87dab522..644b9f59 100644 --- a/src/environments/ctmrg_environments.jl +++ b/src/environments/ctmrg_environments.jl @@ -308,10 +308,10 @@ function CTMRGEnv( chis_west::A=chis_north, ) where {A<:AbstractMatrix{<:ElementarySpaceLike}} Ds_north = map(partfunc.A) do t - return (adjoint(space(t, 1)),) + return (adjoint(space(t, 3)),) end Ds_east = map(partfunc.A) do t - return (adjoint(space(t, 2)),) + return (adjoint(space(t, 4)),) end return CTMRGEnv( randn, @@ -334,10 +334,10 @@ function CTMRGEnv( chis_west::A=chis_north, ) where {A<:AbstractMatrix{<:ElementarySpaceLike}} Ds_north = map(partfunc.A) do t - return (adjoint(space(t, 1)),) + return (adjoint(space(t, 3)),) end Ds_east = map(partfunc.A) do t - return (adjoint(space(t, 2)),) + return (adjoint(space(t, 4)),) end return CTMRGEnv( f, diff --git a/src/states/abstractpeps.jl b/src/states/abstractpeps.jl index 84be177d..8be5d442 100644 --- a/src/states/abstractpeps.jl +++ b/src/states/abstractpeps.jl @@ -79,9 +79,9 @@ Abstract supertype for a 2D projected entangled-pair operator. abstract type AbstractPEPO end # Rotations -Base.rotl90(t::PartitionFunctionTensor) = permute(t, ((2, 3), (1, 2))) -Base.rotr90(t::PartitionFunctionTensor) = permute(t, ((4, 1), (2, 3))) -Base.rot180(t::PartitionFunctionTensor) = permute(t, ((3, 4), (1, 2))) +Base.rotl90(t::PartitionFunctionTensor) = permute(t, ((3, 1), (4, 2))) +Base.rotr90(t::PartitionFunctionTensor) = permute(t, ((2, 4), (1, 3))) +Base.rot180(t::PartitionFunctionTensor) = permute(t, ((4, 3), (2, 1))) Base.rotl90(t::PEPSTensor) = permute(t, ((1,), (3, 4, 5, 2))) Base.rotr90(t::PEPSTensor) = permute(t, ((1,), (5, 2, 3, 4))) diff --git a/test/ctmrg/partition_function.jl b/test/ctmrg/partition_function.jl index f6d8bcad..24b28d17 100644 --- a/test/ctmrg/partition_function.jl +++ b/test/ctmrg/partition_function.jl @@ -66,7 +66,7 @@ function classical_ising(; beta=log(1 + sqrt(2)) / 2, J=1.0) O = zeros(2, 2, 2, 2) O[1, 1, 1, 1] = 1 O[2, 2, 2, 2] = 1 - @tensor o[-1 -2; -3 -4] := O[1 2; 3 4] * nt[-1; 1] * nt[-2; 2] * nt[-3; 3] * nt[-4; 4] + @tensor o[-1 -2; -3 -4] := O[3 4; 2 1] * nt[-3; 3] * nt[-4; 4] * nt[-2; 2] * nt[-1; 1] # magnetization tensor M = copy(O) @@ -101,8 +101,7 @@ function local_contraction( env.edges[SOUTH, 1, 1][C_SSE D_S; C_SSW] * env.corners[SOUTHWEST, 1, 1][C_SSW; C_WSW] * env.edges[WEST, 1, 1][C_WSW D_W; C_WNW] * - O[D_N D_E; D_S D_W] - # O[D_W D_S; D_N D_E] # TODO: switch to this convention + O[D_W D_S; D_N D_E] end ## Test From 9908180856371a37f603622ddf7101b5f1952843 Mon Sep 17 00:00:00 2001 From: sanderdemeyer Date: Mon, 6 Jan 2025 14:27:30 +0100 Subject: [PATCH 08/47] bug fix in left_projector --- .../contractions/ctmrg_contractions.jl | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/algorithms/contractions/ctmrg_contractions.jl b/src/algorithms/contractions/ctmrg_contractions.jl index 1dc6475d..870329d7 100644 --- a/src/algorithms/contractions/ctmrg_contractions.jl +++ b/src/algorithms/contractions/ctmrg_contractions.jl @@ -345,9 +345,12 @@ Contract the CTMRG left projector with the higher-dimensional subspace facing to function left_projector(E_1, C, E_2, V, isqS, partfunc::PartitionFunctionTensor) return @autoopt @tensor P_left[χ_in D_in; χ_out] := - E_1[χ_in D1; χ1] * C[χ1; χ2] * E_2[χ2 D2; χ3] * partfunc[D1 D_in; D2 D3] - conj(V[χ4; χ3 D3]) - return isqS[χ4; χ_out] + E_1[χ_in D1; χ1] * + C[χ1; χ2] * + E_2[χ2 D2; χ3] * + partfunc[D1 D_in; D2 D3] * + conj(V[χ4; χ3 D3]) * + isqS[χ4; χ_out] end """ @@ -388,8 +391,12 @@ Contract the CTMRG right projector with the higher-dimensional subspace facing t function right_projector(E_1, C, E_2, U, isqS, partfunc::PartitionFunctionTensor) return @autoopt @tensor P_right[χ_in; χ_out D_out] := - isqS[χ_in; χ1] * conj(U[χ1; χ2 D1]) * partfunc[D1 D_out; D2 D3] - return E_2[χ2 D2; χ3] * C[χ3; χ4] * E_1[χ4 D3; χ_out] + isqS[χ_in; χ1] * + conj(U[χ1; χ2 D1]) * + partfunc[D1 D_out; D2 D3] * + E_2[χ2 D2; χ3] * + C[χ3; χ4] * + E_1[χ4 D3; χ_out] end """ From 3f128e88002f5c250f42278d34ed8c48566ce659 Mon Sep 17 00:00:00 2001 From: sanderdemeyer Date: Mon, 6 Jan 2025 15:12:48 +0100 Subject: [PATCH 09/47] format fix --- src/states/infinitepartitionfunction.jl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/states/infinitepartitionfunction.jl b/src/states/infinitepartitionfunction.jl index 64d71cdf..7541b783 100644 --- a/src/states/infinitepartitionfunction.jl +++ b/src/states/infinitepartitionfunction.jl @@ -5,7 +5,9 @@ Represents an infinite projected entangled-pair state on a 2D square lattice. """ struct InfinitePartitionFunction{T<:PartitionFunctionTensor} <: AbstractPartitionFunction A::Matrix{T} - InfinitePartitionFunction{T}(A::Matrix{T}) where {T<:PartitionFunctionTensor} = new{T}(A) + function InfinitePartitionFunction{T}(A::Matrix{T}) where {T<:PartitionFunctionTensor} + return new{T}(A) + end function InfinitePartitionFunction(A::Array{T,2}) where {T<:PartitionFunctionTensor} for (d, w) in Tuple.(CartesianIndices(A)) space(A[d, w], 1) == space(A[_prev(d, end), w], 3)' || throw( From c822dc7a6a1f618943e8f534833a6ea628992a63 Mon Sep 17 00:00:00 2001 From: sanderdemeyer Date: Mon, 6 Jan 2025 15:13:14 +0100 Subject: [PATCH 10/47] full_infinite_environment for PartitionFunction --- .../contractions/ctmrg_contractions.jl | 202 ++++++++++++++++++ 1 file changed, 202 insertions(+) diff --git a/src/algorithms/contractions/ctmrg_contractions.jl b/src/algorithms/contractions/ctmrg_contractions.jl index 870329d7..5628aecb 100644 --- a/src/algorithms/contractions/ctmrg_contractions.jl +++ b/src/algorithms/contractions/ctmrg_contractions.jl @@ -878,6 +878,208 @@ function full_infinite_environment( E_8[χ11 D21 D22; χ_in] end +""" + full_infinite_environment( + quadrant1::T, quadrant2::T, quadrant3::T, quadrant4::T + ) where {T<:AbstractTensorMap{<:ElementarySpace,2,2}} + function full_infinite_environment( + half1::T, half2::T + ) where {T<:AbstractTensorMap{<:ElementarySpace,2,2}} + full_infinite_environment(C_1, C_2, C_3, C_4, E_1, E_2, E_3, E_4, E_5, E_6, E_7, E_8, + partfunc_1::P, partfunc_2::P) where {P<:PartitionFunctionTensor} + full_infinite_environment(C_1, C_2, E_1, E_2, E_3, E_4, x, + partfunc_1::P, partfunc_2::P, partfunc_3::P, partfunc_4::P) where {P<:PartitionFunctionTensor} + full_infinite_environment(x, C_1, C_2, E_1, E_2, E_3, E_4, + partfunc_1::P, partfunc_2::P, partfunc_3::P, partfunc_4::P) where {P<:PartitionFunctionTensor} + +Contract four quadrants (enlarged corners) to form a full-infinite environment. + +``` + |~~~~~~~~~| -- |~~~~~~~~~| + |quadrant1| |quadrant2| + |~~~~~~~~~| -- |~~~~~~~~~| + | | | | + | | + | | | | + |~~~~~~~~~| -- |~~~~~~~~~| + |quadrant4| |quadrant3| + |~~~~~~~~~| -- |~~~~~~~~~| +``` + +In the same manner two halfs can be used to contract the full-infinite environment. + +``` + |~~~~~~~~~~~~~~~~~~~~~~~~| + | half1 | + |~~~~~~~~~~~~~~~~~~~~~~~~| + | | | | + | | + | | | | + |~~~~~~~~~~~~~~~~~~~~~~~~| + | half2 | + |~~~~~~~~~~~~~~~~~~~~~~~~| +``` + +The environment can also be contracted directly from all its constituent tensors. + +``` + C_1 -- E_2 -- E_3 -- C_2 + | | | | + E_1 -- partfunc_1 -- partfunc_2 -- E_4 + | | | | + | | + | | | | + E_8 -- partfunc_4 -- partfunc_3 -- E_5 + | | | | + C_4 -- E_7 -- E_6 -- C_3 +``` + +Alternatively, contract the environment with a vector `x` acting on it + +``` + C_1 -- E_2 -- E_3 -- C_2 + | | | | + E_1 -- partfunc_1 -- partfunc_2 -- E_4 + | | | | + | | + | | + [~~~~~x~~~~~~] | | + | | | | + E_8 -- partfunc_4 -- partfunc_3 -- E_5 + | | | | + C_4 -- E_7 -- E_6 -- C_3 + +``` + +or contract the adjoint environment with `x`, e.g. as needed for iterative solvers. +""" +function full_infinite_environment( + quadrant1::T, quadrant2::T, quadrant3::T, quadrant4::T +) where {T<:AbstractTensorMap{<:ElementarySpace,2,2}} + return @autoopt @tensor env[χ_in D_inabove; χ_out D_outabove] := + quadrant1[χ_in D_inabove; χ1 D1] * + quadrant2[χ1 D1; χ2 D2] * + quadrant3[χ2 D2; χ3 D3] * + quadrant4[χ3 D3; χ_out D_outabove] +end +function full_infinite_environment( + half1::T, half2::T +) where {T<:AbstractTensorMap{<:ElementarySpace,2,2}} + return half_infinite_environment(half1, half2) +end +function full_infinite_environment( + C_1, + C_2, + C_3, + C_4, + E_1, + E_2, + E_3, + E_4, + E_5, + E_6, + E_7, + E_8, + partfunc_1::P, + partfunc_2::P, + partfunc_3::P, + partfunc_4::P, +) where {P<:PartitionFunctionTensor} + return @autoopt @tensor env[χ_in D_in; χ_out D_out] := + E_1[χ_in D1; χ1] * + C_1[χ1; χ2] * + E_2[χ2 D3; χ3] * + partfunc_1[D1 D_in; D3 D11] * + partfunc_2[D11 D9; D5 D7] * + E_3[χ3 D5; χ4] * + C_2[χ4; χ5] * + E_4[χ5 D7; χ6] * + E_5[χ6 D13; χ7] * + C_3[χ7; χ8] * + E_6[χ8 D15; χ9] * + partfunc_3[D17 D15; D9 D13] * + partfunc_4[D21 D19; D_out D17] * + E_7[χ9 D19; χ10] * + C_4[χ10; χ11] * + E_8[χ11 D21; χ_out] +end +function full_infinite_environment( + C_1, + C_2, + C_3, + C_4, + E_1, + E_2, + E_3, + E_4, + E_5, + E_6, + E_7, + E_8, + x::AbstractTensor{S,2}, + partfunc_1::P, + partfunc_2::P, + partfunc_3::P, + partfunc_4::P, +) where {S,P<:PartitionFunctionTensor} + return @autoopt @tensor env_x[χ_in D_in] := + E_1[χ_in D1; χ1] * + C_1[χ1; χ2] * + E_2[χ2 D3; χ3] * + partfunc_1[D1 D_in; D3 D11] * + partfunc_2[D11 D9; D5 D7] * + E_3[χ3 D5; χ4] * + C_2[χ4; χ5] * + E_4[χ5 D7; χ6] * + E_5[χ6 D13; χ7] * + C_3[χ7; χ8] * + E_6[χ8 D15; χ9] * + partfunc_3[D17 D15; D9 D13] * + partfunc_4[D21 D19; D_x D17] * + E_7[χ9 D19; χ10] * + C_4[χ10; χ11] * + E_8[χ11 D21; χ_x] * + x[χ_x D_x] +end +function full_infinite_environment( + x::AbstractTensor{S,2}, + C_1, + C_2, + C_3, + C_4, + E_1, + E_2, + E_3, + E_4, + E_5, + E_6, + E_7, + E_8, + partfunc_1::P, + partfunc_2::P, + partfunc_3::P, + partfunc_4::P, +) where {S,P<:PEPSTensor} + return @autoopt @tensor x_env[χ_in D_in] := + x[χ_x D_x] * + E_1[χ_x D1; χ1] * + C_1[χ1; χ2] * + E_2[χ2 D3; χ3] * + partfunc_1[D1 D_x; D3 D11] * + partfunc_2[D11 D9; D5 D7] * + E_3[χ3 D5; χ4] * + C_2[χ4; χ5] * + E_4[χ5 D7; χ6] * + E_5[χ6 D13; χ7] * + C_3[χ7; χ8] * + E_6[χ8 D15; χ9] * + partfunc_3[D17 D15; D9 D13] * + partfunc_4[D21 D19; D_in D17] * + E_7[χ9 D19; χ10] * + C_4[χ10; χ11] * + E_8[χ11 D21; χ_in] +end + # Renormalization contractions # ---------------------------- From 4a90a9a59245945b830395d0f1745a0393c629d8 Mon Sep 17 00:00:00 2001 From: sanderdemeyer Date: Mon, 6 Jan 2025 15:22:51 +0100 Subject: [PATCH 11/47] fixes for sequential ctmrg --- src/algorithms/ctmrg/sequential.jl | 9 ++++++--- src/states/infinitepartitionfunction.jl | 4 ++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/algorithms/ctmrg/sequential.jl b/src/algorithms/ctmrg/sequential.jl index 94f4846e..ec28061b 100644 --- a/src/algorithms/ctmrg/sequential.jl +++ b/src/algorithms/ctmrg/sequential.jl @@ -53,7 +53,10 @@ Compute CTMRG projectors in the `:sequential` scheme either for an entire column for a specific `coordinate` (where `dir=WEST` is already implied in the `:sequential` scheme). """ function sequential_projectors( - col::Int, state::InfinitePEPS, envs::CTMRGEnv, alg::ProjectorAlgorithm + col::Int, + state::Union{InfinitePEPS,InfinitePartitionFunction}, + envs::CTMRGEnv, + alg::ProjectorAlgorithm, ) # SVD half-infinite environment column-wise ϵ = Zygote.Buffer(zeros(real(scalartype(envs)), size(envs, 2))) @@ -71,7 +74,7 @@ function sequential_projectors( end function sequential_projectors( coordinate::NTuple{3,Int}, - state::InfinitePEPS, + state::Union{InfinitePEPS,InfinitePartitionFunction}, envs::CTMRGEnv, alg::HalfInfiniteProjector, ) @@ -83,7 +86,7 @@ function sequential_projectors( end function sequential_projectors( coordinate::NTuple{3,Int}, - state::InfinitePEPS, + state::Union{InfinitePEPS,InfinitePartitionFunction}, envs::CTMRGEnv, alg::FullInfiniteProjector, ) diff --git a/src/states/infinitepartitionfunction.jl b/src/states/infinitepartitionfunction.jl index 7541b783..2a42cf73 100644 --- a/src/states/infinitepartitionfunction.jl +++ b/src/states/infinitepartitionfunction.jl @@ -10,10 +10,10 @@ struct InfinitePartitionFunction{T<:PartitionFunctionTensor} <: AbstractPartitio end function InfinitePartitionFunction(A::Array{T,2}) where {T<:PartitionFunctionTensor} for (d, w) in Tuple.(CartesianIndices(A)) - space(A[d, w], 1) == space(A[_prev(d, end), w], 3)' || throw( + space(A[d, w], 1) == space(A[_prev(d, end), w], 4)' || throw( SpaceMismatch("North virtual space at site $((d, w)) does not match.") ) - space(A[d, w], 2) == space(A[d, _next(w, end)], 4)' || + space(A[d, w], 2) == space(A[d, _next(w, end)], 3)' || throw(SpaceMismatch("East virtual space at site $((d, w)) does not match.")) dim(space(A[d, w])) > 0 || @warn "no fusion channels at site ($d, $w)" end From 327160d0fee50913ae21261e255f9ece388775ef Mon Sep 17 00:00:00 2001 From: Lander Burgelman <39218680+leburgel@users.noreply.github.com> Date: Tue, 7 Jan 2025 09:26:17 +0100 Subject: [PATCH 12/47] Update src/algorithms/contractions/ctmrg_contractions.jl Add internal convenience aliases for different flavors of edge tensors Co-authored-by: Lukas Devos --- src/algorithms/contractions/ctmrg_contractions.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/algorithms/contractions/ctmrg_contractions.jl b/src/algorithms/contractions/ctmrg_contractions.jl index 5628aecb..7ae87622 100644 --- a/src/algorithms/contractions/ctmrg_contractions.jl +++ b/src/algorithms/contractions/ctmrg_contractions.jl @@ -1,4 +1,6 @@ const CTMRGEdgeTensor{S,N} = AbstractTensorMap{S,N,1} +const CTMRG_PEPS_EdgeTensor{S} = CTMRGEdgeTensor{S,3} +const CTMRG_PF_EdgeTensor{S} = CTMRGEdgeTensor{S,2} const CTMRGCornerTensor{S} = AbstractTensorMap{S,1,1} # Enlarged corner contractions From 30cfb4947ee6f1c3395e8bb47d63657357a1e9ce Mon Sep 17 00:00:00 2001 From: leburgel Date: Tue, 7 Jan 2025 10:24:35 +0100 Subject: [PATCH 13/47] Add internal aliases, merge first set of docstrings and update type annotations --- .../contractions/ctmrg_contractions.jl | 286 +++++++----------- src/states/abstractpeps.jl | 1 + src/states/infinitepartitionfunction.jl | 2 + test/ctmrg/partition_function.jl | 4 +- 4 files changed, 109 insertions(+), 184 deletions(-) diff --git a/src/algorithms/contractions/ctmrg_contractions.jl b/src/algorithms/contractions/ctmrg_contractions.jl index 7ae87622..7fa05720 100644 --- a/src/algorithms/contractions/ctmrg_contractions.jl +++ b/src/algorithms/contractions/ctmrg_contractions.jl @@ -7,17 +7,24 @@ const CTMRGCornerTensor{S} = AbstractTensorMap{S,1,1} # ---------------------------- """ - enlarge_northwest_corner((row, col), envs, ket, bra) - enlarge_northwest_corner(E_west, C_northwest, E_north, ket, bra) + enlarge_northwest_corner((row, col), envs, ket::InfinitePEPS, bra::InfinitePEPS=ket) + enlarge_northwest_corner((row, col), envs, partfunc::InfinitePartitionFunction) + enlarge_northwest_corner(E_west, C_northwest, E_north, ket::PEPSTensor, bra::PEPSTensor=ket) + enlarge_northwest_corner(E_west, C_northwest, E_north, partfunc::PartitionFunctionTensor) Contract the enlarged northwest corner of the CTMRG environment, either by specifying the -coordinates, environments and state, or by directly providing the tensors. +coordinates, environments and network, or by directly providing the tensors. + +The networks and tensors (denoted `A` below) can correspond to either: +- a pair of 'ket' and 'bra' `InfinitePEPS` networks and a pair of 'ket' and 'bra' + `PEPSTensor`s +- an `InfinitePartitionFunction` network and a `PartitionFunctionTensor`. ``` C_northwest -- E_north -- - | || - E_west == ket-bra == - | || + | | + E_west -- A -- + | | ``` """ function enlarge_northwest_corner( @@ -31,12 +38,12 @@ function enlarge_northwest_corner( ) end function enlarge_northwest_corner( - E_west::CTMRGEdgeTensor{S,3}, + E_west::CTMRG_PEPS_EdgeTensor, C_northwest::CTMRGCornerTensor, - E_north::CTMRGEdgeTensor{S,3}, + E_north::CTMRG_PEPS_EdgeTensor, ket::PEPSTensor, bra::PEPSTensor=ket, -) where {S} +) return @autoopt @tensor corner[χ_S D_Sabove D_Sbelow; χ_E D_Eabove D_Ebelow] := E_west[χ_S D1 D2; χ1] * C_northwest[χ1; χ2] * @@ -44,24 +51,8 @@ function enlarge_northwest_corner( ket[d; D3 D_Eabove D_Sabove D1] * conj(bra[d; D4 D_Ebelow D_Sbelow D2]) end - -""" - enlarge_northwest_corner((row, col), envs, partfunc) - enlarge_northwest_corner(E_west, C_northwest, E_north, partfunc) - -Contract the enlarged northwest corner of the CTMRG environment, either by specifying the -coordinates, environments and state, or by directly providing the tensors. - -``` - C_northwest -- E_north -- - | | - E_west -- ket-bra -- - | | -``` -""" - function enlarge_northwest_corner( - (row, col), envs::CTMRGEnv, partfunc::InfinitePartitionFunction + (row, col), envs::CTMRGEnv, partfunc::InfinitePF ) E_west = envs.edges[WEST, row, _prev(col, end)] C_northwest = envs.corners[NORTHWEST, _prev(row, end), _prev(col, end)] @@ -69,11 +60,11 @@ function enlarge_northwest_corner( return enlarge_northwest_corner(E_west, C_northwest, E_north, partfunc[row, col]) end function enlarge_northwest_corner( - E_west::CTMRGEdgeTensor{S,2}, + E_west::CTMRG_PF_EdgeTensor, C_northwest::CTMRGCornerTensor, - E_north::CTMRGEdgeTensor{S,2}, - partfunc::PartitionFunctionTensor, -) where {S} + E_north::CTMRG_PF_EdgeTensor, + partfunc::PFunctionTensor, +) return @autoopt @tensor corner[χ_S D_S; χ_E D_E] := E_west[χ_S D1; χ1] * C_northwest[χ1; χ2] * @@ -82,21 +73,28 @@ function enlarge_northwest_corner( end """ - enlarge_northeast_corner((row, col), envs, ket, bra) - enlarge_northeast_corner(E_north, C_northeast, E_east, ket, bra) + enlarge_northeast_corner((row, col), envs, ket::InfinitePEPS, bra::InfinitePEPS=ket) + enlarge_northeast_corner((row, col), envs, partfunc::InfinitePartitionFunction) + enlarge_northeast_corner(E_north, C_northeast, E_east, ket::PEPSTensor, bra::PEPSTensor=ket) + enlarge_northeast_corner(E_north, C_northeast, E_east, partfunc::PartitionFunctionTensor) Contract the enlarged northeast corner of the CTMRG environment, either by specifying the -coordinates, environments and state, or by directly providing the tensors. +coordinates, environments and networks, or by directly providing the tensors. + +The networks and tensors (denoted `A` below) can correspond to either: +- a pair of 'ket' and 'bra' `InfinitePEPS` networks and a pair of 'ket' and 'bra' + `PEPSTensor`s +- an `InfinitePartitionFunction` network and a `PartitionFunctionTensor`. ``` -- E_north -- C_northeast - || | - == ket-bra == E_east - || | + | | + -- A -- E_east + | | ``` """ function enlarge_northeast_corner( - (row, col), envs::CTMRGEnv{S,3}, ket::InfinitePEPS, bra::InfinitePEPS=ket + (row, col), envs::CTMRGEnv, ket::InfinitePEPS, bra::InfinitePEPS=ket ) where {S} E_north = envs.edges[NORTH, _prev(row, end), col] C_northeast = envs.corners[NORTHEAST, _prev(row, end), _next(col, end)] @@ -106,12 +104,12 @@ function enlarge_northeast_corner( ) end function enlarge_northeast_corner( - E_north::CTMRGEdgeTensor{S,3}, + E_north::CTMRG_PEPS_EdgeTensor, C_northeast::CTMRGCornerTensor, - E_east::CTMRGEdgeTensor{S,3}, + E_east::CTMRG_PEPS_EdgeTensor, ket::PEPSTensor, bra::PEPSTensor=ket, -) where {S} +) return @autoopt @tensor corner[χ_W D_Wabove D_Wbelow; χ_S D_Sabove D_Sbelow] := E_north[χ_W D1 D2; χ1] * C_northeast[χ1; χ2] * @@ -119,24 +117,8 @@ function enlarge_northeast_corner( ket[d; D1 D3 D_Sabove D_Wabove] * conj(bra[d; D2 D4 D_Sbelow D_Wbelow]) end - -""" - enlarge_northeast_corner((row, col), envs, partfunc) - enlarge_northeast_corner(E_north, C_northeast, E_east, partfunc) - -Contract the enlarged northeast corner of the CTMRG environment, either by specifying the -coordinates, environments and state, or by directly providing the tensors. - -``` - -- E_north -- C_northeast - | | - -- ket-bra -- E_east - | | -``` -""" - function enlarge_northeast_corner( - (row, col), envs::CTMRGEnv, partfunc::InfinitePartitionFunction + (row, col), envs::CTMRGEnv, partfunc::InfinitePF ) E_north = envs.edges[NORTH, _prev(row, end), col] C_northeast = envs.corners[NORTHEAST, _prev(row, end), _next(col, end)] @@ -144,11 +126,11 @@ function enlarge_northeast_corner( return enlarge_northeast_corner(E_north, C_northeast, E_east, partfunc[row, col]) end function enlarge_northeast_corner( - E_north::CTMRGEdgeTensor{S,2}, + E_north::CTMRG_PF_EdgeTensor, C_northeast::CTMRGCornerTensor, - E_east::CTMRGEdgeTensor{S,2}, + E_east::CTMRG_PF_EdgeTensor, partfunc::PartitionFunctionTensor, -) where {S} +) return @autoopt @tensor corner[χ_W D_W; χ_S D_S] := E_north[χ_W D1; χ1] * C_northeast[χ1; χ2] * @@ -157,16 +139,23 @@ function enlarge_northeast_corner( end """ - enlarge_southeast_corner((row, col), envs, ket, bra) - enlarge_southeast_corner(E_east, C_southeast, E_south, ket, bra) + enlarge_southeast_corner((row, col), envs, ket::InfinitePEPS, bra::InfinitePEPS=ket) + enlarge_southeast_corner((row, col), envs, partfunc::InfinitePartitionFunction) + enlarge_southeast_corner(E_east, C_southeast, E_south, ket::PEPSTensor, bra::PEPSTensor=ket) + enlarge_southeast_corner(E_east, C_southeast, E_south, partfunc::PartitionFunctionTensor) Contract the enlarged southeast corner of the CTMRG environment, either by specifying the coordinates, environments and state, or by directly providing the tensors. +The networks and tensors (denoted `A` below) can correspond to either: +- a pair of 'ket' and 'bra' `InfinitePEPS` networks and a pair of 'ket' and 'bra' + `PEPSTensor`s +- an `InfinitePartitionFunction` network and a `PartitionFunctionTensor`. + ``` - || | - == ket-bra == E_east - || | + | | + -- A -- E_east + | | -- E_south -- C_southeast ``` """ @@ -181,12 +170,12 @@ function enlarge_southeast_corner( ) end function enlarge_southeast_corner( - E_east::CTMRGEdgeTensor{S,3}, + E_east::CTMRG_PEPS_EdgeTensor, C_southeast::CTMRGCornerTensor, - E_south::CTMRGEdgeTensor{S,3}, + E_south::CTMRG_PEPS_EdgeTensor, ket::PEPSTensor, bra::PEPSTensor=ket, -) where {S} +) return @autoopt @tensor corner[χ_N D_Nabove D_Nbelow; χ_W D_Wabove D_Wbelow] := E_east[χ_N D1 D2; χ1] * C_southeast[χ1; χ2] * @@ -194,22 +183,6 @@ function enlarge_southeast_corner( ket[d; D_Nabove D1 D3 D_Wabove] * conj(bra[d; D_Nbelow D2 D4 D_Wbelow]) end - -""" - enlarge_southeast_corner((row, col), envs, partfunc) - enlarge_southeast_corner(E_east, C_southeast, E_south, partfunc) - -Contract the enlarged southeast corner of the CTMRG environment, either by specifying the -coordinates, environments and state, or by directly providing the tensors. - -``` - | | - -- ket-bra -- E_east - | | - -- E_south -- C_southeast -``` -""" - function enlarge_southeast_corner( (row, col), envs::CTMRGEnv, partfunc::InfinitePartitionFunction ) @@ -219,11 +192,11 @@ function enlarge_southeast_corner( return enlarge_southeast_corner(E_east, C_southeast, E_south, partfunc[row, col]) end function enlarge_southeast_corner( - E_east::CTMRGEdgeTensor{S,2}, + E_east::CTMRG_PF_EdgeTensor, C_southeast::CTMRGCornerTensor, - E_south::CTMRGEdgeTensor{S,2}, + E_south::CTMRG_PF_EdgeTensor, partfunc::PartitionFunctionTensor, -) where {S} +) w return @autoopt @tensor corner[χ_N D_N; χ_W D_W] := E_east[χ_N D1; χ1] * C_southeast[χ1; χ2] * @@ -232,16 +205,23 @@ function enlarge_southeast_corner( end """ - enlarge_southwest_corner((row, col), envs, ket, bra) - enlarge_southwest_corner(E_south, C_southwest, E_west, ket, bra) + enlarge_southwest_corner((row, col), envs, ket::InfinitePEPS, bra::InfinitePEPS=ket) + enlarge_southwest_corner((row, col), envs, partfunc::InfinitePartitionFunction) + enlarge_southwest_corner(E_south, C_southwest, E_west, ket::PEPSTensor, bra::PEPSTensor=ket) + enlarge_southwest_corner(E_south, C_southwest, E_west, partfunc::PartitionFunctionTensor) Contract the enlarged southwest corner of the CTMRG environment, either by specifying the coordinates, environments and state, or by directly providing the tensors. +The networks and tensors (denoted `A` below) can correspond to either: +- a pair of 'ket' and 'bra' `InfinitePEPS` networks and a pair of 'ket' and 'bra' + `PEPSTensor`s +- an `InfinitePartitionFunction` network and a `PartitionFunctionTensor`. + ``` - | || - E_west == ket-bra == - | || + | | + E_west -- A -- + | | C_southwest -- E_south -- ``` """ @@ -256,12 +236,12 @@ function enlarge_southwest_corner( ) end function enlarge_southwest_corner( - E_south::CTMRGEdgeTensor{S,3}, + E_south::CTMRG_PEPS_EdgeTensor, C_southwest::CTMRGCornerTensor, - E_west::CTMRGEdgeTensor{S,3}, + E_west::CTMRG_PEPS_EdgeTensor, ket::PEPSTensor, bra::PEPSTensor=ket, -) where {S} +) return @autoopt @tensor corner[χ_E D_Eabove D_Ebelow; χ_N D_Nabove D_Nbelow] := E_south[χ_E D1 D2; χ1] * C_southwest[χ1; χ2] * @@ -269,22 +249,6 @@ function enlarge_southwest_corner( ket[d; D_Nabove D_Eabove D1 D3] * conj(bra[d; D_Nbelow D_Ebelow D2 D4]) end - -""" - enlarge_southwest_corner((row, col), envs, partfunc) - enlarge_southwest_corner(E_south, C_southwest, E_west, partfunc) - -Contract the enlarged southwest corner of the CTMRG environment, either by specifying the -coordinates, environments and state, or by directly providing the tensors. - -``` - | | - E_west -- ket-bra -- - | | - C_southwest -- E_south -- -``` -""" - function enlarge_southwest_corner( (row, col), envs::CTMRGEnv, partfunc::InfinitePartitionFunction ) @@ -294,11 +258,11 @@ function enlarge_southwest_corner( return enlarge_southwest_corner(E_south, C_southwest, E_west, partfunc[row, col]) end function enlarge_southwest_corner( - E_south::CTMRGEdgeTensor{S,2}, + E_south::CTMRG_PF_EdgeTensor, C_southwest::CTMRGCornerTensor, - E_west::CTMRGEdgeTensor{S,2}, + E_west::CTMRG_PF_EdgeTensor, partfunc::PartitionFunctionTensor, -) where {S} +) return @autoopt @tensor corner[χ_E D_E; χ_N D_N] := E_south[χ_E D1; χ1] * C_southwest[χ1; χ2] * @@ -311,14 +275,15 @@ end """ left_projector(E_1, C, E_2, V, isqS, ket::PEPSTensor, bra::PEPSTensor=ket) + left_projector(E_1, C, E_2, V, isqS, partfunc::PartitionFunctionTensor) Contract the CTMRG left projector with the higher-dimensional subspace facing to the left. ``` C -- E_2 -- |~~| - | || |V'| -- isqS -- - E_1 == ket-bra == |~~| - | || + | | |V'| -- isqS -- + E_1 -- A -- |~~| + | | ``` """ function left_projector(E_1, C, E_2, V, isqS, ket::PEPSTensor, bra::PEPSTensor=ket) @@ -331,21 +296,7 @@ function left_projector(E_1, C, E_2, V, isqS, ket::PEPSTensor, bra::PEPSTensor=k conj(V[χ4; χ3 D5 D6]) * isqS[χ4; χ_out] end - -""" - left_projector(E_1, C, E_2, V, isqS, partfunc::PartitionFunctionTensor) - -Contract the CTMRG left projector with the higher-dimensional subspace facing to the left. - -``` - C -- E_2 -- |~~| - | | |V'| -- isqS -- - E_1 -- ket-bra -- |~~| - | | -``` -""" - -function left_projector(E_1, C, E_2, V, isqS, partfunc::PartitionFunctionTensor) +function left_projector(E_1, C, E_2, V, isqS, partfunc::PFTensor) return @autoopt @tensor P_left[χ_in D_in; χ_out] := E_1[χ_in D1; χ1] * C[χ1; χ2] * @@ -357,14 +308,15 @@ end """ right_projector(E_1, C, E_2, U, isqS, ket::PEPSTensor, bra::PEPSTensor=ket) + right_projector(E_1, C, E_2, U, isqS, partfunc::PartitionFunctionTensor) Contract the CTMRG right projector with the higher-dimensional subspace facing to the right. ``` |~~| -- E_2 -- C - -- isqS -- |U'| || | - |~~| == ket-bra == E_1 - || | + -- isqS -- |U'| | | + |~~| -- A -- E_1 + | | ``` """ function right_projector(E_1, C, E_2, U, isqS, ket::PEPSTensor, bra::PEPSTensor=ket) @@ -377,21 +329,7 @@ function right_projector(E_1, C, E_2, U, isqS, ket::PEPSTensor, bra::PEPSTensor= C[χ3; χ4] * E_1[χ4 D5 D6; χ_out] end - -""" - right_projector(E_1, C, E_2, U, isqS, partfunc::PartitionFunctionTensor) - -Contract the CTMRG right projector with the higher-dimensional subspace facing to the right. - -``` - |~~| -- E_2 -- C - -- isqS -- |U'| | | - |~~| -- ket-bra -- E_1 - | | -``` -""" - -function right_projector(E_1, C, E_2, U, isqS, partfunc::PartitionFunctionTensor) +function right_projector(E_1, C, E_2, U, isqS, partfunc::PFTensor) return @autoopt @tensor P_right[χ_in; χ_out D_out] := isqS[χ_in; χ1] * conj(U[χ1; χ2 D1]) * @@ -407,7 +345,6 @@ end Compute projectors based on a SVD of `Q * Q_next`, where the inverse square root `isqS` of the singular values is computed. -For the case of a PEPSTensor: Left projector: ``` -- |~~~~~~| -- |~~| @@ -421,21 +358,6 @@ Right projector: -- isqS -- |U'| | Q | |~~| == |~~~| == ``` - -For the case of a PartitionFunctionTensor: -Left projector: -``` - -- |~~~~~~| -- |~~| - |Q_next| |V'| -- isqS -- - -- |~~~~~~| -- |~~| -``` - -Right projector: -``` - |~~| -- |~~~| -- - -- isqS -- |U'| | Q | - |~~| -- |~~~| -- -``` """ function contract_projectors(U, S, V, Q, Q_next) isqS = sdiag_pow(S, -0.5) @@ -608,7 +530,7 @@ function half_infinite_environment( quadrant1[χ_in D_in; χ D1] * quadrant2[χ D1; χ_out D_out] end -function halfinfinite_environment( +function half_infinite_environment( C_1, C_2, E_1, E_2, E_3, E_4, partfunc_1::P, partfunc_2::P ) where {P<:PartitionFunctionTensor} return @autoopt @tensor env[χ_in D_in; χ_out D_out] := @@ -1462,8 +1384,8 @@ For the case of a PartitionFunctionTensor: ``` """ function renormalize_bottom_corner( - (row, col), envs::CTMRGEnv{C,<:CTMRGEdgeTensor{S,3}}, projectors -) where {C,S} + (row, col), envs::CTMRGEnv{C,<:CTMRG_PEPS_EdgeTensor}, projectors +) where {C} C_southwest = envs.corners[SOUTHWEST, row, _prev(col, end)] E_south = envs.edges[SOUTH, row, col] P_bottom = projectors[1][row] @@ -1471,7 +1393,7 @@ function renormalize_bottom_corner( E_south[χ_in D1 D2; χ1] * C_southwest[χ1; χ2] * P_bottom[χ2 D1 D2; χ_out] end function renormalize_bottom_corner( - (row, col), envs::CTMRGEnv{C,<:CTMRGEdgeTensor{S,2}}, projectors + (row, col), envs::CTMRGEnv{C,<:CTMRG_PF_EdgeTensor}, projectors ) where {C,S} C_southwest = envs.corners[SOUTHWEST, row, _prev(col, end)] E_south = envs.edges[SOUTH, row, col] @@ -1505,11 +1427,11 @@ function renormalize_top_corner((row, col), envs::CTMRGEnv, projectors) P_top = projectors[2][_next(row, end)] return renormalize_top_corner(C_northwest, E_north, P_top) end -function renormalize_top_corner(C_northwest, E_north::CTMRGEdgeTensor{S,3}, P_top) where {S} +function renormalize_top_corner(C_northwest, E_north::CTMRG_PEPS_EdgeTensor, P_top) where {S} return @autoopt @tensor corner[χ_in; χ_out] := P_top[χ_in; χ1 D1 D2] * C_northwest[χ1; χ2] * E_north[χ2 D1 D2; χ_out] end -function renormalize_top_corner(C_northwest, E_north::CTMRGEdgeTensor{S,2}, P_top) where {S} +function renormalize_top_corner(C_northwest, E_north::CTMRG_PF_EdgeTensor, P_top) where {S} return @autoopt @tensor corner[χ_in; χ_out] := P_top[χ_in; χ1 D1] * C_northwest[χ1; χ2] * E_north[χ2 D1; χ_out] end @@ -1542,7 +1464,7 @@ function renormalize_north_edge( end function renormalize_north_edge( - E_north::CTMRGEdgeTensor{S,3}, P_left, P_right, ket::PEPSTensor, bra::PEPSTensor=ket + E_north::CTMRG_PEPS_EdgeTensor, P_left, P_right, ket::PEPSTensor, bra::PEPSTensor=ket ) where {S} return @autoopt @tensor edge[χ_W D_Sab D_Sbe; χ_E] := E_north[χ1 D1 D2; χ2] * @@ -1578,7 +1500,7 @@ function renormalize_north_edge( end function renormalize_north_edge( - E_north::CTMRGEdgeTensor{S,2}, P_left, P_right, partfunc::PartitionFunctionTensor + E_north::CTMRG_PF_EdgeTensor, P_left, P_right, partfunc::PartitionFunctionTensor ) where {S} return @autoopt @tensor edge[χ_W D_S; χ_E] := E_north[χ1 D1; χ2] * @@ -1616,7 +1538,7 @@ function renormalize_east_edge( end function renormalize_east_edge( - E_east::CTMRGEdgeTensor{S,3}, P_bottom, P_top, ket::PEPSTensor, bra::PEPSTensor=ket + E_east::CTMRG_PEPS_EdgeTensor, P_bottom, P_top, ket::PEPSTensor, bra::PEPSTensor=ket ) where {S} return @autoopt @tensor edge[χ_N D_Wab D_Wbe; χ_S] := E_east[χ1 D1 D2; χ2] * @@ -1655,7 +1577,7 @@ function renormalize_east_edge( end function renormalize_east_edge( - E_east::CTMRGEdgeTensor{S,2}, P_bottom, P_top, partfunc::PartitionFunctionTensor + E_east::CTMRG_PF_EdgeTensor, P_bottom, P_top, partfunc::PartitionFunctionTensor ) where {S} return @autoopt @tensor edge[χ_N D_W; χ_S] := E_east[χ1 D1; χ2] * @@ -1691,7 +1613,7 @@ function renormalize_south_edge( end function renormalize_south_edge( - E_south::CTMRGEdgeTensor{S,3}, P_left, P_right, ket::PEPSTensor, bra::PEPSTensor=ket + E_south::CTMRG_PEPS_EdgeTensor, P_left, P_right, ket::PEPSTensor, bra::PEPSTensor=ket ) where {S} return @autoopt @tensor edge[χ_E D_Nab D_Nbe; χ_W] := E_south[χ1 D1 D2; χ2] * @@ -1727,7 +1649,7 @@ function renormalize_south_edge( end function renormalize_south_edge( - E_south::CTMRGEdgeTensor{S,2}, P_left, P_right, partfunc::PartitionFunctionTensor + E_south::CTMRG_PF_EdgeTensor, P_left, P_right, partfunc::PartitionFunctionTensor ) where {S} return @autoopt @tensor edge[χ_E D_N; χ_W] := E_south[χ1 D1; χ2] * @@ -1784,7 +1706,7 @@ function renormalize_west_edge( # For sequential CTMRG scheme ) end function renormalize_west_edge( - E_west::CTMRGEdgeTensor{S,3}, P_bottom, P_top, ket::PEPSTensor, bra::PEPSTensor=ket + E_west::CTMRG_PEPS_EdgeTensor, P_bottom, P_top, ket::PEPSTensor, bra::PEPSTensor=ket ) where {S} return @autoopt @tensor edge[χ_S D_Eab D_Ebe; χ_N] := E_west[χ1 D1 D2; χ2] * @@ -1839,7 +1761,7 @@ function renormalize_west_edge( # For sequential CTMRG scheme ) end function renormalize_west_edge( - E_west::CTMRGEdgeTensor{S,2}, P_bottom, P_top, partfunc::PartitionFunctionTensor + E_west::CTMRG_PF_EdgeTensor, P_bottom, P_top, partfunc::PartitionFunctionTensor ) where {S} return @autoopt @tensor edge[χ_S D_E; χ_N] := E_west[χ1 D1; χ2] * @@ -1936,14 +1858,14 @@ Multiply edge tensor with incoming and outgoing gauge signs. ``` """ function fix_gauge_edge( - edge::CTMRGEdgeTensor{S,3}, σ_in::CTMRGCornerTensor, σ_out::CTMRGCornerTensor + edge::CTMRG_PEPS_EdgeTensor, σ_in::CTMRGCornerTensor, σ_out::CTMRGCornerTensor ) where {S} @autoopt @tensor edge_fix[χ_in D_above D_below; χ_out] := σ_in[χ_in; χ1] * edge[χ1 D_above D_below; χ2] * conj(σ_out[χ_out; χ2]) end function fix_gauge_edge( - edge::CTMRGEdgeTensor{S,2}, σ_in::CTMRGCornerTensor, σ_out::CTMRGCornerTensor + edge::CTMRG_PF_EdgeTensor, σ_in::CTMRGCornerTensor, σ_out::CTMRGCornerTensor ) where {S} @autoopt @tensor edge_fix[χ_in D_above D_below; χ_out] := σ_in[χ_in; χ1] * edge[χ1 D_above D_below; χ2] * conj(σ_out[χ_out; χ2]) diff --git a/src/states/abstractpeps.jl b/src/states/abstractpeps.jl index 8be5d442..5f25d8ee 100644 --- a/src/states/abstractpeps.jl +++ b/src/states/abstractpeps.jl @@ -15,6 +15,7 @@ conventionally ordered as: ``T : W ⊗ S ← N ⊗ E``. Here, ``N``, ``E``, ``S` ``W`` denote the north, east, south and west spaces, respectively. """ const PartitionFunctionTensor{S} = AbstractTensorMap{S,2,2} where {S<:ElementarySpace} +const PFTensor{S} = PartitionFunctionTensor{S} """ PEPSTensor(f, ::Type{T}, Pspace::S, Nspace::S, diff --git a/src/states/infinitepartitionfunction.jl b/src/states/infinitepartitionfunction.jl index 2a42cf73..8110b974 100644 --- a/src/states/infinitepartitionfunction.jl +++ b/src/states/infinitepartitionfunction.jl @@ -21,6 +21,8 @@ struct InfinitePartitionFunction{T<:PartitionFunctionTensor} <: AbstractPartitio end end +const InfinitePF{T} = InfinitePartitionFunction{T} + ## Constructors """ InfinitePartitionFunction(A::AbstractMatrix{T}) diff --git a/test/ctmrg/partition_function.jl b/test/ctmrg/partition_function.jl index 24b28d17..3027df49 100644 --- a/test/ctmrg/partition_function.jl +++ b/test/ctmrg/partition_function.jl @@ -7,7 +7,7 @@ using MPSKit using PEPSKit: @autoopt, - CTMRGEdgeTensor, + CTMRG_PF_EdgeTensor, NORTHWEST, NORTHEAST, SOUTHEAST, @@ -91,7 +91,7 @@ end Contract a local rank-4 tensor with a given partition function environment. """ function local_contraction( - O::AbstractTensorMap{S,2,2}, env::CTMRGEnv{C,<:CTMRGEdgeTensor{S,2}} + O::AbstractTensorMap{S,2,2}, env::CTMRGEnv{C,<:CTMRG_PF_EdgeTensor} ) where {S,C} return @autoopt @tensor env.corners[NORTHWEST, 1, 1][C_WNW; C_NNW] * env.edges[NORTH, 1, 1][C_NNW D_N; C_NNE] * From 55a2a2256411a5835a232182333c0654771ba571 Mon Sep 17 00:00:00 2001 From: leburgel Date: Tue, 7 Jan 2025 10:26:58 +0100 Subject: [PATCH 14/47] Format --- src/algorithms/contractions/ctmrg_contractions.jl | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/algorithms/contractions/ctmrg_contractions.jl b/src/algorithms/contractions/ctmrg_contractions.jl index 7fa05720..6096b3db 100644 --- a/src/algorithms/contractions/ctmrg_contractions.jl +++ b/src/algorithms/contractions/ctmrg_contractions.jl @@ -51,9 +51,7 @@ function enlarge_northwest_corner( ket[d; D3 D_Eabove D_Sabove D1] * conj(bra[d; D4 D_Ebelow D_Sbelow D2]) end -function enlarge_northwest_corner( - (row, col), envs::CTMRGEnv, partfunc::InfinitePF -) +function enlarge_northwest_corner((row, col), envs::CTMRGEnv, partfunc::InfinitePF) E_west = envs.edges[WEST, row, _prev(col, end)] C_northwest = envs.corners[NORTHWEST, _prev(row, end), _prev(col, end)] E_north = envs.edges[NORTH, _prev(row, end), col] @@ -117,9 +115,7 @@ function enlarge_northeast_corner( ket[d; D1 D3 D_Sabove D_Wabove] * conj(bra[d; D2 D4 D_Sbelow D_Wbelow]) end -function enlarge_northeast_corner( - (row, col), envs::CTMRGEnv, partfunc::InfinitePF -) +function enlarge_northeast_corner((row, col), envs::CTMRGEnv, partfunc::InfinitePF) E_north = envs.edges[NORTH, _prev(row, end), col] C_northeast = envs.corners[NORTHEAST, _prev(row, end), _next(col, end)] E_east = envs.edges[EAST, row, _next(col, end)] @@ -196,7 +192,8 @@ function enlarge_southeast_corner( C_southeast::CTMRGCornerTensor, E_south::CTMRG_PF_EdgeTensor, partfunc::PartitionFunctionTensor, -) w +) + w return @autoopt @tensor corner[χ_N D_N; χ_W D_W] := E_east[χ_N D1; χ1] * C_southeast[χ1; χ2] * @@ -1427,7 +1424,9 @@ function renormalize_top_corner((row, col), envs::CTMRGEnv, projectors) P_top = projectors[2][_next(row, end)] return renormalize_top_corner(C_northwest, E_north, P_top) end -function renormalize_top_corner(C_northwest, E_north::CTMRG_PEPS_EdgeTensor, P_top) where {S} +function renormalize_top_corner( + C_northwest, E_north::CTMRG_PEPS_EdgeTensor, P_top +) where {S} return @autoopt @tensor corner[χ_in; χ_out] := P_top[χ_in; χ1 D1 D2] * C_northwest[χ1; χ2] * E_north[χ2 D1 D2; χ_out] end From 6d244d2a48259d9e7037ae340eda8543a46fd8ba Mon Sep 17 00:00:00 2001 From: leburgel Date: Tue, 7 Jan 2025 11:35:21 +0100 Subject: [PATCH 15/47] Fix typos and clean up signatures --- .../contractions/ctmrg_contractions.jl | 34 ++++++++----------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/src/algorithms/contractions/ctmrg_contractions.jl b/src/algorithms/contractions/ctmrg_contractions.jl index 6096b3db..419c332d 100644 --- a/src/algorithms/contractions/ctmrg_contractions.jl +++ b/src/algorithms/contractions/ctmrg_contractions.jl @@ -61,7 +61,7 @@ function enlarge_northwest_corner( E_west::CTMRG_PF_EdgeTensor, C_northwest::CTMRGCornerTensor, E_north::CTMRG_PF_EdgeTensor, - partfunc::PFunctionTensor, + partfunc::PFTensor, ) return @autoopt @tensor corner[χ_S D_S; χ_E D_E] := E_west[χ_S D1; χ1] * @@ -93,7 +93,7 @@ The networks and tensors (denoted `A` below) can correspond to either: """ function enlarge_northeast_corner( (row, col), envs::CTMRGEnv, ket::InfinitePEPS, bra::InfinitePEPS=ket -) where {S} +) E_north = envs.edges[NORTH, _prev(row, end), col] C_northeast = envs.corners[NORTHEAST, _prev(row, end), _next(col, end)] E_east = envs.edges[EAST, row, _next(col, end)] @@ -193,7 +193,6 @@ function enlarge_southeast_corner( E_south::CTMRG_PF_EdgeTensor, partfunc::PartitionFunctionTensor, ) - w return @autoopt @tensor corner[χ_N D_N; χ_W D_W] := E_east[χ_N D1; χ1] * C_southeast[χ1; χ2] * @@ -1391,7 +1390,7 @@ function renormalize_bottom_corner( end function renormalize_bottom_corner( (row, col), envs::CTMRGEnv{C,<:CTMRG_PF_EdgeTensor}, projectors -) where {C,S} +) where {C} C_southwest = envs.corners[SOUTHWEST, row, _prev(col, end)] E_south = envs.edges[SOUTH, row, col] P_bottom = projectors[1][row] @@ -1424,13 +1423,11 @@ function renormalize_top_corner((row, col), envs::CTMRGEnv, projectors) P_top = projectors[2][_next(row, end)] return renormalize_top_corner(C_northwest, E_north, P_top) end -function renormalize_top_corner( - C_northwest, E_north::CTMRG_PEPS_EdgeTensor, P_top -) where {S} +function renormalize_top_corner(C_northwest, E_north::CTMRG_PEPS_EdgeTensor, P_top) return @autoopt @tensor corner[χ_in; χ_out] := P_top[χ_in; χ1 D1 D2] * C_northwest[χ1; χ2] * E_north[χ2 D1 D2; χ_out] end -function renormalize_top_corner(C_northwest, E_north::CTMRG_PF_EdgeTensor, P_top) where {S} +function renormalize_top_corner(C_northwest, E_north::CTMRG_PF_EdgeTensor, P_top) return @autoopt @tensor corner[χ_in; χ_out] := P_top[χ_in; χ1 D1] * C_northwest[χ1; χ2] * E_north[χ2 D1; χ_out] end @@ -1464,7 +1461,7 @@ end function renormalize_north_edge( E_north::CTMRG_PEPS_EdgeTensor, P_left, P_right, ket::PEPSTensor, bra::PEPSTensor=ket -) where {S} +) return @autoopt @tensor edge[χ_W D_Sab D_Sbe; χ_E] := E_north[χ1 D1 D2; χ2] * ket[d; D1 D3 D_Sab D5] * @@ -1500,7 +1497,7 @@ end function renormalize_north_edge( E_north::CTMRG_PF_EdgeTensor, P_left, P_right, partfunc::PartitionFunctionTensor -) where {S} +) return @autoopt @tensor edge[χ_W D_S; χ_E] := E_north[χ1 D1; χ2] * partfunc[D5 D_S; D1 D3] * @@ -1538,7 +1535,7 @@ end function renormalize_east_edge( E_east::CTMRG_PEPS_EdgeTensor, P_bottom, P_top, ket::PEPSTensor, bra::PEPSTensor=ket -) where {S} +) return @autoopt @tensor edge[χ_N D_Wab D_Wbe; χ_S] := E_east[χ1 D1 D2; χ2] * ket[d; D5 D1 D3 D_Wab] * @@ -1577,7 +1574,7 @@ end function renormalize_east_edge( E_east::CTMRG_PF_EdgeTensor, P_bottom, P_top, partfunc::PartitionFunctionTensor -) where {S} +) return @autoopt @tensor edge[χ_N D_W; χ_S] := E_east[χ1 D1; χ2] * partfunc[D_W D3; D5 D1] * @@ -1613,7 +1610,7 @@ end function renormalize_south_edge( E_south::CTMRG_PEPS_EdgeTensor, P_left, P_right, ket::PEPSTensor, bra::PEPSTensor=ket -) where {S} +) return @autoopt @tensor edge[χ_E D_Nab D_Nbe; χ_W] := E_south[χ1 D1 D2; χ2] * ket[d; D_Nab D5 D1 D3] * @@ -1649,7 +1646,7 @@ end function renormalize_south_edge( E_south::CTMRG_PF_EdgeTensor, P_left, P_right, partfunc::PartitionFunctionTensor -) where {S} +) return @autoopt @tensor edge[χ_E D_N; χ_W] := E_south[χ1 D1; χ2] * partfunc[D3 D1; D_N D5] * @@ -1706,7 +1703,7 @@ function renormalize_west_edge( # For sequential CTMRG scheme end function renormalize_west_edge( E_west::CTMRG_PEPS_EdgeTensor, P_bottom, P_top, ket::PEPSTensor, bra::PEPSTensor=ket -) where {S} +) return @autoopt @tensor edge[χ_S D_Eab D_Ebe; χ_N] := E_west[χ1 D1 D2; χ2] * ket[d; D3 D_Eab D5 D1] * @@ -1761,7 +1758,7 @@ function renormalize_west_edge( # For sequential CTMRG scheme end function renormalize_west_edge( E_west::CTMRG_PF_EdgeTensor, P_bottom, P_top, partfunc::PartitionFunctionTensor -) where {S} +) return @autoopt @tensor edge[χ_S D_E; χ_N] := E_west[χ1 D1; χ2] * partfunc[D1 D5; D3 D_E] * @@ -1858,14 +1855,13 @@ Multiply edge tensor with incoming and outgoing gauge signs. """ function fix_gauge_edge( edge::CTMRG_PEPS_EdgeTensor, σ_in::CTMRGCornerTensor, σ_out::CTMRGCornerTensor -) where {S} +) @autoopt @tensor edge_fix[χ_in D_above D_below; χ_out] := σ_in[χ_in; χ1] * edge[χ1 D_above D_below; χ2] * conj(σ_out[χ_out; χ2]) end - function fix_gauge_edge( edge::CTMRG_PF_EdgeTensor, σ_in::CTMRGCornerTensor, σ_out::CTMRGCornerTensor -) where {S} +) @autoopt @tensor edge_fix[χ_in D_above D_below; χ_out] := σ_in[χ_in; χ1] * edge[χ1 D_above D_below; χ2] * conj(σ_out[χ_out; χ2]) end From e65651fa8ba436033cf2015ab9db81bf74100b69 Mon Sep 17 00:00:00 2001 From: leburgel Date: Tue, 7 Jan 2025 11:36:21 +0100 Subject: [PATCH 16/47] Split out abstract network definitions --- src/PEPSKit.jl | 6 +- src/networks/abstract_networks.jl | 20 ++++ .../abstractpeps.jl => networks/tensors.jl} | 113 +++++++++++------- 3 files changed, 96 insertions(+), 43 deletions(-) create mode 100644 src/networks/abstract_networks.jl rename src/{states/abstractpeps.jl => networks/tensors.jl} (62%) diff --git a/src/PEPSKit.jl b/src/PEPSKit.jl index f366e0a6..09f4dd44 100644 --- a/src/PEPSKit.jl +++ b/src/PEPSKit.jl @@ -22,10 +22,12 @@ include("utility/diffset.jl") include("utility/hook_pullback.jl") include("utility/autoopt.jl") -include("states/abstractpeps.jl") -include("states/infinitepartitionfunction.jl") +include("networks/tensors.jl") +include("networks/abstract_networks.jl") + include("states/infinitepeps.jl") include("states/infiniteweightpeps.jl") +include("states/infinitepartitionfunction.jl") include("operators/transferpeps.jl") include("operators/infinitepepo.jl") diff --git a/src/networks/abstract_networks.jl b/src/networks/abstract_networks.jl new file mode 100644 index 00000000..f85cc761 --- /dev/null +++ b/src/networks/abstract_networks.jl @@ -0,0 +1,20 @@ +""" + abstract type AbstractPartitionFunction end + +Abstract supertype for a 2D partitionFunction. +""" +abstract type AbstractPartitionFunction end + +""" + abstract type AbstractPEPS end + +Abstract supertype for a 2D projected entangled-pair state. +""" +abstract type AbstractPEPS end + +""" + abstract type AbstractPEPO end + +Abstract supertype for a 2D projected entangled-pair operator. +""" +abstract type AbstractPEPO end diff --git a/src/states/abstractpeps.jl b/src/networks/tensors.jl similarity index 62% rename from src/states/abstractpeps.jl rename to src/networks/tensors.jl index 5f25d8ee..d240a3e7 100644 --- a/src/states/abstractpeps.jl +++ b/src/networks/tensors.jl @@ -1,21 +1,58 @@ +# +# Partition function +# + """ - const PEPSTensor{S} + const PartitionFunctionTensor{S} -Default type for PEPS tensors with a single physical index, and 4 virtual indices, -conventionally ordered as: ``T : P ← N ⊗ E ⊗ S ⊗ W``. Here, ``P``, ``N``, ``E``, ``S`` and -``W`` denote the physics, north, east, south and west spaces, respectively. +Default type for partition function tensors with 4 virtual indices, conventionally ordered +as: ``T : W ⊗ S ← N ⊗ E``. Here, ``N``, ``E``, ``S`` and ``W`` denote the north, east, south +and west spaces, respectively. + +``` + N + / + v + / + W--<-- --<--E + / + v + / + S +``` """ -const PEPSTensor{S} = AbstractTensorMap{S,1,4} where {S<:ElementarySpace} +const PartitionFunctionTensor{S} = AbstractTensorMap{S,2,2} where {S<:ElementarySpace} +const PFTensor = PartitionFunctionTensor + +Base.rotl90(t::PFTensor) = permute(t, ((3, 1), (4, 2))) +Base.rotr90(t::PFTensor) = permute(t, ((2, 4), (1, 3))) +Base.rot180(t::PFTensor) = permute(t, ((4, 3), (2, 1))) + +# +# PEPS +# """ - const PartitionFunctionTensor{S} + const PEPSTensor{S} + +Default type for PEPS tensors with a single physical index, and 4 virtual indices, +conventionally ordered as: ``T : P ← N ⊗ E ⊗ S ⊗ W``. Here, ``P`` denotes the physical space +and ``N``, ``E``, ``S`` and ``W`` denote the north, east, south and west virtual spaces, +respectively. -Default type for partition function tensors with 4 virtual indices, -conventionally ordered as: ``T : W ⊗ S ← N ⊗ E``. Here, ``N``, ``E``, ``S`` and -``W`` denote the north, east, south and west spaces, respectively. +``` + N + / + v + / + W-->-- --<--E + /| + ^ v + / | + S P +``` """ -const PartitionFunctionTensor{S} = AbstractTensorMap{S,2,2} where {S<:ElementarySpace} -const PFTensor{S} = PartitionFunctionTensor{S} +const PEPSTensor{S} = AbstractTensorMap{S,1,4} where {S<:ElementarySpace} """ PEPSTensor(f, ::Type{T}, Pspace::S, Nspace::S, @@ -50,43 +87,37 @@ function PEPSTensor( return TensorMap(f, T, ℂ^Pspace ← ℂ^Nspace ⊗ ℂ^Espace ⊗ (ℂ^Sspace)' ⊗ (ℂ^Wspace)') end -""" - const PEPOTensor{S} - -Default type for PEPO tensors with a single incoming and outgoing physical index, and 4 -virtual indices, conventionally ordered as: O : P ⊗ P' ← N ⊗ E ⊗ S ⊗ W. -""" -const PEPOTensor{S} = AbstractTensorMap{S,2,4} where {S<:ElementarySpace} - -""" - abstract type AbstractPartitionFunction end +Base.rotl90(t::PEPSTensor) = permute(t, ((1,), (3, 4, 5, 2))) +Base.rotr90(t::PEPSTensor) = permute(t, ((1,), (5, 2, 3, 4))) +Base.rot180(t::PEPSTensor) = permute(t, ((1,), (4, 5, 2, 3))) -Abstract supertype for a 2D projected entangled-pair state. -""" -abstract type AbstractPartitionFunction end +# +# PEPO +# """ - abstract type AbstractPEPS end + const PEPOTensor{S} -Abstract supertype for a 2D projected entangled-pair state. -""" -abstract type AbstractPEPS end +Default type for PEPO tensors with a single incoming and outgoing physical index, and 4 +virtual indices, conventionally ordered as: ``T : P ⊗ P´ ← N ⊗ E ⊗ S ⊗ W``. Here, ``P´`` and +``P`` denote the incoming and outgoing physical space respectively, encoding the physical +mapping from ``P´'`` to ``P`` where ``P´'`` corresponds to a physical PEPS index. ``N``, +``E``, ``S`` and ``W`` denote the physics, north, east, south and west spaces, respectively. -""" - abstract type AbstractPEPO end -Abstract supertype for a 2D projected entangled-pair operator. +``` + P´ N + | / + ^ v + |/ + W-->-- --<--E + /| + ^ v + / | + S P +``` """ -abstract type AbstractPEPO end - -# Rotations -Base.rotl90(t::PartitionFunctionTensor) = permute(t, ((3, 1), (4, 2))) -Base.rotr90(t::PartitionFunctionTensor) = permute(t, ((2, 4), (1, 3))) -Base.rot180(t::PartitionFunctionTensor) = permute(t, ((4, 3), (2, 1))) - -Base.rotl90(t::PEPSTensor) = permute(t, ((1,), (3, 4, 5, 2))) -Base.rotr90(t::PEPSTensor) = permute(t, ((1,), (5, 2, 3, 4))) -Base.rot180(t::PEPSTensor) = permute(t, ((1,), (4, 5, 2, 3))) +const PEPOTensor{S} = AbstractTensorMap{S,2,4} where {S<:ElementarySpace} Base.rotl90(t::PEPOTensor) = permute(t, ((1, 2), (4, 5, 6, 3))) Base.rotr90(t::PEPOTensor) = permute(t, ((1, 2), (6, 3, 4, 5))) From 2140bc26238e504bde0b554f515c95caef372688 Mon Sep 17 00:00:00 2001 From: leburgel Date: Tue, 7 Jan 2025 11:41:16 +0100 Subject: [PATCH 17/47] Test different CTMRG and projector flavors to increase test coverage --- test/ctmrg/partition_function.jl | 51 +++++++++++++++++++------------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/test/ctmrg/partition_function.jl b/test/ctmrg/partition_function.jl index 3027df49..52fe30ea 100644 --- a/test/ctmrg/partition_function.jl +++ b/test/ctmrg/partition_function.jl @@ -117,24 +117,33 @@ Z = InfinitePartitionFunction(O) χenv = ℂ^12 env0 = CTMRGEnv(Z, χenv) -ctm_alg = SimultaneousCTMRG(; tol=1e-10, miniter=4, maxiter=100, verbosity=2) - -env = leading_boundary(env0, Z, ctm_alg) - -# check observables - -λ = norm(Z, env) -m = local_contraction(M, env) / local_contraction(O, env) -e = local_contraction(E, env) / local_contraction(O, env) - -f_exact, m_exact, e_exact = classical_ising_exact(; beta) - -# should be real-ish -@test abs(imag(λ)) < 1e-4 -@test abs(imag(m)) < 1e-4 -@test abs(imag(e)) < 1e-4 - -# should match exact solution -@test -log(λ) / beta ≈ f_exact rtol = 1e-5 -@test abs(m) ≈ abs(m_exact) rtol = 1e-5 -@test e ≈ e_exact rtol = 1e-2 +# cover all different flavors +ctm_styles = [SequentialCTMRG, SimultaneousCTMRG] +projector_algs = [HalfInfiniteProjector, FullInfiniteProjector] + +@testset "Classical Ising partition function using $ctm_style with $projector_alg" for ( + ctm_style, projector_alg +) in Iterators.product( + ctm_styles, projector_algs +) + ctm_alg = ctm_style(; tol=1e-10, miniter=4, maxiter=100, verbosity=2, projector_alg) + env = leading_boundary(env0, Z, ctm_alg) + + # check observables + + λ = norm(Z, env) + m = local_contraction(M, env) / local_contraction(O, env) + e = local_contraction(E, env) / local_contraction(O, env) + + f_exact, m_exact, e_exact = classical_ising_exact(; beta) + + # should be real-ish + @test abs(imag(λ)) < 1e-4 + @test abs(imag(m)) < 1e-4 + @test abs(imag(e)) < 1e-4 + + # should match exact solution + @test -log(λ) / beta ≈ f_exact rtol = 1e-4 + @test abs(m) ≈ abs(m_exact) rtol = 1e-4 + @test e ≈ e_exact rtol = 1e-1 # accuracy limited by bond dimension and maxiter +end From 37ad16b3a26bde9ca919e9552f6b66f4006d8939 Mon Sep 17 00:00:00 2001 From: leburgel Date: Tue, 7 Jan 2025 11:47:05 +0100 Subject: [PATCH 18/47] Use `half_infinite_environment` consistently --- src/algorithms/contractions/ctmrg_contractions.jl | 10 +++++----- src/algorithms/ctmrg/sparse_environments.jl | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/algorithms/contractions/ctmrg_contractions.jl b/src/algorithms/contractions/ctmrg_contractions.jl index 419c332d..cf3aae97 100644 --- a/src/algorithms/contractions/ctmrg_contractions.jl +++ b/src/algorithms/contractions/ctmrg_contractions.jl @@ -409,7 +409,7 @@ function half_infinite_environment( quadrant2[χ D1 D2; χ_out D_outabove D_outbelow] end -function halfinfinite_environment( +function half_infinite_environment( C_1, C_2, E_1, E_2, E_3, E_4, ket_1::P, ket_2::P, bra_1::P=ket_1, bra_2::P=ket_2 ) where {P<:PEPSTensor} return @autoopt @tensor env[χ_in D_inabove D_inbelow; χ_out D_outabove D_outbelow] := @@ -425,7 +425,7 @@ function halfinfinite_environment( E_4[χ5 D7 D8; χ_out] end -function halfinfinite_environment( +function half_infinite_environment( C_1, C_2, E_1, @@ -452,7 +452,7 @@ function halfinfinite_environment( x[χ6 D11 D12] end -function halfinfinite_environment( +function half_infinite_environment( x::AbstractTensor{S,3}, C_1, C_2, @@ -540,7 +540,7 @@ function half_infinite_environment( E_4[χ5 D7; χ_out] end -function halfinfinite_environment( +function half_infinite_environment( C_1, C_2, E_1, E_2, E_3, E_4, x::AbstractTensor{S,2}, partfunc_1::P, partfunc_2::P ) where {S,P<:PartitionFunctionTensor} return @autoopt @tensor env_x[χ_in D_in] := @@ -555,7 +555,7 @@ function halfinfinite_environment( x[χ6 D11] end -function halfinfinite_environment( +function half_infinite_environment( x::AbstractTensor{S,2}, C_1, C_2, E_1, E_2, E_3, E_4, partfunc_1::P, partfunc_2::P ) where {S,P<:PartitionFunctionTensor} return @autoopt @tensor env_x[χ_in D_in] := diff --git a/src/algorithms/ctmrg/sparse_environments.jl b/src/algorithms/ctmrg/sparse_environments.jl index 5e372e51..a6baed2d 100644 --- a/src/algorithms/ctmrg/sparse_environments.jl +++ b/src/algorithms/ctmrg/sparse_environments.jl @@ -262,7 +262,7 @@ function TensorKit.TensorMap(env::HalfInfiniteEnv) # Dense operator end function TensorKit.TensorMap(env::HalfInfinitePartitionFunctionEnv) # Dense operator - return halfinfinite_environment( + return half_infinite_environment( env.C_1, env.C_2, env.E_1, env.E_2, env.E_3, env.E_4, env.partfunc_1, env.partfunc_2 ) end @@ -305,8 +305,8 @@ function (env::HalfInfiniteEnv)(x, ::Val{true}) # Adjoint linear map: env()' * ) end -# Wrapper around halfinfinite_environment contraction using EnlargedCorners (used in ctmrg_projectors) -function halfinfinite_environment(ec_1::EnlargedCorner, ec_2::EnlargedCorner) +# Wrapper around half_infinite_environment contraction using EnlargedCorners (used in ctmrg_projectors) +function half_infinite_environment(ec_1::EnlargedCorner, ec_2::EnlargedCorner) return HalfInfiniteEnv( ec_1.C, ec_2.C, @@ -348,7 +348,7 @@ function (env::HalfInfinitePartitionFunctionEnv)(x, ::Val{true}) # Adjoint line ) end -# Wrapper around halfinfinite_environment contraction using EnlargedCorners (used in ctmrg_projectors) +# Wrapper around half_infinite_environment contraction using EnlargedCorners (used in ctmrg_projectors) function halfinfinite_partitionfunction_environment( ec_1::EnlargedPartitionFunctionCorner, ec_2::EnlargedPartitionFunctionCorner ) From 14ee40b28c26f5babd2854efc2c2fbbcf480af38 Mon Sep 17 00:00:00 2001 From: leburgel Date: Tue, 7 Jan 2025 12:35:17 +0100 Subject: [PATCH 19/47] Squash more docstrings --- .../contractions/ctmrg_contractions.jl | 575 ++++++------------ 1 file changed, 175 insertions(+), 400 deletions(-) diff --git a/src/algorithms/contractions/ctmrg_contractions.jl b/src/algorithms/contractions/ctmrg_contractions.jl index cf3aae97..a38aa743 100644 --- a/src/algorithms/contractions/ctmrg_contractions.jl +++ b/src/algorithms/contractions/ctmrg_contractions.jl @@ -371,35 +371,47 @@ end half_infinite_environment(x, C_1, C_2, E_1, E_2, E_3, E_4, ket_1::P, ket_2::P, bra_1::P=ket_1, bra_2::P=ket_2) where {P<:PEPSTensor} + half_infinite_environment(quadrant1::AbstractTensorMap{S,2,2}, quadrant2::AbstractTensorMap{S,2,2}) + half_infinite_environment(C_1, C_2, E_1, E_2, E_3, E_4, + partfunc_1::P, partfunc_2::P) where {P<:PartitionFunctionTensor} + half_infinite_environment(C_1, C_2, E_1, E_2, E_3, E_4, x, + partfunc_1::P, partfunc_2::P) where {P<:PartitionFunctionTensor} + half_infinite_environment(x, C_1, C_2, E_1, E_2, E_3, E_4, + partfunc_1::P, partfunc_2::P) where {P<:PartitionFunctionTensor} + Contract two quadrants (enlarged corners) to form a half-infinite environment. ``` |~~~~~~~~~| -- |~~~~~~~~~| |quadrant1| |quadrant2| - |~~~~~~~~~| == |~~~~~~~~~| - | || || | + |~~~~~~~~~| -- |~~~~~~~~~| + | | | | ``` The environment can also be contracted directly from all its constituent tensors. ``` - C_1 -- E_2 -- E_3 -- C_2 - | || || | - E_1 == ket_bra_1 == ket_bra_2 == E_4 - | || || | + C_1 -- E_2 -- E_3 -- C_2 + | | | | + E_1 -- A_1 -- A_2 -- E_4 + | | | | ``` Alternatively, contract the environment with a vector `x` acting on it ``` - C_1 -- E_2 -- E_3 -- C_2 - | || || | - E_1 == ket_bra_1 == ket_bra_2 == E_4 - | || || | - [~~~~~~x~~~~~~] + C_1 -- E_2 -- E_3 -- C_2 + | | | | + E_1 -- A_1 -- A_2 -- E_4 + | | | | + [~~~x~~~~] ``` or contract the adjoint environment with `x`, e.g. as needed for iterative solvers. + +Here `A` systematically denotes either: +- a local pair of 'ket' and 'bra' `PEPSTensor`s +- a `PartitionFunctionTensor`. """ function half_infinite_environment( quadrant1::AbstractTensorMap{S,3,3}, quadrant2::AbstractTensorMap{S,3,3} @@ -424,7 +436,6 @@ function half_infinite_environment( C_2[χ4; χ5] * E_4[χ5 D7 D8; χ_out] end - function half_infinite_environment( C_1, C_2, @@ -451,7 +462,6 @@ function half_infinite_environment( E_4[χ5 D7 D8; χ6] * x[χ6 D11 D12] end - function half_infinite_environment( x::AbstractTensor{S,3}, C_1, @@ -478,57 +488,15 @@ function half_infinite_environment( conj(C_2[χ5; χ6]) * conj(E_4[χ6 D9 D10; χ_in]) end - -""" - half_infinite_environment(quadrant1::AbstractTensorMap{S,2,2}, quadrant2::AbstractTensorMap{S,2,2}) - half_infinite_environment(C_1, C_2, E_1, E_2, E_3, E_4, - partfunc_1::P, partfunc_2::P) where {P<:PartitionFunctionTensor} - half_infinite_environment(C_1, C_2, E_1, E_2, E_3, E_4, x, - partfunc_1::P, partfunc_2::P) where {P<:PartitionFunctionTensor} - half_infinite_environment(x, C_1, C_2, E_1, E_2, E_3, E_4, - partfunc_1::P, partfunc_2::P) where {P<:PartitionFunctionTensor} - -Contract two quadrants (enlarged corners) to form a half-infinite environment. - -``` - |~~~~~~~~~| -- |~~~~~~~~~| - |quadrant1| |quadrant2| - |~~~~~~~~~| -- |~~~~~~~~~| - | | | | -``` - -The environment can also be contracted directly from all its constituent tensors. - -``` - C_1 -- E_2 -- E_3 -- C_2 - | | | | - E_1 -- ket_bra_1 -- ket_bra_2 -- E_4 - | | | | -``` - -Alternatively, contract the environment with a vector `x` acting on it - -``` - C_1 -- E_2 -- E_3 -- C_2 - | | | | - E_1 -- ket_bra_1 -- ket_bra_2 -- E_4 - | | | | - [~~~~~~x~~~~~~] -``` - -or contract the adjoint environment with `x`, e.g. as needed for iterative solvers. -""" - function half_infinite_environment( quadrant1::AbstractTensorMap{S,2,2}, quadrant2::AbstractTensorMap{S,2,2} ) where {S} return @autoopt @tensor env[χ_in D_in; χ_out D_out] := quadrant1[χ_in D_in; χ D1] * quadrant2[χ D1; χ_out D_out] end - function half_infinite_environment( C_1, C_2, E_1, E_2, E_3, E_4, partfunc_1::P, partfunc_2::P -) where {P<:PartitionFunctionTensor} +) where {P<:PFunctionTensor} return @autoopt @tensor env[χ_in D_in; χ_out D_out] := E_1[χ_in D1; χ1] * C_1[χ1; χ2] * @@ -539,10 +507,9 @@ function half_infinite_environment( C_2[χ4; χ5] * E_4[χ5 D7; χ_out] end - function half_infinite_environment( C_1, C_2, E_1, E_2, E_3, E_4, x::AbstractTensor{S,2}, partfunc_1::P, partfunc_2::P -) where {S,P<:PartitionFunctionTensor} +) where {S,P<:PFunctionTensor} return @autoopt @tensor env_x[χ_in D_in] := E_1[χ_in D1; χ1] * C_1[χ1; χ2] * @@ -554,10 +521,9 @@ function half_infinite_environment( E_4[χ5 D7; χ6] * x[χ6 D11] end - function half_infinite_environment( x::AbstractTensor{S,2}, C_1, C_2, E_1, E_2, E_3, E_4, partfunc_1::P, partfunc_2::P -) where {S,P<:PartitionFunctionTensor} +) where {S,P<:PFunctionTensor} return @autoopt @tensor env_x[χ_in D_in] := x[χ1 D1 D2] * conj(E_1[χ1 D3; χ2]) * @@ -586,18 +552,31 @@ end ket_1::P, ket_2::P, ket_3::P, ket_4::P, bra_1::P=ket_1, bra_2::P=ket_2, bra_3::P=ket_3, bra_4::P=ket_4) where {P<:PEPSTensor} + full_infinite_environment( + quadrant1::T, quadrant2::T, quadrant3::T, quadrant4::T + ) where {T<:AbstractTensorMap{<:ElementarySpace,2,2}} + function full_infinite_environment( + half1::T, half2::T + ) where {T<:AbstractTensorMap{<:ElementarySpace,2,2}} + full_infinite_environment(C_1, C_2, C_3, C_4, E_1, E_2, E_3, E_4, E_5, E_6, E_7, E_8, + partfunc_1::P, partfunc_2::P) where {P<:PartitionFunctionTensor} + full_infinite_environment(C_1, C_2, E_1, E_2, E_3, E_4, x, + partfunc_1::P, partfunc_2::P, partfunc_3::P, partfunc_4::P) where {P<:PartitionFunctionTensor} + full_infinite_environment(x, C_1, C_2, E_1, E_2, E_3, E_4, + partfunc_1::P, partfunc_2::P, partfunc_3::P, partfunc_4::P) where {P<:PartitionFunctionTensor} + Contract four quadrants (enlarged corners) to form a full-infinite environment. ``` |~~~~~~~~~| -- |~~~~~~~~~| |quadrant1| |quadrant2| |~~~~~~~~~| == |~~~~~~~~~| - | || || | - || | - | || || | + | | | | + | | + | | | | |~~~~~~~~~| -- |~~~~~~~~~| |quadrant4| |quadrant3| - |~~~~~~~~~| == |~~~~~~~~~| + |~~~~~~~~~| -- |~~~~~~~~~| ``` In the same manner two halfs can be used to contract the full-infinite environment. @@ -606,9 +585,9 @@ In the same manner two halfs can be used to contract the full-infinite environme |~~~~~~~~~~~~~~~~~~~~~~~~| | half1 | |~~~~~~~~~~~~~~~~~~~~~~~~| - | || || | - || | - | || || | + | | | | + | | + | | | | |~~~~~~~~~~~~~~~~~~~~~~~~| | half2 | |~~~~~~~~~~~~~~~~~~~~~~~~| @@ -617,35 +596,39 @@ In the same manner two halfs can be used to contract the full-infinite environme The environment can also be contracted directly from all its constituent tensors. ``` - C_1 -- E_2 -- E_3 -- C_2 - | || || | - E_1 == ket_bra_1 == ket_bra_2 == E_4 - | || || | - || | - | || || | - E_8 == ket_bra_4 == ket_bra_3 == E_5 - | || || | - C_4 -- E_7 -- E_6 -- C_3 + C_1 -- E_2 -- E_3 -- C_2 + | | | | + E_1 -- A_1 -- A_2 -- E_4 + | | | | + | | + | | | | + E_8 -- A_4 -- A_3 -- E_5 + | | | | + C_4 -- E_7 -- E_6 -- C_3 ``` Alternatively, contract the environment with a vector `x` acting on it ``` - C_1 -- E_2 -- E_3 -- C_2 - | || || | - E_1 == ket_bra_1 == ket_bra_2 == E_4 - | || || | - || | - || | - [~~~~x~~~~~] || | - | || || | - E_8 == ket_bra_4 == ket_bra_3 == E_5 - | || || | - C_4 -- E_7 -- E_6 -- C_3 + C_1 -- E_2 -- E_3 -- C_2 + | | | | + E_1 -- A_1 -- A_2 -- E_4 + | | | | + | | + | | + [~~~~x~~~] | | + | | | | + E_8 -- A_4 -- A_3 -- E_5 + | | | | + C_4 -- E_7 -- E_6 -- C_3 ``` or contract the adjoint environment with `x`, e.g. as needed for iterative solvers. + +Here `A` systematically denotes either: +- a local pair of 'ket' and 'bra' `PEPSTensor`s +- a `PartitionFunctionTensor`. """ function full_infinite_environment( quadrant1::T, quadrant2::T, quadrant3::T, quadrant4::T @@ -797,82 +780,6 @@ function full_infinite_environment( C_4[χ10; χ11] * E_8[χ11 D21 D22; χ_in] end - -""" - full_infinite_environment( - quadrant1::T, quadrant2::T, quadrant3::T, quadrant4::T - ) where {T<:AbstractTensorMap{<:ElementarySpace,2,2}} - function full_infinite_environment( - half1::T, half2::T - ) where {T<:AbstractTensorMap{<:ElementarySpace,2,2}} - full_infinite_environment(C_1, C_2, C_3, C_4, E_1, E_2, E_3, E_4, E_5, E_6, E_7, E_8, - partfunc_1::P, partfunc_2::P) where {P<:PartitionFunctionTensor} - full_infinite_environment(C_1, C_2, E_1, E_2, E_3, E_4, x, - partfunc_1::P, partfunc_2::P, partfunc_3::P, partfunc_4::P) where {P<:PartitionFunctionTensor} - full_infinite_environment(x, C_1, C_2, E_1, E_2, E_3, E_4, - partfunc_1::P, partfunc_2::P, partfunc_3::P, partfunc_4::P) where {P<:PartitionFunctionTensor} - -Contract four quadrants (enlarged corners) to form a full-infinite environment. - -``` - |~~~~~~~~~| -- |~~~~~~~~~| - |quadrant1| |quadrant2| - |~~~~~~~~~| -- |~~~~~~~~~| - | | | | - | | - | | | | - |~~~~~~~~~| -- |~~~~~~~~~| - |quadrant4| |quadrant3| - |~~~~~~~~~| -- |~~~~~~~~~| -``` - -In the same manner two halfs can be used to contract the full-infinite environment. - -``` - |~~~~~~~~~~~~~~~~~~~~~~~~| - | half1 | - |~~~~~~~~~~~~~~~~~~~~~~~~| - | | | | - | | - | | | | - |~~~~~~~~~~~~~~~~~~~~~~~~| - | half2 | - |~~~~~~~~~~~~~~~~~~~~~~~~| -``` - -The environment can also be contracted directly from all its constituent tensors. - -``` - C_1 -- E_2 -- E_3 -- C_2 - | | | | - E_1 -- partfunc_1 -- partfunc_2 -- E_4 - | | | | - | | - | | | | - E_8 -- partfunc_4 -- partfunc_3 -- E_5 - | | | | - C_4 -- E_7 -- E_6 -- C_3 -``` - -Alternatively, contract the environment with a vector `x` acting on it - -``` - C_1 -- E_2 -- E_3 -- C_2 - | | | | - E_1 -- partfunc_1 -- partfunc_2 -- E_4 - | | | | - | | - | | - [~~~~~x~~~~~~] | | - | | | | - E_8 -- partfunc_4 -- partfunc_3 -- E_5 - | | | | - C_4 -- E_7 -- E_6 -- C_3 - -``` - -or contract the adjoint environment with `x`, e.g. as needed for iterative solvers. -""" function full_infinite_environment( quadrant1::T, quadrant2::T, quadrant3::T, quadrant4::T ) where {T<:AbstractTensorMap{<:ElementarySpace,2,2}} @@ -1007,14 +914,15 @@ end """ renormalize_corner(quadrant::AbstractTensorMap{S,3,3}, P_left, P_right) + renormalize_corner(quadrant::AbstractTensorMap{S,2,2}, P_left, P_right) Apply projectors to each side of a quadrant. ``` |~~~~~~~~| -- |~~~~~~| |quadrant| |P_left| -- - |~~~~~~~~| == |~~~~~~| - | || + |~~~~~~~~| -- |~~~~~~| + | | [P_right] | ``` @@ -1023,22 +931,6 @@ function renormalize_corner(quadrant::AbstractTensorMap{S,3,3}, P_left, P_right) return @autoopt @tensor corner[χ_in; χ_out] := P_right[χ_in; χ1 D1 D2] * quadrant[χ1 D1 D2; χ2 D3 D4] * P_left[χ2 D3 D4; χ_out] end - -""" - renormalize_corner(quadrant::AbstractTensorMap{S,2,2}, P_left, P_right) - -Apply projectors to each side of a quadrant. - -``` - |~~~~~~~~| -- |~~~~~~| - |quadrant| |P_left| -- - |~~~~~~~~| -- |~~~~~~| - | | - [P_right] - | -``` -""" - function renormalize_corner(quadrant::AbstractTensorMap{S,2,2}, P_left, P_right) where {S} return @autoopt @tensor corner[χ_in; χ_out] := P_right[χ_in; χ1 D1] * quadrant[χ1 D1; χ2 D3] * P_left[χ2 D3; χ_out] @@ -1048,18 +940,24 @@ end renormalize_northwest_corner((row, col), enlarged_envs::CTMRGEnv, P_left, P_right) renormalize_northwest_corner(quadrant::AbstractTensorMap{S,3,3}, P_left, P_right) where {S} renormalize_northwest_corner(E_west, C_northwest, E_north, P_left, P_right, ket::PEPSTensor, bra::PEPSTensor=ket) + renormalize_northwest_corner(quadrant::AbstractTensorMap{S,2,2}, P_left, P_right) where {S} + renormalize_northwest_corner(E_west, C_northwest, E_north, P_left, P_right, partfunc::PartitionFunctionTensor) Apply `renormalize_corner` to the enlarged northwest corner. Alternatively, provide the constituent tensors and perform the complete contraction. ``` C_northwest -- E_north -- |~~~~~~| - | || |P_left| -- - E_west == ket-bra == |~~~~~~| - | || - [~~~~~P_right~~~~~] + | | |P_left| -- + E_west -- A -- |~~~~~~| + | | + [~~~~~P_right~~~~] | ``` + +Here `A` denotes either: +- a local pair of 'ket' and 'bra' `PEPSTensor`s +- a `PartitionFunctionTensor`. """ function renormalize_northwest_corner((row, col), enlarged_envs, P_left, P_right) return renormalize_northwest_corner( @@ -1068,13 +966,11 @@ function renormalize_northwest_corner((row, col), enlarged_envs, P_left, P_right P_right[WEST, _next(row, end), col], ) end - function renormalize_northwest_corner( quadrant::AbstractTensorMap{S,3,3}, P_left, P_right ) where {S} return renormalize_corner(quadrant, P_left, P_right) end - function renormalize_northwest_corner( E_west, C_northwest, E_north, P_left, P_right, ket::PEPSTensor, bra::PEPSTensor=ket ) @@ -1087,30 +983,11 @@ function renormalize_northwest_corner( conj(bra[d; D6 D8 D2 D4]) * P_left[χ4 D7 D8; χ_out] end - -""" - renormalize_northwest_corner(quadrant::AbstractTensorMap{S,2,2}, P_left, P_right) where {S} - renormalize_northwest_corner(E_west, C_northwest, E_north, P_left, P_right, partfunc::PartitionFunctionTensor) - -Apply `renormalize_corner` to the enlarged northwest corner. -Alternatively, provide the constituent tensors and perform the complete contraction. - -``` - C_northwest -- E_north -- |~~~~~~| - | | |P_left| -- - E_west -- ket-bra -- |~~~~~~| - | | - [~~~~~P_right~~~~~] - | -``` -""" - function renormalize_northwest_corner( quadrant::AbstractTensorMap{S,2,2}, P_left, P_right ) where {S} return renormalize_corner(quadrant, P_left, P_right) end - function renormalize_northwest_corner( E_west, C_northwest, E_north, P_left, P_right, partfunc::PartitionFunctionTensor ) @@ -1127,18 +1004,24 @@ end renormalize_northeast_corner((row, col), enlarged_envs::CTMRGEnv, P_left, P_right) renormalize_northwest_corner(quadrant::AbstractTensorMap{S,3,3}, P_left, P_right) where {S} renormalize_northeast_corner(E_north, C_northeast, E_east, P_left, P_right, ket::PEPSTensor, bra::PEPSTensor=ket) + renormalize_northwest_corner(quadrant::AbstractTensorMap{S,2,2}, P_left, P_right) where {S} + renormalize_northeast_corner(E_north, C_northeast, E_east, P_left, P_right, partfunc::PartitionFunctionTensor) Apply `renormalize_corner` to the enlarged northeast corner. Alternatively, provide the constituent tensors and perform the complete contraction. ``` - |~~~~~~~| -- E_north -- C_northeast - -- |P_right| || | - |~~~~~~~| == ket-bra == E_east - || | - [~~~~~~P_left~~~~~~] + |~~~~~~~| -- E_north -- C_northeast + -- |P_right| | | + |~~~~~~~| -- A -- E_east + | | + [~~~~~P_left~~~~~] | ``` + +Here `A` denotes either: +- a local pair of 'ket' and 'bra' `PEPSTensor`s +- a `PartitionFunctionTensor`. """ function renormalize_northeast_corner((row, col), enlarged_envs, P_left, P_right) return renormalize_northeast_corner( @@ -1166,30 +1049,11 @@ function renormalize_northeast_corner( conj(bra[d; D4 D6 D8 D2]) * P_left[χ4 D7 D8; χ_out] end - -""" - renormalize_northwest_corner(quadrant::AbstractTensorMap{S,2,2}, P_left, P_right) where {S} - renormalize_northeast_corner(E_north, C_northeast, E_east, P_left, P_right, partfunc::PartitionFunctionTensor) - -Apply `renormalize_corner` to the enlarged northeast corner. -Alternatively, provide the constituent tensors and perform the complete contraction. - -``` - |~~~~~~~| -- E_north -- C_northeast - -- |P_right| | | - |~~~~~~~| -- ket-bra -- E_east - | | - [~~~~~~P_left~~~~~~] - | -``` -""" - function renormalize_northeast_corner( quadrant::AbstractTensorMap{S,2,2}, P_left, P_right ) where {S} return renormalize_corner(quadrant, P_left, P_right) end - function renormalize_northeast_corner( E_north, C_northeast, E_east, P_left, P_right, partfunc::PartitionFunctionTensor ) @@ -1206,18 +1070,24 @@ end renormalize_southeast_corner((row, col), enlarged_envs::CTMRGEnv, P_left, P_right) renormalize_southeast_corner(quadrant::AbstractTensorMap{S,3,3}, P_left, P_right) where {S} renormalize_southeast_corner(E_east, C_southeast, E_south, P_left, P_right, ket::PEPSTensor, bra::PEPSTensor=ket) + renormalize_southeast_corner(quadrant::AbstractTensorMap{S,2,2}, P_left, P_right) where {S} + renormalize_southeast_corner(E_east, C_southeast, E_south, P_left, P_right, partfunc::PartitionFunctionTensor) Apply `renormalize_corner` to the enlarged southeast corner. Alternatively, provide the constituent tensors and perform the complete contraction. ``` | - [~~~~~P_right~~~~~] - || | - |~~~~~~| == ket-bra == E_east - -- |P_left| || | + [~~~~P_right~~~~] + | | + |~~~~~~| -- A -- E_east + -- |P_left| | | |~~~~~~| -- E_south -- C_southeast ``` + +Here `A` denotes either: +- a local pair of 'ket' and 'bra' `PEPSTensor`s +- a `PartitionFunctionTensor`. """ function renormalize_southeast_corner((row, col), enlarged_envs, P_left, P_right) return renormalize_southeast_corner( @@ -1226,13 +1096,11 @@ function renormalize_southeast_corner((row, col), enlarged_envs, P_left, P_right P_right[EAST, _prev(row, end), col], ) end - function renormalize_southeast_corner( quadrant::AbstractTensorMap{S,3,3}, P_left, P_right ) where {S} return renormalize_corner(quadrant, P_left, P_right) end - function renormalize_southeast_corner( E_east, C_southeast, E_south, P_left, P_right, ket::PEPSTensor, bra::PEPSTensor=ket ) @@ -1245,24 +1113,6 @@ function renormalize_southeast_corner( conj(bra[d; D2 D4 D6 D8]) * P_left[χ4 D7 D8; χ_out] end - -""" - renormalize_southeast_corner(quadrant::AbstractTensorMap{S,2,2}, P_left, P_right) where {S} - renormalize_southeast_corner(E_east, C_southeast, E_south, P_left, P_right, partfunc::PartitionFunctionTensor) - -Apply `renormalize_corner` to the enlarged southeast corner. -Alternatively, provide the constituent tensors and perform the complete contraction. - -``` - | - [~~~~~P_right~~~~~] - | | - |~~~~~~| -- ket-bra -- E_east - -- |P_left| | | - |~~~~~~| -- E_south -- C_southeast -``` -""" - function renormalize_southeast_corner( quadrant::AbstractTensorMap{S,2,2}, P_left, P_right ) where {S} @@ -1285,18 +1135,24 @@ end renormalize_southwest_corner((row, col), enlarged_envs::CTMRGEnv, P_left, P_right) renormalize_southwest_corner(quadrant::AbstractTensorMap{S,3,3}, P_left, P_right) where {S} renormalize_southwest_corner(E_south, C_southwest, E_west, P_left, P_right, ket::PEPSTensor, bra::PEPSTensor=ket) + renormalize_southwest_corner(quadrant::AbstractTensorMap{S,2,2}, P_left, P_right) where {S} + renormalize_southwest_corner(E_south, C_southwest, E_west, P_left, P_right, partfunc::PartitionFunctionTensor) Apply `renormalize_corner` to the enlarged southwest corner. Alternatively, provide the constituent tensors and perform the complete contraction. ``` | - [~~~~~P_right~~~~~] - | || - E_west == ket-bra == |~~~~~~| - | || |P_left| -- + [~~~~P_right~~~~~] + | | + E_west -- A -- |~~~~~~| + | | |P_left| -- C_southwest -- E_south -- |~~~~~~| ``` + +Here `A` denotes either: +- a pair of 'ket' and 'bra' `PEPSTensor`s +- a `PartitionFunctionTensor`. """ function renormalize_southwest_corner((row, col), enlarged_envs, P_left, P_right) return renormalize_corner( @@ -1305,13 +1161,11 @@ function renormalize_southwest_corner((row, col), enlarged_envs, P_left, P_right P_right[SOUTH, row, _next(col, end)], ) end - function renormalize_southwest_corner( quadrant::AbstractTensorMap{S,3,3}, P_left, P_right ) where {S} return renormalize_southwest_corner(quadrant, P_left, P_right) end - function renormalize_southwest_corner( E_south, C_southwest, E_west, P_left, P_right, ket::PEPSTensor, bra::PEPSTensor=ket ) @@ -1324,30 +1178,11 @@ function renormalize_southwest_corner( conj(bra[d; D8 D2 D4 D6]) * P_left[χ4 D7 D8; χ_out] end - -""" - renormalize_southwest_corner(quadrant::AbstractTensorMap{S,2,2}, P_left, P_right) where {S} - renormalize_southwest_corner(E_south, C_southwest, E_west, P_left, P_right, partfunc::PartitionFunctionTensor) - -Apply `renormalize_corner` to the enlarged southwest corner. -Alternatively, provide the constituent tensors and perform the complete contraction. - -``` - | - [~~~~~P_right~~~~~] - | | - E_west -- ket-bra -- |~~~~~~| - | | |P_left| -- - C_southwest -- E_south -- |~~~~~~| -``` -""" - function renormalize_southwest_corner( quadrant::AbstractTensorMap{S,2,2}, P_left, P_right ) where {S} return renormalize_southwest_corner(quadrant, P_left, P_right) end - function renormalize_southwest_corner( E_south, C_southwest, E_west, P_left, P_right, partfunc::PartitionFunctionTensor ) @@ -1364,14 +1199,6 @@ end renormalize_bottom_corner((r, c), envs, projectors) Apply bottom projector to southwest corner and south edge. -For the case of a PEPSTensor: -``` - | - [P_bottom] - | || - C -- E -- in -``` -For the case of a PartitionFunctionTensor: ``` | [P_bottom] @@ -1402,14 +1229,6 @@ end renormalize_top_corner((row, col), envs::CTMRGEnv, projectors) Apply top projector to northwest corner and north edge. -For the case of a PEPSTensor: -``` - C -- E -- - | || - [~P_top~] - | -``` -For the case of a PartitionFunctionTensor: ``` C -- E -- | | @@ -1435,17 +1254,24 @@ end # edges """ - renormalize_north_edge((row, col), envs, P_left, P_right, ket, bra) - renormalize_north_edge(E_north, P_left, P_right, ket, bra) + renormalize_north_edge((row, col), envs, P_left, P_right, ket::InfinitePEPS, bra::InfinitePEPS=ket) + renormalize_north_edge(E_north, P_left, P_right, ket::PEPSTensor, bra::PEPSTensor=ket) + renormalize_north_edge((row, col), envs, P_left, P_right, partfunc::InfinitePartitionFunction) + renormalize_north_edge(E_north, P_left, P_right, partfunc::PartitionFunctionTensor) -Absorb a bra-ket pair into the north edge using the given projectors and environment tensors. +Absorb a local effective tensor `A` into the north edge using the given projectors and +environment tensors. ``` |~~~~~~| -- E_north -- |~~~~~~~| - -- |P_left| || |P_right| -- - |~~~~~~| == ket-bra == |~~~~~~~| - || + -- |P_left| | |P_right| -- + |~~~~~~| -- A -- |~~~~~~~| + | ``` + +Here `A` denotes either: +- a pair of 'ket' and 'bra' `PEPSTensor`s +- a `PartitionFunctionTensor`. """ function renormalize_north_edge( (row, col), envs::CTMRGEnv, P_left, P_right, ket::InfinitePEPS, bra::InfinitePEPS=ket @@ -1458,7 +1284,6 @@ function renormalize_north_edge( bra[row, col], ) end - function renormalize_north_edge( E_north::CTMRG_PEPS_EdgeTensor, P_left, P_right, ket::PEPSTensor, bra::PEPSTensor=ket ) @@ -1469,21 +1294,6 @@ function renormalize_north_edge( P_left[χ2 D3 D4; χ_E] * P_right[χ_W; χ1 D5 D6] end - -""" - renormalize_north_edge((row, col), envs, P_left, P_right, partfunc) - renormalize_north_edge(E_north, P_left, P_right, partfunc) - -Absorb a bra-ket pair into the north edge using the given projectors and environment tensors. - -``` - |~~~~~~| -- E_north -- |~~~~~~~| - -- |P_left| | |P_right| -- - |~~~~~~| -- ket-bra -- |~~~~~~~| - | -``` -""" - function renormalize_north_edge( (row, col), envs::CTMRGEnv, P_left, P_right, partfunc::InfinitePartitionFunction ) @@ -1494,7 +1304,6 @@ function renormalize_north_edge( partfunc[row, col], ) end - function renormalize_north_edge( E_north::CTMRG_PF_EdgeTensor, P_left, P_right, partfunc::PartitionFunctionTensor ) @@ -1506,20 +1315,27 @@ function renormalize_north_edge( end """ - renormalize_east_edge((row, col), envs, P_top, P_bottom, ket, bra) - renormalize_east_edge(E_east, P_top, P_bottom, ket, bra) + renormalize_east_edge((row, col), envs, P_top, P_bottom, ket::InfinitePEPS, bra::InfinitePEPS=ket) + renormalize_east_edge(E_east, P_top, P_bottom, ket::PEPSTensor, bra::PEPSTensor=ket) + renormalize_east_edge((row, col), envs, P_top, P_bottom, partfunc::InfinitePartitionFunction) + renormalize_east_edge(E_east, P_top, P_bottom, partfunc::PartitionFunctionTensor) -Absorb a bra-ket pair into the east edge using the given projectors and environment tensors. +Absorb a blocal effective tensor into the east edge using the given projectors and +environment tensors. ``` - | - [~~P_bottom~~] - | || - E_east == ket-bra == - | || - [~~~~P_top~~~] - | + | + [~P_bottom~] + | | + E_east -- A -- + | | + [~~P_top~~~] + | ``` + +Here `A` denotes either: +- a pair of 'ket' and 'bra' `PEPSTensor`s +- a `PartitionFunctionTensor`. """ function renormalize_east_edge( (row, col), envs::CTMRGEnv, P_bottom, P_top, ket::InfinitePEPS, bra::InfinitePEPS=ket @@ -1532,7 +1348,6 @@ function renormalize_east_edge( bra[row, col], ) end - function renormalize_east_edge( E_east::CTMRG_PEPS_EdgeTensor, P_bottom, P_top, ket::PEPSTensor, bra::PEPSTensor=ket ) @@ -1543,24 +1358,6 @@ function renormalize_east_edge( P_bottom[χ2 D3 D4; χ_S] * P_top[χ_N; χ1 D5 D6] end - -""" - renormalize_east_edge((row, col), envs, P_top, P_bottom, partfunc) - renormalize_east_edge(E_east, P_top, P_bottom, partfunc) - -Absorb a bra-ket pair into the east edge using the given projectors and environment tensors. - -``` - | - [~~P_bottom~~] - | | - E_east -- ket-bra -- - | | - [~~~~P_top~~~] - | -``` -""" - function renormalize_east_edge( (row, col), envs::CTMRGEnv, P_bottom, P_top, partfunc::InfinitePartitionFunction ) @@ -1571,7 +1368,6 @@ function renormalize_east_edge( partfunc[row, col], ) end - function renormalize_east_edge( E_east::CTMRG_PF_EdgeTensor, P_bottom, P_top, partfunc::PartitionFunctionTensor ) @@ -1583,18 +1379,25 @@ function renormalize_east_edge( end """ - renormalize_south_edge((row, col), envs, P_left, P_right, ket, bra) - renormalize_south_edge(E_south, P_left, P_right, ket, bra) + renormalize_south_edge((row, col), envs, P_left, P_right, ket::InfinitePEPS, bra::InfinitePEPS=ket) + renormalize_south_edge(E_south, P_left, P_right, ket::PEPSTensor, bra::PEPSTensor=ket) + renormalize_south_edge((row, col), envs, P_left, P_right, partfunc::InfinitePartitionFunction) + renormalize_south_edge(E_south, P_left, P_right, partfunc::PartitionFunctionTensor) -Absorb a bra-ket pair into the south edge using the given projectors and environment tensors. +Absorb a local effective tensor into the south edge using the given projectors and +environment tensors. ``` - || - |~~~~~~~| == ket-bra == |~~~~~~| - -- |P_right| || |P_left| -- + | + |~~~~~~~| -- A -- |~~~~~~| + -- |P_right| | |P_left| -- |~~~~~~~| -- E_south -- |~~~~~~| - || + | ``` + +Here `A` denotes either: +- a pair of 'ket' and 'bra' `PEPSTensor`s +- a `PartitionFunctionTensor`. """ function renormalize_south_edge( (row, col), envs::CTMRGEnv, P_left, P_right, ket::InfinitePEPS, bra::InfinitePEPS=ket @@ -1607,7 +1410,6 @@ function renormalize_south_edge( bra[row, col], ) end - function renormalize_south_edge( E_south::CTMRG_PEPS_EdgeTensor, P_left, P_right, ket::PEPSTensor, bra::PEPSTensor=ket ) @@ -1618,21 +1420,6 @@ function renormalize_south_edge( P_left[χ2 D3 D4; χ_W] * P_right[χ_E; χ1 D5 D6] end - -""" - renormalize_south_edge((row, col), envs, P_left, P_right, partfunc) - renormalize_south_edge(E_south, P_left, P_right, partfunc) - -Absorb a bra-ket pair into the south edge using the given projectors and environment tensors. - -``` - | - |~~~~~~~| -- ket-bra -- |~~~~~~| - -- |P_right| | |P_left| -- - |~~~~~~~| -- E_south -- |~~~~~~| -``` | -""" - function renormalize_south_edge( (row, col), envs::CTMRGEnv, P_left, P_right, partfunc::InfinitePartitionFunction ) @@ -1643,7 +1430,6 @@ function renormalize_south_edge( partfunc[row, col], ) end - function renormalize_south_edge( E_south::CTMRG_PF_EdgeTensor, P_left, P_right, partfunc::PartitionFunctionTensor ) @@ -1655,20 +1441,27 @@ function renormalize_south_edge( end """ - renormalize_west_edge((row, col), envs, P_top, P_bottom, ket, bra) - renormalize_west_edge(E_west, P_top, P_bottom, ket, bra) + renormalize_west_edge((row, col), envs, P_top, P_bottom, ket::InfinitePEPS, bra::InfinitePEPS=ket) + renormalize_west_edge(E_west, P_top, P_bottom, ket::PEPSTensor, bra::PEPSTensor=ket) + renormalize_west_edge((row, col), envs, P_top, P_bottom, partfunc::InfinitePartitionFunction) + renormalize_west_edge(E_west, P_top, P_bottom, partfunc::PartitionFunctionTensor) -Absorb a bra-ket pair into the west edge using the given projectors and environment tensors. +Absorb a local effective tensor into the west edge using the given projectors and +environment tensors. ``` - | - [~~P_bottom~~] - | || - E_west == ket-bra == - | || - [~~~~P_top~~~] - | + | + [~P_bottom~] + | | + -- A -- E_west + | | + [~~P_top~~~] + | ``` + +Here `A` denotes either: +- a pair of 'ket' and 'bra' `PEPSTensor`s +- a `PartitionFunctionTensor`. """ function renormalize_west_edge( # For simultaneous CTMRG scheme (row, col), @@ -1711,24 +1504,6 @@ function renormalize_west_edge( P_bottom[χ2 D3 D4; χ_N] * P_top[χ_S; χ1 D5 D6] end - -""" - renormalize_west_edge((row, col), envs, P_top, P_bottom, partfunc) - renormalize_west_edge(E_west, P_top, P_bottom, partfunc) - -Absorb a bra-ket pair into the west edge using the given projectors and environment tensors. - -``` - | - [~~P_bottom~~] - | | - E_west -- ket-bra -- - | | - [~~~~P_top~~~] - | -``` -""" - function renormalize_west_edge( # For simultaneous CTMRG scheme (row, col), envs::CTMRGEnv, From d1f84d9d752e57fe82407d7f2df1881d6369247a Mon Sep 17 00:00:00 2001 From: leburgel Date: Tue, 7 Jan 2025 12:39:26 +0100 Subject: [PATCH 20/47] Fix typos, switch to shorter aliases internally --- .../contractions/ctmrg_contractions.jl | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/algorithms/contractions/ctmrg_contractions.jl b/src/algorithms/contractions/ctmrg_contractions.jl index a38aa743..785e546b 100644 --- a/src/algorithms/contractions/ctmrg_contractions.jl +++ b/src/algorithms/contractions/ctmrg_contractions.jl @@ -125,7 +125,7 @@ function enlarge_northeast_corner( E_north::CTMRG_PF_EdgeTensor, C_northeast::CTMRGCornerTensor, E_east::CTMRG_PF_EdgeTensor, - partfunc::PartitionFunctionTensor, + partfunc::PFTensor, ) return @autoopt @tensor corner[χ_W D_W; χ_S D_S] := E_north[χ_W D1; χ1] * @@ -180,7 +180,7 @@ function enlarge_southeast_corner( conj(bra[d; D_Nbelow D2 D4 D_Wbelow]) end function enlarge_southeast_corner( - (row, col), envs::CTMRGEnv, partfunc::InfinitePartitionFunction + (row, col), envs::CTMRGEnv, partfunc::InfinitePF ) E_east = envs.edges[EAST, row, _next(col, end)] C_southeast = envs.corners[SOUTHEAST, _next(row, end), _next(col, end)] @@ -191,7 +191,7 @@ function enlarge_southeast_corner( E_east::CTMRG_PF_EdgeTensor, C_southeast::CTMRGCornerTensor, E_south::CTMRG_PF_EdgeTensor, - partfunc::PartitionFunctionTensor, + partfunc::PFTensor, ) return @autoopt @tensor corner[χ_N D_N; χ_W D_W] := E_east[χ_N D1; χ1] * @@ -246,7 +246,7 @@ function enlarge_southwest_corner( conj(bra[d; D_Nbelow D_Ebelow D2 D4]) end function enlarge_southwest_corner( - (row, col), envs::CTMRGEnv, partfunc::InfinitePartitionFunction + (row, col), envs::CTMRGEnv, partfunc::InfinitePF ) E_south = envs.edges[SOUTH, _next(row, end), col] C_southwest = envs.corners[SOUTHWEST, _next(row, end), _prev(col, end)] @@ -257,7 +257,7 @@ function enlarge_southwest_corner( E_south::CTMRG_PF_EdgeTensor, C_southwest::CTMRGCornerTensor, E_west::CTMRG_PF_EdgeTensor, - partfunc::PartitionFunctionTensor, + partfunc::PFTensor, ) return @autoopt @tensor corner[χ_E D_E; χ_N D_N] := E_south[χ_E D1; χ1] * @@ -496,7 +496,7 @@ function half_infinite_environment( end function half_infinite_environment( C_1, C_2, E_1, E_2, E_3, E_4, partfunc_1::P, partfunc_2::P -) where {P<:PFunctionTensor} +) where {P<:PFTensor} return @autoopt @tensor env[χ_in D_in; χ_out D_out] := E_1[χ_in D1; χ1] * C_1[χ1; χ2] * @@ -509,7 +509,7 @@ function half_infinite_environment( end function half_infinite_environment( C_1, C_2, E_1, E_2, E_3, E_4, x::AbstractTensor{S,2}, partfunc_1::P, partfunc_2::P -) where {S,P<:PFunctionTensor} +) where {S,P<:PFTensor} return @autoopt @tensor env_x[χ_in D_in] := E_1[χ_in D1; χ1] * C_1[χ1; χ2] * @@ -523,7 +523,7 @@ function half_infinite_environment( end function half_infinite_environment( x::AbstractTensor{S,2}, C_1, C_2, E_1, E_2, E_3, E_4, partfunc_1::P, partfunc_2::P -) where {S,P<:PFunctionTensor} +) where {S,P<:PFTensor} return @autoopt @tensor env_x[χ_in D_in] := x[χ1 D1 D2] * conj(E_1[χ1 D3; χ2]) * @@ -811,7 +811,7 @@ function full_infinite_environment( partfunc_2::P, partfunc_3::P, partfunc_4::P, -) where {P<:PartitionFunctionTensor} +) where {P<:PFTensor} return @autoopt @tensor env[χ_in D_in; χ_out D_out] := E_1[χ_in D1; χ1] * C_1[χ1; χ2] * @@ -848,7 +848,7 @@ function full_infinite_environment( partfunc_2::P, partfunc_3::P, partfunc_4::P, -) where {S,P<:PartitionFunctionTensor} +) where {S,P<:PFTensor} return @autoopt @tensor env_x[χ_in D_in] := E_1[χ_in D1; χ1] * C_1[χ1; χ2] * @@ -989,7 +989,7 @@ function renormalize_northwest_corner( return renormalize_corner(quadrant, P_left, P_right) end function renormalize_northwest_corner( - E_west, C_northwest, E_north, P_left, P_right, partfunc::PartitionFunctionTensor + E_west, C_northwest, E_north, P_left, P_right, partfunc::PFTensor ) return @autoopt @tensor corner[χ_in; χ_out] := P_right[χ_in; χ1 D1] * @@ -1055,7 +1055,7 @@ function renormalize_northeast_corner( return renormalize_corner(quadrant, P_left, P_right) end function renormalize_northeast_corner( - E_north, C_northeast, E_east, P_left, P_right, partfunc::PartitionFunctionTensor + E_north, C_northeast, E_east, P_left, P_right, partfunc::PFTensor ) return @autoopt @tensor corner[χ_in; χ_out] := P_right[χ_in; χ1 D1] * @@ -1120,7 +1120,7 @@ function renormalize_southeast_corner( end function renormalize_southeast_corner( - E_east, C_southeast, E_south, P_left, P_right, partfunc::PartitionFunctionTensor + E_east, C_southeast, E_south, P_left, P_right, partfunc::PFTensor ) return @autoopt @tensor corner[χ_in; χ_out] := P_right[χ_in; χ1 D1] * @@ -1184,7 +1184,7 @@ function renormalize_southwest_corner( return renormalize_southwest_corner(quadrant, P_left, P_right) end function renormalize_southwest_corner( - E_south, C_southwest, E_west, P_left, P_right, partfunc::PartitionFunctionTensor + E_south, C_southwest, E_west, P_left, P_right, partfunc::PFTensor ) return @autoopt @tensor corner[χ_in; χ_out] := P_right[χ_in; χ1 D1] * @@ -1295,7 +1295,7 @@ function renormalize_north_edge( P_right[χ_W; χ1 D5 D6] end function renormalize_north_edge( - (row, col), envs::CTMRGEnv, P_left, P_right, partfunc::InfinitePartitionFunction + (row, col), envs::CTMRGEnv, P_left, P_right, partfunc::InfinitePF ) return renormalize_north_edge( envs.edges[NORTH, _prev(row, end), col], @@ -1305,7 +1305,7 @@ function renormalize_north_edge( ) end function renormalize_north_edge( - E_north::CTMRG_PF_EdgeTensor, P_left, P_right, partfunc::PartitionFunctionTensor + E_north::CTMRG_PF_EdgeTensor, P_left, P_right, partfunc::PFTensor ) return @autoopt @tensor edge[χ_W D_S; χ_E] := E_north[χ1 D1; χ2] * @@ -1359,7 +1359,7 @@ function renormalize_east_edge( P_top[χ_N; χ1 D5 D6] end function renormalize_east_edge( - (row, col), envs::CTMRGEnv, P_bottom, P_top, partfunc::InfinitePartitionFunction + (row, col), envs::CTMRGEnv, P_bottom, P_top, partfunc::InfinitePF ) return renormalize_east_edge( envs.edges[EAST, row, _next(col, end)], @@ -1369,7 +1369,7 @@ function renormalize_east_edge( ) end function renormalize_east_edge( - E_east::CTMRG_PF_EdgeTensor, P_bottom, P_top, partfunc::PartitionFunctionTensor + E_east::CTMRG_PF_EdgeTensor, P_bottom, P_top, partfunc::PFTensor ) return @autoopt @tensor edge[χ_N D_W; χ_S] := E_east[χ1 D1; χ2] * @@ -1421,7 +1421,7 @@ function renormalize_south_edge( P_right[χ_E; χ1 D5 D6] end function renormalize_south_edge( - (row, col), envs::CTMRGEnv, P_left, P_right, partfunc::InfinitePartitionFunction + (row, col), envs::CTMRGEnv, P_left, P_right, partfunc::InfinitePF ) return renormalize_south_edge( envs.edges[SOUTH, _next(row, end), col], @@ -1431,7 +1431,7 @@ function renormalize_south_edge( ) end function renormalize_south_edge( - E_south::CTMRG_PF_EdgeTensor, P_left, P_right, partfunc::PartitionFunctionTensor + E_south::CTMRG_PF_EdgeTensor, P_left, P_right, partfunc::PFTensor ) return @autoopt @tensor edge[χ_E D_N; χ_W] := E_south[χ1 D1; χ2] * @@ -1509,7 +1509,7 @@ function renormalize_west_edge( # For simultaneous CTMRG scheme envs::CTMRGEnv, P_bottom::Array{Pb,3}, P_top::Array{Pt,3}, - partfunc::InfinitePartitionFunction, + partfunc::InfinitePF, ) where {Pt,Pb} return renormalize_west_edge( envs.edges[WEST, row, _prev(col, end)], @@ -1522,7 +1522,7 @@ function renormalize_west_edge( # For sequential CTMRG scheme (row, col), envs::CTMRGEnv, projectors, - partfunc::InfinitePartitionFunction, + partfunc::InfinitePF, ) return renormalize_west_edge( envs.edges[WEST, row, _prev(col, end)], @@ -1532,7 +1532,7 @@ function renormalize_west_edge( # For sequential CTMRG scheme ) end function renormalize_west_edge( - E_west::CTMRG_PF_EdgeTensor, P_bottom, P_top, partfunc::PartitionFunctionTensor + E_west::CTMRG_PF_EdgeTensor, P_bottom, P_top, partfunc::PFTensor ) return @autoopt @tensor edge[χ_S D_E; χ_N] := E_west[χ1 D1; χ2] * From 063105aa8d34f646f1434085de20946ff882befa Mon Sep 17 00:00:00 2001 From: leburgel Date: Tue, 7 Jan 2025 12:39:55 +0100 Subject: [PATCH 21/47] Format --- src/algorithms/contractions/ctmrg_contractions.jl | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/algorithms/contractions/ctmrg_contractions.jl b/src/algorithms/contractions/ctmrg_contractions.jl index 785e546b..fa605bc0 100644 --- a/src/algorithms/contractions/ctmrg_contractions.jl +++ b/src/algorithms/contractions/ctmrg_contractions.jl @@ -179,9 +179,7 @@ function enlarge_southeast_corner( ket[d; D_Nabove D1 D3 D_Wabove] * conj(bra[d; D_Nbelow D2 D4 D_Wbelow]) end -function enlarge_southeast_corner( - (row, col), envs::CTMRGEnv, partfunc::InfinitePF -) +function enlarge_southeast_corner((row, col), envs::CTMRGEnv, partfunc::InfinitePF) E_east = envs.edges[EAST, row, _next(col, end)] C_southeast = envs.corners[SOUTHEAST, _next(row, end), _next(col, end)] E_south = envs.edges[SOUTH, _next(row, end), col] @@ -245,9 +243,7 @@ function enlarge_southwest_corner( ket[d; D_Nabove D_Eabove D1 D3] * conj(bra[d; D_Nbelow D_Ebelow D2 D4]) end -function enlarge_southwest_corner( - (row, col), envs::CTMRGEnv, partfunc::InfinitePF -) +function enlarge_southwest_corner((row, col), envs::CTMRGEnv, partfunc::InfinitePF) E_south = envs.edges[SOUTH, _next(row, end), col] C_southwest = envs.corners[SOUTHWEST, _next(row, end), _prev(col, end)] E_west = envs.edges[WEST, row, _prev(col, end)] From adf715860411452fe6f0d6bb7130a16bb8a7a9bc Mon Sep 17 00:00:00 2001 From: leburgel Date: Tue, 7 Jan 2025 13:03:02 +0100 Subject: [PATCH 22/47] Remove overwritten method, use random seed in test --- src/algorithms/ctmrg/sparse_environments.jl | 16 ---------------- test/ctmrg/partition_function.jl | 3 +++ 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/src/algorithms/ctmrg/sparse_environments.jl b/src/algorithms/ctmrg/sparse_environments.jl index a6baed2d..e1210e7a 100644 --- a/src/algorithms/ctmrg/sparse_environments.jl +++ b/src/algorithms/ctmrg/sparse_environments.jl @@ -305,22 +305,6 @@ function (env::HalfInfiniteEnv)(x, ::Val{true}) # Adjoint linear map: env()' * ) end -# Wrapper around half_infinite_environment contraction using EnlargedCorners (used in ctmrg_projectors) -function half_infinite_environment(ec_1::EnlargedCorner, ec_2::EnlargedCorner) - return HalfInfiniteEnv( - ec_1.C, - ec_2.C, - ec_1.E_1, - ec_1.E_2, - ec_2.E_1, - ec_2.E_2, - ec_1.ket, - ec_2.ket, - ec_1.bra, - ec_2.bra, - ) -end - function (env::HalfInfinitePartitionFunctionEnv)(x, ::Val{false}) # Linear map: env() * x return halfinfinite_partitionfunction_environment( env.C_1, diff --git a/test/ctmrg/partition_function.jl b/test/ctmrg/partition_function.jl index 52fe30ea..c909e420 100644 --- a/test/ctmrg/partition_function.jl +++ b/test/ctmrg/partition_function.jl @@ -1,4 +1,5 @@ using Test +using Random using PEPSKit using TensorKit using LinearAlgebra @@ -112,6 +113,8 @@ beta = 0.5 O, M, E = classical_ising(; beta) Z = InfinitePartitionFunction(O) +Random.seed!(81812781143) + # contract χenv = ℂ^12 From 2014a173c786077afcd4031fb1d68b4deb49f215 Mon Sep 17 00:00:00 2001 From: Lander Burgelman <39218680+leburgel@users.noreply.github.com> Date: Tue, 7 Jan 2025 15:44:56 +0100 Subject: [PATCH 23/47] Update src/states/infinitepartitionfunction.jl Co-authored-by: Lukas Devos --- src/states/infinitepartitionfunction.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/states/infinitepartitionfunction.jl b/src/states/infinitepartitionfunction.jl index 8110b974..4a9a0aae 100644 --- a/src/states/infinitepartitionfunction.jl +++ b/src/states/infinitepartitionfunction.jl @@ -177,7 +177,7 @@ end function LinearAlgebra.axpy!( α::Number, ψ₁::InfinitePartitionFunction, ψ₂::InfinitePartitionFunction ) - ψ₂.A .+= α * ψ₁.A + axpy!.(α, ψ₁.A, ψ₂.A) return ψ₂ end From 7b66878b18cf7636b730b08b705595e887a4c6ba Mon Sep 17 00:00:00 2001 From: Lander Burgelman <39218680+leburgel@users.noreply.github.com> Date: Tue, 7 Jan 2025 15:45:19 +0100 Subject: [PATCH 24/47] Update src/states/infinitepartitionfunction.jl Co-authored-by: Lukas Devos --- src/states/infinitepartitionfunction.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/states/infinitepartitionfunction.jl b/src/states/infinitepartitionfunction.jl index 4a9a0aae..07a25b93 100644 --- a/src/states/infinitepartitionfunction.jl +++ b/src/states/infinitepartitionfunction.jl @@ -169,7 +169,7 @@ end # Used in _scale during OptimKit.optimize function LinearAlgebra.rmul!(ψ::InfinitePartitionFunction, α::Number) - rmul!(ψ.A, α) + rmul!.(ψ.A, α) return ψ end From 2bf9dac97ae371354eb00105227f45aa5a4b8a35 Mon Sep 17 00:00:00 2001 From: leburgel Date: Wed, 8 Jan 2025 12:34:44 +0100 Subject: [PATCH 25/47] Remove stray `build_projectors` --- src/algorithms/ctmrg/ctmrg.jl | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/src/algorithms/ctmrg/ctmrg.jl b/src/algorithms/ctmrg/ctmrg.jl index 8e47d14f..e35abeaf 100644 --- a/src/algorithms/ctmrg/ctmrg.jl +++ b/src/algorithms/ctmrg/ctmrg.jl @@ -92,31 +92,6 @@ function _singular_value_distance((S₁, S₂)) end end -function build_projectors( - U::AbstractTensorMap{E,2,1}, - S::AbstractTensorMap{E,1,1}, - V::AbstractTensorMap{E,1,2}, - Q::AbstractTensorMap{E,2,2}, - Q_next::AbstractTensorMap{E,2,2}, -) where {E<:ElementarySpace} - isqS = sdiag_pow(S, -0.5) - P_left = Q_next * V' * isqS - P_right = isqS * U' * Q - return P_left, P_right -end -function build_projectors( - U::AbstractTensorMap{E,2,1}, - S::AbstractTensorMap{E,1,1}, - V::AbstractTensorMap{E,1,2}, - Q::EnlargedPartitionFunctionCorner, - Q_next::EnlargedPartitionFunctionCorner, -) where {E<:ElementarySpace} - isqS = sdiag_pow(S, -0.5) - P_left = left_projector(Q.E_1, Q.C, Q.E_2, V, isqS, Q.partfunc) - P_right = right_projector(Q_next.E_1, Q_next.C, Q_next.E_2, U, isqS, Q_next.partfunc) - return P_left, P_right -end - """ calc_convergence(envs, CS_old, TS_old) calc_convergence(envs_new::CTMRGEnv, envs_old::CTMRGEnv) From 484f3baa26b70286ad4fbfe95652eab86323bb59 Mon Sep 17 00:00:00 2001 From: leburgel Date: Wed, 8 Jan 2025 12:47:26 +0100 Subject: [PATCH 26/47] Add `InfiniteSquareNetwork` --- src/algorithms/ctmrg/ctmrg.jl | 1 + src/algorithms/ctmrg/sequential.jl | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/algorithms/ctmrg/ctmrg.jl b/src/algorithms/ctmrg/ctmrg.jl index e35abeaf..a859681c 100644 --- a/src/algorithms/ctmrg/ctmrg.jl +++ b/src/algorithms/ctmrg/ctmrg.jl @@ -1,3 +1,4 @@ +const InfiniteSquareNetwork = Union{InfinitePEPS,InfinitePartitionFunction} """ CTMRGAlgorithm diff --git a/src/algorithms/ctmrg/sequential.jl b/src/algorithms/ctmrg/sequential.jl index ec28061b..12414b15 100644 --- a/src/algorithms/ctmrg/sequential.jl +++ b/src/algorithms/ctmrg/sequential.jl @@ -54,7 +54,7 @@ for a specific `coordinate` (where `dir=WEST` is already implied in the `:sequen """ function sequential_projectors( col::Int, - state::Union{InfinitePEPS,InfinitePartitionFunction}, + state::InfiniteSquareNetwork, envs::CTMRGEnv, alg::ProjectorAlgorithm, ) @@ -74,7 +74,7 @@ function sequential_projectors( end function sequential_projectors( coordinate::NTuple{3,Int}, - state::Union{InfinitePEPS,InfinitePartitionFunction}, + state::Union{InfiniteSquareNetwork}, envs::CTMRGEnv, alg::HalfInfiniteProjector, ) @@ -86,7 +86,7 @@ function sequential_projectors( end function sequential_projectors( coordinate::NTuple{3,Int}, - state::Union{InfinitePEPS,InfinitePartitionFunction}, + state::InfiniteSquareNetwork, envs::CTMRGEnv, alg::FullInfiniteProjector, ) From 52d8d28586b03feb2b49bef44b430b8a828a5cbd Mon Sep 17 00:00:00 2001 From: leburgel Date: Wed, 8 Jan 2025 14:22:10 +0100 Subject: [PATCH 27/47] Fix typos, change temperature in test --- src/algorithms/ctmrg/sequential.jl | 5 +---- src/networks/abstract_networks.jl | 2 +- test/ctmrg/partition_function.jl | 2 +- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/algorithms/ctmrg/sequential.jl b/src/algorithms/ctmrg/sequential.jl index 12414b15..e0c954e2 100644 --- a/src/algorithms/ctmrg/sequential.jl +++ b/src/algorithms/ctmrg/sequential.jl @@ -53,10 +53,7 @@ Compute CTMRG projectors in the `:sequential` scheme either for an entire column for a specific `coordinate` (where `dir=WEST` is already implied in the `:sequential` scheme). """ function sequential_projectors( - col::Int, - state::InfiniteSquareNetwork, - envs::CTMRGEnv, - alg::ProjectorAlgorithm, + col::Int, state::InfiniteSquareNetwork, envs::CTMRGEnv, alg::ProjectorAlgorithm ) # SVD half-infinite environment column-wise ϵ = Zygote.Buffer(zeros(real(scalartype(envs)), size(envs, 2))) diff --git a/src/networks/abstract_networks.jl b/src/networks/abstract_networks.jl index f85cc761..1d92a292 100644 --- a/src/networks/abstract_networks.jl +++ b/src/networks/abstract_networks.jl @@ -1,7 +1,7 @@ """ abstract type AbstractPartitionFunction end -Abstract supertype for a 2D partitionFunction. +Abstract supertype for a 2D partition function. """ abstract type AbstractPartitionFunction end diff --git a/test/ctmrg/partition_function.jl b/test/ctmrg/partition_function.jl index c909e420..2986d4be 100644 --- a/test/ctmrg/partition_function.jl +++ b/test/ctmrg/partition_function.jl @@ -109,7 +109,7 @@ end # initialize -beta = 0.5 +beta = 0.6 O, M, E = classical_ising(; beta) Z = InfinitePartitionFunction(O) From 9f383803624daebd2360f01d9b141eba8d24b301 Mon Sep 17 00:00:00 2001 From: leburgel Date: Wed, 8 Jan 2025 14:23:09 +0100 Subject: [PATCH 28/47] Fix more in-place operations --- src/environments/ctmrg_environments.jl | 8 ++++---- src/states/infinitepeps.jl | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/environments/ctmrg_environments.jl b/src/environments/ctmrg_environments.jl index 644b9f59..4b73e98c 100644 --- a/src/environments/ctmrg_environments.jl +++ b/src/environments/ctmrg_environments.jl @@ -556,14 +556,14 @@ function LinearAlgebra.mul!(edst::CTMRGEnv, esrc::CTMRGEnv, α::Number) end function LinearAlgebra.rmul!(e::CTMRGEnv, α::Number) - rmul!(e.corners, α) - rmul!(e.edges, α) + rmul!.(e.corners, α) + rmul!.(e.edges, α) return e end function LinearAlgebra.axpy!(α::Number, e₁::CTMRGEnv, e₂::CTMRGEnv) - e₂.corners .+= α * e₁.corners - e₂.edges .+= α * e₁.edges + axpy!.(α, e₁.corners, e₂.corners) + axpy!.(α, e₁.edges, e₂.edges) return e₂ end diff --git a/src/states/infinitepeps.jl b/src/states/infinitepeps.jl index fea4ab1f..cf5b6277 100644 --- a/src/states/infinitepeps.jl +++ b/src/states/infinitepeps.jl @@ -155,13 +155,13 @@ end # Used in _scale during OptimKit.optimize function LinearAlgebra.rmul!(ψ::InfinitePEPS, α::Number) - rmul!(ψ.A, α) + rmul!.(ψ.A, α) return ψ end # Used in _add during OptimKit.optimize function LinearAlgebra.axpy!(α::Number, ψ₁::InfinitePEPS, ψ₂::InfinitePEPS) - ψ₂.A .+= α * ψ₁.A + axpy!.(α, ψ₁.A, ψ₂.A) return ψ₂ end From 960f5cc8d546109c09f966d90dd11c6a69d76836 Mon Sep 17 00:00:00 2001 From: leburgel Date: Wed, 8 Jan 2025 15:22:49 +0100 Subject: [PATCH 29/47] Fix typo --- src/algorithms/ctmrg/sequential.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algorithms/ctmrg/sequential.jl b/src/algorithms/ctmrg/sequential.jl index e0c954e2..4404a7f5 100644 --- a/src/algorithms/ctmrg/sequential.jl +++ b/src/algorithms/ctmrg/sequential.jl @@ -71,7 +71,7 @@ function sequential_projectors( end function sequential_projectors( coordinate::NTuple{3,Int}, - state::Union{InfiniteSquareNetwork}, + state::InfiniteSquareNetwork, envs::CTMRGEnv, alg::HalfInfiniteProjector, ) From 5324e895822006b4c653b765c432977d7488029c Mon Sep 17 00:00:00 2001 From: leburgel Date: Wed, 8 Jan 2025 16:41:17 +0100 Subject: [PATCH 30/47] Merge sparse environment structures for different network types --- .../contractions/ctmrg_contractions.jl | 53 +-- src/algorithms/ctmrg/ctmrg.jl | 2 - src/algorithms/ctmrg/sparse_environments.jl | 402 ++++++------------ 3 files changed, 151 insertions(+), 306 deletions(-) diff --git a/src/algorithms/contractions/ctmrg_contractions.jl b/src/algorithms/contractions/ctmrg_contractions.jl index fa605bc0..3e228503 100644 --- a/src/algorithms/contractions/ctmrg_contractions.jl +++ b/src/algorithms/contractions/ctmrg_contractions.jl @@ -1,3 +1,5 @@ +const InfiniteSquareNetwork = Union{InfinitePEPS,InfinitePartitionFunction} + const CTMRGEdgeTensor{S,N} = AbstractTensorMap{S,N,1} const CTMRG_PEPS_EdgeTensor{S} = CTMRGEdgeTensor{S,3} const CTMRG_PF_EdgeTensor{S} = CTMRGEdgeTensor{S,2} @@ -361,11 +363,11 @@ end """ half_infinite_environment(quadrant1::AbstractTensorMap{S,3,3}, quadrant2::AbstractTensorMap{S,3,3}) half_infinite_environment(C_1, C_2, E_1, E_2, E_3, E_4, - ket_1::P, ket_2::P, bra_1::P=ket_1, bra_2::P=ket_2) where {P<:PEPSTensor} + ket_1::P, bra_1::P, ket_2::P, bra_2::P) where {P<:PEPSTensor} half_infinite_environment(C_1, C_2, E_1, E_2, E_3, E_4, x, - ket_1::P, ket_2::P, bra_1::P=ket_1, bra_2::P=ket_2) where {P<:PEPSTensor} + ket_1::P bra_1::P, ket_2::P,, bra_2::P) where {P<:PEPSTensor} half_infinite_environment(x, C_1, C_2, E_1, E_2, E_3, E_4, - ket_1::P, ket_2::P, bra_1::P=ket_1, bra_2::P=ket_2) where {P<:PEPSTensor} + ket_1::P, bra_1::P, ket_2::P, bra_2::P) where {P<:PEPSTensor} half_infinite_environment(quadrant1::AbstractTensorMap{S,2,2}, quadrant2::AbstractTensorMap{S,2,2}) half_infinite_environment(C_1, C_2, E_1, E_2, E_3, E_4, @@ -418,7 +420,7 @@ function half_infinite_environment( end function half_infinite_environment( - C_1, C_2, E_1, E_2, E_3, E_4, ket_1::P, ket_2::P, bra_1::P=ket_1, bra_2::P=ket_2 + C_1, C_2, E_1, E_2, E_3, E_4, ket_1::P, bra_1::P, ket_2::P, bra_2::P ) where {P<:PEPSTensor} return @autoopt @tensor env[χ_in D_inabove D_inbelow; χ_out D_outabove D_outbelow] := E_1[χ_in D1 D2; χ1] * @@ -441,9 +443,9 @@ function half_infinite_environment( E_4, x::AbstractTensor{S,3}, ket_1::P, + bra_1::P, ket_2::P, - bra_1::P=ket_1, - bra_2::P=ket_2, + bra_2::P, ) where {S,P<:PEPSTensor} return @autoopt @tensor env_x[χ_in D_inabove D_inbelow] := E_1[χ_in D1 D2; χ1] * @@ -467,9 +469,9 @@ function half_infinite_environment( E_3, E_4, ket_1::P, + bra_1::P, ket_2::P, - bra_1::P=ket_1, - bra_2::P=ket_2, + bra_2::P, ) where {S,P<:PEPSTensor} return @autoopt @tensor x_env[χ_in D_inabove D_inbelow] := x[χ1 D1 D2] * @@ -540,13 +542,14 @@ end half1::T, half2::T ) where {T<:AbstractTensorMap{<:ElementarySpace,3,3}} full_infinite_environment(C_1, C_2, C_3, C_4, E_1, E_2, E_3, E_4, E_5, E_6, E_7, E_8, - ket_1::P, ket_2::P, bra_1::P=ket_1, bra_2::P=ket_2) where {P<:PEPSTensor} + ket_1::P, bra_1::P, ket_2::P, bra_2::P, + ket_3::P, bra_3::P, ket_4::P, bra_4::P) where {P<:PEPSTensor} full_infinite_environment(C_1, C_2, E_1, E_2, E_3, E_4, x, - ket_1::P, ket_2::P, ket_3::P, ket_4::P, - bra_1::P=ket_1, bra_2::P=ket_2, bra_3::P=ket_3, bra_4::P=ket_4) where {P<:PEPSTensor} + ket_1::P, bra_1::P, ket_2::P, bra_2::P, + ket_3::P, bra_3::P, ket_4::P, bra_4::P) where {P<:PEPSTensor} full_infinite_environment(x, C_1, C_2, E_1, E_2, E_3, E_4, - ket_1::P, ket_2::P, ket_3::P, ket_4::P, - bra_1::P=ket_1, bra_2::P=ket_2, bra_3::P=ket_3, bra_4::P=ket_4) where {P<:PEPSTensor} + ket_1::P, bra_1::P, ket_2::P, bra_2::P, + ket_3::P, bra_3::P, ket_4::P, bra_4::P) where {P<:PEPSTensor} full_infinite_environment( quadrant1::T, quadrant2::T, quadrant3::T, quadrant4::T @@ -654,13 +657,13 @@ function full_infinite_environment( E_7, E_8, ket_1::P, + bra_1::P, ket_2::P, + bra_2::P, ket_3::P, + bra_3::P, ket_4::P, - bra_1::P=ket_1, - bra_2::P=ket_2, - bra_3::P=ket_3, - bra_4::P=ket_4, + bra_4::P, ) where {P<:PEPSTensor} return @autoopt @tensor env[χ_in D_inabove D_inbelow; χ_out D_outabove D_outbelow] := E_1[χ_in D1 D2; χ1] * @@ -699,13 +702,13 @@ function full_infinite_environment( E_8, x::AbstractTensor{S,3}, ket_1::P, + bra_1::P, ket_2::P, + bra_2::P, ket_3::P, + bra_3::P, ket_4::P, - bra_1::P=ket_1, - bra_2::P=ket_2, - bra_3::P=ket_3, - bra_4::P=ket_4, + bra_4::P, ) where {S,P<:PEPSTensor} return @autoopt @tensor env_x[χ_in D_inabove D_inbelow] := E_1[χ_in D1 D2; χ1] * @@ -745,13 +748,13 @@ function full_infinite_environment( E_7, E_8, ket_1::P, + bra_1::P, ket_2::P, + bra_2::P, ket_3::P, + bra_3::P, ket_4::P, - bra_1::P=ket_1, - bra_2::P=ket_2, - bra_3::P=ket_3, - bra_4::P=ket_4, + bra_4::P, ) where {S,P<:PEPSTensor} return @autoopt @tensor x_env[χ_in D_inabove D_inbelow] := x[χ_x D_xabove D_xbelow] * diff --git a/src/algorithms/ctmrg/ctmrg.jl b/src/algorithms/ctmrg/ctmrg.jl index a859681c..02d79533 100644 --- a/src/algorithms/ctmrg/ctmrg.jl +++ b/src/algorithms/ctmrg/ctmrg.jl @@ -1,5 +1,3 @@ -const InfiniteSquareNetwork = Union{InfinitePEPS,InfinitePartitionFunction} - """ CTMRGAlgorithm diff --git a/src/algorithms/ctmrg/sparse_environments.jl b/src/algorithms/ctmrg/sparse_environments.jl index e1210e7a..7ea131de 100644 --- a/src/algorithms/ctmrg/sparse_environments.jl +++ b/src/algorithms/ctmrg/sparse_environments.jl @@ -3,97 +3,66 @@ # -------------------------------------------------------- """ - struct EnlargedCorner{Ct,E,A,A′} + struct EnlargedCorner{TC,TE,TA} Enlarged CTMRG corner tensor storage. """ -struct EnlargedCorner{Ct,E,A,A′} - C::Ct - E_1::E - E_2::E - ket::A - bra::A′ +struct EnlargedCorner{TC,TE,TA} + C::TC + E_1::TE + E_2::TE + A::TA +end +function EnlargedCorner( + C::CTMRGCornerTensor, + E1::CTMRG_PEPS_EdgeTensor, + E2::CTMRG_PEPS_EdgeTensor, + ket::PEPSTensor, + bra::PEPSTensor=ket, +) + return EnlargedCorner(C, E1, E2, (bra, ket)) end - -struct EnlargedPartitionFunctionCorner{Ct,E,A} - C::Ct - E_1::E - E_2::E - partfunc::A +function EnlargedCorner( + C::CTMRGCornerTensor, E1::CTMRG_PF_EdgeTensor, E2::CTMRG_PF_EdgeTensor, pf::PFTensor +) + return EnlargedCorner(C, E1, E2, (pf,)) end """ - EnlargedCorner(state, envs, coordinates) + EnlargedCorner(network::InfiniteSquareNetwork, envs, coordinates) Construct an enlarged corner with the correct row and column indices based on the given `coordinates` which are of the form `(dir, row, col)`. """ -function EnlargedCorner(state::InfinitePEPS, envs, coordinates) +function EnlargedCorner(network::InfiniteSquareNetwork, envs, coordinates) dir, r, c = coordinates if dir == NORTHWEST return EnlargedCorner( envs.corners[NORTHWEST, _prev(r, end), _prev(c, end)], envs.edges[WEST, r, _prev(c, end)], envs.edges[NORTH, _prev(r, end), c], - state[r, c], - state[r, c], + network[r, c], ) elseif dir == NORTHEAST return EnlargedCorner( envs.corners[NORTHEAST, _prev(r, end), _next(c, end)], envs.edges[NORTH, _prev(r, end), c], envs.edges[EAST, r, _next(c, end)], - state[r, c], - state[r, c], + network[r, c], ) elseif dir == SOUTHEAST return EnlargedCorner( envs.corners[SOUTHEAST, _next(r, end), _next(c, end)], envs.edges[EAST, r, _next(c, end)], envs.edges[SOUTH, _next(r, end), c], - state[r, c], - state[r, c], + network[r, c], ) elseif dir == SOUTHWEST return EnlargedCorner( envs.corners[SOUTHWEST, _next(r, end), _prev(c, end)], envs.edges[SOUTH, _next(r, end), c], envs.edges[WEST, r, _prev(c, end)], - state[r, c], - state[r, c], - ) - end -end - -function EnlargedCorner(state::InfinitePartitionFunction, envs, coordinates) - dir, r, c = coordinates - if dir == NORTHWEST - return EnlargedPartitionFunctionCorner( - envs.corners[NORTHWEST, _prev(r, end), _prev(c, end)], - envs.edges[WEST, r, _prev(c, end)], - envs.edges[NORTH, _prev(r, end), c], - state[r, c], - ) - elseif dir == NORTHEAST - return EnlargedPartitionFunctionCorner( - envs.corners[NORTHEAST, _prev(r, end), _next(c, end)], - envs.edges[NORTH, _prev(r, end), c], - envs.edges[EAST, r, _next(c, end)], - state[r, c], - ) - elseif dir == SOUTHEAST - return EnlargedPartitionFunctionCorner( - envs.corners[SOUTHEAST, _next(r, end), _next(c, end)], - envs.edges[EAST, r, _next(c, end)], - envs.edges[SOUTH, _next(r, end), c], - state[r, c], - ) - elseif dir == SOUTHWEST - return EnlargedPartitionFunctionCorner( - envs.corners[SOUTHWEST, _next(r, end), _prev(c, end)], - envs.edges[SOUTH, _next(r, end), c], - envs.edges[WEST, r, _prev(c, end)], - state[r, c], + network[r, c], ) end end @@ -106,59 +75,27 @@ direction, i.e. the way the environment and PEPS tensors connect. """ function TensorKit.TensorMap(Q::EnlargedCorner, dir::Int) if dir == NORTHWEST - return enlarge_northwest_corner(Q.E_1, Q.C, Q.E_2, Q.ket, Q.bra) + return enlarge_northwest_corner(Q.E_1, Q.C, Q.E_2, Q.A...) elseif dir == NORTHEAST - return enlarge_northeast_corner(Q.E_1, Q.C, Q.E_2, Q.ket, Q.bra) + return enlarge_northeast_corner(Q.E_1, Q.C, Q.E_2, Q.A...) elseif dir == SOUTHEAST - return enlarge_southeast_corner(Q.E_1, Q.C, Q.E_2, Q.ket, Q.bra) + return enlarge_southeast_corner(Q.E_1, Q.C, Q.E_2, Q.A...) elseif dir == SOUTHWEST - return enlarge_southwest_corner(Q.E_1, Q.C, Q.E_2, Q.ket, Q.bra) - end -end - -function TensorKit.TensorMap(Q::EnlargedPartitionFunctionCorner, dir::Int) - if dir == NORTHWEST - return enlarge_northwest_corner(Q.E_1, Q.C, Q.E_2, Q.partfunc) - elseif dir == NORTHEAST - return enlarge_northeast_corner(Q.E_1, Q.C, Q.E_2, Q.partfunc) - elseif dir == SOUTHEAST - return enlarge_southeast_corner(Q.E_1, Q.C, Q.E_2, Q.partfunc) - elseif dir == SOUTHWEST - return enlarge_southwest_corner(Q.E_1, Q.C, Q.E_2, Q.partfunc) + return enlarge_southwest_corner(Q.E_1, Q.C, Q.E_2, Q.A...) end end function renormalize_northwest_corner(ec::EnlargedCorner, P_left, P_right) - return renormalize_northwest_corner( - ec.E_1, ec.C, ec.E_2, P_left, P_right, ec.ket, ec.bra - ) + return renormalize_northwest_corner(ec.E_1, ec.C, ec.E_2, P_left, P_right, ec.A...) end function renormalize_northeast_corner(ec::EnlargedCorner, P_left, P_right) - return renormalize_northeast_corner( - ec.E_1, ec.C, ec.E_2, P_left, P_right, ec.ket, ec.bra - ) + return renormalize_northeast_corner(ec.E_1, ec.C, ec.E_2, P_left, P_right, ec.A...) end function renormalize_southeast_corner(ec::EnlargedCorner, P_left, P_right) - return renormalize_southeast_corner( - ec.E_1, ec.C, ec.E_2, P_left, P_right, ec.ket, ec.bra - ) + return renormalize_southeast_corner(ec.E_1, ec.C, ec.E_2, P_left, P_right, ec.A...) end function renormalize_southwest_corner(ec::EnlargedCorner, P_left, P_right) - return renormalize_southwest_corner( - ec.E_1, ec.C, ec.E_2, P_left, P_right, ec.ket, ec.bra - ) -end -function renormalize_northwest_corner(ec::EnlargedPartitionFunctionCorner, P_left, P_right) - return renormalize_northwest_corner(ec.E_1, ec.C, ec.E_2, P_left, P_right, ec.partfunc) -end -function renormalize_northeast_corner(ec::EnlargedPartitionFunctionCorner, P_left, P_right) - return renormalize_northeast_corner(ec.E_1, ec.C, ec.E_2, P_left, P_right, ec.partfunc) -end -function renormalize_southeast_corner(ec::EnlargedPartitionFunctionCorner, P_left, P_right) - return renormalize_southeast_corner(ec.E_1, ec.C, ec.E_2, P_left, P_right, ec.partfunc) -end -function renormalize_southwest_corner(ec::EnlargedPartitionFunctionCorner, P_left, P_right) - return renormalize_southwest_corner(ec.E_1, ec.C, ec.E_2, P_left, P_right, ec.partfunc) + return renormalize_southwest_corner(ec.E_1, ec.C, ec.E_2, P_left, P_right, ec.A...) end # Wrapper around half_infinite_environment contraction using EnlargedCorners (used in ctmrg_projectors) @@ -185,17 +122,41 @@ end Half-infinite CTMRG environment tensor storage. """ -struct HalfInfiniteEnv{C,E,A,A′} # TODO: subtype as AbstractTensorMap once TensorKit is updated - C_1::C - C_2::C - E_1::E - E_2::E - E_3::E - E_4::E - ket_1::A - ket_2::A - bra_1::A′ - bra_2::A′ +struct HalfInfiniteEnv{TC,TE,TA} # TODO: subtype as AbstractTensorMap once TensorKit is updated + C_1::TC + C_2::TC + E_1::TE + E_2::TE + E_3::TE + E_4::TE + A_1::TA + A_2::TA +end +function HalfInfiniteEnv( + C_1::CTMRGCornerTensor, + C_2::CTMRGCornerTensor, + E_1::CTMRG_PEPS_EdgeTensor, + E_2::CTMRG_PEPS_EdgeTensor, + E_3::CTMRG_PEPS_EdgeTensor, + E_4::CTMRG_PEPS_EdgeTensor, + ket_1::PEPSTensor, + ket_2::PEPSTensor, + bra_1::PEPSTensor=ket_1, + bra_2::PEPSTensor=ket_2, +) + return HalfInfiniteEnv(C_1, C_2, E_1, E_2, E_3, E_4, (bra_1, ket_1), (bra_2, ket_2)) +end +function HalfInfiniteEnv( + C_1::CTMRGCornerTensor, + C_2::CTMRGCornerTensor, + E_1::CTMRG_PF_EdgeTensor, + E_2::CTMRG_PF_EdgeTensor, + E_3::CTMRG_PF_EdgeTensor, + E_4::CTMRG_PF_EdgeTensor, + pf_1::PFTensor, + pf_2::PFTensor, +) + return HalfInfiniteEnv(C_1, C_2, E_1, E_2, E_3, E_4, (pf_1,), (pf_2,)) end # Construct environment from two enlarged corners @@ -207,37 +168,8 @@ function HalfInfiniteEnv(quadrant1::EnlargedCorner, quadrant2::EnlargedCorner) quadrant1.E_2, quadrant2.E_1, quadrant2.E_2, - quadrant1.ket, - quadrant2.ket, - quadrant1.bra, - quadrant2.bra, - ) -end - -struct HalfInfinitePartitionFunctionEnv{C,E,A,A′} # TODO: subtype as AbstractTensorMap once TensorKit is updated - C_1::C - C_2::C - E_1::E - E_2::E - E_3::E - E_4::E - partfunc_1::A - partfunc_2::A -end - -# Construct environment from two enlarged corners -function HalfInfinitePartitionFunctionEnv( - quadrant1::EnlargedPartitionFunctionCorner, quadrant2::EnlargedPartitionFunctionCorner -) - return HalfInfinitePartitionFunctionEnv( - quadrant1.C, - quadrant2.C, - quadrant1.E_1, - quadrant1.E_2, - quadrant2.E_1, - quadrant2.E_2, - quadrant1.partfunc, - quadrant2.partfunc, + quadrant1.A_1, + quadrant2.A_2, ) end @@ -248,22 +180,7 @@ Instantiate half-infinite environment as `TensorMap` explicitly. """ function TensorKit.TensorMap(env::HalfInfiniteEnv) # Dense operator return half_infinite_environment( - env.C_1, - env.C_2, - env.E_1, - env.E_2, - env.E_3, - env.E_4, - env.ket_1, - env.ket_2, - env.bra_1, - env.bra_2, - ) -end - -function TensorKit.TensorMap(env::HalfInfinitePartitionFunctionEnv) # Dense operator - return half_infinite_environment( - env.C_1, env.C_2, env.E_1, env.E_2, env.E_3, env.E_4, env.partfunc_1, env.partfunc_2 + env.C_1, env.C_2, env.E_1, env.E_2, env.E_3, env.E_4, env.A_1..., env.A_2... ) end @@ -276,127 +193,70 @@ linear map or adjoint linear map on `x` if `Val(true)` or `Val(false)` is passed """ function (env::HalfInfiniteEnv)(x, ::Val{false}) # Linear map: env() * x return half_infinite_environment( - env.C_1, - env.C_2, - env.E_1, - env.E_2, - env.E_3, - env.E_4, - x, - env.ket_1, - env.ket_2, - env.bra_1, - env.bra_2, + env.C_1, env.C_2, env.E_1, env.E_2, env.E_3, env.E_4, x, env.A_1..., env.A_2... ) end function (env::HalfInfiniteEnv)(x, ::Val{true}) # Adjoint linear map: env()' * x return half_infinite_environment( - x, - env.C_1, - env.C_2, - env.E_1, - env.E_2, - env.E_3, - env.E_4, - env.ket_1, - env.ket_2, - env.bra_1, - env.bra_2, + x, env.C_1, env.C_2, env.E_1, env.E_2, env.E_3, env.E_4, env.A_1..., env.A_2... ) end -function (env::HalfInfinitePartitionFunctionEnv)(x, ::Val{false}) # Linear map: env() * x - return halfinfinite_partitionfunction_environment( - env.C_1, - env.C_2, - env.E_1, - env.E_2, - env.E_3, - env.E_4, - x, - env.partfunc_1, - env.partfunc_2, - ) +# ----------------------------------------------------- +# AbstractTensorMap subtyping and IterSVD compatibility + +function _domain_space(A::NTuple{2,<:PEPSTensor}, n::Int) + return domain(A[1])[n] * domain(A[2])[n]' end -function (env::HalfInfinitePartitionFunctionEnv)(x, ::Val{true}) # Adjoint linear map: env()' * x - return halfinfinite_partitionfunction_environment( - x, - env.C_1, - env.C_2, - env.E_1, - env.E_2, - env.E_3, - env.E_4, - env.partfunc_1, - env.partfunc_2, - ) +function _domain_space(A::NTuple{1,<:PFTensor}, n::Int) + return domain(A[1])[n] end -# Wrapper around half_infinite_environment contraction using EnlargedCorners (used in ctmrg_projectors) -function halfinfinite_partitionfunction_environment( - ec_1::EnlargedPartitionFunctionCorner, ec_2::EnlargedPartitionFunctionCorner -) - return HalfInfiniteEnv( - ec_1.C, ec_2.C, ec_1.E_1, ec_1.E_2, ec_2.E_1, ec_2.E_2, ec_1.partfunc, ec_2.partfunc - ) +function _codomain_space(A::NTuple{2,<:PEPSTensor}, n::Int) + return domain(A[1])[n]' * domain(A[2])[n] +end +function _codomain_space(A::NTuple{1,<:PFTensor}, n::Int) + return domain(A[1])[n]' end -# ----------------------------------------------------- -# AbstractTensorMap subtyping and IterSVD compatibility function TensorKit.domain(env::HalfInfiniteEnv) - return domain(env.E_4) * domain(env.ket_2)[3] * domain(env.bra_2)[3]' + return domain(env.E_4) * _domain_space(env.A_2, 3) end function TensorKit.codomain(env::HalfInfiniteEnv) - return codomain(env.E_1)[1] * domain(env.ket_1)[3]' * domain(env.bra_1)[3] + return codomain(env.E_1)[1] * _codomain_space(env.A_1, 3) end function random_start_vector(env::HalfInfiniteEnv) return Tensor(randn, domain(env)) end -function TensorKit.domain(env::HalfInfinitePartitionFunctionEnv) - return domain(env.E_4) * domain(env.ket_2)[3] * domain(env.bra_2)[3]' -end - -function TensorKit.codomain(env::HalfInfinitePartitionFunctionEnv) - return codomain(env.E_1)[1] * domain(env.ket_1)[3]' * domain(env.bra_1)[3] -end - -function random_start_vector(env::HalfInfinitePartitionFunctionEnv) - return Tensor(randn, domain(env)) -end - # -------------------------------- # Sparse full-infinite environment # -------------------------------- """ - struct FullInfiniteEnv{C,E,A,A′} + struct FullInfiniteEnv{TC,TE,TA} Full-infinite CTMRG environment tensor storage. """ -struct FullInfiniteEnv{C,E,A,A′} # TODO: subtype as AbstractTensorMap once TensorKit is updated - C_1::C - C_2::C - C_3::C - C_4::C - E_1::E - E_2::E - E_3::E - E_4::E - E_5::E - E_6::E - E_7::E - E_8::E - ket_1::A - ket_2::A - ket_3::A - ket_4::A - bra_1::A′ - bra_2::A′ - bra_3::A′ - bra_4::A′ +struct FullInfiniteEnv{TC,TE,TA} # TODO: subtype as AbstractTensorMap once TensorKit is updated + C_1::TC + C_2::TC + C_3::TC + C_4::TC + E_1::TE + E_2::TE + E_3::TE + E_4::TE + E_5::TE + E_6::TE + E_7::TE + E_8::TE + A_1::TA + A_2::TA + A_3::TA + A_4::TA end # Construct environment from two enlarged corners @@ -416,14 +276,10 @@ function FullInfiniteEnv( quadrant3.E_2, quadrant4.E_1, quadrant4.E_2, - quadrant1.ket, - quadrant2.ket, - quadrant3.ket, - quadrant4.ket, - quadrant1.bra, - quadrant2.bra, - quadrant3.bra, - quadrant4.bra, + quadrant1.A, + quadrant2.A, + quadrant3.A, + quadrant4.A, ) end @@ -446,14 +302,10 @@ function TensorKit.TensorMap(env::FullInfiniteEnv) # Dense operator env.E_3, env.E_4, env.E_5, - env.ket_1, - env.ket_2, - env.ket_3, - env.ket_4, - env.bra_1, - env.bra_2, - env.bra_3, - env.bra_4, + env.A_1..., + env.A_2..., + env.A_3..., + env.A_4..., ) end @@ -479,14 +331,10 @@ function (env::FullInfiniteEnv)(x, ::Val{false}) # Linear map: env() * x env.E_7, env.E_8, x, - env.ket_1, - env.ket_2, - env.ket_3, - env.ket_4, - env.bra_1, - env.bra_2, - env.bra_3, - env.bra_4, + env.A_1..., + env.A_2..., + env.A_3..., + env.A_4..., ) end function (env::FullInfiniteEnv)(x, ::Val{true}) # Adjoint linear map: env()' * x @@ -504,14 +352,10 @@ function (env::FullInfiniteEnv)(x, ::Val{true}) # Adjoint linear map: env()' * env.E_6, env.E_7, env.E_8, - env.ket_1, - env.ket_2, - env.ket_3, - env.ket_4, - env.bra_1, - env.bra_2, - env.bra_3, - env.bra_4, + env.A_1..., + env.A_2..., + env.A_3..., + env.A_4..., ) end @@ -524,11 +368,11 @@ end # AbstractTensorMap subtyping and IterSVD compatibility function TensorKit.domain(env::FullInfiniteEnv) - return domain(env.E_8) * domain(env.ket_4)[3] * domain(env.bra_4)[3]' + return domain(env.E_8) * _domain_space(env.A_4, 3) end function TensorKit.codomain(env::FullInfiniteEnv) - return codomain(env.E_1)[1] * domain(env.ket_1)[3]' * domain(env.bra_1)[3] + return codomain(env.E_1)[1] * _codomain_space(env.A_1, 3) end function random_start_vector(env::FullInfiniteEnv) From 97722420cc208d90d78cf2c06922ba42c2eb694e Mon Sep 17 00:00:00 2001 From: leburgel Date: Wed, 8 Jan 2025 16:46:38 +0100 Subject: [PATCH 31/47] Rename `norm` -> `value` for `InfinitePartitionFunction` --- src/PEPSKit.jl | 2 +- src/algorithms/toolbox.jl | 8 +++++++- test/ctmrg/partition_function.jl | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/PEPSKit.jl b/src/PEPSKit.jl index 09f4dd44..8c012b80 100644 --- a/src/PEPSKit.jl +++ b/src/PEPSKit.jl @@ -197,7 +197,7 @@ export fixedpoint export absorb_weight export su_iter, simpleupdate, SimpleUpdate -export InfinitePartitionFunction +export InfinitePartitionFunction, value export InfinitePEPS, InfiniteTransferPEPS export SUWeight, InfiniteWeightPEPS export InfinitePEPO, InfiniteTransferPEPO diff --git a/src/algorithms/toolbox.jl b/src/algorithms/toolbox.jl index bea0f5fb..7eda7249 100644 --- a/src/algorithms/toolbox.jl +++ b/src/algorithms/toolbox.jl @@ -57,7 +57,13 @@ function LinearAlgebra.norm(peps::InfinitePEPS, env::CTMRGEnv) return total end -function LinearAlgebra.norm(partfunc::InfinitePartitionFunction, env::CTMRGEnv) +""" + partition_function(peps::InfinitePartitionFunction, env::CTMRGEnv) + +Return the value (per site) of a given parition function contracted using a given CTMRG +environment. +""" +function value(partfunc::InfinitePartitionFunction, env::CTMRGEnv) total = one(scalartype(partfunc)) for r in 1:size(partfunc, 1), c in 1:size(partfunc, 2) diff --git a/test/ctmrg/partition_function.jl b/test/ctmrg/partition_function.jl index 2986d4be..be3b8b3c 100644 --- a/test/ctmrg/partition_function.jl +++ b/test/ctmrg/partition_function.jl @@ -134,7 +134,7 @@ projector_algs = [HalfInfiniteProjector, FullInfiniteProjector] # check observables - λ = norm(Z, env) + λ = value(Z, env) m = local_contraction(M, env) / local_contraction(O, env) e = local_contraction(E, env) / local_contraction(O, env) From 441040fc1567b4b08d676b6a05d141919f54bf16 Mon Sep 17 00:00:00 2001 From: leburgel Date: Wed, 8 Jan 2025 17:58:24 +0100 Subject: [PATCH 32/47] Remove unused abstract network supertypes --- src/PEPSKit.jl | 1 - src/networks/abstract_networks.jl | 20 -------------------- src/operators/infinitepepo.jl | 2 +- src/states/infinitepartitionfunction.jl | 2 +- src/states/infinitepeps.jl | 2 +- src/states/infiniteweightpeps.jl | 4 ++-- 6 files changed, 5 insertions(+), 26 deletions(-) delete mode 100644 src/networks/abstract_networks.jl diff --git a/src/PEPSKit.jl b/src/PEPSKit.jl index 8c012b80..f1c1238a 100644 --- a/src/PEPSKit.jl +++ b/src/PEPSKit.jl @@ -23,7 +23,6 @@ include("utility/hook_pullback.jl") include("utility/autoopt.jl") include("networks/tensors.jl") -include("networks/abstract_networks.jl") include("states/infinitepeps.jl") include("states/infiniteweightpeps.jl") diff --git a/src/networks/abstract_networks.jl b/src/networks/abstract_networks.jl deleted file mode 100644 index 1d92a292..00000000 --- a/src/networks/abstract_networks.jl +++ /dev/null @@ -1,20 +0,0 @@ -""" - abstract type AbstractPartitionFunction end - -Abstract supertype for a 2D partition function. -""" -abstract type AbstractPartitionFunction end - -""" - abstract type AbstractPEPS end - -Abstract supertype for a 2D projected entangled-pair state. -""" -abstract type AbstractPEPS end - -""" - abstract type AbstractPEPO end - -Abstract supertype for a 2D projected entangled-pair operator. -""" -abstract type AbstractPEPO end diff --git a/src/operators/infinitepepo.jl b/src/operators/infinitepepo.jl index 6fad9fd3..14e21e8a 100644 --- a/src/operators/infinitepepo.jl +++ b/src/operators/infinitepepo.jl @@ -3,7 +3,7 @@ Represents an infinite projected entangled-pair operator (PEPO) on a 3D cubic lattice. """ -struct InfinitePEPO{T<:PEPOTensor} <: AbstractPEPO +struct InfinitePEPO{T<:PEPOTensor} A::Array{T,3} function InfinitePEPO(A::Array{T,3}) where {T<:PEPOTensor} diff --git a/src/states/infinitepartitionfunction.jl b/src/states/infinitepartitionfunction.jl index 07a25b93..3048d36d 100644 --- a/src/states/infinitepartitionfunction.jl +++ b/src/states/infinitepartitionfunction.jl @@ -3,7 +3,7 @@ Represents an infinite projected entangled-pair state on a 2D square lattice. """ -struct InfinitePartitionFunction{T<:PartitionFunctionTensor} <: AbstractPartitionFunction +struct InfinitePartitionFunction{T<:PartitionFunctionTensor} A::Matrix{T} function InfinitePartitionFunction{T}(A::Matrix{T}) where {T<:PartitionFunctionTensor} return new{T}(A) diff --git a/src/states/infinitepeps.jl b/src/states/infinitepeps.jl index cf5b6277..12cbdbb1 100644 --- a/src/states/infinitepeps.jl +++ b/src/states/infinitepeps.jl @@ -3,7 +3,7 @@ Represents an infinite projected entangled-pair state on a 2D square lattice. """ -struct InfinitePEPS{T<:PEPSTensor} <: AbstractPEPS +struct InfinitePEPS{T<:PEPSTensor} A::Matrix{T} InfinitePEPS{T}(A::Matrix{T}) where {T<:PEPSTensor} = new{T}(A) function InfinitePEPS(A::Array{T,2}) where {T<:PEPSTensor} diff --git a/src/states/infiniteweightpeps.jl b/src/states/infiniteweightpeps.jl index 91303bed..24c85633 100644 --- a/src/states/infiniteweightpeps.jl +++ b/src/states/infiniteweightpeps.jl @@ -50,12 +50,12 @@ function compare_weights(wts1::SUWeight, wts2::SUWeight) end """ - struct InfiniteWeightPEPS{T<:PEPSTensor,E<:PEPSWeight} <: AbstractPEPS + struct InfiniteWeightPEPS{T<:PEPSTensor,E<:PEPSWeight} Represents an infinite projected entangled-pair state on a 2D square lattice consisting of vertex tensors and bond weights. """ -struct InfiniteWeightPEPS{T<:PEPSTensor,E<:PEPSWeight} <: AbstractPEPS +struct InfiniteWeightPEPS{T<:PEPSTensor,E<:PEPSWeight} vertices::Matrix{T} weights::SUWeight{E} From 759721bac21425775cea4c768ab6c851c60ee36f Mon Sep 17 00:00:00 2001 From: leburgel Date: Thu, 9 Jan 2025 08:29:20 +0100 Subject: [PATCH 33/47] Break out network-specific CTMRG obective functions --- src/algorithms/ctmrg/ctmrg.jl | 13 ++++++++----- src/algorithms/toolbox.jl | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/algorithms/ctmrg/ctmrg.jl b/src/algorithms/ctmrg/ctmrg.jl index 02d79533..80492436 100644 --- a/src/algorithms/ctmrg/ctmrg.jl +++ b/src/algorithms/ctmrg/ctmrg.jl @@ -35,7 +35,7 @@ function MPSKit.leading_boundary(envinit, state, alg::CTMRGAlgorithm) TS = map(x -> tsvd(x)[2], envinit.edges) η = one(real(scalartype(state))) - N = norm(state, envinit) + N = ctmrg_objective(state, envinit) env = deepcopy(envinit) log = ignore_derivatives(() -> MPSKit.IterLog("CTMRG")) @@ -44,22 +44,25 @@ function MPSKit.leading_boundary(envinit, state, alg::CTMRGAlgorithm) for iter in 1:(alg.maxiter) env, = ctmrg_iteration(state, env, alg) # Grow and renormalize in all 4 directions η, CS, TS = calc_convergence(env, CS, TS) - N = norm(state, env) if η ≤ alg.tol && iter ≥ alg.miniter - ctmrg_logfinish!(log, iter, η, N) + ctmrg_logfinish!(log, iter, η, ctmrg_objective(state, env)) break end if iter == alg.maxiter - ctmrg_logcancel!(log, iter, η, N) + ctmrg_logcancel!(log, iter, η, ctmrg_objective(state, env)) else - ctmrg_logiter!(log, iter, η, N) + ctmrg_logiter!(log, iter, η, ctmrg_objective(state, env)) end end return env end end +# network-specific objective functions +ctmrg_objective(state::InfinitePEPS, env::CTMRGEnv) = norm(state, env) +ctmrg_objective(state::InfinitePartitionFunction, env::CTMRGEnv) = value(state, env) + # custom CTMRG logging ctmrg_loginit!(log, η, N) = @infov 2 loginit!(log, η, N) ctmrg_logiter!(log, iter, η, N) = @infov 3 logiter!(log, iter, η, N) diff --git a/src/algorithms/toolbox.jl b/src/algorithms/toolbox.jl index 7eda7249..c8011fd0 100644 --- a/src/algorithms/toolbox.jl +++ b/src/algorithms/toolbox.jl @@ -58,7 +58,7 @@ function LinearAlgebra.norm(peps::InfinitePEPS, env::CTMRGEnv) end """ - partition_function(peps::InfinitePartitionFunction, env::CTMRGEnv) + value(partfunc::InfinitePartitionFunction, env::CTMRGEnv) Return the value (per site) of a given parition function contracted using a given CTMRG environment. From 328335c5c9287f3d1ed10ad8115187fbbba8201f Mon Sep 17 00:00:00 2001 From: leburgel Date: Thu, 9 Jan 2025 09:01:12 +0100 Subject: [PATCH 34/47] Make norm computation verbosity-dependent --- src/algorithms/ctmrg/ctmrg.jl | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/algorithms/ctmrg/ctmrg.jl b/src/algorithms/ctmrg/ctmrg.jl index 80492436..9fc06466 100644 --- a/src/algorithms/ctmrg/ctmrg.jl +++ b/src/algorithms/ctmrg/ctmrg.jl @@ -35,24 +35,26 @@ function MPSKit.leading_boundary(envinit, state, alg::CTMRGAlgorithm) TS = map(x -> tsvd(x)[2], envinit.edges) η = one(real(scalartype(state))) - N = ctmrg_objective(state, envinit) env = deepcopy(envinit) log = ignore_derivatives(() -> MPSKit.IterLog("CTMRG")) + function get_objective(state, env, verbosity) + return alg.verbosity >= verbosity ? ctmrg_objective(state, env) : nothing + end return LoggingExtras.withlevel(; alg.verbosity) do - ctmrg_loginit!(log, η, N) + ctmrg_loginit!(log, η, get_objective(state, envinit, 2)) for iter in 1:(alg.maxiter) env, = ctmrg_iteration(state, env, alg) # Grow and renormalize in all 4 directions η, CS, TS = calc_convergence(env, CS, TS) if η ≤ alg.tol && iter ≥ alg.miniter - ctmrg_logfinish!(log, iter, η, ctmrg_objective(state, env)) + ctmrg_logfinish!(log, iter, η, get_objective(state, envinit, 2)) break end if iter == alg.maxiter - ctmrg_logcancel!(log, iter, η, ctmrg_objective(state, env)) + ctmrg_logcancel!(log, iter, η, get_objective(state, envinit, 1)) else - ctmrg_logiter!(log, iter, η, ctmrg_objective(state, env)) + ctmrg_logiter!(log, iter, η, get_objective(state, envinit, 3)) end end return env From 47abb4642ea905709bb535df72cd2029be5fe2a5 Mon Sep 17 00:00:00 2001 From: leburgel Date: Thu, 9 Jan 2025 09:29:43 +0100 Subject: [PATCH 35/47] Fix typos --- src/algorithms/ctmrg/ctmrg.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/algorithms/ctmrg/ctmrg.jl b/src/algorithms/ctmrg/ctmrg.jl index 9fc06466..c94197c1 100644 --- a/src/algorithms/ctmrg/ctmrg.jl +++ b/src/algorithms/ctmrg/ctmrg.jl @@ -48,13 +48,13 @@ function MPSKit.leading_boundary(envinit, state, alg::CTMRGAlgorithm) η, CS, TS = calc_convergence(env, CS, TS) if η ≤ alg.tol && iter ≥ alg.miniter - ctmrg_logfinish!(log, iter, η, get_objective(state, envinit, 2)) + ctmrg_logfinish!(log, iter, η, get_objective(state, env, 2)) break end if iter == alg.maxiter - ctmrg_logcancel!(log, iter, η, get_objective(state, envinit, 1)) + ctmrg_logcancel!(log, iter, η, get_objective(state, env, 1)) else - ctmrg_logiter!(log, iter, η, get_objective(state, envinit, 3)) + ctmrg_logiter!(log, iter, η, get_objective(state, env, 3)) end end return env From 78225a63ab00dcf739faeffce53e0c8e908252fb Mon Sep 17 00:00:00 2001 From: leburgel Date: Thu, 9 Jan 2025 10:36:09 +0100 Subject: [PATCH 36/47] Remove arrows in tensor docstring diagrams --- src/networks/tensors.jl | 48 ++++++++++++++++++----------------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/src/networks/tensors.jl b/src/networks/tensors.jl index d240a3e7..e96a2d0e 100644 --- a/src/networks/tensors.jl +++ b/src/networks/tensors.jl @@ -10,15 +10,13 @@ as: ``T : W ⊗ S ← N ⊗ E``. Here, ``N``, ``E``, ``S`` and ``W`` denote the and west spaces, respectively. ``` - N - / - v - / - W--<-- --<--E - / - v - / - S + N + ╱ + ╱ + W---- ----E + ╱ + ╱ + S ``` """ const PartitionFunctionTensor{S} = AbstractTensorMap{S,2,2} where {S<:ElementarySpace} @@ -41,15 +39,13 @@ and ``N``, ``E``, ``S`` and ``W`` denote the north, east, south and west virtual respectively. ``` - N - / - v - / - W-->-- --<--E - /| - ^ v - / | - S P + N + ╱ + ╱ + W---- ----E + ╱| + ╱ | + S P ``` """ const PEPSTensor{S} = AbstractTensorMap{S,1,4} where {S<:ElementarySpace} @@ -106,15 +102,13 @@ mapping from ``P´'`` to ``P`` where ``P´'`` corresponds to a physical PEPS ind ``` - P´ N - | / - ^ v - |/ - W-->-- --<--E - /| - ^ v - / | - S P + P´ N + | ╱ + |╱ + W---- ----E + ╱| + ╱ | + S P ``` """ const PEPOTensor{S} = AbstractTensorMap{S,2,4} where {S<:ElementarySpace} From 5fd0f80a1ebf6b13cc3eca65f35cc18f03fd874a Mon Sep 17 00:00:00 2001 From: leburgel Date: Thu, 9 Jan 2025 12:52:26 +0100 Subject: [PATCH 37/47] Add local expectation value for partition functions --- src/PEPSKit.jl | 2 +- src/algorithms/contractions/localoperator.jl | 38 ++++++++++++++++++++ src/algorithms/toolbox.jl | 21 +++++++++++ 3 files changed, 60 insertions(+), 1 deletion(-) diff --git a/src/PEPSKit.jl b/src/PEPSKit.jl index f1c1238a..d689c97b 100644 --- a/src/PEPSKit.jl +++ b/src/PEPSKit.jl @@ -40,8 +40,8 @@ include("environments/ctmrg_environments.jl") include("environments/transferpeps_environments.jl") include("environments/transferpepo_environments.jl") -include("algorithms/contractions/localoperator.jl") include("algorithms/contractions/ctmrg_contractions.jl") +include("algorithms/contractions/localoperator.jl") include("algorithms/ctmrg/sparse_environments.jl") include("algorithms/ctmrg/ctmrg.jl") diff --git a/src/algorithms/contractions/localoperator.jl b/src/algorithms/contractions/localoperator.jl index 324bb028..6d44f745 100644 --- a/src/algorithms/contractions/localoperator.jl +++ b/src/algorithms/contractions/localoperator.jl @@ -451,3 +451,41 @@ end end return macroexpand(@__MODULE__, returnex) end + +# Partition function contractions + +""" + contract_local_tensor(inds, O, pf::InfinitePartitionFunction, env) + +Contract a local tensor `O` inserted into a partition function `pf` at position `inds`, +using the environment `env`. +""" +function contract_local_tensor( + inds::Tuple{Int,Int}, + O::AbstractTensorMap{S,2,2}, + env::CTMRGEnv{C,<:CTMRG_PF_EdgeTensor}, +) where {S,C} + r, c = inds + return @autoopt @tensor env.corners[NORTHWEST, _prev(r, end), _prev(c, end)][ + χ_WNW + χ_NNW + ] * + env.edges[NORTH, _prev(r, end), c][χ_NNW D_N; χ_NNE] * + env.corners[NORTHEAST, _prev(r, end), _next(c, end)][χ_NNE; χ_ENE] * + env.edges[EAST, r, _next(c, end)][χ_ENE D_E; χ_ESE] * + env.corners[SOUTHEAST, _next(r, end), _next(c, end)][χ_ESE; χ_SSE] * + env.edges[SOUTH, _next(r, end), c][χ_SSE D_S; χ_SSW] * + env.corners[SOUTHWEST, _next(r, end), _prev(c, end)][χ_SSW; χ_WSW] * + env.edges[WEST, r, _prev(c, end)][χ_WSW D_W; χ_WNW] * + O[D_W D_S; D_N D_E] +end +function contract_local_tensor( + inds::CartesianIndex{2}, + O::AbstractTensorMap{S,2,2}, + env::CTMRGEnv{C,<:CTMRG_PF_EdgeTensor}, +) where {S,C} + return contract_local_tensor(Tuple(inds), O, env) +end +function contract_local_tensor(op::Pair, env::CTMRGEnv{C,<:CTMRG_PF_EdgeTensor}) where {C} + return contract_local_tensor(op..., env) +end diff --git a/src/algorithms/toolbox.jl b/src/algorithms/toolbox.jl index c8011fd0..42e18a6d 100644 --- a/src/algorithms/toolbox.jl +++ b/src/algorithms/toolbox.jl @@ -57,6 +57,27 @@ function LinearAlgebra.norm(peps::InfinitePEPS, env::CTMRGEnv) return total end +function MPSKit.expectation_value( + inds::CartesianIndex{2}, + O::AbstractTensorMap{S,2,2}, + pf::InfinitePartitionFunction, + envs::CTMRGEnv, +) where {S} + return contract_local_tensor(inds, O, envs) / + contract_local_tensor(inds, pf[inds], envs) +end +function MPSKit.expectation_value( + inds::Tuple{Int,Int}, + O::AbstractTensorMap{S,2,2}, + pf::InfinitePartitionFunction, + envs::CTMRGEnv, +) where {S} + return expectation_value(CartesianIndex(inds), O, pf, envs) +end +function MPSKit.expectation_value(op::Pair, pf::InfinitePartitionFunction, envs::CTMRGEnv) + return expectation_value(op..., pf, envs) +end + """ value(partfunc::InfinitePartitionFunction, env::CTMRGEnv) From 16777c0c08bfa815736fbc8dc4fc07e8b631d78f Mon Sep 17 00:00:00 2001 From: leburgel Date: Thu, 9 Jan 2025 12:56:01 +0100 Subject: [PATCH 38/47] Correct signature in docstring --- src/algorithms/contractions/localoperator.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algorithms/contractions/localoperator.jl b/src/algorithms/contractions/localoperator.jl index 6d44f745..aaa2cf71 100644 --- a/src/algorithms/contractions/localoperator.jl +++ b/src/algorithms/contractions/localoperator.jl @@ -455,7 +455,7 @@ end # Partition function contractions """ - contract_local_tensor(inds, O, pf::InfinitePartitionFunction, env) + contract_local_tensor(inds, O, env) Contract a local tensor `O` inserted into a partition function `pf` at position `inds`, using the environment `env`. From b818adfbb512d3f19eacc624740044dac5fc3c2b Mon Sep 17 00:00:00 2001 From: leburgel Date: Thu, 9 Jan 2025 13:03:53 +0100 Subject: [PATCH 39/47] Update test to use partition function expectation value --- test/ctmrg/partition_function.jl | 33 ++------------------------------ 1 file changed, 2 insertions(+), 31 deletions(-) diff --git a/test/ctmrg/partition_function.jl b/test/ctmrg/partition_function.jl index be3b8b3c..8107d5e3 100644 --- a/test/ctmrg/partition_function.jl +++ b/test/ctmrg/partition_function.jl @@ -6,18 +6,6 @@ using LinearAlgebra using QuadGK using MPSKit -using PEPSKit: - @autoopt, - CTMRG_PF_EdgeTensor, - NORTHWEST, - NORTHEAST, - SOUTHEAST, - SOUTHWEST, - WEST, - EAST, - NORTH, - SOUTH - ## Setup """ @@ -88,23 +76,6 @@ function classical_ising(; beta=log(1 + sqrt(2)) / 2, J=1.0) return TensorMap(o, TMS), TensorMap(m, TMS), TensorMap(e, TMS) end -""" -Contract a local rank-4 tensor with a given partition function environment. -""" -function local_contraction( - O::AbstractTensorMap{S,2,2}, env::CTMRGEnv{C,<:CTMRG_PF_EdgeTensor} -) where {S,C} - return @autoopt @tensor env.corners[NORTHWEST, 1, 1][C_WNW; C_NNW] * - env.edges[NORTH, 1, 1][C_NNW D_N; C_NNE] * - env.corners[NORTHEAST, 1, 1][C_NNE; C_ENE] * - env.edges[EAST, 1, 1][C_ENE D_E; C_ESE] * - env.corners[SOUTHEAST, 1, 1][C_ESE; C_SSE] * - env.edges[SOUTH, 1, 1][C_SSE D_S; C_SSW] * - env.corners[SOUTHWEST, 1, 1][C_SSW; C_WSW] * - env.edges[WEST, 1, 1][C_WSW D_W; C_WNW] * - O[D_W D_S; D_N D_E] -end - ## Test # initialize @@ -135,8 +106,8 @@ projector_algs = [HalfInfiniteProjector, FullInfiniteProjector] # check observables λ = value(Z, env) - m = local_contraction(M, env) / local_contraction(O, env) - e = local_contraction(E, env) / local_contraction(O, env) + m = expectation_value((1, 1) => M, Z, env) + e = expectation_value((1, 1) => E, Z, env) f_exact, m_exact, e_exact = classical_ising_exact(; beta) From a18824ca93ac00495fc0b22ff8f110fc89150639 Mon Sep 17 00:00:00 2001 From: Paul Brehmer Date: Thu, 9 Jan 2025 14:40:41 +0100 Subject: [PATCH 40/47] Fix small docstring typos --- .../contractions/ctmrg_contractions.jl | 5 +-- src/algorithms/toolbox.jl | 43 +++++++++---------- 2 files changed, 23 insertions(+), 25 deletions(-) diff --git a/src/algorithms/contractions/ctmrg_contractions.jl b/src/algorithms/contractions/ctmrg_contractions.jl index 3e228503..ce1c6c79 100644 --- a/src/algorithms/contractions/ctmrg_contractions.jl +++ b/src/algorithms/contractions/ctmrg_contractions.jl @@ -558,7 +558,7 @@ end half1::T, half2::T ) where {T<:AbstractTensorMap{<:ElementarySpace,2,2}} full_infinite_environment(C_1, C_2, C_3, C_4, E_1, E_2, E_3, E_4, E_5, E_6, E_7, E_8, - partfunc_1::P, partfunc_2::P) where {P<:PartitionFunctionTensor} + partfunc_1::P, partfunc_2::P, partfunc_3::P, partfunc_4::P) where {P<:PartitionFunctionTensor} full_infinite_environment(C_1, C_2, E_1, E_2, E_3, E_4, x, partfunc_1::P, partfunc_2::P, partfunc_3::P, partfunc_4::P) where {P<:PartitionFunctionTensor} full_infinite_environment(x, C_1, C_2, E_1, E_2, E_3, E_4, @@ -569,7 +569,7 @@ Contract four quadrants (enlarged corners) to form a full-infinite environment. ``` |~~~~~~~~~| -- |~~~~~~~~~| |quadrant1| |quadrant2| - |~~~~~~~~~| == |~~~~~~~~~| + |~~~~~~~~~| -- |~~~~~~~~~| | | | | | | | | | | @@ -614,7 +614,6 @@ Alternatively, contract the environment with a vector `x` acting on it E_1 -- A_1 -- A_2 -- E_4 | | | | | | - | | [~~~~x~~~] | | | | | | E_8 -- A_4 -- A_3 -- E_5 diff --git a/src/algorithms/toolbox.jl b/src/algorithms/toolbox.jl index 42e18a6d..e153209b 100644 --- a/src/algorithms/toolbox.jl +++ b/src/algorithms/toolbox.jl @@ -6,6 +6,26 @@ function MPSKit.expectation_value(peps::InfinitePEPS, O::LocalOperator, envs::CT end return sum(term_vals) end +function MPSKit.expectation_value( + inds::CartesianIndex{2}, + O::AbstractTensorMap{S,2,2}, + pf::InfinitePartitionFunction, + envs::CTMRGEnv, +) where {S} + return contract_local_tensor(inds, O, envs) / + contract_local_tensor(inds, pf[inds], envs) +end +function MPSKit.expectation_value( + inds::Tuple{Int,Int}, + O::AbstractTensorMap{S,2,2}, + pf::InfinitePartitionFunction, + envs::CTMRGEnv, +) where {S} + return expectation_value(CartesianIndex(inds), O, pf, envs) +end +function MPSKit.expectation_value(op::Pair, pf::InfinitePartitionFunction, envs::CTMRGEnv) + return expectation_value(op..., pf, envs) +end function costfun(peps::InfinitePEPS, envs::CTMRGEnv, O::LocalOperator) E = MPSKit.expectation_value(peps, O, envs) @@ -57,31 +77,10 @@ function LinearAlgebra.norm(peps::InfinitePEPS, env::CTMRGEnv) return total end -function MPSKit.expectation_value( - inds::CartesianIndex{2}, - O::AbstractTensorMap{S,2,2}, - pf::InfinitePartitionFunction, - envs::CTMRGEnv, -) where {S} - return contract_local_tensor(inds, O, envs) / - contract_local_tensor(inds, pf[inds], envs) -end -function MPSKit.expectation_value( - inds::Tuple{Int,Int}, - O::AbstractTensorMap{S,2,2}, - pf::InfinitePartitionFunction, - envs::CTMRGEnv, -) where {S} - return expectation_value(CartesianIndex(inds), O, pf, envs) -end -function MPSKit.expectation_value(op::Pair, pf::InfinitePartitionFunction, envs::CTMRGEnv) - return expectation_value(op..., pf, envs) -end - """ value(partfunc::InfinitePartitionFunction, env::CTMRGEnv) -Return the value (per site) of a given parition function contracted using a given CTMRG +Return the value (per site) of a given partition function contracted using a given CTMRG environment. """ function value(partfunc::InfinitePartitionFunction, env::CTMRGEnv) From fa63d44a3e80d6c8177081285fca76453d4e341e Mon Sep 17 00:00:00 2001 From: Paul Brehmer Date: Thu, 9 Jan 2025 16:35:10 +0100 Subject: [PATCH 41/47] Add InfiniteSquareNetwork supertype --- src/PEPSKit.jl | 1 + .../contractions/ctmrg_contractions.jl | 2 - src/operators/infinitepepo.jl | 23 +--- src/states/infinitepartitionfunction.jl | 93 +------------- src/states/infinitepeps.jl | 75 +----------- src/states/infinitesquarenetwork.jl | 113 ++++++++++++++++++ 6 files changed, 120 insertions(+), 187 deletions(-) create mode 100644 src/states/infinitesquarenetwork.jl diff --git a/src/PEPSKit.jl b/src/PEPSKit.jl index d689c97b..2e0142d1 100644 --- a/src/PEPSKit.jl +++ b/src/PEPSKit.jl @@ -24,6 +24,7 @@ include("utility/autoopt.jl") include("networks/tensors.jl") +include("states/infinitesquarenetwork.jl") include("states/infinitepeps.jl") include("states/infiniteweightpeps.jl") include("states/infinitepartitionfunction.jl") diff --git a/src/algorithms/contractions/ctmrg_contractions.jl b/src/algorithms/contractions/ctmrg_contractions.jl index ce1c6c79..08a405e9 100644 --- a/src/algorithms/contractions/ctmrg_contractions.jl +++ b/src/algorithms/contractions/ctmrg_contractions.jl @@ -1,5 +1,3 @@ -const InfiniteSquareNetwork = Union{InfinitePEPS,InfinitePartitionFunction} - const CTMRGEdgeTensor{S,N} = AbstractTensorMap{S,N,1} const CTMRG_PEPS_EdgeTensor{S} = CTMRGEdgeTensor{S,3} const CTMRG_PF_EdgeTensor{S} = CTMRGEdgeTensor{S,2} diff --git a/src/operators/infinitepepo.jl b/src/operators/infinitepepo.jl index 14e21e8a..3c4242d7 100644 --- a/src/operators/infinitepepo.jl +++ b/src/operators/infinitepepo.jl @@ -3,7 +3,7 @@ Represents an infinite projected entangled-pair operator (PEPO) on a 3D cubic lattice. """ -struct InfinitePEPO{T<:PEPOTensor} +struct InfinitePEPO{T<:PEPOTensor} <: InfiniteSquareNetwork{T,3} A::Array{T,3} function InfinitePEPO(A::Array{T,3}) where {T<:PEPOTensor} @@ -105,21 +105,7 @@ function InfinitePEPO( ) end -## Shape and size -Base.size(T::InfinitePEPO) = size(T.A) -Base.size(T::InfinitePEPO, i) = size(T.A, i) -Base.length(T::InfinitePEPO) = length(T.A) -Base.eltype(T::InfinitePEPO) = eltype(typeof(T)) -Base.eltype(::Type{<:InfinitePEPO{T}}) where {T} = T -VectorInterface.scalartype(::Type{T}) where {T<:InfinitePEPO} = scalartype(eltype(T)) - -## Copy -Base.copy(T::InfinitePEPO) = InfinitePEPO(copy(T.A)) -Base.similar(T::InfinitePEPO, args...) = InfinitePEPO(similar(T.A, args...)) -Base.repeat(T::InfinitePEPO, counts...) = InfinitePEPO(repeat(T.A, counts...)) - -Base.getindex(T::InfinitePEPO, args...) = Base.getindex(T.A, args...) -Base.axes(T::InfinitePEPO, args...) = axes(T.A, args...) +unitcell(T::InfinitePEPO) = T.A TensorKit.space(T::InfinitePEPO, i, j) = space(T[i, j, end], 1) function initializePEPS( @@ -134,8 +120,3 @@ function initializePEPS( Espaces = repeat([vspace], size(T, 1), size(T, 2)) return InfinitePEPS(Pspaces, Nspaces, Espaces) end - -# Rotations -Base.rotl90(T::InfinitePEPO) = InfinitePEPO(stack(rotl90, eachslice(T.A; dims=3))) -Base.rotr90(T::InfinitePEPO) = InfinitePEPO(stack(rotr90, eachslice(T.A; dims=3))) -Base.rot180(T::InfinitePEPO) = InfinitePEPO(stack(rot180, eachslice(T.A; dims=3))) diff --git a/src/states/infinitepartitionfunction.jl b/src/states/infinitepartitionfunction.jl index 3048d36d..f6b31fd0 100644 --- a/src/states/infinitepartitionfunction.jl +++ b/src/states/infinitepartitionfunction.jl @@ -3,7 +3,7 @@ Represents an infinite projected entangled-pair state on a 2D square lattice. """ -struct InfinitePartitionFunction{T<:PartitionFunctionTensor} +struct InfinitePartitionFunction{T<:PartitionFunctionTensor} <: InfiniteSquareNetwork{T,2} A::Matrix{T} function InfinitePartitionFunction{T}(A::Matrix{T}) where {T<:PartitionFunctionTensor} return new{T}(A) @@ -109,88 +109,9 @@ function InfinitePartitionFunction( return InfinitePartitionFunction(f, T, fill(Nspace, unitcell), fill(Espace, unitcell)) end -## Shape and size -Base.size(T::InfinitePartitionFunction) = size(T.A) -Base.size(T::InfinitePartitionFunction, i) = size(T.A, i) -Base.length(T::InfinitePartitionFunction) = length(T.A) -Base.eltype(T::InfinitePartitionFunction) = eltype(typeof(T)) -Base.eltype(::Type{<:InfinitePartitionFunction{T}}) where {T} = T -function VectorInterface.scalartype(::Type{T}) where {T<:InfinitePartitionFunction} - return scalartype(eltype(T)) -end - -## Copy -Base.copy(T::InfinitePartitionFunction) = InfinitePartitionFunction(copy(T.A)) -function Base.similar(T::InfinitePartitionFunction, args...) - return InfinitePartitionFunction(similar(T.A, args...)) -end -function Base.repeat(T::InfinitePartitionFunction, counts...) - return InfinitePartitionFunction(repeat(T.A, counts...)) -end - -Base.getindex(T::InfinitePartitionFunction, args...) = Base.getindex(T.A, args...) -Base.setindex!(T::InfinitePartitionFunction, args...) = (Base.setindex!(T.A, args...); T) -Base.axes(T::InfinitePartitionFunction, args...) = axes(T.A, args...) -function eachcoordinate(x::InfinitePartitionFunction) - return collect(Iterators.product(axes(x)...)) -end -function eachcoordinate(x::InfinitePartitionFunction, dirs) - return collect(Iterators.product(dirs, axes(x, 1), axes(x, 2))) -end +unitcell(t::InfinitePartitionFunction) = t.A TensorKit.space(t::InfinitePartitionFunction, i, j) = space(t[i, j], 1) -## Math -function Base.:+(ψ₁::InfinitePartitionFunction, ψ₂::InfinitePartitionFunction) - return InfinitePartitionFunction(ψ₁.A + ψ₂.A) -end -function Base.:-(ψ₁::InfinitePartitionFunction, ψ₂::InfinitePartitionFunction) - return InfinitePartitionFunction(ψ₁.A - ψ₂.A) -end -Base.:*(α::Number, ψ::InfinitePartitionFunction) = InfinitePartitionFunction(α * ψ.A) -Base.:/(ψ::InfinitePartitionFunction, α::Number) = InfinitePartitionFunction(ψ.A / α) -function LinearAlgebra.dot(ψ₁::InfinitePartitionFunction, ψ₂::InfinitePartitionFunction) - return dot(ψ₁.A, ψ₂.A) -end -LinearAlgebra.norm(ψ::InfinitePartitionFunction) = norm(ψ.A) - -## (Approximate) equality -function Base.:(==)(ψ₁::InfinitePartitionFunction, ψ₂::InfinitePartitionFunction) - return all(zip(ψ₁.A, ψ₂.A)) do (p₁, p₂) - return p₁ == p₂ - end -end -function Base.isapprox( - ψ₁::InfinitePartitionFunction, ψ₂::InfinitePartitionFunction; kwargs... -) - return all(zip(ψ₁.A, ψ₂.A)) do (p₁, p₂) - return isapprox(p₁, p₂; kwargs...) - end -end - -# Used in _scale during OptimKit.optimize -function LinearAlgebra.rmul!(ψ::InfinitePartitionFunction, α::Number) - rmul!.(ψ.A, α) - return ψ -end - -# Used in _add during OptimKit.optimize -function LinearAlgebra.axpy!( - α::Number, ψ₁::InfinitePartitionFunction, ψ₂::InfinitePartitionFunction -) - axpy!.(α, ψ₁.A, ψ₂.A) - return ψ₂ -end - -# VectorInterface -function VectorInterface.zerovector(x::InfinitePartitionFunction) - return InfinitePartitionFunction(zerovector(x.A)) -end - -# Rotations -Base.rotl90(t::InfinitePartitionFunction) = InfinitePartitionFunction(rotl90(rotl90.(t.A))) -Base.rotr90(t::InfinitePartitionFunction) = InfinitePartitionFunction(rotr90(rotr90.(t.A))) -Base.rot180(t::InfinitePartitionFunction) = InfinitePartitionFunction(rot180(rot180.(t.A))) - # Chainrules function ChainRulesCore.rrule( ::typeof(Base.getindex), state::InfinitePartitionFunction, row::Int, col::Int @@ -230,13 +151,3 @@ function ChainRulesCore.rrule(::typeof(rotr90), peps::InfinitePartitionFunction) end return peps′, rotr90_pullback end - -# FiniteDifferences -# Makes use of tensors already having a to_vec method -function FiniteDifferences.to_vec(state::InfinitePartitionFunction) - vec, back = FiniteDifferences.to_vec(state.A) - function state_from_vec(vec) - return InfinitePartitionFunction(back(vec)) - end - return vec, state_from_vec -end diff --git a/src/states/infinitepeps.jl b/src/states/infinitepeps.jl index 12cbdbb1..29409014 100644 --- a/src/states/infinitepeps.jl +++ b/src/states/infinitepeps.jl @@ -3,7 +3,7 @@ Represents an infinite projected entangled-pair state on a 2D square lattice. """ -struct InfinitePEPS{T<:PEPSTensor} +struct InfinitePEPS{T<:PEPSTensor} <: InfiniteSquareNetwork{T,2} A::Matrix{T} InfinitePEPS{T}(A::Matrix{T}) where {T<:PEPSTensor} = new{T}(A) function InfinitePEPS(A::Array{T,2}) where {T<:PEPSTensor} @@ -109,70 +109,9 @@ function InfinitePEPS( ) end -## Shape and size -Base.size(T::InfinitePEPS) = size(T.A) -Base.size(T::InfinitePEPS, i) = size(T.A, i) -Base.length(T::InfinitePEPS) = length(T.A) -Base.eltype(T::InfinitePEPS) = eltype(typeof(T)) -Base.eltype(::Type{<:InfinitePEPS{T}}) where {T} = T -VectorInterface.scalartype(::Type{T}) where {T<:InfinitePEPS} = scalartype(eltype(T)) - -## Copy -Base.copy(T::InfinitePEPS) = InfinitePEPS(copy(T.A)) -Base.similar(T::InfinitePEPS, args...) = InfinitePEPS(similar(T.A, args...)) -Base.repeat(T::InfinitePEPS, counts...) = InfinitePEPS(repeat(T.A, counts...)) - -Base.getindex(T::InfinitePEPS, args...) = Base.getindex(T.A, args...) -Base.setindex!(T::InfinitePEPS, args...) = (Base.setindex!(T.A, args...); T) -Base.axes(T::InfinitePEPS, args...) = axes(T.A, args...) -function eachcoordinate(x::InfinitePEPS) - return collect(Iterators.product(axes(x)...)) -end -function eachcoordinate(x::InfinitePEPS, dirs) - return collect(Iterators.product(dirs, axes(x, 1), axes(x, 2))) -end +unitcell(t::InfinitePEPS) = t.A TensorKit.space(t::InfinitePEPS, i, j) = space(t[i, j], 1) -## Math -Base.:+(ψ₁::InfinitePEPS, ψ₂::InfinitePEPS) = InfinitePEPS(ψ₁.A + ψ₂.A) -Base.:-(ψ₁::InfinitePEPS, ψ₂::InfinitePEPS) = InfinitePEPS(ψ₁.A - ψ₂.A) -Base.:*(α::Number, ψ::InfinitePEPS) = InfinitePEPS(α * ψ.A) -Base.:/(ψ::InfinitePEPS, α::Number) = InfinitePEPS(ψ.A / α) -LinearAlgebra.dot(ψ₁::InfinitePEPS, ψ₂::InfinitePEPS) = dot(ψ₁.A, ψ₂.A) -LinearAlgebra.norm(ψ::InfinitePEPS) = norm(ψ.A) - -## (Approximate) equality -function Base.:(==)(ψ₁::InfinitePEPS, ψ₂::InfinitePEPS) - return all(zip(ψ₁.A, ψ₂.A)) do (p₁, p₂) - return p₁ == p₂ - end -end -function Base.isapprox(ψ₁::InfinitePEPS, ψ₂::InfinitePEPS; kwargs...) - return all(zip(ψ₁.A, ψ₂.A)) do (p₁, p₂) - return isapprox(p₁, p₂; kwargs...) - end -end - -# Used in _scale during OptimKit.optimize -function LinearAlgebra.rmul!(ψ::InfinitePEPS, α::Number) - rmul!.(ψ.A, α) - return ψ -end - -# Used in _add during OptimKit.optimize -function LinearAlgebra.axpy!(α::Number, ψ₁::InfinitePEPS, ψ₂::InfinitePEPS) - axpy!.(α, ψ₁.A, ψ₂.A) - return ψ₂ -end - -# VectorInterface -VectorInterface.zerovector(x::InfinitePEPS) = InfinitePEPS(zerovector(x.A)) - -# Rotations -Base.rotl90(t::InfinitePEPS) = InfinitePEPS(rotl90(rotl90.(t.A))) -Base.rotr90(t::InfinitePEPS) = InfinitePEPS(rotr90(rotr90.(t.A))) -Base.rot180(t::InfinitePEPS) = InfinitePEPS(rot180(rot180.(t.A))) - # Chainrules function ChainRulesCore.rrule( ::typeof(Base.getindex), state::InfinitePEPS, row::Int, col::Int @@ -210,13 +149,3 @@ function ChainRulesCore.rrule(::typeof(rotr90), peps::InfinitePEPS) end return peps′, rotr90_pullback end - -# FiniteDifferences -# Makes use of tensors already having a to_vec method -function FiniteDifferences.to_vec(state::InfinitePEPS) - vec, back = FiniteDifferences.to_vec(state.A) - function state_from_vec(vec) - return InfinitePEPS(back(vec)) - end - return vec, state_from_vec -end diff --git a/src/states/infinitesquarenetwork.jl b/src/states/infinitesquarenetwork.jl new file mode 100644 index 00000000..85fd5f16 --- /dev/null +++ b/src/states/infinitesquarenetwork.jl @@ -0,0 +1,113 @@ +""" + InfiniteSquareNetwork{T,N} + +Abstract infinite tensor network consisting of a translationally invariant unit cell +on a square lattice. +""" +abstract type InfiniteSquareNetwork{T,N} end + +## Shape and size +function unitcell(::InfiniteSquareNetwork) end # Return array of constituent tensors +Base.size(A::InfiniteSquareNetwork, args...) = size(unitcell(A), args...) +Base.length(A::InfiniteSquareNetwork) = length(unitcell(A)) +Base.eltype(::Type{<:InfiniteSquareNetwork{T}}) where {T} = T +Base.eltype(A::InfiniteSquareNetwork) = eltype(typeof(A)) + +## Copy +Base.copy(A::NWType) where {NWType<:InfiniteSquareNetwork} = NWType(copy(unitcell(A))) +function Base.similar(A::NWType, args...) where {NWType<:InfiniteSquareNetwork} + return NWType(similar(unitcell(A), args...)) +end +function Base.repeat(A::NWType, counts...) where {NWType<:InfiniteSquareNetwork} + return NWType(repeat(unitcell(A), counts...)) +end + +## Indexing +Base.getindex(A::InfiniteSquareNetwork, args...) = Base.getindex(unitcell(A), args...) +function Base.setindex!(A::InfiniteSquareNetwork, args...) + return (Base.setindex!(unitcell(A), args...); A) +end +Base.axes(A::InfiniteSquareNetwork, args...) = axes(unitcell(A), args...) +function eachcoordinate(A::InfiniteSquareNetwork) + return collect(Iterators.product(axes(A)...)) +end +function eachcoordinate(A::InfiniteSquareNetwork, dirs) + return collect(Iterators.product(dirs, axes(A, 1), axes(A, 2))) +end + +## Vector interface +function VectorInterface.scalartype(::Type{NWType}) where {NWType<:InfiniteSquareNetwork} + return scalartype(eltype(NWType)) +end +function VectorInterface.zerovector(A::NWType) where {NWType<:InfiniteSquareNetwork} + return NWType(zerovector(unitcell(A))) +end + +## Math +function Base.:+(A₁::NWType, A₂::NWType) where {NWType<:InfiniteSquareNetwork} + return NWType(unitcell(A₁) + unitcell(A₂)) +end +function Base.:-(A₁::NWType, A₂::NWType) where {NWType<:InfiniteSquareNetwork} + return NWType(unitcell(A₁) - unitcell(A₂)) +end +function Base.:*(α::Number, A::NWType) where {NWType<:InfiniteSquareNetwork} + return NWType(α * unitcell(A)) +end +Base.:/(A::NWType, α::Number) where {NWType<:InfiniteSquareNetwork} = NWType(A / α) +function LinearAlgebra.dot(A₁::InfiniteSquareNetwork, A₂::InfiniteSquareNetwork) + return dot(unitcell(A₁), unitcell(A₂)) +end +LinearAlgebra.norm(A::InfiniteSquareNetwork) = norm(unitcell(A)) + +## (Approximate) equality +function Base.:(==)(A₁::InfiniteSquareNetwork, A₂::InfiniteSquareNetwork) + return all(zip(unitcell(A₁), unitcell(A₂))) do (p₁, p₂) + return p₁ == p₂ + end +end +function Base.isapprox(A₁::InfiniteSquareNetwork, A₂::InfiniteSquareNetwork; kwargs...) + return all(zip(unitcell(A₁), unitcell(A₂))) do (p₁, p₂) + return isapprox(p₁, p₂; kwargs...) + end +end + +## Rotations +function Base.rotl90(A::NWType) where {NWType<:InfiniteSquareNetwork{<:Any,2}} # Rotations of matrix unit cells + return NWType(rotl90(rotl90.(unitcell(A)))) +end +function Base.rotr90(A::NWType) where {NWType<:InfiniteSquareNetwork{<:Any,2}} + return NWType(rotr90(rotr90.(unitcell(A)))) +end +function Base.rot180(A::NWType) where {NWType<:InfiniteSquareNetwork{<:Any,2}} + return NWType(rot180(rot180.(unitcell(A)))) +end +function Base.rotl90(A::NWType) where {NWType<:InfiniteSquareNetwork{<:Any,3}} # Rotations of cubic unit cells along z-axis + return NWType(stack(rotl90, eachslice(unitcell(A); dims=3))) +end +function Base.rotr90(A::NWType) where {NWType<:InfiniteSquareNetwork{<:Any,3}} + return NWType(stack(rotr90, eachslice(unitcell(A); dims=3))) +end +function Base.rot180(A::NWType) where {NWType<:InfiniteSquareNetwork{<:Any,3}} + return NWType(stack(rot180, eachslice(unitcell(A); dims=3))) +end + +## OptimKit optimization compatibility +function LinearAlgebra.rmul!(A::InfiniteSquareNetwork, α::Number) # Used in _scale during OptimKit.optimize + rmul!.(unitcell(A), α) + return A +end +function LinearAlgebra.axpy!( + α::Number, A₁::InfiniteSquareNetwork, A₂::InfiniteSquareNetwork +) # Used in _add during OptimKit.optimize + axpy!.(α, unitcell(A₁), unitcell(A₂)) + return A₂ +end + +## FiniteDifferences vectorization +function FiniteDifferences.to_vec(A::NWType) where {NWType<:InfiniteSquareNetwork} + vec, back = FiniteDifferences.to_vec(unitcell(A)) + function state_from_vec(vec) + return NWType(back(vec)) + end + return vec, state_from_vec +end From 2b7e6007112d711983dab6a68b1b5f2c3af77f72 Mon Sep 17 00:00:00 2001 From: leburgel Date: Fri, 10 Jan 2025 08:59:09 +0100 Subject: [PATCH 42/47] Fix division --- src/states/infinitesquarenetwork.jl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/states/infinitesquarenetwork.jl b/src/states/infinitesquarenetwork.jl index 85fd5f16..539fdab7 100644 --- a/src/states/infinitesquarenetwork.jl +++ b/src/states/infinitesquarenetwork.jl @@ -53,7 +53,9 @@ end function Base.:*(α::Number, A::NWType) where {NWType<:InfiniteSquareNetwork} return NWType(α * unitcell(A)) end -Base.:/(A::NWType, α::Number) where {NWType<:InfiniteSquareNetwork} = NWType(A / α) +function Base.:/(A::NWType, α::Number) where {NWType<:InfiniteSquareNetwork} + return NWType(unitcell(A) / α) +end function LinearAlgebra.dot(A₁::InfiniteSquareNetwork, A₂::InfiniteSquareNetwork) return dot(unitcell(A₁), unitcell(A₂)) end From 7452dd3420ae113fbd4c79f4713387391087e3d9 Mon Sep 17 00:00:00 2001 From: leburgel Date: Fri, 10 Jan 2025 09:02:49 +0100 Subject: [PATCH 43/47] Move `infinitesquarenetwork.jl` to dedicated folder --- src/PEPSKit.jl | 2 +- src/{states => networks}/infinitesquarenetwork.jl | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename src/{states => networks}/infinitesquarenetwork.jl (100%) diff --git a/src/PEPSKit.jl b/src/PEPSKit.jl index 2e0142d1..2bb905b6 100644 --- a/src/PEPSKit.jl +++ b/src/PEPSKit.jl @@ -23,8 +23,8 @@ include("utility/hook_pullback.jl") include("utility/autoopt.jl") include("networks/tensors.jl") +include("networks/infinitesquarenetwork.jl") -include("states/infinitesquarenetwork.jl") include("states/infinitepeps.jl") include("states/infiniteweightpeps.jl") include("states/infinitepartitionfunction.jl") diff --git a/src/states/infinitesquarenetwork.jl b/src/networks/infinitesquarenetwork.jl similarity index 100% rename from src/states/infinitesquarenetwork.jl rename to src/networks/infinitesquarenetwork.jl From 77a60bce5ae10bbcb91052854a351355da49c5e3 Mon Sep 17 00:00:00 2001 From: Paul Brehmer Date: Fri, 10 Jan 2025 18:19:58 +0100 Subject: [PATCH 44/47] Add contract_local_tensor for plaquette tensors and matrices of tensors --- src/algorithms/contractions/localoperator.jl | 220 ++++++++++++++++--- src/algorithms/ctmrg/sparse_environments.jl | 1 + src/algorithms/toolbox.jl | 25 ++- test/ctmrg/partition_function.jl | 4 +- 4 files changed, 201 insertions(+), 49 deletions(-) diff --git a/src/algorithms/contractions/localoperator.jl b/src/algorithms/contractions/localoperator.jl index aaa2cf71..be71e28c 100644 --- a/src/algorithms/contractions/localoperator.jl +++ b/src/algorithms/contractions/localoperator.jl @@ -9,11 +9,11 @@ function MPSKit.tensorexpr(ex::Expr, indout, indin) end """ - contract_localoperator(inds, O, peps, env) + contract_local_operator(inds, O, peps, env) Contract a local operator `O` on the PEPS `peps` at the indices `inds` using the environment `env`. """ -function contract_localoperator( +function contract_local_operator( inds::NTuple{N,CartesianIndex{2}}, O::AbstractTensorMap{S,N,N}, ket::InfinitePEPS, @@ -21,21 +21,21 @@ function contract_localoperator( env::CTMRGEnv, ) where {S,N} static_inds = Val.(inds) - return _contract_localoperator(static_inds, O, ket, bra, env) + return _contract_local_operator(static_inds, O, ket, bra, env) end -function contract_localoperator( +function contract_local_operator( inds::NTuple{N,Tuple{Int,Int}}, O::AbstractTensorMap{S,N,N}, ket::InfinitePEPS, bra::InfinitePEPS, env::CTMRGEnv, ) where {S,N} - return contract_localoperator(CartesianIndex.(inds), O, ket, bra, env) + return contract_local_operator(CartesianIndex.(inds), O, ket, bra, env) end # This implements the contraction of an operator acting on sites `inds`. # The generated function ensures that we can use @tensor to write dynamic contractions (and maximize performance). -@generated function _contract_localoperator( +@generated function _contract_local_operator( inds::NTuple{N,Val}, O::AbstractTensorMap{S,N,N}, ket::InfinitePEPS, @@ -244,22 +244,22 @@ end end """ - contract_localnorm(inds, peps, env) + contract_local_norm(inds, peps, env) Contract a local norm of the PEPS `peps` around indices `inds`. """ -function contract_localnorm( +function contract_local_norm( inds::NTuple{N,CartesianIndex{2}}, ket::InfinitePEPS, bra::InfinitePEPS, env::CTMRGEnv ) where {N} static_inds = Val.(inds) - return _contract_localnorm(static_inds, ket, bra, env) + return _contract_local_norm(static_inds, ket, bra, env) end -function contract_localnorm( +function contract_local_norm( inds::NTuple{N,Tuple{Int,Int}}, ket::InfinitePEPS, bra::InfinitePEPS, env::CTMRGEnv ) where {N} - return contract_localnorm(CartesianIndex.(inds), ket, bra, env) + return contract_local_norm(CartesianIndex.(inds), ket, bra, env) end -@generated function _contract_localnorm( +@generated function _contract_local_norm( inds::NTuple{N,Val}, ket::InfinitePEPS, bra::InfinitePEPS, env::CTMRGEnv ) where {N} cartesian_inds = collect(CartesianIndex{2}, map(x -> x.parameters[1], inds.parameters)) # weird hack to extract information from Val @@ -358,7 +358,7 @@ end ]), ( (i == gridsize[1] ? :C_SW_2 : Symbol(:E_W_virtual, i)), - Symbol(:E_W_top, i), + Symbol(:E_W_top, i), # Is this index labeling correct? Symbol(:E_W_bot, i), ), ((i == 1 ? :C_NW_1 : Symbol(:E_W_virtual, i - 1)),), @@ -461,31 +461,181 @@ Contract a local tensor `O` inserted into a partition function `pf` at position using the environment `env`. """ function contract_local_tensor( - inds::Tuple{Int,Int}, - O::AbstractTensorMap{S,2,2}, + inds::NTuple{N,CartesianIndex{2}}, + O::Union{AbstractTensorMap{S,M,M},Matrix{<:AbstractTensorMap{S,2,2}}}, env::CTMRGEnv{C,<:CTMRG_PF_EdgeTensor}, -) where {S,C} - r, c = inds - return @autoopt @tensor env.corners[NORTHWEST, _prev(r, end), _prev(c, end)][ - χ_WNW - χ_NNW - ] * - env.edges[NORTH, _prev(r, end), c][χ_NNW D_N; χ_NNE] * - env.corners[NORTHEAST, _prev(r, end), _next(c, end)][χ_NNE; χ_ENE] * - env.edges[EAST, r, _next(c, end)][χ_ENE D_E; χ_ESE] * - env.corners[SOUTHEAST, _next(r, end), _next(c, end)][χ_ESE; χ_SSE] * - env.edges[SOUTH, _next(r, end), c][χ_SSE D_S; χ_SSW] * - env.corners[SOUTHWEST, _next(r, end), _prev(c, end)][χ_SSW; χ_WSW] * - env.edges[WEST, r, _prev(c, end)][χ_WSW D_W; χ_WNW] * - O[D_W D_S; D_N D_E] +) where {N,S,M,C} + static_inds = Val.(inds) + return _contract_local_tensor(static_inds, O, env) end function contract_local_tensor( - inds::CartesianIndex{2}, - O::AbstractTensorMap{S,2,2}, + inds::NTuple{N,Tuple{Int,Int}}, + O::Union{AbstractTensorMap{S,M,M},Matrix{<:AbstractTensorMap{S,2,2}}}, env::CTMRGEnv{C,<:CTMRG_PF_EdgeTensor}, -) where {S,C} - return contract_local_tensor(Tuple(inds), O, env) +) where {N,S,M,C} + return contract_local_tensor(CartesianIndex.(inds), O, env) end -function contract_local_tensor(op::Pair, env::CTMRGEnv{C,<:CTMRG_PF_EdgeTensor}) where {C} - return contract_local_tensor(op..., env) +@generated function _contract_local_tensor( + inds::NTuple{N,Val}, + O::Union{AbstractTensorMap{S,M,M},Matrix{<:AbstractTensorMap{S,2,2}}}, + env::CTMRGEnv{C,<:CTMRG_PF_EdgeTensor}, +) where {N,S,M,C} + cartesian_inds = collect(CartesianIndex{2}, map(x -> x.parameters[1], inds.parameters)) # weird hack to extract information from Val + if !allunique(cartesian_inds) + throw(ArgumentError("Indices should not overlap: $cartesian_inds.")) + end + + rmin, rmax = extrema(getindex.(cartesian_inds, 1)) + cmin, cmax = extrema(getindex.(cartesian_inds, 2)) + + gridsize = (rmax - rmin + 1, cmax - cmin + 1) + + corner_NW = tensorexpr( + :(env.corners[ + NORTHWEST, mod1($(rmin - 1), size(env, 2)), mod1($(cmin - 1), size(env, 3)) + ]), + (:χ_C_NW_1,), + (:χ_C_NW_2,), + ) + corner_NE = tensorexpr( + :(env.corners[ + NORTHEAST, mod1($(rmin - 1), size(env, 2)), mod1($(cmax + 1), size(env, 3)) + ]), + (:χ_C_NE_1,), + (:χ_C_NE_2,), + ) + corner_SE = tensorexpr( + :(env.corners[ + SOUTHEAST, mod1($(rmax + 1), size(env, 2)), mod1($(cmax + 1), size(env, 3)) + ]), + (:χ_C_SE_1,), + (:χ_C_SE_2,), + ) + corner_SW = tensorexpr( + :(env.corners[ + SOUTHWEST, mod1($(rmax + 1), size(env, 2)), mod1($(cmin - 1), size(env, 3)) + ]), + (:χ_C_SW_1,), + (:χ_C_SW_2,), + ) + + edges_N = map(1:gridsize[2]) do i + return tensorexpr( + :(env.edges[ + NORTH, + mod1($(rmin - 1), size(env, 2)), + mod1($(cmin + i - 1), size(env, 3)), + ]), + ((i == 1 ? :χ_C_NW_2 : Symbol(:χ_E_N, i - 1)), Symbol(:D_E_N, i)), + ((i == gridsize[2] ? :χ_C_NE_1 : Symbol(:χ_E_N, i)),), + ) + end + edges_E = map(1:gridsize[1]) do i + return tensorexpr( + :(env.edges[ + EAST, + mod1($(rmin + i - 1), size(env, 2)), + mod1($(cmax + 1), size(env, 3)), + ]), + ((i == 1 ? :χ_C_NE_2 : Symbol(:χ_E_E, i - 1)), Symbol(:D_E_E, i)), + ((i == gridsize[1] ? :χ_C_SE_1 : Symbol(:χ_E_E, i)),), + ) + end + edges_S = map(1:gridsize[2]) do i + return tensorexpr( + :(env.edges[ + SOUTH, + mod1($(rmax + 1), size(env, 2)), + mod1($(cmin + i - 1), size(env, 3)), + ]), + ((i == gridsize[2] ? :χ_C_SE_2 : Symbol(:χ_E_S, i)), Symbol(:D_E_S, i)), + ((i == 1 ? :χ_C_SW_1 : Symbol(:χ_E_S, i - 1)),), + ) + end + edges_W = map(1:gridsize[1]) do i + return tensorexpr( + :(env.edges[ + WEST, + mod1($(rmin + i - 1), size(env, 2)), + mod1($(cmin - 1), size(env, 3)), + ]), + ((i == gridsize[1] ? :χ_C_SW_2 : Symbol(:χ_E_W, i)), Symbol(:D_E_W, i)), + ((i == 1 ? :χ_C_NW_1 : Symbol(:χ_E_W, i - 1)),), + ) + end + + tensor = if O <: Matrix + map(Iterators.product(1:gridsize[1], 1:gridsize[2])) do (i, j) + tensorexpr( + :(O[ + mod1($(rmin + i - 1), size(env, 2)), + mod1($(cmin + j - 1), size(env, 3)), + ]), + ( + ( + if i == gridsize[1] + Symbol(:D_E_S, j) + else + Symbol(:D_op_vertical, i, "_", j) + end + ), + ( + if j == 1 + Symbol(:D_E_W, i) + else + Symbol(:D_op_horizontal, i, "_", j - 1) + end + ), + ), + ( + ( + if i == 1 + Symbol(:D_E_N, j) + else + Symbol(:D_op_vertical, i - 1, "_", j) + end + ), + ( + if j == gridsize[2] + Symbol(:D_E_E, i) + else + Symbol(:D_op_horizontal, i, "_", j) + end + ), + ), + ) + end + else + expr = tensorexpr( + :O, + ( + ntuple(i -> Symbol(:D_E_S, i), gridsize[2])..., + ntuple(i -> Symbol(:D_E_W, i), gridsize[1])..., + ), + ( + ntuple(i -> Symbol(:D_E_N, i), gridsize[2])..., + ntuple(i -> Symbol(:D_E_E, i), gridsize[1])..., + ), + ) + [expr] + end + + multiplication_ex = Expr( + :call, + :*, + corner_NW, + corner_NE, + corner_SE, + corner_SW, + edges_N..., + edges_E..., + edges_S..., + edges_W..., + tensor..., + ) + + returnex = quote + @autoopt @tensor opt = $multiplication_ex + end + return macroexpand(@__MODULE__, returnex) end diff --git a/src/algorithms/ctmrg/sparse_environments.jl b/src/algorithms/ctmrg/sparse_environments.jl index 7ea131de..ce243333 100644 --- a/src/algorithms/ctmrg/sparse_environments.jl +++ b/src/algorithms/ctmrg/sparse_environments.jl @@ -204,6 +204,7 @@ end # ----------------------------------------------------- # AbstractTensorMap subtyping and IterSVD compatibility +# ----------------------------------------------------- function _domain_space(A::NTuple{2,<:PEPSTensor}, n::Int) return domain(A[1])[n] * domain(A[2])[n]' diff --git a/src/algorithms/toolbox.jl b/src/algorithms/toolbox.jl index e153209b..f32e0f0a 100644 --- a/src/algorithms/toolbox.jl +++ b/src/algorithms/toolbox.jl @@ -1,29 +1,30 @@ function MPSKit.expectation_value(peps::InfinitePEPS, O::LocalOperator, envs::CTMRGEnv) checklattice(peps, O) term_vals = dtmap([O.terms...]) do (inds, operator) # OhMyThreads can't iterate over O.terms directly - contract_localoperator(inds, operator, peps, peps, envs) / - contract_localnorm(inds, peps, peps, envs) + contract_local_operator(inds, operator, peps, peps, envs) / + contract_local_norm(inds, peps, peps, envs) end return sum(term_vals) end function MPSKit.expectation_value( - inds::CartesianIndex{2}, - O::AbstractTensorMap{S,2,2}, + inds::NTuple{N,CartesianIndex{2}}, + O::Union{AbstractTensorMap{S,M,M},Matrix{<:AbstractTensorMap{S,2,2}}}, pf::InfinitePartitionFunction, envs::CTMRGEnv, -) where {S} - return contract_local_tensor(inds, O, envs) / - contract_local_tensor(inds, pf[inds], envs) +) where {N,S,M} + return contract_local_tensor(inds, O, envs) / contract_local_tensor(inds, pf.A, envs) end function MPSKit.expectation_value( - inds::Tuple{Int,Int}, - O::AbstractTensorMap{S,2,2}, + inds::NTuple{N,Tuple{Int,Int}}, + O::Union{AbstractTensorMap{S,M,M},Matrix{<:AbstractTensorMap{S,2,2}}}, pf::InfinitePartitionFunction, envs::CTMRGEnv, -) where {S} - return expectation_value(CartesianIndex(inds), O, pf, envs) +) where {N,S,M} + return expectation_value(CartesianIndex.(inds), O, pf, envs) end -function MPSKit.expectation_value(op::Pair, pf::InfinitePartitionFunction, envs::CTMRGEnv) +function MPSKit.expectation_value( + op::NTuple{N,<:Pair}, pf::InfinitePartitionFunction, envs::CTMRGEnv +) where {N} return expectation_value(op..., pf, envs) end diff --git a/test/ctmrg/partition_function.jl b/test/ctmrg/partition_function.jl index 8107d5e3..6b94586f 100644 --- a/test/ctmrg/partition_function.jl +++ b/test/ctmrg/partition_function.jl @@ -106,8 +106,8 @@ projector_algs = [HalfInfiniteProjector, FullInfiniteProjector] # check observables λ = value(Z, env) - m = expectation_value((1, 1) => M, Z, env) - e = expectation_value((1, 1) => E, Z, env) + m = expectation_value(((1, 1) => M), Z, env) + e = expectation_value(((1, 1) => E), Z, env) f_exact, m_exact, e_exact = classical_ising_exact(; beta) From e065897e735842a43c196e96b9ca82e0b9af190d Mon Sep 17 00:00:00 2001 From: Paul Brehmer Date: Fri, 10 Jan 2025 19:15:58 +0100 Subject: [PATCH 45/47] Fix partition_function.jl test --- Project.toml | 2 ++ src/algorithms/toolbox.jl | 6 ++---- test/ctmrg/partition_function.jl | 11 +++-------- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/Project.toml b/Project.toml index 882c3a57..9ab93be3 100644 --- a/Project.toml +++ b/Project.toml @@ -16,6 +16,7 @@ MPSKitModels = "ca635005-6f8c-4cd1-b51d-8491250ef2ab" OhMyThreads = "67456a42-1dca-4109-a031-0a68de7e3ad5" OptimKit = "77e91f04-9b3b-57a6-a776-40b61faaebe0" Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" +QuadGK = "1fd47b50-473d-5c70-9696-f719f8f3bcdc" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" TensorKit = "07d1fe3e-3e46-537d-9eac-e9e13d0d4cec" @@ -36,6 +37,7 @@ MPSKitModels = "0.3.5" OhMyThreads = "0.7" OptimKit = "0.3" Printf = "1" +QuadGK = "2.11.1" Random = "1" Statistics = "1" TensorKit = "0.12.5" diff --git a/src/algorithms/toolbox.jl b/src/algorithms/toolbox.jl index f32e0f0a..f8ad0e5b 100644 --- a/src/algorithms/toolbox.jl +++ b/src/algorithms/toolbox.jl @@ -22,10 +22,8 @@ function MPSKit.expectation_value( ) where {N,S,M} return expectation_value(CartesianIndex.(inds), O, pf, envs) end -function MPSKit.expectation_value( - op::NTuple{N,<:Pair}, pf::InfinitePartitionFunction, envs::CTMRGEnv -) where {N} - return expectation_value(op..., pf, envs) +function MPSKit.expectation_value(op::Pair, pf::InfinitePartitionFunction, envs::CTMRGEnv) + return expectation_value(first.(op), last.(op), pf, envs) end function costfun(peps::InfinitePEPS, envs::CTMRGEnv, O::LocalOperator) diff --git a/test/ctmrg/partition_function.jl b/test/ctmrg/partition_function.jl index 6b94586f..2bd16431 100644 --- a/test/ctmrg/partition_function.jl +++ b/test/ctmrg/partition_function.jl @@ -79,15 +79,12 @@ end ## Test # initialize - beta = 0.6 O, M, E = classical_ising(; beta) Z = InfinitePartitionFunction(O) - Random.seed!(81812781143) # contract - χenv = ℂ^12 env0 = CTMRGEnv(Z, χenv) @@ -100,15 +97,13 @@ projector_algs = [HalfInfiniteProjector, FullInfiniteProjector] ) in Iterators.product( ctm_styles, projector_algs ) - ctm_alg = ctm_style(; tol=1e-10, miniter=4, maxiter=100, verbosity=2, projector_alg) + ctm_alg = ctm_style(; maxiter=150, projector_alg) env = leading_boundary(env0, Z, ctm_alg) # check observables - λ = value(Z, env) - m = expectation_value(((1, 1) => M), Z, env) - e = expectation_value(((1, 1) => E), Z, env) - + m = expectation_value(((1, 1),) => M, Z, env) + e = expectation_value(((1, 1),) => E, Z, env) f_exact, m_exact, e_exact = classical_ising_exact(; beta) # should be real-ish From 959a23a758194a208b59aafef7c82aa4e03299e2 Mon Sep 17 00:00:00 2001 From: Paul Brehmer Date: Fri, 10 Jan 2025 19:55:29 +0100 Subject: [PATCH 46/47] Refactor contract_local_tensor --- Project.toml | 1 - src/algorithms/contractions/localoperator.jl | 236 ++++++++----------- 2 files changed, 100 insertions(+), 137 deletions(-) diff --git a/Project.toml b/Project.toml index 9ab93be3..8b9d043d 100644 --- a/Project.toml +++ b/Project.toml @@ -16,7 +16,6 @@ MPSKitModels = "ca635005-6f8c-4cd1-b51d-8491250ef2ab" OhMyThreads = "67456a42-1dca-4109-a031-0a68de7e3ad5" OptimKit = "77e91f04-9b3b-57a6-a776-40b61faaebe0" Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" -QuadGK = "1fd47b50-473d-5c70-9696-f719f8f3bcdc" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" TensorKit = "07d1fe3e-3e46-537d-9eac-e9e13d0d4cec" diff --git a/src/algorithms/contractions/localoperator.jl b/src/algorithms/contractions/localoperator.jl index feb665c0..fcfefbc5 100644 --- a/src/algorithms/contractions/localoperator.jl +++ b/src/algorithms/contractions/localoperator.jl @@ -122,6 +122,42 @@ function _contract_edge_expr(rowrange, colrange) return edges_N, edges_E, edges_S, edges_W end +function _contract_pf_edge_expr(rowrange, colrange) + rmin, rmax = extrema(rowrange) + cmin, cmax = extrema(colrange) + gridsize = (rmax - rmin + 1, cmax - cmin + 1) + + edges_N = map(1:gridsize[2]) do i + E_N = :(env.edges[NORTH, mod1($(rmin - 1), end), mod1($(cmin + i - 1), end)]) + return tensorexpr( + E_N, (envlabel(NORTH, i - 1), virtuallabel(NORTH, i)), envlabel(NORTH, i) + ) + end + + edges_E = map(1:gridsize[1]) do i + E_E = :(env.edges[EAST, mod1($(rmin + i - 1), end), mod1($(cmax + 1), end)]) + return tensorexpr( + E_E, (envlabel(EAST, i - 1), virtuallabel(EAST, i)), envlabel(EAST, i) + ) + end + + edges_S = map(1:gridsize[2]) do i + E_S = :(env.edges[SOUTH, mod1($(rmax + 1), end), mod1($(cmin + i - 1), end)]) + return tensorexpr( + E_S, (envlabel(SOUTH, i), virtuallabel(SOUTH, i)), envlabel(SOUTH, i - 1) + ) + end + + edges_W = map(1:gridsize[1]) do i + E_W = :(env.edges[WEST, mod1($(rmin + i - 1), end), mod1($(cmin - 1), end)]) + return tensorexpr( + E_W, (envlabel(WEST, i), virtuallabel(WEST, i)), envlabel(WEST, i - 1) + ) + end + + return edges_N, edges_E, edges_S, edges_W +end + function _contract_state_expr(rowrange, colrange, cartesian_inds=nothing) rmin, rmax = extrema(rowrange) cmin, cmax = extrema(colrange) @@ -169,6 +205,64 @@ function _contract_state_expr(rowrange, colrange, cartesian_inds=nothing) end end +function _contract_tensor_expr(O, rowrange, colrange) + rmin, rmax = extrema(rowrange) + cmin, cmax = extrema(colrange) + gridsize = (rmax - rmin + 1, cmax - cmin + 1) + if O <: Matrix + return map(Iterators.product(1:gridsize[1], 1:gridsize[2])) do (i, j) + tensorexpr( + :(O[mod1($(rmin + i - 1), end), mod1($(cmin + j - 1), end)]), + ( + ( + if i == gridsize[1] + virtuallabel(SOUTH, j) + else + virtuallabel(:vertical, i, j) + end + ), + ( + if j == 1 + virtuallabel(WEST, i) + else + virtuallabel(:horizontal, i, j - 1) + end + ), + ), + ( + ( + if i == 1 + virtuallabel(NORTH, j) + else + virtuallabel(:vertical, i - 1, j) + end + ), + ( + if j == gridsize[2] + virtuallabel(EAST, i) + else + virtuallabel(:horizontal, i, j) + end + ), + ), + ) + end + else + expr = tensorexpr( + :O, + ( + ntuple(i -> virtuallabel(SOUTH, i), gridsize[2])..., + ntuple(i -> virtuallabel(WEST, i), gridsize[1])..., + ), + ( + ntuple(i -> virtuallabel(NORTH, i), gridsize[2])..., + ntuple(i -> virtuallabel(EAST, i), gridsize[1])..., + ), + ) + return [expr] + end +end + @generated function _contract_local_operator( inds::NTuple{N,Val}, O::AbstractTensorMap{S,N,N}, @@ -292,144 +386,14 @@ end env::CTMRGEnv{C,<:CTMRG_PF_EdgeTensor}, ) where {N,S,M,C} cartesian_inds = collect(CartesianIndex{2}, map(x -> x.parameters[1], inds.parameters)) # weird hack to extract information from Val - if !allunique(cartesian_inds) + allunique(cartesian_inds) || throw(ArgumentError("Indices should not overlap: $cartesian_inds.")) - end - - rmin, rmax = extrema(getindex.(cartesian_inds, 1)) - cmin, cmax = extrema(getindex.(cartesian_inds, 2)) - - gridsize = (rmax - rmin + 1, cmax - cmin + 1) - - corner_NW = tensorexpr( - :(env.corners[ - NORTHWEST, mod1($(rmin - 1), size(env, 2)), mod1($(cmin - 1), size(env, 3)) - ]), - (:χ_C_NW_1,), - (:χ_C_NW_2,), - ) - corner_NE = tensorexpr( - :(env.corners[ - NORTHEAST, mod1($(rmin - 1), size(env, 2)), mod1($(cmax + 1), size(env, 3)) - ]), - (:χ_C_NE_1,), - (:χ_C_NE_2,), - ) - corner_SE = tensorexpr( - :(env.corners[ - SOUTHEAST, mod1($(rmax + 1), size(env, 2)), mod1($(cmax + 1), size(env, 3)) - ]), - (:χ_C_SE_1,), - (:χ_C_SE_2,), - ) - corner_SW = tensorexpr( - :(env.corners[ - SOUTHWEST, mod1($(rmax + 1), size(env, 2)), mod1($(cmin - 1), size(env, 3)) - ]), - (:χ_C_SW_1,), - (:χ_C_SW_2,), - ) - - edges_N = map(1:gridsize[2]) do i - return tensorexpr( - :(env.edges[ - NORTH, - mod1($(rmin - 1), size(env, 2)), - mod1($(cmin + i - 1), size(env, 3)), - ]), - ((i == 1 ? :χ_C_NW_2 : Symbol(:χ_E_N, i - 1)), Symbol(:D_E_N, i)), - ((i == gridsize[2] ? :χ_C_NE_1 : Symbol(:χ_E_N, i)),), - ) - end - edges_E = map(1:gridsize[1]) do i - return tensorexpr( - :(env.edges[ - EAST, - mod1($(rmin + i - 1), size(env, 2)), - mod1($(cmax + 1), size(env, 3)), - ]), - ((i == 1 ? :χ_C_NE_2 : Symbol(:χ_E_E, i - 1)), Symbol(:D_E_E, i)), - ((i == gridsize[1] ? :χ_C_SE_1 : Symbol(:χ_E_E, i)),), - ) - end - edges_S = map(1:gridsize[2]) do i - return tensorexpr( - :(env.edges[ - SOUTH, - mod1($(rmax + 1), size(env, 2)), - mod1($(cmin + i - 1), size(env, 3)), - ]), - ((i == gridsize[2] ? :χ_C_SE_2 : Symbol(:χ_E_S, i)), Symbol(:D_E_S, i)), - ((i == 1 ? :χ_C_SW_1 : Symbol(:χ_E_S, i - 1)),), - ) - end - edges_W = map(1:gridsize[1]) do i - return tensorexpr( - :(env.edges[ - WEST, - mod1($(rmin + i - 1), size(env, 2)), - mod1($(cmin - 1), size(env, 3)), - ]), - ((i == gridsize[1] ? :χ_C_SW_2 : Symbol(:χ_E_W, i)), Symbol(:D_E_W, i)), - ((i == 1 ? :χ_C_NW_1 : Symbol(:χ_E_W, i - 1)),), - ) - end + rowrange = getindex.(cartesian_inds, 1) + colrange = getindex.(cartesian_inds, 2) - tensor = if O <: Matrix - map(Iterators.product(1:gridsize[1], 1:gridsize[2])) do (i, j) - tensorexpr( - :(O[ - mod1($(rmin + i - 1), size(env, 2)), - mod1($(cmin + j - 1), size(env, 3)), - ]), - ( - ( - if i == gridsize[1] - Symbol(:D_E_S, j) - else - Symbol(:D_op_vertical, i, "_", j) - end - ), - ( - if j == 1 - Symbol(:D_E_W, i) - else - Symbol(:D_op_horizontal, i, "_", j - 1) - end - ), - ), - ( - ( - if i == 1 - Symbol(:D_E_N, j) - else - Symbol(:D_op_vertical, i - 1, "_", j) - end - ), - ( - if j == gridsize[2] - Symbol(:D_E_E, i) - else - Symbol(:D_op_horizontal, i, "_", j) - end - ), - ), - ) - end - else - expr = tensorexpr( - :O, - ( - ntuple(i -> Symbol(:D_E_S, i), gridsize[2])..., - ntuple(i -> Symbol(:D_E_W, i), gridsize[1])..., - ), - ( - ntuple(i -> Symbol(:D_E_N, i), gridsize[2])..., - ntuple(i -> Symbol(:D_E_E, i), gridsize[1])..., - ), - ) - [expr] - end + corner_NW, corner_NE, corner_SE, corner_SW = _contract_corner_expr(rowrange, colrange) + edges_N, edges_E, edges_S, edges_W = _contract_pf_edge_expr(rowrange, colrange) + tensor = _contract_tensor_expr(O, rowrange, colrange) multiplication_ex = Expr( :call, From fde495b6dbe57e0f873c8bb7b2a5aee133ad3fbc Mon Sep 17 00:00:00 2001 From: Paul Brehmer Date: Fri, 10 Jan 2025 20:04:32 +0100 Subject: [PATCH 47/47] Add operator index safeguard --- src/algorithms/toolbox.jl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/algorithms/toolbox.jl b/src/algorithms/toolbox.jl index f8ad0e5b..5ef0f465 100644 --- a/src/algorithms/toolbox.jl +++ b/src/algorithms/toolbox.jl @@ -12,6 +12,10 @@ function MPSKit.expectation_value( pf::InfinitePartitionFunction, envs::CTMRGEnv, ) where {N,S,M} + if O isa Matrix + (length(inds) != length(O)) && + throw(ArgumentError("Indices and tensor matrix must match")) + end return contract_local_tensor(inds, O, envs) / contract_local_tensor(inds, pf.A, envs) end function MPSKit.expectation_value(