def maximize_overlap(thatmpslist, chi, thatAC=None, tol=1E-13): """ Generate MPS tensors AL, C, AR of bond dimension chi, such that the overlap with the tensors in thatmpslist is maximized up to tolerance tol. """ thatmpslist, thosefpoints = regauge(thatmpslist, tol=tol) thatAL, thatC, thatAR = thatmpslist print(np.diag(thatC)) if thatAC is None: thatAC = ct.rightmult(thatAL, thatC) d, _, _ = thatAL.shape #IF CHANGING TO FLOAT LOOK HERE AL = utils.random_complex((d, chi, chi)) AR = utils.random_complex((d, chi, chi)) C = utils.random_complex((chi, chi)) lam, L = tmeigs(thatAL, B=np.conj(AL), tol=0.01, which="LM", direction="left") _, R = tmeigs(thatAR, B=np.conj(AR), tol=0.01, which="LM", direction="right") AC = ct.gauge_transform(L, thatAC, R.T) C = ct.gauge_transform(L, thatC, R.T) AL, AR = gauge_match_polar(AC, C) delta = np.linalg.norm((ct.rightmult(AL, C) - AC / lam).flatten()) while delta >= tol: print(delta) lam, L = tmeigs(thatAL, B=np.conj(AL), tol=delta / 10, which="LM", direction="left") _, R = tmeigs(thatAR, B=np.conj(AR), tol=delta / 10, which="LM", direction="right") AC = ct.gauge_transform(L, thatAC, R.T) C = ct.gauge_transform(L, thatC, R.T) print(np.diag(C)) AL, AR = gauge_match_polar(AC, C) delta = np.linalg.norm((ct.rightmult(AL, C) - AC / lam).flatten()) thismpslist = [AL, C, AR] return thismpslist
def B2_tensor(oldlist, newlist): NL, NR = null_spaces(oldlist) AL, C, AR = newlist AC = ct.rightmult(AL, C) L = ct.XopL(AC, B=np.conj(NL)) R = ct.XopR(AR, B=np.conj(NR)) return np.dot(L, R.T)
def testHAc(chi, d=2): """ Tests that the sparse and dense apply_HAc give the same answer on random input. """ h = utils.random_complex((d, d, d, d)) A = utils.random_complex((d, chi, chi)) mpslist = vumps.mixed_canonical(A) A_L, C, A_R = mpslist A_C = ct.rightmult(A_L, C) hL = utils.random_complex((chi, chi)) hR = utils.random_complex((chi, chi)) hlist = [h, hL, hR] Acp_sparse = vumps.apply_HAc(A_C, A_L, A_R, hlist) #print("Sparse: ", Acp_sparse) Acp_dense = vumps.apply_HAc_dense(A_C, A_L, A_R, hlist) # print("Dense: ", Acp_dense) # print("*") norm = np.linalg.norm(Acp_sparse - Acp_dense) / chi**2 print("Test HAc.") print("Norm resid: ", norm) if norm < 1E-13: print("Passed!") else: print("Failed!")
def onesiteexpect(A_R, C, O, real=True, L=None, R=None): A_C = ct.rightmult(A_R, C) E = ct.chainwithops([A_C], ops=[(O, 0)], lvec=L, rvec=R) if real: if np.abs(E.imag) > 1E-14: print("Warning: EV had large imaginary part ", str(E.imag)) E = E.real return E
def compute_eL(A_L, C, A_C): """ Approximate left loss function eL = ||A_C - A_L . C||. """ eLmid = A_C - ct.rightmult(A_L, C) eL = np.linalg.norm(ct.fuse_left(eLmid)) return eL
def vumps_expand(thatmpslist, H, chi, delta, params, thatAC=None): mpslist = maximize_overlap(thatmpslist, chi, thatAC=thatAC, tol=delta / 10) A_C = ct.rightmult(mpslist[0], mpslist[1]) TMtol = params["TM_tol"] if params["adaptive_tm_tol"]: TMtol *= delta fpoints = vumps_tm_eigs(mpslist, params, tol=TMtol) H_env = vumps_environment(mpslist, fpoints, H, delta, params) return [mpslist, A_C, fpoints, H_env]
def gauge_match_QR(A_C, C): QAC, RAC = qrpos(A_C) QC, RC = qrpos(C) A_L = ct.rightmult(QAC, np.conj(RC.T)) errL = np.linalg.norm(RAC-RC) QAC, LAC = rqpos(A_C) QC, LC = rqpos(C) A_R = ct.leftmult(QC.T, QAC) errR = np.linalg.norm(LAC-LC) err = max(errL, errR) return (A_L, A_R, err)
def mixed_canonical_old(A, lam=None): # """ # Bring a uniform MPS tensor into mixed canonical form. # """ lam, gam = tm.canonicalized_gamma(A, lam=lam) A_L = ct.leftmult(lam, gam) A_R = ct.rightmult(gam, lam) chi = lam.size C = np.zeros(chi, dtype=A.dtype) C[:] = lam.real[:] C = np.diag(C) mpslist = [A_L, C, A_R] return mpslist
def expand_tensors(oldlist, newlist, Dchi): NL, NR = null_spaces(oldlist) #AL, C, AR = newlist AL, C, AR = oldlist d, chi, _ = AL.shape B2 = B2_tensor(oldlist, newlist) #U, S, VH = sp.linalg.svd(B2) print("B2: ", B2.shape) try: U, s, V = np.linalg.svd(B2, full_matrices=False, compute_uv=True) except: print("Divide-and-conquer SVD failed. Trying gesvd...") U, s, V = sp.linalg.svd(B2, full_matrices=False, overwrite_a=False, check_finite=True, lapack_driver='gesvd') U = U[:, :Dchi] Vh = dag(V[:Dchi, :]) newchi = chi + Dchi NLU = ct.rightmult(NL, U) newAL = np.zeros((d, newchi, newchi), dtype=oldlist[0].dtype) newAL[:, :chi, :chi] = AL[:, :, :] newAL[:, chi:, chi:] = NLU[:, :] newAL = ct.unfuse_left(newAL, (d, newchi, newchi)) newC = np.zeros((newchi, newchi), dtype=oldlist[0].dtype) newC[:chi, :chi] = C[:, :] VhNR = ct.leftmult(Vh, NR) newAR = np.zeros((d, newchi, newchi), dtype=oldlist[0].dtype) newAR[:, :chi, :chi] = AR[:, :chi, :chi] newAR[:, chi:, chi:] = VhNR[:, :, :] newmpslist = [newAL, newC, newAR] newAC = ct.rightmult(newAL, newC) return (newmpslist, newAC)
def apply_Hc(C, A_L, A_R, Hlist): """ Compute C' via eq 16 of vumps paper (132 of tangent space methods). """ H, LH, RH = Hlist A_Lstar = np.conj(A_L) A_C = ct.rightmult(A_L, C) to_contract = [A_C, A_Lstar, A_R, np.conj(A_R), H] idxs = [(4, 1, 3), (6, 1, -1), (5, 3, 2), (7, -2, 2), (6, 7, 4, 5)] term1 = scon(to_contract, idxs) term2 = np.dot(LH, C) term3 = np.dot(C, RH.T) C_prime = term1 + term2 + term3 return C_prime
def apply_HAc(A_C, A_L, A_R, Hlist): """ Compute A'C via eq 11 of vumps paper (131 of tangent space methods). """ H, LH, RH = Hlist to_contract_1 = [A_L, np.conj(A_L), A_C, H] idxs_1 = [(2, 1, 4), (3, 1, -2), (5, 4, -3), (3, -1, 2, 5)] term1 = scon(to_contract_1, idxs_1) to_contract_2 = [A_C, A_R, np.conj(A_R), H] idxs_2 = [(5, -2, 4), (2, 4, 1), (3, -3, 1), (-1, 3, 5, 2)] term2 = scon(to_contract_2, idxs_2) term3 = ct.leftmult(LH, A_C) term4 = ct.rightmult(A_C, RH.T) A_C_prime = term1 + term2 + term3 + term4 return A_C_prime
def vumps_initial_tensor(d, chi, params, dtype=np.complex128): """ Generate a random uMPS in mixed canonical forms, along with the left dominant eV L of A_L and right dominant eV R of A_R. """ Ainit = utils.random_complex((d, chi, chi)) if dtype == np.float64 or dtype == np.float32: Ainit = Ainit.real mpslist = mixed_canonical(Ainit) A_L, C, A_R = mpslist Cd = np.conj(C.T) rL = np.dot(Cd, C) lR = np.dot(C, Cd) lR /= np.trace(lR) rL /= np.trace(rL) A_C = ct.rightmult(A_L, C) fpoints = [rL, lR] return (mpslist, A_C, fpoints)
def vumps_truncate(mpslist, maxchi=None, writer=None, Niter=None): """ Use an SVD to adjust the bond dimension of the MPS. """ A_L, C, A_R = mpslist A_C = ct.leftmult(C, A_R) th = ct.twositecontract(A_L, A_C) gam_L, gam_R, lam, newchi, err = ct.svd(th, maxchi=maxchi) A_L = ct.leftmult(lam, gam_L) A_R = ct.rightmult(gam_R, lam) C = np.zeros((lam.size, lam.size), dtype=C.dtype) C += np.diag(lam) newmpslist = [A_L, C, A_R] if writer is not None: vumps_print(writer, "Adjusting bond dimension...") vumps_print(writer, "\tNew chi: ", str(newchi)) vumps_print("\tTruncation error: ", str(err)) truncarr = np.array([err]) truncfile = "TruncationError.txt" writer.writearray(truncfile, truncarr, Niter, header="TruncationError") return (newmpslist, newchi, err)
def RH_test(chi, d=2, tol=1E-11): """ Tests that <L|R_H> = 0 where R_H is the renormalized effective Hamiltonian of the right infinite block of a random uMPS with bond dimension chi. The Hamiltonian is randomized and Hermitian. """ params = vumps.vumps_params() params["dom_ev_approx"] = False mpslist, rL, lR = vumps.vumps_initial_tensor(d, chi, params) A_L, C, A_R = mpslist # evl, evr, eVl, eVr = tm.tmeigs(A_R, nev=3, ncv=30, tol=1E-13, # which="both") #H = utils.random_hermitian(d*d).reshape((d,d,d,d)) H = utils.H_ising(-1.0, -0.48).reshape((d, d, d, d)) #RH = vumps.solve_for_RH(A_R, H, rL, params) RH = vumps.solve_for_RH(A_R, H, lR, params) proj = np.abs(vumps.proj(rL, RH)) print("<L|RH>:", proj) if proj > tol: print("Failed!") else: print("Passed!") print("GAUGE MATCHING RANDOM AC AND C") mpslist, _, _ = vumps.vumps_initial_tensor(d, chi, params) A_C = utils.random_unitary(d * chi)[:, :chi].reshape((d, chi, chi)) # A_C = utils.random_unitary(d*chi)[:, :chi].reshape( # (d, chi, chi)) A_C = utils.random_complex((d, chi, chi)) #C = np.diag(utils.random_rng(chi, 0.1, 1)) C = utils.random_complex((chi, chi)) A_L, A_R, _ = vumps.gauge_match_SVD(A_C, C, 1E-15) mpslist = [A_L, C, A_R] rL, lR = vumps.normalized_tm_eigs(mpslist, params) RH = vumps.solve_for_RH(A_R, H, rL, params) proj = np.abs(vumps.proj(rL, RH)) print("<L|RH>:", proj) if proj > tol: print("Failed!") else: print("Passed!") print("GAUGE MATCHING CANONICAL AC AND C") mpslist, _, _ = vumps.vumps_initial_tensor(d, chi, params) A_L, C, A_R = mpslist A_C = ct.rightmult(A_L, C) A_L, A_R, _ = vumps.gauge_match_SVD(A_C, C, 1E-15) mpslist = [A_L, C, A_R] rL, lR = vumps.normalized_tm_eigs(mpslist, params) RH = vumps.solve_for_RH(A_R, H, rL, params) proj = np.abs(vumps.proj(rL, RH)) print("<L|RH>:", proj) if proj > tol: print("Failed!") else: print("Passed!") print("TENSORS AFTER ONE VUMPS ITERATION") mpslist, rL, lR = vumps.vumps_initial_tensor(d, chi, params) A_L, C, A_R = mpslist A_C = ct.rightmult(A_L, C) vumps_state = [True, A_C, None, None] mpslist, delta, vumps_state = vumps.vumps_iteration( mpslist, H, params["delta_0"], params, vumps_state) A_L, C, A_R = mpslist rL, lR = vumps.normalized_tm_eigs(mpslist, params) RH = vumps.solve_for_RH(A_R, H, rL, params) proj = np.abs(vumps.proj(rL, RH)) print("<L|RH>:", proj) if proj > tol: print("Failed!") else: print("Passed!")
def LH_test(chi, d=2, tol=1E-13): """ Tests that <LH|R> = 0 where LH is the renormalized effective Hamiltonian of the left infinite block of a random uMPS with bond dimension chi. The Hamiltonian is randomized and Hermitian. """ params = vumps.vumps_params() params["dom_ev_approx"] = False params["env_tol"] = 1E-12 enviro_params = vumps.extract_enviro_params(params, params["delta_0"]) H = utils.random_hermitian(d * d).reshape((d, d, d, d)) print("MIXED CANONICAL") mpslist, rL, lR = vumps.vumps_initial_tensor(d, chi, params) A_L, C, A_R = mpslist #rL, lR = vumps.normalized_tm_eigs(mpslist, params) # print("rL - lR:", np.linalg.norm(rL-lR)) # print("rL - rL.T:", np.linalg.norm(rL-rL.T)) # print("rL - dag(rL):", np.linalg.norm(rL-np.conj(rL.T))) # print("E: ", vumps.twositeexpect(mpslist, H)) # hL = vumps.compute_hL(A_L, H) # print("<hL|R>: ", vumps.proj(hL, lR)) LH = vumps.solve_for_LH(A_L, H, lR, enviro_params) proj = np.abs(vumps.proj(LH, lR)) print("<LH|R>:", proj) if proj > tol: print("Failed!") else: print("Passed!") print("GAUGE MATCHING RANDOM AC AND C") mpslist, rL, lR = vumps.vumps_initial_tensor(d, chi, params) A_C = utils.random_unitary(d * chi)[:, :chi].reshape((d, chi, chi)) C = np.diag(utils.random_rng(chi, 0.1, 1)) A_L, A_R = vumps.gauge_match_polar(A_C, C) mpslist = [A_L, C, A_R] print("E:", vumps.twositeexpect(mpslist, H)) rL, lR = vumps.normalized_tm_eigs(mpslist, params) #hL = vumps.compute_hL(A_L, H) # print("E: ", vumps.twositeexpect(mpslist, H)) # print("<hL|R>: ", vumps.proj(hL, lR)) LH = vumps.solve_for_LH(A_L, H, lR, enviro_params) proj = np.abs(vumps.proj(LH, lR)) print("<LH|R>:", proj) if proj > tol: print("Failed!") else: print("Passed!") print("TENSORS AFTER ONE VUMPS ITERATION") mpslist, rL, lR = vumps.vumps_initial_tensor(d, chi, params) A_L, C, A_R = mpslist A_C = ct.rightmult(A_L, C) environment_init = [rL, lR, None, None] environment = vumps.vumps_environment(mpslist, H, tol, params, environment_init) vumps_state = [False, A_C] mpslist, delta, vumps_state = vumps.vumps_gradient(mpslist, H, environment, tol, params, vumps_state) environment = vumps.vumps_environment(mpslist, H, tol, params, environment) A_L, C, A_R = mpslist rL, lR = vumps.normalized_tm_eigs(mpslist, params) LH = vumps.solve_for_LH(A_L, H, lR, params) proj = np.abs(vumps.proj(LH, lR)) print("<LH|R>:", proj) if proj > tol: print("Failed!") else: print("Passed!")