qml.noise

This module contains the functionality for building and manipulating insertion-based noise models, where noisy gates and channels are inserted based on the target operations and measurements.

Overview

Insertion-based noise models in PennyLane are defined via a mapping from conditionals, specified as BooleanFn objects, to quantum function-like callables that contain the noisy operations to be applied, but without any return statements. Additional noise-related metadata can also be supplied to construct a noise model using:

NoiseModel(model_map[, meas_map])

Builds a noise model based on the mappings of conditionals to callables that define noise operations using some optional metadata.

Each conditional in the model_map (and meas_map) evaluates the gate operations (and terminal measurments) in the quantum circuit based on some condition of its attributes (e.g., type, parameters, wires, etc.) and uses the corresponding callable to apply the noise operations, using the user-provided metadata (e.g., hardware topologies or relaxation times), whenever the condition is true. A noise model, once built, can be attached to a circuit or device via the following transform:

add_noise(tape, noise_model[, level])

Insert operations according to a provided noise model.

Boolean functions

Each BooleanFn in the noise model is evaluated on the operations of a given quantum circuit. One can construct standard Boolean functions using the following helpers:

meas_eq(mps)

Builds a conditional as a BooleanFn for evaluating if a given measurement process is equal to the specified measurement process.

op_eq(ops)

Builds a conditional as a BooleanFn for evaluating if a given operation is equal to the specified operation.

op_in(ops)

Builds a conditional as a BooleanFn for evaluating if a given operation exist in a specified set of operations.

wires_eq(wires)

Builds a conditional as a BooleanFn for evaluating if a given wire is equal to specified set of wires.

wires_in(wires)

Builds a conditional as a BooleanFn for evaluating if the wires of an input operation are within the specified set of wires.

For example, a Boolean function that checks if an operation is on wire 0 can be created as follows:

>>> fn = qml.noise.wires_eq(0)
>>> op1, op2 = qml.PauliX(0), qml.PauliX(1)
>>> fn(op1)
True
>>> fn(op2)
False

Arbitrary Boolean functions can also be defined by wrapping the functional form of custom conditions with the following decorator:

BooleanFn(fn[, name])

Wrapper for simple callables with Boolean output that can be manipulated and combined with bitwise operators.

For example, a Boolean function can be created to identify an RX gate with a maximum parameter value:

@qml.BooleanFn
def rx_condition(op, **metadata):
    return isinstance(op, qml.RX) and op.parameters[0] < 1.0

Boolean functions can be combined using standard bitwise operators, such as &, |, ^, or ~. The result will be another Boolean function. It is important to note that as Python will evaluate the expression in the order of their combination, i.e., left to right, the order of composition could matter, even though bitwise operations are symmetric by definition.

Noisy quantum functions

If a Boolean function evaluates to True on a given operation in the quantum circuit, the corresponding quantum function is evaluated that inserts the noise directly after the operation. The quantum function should have signature fn(op, **metadata), allowing for dependency on both the preceding operation and metadata specified in the noise model. For example, the following noise model adds an over-rotation to the RX gate:

def noisy_rx(op, **metadata):
    qml.RX(op.parameters[0] * 0.05, op.wires)

noise_model = qml.NoiseModel({rx_condition: noisy_rx})

A common use case is to have a single-operation noise channel whose wires are the same as the preceding operation. This can be constructed using:

partial_wires(operation, *args, **kwargs)

Builds a partial function based on the given gate operation or measurement process with all argument frozen except wires.

For example, a constant-valued over-rotation can be created using:

>>> rx_constant = qml.noise.partial_wires(qml.RX(0.1, wires=[0]))
>>> rx_constant(2)
RX(0.1, 2)
>>> qml.NoiseModel({rx_condition: rx_constant})
NoiseModel({
    BooleanFn(rx_condition): RX(phi=0.1)
})

Example noise model

The following example shows how to set up an artificial noise model in PennyLane:

# Set up the conditions
c0 = qml.noise.op_eq(qml.PauliX) | qml.noise.op_eq(qml.PauliY)
c1 = qml.noise.op_eq(qml.Hadamard) & qml.noise.wires_in([0, 1])
c2 = qml.noise.op_eq(qml.RX)

@qml.BooleanFn
def c3(op, **metadata):
    return isinstance(op, qml.RY) and op.parameters[0] >= 0.5

# Set up noisy ops
n0 = qml.noise.partial_wires(qml.AmplitudeDamping, 0.4)

def n1(op, **metadata):
    ThermalRelaxationError(0.4, metadata["t1"], 0.2, 0.6, op.wires)

def n2(op, **metadata):
    qml.RX(op.parameters[0] * 0.05, op.wires)

n3 = qml.noise.partial_wires(qml.PhaseDamping, 0.9)

# Set up noise model
noise_model = qml.NoiseModel({c0: n0, c1: n1, c2: n2}, t1=0.04)
noise_model += {c3: n3}  # One-at-a-time construction
>>> noise_model
NoiseModel({
    OpEq(PauliX) | OpEq(PauliY): AmplitudeDamping(gamma=0.4)
    OpEq(Hadamard) & WiresIn([0, 1]): n1
    OpEq(RX): n2
    BooleanFn(c3): PhaseDamping(gamma=0.9)
}, t1 = 0.04)

API overview

The following are the BooleanFn objects created by calling the helper functions above, such as op_eq(). These objects do not need to be instantiated directly

MeasEq(mps)

A conditional for evaluating if a given measurement process is equal to the specified measurement process.

OpEq(ops)

A conditional for evaluating if a given operation is equal to the specified operation.

OpIn(ops)

A conditional for evaluating if a given operation exist in a specified set of operations.

WiresEq(wires)

A conditional for evaluating if a given wire is equal to a specified set of wires.

WiresIn(wires)

A conditional for evaluating if the wires of an operation exist in a specified set of wires.

Bitwise operations like And and Or are represented with the following classes in the boolean_fn module:

And(left, right)

Developer facing class for implemeting bitwise AND for callables wrapped up with BooleanFn.

Or(left, right)

Developer facing class for implemeting bitwise OR for callables wrapped up with BooleanFn.

Xor(left, right)

Developer facing class for implemeting bitwise XOR for callables wrapped up with BooleanFn.

Not(left)

Developer facing class for implemeting bitwise NOT for callables wrapped up with BooleanFn.

Class Inheritence Diagram

Note all child classes inherit from the same parent BooleanFn, but are just located in different modules.

Noise Conditionals:

Inheritance diagram of pennylane.noise.conditionals

Boolean Fn conditionals:

Inheritance diagram of pennylane.boolean_fn