def rand_matrix_product_state(n, bond_dim, phys_dim=2, dtype=complex, cyclic=False, trans_invar=False): """Generate a random matrix product state (in dense form, see :func:`~quimb.tensor.MPS_rand_state` for tensor network form). Parameters ---------- n : int Number of sites. bond_dim : int Dimension of the bond (virtual) indices. phys_dim : int, optional Physical dimension of each local site, defaults to 2 (qubits). cyclic : bool (optional) Whether to impose cyclic boundary conditions on the entanglement structure. trans_invar : bool (optional) Whether to generate a translationally invariant state, requires cyclic=True. Returns ------- ket : qarray The random state, with shape (phys_dim**n, 1) """ from quimb.tensor import MPS_rand_state mps = MPS_rand_state(n, bond_dim, phys_dim=phys_dim, dtype=dtype, cyclic=cyclic, trans_invar=trans_invar) return mps.to_dense()
def test_apply_mps(self, cyclic, site_ind_id): A = MPO_rand(8, 5, cyclic=cyclic) x = MPS_rand_state(8, 4, site_ind_id=site_ind_id, cyclic=cyclic) y = A.apply(x) assert y.max_bond() == 20 assert isinstance(y, MatrixProductState) assert len(y.tensors) == 8 assert y.site_ind_id == site_ind_id Ad, xd, yd = A.to_dense(), x.to_dense(), y.to_dense() assert_allclose(Ad @ xd, yd)
def test_insert_operator(self): p = MPS_rand_state(3, 7, tags='KET') q = p.H.retag({'KET': 'BRA'}) qp = q & p sz = qu.spin_operator('z').real qp.insert_operator(sz, ('KET', 'I1'), ('BRA', 'I1'), tags='SZ', inplace=True) assert 'SZ' in qp.tags assert len(qp.tensors) == 7 x1 = qp ^ all x2 = qu.expec(p.to_dense(), qu.ikron(sz, [2, 2, 2], inds=1)) assert x1 == pytest.approx(x2)
def test_schmidt_values_entropy_gap_simple(self): n = 12 p = MPS_rand_state(n, 16) p.right_canonize() svns = [] sgs = [] for i in range(1, n): sgs.append(p.schmidt_gap(i, current_orthog_centre=i - 1)) svns.append(p.entropy(i, current_orthog_centre=i)) pd = p.to_dense() ex_svns = [entropy_subsys(pd, [2] * n, range(i)) for i in range(1, n)] ex_sgs = [schmidt_gap(pd, [2] * n, range(i)) for i in range(1, n)] assert_allclose(ex_svns, svns) assert_allclose(ex_sgs, sgs)
def test_partial_trace(self, rescale): n = 10 p = MPS_rand_state(n, 7) r = p.ptr(keep=[2, 3, 4, 6, 8], upper_ind_id='u{}', rescale_sites=rescale) rd = r.to_dense() if rescale: assert r.lower_inds == ('u0', 'u1', 'u2', 'u3', 'u4') assert r.upper_inds == ('k0', 'k1', 'k2', 'k3', 'k4') else: assert r.lower_inds == ('u2', 'u3', 'u4', 'u6', 'u8') assert r.upper_inds == ('k2', 'k3', 'k4', 'k6', 'k8') assert_allclose(r.trace(), 1.0) assert isherm(rd) pd = p.to_dense() rdd = pd.ptr([2] * n, keep=[2, 3, 4, 6, 8]) assert_allclose(rd, rdd)
def test_partial_trace(self, rescale, keep): n = 10 p = MPS_rand_state(n, 7) r = p.ptr(keep=keep, upper_ind_id='u{}', rescale_sites=rescale) rd = r.to_dense() if isinstance(keep, slice): keep = p.slice2sites(keep) else: if rescale: assert r.lower_inds == ('u0', 'u1', 'u2', 'u3', 'u4') assert r.upper_inds == ('k0', 'k1', 'k2', 'k3', 'k4') else: assert r.lower_inds == ('u2', 'u3', 'u4', 'u6', 'u8') assert r.upper_inds == ('k2', 'k3', 'k4', 'k6', 'k8') assert_allclose(r.trace(), 1.0) assert qu.isherm(rd) pd = p.to_dense() rdd = pd.ptr([2] * n, keep=keep) assert_allclose(rd, rdd)
def test_bipartite_schmidt_state(self): psi = MPS_rand_state(16, 5) psid = psi.to_dense() eln = qu.logneg(psid, [2**7, 2**9]) s_d_ket = psi.bipartite_schmidt_state(7, get='ket-dense') ln_d_ket = qu.logneg(s_d_ket, [5, 5]) assert_allclose(eln, ln_d_ket, rtol=1e-5) s_d_rho = psi.bipartite_schmidt_state(7, get='rho-dense') ln_d_rho = qu.logneg(s_d_rho, [5, 5]) assert_allclose(eln, ln_d_rho, rtol=1e-5) T_s_ket = psi.bipartite_schmidt_state(7, get='ket') assert set(T_s_ket.inds) == {'kA', 'kB'} assert_allclose(T_s_ket.H @ T_s_ket, 1.0) T_s_rho = psi.bipartite_schmidt_state(7, get='rho') assert set(T_s_rho.outer_inds()) == {'kA', 'kB', 'bA', 'bB'} assert_allclose(T_s_rho.H @ T_s_rho, 1.0)
def test_gate2split(self): psi = MPS_rand_state(10, 3) psi2 = psi.copy() G = qu.eye(2) & qu.eye(2) psi.gate2split(G, (2, 3), cutoff=0) assert psi.bond_size(2, 3) == 6 assert psi.H @ psi2 == pytest.approx(1.0) # check a unitary application G = qu.rand_uni(2**2) psi.gate2split(G, (7, 8)) psi.compress() assert psi.bond_size(2, 3) == 3 assert psi.bond_size(7, 8) > 3 assert psi.H @ psi == pytest.approx(1.0) assert abs(psi2.H @ psi) < 1.0 # check matches dense application of gate psid = psi2.to_dense() Gd = qu.ikron(G, [2] * 10, (7, 8)) assert psi.to_dense().H @ (Gd @ psid) == pytest.approx(1.0)
def test_entropy_matches_dense(self, method): p = MPS_rand_state(5, 32) p_dense = p.to_dense() real_svn = qu.entropy(p_dense.ptr([2] * 5, [0, 1, 2])) svn = (p ^ ...).entropy(('k0', 'k1', 'k2')) assert_allclose(real_svn, svn) # use tensor to left of bipartition p.canonize(2) t1 = p['I2'] left_inds = set(t1.inds) - set(p['I3'].inds) svn = (t1).entropy(left_inds, method=method) assert_allclose(real_svn, svn) # use tensor to right of bipartition p.canonize(3) t2 = p['I3'] left_inds = set(t2.inds) & set(p['I2'].inds) svn = (t2).entropy(left_inds, method=method) assert_allclose(real_svn, svn)