Esempio n. 1
0
def test_mppovm_sample(
        method, n_samples, nr_sites, startsite, local_dim, rgen):
    """Check that probability estimates from samples are reasonable accurate"""
    rank = 3
    eps = 1e-10
    mps = factory.random_mps(nr_sites, local_dim, rank, rgen)
    mps.canonicalize()

    local_x = povm.x_povm(local_dim)
    local_y = povm.y_povm(local_dim)
    xx = povm.MPPovm.from_local_povm(local_x, 2)
    y = povm.MPPovm.from_local_povm(local_y, 1)
    mpp = mp.chain([xx, povm.MPPovm.eye([local_dim]), y]) \
            .embed(nr_sites, startsite, local_dim)

    pmf_exact = mpp.pmf_as_array(mps, 'mps', eps)

    if n_samples > 100:
        n_gr = 5
    elif local_dim == 3:
        n_gr = 2
    else:
        n_gr = 3
    samples = mpp.sample(rgen, mps, n_samples, method, n_gr, 'mps', eps=eps)

    pmf_est = mpp.est_pmf(samples)

    assert abs(pmf_est.sum() - 1.0) <= eps
    assert abs(pmf_exact - pmf_est).max() <= 3 / n_samples**0.5
Esempio n. 2
0
def test_reductions_mps(nr_sites, local_dim, rank, width, rgen):
    mps = factory.random_mps(nr_sites, local_dim, rank, randstate=rgen)
    mpo = mp.localouter(mps, mps.conj())

    pmps_reds = mm.reductions_mps_as_mpo(mps, width)
    mpo_reds = mm.reductions_mpo(mpo, width)

    for red1, red2 in zip(pmps_reds, mpo_reds):
        assert_array_almost_equal(red1.to_array(), red2.to_array())
Esempio n. 3
0
def test_reductions_mps(nr_sites, local_dim, rank, width, rgen):
    mps = factory.random_mps(nr_sites, local_dim, rank, randstate=rgen)
    mpo = mp.localouter(mps, mps.conj())

    pmps_reds = mm.reductions_mps_as_mpo(mps, width)
    mpo_reds = mm.reductions_mpo(mpo, width)

    for red1, red2 in zip(pmps_reds, mpo_reds):
        assert_array_almost_equal(red1.to_array(), red2.to_array())
Esempio n. 4
0
def test_mppovm_expectation_pure(nr_sites, width, local_dim, rank, rgen):
    paulis = povm.pauli_povm(local_dim)
    mppaulis = povm.MPPovm.from_local_povm(paulis, width)
    psi = factory.random_mps(nr_sites, local_dim, rank, randstate=rgen)
    rho = mpsmpo.mps_to_mpo(psi)
    expect_psi = list(mppaulis.expectations(psi))
    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())
Esempio n. 5
0
def test_mps_to_mpo(nr_sites, local_dim, rank, rgen):
    mps = factory.random_mps(nr_sites, local_dim, rank, randstate=rgen)
    # Instead of calling the two functions, we call mps_to_mpo(),
    # which does exactly that:
    #   mps_as_puri = mp.mps_as_local_purification_mps(mps)
    #   mpo = mp.pmps_to_mpo(mps_as_puri)
    mpo = mm.mps_to_mpo(mps)
    # This is also a test of mp.mps_as_local_purification_mps() in the
    # following sense: Local purifications are representations of
    # mixed states. Therefore, compare mps and mps_as_puri by
    # converting them to mixed states.
    state = mps.to_array()
    state = np.outer(state, state.conj())
    state.shape = (local_dim,) * (2 * nr_sites)
    state2 = mpo.to_array_global()
    assert_array_almost_equal(state, state2)
Esempio n. 6
0
def test_mps_to_mpo(nr_sites, local_dim, rank, rgen):
    mps = factory.random_mps(nr_sites, local_dim, rank, randstate=rgen)
    # Instead of calling the two functions, we call mps_to_mpo(),
    # which does exactly that:
    #   mps_as_puri = mp.mps_as_local_purification_mps(mps)
    #   mpo = mp.pmps_to_mpo(mps_as_puri)
    mpo = mm.mps_to_mpo(mps)
    # This is also a test of mp.mps_as_local_purification_mps() in the
    # following sense: Local purifications are representations of
    # mixed states. Therefore, compare mps and mps_as_puri by
    # converting them to mixed states.
    state = mps.to_array()
    state = np.outer(state, state.conj())
    state.shape = (local_dim,) * (2 * nr_sites)
    state2 = mpo.to_array_global()
    assert_array_almost_equal(state, state2)
Esempio n. 7
0
def test_mppovmlist_pack_unpack_samples(
        method, n_samples, nr_sites, local_dim, rank, measure_width,
        rgen, eps=1e-10):
    """Check that packing and unpacking samples does not change them"""

    mps = factory.random_mps(nr_sites, local_dim, rank, rgen)
    mps.canonicalize()

    s_povm = povm.pauli_mpp(measure_width, local_dim).block(nr_sites)
    samples = tuple(s_povm.sample(
        rgen, mps, n_samples, method, mode='mps', pack=False, eps=eps))
    packed = tuple(s_povm.pack_samples(samples))
    unpacked = tuple(s_povm.unpack_samples(packed))

    assert all(s.dtype == np.uint8 for s in samples)
    assert all(s.dtype == np.uint8 for s in unpacked)
    assert all((s == u).all() for s, u in zip(samples, unpacked))
Esempio n. 8
0
def test_mppovm_est_pmf_from(
        method, n_samples, nr_sites, startsite, local_dim, rgen):
    """Check that probability estimates from samples are reasonable accurate"""
    rank = 3
    eps = 1e-10
    mps = factory.random_mps(nr_sites, local_dim, rank, rgen)
    mps.canonicalize()

    lx = povm.x_povm(local_dim)
    ly = povm.y_povm(local_dim)
    lp = povm.pauli_povm(local_dim)
    x = povm.MPPovm.from_local_povm(lx, 1)
    y = povm.MPPovm.from_local_povm(ly, 1)
    pauli = povm.MPPovm.from_local_povm(lp, 1)
    xy = mp.chain((x, y))
    mpp = mp.chain((xy,) * (nr_sites // 2))
    if (nr_sites % 2) == 1:
        mpp = mp.chain((mpp, x))
    small_mpp = mp.chain((pauli, povm.MPPovm.eye([local_dim]), pauli, pauli)) \
                  .embed(nr_sites, startsite, local_dim)

    x_given = np.arange(len(lp)) < len(lx)
    y_given = ((np.arange(len(lp)) >= len(lx))
               & (np.arange(len(lp)) < len(lx) + len(ly)))
    given_sites = [x_given if ((startsite + i) % 2) == 0 else y_given
                   for i in (0, 2, 3)]
    given_expected = np.einsum('i, j, k -> ijk', *given_sites)
    pmf_exact = small_mpp.pmf_as_array(mps, 'mps', eps)

    if n_samples > 100:
        n_gr = 5
    elif local_dim == 3:
        n_gr = 2
    else:
        n_gr = 3

    samples = mpp.sample(rgen, mps, n_samples, method, n_gr, 'mps', eps=eps)
    est_pmf, est_n_samples = small_mpp.est_pmf_from(mpp, samples)
    # In this case, we use all the samples from `mpp`.
    assert est_n_samples == n_samples
    given = ~np.isnan(est_pmf)
    assert (given == given_expected).all()

    assert abs(pmf_exact[given].sum() - est_pmf[given].sum()) <= eps
    assert abs(pmf_exact[given] - est_pmf[given]).max() <= 1 / n_samples**0.5
Esempio n. 9
0
def test_mppovmlist_est_pmf_from(
        method, n_samples, nr_sites, local_dim, rank, measure_width,
        local_width, nonuniform, splitpauli, rgen, eps=1e-10):
    """Verify that estimated probabilities from MPPovmList.est_pmf_from()
    are reasonable accurate

    """

    mps = factory.random_mps(nr_sites, local_dim, rank, rgen)
    mps.canonicalize()

    x, y = (povm.MPPovm.from_local_povm(p, 1)
            for p in povm.pauli_parts(local_dim)[:2])
    # POVM list with global support
    g_povm = povm.pauli_mpps(measure_width, local_dim).repeat(nr_sites)
    if nonuniform:
        add_povm = mp.chain((nr_sites - 1) * (x,) + (y,))
        g_povm = povm.MPPovmList(g_povm.mpps + (add_povm,))
    # POVM list with local support
    l_povm = povm.pauli_mpps if splitpauli else povm.pauli_mpp
    l_povm = l_povm(local_width, local_dim).block(nr_sites)
    samples = tuple(g_povm.sample(
        rgen, mps, n_samples, method, mode='mps', eps=eps))
    est_prob, n_samples = zip(*l_povm.est_pmf_from(g_povm, samples, eps))
    exact_prob = tuple(l_povm.pmf_as_array(mps, 'mps', eps))
    # Consistency check on n_samples: All entries should be equal
    # unless `nonuniform` is True.
    all_n_sam = np.concatenate(n_samples)
    assert (not (all_n_sam == all_n_sam[0]).all()) == nonuniform
    for n_sam, est, exact, mpp in zip(
            n_samples, est_prob, exact_prob, l_povm.mpps):
        assert est.shape == mpp.nsoutdims
        assert est.shape == exact.shape
        assert n_sam.shape == exact.shape
        # Compare against exact probabilities
        assert (abs(est - exact) / (3 / n_sam**0.5)).max() <= 1
Esempio n. 10
0
def test_mppovmlist_est_lfun_from(
        method, n_samples, nr_sites, local_dim, rank, measure_width,
        local_width, nonuniform, function, povm_combo, rgen, eps=1e-10):
    """Verify that estimated probabilities from MPPovmList.est_pmf_from()
    are reasonable accurate

    .. todo:: This test is too long and should be split into several
              smaller tests. Also, some of the testing done here is
              redundant.

    """

    mps = factory.random_mps(nr_sites, local_dim, rank, rgen)
    mps.canonicalize()

    sample_povm, fun_povm = povm_combo
    estimation_impossible = (sample_povm == "all-y" and
                             fun_povm in {"local-x", "pauli"})
    fromself = sample_povm == fun_povm and measure_width == local_width
    # s_povm: POVM used to obtain samples
    s_povm = _get_povm(sample_povm, nr_sites, local_dim, measure_width)
    # f_povm: POVM on which a linear function is defined
    if fromself:
        f_povm = s_povm
    else:
        f_povm = _get_povm(fun_povm, nr_sites, local_dim, local_width)
    if function == 'rand':
        def coeff(x): return rgen.rand(*x)
    elif function == 'randn':
        def coeff(x): return rgen.randn(*x)
    elif function == 'ones':
        def coeff(x): return np.ones(x)
    elif function == 'signs':
        def coeff(x): return rgen.choice([1., -1.], x)
    else:
        raise ValueError('Unknown function {!r}'.format(function))

    # More POVMs in s_povm means more samples. Consider this in the tests.
    n_samples_eff = n_samples * len(s_povm.mpps)
    # We divide the coefficients by len(f_povm.mpps) to make the
    # estimated value have approximately same magnitude, independently
    # of len(f_povm.mpps).
    coeff = [coeff(mpp.nsoutdims) / len(f_povm.mpps) for mpp in f_povm.mpps]
    samples = tuple(s_povm.sample(
        rgen, mps, n_samples, method, mode='mps', eps=eps))
    exact_prob = tuple(f_povm.pmf_as_array(mps, 'mps', eps))

    # Compute exact estimate directly
    exact_est1, exact_var1 = f_povm.lfun([c.ravel() for c in coeff],
                                         None, mps, 'mps', eps)
    # Compute exact estimate and variance using the other POVM
    exact_est2, exact_var2 = f_povm.lfun_from(s_povm, coeff, mps, 'mps', eps=eps)
    if estimation_impossible:
        assert np.isnan(exact_est2)
        assert np.isnan(exact_var2)
    else:
        # Estimates must agree.
        assert abs(exact_est1 - exact_est2) <= eps
        if fromself:
            # Variances can be different unless f_povm and s_povm are the same.
            assert abs(exact_var1 - exact_var2) <= eps

    est, var = f_povm.est_lfun_from(s_povm, coeff, samples, eps)

    if fromself:
        # In this case, est_lfun() and est_lfun_from() must give exactly
        # the same result.
        est2, var2 = f_povm.est_lfun([c.ravel() for c in coeff],
                                     None, samples, eps)
        assert abs(est - est2) <= eps
        assert abs(var - var2) <= eps
        # We use est_pmf() to test est_pmf_from()
        # again. MPPovmList.est_pmf() just aggregates results from
        # MPPovm.est_pmf().
        pmf1 = f_povm.est_pmf(samples, normalized=True, eps=eps)
        pmf2, _ = zip(*f_povm.est_pmf_from(s_povm, samples, eps=eps))
        assert all(abs(p1 - p2).max() <= eps for p1, p2 in zip(pmf1, pmf2))

    # The final estimator is based on the samples for
    # `s_povm`. Therefore, it is correct to use `n_samples_eff` below
    # (and not the "effective samples" for the `f_povm` probability
    # estimation returned by :func:`f_povm.est_pmf_from()`).
    exact_est = sum(np.inner(c.flat, p.flat) for c, p in zip(coeff, exact_prob))
    if estimation_impossible:
        assert np.isnan(est)
    else:
        assert abs(exact_est - exact_est2) <= eps
        bound = 20 if fun_povm == 'all-y' else 6
        assert abs(est - exact_est) <= bound / n_samples_eff**0.5
        if function == 'ones':
            assert abs(exact_est - 1) <= eps
            assert abs(est - exact_est) <= eps

    # The code below will only work for small systems. Probably
    # nr_sites = 16 will work, but let's stay safe.
    assert nr_sites <= 8, "Larger systems will require a lot of memory"

    # Use the estimator from `f_povm._estfun_from_estimator()` to
    # compute the exact variance of the estimate. We can assume that
    # estimator is mostly correct because we have checked that it
    # produces accurate estimates (for large numbers of samples)
    # above.
    #
    # FIXME: Drop the exact variance computation here and use
    # exact_var2 from above.
    #
    # Convert from matching functions + coefficients to coefficients
    # for each probability.
    n_samples2 = [s.shape[0] for s in samples]
    _, est_coeff, est_funs = f_povm._lfun_estimator(s_povm, coeff, n_samples2, eps)
    est_p_coeff = [np.zeros(mpp.nsoutdims, float) for mpp in s_povm.mpps]
    for fun_coeff, funs, p_coeff, mpp in zip(
            est_coeff, est_funs, est_p_coeff, s_povm.mpps):
        out = np.unravel_index(range(np.prod(mpp.nsoutdims)), mpp.nsoutdims)
        out = np.array(out).T.copy()
        for c, fun in zip(fun_coeff, funs):
            match = fun(out)
            p_coeff.flat[match] += c
    exact_prob = tuple(s_povm.pmf_as_array(mps, 'mps', eps))
    exact_p_cov = (np.diag(p.flat) - np.outer(p.flat, p.flat) for p in exact_prob)
    exact_var = sum(np.inner(c.flat, np.dot(cov, c.flat))
                    for c, cov in zip(est_p_coeff, exact_p_cov))
    if estimation_impossible:
        assert np.isnan(var)
    else:
        assert abs(exact_var - exact_var2) <= eps
        if fromself:
            # `f_povm` and `s_povm` are equal. We must obtain exactly the
            # same result without using the matching functions from above:
            exact_prob = tuple(f_povm.pmf_as_array(mps, 'mps', eps))
            exact_p_cov = (np.diag(p.flat) - np.outer(p.flat, p.flat)
                           for p in exact_prob)
            exact_var2 = sum(np.inner(c.flat, np.dot(cov, c.flat))
                             for c, cov in zip(coeff, exact_p_cov))
            assert abs(exact_var - exact_var2) <= eps
        # Convert variance to variance of the estimator (=average)
        exact_var /= n_samples

        if sample_povm == 'pauli':
            bound = 6
        elif fun_povm == 'all-y':
            bound = 10
        else:
            bound = 1
        assert n_samples * abs(var - exact_var) <= bound / n_samples_eff**0.5
        if function == 'ones':
            assert abs(exact_var) <= eps
            assert abs(var - exact_var) <= eps
Esempio n. 11
0
def test_mppovm_est(
        method, n_samples, nr_sites, startsite, local_dim, rgen):
    """Check that estimates from .est_pmf() and .est_lfun() are reasonably
    accurate

    """
    rank = 3
    eps = 1e-10
    mps = factory.random_mps(nr_sites, local_dim, rank, rgen)
    mps.canonicalize()

    local_x = povm.x_povm(local_dim)
    local_y = povm.y_povm(local_dim)
    xx = povm.MPPovm.from_local_povm(local_x, 2)
    y = povm.MPPovm.from_local_povm(local_y, 1)
    mpp = mp.chain([xx, povm.MPPovm.eye([local_dim]), y]) \
            .embed(nr_sites, startsite, local_dim)

    p_exact = mpp.pmf_as_array(mps, 'mps', eps)
    p_exact = project_pmf(p_exact, eps, eps)

    cov_p_exact = np.diag(p_exact.flat) - np.outer(p_exact.flat, p_exact.flat)
    samples = mpp.sample(rgen, mps, n_samples, method, 4, 'mps', eps=eps)

    p_est = mpp.est_pmf(samples)
    ept, cov = mpp.est_lfun(None, None, samples, None, eps)
    ept_ex, single_cov_ex = mpp.lfun(None, None, mps, 'mps', eps)
    # The two exact values must match
    assert abs(ept_ex - p_exact.ravel()).max() <= eps
    # The two exact values must match
    assert abs(cov_p_exact - single_cov_ex).max() <= eps
    # The two estimates must match. This verifies that we have chosen
    # our estimator will be unbiased. (There are many other things we
    # might want to know about our estimator.)
    assert (ept == p_est.ravel()).all()
    # The estimate must be close to the true value
    assert abs(p_exact - p_est).max() <= 3 / n_samples**0.5

    cov_ex = cov_p_exact / n_samples
    # The covariances of the sample means (which we estimate here)
    # decrease by 1/n_samples, so we multiply with n_samples before
    # comparing to the rule-of-thumb for the estimation error.
    assert abs(cov - cov_ex).max() * n_samples <= 1 / n_samples**0.5

    funs = []
    nsoutdims = mpp.nsoutdims
    out = np.unravel_index(range(np.prod(nsoutdims)), nsoutdims)
    out = np.array(out).T[:, None, :].copy()
    for ind in range(np.prod(nsoutdims)):
        funs.append(lambda s, ind=ind: (s == out[ind]).all(1))

    # All probabilities sum to one, and we can estimate that well.
    coeff = np.ones(len(funs), dtype=float)
    # Test with dummy weights
    weights = np.ones(n_samples, dtype=float)
    sum_ept, sum_var = mpp.est_lfun(coeff, funs, samples, weights, eps)
    assert abs(sum_ept - 1.0) <= eps
    assert sum_var <= eps

    # Check a sum of probabilities with varying signs.
    coeff = ((-1)**rgen.choice(2, len(funs))).astype(float)
    sum_ept, sum_var = mpp.est_lfun(coeff, funs, samples, None, eps)
    ex_sum = np.inner(coeff, p_exact.flat)
    ex_var = np.inner(coeff, np.dot(cov_ex, coeff))
    assert abs(sum_ept - ex_sum) <= 5 / n_samples**0.5
    assert abs(sum_var - ex_var) * n_samples <= 5 / n_samples**0.5

    # Convert samples to counts and test again
    counts = mpp.est_pmf(samples, normalize=False, eps=eps)
    assert counts.sum() == n_samples
    count_samples = np.array(np.unravel_index(range(np.prod(mpp.nsoutdims)),
                                              mpp.nsoutdims)).T
    weights = counts.ravel()
    sum_ept2, sum_var2 = mpp.est_lfun(coeff, funs, count_samples, weights, eps)
    assert abs(sum_ept - sum_ept2) <= eps
    assert abs(sum_var - sum_var2) <= eps