-
Notifications
You must be signed in to change notification settings - Fork 16
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
base: master
Are you sure you want to change the base?
Changes from all commits
6f385f3
a539e18
d684e8d
f4e671a
8ee4612
8a6551d
a202b47
1683d12
942d944
6aa5b81
e8ab176
84c9541
6e0eb4e
87d49a1
87b4606
b2978ba
d41ea96
0825212
cd8ad25
0281c91
dcb20bf
56059f3
0991196
d32ed5c
52458e9
0b0f976
32fb6af
cfa91fa
1c60f36
97cf159
ee97c1c
d76c4ac
6c91e37
37858c3
53c781e
5f61d09
7b856bf
0f9b760
fd7d25d
7936a27
496afbf
aba0c2c
9ccc71a
15fe65f
c62f9fc
738c430
213742f
d05446b
4eff1c3
e651c15
9336972
39f0b09
2fba53f
1311930
0a7c7c0
493f8cd
d614c8b
da04a1d
f342458
69c8a67
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -32,6 +32,7 @@ jobs: | |
- examples | ||
- utility | ||
- bondenv | ||
- timeevol | ||
os: | ||
- ubuntu-latest | ||
- macOS-latest | ||
|
Large diffs are not rendered by default.
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 | ||
} |
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: | ||||||||||
""" | ||||||||||
|
||||||||||
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
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
I know this used to fail since we tried to construct |
||||||||||
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)) | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same comment about |
||||||||||
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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
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.$2x2$ unit cell for a next-nearest-neighbour hamiltonian.
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
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?