[RESOLVED] Issue in purification method (normalization of temperature and/or timescales?)

How do I use this algorithm? What does that parameter do?
Post Reply
rubenv
Posts: 6
Joined: 03 Mar 2021, 16:15

[RESOLVED] Issue in purification method (normalization of temperature and/or timescales?)

Post by rubenv »

Hi everyone,

I noticed that the finite-temperature results I obtain using the purification method do not match ED calculations; however, they do match if i change the temperature by a factor of 2 (i.e., the ED results for a temperature T seem to correspond to purification results at 'temperature' T/2). I wrote a minimal code that reproduces this (including also an ED snippet as a benchmark):

Code: Select all

import numpy as np
from tenpy.networks.purification_mps import PurificationMPS
from tenpy.models.spins import SpinChain
from tenpy.algorithms import dmrg, mpo_evolution
from tenpy.algorithms.purification import PurificationApplyMPO
import scipy.sparse as sparse
from numpy.linalg import eig
import tenpy
tenpy.show_config()

L = 4
chi = 10
Jz = 1
hx = 0.5
dt = 0.05
beta = 2.

print("\nConsider the Ising chain H = Jz*Sz*Sz - hx*Sx with Jz =", Jz, ", hx =", hx,"and length L =", L)

################### ED ###################

sx = sparse.csr_matrix(np.array([[0.,1.],[1.,0.]]))
sz = sparse.csr_matrix(np.array([[1.,0.],[0.,-1.]]))
Sx = []
Sz = []
for i_site in range(L): 
	if i_site==0: 
		X=sx
		Z=sz 
	else: 
		X=sparse.csr_matrix(np.eye(2)) 
		Z=sparse.csr_matrix(np.eye(2)) 
	for j_site in range(1,L): 
		if j_site==i_site: 
			X=sparse.kron(X,sx,'csr')
			Z=sparse.kron(Z,sz,'csr') 
		else: 
			X=sparse.kron(X,np.eye(2),'csr')
			Z=sparse.kron(Z,np.eye(2),'csr') 
	Sx.append(0.5*X)
	Sz.append(0.5*Z)

H = -hx*Sx[0]
for i in range(L-1): H += Jz*Sz[i]*Sz[i+1] - hx*Sx[i+1]
e,v = np.linalg.eigh(H.todense())
V = v; Vd = v.conj().T; D = np.diag(e) ### note that H = V.dot(D.dot(Vd)) 

print("\nFor inverse temperature beta =", beta/2, ", the thermal state obtained with ED gives us")
U = V.dot(np.diag(np.exp(-(beta/2)*e)).dot(Vd))
print("<Sx> =", np.real([np.trace(Sx[i]*U)/np.trace(U) for i in range(L)]))
print("For inverse temperature beta =", beta, ", the thermal state obtained with ED gives us")
U = V.dot(np.diag(np.exp(-beta*e)).dot(Vd))
print("<Sx> =", np.real([np.trace(Sx[i]*U)/np.trace(U) for i in range(L)]))

################### purification and tenpy ###################

model_params = dict(L=L,bc_MPS='finite',conserve=None,S=0.5,Jx=0,Jy=0,Jz=Jz,hx=hx)
M = SpinChain(model_params)

psi = PurificationMPS.from_infiniteT(M.lat.mps_sites(),bc='finite')
psi.canonical_form()

steps = int(0.5*beta/dt)
dt = 0.5*beta/steps ### makes sure that dt is such that an integer multiple gives the desired beta
par = {
	'N_steps':1,
	'compression_method': 'SVD', ### same results for 'SVD' and 'variational'
	'trunc_params': {"chi_max": chi,"svd_min": 1e-10,},
	'dt':-1j*dt,
}
evol = mpo_evolution.ExpMPOEvolution(psi,M,par)
evol.calc_U(-1j*dt,order=2)
U = evol._U_MPO
print("\nWe will now try to derive the same result using the purification method (using tenpy)")
print("We perform imaginary time-evolution with dt =", dt)
option = {'chi_list':{0:chi}}
for i in range(steps):
	evol1 = PurificationApplyMPO(psi,U[0],option)
	evol2 = PurificationApplyMPO(psi,U[1],option)
	evol1.run()
	evol2.run()

print("After having evolved by", steps, "steps, we obtain an effective beta =", 2*steps*dt)
psi.canonical_form()
print("<Sx> =", psi.expectation_value("Sx"), "\n")

The code only takes a few seconds to run. For convenience, the output is shown as an attachment.

We see that the ED results at beta = 1 match the purification results at beta = 2.
Note: in the purification approach, I time-evolved over an imaginary time of steps*dt = 1. As explained in the documentation ( https://tenpy.readthedocs.io/en/latest/ ... cation_mps ), this should correspond to beta = 2. (More generally, when using the purification approach, one should only need to time-evolve with exp(-beta H/2) to obtain an effective inverse temperature beta when calculating correlations.)

If anyone has any ideas what is going on, that would be really appreciated!
Attachments
output_purification_test.png
output_purification_test.png (58.5 KiB) Viewed 2967 times
rubenv
Posts: 6
Joined: 03 Mar 2021, 16:15

Re: [RESOLVED] Issue in purification method (normalization of temperature and/or timescales?)

Post by rubenv »

The wrong piece of code was apparently:

Code: Select all

evol1 = PurificationApplyMPO(psi,U[0],option)
evol2 = PurificationApplyMPO(psi,U[1],option)
evol1.run()
evol2.run()
The correct result is obtained with

Code: Select all

evol1 = PurificationApplyMPO(psi,U[0],option)
evol1.run()
evol2 = PurificationApplyMPO(psi,U[1],option)
evol2.run()
So I guess when you run "evol2.run()", it does not act on the current state of psi, but on a copied version of psi which was copied at the time of defining evol2. Hence, evol2.run() does not notice that evol1.run() was called. Since order=2 uses a dt -> (1+i)/2 * dt, you still get half the desired imaginary time evolution, explaining the factor of 2. The real time evolution part drops out due to the structure of the purification state (and the fact that it commutes with the imaginary time evolution part).

I admit I am still a bit conceptually confused: so the mpo method carries a copied version of psi? But at the same time, when it runs, it overrides the original psi as well? So it's a bit of a one-way street: changes to psi will not affect future runs of the evolution, but runs of the evolution will affect anything you afterwards do with psi?
shaktiman
Posts: 4
Joined: 19 Apr 2020, 19:58

Re: [RESOLVED] Issue in purification method (normalization of temperature and/or timescales?)

Post by shaktiman »

Hi
Since you tried this method, I had a question. I was playing around on this purification method by implementing it on Kitaev model. I tried to evaluate the flux expectation values at different beta ranging from zero to lets say 30. Using Exact diagonalization, I see flux value reaches one(it should) at Temperature near to zero and at small beta it is almost zero.
But by using purification method, I gets almost zero value of flux (~1e -50) at all temperature range. May be I am making some mistake or does this purification method fails while evaluating a non local quantities or something else is wrong.
Please let me know if you know something about it. I can attach the code also, if required.

Thanks
User avatar
Johannes
Site Admin
Posts: 413
Joined: 21 Jul 2018, 12:52
Location: TU Munich

Re: [RESOLVED] Issue in purification method (normalization of temperature and/or timescales?)

Post by Johannes »

@rubenv Good catch, the fix is of course correct.
Let me explain:
The variation compression needs a copy of the old psi to compress against, and that copy is made during the class intialization, more precisely
in [tenpyclass=tenpy.algorithms.mps_common.VariationalApplyMPO]init_env[/inline].
So it modifies psi in place, but it still makes a copy during intialization, against which it compresses -
hence the evol2.run() updates psi in place to be the compressed version of U[1]|psi0> where psi0 is the MPS it got during intialization, i.e. at the beginning of the loop in your first code, or the U[0] applied to that in the corrected version.

I guess we didn't expect that you initialize the class and only later call run(). I also don't really know how to avoid this - we could delay the initializaiton of the environment until the beginning of the run(), but this goes against the intuitive separation of initialization and run in the first place.
To be fair, the docs suggest comprression with `VariationalApplyMPO(psi, U, params).run()`...
I added an extra warning to the docs in `run()` that this is what you should do, but I din't

@shaktiman Can you elaborato on which Kitaev model you tried? I'd guess Kitaev Honeycomb?
What flux were calculating?
Post Reply