def vumps_loss(A_L, A_C): """ Norm of MPS gradient: see Appendix 4. """ A_L_mat = ct.fuse_left(A_L) A_L_dag = np.conj(A_L_mat.T) N_L = sp.linalg.null_space(A_L_dag) N_L_dag = np.conj(N_L.T) A_C_mat = ct.fuse_left(A_C) B = np.dot(N_L_dag, A_C_mat) Bnorm = np.linalg.norm(B) return Bnorm
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 compute_eR(A_R, C, A_C): """ Approximate right loss function eR = ||A_C - C . A_R|| """ eRmid = A_C - ct.leftmult(C, A_R) eR = np.linalg.norm(ct.fuse_left(eRmid)) return eR
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 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 null_spaces(mpslist): """ Return matrices spanning the null spaces of A_L and A_R, and the hermitian conjugates of these, reshaped into rank 3 tensors. """ AL, C, AR = mpslist d, chi, _ = AL.shape NLshp = (d, chi, (d-1)*chi) ALdag = ct.fuse_left(AL).T.conj() NLm = sp.linalg.null_space(ALdag) NL = NLm.reshape(NLshp) ARmat = ct.fuse_right(AR) NRm_dag = sp.linalg.null_space(ARmat) NRm = np.conj(NRm_dag) NR = NRm.reshape((d, chi, (d-1)*chi)) NR = NR.transpose((0, 2, 1)) return (NL, NR)