From 88590b071162a6259cd66933c42501b5ec7c3127 Mon Sep 17 00:00:00 2001 From: sanderdemeyer Date: Fri, 6 Jun 2025 12:36:02 +0200 Subject: [PATCH 01/27] add anisotropic Simple Update --- src/algorithms/time_evolution/simpleupdate.jl | 16 +++++++++++----- test/examples/heisenberg.jl | 8 +++++++- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/algorithms/time_evolution/simpleupdate.jl b/src/algorithms/time_evolution/simpleupdate.jl index de75c323d..527fb05f5 100644 --- a/src/algorithms/time_evolution/simpleupdate.jl +++ b/src/algorithms/time_evolution/simpleupdate.jl @@ -12,10 +12,16 @@ struct SimpleUpdate dt::Float64 tol::Float64 maxiter::Int - trscheme::TensorKit.TruncationScheme + trschemes::NTuple{2,TensorKit.TruncationScheme} # truncation schemes for x and y bonds end # TODO: add kwarg constructor and SU Defaults +function SimpleUpdate( + dt::Float64, tol::Float64, maxiter::Int, trscheme::TensorKit.TruncationScheme +) + return SimpleUpdate(dt, tol, maxiter, (trscheme, trscheme)) +end + """ $(SIGNATURES) @@ -34,7 +40,7 @@ function _su_bondx!( col::Int, gate::AbstractTensorMap{T,S,2,2}, peps::InfiniteWeightPEPS, - alg::SimpleUpdate, + trscheme::TensorKit.TruncationScheme, ) where {T<:Number,S<:ElementarySpace} Nr, Nc = size(peps) @assert 1 <= row <= Nr && 1 <= col <= Nc @@ -47,7 +53,7 @@ function _su_bondx!( B = _absorb_weights(B, peps.weights, row, cp1, Tuple(1:4), sqrtsB, false) # apply gate X, a, b, Y = _qr_bond(A, B) - a, s, b, ϵ = _apply_gate(a, b, gate, alg.trscheme) + a, s, b, ϵ = _apply_gate(a, b, gate, trscheme) A, B = _qr_bond_undo(X, a, b, Y) # remove environment weights _allfalse = ntuple(Returns(false), 3) @@ -94,7 +100,7 @@ function su_iter( direction == 1 ? gate : gate_mirrored, (CartesianIndex(r, 1), CartesianIndex(r, 2)), ) - ϵ = _su_bondx!(r, 1, term, peps2, alg) + ϵ = _su_bondx!(r, 1, term, peps2, alg.trschemes[direction]) peps2.vertices[rp1, 2] = deepcopy(peps2.vertices[r, 1]) peps2.vertices[rp1, 1] = deepcopy(peps2.vertices[r, 2]) peps2.weights[1, rp1, 2] = deepcopy(peps2.weights[1, r, 1]) @@ -106,7 +112,7 @@ function su_iter( direction == 1 ? gate : gate_mirrored, (CartesianIndex(r, c), CartesianIndex(r, c + 1)), ) - ϵ = _su_bondx!(r, c, term, peps2, alg) + ϵ = _su_bondx!(r, c, term, peps2, alg.trschemes[direction]) end end if direction == 2 diff --git a/test/examples/heisenberg.jl b/test/examples/heisenberg.jl index 262ba8b28..a8821639b 100644 --- a/test/examples/heisenberg.jl +++ b/test/examples/heisenberg.jl @@ -71,7 +71,13 @@ end maxiter = 5000 for (n, (dt, tol)) in enumerate(zip(dts, tols)) Dbond2 = (n == 2) ? Dbond + 2 : Dbond - trscheme = truncerr(1e-10) & truncdim(Dbond2) + if n == 3 + trscheme = ( + truncerr(1e-10) & truncdim(Dbond2), truncerr(1e-10) & truncdim(Dbond2 + 1) + ) + else + trscheme = truncerr(tol) & truncdim(Dbond2) + end alg = SimpleUpdate(dt, tol, maxiter, trscheme) result = simpleupdate(wpeps, ham, alg; bipartite=false) wpeps = result[1] From e2eeb6660645271ae8922bc659aa9ad66249536f Mon Sep 17 00:00:00 2001 From: sanderdemeyer Date: Fri, 6 Jun 2025 13:25:54 +0200 Subject: [PATCH 02/27] fix 3site su --- src/algorithms/time_evolution/simpleupdate3site.jl | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/algorithms/time_evolution/simpleupdate3site.jl b/src/algorithms/time_evolution/simpleupdate3site.jl index 678ac69a0..c1081c86e 100644 --- a/src/algorithms/time_evolution/simpleupdate3site.jl +++ b/src/algorithms/time_evolution/simpleupdate3site.jl @@ -373,7 +373,11 @@ function get_3site_se(peps::InfiniteWeightPEPS, row::Int, col::Int) end function _su3site_se!( - row::Int, col::Int, gs::Vector{T}, peps::InfiniteWeightPEPS, alg::SimpleUpdate + row::Int, + col::Int, + gs::Vector{T}, + peps::InfiniteWeightPEPS, + trscheme::TensorKit.TruncationScheme, ) where {T<:AbstractTensorMap} Nr, Nc = size(peps) @assert 1 <= row <= Nr && 1 <= col <= Nc @@ -384,7 +388,7 @@ function _su3site_se!( coords = ((row, col), (row, cp1), (rm1, cp1)) # weights in the cluster wt_idxs = ((1, row, col), (2, row, cp1)) - wts, ϵ = apply_gatempo!(Ms, gs; trunc=alg.trscheme) + wts, ϵ = apply_gatempo!(Ms, gs; trunc=trscheme) for (wt, wt_idx) in zip(wts, wt_idxs) peps.weights[CartesianIndex(wt_idx)] = wt / norm(wt, Inf) end @@ -418,7 +422,7 @@ function su3site_iter( for site in CartesianIndices(peps2.vertices) r, c = site[1], site[2] gs = gatempos[i][r, c] - _su3site_se!(r, c, gs, peps2, alg) + _su3site_se!(r, c, gs, peps2, alg.trschemes[i]) end peps2 = (i == 1) ? rotl90(peps2) : rotr90(peps2) end From 308f3fb4f967ec31524f0846ac348407e1118974 Mon Sep 17 00:00:00 2001 From: sanderdemeyer Date: Mon, 16 Jun 2025 17:44:19 +0200 Subject: [PATCH 03/27] make SiteDependentTruncation a new truncation scheme Simple update was changed accordingly, CTMRG not yet --- src/PEPSKit.jl | 3 +- src/algorithms/time_evolution/simpleupdate.jl | 24 ++++++++----- .../time_evolution/simpleupdate3site.jl | 8 ++++- .../truncation/truncationschemes.jl | 35 +++++++++++++++++++ test/examples/heisenberg.jl | 25 +++++++++++-- 5 files changed, 81 insertions(+), 14 deletions(-) diff --git a/src/PEPSKit.jl b/src/PEPSKit.jl index 391a7e151..673e4f21e 100644 --- a/src/PEPSKit.jl +++ b/src/PEPSKit.jl @@ -82,7 +82,8 @@ using .Defaults: set_scheduler! export set_scheduler! export SVDAdjoint, FullSVDReverseRule, IterSVD export CTMRGEnv, SequentialCTMRG, SimultaneousCTMRG -export FixedSpaceTruncation, HalfInfiniteProjector, FullInfiniteProjector +export FixedSpaceTruncation, SiteDependentTruncation +export HalfInfiniteProjector, FullInfiniteProjector export LocalOperator, physicalspace export expectation_value, cost_function, product_peps, correlation_length, network_value export correlator diff --git a/src/algorithms/time_evolution/simpleupdate.jl b/src/algorithms/time_evolution/simpleupdate.jl index 527fb05f5..c65691c45 100644 --- a/src/algorithms/time_evolution/simpleupdate.jl +++ b/src/algorithms/time_evolution/simpleupdate.jl @@ -12,16 +12,10 @@ struct SimpleUpdate dt::Float64 tol::Float64 maxiter::Int - trschemes::NTuple{2,TensorKit.TruncationScheme} # truncation schemes for x and y bonds + trscheme::TensorKit.TruncationScheme end # TODO: add kwarg constructor and SU Defaults -function SimpleUpdate( - dt::Float64, tol::Float64, maxiter::Int, trscheme::TensorKit.TruncationScheme -) - return SimpleUpdate(dt, tol, maxiter, (trscheme, trscheme)) -end - """ $(SIGNATURES) @@ -100,7 +94,13 @@ function su_iter( direction == 1 ? gate : gate_mirrored, (CartesianIndex(r, 1), CartesianIndex(r, 2)), ) - ϵ = _su_bondx!(r, 1, term, peps2, alg.trschemes[direction]) + ϵ = _su_bondx!( + r, + 1, + term, + peps2, + truncation_scheme(alg.trscheme; direction, r, c, mirror_antidiag=true), + ) peps2.vertices[rp1, 2] = deepcopy(peps2.vertices[r, 1]) peps2.vertices[rp1, 1] = deepcopy(peps2.vertices[r, 2]) peps2.weights[1, rp1, 2] = deepcopy(peps2.weights[1, r, 1]) @@ -112,7 +112,13 @@ function su_iter( direction == 1 ? gate : gate_mirrored, (CartesianIndex(r, c), CartesianIndex(r, c + 1)), ) - ϵ = _su_bondx!(r, c, term, peps2, alg.trschemes[direction]) + ϵ = _su_bondx!( + r, + c, + term, + peps2, + truncation_scheme(alg.trscheme; direction, r, c, mirror_antidiag=true), + ) end end if direction == 2 diff --git a/src/algorithms/time_evolution/simpleupdate3site.jl b/src/algorithms/time_evolution/simpleupdate3site.jl index c1081c86e..ac0d1048a 100644 --- a/src/algorithms/time_evolution/simpleupdate3site.jl +++ b/src/algorithms/time_evolution/simpleupdate3site.jl @@ -422,7 +422,13 @@ function su3site_iter( for site in CartesianIndices(peps2.vertices) r, c = site[1], site[2] gs = gatempos[i][r, c] - _su3site_se!(r, c, gs, peps2, alg.trschemes[i]) + _su3site_se!( + r, + c, + gs, + peps2, + truncation_scheme(alg.trscheme, direction, r, c; mirror_antidiag=true), + ) end peps2 = (i == 1) ? rotl90(peps2) : rotr90(peps2) end diff --git a/src/algorithms/truncation/truncationschemes.jl b/src/algorithms/truncation/truncationschemes.jl index 9039d925e..c7aa6cebe 100644 --- a/src/algorithms/truncation/truncationschemes.jl +++ b/src/algorithms/truncation/truncationschemes.jl @@ -7,6 +7,22 @@ have different spaces, this truncation style is different from `TruncationSpace` """ struct FixedSpaceTruncation <: TensorKit.TruncationScheme end +struct SiteDependentTruncation <: TensorKit.TruncationScheme + trschemes::Array{T,3} where {T<:TensorKit.TruncationScheme} +end + +function SiteDependentTruncation(trscheme::TensorKit.TruncationScheme, Nr::Int, Nc::Int) + return SiteDependentTruncation(reshape(fill(trscheme, Nr, Nc), 2, Nr, Nc)) +end + +function SiteDependentTruncation( + trschemes::Tuple{T,S}, Nr::Int, Nc::Int +) where {T<:TensorKit.TruncationScheme,S<:TensorKit.TruncationScheme} + return SiteDependentTruncation( + reshape([trschemes[mod1(i, 2)] for i in 1:(2 * Nr * Nc)], 2, Nr, Nc) + ) +end + const TRUNCATION_SCHEME_SYMBOLS = IdDict{Symbol,Type{<:TruncationScheme}}( :fixedspace => FixedSpaceTruncation, :notrunc => TensorKit.NoTruncation, @@ -25,3 +41,22 @@ function _TruncationScheme(; alg=Defaults.trscheme, η=nothing) return isnothing(η) ? alg_type() : alg_type(η) end + +function truncation_scheme(trscheme::T; kwargs...) where {T<:TensorKit.TruncationScheme} + return trscheme +end + +function truncation_scheme( + trscheme::SiteDependentTruncation; + direction::Int, + r::Int, + c::Int, + mirror_antidiag::Bool=false, +) + if mirror_antidiag && direction == 2 + depth, Nr, Nc = size(trscheme.trschemes) + @assert depth == 2 + return trscheme.trschemes[direction, Nc - c + 1, Nr - r + 1] + end + return trscheme.trschemes[direction, r, c] +end diff --git a/test/examples/heisenberg.jl b/test/examples/heisenberg.jl index a8821639b..7a84cfafa 100644 --- a/test/examples/heisenberg.jl +++ b/test/examples/heisenberg.jl @@ -71,9 +71,28 @@ end maxiter = 5000 for (n, (dt, tol)) in enumerate(zip(dts, tols)) Dbond2 = (n == 2) ? Dbond + 2 : Dbond - if n == 3 - trscheme = ( - truncerr(1e-10) & truncdim(Dbond2), truncerr(1e-10) & truncdim(Dbond2 + 1) + if n == 2 + trscheme = SiteDependentTruncation( + (truncerr(tol) & truncdim(Dbond2), truncerr(tol) & truncdim(Dbond2 + 1)), + N1, + N2, + ) + elseif n == 3 + trscheme = SiteDependentTruncation( + reshape( + [truncerr(tol) & truncdim(Dbond2) truncerr(tol) & truncdim(Dbond2 + 1) truncerr( + tol + ) & truncdim( + Dbond2 + ) truncerr(tol) & truncdim(Dbond2 + 1) truncerr(tol) & truncdim(Dbond2) truncerr( + tol + ) & truncdim( + Dbond2 + ) truncerr(tol) & truncdim(Dbond2) truncerr(tol) & truncdim(Dbond2)], + 2, + 2, + 2, + ), ) else trscheme = truncerr(tol) & truncdim(Dbond2) From 213b4f7a390617f6384d4f603de66cc301f05cdc Mon Sep 17 00:00:00 2001 From: sanderdemeyer Date: Tue, 17 Jun 2025 14:47:22 +0200 Subject: [PATCH 04/27] update on arguments and constructors --- src/algorithms/time_evolution/simpleupdate.jl | 15 ++---- .../time_evolution/simpleupdate3site.jl | 8 +-- .../truncation/truncationschemes.jl | 52 +++++++++++++------ test/examples/heisenberg.jl | 5 +- 4 files changed, 44 insertions(+), 36 deletions(-) diff --git a/src/algorithms/time_evolution/simpleupdate.jl b/src/algorithms/time_evolution/simpleupdate.jl index 16b9d18c9..4129ff46d 100644 --- a/src/algorithms/time_evolution/simpleupdate.jl +++ b/src/algorithms/time_evolution/simpleupdate.jl @@ -86,6 +86,9 @@ function su_iter( # to update them using code for x-weights if direction == 2 peps2 = mirror_antidiag(peps2) + trscheme = mirror_antidiag(alg.trscheme) + else + trscheme = alg.trscheme end if bipartite for r in 1:2 @@ -95,11 +98,7 @@ function su_iter( (CartesianIndex(r, 1), CartesianIndex(r, 2)), ) ϵ = _su_xbond!( - r, - 1, - term, - peps2, - truncation_scheme(alg.trscheme; direction, r, c, mirror_antidiag=true), + r, 1, term, peps2, truncation_scheme(trscheme, direction, r, 1) ) peps2.vertices[rp1, 2] = deepcopy(peps2.vertices[r, 1]) peps2.vertices[rp1, 1] = deepcopy(peps2.vertices[r, 2]) @@ -113,11 +112,7 @@ function su_iter( (CartesianIndex(r, c), CartesianIndex(r, c + 1)), ) ϵ = _su_xbond!( - r, - c, - term, - peps2, - truncation_scheme(alg.trscheme; direction, r, c, mirror_antidiag=true), + r, c, term, peps2, truncation_scheme(trscheme, direction, r, c) ) end end diff --git a/src/algorithms/time_evolution/simpleupdate3site.jl b/src/algorithms/time_evolution/simpleupdate3site.jl index 6e8844911..ec6f35308 100644 --- a/src/algorithms/time_evolution/simpleupdate3site.jl +++ b/src/algorithms/time_evolution/simpleupdate3site.jl @@ -422,13 +422,7 @@ function su3site_iter( for site in CartesianIndices(peps2.vertices) r, c = site[1], site[2] gs = gatempos[i][r, c] - _su3site_se!( - r, - c, - gs, - peps2, - truncation_scheme(alg.trscheme, direction, r, c; mirror_antidiag=true), - ) + _su3site_se!(r, c, gs, peps2, truncation_scheme(alg.trscheme, direction, r, c)) end peps2 = rotl90(peps2) end diff --git a/src/algorithms/truncation/truncationschemes.jl b/src/algorithms/truncation/truncationschemes.jl index c7aa6cebe..ef023f70a 100644 --- a/src/algorithms/truncation/truncationschemes.jl +++ b/src/algorithms/truncation/truncationschemes.jl @@ -11,15 +11,21 @@ struct SiteDependentTruncation <: TensorKit.TruncationScheme trschemes::Array{T,3} where {T<:TensorKit.TruncationScheme} end -function SiteDependentTruncation(trscheme::TensorKit.TruncationScheme, Nr::Int, Nc::Int) - return SiteDependentTruncation(reshape(fill(trscheme, Nr, Nc), 2, Nr, Nc)) +function SiteDependentTruncation( + trscheme::TensorKit.TruncationScheme, directions::Int; unitcell::Tuple{Int,Int}=(1, 1) +) + Nr, Nc = unitcell + return SiteDependentTruncation(fill(trscheme, directions, Nr, Nc)) end +# This constructor for SiteDependentTruncation takes one truncation scheme for each direction, independent on the site of the unit cell. +# If the input is an Tuple of size N, trschemes becomes an Array of size NxNrxNc, where trschemes[N,Nr,Nc] = truncation_schemes[N]. function SiteDependentTruncation( - trschemes::Tuple{T,S}, Nr::Int, Nc::Int -) where {T<:TensorKit.TruncationScheme,S<:TensorKit.TruncationScheme} + truncation_schemes::NTuple{N,T}; unitcell::Tuple{Int,Int}=(1, 1) +) where {N,T<:TensorKit.TruncationScheme} + Nr, Nc = unitcell return SiteDependentTruncation( - reshape([trschemes[mod1(i, 2)] for i in 1:(2 * Nr * Nc)], 2, Nr, Nc) + reshape([truncation_schemes[mod1(i, N)] for i in 1:(N * Nr * Nc)], N, Nr, Nc) ) end @@ -42,21 +48,35 @@ function _TruncationScheme(; alg=Defaults.trscheme, η=nothing) return isnothing(η) ? alg_type() : alg_type(η) end -function truncation_scheme(trscheme::T; kwargs...) where {T<:TensorKit.TruncationScheme} +function truncation_scheme( + trscheme::T, direction::Int, row::Int, col::Int; kwargs... +) where {T<:TensorKit.TruncationScheme} return trscheme end function truncation_scheme( - trscheme::SiteDependentTruncation; - direction::Int, - r::Int, - c::Int, - mirror_antidiag::Bool=false, + trscheme::SiteDependentTruncation, direction::Int, row::Int, col::Int; ) - if mirror_antidiag && direction == 2 - depth, Nr, Nc = size(trscheme.trschemes) - @assert depth == 2 - return trscheme.trschemes[direction, Nc - c + 1, Nr - r + 1] + return trscheme.trschemes[direction, row, col] +end + +# Mirror a TruncationScheme by its anti-diagonal line. +function mirror_antidiag(trscheme::T) where {T<:TensorKit.TruncationScheme} + return trscheme +end +function mirror_antidiag(trscheme::T) where {T<:SiteDependentTruncation} + directions = size(trscheme.trschemes)[1] + trschemes_mirrored = permutedims(trscheme.trschemes, (1, 3, 2)) + if directions == 2 + trschemes_mirrored[1, :, :] = mirror_antidiag(trscheme.trschemes[2, :, :]) + trschemes_mirrored[2, :, :] = mirror_antidiag(trscheme.trschemes[1, :, :]) + elseif directions == 4 + trschemes_mirrored[1, :, :] = mirror_antidiag(trscheme.trschemes[2, :, :]) + trschemes_mirrored[2, :, :] = mirror_antidiag(trscheme.trschemes[1, :, :]) + trschemes_mirrored[3, :, :] = mirror_antidiag(trscheme.trschemes[4, :, :]) + trschemes_mirrored[4, :, :] = mirror_antidiag(trscheme.trschemes[3, :, :]) + else + error("Unsupported number of directions for mirror_antidiag: $directions") end - return trscheme.trschemes[direction, r, c] + return SiteDependentTruncation(trschemes_mirrored) end diff --git a/test/examples/heisenberg.jl b/test/examples/heisenberg.jl index 7a84cfafa..cddc97d2b 100644 --- a/test/examples/heisenberg.jl +++ b/test/examples/heisenberg.jl @@ -73,9 +73,8 @@ end Dbond2 = (n == 2) ? Dbond + 2 : Dbond if n == 2 trscheme = SiteDependentTruncation( - (truncerr(tol) & truncdim(Dbond2), truncerr(tol) & truncdim(Dbond2 + 1)), - N1, - N2, + (truncerr(tol) & truncdim(Dbond2), truncerr(tol) & truncdim(Dbond2 + 1)); + unitcell=(N1, N2), ) elseif n == 3 trscheme = SiteDependentTruncation( From 436f8cc5dbb3bfe6cb247e6fd44a11999b8d6ab4 Mon Sep 17 00:00:00 2001 From: sanderdemeyer Date: Tue, 17 Jun 2025 16:13:51 +0200 Subject: [PATCH 05/27] Fix 3-site SU for SiteDependentTruncationScheme --- .../time_evolution/simpleupdate3site.jl | 40 ++++++++++--------- test/timeevol/cluster_projectors.jl | 4 +- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/algorithms/time_evolution/simpleupdate3site.jl b/src/algorithms/time_evolution/simpleupdate3site.jl index ec6f35308..f85e3927c 100644 --- a/src/algorithms/time_evolution/simpleupdate3site.jl +++ b/src/algorithms/time_evolution/simpleupdate3site.jl @@ -235,16 +235,20 @@ end Given a cluster `Ms` and the pre-calculated `R`, `L` bond matrices, find all projectors `Pa`, `Pb` and Schmidt weights `wts` on internal bonds. """ -function _get_allprojs(Ms, Rs, Ls, trunc::TensorKit.TruncationScheme, revs::Vector{Bool}) +function _get_allprojs( + Ms, Rs, Ls, trschemes::Vector{E}, revs::Vector{Bool} +) where {E<:TensorKit.TruncationScheme} N = length(Ms) + @assert length(trschemes) == N - 1 projs_errs = map(1:(N - 1)) do i - trunc2 = if isa(trunc, FixedSpaceTruncation) + trunc = trschemes[i] + trunc = if isa(trschemes[i], FixedSpaceTruncation) V = space(Ms[i + 1], 1) truncspace(isdual(V) ? V' : V) else - trunc + trschemes[i] end - return _proj_from_RL(Rs[i], Ls[i]; trunc=trunc2, rev=revs[i]) + return _proj_from_RL(Rs[i], Ls[i]; trunc, rev=revs[i]) end Pas = map(Base.Fix2(getindex, 1), projs_errs) wts = map(Base.Fix2(getindex, 2), projs_errs) @@ -258,10 +262,10 @@ end Find projectors to truncate internal bonds of the cluster `Ms` """ function _cluster_truncate!( - Ms::Vector{T}, trunc::TensorKit.TruncationScheme, revs::Vector{Bool} -) where {T<:PEPSTensor} + Ms::Vector{T}, trschemes::Vector{E}, revs::Vector{Bool} +) where {T<:PEPSTensor,E<:TensorKit.TruncationScheme} Rs, Ls = _get_allRLs(Ms) - Pas, Pbs, wts, ϵs = _get_allprojs(Ms, Rs, Ls, trunc, revs) + Pas, Pbs, wts, ϵs = _get_allprojs(Ms, Rs, Ls, trschemes, revs) # apply projectors # M1 -- (Pa1,wt1,Pb1) -- M2 -- (Pa2,wt2,Pb2) -- M3 for (i, (Pa, Pb)) in enumerate(zip(Pas, Pbs)) @@ -322,13 +326,13 @@ In the cluster, the axes of each PEPSTensor are reordered as ``` """ function apply_gatempo!( - Ms::Vector{T1}, gs::Vector{T2}; trunc::TensorKit.TruncationScheme -) where {T1<:PEPSTensor,T2<:AbstractTensorMap} + Ms::Vector{T1}, gs::Vector{T2}; trschemes::Vector{E} +) where {T1<:PEPSTensor,T2<:AbstractTensorMap,E<:TensorKit.TruncationScheme} @assert length(Ms) == length(gs) revs = [isdual(space(M, 1)) for M in Ms[2:end]] @assert !all(revs) _apply_gatempo!(Ms, gs) - wts, ϵs, = _cluster_truncate!(Ms, trunc, revs) + wts, ϵs, = _cluster_truncate!(Ms, trschemes, revs) return wts, ϵs end @@ -373,12 +377,8 @@ function get_3site_se(peps::InfiniteWeightPEPS, row::Int, col::Int) end function _su3site_se!( - row::Int, - col::Int, - gs::Vector{T}, - peps::InfiniteWeightPEPS, - trscheme::TensorKit.TruncationScheme, -) where {T<:AbstractTensorMap} + row::Int, col::Int, gs::Vector{T}, peps::InfiniteWeightPEPS, trschemes::Vector{E} +) where {T<:AbstractTensorMap,E<:TensorKit.TruncationScheme} Nr, Nc = size(peps) @assert 1 <= row <= Nr && 1 <= col <= Nc rm1, cp1 = _prev(row, Nr), _next(col, Nc) @@ -388,7 +388,7 @@ function _su3site_se!( coords = ((row, col), (row, cp1), (rm1, cp1)) # weights in the cluster wt_idxs = ((1, row, col), (2, row, cp1)) - wts, ϵ = apply_gatempo!(Ms, gs; trunc=trscheme) + wts, ϵ = apply_gatempo!(Ms, gs; trschemes) for (wt, wt_idx) in zip(wts, wt_idxs) peps.weights[CartesianIndex(wt_idx)] = wt / norm(wt, Inf) end @@ -422,7 +422,11 @@ function su3site_iter( for site in CartesianIndices(peps2.vertices) r, c = site[1], site[2] gs = gatempos[i][r, c] - _su3site_se!(r, c, gs, peps2, truncation_scheme(alg.trscheme, direction, r, c)) + trschemes = [ + truncation_scheme(alg.trscheme, 1, r, c) + truncation_scheme(alg.trscheme, 2, r, _next(c, Nc)) + ] + _su3site_se!(r, c, gs, peps2, trschemes) end peps2 = rotl90(peps2) end diff --git a/test/timeevol/cluster_projectors.jl b/test/timeevol/cluster_projectors.jl index 4ad3f60f6..91b2994e8 100644 --- a/test/timeevol/cluster_projectors.jl +++ b/test/timeevol/cluster_projectors.jl @@ -30,7 +30,7 @@ Vspaces = [ revs = [isdual(space(M, 1)) for M in Ms1[2:end]] # no truncation Ms2 = deepcopy(Ms1) - wts2, ϵs, = _cluster_truncate!(Ms2, FixedSpaceTruncation(), revs) + wts2, ϵs, = _cluster_truncate!(Ms2, fill(FixedSpaceTruncation(), N-1), revs) @test all((ϵ == 0) for ϵ in ϵs) absorb_wts_cluster!(Ms2, wts2) for (i, M) in enumerate(Ms2) @@ -41,7 +41,7 @@ Vspaces = [ @test all(lorths) && all(rorths) # truncation on one bond Ms3 = deepcopy(Ms1) - wts3, ϵs, = _cluster_truncate!(Ms3, truncspace(Vns), revs) + wts3, ϵs, = _cluster_truncate!(Ms3, fill(truncspace(Vns), N-1), revs) @test all((i == n) || (ϵ == 0) for (i, ϵ) in enumerate(ϵs)) absorb_wts_cluster!(Ms3, wts3) for (i, M) in enumerate(Ms3) From 12ff1bddb080374bcd126677bd42fc050e50056b Mon Sep 17 00:00:00 2001 From: sanderdemeyer Date: Tue, 17 Jun 2025 16:16:31 +0200 Subject: [PATCH 06/27] small documentation update --- src/algorithms/truncation/truncationschemes.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/algorithms/truncation/truncationschemes.jl b/src/algorithms/truncation/truncationschemes.jl index ef023f70a..8263b9e71 100644 --- a/src/algorithms/truncation/truncationschemes.jl +++ b/src/algorithms/truncation/truncationschemes.jl @@ -61,6 +61,8 @@ function truncation_scheme( end # Mirror a TruncationScheme by its anti-diagonal line. +# When the number of directions is 2, it swaps the first and second direction, consistent with xbonds and ybonds, respectively. +# When the number of directions is 4, it swaps the first and second, and third and fourth directions, consistent with the order NORTH, EAST, SOUTH, WEST. function mirror_antidiag(trscheme::T) where {T<:TensorKit.TruncationScheme} return trscheme end From b92df220423878679d8d98ac6562cdf0356301df Mon Sep 17 00:00:00 2001 From: sanderdemeyer Date: Tue, 17 Jun 2025 21:05:36 +0200 Subject: [PATCH 07/27] Change name and add rotl90 --- .../time_evolution/simpleupdate3site.jl | 6 ++- .../truncation/truncationschemes.jl | 44 ++++++++++++------- test/examples/heisenberg.jl | 4 +- 3 files changed, 33 insertions(+), 21 deletions(-) diff --git a/src/algorithms/time_evolution/simpleupdate3site.jl b/src/algorithms/time_evolution/simpleupdate3site.jl index f85e3927c..36934ff0c 100644 --- a/src/algorithms/time_evolution/simpleupdate3site.jl +++ b/src/algorithms/time_evolution/simpleupdate3site.jl @@ -418,17 +418,19 @@ function su3site_iter( ), ) peps2 = deepcopy(peps) + trscheme = alg.trscheme for i in 1:4 for site in CartesianIndices(peps2.vertices) r, c = site[1], site[2] gs = gatempos[i][r, c] trschemes = [ - truncation_scheme(alg.trscheme, 1, r, c) - truncation_scheme(alg.trscheme, 2, r, _next(c, Nc)) + truncation_scheme(trscheme, 1, r, c) + truncation_scheme(trscheme, 2, r, _next(c, Nc)) ] _su3site_se!(r, c, gs, peps2, trschemes) end peps2 = rotl90(peps2) + trscheme = rotl90(trscheme) end return peps2 end diff --git a/src/algorithms/truncation/truncationschemes.jl b/src/algorithms/truncation/truncationschemes.jl index 8263b9e71..fb61fd87a 100644 --- a/src/algorithms/truncation/truncationschemes.jl +++ b/src/algorithms/truncation/truncationschemes.jl @@ -7,26 +7,15 @@ have different spaces, this truncation style is different from `TruncationSpace` """ struct FixedSpaceTruncation <: TensorKit.TruncationScheme end -struct SiteDependentTruncation <: TensorKit.TruncationScheme +struct VariableTruncation <: TensorKit.TruncationScheme trschemes::Array{T,3} where {T<:TensorKit.TruncationScheme} end -function SiteDependentTruncation( +function VariableTruncation( trscheme::TensorKit.TruncationScheme, directions::Int; unitcell::Tuple{Int,Int}=(1, 1) ) Nr, Nc = unitcell - return SiteDependentTruncation(fill(trscheme, directions, Nr, Nc)) -end - -# This constructor for SiteDependentTruncation takes one truncation scheme for each direction, independent on the site of the unit cell. -# If the input is an Tuple of size N, trschemes becomes an Array of size NxNrxNc, where trschemes[N,Nr,Nc] = truncation_schemes[N]. -function SiteDependentTruncation( - truncation_schemes::NTuple{N,T}; unitcell::Tuple{Int,Int}=(1, 1) -) where {N,T<:TensorKit.TruncationScheme} - Nr, Nc = unitcell - return SiteDependentTruncation( - reshape([truncation_schemes[mod1(i, N)] for i in 1:(N * Nr * Nc)], N, Nr, Nc) - ) + return VariableTruncation(fill(trscheme, directions, Nr, Nc)) end const TRUNCATION_SCHEME_SYMBOLS = IdDict{Symbol,Type{<:TruncationScheme}}( @@ -55,7 +44,7 @@ function truncation_scheme( end function truncation_scheme( - trscheme::SiteDependentTruncation, direction::Int, row::Int, col::Int; + trscheme::VariableTruncation, direction::Int, row::Int, col::Int; ) return trscheme.trschemes[direction, row, col] end @@ -66,7 +55,7 @@ end function mirror_antidiag(trscheme::T) where {T<:TensorKit.TruncationScheme} return trscheme end -function mirror_antidiag(trscheme::T) where {T<:SiteDependentTruncation} +function mirror_antidiag(trscheme::T) where {T<:VariableTruncation} directions = size(trscheme.trschemes)[1] trschemes_mirrored = permutedims(trscheme.trschemes, (1, 3, 2)) if directions == 2 @@ -80,5 +69,26 @@ function mirror_antidiag(trscheme::T) where {T<:SiteDependentTruncation} else error("Unsupported number of directions for mirror_antidiag: $directions") end - return SiteDependentTruncation(trschemes_mirrored) + return VariableTruncation(trschemes_mirrored) +end + +function Base.rotl90(trscheme::T) where {T<:TensorKit.TruncationScheme} + return trscheme +end + +function Base.rotl90(trscheme::T) where {T<:VariableTruncation} + directions = size(trscheme.trschemes)[1] + trschemes_rotated = permutedims(trscheme.trschemes, (1, 3, 2)) + if directions == 2 + trschemes_rotated[1, :, :] = circshift(rotl90(trscheme.trschemes[2, :, :]), (0, -1)) + trschemes_rotated[2, :, :] = rotl90(trscheme.trschemes[1, :, :]) + elseif directions == 4 + trschemes_rotated[1, :, :] = rotl90(trscheme.trschemes[2, :, :]) + trschemes_rotated[2, :, :] = rotl90(trscheme.trschemes[3, :, :]) + trschemes_rotated[3, :, :] = rotl90(trscheme.trschemes[4, :, :]) + trschemes_rotated[4, :, :] = rotl90(trscheme.trschemes[1, :, :]) + else + error("Unsupported number of directions for rotl90: $directions") + end + return VariableTruncation(trschemes_rotated) end diff --git a/test/examples/heisenberg.jl b/test/examples/heisenberg.jl index cddc97d2b..20af65664 100644 --- a/test/examples/heisenberg.jl +++ b/test/examples/heisenberg.jl @@ -72,12 +72,12 @@ end for (n, (dt, tol)) in enumerate(zip(dts, tols)) Dbond2 = (n == 2) ? Dbond + 2 : Dbond if n == 2 - trscheme = SiteDependentTruncation( + trscheme = VariableTruncation( (truncerr(tol) & truncdim(Dbond2), truncerr(tol) & truncdim(Dbond2 + 1)); unitcell=(N1, N2), ) elseif n == 3 - trscheme = SiteDependentTruncation( + trscheme = VariableTruncation( reshape( [truncerr(tol) & truncdim(Dbond2) truncerr(tol) & truncdim(Dbond2 + 1) truncerr( tol From ff5930e68041efe6d99c4b965f3185c1e95556f5 Mon Sep 17 00:00:00 2001 From: sanderdemeyer Date: Tue, 17 Jun 2025 22:33:00 +0200 Subject: [PATCH 08/27] fix export --- src/PEPSKit.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PEPSKit.jl b/src/PEPSKit.jl index 673e4f21e..6dd1948de 100644 --- a/src/PEPSKit.jl +++ b/src/PEPSKit.jl @@ -82,7 +82,7 @@ using .Defaults: set_scheduler! export set_scheduler! export SVDAdjoint, FullSVDReverseRule, IterSVD export CTMRGEnv, SequentialCTMRG, SimultaneousCTMRG -export FixedSpaceTruncation, SiteDependentTruncation +export FixedSpaceTruncation, VariableTruncation export HalfInfiniteProjector, FullInfiniteProjector export LocalOperator, physicalspace export expectation_value, cost_function, product_peps, correlation_length, network_value From 578b54e77bbbd458d1ccb45f505e032372dea922 Mon Sep 17 00:00:00 2001 From: sanderdemeyer Date: Tue, 17 Jun 2025 23:22:44 +0200 Subject: [PATCH 09/27] change arguments in test --- test/examples/heisenberg.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/examples/heisenberg.jl b/test/examples/heisenberg.jl index 20af65664..20b55afb5 100644 --- a/test/examples/heisenberg.jl +++ b/test/examples/heisenberg.jl @@ -73,8 +73,7 @@ end Dbond2 = (n == 2) ? Dbond + 2 : Dbond if n == 2 trscheme = VariableTruncation( - (truncerr(tol) & truncdim(Dbond2), truncerr(tol) & truncdim(Dbond2 + 1)); - unitcell=(N1, N2), + truncerr(tol) & truncdim(Dbond2), 2; unitcell=(N1, N2) ) elseif n == 3 trscheme = VariableTruncation( From e06f568404723d17ecc6d8a3a239545faeb55bd6 Mon Sep 17 00:00:00 2001 From: sanderdemeyer Date: Wed, 18 Jun 2025 10:38:27 +0200 Subject: [PATCH 10/27] add test for 3-site cluster update --- test/timeevol/cluster_projectors.jl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/timeevol/cluster_projectors.jl b/test/timeevol/cluster_projectors.jl index 91b2994e8..83f71d946 100644 --- a/test/timeevol/cluster_projectors.jl +++ b/test/timeevol/cluster_projectors.jl @@ -95,7 +95,9 @@ end tols = [1e-8, 1e-8, 1e-8] maxiter = 10000 for (n, (dt, tol)) in enumerate(zip(dts, tols)) - trscheme = truncerr(1e-10) & truncdim(n == 1 ? 4 : 2) + trscheme = VariableTruncation( + truncerr(1e-10) & truncdim(n == 1 ? 4 : 2), 2; unitcell=(Nr, Nc) + ) alg = SimpleUpdate(dt, tol, maxiter, trscheme) result = simpleupdate(wpeps, ham, alg; bipartite=true, check_interval=1000) wpeps = result[1] From 076b3c8037a365e88b46c17e100802ce2a6c8ca8 Mon Sep 17 00:00:00 2001 From: sanderdemeyer Date: Wed, 18 Jun 2025 15:17:00 +0200 Subject: [PATCH 11/27] change test to increase patch coverage --- test/timeevol/cluster_projectors.jl | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/test/timeevol/cluster_projectors.jl b/test/timeevol/cluster_projectors.jl index 83f71d946..0ecbf329c 100644 --- a/test/timeevol/cluster_projectors.jl +++ b/test/timeevol/cluster_projectors.jl @@ -95,9 +95,7 @@ end tols = [1e-8, 1e-8, 1e-8] maxiter = 10000 for (n, (dt, tol)) in enumerate(zip(dts, tols)) - trscheme = VariableTruncation( - truncerr(1e-10) & truncdim(n == 1 ? 4 : 2), 2; unitcell=(Nr, Nc) - ) + trscheme = truncerr(1e-10) & truncdim(n == 1 ? 4 : 2) alg = SimpleUpdate(dt, tol, maxiter, trscheme) result = simpleupdate(wpeps, ham, alg; bipartite=true, check_interval=1000) wpeps = result[1] @@ -111,7 +109,7 @@ end # continue with 3-site simple update; energy should not change much dts = [1e-2, 5e-3] tols = [1e-8, 1e-8] - trscheme = truncerr(1e-10) & truncdim(2) + trscheme = VariableTruncation(truncerr(1e-10) & truncdim(2), 2; unitcell=(Nr, Nc)) for (n, (dt, tol)) in enumerate(zip(dts, tols)) alg = SimpleUpdate(dt, tol, maxiter, trscheme) result = simpleupdate(wpeps, ham, alg; check_interval=1000, force_3site=true) From e515976b1c84bfc36dba8e31edc7104129eb8dae Mon Sep 17 00:00:00 2001 From: sanderdemeyer Date: Wed, 18 Jun 2025 15:25:43 +0200 Subject: [PATCH 12/27] change name again --- src/PEPSKit.jl | 2 +- src/algorithms/truncation/truncationschemes.jl | 16 ++++++++-------- test/examples/heisenberg.jl | 4 ++-- test/timeevol/cluster_projectors.jl | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/PEPSKit.jl b/src/PEPSKit.jl index 6dd1948de..673e4f21e 100644 --- a/src/PEPSKit.jl +++ b/src/PEPSKit.jl @@ -82,7 +82,7 @@ using .Defaults: set_scheduler! export set_scheduler! export SVDAdjoint, FullSVDReverseRule, IterSVD export CTMRGEnv, SequentialCTMRG, SimultaneousCTMRG -export FixedSpaceTruncation, VariableTruncation +export FixedSpaceTruncation, SiteDependentTruncation export HalfInfiniteProjector, FullInfiniteProjector export LocalOperator, physicalspace export expectation_value, cost_function, product_peps, correlation_length, network_value diff --git a/src/algorithms/truncation/truncationschemes.jl b/src/algorithms/truncation/truncationschemes.jl index fb61fd87a..097fa55e2 100644 --- a/src/algorithms/truncation/truncationschemes.jl +++ b/src/algorithms/truncation/truncationschemes.jl @@ -7,15 +7,15 @@ have different spaces, this truncation style is different from `TruncationSpace` """ struct FixedSpaceTruncation <: TensorKit.TruncationScheme end -struct VariableTruncation <: TensorKit.TruncationScheme +struct SiteDependentTruncation <: TensorKit.TruncationScheme trschemes::Array{T,3} where {T<:TensorKit.TruncationScheme} end -function VariableTruncation( +function SiteDependentTruncation( trscheme::TensorKit.TruncationScheme, directions::Int; unitcell::Tuple{Int,Int}=(1, 1) ) Nr, Nc = unitcell - return VariableTruncation(fill(trscheme, directions, Nr, Nc)) + return SiteDependentTruncation(fill(trscheme, directions, Nr, Nc)) end const TRUNCATION_SCHEME_SYMBOLS = IdDict{Symbol,Type{<:TruncationScheme}}( @@ -44,7 +44,7 @@ function truncation_scheme( end function truncation_scheme( - trscheme::VariableTruncation, direction::Int, row::Int, col::Int; + trscheme::SiteDependentTruncation, direction::Int, row::Int, col::Int; ) return trscheme.trschemes[direction, row, col] end @@ -55,7 +55,7 @@ end function mirror_antidiag(trscheme::T) where {T<:TensorKit.TruncationScheme} return trscheme end -function mirror_antidiag(trscheme::T) where {T<:VariableTruncation} +function mirror_antidiag(trscheme::T) where {T<:SiteDependentTruncation} directions = size(trscheme.trschemes)[1] trschemes_mirrored = permutedims(trscheme.trschemes, (1, 3, 2)) if directions == 2 @@ -69,14 +69,14 @@ function mirror_antidiag(trscheme::T) where {T<:VariableTruncation} else error("Unsupported number of directions for mirror_antidiag: $directions") end - return VariableTruncation(trschemes_mirrored) + return SiteDependentTruncation(trschemes_mirrored) end function Base.rotl90(trscheme::T) where {T<:TensorKit.TruncationScheme} return trscheme end -function Base.rotl90(trscheme::T) where {T<:VariableTruncation} +function Base.rotl90(trscheme::T) where {T<:SiteDependentTruncation} directions = size(trscheme.trschemes)[1] trschemes_rotated = permutedims(trscheme.trschemes, (1, 3, 2)) if directions == 2 @@ -90,5 +90,5 @@ function Base.rotl90(trscheme::T) where {T<:VariableTruncation} else error("Unsupported number of directions for rotl90: $directions") end - return VariableTruncation(trschemes_rotated) + return SiteDependentTruncation(trschemes_rotated) end diff --git a/test/examples/heisenberg.jl b/test/examples/heisenberg.jl index 20b55afb5..42f3bf4b6 100644 --- a/test/examples/heisenberg.jl +++ b/test/examples/heisenberg.jl @@ -72,11 +72,11 @@ end for (n, (dt, tol)) in enumerate(zip(dts, tols)) Dbond2 = (n == 2) ? Dbond + 2 : Dbond if n == 2 - trscheme = VariableTruncation( + trscheme = SiteDependentTruncation( truncerr(tol) & truncdim(Dbond2), 2; unitcell=(N1, N2) ) elseif n == 3 - trscheme = VariableTruncation( + trscheme = SiteDependentTruncation( reshape( [truncerr(tol) & truncdim(Dbond2) truncerr(tol) & truncdim(Dbond2 + 1) truncerr( tol diff --git a/test/timeevol/cluster_projectors.jl b/test/timeevol/cluster_projectors.jl index 0ecbf329c..377242b6d 100644 --- a/test/timeevol/cluster_projectors.jl +++ b/test/timeevol/cluster_projectors.jl @@ -109,7 +109,7 @@ end # continue with 3-site simple update; energy should not change much dts = [1e-2, 5e-3] tols = [1e-8, 1e-8] - trscheme = VariableTruncation(truncerr(1e-10) & truncdim(2), 2; unitcell=(Nr, Nc)) + trscheme = SiteDependentTruncation(truncerr(1e-10) & truncdim(2), 2; unitcell=(Nr, Nc)) for (n, (dt, tol)) in enumerate(zip(dts, tols)) alg = SimpleUpdate(dt, tol, maxiter, trscheme) result = simpleupdate(wpeps, ham, alg; check_interval=1000, force_3site=true) From 0e405f0e1aa26d045a9e3b6a1b6dae145cc36e1a Mon Sep 17 00:00:00 2001 From: sanderdemeyer Date: Thu, 19 Jun 2025 11:18:00 +0200 Subject: [PATCH 13/27] small updates --- src/PEPSKit.jl | 6 +++- .../truncation/truncationschemes.jl | 36 +++++++++---------- test/examples/heisenberg.jl | 17 ++++----- test/timeevol/cluster_projectors.jl | 2 +- 4 files changed, 29 insertions(+), 32 deletions(-) diff --git a/src/PEPSKit.jl b/src/PEPSKit.jl index 975f4b6cb..1e048f254 100644 --- a/src/PEPSKit.jl +++ b/src/PEPSKit.jl @@ -5,7 +5,11 @@ using Compat using Accessors: @set, @reset using VectorInterface import VectorInterface as VI -using TensorKit, KrylovKit, OptimKit, TensorOperations + +using TensorKit +using TensorKit: TruncationScheme + +using KrylovKit, OptimKit, TensorOperations using ChainRulesCore, Zygote using LoggingExtras diff --git a/src/algorithms/truncation/truncationschemes.jl b/src/algorithms/truncation/truncationschemes.jl index 097fa55e2..32deff96f 100644 --- a/src/algorithms/truncation/truncationschemes.jl +++ b/src/algorithms/truncation/truncationschemes.jl @@ -5,17 +5,10 @@ CTMRG specific truncation scheme for `tsvd` which keeps the bond space on which is performed fixed. Since different environment directions and unit cell entries might have different spaces, this truncation style is different from `TruncationSpace`. """ -struct FixedSpaceTruncation <: TensorKit.TruncationScheme end +struct FixedSpaceTruncation <: TruncationScheme end -struct SiteDependentTruncation <: TensorKit.TruncationScheme - trschemes::Array{T,3} where {T<:TensorKit.TruncationScheme} -end - -function SiteDependentTruncation( - trscheme::TensorKit.TruncationScheme, directions::Int; unitcell::Tuple{Int,Int}=(1, 1) -) - Nr, Nc = unitcell - return SiteDependentTruncation(fill(trscheme, directions, Nr, Nc)) +struct SiteDependentTruncation <: TruncationScheme + trschemes::Array{T,3} where {T<:TruncationScheme} end const TRUNCATION_SCHEME_SYMBOLS = IdDict{Symbol,Type{<:TruncationScheme}}( @@ -39,7 +32,7 @@ end function truncation_scheme( trscheme::T, direction::Int, row::Int, col::Int; kwargs... -) where {T<:TensorKit.TruncationScheme} +) where {T<:TruncationScheme} return trscheme end @@ -52,7 +45,7 @@ end # Mirror a TruncationScheme by its anti-diagonal line. # When the number of directions is 2, it swaps the first and second direction, consistent with xbonds and ybonds, respectively. # When the number of directions is 4, it swaps the first and second, and third and fourth directions, consistent with the order NORTH, EAST, SOUTH, WEST. -function mirror_antidiag(trscheme::T) where {T<:TensorKit.TruncationScheme} +function mirror_antidiag(trscheme::T) where {T<:TruncationScheme} return trscheme end function mirror_antidiag(trscheme::T) where {T<:SiteDependentTruncation} @@ -72,21 +65,24 @@ function mirror_antidiag(trscheme::T) where {T<:SiteDependentTruncation} return SiteDependentTruncation(trschemes_mirrored) end -function Base.rotl90(trscheme::T) where {T<:TensorKit.TruncationScheme} +# TODO: type piracy +function Base.rotl90(trscheme::T) where {T<:TruncationScheme} return trscheme end function Base.rotl90(trscheme::T) where {T<:SiteDependentTruncation} directions = size(trscheme.trschemes)[1] trschemes_rotated = permutedims(trscheme.trschemes, (1, 3, 2)) - if directions == 2 - trschemes_rotated[1, :, :] = circshift(rotl90(trscheme.trschemes[2, :, :]), (0, -1)) - trschemes_rotated[2, :, :] = rotl90(trscheme.trschemes[1, :, :]) + if directions == EAST + trschemes_rotated[NORTH, :, :] = circshift( + rotl90(trscheme.trschemes[EAST, :, :]), (0, -1) + ) + trschemes_rotated[EAST, :, :] = rotl90(trscheme.trschemes[NORTH, :, :]) elseif directions == 4 - trschemes_rotated[1, :, :] = rotl90(trscheme.trschemes[2, :, :]) - trschemes_rotated[2, :, :] = rotl90(trscheme.trschemes[3, :, :]) - trschemes_rotated[3, :, :] = rotl90(trscheme.trschemes[4, :, :]) - trschemes_rotated[4, :, :] = rotl90(trscheme.trschemes[1, :, :]) + trschemes_rotated[NORTH, :, :] = rotl90(trscheme.trschemes[EAST, :, :]) + trschemes_rotated[EAST, :, :] = rotl90(trscheme.trschemes[SOUTH, :, :]) + trschemes_rotated[SOUTH, :, :] = rotl90(trscheme.trschemes[WEST, :, :]) + trschemes_rotated[WEST, :, :] = rotl90(trscheme.trschemes[NORTH, :, :]) else error("Unsupported number of directions for rotl90: $directions") end diff --git a/test/examples/heisenberg.jl b/test/examples/heisenberg.jl index 42f3bf4b6..6bc0c9a40 100644 --- a/test/examples/heisenberg.jl +++ b/test/examples/heisenberg.jl @@ -73,20 +73,17 @@ end Dbond2 = (n == 2) ? Dbond + 2 : Dbond if n == 2 trscheme = SiteDependentTruncation( - truncerr(tol) & truncdim(Dbond2), 2; unitcell=(N1, N2) + fill(truncerr(tol) & truncdim(Dbond2), 2, N1, N2) ) elseif n == 3 + trunc_low = truncerr(tol) & truncdim(Dbond2) + trunc_high = truncerr(tol) & truncdim(Dbond2 + 1) trscheme = SiteDependentTruncation( reshape( - [truncerr(tol) & truncdim(Dbond2) truncerr(tol) & truncdim(Dbond2 + 1) truncerr( - tol - ) & truncdim( - Dbond2 - ) truncerr(tol) & truncdim(Dbond2 + 1) truncerr(tol) & truncdim(Dbond2) truncerr( - tol - ) & truncdim( - Dbond2 - ) truncerr(tol) & truncdim(Dbond2) truncerr(tol) & truncdim(Dbond2)], + [ + trunc_low trunc_high trunc_low trunc_high + trunc_low trunc_low trunc_low trunc_low + ], 2, 2, 2, diff --git a/test/timeevol/cluster_projectors.jl b/test/timeevol/cluster_projectors.jl index 377242b6d..666fc7f16 100644 --- a/test/timeevol/cluster_projectors.jl +++ b/test/timeevol/cluster_projectors.jl @@ -109,7 +109,7 @@ end # continue with 3-site simple update; energy should not change much dts = [1e-2, 5e-3] tols = [1e-8, 1e-8] - trscheme = SiteDependentTruncation(truncerr(1e-10) & truncdim(2), 2; unitcell=(Nr, Nc)) + trscheme = SiteDependentTruncation(fill(truncerr(1e-10) & truncdim(2), 2, Nr, Nc)) for (n, (dt, tol)) in enumerate(zip(dts, tols)) alg = SimpleUpdate(dt, tol, maxiter, trscheme) result = simpleupdate(wpeps, ham, alg; check_interval=1000, force_3site=true) From acf19cbb13d37a6e3e6d1ee46f7848dd0e25bde0 Mon Sep 17 00:00:00 2001 From: sanderdemeyer Date: Thu, 19 Jun 2025 16:38:08 +0200 Subject: [PATCH 14/27] rewrite mirror_antidiag --- .../truncation/truncationschemes.jl | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/algorithms/truncation/truncationschemes.jl b/src/algorithms/truncation/truncationschemes.jl index 32deff96f..cc6cfaf2c 100644 --- a/src/algorithms/truncation/truncationschemes.jl +++ b/src/algorithms/truncation/truncationschemes.jl @@ -50,15 +50,21 @@ function mirror_antidiag(trscheme::T) where {T<:TruncationScheme} end function mirror_antidiag(trscheme::T) where {T<:SiteDependentTruncation} directions = size(trscheme.trschemes)[1] - trschemes_mirrored = permutedims(trscheme.trschemes, (1, 3, 2)) if directions == 2 - trschemes_mirrored[1, :, :] = mirror_antidiag(trscheme.trschemes[2, :, :]) - trschemes_mirrored[2, :, :] = mirror_antidiag(trscheme.trschemes[1, :, :]) + trschemes_mirrored = stack( + ( + mirror_antidiag(trscheme.trschemes[EAST, :, :]), + mirror_antidiag(trscheme.trschemes[NORTH, :, :]), + ); + dims=1, + ) elseif directions == 4 - trschemes_mirrored[1, :, :] = mirror_antidiag(trscheme.trschemes[2, :, :]) - trschemes_mirrored[2, :, :] = mirror_antidiag(trscheme.trschemes[1, :, :]) - trschemes_mirrored[3, :, :] = mirror_antidiag(trscheme.trschemes[4, :, :]) - trschemes_mirrored[4, :, :] = mirror_antidiag(trscheme.trschemes[3, :, :]) + trschemes_mirrored = stack(( + mirror_antidiag(trscheme.trschemes[EAST, :, :]), + mirror_antidiag(trscheme.trschemes[NORTH, :, :]), + mirror_antidiag(trscheme.trschemes[WEST, :, :]), + mirror_antidiag(trscheme.trschemes[SOUTH, :, :]), + )) else error("Unsupported number of directions for mirror_antidiag: $directions") end From d1d12984d725920ce214423dfebb94612e14f379 Mon Sep 17 00:00:00 2001 From: sanderdemeyer Date: Fri, 20 Jun 2025 14:16:09 +0200 Subject: [PATCH 15/27] add test on non-square unit cell and fix bug --- src/algorithms/time_evolution/simpleupdate.jl | 10 +++--- .../time_evolution/simpleupdate3site.jl | 2 +- test/examples/heisenberg.jl | 10 ++++-- test/timeevol/cluster_projectors.jl | 33 +++++++++++++++++-- 4 files changed, 43 insertions(+), 12 deletions(-) diff --git a/src/algorithms/time_evolution/simpleupdate.jl b/src/algorithms/time_evolution/simpleupdate.jl index 4129ff46d..a63b8220a 100644 --- a/src/algorithms/time_evolution/simpleupdate.jl +++ b/src/algorithms/time_evolution/simpleupdate.jl @@ -97,9 +97,7 @@ function su_iter( direction == 1 ? gate : gate_mirrored, (CartesianIndex(r, 1), CartesianIndex(r, 2)), ) - ϵ = _su_xbond!( - r, 1, term, peps2, truncation_scheme(trscheme, direction, r, 1) - ) + ϵ = _su_xbond!(r, 1, term, peps2, truncation_scheme(trscheme, 1, r, 1)) peps2.vertices[rp1, 2] = deepcopy(peps2.vertices[r, 1]) peps2.vertices[rp1, 1] = deepcopy(peps2.vertices[r, 2]) peps2.weights[1, rp1, 2] = deepcopy(peps2.weights[1, r, 1]) @@ -111,9 +109,7 @@ function su_iter( direction == 1 ? gate : gate_mirrored, (CartesianIndex(r, c), CartesianIndex(r, c + 1)), ) - ϵ = _su_xbond!( - r, c, term, peps2, truncation_scheme(trscheme, direction, r, c) - ) + ϵ = _su_xbond!(r, c, term, peps2, truncation_scheme(trscheme, 1, r, c)) end end if direction == 2 @@ -192,6 +188,8 @@ function simpleupdate( nnonly = is_nearest_neighbour(ham) use_3site = force_3site || !nnonly @assert !(bipartite && use_3site) "3-site simple update is incompatible with bipartite lattice." + bipartite && + @assert size(peps) == (2, 2) "Bipartite structure is only compatible with square unit cells." if use_3site return _simpleupdate3site(peps, ham, alg; check_interval) else diff --git a/src/algorithms/time_evolution/simpleupdate3site.jl b/src/algorithms/time_evolution/simpleupdate3site.jl index 36934ff0c..8a9d5bbfd 100644 --- a/src/algorithms/time_evolution/simpleupdate3site.jl +++ b/src/algorithms/time_evolution/simpleupdate3site.jl @@ -425,7 +425,7 @@ function su3site_iter( gs = gatempos[i][r, c] trschemes = [ truncation_scheme(trscheme, 1, r, c) - truncation_scheme(trscheme, 2, r, _next(c, Nc)) + truncation_scheme(trscheme, 2, r, _next(c, size(peps2)[2])) ] _su3site_se!(r, c, gs, peps2, trschemes) end diff --git a/test/examples/heisenberg.jl b/test/examples/heisenberg.jl index 6bc0c9a40..e315169e7 100644 --- a/test/examples/heisenberg.jl +++ b/test/examples/heisenberg.jl @@ -75,7 +75,7 @@ end trscheme = SiteDependentTruncation( fill(truncerr(tol) & truncdim(Dbond2), 2, N1, N2) ) - elseif n == 3 + elseif n == 4 trunc_low = truncerr(tol) & truncdim(Dbond2) trunc_high = truncerr(tol) & truncdim(Dbond2 + 1) trscheme = SiteDependentTruncation( @@ -101,11 +101,17 @@ end peps = InfinitePEPS(wpeps) env, = leading_boundary(CTMRGEnv(rand, Float64, peps, Espace), peps; tol=ctmrg_tol) + # Test spaces resulting from a SiteDependentTruncation + @test dim.(domain(peps[1, 1])) == [2, 2, 2, 2] + @test dim.(domain(peps[1, 2])) == [2, 2, 2, 2] + @test dim.(domain(peps[2, 1])) == [2, 3, 2, 3] + @test dim.(domain(peps[2, 2])) == [2, 3, 2, 3] + # measure physical quantities e_site = cost_function(peps, env, ham) / (N1 * N2) @info "Simple update energy = $e_site" # benchmark data from Phys. Rev. B 94, 035133 (2016) - @test isapprox(e_site, -0.6594; atol=1e-3) + @test isapprox(e_site, -0.6594; atol=2e-3) # continue with auto differentiation peps_final, env_final, E_final, = fixedpoint( diff --git a/test/timeevol/cluster_projectors.jl b/test/timeevol/cluster_projectors.jl index 666fc7f16..f84d04922 100644 --- a/test/timeevol/cluster_projectors.jl +++ b/test/timeevol/cluster_projectors.jl @@ -78,7 +78,7 @@ end end @testset "Hubbard model with usual SU and 3-site SU" begin - Nr, Nc = 2, 2 + Nr, Nc = 2, 3 ctmrg_tol = 1e-9 Random.seed!(100) # with U(1) spin rotation symmetry @@ -97,7 +97,7 @@ end for (n, (dt, tol)) in enumerate(zip(dts, tols)) trscheme = truncerr(1e-10) & truncdim(n == 1 ? 4 : 2) alg = SimpleUpdate(dt, tol, maxiter, trscheme) - result = simpleupdate(wpeps, ham, alg; bipartite=true, check_interval=1000) + result = simpleupdate(wpeps, ham, alg; bipartite=false, check_interval=1000) wpeps = result[1] end peps = InfinitePEPS(wpeps) @@ -109,7 +109,7 @@ end # continue with 3-site simple update; energy should not change much dts = [1e-2, 5e-3] tols = [1e-8, 1e-8] - trscheme = SiteDependentTruncation(fill(truncerr(1e-10) & truncdim(2), 2, Nr, Nc)) + trscheme = truncerr(1e-10) & truncdim(2) for (n, (dt, tol)) in enumerate(zip(dts, tols)) alg = SimpleUpdate(dt, tol, maxiter, trscheme) result = simpleupdate(wpeps, ham, alg; check_interval=1000, force_3site=true) @@ -121,4 +121,31 @@ end e_site2 = cost_function(peps, env, ham) / (Nr * Nc) @info "3-site simple update energy = $e_site2" @test e_site ≈ e_site2 atol = 5e-4 + + # continue with 3-site simple update with SiteDependentTruncation and check the spaces. + trunc_low = truncerr(1e-10) & truncdim(2) + trunc_high = truncerr(1e-10) & truncdim(3) + trscheme = SiteDependentTruncation( + reshape( + [ + trunc_low; trunc_high;; trunc_low; trunc_high;;; + trunc_low; trunc_low;; trunc_low; trunc_low;;; + trunc_high; trunc_low;; trunc_high; trunc_low + ], + 2, + 2, + 3, + ), + ) + for (n, (dt, tol)) in enumerate(zip(dts, tols)) + alg = SimpleUpdate(dt, tol, maxiter, trscheme) + result = simpleupdate(wpeps, ham, alg; check_interval=1000, force_3site=true) + wpeps = result[1] + end + @test dim.(domain(wpeps.vertices[1, 1])) == [3, 2, 3, 3] + @test dim.(domain(wpeps.vertices[1, 2])) == [2, 2, 2, 2] + @test dim.(domain(wpeps.vertices[1, 3])) == [2, 3, 2, 2] + @test dim.(domain(wpeps.vertices[2, 1])) == [3, 2, 3, 3] + @test dim.(domain(wpeps.vertices[2, 2])) == [2, 2, 2, 2] + @test dim.(domain(wpeps.vertices[2, 3])) == [2, 3, 2, 2] end From 721cd2b72099ec9930fbdb59619ffdd149ac067e Mon Sep 17 00:00:00 2001 From: sanderdemeyer Date: Fri, 20 Jun 2025 14:42:46 +0200 Subject: [PATCH 16/27] make the new test a separate test to test bipartite=true --- test/timeevol/cluster_projectors.jl | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/test/timeevol/cluster_projectors.jl b/test/timeevol/cluster_projectors.jl index f84d04922..194c2f886 100644 --- a/test/timeevol/cluster_projectors.jl +++ b/test/timeevol/cluster_projectors.jl @@ -78,7 +78,7 @@ end end @testset "Hubbard model with usual SU and 3-site SU" begin - Nr, Nc = 2, 3 + Nr, Nc = 2, 2 ctmrg_tol = 1e-9 Random.seed!(100) # with U(1) spin rotation symmetry @@ -97,7 +97,7 @@ end for (n, (dt, tol)) in enumerate(zip(dts, tols)) trscheme = truncerr(1e-10) & truncdim(n == 1 ? 4 : 2) alg = SimpleUpdate(dt, tol, maxiter, trscheme) - result = simpleupdate(wpeps, ham, alg; bipartite=false, check_interval=1000) + result = simpleupdate(wpeps, ham, alg; bipartite=true, check_interval=1000) wpeps = result[1] end peps = InfinitePEPS(wpeps) @@ -121,7 +121,18 @@ end e_site2 = cost_function(peps, env, ham) / (Nr * Nc) @info "3-site simple update energy = $e_site2" @test e_site ≈ e_site2 atol = 5e-4 +end +@testset "Hubbard model with 3-site SU with SiteDependentTruncation" begin + Nr, Nc = 2, 3 + Random.seed!(100) + # with U(1) spin rotation symmetry + Pspace = hubbard_space(Trivial, U1Irrep) + Vspace = Vect[FermionParity ⊠ U1Irrep]((0, 0) => 2, (1, 1//2) => 1, (1, -1//2) => 1) + wpeps = InfiniteWeightPEPS(rand, Float64, Pspace, Vspace; unitcell=(Nr, Nc)) + ham = real( + hubbard_model(ComplexF64, Trivial, U1Irrep, InfiniteSquare(Nr, Nc); t=1.0, U=8.0) + ) # continue with 3-site simple update with SiteDependentTruncation and check the spaces. trunc_low = truncerr(1e-10) & truncdim(2) trunc_high = truncerr(1e-10) & truncdim(3) @@ -137,6 +148,9 @@ end 3, ), ) + dts = [1e-2, 5e-3] + tols = [1e-8, 1e-8] + maxiter = 10000 for (n, (dt, tol)) in enumerate(zip(dts, tols)) alg = SimpleUpdate(dt, tol, maxiter, trscheme) result = simpleupdate(wpeps, ham, alg; check_interval=1000, force_3site=true) From ad2126647fec26a38d9befc675530c4c43e9eb00 Mon Sep 17 00:00:00 2001 From: Yue Zhengyuan Date: Fri, 20 Jun 2025 21:50:05 +0800 Subject: [PATCH 17/27] Restore old Heisenberg SU-AD test --- test/examples/heisenberg.jl | 30 ++---------------------------- 1 file changed, 2 insertions(+), 28 deletions(-) diff --git a/test/examples/heisenberg.jl b/test/examples/heisenberg.jl index e315169e7..262ba8b28 100644 --- a/test/examples/heisenberg.jl +++ b/test/examples/heisenberg.jl @@ -71,27 +71,7 @@ end maxiter = 5000 for (n, (dt, tol)) in enumerate(zip(dts, tols)) Dbond2 = (n == 2) ? Dbond + 2 : Dbond - if n == 2 - trscheme = SiteDependentTruncation( - fill(truncerr(tol) & truncdim(Dbond2), 2, N1, N2) - ) - elseif n == 4 - trunc_low = truncerr(tol) & truncdim(Dbond2) - trunc_high = truncerr(tol) & truncdim(Dbond2 + 1) - trscheme = SiteDependentTruncation( - reshape( - [ - trunc_low trunc_high trunc_low trunc_high - trunc_low trunc_low trunc_low trunc_low - ], - 2, - 2, - 2, - ), - ) - else - trscheme = truncerr(tol) & truncdim(Dbond2) - end + trscheme = truncerr(1e-10) & truncdim(Dbond2) alg = SimpleUpdate(dt, tol, maxiter, trscheme) result = simpleupdate(wpeps, ham, alg; bipartite=false) wpeps = result[1] @@ -101,17 +81,11 @@ end peps = InfinitePEPS(wpeps) env, = leading_boundary(CTMRGEnv(rand, Float64, peps, Espace), peps; tol=ctmrg_tol) - # Test spaces resulting from a SiteDependentTruncation - @test dim.(domain(peps[1, 1])) == [2, 2, 2, 2] - @test dim.(domain(peps[1, 2])) == [2, 2, 2, 2] - @test dim.(domain(peps[2, 1])) == [2, 3, 2, 3] - @test dim.(domain(peps[2, 2])) == [2, 3, 2, 3] - # measure physical quantities e_site = cost_function(peps, env, ham) / (N1 * N2) @info "Simple update energy = $e_site" # benchmark data from Phys. Rev. B 94, 035133 (2016) - @test isapprox(e_site, -0.6594; atol=2e-3) + @test isapprox(e_site, -0.6594; atol=1e-3) # continue with auto differentiation peps_final, env_final, E_final, = fixedpoint( From 0ff0f7d328c4bf4e308879707ac29395ce8e008d Mon Sep 17 00:00:00 2001 From: Yue Zhengyuan Date: Fri, 20 Jun 2025 22:51:48 +0800 Subject: [PATCH 18/27] Add test of SU with SiteDependentTruncation --- test/runtests.jl | 3 ++ test/timeevol/sitedep_truncation.jl | 54 +++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 test/timeevol/sitedep_truncation.jl diff --git a/test/runtests.jl b/test/runtests.jl index 7d93eda49..787964a9b 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -61,6 +61,9 @@ end @time @safetestset "Cluster truncation with projectors" begin include("timeevol/cluster_projectors.jl") end + @time @safetestset "Time evolution with site-dependent truncation" begin + include("timeevol/sitedep_truncation.jl") + end end if GROUP == "ALL" || GROUP == "UTILITY" @time @safetestset "LocalOperator" begin diff --git a/test/timeevol/sitedep_truncation.jl b/test/timeevol/sitedep_truncation.jl new file mode 100644 index 000000000..ca62daca9 --- /dev/null +++ b/test/timeevol/sitedep_truncation.jl @@ -0,0 +1,54 @@ +using Test +using LinearAlgebra +using Random +using TensorKit +using PEPSKit +using PEPSKit: NORTH, EAST + +function get_bonddims(wpeps::InfiniteWeightPEPS) + xdims = collect(dim(domain(t, EAST)) for t in wpeps.vertices) + ydims = collect(dim(domain(t, NORTH)) for t in wpeps.vertices) + return stack([xdims, ydims]; dims=1) +end + +@testset "Simple update: bipartite 2-site" begin + Nr, Nc = 2, 2 + ham = real(heisenberg_XYZ(InfiniteSquare(Nr, Nc); Jx=1.0, Jy=1.0, Jz=1.0)) + Random.seed!(100) + wpeps0 = InfiniteWeightPEPS(rand, Float64, ℂ^2, ℂ^10; unitcell=(Nr, Nc)) + normalize!.(wpeps0.vertices, Inf) + # set trscheme to be compatible with bipartite structure + bonddims = stack([[6 4; 4 6], [5 7; 7 5]]; dims=1) + trscheme = SiteDependentTruncation(collect(truncdim(d) for d in bonddims)) + alg = SimpleUpdate(1e-2, 1e-14, 4, trscheme) + wpeps, = simpleupdate(wpeps0, ham, alg; bipartite=true) + @test get_bonddims(wpeps) == bonddims + # check bipartite structure is preserved + for col in 1:2 + cp1 = PEPSKit._next(col, 2) + @test ( + wpeps.vertices[1, col] == wpeps.vertices[2, cp1] && + wpeps.weights[1, 1, col] == wpeps.weights[1, 2, cp1] && + wpeps.weights[2, 1, col] == wpeps.weights[2, 2, cp1] + ) + end +end + +@testset "Simple update: generic 2-site and 3-site" begin + Nr, Nc = 3, 4 + ham = real(heisenberg_XYZ(InfiniteSquare(Nr, Nc); Jx=1.0, Jy=1.0, Jz=1.0)) + Random.seed!(100) + wpeps0 = InfiniteWeightPEPS(rand, Float64, ℂ^2, ℂ^10; unitcell=(Nr, Nc)) + normalize!.(wpeps0.vertices, Inf) + # Site dependent truncation + bonddims = rand(2:8, 2, Nr, Nc) + @show bonddims + trscheme = SiteDependentTruncation(collect(truncdim(d) for d in bonddims)) + alg = SimpleUpdate(1e-2, 1e-14, 2, trscheme) + # 2-site SU + wpeps, = simpleupdate(wpeps0, ham, alg; bipartite=false) + @test get_bonddims(wpeps) == bonddims + # 3-site SU + wpeps, = simpleupdate(wpeps0, ham, alg; bipartite=false, force_3site=true) + @test get_bonddims(wpeps) == bonddims +end From 136ec188bed0e8503eaac79dc0c370e994c4d152 Mon Sep 17 00:00:00 2001 From: Yue Zhengyuan Date: Fri, 20 Jun 2025 22:57:23 +0800 Subject: [PATCH 19/27] Add TODO on bipartite check for SiteDependentTruncation --- src/algorithms/time_evolution/simpleupdate.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/algorithms/time_evolution/simpleupdate.jl b/src/algorithms/time_evolution/simpleupdate.jl index a63b8220a..baac7465e 100644 --- a/src/algorithms/time_evolution/simpleupdate.jl +++ b/src/algorithms/time_evolution/simpleupdate.jl @@ -188,8 +188,7 @@ function simpleupdate( nnonly = is_nearest_neighbour(ham) use_3site = force_3site || !nnonly @assert !(bipartite && use_3site) "3-site simple update is incompatible with bipartite lattice." - bipartite && - @assert size(peps) == (2, 2) "Bipartite structure is only compatible with square unit cells." + # TODO: check SiteDependentTruncation is compatible with bipartite structure if use_3site return _simpleupdate3site(peps, ham, alg; check_interval) else From 5b98cc9aa9a9f453a305e369c56d1c7e468555f0 Mon Sep 17 00:00:00 2001 From: Sander De Meyer <74001142+sanderdemeyer@users.noreply.github.com> Date: Tue, 24 Jun 2025 17:10:30 +0200 Subject: [PATCH 20/27] Update src/algorithms/time_evolution/simpleupdate3site.jl Co-authored-by: Yue Zhengyuan --- src/algorithms/time_evolution/simpleupdate3site.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/algorithms/time_evolution/simpleupdate3site.jl b/src/algorithms/time_evolution/simpleupdate3site.jl index 8a9d5bbfd..ab376b4ed 100644 --- a/src/algorithms/time_evolution/simpleupdate3site.jl +++ b/src/algorithms/time_evolution/simpleupdate3site.jl @@ -241,7 +241,6 @@ function _get_allprojs( N = length(Ms) @assert length(trschemes) == N - 1 projs_errs = map(1:(N - 1)) do i - trunc = trschemes[i] trunc = if isa(trschemes[i], FixedSpaceTruncation) V = space(Ms[i + 1], 1) truncspace(isdual(V) ? V' : V) From ec2897c1da5906d6c12ec59e5a2223ddc00c44d8 Mon Sep 17 00:00:00 2001 From: sanderdemeyer Date: Tue, 24 Jun 2025 17:27:09 +0200 Subject: [PATCH 21/27] remove redundant TensorKit. before TruncationScheme --- src/algorithms/time_evolution/simpleupdate3site.jl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/algorithms/time_evolution/simpleupdate3site.jl b/src/algorithms/time_evolution/simpleupdate3site.jl index ab376b4ed..1672e2c5e 100644 --- a/src/algorithms/time_evolution/simpleupdate3site.jl +++ b/src/algorithms/time_evolution/simpleupdate3site.jl @@ -215,7 +215,7 @@ The arrows between `Pa`, `s`, `Pb` are function _proj_from_RL( r::AbstractTensorMap{T,S,1,1}, l::AbstractTensorMap{T,S,1,1}; - trunc::TensorKit.TruncationScheme=notrunc(), + trunc::TruncationScheme=notrunc(), rev::Bool=false, ) where {T<:Number,S<:ElementarySpace} rl = r * l @@ -237,7 +237,7 @@ find all projectors `Pa`, `Pb` and Schmidt weights `wts` on internal bonds. """ function _get_allprojs( Ms, Rs, Ls, trschemes::Vector{E}, revs::Vector{Bool} -) where {E<:TensorKit.TruncationScheme} +) where {E<:TruncationScheme} N = length(Ms) @assert length(trschemes) == N - 1 projs_errs = map(1:(N - 1)) do i @@ -262,7 +262,7 @@ Find projectors to truncate internal bonds of the cluster `Ms` """ function _cluster_truncate!( Ms::Vector{T}, trschemes::Vector{E}, revs::Vector{Bool} -) where {T<:PEPSTensor,E<:TensorKit.TruncationScheme} +) where {T<:PEPSTensor,E<:TruncationScheme} Rs, Ls = _get_allRLs(Ms) Pas, Pbs, wts, ϵs = _get_allprojs(Ms, Rs, Ls, trschemes, revs) # apply projectors @@ -326,7 +326,7 @@ In the cluster, the axes of each PEPSTensor are reordered as """ function apply_gatempo!( Ms::Vector{T1}, gs::Vector{T2}; trschemes::Vector{E} -) where {T1<:PEPSTensor,T2<:AbstractTensorMap,E<:TensorKit.TruncationScheme} +) where {T1<:PEPSTensor,T2<:AbstractTensorMap,E<:TruncationScheme} @assert length(Ms) == length(gs) revs = [isdual(space(M, 1)) for M in Ms[2:end]] @assert !all(revs) @@ -377,7 +377,7 @@ end function _su3site_se!( row::Int, col::Int, gs::Vector{T}, peps::InfiniteWeightPEPS, trschemes::Vector{E} -) where {T<:AbstractTensorMap,E<:TensorKit.TruncationScheme} +) where {T<:AbstractTensorMap,E<:TruncationScheme} Nr, Nc = size(peps) @assert 1 <= row <= Nr && 1 <= col <= Nc rm1, cp1 = _prev(row, Nr), _next(col, Nc) From 0db17a0aab899530a447a85e8689a390ff17071c Mon Sep 17 00:00:00 2001 From: sanderdemeyer Date: Tue, 24 Jun 2025 17:57:33 +0200 Subject: [PATCH 22/27] remove redundant TensorKit. before TruncationScheme bis --- src/algorithms/time_evolution/simpleupdate.jl | 4 ++-- src/algorithms/truncation/bond_truncation.jl | 4 ++-- src/algorithms/truncation/fullenv_truncation.jl | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/algorithms/time_evolution/simpleupdate.jl b/src/algorithms/time_evolution/simpleupdate.jl index baac7465e..db6e0aa49 100644 --- a/src/algorithms/time_evolution/simpleupdate.jl +++ b/src/algorithms/time_evolution/simpleupdate.jl @@ -12,7 +12,7 @@ struct SimpleUpdate dt::Number tol::Float64 maxiter::Int - trscheme::TensorKit.TruncationScheme + trscheme::TruncationScheme end # TODO: add kwarg constructor and SU Defaults @@ -34,7 +34,7 @@ function _su_xbond!( col::Int, gate::AbstractTensorMap{T,S,2,2}, peps::InfiniteWeightPEPS, - trscheme::TensorKit.TruncationScheme, + trscheme::TruncationScheme, ) where {T<:Number,S<:ElementarySpace} Nr, Nc = size(peps) @assert 1 <= row <= Nr && 1 <= col <= Nc diff --git a/src/algorithms/truncation/bond_truncation.jl b/src/algorithms/truncation/bond_truncation.jl index 40f413074..c50e1ac38 100644 --- a/src/algorithms/truncation/bond_truncation.jl +++ b/src/algorithms/truncation/bond_truncation.jl @@ -13,13 +13,13 @@ $(TYPEDFIELDS) The truncation algorithm can be constructed from the following keyword arguments: -* `trscheme::TensorKit.TruncationScheme`: SVD truncation scheme when initilizing the truncated tensors connected by the bond. +* `trscheme::TruncationScheme`: SVD truncation scheme when initilizing the truncated tensors connected by the bond. * `maxiter::Int=50` : Maximal number of ALS iterations. * `tol::Float64=1e-15` : ALS converges when fidelity change between two FET iterations is smaller than `tol`. * `check_interval::Int=0` : Set number of iterations to print information. Output is suppressed when `check_interval <= 0`. """ @kwdef struct ALSTruncation - trscheme::TensorKit.TruncationScheme + trscheme::TruncationScheme maxiter::Int = 50 tol::Float64 = 1e-15 check_interval::Int = 0 diff --git a/src/algorithms/truncation/fullenv_truncation.jl b/src/algorithms/truncation/fullenv_truncation.jl index 7856f499b..f3fa336b3 100644 --- a/src/algorithms/truncation/fullenv_truncation.jl +++ b/src/algorithms/truncation/fullenv_truncation.jl @@ -13,7 +13,7 @@ $(TYPEDFIELDS) The truncation algorithm can be constructed from the following keyword arguments: -* `trscheme::TensorKit.TruncationScheme` : SVD truncation scheme when optimizing the new bond matrix. +* `trscheme::TruncationScheme` : SVD truncation scheme when optimizing the new bond matrix. * `maxiter::Int=50` : Maximal number of FET iterations. * `tol::Float64=1e-15` : FET converges when fidelity change between two FET iterations is smaller than `tol`. * `trunc_init::Bool=true` : Controls whether the initialization of the new bond matrix is obtained from truncated SVD of the old bond matrix. @@ -24,7 +24,7 @@ The truncation algorithm can be constructed from the following keyword arguments * [Glen Evenbly, Phys. Rev. B 98, 085155 (2018)](@cite evenbly_gauge_2018). """ @kwdef struct FullEnvTruncation - trscheme::TensorKit.TruncationScheme + trscheme::TruncationScheme maxiter::Int = 50 tol::Float64 = 1e-15 trunc_init::Bool = true From 1707d3c7fb42456f4514fc8e1ac2f7673f3b69c4 Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Tue, 24 Jun 2025 14:29:20 -0400 Subject: [PATCH 23/27] remove redundant where clauses --- .../truncation/truncationschemes.jl | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/algorithms/truncation/truncationschemes.jl b/src/algorithms/truncation/truncationschemes.jl index cc6cfaf2c..16f19bc16 100644 --- a/src/algorithms/truncation/truncationschemes.jl +++ b/src/algorithms/truncation/truncationschemes.jl @@ -7,8 +7,8 @@ have different spaces, this truncation style is different from `TruncationSpace` """ struct FixedSpaceTruncation <: TruncationScheme end -struct SiteDependentTruncation <: TruncationScheme - trschemes::Array{T,3} where {T<:TruncationScheme} +struct SiteDependentTruncation{T<:TruncationScheme} <: TruncationScheme + trschemes::Array{T,3} end const TRUNCATION_SCHEME_SYMBOLS = IdDict{Symbol,Type{<:TruncationScheme}}( @@ -31,8 +31,8 @@ function _TruncationScheme(; alg=Defaults.trscheme, η=nothing) end function truncation_scheme( - trscheme::T, direction::Int, row::Int, col::Int; kwargs... -) where {T<:TruncationScheme} + trscheme::TruncationScheme, direction::Int, row::Int, col::Int; kwargs... +) return trscheme end @@ -45,10 +45,8 @@ end # Mirror a TruncationScheme by its anti-diagonal line. # When the number of directions is 2, it swaps the first and second direction, consistent with xbonds and ybonds, respectively. # When the number of directions is 4, it swaps the first and second, and third and fourth directions, consistent with the order NORTH, EAST, SOUTH, WEST. -function mirror_antidiag(trscheme::T) where {T<:TruncationScheme} - return trscheme -end -function mirror_antidiag(trscheme::T) where {T<:SiteDependentTruncation} +mirror_antidiag(trscheme::TruncationScheme) = trscheme +function mirror_antidiag(trscheme::SiteDependentTruncation) directions = size(trscheme.trschemes)[1] if directions == 2 trschemes_mirrored = stack( @@ -72,11 +70,9 @@ function mirror_antidiag(trscheme::T) where {T<:SiteDependentTruncation} end # TODO: type piracy -function Base.rotl90(trscheme::T) where {T<:TruncationScheme} - return trscheme -end +Base.rotl90(trscheme::TruncationScheme) = trscheme -function Base.rotl90(trscheme::T) where {T<:SiteDependentTruncation} +function Base.rotl90(trscheme::SiteDependentTruncation) directions = size(trscheme.trschemes)[1] trschemes_rotated = permutedims(trscheme.trschemes, (1, 3, 2)) if directions == EAST From 6854da9b11c72e140b8f491e5701b5ee0cf6efb7 Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Tue, 24 Jun 2025 14:29:33 -0400 Subject: [PATCH 24/27] Add selection support with symbol --- src/algorithms/truncation/truncationschemes.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/algorithms/truncation/truncationschemes.jl b/src/algorithms/truncation/truncationschemes.jl index 16f19bc16..902588bce 100644 --- a/src/algorithms/truncation/truncationschemes.jl +++ b/src/algorithms/truncation/truncationschemes.jl @@ -18,6 +18,7 @@ const TRUNCATION_SCHEME_SYMBOLS = IdDict{Symbol,Type{<:TruncationScheme}}( :truncdim => TensorKit.TruncationDimension, :truncspace => TensorKit.TruncationSpace, :truncbelow => TensorKit.TruncationCutoff, + :sitedependent => SiteDependentTruncation, ) # Should be TruncationScheme but rename to avoid type piracy From 4eee139d377fe62bbc17a2c525ad23e6408e919f Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Tue, 24 Jun 2025 14:31:28 -0400 Subject: [PATCH 25/27] Change back constant --- src/algorithms/truncation/truncationschemes.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algorithms/truncation/truncationschemes.jl b/src/algorithms/truncation/truncationschemes.jl index 902588bce..5df4cf341 100644 --- a/src/algorithms/truncation/truncationschemes.jl +++ b/src/algorithms/truncation/truncationschemes.jl @@ -76,7 +76,7 @@ Base.rotl90(trscheme::TruncationScheme) = trscheme function Base.rotl90(trscheme::SiteDependentTruncation) directions = size(trscheme.trschemes)[1] trschemes_rotated = permutedims(trscheme.trschemes, (1, 3, 2)) - if directions == EAST + if directions == 2 trschemes_rotated[NORTH, :, :] = circshift( rotl90(trscheme.trschemes[EAST, :, :]), (0, -1) ) From 615fa7f3a80fb823f69543162334a806e977f05e Mon Sep 17 00:00:00 2001 From: Lukas Devos Date: Tue, 24 Jun 2025 14:35:39 -0400 Subject: [PATCH 26/27] Also simplify rotation --- src/algorithms/truncation/truncationschemes.jl | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/algorithms/truncation/truncationschemes.jl b/src/algorithms/truncation/truncationschemes.jl index 5df4cf341..3420c90b3 100644 --- a/src/algorithms/truncation/truncationschemes.jl +++ b/src/algorithms/truncation/truncationschemes.jl @@ -74,20 +74,21 @@ end Base.rotl90(trscheme::TruncationScheme) = trscheme function Base.rotl90(trscheme::SiteDependentTruncation) - directions = size(trscheme.trschemes)[1] - trschemes_rotated = permutedims(trscheme.trschemes, (1, 3, 2)) + directions, rows, cols = size(trscheme.trschemes) + trschemes_rotated = similar(trscheme.trschemes, directions, cols, rows) + if directions == 2 trschemes_rotated[NORTH, :, :] = circshift( rotl90(trscheme.trschemes[EAST, :, :]), (0, -1) ) trschemes_rotated[EAST, :, :] = rotl90(trscheme.trschemes[NORTH, :, :]) elseif directions == 4 - trschemes_rotated[NORTH, :, :] = rotl90(trscheme.trschemes[EAST, :, :]) - trschemes_rotated[EAST, :, :] = rotl90(trscheme.trschemes[SOUTH, :, :]) - trschemes_rotated[SOUTH, :, :] = rotl90(trscheme.trschemes[WEST, :, :]) - trschemes_rotated[WEST, :, :] = rotl90(trscheme.trschemes[NORTH, :, :]) + for dir in 1:4 + dir′ = _prev(dir, 4) + trschemes_rotated[dir′, :, :] = rotl90(trscheme.trschemes[dir, :, :]) + end else - error("Unsupported number of directions for rotl90: $directions") + throw(ArgumentError("Unsupported number of directions for rotl90: $directions")) end return SiteDependentTruncation(trschemes_rotated) end From e70759acc6f6159c8077b1a77cdab1a48359c284 Mon Sep 17 00:00:00 2001 From: Yue Zhengyuan Date: Wed, 25 Jun 2025 08:54:16 +0800 Subject: [PATCH 27/27] Remove test on Hubbard SU with SiteDependentTruncation --- test/timeevol/cluster_projectors.jl | 41 ----------------------------- 1 file changed, 41 deletions(-) diff --git a/test/timeevol/cluster_projectors.jl b/test/timeevol/cluster_projectors.jl index 194c2f886..91b2994e8 100644 --- a/test/timeevol/cluster_projectors.jl +++ b/test/timeevol/cluster_projectors.jl @@ -122,44 +122,3 @@ end @info "3-site simple update energy = $e_site2" @test e_site ≈ e_site2 atol = 5e-4 end - -@testset "Hubbard model with 3-site SU with SiteDependentTruncation" begin - Nr, Nc = 2, 3 - Random.seed!(100) - # with U(1) spin rotation symmetry - Pspace = hubbard_space(Trivial, U1Irrep) - Vspace = Vect[FermionParity ⊠ U1Irrep]((0, 0) => 2, (1, 1//2) => 1, (1, -1//2) => 1) - wpeps = InfiniteWeightPEPS(rand, Float64, Pspace, Vspace; unitcell=(Nr, Nc)) - ham = real( - hubbard_model(ComplexF64, Trivial, U1Irrep, InfiniteSquare(Nr, Nc); t=1.0, U=8.0) - ) - # continue with 3-site simple update with SiteDependentTruncation and check the spaces. - trunc_low = truncerr(1e-10) & truncdim(2) - trunc_high = truncerr(1e-10) & truncdim(3) - trscheme = SiteDependentTruncation( - reshape( - [ - trunc_low; trunc_high;; trunc_low; trunc_high;;; - trunc_low; trunc_low;; trunc_low; trunc_low;;; - trunc_high; trunc_low;; trunc_high; trunc_low - ], - 2, - 2, - 3, - ), - ) - dts = [1e-2, 5e-3] - tols = [1e-8, 1e-8] - maxiter = 10000 - for (n, (dt, tol)) in enumerate(zip(dts, tols)) - alg = SimpleUpdate(dt, tol, maxiter, trscheme) - result = simpleupdate(wpeps, ham, alg; check_interval=1000, force_3site=true) - wpeps = result[1] - end - @test dim.(domain(wpeps.vertices[1, 1])) == [3, 2, 3, 3] - @test dim.(domain(wpeps.vertices[1, 2])) == [2, 2, 2, 2] - @test dim.(domain(wpeps.vertices[1, 3])) == [2, 3, 2, 2] - @test dim.(domain(wpeps.vertices[2, 1])) == [3, 2, 3, 3] - @test dim.(domain(wpeps.vertices[2, 2])) == [2, 2, 2, 2] - @test dim.(domain(wpeps.vertices[2, 3])) == [2, 3, 2, 2] -end