Why `movesite` changes two-point fermionic correlation function?

Hi everyone,

I am quite curious about a fact about the function ITensors.ITensorMPS.movesite. I’d like to calculate two-point correlation function between site s1 and s2 in two ways:

  1. just calculate using inner
  2. first use movesite to move s2 to s1+1, and then calculate the correlation between s1 and s1+1. (one can further change s2 to arbitrary site s3)

Should the two approaches be equivalent?

Based on my test, for spin system (transversed-field Ising model), the correlations between spin operators are unchanged.

using ITensors, ITensorMPS

function TFIM_MPO(L::Int64, J::Float64, h::Float64)
    sites = siteinds("S=1/2",L)
    os = OpSum()
    for jc ∈ 1:L
        # transverse field
        os += -2.0*h,"Sz",jc
        # Ising interaction
        os += -4.0*J,"Sx",jc,"Sx",mod1(jc+1,L)
    end
    H = MPO(os,sites)
    # initialize the MPS
    state = [isodd(i) ? "Up" : "Up" for i in 1:L]
    psi0 = productMPS(sites, state)
    return sites, H, psi0
end

L = 8
J = 1.0
h = 0.5
sites, H, psi0 = TFIM_MPO(L, J, h)
nsweeps = 20
maxdims = [2,2,8,8,20,20,50,50,100,100,200,200,400]
cutoff1 = [1E-13]
noise = [1E-4, 1E-4, 1E-5, 1E-6, 1E-7, 1E-8, 0.0]
energy, psi = dmrg(H,psi0;nsweeps,maxdim=maxdims,cutoff=cutoff1, noise)

## correlation functions under movesite
s1 = 1
s2 = 4
SS = zeros(3)
sites = siteinds(psi)
for (i,comp) in enumerate(["Sx","Sy","Sz"])
    SS_os = OpSum()
    SS_os += 1,comp,s1,comp,s2
    SS_mpo = MPO(SS_os, sites)
    SS[i] = inner(psi',SS_mpo,psi)
end
@show SS

psi2 = movesite(psi, s2=>2)
s2 = 2
SS2 = zeros(3)
sites = siteinds(psi2)
for (i,comp) in enumerate(["Sx","Sy","Sz"])
    SS_os = OpSum()
    SS_os += 1,comp,s1,comp,s2
    SS_mpo = MPO(SS_os, sites)
    SS2[i] = inner(psi2',SS_mpo,psi2)
end
@show SS2

However, for fermionic system (free fermion), the Green’s functions obtained through the two approaches are different.

using ITensors, ITensorMPS

function free_fermion_MPO(L::Int64, t::Float64, μ::Float64)
    sites = siteinds("Fermion",L)
    os = OpSum()
    for jc ∈ 1:L
        # chemical potential
        os += -μ, "n", jc
        # hopping
        os += -t, "c†", jc, "c", mod1(jc+1,L)
        os += -t, "c†", mod1(jc+1,L), "c", jc
    end
    H = MPO(os,sites)
    # initialize the MPS
    psi0 = random_mps(sites;linkdims=10)
    return sites, H, psi0
end

L = 8
t = 1.0
μ = 0.5
sites, H, psi0 = free_fermion_MPO(L, t, μ)
nsweeps = 10
maxdims = [2,2,8,8,20,20,50,50,100,100,200,200,400]
cutoff1 = [1E-10]
noise = [1E-4, 1E-4, 1E-5, 1E-6, 1E-7, 1E-8, 0.0]
energy, psi = dmrg(H,psi0;nsweeps,maxdim=maxdims,cutoff=cutoff1, noise)

## correlation functions under movesite
s1 = 1
s2 = 3
sites = siteinds(psi)
gr_os = OpSum()
gr_os += 1, "c†", s1, "c", s2
gr_mpo = MPO(gr_os, sites)
gr = inner(psi', gr_mpo, psi)
@show gr # -0.125

psi2 = movesite(psi, s2=>2)
s2 = 2
sites = siteinds(psi2)
gr_os = OpSum()
gr_os += 1, "c†", s1, "c", s2
gr_mpo = MPO(gr_os, sites)
gr2 = inner(psi2', gr_mpo, psi2)
@show gr2 # 0.21338834764831804

From my naive perspective and intuition, this does not make sense. So my question is how to understand this behavior. I’m not very familiar with the language of MPS. Any idea would be appreciated!

Fo-Hong