Hi everyone,
I am new to this amazing package and working on extracting two-site reduced density matrices from MPS. With the help of Is this a correct way to calculate one-site and two-site entanglement spectrum and entropy? - ITensor Julia Questions - ITensor Discourse, I figure out the way and benchmark it with theoretical formula from https://arxiv.org/abs/2310.15273,
where m_z=\left\langle S_{i_1}^z\right\rangle and \varrho_r^\alpha=\left\langle S_{i_1}^\alpha S_{i_i}^\alpha\right\rangle. Note that there are some constraint on the models. The minimal code for transversed-field Ising chain is as follows,
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 = 40
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)
## two-site reduced density matrix
s1 = 2
s2 = 4
begin
orthogonalize!(psi,s1)
psidag = prime(dag(psi), linkinds(psi))
rho_red = prime(psi[s1],linkinds(psi,s1-1))*prime(psidag[s1],sites[s1])
# @show rho_red
for i = s1+1:s2-1
rho_red *= psi[i]
rho_red *= psidag[i]
end
rho_red *= prime(psi[s2],linkinds(psi,s2))*prime(psidag[s2],sites[s2])
C1 = combiner(sites[s1],sites[s2]; tags="s")
C2 = combiner(sites[s1]',sites[s2]'; tags="s'")
rho_red = C2*(C1*rho_red)
## Correlation function
SS = zeros(3)
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
mzs1_os = OpSum()
mzs1_os += 1,"Sz",s1
mzs1_mpo = MPO(mzs1_os, sites)
mzs1 = inner(psi',mzs1_mpo,psi)
@show rho_red
@show (0.25+mzs1+SS[3]) ≈ rho_red[1,1]
@show (SS[1]-SS[2]) ≈ rho_red[1,4]
@show (0.25-SS[3]) ≈ rho_red[2,2]
@show (SS[1]+SS[2]) ≈ rho_red[2,3]
@show (SS[1]+SS[2]) ≈ rho_red[3,2]
@show (0.25-SS[3]) ≈ rho_red[3,3]
@show (SS[1]-SS[2]) ≈ rho_red[4,1]
@show (0.25-mzs1+SS[3]) ≈ rho_red[4,4]
end
One can change the s1
and s2
and find that all the relations can be verified. The reduced density matrices are also consistent with my exact diagonalization calculations. I hope that this benchmark would be helpful.
However, my question lies in the fermionic scenario. There is also a similar formula for two-site fermionic reduced density matrix,
where \overline{\mathrm{n}}=\left\langle\mathrm{n}_{i_1}\right\rangle, g_r=\langle c_{i_1}^{\dagger} c_{i_2}\rangle and \varrho_r^{\mathrm{n}}=\left\langle\mathrm{n}_{i_1} \mathrm{n}_{i_2}\right\rangle. The above method seems to not respect the anti-commutation relationship between fermions. In the following codes for simply free fermions,
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)
## two-site reduced density matrix
s1 = 1
s2 = 2
begin
orthogonalize!(psi,s1)
psidag = prime(dag(psi), linkinds(psi))
rho_red = prime(psi[s1],linkinds(psi,s1-1))*prime(psidag[s1],sites[s1])
# @show rho_red
for i = s1+1:s2-1
rho_red *= psi[i]
rho_red *= psidag[i]
end
rho_red *= prime(psi[s2],linkinds(psi,s2))*prime(psidag[s2],sites[s2])
C1 = combiner(sites[s1],sites[s2]; tags="s")
C2 = combiner(sites[s1]',sites[s2]'; tags="s'")
rho_red = C2*(C1*rho_red)
## Green's function
ns1_os = OpSum()
ns1_os += 1, "n", s1
ns1_mpo = MPO(ns1_os, sites)
ns1 = inner(psi', ns1_mpo, psi)
ns2_os = OpSum()
ns2_os += 1, "n", s2
ns2_mpo = MPO(ns2_os, sites)
ns2 = inner(psi', ns2_mpo, psi)
gr_os = OpSum()
gr_os += 1, "c†", s1, "c", s2
gr_mpo = MPO(gr_os, sites)
gr = inner(psi', gr_mpo, psi)
nnr_os = OpSum()
nnr_os += 1, "n", s1, "n", s2
nnr_mpo = MPO(nnr_os, sites)
nnr = inner(psi', nnr_mpo, psi)
@show rho_red
@show 1-ns1-ns2+nnr ≈ rho_red[1,1]
@show ns2-nnr ≈ rho_red[2,2]
@show ns1-nnr ≈ rho_red[3,3]
@show nnr ≈ rho_red[4,4]
@show gr ≈ rho_red[2,3]
end
when s2
is not adjacent to s1
(e.g., s1=1,s2=3
), the element rho_red[2,3]
is not equal to the Green’s function gr
, while the diagonal elements are good.
I’m quite certain that the issue lies in neglecting the sign change that occurs when fermions are exchanged. There are two reasons:
- When
s2=s1±1
, all the elements are good. - At the beginning, the reduced density matrix was consistent with my own exact diagonalization codes. But soon I realized that both of them were problematic. I solved the discrepancy with Eq. (2), in my ED code, by adding the sign caused by partial trace. For example, \langle B_1 B_2|A_1B_1A_2B_2\rangle=(-1)^{n_{B_1}*n_{A_2}}\langle B_1 B_2|A_1A_2B_1B_2\rangle (see my last commit, if interested).
So I would like to ask what is the correct way to obtain two-site reduced density matrix of fermionic MPS.
Since the code works for s2=s1±1
, I also tried to use ITensors.ITensorMPS.movesite before doing partial trace, like:
s1=1
if abs(s2-s1) == 1
rho_red = reduced_density_matrix(psi, s1, s2)
else
psi2 = movesite(psi, s2=>2)
rho_red = reduced_density_matrix(psi2, s1, 2)
end
but that give me the same result as before. So maybe a related question is whether movesite
respects the anti-commutation relation between fermions.
Thank you for reading!
Fo-Hong