Skip to content

Commit 813e3f4

Browse files
authored
Fix derivatives at the edges of finite operators (#296)
* Fix edge logic for AC_hamiltonian * Fix edge logic for AC2_hamiltonian * Fix conversion logic for `SparseBlockTensorMap` * Better type detection in `complex` * Handle real/complex environments * update storagetype determination * Additional tests * fix tests? * Fix tests! * Fix braille checks * Update tests for sparsity improvements in BlockTensorKit
1 parent e5ab7e8 commit 813e3f4

File tree

8 files changed

+78
-56
lines changed

8 files changed

+78
-56
lines changed

src/algorithms/derivatives/hamiltonian_derivatives.jl

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,11 @@ struct JordanMPO_AC_Hamiltonian{O1,O2,O3} <: DerivativeOperator
1313
A::O3 # continuing
1414
function JordanMPO_AC_Hamiltonian(onsite, not_started, finished, starting, ending,
1515
continuing)
16-
tensor = coalesce(onsite, not_started, finished, starting, ending)
17-
ismissing(tensor) && throw(ArgumentError("unable to determine type"))
18-
S = spacetype(tensor)
19-
M = storagetype(tensor)
16+
# obtaining storagetype of environments since these should have already mixed
17+
# the types of the operator and state
18+
gl = continuing[1]
19+
S = spacetype(gl)
20+
M = storagetype(gl)
2021
O1 = tensormaptype(S, 1, 1, M)
2122
O2 = tensormaptype(S, 2, 2, M)
2223
return new{O1,O2,typeof(continuing)}(onsite, not_started, finished, starting,
@@ -46,10 +47,11 @@ struct JordanMPO_AC2_Hamiltonian{O1,O2,O3,O4} <: DerivativeOperator
4647
DE::Union{O1,Missing} # onsite left
4748
EE::Union{O1,Missing} # finished
4849
function JordanMPO_AC2_Hamiltonian(II, IC, ID, CB, CA, AB, AA, BE, DE, EE)
49-
tensor = coalesce(II, IC, ID, CB, CA, AB, AA, BE, DE, EE)
50-
ismissing(tensor) && throw(ArgumentError("unable to determine type"))
51-
S = spacetype(tensor)
52-
M = storagetype(tensor)
50+
# obtaining storagetype of environments since these should have already mixed
51+
# the types of the operator and state
52+
gl = AA[1]
53+
S = spacetype(gl)
54+
M = storagetype(gl)
5355
O1 = tensormaptype(S, 1, 1, M)
5456
O2 = tensormaptype(S, 2, 2, M)
5557
O3 = tensormaptype(S, 3, 3, M)
@@ -107,7 +109,9 @@ function AC_hamiltonian(site::Int, below::_HAM_MPS_TYPES,
107109
end
108110

109111
# not_started
110-
if (!isfinite(operator) || site < length(operator)) && !ismissing(starting)
112+
if isfinite(operator) && site == length(operator)
113+
not_started = missing
114+
elseif !ismissing(starting)
111115
I = id(storagetype(GR[1]), physicalspace(W))
112116
@plansor starting[-1 -2; -3 -4] += I[-1; -3] * removeunit(GR[1], 2)[-4; -2]
113117
not_started = missing
@@ -116,7 +120,9 @@ function AC_hamiltonian(site::Int, below::_HAM_MPS_TYPES,
116120
end
117121

118122
# finished
119-
if (!isfinite(operator) || site > 1) && !ismissing(ending)
123+
if isfinite(operator) && site == 1
124+
finished = missing
125+
elseif !ismissing(ending)
120126
I = id(storagetype(GL[end]), physicalspace(W))
121127
@plansor ending[-1 -2; -3 -4] += removeunit(GL[end], 2)[-1; -3] * I[-2; -4]
122128
finished = missing
@@ -241,7 +247,9 @@ function AC2_hamiltonian(site::Int, below::_HAM_MPS_TYPES,
241247
end
242248

243249
# finished
244-
if !ismissing(IC)
250+
if isfinite(operator) && site + 1 == length(operator)
251+
II = missing
252+
elseif !ismissing(IC)
245253
I = id(storagetype(GR[1]), physicalspace(W2))
246254
@plansor IC[-1 -2; -3 -4] += I[-1; -3] * removeunit(GR[1], 2)[-4; -2]
247255
II = missing
@@ -254,7 +262,9 @@ function AC2_hamiltonian(site::Int, below::_HAM_MPS_TYPES,
254262
end
255263

256264
# unstarted
257-
if !ismissing(BE)
265+
if isfinite(operator) && site == 1
266+
EE = missing
267+
elseif !ismissing(BE)
258268
I = id(storagetype(GL[end]), physicalspace(W1))
259269
@plansor BE[-1 -2; -3 -4] += removeunit(GL[end], 2)[-1; -3] * I[-2; -4]
260270
EE = missing

src/algorithms/timestep/tdvp.jl

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,18 @@ end
178178

179179
#copying version
180180
function timestep::AbstractFiniteMPS, H, time::Number, timestep::Number,
181-
alg::Union{TDVP,TDVP2}, envs::AbstractMPSEnvironments=environments(ψ, H);
181+
alg::Union{TDVP,TDVP2}, envs::AbstractMPSEnvironments...;
182182
kwargs...)
183-
return timestep!(copy(complex(ψ)), H, time, timestep, alg, envs; kwargs...)
183+
isreal = scalartype(ψ) <: Real
184+
ψ′ = isreal ? complex(ψ) : copy(ψ)
185+
if length(envs) != 0 && isreal
186+
@warn "Currently cannot reuse real environments for complex evolution"
187+
envs′ = environments(ψ′, H)
188+
elseif length(envs) == 1
189+
envs′ = only(envs)
190+
else
191+
@assert length(envs) == 0 "Invalid signature"
192+
envs′ = environments(ψ′, H)
193+
end
194+
return timestep!(ψ′, H, time, timestep, alg, envs′; kwargs...)
184195
end

src/operators/jordanmpotensor.jl

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -155,10 +155,10 @@ function SparseBlockTensorMap(W::JordanMPOTensor)
155155
τ = BraidingTensor{scalartype(W)}(eachspace(W)[1])
156156
W′ = SparseBlockTensorMap{AbstractTensorMap{scalartype(W),spacetype(W),2,2}}(undef_blocks,
157157
space(W))
158-
if size(W, 1) > 1
158+
if size(W, 4) > 1
159159
W′[1, 1, 1, 1] = τ
160160
end
161-
if size(W, 4) > 1
161+
if size(W, 1) > 1
162162
W′[end, 1, 1, end] = τ
163163
end
164164

@@ -174,7 +174,9 @@ function SparseBlockTensorMap(W::JordanMPOTensor)
174174
for (I, v) in nonzero_pairs(W.C)
175175
W′[1, I + Ic] = insertleftunit(v, 1)
176176
end
177-
W′[1, 1, 1, end] = insertrightunit(insertleftunit(only(W.D), 1), 3)
177+
if nonzero_length(W.D) > 0
178+
W′[1, 1, 1, end] = insertrightunit(insertleftunit(only(W.D), 1), 3)
179+
end
178180

179181
return W′
180182
end

src/states/finitemps.jl

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -325,10 +325,12 @@ function Base.complex(mps::FiniteMPS)
325325
ARs = _complex_if_not_missing.(mps.ARs)
326326
Cs = _complex_if_not_missing.(mps.Cs)
327327
ACs = _complex_if_not_missing.(mps.ACs)
328-
return FiniteMPS(collect(Union{Missing,eltype(ALs)}, ALs),
329-
collect(Union{Missing,eltype(ARs)}, ARs),
330-
collect(Union{Missing,eltype(ACs)}, ACs),
331-
collect(Union{Missing,eltype(Cs)}, Cs))
328+
TA = Base.promote_op(complex, site_type(mps))
329+
TB = Base.promote_op(complex, bond_type(mps))
330+
return FiniteMPS(collect(Union{Missing,TA}, ALs),
331+
collect(Union{Missing,TA}, ARs),
332+
collect(Union{Missing,TA}, ACs),
333+
collect(Union{Missing,TB}, Cs))
332334
end
333335

334336
@inline function Base.getindex::FiniteMPS, I::AbstractUnitRange)

test/algorithms.jl

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -326,14 +326,17 @@ end
326326
algs = [TDVP(), TDVP2(; trscheme=truncdim(10))]
327327
L = 10
328328

329-
H = force_planar(heisenberg_XXX(; spin=1 // 2, L))
330-
ψ₀ = FiniteMPS(L, ℙ^2, ℙ^1)
329+
H = force_planar(heisenberg_XXX(Trivial, Float64; spin=1 // 2, L))
330+
ψ = FiniteMPS(rand, Float64, L, ℙ^2, ℙ^4)
331+
E = expectation_value(ψ, H)
332+
ψ₀, = find_groundstate(ψ, H)
331333
E₀ = expectation_value(ψ₀, H)
332334

333335
@testset "Finite $(alg isa TDVP ? "TDVP" : "TDVP2")" for alg in algs
334-
ψ, envs = timestep(ψ₀, H, 0.0, dt, alg)
335-
E = expectation_value(ψ, H, envs)
336-
@test E₀ E atol = 1e-2
336+
ψ1, envs = timestep(ψ₀, H, 0.0, dt, alg)
337+
E1 = expectation_value(ψ1, H, envs)
338+
@test E₀ E1 atol = 1e-2
339+
@test dot(ψ1, ψ₀) exp(im * dt * E₀) atol = 1e-4
337340
end
338341

339342
Hlazy = LazySum([3 * H, 1.55 * H, -0.1 * H])

test/other.jl

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,27 +70,33 @@ end
7070
buffer = IOBuffer()
7171
braille(buffer, H)
7272
output = String(take!(buffer))
73-
check = "... 🭻⎡⠉⢀⎤🭻 ...\n ⎣⠀⢀⎦ \n"
73+
check = """
74+
... 🭻⎡⠉⢈⎤🭻 ...
75+
⎣⠀⢀⎦
76+
"""
7477
@test output == check
7578

7679
O = make_time_mpo(H, 1.0, TaylorCluster(3, false, false))
7780
braille(buffer, O)
7881
output = String(take!(buffer))
79-
check = "... 🭻⎡⡏⠉⠒⠔⎤🭻 ...\n ⎣⡇⠀⠀⡂⎦ \n"
82+
check = """
83+
... 🭻⎡⡏⠉⠛⠟⎤🭻 ...
84+
⎣⡇⠀⠀⡂⎦
85+
"""
8086
@test output == check
8187

8288
# Finite Hamiltonians and MPOs
8389
# ----------------------------
8490
H = transverse_field_ising(; L=4)
8591
braille(buffer, H)
8692
output = String(take!(buffer))
87-
check = " ⎡⠉⎤🭻🭻⎡⠉⎤🭻🭻⎡⠉⎤🭻🭻⎡⠀⎤ \n ⎣⠀⠀⎦ ⎣⠀⢀⎦ ⎣⠀⢀⎦ ⎣⡀⠀⎦ \n"
93+
check = " ⎡⠉⎤🭻🭻⎡⠉⎤🭻🭻⎡⠉⎤🭻🭻⎡⠀⎤ \n ⎣⠀⠀⎦ ⎣⠀⢀⎦ ⎣⠀⢀⎦ ⎣⡀⠀⎦ \n"
8894
@test output == check
8995

9096
O = make_time_mpo(H, 1.0, TaylorCluster(3, false, false))
9197
braille(buffer, O)
9298
output = String(take!(buffer))
93-
check = " ⎡⠉⠉⎤🭻🭻⎡⠍⠉⠤⠠⎤🭻🭻⎡⡏⠉⠒⠔⎤🭻🭻⎡⡇⠀⎤ \n ⎣⠀⠀⎦ ⎣⡂⠀⠀⠂⎦ ⎣⡇⠀⠀⡂⎦ ⎣⡇⠀⎦ \n"
99+
check = " ⎡⠉⠉⠉⠉⎤🭻🭻⎡⡏⠉⠛⠟⎤🭻🭻⎡⡏⠉⠛⠟⎤🭻🭻⎡⡇⠀⎤ \n ⎣⠀⠀⠀⠀⎦ ⎣⡇⠀⠀⡂⎦ ⎣⡇⠀⠀⡂⎦ ⎣⡇⠀⎦ \n"
94100
@test output == check
95101
end
96102
end

test/setup.jl

Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -123,33 +123,20 @@ function S_zz(::Type{Trivial}=Trivial, ::Type{T}=ComplexF64; spin=1 // 2) where
123123
return S_z(Trivial, T; spin) S_z(Trivial, T; spin)
124124
end
125125

126-
function transverse_field_ising(; g=1.0, L=Inf)
127-
X = S_x(; spin=1 // 2)
128-
ZZ = S_zz(; spin=1 // 2)
129-
E = TensorMap(ComplexF64[1 0; 0 1], ℂ^2 ^2)
126+
function transverse_field_ising(::Type{T}=ComplexF64; g=1.0, L=Inf) where {T<:Number}
127+
X = S_x(Trivial, T; spin=1 // 2)
128+
ZZ = S_zz(Trivial, T; spin=1 // 2)
130129

131-
# lattice = L == Inf ? PeriodicVector([ℂ^2]) : fill(ℂ^2, L)
132130
if L == Inf
133131
lattice = PeriodicArray([ℂ^2])
134-
return InfiniteMPOHamiltonian(lattice,
135-
(i, i + 1) => -(ZZ + (g / 2) * (X E + E X))
136-
for i in 1:1)
137-
# return MPOHamiltonian(-ZZ - (g / 2) * (X ⊗ E + E ⊗ X))
132+
H₁ = InfiniteMPOHamiltonian(lattice, i => -g * X for i in 1:1)
133+
H₂ = InfiniteMPOHamiltonian(lattice, (i, i + 1) => -ZZ for i in 1:1)
138134
else
139135
lattice = fill(ℂ^2, L)
140-
return FiniteMPOHamiltonian(lattice,
141-
(i, i + 1) => -(ZZ + (g / 2) * (X E + E X))
142-
for i in 1:(L - 1)) #+
143-
# FiniteMPOHamiltonian(lattice, (i,) => -g * X for i in 1:L)
136+
H₁ = FiniteMPOHamiltonian(lattice, i => -g * X for i in 1:L)
137+
H₂ = FiniteMPOHamiltonian(lattice, (i, i + 1) => -ZZ for i in 1:(L - 1))
144138
end
145-
146-
H = S_zz(; spin=1 // 2) + (g / 2) * (X E + E X)
147-
return if L == Inf
148-
MPOHamiltonian(H)
149-
else
150-
FiniteMPOHamiltonian(fill(ℂ^2, L), (i, i + 1) => H for i in 1:(L - 1))
151-
end
152-
return MPOHamiltonian(-H)
139+
return H₁ + H₂
153140
end
154141

155142
function heisenberg_XXX(::Type{SU2Irrep}; spin=1, L=Inf)
@@ -169,8 +156,9 @@ function heisenberg_XXX(::Type{SU2Irrep}; spin=1, L=Inf)
169156
end
170157
end
171158

172-
function heisenberg_XXX(; spin=1, L=Inf)
173-
h = ones(ComplexF64, SU2Space(spin => 1)^2 SU2Space(spin => 1)^2)
159+
function heisenberg_XXX(::Type{Trivial}=Trivial, ::Type{T}=ComplexF64; spin=1,
160+
L=Inf) where {T<:Number}
161+
h = ones(T, SU2Space(spin => 1)^2 SU2Space(spin => 1)^2)
174162
for (c, b) in blocks(h)
175163
S = (dim(c) - 1) / 2
176164
b .= S * (S + 1) / 2 - spin * (spin + 1)

test/states.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -168,18 +168,18 @@ end
168168
@test 9 * 9 norm(window)^2
169169
normalize!(window)
170170

171-
e1 = expectation_value(window, (1, 2) => O)
171+
e1 = expectation_value(window, (2, 3) => O)
172172

173173
window, envs, _ = find_groundstate(window, ham, DMRG(; verbosity=0))
174174

175-
e2 = expectation_value(window, (1, 2) => O)
175+
e2 = expectation_value(window, (2, 3) => O)
176176

177177
@test real(e2) real(e1)
178178

179179
window, envs = timestep(window, ham, 0.1, 0.0, TDVP2(; trscheme=truncdim(20)), envs)
180180
window, envs = timestep(window, ham, 0.1, 0.0, TDVP(), envs)
181181

182-
e3 = expectation_value(window, (1, 2) => O)
182+
e3 = expectation_value(window, (2, 3) => O)
183183

184184
@test e2 e3 atol = 1e-4
185185
end

0 commit comments

Comments
 (0)