Hi!
In the process of calculating OTOCβs for a spin chain mode, I came across a strange error when I perform backward time evolution.
In the following code, I am performing
I am doing it in two different ways
-
\psi_R (t) = S^z_i e^{-iHt} S^z_0|\psi_{init \rangle}\psi_L (t) = e^{-iHt} |\psi_{init \rangle}C[i,t] = \langle \psi_L(t) , \psi_R(t) \rangle
-
\phi (t) = e^{+iHt }S^z_i e^{-iHt} S^z_0|\psi_{init} \rangleF[i,t] = \langle \psi_{init} , \phi(t) \rangle
Logically, both the methods should give the same result but I notice discrepancy in the result.
Starting TEBD time evolution...
Steps: 40 | dt = 0.05 | t_end = 2.0
------------------------------------------------------------
t = 0.50 | C(L/2,t) = 0.6849 + -0.0000i | F(L/2)=-0.4024+-0.4702i | abs(F) = 0.6189 | maxdim = 4
t = 1.00 | C(L/2,t) = 0.5726 + -0.0000i | F(L/2)=-0.5041+ 0.1552i | abs(F) = 0.5274 | maxdim = 6
t = 1.50 | C(L/2,t) = 0.5867 + 0.0000i | F(L/2)= 0.0110+ 0.5736i | abs(F) = 0.5737 | maxdim = 8
t = 2.00 | C(L/2,t) = 0.6443 + 0.0000i | F(L/2)= 0.7891+ 0.0646i | abs(F) = 0.7918 | maxdim = 8
I have checked that the states are normalized at each time step and after application of certain operators.
using ITensors
using ITensorMPS
using Printf
using DelimitedFiles
using Plots
# ββ parameters ββββββββββββββββββββββββββββββββββββββββββββββββ
const L = 6 # chain length
const J = 1.0 # Ising coupling (ZZ)
const hx = 1.05 # transverse field (x)
const hz = 0.5 # longitudinal field (z)
const j_ref = 1 # reference site for correlator (1-indexed)
const dt = 0.05 # time step
const t_end = 2.0 # total evolution time
const maxdim = 200 # max MPS bond dimension
const cutoff = 1e-10 # SVD truncation cutoff
function make_gates(sites, J, hz, hx, dt)
L = length(sites)
gates = ITensor[]
for j in 1:L-1
s1, s2 = sites[j], sites[j+1]
hj = ITensor()
#hj = emptyITensor(s1, s2)
# Construct the two-site gate for the interaction term
if j == 1
# For the first and last bond, we only have one site with the interaction term
hj = -J*4.0* op("Sz", s1) * op("Sz", s2)
hj += -hx*2.0* op("Sx", s1) * op("Id", s2)
hj += -hz*2.0* op("Sz", s1) * op("Id", s2)
hj += -hx/2*2.0* op("Id", s1) * op("Sx", s2)
hj += -hz/2*2.0* op("Id", s1) * op("Sz", s2)
elseif j == L-1
hj = -J*4.0* op("Sz", s1) * op("Sz", s2)
hj += -hx/2*2.0* op("Sx", s1) * op("Id", s2)
hj += -hz/2*2.0* op("Sz", s1) * op("Id", s2)
hj += -hx*2.0* op("Id", s1) * op("Sx", s2)
hj += -hz*2.0* op("Id", s1) * op("Sz", s2)
else
# For the middle bonds, we have both sites with the interaction term
hj = -J*4.0* op("Sz", s1) * op("Sz", s2)
hj += -hx/2*2.0* op("Sx", s1) * op("Id", s2)
hj += -hz/2*2.0* op("Sz", s1) * op("Id", s2)
hj += -hx/2*2.0* op("Id", s1) * op("Sx", s2)
hj += -hz/2*2.0* op("Id", s1) * op("Sz", s2)
end
# gate: e^{-i hj dt/2}
Gj = exp(-im * dt/2 * hj)
push!(gates, Gj)
end
append!(gates, reverse(gates)) # Add the gates in reverse order for the second half of the step
return gates # length (2*(L-1))
end
let
n_steps = Int(round(t_end / dt))
times = collect(0.0:dt:t_end)
# ββ sites βββββββββββββββββββββββββββββββββββββββββββββββββββββ
sites = siteinds("S=1/2", L; conserve_qns=false)
gates = make_gates(sites, J, hz, hx, dt)
gates_dag = make_gates(sites, J, hz, hx, -dt) # gates for backward evolution (dagger)
println("Gates built: $(length(gates)) two-site gates")
println("Gates built: $(length(gates_dag)) two-site gates")
#ββ TEBD time evolution βββββββββββββββββββββββββββββββββββββββ
psi_init = MPS(sites, "Up") # Start from a simple product state (all spins down)
# ββ apply Sz at reference site to initial state ββββββββββββββββ
Sz_ref = 2.0*op("Sz", sites, j_ref)
psi_R = apply(Sz_ref, psi_init) # |phi_R> = Sz_{j_ref}|psi_init>
C_it = zeros(ComplexF64, L, length(times))
F_it = zeros(ComplexF64, L, length(times)) # OTOC, <psi| Sz_i(t) Sz_0 Sz_i(t) Sz_0 |psi>
# ββ measure at t=0 ββββββββββββββββββββββββββββββββββββββββββββ
for i in 1:L
Sz_i = 2.0*op("Sz", sites, i)
Sz_i_psi_R = apply(Sz_i, psi_R)
C_it[i, 1] = inner(psi_init, Sz_i_psi_R)
F_it[i, 1] = C_it[i, 1]
end
# ββ time evolution loop βββββββββββββββββββββββββββββββββββββββ
println("Starting TEBD time evolution...")
println("Steps: $n_steps | dt = $dt | t_end = $t_end")
println("-"^60)
psi_L = copy(psi_init) # |psi(t)>
for step in 1:n_steps
t = step * dt
# evolve both states by one dt
psi_L = apply(gates, psi_L; maxdim, cutoff) # e^{-iHt} |psi(t)>
psi_R = apply(gates, psi_R; maxdim, cutoff) # e^{-iHt} [Sz_{j_ref} |psi(t)>]
for i in 1:L
Sz_i = 2.0*op("Sz", sites, i)
Sz_i_psi_R = apply(Sz_i, psi_R)
C_it[i, step+1] = inner(psi_L, Sz_i_psi_R) # <psi(t)| Sz_i [e^{-iHt} Sz_{j_ref} |psi(t)>]
phi = apply(Sz_i, psi_R) # Sz_i [e^{-iHt} Sz_0 |psi>]
phi = apply(gates_dag, phi; maxdim, cutoff)
F_it[i, step+1] = inner(psi_init, phi) # <psi_init| e^{+iHt} Sz_i [e^{-iHt} Sz_0 |psi_init>]
#F_it[i, step+1] = inner(psi_L, phi) # <psi(t)| Sz_i [e^{-iHt} Sz_0 |psi>]
end
if step % 10 == 0
@printf("t = %5.2f | C(L/2,t) = %7.4f + %7.4fi | F(L/2)=%7.4f+%7.4fi | abs(F) = %7.4f | maxdim = %d\n",
t,
real(C_it[LΓ·2, step+1]), imag(C_it[LΓ·2, step+1]),
real(F_it[LΓ·2, step+1]), imag(F_it[LΓ·2, step+1]),
abs(F_it[LΓ·2, step+1]),
maxlinkdim(psi_L))
end
end
end