Skip to content

Commit 75e761e

Browse files
authored
Replace the local ITensors by MPOs in InfiniteITensorSum (#45)
1 parent 7cb7673 commit 75e761e

File tree

11 files changed

+337
-409
lines changed

11 files changed

+337
-409
lines changed

examples/vumps/vumps_ising_extended.jl

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -44,39 +44,6 @@ for j in 1:outer_iters
4444
ψ_0 = vumps(H, ψ_1; vumps_kwargs...)
4545
end
4646

47-
function ITensors.expect::InfiniteCanonicalMPS, o, n)
48-
return (noprime.AL[n] * ψ.C[n] * op(o, s[n])) * dag.AL[n] * ψ.C[n]))[]
49-
end
50-
51-
function ITensors.expect::InfiniteCanonicalMPS, h::ITensor)
52-
l = linkinds(only, ψ.AL)
53-
r = linkinds(only, ψ.AR)
54-
s = siteinds(only, ψ)
55-
δˢ(n) = δ(dag(s[n]), prime(s[n]))
56-
δˡ(n) = δ(l[n], prime(dag(l[n])))
57-
δʳ(n) = δ(dag(r[n]), prime(r[n]))
58-
ψ′ = prime(dag(ψ))
59-
60-
ns = sort(findsites(ψ, h))
61-
nrange = ns[end] - ns[1] + 1
62-
idx = 2
63-
temp_O = δˡ(ns[1] - 1) * ψ.AL[ns[1]] * h * ψ′.AL[ns[1]]
64-
for n in (ns[1] + 1):(ns[1] + nrange - 1)
65-
if n == ns[idx]
66-
temp_O = temp_O * ψ.AL[n] * ψ′.AL[n]
67-
idx += 1
68-
else
69-
temp_O = temp_O * ψ.AL[n] * δˢ(n) * ψ′.AL[n]
70-
end
71-
end
72-
temp_O = temp_O * ψ.C[ns[end]] * δʳ(ns[end]) * ψ′.C[ns[end]]
73-
return temp_O[]
74-
end
75-
76-
function ITensors.expect::InfiniteCanonicalMPS, h::InfiniteITensorSum)
77-
return [expect(ψ, h[(j, j + 1)]) for j in 1:nsites(ψ)]
78-
end
79-
8047
Sz = [expect(ψ_0, "Sz", n) for n in 1:N]
8148
energy_infinite = expect(ψ_0, H)
8249

examples/vumps/vumps_ising_noncontiguous.jl

Lines changed: 5 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,11 @@ model = Model("ising");
3131
H = InfiniteITensorSum(model, s; J=J, h=h);
3232
#to test the case where the range is larger than the unit cell size
3333
for x in 1:N
34-
H.data[x] = H.data[x] * delta(prime(s[x + 3]), dag(s[x + 3]))
34+
temp = MPO(3)
35+
temp[1] = H[x][1]
36+
temp[2] = H[x][2]
37+
temp[3] = delta(prime(s[x + 3]), dag(s[x + 3]))
38+
H.data[x] = temp
3539
end
3640

3741
@show norm(contract.AL[1:N]..., ψ.C[N]) - contract.C[0], ψ.AR[1:N]...));
@@ -47,39 +51,6 @@ for j in 1:outer_iters
4751
ψ_0 = vumps(H, ψ_1; vumps_kwargs...)
4852
end
4953

50-
function ITensors.expect::InfiniteCanonicalMPS, o, n)
51-
return (noprime.AL[n] * ψ.C[n] * op(o, s[n])) * dag.AL[n] * ψ.C[n]))[]
52-
end
53-
54-
function ITensors.expect::InfiniteCanonicalMPS, h::ITensor)
55-
l = linkinds(only, ψ.AL)
56-
r = linkinds(only, ψ.AR)
57-
s = siteinds(only, ψ)
58-
δˢ(n) = δ(dag(s[n]), prime(s[n]))
59-
δˡ(n) = δ(l[n], prime(dag(l[n])))
60-
δʳ(n) = δ(dag(r[n]), prime(r[n]))
61-
ψ′ = prime(dag(ψ))
62-
63-
ns = sort(findsites(ψ, h))
64-
nrange = ns[end] - ns[1] + 1
65-
idx = 2
66-
temp_O = δˡ(ns[1] - 1) * ψ.AL[ns[1]] * h * ψ′.AL[ns[1]]
67-
for n in (ns[1] + 1):(ns[1] + nrange - 1)
68-
if n == ns[idx]
69-
temp_O = temp_O * ψ.AL[n] * ψ′.AL[n]
70-
idx += 1
71-
else
72-
temp_O = temp_O * ψ.AL[n] * δˢ(n) * ψ′.AL[n]
73-
end
74-
end
75-
temp_O = temp_O * ψ.C[ns[end]] * δʳ(ns[end]) * ψ′.C[ns[end]]
76-
return temp_O[]
77-
end
78-
79-
function ITensors.expect::InfiniteCanonicalMPS, h::InfiniteITensorSum)
80-
return [expect(ψ, h[(j, j + 1)]) for j in 1:nsites(ψ)]
81-
end
82-
8354
Sz = [expect(ψ_0, "Sz", n) for n in 1:N]
8455
energy_infinite = expect(ψ_0, H)
8556

src/ITensors.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ function Base.startswith(tag::Tag, subtag::Tag)
7272
end
7373

7474
function tag_starting_with(ts::TagSet, prefix)
75+
x = findfirst(t -> startswith(t, Tag(prefix)), ts)
76+
if isnothing(x) #in case the function is called one a link leg. Can be probably improved
77+
return x
78+
end
7579
return ts[findfirst(t -> startswith(t, Tag(prefix)), ts)]
7680
end
7781

src/celledvectors.jl

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,22 @@ indextagprefix() = "n="
2525
# Determine the cell `n` from the tag `"c=n"`
2626
function getcell(ts::TagSet)
2727
celltag = tag_starting_with(ts, celltagprefix())
28+
if isnothing(celltag) #dealing with link legs
29+
return celltag
30+
end
2831
return parse(Int, celltag[(length(celltagprefix()) + 1):end])
2932
end
3033

3134
function getsite(ts::TagSet)
32-
celltag = ITensorInfiniteMPS.tag_starting_with(ts, indextagprefix())
35+
celltag = tag_starting_with(ts, indextagprefix())
3336
return parse(Int, celltag[(length(indextagprefix()) + 1):end])
3437
end
3538

3639
function translatecell(ts::TagSet, n::Integer)
3740
ncell = getcell(ts)
41+
if isnothing(ncell)
42+
return ts
43+
end
3844
return replacetags(ts, celltags(ncell) => celltags(ncell + n))
3945
end
4046

@@ -49,6 +55,7 @@ function translatecell(is::Union{<:Tuple,<:Vector}, n::Integer)
4955
end
5056

5157
translatecell(T::ITensor, n::Integer) = ITensors.setinds(T, translatecell(inds(T), n))
58+
translatecell(T::MPO, n::Integer) = translatecell.(T, n)
5259

5360
struct CelledVector{T} <: AbstractVector{T}
5461
data::Vector{T}

src/infinitecanonicalmps.jl

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,3 +115,37 @@ function InfMPS(s::CelledVector, f::Function)
115115
end
116116
return ψ = InfiniteCanonicalMPS(ψL, ψC, ψR)
117117
end
118+
119+
function ITensors.expect::InfiniteCanonicalMPS, o, n)
120+
s = siteinds(only, ψ.AL)
121+
return (noprime.AL[n] * ψ.C[n] * op(o, s[n])) * dag.AL[n] * ψ.C[n]))[]
122+
end
123+
124+
function ITensors.expect::InfiniteCanonicalMPS, h::MPO)
125+
l = linkinds(ITensorInfiniteMPS.only, ψ.AL)
126+
r = linkinds(ITensorInfiniteMPS.only, ψ.AR)
127+
s = siteinds(ITensorInfiniteMPS.only, ψ)
128+
δˢ(n) = ITensorInfiniteMPS.δ(dag(s[n]), prime(s[n]))
129+
δˡ(n) = ITensorInfiniteMPS.δ(l[n], prime(dag(l[n])))
130+
δʳ(n) = ITensorInfiniteMPS.δ(dag(r[n]), prime(r[n]))
131+
ψ′ = prime(dag(ψ))
132+
133+
ns = ITensorInfiniteMPS.findsites(ψ, h)
134+
nrange = ns[end] - ns[1] + 1
135+
idx = 2
136+
temp_O = δˡ(ns[1] - 1) * ψ.AL[ns[1]] * ψ′.AL[ns[1]] * h[1]
137+
for n in (ns[1] + 1):(ns[1] + nrange - 1)
138+
if n == ns[idx]
139+
temp_O = temp_O * ψ.AL[n] * ψ′.AL[n] * h[idx]
140+
idx += 1
141+
else
142+
temp_O = temp_O * ψ.AL[n] * δˢ(n) * ψ′.AL[n]
143+
end
144+
end
145+
temp_O = temp_O * ψ.C[ns[end]] * δʳ(ns[end]) * ψ′.C[ns[end]]
146+
return temp_O[]
147+
end
148+
149+
function ITensors.expect::InfiniteCanonicalMPS, h::InfiniteITensorSum)
150+
return [expect(ψ, h[j]) for j in 1:nsites(ψ)]
151+
end

src/infinitemps.jl

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,24 @@ end
5757

5858
ITensors.siteinds(f::typeof(only), ψ::InfiniteCanonicalMPS) = siteinds(f, ψ.AL)
5959

60-
ITensorInfiniteMPS.getcell(i::Index) = ITensorInfiniteMPS.getcell(tags(i))
60+
getcell(i::Index) = ITensorInfiniteMPS.getcell(tags(i))
6161
getsite(i::Index) = getsite(tags(i))
62+
63+
#Before, for a two site Hamiltonian, findsites(ψ, H[3]) would return [1, 2]
64+
#Appeared unsafe for index purpose
6265
function ITensors.findfirstsiteind::InfiniteMPS, i::Index)
6366
c = ITensorInfiniteMPS.getcell(i)
64-
i1 = translatecell(i, -(c - 1))
65-
n1 = findfirst(hascommoninds(i1), ψ[Cell(1)])
67+
n1 = getsite(i)
6668
return (c - 1) * nsites(ψ) + n1
6769
end
70+
71+
function ITensors.findsites::InfiniteMPS, T::MPO)
72+
s = [noprime(filterinds(T[x]; plev=1)[1]) for x in 1:length(T)]
73+
return sort([ITensors.findfirstsiteind(ψ, i) for i in s])
74+
end
75+
ITensors.findsites::InfiniteCanonicalMPS, T::MPO) = findsites.AL, T)
76+
77+
#Kept for historical reason
6878
function ITensors.findsites::InfiniteMPS, T::ITensor)
6979
s = filterinds(T; plev=0)
7080
return sort([ITensors.findfirstsiteind(ψ, i) for i in s])
@@ -74,38 +84,57 @@ ITensors.findsites(ψ::InfiniteCanonicalMPS, T::ITensor) = findsites(ψ.AL, T)
7484
# For now, only represents nearest neighbor interactions
7585
# on a linear chain
7686
struct InfiniteITensorSum
77-
data::CelledVector{ITensor}
87+
data::CelledVector{MPO}
7888
end
7989
InfiniteITensorSum(N::Int) = InfiniteITensorSum(Vector{ITensor}(undef, N))
80-
InfiniteITensorSum(data::Vector{ITensor}) = InfiniteITensorSum(CelledVector(data))
90+
InfiniteITensorSum(data::Vector{MPO}) = InfiniteITensorSum(CelledVector(data))
91+
InfiniteITensorSum(data::Vector{ITensor}) = InfiniteITensorSum(CelledVector(MPO.(data)))
8192
function Base.getindex(l::InfiniteITensorSum, n1n2::Tuple{Int,Int})
8293
n1, n2 = n1n2
8394
@assert n2 == n1 + 1
8495
return l.data[n1]
8596
end
97+
function Base.getindex(l::InfiniteITensorSum, n1::Int)
98+
return l.data[n1]
99+
end
86100
nsites(h::InfiniteITensorSum) = length(h.data)
87101
#Gives the range of the Hamiltonian. Useful for better optimized contraction in VUMPS
88-
nsites_support(h::InfiniteITensorSum) = order.(h.data) ÷ 2
89-
nsites_support(h::InfiniteITensorSum, n::Int64) = order(h.data[n]) ÷ 2
102+
nsites_support(h::InfiniteITensorSum) = length.(h.data)
103+
nsites_support(h::InfiniteITensorSum, n::Int64) = length(h.data[n])
90104

91105
nrange(h::InfiniteITensorSum) = nrange.(h.data, ncell=nsites(h))
92106
nrange(h::InfiniteITensorSum, n::Int64) = nrange(h.data[n]; ncell=nsites(h))
93-
function nrange(h::ITensor; ncell=0)
107+
function nrange(h::MPO; ncell=1)
94108
ns = findsites(h; ncell=ncell)
95109
return ns[end] - ns[1] + 1
96110
end
97111

98-
function ITensors.findfirstsiteind(h::ITensor, i::Index, ncell::Int64)
112+
ITensors.findsites(h::InfiniteITensorSum) = [findsites(h, n) for n in 1:nsites(h)]
113+
ITensors.findsites(h::InfiniteITensorSum, n::Int64) = findsites(h.data[n]; ncell=nsites(h))
114+
function ITensors.findfirstsiteind(i::Index, ncell::Int64)
99115
c = ITensorInfiniteMPS.getcell(i)
100116
n1 = getsite(i)
101117
return (c - 1) * ncell + n1
102118
end
119+
function ITensors.findsites(h::MPO; ncell::Int64=1)
120+
s = [filterinds(h[x]; plev=1)[1] for x in 1:length(h)]
121+
return sort([ITensors.findfirstsiteind(i, ncell) for i in s])
122+
end
123+
124+
#Kept for historical reasons
125+
function nrange(h::ITensor; ncell=0)
126+
ns = findsites(h; ncell=ncell)
127+
return ns[end] - ns[1] + 1
128+
end
129+
function ITensors.findfirstsiteind(h::ITensor, i::Index, ncell::Int64)
130+
c = getcell(i)
131+
n1 = getsite(i)
132+
return (c - 1) * ncell + n1
133+
end
103134
function ITensors.findsites(h::ITensor; ncell::Int64=1)
104135
s = filterinds(h; plev=0)
105136
return sort([ITensors.findfirstsiteind(h, i, ncell) for i in s])
106137
end
107-
ITensors.findsites(h::InfiniteITensorSum) = [findsites(h, n) for n in 1:nsites(h)]
108-
ITensors.findsites(h::InfiniteITensorSum, n::Int64) = findsites(h.data[n]; ncell=nsites(h))
109138

110139
## HDF5 support for the InfiniteCanonicalMPS type
111140

src/models/models.jl

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,18 @@ end
2424

2525
function InfiniteITensorSum(model::Model, s::CelledVector; kwargs...)
2626
N = length(s)
27-
tensors = [ITensor(model, s, n; kwargs...) for n in 1:N] #slightly improved version. Note: the current implementation does not really allow for staggered potentials for example
28-
return InfiniteITensorSum(tensors)
27+
mpos = [MPO(model, s, n; kwargs...) for n in 1:N] #slightly improved version. Note: the current implementation does not really allow for staggered potentials for example
28+
return InfiniteITensorSum(mpos)
2929
end
3030

31-
# Version accepting IndexSet
32-
function ITensors.ITensor(model::Model, s::CelledVector, n::Int64; kwargs...)
31+
# MPO building version
32+
function ITensors.MPO(model::Model, s::CelledVector, n::Int64; kwargs...)
3333
n1, n2 = 1, 2
3434
opsum = OpSum(model, n1, n2; kwargs...)
35-
return prod(MPO(opsum, [s[x] for x in n:(n + nrange(model) - 1)])) #modification to allow for more than two sites per term in the Hamiltonians
35+
return MPO(opsum, [s[x] for x in n:(n + nrange(model) - 1)]) #modification to allow for more than two sites per term in the Hamiltonians
36+
end
37+
38+
# Version accepting IndexSet
39+
function ITensors.ITensor(model::Model, s::CelledVector, n::Int64; kwargs...)
40+
return prod(MPO(model, s, n; kwargs...)) #modification to allow for more than two sites per term in the Hamiltonians
3641
end

src/subspace_expansion.jl

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -45,48 +45,61 @@ function subspace_expansion(
4545
nL = uniqueinds(NL, ψ.AL[n1])
4646
nR = uniqueinds(NR, ψ.AR[n2])
4747
if range_H == 2
48-
ψH2 = noprime.AL[n1] * H[(n1, n2)] * ψ.C[n1] * ψ.AR[n2])
48+
ψH2 = noprime.AL[n1] * H[n1][1] * H[n1][2] * ψ.C[n1] * ψ.AR[n2])
4949
else # Should be a better version now
5050
ψH2 =
51-
H[(n1, n2)] * ψ.AR[n2 + range_H - 2] * ψ′.AR[n2 + range_H - 2] * δʳ(n2 + range_H - 2)
51+
H[n1][end] * ψ.AR[n2 + range_H - 2] * ψ′.AR[n2 + range_H - 2] * δʳ(n2 + range_H - 2)
5252
common_sites = findsites(ψ, H[(n1, n2)])
5353
idx = length(common_sites) - 1
5454
for j in reverse(1:(range_H - 3))
5555
if n2 + j == common_sites[idx]
56-
ψH2 = ψH2 * ψ.AR[n2 + j] * ψ′.AR[n2 + j]
56+
ψH2 = ψH2 * ψ.AR[n2 + j] * ψ′.AR[n2 + j] * H[n1][idx]
5757
idx -= 1
5858
else
5959
ψH2 = ψH2 * ψ.AR[n2 + j] * δˢ(n2 + j) * ψ′.AR[n2 + j]
6060
end
6161
end
62-
ψH2 = noprime(ψH2 * ψ.AL[n1] * ψ.C[n1] * ψ.AR[n2])
62+
if common_sites[idx] == n2
63+
ψH2 = ψH2 * ψ.AR[n2] * H[n1][idx]
64+
idx -= 1
65+
else
66+
ψH2 = ψH2 * ψ.AR[n2] * δˢ(n2)
67+
end
68+
if common_sites[idx] == n1
69+
ψH2 = ψH2 * ψ.AL[n1] * ψ.C[n1] * H[n1][idx]
70+
idx -= 1
71+
else
72+
ψH2 = ψH2 * ψ.AL[n1] * ψ.C[n1] * δˢ(n1)
73+
end
74+
75+
ψH2 = noprime(ψH2)
6376
for n in 1:(range_H - 2)
64-
temp_H2 = H[(n1 - n, n2 - n)] * δʳ(n2 + range_H - 2 - n)
65-
common_sites = findsites(ψ, H[(n1 - n, n2 - n)])
77+
temp_H2 = δʳ(n2 + range_H - 2 - n)
78+
common_sites = findsites(ψ, H[n1 - n])
6679
idx = length(common_sites)
6780
for j in (n2 + range_H - 2 - n):-1:(n2 + 1)
6881
if j == common_sites[idx]
69-
temp_H2 = temp_H2 * ψ.AR[j] * ψ′.AR[j]
82+
temp_H2 = temp_H2 * ψ.AR[j] * ψ′.AR[j] * H[n1 - n][idx]
7083
idx -= 1
7184
else
7285
temp_H2 = temp_H2 * ψ.AR[j] * ψ′.AR[j] * δˢ(j)
7386
end
7487
end
7588
if common_sites[idx] == n2
76-
temp_H2 = temp_H2 * ψ.AR[n2]
89+
temp_H2 = temp_H2 * ψ.AR[n2] * H[n1 - n][idx]
7790
idx -= 1
7891
else
7992
temp_H2 = temp_H2 * ψ.AR[n2] * δˢ(n2)
8093
end
8194
if common_sites[idx] == n1
82-
temp_H2 = temp_H2 * ψ.AL[n1] * ψ.C[n1]
95+
temp_H2 = temp_H2 * ψ.AL[n1] * ψ.C[n1] * H[n1 - n][idx]
8396
idx -= 1
8497
else
8598
temp_H2 = temp_H2 * ψ.AL[n1] * ψ.C[n1] * δˢ(n1)
8699
end
87100
for j in 1:n
88101
if n1 - j == common_sites[idx]
89-
temp_H2 = temp_H2 * ψ.AL[n1 - j] * ψ′.AL[n1 - j]
102+
temp_H2 = temp_H2 * ψ.AL[n1 - j] * ψ′.AL[n1 - j] * H[n1 - n][idx]
90103
idx -= 1
91104
else
92105
temp_H2 = temp_H2 * ψ.AL[n1 - j] * δˢ(n1 - j) * ψ′.AL[n1 - j]

0 commit comments

Comments
 (0)