Processing math: 100%
/ Demos / Quantum Computing / How to use noise models in PennyLane

How to use noise models in PennyLane

Published: October 1, 2024. Last updated: November 22, 2024.

Noise models are essential for understanding and describing the effects of physical errors in a quantum computation. They allow for simulating the imperfections in state evolution arising from environment-based errors, state preparation routines, measurements, and more.

Here, we show how to use the features provided in PennyLane’s noise module to construct and manipulate noise models, enabling noisy simulation (see the noise module documentation for more details). In PennyLane, noise models are constructed from two main components:

  1. Boolean conditions (referred to as conditionals) that dictate whether noise is inserted into the circuit.

  2. Callables (called noise functions) that apply noise operations when a corresponding condition is satisfied.

The following figure is an example that shows how a noise model transforms a sample circuit by inserting amplitude and phase damping errors for RX and RY gates, respectively.

/_images/noise_model_long.jpg

In the upcoming sections, we will first cover the underlying components of noise models and learn how to use them to construct desired noise models. Finally, we will use our noise model to perform noisy simulations.

Conditionals

We implement conditions as Boolean functions that accept an operation and evaluate it to return a Boolean output. In PennyLane, such objects are referred to as conditionals. They are constructed as instances of BooleanFn and can be combined using standard bitwise operations such as &, |, ^, or ~. PennyLane supports the following types of conditionals:

  1. Operation-based conditionals: They evaluate whether a gate operation is a specific type of operation or belongs to a specified set of operations. They are built using op_eq() and op_in(), respectively.

  2. Wire-based conditionals: They evaluate whether a gate operation’s wires are equal to or are contained in a specified set of wires. They are built using wires_eq() and wires_in(), respectively.

  3. Arbitrary conditionals: Custom conditionals can be defined as a function wrapped with a BooleanFn decorator. The signature for such conditionals must be cond_fn(operation: Operation) -> bool.

For example, here’s how we would define a conditional that checks for RX(ϕ) gate operations with |ϕ|<1.0 and wires {0,1}:

import pennylane as qml
import numpy as np

@qml.BooleanFn def rx_cond(op): return isinstance(op, qml.RX) and np.abs(op.parameters[0]) < 1.0

# Combine this arbitrary conditional with a wire-based conditional rx_and_wires_cond = rx_cond & qml.noise.wires_in([0, 1]) for op in [qml.RX(0.05, wires=[0]), qml.RX(2.34, wires=[1])]: print(f"Result for {op}: {rx_and_wires_cond(op)}")
Result for RX(0.05, wires=[0]): True
Result for RX(2.34, wires=[1]): False

Noise functions

Callables that apply noise operations are referred to as noise functions and have the signature fn(op, **metadata) -> None. Their definition has no return statement and contains the error operations that are inserted when a gate operation in the circuit satisfies corresponding conditional. There are a few ways to construct noise functions:

  1. Single-instruction noise functions: To add a single-operation noise, we can use partial_wires(). It performs a partial initialization of the noise operation and queues it on the wires of the gate operation.

  2. User-defined noise functions: For adding more sophisticated and custom noise, we can define our own quantum function with the signature specified above.

For example, one can use the following to insert a depolarization error and show the error that gets queued with an example gate operation:

depol_error = qml.noise.partial_wires(qml.DepolarizingChannel, 0.01)

op = qml.X('w1') # Example gate operation print(f"Error for {op}: {depol_error(op)}")
Error for X('w1'): DepolarizingChannel(0.01, wires=['w1'])

Creating a noise model

We can now create a PennyLane NoiseModel by stitching together multiple condition-callable pairs, where noise operations are inserted into the circuit when their corresponding condition is satisfied. For the first pair, we will use the previously constructed conditional and callable to insert a depolarization error after RX gates that satisfy |ϕ|<1.0 and that act on the wires {0,1}.

fcond1, noise1 = rx_and_wires_cond, depol_error

Next, we construct a pair to mimic thermal relaxation errors that are encountered during the state preparation via ThermalRelaxationError:

fcond2 = qml.noise.op_eq(qml.StatePrep)

def noise2(op, **kwargs): for wire in op.wires: qml.ThermalRelaxationError(0.1, kwargs["t1"], kwargs["t2"], kwargs["tg"], wire)

By default, noise operations specified by a noise function will be inserted after the gate operation that satisfies the conditional. However, they can be inserted in a custom order by manually queuing the evaluated gate operation via apply() within the function definition. For example, we can add a sandwiching constant-valued rotation error for Hadamard gates on the wires {0,1}:

fcond3 = qml.noise.op_eq("Hadamard") & qml.noise.wires_in([0, 1])

def noise3(op, **kwargs): qml.RX(np.pi / 16, op.wires) qml.apply(op) qml.RY(np.pi / 8, op.wires)

Finally, we can build the noise model with some required metadata for noise2:

metadata = dict(t1=0.02, t2=0.03, tg=0.001)  # times unit: sec
noise_model = qml.NoiseModel(
    {fcond1: noise1, fcond2: noise2, fcond3: noise3}, **metadata
)
print(noise_model)
NoiseModel({
    rx_cond & WiresIn([0, 1]): DepolarizingChannel(p=0.01)
    OpEq(StatePrep): noise2
    OpEq(Hadamard) & WiresIn([0, 1]): noise3
}, t1 = 0.02, t2 = 0.03, tg = 0.001)

Adding noise models to your workflow

Now that we have built our noise model, we can learn how to use it. A noise model can be applied to a circuit or device via the add_noise() transform. For example, consider the following circuit that performs the evolution and de-evolution of a given initial state based on some parameters:

from matplotlib import pyplot as plt

qml.drawer.use_style("pennylane") dev = qml.device("default.mixed", wires=3) init_state = np.random.RandomState(42).rand(2 ** len(dev.wires)) init_state /= np.linalg.norm(init_state)

def circuit(theta, phi): # State preparation qml.StatePrep(init_state, wires=[0, 1, 2])

# Evolve state qml.Hadamard(0) qml.RX(theta, 1) qml.RX(phi, 2) qml.CNOT([1, 2]) qml.CNOT([0, 1])

# De-evolve state qml.CNOT([0, 1]) qml.CNOT([1, 2]) qml.RX(-phi, 2) qml.RX(-theta, 1) qml.Hadamard(0) return qml.state()

theta, phi = 0.21, 0.43 ideal_circuit = qml.QNode(circuit, dev) qml.draw_mpl(ideal_circuit)(theta, phi) plt.show()
tutorial how to use noise models

To attach the noise_model to this quantum circuit, we use the add_noise() transform:

noisy_circuit = qml.add_noise(ideal_circuit, noise_model)
qml.draw_mpl(noisy_circuit)(theta, phi)
plt.show()
tutorial how to use noise models

We can then use the noisy_circuit to run noisy simulations as shown below:

init_dm = np.outer(init_state, init_state) # density matrix for the init_state
ideal_res = np.round(qml.math.fidelity(ideal_circuit(theta, phi), init_dm), 8)
noisy_res = np.round(qml.math.fidelity(noisy_circuit(theta, phi), init_dm), 8)

print(f"Ideal v/s Noisy: {ideal_res} and {noisy_res}")
Ideal v/s Noisy: 1.00000002 and 0.90174224

The fidelity for the state obtained from the ideal circuit is 1.0, which is expected since our circuit effectively does nothing to the initial state. We see that this is not the case for the result obtained from the noisy simulation, due to the error operations inserted in the circuit.

Conclusion

Noise models provide a succinct way to describe the impact of the environment on quantum computation. In PennyLane, we define such models as mapping between conditionals that select the target operation and their corresponding noise operations. These can be constructed with utmost flexibility as we showed here.

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 on noise, or create a post on the PennyLane Discussion Forum. You can also follow us on X (formerly Twitter) or LinkedIn to stay up-to-date with the latest and greatest from PennyLane!

Total running time of the script: (0 minutes 0.615 seconds)

Utkarsh Azad

Utkarsh Azad

Fractals, computing and poetry.

Total running time of the script: (0 minutes 0.615 seconds)