Skip to content

Latest commit

 

History

History
94 lines (73 loc) · 3.55 KB

qibo-noisy-simulation.md

File metadata and controls

94 lines (73 loc) · 3.55 KB
jupytext kernelspec
text_representation
extension format_name format_version jupytext_version
.myst
myst
0.13
1.11.1
display_name language name
Python 3 (ipykernel)
python
python3

Error mitigation with Qibo using noisy simulation

In this tutorial we will cover how to use Mitiq to apply Zero-Noise Extrapolation (ZNE) to a quantum program written using Qibo. We will demonstrate the use of these two tools by implementing a noisy simulation as random Pauli gates probabilistically applied after each ideal gate.

Defining a circuit

For simplicity, we will use a single-qubit circuit with ten Pauli X gates that compiles to the identity. This will give us a simple circuit whose probability of measuring the $|0\rangle$ state at the end, ideally, should be 1.

import os 
os.environ['QIBO_LOG_LEVEL'] = '3' #Supress Qibo INFO messages

from qibo import Circuit, gates

c = Circuit(1)
for _ in range(10):
    c.add(gates.X(0))
c.add(gates.M(0))

We will use the probability of measuring the $|0\rangle$ state as our observable to mitigate.

Defining the executor

To use Mitiq, an executor function is required to be defined. This function abstracts away the logic of how a circuit is executed, allowing Mitiq to only see the circuit, and the value received from the executor (which, in the case of applying ZNE, must be a float). In the executor, we create a noise map and apply it to the circuit. We then simulate the noisy circuit and return the measured observable. For more detailed information about the noise map features see Qibo's documentation on noisy simulation.

def executor(circuit, shots=100):
    """Returns the expectation value to be mitigated.
    In this case the expectation value is the probability to get the |0⟩ state.

    Args:
        circuit: Circuit to run.
        shots: Number of times to execute the circuit to compute the expectation value.
    """
    # noise_map = {qubit_id: [(gate, probability)]}
    noise_map = {0: [('X', 0.03), ('Z', 0.03)]}
    noisy_c = circuit.with_pauli_noise(noise_map)

    result = noisy_c(nshots=shots)
    result_freq = result.frequencies(binary=True)
    counts_0 = result_freq.get('0', 0)

    return counts_0 / shots

Applying ZNE

We can now test the mitigated version of the circuit against the unmitigated one to ensure it is working as expected. We apply ZNE with scale factors 1, 2 and 3 and using LinearFactory (which extrapolates the measured expectation values using a linear extrapolation). For each scaling factor we average over three circuits.

from mitiq import zne
from mitiq.zne.inference import LinearFactory

unmitigated = executor(c)
print(f"Unmitigated result {unmitigated:.3f}")

scale_factors = [1, 2, 3]
factory = LinearFactory(
    scale_factors=scale_factors
)  # default ZNE configuration
mitigated = zne.execute_with_zne(c, executor, factory=factory, num_to_average=3)
print(f"Mitigated result {mitigated:.3f}")

The mitigated result is noticeably closer to the noiseless result compared to the result without mitigation. In addition, Mitiq offers the capability to view the extrapolation directly from the RichardsonFactory object.

import matplotlib.pyplot as plt
factory.plot_fit()
plt.show()