Skip to content

Add 3-site simple update (aka 3-site cluster update) #171

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 69 commits into from
May 22, 2025

Conversation

Yue-Zhengyuan
Copy link
Collaborator

This PR adds the 3-site simple update (aka 3-site cluster update; see discussion in Issue #164), which can handle Hamiltonians containing up to next nearest neighbor terms (e.g. the J1-J2 model).

  • It convert the Hamiltonian from LocalOperator format to a bunch of 3-site MPOs acting on the clusters. Relevant functions are added in src/algorithms/time_evolution/evoltools.jl.
  • Truncation of bonds in the 3-site cluster after applying the time evolution gate is done using some "projectors" (I didn't bother to customize OBC MPS algorithms from MPSKit to suit my needs). Their construction is explained in detail in the beginning of the file src/algorithms/time_evolution/simpleupdate3site.jl. It is tested in the new test file test/timeevol/cluster_projectors.jl.
  • Added an J1-J2 model SU example at examples/heisenberg_evol/j1j2.jl. We may also consider using the 3-site SU to provide initialization in the J1-J2 AD test. But note that the 3-site SU also requires a minimal unit cell size (2, 2) (in addition, bipartite structure is now not allowed), while the AD test currently uses 1-site unit cell with C4v symmetry.

This is kind of a large unseparated PR. Suggestions are welcome. I'm still testing fermion models, so the code is not finalized yet.

Copy link

codecov bot commented Apr 9, 2025

Codecov Report

Attention: Patch coverage is 96.74419% with 7 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/operators/localoperator.jl 53.84% 6 Missing ⚠️
src/algorithms/time_evolution/evoltools.jl 97.29% 1 Missing ⚠️
Files with missing lines Coverage Δ
src/PEPSKit.jl 100.00% <ø> (ø)
src/algorithms/time_evolution/simpleupdate.jl 100.00% <100.00%> (+13.04%) ⬆️
src/algorithms/time_evolution/simpleupdate3site.jl 100.00% <100.00%> (ø)
src/algorithms/time_evolution/evoltools.jl 98.36% <97.29%> (-1.64%) ⬇️
src/operators/localoperator.jl 69.09% <53.84%> (+7.88%) ⬆️

... and 2 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@Yue-Zhengyuan
Copy link
Collaborator Author

I further added a test to compare the SU and 3-site SU energy for the Hubbard model without next-nearest neighbor terms (they should be close). I think the code is now ready for fermions.

Copy link
Member

@lkdvos lkdvos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left some general comments throughout, keep in mind that I do not have much experience with the algorithm itself so I definitely might be missing some things or getting things wrong.
As always though, this is an impressive amount of work, and a great addition.

@pbrehmer
Copy link
Collaborator

AD optimization seems to work but it has some hickups at some point due to linesearching. I will try to improve that tomorrow. I also extended the commentary in the J1-J2 example a bit to make it similar style-wise to other examples.

@pbrehmer
Copy link
Collaborator

I decided to just restrict the maxiter of the optimization since the AD-optimized estimate already improves the SU estimate quite a bit and a proper full optimization would probably take long and be more complicated. I added the rendered example as well, so it should show up in the docs now. Ready to merge for me!

@Yue-Zhengyuan
Copy link
Collaborator Author

@pbrehmer I'm glad to see that with SU initialization the AD energy is lower than YASTN result, so maybe a good initialization does help. How does the energy compare with the AD optimization with just 1x1 unit cell starting from random initialization?

@pbrehmer
Copy link
Collaborator

I was also happy to see that! Actually, on a 1x1 unit cell from random initialization, I'm having a lot of trouble to optimize the PEPS. There, I'm encountering degenerate singular values sometimes and CTMRG sometimes struggles to converge during optimization such that the linesearch fails. I also tried Lander's backtracking linesearch algorithm and also there I'm having problems.

So my feeling is that the SU-evolved PEPS is actually quite a nice starting point for the AD optimization. I'll try to optimize that fully (up to higher accuracy) but I suspect that the environment dimension might be a little low for that - for small chi, PEPS optimization runs tend to get stuck at some point.

@Yue-Zhengyuan
Copy link
Collaborator Author

Looking at YASTN data, the first line is

# uuid CTM_BFGS100LS_U1B_D4-chi96-j20.5-run0-c2U1BD4j2045chi96n0

So he is already using $\chi = 96$. Then he measure the optmized state with various $\chi$'s, and the energy converges to 1e-6 precision for $\chi \gtrsim 128$. Indeed a large $\chi$ is necessary. Maybe now IterSVD can be used to speed up the optimization?

In the calculation he also imposes the geometric $C_{4v}$ symmetry to the 1x1 unit cell in addition to a sub-lattice spin rotation, which further reduces the number of parameters. Did you do this for the 1x1 optimization before?

@pbrehmer
Copy link
Collaborator

Indeed! I'm not yet sure if IterSVD already pays off here with D=4 but in any case we can push the environment dimension quite a bit. I didn't impose $C_{4v}$ symmetry but I'll try that next. Of course we don't have proper $C_{4v}$ CTMRG yet because the environment should consist only of one corner and edge tensor (per unit cell entry). But I'm thinking that we should implement that anyway at some point (also if we want to run proper benchmarks).

Copy link
Member

@lkdvos lkdvos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left some small comments, but in general this looks almost good to go for me!


Let's start by initializing an `InfiniteWeightPEPS` for which we set the required
parameters as well as physical and virtual vector spaces. Since the $J_1$-$J_2$ model has
*next*-neighbor interactions, the simple update algorithm requires a $2 \times 2$ unit cell:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
*next*-neighbor interactions, the simple update algorithm requires a $2 \times 2$ unit cell:
*next*-nearest-neighbor interactions, the simple update algorithm requires a $2 \times 2$ unit cell:

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, I'm slightly confused by this explanation: for me this sounds like next-nearest neighbor hamiltonians have a 2x2 unitcell ground state.
In principle the Hamiltonian still has a translation symmetry for a single site, so I don't think it follows automatically that you would need a $2x2$ unit cell for a next-nearest-neighbour hamiltonian.
From what I understand, this is mostly an algorithmic restriction, and is a result of using simple update, so maybe we can slightly reword this to make that more obvious?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed it's an algorithm limitation. I'll make this point more clear.

Comment on lines +55 to +57
H = real( ## convert Hamiltonian `LocalOperator` to real floats
j1_j2_model(ComplexF64, symm, InfiniteSquare(Nr, Nc); J1, J2, sublattice=false),
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
H = real( ## convert Hamiltonian `LocalOperator` to real floats
j1_j2_model(ComplexF64, symm, InfiniteSquare(Nr, Nc); J1, J2, sublattice=false),
)
H = j1_j2_model(Float64, symm, InfiniteSquare(Nr, Nc); J1, J2, sublattice=false)

I know this used to fail since we tried to construct Sy, was this not fixed in the meantime?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I still cannot directly set T = Float64 because of S_y in MPSKitModels v0.4.2.

Comment on lines 4 to 5
Compute `exp(-dt * H)` from Hamiltonian `H`.
Each term in `H` must be a single `TensorMap`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit misleading, given that this is not actually the full exponential of the hamiltonian, but rather a weird intermediate struct we use that represents sum(exp(-h * dt) for h in H) but is not used that way. (in particular, exp(sum) would be prod(exp), not sum(exp)). I don't have any issues with reusing LocalOperator that way, I would just reword the docstring.

Comment on lines 12 to 14
Check if a Hamiltonian contains only nearest neighbor terms
"""
function is_nnham(H::LocalOperator)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Check if a Hamiltonian contains only nearest neighbor terms
"""
function is_nnham(H::LocalOperator)
is_nearest_neighbour(H)
Check if an operator contains only nearest neighbor terms
"""
function is_nearest_neighbour(H::LocalOperator)

In general I think using longer names might be easier to read here, but I don't feel that strongly about it.
Adding the signature in the docstring is a good idea though

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we following the British spelling in the repo? (neighbour instead of neighbor) But I also see that center instead of centre is used...

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think British and American spelling are mixed throughout the repo, so at this point you can use what you prefer. (Perhaps we can unify at some point but I dont think that's a super high-priority issue right now.)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then I just follow whatever is already in the repo.

@Yue-Zhengyuan
Copy link
Collaborator Author

@pbrehmer I tried to regenerate the J1-J2 SU example by deleting the entry in examples/Cache.toml and run julia examples/make.jl, but it still tries to generate all examples. Can you help look at this?

@pbrehmer
Copy link
Collaborator

Alright this seems to be good to go now!

Regarding the example cache: I think that the caching is somehow broken when running the examples from a forked repository. This might be because @__DIR__ returns an absolute path which is then used in the checksum. (The absolute paths are of course different for different users.) I need to clean up this caching mechanism at some point and then I'll take care of that. I'll do that in a separate PR once I find the time/need!

@pbrehmer pbrehmer requested a review from lkdvos May 22, 2025 09:45
@pbrehmer pbrehmer merged commit 1c1d1f7 into QuantumKitHub:master May 22, 2025
45 checks passed
@Yue-Zhengyuan Yue-Zhengyuan deleted the su-nnn branch May 23, 2025 01:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants