Skip to content

Commit db941c6

Browse files
authored
Simplify the necessary OpSum definitions for Models (#63)
* New interface for models in terms of `ITensorInfiniteMPS.unit_cell_terms`, which should return an `OpSum` containing the terms of the Hamiltonian in the unit cell. * Simplify the interface for `infsiteinds`, automatically shift the space of the site indices based on the initial state.
1 parent 07deb47 commit db941c6

40 files changed

+875
-860
lines changed

Project.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,19 @@ LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
1414
OffsetArrays = "6fe1bfb0-de20-5000-8ca7-80f57d26f881"
1515
QuadGK = "1fd47b50-473d-5c70-9696-f719f8f3bcdc"
1616
Requires = "ae029012-a4dd-5104-9daa-d747884805df"
17+
SplitApplyCombine = "03a91e81-4c3e-53e1-a0a4-9c0c8f19dd66"
1718

1819
[compat]
1920
Compat = "3, 4"
2021
HDF5 = "0.15, 0.16"
21-
ITensors = "0.3"
22+
ITensors = "0.3.18"
2223
Infinities = "0.1"
2324
IterTools = "1"
2425
KrylovKit = "0.5"
2526
OffsetArrays = "1"
2627
QuadGK = "2"
2728
Requires = "1"
29+
SplitApplyCombine = "1.2.2"
2830
julia = "1.6"
2931

3032
[extras]
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
using ITensors
2+
using ITensorInfiniteMPS
3+
4+
# H = -J Σⱼ XⱼXⱼ₊₁ - h Σⱼ Zⱼ
5+
function ising_opsum_infinite(N; J, h)
6+
os = OpSum()
7+
for n in 1:N
8+
os -= J, "X", n, "X", n + 1
9+
end
10+
for n in 1:N
11+
os -= h, "Z", n
12+
end
13+
return os
14+
end
15+
16+
function ising_opsum_finite(N; J, h)
17+
return ising_opsum_infinite(N - 1; J, h) + (-h, "Z", N)
18+
end
19+
20+
function main(; N, J, h, nsites)
21+
s = siteinds("S=1/2", N)
22+
23+
H = MPO(ising_opsum_finite(N; J=J, h=h), s)
24+
ψ0 = randomMPS(s)
25+
26+
energy, ψ = dmrg(H, ψ0; nsweeps=10, cutoff=1e-10)
27+
@show energy / N
28+
29+
n1 = N ÷ 2
30+
n2 = n1 + 1
31+
32+
ψ = orthogonalize(ψ, n1)
33+
34+
println("\nFinite MPS energy on bond (n1, n2) = $((n1, n2))")
35+
36+
ϕ12 = ψ[n1] * ψ[n2]
37+
ham12 = contract(MPO(ising_opsum_infinite(1; J=J, h=h), [s[n1], s[n2]]))
38+
@show inner(ϕ12, apply(ham12, ϕ12))
39+
40+
# Get an infinite MPS that approximates
41+
# the finite MPS in the bulk.
42+
# `nsites` sets the number of sites in the unit
43+
# cell of the infinite MPS.
44+
ψ∞ = infinitemps_approx(ψ; nsites=nsites, nsweeps=10)
45+
46+
println("\nInfinite MPS energy on a few different bonds")
47+
println("Infinite MPS has unit cell of size $nsites")
48+
49+
# Compute a few energies
50+
for n1 in 1:3
51+
n2 = n1 + 1
52+
@show n1, n2
53+
ϕ12 = ψ∞.AL[n1] * ψ∞.AL[n2] * ψ∞.C[n2]
54+
s1 = siteind(ψ∞, n1)
55+
s2 = siteind(ψ∞, n2)
56+
ham12 = contract(MPO(ising_opsum_infinite(1; J=J, h=h), [s1, s2]))
57+
@show inner(ϕ12, apply(ham12, ϕ12)) / norm(ϕ12)
58+
end
59+
60+
return nothing
61+
end
62+
63+
main(; N=100, J=1.0, h=1.5, nsites=1)
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using ITensors
2+
using ITensorInfiniteMPS
3+
using Random
4+
5+
Random.seed!(1234)
6+
7+
# n-site unit cell
8+
nsites = 4
9+
s = siteinds("S=1/2", nsites; conserve_szparity=true)
10+
χ = 10
11+
@assert iseven(χ)
12+
space = (("SzParity", 1, 2) => χ ÷ 2) (("SzParity", 0, 2) => χ ÷ 2)
13+
ψ = InfiniteMPS(ComplexF64, s; space=space)
14+
for n in 1:nsites
15+
ψ[n] = randomITensor(inds(ψ[n]))
16+
end
17+
18+
ψ = orthogonalize(ψ, :)
19+
@show norm(contract.AL[1:nsites]) * ψ.C[nsites] - ψ.C[0] * contract.AR[1:nsites]))
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
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 = false
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+
initstate(n) = ""
29+
s = infsiteinds("S=1/2", N; initstate, conserve_szparity=conserve_qns)
30+
ψ = InfMPS(s, initstate)
31+
32+
# Form the Hamiltonian
33+
H = InfiniteSum{MPO}(model, s; model_params...)
34+
35+
# Check translational invariance
36+
@show norm(contract.AL[1:N]..., ψ.C[N]) - contract.C[0], ψ.AR[1:N]...))
37+
38+
vumps_kwargs = (
39+
tol=tol,
40+
maxiter=max_vumps_iters,
41+
solver_tol=solver_tol,
42+
multisite_update_alg=multisite_update_alg,
43+
)
44+
subspace_expansion_kwargs = (cutoff=cutoff, maxdim=maxdim)
45+
#ψ = tdvp(H, ψ; time_step=time_step, vumps_kwargs...)
46+
47+
# Alternate steps of running VUMPS and increasing the bond dimension
48+
@time for _ in 1:outer_iters
49+
println("\nIncrease bond dimension")
50+
global ψ = subspace_expansion(ψ, H; subspace_expansion_kwargs...)
51+
println("Run VUMPS with new bond dimension")
52+
global ψ = tdvp(H, ψ; time_step=time_step, vumps_kwargs...)
53+
end
54+
55+
# Check translational invariance
56+
@show norm(contract.AL[1:N]..., ψ.C[N]) - contract.C[0], ψ.AR[1:N]...))
57+
58+
#
59+
# Compare to DMRG
60+
#
61+
62+
Nfinite = 100
63+
sfinite = siteinds("S=1/2", Nfinite; conserve_szparity=true)
64+
Hfinite = MPO(model, sfinite; model_params...)
65+
ψfinite = randomMPS(sfinite, initstate)
66+
@show flux(ψfinite)
67+
sweeps = Sweeps(10)
68+
setmaxdim!(sweeps, maxdim)
69+
setcutoff!(sweeps, cutoff)
70+
energy_finite_total, ψfinite = @time dmrg(Hfinite, ψfinite, sweeps)
71+
@show energy_finite_total / Nfinite
72+
73+
function energy_local(ψ1, ψ2, h)
74+
ϕ = ψ1 * ψ2
75+
return (noprime* h) * dag(ϕ))[]
76+
end
77+
78+
function ITensors.expect(ψ, o)
79+
return (noprime* op(o, filterinds(ψ, "Site")...)) * dag(ψ))[]
80+
end
81+
82+
# Exact energy at criticality: 4/pi = 1.2732395447351628
83+
84+
nfinite = Nfinite ÷ 2
85+
orthogonalize!(ψfinite, nfinite)
86+
hnfinite = ITensor(model, sfinite[nfinite], sfinite[nfinite + 1]; model_params...)
87+
energy_finite = energy_local(ψfinite[nfinite], ψfinite[nfinite + 1], hnfinite)
88+
energy_infinite = energy_local.AL[1], ψ.AL[2] * ψ.C[2], contract(H[(1, 2)]))
89+
@show energy_finite, energy_infinite
90+
@show abs(energy_finite - energy_infinite)
91+
92+
energy_exact = reference(model, Observable("energy"); model_params...)
93+
@show energy_exact
94+
95+
Sz1_finite = expect(ψfinite[nfinite], "Sz")
96+
orthogonalize!(ψfinite, nfinite + 1)
97+
Sz2_finite = expect(ψfinite[nfinite + 1], "Sz")
98+
Sz1_infinite = expect.AL[1] * ψ.C[1], "Sz")
99+
Sz2_infinite = expect.AL[2] * ψ.C[2], "Sz")
100+
101+
@show Sz1_finite, Sz2_finite
102+
@show Sz1_infinite, Sz2_infinite
103+
104+
##############################################################################
105+
# Compute eigenspace of the transfer matrix
106+
#
107+
108+
using Arpack
109+
using KrylovKit: eigsolve
110+
using LinearAlgebra
111+
112+
T = TransferMatrix.AL)
113+
Tᵀ = transpose(T)
114+
vⁱᴿ = randomITensor(dag(input_inds(T)))
115+
vⁱᴸ = randomITensor(dag(input_inds(Tᵀ)))
116+
117+
neigs = 10
118+
tol = 1e-10
119+
λ⃗ᴿ, v⃗ᴿ, right_info = eigsolve(T, vⁱᴿ, neigs, :LM; tol=tol)
120+
λ⃗ᴸ, v⃗ᴸ, left_info = eigsolve(Tᵀ, vⁱᴸ, neigs, :LM; tol=tol)
121+
122+
@show norm(T(v⃗ᴿ[1]) - λ⃗ᴿ[1] * v⃗ᴿ[1])
123+
@show norm(Tᵀ(v⃗ᴸ[1]) - λ⃗ᴸ[1] * v⃗ᴸ[1])
124+
125+
@show λ⃗ᴿ
126+
@show λ⃗ᴸ
127+
@show flux.(v⃗ᴿ)
128+
129+
neigs = min(length(v⃗ᴸ), length(v⃗ᴿ))
130+
v⃗ᴸ = v⃗ᴸ[1:neigs]
131+
v⃗ᴿ = v⃗ᴿ[1:neigs]
132+
133+
# Normalize the vectors
134+
N⃗ = [(translatecelltags(v⃗ᴸ[n], 1) * v⃗ᴿ[n])[] for n in 1:neigs]
135+
136+
v⃗ᴿ ./= sqrt.(N⃗)
137+
v⃗ᴸ ./= sqrt.(N⃗)
138+
139+
# Form a second starting vector orthogonal to v⃗ᴿ[1]
140+
# This doesn't work. TODO: project out v⃗ᴿ[1], v⃗ᴸ[1] from T
141+
#λ⃗ᴿ², v⃗ᴿ², right_info_2 = eigsolve(T, vⁱᴿ², neigs, :LM; tol=tol)
142+
143+
# Projector onto the n-th eigenstate
144+
function proj(v⃗ᴸ, v⃗ᴿ, n)
145+
Lⁿ = v⃗ᴸ[n]
146+
Rⁿ = v⃗ᴿ[n]
147+
return ITensorMap(
148+
[translatecelltags(Lⁿ, 1), translatecelltags(Rⁿ, -1)];
149+
input_inds=inds(Rⁿ),
150+
output_inds=inds(Lⁿ),
151+
)
152+
end
153+
154+
P⃗ = [proj(v⃗ᴸ, v⃗ᴿ, n) for n in 1:neigs]
155+
T⁻P = T - sum(P⃗)
156+
157+
#vⁱᴿ² = vⁱᴿ - (translatecelltags(v⃗ᴸ[1], 1) * vⁱᴿ)[] / norm(v⃗ᴿ[1]) * v⃗ᴿ[1]
158+
#@show norm(dag(vⁱᴿ²) * v⃗ᴿ[1])
159+
160+
# XXX: Error with mismatched QN index arrows
161+
# λ⃗ᴾᴿ, v⃗ᴾᴿ, right_info = eigsolve(T⁻P, vⁱᴿ, neigs, :LM; tol=tol)
162+
# @show λ⃗ᴾᴿ
163+
164+
vⁱᴿ⁻ᵈᵃᵗᵃ = vec(array(vⁱᴿ))
165+
λ⃗ᴿᴬ, v⃗ᴿ⁻ᵈᵃᵗᵃ = Arpack.eigs(T; v0=vⁱᴿ⁻ᵈᵃᵗᵃ, nev=neigs)
166+
167+
## XXX: this is giving an error about trying to set the element of the wrong QN block for:
168+
## maxdim = 5
169+
## cutoff = 1e-12
170+
## max_vumps_iters = 10
171+
## outer_iters = 10
172+
## model_params = (J=1.0, h=0.8)
173+
##
174+
## v⃗ᴿᴬ = [itensor(v⃗ᴿ⁻ᵈᵃᵗᵃ[:, n], input_inds(T); tol=1e-4) for n in 1:length(λ⃗ᴿᴬ)]
175+
## @show flux.(v⃗ᴿᴬ)
176+
177+
@show λ⃗ᴿᴬ
178+
179+
# Full eigendecomposition
180+
181+
Tfull = prod(T)
182+
DV = eigen(Tfull, input_inds(T), output_inds(T))
183+
184+
@show norm(Tfull * DV.V - DV.Vt * DV.D)
185+
186+
d = diag(array(DV.D))
187+
188+
p = sortperm(d; by=abs, rev=true)
189+
@show p[1:neigs]
190+
@show d[p[1:neigs]]
191+
192+
println("Error if ED with Arpack")
193+
@show d[p[1:neigs]] - λ⃗ᴿᴬ
File renamed without changes.

examples/vumps/vumps_ising_noncontiguous.jl renamed to examples/development/vumps/vumps_ising_noncontiguous.jl

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,8 @@ N = 2# Number of sites in the unit cell
1818
J = 1.0
1919
h = 1.0;
2020

21-
function space_shifted(q̃sz)
22-
return [QN("SzParity", 1 - q̃sz, 2) => 1, QN("SzParity", 0 - q̃sz, 2) => 1]
23-
end
24-
25-
space_ = fill(space_shifted(1), N);
26-
s = infsiteinds("S=1/2", N; space=space_)
2721
initstate(n) = ""
22+
s = infsiteinds("S=1/2", N; initstate)
2823
ψ = InfMPS(s, initstate);
2924

3025
model = Model("ising");
@@ -70,7 +65,7 @@ Sz_finite = expect(ψfinite, "Sz")[nfinite:(nfinite + N - 1)]
7065
@show (
7166
energy_infinite,
7267
energy_finite_total / Nfinite,
73-
reference(model, Observable("energy"); J=J, h=h, J₂=J₂),
68+
reference(model, Observable("energy"); J=J, h=h),
7469
)
7570

7671
@show (Sz, Sz_finite)

examples/vumps/vumps_localham.jl renamed to examples/development/vumps/vumps_localham.jl

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ using Random
44

55
Random.seed!(1234)
66

7-
include("models.jl")
8-
97
function _siteind(site_tag, n::Int; space)
108
return addtags(Index(space, "Site,n=$n"), site_tag)
119
end

examples/vumps/development/vumps_mpo.jl renamed to examples/development/vumps/vumps_mpo.jl

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,35 +10,30 @@ maxiter = 20
1010
outer_iters = 3
1111

1212
N = 2
13-
model = Model"ising"()
13+
model = Model("ising")
1414

15-
function space_shifted(::Model"ising", q̃sz)
16-
return [QN("SzParity", 1 - q̃sz, 2) => 1, QN("SzParity", 0 - q̃sz, 2) => 1]
17-
end
18-
19-
space_ = fill(space_shifted(model, 1), N)
20-
s = infsiteinds("S=1/2", N; space=space_)
2115
initstate(n) = ""
16+
s = infsiteinds("S=1/2", N; initstate)
2217
ψ = InfMPS(s, initstate)
2318

2419
model_params = (J=-1.0, h=0.9)
2520
vumps_kwargs = (multisite_update_alg="sequential", tol=tol, maxiter=maxiter)
2621
subspace_expansion_kwargs = (cutoff=cutoff, maxdim=maxdim)
2722

28-
H = InfiniteITensorSum(model, s; model_params...)
23+
H = InfiniteSum{ITensor}(model, s; model_params...)
2924
# Alternate steps of running VUMPS and increasing the bond dimension
3025
ψ1 = vumps(H, ψ; vumps_kwargs...)
3126
for _ in 1:outer_iters
32-
ψ1 = subspace_expansion(ψ1, H; subspace_expansion_kwargs...)
33-
ψ1 = vumps(H, ψ1; vumps_kwargs...)
27+
global ψ1 = subspace_expansion(ψ1, H; subspace_expansion_kwargs...)
28+
global ψ1 = vumps(H, ψ1; vumps_kwargs...)
3429
end
3530

3631
Hmpo = InfiniteMPOMatrix(model, s; model_params...)
3732
# Alternate steps of running VUMPS and increasing the bond dimension
3833
ψ2 = vumps(Hmpo, ψ; vumps_kwargs...)
3934
for _ in 1:outer_iters
40-
ψ2 = subspace_expansion(ψ2, Hmpo; subspace_expansion_kwargs...)
41-
ψ2 = vumps(Hmpo, ψ2; vumps_kwargs...)
35+
global ψ2 = subspace_expansion(ψ2, Hmpo; subspace_expansion_kwargs...)
36+
global ψ2 = vumps(Hmpo, ψ2; vumps_kwargs...)
4237
end
4338

4439
SzSz = prod(op("Sz", s[1]) * op("Sz", s[2]))

0 commit comments

Comments
 (0)