|
| 1 | +using ITensors |
| 2 | +using ITensorInfiniteMPS |
| 3 | + |
| 4 | +############################################################################## |
| 5 | +# VUMPS parameters |
| 6 | +# |
| 7 | + |
| 8 | +maxdim = 10 # Maximum bond dimension |
| 9 | +cutoff = 1e-6 # Singular value cutoff when increasing the bond dimension |
| 10 | +max_vumps_iters = 20 # Maximum number of iterations of the VUMPS algorithm at a fixed bond dimension |
| 11 | +tol = 1e-5 # Precision error tolerance for outer loop of VUMPS or TDVP |
| 12 | +outer_iters = 5 # Number of times to increase the bond dimension |
| 13 | +time_step = -Inf # -Inf corresponds to VUMPS |
| 14 | +solver_tol = (x -> x / 100) # Tolerance for the local solver (eigsolve in VUMPS and exponentiate in TDVP) |
| 15 | +multisite_update_alg = "parallel" # Choose between ["sequential", "parallel"] |
| 16 | +conserve_qns = true |
| 17 | +N = 2 # Number of sites in the unit cell (1 site unit cell is currently broken) |
| 18 | + |
| 19 | +# Parameters of the transverse field Ising model |
| 20 | +model_params = (J=1.0, h=0.9) |
| 21 | + |
| 22 | +############################################################################## |
| 23 | +# CODE BELOW HERE DOES NOT NEED TO BE MODIFIED |
| 24 | +# |
| 25 | + |
| 26 | +model = Model"ising"() |
| 27 | + |
| 28 | +function space_shifted(::Model"ising", q̃sz; conserve_qns=true) |
| 29 | + if conserve_qns |
| 30 | + return [QN("SzParity", 1 - q̃sz, 2) => 1, QN("SzParity", 0 - q̃sz, 2) => 1] |
| 31 | + else |
| 32 | + return [QN() => 2] |
| 33 | + end |
| 34 | +end |
| 35 | + |
| 36 | +space_ = fill(space_shifted(model, 0; conserve_qns=conserve_qns), N) |
| 37 | +s = infsiteinds("S=1/2", N; space=space_) |
| 38 | +initstate(n) = "↑" |
| 39 | +ψ = InfMPS(s, initstate) |
| 40 | + |
| 41 | +# Form the Hamiltonian |
| 42 | +H = InfiniteITensorSum(model, s; model_params...) |
| 43 | + |
| 44 | +# Check translational invariance |
| 45 | +@show norm(contract(ψ.AL[1:N]..., ψ.C[N]) - contract(ψ.C[0], ψ.AR[1:N]...)) |
| 46 | + |
| 47 | +vumps_kwargs = ( |
| 48 | + tol=tol, |
| 49 | + maxiter=max_vumps_iters, |
| 50 | + solver_tol=solver_tol, |
| 51 | + multisite_update_alg=multisite_update_alg, |
| 52 | +) |
| 53 | +subspace_expansion_kwargs = (cutoff=cutoff, maxdim=maxdim) |
| 54 | +#ψ = tdvp(H, ψ; time_step=time_step, vumps_kwargs...) |
| 55 | + |
| 56 | +# Alternate steps of running VUMPS and increasing the bond dimension |
| 57 | +@time for _ in 1:outer_iters |
| 58 | + println("\nIncrease bond dimension") |
| 59 | + global ψ = subspace_expansion(ψ, H; subspace_expansion_kwargs...) |
| 60 | + println("Run VUMPS with new bond dimension") |
| 61 | + global ψ = tdvp(H, ψ; time_step=time_step, vumps_kwargs...) |
| 62 | +end |
| 63 | + |
| 64 | +# Check translational invariance |
| 65 | +@show norm(contract(ψ.AL[1:N]..., ψ.C[N]) - contract(ψ.C[0], ψ.AR[1:N]...)) |
| 66 | + |
| 67 | +# |
| 68 | +# Compare to DMRG |
| 69 | +# |
| 70 | + |
| 71 | +Nfinite = 100 |
| 72 | +sfinite = siteinds("S=1/2", Nfinite; conserve_szparity=true) |
| 73 | +Hfinite = MPO(model, sfinite; model_params...) |
| 74 | +ψfinite = randomMPS(sfinite, initstate) |
| 75 | +@show flux(ψfinite) |
| 76 | +sweeps = Sweeps(10) |
| 77 | +setmaxdim!(sweeps, maxdim) |
| 78 | +setcutoff!(sweeps, cutoff) |
| 79 | +energy_finite_total, ψfinite = @time dmrg(Hfinite, ψfinite, sweeps) |
| 80 | +@show energy_finite_total / Nfinite |
| 81 | + |
| 82 | +function energy_local(ψ1, ψ2, h) |
| 83 | + ϕ = ψ1 * ψ2 |
| 84 | + return (noprime(ϕ * h) * dag(ϕ))[] |
| 85 | +end |
| 86 | + |
| 87 | +function ITensors.expect(ψ, o) |
| 88 | + return (noprime(ψ * op(o, filterinds(ψ, "Site")...)) * dag(ψ))[] |
| 89 | +end |
| 90 | + |
| 91 | +# Exact energy at criticality: 4/pi = 1.2732395447351628 |
| 92 | + |
| 93 | +nfinite = Nfinite ÷ 2 |
| 94 | +orthogonalize!(ψfinite, nfinite) |
| 95 | +hnfinite = ITensor(model, sfinite[nfinite], sfinite[nfinite + 1]; model_params...) |
| 96 | +energy_finite = energy_local(ψfinite[nfinite], ψfinite[nfinite + 1], hnfinite) |
| 97 | +energy_infinite = energy_local(ψ.AL[1], ψ.AL[2] * ψ.C[2], H[(1, 2)]) |
| 98 | +@show energy_finite, energy_infinite |
| 99 | +@show abs(energy_finite - energy_infinite) |
| 100 | + |
| 101 | +energy_exact = reference(model, Observable("energy"); model_params...) |
| 102 | +@show energy_exact |
| 103 | + |
| 104 | +Sz1_finite = expect(ψfinite[nfinite], "Sz") |
| 105 | +orthogonalize!(ψfinite, nfinite + 1) |
| 106 | +Sz2_finite = expect(ψfinite[nfinite + 1], "Sz") |
| 107 | +Sz1_infinite = expect(ψ.AL[1] * ψ.C[1], "Sz") |
| 108 | +Sz2_infinite = expect(ψ.AL[2] * ψ.C[2], "Sz") |
| 109 | + |
| 110 | +@show Sz1_finite, Sz2_finite |
| 111 | +@show Sz1_infinite, Sz2_infinite |
| 112 | + |
| 113 | +############################################################################## |
| 114 | +# Compute eigenspace of the transfer matrix |
| 115 | +# |
| 116 | + |
| 117 | +using Arpack |
| 118 | +using KrylovKit |
| 119 | +using LinearAlgebra |
| 120 | + |
| 121 | +T = TransferMatrix(ψ.AL) |
| 122 | +Tᵀ = transpose(T) |
| 123 | +vⁱᴿ = randomITensor(dag(input_inds(T))) |
| 124 | +vⁱᴸ = randomITensor(dag(input_inds(Tᵀ))) |
| 125 | + |
| 126 | +neigs = 10 |
| 127 | +tol = 1e-10 |
| 128 | +λ⃗ᴿ, v⃗ᴿ, right_info = eigsolve(T, vⁱᴿ, neigs, :LM; tol=tol) |
| 129 | +λ⃗ᴸ, v⃗ᴸ, left_info = eigsolve(Tᵀ, vⁱᴸ, neigs, :LM; tol=tol) |
| 130 | + |
| 131 | +@show norm(T(v⃗ᴿ[1]) - λ⃗ᴿ[1] * v⃗ᴿ[1]) |
| 132 | +@show norm(Tᵀ(v⃗ᴸ[1]) - λ⃗ᴸ[1] * v⃗ᴸ[1]) |
| 133 | + |
| 134 | +@show λ⃗ᴿ |
| 135 | +@show λ⃗ᴸ |
| 136 | +@show flux.(v⃗ᴿ) |
| 137 | + |
| 138 | +neigs = length(v⃗ᴿ) |
| 139 | + |
| 140 | +# Normalize the vectors |
| 141 | +N⃗ = [(translatecell(v⃗ᴸ[n], 1) * v⃗ᴿ[n])[] for n in 1:neigs] |
| 142 | + |
| 143 | +v⃗ᴿ ./= sqrt.(N⃗) |
| 144 | +v⃗ᴸ ./= sqrt.(N⃗) |
| 145 | + |
| 146 | +# Form a second starting vector orthogonal to v⃗ᴿ[1] |
| 147 | +# This doesn't work. TODO: project out v⃗ᴿ[1], v⃗ᴸ[1] from T |
| 148 | +#λ⃗ᴿ², v⃗ᴿ², right_info_2 = eigsolve(T, vⁱᴿ², neigs, :LM; tol=tol) |
| 149 | + |
| 150 | +# Projector onto the n-th eigenstate |
| 151 | +function proj(v⃗ᴸ, v⃗ᴿ, n) |
| 152 | + Lⁿ = v⃗ᴸ[n] |
| 153 | + Rⁿ = v⃗ᴿ[n] |
| 154 | + return ITensorMap( |
| 155 | + [translatecell(Lⁿ, 1), translatecell(Rⁿ, -1)]; input_inds=inds(Rⁿ), output_inds=inds(Lⁿ) |
| 156 | + ) |
| 157 | +end |
| 158 | + |
| 159 | +P⃗ = [proj(v⃗ᴸ, v⃗ᴿ, n) for n in 1:neigs] |
| 160 | +T⁻P = T - sum(P⃗) |
| 161 | + |
| 162 | +#vⁱᴿ² = vⁱᴿ - (translatecell(v⃗ᴸ[1], 1) * vⁱᴿ)[] / norm(v⃗ᴿ[1]) * v⃗ᴿ[1] |
| 163 | +#@show norm(dag(vⁱᴿ²) * v⃗ᴿ[1]) |
| 164 | + |
| 165 | +λ⃗ᴾᴿ, v⃗ᴾᴿ, right_info = eigsolve(T⁻P, vⁱᴿ, neigs, :LM; tol=tol) |
| 166 | +@show λ⃗ᴾᴿ |
| 167 | + |
| 168 | +vⁱᴿ⁻ᵈᵃᵗᵃ = vec(array(vⁱᴿ)) |
| 169 | +λ⃗ᴿᴬ, v⃗ᴿ⁻ᵈᵃᵗᵃ = Arpack.eigs(T; v0=vⁱᴿ⁻ᵈᵃᵗᵃ, nev=neigs) |
| 170 | + |
| 171 | +## XXX: this is giving an error about trying to set the element of the wrong QN block for: |
| 172 | +## maxdim = 5 |
| 173 | +## cutoff = 1e-12 |
| 174 | +## max_vumps_iters = 10 |
| 175 | +## outer_iters = 10 |
| 176 | +## model_params = (J=1.0, h=0.8) |
| 177 | +## |
| 178 | +## v⃗ᴿᴬ = [itensor(v⃗ᴿ⁻ᵈᵃᵗᵃ[:, n], input_inds(T); tol=1e-4) for n in 1:length(λ⃗ᴿᴬ)] |
| 179 | +## @show flux.(v⃗ᴿᴬ) |
| 180 | + |
| 181 | +@show λ⃗ᴿᴬ |
| 182 | + |
| 183 | +# Full eigendecomposition |
| 184 | + |
| 185 | +Tfull = prod(T) |
| 186 | +DV = eigen(Tfull, input_inds(T), output_inds(T)) |
| 187 | + |
| 188 | +@show norm(Tfull * DV.V - DV.Vt * DV.D) |
| 189 | + |
| 190 | +d = diag(array(DV.D)) |
| 191 | + |
| 192 | +p = sortperm(d; by=abs, rev=true) |
| 193 | +@show p[1:neigs] |
| 194 | +@show d[p[1:neigs]] |
| 195 | + |
| 196 | +println("Error if ED with Arpack") |
| 197 | +@show d[p[1:neigs]] - λ⃗ᴿᴬ |
0 commit comments