def two_site_hamiltonian(coupling=1, ferro=True): """ returns the two site gate h = -ZZ - gX for ferro=True and h = ZZ - gX otherwise the gX term is symmetrised as 1/2 (1*Sx + Sx*1) Index convention p1* p2* ^ ^ | | |---------| | h | |---------| | | ^ ^ p1 p2 """ h = -npc.outer(Sz, Sz) sign = -1. if ferro else 1. h = h + sign * coupling * .5 * (npc.outer(Sx, S0) + npc.outer(S0, Sx)) h.iset_leg_labels(['p1*', 'p1', 'p2*', 'p2']) return h
def gen_disentangler_psi_prod(psiP, psiQ): """generate a PurificationMPS as tensorproduct (psi_P x psi_Q). psiQ should have the same `sites` as psiP.""" L = psiP.L Bs = [] for i in range(L): BP = psiP.get_B(i) BQ = psiQ.get_B(i) B2 = npc.outer(BP, BQ.conj()) B2 = B2.combine_legs([['vL', 'vL*'], ['vR', 'vR*']], qconj=[+1, -1]) B2.ireplace_labels(['(vL.vL*)', '(vR.vR*)', 'p*'], ['vL', 'vR', 'q']) Bs.append(B2) Ss = [np.outer(S, S2).flatten() for S, S2 in zip(psiP._S, psiQ._S)] return purification_mps.PurificationMPS(psiP.sites, Bs, Ss)
def test_expectation_value_multisite(): s = spin_half psi = mps.MPS.from_singlets(s, 6, [(0, 1), (2, 3), (4, 5)], lonely=[], bc='finite') SpSm = npc.outer(s.Sp.replace_labels(['p', 'p*'], ['p0', 'p0*']), s.Sm.replace_labels(['p', 'p*'], ['p1', 'p1*'])) psi1 = psi.copy() ev = psi.expectation_value(SpSm) npt.assert_almost_equal(ev, [-0.5, 0., -0.5, 0., -0.5]) env1 = mps.MPSEnvironment(psi1, psi) ev = env1.expectation_value(SpSm) npt.assert_almost_equal(ev, [-0.5, 0., -0.5, 0., -0.5]) psi1.apply_local_op(2, SpSm) # multi-site operator ev = psi1.expectation_value(SpSm) # normalized! npt.assert_almost_equal(ev, [-0.5, 0., 0.0, 0., -0.5]) env1 = mps.MPSEnvironment(psi1, psi) ev = env1.expectation_value(SpSm) / psi1.overlap(psi) # normalize npt.assert_almost_equal(ev, [-0.5, 0., -1., 0., -0.5])
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))
"""Explicit definition of charges and spin-1/2 operators.""" import tenpy.linalg.np_conserved as npc # consider spin-1/2 with Sz-conservation chinfo = npc.ChargeInfo([1]) # just a U(1) charge # charges for up, down state p_leg = npc.LegCharge.from_qflat(chinfo, [[1], [-1]]) Sz = npc.Array.from_ndarray([[0.5, 0.], [0., -0.5]], [p_leg, p_leg.conj()]) Sp = npc.Array.from_ndarray([[0., 1.], [0., 0.]], [p_leg, p_leg.conj()]) Sm = npc.Array.from_ndarray([[0., 0.], [1., 0.]], [p_leg, p_leg.conj()]) Hxy = 0.5 * (npc.outer(Sp, Sm) + npc.outer(Sm, Sp)) Hz = npc.outer(Sz, Sz) H = Hxy + Hz # here, H has 4 legs H.iset_leg_labels(["s1", "t1", "s2", "t2"]) H = H.combine_legs([["s1", "s2"], ["t1", "t2"]], qconj=[+1, -1]) # here, H has 2 legs print(H.legs[0].to_qflat().flatten()) # prints [-2 0 0 2] E, U = npc.eigh(H) # diagonalize blocks individually print(E) # [ 0.25 -0.75 0.25 0.25]