From cb6b2a3290c9f43d5ab65d80214aaae710646286 Mon Sep 17 00:00:00 2001 From: leburgel Date: Fri, 26 Sep 2025 08:50:01 +0200 Subject: [PATCH 1/8] Add `initialize_environment` --- src/PEPSKit.jl | 3 ++ src/algorithms/ctmrg/initialization.jl | 52 ++++++++++++++++++++++++++ src/networks/infinitesquarenetwork.jl | 1 + 3 files changed, 56 insertions(+) create mode 100644 src/algorithms/ctmrg/initialization.jl diff --git a/src/PEPSKit.jl b/src/PEPSKit.jl index 9e1c24b74..1ae7f42a7 100644 --- a/src/PEPSKit.jl +++ b/src/PEPSKit.jl @@ -64,6 +64,7 @@ include("algorithms/ctmrg/projectors.jl") include("algorithms/ctmrg/simultaneous.jl") include("algorithms/ctmrg/sequential.jl") include("algorithms/ctmrg/gaugefix.jl") +include("algorithms/ctmrg/initialization.jl") include("algorithms/truncation/truncationschemes.jl") include("algorithms/truncation/fullenv_truncation.jl") @@ -87,6 +88,8 @@ using .Defaults: set_scheduler! export set_scheduler! export SVDAdjoint, FullSVDReverseRule, IterSVD export CTMRGEnv, SequentialCTMRG, SimultaneousCTMRG +export initialize_environment, + RandomInitialization, ProductStateInitialization, ApplicationInitialization export FixedSpaceTruncation, SiteDependentTruncation export HalfInfiniteProjector, FullInfiniteProjector export LocalOperator, physicalspace diff --git a/src/algorithms/ctmrg/initialization.jl b/src/algorithms/ctmrg/initialization.jl new file mode 100644 index 000000000..cb5a5eebf --- /dev/null +++ b/src/algorithms/ctmrg/initialization.jl @@ -0,0 +1,52 @@ +abstract type InitializationStyle end +struct ProductStateInitialization <: InitializationStyle end +struct RandomInitialization <: InitializationStyle end +struct ApplicationInitialization <: InitializationStyle end + +function initialize_environment( + elt::Type{<:Number}, + n::InfiniteSquareNetwork, + ::RandomInitialization, + init_spec::ElementarySpace = oneunit(spacetype(n)), # TODO: non-uniform space specification? + ) + return CTMRGEnv(randn, elt, n, init_spec) +end + +function initialize_environment( + elt::Type{<:Number}, + n::InfiniteSquareNetwork, + ::ProductStateInitialization, + init_spec::ElementarySpace = oneunit(spacetype(n)), # TODO: non-uniform space specification? + ) + i = one(sectortype(init_spec)) + env = CTMRGEnv(ones, elt, n, init_spec) + for (dir, r, c) in Iterators.product(axes(env)...) + @assert i in blocksectors(env.corners[dir, r, c]) + block(env.corners[dir, r, c], i)[1, 1] = 1 + end + return env +end + +function initialize_environment( + elt::Type{<:Number}, + n::InfiniteSquareNetwork, + ::ApplicationInitialization, + init_spec::TruncationScheme; + boundary_alg = (; + alg = :sequential, tol = 1.0e-5, maxiter = 10, verbosity = -1, trscheme = init_spec, + ) + ) + env = initialize_environment(elt, n, ProductStateInitialization()) + env, = leading_boundary(env, n; boundary_alg...) + return env +end + +function initialize_environment(n::InfiniteSquareNetwork, args...; kwargs...) + return initialize_environment(ComplexF64, n, args...; kwargs...) +end +function initialize_environment(A::Union{InfinitePEPS, InfinitePartitionFunction}, args...; kwargs...) + return initialize_environment(ComplexF64, A, args...; kwargs...) +end +function initialize_environment(elt::Type{<:Number}, A::Union{InfinitePEPS, InfinitePartitionFunction}, args...; kwargs...) + return initialize_environment(elt, InfiniteSquareNetwork(A), args...; kwargs...) +end diff --git a/src/networks/infinitesquarenetwork.jl b/src/networks/infinitesquarenetwork.jl index f003bd095..acb03c036 100644 --- a/src/networks/infinitesquarenetwork.jl +++ b/src/networks/infinitesquarenetwork.jl @@ -55,6 +55,7 @@ end ## Spaces +TensorKit.spacetype(::Type{T}) where {T <: InfiniteSquareNetwork} = spacetype(eltype(T)) virtualspace(n::InfiniteSquareNetwork, r::Int, c::Int, dir) = virtualspace(n[r, c], dir) ## Vector interface From c1216f49098f3f91cc847ee0cbf3ec02a60cafc5 Mon Sep 17 00:00:00 2001 From: leburgel Date: Fri, 26 Sep 2025 11:19:39 +0200 Subject: [PATCH 2/8] Add test --- src/PEPSKit.jl | 2 +- src/algorithms/ctmrg/ctmrg.jl | 2 ++ test/ctmrg/initialization.jl | 51 +++++++++++++++++++++++++++++++++++ test/runtests.jl | 3 +++ 4 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 test/ctmrg/initialization.jl diff --git a/src/PEPSKit.jl b/src/PEPSKit.jl index 1ae7f42a7..a1363d541 100644 --- a/src/PEPSKit.jl +++ b/src/PEPSKit.jl @@ -2,7 +2,7 @@ module PEPSKit using LinearAlgebra, Statistics, Base.Threads, Base.Iterators, Printf using Compat -using Accessors: @set, @reset +using Accessors: @set, @reset, @insert using VectorInterface import VectorInterface as VI diff --git a/src/algorithms/ctmrg/ctmrg.jl b/src/algorithms/ctmrg/ctmrg.jl index a1cba4fc9..9820b6f9e 100644 --- a/src/algorithms/ctmrg/ctmrg.jl +++ b/src/algorithms/ctmrg/ctmrg.jl @@ -88,6 +88,7 @@ containing the following fields: * `truncation_error` : Last (maximal) SVD truncation error of the CTMRG projectors. * `condition_number` : Last (maximal) condition number of the enlarged CTMRG environment. +* `convergence_error` : Convergence error of the CTMRG algorithm at termination. In case the `alg` is a `SimultaneousCTMRG`, the last SVD will also be returned: @@ -120,6 +121,7 @@ function leading_boundary( for iter in 1:(alg.maxiter) env, info = ctmrg_iteration(network, env, alg) # Grow and renormalize in all 4 directions η, CS, TS = calc_convergence(env, CS, TS) + info = @insert info.convergence_error = η if η ≤ alg.tol && iter ≥ alg.miniter ctmrg_logfinish!(log, iter, η, network, env) diff --git a/test/ctmrg/initialization.jl b/test/ctmrg/initialization.jl new file mode 100644 index 000000000..111f602d4 --- /dev/null +++ b/test/ctmrg/initialization.jl @@ -0,0 +1,51 @@ +using Test +using TensorKit +using PEPSKit +using Random + +using MPSKitModels: classical_ising + +sd = 12345 + +# toggle symmetry, but same issue for both +symmetries = [Z2Irrep, Trivial] + +χ = 20 +tol = 1.0e-4 +maxiter = 1000 +verbosity = 2 +trscheme = FixedSpaceTruncation() +boundary_alg = (; + alg = :simultaneous, + tol, + verbosity, + trscheme, + maxiter, +) + +@testset "CTMRG environment initialization for critical ising with $S symmetry (#255)" for S in symmetries + # initialize + T = classical_ising(S) + O = T[1] + n = InfinitePartitionFunction([O O; O O]) + Venv = S == Z2Irrep ? Z2Space(0 => χ / 2, 1 => χ / 2) : ℂ^χ + P = space(O, 2) + + # random, doesn't converge + Random.seed!(sd) + env0_rand = initialize_environment(n, RandomInitialization(), Venv) + env_rand, info = leading_boundary(env0_rand, n; boundary_alg...) + @test info.convergence_error > tol + + # embedded product state, converges + Random.seed!(sd) + env0_prod = initialize_environment(n, ProductStateInitialization(), Venv) + env_prod, info = leading_boundary(env0_prod, n; boundary_alg...) + @test info.convergence_error ≤ tol + + # grown product state, converges + Random.seed!(sd) + env0_appl = initialize_environment(n, ApplicationInitialization(), truncdim(χ)) + env_appl, info = leading_boundary(env0_appl, n; boundary_alg...) + @test info.convergence_error ≤ tol +end diff --git a/test/runtests.jl b/test/runtests.jl index 496fb7437..aa153bd73 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -35,6 +35,9 @@ end @time @safetestset "correlation length" begin include("ctmrg/correlation_length.jl") end + @time @safetestset "initialization" begin + include("ctmrg/initialization.jl") + end end if GROUP == "ALL" || GROUP == "GRADIENTS" @time @safetestset "CTMRG gradients" begin From 2a6f121e6d77796717c37290a438755ae30c7bb5 Mon Sep 17 00:00:00 2001 From: leburgel Date: Fri, 26 Sep 2025 11:26:22 +0200 Subject: [PATCH 3/8] Not converging isn't really passing though --- test/ctmrg/initialization.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/ctmrg/initialization.jl b/test/ctmrg/initialization.jl index 111f602d4..5ed54fcdb 100644 --- a/test/ctmrg/initialization.jl +++ b/test/ctmrg/initialization.jl @@ -35,7 +35,7 @@ boundary_alg = (; Random.seed!(sd) env0_rand = initialize_environment(n, RandomInitialization(), Venv) env_rand, info = leading_boundary(env0_rand, n; boundary_alg...) - @test info.convergence_error > tol + @test_broken info.convergence_error ≤ tol # embedded product state, converges Random.seed!(sd) From 78cef7ca319f0c6820fa52021b1b883aab6057aa Mon Sep 17 00:00:00 2001 From: leburgel Date: Fri, 26 Sep 2025 13:03:14 +0200 Subject: [PATCH 4/8] Pass virtual space specification through to `CTMRGEnv` constructor --- src/algorithms/ctmrg/initialization.jl | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/algorithms/ctmrg/initialization.jl b/src/algorithms/ctmrg/initialization.jl index cb5a5eebf..36bd16f15 100644 --- a/src/algorithms/ctmrg/initialization.jl +++ b/src/algorithms/ctmrg/initialization.jl @@ -3,23 +3,26 @@ struct ProductStateInitialization <: InitializationStyle end struct RandomInitialization <: InitializationStyle end struct ApplicationInitialization <: InitializationStyle end +_to_tuple(x) = (x,) +_to_tuple(x::Tuple) = x + function initialize_environment( elt::Type{<:Number}, n::InfiniteSquareNetwork, ::RandomInitialization, - init_spec::ElementarySpace = oneunit(spacetype(n)), # TODO: non-uniform space specification? + init_spec = oneunit(spacetype(n)), ) - return CTMRGEnv(randn, elt, n, init_spec) + return CTMRGEnv(randn, elt, n, _to_tuple(init_spec)...) end function initialize_environment( elt::Type{<:Number}, n::InfiniteSquareNetwork, ::ProductStateInitialization, - init_spec::ElementarySpace = oneunit(spacetype(n)), # TODO: non-uniform space specification? + init_spec = oneunit(spacetype(n)), ) i = one(sectortype(init_spec)) - env = CTMRGEnv(ones, elt, n, init_spec) + env = CTMRGEnv(ones, elt, n, _to_tuple(init_spec)...) for (dir, r, c) in Iterators.product(axes(env)...) @assert i in blocksectors(env.corners[dir, r, c]) block(env.corners[dir, r, c], i)[1, 1] = 1 From c20aab3e9d13a7983cc0984ed1369398a6dca529 Mon Sep 17 00:00:00 2001 From: leburgel Date: Sun, 28 Sep 2025 12:45:49 +0200 Subject: [PATCH 5/8] Slurp, make an actual product state, and increase coverage --- src/algorithms/ctmrg/initialization.jl | 22 +++++++++++----------- test/ctmrg/initialization.jl | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/algorithms/ctmrg/initialization.jl b/src/algorithms/ctmrg/initialization.jl index 36bd16f15..14325bfa1 100644 --- a/src/algorithms/ctmrg/initialization.jl +++ b/src/algorithms/ctmrg/initialization.jl @@ -3,29 +3,29 @@ struct ProductStateInitialization <: InitializationStyle end struct RandomInitialization <: InitializationStyle end struct ApplicationInitialization <: InitializationStyle end -_to_tuple(x) = (x,) -_to_tuple(x::Tuple) = x - function initialize_environment( elt::Type{<:Number}, n::InfiniteSquareNetwork, ::RandomInitialization, - init_spec = oneunit(spacetype(n)), + virtual_spaces... = oneunit(spacetype(n)), ) - return CTMRGEnv(randn, elt, n, _to_tuple(init_spec)...) + return CTMRGEnv(randn, elt, n, virtual_spaces...) end function initialize_environment( elt::Type{<:Number}, n::InfiniteSquareNetwork, ::ProductStateInitialization, - init_spec = oneunit(spacetype(n)), + virtual_spaces... = oneunit(spacetype(n)), ) - i = one(sectortype(init_spec)) - env = CTMRGEnv(ones, elt, n, _to_tuple(init_spec)...) + i = one(sectortype(n)) + env = CTMRGEnv(ones, elt, n, virtual_spaces...) for (dir, r, c) in Iterators.product(axes(env)...) @assert i in blocksectors(env.corners[dir, r, c]) - block(env.corners[dir, r, c], i)[1, 1] = 1 + for (c, b) in blocks(env.corners[dir, r, c]) + b .= 0 + c == i && (b[1, 1] = 1) + end end return env end @@ -34,9 +34,9 @@ function initialize_environment( elt::Type{<:Number}, n::InfiniteSquareNetwork, ::ApplicationInitialization, - init_spec::TruncationScheme; + trscheme::TruncationScheme; boundary_alg = (; - alg = :sequential, tol = 1.0e-5, maxiter = 10, verbosity = -1, trscheme = init_spec, + alg = :sequential, tol = 1.0e-5, maxiter = 10, verbosity = -1, trscheme, ) ) env = initialize_environment(elt, n, ProductStateInitialization()) diff --git a/test/ctmrg/initialization.jl b/test/ctmrg/initialization.jl index 5ed54fcdb..ba7a2fdd0 100644 --- a/test/ctmrg/initialization.jl +++ b/test/ctmrg/initialization.jl @@ -45,7 +45,7 @@ boundary_alg = (; # grown product state, converges Random.seed!(sd) - env0_appl = initialize_environment(n, ApplicationInitialization(), truncdim(χ)) + env0_appl = initialize_environment(InfiniteSquareNetwork(n), ApplicationInitialization(), truncdim(χ)) env_appl, info = leading_boundary(env0_appl, n; boundary_alg...) @test info.convergence_error ≤ tol end From 11d8535e2a34ba1ab57c7fdb1e6ae64e27a25b70 Mon Sep 17 00:00:00 2001 From: leburgel Date: Sun, 28 Sep 2025 13:19:09 +0200 Subject: [PATCH 6/8] Better optional alg specification --- src/algorithms/ctmrg/initialization.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/algorithms/ctmrg/initialization.jl b/src/algorithms/ctmrg/initialization.jl index 14325bfa1..9308cf128 100644 --- a/src/algorithms/ctmrg/initialization.jl +++ b/src/algorithms/ctmrg/initialization.jl @@ -36,9 +36,10 @@ function initialize_environment( ::ApplicationInitialization, trscheme::TruncationScheme; boundary_alg = (; - alg = :sequential, tol = 1.0e-5, maxiter = 10, verbosity = -1, trscheme, + alg = :sequential, tol = 1.0e-5, maxiter = 10, verbosity = -1, ) ) + boundary_alg = (; boundary_alg..., trscheme) # merge trscheme with optional alg definition env = initialize_environment(elt, n, ProductStateInitialization()) env, = leading_boundary(env, n; boundary_alg...) return env From 991ecc70abb4f21b56c60a2e238e193f69e4ad45 Mon Sep 17 00:00:00 2001 From: Lander Burgelman <39218680+leburgel@users.noreply.github.com> Date: Wed, 1 Oct 2025 10:31:07 +0200 Subject: [PATCH 7/8] Apply suggestions from code review Co-authored-by: Lukas Devos --- src/algorithms/ctmrg/initialization.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/algorithms/ctmrg/initialization.jl b/src/algorithms/ctmrg/initialization.jl index 9308cf128..0dc0cf65d 100644 --- a/src/algorithms/ctmrg/initialization.jl +++ b/src/algorithms/ctmrg/initialization.jl @@ -46,10 +46,10 @@ function initialize_environment( end function initialize_environment(n::InfiniteSquareNetwork, args...; kwargs...) - return initialize_environment(ComplexF64, n, args...; kwargs...) + return initialize_environment(scalartype(n), n, args...; kwargs...) end function initialize_environment(A::Union{InfinitePEPS, InfinitePartitionFunction}, args...; kwargs...) - return initialize_environment(ComplexF64, A, args...; kwargs...) + return initialize_environment(scalartype(A), A, args...; kwargs...) end function initialize_environment(elt::Type{<:Number}, A::Union{InfinitePEPS, InfinitePartitionFunction}, args...; kwargs...) return initialize_environment(elt, InfiniteSquareNetwork(A), args...; kwargs...) From 4996e1bc56ca025e2a79370124fd4ef8f7f1c486 Mon Sep 17 00:00:00 2001 From: leburgel Date: Mon, 6 Oct 2025 11:18:28 +0200 Subject: [PATCH 8/8] Add initialization function to `ProductStateInitialization` struct --- src/algorithms/ctmrg/initialization.jl | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/algorithms/ctmrg/initialization.jl b/src/algorithms/ctmrg/initialization.jl index 0dc0cf65d..45e2d456e 100644 --- a/src/algorithms/ctmrg/initialization.jl +++ b/src/algorithms/ctmrg/initialization.jl @@ -1,15 +1,18 @@ abstract type InitializationStyle end struct ProductStateInitialization <: InitializationStyle end -struct RandomInitialization <: InitializationStyle end +struct RandomInitialization{F} <: InitializationStyle + f::F + RandomInitialization(f::F = randn) where {F} = new{F}(f) +end struct ApplicationInitialization <: InitializationStyle end function initialize_environment( elt::Type{<:Number}, n::InfiniteSquareNetwork, - ::RandomInitialization, + alg::RandomInitialization, virtual_spaces... = oneunit(spacetype(n)), ) - return CTMRGEnv(randn, elt, n, virtual_spaces...) + return CTMRGEnv(alg.f, elt, n, virtual_spaces...) end function initialize_environment(