Page 1 of 1

### Non-hermitian Matrices

Posted: 22 May 2020, 15:32
Hi, all

Can TeNPy be used to deal with non-hermitian matrices? I see this issue https://github.com/tenpy/tenpy/issues/96 but I am not sure about the current status. Does TEBD work now? How about DMRG? If it helps, the eigenvalues of the matrices that I want to deal with are all real.

### Re: Non-hermitian Matrices

Posted: 26 May 2020, 03:27
TEBD does work for non-hermitian hamiltonians since the commit closing the issue.

DMRG does right now not work in this case, since it uses Lanczos which crucially assumes that the hamiltonian is hermitian.
You would need to use a different eigensolver for non-hermitian H, and I have now idea how well it would actually work.
However, you can just try your luck, as it's not too difficult to implement.

Basically, you just need to override the diag method.
The following code does this to use scipy.sparse.linalg.eigs instead of the Lanczos from tenpy, and hence should work accordingly for non-hermitian H if you set `'diag_method': 'arpack_eigs'`.
Note that I've set the data type to be complex explicitly to avoid a bunch of warnings where the imaginary part was discarded, I'm not sure if this is necessary.

Code: Select all

``````import numpy as np
import scipy

from tenpy.networks.mps import MPS
from tenpy.models.tf_ising import TFIChain
from tenpy.models.spins import SpinModel
from tenpy.algorithms import dmrg
import tenpy.linalg.np_conserved as npc
from tenpy.linalg.sparse import FlatLinearOperator
from tenpy.tools.math import speigs

def diag_arpack(H, psi, options={}):
H_flat, psi_flat = FlatLinearOperator.from_guess_with_pipe(H.matvec, psi, dtype=np.complex128)
tol = options.get('P_tol', 1.e-14)
N_min = options.get('N_min', None)
try:
Es, Vs = speigs(H_flat, k=1, which='SR', v0=psi_flat, tol=tol, ncv=N_min)
except scipy.sparse.linalg.ArpackNoConvergence:
# simply try again with larger "k", that often helps
new_k = min(6, H_flat.shape[1])
if new_k <= 1:
raise
Es, Vs = speigsh(H_flat, k=new_k, which='SR', v0=psi_flat, tol=tol, ncv=N_min)
psi0 = H_flat.flat_to_npc(Vs[:, 0]).split_legs(0)
psi0.itranspose(psi.get_leg_labels())
return Es[0], psi0

class NonHermitianDMRG(dmrg.TwoSiteDMRGEngine):
def diag(self, theta_guess):
if self.diag_method == 'arpack_eigs':
E, theta = diag_arpack(self.eff_H, theta_guess, self.lanczos_params)
else:
return super().diag(theta_guess)
ov_change = 1. - abs(npc.inner(theta_guess, theta, 'labels', do_conj=True))
return E, theta, -1, ov_change

def example_DMRG_tf_ising_finite(L, g, verbose=True):
print("finite DMRG, transverse field Ising model")
print("L={L:d}, g={g:.2f}".format(L=L, g=g))
model_params = dict(L=L, J=1., g=g, bc_MPS='finite', conserve=None, verbose=verbose)
M = TFIChain(model_params)
product_state = ["up"] * M.lat.N_sites
psi = MPS.from_product_state(M.lat.mps_sites(), product_state, bc=M.lat.bc_MPS)
dmrg_params = {
'mixer': None,  # setting this to True helps to escape local minima
'max_E_err': 1.e-10,
'trunc_params': {
'chi_max': 30,
'svd_min': 1.e-10
},
'diag_method': 'arpack_eigs',   # crucial!!!
'verbose': verbose,
'combine': True
}
eng = NonHermitianDMRG(psi, M, dmrg_params)
E, psi = eng.run()
print("E = {E:.13f}".format(E=E))
print("final bond dimensions: ", psi.chi)
mag_x = np.sum(psi.expectation_value("Sigmax"))
mag_z = np.sum(psi.expectation_value("Sigmaz"))
print("magnetization in X = {mag_x:.5f}".format(mag_x=mag_x))
print("magnetization in Z = {mag_z:.5f}".format(mag_z=mag_z))
if L < 20:  # compare to exact result
from tfi_exact import finite_gs_energy
E_exact = finite_gs_energy(L, 1., g)
print("Exact diagonalization: E = {E:.13f}".format(E=E_exact))
print("relative error: ", abs((E - E_exact) / E_exact))
return E, psi, M

if __name__ == "__main__":
example_DMRG_tf_ising_finite(L=10, g=1., verbose=True)
``````
Copy this to a file with the `examples/tfi_exact.py` from the tenpy repository in the same folder to execute it.

Disclaimer: I'm not sure and didn't try how well this whole thing behaves for non-hermitian H!