Example #1
0
def test_sample_circuit_with_seed():
    decomp = _simple_pauli_deco_dict(0.7, simplify_paulis=True)
    circ = Circuit([X.on(LineQubit(0)) for _ in range(10)])

    expected = sample_circuit(circ, decomp, random_state=4)[0]

    # Check we're not sampling the same operation every call to sample_sequence
    assert len(set(expected.all_operations())) > 1

    for _ in range(10):
        sampled = sample_circuit(circ, decomp, random_state=4)[0]
        assert _equal(sampled, expected)
Example #2
0
def test_sample_circuit_random_state(seed, seed_type):
    decomposition = _simple_pauli_deco_dict(0.5)

    if isinstance(seed_type, np.random.RandomState):
        seed = np.random.RandomState(seed)
    circuit, sign, norm = sample_circuit(twoq_circ,
                                         decomposition,
                                         random_state=seed)

    for _ in range(20):
        if isinstance(seed_type, np.random.RandomState):
            seed = np.random.RandomState(seed)
        new_circuit, new_sign, new_norm = sample_circuit(twoq_circ,
                                                         decomposition,
                                                         random_state=seed)
        assert _equal(new_circuit, circuit)
        assert new_sign == sign
        assert np.isclose(new_norm, norm)
Example #3
0
def test_sample_circuit_choi(decomposition_dict: DecompositionDict):
    """Tests the sample_circuit by comparing the exact Choi matrices."""
    ideal_choi = _circuit_to_choi(twoq_circ)
    noisy_circuit = twoq_circ.with_noise(depolarize(BASE_NOISE))
    noisy_choi = _circuit_to_choi(noisy_circuit)
    choi_unbiased_estimates = []
    for _ in range(500):
        imp_circuit, sign, norm = sample_circuit(twoq_circ, decomposition_dict)
        noisy_imp_circuit = imp_circuit.with_noise(depolarize(BASE_NOISE))
        imp_circuit_choi = _circuit_to_choi(noisy_imp_circuit)
        choi_unbiased_estimates.append(norm * sign * imp_circuit_choi)
    choi_pec_estimate = np.average(choi_unbiased_estimates, axis=0)

    noise_error = np.linalg.norm(ideal_choi - noisy_choi)
    pec_error = np.linalg.norm(ideal_choi - choi_pec_estimate)
    assert pec_error < noise_error
    assert np.allclose(ideal_choi, choi_pec_estimate, atol=0.05)
Example #4
0
def test_sample_circuit_types():
    imp_circuit, sign, norm = sample_circuit(twoq_circ, DECO_DICT)
    assert isinstance(imp_circuit, Circuit)
    assert sign in {1, -1}
    assert norm > 1
Example #5
0
def test_sample_circuit_types_trivial():
    imp_circuit, sign, norm = sample_circuit(twoq_circ, NOISELESS_DECO_DICT)
    assert imp_circuit == twoq_circ
    assert sign == 1
    assert np.isclose(norm, 1)
Example #6
0
File: pec.py Project: sid1993/mitiq
def execute_with_pec(
    circuit: QPROGRAM,
    executor: Callable[[QPROGRAM], float],
    decomposition_dict: DecompositionDict,
    precision: float = 0.03,
    num_samples: Optional[int] = None,
    random_state: Optional[Union[int, np.random.RandomState]] = None,
    full_output: bool = False,
) -> Union[float, Tuple[float, float]]:
    """Evaluates the expectation value associated to the input circuit
    using probabilistic error cancellation (PEC) [Temme2017]_ [Endo2018]_.

    This function implements PEC by:

    1. Sampling different implementable circuits from the quasi-probability
       representation of the input circuit;
    2. Evaluating the noisy expectation values associated to the sampled
       circuits (through the "executor" function provided by the user);
    3. Estimating the ideal expectation value from a suitable linear
       combination of the noisy ones.

    Args:
        circuit: The input circuit to execute with error-mitigation.
        executor: A function which executes a circuit and returns an
            expectation value.
        decomposition_dict: The decomposition dictionary containing the
            quasi-probability representation of the ideal operations (those
            which are part of the input circuit).
        num_samples: The number of noisy circuits to be sampled for PEC.
            If not given, this is deduced from the argument 'precision'.
        precision: The desired estimation precision (assuming the observable
            is bounded by 1). The number of samples is deduced according
            to the formula (one_norm / precision) ** 2, where 'one_norm'
            is related to the negativity of the quasi-probability
            representation [Temme2017]_. If 'num_samples' is explicitly set
            by the user, 'precision' is ignored and has no effect.
        random_state: Seed for sampling circuits.
        full_output: If False only the average PEC value is returned.
            If True an estimate of the associated error is returned too.

    Returns:
        pec_value: The PEC estimate of the ideal expectation value associated
            to the input circuit.
        pec_error: The estimated error between the mitigated 'pec_value' and
            the actual ideal expectation value. This is estimated as the ratio
            pec_std / sqrt(num_samples), where 'pec_std' is the
            standard deviation of the PEC samples, i.e., the square root of
            the mean squared deviation of the sampled values from 'pec_value'.
            This is returned only if 'full_output' is True.

    .. [Temme2017] : Kristan Temme, Sergey Bravyi, Jay M. Gambetta,
        "Error mitigation for short-depth quantum circuits,"
        *Phys. Rev. Lett.* **119**, 180509 (2017),
        (https://arxiv.org/abs/1612.02058).

    .. [Endo2018] : Suguru Endo, Simon C. Benjamin, Ying Li,
        "Practical Quantum Error Mitigation for Near-Future Applications"
        *Phys. Rev. **X 8**, 031027 (2018),
        (https://arxiv.org/abs/1712.09271).

    .. [Takagi2020] : Ryuji Takagi,
        "Optimal resource cost for error mitigation,"
        (https://arxiv.org/abs/2006.12509).
    """
    if isinstance(random_state, int):
        random_state = np.random.RandomState(random_state)

    # Get the 1-norm of the circuit quasi-probability representation
    _, _, norm = sample_circuit(circuit, decomposition_dict)

    if not (0 < precision <= 1):
        raise ValueError(
            "The value of 'precision' should be within the interval (0, 1],"
            f" but precision is {precision}."
        )

    # Deduce the number of samples (if not given by the user)
    if not isinstance(num_samples, int):
        num_samples = int((norm / precision) ** 2)

    # Issue warning for very large sample size
    if num_samples > 10 ** 5:
        warnings.warn(_LARGE_SAMPLE_WARN, LargeSampleWarning)

    sampled_circuits = []
    signs = []

    for _ in range(num_samples):
        sampled_circuit, sign, _ = sample_circuit(
            circuit, decomposition_dict, random_state
        )
        sampled_circuits.append(sampled_circuit)
        signs.append(sign)

    # TODO gh-412: Add support for batched executors in the PEC module
    # Execute all the circuits
    exp_values = [executor(circ) for circ in sampled_circuits]

    # Evaluate unbiased estimators [Temme2017] [Endo2018] [Takagi2020]
    unbiased_estimators = [norm * s * val for s, val in zip(signs, exp_values)]

    pec_value = np.average(unbiased_estimators)

    if full_output:
        pec_error = np.std(unbiased_estimators) / np.sqrt(num_samples)
        return pec_value, pec_error

    return pec_value
Example #7
0
def execute_with_pec(
    circuit: QPROGRAM,
    executor: Callable[[QPROGRAM], float],
    decomposition_dict: DecompositionDict,
    num_samples: Optional[int] = None,
    random_state: Optional[Union[int, np.random.RandomState]] = None,
    full_output: bool = False,
) -> Union[float, Tuple[float, float]]:
    """Evaluates the expectation value associated to the input circuit
    using probabilistic error cancellation (PEC) [Temme2017]_.

    This function implements PEC by:

    1. Sampling different implementable circuits from the quasi-probability
       representation of the input circuit;
    2. Evaluating the noisy expectation values associated to the sampled
       circuits (through the "executor" function provided by the user);
    3. Estimating the ideal expectation value from a suitable linear
       combination of the noisy ones.

    Args:
        circuit: The input circuit to execute with error-mitigation.
        executor: A function which executes a circuit and returns an
            expectation value.
        decomposition_dict: The decomposition dictionary containing the
            quasi-probability representation of the ideal operations (those
            which are part of the input circuit).
        num_samples: The number of noisy circuits to be sampled for PEC.
            If equal to None, it is deduced from the amount of "negativity"
            of the quasi-probability representation of the input circuit.
            Note: the latter feature is not yet implemented and num_samples
            is just set to 1000 if not specified.
        random_state: Seed for sampling circuits.
        full_output: If False only the average PEC value is returned.
            If True an estimate of the associated error is returned too.

    Returns:
        pec_value: The PEC estimate of the ideal expectation value associated
            to the input circuit.
        pec_error: The estimated error between the mitigated 'pec_value' and
            the actual ideal expectation value. This is estimated as the ratio
            pec_std / sqrt(num_samples), where 'pec_std' is the
            standard deviation of the PEC samples, i.e., the square root of
            the mean squared deviation of the sampled values from 'pec_value'.
            This is returned only if 'full_output' is True.

    .. [Temme2017] : Kristan Temme, Sergey Bravyi, Jay M. Gambetta,
        "Error mitigation for short-depth quantum circuits,"
        *Phys. Rev. Lett.* **119**, 180509 (2017),
        (https://arxiv.org/abs/1612.02058).

    .. [Endo2018] : Suguru Endo, Simon C. Benjamin, Ying Li,
        "Practical Quantum Error Mitigation for Near-Future Applications"
        *Phys. Rev. **X 8**, 031027 (2018),
        (https://arxiv.org/abs/1712.09271).

    .. [Takagi2020] : Ryuji Takagi,
        "Optimal resource cost for error mitigation,"
        (https://arxiv.org/abs/2006.12509).
    """

    # TODO gh-413: Add option to automatically deduce the number of PEC samples
    if not num_samples:
        num_samples = 1000

    sampled_circuits = []
    signs = []

    for _ in range(num_samples):
        # Note: the norm is the same for each sample.
        sampled_circuit, sign, norm = sample_circuit(
            circuit, decomposition_dict, random_state
        )
        sampled_circuits.append(sampled_circuit)
        signs.append(sign)

    # TODO gh-412: Add support for batched executors in the PEC module
    # Execute all the circuits
    exp_values = [executor(circ) for circ in sampled_circuits]

    # Evaluate unbiased estimators [Temme2017], [Endo2018], [Takagi2020]
    unbiased_estimators = [norm * s * val for s, val in zip(signs, exp_values)]

    pec_value = np.average(unbiased_estimators)

    if full_output:
        pec_error = np.std(unbiased_estimators) / np.sqrt(num_samples)
        return pec_value, pec_error

    return pec_value