def gauge_match_SVD(A_C, C, thresh=1E-13): """ Return approximately gauge-matched A_L and A_R from A_C and C using an SVD. If """ Ashape = A_C.shape Cdag = np.conj(C.T) AC_mat_l = ct.fuse_left(A_C) #A_C.reshape(d*chi, chi) ACl_Cd = np.dot(AC_mat_l, Cdag) Ul, Sl, Vld = np.linalg.svd(ACl_Cd, full_matrices=False) AL_mat = np.dot(Ul, Vld) A_L = ct.unfuse_left(AL_mat, Ashape) AC_mat_r = ct.fuse_right(A_C) d, chi, chi = Ashape AC_mat_r = A_C.reshape(chi, d * chi) Cd_ACr = np.dot(Cdag, AC_mat_r) Ur, Sr, Vrd = np.linalg.svd(Cd_ACr, full_matrices=False) AR_mat = np.dot(Ur, Vrd) A_R = ct.unfuse_right(AR_mat, Ashape) smallest = min(min(Sl), min(Sr)) SVD_ok = smallest > thresh if not SVD_ok: print("Singular values fell beneath threshold.") return (A_L, A_R, SVD_ok)
def qrpos(A): """ QR decomp. of A, with phase convention such that R has only positive elements on the main diagonal. If A is an MPS tensor (d, chiL, chiR), it is reshaped appropriately before the throughput begins. In that case, Q will be a tensor of the same size, while R will be a chiR x chiR matrix. """ Ashp = A.shape if len(Ashp) == 2: return qrmat(A) elif len(Ashp) != 3: print("A had invalid dimensions, ", A.shape) A = ct.fuse_left(A) #d*chiL, chiR Q, R = qrmat(A, mode="economic") Q = ct.unfuse_left(Q, Ashp) return (Q, R)
def gauge_match_polar(A_C, C): """ Return approximately gauge-matched A_L and A_R from A_C and C using a polar decomposition. """ Ashape = A_C.shape AC_mat_l = ct.fuse_left(A_C) AC_mat_r = ct.fuse_right(A_C) UAc_l, PAc_l = sp.linalg.polar(AC_mat_l, side="right") UAc_r, PAc_r = sp.linalg.polar(AC_mat_r, side="left") UC_l, PC_l = sp.linalg.polar(C, side="right") UC_r, PC_r = sp.linalg.polar(C, side="left") A_L = np.dot(UAc_l, np.conj(UC_l.T)) A_L = ct.unfuse_left(A_L, Ashape) A_R = np.dot(np.conj(UC_r.T), UAc_r) A_R = ct.unfuse_right(A_R, Ashape) return (A_L, A_R)
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)