I am testing a simple 1D spin-1 chain (L = 4, open BCs) and have encountered trouble projecting my MPS onto the leading Schmidt component (around bond 2).
I have two wavefunctions \(\psi\) and \(\psi_0\).
Conceptually, my code should:
1 ) Time-evolve both states.
2) Project \(\psi\) onto its leading Schmidt component across the middle bond.
3) Compute the overlap between the projected \(\psi\) and \(\psi_0\).
I verified numerically (without TeNPy) that this procedure works as expected.
In TeNPy, I attempt the projection like this:
Python: Select all
Ss = psi.get_SL(i = L // 2)
Ss_new = np.zeros_like(Ss)
Ss_new[0] = 1.0
psi.set_SL(i = L // 2, S = Ss_new)
Python: Select all
psi.overlap(psi_0)
If I extract the full wavefunction using
Python: Select all
wf_full = get_full_wavefunction(psi.copy())
So my question is:
Does modifying psi._S (or using set_SL) not update the underlying tensors? and if not, how then can I update them based on the new singular values?
Below is a code excerpt:
Python: Select all
# Time evolve numeric
H = get_numpy_Hamiltonian( model = model ).real
def time_evo( ts , H , wf0 ):
egvr, egvk = np.linalg.eigh( H )
wf = egvk.conj().T @ wf0
wf_time_evolution = lambda t: egvk @ ( np.exp( - 1j * egvr * t ) * wf )
wf_ts = [ wf_time_evolution(t) for t in ts ]
return wf_ts
def Eng_time_evo( dt , N_steps ):
TDVPEng.evolve( N_steps = N_steps , dt = dt )
TDVPEng_0.evolve( N_steps = N_steps , dt = dt )
def projection( psi ):
Ss = psi.get_SL( i = L // 2 )
Ss_new = np.zeros_like( a = Ss )
Ss_new[0] = 1.
psi.set_SL( i = L // 2 , S = Ss_new )
### PARAMETERS ###
dt = 0.1
N_steps = 20
ts = [ N_steps * dt ]
### TIME EVOLUTION AND PROJECTION ###
# TENPY #
Eng_time_evo( dt = dt , N_steps = N_steps )
print('Singular values, before p:' , psi._S)
projection( psi = psi )
print('Singular values, after p:' , psi._S)
wf_full = get_full_wavefunction( psi = psi.copy() )
# NUMERIC #
wf_t = time_evo( ts = ts , H = H , wf0 = psi_init )[0]
wf_0_t = time_evo( ts = ts , H = H , wf0 = psi_0_init )[0]
psi_p_schmidt = wf_t.reshape( ( dim_A , dim_B ) )
U , s , Vh = np.linalg.svd( psi_p_schmidt , full_matrices = False )
print('Numeric, acurate, singular values', s)
psi_proj = np.kron( U[ : , 0 ] , Vh[ 0 , : ] )
### OVERLAPS ###
# TENPY #
ov_tenpy = psi.overlap( psi_0 )
print( 'ov_tenpy' , round( ov_tenpy , 3 ) )
# TENPY NUMERIC #
ov_tenpy_numeric = np.abs( np.vdot( wf_full , wf_0_t ) )
print( 'ov_tenpy_numeric' , round( ov_tenpy_numeric , 3 ) )
# NUMERIC #
ov_numeric = np.vdot( psi_proj , wf_0_t )
print( 'ov_numeric' , round( ov_numeric , 3 ) )