def test_lanczos(n=30, k=5, tol=5.e-15): # generate Hermitian test array leg = gen_random_legcharge(ch, n) H = npc.Array.from_func_square(rmat.GUE, leg) H_flat = H.to_ndarray() E_flat, psi_flat = np.linalg.eigh(H_flat) E0_flat, psi0_flat = E_flat[0], psi_flat[:, 0] qtotal = npc.detect_qtotal(psi0_flat, [leg]) H_Op = H # use `matvec` of the array psi_init = npc.Array.from_func(np.random.random, [leg], qtotal=qtotal) E0, psi0, N = lanczos.lanczos(H_Op, psi_init, {'verbose': 1}) print("full spectrum:", E_flat) print("E0 = {E0:.14f} vs exact {E0_flat:.14f}".format(E0=E0, E0_flat=E0_flat)) print("|E0-E0_flat| / |E0_flat| =", abs((E0 - E0_flat) / E0_flat)) psi0_H_psi0 = npc.inner(psi0, npc.tensordot(H, psi0, axes=[1, 0]), do_conj=True) print("<psi0|H|psi0> / E0 = 1. + ", psi0_H_psi0 / E0 - 1.) assert (abs(psi0_H_psi0 / E0 - 1.) < tol) print("<psi0_flat|H_flat|psi0_flat> / E0_flat = ", end=' ') print(np.inner(psi0_flat.conj(), np.dot(H_flat, psi0_flat)) / E0_flat) ov = np.inner(psi0.to_ndarray().conj(), psi0_flat) print("|<psi0|psi0_flat>|=", abs(ov)) assert (abs(1. - abs(ov)) < tol) # now repeat, but keep orthogonal to original ground state # -> should give second eigenvector psi1 in the same charge sector for i in range(1, len(E_flat)): E1_flat, psi1_flat = E_flat[i], psi_flat[:, i] qtotal = npc.detect_qtotal(psi1_flat, psi0.legs) if np.all(qtotal == psi0.qtotal): break # found psi1 in same charge sector else: print( "warning: test didn't find a second eigenvector in the same charge sector!" ) return # just ignore the rest.... E1, psi1, N = lanczos.lanczos(H_Op, psi_init, {'verbose': 1}, orthogonal_to=[psi0]) print("E1 = {E1:.14f} vs exact {E1_flat:.14f}".format(E1=E1, E1_flat=E1_flat)) print("|E1-E1_flat| / |E1_flat| =", abs((E1 - E1_flat) / E1_flat)) psi1_H_psi1 = npc.inner(psi1, npc.tensordot(H, psi1, axes=[1, 0]), do_conj=True) print("<psi1|H|psi1> / E1 = 1 + ", psi1_H_psi1 / E1 - 1.) assert (abs(psi1_H_psi1 / E1 - 1.) < tol) print("<psi1_flat|H_flat|psi1_flat> / E1_flat = ", end=' ') print(np.inner(psi1_flat.conj(), np.dot(H_flat, psi1_flat)) / E1_flat) ov = np.inner(psi1.to_ndarray().conj(), psi1_flat) print("|<psi1|psi1_flat>|=", abs(ov)) assert (abs(1. - abs(ov)) < tol) # and finnally check also orthogonality to psi0 ov = npc.inner(psi0, psi1, do_conj=True) print("|<psi0|psi1>| =", abs(ov)) assert (abs(ov) < tol**0.5)
def test_ED(): # just quickly check that it runs without errors for a small system xxz_pars = dict(L=4, Jxx=1., Jz=1., hz=0.0, bc_MPS='finite') M = XXZChain(xxz_pars) ED = ExactDiag(M) ED.build_full_H_from_mpo() H, ED.full_H = ED.full_H, None ED.build_full_H_from_bonds() H2 = ED.full_H assert (npc.norm(H - H2, np.inf) < 1.e-14) ED.full_diagonalization() psi = ED.groundstate() print("select charge_sector =", psi.qtotal) ED2 = ExactDiag(M, psi.qtotal) ED2.build_full_H_from_mpo() ED2.full_diagonalization() psi2 = ED2.groundstate() full_psi2 = psi.zeros_like() full_psi2[ED2._mask] = psi2 ov = npc.inner(psi, full_psi2, do_conj=True) print("overlab <psi | psi2> = 1. -", 1. - ov) assert (abs(abs(ov) - 1.) < 1.e-15) # starting from a random guess in the correct charge sector, # check if we can also do lanczos. np.random.seed(12345) psi3 = npc.Array.from_func(np.random.random, psi2.legs, qtotal=psi2.qtotal, shape_kw='size') E0, psi3, N = lanczos(ED2, psi3) print("Lanczos E0 =", E0) ov = npc.inner(psi3, psi2, do_conj=True) print("overlab <psi2 | psi3> = 1. -", 1. - ov) assert (abs(abs(ov) - 1.) < 1.e-15)
def test_lanczos_gs(n, N_cache, tol=5.e-14): # generate Hermitian test array leg = gen_random_legcharge(ch, n) H = npc.Array.from_func_square(rmat.GUE, leg) H_flat = H.to_ndarray() E_flat, psi_flat = np.linalg.eigh(H_flat) E0_flat, psi0_flat = E_flat[0], psi_flat[:, 0] qtotal = npc.detect_qtotal(psi0_flat, [leg]) H_Op = H # use `matvec` of the array psi_init = npc.Array.from_func(np.random.random, [leg], qtotal=qtotal) E0, psi0, N = lanczos.lanczos(H_Op, psi_init, { 'verbose': 1, 'N_cache': N_cache }) print("full spectrum:", E_flat) print("E0 = {E0:.14f} vs exact {E0_flat:.14f}".format(E0=E0, E0_flat=E0_flat)) print("|E0-E0_flat| / |E0_flat| =", abs((E0 - E0_flat) / E0_flat)) psi0_H_psi0 = npc.inner(psi0, npc.tensordot(H, psi0, axes=[1, 0]), 'range', do_conj=True) print("<psi0|H|psi0> / E0 = 1. + ", psi0_H_psi0 / E0 - 1.) assert (abs(psi0_H_psi0 / E0 - 1.) < tol) print("<psi0_flat|H_flat|psi0_flat> / E0_flat = ", end=' ') print(np.inner(psi0_flat.conj(), np.dot(H_flat, psi0_flat)) / E0_flat) ov = np.inner(psi0.to_ndarray().conj(), psi0_flat) print("|<psi0|psi0_flat>|=", abs(ov)) assert (abs(1. - abs(ov)) < tol) print("version with arpack") E0a, psi0a = lanczos.lanczos_arpack(H_Op, psi_init, {'verbose': 1}) print("E0a = {E0a:.14f} vs exact {E0_flat:.14f}".format(E0a=E0a, E0_flat=E0_flat)) print("|E0a-E0_flat| / |E0_flat| =", abs((E0a - E0_flat) / E0_flat)) psi0a_H_psi0a = npc.inner(psi0a, npc.tensordot(H, psi0a, axes=[1, 0]), 'range', do_conj=True) print("<psi0a|H|psi0a> / E0a = 1. + ", psi0a_H_psi0a / E0a - 1.) assert (abs(psi0a_H_psi0a / E0a - 1.) < tol) ov = np.inner(psi0a.to_ndarray().conj(), psi0_flat) print("|<psi0a|psi0_flat>|=", abs(ov)) assert (abs(1. - abs(ov)) < tol) # now repeat, but keep orthogonal to original ground state orthogonal_to = [psi0] # -> should give second eigenvector psi1 in the same charge sector for i in range(1, len(E_flat)): E1_flat, psi1_flat = E_flat[i], psi_flat[:, i] qtotal = npc.detect_qtotal(psi1_flat, psi0.legs, cutoff=1.e-10) if np.any(qtotal != psi0.qtotal): continue # not in same charge sector print("--- excited state #", len(orthogonal_to)) ortho_to = [psi.copy() for psi in orthogonal_to] # (gets modified inplace) lanczos_params = {'verbose': 1, 'reortho': True} if E1_flat > -0.01: lanczos_params['E_shift'] = -2. * E1_flat - 0.2 E1, psi1, N = lanczos.lanczos( sparse.OrthogonalNpcLinearOperator(H_Op, ortho_to), psi_init, lanczos_params) print("E1 = {E1:.14f} vs exact {E1_flat:.14f}".format(E1=E1, E1_flat=E1_flat)) print("|E1-E1_flat| / |E1_flat| =", abs((E1 - E1_flat) / E1_flat)) psi1_H_psi1 = npc.inner(psi1, npc.tensordot(H, psi1, axes=[1, 0]), 'range', do_conj=True) print("<psi1|H|psi1> / E1 = 1 + ", psi1_H_psi1 / E1 - 1.) assert (abs(psi1_H_psi1 / E1 - 1.) < tol) print("<psi1_flat|H_flat|psi1_flat> / E1_flat = ", end='') print(np.inner(psi1_flat.conj(), np.dot(H_flat, psi1_flat)) / E1_flat) ov = np.inner(psi1.to_ndarray().conj(), psi1_flat) print("|<psi1|psi1_flat>|=", abs(ov)) assert (abs(1. - abs(ov)) < tol) # and finnally check also orthogonality to previous states for psi_prev in orthogonal_to: ov = npc.inner(psi_prev, psi1, 'range', do_conj=True) assert (abs(ov) < tol) orthogonal_to.append(psi1) if len(orthogonal_to) == 1: print( "warning: test didn't find a second eigenvector in the same charge sector!" )