The Haldane gap

In this tutorial we will calculate the Haldane gap (the energy gap in the $S = 1$ Heisenberg model) in two different ways. To follow the tutorial you need the following packages:

using MPSKit, MPSKitModels, TensorKit, Plots, Polynomials
import TensorOperations; TensorOperations.disable_cache(); # hide

The Heisenberg model is defined by the following hamiltonian:

\[H = -J∑_{⟨i,j⟩} (X_i X_j + Y_i Y_j + Z_i Z_j)\]

This hamiltonian has an SU(2) symmetry, which we can enforce by using SU(2)-symmetric tensors:

H = heisenberg_XXX(ComplexF64, SU2Irrep; spin=1, J=-1);

Finite size extrapolation

We can start the analysis using finite-size methods. The groundstate of this model can be approximated using finite MPS through the use of DMRG.

The typical way to find excited states is to minimize the energy while adding an error term $λ \left|gs\right> \left< gs\right|$ Here we will instead use the quasiparticle ansatz.

In Steven White's original DMRG paper it was remarked that the $S = 1$ excitations correspond to edge states, and that one should define the Haldane gap as the difference in energy between the $S = 2$ and $S = 1$ states. This can be done as follows.

L = 10
physical_space = Rep[SU₂](1 => 1)
virtual_space = Rep[SU₂](0 => 15, 1 => 15, 2 => 10, 3 => 5)
ψ₀ = FiniteMPS(rand, ComplexF64, L, physical_space, virtual_space)
ψ, envs, delta = find_groundstate(ψ₀, H, DMRG(; verbose=false))
E₀ = real.(expectation_value(ψ, H))
En_1, st_1 = excitations(H, QuasiparticleAnsatz(), ψ, envs; sector=SU₂(1))
En_2, st_2 = excitations(H, QuasiparticleAnsatz(), ψ, envs; sector=SU₂(2))
ΔE_finite = real(En_2[1] - En_1[1])
-0.2897302384697755

We can go even further and doublecheck the claim that $S = 1$ is an edge excitation, by plotting the energy density.

p_density = plot(; xaxis="position", yaxis="energy density")
excited_1 = convert(FiniteMPS, st_1[1])
excited_2 = convert(FiniteMPS, st_2[1])
plot!(p_density, real.(expectation_value(excited_1, H) .- E₀) ./ L; label="S = 1")
plot!(p_density, real.(expectation_value(excited_2, H) .- E₀) ./ L; label="S = 2")

Finally, we can obtain a value for the Haldane gap by extrapolating our results for different system sizes.

Ls = 5:5:50
ΔEs = map(Ls) do L
    ψ₀ = FiniteMPS(rand, ComplexF64, L, physical_space, virtual_space)
    ψ, envs, delta = find_groundstate(ψ₀, H, DMRG(; verbose=false))
    En_1, st_1 = excitations(H, QuasiparticleAnsatz(), ψ, envs; sector=SU₂(1))
    En_2, st_2 = excitations(H, QuasiparticleAnsatz(), ψ, envs; sector=SU₂(2))
    return real(En_2[1] - En_1[1])
end

f = fit(Ls .^ (-2), ΔEs, 1)
ΔE_extrapolated = f.coeffs[1]
-0.2155532516993712
p_size_extrapolation = plot(; xaxis="L^(-2)", yaxis="ΔE",
    xlims=(0, 0.015))
plot!(p_size_extrapolation, Ls .^ (-2), ΔEs;
    seriestype=:scatter, label="numerical")
plot!(p_size_extrapolation, x -> f(x); label="fit")

Thermodynamic limit

A much nicer way of obtaining the Haldane gap is by working directly in the thermodynamic limit. As was already hinted at by the edge modes, this model is in a non-trivial SPT phase. Thus, care must be taken when selecting the symmetry sectors. The groundstate has half-integer edge modes, thus the virtual spaces must also all carry half-integer charges.

In contrast with the finite size case, we now should specify a momentum label to the excitations. This way, it is possible to scan the dispersion relation over the entire momentum space.

virtual_space_inf = Rep[SU₂](1 // 2 => 20, 3 // 2 => 20, 5 // 2 => 10, 7 // 2 => 10,
    9 // 2 => 5)
ψ₀_inf = InfiniteMPS([physical_space], [virtual_space_inf])
ψ_inf, envs_inf, delta_inf = find_groundstate(ψ₀_inf, H)

kspace = range(0, π, 16)
Es, _ = excitations(H, QuasiparticleAnsatz(), kspace, ψ_inf, envs_inf; sector=SU₂(1))

ΔE, idx = findmin(real.(Es))
println("minimum @k = $(kspace[idx]):\t ΔE = $(ΔE)")
[ Info: vumps @iteration 1 galerkin = 0.6648889732866761
[ Info: vumps @iteration 2 galerkin = 0.06359011437557995
[ Info: vumps @iteration 3 galerkin = 0.0164265217276693
[ Info: vumps @iteration 4 galerkin = 0.002373916187780843
[ Info: vumps @iteration 5 galerkin = 0.0006289175273869992
[ Info: vumps @iteration 6 galerkin = 0.00022983228453123588
[ Info: vumps @iteration 7 galerkin = 0.00010467216817002606
[ Info: vumps @iteration 8 galerkin = 5.438736021221384e-5
[ Info: CG: initializing with f = -0.936207316315, ‖∇f‖ = 7.6838e-05
[ Info: CG: iter    1: f = -0.936207316802, ‖∇f‖ = 3.3956e-05, α = 1.77e-01, β = 0.00e+00, nfg = 5
[ Info: CG: iter    2: f = -0.936207316979, ‖∇f‖ = 2.4905e-05, α = 3.25e-01, β = 1.65e-01, nfg = 2
[ Info: CG: iter    3: f = -0.936207317061, ‖∇f‖ = 1.3668e-05, α = 2.55e-01, β = 6.41e-01, nfg = 2
[ Info: CG: iter    4: f = -0.936207317085, ‖∇f‖ = 8.2456e-06, α = 2.51e-01, β = 3.10e-01, nfg = 2
[ Info: CG: iter    5: f = -0.936207317094, ‖∇f‖ = 5.4141e-06, α = 2.88e-01, β = 3.53e-01, nfg = 2
[ Info: CG: iter    6: f = -0.936207317098, ‖∇f‖ = 3.5886e-06, α = 2.58e-01, β = 4.29e-01, nfg = 2
[ Info: CG: iter    7: f = -0.936207317100, ‖∇f‖ = 2.3617e-06, α = 2.28e-01, β = 4.39e-01, nfg = 2
[ Info: CG: iter    8: f = -0.936207317100, ‖∇f‖ = 1.5488e-06, α = 2.07e-01, β = 4.38e-01, nfg = 2
[ Info: CG: iter    9: f = -0.936207317101, ‖∇f‖ = 1.0240e-06, α = 2.29e-01, β = 4.16e-01, nfg = 2
[ Info: CG: iter   10: f = -0.936207317101, ‖∇f‖ = 6.7229e-07, α = 2.44e-01, β = 4.52e-01, nfg = 2
[ Info: CG: iter   11: f = -0.936207317101, ‖∇f‖ = 4.5048e-07, α = 2.40e-01, β = 4.23e-01, nfg = 2
[ Info: CG: iter   12: f = -0.936207317101, ‖∇f‖ = 2.8542e-07, α = 2.10e-01, β = 4.53e-01, nfg = 2
[ Info: CG: iter   13: f = -0.936207317101, ‖∇f‖ = 1.7638e-07, α = 2.10e-01, β = 3.99e-01, nfg = 2
[ Info: CG: iter   14: f = -0.936207317101, ‖∇f‖ = 1.1830e-07, α = 2.33e-01, β = 3.84e-01, nfg = 2
[ Info: CG: iter   15: f = -0.936207317101, ‖∇f‖ = 8.0831e-08, α = 2.09e-01, β = 4.50e-01, nfg = 2
[ Info: CG: iter   16: f = -0.936207317101, ‖∇f‖ = 5.8991e-08, α = 2.06e-01, β = 4.67e-01, nfg = 2
[ Info: CG: iter   17: f = -0.936207317101, ‖∇f‖ = 4.3695e-08, α = 2.09e-01, β = 5.30e-01, nfg = 2
[ Info: CG: iter   18: f = -0.936207317101, ‖∇f‖ = 3.2093e-08, α = 1.97e-01, β = 5.52e-01, nfg = 2
[ Info: CG: iter   19: f = -0.936207317101, ‖∇f‖ = 2.3767e-08, α = 2.23e-01, β = 5.39e-01, nfg = 2
[ Info: CG: iter   20: f = -0.936207317101, ‖∇f‖ = 1.7986e-08, α = 2.39e-01, β = 5.49e-01, nfg = 2
[ Info: CG: iter   21: f = -0.936207317101, ‖∇f‖ = 1.3820e-08, α = 2.37e-01, β = 5.73e-01, nfg = 2
[ Info: CG: iter   22: f = -0.936207317101, ‖∇f‖ = 1.0492e-08, α = 2.20e-01, β = 5.91e-01, nfg = 2
[ Info: CG: iter   23: f = -0.936207317101, ‖∇f‖ = 8.5940e-09, α = 2.39e-01, β = 5.76e-01, nfg = 2
[ Info: CG: iter   24: f = -0.936207317101, ‖∇f‖ = 7.4331e-09, α = 2.67e-01, β = 6.72e-01, nfg = 2
[ Info: CG: iter   25: f = -0.936207317101, ‖∇f‖ = 6.0167e-09, α = 2.45e-01, β = 7.48e-01, nfg = 2
[ Info: CG: iter   26: f = -0.936207317101, ‖∇f‖ = 4.5352e-09, α = 2.12e-01, β = 6.55e-01, nfg = 2
[ Info: CG: iter   27: f = -0.936207317101, ‖∇f‖ = 2.9325e-09, α = 1.91e-01, β = 5.68e-01, nfg = 2
[ Info: CG: iter   28: f = -0.936207317101, ‖∇f‖ = 1.7500e-09, α = 1.76e-01, β = 4.18e-01, nfg = 2
[ Info: CG: iter   29: f = -0.936207317101, ‖∇f‖ = 1.0053e-09, α = 1.85e-01, β = 3.56e-01, nfg = 2
[ Info: CG: iter   30: f = -0.936207317101, ‖∇f‖ = 6.0296e-10, α = 2.02e-01, β = 3.30e-01, nfg = 2
[ Info: CG: iter   31: f = -0.936207317101, ‖∇f‖ = 3.9119e-10, α = 2.11e-01, β = 3.60e-01, nfg = 2
[ Info: CG: iter   32: f = -0.936207317101, ‖∇f‖ = 2.8042e-10, α = 2.19e-01, β = 4.21e-01, nfg = 2
[ Info: CG: iter   33: f = -0.936207317101, ‖∇f‖ = 2.1988e-10, α = 2.21e-01, β = 5.14e-01, nfg = 2
[ Info: CG: iter   34: f = -0.936207317101, ‖∇f‖ = 1.9308e-10, α = 2.56e-01, β = 6.15e-01, nfg = 2
[ Info: CG: iter   35: f = -0.936207317101, ‖∇f‖ = 1.6850e-10, α = 2.54e-01, β = 7.71e-01, nfg = 2
[ Info: CG: iter   36: f = -0.936207317101, ‖∇f‖ = 1.4140e-10, α = 2.25e-01, β = 7.61e-01, nfg = 2
[ Info: CG: iter   37: f = -0.936207317101, ‖∇f‖ = 1.1451e-10, α = 2.29e-01, β = 7.04e-01, nfg = 2
[ Info: CG: iter   38: f = -0.936207317101, ‖∇f‖ = 9.1346e-11, α = 2.33e-01, β = 6.55e-01, nfg = 2
[ Info: CG: iter   39: f = -0.936207317101, ‖∇f‖ = 7.0586e-11, α = 2.35e-01, β = 6.37e-01, nfg = 2
[ Info: CG: iter   40: f = -0.936207317101, ‖∇f‖ = 5.8120e-11, α = 2.60e-01, β = 5.97e-01, nfg = 2
[ Info: CG: iter   41: f = -0.936207317101, ‖∇f‖ = 4.7058e-11, α = 2.59e-01, β = 6.78e-01, nfg = 2
[ Info: CG: iter   42: f = -0.936207317101, ‖∇f‖ = 3.2408e-11, α = 2.24e-01, β = 6.55e-01, nfg = 2
[ Info: CG: iter   43: f = -0.936207317101, ‖∇f‖ = 2.1412e-11, α = 2.07e-01, β = 4.75e-01, nfg = 2
[ Info: CG: iter   44: f = -0.936207317101, ‖∇f‖ = 1.3598e-11, α = 1.86e-01, β = 4.35e-01, nfg = 2
[ Info: CG: iter   45: f = -0.936207317101, ‖∇f‖ = 8.9005e-12, α = 1.76e-01, β = 4.05e-01, nfg = 2
[ Info: CG: iter   46: f = -0.936207317101, ‖∇f‖ = 5.5988e-12, α = 1.85e-01, β = 4.27e-01, nfg = 2
[ Info: CG: iter   47: f = -0.936207317101, ‖∇f‖ = 3.6664e-12, α = 2.10e-01, β = 3.97e-01, nfg = 2
[ Info: CG: iter   48: f = -0.936207317101, ‖∇f‖ = 2.5881e-12, α = 2.24e-01, β = 4.29e-01, nfg = 2
[ Info: CG: iter   49: f = -0.936207317101, ‖∇f‖ = 1.9556e-12, α = 2.36e-01, β = 4.95e-01, nfg = 2
[ Info: CG: iter   50: f = -0.936207317101, ‖∇f‖ = 1.5149e-12, α = 2.25e-01, β = 5.73e-01, nfg = 2
[ Info: CG: iter   51: f = -0.936207317101, ‖∇f‖ = 1.2152e-12, α = 2.33e-01, β = 6.02e-01, nfg = 2
[ Info: CG: converged after 52 iterations: f = -0.936207317101, ‖∇f‖ = 9.9968e-13
[ Info: Found excitations for p = 2.9321531433504737
[ Info: Found excitations for p = 3.141592653589793
[ Info: Found excitations for p = 2.722713633111154
[ Info: Found excitations for p = 2.5132741228718345
[ Info: Found excitations for p = 2.303834612632515
[ Info: Found excitations for p = 0.0
[ Info: Found excitations for p = 2.0943951023931953
[ Info: Found excitations for p = 1.8849555921538759
[ Info: Found excitations for p = 1.6755160819145563
[ Info: Found excitations for p = 1.4660765716752369
[ Info: Found excitations for p = 0.8377580409572781
[ Info: Found excitations for p = 1.0471975511965976
[ Info: Found excitations for p = 1.2566370614359172
[ Info: Found excitations for p = 0.6283185307179586
[ Info: Found excitations for p = 0.41887902047863906
[ Info: Found excitations for p = 0.20943951023931953
minimum @k = 0.0:	 ΔE = -0.2595611997968351
plot(kspace, real.(Es); xaxis="momentum", yaxis="ΔE", label="S = 1")

This page was generated using Literate.jl.