Skip to content

Commit f54c85c

Browse files
authored
Finite-T improvements and utility (#324)
* Add missing transfer operations * Add fallback `contract_mpo_expval` definition * fix merge * Add support for imaginary time evolution with real tensors * Fix `complex(::MPOHamiltonian)` * fix typo * fix typo * Refactor IDMRG to be compatible with density matrix mps * Fix fallback with missing function * Real scalartype improvements * Disable spacecheck for finite T * Fix spacecheck on operator * Add missing return value * Fix wrong derivative * fix `dot(::InfiniteMPS, ::InfiniteMPO, ::InfiniteMPS)` * loosen type restriction * fix type check * fix possibly-in-place-copy * formatter * fix timedependent integrator * fix scalartype determination in InfiniteMPS constructor * improve test coverage * improve WII coverage and fix * improve `real(::MPOHamiltonian)` coverage * small fix in dot(::InfiniteMPS, ::InfiniteMPO, ::InfiniteMPS) * Distinguish between finite and infinite traces of MPO * improve coverage some more
1 parent de2ac9f commit f54c85c

File tree

17 files changed

+386
-159
lines changed

17 files changed

+386
-159
lines changed

src/algorithms/approximate/approximate.jl

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,13 @@ function approximate(
3232
envs = environments(ψ, toapprox)
3333
)
3434
envs′ = Multiline([envs])
35-
multi, envs = approximate(
35+
multi, envs, δ = approximate(
3636
convert(MultilineMPS, ψ),
3737
(convert(MultilineMPO, toapprox[1]), convert(MultilineMPS, toapprox[2])),
38-
algorithm,
39-
envs′
38+
algorithm, envs′
4039
)
4140
ψ = convert(InfiniteMPS, multi)
42-
return ψ, envs
41+
return ψ, envs, δ
4342
end
4443

4544
# dispatch to in-place method
@@ -56,12 +55,11 @@ function approximate(
5655
algorithm::Union{IDMRG, IDMRG2}, envs = environments(ψ, toapprox)
5756
)
5857
envs′ = Multiline([envs])
59-
multi, envs = approximate(
58+
multi, envs, δ = approximate(
6059
convert(MultilineMPS, ψ),
6160
(convert(MultilineMPO, toapprox[1]), convert(MultilineMPS, toapprox[2])),
62-
algorithm,
63-
envs′
61+
algorithm, envs′
6462
)
6563
ψ = convert(InfiniteMPS, multi)
66-
return ψ, envs
64+
return ψ, envs, δ
6765
end

src/algorithms/changebonds/svdcut.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ function changebonds!(ψ::AbstractFiniteMPS, alg::SvdCut; normalize::Bool = true
2929
for i in (length(ψ) - 1):-1:1
3030
U, S, V, = tsvd.C[i]; trunc = alg.trscheme, alg = alg.alg_svd)
3131
AL′ = ψ.AL[i] * U
32-
ψ.AC[i] = (AL′, complex(S))
32+
ψ.AC[i] = (AL′, S)
3333
AR′ = _transpose_front(V * _transpose_tail.AR[i + 1]))
34-
ψ.AC[i + 1] = (complex(S), AR′)
34+
ψ.AC[i + 1] = (S, AR′)
3535
end
3636
return normalize ? normalize!(ψ) : ψ
3737
end
@@ -87,7 +87,7 @@ function changebonds(ψ::MultilineMPS, alg::SvdCut)
8787
return Multiline(map(x -> changebonds(x, alg), ψ.data))
8888
end
8989
function changebonds::InfiniteMPS, alg::SvdCut)
90-
copied = complex.(ψ.AL)
90+
copied = copy.(ψ.AL)
9191
ncr = ψ.C[1]
9292

9393
for i in 1:length(ψ)
@@ -103,7 +103,7 @@ function changebonds(ψ::InfiniteMPS, alg::SvdCut)
103103
ψ = if space(ncr, 1) != space(copied[1], 1)
104104
InfiniteMPS(copied)
105105
else
106-
C₀ = ncr isa TensorMap ? complex(ncr) : TensorMap(complex(ncr))
106+
C₀ = ncr isa TensorMap ? ncr : TensorMap(ncr)
107107
InfiniteMPS(copied, C₀)
108108
end
109109
return normalize!(ψ)

src/algorithms/expval.jl

Lines changed: 74 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -37,53 +37,42 @@ function expectation_value end
3737
function expectation_value::AbstractMPS, (inds, O)::Pair)
3838
@boundscheck foreach(Base.Fix1(Base.checkbounds, ψ), inds)
3939

40-
sites, local_mpo = instantiate_operator(physicalspace(ψ), inds => O)
41-
@assert _firstspace(first(local_mpo)) == oneunit(_firstspace(first(local_mpo))) ==
42-
dual(_lastspace(last(local_mpo)))
43-
for (site, o) in zip(sites, local_mpo)
44-
if o isa MPOTensor
45-
physicalspace(ψ, site) == physicalspace(o) ||
46-
throw(SpaceMismatch("physical space does not match at site $site"))
47-
end
40+
# special cases that can be handled more efficiently
41+
if length(inds) == 1
42+
return local_expectation_value1(ψ, inds[1], O)
43+
elseif length(inds) == 2 && eltype(inds) <: Integer && inds[1] + 1 == inds[2]
44+
return local_expectation_value2(ψ, inds[1], O)
4845
end
4946

50-
Ut = fill_data!(similar(local_mpo[1], _firstspace(first(local_mpo))), one)
51-
52-
# some special cases that avoid using transfer matrices
53-
if length(sites) == 1
54-
AC = ψ.AC[sites[1]]
55-
E = @plansor conj(AC[4 5; 6]) * conj(Ut[1]) * local_mpo[1][1 5; 3 2] * Ut[2] *
56-
AC[4 3; 6]
57-
elseif length(sites) == 2 && (sites[1] + 1 == sites[2])
58-
AC = ψ.AC[sites[1]]
59-
AR = ψ.AR[sites[2]]
60-
O1, O2 = local_mpo
61-
E = @plansor conj(AC[4 5; 10]) * conj(Ut[1]) * O1[1 5; 3 8] * AC[4 3; 6] *
62-
conj(AR[10 9; 11]) * Ut[2] * O2[8 9; 7 2] * AR[6 7; 11]
63-
else
64-
# generic case: write as Vl * T^N * Vr
65-
# left side
66-
T = storagetype(site_type(ψ))
67-
@plansor Vl[-1 -2; -3] := isomorphism(
68-
T, left_virtualspace(ψ, sites[1]), left_virtualspace(ψ, sites[1])
69-
)[-1; -3] *
70-
conj(Ut[-2])
71-
72-
# middle
73-
M = foldl(zip(sites, local_mpo); init = Vl) do v, (site, o)
74-
if o isa Number
75-
return scale!(v * TransferMatrix.AL[site], ψ.AL[site]), o)
76-
else
77-
return v * TransferMatrix.AL[site], o, ψ.AL[site])
78-
end
79-
end
47+
# generic case: convert to MPO and write as Vl * T^N * Vr
48+
sites, local_mpo = instantiate_operator(ψ, inds => O)
49+
50+
# left side
51+
Vl = insertrightunit(l_LL(ψ, sites[1]), 1; dual = true)
8052

81-
# right side
82-
E = @plansor M[1 2; 3] * Ut[2] * ψ.C[sites[end]][3; 4] *
83-
conj.C[sites[end]][1; 4])
53+
# middle
54+
M = foldl(zip(sites, local_mpo); init = Vl) do v, (site, o)
55+
if o isa Number
56+
return scale!(v * TransferMatrix.AL[site], ψ.AL[site]), o)
57+
else
58+
return v * TransferMatrix.AL[site], o, ψ.AL[site])
59+
end
8460
end
8561

86-
return E / norm(ψ)^2
62+
# right side
63+
E = @plansor removeunit(M, 2)[1; 2] * ψ.C[sites[end]][2; 3] * conj.C[sites[end]][1; 3])
64+
return E / dot(ψ, ψ)
65+
end
66+
67+
function local_expectation_value1::AbstractMPS, site, O)
68+
E = contract_mpo_expval1.AC[site], O, ψ.AC[site])
69+
return E / dot(ψ, ψ)
70+
end
71+
function local_expectation_value2::AbstractMPS, site, O)
72+
AC = ψ.AC[site]
73+
AR = ψ.AR[site + 1]
74+
E = contract_mpo_expval2(AC, AR, O, AC, AR)
75+
return E / dot(ψ, ψ)
8776
end
8877

8978
# MPOHamiltonian
@@ -93,6 +82,40 @@ function contract_mpo_expval(
9382
)
9483
return @plansor GL[1 2; 3] * AC[3 7; 5] * GR[5 8; 6] * O[2 4; 7 8] * conj(ACbar[1 4; 6])
9584
end
85+
# generic fallback
86+
function contract_mpo_expval(AC, GL, O, GR, ACbar = AC)
87+
return dot(ACbar, MPO_AC_Hamiltonian(GL, O, GR) * AC)
88+
end
89+
90+
function contract_mpo_expval1(AC::MPSTensor, O::AbstractTensorMap, ACbar::MPSTensor = AC)
91+
numin(O) == numout(O) == 1 || throw(ArgumentError("O is not a single-site operator"))
92+
return @plansor conj(ACbar[2 3; 4]) * O[3; 1] * AC[2 1; 4]
93+
end
94+
function contract_mpo_expval1(
95+
AC::GenericMPSTensor{S, 3}, O::AbstractTensorMap{<:Any, S},
96+
ACbar::GenericMPSTensor{S, 3} = AC
97+
) where {S}
98+
numin(O) == numout(O) == 1 || throw(ArgumentError("O is not a single-site operator"))
99+
return @plansor conj(ACbar[2 3 4; 5]) * O[3; 1] * AC[2 1 4; 5]
100+
end
101+
102+
function contract_mpo_expval2(
103+
A1::MPSTensor, A2::MPSTensor, O::AbstractTensorMap,
104+
A1bar::MPSTensor = A1, A2bar::MPSTensor = A2
105+
)
106+
numin(O) == numout(O) == 2 || throw(ArgumentError("O is not a two-site operator"))
107+
return @plansor conj(A1bar[4 5; 6]) * conj(A2bar[6 7; 8]) * O[5 7; 2 3] * A1[4 2; 1] *
108+
A2[1 3; 8]
109+
end
110+
function contract_mpo_expval2(
111+
A1::GenericMPSTensor{S, 3}, A2::GenericMPSTensor{S, 3},
112+
O::AbstractTensorMap{<:Any, S},
113+
A1bar::GenericMPSTensor{S, 3} = A1, A2bar::GenericMPSTensor{S, 3} = A2
114+
) where {S}
115+
numin(O) == numout(O) == 2 || throw(ArgumentError("O is not a two-site operator"))
116+
return @plansor conj(A1bar[8 3 4; 11]) * conj(A2bar[11 12 13; 14]) * τ[9 6; 1 2] *
117+
τ[3 4; 9 10] * A1[8 1 2; 5] * A2[5 7 13; 14] * O[10 12; 6 7]
118+
end
96119

97120
function expectation_value(
98121
ψ::FiniteMPS, H::FiniteMPOHamiltonian,
@@ -177,3 +200,12 @@ function expectation_value(
177200
n = norm.AC[end])^2
178201
return sum(ens) / (n * length(ψ))
179202
end
203+
204+
# Density matrices
205+
# ----------------
206+
function expectation_value::FiniteMPO, args...)
207+
return expectation_value(convert(FiniteMPS, ρ), args...)
208+
end
209+
function expectation_value::InfiniteMPO, args...)
210+
return expectation_value(convert(InfiniteMPS, ρ), args...)
211+
end

src/algorithms/timestep/integrators.jl

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,12 @@ function integrate end
1717
_eval_t(f, t::Number) = Base.Fix2(f, t)
1818
_eval_x(f, x) = Base.Fix1(f, x)
1919

20-
function integrate(f, y₀, t::Number, dt::Number, alg::Union{Arnoldi, Lanczos})
21-
y, convhist = exponentiate(_eval_t(f, t + dt / 2), -1im * dt, y₀, alg)
20+
function integrate(
21+
f, y₀, t::Number, dt::Number, alg::Union{Arnoldi, Lanczos};
22+
imaginary_evolution::Bool = false
23+
)
24+
dt′ = imaginary_evolution ? -dt : -1im * dt
25+
y, convhist = exponentiate(_eval_t(f, t + dt / 2), dt′, y₀, alg)
2226
convhist.converged == 0 &&
2327
@warn "integrator failed to converge: normres = $(convhist.normres)"
2428
return y

src/algorithms/timestep/taylorcluster.jl

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,11 @@ First order Taylor expansion for a time-evolution MPO.
2828
const WI = TaylorCluster(; N = 1, extension = false, compression = false)
2929

3030
function make_time_mpo(
31-
H::MPOHamiltonian, dt::Number, alg::TaylorCluster; tol = eps(real(scalartype(H)))
31+
H::MPOHamiltonian, dt::Number, alg::TaylorCluster;
32+
tol = eps(real(scalartype(H))), imaginary_evolution::Bool = false
3233
)
3334
N = alg.N
34-
τ = -1im * dt
35+
τ = imaginary_evolution ? -dt : -1im * dt
3536

3637
# start with H^N
3738
H_n = H^N
@@ -180,7 +181,7 @@ end
180181
# Hack to treat FiniteMPOhamiltonians as Infinite
181182
function make_time_mpo(
182183
H::FiniteMPOHamiltonian, dt::Number, alg::TaylorCluster;
183-
tol = eps(real(scalartype(H)))
184+
tol = eps(real(scalartype(H))), imaginary_evolution::Bool = false
184185
)
185186
H′ = copy(parent(H))
186187

@@ -201,7 +202,7 @@ function make_time_mpo(
201202
H′[1][end, 1, 1, end] = H′[1][1, 1, 1, 1]
202203
H′[end][1, 1, 1, 1] = H′[end][end, 1, 1, end]
203204

204-
mpo = make_time_mpo(InfiniteMPOHamiltonian(H′), dt, alg; tol)
205+
mpo = make_time_mpo(InfiniteMPOHamiltonian(H′), dt, alg; tol, imaginary_evolution)
205206

206207
# Impose boundary conditions
207208
mpo_fin = open_boundary_conditions(mpo, length(H))

0 commit comments

Comments
 (0)