Skip to content

Issue with SimultaneousCTMRG convergence starting from random initial environment #255

@leburgel

Description

@leburgel

I ran into an issue when running leading_boundary on a $2 \times 2$ InfinitePartitionFunction using SimultaneousCTMRG (originally pointed out by @dartsushi).

Usually, when running leading_boundary at a fixed environment bond dimension $\chi$ using either trscheme = FixedSpaceTruncation() or trscheme = truncdim(χ), I would initialize a CTMRG environment with a total bond dimension $\chi$ first and then plug this into the leading_boundary call. However, it turns out that the default randomly initialized environments can give very bad convergence if you directly intialize them with a nontrivial virtual space. Initializing with a trivial virtual space and growing it solves this, but in this case you can't use FixedSpaceTruncation.

For example, for the 2D classical Ising model with a $2 x 2$ unit cell at criticality:

using TensorKit
using PEPSKit
using Random

using MPSKitModels: classical_ising

Random.seed!(1234) # same problem for many seeds...

# toggle symmetry, but same issue for both
S = Z2Irrep
# S = Trivial

χ = 20
tol = 1.0e-4
maxiter = 1000
verbosity = 2

# 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)
trscheme = FixedSpaceTruncation()

# simultaneous CTMRG: very sensitive to initial guess
simultaneous_alg = (;
    alg = :simultaneous,
    tol,
    verbosity,
    trscheme,
    maxiter,
)
env0 = CTMRGEnv(n, Venv)
env_sim, = leading_boundary(env0, n; simultaneous_alg...)

gives

[ Info: CTMRG init:     obj = -2.222242140629e+01 +1.949978774954e+01im err = 1.0000e+00
┌ Warning: CTMRG cancel 1000:   obj = +3.739239477627e+01 -5.522835410994e-01im err = 2.5066866523e-01  time = 11.77 sec
└ @ PEPSKit ~/ctmbench/lib/PEPSKit.jl/src/algorithms/ctmrg/ctmrg.jl:152

Initializing with a trivial virtual space and growing until truncdim(χ) to grow the environment first seems to avoid this,

env0 = CTMRGEnv(n, oneunit(P))
env_sim, = leading_boundary(env0, n; trscheme = truncdim(χ), simultaneous_alg...)
[ Info: CTMRG init:     obj = +3.397056274848e+01       err = 1.0000e+00
[ Info: CTMRG conv 534: obj = +4.121413131732e+01       err = 9.9855540314e-05  time = 6.24 sec

but this can give a space that is slightly different from the one we want,

space(env_sim.corners[1])
Rep[ℤ₂](0=>11, 1=>9) ← Rep[ℤ₂](0=>11, 1=>9)

For some reason, SequentialCTMRG seems to suffer much less from this problem:

sequential_alg = (;
    alg = :sequential,
    tol,
    verbosity,
    trscheme = FixedSpaceTruncation(),
    maxiter,
)
env0 = CTMRGEnv(n, Venv)
env_seq, = leading_boundary(env0, n; sequential_alg...)
[ Info: CTMRG conv 318: obj = +4.121402200669e+01 -7.312051507224e-05im err = 9.9978661272e-05  time = 4.70 sec
[ Info: CTMRG init:     obj = +3.397056274848e+01       err = 1.0000e+00

To circumvent the problem for SimultaneousCTMRG, sometimes initializing with ones instead of randn stabilizes things, but seems a bit too black magic to actually change the default.

A better solution that seems to really solve things is to initialize an environment with the proper virtualspace Venv by growing it from a trivial virtual space using a few dummy CTMRG iteration with trscheme = truncspace(Venv), and then starting from there,

dummy_alg = (;
    alg = :simultaneous,
    trscheme = truncspace(Venv),
    maxiter = 5,
)
env0 = CTMRGEnv(n, oneunit(P))
env1, = leading_boundary(env0, n; dummy_alg...)
env_sim_better, = leading_boundary(env1, n; simultaneous_alg...)
[ Info: CTMRG init:     obj = +3.397056274848e+01       err = 1.0000e+00
┌ Warning: CTMRG cancel 5:      obj = +4.095118941961e+01       err = 9.9825766951e-02  time = 0.02 sec
└ @ PEPSKit ~/ctmbench/lib/PEPSKit.jl/src/algorithms/ctmrg/ctmrg.jl:152
[ Info: CTMRG init:     obj = +4.095118941961e+01       err = 1.0000e+00
[ Info: CTMRG conv 190: obj = +4.121361334018e+01       err = 9.8857674692e-05  time = 0.82 sec

So long story short, I was wondering if it's sensible to just not use random initializations, but always initialize an environment of with a requested virtual space by growing it from a smaller one?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions