def test_qr(): for shape in [(4, 4), (6, 8), (8, 6)]: tol = shape[0] * shape[1] * 100 for qtotal_A in [None, [1]]: A = random_Array(shape, chinfo3, qtotal=qtotal_A, sort=False) A_flat = A.to_ndarray() for qtotal_Q in [None, [1]]: for mode in ['reduced', 'complete']: for qconj in [+1, -1]: for pos in [False, True]: print( f"shape={shape!s} qtot_A={qtotal_A!s} qtot_Q={qtotal_Q!s}" f"mode={mode!s} pos_diag_R={pos!s} inner_qconj={qconj:+d}" ) Q, R = npc.qr(A, mode=mode, pos_diag_R=pos, qtotal_Q=qtotal_Q, inner_qconj=qconj) # print(q._qdata) Q.test_sanity() R.test_sanity() assert np.all( Q.qtotal) == A.chinfo.make_valid(qtotal_Q) assert R.legs[0].qconj == qconj QR = npc.tensordot(Q, R, axes=1) npt.assert_array_almost_equal_nulp( A_flat, QR.to_ndarray(), tol) QdaggerQ = npc.tensordot(Q.conj(), Q, axes=[0, 0]) assert npc.norm(QdaggerQ - npc.eye_like(QdaggerQ)) < 1.e-10
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_TransferMatrix(chi=4, d=2): psi = random_MPS(2, d, chi, bc='infinite', form=None) full_TM = npc.tensordot(psi._B[0], psi._B[0].conj(), axes=['p', 'p*']) full_TM = npc.tensordot(full_TM, psi._B[1], axes=['vR', 'vL']) full_TM = npc.tensordot(full_TM, psi._B[1].conj(), axes=[['vR*', 'p'], ['vL*', 'p*']]) full_TM = full_TM.combine_legs([['vL', 'vL*'], ['vR', 'vR*']], qconj=[+1, -1]) full_TM_dense = full_TM.to_ndarray() eta_full, w_full = np.linalg.eig(full_TM_dense) sort = np.argsort(np.abs(eta_full))[::-1] eta_full = eta_full[sort] w_full = w_full[:, sort] TM = mps.TransferMatrix(psi, psi, charge_sector=0, form=None) eta, w = TM.eigenvectors(3) print("transfer matrix yields eigenvalues ", eta) print(eta.shape, eta_full.shape) print(psi.dtype) # note: second and third eigenvalue are complex conjugates if bool(eta[2].imag > 0.) == bool(eta_full[2].imag > 0.): npt.assert_allclose(eta[:3], eta_full[:3]) else: npt.assert_allclose(eta[:3], eta_full[:3].conj()) # compare largest eigenvector w0_full = w_full[:, 0] w0 = w[0].to_ndarray() assert (abs(np.sum(w0_full)) > 1.e-20) # should be the case for random stuff w0_full /= np.sum(w0_full) # fixes norm & phase w0 /= np.sum(w0) npt.assert_allclose(w0, w0_full)
def _swap_disentangle_bond(self, i, swap=True, disentangle=False): """swap sites (i-1, i) (if swap = True) """ # very similar to update_bond i0, i1 = i - 1, i # Construct the theta matrix theta = self.psi.get_theta(i0, n=2) # 'vL', 'vR', 'p0', 'p1', 'q0', 'q1' if swap: theta.ireplace_labels(['p0', 'q0', 'p1', 'q1'], ['p1', 'q1', 'p0', 'q0']) if disentangle: theta, U_disent = self.disentangle(theta) theta = theta.combine_legs([('vL', 'p0', 'q0'), ('vR', 'p1', 'q1')], qconj=[+1, -1]) # Perform the SVD and truncate the wavefunction U, S, V, trunc_err, renormalize = svd_theta(theta, self.trunc_params, inner_labels=['vR', 'vL']) # bring back to right-canonical 'B' form and update matrices B_R = V.split_legs(1).ireplace_labels(['p1', 'q1'], ['p', 'q']) C = self.psi.get_theta(i0, n=2, formL=0.) if swap: C.ireplace_labels(['p0', 'q0', 'p1', 'q1'], ['p1', 'q1', 'p0', 'q0']) if disentangle and U_disent is not None: C = npc.tensordot(U_disent, C, axes=[['q0*', 'q1*'], ['q0', 'q1']]) B_L = npc.tensordot(C.combine_legs(('vR', 'p1', 'q1'), pipes=theta.legs[1]), V.conj(), axes=['(vR.p1.q1)', '(vR*.p1*.q1*)']) B_L.ireplace_labels(['vL*', 'p0', 'q0'], ['vR', 'p', 'q']) B_L /= renormalize # re-normalize to <psi|psi> = 1 self.psi.set_SR(i0, S) self.psi.set_B(i0, B_L, form='B') self.psi.set_B(i1, B_R, form='B') self._trunc_err_bonds[i] = self._trunc_err_bonds[i] + trunc_err return trunc_err
def sweep_one(self): LP, RP = make_environment(self.psi, self.H, N=self.options.get('N_env', 20)) _theta = self.psi.get_B(0, form='Th') W = self.H.get_W(0) _C = npc.Array.from_ndarray( np.diagflat(self.psi.get_SR(0)), [LP.get_leg('vR').conj(), RP.get_leg('vL').conj()], labels=['vL', 'vR']) dt = self.dt * self.dt_scale theta, N_t = self.update_theta_h1(LP, RP, _theta, W, dt) #time evolve theta with H1 C, N_C = self.update_s_h0(LP, RP, _C, dt) # time evolve s with H0 Cdag = C.conj().itranspose(['vR*', 'vL*']).iset_leg_labels(['vL', 'vR']) theta_Cdag = npc.tensordot(theta, Cdag, axes=('vR', 'vL')) Cdag_theta = npc.tensordot(Cdag, theta, axes=('vR', 'vL')) A = self.calc_A(theta_Cdag) B = self.calc_B(Cdag_theta) A, B, theta, s = self.gauge_transform(A, B, theta, C) self.psi.set_B(0, A, form='A') self.psi.set_B(0, theta, form='Th') self.psi.set_B(0, B, form='B') self.psi.set_SL(0, s)
def test_MPO_var(L=8, tol=1.e-13): xxz_pars = dict(L=L, Jx=1., Jy=1., Jz=1.1, hz=0.1, bc_MPS='finite', conserve=None) M = SpinChain(xxz_pars) psi = random_MPS(L, 2, 10) exp_val = M.H_MPO.expectation_value(psi) ED = ExactDiag(M) ED.build_full_H_from_mpo() psi_full = ED.mps_to_full(psi) exp_val_full = npc.inner(psi_full, npc.tensordot(ED.full_H, psi_full, axes=1), axes='range', do_conj=True) assert abs(exp_val - exp_val_full) / abs(exp_val_full) < tol Hsquared = M.H_MPO.variance(psi, 0.) Hsquared_full = npc.inner(psi_full, npc.tensordot(ED.full_H, npc.tensordot(ED.full_H, psi_full, axes=1), axes=1), axes='range', do_conj=True) assert abs(Hsquared - Hsquared_full) / abs(Hsquared_full) < tol var = M.H_MPO.variance(psi) var_full = Hsquared_full - exp_val_full**2 assert abs(var - var_full) / abs(var_full) < tol
def make_uniform(psi): _chis = psi.chi #RCF TB = TransferMatrix(psi, psi, shift_bra=1, shift_ket=0) es_B, evs_B = TB.eigenvectors() U = evs_B[0].split_legs(['(vL.vL*)']).iset_leg_labels(['vL','vR']) _B = psi.get_B(1) B = npc.tensordot(_B, U, axes=('vR','vL')) B = (B/npc.norm(B))*np.sqrt(_chis[1]) #LCF TA = TransferMatrix(psi, psi, shift_bra=1, shift_ket=0, form='A', transpose=True) es_A, evs_A = TA.eigenvectors() V = evs_A[0].split_legs(['(vR*.vR)']) Vdag = V.conj() _A = psi.get_B(1, form='A') A = npc.tensordot(_A, Vdag, axes=('vR','vR*')) A = (A/npc.norm(A))*np.sqrt(_chis[1]) s = 0.5*(psi.get_SL(0) + psi.get_SL(1)) upsi = make_uMPS(psi) upsi.set_B(0, A, form='A') upsi.set_B(0, B) upsi.set_SL(0, s) return upsi
def matvec(self, x): x = x.split_legs(['(vL.vR)']) x = npc.tensordot(self.Lp, x, axes=('vR', 'vL')) x = npc.tensordot(x, self.Rp, axes=(['vR', 'wR'], ['vL', 'wL'])) x = x.transpose(['vR*', 'vL*']) x = x.iset_leg_labels(['vL', 'vR']) x = x.combine_legs(['vL', 'vR']) return (x)
def test_eig(): size = 10 max_nulp = 10 * size**3 ci = chinfo3 l = gen_random_legcharge(ci, size) A = npc.Array.from_func(np.random.random, [l, l.conj()], qtotal=None, shape_kw='size') print("hermitian A") A += A.conj().itranspose() Aflat = A.to_ndarray() W, V = npc.eigh(A, sort='m>') V.test_sanity() V_W = V.scale_axis(W, axis=-1) recalc = npc.tensordot(V_W, V.conj(), axes=[1, 1]) npt.assert_array_almost_equal_nulp(Aflat, recalc.to_ndarray(), max_nulp) Wflat, Vflat = np.linalg.eigh(Aflat) npt.assert_array_almost_equal_nulp(np.sort(W), Wflat, max_nulp) W2 = npc.eigvalsh(A, sort='m>') npt.assert_array_almost_equal_nulp(W, W2, max_nulp) print("check complex B") B = 1.j * npc.Array.from_func(np.random.random, [l, l.conj()], shape_kw='size') B += B.conj().itranspose() B = A + B Bflat = B.to_ndarray() W, V = npc.eigh(B, sort='m>') V.test_sanity() recalc = npc.tensordot(V.scale_axis(W, axis=-1), V.conj(), axes=[1, 1]) npt.assert_array_almost_equal_nulp(Bflat, recalc.to_ndarray(), max_nulp) Wflat, Vflat = np.linalg.eigh(Bflat) npt.assert_array_almost_equal_nulp(np.sort(W), Wflat, max_nulp) print("calculate without 'hermitian' knownledge") W, V = npc.eig(B, sort='m>') assert (np.max(np.abs(W.imag)) < EPS * max_nulp) npt.assert_array_almost_equal_nulp(np.sort(W.real), Wflat, max_nulp) print("sparse speigs") qi = 1 ch_sect = B.legs[0].get_charge(qi) k = min(3, B.legs[0].slices[qi + 1] - B.legs[0].slices[qi]) Wsp, Vsp = npc.speigs(B, ch_sect, k=k, which='LM') for W_i, V_i in zip(Wsp, Vsp): V_i.test_sanity() diff = npc.tensordot(B, V_i, axes=1) - V_i * W_i assert (npc.norm(diff, np.inf) < EPS * max_nulp) print("for trivial charges") A = npc.Array.from_func(np.random.random, [lcTr, lcTr.conj()], shape_kw='size') A = A + A.conj().itranspose() Aflat = A.to_ndarray() W, V = npc.eigh(A) recalc = npc.tensordot(V.scale_axis(W, axis=-1), V.conj(), axes=[1, 1]) npt.assert_array_almost_equal_nulp(Aflat, recalc.to_ndarray(), 10 * A.shape[0]**3)
def matvec(self, x): x = x.split_legs(['(vL.vR)']) x = npc.tensordot(self.Lp, x, axes=('vR', 'vL')) x = npc.tensordot(x, self.Rp, axes=(['vR', 'wR'], ['vL', 'wL'])) #TODO:next line not needed. Since the transpose does not do anything, should not cost anything. Keep for safety ? x = x.transpose(['vR*', 'vL*']) x = x.iset_leg_labels(['vL', 'vR']) x = x.combine_legs(['vL', 'vR']) return (x)
def test_npc_tensordot(): for sort in [True, False]: print("sort =", sort) a = random_Array((10, 12, 15), chinfo3, qtotal=[0], sort=sort) aflat = a.to_ndarray() legs_b = [l.conj() for l in a.legs[::-1]] b = npc.Array.from_func(np.random.random, legs_b, qtotal=[1], shape_kw='size') b = b * ( 1 + 1.j ) # make second array complex: check that different dtypes work bflat = b.to_ndarray() print("axes = 1") # start simple: only one axes c = npc.tensordot(a, b, axes=1) c.test_sanity() a.test_sanity() b.test_sanity() npt.assert_array_almost_equal_nulp(a.to_ndarray(), aflat, 1) npt.assert_array_almost_equal_nulp(b.to_ndarray(), bflat, 1) cflat = np.tensordot(aflat, bflat, axes=1) npt.assert_array_almost_equal_nulp(c.to_ndarray(), cflat, sum(a.shape)) print("axes = 2") # second: more than one axis c = npc.tensordot(a, b, axes=([1, 2], [1, 0])) a.test_sanity() b.test_sanity() npt.assert_array_almost_equal_nulp(a.to_ndarray(), aflat, 1) npt.assert_array_almost_equal_nulp(b.to_ndarray(), bflat, 1) c.test_sanity() cflat = np.tensordot(aflat, bflat, axes=([1, 2], [1, 0])) npt.assert_array_almost_equal_nulp(c.to_ndarray(), cflat, sum(a.shape)) for i in range(b.shape[0]): b2 = b[i, :, :] if b2.stored_blocks > 0: break b2flat = b2.to_ndarray() print("right tensor fully contracted") print(a.shape, b2.shape) d = npc.tensordot(a, b2, axes=([0, 1], [1, 0])) d.test_sanity() dflat = np.tensordot(aflat, b2flat, axes=([0, 1], [1, 0])) npt.assert_array_almost_equal_nulp(d.to_ndarray(), dflat, sum(a.shape)) print("left tensor fully contracted") d = npc.tensordot(b2, a, axes=([0, 1], [1, 0])) d.test_sanity() dflat = np.tensordot(b2flat, aflat, axes=([0, 1], [1, 0])) npt.assert_array_almost_equal_nulp(d.to_ndarray(), dflat, sum(a.shape)) # full/no contraction is tested in test_npc_inner/test_npc_outer print("for trivial charge") a = npc.Array.from_func(np.random.random, [lcTr, lcTr.conj()], shape_kw='size') aflat = a.to_ndarray() b = npc.tensordot(a, a, axes=1) bflat = np.tensordot(aflat, aflat, axes=1) npt.assert_array_almost_equal_nulp(b.to_ndarray(), bflat, sum(a.shape))
def matvec(self, theta): theta = theta.split_legs(['(p.vR.vL)']) Lp = self.Lp Rp = self.Rp x = npc.tensordot(Lp, theta, axes=('vR', 'vL')) x = npc.tensordot(x, self.M, axes=(['p', 'wR'], ['p*', 'wL'])) x = npc.tensordot(x, Rp, axes=(['vR', 'wR'], ['vL', 'wL'])) x = x.transpose(['p', 'vR*', 'vL*']) x = x.iset_leg_labels(['p', 'vL', 'vR']) h = x.combine_legs(['p', 'vR', 'vL']) return h
def calculate_error_left_right(self, i): Lp = self.environment.get_LP(i) Rp = self.environment.get_RP(i) W = self.H_MPO.get_W(i) B = self.psi.get_B(i) p_h_phi = npc.tensordot(Lp, W, axes=['wR', 'wL']) p_h_phi = npc.tensordot(p_h_phi, Rp, axes=['wR', 'wL']) p_h_phi = npc.tensordot(p_h_phi, B, axes=[('p*', 'vR', 'vL'), ('p', 'vL', 'vR')]) npc.norm(p_h_phi)
def matvec(self, theta): theta = theta.split_legs(['(vL.p.vR)']) Lp = self.Lp Rp = self.Rp x = npc.tensordot(Lp, theta, axes=('vR', 'vL')) x = npc.tensordot(x, self.W, axes=(['p', 'wR'], ['p*', 'wL'])) x = npc.tensordot(x, Rp, axes=(['vR', 'wR'], ['vL', 'wL'])) #TODO:next line not needed. Since the transpose does not do anything, should not cost anything. Keep for safety ? x = x.transpose(['vR*', 'p', 'vL*']) x = x.iset_leg_labels(['vL', 'p', 'vR']) h = x.combine_legs(['vL', 'p', 'vR']) return h
def test_random_matrix_CUE(): for size in [1, 3, 4]: a = rmat.CUE((size, size)) print(a) assert (a.dtype == np.complex) npt.assert_allclose(np.dot(a, a.T.conj()), np.eye(size), EPS, EPS) b = npc.Array.from_func_square(rmat.CUE, leg) b.test_sanity() assert (b.dtype == np.complex) print("b =", b) id = npc.eye_like(b) assert (npc.norm(npc.tensordot(b, b.conj().itranspose(), axes=[1, 0]) - id) < EPS) assert (npc.norm(npc.tensordot(b.conj().itranspose(), b, axes=[1, 0]) - id) < EPS)
def matvec(self, theta): theta = theta.split_legs(['(vL.p0.p1.vR)']) Lp = self.Lp Rp = self.Rp x = npc.tensordot(Lp, theta, axes=('vR', 'vL')) x = npc.tensordot(x, self.H_MPO0, axes=(['p0', 'wR'], ['p*', 'wL'])) x.ireplace_label('p', 'p0') x = npc.tensordot(x, self.H_MPO1, axes=(['p1', 'wR'], ['p*', 'wL'])) x.ireplace_label('p', 'p1') x = npc.tensordot(x, Rp, axes=(['vR', 'wR'], ['vL', 'wL'])) x.ireplace_label('vL*', 'vR') x.ireplace_label('vR*', 'vL') h = x.combine_legs(['vL', 'p0', 'p1', 'vR']) return h
def __init__(self, model_params): model_params = asConfig(model_params, "AKLTModel") L = model_params.get('L', 2) site = SpinSite(S=1., conserve='Sz') # lattice bc_MPS = model_params.get('bc_MPS', 'finite') bc = 'open' if bc_MPS == 'finite' else 'periodic' lat = Chain(L, site, bc=bc, bc_MPS=bc_MPS) Sp, Sm, Sz = site.Sp, site.Sm, site.Sz S_dot_S = 0.5 * (kron(Sp, Sm) + kron(Sm, Sp)) + kron(Sz, Sz) S_dot_S_square = npc.tensordot(S_dot_S, S_dot_S, [['(p0*.p1*)'], ['(p0.p1)']]) H_bond = S_dot_S + S_dot_S_square / 3. # P_2 = H_bond * 0.5 + 1/3 * npc.eye_like(S_dot_S) J = model_params.get('J', 1.) H_bond = J * H_bond.split_legs().transpose(['p0', 'p1', 'p0*', 'p1*']) H_bond = [H_bond] * L # H_bond[i] acts on sites (i-1, i) if bc_MPS == "finite": H_bond[0] = None # 7) initialize H_bond (the order of 7/8 doesn't matter) NearestNeighborModel.__init__(self, lat, H_bond) # 9) initialize H_MPO MPOModel.__init__(self, lat, self.calc_H_MPO_from_bond())
def update_new_psi(self, theta): i0 = self.i0 new_psi = self.psi qtotal_i0 = new_psi.get_B(i0, form=None).qtotal U, S, VH, err, renormalize = svd_theta(theta, self.trunc_params, qtotal_LR=[qtotal_i0, None], inner_labels=['vR', 'vL']) self.renormalize.append(renormalize) # TODO: up to the `renormalize`, we could use `new_psi.set_svd_theta`. A0 = U.split_legs(['(vL.p0.q0)']) B1 = VH.split_legs(['(p1.q1.vR)']) # first compare to old best guess to check convergence of the sweeps if self._tol_theta_diff is not None and self.update_LP_RP[0] == False: theta_old = new_psi.get_theta(i0) theta_new_trunc = npc.tensordot(A0.scale_axis(S, 'vR'), B1, ['vR', 'vL']) ov = npc.inner(theta_new_trunc, theta_old, do_conj=True, axes='labels') theta_diff = 1. - abs(ov) self._theta_diff.append(theta_diff) A0.ireplace_labels(['p0', 'q0'], ['p', 'q']) B1.ireplace_labels(['p1', 'q1'], ['p', 'q']) new_psi.set_B(i0, A0, form='A') # left-canonical new_psi.set_B(i0 + 1, B1, form='B') # right-canonical new_psi.set_SR(i0, S) return {'U': U, 'VH': VH, 'err': err}
def test_site(): chinfo = npc.ChargeInfo([1, 3]) leg = gen_random_legcharge(chinfo, 8) op1 = npc.Array.from_func(np.random.random, [leg, leg.conj()], shape_kw='size') op2 = npc.Array.from_func(np.random.random, [leg, leg.conj()], shape_kw='size') labels = ['up'] + [None] * (leg.ind_len - 2) + ['down'] s = site.Site(leg, labels, silly_op=op1) assert s.state_index('up') == 0 assert s.state_index('down') == leg.ind_len - 1 assert s.opnames == set(['silly_op', 'Id', 'JW']) assert s.silly_op is op1 s.add_op('op2', op2) assert s.op2 is op2 assert s.get_op('op2') is op2 assert s.get_op('silly_op') is op1 npt.assert_equal( s.get_op('silly_op op2').to_ndarray(), npc.tensordot(op1, op2, [1, 0]).to_ndarray()) leg2 = npc.LegCharge.from_drop_charge(leg, 1) leg2 = npc.LegCharge.from_change_charge(leg2, 0, 2, 'changed') s2 = copy.deepcopy(s) s2.change_charge(leg2) perm_qind, leg2s = leg2.sort() perm_flat = leg2.perm_flat_from_perm_qind(perm_qind) s2s = copy.deepcopy(s2) s2s.change_charge(leg2s, perm_flat) for site_check in [s2, s2s]: print("site_check.leg = ", site_check.leg) for opn in site_check.opnames: op1 = s.get_op(opn).to_ndarray() op2 = site_check.get_op(opn).to_ndarray() perm = site_check.perm npt.assert_equal(op1[np.ix_(perm, perm)], op2)
def test_npc_inner(tol=1.e-13): for sort in [True, False]: print("sort =", sort) a = random_Array((10, 7, 5), chinfo3, sort=sort) a.iset_leg_labels(['x', 'y', 'z']) aflat = a.to_ndarray() b = npc.Array.from_func(np.random.random, a.legs, qtotal=a.qtotal, shape_kw='size') b.iset_leg_labels(['x', 'y', 'z']) b_conj = b.conj() b_conj_flat = b.to_ndarray() cflat = np.tensordot(aflat, b_conj_flat, axes=[[0, 1, 2], [0, 1, 2]]) c = npc.inner(a, b_conj, axes='range') # no transpose assert type(c) == np.dtype(float) assert (abs(c - cflat) < tol) c = npc.inner(a, b_conj, axes=[[0, 1, 2], [0, 1, 2]]) assert (abs(c - cflat) < tol) c = npc.inner(a, b, axes='range', do_conj=True) assert (abs(c - cflat) < tol) # now transpose b.itranspose([2, 1, 0]) b_conj.itranspose([2, 1, 0]) c = npc.inner(a, b_conj, axes=[[2, 0, 1], [0, 2, 1]]) # unordered axes! assert (abs(c - cflat) < tol) c = npc.inner(a, b_conj, axes='labels') assert (abs(c - cflat) < tol) c = npc.inner(a, b, axes='labels', do_conj=True) assert (abs(c - cflat) < tol) print("for trivial charge") a = npc.Array.from_func(np.random.random, [lcTr, lcTr.conj()], shape_kw='size') aflat = a.to_ndarray() b = npc.tensordot(a, a, axes=2) bflat = np.tensordot(aflat, aflat, axes=2) npt.assert_array_almost_equal_nulp(b, bflat, sum(a.shape))
def test_canonical_form(bc, method): psi = random_MPS(8, 2, 6, form=None, bc=bc) psi2 = psi.copy() norm = np.sqrt(psi2.overlap(psi2, ignore_form=True)) print("norm =", norm) psi2.norm /= norm # normalize psi2 norm2 = psi.overlap(psi2, ignore_form=True) print("norm2 =", norm2) assert abs(norm2 - norm) < 1.e-14 * norm meth = getattr(psi, method) meth(renormalize=False) # psi.canonical_form_[infinite[2]]() psi.test_sanity() assert abs(psi.norm - norm) < 1.e-14 * norm psi.norm = 1. # normalized psi ov = psi.overlap(psi2, ignore_form=True) print("normalized states: overlap <psi_canonical|psi> = 1.-", 1. - ov) assert abs(ov - 1.) < 1.e-14 print("norm_test") print(psi.norm_test()) assert np.max(psi.norm_test()) < 1.e-14 # SB = AS to good precision psi3 = psi.copy() # call canonical_form again, it shouldn't do anything now meth(renormalize=True) psi.test_sanity() ov = psi.overlap(psi3) assert abs(ov - 1.) < 1.e-14 if method in ['canonical_form_finite', 'canonical_form_infinite2']: # check that A = SB S^-1 is orthonormal for i in range(psi.L): A = psi.get_B(i, 'A') c = npc.tensordot(A, A.conj(), axes=[['vL', 'p'], ['vL*', 'p*']]) A_err = (c - npc.diag(1., c.legs[0])).norm() print(A_err) assert A_err < 1.e-13
def test_random_matrix_U_close_1(): for x in [0., 0.001]: for size in [1, 3, 4]: a = rmat.U_close_1((size, size), x) print(a) assert (a.dtype == np.complex) npt.assert_allclose(np.dot(a, a.T.conj()), np.eye(size), EPS, EPS) npt.assert_allclose(a, np.eye(size), 10 * x, 10 * x + EPS) # not exact for x=0! b = npc.Array.from_func_square(rmat.U_close_1, leg, func_args=[x]) b.test_sanity() assert (b.dtype == np.complex) print("b =", b) id = npc.eye_like(b) assert (npc.norm(npc.tensordot(b, b.conj().itranspose(), axes=[1, 0]) - id) < EPS) assert (npc.norm(npc.tensordot(b.conj().itranspose(), b, axes=[1, 0]) - id) < EPS) assert (npc.norm(b - id) <= 10 * x + EPS) # not exact for x=0!
def test_ExpMPOEvolution(bc_MPS, approximation, compression, g=1.5): # Test a time evolution against exact diagonalization for finite bc dt = 0.01 if bc_MPS == 'finite': L = 6 else: L = 2 model_pars = dict(L=L, Jx=0., Jy=0., Jz=-4., hx=2. * g, bc_MPS=bc_MPS, conserve=None) M = SpinChain(model_pars) state = ([[1 / np.sqrt(2), -1 / np.sqrt(2)]] * L ) # pointing in (-x)-direction state = ['up'] * L # pointing in (-z)-direction psi = MPS.from_product_state(M.lat.mps_sites(), state, bc=bc_MPS) options = { 'dt': dt, 'N_steps': 1, 'order': 1, 'approximation': approximation, 'compression_method': compression, 'trunc_params': { 'chi_max': 30 } } eng = mpo_evolution.ExpMPOEvolution(psi, M, options) if bc_MPS == 'finite': ED = exact_diag.ExactDiag(M) ED.build_full_H_from_mpo() ED.full_diagonalization() psiED = ED.mps_to_full(psi) psiED /= psiED.norm() UED = ED.exp_H(dt) for i in range(30): psi = eng.run() psiED = npc.tensordot(UED, psiED, ('ps*', [0])) psi_full = ED.mps_to_full(psi) assert (abs(abs(npc.inner(psiED, psi_full, [0, 0], True)) - 1) < dt) if bc_MPS == 'infinite': psiTEBD = psi.copy() TEBD_params = {'dt': dt, 'N_steps': 1} EngTEBD = tebd.Engine(psiTEBD, M, TEBD_params) for i in range(30): EngTEBD.run() psi = eng.run() print(psi.norm) print(np.abs(psi.overlap(psiTEBD) - 1)) #This test fails assert (abs(abs(psi.overlap(psiTEBD)) - 1) < 1e-2)
def sweep_right_left(self): """Performs the sweep right->left of the second order TDVP scheme with one site update. Evolve from 0.5*dt""" spectrum = [] spectrum.append(np.array([1])) expectation_O = [] for j in range(self.L - 1, -1, -1): B = self.psi.get_B(j, form='A') # Get theta if j == self.L - 1: theta = B else: theta = npc.tensordot( s, B, axes=('vL', 'vR')) #theta[vL,p,vR]=s[vL,vR]*self.psi[p,vL,vR] theta = theta.transpose([ 'p', 'vL', 'vR', ]) # Apply expm (-dt H) for 1-site chiB, chiA, d = theta.to_ndarray().shape Lp = self.environment.get_LP(j) Rp = self.environment.get_RP(j) W1 = self.environment.H.get_W(j) theta = self.update_theta_h1(Lp, Rp, theta, W1, -1j * 0.5 * self.dt) # SVD and update environment U, s, V = self.theta_svd_right_left(theta) spectrum.append(s / np.linalg.norm(s.to_ndarray())) self.psi.set_B(j, U, form='B') self._del_correct(j) if j > 0: # Apply expm (-dt H) for 0-site B = self.psi.get_B(j - 1, form='A') B_jm1 = npc.tensordot(V, B, axes=['vL', 'vR']) self.psi.set_B(j - 1, B_jm1, form='A') Lp = npc.tensordot(Lp, V, axes=['vR', 'vL']) Lp = npc.tensordot(Lp, V.conj(), axes=['vR*', 'vL*']) H = H0_mixed(Lp, self.environment.get_RP(j - 1)) s = self.update_s_h0(s, H, 1j * 0.5 * self.dt) s = s / np.linalg.norm(s.to_ndarray())
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 test_renyi_disentangler(L=4, eps=1.e-15): xxz_pars = dict(L=L, Jxx=1., Jz=3., hz=0., bc_MPS='finite') M = XXZChain(xxz_pars) psi = purification_mps.PurificationMPS.from_infiniteT(M.lat.mps_sites(), bc='finite') eng = PurificationTEBD(psi, M, {'verbose': 30, 'disentangle': 'renyi'}) theta = eng.psi.get_theta(1, 2) print(theta[0, :, :, 0, :, :]) # find random unitary: SVD of random matix pleg = psi.sites[0].leg pipe = npc.LegPipe([pleg, pleg]) A = npc.Array.from_func_square(rmat.CUE, pipe).split_legs() A.iset_leg_labels(['p0', 'p1', 'p0*', 'p1*']) # Now we have unitary `A`, i.e. the optimal `U` should be `A^dagger`. theta = npc.tensordot(A, theta, axes=[['p0*', 'p1*'], ['p0', 'p1']]) U0 = npc.outer( npc.eye_like(theta, 'q0').iset_leg_labels(['q0', 'q0*']), npc.eye_like(theta, 'q1').iset_leg_labels(['q1', 'q1*'])) U = U0 Sold = np.inf for i in range(20): S, U = eng.used_disentangler.iter(theta, U) if i == 0: S_0 = S print("iteration {i:d}: S={S:.5f}, DS={DS:.4e} ".format(i=i, S=S, DS=Sold - S)) if abs(Sold - S) < eps: print("break: S converged down to {eps:.1e}".format(eps=eps)) break Sold, S = S, Sold else: print("maximum number of iterations reached") theta = npc.tensordot(U, theta, axes=[['q0*', 'q1*'], ['q0', 'q1']]) print("new theta = ") print(theta.itranspose(['vL', 'vR', 'p0', 'q0', 'p1', 'q1'])) print(theta[0, 0]) assert (S < S_0) # this should always be true... if S > 100 * eps: print("final S =", S) warnings.warn("test of purification failed to find the optimum.")
def test_npc_outer(): for sort in [True, False]: print("sort =", sort) a = random_Array((6, 7), chinfo3, sort=sort) b = random_Array((5, 5), chinfo3, sort=sort) aflat = a.to_ndarray() bflat = b.to_ndarray() c = npc.outer(a, b) c.test_sanity() cflat = np.tensordot(aflat, bflat, axes=0) npt.assert_equal(c.to_ndarray(), cflat) c = npc.tensordot(a, b, axes=0) # (should as well call npc.outer) npt.assert_equal(c.to_ndarray(), cflat) print("for trivial charge") a = npc.Array.from_func(np.random.random, [lcTr, lcTr.conj()], shape_kw='size') aflat = a.to_ndarray() b = npc.tensordot(a, a, axes=0) bflat = np.tensordot(aflat, aflat, axes=0) npt.assert_array_almost_equal_nulp(b.to_ndarray(), bflat, sum(a.shape))
def test_qr(): for shape in [(4, 4), (6, 8), (8, 6)]: for qtotal in [None, [1]]: print("qtotal=", qtotal, "shape =", shape) A = random_Array(shape, chinfo3, qtotal=qtotal, sort=False) A_flat = A.to_ndarray() q, r = npc.qr(A, 'reduced') print(q._qdata) q.test_sanity() r.test_sanity() qr = npc.tensordot(q, r, axes=1) npt.assert_array_almost_equal_nulp(A_flat, qr.to_ndarray(), shape[0] * shape[1] * 100)
def check_hermitian(H): """Check if `H` is a hermitian MPO.""" if not H.finite: # include once over the boundary: double the unit cell # a general MPO might have terms going over multiple unit cells, but we ignore that... Ws = H._W * 2 else: Ws = H._W #check trace(H.H) = trace(H.H^dagger): equivalent to H=H^dagger W = Ws[0].take_slice([H.get_IdL(0)], ['wL']) trHH = npc.tensordot(W, W.replace_label('wR', 'wR*'), axes=[['p', 'p*'], ['p*', 'p']]) trHHd = npc.tensordot(W, W.conj(), axes=[['p', 'p*'], ['p*', 'p']]) for W in Ws[1:]: trHH = npc.tensordot(trHH, W, axes=['wR', 'wL']) trHHd = npc.tensordot(trHHd, W, axes=['wR', 'wL']) trHH = npc.tensordot(trHH, W.replace_label('wR', 'wR*'), axes=[['wR*', 'p', 'p*'], ['wL', 'p*', 'p']]) trHHd = npc.tensordot(trHHd, W.conj(), axes=[['wR*', 'p', 'p*'], ['wL*', 'p*', 'p']]) i = H.get_IdR(H.L - 1) trHH = trHH[i, i] trHHd = trHHd[i, i] print("check_hermitian: ", trHH, trHHd) npt.assert_array_almost_equal_nulp(trHH, trHHd, H.L * 20)
def sweep_left_right(self): """Performs the sweep left->right of the second order TDVP scheme with one site update. Evolve from 0.5*dt. """ for j in range(self.L): B = self.psi.get_B(j) # Get theta if j == 0: theta = B else: theta = npc.tensordot( B, s, axes=('vL', 'vR')) #theta[vL,p,vR]=s[vL,vR]*self.psi[p,vL,vR] Lp = self.environment.get_LP(j) Rp = self.environment.get_RP(j) W1 = self.environment.H.get_W(j) theta = self.update_theta_h1(Lp, Rp, theta, W1, -1j * 0.5 * self.dt) # SVD and update environment U, s, V = self.theta_svd_left_right(theta) self.psi.set_B(j, U, form='A') self.psi.set_SR(j, np.diag(s.to_ndarray())) self._del_correct(j) if j < self.L - 1: # Apply expm (-dt H) for 0-site B = self.psi.get_B(j + 1) B_jp1 = npc.tensordot(V, B, axes=['vR', 'vL']) self.psi.set_B(j + 1, B_jp1, form='B') Lpp = self.environment.get_LP(j + 1) Rp = npc.tensordot(Rp, V, axes=['vL', 'vR']) Rp = npc.tensordot(Rp, V.conj(), axes=['vL*', 'vR*']) H = H0_mixed(Lpp, Rp) s = self.update_s_h0(s, H, 1j * 0.5 * self.dt) s = s / np.linalg.norm(s.to_ndarray())