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

Open
wants to merge 60 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
6f385f3
Add 3-site simple update
Yue-Zhengyuan Apr 9, 2025
a539e18
Merge remote-tracking branch 'upstream/master' into su-nnn
Yue-Zhengyuan Apr 10, 2025
d684e8d
Update SU examples
Yue-Zhengyuan Apr 11, 2025
f4e671a
Add test to check consistency of SU and 3-site SU on Heisenberg model
Yue-Zhengyuan Apr 11, 2025
8ee4612
Merge remote-tracking branch 'upstream/master' into su-nnn
Yue-Zhengyuan Apr 11, 2025
8a6551d
Fix formatting
Yue-Zhengyuan Apr 11, 2025
a202b47
Merge remote-tracking branch 'upstream/master' into su-nnn
Yue-Zhengyuan Apr 12, 2025
1683d12
Define normalize! for InfinitePEPS
Yue-Zhengyuan Apr 13, 2025
942d944
Update test and docstring on cluster canonical form
Yue-Zhengyuan Apr 13, 2025
6aa5b81
Define `real`, `imag` for `LocalOperator`
Yue-Zhengyuan Apr 13, 2025
e8ab176
Gate MPO now acts on cluster from below
Yue-Zhengyuan Apr 14, 2025
84c9541
Fix formatting
Yue-Zhengyuan Apr 14, 2025
6e0eb4e
Improve type stability of cluster, projector list
Yue-Zhengyuan Apr 14, 2025
87d49a1
Improve `normalize` for `InfinitePEPS`
Yue-Zhengyuan Apr 14, 2025
87b4606
Add test on `imag` for `LocalOperator`
Yue-Zhengyuan Apr 14, 2025
b2978ba
Merge remote-tracking branch 'origin/real-imag-localop' into su-nnn
Yue-Zhengyuan Apr 14, 2025
d41ea96
Simplify conversion to real Hamiltonian
Yue-Zhengyuan Apr 14, 2025
0825212
Fix formatting
Yue-Zhengyuan Apr 14, 2025
cd8ad25
Use `flip` to reverse arrows for SVD result
Yue-Zhengyuan Apr 14, 2025
0281c91
Make type annotation more precise
Yue-Zhengyuan Apr 14, 2025
dcb20bf
Use `NamedTuple` to store gatempo
Yue-Zhengyuan Apr 14, 2025
56059f3
Remove definition of normalize! for InfinitePEPS
Yue-Zhengyuan Apr 14, 2025
0991196
Remove unused variable
Yue-Zhengyuan Apr 14, 2025
d32ed5c
Improve type stability
Yue-Zhengyuan Apr 15, 2025
52458e9
Merge upstream/master
Yue-Zhengyuan Apr 15, 2025
0b0f976
Unify 2-site and 3-site SU in exported `simpleupdate`
Yue-Zhengyuan Apr 16, 2025
32fb6af
Merge remote-tracking branch 'upstream/master' into su-nnn
Yue-Zhengyuan Apr 16, 2025
cfa91fa
Merge remote-tracking branch 'upstream/master' into su-nnn
Yue-Zhengyuan Apr 17, 2025
1c60f36
Add `flip_svd` utility function
Yue-Zhengyuan Apr 18, 2025
97cf159
WIP: Implement rotations for `InfiniteWeightPEPS`
Yue-Zhengyuan Apr 20, 2025
ee97c1c
Merge upstream/master
Yue-Zhengyuan Apr 20, 2025
d76c4ac
Merge remote-tracking branch 'upstream/master' into iwpeps-rotation
Yue-Zhengyuan Apr 25, 2025
6c91e37
Restrict virtual arrows to left/down in `InfiniteWeightPEPS`
Yue-Zhengyuan Apr 25, 2025
37858c3
Add test for `InfiniteWeightPEPS` rotation
Yue-Zhengyuan Apr 25, 2025
53c781e
Remove redundant `isdual` check in simple update
Yue-Zhengyuan Apr 25, 2025
5f61d09
Merge `origin/iwpeps-rotation`
Yue-Zhengyuan Apr 25, 2025
7b856bf
Remove periodic shift when rotating coordinate of a site
Yue-Zhengyuan Apr 25, 2025
0f9b760
Remove code related to `sw` cluster
Yue-Zhengyuan Apr 25, 2025
fd7d25d
Add spin correlation measurement to SU example
Yue-Zhengyuan Apr 25, 2025
7936a27
Improve J1-J2 example
Yue-Zhengyuan Apr 25, 2025
496afbf
Merge remote-tracking branch 'upstream/master' into iwpeps-rotation
Yue-Zhengyuan May 2, 2025
aba0c2c
Merge branch 'iwpeps-rotation' into su-nnn
Yue-Zhengyuan May 2, 2025
9ccc71a
Merge remote-tracking branch 'upstream/master' into iwpeps-rotation
Yue-Zhengyuan May 7, 2025
15fe65f
Simplify `==` for InfiniteWeightPEPS
Yue-Zhengyuan May 7, 2025
c62f9fc
Clean up rotations for SUWeight
Yue-Zhengyuan May 8, 2025
738c430
Move SUWeight restrictions to outer constructor
Yue-Zhengyuan May 8, 2025
213742f
Add TensorKit version check in test
Yue-Zhengyuan May 8, 2025
d05446b
Merge branch 'iwpeps-rotation' into su-nnn
Yue-Zhengyuan May 8, 2025
4eff1c3
Remove old J1-J2 example
Yue-Zhengyuan May 8, 2025
e651c15
Fix variable names
Yue-Zhengyuan May 8, 2025
9336972
Change rotations in `su3site_iter`
Yue-Zhengyuan May 12, 2025
39f0b09
Merge remote-tracking branch 'upstream/master' into su-nnn
Yue-Zhengyuan May 12, 2025
2fba53f
Add example on J1-J2 simple update
Yue-Zhengyuan May 12, 2025
1311930
Add extra explanations to J1-J2 SU example
pbrehmer May 14, 2025
0a7c7c0
Add AD optimization part to J1-J2 example
pbrehmer May 14, 2025
493f8cd
Merge branch 'master' into su-nnn
pbrehmer May 14, 2025
d614c8b
Add rendered J1-J2 example
pbrehmer May 15, 2025
da04a1d
Fix docs issues
pbrehmer May 15, 2025
f342458
Fix formatting
pbrehmer May 15, 2025
69c8a67
Merge branch 'master' into su-nnn
pbrehmer May 16, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/Tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ jobs:
- examples
- utility
- bondenv
- timeevol
os:
- ubuntu-latest
- macOS-latest
Expand Down
3 changes: 2 additions & 1 deletion docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ mathengine = MathJax3(
# examples pages
examples_optimization =
joinpath.(["heisenberg", "bose_hubbard", "xxz", "fermi_hubbard"], Ref("index.md"))
examples_time_evolution = joinpath.(["heisenberg_su", "hubbard_su"], Ref("index.md"))
examples_time_evolution =
joinpath.(["heisenberg_su", "hubbard_su", "j1j2_su"], Ref("index.md"))
examples_partition_functions =
joinpath.(
["2d_ising_partition_function", "3d_ising_partition_function"], Ref("index.md")
Expand Down
340 changes: 340 additions & 0 deletions docs/src/examples/j1j2_su/index.md

Large diffs are not rendered by default.

238 changes: 238 additions & 0 deletions docs/src/examples/j1j2_su/main.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"using Markdown #hide"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Three-site simple update for the $J_1$-$J_2$ model\n",
"\n",
"In this example, we will use `SimpleUpdate` imaginary time evolution to treat\n",
"the two-dimensional $J_1$-$J_2$ model, which contains next-nearest neighbor interactions:\n",
"\n",
"$$\n",
"H = J_1 \\sum_{\\langle i,j \\rangle} \\mathbf{S}_i \\cdot \\mathbf{S}_j\n",
"+ J_2 \\sum_{\\langle \\langle i,j \\rangle \\rangle} \\mathbf{S}_i \\cdot \\mathbf{S}_j\n",
"$$\n",
"\n",
"Note that the $J_1$-$J_2$ model exhibits a $U(1)$ spin rotation symmetry, which we want to\n",
"exploit here. The goal will be to calculate the energy at $J_1 = 1$ and $J_2 = 1/2$, first\n",
"using the simple update algorithm and then, to refine the energy estimate, using AD-based\n",
"variational PEPS optimization.\n",
"\n",
"We first import all required modules and seed the RNG:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"using Random\n",
"using TensorKit, PEPSKit\n",
"Random.seed!(2025);"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Simple updating a challenging phase\n",
"\n",
"Let's start by initializing an `InfiniteWeightPEPS` for which we set the required\n",
"parameters as well as physical and virtual vector spaces. Since the $J_1$-$J_2$ model has\n",
"*next*-neighbor interactions, the simple update algorithm requires a $2 \\times 2$ unit cell:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"Dbond, χenv, symm = 4, 32, U1Irrep\n",
"trscheme_env = truncerr(1e-10) & truncdim(χenv)\n",
"Nr, Nc, J1 = 2, 2, 1.0\n",
"\n",
"# random initialization of 2x2 iPEPS with weights and CTMRGEnv (using real numbers)\n",
"Pspace = Vect[U1Irrep](1//2 => 1, -1//2 => 1)\n",
"Vspace = Vect[U1Irrep](0 => 2, 1//2 => 1, -1//2 => 1)\n",
"Espace = Vect[U1Irrep](0 => χenv ÷ 2, 1//2 => χenv ÷ 4, -1//2 => χenv ÷ 4)\n",
"wpeps = InfiniteWeightPEPS(rand, Float64, Pspace, Vspace; unitcell=(Nr, Nc));"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The value $J_2 / J_1 = 0.5$ is close to a possible spin liquid phase, which is challenging\n",
"for SU to produce a relatively good state from random initialization. Therefore, we shall\n",
"gradually increase $J_2 / J_1$ from 0.1 to 0.5, each time initializing on the previously\n",
"evolved PEPS:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"dt, tol, maxiter = 1e-2, 1e-8, 30000\n",
"check_interval = 4000\n",
"trscheme_peps = truncerr(1e-10) & truncdim(Dbond)\n",
"alg = SimpleUpdate(dt, tol, maxiter, trscheme_peps)\n",
"for J2 in 0.1:0.1:0.5\n",
" H = real( ## convert Hamiltonian `LocalOperator` to real floats\n",
" j1_j2_model(ComplexF64, symm, InfiniteSquare(Nr, Nc); J1, J2, sublattice=false),\n",
" )\n",
" result = simpleupdate(wpeps, H, alg; check_interval)\n",
" global wpeps = result[1]\n",
"end"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"After we reach $J_2 / J_1 = 0.5$, we gradually decrease the evolution time step to obtain\n",
"a more accurately evolved PEPS:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"dts = [1e-3, 1e-4]\n",
"tols = [1e-9, 1e-9]\n",
"J2 = 0.5\n",
"H = real(j1_j2_model(ComplexF64, symm, InfiniteSquare(Nr, Nc); J1, J2, sublattice=false))\n",
"for (dt, tol) in zip(dts, tols)\n",
" alg′ = SimpleUpdate(dt, tol, maxiter, trscheme_peps)\n",
" result = simpleupdate(wpeps, H, alg′; check_interval)\n",
" global wpeps = result[1]\n",
"end"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Computing the simple update energy estimate\n",
"\n",
"Finally, we measure the ground-state energy by converging a CTMRG environment and computing\n",
"the expectation value, where we make sure to normalize by the unit cell size:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"peps = InfinitePEPS(wpeps)\n",
"normalize!.(peps.A, Inf) ## normalize PEPS with absorbed weights by largest element\n",
"env₀ = CTMRGEnv(rand, Float64, peps, Espace)\n",
"env, = leading_boundary(env₀, peps; tol=1e-10, alg=:sequential, trscheme=trscheme_env);\n",
"E = expectation_value(peps, H, env) / (Nr * Nc)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let us compare that estimate with benchmark data obtained from the\n",
"[YASTN/peps-torch package](https://github.com/jurajHasik/j1j2_ipeps_states/blob/ea4140fbd7da0fc1b75fac2871f75bda125189a8/single-site_pg-C4v-A1_internal-U1/j20.5/state_1s_A1_U1B_j20.5_D4_chi_opt96.dat).\n",
"which utilizes AD-based PEPS optimization to find $E_\\text{ref}=-0.49425$:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"E_ref = -0.49425\n",
"@show (E - E_ref) / abs(E_ref);"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Variational PEPS optimization using AD\n",
"\n",
"As a last step, we will use the SU-evolved PEPS as a starting point for a `fixedpoint`\n",
"PEPS optimization. Note that we could have also used a sublattice-rotated version of `H` to\n",
"fit the Hamiltonian onto a single-site unit cell which would require us to optimize fewer\n",
"parameters and hence lead to a faster optimization. But here we instead take advantage of\n",
"the already evolved `peps`, thus giving us a physical initial guess for the optimization:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"peps_opt, env_opt, E_opt, = fixedpoint(\n",
" H, peps, env; optimizer_alg=(; tol=1e-4, maxiter=120)\n",
");"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Finally, we compare the variationally optimized energy against the reference energy. Indeed,\n",
"we find that the additional AD-based optimization improves the SU-evolved PEPS and leads to\n",
"a more accurate energy estimate."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"E_opt /= (Nr * Nc)\n",
"@show E_opt\n",
"@show (E_opt - E_ref) / abs(E_ref);"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n",
"\n",
"*This notebook was generated using [Literate.jl](https://github.com/fredrikekre/Literate.jl).*"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Julia 1.11.5",
"language": "julia",
"name": "julia-1.11"
},
"language_info": {
"file_extension": ".jl",
"mimetype": "application/julia",
"name": "julia",
"version": "1.11.5"
}
},
"nbformat": 4,
"nbformat_minor": 3
}
1 change: 1 addition & 0 deletions examples/Cache.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ boundary_mps = "31e14bd742c12acfc4facd5bc8f28752f025a1a523c72ffccc8581e38880d3cd
heisenberg_su = "299b79f36b94b301dafa0d39fc54498b44dcdf0e4988e3c5416aa6c4e9e8f584"
xxz = "b5ab0efe6b9addb4b029250d7212d8b2e771136ca4ec4a4bfd7bccc8c688b949"
fermi_hubbard = "13d6d827a9851bef2c47cbe8894bf6eec9e1fb3222ecc24d2a876336553439ff"
j1j2_su = "883df8a1ccf061754538620c1086e2e13f1fd7821b8f2f489f305d0cf7098908"
heisenberg = "f6b057dacb058656ad903778fc00832c6c8a61df930118872e04006b086030c7"
121 changes: 121 additions & 0 deletions examples/j1j2_su/main.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
using Markdown #hide
md"""
# Three-site simple update for the $J_1$-$J_2$ model

In this example, we will use [`SimpleUpdate`](@ref) imaginary time evolution to treat
the two-dimensional $J_1$-$J_2$ model, which contains next-nearest neighbor interactions:

```math
H = J_1 \sum_{\langle i,j \rangle} \mathbf{S}_i \cdot \mathbf{S}_j
+ J_2 \sum_{\langle \langle i,j \rangle \rangle} \mathbf{S}_i \cdot \mathbf{S}_j
```

Note that the $J_1$-$J_2$ model exhibits a $U(1)$ spin rotation symmetry, which we want to
exploit here. The goal will be to calculate the energy at $J_1 = 1$ and $J_2 = 1/2$, first
using the simple update algorithm and then, to refine the energy estimate, using AD-based
variational PEPS optimization.

We first import all required modules and seed the RNG:
"""

using Random
using TensorKit, PEPSKit
Random.seed!(2025);

md"""
## Simple updating a challenging phase

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?

"""

Dbond, χenv, symm = 4, 32, U1Irrep
trscheme_env = truncerr(1e-10) & truncdim(χenv)
Nr, Nc, J1 = 2, 2, 1.0

## random initialization of 2x2 iPEPS with weights and CTMRGEnv (using real numbers)
Pspace = Vect[U1Irrep](1//2 => 1, -1//2 => 1)
Vspace = Vect[U1Irrep](0 => 2, 1//2 => 1, -1//2 => 1)
Espace = Vect[U1Irrep](0 => χenv ÷ 2, 1//2 => χenv ÷ 4, -1//2 => χenv ÷ 4)
wpeps = InfiniteWeightPEPS(rand, Float64, Pspace, Vspace; unitcell=(Nr, Nc));

md"""
The value $J_2 / J_1 = 0.5$ is close to a possible spin liquid phase, which is challenging
for SU to produce a relatively good state from random initialization. Therefore, we shall
gradually increase $J_2 / J_1$ from 0.1 to 0.5, each time initializing on the previously
evolved PEPS:
"""

dt, tol, maxiter = 1e-2, 1e-8, 30000
check_interval = 4000
trscheme_peps = truncerr(1e-10) & truncdim(Dbond)
alg = SimpleUpdate(dt, tol, maxiter, trscheme_peps)
for J2 in 0.1:0.1:0.5
H = real( ## convert Hamiltonian `LocalOperator` to real floats
j1_j2_model(ComplexF64, symm, InfiniteSquare(Nr, Nc); J1, J2, sublattice=false),
)
Comment on lines +55 to +57
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?

result = simpleupdate(wpeps, H, alg; check_interval)
global wpeps = result[1]
end

md"""
After we reach $J_2 / J_1 = 0.5$, we gradually decrease the evolution time step to obtain
a more accurately evolved PEPS:
"""

dts = [1e-3, 1e-4]
tols = [1e-9, 1e-9]
J2 = 0.5
H = real(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.

Same comment about real here.

for (dt, tol) in zip(dts, tols)
alg′ = SimpleUpdate(dt, tol, maxiter, trscheme_peps)
result = simpleupdate(wpeps, H, alg′; check_interval)
global wpeps = result[1]
end

md"""
## Computing the simple update energy estimate

Finally, we measure the ground-state energy by converging a CTMRG environment and computing
the expectation value, where we make sure to normalize by the unit cell size:
"""

peps = InfinitePEPS(wpeps)
normalize!.(peps.A, Inf) ## normalize PEPS with absorbed weights by largest element
env₀ = CTMRGEnv(rand, Float64, peps, Espace)
env, = leading_boundary(env₀, peps; tol=1e-10, alg=:sequential, trscheme=trscheme_env);
E = expectation_value(peps, H, env) / (Nr * Nc)

md"""
Let us compare that estimate with benchmark data obtained from the
[YASTN/peps-torch package](https://github.com/jurajHasik/j1j2_ipeps_states/blob/ea4140fbd7da0fc1b75fac2871f75bda125189a8/single-site_pg-C4v-A1_internal-U1/j20.5/state_1s_A1_U1B_j20.5_D4_chi_opt96.dat).
which utilizes AD-based PEPS optimization to find $E_\text{ref}=-0.49425$:
"""

E_ref = -0.49425
@show (E - E_ref) / abs(E_ref);

md"""
## Variational PEPS optimization using AD

As a last step, we will use the SU-evolved PEPS as a starting point for a [`fixedpoint`](@ref)
PEPS optimization. Note that we could have also used a sublattice-rotated version of `H` to
fit the Hamiltonian onto a single-site unit cell which would require us to optimize fewer
parameters and hence lead to a faster optimization. But here we instead take advantage of
the already evolved `peps`, thus giving us a physical initial guess for the optimization:
"""

peps_opt, env_opt, E_opt, = fixedpoint(
H, peps, env; optimizer_alg=(; tol=1e-4, maxiter=120)
);

md"""
Finally, we compare the variationally optimized energy against the reference energy. Indeed,
we find that the additional AD-based optimization improves the SU-evolved PEPS and leads to
a more accurate energy estimate.
"""

E_opt /= (Nr * Nc)
@show E_opt
@show (E_opt - E_ref) / abs(E_ref);
Loading
Loading