def test_npc_svd(): for m, n in [(1, 1), (1, 10), (10, 1), (10, 10), (10, 20)]: print("m, n = ", m, n) tol_NULP = max(20 * max(m, n)**3, 1000) for i in range(1000): A = random_Array((m, n), chinfo3, sort=True) if A.stored_blocks > 0: break Aflat = A.to_ndarray() Sonly = npc.svd(A, compute_uv=False) U, S, VH = npc.svd(A, full_matrices=False, compute_uv=True) assert (U.shape[1] == S.shape[0] == VH.shape[0]) U.test_sanity() VH.test_sanity() npt.assert_array_almost_equal_nulp(Sonly, S, tol_NULP) recalc = npc.tensordot(U.scale_axis(S, axis=-1), VH, axes=1) npt.assert_array_almost_equal_nulp(recalc.to_ndarray(), Aflat, tol_NULP) # compare with flat SVD Uflat, Sflat, VHflat = np.linalg.svd(Aflat, False, True) perm = np.argsort(-S) # sort descending print(S[perm]) iperm = inverse_permutation(perm) for i in range(len(Sflat)): if i not in iperm: # dopped it in npc.svd() assert (Sflat[i] < EPS * 10) Sflat = Sflat[iperm] npt.assert_array_almost_equal_nulp(Sonly, Sflat, tol_NULP) # comparing U and Uflat is hard: U columns can change by a phase... print("with full_matrices") Ufull, Sfull, VHfull = npc.svd(A, full_matrices=True, compute_uv=True) Ufull.test_sanity() VHfull.test_sanity() npt.assert_array_almost_equal_nulp(Sfull, S, tol_NULP) print("for trivial charges") A = npc.Array.from_func(np.random.random, [lcTr, lcTr.conj()], shape_kw='size') Aflat = A.to_ndarray() U, S, VH = npc.svd(A) recalc = npc.tensordot(U.scale_axis(S, axis=-1), VH, axes=1) tol_NULP = max(20 * max(A.shape)**3, 1000) npt.assert_array_almost_equal_nulp(recalc.to_ndarray(), Aflat, tol_NULP)
def calc_B(self, M): """Performs the SVD to extract B from s * theta Parameters ---------- M: :class:`tenpy.linalg.np_conserved.Array` the tensor to apply svd to """ M = M.combine_legs(['p', 'vR']) U, s, V = npc.svd(M, full_matrices=0) V = V.split_legs(['(p.vR)']) V = self.set_anonymous_svd(V, 'vL') #V['vL','p','vR'] U = self.set_anonymous_svd(U, 'vR') #U['vL','vR'] new_B = npc.tensordot(U, V, axes=('vR', 'vL')) return new_B
def calc_A(self, M): """Performs the SVD to extract A from theta * s Parameters ---------- M: :class:`tenpy.linalg.np_conserved.Array` the tensor to apply svd to """ M = M.combine_legs(['vL', 'p']) U, s, V = npc.svd(M, full_matrices=0) U = U.split_legs(['(vL.p)']) U = self.set_anonymous_svd(U, 'vR') #U['vL','p','vR'] V = self.set_anonymous_svd(V, 'vL') #V['vL','vR'] new_A = npc.tensordot(U, V, axes=('vR', 'vL')) #A['vL','p','vR'] return new_A
def gauge_transform(self, A, B, theta, C): U, s, Vdag = npc.svd(C, full_matrices=0) U = self.set_anonymous_svd(U, 'vR') Vdag = self.set_anonymous_svd(Vdag, 'vL') Udag = U.conj().itranspose(['vR*', 'vL*']).iset_leg_labels(['vL', 'vR']) V = Vdag.conj().itranspose(['vR*', 'vL*']).iset_leg_labels(['vL', 'vR']) Ap = npc.tensordot(Udag, A, axes=('vR', 'vL')) Ap = npc.tensordot(Ap, U, axes=('vR', 'vL')) Bp = npc.tensordot(Vdag, B, axes=('vR', 'vL')) Bp = npc.tensordot(Bp, V, axes=('vR', 'vL')) thetap = npc.tensordot(Udag, theta, axes=('vR', 'vL')) thetap = npc.tensordot(thetap, V, axes=('vR', 'vL')) return Ap, Bp, thetap, s
def update_AB(self, A, B, theta, C): U, s, V = npc.svd(C, full_matrices=0) U = self.set_anonymous_svd(U, 'vR') V = self.set_anonymous_svd(V, 'vL') Udag = U.conj() Vdag = V.conj() new_A = npc.tensordot(Udag, A, axes=('vL*', 'vL')) new_A = npc.tensordot(new_A, U, axes=('vR', 'vL')) new_B = npc.tensordot(V, B, axes=('vR', 'vL')) new_B = npc.tensordot(new_B, Vdag, axes=('vR', 'vR*')) new_theta = npc.tensordot(Udag, theta, axes=('vL*', 'vL')) new_theta = npc.tensordot(new_theta, Vdag, axes=('vR', 'vR*')) new_A.iset_leg_labels(['vL', 'p', 'vR']) new_B.iset_leg_labels(['vL', 'p', 'vR']) new_theta.iset_leg_labels(['vL', 'p', 'vR']) return new_A, new_B, new_theta, s
def theta_svd_right_left(self, theta): """Performs the SVD from right to left""" theta = theta.transpose(['vL', 'p', 'vR']) theta = theta.combine_legs(['p', 'vR']) theta = theta.transpose(['vL', '(p.vR)']) V, s, U = npc.svd(theta, full_matrices=0) U = U.split_legs(['(p.vR)']) U = self.set_anonymous_svd(U, 'vL') V = self.set_anonymous_svd(V, 'vR') s_ndarray = np.diag(s) vL_U = U.get_leg('vL') vR_V = V.get_leg('vR') s = npc.Array.from_ndarray(s_ndarray, [vR_V.conj(), vL_U.conj()], dtype=None, qtotal=None, cutoff=None) s.iset_leg_labels(['vL', 'vR']) return U, s, V
def theta_svd_right_left(self, theta): """Performs the SVD from right to left Parameters ---------- theta : :class:`tenpy.linalg.np_conserved.Array`, The theta tensor on which the SVD is applied """ theta = theta.combine_legs(['p', 'vR']) V, s, U = npc.svd(theta, full_matrices=0) U = U.split_legs(['(p.vR)']) U = self.set_anonymous_svd(U, 'vL') V = self.set_anonymous_svd(V, 'vR') s_ndarray = np.diag(s) vL_U = U.get_leg('vL') vR_V = V.get_leg('vR') s = npc.Array.from_ndarray(s_ndarray, [vR_V.conj(), vL_U.conj()], dtype=None, qtotal=None, cutoff=None) s.iset_leg_labels(['vL', 'vR']) return U, s, V
exp_H2 = exp_H2.split_legs() # by default split all legs which are `LegPipe` # (this restores the originial labels ['p0', 'p1', 'p0*', 'p1*'] of `H2` in `exp_H2`) print("7) apply exp(H2) to even/odd bonds of the MPS and truncate with svd") # (this implements one time step of first order TEBD) for even_odd in [0, 1]: for i in range(even_odd, L - 1, 2): B_L = Bs[i].scale_axis(Ss[i], 'vL').ireplace_label('p', 'p0') B_R = Bs[i + 1].replace_label('p', 'p1') theta = npc.tensordot(B_L, B_R, axes=('vR', 'vL')) theta = npc.tensordot(exp_H2, theta, axes=(['p0*', 'p1*'], ['p0', 'p1'])) # view as matrix for SVD theta = theta.combine_legs([('vL', 'p0'), ('p1', 'vR')], new_axes=[0, 1], qconj=[+1, -1]) # now theta has labels '(vL.p0)', '(p1.vR)' U, S, V = npc.svd(theta, inner_labels=['vR', 'vL']) # truncate keep = S > cutoff S = S[keep] invsq = np.linalg.norm(S) Ss[i + 1] = S / invsq U = U.iscale_axis(S / invsq, 'vR') Bs[i] = U.split_legs('(vL.p0)').iscale_axis(Ss[i]**(-1), 'vL').ireplace_label( 'p0', 'p') Bs[i + 1] = V.split_legs('(p1.vR)').ireplace_label('p1', 'p') print("finished")