예제 #1
0
def test_precision_option_in_execute_with_pec(precision: float):
    """Tests that the 'precision' argument is used to deduce num_samples."""
    # For a noiseless circuit we expect num_samples = 1/precision^2:
    _, pec_data = execute_with_pec(
        oneq_circ,
        partial(fake_executor, random_state=np.random.RandomState(0)),
        representations=pauli_representations,
        precision=precision,
        force_run_all=True,
        full_output=True,
        random_state=1,
    )
    # The error should scale as precision
    print(pec_data["pec_error"] / precision)
    assert np.isclose(pec_data["pec_error"] / precision, 1.0, atol=0.15)

    # Check precision is ignored when num_samples is given.
    num_samples = 1
    _, pec_data = execute_with_pec(
        oneq_circ,
        partial(fake_executor, random_state=np.random.RandomState(0)),
        representations=pauli_representations,
        precision=precision,
        num_samples=num_samples,
        full_output=True,
    )
    assert pec_data["num_samples"] == num_samples
예제 #2
0
def test_execute_with_pec_with_different_samples(circuit, seed):
    """Tests that, on average, the error decreases as the number of samples is
    increased.
    """
    errors_few_samples = []
    errors_more_samples = []
    for _ in range(10):
        mitigated = execute_with_pec(
            circuit,
            serial_executor,
            representations=pauli_representations,
            num_samples=10,
            force_run_all=True,
            random_state=seed,
        )
        errors_few_samples.append(abs(mitigated - 1.0))
        mitigated = execute_with_pec(
            circuit,
            serial_executor,
            representations=pauli_representations,
            num_samples=100,
            force_run_all=True,
            random_state=seed,
        )
        errors_more_samples.append(abs(mitigated - 1.0))

    assert np.average(errors_more_samples) < np.average(errors_few_samples)
예제 #3
0
def test_bad_precision_argument(bad_value: float):
    """Tests that if 'precision' is not within (0, 1] an error is raised."""
    with pytest.raises(ValueError, match="The value of 'precision' should"):
        execute_with_pec(oneq_circ,
                         serial_executor,
                         pauli_representations,
                         precision=bad_value)
예제 #4
0
def test_precision_option_in_execute_with_pec(precision: float):
    """Tests that the 'precision' argument is used to deduce num_samples."""
    # For a noiseless circuit we expect num_samples = 1/precision^2:
    _, pec_data = execute_with_pec(
        oneq_circ,
        partial(fake_executor, random_state=np.random.RandomState(0)),
        representations=pauli_representations,
        precision=precision,
        force_run_all=True,
        full_output=True,
    )
    # The error should scale as precision
    assert np.isclose(pec_data["pec_error"] / precision, 1.0, atol=0.1)

    # If num_samples is given, precision is ignored.
    nsamples = 1000
    _, pec_data = execute_with_pec(
        oneq_circ,
        partial(fake_executor, random_state=np.random.RandomState(0)),
        representations=pauli_representations,
        precision=precision,
        num_samples=nsamples,
        full_output=True,
    )
    # The error should scale as 1/sqrt(num_samples)
    assert not np.isclose(pec_data["pec_error"] / precision, 1.0, atol=0.1)
    assert np.isclose(pec_data["pec_error"] * np.sqrt(nsamples), 1.0, atol=0.1)
예제 #5
0
def test_large_sample_size_warning():
    """Tests whether a warning is raised when PEC sample size
    is greater than 10 ** 5.
    """
    with pytest.warns(
            LargeSampleWarning,
            match=r"The number of PEC samples is very large.",
    ):
        execute_with_pec(oneq_circ,
                         partial(fake_executor,
                                 random_state=np.random.RandomState(0)),
                         pauli_representations,
                         num_samples=100001)
예제 #6
0
def test_execute_with_pec_mitigates_noise(circuit, executor, circuit_type):
    """Tests that execute_with_pec mitigates the error of a noisy
    expectation value.
    """
    circuit = convert_from_mitiq(circuit, circuit_type)

    true_noiseless_value = 1.0
    unmitigated = serial_executor(circuit)

    if circuit_type == "qiskit":
        # Note this is an important subtlety necessary because of conversions.
        reps = get_pauli_representations(
            base_noise=BASE_NOISE,
            qubits=[cirq.NamedQubit(name) for name in ("q_0", "q_1")],
        )
        # TODO: PEC with Qiskit is slow.
        #  See https://github.com/unitaryfund/mitiq/issues/507.
        circuit, _ = convert_to_mitiq(circuit)
    else:
        reps = pauli_representations

    mitigated = execute_with_pec(
        circuit,
        executor,
        representations=reps,
        force_run_all=False,
        random_state=101,
    )
    error_unmitigated = abs(unmitigated - true_noiseless_value)
    error_mitigated = abs(mitigated - true_noiseless_value)

    assert error_mitigated < error_unmitigated
    assert np.isclose(mitigated, true_noiseless_value, atol=0.1)
예제 #7
0
def test_qiskit_noiseless_decomposition_multiqubit(nqubits):
    qreg = [qiskit.QuantumRegister(1) for _ in range(nqubits)]
    circuit = qiskit.QuantumCircuit(*qreg)
    for q in qreg:
        circuit.h(q)

    # Decompose H(q) for each qubit q into Paulis.
    representations = []
    for q in qreg:
        opcircuit = qiskit.QuantumCircuit(q)
        opcircuit.h(q)

        xcircuit = qiskit.QuantumCircuit(q)
        xcircuit.x(q)

        zcircuit = qiskit.QuantumCircuit(q)
        zcircuit.z(q)

        representation = OperationRepresentation(
            ideal=opcircuit,
            basis_expansion={
                NoisyOperation(ideal=xcircuit): 0.5,
                NoisyOperation(ideal=zcircuit): 0.5,
            })
        representations.append(representation)

    exact = noiseless_serial_executor(circuit)
    pec_value = execute_with_pec(
        circuit,
        noiseless_serial_executor,
        representations=representations,
        num_samples=500,
        random_state=1,
    )
    assert np.isclose(pec_value, exact, atol=0.1)
예제 #8
0
def test_pec_data_with_full_output():
    """Tests that execute_with_pec mitigates the error of a noisy
    expectation value.
    """
    precision = 0.1
    pec_value, pec_data = execute_with_pec(
        twoq_circ,
        serial_executor,
        precision=precision,
        representations=pauli_representations,
        full_output=True,
        random_state=102,
    )
    # Get num samples from precision
    norm = 1.0
    for op in twoq_circ.all_operations():
        for rep in pauli_representations:
            if rep.ideal == cirq.Circuit(op):
                norm *= rep.norm
    num_samples = int((norm / precision)**2)

    # Manually get raw expectation values
    exp_values = [serial_executor(c) for c in pec_data["sampled_circuits"]]

    assert pec_data["num_samples"] == num_samples
    assert pec_data["precision"] == precision
    assert np.isclose(pec_data["pec_value"], pec_value)
    assert np.isclose(
        pec_data["pec_error"],
        np.std(pec_data["unbiased_estimators"]) / np.sqrt(num_samples),
    )
    assert np.isclose(np.average(pec_data["unbiased_estimators"]), pec_value)
    assert np.allclose(pec_data["measured_expectation_values"], exp_values)
예제 #9
0
def test_execute_with_pec_cirq_noiseless_decomposition(circuit):
    unmitigated = noiseless_serial_executor(circuit)

    mitigated = execute_with_pec(
        circuit,
        noiseless_serial_executor,
        representations=noiseless_pauli_representations,
        num_samples=10,
        random_state=1,
    )

    assert np.isclose(unmitigated, mitigated)
예제 #10
0
def test_execute_with_pec_pyquil_trivial_decomposition():
    circuit = pyquil.Program(pyquil.gates.H(0))
    rep = OperationRepresentation(
        circuit, basis_expansion={NoisyOperation(circuit): 1.0})
    unmitigated = serial_executor(circuit)

    mitigated = execute_with_pec(
        circuit,
        serial_executor,
        representations=[rep],
        num_samples=10,
        random_state=1,
    )

    assert np.isclose(unmitigated, mitigated)
예제 #11
0
def test_execute_with_pec_cirq_trivial_decomposition():
    circuit = cirq.Circuit(cirq.H.on(cirq.LineQubit(0)))
    rep = OperationRepresentation(
        circuit, basis_expansion={NoisyOperation(circuit): 1.0})

    unmitigated = serial_executor(circuit)
    mitigated = execute_with_pec(
        circuit,
        serial_executor,
        representations=[rep],
        num_samples=10,
        random_state=1,
    )

    assert np.isclose(unmitigated, mitigated)
예제 #12
0
def test_execute_with_pec_error_scaling(num_samples: int):
    """Tests that the error associated to the PEC value scales as
    1/sqrt(num_samples).
    """
    _, pec_data = execute_with_pec(
        oneq_circ,
        partial(fake_executor, random_state=np.random.RandomState(0)),
        representations=pauli_representations,
        num_samples=num_samples,
        force_run_all=True,
        full_output=True,
    )
    # The error should scale as 1/sqrt(num_samples)
    normalized_error = pec_data["pec_error"] * np.sqrt(num_samples)
    assert np.isclose(normalized_error, 1.0, atol=0.1)
예제 #13
0
def test_execute_with_pec_qiskit_trivial_decomposition():
    qreg = qiskit.QuantumRegister(1)
    circuit = qiskit.QuantumCircuit(qreg)
    _ = circuit.x(qreg)
    rep = OperationRepresentation(
        circuit, basis_expansion={NoisyOperation(circuit): 1.0})
    unmitigated = serial_executor(circuit)

    mitigated = execute_with_pec(
        circuit,
        serial_executor,
        representations=[rep],
        num_samples=10,
        random_state=1,
    )

    assert np.isclose(unmitigated, mitigated)
예제 #14
0
def test_executed_circuits_have_the_expected_type(circuit_type):

    circuit = convert_from_mitiq(oneq_circ, circuit_type)
    circuit_type = type(circuit)

    # Fake executor just for testing types
    def type_detecting_executor(circuit: QPROGRAM):
        assert type(circuit) is circuit_type
        return 0.0

    mitigated = execute_with_pec(
        circuit,
        executor=type_detecting_executor,
        representations=pauli_representations,
        num_samples=1,
    )
    assert np.isclose(mitigated, 0.0)
예제 #15
0
def test_execute_with_pec_partial_representations():
    # Only use the CNOT representation.
    reps = [pauli_representations[-1]]

    pec_value = execute_with_pec(
        twoq_circ,
        executor=partial(
            mitiq_cirq.compute_density_matrix,
            noise_model=cirq.depolarize,
            noise_level=(BASE_NOISE, ),
        ),
        observable=Observable(PauliString("ZZ")),
        representations=reps,
        num_samples=100,
        force_run_all=False,
        random_state=101,
    )
    assert isinstance(pec_value, complex)
예제 #16
0
def track_pec(
    circuit_type: str,
    nqubits: int,
    depth: int,
    observable: Observable,
    num_samples: int,
) -> float:
    """Returns the PEC error mitigation factor, i.e., the ratio

    (error without PEC) / (error with PEC).

    Args:
        circuit_type: Type of benchmark circuit.
        nqubits: Number of qubits in the benchmark circuit.
        depth: Some proxy of depth in the benchmark circuit.
        observable: Observable to compute the expectation value of.
        num_samples: Number of circuits to sample/run.
    """
    circuit = get_benchmark_circuit(circuit_type, nqubits, depth)

    noise_level = 0.01
    reps = pec.represent_operations_in_circuit_with_local_depolarizing_noise(
        circuit, noise_level
    )

    compute_density_matrix = functools.partial(
        mitiq_cirq.compute_density_matrix,
        noise_model=cirq.depolarize,
        noise_level=(noise_level,),
    )

    true_value = raw.execute(
        circuit, compute_density_matrix_noiseless, observable
    )
    raw_value = raw.execute(circuit, compute_density_matrix, observable)
    pec_value = pec.execute_with_pec(
        circuit,
        compute_density_matrix,
        observable,
        representations=reps,
        num_samples=num_samples,
    )
    return np.real(abs(true_value - raw_value) / abs(true_value - pec_value))
예제 #17
0
def test_execute_with_pec_with_different_samples(circuit, seed):
    """Tests that, on average, the error decreases as the number of samples is
    increased.
    """
    small_sample_number = 10
    large_sample_number = 100

    errors = []
    for num_samples in (small_sample_number, large_sample_number):
        mitigated = execute_with_pec(
            circuit,
            serial_executor,
            representations=pauli_representations,
            num_samples=num_samples,
            force_run_all=True,
            random_state=seed,
        )
        errors.append(abs(mitigated - 1.0))

    assert np.average(errors[1]) < np.average(errors[0])
예제 #18
0
def test_execute_with_pec_with_observable():
    circuit = twoq_circ
    obs = Observable(PauliString("ZZ"))
    executor = partial(
        mitiq_cirq.compute_density_matrix,
        noise_model=cirq.depolarize,
        noise_level=(BASE_NOISE, ),
    )
    true_value = 1.0

    noisy_value = obs.expectation(circuit, mitiq_cirq.compute_density_matrix)
    pec_value = execute_with_pec(
        circuit,
        executor,
        observable=obs,
        representations=pauli_representations,
        num_samples=100,
        force_run_all=False,
        random_state=101,
    )
    assert abs(pec_value - true_value) < abs(noisy_value - true_value)
    assert np.isclose(pec_value, true_value, atol=0.1)
예제 #19
0
def test_pyquil_noiseless_decomposition_multiqubit(nqubits):
    circuit = pyquil.Program(pyquil.gates.H(q) for q in range(nqubits))

    # Decompose H(q) for each qubit q into Paulis.
    representations = []
    for q in range(nqubits):
        representation = OperationRepresentation(
            ideal=pyquil.Program(pyquil.gates.H(q)),
            basis_expansion={
                NoisyOperation(ideal=pyquil.Program(pyquil.gates.X(q))): 0.5,
                NoisyOperation(ideal=pyquil.Program(pyquil.gates.Z(q))): 0.5,
            })
        representations.append(representation)

    exact = noiseless_serial_executor(circuit)
    pec_value = execute_with_pec(
        circuit,
        noiseless_serial_executor,
        representations=representations,
        num_samples=500,
        random_state=1,
    )
    assert np.isclose(pec_value, exact, atol=0.1)