diff --git a/_static/demo_thumbnails/large_demo_thumbnails/thumbnail_large_how_to_import_qiskit_noise_models.png b/_static/demo_thumbnails/large_demo_thumbnails/thumbnail_large_how_to_import_qiskit_noise_models.png new file mode 100644 index 0000000000..2a6defd8ce Binary files /dev/null and b/_static/demo_thumbnails/large_demo_thumbnails/thumbnail_large_how_to_import_qiskit_noise_models.png differ diff --git a/_static/demo_thumbnails/opengraph_demo_thumbnails/OGthumbnail_how_to_import_qiskit_noise_models.png b/_static/demo_thumbnails/opengraph_demo_thumbnails/OGthumbnail_how_to_import_qiskit_noise_models.png new file mode 100644 index 0000000000..61624999e3 Binary files /dev/null and b/_static/demo_thumbnails/opengraph_demo_thumbnails/OGthumbnail_how_to_import_qiskit_noise_models.png differ diff --git a/_static/demo_thumbnails/regular_demo_thumbnails/thumbnail_how_to_import_qiskit_noise_models.png b/_static/demo_thumbnails/regular_demo_thumbnails/thumbnail_how_to_import_qiskit_noise_models.png new file mode 100644 index 0000000000..c8d57b6f08 Binary files /dev/null and b/_static/demo_thumbnails/regular_demo_thumbnails/thumbnail_how_to_import_qiskit_noise_models.png differ diff --git a/demonstrations/tutorial_how_to_import_qiskit_noise_models.metadata.json b/demonstrations/tutorial_how_to_import_qiskit_noise_models.metadata.json new file mode 100644 index 0000000000..78b1bd040a --- /dev/null +++ b/demonstrations/tutorial_how_to_import_qiskit_noise_models.metadata.json @@ -0,0 +1,43 @@ +{ + "title": "How to import noise models from Qiskit", + "authors": [ + { + "username": "whatsis" + } + ], + "dateOfPublication": "2024-11-25T00:00:00+00:00", + "dateOfLastModification": "2024-11-25T00:00:00+00:00", + "categories": [ + "Quantum Computing", + "How-to" + ], + "tags": [], + "previewImages": [ + { + "type": "thumbnail", + "uri": "/_static/demo_thumbnails/regular_demo_thumbnails/thumbnail_how_to_import_qiskit_noise_models.png" + }, + { + "type": "large_thumbnail", + "uri": "/_static/demo_thumbnails/large_demo_thumbnails/thumbnail_large_how_to_import_qiskit_noise_models.png" + } + ], + "seoDescription": "Learn how noise models can be imported into PennyLane from Qiskit.", + "doi": "", + "references": [ + ], + "basedOnPapers": [], + "referencedByPapers": [], + "relatedContent": [ + { + "type": "demonstration", + "id": "tutorial_how_to_use_noise_models", + "weight": 1.0 + }, + { + "type": "demonstration", + "id": "tutorial_noisy_circuits", + "weight": 1.0 + } + ] +} diff --git a/demonstrations/tutorial_how_to_import_qiskit_noise_models.py b/demonstrations/tutorial_how_to_import_qiskit_noise_models.py new file mode 100644 index 0000000000..7568184d0e --- /dev/null +++ b/demonstrations/tutorial_how_to_import_qiskit_noise_models.py @@ -0,0 +1,219 @@ +r"""How to import noise models from Qiskit +========================================== + +Noise models describe how a quantum system interacts with its environment. +These models are typically represented by a set of +`Kraus operators `_ +that encapsulates the probabilistic nature of quantum errors. ⚡ +Interestingly, different sets of Kraus operators can represent the same quantum noise process. +The non-unique nature of these representations allows quantum computing libraries to use +different approaches for storing and building Kraus operators to construct noise models. +In this how-to guide, we will first compare the construction of noise models in +`Qiskit `_ and +`PennyLane `_. Then, we will learn how to +convert a Qiskit noise model into an equivalent PennyLane one, allowing users to import any +custom user-defined or fake backend-based noise models. +""" + +###################################################################### +# Noise models in Qiskit and PennyLane +# ------------------------------------ +# +# The noise models in Qiskit are built using the tools available in the +# `noise module `_ +# of the ``Qiskit-Aer`` package. Each model is represented by a `NoiseModel +# `_ +# object that contains `QuantumError +# `_ +# to describe the errors encountered in gate operations. Optionally, it may also have a +# `ReadoutError `_ +# that describes the classical readout errors. +# +# Let's build a Qiskit noise model that inserts *depolarization* errors for single-qubit gates, +# *bit-flip* errors for the target qubit of the two-qubit gates, +# and *amplitude damping* errors for each measurement: +# + +import numpy as np +from qiskit_aer.noise import ( + amplitude_damping_error, depolarizing_error, pauli_error, NoiseModel +) + +# Building the Qiskit noise model +model_qk = NoiseModel() + +# Depolarization error for single-qubit gates +prob_depol = 0.2 +error_gate1 = depolarizing_error(prob_depol, 1) +model_qk.add_all_qubit_quantum_error(error_gate1, ["u1", "u2", "u3"]) + +# Bit flip errors for two-qubit gate +prob_bit_flip = 0.1 +error_gate2 = pauli_error([('X', prob_bit_flip), ('I', 1 - prob_bit_flip)]).tensor( + pauli_error([('I', 1)]) +) +model_qk.add_all_qubit_quantum_error(error_gate2, ["cx"]) + +# Amplitude damping error for measurements +n_qubits = 3 +exc_population = 0.2 +prob_ampl_damp = np.random.default_rng(42).uniform(0, 0.2, n_qubits) +for qubit in range(n_qubits): + error_meas = amplitude_damping_error(prob_ampl_damp[qubit], exc_population) + model_qk.add_quantum_error(error_meas, "measure", [qubit]) + +print(model_qk) + +###################################################################### +# In contrast, the noise models in PennyLane are :class:`~.pennylane.NoiseModel` +# objects with Boolean conditions that select the operation for which +# we want to apply noise. These conditions are mapped to noise functions +# that apply (or queue) the corresponding noise for the selected operation +# or measurement process based on user-provided metadata. This allows +# for a more functional construction, as we can see by recreating the +# above noise model as shown below. For more information on this, check out our +# :doc:`how-to for noise models in PennyLane `. 🧑‍🏫 +# + +import pennylane as qml + +# Depolarization error for single-qubit gates +gate1_fcond = qml.noise.op_in(["U1", "U2", "U3"]) & qml.noise.wires_in(range(n_qubits)) +gate1_noise = qml.noise.partial_wires(qml.DepolarizingChannel, prob_depol) + +# Bit flip errors for two-qubit gate +gate2_fcond = qml.noise.op_eq("CNOT") +def gate2_noise(op, **metadata): + qml.BitFlip(prob_bit_flip, op.wires[1]) + +# Readout errors for measurements +rmeas_fcond = qml.noise.meas_eq(qml.counts) +def rmeas_noise(op, **metadata): + for wire in op.wires: + qml.GeneralizedAmplitudeDamping(prob_ampl_damp[wire], 1 - exc_population, wire) + +# Building the PennyLane noise model +model_pl = qml.NoiseModel( + {gate1_fcond: gate1_noise, gate2_fcond: gate2_noise}, {rmeas_fcond: rmeas_noise}, +) + +print(model_pl) + +###################################################################### +# It is important to verify whether these noise models work the intended way. +# For this purpose, we will use them while simulating a +# `GHZ state `_ using the +# `default.mixed `_ +# and `qiskit.aer `_ +# devices. Note that we require :func:`~.pennylane.add_noise` transform for +# adding the PennyLane noise model but the Qiskit noise model is provided in +# the device definition itself: +# + +# Preparing the devices +n_shots = int(2e6) +dev_pl_ideal = qml.device("default.mixed", wires=n_qubits, shots=n_shots) +dev_qk_noisy = qml.device("qiskit.aer", wires=n_qubits, shots=n_shots, noise_model=model_qk) + +def GHZcircuit(): + qml.U2(0, np.pi, wires=[0]) + for wire in range(n_qubits-1): + qml.CNOT([wire, wire + 1]) + return qml.counts(wires=range(n_qubits), all_outcomes=True) + +# Preparing the circuits +pl_ideal_circ = qml.QNode(GHZcircuit, dev_pl_ideal) +pl_noisy_circ = qml.add_noise(pl_ideal_circ, noise_model=model_pl) +qk_noisy_circ = qml.QNode(GHZcircuit, dev_qk_noisy) + +# Preparing the results +pl_noisy_res, qk_noisy_res = pl_noisy_circ(), qk_noisy_circ() + +###################################################################### +# Now let's look at the results to compare the two noise models: +# + +pl_probs = np.array(list(pl_noisy_res.values())) / n_shots +qk_probs = np.array(list(qk_noisy_res.values())) / n_shots + +print("PennyLane Results: ", np.round(pl_probs, 3)) +print("Qiskit Results: ", np.round(qk_probs, 3)) +print("Are results equal? ", np.allclose(pl_probs, qk_probs, atol=1e-2)) + +###################################################################### +# As the results are equal within a targeted tolerance, +# we can confirm that the two noise models are equivalent. +# Note that this tolerance can be further suppressed by +# increasing the number of shots (``n_shots``) in the simulation. +# + +###################################################################### +# Importing Qiskit noise models +# ----------------------------- +# +# PennyLane provides the :func:`~.pennylane.from_qiskit_noise` function to +# easily convert a Qiskit noise model into an equivalent PennyLane noise model. +# Let's look at an example of a noise model based on the `GenericBackendV2 +# `_ +# backend that gets instantiated with the error data generated and sampled randomly from +# historical IBM backend data. +# + +from qiskit.providers.fake_provider import GenericBackendV2 + +backend = GenericBackendV2(num_qubits=2, seed=42) +qk_noise_model = NoiseModel.from_backend(backend) +print(qk_noise_model) + +###################################################################### +# To import this noise model as a PennyLane one, we simply do: +# + +pl_noise_model = qml.from_qiskit_noise(qk_noise_model) +print(pl_noise_model) + +###################################################################### +# This conversion leverages the standard Kraus representation of the errors +# stored in the ``qk_noise_model``. Internally, this is done in a smart three-step process: +# +# 1. First, all the basis gates from the noise model are mapped to the corresponding PennyLane +# gate `operations `_. +# 2. Next, the operations with noise are mapped to the corresponding error channels +# defined via :class:`~.pennylane.QubitChannel`. +# 3. Finally, the `Boolean conditionals `_ +# are constructed and combined based on their associated errors. +# +# This can be done for any noise model defined in Qiskit with a minor catch that +# the classical readout errors are not supported yet in PennyLane. +# However, we can easily re-insert quantum readout errors into our converted noise model. +# Here's an example that adds ``rmeas_fcond`` and ``rmeas_noise`` (defined earlier) to +# ``pl_noise_model``: +# + +pl_noise_model += {"meas_map": {rmeas_fcond: rmeas_noise}} +print(pl_noise_model.meas_map) + +###################################################################### +# Conclusion +# ---------- +# + +###################################################################### +# Qiskit provides noise models and tools that could be used to mirror the behaviour of quantum +# devices. Integrating them into PennyLane is a powerful way to enable users to perform +# differentiable noisy simulations that help them study the effects of noise on quantum circuits +# and develop noise-robust quantum algorithms. In this how-to guide, we learned how to construct +# PennyLane noise models from Qiskit ones by manually building one-to-one mappings +# for each kind of error and also by using the :func:`~.pennylane.from_qiskit_noise` function +# to convert the Qiskit noise model automatically. 💪 +# +# Should you have any questions about using noise models in PennyLane, you can consult the +# `noise module documentation `_, +# the `PennyLane Codebook module on Noisy Quantum Theory +# `_, +# or create a post on the `PennyLane Discussion Forum `_. +# + +###################################################################### +# About the author +# ---------------- diff --git a/demonstrations/tutorial_how_to_use_noise_models.metadata.json b/demonstrations/tutorial_how_to_use_noise_models.metadata.json index 9f0c0fce6e..f79c640020 100644 --- a/demonstrations/tutorial_how_to_use_noise_models.metadata.json +++ b/demonstrations/tutorial_how_to_use_noise_models.metadata.json @@ -6,7 +6,7 @@ } ], "dateOfPublication": "2024-10-01T00:00:00+00:00", - "dateOfLastModification": "2024-11-08T00:00:00+00:00", + "dateOfLastModification": "2024-11-22T00:00:00+00:00", "categories": [ "Quantum Computing", "How-to" @@ -33,6 +33,11 @@ "type": "demonstration", "id": "tutorial_noisy_circuits", "weight": 1.0 + }, + { + "type": "demonstration", + "id": "tutorial_how_to_import_qiskit_noise_models", + "weight": 1.0 } ] }