def test_inner_prod_mps(nr_sites, local_dim, rank, dtype, rgen): mpa1 = factory.random_mpa(nr_sites, local_dim, 1, dtype=dtype, randstate=rgen, normalized=True) mpa2 = factory.random_mpa(nr_sites, local_dim, rank, dtype=dtype, randstate=rgen, normalized=True) res_slow = mp.inner(mpa1, mpa2) res_fast = mpsp.inner_prod_mps(mpa1, mpa2) assert_almost_equal(res_slow, res_fast) try: mpsp.inner_prod_mps(mpa2, mpa1) except AssertionError: pass else: if rank > 1: raise AssertionError( "inner_prod_mps should only accept r=1 in first argument") mpa1 = factory.random_mpo(nr_sites, local_dim, 1) try: mpsp.inner_prod_mps(mpa1, mpa1) except AssertionError: pass else: raise AssertionError("inner_prod_mps should only accept ndims=1")
def test_inner_slow(nr_sites, local_dim, rank, benchmark, rgen): mpa1 = factory.random_mpa(nr_sites, local_dim, 1, dtype=np.float_, randstate=rgen) mpa2 = factory.random_mpa(nr_sites, local_dim, rank, dtype=np.float_, randstate=rgen) benchmark(mp.inner, mpa1, mpa2)
def test_inner_fast(nr_sites, local_dim, rank, benchmark, rgen): mpa1 = factory.random_mpa(nr_sites, local_dim, 1, dtype=np.float_, randstate=rgen, normalized=True) mpa2 = factory.random_mpa(nr_sites, local_dim, rank, dtype=np.float_, randstate=rgen, normalized=True) benchmark(mpsp.inner_prod_mps, mpa1, mpa2)
def test_mpo_to_pmps(nr_sites, local_dim, rgen): pmps = factory.random_mpa(nr_sites, (local_dim, local_dim), 1, dtype=np.complex_, randstate=rgen) assert_almost_equal(mp.normdist(mm.mpo_to_pmps(mm.pmps_to_mpo(pmps)), pmps), 0) mpo = factory.random_mpa(nr_sites, (local_dim, local_dim), 1, dtype=np.complex_, randstate=rgen, normalized=True) assert_almost_equal(mp.normdist(mm.pmps_to_mpo(mm.mpo_to_pmps(mpo)), mpo), 0)
def test_eig_sum(nr_sites, local_dim, rank, rgen): # Need at least three sites for var_sites = 2 if nr_sites < 3: pt.skip("Nothing to test") return rank = max(1, rank // 2) mpo = factory.random_mpo(nr_sites, local_dim, rank, randstate=rgen, hermitian=True, normalized=True) mpo.canonicalize() mps = factory.random_mpa(nr_sites, local_dim, rank, randstate=rgen, dtype=np.complex_, normalized=True) mpas = [mpo, mps] vec = mps.to_array().ravel() op = mpo.to_array_global().reshape((local_dim**nr_sites,) * 2) op += np.outer(vec, vec.conj()) eigvals, eigvec = np.linalg.eigh(op) # Eigenvals should be real for a hermitian matrix assert (np.abs(eigvals.imag) < 1e-10).all(), str(eigvals.imag) mineig_pos = eigvals.argmin() mineig, mineig_eigvec = eigvals[mineig_pos], eigvec[:, mineig_pos] mineig_mp, mineig_eigvec_mp = mp.eig_sum( mpas, num_sweeps=5, startvec_rank=5 * rank, randstate=rgen, eigs=ft.partial(eigsh, k=1, which='SA', tol=1e-6), var_sites=2) mineig_eigvec_mp = mineig_eigvec_mp.to_array().flatten() overlap = np.inner(mineig_eigvec.conj(), mineig_eigvec_mp) assert_almost_equal(mineig_mp, mineig) assert_almost_equal(abs(overlap), 1)
def test_sumup(nr_sites, local_dim, rank, rgen): rank = rank if rank is not np.nan else 1 mpas = [ factory.random_mpa(nr_sites, local_dim, 1, dtype=np.float_, randstate=rgen) for _ in range(10 * rank) ] weights = rgen.randn(len(mpas)) # parameters chosen such that only one round of compression occurs summed_fast = mpsp.sumup(mpas, rank, weights=weights, svdfunc=truncated_svd) # summed_slow = mp.sumup(mpa * w for mpa, w in zip(mpas, weights)) summed_slow = mp.sumup(mpas, weights=weights) summed_slow.compress('svd', rank=rank, direction='right', canonicalize=False) assert_mpa_identical(summed_fast, summed_slow) try: mpsp.sumup(mpas, rank, weights=np.ones(rank)) except AssertionError: pass else: raise AssertionError("sumup did not catch unbalanced arguments")
def test_reductions_pmps(nr_sites, local_dim, rank, max_red_width, rgen): pmps = factory.random_mpa(nr_sites, (local_dim, local_dim), rank, dtype=np.complex_, randstate=rgen) op = mm.pmps_to_mpo(pmps).to_array_global() start, stop, red = _get_reductions(mm.reductions_pmps, pmps, max_red_width) for start, stop, reduced_pmps in zip(start, stop, red): # Check that startsites/stopsites and width produce the same result: reduced_pmps2 = tuple(mm.reductions_pmps(pmps, stop - start))[start] # NB: reduced_pmps and reduced_pmps2 are in general not equal, # but red and red2 are. red = mm.pmps_to_mpo(reduced_pmps).to_array_global() red2 = mm.pmps_to_mpo(reduced_pmps2).to_array_global() assert_array_almost_equal(red, red2) traceout = tuple(range(start)) + tuple(range(stop, nr_sites)) red_from_op = utils.partial_trace(op, traceout) assert_array_almost_equal(red, red_from_op, err_msg="not equal at {}:{}".format( start, stop)) # check default argument for startsite assert len(list(mm.reductions_pmps(pmps, max_red_width))) \ == nr_sites - max_red_width + 1
def test_mppovm_pmf_as_array_pmps_benchmark( nr_sites, local_dim, rank, startsite, width, impl, rgen, benchmark): pauli_y = povm.pauli_parts(local_dim)[1] mpp_y = povm.MPPovm.from_local_povm(pauli_y, width) \ .embed(nr_sites, startsite, local_dim) pmps = factory.random_mpa(nr_sites, (local_dim, local_dim), rank, dtype=np.complex_, randstate=rgen, normalized=True) benchmark(lambda: mpp_y.pmf_as_array(pmps, 'pmps', impl=impl))
def test_pmps_reduction_array_fast(nr_sites, local_dim, rank, keep, rgen, benchmark): pmps = factory.random_mpa(nr_sites, (local_dim, local_dim), rank, dtype=np.complex_, normalized=True, randstate=rgen) benchmark(lambda: mm.pmps_dm_to_array(mm.pmps_reduction(pmps, keep)))
def test_pmps_dm_to_array_slow(nr_sites, local_dim, rank, rgen, benchmark): pmps = factory.random_mpa(nr_sites, (local_dim, local_dim), rank, dtype=np.complex_, normalized=True, randstate=rgen) benchmark(lambda x: mm.pmps_to_mpo(pmps).to_array(), pmps)
def test_pmps_dm_to_array_fast(nr_sites, local_dim, rank, rgen, benchmark): pmps = factory.random_mpa(nr_sites, (local_dim, local_dim), rank, dtype=np.complex_, normalized=True, randstate=rgen) benchmark(mm.pmps_dm_to_array, pmps)
def test_pmps_reduction_array_slow_prune( nr_sites, local_dim, rank, keep, rgen, benchmark): pmps = factory.random_mpa(nr_sites, (local_dim, local_dim), rank, dtype=np.complex_, normalized=True, randstate=rgen) benchmark( lambda: mp.prune(mm.pmps_to_mpo(mm.pmps_reduction(pmps, keep)), singletons=True).to_array() )
def test_pmps_reduction_array_slow_noprune( nr_sites, local_dim, rank, keep, rgen, benchmark): pmps = factory.random_mpa(nr_sites, (local_dim, local_dim), rank, dtype=np.complex_, normalized=True, randstate=rgen) # NB: The maximal distance between sites of the reduction is # limited by the fact that normal numpy builds support arrays with # at most 32 indices. benchmark(lambda: mm.pmps_to_mpo(mm.pmps_reduction(pmps, keep)).to_array())
def test_iter_readonly(): mpa = factory.random_mpa(4, 2, 1) ltens = next(iter(mpa.lt)) try: ltens[0] = 0 except ValueError: pass else: raise AssertionError("Iterator over ltens should be read only")
def test_pmps_reduction_dm_to_array(nr_sites, local_dim, rank, keep, rgen): pmps = factory.random_mpa(nr_sites, (local_dim, local_dim), rank, dtype=np.complex_, randstate=rgen) rho = mm.pmps_to_mpo(pmps).to_array_global() traceout = [pos for pos in range(nr_sites) if pos not in keep] red = utils.partial_trace(rho, traceout) pmps_red = mm.pmps_reduction(pmps, keep) red2 = mm.pmps_dm_to_array(pmps_red, True) assert_array_almost_equal(red2, red)
def test_update_normalization(mpa_norm, upd_pos, upd_norm, rgen, n_sites=UPDATE_N_SITES): """Verify normalization after local tensor update We test two things: 1. The normalization info after update is what we expect (in some special cases, see `norm_expected`) 2. The normalization info is actually correct (in all cases) """ n_sites = UPDATE_N_SITES ldim = 4 rank = 3 mpa = factory.random_mpa(n_sites, ldim, rank, rgen) assert_correct_normalization(mpa, 0, n_sites) mpa.canonicalize(*mpa_norm) assert_correct_normalization(mpa, *mpa_norm) dims = mpa.lt.shape[upd_pos] tensor = factory._zrandn(dims, rgen) if upd_norm == 'left': tensor = tensor.reshape((-1, dims[-1])) tensor, _ = np.linalg.qr(tensor) tensor = tensor.reshape(dims) elif upd_norm == 'right': tensor = tensor.reshape((dims[0], -1)).T tensor, _ = np.linalg.qr(tensor) tensor = tensor.T.reshape(dims) norm_expected = { # Replacing in unnormalized tensor (0, n_sites, 0, None): (0, 4), (0, n_sites, 3, None): (0, 4), # Replacing in left-normalized part with unnormalized tensor (3, n_sites, 3, 'left'): (3, 4), (3, n_sites, 0, 'left'): (0, 4), # Replacing in right-normalized part with unnormalized tensor (0, 1, 0, None): (0, 1), (0, 1, 3, None): (0, 4), # Replacing in left-normalized part with normalized tensor (3, 4, 2, 'left'): (3, 4), (3, 4, 2, 'right'): (2, 4), # Replacing in right-normalized part with normalized tensor (0, 1, 2, 'right'): (0, 1), (0, 1, 2, 'left'): (0, 3), } expected = norm_expected.get((mpa_norm[0], mpa_norm[1], upd_pos, upd_norm), ()) mpa.lt.update(upd_pos, tensor, upd_norm) assert_correct_normalization(mpa, *expected)
def test_pmps_dm_to_array(nr_sites, local_dim, rank, rgen): pmps = factory.random_mpa(nr_sites, (local_dim, local_dim), rank, randstate=rgen, dtype=np.complex_) mpo = mm.pmps_to_mpo(pmps) op = mpo.to_array() op2 = mm.pmps_dm_to_array(pmps) assert_array_almost_equal(op2, op) op = mpo.to_array_global() op2 = mm.pmps_dm_to_array(pmps, True) assert_array_almost_equal(op2, op)
def test_local_add_sparse(nr_sites, local_dim, rank, dtype, rgen): # Just get some random number of summands, these parameters arent used # anyway later on nr_summands = nr_sites if rank is np.nan else nr_sites * rank summands = [factory.random_mpa(1, local_dim, 1, dtype=dtype, randstate=rgen).lt[0] for _ in range(nr_summands)] sum_slow = mp._local_add(summands).reshape((nr_summands, nr_summands * local_dim)) sum_fast = mpsp._local_add_sparse([s.ravel() for s in summands]).toarray() \ assert_array_almost_equal(sum_slow, sum_fast)
def test_mppovm_expectation_pmps(nr_sites, width, local_dim, rank, rgen): paulis = povm.pauli_povm(local_dim) mppaulis = povm.MPPovm.from_local_povm(paulis, width) pmps = factory.random_mpa(nr_sites, (local_dim, local_dim), rank, dtype=np.complex_, randstate=rgen) rho = mpsmpo.pmps_to_mpo(pmps) expect_psi = list(mppaulis.expectations(pmps, mode='pmps')) expect_rho = list(mppaulis.expectations(rho)) assert len(expect_psi) == len(expect_rho) for e_rho, e_psi in zip(expect_rho, expect_psi): assert_array_almost_equal(e_rho.to_array(), e_psi.to_array())
def test_eig_sum_benchmark( nr_sites, local_dim, rank, ev_rank, rgen, benchmark): mpo = factory.random_mpo(nr_sites, local_dim, rank, randstate=rgen, hermitian=True, normalized=True) mpo.canonicalize() mps = factory.random_mpa(nr_sites, local_dim, rank, randstate=rgen, dtype=np.complex_, normalized=True) benchmark( mp.eig_sum, [mpo, mps], startvec_rank=ev_rank, randstate=rgen, var_sites=1, num_sweeps=1, )
def test_local_add_sparse(nr_sites, local_dim, rank, dtype, rgen): # Just get some random number of summands, these parameters arent used # anyway later on nr_summands = nr_sites if rank is np.nan else nr_sites * rank summands = [ factory.random_mpa(1, local_dim, 1, dtype=dtype, randstate=rgen).lt[0] for _ in range(nr_summands) ] sum_slow = mp._local_add(summands).reshape( (nr_summands, nr_summands * local_dim)) sum_fast = mpsp._local_add_sparse([s.ravel() for s in summands]).toarray() \ assert_array_almost_equal(sum_slow, sum_fast)
def test_eig_sum(nr_sites, local_dim, rank, rgen): # Need at least three sites for var_sites = 2 if nr_sites < 3: pt.skip("Nothing to test") return rank = max(1, rank // 2) mpo = factory.random_mpo(nr_sites, local_dim, rank, randstate=rgen, hermitian=True, normalized=True) mpo.canonicalize() mps = factory.random_mpa(nr_sites, local_dim, rank, randstate=rgen, dtype=np.complex_, normalized=True) mpas = [mpo, mps] vec = mps.to_array().ravel() op = mpo.to_array_global().reshape((local_dim**nr_sites, ) * 2) op += np.outer(vec, vec.conj()) eigvals, eigvec = np.linalg.eigh(op) # Eigenvals should be real for a hermitian matrix assert (np.abs(eigvals.imag) < 1e-10).all(), str(eigvals.imag) mineig_pos = eigvals.argmin() mineig, mineig_eigvec = eigvals[mineig_pos], eigvec[:, mineig_pos] mineig_mp, mineig_eigvec_mp = mp.eig_sum(mpas, num_sweeps=5, startvec_rank=5 * rank, randstate=rgen, eigs=ft.partial(eigsh, k=1, which='SA', tol=1e-6), var_sites=2) mineig_eigvec_mp = mineig_eigvec_mp.to_array().flatten() overlap = np.inner(mineig_eigvec.conj(), mineig_eigvec_mp) assert_almost_equal(mineig_mp, mineig) assert_almost_equal(abs(overlap), 1)
def test_pmps_to_mpo(nr_sites, local_dim, rank, rgen): if (nr_sites % 2) != 0: return nr_sites = nr_sites // 2 pmps = factory.random_mpa(nr_sites, (local_dim, local_dim), rank, dtype=np.complex_, randstate=rgen) rho_mp = mm.pmps_to_mpo(pmps).to_array_global() # Local form is what we will use: One system site, one ancilla site, etc purification = pmps.to_array() # Convert to a density matrix purification = np.outer(purification, purification.conj()) purification = purification.reshape((local_dim,) * (2 * 2 * nr_sites)) # Trace out the ancilla sites traceout = tuple(range(1, 2 * nr_sites, 2)) rho_np = utils.partial_trace(purification, traceout) # Here, we need global form assert_array_almost_equal(rho_mp, rho_np)
def test_povm_ic_mpa(nr_sites, local_dim, rank, rgen): # Check that the tensor product of the PauliGen POVM is IC. paulis = povm.pauli_povm(local_dim) inv_map = mp_from_array_repeat(paulis.linear_inversion_map, nr_sites) probab_map = mp_from_array_repeat(paulis.probability_map, nr_sites) reconstruction_map = mp.dot(inv_map, probab_map) eye = factory.eye(nr_sites, local_dim**2) assert mp.norm(reconstruction_map - eye) < 1e-5 # Check linear inversion for a particular example MPA. # Linear inversion works for arbitrary matrices, not only for states, # so we test it for an arbitrary MPA. # Normalize, otherwise the absolute error check below will not work. mpa = factory.random_mpa(nr_sites, local_dim**2, rank, dtype=np.complex_, randstate=rgen, normalized=True) probabs = mp.dot(probab_map, mpa) recons = mp.dot(inv_map, probabs) assert mp.norm(recons - mpa) < 1e-6
def test_mppovm_pmf_as_array_pmps( nr_sites, local_dim, rank, startsite, width, rgen): if hasattr(local_dim, '__len__'): pdims = [d for d, _ in local_dim] mppaulis = mp.chain( povm.MPPovm.from_local_povm(povm.pauli_povm(d), 1) for d in pdims[startsite:startsite + width] ) else: pdims = local_dim local_dim = (local_dim, local_dim) mppaulis = povm.MPPovm.from_local_povm(povm.pauli_povm(pdims), width) mppaulis = mppaulis.embed(nr_sites, startsite, pdims) pmps = factory.random_mpa(nr_sites, local_dim, rank, dtype=np.complex_, randstate=rgen, normalized=True) rho = mpsmpo.pmps_to_mpo(pmps) expect_rho = mppaulis.pmf_as_array(rho, 'mpdo') for impl in ['default', 'pmps-ltr', 'pmps-symm']: expect_pmps = mppaulis.pmf_as_array(pmps, 'pmps', impl=impl) assert_array_almost_equal(expect_rho, expect_pmps, err_msg=impl)
def test_getitem(): ltens = factory.random_mpa(10, 2, 1).lt assert isinstance(ltens[0], np.ndarray) try: ltens[0][0] = 0 except ValueError: pass else: raise AssertionError("Getitem should be read only") rest = list(ltens[1:]) assert len(rest) == 9 for n, lt in enumerate(rest): assert_array_equal(lt, ltens[1 + n]) try: lt[0] = 0 except ValueError: pass else: raise AssertionError("Getitem slice over ltens should be read only")
def test_sumup(nr_sites, local_dim, rank, rgen): rank = rank if rank is not np.nan else 1 mpas = [factory.random_mpa(nr_sites, local_dim, 1, dtype=np.float_, randstate=rgen) for _ in range(10 * rank)] weights = rgen.randn(len(mpas)) # parameters chosen such that only one round of compression occurs summed_fast = mpsp.sumup(mpas, rank, weights=weights, svdfunc=truncated_svd) # summed_slow = mp.sumup(mpa * w for mpa, w in zip(mpas, weights)) summed_slow = mp.sumup(mpas, weights=weights) summed_slow.compress('svd', rank=rank, direction='right', canonicalize=False) assert_mpa_identical(summed_fast, summed_slow) try: mpsp.sumup(mpas, rank, weights=np.ones(rank)) except AssertionError: pass else: raise AssertionError("sumup did not catch unbalanced arguments")
def test_getitem(): ltens = factory.random_mpa(10, 2, 1).lt assert isinstance(ltens[0], np.ndarray) try: ltens[0][0] = 0 except ValueError: pass else: raise AssertionError("Getitem should be read only") rest = list(ltens[1:]) assert len(rest) == 9 for n, lt in enumerate(rest): assert_array_equal(lt, ltens[1 + n]) try: lt[0] = 0 except ValueError: pass else: raise AssertionError( "Getitem slice over ltens should be read only")
def test_reductions_pmps(nr_sites, local_dim, rank, max_red_width, rgen): pmps = factory.random_mpa(nr_sites, (local_dim, local_dim), rank, dtype=np.complex_, randstate=rgen) op = mm.pmps_to_mpo(pmps).to_array_global() start, stop, red = _get_reductions(mm.reductions_pmps, pmps, max_red_width) for start, stop, reduced_pmps in zip(start, stop, red): # Check that startsites/stopsites and width produce the same result: reduced_pmps2 = tuple(mm.reductions_pmps(pmps, stop - start))[start] # NB: reduced_pmps and reduced_pmps2 are in general not equal, # but red and red2 are. red = mm.pmps_to_mpo(reduced_pmps).to_array_global() red2 = mm.pmps_to_mpo(reduced_pmps2).to_array_global() assert_array_almost_equal(red, red2) traceout = tuple(range(start)) + tuple(range(stop, nr_sites)) red_from_op = utils.partial_trace(op, traceout) assert_array_almost_equal( red, red_from_op, err_msg="not equal at {}:{}".format(start, stop)) # check default argument for startsite assert len(list(mm.reductions_pmps(pmps, max_red_width))) \ == nr_sites - max_red_width + 1
def test_eig_sum_benchmark(nr_sites, local_dim, rank, ev_rank, rgen, benchmark): mpo = factory.random_mpo(nr_sites, local_dim, rank, randstate=rgen, hermitian=True, normalized=True) mpo.canonicalize() mps = factory.random_mpa(nr_sites, local_dim, rank, randstate=rgen, dtype=np.complex_, normalized=True) benchmark( mp.eig_sum, [mpo, mps], startvec_rank=ev_rank, randstate=rgen, var_sites=1, num_sweeps=1, )