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)
E = env.full_contraction(L - 1) print("E =", E) print("5) calculate two-site hamiltonian ``H2`` from the MPO") # label left, right physical legs with p, q W0 = H.get_W(0).replace_labels(['p', 'p*'], ['p0', 'p0*']) W1 = H.get_W(1).replace_labels(['p', 'p*'], ['p1', 'p1*']) H2 = npc.tensordot(W0, W1, axes=('wR', 'wL')).itranspose(['wL', 'wR', 'p0', 'p1', 'p0*', 'p1*']) H2 = H2[H.IdL[0], H.IdR[2]] # (If H has single-site terms, it's not that simple anymore) print("H2 labels:", H2.get_leg_labels()) print("6) calculate exp(H2) by diagonalization of H2") # diagonalization requires to view H2 as a matrix H2 = H2.combine_legs([('p0', 'p1'), ('p0*', 'p1*')], qconj=[+1, -1]) print("labels after combine_legs:", H2.get_leg_labels()) E2, U2 = npc.eigh(H2) print("Eigenvalues of H2:", E2) U_expE2 = U2.scale_axis(np.exp(-1.j * dt * E2), axis=1) # scale_axis ~= apply a diagonal matrix exp_H2 = npc.tensordot(U_expE2, U2.conj(), axes=(1, 1)) exp_H2.iset_leg_labels(H2.get_leg_labels()) 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`) # alternative way: use :func:`~tenpy.linalg.np_conserved.expm` exp_H2_alternative = npc.expm(-1.j * dt * H2).split_legs() assert (npc.norm(exp_H2_alternative - exp_H2) < 1.e-14) 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) trunc_par = {'svd_min': cutoff, 'trunc_cut': None, 'verbose': 0} for even_odd in [0, 1]:
"""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]