From e44eb726a4ba7b6fe60e00752710ff7f285fe3af Mon Sep 17 00:00:00 2001 From: XingyuZhang2018 <864129714@qq.com> Date: Thu, 10 Oct 2024 18:12:16 +0200 Subject: [PATCH 01/25] InfiniteTransferPEPS(PeriodicArray is so weird! --- Project.toml | 1 + src/operators/derivatives.jl | 1 + src/operators/lattices/squarelattice.jl | 26 +++++++ src/operators/transferpeps.jl | 26 ++++++- src/states/abstractpeps.jl | 8 +++ test/boundarymps/gradparts.jl | 91 +++++++++++++++++++++++++ 6 files changed, 152 insertions(+), 1 deletion(-) create mode 100644 test/boundarymps/gradparts.jl diff --git a/Project.toml b/Project.toml index aa1fc857..590ff969 100644 --- a/Project.toml +++ b/Project.toml @@ -7,6 +7,7 @@ version = "0.2.1" Accessors = "7d9f7c33-5ae7-4f3b-8dc6-eff91059b697" ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" Compat = "34da2185-b29b-5c13-b0c7-acf172513d20" +InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240" KrylovKit = "0b1a1467-8014-51b9-945f-bf0ae24f4b77" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" LoggingExtras = "e6f89c97-d47a-5376-807f-9c37f3926c36" diff --git a/src/operators/derivatives.jl b/src/operators/derivatives.jl index 36c0d149..a4dba3a4 100644 --- a/src/operators/derivatives.jl +++ b/src/operators/derivatives.jl @@ -49,6 +49,7 @@ end (H::PEPS_∂∂AC)(x) = MPSKit.∂AC(x, (H.top, H.bot), H.GL, H.GR) function MPSKit.∂AC(x::RecursiveVec, O::Tuple, GL, GR) + @show typeof(x) return RecursiveVec( circshift( map((v, O1, O2, l, r) -> ∂AC(v, (O1, O2), l, r), x.vecs, O[1], O[2], GL, GR), 1 diff --git a/src/operators/lattices/squarelattice.jl b/src/operators/lattices/squarelattice.jl index 097a4f7b..c5bc22a9 100644 --- a/src/operators/lattices/squarelattice.jl +++ b/src/operators/lattices/squarelattice.jl @@ -16,6 +16,19 @@ function vertices(lattice::InfiniteSquare) return CartesianIndices((1:(lattice.Nrows), 1:(lattice.Ncols))) end +""" + nearest_neighbours(lattice::InfiniteSquare) + +Return the nearest neighbors of the lattice `lattice`. + +```` + +---*---+ + | + * + | + + +```` +""" function nearest_neighbours(lattice::InfiniteSquare) neighbors = Tuple{CartesianIndex,CartesianIndex}[] for idx in vertices(lattice) @@ -25,6 +38,19 @@ function nearest_neighbours(lattice::InfiniteSquare) return neighbors end +""" + next_nearest_neighbours(lattice::InfiniteSquare) + +Return the next nearest neighbors of the lattice `lattice`. + +```` + +------+ + | \\ ╱ | + | * | + | ╱ \\| + +------+ +```` +""" function next_nearest_neighbours(lattice::InfiniteSquare) neighbors = Tuple{CartesianIndex,CartesianIndex}[] for idx in vertices(lattice) diff --git a/src/operators/transferpeps.jl b/src/operators/transferpeps.jl index 4706c293..44a3fa68 100644 --- a/src/operators/transferpeps.jl +++ b/src/operators/transferpeps.jl @@ -11,6 +11,21 @@ end InfiniteTransferPEPS(top) = InfiniteTransferPEPS(top, top) +function ChainRulesCore.rrule(::typeof(InfiniteTransferPEPS), top::PeriodicArray, bot::PeriodicArray) + function pullback(Δ) + @show typeof(Δ) + return NoTangent(), Δ.top, Δ.bot + end + @show typeof(top) typeof(bot) + return InfiniteTransferPEPS(top, bot), pullback +end + +# function ChainRulesCore.rrule(::typeof(MPSKit.Multiline), data::AbstractVector) +# @show typeof(data) +# return MPSKit.Multiline(data), Δ -> (NoTangent(), Δ.data) +# end + + """ InfiniteTransferPEPS(T::InfinitePEPS, dir, row) @@ -19,7 +34,9 @@ representing the norm of the state `T`. The partition function is first rotated the direction `dir` faces north, after which its `row`th row from the north is selected. """ function InfiniteTransferPEPS(T::InfinitePEPS, dir, row) + # @show 1111111111 typeof(T) T = rotate_north(T, dir) + # @show 2222222222 typeof(T) return InfiniteTransferPEPS(PeriodicArray(T[row, :])) end @@ -66,7 +83,14 @@ end virtualspaces::AbstractArray{<:ElementarySpace,2} ) -Inialize a boundary MPS for the transfer operator `O` by specifying an array of virtual +```` + + l ←------- r + / \ + / \ + t d +```` +Initalize a boundary MPS for the transfer operator `O` by specifying an array of virtual spaces consistent with the unit cell. """ function initializeMPS(O::InfiniteTransferPEPS, virtualspaces::AbstractArray{S,1}) where {S} diff --git a/src/states/abstractpeps.jl b/src/states/abstractpeps.jl index 93a27142..c6694c11 100644 --- a/src/states/abstractpeps.jl +++ b/src/states/abstractpeps.jl @@ -1,6 +1,14 @@ """ const PEPSTensor{S} +```` + N + ↓ +W ← + ← E + ↓ ⬊ + S P + +```` Default type for PEPS tensors with a single physical index, and 4 virtual indices, conventionally ordered as: ``T : P ← N ⊗ E ⊗ S ⊗ W``. Here, ``P``, ``N``, ``E``, ``S`` and ``W`` denote the physics, north, east, south and west spaces, respectively. diff --git a/test/boundarymps/gradparts.jl b/test/boundarymps/gradparts.jl new file mode 100644 index 00000000..8312e6f1 --- /dev/null +++ b/test/boundarymps/gradparts.jl @@ -0,0 +1,91 @@ +using Test +using Random +using PEPSKit +using MPSKit +using MPSKit: ∂∂AC, MPSMultiline, Multiline,fixedpoint,updatetol +using KrylovKit +using Zygote +using TensorKit +using ChainRulesTestUtils +using ChainRulesCore +const vumps_alg = VUMPS(; alg_eigsolve=MPSKit.Defaults.alg_eigsolve(; ishermitian=true)) + +function num_grad(f, K; δ::Real=1e-5) + if eltype(K) == ComplexF64 + (f(K + δ / 2) - f(K - δ / 2)) / δ + + (f(K + δ / 2 * 1.0im) - f(K - δ / 2 * 1.0im)) / δ * 1.0im + else + (f(K + δ / 2) - f(K - δ / 2)) / δ + end +end + +@testset "InfinitePEPS" begin + Random.seed!(42) + psi = InfinitePEPS(ComplexSpace(2), ComplexSpace(2)) + function f(β) + psir = β * psi + norm(psir) + end + # @show typeof(psi.A) psi.A + @test Zygote.gradient(f, 1.0)[1] ≈ num_grad(f, 1.0) +end + +@testset "InfiniteTransferPEPS" begin + Random.seed!(42) + psi = InfinitePEPS(ComplexSpace(2), ComplexSpace(2)) + function f(β) + psir = β * psi + # @show 123 typeof(psir) + T = PEPSKit.InfiniteTransferPEPS(psir, 1, 1) + # @show 213123 typeof(T) + real(dot(T.top, T.bot)) + end + @show f(1) + @show Zygote.gradient(f, 1.0)[1] + # @show num_grad(f, 1.0) +end + +@testset "dominant eigensolve" begin + Random.seed!(42) + alg_eigsolve = updatetol(vumps_alg.alg_eigsolve, 1, 1) + psi = InfinitePEPS(ComplexSpace(2), ComplexSpace(2)) + psi = symmetrize!(psi, RotateReflect()) + + T = PEPSKit.InfiniteTransferPEPS(psi, 1, 1) + mps = PEPSKit.initializeMPS(T, [ComplexSpace(3)]) + envs=environments(mps, T) + + mps, T = convert(MPSMultiline, mps), Multiline([T]) + + # envs=environments(mps, T) + # H_AC = ∂∂AC(1, mps, T, envs) + ac = RecursiveVec(mps.AC[:, 1]) + + # _, ac′ = MPSKit.fixedpoint(H_AC, ac, :LM, alg_eigsolve) + # @show typeof(H_AC) + function f(β) + # InfinitePEPS(ComplexSpace(2), ComplexSpace(2)) + psi = β * psi + # @show @which PEPSKit.InfiniteTransferPEPS(psi, 1, 1) + # T = PEPSKit.InfiniteTransferPEPS(psi, 1, 1) + # mps, T = convert(MPSMultiline, mps), Multiline([T]) + + # @show typeof(mps) typeof(T) + # H_AC = MPSKit.∂∂AC(1, mps, T, envs) + + # _, ac′ = MPSKit.fixedpoint(H_AC, ac, :LM, alg_eigsolve) + + # AC = ac′.vecs[1] + # real(dot(AC, AC)) + @show typeof(T.bot) + + real(dot(T.bot,T.bot)) + end + # # # # # Zygote.gradient(f, 1.0) + @show f(1.0) + @show Zygote.gradient(f, 1.0) + # end + + +end + From fd4b42d4f6d90f9b41fa9be67381549a09ef04b1 Mon Sep 17 00:00:00 2001 From: XingyuZhang2018 <864129714@qq.com> Date: Fri, 11 Oct 2024 18:00:13 +0200 Subject: [PATCH 02/25] ::Type for constructer! --- src/operators/derivatives.jl | 1 - src/operators/transferpeps.jl | 12 +-------- test/boundarymps/gradparts.jl | 49 ++++++++++++----------------------- 3 files changed, 18 insertions(+), 44 deletions(-) diff --git a/src/operators/derivatives.jl b/src/operators/derivatives.jl index a4dba3a4..36c0d149 100644 --- a/src/operators/derivatives.jl +++ b/src/operators/derivatives.jl @@ -49,7 +49,6 @@ end (H::PEPS_∂∂AC)(x) = MPSKit.∂AC(x, (H.top, H.bot), H.GL, H.GR) function MPSKit.∂AC(x::RecursiveVec, O::Tuple, GL, GR) - @show typeof(x) return RecursiveVec( circshift( map((v, O1, O2, l, r) -> ∂AC(v, (O1, O2), l, r), x.vecs, O[1], O[2], GL, GR), 1 diff --git a/src/operators/transferpeps.jl b/src/operators/transferpeps.jl index 44a3fa68..2d11dee9 100644 --- a/src/operators/transferpeps.jl +++ b/src/operators/transferpeps.jl @@ -11,21 +11,13 @@ end InfiniteTransferPEPS(top) = InfiniteTransferPEPS(top, top) -function ChainRulesCore.rrule(::typeof(InfiniteTransferPEPS), top::PeriodicArray, bot::PeriodicArray) +function ChainRulesCore.rrule(::Type{InfiniteTransferPEPS}, top::PeriodicArray{T,1}, bot::PeriodicArray{T,1}) where {T} function pullback(Δ) - @show typeof(Δ) return NoTangent(), Δ.top, Δ.bot end - @show typeof(top) typeof(bot) return InfiniteTransferPEPS(top, bot), pullback end -# function ChainRulesCore.rrule(::typeof(MPSKit.Multiline), data::AbstractVector) -# @show typeof(data) -# return MPSKit.Multiline(data), Δ -> (NoTangent(), Δ.data) -# end - - """ InfiniteTransferPEPS(T::InfinitePEPS, dir, row) @@ -34,9 +26,7 @@ representing the norm of the state `T`. The partition function is first rotated the direction `dir` faces north, after which its `row`th row from the north is selected. """ function InfiniteTransferPEPS(T::InfinitePEPS, dir, row) - # @show 1111111111 typeof(T) T = rotate_north(T, dir) - # @show 2222222222 typeof(T) return InfiniteTransferPEPS(PeriodicArray(T[row, :])) end diff --git a/test/boundarymps/gradparts.jl b/test/boundarymps/gradparts.jl index 8312e6f1..9f517e7f 100644 --- a/test/boundarymps/gradparts.jl +++ b/test/boundarymps/gradparts.jl @@ -2,11 +2,10 @@ using Test using Random using PEPSKit using MPSKit -using MPSKit: ∂∂AC, MPSMultiline, Multiline,fixedpoint,updatetol +using MPSKit: ∂∂AC, MPSMultiline, Multiline, fixedpoint,updatetol using KrylovKit using Zygote using TensorKit -using ChainRulesTestUtils using ChainRulesCore const vumps_alg = VUMPS(; alg_eigsolve=MPSKit.Defaults.alg_eigsolve(; ishermitian=true)) @@ -21,7 +20,7 @@ end @testset "InfinitePEPS" begin Random.seed!(42) - psi = InfinitePEPS(ComplexSpace(2), ComplexSpace(2)) + psi = InfinitePEPS(ℂ^2, ℂ^2) function f(β) psir = β * psi norm(psir) @@ -32,60 +31,46 @@ end @testset "InfiniteTransferPEPS" begin Random.seed!(42) - psi = InfinitePEPS(ComplexSpace(2), ComplexSpace(2)) + psi = InfinitePEPS(ℂ^2, ℂ^2) function f(β) psir = β * psi - # @show 123 typeof(psir) T = PEPSKit.InfiniteTransferPEPS(psir, 1, 1) - # @show 213123 typeof(T) real(dot(T.top, T.bot)) end - @show f(1) - @show Zygote.gradient(f, 1.0)[1] - # @show num_grad(f, 1.0) + + @test Zygote.gradient(f, 1.0)[1] ≈ num_grad(f, 1.0) end @testset "dominant eigensolve" begin Random.seed!(42) alg_eigsolve = updatetol(vumps_alg.alg_eigsolve, 1, 1) - psi = InfinitePEPS(ComplexSpace(2), ComplexSpace(2)) + psi = InfinitePEPS(ℂ^2, ℂ^2) psi = symmetrize!(psi, RotateReflect()) T = PEPSKit.InfiniteTransferPEPS(psi, 1, 1) - mps = PEPSKit.initializeMPS(T, [ComplexSpace(3)]) + mps = PEPSKit.initializeMPS(T, [ℂ^3]) envs=environments(mps, T) mps, T = convert(MPSMultiline, mps), Multiline([T]) - # envs=environments(mps, T) - # H_AC = ∂∂AC(1, mps, T, envs) ac = RecursiveVec(mps.AC[:, 1]) - # _, ac′ = MPSKit.fixedpoint(H_AC, ac, :LM, alg_eigsolve) - # @show typeof(H_AC) + S = TensorMap(randn, ComplexF64, ℂ^3*ℂ^2*(ℂ^2)'*(ℂ^3)'← ℂ^3*ℂ^2*(ℂ^2)'*(ℂ^3)') + function f(β) - # InfinitePEPS(ComplexSpace(2), ComplexSpace(2)) psi = β * psi - # @show @which PEPSKit.InfiniteTransferPEPS(psi, 1, 1) - # T = PEPSKit.InfiniteTransferPEPS(psi, 1, 1) - # mps, T = convert(MPSMultiline, mps), Multiline([T]) + T = PEPSKit.InfiniteTransferPEPS(psi, 1, 1) + T = MPSKit.Multiline([T]) - # @show typeof(mps) typeof(T) - # H_AC = MPSKit.∂∂AC(1, mps, T, envs) + H_AC = MPSKit.∂∂AC(1, mps, T, envs) - # _, ac′ = MPSKit.fixedpoint(H_AC, ac, :LM, alg_eigsolve) + _, ac′ = MPSKit.fixedpoint(H_AC, ac, :LM, alg_eigsolve) - # AC = ac′.vecs[1] - # real(dot(AC, AC)) - @show typeof(T.bot) - - real(dot(T.bot,T.bot)) + AC = ac′.vecs[1] + @tensor d = conj(AC[1 2 3 4]) * S[1 2 3 4; 5 6 7 8] * AC[5 6 7 8] + norm(d) end - # # # # # Zygote.gradient(f, 1.0) - @show f(1.0) - @show Zygote.gradient(f, 1.0) - # end - + @test Zygote.gradient(f, 1.0)[1] ≈ num_grad(f, 1.0) atol = 1e-3 end From a193ea837d16f6aa38239b1deb36be870a00e301 Mon Sep 17 00:00:00 2001 From: XingyuZhang2018 <864129714@qq.com> Date: Mon, 14 Oct 2024 18:13:25 +0200 Subject: [PATCH 03/25] backup --- src/PEPSKit.jl | 2 + src/algorithms/peps_opt.jl | 4 ++ test/boundarymps/gradparts.jl | 120 ++++++++++++++++++++++++++++++++-- 3 files changed, 120 insertions(+), 6 deletions(-) diff --git a/src/PEPSKit.jl b/src/PEPSKit.jl index 5a4fdb0a..1506d479 100644 --- a/src/PEPSKit.jl +++ b/src/PEPSKit.jl @@ -39,6 +39,8 @@ include("algorithms/contractions/ctmrg_contractions.jl") include("algorithms/ctmrg/ctmrg.jl") include("algorithms/ctmrg/gaugefix.jl") +# include("algorithms/vumps/vumps.jl") + include("algorithms/toolbox.jl") include("algorithms/peps_opt.jl") diff --git a/src/algorithms/peps_opt.jl b/src/algorithms/peps_opt.jl index 3b569e6b..a746798c 100644 --- a/src/algorithms/peps_opt.jl +++ b/src/algorithms/peps_opt.jl @@ -218,6 +218,8 @@ function _rrule( state, alg::CTMRG, ) + + @show 22222222222 envs = leading_boundary(envinit, state, alg) #TODO: fixed space for unit cells function leading_boundary_diffgauge_pullback(Δenvs′) @@ -249,6 +251,8 @@ function _rrule( state, alg::CTMRG{C}, ) where {C} + + @show 11111111111111111111 @assert C === :simultaneous @assert !isnothing(alg.projector_alg.svd_alg.rrule_alg) envs = leading_boundary(envinit, state, alg) diff --git a/test/boundarymps/gradparts.jl b/test/boundarymps/gradparts.jl index 9f517e7f..d2632967 100644 --- a/test/boundarymps/gradparts.jl +++ b/test/boundarymps/gradparts.jl @@ -2,14 +2,14 @@ using Test using Random using PEPSKit using MPSKit -using MPSKit: ∂∂AC, MPSMultiline, Multiline, fixedpoint,updatetol +using MPSKit: ∂∂AC, ∂∂C, MPSMultiline, Multiline, fixedpoint,updatetol using KrylovKit using Zygote using TensorKit using ChainRulesCore const vumps_alg = VUMPS(; alg_eigsolve=MPSKit.Defaults.alg_eigsolve(; ishermitian=true)) -function num_grad(f, K; δ::Real=1e-5) +function num_grad(f, K::Number; δ::Real=1e-5) if eltype(K) == ComplexF64 (f(K + δ / 2) - f(K - δ / 2)) / δ + (f(K + δ / 2 * 1.0im) - f(K - δ / 2 * 1.0im)) / δ * 1.0im @@ -18,6 +18,15 @@ function num_grad(f, K; δ::Real=1e-5) end end +function num_grad(f, a; δ::Real=1e-5) + b = copy(a) + df = map(CartesianIndices(size())) do i + foo = x -> (ac = copy(b); ac[i] = x; f(ac)) + num_grad(foo, b[i], δ=δ) + end + return df +end + @testset "InfinitePEPS" begin Random.seed!(42) psi = InfinitePEPS(ℂ^2, ℂ^2) @@ -54,10 +63,12 @@ end mps, T = convert(MPSMultiline, mps), Multiline([T]) ac = RecursiveVec(mps.AC[:, 1]) + c = RecursiveVec(mps.CR[:, 1]) - S = TensorMap(randn, ComplexF64, ℂ^3*ℂ^2*(ℂ^2)'*(ℂ^3)'← ℂ^3*ℂ^2*(ℂ^2)'*(ℂ^3)') + S1 = TensorMap(randn, ComplexF64, ℂ^3*ℂ^2*(ℂ^2)'*(ℂ^3)'← ℂ^3*ℂ^2*(ℂ^2)'*(ℂ^3)') + S2 = TensorMap(randn, ComplexF64, ℂ^3*(ℂ^3)'← ℂ^3*(ℂ^3)') - function f(β) + function foo1(β) psi = β * psi T = PEPSKit.InfiniteTransferPEPS(psi, 1, 1) T = MPSKit.Multiline([T]) @@ -67,10 +78,107 @@ end _, ac′ = MPSKit.fixedpoint(H_AC, ac, :LM, alg_eigsolve) AC = ac′.vecs[1] - @tensor d = conj(AC[1 2 3 4]) * S[1 2 3 4; 5 6 7 8] * AC[5 6 7 8] + @tensor d = conj(AC[1 2 3 4]) * S1[1 2 3 4; 5 6 7 8] * AC[5 6 7 8] norm(d) end - @test Zygote.gradient(f, 1.0)[1] ≈ num_grad(f, 1.0) atol = 1e-3 + @test Zygote.gradient(foo1, 1.0)[1] ≈ num_grad(foo1, 1.0) atol = 1e-4 + + # function foo2(β) + # psi = β * psi + # T = PEPSKit.InfiniteTransferPEPS(psi, 1, 1) + # T = MPSKit.Multiline([T]) + + # H_C = ∂∂C(1, mps, T, envs) + + # _, c′ = MPSKit.fixedpoint(H_C, c, :LM, alg_eigsolve) + # C = c′.vecs[1] + # # @show space(C) + # # norm(C) + # @tensor d = conj(C[1 2]) * S2[1 2; 3 4] * C[3 4] + # norm(d) + # end + + # @show foo2(1.0) num_grad(foo2, 1.0) + # @test Zygote.gradient(foo2, 1.0)[1] ≈ num_grad(foo2, 1.0) atol = 1e-4 end +@testset "(1, 1) PEPS" begin + psi = InfinitePEPS(ComplexSpace(2), ComplexSpace(2)) + # @show size(psi[1]) + # T = PEPSKit.InfiniteTransferPEPS(psi, 1, 1) + # mps = PEPSKit.initializeMPS(T, [ComplexSpace(20)]) + + # mps, envs, ϵ = leading_boundary(mps, T, vumps_alg) + # AC_0 = mps.AL[1] + # mps, envs, ϵ = vumps_iter(mps, T, vumps_alg, envs, ϵ) + # AC_1 = mps.AL[1] + # @show norm(AC_0 - AC_1) + + # function f(x) + # psi = x * psi + # T = PEPSKit.InfiniteTransferPEPS(psi, 1, 1) + # mps, envs, ϵ = vumps_iter(mps, T, vumps_alg, envs, ϵ) + # return abs(prod(expectation_value(mps, T))) + # end + # @show f(2) + # N = abs(sum(expectation_value(mps, T))) + # @show N + + # ctm = leading_boundary(CTMRGEnv(psi, ComplexSpace(20)), psi, CTMRG(; verbosity=1)) + # N´ = abs(norm(psi, ctm)) + ctm = leading_boundary(CTMRGEnv(psi, ComplexSpace(20)), psi, CTMRG(; verbosity=1)) + + boundary_algs = [ + CTMRG(; + tol=1e-10, + verbosity=0, + ctmrgscheme=:simultaneous, + svd_alg=SVDAdjoint(; fwd_alg=TensorKit.SVD(), rrule_alg=GMRES(; tol=1e-10)), + ), + CTMRG(; tol=1e-10, verbosity=0, ctmrgscheme=:sequential), + ] + + gradtol = 1e-4 + + gradmodes = [ + [ + nothing, + GeomSum(; tol=gradtol, iterscheme=:fixed), + GeomSum(; tol=gradtol, iterscheme=:diffgauge), + ManualIter(; tol=gradtol, iterscheme=:fixed), + ManualIter(; tol=gradtol, iterscheme=:diffgauge), + LinSolver(; solver=KrylovKit.GMRES(; tol=gradtol), iterscheme=:fixed), + LinSolver(; solver=KrylovKit.GMRES(; tol=gradtol), iterscheme=:diffgauge), + ], + [ + nothing, + GeomSum(; tol=gradtol, iterscheme=:diffgauge), + ManualIter(; tol=gradtol, iterscheme=:diffgauge), + LinSolver(; solver=KrylovKit.GMRES(; tol=gradtol), iterscheme=:diffgauge), + ], + ] + + boundary_alg = boundary_algs[1] + function foo2(psi) + # psi = x * psi + + ctm = PEPSKit.hook_pullback( + leading_boundary, ctm, psi, boundary_alg; alg_rrule = gradmodes[1][2] + ) + abs(norm(psi, ctm)) + end + + function foo3(psi) + # psi = x * psi + + ctm = PEPSKit.hook_pullback( + leading_boundary, ctm, psi, boundary_alg; alg_rrule = gradmodes[1][3] + ) + abs(norm(psi, ctm)) + end + # @show foo2(1.0) + @show norm(Zygote.gradient(foo2, psi)[1] - Zygote.gradient(foo3, psi)[1]) + # @show num_grad(foo2, 1.0) + # @test N ≈ N´ atol = 1e-3 +end From 1c490d873637af00b14112073e3a4a4c0c9e6870 Mon Sep 17 00:00:00 2001 From: XingyuZhang2018 <864129714@qq.com> Date: Tue, 15 Oct 2024 00:15:44 +0200 Subject: [PATCH 04/25] =?UTF-8?q?why=20does=20vumps=20fix=20gauge=20not=20?= =?UTF-8?q?work=EF=BC=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/algorithms/peps_opt.jl | 33 +++++++++++++++++++-- test/boundarymps/gradparts.jl | 56 +++++++++++++++++++---------------- 2 files changed, 61 insertions(+), 28 deletions(-) diff --git a/src/algorithms/peps_opt.jl b/src/algorithms/peps_opt.jl index a746798c..fe20a35e 100644 --- a/src/algorithms/peps_opt.jl +++ b/src/algorithms/peps_opt.jl @@ -219,7 +219,6 @@ function _rrule( alg::CTMRG, ) - @show 22222222222 envs = leading_boundary(envinit, state, alg) #TODO: fixed space for unit cells function leading_boundary_diffgauge_pullback(Δenvs′) @@ -242,6 +241,37 @@ function _rrule( return envs, leading_boundary_diffgauge_pullback end +function _rrule( + gradmode::GradMode{:diffgauge}, + ::RuleConfig, + ::typeof(MPSKit.leading_boundary), + envinit, + state, + alg::VUMPS, +) + + envs = leading_boundary(envinit, state, alg) + + function leading_boundary_diffgauge_pullback(Δenvs′) + Δenvs = unthunk(Δenvs′) + + # find partial gradients of gauge_fixed single CTMRG iteration + # TODO: make this rrule_via_ad so it's zygote-agnostic + _, env_vjp = pullback(state, envs) do A, x + return gauge_fix(x, ctmrg_iter(A, x, alg)[1])[1] + end + + # evaluate the geometric sum + ∂f∂A(x)::typeof(state) = env_vjp(x)[1] + ∂f∂x(x)::typeof(envs) = env_vjp(x)[2] + ∂F∂envs = fpgrad(Δenvs, ∂f∂x, ∂f∂A, Δenvs, gradmode) + + return NoTangent(), ZeroTangent(), ∂F∂envs, NoTangent() + end + + return envs, leading_boundary_diffgauge_pullback +end + # Here f is differentiated from an pre-computed SVD with fixed U, S and V function _rrule( gradmode::GradMode{:fixed}, @@ -252,7 +282,6 @@ function _rrule( alg::CTMRG{C}, ) where {C} - @show 11111111111111111111 @assert C === :simultaneous @assert !isnothing(alg.projector_alg.svd_alg.rrule_alg) envs = leading_boundary(envinit, state, alg) diff --git a/test/boundarymps/gradparts.jl b/test/boundarymps/gradparts.jl index d2632967..f3ef02ac 100644 --- a/test/boundarymps/gradparts.jl +++ b/test/boundarymps/gradparts.jl @@ -2,12 +2,12 @@ using Test using Random using PEPSKit using MPSKit -using MPSKit: ∂∂AC, ∂∂C, MPSMultiline, Multiline, fixedpoint,updatetol +using MPSKit: ∂∂AC, ∂∂C, MPSMultiline, Multiline, fixedpoint,updatetol, vumps_iter using KrylovKit using Zygote using TensorKit using ChainRulesCore -const vumps_alg = VUMPS(; alg_eigsolve=MPSKit.Defaults.alg_eigsolve(; ishermitian=true)) +const vumps_alg = VUMPS(; alg_eigsolve=MPSKit.Defaults.alg_eigsolve(; ishermitian=false)) function num_grad(f, K::Number; δ::Real=1e-5) if eltype(K) == ComplexF64 @@ -103,30 +103,8 @@ end # @test Zygote.gradient(foo2, 1.0)[1] ≈ num_grad(foo2, 1.0) atol = 1e-4 end -@testset "(1, 1) PEPS" begin +@testset "(1, 1) ctm PEPS" begin psi = InfinitePEPS(ComplexSpace(2), ComplexSpace(2)) - # @show size(psi[1]) - # T = PEPSKit.InfiniteTransferPEPS(psi, 1, 1) - # mps = PEPSKit.initializeMPS(T, [ComplexSpace(20)]) - - # mps, envs, ϵ = leading_boundary(mps, T, vumps_alg) - # AC_0 = mps.AL[1] - # mps, envs, ϵ = vumps_iter(mps, T, vumps_alg, envs, ϵ) - # AC_1 = mps.AL[1] - # @show norm(AC_0 - AC_1) - - # function f(x) - # psi = x * psi - # T = PEPSKit.InfiniteTransferPEPS(psi, 1, 1) - # mps, envs, ϵ = vumps_iter(mps, T, vumps_alg, envs, ϵ) - # return abs(prod(expectation_value(mps, T))) - # end - # @show f(2) - # N = abs(sum(expectation_value(mps, T))) - # @show N - - # ctm = leading_boundary(CTMRGEnv(psi, ComplexSpace(20)), psi, CTMRG(; verbosity=1)) - # N´ = abs(norm(psi, ctm)) ctm = leading_boundary(CTMRGEnv(psi, ComplexSpace(20)), psi, CTMRG(; verbosity=1)) boundary_algs = [ @@ -178,7 +156,33 @@ end abs(norm(psi, ctm)) end # @show foo2(1.0) - @show norm(Zygote.gradient(foo2, psi)[1] - Zygote.gradient(foo3, psi)[1]) + # @show norm(Zygote.gradient(foo2, psi)[1] - Zygote.gradient(foo3, psi)[1]) # @show num_grad(foo2, 1.0) # @test N ≈ N´ atol = 1e-3 end + +@testset "(1, 1) vumps PEPS " begin + Random.seed!(42) + psi = InfinitePEPS(ComplexSpace(2), ComplexSpace(2)) + T = PEPSKit.InfiniteTransferPEPS(psi, 1, 1) + mps = PEPSKit.initializeMPS(T, [ComplexSpace(20)]) + + mps, envs, ϵ = leading_boundary(mps, T, vumps_alg) + AC_0 = mps.AC[1] + mps, envs, ϵ = vumps_iter(mps, T, vumps_alg, envs, ϵ) + AC_1 = mps.AC[1] + # @show norm(AC_0 - AC_1) + + function foo1(psi) + T = PEPSKit.InfiniteTransferPEPS(psi, 1, 1) + mps, envs, ϵ = vumps_iter(mps, T, vumps_alg, envs, ϵ) + return abs(prod(expectation_value(mps, T))) + end + @show foo1(psi) + + @show Zygote.gradient(foo1, psi)[1] + # @show foo2(1.0) + # @show norm(Zygote.gradient(foo1, psi)[1] - Zygote.gradient(foo3, psi)[1]) + # @show num_grad(foo2, 1.0) + # @test N ≈ N´ atol = 1e-3 +end \ No newline at end of file From bef7ce0f2d5055719c3e9dc9690d648f19ccc109 Mon Sep 17 00:00:00 2001 From: XingyuZhang2018 <864129714@qq.com> Date: Fri, 18 Oct 2024 17:44:20 +0200 Subject: [PATCH 05/25] backup --- src/PEPSKit.jl | 2 + src/algorithms/vumps/vumps_iter.jl | 62 +++++++++++++++++++ src/environments/transferpeps_environments.jl | 38 ++++++------ src/operators/transferpeps.jl | 4 +- test/boundarymps/gradparts.jl | 20 +++--- 5 files changed, 97 insertions(+), 29 deletions(-) create mode 100644 src/algorithms/vumps/vumps_iter.jl diff --git a/src/PEPSKit.jl b/src/PEPSKit.jl index 1506d479..de25fd21 100644 --- a/src/PEPSKit.jl +++ b/src/PEPSKit.jl @@ -39,6 +39,8 @@ include("algorithms/contractions/ctmrg_contractions.jl") include("algorithms/ctmrg/ctmrg.jl") include("algorithms/ctmrg/gaugefix.jl") +include("algorithms/vumps/vumps_iter.jl") + # include("algorithms/vumps/vumps.jl") include("algorithms/toolbox.jl") diff --git a/src/algorithms/vumps/vumps_iter.jl b/src/algorithms/vumps/vumps_iter.jl new file mode 100644 index 00000000..4914408a --- /dev/null +++ b/src/algorithms/vumps/vumps_iter.jl @@ -0,0 +1,62 @@ +function vumps_iter(ψ::InfiniteMPS, H, alg, envs, ϵ) + (st, pr, de) = vumps_iter(convert(MPSMultiline, ψ), Multiline([H]), alg, envs, ϵ) + return convert(InfiniteMPS, st), pr, de +end + +using MPSKit: gaugefix!, _firstspace +function vumps_iter(ψ::MPSMultiline, H, alg::VUMPS, envs, ϵ) + ACs = Zygote.Buffer(ψ.AC) + Cs = Zygote.Buffer(ψ.CR) + + iter = alg.maxiter + alg_eigsolve = updatetol(alg.alg_eigsolve, iter, ϵ) + for col in 1:size(ψ, 2) + H_AC = ∂∂AC(col, ψ, H, envs) + ac = RecursiveVec(ψ.AC[:, col]) + _, ac′ = MPSKit.fixedpoint(H_AC, ac, :LM, alg_eigsolve) + ACs[:, col] = ac′.vecs[:] + + H_C = ∂∂C(col, ψ, H, envs) + c = RecursiveVec(ψ.CR[:, col]) + _, c′ = MPSKit.fixedpoint(H_C, c, :LM, alg_eigsolve) + Cs[:, col] = c′.vecs[:] + end + + # normalize + ACs = [AC / norm(AC) for AC in copy(ACs)] + Cs = [C / norm(C) for C in copy(Cs)] + + ALs = [regauge(AC, C) for (AC, C) in zip(ACs, Cs)] + ARs = [regauge(C, AC) for (C, AC) in zip(Cs, ACs)] + ACs = [AL * C for (AL, C) in zip(ALs, Cs)] + # ACs2 = [_transpose_front(C * _transpose_tail(AR)) for (C, AR) in zip(Cs, ARs)] + # @show norm(ACs1[1] - ACs2[1]) + + # ψ = MPSMultiline(vec([InfiniteMPS(ALs[i, :], ARs[i, :], Cs[i, :], ACs[i, :]) for i in size(ALs, 1)])) + + data = map(eachrow(ALs), eachrow(ARs), eachrow(Cs), eachrow(ACs)) do ALrow, ARrow, Crow, ACrow + InfiniteMPS(ALrow, ARrow, Crow, ACrow) + end + ψ = MPSMultiline(data) + + # alg_environments = updatetol(alg.alg_environments, iter, ϵ) + # @show typeof(envs) typeof(ψ) + # recalculate!(envs, ψ; alg_environments.tol) + + return ψ, envs, ϵ +end + +function regauge(AC::GenericMPSTensor, CR::MPSBondTensor; alg=QRpos()) + Q_AC, _ = leftorth(AC; alg) + Q_C, _ = leftorth(CR; alg) + return Q_AC * Q_C' +end + +function regauge(CL::MPSBondTensor, AC::GenericMPSTensor; alg=LQpos()) + AC_tail = _transpose_tail(AC) + _, Q_AC = rightorth(AC_tail; alg) + _, Q_C = rightorth(CL; alg) + AR_tail = Q_C' * Q_AC + return _transpose_front(AR_tail) +end + diff --git a/src/environments/transferpeps_environments.jl b/src/environments/transferpeps_environments.jl index 4332c232..415270e7 100644 --- a/src/environments/transferpeps_environments.jl +++ b/src/environments/transferpeps_environments.jl @@ -1,4 +1,3 @@ - function MPSKit.environments(state::InfiniteMPS, O::InfiniteTransferPEPS; kwargs...) return environments( convert(MPSMultiline, state), convert(TransferPEPSMultiline, O); kwargs... @@ -28,32 +27,31 @@ function MPSKit.mixed_fixpoints( @assert size(below) == size(O) envtype = eltype(init[1]) + # @show envtype lefties = PeriodicArray{envtype,2}(undef, numrows, numcols) righties = PeriodicArray{envtype,2}(undef, numrows, numcols) - @threads for cr in 1:numrows + # lefties = Zygote.Buffer(envtype, numrows, numcols) + # righties = Zygote.Buffer(envtype, numrows, numcols) + lefties = Zygote.Buffer(lefties) + righties = Zygote.Buffer(righties) + for cr in 1:numrows c_above = above[cr] # TODO: Update index convention to above[cr - 1] c_below = below[cr + 1] (L0, R0) = init[cr] - @sync begin - Threads.@spawn begin - E_LL = TransferMatrix($c_above.AL, $O[cr], $c_below.AL) - (_, Ls, convhist) = eigsolve(flip(E_LL), $L0, 1, :LM, $solver) - convhist.converged < 1 && - @info "left eigenvalue failed to converge $(convhist.normres)" - L0 = first(Ls) - end - - Threads.@spawn begin - E_RR = TransferMatrix($c_above.AR, $O[cr], $c_below.AR) - (_, Rs, convhist) = eigsolve(E_RR, $R0, 1, :LM, $solver) - convhist.converged < 1 && - @info "right eigenvalue failed to converge $(convhist.normres)" - R0 = first(Rs) - end - end + E_LL = TransferMatrix(c_above.AL, O[cr], c_below.AL) + (_, Ls, convhist) = eigsolve(flip(E_LL), L0, 1, :LM, solver) + convhist.converged < 1 && + @info "left eigenvalue failed to converge $(convhist.normres)" + L0 = first(Ls) + + E_RR = TransferMatrix(c_above.AR, O[cr], c_below.AR) + (_, Rs, convhist) = eigsolve(E_RR, R0, 1, :LM, solver) + convhist.converged < 1 && + @info "right eigenvalue failed to converge $(convhist.normres)" + R0 = first(Rs) lefties[cr, 1] = L0 for loc in 2:numcols @@ -81,7 +79,7 @@ function MPSKit.mixed_fixpoints( end end - return (lefties, righties) + return (copy(lefties), copy(righties)) end function gen_init_fps(above::MPSMultiline, O::TransferPEPSMultiline, below::MPSMultiline) diff --git a/src/operators/transferpeps.jl b/src/operators/transferpeps.jl index 2d11dee9..98093025 100644 --- a/src/operators/transferpeps.jl +++ b/src/operators/transferpeps.jl @@ -172,10 +172,10 @@ function MPSKit.expectation_value( return prod(product(1:size(st, 1), 1:size(st, 2))) do (i, j) O_ij = opp[i, j] return @tensor leftenv(ca, i, j, st)[1 2 4; 7] * - conj(st.AC[i + 1, j][1 3 6; 13]) * + conj(st[i + 1].AC[j][1 3 6; 13]) * O_ij[1][5; 8 11 3 2] * conj(O_ij[2][5; 9 12 6 4]) * - st.AC[i, j][7 8 9; 10] * + st[i].AC[j][7 8 9; 10] * rightenv(ca, i, j, st)[10 11 12; 13] end end diff --git a/test/boundarymps/gradparts.jl b/test/boundarymps/gradparts.jl index f3ef02ac..37b818eb 100644 --- a/test/boundarymps/gradparts.jl +++ b/test/boundarymps/gradparts.jl @@ -2,12 +2,13 @@ using Test using Random using PEPSKit using MPSKit -using MPSKit: ∂∂AC, ∂∂C, MPSMultiline, Multiline, fixedpoint,updatetol, vumps_iter +using MPSKit: ∂∂AC, ∂∂C, MPSMultiline, Multiline, fixedpoint, updatetol +using PEPSKit: vumps_iter, TransferPEPSMultiline using KrylovKit using Zygote using TensorKit using ChainRulesCore -const vumps_alg = VUMPS(; alg_eigsolve=MPSKit.Defaults.alg_eigsolve(; ishermitian=false)) +const vumps_alg = VUMPS(; maxiter=20, alg_eigsolve=MPSKit.Defaults.alg_eigsolve(; ishermitian=false)) function num_grad(f, K::Number; δ::Real=1e-5) if eltype(K) == ComplexF64 @@ -168,15 +169,20 @@ end mps = PEPSKit.initializeMPS(T, [ComplexSpace(20)]) mps, envs, ϵ = leading_boundary(mps, T, vumps_alg) - AC_0 = mps.AC[1] - mps, envs, ϵ = vumps_iter(mps, T, vumps_alg, envs, ϵ) - AC_1 = mps.AC[1] + # AC_0 = mps.AC[1] + # mps, envs, ϵ = vumps_iter(mps, T, vumps_alg, envs, ϵ) + # AC_1 = mps.AC[1] # @show norm(AC_0 - AC_1) + @show abs(prod(expectation_value(mps, T))) + # @show propertynames(envs) envs.dependency envs.lock function foo1(psi) T = PEPSKit.InfiniteTransferPEPS(psi, 1, 1) - mps, envs, ϵ = vumps_iter(mps, T, vumps_alg, envs, ϵ) - return abs(prod(expectation_value(mps, T))) + # mps, envs, ϵ = vumps_iter(mps, T, vumps_alg, envs, ϵ) + mps = convert(MPSMultiline, mps) + T = convert(TransferPEPSMultiline, T) + ca = environments(mps, T) + return abs(prod(expectation_value(mps, T, ca))) end @show foo1(psi) From 85b1983e7d3e57a20634c02b27d865dc2654f428 Mon Sep 17 00:00:00 2001 From: XingyuZhang2018 <864129714@qq.com> Date: Sun, 20 Oct 2024 13:09:56 +0200 Subject: [PATCH 06/25] backup --- src/PEPSKit.jl | 46 +---------- .../contractions/vumps_contractions.jl | 0 src/algorithms/ctmrg/ctmrg.jl | 32 +++----- src/algorithms/vumps/vumps.jl | 23 ++++++ src/environments/vumps_environments.jl | 79 +++++++++++++++++++ src/utility/defaults.jl | 53 +++++++++++++ src/utility/loginfo.jl | 9 +++ 7 files changed, 179 insertions(+), 63 deletions(-) create mode 100644 src/algorithms/contractions/vumps_contractions.jl create mode 100644 src/algorithms/vumps/vumps.jl create mode 100644 src/environments/vumps_environments.jl create mode 100644 src/utility/defaults.jl create mode 100644 src/utility/loginfo.jl diff --git a/src/PEPSKit.jl b/src/PEPSKit.jl index de25fd21..5a1fa557 100644 --- a/src/PEPSKit.jl +++ b/src/PEPSKit.jl @@ -11,12 +11,14 @@ using LoggingExtras using MPSKit: loginit!, logiter!, logfinish!, logcancel! using MPSKitModels +include("utility/defaults.jl") include("utility/util.jl") include("utility/svd.jl") include("utility/rotations.jl") include("utility/diffset.jl") include("utility/hook_pullback.jl") include("utility/autoopt.jl") +include("utility/loginfo.jl") include("states/abstractpeps.jl") include("states/infinitepeps.jl") @@ -33,15 +35,14 @@ include("environments/ctmrg_environments.jl") include("environments/transferpeps_environments.jl") include("environments/transferpepo_environments.jl") +abstract type Algorithm end include("algorithms/contractions/localoperator.jl") include("algorithms/contractions/ctmrg_contractions.jl") include("algorithms/ctmrg/ctmrg.jl") include("algorithms/ctmrg/gaugefix.jl") -include("algorithms/vumps/vumps_iter.jl") - -# include("algorithms/vumps/vumps.jl") +include("algorithms/vumps/vumps.jl") include("algorithms/toolbox.jl") @@ -49,45 +50,6 @@ include("algorithms/peps_opt.jl") include("utility/symmetrization.jl") -""" - module Defaults - const ctmrg_maxiter = 100 - const ctmrg_miniter = 4 - const ctmrg_tol = 1e-12 - const fpgrad_maxiter = 100 - const fpgrad_tol = 1e-6 - end - -Module containing default values that represent typical algorithm parameters. - -- `ctmrg_maxiter = 100`: Maximal number of CTMRG iterations per run -- `ctmrg_miniter = 4`: Minimal number of CTMRG carried out -- `ctmrg_tol = 1e-12`: Tolerance checking singular value and norm convergence -- `fpgrad_maxiter = 100`: Maximal number of iterations for computing the CTMRG fixed-point gradient -- `fpgrad_tol = 1e-6`: Convergence tolerance for the fixed-point gradient iteration -""" -module Defaults - using TensorKit, KrylovKit, OptimKit - using PEPSKit: LinSolver, FixedSpaceTruncation, SVDAdjoint - const ctmrg_maxiter = 100 - const ctmrg_miniter = 4 - const ctmrg_tol = 1e-8 - const fpgrad_maxiter = 30 - const fpgrad_tol = 1e-6 - const ctmrgscheme = :simultaneous - const reuse_env = true - const trscheme = FixedSpaceTruncation() - const iterscheme = :fixed - const fwd_alg = TensorKit.SVD() - const rrule_alg = GMRES(; tol=1e1ctmrg_tol) - const svd_alg = SVDAdjoint(; fwd_alg, rrule_alg) - const optimizer = LBFGS(32; maxiter=100, gradtol=1e-4, verbosity=2) - const gradient_linsolver = KrylovKit.BiCGStab(; - maxiter=Defaults.fpgrad_maxiter, tol=Defaults.fpgrad_tol - ) - const gradient_alg = LinSolver(; solver=gradient_linsolver, iterscheme) -end - export SVDAdjoint, IterSVD, NonTruncSVDAdjoint export FixedSpaceTruncation, ProjectorAlg, CTMRG, CTMRGEnv, correlation_length export LocalOperator diff --git a/src/algorithms/contractions/vumps_contractions.jl b/src/algorithms/contractions/vumps_contractions.jl new file mode 100644 index 00000000..e69de29b diff --git a/src/algorithms/ctmrg/ctmrg.jl b/src/algorithms/ctmrg/ctmrg.jl index bba37f25..e55843cd 100644 --- a/src/algorithms/ctmrg/ctmrg.jl +++ b/src/algorithms/ctmrg/ctmrg.jl @@ -43,8 +43,8 @@ function svd_algorithm(alg::ProjectorAlg, (dir, r, c)) end """ - CTMRG(; tol=Defaults.ctmrg_tol, maxiter=Defaults.ctmrg_maxiter, - miniter=Defaults.ctmrg_miniter, verbosity=0, + CTMRG(; tol=Defaults.contr_tol, maxiter=Defaults.contr_maxiter, + miniter=Defaults.contr_miniter, verbosity=0, svd_alg=SVDAdjoint(), trscheme=FixedSpaceTruncation(), ctmrgscheme=Defaults.ctmrgscheme) @@ -64,7 +64,7 @@ computed on the western side, and then applied and rotated. Or with `:simultaneo are computed and applied simultaneously on all sides, where in particular the corners get contracted with two projectors at the same time. """ -struct CTMRG{S} +struct CTMRG{S} <: Algorithm tol::Float64 maxiter::Int miniter::Int @@ -72,9 +72,9 @@ struct CTMRG{S} projector_alg::ProjectorAlg end function CTMRG(; - tol=Defaults.ctmrg_tol, - maxiter=Defaults.ctmrg_maxiter, - miniter=Defaults.ctmrg_miniter, + tol=Defaults.contr_tol, + maxiter=Defaults.contr_maxiter, + miniter=Defaults.contr_miniter, verbosity=2, svd_alg=Defaults.svd_alg, trscheme=Defaults.trscheme, @@ -110,22 +110,22 @@ function MPSKit.leading_boundary(envinit, state, alg::CTMRG) log = ignore_derivatives(() -> MPSKit.IterLog("CTMRG")) return LoggingExtras.withlevel(; alg.verbosity) do - ctmrg_loginit!(log, η, N) + contr_loginit!(log, η, N) for iter in 1:(alg.maxiter) env, = ctmrg_iter(state, env, alg) # Grow and renormalize in all 4 directions η, CS, TS = calc_convergence(env, CS, TS) N = norm(state, env) - ctmrg_logiter!(log, iter, η, N) + contr_logiter!(log, iter, η, N) if η ≤ alg.tol - ctmrg_logfinish!(log, iter, η, N) + contr_logfinish!(log, iter, η, N) break end if iter == alg.maxiter - ctmrg_logcancel!(log, iter, η, N) + contr_logcancel!(log, iter, η, N) else - ctmrg_logiter!(log, iter, η, N) + contr_logiter!(log, iter, η, N) end end return env @@ -161,16 +161,6 @@ function ctmrg_iter(state, envs::CTMRGEnv, alg::SimultaneousCTMRG) return envs′, info end -ctmrg_loginit!(log, η, N) = @infov 2 loginit!(log, η, N) -ctmrg_logiter!(log, iter, η, N) = @infov 3 logiter!(log, iter, η, N) -ctmrg_logfinish!(log, iter, η, N) = @infov 2 logfinish!(log, iter, η, N) -ctmrg_logcancel!(log, iter, η, N) = @warnv 1 logcancel!(log, iter, η, N) - -@non_differentiable ctmrg_loginit!(args...) -@non_differentiable ctmrg_logiter!(args...) -@non_differentiable ctmrg_logfinish!(args...) -@non_differentiable ctmrg_logcancel!(args...) - # ======================================================================================== # # Expansion step # ======================================================================================== # diff --git a/src/algorithms/vumps/vumps.jl b/src/algorithms/vumps/vumps.jl new file mode 100644 index 00000000..41094db7 --- /dev/null +++ b/src/algorithms/vumps/vumps.jl @@ -0,0 +1,23 @@ +@kwdef mutable struct VUMPS{F} <: Algorithm + tol::Float64 = Defaults.contr_tol + maxiter::Int = Defaults.contr_maxiter + finalize::F = Defaults._finalize + verbosity::Int = Defaults.verbosity +end + +function leading_boundary(O::Matrix{<:AbstractTensorMap{S, 2, 2}}, alg::VUMPS) + # initialize + rt = VUMPSRuntime(O, nothing, nothing, nothing, nothing, nothing) + return rt +end + +function vumps(rt::VUMPSRuntime; tol::Real=1e-10, maxiter::Int=10, miniter::Int=1, verbose=false, show_every = Inf) + # initialize + olderror = Inf + vumps_counting = show_every_count(show_every) + + stopfun = StopFunction(olderror, -1, tol, maxiter, miniter) + rt, err = fixedpoint(res -> vumpstep(res...;show_counting=vumps_counting), (rt, olderror), stopfun) + verbose && println("vumps done@step: $(stopfun.counter), error=$(err)") + return rt, err +end \ No newline at end of file diff --git a/src/environments/vumps_environments.jl b/src/environments/vumps_environments.jl new file mode 100644 index 00000000..ce198d5a --- /dev/null +++ b/src/environments/vumps_environments.jl @@ -0,0 +1,79 @@ +""" + VUMPSEnv{T<:Number, S<:IndexSpace, + OT<:AbstractTensorMap{S, 2, 2}, + ET<:AbstractTensorMap{S, 2, 1}, + CT<:AbstractTensorMap{S, 1, 1}} + +A struct that contains the environment of the VUMPS algorithm for calculate observables. + +For a `Ni` x `Nj` unitcell, each is a Matrix, containing + +- `AC`: The mixed canonical environment tensor. +- `AR`: The right canonical environment tensor. +- `Lu`: The left upper environment tensor. +- `Ru`: The right upper environment tensor. +- `Lo`: The left mixed environment tensor. +- `Ro`: The right mixed environment tensor. +""" +struct VUMPSEnv{T<:Number, S<:IndexSpace, + OT<:AbstractTensorMap{S, 2, 2}, + ET<:AbstractTensorMap{S, 2, 1}, + CT<:AbstractTensorMap{S, 1, 1}} + AC::Matrix{ET} + AR::Matrix{ET} + Lu::Matrix{ET} + Ru::Matrix{ET} + Lo::Matrix{ET} + Ro::Matrix{ET} + function VUMPSEnv(AC::Matrix{ET}, + AR::Matrix{ET} + Lu::Matrix{ET}, + Ru::Matrix{ET}, + Lo::Matrix{ET}, + Ro::Matrix{ET}) where {OT, ET, CT} + T = eltype(O[1]) + new{T, S, OT, ET, CT}(AC, AR, Lu, Ru, Lo, Ro) + end +end + +""" + VUMPSRuntime{T<:Number, S<:IndexSpace, + OT<:AbstractTensorMap{S, 2, 2}, + ET<:AbstractTensorMap{S, 2, 1}, + CT<:AbstractTensorMap{S, 1, 1}} + +A struct that contains the environment of the VUMPS algorithm for runtime calculations. + +For a `Ni` x `Nj` unitcell, each is a Matrix, containing + +- `O`: The center transfer matrix PEPO tensor. +- `AL`: The left canonical environment tensor. +- `AR`: The right canonical environment tensor. +- `C`: The canonical environment tensor. +- `L`: The left environment tensor. +- `R`: The right environment tensor. +""" +struct VUMPSRuntime{T<:Number, S<:IndexSpace, + OT<:AbstractTensorMap{S, 2, 2}, + ET<:AbstractTensorMap{S, 2, 1}, + CT<:AbstractTensorMap{S, 1, 1}} + O::Matrix{OT} + AL::Matrix{ET} + AR::Matrix{ET} + C::Matrix{CT} + L::Matrix{ET} + R::Matrix{ET} + function VUMPSRuntime(O::Matrix{OT}, + AL::Matrix{ET}, + AR::Matrix{ET}, + C::Matrix{CT}, + L::Matrix{ET}, + R::Matrix{ET}) where {OT, ET, CT} + T = eltype(O[1]) + new{T, S, OT, ET, CT}(O, AL, AR, C, L, R) + end +end + +function VUMPSRuntime(ψ₀, χ::Int) + +end \ No newline at end of file diff --git a/src/utility/defaults.jl b/src/utility/defaults.jl new file mode 100644 index 00000000..5c195834 --- /dev/null +++ b/src/utility/defaults.jl @@ -0,0 +1,53 @@ +""" + module Defaults + +Module containing default values that represent typical algorithm parameters. + +- `contr_maxiter`: Maximum number of iterations for the contraction algorithm. +- `contr_miniter`: Minimum number of iterations for the contraction algorithm. +- `contr_tol`: Tolerance for the contraction algorithm. +- `fpgrad_maxiter`: Maximum number of iterations for the fixed-point gradient algorithm. +- `fpgrad_tol`: Tolerance for the fixed-point gradient algorithm. +- `verbosity`: Level of verbosity for the algorithm. +- `contractionscheme`: Scheme for contracting the environment. +- `reuse_env`: Whether to reuse the environment. +- `trscheme`: Truncation scheme. +- `iterscheme`: Iteration scheme. +- `fwd_alg`: Forward algorithm for the SVD. +- `rrule_alg`: Rule algorithm for the SVD. +- `svd_alg`: SVD algorithm. +- `optimizer`: Optimizer for the algorithm. +- `gradient_linsolver`: Linear solver for the gradient. +- `gradient_alg`: Algorithm for the gradient. +- `_finalize`: Function to finalize the algorithm. +""" +module Defaults + const VERBOSE_NONE = 0 + const VERBOSE_WARN = 1 + const VERBOSE_CONV = 2 + const VERBOSE_ITER = 3 + const VERBOSE_ALL = 4 + + using TensorKit, KrylovKit, OptimKit + using PEPSKit: LinSolver, FixedSpaceTruncation, SVDAdjoint + const contr_maxiter = 100 + const contr_miniter = 4 + const contr_tol = 1e-8 + const fpgrad_maxiter = 30 + const fpgrad_tol = 1e-6 + const verbosity = VERBOSE_ITER + const contractionscheme = :simultaneous + const reuse_env = true + const trscheme = FixedSpaceTruncation() + const iterscheme = :fixed + const fwd_alg = TensorKit.SVD() + const rrule_alg = GMRES(; tol=1e1contr_tol) + const svd_alg = SVDAdjoint(; fwd_alg, rrule_alg) + const optimizer = LBFGS(32; maxiter=100, gradtol=1e-4, verbosity=2) + const gradient_linsolver = KrylovKit.BiCGStab(; + maxiter=Defaults.fpgrad_maxiter, tol=Defaults.fpgrad_tol + ) + const gradient_alg = LinSolver(; solver=gradient_linsolver, iterscheme) + + _finalize(iter, state, opp, envs) = (state, envs) +end \ No newline at end of file diff --git a/src/utility/loginfo.jl b/src/utility/loginfo.jl new file mode 100644 index 00000000..4847e00e --- /dev/null +++ b/src/utility/loginfo.jl @@ -0,0 +1,9 @@ +contr_loginit!(log, η, N) = @infov 2 loginit!(log, η, N) +contr_logiter!(log, iter, η, N) = @infov 3 logiter!(log, iter, η, N) +contr_logfinish!(log, iter, η, N) = @infov 2 logfinish!(log, iter, η, N) +contr_logcancel!(log, iter, η, N) = @warnv 1 logcancel!(log, iter, η, N) + +@non_differentiable contr_loginit!(args...) +@non_differentiable contr_logiter!(args...) +@non_differentiable contr_logfinish!(args...) +@non_differentiable contr_logcancel!(args...) \ No newline at end of file From 4d322829b3ca7895674eeb2c4f0218aab5d1120e Mon Sep 17 00:00:00 2001 From: XingyuZhang2018 <864129714@qq.com> Date: Mon, 21 Oct 2024 18:14:18 +0200 Subject: [PATCH 07/25] start own VUMPS without MPSKit --- src/PEPSKit.jl | 16 +- src/algorithms/vumps/vumps.jl | 2 +- src/environments/vumps_environments.jl | 58 ++++- src/operators/transferpeps.jl | 293 ++++++++++------------- src/utility/defaults.jl | 1 + test/boundarymps/vumps.jl | 69 ------ test/{boundarymps => vumps}/gradparts.jl | 0 test/vumps/vumps_environment.jl | 116 +++++++++ 8 files changed, 301 insertions(+), 254 deletions(-) delete mode 100644 test/boundarymps/vumps.jl rename test/{boundarymps => vumps}/gradparts.jl (100%) create mode 100644 test/vumps/vumps_environment.jl diff --git a/src/PEPSKit.jl b/src/PEPSKit.jl index 5a1fa557..9aa84995 100644 --- a/src/PEPSKit.jl +++ b/src/PEPSKit.jl @@ -11,7 +11,7 @@ using LoggingExtras using MPSKit: loginit!, logiter!, logfinish!, logcancel! using MPSKitModels -include("utility/defaults.jl") + include("utility/util.jl") include("utility/svd.jl") include("utility/rotations.jl") @@ -24,16 +24,17 @@ include("states/abstractpeps.jl") include("states/infinitepeps.jl") include("operators/transferpeps.jl") -include("operators/infinitepepo.jl") -include("operators/transferpepo.jl") -include("operators/derivatives.jl") +# include("operators/infinitepepo.jl") +# include("operators/transferpepo.jl") +# include("operators/derivatives.jl") include("operators/localoperator.jl") include("operators/lattices/squarelattice.jl") include("operators/models.jl") include("environments/ctmrg_environments.jl") -include("environments/transferpeps_environments.jl") -include("environments/transferpepo_environments.jl") +# include("environments/transferpeps_environments.jl") +# include("environments/transferpepo_environments.jl") +include("environments/vumps_environments.jl") abstract type Algorithm end include("algorithms/contractions/localoperator.jl") @@ -50,6 +51,8 @@ include("algorithms/peps_opt.jl") include("utility/symmetrization.jl") +include("utility/defaults.jl") + export SVDAdjoint, IterSVD, NonTruncSVDAdjoint export FixedSpaceTruncation, ProjectorAlg, CTMRG, CTMRGEnv, correlation_length export LocalOperator @@ -59,7 +62,6 @@ export PEPSOptimize, GeomSum, ManualIter, LinSolver export fixedpoint export InfinitePEPS, InfiniteTransferPEPS -export InfinitePEPO, InfiniteTransferPEPO export initializeMPS, initializePEPS export ReflectDepth, ReflectWidth, Rotate, RotateReflect export symmetrize!, symmetrize_retract_and_finalize! diff --git a/src/algorithms/vumps/vumps.jl b/src/algorithms/vumps/vumps.jl index 41094db7..e1716163 100644 --- a/src/algorithms/vumps/vumps.jl +++ b/src/algorithms/vumps/vumps.jl @@ -5,7 +5,7 @@ verbosity::Int = Defaults.verbosity end -function leading_boundary(O::Matrix{<:AbstractTensorMap{S, 2, 2}}, alg::VUMPS) +function leading_boundary(O::Matrix, alg::VUMPS) # initialize rt = VUMPSRuntime(O, nothing, nothing, nothing, nothing, nothing) return rt diff --git a/src/environments/vumps_environments.jl b/src/environments/vumps_environments.jl index ce198d5a..cc7c909e 100644 --- a/src/environments/vumps_environments.jl +++ b/src/environments/vumps_environments.jl @@ -16,9 +16,7 @@ For a `Ni` x `Nj` unitcell, each is a Matrix, containing - `Ro`: The right mixed environment tensor. """ struct VUMPSEnv{T<:Number, S<:IndexSpace, - OT<:AbstractTensorMap{S, 2, 2}, - ET<:AbstractTensorMap{S, 2, 1}, - CT<:AbstractTensorMap{S, 1, 1}} + ET<:AbstractTensorMap{S, 3, 1}} AC::Matrix{ET} AR::Matrix{ET} Lu::Matrix{ET} @@ -26,13 +24,14 @@ struct VUMPSEnv{T<:Number, S<:IndexSpace, Lo::Matrix{ET} Ro::Matrix{ET} function VUMPSEnv(AC::Matrix{ET}, - AR::Matrix{ET} + AR::Matrix{ET}, Lu::Matrix{ET}, Ru::Matrix{ET}, Lo::Matrix{ET}, - Ro::Matrix{ET}) where {OT, ET, CT} - T = eltype(O[1]) - new{T, S, OT, ET, CT}(AC, AR, Lu, Ru, Lo, Ro) + Ro::Matrix{ET}) where {ET} + T = eltype(AC[1]) + S = spacetype(AC[1]) + new{T, S, ET}(AC, AR, Lu, Ru, Lo, Ro) end end @@ -54,26 +53,61 @@ For a `Ni` x `Nj` unitcell, each is a Matrix, containing - `R`: The right environment tensor. """ struct VUMPSRuntime{T<:Number, S<:IndexSpace, - OT<:AbstractTensorMap{S, 2, 2}, - ET<:AbstractTensorMap{S, 2, 1}, + OT<:InfiniteTransferPEPS, + ET<:AbstractTensorMap{S, 3, 1}, CT<:AbstractTensorMap{S, 1, 1}} - O::Matrix{OT} + O::OT AL::Matrix{ET} AR::Matrix{ET} C::Matrix{CT} L::Matrix{ET} R::Matrix{ET} - function VUMPSRuntime(O::Matrix{OT}, + function VUMPSRuntime(O::OT, AL::Matrix{ET}, AR::Matrix{ET}, C::Matrix{CT}, L::Matrix{ET}, R::Matrix{ET}) where {OT, ET, CT} - T = eltype(O[1]) + T = eltype(AL[1]) + S = spacetype(AL[1]) new{T, S, OT, ET, CT}(O, AL, AR, C, L, R) end end +""" + +```` + + l ←------- r + / \ + / \ + t d +```` +Initalize a boundary MPS for the transfer operator `O` by specifying an array of virtual +spaces consistent with the unit cell. +""" +function initial_A(O::InfiniteTransferPEPS, χ::VectorSpace) + T = eltype(O) + Ni, Nj = size(O) + A = Matrix{TensorMap}(undef, Ni, Nj) + for j in 1:Nj, i in 1:Ni + D = space(O.top[i, j], 4) + A[i, j] = TensorMap(rand, T, χ * D * D', χ) + end + return A +end + +function initial_C(A::Matrix{<:AbstractTensorMap}) + T = eltype(A[1]) + Ni, Nj = size(A) + C = Matrix{TensorMap}(undef, Ni, Nj) + for j in 1:Nj, i in 1:Ni + χ = space(A[i, j], 1) + C[i, j] = isomorphism(Matrix{T}, χ, χ) # only for CPU + end + return C +end + function VUMPSRuntime(ψ₀, χ::Int) end \ No newline at end of file diff --git a/src/operators/transferpeps.jl b/src/operators/transferpeps.jl index 98093025..6a3c6225 100644 --- a/src/operators/transferpeps.jl +++ b/src/operators/transferpeps.jl @@ -4,190 +4,153 @@ Represents an infinite transfer operator corresponding to a single row of a partition function which corresponds to the overlap between 'ket' and 'bra' `InfinitePEPS` states. """ -struct InfiniteTransferPEPS{T} - top::PeriodicArray{T,1} - bot::PeriodicArray{T,1} +struct InfiniteTransferPEPS{TT, BT} + top::Matrix{TT} + bot::Matrix{BT} end -InfiniteTransferPEPS(top) = InfiniteTransferPEPS(top, top) +function InfiniteTransferPEPS(ipeps::InfinitePEPS) + top = ipeps.A + bot = [A' for A in ipeps.A] + return InfiniteTransferPEPS(top, bot) +end -function ChainRulesCore.rrule(::Type{InfiniteTransferPEPS}, top::PeriodicArray{T,1}, bot::PeriodicArray{T,1}) where {T} +function ChainRulesCore.rrule(::Type{InfiniteTransferPEPS}, top::Matrix, bot::Matrix) function pullback(Δ) return NoTangent(), Δ.top, Δ.bot end return InfiniteTransferPEPS(top, bot), pullback end -""" - InfiniteTransferPEPS(T::InfinitePEPS, dir, row) - -Constructs a transfer operator corresponding to a single row of a partition function -representing the norm of the state `T`. The partition function is first rotated such that -the direction `dir` faces north, after which its `row`th row from the north is selected. -""" -function InfiniteTransferPEPS(T::InfinitePEPS, dir, row) - T = rotate_north(T, dir) - return InfiniteTransferPEPS(PeriodicArray(T[row, :])) -end - +Base.eltype(transfer::InfiniteTransferPEPS) = eltype(transfer.top[1]) Base.size(transfer::InfiniteTransferPEPS) = size(transfer.top) -Base.size(transfer::InfiniteTransferPEPS, args...) = size(transfer.top, args...) -Base.length(transfer::InfiniteTransferPEPS) = size(transfer, 1) -Base.getindex(O::InfiniteTransferPEPS, i) = (O.top[i], O.bot[i]) - -Base.iterate(O::InfiniteTransferPEPS, i=1) = i > length(O) ? nothing : (O[i], i + 1) - -import MPSKit.GenericMPSTensor - -""" - const TransferPEPSMultiline = MPSKit.Multiline{<:InfiniteTransferPEPS} +# Base.size(transfer::InfiniteTransferPEPS, args...) = size(transfer.top, args...) +# Base.length(transfer::InfiniteTransferPEPS) = size(transfer, 1) +# Base.getindex(O::InfiniteTransferPEPS, i) = (O.top[i], O.bot[i]) -Type that represents a multi-line transfer operator, where each line each corresponds to a -row of a partition function encoding the overlap between 'ket' and 'bra' `InfinitePEPS` -states. -""" -const TransferPEPSMultiline = MPSKit.Multiline{<:InfiniteTransferPEPS} -Base.convert(::Type{TransferPEPSMultiline}, O::InfiniteTransferPEPS) = MPSKit.Multiline([O]) -Base.getindex(t::TransferPEPSMultiline, i::Colon, j::Int) = Base.getindex.(t.data[i], j) -Base.getindex(t::TransferPEPSMultiline, i::Int, j) = Base.getindex(t.data[i], j) +# Base.iterate(O::InfiniteTransferPEPS, i=1) = i > length(O) ? nothing : (O[i], i + 1) """ - TransferPEPSMultiline(T::InfinitePEPS, dir) - -Construct a multi-row transfer operator corresponding to the partition function representing -the norm of the state `T`. The partition function is first rotated such -that the direction `dir` faces north. -""" -function TransferPEPSMultiline(T::InfinitePEPS, dir) - rowsize = size(T, mod1(dir, 2)) # depends on dir - return MPSKit.Multiline(map(cr -> InfiniteTransferPEPS(T, dir, cr), 1:rowsize)) -end - -""" - initializeMPS( - O::Union{InfiniteTransferPEPS,InfiniteTransferPEPO}, - virtualspaces::AbstractArray{<:ElementarySpace,1} - ) - initializeMPS( - O::Union{TransferPEPSMultiline,TransferPEPOMultiline}, - virtualspaces::AbstractArray{<:ElementarySpace,2} - ) - ```` - - l ←------- r - / \ - / \ - t d + ┌─ Aᵢⱼ─ ┌─ + ρᵢⱼ │ = ρⱼ₊₁ + └─ Aᵢⱼ─ └─ ```` -Initalize a boundary MPS for the transfer operator `O` by specifying an array of virtual -spaces consistent with the unit cell. """ -function initializeMPS(O::InfiniteTransferPEPS, virtualspaces::AbstractArray{S,1}) where {S} - return InfiniteMPS([ - TensorMap( - rand, - MPSKit.Defaults.eltype, # should be scalartype of transfer PEPS? - virtualspaces[_prev(i, end)] * space(O.top[i], 2)' * space(O.bot[i], 2), - virtualspaces[mod1(i, end)], - ) for i in 1:length(O) - ]) -end -function initializeMPS(O::InfiniteTransferPEPS, χ::Int) - return InfiniteMPS([ - TensorMap( - rand, - MPSKit.Defaults.eltype, - ℂ^χ * space(O.top[i], 2)' * space(O.bot[i], 2), - ℂ^χ, - ) for i in 1:length(O) - ]) -end -function initializeMPS(O::MPSKit.Multiline, virtualspaces::AbstractArray{S,2}) where {S} - mpss = map(cr -> initializeMPS(O[cr], virtualspaces[cr, :]), 1:size(O, 1)) - return MPSKit.Multiline(mpss) -end -function initializeMPS(O::MPSKit.Multiline, virtualspaces::AbstractArray{S,1}) where {S} - return initializeMPS(O, repeat(virtualspaces, length(O), 1)) -end -function initializeMPS(O::MPSKit.Multiline, V::ElementarySpace) - return initializeMPS(O, repeat([V], length(O), length(O[1]))) -end -function initializeMPS(O::MPSKit.Multiline, χ::Int) - return initializeMPS(O, repeat([ℂ^χ], length(O), length(O[1]))) -end - -function MPSKit.transfer_left( - GL::GenericMPSTensor{S,3}, - O::NTuple{2,PEPSTensor}, - A::GenericMPSTensor{S,3}, - Ā::GenericMPSTensor{S,3}, -) where {S} - return @tensor GL′[-1 -2 -3; -4] := - GL[1 2 4; 7] * - conj(Ā[1 3 6; -1]) * - O[1][5; 8 -2 3 2] * - conj(O[2][5; 9 -3 6 4]) * - A[7 8 9; -4] +function Cmap(C::Matrix{<:AbstractTensorMap}, A::Matrix{<:AbstractTensorMap}) + Ni, Nj = size(C) + C = copy(C) + for j in 1:Nj, i in 1:Ni + jr = mod1(j + 1, Nj) + @tensor C[i,jr][-1; -2] = C[i,j][4; 1] * A[i,j][1 2 3; -2] * conj(A[i,j][4 2 3; -1]) + end + return C end -function MPSKit.transfer_right( - GR::GenericMPSTensor{S,3}, - O::NTuple{2,PEPSTensor}, - A::GenericMPSTensor{S,3}, - Ā::GenericMPSTensor{S,3}, -) where {S} - return @tensor GR′[-1 -2 -3; -4] := - GR[7 6 2; 1] * - conj(Ā[-4 4 3; 1]) * - O[1][5; 9 6 4 -2] * - conj(O[2][5; 8 2 3 -3]) * - A[-1 9 8 7] -end +TensorKit.inner(x::Matrix{TensorMap}, y::Matrix{TensorMap}) = sum(map(TensorKit.inner, x, y)) +TensorKit.add!!(x::Matrix{<:AbstractTensorMap}, y::Matrix{<:AbstractTensorMap}, a::Number, b::Number) = (x .= map((x, y) -> TensorKit.add!!(x, y, a, b), x, y); x) +TensorKit.scale!!(x::Matrix{<:AbstractTensorMap}, a::Number) = (x .= map(x -> TensorKit.scale!!(x, a), x); x) -@doc """ - MPSKit.expectation_value(st::InfiniteMPS, op::Union{InfiniteTransferPEPS,InfiniteTransferPEPO}) - MPSKit.expectation_value(st::MPSMultiline, op::Union{TransferPEPSMultiline,TransferPEPOMultiline}) +""" + getL!(A,L; kwargs...) -Compute expectation value of the transfer operator `op` for the state `st` for each site in -the unit cell. -""" MPSKit.expectation_value(st, op) +```` + ┌─ Aᵢⱼ ─ Aᵢⱼ₊₁─ ┌─ L ─ + ρᵢⱼ │ │ = ρᵢⱼ = │ + └─ Aᵢⱼ─ Aᵢⱼ₊₁─ └─ L'─ +```` -function MPSKit.expectation_value(st::InfiniteMPS, transfer::InfiniteTransferPEPS) - return expectation_value( - convert(MPSMultiline, st), convert(TransferPEPSMultiline, transfer) - ) -end -function MPSKit.expectation_value(st::MPSMultiline, mpo::TransferPEPSMultiline) - return expectation_value(st, environments(st, mpo)) -end -function MPSKit.expectation_value( - st::MPSMultiline, ca::MPSKit.PerMPOInfEnv{H,V,S,A} -) where {H<:TransferPEPSMultiline,V,S,A} - return expectation_value(st, ca.opp, ca) -end -function MPSKit.expectation_value( - st::MPSMultiline, opp::TransferPEPSMultiline, ca::MPSKit.PerMPOInfEnv -) - return prod(product(1:size(st, 1), 1:size(st, 2))) do (i, j) - O_ij = opp[i, j] - return @tensor leftenv(ca, i, j, st)[1 2 4; 7] * - conj(st[i + 1].AC[j][1 3 6; 13]) * - O_ij[1][5; 8 11 3 2] * - conj(O_ij[2][5; 9 12 6 4]) * - st[i].AC[j][7 8 9; 10] * - rightenv(ca, i, j, st)[10 11 12; 13] - end -end +ρ=L'*L, return L, where `L`is guaranteed to have positive diagonal elements. -@doc """ - MPSKit.leading_boundary( - st::InfiniteMPS, op::Union{InfiniteTransferPEPS,InfiniteTransferPEPO}, alg, [envs] - ) - MPSKit.leading_boundary( - st::MPSMulitline, op::Union{TransferPEPSMultiline,TransferPEPOMultiline}, alg, [envs] - ) - -Approximate the leading boundary MPS eigenvector for the transfer operator `op` using `st` -as initial guess. -""" MPSKit.leading_boundary(st, op, alg) +""" +function getL!(A::Matrix{<:AbstractTensorMap}, L::Matrix{<:AbstractTensorMap}; kwargs...) + Ni, Nj = size(A) + λs, Cs, info = eigsolve(C -> Cmap(C, A), L, 1, :LM; ishermitian = false, maxiter = 1, kwargs...) + + # @debug "getL eigsolve" λs info sort(abs.(λs)) + # info.converged == 0 && @warn "getL not converged" + # _, ρs1 = selectpos(λs, ρs, Nj) + # @inbounds @views for j = 1:Nj, i = 1:Ni + # ρ = ρs1[:,:,i,j] + ρs1[:,:,i,j]' + # ρ ./= tr(ρ) + # F = svd!(ρ) + # Lo = lmul!(Diagonal(sqrt.(F.S)), F.Vt) + # _, R = qrpos!(Lo) + # L[:,:,i,j] = R + # end + # return L +end +# function MPSKit.transfer_left( +# GL::GenericMPSTensor{S,3}, +# O::NTuple{2,PEPSTensor}, +# A::GenericMPSTensor{S,3}, +# Ā::GenericMPSTensor{S,3}, +# ) where {S} +# return @tensor GL′[-1 -2 -3; -4] := +# GL[1 2 4; 7] * +# conj(Ā[1 3 6; -1]) * +# O[1][5; 8 -2 3 2] * +# conj(O[2][5; 9 -3 6 4]) * +# A[7 8 9; -4] +# end + +# function MPSKit.transfer_right( +# GR::GenericMPSTensor{S,3}, +# O::NTuple{2,PEPSTensor}, +# A::GenericMPSTensor{S,3}, +# Ā::GenericMPSTensor{S,3}, +# ) where {S} +# return @tensor GR′[-1 -2 -3; -4] := +# GR[7 6 2; 1] * +# conj(Ā[-4 4 3; 1]) * +# O[1][5; 9 6 4 -2] * +# conj(O[2][5; 8 2 3 -3]) * +# A[-1 9 8 7] +# end + +# @doc """ +# MPSKit.expectation_value(st::InfiniteMPS, op::Union{InfiniteTransferPEPS,InfiniteTransferPEPO}) +# MPSKit.expectation_value(st::MPSMultiline, op::Union{TransferPEPSMultiline,TransferPEPOMultiline}) + +# Compute expectation value of the transfer operator `op` for the state `st` for each site in +# the unit cell. +# """ MPSKit.expectation_value(st, op) + +# function MPSKit.expectation_value(st::InfiniteMPS, transfer::InfiniteTransferPEPS) +# return expectation_value( +# convert(MPSMultiline, st), convert(TransferPEPSMultiline, transfer) +# ) +# end +# function MPSKit.expectation_value(st::MPSMultiline, mpo::TransferPEPSMultiline) +# return expectation_value(st, environments(st, mpo)) +# end +# function MPSKit.expectation_value( +# st::MPSMultiline, ca::MPSKit.PerMPOInfEnv{H,V,S,A} +# ) where {H<:TransferPEPSMultiline,V,S,A} +# return expectation_value(st, ca.opp, ca) +# end +# function MPSKit.expectation_value( +# st::MPSMultiline, opp::TransferPEPSMultiline, ca::MPSKit.PerMPOInfEnv +# ) +# return prod(product(1:size(st, 1), 1:size(st, 2))) do (i, j) +# O_ij = opp[i, j] +# return @tensor leftenv(ca, i, j, st)[1 2 4; 7] * +# conj(st[i + 1].AC[j][1 3 6; 13]) * +# O_ij[1][5; 8 11 3 2] * +# conj(O_ij[2][5; 9 12 6 4]) * +# st[i].AC[j][7 8 9; 10] * +# rightenv(ca, i, j, st)[10 11 12; 13] +# end +# end + +# @doc """ +# MPSKit.leading_boundary( +# st::InfiniteMPS, op::Union{InfiniteTransferPEPS,InfiniteTransferPEPO}, alg, [envs] +# ) +# MPSKit.leading_boundary( +# st::MPSMulitline, op::Union{TransferPEPSMultiline,TransferPEPOMultiline}, alg, [envs] +# ) + +# Approximate the leading boundary MPS eigenvector for the transfer operator `op` using `st` +# as initial guess. +# """ MPSKit.leading_boundary(st, op, alg) diff --git a/src/utility/defaults.jl b/src/utility/defaults.jl index 5c195834..78d3c6d1 100644 --- a/src/utility/defaults.jl +++ b/src/utility/defaults.jl @@ -30,6 +30,7 @@ module Defaults using TensorKit, KrylovKit, OptimKit using PEPSKit: LinSolver, FixedSpaceTruncation, SVDAdjoint + const eltype = ComplexF64 const contr_maxiter = 100 const contr_miniter = 4 const contr_tol = 1e-8 diff --git a/test/boundarymps/vumps.jl b/test/boundarymps/vumps.jl deleted file mode 100644 index a161c073..00000000 --- a/test/boundarymps/vumps.jl +++ /dev/null @@ -1,69 +0,0 @@ -using Test -using Random -using PEPSKit -using TensorKit -using MPSKit -using LinearAlgebra - -Random.seed!(29384293742893) - -const vumps_alg = VUMPS(; alg_eigsolve=MPSKit.Defaults.alg_eigsolve(; ishermitian=false)) -@testset "(1, 1) PEPS" begin - psi = InfinitePEPS(ComplexSpace(2), ComplexSpace(2)) - - T = PEPSKit.InfiniteTransferPEPS(psi, 1, 1) - mps = PEPSKit.initializeMPS(T, [ComplexSpace(20)]) - - mps, envs, ϵ = leading_boundary(mps, T, vumps_alg) - N = abs(sum(expectation_value(mps, T))) - - ctm = leading_boundary(CTMRGEnv(psi, ComplexSpace(20)), psi, CTMRG(; verbosity=1)) - N´ = abs(norm(psi, ctm)) - - @test N ≈ N´ atol = 1e-3 -end - -@testset "(2, 2) PEPS" begin - psi = InfinitePEPS(ComplexSpace(2), ComplexSpace(2); unitcell=(2, 2)) - T = PEPSKit.TransferPEPSMultiline(psi, 1) - - mps = PEPSKit.initializeMPS(T, fill(ComplexSpace(20), 2, 2)) - mps, envs, ϵ = leading_boundary(mps, T, vumps_alg) - N = abs(prod(expectation_value(mps, T))) - - ctm = leading_boundary(CTMRGEnv(psi, ComplexSpace(20)), psi, CTMRG(; verbosity=1)) - N´ = abs(norm(psi, ctm)) - - @test N ≈ N´ rtol = 1e-2 -end - -@testset "PEPO runthrough" begin - function ising_pepo(beta; unitcell=(1, 1, 1)) - t = ComplexF64[exp(beta) exp(-beta); exp(-beta) exp(beta)] - q = sqrt(t) - - O = zeros(2, 2, 2, 2, 2, 2) - O[1, 1, 1, 1, 1, 1] = 1 - O[2, 2, 2, 2, 2, 2] = 1 - @tensor o[-1 -2; -3 -4 -5 -6] := - O[1 2; 3 4 5 6] * - q[-1; 1] * - q[-2; 2] * - q[-3; 3] * - q[-4; 4] * - q[-5; 5] * - q[-6; 6] - - O = TensorMap(o, ℂ^2 ⊗ (ℂ^2)' ← ℂ^2 ⊗ ℂ^2 ⊗ (ℂ^2)' ⊗ (ℂ^2)') - - return InfinitePEPO(O; unitcell) - end - - psi = InfinitePEPS(ComplexSpace(2), ComplexSpace(2)) - O = ising_pepo(1) - T = InfiniteTransferPEPO(psi, O, 1, 1) - - mps = PEPSKit.initializeMPS(T, [ComplexSpace(10)]) - mps, envs, ϵ = leading_boundary(mps, T, vumps_alg) - f = abs(prod(expectation_value(mps, T))) -end diff --git a/test/boundarymps/gradparts.jl b/test/vumps/gradparts.jl similarity index 100% rename from test/boundarymps/gradparts.jl rename to test/vumps/gradparts.jl diff --git a/test/vumps/vumps_environment.jl b/test/vumps/vumps_environment.jl new file mode 100644 index 00000000..481c925f --- /dev/null +++ b/test/vumps/vumps_environment.jl @@ -0,0 +1,116 @@ +using Test +using Random +using PEPSKit +using PEPSKit: initial_A, initial_C +using PEPSKit: Cmap, getL! +using TensorKit +using LinearAlgebra + +begin "test utility" + ds = [ℂ^2] + Ds = [ℂ^3] + χs = [ℂ^4] +end +@testset begin + A = TensorMap(rand, ComplexF64, ℂ^2 ⊗ ℂ^3, ℂ^10) + @show storagetype(typeof(A)) + # @tensor C = conj(A[1 2;3]) * A[1 2;3] + @tensor C = A'[3; 1 2] * A[1 2;3] + @show sqrt(C) norm(A) +end + + +@testset "InfiniteTransferPEPS for unitcell $Ni x $Nj" for Ni in 1:2, Nj in 1:2, (d, D, χ) in zip(ds, Ds, χs) + Random.seed!(42) + ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) + + itp = InfiniteTransferPEPS(ipeps) + @test itp.top == ipeps.A + @test itp.bot == [A' for A in ipeps.A] + @test all(i -> space(i) == (d ← D * D * D' * D'), itp.top) + @test all(i -> space(i) == (D * D * D' * D' ← d), itp.bot) +end + +@testset "initialize A C for unitcell $Ni x $Nj" for Ni in 1:2, Nj in 1:2, (d, D, χ) in zip(ds, Ds, χs) + Random.seed!(42) + ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) + + itp = InfiniteTransferPEPS(ipeps) + A = initial_A(itp, χ) + C = initial_C(A) + @test size(A) == (Ni, Nj) + @test size(C) == (Ni, Nj) + @test all(i -> space(i) == (χ * D * D' ← χ), A) + @test all(i -> space(i) == (χ ← χ), C) +end + + +@testset "Cmap for unitcell $Ni x $Nj" for Ni in 1:2, Nj in 1:2, (d, D, χ) in zip(ds, Ds, χs) + ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) + + itp = InfiniteTransferPEPS(ipeps) + A = initial_A(itp, χ) + C = initial_C(A) + C = Cmap(C, A) + + # @show inner(C, C) + getL!(A, C) +end + + + + + + + + + + + + + + +@testset "(2, 2) PEPS" begin + psi = InfinitePEPS(ComplexSpace(2), ComplexSpace(2); unitcell=(2, 2)) + T = PEPSKit.TransferPEPSMultiline(psi, 1) + + mps = PEPSKit.initializeMPS(T, fill(ComplexSpace(20), 2, 2)) + mps, envs, ϵ = leading_boundary(mps, T, vumps_alg) + N = abs(prod(expectation_value(mps, T))) + + ctm = leading_boundary(CTMRGEnv(psi, ComplexSpace(20)), psi, CTMRG(; verbosity=1)) + N´ = abs(norm(psi, ctm)) + + @test N ≈ N´ rtol = 1e-2 +end + +@testset "PEPO runthrough" begin + function ising_pepo(beta; unitcell=(1, 1, 1)) + t = ComplexF64[exp(beta) exp(-beta); exp(-beta) exp(beta)] + q = sqrt(t) + + O = zeros(2, 2, 2, 2, 2, 2) + O[1, 1, 1, 1, 1, 1] = 1 + O[2, 2, 2, 2, 2, 2] = 1 + @tensor o[-1 -2; -3 -4 -5 -6] := + O[1 2; 3 4 5 6] * + q[-1; 1] * + q[-2; 2] * + q[-3; 3] * + q[-4; 4] * + q[-5; 5] * + q[-6; 6] + + O = TensorMap(o, ℂ^2 ⊗ (ℂ^2)' ← ℂ^2 ⊗ ℂ^2 ⊗ (ℂ^2)' ⊗ (ℂ^2)') + + return InfinitePEPO(O; unitcell) + end + + psi = InfinitePEPS(ComplexSpace(2), ComplexSpace(2)) + O = ising_pepo(1) + T = InfiniteTransferPEPO(psi, O, 1, 1) + + mps = PEPSKit.initializeMPS(T, [ComplexSpace(10)]) + mps, envs, ϵ = leading_boundary(mps, T, vumps_alg) + f = abs(prod(expectation_value(mps, T))) +end From b4be238703d0406b5b22e8341e63862b24811e91 Mon Sep 17 00:00:00 2001 From: XingyuZhang2018 <864129714@qq.com> Date: Mon, 21 Oct 2024 21:50:20 +0200 Subject: [PATCH 08/25] to do: leftorth and rightorth --- src/environments/vumps_environments.jl | 72 ++++++++++++++++++++++++++ src/operators/transferpeps.jl | 45 +++------------- test/vumps/vumps_environment.jl | 3 +- 3 files changed, 80 insertions(+), 40 deletions(-) diff --git a/src/environments/vumps_environments.jl b/src/environments/vumps_environments.jl index cc7c909e..655bdadd 100644 --- a/src/environments/vumps_environments.jl +++ b/src/environments/vumps_environments.jl @@ -108,6 +108,78 @@ function initial_C(A::Matrix{<:AbstractTensorMap}) return C end +# KrylovKit patch +TensorKit.inner(x::Matrix{TensorMap}, y::Matrix{TensorMap}) = sum(map(TensorKit.inner, x, y)) +TensorKit.add!!(x::Matrix{<:AbstractTensorMap}, y::Matrix{<:AbstractTensorMap}, a::Number, b::Number) = map((x, y) -> TensorKit.add!!(x, y, a, b), x, y) +TensorKit.scale!!(x::Matrix{<:AbstractTensorMap}, a::Number) = map(x -> TensorKit.scale!!(x, a), x) + +""" + λs[1], Fs[1] = selectpos(λs, Fs) + +Select the max positive one of λs and corresponding Fs. +""" +function selectpos(λs, Fs, N) + if length(λs) > 1 && norm(abs(λs[1]) - abs(λs[2])) < 1e-12 + # @show "selectpos: λs are degeneracy" + N = min(N, length(λs)) + p = argmax(real(λs[1:N])) + # @show λs p abs.(λs) + return λs[1:N][p], Fs[1:N][p] + else + return λs[1], Fs[1] + end +end + +""" + getL!(A,L; kwargs...) + +```` + ┌─ Aᵢⱼ ─ Aᵢⱼ₊₁─ ┌─ L ─ + ρᵢⱼ │ │ = ρᵢⱼ = │ + └─ Aᵢⱼ─ Aᵢⱼ₊₁─ └─ L'─ +```` + +ρ=L'*L, return L, where `L`is guaranteed to have positive diagonal elements. + +""" +function getL!(A::Matrix{<:AbstractTensorMap}, L::Matrix{<:AbstractTensorMap}; verbosity = Defaults.verbosity, kwargs...) + Ni, Nj = size(A) + λs, ρs, info = eigsolve(ρ -> Cmap(ρ, A), L, 1, :LM; ishermitian = false, maxiter = 1, kwargs...) + verbosity >= 1 && info.converged == 0 && @warn "getL not converged" + _, ρs1 = selectpos(λs, ρs, Nj) + @inbounds for j = 1:Nj, i = 1:Ni + ρ = ρs1[i,j] + ρs1[i,j]' + ρ /= tr(ρ) + _, S, Vt = tsvd!(ρ) + # Lo = lmul!(Diagonal(sqrt.(F.S)), F.Vt) + Lo = sqrt(S) * Vt + _, R = leftorth!(Lo) + L[i,j] = R + end + return L +end + +""" + getAL(A,L) + +Given an MPS tensor `A` and `L` ,return a left-canonical MPS tensor `AL`, a gauge transform `R` and +a scalar factor `λ` such that ``λ AR R = L A`` +""" +function getAL(A::Matrix{<:AbstractTensorMap}, L::Matrix{<:AbstractTensorMap}) + Ni, Nj = size(A) + AL = similar(A) + Le = similar(L) + λ = zeros(Ni, Nj) + @inbounds for j = 1:Nj, i = 1:Ni + Q, R = leftorth!(reshape(L[:,:,i,j]*reshape(A[:,:,:,i,j], χ, D*χ), D*χ, χ)) # To do: correct the reshape to transpose + AL[:,:,:,i,j] = reshape(Q, χ, D, χ) + λ[i,j] = norm(R) + Le[:,:,i,j] = rmul!(R, 1/λ[i,j]) + end + return AL, Le, λ +end + + function VUMPSRuntime(ψ₀, χ::Int) end \ No newline at end of file diff --git a/src/operators/transferpeps.jl b/src/operators/transferpeps.jl index 6a3c6225..7c517de8 100644 --- a/src/operators/transferpeps.jl +++ b/src/operators/transferpeps.jl @@ -37,49 +37,16 @@ Base.size(transfer::InfiniteTransferPEPS) = size(transfer.top) └─ Aᵢⱼ─ └─ ```` """ -function Cmap(C::Matrix{<:AbstractTensorMap}, A::Matrix{<:AbstractTensorMap}) - Ni, Nj = size(C) - C = copy(C) - for j in 1:Nj, i in 1:Ni +function Cmap(ρ::Matrix{<:AbstractTensorMap}, A::Matrix{<:AbstractTensorMap}) + Ni, Nj = size(ρ) + ρ = deepcopy(ρ) + @inbounds for j in 1:Nj, i in 1:Ni jr = mod1(j + 1, Nj) - @tensor C[i,jr][-1; -2] = C[i,j][4; 1] * A[i,j][1 2 3; -2] * conj(A[i,j][4 2 3; -1]) + @tensor ρ[i,jr][-1; -2] = ρ[i,j][4; 1] * A[i,j][1 2 3; -2] * conj(A[i,j][4 2 3; -1]) end - return C + return ρ end -TensorKit.inner(x::Matrix{TensorMap}, y::Matrix{TensorMap}) = sum(map(TensorKit.inner, x, y)) -TensorKit.add!!(x::Matrix{<:AbstractTensorMap}, y::Matrix{<:AbstractTensorMap}, a::Number, b::Number) = (x .= map((x, y) -> TensorKit.add!!(x, y, a, b), x, y); x) -TensorKit.scale!!(x::Matrix{<:AbstractTensorMap}, a::Number) = (x .= map(x -> TensorKit.scale!!(x, a), x); x) - -""" - getL!(A,L; kwargs...) - -```` - ┌─ Aᵢⱼ ─ Aᵢⱼ₊₁─ ┌─ L ─ - ρᵢⱼ │ │ = ρᵢⱼ = │ - └─ Aᵢⱼ─ Aᵢⱼ₊₁─ └─ L'─ -```` - -ρ=L'*L, return L, where `L`is guaranteed to have positive diagonal elements. - -""" -function getL!(A::Matrix{<:AbstractTensorMap}, L::Matrix{<:AbstractTensorMap}; kwargs...) - Ni, Nj = size(A) - λs, Cs, info = eigsolve(C -> Cmap(C, A), L, 1, :LM; ishermitian = false, maxiter = 1, kwargs...) - - # @debug "getL eigsolve" λs info sort(abs.(λs)) - # info.converged == 0 && @warn "getL not converged" - # _, ρs1 = selectpos(λs, ρs, Nj) - # @inbounds @views for j = 1:Nj, i = 1:Ni - # ρ = ρs1[:,:,i,j] + ρs1[:,:,i,j]' - # ρ ./= tr(ρ) - # F = svd!(ρ) - # Lo = lmul!(Diagonal(sqrt.(F.S)), F.Vt) - # _, R = qrpos!(Lo) - # L[:,:,i,j] = R - # end - # return L -end # function MPSKit.transfer_left( # GL::GenericMPSTensor{S,3}, # O::NTuple{2,PEPSTensor}, diff --git a/test/vumps/vumps_environment.jl b/test/vumps/vumps_environment.jl index 481c925f..fcc2e237 100644 --- a/test/vumps/vumps_environment.jl +++ b/test/vumps/vumps_environment.jl @@ -19,7 +19,6 @@ end @show sqrt(C) norm(A) end - @testset "InfiniteTransferPEPS for unitcell $Ni x $Nj" for Ni in 1:2, Nj in 1:2, (d, D, χ) in zip(ds, Ds, χs) Random.seed!(42) ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) @@ -55,6 +54,8 @@ end # @show inner(C, C) getL!(A, C) + # λs, Cs, info = getL!(A, C) + # @test λs[1] * Cs[1] ≈ Cmap(Cs[1], A) rtol = 1e-12 end From ad1ad05ac73e9a41647b60c35e649fe7f99358a5 Mon Sep 17 00:00:00 2001 From: XingyuZhang2018 <864129714@qq.com> Date: Tue, 22 Oct 2024 17:45:46 +0200 Subject: [PATCH 09/25] finish canonical form, start FLFR --- src/PEPSKit.jl | 1 + .../contractions/vumps_contractions.jl | 80 ++++++++++ src/environments/vumps_environments.jl | 90 ++++++++++- src/operators/transferpeps.jl | 17 --- test/vumps/vumps_environment.jl | 143 +++++++++++------- 5 files changed, 255 insertions(+), 76 deletions(-) diff --git a/src/PEPSKit.jl b/src/PEPSKit.jl index 9aa84995..64f3176a 100644 --- a/src/PEPSKit.jl +++ b/src/PEPSKit.jl @@ -39,6 +39,7 @@ include("environments/vumps_environments.jl") abstract type Algorithm end include("algorithms/contractions/localoperator.jl") include("algorithms/contractions/ctmrg_contractions.jl") +include("algorithms/contractions/vumps_contractions.jl") include("algorithms/ctmrg/ctmrg.jl") include("algorithms/ctmrg/gaugefix.jl") diff --git a/src/algorithms/contractions/vumps_contractions.jl b/src/algorithms/contractions/vumps_contractions.jl index e69de29b..9619bfd5 100644 --- a/src/algorithms/contractions/vumps_contractions.jl +++ b/src/algorithms/contractions/vumps_contractions.jl @@ -0,0 +1,80 @@ + +""" + ρ = ρmap(ρ::Matrix{<:AbstractTensorMap}, A::Matrix{<:AbstractTensorMap}) +```` + ┌─ Aᵢⱼ─ ┌─ + ρᵢⱼ │ = ρⱼ₊₁ + └─ Aᵢⱼ─ └─ +```` +""" +function ρmap(ρ::Matrix{<:AbstractTensorMap}, A::Matrix{<:AbstractTensorMap}) + Ni, Nj = size(ρ) + ρ = deepcopy(ρ) + @inbounds for j in 1:Nj, i in 1:Ni + jr = mod1(j + 1, Nj) + @tensor ρ[i,jr][-1; -2] = ρ[i,j][4; 1] * A[i,j][1 2 3; -2] * conj(A[i,j][4 2 3; -1]) + end + return ρ +end + +""" + C = LRtoC(L,R) + +``` + ── Cᵢⱼ ── = ── Lᵢⱼ ── Rᵢⱼ₊₁ ── +``` +""" +function LRtoC(L::Matrix{<:AbstractTensorMap}, R::Matrix{<:AbstractTensorMap}) + Rijr = circshift(R, (0, -1)) + return [L * R for (L, R) in zip(L, Rijr)] +end + +""" + FLm = FLmap(FLi::Vector{<:AbstractTensorMap}, + ALui::Vector{<:AbstractTensorMap}, + ALdir::Vector{<:AbstractTensorMap}, + Ati::Vector{<:AbstractTensorMap}, + Abi::Vector{<:AbstractTensorMap}) + +``` + ┌── ┌── ALuᵢⱼ ── + │ │ │ +FLᵢⱼ₊₁ = FLᵢⱼ ─ Oᵢⱼ ── + │ │ │ + └── └── ALdᵢᵣⱼ ─ +``` +""" +function FLmap(FLi::Vector{<:AbstractTensorMap}, + ALui::Vector{<:AbstractTensorMap}, + ALdir::Vector{<:AbstractTensorMap}, + Ati::Vector{<:AbstractTensorMap}, + Abi::Vector{<:AbstractTensorMap}) + FLm = [@tensoropt FL[-1 -2 -3; -4] := FL[6 5 4; 1] * ALu[1 2 3; -4] * At[9; 2 -2 8 5] * Ab[3 -3 7 4; 9] * ALd[6 8 7; -1] for (FL, ALu, ALd, At, Ab) in zip(FLi, ALui, ALdir, Ati, Abi)] + + return circshift(FLm, 1) +end + +""" + FRm = FRmap(FRi::Vector{<:AbstractTensorMap}, + ARui::Vector{<:AbstractTensorMap}, + ARdir::Vector{<:AbstractTensorMap}, + Ati::Vector{<:AbstractTensorMap}, + Abi::Vector{<:AbstractTensorMap}) + +``` + ── ARuᵢⱼ ──┐ ──┐ + │ │ │ + ── Oᵢⱼ ──FRᵢⱼ = ──FRᵢⱼ₋₁ + │ │ │ + ── ARdᵢᵣⱼ ──┘ ──┘ +``` +""" +function FRmap(FRi::Vector{<:AbstractTensorMap}, + ARui::Vector{<:AbstractTensorMap}, + ARdir::Vector{<:AbstractTensorMap}, + Ati::Vector{<:AbstractTensorMap}, + Abi::Vector{<:AbstractTensorMap}) + FRm = [@tensoropt FR[-1 -2 -3; -4] := ARu[-1;1 2 3] * FR[3 4 5; 8] * At[9; 1 4 7 -2] * Ab[2 5 6 -3; 9] * ARd[-4; 7 6 8] for (FR, ARu, ARd, At, Ab) in zip(FRi, ARui, ARdir, Ati, Abi)] + + return circshift(FRm, -1) +end \ No newline at end of file diff --git a/src/environments/vumps_environments.jl b/src/environments/vumps_environments.jl index 655bdadd..02dc40d2 100644 --- a/src/environments/vumps_environments.jl +++ b/src/environments/vumps_environments.jl @@ -131,7 +131,7 @@ function selectpos(λs, Fs, N) end """ - getL!(A,L; kwargs...) + L = getL!(A::Matrix{<:AbstractTensorMap}, L::Matrix{<:AbstractTensorMap}; verbosity = Defaults.verbosity, kwargs...) ```` ┌─ Aᵢⱼ ─ Aᵢⱼ₊₁─ ┌─ L ─ @@ -144,7 +144,7 @@ end """ function getL!(A::Matrix{<:AbstractTensorMap}, L::Matrix{<:AbstractTensorMap}; verbosity = Defaults.verbosity, kwargs...) Ni, Nj = size(A) - λs, ρs, info = eigsolve(ρ -> Cmap(ρ, A), L, 1, :LM; ishermitian = false, maxiter = 1, kwargs...) + λs, ρs, info = eigsolve(ρ -> ρmap(ρ, A), L, 1, :LM; ishermitian = false, maxiter = 1, kwargs...) verbosity >= 1 && info.converged == 0 && @warn "getL not converged" _, ρs1 = selectpos(λs, ρs, Nj) @inbounds for j = 1:Nj, i = 1:Ni @@ -160,10 +160,10 @@ function getL!(A::Matrix{<:AbstractTensorMap}, L::Matrix{<:AbstractTensorMap}; v end """ - getAL(A,L) + AL, Le, λ = getAL(A::Matrix{<:AbstractTensorMap}, L::Matrix{<:AbstractTensorMap}) Given an MPS tensor `A` and `L` ,return a left-canonical MPS tensor `AL`, a gauge transform `R` and -a scalar factor `λ` such that ``λ AR R = L A`` +a scalar factor `λ` such that ``λ * AL * Le = L * A`` """ function getAL(A::Matrix{<:AbstractTensorMap}, L::Matrix{<:AbstractTensorMap}) Ni, Nj = size(A) @@ -171,14 +171,90 @@ function getAL(A::Matrix{<:AbstractTensorMap}, L::Matrix{<:AbstractTensorMap}) Le = similar(L) λ = zeros(Ni, Nj) @inbounds for j = 1:Nj, i = 1:Ni - Q, R = leftorth!(reshape(L[:,:,i,j]*reshape(A[:,:,:,i,j], χ, D*χ), D*χ, χ)) # To do: correct the reshape to transpose - AL[:,:,:,i,j] = reshape(Q, χ, D, χ) + Q, R = leftorth!(transpose(L[i,j]*transpose(A[i,j], ((1,),(4,3,2))), ((1,4,3),(2,)))) + AL[i,j] = Q λ[i,j] = norm(R) - Le[:,:,i,j] = rmul!(R, 1/λ[i,j]) + Le[i,j] = rmul!(R, 1/λ[i,j]) end return AL, Le, λ end +function getLsped(Le::Matrix{<:AbstractTensorMap}, A::Matrix{<:AbstractTensorMap}, AL::Matrix{<:AbstractTensorMap}; verbosity = Defaults.verbosity, kwargs...) + Ni, Nj = size(A) + L = similar(Le) + @inbounds for j = 1:Nj, i = 1:Ni + λs, Ls, info = eigsolve(L -> (@tensor Ln[-1; -2] := L[4; 1] * A[i,j][1 2 3; -2] * conj(AL[i,j][4 2 3; -1])), Le[i,j], 1, :LM; ishermitian = false, kwargs...) + verbosity >= 1 && info.converged == 0 && @warn "getLsped not converged" + _, Ls1 = selectpos(λs, Ls, Nj) + _, R = leftorth!(Ls1) + L[i,j] = R + end + return L +end + +""" + AL, L, λ = left_canonical(A::Matrix{<:AbstractTensorMap}, L::Matrix{<:AbstractTensorMap} = initial_C(A); kwargs...) + +Given an MPS tensor `A`, return a left-canonical MPS tensor `AL`, a gauge transform `L` and +a scalar factor `λ` such that ``λ*AL*L = L*A``, where an initial guess for `L` can be +provided. +""" +function left_canonical(A::Matrix{<:AbstractTensorMap}, L::Matrix{<:AbstractTensorMap} = initial_C(A); tol = 1e-12, maxiter = 100, kwargs...) + L = getL!(A, L; kwargs...) + AL, Le, λ = getAL(A, L;kwargs...) + numiter = 1 + while norm(L.-Le) > tol && numiter < maxiter + L = getLsped(Le, A, AL; kwargs...) + AL, Le, λ = getAL(A, L; kwargs...) + numiter += 1 + end + L = Le + return AL, L, λ +end + +""" + R, AR, λ = right_canonical(A::Matrix{<:AbstractTensorMap}, L::Matrix{<:AbstractTensorMap} = initial_C(A); tol = 1e-12, maxiter = 100, kwargs...) + +Given an MPS tensor `A`, return a gauge transform R, a right-canonical MPS tensor `AR`, and +a scalar factor `λ` such that ``λ * R * AR = A * R``, where an initial guess for `R` can be +provided. +""" +function right_canonical(A::Matrix{<:AbstractTensorMap}, L::Matrix{<:AbstractTensorMap} = initial_C(A); tol = 1e-12, maxiter = 100, kwargs...) + Ar = [permute(A, ((4,2,3), (1,))) for A in A] + Lr = [permute(L, ((2, ), (1,))) for L in L] + + AL, L, λ = left_canonical(Ar, Lr; tol, maxiter, kwargs...) + + R = [permute( L, ((2,), (1, ))) for L in L] + AR = [permute(AL, ((4,), (2,3,1))) for AL in AL] + return R, AR, λ +end + +function initial_FL(AL::Matrix{<:AbstractTensorMap}, O::InfiniteTransferPEPS) + T = eltype(O) + Ni, Nj = size(O) + FL = Matrix{TensorMap}(undef, Ni, Nj) + for j in 1:Nj, i in 1:Ni + D = space(O.top[i, j], 5) + χ = space(AL[i, j], 1) + FL[i, j] = TensorMap(rand, T, χ' * D * D', χ) + end + + return FL +end + +function initial_FR(AR::Matrix{<:AbstractTensorMap}, O::InfiniteTransferPEPS) + T = eltype(O) + Ni, Nj = size(O) + FR = Matrix{TensorMap}(undef, Ni, Nj) + for j in 1:Nj, i in 1:Ni + D = space(O.top[i, j], 3) + χ = space(AR[i, j], 1) + FR[i, j] = TensorMap(rand, T, χ * D * D', χ') + end + + return FR +end function VUMPSRuntime(ψ₀, χ::Int) diff --git a/src/operators/transferpeps.jl b/src/operators/transferpeps.jl index 7c517de8..78cb33a1 100644 --- a/src/operators/transferpeps.jl +++ b/src/operators/transferpeps.jl @@ -30,23 +30,6 @@ Base.size(transfer::InfiniteTransferPEPS) = size(transfer.top) # Base.iterate(O::InfiniteTransferPEPS, i=1) = i > length(O) ? nothing : (O[i], i + 1) -""" -```` - ┌─ Aᵢⱼ─ ┌─ - ρᵢⱼ │ = ρⱼ₊₁ - └─ Aᵢⱼ─ └─ -```` -""" -function Cmap(ρ::Matrix{<:AbstractTensorMap}, A::Matrix{<:AbstractTensorMap}) - Ni, Nj = size(ρ) - ρ = deepcopy(ρ) - @inbounds for j in 1:Nj, i in 1:Ni - jr = mod1(j + 1, Nj) - @tensor ρ[i,jr][-1; -2] = ρ[i,j][4; 1] * A[i,j][1 2 3; -2] * conj(A[i,j][4 2 3; -1]) - end - return ρ -end - # function MPSKit.transfer_left( # GL::GenericMPSTensor{S,3}, # O::NTuple{2,PEPSTensor}, diff --git a/test/vumps/vumps_environment.jl b/test/vumps/vumps_environment.jl index fcc2e237..00b77dec 100644 --- a/test/vumps/vumps_environment.jl +++ b/test/vumps/vumps_environment.jl @@ -1,8 +1,8 @@ using Test using Random using PEPSKit -using PEPSKit: initial_A, initial_C -using PEPSKit: Cmap, getL! +using PEPSKit: initial_A, initial_C, initial_FL, initial_FR +using PEPSKit: ρmap, getL!, getAL, getLsped, left_canonical, right_canonical using TensorKit using LinearAlgebra @@ -12,11 +12,12 @@ begin "test utility" χs = [ℂ^4] end @testset begin - A = TensorMap(rand, ComplexF64, ℂ^2 ⊗ ℂ^3, ℂ^10) + A = TensorMap(rand, ComplexF64, ℂ^2 * ℂ^3, ℂ^4 * ℂ^5) @show storagetype(typeof(A)) # @tensor C = conj(A[1 2;3]) * A[1 2;3] - @tensor C = A'[3; 1 2] * A[1 2;3] - @show sqrt(C) norm(A) + @show space(A, 1) space(A, 2) space(A, 3) space(A, 4) + # @tensor C = A'[3; 1 2] * A[1 2;3] + # @show sqrt(C) norm(A) end @testset "InfiniteTransferPEPS for unitcell $Ni x $Nj" for Ni in 1:2, Nj in 1:2, (d, D, χ) in zip(ds, Ds, χs) @@ -43,19 +44,62 @@ end @test all(i -> space(i) == (χ ← χ), C) end +@testset "getL!, getAL and getLsped for unitcell $Ni x $Nj" for Ni in 1:2, Nj in 1:2, (d, D, χ) in zip(ds, Ds, χs) + ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) + itp = InfiniteTransferPEPS(ipeps) + A = initial_A(itp, χ) + C = initial_C(A) + C = ρmap(C, A) + + L = getL!(A, C) + + @test all(i -> all(j -> real(j) > 0, diag(i).values[]), L) + @test all(i -> all(j -> imag(j) ≈ 0, diag(i).values[]), L) + @test all(i -> space(i) == (χ ← χ), L) + + AL, Le, λ = getAL(A, L) + @test all(i -> space(i) == (χ * D * D' ← χ), AL) + @test all(i -> space(i) == (χ ← χ), Le) + @test all(map((λ, AL, Le, A, L) -> λ * AL * Le ≈ transpose(L*transpose(A, ((1,),(4,3,2))), ((1,4,3),(2,))), λ, AL, Le, A, L)) + + L = getLsped(Le, A, AL) + @test all(i -> space(i) == (χ ← χ), L) + @test all(i -> all(j -> real(j) > 0, diag(i).values[]), L) + @test all(i -> all(j -> imag(j) ≈ 0, diag(i).values[]), L) +end -@testset "Cmap for unitcell $Ni x $Nj" for Ni in 1:2, Nj in 1:2, (d, D, χ) in zip(ds, Ds, χs) +@testset "canonical form for unitcell $Ni x $Nj" for Ni in 1:2, Nj in 1:2, (d, D, χ) in zip(ds, Ds, χs) + ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) + itp = InfiniteTransferPEPS(ipeps) + A = initial_A(itp, χ) + + AL, L, λ = left_canonical(A) + @test all(i -> space(i) == (χ * D * D' ← χ), AL) + @test all(i -> space(i) == (χ ← χ), L) + @test all(AL -> (AL' * AL ≈ isomorphism(χ, χ)), AL) + @test all(map((A, AL, L, λ) -> λ * AL * L ≈ transpose(L*transpose(A, ((1,),(4,3,2))), ((1,4,3),(2,))), A, AL, L, λ)) + + R, AR, λ = right_canonical(A) + @test all(i -> space(i) == (χ ← D' * D * χ), AR) + @test all(i -> space(i) == (χ ← χ), R) + @test all(AR -> (AR * AR' ≈ isomorphism(χ, χ)), AR) + @test all(map((A, R, AR, λ) -> transpose(λ * R * AR, ((1,2,3),(4,))) ≈ A * R, A, R, AR, λ)) +end + +@testset "initialize A C for unitcell $Ni x $Nj" for Ni in 1:2, Nj in 1:2, (d, D, χ) in zip(ds, Ds, χs) + Random.seed!(42) ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) itp = InfiniteTransferPEPS(ipeps) A = initial_A(itp, χ) - C = initial_C(A) - C = Cmap(C, A) + AL, L, λ = left_canonical(A) + R, AR, λ = right_canonical(A) + + FL = initial_FL(AL, itp) + @test all(i -> space(i) == (χ' * D * D' ← χ), FL) - # @show inner(C, C) - getL!(A, C) - # λs, Cs, info = getL!(A, C) - # @test λs[1] * Cs[1] ≈ Cmap(Cs[1], A) rtol = 1e-12 + FR = initial_FR(AR, itp) + @test all(i -> space(i) == (χ * D' * D ← χ'), FR) end @@ -66,52 +110,47 @@ end +# @testset "(2, 2) PEPS" begin +# psi = InfinitePEPS(ComplexSpace(2), ComplexSpace(2); unitcell=(2, 2)) +# T = PEPSKit.TransferPEPSMultiline(psi, 1) +# mps = PEPSKit.initializeMPS(T, fill(ComplexSpace(20), 2, 2)) +# mps, envs, ϵ = leading_boundary(mps, T, vumps_alg) +# N = abs(prod(expectation_value(mps, T))) +# ctm = leading_boundary(CTMRGEnv(psi, ComplexSpace(20)), psi, CTMRG(; verbosity=1)) +# N´ = abs(norm(psi, ctm)) +# @test N ≈ N´ rtol = 1e-2 +# end +# @testset "PEPO runthrough" begin +# function ising_pepo(beta; unitcell=(1, 1, 1)) +# t = ComplexF64[exp(beta) exp(-beta); exp(-beta) exp(beta)] +# q = sqrt(t) -@testset "(2, 2) PEPS" begin - psi = InfinitePEPS(ComplexSpace(2), ComplexSpace(2); unitcell=(2, 2)) - T = PEPSKit.TransferPEPSMultiline(psi, 1) +# O = zeros(2, 2, 2, 2, 2, 2) +# O[1, 1, 1, 1, 1, 1] = 1 +# O[2, 2, 2, 2, 2, 2] = 1 +# @tensor o[-1 -2; -3 -4 -5 -6] := +# O[1 2; 3 4 5 6] * +# q[-1; 1] * +# q[-2; 2] * +# q[-3; 3] * +# q[-4; 4] * +# q[-5; 5] * +# q[-6; 6] - mps = PEPSKit.initializeMPS(T, fill(ComplexSpace(20), 2, 2)) - mps, envs, ϵ = leading_boundary(mps, T, vumps_alg) - N = abs(prod(expectation_value(mps, T))) +# O = TensorMap(o, ℂ^2 ⊗ (ℂ^2)' ← ℂ^2 ⊗ ℂ^2 ⊗ (ℂ^2)' ⊗ (ℂ^2)') - ctm = leading_boundary(CTMRGEnv(psi, ComplexSpace(20)), psi, CTMRG(; verbosity=1)) - N´ = abs(norm(psi, ctm)) +# return InfinitePEPO(O; unitcell) +# end - @test N ≈ N´ rtol = 1e-2 -end +# psi = InfinitePEPS(ComplexSpace(2), ComplexSpace(2)) +# O = ising_pepo(1) +# T = InfiniteTransferPEPO(psi, O, 1, 1) -@testset "PEPO runthrough" begin - function ising_pepo(beta; unitcell=(1, 1, 1)) - t = ComplexF64[exp(beta) exp(-beta); exp(-beta) exp(beta)] - q = sqrt(t) - - O = zeros(2, 2, 2, 2, 2, 2) - O[1, 1, 1, 1, 1, 1] = 1 - O[2, 2, 2, 2, 2, 2] = 1 - @tensor o[-1 -2; -3 -4 -5 -6] := - O[1 2; 3 4 5 6] * - q[-1; 1] * - q[-2; 2] * - q[-3; 3] * - q[-4; 4] * - q[-5; 5] * - q[-6; 6] - - O = TensorMap(o, ℂ^2 ⊗ (ℂ^2)' ← ℂ^2 ⊗ ℂ^2 ⊗ (ℂ^2)' ⊗ (ℂ^2)') - - return InfinitePEPO(O; unitcell) - end - - psi = InfinitePEPS(ComplexSpace(2), ComplexSpace(2)) - O = ising_pepo(1) - T = InfiniteTransferPEPO(psi, O, 1, 1) - - mps = PEPSKit.initializeMPS(T, [ComplexSpace(10)]) - mps, envs, ϵ = leading_boundary(mps, T, vumps_alg) - f = abs(prod(expectation_value(mps, T))) -end +# mps = PEPSKit.initializeMPS(T, [ComplexSpace(10)]) +# mps, envs, ϵ = leading_boundary(mps, T, vumps_alg) +# f = abs(prod(expectation_value(mps, T))) +# end From 8dafeb26f99da91f2f930869004955e28a8b26f9 Mon Sep 17 00:00:00 2001 From: XingyuZhang2018 <864129714@qq.com> Date: Tue, 22 Oct 2024 22:21:48 +0200 Subject: [PATCH 10/25] finish leftenv --- .../contractions/vumps_contractions.jl | 6 +- src/environments/vumps_environments.jl | 46 +++++++++---- test/vumps/vumps_environment.jl | 66 ++++++++----------- 3 files changed, 64 insertions(+), 54 deletions(-) diff --git a/src/algorithms/contractions/vumps_contractions.jl b/src/algorithms/contractions/vumps_contractions.jl index 9619bfd5..6d2f320b 100644 --- a/src/algorithms/contractions/vumps_contractions.jl +++ b/src/algorithms/contractions/vumps_contractions.jl @@ -49,7 +49,8 @@ function FLmap(FLi::Vector{<:AbstractTensorMap}, ALdir::Vector{<:AbstractTensorMap}, Ati::Vector{<:AbstractTensorMap}, Abi::Vector{<:AbstractTensorMap}) - FLm = [@tensoropt FL[-1 -2 -3; -4] := FL[6 5 4; 1] * ALu[1 2 3; -4] * At[9; 2 -2 8 5] * Ab[3 -3 7 4; 9] * ALd[6 8 7; -1] for (FL, ALu, ALd, At, Ab) in zip(FLi, ALui, ALdir, Ati, Abi)] + FLm = [@tensoropt FL[-1 -2 -3; -4] := FL[6 5 4; 1] * ALu[1 2 3; -4] * At[9; 2 -2 8 5] * + Ab[3 -3 7 4; 9] * ALd[-1; 6 8 7] for (FL, ALu, ALd, At, Ab) in zip(FLi, ALui, ALdir, Ati, Abi)] return circshift(FLm, 1) end @@ -74,7 +75,8 @@ function FRmap(FRi::Vector{<:AbstractTensorMap}, ARdir::Vector{<:AbstractTensorMap}, Ati::Vector{<:AbstractTensorMap}, Abi::Vector{<:AbstractTensorMap}) - FRm = [@tensoropt FR[-1 -2 -3; -4] := ARu[-1;1 2 3] * FR[3 4 5; 8] * At[9; 1 4 7 -2] * Ab[2 5 6 -3; 9] * ARd[-4; 7 6 8] for (FR, ARu, ARd, At, Ab) in zip(FRi, ARui, ARdir, Ati, Abi)] + FRm = [@tensoropt FR[-1 -2 -3; -4] := ARu[-1;1 2 3] * FR[3 4 5; 8] * At[9; 1 4 7 -2] * + Ab[2 5 6 -3; 9] * ARd[-4; 7 6 8] for (FR, ARu, ARd, At, Ab) in zip(FRi, ARui, ARdir, Ati, Abi)] return circshift(FRm, -1) end \ No newline at end of file diff --git a/src/environments/vumps_environments.jl b/src/environments/vumps_environments.jl index 02dc40d2..06d5b6f9 100644 --- a/src/environments/vumps_environments.jl +++ b/src/environments/vumps_environments.jl @@ -91,7 +91,7 @@ function initial_A(O::InfiniteTransferPEPS, χ::VectorSpace) Ni, Nj = size(O) A = Matrix{TensorMap}(undef, Ni, Nj) for j in 1:Nj, i in 1:Ni - D = space(O.top[i, j], 4) + D = space(O.top[i, j], 2)' A[i, j] = TensorMap(rand, T, χ * D * D', χ) end return A @@ -109,9 +109,9 @@ function initial_C(A::Matrix{<:AbstractTensorMap}) end # KrylovKit patch -TensorKit.inner(x::Matrix{TensorMap}, y::Matrix{TensorMap}) = sum(map(TensorKit.inner, x, y)) -TensorKit.add!!(x::Matrix{<:AbstractTensorMap}, y::Matrix{<:AbstractTensorMap}, a::Number, b::Number) = map((x, y) -> TensorKit.add!!(x, y, a, b), x, y) -TensorKit.scale!!(x::Matrix{<:AbstractTensorMap}, a::Number) = map(x -> TensorKit.scale!!(x, a), x) +TensorKit.inner(x::AbstractArray{<:AbstractTensorMap}, y::AbstractArray{<:AbstractTensorMap}) = sum(map(TensorKit.inner, x, y)) +TensorKit.add!!(x::AbstractArray{<:AbstractTensorMap}, y::AbstractArray{<:AbstractTensorMap}, a::Number, b::Number) = map((x, y) -> TensorKit.add!!(x, y, a, b), x, y) +TensorKit.scale!!(x::AbstractArray{<:AbstractTensorMap}, a::Number) = map(x -> TensorKit.scale!!(x, a), x) """ λs[1], Fs[1] = selectpos(λs, Fs) @@ -235,9 +235,9 @@ function initial_FL(AL::Matrix{<:AbstractTensorMap}, O::InfiniteTransferPEPS) Ni, Nj = size(O) FL = Matrix{TensorMap}(undef, Ni, Nj) for j in 1:Nj, i in 1:Ni - D = space(O.top[i, j], 5) - χ = space(AL[i, j], 1) - FL[i, j] = TensorMap(rand, T, χ' * D * D', χ) + D = space(O.top[i, j], 5)' + χ = space(AL[i, j], 4)' + FL[i, j] = TensorMap(rand, T, χ * D * D', χ) end return FL @@ -248,14 +248,36 @@ function initial_FR(AR::Matrix{<:AbstractTensorMap}, O::InfiniteTransferPEPS) Ni, Nj = size(O) FR = Matrix{TensorMap}(undef, Ni, Nj) for j in 1:Nj, i in 1:Ni - D = space(O.top[i, j], 3) - χ = space(AR[i, j], 1) - FR[i, j] = TensorMap(rand, T, χ * D * D', χ') + D = space(O.top[i, j], 3)' + χ = space(AR[i, j], 4)' + FR[i, j] = TensorMap(rand, T, χ * D * D', χ) end return FR end -function VUMPSRuntime(ψ₀, χ::Int) - +""" + λL, FL = leftenv(ALu, ALd, O, FL = initial_FL(ALu,O); kwargs...) + +Compute the left environment tensor for MPS A and MPO O, by finding the left fixed point +of ALu - O - ALd contracted along the physical dimension. +``` + ┌── ALuᵢⱼ ── ┌── + │ │ │ +FLᵢⱼ ─ Oᵢⱼ ── = λLᵢⱼ FLᵢⱼ₊₁ + │ │ │ + └── ALdᵢᵣⱼ ─ └── +``` +""" +leftenv(ALu::Matrix{<:AbstractTensorMap}, ALd::Matrix{<:AbstractTensorMap}, O::InfiniteTransferPEPS, FL::Matrix{<:AbstractTensorMap} = initial_FL(ALu,O); kwargs...) = leftenv!(ALu, ALd, O, deepcopy(FL); kwargs...) +function leftenv!(ALu::Matrix{<:AbstractTensorMap}, ALd::Matrix{<:AbstractTensorMap}, O::InfiniteTransferPEPS, FL::Matrix{<:AbstractTensorMap}; ifobs=false, kwargs...) + Ni, Nj = size(O) + λL = zeros(eltype(O), Ni) + for i in 1:Ni + ir = ifobs ? Ni + 1 - i : mod1(i + 1, Ni) + λLs, FL1s, info = eigsolve(FLi -> FLmap(FLi, ALu[i,:], ALd[ir,:], O.top[i,:], O.bot[i,:]), FL[i,:], 1, :LM; maxiter=100, ishermitian = false, kwargs...) + info.converged == 0 && @warn "leftenv not converged" + λL[i], FL[i,:] = selectpos(λLs, FL1s, Nj) + end + return λL, FL end \ No newline at end of file diff --git a/test/vumps/vumps_environment.jl b/test/vumps/vumps_environment.jl index 00b77dec..8b22fe95 100644 --- a/test/vumps/vumps_environment.jl +++ b/test/vumps/vumps_environment.jl @@ -3,6 +3,7 @@ using Random using PEPSKit using PEPSKit: initial_A, initial_C, initial_FL, initial_FR using PEPSKit: ρmap, getL!, getAL, getLsped, left_canonical, right_canonical +using PEPSKit: leftenv, FLmap using TensorKit using LinearAlgebra @@ -12,11 +13,12 @@ begin "test utility" χs = [ℂ^4] end @testset begin - A = TensorMap(rand, ComplexF64, ℂ^2 * ℂ^3, ℂ^4 * ℂ^5) - @show storagetype(typeof(A)) - # @tensor C = conj(A[1 2;3]) * A[1 2;3] - @show space(A, 1) space(A, 2) space(A, 3) space(A, 4) - # @tensor C = A'[3; 1 2] * A[1 2;3] + A = TensorMap(rand, ComplexF64, ℂ^2 * ℂ^3, ℂ^4) + # @show storagetype(typeof(A)) + # # @tensor C = conj(A[1 2;3]) * A[1 2;3] + @show space(A, 1) space(A, 2) space(A, 3) + @show space(A', 1) space(A', 2) space(A', 3) + @tensor C = A'[3; 1 2] * A[1 2;3] # @show sqrt(C) norm(A) end @@ -86,7 +88,7 @@ end @test all(map((A, R, AR, λ) -> transpose(λ * R * AR, ((1,2,3),(4,))) ≈ A * R, A, R, AR, λ)) end -@testset "initialize A C for unitcell $Ni x $Nj" for Ni in 1:2, Nj in 1:2, (d, D, χ) in zip(ds, Ds, χs) +@testset "initialize FL FR for unitcell $Ni x $Nj" for Ni in 1:2, Nj in 1:2, (d, D, χ) in zip(ds, Ds, χs) Random.seed!(42) ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) @@ -96,14 +98,29 @@ end R, AR, λ = right_canonical(A) FL = initial_FL(AL, itp) - @test all(i -> space(i) == (χ' * D * D' ← χ), FL) + @test all(i -> space(i) == (χ * D' * D ← χ), FL) FR = initial_FR(AR, itp) - @test all(i -> space(i) == (χ * D' * D ← χ'), FR) + @test all(i -> space(i) == (χ * D * D' ← χ), FR) end +@testset "leftenv and rightenv for unitcell $Ni x $Nj" for Ni in 1:3, Nj in 1:3, (d, D, χ) in zip(ds, Ds, χs), ifobs in [true, false] + Random.seed!(42) + ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) + + itp = InfiniteTransferPEPS(ipeps) + A = initial_A(itp, χ) + AL, L, λ = left_canonical(A) + R, AR, λ = right_canonical(A) + λL, FL = leftenv(AL, adjoint.(AL), itp; ifobs) + @test all(i -> space(i) == (χ * D' * D ← χ), FL) + for i in 1:Ni + ir = ifobs ? Ni + 1 - i : mod1(i + 1, Ni) + @test λL[i] * FL[i,:] ≈ FLmap(FL[i,:], AL[i,:], adjoint.(AL)[ir,:], itp.top[i,:], itp.bot[i,:]) rtol = 1e-12 + end +end @@ -122,35 +139,4 @@ end # N´ = abs(norm(psi, ctm)) # @test N ≈ N´ rtol = 1e-2 -# end - -# @testset "PEPO runthrough" begin -# function ising_pepo(beta; unitcell=(1, 1, 1)) -# t = ComplexF64[exp(beta) exp(-beta); exp(-beta) exp(beta)] -# q = sqrt(t) - -# O = zeros(2, 2, 2, 2, 2, 2) -# O[1, 1, 1, 1, 1, 1] = 1 -# O[2, 2, 2, 2, 2, 2] = 1 -# @tensor o[-1 -2; -3 -4 -5 -6] := -# O[1 2; 3 4 5 6] * -# q[-1; 1] * -# q[-2; 2] * -# q[-3; 3] * -# q[-4; 4] * -# q[-5; 5] * -# q[-6; 6] - -# O = TensorMap(o, ℂ^2 ⊗ (ℂ^2)' ← ℂ^2 ⊗ ℂ^2 ⊗ (ℂ^2)' ⊗ (ℂ^2)') - -# return InfinitePEPO(O; unitcell) -# end - -# psi = InfinitePEPS(ComplexSpace(2), ComplexSpace(2)) -# O = ising_pepo(1) -# T = InfiniteTransferPEPO(psi, O, 1, 1) - -# mps = PEPSKit.initializeMPS(T, [ComplexSpace(10)]) -# mps, envs, ϵ = leading_boundary(mps, T, vumps_alg) -# f = abs(prod(expectation_value(mps, T))) -# end +# endn \ No newline at end of file From 7c274df086cffac3030118c1527cfc90d6241cd5 Mon Sep 17 00:00:00 2001 From: XingyuZhang2018 <864129714@qq.com> Date: Wed, 23 Oct 2024 17:51:54 +0200 Subject: [PATCH 11/25] finished vumps forward --- Project.toml | 1 + src/PEPSKit.jl | 9 +- .../contractions/vumps_contractions.jl | 65 +++- src/algorithms/vumps/vumps.jl | 123 ++++++- src/environments/vumps_environments.jl | 319 ++++++++++++------ src/operators/infinitepepo.jl | 139 -------- src/operators/transferpepo.jl | 232 ------------- src/operators/transferpeps.jl | 106 ------ test/vumps/vumps.jl | 43 +++ test/vumps/vumps_environment.jl | 76 ++++- 10 files changed, 498 insertions(+), 615 deletions(-) delete mode 100644 src/operators/infinitepepo.jl delete mode 100644 src/operators/transferpepo.jl delete mode 100644 src/operators/transferpeps.jl create mode 100644 test/vumps/vumps.jl diff --git a/Project.toml b/Project.toml index 590ff969..903111cd 100644 --- a/Project.toml +++ b/Project.toml @@ -14,6 +14,7 @@ LoggingExtras = "e6f89c97-d47a-5376-807f-9c37f3926c36" MPSKit = "bb1c41ca-d63c-52ed-829e-0820dda26502" MPSKitModels = "ca635005-6f8c-4cd1-b51d-8491250ef2ab" OptimKit = "77e91f04-9b3b-57a6-a776-40b61faaebe0" +Parameters = "d96e819e-fc66-5662-9728-84c9c7592b0a" Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" diff --git a/src/PEPSKit.jl b/src/PEPSKit.jl index 64f3176a..48604bc3 100644 --- a/src/PEPSKit.jl +++ b/src/PEPSKit.jl @@ -2,6 +2,7 @@ module PEPSKit using LinearAlgebra, Statistics, Base.Threads, Base.Iterators, Printf using Base: @kwdef +using Parameters using Compat using Accessors using VectorInterface @@ -23,17 +24,11 @@ include("utility/loginfo.jl") include("states/abstractpeps.jl") include("states/infinitepeps.jl") -include("operators/transferpeps.jl") -# include("operators/infinitepepo.jl") -# include("operators/transferpepo.jl") -# include("operators/derivatives.jl") include("operators/localoperator.jl") include("operators/lattices/squarelattice.jl") include("operators/models.jl") include("environments/ctmrg_environments.jl") -# include("environments/transferpeps_environments.jl") -# include("environments/transferpepo_environments.jl") include("environments/vumps_environments.jl") abstract type Algorithm end @@ -55,7 +50,7 @@ include("utility/symmetrization.jl") include("utility/defaults.jl") export SVDAdjoint, IterSVD, NonTruncSVDAdjoint -export FixedSpaceTruncation, ProjectorAlg, CTMRG, CTMRGEnv, correlation_length +export FixedSpaceTruncation, ProjectorAlg, CTMRG, CTMRGEnv, VUMPS, VUMPSRuntime, VUMPSEnv, correlation_length export LocalOperator export expectation_value, costfun, product_peps export leading_boundary diff --git a/src/algorithms/contractions/vumps_contractions.jl b/src/algorithms/contractions/vumps_contractions.jl index 6d2f320b..84b1673a 100644 --- a/src/algorithms/contractions/vumps_contractions.jl +++ b/src/algorithms/contractions/vumps_contractions.jl @@ -18,7 +18,7 @@ function ρmap(ρ::Matrix{<:AbstractTensorMap}, A::Matrix{<:AbstractTensorMap}) end """ - C = LRtoC(L,R) + C = LRtoC(L::Matrix{<:AbstractTensorMap}, R::Matrix{<:AbstractTensorMap}) ``` ── Cᵢⱼ ── = ── Lᵢⱼ ── Rᵢⱼ₊₁ ── @@ -26,7 +26,19 @@ end """ function LRtoC(L::Matrix{<:AbstractTensorMap}, R::Matrix{<:AbstractTensorMap}) Rijr = circshift(R, (0, -1)) - return [L * R for (L, R) in zip(L, Rijr)] + return L .* Rijr +end + +""" + AC = ALCtoAC(AL::Matrix{<:AbstractTensorMap}, C::Matrix{<:AbstractTensorMap}) + +``` + ── ACᵢⱼ ── = ── ALᵢⱼ ── Cᵢⱼ ── + | | +``` +""" +function ALCtoAC(AL::Matrix{<:AbstractTensorMap}, C::Matrix{<:AbstractTensorMap}) + return AL .* C end """ @@ -75,8 +87,53 @@ function FRmap(FRi::Vector{<:AbstractTensorMap}, ARdir::Vector{<:AbstractTensorMap}, Ati::Vector{<:AbstractTensorMap}, Abi::Vector{<:AbstractTensorMap}) - FRm = [@tensoropt FR[-1 -2 -3; -4] := ARu[-1;1 2 3] * FR[3 4 5; 8] * At[9; 1 4 7 -2] * - Ab[2 5 6 -3; 9] * ARd[-4; 7 6 8] for (FR, ARu, ARd, At, Ab) in zip(FRi, ARui, ARdir, Ati, Abi)] + FRm = [@tensoropt FR[-1 -2 -3; -4] := ARu[-1 1 2; 3] * FR[3 4 5; 8] * At[9; 1 4 7 -2] * + Ab[2 5 6 -3; 9] * ARd[8; -4 7 6] for (FR, ARu, ARd, At, Ab) in zip(FRi, ARui, ARdir, Ati, Abi)] return circshift(FRm, -1) +end + +""" + ACm = ACmap(ACj::Vector{<:AbstractTensorMap}, + FLj::Vector{<:AbstractTensorMap}, + FRj::Vector{<:AbstractTensorMap}, + Atj::Vector{<:AbstractTensorMap}, + Abj::Vector{<:AbstractTensorMap}) + +``` + ┌─────── ACᵢⱼ ─────┐ +┌───── ACᵢ₊₁ⱼ ─────┐ │ │ │ +│ │ │ = FLᵢⱼ ─── Mᵢⱼ ───── FRᵢⱼ + │ │ │ + +``` +""" +function ACmap(ACj::Vector{<:AbstractTensorMap}, + FLj::Vector{<:AbstractTensorMap}, + FRj::Vector{<:AbstractTensorMap}, + Atj::Vector{<:AbstractTensorMap}, + Abj::Vector{<:AbstractTensorMap}) + ACm = [@tensoropt AC[-1 -2 -3; -4] := AC[1 2 3; 4] * FL[-1 6 5; 1]* At[9; 2 7 -2 6] * + Ab[3 8 -3 5; 9] * FR[4 7 8; -4] for (AC, FL, FR, At, Ab) in zip(ACj, FLj, FRj, Atj, Abj)] + + return circshift(ACm, 1) +end + +""" + Cmap(Cij, FLjp, FRj, II) + +``` + ┌────Cᵢⱼ ───┐ +┌── Cᵢ₊₁ⱼ ──┐ │ │ +│ │ = FLᵢⱼ₊₁ ──── FRᵢⱼ + │ │ + +``` +""" +function Cmap(Cj::Vector{<:AbstractTensorMap}, + FLjr::Vector{<:AbstractTensorMap}, + FRj::Vector{<:AbstractTensorMap}) + Cm = [@tensoropt C[-1; -2] := C[1; 2] * FL[-1 3 4; 1] * FR[2 3 4; -2] for (C, FL, FR) in zip(Cj, FLjr, FRj)] + + return circshift(Cm, 1) end \ No newline at end of file diff --git a/src/algorithms/vumps/vumps.jl b/src/algorithms/vumps/vumps.jl index e1716163..442c5b98 100644 --- a/src/algorithms/vumps/vumps.jl +++ b/src/algorithms/vumps/vumps.jl @@ -5,19 +5,120 @@ verbosity::Int = Defaults.verbosity end -function leading_boundary(O::Matrix, alg::VUMPS) - # initialize - rt = VUMPSRuntime(O, nothing, nothing, nothing, nothing, nothing) +""" + VUMPSEnv{T<:Number, S<:IndexSpace, + OT<:AbstractTensorMap{S, 2, 2}, + ET<:AbstractTensorMap{S, 2, 1}, + CT<:AbstractTensorMap{S, 1, 1}} + +A struct that contains the environment of the VUMPS algorithm for calculate observables. + +For a `Ni` x `Nj` unitcell, each is a Matrix, containing + +- `AC`: The mixed canonical environment tensor. +- `AR`: The right canonical environment tensor. +- `Lu`: The left upper environment tensor. +- `Ru`: The right upper environment tensor. +- `Lo`: The left mixed environment tensor. +- `Ro`: The right mixed environment tensor. +""" +struct VUMPSEnv{T<:Number, S<:IndexSpace, + ET<:AbstractTensorMap{S, 3, 1}} + AC::Matrix{ET} + AR::Matrix{ET} + FLu::Matrix{ET} + FRu::Matrix{ET} + FLo::Matrix{ET} + FRo::Matrix{ET} + function VUMPSEnv(AC::Matrix{ET}, + AR::Matrix{ET}, + FLu::Matrix{ET}, + FRu::Matrix{ET}, + FLo::Matrix{ET}, + FRo::Matrix{ET}) where {ET} + T = eltype(AC[1]) + S = spacetype(AC[1]) + new{T, S, ET}(AC, AR, FLu, FRu, FLo, FRo) + end +end + +""" + VUMPSRuntime{T<:Number, S<:IndexSpace, + OT<:AbstractTensorMap{S, 2, 2}, + ET<:AbstractTensorMap{S, 2, 1}, + CT<:AbstractTensorMap{S, 1, 1}} + +A struct that contains the environment of the VUMPS algorithm for runtime calculations. + +For a `Ni` x `Nj` unitcell, each is a Matrix, containing + +- `O`: The center transfer matrix PEPO tensor. +- `AL`: The left canonical environment tensor. +- `AR`: The right canonical environment tensor. +- `C`: The canonical environment tensor. +- `L`: The left environment tensor. +- `R`: The right environment tensor. +""" +struct VUMPSRuntime{T<:Number, S<:IndexSpace, + ET<:AbstractTensorMap{S, 3, 1}, + CT<:AbstractTensorMap{S, 1, 1}} + AL::Matrix{ET} + AR::Matrix{ET} + C::Matrix{CT} + FL::Matrix{ET} + FR::Matrix{ET} + function VUMPSRuntime(AL::Matrix{ET}, + AR::Matrix{ET}, + C::Matrix{CT}, + FL::Matrix{ET}, + FR::Matrix{ET}) where {ET, CT} + T = eltype(AL[1]) + S = spacetype(AL[1]) + new{T, S, ET, CT}(AL, AR, C, FL, FR) + end +end + +function VUMPSRuntime(O::InfiniteTransferPEPS, χ::VectorSpace, alg::VUMPS) + A = initial_A(O, χ) + AL, L, _ = left_canonical(A) + R, AR, _ = right_canonical(AL) + + _, FL = leftenv(AL, adjoint.(AL), O) + _, FR = rightenv(AR, adjoint.(AR), O) + C = LRtoC(L, R) + Ni, Nj = size(O) + alg.verbosity >= 2 && println("===== vumps random initial $(Ni)×$(Nj) vumps χ = $(χ) environment =====") + return VUMPSRuntime(AL, AR, C, FL, FR) +end + +function leading_boundary(O::InfiniteTransferPEPS, rt::VUMPSRuntime, alg::VUMPS) + for i in 1:alg.maxiter + rt, err = vumps_itr(O, rt, alg) + alg.verbosity >= 3 && println(@sprintf("vumps@step: i = %4d\terr = %.3e\t", i, err)) + if err < alg.tol + alg.verbosity >= 2 && println(@sprintf("===== vumps@step: i = %4d\terr = %.3e\t coveraged =====", i, err)) + break + end + if i == alg.maxiter + alg.verbosity >= 2 && println(@sprintf("===== vumps@step: i = %4d\terr = %.3e\t not coveraged =====", i, err)) + end + end return rt end -function vumps(rt::VUMPSRuntime; tol::Real=1e-10, maxiter::Int=10, miniter::Int=1, verbose=false, show_every = Inf) - # initialize - olderror = Inf - vumps_counting = show_every_count(show_every) +function vumps_itr(O::InfiniteTransferPEPS, rt::VUMPSRuntime, alg::VUMPS) + @unpack AL, C, AR, FL, FR = rt + AC = Zygote.@ignore ALCtoAC(AL,C) + _, ACp = ACenv(AC, FL, FR, O) + _, Cp = Cenv( C, FL, FR) + ALp, ARp, _, _ = ACCtoALAR(ACp, Cp) + _, FL = leftenv(AL, adjoint.(ALp), O, FL) + _, FR = rightenv(AR, adjoint.(ARp), O, FR) + _, ACp = ACenv(ACp, FL, FR, O) + _, Cp = Cenv( Cp, FL, FR) + ALp, ARp, errL, errR = ACCtoALAR(ACp, Cp) + err = errL + errR + alg.verbosity >= 4 && err > 1e-8 && println("errL=$errL, errR=$errR") - stopfun = StopFunction(olderror, -1, tol, maxiter, miniter) - rt, err = fixedpoint(res -> vumpstep(res...;show_counting=vumps_counting), (rt, olderror), stopfun) - verbose && println("vumps done@step: $(stopfun.counter), error=$(err)") - return rt, err + return VUMPSRuntime(ALp, ARp, Cp, FL, FR), err end \ No newline at end of file diff --git a/src/environments/vumps_environments.jl b/src/environments/vumps_environments.jl index 06d5b6f9..2ca3af20 100644 --- a/src/environments/vumps_environments.jl +++ b/src/environments/vumps_environments.jl @@ -1,79 +1,30 @@ """ - VUMPSEnv{T<:Number, S<:IndexSpace, - OT<:AbstractTensorMap{S, 2, 2}, - ET<:AbstractTensorMap{S, 2, 1}, - CT<:AbstractTensorMap{S, 1, 1}} + InfiniteTransferPEPS{T} -A struct that contains the environment of the VUMPS algorithm for calculate observables. - -For a `Ni` x `Nj` unitcell, each is a Matrix, containing - -- `AC`: The mixed canonical environment tensor. -- `AR`: The right canonical environment tensor. -- `Lu`: The left upper environment tensor. -- `Ru`: The right upper environment tensor. -- `Lo`: The left mixed environment tensor. -- `Ro`: The right mixed environment tensor. +Represents an infinite transfer operator corresponding to a single row of a partition +function which corresponds to the overlap between 'ket' and 'bra' `InfinitePEPS` states. """ -struct VUMPSEnv{T<:Number, S<:IndexSpace, - ET<:AbstractTensorMap{S, 3, 1}} - AC::Matrix{ET} - AR::Matrix{ET} - Lu::Matrix{ET} - Ru::Matrix{ET} - Lo::Matrix{ET} - Ro::Matrix{ET} - function VUMPSEnv(AC::Matrix{ET}, - AR::Matrix{ET}, - Lu::Matrix{ET}, - Ru::Matrix{ET}, - Lo::Matrix{ET}, - Ro::Matrix{ET}) where {ET} - T = eltype(AC[1]) - S = spacetype(AC[1]) - new{T, S, ET}(AC, AR, Lu, Ru, Lo, Ro) - end +struct InfiniteTransferPEPS{TT, BT} + top::Matrix{TT} + bot::Matrix{BT} end -""" - VUMPSRuntime{T<:Number, S<:IndexSpace, - OT<:AbstractTensorMap{S, 2, 2}, - ET<:AbstractTensorMap{S, 2, 1}, - CT<:AbstractTensorMap{S, 1, 1}} +function InfiniteTransferPEPS(ipeps::InfinitePEPS) + top = ipeps.A + bot = [A' for A in ipeps.A] + return InfiniteTransferPEPS(top, bot) +end -A struct that contains the environment of the VUMPS algorithm for runtime calculations. - -For a `Ni` x `Nj` unitcell, each is a Matrix, containing - -- `O`: The center transfer matrix PEPO tensor. -- `AL`: The left canonical environment tensor. -- `AR`: The right canonical environment tensor. -- `C`: The canonical environment tensor. -- `L`: The left environment tensor. -- `R`: The right environment tensor. -""" -struct VUMPSRuntime{T<:Number, S<:IndexSpace, - OT<:InfiniteTransferPEPS, - ET<:AbstractTensorMap{S, 3, 1}, - CT<:AbstractTensorMap{S, 1, 1}} - O::OT - AL::Matrix{ET} - AR::Matrix{ET} - C::Matrix{CT} - L::Matrix{ET} - R::Matrix{ET} - function VUMPSRuntime(O::OT, - AL::Matrix{ET}, - AR::Matrix{ET}, - C::Matrix{CT}, - L::Matrix{ET}, - R::Matrix{ET}) where {OT, ET, CT} - T = eltype(AL[1]) - S = spacetype(AL[1]) - new{T, S, OT, ET, CT}(O, AL, AR, C, L, R) +function ChainRulesCore.rrule(::Type{InfiniteTransferPEPS}, top::Matrix, bot::Matrix) + function pullback(Δ) + return NoTangent(), Δ.top, Δ.bot end + return InfiniteTransferPEPS(top, bot), pullback end +Base.eltype(transfer::InfiniteTransferPEPS) = eltype(transfer.top[1]) +Base.size(transfer::InfiniteTransferPEPS) = size(transfer.top) + """ ```` @@ -89,22 +40,16 @@ spaces consistent with the unit cell. function initial_A(O::InfiniteTransferPEPS, χ::VectorSpace) T = eltype(O) Ni, Nj = size(O) - A = Matrix{TensorMap}(undef, Ni, Nj) - for j in 1:Nj, i in 1:Ni - D = space(O.top[i, j], 2)' - A[i, j] = TensorMap(rand, T, χ * D * D', χ) - end + A = [(D = space(O.top[i, j], 2)'; + TensorMap(rand, T, χ * D * D', χ)) for i in 1:Ni, j in 1:Nj] return A end function initial_C(A::Matrix{<:AbstractTensorMap}) T = eltype(A[1]) Ni, Nj = size(A) - C = Matrix{TensorMap}(undef, Ni, Nj) - for j in 1:Nj, i in 1:Ni - χ = space(A[i, j], 1) - C[i, j] = isomorphism(Matrix{T}, χ, χ) # only for CPU - end + C = [(χ = space(A[i, j], 1); + isomorphism(Matrix{T}, χ, χ)) for i in 1:Ni, j in 1:Nj] return C end @@ -159,6 +104,18 @@ function getL!(A::Matrix{<:AbstractTensorMap}, L::Matrix{<:AbstractTensorMap}; v return L end +function _to_front(t::AbstractTensorMap) # make TensorMap{S,N₁+N₂-1,1} + I1 = TensorKit.codomainind(t) + I2 = TensorKit.domainind(t) + return transpose(t, ((I1..., reverse(Base.tail(I2))...), (I2[1],))) +end + +function _to_tail(t::AbstractTensorMap) # make TensorMap{S,1,N₁+N₂-1} + I1 = TensorKit.codomainind(t) + I2 = TensorKit.domainind(t) + return transpose(t, ((I1[1],), (I2..., reverse(Base.tail(I1))...))) +end + """ AL, Le, λ = getAL(A::Matrix{<:AbstractTensorMap}, L::Matrix{<:AbstractTensorMap}) @@ -171,7 +128,7 @@ function getAL(A::Matrix{<:AbstractTensorMap}, L::Matrix{<:AbstractTensorMap}) Le = similar(L) λ = zeros(Ni, Nj) @inbounds for j = 1:Nj, i = 1:Ni - Q, R = leftorth!(transpose(L[i,j]*transpose(A[i,j], ((1,),(4,3,2))), ((1,4,3),(2,)))) + Q, R = leftorth!(_to_front(L[i,j] * _to_tail(A[i,j]))) AL[i,j] = Q λ[i,j] = norm(R) Le[i,j] = rmul!(R, 1/λ[i,j]) @@ -226,33 +183,23 @@ function right_canonical(A::Matrix{<:AbstractTensorMap}, L::Matrix{<:AbstractTen AL, L, λ = left_canonical(Ar, Lr; tol, maxiter, kwargs...) R = [permute( L, ((2,), (1, ))) for L in L] - AR = [permute(AL, ((4,), (2,3,1))) for AL in AL] + AR = [permute(AL, ((4,2,3), (1,))) for AL in AL] return R, AR, λ end function initial_FL(AL::Matrix{<:AbstractTensorMap}, O::InfiniteTransferPEPS) T = eltype(O) - Ni, Nj = size(O) - FL = Matrix{TensorMap}(undef, Ni, Nj) - for j in 1:Nj, i in 1:Ni - D = space(O.top[i, j], 5)' - χ = space(AL[i, j], 4)' - FL[i, j] = TensorMap(rand, T, χ * D * D', χ) - end - + FL = [(D = space(top, 5)'; + χ = space(AL, 4)'; + TensorMap(rand, T, χ * D * D', χ)) for (top, AL) in zip(O.top, AL)] return FL end function initial_FR(AR::Matrix{<:AbstractTensorMap}, O::InfiniteTransferPEPS) T = eltype(O) - Ni, Nj = size(O) - FR = Matrix{TensorMap}(undef, Ni, Nj) - for j in 1:Nj, i in 1:Ni - D = space(O.top[i, j], 3)' - χ = space(AR[i, j], 4)' - FR[i, j] = TensorMap(rand, T, χ * D * D', χ) - end - + FR = [(D = space(top, 3)'; + χ = space(AR, 4)'; + TensorMap(rand, T, χ * D * D', χ)) for (top, AR) in zip(O.top, AR)] return FR end @@ -269,15 +216,189 @@ FLᵢⱼ ─ Oᵢⱼ ── = λLᵢⱼ FLᵢⱼ₊₁ └── ALdᵢᵣⱼ ─ └── ``` """ -leftenv(ALu::Matrix{<:AbstractTensorMap}, ALd::Matrix{<:AbstractTensorMap}, O::InfiniteTransferPEPS, FL::Matrix{<:AbstractTensorMap} = initial_FL(ALu,O); kwargs...) = leftenv!(ALu, ALd, O, deepcopy(FL); kwargs...) -function leftenv!(ALu::Matrix{<:AbstractTensorMap}, ALd::Matrix{<:AbstractTensorMap}, O::InfiniteTransferPEPS, FL::Matrix{<:AbstractTensorMap}; ifobs=false, kwargs...) +leftenv(ALu::Matrix{<:AbstractTensorMap}, + ALd::Matrix{<:AbstractTensorMap}, + O::InfiniteTransferPEPS, + FL::Matrix{<:AbstractTensorMap} = initial_FL(ALu,O); + kwargs...) = leftenv!(ALu, ALd, O, deepcopy(FL); kwargs...) + +function leftenv!(ALu::Matrix{<:AbstractTensorMap}, + ALd::Matrix{<:AbstractTensorMap}, + O::InfiniteTransferPEPS, + FL::Matrix{<:AbstractTensorMap}; + ifobs=false, verbosity = Defaults.verbosity, kwargs...) + Ni, Nj = size(O) λL = zeros(eltype(O), Ni) for i in 1:Ni ir = ifobs ? Ni + 1 - i : mod1(i + 1, Ni) - λLs, FL1s, info = eigsolve(FLi -> FLmap(FLi, ALu[i,:], ALd[ir,:], O.top[i,:], O.bot[i,:]), FL[i,:], 1, :LM; maxiter=100, ishermitian = false, kwargs...) - info.converged == 0 && @warn "leftenv not converged" + λLs, FL1s, info = eigsolve(FLi -> FLmap(FLi, ALu[i,:], ALd[ir,:], O.top[i,:], O.bot[i,:]), + FL[i,:], 1, :LM; maxiter=100, ishermitian = false, kwargs...) + verbosity >= 1 && info.converged == 0 && @warn "leftenv not converged" λL[i], FL[i,:] = selectpos(λLs, FL1s, Nj) end return λL, FL +end + +""" + λR, FR = rightenv(ARu, ARd, M, FR = FRint(ARu,M); kwargs...) + +Compute the right environment tensor for MPS A and MPO M, by finding the left fixed point +of AR - M - conj(AR) contracted along the physical dimension. +``` + ── ARuᵢⱼ ──┐ ──┐ + │ │ │ + ── Mᵢⱼ ──FRᵢⱼ = λRᵢⱼ──FRᵢⱼ₋₁ + │ │ │ + ── ARdᵢᵣⱼ ──┘ ──┘ +``` +""" +rightenv(ARu::Matrix{<:AbstractTensorMap}, + ARd::Matrix{<:AbstractTensorMap}, + O::InfiniteTransferPEPS, + FR::Matrix{<:AbstractTensorMap} = initial_FR(ARu,O); + kwargs...) = rightenv!(ARu, ARd, O, deepcopy(FR); kwargs...) + +function rightenv!(ARu::Matrix{<:AbstractTensorMap}, + ARd::Matrix{<:AbstractTensorMap}, + O::InfiniteTransferPEPS, + FR::Matrix{<:AbstractTensorMap}; + ifobs=false, verbosity = Defaults.verbosity, kwargs...) + + Ni, Nj = size(O) + λR = zeros(eltype(O), Ni) + for i in 1:Ni + ir = ifobs ? Ni + 1 - i : mod1(i + 1, Ni) + λRs, FR1s, info = eigsolve(FR -> FRmap(FR, ARu[i,:], ARd[ir,:], O.top[i,:], O.bot[i,:]), + FR[i,:], 1, :LM; maxiter=100, ishermitian = false, kwargs...) + verbosity >= 1 && info.converged == 0 && @warn "rightenv not converged" + λR[i], FR[i,:] = selectpos(λRs, FR1s, Nj) + end + return λR, FR +end + +""" + ACenv(AC, FL, M, FR;kwargs...) + +Compute the up environment tensor for MPS `FL`,`FR` and MPO `M`, by finding the up fixed point + of `FL - M - FR` contracted along the physical dimension. +``` +┌─────── ACᵢⱼ ─────┐ +│ │ │ = λACᵢⱼ ┌─── ACᵢ₊₁ⱼ ──┐ +FLᵢⱼ ─── Oᵢⱼ ───── FRᵢⱼ │ │ │ +│ │ │ +``` +""" +ACenv(AC::Matrix{<:AbstractTensorMap}, + FL::Matrix{<:AbstractTensorMap}, + FR::Matrix{<:AbstractTensorMap}, + O::InfiniteTransferPEPS; + kwargs...) = ACenv!(deepcopy(AC), FL, FR, O; kwargs...) + +function ACenv!(AC::Matrix{<:AbstractTensorMap}, + FL::Matrix{<:AbstractTensorMap}, + FR::Matrix{<:AbstractTensorMap}, + O::InfiniteTransferPEPS; + verbosity = Defaults.verbosity, kwargs...) + + Ni, Nj = size(O) + λAC = zeros(eltype(O),Nj) + for j in 1:Nj + λACs, ACs, info = eigsolve(AC -> ACmap(AC, FL[:,j], FR[:,j], O.top[:,j], O.bot[:,j]), + AC[:,j], 1, :LM; maxiter=100, ishermitian = false, kwargs...) + verbosity >= 1 && info.converged == 0 && @warn "ACenv Not converged" + λAC[j], AC[:,j] = selectpos(λACs, ACs, Ni) + end + return λAC, AC +end + +""" + λC, C = Cenv(C::Matrix{<:AbstractTensorMap}, + FL::Matrix{<:AbstractTensorMap}, + FR::Matrix{<:AbstractTensorMap}; + kwargs...) = Cenv!(copy(C), FL, FR; kwargs...) + +Compute the up environment tensor for MPS `FL` and `FR`, by finding the up fixed point + of `FL - FR` contracted along the physical dimension. +``` +┌────Cᵢⱼ ───┐ +│ │ = λCᵢⱼ ┌──Cᵢⱼ ─┐ +FLᵢⱼ₊₁ ──── FRᵢⱼ │ │ +│ │ +``` +""" +Cenv(C::Matrix{<:AbstractTensorMap}, + FL::Matrix{<:AbstractTensorMap}, + FR::Matrix{<:AbstractTensorMap}; + kwargs...) = Cenv!(copy(C), FL, FR; kwargs...) + +function Cenv!(C::Matrix{<:AbstractTensorMap}, + FL::Matrix{<:AbstractTensorMap}, + FR::Matrix{<:AbstractTensorMap}; + verbosity = Defaults.verbosity, kwargs...) + + Ni, Nj = size(C) + λC = zeros(eltype(C[1]), Nj) + for j in 1:Nj + jr = mod1(j + 1, Nj) + λCs, Cs, info = eigsolve(C -> Cmap(C, FL[:,jr], FR[:,j]), + C[:,j], 1, :LM; maxiter=100, ishermitian = false, kwargs...) + verbosity >= 1 && info.converged == 0 && @warn "Cenv Not converged" + λC[j], C[:,j] = selectpos(λCs, Cs, Ni) + end + return λC, C +end + +function env_norm(F::Matrix{<:AbstractTensorMap}) + Ni, Nj = size(F) + buf = Zygote.Buffer(F) + @inbounds for j in 1:Nj, i in 1:Ni + buf[i,j] = F[i,j]/norm(F[i,j]) + end + return copy(buf) +end + +""" + AL, AR = ACCtoALAR(AC, C) + +QR factorization to get `AL` and `AR` from `AC` and `C` + +```` +──ALᵢⱼ──Cᵢⱼ── = ──ACᵢⱼ── = ──Cᵢ₋₁ⱼ ──ARᵢⱼ── + │ │ │ +```` +""" +function ACCtoALAR(AC::Matrix{<:AbstractTensorMap}, C::Matrix{<:AbstractTensorMap}) + AC = env_norm(AC) + C = env_norm( C) + AL, errL = ACCtoAL(AC, C) + AR, errR = ACCtoAR(AC, C) + return AL, AR, errL, errR +end + +function ACCtoAL(AC::Matrix{<:AbstractTensorMap}, C::Matrix{<:AbstractTensorMap}) + Ni, Nj = size(AC) + errL = 0.0 + AL = Zygote.Buffer(AC) + @inbounds for j in 1:Nj, i in 1:Ni + QAC, RAC = TensorKit.leftorth(AC[i,j]) + QC, RC = TensorKit.leftorth( C[i,j]) + errL += norm(RAC - RC) + AL[i,j] = QAC * QC' + end + return copy(AL), errL +end + +function ACCtoAR(AC::Matrix{<:AbstractTensorMap}, C::Matrix{<:AbstractTensorMap}) + Ni, Nj = size(AC) + errR = 0.0 + AR = Zygote.Buffer(AC) + @inbounds for j in 1:Nj, i in 1:Ni + jr = j - 1 + (j==1)*Nj + LAC, QAC = rightorth(_to_tail(AC[i,j])) + LC, QC = rightorth(C[i,jr]) + errR += norm(LAC - LC) + AR[i,j] = _to_front(QC' * QAC) + end + return copy(AR), errR end \ No newline at end of file diff --git a/src/operators/infinitepepo.jl b/src/operators/infinitepepo.jl deleted file mode 100644 index a33c7e2c..00000000 --- a/src/operators/infinitepepo.jl +++ /dev/null @@ -1,139 +0,0 @@ -""" - struct InfinitePEPO{T<:PEPOTensor} - -Represents an infinite projected entangled-pair operator (PEPO) on a 3D cubic lattice. -""" -struct InfinitePEPO{T<:PEPOTensor} <: AbstractPEPO - A::Array{T,3} - - function InfinitePEPO(A::Array{T,3}) where {T<:PEPOTensor} - # space checks - for (d, w, h) in Tuple.(CartesianIndices(A)) - space(A[d, w, h], 1) == space(A[d, w, _next(h, end)], 2)' || - throw(SpaceMismatch("Physical space at site $((d, w, h)) does not match.")) - space(A[d, w, h], 3) == space(A[_prev(d, end), w, h], 5)' || throw( - SpaceMismatch("North virtual space at site $((d, w, h)) does not match."), - ) - space(A[d, w, h], 4) == space(A[d, _next(w, end), h], 6)' || throw( - SpaceMismatch("East virtual space at site $((d, w, h)) does not match.") - ) - end - return new{T}(A) - end -end - -## Constructors -""" - InfinitePEPO(A::AbstractArray{T, 3}) - -Allow users to pass in an array of tensors. -""" -function InfinitePEPO(A::AbstractArray{T,3}) where {T<:PEPOTensor} - return InfinitePEPO(Array(deepcopy(A))) -end - -""" - InfinitePEPO(f=randn, T=ComplexF64, Pspaces, Nspaces, Espaces) - -Allow users to pass in arrays of spaces. -""" -function InfinitePEPO( - Pspaces::A, Nspaces::A, Espaces::A=Nspaces -) where {A<:AbstractArray{<:ElementarySpace,3}} - return InfinitePEPO(randn, ComplexF64, Pspaces, Nspaces, Espaces) -end -function InfinitePEPO( - f, T, Pspaces::A, Nspaces::A, Espaces::A=Nspaces -) where {A<:AbstractArray{<:ElementarySpace,3}} - size(Pspaces) == size(Nspaces) == size(Espaces) || - throw(ArgumentError("Input spaces should have equal sizes.")) - - Sspaces = adjoint.(circshift(Nspaces, (1, 0, 0))) - Wspaces = adjoint.(circshift(Espaces, (0, -1, 0))) - Ppspaces = adjoint.(circshift(Pspaces, (0, 0, -1))) - - P = map(Pspaces, Ppspaces, Nspaces, Espaces, Sspaces, Wspaces) do P, Pp, N, E, S, W - return TensorMap(f, T, P * Pp ← N * E * S * W) - end - - return InfinitePEPO(P) -end - -function InfinitePEPO( - Pspaces::A, Nspaces::A, Espaces::A=Nspaces -) where {A<:AbstractArray{<:ElementarySpace,2}} - size(Pspaces) == size(Nspaces) == size(Espaces) || - throw(ArgumentError("Input spaces should have equal sizes.")) - - Pspaces = reshape(Pspaces, (size(Pspaces)..., 1)) - Nspaces = reshape(Pspaces, (size(Nspaces)..., 1)) - Espaces = reshape(Pspaces, (size(Espaces)..., 1)) - - return InfinitePEPO(Pspaces, Nspaces, Espaces) -end - -""" - InfinitePEPO(A; unitcell=(1, 1, 1)) - -Create an InfinitePEPO by specifying a tensor and unit cell. -""" -function InfinitePEPO(A::T; unitcell::Tuple{Int,Int,Int}=(1, 1, 1)) where {T<:PEPOTensor} - return InfinitePEPO(fill(A, unitcell)) -end - -""" - InfinitePEPO(f=randn, T=ComplexF64, Pspace, Nspace, [Espace]; unitcell=(1,1,1)) - -Create an InfinitePEPO by specifying its spaces and unit cell. -""" -function InfinitePEPO( - Pspace::S, Nspace::S, Espace::S=Nspace; unitcell::Tuple{Int,Int,Int}=(1, 1, 1) -) where {S<:ElementarySpace} - return InfinitePEPO( - randn, - ComplexF64, - fill(Pspace, unitcell), - fill(Nspace, unitcell), - fill(Espace, unitcell), - ) -end -function InfinitePEPO( - f, T, Pspace::S, Nspace::S, Espace::S=Nspace; unitcell::Tuple{Int,Int,Int}=(1, 1, 1) -) where {S<:ElementarySpace} - return InfinitePEPO( - f, T, fill(Pspace, unitcell), fill(Nspace, unitcell), fill(Espace, unitcell) - ) -end - -## Shape and size -Base.size(T::InfinitePEPO) = size(T.A) -Base.size(T::InfinitePEPO, i) = size(T.A, i) -Base.length(T::InfinitePEPO) = length(T.A) -Base.eltype(T::InfinitePEPO) = eltype(T.A) -VectorInterface.scalartype(T::InfinitePEPO) = scalartype(T.A) - -## Copy -Base.copy(T::InfinitePEPO) = InfinitePEPO(copy(T.A)) -Base.similar(T::InfinitePEPO) = InfinitePEPO(similar(T.A)) -Base.repeat(T::InfinitePEPO, counts...) = InfinitePEPO(repeat(T.A, counts...)) - -Base.getindex(T::InfinitePEPO, args...) = Base.getindex(T.A, args...) -Base.axes(T::InfinitePEPO, args...) = axes(T.A, args...) -TensorKit.space(T::InfinitePEPO, i, j) = space(T[i, j, end], 1) - -function initializePEPS( - T::InfinitePEPO{<:PEPOTensor{S}}, vspace::S -) where {S<:ElementarySpace} - Pspaces = Array{S,2}(undef, size(T, 1), size(T, 2)) - for (i, j) in product(1:size(T, 1), 1:size(T, 2)) - Pspaces[i, j] = space(T, i, j) - end - Nspaces = repeat([vspace], size(T, 1), size(T, 2)) - Espaces = repeat([vspace], size(T, 1), size(T, 2)) - return InfinitePEPS(Pspaces, Nspaces, Espaces) -end - -# Rotations -Base.rotl90(T::InfinitePEPO) = InfinitePEPO(stack(rotl90, eachslice(T.A; dims=3))) -Base.rotr90(T::InfinitePEPO) = InfinitePEPO(stack(rotr90, eachslice(T.A; dims=3))) -Base.rot180(T::InfinitePEPO) = InfinitePEPO(stack(rot180, eachslice(T.A; dims=3))) diff --git a/src/operators/transferpepo.jl b/src/operators/transferpepo.jl deleted file mode 100644 index 5215834c..00000000 --- a/src/operators/transferpepo.jl +++ /dev/null @@ -1,232 +0,0 @@ -""" - InfiniteTransferPEPO{T,O} - -Represents an infinite transfer operator corresponding to a single row of a partition -function which corresponds to the expectation value of an `InfinitePEPO` between 'ket' and -'bra' `InfinitePEPS` states. -""" -struct InfiniteTransferPEPO{T,O} - top::PeriodicArray{T,1} - mid::PeriodicArray{O,2} - bot::PeriodicArray{T,1} -end - -InfiniteTransferPEPO(top, mid) = InfiniteTransferPEPO(top, mid, top) - -""" - InfiniteTransferPEPO(T::InfinitePEPS, O::InfinitePEPO, dir, row) - -Constructs a transfer operator corresponding to a single row of a partition function -representing the expectation value of `O` for the state `T`. The partition function is first -rotated such that the direction `dir` faces north, after which its `row`th row from the -north is selected. -""" -function InfiniteTransferPEPO(T::InfinitePEPS, O::InfinitePEPO, dir, row) - T = rotate_north(T, dir) - O = rotate_north(O, dir) - return InfiniteTransferPEPO(PeriodicArray(T[row, :]), PeriodicArray(O[row, :, :])) -end - -Base.size(transfer::InfiniteTransferPEPO) = size(transfer.top) -Base.size(transfer::InfiniteTransferPEPO, args...) = size(transfer.top, args...) -Base.length(transfer::InfiniteTransferPEPO) = size(transfer, 1) -height(transfer::InfiniteTransferPEPO) = size(transfer.mid, 2) -Base.getindex(O::InfiniteTransferPEPO, i) = (O.top[i], O.bot[i], Tuple(O.mid[i, :])) # TODO: not too sure about this - -Base.iterate(O::InfiniteTransferPEPO, i=1) = i > length(O) ? nothing : (O[i], i + 1) - -function virtual_spaces(O::InfiniteTransferPEPO, i, dir) - return [ - space(O.top[i], dir + 1), - space.(O.mid[i, :], Ref(dir + 2))..., - space(O.bot[i], dir + 1)', - ] -end -north_spaces(O::InfiniteTransferPEPO, i) = virtual_spaces(O, i, NORTH) -east_spaces(O::InfiniteTransferPEPO, i) = virtual_spaces(O, i, EAST) -south_spaces(O::InfiniteTransferPEPO, i) = virtual_spaces(O, i, SOUTH) -west_spaces(O::InfiniteTransferPEPO, i) = virtual_spaces(O, i, WEST) - -function initializeMPS(O::InfiniteTransferPEPO, virtualspaces::AbstractArray{S,1}) where {S} - return InfiniteMPS([ - TensorMap( - rand, - MPSKit.Defaults.eltype, # should be scalartype of transfer PEPO? - virtualspaces[_prev(i, end)] * prod(adjoint.(north_spaces(O, i))), - virtualspaces[mod1(i, end)], - ) for i in 1:length(O) - ]) -end - -function initializeMPS(O::InfiniteTransferPEPO, χ::Int) - return InfiniteMPS([ - TensorMap( - rand, MPSKit.Defaults.eltype, ℂ^χ * prod(adjoint.(north_spaces(O, i))), ℂ^χ - ) for i in 1:length(O) - ]) -end - -""" - const TransferPEPOMultiline = MPSKit.Multiline{<:InfiniteTransferPEPO} - -Type that represents a multi-line transfer operator, where each line each corresponds to a -row of a partition function encoding the overlap of an `InfinitePEPO` between 'ket' and -'bra' `InfinitePEPS` states. -""" -const TransferPEPOMultiline = MPSKit.Multiline{<:InfiniteTransferPEPO} -Base.convert(::Type{TransferPEPOMultiline}, O::InfiniteTransferPEPO) = MPSKit.Multiline([O]) -Base.getindex(t::TransferPEPOMultiline, i::Colon, j::Int) = Base.getindex.(t.data[i], j) -Base.getindex(t::TransferPEPOMultiline, i::Int, j) = Base.getindex(t.data[i], j) - -""" - TransferPEPOMultiline(T::InfinitePEPS, O::InfinitePEPO, dir) - -Construct a multi-row transfer operator corresponding to the partition function representing -the expectation value of `O` for the state `T`. The partition function is first rotated such -that the direction `dir` faces north. -""" -function TransferPEPOMultiline(T::InfinitePEPS, O::InfinitePEPO, dir) - rowsize = size(T, mod1(dir, 2)) # depends on dir - return MPSKit.Multiline(map(cr -> InfiniteTransferPEPO(T, O, dir, cr), 1:rowsize)) -end - -# specialize simple case -function MPSKit.transfer_left( - GL::GenericMPSTensor{S,4}, - O::Tuple{T,T,Tuple{P}}, - A::GenericMPSTensor{S,4}, - Ā::GenericMPSTensor{S,4}, -) where {S,T<:PEPSTensor,P<:PEPOTensor} - @tensor GL′[-1 -2 -3 -4; -5] := - GL[10 7 4 2; 1] * - conj(Ā[10 11 12 13; -1]) * - O[1][8; 9 -2 11 7] * - O[3][1][5 8; 6 -3 12 4] * - conj(O[2][5; 3 -4 13 2]) * - A[1 9 6 3; -5] -end - -# general case -function MPSKit.transfer_left( - GL::GenericMPSTensor{S,N}, - O::Tuple{T,T,Tuple{Vararg{P,H}}}, - A::GenericMPSTensor{S,N}, - Ā::GenericMPSTensor{S,N}, -) where {S,T<:PEPSTensor,P<:PEPOTensor,N,H} - # sanity check - @assert H == N - 3 - - # collect tensors in convenient order: env, above, below, top, mid, bot - tensors = [GL, A, Ā, O[1], O[3]..., O[2]] - - # contraction order: GL, A, top, mid..., bot, Ā - - # number of contracted legs for full top-mid-bot stack - nlegs_tmb = 5 + 3 * H - - # assign and collect all contraction indices - indicesGL = [2 + nlegs_tmb, 2, ((1:3:((H + 1) * 3)) .+ 3)..., 1] - indicesA = [1, 3, ((1:3:((H + 1) * 3)) .+ 4)..., -(N + 1)] - indicesĀ = [((1:N) .+ (1 + nlegs_tmb))..., -1] - indicesTop = [6, 3, -2, 3 + nlegs_tmb, 2] - indicesBot = [1 + nlegs_tmb, nlegs_tmb, -N, 4 + H + nlegs_tmb, nlegs_tmb - 1] - indicesMid = Vector{Vector{Int}}(undef, H) - for h in 1:H - indicesMid[h] = [ - 3 + 3 * (h + 1), 3 + 3 * h, 2 + 3 * h, -(2 + h), 3 + h + nlegs_tmb, 1 + 3 * h - ] - end - indices = [indicesGL, indicesA, indicesĀ, indicesTop, indicesMid..., indicesBot] - - # record conjflags - conjlist = [false, false, true, false, repeat([false], H)..., true] - - # perform contraction, permute to restore partition - GL′ = permute(ncon(tensors, indices, conjlist), (Tuple(1:N), (N + 1,))) - - return GL′ -end - -# specialize simple case -function MPSKit.transfer_right( - GR::GenericMPSTensor{S,4}, - O::Tuple{T,T,Tuple{P}}, - A::GenericMPSTensor{S,4}, - Ā::GenericMPSTensor{S,4}, -) where {S,T<:PEPSTensor,P<:PEPOTensor} - return @tensor GR′[-1 -2 -3 -4; -5] := - GR[10 7 4 2; 1] * - conj(Ā[-5 9 6 3; 1]) * - O[1][8; 11 7 9 -2] * - O[3][1][5 8; 12 4 6 -3] * - conj(O[2][5; 13 2 3 -4]) * - A[-1 11 12 13; 10] -end - -# general case -function MPSKit.transfer_right( - GR::GenericMPSTensor{S,N}, - O::Tuple{T,T,Tuple{Vararg{P,H}}}, - A::GenericMPSTensor{S,N}, - Ā::GenericMPSTensor{S,N}, -) where {S,T<:PEPSTensor,P<:PEPOTensor,N,H} - # sanity check - @assert H == N - 3 - - # collect tensors in convenient order: env, above, below, top, mid, bot - tensors = [GR, A, Ā, O[1], O[3]..., O[2]] - - # contraction order: GR, A, top, mid..., bot, Ā - - # number of contracted legs for full top-mid-bot stack - nlegs_tmb = 5 + 3 * H - - # assign and collect all contraction indices - indicesGR = [1, 2, ((1:3:((H + 1) * 3)) .+ 3)..., 2 + nlegs_tmb] - indicesA = [-1, 3, ((1:3:((H + 1) * 3)) .+ 4)..., 1] - indicesĀ = [-(N + 1), ((2:N) .+ (1 + nlegs_tmb))..., 2 + nlegs_tmb] - indicesTop = [6, 3, 2, 3 + nlegs_tmb, -2] - indicesBot = [1 + nlegs_tmb, nlegs_tmb, nlegs_tmb - 1, 4 + H + nlegs_tmb, -N] - indicesMid = Vector{Vector{Int}}(undef, H) - for h in 1:H - indicesMid[h] = [ - 3 + 3 * (h + 1), 3 + 3 * h, 2 + 3 * h, 1 + 3 * h, 3 + h + nlegs_tmb, -(2 + h) - ] - end - indices = [indicesGR, indicesA, indicesĀ, indicesTop, indicesMid..., indicesBot] - - # record conjflags - conjlist = [false, false, true, false, repeat([false], H)..., true] - - # perform contraction, permute to restore partition - GR′ = permute(ncon(tensors, indices, conjlist), (Tuple(1:N), (N + 1,))) - - return GR′ -end - -function MPSKit.expectation_value(st::InfiniteMPS, transfer::InfiniteTransferPEPO) - return expectation_value( - convert(MPSMultiline, st), convert(TransferPEPOMultiline, transfer) - ) -end -function MPSKit.expectation_value(st::MPSMultiline, mpo::TransferPEPOMultiline) - return expectation_value(st, environments(st, mpo)) -end -function MPSKit.expectation_value( - st::MPSMultiline, ca::MPSKit.PerMPOInfEnv{H,V,S,A} -) where {H<:TransferPEPOMultiline,V,S,A} - return expectation_value(st, ca.opp, ca) -end -function MPSKit.expectation_value( - st::MPSMultiline, opp::TransferPEPOMultiline, ca::MPSKit.PerMPOInfEnv -) - return prod(product(1:size(st, 1), 1:size(st, 2))) do (i, j) - O_ij = opp[i, j] - N = height(opp[1]) + 4 - # just reuse left environment contraction - GL´ = transfer_left(leftenv(ca, i, j, st), O_ij, st.AC[i, j], st.AC[i + 1, j]) - return TensorOperations.tensorscalar( - ncon([GL´, rightenv(ca, i, j, st)], [[N, (2:(N - 1))..., 1], [(1:N)...]]) - ) - end -end diff --git a/src/operators/transferpeps.jl b/src/operators/transferpeps.jl deleted file mode 100644 index 78cb33a1..00000000 --- a/src/operators/transferpeps.jl +++ /dev/null @@ -1,106 +0,0 @@ -""" - InfiniteTransferPEPS{T} - -Represents an infinite transfer operator corresponding to a single row of a partition -function which corresponds to the overlap between 'ket' and 'bra' `InfinitePEPS` states. -""" -struct InfiniteTransferPEPS{TT, BT} - top::Matrix{TT} - bot::Matrix{BT} -end - -function InfiniteTransferPEPS(ipeps::InfinitePEPS) - top = ipeps.A - bot = [A' for A in ipeps.A] - return InfiniteTransferPEPS(top, bot) -end - -function ChainRulesCore.rrule(::Type{InfiniteTransferPEPS}, top::Matrix, bot::Matrix) - function pullback(Δ) - return NoTangent(), Δ.top, Δ.bot - end - return InfiniteTransferPEPS(top, bot), pullback -end - -Base.eltype(transfer::InfiniteTransferPEPS) = eltype(transfer.top[1]) -Base.size(transfer::InfiniteTransferPEPS) = size(transfer.top) -# Base.size(transfer::InfiniteTransferPEPS, args...) = size(transfer.top, args...) -# Base.length(transfer::InfiniteTransferPEPS) = size(transfer, 1) -# Base.getindex(O::InfiniteTransferPEPS, i) = (O.top[i], O.bot[i]) - -# Base.iterate(O::InfiniteTransferPEPS, i=1) = i > length(O) ? nothing : (O[i], i + 1) - -# function MPSKit.transfer_left( -# GL::GenericMPSTensor{S,3}, -# O::NTuple{2,PEPSTensor}, -# A::GenericMPSTensor{S,3}, -# Ā::GenericMPSTensor{S,3}, -# ) where {S} -# return @tensor GL′[-1 -2 -3; -4] := -# GL[1 2 4; 7] * -# conj(Ā[1 3 6; -1]) * -# O[1][5; 8 -2 3 2] * -# conj(O[2][5; 9 -3 6 4]) * -# A[7 8 9; -4] -# end - -# function MPSKit.transfer_right( -# GR::GenericMPSTensor{S,3}, -# O::NTuple{2,PEPSTensor}, -# A::GenericMPSTensor{S,3}, -# Ā::GenericMPSTensor{S,3}, -# ) where {S} -# return @tensor GR′[-1 -2 -3; -4] := -# GR[7 6 2; 1] * -# conj(Ā[-4 4 3; 1]) * -# O[1][5; 9 6 4 -2] * -# conj(O[2][5; 8 2 3 -3]) * -# A[-1 9 8 7] -# end - -# @doc """ -# MPSKit.expectation_value(st::InfiniteMPS, op::Union{InfiniteTransferPEPS,InfiniteTransferPEPO}) -# MPSKit.expectation_value(st::MPSMultiline, op::Union{TransferPEPSMultiline,TransferPEPOMultiline}) - -# Compute expectation value of the transfer operator `op` for the state `st` for each site in -# the unit cell. -# """ MPSKit.expectation_value(st, op) - -# function MPSKit.expectation_value(st::InfiniteMPS, transfer::InfiniteTransferPEPS) -# return expectation_value( -# convert(MPSMultiline, st), convert(TransferPEPSMultiline, transfer) -# ) -# end -# function MPSKit.expectation_value(st::MPSMultiline, mpo::TransferPEPSMultiline) -# return expectation_value(st, environments(st, mpo)) -# end -# function MPSKit.expectation_value( -# st::MPSMultiline, ca::MPSKit.PerMPOInfEnv{H,V,S,A} -# ) where {H<:TransferPEPSMultiline,V,S,A} -# return expectation_value(st, ca.opp, ca) -# end -# function MPSKit.expectation_value( -# st::MPSMultiline, opp::TransferPEPSMultiline, ca::MPSKit.PerMPOInfEnv -# ) -# return prod(product(1:size(st, 1), 1:size(st, 2))) do (i, j) -# O_ij = opp[i, j] -# return @tensor leftenv(ca, i, j, st)[1 2 4; 7] * -# conj(st[i + 1].AC[j][1 3 6; 13]) * -# O_ij[1][5; 8 11 3 2] * -# conj(O_ij[2][5; 9 12 6 4]) * -# st[i].AC[j][7 8 9; 10] * -# rightenv(ca, i, j, st)[10 11 12; 13] -# end -# end - -# @doc """ -# MPSKit.leading_boundary( -# st::InfiniteMPS, op::Union{InfiniteTransferPEPS,InfiniteTransferPEPO}, alg, [envs] -# ) -# MPSKit.leading_boundary( -# st::MPSMulitline, op::Union{TransferPEPSMultiline,TransferPEPOMultiline}, alg, [envs] -# ) - -# Approximate the leading boundary MPS eigenvector for the transfer operator `op` using `st` -# as initial guess. -# """ MPSKit.leading_boundary(st, op, alg) diff --git a/test/vumps/vumps.jl b/test/vumps/vumps.jl new file mode 100644 index 00000000..cedff0b9 --- /dev/null +++ b/test/vumps/vumps.jl @@ -0,0 +1,43 @@ +using Test +using Random +using PEPSKit: leading_boundary +using TensorKit + +begin "test utility" + ds = [ℂ^2] + Ds = [ℂ^3] + χs = [ℂ^4] +end + +@testset "initialize environments for unitcell $Ni x $Nj" for Ni in 1:2, Nj in 1:2, (d, D, χ) in zip(ds, Ds, χs) + Random.seed!(42) + ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) + alg = VUMPS(verbosity=4) + + itp = InfiniteTransferPEPS(ipeps) + vumpsruntime = VUMPSRuntime(itp, χ, alg) + @test vumpsruntime isa VUMPSRuntime +end + +@testset "vumps runtime for unitcell $Ni x $Nj" for Ni in 1:2, Nj in 1:2, (d, D, χ) in zip(ds, Ds, χs) + Random.seed!(42) + ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) + alg = VUMPS(maxiter=100, verbosity=2) + + itp = InfiniteTransferPEPS(ipeps) + leading_boundary(itp, VUMPSRuntime(itp, χ, alg), alg) +end + +# @testset "(2, 2) PEPS" begin +# psi = InfinitePEPS(ComplexSpace(2), ComplexSpace(2); unitcell=(2, 2)) +# T = PEPSKit.TransferPEPSMultiline(psi, 1) + +# mps = PEPSKit.initializeMPS(T, fill(ComplexSpace(20), 2, 2)) +# mps, envs, ϵ = leading_boundary(mps, T, vumps_alg) +# N = abs(prod(expectation_value(mps, T))) + +# ctm = leading_boundary(CTMRGEnv(psi, ComplexSpace(20)), psi, CTMRG(; verbosity=1)) +# N´ = abs(norm(psi, ctm)) + +# @test N ≈ N´ rtol = 1e-2 +# end \ No newline at end of file diff --git a/test/vumps/vumps_environment.jl b/test/vumps/vumps_environment.jl index 8b22fe95..6ec71a8d 100644 --- a/test/vumps/vumps_environment.jl +++ b/test/vumps/vumps_environment.jl @@ -2,8 +2,9 @@ using Test using Random using PEPSKit using PEPSKit: initial_A, initial_C, initial_FL, initial_FR -using PEPSKit: ρmap, getL!, getAL, getLsped, left_canonical, right_canonical -using PEPSKit: leftenv, FLmap +using PEPSKit: ρmap, getL!, getAL, getLsped, _to_tail, _to_front, left_canonical, right_canonical +using PEPSKit: leftenv, FLmap, rightenv, FRmap, ACenv, ACmap, Cenv, Cmap +using PEPSKit: LRtoC, ALCtoAC, ACCtoALAR using TensorKit using LinearAlgebra @@ -12,6 +13,7 @@ begin "test utility" Ds = [ℂ^3] χs = [ℂ^4] end + @testset begin A = TensorMap(rand, ComplexF64, ℂ^2 * ℂ^3, ℂ^4) # @show storagetype(typeof(A)) @@ -19,6 +21,7 @@ end @show space(A, 1) space(A, 2) space(A, 3) @show space(A', 1) space(A', 2) space(A', 3) @tensor C = A'[3; 1 2] * A[1 2;3] + @show eltype(A) # @show sqrt(C) norm(A) end @@ -79,13 +82,13 @@ end @test all(i -> space(i) == (χ * D * D' ← χ), AL) @test all(i -> space(i) == (χ ← χ), L) @test all(AL -> (AL' * AL ≈ isomorphism(χ, χ)), AL) - @test all(map((A, AL, L, λ) -> λ * AL * L ≈ transpose(L*transpose(A, ((1,),(4,3,2))), ((1,4,3),(2,))), A, AL, L, λ)) + @test all(map((A, AL, L, λ) -> λ * AL * L ≈ _to_front(L * _to_tail(A)), A, AL, L, λ)) R, AR, λ = right_canonical(A) - @test all(i -> space(i) == (χ ← D' * D * χ), AR) + @test all(i -> space(i) == (χ * D * D' ← χ), AR) @test all(i -> space(i) == (χ ← χ), R) - @test all(AR -> (AR * AR' ≈ isomorphism(χ, χ)), AR) - @test all(map((A, R, AR, λ) -> transpose(λ * R * AR, ((1,2,3),(4,))) ≈ A * R, A, R, AR, λ)) + @test all(AR -> (_to_tail(AR) * _to_tail(AR)' ≈ isomorphism(χ, χ)), AR) + @test all(map((A, R, AR, λ) -> _to_front(λ * R * _to_tail(AR)) ≈ A * R, A, R, AR, λ)) end @testset "initialize FL FR for unitcell $Ni x $Nj" for Ni in 1:2, Nj in 1:2, (d, D, χ) in zip(ds, Ds, χs) @@ -104,7 +107,6 @@ end @test all(i -> space(i) == (χ * D * D' ← χ), FR) end - @testset "leftenv and rightenv for unitcell $Ni x $Nj" for Ni in 1:3, Nj in 1:3, (d, D, χ) in zip(ds, Ds, χs), ifobs in [true, false] Random.seed!(42) ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) @@ -115,28 +117,68 @@ end R, AR, λ = right_canonical(A) λL, FL = leftenv(AL, adjoint.(AL), itp; ifobs) + λR, FR = rightenv(AR, adjoint.(AR), itp; ifobs) + @test all(i -> space(i) == (χ * D' * D ← χ), FL) + @test all(i -> space(i) == (χ * D * D' ← χ), FR) + for i in 1:Ni ir = ifobs ? Ni + 1 - i : mod1(i + 1, Ni) @test λL[i] * FL[i,:] ≈ FLmap(FL[i,:], AL[i,:], adjoint.(AL)[ir,:], itp.top[i,:], itp.bot[i,:]) rtol = 1e-12 + @test λR[i] * FR[i,:] ≈ FRmap(FR[i,:], AR[i,:], adjoint.(AR)[ir,:], itp.top[i,:], itp.bot[i,:]) rtol = 1e-12 end end +@testset "ACenv and Cenv for unitcell $Ni x $Nj" for Ni in 1:3, Nj in 1:3, (d, D, χ) in zip(ds, Ds, χs) + Random.seed!(42) + ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) + itp = InfiniteTransferPEPS(ipeps) + A = initial_A(itp, χ) + AL, L, λ = left_canonical(A) + R, AR, λ = right_canonical(A) + λL, FL = leftenv(AL, adjoint.(AL), itp) + λR, FR = rightenv(AR, adjoint.(AR), itp) + C = LRtoC(L, R) + AC = ALCtoAC(AL, C) + λAC, AC = ACenv(AC, FL, FR, itp) + λC, C = Cenv( C, FL, FR) + @test all(i -> space(i) == (χ * D * D' ← χ), AC) + @test all(i -> space(i) == (χ ← χ), C) -# @testset "(2, 2) PEPS" begin -# psi = InfinitePEPS(ComplexSpace(2), ComplexSpace(2); unitcell=(2, 2)) -# T = PEPSKit.TransferPEPSMultiline(psi, 1) + for j in 1:Nj + jr = mod1(j + 1, Nj) + @test λAC[j] * AC[:,j] ≈ ACmap(AC[:,j], FL[:,j], FR[:,j], itp.top[:,j], itp.bot[:,j]) rtol = 1e-12 + @test λC[j] * C[:,j] ≈ Cmap( C[:,j], FL[:,jr], FR[:,j]) rtol = 1e-12 + end +end -# mps = PEPSKit.initializeMPS(T, fill(ComplexSpace(20), 2, 2)) -# mps, envs, ϵ = leading_boundary(mps, T, vumps_alg) -# N = abs(prod(expectation_value(mps, T))) +@testset "ACenv and Cenv for unitcell $Ni x $Nj" for Ni in 1:3, Nj in 1:3, (d, D, χ) in zip(ds, Ds, χs) + Random.seed!(42) + ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) + + itp = InfiniteTransferPEPS(ipeps) + A = initial_A(itp, χ) + AL, L, λ = left_canonical(A) + R, AR, λ = right_canonical(A) + + λL, FL = leftenv(AL, adjoint.(AL), itp) + λR, FR = rightenv(AR, adjoint.(AR), itp) + + C = LRtoC(L, R) + AC = ALCtoAC(AL, C) -# ctm = leading_boundary(CTMRGEnv(psi, ComplexSpace(20)), psi, CTMRG(; verbosity=1)) -# N´ = abs(norm(psi, ctm)) + λAC, AC = ACenv(AC, FL, FR, itp) + λC, C = Cenv( C, FL, FR) -# @test N ≈ N´ rtol = 1e-2 -# endn \ No newline at end of file + AL, AR, errL, errR = ACCtoALAR(AC, C) + @test all(i -> space(i) == (χ * D * D' ← χ), AL) + @test all(i -> space(i) == (χ * D * D' ← χ), AR) + @test all(AL -> (AL' * AL ≈ isomorphism(χ, χ)), AL) + @test all(AR -> (_to_tail(AR) * _to_tail(AR)' ≈ isomorphism(χ, χ)), AR) + @test errL isa Real + @test errR isa Real +end From ab980aea9e1563d03b68434e5e8be1dcd5e8a61c Mon Sep 17 00:00:00 2001 From: XingyuZhang2018 <864129714@qq.com> Date: Wed, 23 Oct 2024 20:31:07 +0200 Subject: [PATCH 12/25] add test --- src/algorithms/toolbox.jl | 18 ++++++++++++++++++ src/utility/defaults.jl | 2 +- test/vumps/vumps.jl | 26 +++++++++++--------------- 3 files changed, 30 insertions(+), 16 deletions(-) diff --git a/src/algorithms/toolbox.jl b/src/algorithms/toolbox.jl index 4f48cdf4..8414cd7a 100644 --- a/src/algorithms/toolbox.jl +++ b/src/algorithms/toolbox.jl @@ -56,6 +56,24 @@ function LinearAlgebra.norm(peps::InfinitePEPS, env::CTMRGEnv) return total end +function LinearAlgebra.norm(ipeps::InfinitePEPS, env::VUMPSRuntime) + @unpack AL, C, AR, FL, FR = env + Ni, Nj = size(ipeps) + # AC = Zygote.@ignore ALCtoAC(AL, C) + # total = 1 + # for j in 1:Nj, i in 1:Ni + # ir = mod1(i + 1, Ni) + # @tensoropt Z = FL[i,j][6 5 4; 1] * AC[i,j][1 2 3; -4] * ipeps[i,j][9; 2 -2 8 5] * + # ipeps[i,j]'[3 -3 7 4; 9] * AC[ir,j]'[-1; 6 8 7] * FR[i,j][-4 -2 -3; -1] + # @tensor n = FL[i,j][1 2 3; 4] * C[i,j][4; 5] * FR[i,j][5 2 3; 6] * C[i,j]'[6; 1] + # total *= Z / n + # end + + itp = InfiniteTransferPEPS(ipeps) + λL, FL = leftenv(AL, adjoint.(AL), itp; ifobs=true) + + return prod(λL)^(1/Ni) +end """ correlation_length(peps::InfinitePEPS, env::CTMRGEnv; howmany=2) diff --git a/src/utility/defaults.jl b/src/utility/defaults.jl index 78d3c6d1..45101770 100644 --- a/src/utility/defaults.jl +++ b/src/utility/defaults.jl @@ -37,7 +37,7 @@ module Defaults const fpgrad_maxiter = 30 const fpgrad_tol = 1e-6 const verbosity = VERBOSE_ITER - const contractionscheme = :simultaneous + const ctmrgscheme = :simultaneous const reuse_env = true const trscheme = FixedSpaceTruncation() const iterscheme = :fixed diff --git a/test/vumps/vumps.jl b/test/vumps/vumps.jl index cedff0b9..05915527 100644 --- a/test/vumps/vumps.jl +++ b/test/vumps/vumps.jl @@ -1,12 +1,14 @@ using Test using Random +using PEPSKit using PEPSKit: leading_boundary using TensorKit +using LinearAlgebra begin "test utility" ds = [ℂ^2] - Ds = [ℂ^3] - χs = [ℂ^4] + Ds = [ℂ^2] + χs = [ℂ^20] end @testset "initialize environments for unitcell $Ni x $Nj" for Ni in 1:2, Nj in 1:2, (d, D, χ) in zip(ds, Ds, χs) @@ -25,19 +27,13 @@ end alg = VUMPS(maxiter=100, verbosity=2) itp = InfiniteTransferPEPS(ipeps) - leading_boundary(itp, VUMPSRuntime(itp, χ, alg), alg) -end - -# @testset "(2, 2) PEPS" begin -# psi = InfinitePEPS(ComplexSpace(2), ComplexSpace(2); unitcell=(2, 2)) -# T = PEPSKit.TransferPEPSMultiline(psi, 1) + rt = leading_boundary(itp, VUMPSRuntime(itp, χ, alg), alg) + @test rt isa VUMPSRuntime -# mps = PEPSKit.initializeMPS(T, fill(ComplexSpace(20), 2, 2)) -# mps, envs, ϵ = leading_boundary(mps, T, vumps_alg) -# N = abs(prod(expectation_value(mps, T))) + Z = abs(norm(ipeps, rt)) -# ctm = leading_boundary(CTMRGEnv(psi, ComplexSpace(20)), psi, CTMRG(; verbosity=1)) -# N´ = abs(norm(psi, ctm)) + ctm = MPSKit.leading_boundary(CTMRGEnv(ipeps, χ), ipeps, CTMRG(; verbosity=2)) + Z′ = abs(norm(ipeps, ctm))^(1/Ni/Nj) -# @test N ≈ N´ rtol = 1e-2 -# end \ No newline at end of file + @test Z ≈ Z′ rtol = 1e-2 +end \ No newline at end of file From 2f250707018470e354801362046e82e4fba5b2b0 Mon Sep 17 00:00:00 2001 From: XingyuZhang2018 <864129714@qq.com> Date: Thu, 24 Oct 2024 17:49:32 +0200 Subject: [PATCH 13/25] add updown --- src/algorithms/toolbox.jl | 13 ++--- src/algorithms/vumps/vumps.jl | 93 ++++++++++++++++++++++++++++++----- test/vumps/vumps.jl | 20 ++++---- 3 files changed, 98 insertions(+), 28 deletions(-) diff --git a/src/algorithms/toolbox.jl b/src/algorithms/toolbox.jl index 8414cd7a..db82824e 100644 --- a/src/algorithms/toolbox.jl +++ b/src/algorithms/toolbox.jl @@ -56,23 +56,24 @@ function LinearAlgebra.norm(peps::InfinitePEPS, env::CTMRGEnv) return total end -function LinearAlgebra.norm(ipeps::InfinitePEPS, env::VUMPSRuntime) - @unpack AL, C, AR, FL, FR = env +function LinearAlgebra.norm(ipeps::InfinitePEPS, env::VUMPSEnv) + @unpack ACu, ARu, ACd, ARd, FLu, FRu, FLo, FRo = env Ni, Nj = size(ipeps) - # AC = Zygote.@ignore ALCtoAC(AL, C) # total = 1 # for j in 1:Nj, i in 1:Ni # ir = mod1(i + 1, Ni) - # @tensoropt Z = FL[i,j][6 5 4; 1] * AC[i,j][1 2 3; -4] * ipeps[i,j][9; 2 -2 8 5] * + # @tensoropt Z = FLo[i,j][6 5 4; 1] * ACu[i,j][1 2 3; -4] * ipeps[i,j][9; 2 -2 8 5] * # ipeps[i,j]'[3 -3 7 4; 9] * AC[ir,j]'[-1; 6 8 7] * FR[i,j][-4 -2 -3; -1] # @tensor n = FL[i,j][1 2 3; 4] * C[i,j][4; 5] * FR[i,j][5 2 3; 6] * C[i,j]'[6; 1] # total *= Z / n # end itp = InfiniteTransferPEPS(ipeps) - λL, FL = leftenv(AL, adjoint.(AL), itp; ifobs=true) + λFL, _ = rightenv(ARu, adjoint.(ARd), itp; ifobs=true) + # to do: + # λC, _ = rightCenv(ARu, adjoint.(ARd); ifobs=true) - return prod(λL)^(1/Ni) + return prod(λFL)^(1/Ni) end """ correlation_length(peps::InfinitePEPS, env::CTMRGEnv; howmany=2) diff --git a/src/algorithms/vumps/vumps.jl b/src/algorithms/vumps/vumps.jl index 442c5b98..18e9dcb2 100644 --- a/src/algorithms/vumps/vumps.jl +++ b/src/algorithms/vumps/vumps.jl @@ -1,4 +1,5 @@ @kwdef mutable struct VUMPS{F} <: Algorithm + ifupdown::Bool = true tol::Float64 = Defaults.contr_tol maxiter::Int = Defaults.contr_maxiter finalize::F = Defaults._finalize @@ -24,21 +25,25 @@ For a `Ni` x `Nj` unitcell, each is a Matrix, containing """ struct VUMPSEnv{T<:Number, S<:IndexSpace, ET<:AbstractTensorMap{S, 3, 1}} - AC::Matrix{ET} - AR::Matrix{ET} + ACu::Matrix{ET} + ARu::Matrix{ET} + ACd::Matrix{ET} + ARd::Matrix{ET} FLu::Matrix{ET} FRu::Matrix{ET} FLo::Matrix{ET} FRo::Matrix{ET} - function VUMPSEnv(AC::Matrix{ET}, - AR::Matrix{ET}, + function VUMPSEnv(ACu::Matrix{ET}, + ARu::Matrix{ET}, + ACd::Matrix{ET}, + ARd::Matrix{ET}, FLu::Matrix{ET}, FRu::Matrix{ET}, FLo::Matrix{ET}, FRo::Matrix{ET}) where {ET} - T = eltype(AC[1]) - S = spacetype(AC[1]) - new{T, S, ET}(AC, AR, FLu, FRu, FLo, FRo) + T = eltype(ACu[1]) + S = spacetype(ACu[1]) + new{T, S, ET}(ACu, ARu, ACd, ARd, FLu, FRu, FLo, FRo) end end @@ -78,7 +83,7 @@ struct VUMPSRuntime{T<:Number, S<:IndexSpace, end end -function VUMPSRuntime(O::InfiniteTransferPEPS, χ::VectorSpace, alg::VUMPS) +function VUMPSRuntime(O::InfiniteTransferPEPS, χ::VectorSpace) A = initial_A(O, χ) AL, L, _ = left_canonical(A) R, AR, _ = right_canonical(AL) @@ -86,14 +91,39 @@ function VUMPSRuntime(O::InfiniteTransferPEPS, χ::VectorSpace, alg::VUMPS) _, FL = leftenv(AL, adjoint.(AL), O) _, FR = rightenv(AR, adjoint.(AR), O) C = LRtoC(L, R) - Ni, Nj = size(O) - alg.verbosity >= 2 && println("===== vumps random initial $(Ni)×$(Nj) vumps χ = $(χ) environment =====") return VUMPSRuntime(AL, AR, C, FL, FR) end -function leading_boundary(O::InfiniteTransferPEPS, rt::VUMPSRuntime, alg::VUMPS) +function down_itp(O) + Ni, Nj = size(O) + ipepsd = Zygote.Buffer(O.top) + for j in 1:Nj, i in 1:Ni + ir = Ni + 1 - i + ipepsd[i, j] = permute(ipeps[ir,j], ((1,), (4,3,2,5))) + end + return InfiniteTransferPEPS(copy(ipepsd)) +end + +function VUMPSRuntime(O::InfiniteTransferPEPS, χ::VectorSpace, alg::VUMPS) + Ni, Nj = size(O) + + rtup = VUMPSRuntime(O, χ) + alg.verbosity >= 2 && println("===== vumps random initial $(Ni)×$(Nj) vumps χ = $(χ) up ↑ environment =====") + + if alg.ifupdown + Od = down_itp(O) + rtdown = VUMPSRuntime(Od, χ) + alg.verbosity >= 2 && println("===== vumps random initial $(Ni)×$(Nj) vumps χ = $(χ) down ↓ environment =====") + + return rtup, rtdown + else + return rtup + end +end + +function vumps_itr(O::InfiniteTransferPEPS, rt::VUMPSRuntime, alg::VUMPS) for i in 1:alg.maxiter - rt, err = vumps_itr(O, rt, alg) + rt, err = vumps_step(O, rt, alg) alg.verbosity >= 3 && println(@sprintf("vumps@step: i = %4d\terr = %.3e\t", i, err)) if err < alg.tol alg.verbosity >= 2 && println(@sprintf("===== vumps@step: i = %4d\terr = %.3e\t coveraged =====", i, err)) @@ -106,7 +136,44 @@ function leading_boundary(O::InfiniteTransferPEPS, rt::VUMPSRuntime, alg::VUMPS) return rt end -function vumps_itr(O::InfiniteTransferPEPS, rt::VUMPSRuntime, alg::VUMPS) +function leading_boundary(O::InfiniteTransferPEPS, rt::VUMPSRuntime, alg::VUMPS) + rt = vumps_itr(O, rt, alg) + return VUMPSEnv(rt) +end + +function leading_boundary(O::InfiniteTransferPEPS, rt::Tuple{VUMPSRuntime}, alg::VUMPS) + rtup, rtdown = rt + + rtup = vumps_itr(O, rtup, alg) + + Od = down_itp(O) + rtdown = vumps_itr(Od, rtdown, alg) + + return VUMPSEnv(rtup, rtdown) +end + +function VUMPSEnv(rt::VUMPSRuntime) + @unpack AL, AR, C, FL, FR = rt + AC = ALCtoAC(AL, C) + return VUMPSEnv(AC, AR, AC, AR, FL, FR, FL, FR) +end + +function VUMPSEnv(rt::Tuple{VUMPSRuntime}) + rtup, rtdown = rt + + ALu, ARu, Cu, FLu, FRu = rtup.AL, rtup.AR, rtup.C, rtup.FL, rtup.FR + ACu = ALCtoAC(ALu, Cu) + + ALd, ARd, Cd = rtdown.AL, rtdown.AR, rtdown.C + ACd = ALCtoAC(ALd, Cd) + + _, FLo = leftenv(ALu, adjoint.(ALd), O, FLup; ifobs = true) + _, FRo = rightenv(ARu, adjoint.(ARd), O, FRup; ifobs = true) + + return VUMPSEnv(ACu, ARu, ACd, ARd, FLu, FRu, FLo, FRo) +end + +function vumps_step(O::InfiniteTransferPEPS, rt::VUMPSRuntime, alg::VUMPS) @unpack AL, C, AR, FL, FR = rt AC = Zygote.@ignore ALCtoAC(AL,C) _, ACp = ACenv(AC, FL, FR, O) diff --git a/test/vumps/vumps.jl b/test/vumps/vumps.jl index 05915527..9b311bb0 100644 --- a/test/vumps/vumps.jl +++ b/test/vumps/vumps.jl @@ -1,6 +1,7 @@ using Test using Random using PEPSKit +using MPSKit using PEPSKit: leading_boundary using TensorKit using LinearAlgebra @@ -14,26 +15,27 @@ end @testset "initialize environments for unitcell $Ni x $Nj" for Ni in 1:2, Nj in 1:2, (d, D, χ) in zip(ds, Ds, χs) Random.seed!(42) ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) - alg = VUMPS(verbosity=4) itp = InfiniteTransferPEPS(ipeps) - vumpsruntime = VUMPSRuntime(itp, χ, alg) - @test vumpsruntime isa VUMPSRuntime + rt = VUMPSRuntime(itp, χ) + @test rt isa VUMPSRuntime end -@testset "vumps runtime for unitcell $Ni x $Nj" for Ni in 1:2, Nj in 1:2, (d, D, χ) in zip(ds, Ds, χs) +@testset "vumps one side runtime for unitcell $Ni x $Nj" for Ni in 1:1, Nj in 1:1, (d, D, χ) in zip(ds, Ds, χs) Random.seed!(42) ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) - alg = VUMPS(maxiter=100, verbosity=2) + alg = PEPSKit.VUMPS(maxiter=10, verbosity=2, ifupdown=false) itp = InfiniteTransferPEPS(ipeps) - rt = leading_boundary(itp, VUMPSRuntime(itp, χ, alg), alg) - @test rt isa VUMPSRuntime + env = leading_boundary(itp, VUMPSRuntime(itp, χ), alg) + @test env isa VUMPSEnv - Z = abs(norm(ipeps, rt)) + Z = abs(norm(ipeps, env)) + @show Z ctm = MPSKit.leading_boundary(CTMRGEnv(ipeps, χ), ipeps, CTMRG(; verbosity=2)) Z′ = abs(norm(ipeps, ctm))^(1/Ni/Nj) + @show Z′ - @test Z ≈ Z′ rtol = 1e-2 + # @test Z ≈ Z′ rtol = 1e-2 end \ No newline at end of file From 0eb4515569582d1fa14bf35c8573f61c47cd8595 Mon Sep 17 00:00:00 2001 From: XingyuZhang2018 <864129714@qq.com> Date: Thu, 24 Oct 2024 18:51:15 +0200 Subject: [PATCH 14/25] to do: fix updown index --- .../contractions/vumps_contractions.jl | 20 +++++++++++ src/algorithms/toolbox.jl | 5 +-- src/algorithms/vumps/vumps.jl | 28 ++++++--------- src/environments/vumps_environments.jl | 36 +++++++++++++++++++ test/vumps/vumps.jl | 6 ++-- test/vumps/vumps_environment.jl | 19 +++++++++- 6 files changed, 90 insertions(+), 24 deletions(-) diff --git a/src/algorithms/contractions/vumps_contractions.jl b/src/algorithms/contractions/vumps_contractions.jl index 84b1673a..11ad8bd2 100644 --- a/src/algorithms/contractions/vumps_contractions.jl +++ b/src/algorithms/contractions/vumps_contractions.jl @@ -93,6 +93,26 @@ function FRmap(FRi::Vector{<:AbstractTensorMap}, return circshift(FRm, -1) end +""" + Rm = Rmap(FRi::Vector{<:AbstractTensorMap}, + ARui::Vector{<:AbstractTensorMap}, + ARdir::Vector{<:AbstractTensorMap}, + ) + +``` + ── ARuᵢⱼ ──┐ ──┐ + │ Rᵢⱼ = ── Rᵢⱼ₋₁ + ── ARdᵢᵣⱼ ──┘ ──┘ +``` +""" +function Rmap(Ri::Vector{<:AbstractTensorMap}, + ARui::Vector{<:AbstractTensorMap}, + ARdir::Vector{<:AbstractTensorMap}, ) + Rm = [@tensoropt R[-1; -5] := ARu[-1 2 3; 4] * R[4; 6] * ARd[6; -5 2 3] for (R, ARu, ARd) in zip(Ri, ARui, ARdir)] + + return circshift(Rm, -1) +end + """ ACm = ACmap(ACj::Vector{<:AbstractTensorMap}, FLj::Vector{<:AbstractTensorMap}, diff --git a/src/algorithms/toolbox.jl b/src/algorithms/toolbox.jl index db82824e..e6f2943b 100644 --- a/src/algorithms/toolbox.jl +++ b/src/algorithms/toolbox.jl @@ -71,9 +71,10 @@ function LinearAlgebra.norm(ipeps::InfinitePEPS, env::VUMPSEnv) itp = InfiniteTransferPEPS(ipeps) λFL, _ = rightenv(ARu, adjoint.(ARd), itp; ifobs=true) # to do: - # λC, _ = rightCenv(ARu, adjoint.(ARd); ifobs=true) + λC, _ = rightCenv(ARu, adjoint.(ARd); ifobs=true) + @show λC - return prod(λFL)^(1/Ni) + return prod(λFL ./ λC)^(1/Ni) end """ correlation_length(peps::InfinitePEPS, env::CTMRGEnv; howmany=2) diff --git a/src/algorithms/vumps/vumps.jl b/src/algorithms/vumps/vumps.jl index 18e9dcb2..011fe4f5 100644 --- a/src/algorithms/vumps/vumps.jl +++ b/src/algorithms/vumps/vumps.jl @@ -99,9 +99,9 @@ function down_itp(O) ipepsd = Zygote.Buffer(O.top) for j in 1:Nj, i in 1:Ni ir = Ni + 1 - i - ipepsd[i, j] = permute(ipeps[ir,j], ((1,), (4,3,2,5))) + ipepsd[i, j] = permute(O.top[ir,j], ((1,), (4,3,2,5))) end - return InfiniteTransferPEPS(copy(ipepsd)) + return InfiniteTransferPEPS(InfinitePEPS(copy(ipepsd))) end function VUMPSRuntime(O::InfiniteTransferPEPS, χ::VectorSpace, alg::VUMPS) @@ -138,10 +138,13 @@ end function leading_boundary(O::InfiniteTransferPEPS, rt::VUMPSRuntime, alg::VUMPS) rt = vumps_itr(O, rt, alg) - return VUMPSEnv(rt) + + @unpack AL, AR, C, FL, FR = rt + AC = ALCtoAC(AL, C) + return VUMPSEnv(AC, AR, AC, AR, FL, FR, FL, FR) end -function leading_boundary(O::InfiniteTransferPEPS, rt::Tuple{VUMPSRuntime}, alg::VUMPS) +function leading_boundary(O::InfiniteTransferPEPS, rt::Tuple, alg::VUMPS) rtup, rtdown = rt rtup = vumps_itr(O, rtup, alg) @@ -149,26 +152,15 @@ function leading_boundary(O::InfiniteTransferPEPS, rt::Tuple{VUMPSRuntime}, alg: Od = down_itp(O) rtdown = vumps_itr(Od, rtdown, alg) - return VUMPSEnv(rtup, rtdown) -end - -function VUMPSEnv(rt::VUMPSRuntime) - @unpack AL, AR, C, FL, FR = rt - AC = ALCtoAC(AL, C) - return VUMPSEnv(AC, AR, AC, AR, FL, FR, FL, FR) -end - -function VUMPSEnv(rt::Tuple{VUMPSRuntime}) - rtup, rtdown = rt - ALu, ARu, Cu, FLu, FRu = rtup.AL, rtup.AR, rtup.C, rtup.FL, rtup.FR ACu = ALCtoAC(ALu, Cu) ALd, ARd, Cd = rtdown.AL, rtdown.AR, rtdown.C ACd = ALCtoAC(ALd, Cd) - _, FLo = leftenv(ALu, adjoint.(ALd), O, FLup; ifobs = true) - _, FRo = rightenv(ARu, adjoint.(ARd), O, FRup; ifobs = true) + # to do fix the follow index + _, FLo = leftenv(ALu, adjoint.(ALd), O, FLu; ifobs = true) + _, FRo = rightenv(ARu, adjoint.(ARd), O, FRu; ifobs = true) return VUMPSEnv(ACu, ARu, ACd, ARd, FLu, FRu, FLo, FRo) end diff --git a/src/environments/vumps_environments.jl b/src/environments/vumps_environments.jl index 2ca3af20..8677f468 100644 --- a/src/environments/vumps_environments.jl +++ b/src/environments/vumps_environments.jl @@ -277,6 +277,42 @@ function rightenv!(ARu::Matrix{<:AbstractTensorMap}, return λR, FR end +""" + λR, FR = rightCenv(ARu::Matrix{<:AbstractTensorMap}, + ARd::Matrix{<:AbstractTensorMap}, + R::Matrix{<:AbstractTensorMap} = initial_C(ARu); + kwargs...) + +Compute the right environment tensor for MPS A and MPO M, by finding the left fixed point +of AR - M - conj(AR) contracted along the physical dimension. +``` + ── ARuᵢⱼ ──┐ ──┐ + | Rᵢⱼ = λRᵢⱼ Rᵢⱼ₋₁ + ── ARdᵢᵣⱼ ──┘ ──┘ +``` +""" +rightCenv(ARu::Matrix{<:AbstractTensorMap}, + ARd::Matrix{<:AbstractTensorMap}, + R::Matrix{<:AbstractTensorMap} = initial_C(ARu); + kwargs...) = rightCenv!(ARu, ARd, deepcopy(R); kwargs...) + +function rightCenv!(ARu::Matrix{<:AbstractTensorMap}, + ARd::Matrix{<:AbstractTensorMap}, + R::Matrix{<:AbstractTensorMap}; + ifobs=false, verbosity = Defaults.verbosity, kwargs...) + + Ni, Nj = size(ARu) + λR = zeros(eltype(ARu[1]), Ni) + for i in 1:Ni + ir = ifobs ? Ni + 1 - i : mod1(i + 1, Ni) + λRs, R1s, info = eigsolve(R -> Rmap(R, ARu[i,:], ARd[ir,:]), + R[i,:], 1, :LM; maxiter=100, ishermitian = false, kwargs...) + verbosity >= 1 && info.converged == 0 && @warn "rightenv not converged" + λR[i], R[i,:] = selectpos(λRs, R1s, Nj) + end + return λR, R +end + """ ACenv(AC, FL, M, FR;kwargs...) diff --git a/test/vumps/vumps.jl b/test/vumps/vumps.jl index 9b311bb0..a5d3040d 100644 --- a/test/vumps/vumps.jl +++ b/test/vumps/vumps.jl @@ -24,11 +24,11 @@ end @testset "vumps one side runtime for unitcell $Ni x $Nj" for Ni in 1:1, Nj in 1:1, (d, D, χ) in zip(ds, Ds, χs) Random.seed!(42) ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) - alg = PEPSKit.VUMPS(maxiter=10, verbosity=2, ifupdown=false) + alg = PEPSKit.VUMPS(maxiter=10, verbosity=2, ifupdown=true) itp = InfiniteTransferPEPS(ipeps) - env = leading_boundary(itp, VUMPSRuntime(itp, χ), alg) - @test env isa VUMPSEnv + env = leading_boundary(itp, VUMPSRuntime(itp, χ, alg), alg) + # @test env isa VUMPSEnv Z = abs(norm(ipeps, env)) @show Z diff --git a/test/vumps/vumps_environment.jl b/test/vumps/vumps_environment.jl index 6ec71a8d..57845585 100644 --- a/test/vumps/vumps_environment.jl +++ b/test/vumps/vumps_environment.jl @@ -3,7 +3,7 @@ using Random using PEPSKit using PEPSKit: initial_A, initial_C, initial_FL, initial_FR using PEPSKit: ρmap, getL!, getAL, getLsped, _to_tail, _to_front, left_canonical, right_canonical -using PEPSKit: leftenv, FLmap, rightenv, FRmap, ACenv, ACmap, Cenv, Cmap +using PEPSKit: leftenv, FLmap, rightenv, FRmap, ACenv, ACmap, Cenv, Cmap, rightCenv, Rmap using PEPSKit: LRtoC, ALCtoAC, ACCtoALAR using TensorKit using LinearAlgebra @@ -182,3 +182,20 @@ end @test errL isa Real @test errR isa Real end + +@testset "ACenv and Cenv for unitcell $Ni x $Nj" for Ni in 1:3, Nj in 1:3, (d, D, χ) in zip(ds, Ds, χs), ifobs in [true, false] + Random.seed!(42) + ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) + + itp = InfiniteTransferPEPS(ipeps) + A = initial_A(itp, χ) + R, AR, λ = right_canonical(A) + + λR, R = rightCenv(AR, adjoint.(AR); ifobs) + @test all(i -> space(i) == (χ ← χ), R) + + for i in 1:Ni + ir = ifobs ? Ni + 1 - i : mod1(i + 1, Ni) + @test λR[i] * R[i,:] ≈ Rmap(R[i,:], AR[i,:], adjoint.(AR)[ir,:]) rtol = 1e-12 + end +end \ No newline at end of file From 27321219f53664eee5c6e83f0ee3a2bc03346104 Mon Sep 17 00:00:00 2001 From: XingyuZhang2018 <864129714@qq.com> Date: Fri, 25 Oct 2024 15:21:24 +0200 Subject: [PATCH 15/25] finish vumps forward --- .../contractions/vumps_contractions.jl | 4 +-- src/algorithms/toolbox.jl | 19 ++++--------- src/algorithms/vumps/vumps.jl | 17 +++++++----- src/environments/vumps_environments.jl | 13 ++++++--- test/vumps/vumps.jl | 27 +++++++++++++++---- test/vumps/vumps_environment.jl | 17 +++--------- 6 files changed, 52 insertions(+), 45 deletions(-) diff --git a/src/algorithms/contractions/vumps_contractions.jl b/src/algorithms/contractions/vumps_contractions.jl index 11ad8bd2..5f84d948 100644 --- a/src/algorithms/contractions/vumps_contractions.jl +++ b/src/algorithms/contractions/vumps_contractions.jl @@ -106,8 +106,8 @@ end ``` """ function Rmap(Ri::Vector{<:AbstractTensorMap}, - ARui::Vector{<:AbstractTensorMap}, - ARdir::Vector{<:AbstractTensorMap}, ) + ARui::Vector{<:AbstractTensorMap}, + ARdir::Vector{<:AbstractTensorMap}) Rm = [@tensoropt R[-1; -5] := ARu[-1 2 3; 4] * R[4; 6] * ARd[6; -5 2 3] for (R, ARu, ARd) in zip(Ri, ARui, ARdir)] return circshift(Rm, -1) diff --git a/src/algorithms/toolbox.jl b/src/algorithms/toolbox.jl index e6f2943b..5fe8493e 100644 --- a/src/algorithms/toolbox.jl +++ b/src/algorithms/toolbox.jl @@ -58,24 +58,15 @@ end function LinearAlgebra.norm(ipeps::InfinitePEPS, env::VUMPSEnv) @unpack ACu, ARu, ACd, ARd, FLu, FRu, FLo, FRo = env - Ni, Nj = size(ipeps) - # total = 1 - # for j in 1:Nj, i in 1:Ni - # ir = mod1(i + 1, Ni) - # @tensoropt Z = FLo[i,j][6 5 4; 1] * ACu[i,j][1 2 3; -4] * ipeps[i,j][9; 2 -2 8 5] * - # ipeps[i,j]'[3 -3 7 4; 9] * AC[ir,j]'[-1; 6 8 7] * FR[i,j][-4 -2 -3; -1] - # @tensor n = FL[i,j][1 2 3; 4] * C[i,j][4; 5] * FR[i,j][5 2 3; 6] * C[i,j]'[6; 1] - # total *= Z / n - # end + Ni = size(ipeps, 1) itp = InfiniteTransferPEPS(ipeps) - λFL, _ = rightenv(ARu, adjoint.(ARd), itp; ifobs=true) - # to do: + λFLo, _ = rightenv(ARu, adjoint.(ARd), itp; ifobs=true) λC, _ = rightCenv(ARu, adjoint.(ARd); ifobs=true) - @show λC - - return prod(λFL ./ λC)^(1/Ni) + + return prod(λFLo./λC)^(1/Ni) end + """ correlation_length(peps::InfinitePEPS, env::CTMRGEnv; howmany=2) diff --git a/src/algorithms/vumps/vumps.jl b/src/algorithms/vumps/vumps.jl index 011fe4f5..dfd945ed 100644 --- a/src/algorithms/vumps/vumps.jl +++ b/src/algorithms/vumps/vumps.jl @@ -99,21 +99,23 @@ function down_itp(O) ipepsd = Zygote.Buffer(O.top) for j in 1:Nj, i in 1:Ni ir = Ni + 1 - i - ipepsd[i, j] = permute(O.top[ir,j], ((1,), (4,3,2,5))) + Ad = permute(O.top[ir,j]', ((5,), (3,2,1,4))) + ipepsd[i, j] = _fit_spaces(Ad, O.top[ir,j]) end - return InfiniteTransferPEPS(InfinitePEPS(copy(ipepsd))) + + return InfiniteTransferPEPS(copy(ipepsd)) end function VUMPSRuntime(O::InfiniteTransferPEPS, χ::VectorSpace, alg::VUMPS) Ni, Nj = size(O) rtup = VUMPSRuntime(O, χ) - alg.verbosity >= 2 && println("===== vumps random initial $(Ni)×$(Nj) vumps χ = $(χ) up ↑ environment =====") + alg.verbosity >= 2 && @info "VUMPS init: cell=($(Ni)×$(Nj)) χ = $(χ) up(↑) environment" if alg.ifupdown Od = down_itp(O) rtdown = VUMPSRuntime(Od, χ) - alg.verbosity >= 2 && println("===== vumps random initial $(Ni)×$(Nj) vumps χ = $(χ) down ↓ environment =====") + alg.verbosity >= 2 && @info "VUMPS init: cell=($(Ni)×$(Nj)) χ = $(χ) down(↓) environment" return rtup, rtdown else @@ -122,15 +124,16 @@ function VUMPSRuntime(O::InfiniteTransferPEPS, χ::VectorSpace, alg::VUMPS) end function vumps_itr(O::InfiniteTransferPEPS, rt::VUMPSRuntime, alg::VUMPS) + t = time() for i in 1:alg.maxiter rt, err = vumps_step(O, rt, alg) - alg.verbosity >= 3 && println(@sprintf("vumps@step: i = %4d\terr = %.3e\t", i, err)) + alg.verbosity >= 3 && @info @sprintf("VUMPS@step: %4d\terr = %.3e\ttime = %.3f sec", i, err, time()-t) if err < alg.tol - alg.verbosity >= 2 && println(@sprintf("===== vumps@step: i = %4d\terr = %.3e\t coveraged =====", i, err)) + alg.verbosity >= 2 && @info @sprintf("VUMPS conv@step: %4d\terr = %.3e\ttime = %.3f sec", i, err, time()-t) break end if i == alg.maxiter - alg.verbosity >= 2 && println(@sprintf("===== vumps@step: i = %4d\terr = %.3e\t not coveraged =====", i, err)) + alg.verbosity >= 2 && @warn @sprintf("VUMPS cancel@step: %4d\terr = %.3e\ttime = %.3f sec", i, err, time()-t) end end return rt diff --git a/src/environments/vumps_environments.jl b/src/environments/vumps_environments.jl index 8677f468..726210f2 100644 --- a/src/environments/vumps_environments.jl +++ b/src/environments/vumps_environments.jl @@ -11,7 +11,13 @@ end function InfiniteTransferPEPS(ipeps::InfinitePEPS) top = ipeps.A - bot = [A' for A in ipeps.A] + bot = adjoint.(ipeps.A) + return InfiniteTransferPEPS(top, bot) +end + +function InfiniteTransferPEPS(A::Matrix{<:AbstractTensorMap}) + top = A + bot = adjoint.(A) return InfiniteTransferPEPS(top, bot) end @@ -263,12 +269,13 @@ function rightenv!(ARu::Matrix{<:AbstractTensorMap}, ARd::Matrix{<:AbstractTensorMap}, O::InfiniteTransferPEPS, FR::Matrix{<:AbstractTensorMap}; - ifobs=false, verbosity = Defaults.verbosity, kwargs...) + ifobs=false, ifinline=false,verbosity = Defaults.verbosity, kwargs...) Ni, Nj = size(O) λR = zeros(eltype(O), Ni) for i in 1:Ni ir = ifobs ? Ni + 1 - i : mod1(i + 1, Ni) + ifinline && (ir = i) λRs, FR1s, info = eigsolve(FR -> FRmap(FR, ARu[i,:], ARd[ir,:], O.top[i,:], O.bot[i,:]), FR[i,:], 1, :LM; maxiter=100, ishermitian = false, kwargs...) verbosity >= 1 && info.converged == 0 && @warn "rightenv not converged" @@ -304,7 +311,7 @@ function rightCenv!(ARu::Matrix{<:AbstractTensorMap}, Ni, Nj = size(ARu) λR = zeros(eltype(ARu[1]), Ni) for i in 1:Ni - ir = ifobs ? Ni + 1 - i : mod1(i + 1, Ni) + ir = ifobs ? mod1(Ni - i + 2, Ni) : i λRs, R1s, info = eigsolve(R -> Rmap(R, ARu[i,:], ARd[ir,:]), R[i,:], 1, :LM; maxiter=100, ishermitian = false, kwargs...) verbosity >= 1 && info.converged == 0 && @warn "rightenv not converged" diff --git a/test/vumps/vumps.jl b/test/vumps/vumps.jl index a5d3040d..4b37f78e 100644 --- a/test/vumps/vumps.jl +++ b/test/vumps/vumps.jl @@ -22,20 +22,37 @@ end end @testset "vumps one side runtime for unitcell $Ni x $Nj" for Ni in 1:1, Nj in 1:1, (d, D, χ) in zip(ds, Ds, χs) + Random.seed!(100) + ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) + ipeps = symmetrize!(ipeps, RotateReflect()) + + alg = PEPSKit.VUMPS(maxiter=100, verbosity=2, ifupdown=false) + + itp = InfiniteTransferPEPS(ipeps) + env = leading_boundary(itp, VUMPSRuntime(itp, χ, alg), alg) + @test env isa VUMPSEnv + + Z = abs(norm(ipeps, env)) + + ctm = MPSKit.leading_boundary(CTMRGEnv(ipeps, χ), ipeps, CTMRG(; verbosity=2)) + Z′ = abs(norm(ipeps, ctm))^(1/Ni/Nj) + + @test Z ≈ Z′ rtol = 1e-12 +end + +@testset "vumps two side runtime for unitcell $Ni x $Nj" for Ni in 1:3, Nj in 1:3, (d, D, χ) in zip(ds, Ds, χs) Random.seed!(42) ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) - alg = PEPSKit.VUMPS(maxiter=10, verbosity=2, ifupdown=true) + alg = PEPSKit.VUMPS(maxiter=100, verbosity=2, ifupdown=true) itp = InfiniteTransferPEPS(ipeps) env = leading_boundary(itp, VUMPSRuntime(itp, χ, alg), alg) - # @test env isa VUMPSEnv + @test env isa VUMPSEnv Z = abs(norm(ipeps, env)) - @show Z ctm = MPSKit.leading_boundary(CTMRGEnv(ipeps, χ), ipeps, CTMRG(; verbosity=2)) Z′ = abs(norm(ipeps, ctm))^(1/Ni/Nj) - @show Z′ - # @test Z ≈ Z′ rtol = 1e-2 + @test Z ≈ Z′ rtol = 1e-8 end \ No newline at end of file diff --git a/test/vumps/vumps_environment.jl b/test/vumps/vumps_environment.jl index 57845585..7504f226 100644 --- a/test/vumps/vumps_environment.jl +++ b/test/vumps/vumps_environment.jl @@ -14,17 +14,6 @@ begin "test utility" χs = [ℂ^4] end -@testset begin - A = TensorMap(rand, ComplexF64, ℂ^2 * ℂ^3, ℂ^4) - # @show storagetype(typeof(A)) - # # @tensor C = conj(A[1 2;3]) * A[1 2;3] - @show space(A, 1) space(A, 2) space(A, 3) - @show space(A', 1) space(A', 2) space(A', 3) - @tensor C = A'[3; 1 2] * A[1 2;3] - @show eltype(A) - # @show sqrt(C) norm(A) -end - @testset "InfiniteTransferPEPS for unitcell $Ni x $Nj" for Ni in 1:2, Nj in 1:2, (d, D, χ) in zip(ds, Ds, χs) Random.seed!(42) ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) @@ -152,7 +141,7 @@ end for j in 1:Nj jr = mod1(j + 1, Nj) @test λAC[j] * AC[:,j] ≈ ACmap(AC[:,j], FL[:,j], FR[:,j], itp.top[:,j], itp.bot[:,j]) rtol = 1e-12 - @test λC[j] * C[:,j] ≈ Cmap( C[:,j], FL[:,jr], FR[:,j]) rtol = 1e-12 + @test λC[j] * C[:,j] ≈ Cmap( C[:,j], FL[:,jr], FR[:,j]) rtol = 1e-10 end end @@ -183,7 +172,7 @@ end @test errR isa Real end -@testset "ACenv and Cenv for unitcell $Ni x $Nj" for Ni in 1:3, Nj in 1:3, (d, D, χ) in zip(ds, Ds, χs), ifobs in [true, false] +@testset "rightCenv for unitcell $Ni x $Nj" for Ni in 1:3, Nj in 1:3, (d, D, χ) in zip(ds, Ds, χs), ifobs in [true, false] Random.seed!(42) ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) @@ -195,7 +184,7 @@ end @test all(i -> space(i) == (χ ← χ), R) for i in 1:Ni - ir = ifobs ? Ni + 1 - i : mod1(i + 1, Ni) + ir = ifobs ? mod1(Ni + 2 - i, Ni) : i @test λR[i] * R[i,:] ≈ Rmap(R[i,:], AR[i,:], adjoint.(AR)[ir,:]) rtol = 1e-12 end end \ No newline at end of file From 7152ba92f6f5ccdd4953685ce9c52e48634b66aa Mon Sep 17 00:00:00 2001 From: XingyuZhang2018 <864129714@qq.com> Date: Fri, 25 Oct 2024 22:10:21 +0200 Subject: [PATCH 16/25] AD for leftenv and rightenv --- src/environments/vumps_environments.jl | 34 +++---- test/vumps/gradparts.jl | 125 ++++++++++--------------- 2 files changed, 62 insertions(+), 97 deletions(-) diff --git a/src/environments/vumps_environments.jl b/src/environments/vumps_environments.jl index 726210f2..9520d14a 100644 --- a/src/environments/vumps_environments.jl +++ b/src/environments/vumps_environments.jl @@ -222,28 +222,23 @@ FLᵢⱼ ─ Oᵢⱼ ── = λLᵢⱼ FLᵢⱼ₊₁ └── ALdᵢᵣⱼ ─ └── ``` """ -leftenv(ALu::Matrix{<:AbstractTensorMap}, +function leftenv(ALu::Matrix{<:AbstractTensorMap}, ALd::Matrix{<:AbstractTensorMap}, O::InfiniteTransferPEPS, FL::Matrix{<:AbstractTensorMap} = initial_FL(ALu,O); - kwargs...) = leftenv!(ALu, ALd, O, deepcopy(FL); kwargs...) - -function leftenv!(ALu::Matrix{<:AbstractTensorMap}, - ALd::Matrix{<:AbstractTensorMap}, - O::InfiniteTransferPEPS, - FL::Matrix{<:AbstractTensorMap}; - ifobs=false, verbosity = Defaults.verbosity, kwargs...) + ifobs=false, verbosity = Defaults.verbosity, kwargs...) Ni, Nj = size(O) - λL = zeros(eltype(O), Ni) + λL = Zygote.Buffer(zeros(eltype(O), Ni)) + FL′ = Zygote.Buffer(FL) for i in 1:Ni ir = ifobs ? Ni + 1 - i : mod1(i + 1, Ni) λLs, FL1s, info = eigsolve(FLi -> FLmap(FLi, ALu[i,:], ALd[ir,:], O.top[i,:], O.bot[i,:]), FL[i,:], 1, :LM; maxiter=100, ishermitian = false, kwargs...) verbosity >= 1 && info.converged == 0 && @warn "leftenv not converged" - λL[i], FL[i,:] = selectpos(λLs, FL1s, Nj) + λL[i], FL′[i,:] = selectpos(λLs, FL1s, Nj) end - return λL, FL + return copy(λL), copy(FL′) end """ @@ -259,29 +254,24 @@ of AR - M - conj(AR) contracted along the physical dimension. ── ARdᵢᵣⱼ ──┘ ──┘ ``` """ -rightenv(ARu::Matrix{<:AbstractTensorMap}, +function rightenv(ARu::Matrix{<:AbstractTensorMap}, ARd::Matrix{<:AbstractTensorMap}, O::InfiniteTransferPEPS, FR::Matrix{<:AbstractTensorMap} = initial_FR(ARu,O); - kwargs...) = rightenv!(ARu, ARd, O, deepcopy(FR); kwargs...) - -function rightenv!(ARu::Matrix{<:AbstractTensorMap}, - ARd::Matrix{<:AbstractTensorMap}, - O::InfiniteTransferPEPS, - FR::Matrix{<:AbstractTensorMap}; - ifobs=false, ifinline=false,verbosity = Defaults.verbosity, kwargs...) + ifobs=false, ifinline=false,verbosity = Defaults.verbosity, kwargs...) Ni, Nj = size(O) - λR = zeros(eltype(O), Ni) + λR = Zygote.Buffer(zeros(eltype(O), Ni)) + FR′ = Zygote.Buffer(FR) for i in 1:Ni ir = ifobs ? Ni + 1 - i : mod1(i + 1, Ni) ifinline && (ir = i) λRs, FR1s, info = eigsolve(FR -> FRmap(FR, ARu[i,:], ARd[ir,:], O.top[i,:], O.bot[i,:]), FR[i,:], 1, :LM; maxiter=100, ishermitian = false, kwargs...) verbosity >= 1 && info.converged == 0 && @warn "rightenv not converged" - λR[i], FR[i,:] = selectpos(λRs, FR1s, Nj) + λR[i], FR′[i,:] = selectpos(λRs, FR1s, Nj) end - return λR, FR + return copy(λR), copy(FR′) end """ diff --git a/test/vumps/gradparts.jl b/test/vumps/gradparts.jl index 37b818eb..78912dd1 100644 --- a/test/vumps/gradparts.jl +++ b/test/vumps/gradparts.jl @@ -1,107 +1,82 @@ using Test using Random using PEPSKit -using MPSKit -using MPSKit: ∂∂AC, ∂∂C, MPSMultiline, Multiline, fixedpoint, updatetol -using PEPSKit: vumps_iter, TransferPEPSMultiline -using KrylovKit -using Zygote +using PEPSKit: initial_A, left_canonical, right_canonical, leftenv, rightenv using TensorKit -using ChainRulesCore -const vumps_alg = VUMPS(; maxiter=20, alg_eigsolve=MPSKit.Defaults.alg_eigsolve(; ishermitian=false)) - -function num_grad(f, K::Number; δ::Real=1e-5) - if eltype(K) == ComplexF64 - (f(K + δ / 2) - f(K - δ / 2)) / δ + - (f(K + δ / 2 * 1.0im) - f(K - δ / 2 * 1.0im)) / δ * 1.0im - else - (f(K + δ / 2) - f(K - δ / 2)) / δ - end -end - -function num_grad(f, a; δ::Real=1e-5) - b = copy(a) - df = map(CartesianIndices(size())) do i - foo = x -> (ac = copy(b); ac[i] = x; f(ac)) - num_grad(foo, b[i], δ=δ) +using Zygote +using LinearAlgebra + +begin "test utility" + ds = [ℂ^2] + Ds = [ℂ^2] + χs = [ℂ^4] + + function num_grad(f, K::Number; δ::Real=1e-5) + if eltype(K) == ComplexF64 + (f(K + δ / 2) - f(K - δ / 2)) / δ + + (f(K + δ / 2 * 1.0im) - f(K - δ / 2 * 1.0im)) / δ * 1.0im + else + (f(K + δ / 2) - f(K - δ / 2)) / δ + end end - return df end -@testset "InfinitePEPS" begin +@testset "InfinitePEPS for unitcell $Ni x $Nj" for Ni in 1:2, Nj in 1:2, (d, D, χ) in zip(ds, Ds, χs) Random.seed!(42) - psi = InfinitePEPS(ℂ^2, ℂ^2) + ipepes = InfinitePEPS(d, D; unitcell=(Ni, Nj)) function f(β) - psir = β * psi - norm(psir) + norm(β * ipepes) end - # @show typeof(psi.A) psi.A @test Zygote.gradient(f, 1.0)[1] ≈ num_grad(f, 1.0) end -@testset "InfiniteTransferPEPS" begin +@testset "InfiniteTransferPEPS for unitcell $Ni x $Nj" for Ni in 1:2, Nj in 1:2, (d, D, χ) in zip(ds, Ds, χs) Random.seed!(42) - psi = InfinitePEPS(ℂ^2, ℂ^2) + ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) function f(β) - psir = β * psi - T = PEPSKit.InfiniteTransferPEPS(psir, 1, 1) - real(dot(T.top, T.bot)) + T = PEPSKit.InfiniteTransferPEPS(β * ipeps) + norm(T.bot .* T.top) end @test Zygote.gradient(f, 1.0)[1] ≈ num_grad(f, 1.0) end -@testset "dominant eigensolve" begin - Random.seed!(42) - alg_eigsolve = updatetol(vumps_alg.alg_eigsolve, 1, 1) - psi = InfinitePEPS(ℂ^2, ℂ^2) - psi = symmetrize!(psi, RotateReflect()) +@testset "leftenv and rightenv for unitcell $Ni x $Nj" for Ni in 1:2, Nj in 1:2, (d, D, χ) in zip(ds, Ds, χs), ifobs in [true, false] + Random.seed!(50) + ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) - T = PEPSKit.InfiniteTransferPEPS(psi, 1, 1) - mps = PEPSKit.initializeMPS(T, [ℂ^3]) - envs=environments(mps, T) - - mps, T = convert(MPSMultiline, mps), Multiline([T]) + itp = InfiniteTransferPEPS(ipeps) + A = initial_A(itp, χ) + AL, L, λ = left_canonical(A) + R, AR, λ = right_canonical(A) - ac = RecursiveVec(mps.AC[:, 1]) - c = RecursiveVec(mps.CR[:, 1]) + λL, FL = leftenv(AL, adjoint.(AL), itp; ifobs) + λR, FR = rightenv(AR, adjoint.(AR), itp; ifobs) - S1 = TensorMap(randn, ComplexF64, ℂ^3*ℂ^2*(ℂ^2)'*(ℂ^3)'← ℂ^3*ℂ^2*(ℂ^2)'*(ℂ^3)') - S2 = TensorMap(randn, ComplexF64, ℂ^3*(ℂ^3)'← ℂ^3*(ℂ^3)') + S1 = TensorMap(rand, ComplexF64, χ*D'*D*χ' ← χ*D'*D*χ') + S2 = TensorMap(rand, ComplexF64, χ*D*D'*χ' ← χ*D*D'*χ') function foo1(β) - psi = β * psi - T = PEPSKit.InfiniteTransferPEPS(psi, 1, 1) - T = MPSKit.Multiline([T]) + ipeps = β * ipeps + itp = InfiniteTransferPEPS(ipeps) - H_AC = MPSKit.∂∂AC(1, mps, T, envs) - - _, ac′ = MPSKit.fixedpoint(H_AC, ac, :LM, alg_eigsolve) + _, FL = leftenv(AL, adjoint.(AL), itp; ifobs) - AC = ac′.vecs[1] - @tensor d = conj(AC[1 2 3 4]) * S1[1 2 3 4; 5 6 7 8] * AC[5 6 7 8] - norm(d) + tol = [@tensor d = conj(FL[1 2 3 4]) * S1[1 2 3 4; 5 6 7 8] * FL[5 6 7 8] for FL in FL] + return norm(tol) end + @test Zygote.gradient(foo1, 1.0)[1] ≈ num_grad(foo1, 1.0) atol = 1e-8 + + function foo2(β) + ipeps = β * ipeps + itp = InfiniteTransferPEPS(ipeps) - @test Zygote.gradient(foo1, 1.0)[1] ≈ num_grad(foo1, 1.0) atol = 1e-4 - - # function foo2(β) - # psi = β * psi - # T = PEPSKit.InfiniteTransferPEPS(psi, 1, 1) - # T = MPSKit.Multiline([T]) - - # H_C = ∂∂C(1, mps, T, envs) - - # _, c′ = MPSKit.fixedpoint(H_C, c, :LM, alg_eigsolve) - # C = c′.vecs[1] - # # @show space(C) - # # norm(C) - # @tensor d = conj(C[1 2]) * S2[1 2; 3 4] * C[3 4] - # norm(d) - # end - - # @show foo2(1.0) num_grad(foo2, 1.0) - # @test Zygote.gradient(foo2, 1.0)[1] ≈ num_grad(foo2, 1.0) atol = 1e-4 + _, FR = rightenv(AR, adjoint.(AR), itp; ifobs) + + tol = [@tensor d = conj(FR[1 2 3 4]) * S2[1 2 3 4; 5 6 7 8] * FR[5 6 7 8] for FR in FR] + return norm(tol) + end + @test Zygote.gradient(foo2, 1.0)[1] ≈ num_grad(foo2, 1.0) atol = 1e-8 end @testset "(1, 1) ctm PEPS" begin From d7e146cb7d21bca2312cabf60e1d7d8cf0ddb8e2 Mon Sep 17 00:00:00 2001 From: XingyuZhang2018 <864129714@qq.com> Date: Sat, 26 Oct 2024 13:22:50 +0200 Subject: [PATCH 17/25] finish ad one unit cell vumps --- src/algorithms/vumps/vumps.jl | 27 ++-- src/environments/vumps_environments.jl | 63 ++++----- src/utility/symmetrization.jl | 10 ++ test/vumps/gradparts.jl | 189 ++++++++++++++----------- test/vumps/vumps_environment.jl | 2 +- 5 files changed, 157 insertions(+), 134 deletions(-) diff --git a/src/algorithms/vumps/vumps.jl b/src/algorithms/vumps/vumps.jl index dfd945ed..bdd82ee9 100644 --- a/src/algorithms/vumps/vumps.jl +++ b/src/algorithms/vumps/vumps.jl @@ -83,6 +83,7 @@ struct VUMPSRuntime{T<:Number, S<:IndexSpace, end end +@non_differentiable VUMPSRuntime(O::InfiniteTransferPEPS, χ::VectorSpace) function VUMPSRuntime(O::InfiniteTransferPEPS, χ::VectorSpace) A = initial_A(O, χ) AL, L, _ = left_canonical(A) @@ -106,16 +107,17 @@ function down_itp(O) return InfiniteTransferPEPS(copy(ipepsd)) end +@non_differentiable VUMPSRuntime(O::InfiniteTransferPEPS, χ::VectorSpace, alg::VUMPS) function VUMPSRuntime(O::InfiniteTransferPEPS, χ::VectorSpace, alg::VUMPS) Ni, Nj = size(O) rtup = VUMPSRuntime(O, χ) - alg.verbosity >= 2 && @info "VUMPS init: cell=($(Ni)×$(Nj)) χ = $(χ) up(↑) environment" + alg.verbosity >= 2 && Zygote.@ignore @info "VUMPS init: cell=($(Ni)×$(Nj)) χ = $(χ) up(↑) environment" if alg.ifupdown Od = down_itp(O) rtdown = VUMPSRuntime(Od, χ) - alg.verbosity >= 2 && @info "VUMPS init: cell=($(Ni)×$(Nj)) χ = $(χ) down(↓) environment" + alg.verbosity >= 2 && Zygote.@ignore @info "VUMPS init: cell=($(Ni)×$(Nj)) χ = $(χ) down(↓) environment" return rtup, rtdown else @@ -124,16 +126,16 @@ function VUMPSRuntime(O::InfiniteTransferPEPS, χ::VectorSpace, alg::VUMPS) end function vumps_itr(O::InfiniteTransferPEPS, rt::VUMPSRuntime, alg::VUMPS) - t = time() + t = Zygote.@ignore time() for i in 1:alg.maxiter rt, err = vumps_step(O, rt, alg) - alg.verbosity >= 3 && @info @sprintf("VUMPS@step: %4d\terr = %.3e\ttime = %.3f sec", i, err, time()-t) + alg.verbosity >= 3 && Zygote.@ignore @info @sprintf("VUMPS@step: %4d\terr = %.3e\ttime = %.3f sec", i, err, time()-t) if err < alg.tol - alg.verbosity >= 2 && @info @sprintf("VUMPS conv@step: %4d\terr = %.3e\ttime = %.3f sec", i, err, time()-t) + alg.verbosity >= 2 && Zygote.@ignore @info @sprintf("VUMPS conv@step: %4d\terr = %.3e\ttime = %.3f sec", i, err, time()-t) break end if i == alg.maxiter - alg.verbosity >= 2 && @warn @sprintf("VUMPS cancel@step: %4d\terr = %.3e\ttime = %.3f sec", i, err, time()-t) + alg.verbosity >= 2 && Zygote.@ignore @warn @sprintf("VUMPS cancel@step: %4d\terr = %.3e\ttime = %.3f sec", i, err, time()-t) end end return rt @@ -169,15 +171,16 @@ function leading_boundary(O::InfiniteTransferPEPS, rt::Tuple, alg::VUMPS) end function vumps_step(O::InfiniteTransferPEPS, rt::VUMPSRuntime, alg::VUMPS) + verbosity = alg.verbosity @unpack AL, C, AR, FL, FR = rt AC = Zygote.@ignore ALCtoAC(AL,C) - _, ACp = ACenv(AC, FL, FR, O) - _, Cp = Cenv( C, FL, FR) + _, ACp = ACenv(AC, FL, FR, O; verbosity) + _, Cp = Cenv( C, FL, FR; verbosity) ALp, ARp, _, _ = ACCtoALAR(ACp, Cp) - _, FL = leftenv(AL, adjoint.(ALp), O, FL) - _, FR = rightenv(AR, adjoint.(ARp), O, FR) - _, ACp = ACenv(ACp, FL, FR, O) - _, Cp = Cenv( Cp, FL, FR) + _, FL = leftenv(AL, adjoint.(ALp), O, FL; verbosity) + _, FR = rightenv(AR, adjoint.(ARp), O, FR; verbosity) + _, ACp = ACenv(ACp, FL, FR, O; verbosity) + _, Cp = Cenv( Cp, FL, FR; verbosity) ALp, ARp, errL, errR = ACCtoALAR(ACp, Cp) err = errL + errR alg.verbosity >= 4 && err > 1e-8 && println("errL=$errL, errR=$errR") diff --git a/src/environments/vumps_environments.jl b/src/environments/vumps_environments.jl index 9520d14a..b712a67c 100644 --- a/src/environments/vumps_environments.jl +++ b/src/environments/vumps_environments.jl @@ -288,26 +288,22 @@ of AR - M - conj(AR) contracted along the physical dimension. ── ARdᵢᵣⱼ ──┘ ──┘ ``` """ -rightCenv(ARu::Matrix{<:AbstractTensorMap}, - ARd::Matrix{<:AbstractTensorMap}, - R::Matrix{<:AbstractTensorMap} = initial_C(ARu); - kwargs...) = rightCenv!(ARu, ARd, deepcopy(R); kwargs...) - -function rightCenv!(ARu::Matrix{<:AbstractTensorMap}, - ARd::Matrix{<:AbstractTensorMap}, - R::Matrix{<:AbstractTensorMap}; - ifobs=false, verbosity = Defaults.verbosity, kwargs...) +function rightCenv(ARu::Matrix{<:AbstractTensorMap}, + ARd::Matrix{<:AbstractTensorMap}, + R::Matrix{<:AbstractTensorMap} = initial_C(ARu); + ifobs=false, verbosity = Defaults.verbosity, kwargs...) Ni, Nj = size(ARu) - λR = zeros(eltype(ARu[1]), Ni) + λR = Zygote.Buffer(zeros(eltype(ARu[1]), Ni)) + R′ = Zygote.Buffer(R) for i in 1:Ni ir = ifobs ? mod1(Ni - i + 2, Ni) : i λRs, R1s, info = eigsolve(R -> Rmap(R, ARu[i,:], ARd[ir,:]), R[i,:], 1, :LM; maxiter=100, ishermitian = false, kwargs...) verbosity >= 1 && info.converged == 0 && @warn "rightenv not converged" - λR[i], R[i,:] = selectpos(λRs, R1s, Nj) + λR[i], R′[i,:] = selectpos(λRs, R1s, Nj) end - return λR, R + return copy(λR), copy(R′) end """ @@ -322,27 +318,22 @@ FLᵢⱼ ─── Oᵢⱼ ───── FRᵢⱼ │ │ │ │ │ ``` """ -ACenv(AC::Matrix{<:AbstractTensorMap}, - FL::Matrix{<:AbstractTensorMap}, - FR::Matrix{<:AbstractTensorMap}, - O::InfiniteTransferPEPS; - kwargs...) = ACenv!(deepcopy(AC), FL, FR, O; kwargs...) - -function ACenv!(AC::Matrix{<:AbstractTensorMap}, - FL::Matrix{<:AbstractTensorMap}, - FR::Matrix{<:AbstractTensorMap}, - O::InfiniteTransferPEPS; - verbosity = Defaults.verbosity, kwargs...) +function ACenv(AC::Matrix{<:AbstractTensorMap}, + FL::Matrix{<:AbstractTensorMap}, + FR::Matrix{<:AbstractTensorMap}, + O::InfiniteTransferPEPS; + verbosity = Defaults.verbosity, kwargs...) Ni, Nj = size(O) - λAC = zeros(eltype(O),Nj) + λAC = Zygote.Buffer(zeros(eltype(O),Nj)) + AC′ = Zygote.Buffer(AC) for j in 1:Nj λACs, ACs, info = eigsolve(AC -> ACmap(AC, FL[:,j], FR[:,j], O.top[:,j], O.bot[:,j]), AC[:,j], 1, :LM; maxiter=100, ishermitian = false, kwargs...) verbosity >= 1 && info.converged == 0 && @warn "ACenv Not converged" - λAC[j], AC[:,j] = selectpos(λACs, ACs, Ni) + λAC[j], AC′[:,j] = selectpos(λACs, ACs, Ni) end - return λAC, AC + return copy(λAC), copy(AC′) end """ @@ -360,26 +351,22 @@ FLᵢⱼ₊₁ ──── FRᵢⱼ │ │ │ │ ``` """ -Cenv(C::Matrix{<:AbstractTensorMap}, - FL::Matrix{<:AbstractTensorMap}, - FR::Matrix{<:AbstractTensorMap}; - kwargs...) = Cenv!(copy(C), FL, FR; kwargs...) - -function Cenv!(C::Matrix{<:AbstractTensorMap}, - FL::Matrix{<:AbstractTensorMap}, - FR::Matrix{<:AbstractTensorMap}; - verbosity = Defaults.verbosity, kwargs...) +function Cenv(C::Matrix{<:AbstractTensorMap}, + FL::Matrix{<:AbstractTensorMap}, + FR::Matrix{<:AbstractTensorMap}; + verbosity = Defaults.verbosity, kwargs...) Ni, Nj = size(C) - λC = zeros(eltype(C[1]), Nj) + λC = Zygote.Buffer(zeros(eltype(C[1]), Nj)) + C′ = Zygote.Buffer(C) for j in 1:Nj jr = mod1(j + 1, Nj) λCs, Cs, info = eigsolve(C -> Cmap(C, FL[:,jr], FR[:,j]), C[:,j], 1, :LM; maxiter=100, ishermitian = false, kwargs...) verbosity >= 1 && info.converged == 0 && @warn "Cenv Not converged" - λC[j], C[:,j] = selectpos(λCs, Cs, Ni) + λC[j], C′[:,j] = selectpos(λCs, Cs, Ni) end - return λC, C + return copy(λC), copy(C′) end function env_norm(F::Matrix{<:AbstractTensorMap}) diff --git a/src/utility/symmetrization.jl b/src/utility/symmetrization.jl index 5bec6a96..88f2ad15 100644 --- a/src/utility/symmetrization.jl +++ b/src/utility/symmetrization.jl @@ -68,8 +68,18 @@ function _fit_spaces( end return y end + +function ChainRulesCore.rrule(::typeof(_fit_spaces), y::AbstractTensorMap, x::AbstractTensorMap) + function pullback(Δ) + return _fit_spaces(Δ, y) + end + return _fit_spaces(y, x), pullback +end + _fit_spaces(y::InfinitePEPS, x::InfinitePEPS) = InfinitePEPS(map(_fit_spaces, y.A, x.A)) + + function herm_depth_inv(x::Union{PEPSTensor,PEPOTensor}) return 0.5 * (x + _fit_spaces(herm_depth(x), x)) end diff --git a/test/vumps/gradparts.jl b/test/vumps/gradparts.jl index 78912dd1..7fa77e6a 100644 --- a/test/vumps/gradparts.jl +++ b/test/vumps/gradparts.jl @@ -1,7 +1,8 @@ using Test using Random using PEPSKit -using PEPSKit: initial_A, left_canonical, right_canonical, leftenv, rightenv +using PEPSKit: initial_A, left_canonical, right_canonical, leftenv, rightenv, ACenv, Cenv, LRtoC, ALCtoAC, ACCtoALAR +using MPSKit using TensorKit using Zygote using LinearAlgebra @@ -9,7 +10,7 @@ using LinearAlgebra begin "test utility" ds = [ℂ^2] Ds = [ℂ^2] - χs = [ℂ^4] + χs = [ℂ^5] function num_grad(f, K::Number; δ::Real=1e-5) if eltype(K) == ComplexF64 @@ -62,7 +63,7 @@ end _, FL = leftenv(AL, adjoint.(AL), itp; ifobs) - tol = [@tensor d = conj(FL[1 2 3 4]) * S1[1 2 3 4; 5 6 7 8] * FL[5 6 7 8] for FL in FL] + tol = [(@tensor conj(FL[1 2 3 4]) * S1[1 2 3 4; 5 6 7 8] * FL[5 6 7 8]) / dot(FL, FL) for FL in FL] return norm(tol) end @test Zygote.gradient(foo1, 1.0)[1] ≈ num_grad(foo1, 1.0) atol = 1e-8 @@ -73,97 +74,119 @@ end _, FR = rightenv(AR, adjoint.(AR), itp; ifobs) - tol = [@tensor d = conj(FR[1 2 3 4]) * S2[1 2 3 4; 5 6 7 8] * FR[5 6 7 8] for FR in FR] + tol = [(@tensor conj(FR[1 2 3 4]) * S2[1 2 3 4; 5 6 7 8] * FR[5 6 7 8]) / dot(FR, FR) for FR in FR] return norm(tol) end @test Zygote.gradient(foo2, 1.0)[1] ≈ num_grad(foo2, 1.0) atol = 1e-8 end -@testset "(1, 1) ctm PEPS" begin - psi = InfinitePEPS(ComplexSpace(2), ComplexSpace(2)) - ctm = leading_boundary(CTMRGEnv(psi, ComplexSpace(20)), psi, CTMRG(; verbosity=1)) - - boundary_algs = [ - CTMRG(; - tol=1e-10, - verbosity=0, - ctmrgscheme=:simultaneous, - svd_alg=SVDAdjoint(; fwd_alg=TensorKit.SVD(), rrule_alg=GMRES(; tol=1e-10)), - ), - CTMRG(; tol=1e-10, verbosity=0, ctmrgscheme=:sequential), - ] - - gradtol = 1e-4 - - gradmodes = [ - [ - nothing, - GeomSum(; tol=gradtol, iterscheme=:fixed), - GeomSum(; tol=gradtol, iterscheme=:diffgauge), - ManualIter(; tol=gradtol, iterscheme=:fixed), - ManualIter(; tol=gradtol, iterscheme=:diffgauge), - LinSolver(; solver=KrylovKit.GMRES(; tol=gradtol), iterscheme=:fixed), - LinSolver(; solver=KrylovKit.GMRES(; tol=gradtol), iterscheme=:diffgauge), - ], - [ - nothing, - GeomSum(; tol=gradtol, iterscheme=:diffgauge), - ManualIter(; tol=gradtol, iterscheme=:diffgauge), - LinSolver(; solver=KrylovKit.GMRES(; tol=gradtol), iterscheme=:diffgauge), - ], - ] - - boundary_alg = boundary_algs[1] - function foo2(psi) - # psi = x * psi - - ctm = PEPSKit.hook_pullback( - leading_boundary, ctm, psi, boundary_alg; alg_rrule = gradmodes[1][2] - ) - abs(norm(psi, ctm)) +@testset "ACenv and Cenv for unitcell $Ni x $Nj" for Ni in 1:2, Nj in 1:2, (d, D, χ) in zip(ds, Ds, χs) + Random.seed!(50) + ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) + + itp = InfiniteTransferPEPS(ipeps) + A = initial_A(itp, χ) + AL, L, λ = left_canonical(A) + R, AR, λ = right_canonical(A) + + _, FL = leftenv(AL, adjoint.(AL), itp) + _, FR = rightenv(AR, adjoint.(AR), itp) + C = LRtoC(L, R) + AC = ALCtoAC(AL, C) + + S1 = TensorMap(randn, ComplexF64, χ*D*D'*χ' ← χ*D*D'*χ') + S2 = TensorMap(randn, ComplexF64, χ*χ' ← χ*χ') + + function foo1(β) + ipeps = β * ipeps + itp = InfiniteTransferPEPS(ipeps) + + _, AC = ACenv(AC, FL, FR, itp) + + tol = [(@tensor conj(AC[1 2 3 4]) * S1[1 2 3 4; 5 6 7 8] * AC[5 6 7 8]) / dot(AC, AC) for AC in AC] + return norm(tol) end + @test Zygote.gradient(foo1, 1.0)[1] ≈ num_grad(foo1, 1.0) atol = 1e-8 - function foo3(psi) - # psi = x * psi - - ctm = PEPSKit.hook_pullback( - leading_boundary, ctm, psi, boundary_alg; alg_rrule = gradmodes[1][3] - ) - abs(norm(psi, ctm)) + function foo2(β) + _, C = Cenv(C, β*FL, β*FR) + + tol = [(@tensor d = conj(C[1 2]) * S2[1 2; 3 4] * C[3 4]) / dot(C, C) for C in C] + return norm(tol) end - # @show foo2(1.0) - # @show norm(Zygote.gradient(foo2, psi)[1] - Zygote.gradient(foo3, psi)[1]) - # @show num_grad(foo2, 1.0) - # @test N ≈ N´ atol = 1e-3 + @test Zygote.gradient(foo2, 1.0)[1] ≈ num_grad(foo2, 1.0) atol = 1e-8 end -@testset "(1, 1) vumps PEPS " begin +@testset "ACCtoALAR for unitcell $Ni x $Nj" for Ni in 1:2, Nj in 1:2, (d, D, χ) in zip(ds, Ds, χs) Random.seed!(42) - psi = InfinitePEPS(ComplexSpace(2), ComplexSpace(2)) - T = PEPSKit.InfiniteTransferPEPS(psi, 1, 1) - mps = PEPSKit.initializeMPS(T, [ComplexSpace(20)]) - - mps, envs, ϵ = leading_boundary(mps, T, vumps_alg) - # AC_0 = mps.AC[1] - # mps, envs, ϵ = vumps_iter(mps, T, vumps_alg, envs, ϵ) - # AC_1 = mps.AC[1] - # @show norm(AC_0 - AC_1) - @show abs(prod(expectation_value(mps, T))) - - # @show propertynames(envs) envs.dependency envs.lock - function foo1(psi) - T = PEPSKit.InfiniteTransferPEPS(psi, 1, 1) - # mps, envs, ϵ = vumps_iter(mps, T, vumps_alg, envs, ϵ) - mps = convert(MPSMultiline, mps) - T = convert(TransferPEPSMultiline, T) - ca = environments(mps, T) - return abs(prod(expectation_value(mps, T, ca))) + ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) + + itp = InfiniteTransferPEPS(ipeps) + A = initial_A(itp, χ) + AL, L, λ = left_canonical(A) + R, AR, λ = right_canonical(A) + + λL, FL = leftenv(AL, adjoint.(AL), itp) + λR, FR = rightenv(AR, adjoint.(AR), itp) + + C = LRtoC(L, R) + AC = ALCtoAC(AL, C) + + λAC, AC = ACenv(AC, FL, FR, itp) + λC, C = Cenv( C, FL, FR) + + S = TensorMap(rand, ComplexF64, χ*D*D'*χ' ← χ*D*D'*χ') + function foo1(β) + ipeps = β * ipeps + itp = InfiniteTransferPEPS(ipeps) + _, AC = ACenv(AC, FL, FR, itp) + AL, AR, _, _ = ACCtoALAR(AC, C) + tol1 = [(@tensor conj(AL[1 2 3 4]) * S[1 2 3 4; 5 6 7 8] * AL[5 6 7 8]) / dot(AL, AL) for AL in AL] + tol2 = [(@tensor conj(AR[1 2 3 4]) * S[1 2 3 4; 5 6 7 8] * AR[5 6 7 8]) / dot(AR, AR) for AR in AR] + return norm(tol1 + tol2) + end + @test Zygote.gradient(foo1, 1.0)[1] ≈ num_grad(foo1, 1.0) atol = 1e-8 +end + +@testset "ad vumps iPEPS one side for unitcell $Ni x $Nj" for Ni in 1:1, Nj in 1:1, (d, D, χ) in zip(ds, Ds, χs) + ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) + ipeps = symmetrize!(ipeps, RotateReflect()) + + alg = PEPSKit.VUMPS(maxiter=100, verbosity=2, ifupdown=false) + + function foo1(ipeps) + itp = InfiniteTransferPEPS(ipeps) + env = PEPSKit.leading_boundary(itp, VUMPSRuntime(itp, χ, alg), alg) + Z = abs(norm(ipeps, env)) + return Z + end + + function foo2(ipeps) + ctm = MPSKit.leading_boundary(CTMRGEnv(ipeps, χ), ipeps, CTMRG(; verbosity=2)) + Z = abs(norm(ipeps, ctm))^(1/Ni/Nj) + return Z end - @show foo1(psi) - @show Zygote.gradient(foo1, psi)[1] - # @show foo2(1.0) - # @show norm(Zygote.gradient(foo1, psi)[1] - Zygote.gradient(foo3, psi)[1]) - # @show num_grad(foo2, 1.0) - # @test N ≈ N´ atol = 1e-3 + @test norm(Zygote.gradient(foo1, ipeps)[1].A - Zygote.gradient(foo2, ipeps)[1].A) < 1e-8 +end + +@testset "ad vumps iPEPS two side for unitcell $Ni x $Nj" for Ni in 1:1, Nj in 1:1, (d, D, χ) in zip(ds, Ds, χs) + ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) + + alg = PEPSKit.VUMPS(maxiter=100, verbosity=2, ifupdown=true) + + function foo1(ipeps) + itp = InfiniteTransferPEPS(ipeps) + env = PEPSKit.leading_boundary(itp, VUMPSRuntime(itp, χ, alg), alg) + Z = abs(norm(ipeps, env)) + return Z + end + + function foo2(ipeps) + ctm = MPSKit.leading_boundary(CTMRGEnv(ipeps, χ), ipeps, CTMRG(; verbosity=2)) + Z = abs(norm(ipeps, ctm))^(1/Ni/Nj) + return Z + end + @show Zygote.gradient(foo1, ipeps)[1] + # @test norm(Zygote.gradient(foo1, ipeps)[1].A - Zygote.gradient(foo2, ipeps)[1].A) < 1e-8 end \ No newline at end of file diff --git a/test/vumps/vumps_environment.jl b/test/vumps/vumps_environment.jl index 7504f226..62f04d89 100644 --- a/test/vumps/vumps_environment.jl +++ b/test/vumps/vumps_environment.jl @@ -145,7 +145,7 @@ end end end -@testset "ACenv and Cenv for unitcell $Ni x $Nj" for Ni in 1:3, Nj in 1:3, (d, D, χ) in zip(ds, Ds, χs) +@testset "ACCtoALAR for unitcell $Ni x $Nj" for Ni in 1:3, Nj in 1:3, (d, D, χ) in zip(ds, Ds, χs) Random.seed!(42) ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) From 3c2620ff109807dcf6e0e51f23f014dde3c7aeeb Mon Sep 17 00:00:00 2001 From: XingyuZhang2018 <864129714@qq.com> Date: Sun, 27 Oct 2024 11:01:53 +0100 Subject: [PATCH 18/25] two side vumps ad is not stable --- src/algorithms/vumps/vumps.jl | 14 ++++++++++++-- src/utility/symmetrization.jl | 4 ++-- test/vumps/gradparts.jl | 30 ++++++++++++++++++++++++++---- 3 files changed, 40 insertions(+), 8 deletions(-) diff --git a/src/algorithms/vumps/vumps.jl b/src/algorithms/vumps/vumps.jl index bdd82ee9..817eca97 100644 --- a/src/algorithms/vumps/vumps.jl +++ b/src/algorithms/vumps/vumps.jl @@ -141,15 +141,19 @@ function vumps_itr(O::InfiniteTransferPEPS, rt::VUMPSRuntime, alg::VUMPS) return rt end +function vumps(O::InfiniteTransferPEPS, rt::VUMPSRuntime, alg::VUMPS) + return vumps_itr(O, rt, alg) +end + function leading_boundary(O::InfiniteTransferPEPS, rt::VUMPSRuntime, alg::VUMPS) - rt = vumps_itr(O, rt, alg) + rt = vumps(O, rt, alg) @unpack AL, AR, C, FL, FR = rt AC = ALCtoAC(AL, C) return VUMPSEnv(AC, AR, AC, AR, FL, FR, FL, FR) end -function leading_boundary(O::InfiniteTransferPEPS, rt::Tuple, alg::VUMPS) +function vumps(O::InfiniteTransferPEPS, rt::Tuple, alg::VUMPS) rtup, rtdown = rt rtup = vumps_itr(O, rtup, alg) @@ -157,6 +161,12 @@ function leading_boundary(O::InfiniteTransferPEPS, rt::Tuple, alg::VUMPS) Od = down_itp(O) rtdown = vumps_itr(Od, rtdown, alg) + return rtup, rtdown +end + +function leading_boundary(O::InfiniteTransferPEPS, rt::Tuple, alg::VUMPS) + rtup, rtdown = vumps(O, rt, alg) + ALu, ARu, Cu, FLu, FRu = rtup.AL, rtup.AR, rtup.C, rtup.FL, rtup.FR ACu = ALCtoAC(ALu, Cu) diff --git a/src/utility/symmetrization.jl b/src/utility/symmetrization.jl index 88f2ad15..8e3bc5f6 100644 --- a/src/utility/symmetrization.jl +++ b/src/utility/symmetrization.jl @@ -71,9 +71,9 @@ end function ChainRulesCore.rrule(::typeof(_fit_spaces), y::AbstractTensorMap, x::AbstractTensorMap) function pullback(Δ) - return _fit_spaces(Δ, y) + return NoTangent(), _fit_spaces(Δ, y), NoTangent() end - return _fit_spaces(y, x), pullback + return _fit_spaces(y, x), pullback end _fit_spaces(y::InfinitePEPS, x::InfinitePEPS) = InfinitePEPS(map(_fit_spaces, y.A, x.A)) diff --git a/test/vumps/gradparts.jl b/test/vumps/gradparts.jl index 7fa77e6a..3b1afcfa 100644 --- a/test/vumps/gradparts.jl +++ b/test/vumps/gradparts.jl @@ -149,14 +149,17 @@ end end @testset "ad vumps iPEPS one side for unitcell $Ni x $Nj" for Ni in 1:1, Nj in 1:1, (d, D, χ) in zip(ds, Ds, χs) + Random.seed!(50) ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) ipeps = symmetrize!(ipeps, RotateReflect()) alg = PEPSKit.VUMPS(maxiter=100, verbosity=2, ifupdown=false) + itp = InfiniteTransferPEPS(ipeps) + rt = PEPSKit.vumps(itp, VUMPSRuntime(itp, χ, alg), alg) function foo1(ipeps) itp = InfiniteTransferPEPS(ipeps) - env = PEPSKit.leading_boundary(itp, VUMPSRuntime(itp, χ, alg), alg) + env = PEPSKit.leading_boundary(itp, rt, alg) Z = abs(norm(ipeps, env)) return Z end @@ -170,14 +173,31 @@ end @test norm(Zygote.gradient(foo1, ipeps)[1].A - Zygote.gradient(foo2, ipeps)[1].A) < 1e-8 end +@testset "_fit_spaces" for (d, D, χ) in zip(ds, Ds, χs) + Random.seed!(42) + A = TensorMap(randn, ComplexF64, d ← D*D*D'*D') + B = TensorMap(randn, ComplexF64, d ← D*D*D'*D) + + function f(β) + C = PEPSKit._fit_spaces(β * B, A) + return norm(C) + end + + @test Zygote.gradient(f, 1.0)[1] ≈ num_grad(f, 1.0) +end + @testset "ad vumps iPEPS two side for unitcell $Ni x $Nj" for Ni in 1:1, Nj in 1:1, (d, D, χ) in zip(ds, Ds, χs) + Random.seed!(50) ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) - + ipeps = symmetrize!(ipeps, RotateReflect()) + itp = InfiniteTransferPEPS(ipeps) + alg = PEPSKit.VUMPS(maxiter=100, verbosity=2, ifupdown=true) + rt = PEPSKit.vumps(itp, VUMPSRuntime(itp, χ, alg), alg) function foo1(ipeps) itp = InfiniteTransferPEPS(ipeps) - env = PEPSKit.leading_boundary(itp, VUMPSRuntime(itp, χ, alg), alg) + env = PEPSKit.leading_boundary(itp, rt, alg) Z = abs(norm(ipeps, env)) return Z end @@ -187,6 +207,8 @@ end Z = abs(norm(ipeps, ctm))^(1/Ni/Nj) return Z end - @show Zygote.gradient(foo1, ipeps)[1] + @show foo1(ipeps) - foo2(ipeps) + # @show Zygote.gradient(foo1, ipeps)[1].A Zygote.gradient(foo2, ipeps)[1].A + @show Zygote.gradient(foo1, ipeps)[1].A - Zygote.gradient(foo2, ipeps)[1].A # @test norm(Zygote.gradient(foo1, ipeps)[1].A - Zygote.gradient(foo2, ipeps)[1].A) < 1e-8 end \ No newline at end of file From d70832092affcd2d63e26333f60c29f4ac370195 Mon Sep 17 00:00:00 2001 From: XingyuZhang2018 <864129714@qq.com> Date: Mon, 28 Oct 2024 12:24:58 +0100 Subject: [PATCH 19/25] another way to calculate Z; but still incorrect two side AD --- .../contractions/vumps_contractions.jl | 17 ++++++++- src/algorithms/toolbox.jl | 23 ++++++++++- src/environments/vumps_environments.jl | 38 +++++++++++++++++-- test/vumps/gradparts.jl | 6 ++- test/vumps/vumps_environment.jl | 8 +++- 5 files changed, 83 insertions(+), 9 deletions(-) diff --git a/src/algorithms/contractions/vumps_contractions.jl b/src/algorithms/contractions/vumps_contractions.jl index 5f84d948..5210161c 100644 --- a/src/algorithms/contractions/vumps_contractions.jl +++ b/src/algorithms/contractions/vumps_contractions.jl @@ -67,6 +67,21 @@ function FLmap(FLi::Vector{<:AbstractTensorMap}, return circshift(FLm, 1) end +""" + ``` + ┌── ALuᵢⱼ ── ┌── + Lᵢⱼ | = Lᵢⱼ₊₁ + └── ALdᵢᵣⱼ ── └── + ``` +""" +function Lmap(Li::Vector{<:AbstractTensorMap}, + ALui::Vector{<:AbstractTensorMap}, + ALdir::Vector{<:AbstractTensorMap}) + Lm = [@tensoropt L[-6; -4] := ALu[1 2 3; -4] * L[5; 1] * ALd[-6; 5 2 3] for (L, ALu, ALd) in zip(Li, ALui, ALdir)] + + return circshift(Lm, 1) +end + """ FRm = FRmap(FRi::Vector{<:AbstractTensorMap}, ARui::Vector{<:AbstractTensorMap}, @@ -101,7 +116,7 @@ end ``` ── ARuᵢⱼ ──┐ ──┐ - │ Rᵢⱼ = ── Rᵢⱼ₋₁ + │ Rᵢⱼ = Rᵢⱼ₋₁ ── ARdᵢᵣⱼ ──┘ ──┘ ``` """ diff --git a/src/algorithms/toolbox.jl b/src/algorithms/toolbox.jl index 5fe8493e..5e279ca2 100644 --- a/src/algorithms/toolbox.jl +++ b/src/algorithms/toolbox.jl @@ -58,13 +58,34 @@ end function LinearAlgebra.norm(ipeps::InfinitePEPS, env::VUMPSEnv) @unpack ACu, ARu, ACd, ARd, FLu, FRu, FLo, FRo = env - Ni = size(ipeps, 1) + Ni, Nj = size(ipeps) itp = InfiniteTransferPEPS(ipeps) λFLo, _ = rightenv(ARu, adjoint.(ARd), itp; ifobs=true) λC, _ = rightCenv(ARu, adjoint.(ARd); ifobs=true) return prod(λFLo./λC)^(1/Ni) + + # test for 1x1 unitcell + # _, FLo = leftenv(ARu, adjoint.(ARd), itp; ifobs=true) + # _, FRo = rightenv(ARu, adjoint.(ARd), itp; ifobs=true) + # _, Lo = leftCenv(ARu, adjoint.(ARd); ifobs=true) + # _, Ro = rightCenv(ARu, adjoint.(ARd); ifobs=true) + + # λFLo = Zygote.Buffer(zeros(ComplexF64, Ni, Nj)) + # λCo = Zygote.Buffer(zeros(ComplexF64, Ni, Nj)) + # for i in 1:Ni, j in 1:Nj + # ir = Ni + 1 - i + # irr = mod1(Ni + 2 - i, Ni) + # @tensoropt FLm[-1 -2 -3; -4] := FLo[i,j][6 5 4; 1] * ARu[i,j][1 2 3; -4] * itp.top[i,j][9; 2 -2 8 5] * + # itp.bot[i,j][3 -3 7 4; 9] * adjoint(ARd[ir,j])[-1; 6 8 7] + # @tensoropt Lm[-6; -4] := ARu[i,j][1 2 3; -4] * Lo[i,j][5; 1] * adjoint(ARd[irr,j])[-6; 5 2 3] + # λFLo[i, j] = (@tensor FLm[1 2 3; 4] * FRo[i, j][4 2 3; 1]) / + # (@tensor FLo[i, j][1 2 3; 4] * FRo[i, j][4 2 3; 1]) + # λCo[i, j] = (@tensor Lm[1; 2] * Ro[i, j][2; 1]) / + # (@tensor Lo[i, j][1; 2] * Ro[i, j][2; 1]) + # end + # return prod(copy(λFLo)./copy(λCo))^(1/Ni/Nj) end """ diff --git a/src/environments/vumps_environments.jl b/src/environments/vumps_environments.jl index b712a67c..f5d51eb3 100644 --- a/src/environments/vumps_environments.jl +++ b/src/environments/vumps_environments.jl @@ -241,6 +241,38 @@ function leftenv(ALu::Matrix{<:AbstractTensorMap}, return copy(λL), copy(FL′) end +""" + leftCenv(ALu::Matrix{<:AbstractTensorMap}, + ALd::Matrix{<:AbstractTensorMap}, + L::Matrix{<:AbstractTensorMap} = initial_C(ALu); + ifobs=false, verbosity = Defaults.verbosity, kwargs...) + +Compute the left environment tensor for MPS A, by finding the left fixed point +of ALu - ALd contracted along the physical dimension. +``` + ┌── ALuᵢⱼ ── ┌── + Lᵢⱼ | = λLᵢⱼ Lᵢⱼ₊₁ + └── ALdᵢᵣⱼ ── └── +``` +""" +function leftCenv(ALu::Matrix{<:AbstractTensorMap}, + ALd::Matrix{<:AbstractTensorMap}, + L::Matrix{<:AbstractTensorMap} = initial_C(ALu); + ifobs=false, verbosity = Defaults.verbosity, kwargs...) + + Ni, Nj = size(ALu) + λL = Zygote.Buffer(zeros(eltype(ALu[1]), Ni)) + L′ = Zygote.Buffer(L) + for i in 1:Ni + ir = ifobs ? mod1(Ni - i + 2, Ni) : i + λLs, L1s, info = eigsolve(L -> Lmap(L, ALu[i,:], ALd[ir,:]), + L[i,:], 1, :LM; maxiter=100, ishermitian = false, kwargs...) + verbosity >= 1 && info.converged == 0 && @warn "leftenv not converged" + λL[i], L′[i,:] = selectpos(λLs, L1s, Nj) + end + return copy(λL), copy(L′) +end + """ λR, FR = rightenv(ARu, ARd, M, FR = FRint(ARu,M); kwargs...) @@ -280,8 +312,8 @@ end R::Matrix{<:AbstractTensorMap} = initial_C(ARu); kwargs...) -Compute the right environment tensor for MPS A and MPO M, by finding the left fixed point -of AR - M - conj(AR) contracted along the physical dimension. +Compute the right environment tensor for MPS A by finding the left fixed point +of AR - conj(AR) contracted along the physical dimension. ``` ── ARuᵢⱼ ──┐ ──┐ | Rᵢⱼ = λRᵢⱼ Rᵢⱼ₋₁ @@ -414,7 +446,7 @@ function ACCtoAR(AC::Matrix{<:AbstractTensorMap}, C::Matrix{<:AbstractTensorMap} errR = 0.0 AR = Zygote.Buffer(AC) @inbounds for j in 1:Nj, i in 1:Ni - jr = j - 1 + (j==1)*Nj + jr = mod1(j - 1, Nj) LAC, QAC = rightorth(_to_tail(AC[i,j])) LC, QC = rightorth(C[i,jr]) errR += norm(LAC - LC) diff --git a/test/vumps/gradparts.jl b/test/vumps/gradparts.jl index 3b1afcfa..5e4ac80c 100644 --- a/test/vumps/gradparts.jl +++ b/test/vumps/gradparts.jl @@ -153,7 +153,7 @@ end ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) ipeps = symmetrize!(ipeps, RotateReflect()) - alg = PEPSKit.VUMPS(maxiter=100, verbosity=2, ifupdown=false) + alg = PEPSKit.VUMPS(maxiter=100, verbosity=2, ifupdown=true) itp = InfiniteTransferPEPS(ipeps) rt = PEPSKit.vumps(itp, VUMPSRuntime(itp, χ, alg), alg) @@ -170,6 +170,8 @@ end return Z end + # @show foo1(ipeps) - foo2(ipeps) + @test norm(Zygote.gradient(foo1, ipeps)[1].A - Zygote.gradient(foo2, ipeps)[1].A) < 1e-8 end @@ -209,6 +211,6 @@ end end @show foo1(ipeps) - foo2(ipeps) # @show Zygote.gradient(foo1, ipeps)[1].A Zygote.gradient(foo2, ipeps)[1].A - @show Zygote.gradient(foo1, ipeps)[1].A - Zygote.gradient(foo2, ipeps)[1].A + # @show Zygote.gradient(foo1, ipeps)[1].A - Zygote.gradient(foo2, ipeps)[1].A # @test norm(Zygote.gradient(foo1, ipeps)[1].A - Zygote.gradient(foo2, ipeps)[1].A) < 1e-8 end \ No newline at end of file diff --git a/test/vumps/vumps_environment.jl b/test/vumps/vumps_environment.jl index 62f04d89..85a6fb4f 100644 --- a/test/vumps/vumps_environment.jl +++ b/test/vumps/vumps_environment.jl @@ -3,7 +3,7 @@ using Random using PEPSKit using PEPSKit: initial_A, initial_C, initial_FL, initial_FR using PEPSKit: ρmap, getL!, getAL, getLsped, _to_tail, _to_front, left_canonical, right_canonical -using PEPSKit: leftenv, FLmap, rightenv, FRmap, ACenv, ACmap, Cenv, Cmap, rightCenv, Rmap +using PEPSKit: leftenv, FLmap, rightenv, FRmap, ACenv, ACmap, Cenv, Cmap, leftCenv, Lmap, rightCenv, Rmap using PEPSKit: LRtoC, ALCtoAC, ACCtoALAR using TensorKit using LinearAlgebra @@ -172,19 +172,23 @@ end @test errR isa Real end -@testset "rightCenv for unitcell $Ni x $Nj" for Ni in 1:3, Nj in 1:3, (d, D, χ) in zip(ds, Ds, χs), ifobs in [true, false] +@testset "leftCenv and rightCenv for unitcell $Ni x $Nj" for Ni in 1:3, Nj in 1:3, (d, D, χ) in zip(ds, Ds, χs), ifobs in [true, false] Random.seed!(42) ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) itp = InfiniteTransferPEPS(ipeps) A = initial_A(itp, χ) + AL, L, λ = left_canonical(A) R, AR, λ = right_canonical(A) + λL, L = leftCenv(AL, adjoint.(AL); ifobs) λR, R = rightCenv(AR, adjoint.(AR); ifobs) @test all(i -> space(i) == (χ ← χ), R) + @test all(i -> space(i) == (χ ← χ), L) for i in 1:Ni ir = ifobs ? mod1(Ni + 2 - i, Ni) : i + @test λL[i] * L[i,:] ≈ Lmap(L[i,:], AL[i,:], adjoint.(AL)[ir,:]) rtol = 1e-12 @test λR[i] * R[i,:] ≈ Rmap(R[i,:], AR[i,:], adjoint.(AR)[ir,:]) rtol = 1e-12 end end \ No newline at end of file From ff76337f995257a65de09cd846eb9a19eab6d0f9 Mon Sep 17 00:00:00 2001 From: XingyuZhang2018 <864129714@qq.com> Date: Wed, 30 Oct 2024 12:00:59 +0100 Subject: [PATCH 20/25] C4 iPEPS opt with ad-vumps --- src/PEPSKit.jl | 1 - .../contractions/vumps_contractions.jl | 26 +++ src/algorithms/ctmrg/ctmrg.jl | 10 +- src/algorithms/peps_opt.jl | 15 +- src/algorithms/toolbox.jl | 16 +- src/algorithms/vumps/vumps.jl | 159 +++++------------- src/environments/vumps_environments.jl | 153 +++++++++++------ src/utility/defaults.jl | 2 +- test/{heisenberg.jl => heisenberg_ctmrg.jl} | 4 +- test/heisenberg_vumps.jl | 34 ++++ test/vumps/gradparts.jl | 73 +++----- test/vumps/vumps.jl | 41 +++-- test/vumps/vumps_environment.jl | 61 +++---- 13 files changed, 308 insertions(+), 287 deletions(-) rename test/{heisenberg.jl => heisenberg_ctmrg.jl} (91%) create mode 100644 test/heisenberg_vumps.jl diff --git a/src/PEPSKit.jl b/src/PEPSKit.jl index 48604bc3..4fe6c037 100644 --- a/src/PEPSKit.jl +++ b/src/PEPSKit.jl @@ -31,7 +31,6 @@ include("operators/models.jl") include("environments/ctmrg_environments.jl") include("environments/vumps_environments.jl") -abstract type Algorithm end include("algorithms/contractions/localoperator.jl") include("algorithms/contractions/ctmrg_contractions.jl") include("algorithms/contractions/vumps_contractions.jl") diff --git a/src/algorithms/contractions/vumps_contractions.jl b/src/algorithms/contractions/vumps_contractions.jl index 5210161c..9b15458c 100644 --- a/src/algorithms/contractions/vumps_contractions.jl +++ b/src/algorithms/contractions/vumps_contractions.jl @@ -171,4 +171,30 @@ function Cmap(Cj::Vector{<:AbstractTensorMap}, Cm = [@tensoropt C[-1; -2] := C[1; 2] * FL[-1 3 4; 1] * FR[2 3 4; -2] for (C, FL, FR) in zip(Cj, FLjr, FRj)] return circshift(Cm, 1) +end + +function nearest_neighbour_energy(ipeps::InfinitePEPS, Hh, Hv, rt::VUMPSRuntime) + @unpack AL, C, AR, FL, FR = rt + + AC = ALCtoAC(AL, C) + Ni, Nj = size(ipeps) + (Ni, Nj) == (1, 1) || throw(ArgumentError("Only 1x1 unitcell is supported for one side VUMPSRuntime")) + + At = ipeps.A[1] + Ab = adjoint(ipeps.A[1]) + @tensoropt oph[-1 -2; -3 -4] := FL[1][18 12 15; 5] * AC[1][5 6 7; 8] * At[-1; 6 13 19 12] * Ab[7 16 20 15; -3] * + conj(AC[1][18 19 20; 21]) * AR[1][8 9 10; 11] * At[-2; 9 14 22 13] * Ab[10 17 23 16; -4] * + conj(AR[1][21 22 23; 24]) * FR[1][11 14 17; 24] + + @tensor eh = oph[1 2; 3 4] * Hh[3 4; 1 2] + @tensor nh = oph[1 2; 1 2] + + @tensoropt opv[-1 -2; -3 -4] := FL[1][21 19 20; 18] * AC[1][18 12 15 5] * At[-1; 12 6 13 19] * Ab[15 7 16 20; -3] * + FR[1][5 6 7; 8] * FL[1][24 22 23; 21] * At[-2; 13 9 14 22] * Ab[16 10 17 23; -4] * + FR[1][8 9 10; 11] * conj(AC[1][24 14 17; 11]) + + @tensor ev = opv[1 2; 3 4] * Hv[3 4; 1 2] + @tensor nv = opv[1 2; 1 2] + + return eh / nh + ev / nv end \ No newline at end of file diff --git a/src/algorithms/ctmrg/ctmrg.jl b/src/algorithms/ctmrg/ctmrg.jl index e55843cd..2cfacdf1 100644 --- a/src/algorithms/ctmrg/ctmrg.jl +++ b/src/algorithms/ctmrg/ctmrg.jl @@ -64,7 +64,7 @@ computed on the western side, and then applied and rotated. Or with `:simultaneo are computed and applied simultaneously on all sides, where in particular the corners get contracted with two projectors at the same time. """ -struct CTMRG{S} <: Algorithm +struct CTMRG{S} tol::Float64 maxiter::Int miniter::Int @@ -92,15 +92,15 @@ const SequentialCTMRG = CTMRG{:sequential} const SimultaneousCTMRG = CTMRG{:simultaneous} """ - MPSKit.leading_boundary([envinit], state, alg::CTMRG) + leading_boundary([envinit], state, alg::CTMRG) 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, oneunit(spacetype(state))), state, alg) +function leading_boundary(state, alg::CTMRG) + return leading_boundary(CTMRGEnv(state, oneunit(spacetype(state))), state, alg) end -function MPSKit.leading_boundary(envinit, state, alg::CTMRG) +function leading_boundary(envinit, state, alg::CTMRG) CS = map(x -> tsvd(x; alg=TensorKit.SVD())[2], envinit.corners) TS = map(x -> tsvd(x; alg=TensorKit.SVD())[2], envinit.edges) diff --git a/src/algorithms/peps_opt.jl b/src/algorithms/peps_opt.jl index fe20a35e..36d76230 100644 --- a/src/algorithms/peps_opt.jl +++ b/src/algorithms/peps_opt.jl @@ -89,13 +89,13 @@ step by setting `reuse_env` to true. Otherwise a random environment is used at e step. The CTMRG gradient itself is computed using the `gradient_alg` algorithm. """ struct PEPSOptimize{G} - boundary_alg::CTMRG + boundary_alg::Union{CTMRG, VUMPS} optimizer::OptimKit.OptimizationAlgorithm reuse_env::Bool gradient_alg::G function PEPSOptimize( # Inner constructor to prohibit illegal setting combinations - boundary_alg::CTMRG{S}, + boundary_alg::Union{CTMRG{S}, VUMPS}, optimizer, reuse_env, gradient_alg::G, @@ -106,6 +106,8 @@ struct PEPSOptimize{G} elseif boundary_alg.projector_alg.svd_alg.fwd_alg isa IterSVD && iterscheme(gradient_alg) === :fixed throw(ArgumentError("IterSVD and :fixed are currently not compatible")) + elseif boundary_alg isa VUMPS && iterscheme(gradient_alg) === :fixed + throw(ArgumentError("VUMPS and :fixed are currently not compatible")) end end return new{G}(boundary_alg, optimizer, reuse_env, gradient_alg) @@ -148,7 +150,7 @@ function fixedpoint( ψ₀::InfinitePEPS{T}, H, alg::PEPSOptimize, - env₀::CTMRGEnv=CTMRGEnv(ψ₀, field(T)^20); + env₀::Union{CTMRGEnv, VUMPSRuntime}=CTMRGEnv(ψ₀, field(T)^20); (finalize!)=OptimKit._finalize!, symmetrization=nothing, ) where {T} @@ -177,6 +179,7 @@ function fixedpoint( return costfun(ψ, envs´, H) end g = only(gs) # `withgradient` returns tuple of gradients `gs` + envs isa VUMPSRuntime && (g = InfinitePEPS(g.A)) # KrylovKit patch return E, g end @@ -213,7 +216,7 @@ Evaluating the gradient of the cost function for CTMRG: function _rrule( gradmode::GradMode{:diffgauge}, ::RuleConfig, - ::typeof(MPSKit.leading_boundary), + ::typeof(leading_boundary), envinit, state, alg::CTMRG, @@ -244,7 +247,7 @@ end function _rrule( gradmode::GradMode{:diffgauge}, ::RuleConfig, - ::typeof(MPSKit.leading_boundary), + ::typeof(leading_boundary), envinit, state, alg::VUMPS, @@ -276,7 +279,7 @@ end function _rrule( gradmode::GradMode{:fixed}, ::RuleConfig, - ::typeof(MPSKit.leading_boundary), + ::typeof(leading_boundary), envinit, state, alg::CTMRG{C}, diff --git a/src/algorithms/toolbox.jl b/src/algorithms/toolbox.jl index 5e279ca2..586367f1 100644 --- a/src/algorithms/toolbox.jl +++ b/src/algorithms/toolbox.jl @@ -1,4 +1,4 @@ -function MPSKit.expectation_value(peps::InfinitePEPS, O::LocalOperator, envs::CTMRGEnv) +function expectation_value(peps::InfinitePEPS, O::LocalOperator, envs::CTMRGEnv) checklattice(peps, O) return sum(O.terms) do (inds, operator) # TODO: parallelize this map, especially for the backwards pass contract_localoperator(inds, operator, peps, peps, envs) / @@ -6,8 +6,15 @@ function MPSKit.expectation_value(peps::InfinitePEPS, O::LocalOperator, envs::CT end end -function costfun(peps::InfinitePEPS, envs::CTMRGEnv, O::LocalOperator) - E = MPSKit.expectation_value(peps, O, envs) +function expectation_value(peps::InfinitePEPS, O::LocalOperator, rt::VUMPSRuntime) + checklattice(peps, O) + Hh = O.terms[1].second + Hv = O.terms[2].second + return nearest_neighbour_energy(peps, Hh, Hv, rt) +end + +function costfun(peps::InfinitePEPS, envs::Union{CTMRGEnv, VUMPSRuntime}, O::LocalOperator) + E = expectation_value(peps, O, envs) ignore_derivatives() do isapprox(imag(E), 0; atol=sqrt(eps(real(E)))) || @warn "Expectation value is not real: $E." @@ -60,8 +67,7 @@ function LinearAlgebra.norm(ipeps::InfinitePEPS, env::VUMPSEnv) @unpack ACu, ARu, ACd, ARd, FLu, FRu, FLo, FRo = env Ni, Nj = size(ipeps) - itp = InfiniteTransferPEPS(ipeps) - λFLo, _ = rightenv(ARu, adjoint.(ARd), itp; ifobs=true) + λFLo, _ = rightenv(ARu, adjoint.(ARd), ipeps; ifobs=true) λC, _ = rightCenv(ARu, adjoint.(ARd); ifobs=true) return prod(λFLo./λC)^(1/Ni) diff --git a/src/algorithms/vumps/vumps.jl b/src/algorithms/vumps/vumps.jl index 817eca97..20ab3a22 100644 --- a/src/algorithms/vumps/vumps.jl +++ b/src/algorithms/vumps/vumps.jl @@ -1,122 +1,47 @@ -@kwdef mutable struct VUMPS{F} <: Algorithm +@kwdef mutable struct VUMPS{F} ifupdown::Bool = true tol::Float64 = Defaults.contr_tol maxiter::Int = Defaults.contr_maxiter + miniter::Int = Defaults.contr_miniter finalize::F = Defaults._finalize verbosity::Int = Defaults.verbosity end -""" - VUMPSEnv{T<:Number, S<:IndexSpace, - OT<:AbstractTensorMap{S, 2, 2}, - ET<:AbstractTensorMap{S, 2, 1}, - CT<:AbstractTensorMap{S, 1, 1}} - -A struct that contains the environment of the VUMPS algorithm for calculate observables. - -For a `Ni` x `Nj` unitcell, each is a Matrix, containing - -- `AC`: The mixed canonical environment tensor. -- `AR`: The right canonical environment tensor. -- `Lu`: The left upper environment tensor. -- `Ru`: The right upper environment tensor. -- `Lo`: The left mixed environment tensor. -- `Ro`: The right mixed environment tensor. -""" -struct VUMPSEnv{T<:Number, S<:IndexSpace, - ET<:AbstractTensorMap{S, 3, 1}} - ACu::Matrix{ET} - ARu::Matrix{ET} - ACd::Matrix{ET} - ARd::Matrix{ET} - FLu::Matrix{ET} - FRu::Matrix{ET} - FLo::Matrix{ET} - FRo::Matrix{ET} - function VUMPSEnv(ACu::Matrix{ET}, - ARu::Matrix{ET}, - ACd::Matrix{ET}, - ARd::Matrix{ET}, - FLu::Matrix{ET}, - FRu::Matrix{ET}, - FLo::Matrix{ET}, - FRo::Matrix{ET}) where {ET} - T = eltype(ACu[1]) - S = spacetype(ACu[1]) - new{T, S, ET}(ACu, ARu, ACd, ARd, FLu, FRu, FLo, FRo) - end -end - -""" - VUMPSRuntime{T<:Number, S<:IndexSpace, - OT<:AbstractTensorMap{S, 2, 2}, - ET<:AbstractTensorMap{S, 2, 1}, - CT<:AbstractTensorMap{S, 1, 1}} - -A struct that contains the environment of the VUMPS algorithm for runtime calculations. - -For a `Ni` x `Nj` unitcell, each is a Matrix, containing - -- `O`: The center transfer matrix PEPO tensor. -- `AL`: The left canonical environment tensor. -- `AR`: The right canonical environment tensor. -- `C`: The canonical environment tensor. -- `L`: The left environment tensor. -- `R`: The right environment tensor. -""" -struct VUMPSRuntime{T<:Number, S<:IndexSpace, - ET<:AbstractTensorMap{S, 3, 1}, - CT<:AbstractTensorMap{S, 1, 1}} - AL::Matrix{ET} - AR::Matrix{ET} - C::Matrix{CT} - FL::Matrix{ET} - FR::Matrix{ET} - function VUMPSRuntime(AL::Matrix{ET}, - AR::Matrix{ET}, - C::Matrix{CT}, - FL::Matrix{ET}, - FR::Matrix{ET}) where {ET, CT} - T = eltype(AL[1]) - S = spacetype(AL[1]) - new{T, S, ET, CT}(AL, AR, C, FL, FR) - end -end - -@non_differentiable VUMPSRuntime(O::InfiniteTransferPEPS, χ::VectorSpace) -function VUMPSRuntime(O::InfiniteTransferPEPS, χ::VectorSpace) - A = initial_A(O, χ) +VUMPSRuntime(ipeps::InfinitePEPS, χ::Int) = VUMPSRuntime(ipeps, ℂ^χ) +function VUMPSRuntime(ipeps::InfinitePEPS, χ::VectorSpace) + A = initial_A(ipeps, χ) AL, L, _ = left_canonical(A) R, AR, _ = right_canonical(AL) - _, FL = leftenv(AL, adjoint.(AL), O) - _, FR = rightenv(AR, adjoint.(AR), O) + _, FL = leftenv(AL, adjoint.(AL), ipeps) + _, FR = rightenv(AR, adjoint.(AR), ipeps) C = LRtoC(L, R) return VUMPSRuntime(AL, AR, C, FL, FR) end +@non_differentiable VUMPSRuntime(ipeps::InfinitePEPS, χ::VectorSpace) -function down_itp(O) - Ni, Nj = size(O) - ipepsd = Zygote.Buffer(O.top) +function _down_ipeps(ipeps::InfinitePEPS) + Ni, Nj = size(ipeps) + ipepsd = Zygote.Buffer(ipeps.A) for j in 1:Nj, i in 1:Ni - ir = Ni + 1 - i - Ad = permute(O.top[ir,j]', ((5,), (3,2,1,4))) - ipepsd[i, j] = _fit_spaces(Ad, O.top[ir,j]) + ir = Ni + 1 - i + Ad = permute(ipeps[ir,j]', ((5,), (3,2,1,4))) + ipepsd[i, j] = _fit_spaces(Ad, ipeps[ir,j]) end - return InfiniteTransferPEPS(copy(ipepsd)) + return InfinitePEPS(copy(ipepsd)) end -@non_differentiable VUMPSRuntime(O::InfiniteTransferPEPS, χ::VectorSpace, alg::VUMPS) -function VUMPSRuntime(O::InfiniteTransferPEPS, χ::VectorSpace, alg::VUMPS) - Ni, Nj = size(O) +@non_differentiable VUMPSRuntime(ipeps::InfinitePEPS, χ::VectorSpace, alg::VUMPS) +function VUMPSRuntime(ipeps::InfinitePEPS, χ::VectorSpace, alg::VUMPS) + Ni, Nj = size(ipeps) - rtup = VUMPSRuntime(O, χ) + rtup = VUMPSRuntime(ipeps, χ) alg.verbosity >= 2 && Zygote.@ignore @info "VUMPS init: cell=($(Ni)×$(Nj)) χ = $(χ) up(↑) environment" if alg.ifupdown - Od = down_itp(O) - rtdown = VUMPSRuntime(Od, χ) + ipepsd = _down_ipeps(ipeps) + rtdown = VUMPSRuntime(ipepsd, χ) alg.verbosity >= 2 && Zygote.@ignore @info "VUMPS init: cell=($(Ni)×$(Nj)) χ = $(χ) down(↓) environment" return rtup, rtdown @@ -125,12 +50,12 @@ function VUMPSRuntime(O::InfiniteTransferPEPS, χ::VectorSpace, alg::VUMPS) end end -function vumps_itr(O::InfiniteTransferPEPS, rt::VUMPSRuntime, alg::VUMPS) +function vumps_itr(rt::VUMPSRuntime, ipeps::InfinitePEPS, alg::VUMPS) t = Zygote.@ignore time() for i in 1:alg.maxiter - rt, err = vumps_step(O, rt, alg) + rt, err = vumps_step(rt, ipeps, alg) alg.verbosity >= 3 && Zygote.@ignore @info @sprintf("VUMPS@step: %4d\terr = %.3e\ttime = %.3f sec", i, err, time()-t) - if err < alg.tol + if err < alg.tol && i >= alg.miniter alg.verbosity >= 2 && Zygote.@ignore @info @sprintf("VUMPS conv@step: %4d\terr = %.3e\ttime = %.3f sec", i, err, time()-t) break end @@ -141,31 +66,29 @@ function vumps_itr(O::InfiniteTransferPEPS, rt::VUMPSRuntime, alg::VUMPS) return rt end -function vumps(O::InfiniteTransferPEPS, rt::VUMPSRuntime, alg::VUMPS) - return vumps_itr(O, rt, alg) +function leading_boundary(rt::VUMPSRuntime, ipeps::InfinitePEPS, alg::VUMPS) + return vumps_itr(rt, ipeps, alg) end -function leading_boundary(O::InfiniteTransferPEPS, rt::VUMPSRuntime, alg::VUMPS) - rt = vumps(O, rt, alg) - +function VUMPSEnv(rt::VUMPSRuntime) @unpack AL, AR, C, FL, FR = rt AC = ALCtoAC(AL, C) return VUMPSEnv(AC, AR, AC, AR, FL, FR, FL, FR) end -function vumps(O::InfiniteTransferPEPS, rt::Tuple, alg::VUMPS) +function leading_boundary(rt::Tuple{VUMPSRuntime, VUMPSRuntime}, ipeps::InfinitePEPS, alg::VUMPS) rtup, rtdown = rt + + rtup = vumps_itr(rtup, ipeps, alg) - rtup = vumps_itr(O, rtup, alg) - - Od = down_itp(O) - rtdown = vumps_itr(Od, rtdown, alg) + ipepsd = _down_ipeps(ipeps) + rtdown = vumps_itr(rtdown, ipepsd, alg) return rtup, rtdown end -function leading_boundary(O::InfiniteTransferPEPS, rt::Tuple, alg::VUMPS) - rtup, rtdown = vumps(O, rt, alg) +function VUMPSEnv(rt::Tuple{VUMPSRuntime, VUMPSRuntime}, ipeps::InfinitePEPS) + rtup, rtdown = rt ALu, ARu, Cu, FLu, FRu = rtup.AL, rtup.AR, rtup.C, rtup.FL, rtup.FR ACu = ALCtoAC(ALu, Cu) @@ -174,22 +97,22 @@ function leading_boundary(O::InfiniteTransferPEPS, rt::Tuple, alg::VUMPS) ACd = ALCtoAC(ALd, Cd) # to do fix the follow index - _, FLo = leftenv(ALu, adjoint.(ALd), O, FLu; ifobs = true) - _, FRo = rightenv(ARu, adjoint.(ARd), O, FRu; ifobs = true) + _, FLo = leftenv(ALu, adjoint.(ALd), ipeps, FLu; ifobs = true) + _, FRo = rightenv(ARu, adjoint.(ARd), ipeps, FRu; ifobs = true) return VUMPSEnv(ACu, ARu, ACd, ARd, FLu, FRu, FLo, FRo) end -function vumps_step(O::InfiniteTransferPEPS, rt::VUMPSRuntime, alg::VUMPS) +function vumps_step(rt::VUMPSRuntime, ipeps::InfinitePEPS, alg::VUMPS) verbosity = alg.verbosity @unpack AL, C, AR, FL, FR = rt AC = Zygote.@ignore ALCtoAC(AL,C) - _, ACp = ACenv(AC, FL, FR, O; verbosity) + _, ACp = ACenv(AC, FL, FR, ipeps; verbosity) _, Cp = Cenv( C, FL, FR; verbosity) ALp, ARp, _, _ = ACCtoALAR(ACp, Cp) - _, FL = leftenv(AL, adjoint.(ALp), O, FL; verbosity) - _, FR = rightenv(AR, adjoint.(ARp), O, FR; verbosity) - _, ACp = ACenv(ACp, FL, FR, O; verbosity) + _, FL = leftenv(AL, adjoint.(ALp), ipeps, FL; verbosity) + _, FR = rightenv(AR, adjoint.(ARp), ipeps, FR; verbosity) + _, ACp = ACenv(ACp, FL, FR, ipeps; verbosity) _, Cp = Cenv( Cp, FL, FR; verbosity) ALp, ARp, errL, errR = ACCtoALAR(ACp, Cp) err = errL + errR diff --git a/src/environments/vumps_environments.jl b/src/environments/vumps_environments.jl index f5d51eb3..c922f13b 100644 --- a/src/environments/vumps_environments.jl +++ b/src/environments/vumps_environments.jl @@ -1,36 +1,89 @@ """ - InfiniteTransferPEPS{T} + VUMPSEnv{T<:Number, S<:IndexSpace, + OT<:AbstractTensorMap{S, 2, 2}, + ET<:AbstractTensorMap{S, 2, 1}, + CT<:AbstractTensorMap{S, 1, 1}} -Represents an infinite transfer operator corresponding to a single row of a partition -function which corresponds to the overlap between 'ket' and 'bra' `InfinitePEPS` states. +A struct that contains the environment of the VUMPS algorithm for calculate observables. + +For a `Ni` x `Nj` unitcell, each is a Matrix, containing + +- `AC`: The mixed canonical environment tensor. +- `AR`: The right canonical environment tensor. +- `Lu`: The left upper environment tensor. +- `Ru`: The right upper environment tensor. +- `Lo`: The left mixed environment tensor. +- `Ro`: The right mixed environment tensor. """ -struct InfiniteTransferPEPS{TT, BT} - top::Matrix{TT} - bot::Matrix{BT} -end - -function InfiniteTransferPEPS(ipeps::InfinitePEPS) - top = ipeps.A - bot = adjoint.(ipeps.A) - return InfiniteTransferPEPS(top, bot) +struct VUMPSEnv{T<:Number, S<:IndexSpace, + ET<:AbstractTensorMap{S, 3, 1}} + ACu::Matrix{ET} + ARu::Matrix{ET} + ACd::Matrix{ET} + ARd::Matrix{ET} + FLu::Matrix{ET} + FRu::Matrix{ET} + FLo::Matrix{ET} + FRo::Matrix{ET} + function VUMPSEnv(ACu::Matrix{ET}, + ARu::Matrix{ET}, + ACd::Matrix{ET}, + ARd::Matrix{ET}, + FLu::Matrix{ET}, + FRu::Matrix{ET}, + FLo::Matrix{ET}, + FRo::Matrix{ET}) where {ET} + T = eltype(ACu[1]) + S = spacetype(ACu[1]) + new{T, S, ET}(ACu, ARu, ACd, ARd, FLu, FRu, FLo, FRo) + end end -function InfiniteTransferPEPS(A::Matrix{<:AbstractTensorMap}) - top = A - bot = adjoint.(A) - return InfiniteTransferPEPS(top, bot) -end +""" + VUMPSRuntime{T<:Number, S<:IndexSpace, + OT<:AbstractTensorMap{S, 2, 2}, + ET<:AbstractTensorMap{S, 2, 1}, + CT<:AbstractTensorMap{S, 1, 1}} -function ChainRulesCore.rrule(::Type{InfiniteTransferPEPS}, top::Matrix, bot::Matrix) - function pullback(Δ) - return NoTangent(), Δ.top, Δ.bot +A struct that contains the environment of the VUMPS algorithm for runtime calculations. + +For a `Ni` x `Nj` unitcell, each is a Matrix, containing + +- `O`: The center transfer matrix PEPO tensor. +- `AL`: The left canonical environment tensor. +- `AR`: The right canonical environment tensor. +- `C`: The canonical environment tensor. +- `L`: The left environment tensor. +- `R`: The right environment tensor. +""" +struct VUMPSRuntime{T<:Number, S<:IndexSpace, + ET<:AbstractTensorMap{S, 3, 1}, + CT<:AbstractTensorMap{S, 1, 1}} + AL::Matrix{ET} + AR::Matrix{ET} + C::Matrix{CT} + FL::Matrix{ET} + FR::Matrix{ET} + function VUMPSRuntime(AL::Matrix{ET}, + AR::Matrix{ET}, + C::Matrix{CT}, + FL::Matrix{ET}, + FR::Matrix{ET}) where {ET, CT} + T = eltype(AL[1]) + S = spacetype(AL[1]) + new{T, S, ET, CT}(AL, AR, C, FL, FR) end - return InfiniteTransferPEPS(top, bot), pullback end -Base.eltype(transfer::InfiniteTransferPEPS) = eltype(transfer.top[1]) -Base.size(transfer::InfiniteTransferPEPS) = size(transfer.top) - +# In-place update of environment +function update!(env::VUMPSRuntime, env´::VUMPSRuntime) + env.AL .= env´.AL + env.AR .= env´.AR + env.C .= env´.C + env.FL .= env´.FL + env.FR .= env´.FR + return env +end """ ```` @@ -43,10 +96,10 @@ Base.size(transfer::InfiniteTransferPEPS) = size(transfer.top) Initalize a boundary MPS for the transfer operator `O` by specifying an array of virtual spaces consistent with the unit cell. """ -function initial_A(O::InfiniteTransferPEPS, χ::VectorSpace) - T = eltype(O) - Ni, Nj = size(O) - A = [(D = space(O.top[i, j], 2)'; +function initial_A(ipeps::InfinitePEPS, χ::VectorSpace) + T = eltype(ipeps[1]) + Ni, Nj = size(ipeps) + A = [(D = space(ipeps[i, j], 2)'; TensorMap(rand, T, χ * D * D', χ)) for i in 1:Ni, j in 1:Nj] return A end @@ -193,19 +246,19 @@ function right_canonical(A::Matrix{<:AbstractTensorMap}, L::Matrix{<:AbstractTen return R, AR, λ end -function initial_FL(AL::Matrix{<:AbstractTensorMap}, O::InfiniteTransferPEPS) - T = eltype(O) - FL = [(D = space(top, 5)'; +function initial_FL(AL::Matrix{<:AbstractTensorMap}, ipeps::InfinitePEPS) + T = eltype(ipeps[1]) + FL = [(D = space(ipeps, 5)'; χ = space(AL, 4)'; - TensorMap(rand, T, χ * D * D', χ)) for (top, AL) in zip(O.top, AL)] + TensorMap(rand, T, χ * D * D', χ)) for (ipeps, AL) in zip(ipeps.A, AL)] return FL end -function initial_FR(AR::Matrix{<:AbstractTensorMap}, O::InfiniteTransferPEPS) - T = eltype(O) - FR = [(D = space(top, 3)'; +function initial_FR(AR::Matrix{<:AbstractTensorMap}, ipeps::InfinitePEPS) + T = eltype(ipeps[1]) + FR = [(D = space(ipeps, 3)'; χ = space(AR, 4)'; - TensorMap(rand, T, χ * D * D', χ)) for (top, AR) in zip(O.top, AR)] + TensorMap(rand, T, χ * D * D', χ)) for (ipeps, AR) in zip(ipeps.A, AR)] return FR end @@ -224,16 +277,16 @@ FLᵢⱼ ─ Oᵢⱼ ── = λLᵢⱼ FLᵢⱼ₊₁ """ function leftenv(ALu::Matrix{<:AbstractTensorMap}, ALd::Matrix{<:AbstractTensorMap}, - O::InfiniteTransferPEPS, - FL::Matrix{<:AbstractTensorMap} = initial_FL(ALu,O); + ipeps::InfinitePEPS, + FL::Matrix{<:AbstractTensorMap} = initial_FL(ALu,ipeps); ifobs=false, verbosity = Defaults.verbosity, kwargs...) - Ni, Nj = size(O) - λL = Zygote.Buffer(zeros(eltype(O), Ni)) + Ni, Nj = size(ipeps) + λL = Zygote.Buffer(zeros(eltype(ipeps[1]), Ni)) FL′ = Zygote.Buffer(FL) for i in 1:Ni ir = ifobs ? Ni + 1 - i : mod1(i + 1, Ni) - λLs, FL1s, info = eigsolve(FLi -> FLmap(FLi, ALu[i,:], ALd[ir,:], O.top[i,:], O.bot[i,:]), + λLs, FL1s, info = eigsolve(FLi -> FLmap(FLi, ALu[i,:], ALd[ir,:], ipeps[i,:], adjoint.(ipeps[i,:])), FL[i,:], 1, :LM; maxiter=100, ishermitian = false, kwargs...) verbosity >= 1 && info.converged == 0 && @warn "leftenv not converged" λL[i], FL′[i,:] = selectpos(λLs, FL1s, Nj) @@ -288,17 +341,17 @@ of AR - M - conj(AR) contracted along the physical dimension. """ function rightenv(ARu::Matrix{<:AbstractTensorMap}, ARd::Matrix{<:AbstractTensorMap}, - O::InfiniteTransferPEPS, - FR::Matrix{<:AbstractTensorMap} = initial_FR(ARu,O); + ipeps::InfinitePEPS, + FR::Matrix{<:AbstractTensorMap} = initial_FR(ARu,ipeps); ifobs=false, ifinline=false,verbosity = Defaults.verbosity, kwargs...) - Ni, Nj = size(O) - λR = Zygote.Buffer(zeros(eltype(O), Ni)) + Ni, Nj = size(ipeps) + λR = Zygote.Buffer(zeros(eltype(ipeps[1]), Ni)) FR′ = Zygote.Buffer(FR) for i in 1:Ni ir = ifobs ? Ni + 1 - i : mod1(i + 1, Ni) ifinline && (ir = i) - λRs, FR1s, info = eigsolve(FR -> FRmap(FR, ARu[i,:], ARd[ir,:], O.top[i,:], O.bot[i,:]), + λRs, FR1s, info = eigsolve(FR -> FRmap(FR, ARu[i,:], ARd[ir,:], ipeps[i,:], adjoint.(ipeps[i,:])), FR[i,:], 1, :LM; maxiter=100, ishermitian = false, kwargs...) verbosity >= 1 && info.converged == 0 && @warn "rightenv not converged" λR[i], FR′[i,:] = selectpos(λRs, FR1s, Nj) @@ -353,14 +406,14 @@ FLᵢⱼ ─── Oᵢⱼ ───── FRᵢⱼ │ │ function ACenv(AC::Matrix{<:AbstractTensorMap}, FL::Matrix{<:AbstractTensorMap}, FR::Matrix{<:AbstractTensorMap}, - O::InfiniteTransferPEPS; + ipeps::InfinitePEPS; verbosity = Defaults.verbosity, kwargs...) - Ni, Nj = size(O) - λAC = Zygote.Buffer(zeros(eltype(O),Nj)) + Ni, Nj = size(ipeps) + λAC = Zygote.Buffer(zeros(eltype(ipeps[1]),Nj)) AC′ = Zygote.Buffer(AC) for j in 1:Nj - λACs, ACs, info = eigsolve(AC -> ACmap(AC, FL[:,j], FR[:,j], O.top[:,j], O.bot[:,j]), + λACs, ACs, info = eigsolve(AC -> ACmap(AC, FL[:,j], FR[:,j], ipeps[:,j], adjoint.(ipeps[:,j])), AC[:,j], 1, :LM; maxiter=100, ishermitian = false, kwargs...) verbosity >= 1 && info.converged == 0 && @warn "ACenv Not converged" λAC[j], AC′[:,j] = selectpos(λACs, ACs, Ni) diff --git a/src/utility/defaults.jl b/src/utility/defaults.jl index 45101770..5a5b120c 100644 --- a/src/utility/defaults.jl +++ b/src/utility/defaults.jl @@ -44,7 +44,7 @@ module Defaults const fwd_alg = TensorKit.SVD() const rrule_alg = GMRES(; tol=1e1contr_tol) const svd_alg = SVDAdjoint(; fwd_alg, rrule_alg) - const optimizer = LBFGS(32; maxiter=100, gradtol=1e-4, verbosity=2) + const optimizer = LBFGS(32; maxiter=100, gradtol=1e-8, verbosity=2) const gradient_linsolver = KrylovKit.BiCGStab(; maxiter=Defaults.fpgrad_maxiter, tol=Defaults.fpgrad_tol ) diff --git a/test/heisenberg.jl b/test/heisenberg_ctmrg.jl similarity index 91% rename from test/heisenberg.jl rename to test/heisenberg_ctmrg.jl index 4fa67362..11669eba 100644 --- a/test/heisenberg.jl +++ b/test/heisenberg_ctmrg.jl @@ -18,7 +18,7 @@ ctm_alg = CTMRG(; ) opt_alg = PEPSOptimize(; boundary_alg=ctm_alg, - optimizer=LBFGS(4; maxiter=100, gradtol=1e-3, verbosity=2), + optimizer=LBFGS(4; maxiter=0, gradtol=1e-3, verbosity=2), gradient_alg=LinSolver(; solver=GMRES(; tol=1e-6), iterscheme=:fixed), reuse_env=true, ) @@ -30,7 +30,7 @@ psi_init = InfinitePEPS(2, χbond) env_init = leading_boundary(CTMRGEnv(psi_init, ComplexSpace(χenv)), psi_init, ctm_alg) # find fixedpoint -result = fixedpoint(psi_init, H, opt_alg, env_init) +result = fixedpoint(psi_init, H, opt_alg, env_init); ξ_h, ξ_v, = correlation_length(result.peps, result.env) @test result.E ≈ -0.6694421 atol = 1e-2 diff --git a/test/heisenberg_vumps.jl b/test/heisenberg_vumps.jl new file mode 100644 index 00000000..36430e54 --- /dev/null +++ b/test/heisenberg_vumps.jl @@ -0,0 +1,34 @@ +using Test +using Random +using PEPSKit +using TensorKit +using KrylovKit +using OptimKit + +# initialize parameters +χbond = 2 +χenv = 16 +boundary_alg = VUMPS( + ifupdown=false, + tol=1e-10, + miniter=4, + maxiter=10, + verbosity=2 +) +opt_alg = PEPSOptimize(; + boundary_alg, + optimizer=LBFGS(4; maxiter=100, gradtol=1e-8, verbosity=2), + gradient_alg=nothing, + reuse_env=true +) + +# initialize states +Random.seed!(91283219347) +H = heisenberg_XYZ(InfiniteSquare()) +psi_init = InfinitePEPS(2, χbond; unitcell=(1, 1)) +env_init = VUMPSRuntime(psi_init, χenv) + +# find fixedpoint +result = fixedpoint(psi_init, H, opt_alg, env_init; +symmetrization=RotateReflect()); +@test result.E ≈ -0.66023 atol = 1e-4 diff --git a/test/vumps/gradparts.jl b/test/vumps/gradparts.jl index 5e4ac80c..959c2f4d 100644 --- a/test/vumps/gradparts.jl +++ b/test/vumps/gradparts.jl @@ -2,7 +2,6 @@ using Test using Random using PEPSKit using PEPSKit: initial_A, left_canonical, right_canonical, leftenv, rightenv, ACenv, Cenv, LRtoC, ALCtoAC, ACCtoALAR -using MPSKit using TensorKit using Zygote using LinearAlgebra @@ -31,37 +30,24 @@ end @test Zygote.gradient(f, 1.0)[1] ≈ num_grad(f, 1.0) end -@testset "InfiniteTransferPEPS for unitcell $Ni x $Nj" for Ni in 1:2, Nj in 1:2, (d, D, χ) in zip(ds, Ds, χs) - Random.seed!(42) - ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) - function f(β) - T = PEPSKit.InfiniteTransferPEPS(β * ipeps) - norm(T.bot .* T.top) - end - - @test Zygote.gradient(f, 1.0)[1] ≈ num_grad(f, 1.0) -end - @testset "leftenv and rightenv for unitcell $Ni x $Nj" for Ni in 1:2, Nj in 1:2, (d, D, χ) in zip(ds, Ds, χs), ifobs in [true, false] Random.seed!(50) ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) - itp = InfiniteTransferPEPS(ipeps) - A = initial_A(itp, χ) + A = initial_A(ipeps, χ) AL, L, λ = left_canonical(A) R, AR, λ = right_canonical(A) - λL, FL = leftenv(AL, adjoint.(AL), itp; ifobs) - λR, FR = rightenv(AR, adjoint.(AR), itp; ifobs) + λL, FL = leftenv(AL, adjoint.(AL), ipeps; ifobs) + λR, FR = rightenv(AR, adjoint.(AR), ipeps; ifobs) S1 = TensorMap(rand, ComplexF64, χ*D'*D*χ' ← χ*D'*D*χ') S2 = TensorMap(rand, ComplexF64, χ*D*D'*χ' ← χ*D*D'*χ') function foo1(β) ipeps = β * ipeps - itp = InfiniteTransferPEPS(ipeps) - _, FL = leftenv(AL, adjoint.(AL), itp; ifobs) + _, FL = leftenv(AL, adjoint.(AL), ipeps; ifobs) tol = [(@tensor conj(FL[1 2 3 4]) * S1[1 2 3 4; 5 6 7 8] * FL[5 6 7 8]) / dot(FL, FL) for FL in FL] return norm(tol) @@ -70,9 +56,8 @@ end function foo2(β) ipeps = β * ipeps - itp = InfiniteTransferPEPS(ipeps) - _, FR = rightenv(AR, adjoint.(AR), itp; ifobs) + _, FR = rightenv(AR, adjoint.(AR), ipeps; ifobs) tol = [(@tensor conj(FR[1 2 3 4]) * S2[1 2 3 4; 5 6 7 8] * FR[5 6 7 8]) / dot(FR, FR) for FR in FR] return norm(tol) @@ -84,13 +69,12 @@ end Random.seed!(50) ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) - itp = InfiniteTransferPEPS(ipeps) - A = initial_A(itp, χ) + A = initial_A(ipeps, χ) AL, L, λ = left_canonical(A) R, AR, λ = right_canonical(A) - _, FL = leftenv(AL, adjoint.(AL), itp) - _, FR = rightenv(AR, adjoint.(AR), itp) + _, FL = leftenv(AL, adjoint.(AL), ipeps) + _, FR = rightenv(AR, adjoint.(AR), ipeps) C = LRtoC(L, R) AC = ALCtoAC(AL, C) @@ -99,9 +83,7 @@ end function foo1(β) ipeps = β * ipeps - itp = InfiniteTransferPEPS(ipeps) - - _, AC = ACenv(AC, FL, FR, itp) + _, AC = ACenv(AC, FL, FR, ipeps) tol = [(@tensor conj(AC[1 2 3 4]) * S1[1 2 3 4; 5 6 7 8] * AC[5 6 7 8]) / dot(AC, AC) for AC in AC] return norm(tol) @@ -120,26 +102,23 @@ end @testset "ACCtoALAR for unitcell $Ni x $Nj" for Ni in 1:2, Nj in 1:2, (d, D, χ) in zip(ds, Ds, χs) Random.seed!(42) ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) - - itp = InfiniteTransferPEPS(ipeps) - A = initial_A(itp, χ) + A = initial_A(ipeps, χ) AL, L, λ = left_canonical(A) R, AR, λ = right_canonical(A) - λL, FL = leftenv(AL, adjoint.(AL), itp) - λR, FR = rightenv(AR, adjoint.(AR), itp) + λL, FL = leftenv(AL, adjoint.(AL), ipeps) + λR, FR = rightenv(AR, adjoint.(AR), ipeps) C = LRtoC(L, R) AC = ALCtoAC(AL, C) - λAC, AC = ACenv(AC, FL, FR, itp) + λAC, AC = ACenv(AC, FL, FR, ipeps) λC, C = Cenv( C, FL, FR) S = TensorMap(rand, ComplexF64, χ*D*D'*χ' ← χ*D*D'*χ') function foo1(β) ipeps = β * ipeps - itp = InfiniteTransferPEPS(ipeps) - _, AC = ACenv(AC, FL, FR, itp) + _, AC = ACenv(AC, FL, FR, ipeps) AL, AR, _, _ = ACCtoALAR(AC, C) tol1 = [(@tensor conj(AL[1 2 3 4]) * S[1 2 3 4; 5 6 7 8] * AL[5 6 7 8]) / dot(AL, AL) for AL in AL] tol2 = [(@tensor conj(AR[1 2 3 4]) * S[1 2 3 4; 5 6 7 8] * AR[5 6 7 8]) / dot(AR, AR) for AR in AR] @@ -153,19 +132,18 @@ end ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) ipeps = symmetrize!(ipeps, RotateReflect()) - alg = PEPSKit.VUMPS(maxiter=100, verbosity=2, ifupdown=true) - itp = InfiniteTransferPEPS(ipeps) - rt = PEPSKit.vumps(itp, VUMPSRuntime(itp, χ, alg), alg) + alg = VUMPS(maxiter=100, verbosity=2, ifupdown=false) + rt = leading_boundary(VUMPSRuntime(ipeps, χ, alg), ipeps, alg) function foo1(ipeps) - itp = InfiniteTransferPEPS(ipeps) - env = PEPSKit.leading_boundary(itp, rt, alg) + rt = leading_boundary(rt, ipeps, alg) + env = VUMPSEnv(rt) Z = abs(norm(ipeps, env)) return Z end function foo2(ipeps) - ctm = MPSKit.leading_boundary(CTMRGEnv(ipeps, χ), ipeps, CTMRG(; verbosity=2)) + ctm = leading_boundary(CTMRGEnv(ipeps, χ), ipeps, CTMRG(; verbosity=2)) Z = abs(norm(ipeps, ctm))^(1/Ni/Nj) return Z end @@ -192,25 +170,24 @@ end Random.seed!(50) ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) ipeps = symmetrize!(ipeps, RotateReflect()) - itp = InfiniteTransferPEPS(ipeps) - alg = PEPSKit.VUMPS(maxiter=100, verbosity=2, ifupdown=true) - rt = PEPSKit.vumps(itp, VUMPSRuntime(itp, χ, alg), alg) + alg = VUMPS(maxiter=100, verbosity=2, ifupdown=true) + rt = leading_boundary(VUMPSRuntime(ipeps, χ, alg), ipeps, alg) function foo1(ipeps) - itp = InfiniteTransferPEPS(ipeps) - env = PEPSKit.leading_boundary(itp, rt, alg) + rt = leading_boundary(rt, ipeps, alg) + env = VUMPSEnv(rt, ipeps) Z = abs(norm(ipeps, env)) return Z end function foo2(ipeps) - ctm = MPSKit.leading_boundary(CTMRGEnv(ipeps, χ), ipeps, CTMRG(; verbosity=2)) + ctm = leading_boundary(CTMRGEnv(ipeps, χ), ipeps, CTMRG(; verbosity=2)) Z = abs(norm(ipeps, ctm))^(1/Ni/Nj) return Z end @show foo1(ipeps) - foo2(ipeps) - # @show Zygote.gradient(foo1, ipeps)[1].A Zygote.gradient(foo2, ipeps)[1].A + @show Zygote.gradient(foo1, ipeps)[1] Zygote.gradient(foo2, ipeps)[1].A # @show Zygote.gradient(foo1, ipeps)[1].A - Zygote.gradient(foo2, ipeps)[1].A # @test norm(Zygote.gradient(foo1, ipeps)[1].A - Zygote.gradient(foo2, ipeps)[1].A) < 1e-8 end \ No newline at end of file diff --git a/test/vumps/vumps.jl b/test/vumps/vumps.jl index 4b37f78e..b5f578bd 100644 --- a/test/vumps/vumps.jl +++ b/test/vumps/vumps.jl @@ -1,8 +1,7 @@ using Test using Random using PEPSKit -using MPSKit -using PEPSKit: leading_boundary +using PEPSKit: nearest_neighbour_energy using TensorKit using LinearAlgebra @@ -16,8 +15,7 @@ end Random.seed!(42) ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) - itp = InfiniteTransferPEPS(ipeps) - rt = VUMPSRuntime(itp, χ) + rt = VUMPSRuntime(ipeps, χ) @test rt isa VUMPSRuntime end @@ -26,32 +24,53 @@ end ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) ipeps = symmetrize!(ipeps, RotateReflect()) - alg = PEPSKit.VUMPS(maxiter=100, verbosity=2, ifupdown=false) + alg = VUMPS(maxiter=100, verbosity=2, ifupdown=false) - itp = InfiniteTransferPEPS(ipeps) - env = leading_boundary(itp, VUMPSRuntime(itp, χ, alg), alg) + rt = leading_boundary(VUMPSRuntime(ipeps, χ, alg), ipeps, alg) + env = VUMPSEnv(rt) @test env isa VUMPSEnv Z = abs(norm(ipeps, env)) - ctm = MPSKit.leading_boundary(CTMRGEnv(ipeps, χ), ipeps, CTMRG(; verbosity=2)) + ctm = leading_boundary(CTMRGEnv(ipeps, χ), ipeps, CTMRG(; verbosity=2)) Z′ = abs(norm(ipeps, ctm))^(1/Ni/Nj) @test Z ≈ Z′ rtol = 1e-12 end +@testset "vumps one side runtime energy for unitcell $Ni x $Nj" for Ni in 1:1, Nj in 1:1, (d, D, χ) in zip(ds, Ds, χs) + Random.seed!(100) + ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) + ipeps = symmetrize!(ipeps, RotateReflect()) + + alg = VUMPS(maxiter=100, verbosity=2, ifupdown=false) + + rt = leading_boundary(VUMPSRuntime(ipeps, χ, alg), ipeps, alg) + H = heisenberg_XYZ(InfiniteSquare()) + H = H.terms[1].second + # Hh, Hv = H.terms[1] + + @show nearest_neighbour_energy(ipeps, H, H, rt) + # Z = abs(norm(ipeps, env)) + + # ctm = leading_boundary(CTMRGEnv(ipeps, χ), ipeps, CTMRG(; verbosity=2)) + # Z′ = abs(norm(ipeps, ctm))^(1/Ni/Nj) + + # @test Z ≈ Z′ rtol = 1e-12 +end + @testset "vumps two side runtime for unitcell $Ni x $Nj" for Ni in 1:3, Nj in 1:3, (d, D, χ) in zip(ds, Ds, χs) Random.seed!(42) ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) alg = PEPSKit.VUMPS(maxiter=100, verbosity=2, ifupdown=true) - itp = InfiniteTransferPEPS(ipeps) - env = leading_boundary(itp, VUMPSRuntime(itp, χ, alg), alg) + rt = leading_boundary(VUMPSRuntime(ipeps, χ, alg), ipeps, alg) + env = VUMPSEnv(rt, ipeps) @test env isa VUMPSEnv Z = abs(norm(ipeps, env)) - ctm = MPSKit.leading_boundary(CTMRGEnv(ipeps, χ), ipeps, CTMRG(; verbosity=2)) + ctm = leading_boundary(CTMRGEnv(ipeps, χ), ipeps, CTMRG(; verbosity=2)) Z′ = abs(norm(ipeps, ctm))^(1/Ni/Nj) @test Z ≈ Z′ rtol = 1e-8 diff --git a/test/vumps/vumps_environment.jl b/test/vumps/vumps_environment.jl index 85a6fb4f..88539093 100644 --- a/test/vumps/vumps_environment.jl +++ b/test/vumps/vumps_environment.jl @@ -14,23 +14,11 @@ begin "test utility" χs = [ℂ^4] end -@testset "InfiniteTransferPEPS for unitcell $Ni x $Nj" for Ni in 1:2, Nj in 1:2, (d, D, χ) in zip(ds, Ds, χs) - Random.seed!(42) - ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) - - itp = InfiniteTransferPEPS(ipeps) - @test itp.top == ipeps.A - @test itp.bot == [A' for A in ipeps.A] - @test all(i -> space(i) == (d ← D * D * D' * D'), itp.top) - @test all(i -> space(i) == (D * D * D' * D' ← d), itp.bot) -end - @testset "initialize A C for unitcell $Ni x $Nj" for Ni in 1:2, Nj in 1:2, (d, D, χ) in zip(ds, Ds, χs) Random.seed!(42) ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) - itp = InfiniteTransferPEPS(ipeps) - A = initial_A(itp, χ) + A = initial_A(ipeps, χ) C = initial_C(A) @test size(A) == (Ni, Nj) @test size(C) == (Ni, Nj) @@ -40,8 +28,7 @@ end @testset "getL!, getAL and getLsped for unitcell $Ni x $Nj" for Ni in 1:2, Nj in 1:2, (d, D, χ) in zip(ds, Ds, χs) ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) - itp = InfiniteTransferPEPS(ipeps) - A = initial_A(itp, χ) + A = initial_A(ipeps, χ) C = initial_C(A) C = ρmap(C, A) @@ -64,8 +51,7 @@ end @testset "canonical form for unitcell $Ni x $Nj" for Ni in 1:2, Nj in 1:2, (d, D, χ) in zip(ds, Ds, χs) ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) - itp = InfiniteTransferPEPS(ipeps) - A = initial_A(itp, χ) + A = initial_A(ipeps, χ) AL, L, λ = left_canonical(A) @test all(i -> space(i) == (χ * D * D' ← χ), AL) @@ -84,15 +70,14 @@ end Random.seed!(42) ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) - itp = InfiniteTransferPEPS(ipeps) - A = initial_A(itp, χ) + A = initial_A(ipeps, χ) AL, L, λ = left_canonical(A) R, AR, λ = right_canonical(A) - FL = initial_FL(AL, itp) + FL = initial_FL(AL, ipeps) @test all(i -> space(i) == (χ * D' * D ← χ), FL) - FR = initial_FR(AR, itp) + FR = initial_FR(AR, ipeps) @test all(i -> space(i) == (χ * D * D' ← χ), FR) end @@ -100,21 +85,20 @@ end Random.seed!(42) ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) - itp = InfiniteTransferPEPS(ipeps) - A = initial_A(itp, χ) + A = initial_A(ipeps, χ) AL, L, λ = left_canonical(A) R, AR, λ = right_canonical(A) - λL, FL = leftenv(AL, adjoint.(AL), itp; ifobs) - λR, FR = rightenv(AR, adjoint.(AR), itp; ifobs) + λL, FL = leftenv(AL, adjoint.(AL), ipeps; ifobs) + λR, FR = rightenv(AR, adjoint.(AR), ipeps; ifobs) @test all(i -> space(i) == (χ * D' * D ← χ), FL) @test all(i -> space(i) == (χ * D * D' ← χ), FR) for i in 1:Ni ir = ifobs ? Ni + 1 - i : mod1(i + 1, Ni) - @test λL[i] * FL[i,:] ≈ FLmap(FL[i,:], AL[i,:], adjoint.(AL)[ir,:], itp.top[i,:], itp.bot[i,:]) rtol = 1e-12 - @test λR[i] * FR[i,:] ≈ FRmap(FR[i,:], AR[i,:], adjoint.(AR)[ir,:], itp.top[i,:], itp.bot[i,:]) rtol = 1e-12 + @test λL[i] * FL[i,:] ≈ FLmap(FL[i,:], AL[i,:], adjoint.(AL)[ir,:], ipeps[i,:], adjoint.(ipeps[i,:])) rtol = 1e-12 + @test λR[i] * FR[i,:] ≈ FRmap(FR[i,:], AR[i,:], adjoint.(AR)[ir,:], ipeps[i,:], adjoint.(ipeps[i,:])) rtol = 1e-12 end end @@ -122,25 +106,24 @@ end Random.seed!(42) ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) - itp = InfiniteTransferPEPS(ipeps) - A = initial_A(itp, χ) + A = initial_A(ipeps, χ) AL, L, λ = left_canonical(A) R, AR, λ = right_canonical(A) - λL, FL = leftenv(AL, adjoint.(AL), itp) - λR, FR = rightenv(AR, adjoint.(AR), itp) + λL, FL = leftenv(AL, adjoint.(AL), ipeps) + λR, FR = rightenv(AR, adjoint.(AR), ipeps) C = LRtoC(L, R) AC = ALCtoAC(AL, C) - λAC, AC = ACenv(AC, FL, FR, itp) + λAC, AC = ACenv(AC, FL, FR, ipeps) λC, C = Cenv( C, FL, FR) @test all(i -> space(i) == (χ * D * D' ← χ), AC) @test all(i -> space(i) == (χ ← χ), C) for j in 1:Nj jr = mod1(j + 1, Nj) - @test λAC[j] * AC[:,j] ≈ ACmap(AC[:,j], FL[:,j], FR[:,j], itp.top[:,j], itp.bot[:,j]) rtol = 1e-12 + @test λAC[j] * AC[:,j] ≈ ACmap(AC[:,j], FL[:,j], FR[:,j], ipeps[:,j], adjoint.(ipeps[:,j])) rtol = 1e-12 @test λC[j] * C[:,j] ≈ Cmap( C[:,j], FL[:,jr], FR[:,j]) rtol = 1e-10 end end @@ -149,18 +132,17 @@ end Random.seed!(42) ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) - itp = InfiniteTransferPEPS(ipeps) - A = initial_A(itp, χ) + A = initial_A(ipeps, χ) AL, L, λ = left_canonical(A) R, AR, λ = right_canonical(A) - λL, FL = leftenv(AL, adjoint.(AL), itp) - λR, FR = rightenv(AR, adjoint.(AR), itp) + λL, FL = leftenv(AL, adjoint.(AL), ipeps) + λR, FR = rightenv(AR, adjoint.(AR), ipeps) C = LRtoC(L, R) AC = ALCtoAC(AL, C) - λAC, AC = ACenv(AC, FL, FR, itp) + λAC, AC = ACenv(AC, FL, FR, ipeps) λC, C = Cenv( C, FL, FR) AL, AR, errL, errR = ACCtoALAR(AC, C) @@ -176,8 +158,7 @@ end Random.seed!(42) ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) - itp = InfiniteTransferPEPS(ipeps) - A = initial_A(itp, χ) + A = initial_A(ipeps, χ) AL, L, λ = left_canonical(A) R, AR, λ = right_canonical(A) From 1dd02a13c3fa5a74dc995b2cc59faea8e2ed3da6 Mon Sep 17 00:00:00 2001 From: XingyuZhang2018 <864129714@qq.com> Date: Wed, 30 Oct 2024 12:02:55 +0100 Subject: [PATCH 21/25] delete some things --- src/algorithms/vumps/vumps_iter.jl | 62 -------- src/environments/transferpepo_environments.jl | 103 ------------- src/environments/transferpeps_environments.jl | 135 ------------------ test/heisenberg_vumps.jl | 4 +- 4 files changed, 2 insertions(+), 302 deletions(-) delete mode 100644 src/algorithms/vumps/vumps_iter.jl delete mode 100644 src/environments/transferpepo_environments.jl delete mode 100644 src/environments/transferpeps_environments.jl diff --git a/src/algorithms/vumps/vumps_iter.jl b/src/algorithms/vumps/vumps_iter.jl deleted file mode 100644 index 4914408a..00000000 --- a/src/algorithms/vumps/vumps_iter.jl +++ /dev/null @@ -1,62 +0,0 @@ -function vumps_iter(ψ::InfiniteMPS, H, alg, envs, ϵ) - (st, pr, de) = vumps_iter(convert(MPSMultiline, ψ), Multiline([H]), alg, envs, ϵ) - return convert(InfiniteMPS, st), pr, de -end - -using MPSKit: gaugefix!, _firstspace -function vumps_iter(ψ::MPSMultiline, H, alg::VUMPS, envs, ϵ) - ACs = Zygote.Buffer(ψ.AC) - Cs = Zygote.Buffer(ψ.CR) - - iter = alg.maxiter - alg_eigsolve = updatetol(alg.alg_eigsolve, iter, ϵ) - for col in 1:size(ψ, 2) - H_AC = ∂∂AC(col, ψ, H, envs) - ac = RecursiveVec(ψ.AC[:, col]) - _, ac′ = MPSKit.fixedpoint(H_AC, ac, :LM, alg_eigsolve) - ACs[:, col] = ac′.vecs[:] - - H_C = ∂∂C(col, ψ, H, envs) - c = RecursiveVec(ψ.CR[:, col]) - _, c′ = MPSKit.fixedpoint(H_C, c, :LM, alg_eigsolve) - Cs[:, col] = c′.vecs[:] - end - - # normalize - ACs = [AC / norm(AC) for AC in copy(ACs)] - Cs = [C / norm(C) for C in copy(Cs)] - - ALs = [regauge(AC, C) for (AC, C) in zip(ACs, Cs)] - ARs = [regauge(C, AC) for (C, AC) in zip(Cs, ACs)] - ACs = [AL * C for (AL, C) in zip(ALs, Cs)] - # ACs2 = [_transpose_front(C * _transpose_tail(AR)) for (C, AR) in zip(Cs, ARs)] - # @show norm(ACs1[1] - ACs2[1]) - - # ψ = MPSMultiline(vec([InfiniteMPS(ALs[i, :], ARs[i, :], Cs[i, :], ACs[i, :]) for i in size(ALs, 1)])) - - data = map(eachrow(ALs), eachrow(ARs), eachrow(Cs), eachrow(ACs)) do ALrow, ARrow, Crow, ACrow - InfiniteMPS(ALrow, ARrow, Crow, ACrow) - end - ψ = MPSMultiline(data) - - # alg_environments = updatetol(alg.alg_environments, iter, ϵ) - # @show typeof(envs) typeof(ψ) - # recalculate!(envs, ψ; alg_environments.tol) - - return ψ, envs, ϵ -end - -function regauge(AC::GenericMPSTensor, CR::MPSBondTensor; alg=QRpos()) - Q_AC, _ = leftorth(AC; alg) - Q_C, _ = leftorth(CR; alg) - return Q_AC * Q_C' -end - -function regauge(CL::MPSBondTensor, AC::GenericMPSTensor; alg=LQpos()) - AC_tail = _transpose_tail(AC) - _, Q_AC = rightorth(AC_tail; alg) - _, Q_C = rightorth(CL; alg) - AR_tail = Q_C' * Q_AC - return _transpose_front(AR_tail) -end - diff --git a/src/environments/transferpepo_environments.jl b/src/environments/transferpepo_environments.jl deleted file mode 100644 index f79d641b..00000000 --- a/src/environments/transferpepo_environments.jl +++ /dev/null @@ -1,103 +0,0 @@ - -function MPSKit.environments(state::InfiniteMPS, O::InfiniteTransferPEPO; kwargs...) - return environments( - convert(MPSMultiline, state), convert(TransferPEPOMultiline, O); kwargs... - ) -end - -function MPSKit.environments( - state::MPSMultiline, O::TransferPEPOMultiline; solver=MPSKit.Defaults.eigsolver -) - (lw, rw) = MPSKit.mixed_fixpoints(state, O, state; solver) - return MPSKit.PerMPOInfEnv(nothing, O, state, solver, lw, rw, ReentrantLock()) -end - -function MPSKit.mixed_fixpoints( - above::MPSMultiline, - O::TransferPEPOMultiline, - below::MPSMultiline, - init=gen_init_fps(above, O, below); - solver=MPSKit.Defaults.eigsolver, -) - T = eltype(above) - - (numrows, numcols) = size(above) - @assert size(above) == size(O) - @assert size(below) == size(O) - - envtype = eltype(init[1]) - lefties = PeriodicArray{envtype,2}(undef, numrows, numcols) - righties = PeriodicArray{envtype,2}(undef, numrows, numcols) - - @threads for cr in 1:numrows - c_above = above[cr] # TODO: Update index convention to above[cr - 1] - c_below = below[cr + 1] - - (L0, R0) = init[cr] - - @sync begin - Threads.@spawn begin - E_LL = TransferMatrix($c_above.AL, $O[cr], $c_below.AL) - (_, Ls, convhist) = eigsolve(flip(E_LL), $L0, 1, :LM, $solver) - convhist.converged < 1 && - @info "left eigenvalue failed to converge $(convhist.normres)" - L0 = first(Ls) - end - - Threads.@spawn begin - E_RR = TransferMatrix($c_above.AR, $O[cr], $c_below.AR) - (_, Rs, convhist) = eigsolve(E_RR, $R0, 1, :LM, $solver) - convhist.converged < 1 && - @info "right eigenvalue failed to converge $(convhist.normres)" - R0 = first(Rs) - end - end - - lefties[cr, 1] = L0 - for loc in 2:numcols - lefties[cr, loc] = - lefties[cr, loc - 1] * - TransferMatrix(c_above.AL[loc - 1], O[cr, loc - 1], c_below.AL[loc - 1]) - end - - renormfact::scalartype(T) = dot(c_below.CR[0], PEPO_∂∂C(L0, R0) * c_above.CR[0]) - - righties[cr, end] = R0 / sqrt(renormfact) - lefties[cr, 1] /= sqrt(renormfact) - - for loc in (numcols - 1):-1:1 - righties[cr, loc] = - TransferMatrix(c_above.AR[loc + 1], O[cr, loc + 1], c_below.AR[loc + 1]) * - righties[cr, loc + 1] - - renormfact = dot( - c_below.CR[loc], - PEPO_∂∂C(lefties[cr, loc + 1], righties[cr, loc]) * c_above.CR[loc], - ) - righties[cr, loc] /= sqrt(renormfact) - lefties[cr, loc + 1] /= sqrt(renormfact) - end - end - - return (lefties, righties) -end - -function gen_init_fps(above::MPSMultiline, O::TransferPEPOMultiline, below::MPSMultiline) - T = eltype(above) - - map(1:size(O, 1)) do cr - L0::T = TensorMap( - rand, - scalartype(T), - left_virtualspace(below, cr + 1, 0) * prod(adjoint.(west_spaces(O[cr], 1))), - left_virtualspace(above, cr, 0), # TODO: Update index convention to above[cr - 1] - ) - R0::T = TensorMap( - rand, - scalartype(T), - right_virtualspace(above, cr, 0) * prod(adjoint.(east_spaces(O[cr], 1))), - right_virtualspace(below, cr + 1, 0), - ) - (L0, R0) - end -end diff --git a/src/environments/transferpeps_environments.jl b/src/environments/transferpeps_environments.jl deleted file mode 100644 index 415270e7..00000000 --- a/src/environments/transferpeps_environments.jl +++ /dev/null @@ -1,135 +0,0 @@ -function MPSKit.environments(state::InfiniteMPS, O::InfiniteTransferPEPS; kwargs...) - return environments( - convert(MPSMultiline, state), convert(TransferPEPSMultiline, O); kwargs... - ) -end - -import MPSKit.MPSMultiline - -function MPSKit.environments( - state::MPSMultiline, O::TransferPEPSMultiline; solver=MPSKit.Defaults.eigsolver -) - (lw, rw) = MPSKit.mixed_fixpoints(state, O, state; solver) - return MPSKit.PerMPOInfEnv(nothing, O, state, solver, lw, rw, ReentrantLock()) -end - -function MPSKit.mixed_fixpoints( - above::MPSMultiline, - O::TransferPEPSMultiline, - below::MPSMultiline, - init=gen_init_fps(above, O, below); - solver=MPSKit.Defaults.eigsolver, -) - T = eltype(above) - - (numrows, numcols) = size(above) - @assert size(above) == size(O) - @assert size(below) == size(O) - - envtype = eltype(init[1]) - # @show envtype - lefties = PeriodicArray{envtype,2}(undef, numrows, numcols) - righties = PeriodicArray{envtype,2}(undef, numrows, numcols) - - # lefties = Zygote.Buffer(envtype, numrows, numcols) - # righties = Zygote.Buffer(envtype, numrows, numcols) - lefties = Zygote.Buffer(lefties) - righties = Zygote.Buffer(righties) - for cr in 1:numrows - c_above = above[cr] # TODO: Update index convention to above[cr - 1] - c_below = below[cr + 1] - - (L0, R0) = init[cr] - - E_LL = TransferMatrix(c_above.AL, O[cr], c_below.AL) - (_, Ls, convhist) = eigsolve(flip(E_LL), L0, 1, :LM, solver) - convhist.converged < 1 && - @info "left eigenvalue failed to converge $(convhist.normres)" - L0 = first(Ls) - - E_RR = TransferMatrix(c_above.AR, O[cr], c_below.AR) - (_, Rs, convhist) = eigsolve(E_RR, R0, 1, :LM, solver) - convhist.converged < 1 && - @info "right eigenvalue failed to converge $(convhist.normres)" - R0 = first(Rs) - - lefties[cr, 1] = L0 - for loc in 2:numcols - lefties[cr, loc] = - lefties[cr, loc - 1] * - TransferMatrix(c_above.AL[loc - 1], O[cr, loc - 1], c_below.AL[loc - 1]) - end - - renormfact::scalartype(T) = dot(c_below.CR[0], PEPS_∂∂C(L0, R0) * c_above.CR[0]) - - righties[cr, end] = R0 / sqrt(renormfact) - lefties[cr, 1] /= sqrt(renormfact) - - for loc in (numcols - 1):-1:1 - righties[cr, loc] = - TransferMatrix(c_above.AR[loc + 1], O[cr, loc + 1], c_below.AR[loc + 1]) * - righties[cr, loc + 1] - - renormfact = dot( - c_below.CR[loc], - PEPS_∂∂C(lefties[cr, loc + 1], righties[cr, loc]) * c_above.CR[loc], - ) - righties[cr, loc] /= sqrt(renormfact) - lefties[cr, loc + 1] /= sqrt(renormfact) - end - end - - return (copy(lefties), copy(righties)) -end - -function gen_init_fps(above::MPSMultiline, O::TransferPEPSMultiline, below::MPSMultiline) - T = eltype(above) - - map(1:size(O, 1)) do cr - L0::T = TensorMap( - rand, - scalartype(T), - left_virtualspace(below, cr + 1, 0) * - space(O[cr].top[1], 5)' * - space(O[cr].bot[1], 5), - left_virtualspace(above, cr, 0), # TODO: Update index convention to above[cr - 1] - ) - R0::T = TensorMap( - rand, - scalartype(T), - right_virtualspace(above, cr, 0) * - space(O[cr].top[1], 3)' * - space(O[cr].bot[1], 3), - right_virtualspace(below, cr + 1, 0), - ) - (L0, R0) - end -end - -function MPSKit.transfer_spectrum( - above::MPSMultiline, - O::TransferPEPSMultiline, - below::MPSMultiline, - init=gen_init_fps(above, O, below); - num_vals=2, - solver=MPSKit.Defaults.eigsolver, -) - @assert size(above) == size(O) - @assert size(below) == size(O) - - numrows = size(above, 1) - envtype = eltype(init[1]) - eigenvals = Vector{Vector{scalartype(envtype)}}(undef, numrows) - - @threads for cr in 1:numrows - L0, = init[cr] - - E_LL = TransferMatrix(above[cr - 1].AL, O[cr], below[cr + 1].AL) # Note that this index convention is different from above! - λ, _, convhist = eigsolve(flip(E_LL), L0, num_vals, :LM, solver) - convhist.converged < num_vals && - @warn "correlation length failed to converge: normres = $(convhist.normres)" - eigenvals[cr] = λ - end - - return eigenvals -end diff --git a/test/heisenberg_vumps.jl b/test/heisenberg_vumps.jl index 36430e54..de1a61e6 100644 --- a/test/heisenberg_vumps.jl +++ b/test/heisenberg_vumps.jl @@ -29,6 +29,6 @@ psi_init = InfinitePEPS(2, χbond; unitcell=(1, 1)) env_init = VUMPSRuntime(psi_init, χenv) # find fixedpoint -result = fixedpoint(psi_init, H, opt_alg, env_init; -symmetrization=RotateReflect()); +result = fixedpoint(psi_init, H, opt_alg, env_init; + symmetrization=RotateReflect()); @test result.E ≈ -0.66023 atol = 1e-4 From da2adff5b81aacf2818336c2141b37774c8042fe Mon Sep 17 00:00:00 2001 From: XingyuZhang2018 <864129714@qq.com> Date: Wed, 30 Oct 2024 17:13:58 +0100 Subject: [PATCH 22/25] two side vumps --- .../contractions/vumps_contractions.jl | 54 +++++++++++-------- src/algorithms/peps_opt.jl | 4 +- src/algorithms/toolbox.jl | 7 +-- src/algorithms/vumps/vumps.jl | 10 ++-- src/environments/vumps_environments.jl | 13 +++-- src/states/infinitepeps.jl | 4 ++ test/heisenberg_vumps.jl | 41 ++++++++++---- test/vumps/gradparts.jl | 24 ++++----- 8 files changed, 99 insertions(+), 58 deletions(-) diff --git a/src/algorithms/contractions/vumps_contractions.jl b/src/algorithms/contractions/vumps_contractions.jl index 9b15458c..d94cab3f 100644 --- a/src/algorithms/contractions/vumps_contractions.jl +++ b/src/algorithms/contractions/vumps_contractions.jl @@ -173,28 +173,40 @@ function Cmap(Cj::Vector{<:AbstractTensorMap}, return circshift(Cm, 1) end -function nearest_neighbour_energy(ipeps::InfinitePEPS, Hh, Hv, rt::VUMPSRuntime) - @unpack AL, C, AR, FL, FR = rt - - AC = ALCtoAC(AL, C) +function nearest_neighbour_energy(ipeps::InfinitePEPS, Hh, Hv, env::VUMPSEnv) + @unpack ACu, ARu, ACd, ARd, FLu, FRu, FLo, FRo = env Ni, Nj = size(ipeps) - (Ni, Nj) == (1, 1) || throw(ArgumentError("Only 1x1 unitcell is supported for one side VUMPSRuntime")) - - At = ipeps.A[1] - Ab = adjoint(ipeps.A[1]) - @tensoropt oph[-1 -2; -3 -4] := FL[1][18 12 15; 5] * AC[1][5 6 7; 8] * At[-1; 6 13 19 12] * Ab[7 16 20 15; -3] * - conj(AC[1][18 19 20; 21]) * AR[1][8 9 10; 11] * At[-2; 9 14 22 13] * Ab[10 17 23 16; -4] * - conj(AR[1][21 22 23; 24]) * FR[1][11 14 17; 24] - - @tensor eh = oph[1 2; 3 4] * Hh[3 4; 1 2] - @tensor nh = oph[1 2; 1 2] - - @tensoropt opv[-1 -2; -3 -4] := FL[1][21 19 20; 18] * AC[1][18 12 15 5] * At[-1; 12 6 13 19] * Ab[15 7 16 20; -3] * - FR[1][5 6 7; 8] * FL[1][24 22 23; 21] * At[-2; 13 9 14 22] * Ab[16 10 17 23; -4] * - FR[1][8 9 10; 11] * conj(AC[1][24 14 17; 11]) - @tensor ev = opv[1 2; 3 4] * Hv[3 4; 1 2] - @tensor nv = opv[1 2; 1 2] + energy_tol = 0 + for j in 1:Nj, i in 1:Ni + # horizontal contraction + id = Ni + 1 - i + jr = mod1(j + 1, Nj) + @tensoropt oph[-1 -2; -3 -4] := FLo[i,j][18 12 15; 5] * ACu[i,j][5 6 7; 8] * ipeps.A[i,j][-1; 6 13 19 12] * + conj(ipeps.A[i,j][-3; 7 16 20 15]) * conj(ACd[id,j][18 19 20; 21]) * + ARu[i,jr][8 9 10; 11] * ipeps.A[i,jr][-2; 9 14 22 13] * + conj(ipeps.A[i,jr][-4; 10 17 23 16]) * conj(ARd[id,jr][21 22 23; 24]) * FRo[i,jr][11 14 17; 24] + + @tensor eh = oph[1 2; 3 4] * Hh[3 4; 1 2] + @tensor nh = oph[1 2; 1 2] + energy_tol += eh / nh + @show eh / nh + + # vertical contraction + ir = mod1(i + 1, Ni) + @tensoropt opv[-1 -2; -3 -4] := FLu[i,j][21 19 20; 18] * ACu[i,j][18 12 15 5] * ipeps.A[i,j][-1; 12 6 13 19] * + conj(ipeps.A[i,j][-3; 15 7 16 20]) * FRu[i,j][5 6 7; 8] * FLo[ir,j][24 22 23; 21] * + ipeps.A[ir,j][-2; 13 9 14 22] * conj(ipeps.A[ir,j][-4; 16 10 17 23]) * + FRo[ir,j][8 9 10; 11] * conj(ACd[id,j][24 14 17; 11]) + + @tensor ev = opv[1 2; 3 4] * Hv[3 4; 1 2] + @tensor nv = opv[1 2; 1 2] + energy_tol += ev / nv + @show ev / nv + + # penalty term + energy_tol += 0.1 * abs(eh / nh - eh / nh) + end - return eh / nh + ev / nv + return energy_tol end \ No newline at end of file diff --git a/src/algorithms/peps_opt.jl b/src/algorithms/peps_opt.jl index 36d76230..09fcf3f3 100644 --- a/src/algorithms/peps_opt.jl +++ b/src/algorithms/peps_opt.jl @@ -150,7 +150,7 @@ function fixedpoint( ψ₀::InfinitePEPS{T}, H, alg::PEPSOptimize, - env₀::Union{CTMRGEnv, VUMPSRuntime}=CTMRGEnv(ψ₀, field(T)^20); + env₀=CTMRGEnv(ψ₀, field(T)^20); (finalize!)=OptimKit._finalize!, symmetrization=nothing, ) where {T} @@ -179,7 +179,7 @@ function fixedpoint( return costfun(ψ, envs´, H) end g = only(gs) # `withgradient` returns tuple of gradients `gs` - envs isa VUMPSRuntime && (g = InfinitePEPS(g.A)) # KrylovKit patch + envs isa Union{VUMPSRuntime, Tuple{VUMPSRuntime, VUMPSRuntime}} && (g = InfinitePEPS(g.A)) # KrylovKit patch return E, g end diff --git a/src/algorithms/toolbox.jl b/src/algorithms/toolbox.jl index 586367f1..bc6c99ea 100644 --- a/src/algorithms/toolbox.jl +++ b/src/algorithms/toolbox.jl @@ -6,14 +6,15 @@ function expectation_value(peps::InfinitePEPS, O::LocalOperator, envs::CTMRGEnv) end end -function expectation_value(peps::InfinitePEPS, O::LocalOperator, rt::VUMPSRuntime) +function expectation_value(peps::InfinitePEPS, O::LocalOperator, rt::Union{VUMPSRuntime, Tuple{VUMPSRuntime, VUMPSRuntime}}) checklattice(peps, O) + env = VUMPSEnv(rt, peps) Hh = O.terms[1].second Hv = O.terms[2].second - return nearest_neighbour_energy(peps, Hh, Hv, rt) + return nearest_neighbour_energy(peps, Hh, Hv, env) end -function costfun(peps::InfinitePEPS, envs::Union{CTMRGEnv, VUMPSRuntime}, O::LocalOperator) +function costfun(peps::InfinitePEPS, envs, O::LocalOperator) E = expectation_value(peps, O, envs) ignore_derivatives() do isapprox(imag(E), 0; atol=sqrt(eps(real(E)))) || diff --git a/src/algorithms/vumps/vumps.jl b/src/algorithms/vumps/vumps.jl index 20ab3a22..59c5589e 100644 --- a/src/algorithms/vumps/vumps.jl +++ b/src/algorithms/vumps/vumps.jl @@ -1,13 +1,11 @@ -@kwdef mutable struct VUMPS{F} +@kwdef mutable struct VUMPS ifupdown::Bool = true tol::Float64 = Defaults.contr_tol maxiter::Int = Defaults.contr_maxiter miniter::Int = Defaults.contr_miniter - finalize::F = Defaults._finalize verbosity::Int = Defaults.verbosity end -VUMPSRuntime(ipeps::InfinitePEPS, χ::Int) = VUMPSRuntime(ipeps, ℂ^χ) function VUMPSRuntime(ipeps::InfinitePEPS, χ::VectorSpace) A = initial_A(ipeps, χ) AL, L, _ = left_canonical(A) @@ -32,7 +30,7 @@ function _down_ipeps(ipeps::InfinitePEPS) return InfinitePEPS(copy(ipepsd)) end -@non_differentiable VUMPSRuntime(ipeps::InfinitePEPS, χ::VectorSpace, alg::VUMPS) +VUMPSRuntime(ipeps::InfinitePEPS, χ::Int, alg::VUMPS) = VUMPSRuntime(ipeps, ℂ^χ, alg) function VUMPSRuntime(ipeps::InfinitePEPS, χ::VectorSpace, alg::VUMPS) Ni, Nj = size(ipeps) @@ -49,6 +47,7 @@ function VUMPSRuntime(ipeps::InfinitePEPS, χ::VectorSpace, alg::VUMPS) return rtup end end +@non_differentiable VUMPSRuntime(ipeps::InfinitePEPS, χ::VectorSpace, alg::VUMPS) function vumps_itr(rt::VUMPSRuntime, ipeps::InfinitePEPS, alg::VUMPS) t = Zygote.@ignore time() @@ -70,7 +69,7 @@ function leading_boundary(rt::VUMPSRuntime, ipeps::InfinitePEPS, alg::VUMPS) return vumps_itr(rt, ipeps, alg) end -function VUMPSEnv(rt::VUMPSRuntime) +function VUMPSEnv(rt::VUMPSRuntime, ::InfinitePEPS) @unpack AL, AR, C, FL, FR = rt AC = ALCtoAC(AL, C) return VUMPSEnv(AC, AR, AC, AR, FL, FR, FL, FR) @@ -96,7 +95,6 @@ function VUMPSEnv(rt::Tuple{VUMPSRuntime, VUMPSRuntime}, ipeps::InfinitePEPS) ALd, ARd, Cd = rtdown.AL, rtdown.AR, rtdown.C ACd = ALCtoAC(ALd, Cd) - # to do fix the follow index _, FLo = leftenv(ALu, adjoint.(ALd), ipeps, FLu; ifobs = true) _, FRo = rightenv(ARu, adjoint.(ARd), ipeps, FRu; ifobs = true) diff --git a/src/environments/vumps_environments.jl b/src/environments/vumps_environments.jl index c922f13b..63c1bd88 100644 --- a/src/environments/vumps_environments.jl +++ b/src/environments/vumps_environments.jl @@ -84,6 +84,13 @@ function update!(env::VUMPSRuntime, env´::VUMPSRuntime) env.FR .= env´.FR return env end + +function update!(env::Tuple{VUMPSRuntime, VUMPSRuntime}, env´::Tuple{VUMPSRuntime, VUMPSRuntime}) + update!(env[1], env´[1]) + update!(env[2], env´[2]) + return env +end + """ ```` @@ -286,7 +293,7 @@ function leftenv(ALu::Matrix{<:AbstractTensorMap}, FL′ = Zygote.Buffer(FL) for i in 1:Ni ir = ifobs ? Ni + 1 - i : mod1(i + 1, Ni) - λLs, FL1s, info = eigsolve(FLi -> FLmap(FLi, ALu[i,:], ALd[ir,:], ipeps[i,:], adjoint.(ipeps[i,:])), + λLs, FL1s, info = eigsolve(FLi -> FLmap(FLi, ALu[i,:], ALd[ir,:], ipeps.A[i,:], adjoint.(ipeps.A[i,:])), FL[i,:], 1, :LM; maxiter=100, ishermitian = false, kwargs...) verbosity >= 1 && info.converged == 0 && @warn "leftenv not converged" λL[i], FL′[i,:] = selectpos(λLs, FL1s, Nj) @@ -351,7 +358,7 @@ function rightenv(ARu::Matrix{<:AbstractTensorMap}, for i in 1:Ni ir = ifobs ? Ni + 1 - i : mod1(i + 1, Ni) ifinline && (ir = i) - λRs, FR1s, info = eigsolve(FR -> FRmap(FR, ARu[i,:], ARd[ir,:], ipeps[i,:], adjoint.(ipeps[i,:])), + λRs, FR1s, info = eigsolve(FR -> FRmap(FR, ARu[i,:], ARd[ir,:], ipeps.A[i,:], adjoint.(ipeps.A[i,:])), FR[i,:], 1, :LM; maxiter=100, ishermitian = false, kwargs...) verbosity >= 1 && info.converged == 0 && @warn "rightenv not converged" λR[i], FR′[i,:] = selectpos(λRs, FR1s, Nj) @@ -413,7 +420,7 @@ function ACenv(AC::Matrix{<:AbstractTensorMap}, λAC = Zygote.Buffer(zeros(eltype(ipeps[1]),Nj)) AC′ = Zygote.Buffer(AC) for j in 1:Nj - λACs, ACs, info = eigsolve(AC -> ACmap(AC, FL[:,j], FR[:,j], ipeps[:,j], adjoint.(ipeps[:,j])), + λACs, ACs, info = eigsolve(AC -> ACmap(AC, FL[:,j], FR[:,j], ipeps.A[:,j], adjoint.(ipeps.A[:,j])), AC[:,j], 1, :LM; maxiter=100, ishermitian = false, kwargs...) verbosity >= 1 && info.converged == 0 && @warn "ACenv Not converged" λAC[j], AC′[:,j] = selectpos(λACs, ACs, Ni) diff --git a/src/states/infinitepeps.jl b/src/states/infinitepeps.jl index 0a7d63aa..e6236a62 100644 --- a/src/states/infinitepeps.jl +++ b/src/states/infinitepeps.jl @@ -134,6 +134,10 @@ Base.:/(ψ::InfinitePEPS, α::Number) = InfinitePEPS(ψ.A / α) LinearAlgebra.dot(ψ₁::InfinitePEPS, ψ₂::InfinitePEPS) = dot(ψ₁.A, ψ₂.A) LinearAlgebra.norm(ψ::InfinitePEPS) = norm(ψ.A) +## not a nice solution, but it works +Base.:+(ipeps::InfinitePEPS, x::NamedTuple) = InfinitePEPS(ipeps.A .+ x.A) +Base.:+(x::NamedTuple, ipeps::InfinitePEPS) = InfinitePEPS(ipeps.A .+ x.A) + ## (Approximate) equality function Base.:(==)(ψ₁::InfinitePEPS, ψ₂::InfinitePEPS) return all(zip(ψ₁.A, ψ₂.A)) do (p₁, p₂) diff --git a/test/heisenberg_vumps.jl b/test/heisenberg_vumps.jl index de1a61e6..55f51026 100644 --- a/test/heisenberg_vumps.jl +++ b/test/heisenberg_vumps.jl @@ -8,27 +8,46 @@ using OptimKit # initialize parameters χbond = 2 χenv = 16 + +# initialize states +Random.seed!(91283219347) +H = heisenberg_XYZ(InfiniteSquare()) +psi_init = InfinitePEPS(2, χbond; unitcell=(1, 1)) + +# find fixedpoint one-site vumps boundary_alg = VUMPS( ifupdown=false, tol=1e-10, - miniter=4, + miniter=0, maxiter=10, verbosity=2 ) opt_alg = PEPSOptimize(; boundary_alg, - optimizer=LBFGS(4; maxiter=100, gradtol=1e-8, verbosity=2), + optimizer=LBFGS(4; maxiter=100, gradtol=1e-6, verbosity=2), gradient_alg=nothing, reuse_env=true ) - -# initialize states -Random.seed!(91283219347) -H = heisenberg_XYZ(InfiniteSquare()) -psi_init = InfinitePEPS(2, χbond; unitcell=(1, 1)) -env_init = VUMPSRuntime(psi_init, χenv) - -# find fixedpoint +env_init = VUMPSRuntime(psi_init, χenv, boundary_alg) result = fixedpoint(psi_init, H, opt_alg, env_init; - symmetrization=RotateReflect()); + symmetrization=RotateReflect() + ); @test result.E ≈ -0.66023 atol = 1e-4 + +# find fixedpoint two-site vumps +boundary_alg = VUMPS( + ifupdown=true, + tol=1e-10, + miniter=0, + maxiter=10, + verbosity=2 +) +opt_alg = PEPSOptimize(; + boundary_alg, + optimizer=LBFGS(4; maxiter=100, gradtol=1e-6, verbosity=2), + gradient_alg=nothing, + reuse_env=true +) +env_init = VUMPSRuntime(psi_init, χenv, boundary_alg) +result = fixedpoint(psi_init, H, opt_alg, env_init); +@test result.E ≈ -0.66251 atol = 1e-4 \ No newline at end of file diff --git a/test/vumps/gradparts.jl b/test/vumps/gradparts.jl index 959c2f4d..b227ab92 100644 --- a/test/vumps/gradparts.jl +++ b/test/vumps/gradparts.jl @@ -30,7 +30,7 @@ end @test Zygote.gradient(f, 1.0)[1] ≈ num_grad(f, 1.0) end -@testset "leftenv and rightenv for unitcell $Ni x $Nj" for Ni in 1:2, Nj in 1:2, (d, D, χ) in zip(ds, Ds, χs), ifobs in [true, false] +@testset "leftenv and rightenv for unitcell $Ni x $Nj" for Ni in 1:1, Nj in 1:1, (d, D, χ) in zip(ds, Ds, χs), ifobs in [true, false] Random.seed!(50) ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) @@ -44,25 +44,25 @@ end S1 = TensorMap(rand, ComplexF64, χ*D'*D*χ' ← χ*D'*D*χ') S2 = TensorMap(rand, ComplexF64, χ*D*D'*χ' ← χ*D*D'*χ') - function foo1(β) - ipeps = β * ipeps + function foo1(ipeps) + # ipeps = β * ipeps _, FL = leftenv(AL, adjoint.(AL), ipeps; ifobs) tol = [(@tensor conj(FL[1 2 3 4]) * S1[1 2 3 4; 5 6 7 8] * FL[5 6 7 8]) / dot(FL, FL) for FL in FL] return norm(tol) end - @test Zygote.gradient(foo1, 1.0)[1] ≈ num_grad(foo1, 1.0) atol = 1e-8 - - function foo2(β) - ipeps = β * ipeps + # @test Zygote.gradient(foo1, 1.0)[1] ≈ num_grad(foo1, 1.0) atol = 1e-8 + @show typeof(Zygote.gradient(foo1, ipeps)[1]) + # function foo2(β) + # ipeps = β * ipeps - _, FR = rightenv(AR, adjoint.(AR), ipeps; ifobs) + # _, FR = rightenv(AR, adjoint.(AR), ipeps; ifobs) - tol = [(@tensor conj(FR[1 2 3 4]) * S2[1 2 3 4; 5 6 7 8] * FR[5 6 7 8]) / dot(FR, FR) for FR in FR] - return norm(tol) - end - @test Zygote.gradient(foo2, 1.0)[1] ≈ num_grad(foo2, 1.0) atol = 1e-8 + # tol = [(@tensor conj(FR[1 2 3 4]) * S2[1 2 3 4; 5 6 7 8] * FR[5 6 7 8]) / dot(FR, FR) for FR in FR] + # return norm(tol) + # end + # @test Zygote.gradient(foo2, 1.0)[1] ≈ num_grad(foo2, 1.0) atol = 1e-8 end @testset "ACenv and Cenv for unitcell $Ni x $Nj" for Ni in 1:2, Nj in 1:2, (d, D, χ) in zip(ds, Ds, χs) From 3e542c39d2a0215c380d456ad3793c77fb01a30f Mon Sep 17 00:00:00 2001 From: XingyuZhang2018 <864129714@qq.com> Date: Sat, 2 Nov 2024 10:45:10 +0100 Subject: [PATCH 23/25] correct large unit cell index --- .../contractions/vumps_contractions.jl | 42 +++-- src/algorithms/toolbox.jl | 2 +- test/heisenberg_vumps.jl | 162 +++++++++++++----- 3 files changed, 149 insertions(+), 57 deletions(-) diff --git a/src/algorithms/contractions/vumps_contractions.jl b/src/algorithms/contractions/vumps_contractions.jl index d94cab3f..8a816467 100644 --- a/src/algorithms/contractions/vumps_contractions.jl +++ b/src/algorithms/contractions/vumps_contractions.jl @@ -138,7 +138,7 @@ end ``` ┌─────── ACᵢⱼ ─────┐ ┌───── ACᵢ₊₁ⱼ ─────┐ │ │ │ -│ │ │ = FLᵢⱼ ─── Mᵢⱼ ───── FRᵢⱼ +│ │ │ = FLᵢⱼ ─── Oᵢⱼ ───── FRᵢⱼ │ │ │ ``` @@ -173,6 +173,27 @@ function Cmap(Cj::Vector{<:AbstractTensorMap}, return circshift(Cm, 1) end +""" + nearest_neighbour_energy(ipeps::InfinitePEPS, Hh, Hv, env::VUMPSEnv) + + Compute the energy of the nearest neighbour Hamiltonian for an infinite PEPS. + +``` + ┌────── ACuᵢⱼ ────ARuᵢᵣ ──────┐ + │ │ │ │ + FLoᵢⱼ ── Oᵢⱼ ────── Oᵢᵣ ──── FRoᵢᵣ ir = Ni + 1 - i + │ │ │ │ jr = j + 1 + └───── ACdᵢᵣⱼ ─────ARdᵢᵣᵣ─────┘ + + ┌─────── ACuᵢⱼ ─────┐ + │ │ │ + FLuᵢⱼ ─── Oᵢⱼ ───── FRuᵢⱼ ir = i + 1 + │ │ │ irr = Ni - i + FLoᵢᵣⱼ ── Oᵢᵣⱼ ─── FRoᵢᵣⱼ + │ │ │ + └────── ACdᵢᵣᵣⱼ ───┘ +``` +""" function nearest_neighbour_energy(ipeps::InfinitePEPS, Hh, Hv, env::VUMPSEnv) @unpack ACu, ARu, ACd, ARd, FLu, FRu, FLo, FRo = env Ni, Nj = size(ipeps) @@ -180,33 +201,34 @@ function nearest_neighbour_energy(ipeps::InfinitePEPS, Hh, Hv, env::VUMPSEnv) energy_tol = 0 for j in 1:Nj, i in 1:Ni # horizontal contraction - id = Ni + 1 - i + ir = Ni + 1 - i jr = mod1(j + 1, Nj) @tensoropt oph[-1 -2; -3 -4] := FLo[i,j][18 12 15; 5] * ACu[i,j][5 6 7; 8] * ipeps.A[i,j][-1; 6 13 19 12] * - conj(ipeps.A[i,j][-3; 7 16 20 15]) * conj(ACd[id,j][18 19 20; 21]) * + conj(ipeps.A[i,j][-3; 7 16 20 15]) * conj(ACd[ir,j][18 19 20; 21]) * ARu[i,jr][8 9 10; 11] * ipeps.A[i,jr][-2; 9 14 22 13] * - conj(ipeps.A[i,jr][-4; 10 17 23 16]) * conj(ARd[id,jr][21 22 23; 24]) * FRo[i,jr][11 14 17; 24] + conj(ipeps.A[i,jr][-4; 10 17 23 16]) * conj(ARd[ir,jr][21 22 23; 24]) * FRo[i,jr][11 14 17; 24] @tensor eh = oph[1 2; 3 4] * Hh[3 4; 1 2] @tensor nh = oph[1 2; 1 2] energy_tol += eh / nh - @show eh / nh - + @show eh / nh eh nh + # vertical contraction ir = mod1(i + 1, Ni) + irr = mod1(Ni - i, Ni) @tensoropt opv[-1 -2; -3 -4] := FLu[i,j][21 19 20; 18] * ACu[i,j][18 12 15 5] * ipeps.A[i,j][-1; 12 6 13 19] * conj(ipeps.A[i,j][-3; 15 7 16 20]) * FRu[i,j][5 6 7; 8] * FLo[ir,j][24 22 23; 21] * ipeps.A[ir,j][-2; 13 9 14 22] * conj(ipeps.A[ir,j][-4; 16 10 17 23]) * - FRo[ir,j][8 9 10; 11] * conj(ACd[id,j][24 14 17; 11]) + FRo[ir,j][8 9 10; 11] * conj(ACd[irr,j][24 14 17; 11]) @tensor ev = opv[1 2; 3 4] * Hv[3 4; 1 2] @tensor nv = opv[1 2; 1 2] energy_tol += ev / nv - @show ev / nv + @show ev / nv ev nv # penalty term - energy_tol += 0.1 * abs(eh / nh - eh / nh) + # energy_tol += 0.1 * abs(eh / nh - eh / nh) end - return energy_tol + return energy_tol/Ni/Nj end \ No newline at end of file diff --git a/src/algorithms/toolbox.jl b/src/algorithms/toolbox.jl index bc6c99ea..787db82a 100644 --- a/src/algorithms/toolbox.jl +++ b/src/algorithms/toolbox.jl @@ -7,7 +7,7 @@ function expectation_value(peps::InfinitePEPS, O::LocalOperator, envs::CTMRGEnv) end function expectation_value(peps::InfinitePEPS, O::LocalOperator, rt::Union{VUMPSRuntime, Tuple{VUMPSRuntime, VUMPSRuntime}}) - checklattice(peps, O) + # checklattice(peps, O) env = VUMPSEnv(rt, peps) Hh = O.terms[1].second Hv = O.terms[2].second diff --git a/test/heisenberg_vumps.jl b/test/heisenberg_vumps.jl index 55f51026..5c3b9710 100644 --- a/test/heisenberg_vumps.jl +++ b/test/heisenberg_vumps.jl @@ -4,50 +4,120 @@ using PEPSKit using TensorKit using KrylovKit using OptimKit +using Printf -# initialize parameters -χbond = 2 -χenv = 16 - -# initialize states -Random.seed!(91283219347) -H = heisenberg_XYZ(InfiniteSquare()) -psi_init = InfinitePEPS(2, χbond; unitcell=(1, 1)) - -# find fixedpoint one-site vumps -boundary_alg = VUMPS( - ifupdown=false, - tol=1e-10, - miniter=0, - maxiter=10, - verbosity=2 -) -opt_alg = PEPSOptimize(; - boundary_alg, - optimizer=LBFGS(4; maxiter=100, gradtol=1e-6, verbosity=2), - gradient_alg=nothing, - reuse_env=true -) -env_init = VUMPSRuntime(psi_init, χenv, boundary_alg) -result = fixedpoint(psi_init, H, opt_alg, env_init; - symmetrization=RotateReflect() - ); -@test result.E ≈ -0.66023 atol = 1e-4 - -# find fixedpoint two-site vumps -boundary_alg = VUMPS( - ifupdown=true, - tol=1e-10, - miniter=0, - maxiter=10, - verbosity=2 -) -opt_alg = PEPSOptimize(; - boundary_alg, - optimizer=LBFGS(4; maxiter=100, gradtol=1e-6, verbosity=2), - gradient_alg=nothing, - reuse_env=true -) -env_init = VUMPSRuntime(psi_init, χenv, boundary_alg) -result = fixedpoint(psi_init, H, opt_alg, env_init); -@test result.E ≈ -0.66251 atol = 1e-4 \ No newline at end of file +@testset "heisenberg_XYZ 1x1 unitcell C4 symmetry" begin + Random.seed!(100) + # initialize parameters + χbond = 2 + χenv = 16 + + # initialize states + H = heisenberg_XYZ(InfiniteSquare(); Jx=1.0, Jy=1.0, Jz=1.0) + psi_init = InfinitePEPS(2, χbond; unitcell=(1, 1)) + + # find fixedpoint one-site ctmrg + boundary_alg = VUMPS( + ifupdown=false, + tol=1e-10, + miniter=3, + maxiter=10, + verbosity=1 + ) + opt_alg = PEPSOptimize(; + boundary_alg, + optimizer=LBFGS(20; maxiter=100, gradtol=1e-6, verbosity=2), + gradient_alg=nothing, + reuse_env=true + ) + + t = time() + function finalize!(x, f, g, numiter) + print(@sprintf("%.3f sec", time()-t)) + return x, f, g + end + + env_init = VUMPSRuntime(psi_init, χenv, boundary_alg) + result = fixedpoint(psi_init, H, opt_alg, env_init; + symmetrization=RotateReflect(), + finalize! + ); + @test result.E ≈ -0.66023 atol = 1e-4 +end + +@testset "heisenberg_XYZ 1x1 unitcell without C4 symmetry" begin + Random.seed!(100) + # initialize parameters + χbond = 2 + χenv = 16 + + # initialize states + H = heisenberg_XYZ(InfiniteSquare()) + psi_init = InfinitePEPS(2, χbond; unitcell=(1, 1)) + + # find fixedpoint one-site ctmrg + boundary_alg = VUMPS( + ifupdown=true, + tol=1e-10, + miniter=3, + maxiter=10, + verbosity=1 + ) + opt_alg = PEPSOptimize(; + boundary_alg, + optimizer=LBFGS(20; maxiter=100, gradtol=1e-6, verbosity=2), + gradient_alg=nothing, + reuse_env=true + ) + + t = time() + function finalize!(x, f, g, numiter) + print(@sprintf("%.3f sec", time()-t)) + return x, f, g + end + + env_init = VUMPSRuntime(psi_init, χenv, boundary_alg) + result = fixedpoint(psi_init, H, opt_alg, env_init; + finalize! + ); + @test result.E ≈ -0.66251 atol = 1e-4 +end + +@testset "heisenberg_XYZ 2x2 unitcell without C4 symmetry" begin + Random.seed!(42) + # initialize parameters + χbond = 2 + χenv = 16 + + # initialize states + H = heisenberg_XYZ(InfiniteSquare(); Jx=1.0, Jy=1.0, Jz=1.0) + psi_init = InfinitePEPS(2, χbond; unitcell=(2, 2)) + + # find fixedpoint one-site ctmrg + boundary_alg = VUMPS( + ifupdown=true, + tol=1e-10, + miniter=3, + maxiter=10, + verbosity=2 + ) + opt_alg = PEPSOptimize(; + boundary_alg, + optimizer=LBFGS(20; maxiter=100, gradtol=1e-6, verbosity=2), + gradient_alg=nothing, + reuse_env=true + ) + + t = time() + function finalize!(x, f, g, numiter) + print(@sprintf("%.3f sec", time()-t)) + return x, f, g + end + + env_init = VUMPSRuntime(psi_init, χenv, boundary_alg) + result = fixedpoint(psi_init, H, opt_alg, env_init; + finalize! + ); + @show result.E + # @test result.E ≈ -0.66251 atol = 1e-4 +end From 03c0e82fe6158561fd6f0c335a5f9faf9347e4bf Mon Sep 17 00:00:00 2001 From: XingyuZhang2018 <864129714@qq.com> Date: Thu, 7 Nov 2024 10:10:29 +0100 Subject: [PATCH 24/25] backup --- test/heisenberg_vumps.jl | 16 ++++++------ test/vumps/gradparts.jl | 53 ++++++++++++++++++++-------------------- test/vumps/vumps.jl | 5 ++-- 3 files changed, 38 insertions(+), 36 deletions(-) diff --git a/test/heisenberg_vumps.jl b/test/heisenberg_vumps.jl index 5c3b9710..f6cd018f 100644 --- a/test/heisenberg_vumps.jl +++ b/test/heisenberg_vumps.jl @@ -10,10 +10,10 @@ using Printf Random.seed!(100) # initialize parameters χbond = 2 - χenv = 16 + χenv = 10 # initialize states - H = heisenberg_XYZ(InfiniteSquare(); Jx=1.0, Jy=1.0, Jz=1.0) + H = heisenberg_XYZ(InfiniteSquare()) psi_init = InfinitePEPS(2, χbond; unitcell=(1, 1)) # find fixedpoint one-site ctmrg @@ -49,7 +49,7 @@ end Random.seed!(100) # initialize parameters χbond = 2 - χenv = 16 + χenv = 10 # initialize states H = heisenberg_XYZ(InfiniteSquare()) @@ -59,7 +59,7 @@ end boundary_alg = VUMPS( ifupdown=true, tol=1e-10, - miniter=3, + miniter=1, maxiter=10, verbosity=1 ) @@ -90,15 +90,15 @@ end χenv = 16 # initialize states - H = heisenberg_XYZ(InfiniteSquare(); Jx=1.0, Jy=1.0, Jz=1.0) - psi_init = InfinitePEPS(2, χbond; unitcell=(2, 2)) + H = heisenberg_XYZ(InfiniteSquare()) + psi_init = InfinitePEPS(2, χbond; unitcell=(2, 1)) # find fixedpoint one-site ctmrg boundary_alg = VUMPS( ifupdown=true, tol=1e-10, - miniter=3, - maxiter=10, + miniter=10, + maxiter=1, verbosity=2 ) opt_alg = PEPSOptimize(; diff --git a/test/vumps/gradparts.jl b/test/vumps/gradparts.jl index b227ab92..360d1f17 100644 --- a/test/vumps/gradparts.jl +++ b/test/vumps/gradparts.jl @@ -30,7 +30,7 @@ end @test Zygote.gradient(f, 1.0)[1] ≈ num_grad(f, 1.0) end -@testset "leftenv and rightenv for unitcell $Ni x $Nj" for Ni in 1:1, Nj in 1:1, (d, D, χ) in zip(ds, Ds, χs), ifobs in [true, false] +@testset "leftenv and rightenv for unitcell $Ni x $Nj" for Ni in 1:2, Nj in 1:2, (d, D, χ) in zip(ds, Ds, χs), ifobs in [true, false] Random.seed!(50) ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) @@ -41,28 +41,28 @@ end λL, FL = leftenv(AL, adjoint.(AL), ipeps; ifobs) λR, FR = rightenv(AR, adjoint.(AR), ipeps; ifobs) - S1 = TensorMap(rand, ComplexF64, χ*D'*D*χ' ← χ*D'*D*χ') - S2 = TensorMap(rand, ComplexF64, χ*D*D'*χ' ← χ*D*D'*χ') + S1 = TensorMap(randn, ComplexF64, χ*D'*D*χ' ← χ*D'*D*χ') + S2 = TensorMap(randn, ComplexF64, χ*D*D'*χ' ← χ*D*D'*χ') - function foo1(ipeps) - # ipeps = β * ipeps + function foo1(β) + ipeps = β * ipeps _, FL = leftenv(AL, adjoint.(AL), ipeps; ifobs) tol = [(@tensor conj(FL[1 2 3 4]) * S1[1 2 3 4; 5 6 7 8] * FL[5 6 7 8]) / dot(FL, FL) for FL in FL] return norm(tol) end - # @test Zygote.gradient(foo1, 1.0)[1] ≈ num_grad(foo1, 1.0) atol = 1e-8 - @show typeof(Zygote.gradient(foo1, ipeps)[1]) - # function foo2(β) - # ipeps = β * ipeps + @test Zygote.gradient(foo1, 1.0)[1] ≈ num_grad(foo1, 1.0) atol = 1e-8 + + function foo2(β) + ipeps = β * ipeps - # _, FR = rightenv(AR, adjoint.(AR), ipeps; ifobs) + _, FR = rightenv(AR, adjoint.(AR), ipeps; ifobs) - # tol = [(@tensor conj(FR[1 2 3 4]) * S2[1 2 3 4; 5 6 7 8] * FR[5 6 7 8]) / dot(FR, FR) for FR in FR] - # return norm(tol) - # end - # @test Zygote.gradient(foo2, 1.0)[1] ≈ num_grad(foo2, 1.0) atol = 1e-8 + tol = [(@tensor conj(FR[1 2 3 4]) * S2[1 2 3 4; 5 6 7 8] * FR[5 6 7 8]) / dot(FR, FR) for FR in FR] + return norm(tol) + end + @test Zygote.gradient(foo2, 1.0)[1] ≈ num_grad(foo2, 1.0) atol = 1e-8 end @testset "ACenv and Cenv for unitcell $Ni x $Nj" for Ni in 1:2, Nj in 1:2, (d, D, χ) in zip(ds, Ds, χs) @@ -115,7 +115,7 @@ end λAC, AC = ACenv(AC, FL, FR, ipeps) λC, C = Cenv( C, FL, FR) - S = TensorMap(rand, ComplexF64, χ*D*D'*χ' ← χ*D*D'*χ') + S = TensorMap(randn, ComplexF64, χ*D*D'*χ' ← χ*D*D'*χ') function foo1(β) ipeps = β * ipeps _, AC = ACenv(AC, FL, FR, ipeps) @@ -137,7 +137,7 @@ end function foo1(ipeps) rt = leading_boundary(rt, ipeps, alg) - env = VUMPSEnv(rt) + env = VUMPSEnv(rt, ipeps) Z = abs(norm(ipeps, env)) return Z end @@ -148,8 +148,7 @@ end return Z end - # @show foo1(ipeps) - foo2(ipeps) - + @show norm(foo1(ipeps) - foo2(ipeps)) < 1e-8 @test norm(Zygote.gradient(foo1, ipeps)[1].A - Zygote.gradient(foo2, ipeps)[1].A) < 1e-8 end @@ -166,28 +165,30 @@ end @test Zygote.gradient(f, 1.0)[1] ≈ num_grad(f, 1.0) end -@testset "ad vumps iPEPS two side for unitcell $Ni x $Nj" for Ni in 1:1, Nj in 1:1, (d, D, χ) in zip(ds, Ds, χs) - Random.seed!(50) +@testset "ad vumps iPEPS two side for unitcell $Ni x $Nj" for Ni in 2:2, Nj in 1:1, (d, D, χ) in zip(ds, Ds, [10]) + Random.seed!(42) ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) - ipeps = symmetrize!(ipeps, RotateReflect()) - alg = VUMPS(maxiter=100, verbosity=2, ifupdown=true) + alg = VUMPS(maxiter=100, verbosity=3, ifupdown=true) rt = leading_boundary(VUMPSRuntime(ipeps, χ, alg), ipeps, alg) + function foo1(ipeps) + alg = VUMPS(maxiter=2, verbosity=3, ifupdown=true) rt = leading_boundary(rt, ipeps, alg) env = VUMPSEnv(rt, ipeps) Z = abs(norm(ipeps, env)) return Z end + Zygote.gradient(foo1, ipeps)[1] function foo2(ipeps) ctm = leading_boundary(CTMRGEnv(ipeps, χ), ipeps, CTMRG(; verbosity=2)) Z = abs(norm(ipeps, ctm))^(1/Ni/Nj) return Z end - @show foo1(ipeps) - foo2(ipeps) - @show Zygote.gradient(foo1, ipeps)[1] Zygote.gradient(foo2, ipeps)[1].A - # @show Zygote.gradient(foo1, ipeps)[1].A - Zygote.gradient(foo2, ipeps)[1].A - # @test norm(Zygote.gradient(foo1, ipeps)[1].A - Zygote.gradient(foo2, ipeps)[1].A) < 1e-8 + + # @test norm(foo1(ipeps) - foo2(ipeps)) < 1e-6 + @show norm(Zygote.gradient(foo1, ipeps)[1].A - Zygote.gradient(foo2, ipeps)[1].A) + # @test norm(Zygote.gradient(foo1, ipeps)[1].A - Zygote.gradient(foo2, ipeps)[1].A) < 1e-5 end \ No newline at end of file diff --git a/test/vumps/vumps.jl b/test/vumps/vumps.jl index b5f578bd..5bc03862 100644 --- a/test/vumps/vumps.jl +++ b/test/vumps/vumps.jl @@ -27,7 +27,7 @@ end alg = VUMPS(maxiter=100, verbosity=2, ifupdown=false) rt = leading_boundary(VUMPSRuntime(ipeps, χ, alg), ipeps, alg) - env = VUMPSEnv(rt) + env = VUMPSEnv(rt, ipeps) @test env isa VUMPSEnv Z = abs(norm(ipeps, env)) @@ -46,11 +46,12 @@ end alg = VUMPS(maxiter=100, verbosity=2, ifupdown=false) rt = leading_boundary(VUMPSRuntime(ipeps, χ, alg), ipeps, alg) + env = VUMPSEnv(rt, ipeps) H = heisenberg_XYZ(InfiniteSquare()) H = H.terms[1].second # Hh, Hv = H.terms[1] - @show nearest_neighbour_energy(ipeps, H, H, rt) + @show nearest_neighbour_energy(ipeps, H, H, env) # Z = abs(norm(ipeps, env)) # ctm = leading_boundary(CTMRGEnv(ipeps, χ), ipeps, CTMRG(; verbosity=2)) From 14e97ed2aa5059749a890814f0a3ab3f01e88048 Mon Sep 17 00:00:00 2001 From: XingyuZhang2018 <864129714@qq.com> Date: Fri, 8 Nov 2024 14:40:54 +0100 Subject: [PATCH 25/25] alg_rrule=KrylovKit.GMRES() for degeneracy --- src/algorithms/contractions/vumps_contractions.jl | 4 ++-- src/environments/vumps_environments.jl | 12 ++++++------ test/heisenberg_vumps.jl | 6 +++--- test/vumps/gradparts.jl | 3 +-- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/algorithms/contractions/vumps_contractions.jl b/src/algorithms/contractions/vumps_contractions.jl index 8a816467..ecab0335 100644 --- a/src/algorithms/contractions/vumps_contractions.jl +++ b/src/algorithms/contractions/vumps_contractions.jl @@ -211,7 +211,7 @@ function nearest_neighbour_energy(ipeps::InfinitePEPS, Hh, Hv, env::VUMPSEnv) @tensor eh = oph[1 2; 3 4] * Hh[3 4; 1 2] @tensor nh = oph[1 2; 1 2] energy_tol += eh / nh - @show eh / nh eh nh + # @show eh / nh eh nh # vertical contraction ir = mod1(i + 1, Ni) @@ -224,7 +224,7 @@ function nearest_neighbour_energy(ipeps::InfinitePEPS, Hh, Hv, env::VUMPSEnv) @tensor ev = opv[1 2; 3 4] * Hv[3 4; 1 2] @tensor nv = opv[1 2; 1 2] energy_tol += ev / nv - @show ev / nv ev nv + # @show ev / nv ev nv # penalty term # energy_tol += 0.1 * abs(eh / nh - eh / nh) diff --git a/src/environments/vumps_environments.jl b/src/environments/vumps_environments.jl index 63c1bd88..33d28650 100644 --- a/src/environments/vumps_environments.jl +++ b/src/environments/vumps_environments.jl @@ -294,7 +294,7 @@ function leftenv(ALu::Matrix{<:AbstractTensorMap}, for i in 1:Ni ir = ifobs ? Ni + 1 - i : mod1(i + 1, Ni) λLs, FL1s, info = eigsolve(FLi -> FLmap(FLi, ALu[i,:], ALd[ir,:], ipeps.A[i,:], adjoint.(ipeps.A[i,:])), - FL[i,:], 1, :LM; maxiter=100, ishermitian = false, kwargs...) + FL[i,:], 1, :LM; alg_rrule=KrylovKit.GMRES(), maxiter=100, ishermitian = false, kwargs...) verbosity >= 1 && info.converged == 0 && @warn "leftenv not converged" λL[i], FL′[i,:] = selectpos(λLs, FL1s, Nj) end @@ -326,7 +326,7 @@ function leftCenv(ALu::Matrix{<:AbstractTensorMap}, for i in 1:Ni ir = ifobs ? mod1(Ni - i + 2, Ni) : i λLs, L1s, info = eigsolve(L -> Lmap(L, ALu[i,:], ALd[ir,:]), - L[i,:], 1, :LM; maxiter=100, ishermitian = false, kwargs...) + L[i,:], 1, :LM; alg_rrule=KrylovKit.GMRES(), maxiter=100, ishermitian = false, kwargs...) verbosity >= 1 && info.converged == 0 && @warn "leftenv not converged" λL[i], L′[i,:] = selectpos(λLs, L1s, Nj) end @@ -359,7 +359,7 @@ function rightenv(ARu::Matrix{<:AbstractTensorMap}, ir = ifobs ? Ni + 1 - i : mod1(i + 1, Ni) ifinline && (ir = i) λRs, FR1s, info = eigsolve(FR -> FRmap(FR, ARu[i,:], ARd[ir,:], ipeps.A[i,:], adjoint.(ipeps.A[i,:])), - FR[i,:], 1, :LM; maxiter=100, ishermitian = false, kwargs...) + FR[i,:], 1, :LM; alg_rrule=KrylovKit.GMRES(), maxiter=100, ishermitian = false, kwargs...) verbosity >= 1 && info.converged == 0 && @warn "rightenv not converged" λR[i], FR′[i,:] = selectpos(λRs, FR1s, Nj) end @@ -391,7 +391,7 @@ function rightCenv(ARu::Matrix{<:AbstractTensorMap}, for i in 1:Ni ir = ifobs ? mod1(Ni - i + 2, Ni) : i λRs, R1s, info = eigsolve(R -> Rmap(R, ARu[i,:], ARd[ir,:]), - R[i,:], 1, :LM; maxiter=100, ishermitian = false, kwargs...) + R[i,:], 1, :LM; alg_rrule=KrylovKit.GMRES(), maxiter=100, ishermitian = false, kwargs...) verbosity >= 1 && info.converged == 0 && @warn "rightenv not converged" λR[i], R′[i,:] = selectpos(λRs, R1s, Nj) end @@ -421,7 +421,7 @@ function ACenv(AC::Matrix{<:AbstractTensorMap}, AC′ = Zygote.Buffer(AC) for j in 1:Nj λACs, ACs, info = eigsolve(AC -> ACmap(AC, FL[:,j], FR[:,j], ipeps.A[:,j], adjoint.(ipeps.A[:,j])), - AC[:,j], 1, :LM; maxiter=100, ishermitian = false, kwargs...) + AC[:,j], 1, :LM; alg_rrule=KrylovKit.GMRES(), maxiter=100, ishermitian = false, kwargs...) verbosity >= 1 && info.converged == 0 && @warn "ACenv Not converged" λAC[j], AC′[:,j] = selectpos(λACs, ACs, Ni) end @@ -454,7 +454,7 @@ function Cenv(C::Matrix{<:AbstractTensorMap}, for j in 1:Nj jr = mod1(j + 1, Nj) λCs, Cs, info = eigsolve(C -> Cmap(C, FL[:,jr], FR[:,j]), - C[:,j], 1, :LM; maxiter=100, ishermitian = false, kwargs...) + C[:,j], 1, :LM; alg_rrule=KrylovKit.GMRES(), maxiter=100, ishermitian = false, kwargs...) verbosity >= 1 && info.converged == 0 && @warn "Cenv Not converged" λC[j], C′[:,j] = selectpos(λCs, Cs, Ni) end diff --git a/test/heisenberg_vumps.jl b/test/heisenberg_vumps.jl index f6cd018f..c90b9f1f 100644 --- a/test/heisenberg_vumps.jl +++ b/test/heisenberg_vumps.jl @@ -91,14 +91,14 @@ end # initialize states H = heisenberg_XYZ(InfiniteSquare()) - psi_init = InfinitePEPS(2, χbond; unitcell=(2, 1)) + psi_init = InfinitePEPS(2, χbond; unitcell=(2, 2)) # find fixedpoint one-site ctmrg boundary_alg = VUMPS( ifupdown=true, tol=1e-10, - miniter=10, - maxiter=1, + miniter=1, + maxiter=10, verbosity=2 ) opt_alg = PEPSOptimize(; diff --git a/test/vumps/gradparts.jl b/test/vumps/gradparts.jl index 360d1f17..7d619a12 100644 --- a/test/vumps/gradparts.jl +++ b/test/vumps/gradparts.jl @@ -165,14 +165,13 @@ end @test Zygote.gradient(f, 1.0)[1] ≈ num_grad(f, 1.0) end -@testset "ad vumps iPEPS two side for unitcell $Ni x $Nj" for Ni in 2:2, Nj in 1:1, (d, D, χ) in zip(ds, Ds, [10]) +@testset "ad vumps iPEPS two side for unitcell $Ni x $Nj" for Ni in 2:2, Nj in 2:2, (d, D, χ) in zip(ds, Ds, [10]) Random.seed!(42) ipeps = InfinitePEPS(d, D; unitcell=(Ni, Nj)) alg = VUMPS(maxiter=100, verbosity=3, ifupdown=true) rt = leading_boundary(VUMPSRuntime(ipeps, χ, alg), ipeps, alg) - function foo1(ipeps) alg = VUMPS(maxiter=2, verbosity=3, ifupdown=true) rt = leading_boundary(rt, ipeps, alg)