From 4ebcbec71cd6dd8c70f2bcbf161b41f5b4a07b93 Mon Sep 17 00:00:00 2001 From: leburgel Date: Tue, 9 Jul 2024 16:57:49 +0200 Subject: [PATCH 1/8] Fix unit cell indexing in `CTMRGEnv` constructor --- src/environments/ctmrgenv.jl | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/environments/ctmrgenv.jl b/src/environments/ctmrgenv.jl index fd2bf4c4..9945816b 100644 --- a/src/environments/ctmrgenv.jl +++ b/src/environments/ctmrgenv.jl @@ -22,21 +22,30 @@ function CTMRGEnv(peps::InfinitePEPS{P}; Venv=oneunit(spacetype(P))) where {P} corners = Array{C_type}(undef, 4, size(peps)...) edges = Array{T_type}(undef, 4, size(peps)...) - for dir in 1:4, i in 1:size(peps, 1), j in 1:size(peps, 2) - @diffset corners[dir, i, j] = TensorMap(randn, scalartype(P), Venv, Venv) - @diffset edges[dir, i, j] = TensorMap( - randn, - scalartype(P), - Venv * space(peps[i, j], dir + 1)' * space(peps[i, j], dir + 1), - Venv, + for (r, c) in Iterators.product(axes(peps)...) + for dir in 1:4 + corners[dir, r, c] = TensorMap(randn, scalartype(P), Venv, Venv) + end + edges[NORTH, _prev(r, end), c] = TensorMap( + randn, scalartype(P), Venv * space(peps[r, c], 2)' * space(peps[r, c], 2), Venv + ) + edges[EAST, r, _next(c, end)] = TensorMap( + randn, scalartype(P), Venv * space(peps[r, c], 3)' * space(peps[r, c], 3), Venv + ) + edges[SOUTH, _next(r, end), c] = TensorMap( + randn, scalartype(P), Venv * space(peps[r, c], 4)' * space(peps[r, c], 4), Venv + ) + edges[WEST, r, _prev(c, end)] = TensorMap( + randn, scalartype(P), Venv * space(peps[r, c], 5)' * space(peps[r, c], 5), Venv ) end - @diffset corners[:, :, :] ./= norm.(corners[:, :, :]) - @diffset edges[:, :, :] ./= norm.(edges[:, :, :]) + corners[:, :, :] ./= norm.(corners[:, :, :]) + edges[:, :, :] ./= norm.(edges[:, :, :]) return CTMRGEnv(corners, edges) end +@non_differentiable CTMRGEnv(peps::InfinitePEPS) # Custom adjoint for CTMRGEnv constructor, needed for fixed-point differentiation function ChainRulesCore.rrule(::Type{CTMRGEnv}, corners, edges) From 574fc76263c7ad51cecfe1d93df86ad51b5d83de Mon Sep 17 00:00:00 2001 From: leburgel Date: Wed, 10 Jul 2024 17:45:31 +0200 Subject: [PATCH 2/8] Extend `CTMRGEnv` constructor --- README.md | 2 +- docs/src/index.md | 2 +- examples/boundary_mps.jl | 4 +- examples/heisenberg.jl | 2 +- src/algorithms/ctmrg.jl | 2 +- src/algorithms/peps_opt.jl | 2 +- src/environments/ctmrgenv.jl | 270 ++++++++++++++++++++++++++++++++--- test/boundarymps/vumps.jl | 4 +- test/ctmrg/gaugefix.jl | 4 +- test/ctmrg/gradients.jl | 2 +- test/ctmrg/gradparts.jl | 2 +- test/ctmrg/unitcell.jl | 111 +++++++++----- test/heisenberg.jl | 4 +- test/pwave.jl | 2 +- test/runtests.jl | 3 + test/tf_ising.jl | 2 +- 16 files changed, 343 insertions(+), 75 deletions(-) diff --git a/README.md b/README.md index a45818d6..80e6fec0 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ opt_alg = PEPSOptimize(; # ground state search state = InfinitePEPS(2, D) -ctm = leading_boundary(CTMRGEnv(state; Venv=ComplexSpace(chi)), state, ctm_alg) +ctm = leading_boundary(CTMRGEnv(state, ComplexSpace(chi)), state, ctm_alg) result = fixedpoint(state, Heisenberg_hamiltonian, opt_alg, ctm) @show result.E # -0.6625... diff --git a/docs/src/index.md b/docs/src/index.md index 305f6d84..3f199114 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -44,7 +44,7 @@ opt_alg = PEPSOptimize(; # ground state search state = InfinitePEPS(2, D) -ctm = leading_boundary(CTMRGEnv(state; Venv=ComplexSpace(chi)), state, ctm_alg) +ctm = leading_boundary(CTMRGEnv(state, ComplexSpace(chi)), state, ctm_alg) result = fixedpoint(state, Heisenberg_hamiltonian, opt_alg, ctm) @show result.E # -0.6625... diff --git a/examples/boundary_mps.jl b/examples/boundary_mps.jl index abd52e17..6f6c1899 100644 --- a/examples/boundary_mps.jl +++ b/examples/boundary_mps.jl @@ -33,7 +33,7 @@ N = abs(prod(expectation_value(mps, T))) # This can be compared to the result obtained using the CTMRG algorithm ctm = leading_boundary( - peps, CTMRG(; verbosity=1, fixedspace=true), CTMRGEnv(peps; Venv=ComplexSpace(20)) + peps, CTMRG(; verbosity=1, fixedspace=true), CTMRGEnv(peps, ComplexSpace(20)) ) N´ = abs(norm(peps, ctm)) @@ -56,7 +56,7 @@ mps2, envs2, ϵ = leading_boundary(mps2, T2, VUMPS()) N2 = abs(prod(expectation_value(mps2, T2))) ctm2 = leading_boundary( - peps2, CTMRG(; verbosity=1, fixedspace=true), CTMRGEnv(peps2; Venv=ComplexSpace(20)) + peps2, CTMRG(; verbosity=1, fixedspace=true), CTMRGEnv(peps2, ComplexSpace(20)) ) N2´ = abs(norm(peps2, ctm2)) diff --git a/examples/heisenberg.jl b/examples/heisenberg.jl index 0cfd8c06..4d981ddd 100644 --- a/examples/heisenberg.jl +++ b/examples/heisenberg.jl @@ -27,6 +27,6 @@ alg = PEPSOptimize(; # E/N = −0.6694421, which is a QMC estimate from https://arxiv.org/abs/1101.3281. # Of course there is a noticable bias for small χbond and χenv. ψ₀ = InfinitePEPS(2, χbond) -env₀ = leading_boundary(CTMRGEnv(ψ₀; Venv=ℂ^χenv), ψ₀, ctmalg) +env₀ = leading_boundary(CTMRGEnv(ψ₀, ℂ^χenv), ψ₀, ctmalg) result = fixedpoint(ψ₀, H, alg, env₀) @show result.E diff --git a/src/algorithms/ctmrg.jl b/src/algorithms/ctmrg.jl index b86ccfc8..badd71f3 100644 --- a/src/algorithms/ctmrg.jl +++ b/src/algorithms/ctmrg.jl @@ -28,7 +28,7 @@ Contract `state` using CTMRG and return the CTM environment. Per default, a random initial environment is used. """ function MPSKit.leading_boundary(state, alg::CTMRG) - return MPSKit.leading_boundary(CTMRGEnv(state), state, alg) + return MPSKit.leading_boundary(CTMRGEnv(state, oneunit(spacetype(state))), state, alg) end function MPSKit.leading_boundary(envinit, state, alg::CTMRG) normold = 1.0 diff --git a/src/algorithms/peps_opt.jl b/src/algorithms/peps_opt.jl index cdee687f..c8b205a3 100644 --- a/src/algorithms/peps_opt.jl +++ b/src/algorithms/peps_opt.jl @@ -60,7 +60,7 @@ in `alg`. The initial environment `env₀` serves as an initial guess for the fi By default, a random initial environment is used. """ function fixedpoint( - ψ₀::InfinitePEPS{T}, H, alg::PEPSOptimize, env₀::CTMRGEnv=CTMRGEnv(ψ₀; Venv=field(T)^20) + ψ₀::InfinitePEPS{T}, H, alg::PEPSOptimize, env₀::CTMRGEnv=CTMRGEnv(ψ₀, field(T)^20) ) where {T} (peps, env), E, ∂E, info = optimize( (ψ₀, env₀), alg.optimizer; retract=my_retract, inner=my_inner diff --git a/src/environments/ctmrgenv.jl b/src/environments/ctmrgenv.jl index 9945816b..85d6ab29 100644 --- a/src/environments/ctmrgenv.jl +++ b/src/environments/ctmrgenv.jl @@ -8,36 +8,124 @@ struct CTMRGEnv{C,T} edges::Array{T,3} end +_spacetype(::Int) = ComplexSpace +_spacetype(::S) where {S<:ElementarySpace} = S + +_to_space(χ::Int) = ℂ^χ +_to_space(χ::ElementarySpace) = χ + +function _corner_tensor( + f, ::Type{T}, left_vspace::S, right_vspace::S=left_vspace +) where {T,S<:ElementarySpace} + return TensorMap(f, T, left_vspace ← right_vspace) +end +function _corner_tensor( + f, ::Type{T}, left_vspace::Int, right_vspace::Int=left_vspace +) where {T} + return _corner_tensor(f, T, _to_space(left_vspace), _to_space(right_vspace)) +end + +function _edge_tensor( + f, + ::Type{T}, + left_vspace::S, + top_pspace::S, + bot_pspace::S=top_pspace, + right_vspace::S=left_vspace, +) where {T,S<:ElementarySpace} + return TensorMap(f, T, left_vspace ⊗ top_pspace ⊗ dual(bot_pspace) ← right_vspace) +end +function _edge_tensor( + f, + ::Type{T}, + left_vspace::Int, + top_pspace::Int, + bot_pspace::Int, + right_vspace::Int=left_vspace, +) where {T} + return _edge_tensor( + f, + T, + _to_space(left_vspace), + _to_space(top_pspace), + _to_space(bot_pspace), + _to_space(right_vspace), + ) +end + """ - CTMRGEnv(peps::InfinitePEPS{P}; Venv=oneunit(spacetype(P))) + CTMRGEnv( + [f=randn, ComplexF64], Ds_east::A, chis_north::A, chis_east::A, chis_south::A, chis_west::A + ) where {A<:AbstractMatrix{<:Union{Int,ElementarySpace}}} -Create a random CTMRG environment from a PEPS tensor. The environment bond dimension -defaults to one and can be specified using the `Venv` space. +TODO: docstring. """ -function CTMRGEnv(peps::InfinitePEPS{P}; Venv=oneunit(spacetype(P))) where {P} - C_type = tensormaptype(spacetype(P), 1, 1, storagetype(P)) - T_type = tensormaptype(spacetype(P), 3, 1, storagetype(P)) +function CTMRGEnv( + Ds_north::A, Ds_east::A, chis_north::A, chis_east::A, chis_south::A, chis_west::A +) where {A<:AbstractMatrix{<:Union{Int,ElementarySpace}}} + return CTMRGEnv( + randn, ComplexF64, Ds_north, Ds_east, chis_north, chis_east, chis_south, chis_west + ) +end +function CTMRGEnv( + f, T, Ds_north::A, Ds_east::A, chis_north::A, chis_east::A, chis_south::A, chis_west::A +) where {A<:AbstractMatrix{<:Union{Int,ElementarySpace}}} + Ds_south = adjoint.(circshift(Ds_north, (-1, 0))) + Ds_west = adjoint.(circshift(Ds_east, (0, 1))) + + # do the whole thing + st = _spacetype(first(Ds_north)) + C_type = tensormaptype(st, 1, 1, T) + T_type = tensormaptype(st, 3, 1, T) # First index is direction - corners = Array{C_type}(undef, 4, size(peps)...) - edges = Array{T_type}(undef, 4, size(peps)...) + corners = Array{C_type}(undef, 4, size(Ds_north)...) + edges = Array{T_type}(undef, 4, size(Ds_north)...) - for (r, c) in Iterators.product(axes(peps)...) - for dir in 1:4 - corners[dir, r, c] = TensorMap(randn, scalartype(P), Venv, Venv) - end - edges[NORTH, _prev(r, end), c] = TensorMap( - randn, scalartype(P), Venv * space(peps[r, c], 2)' * space(peps[r, c], 2), Venv + for (r, c) in Iterators.product(axes(Ds_north)...) + edges[NORTH, r, c] = _edge_tensor( + f, + 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( + f, + T, + chis_east[r, c], + Ds_east[r, _prev(c, end)], + Ds_east[r, _prev(c, end)], + chis_east[_next(r, end), c], ) - edges[EAST, r, _next(c, end)] = TensorMap( - randn, scalartype(P), Venv * space(peps[r, c], 3)' * space(peps[r, c], 3), Venv + edges[SOUTH, r, c] = _edge_tensor( + f, + T, + chis_south[r, c], + Ds_south[_prev(r, end), c], + Ds_south[_prev(r, end), c], + chis_south[r, _prev(c, end)], ) - edges[SOUTH, _next(r, end), c] = TensorMap( - randn, scalartype(P), Venv * space(peps[r, c], 4)' * space(peps[r, c], 4), Venv + edges[WEST, r, c] = _edge_tensor( + f, + T, + chis_west[_next(r, end), c], + Ds_west[r, _next(c, end)], + Ds_west[r, _next(c, end)], + chis_west[r, c], + ) + + corners[NORTHWEST, r, c] = _corner_tensor( + f, T, chis_west[_next(r, end), c], chis_north[r, c] ) - edges[WEST, r, _prev(c, end)] = TensorMap( - randn, scalartype(P), Venv * space(peps[r, c], 5)' * space(peps[r, c], 5), Venv + corners[NORTHEAST, r, c] = _corner_tensor( + f, T, chis_north[r, _prev(c, end)], chis_east[_next(r, end), c] ) + corners[SOUTHEAST, r, c] = _corner_tensor( + f, T, chis_east[r, c], chis_south[r, _prev(c, end)] + ) + corners[SOUTHWEST, r, c] = _corner_tensor(f, T, chis_south[r, c], chis_west[r, c]) end corners[:, :, :] ./= norm.(corners[:, :, :]) @@ -45,7 +133,147 @@ function CTMRGEnv(peps::InfinitePEPS{P}; Venv=oneunit(spacetype(P))) where {P} return CTMRGEnv(corners, edges) end -@non_differentiable CTMRGEnv(peps::InfinitePEPS) + +""" + CTMRGEnv( + [f=randn, ComplexF64], D_north::S, D_south::S, chi_north::S, chi_east::S, chi_south::S, chi_west::S; unitcell::Tuple{Int,Int}=(1, 1), + ) where {S<:Union{Int,ElementarySpace}} + +TODO: docstring. +""" +function CTMRGEnv( + D_north::S, + D_south::S, + chi_north::S, + chi_east::S, + chi_south::S, + chi_west::S; + unitcell::Tuple{Int,Int}=(1, 1), +) where {S<:Union{Int,ElementarySpace}} + return CTMRGEnv( + randn, + ComplexF64, + fill(D_north, unitcell), + fill(D_south, unitcell), + fill(chi_north, unitcell), + fill(chi_east, unitcell), + fill(chi_south, unitcell), + fill(chi_west, unitcell), + ) +end +function CTMRGEnv( + f, + T, + D_north::S, + D_south::S, + chi_north::S, + chi_east::S, + chi_south::S, + chi_west::S; + unitcell::Tuple{Int,Int}=(1, 1), +) where {S<:Union{Int,ElementarySpace}} + return CTMRGEnv( + f, + T, + fill(D_north, unitcell), + fill(D_south, unitcell), + fill(chi_north, unitcell), + fill(chi_east, unitcell), + fill(chi_south, unitcell), + fill(chi_west, unitcell), + ) +end + +""" + function CTMRGEnv( + [f=randn, T=ComplexF64], peps::InfinitePEPS, chis_north::A, chis_east::A, chis_south::A, chis_west::A + ) where {A<:AbstractMatrix{<:Union{Int,ElementarySpace}}} + +TODO: docstring. +""" +function CTMRGEnv( + peps::InfinitePEPS, chis_north::A, chis_east::A, chis_south::A, chis_west::A +) where {A<:AbstractMatrix{<:Union{Int,ElementarySpace}}} + Ds_north = map(peps.A) do t + return adjoint(space(t, 2)) + end + Ds_east = map(peps.A) do t + return adjoint(space(t, 3)) + 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, peps::InfinitePEPS, chis_north::A, chis_east::A, chis_south::A, chis_west::A +) where {A<:AbstractMatrix{<:Union{Int,ElementarySpace}}} + Ds_north = map(peps.A) do t + return adjoint(space(t, 2)) + end + Ds_east = map(peps.A) do t + return adjoint(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 + +""" +function CTMRGEnv( + peps::InfinitePEPS, chi_north::S, chi_east::S=chi_north, chi_south::S=chi_north, chi_west::S=chi_north, +) where {S<:Union{Int,ElementarySpace}} + +TODO: docstring. +""" +function CTMRGEnv( + peps::InfinitePEPS, + chi_north::S, + chi_east::S=chi_north, + chi_south::S=chi_north, + chi_west::S=chi_north, +) where {S<:Union{Int,ElementarySpace}} + return CTMRGEnv( + peps, + fill(chi_north, size(peps)), + fill(chi_east, size(peps)), + fill(chi_south, size(peps)), + fill(chi_west, size(peps)), + ) +end +function CTMRGEnv( + f, + T, + peps::InfinitePEPS, + chi_north::S, + chi_east::S=chi_north, + chi_south::S=chi_north, + chi_west::S=chi_north, +) where {S<:Union{Int,ElementarySpace}} + return CTMRGEnv( + f, + T, + peps, + fill(chi_north, size(peps)), + fill(chi_east, size(peps)), + fill(chi_south, size(peps)), + fill(chi_west, size(peps)), + ) +end +@non_differentiable CTMRGEnv(peps::InfinitePEPS, args...) # Custom adjoint for CTMRGEnv constructor, needed for fixed-point differentiation function ChainRulesCore.rrule(::Type{CTMRGEnv}, corners, edges) diff --git a/test/boundarymps/vumps.jl b/test/boundarymps/vumps.jl index bbf69006..d9992c12 100644 --- a/test/boundarymps/vumps.jl +++ b/test/boundarymps/vumps.jl @@ -18,7 +18,7 @@ const vumps_alg = VUMPS(; alg_eigsolve=MPSKit.Defaults.alg_eigsolve(; ishermitia N = abs(sum(expectation_value(mps, T))) ctm = leading_boundary( - CTMRGEnv(psi; Venv=ComplexSpace(20)), psi, CTMRG(; verbosity=1, fixedspace=true) + CTMRGEnv(psi, ComplexSpace(20)), psi, CTMRG(; verbosity=1, fixedspace=true) ) N´ = abs(norm(psi, ctm)) @@ -34,7 +34,7 @@ end N = abs(prod(expectation_value(mps, T))) ctm = leading_boundary( - CTMRGEnv(psi; Venv=ComplexSpace(20)), psi, CTMRG(; verbosity=1, fixedspace=true) + CTMRGEnv(psi, ComplexSpace(20)), psi, CTMRG(; verbosity=1, fixedspace=true) ) N´ = abs(norm(psi, ctm)) diff --git a/test/ctmrg/gaugefix.jl b/test/ctmrg/gaugefix.jl index 45bee5d5..c8afb5ca 100644 --- a/test/ctmrg/gaugefix.jl +++ b/test/ctmrg/gaugefix.jl @@ -42,7 +42,7 @@ end psi = _make_symmetric(psi) Random.seed!(987654321) # Seed RNG to make random environment consistent - ctm = CTMRGEnv(psi; Venv=ctm_space) + ctm = CTMRGEnv(psi, ctm_space) verbosity = 1 alg = CTMRG(; @@ -67,7 +67,7 @@ end psi = _make_symmetric(psi) Random.seed!(123456789) # Seed RNG to make random environment consistent - ctm = CTMRGEnv(psi; Venv=ctm_space) + ctm = CTMRGEnv(psi, ctm_space) verbosity = 1 alg = CTMRG(; diff --git a/test/ctmrg/gradients.jl b/test/ctmrg/gradients.jl index 1c81063a..301d7b5f 100644 --- a/test/ctmrg/gradients.jl +++ b/test/ctmrg/gradients.jl @@ -38,7 +38,7 @@ steps = -0.01:0.005:0.01 @testset "$alg_rrule" for alg_rrule in gradmodes dir = InfinitePEPS(Pspace, Vspace, Vspace) psi = InfinitePEPS(Pspace, Vspace, Vspace) - env = leading_boundary(CTMRGEnv(psi; Venv=Espace), psi, boundary_alg) + env = leading_boundary(CTMRGEnv(psi, Espace), psi, boundary_alg) alphas, fs, dfs1, dfs2 = OptimKit.optimtest( (psi, env), dir; diff --git a/test/ctmrg/gradparts.jl b/test/ctmrg/gradparts.jl index c21a2420..a03c6466 100644 --- a/test/ctmrg/gradparts.jl +++ b/test/ctmrg/gradparts.jl @@ -56,7 +56,7 @@ end Pspaces ) psi = InfinitePEPS(Pspaces[i], Vspaces[i], Vspaces[i]) - env = CTMRGEnv(psi; Venv=Espaces[i]) + env = CTMRGEnv(psi, Espaces[i]) @testset "$f" for f in functions atol = f == leading_boundary ? sqrt(tol) : tol diff --git a/test/ctmrg/unitcell.jl b/test/ctmrg/unitcell.jl index 9d8cad8a..30103665 100644 --- a/test/ctmrg/unitcell.jl +++ b/test/ctmrg/unitcell.jl @@ -4,48 +4,85 @@ using PEPSKit using PEPSKit: _prev, _next, ctmrg_iter using TensorKit -# initialize (3, 3) PEPS with unique N and E bond spaces +# settings Random.seed!(91283219347) -unitcell = (3, 3) -Pspace = ℂ^2 -Nspace = ℂ^2 -Espace = ℂ^3 stype = ComplexF64 -peps = InfinitePEPS(randn, stype, Pspace, Nspace, Espace; unitcell) - -# initialize (3, 3) environment with unique environment spaces -C_type = tensormaptype(spacetype(peps[1]), 1, 1, storagetype(peps[1])) -T_type = tensormaptype(spacetype(peps[1]), 3, 1, storagetype(peps[1])) -corners = Array{C_type}(undef, 4, unitcell...) -edges = Array{T_type}(undef, 4, unitcell...) -for r in 1:unitcell[1], c in 1:unitcell[2] - corners[1, _prev(r, end), _prev(c, end)] = TensorMap(randn, stype, ℂ^5, ℂ^2) - edges[1, _prev(r, end), c] = TensorMap( - randn, stype, ℂ^2 * space(peps[r, c], 1 + 1)' * space(peps[r, c], 1 + 1), ℂ^2 - ) - corners[2, _prev(r, end), _next(c, end)] = TensorMap(randn, stype, ℂ^2, ℂ^3) - edges[2, r, _next(c, end)] = TensorMap( - randn, stype, ℂ^3 * space(peps[r, c], 2 + 1)' * space(peps[r, c], 2 + 1), ℂ^3 +ctm_alg = CTMRG(; fixedspace=true) + +function test_unitcell( + unitcell, Pspaces, Nspaces, Espaces, chis_north, chis_east, chis_south, chis_west +) + peps = InfinitePEPS(randn, stype, Pspaces, Nspaces, Espaces) + env = CTMRGEnv(randn, stype, peps, chis_north, chis_east, chis_south, chis_west) + + # apply one CTMRG iteration with fixeds + env′, = ctmrg_iter(peps, env, ctm_alg) + + # compute random expecation value to test matching bonds + random_op = LocalOperator( + PEPSKit._to_space.(Pspaces), + [ + (c,) => TensorMap( + randn, + scalartype(peps), + PEPSKit._to_space(Pspaces[c]), + PEPSKit._to_space(Pspaces[c]), + ) for c in CartesianIndices(unitcell) + ]..., ) - corners[3, _next(r, end), _next(c, end)] = TensorMap(randn, stype, ℂ^3, ℂ^4) - edges[3, _next(r, end), c] = TensorMap( - randn, stype, ℂ^4 * space(peps[r, c], 3 + 1)' * space(peps[r, c], 3 + 1), ℂ^4 + @test expectation_value(peps, random_op, env) isa Number + @test expectation_value(peps, random_op, env′) isa Number +end + +function random_dualize!(M::AbstractMatrix{<:ElementarySpace}) + mask = rand([true, false], size(M)) + M[mask] .= adjoint.(M[mask]) + return M +end + +@testset "Integer space specifiers" begin + unitcell = (3, 3) + + Pspaces = rand(2:3, unitcell...) + Nspaces = rand(2:4, unitcell...) + Espaces = rand(2:4, unitcell...) + chis_north = rand(5:10, unitcell...) + chis_east = rand(5:10, unitcell...) + chis_south = rand(5:10, unitcell...) + chis_west = rand(5:10, unitcell...) + + test_unitcell( + unitcell, Pspaces, Nspaces, Espaces, chis_north, chis_east, chis_south, chis_west ) - corners[4, _next(r, end), _prev(c, end)] = TensorMap(randn, stype, ℂ^4, ℂ^5) - edges[4, r, _prev(c, end)] = TensorMap( - randn, stype, ℂ^5 * space(peps[r, c], 4 + 1)' * space(peps[r, c], 4 + 1), ℂ^5 +end + +@testset "Random Cartesian spaces" begin + unitcell = (3, 3) + + Pspaces = random_dualize!(ComplexSpace.(rand(2:3, unitcell...))) + Nspaces = random_dualize!(ComplexSpace.(rand(2:4, unitcell...))) + Espaces = random_dualize!(ComplexSpace.(rand(2:4, unitcell...))) + chis_north = random_dualize!(ComplexSpace.(rand(5:10, unitcell...))) + chis_east = random_dualize!(ComplexSpace.(rand(5:10, unitcell...))) + chis_south = random_dualize!(ComplexSpace.(rand(5:10, unitcell...))) + chis_west = random_dualize!(ComplexSpace.(rand(5:10, unitcell...))) + + test_unitcell( + unitcell, Pspaces, Nspaces, Espaces, chis_north, chis_east, chis_south, chis_west ) end -env = CTMRGEnv(corners, edges) -# apply one CTMRG iteration with fixeds -ctm_alg = CTMRG(; fixedspace=true) -env′, = ctmrg_iter(peps, env, ctm_alg) +@testset "Specific U1 spaces" begin + unitcell = (2, 2) -# compute random expecation value to test matching bonds -random_tensor = TensorMap(randn, scalartype(peps), Pspace, Pspace) -random_op = repeat( - LocalOperator(fill(ℂ^2, 1, 1), (CartesianIndex(1, 1),) => random_tensor), unitcell... -) -@test expectation_value(peps, random_op, env) isa Number -@test expectation_value(peps, random_op, env′) isa Number + PA = U1Space(-1 => 1, 0 => 1) + PB = U1Space(0 => 1, 1 => 1) + Vpeps = U1Space(-1 => 2, 0 => 1, 1 => 2) + Venv = U1Space(-2 => 2, -1 => 3, 0 => 4, 1 => 3, 2 => 2) + + Pspaces = [PA PB; PB PA] + Nspaces = [Vpeps Vpeps'; Vpeps' Vpeps] + chis = [Venv Venv; Venv Venv] + + test_unitcell(unitcell, Pspaces, Nspaces, Nspaces, chis, chis, chis, chis) +end diff --git a/test/heisenberg.jl b/test/heisenberg.jl index b72268ad..024d0f36 100644 --- a/test/heisenberg.jl +++ b/test/heisenberg.jl @@ -21,7 +21,7 @@ opt_alg = PEPSOptimize(; Random.seed!(91283219347) H = square_lattice_heisenberg() psi_init = InfinitePEPS(2, χbond) -env_init = leading_boundary(CTMRGEnv(psi_init; Venv=ComplexSpace(χenv)), psi_init, ctm_alg) +env_init = leading_boundary(CTMRGEnv(psi_init, ComplexSpace(χenv)), psi_init, ctm_alg) # find fixedpoint result = fixedpoint(psi_init, H, opt_alg, env_init) @@ -32,7 +32,7 @@ result = fixedpoint(psi_init, H, opt_alg, env_init) H_2x2 = square_lattice_heisenberg(; unitcell=(2, 2)) psi_init_2x2 = InfinitePEPS(2, χbond; unitcell=(2, 2)) env_init_2x2 = leading_boundary( - CTMRGEnv(psi_init_2x2; Venv=ComplexSpace(χenv)), psi_init_2x2, ctm_alg + CTMRGEnv(psi_init_2x2, ComplexSpace(χenv)), psi_init_2x2, ctm_alg ) result_2x2 = fixedpoint(psi_init_2x2, H_2x2, opt_alg, env_init_2x2) diff --git a/test/pwave.jl b/test/pwave.jl index 0c08c93b..6353fcfa 100644 --- a/test/pwave.jl +++ b/test/pwave.jl @@ -26,7 +26,7 @@ Pspace = Vect[FermionParity](0 => 1, 1 => 1) Vspace = Vect[FermionParity](0 => χbond ÷ 2, 1 => χbond ÷ 2) Envspace = Vect[FermionParity](0 => χenv ÷ 2, 1 => χenv ÷ 2) psi_init = InfinitePEPS(Pspace, Vspace, Vspace; unitcell) -env_init = leading_boundary(CTMRGEnv(psi_init; Venv=Envspace), psi_init, ctm_alg); +env_init = leading_boundary(CTMRGEnv(psi_init, Envspace), psi_init, ctm_alg); # find fixedpoint result = fixedpoint(psi_init, H, opt_alg, env_init) diff --git a/test/runtests.jl b/test/runtests.jl index 799726b8..3333d21a 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -17,6 +17,9 @@ end @time @safetestset "Gradients" begin include("ctmrg/gradients.jl") end + @time @safetestset "Unit cell" begin + include("ctmrg/unitcell.jl") + end end if GROUP == "ALL" || GROUP == "MPS" @time @safetestset "VUMPS" begin diff --git a/test/tf_ising.jl b/test/tf_ising.jl index 881bdd13..c40b17ba 100644 --- a/test/tf_ising.jl +++ b/test/tf_ising.jl @@ -31,7 +31,7 @@ opt_alg = PEPSOptimize(; # initialize states H = square_lattice_tf_ising(; h) psi_init = InfinitePEPS(2, χbond) -env_init = leading_boundary(CTMRGEnv(psi_init; Venv=ComplexSpace(χenv)), psi_init, ctm_alg) +env_init = leading_boundary(CTMRGEnv(psi_init, ComplexSpace(χenv)), psi_init, ctm_alg) # find fixedpoint result = fixedpoint(psi_init, H, opt_alg, env_init) From 6ed78bf0f43593752fade436ceeaa45b2250e251 Mon Sep 17 00:00:00 2001 From: leburgel Date: Wed, 10 Jul 2024 18:06:38 +0200 Subject: [PATCH 3/8] Squash --- src/environments/ctmrgenv.jl | 27 +++++---------------------- 1 file changed, 5 insertions(+), 22 deletions(-) diff --git a/src/environments/ctmrgenv.jl b/src/environments/ctmrgenv.jl index 85d6ab29..621f6690 100644 --- a/src/environments/ctmrgenv.jl +++ b/src/environments/ctmrgenv.jl @@ -16,13 +16,8 @@ _to_space(χ::ElementarySpace) = χ function _corner_tensor( f, ::Type{T}, left_vspace::S, right_vspace::S=left_vspace -) where {T,S<:ElementarySpace} - return TensorMap(f, T, left_vspace ← right_vspace) -end -function _corner_tensor( - f, ::Type{T}, left_vspace::Int, right_vspace::Int=left_vspace -) where {T} - return _corner_tensor(f, T, _to_space(left_vspace), _to_space(right_vspace)) +) where {T,S<:Union{Int,ElementarySpace}} + return TensorMap(f, T, _to_space(left_vspace) ← _to_space(right_vspace)) end function _edge_tensor( @@ -32,23 +27,11 @@ function _edge_tensor( top_pspace::S, bot_pspace::S=top_pspace, right_vspace::S=left_vspace, -) where {T,S<:ElementarySpace} - return TensorMap(f, T, left_vspace ⊗ top_pspace ⊗ dual(bot_pspace) ← right_vspace) -end -function _edge_tensor( - f, - ::Type{T}, - left_vspace::Int, - top_pspace::Int, - bot_pspace::Int, - right_vspace::Int=left_vspace, -) where {T} - return _edge_tensor( +) where {T,S<:Union{Int,ElementarySpace}} + return TensorMap( f, T, - _to_space(left_vspace), - _to_space(top_pspace), - _to_space(bot_pspace), + _to_space(left_vspace) ⊗ _to_space(top_pspace) ⊗ dual(_to_space(bot_pspace)) ← _to_space(right_vspace), ) end From 8520bc3d8a0657c6f4517abddd220d6437d76405 Mon Sep 17 00:00:00 2001 From: leburgel Date: Thu, 11 Jul 2024 11:41:41 +0200 Subject: [PATCH 4/8] Remove deprecated kwarg --- test/ctmrg/unitcell.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/ctmrg/unitcell.jl b/test/ctmrg/unitcell.jl index 30103665..0ffbdc09 100644 --- a/test/ctmrg/unitcell.jl +++ b/test/ctmrg/unitcell.jl @@ -7,7 +7,7 @@ using TensorKit # settings Random.seed!(91283219347) stype = ComplexF64 -ctm_alg = CTMRG(; fixedspace=true) +ctm_alg = CTMRG() function test_unitcell( unitcell, Pspaces, Nspaces, Espaces, chis_north, chis_east, chis_south, chis_west From d5506fd6b83ab14bccf647e7cef6d5f043a6baa8 Mon Sep 17 00:00:00 2001 From: leburgel Date: Fri, 12 Jul 2024 09:13:55 +0200 Subject: [PATCH 5/8] Fix merge conflict --- docs/src/index.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/docs/src/index.md b/docs/src/index.md index 6e2ee183..5ceb20c7 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -37,13 +37,8 @@ opt_alg = PEPSOptimize(; # ground state search state = InfinitePEPS(2, D) -<<<<<<< HEAD ctm = leading_boundary(CTMRGEnv(state, ComplexSpace(chi)), state, ctm_alg) -result = fixedpoint(state, Heisenberg_hamiltonian, opt_alg, ctm) -======= -ctm = leading_boundary(CTMRGEnv(state; Venv=ComplexSpace(chi)), state, ctm_alg) result = fixedpoint(state, H, opt_alg, ctm) ->>>>>>> master @show result.E # -0.6625... ``` From 363412325b105104280eca07b7319f926ce27907 Mon Sep 17 00:00:00 2001 From: leburgel Date: Fri, 12 Jul 2024 11:41:49 +0200 Subject: [PATCH 6/8] Docstrings and defaults --- src/environments/ctmrgenv.jl | 113 ++++++++++++++++++++++++++++------- src/states/abstractpeps.jl | 3 +- src/states/infinitepeps.jl | 19 +++--- 3 files changed, 106 insertions(+), 29 deletions(-) diff --git a/src/environments/ctmrgenv.jl b/src/environments/ctmrgenv.jl index 621f6690..b600b0fa 100644 --- a/src/environments/ctmrgenv.jl +++ b/src/environments/ctmrgenv.jl @@ -2,6 +2,24 @@ struct CTMRGEnv{C,T} Corner transfer-matrix environment containing unit-cell arrays of corner and edge tensors. +The last two indices of the arrays correspond to the row and column indices of the unit +cell, whereas the first index corresponds to the direction of the corner or edge tensor. The +directions are labeled in clockwise direction, starting from the north-west corner and north +edge respectively. + +Given arrays of corners `c` and edges `t`, they connect to the PEPS tensors at site `(r, c)` +isn the unit cell as: +``` + c[1,r-1,c-1]---t[1,r-1,c]----c[2,r-1,c+1] + | || | + t[4,r,c-1]=====AA[r,c]=======t[2,r,c+1] + | || | + c[4,r+1,c-1]---t[3,r+1,c]----c[3,r+1,c+1] +``` + +# Fields +- `corners::Array{C,3}`: Array of corner tensors. +- `edges::Array{T,3}`: Array of edge tensors. """ struct CTMRGEnv{C,T} corners::Array{C,3} @@ -38,20 +56,42 @@ end """ CTMRGEnv( - [f=randn, ComplexF64], Ds_east::A, chis_north::A, chis_east::A, chis_south::A, chis_west::A + [f=randn, ComplexF64], Ds_north, Ds_east::A, chis_north::A, [chis_east::A], [chis_south::A], [chis_west::A] ) where {A<:AbstractMatrix{<:Union{Int,ElementarySpace}}} -TODO: docstring. +Construct a CTMRG environment by specifying matrices of north and east virtual spaces of the +corresponding [`InfinitePEPS`](@ref) and the north, east, south and west virtual spaces of +the environment. Each respective matrix entry corresponds to a site in the unit cell. By +default, the virtual environment 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( - Ds_north::A, Ds_east::A, chis_north::A, chis_east::A, chis_south::A, chis_west::A + Ds_north::A, + Ds_east::A, + chis_north::A, + chis_east::A=chis_north, + chis_south::A=chis_north, + chis_west::A=chis_north, ) where {A<:AbstractMatrix{<:Union{Int,ElementarySpace}}} return CTMRGEnv( randn, ComplexF64, Ds_north, Ds_east, chis_north, chis_east, chis_south, chis_west ) end function CTMRGEnv( - f, T, Ds_north::A, Ds_east::A, chis_north::A, chis_east::A, chis_south::A, chis_west::A + f, + T, + Ds_north::A, + Ds_east::A, + chis_north::A, + chis_east::A=chis_north, + chis_south::A=chis_north, + chis_west::A=chis_north, ) where {A<:AbstractMatrix{<:Union{Int,ElementarySpace}}} Ds_south = adjoint.(circshift(Ds_north, (-1, 0))) Ds_west = adjoint.(circshift(Ds_east, (0, 1))) @@ -119,18 +159,24 @@ end """ CTMRGEnv( - [f=randn, ComplexF64], D_north::S, D_south::S, chi_north::S, chi_east::S, chi_south::S, chi_west::S; unitcell::Tuple{Int,Int}=(1, 1), + [f=randn, ComplexF64], D_north::S, D_south::S, chi_north::S, [chi_east::S], [chi_south::S], [chi_west::S]; unitcell::Tuple{Int,Int}=(1, 1), ) where {S<:Union{Int,ElementarySpace}} -TODO: docstring. +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 +the environment. The PEPS unit cell can be specified by the `unitcell` keyword argument. By +default, the virtual environment 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( D_north::S, D_south::S, chi_north::S, - chi_east::S, - chi_south::S, - chi_west::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}} return CTMRGEnv( @@ -150,9 +196,9 @@ function CTMRGEnv( D_north::S, D_south::S, chi_north::S, - chi_east::S, - chi_south::S, - chi_west::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}} return CTMRGEnv( @@ -168,14 +214,28 @@ function CTMRGEnv( end """ - function CTMRGEnv( - [f=randn, T=ComplexF64], peps::InfinitePEPS, chis_north::A, chis_east::A, chis_south::A, chis_west::A + CTMRGEnv( + [f=randn, T=ComplexF64], peps::InfinitePEPS, chis_north::A, [chis_east::A], [chis_south::A], [chis_west::A] ) where {A<:AbstractMatrix{<:Union{Int,ElementarySpace}}} -TODO: docstring. +Construct a CTMRG environment by specifying a corresponding [`InfinitePEPS`](@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( - peps::InfinitePEPS, chis_north::A, chis_east::A, chis_south::A, chis_west::A + peps::InfinitePEPS, + chis_north::A, + chis_east::A=chis_north, + chis_south::A=chis_north, + chis_west::A=chis_north, ) where {A<:AbstractMatrix{<:Union{Int,ElementarySpace}}} Ds_north = map(peps.A) do t return adjoint(space(t, 2)) @@ -195,7 +255,13 @@ function CTMRGEnv( ) end function CTMRGEnv( - f, T, peps::InfinitePEPS, chis_north::A, chis_east::A, chis_south::A, chis_west::A + f, + T, + peps::InfinitePEPS, + chis_north::A, + chis_east::A=chis_north, + chis_south::A=chis_north, + chis_west::A=chis_north, ) where {A<:AbstractMatrix{<:Union{Int,ElementarySpace}}} Ds_north = map(peps.A) do t return adjoint(space(t, 2)) @@ -216,11 +282,16 @@ function CTMRGEnv( end """ -function CTMRGEnv( - peps::InfinitePEPS, chi_north::S, chi_east::S=chi_north, chi_south::S=chi_north, chi_west::S=chi_north, -) where {S<:Union{Int,ElementarySpace}} + CTMRGEnv( + peps::InfinitePEPS, chi_north::S, [chi_east::S], [chi_south::S], [chi_west::S], + ) where {S<:Union{Int,ElementarySpace}} + +Construct a CTMRG environment by specifying a corresponding [`InfinitePEPS`](@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. -TODO: docstring. +The environment virtual spaces for each site correspond to virtual space of the +corresponding edge tensor for each direction. """ function CTMRGEnv( peps::InfinitePEPS, diff --git a/src/states/abstractpeps.jl b/src/states/abstractpeps.jl index 467b05c3..93a27142 100644 --- a/src/states/abstractpeps.jl +++ b/src/states/abstractpeps.jl @@ -2,7 +2,8 @@ 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. +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. """ const PEPSTensor{S} = AbstractTensorMap{S,1,4} where {S<:ElementarySpace} diff --git a/src/states/infinitepeps.jl b/src/states/infinitepeps.jl index 4135e8f1..2661c072 100644 --- a/src/states/infinitepeps.jl +++ b/src/states/infinitepeps.jl @@ -21,18 +21,23 @@ end ## Constructors """ - InfinitePEPS(A::AbstractArray{T, 2}) + InfinitePEPS(A::AbstractMatrix{T}) -Allow users to pass in an array of tensors. +Create an `InfinitePEPS` by specifying a matrix containing the PEPS tensors at each site in +the unit cell. """ -function InfinitePEPS(A::AbstractArray{T,2}) where {T<:PEPSTensor} +function InfinitePEPS(A::AbstractMatrix{T}) where {T<:PEPSTensor} return InfinitePEPS(Array(deepcopy(A))) # TODO: find better way to copy end """ - InfinitePEPS(f=randn, T=ComplexF64, Pspaces, Nspaces, Espaces) + InfinitePEPS( + f=randn, T=ComplexF64, Pspaces::A, Nspaces::A, [Espaces::A] + ) where {A<:AbstractMatrix{<:Union{Int,ElementarySpace}}} -Allow users to pass in arrays of spaces. +Create an `InfinitePEPS` 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 InfinitePEPS( Pspaces::A, Nspaces::A, Espaces::A @@ -82,8 +87,8 @@ end """ InfinitePEPS(f=randn, T=ComplexF64, Pspace, Nspace, [Espace]; unitcell=(1,1)) -Create an InfinitePEPS by specifying its spaces and unit cell. Spaces can be specified -either via `Int` or via `ElementarySpace`. +Create an InfinitePEPS by specifying its physical, north and east spaces and unit cell. +Spaces can be specified either via `Int` or via `ElementarySpace`. """ function InfinitePEPS( Pspace::S, Nspace::S, Espace::S=Nspace; unitcell::Tuple{Int,Int}=(1, 1) From 4c643cb6105a4b1848b084e7bae4ae6e3484ad48 Mon Sep 17 00:00:00 2001 From: leburgel Date: Fri, 12 Jul 2024 11:49:25 +0200 Subject: [PATCH 7/8] One more merge artifact --- examples/heisenberg.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/heisenberg.jl b/examples/heisenberg.jl index 2a12f904..9dd8dbe3 100644 --- a/examples/heisenberg.jl +++ b/examples/heisenberg.jl @@ -27,6 +27,6 @@ opt_alg = PEPSOptimize(; # E/N = −0.6694421, which is a QMC estimate from https://arxiv.org/abs/1101.3281. # Of course there is a noticable bias for small χbond and χenv. ψ₀ = InfinitePEPS(2, χbond) -env₀ = leading_boundary(CTMRGEnv(ψ₀, ℂ^χenv), ψ₀, ctmalg) +env₀ = leading_boundary(CTMRGEnv(ψ₀, ℂ^χenv), ψ₀, ctm_alg) result = fixedpoint(ψ₀, H, opt_alg, env₀) @show result.E From ff30f2cc31b929be5b97a22cb2db711bb1b3613b Mon Sep 17 00:00:00 2001 From: Lander Burgelman <39218680+leburgel@users.noreply.github.com> Date: Fri, 12 Jul 2024 16:51:24 +0200 Subject: [PATCH 8/8] Update src/environments/ctmrgenv.jl Co-authored-by: Lukas <37111893+lkdvos@users.noreply.github.com> --- src/environments/ctmrgenv.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/environments/ctmrgenv.jl b/src/environments/ctmrgenv.jl index b600b0fa..cf90e2f0 100644 --- a/src/environments/ctmrgenv.jl +++ b/src/environments/ctmrgenv.jl @@ -8,7 +8,7 @@ directions are labeled in clockwise direction, starting from the north-west corn edge respectively. Given arrays of corners `c` and edges `t`, they connect to the PEPS tensors at site `(r, c)` -isn the unit cell as: +in the unit cell as: ``` c[1,r-1,c-1]---t[1,r-1,c]----c[2,r-1,c+1] | || |