def test_split_tensor(self): # physical dimensions d0, d1 = 3, 5 # outer virtual bond dimensions D0, D2 = 14, 17 Apair = randn_complex((d0*d1, D0, D2)) / np.sqrt(d0*d1*D0*D2) # fictitious quantum numbers qd0 = np.random.randint(-2, 3, size=d0) qd1 = np.random.randint(-2, 3, size=d1) qD = [np.random.randint(-2, 3, size=D0), np.random.randint(-2, 3, size=D2)] # enforce block sparsity structure dictated by quantum numbers mask = ptn.qnumber_outer_sum([ptn.qnumber_flatten([qd0, qd1]), qD[0], -qD[1]]) Apair = np.where(mask == 0, Apair, 0) for svd_distr in ['left', 'right', 'sqrt']: (A0, A1, qbond) = ptn.split_MPS_tensor(Apair, qd0, qd1, qD, svd_distr=svd_distr, tol=0) self.assertTrue(ptn.is_qsparse(A0, [qd0, qD[0], -qbond]), msg='sparsity pattern of A0 tensors must match quantum numbers') self.assertTrue(ptn.is_qsparse(A1, [qd1, qbond, -qD[1]]), msg='sparsity pattern of A1 tensors must match quantum numbers') # merged tensor must agree with the original tensor Amrg = ptn.merge_MPS_tensor_pair(A0, A1) self.assertAlmostEqual(np.linalg.norm(Amrg - Apair), 0., delta=1e-13, msg='splitting and subsequent merging must give the same tensor')
def cast_to_MPS(mpo): """ Cast a matrix product operator into MPS form by combining the pair of local physical dimensions into one dimension. """ mps = ptn.MPS(ptn.qnumber_flatten([mpo.qd, -mpo.qd]), mpo.qD, fill=0.0) for i in range(mpo.nsites): s = mpo.A[i].shape mps.A[i] = mpo.A[i].reshape((s[0] * s[1], s[2], s[3])).copy() assert ptn.is_qsparse(mps.A[i], [mps.qd, mps.qD[i], -mps.qD[i + 1]]) return mps
def cast_to_MPO(mps, qd): """ Cast a matrix product state into MPO form by interpreting the physical dimension as Kronecker product of a pair of dimensions. """ assert np.array_equal(mps.qd, ptn.qnumber_flatten([qd, -qd])) mpo = ptn.MPO(qd, mps.qD, fill=0.0) for i in range(mps.nsites): s = mps.A[i].shape mpo.A[i] = mps.A[i].reshape((len(qd), len(qd), s[1], s[2])).copy() assert ptn.is_qsparse(mpo.A[i], [mpo.qd, -mpo.qd, mpo.qD[i], -mpo.qD[i + 1]]) return mpo
def heisenberg_XXZ_comm_MPO(L, J, D, h): """Construct commutator with XXZ Heisenberg Hamiltonian 'sum J X X + J Y Y + D Z Z - h Z' on a 1D lattice as MPO.""" # physical quantum numbers (multiplied by 2) qd = np.array([1, -1]) # spin operators Sup = np.array([[0., 1.], [0., 0.]]) Sdn = np.array([[0., 0.], [1., 0.]]) Sz = np.array([[0.5, 0.], [0., -0.5]]) # local two-site and single-site terms lopchains = [ ptn.OpChain([0.5 * J * Sup, Sdn], [2]), ptn.OpChain([0.5 * J * Sdn, Sup], [-2]), ptn.OpChain([D * Sz, Sz], [0]), ptn.OpChain([-h * Sz], []) ] # convert to MPO form, with local terms acting either on first or second physical dimension locopchains = [] for opchain in lopchains: locopchains += construct_comm_opchain(opchain) return ptn.local_opchains_to_MPO(ptn.qnumber_flatten([qd, -qd]), L, locopchains)