Repository navigation
Description
I ran into an issue when running leading_boundary on a InfinitePartitionFunction using SimultaneousCTMRG (originally pointed out by @dartsushi).
Usually, when running leading_boundary at a fixed environment bond dimension trscheme = FixedSpaceTruncation() or trscheme = truncdim(χ), I would initialize a CTMRG environment with a total bond dimension 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
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?
Activity
dartsushi commentedon Sep 11, 2025
CTMRG is practically computing 2N x 2N open-boundary partition funciton. The initial condition of the boundary tensors then represents the bounadry condition thereof. If we start from bond dimension 1 with ones this corresponds to a fixed boundary condition with a spin in a specific direction. Starting from radn with bond dimension chi, on the other hand, means that your boundary spins are highly entangled in a random way. This seems to be very problematic to me.
pbrehmer commentedon Sep 11, 2025
Thanks for documenting this! I feel that I encountered similar issues with contracting PEPS and randomly initialized environments before but I've never tried to pin them down. Also not sure where the difference between
:simultaneousand:sequentialcomes from and whether that is a systematic thing.I'm wondering whether growing the initial environment from a smaller one generically is the better approach. It seems that using
randninitialized environment with fixed virtual spaces does work reasonably well in many cases. It might still be that in these cases growing the initial environment improves convergence.In any case I think we should have the option to (automatically) initialize from a smaller environment, so I'm linking the roadmap where we actually discussed that it would be useful to have more environment initialization techniques.
Yue-Zhengyuan commentedon Sep 12, 2025
Using random initializations is fine if you first converge for an environment with small χ, and then grow it by relaxing the truncation scheme (using dynamic ones like
truncerr,truncbelowtogether withtruncdim(χ)). For sequential CTMRG it is also likely to fail to converge if you directly set χ to a large value that you want to obtain in the end. The example on fermi-Hubbard simple update demonstrates my usual workflow (here for simplicity I only usedtruncdim).PEPSKit.jl/examples/hubbard_su/main.jl
Lines 75 to 93 in 1ac5857
Yue-Zhengyuan commentedon Sep 12, 2025
BTW, besides of being completely unable to converge, do you sometimes observe that the
objanderrjumps back and forth between two (or a bit more) values? like the following when I try to measure a Gutzwiller-projected Gaussian fermionic PEPS (with SequentialCTMRG):Here the period is 3.
pbrehmer commentedon Sep 12, 2025
I have definitely seen this before (I think with both
:sequentialand:simultaneous) and I've always wondered how these cycles work and what the underlying reason is that CTMRG can get stuck in such a loop.lkdvos commentedon Sep 15, 2025
While I somewhat agree with this intuitive picture, keep in mind that if you start from an MPS with random entries, the spins aren't highly entangled at all, in fact the entanglement basically becomes zero with increasing system size. This is different from starting from a random boundary (dense) state, where you indeed would expect a volume law of entanglement.
Something that might also be relevant, especially when dealing with symmetries is that for iMPS simulations there actually is a very similar kind of pattern, especially when the initialization happens with the wrong distribution of sectors. It seems that in these cases, the local updates are never large enough to redistribute the weight in the different sectors, and therefore the entire algorithm becomes stuck in a local basin. In that sense I would also expect that just starting from a product state in the right phase and gradually growing it helps since the distribution of weights between the different sectors is at least based on (small patches of) the actual PEPS.
It might just be more important that the state is low bond dimension, such that it doesn't prioritize one of the sectors, rather than whether or not the entanglement is high.
I have definitely also noticed these cycles. It might be useful to have a look at the corner entanglement spectra in these cases and see how they change. Sometimes it is really clear that this comes from one value being truncated or not, or multiplets that are being cut, or ...
leburgel commentedon Sep 19, 2025
Okay, setting aside the strange cycles and how to diagnose them, I think the conclusion is that some more robust initialization routines would be useful to many people. The roadmap mostly discusses the use of environments during a full optimization, specifically between iterations. However, I think a good place to start is to just provide some initialization tools in the first place, after which we can think how to integrate this into the optimization.
Specifically, we could provide functions like
initialize_environmentandinitialize_peps(orinitialize_fixedpointwhich combines both?) that take some specification of what we want to end up with (say virtual spaces) and how to get there (say a contraction algorithm, or at least parts that specify one to the degree that we need). This would solve the original problem brought up here, and if properly demonstrated could save people a lot of headaches figuring out why their contractions aren't converging.lkdvos commentedon Sep 19, 2025
I like the idea of designing an initialization interface. I would also like this in MPSKit, do you think there is a way we can share similar call signatures/functions?
leburgel commentedon Sep 19, 2025
I'm sure we can make the signatures match, should be very similar. I can make a PR here which wraps the fix outlined in the issue here into an initialization interface. Then we have an idea how this would look like, and we can discuss what would have to change to make it usable elsewhere and where to best implement it.