Three-site simple update for the $J_1$-$J_2$ model
In this example, we will use SimpleUpdate
imaginary time evolution to treat the two-dimensional $J_1$-$J_2$ model, which contains next-nearest-neighbour interactions:
\[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\]
Here we will exploit the $U(1)$ spin rotation symmetry in the $J_1$-$J_2$ model. 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!(29385293);
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. We use the minimal unit cell size ($2 \times 2$) required by the simple update algorithm for Hamiltonians with next-nearest-neighbour interactions:
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));
The value $J_2 / J_1 = 0.5$ corresponds 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),
)
result = simpleupdate(wpeps, H, alg; check_interval)
global wpeps = result[1]
end
[ Info: Space of x-weight at [1, 1] = Rep[U₁](0=>2, 1/2=>1, -1/2=>1)
[ Info: SU iter 1 : dt = 1e-02, weight diff = 1.188e+00, time = 0.029 sec
[ Info: Space of x-weight at [1, 1] = Rep[U₁](0=>2, 1=>1, -1=>1)
[ Info: SU conv 1832 : dt = 1e-02, weight diff = 9.942e-09, time = 52.896 sec
[ Info: Space of x-weight at [1, 1] = Rep[U₁](0=>2, 1=>1, -1=>1)
[ Info: SU iter 1 : dt = 1e-02, weight diff = 3.400e-04, time = 0.031 sec
[ Info: Space of x-weight at [1, 1] = Rep[U₁](0=>2, 1=>1, -1=>1)
[ Info: SU conv 523 : dt = 1e-02, weight diff = 9.964e-09, time = 15.817 sec
[ Info: Space of x-weight at [1, 1] = Rep[U₁](0=>2, 1=>1, -1=>1)
[ Info: SU iter 1 : dt = 1e-02, weight diff = 3.524e-04, time = 0.029 sec
[ Info: Space of x-weight at [1, 1] = Rep[U₁](0=>2, 1=>1, -1=>1)
[ Info: SU conv 611 : dt = 1e-02, weight diff = 9.848e-09, time = 18.467 sec
[ Info: Space of x-weight at [1, 1] = Rep[U₁](0=>2, 1=>1, -1=>1)
[ Info: SU iter 1 : dt = 1e-02, weight diff = 3.661e-04, time = 0.029 sec
[ Info: Space of x-weight at [1, 1] = Rep[U₁](0=>2, 1=>1, -1=>1)
[ Info: SU conv 735 : dt = 1e-02, weight diff = 9.962e-09, time = 22.205 sec
[ Info: Space of x-weight at [1, 1] = Rep[U₁](0=>2, 1=>1, -1=>1)
[ Info: SU iter 1 : dt = 1e-02, weight diff = 3.823e-04, time = 0.029 sec
[ Info: Space of x-weight at [1, 1] = Rep[U₁](0=>2, 1=>1, -1=>1)
[ Info: SU conv 901 : dt = 1e-02, weight diff = 9.994e-09, time = 27.331 sec
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))
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
[ Info: Space of x-weight at [1, 1] = Rep[U₁](0=>2, 1=>1, -1=>1)
[ Info: SU iter 1 : dt = 1e-03, weight diff = 4.447e-04, time = 0.030 sec
[ Info: Space of x-weight at [1, 1] = Rep[U₁](0=>2, 1=>1, -1=>1)
[ Info: SU conv 3236 : dt = 1e-03, weight diff = 9.998e-10, time = 97.398 sec
[ Info: Space of x-weight at [1, 1] = Rep[U₁](0=>2, 1=>1, -1=>1)
[ Info: SU iter 1 : dt = 1e-04, weight diff = 4.436e-05, time = 0.031 sec
[ Info: Space of x-weight at [1, 1] = Rep[U₁](0=>2, 1=>1, -1=>1)
[ Info: SU conv 796 : dt = 1e-04, weight diff = 9.999e-10, time = 24.018 sec
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)
-0.4908482949688868
Let us compare that estimate with benchmark data obtained from the YASTN/peps-torch package. which utilizes AD-based PEPS optimization to find $E_\text{ref}=-0.49425$:
E_ref = -0.49425
@show (E - E_ref) / abs(E_ref);
(E - E_ref) / abs(E_ref) = 0.0068825594964354074
Variational PEPS optimization using AD
As a last step, we will use the SU-evolved PEPS as a starting point for a fixedpoint
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. In order to break some of the $C_{4v}$ symmetry of the PEPS, we will add a bit of noise to it
- this is conviently done using MPSKit's
randomize!
function. (Breaking some of the spatial
symmetry can be advantageous for obtaining lower energies.)
using MPSKit: randomize!
noise_peps = InfinitePEPS(randomize!.(deepcopy(peps.A)))
peps₀ = peps + 1e-1noise_peps
peps_opt, env_opt, E_opt, = fixedpoint(
H, peps₀, env; optimizer_alg=(; tol=1e-4, maxiter=80)
);
┌ Warning: the provided real environment was converted to a complex environment since :fixed mode generally produces complex gauges; use :diffgauge mode instead by passing gradient_alg=(; iterscheme=:diffgauge) to the fixedpoint keyword arguments to work with purely real environments
└ @ PEPSKit ~/repos/PEPSKit.jl/src/algorithms/optimization/peps_optimization.jl:219
[ Info: LBFGS: initializing with f = -1.906213849448, ‖∇f‖ = 7.1073e-01
[ Info: LBFGS: iter 1, time 11.81 s: f = -1.912844704482, ‖∇f‖ = 6.1629e-01, α = 1.00e+00, m = 0, nfg = 1
[ Info: LBFGS: iter 2, time 16.75 s: f = -1.937956267904, ‖∇f‖ = 2.9827e-01, α = 1.00e+00, m = 1, nfg = 1
[ Info: LBFGS: iter 3, time 21.80 s: f = -1.943097546791, ‖∇f‖ = 2.0511e-01, α = 1.00e+00, m = 2, nfg = 1
[ Info: LBFGS: iter 4, time 26.69 s: f = -1.951025946434, ‖∇f‖ = 1.4073e-01, α = 1.00e+00, m = 3, nfg = 1
[ Info: LBFGS: iter 5, time 31.77 s: f = -1.955168800010, ‖∇f‖ = 1.2051e-01, α = 1.00e+00, m = 4, nfg = 1
[ Info: LBFGS: iter 6, time 36.87 s: f = -1.960117968919, ‖∇f‖ = 1.1611e-01, α = 1.00e+00, m = 5, nfg = 1
[ Info: LBFGS: iter 7, time 42.26 s: f = -1.961216587562, ‖∇f‖ = 1.6042e-01, α = 1.00e+00, m = 6, nfg = 1
[ Info: LBFGS: iter 8, time 47.58 s: f = -1.963394830132, ‖∇f‖ = 7.0500e-02, α = 1.00e+00, m = 7, nfg = 1
[ Info: LBFGS: iter 9, time 52.76 s: f = -1.964678528654, ‖∇f‖ = 4.8767e-02, α = 1.00e+00, m = 8, nfg = 1
[ Info: LBFGS: iter 10, time 58.23 s: f = -1.965924377851, ‖∇f‖ = 6.0609e-02, α = 1.00e+00, m = 9, nfg = 1
[ Info: LBFGS: iter 11, time 64.25 s: f = -1.968120624918, ‖∇f‖ = 7.1520e-02, α = 1.00e+00, m = 10, nfg = 1
[ Info: LBFGS: iter 12, time 70.40 s: f = -1.969562421458, ‖∇f‖ = 9.5064e-02, α = 1.00e+00, m = 11, nfg = 1
[ Info: LBFGS: iter 13, time 76.48 s: f = -1.970581981978, ‖∇f‖ = 6.1731e-02, α = 1.00e+00, m = 12, nfg = 1
[ Info: LBFGS: iter 14, time 82.38 s: f = -1.971121190048, ‖∇f‖ = 3.2138e-02, α = 1.00e+00, m = 13, nfg = 1
[ Info: LBFGS: iter 15, time 88.28 s: f = -1.971554447655, ‖∇f‖ = 2.5404e-02, α = 1.00e+00, m = 14, nfg = 1
[ Info: LBFGS: iter 16, time 94.48 s: f = -1.972190046057, ‖∇f‖ = 3.2651e-02, α = 1.00e+00, m = 15, nfg = 1
[ Info: LBFGS: iter 17, time 100.54 s: f = -1.972856179552, ‖∇f‖ = 3.0426e-02, α = 1.00e+00, m = 16, nfg = 1
[ Info: LBFGS: iter 18, time 106.47 s: f = -1.973765629052, ‖∇f‖ = 3.2210e-02, α = 1.00e+00, m = 17, nfg = 1
[ Info: LBFGS: iter 19, time 112.59 s: f = -1.974162050742, ‖∇f‖ = 3.5505e-02, α = 1.00e+00, m = 18, nfg = 1
[ Info: LBFGS: iter 20, time 118.60 s: f = -1.974478515407, ‖∇f‖ = 1.8647e-02, α = 1.00e+00, m = 19, nfg = 1
[ Info: LBFGS: iter 21, time 124.39 s: f = -1.974711840147, ‖∇f‖ = 1.5939e-02, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 22, time 130.52 s: f = -1.974976992882, ‖∇f‖ = 2.3561e-02, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 23, time 136.50 s: f = -1.975198552395, ‖∇f‖ = 2.8074e-02, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 24, time 141.91 s: f = -1.975397188154, ‖∇f‖ = 2.4018e-02, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 25, time 147.64 s: f = -1.975511606909, ‖∇f‖ = 3.1378e-02, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 26, time 153.26 s: f = -1.975619359852, ‖∇f‖ = 1.7031e-02, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 27, time 158.40 s: f = -1.975706047066, ‖∇f‖ = 1.5318e-02, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 28, time 163.89 s: f = -1.975792908561, ‖∇f‖ = 1.3145e-02, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 29, time 169.21 s: f = -1.975874444762, ‖∇f‖ = 2.0056e-02, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 30, time 174.74 s: f = -1.975957400077, ‖∇f‖ = 1.2628e-02, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 31, time 179.85 s: f = -1.976016647203, ‖∇f‖ = 1.0550e-02, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 32, time 185.40 s: f = -1.976101267437, ‖∇f‖ = 1.0041e-02, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 33, time 190.83 s: f = -1.976173093824, ‖∇f‖ = 1.4127e-02, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 34, time 196.38 s: f = -1.976232003564, ‖∇f‖ = 9.3789e-03, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 35, time 201.98 s: f = -1.976279429987, ‖∇f‖ = 9.6660e-03, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 36, time 207.59 s: f = -1.976319807091, ‖∇f‖ = 1.2942e-02, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 37, time 212.95 s: f = -1.976360454958, ‖∇f‖ = 8.8852e-03, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 38, time 218.74 s: f = -1.976400234179, ‖∇f‖ = 6.9115e-03, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 39, time 224.19 s: f = -1.976428915464, ‖∇f‖ = 7.0766e-03, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 40, time 229.67 s: f = -1.976468131930, ‖∇f‖ = 7.3518e-03, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 41, time 235.18 s: f = -1.976524294633, ‖∇f‖ = 1.0581e-02, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 42, time 240.74 s: f = -1.976526983977, ‖∇f‖ = 1.6104e-02, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 43, time 246.33 s: f = -1.976576416539, ‖∇f‖ = 6.5034e-03, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 44, time 251.74 s: f = -1.976601737265, ‖∇f‖ = 5.8912e-03, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 45, time 257.37 s: f = -1.976637886122, ‖∇f‖ = 8.4756e-03, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 46, time 262.96 s: f = -1.976694292720, ‖∇f‖ = 9.7710e-03, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 47, time 274.56 s: f = -1.976719690626, ‖∇f‖ = 1.9617e-02, α = 2.83e-01, m = 20, nfg = 2
[ Info: LBFGS: iter 48, time 279.89 s: f = -1.976757180903, ‖∇f‖ = 9.0902e-03, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 49, time 285.45 s: f = -1.976778896839, ‖∇f‖ = 8.4485e-03, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 50, time 290.77 s: f = -1.976801887998, ‖∇f‖ = 1.3765e-02, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 51, time 296.25 s: f = -1.976830529576, ‖∇f‖ = 1.8017e-02, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 52, time 301.90 s: f = -1.976861162991, ‖∇f‖ = 2.6927e-02, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 53, time 307.18 s: f = -1.976929533535, ‖∇f‖ = 1.0242e-02, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 54, time 312.67 s: f = -1.976973353625, ‖∇f‖ = 7.1802e-03, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 55, time 317.85 s: f = -1.976993717783, ‖∇f‖ = 8.8958e-03, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 56, time 323.48 s: f = -1.977060306915, ‖∇f‖ = 1.1556e-02, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 57, time 334.45 s: f = -1.977091448236, ‖∇f‖ = 1.6192e-02, α = 3.03e-01, m = 20, nfg = 2
[ Info: LBFGS: iter 58, time 339.98 s: f = -1.977138624322, ‖∇f‖ = 1.0354e-02, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 59, time 345.41 s: f = -1.977208179209, ‖∇f‖ = 8.7382e-03, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 60, time 351.07 s: f = -1.977244959697, ‖∇f‖ = 1.7905e-02, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 61, time 356.49 s: f = -1.977290172079, ‖∇f‖ = 1.1535e-02, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 62, time 361.80 s: f = -1.977346829138, ‖∇f‖ = 9.3061e-03, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 63, time 367.29 s: f = -1.977390173782, ‖∇f‖ = 1.0691e-02, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 64, time 372.77 s: f = -1.977406788841, ‖∇f‖ = 2.4206e-02, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 65, time 378.41 s: f = -1.977475388304, ‖∇f‖ = 8.1223e-03, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 66, time 383.66 s: f = -1.977496756947, ‖∇f‖ = 6.2713e-03, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 67, time 389.41 s: f = -1.977538498943, ‖∇f‖ = 8.1518e-03, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 68, time 394.85 s: f = -1.977582944207, ‖∇f‖ = 1.2523e-02, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 69, time 406.53 s: f = -1.977612439512, ‖∇f‖ = 1.7582e-02, α = 3.89e-01, m = 20, nfg = 2
[ Info: LBFGS: iter 70, time 412.07 s: f = -1.977652248007, ‖∇f‖ = 9.1652e-03, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 71, time 417.85 s: f = -1.977681403489, ‖∇f‖ = 8.3683e-03, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 72, time 423.98 s: f = -1.977721141239, ‖∇f‖ = 9.4541e-03, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 73, time 429.73 s: f = -1.977775043848, ‖∇f‖ = 1.1036e-02, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 74, time 435.11 s: f = -1.977818026910, ‖∇f‖ = 1.2406e-02, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 75, time 440.76 s: f = -1.977848105077, ‖∇f‖ = 1.1495e-02, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 76, time 446.06 s: f = -1.977873438780, ‖∇f‖ = 5.9210e-03, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 77, time 451.54 s: f = -1.977888581900, ‖∇f‖ = 6.3137e-03, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 78, time 456.92 s: f = -1.977922415140, ‖∇f‖ = 1.1600e-02, α = 1.00e+00, m = 20, nfg = 1
[ Info: LBFGS: iter 79, time 462.53 s: f = -1.977946751759, ‖∇f‖ = 1.2523e-02, α = 1.00e+00, m = 20, nfg = 1
┌ Warning: LBFGS: not converged to requested tol after 80 iterations and time 468.13 s: f = -1.977972943430, ‖∇f‖ = 7.7636e-03
└ @ OptimKit ~/.julia/packages/OptimKit/G6i79/src/lbfgs.jl:197
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);
E_opt = -0.49449323585738636
(E_opt - E_ref) / abs(E_ref) = -0.0004921312238469133
This page was generated using Literate.jl.