New release: v0.7.1.

Non-hermitian Matrices

How do I use this algorithm? What does that parameter do?
Post Reply
wye
Posts: 3
Joined: 01 Oct 2018, 20:46

Non-hermitian Matrices

Post by wye »

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.
User avatar
Johannes
Site Admin
Posts: 188
Joined: 21 Jul 2018, 12:52
Location: UC Berkeley

Re: Non-hermitian Matrices

Post by Johannes »

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! :!:
Post Reply