



PennyLane 0.32.0 documentation

[![](_static/navbar.svg)](https://pennylane.ai)

* [Learn](https://pennylane.ai/qml/)

	+ [Demos](https://pennylane.ai/qml/)

	+ [Codebook](https://codebook.xanadu.ai/)

	+ [Videos](https://pennylane.ai/qml/videos/)

	+ [Glossary](https://pennylane.ai/qml/glossary/)

	+ [Education](https://pennylane.ai/education/)

	+ [FAQ](https://pennylane.ai/faq/)

* [Documentation](https://docs.pennylane.ai)

	+ [API](https://docs.pennylane.ai/en/stable/code/qml.html)

	+ [Devices](https://pennylane.ai/plugins/)

	+ [GitHub](https://github.com/PennyLaneAI/pennylane)

	+ [Catalyst](https://docs.pennylane.ai/projects/catalyst/)

* [Datasets](https://pennylane.ai/datasets/)

* [Blog](https://pennylane.ai/blog/)

* [Support](https://discuss.pennylane.ai)

* 

* [Install](https://pennylane.ai/install)

* Learn

	+ [Learn](https://pennylane.ai/qml/)

	+ [Demos](https://pennylane.ai/qml/)

	+ [Codebook](https://codebook.xanadu.ai/)

	+ [Videos](https://pennylane.ai/qml/videos/)

	+ [Glossary](https://pennylane.ai/qml/glossary/)

	+ [Education](https://pennylane.ai/education/)

	+ [FAQ](https://pennylane.ai/faq/)

* Documentation

	+ [Documentation](https://docs.pennylane.ai)

	+ [API](https://docs.pennylane.ai/en/stable/code/qml.html)

	+ [Devices](https://pennylane.ai/plugins/)

	+ [GitHub](https://github.com/PennyLaneAI/pennylane)

	+ [Catalyst](https://docs.pennylane.ai/projects/catalyst/)

* [Datasets](https://pennylane.ai/datasets/)

* [Blog](https://pennylane.ai/blog/)

* [Support](https://discuss.pennylane.ai)

* [GitHub](https://github.com/PennyLaneAI/pennylane)

* [Install](https://pennylane.ai/install)

### Navigation

* [PennyLane 0.32.0 documentation](#) »

* PennyLane 0.32.0 documentation

Table of contents

Search

Using PennyLane

* [What is PennyLane?](index.html#document-introduction/pennylane)

* [Quantum circuits](index.html#document-introduction/circuits)

* [Gradients and training](index.html#document-introduction/interfaces)

* [Quantum operators](index.html#document-introduction/operations)

* [Measurements](index.html#document-introduction/measurements)

* [Templates](index.html#document-introduction/templates)

* [Inspecting circuits](index.html#document-introduction/inspecting_circuits)

* [Compiling circuits](index.html#document-introduction/compiling_circuits)

* [Quantum Chemistry](index.html#document-introduction/chemistry)

* [Quantum Datasets](index.html#document-introduction/data)

* [QNode returns](index.html#document-introduction/returns)

* [Logging](index.html#document-introduction/logging)

Development

* [Development guide](index.html#document-development/guide)

* [Building a plugin](index.html#document-development/plugins)

* [Adding new operators](index.html#document-development/adding_operators)

* [Deprecations](index.html#document-development/deprecations)

* [Release notes](index.html#document-development/release_notes)

API

* [qml](index.html#document-code/qml)

* [qml.data](index.html#document-code/qml_data)

* [qml.drawer](index.html#document-code/qml_drawer)

* [qml.fermi](index.html#document-code/qml_fermi)

* [qml.fourier](index.html#document-code/qml_fourier)

* [qml.gradients](index.html#document-code/qml_gradients)

* [qml.kernels](index.html#document-code/qml_kernels)

* [qml.logging](index.html#document-code/qml_logging)

* [qml.math](index.html#document-code/qml_math)

* [qml.numpy](index.html#document-code/qml_numpy)

* [qml.ops.op\_math](index.html#document-code/qml_ops_op_math)

* [qml.pauli](index.html#document-code/qml_pauli)

* [qml.pulse](index.html#document-code/qml_pulse)

* [qml.qinfo](index.html#document-code/qml_qinfo)

* [qml.resource](index.html#document-code/qml_resource)

* [qml.shadows](index.html#document-code/qml_shadows)

* [qml.transforms](index.html#document-code/qml_transforms)

* [qml.qaoa](index.html#document-code/qml_qaoa)

* [qml.qchem](index.html#document-code/qml_qchem)

* [qml.qnn](index.html#document-code/qml_qnn)

Internals

* [qml.devices](index.html#document-code/qml_devices)

* [qml.interfaces](index.html#document-code/qml_interfaces)

* [qml.measurements](index.html#document-code/qml_measurements)

* [qml.operation](index.html#document-code/qml_operation)

* [qml.queuing](index.html#document-code/qml_queuing)

* [qml.tape](index.html#document-code/qml_tape)

* [qml.utils](index.html#document-code/qml_utils)

* [qml.wires](index.html#document-code/qml_wires)

1. [Docs](#)

2. PennyLane 0.32.0 documentation

PennyLane Documentation[¶](#pennylane-documentation "Permalink to this headline")

=================================================================================

Release

0.32.0

 .breadcrumb {

 display: none;

 }

 h1 {

 text-align: center;

 margin-bottom: 15px;

 }

 p.lead.grey-text {

 margin-bottom: 30px;

 }

 .footer-relations {

 border-top: 0px;

 }

 PennyLane is a cross-platform Python library for differentiable

 programming of quantum computers. Train a quantum computer the same

 way as a neural network.

 

[### 

 Using PennyLane

 A guided tour of the core features of PennyLane](introduction/pennylane.html)

[### 

 Developing

 How you can contribute to the development of PennyLane](development/guide.html)

[### 

 API

 Explore the PennyLane API](code/qml.html)

Features[¶](#features "Permalink to this headline")

---------------------------------------------------

[![_images/header-tall.png](_images/header-tall.png)](javascript:void(0);)

* *Follow the gradient*.

Built-in **automatic differentiation** of quantum circuits.

* *Best of both worlds*.

Support for **hybrid quantum and classical** models; connect quantum

hardware with PyTorch, TensorFlow, and NumPy.

* *Just in time compilation*. Compile your **entire hybrid workflow**, with support for

adaptive circuits, real-time measurement feedback, unbounded loops, and more. See

[Catalyst](https://github.com/pennylaneai/catalyst) for more details.

* *Batteries included*.

Provides **optimization and machine learning** tools.

* *Device-independent*.

The same quantum circuit model can be **run on different backends**. Install

[plugins](https://pennylane.ai/plugins.html) to access even more

devices, including **Strawberry Fields**, **Amazon Braket**, **IBM Q**, **Google Cirq**, **Rigetti Forest**,

**Microsoft QDK**, and **ProjectQ**.

Getting started[¶](#getting-started "Permalink to this headline")

-----------------------------------------------------------------

For an introduction to quantum machine learning, we have several guides and resources available

on our [QML website](https://pennylane.ai/qml/), including

[What is QML?](https://pennylane.ai/qml/whatisqml.html),

[frequently asked questions](https://pennylane.ai/faq.html),

a [glossary of key concepts](https://pennylane.ai/qml/glossary.html), and a curated selection

of [QML videos](https://pennylane.ai/qml/videos.html).

Then, take a deeper dive into quantum machine learning by

exploring cutting-edge algorithms using PennyLane and near-term quantum hardware,

with our collection of

[QML demonstrations](https://pennylane.ai/qml/demonstrations.html).

You can also check out the [Using PennyLane](index.html#document-introduction/pennylane) section for

more details on the [quantum operations](index.html#document-introduction/operations), and to explore

the available [optimization tools](index.html#document-introduction/interfaces) provided by PennyLane.

We also have a detailed guide on [how to write your own](index.html#document-development/plugins)

PennyLane-compatible quantum device.

Finally, play around with the numerous [devices and plugins](https://pennylane.ai/plugins.html)

available for running your hybrid optimizations—these include

IBM Q, provided by the [PennyLane-Qiskit](https://pennylaneqiskit.rtfd.io) plugin,

as well as the Rigetti Aspen QPU provided by [PennyLane-Forest](https://pennylane-forest.rtfd.io).

How to cite[¶](#how-to-cite "Permalink to this headline")

---------------------------------------------------------

If you are doing research using PennyLane, please cite

Ville Bergholm et al. *PennyLane: Automatic differentiation of hybrid

quantum-classical computations.* 2018. [arXiv:1811.04968](https://arxiv.org/abs/1811.04968)

Support and contribution[¶](#support-and-contribution "Permalink to this headline")

-----------------------------------------------------------------------------------

* **Source Code:** <https://github.com/PennyLaneAI/pennylane>

* **Issue Tracker:** <https://github.com/PennyLaneAI/pennylane/issues>

If you are having issues, please let us know by posting the issue on our GitHub issue tracker.

We encourage contributions — simply fork the PennyLane repository, and then make a

[pull request](https://help.github.com/articles/about-pull-requests/) containing

your contribution. All contributers to PennyLane will be listed as authors on the releases.

To chat directly with the team designing and building PennyLane, as well as members of

our community — ranging from quantum machine learning researchers, to students, to those

just interested in being a part of a rapidly growing industry — you can join our

[discussion forum](https://discuss.pennylane.ai).

License[¶](#license "Permalink to this headline")

-------------------------------------------------

PennyLane is **free** and **open source**, released under the Apache License, Version 2.0.

### What is PennyLane?[¶](#what-is-pennylane "Permalink to this headline")

[![_images/code.png](_images/code.png)](javascript:void(0);)

  

PennyLane is a cross-platform Python library for programming quantum computers.

Its differentiable programming paradigm enables the execution and training of quantum programs on various backends.

PennyLane connects quantum computing with powerful machine learning frameworks

like [NumPy](https://numpy.org/)’s [autograd](https://github.com/HIPS/autograd),

[JAX](https://github.com/google/jax),

[PyTorch](https://pytorch.org/), and [TensorFlow](https://www.tensorflow.org/),

making them quantum-aware.

Its central job is to manage the execution of quantum computations, including

the evaluation of circuits and the computation of their gradients.

This information is forwarded to the classical

framework, creating seamless quantum-classical pipelines for applications.

  

[![_images/jigsaw.png](_images/jigsaw.png)](javascript:void(0);)

PennyLane’s design principle states that

circuits can be run on various kinds of simulators or hardware devices without making any changes –

the complex job of optimising communication with the devices, compiling circuits to suit the backend,

and choosing the best gradient strategies is taken care of.

The library comes with default simulator devices, but is well-integrated with

[external software and hardware](https://pennylane.ai/plugins.html) to run quantum

circuits—such as IBM’s Qiskit, or Google’s Cirq, Rigetti’s Forest, or Xanadu’s Strawberry Fields.

### Quantum circuits[¶](#quantum-circuits "Permalink to this headline")

[![_images/qnode.png](_images/qnode.png)](javascript:void(0);)

In PennyLane, quantum computations, which involve the execution of one or more quantum circuits,

are represented as *quantum node* objects. A quantum node is used to

declare the quantum circuit, and also ties the computation to a specific device that executes it.

QNodes can interface with any of the supported numerical and machine learning libraries—[NumPy](index.html#document-introduction/interfaces/numpy),

[PyTorch](index.html#document-introduction/interfaces/torch), [TensorFlow](index.html#document-introduction/interfaces/tf), and

[JAX](index.html#document-introduction/interfaces/jax)—indicated by providing an optional `interface` argument

when creating a QNode. Each interface allows the quantum circuit to integrate seamlessly with

library-specific data structures (e.g., NumPy and JAX arrays or Pytorch/TensorFlow tensors) and

[optimizers](index.html#document-introduction/interfaces).

By default, QNodes use the NumPy interface. The other PennyLane interfaces are

introduced in more detail in the section on [interfaces](index.html#document-introduction/interfaces).

#### Quantum functions[¶](#quantum-functions "Permalink to this headline")

A quantum circuit is constructed as a special Python function, a

*quantum circuit function*, or *quantum function* in short.

For example:

```

import pennylane as qml

def my\_quantum\_function(x, y):

    qml.RZ(x, wires=0)

    qml.CNOT(wires=[0,1])

    qml.RY(y, wires=1)

    return qml.expval(qml.PauliZ(1))

```

Note

PennyLane uses the term *wires* to refer to a quantum subsystem—for most

devices, this corresponds to a qubit. For continuous-variable

devices, a wire corresponds to a quantum mode.

Quantum functions are a restricted subset of Python functions, adhering to the following

constraints:

* The quantum function accepts classical inputs, and consists of

[quantum operators](index.html#document-introduction/operations) or sequences of operators called [Templates](index.html#document-introduction/templates).

* The function can contain classical flow control structures such as `for` loops or `if` statements.

* The quantum function must always return either a single or a tuple of

*measurement values*, by applying a [measurement function](index.html#document-introduction/measurements)

to the qubit register. The most common example is to measure the expectation value of

a [qubit observable](index.html#intro-ref-ops-qobs) or

[continuous-value observable](index.html#intro-ref-ops-cvobs).

Note

Quantum functions are evaluated on a device from within a QNode.

#### Defining a device[¶](#defining-a-device "Permalink to this headline")

To run—and later optimize—a quantum circuit, one needs to first specify a *computational device*.

The device is an instance of the [`Device`](index.html#pennylane.Device "pennylane.Device")

class, and can represent either a simulator or hardware device. They can be

instantiated using the [`device`](index.html#pennylane.device "pennylane.device") loader.

```

dev = qml.device('default.qubit', wires=2, shots=1000)

```

PennyLane offers some basic devices such as the `'default.qubit'`, `'default.mixed'`, `lightning.qubit`,

and `'default.gaussian'` simulators; additional devices can be installed as plugins (see

[available plugins](https://pennylane.ai/plugins.html) for more details). Note that the

choice of a device significantly determines the speed of your computation, as well as

the available options that can be passed to the device loader.

Note

For example, check out the `'lightning.gpu'`

[plugin](https://docs.pennylane.ai/projects/lightning-gpu/en/latest/index.html),

which is a fast state-vector simulator offloading to the NVIDIA cuQuantum SDK for GPU accelerated circuit simulation.

Note

For details on saving device configurations, please visit the

[configurations page](index.html#document-introduction/configuration).

##### Device options[¶](#device-options "Permalink to this headline")

When loading a device, the name of the device must always be specified.

Further options can then be passed as keyword arguments, and can differ based

on the device. For a plugin device, refer to the plugin documentation for available device options.

The two most important device options are the `wires` and `shots` arguments.

###### Wires[¶](#wires "Permalink to this headline")

The wires argument can be an integer that defines the *number of wires*

that you can address by consecutive integer labels `0, 1, 2, ...`.

```

dev = qml.device('default.qubit', wires=3)

```

Alternatively, you can use custom labels by passing an iterable that contains unique labels for the subsystems:

```

dev\_unique\_wires = qml.device('default.qubit', wires=['aux', 'q1', 'q2'])

```

In the quantum function you can now use your own labels to address wires:

```

def my\_quantum\_function(x, y):

    qml.RZ(x, wires='q1')

    qml.CNOT(wires=['aux' ,'q1'])

    qml.RY(y, wires='q2')

    return qml.expval(qml.PauliZ('q2'))

```

Allowed wire labels can be of any type that is hashable, which allows two wires to be uniquely distinguished.

Note

Some devices, such as hardware chips, may have a fixed number of wires.

The iterable of labels passed to the device’s `wires`

argument must match this expected number of wires.

Warning

In order to support wire labels of any hashable type, integers and 0-d arrays are considered different.

For example, running `qml.RX(1.1, qml.numpy.array(0))` on a device initialized with `wires=[0]`

will fail because `qml.numpy.array(0)` does not exist in the device’s wire map.

###### Shots[¶](#shots "Permalink to this headline")

The `shots` argument is an integer that defines how many times the circuit should be evaluated (or “sampled”)

to estimate statistical quantities. On some supported simulator devices, `shots=None` computes

measurement statistics *exactly*.

Note that this argument can be temporarily overwritten when a QNode is called. For example, `my\_qnode(shots=3)`

will temporarily evaluate `my\_qnode` using three shots. This is a feature of each QNode and it is not

necessary to manually implement the `shots` keyword argument of the quantum function.

It is sometimes useful to retrieve the result of a computation for different shot numbers without evaluating a

QNode several times (“shot batching”). Batches of shots can be specified by passing a list of integers,

allowing measurement statistics to be course-grained with a single QNode evaluation.

Consider

```

>>> shots\_list = [5, 10, 1000]

>>> dev = qml.device("default.qubit", wires=2, shots=shots\_list)

```

When QNodes are executed on this device, a single execution of 1015 shots will be submitted.

However, three sets of measurement statistics will be returned; using the first 5 shots,

second set of 10 shots, and final 1000 shots, separately.

For example:

```

@qml.qnode(dev)

def circuit(x):

    qml.RX(x, wires=0)

    qml.CNOT(wires=[0, 1])

    return qml.expval(qml.PauliZ(0) @ qml.PauliX(1)), qml.expval(qml.PauliZ(0))

```

Executing this, we will get an output of shape `(3, 2)`:

```

>>> results = circuit(0.5)

>>> results

((array(0.6), array(1.)),

 (array(-0.4), array(1.)),

 (array(0.048), array(0.902)))

```

We can index into this tuple and retrieve the results computed with only 5 shots:

```

>>> results[0]

(array(0.6), array(1.))

```

#### Creating a quantum node[¶](#creating-a-quantum-node "Permalink to this headline")

Together, a quantum function and a device are used to create a *quantum node* or

[`QNode`](index.html#pennylane.QNode "pennylane.QNode") object, which wraps the quantum function and binds it to the device.

A QNode can be explicitly created as follows:

```

circuit = qml.QNode(my\_quantum\_function, dev\_unique\_wires)

```

The QNode can be used to compute the result of a quantum circuit as if it was a standard Python

function. It takes the same arguments as the original quantum function:

```

>>> circuit(np.pi/4, 0.7)

tensor(0.764, requires\_grad=True)

```

To view the quantum circuit given specific parameter values, we can use the [`draw()`](index.html#pennylane.draw "pennylane.draw")

transform,

```

>>> print(qml.draw(circuit)(np.pi/4, 0.7))

aux: ───────────╭●─┤

 q1: ──RZ(0.79)─╰X─┤

 q2: ──RY(0.70)────┤ <Z>

```

or the [`draw\_mpl()`](index.html#pennylane.draw_mpl "pennylane.draw_mpl") transform:

```

>>> import matplotlib.pyplot as plt

>>> qml.drawer.use\_style("black\_white")

>>> fig, ax = qml.draw\_mpl(circuit)(np.pi/4, 0.7)

>>> plt.show()

```

[![_images/draw_mpl.png](_images/draw_mpl.png)](javascript:void(0);)

#### The QNode decorator[¶](#the-qnode-decorator "Permalink to this headline")

A more convenient—and in fact the recommended—way for creating QNodes is the provided

`qnode` decorator. This decorator converts a Python function containing PennyLane quantum

operations to a [`QNode`](index.html#pennylane.QNode "pennylane.QNode") circuit that will run on a quantum device.

Note

The decorator completely replaces the Python-based quantum function with

a [`QNode`](index.html#pennylane.QNode "pennylane.QNode") of the same name—as such, the original

function is no longer accessible.

For example:

```

dev = qml.device('default.qubit', wires=2)

@qml.qnode(dev)

def circuit(x):

    qml.RZ(x, wires=0)

    qml.CNOT(wires=[0,1])

    qml.RY(x, wires=1)

    return qml.expval(qml.PauliZ(1))

result = circuit(0.543)

```

#### Parameter Broadcasting in QNodes[¶](#parameter-broadcasting-in-qnodes "Permalink to this headline")

Depending on the quantum operations used, a [`QNode`](index.html#pennylane.QNode "pennylane.QNode") may support execution at multiple parameters simultaneously:

```

>>> x = np.array([0.543, 1.234])

>>> result = circuit(x)

>>> result

tensor([0.85616242, 0.33046511], requires\_grad=True)

```

Note that we are passing in a 1-dimensional array of parameters to the circuit()

QNode defined above, which takes a single parameter and returns a single expectation

value. As the input is now an array, the output is also an array, with each

element the expectation value of the corresponding input element.

This is called *parameter broadcasting* (as for, say, NumPy functions executed along an axis)

or *parameter batching* (as in the application of a function to a *batch* of parameters in

machine learning).

In addition to a more flexible execution syntax, broadcasting can yield performance boosts

compared to the separate execution of the QNode for each parameter setting. Whether or not this is

the case depends on quite a few details, but in particular for (at most) moderately sized circuits

(\(\lesssim 20\) wires) with a moderate number of parameters (\(\lesssim 200\)) executed

on a classical simulator, one can expect to benefit from broadcasting.

See the [`QNode`](index.html#pennylane.QNode "pennylane.QNode") documentation for usage details.

Many standard quantum operators support broadcasting; see the corresponding attribute

[`supports\_broadcasting`](index.html#pennylane.ops.qubit.attributes.supports_broadcasting "pennylane.ops.qubit.attributes.supports_broadcasting") for a list. The

[`Operator`](index.html#pennylane.operation.Operator "pennylane.operation.Operator") documentation contains implementation details

and a guide to make custom operators compatible with broadcasting.

Broadcasting can be used with any device, but will usually only yield performance upgrades for

devices like `"default.qubit"` that indicate that they support it:

```

>>> cap = dev.capabilities()

>>> cap["supports\_broadcasting"]

True

```

Other devices separate the parameters and execute the QNode sequentially.

#### Importing circuits from other frameworks[¶](#importing-circuits-from-other-frameworks "Permalink to this headline")

PennyLane supports creating customized PennyLane templates imported from other

frameworks. By loading your existing quantum code as a PennyLane template, you

add the ability to perform analytic differentiation, and interface with machine

learning libraries such as PyTorch and TensorFlow. Currently, `QuantumCircuit`

objects from Qiskit, OpenQASM files, pyQuil `programs`, and Quil files can

be loaded by using the following functions:

| [`from\_qiskit`](index.html#pennylane.from_qiskit "pennylane.from_qiskit") | Loads Qiskit QuantumCircuit objects by using the converter in the PennyLane-Qiskit plugin. |

| [`from\_qasm`](index.html#pennylane.from_qasm "pennylane.from_qasm") | Loads quantum circuits from a QASM string using the converter in the PennyLane-Qiskit plugin. |

| [`from\_qasm\_file`](index.html#pennylane.from_qasm_file "pennylane.from_qasm_file") | Loads quantum circuits from a QASM file using the converter in the PennyLane-Qiskit plugin. |

| [`from\_pyquil`](index.html#pennylane.from_pyquil "pennylane.from_pyquil") | Loads pyQuil Program objects by using the converter in the PennyLane-Forest plugin. |

| [`from\_quil`](index.html#pennylane.from_quil "pennylane.from_quil") | Loads quantum circuits from a Quil string using the converter in the PennyLane-Forest plugin. |

| [`from\_quil\_file`](index.html#pennylane.from_quil_file "pennylane.from_quil_file") | Loads quantum circuits from a Quil file using the converter in the PennyLane-Forest plugin. |

Note

To use these conversion functions, the latest version of the PennyLane-Qiskit

and PennyLane-Forest plugins need to be installed.

Objects for quantum circuits can be loaded outside or directly inside of a

[`QNode`](index.html#pennylane.QNode "pennylane.QNode"). Circuits that contain unbound parameters are also

supported. Parameter binding may happen by passing a dictionary containing the

parameter-value pairs.

Once a PennyLane template has been created from such a quantum circuit, it can

be used similarly to other [templates](index.html#document-introduction/templates) in PennyLane. One important thing to note

is that custom templates must always be executed

within a [`QNode`](index.html#pennylane.QNode "pennylane.QNode") (similar to pre-defined templates).

Note

Certain instructions that are specific to the external frameworks might be

ignored when loading an external quantum circuit. Warning messages will

be emitted for ignored instructions.

The following is an example of loading and calling a parametrized Qiskit `QuantumCircuit` object

while using the [`QNode`](index.html#pennylane.QNode "pennylane.QNode") decorator:

```

from qiskit import QuantumCircuit

from qiskit.circuit import Parameter

import numpy as np

dev = qml.device('default.qubit', wires=2)

theta = Parameter('θ')

qc = QuantumCircuit(2)

qc.rz(theta, [0])

qc.rx(theta, [0])

qc.cx(0, 1)

@qml.qnode(dev)

def quantum\_circuit\_with\_loaded\_subcircuit(x):

    qml.from\_qiskit(qc)({theta: x})

    return qml.expval(qml.PauliZ(0))

angle = np.pi/2

result = quantum\_circuit\_with\_loaded\_subcircuit(angle)

```

Furthermore, loaded templates can be used with any supported device, any number of times.

For instance, in the following example a template is loaded from a QASM string,

and then used multiple times on the `forest.qpu` device provided by PennyLane-Forest:

```

import pennylane as qml

dev = qml.device('forest.qpu', wires=2)

hadamard\_qasm = 'OPENQASM 2.0;' \

                'include "qelib1.inc";' \

                'qreg q[1];' \

                'h q[0];'

apply\_hadamard = qml.from\_qasm(hadamard\_qasm)

@qml.qnode(dev)

def circuit\_with\_hadamards():

    apply\_hadamard(wires=[0])

    apply\_hadamard(wires=[1])

    qml.Hadamard(wires=[1])

    return qml.expval(qml.PauliX(0)), qml.expval(qml.PauliX(1))

result = circuit\_with\_hadamards()

```

### Gradients and training[¶](#gradients-and-training "Permalink to this headline")

PennyLane offers seamless integration between classical and quantum computations. Code up quantum

circuits in PennyLane, compute [gradients of quantum circuits](https://pennylane.ai/qml/glossary/quantum_gradient.html "(in PennyLane)"), and

connect them easily to the top scientific computing and machine learning libraries.

#### Training and interfaces[¶](#training-and-interfaces "Permalink to this headline")

The bridge between the quantum and classical worlds is provided in PennyLane via interfaces to

automatic differentiation libraries.

Currently, four libraries are supported: [NumPy](index.html#document-introduction/interfaces/numpy), [PyTorch](index.html#document-introduction/interfaces/torch), [JAX](index.html#document-introduction/interfaces/jax), and [TensorFlow](index.html#document-introduction/interfaces/tf). PennyLane makes

each of these libraries quantum-aware, allowing quantum circuits to be treated just

like any other operation. Any automatic differentiation framework can be chosen with any device.

In PennyLane, an automatic differentiation framework is declared using the `interface` argument when creating

a [`QNode`](index.html#pennylane.QNode "pennylane.QNode"), e.g.,

```

@qml.qnode(dev, interface="tf")

def my\_quantum\_circuit(...):

    ...

```

Note

If no interface is specified, PennyLane will automatically determine the interface based on provided arguments and keyword arguments.

This will allow native numerical objects of the specified library (NumPy arrays, JAX arrays, Torch Tensors,

or TensorFlow Tensors) to be passed as parameters to the quantum circuit. It also makes

the gradients of the quantum circuit accessible to the classical library, enabling the

optimization of arbitrary hybrid circuits by making use of the library’s native optimizers.

When specifying an interface, the objects of the chosen framework are converted

into NumPy objects and are passed to a device in most cases. Exceptions include

cases when the devices support end-to-end computations in a framework. Such

devices may be referred to as backpropagation or passthru devices.

See the links below for walkthroughs of each specific interface:

 #interfaces .card {

 box-shadow: none!important;

 }

 #interfaces .card:hover {

 box-shadow: none!important;

 }

[![](../_static/numpy.png)](interfaces/numpy.html)

[![](../_static/pytorch.png)](interfaces/torch.html)

[![](../_static/tensorflow.png)](interfaces/tf.html)

[![](../_static/jax.png)](interfaces/jax.html)

In addition to the core automatic differentiation frameworks discussed above,

PennyLane also provides higher-level classes for converting QNodes into both Keras and `torch.nn` layers:

| [`pennylane.qnn.KerasLayer`](index.html#pennylane.qnn.KerasLayer "pennylane.qnn.KerasLayer")(\*args, \*\*kwargs) | Converts a [`QNode`](index.html#pennylane.QNode "pennylane.QNode") to a Keras [Layer](https://www.tensorflow.org/api_docs/python/tf/keras/layers/Layer). |

| [`pennylane.qnn.TorchLayer`](index.html#pennylane.qnn.TorchLayer "pennylane.qnn.TorchLayer")(qnode, weight\_shapes) | Converts a [`QNode`](index.html#pennylane.QNode "pennylane.QNode") to a Torch layer. |

Note

QNodes that allow for automatic differentiation will always incur a small overhead on evaluation.

If you do not need to compute quantum gradients of a QNode, specifying `interface=None` will remove

this overhead and result in a slightly faster evaluation. However, gradients will no

longer be available.

#### Optimizers[¶](#optimizers "Permalink to this headline")

Optimizers are objects which can be used to automatically update the parameters of a quantum

or hybrid machine learning model. The optimizers you should use are dependent on your choice

of the classical autodifferentiation library, and are available from different access

points.

##### NumPy[¶](#numpy "Permalink to this headline")

When using the standard NumPy framework, PennyLane offers some built-in optimizers.

Some of these are specific to quantum optimization, such as the [`QNGOptimizer`](index.html#pennylane.QNGOptimizer "pennylane.QNGOptimizer"),

[`RiemannianGradientOptimizer`](index.html#pennylane.RiemannianGradientOptimizer "pennylane.RiemannianGradientOptimizer"), [`RotosolveOptimizer`](index.html#pennylane.RotosolveOptimizer "pennylane.RotosolveOptimizer"), [`RotoselectOptimizer`](index.html#pennylane.RotoselectOptimizer "pennylane.RotoselectOptimizer"),

[`ShotAdaptiveOptimizer`](index.html#pennylane.ShotAdaptiveOptimizer "pennylane.ShotAdaptiveOptimizer"), and [`QNSPSAOptimizer`](index.html#pennylane.QNSPSAOptimizer "pennylane.QNSPSAOptimizer").

| [`AdagradOptimizer`](index.html#pennylane.AdagradOptimizer "pennylane.AdagradOptimizer") | Gradient-descent optimizer with past-gradient-dependent learning rate in each dimension. |

| [`AdamOptimizer`](index.html#pennylane.AdamOptimizer "pennylane.AdamOptimizer") | Gradient-descent optimizer with adaptive learning rate, first and second moment. |

| [`AdaptiveOptimizer`](index.html#pennylane.AdaptiveOptimizer "pennylane.AdaptiveOptimizer") | Optimizer for building fully trained quantum circuits by adding gates adaptively. |

| [`GradientDescentOptimizer`](index.html#pennylane.GradientDescentOptimizer "pennylane.GradientDescentOptimizer") | Basic gradient-descent optimizer. |

| [`MomentumOptimizer`](index.html#pennylane.MomentumOptimizer "pennylane.MomentumOptimizer") | Gradient-descent optimizer with momentum. |

| [`NesterovMomentumOptimizer`](index.html#pennylane.NesterovMomentumOptimizer "pennylane.NesterovMomentumOptimizer") | Gradient-descent optimizer with Nesterov momentum. |

| [`QNGOptimizer`](index.html#pennylane.QNGOptimizer "pennylane.QNGOptimizer") | Optimizer with adaptive learning rate, via calculation of the diagonal or block-diagonal approximation to the Fubini-Study metric tensor. |

| [`RiemannianGradientOptimizer`](index.html#pennylane.RiemannianGradientOptimizer "pennylane.RiemannianGradientOptimizer") | Riemannian gradient optimizer. |

| [`RMSPropOptimizer`](index.html#pennylane.RMSPropOptimizer "pennylane.RMSPropOptimizer") | Root mean squared propagation optimizer. |

| [`RotosolveOptimizer`](index.html#pennylane.RotosolveOptimizer "pennylane.RotosolveOptimizer") | Rotosolve gradient-free optimizer. |

| [`RotoselectOptimizer`](index.html#pennylane.RotoselectOptimizer "pennylane.RotoselectOptimizer") | Rotoselect gradient-free optimizer. |

| [`ShotAdaptiveOptimizer`](index.html#pennylane.ShotAdaptiveOptimizer "pennylane.ShotAdaptiveOptimizer") | Optimizer where the shot rate is adaptively calculated using the variances of the parameter-shift gradient. |

| [`SPSAOptimizer`](index.html#pennylane.SPSAOptimizer "pennylane.SPSAOptimizer") | The Simultaneous Perturbation Stochastic Approximation method (SPSA) is a stochastic approximation algorithm for optimizing cost functions whose evaluation may involve noise. |

| [`QNSPSAOptimizer`](index.html#pennylane.QNSPSAOptimizer "pennylane.QNSPSAOptimizer") | Quantum natural SPSA (QNSPSA) optimizer. |

##### PyTorch[¶](#pytorch "Permalink to this headline")

If you are using the [PennyLane PyTorch framework](index.html#torch-interf), you should import one of the native

[PyTorch optimizers](https://pytorch.org/docs/stable/optim.html) (found in `torch.optim`).

##### TensorFlow[¶](#tensorflow "Permalink to this headline")

When using the [PennyLane TensorFlow framework](index.html#tf-interf), you will need to leverage one of

the [TensorFlow optimizers](https://www.tensorflow.org/api_docs/python/tf/keras/optimizers/Optimizer)

(found in `tf.keras.optimizers`).

##### JAX[¶](#jax "Permalink to this headline")

Check out the [JAXopt](https://github.com/google/jaxopt) and the [Optax](https://optax.readthedocs.io/en/latest/) packages to find optimizers for the

[PennyLane JAX framework](index.html#jax-interf).

#### Gradients[¶](#gradients "Permalink to this headline")

The interface between PennyLane and automatic differentiation libraries relies on PennyLane’s ability

to compute or estimate gradients of quantum circuits. There are different strategies to do so, and they may

depend on the device used.

When creating a QNode, you can specify the [differentiation method](https://pennylane.ai/qml/glossary/quantum_differentiable_programming.html "(in PennyLane)") like this:

```

@qml.qnode(dev, diff\_method="parameter-shift")

def circuit(x):

    qml.RX(x, wires=0)

    return qml.probs(wires=0)

```

PennyLane currently provides the following differentiation methods for QNodes:

##### Simulation-based differentiation[¶](#simulation-based-differentiation "Permalink to this headline")

The following methods use [reverse accumulation](https://en.wikipedia.org/wiki/Automatic_differentiation#Reverse_accumulation) to compute

gradients; a well-known example of this approach is backpropagation. These methods are **not** hardware compatible; they are only supported on

*statevector* simulator devices such as `default.qubit`.

However, for rapid prototyping on simulators, these methods typically out-perform forward-mode

accumulators such as the parameter-shift rule and finite-differences. For more details, see the

[quantum backpropagation](https://pennylane.ai/qml/demos/tutorial_backprop.html "(in PennyLane)") demonstration.

* `"backprop"`: Use standard backpropagation.

This differentiation method is only allowed on simulator

devices that are classically end-to-end differentiable, for example

`default.qubit`. This method does *not* work on devices

that estimate measurement statistics using a finite number of shots; please use

the `parameter-shift` rule instead.

* `"adjoint"`: Use a form of backpropagation that takes advantage of the unitary or reversible

nature of quantum computation.

The [adjoint method](https://arxiv.org/abs/2009.02823) reverses through the circuit after a

forward pass by iteratively applying the inverse (adjoint) gate. This method is similar to

`"backprop"`, but has significantly lower memory usage and a similar runtime.

##### Hardware-compatible differentiation[¶](#hardware-compatible-differentiation "Permalink to this headline")

The following methods support both quantum hardware and simulators, and are examples of [forward

accumulation](https://en.wikipedia.org/wiki/Automatic_differentiation#Forward_accumulation).

However, when using a simulator, you may notice that the number of circuit executions required to

compute the gradients with these methods [scales linearly](https://pennylane.ai/qml/demos/tutorial_backprop.html "(in PennyLane)")

with the number of trainable circuit parameters.

* `"parameter-shift"`: Use the analytic [parameter-shift rule](https://pennylane.ai/qml/glossary/parameter_shift.html "(in PennyLane)") for all supported quantum operation arguments, with

finite-difference as a fallback.

* `"finite-diff"`: Use numerical finite-differences for all quantum operation arguments.

* `"hadamard"`: Use hadamard tests on the generators for all compatible quantum operations arguments.

* `qml.gradients.stoch\_pulse\_grad`: Use a stochastic variant of the

parameter-shift rule for pulse programs.

* `qml.gradients.pulse\_generator`: Combine classical processing with the parameter-shift rule for multivariate gates to differentiate pulse programs.

##### Device gradients[¶](#device-gradients "Permalink to this headline")

* `"device"`: Queries the device directly for the gradient.

Only allowed on devices that provide their own gradient computation.

Note

If not specified, the default differentiation method is `diff\_method="best"`. PennyLane

will attempt to determine the *best* differentiation method given the device and interface.

Typically, PennyLane will prioritize device-provided gradients, backpropagation, parameter-shift

rule, and finally finite differences, in that order.

#### Gradient transforms[¶](#gradient-transforms "Permalink to this headline")

In addition to registering the differentiation method of QNodes to be used with autodifferentiation

frameworks, PennyLane also provides a library of **gradient transforms** via the

[`qml.gradients`](index.html#module-pennylane.gradients "pennylane.gradients") module.

Quantum gradient transforms are strategies for computing the gradient of a quantum

circuit that work by **transforming** the quantum circuit into one or more gradient circuits.

They accompany these circuits with a function that **post-processes** their output.

These gradient circuits, once executed and post-processed, return the gradient

of the original circuit.

Examples of quantum gradient transforms include finite-difference rules and parameter-shift

rules; these can be applied *directly* to QNodes:

```

dev = qml.device("default.qubit", wires=2)

@qml.qnode(dev)

def circuit(weights):

    qml.RX(weights[0], wires=0)

    qml.RY(weights[1], wires=1)

    qml.CNOT(wires=[0, 1])

    qml.RX(weights[2], wires=1)

    return qml.probs(wires=1)

```

```

>>> weights = np.array([0.1, 0.2, 0.3], requires\_grad=True)

>>> circuit(weights)

tensor([0.9658079, 0.0341921], requires\_grad=True)

>>> qml.gradients.param\_shift(circuit)(weights)

(tensor([-0.04673668, 0.04673668], requires\_grad=True),

 tensor([-0.09442394, 0.09442394], requires\_grad=True),

 tensor([-0.14409127, 0.14409127], requires\_grad=True))

```

Note that, while gradient transforms allow quantum gradient rules to be applied directly to QNodes,

this is not a replacement — and should not be used instead of — standard training workflows (for example,

`qml.grad()` if using Autograd, `loss.backward()` for PyTorch, or `tape.gradient()` for TensorFlow).

This is because gradient transforms do not take into account classical computation nodes, and only

support gradients of QNodes.

For more details on available gradient transforms, as well as learning how to define your own

gradient transform, please see the [`qml.gradients`](index.html#module-pennylane.gradients "pennylane.gradients") documentation.

#### Differentiating gradient transforms and higher-order derivatives[¶](#differentiating-gradient-transforms-and-higher-order-derivatives "Permalink to this headline")

Gradient transforms are themselves differentiable, allowing higher-order

gradients to be computed:

```

dev = qml.device("default.qubit", wires=2)

@qml.qnode(dev)

def circuit(weights):

    qml.RX(weights[0], wires=0)

    qml.RY(weights[1], wires=1)

    qml.CNOT(wires=[0, 1])

    qml.RX(weights[2], wires=1)

    return qml.expval(qml.PauliZ(1))

```

```

>>> weights = np.array([0.1, 0.2, 0.3], requires\_grad=True)

>>> circuit(weights)

tensor(0.9316158, requires\_grad=True)

>>> qml.gradients.param\_shift(circuit)(weights)  # gradient

(tensor(-0.09347337, requires\_grad=True),

 tensor(-0.18884787, requires\_grad=True),

 tensor(-0.28818254, requires\_grad=True))

>>> def f(weights):

...     return np.stack(qml.gradients.param\_shift(circuit)(weights))

>>> qml.jacobian(f)(weights)  # hessian

array([[[-0.9316158 , 0.01894799, 0.0289147 ],

 [ 0.01894799, -0.9316158 , 0.05841749],

 [ 0.0289147 , 0.05841749, -0.9316158 ]]])

```

Another way to compute higher-order derivatives is by passing the `max\_diff` and

`diff\_method` arguments to the QNode and by successive differentiation:

```

@qml.qnode(dev, diff\_method="parameter-shift", max\_diff=2)

def circuit(weights):

    qml.RX(weights[0], wires=0)

    qml.RY(weights[1], wires=1)

    qml.CNOT(wires=[0, 1])

    qml.RX(weights[2], wires=1)

    return qml.expval(qml.PauliZ(1))

```

```

>>> weights = np.array([0.1, 0.2, 0.3], requires\_grad=True)

>>> qml.jacobian(qml.jacobian(circuit))(weights)  # hessian

array([[-0.9316158 , 0.01894799, 0.0289147 ],

 [ 0.01894799, -0.9316158 , 0.05841749],

 [ 0.0289147 , 0.05841749, -0.9316158 ]])

```

Note that the `max\_diff` argument only applies to gradient transforms and that its default value is `1`; failing to

set its value correctly may yield incorrect results for higher-order derivatives. Also, passing

`diff\_method="parameter-shift"` is equivalent to passing `diff\_method=qml.gradients.param\_shift`.

#### Supported configurations[¶](#supported-configurations "Permalink to this headline")

 .gr-parent {background-color:#bbffbb}

 .rd-parent {background-color:#ffbbbb}

The table below show all the currently supported functionality for the `"default.qubit"` device.

At the moment, it takes into account the following parameters:

* The interface, e.g. `"jax"`

* The differentiation method, e.g. `"parameter-shift"`

* The return value of the QNode, e.g. `qml.expval()` or `qml.probs()`

* The number of shots, either None or an integer > 0

 .tb { border-collapse: collapse; }

 .tb th, .tb td { padding: 1px; border: solid 1px black; }

|  | **Return type** |

| --- | --- |

| **Interface** | **Differentiation method** | state | density matrix | probs | sample | expval (obs) | expval (herm) | expval (proj) | var | vn entropy | mutual info |

| `None` | `"device"` | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |

| `"backprop"` | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |

| `"adjoint"` | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 |

| `"parameter-shift"` | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 |

| `"finite-diff"` | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 |

| `"spsa"` | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 |

| `"hadamard"` | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 |

| `"autograd"` | `"device"` | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 |

| `"backprop"` | 4 | 4 | 5 | 9 | 5 | 5 | 5 | 5 | 5 | 5 |

| `"adjoint"` | 6 | 6 | 6 | 6 | 7 | 7 | 7 | 6 | 6 | 6 |

| `"parameter-shift"` | 10 | 10 | 8 | 9 | 8 | 8 | 8 | 8 | 10 | 10 |

| `"finite-diff"` | 10 | 10 | 8 | 9 | 8 | 8 | 8 | 8 | 8 | 8 |

| `"spsa"` | 10 | 10 | 8 | 9 | 8 | 8 | 8 | 8 | 8 | 8 |

| `"hadamard"` | 10 | 10 | 8 | 9 | 8 | 8 | 8 | 11 | 10 | 10 |

| `"jax"` | `"device"` | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 |

| `"backprop"` | 5 | 5 | 5 | 9 | 5 | 5 | 5 | 5 | 5 | 5 |

| `"adjoint"` | 6 | 6 | 6 | 6 | 7 | 7 | 7 | 6 | 6 | 6 |

| `"parameter-shift"` | 10 | 10 | 8 | 9 | 8 | 8 | 8 | 8 | 10 | 10 |

| `"finite-diff"` | 10 | 10 | 8 | 9 | 8 | 8 | 8 | 8 | 8 | 8 |

| `"spsa"` | 10 | 10 | 8 | 9 | 8 | 8 | 8 | 8 | 8 | 8 |

| `"hadamard"` | 10 | 10 | 8 | 9 | 8 | 8 | 8 | 11 | 10 | 10 |

| `"tf"` | `"device"` | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 |

| `"backprop"` | 5 | 5 | 5 | 9 | 5 | 5 | 5 | 5 | 5 | 5 |

| `"adjoint"` | 6 | 6 | 6 | 6 | 7 | 7 | 7 | 6 | 6 | 6 |

| `"parameter-shift"` | 10 | 10 | 8 | 9 | 8 | 8 | 8 | 8 | 10 | 10 |

| `"finite-diff"` | 10 | 10 | 8 | 9 | 8 | 8 | 8 | 8 | 8 | 8 |

| `"spsa"` | 10 | 10 | 8 | 9 | 8 | 8 | 8 | 8 | 8 | 8 |

| `"hadamard"` | 10 | 10 | 8 | 9 | 8 | 8 | 8 | 11 | 10 | 10 |

| `"torch"` | `"device"` | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 |

| `"backprop"` | 5 | 5 | 5 | 9 | 5 | 5 | 5 | 5 | 5 | 5 |

| `"adjoint"` | 6 | 6 | 6 | 6 | 7 | 7 | 7 | 6 | 6 | 6 |

| `"parameter-shift"` | 10 | 10 | 8 | 9 | 8 | 8 | 8 | 8 | 10 | 10 |

| `"finite-diff"` | 10 | 10 | 8 | 9 | 8 | 8 | 8 | 8 | 8 | 8 |

| `"spsa"` | 10 | 10 | 8 | 9 | 8 | 8 | 8 | 8 | 8 | 8 |

| `"hadamard"` | 10 | 10 | 8 | 9 | 8 | 8 | 8 | 11 | 10 | 10 |

1. Not supported. Gradients are not computed even though `diff\_method` is provided. Fails with error.

2. Not supported. Gradients are not computed even though `diff\_method` is provided. Warns that no auto-differentiation framework is being used, but does not fail.

Forward pass is still supported.

3. Not supported. The `default.qubit` device does not provide a native way to compute gradients. See

[Device jacobian](index.html#device-jacobian) for details.

4. Supported, but only when `shots=None`. See [Backpropagation](index.html#analytic-backpropagation) for details.

If the circuit returns a state, then the circuit itself is not differentiable

directly. However, any real scalar-valued post-processing done to the output of the

circuit will be differentiable. See [State gradients](index.html#state-gradients) for details.

5. Supported, but only when `shots=None`. See [Backpropagation](index.html#analytic-backpropagation) for details.

6. Not supported. The adjoint differentiation algorithm is only implemented for computing the expectation values of observables. See

[Adjoint differentation](index.html#adjoint-differentation) for details.

7. Supported. Raises warning when `shots>0` since the gradient is always computed analytically. See

[Adjoint differentation](index.html#adjoint-differentation) for details.

8. Supported.

9. Not supported. The discretization of the output caused by wave function collapse is

not differentiable. The forward pass is still supported. See [Sample gradients](index.html#sample-gradients) for details.

10. Not supported. “We just don’t have the theory yet.”

11. Not implemented.

##### NumPy interface[¶](#numpy-interface "Permalink to this headline")

Note

This interface is the default interface supported by PennyLane’s [`QNode`](index.html#pennylane.QNode "pennylane.QNode").

###### Using the NumPy interface[¶](#using-the-numpy-interface "Permalink to this headline")

Using the NumPy interface is easy in PennyLane, and the default approach —

designed so it will feel like you are just using standard NumPy, with the

added benefit of automatic differentiation.

All you have to do is make sure to import the wrapped version of NumPy

provided by PennyLane alongside with the PennyLane library:

```

import pennylane as qml

from pennylane import numpy as np

```

This is powered via [Autograd](https://github.com/HIPS/autograd), and enables

automatic differentiation and backpropagation of classical computations using familiar

NumPy functions and modules (such as `np.sin`, `np.cos`, `np.exp`, `np.linalg`,

`np.fft`), as well as standard Python constructs, such as `if` statements, and `for`

and `while` loops.

####### Via the QNode decorator[¶](#via-the-qnode-decorator "Permalink to this headline")

The [QNode decorator](index.html#intro-vcirc-decorator) is the recommended way for creating QNodes

in PennyLane. By default, all QNodes are constructed for the NumPy interface,

but this can also be specified explicitly by passing the `interface='autograd'` keyword argument:

```

dev = qml.device('default.qubit', wires=2)

@qml.qnode(dev, interface='autograd')

def circuit1(phi, theta):

    qml.RX(phi[0], wires=0)

    qml.RY(phi[1], wires=1)

    qml.CNOT(wires=[0, 1])

    qml.PhaseShift(theta, wires=0)

    return qml.expval(qml.PauliZ(0)), qml.expval(qml.Hadamard(1))

```

The QNode `circuit1()` is a NumPy-interfacing QNode, accepting standard Python

data types such as ints, floats, lists, and tuples, as well as NumPy arrays, and

returning NumPy arrays.

It can now be used like any other Python/NumPy function:

```

>>> phi = np.array([0.5, 0.1])

>>> theta = 0.2

>>> circuit1(phi, theta)

(tensor(0.87758256, requires\_grad=True),

 tensor(0.68803733, requires\_grad=True))

```

The interface can also be automatically determined when the `QNode` is called. You do not need to pass the interface

if you provide parameters.

####### Via the QNode constructor[¶](#via-the-qnode-constructor "Permalink to this headline")

In the [introduction](index.html#intro-vcirc-qnode) it was shown how to instantiate a `QNode`

object directly, for example, if you would like to reuse the same quantum function across

multiple devices, or even use different classical interfaces:

```

dev1 = qml.device('default.qubit', wires=2)

dev2 = qml.device('forest.wavefunction', wires=2)

def circuit2(phi, theta):

    qml.RX(phi[0], wires=0)

    qml.RY(phi[1], wires=1)

    qml.CNOT(wires=[0, 1])

    qml.PhaseShift(theta, wires=0)

    return qml.expval(qml.PauliZ(0)), qml.expval(qml.Hadamard(1))

qnode1 = qml.QNode(circuit2, dev1)

qnode2 = qml.QNode(circuit2, dev2)

```

By default, all QNodes created this way are NumPy interfacing QNodes.

###### Quantum gradients[¶](#quantum-gradients "Permalink to this headline")

To calculate the gradient of a NumPy-QNode, we can simply use the provided

`grad()` function.

For example, consider the following QNode:

```

dev = qml.device('default.qubit', wires=2)

@qml.qnode(dev)

def circuit3(phi, theta):

    qml.RX(phi[0], wires=0)

    qml.RY(phi[1], wires=1)

    qml.CNOT(wires=[0, 1])

    qml.PhaseShift(theta, wires=0)

    return qml.expval(qml.PauliZ(0))

```

We can now use `grad()` to create a QNode *gradient function*,

with respect to both QNode parameters `phi` and `theta`:

```

phi = np.array([0.5, 0.1], requires\_grad=True)

theta = np.array(0.2, requires\_grad=True)

dcircuit = qml.grad(circuit3)

```

Evaluating this gradient function at specific parameter values:

```

>>> dcircuit(phi, theta)

(array([ -4.79425539e-01, 1.11022302e-16]), array(0.0))

```

####### Differentiable and non-differentiable arguments[¶](#differentiable-and-non-differentiable-arguments "Permalink to this headline")

How does PennyLane know which arguments of a quantum function to differentiate, and which to ignore?

For example, you may want to pass arguments to a QNode but *not* have

PennyLane consider them when computing gradients.

Regular positional arguments provided to the QNode are not assumed to be differentiable

by default. This includes arguments in the form of built-in Python data types, and arrays from

the original NumPy module. Thus, arguments need to be explicitly marked as trainable or selected

using the `argnum` keyword. To mark an argument as trainable, a special flag `requires\_grad`

has been added to arrays from PennyLane’s NumPy module:

```

>>> from pennylane import numpy as np

>>> np.array([0.1, 0.2], requires\_grad=True)

tensor([0.1, 0.2], requires\_grad=True)

```

When omitted, the value for this flag is `True`, so if you would like to provide a

non-differentiable PennyLane NumPy array to the QNode or gradient function, make sure

to specify `requires\_grad=False`:

```

>>> from pennylane import numpy as np

>>> np.array([0.1, 0.2], requires\_grad=False)

tensor([0.1, 0.2], requires\_grad=False)

```

Note

The `requires\_grad` argument can be passed to any NumPy function provided by PennyLane,

including NumPy functions that create arrays like `np.random.random`, `np.zeros`, etc.

On the other hand, keyword arguments (whether they have a default value or not), are always

considered non-trainable, no matter their data type or flags they may have. For example, consider

the following QNode that accepts two arguments `data` and `weights`:

```

dev = qml.device('default.qubit', wires=5)

@qml.qnode(dev)

def circuit(data, weights):

    qml.AmplitudeEmbedding(data, wires=[0, 1, 2], normalize=True)

    qml.RX(weights[0], wires=0)

    qml.RY(weights[1], wires=1)

    qml.RZ(weights[2], wires=2)

    qml.CNOT(wires=[0, 1])

    qml.CNOT(wires=[0, 2])

    return qml.expval(qml.PauliZ(0))

rng = np.random.default\_rng(seed=42)  # make the results reproducable

data = rng.random([2 \*\* 3], requires\_grad=False)

weights = np.array([0.1, 0.2, 0.3], requires\_grad=True)

```

When we compute the derivative, arguments with `requires\_grad=False` as well as arguments

passed as keyword arguments are ignored by `grad()`, which in this case means no gradient

is computed at all:

```

>>> qml.grad(circuit)(data, weights=weights)

UserWarning: Attempted to differentiate a function with no trainable parameters. If this is unintended, please add trainable parameters via the 'requires\_grad' attribute or 'argnum' keyword.

()

```

###### Optimization[¶](#optimization "Permalink to this headline")

To optimize your hybrid classical-quantum model using the NumPy interface,

use the provided optimizers:

| [`AdagradOptimizer`](index.html#pennylane.AdagradOptimizer "pennylane.AdagradOptimizer") | Gradient-descent optimizer with past-gradient-dependent learning rate in each dimension. |

| [`AdamOptimizer`](index.html#pennylane.AdamOptimizer "pennylane.AdamOptimizer") | Gradient-descent optimizer with adaptive learning rate, first and second moment. |

| [`GradientDescentOptimizer`](index.html#pennylane.GradientDescentOptimizer "pennylane.GradientDescentOptimizer") | Basic gradient-descent optimizer. |

| [`MomentumOptimizer`](index.html#pennylane.MomentumOptimizer "pennylane.MomentumOptimizer") | Gradient-descent optimizer with momentum. |

| [`NesterovMomentumOptimizer`](index.html#pennylane.NesterovMomentumOptimizer "pennylane.NesterovMomentumOptimizer") | Gradient-descent optimizer with Nesterov momentum. |

| [`QNGOptimizer`](index.html#pennylane.QNGOptimizer "pennylane.QNGOptimizer") | Optimizer with adaptive learning rate, via calculation of the diagonal or block-diagonal approximation to the Fubini-Study metric tensor. |

| [`RiemannianGradientOptimizer`](index.html#pennylane.RiemannianGradientOptimizer "pennylane.RiemannianGradientOptimizer") | Riemannian gradient optimizer. |

| [`RMSPropOptimizer`](index.html#pennylane.RMSPropOptimizer "pennylane.RMSPropOptimizer") | Root mean squared propagation optimizer. |

| [`RotosolveOptimizer`](index.html#pennylane.RotosolveOptimizer "pennylane.RotosolveOptimizer") | Rotosolve gradient-free optimizer. |

| [`RotoselectOptimizer`](index.html#pennylane.RotoselectOptimizer "pennylane.RotoselectOptimizer") | Rotoselect gradient-free optimizer. |

| [`ShotAdaptiveOptimizer`](index.html#pennylane.ShotAdaptiveOptimizer "pennylane.ShotAdaptiveOptimizer") | Optimizer where the shot rate is adaptively calculated using the variances of the parameter-shift gradient. |

For example, we can optimize a NumPy-interfacing QNode (below) such that the weights `x`

lead to a final expectation value of 0.5:

```

dev = qml.device('default.qubit', wires=2)

@qml.qnode(dev)

def circuit4(x):

    qml.RX(x[0], wires=0)

    qml.RZ(x[1], wires=1)

    qml.CNOT(wires=[0, 1])

    qml.RX(x[2], wires=0)

    return qml.expval(qml.PauliZ(0))

def cost(x):

    return np.abs(circuit4(x) - 0.5)\*\*2

opt = qml.GradientDescentOptimizer(stepsize=0.4)

steps = 100

params = np.array([0.011, 0.012, 0.05], requires\_grad=True)

for i in range(steps):

    # update the circuit parameters

    params = opt.step(cost, params)

```

The final weights and circuit value are:

```

>>> params

tensor([0.19846757, 0.012 , 1.03559806], requires\_grad=True)

>>> circuit4(params)

tensor(0.5, requires\_grad=True)

```

For more details on the NumPy optimizers, check out the tutorials, as well as the

`pennylane.optimize` documentation.

###### Vector-valued QNodes and the Jacobian[¶](#vector-valued-qnodes-and-the-jacobian "Permalink to this headline")

How does automatic differentiation work in the case where the QNode returns multiple expectation values?

```

dev = qml.device('default.qubit', wires=2)

@qml.qnode(dev)

def circuit5(params):

    qml.Hadamard(wires=0)

    qml.CNOT(wires=[0, 1])

    qml.RX(params[0], wires=0)

    qml.RY(params[1], wires=1)

    qml.CNOT(wires=[0, 1])

    return qml.expval(qml.PauliY(0)), qml.expval(qml.PauliZ(1))

```

If we were to naively try computing the gradient of `circuit5` using the `grad()` function,

```

>>> g1 = qml.grad(circuit5)

>>> params = np.array([np.pi/2, 0.2], requires\_grad=True)

>>> g1(params)

TypeError: Grad only applies to real scalar-output functions. Try jacobian, elementwise\_grad or holomorphic\_grad.

```

we would get an error message. This is because the [gradient](https://en.wikipedia.org/wiki/Gradient) is

only defined for scalar functions, i.e., functions which return a single value. In the case where the QNode

returns multiple expectation values, the correct differential operator to use is

the [Jacobian matrix](https://en.wikipedia.org/wiki/Jacobian_matrix_and_determinant).

This can be accessed in PennyLane as [`jacobian()`](index.html#pennylane.jacobian "pennylane.jacobian").

As the `circuit5` returns a tuple of numpy arrays instead of a single numpy array, the results need

to be stacked into a single array before use with [`jacobian()`](index.html#pennylane.jacobian "pennylane.jacobian").

```

>>> j1 = qml.jacobian(lambda x: np.stack(circuit5(x)))

>>> j1(params)

array([[ 0. , -0.98006658],

 [-0.98006658, 0. ]])

```

The output of [`jacobian()`](index.html#pennylane.jacobian "pennylane.jacobian") is a two-dimensional vector, with the first/second element being

the partial derivative of the first/second expectation value with respect to the input parameter.

###### Advanced Autograd usage[¶](#advanced-autograd-usage "Permalink to this headline")

The PennyLane NumPy interface leverages the Python library [Autograd](https://github.com/HIPS/autograd) to enable automatic differentiation of NumPy code, and extends

it to provide gradients of quantum circuit functions encapsulated in QNodes. In order to make NumPy

code differentiable, Autograd provides a wrapped version of NumPy (exposed in PennyLane as

`pennylane.numpy`).

Warning

As stated in other sections, using this interface, any hybrid computation should be coded using the

wrapped version of NumPy provided by PennyLane. If you accidentally import the vanilla version of

NumPy, your code will not be automatically differentiable.

Because of the way Autograd wraps NumPy, the PennyLane NumPy interface allows standard NumPy

functions and basic Python control statements (`if` statements, loops, etc.) for declaring

differentiable classical computations.

That being said, Autograd’s coverage of NumPy is not complete. It is best to consult the [Autograd

docs](https://github.com/HIPS/autograd/blob/master/docs/tutorial.md) for a more complete overview

of supported and unsupported features. We highlight a few of the major ‘gotchas’ here.

**Do not use:**

* Assignment to arrays, such as `A[0, 0] = x`.

* Implicit casting of lists to arrays, for example `A = np.sum([x, y])`.

Make sure to explicitly cast to a NumPy array first, i.e., `A = np.sum(np.array([x, y]))` instead.

* `A.dot(B)` notation.

Use `np.dot(A, B)` or `A @ B` instead.

* In-place operations such as `a += b`.

Use `a = a + b` instead.

* Some `isinstance` checks, like `isinstance(x, np.ndarray)` or `isinstance(x, tuple)`, without first doing `from autograd.builtins import isinstance, tuple`.

###### SciPy Optimization[¶](#scipy-optimization "Permalink to this headline")

In addition to using autodifferentiation provided by Autograd, the NumPy interface

also allows QNodes to be optimized directly using the

[SciPy optimize](https://docs.scipy.org/doc/scipy/reference/optimize.html) module.

Simply pass the QNode, or your hybrid cost function containing QNodes, directly

to the `scipy.minimize` function:

```

from scipy.optimize import minimize

dev = qml.device('default.qubit', wires=2)

@qml.qnode(dev)

def circuit(x):

    qml.RX(x[0], wires=0)

    qml.RZ(x[1], wires=1)

    qml.CNOT(wires=[0, 1])

    qml.RX(x[2], wires=0)

    return qml.expval(qml.PauliZ(0))

def cost(x):

    return np.abs(circuit(x) - 0.5) \*\* 2

params = np.array([0.011, 0.012, 0.05], requires\_grad=True)

minimize(cost, params, method='BFGS')

```

Some of the SciPy minimization methods require information about the gradient

of the cost function via the `jac` keyword argument. This is easy to include; we

can simply create a function that computes the gradient using `qml.grad`. Since

`minimize` does not use our wrapped version of numpy, we need to explicitly

specify which arguments are trainable via the `argnum` keyword.

```

>>> minimize(cost, params, method='BFGS', jac=qml.grad(cost, argnum=0))

 fun: 6.3491130264451484e-18

 hess\_inv: array([[ 1.85642354e+00, -8.84954187e-22, 3.89539943e+00],

 [-8.84954187e-22, 1.00000000e+00, -4.02571211e-21],

 [ 3.89539943e+00, -4.02571211e-21, 1.87180282e+01]])

 jac: array([5.81636983e-10, 3.23117427e-27, 4.21456861e-09])

 message: 'Optimization terminated successfully.'

 nfev: 8

 nit: 2

 njev: 8

 status: 0

 success: True

 x: array([0.22685818, 0.012 , 1.03194789])

```

##### PyTorch interface[¶](#pytorch-interface "Permalink to this headline")

In order to use PennyLane in combination with PyTorch, we have to generate PyTorch-compatible

quantum nodes. Such a QNode can be created explicitly using the `interface='torch'` keyword in

the QNode decorator or QNode class constructor.

Note

To use the PyTorch interface in PennyLane, you must first

[install PyTorch](https://pytorch.org/get-started/locally/#start-locally)

and import it together with PennyLane via:

```

import pennylane as qml

import torch

```

Using the PyTorch interface is easy in PennyLane — let’s consider a few ways

it can be done.

###### Construction via keyword[¶](#construction-via-keyword "Permalink to this headline")

The [QNode decorator](index.html#intro-vcirc-decorator) is the recommended way for creating

[`QNode`](index.html#pennylane.QNode "pennylane.QNode") objects in PennyLane. The only change required to construct a PyTorch-capable

QNode is to specify the `interface='torch'` keyword argument:

```

dev = qml.device('default.qubit', wires=2)

@qml.qnode(dev, interface='torch')

def circuit(phi, theta):

    qml.RX(phi[0], wires=0)

    qml.RY(phi[1], wires=1)

    qml.CNOT(wires=[0, 1])

    qml.PhaseShift(theta, wires=0)

    return qml.expval(qml.PauliZ(0)), qml.expval(qml.Hadamard(1))

```

The QNode `circuit()` is now a PyTorch-capable QNode, accepting `torch.tensor` objects as

input, and returning `torch.tensor` objects. Subclassing from `torch.autograd.Function`,

it can now be used like any other PyTorch function:

```

>>> phi = torch.tensor([0.5, 0.1])

>>> theta = torch.tensor(0.2)

>>> circuit(phi, theta)

(tensor(0.8776, dtype=torch.float64), tensor(0.6880, dtype=torch.float64))

```

The interface can also be automatically determined when the `QNode` is called. You do not need to pass the interface

if you provide parameters.

PyTorch-capable QNodes can also be created using the

[QNode class constructor](index.html#intro-vcirc-qnode):

```

dev1 = qml.device('default.qubit', wires=2)

dev2 = qml.device('default.mixed', wires=2)

def circuit1(phi, theta):

    qml.RX(phi[0], wires=0)

    qml.RY(phi[1], wires=1)

    qml.CNOT(wires=[0, 1])

    qml.PhaseShift(theta, wires=0)

    return qml.expval(qml.PauliZ(0)), qml.expval(qml.Hadamard(1))

qnode1 = qml.QNode(circuit1, dev1)

qnode2 = qml.QNode(circuit1, dev2, interface='torch')

```

`qnode1()` detects the interface from the parameters of each call, while `qnode2()` is a strictly a PyTorch-capable

QNode:

```

>>> qnode1(phi, theta)

(tensor(0.8776, dtype=torch.float64), tensor(0.6880, dtype=torch.float64))

>>> qnode2(phi, theta)

(tensor(0.8776, dtype=torch.float64), tensor(0.6880, dtype=torch.float64))

```

###### Quantum gradients using PyTorch[¶](#quantum-gradients-using-pytorch "Permalink to this headline")

Since a PyTorch-interfacing QNode acts like any other `torch.autograd.Function`,

the standard method used to calculate gradients with PyTorch can be used.

For example:

```

dev = qml.device('default.qubit', wires=2)

@qml.qnode(dev, interface='torch')

def circuit3(phi, theta):

    qml.RX(phi[0], wires=0)

    qml.RY(phi[1], wires=1)

    qml.CNOT(wires=[0, 1])

    qml.PhaseShift(theta, wires=0)

    return qml.expval(qml.PauliZ(0))

phi = torch.tensor([0.5, 0.1], requires\_grad=True)

theta = torch.tensor(0.2, requires\_grad=True)

result = circuit3(phi, theta)

```

Now, performing the backpropagation and accumulating the gradients:

```

>>> result.backward()

>>> phi.grad

tensor([-0.4794, 0.0000])

>>> theta.grad

tensor(-5.5511e-17)

```

To include non-differentiable data arguments, simply set `requires\_grad=False`:

```

@qml.qnode(dev, interface='torch')

def circuit3(weights, data):

    qml.AmplitudeEmbedding(data, normalize=True, wires=[0, 1])

    qml.RX(weights[0], wires=0)

    qml.RY(weights[1], wires=1)

    qml.CNOT(wires=[0, 1])

    qml.PhaseShift(weights[2], wires=0)

    return qml.expval(qml.PauliZ(0))

```

Here, `data` is non-trainable embedded data, so should be marked as non-differentiable:

```

>>> weights = torch.tensor([0.1, 0.2, 0.3], requires\_grad=True)

>>> data = torch.tensor([0.4741, 0.9257, 0.5541, 0.3137], requires\_grad=False)

>>> result = circuit3(weights, data)

>>> result.backward()

>>> data.grad is None

True

>>> weights.grad

tensor([-4.5398e-02, -3.7253e-09, 0.0000e+00])

```

###### Optimization using PyTorch[¶](#optimization-using-pytorch "Permalink to this headline")

To optimize your hybrid classical-quantum model using the Torch interface,

you **must** make use of the [PyTorch provided optimizers](https://pytorch.org/docs/stable/optim.html),

or your own custom PyTorch optimizer. **The** [PennyLane optimizers](index.html#intro-ref-opt)

**cannot be used with the Torch interface**.

For example, to optimize a Torch-interfacing QNode (below) such that the weights `x`

result in an expectation value of 0.5 we can do the following:

```

import torch

import pennylane as qml

dev = qml.device('default.qubit', wires=2)

@qml.qnode(dev, interface='torch')

def circuit4(phi, theta):

    qml.RX(phi[0], wires=0)

    qml.RZ(phi[1], wires=1)

    qml.CNOT(wires=[0, 1])

    qml.RX(theta, wires=0)

    return qml.expval(qml.PauliZ(0))

def cost(phi, theta):

    return torch.abs(circuit4(phi, theta) - 0.5)\*\*2

phi = torch.tensor([0.011, 0.012], requires\_grad=True)

theta = torch.tensor(0.05, requires\_grad=True)

opt = torch.optim.Adam([phi, theta], lr = 0.1)

steps = 200

def closure():

    opt.zero\_grad()

    loss = cost(phi, theta)

    loss.backward()

    return loss

for i in range(steps):

    opt.step(closure)

```

The final weights and circuit value are:

```

>>> phi\_final, theta\_final = opt.param\_groups[0]['params']

>>> phi\_final

tensor([7.3449e-01, 3.1554e-04], requires\_grad=True)

>>> theta\_final

tensor(0.8316, requires\_grad=True)

>>> circuit4(phi\_final, theta\_final)

tensor(0.5000, dtype=torch.float64, grad\_fn=<SqueezeBackward0>)

```

Note

For more advanced PyTorch models, Torch-interfacing QNodes can be used to construct

layers in custom PyTorch modules (`torch.nn.Module`).

See <https://pytorch.org/docs/stable/notes/extending.html#adding-a-module> for more details.

###### GPU and CUDA support[¶](#gpu-and-cuda-support "Permalink to this headline")

This section only applies to users who have installed torch with CUDA support.

If you are not sure if you have CUDA support, you can check with the following function:

```

>>> torch.cuda.is\_available()

True

```

If at least one input parameter is on a CUDA device and you are using backpropogation,

the execution will occur on the CUDA device. For systems with a high number of wires, CUDA

execution can be much faster. For lower wire count, the overhead of moving everything to

the GPU will dominate performance; for less than 15 wires, the GPU will probably be slower.

```

n\_wires = 20

n\_layers = 10

dev = qml.device('default.qubit', wires=n\_wires)

params\_shape = qml.StronglyEntanglingLayers.shape(n\_layers=n\_layers, n\_wires=n\_wires)

params = torch.rand(params\_shape)

@qml.qnode(dev, interface='torch', diff\_method="backprop")

def circuit\_cuda(params):

    qml.StronglyEntanglingLayers(params, wires=range(n\_wires))

    return qml.expval(qml.PauliZ(0))

```

```

>>> import timeit

>>> timeit.timeit("circuit\_cuda(params)", globals=globals(), number=5))

10.110647433029953

>>> params = params.to(device=torch.device('cuda'))

>>> timeit.timeit("circuit\_cuda(params)", globals=globals(), number=5)

2.297812332981266

```

###### Torch.nn integration[¶](#torch-nn-integration "Permalink to this headline")

Once you have a Torch-compaible QNode, it is easy to convert this into a `torch.nn` layer. To help

automate this process, PennyLane also provides a [`TorchLayer`](index.html#pennylane.qnn.TorchLayer "pennylane.qnn.TorchLayer") class to easily

convert a QNode to a `torch.nn` layer. Please see the corresponding [`TorchLayer`](index.html#pennylane.qnn.TorchLayer "pennylane.qnn.TorchLayer")

documentation for more details and examples.

##### TensorFlow interface[¶](#tensorflow-interface "Permalink to this headline")

In order to use PennyLane in combination with TensorFlow, we have to generate TensorFlow-compatible

quantum nodes. Such a QNode can be created explicitly using the `interface='tf'` keyword in the

QNode decorator or QNode class constructor.

Note

To use the TensorFlow interface in PennyLane, you must first install TensorFlow.

Note that this interface only supports TensorFlow versions >= 2.3!

Tensorflow is imported as follows:

```

import pennylane as qml

import tensorflow as tf

```

Using the TensorFlow interface is easy in PennyLane — let’s consider a few ways

it can be done.

###### Construction via keyword[¶](#construction-via-keyword "Permalink to this headline")

The [QNode decorator](index.html#intro-vcirc-decorator) is the recommended way for creating

[`QNode`](index.html#pennylane.QNode "pennylane.QNode") objects in PennyLane. The only change required to construct a TensorFlow-capable

QNode is to specify the `interface='tf'` keyword argument:

```

dev = qml.device('default.qubit', wires=2)

@qml.qnode(dev, interface='tf')

def circuit(phi, theta):

    qml.RX(phi[0], wires=0)

    qml.RY(phi[1], wires=1)

    qml.CNOT(wires=[0, 1])

    qml.PhaseShift(theta, wires=0)

    return qml.expval(qml.PauliZ(0)), qml.expval(qml.Hadamard(1))

```

The QNode `circuit()` is now a TensorFlow-capable QNode, accepting `tf.Variable` and

`tf.Tensor` objects as input, and returning `tf.Tensor` objects.

```

>>> phi = tf.Variable([0.5, 0.1])

>>> theta = tf.Variable(0.2)

>>> circuit(phi, theta)

(<tf.Tensor: shape=(), dtype=float64, numpy=0.8775825769558366>,

 <tf.Tensor: shape=(), dtype=float64, numpy=0.6880373394540326>)

```

The interface can also be automatically determined when the `QNode` is called. You do not need to pass the interface

if you provide parameters.

TensorFlow-capable QNodes can also be created using the

[QNode class constructor](index.html#intro-vcirc-qnode):

```

dev1 = qml.device('default.qubit', wires=2)

dev2 = qml.device('default.mixed', wires=2)

def circuit1(phi, theta):

    qml.RX(phi[0], wires=0)

    qml.RY(phi[1], wires=1)

    qml.CNOT(wires=[0, 1])

    qml.PhaseShift(theta, wires=0)

    return qml.expval(qml.PauliZ(0)), qml.expval(qml.Hadamard(1))

qnode1 = qml.QNode(circuit1, dev1)

qnode2 = qml.QNode(circuit1, dev2, interface='tf')

```

`qnode1()` is a default NumPy-interfacing QNode, while `qnode2()` is a TensorFlow-capable

QNode:

```

>>> qnode2(phi, theta)

(<tf.Tensor: shape=(), dtype=float64, numpy=0.8775825769558366>,

 <tf.Tensor: shape=(), dtype=float64, numpy=0.6880373394540326>)

```

###### Quantum gradients using TensorFlow[¶](#quantum-gradients-using-tensorflow "Permalink to this headline")

Since a TensorFlow-interfacing QNode acts like any other TensorFlow function,

the standard method used to calculate gradients in eager mode with TensorFlow can be used.

For example:

```

dev = qml.device('default.qubit', wires=2)

@qml.qnode(dev, interface='tf')

def circuit(phi, theta):

    qml.RX(phi[0], wires=0)

    qml.RY(phi[1], wires=1)

    qml.CNOT(wires=[0, 1])

    qml.PhaseShift(theta, wires=0)

    return qml.expval(qml.PauliZ(0))

phi = tf.Variable([0.5, 0.1])

theta = tf.Variable(0.2)

with tf.GradientTape() as tape:

    # Use the circuit to calculate the loss value

    loss = circuit(phi, theta)

phi\_grad, theta\_grad = tape.gradient(loss, [phi, theta])

```

Now, printing the gradients, we get:

```

>>> phi\_grad

<tf.Tensor: shape=(2,), dtype=float32, numpy=array([-0.47942555, 0. ], dtype=float32)>

>>> theta\_grad

<tf.Tensor: shape=(), dtype=float32, numpy=3.469447e-18>

```

To include non-differentiable data arguments, simply use `tf.constant`:

```

@qml.qnode(dev, interface='tf')

def circuit3(weights, data):

    qml.AmplitudeEmbedding(data, normalize=True, wires=[0, 1])

    qml.RX(weights[0], wires=0)

    qml.RY(weights[1], wires=1)

    qml.CNOT(wires=[0, 1])

    qml.PhaseShift(weights[2], wires=0)

    return qml.expval(qml.PauliZ(0))

weights = tf.Variable([0.1, 0.2, 0.3])

rng = np.random.default\_rng(seed=111)

data = tf.constant(rng.random([4]))

with tf.GradientTape() as tape:

    result = circuit3(weights, data)

```

Calculating the gradient:

```

>>> grad = tape.gradient(result, weights)

>>> grad

<tf.Tensor: shape=(3,), dtype=float32, numpy=array([0.08575502, 0. , 0. ], dtype=float32)>

```

###### Optimization using TensorFlow[¶](#optimization-using-tensorflow "Permalink to this headline")

To optimize your hybrid classical-quantum model using the TensorFlow eager interface,

you **must** make use of the TensorFlow optimizers provided in the `tf.train` module,

or your own custom TensorFlow optimizer. **The** [PennyLane optimizers](index.html#intro-ref-opt)

**cannot be used with the TensorFlow interface**.

For example, to optimize a TensorFlow-interfacing QNode (below) such that the weights `x`

result in an expectation value of 0.5, we can do the following:

```

dev = qml.device('default.qubit', wires=2)

@qml.qnode(dev, interface='tf')

def circuit4(phi, theta):

    qml.RX(phi[0], wires=0)

    qml.RY(phi[1], wires=1)

    qml.CNOT(wires=[0, 1])

    qml.PhaseShift(theta, wires=0)

    return qml.expval(qml.PauliZ(0))

phi = tf.Variable([0.5, 0.1], dtype=tf.float64)

theta = tf.Variable(0.2, dtype=tf.float64)

opt = tf.keras.optimizers.SGD(learning\_rate=0.1)

steps = 200

for i in range(steps):

    with tf.GradientTape() as tape:

        loss = tf.abs(circuit4(phi, theta) - 0.5)\*\*2

    gradients = tape.gradient(loss, [phi, theta])

    opt.apply\_gradients(zip(gradients, [phi, theta]))

```

The final weights and circuit value are:

```

>>> phi

<tf.Variable 'Variable:0' shape=(2,) dtype=float64, numpy=array([ 1.04719755, 0.1 ])>

>>> theta

<tf.Variable 'Variable:0' shape=() dtype=float64, numpy=0.20000000000000001>

>>> circuit4(phi, theta)

<tf.Tensor: id=106269, shape=(), dtype=float64, numpy=0.5000000000000091>

```

###### Keras integration[¶](#keras-integration "Permalink to this headline")

Once you have a TensorFlow-compaible QNode, it is easy to convert this into a Keras layer. To

help automate this process, PennyLane also provides a [`KerasLayer`](index.html#pennylane.qnn.KerasLayer "pennylane.qnn.KerasLayer") class to easily

convert a QNode to a Keras layer. Please see the corresponding [`KerasLayer`](index.html#pennylane.qnn.KerasLayer "pennylane.qnn.KerasLayer")

documentation for more details and examples.

##### JAX interface[¶](#jax-interface "Permalink to this headline")

Born out of the autograd package, [JAX](https://jax.readthedocs.io/en/latest/index.html) is the

next generation of differentiable functional computation, adding support for powerful hardware

accelerators like GPUs and TPUs via [XLA](https://www.tensorflow.org/xla). To use

PennyLane in combination with JAX, we have to generate JAX-compatible quantum nodes. A basic

`QNode` can be translated into a quantum node that interfaces with JAX by using the

`interface='jax'` flag in the QNode decorator.

Note

When using `diff\_method="parameter-shift"`, `diff\_method="finite-diff"`

or `diff\_method="adjoint"` with the JAX interface some restrictions apply to

the measurements in the QNode:

* Sample and probability measurements cannot be mixed with other measurement

types in QNodes;

* Multiple probability measurements need to have the same number of wires

specified;

However, when using `diff\_method="backprop"`, all QNode measurement statistics

are supported.

Note

To use the JAX interface in PennyLane, you must first

install `jax` and `jaxlib`. You can then import PennyLane and JAX as follows:

```

import pennylane as qml

import jax

import jax.numpy as jnp

```

Note

JAX supports the single-precision numbers by default. To enable

double-precision, add the following code on startup:

```

from jax.config import config

config.update("jax\_enable\_x64", True)

```

###### Construction via the decorator[¶](#construction-via-the-decorator "Permalink to this headline")

The [QNode decorator](index.html#intro-vcirc-decorator) is the recommended way for creating

a JAX-capable QNode in PennyLane. Simply specify the `interface='jax'` keyword argument:

```

dev = qml.device('default.qubit.jax', wires=2)

@qml.qnode(dev, interface='jax')

def circuit1(phi, theta):

    qml.RX(phi[0], wires=0)

    qml.RY(phi[1], wires=1)

    qml.CNOT(wires=[0, 1])

    qml.PhaseShift(theta, wires=0)

    return qml.expval(qml.PauliZ(0)), qml.expval(qml.Hadamard(1))

```

The QNode `circuit1()` is now a JAX-capable QNode, accepting `jax.Array` objects

as input, and returning `jax.Array` objects. It can now be used like any other JAX function:

```

>>> phi = jnp.array([0.5, 0.1])

>>> theta = jnp.array(0.2)

>>> circuit1(phi, theta)

(Array(0.87758256, dtype=float64), Array(0.68803733, dtype=float64))

```

The interface can also be automatically determined when the `QNode` is called. You do not need to pass the interface

if you provide parameters.

###### Quantum gradients using JAX[¶](#quantum-gradients-using-jax "Permalink to this headline")

Since a JAX-interfacing QNode acts like any other JAX interfacing python function,

the standard method used to calculate gradients with JAX can be used.

For example:

```

dev = qml.device('default.qubit.jax', wires=2)

@qml.qnode(dev, interface='jax')

def circuit3(phi, theta):

    qml.RX(phi[0], wires=0)

    qml.RY(phi[1], wires=1)

    qml.CNOT(wires=[0, 1])

    qml.PhaseShift(theta, wires=0)

    return qml.expval(qml.PauliZ(0))

phi = jnp.array([0.5, 0.1])

theta = jnp.array(0.2)

grads = jax.grad(circuit3, argnums=(0, 1))

phi\_grad, theta\_grad = grads(phi, theta)

```

This has output:

```

>>> phi\_grad

Array([-0.47942555, 0. ], dtype=float32)

>>> theta\_grad

Array(-3.4332792e-10, dtype=float32)

```

###### Using jax.jit on QNodes[¶](#using-jax-jit-on-qnodes "Permalink to this headline")

To fully utilize the power and speed of JAX, you’ll need to just-in-time compile your functions - a

process called “jitting”. If only expectation values or variances are returned,

the `@jax.jit` decorator can be directly applied to the QNode.

```

dev = qml.device('default.qubit.jax', wires=2)

@jax.jit  # QNode calls will now be jitted, and should run faster.

@qml.qnode(dev, interface='jax')

def circuit4(phi, theta):

    qml.RX(phi[0], wires=0)

    qml.RZ(phi[1], wires=1)

    qml.CNOT(wires=[0, 1])

    qml.RX(theta, wires=0)

    return qml.expval(qml.PauliZ(0))

```

Note

For differentiation methods other than `backprop`, when

`interface='jax'` is specified, PennyLane will attempt to determine if

the computation was just-in-time compiled. This is done by checking if any

of the input parameters were subject to a JAX transformation. If so, a

variant of the interface that supports the just-in-time compilation of

QNodes will be used. This is equivalent to passing `interface='jax-jit'`.

Computing the jacobian of vector-valued QNodes is not supported with the

JAX JIT interface. The output of vector-valued QNodes can, however, be used

in the definition of scalar-valued cost functions whose gradients can be

computed.

Specify `interface='jax-python'` to enforce support for computing the

backward pass of vector-valued QNodes (e.g., QNodes with probability, state

or multiple expectation value measurements). This option does not support

just-in-time compilation.

###### Randomness: Shots and Samples[¶](#randomness-shots-and-samples "Permalink to this headline")

In JAX, there is no such thing as statefull randomness, meaning all random number generators must be

explicitly seeded. (See the [JAX random package documentation](https://jax.readthedocs.io/en/latest/jax.random.html?highlight=random#module-jax.random) for more

details).

When simulations include randomness (i.e., if the device has a finite `shots` value, or the qnode

returns `qml.sample()`), the JAX device requires a `jax.random.PRNGKey`. Usually, PennyLane

automatically handles this for you. However, if you wish to use jitting with randomness, both the

qnode and the device need to be created in the context of the `jax.jit` decorator. This can be

achieved by wrapping device and qnode creation into a function decorated by `@jax.jit`:

Example:

```

import jax

import pennylane as qml

@jax.jit

def sample\_circuit(phi, theta, key):

    # Device construction should happen inside a `jax.jit` decorated

    # method when using a PRNGKey.

    dev = qml.device('default.qubit.jax', wires=2, prng\_key=key, shots=100)

    @qml.qnode(dev, interface='jax', diff\_method=None)

    def circuit(phi, theta):

        qml.RX(phi[0], wires=0)

        qml.RZ(phi[1], wires=1)

        qml.CNOT(wires=[0, 1])

        qml.RX(theta, wires=0)

        return qml.sample() # Here, we take samples instead.

    return circuit(phi, theta)

# Get the samples from the jitted method.

samples = sample\_circuit([0.2, 1.0], 5.2, jax.random.PRNGKey(0))

```

Note

If you don’t pass a PRNGKey when sampling with a `jax.jit`, every call to the sample function

will return the same result.

###### Optimization using JAXopt and Optax[¶](#optimization-using-jaxopt-and-optax "Permalink to this headline")

To optimize your hybrid classical-quantum model using the JAX interface, you

**must** make use of a package meant for optimizing JAX code (such as [JAXopt](https://jaxopt.github.io/stable/) or [Optax](https://optax.readthedocs.io/en/latest/)) or your own custom JAX optimizer.

**The** [PennyLane optimizers](index.html#intro-ref-opt) **cannot be used with the

JAX interface**.

As an example of using `JAXopt`, the `GradientDescent` optimizer may be

used to optimize a QNode that is transformed by `jax.jit`:

```

import pennylane as qml

import jax

import jaxopt

jax.config.update("jax\_enable\_x64", True)

dev = qml.device("default.qubit", wires=1, shots=None)

@jax.jit

@qml.qnode(dev, interface="jax")

def energy(a):

    qml.RX(a, wires=0)

    return qml.expval(qml.PauliZ(0))

gd = jaxopt.GradientDescent(energy, maxiter=5)

res = gd.run(0.5)

optimized\_params = res.params

```

```

>>> optimized\_params

Array(3.1415861, dtype=float64, weak\_type=True)

```

Alternatively, optimizers from `Optax` may also be used to optimize the same

QNode:

```

import pennylane as qml

from jax import numpy as jnp

import jax

import optax

learning\_rate = 0.15

dev = qml.device("default.qubit", wires=1, shots=None)

@jax.jit

@qml.qnode(dev, interface="jax")

def energy(a):

    qml.RX(a, wires=0)

    return qml.expval(qml.PauliZ(0))

optimizer = optax.adam(learning\_rate)

params = jnp.array(0.5)

opt\_state = optimizer.init(params)

for \_ in range(200):

    grads = jax.grad(energy)(params)

    updates, opt\_state = optimizer.update(grads, opt\_state)

    params = optax.apply\_updates(params, updates)

```

```

>>> params

Array(3.14159111, dtype=float64)

```

##### Unsupported gradient configurations[¶](#unsupported-gradient-configurations "Permalink to this headline")

###### Device jacobian[¶](#device-jacobian "Permalink to this headline")

In order to use `diff\_method="device"` for a QNode, the device passed into

the constructor of a QNode must have its `"provides\_jacobian"` capability set to `True`

and must contain a method `jacobian(circuits, \*\*kwargs)` that returns the gradients for

each quantum circuit. This is not implemented for the `default.qubit` device because

the device doesn’t provide such a jacobian method (instead allows backpropagation to work).

See the [custom plugins](index.html#plugin-overview) page for more detail.

An exception is raised if this configuration is used:

```

def print\_grad():

    dev = qml.device('default.qubit', wires=1, shots=None)

    @qml.qnode(dev, diff\_method='device')

    def circuit(x):

        qml.RX(x[0], wires=0)

        return qml.expval(qml.PauliZ(wires=0))

    x = np.array([0.1], requires\_grad=True)

    print(qml.grad(circuit)(x))

```

```

>>> print\_grad()

Traceback (most recent call last):

 ...

  File "C:\pennylane\pennylane\qnode.py", line 448, in \_validate\_device\_method

 raise qml.QuantumFunctionError(

pennylane.QuantumFunctionError: The default.qubit device does not provide a native method for computing the jacobian.

```

###### Backpropagation[¶](#backpropagation "Permalink to this headline")

The backpropagation algorithm is analytic by nature, and hence passing `shots=None`

is the only supported configuration when `diff\_method="backprop"` is used. Though

it is possible to always use the analytic gradient even when `shots>0` (as is the case

with adjoint differentiation, see next section), in the current state of the code this would

break other things.

Currently an exception is raised if this invalid configuration is used:

```

def print\_grad():

    dev = qml.device('default.qubit', wires=1, shots=100)

    @qml.qnode(dev, diff\_method='backprop')

    def circuit(x):

        qml.RX(x[0], wires=0)

        return qml.expval(qml.PauliZ(wires=0))

    x = np.array([0.1], requires\_grad=True)

    print(qml.grad(circuit)(x))

```

```

>>> print\_grad()

Traceback (most recent call last):

 ...

  File "C:\pennylane\pennylane\qnode.py", line 375, in \_validate\_backprop\_method

 raise qml.QuantumFunctionError("Backpropagation is only supported when shots=None.")

pennylane.QuantumFunctionError: Backpropagation is only supported when shots=None.

```

Changing to `shots=None` allows computing the analytic gradient:

```

def print\_grad():

    dev = qml.device('default.qubit', wires=1, shots=None)

    @qml.qnode(dev, diff\_method='backprop')

    def circuit(x):

        qml.RX(x[0], wires=0)

        return qml.expval(qml.PauliZ(wires=0))

    x = np.array([0.1], requires\_grad=True)

    print(qml.grad(circuit)(x))

```

```

>>> print\_grad()

[-0.09983342]

```

###### Adjoint differentiation[¶](#adjoint-differentiation "Permalink to this headline")

PennyLane implements the adjoint differentiation method from

[2009.02823](https://arxiv.org/pdf/2009.02823.pdf), which only discusses

the gradient of expectation of observables. The implementation is specific to the paper, hence the return statement

of the quantum function wrapped in `qml.qnode` can only contain [`expval()`](index.html#pennylane.expval "pennylane.expval") as a measurement.

In particular, the following code works as expected:

```

def print\_grad():

    dev = qml.device('default.qubit', wires=1, shots=None)

    @qml.qnode(dev, diff\_method='adjoint')

    def circuit(x):

        qml.RX(x[0], wires=0)

        return qml.expval(qml.PauliZ(wires=0))

    x = np.array([0.1], requires\_grad=True)

    print(qml.grad(circuit)(x))

```

```

>>> print\_grad()

[-0.09983342]

```

But the following code raises an error:

```

def print\_grad\_bad():

    dev = qml.device('default.qubit', wires=1, shots=None)

    @qml.qnode(dev, diff\_method='adjoint')

    def circuit(x):

        qml.RX(x[0], wires=0)

        return qml.state()

    def cost\_fn(x):

        out = circuit(x)

        return np.abs(out[0])

    x = np.array([0.1], requires\_grad=True)

    print(qml.grad(cost\_fn)(x))

```

```

>>> print\_grad\_bad()

Traceback (most recent call last):

 ...

  File "C:\pennylane\pennylane\\_qubit\_device.py", line 951, in adjoint\_jacobian

 raise qml.QuantumFunctionError(

pennylane.QuantumFunctionError: Adjoint differentiation method does not support measurement state

```

Furthermore, the adjoint differentiation algorithm is analytic by nature. If the user creates a device

with `shots>0`, a warning is raised and gradients are computed analytically:

```

def print\_grad\_ok():

    dev = qml.device('default.qubit', wires=1, shots=100)

    @qml.qnode(dev, diff\_method='adjoint')

    def circuit(x):

        qml.RX(x[0], wires=0)

        return qml.expval(qml.PauliZ(wires=0))

    x = np.array([0.1], requires\_grad=True)

    print(qml.grad(circuit)(x))

```

```

>>> print\_grad\_ok()

C:\pennylane\pennylane\qnode.py:434: UserWarning: Requested adjoint differentiation to be computed with finite shots. Adjoint differentiation always calculated exactly.

 warnings.warn(

C:\pennylane\pennylane\\_qubit\_device.py:965: UserWarning: Requested adjoint differentiation to be computed with finite shots. The derivative is always exact when using the adjoint differentiation method.

 warnings.warn(

[-0.09983342]

```

###### State gradients[¶](#state-gradients "Permalink to this headline")

In general, the state of a quantum circuit will be complex-valued, so differentiating

the state directly is not possible without the use of

[complex analysis](https://en.wikipedia.org/wiki/Holomorphic_function). Though complex

gradients can be implemented for most “simple” functions, this is not supported in Autograd

but is done in the other three interfaces.

Instead, in Autograd, real scalar-valued post-processing should be performed on the output state to allow

the auto-differentiation frameworks to backpropagate through them. For example, the following

code uses a scalar cost function dependent on the output state:

```

def state\_scalar\_grad():

    dev = qml.device('default.qubit', wires=1, shots=None)

    @qml.qnode(dev, diff\_method='backprop')

    def circuit(x):

        qml.RX(x[0], wires=0)

        return qml.state()

    def cost\_fn(x):

        out = circuit(x)

        return np.abs(out[0])

    x = np.array([0.1], requires\_grad=True)

    print(qml.grad(cost\_fn)(x))

```

```

>>> state\_scalar\_grad()

[-0.02498958]

```

However, changing from differentiating the scalar cost to differentiating the state

directly will fail with an error:

```

def state\_vector\_grad():

    dev = qml.device('default.qubit', wires=1, shots=None)

    @qml.qnode(dev, diff\_method='backprop')

    def circuit(x):

        qml.RX(x[0], wires=0)

        return qml.state()

    x = np.array([0.1], requires\_grad=True)

    print(qml.jacobian(circuit)(x))

```

```

>>> state\_vector\_grad()

Traceback (most recent call last):

 ...

  File "C:\Python38\lib\site-packages\numpy\core\fromnumeric.py", line 57, in \_wrapfunc

 return bound(\*args, \*\*kwds)

ValueError: cannot reshape array of size 4 into shape (2,1)

```

Using a different interface that supports complex differentiation will fix this error:

```

def state\_vector\_grad\_jax():

    dev = qml.device('default.qubit', wires=1, shots=None)

    @qml.qnode(dev, interface='jax', diff\_method='backprop')

    def circuit(x):

        qml.RX(x[0], wires=0)

        return qml.state()

    x = jnp.array([0.1], dtype=np.complex64)

    print(jax.jacrev(circuit, holomorphic=True)(x))

def state\_vector\_grad\_tf():

    dev = qml.device('default.qubit', wires=1, shots=None)

    @qml.qnode(dev, interface='tf', diff\_method='backprop')

    def circuit(x):

        qml.RX(x[0], wires=0)

        return qml.state()

    x = tf.Variable([0.1], trainable=True, dtype=np.complex64)

    with tf.GradientTape() as tape:

        out = circuit(x)

    print(tape.jacobian(out, [x]))

def state\_vector\_grad\_torch():

    dev = qml.device('default.qubit', wires=1, shots=None)

    @qml.qnode(dev, interface='torch', diff\_method='backprop')

    def circuit(x):

        qml.RX(x[0], wires=0)

        return qml.state()

    x = torch.tensor([0.1], requires\_grad=True, dtype=torch.complex64)

    print(torch.autograd.functional.jacobian(circuit, (x,)))

```

```

>>> state\_vector\_grad\_jax()

[[-0.02498958+0.j ]

 [ 0. -0.49937513j]]

>>> state\_vector\_grad\_tf()

[<tf.Tensor: shape=(2, 1), dtype=complex64, numpy=

array([[-0.02498958+0.j ],

 [-0. +0.49937513j]], dtype=complex64)>]

>>> state\_vector\_grad\_torch()

(tensor([[-0.0250+0.0000j],

 [ 0.0000+0.4994j]]),)

```

###### Sample gradients[¶](#sample-gradients "Permalink to this headline")

In PennyLane, samples are drawn from the eigenvalues of an observable, or from the

computational basis states if no observable is provided. This process is not differentiable

in general, so no gradient flow backwards through the sampling is allowed.

Currently, attempting to compute the gradient in this scenario will not raise an

error, but the results will be incorrect:

```

def sample\_backward():

    dev = qml.device('default.qubit', wires=1, shots=20)

    @qml.qnode(dev)

    def circuit(x):

        qml.RX(x[0], wires=0)

        return qml.sample(wires=0)

    x = np.array([np.pi / 2])

    print(qml.jacobian(circuit)(x))

```

```

>>> sample\_backward()

[[0.5]

 [0.5]

 [0.5]

 [0.5]

 [0.5]

 [0.5]

 [0.5]

 [0.5]

 [0.5]

 [0.5]

 [0.5]

 [0.5]

 [0.5]

 [0.5]

 [0.5]

 [0.5]

 [0.5]

 [0.5]

 [0.5]

 [0.5]]

```

The forward pass is supported and will work as expected:

```

def sample\_forward():

    dev = qml.device('default.qubit', wires=1, shots=20)

    @qml.qnode(dev)

    def circuit(x):

        qml.RX(x[0], wires=0)

        return qml.sample(wires=0)

    x = np.array([np.pi / 2])

    print(circuit(x))

```

```

>>> sample\_forward()

[0 1 0 0 0 1 1 0 0 1 1 1 0 0 0 1 1 0 0 0]

```

### Quantum operators[¶](#quantum-operators "Permalink to this headline")

PennyLane supports a wide variety of quantum operators—such as gates, noisy channels, state preparations and measurements.

These operators can be used in quantum functions, like shown in the following example:

```

import pennylane as qml

def my\_quantum\_function(x, y):

    qml.RZ(x, wires=0)

    qml.CNOT(wires=[0,1])

    qml.RY(y, wires=1)

    qml.AmplitudeDamping(0.1, wires=0)

    return qml.expval(qml.PauliZ(1))

```

This quantum function uses the [`RZ`](index.html#pennylane.RZ "pennylane.RZ"),

[`CNOT`](index.html#pennylane.CNOT "pennylane.CNOT"),

[`RY`](index.html#pennylane.RY "pennylane.RY") gates, the

[`AmplitudeDamping`](index.html#pennylane.AmplitudeDamping "pennylane.AmplitudeDamping")

noisy channel as well as the

[`PauliZ`](index.html#pennylane.PauliZ "pennylane.PauliZ") observable.

Functions applied to operators extract information (such as the matrix representation) or

transform operators (like turning a gate into a controlled gate).

PennyLane supports the following operators and operator functions:

#### Operator functions[¶](#operator-functions "Permalink to this headline")

Various functions and transforms are available for manipulating operators,

and extracting information. These can be broken down into two main categories:

##### Operator to Operator functions[¶](#operator-to-operator-functions "Permalink to this headline")

| [`adjoint`](index.html#pennylane.adjoint "pennylane.adjoint")(fn[, lazy]) | Create the adjoint of an Operator or a function that applies the adjoint of the provided function. |

| [`ctrl`](index.html#pennylane.ctrl "pennylane.ctrl")(op, control[, control\_values, work\_wires]) | Create a method that applies a controlled version of the provided op. |

| [`cond`](index.html#pennylane.cond "pennylane.cond")(condition, true\_fn[, false\_fn]) | Condition a quantum operation on the results of mid-circuit qubit measurements. |

| [`exp`](index.html#pennylane.exp "pennylane.exp")(op[, coeff, num\_steps, id]) | Take the exponential of an Operator times a coefficient. |

| [`sum`](index.html#pennylane.sum "pennylane.sum")(\*summands[, id, lazy]) | Construct an operator which is the sum of the given operators. |

| [`pow`](index.html#pennylane.pow "pennylane.pow")(base[, z, lazy, id]) | Raise an Operator to a power. |

| [`prod`](index.html#pennylane.prod "pennylane.prod")(\*ops[, id, lazy]) | Construct an operator which represents the generalized product of the operators provided. |

| [`s\_prod`](index.html#pennylane.s_prod "pennylane.s_prod")(scalar, operator[, lazy, id]) | Construct an operator which is the scalar product of the given scalar and operator provided. |

| [`generator`](index.html#pennylane.generator "pennylane.generator")(op[, format]) | Returns the generator of an operation. |

| [`map\_wires`](index.html#pennylane.map_wires "pennylane.map_wires")(input, wire\_map[, queue, replace]) | Changes the wires of an operator, tape, qnode or quantum function according to the given wire map. |

| [`dot`](index.html#pennylane.dot "pennylane.dot")(coeffs, ops[, pauli]) | Returns the dot product between the `coeffs` vector and the `ops` list of operators. |

| [`evolve`](index.html#pennylane.evolve "pennylane.evolve")() | This method is dispatched and its functionality depends on the type of the input `op`. |

These operator functions act on operators to produce new operators.

```

>>> op = qml.prod(qml.PauliX(0), qml.PauliZ(1))

>>> op = qml.sum(qml.Hadamard(0), op)

>>> op = qml.s\_prod(1.2, op)

>>> op

1.2\*(Hadamard(wires=[0]) + (PauliX(wires=[0]) @ PauliZ(wires=[1])))

```

##### Operator to Other functions[¶](#operator-to-other-functions "Permalink to this headline")

| [`matrix`](index.html#pennylane.matrix "pennylane.matrix")(op, \*[, wire\_order]) | The matrix representation of an operation or quantum circuit. |

| [`eigvals`](index.html#pennylane.eigvals "pennylane.eigvals")(op[, k, which]) | The eigenvalues of one or more operations. |

| [`is\_commuting`](index.html#pennylane.is_commuting "pennylane.is_commuting")(operation1, operation2[, wire\_map]) | Check if two operations are commuting using a lookup table. |

| [`is\_hermitian`](index.html#pennylane.is_hermitian "pennylane.is_hermitian")(op) | Check if the operation is hermitian. |

| [`is\_unitary`](index.html#pennylane.is_unitary "pennylane.is_unitary")(op) | Check if the operation is unitary. |

| [`simplify`](index.html#pennylane.simplify "pennylane.simplify")(input) | Simplifies an operator, tape, qnode or quantum function by reducing its arithmetic depth or number of rotation parameters. |

These operator functions act on operators and return other data types.

All operator functions can be used on instantiated operators.

```

>>> op = qml.RX(0.54, wires=0)

>>> qml.matrix(op)

[[0.9637709+0.j 0. -0.26673144j]

[0. -0.26673144j 0.9637709+0.j ]]

```

Some operator functions can also be used in a functional form:

```

>>> x = torch.tensor(0.6, requires\_grad=True)

>>> matrix\_fn = qml.matrix(qml.RX)

>>> matrix\_fn(x, wires=0)

tensor([[0.9553+0.0000j, 0.0000-0.2955j],

 [0.0000-0.2955j, 0.9553+0.0000j]], grad\_fn=<StackBackward0>)

```

In the functional form, they are usually differentiable with respect to gate arguments:

```

>>> loss = torch.real(torch.trace(matrix\_fn(x, wires=0)))

>>> loss.backward()

>>> x.grad

tensor(-0.2955)

```

Some operator transforms can also act on multiple operators, by passing

quantum functions, QNodes or tapes:

```

>>> def circuit(theta):

...     qml.RX(theta, wires=1)

...     qml.PauliZ(wires=0)

>>> qml.matrix(circuit)(np.pi / 4)

array([[ 0.92387953+0.j, 0.+0.j , 0.-0.38268343j, 0.+0.j],

[ 0.+0.j, -0.92387953+0.j, 0.+0.j, 0. +0.38268343j],

[ 0. -0.38268343j, 0.+0.j, 0.92387953+0.j, 0.+0.j],

[ 0.+0.j, 0.+0.38268343j, 0.+0.j, -0.92387953+0.j]])

```

##### Matrix to Operator functions[¶](#matrix-to-operator-functions "Permalink to this headline")

| [`pauli\_decompose`](index.html#pennylane.pauli_decompose "pennylane.pauli_decompose")(H[, hide\_identity, …]) | Decomposes a Hermitian matrix into a linear combination of Pauli operators. |

| [`qsvt`](index.html#pennylane.qsvt "pennylane.qsvt")(A, angles, wires[, convention]) | Implements the [quantum singular value transformation](https://arxiv.org/abs/1806.01838) (QSVT) circuit. |

These functions take a matrix and return an associated native PennyLane operator.

For example:

```

>>> mat = np.array([[1, 1], [1, -1]])

>>> h = qml.pauli\_decompose(mat)

>>> type(h)

<class 'pennylane.ops.qubit.hamiltonian.Hamiltonian'>

>>> print(h)

(1.0) [X0]

+ (1.0) [Z0]

```

#### Qubit operators[¶](#qubit-operators "Permalink to this headline")

##### Non-parametrized gates[¶](#non-parametrized-gates "Permalink to this headline")

| [`Identity`](index.html#pennylane.Identity "pennylane.Identity") | The identity observable \(\I\). |

| [`Hadamard`](index.html#pennylane.Hadamard "pennylane.Hadamard") | The Hadamard operator |

| [`PauliX`](index.html#pennylane.PauliX "pennylane.PauliX") | The Pauli X operator |

| [`PauliY`](index.html#pennylane.PauliY "pennylane.PauliY") | The Pauli Y operator |

| [`PauliZ`](index.html#pennylane.PauliZ "pennylane.PauliZ") | The Pauli Z operator |

| [`S`](index.html#pennylane.S "pennylane.S") | The single-qubit phase gate |

| [`T`](index.html#pennylane.T "pennylane.T") | The single-qubit T gate |

| [`SX`](index.html#pennylane.SX "pennylane.SX") | The single-qubit Square-Root X operator. |

| [`CNOT`](index.html#pennylane.CNOT "pennylane.CNOT") | The controlled-NOT operator |

| [`CZ`](index.html#pennylane.CZ "pennylane.CZ") | The controlled-Z operator |

| [`CY`](index.html#pennylane.CY "pennylane.CY") | The controlled-Y operator |

| [`CH`](index.html#pennylane.CH "pennylane.CH") | The controlled-Hadamard operator |

| [`SWAP`](index.html#pennylane.SWAP "pennylane.SWAP") | The swap operator |

| [`ISWAP`](index.html#pennylane.ISWAP "pennylane.ISWAP") | The i-swap operator |

| [`ECR`](index.html#pennylane.ECR "pennylane.ECR") | An echoed RZX(pi/2) gate. |

| [`SISWAP`](index.html#pennylane.SISWAP "pennylane.SISWAP") | The square root of i-swap operator. |

| [`SQISW`](index.html#pennylane.SQISW "pennylane.SQISW") | alias of `pennylane.ops.qubit.non\_parametric\_ops.SISWAP` |

| [`CSWAP`](index.html#pennylane.CSWAP "pennylane.CSWAP") | The controlled-swap operator |

| [`Toffoli`](index.html#pennylane.Toffoli "pennylane.Toffoli") | Toffoli (controlled-controlled-X) gate. |

| [`MultiControlledX`](index.html#pennylane.MultiControlledX "pennylane.MultiControlledX") | Apply a Pauli X gate controlled on an arbitrary computational basis state. |

| [`Barrier`](index.html#pennylane.Barrier "pennylane.Barrier") | The Barrier operator, used to separate the compilation process into blocks or as a visual tool. |

| [`WireCut`](index.html#pennylane.WireCut "pennylane.WireCut") | The wire cut operation, used to manually mark locations for wire cuts. |

##### Parametrized gates[¶](#parametrized-gates "Permalink to this headline")

| [`Rot`](index.html#pennylane.Rot "pennylane.Rot") | Arbitrary single qubit rotation |

| [`RX`](index.html#pennylane.RX "pennylane.RX") | The single qubit X rotation |

| [`RY`](index.html#pennylane.RY "pennylane.RY") | The single qubit Y rotation |

| [`RZ`](index.html#pennylane.RZ "pennylane.RZ") | The single qubit Z rotation |

| [`MultiRZ`](index.html#pennylane.MultiRZ "pennylane.MultiRZ") | Arbitrary multi Z rotation. |

| [`PauliRot`](index.html#pennylane.PauliRot "pennylane.PauliRot") | Arbitrary Pauli word rotation. |

| [`PhaseShift`](index.html#pennylane.PhaseShift "pennylane.PhaseShift") | Arbitrary single qubit local phase shift |

| [`ControlledPhaseShift`](index.html#pennylane.ControlledPhaseShift "pennylane.ControlledPhaseShift") | A qubit controlled phase shift. |

| [`CPhase`](index.html#pennylane.CPhase "pennylane.CPhase") | alias of `pennylane.ops.qubit.parametric\_ops\_controlled.ControlledPhaseShift` |

| [`PCPhase`](index.html#pennylane.PCPhase "pennylane.PCPhase") | A projector-controlled phase gate. |

| [`CPhaseShift00`](index.html#pennylane.CPhaseShift00 "pennylane.CPhaseShift00") | A qubit controlled phase shift. |

| [`CPhaseShift01`](index.html#pennylane.CPhaseShift01 "pennylane.CPhaseShift01") | A qubit controlled phase shift. |

| [`CPhaseShift10`](index.html#pennylane.CPhaseShift10 "pennylane.CPhaseShift10") | A qubit controlled phase shift. |

| [`CRX`](index.html#pennylane.CRX "pennylane.CRX") | The controlled-RX operator |

| [`CRY`](index.html#pennylane.CRY "pennylane.CRY") | The controlled-RY operator |

| [`CRZ`](index.html#pennylane.CRZ "pennylane.CRZ") | The controlled-RZ operator |

| [`CRot`](index.html#pennylane.CRot "pennylane.CRot") | The controlled-Rot operator |

| [`U1`](index.html#pennylane.U1 "pennylane.U1") | U1 gate. |

| [`U2`](index.html#pennylane.U2 "pennylane.U2") | U2 gate. |

| [`U3`](index.html#pennylane.U3 "pennylane.U3") | Arbitrary single qubit unitary. |

| [`IsingXX`](index.html#pennylane.IsingXX "pennylane.IsingXX") | Ising XX coupling gate |

| [`IsingXY`](index.html#pennylane.IsingXY "pennylane.IsingXY") | Ising (XX + YY) coupling gate |

| [`IsingYY`](index.html#pennylane.IsingYY "pennylane.IsingYY") | Ising YY coupling gate |

| [`IsingZZ`](index.html#pennylane.IsingZZ "pennylane.IsingZZ") | Ising ZZ coupling gate |

| [`PSWAP`](index.html#pennylane.PSWAP "pennylane.PSWAP") | Phase SWAP gate |

##### Quantum chemistry gates[¶](#quantum-chemistry-gates "Permalink to this headline")

| [`SingleExcitation`](index.html#pennylane.SingleExcitation "pennylane.SingleExcitation") | Single excitation rotation. |

| [`SingleExcitationPlus`](index.html#pennylane.SingleExcitationPlus "pennylane.SingleExcitationPlus") | Single excitation rotation with positive phase-shift outside the rotation subspace. |

| [`SingleExcitationMinus`](index.html#pennylane.SingleExcitationMinus "pennylane.SingleExcitationMinus") | Single excitation rotation with negative phase-shift outside the rotation subspace. |

| [`DoubleExcitation`](index.html#pennylane.DoubleExcitation "pennylane.DoubleExcitation") | Double excitation rotation. |

| [`DoubleExcitationPlus`](index.html#pennylane.DoubleExcitationPlus "pennylane.DoubleExcitationPlus") | Double excitation rotation with positive phase-shift outside the rotation subspace. |

| [`DoubleExcitationMinus`](index.html#pennylane.DoubleExcitationMinus "pennylane.DoubleExcitationMinus") | Double excitation rotation with negative phase-shift outside the rotation subspace. |

| [`OrbitalRotation`](index.html#pennylane.OrbitalRotation "pennylane.OrbitalRotation") | Spin-adapted spatial orbital rotation. |

| [`FermionicSWAP`](index.html#pennylane.FermionicSWAP "pennylane.FermionicSWAP") | Fermionic SWAP rotation. |

Electronic Hamiltonians built independently using

[OpenFermion](https://github.com/quantumlib/OpenFermion) tools can be readily converted to a

PennyLane observable using the [`import\_operator()`](index.html#pennylane.import_operator "pennylane.import_operator") function.

##### Gates constructed from a matrix[¶](#gates-constructed-from-a-matrix "Permalink to this headline")

| [`QubitUnitary`](index.html#pennylane.QubitUnitary "pennylane.QubitUnitary") | Apply an arbitrary unitary matrix with a dimension that is a power of two. |

| [`ControlledQubitUnitary`](index.html#pennylane.ControlledQubitUnitary "pennylane.ControlledQubitUnitary") | Apply an arbitrary fixed unitary to `wires` with control from the `control\_wires`. |

| [`DiagonalQubitUnitary`](index.html#pennylane.DiagonalQubitUnitary "pennylane.DiagonalQubitUnitary") | Apply an arbitrary diagonal unitary matrix with a dimension that is a power of two. |

| [`SpecialUnitary`](index.html#pennylane.SpecialUnitary "pennylane.SpecialUnitary") | Gate from the group \(SU(N)\) with \(N=2^n\) for \(n\) qubits. |

| [`BlockEncode`](index.html#pennylane.BlockEncode "pennylane.BlockEncode") | Construct a unitary \(U(A)\) such that an arbitrary matrix \(A\) is encoded in the top-left block. |

##### Gates performing arithmetics[¶](#gates-performing-arithmetics "Permalink to this headline")

| [`QubitCarry`](index.html#pennylane.QubitCarry "pennylane.QubitCarry") | Apply the `QubitCarry` operation to four input wires. |

| [`QubitSum`](index.html#pennylane.QubitSum "pennylane.QubitSum") | Apply a `QubitSum` operation on three input wires. |

| [`IntegerComparator`](index.html#pennylane.IntegerComparator "pennylane.IntegerComparator") | Apply a controlled Pauli X gate using integer comparison as the condition. |

##### State preparation[¶](#state-preparation "Permalink to this headline")

| [`BasisState`](index.html#pennylane.BasisState "pennylane.BasisState") | Prepares a single computational basis state. |

| [`StatePrep`](index.html#pennylane.StatePrep "pennylane.StatePrep") | Prepare subsystems using the given ket vector in the computational basis. |

| [`QubitDensityMatrix`](index.html#pennylane.QubitDensityMatrix "pennylane.QubitDensityMatrix") | Prepare subsystems using the given density matrix. |

##### Noisy channels[¶](#noisy-channels "Permalink to this headline")

| [`AmplitudeDamping`](index.html#pennylane.AmplitudeDamping "pennylane.AmplitudeDamping") | Single-qubit amplitude damping error channel. |

| [`GeneralizedAmplitudeDamping`](index.html#pennylane.GeneralizedAmplitudeDamping "pennylane.GeneralizedAmplitudeDamping") | Single-qubit generalized amplitude damping error channel. |

| [`PhaseDamping`](index.html#pennylane.PhaseDamping "pennylane.PhaseDamping") | Single-qubit phase damping error channel. |

| [`DepolarizingChannel`](index.html#pennylane.DepolarizingChannel "pennylane.DepolarizingChannel") | Single-qubit symmetrically depolarizing error channel. |

| [`BitFlip`](index.html#pennylane.BitFlip "pennylane.BitFlip") | Single-qubit bit flip (Pauli \(X\)) error channel. |

| [`PhaseFlip`](index.html#pennylane.PhaseFlip "pennylane.PhaseFlip") | Single-qubit bit flip (Pauli \(Z\)) error channel. |

| [`ResetError`](index.html#pennylane.ResetError "pennylane.ResetError") | Single-qubit Reset error channel. |

| [`PauliError`](index.html#pennylane.PauliError "pennylane.PauliError") | Pauli operator error channel for an arbitrary number of qubits. |

| [`QubitChannel`](index.html#pennylane.QubitChannel "pennylane.QubitChannel") | Apply an arbitrary fixed quantum channel. |

| [`ThermalRelaxationError`](index.html#pennylane.ThermalRelaxationError "pennylane.ThermalRelaxationError") | Thermal relaxation error channel. |

##### Observables[¶](#observables "Permalink to this headline")

| [`Hadamard`](index.html#pennylane.Hadamard "pennylane.Hadamard") | The Hadamard operator |

| [`Hermitian`](index.html#pennylane.Hermitian "pennylane.Hermitian") | An arbitrary Hermitian observable. |

| [`Identity`](index.html#pennylane.Identity "pennylane.Identity") | The identity observable \(\I\). |

| [`PauliX`](index.html#pennylane.PauliX "pennylane.PauliX") | The Pauli X operator |

| [`PauliY`](index.html#pennylane.PauliY "pennylane.PauliY") | The Pauli Y operator |

| [`PauliZ`](index.html#pennylane.PauliZ "pennylane.PauliZ") | The Pauli Z operator |

| [`Projector`](index.html#pennylane.Projector "pennylane.Projector") | Observable corresponding to the state projector \(P=\ket{\phi}\bra{\phi}\). |

| [`Hamiltonian`](index.html#pennylane.Hamiltonian "pennylane.Hamiltonian") | Operator representing a Hamiltonian. |

| [`SparseHamiltonian`](index.html#pennylane.SparseHamiltonian "pennylane.SparseHamiltonian") | A Hamiltonian represented directly as a sparse matrix in Compressed Sparse Row (CSR) format. |

#### Continuous-Variable (CV) operators[¶](#continuous-variable-cv-operators "Permalink to this headline")

If you would like to learn more about the CV model of quantum computing, check out the

[quantum photonics](https://strawberryfields.ai/photonics/concepts/photonics.html)

page of the [Strawberry Fields](https://strawberryfields.ai/) documentation.

##### CV gates[¶](#cv-gates "Permalink to this headline")

| [`Identity`](index.html#pennylane.Identity "pennylane.Identity") | The identity observable \(\I\). |

| [`Beamsplitter`](index.html#pennylane.Beamsplitter "pennylane.Beamsplitter") | Beamsplitter interaction. |

| [`ControlledAddition`](index.html#pennylane.ControlledAddition "pennylane.ControlledAddition") | Controlled addition operation. |

| [`ControlledPhase`](index.html#pennylane.ControlledPhase "pennylane.ControlledPhase") | Controlled phase operation. |

| [`CrossKerr`](index.html#pennylane.CrossKerr "pennylane.CrossKerr") | Cross-Kerr interaction. |

| [`CubicPhase`](index.html#pennylane.CubicPhase "pennylane.CubicPhase") | Cubic phase shift. |

| [`Displacement`](index.html#pennylane.Displacement "pennylane.Displacement") | Phase space displacement. |

| [`InterferometerUnitary`](index.html#pennylane.InterferometerUnitary "pennylane.InterferometerUnitary") | A linear interferometer transforming the bosonic operators according to the unitary matrix \(U\). |

| [`Kerr`](index.html#pennylane.Kerr "pennylane.Kerr") | Kerr interaction. |

| [`QuadraticPhase`](index.html#pennylane.QuadraticPhase "pennylane.QuadraticPhase") | Quadratic phase shift. |

| [`Rotation`](index.html#pennylane.Rotation "pennylane.Rotation") | Phase space rotation. |

| [`Squeezing`](index.html#pennylane.Squeezing "pennylane.Squeezing") | Phase space squeezing. |

| [`TwoModeSqueezing`](index.html#pennylane.TwoModeSqueezing "pennylane.TwoModeSqueezing") | Phase space two-mode squeezing. |

##### CV state preparation[¶](#cv-state-preparation "Permalink to this headline")

| [`CatState`](index.html#pennylane.CatState "pennylane.CatState") | Prepares a cat state. |

| [`CoherentState`](index.html#pennylane.CoherentState "pennylane.CoherentState") | Prepares a coherent state. |

| [`DisplacedSqueezedState`](index.html#pennylane.DisplacedSqueezedState "pennylane.DisplacedSqueezedState") | Prepares a displaced squeezed vacuum state. |

| [`FockDensityMatrix`](index.html#pennylane.FockDensityMatrix "pennylane.FockDensityMatrix") | Prepare subsystems using the given density matrix in the Fock basis. |

| [`FockState`](index.html#pennylane.FockState "pennylane.FockState") | Prepares a single Fock state. |

| [`FockStateVector`](index.html#pennylane.FockStateVector "pennylane.FockStateVector") | Prepare subsystems using the given ket vector in the Fock basis. |

| [`GaussianState`](index.html#pennylane.GaussianState "pennylane.GaussianState") | Prepare subsystems in a given Gaussian state. |

| [`SqueezedState`](index.html#pennylane.SqueezedState "pennylane.SqueezedState") | Prepares a squeezed vacuum state. |

| [`ThermalState`](index.html#pennylane.ThermalState "pennylane.ThermalState") | Prepares a thermal state. |

##### CV observables[¶](#cv-observables "Permalink to this headline")

| [`FockStateProjector`](index.html#pennylane.FockStateProjector "pennylane.FockStateProjector") | The number state observable \(\ket{n}\bra{n}\). |

| [`Identity`](index.html#pennylane.Identity "pennylane.Identity") | The identity observable \(\I\). |

| [`NumberOperator`](index.html#pennylane.NumberOperator "pennylane.NumberOperator") | The photon number observable \(\langle \hat{n}\rangle\). |

| [`TensorN`](index.html#pennylane.TensorN "pennylane.TensorN") | The tensor product of the [`NumberOperator`](index.html#pennylane.NumberOperator "pennylane.NumberOperator") acting on different wires. |

| [`QuadP`](index.html#pennylane.QuadP "pennylane.QuadP") | The momentum quadrature observable \(\hat{p}\). |

| [`PolyXP`](index.html#pennylane.PolyXP "pennylane.PolyXP") | An arbitrary second-order polynomial observable. |

| [`QuadOperator`](index.html#pennylane.QuadOperator "pennylane.QuadOperator") | The generalized quadrature observable \(\x\_\phi = \x cos\phi+\p\sin\phi\). |

| [`QuadX`](index.html#pennylane.QuadX "pennylane.QuadX") | The position quadrature observable \(\hat{x}\). |

#### Qutrit operators[¶](#qutrit-operators "Permalink to this headline")

##### Qutrit non-parametrized gates[¶](#qutrit-non-parametrized-gates "Permalink to this headline")

| [`TShift`](index.html#pennylane.TShift "pennylane.TShift") | The qutrit shift operator |

| [`TClock`](index.html#pennylane.TClock "pennylane.TClock") | Ternary Clock gate |

| [`THadamard`](index.html#pennylane.THadamard "pennylane.THadamard") | The ternary Hadamard operator |

| [`TAdd`](index.html#pennylane.TAdd "pennylane.TAdd") | The 2-qutrit controlled add gate |

| [`TSWAP`](index.html#pennylane.TSWAP "pennylane.TSWAP") | The ternary swap operator. |

##### Qutrit gates constructed from a matrix[¶](#qutrit-gates-constructed-from-a-matrix "Permalink to this headline")

| [`QutritUnitary`](index.html#pennylane.QutritUnitary "pennylane.QutritUnitary") | Apply an arbitrary, fixed unitary matrix. |

| [`ControlledQutritUnitary`](index.html#pennylane.ControlledQutritUnitary "pennylane.ControlledQutritUnitary") | Apply an arbitrary fixed unitary to `wires` with control from the `control\_wires`. |

##### Qutrit parametrized gates[¶](#qutrit-parametrized-gates "Permalink to this headline")

| [`TRX`](index.html#pennylane.TRX "pennylane.TRX") | The single qutrit X rotation |

| [`TRY`](index.html#pennylane.TRY "pennylane.TRY") | The single qutrit Y rotation |

| [`TRZ`](index.html#pennylane.TRZ "pennylane.TRZ") | The single qutrit Z rotation |

##### Qutrit State preparation[¶](#qutrit-state-preparation "Permalink to this headline")

| [`QutritBasisState`](index.html#pennylane.QutritBasisState "pennylane.QutritBasisState") | Prepares a single computational basis state for a qutrit system. |

##### Qutrit Observables[¶](#qutrit-observables "Permalink to this headline")

| [`THermitian`](index.html#pennylane.THermitian "pennylane.THermitian") | An arbitrary Hermitian observable for qutrits. |

| [`GellMann`](index.html#pennylane.GellMann "pennylane.GellMann") | The Gell-Mann observables for qutrits |

#### Pulse-level operators[¶](#pulse-level-operators "Permalink to this headline")

If you would like to learn more about the implementation of pulse-level control in PennyLane, see the

[`pulse`](index.html#module-pennylane.pulse "pennylane.pulse") module documentation.

##### Pulse operator[¶](#pulse-operator "Permalink to this headline")

| [`ParametrizedEvolution`](index.html#pennylane.pulse.ParametrizedEvolution "pennylane.pulse.ParametrizedEvolution") | Parametrized evolution gate, created by passing a [`ParametrizedHamiltonian`](index.html#pennylane.pulse.ParametrizedHamiltonian "pennylane.pulse.ParametrizedHamiltonian") to the [`evolve()`](index.html#pennylane.evolve "pennylane.evolve") function |

| [`ParametrizedHamiltonian`](index.html#pennylane.pulse.ParametrizedHamiltonian "pennylane.pulse.ParametrizedHamiltonian") | Callable object holding the information representing a parametrized Hamiltonian. |

### Measurements[¶](#measurements "Permalink to this headline")

PennyLane can extract different types of measurement results from quantum

devices: the expectation of an observable, its variance,

samples of a single measurement, or computational basis state probabilities.

For example, the following circuit returns the expectation value of the

[`PauliZ`](index.html#pennylane.PauliZ "pennylane.PauliZ") observable on wire 1:

```

def my\_quantum\_function(x, y):

    qml.RZ(x, wires=0)

    qml.CNOT(wires=[0, 1])

    qml.RY(y, wires=1)

    return qml.expval(qml.PauliZ(1))

```

The available measurement functions are

| [`expval`](index.html#pennylane.expval "pennylane.expval")(op) | Expectation value of the supplied observable. |

| [`sample`](index.html#pennylane.sample "pennylane.sample")([op, wires]) | Sample from the supplied observable, with the number of shots determined from the `dev.shots` attribute of the corresponding device, returning raw samples. |

| [`counts`](index.html#pennylane.counts "pennylane.counts")([op, wires, all\_outcomes]) | Sample from the supplied observable, with the number of shots determined from the `dev.shots` attribute of the corresponding device, returning the number of counts for each sample. |

| [`var`](index.html#pennylane.var "pennylane.var")(op) | Variance of the supplied observable. |

| [`probs`](index.html#pennylane.probs "pennylane.probs")([wires, op]) | Probability of each computational basis state. |

| [`state`](index.html#pennylane.state "pennylane.state")() | Quantum state in the computational basis. |

| [`density\_matrix`](index.html#pennylane.density_matrix "pennylane.density_matrix")(wires) | Quantum density matrix in the computational basis. |

| [`vn\_entropy`](index.html#pennylane.vn_entropy "pennylane.vn_entropy")(wires[, log\_base]) | Von Neumann entropy of the system prior to measurement. |

| [`mutual\_info`](index.html#pennylane.mutual_info "pennylane.mutual_info")(wires0, wires1[, log\_base]) | Mutual information between the subsystems prior to measurement: |

| [`purity`](index.html#pennylane.purity "pennylane.purity")(wires) | The purity of the system prior to measurement. |

| [`classical\_shadow`](index.html#pennylane.classical_shadow "pennylane.classical_shadow")(wires[, seed]) | The classical shadow measurement protocol. |

| [`shadow\_expval`](index.html#pennylane.shadow_expval "pennylane.shadow_expval")(H[, k, seed]) | Compute expectation values using classical shadows in a differentiable manner. |

Note

All measurement functions support analytic differentiation, with the

exception of [`sample()`](index.html#pennylane.sample "pennylane.sample"), [`counts()`](index.html#pennylane.counts "pennylane.counts"), and

[`classical\_shadow()`](index.html#pennylane.classical_shadow "pennylane.classical_shadow"), as they return *stochastic*

results.

#### Combined measurements[¶](#combined-measurements "Permalink to this headline")

Quantum functions can also return combined measurements of multiple observables. If the observables are not

qubit-wise-commuting, then multiple device executions may occur behind the scenes. Non-commuting oberservables

can not be simultaneously measured in conjunction with non-observable type measurements such as `sample()`,

`counts()`, `probs()`, `state()`, and `density\_matrix()`.

```

def my\_quantum\_function(x, y):

    qml.RZ(x, wires=0)

    qml.CNOT(wires=[0, 1])

    qml.RY(y, wires=1)

    return qml.expval(qml.PauliZ(0)), qml.var(qml.PauliX(0))

```

You can also use list comprehensions, and other common Python patterns:

```

def my\_quantum\_function(x, y):

    qml.RZ(x, wires=0)

    qml.CNOT(wires=[0, 1])

    qml.RY(y, wires=1)

    return [qml.expval(qml.PauliZ(i)) for i in range(2)]

```

As a full example of combined measurements, let us look at

a Bell state \((|00\rangle + |11\rangle)/\sqrt{2}\), prepared

by a `Hadamard` and `CNOT` gate.

```

import pennylane as qml

from pennylane import numpy as np

dev = qml.device("default.qubit", wires=2, shots=1000)

@qml.qnode(dev)

def circuit():

    qml.Hadamard(wires=0)

    qml.CNOT(wires=[0, 1])

    return qml.sample(qml.PauliZ(0)), qml.sample(qml.PauliZ(1))

```

The combined PauliZ-measurement of the

first and second qubit returns a tuple of two arrays, each containing

the measurement results of the respective qubit. [`sample()`](index.html#pennylane.sample "pennylane.sample")

returns 1000 samples per observable as defined on the device.

```

>>> results = circuit()

>>> results[0].shape

(1000,)

>>> results[1].shape

(1000,)

```

Since the two qubits are maximally entangled,

the measurement results always coincide, and the lists are therefore equal:

```

>>> np.all(result[0] == result[1])

True

```

#### Tensor observables[¶](#tensor-observables "Permalink to this headline")

PennyLane supports measuring the tensor product of observables, by using

the `@` notation. For example, to measure the expectation value of

\(Z\otimes I \otimes X\):

```

def my\_quantum\_function(x, y):

    qml.RZ(x, wires=0)

    qml.CNOT(wires=[0, 1])

    qml.RY(y, wires=1)

    qml.CNOT(wires=[0, 2])

    return qml.expval(qml.PauliZ(0) @ qml.PauliX(2))

```

Note that we don’t need to declare the identity observable on wire 1; this is

implicitly assumed.

The tensor observable notation can be used inside all measurement functions that

accept observables as arguments,

including [`expval()`](index.html#pennylane.expval "pennylane.expval"), [`var()`](index.html#pennylane.var "pennylane.var"),

and [`sample()`](index.html#pennylane.sample "pennylane.sample").

#### Counts[¶](#counts "Permalink to this headline")

To avoid dealing with long arrays for the larger numbers of shots, one can use [`counts()`](index.html#pennylane.counts "pennylane.counts") rather than

[`sample()`](index.html#pennylane.sample "pennylane.sample"). This performs the same measurement as sampling, but returns a dictionary containing the

possible measurement outcomes and the number of occurrences for each, rather than a list of all outcomes.

The previous example will be modified as follows:

```

dev = qml.device("default.qubit", wires=2, shots=1000)

@qml.qnode(dev)

def circuit():

    qml.Hadamard(wires=0)

    qml.CNOT(wires=[0, 1])

    return qml.counts(qml.PauliZ(0)), qml.counts(qml.PauliZ(1))

```

After executing the circuit, we can directly see how many times each measurement outcome occurred:

```

>>> circuit()

({-1: 496, 1: 504}, {-1: 496, 1: 504})

```

Similarly, if the observable is not provided, the count of the observed computational basis state is returned.

```

dev = qml.device("default.qubit", wires=2, shots=1000)

@qml.qnode(dev)

def circuit():

    qml.Hadamard(wires=0)

    qml.CNOT(wires=[0, 1])

    return qml.counts()

```

And the result is:

```

>>> circuit()

{'00': 495, '11': 505}

```

By default, only observed outcomes are included in the dictionary. The kwarg `all\_outcomes=True` can

be used to display all possible outcomes, including those that were observed `0` times in sampling.

For example, we could run the previous circuit with `all\_outcomes=True`:

```

dev = qml.device("default.qubit", wires=2, shots=1000)

@qml.qnode(dev)

def circuit():

    qml.Hadamard(wires=0)

    qml.CNOT(wires=[0, 1])

    return qml.counts(all\_outcomes=True)

```

```

>>> result = circuit()

>>> print(result)

{'00': 518, '01': 0, '10': 0, '11': 482}

```

Note: For complicated Hamiltonians, this can add considerable overhead time (due to the cost of calculating

eigenvalues to determine possible outcomes), and as the number of qubits increases, the length of the output

dictionary showing possible computational basis states grows rapidly.

If counts are obtained along with a measurement function other than [`sample()`](index.html#pennylane.sample "pennylane.sample"),

a tuple is returned to provide differentiability for the outputs of QNodes.

```

@qml.qnode(dev)

def circuit():

    qml.Hadamard(wires=0)

    qml.CNOT(wires=[0,1])

    qml.PauliX(wires=1)

    return qml.expval(qml.PauliZ(0)),qml.expval(qml.PauliZ(1)), qml.counts()

```

```

>>> circuit()

(-0.036, 0.036, {'01': 482, '10': 518})

```

#### Probability[¶](#probability "Permalink to this headline")

You can also train QNodes on computational basis probabilities, by using

the [`probs()`](index.html#pennylane.probs "pennylane.probs") measurement function. The function can

accept either specified `wires` or an observable that rotates the

computational basis.

```

def my\_quantum\_function(x, y):

    qml.RZ(x, wires=0)

    qml.CNOT(wires=[0, 1])

    qml.RY(y, wires=1)

    qml.CNOT(wires=[0, 2])

    return qml.probs(wires=[0, 1])

```

For example:

```

>>> dev = qml.device("default.qubit", wires=3)

>>> qnode = qml.QNode(my\_quantum\_function, dev)

>>> qnode(0.56, 0.1)

array([0.99750208, 0.00249792, 0. , 0. ])

```

The returned probability array uses lexicographical ordering,

so corresponds to a \(99.75\%\) probability of measuring

state \(|00\rangle\), and a \(0.25\%\) probability of

measuring state \(|01\rangle\).

#### Mid-circuit measurements and conditional operations[¶](#mid-circuit-measurements-and-conditional-operations "Permalink to this headline")

PennyLane allows specifying measurements in the middle of the circuit.

Quantum functions such as operations can then be conditioned on the measurement

outcome of such mid-circuit measurements:

```

def my\_quantum\_function(x, y):

    qml.RY(x, wires=0)

    qml.CNOT(wires=[0, 1])

    m\_0 = qml.measure(1)

    qml.cond(m\_0, qml.RY)(y, wires=0)

    return qml.probs(wires=[0])

```

A quantum function with mid-circuit measurements (defined using

[`measure()`](index.html#pennylane.measure "pennylane.measure")) and conditional operations (defined using

[`cond()`](index.html#pennylane.cond "pennylane.cond")) can be executed by applying the [deferred measurement

principle](https://en.wikipedia.org/wiki/Deferred_Measurement_Principle). In

the example above, we apply the [`RY`](index.html#pennylane.RY "pennylane.RY") rotation if the mid-circuit

measurement on qubit 1 yielded `1` as an outcome, otherwise doing nothing

for the `0` measurement outcome.

PennyLane implements the deferred measurement principle to transform

conditional operations with the [`defer\_measurements()`](index.html#pennylane.defer_measurements "pennylane.defer_measurements") quantum

function transform.

```

transformed\_qfunc = qml.transforms.defer\_measurements(my\_quantum\_function)

transformed\_qnode = qml.QNode(transformed\_qfunc, dev)

pars = np.array([0.643, 0.246], requires\_grad=True)

```

```

>>> transformed\_qnode(\*pars)

tensor([0.90165331, 0.09834669], requires\_grad=True)

```

The decorator syntax applies equally well:

```

@qml.qnode(dev)

@qml.defer\_measurements

def qnode(x, y):

    (...)

```

Note that we can also specify an outcome when defining a conditional operation:

```

@qml.qnode(dev)

@qml.defer\_measurements

def qnode\_conditional\_op\_on\_zero(x, y):

    qml.RY(x, wires=0)

    qml.CNOT(wires=[0, 1])

    m\_0 = qml.measure(1)

    qml.cond(m\_0 == 0, qml.RY)(y, wires=0)

    return qml.probs(wires=[0])

pars = np.array([0.643, 0.246], requires\_grad=True)

```

```

>>> qnode\_conditional\_op\_on\_zero(\*pars)

tensor([0.88660045, 0.11339955], requires\_grad=True)

```

Wires can be reused as normal after making mid-circuit measurements. Moreover, a measured wire can also be

reset to the \(|0 \rangle\) state by setting the `reset` keyword argument of [`measure()`](index.html#pennylane.measure "pennylane.measure")

to `True`.

```

dev = qml.device("default.qubit", wires=3)

@qml.qnode(dev)

def func():

    qml.PauliX(1)

    m\_0 = qml.measure(1, reset=True)

    qml.PauliX(1)

    return qml.probs(wires=[1])

```

Executing this QNode:

```

>>> func()

tensor([0., 1.], requires\_grad=True)

```

The deferred measurement principle provides a natural method to simulate the

application of mid-circuit measurements and conditional operations in a

differentiable and device-independent way. Performing true mid-circuit

measurements and conditional operations is dependent on the

quantum hardware and PennyLane device capabilities.

For more examples on applying quantum functions conditionally, refer to the

[`cond()`](index.html#pennylane.cond "pennylane.cond") transform.

#### Changing the number of shots[¶](#changing-the-number-of-shots "Permalink to this headline")

For hardware devices where the number of shots determines the accuracy

of the expectation value and variance, as well as the number of samples returned,

it can sometimes be convenient to execute the same QNode with differing

number of shots.

For simulators like `default.qubit`, finite shots will be simulated if

we set `shots` to a positive integer.

The shot number can be changed on the device itself, or temporarily altered

by the `shots` keyword argument when executing the QNode:

```

dev = qml.device("default.qubit", wires=1, shots=10)

@qml.qnode(dev)

def circuit(x, y):

    qml.RX(x, wires=0)

    qml.RY(y, wires=0)

    return qml.expval(qml.PauliZ(0))

# execute the QNode using 10 shots

result = circuit(0.54, 0.1)

# execute the QNode again, now using 1 shot

result = circuit(0.54, 0.1, shots=1)

```

With an increasing number of shots, the average over

measurement samples converges to the exact expectation of an observable. Consider the following

circuit:

```

# fix seed to make results reproducable

np.random.seed(1)

dev = qml.device("default.qubit", wires=1)

@qml.qnode(dev)

def circuit():

    qml.Hadamard(wires=0)

    return qml.expval(qml.PauliZ(0))

```

Running the simulator with `shots=None` returns the exact expectation.

```

>>> circuit(shots=None)

0.0

```

Now we set the device to return stochastic results, and increase the number of shots starting from `10`.

```

>>> circuit(shots=10)

0.2

```

```

>>> circuit(shots=1000)

-0.062

```

```

>>> circuit(shots=100000)

0.00056

```

The result converges to the exact expectation.

### Templates[¶](#templates "Permalink to this headline")

PennyLane provides a growing library of pre-coded templates of common variational circuit architectures

that can be used to easily build, evaluate, and train more complex models. In the

literature, such architectures are commonly known as an *ansatz*. Templates can be used to

[embed data](#intro-ref-temp-emb) into quantum states, to define trainable [layers](#intro-ref-temp-lay)

of quantum gates, to [prepare quantum states](#intro-ref-temp-stateprep) as the first operation in a circuit,

or simply as general [subroutines](#intro-ref-temp-subroutines) that a circuit is built from.

The following is a gallery of built-in templates provided by PennyLane.

#### Embedding templates[¶](#embedding-templates "Permalink to this headline")

Embeddings encode input features into the quantum state of the circuit.

Hence, they usually take a data sample such as a feature vector as an argument. Embeddings can also depend on

trainable parameters, and they may be constructed from repeated layers.

![_images/amplitude.png](_images/amplitude.png)

[AmplitudeEmbedding](index.html#document-code/api/pennylane.AmplitudeEmbedding)[¶](#id1 "Permalink to this image")

![_images/angle.png](_images/angle.png)

[AngleEmbedding](index.html#document-code/api/pennylane.AngleEmbedding)[¶](#id2 "Permalink to this image")

![_images/basis.png](_images/basis.png)

[BasisEmbedding](index.html#document-code/api/pennylane.BasisEmbedding)[¶](#id3 "Permalink to this image")

![_images/displacement.png](_images/displacement.png)

[DisplacementEmbedding](index.html#document-code/api/pennylane.DisplacementEmbedding)[¶](#id4 "Permalink to this image")

![_images/iqp1.png](_images/iqp1.png)

[IQPEmbedding](index.html#document-code/api/pennylane.IQPEmbedding)[¶](#id5 "Permalink to this image")

![_images/qaoa.png](_images/qaoa.png)

[QAOAEmbedding](index.html#document-code/api/pennylane.QAOAEmbedding)[¶](#id6 "Permalink to this image")

![_images/squeezing.png](_images/squeezing.png)

[SqueezingEmbedding](index.html#document-code/api/pennylane.SqueezingEmbedding)[¶](#id7 "Permalink to this image")

#### Layer templates[¶](#layer-templates "Permalink to this headline")

Layer architectures define sequences of trainable gates that are repeated like the layers in a

neural network. Note that arbitrary templates or operations can also be repeated using the

[`layer()`](index.html#pennylane.layer "pennylane.layer") function.

![_images/cvqnn.png](_images/cvqnn.png)

[CVNeuralNetLayers](index.html#document-code/api/pennylane.CVNeuralNetLayers)[¶](#id8 "Permalink to this image")

![_images/random.png](_images/random.png)

[RandomLayers](index.html#document-code/api/pennylane.RandomLayers)[¶](#id9 "Permalink to this image")

![_images/strongly_entangling.png](_images/strongly_entangling.png)

[StronglyEntanglingLayers](index.html#document-code/api/pennylane.StronglyEntanglingLayers)[¶](#id10 "Permalink to this image")

![_images/simplified_two_design1.png](_images/simplified_two_design1.png)

[SimplifiedTwoDesign](index.html#document-code/api/pennylane.SimplifiedTwoDesign)[¶](#id11 "Permalink to this image")

![_images/basic_entangler1.png](_images/basic_entangler1.png)

[BasicEntanglerLayers](index.html#document-code/api/pennylane.BasicEntanglerLayers)[¶](#id12 "Permalink to this image")

#### State Preparations[¶](#state-preparations "Permalink to this headline")

State preparation templates transform the zero state \(|0\dots 0 \rangle\) to another initial

state. In contrast to embeddings that can in principle be used anywhere in a circuit,

state preparation is typically used as the first operation.

![_images/basis.png](_images/basis.png)

[BasisStatePreparation](index.html#document-code/api/pennylane.BasisStatePreparation)[¶](#id13 "Permalink to this image")

![_images/basis_qutrit.png](_images/basis_qutrit.png)

[QutritBasisStatePreparation](index.html#document-code/api/pennylane.QutritBasisStatePreparation)[¶](#id14 "Permalink to this image")

![_images/mottonen.png](_images/mottonen.png)

[MottonenStatePreparation](index.html#document-code/api/pennylane.MottonenStatePreparation)[¶](#id15 "Permalink to this image")

![_images/arbitrarystateprep.png](_images/arbitrarystateprep.png)

[ArbitraryStatePreparation](index.html#document-code/api/pennylane.ArbitraryStatePreparation)[¶](#id16 "Permalink to this image")

#### Quantum Chemistry templates[¶](#quantum-chemistry-templates "Permalink to this headline")

Quantum chemistry templates define various quantum circuits used in variational algorithms

like VQE to perform quantum chemistry simulations.

![_images/all_singles_doubles1.png](_images/all_singles_doubles1.png)

[AllSinglesDoubles](index.html#document-code/api/pennylane.AllSinglesDoubles)[¶](#id17 "Permalink to this image")

![_images/basis_rotation.jpeg](_images/basis_rotation.jpeg)

[Basis Rotation](index.html#document-code/api/pennylane.BasisRotation)[¶](#id18 "Permalink to this image")

![_images/gate_fabric_layer1.png](_images/gate_fabric_layer1.png)

[GateFabric](index.html#document-code/api/pennylane.GateFabric)[¶](#id19 "Permalink to this image")

![_images/uccsd.png](_images/uccsd.png)

[UCCSD](index.html#document-code/api/pennylane.UCCSD)[¶](#id20 "Permalink to this image")

![_images/kupccgsd.png](_images/kupccgsd.png)

[k-UpCCGSD](index.html#document-code/api/pennylane.kUpCCGSD)[¶](#id21 "Permalink to this image")

![_images/particle_conserving_u1_thumbnail.png](_images/particle_conserving_u1_thumbnail.png)

[ParticleConservingU1](index.html#document-code/api/pennylane.ParticleConservingU1)[¶](#id22 "Permalink to this image")

![_images/particle_conserving_u21.png](_images/particle_conserving_u21.png)

[ParticleConservingU2](index.html#document-code/api/pennylane.ParticleConservingU2)[¶](#id23 "Permalink to this image")

#### Tensor networks[¶](#tensor-networks "Permalink to this headline")

Tensor-network templates create quantum circuit architectures where circuit blocks

can be broadcast with the shape and connectivity of tensor networks.

![_images/MPS_template.png](_images/MPS_template.png)

[Matrix Product State](index.html#document-code/api/pennylane.MPS)[¶](#id24 "Permalink to this image")

![_images/TTN_template.png](_images/TTN_template.png)

[Tree Tensor Network](index.html#document-code/api/pennylane.TTN)[¶](#id25 "Permalink to this image")

![_images/MERA_template.png](_images/MERA_template.png)

[Multi-scale Entanglement Renormalization Ansatz](index.html#document-code/api/pennylane.MERA)[¶](#id26 "Permalink to this image")

#### Swap networks[¶](#swap-networks "Permalink to this headline")

Swap network templates perform qubit routing with linear cost, providing a quadratic advantage in

circuit depth for carrying out all pair-wise interactions between qubits.

![_images/ccl2.jpeg](_images/ccl2.jpeg)

[Canonical 2-Complete Linear Swap Network](index.html#document-code/api/pennylane.TwoLocalSwapNetwork)[¶](#id27 "Permalink to this image")

#### Other subroutines[¶](#other-subroutines "Permalink to this headline")

Other useful templates which do not belong to the previous categories can be found here.

![_images/grover1.svg](_images/grover1.svg)[Grover Diffusion Operator](index.html#document-code/api/pennylane.GroverOperator)[¶](#id28 "Permalink to this image")

![_images/interferometer.png](_images/interferometer.png)

[Interferometer](index.html#document-code/api/pennylane.Interferometer)[¶](#id29 "Permalink to this image")

![_images/single_excitation_unitary1.png](_images/single_excitation_unitary1.png)

[FermionicSingleExcitation](index.html#document-code/api/pennylane.FermionicSingleExcitation)[¶](#id30 "Permalink to this image")

![_images/double_excitation_unitary1.png](_images/double_excitation_unitary1.png)

[FermionicDoubleExcitation](index.html#document-code/api/pennylane.FermionicDoubleExcitation)[¶](#id31 "Permalink to this image")

![_images/arbitraryunitary.png](_images/arbitraryunitary.png)

[ArbitraryUnitary](index.html#document-code/api/pennylane.ArbitraryUnitary)[¶](#id32 "Permalink to this image")

![_images/approx_time_evolution1.png](_images/approx_time_evolution1.png)

[ApproxTimeEvolution](index.html#document-code/api/pennylane.ApproxTimeEvolution)[¶](#id33 "Permalink to this image")

![_images/permute.png](_images/permute.png)

[Permute](index.html#document-code/api/pennylane.Permute)[¶](#id34 "Permalink to this image")

![_images/qpe1.svg](_images/qpe1.svg)[QuantumPhaseEstimation](index.html#document-code/api/pennylane.QuantumPhaseEstimation)[¶](#id35 "Permalink to this image")

![_images/qmc2.svg](_images/qmc2.svg)[QuantumMonteCarlo](index.html#document-code/api/pennylane.QuantumMonteCarlo)[¶](#id36 "Permalink to this image")

![_images/qft.svg](_images/qft.svg)[QuantumFourierTransform](index.html#document-code/api/pennylane.QFT)[¶](#id37 "Permalink to this image")

![_images/commuting_evolution.png](_images/commuting_evolution.png)

[CommutingEvolution](index.html#document-code/api/pennylane.CommutingEvolution)[¶](#id38 "Permalink to this image")

![_images/hst1.png](_images/hst1.png)

[HilbertSchmidt](index.html#document-code/api/pennylane.HilbertSchmidt)[¶](#id39 "Permalink to this image")

![_images/lhst1.png](_images/lhst1.png)

[LocalHilbertSchmidt](index.html#document-code/api/pennylane.LocalHilbertSchmidt)[¶](#id40 "Permalink to this image")

![_images/flip_sign.png](_images/flip_sign.png)

[FlipSign operator](index.html#document-code/api/pennylane.FlipSign)[¶](#id41 "Permalink to this image")

![_images/qsvt.png](_images/qsvt.png)

[QSVT](index.html#document-code/api/pennylane.QSVT)[¶](#id42 "Permalink to this image")

![_images/select1.png](_images/select1.png)

[Select](index.html#document-code/api/pennylane.Select)[¶](#id43 "Permalink to this image")

#### Broadcasting function[¶](#broadcasting-function "Permalink to this headline")

PennyLane offers a broadcasting function to easily construct templates: [`broadcast()`](index.html#pennylane.broadcast "pennylane.broadcast")

takes either quantum gates or templates and applies them to wires in a specific pattern.

Warning

While the broadcasting function can make template construction very convenient, it

adds an overhead and is therefore not recommended when speed is a major concern.

![_images/broadcast_single1.png](_images/broadcast_single1.png)

[Broadcast (Single)](index.html#document-code/api/pennylane.broadcast)[¶](#id44 "Permalink to this image")

![_images/broadcast_double1.png](_images/broadcast_double1.png)

[Broadcast (Double)](index.html#document-code/api/pennylane.broadcast)[¶](#id45 "Permalink to this image")

![_images/broadcast_double_odd1.png](_images/broadcast_double_odd1.png)

[Broadcast (Double Odd)](index.html#document-code/api/pennylane.broadcast)[¶](#id46 "Permalink to this image")

![_images/broadcast_chain1.png](_images/broadcast_chain1.png)

[Broadcast (Chain)](index.html#document-code/api/pennylane.broadcast)[¶](#id47 "Permalink to this image")

![_images/broadcast_ring1.png](_images/broadcast_ring1.png)

[Broadcast (Ring)](index.html#document-code/api/pennylane.broadcast)[¶](#id48 "Permalink to this image")

![_images/broadcast_pyramid1.png](_images/broadcast_pyramid1.png)

[Broadcast (Pyramid)](index.html#document-code/api/pennylane.broadcast)[¶](#id49 "Permalink to this image")

![_images/broadcast_alltoall1.png](_images/broadcast_alltoall1.png)

[Broadcast (All-to-All)](index.html#document-code/api/pennylane.broadcast)[¶](#id50 "Permalink to this image")

![_images/broadcast_custom1.png](_images/broadcast_custom1.png)

[Broadcast (Custom)](index.html#document-code/api/pennylane.broadcast)[¶](#id51 "Permalink to this image")

#### Parameter initializations[¶](#parameter-initializations "Permalink to this headline")

Templates that take a weight parameter tensor usually provide methods that return the shape of this tensor.

The shape can for example be used to construct random weights at the beginning of training.

```

import pennylane as qml

from pennylane.templates import BasicEntanglerLayers

from pennylane import numpy as np

n\_wires = 3

dev = qml.device('default.qubit', wires=n\_wires)

@qml.qnode(dev)

def circuit(weights):

    BasicEntanglerLayers(weights=weights, wires=range(n\_wires))

    return qml.expval(qml.PauliZ(0))

shape = BasicEntanglerLayers.shape(n\_layers=2, n\_wires=n\_wires)

np.random.seed(42)  # to make the result reproducable

weights = np.random.random(size=shape)

```

```

>>> circuit(weights)

tensor(0.72588592, requires\_grad=True)

```

If a template takes more than one weight tensor, the `shape` method returns a list of shape tuples.

#### Custom templates[¶](#custom-templates "Permalink to this headline")

Creating a custom template can be as simple as defining a function that creates operations and does not have a return

statement:

```

from pennylane import numpy as np

def MyTemplate(a, b, wires):

    c = np.sin(a) + b

    qml.RX(c, wires=wires[0])

n\_wires = 3

dev = qml.device('default.qubit', wires=n\_wires)

@qml.qnode(dev)

def circuit(a, b):

    MyTemplate(a, b, wires=range(n\_wires))

    return qml.expval(qml.PauliZ(0))

```

```

>>> circuit(2, 3)

-0.7195065654396784

```

Note

Make sure that classical processing is compatible with the autodifferentiation library you are using. For example,

if `MyTemplate` is to be used with the torch framework, we would have to change `np.sin` to `torch.sin`.

PennyLane’s [`math`](index.html#module-pennylane.math "pennylane.math") library contains some advanced functionality for

framework-agnostic processing.

As suggested by the camel-case naming, built-in templates in PennyLane are classes. Classes are more complex

data structures than functions, since they can define properties and methods of templates (such as gradient

recipes or matrix representations). Consult the [Contributing operators](index.html#contributing-operators)

page to learn how to code up your own template class, and how to add it to the PennyLane template library.

#### Layering Function[¶](#layering-function "Permalink to this headline")

The layer function creates a new template by repeatedly applying a sequence of quantum

gates to a set of wires. You can import this function both via

`qml.layer` and `qml.templates.layer`.

| [`pennylane.layer`](index.html#pennylane.layer "pennylane.layer")(template, depth, \*args, \*\*kwargs) | Repeatedly applies a unitary a given number of times. |

### Inspecting circuits[¶](#inspecting-circuits "Permalink to this headline")

PennyLane offers functionality to inspect, visualize or analyze quantum circuits.

Most of these tools are implemented as **transforms**. Transforms take a [`QNode`](index.html#pennylane.QNode "pennylane.QNode") instance and return a function:

```

>>> @qml.qnode(dev, diff\_method='parameter-shift')

... def my\_qnode(x, a=True):

...     # ...

>>> new\_func = my\_transform(qnode)

```

This new function accepts the same arguments as the QNode and returns the desired outcome,

such as a dictionary of the QNode’s properties, a matplotlib figure drawing the circuit,

or a DAG representing its connectivity structure.

```

>>> new\_func(0.1, a=False)

```

More information on the concept of transforms can be found in

[Di Matteo et al. (2022)](https://arxiv.org/abs/2202.13414).

#### Extracting properties of a circuit[¶](#extracting-properties-of-a-circuit "Permalink to this headline")

The [`specs()`](index.html#pennylane.specs "pennylane.specs") transform takes a

QNode and creates a function that returns

details about the QNode, including depth, number of gates, and number of

gradient executions required.

For example:

```

dev = qml.device('default.qubit', wires=4)

@qml.qnode(dev, diff\_method='parameter-shift')

def circuit(x, y):

    qml.RX(x[0], wires=0)

    qml.Toffoli(wires=(0, 1, 2))

    qml.CRY(x[1], wires=(0, 1))

    qml.Rot(x[2], x[3], y, wires=0)

    return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliX(1))

```

We can now use the [`specs()`](index.html#pennylane.specs "pennylane.specs") transform to generate a function that returns

details and resource information:

```

>>> x = np.array([0.05, 0.1, 0.2, 0.3], requires\_grad=True)

>>> y = np.array(0.4, requires\_grad=False)

>>> specs\_func = qml.specs(circuit)

>>> specs\_func(x, y)

{'resources': Resources(num\_wires=3, num\_gates=4, gate\_types=defaultdict(<class 'int'>, {'RX': 1, 'Toffoli': 1, 'CRY': 1, 'Rot': 1}), depth=4, shots=0),

 'gate\_sizes': defaultdict(int, {1: 2, 3: 1, 2: 1}),

 'gate\_types': defaultdict(int, {'RX': 1, 'Toffoli': 1, 'CRY': 1, 'Rot': 1}),

 'num\_operations': 4,

 'num\_observables': 2,

 'num\_diagonalizing\_gates': 1,

 'num\_used\_wires': 3,

 'num\_trainable\_params': 4,

 'depth': 4,

 'num\_device\_wires': 4,

 'device\_name': 'default.qubit',

 'expansion\_strategy': 'gradient',

 'gradient\_options': {},

 'interface': 'auto',

 'diff\_method': 'parameter-shift',

 'gradient\_fn': 'pennylane.gradients.parameter\_shift.param\_shift',

 'num\_gradient\_executions': 10}

```

#### Circuit drawing[¶](#circuit-drawing "Permalink to this headline")

PennyLane has two built-in circuit drawers, [`draw()`](index.html#pennylane.draw "pennylane.draw") and

[`draw\_mpl()`](index.html#pennylane.draw_mpl "pennylane.draw_mpl").

For example:

```

dev = qml.device('lightning.qubit', wires=(0,1,2,3))

@qml.qnode(dev)

def circuit(x, z):

    qml.QFT(wires=(0,1,2,3))

    qml.IsingXX(1.234, wires=(0,2))

    qml.Toffoli(wires=(0,1,2))

    qml.CSWAP(wires=(0,2,3))

    qml.RX(x, wires=0)

    qml.CRZ(z, wires=(3,0))

    return qml.expval(qml.PauliZ(0))

fig, ax = qml.draw\_mpl(circuit)(1.2345,1.2345)

fig.show()

```

[![_images/main_example.png](_images/main_example.png)](javascript:void(0);)

```

>>> print(qml.draw(circuit)(1.2345,1.2345))

0: ─╭QFT─╭IsingXX(1.23)─╭●─╭●─────RX(1.23)─╭RZ(1.23)─┤ <Z>

1: ─├QFT─│──────────────├●─│───────────────│─────────┤

2: ─├QFT─╰IsingXX(1.23)─╰X─├SWAP───────────│─────────┤

3: ─╰QFT───────────────────╰SWAP───────────╰●────────┤

```

More information, including various fine-tuning options, can be found in

the [drawing module](index.html#document-code/qml_drawer).

#### Debugging with mid-circuit snapshots[¶](#debugging-with-mid-circuit-snapshots "Permalink to this headline")

When debugging quantum circuits run on simulators, we may want to inspect the current quantum state between gates.

[`Snapshot`](index.html#pennylane.Snapshot "pennylane.Snapshot") is an operator like a gate, but it saves the device state at its location in the circuit instead of manipulating the quantum state.

Currently supported devices include:

* `default.qubit`: each snapshot saves the quantum state vector

* `default.mixed`: each snapshot saves the density matrix

* `default.gaussian`: each snapshot saves the covariance matrix and vector of means

During normal execution, the snapshots are ignored:

```

dev = qml.device("default.qubit", wires=2)

@qml.qnode(dev, interface=None)

def circuit():

    qml.Snapshot()

    qml.Hadamard(wires=0)

    qml.Snapshot("very\_important\_state")

    qml.CNOT(wires=[0, 1])

    qml.Snapshot()

    return qml.expval(qml.PauliX(0))

```

However, when using the [`snapshots()`](index.html#pennylane.snapshots "pennylane.snapshots")

transform, intermediate device states will be stored and returned alongside the

results.

```

>>> qml.snapshots(circuit)()

{0: array([1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j]),

'very\_important\_state': array([0.707+0.j, 0.+0.j, 0.707+0.j, 0.+0.j]),

2: array([0.707+0.j, 0.+0.j, 0.+0.j, 0.707+0.j]),

'execution\_results': array(0.)}

```

#### Graph representation[¶](#graph-representation "Permalink to this headline")

PennyLane makes use of several ways to represent a quantum circuit as a Directed Acyclic Graph (DAG).

##### DAG of causal relations between ops[¶](#dag-of-causal-relations-between-ops "Permalink to this headline")

A DAG can be used to represent which operator in a circuit is causally related to another. There are two

options to construct such a DAG:

The [`CircuitGraph`](index.html#pennylane.CircuitGraph "pennylane.CircuitGraph") class takes a list of gates or channels and hermitian observables

as well as a set of wire labels and constructs a DAG in which the [`Operator`](index.html#pennylane.operation.Operator "pennylane.operation.Operator")

instances are the nodes, and each directed edge corresponds to a wire

(or a group of wires) on which the “nodes” act subsequently.

For example, this can be used to compute the effective depth of a circuit,

or to check whether two gates causally influence each other.

```

import pennylane as qml

from pennylane import CircuitGraph

dev = qml.device('lightning.qubit', wires=(0,1,2,3))

@qml.qnode(dev)

def circuit():

    qml.Hadamard(0)

    qml.CNOT([1, 2])

    qml.CNOT([2, 3])

    qml.CNOT([3, 1])

    return qml.expval(qml.PauliZ(0))

circuit()

tape = circuit.qtape

ops = tape.operations

obs = tape.observables

g = CircuitGraph(ops, obs, tape.wires)

```

Internally, the [`CircuitGraph`](index.html#pennylane.CircuitGraph "pennylane.CircuitGraph") class constructs a `rustworkx` graph object.

```

>>> type(g.graph)

<class 'rustworkx.PyDiGraph'>

```

There is no edge between the `Hadamard` and the first `CNOT`, but between consecutive `CNOT` gates:

```

>>> g.has\_path(ops[0], ops[1])

False

>>> g.has\_path(ops[1], ops[3])

True

```

The Hadamard is connected to the observable, while the `CNOT` operators are not. The observable

does not follow the Hadamard.

```

>>> g.has\_path(ops[0], obs[0])

True

>>> g.has\_path(ops[1], obs[0])

False

>>> g.has\_path(obs[0], ops[0])

False

```

Another way to construct the “causal” DAG of a circuit is to use the

[`tape\_to\_graph()`](index.html#pennylane.transforms.qcut.tape_to_graph "pennylane.transforms.qcut.tape_to_graph") function used by the `qcut` module. This

function takes a quantum tape and creates a `MultiDiGraph` instance from the `networkx` python package.

Using the above example, we get:

```

>>> g2 = qml.transforms.qcut.tape\_to\_graph(tape)

>>> type(g2)

<class 'networkx.classes.multidigraph.MultiDiGraph'>

>>> for k, v in g2.adjacency():

...    print(k, v)

Hadamard(wires=[0]) {expval(PauliZ(wires=[0])): {0: {'wire': 0}}}

CNOT(wires=[1, 2]) {CNOT(wires=[2, 3]): {0: {'wire': 2}}, CNOT(wires=[3, 1]): {0: {'wire': 1}}}

CNOT(wires=[2, 3]) {CNOT(wires=[3, 1]): {0: {'wire': 3}}}

CNOT(wires=[3, 1]) {}

expval(PauliZ(wires=[0])) {}

```

##### DAG of non-commuting ops[¶](#dag-of-non-commuting-ops "Permalink to this headline")

The [`commutation\_dag()`](index.html#pennylane.commutation_dag "pennylane.commutation_dag") transform can be used to produce an instance of the `CommutationDAG` class.

In a commutation DAG, each node represents a quantum operation, and edges represent non-commutation

between two operations.

This transform takes into account that not all operations can be moved next to each other by

pairwise commutation:

```

>>> def circuit(x, y, z):

...     qml.RX(x, wires=0)

...     qml.RX(y, wires=0)

...     qml.CNOT(wires=[1, 2])

...     qml.RY(y, wires=1)

...     qml.Hadamard(wires=2)

...     qml.CRZ(z, wires=[2, 0])

...     qml.RY(-y, wires=1)

...     return qml.expval(qml.PauliZ(0))

>>> dag\_fn = qml.commutation\_dag(circuit)

>>> dag = dag\_fn(np.pi / 4, np.pi / 3, np.pi / 2)

```

Nodes in the commutation DAG can be accessed via the `get\_nodes()` method, returning a list of

the form `(ID, CommutationDAGNode)`:

```

>>> nodes = dag.get\_nodes()

>>> nodes

NodeDataView({0: <pennylane.transforms.commutation\_dag.CommutationDAGNode object at 0x7f461c4bb580>, ...}, data='node')

```

Specific nodes in the commutation DAG can be accessed via the `get\_node()` method:

```

>>> second\_node = dag.get\_node(2)

>>> second\_node

<pennylane.transforms.commutation\_dag.CommutationDAGNode object at 0x136f8c4c0>

>>> second\_node.op

CNOT(wires=[1, 2])

>>> second\_node.successors

[3, 4, 5, 6]

>>> second\_node.predecessors

[]

```

#### Fourier representation[¶](#fourier-representation "Permalink to this headline")

Parametrized quantum circuits often compute functions in the parameters that

can be represented by Fourier series of a low degree.

The [qml.fourier](index.html#document-code/qml_fourier) module contains functionality to compute and visualize

properties of such Fourier series.

[![_images/fourier_vis_radial_box.png](_images/fourier_vis_radial_box.png)](javascript:void(0);)

### Compiling circuits[¶](#compiling-circuits "Permalink to this headline")

PennyLane offers multiple tools for compiling circuits. We use the term “compilation”

here in a loose sense as the process of transforming one circuit

into one or more differing circuits. A circuit could be either a quantum function or a sequence of operators. For example, such a transformation could

replace a gate type with another, fuse gates, exploit mathematical relations that simplify an observable,

or replace a large circuit by a number of smaller circuits.

Compilation functionality is mostly designed as **transforms**, which you can read up on in the

section on [inspecting circuits](index.html#document-introduction/inspecting_circuits).

In addition to quantum circuit transforms, PennyLane also

supports experimental just-in-time compilation, via

[Catalyst](https://github.com/pennylaneai/catalyst). This is more general, and

supports full hybrid compilation — compiling both the classical and quantum components

of your workflow into a binary that can be run close to the accelerators.

that you are using.

#### Simplifying Operators[¶](#simplifying-operators "Permalink to this headline")

PennyLane provides the [`simplify()`](index.html#pennylane.simplify "pennylane.simplify") function to simplify single operators, quantum

functions, QNodes and tapes. This function has several purposes:

* Reducing the arithmetic depth of the given operators to its minimum.

* Grouping like terms in sums and products.

* Resolving products of Pauli operators.

* Combining identical rotation gates by summing its angles.

Here are some simple simplification routines:

```

>>> qml.simplify(qml.RX(4\*np.pi+0.1, 0 ))

RX(0.09999999999999964, wires=[0])

>>> qml.simplify(qml.adjoint(qml.RX(1.23, 0)))

RX(11.336370614359172, wires=[0])

>>> qml.simplify(qml.ops.Pow(qml.RX(1, 0), 3))

RX(3.0, wires=[0])

>>> qml.simplify(qml.sum(qml.PauliY(3), qml.PauliY(3)))

2\*(PauliY(wires=[3]))

>>> qml.simplify(qml.RX(1, 0) @ qml.RX(1, 0))

RX(2.0, wires=[0])

>>> qml.simplify(qml.prod(qml.PauliX(0), qml.PauliZ(0)))

-1j\*(PauliY(wires=[0]))

```

Now lets simplify a nested operator:

```

>>> sum\_op = qml.RX(1, 0) + qml.PauliX(0)

>>> prod1 = qml.PauliX(0) @ sum\_op

>>> nested\_op = prod1 @ qml.RX(1, 0)

>>> qml.simplify(nested\_op)

(PauliX(wires=[0]) @ RX(2.0, wires=[0])) + RX(1.0, wires=[0])

```

Several simplifications steps are happening here. First of all, the nested products are removed:

```

qml.prod(qml.PauliX(0), qml.sum(qml.RX(1, 0), qml.PauliX(0)), qml.RX(1, 0))

```

Then the product of sums is transformed into a sum of products:

```

qml.sum(qml.prod(qml.PauliX(0), qml.RX(1, 0), qml.RX(1, 0)), qml.prod(qml.PauliX(0), qml.PauliX(0), qml.RX(1, 0)))

```

And finally like terms in the obtained products are grouped together, removing all identities:

```

qml.sum(qml.prod(qml.PauliX(0), qml.RX(2, 0)), qml.RX(1, 0))

```

As mentioned earlier we can also simplify QNode objects to, for example, group rotation gates:

```

dev = qml.device("default.qubit", wires=2)

@qml.simplify

@qml.qnode(dev)

def circuit(x):

    (

        qml.RX(x[0], wires=0)

        @ qml.RY(x[1], wires=1)

        @ qml.RZ(x[2], wires=2)

        @ qml.RX(-1, wires=0)

        @ qml.RY(-2, wires=1)

        @ qml.RZ(2, wires=2)

    )

    return qml.probs([0, 1, 2])

```

```

>>> x = [1, 2, 3]

>>> print(qml.draw(circuit)(x))

0: ───────────┤ ╭Probs

1: ───────────┤ ├Probs

2: ──RZ(5.00)─┤ ╰Probs

```

#### Compilation transforms for circuit optimization[¶](#compilation-transforms-for-circuit-optimization "Permalink to this headline")

PennyLane includes multiple transforms that take quantum functions and return new

quantum functions of optimized circuits:

| [`cancel\_inverses`](index.html#pennylane.transforms.cancel_inverses "pennylane.transforms.cancel_inverses") | Quantum function transform to remove any operations that are applied next to their (self-)inverses or adjoint. |

| [`commute\_controlled`](index.html#pennylane.transforms.commute_controlled "pennylane.transforms.commute_controlled") | Quantum function transform to move commuting gates past control and target qubits of controlled operations. |

| [`merge\_amplitude\_embedding`](index.html#pennylane.transforms.merge_amplitude_embedding "pennylane.transforms.merge_amplitude_embedding") | Quantum function transform to combine amplitude embedding templates that act on different qubits. |

| [`cancel\_inverses`](index.html#pennylane.transforms.cancel_inverses "pennylane.transforms.cancel_inverses") | Quantum function transform to remove any operations that are applied next to their (self-)inverses or adjoint. |

| [`merge\_rotations`](index.html#pennylane.transforms.merge_rotations "pennylane.transforms.merge_rotations") | Quantum function transform to combine rotation gates of the same type that act sequentially. |

| [`pattern\_matching`](index.html#pennylane.transforms.pattern_matching "pennylane.transforms.pattern_matching") | Function that applies the pattern matching algorithm and returns the list of maximal matches. |

| [`remove\_barrier`](index.html#pennylane.transforms.remove_barrier "pennylane.transforms.remove_barrier") | Quantum function transform to remove Barrier gates. |

| [`single\_qubit\_fusion`](index.html#pennylane.transforms.single_qubit_fusion "pennylane.transforms.single_qubit_fusion") | Quantum function transform to fuse together groups of single-qubit operations into a general single-qubit unitary operation ([`Rot`](index.html#pennylane.Rot "pennylane.Rot")). |

| [`undo\_swaps`](index.html#pennylane.transforms.undo_swaps "pennylane.transforms.undo_swaps") | Quantum function transform to remove SWAP gates by running from right to left through the circuit changing the position of the qubits accordingly. |

Note

Most compilation transforms support just-in-time compilation with `jax.jit`.

The [`compile()`](index.html#pennylane.compile "pennylane.compile") transform allows you to chain together

sequences of quantum function transforms into custom circuit optimization pipelines.

For example, take the following decorated quantum function:

```

dev = qml.device('default.qubit', wires=[0, 1, 2])

@qml.qnode(dev)

@qml.compile()

def qfunc(x, y, z):

    qml.Hadamard(wires=0)

    qml.Hadamard(wires=1)

    qml.Hadamard(wires=2)

    qml.RZ(z, wires=2)

    qml.CNOT(wires=[2, 1])

    qml.RX(z, wires=0)

    qml.CNOT(wires=[1, 0])

    qml.RX(x, wires=0)

    qml.CNOT(wires=[1, 0])

    qml.RZ(-z, wires=2)

    qml.RX(y, wires=2)

    qml.PauliY(wires=2)

    qml.CZ(wires=[1, 2])

    return qml.expval(qml.PauliZ(wires=0))

```

The default behaviour of [`compile()`](index.html#pennylane.compile "pennylane.compile") applies a sequence of three

transforms: [`commute\_controlled()`](index.html#pennylane.transforms.commute_controlled "pennylane.transforms.commute_controlled"), [`cancel\_inverses()`](index.html#pennylane.transforms.cancel_inverses "pennylane.transforms.cancel_inverses"),

and then [`merge\_rotations()`](index.html#pennylane.transforms.merge_rotations "pennylane.transforms.merge_rotations").

```

>>> print(qml.draw(qfunc)(0.2, 0.3, 0.4))

0: ──H──RX(0.60)─────────────────┤ <Z>

1: ──H─╭X─────────────────────╭●─┤

2: ──H─╰●─────────RX(0.30)──Y─╰Z─┤

```

The [`compile()`](index.html#pennylane.compile "pennylane.compile") transform is flexible and accepts a custom pipeline

of quantum function transforms (you can even write your own!).

For example, if we wanted to only push single-qubit gates through

controlled gates and cancel adjacent inverses, we could do:

```

from pennylane.transforms import commute\_controlled, cancel\_inverses

pipeline = [commute\_controlled, cancel\_inverses]

@qml.qnode(dev)

@qml.compile(pipeline=pipeline)

def qfunc(x, y, z):

    qml.Hadamard(wires=0)

    qml.Hadamard(wires=1)

    qml.Hadamard(wires=2)

    qml.RZ(z, wires=2)

    qml.CNOT(wires=[2, 1])

    qml.RX(z, wires=0)

    qml.CNOT(wires=[1, 0])

    qml.RX(x, wires=0)

    qml.CNOT(wires=[1, 0])

    qml.RZ(-z, wires=2)

    qml.RX(y, wires=2)

    qml.PauliY(wires=2)

    qml.CZ(wires=[1, 2])

    return qml.expval(qml.PauliZ(wires=0))

```

```

>>> print(qml.draw(qfunc)(0.2, 0.3, 0.4))

0: ──H──RX(0.40)──RX(0.20)────────────────────────────┤ <Z>

1: ──H─╭X──────────────────────────────────────────╭●─┤

2: ──H─╰●─────────RZ(0.40)──RZ(-0.40)──RX(0.30)──Y─╰Z─┤

```

Note

The [`Barrier`](index.html#pennylane.Barrier "pennylane.Barrier") operator can be used to prevent blocks of code from being merged during

compilation.

For more details on [`compile()`](index.html#pennylane.compile "pennylane.compile") and the available compilation transforms, visit

[the compilation documentation](../code/qml_transforms.html#transforms-for-circuit-compilation).

#### Custom decompositions[¶](#custom-decompositions "Permalink to this headline")

PennyLane decomposes gates unknown to the device into other, “lower-level” gates. As a user, you may want to fine-tune this mechanism. For example, you may wish your circuit to use different fundamental gates.

For example, suppose we would like to implement the following QNode:

```

def circuit(weights):

    qml.BasicEntanglerLayers(weights, wires=[0, 1, 2])

    return qml.expval(qml.PauliZ(0))

original\_dev = qml.device("default.qubit", wires=3)

original\_qnode = qml.QNode(circuit, original\_dev)

```

```

>>> weights = np.array([[0.4, 0.5, 0.6]])

>>> print(qml.draw(original\_qnode, expansion\_strategy="device")(weights))

0: ──RX(0.40)─╭●────╭X─┤ <Z>

1: ──RX(0.50)─╰X─╭●─│──┤

2: ──RX(0.60)────╰X─╰●─┤

```

Now, let’s swap out PennyLane’s default decomposition of the `CNOT` gate into `CZ`

and `Hadamard`.

We define the custom decompositions like so, and pass them to a device:

```

def custom\_cnot(wires):

    return [

        qml.Hadamard(wires=wires[1]),

        qml.CZ(wires=[wires[0], wires[1]]),

        qml.Hadamard(wires=wires[1])

    ]

custom\_decomps = {qml.CNOT: custom\_cnot}

decomp\_dev = qml.device("default.qubit", wires=3, custom\_decomps=custom\_decomps)

decomp\_qnode = qml.QNode(circuit, decomp\_dev)

```

Now when we draw or run a QNode on this device, the gates will be expanded

according to our specifications:

```

>>> print(qml.draw(decomp\_qnode, expansion\_strategy="device")(weights))

0: ──RX(0.40)────╭●──H───────╭Z──H─┤ <Z>

1: ──RX(0.50)──H─╰Z──H─╭●────│─────┤

2: ──RX(0.60)──H───────╰Z──H─╰●────┤

```

Note

If the custom decomposition is only supposed to be used in a specific code context,

a separate context manager [`set\_decomposition()`](index.html#pennylane.transforms.set_decomposition "pennylane.transforms.set_decomposition") can be used.

#### Circuit cutting[¶](#circuit-cutting "Permalink to this headline")

Circuit cutting allows you to replace a circuit with `N` wires by a set of circuits with less than

`N` wires (see also [Peng et. al](https://arxiv.org/abs/1904.00102)). Of course this comes with a cost: The smaller circuits

require a greater number of device executions to be evaluated.

In PennyLane, circuit cutting can be

activated by positioning [`WireCut`](index.html#pennylane.WireCut "pennylane.WireCut") operators at the desired cut locations, and

by decorating the QNode with the [`cut\_circuit()`](index.html#pennylane.cut_circuit "pennylane.cut_circuit") transform.

The example below shows how a three-wire circuit can be run on a two-wire device:

```

dev = qml.device("default.qubit", wires=2)

@qml.cut\_circuit

@qml.qnode(dev)

def circuit(x):

    qml.RX(x, wires=0)

    qml.RY(0.9, wires=1)

    qml.RX(0.3, wires=2)

    qml.CZ(wires=[0, 1])

    qml.RY(-0.4, wires=0)

    qml.WireCut(wires=1)

    qml.CZ(wires=[1, 2])

    return qml.expval(qml.pauli.string\_to\_pauli\_word("ZZZ"))

```

Instead of being executed directly, the circuit will be partitioned into

smaller fragments according to the [`WireCut`](index.html#pennylane.WireCut "pennylane.WireCut") locations,

and each fragment will be executed multiple times. PennyLane automatically combines the results

of the fragment executions to recover the expected output of the original uncut circuit.

```

>>> x = np.array(0.531, requires\_grad=True)

>>> circuit(0.531)

0.47165198882111165

```

Circuit cutting support is also differentiable:

```

>>> qml.grad(circuit)(x)

-0.276982865449393

```

Note

Simulated quantum circuits that produce samples can be cut using

the [`cut\_circuit\_mc()`](index.html#pennylane.cut_circuit_mc "pennylane.cut_circuit_mc")

transform, which is based on the Monte Carlo method.

#### Groups of commuting Pauli words[¶](#groups-of-commuting-pauli-words "Permalink to this headline")

Mutually commuting Pauli words can be measured simultaneously on a quantum computer.

Finding groups of mutually commuting observables can therefore reduce the number of circuit executions,

and is an example of how observables can be “compiled”.

PennyLane contains different functionalities for this purpose, ranging from higher-level

transforms acting on QNodes to lower-level functions acting on operators.

An example of a transform manipulating QNodes is [`split\_non\_commuting()`](index.html#pennylane.transforms.split_non_commuting "pennylane.transforms.split_non_commuting").

It turns a QNode that measures non-commuting observables into a QNode that internally

uses *multiple* circuit executions with qubit-wise commuting groups. The transform is used

by devices to make such measurements possible.

On a lower level, the [`group\_observables()`](index.html#pennylane.pauli.group_observables "pennylane.pauli.group_observables") function can be used to split lists of

observables and coefficients:

```

>>> obs = [qml.PauliY(0), qml.PauliX(0) @ qml.PauliX(1), qml.PauliZ(1)]

>>> coeffs = [1.43, 4.21, 0.97]

>>> obs\_groupings, coeffs\_groupings = qml.pauli.group\_observables(obs, coeffs, 'anticommuting', 'lf')

>>> obs\_groupings

[[PauliZ(wires=[1]), PauliX(wires=[0]) @ PauliX(wires=[1])],

 [PauliY(wires=[0])]]

>>> coeffs\_groupings

[[0.97, 4.21], [1.43]]

```

This and more logic to manipulate Pauli observables is found in the `pauli` module.

#### Just-in-time compilation with Catalyst[¶](#just-in-time-compilation-with-catalyst "Permalink to this headline")

In addition to quantum circuit transformations, PennyLane also supports full

hybrid just-in-time (JIT) compilation via [Catalyst](https://github.com/pennylaneai/catalyst). Catalyst allows you to compile

the entire quantum-classical workflow, including any optimization loops,

which allows for optimized performance, and the ability to run the entire

workflow on accelerator devices as appropriate.

Currently, Catalyst must be installed separately, and only supports the JAX

interface and `lightning.qubit`. Check out the Catalyst documentation for

[installation instructions](https://docs.pennylane.ai/projects/catalyst/en/latest/dev/installation.html).

Using Catalyst with PennyLane is a simple as using the `@qjit` decorator to

compile your hybrid workflows:

```

from catalyst import qjit

from jax import numpy as jnp

dev = qml.device("lightning.qubit", wires=2, shots=1000)

@qjit

@qml.qnode(dev)

def cost(params):

    qml.Hadamard(0)

    qml.RX(jnp.sin(params[0]) \*\* 2, wires=1)

    qml.CRY(params[0], wires=[0, 1])

    qml.RX(jnp.sqrt(params[1]), wires=1)

    return qml.expval(qml.PauliZ(1))

```

The `qjit` decorator can also be used on hybrid cost functions – that is,

cost functions that include both QNodes and classical processing. We can even

JIT compile the full optimization loop, for example when training models:

```

import jaxopt

@jax.jit

def optimization():

    # initial parameter

    params = jnp.array([0.54, 0.3154])

    # define the optimizer

    opt = jaxopt.GradientDescent(cost, stepsize=0.4)

    update = lambda i, args: tuple(opt.update(\*args))

    # perform optimization loop

    state = opt.init\_state(params)

    (params, \_) = jax.lax.fori\_loop(0, 100, update, (params, state))

    return params

```

Finally, Catalyst provides additional features to PennyLane, such as classical

control of quantum operations that are JIT-enabled, via the function

`catalyst.for\_loop` and `catalyst.cond`. It also enables arbitrary

post-processing of mid-circuit measurements.

For more details, see the [Catalyst documentation and tutorials](https://docs.pennylane.ai/projects/catalyst/).

### Quantum Chemistry[¶](#quantum-chemistry "Permalink to this headline")

PennyLane provides the [`qchem`](index.html#module-pennylane.qchem "pennylane.qchem") module to perform quantum chemistry simulations. It

contains a differentiable Hartree-Fock solver and the functionality to construct a

fully-differentiable molecular Hamiltonian that can be used as input to quantum algorithms

such as the variational quantum eigensolver (VQE) algorithm. The [`qchem`](index.html#module-pennylane.qchem "pennylane.qchem") module

also provides tools for building other observables such as molecular dipole moment, spin

and particle number observables. The theoretical foundation of the quantum chemistry functionality

in PennyLane is explained in our [white paper](https://arxiv.org/abs/2111.09967).

#### Building the electronic Hamiltonian[¶](#building-the-electronic-hamiltonian "Permalink to this headline")

The [`qchem`](index.html#module-pennylane.qchem "pennylane.qchem") module provides access to a driver function [`molecular\_hamiltonian()`](index.html#pennylane.qchem.molecular_hamiltonian "pennylane.qchem.molecular_hamiltonian")

to generate the electronic Hamiltonian in a single call. For example,

```

import pennylane as qml

from pennylane import numpy as np

symbols = ["H", "H"]

geometry = np.array([[0., 0., -0.66140414], [0., 0., 0.66140414]])

hamiltonian, qubits = qml.qchem.molecular\_hamiltonian(symbols, geometry)

```

where:

* `hamiltonian` is the qubit Hamiltonian of the molecule represented as a PennyLane Hamiltonian and

* `qubits` is the number of qubits needed to perform the quantum simulation.

The [`molecular\_hamiltonian()`](index.html#pennylane.qchem.molecular_hamiltonian "pennylane.qchem.molecular_hamiltonian") function can also be used to construct the molecular Hamiltonian

with an external backend that uses the

[OpenFermion-PySCF](https://github.com/quantumlib/OpenFermion-PySCF) plugin interfaced with the

electronic structure package [PySCF](https://github.com/pyscf/pyscf), which requires separate

installation. This backend is non-differentiable and can be selected by setting

`method='pyscf'` in [`molecular\_hamiltonian()`](index.html#pennylane.qchem.molecular_hamiltonian "pennylane.qchem.molecular_hamiltonian").

Furthermore, the net charge,

the [spin multiplicity](https://en.wikipedia.org/wiki/Multiplicity_(chemistry)), the

[atomic basis functions](https://www.basissetexchange.org/) and the active space can also be

specified for each backend.

```

hamiltonian, qubits = qml.qchem.molecular\_hamiltonian(

    symbols,

    geometry,

    charge=0,

    mult=1,

    basis='sto-3g',

    method='pyscf',

    active\_electrons=2,

    active\_orbitals=2

)

```

##### Importing the Hamiltonian and ansatz state[¶](#importing-the-hamiltonian-and-ansatz-state "Permalink to this headline")

If the electronic Hamiltonian is built independently using

[OpenFermion](https://github.com/quantumlib/OpenFermion) tools, it can be readily converted

to a PennyLane observable using the [`import\_operator()`](index.html#pennylane.import_operator "pennylane.import_operator") function. There is also

capability to import wavefunctions (states) that have been pre-computed by traditional quantum chemistry methods

from [PySCF](https://github.com/pyscf/pyscf), which could be used to for example to provide a better

starting point to a quantum algorithm. State import can be accomplished using the [`import\_state()`](index.html#pennylane.qchem.import_state "pennylane.qchem.import_state")

utility function.

##### Importing molecular structure data[¶](#importing-molecular-structure-data "Permalink to this headline")

The atomic structure of a molecule can be either defined as an array or imported from an external

file using the [`read\_structure()`](index.html#pennylane.qchem.read_structure "pennylane.qchem.read_structure") function:

```

symbols, geometry = qml.qchem.read\_structure('h2.xyz')

```

#### VQE simulations[¶](#vqe-simulations "Permalink to this headline")

The Variational Quantum Eigensolver (VQE) is a hybrid quantum-classical computational scheme,

where a quantum computer is used to prepare the trial wave function of a molecule and to measure

the expectation value of the *electronic Hamiltonian*, while a classical optimizer is used to

find its ground state.

PennyLane supports treating Hamiltonians just like any other observable, and the

expectation value of a Hamiltonian can be calculated using `qml.expval`:

```

dev = qml.device('default.qubit', wires=4)

symbols = ["H", "H"]

geometry = np.array([[0., 0., -0.66140414], [0., 0., 0.66140414]])

hamiltonian, qubits = qml.qchem.molecular\_hamiltonian(symbols, geometry)

@qml.qnode(dev)

def circuit(params):

    qml.BasisState(np.array([1, 1, 0, 0]), wires=[0, 1, 2, 3])

    qml.DoubleExcitation(params, wires=[0, 1, 2, 3])

    return qml.expval(hamiltonian)

params = np.array(0.20885146442480412, requires\_grad=True)

circuit(params)

```

```

tensor(-1.13618912, requires_grad=True)

```

The circuit parameter can be optimized using the interface of choice.

Note

For more details on VQE and the quantum chemistry functionality available in

[`qchem`](index.html#module-pennylane.qchem "pennylane.qchem"), check out the PennyLane [quantum chemistry tutorials](https://pennylane.ai/qml/demos_quantum-chemistry.html).

#### Quantum chemistry functions and classes[¶](#quantum-chemistry-functions-and-classes "Permalink to this headline")

PennyLane supports the following quantum chemistry functions and classes.

##### Molecular integrals and matrices[¶](#molecular-integrals-and-matrices "Permalink to this headline")

| [`attraction\_integral`](index.html#pennylane.qchem.attraction_integral "pennylane.qchem.attraction_integral") | Return a function that computes the nuclear attraction integral for two contracted Gaussian functions. |

| [`attraction\_matrix`](index.html#pennylane.qchem.attraction_matrix "pennylane.qchem.attraction_matrix") | Return a function that computes the electron-nuclear attraction matrix for a given set of basis functions. |

| [`contracted\_norm`](index.html#pennylane.qchem.contracted_norm "pennylane.qchem.contracted_norm") | Compute the normalization constant for a contracted Gaussian function. |

| [`core\_matrix`](index.html#pennylane.qchem.core_matrix "pennylane.qchem.core_matrix") | Return a function that computes the core matrix for a given set of basis functions. |

| [`dipole\_integrals`](index.html#pennylane.qchem.dipole_integrals "pennylane.qchem.dipole_integrals") | Return a function that computes the dipole moment integrals over the molecular orbitals. |

| [`electron\_integrals`](index.html#pennylane.qchem.electron_integrals "pennylane.qchem.electron_integrals") | Return a function that computes the one- and two-electron integrals in the molecular orbital basis. |

| [`electron\_repulsion`](index.html#pennylane.qchem.electron_repulsion "pennylane.qchem.electron_repulsion") | Compute the electron-electron repulsion integral between four primitive Gaussian functions. |

| [`expansion`](index.html#pennylane.qchem.expansion "pennylane.qchem.expansion") | Compute Hermite Gaussian expansion coefficients recursively for two Gaussian functions. |

| [`gaussian\_kinetic`](index.html#pennylane.qchem.gaussian_kinetic "pennylane.qchem.gaussian_kinetic") | Compute the kinetic integral for two primitive Gaussian functions. |

| [`gaussian\_moment`](index.html#pennylane.qchem.gaussian_moment "pennylane.qchem.gaussian_moment") | Compute the one-dimensional multipole moment integral for two primitive Gaussian functions. |

| [`gaussian\_overlap`](index.html#pennylane.qchem.gaussian_overlap "pennylane.qchem.gaussian_overlap") | Compute overlap integral for two primitive Gaussian functions. |

| [`hermite\_moment`](index.html#pennylane.qchem.hermite_moment "pennylane.qchem.hermite_moment") | Compute the Hermite moment integral recursively. |

| [`kinetic\_integral`](index.html#pennylane.qchem.kinetic_integral "pennylane.qchem.kinetic_integral") | Return a function that computes the kinetic integral for two contracted Gaussian functions. |

| [`kinetic\_matrix`](index.html#pennylane.qchem.kinetic_matrix "pennylane.qchem.kinetic_matrix") | Return a function that computes the kinetic matrix for a given set of basis functions. |

| [`mol\_density\_matrix`](index.html#pennylane.qchem.mol_density_matrix "pennylane.qchem.mol_density_matrix") | Compute the molecular density matrix. |

| [`moment\_integral`](index.html#pennylane.qchem.moment_integral "pennylane.qchem.moment_integral") | Return a function that computes the multipole moment integral for two contracted Gaussians. |

| [`moment\_matrix`](index.html#pennylane.qchem.moment_matrix "pennylane.qchem.moment_matrix") | Return a function that computes the multipole moment matrix for a set of basis functions. |

| [`nuclear\_attraction`](index.html#pennylane.qchem.nuclear_attraction "pennylane.qchem.nuclear_attraction") | Compute nuclear attraction integral between primitive Gaussian functions. |

| [`overlap\_integral`](index.html#pennylane.qchem.overlap_integral "pennylane.qchem.overlap_integral") | Return a function that computes the overlap integral for two contracted Gaussian functions. |

| [`overlap\_matrix`](index.html#pennylane.qchem.overlap_matrix "pennylane.qchem.overlap_matrix") | Return a function that computes the overlap matrix for a given set of basis functions. |

| [`primitive\_norm`](index.html#pennylane.qchem.primitive_norm "pennylane.qchem.primitive_norm") | Compute the normalization constant for a primitive Gaussian function. |

| [`repulsion\_integral`](index.html#pennylane.qchem.repulsion_integral "pennylane.qchem.repulsion_integral") | Return a function that computes the electron-electron repulsion integral for four contracted Gaussian functions. |

| [`repulsion\_tensor`](index.html#pennylane.qchem.repulsion_tensor "pennylane.qchem.repulsion_tensor") | Return a function that computes the electron repulsion tensor for a given set of basis functions. |

##### Differentiable Hartree-Fock[¶](#differentiable-hartree-fock "Permalink to this headline")

| [`hf\_energy`](index.html#pennylane.qchem.hf_energy "pennylane.qchem.hf_energy") | Return a function that computes the Hartree-Fock energy. |

| [`nuclear\_energy`](index.html#pennylane.qchem.nuclear_energy "pennylane.qchem.nuclear_energy") | Return a function that computes the nuclear-repulsion energy. |

| [`scf`](index.html#pennylane.qchem.scf "pennylane.qchem.scf") | Return a function that performs the self-consistent-field calculations. |

##### Hartree-Fock with external packages[¶](#hartree-fock-with-external-packages "Permalink to this headline")

| [`decompose`](index.html#pennylane.qchem.decompose "pennylane.qchem.decompose") | Decomposes the molecular Hamiltonian into a linear combination of Pauli operators using OpenFermion tools. |

| [`meanfield`](index.html#pennylane.qchem.meanfield "pennylane.qchem.meanfield") | Generates a file from which the mean field electronic structure of the molecule can be retrieved. |

| [`one\_particle`](index.html#pennylane.qchem.one_particle "pennylane.qchem.one_particle") | Generates the [FermionOperator](https://github.com/quantumlib/OpenFermion/blob/master/docs/tutorials/intro_to_openfermion.ipynb) representing a given one-particle operator required to build many-body qubit observables. |

| [`two\_particle`](index.html#pennylane.qchem.two_particle "pennylane.qchem.two_particle") | Generates the [FermionOperator](https://github.com/quantumlib/OpenFermion/blob/master/docs/tutorials/intro_to_openfermion.ipynb) representing a given two-particle operator required to build many-body qubit observables.

 |

##### Differentiable observables[¶](#differentiable-observables "Permalink to this headline")

| [`diff\_hamiltonian`](index.html#pennylane.qchem.diff_hamiltonian "pennylane.qchem.diff_hamiltonian") | Return a function that computes the qubit Hamiltonian. |

| [`dipole\_moment`](index.html#pennylane.qchem.dipole_moment "pennylane.qchem.dipole_moment") | Return a function that computes the qubit dipole moment observable. |

| [`fermionic\_dipole`](index.html#pennylane.qchem.fermionic_dipole "pennylane.qchem.fermionic_dipole") | Return a function that builds the fermionic dipole moment observable. |

| [`fermionic\_hamiltonian`](index.html#pennylane.qchem.fermionic_hamiltonian "pennylane.qchem.fermionic_hamiltonian") | Return a function that computes the fermionic Hamiltonian. |

| [`fermionic\_observable`](index.html#pennylane.qchem.fermionic_observable "pennylane.qchem.fermionic_observable") | Create a fermionic observable from molecular orbital integrals. |

| [`jordan\_wigner`](index.html#pennylane.qchem.jordan_wigner "pennylane.qchem.jordan_wigner") | Convert a fermionic operator to a qubit operator using the Jordan-Wigner mapping. |

| [`molecular\_hamiltonian`](index.html#pennylane.qchem.molecular_hamiltonian "pennylane.qchem.molecular_hamiltonian") | Generate the qubit Hamiltonian of a molecule. |

| [`qubit\_observable`](index.html#pennylane.qchem.qubit_observable "pennylane.qchem.qubit_observable") | Convert a fermionic observable to a PennyLane qubit observable. |

##### Other observables[¶](#other-observables "Permalink to this headline")

| [`dipole\_of`](index.html#pennylane.qchem.dipole_of "pennylane.qchem.dipole_of") | Computes the electric dipole moment operator in the Pauli basis. |

| [`observable`](index.html#pennylane.qchem.observable "pennylane.qchem.observable") | Builds the fermionic many-body observable whose expectation value can be measured in PennyLane. |

| [`particle\_number`](index.html#pennylane.qchem.particle_number "pennylane.qchem.particle_number") | Compute the particle number observable \(\hat{N}=\sum\_\alpha \hat{n}\_\alpha\) in the Pauli basis. |

| [`spin2`](index.html#pennylane.qchem.spin2 "pennylane.qchem.spin2") | Compute the total spin observable \(\hat{S}^2\). |

| [`spinz`](index.html#pennylane.qchem.spinz "pennylane.qchem.spinz") | Computes the total spin projection observable \(\hat{S}\_z\). |

##### Qubit tapering[¶](#qubit-tapering "Permalink to this headline")

| [`clifford`](index.html#pennylane.qchem.clifford "pennylane.qchem.clifford") | Compute a Clifford operator from a set of generators and Pauli-X operators. |

| [`optimal\_sector`](index.html#pennylane.qchem.optimal_sector "pennylane.qchem.optimal_sector") | Get the optimal sector which contains the ground state. |

| [`paulix\_ops`](index.html#pennylane.paulix_ops "pennylane.paulix_ops") | Generate the single qubit Pauli-X operators \(\sigma^{x}\_{i}\) for each symmetry \(\tau\_j\), such that it anti-commutes with \(\tau\_j\) and commutes with all others symmetries \(\tau\_{k\neq j}\). |

| [`symmetry\_generators`](index.html#pennylane.symmetry_generators "pennylane.symmetry_generators") | Compute the generators \(\{\tau\_1, \ldots, \tau\_k\}\) for a Hamiltonian over the binary field \(\mathbb{Z}\_2\). |

| [`taper`](index.html#pennylane.taper "pennylane.taper") | Transform a Hamiltonian with a Clifford operator and then taper qubits. |

| [`taper\_hf`](index.html#pennylane.qchem.taper_hf "pennylane.qchem.taper_hf") | Transform a Hartree-Fock state with a Clifford operator and then taper qubits. |

| [`taper\_operation`](index.html#pennylane.qchem.taper_operation "pennylane.qchem.taper_operation") | Transform a gate operation with a Clifford operator and then taper qubits. |

##### Utility functions[¶](#utility-functions "Permalink to this headline")

| [`active\_space`](index.html#pennylane.qchem.active_space "pennylane.qchem.active_space") | Build the active space for a given number of active electrons and active orbitals. |

| [`excitations`](index.html#pennylane.qchem.excitations "pennylane.qchem.excitations") | Generate single and double excitations from a Hartree-Fock reference state. |

| [`excitations\_to\_wires`](index.html#pennylane.qchem.excitations_to_wires "pennylane.qchem.excitations_to_wires") | Map the indices representing the single and double excitations generated with the function [`excitations()`](index.html#pennylane.qchem.excitations "pennylane.qchem.excitations") to the wires that the Unitary Coupled-Cluster (UCCSD) template will act on. |

| [`factorize`](index.html#pennylane.qchem.factorize "pennylane.qchem.factorize") | Return the double-factorized form of a two-electron integral tensor in spatial basis. |

| [`givens\_decomposition`](index.html#pennylane.qchem.givens_decomposition "pennylane.qchem.givens_decomposition") | Decompose a unitary into a sequence of Givens rotation gates with phase shifts and a diagonal phase matrix. |

| [`hf\_state`](index.html#pennylane.qchem.hf_state "pennylane.qchem.hf_state") | Generate the occupation-number vector representing the Hartree-Fock state. |

| [`import\_operator`](index.html#pennylane.import_operator "pennylane.import_operator") | Convert an external operator to a PennyLane operator. |

| [`import\_state`](index.html#pennylane.qchem.import_state "pennylane.qchem.import_state") | Convert an external wavefunction to a state vector. |

| [`mol\_data`](index.html#pennylane.qchem.mol_data "pennylane.qchem.mol_data") | Obtain symbols and geometry of a compound from the PubChem Database. |

| [`read\_structure`](index.html#pennylane.qchem.read_structure "pennylane.qchem.read_structure") | Read the structure of the polyatomic system from a file and returns a list with the symbols of the atoms in the molecule and a 1D array with their positions \([x\_1, y\_1, z\_1, x\_2, y\_2, z\_2, \dots]\) in atomic units (Bohr radius = 1). |

##### Molecule class and basis functions[¶](#molecule-class-and-basis-functions "Permalink to this headline")

| [`atom\_basis\_data`](index.html#pennylane.qchem.atom_basis_data "pennylane.qchem.atom_basis_data") | Generate default basis set parameters for an atom. |

| [`BasisFunction`](index.html#pennylane.qchem.BasisFunction "pennylane.qchem.BasisFunction") | Create a basis function object. |

| [`Molecule`](index.html#pennylane.qchem.Molecule "pennylane.qchem.Molecule") | Create a molecule object that stores molecular information and default basis set parameters. |

| [`mol\_basis\_data`](index.html#pennylane.qchem.mol_basis_data "pennylane.qchem.mol_basis_data") | Generates default basis set parameters for a molecule. |

### Quantum Datasets[¶](#quantum-datasets "Permalink to this headline")

PennyLane provides the [`data`](index.html#module-pennylane.data "pennylane.data") subpackage to download, create, store and manipulate quantum datasets,

where the quantum dataset is a collection of quantum data obtained from various quantum systems that describe it and its evolution.

Note

The packages `aiohttp`, `fsspec`, and `h5py` are required to use the [`data`](index.html#module-pennylane.data "pennylane.data") module.

These can be installed with:

```

pip install aiohttp fsspec h5py

```

#### Loading Datasets in PennyLane[¶](#loading-datasets-in-pennylane "Permalink to this headline")

We can access data of a desired type with the [`load()`](index.html#pennylane.data.load "pennylane.data.load") or [`load\_interactive()`](index.html#pennylane.data.load_interactive "pennylane.data.load_interactive") functions.

These download the desired datasets or load them from local storage if previously downloaded.

To specify the dataset to be loaded, the data category (`data\_name`) must be

specified, alongside category-specific keyword arguments. For the full list

of available datasets, please see the [datasets website](https://pennylane.ai/datasets).

The [`load()`](index.html#pennylane.data.load "pennylane.data.load") function returns a `list` with the desired data.

```

>>> H2datasets = qml.data.load("qchem", molname="H2", basis="STO-3G", bondlength=1.1)

>>> print(H2datasets)

[<Dataset = molname: H2, basis: STO-3G, bondlength: 1.1, attributes: ['basis', 'basis\_rot\_groupings', ...]>]

>>> H2data = H2datasets[0]

```

We can load datasets for multiple parameter values by providing a list of values instead of a single value.

To load all possible values, use the special value `FULL` or the string `"full"`:

```

>>> H2datasets = qml.data.load("qchem", molname="H2", basis="full", bondlength=[0.5, 1.1])

>>> print(H2datasets)

[<Dataset = molname: H2, basis: STO-3G, bondlength: 0.5, attributes: ['basis', 'basis\_rot\_groupings', ...]>,

<Dataset = molname: H2, basis: STO-3G, bondlength: 1.1, attributes: ['basis', 'basis\_rot\_groupings', ...]>,

<Dataset = molname: H2, basis: CC-PVDZ, bondlength: 0.5, attributes: ['basis', 'basis\_rot\_groupings', ...]>,

<Dataset = molname: H2, basis: CC-PVDZ, bondlength: 1.1, attributes: ['basis', 'basis\_rot\_groupings', ...]>,

<Dataset = molname: H2, basis: 6-31G, bondlength: 0.5, attributes: ['basis', 'basis\_rot\_groupings', ...]>,

<Dataset = molname: H2, basis: 6-31G, bondlength: 1.1, attributes: ['basis', 'basis\_rot\_groupings', ...]>]

```

When we only want to download portions of a large dataset, we can specify the desired properties (referred to as ‘attributes’).

For example, we can download or load only the molecule and energy of a dataset as follows:

```

>>> part = qml.data.load("qchem", molname="H2", basis="STO-3G", bondlength=1.1,

...                      attributes=["molecule", "fci\_energy"])[0]

>>> part.molecule

<Molecule = H2, Charge: 0, Basis: STO-3G, Orbitals: 2, Electrons: 2>

>>> part.fci\_energy

-1.0791924385860894

```

To determine what attributes are available for a type of dataset, we can use the function [`list\_attributes()`](index.html#pennylane.data.list_attributes "pennylane.data.list_attributes"):

```

>>> qml.data.list\_attributes(data\_name="qchem")

['molname',

 'basis',

 'bondlength',

 ...

 'vqe\_params',

 'vqe\_energy']

```

Note

The default values for attributes are as follows:

* Molecules: `basis` is the smallest available basis, usually `"STO-3G"`, and `bondlength` is the optimal bondlength for the molecule or an alternative if the optimal is not known.

* Spin systems: `periodicity` is `"open"`, `lattice` is `"chain"`, and `layout` is `1x4` for `chain` systems and `2x2` for `rectangular` systems.

#### Using Datasets in PennyLane[¶](#using-datasets-in-pennylane "Permalink to this headline")

Once loaded, one can access properties of the datasets:

```

>>> H2data.molecule

<Molecule = H2, Charge: 0, Basis: STO-3G, Orbitals: 2, Electrons: 2>

>>> print(H2data.hf\_state)

[1 1 0 0]

```

The loaded data items are fully compatible with PennyLane. We can therefore

use them directly in a PennyLane circuits as follows:

```

>>> dev = qml.device("default.qubit",wires=4)

>>> @qml.qnode(dev)

... def circuit():

...     qml.BasisState(H2data.hf\_state, wires = [0, 1, 2, 3])

...     for op in H2data.vqe\_gates:

...         qml.apply(op)

...     return qml.expval(H2data.hamiltonian)

>>> print(circuit())

-1.0791430411076344

```

#### Dataset Structure[¶](#dataset-structure "Permalink to this headline")

You can call the

[`list\_datasets()`](index.html#pennylane.data.list_datasets "pennylane.data.list_datasets") function to get a snapshot of the currently available data.

This function returns a nested dictionary as we show below.

```

>>> available\_data = qml.data.list\_datasets()

>>> available\_data.keys()

dict\_keys(["qspin", "qchem"])

>>> available\_data["qchem"].keys()

dict\_keys(["H2", "LiH", ...])

>>> available\_data['qchem']['H2'].keys()

dict\_keys(["6-31G", "STO-3G"])

>>> print(available\_data['qchem']['H2']['STO-3G'])

["0.5", "0.54", "0.62", "0.66", ...]

```

Note that this example limits the results

of the function calls for clarity and that as more data becomes available, the results of these

function calls will change.

#### Creating Custom Datasets[¶](#creating-custom-datasets "Permalink to this headline")

The functionality in [`data`](index.html#module-pennylane.data "pennylane.data") also includes creating and reading custom-made datasets.

We can use custom datasets to store any data generated in PennyLane and its supporting data.

To create a dataset, we can do the following:

```

>>> coeffs = [1, 0.5]

>>> observables = [qml.PauliZ(wires=0), qml.PauliX(wires=1)]

>>> H = qml.Hamiltonian(coeffs, observables)

>>> energies, \_ = np.linalg.eigh(qml.matrix(H)) #Calculate the energies

>>> dataset = qml.data.Dataset(data\_name = "Example", hamiltonian=H, energies=energies)

>>> dataset.data\_name

"Example"

>>> dataset.hamiltonian

(0.5) [X1]

+ (1) [Z0]

>>> dataset.energies

array([-1.5, -0.5, 0.5, 1.5])

```

We can then write this [`Dataset`](index.html#pennylane.data.Dataset "pennylane.data.Dataset") to storage and read it as follows:

```

>>> dataset.write("./path/to/dataset.h5")

>>> read\_dataset = qml.data.Dataset()

>>> read\_dataset.read("./path/to/dataset.h5")

>>> read\_dataset.data\_name

"Example"

>>> read\_dataset.hamiltonian

(0.5) [X1]

+ (1) [Z0]

>>> read\_dataset.energies

array([-1.5, -0.5, 0.5, 1.5])

```

#### Quantum Datasets Functions and Classes[¶](#quantum-datasets-functions-and-classes "Permalink to this headline")

| [`list\_datasets`](index.html#pennylane.data.list_datasets "pennylane.data.list_datasets") | Returns a dictionary of the available datasets. |

| [`list\_attributes`](index.html#pennylane.data.list_attributes "pennylane.data.list_attributes") | List the attributes that exist for a specific `data\_name`. |

| [`load`](index.html#pennylane.data.load "pennylane.data.load") | Downloads the data if it is not already present in the directory and returns it as a list of [`Dataset`](index.html#pennylane.data.Dataset "pennylane.data.Dataset") objects. |

| [`load\_interactive`](index.html#pennylane.data.load_interactive "pennylane.data.load_interactive") | Download a dataset using an interactive load prompt. |

| [`Dataset`](index.html#pennylane.data.Dataset "pennylane.data.Dataset") | Base class for Datasets. |

### QNode returns[¶](#qnode-returns "Permalink to this headline")

Version 0.30.0 of PennyLane updated the return type of a [`QNode`](index.html#pennylane.QNode "pennylane.QNode"). This page

provides additional details about the update and can be used to troubleshoot issues.

Note

If you are looking for a quick fix, jump to the [Troubleshooting](#troubleshooting) section!

After visiting the [Troubleshooting](#troubleshooting) section, if you are still stuck then you can:

* Post on the PennyLane [discussion forum](https://discuss.pennylane.ai).

* If you suspect that your issue is due to a bug in PennyLane itself, please open a

[bug report](https://github.com/PennyLaneAI/pennylane/issues/new?labels=bug+%3Abug%3A&template=bug_report.yml&title=[BUG])

on the PennyLane GitHub page.

#### Summary of the update[¶](#summary-of-the-update "Permalink to this headline")

[![_images/new_return_types.png](_images/new_return_types.png)](javascript:void(0);)

PennyLane QNodes now return exactly what you tell them to! 🎉

Consider the following circuit:

```

import pennylane as qml

dev = qml.device("default.qubit", wires=1)

@qml.qnode(dev)

def circuit(x):

    qml.RX(x, wires=0)

    return qml.expval(qml.PauliZ(0)), qml.probs(0)

```

In version 0.29 and earlier of PennyLane, `circuit()` would return a single length-3 array:

```

>>> circuit(0.5)

tensor([0.87758256, 0.93879128, 0.06120872], requires\_grad=True)

```

In versions 0.30 and above, `circuit()` returns a length-2 tuple containing the expectation value

and probabilities separately:

```

>>> circuit(0.5)

(tensor(0.87758256, requires\_grad=True),

 tensor([0.93879128, 0.06120872], requires\_grad=True))

```

For a detailed explanation of this change, along with code examples, check out the

[`enable\_return()`](index.html#pennylane.enable_return "pennylane.enable_return") function documentation.

#### Motivation[¶](#motivation "Permalink to this headline")

PennyLane has historically adopted the approach of combining the returned

[measurements](index.html#intro-ref-meas) of a QNode into a single array. However, this has presented

some challenges:

* The return of a QNode could be different from what is expected, as shown in the

[example](#return-type-example-issue) above.

* For measurements of different shapes, ragged arrays were generated internally and then squeezed

into a single output array. This is incompatible with NumPy’s

[NEP 34](https://numpy.org/neps/nep-0034-infer-dtype-is-object.html) and constrains the

[version of NumPy](https://github.com/PennyLaneAI/pennylane/blob/v0.29.1/setup.py#L21) that

PennyLane is compatible with.

* Use of stacking and squeezing presents performance bottlenecks.

The changes made in version 0.30 of PennyLane address the challenges above. However, existing users

may experience breaking changes or issues when upgrading their PennyLane version.

#### Troubleshooting[¶](#troubleshooting "Permalink to this headline")

You may experience issues with PennyLane’s updated QNode return system in version 0.30 and above

if you have existing code that works with an earlier version of PennyLane. To help identify a fix,

select the option below that describes your situation.

[I am using a QNode that returns more than one quantity

--------------------------------------------------------](#qnode-multiple-returns)

Your issue may be because:

* You are calculating the Jacobian of the QNode using the [NumPy](index.html#numpy-interf) or

[TensorFlow](index.html#tf-interf) interface. For example, the following will now raise an error:

```

from pennylane import numpy as np

dev = qml.device("default.qubit", wires=1)

@qml.qnode(dev)

def circuit(x):

    qml.RX(x, wires=0)

    return qml.expval(qml.PauliY(0)), qml.expval(qml.PauliZ(0))

x = np.array(0.5, requires\_grad=True)

qml.jacobian(circuit)(x)

```

Follow the instructions [here](index.html#return-autograd-tf-gotcha) to fix this issue, which

arises because NumPy and TensorFlow do not support differentiating tuples.

Alternatively, consider porting your code to use the [JAX](index.html#jax-interf) or

[Torch](index.html#torch-interf) interface, which could unlock additional features and performance

benefits!

* You are returning differently-shaped quantities together, such as

[`expval()`](index.html#pennylane.expval "pennylane.expval") and [`probs()`](index.html#pennylane.probs "pennylane.probs"). For example, the

following code is compatible with version 0.29 of PennyLane but will raise an error in version

0.30 and above:

```

dev = qml.device("default.qubit", wires=1)

@qml.qnode(dev)

def circuit(x):

    qml.RX(x, wires=0)

    return qml.expval(qml.PauliZ(0)), qml.probs(0)

def result(x):

    expval, p0, p1 = circuit(x)

    return expval + p0 - p1

x = np.array(0.5, requires\_grad=True)

result(x)

```

Such issues can be addressed by updating how the return of a QNode is processed, being aware

of unpacking, slicing, and indexing. The example above would be fixed simply by updating

`result()` to:

```

def result(x):

    expval, (p0, p1) = circuit(x)

    return expval + p0 - p1

```

[I am a device developer

-------------------------](#device-developer)

If you are a [device developer](index.html#plugin-overview), your issue may be because:

* Your device inherits from [`QubitDevice`](index.html#pennylane.QubitDevice "pennylane.QubitDevice") and you have overriden or interact with the

[`execute()`](index.html#pennylane.QubitDevice.execute "pennylane.QubitDevice.execute"), [`batch\_execute()`](index.html#pennylane.QubitDevice.batch_execute "pennylane.QubitDevice.batch_execute"), or

[`statistics()`](index.html#pennylane.QubitDevice.statistics "pennylane.QubitDevice.statistics") methods. Your device will need to be updated to accommodate

for the new return behaviour. An example can be found

[here](https://github.com/PennyLaneAI/pennylane-qiskit/pull/281) for the

[Qiskit plugin](https://docs.pennylane.ai/projects/qiskit/en/latest/).

* Your device inherits directly from [`Device`](index.html#pennylane.Device "pennylane.Device"), in which case you may

need to rewrite the [`execute()`](index.html#pennylane.Device.execute "pennylane.Device.execute") and

[`batch\_execute()`](index.html#pennylane.Device.batch_execute "pennylane.Device.batch_execute") methods.

In either case, please [reach out to us](https://discuss.pennylane.ai) for guidance!

[I am unsure what to do

------------------------](#unsure)

Please carefully read through the options above. If you are still stuck, you can:

* Post on the PennyLane [discussion forum](https://discuss.pennylane.ai). Please include

a complete block of code demonstrating your issue so that we can quickly troubleshoot.

* If you suspect that your issue is due to a bug in PennyLane itself, please open a

[bug report](https://github.com/PennyLaneAI/pennylane/issues/new?labels=bug+%3Abug%3A&template=bug_report.yml&title=[BUG])

on the PennyLane GitHub page.

* As a *last resort*, you can place [`qml.disable\_return()`](index.html#pennylane.disable_return "pennylane.disable_return") at the top of

your code. This will revert PennyLane’s behaviour to the QNode return type in version 0.29.

However, be aware that this capability will be removed in a future version of PennyLane!

### Logging[¶](#logging "Permalink to this headline")

PennyLane has support for Python’s logging framework. PennyLane defines all logging configuration in a static TOML file, `log\_config.toml`, which can be customized to support rules for a given user or system environment.

To see the default logging options you can explore the contexts of `log\_config.toml` at the path given from [`pennylane.logging.config\_path()`](index.html#pennylane.logging.config_path "pennylane.logging.config_path").

#### Enabling logging[¶](#enabling-logging "Permalink to this headline")

To enable logging support with the default options defined in `log\_config.toml` simply call [`pennylane.logging.enable\_logging()`](index.html#pennylane.logging.enable_logging "pennylane.logging.enable_logging") after importing PennyLane:

```

import pennylane as qml

qml.logging.enable\_logging()

...

```

This will ensure all levels of the execution pipeline logs function entries, and

outputs to the default configured handler, which is directed to the standard output stream. To also direct logging output to a file named `qml\_debug.log` in the directory of execution, the `qml\_debug\_file` handler can be added to the defined loggers in `log\_config.toml` as follows:

```

# Control logging across pennylane

[loggers.pennylane]

handlers = ["qml\_debug\_stream", "qml\_debug\_file"]

level = "DEBUG" # Set to TRACE for highest verbosity

propagate = false

```

For more info on the customization of the logging options, please see the logging development guide at [Logging development guidelines](index.html#document-development/guide/logging), and the [Python logging documentation](https://docs.python.org/3/library/logging.html).

### Development guide[¶](#development-guide "Permalink to this headline")

The Development guide contains information regarding how to contribute to the

PennyLane codebase.

The guides below are aimed towards developers and cover how to install

PennyLane and its dependencies in development mode, run and add tests, write

documentation, as well as general best practices and an architectural overview

of PennyLane, plugins, and devices.

[**Installation**

 Installation and dependencies of the PennyLane source code using development mode.](guide/installation.html)

[**Contribution guide**

 How to get involved in the PennyLane community and help improve PennyLane.](guide/contributing.html)

[**Software tests**

 Installing dependencies, running the PennyLane test suite and measuring coverage.](guide/tests.html)

[**Documentation**

 Building and contributing modules and packages to the PennyLane documentation.](guide/documentation.html)

[**Submitting a pull request**

 Creating and submitting a pull request to the PennyLane repository.](guide/pullrequests.html)

[**Architecture Design Records**

 Proposing important PennyLane architectural decisions.](guide/adr.html)

[**Logging guidelines**

 Defining how to develop using logging supports in PennyLane.](guide/logging.html)

[**Architectural overview**

 Architectural overview of PennyLane, its plugins and devices.](guide/architecture.html)

#### Installation and dependencies[¶](#installation-and-dependencies "Permalink to this headline")

##### Dependencies[¶](#dependencies "Permalink to this headline")

PennyLane requires the following libraries be installed:

* [Python](http://python.org/) >= 3.9

The following Python packages are hard dependencies, and will automatically

be installed alongside PennyLane:

* [numpy](http://numpy.org/) >= 1.13.3

* [scipy](http://scipy.org/) >= 1.0.0

* [NetworkX](https://networkx.github.io/) >= 1.0.0

* [autograd](https://github.com/HIPS/autograd)

* [toml](https://github.com/uiri/toml)

* [appdirs](https://github.com/ActiveState/appdirs)

* [semantic-version](https://github.com/rbarrois/python-semanticversion) >= 2.7

* [autoray](https://github.com/jcmgray/autoray)

The following Python packages are optional:

* [dask[“parallel”]](https://dask.org/), for parallel QNodeCollection execution

* [tensornetwork](https://github.com/google/TensorNetwork) >= 0.3, for the `default.tensor` plugin

* [openfermionpyscf](https://github.com/quantumlib/OpenFermion-PySCF), for the non-differentiable backend of the `qml.qchem` module

If you currently do not have Python 3 installed, we recommend

[Anaconda for Python 3](https://www.anaconda.com/download/), a distributed version

of Python packaged for scientific computation.

###### Interface dependencies[¶](#interface-dependencies "Permalink to this headline")

For development of the TensorFlow, PyTorch, and JAX interfaces, there are additional

requirements which must be installed manually:

* **JAX interface**: `jax > 0.2.0` and `jaxlib`

* **PyTorch interface**: `pytorch >= 1.1`

* **TensorFlow interface**: `tensorflow >= 2.3`

##### Installation[¶](#installation "Permalink to this headline")

For development purposes, it is recommended to install PennyLane source code

using development mode:

```

git clone https://github.com/PennyLaneAI/pennylane

cd pennylane

pip install -e .

```

The `-e` flag ensures that edits to the source code will be reflected when

importing PennyLane in Python.

Note

Due to the use of [entry points](index.html#installing-plugin) to install

plugins, changes to PennyLane device class locations or shortnames

requires `pip install -e .` to be re-run in the plugin repository

for the changes to take effect.

##### Docker[¶](#docker "Permalink to this headline")

###### Build a PennyLane Docker image[¶](#build-a-pennylane-docker-image "Permalink to this headline")

**Docker** support exists for building using **CPU** and **GPU** (Nvidia CUDA 11.1+) images.

Note

Docker builds using “make” will work on Linux and MacOS only. For MS Windows

you can use [WSL](https://docs.microsoft.com/en-us/windows/wsl/install-win10).

They are currently not supported on the Apple M1 chip (ARM64).

###### Build a basic PennyLane image[¶](#build-a-basic-pennylane-image "Permalink to this headline")

* To build a basic PennyLane image without any additional interfaces (Torch,

TensorFlow, or Jax) or **plugins** (qiskit, amazon-braket, cirq, forest), run

the following:

```

make -f docker/Makefile build-base

```

###### Build a PennyLane image with a specific interface[¶](#build-a-pennylane-image-with-a-specific-interface "Permalink to this headline")

* To build a PennyLane image using a specific **interface** (Torch, TensorFlow or Jax), run the following:

```

make -f docker/Makefile build-interface interface-name=tensorflow

```

* To build a PennyLane image using a specific interface (Torch, TensorFlow or

Jax) with GPU support, run the following:

```

make -f docker/Makefile build-interface-gpu interface-name=tensorflow

```

###### Build a PennyLane image with a plugin[¶](#build-a-pennylane-image-with-a-plugin "Permalink to this headline")

* To build a PennyLane image using a specific plugin (qiskit, amazon-braket,

cirq, forest, etc), run the following:

```

make -f docker/Makefile build-plugin plugin-name=qiskit

```

#### Contributing to PennyLane[¶](#contributing-to-pennylane "Permalink to this headline")

Thank you for taking the time to contribute to PennyLane!

PennyLane is a collaborative effort with the quantum computation and machine learning communities.

We invite you to join our team in whatever capacity works best for you.

Learn more about contributing to open source in general with

[this great guide](https://opensource.guide/how-to-contribute/).

Please pay attention to our

[code of conduct](https://github.com/PennyLaneAI/pennylane/blob/master/.github/CODE_OF_CONDUCT.md)

and help us make quantum computing a welcoming place for all.

##### How can I get involved in the community?[¶](#how-can-i-get-involved-in-the-community "Permalink to this headline")

Start by experimenting with PennyLane. Figure out how to do things and form opinions about what you

like and dislike about the ecosystem. What made your life easier? What was a source of

difficulty and confusion? We can always use more user feedback. You can use our

[demonstrations](https://pennylane.ai/qml/demonstrations.html) and

[blog](https://pennylane.ai/blog/) to learn about features and applications.

As you get a feel for the user experience, you can start peeking under the hood and finding out how

the package accomplishes its tasks.

To chat directly with the dedicated team behind PennyLane or other members of our community, you

can join our [PennyLane discussion forum](https://discuss.pennylane.ai).

Sometimes, it might take us a couple of hours to reply - please be patient!

##### How can I contribute?[¶](#how-can-i-contribute "Permalink to this headline")

It’s up to you!

* **Write a Community Demo.** - Show off your PennyLane application on

[our community page](https://pennylane.ai/qml/demos_community.html). We take Jupyter notebooks,

scripts with explanations, or entire repositories. Community demos are a great way to showcase

research and new papers.

* **Be a part of our community.** - Respond to questions, issues, and

provide updates on the projects/experiments you are investigating with PennyLane.

* **Test the cutting-edge PennyLane releases.** - Clone our GitHub repository, and keep up with

the latest features. Learn how to install PennyLane from source

[here](https://pennylane.ai/install.html?version=preview). If you run into any bugs, make a bug

report on our [issue tracker](https://github.com/XanaduAI/pennylane/issues).

* **Report bugs.** - If you come across any bugs or issues, make a bug report. PennyLane has

[a form](https://github.com/PennyLaneAI/pennylane/issues/new?assignees=&labels=bug+%3Abug%3A&template=bug_report.yml&title=%5BBUG%5D)

to help walk you through submitting a bug report. Providing a complete, detailed description

helps us figure out the source of the problem faster.

* **Suggest new features and enhancements.** Use our

[Feature Request form](https://github.com/PennyLaneAI/pennylane/issues/new?assignees=&labels=enhancement+%3Asparkles%3A&template=feature_request.yml)

and let us know what will make PennyLane even better for you.

* **Contribute to the PennyLane repository itself.** See more below.

###### Ways to contribute to the PennyLane repository[¶](#ways-to-contribute-to-the-pennylane-repository "Permalink to this headline")

Want to help with the repository itself? There are several different avenues for that:

* **Good first issues** - Don’t know where to start? Take a look at our

[“good first issue” label](https://github.com/PennyLaneAI/pennylane/contribute). Issues with

this label are meant for newcomers and *should* contain fewer challenging bits. If the issue

ends up trickier than we assumed, you can start a conversation on the issue page or open up a

“Work in Progress” PR to ask for help. Developers new to PennyLane can use the [requirements-dev.txt](https://github.com/PennyLaneAI/pennylane/blob/master/requirements-dev.txt) file to install dependencies required for PennyLane code development. Simply run `pip install -r requirements-dev.txt` from the root of the repository.

* **Documentation**- If you would like to add to our documentation or suggest

improvements/changes, let us know or submit a pull request directly. Changes that fix rendering

issues, grammar, or a broken code example help us a lot too. Take a look at the

[documentation guide](https://pennylane.readthedocs.io/en/stable/development/guide/documentation.html)

for more specifics.

* **Add a new Operator or Template.** Circuit structures crop up in literature faster than we can

add them, so we are always looking for help. Take a look at the

[Contributing operators](https://pennylane.readthedocs.io/en/stable/development/adding_operators.html)

page for more information.

* **Develop a PennyLane plugin** - PennyLane is designed to be device and quantum-framework

agnostic. Users can switch a circuit’s device to any other compatible device with barely any code

changes. We would love to support even more devices and quantum frameworks. If you would like to

write a PennyLane plugin, see the page on

[“Building a plugin”](https://pennylane.readthedocs.io/en/stable/development/plugins.html).

Did we catch your interest?

##### Pull requests[¶](#pull-requests "Permalink to this headline")

If you would like to contribute directly to the PennyLane codebase, make a fork of the master

branch and submit a [pull request](https://help.github.com/articles/about-pull-requests). We

encourage everyone to fork and modify the PennyLane source code. However, we have a couple of

guidelines on pull requests to ensure the master branch of PennyLane conforms to existing standards

and quality. We can help you meet these standards during our code review process, so don’t let

those stop you from getting started. Pull Requests do not need to be big and complicated. We

appreciate even minor bug fixes or documentation improvements.

See our [Development Guide](https://pennylane.readthedocs.io/en/stable/development/guide.html)

and the page on

[submitting a pull request](https://pennylane.readthedocs.io/en/stable/development/guide/pullrequests.html)

in particular for more information.

Thank you for your interest in PennyLane! 🎆

#### Software tests[¶](#software-tests "Permalink to this headline")

##### Requirements[¶](#requirements "Permalink to this headline")

The PennyLane test suite requires the Python `pytest` package, as well as:

* `pytest-cov`: determines test coverage

* `pytest-mock`: allows replacing components with dummy/mock objects

* `flaky`: manages tests with non-deterministic behaviour

These requirements can be installed via `pip`:

```

pip install pytest pytest-cov pytest-mock flaky

```

##### Creating a test[¶](#creating-a-test "Permalink to this headline")

Every test has to be added to the PennyLane [test folder](https://github.com/PennyLaneAI/pennylane/tree/master/tests).

The test folder follows the structure of the PennyLane module folder. Therefore, tests needs to be added to the corresponding subfolder of the functionality they are testing.

Most tests typically will not require the use of an interface or autodifferentiation framework (such as Autograd, Torch, TensorFlow and Jax). Tests without an interface will be marked

as a `core` test automatically by pytest (the functionality for this is located in `conftest.py`). For such general tests, you can follow the structure of the example below,

where it is recommended that you follow general [pytest guidelines](https://docs.pytest.org/):

```

import pennylane as qml

def test\_circuit\_expval(self):

 """ Test that the circuit expectation value for PauliX is 0."""

    dev = qml.device("default.qubit", wires=1)

    @qml.qnode(dev)

    def circuit():

        return qml.expval(qml.PauliX(0))

    expval = circuit()

    assert expval == 0

```

This test will be marked automatically as a `core` test.

On the other hand, some tests require specific interfaces and need to be marked in order to be run on our Github test suite.

Tests involving interfaces have to be marked with their respective marker:

* `@pytest.mark.autograd`,

* `@pytest.mark.torch`,

* `@pytest.mark.tf`, and

* `@pytest.mark.jax`.

If tests involve multiple interfaces, one should add the marker:

* `@pytest.mark.all\_interfaces`.

Warning

Please do not use `pytest.importorskip` inside your tests. Instead, simply import the autodifferentiation package

as needed inside your marked test. The mark will automatically ensure that the test is skipped if the

autodifferentiation framework is not installed.

Tests that are not marked but do import an interface will lead to a failure in the GitHub test suite.

Below you can find an example for testing a PennyLane template with Jax:

```

def circuit\_template(features):

    qml.AngleEmbedding(features, range(3))

    return qml.expval(qml.PauliZ(0))

def circuit\_decomposed(features):

    qml.RX(features[0], wires=0)

    qml.RX(features[1], wires=1)

    qml.RX(features[2], wires=2)

    return qml.expval(qml.PauliZ(0))

@pytest.mark.jax

def test\_jax(self, tol):

 """Tests the jax interface."""

    import jax

    import jax.numpy as jnp

    features = jnp.array([1.0, 1.0, 1.0])

    dev = qml.device("default.qubit", wires=3)

    circuit = qml.QNode(circuit\_template, dev, interface="jax")

    circuit2 = qml.QNode(circuit\_decomposed, dev, interface="jax")

    res = circuit(features)

    res2 = circuit2(features)

    assert qml.math.allclose(res, res2, atol=tol, rtol=0)

```

Another example of a test involving multiple interfaces is shown below:

```

def circuit(features):

    qml.AngleEmbedding(features, range(3))

    return qml.expval(qml.PauliZ(0))

@pytest.mark.all\_interfaces

def test\_all\_interfaces\_gradient\_agree(self):

 """Test the results are similar between torch and tf"""

    import torch

    import tensorflow as tf

    dev = qml.device("default.qubit", wires=3)

    features\_torch = torch.Tensor([1.0, 1.0, 1.0])

    features\_tf = tf.Variable([1.0, 1.0, 1.0], dtype=tf.float64)

    circuit\_torch = qml.QNode(circuit, dev, interface="torch")

    circuit\_tf = qml.QNode(circuit, dev, interface="tf")

    res\_torch = circuit\_torch(features\_torch)

    res\_tf = circuit\_tf(features\_tf)

    assert np.allclose(res\_torch, res\_tf)

```

##### Running the tests[¶](#running-the-tests "Permalink to this headline")

The [tests](https://github.com/PennyLaneAI/pennylane/tree/master/tests) folder of the root PennyLane directory contains the PennyLane test suite. Run all tests in this folder via:

```

python -m pytest tests

```

Using `python -m` ensures that the tests run with the correct Python version if multiple versions are on the system.

As the entire test suite takes some time, locally running only relevant files speeds up the debugging cycle. For example,

if a developer was adding a new non-parametric operation, they could run:

```

python -m pytest tests/ops/qubit/test_non_parametric_ops.py

```

Using `pytest -m` offers the possibility to select and run tests with specific markers. For example,

if Jax is installed and a developer wants to run only Jax related tests, they could run:

```

python -m pytest tests -m "jax"

```

There exists markers for interfaces (`autograd`, `torch`, `tf`, `jax`), for multiple interfaces (`all\_interfaces`) and

also for certain PennyLane submodules (`qchem` and `qcut`).

For running `qchem` tests, one can run the following:

```

python -m pytest tests -m "qchem"

```

The slowest tests are marked with `slow` and can be deselected by:

```

python -m pytest -m "not slow" tests

```

The `pytest -m` option supports Boolean combinations of markers. It is therefore possible to run both Jax and TensorFlow

tests by writing:

```

python -m pytest -m "jax and tf" tests

```

or Jax tests that are not slow:

```

python -m pytest -m "jax and not slow" tests

```

Pytest supports many other command-line options, which can be found with the command:

```

pytest --help

```

Or by visiting the [pytest documentation](https://docs.pytest.org/en/latest/reference/reference.html#id88) .

PennyLane provides a set of integration tests for all PennyLane plugins and devices. See the documentation on these tests under the section on the [device API](https://pennylane.readthedocs.io/en/latest/code/api/pennylane.devices.tests.html). These tests can be run from the PennyLane root folder by:

```

pytest pennylane/devices/tests --device=default.qubit --shots=1000

```

All PennyLane tests and the device suite on core devices can be run from the PennyLane root folder via:

```

make test

```

##### Testing Matplotlib based code[¶](#testing-matplotlib-based-code "Permalink to this headline")

Matplotlib images can display differently due to various factors outside the standard developer’s control, such as image backend and available fonts. Even though matplotlib provides

[functionality for pointwise comparison of images](https://matplotlib.org/stable/api/testing_api.html#module-matplotlib.testing) , they require caching

correct images in a particular location and are sensitive to details we don’t need to test.

Instead of performing per-pixel comparison of saved images, we can instead inspect the [figure](https://matplotlib.org/stable/api/figure_api.html?highlight=figure#matplotlib.figure.Figure)

and [axes](https://matplotlib.org/stable/api/axes_api.html?highlight=axes#module-matplotlib.axes)

objects to ascertain whether they contain the correct information. The figure should contain the axis object in its `fig.axes` attribute, and the axis object should contain the [Artists](https://matplotlib.org/stable/tutorials/intermediate/artists.html) that get displayed. These artists relevant to us are located in one of three attributes. Each attribute is a list of relevant objects, ordered as they were added:

* `ax.texts`

* `ax.lines`

* `ax.patches`

Instead of testing every relevant piece of information for all objects in the graphic, we can check key pieces of information to make sure everything looks decent. These key pieces of information can include (but are not limited to):

* number of objects

* type of objects

* location

**Text objects**

[Text objects](https://matplotlib.org/stable/api/text_api.html#matplotlib.text.Text)

are stored in `ax.texts`. While the text object has many methods and attributes for relevant information, the two most commonly used in testing text objects are:

* `text\_obj.get\_text()` : Get the string value for the text object

* `text\_obj.get\_position()`: Get the `(x,y)` position of the object

**Lines**

[2D lines](https://matplotlib.org/stable/api/_as_gen/matplotlib.lines.Line2D.html?highlight=line2d#matplotlib.lines.Line2D) are stored in `ax.lines`. PennyLane’s

circuit drawing code uses lines for wires, SWAP gates, and controlled operations. The most important method for checking lines is `line\_obj.get\_data()`. For easier reading, you

can also use `line\_obj.get\_xdata()` and `line\_obj.get\_ydata()`.

**Patches**

[Patches](https://matplotlib.org/stable/api/_as_gen/matplotlib.patches.Patch.html?highlight=patch#matplotlib.patches.Patch)

can be a wide variety of different objects, like:

* [Rectangle](https://matplotlib.org/stable/api/_as_gen/matplotlib.patches.Rectangle.html?highlight=rectangle#matplotlib.patches.Rectangle)

* [Circle](https://matplotlib.org/stable/api/_as_gen/matplotlib.patches.Circle.html?highlight=circle#matplotlib.patches.Circle)

* [Arc](https://matplotlib.org/stable/api/_as_gen/matplotlib.patches.Arc.html?highlight=arc#matplotlib.patches.Arc)

* [Fancy Arrow](https://matplotlib.org/stable/api/_as_gen/matplotlib.patches.FancyArrow.html?highlight=fancyarrow#matplotlib.patches.FancyArrow)

Each can have its own getter methods and attributes. For example, an arc has `theta1` and `theta2`. `dir(patch\_obj)` can help developers determine which methods and attributes a given object has.

For Rectangles, the most relevant methods are:

* `rectangle\_obj.get\_xy()`

* `rectangle\_obj.get\_width()`

* `rectangle\_obj.get\_height()`

#### Documentation[¶](#documentation "Permalink to this headline")

Good documentation is just as important, if not more important, than the code itself.

**No matter how good the code is**, without decent documentation, users are deterred from

using the library, and developers are less likely to contribute.

This document describes the requirements, recommendations, and guides for writing documentation

for PennyLane, as well as details for contributing to and building the PennyLane documentation.

##### Overview[¶](#overview "Permalink to this headline")

The PennyLane documentation consists of three main sections:

The introductory ‘quickstarts’.These are short, referential guides designed to quickly

guide new users around the core functionality of PennyLane, and show available functions and classes.

These are summaries, *not* full-form tutorials; all [code examples are minimal](#code-examples),

and readers should be directed to function/class docstrings for more details.

All introductory quickstarts are in `doc/introduction`, formatted as reStructuredText documents.

Development guides.Similar to the introductory quickstarts, but focused on information

regarding how to contribute to the PennyLane codebase.

Development guides are in `doc/development`, formatted as reStructuredText documents.

The API.Automatically generated from docstrings in the PennyLane source code. Code stubs, one per

module, are placed in `doc/code`. The Sphinx extension

[sphinx-automodapi](https://github.com/astropy/sphinx-automodapi) is then used

to automatically generate API documentation pages for public classes and functions

in `doc/code/api`.

PennyLane displays the API using the **import path**—rather than absolute

path—of the documented code object.

Note

Long-form tutorials, as well as quantum machine learning theory and background information,

is not part of the PennyLane documentation. Instead, this content is available over in the

[XanaduAI/QML](https://github.com/XanaduAI/qml) GitHub repository (viewable at

<https://pennylane.ai/qml>).

##### Punctuation and spelling[¶](#punctuation-and-spelling "Permalink to this headline")

* Use Canadian spellings. That is, “centre” instead of “center”, “realize” instead of “realise”,

“acknowledgement” instead of “acknowledgment”, “colour” instead of “color”, etc.

* Use complete sentences with capitalization and punctuation. The one exemption

is when describing arguments, return values, attributes, and exceptions; sentence fragments

may be used for short descriptions:

```

wires (List[int]): subsystems the operation is applied to

diff_method (str or None): the method of differentiation to use in the created QNode

```

Multi-sentence argument descriptions, or longer sentence fragments with mid-sentence punctuation marks,

should use full capitalization and punctuation:

```

device (Device, Sequence[Device]): Corresponding device(s) where the

    ``QNodeCollection`` should be executed. This can either be a single device, or a list

    of devices of length ``len(observables)``.

```

* Comments may be written more informally than docstrings, as long as consistency and clarity are maintained.

Capitalization and punctuation should be used with multi-sentence comments to aid with readability.

##### Docstrings[¶](#docstrings "Permalink to this headline")

Documentation strings (docstrings) describe the use and functionality of modules, functions,

classes, and variables. Docstrings in PennyLane are enclosed within triple-quotes (`"""`), and are

written using [reStructuredText (ReST)](https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html)

markup, and are formatted [Google-style](https://www.sphinx-doc.org/en/master/usage/extensions/napoleon.html#google-vs-numpy).

Docstrings are a part of Python; an objects’ docstring is stored under the `\_\_doc\_\_`

attribute, and accessible to the user via the `help()` function. In addition, docstrings

are automatically extracted and rendered by Sphinx, and inserted into the

[API](index.html#document-code/qml) section of the documentation.

###### Guiding principles[¶](#guiding-principles "Permalink to this headline")

Below, we list some general guidelines, before discussing required docstring styles and formatting

for various PennyLane objects.

* **Be clear and concise, and avoid redundant information.** Favour clarity over completeness; too

much information can distract from conveying the functionality of the code unit.

Assume the reader has basic domain knowledge, and provide links to internal/external resources

where deemed necessary.

* **Be mindful with ReST markup**. Overly complex formatting can make the content difficult

to read for users viewing the docstring in a terminal/Jupyter environment. Try to also avoid

complex formatting such as tables, which can be difficult to maintain over time.

* **Do not assume the reader can view the accompanying code.** The reader will most likely

be viewing the docstring via the Sphinx-rendered website, or in a terminal/Jupyter environment.

For documenting how the code itself works, favour comments.

* **Cross reference code units where applicable.** Use the roles `:class:`, `:func:`, `:attr:`,

`:meth:`, and `:mod:` where applicable to have Sphinx automatically include a cross-reference

to the specified code object.

For example:

```

The recommended method of creating a QNodeCollection is via :func:`~.map`.

```

Here, `~` instructs Sphinx to display just the object name, as opposed to the full absolute path

of the object (`pennylane.map()`). To use custom text, you may use the syntax

`:func:`map function <~.map>``.

* **Cross reference internal links.** Internal links should *not* use the URL of the built documentation,

this is unmaintainable and URLs might change in the future. If linking to a particular page, always use

`:doc:`relative/path/filename`` or `:doc:`/absolute/path/filename`` instead of `:ref:`. Only

use `:ref:` if linking to a particular subsection, and only when necessary.

###### Modules[¶](#modules "Permalink to this headline")

Every module should begin with the license boilerplate, followed by a module docstring.

The module docstring must contain a short, single sentence summary of the module, followed

by an (optional) multi-line description of the contents and usage.

```

"""

Single sentence that summarizes the module and its contents.

Optional multi-line description. Make sure to focus on functionality first and

foremost, and implementation details or background theory afterwards if required.

"""

```

Warning

Do not manually list the contents of the module; PennyLane uses

[sphinx-automodapi](https://github.com/astropy/sphinx-automodapi) to automatically

create module listings.

###### Functions and methods[¶](#functions-and-methods "Permalink to this headline")

The docstring should provide enough information for the reader to call and use the

function or method without having access to the code.

Most functions or methods should have the following structure:

```

def func(arg1, arg2, arg3="default\_value", \*\*kwargs):

 """Single sentence that summarizes the function.

 Multi-line description of the function (optional, only if necessary).

 Args:

 arg1 (type): Description.

 Continuation line is indented if needed.

 arg2 (type): description

 arg3 (str): Description. Do not provide the default

 value, as this is already present in the signature.

 Keyword Args:

 kwarg1 (type): Description. Provide the default value if applicable.

 Returns:

 type: Description.

 Continuation line is not indented.

 Raises:

 ExceptionType: description

 .. seealso:: :func:`~.relevant\_func`, :class:`~.RelevantClass` (optional)

 \*\*Example\*\*

 Minimal example with 1 or 2 code blocks (required).

 .. details::

 :title: Usage Details

 More complicated use cases, options, and larger code blocks (optional).

 \*\*Related tutorials\*\*

 Links to any relevant PennyLane demos (optional).

 """

```

For predominantly developer-facing functions and methods (e.g., private functions and methods),

the `Example` section is not required. In addition, if the function is very short and its use

is apparent from the signature, it is sufficient for the docstring to simply consist of the single

line summary sentence.

Some notes on the above structure:

* **Function summary:** The summary should provide a brief, basic description of the function. Do not

include the function or argument names in the summary. It is important that the initial summary

be a single sentence; Sphinx will truncate the summary at the first period otherwise.

* **Arguments:** To describe named function arguments in the signature. If the type is a PennyLane class or

function, use the syntax `(~.Operation)`; do **not** use a Sphinx role such as `:class:` or `:func:`.

The level of type description is up to the discretion of the code author and reviewers; acceptable

examples include `(array)`, `(array[float])`, `(dict)`, `(dict[str, int])`, `(Sequence[int] or int)`.

Note that square brakets are used to define the required types of container elements.

*Note:* if the argument has a default value, *do not* include it in the description if it is declared

in the signature. Sphinx will automatically extract the default and render it with the argument

description.

* **Keyword Arguments:** To describe variable length named keyword arguments provided via

`\*\*kwargs`. Provide the default values if relevant.

* **Returns:/Yields:** To describe the return (yielded) value of the function (generator). This may

be omitted if the function signature/summary already sufficiently describe both the return value

and type.

* **See also:** Provide optional links to relevant pages, functions, classes, methods, etc.

* **Example:** To provide a minimal working example showing basic usage of the function. The example

should be *minimal* (reduce line counts where possible), but complete; a reader should be able to

copy and paste the example and get the same output. See [Code examples](#code-examples) for guidelines on writing

useful code examples in docstrings.

* **Usage details:** To provide a more complicated usage details showing different edge cases and

advanced usage of the function, as well as implementation details. This section of the docstring

is *collapsed by default* in the rendered Sphinx documentation to avoid overwhelming the reader with

information, however will be displayed in full to users in the terminal/Jupyter notebooks, so

do not let this section become too long.

###### Classes[¶](#classes "Permalink to this headline")

The class docstring is placed directly below the class definition:

```

class MyClass:

 """Single sentence that summarizes the class.

 Multi-line description of the class (optional, if required).

 Args:

 arg1 (type): Description.

 Continuation line is indented if needed.

 arg2 (type): description

 Keyword Args:

 kwarg1 (type): description

 Attributes:

 attr1 (type): description

 Raises:

 ExceptionType: description

 .. seealso:: :func:`~.relevant\_func`, :class:`~.RelevantClass` (optional)

 \*\*Example\*\*

 Minimal example with 1 or 2 code blocks (required).

 .. details::

 :title: Usage Details

 More complicated use cases, options, and larger code blocks (optional).

 \*\*Related tutorials\*\*

 Links to any relevant PennyLane demos (optional).

 """

```

Docstrings for classes follow a similar structure as functions, with a few differences:

* **Include initialization arguments.** The constructor `\_\_init\_\_()` is documented

here. Note that as the constructor simply returns an instance of the class, no `Returns:`

section is included.

* **Do not list methods and properties.** Class properties and methods will be automatically

listed alongside the class in the generated documentation.

* **List attributes if relevant.**

Document all methods and properties with docstrings below the method declaration,

as you would for functions above. However, there are two

exemptions, where docstrings should *not* be provided:

* **Magic or special methods.** This includes methods such as `\_\_init\_\_`, `\_\_call\_\_`,

`\_\_len\_\_`, `\_\_getitem\_\_`, etc. Only provide docstrings for special methods if

their behaviour is modified in a non-standard way (e.g., if negative indices are allowed

as arguments for `\_\_getitem\_\_`).

* **Overwritten methods.** Overwritten inherited methods automatically inherit the parent methods

docstring, even when overwritten. This is particularly useful when creating an instance

of an abstract base class; the abstract method docstring is defined in the parent, and automatically

inherited by the child class, even when overwritten.

As with special methods, only provide docstrings for overwritten methods if

their behaviour is modified in a non-standard way (as defined in the parent class).

###### Variables[¶](#variables "Permalink to this headline")

Module-level variables may also be optionally documented, by providing a triple-quote docstring

**below** the variable definition. For example,

```

x = {"John": 23, "James": 54}

"""dict[str, int]: stores the ages of known users"""

```

The syntax is the same as those used for describing function arguments.

##### Code examples[¶](#code-examples "Permalink to this headline")

Code examples are very important; they *show* readers how the function or class should be used.

When writing code examples for docstrings, use the following guidelines:

* You may assume that PennyLane is imported as `qml` and NumPy is imported as `np` in the code examples.

All other imports must be specified explicitly.

* For single line statements and associated output, use Python console syntax (`pycon`):

```

>>> circuit(0.5, 0.1)

[0.43241234312, -0.543534534]

```

Multi-line statements should use `...` to indicate continuation lines:

```

>>> dev = qml.device("default.qubit", wires=1)

>>> @qml.qnode(dev)

>>> def circuit(x):

...     qml.RX(x, wires=0)

...     return qml.expval(qml.PauliZ(0))

>>> circuit(0.5)

0.8775825618903726

```

For larger, more complicated code blocks, favour standard Python code-block with

Python console syntax for displaying output:

```

.. code-block:: python3

    dev = qml.device("default.qubit", wires=1)

    @qml.qnode(dev)

    def circuit(x):

        qml.RX(x, wires=0)

        return qml.expval(qml.PauliZ(0))

Executing this circuit:

>>> circuit(0.5)

0.8775825618903726

```

##### Commenting code[¶](#commenting-code "Permalink to this headline")

While docstrings describe *what* a function or class does, or how it is used, **comments**

are used to document the underlying implementation. Use comments where applicable to make

your code easy to follow and understand, keeping to the following guidelines.

* **Use comments to explain the implementation or algorithm, never to describe the code.**

Assume the reader has basic understanding of common programming principles and syntax.

Do not assume the reader knows what you’re trying to do with it!

Note

If additional implementation details have been requested by reviewers during code review,

these must be incorporated as code comments.

* **Code should be self-documented where possible.** Code should be clear and concise,

with the logical flow easily followed by the reader. This can be done by using common

programming patterns alongside sensible variable and function names.

Note that this does not exclude the use of code comments; comments are particularly valuable

in quantum software, where the underlying algorithm can be highly non-trivial. Rather,

self-documented code simply excludes *unnecessary* comments.

* **Comments should be as close to the described code as possible.** These can either be

single- or multi-line comments *above* the described code block,

```

# Note: in the following template definition, we pass the observable, measurement,

# and wires as \*default arguments\* to named parameters. This is to avoid

# Python's late binding closure behaviour

# (see https://docs.python-guide.org/writing/gotchas/#late-binding-closures)

def circuit(params, \_obs=obs, \_m=m, \_wires=wires, \*\*kwargs):

    template(params, wires=\_wires, \*\*kwargs)

    return MEASURE\_MAP[\_m](\_obs)

```

or, for shorter comments, single line comments at the end of the line.

* **Avoid markup and complex formatting in comments.** Markup, such as text formatting and

hyperlink markup, are unnecessary in comments as they are not rendered, and will simply

be read in plain text. Use text formatting sparingly for emphasis, and simply insert URLs

directly. In addition, avoid complex formatting such as tables—these are difficult

to maintain and modify.

##### Contributing documentation[¶](#contributing-documentation "Permalink to this headline")

Contributions to the PennyLane documentation are encouraged; to contribute to the introductory

quickstarts or developer guides, simply make a [pull request on GitHub](index.html#document-development/guide/pullrequests).

If you are making a contribution to the PennyLane source code, **all new and modified

functions and code must be clearly commented and documented**. See below for guidelines

on code docstrings, as well as how to add a new module or package to the API documentation.

In addition, specific additions to the code base must also be reflected in the

introductory quickstarts:

* **Operations**: new operations should be added to the [Quantum operators](index.html#document-introduction/operations) quickstart

located at `doc/introduction/operations.rst`. For more details, see [Adding new operators](index.html#document-development/adding_operators).

* **Templates**: new templates should be added to the [Templates](index.html#document-introduction/templates) quickstart,

located at `doc/introduction/templates.rst`. For more details, see [Adding new operators](index.html#document-development/adding_operators).

* **Optimizers**: new optimizers should be added to the relevant quickstart section

in [Gradients and training](index.html#document-introduction/interfaces), located at `doc/introduction/interfaces.rst`.

* **Measurement**: new measurement functions should be added to the [Measurements](index.html#document-introduction/measurements) quickstart,

located at `doc/introduction/measurements.rst`.

* **Interfaces**: new interfaces should include a quickstart guide in the `introduction/interfaces`

directory, with a link and table of contents entry added to the `introduction/interfaces.rst` page.

Finally, any underlying logic change, new feature, or UI change to the core PennyLane QNode interface

should be reflected on the [Quantum circuits](index.html#document-introduction/circuits) quickstart, located at

`doc/introduction/circuits.rst`.

###### Adding a new module to the docs[¶](#adding-a-new-module-to-the-docs "Permalink to this headline")

There are several steps to adding a new module to the documentation:

1. Make sure your module has a one- to two-line module docstring, that summarizes

what the module purpose is, and what it contains.

2. Add a file `doc/code/qml\_module\_name.rst`, that contains the following:

```

qml.module\_name

===============

.. currentmodule:: pennylane.module_name

.. automodapi:: pennylane.module_name

    :no-heading:

    :include-all-objects:

    :skip: <Place objects that shouldn't be documented here>

```

3. Add `code/qml\_module\_name` to the table of contents at the bottom of `doc/index.rst`.

###### Adding a new package to the docs[¶](#adding-a-new-package-to-the-docs "Permalink to this headline")

Adding a new subpackage to the documentation requires a slightly different process than

a module:

1. Make sure your package `\_\_init\_\_.py` file has a one- to two-line module docstring,

that summarizes what the package purpose is, and what it contains.

2. At the bottom of the `\_\_init\_\_.py` docstring, add an autosummary table that contains

all modules in your package:

```

.. currentmodule:: pennylane.package_name

.. autosummary::

   :toctree: api

   module1

   module2

```

All modules should also contain a module docstring that summarizes the module.

3. Add a file `doc/code/qml\_package\_name.rst`, that contains the following:

```

qml.package\_name

================

.. rubric:: Modules

.. automodule:: pennylane.package_name

```

4. Add `code/qml\_package\_name` to the table of contents at the bottom of `doc/index.rst`.

##### Building the documentation[¶](#building-the-documentation "Permalink to this headline")

To build the documentation, in addition to the standard PennyLane dependencies,

the following additional packages are required:

* [Sphinx](http://sphinx-doc.org/) == 2.2.2

* [sphinx-automodapi](https://github.com/astropy/sphinx-automodapi)

* [pygments-github-lexers](https://github.com/liluo/pygments-github-lexers)

* [m2r](https://github.com/miyakogi/m2r)

* [sphinx-copybutton](https://github.com/ExecutableBookProject/sphinx-copybutton)

In addition, some pages in the documentation have additional dependencies:

* The latest version of PyTorch and TensorFlow are required to build the interface documentation,

* The latest version of TensorNetwork is required to build the `default.tensor` documentation.

These can all be installed via `pip`:

```

$ pip install -r doc/requirements.txt

```

To build the HTML documentation, go to the top-level directory and run

```

make docs

```

The documentation can then be found in the `doc/\_build/html/` directory.

Note

To build the interfaces documentation, PyTorch and TensorFlow will need to

be installed, see [Interface dependencies](index.html#install-interfaces).

Note

If you are running Python3.8 on an M1 Mac you need to set the following environment variables

before installing the requirements to be able to install the grpcio package required by TensorFlow

(see thread <https://github.com/grpc/grpc/issues/25082#issuecomment-778392661>):

```

export GRPC\_PYTHON\_BUILD\_SYSTEM\_OPENSSL=1

export GRPC\_PYTHON\_BUILD\_SYSTEM\_ZLIB=1

```

#### Submitting a pull request[¶](#submitting-a-pull-request "Permalink to this headline")

##### Creating a Pull Request[¶](#creating-a-pull-request "Permalink to this headline")

When you are ready, go ahead and click on “New Pull Request” on the

[pull request page](https://github.com/PennyLaneAI/pennylane/pulls). On the next page, you need

to select your fork and branch to merge into the PennyLane master branch.

On the page for creating a new pull request, you need to specify the name of the PR and write an

introductory description. We have a PR template with a checklist that can help

you determine what to say. Please be as detailed as possible, and assume the reader does not have extensive background knowledge of the issue at hand.

If the PR is in response to an Issue, please

[link the issue](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue)

with the relevant keywords. One simple way is adding a related sentence to the PR description, e.g.

“Closes #ABCD” where ABCD is the number of the PR.

You can make a “Work in Progress” PR with `[WIP]` in the title or with the “WIP” label.

That way, we can see your work and give feedback early.

Once you create the PR, you can also view the status of the *Continuous Integration* (CI) checks

for things like tests, code quality, and documentation rendering.

##### Continuous Integration Checks[¶](#continuous-integration-checks "Permalink to this headline")

Once a PR is opened on the repository, GitHub runs a series of checks on the

branch. All tests need to pass (green check) for the PR to get approved and

merged.

* **Formatting check**: We use [black](https://black.readthedocs.io/en/stable/) to autoformat our

code to [PEP8](https://www.python.org/dev/peps/pep-0008/) standards. You should run `black`

locally on changed files, as the CI check determines whether `black` would change

anything. Black installs with `pip`. We run black on both the source folder `pennylane` and

the `tests` folder. We format with a line length of 100. From the PennyLane’s root folder, you

can run:

```

black -l 100 pennylane tests

```

* **Code factor**: [Code factor](https://www.codefactor.io/) checks several common code quality

characteristics.

To make sure that the formatting and the quality of the new piece of code is up

to [PEP8](https://www.python.org/dev/peps/pep-0008/) dedicated tools

(`black` and `pylint`) should be run locally.

The PennyLane repository provides top-level files (`.pre-commit-config.yaml`

and a `pyproject.toml`) for configuring [pre-commit](https://pre-commit.com/) to run `black` and `pylint` as a `git`

pre-commit hook. Once configured, issuing `git commit` will run the tools

automatically. If any of the checks fail, committing fails too. A failed

`black` check will reformat the required files. Running the pre-commit hook

mechanisms can be disabled for a commit by passing the `-n/--no-verify`

option.

The `pre-commit` package can be installed e.g., via `pip`:

```

pip install pre-commit

```

Then, it can be installed for a specific repository by running

```

pre-commit install

```

in the folder where the `.pre-commit-config.yaml` file exists (the top-level

folder for PennyLane).

Note

The `.pre-commit-config.yaml` file pins `black` to a specific version.

As new versions of `black` are released, developers will have to run

`pre-commit autoupdate` to update the package versions used by

`pre-commit`.

* **Tests**: Github Actions runs the core tests and device tests for a series of different Python

versions and interface installations.

* **Code Coverage**: [codecov](https://app.codecov.io/gh/PennyLaneAI/pennylane/) determines if

all lines are executed during the automated testing and tells you which ones are not. We want all

lines to be covered, but that is insufficient to determine if the testing is complete enough.

That takes thought and thinking through the test design to ensure that all edge cases are being

tested.

* **Documentation**: The “Documentation check” determines if there are any issues with the build,

but you also need to inspect the relevant pages in the website build visually. You can access the

temporary website by clicking on `Details` for `docs/readthedocs.org:pennylane`, as shown in

the following image.

[![_images/view_doc_build.jpeg](_images/view_doc_build.jpeg)](_images/view_doc_build.jpeg)

Using the “Search” toolbar on the top left of the generated website can help with navigating to new

or updated pages. New functions or classes that are available for users should appear as

search results.

Note that including `skip ci` (or a similar string) will mark a `git commit`

such that [CI checks are being skipped](https://docs.github.com/en/actions/managing-workflow-runs/skipping-workflow-runs).

##### Ready for review?[¶](#ready-for-review "Permalink to this headline")

A review-ready pull request (PR) includes the following:

* **All new code is clearly commented and documented.** See our [documentation guidelines](index.html#document-development/guide/documentation) for more details.

* **All changes must include tests.** If you fix a bug, write a test that would fail before the

bugfix. See [Tests](index.html#document-development/guide/tests) for more information.

* **Code conforms to PEP8 standards.** As mentioned in the section above, all code needs to be

formatted via [Black](https://black.readthedocs.io/en/stable/) with a line length of 100.

* **Write a changelog entry for all Pull Requests.** The changelog entry should include a link back

to the PR. More significant user-facing changes should include a code example. In addition to the changelog entry itself, add your name to the alphabetical contributors’ list at the bottom of

each release’s section. The changelog is located at doc/releases/changelog-dev.md.

Please note that our review process can take some time and require a bit of back and forth. We try

to enforce a high level of detail in reviews to reduce future bugs and prevent technical debt from

accruing. You can speed the review process by keeping pull requests small and fully explaining

decisions in the pull request introduction.

#### Architecture Design Records[¶](#architecture-design-records "Permalink to this headline")

Any significant design decision in PennyLane must first be discussed and agreed to by the

core development team before implementation begins. This is done by drafting an

[Architectural Design Record (ADR)](https://github.com/joelparkerhenderson/architecture_decision_record),

which details the **context** behind the proposal, potential solutions, and any

consequences should the ADR be accepted.

This document describes the requirements and recommendations for PennyLane ADRs.

##### When to write an ADR[¶](#when-to-write-an-adr "Permalink to this headline")

Not all contributions and modifications of the PennyLane source code requires an ADR.

Bug fixes and minor modifications can usually proceed directly to a pull request. Further,

straightforward modifications, where no major architectural or user interface decisions need

to be made—such as adding a new template or optimizer—can usually proceed directly

to a pull request.

On the other hand, the following changes typically require an ADR proposal:

* Changes to the user interface

* Changes to the device or plugin API

* Changes that affect multiple core components of the library

* New features that require decisions as to source code location and user interface

* Structural changes to the source code, documentation, or tests

If you are unsure if a change requires an ADR proposal or not, please open a

[GitHub issue](https://github.com/PennyLaneAI/pennylane/issues) or post in the

[discussion forum](https://discuss.pennylane.ai) to discuss it with the PennyLane

development team.

##### What to include in a PennyLane ADR[¶](#what-to-include-in-a-pennylane-adr "Permalink to this headline")

The ADR is a Markdown or reStructuredText document that outlines:

* The context behind this design discussion,

* Analysis of potential options, pros/cons of each approach, and any implementation ‘gotchas’ that

might arise, and

* A summary of the decision and an outline of the required work package.

The ADR must have the following components:

**Title**The title should directly reflect the decision made by the ADR.

The title should be 50 characters or less, reflect the final decision, and be written in present

tense imperative form. For example, “Move common plugin utilities to PennyLane core”, or “Add a

high-level `qnn` module to PennyLane”.

**Status**This acts as a *record* of status updates for the ADR.

Statuses should be one of: ‘Proposed’, ‘Accepted’, ‘Rejected’, ‘Deprecated’, ‘Superseded’, or

‘Amended’. When the status changes, leave the old status and create a new entry for the new

status, so that we have a log of when changes were made.

**Context**Background information, alongside any other general organizational or

architectural needs, that allows readers to place the ADR in context.

The context section should provide sufficient information such that readers of the ADR understand

the problem the ADR is addressing, and *why* the ADR is required. This section can include

code/pseudo-code snippets, diagrams, and images if relevant.

**Analysis**The outcome of any research undertaken to make the decision.

This should include an overview of all possible alternatives, potential risks and downsides,

assumptions that have been made, and all implications. As with the context section, this section

can include code/pseudo-code snippets, diagrams, and images if relevant.

**Decision**Outlines the final decision(s), in present-tense imperative form.

The decision section should also include:

* A summary of the resulting work package. This is typically a bullet-point list,

with each item corresponding to a task such as a pull request or follow-on ADR.

Care should be taken such that the work package is sufficiently broken down; a series

of smaller, self-contained pull requests should be favoured over fewer, larger pull requests.

* Additional or further questions. An ADR may be accepted with some open questions, as long as

their resolution is (a) not a short-term priority, or (b) must be informed by the upcoming

implementation. These questions, and any missing information, should be recorded here.

In addition, the following *optional* sections may be included:

* A **review** section, where notes can be made *after* the decision has been implemented for a

record of the actual outcome and effect the decision has had.

* A **further reading** section where links can be posted to relevant external documentation,

articles, etc.

##### Further reading[¶](#further-reading "Permalink to this headline")

* [Documenting Architecture Decisions blog post by Fabian Keller](https://www.fabian-keller.de/blog/documenting-architecture-decisions/)

* [Joel Parker Henderson: Architecture Decision Record](https://github.com/joelparkerhenderson/architecture_decision_record)

* [ADR links and tooling](https://adr.github.io/)

#### Architectural overview[¶](#architectural-overview "Permalink to this headline")

PennyLane’s core feature is the ability to compute gradients of variational

quantum circuits in a way that is compatible with classical techniques such as

backpropagation. PennyLane thus extends the automatic differentiation

algorithms common in optimization and machine learning to include quantum and

[hybrid computations](https://pennylane.ai/qml/glossary/hybrid_computation.html "(in PennyLane)").

A plugin system makes the framework compatible with many quantum

simulators or hardware devices, remote or local.

This architectural overview introduces the basic building blocks and terminology

used by PennyLane.

##### Components[¶](#components "Permalink to this headline")

The central object in PennyLane is a **QNode**, which represents a

“node” performing a quantum computation. Several quantum nodes may be

part of a larger hybrid quantum-classical computation.

QNodes run **quantum circuits** on **devices**.

The devices may be simulators built into PennyLane, or external devices

provided by plugins.

The quantum circuit is specified by defining a **quantum function**,

which is a Python function that contains quantum operations and measurements

represented by the [`Operator`](index.html#pennylane.operation.Operator "pennylane.operation.Operator") and [`MeasurementProcess`](index.html#pennylane.measurements.MeasurementProcess "pennylane.measurements.MeasurementProcess") classes,

respectively.

Internally, the quantum function is used to construct one or more

**quantum tapes**. A quantum tape is a context manager that records a queue of

instructions required to run a quantum circuit.

  

[![_images/pl_overview.png](_images/pl_overview.png)](_images/pl_overview.png)

  

The power of a QNode lies in the fact that it can be run in a “forward” fashion to

execute the quantum circuit, or in a “backward” fashion in which it provides

gradients (or, more precisely, *jacobian-vector products*).

Let’s go through these components one-by-one, this time from the “inside out” of the

schematic drawing above.

###### Operator[¶](#operator "Permalink to this headline")

Quantum operators are represented by the [`Operator`](index.html#pennylane.operation.Operator "pennylane.operation.Operator") class.

Operators are uniquely defined by their **name**, their (trainable) **parameters**,

their (non-trainable) **hyperparameters**, and the **wires** they act on. Note that the

trainable parameters can be tensors of any supported autodifferentiation framework.

These four defining properties are accessible for all [`Operator`](index.html#pennylane.operation.Operator "pennylane.operation.Operator") instances:

```

>>> from jax import numpy as jnp

>>> op = qml.Rot(jnp.array(0.1), jnp.array(0.2), jnp.array(0.3), wires=["a"])

```

```

>>> op.name

Rot

>>> op.parameters

[Array(0.1, dtype=float32, weak\_type=True),

 Array(0.2, dtype=float32, weak\_type=True),

 Array(0.3, dtype=float32, weak\_type=True)]

>>> op.hyperparameters

{}

>>> op.wires

<Wires = ['a']>

```

Operators can optionally define the transformation they implement via

symbolic or numerical representations. Here are two examples, and you find more

details in the documentation on [adding operations](index.html#document-development/adding_operators):

* Representation as a product of operators

```

>>> op = qml.Rot(0.1, 0.2, 0.3, wires=["a"])

>>> op.decomposition()

[RZ(0.1, wires=['a']), RY(0.2, wires=['a']), RZ(0.3, wires=['a'])]

```

* Representation as a matrix

```

>>> op = qml.PauliRot(0.2, "X", wires=["b"])

>>> op.matrix()

[[9.95004177e-01-2.25761781e-18j 2.72169462e-17-9.98334214e-02j]

 [2.72169462e-17-9.98334214e-02j 9.95004177e-01-2.25761781e-18j]]

```

Devices query operators for their properties and representations to

gain information on how to implement the operator.

###### MeasurementProcess[¶](#measurementprocess "Permalink to this headline")

While the [`Operator`](index.html#pennylane.operation.Operator "pennylane.operation.Operator") class describes a physical system and its dynamics,

the `pennylane.measurement.MeasurementProcess` class describes how we extract information from the quantum system.

Each measurement in pennylane has a specific class that inherits from `pennylane.measurement.MeasurementProcess`.

The measurement functions such as [`expval()`](index.html#pennylane.expval "pennylane.expval") create an instance of its corresponding

class ([`pennylane.measurements.ExpectationMP`](index.html#pennylane.measurements.ExpectationMP "pennylane.measurements.ExpectationMP")).

```

>>> m = qml.expval(qml.PauliZ("a"))

>>> type(m)

<class 'pennylane.measurements.expval.ExpectationMP'>

```

An instance of the [`MeasurementProcess`](index.html#pennylane.measurements.MeasurementProcess "pennylane.measurements.MeasurementProcess") class specifies the measured observables,

which are themselves operators.

```

>>> m.obs

PauliZ(wires=['a'])

```

Furthermore, it specifies a “return type” which defines the kind of measurement performed,

such as expectation, variance, probability, state, or sample.

```

>>> m.return\_type

ObservableReturnTypes.Expectation

```

For more information, check out the documentation on [measurements](index.html#document-introduction/measurements)

###### QuantumTape[¶](#quantumtape "Permalink to this headline")

Quantum operators and measurement processes can be used to build a quantum circuit.

The user defines the circuit by constructing a quantum function, such as:

```

def qfunc(params):

    qml.RX(params[0], wires='b')

    qml.CNOT(wires=['a', 'b'])

    qml.RY(params[1], wires='a')

    return qml.expval(qml.PauliZ(wires='b'))

```

Internally, a quantum function is translated to a quantum tape, which is

the central representation of a quantum circuit. The tape is a context manager that stores lists

of [`Operator`](index.html#pennylane.operation.Operator "pennylane.operation.Operator") and `MeasurementProcesses` instances.

If we call the quantum function in a tape context, the

gates are stored in the tape’s `operation` property, while the

measurement functions such as [`expval()`](index.html#pennylane.expval "pennylane.expval") are responsible for adding measurement processes

to the tape’s `measurement` property.

```

>>> with qml.tape.QuantumTape() as tape:

...         qfunc(params)

```

```

>>> tape.operations

[RX(Array(0.5, dtype=float32), wires=['b']),

 CNOT(wires=['a', 'b']),

 RY(Array(0.2, dtype=float32), wires=['a'])]

```

```

>>> tape.measurements

[expval(PauliZ(wires=['b']))]

```

These two “queues” are used by devices to get information on the circuit they

have to run.

Note

Tapes can represent parts of quantum circuits and do not necessarily need to define a measurement.

They can also be nested.

###### Devices[¶](#devices "Permalink to this headline")

In PennyLane, the abstraction of a quantum computation device is encompassed

within the [`pennylane.Device`](index.html#pennylane.Device "pennylane.Device") class. The main job of devices is to

interpret and execute tapes. The most important method is `batch\_execute`,

which executes a list of tapes, such as a list of the single tape created above:

```

>>> device = qml.device("default.qubit", wires=['a', 'b'], shots=None)

>>> device.batch\_execute([tape])

[array([0.87758256])]

```

There are also device subclasses available, containing shared logic for

particular types of devices. For example, qubit-based devices can inherit from

the [`QubitDevice`](index.html#pennylane.QubitDevice "pennylane.QubitDevice") class, easing development.

To register a new device with PennyLane, a device subclass has to be created and registered

as an [entry point](https://packaging.python.org/specifications/entry-points/) under the `pennylane.plugins`

namespace using Setuptools. Once registered, the device can be instantiated using the [`device()`](index.html#pennylane.device "pennylane.device")

loader function, using the device’s name.

A Python package that registers one or more PennyLane devices is known as a *plugin*. For more details

on plugins and devices, see [Building a plugin](index.html#document-development/plugins).

###### QNodes[¶](#qnodes "Permalink to this headline")

This is where it all comes together: A **QNode** is an encapsulation of a function

\(f(x;\theta)=R^m\rightarrow R^n\) that is executed using quantum

information processing on a quantum device. It is created by a quantum function and a device.

```

>>> import jax

>>> from jax import numpy as jnp

>>> params = jnp.array([0.5, 0.2])

```

```

>>> qnode = qml.QNode(qfunc, device, interface='jax')

>>> qnode(params)

0.8776

```

```

>>> qnode\_drawer = qml.draw(qnode)

>>> print(qnode\_drawer(params))

a: ───────────╭●──RY(0.20)─┤

b: ──RX(0.50)─╰X───────────┤ <Z>

```

Note

Users don’t typically instantiate QNodes directly—instead, the [`qnode()`](index.html#pennylane.qnode "pennylane.qnode") decorator or

[`QNode()`](index.html#pennylane.QNode "pennylane.QNode") constructor function automates the process of creating a QNode from a provided

quantum function and device.

Internally, the QNode translates the quantum function into one or more quantum tapes

and classical processing routines that, taken together, execute the quantum computation.

The crucial property of a QNode is that it is differentiable by classical autodifferentiation

frameworks such as autograd, jax, TensorFlow and PyTorch.

```

>>> jax.grad(qnode)

[-0.4794 0.]

```

##### Workflow[¶](#workflow "Permalink to this headline")

Autodifferentiation frameworks may run QNodes in “forward mode”

to compute the result of a quantum circuit, or in “backward mode” to compute

the gradient of a qnode with respect to some trainable parameters.

The internal workflow in the QNode is surprisingly similar in both cases, and

consists of three steps: to construct one or more tapes using the quantum function,

to run the tapes on the device, and to post-process the results. The classical processing of this pipeline

maintains differentiability, so that we can not only compute the result, but the gradient of the result

with respect to the trainable parameters.

  

[![_images/pl_workflow.png](_images/pl_workflow.png)](_images/pl_workflow.png)

  

The fact that multiple tapes can be constructed from one quantum function may be

surprising at first, but there are many situations in which the evaluation of a quantum circuit

practically requires many circuits to be evaluated, for example:

* When the observable is a Hamiltonian represented as a linear combination of Pauli words, the device may

instruct the QNode to create one circuit for each Pauli word, and to compute their linear combination

during post-processing.

* When a gradient of the QNode is requested, and parameter-shift rules have to be used, the QNode

constructs tapes in which parameters are shifted, and recombines the result to return a gradient.

###### Interfaces[¶](#interfaces "Permalink to this headline")

The construction of tapes, as well as post-processing the results from executing tapes,

are classical computations, and they are “tracked” by the autodifferentiation framework.

In other words, these steps can invoke differentiable classical computations, such as:

* Computing gate parameters of a compiled circuit, which are functions of the original gate parameters.

* Computing linear combinations of expectations, for example when evaluating Hamiltonians term-by-term.

There are some devices where the execution of the quantum circuit is also tracked by the

autodifferentiation framework. This is possible if the device is a simulator that is

coded entirely in the framework’s language (such as a TensorFlow quantum simulator).

  

[![_images/pl_backprop_device.png](_images/pl_backprop_device.png)](_images/pl_backprop_device.png)

  

Most devices, however, are blackboxes with regards to the autodifferentiation framework.

This means that when the execution on the device begins, autograd, jax, PyTorch and TensorFlow

tensors need to be converted to formats that the device understands - which is in most cases

a representation as Numpy arrays. Likewise, the results of the execution have to be translated

back to differentiable tensors. These two conversions happen at what PennyLane calls the

“interface”, and you can specify this interface in the QNode with the `interface` keyword argument.

#### Logging development guidelines[¶](#logging-development-guidelines "Permalink to this headline")

##### Enabling logging[¶](#enabling-logging "Permalink to this headline")

To enable logging support in your PennyLane work-flow simply run the following lines:

```

import pennylane as qml

qml.logging.enable\_logging()

```

This will ensure all levels of the execution pipeline log function entries and

outputs. These are logged to handlers pointing to the standard output. Note, since Python’s logging framework configuration functions overwrite previous logger configurations, it is expected that [`enable\_logging()`](index.html#pennylane.logging.enable_logging "pennylane.logging.enable_logging") is called only when not using external logging configurations.

If you are defining custom logging configurations, you can extend the logging configuration options as defined in the section [Customizing the logging configuration](logging-config), or avoid calling [`enable\_logging()`](index.html#pennylane.logging.enable_logging "pennylane.logging.enable_logging") in favour of tour custom configuration options.

##### Adding logging supports during development[¶](#adding-logging-supports-during-development "Permalink to this headline")

To add logging support to components of PennyLane, we must define a module logger and ensure all scoped log statements use that logger. A logger can be imported and defined with:

```

import logging

logger = logging.getLogger(\_\_name\_\_)

```

which will be used within the given module, and track directories,

filenames and function names, as we have defined the appropriate types

within the formatter configuration (see [`pennylane.logging.DefaultFormatter`](index.html#pennylane.logging.DefaultFormatter "pennylane.logging.DefaultFormatter")). With the logger defined, we can selectively add to the logger by if-else statements, which compare the given module’s log-level to any log record

message it receives. This step is not necessary, as the message will

only output if the level is enabled, though if an expensive function

call is required to build the string for the log-message, it can be

faster to perform this check:

```

if logger.isEnabledFor(logging.DEBUG):

    logger.debug(

 """Entry with args=(arg\_name\_1=%s, arg\_name\_2=%s, ..., arg\_name\_n=%s)""",

        arg\_name\_1, arg\_name\_2, ..., arg\_name\_n,

    )

```

The above line can be added below the function/method entry point,

and the provided arguments can be used to populate the log message. This

allows us a way to track the inputs and calls through the stack in the

order they are executed, as is the basis for following a trail of

execution as needed.

All debug log-statements currently added to the PennyLane execution

pipeline output log level messages with the originating function making

that call, as this can allow us to track hard-to-find bug origins in the

execution pipeline.

##### Customizing the logging configuration[¶](#logging-config "Permalink to this headline")

As with any package that targets many domains, Python’s logging is as

extensible and flexible as it is a challenge to configure for all user needs

– ideally we define some good defaults that meet our development goals,

and only deviate from them if required. For further details and customization

options, consider reading the Python logging documentation

[how-to](https://docs.python.org/3/howto/logging.html#python%20logging)

and [“advanced”

tutorial](https://docs.python.org/3/howto/logging.html#logging-advanced-tutorial)

level.

PennyLane logging defaults are contained in a configuration file in the logging module titled

`log\_config.toml`, which is imported when logging is enabled.

The file path can be accessed with `qml.logging.config\_path()`. To change log-levels that are

reporting on a package or module-wide basis, it is possible to do so by

modifying the entries in the `log\_config.toml` file, under the `[loggers]`

section. In addition, if we want to send the logs elsewhere, we can

adjust the `[handlers]` section, which controls what happens to each

message. If we do not like the output format of the messages, we can

adjust these through the `[formatters]` section. If we want to filter

messages based on some criteria, we can add these to the respective

handlers. As an example, we can go through the configuration file and

explore the options.

###### Modifying the configuration options[¶](#modifying-the-configuration-options "Permalink to this headline")

To allow for good expressivity when requiring logging, we must often

adjust several parts of the ecosystem to ensure messages are formatted a

certain way, we control logging internally to PennyLane different to

external packages, messages are sent to somewhere we can make them

actionable, and we can remove messages that are not needed based on some

criteria of interest. Let’s break the `log\_config.toml` file into

sections to discuss how these can be adjusted to suit needs:

```

###############################################################################

# Avoid interfering with existing loggers in dependent libraries

###############################################################################

disable\_existing\_loggers = false

version = 1

###############################################################################

# Bind formatters defined locally and those defined in pennylane.logging

###############################################################################

[formatters]

[formatters.qml\_default\_formatter]

"()" = "pennylane.logging.formatters.formatter.DefaultFormatter"

[formatters.qml\_alt\_formatter]

"()" = "pennylane.logging.formatters.formatter.AnotherLogFormatter"

[formatters.local\_detailed]

format = "\u001B[38;2;45;145;210m[%(asctime)s][%(levelname)s][<PID %(process)d:%(processName)s>] - %(name)s.%(funcName)s()::\"%(message)s\"\u001B[0m"

[formatters.local\_standard]

format = "[%(asctime)s] - %(name)s - %(levelname)s - %(message)s"

```

The first sections of the configuration file tell the logging

infrastructure to avoid modification to existing log settings — this is

set to `true` by default for backwards compatibility, though can be

problematic if using external packages. It is recommended to keep this

as `false` unless required otherwise.

```

###############################################################################

# Bind LogRecord filters defined in pennylane.logging module

###############################################################################

[filters]

# Filter to show messages from the same local process as the Python script

[filters.qml\_LocalProcessFilter]

"()" = "pennylane.logging.filter.LocalProcessFilter"

# Filter to show debug level messages only

[filters.qml\_DebugOnlyFilter]

"()" = "pennylane.logging.filter.DebugOnlyFilter"

```

The above section defines how to filter log messages (known as

`LogRecords`), given some predicate. In this case, we have defined

some classes, `LocalProcessFilter` and `DebugOnlyFilter` to filter

based on process ID and on the severity of the incoming message. These

can be used in the next section.

```

###############################################################################

# Bind handlers defined in the logging and in pennylane.logging modules

###############################################################################

[handlers]

[handlers.qml\_debug\_stream]

class = "logging.StreamHandler"

formatter = "qml\_default\_formatter"

level = "DEBUG"

stream = "ext://sys.stdout"

[handlers.qml\_debug\_stream\_alt]

class = "logging.StreamHandler"

formatter = "qml\_alt\_formatter"

level = "DEBUG"

stream = "ext://sys.stdout"

[handlers.qml\_debug\_file]

class = "logging.handlers.RotatingFileHandler"

formatter = "local\_standard"

level = "DEBUG"

filename ='qml\_debug.log' # use `/tmp/filename.log` on Linux machines to avoid long-term persistence

maxBytes = 16777216 # 16MB per file before splitting

backupCount = 10 # Create 'qml\_debug.log.1', ... 'qml\_debug.log.backupCount' files and rollover when maxBytes is reached

[handlers.local\_filtered\_detailed\_stdout]

class = "logging.StreamHandler"

formatter = "local\_standard"

level = "DEBUG"

stream = "ext://sys.stdout"

filters = ["qml\_LocalProcessFilter", "qml\_DebugOnlyFilter"]

```

The above defines how `LogRecord` messages are handled, and directs

them to the appropriate sink. The logging framework supports many such

directions (see

[here](https://docs.python.org/3/library/logging.handlers.html) for

more info), but for this example we have defined stream handlers

(printing to the screen via the standard output), and a file handler

with a size cap at 16MB. Each handler can be customized by filters and

formatters so that the consumed message fits the needs of the user.

```

###############################################################################

# Define logger controls for internal and external packages

###############################################################################

[loggers]

# Control JAX logging

[loggers.jax]

handlers = ["qml\_debug\_stream",]

level = "WARN"

propagate = false

# Control logging across pennylane

[loggers.pennylane]

handlers = ["qml\_debug\_stream",]

level = "DEBUG" # Set to TRACE for highest verbosity

propagate = false

# Control logging specifically in the pennylane.qnode module

# Note the required quotes to overcome TOML nesting issues

[loggers."pennylane.qnode"]

handlers = ["qml\_debug\_stream\_alt",]

level = "DEBUG" # Set to TRACE for highest verbosity

propagate = false

###############################################################################

```

Finally, the `loggers` section which controls the individual loggers

across the packages we are using. Python’s logging framework follows a

parent-child hierarchy, where a logging configuration set at a parent

level will set all child levels with the same features. In this

instance, we have configured JAX, PennyLane and our script to all log

into the `qml\_debug\_stream` handler we defined earlier, and modified

the child logger `"pennylane.qnode"` (quotes needed due to TOML

parsing limitations) to use a different logger, in this case

`qml\_debug\_stream\_alt`. We are free to define the module/package

log-level here (we opt for `DEBUG` for all), and to also use multiple

handlers per logger (such as for logging to the standard output and

files through `qml\_debug\_stream` and `qml\_debug\_file`

simultaneously). Given the complexity explosion with configuring these

options, the default features in `log\_config.toml` all use the same

log-level, and handler, which can be adjusted based on developer needs.

##### Logging example with PennyLane and JAX’s JIT support[¶](#logging-example-with-pennylane-and-jaxs-jit-support "Permalink to this headline")

As mentioned above, we have added execution function entry logging

supports, including some supports for each target interface. We can

examine this support for both internal and external packages, where we

enable logs for JAX, which has support for Python-native log messages.

To enable logging specifically for JAX, we can modify the `level`

parameter for the `[loggers.jax]` entry in the `log\_config.toml`

file as:

```

[loggers.jax]

handlers = ["qml\_debug\_stream"]

level = "DEBUG"

propagate = false

```

where `handlers` represents some arbitrary custom class we define to

deal with the message, `level` the associated level we want that

package to log at, and `propagate` tells the logger to keep the

message at the given handler level, or also to throw it up to the parent logger

interface — all of these are adhering to the logging API. We convert the

highest supported log level from warning (less verbose) to debug (more

verbose). We can at the same time change the PennyLane logging level to

warnings and more severe, by making the following change:

```

[loggers.pennylane]

handlers = ["qml\_debug\_stream"]

level = "WARN"

propagate = false

```

Running the following example will produce lots of output about the JIT

process, and surrounding operations:

```

import pennylane as qml

import jax, jax.numpy as jnp

from jax import jacfwd, jacrev

import logging

# Enable logging

qml.logging.enable\_logging()

# Get logger for use by this script only.

logger = logging.getLogger(\_\_name\_\_)

dev\_name = "default.qubit.jax"

num\_wires = 2

num\_shots = None

@jax.jit

def circuit(key, param):

    logger.info(f"Creating {dev\_name} device with {num\_wires} wires and {num\_shots} shots with {key} PNRG")

    dev = qml.device(dev\_name, wires=num\_wires, shots=num\_shots, prng\_key=key)

    @qml.qnode(dev, interface="jax", diff\_method="backprop")

    def my\_circuit():

        qml.RX(param, wires=0)

        qml.CNOT(wires=[0, 1])

        return qml.expval(qml.PauliZ(0))

    logger.info(f"Created QNODE={my\_circuit}")

    res =  my\_circuit()

    logger.info(f"Created QNODE evaluation={res}")

    return res

key1 = jax.random.PRNGKey(0)

key2 = jax.random.PRNGKey(1)

logger.info(f"Running circuit with key={key1}")

circuit(key1, jnp.pi/2)

logger.info(f"Running circuit with key={key2}")

circuit(key2, jnp.pi/2)

logger.info(f"Calculating jacobian circuit with key={key1}")

logger.info(f"Jacobian={jacfwd(lambda x: circuit(key1, x))(jnp.pi/3)}")

```

We can examine the output of the log-statements, which shows debug level

messages from JAX, and info-level messages for the given script. To modify the logger defined in the Python script, a new section can be added as:

```

# Control logging in the executing Python script

[loggers.\_\_main\_\_]

handlers = ["qml\_debug\_stream",]

level = "INFO"

propagate = false

```

To see PennyLane-wide debug messages, we can revert the PennyLane log level to

debug, and rerun the script. There should be more output than previously

observed.

##### Adding log-statements to the interface execution pipelines[¶](#adding-log-statements-to-the-interface-execution-pipelines "Permalink to this headline")

Similarly, for autograd (TF and Torch also), we can run examples that

tie-into the execution pipeline for devices without backprop supports:

```

import pennylane as qml

import logging

qml.logging.enable\_logging()

logger = logging.getLogger(\_\_name\_\_)

dev\_name = "lightning.qubit"

num\_wires = 2

num\_shots = None

def circuit(param):

    logger.info(f"Creating {dev\_name} device with {num\_wires} wires and {num\_shots} shots")

    dev = qml.device(dev\_name, wires=num\_wires, shots=num\_shots)

    @qml.qnode(dev, diff\_method="adjoint")

    def my\_circuit(param):

        qml.RX(param, wires=0)

        qml.CNOT(wires=[0, 1])

        return qml.expval(qml.PauliZ(0))

    logger.info(f"Created QNODE={my\_circuit}")

    res =  my\_circuit(param)

    logger.info(f"Created QNODE evaluation={res}")

    return res

par = qml.numpy.array([0.1,0.2])

logger.info(f"Running circuit with par={par[0]}")

circuit(par[0])

logger.info(f"Running circuit with par={par[1]}")

circuit(par[1])

logger.info(f"Calculating jacobian circuit with par={par}")

logger.info(f"Jacobian={qml.jacobian(circuit)(par[0])}")

```

By using `lightning.qubit` we can now treat the execution environment

as a black-box, and see the log-level messages as they hit the custom

functions as part of the execution pipeline.

The above features have been added for Torch, Tensorflow, JAX and

autograd, and should produce a sufficient level of detail in the

execution messages.

##### Log formatting[¶](#log-formatting "Permalink to this headline")

The logging-formatter ties-into the ANSI color-code system to improve

visibility of standard output and error logging during execution. The

ANSI codes accept RGB-coded code to change the text and background

colors, allowing messages to be color coded for ease of readability. For

example, to generate all such sequences in steps of 5 across each 8-bit

range per color, we can use the following bash command:

```

for r in `seq 0 5 255`; do

 for g in `seq 0 5 255`; do

 for b in `seq 0 5 255`; do

 echo -e "\e[38;2;${r};${g};${b}m"'\\e[38;2;'"${r};${g};${b}"m" FOREGROUND\e[0m"

 echo -e "\e[48;2;${r};${g};${b}m"'\\e[48;2;'"${r};${g};${b}"m" BACKGROUND\e[0m"

 done

 done

done

```

The strings in the log messages are prepended with the appropriate ANSI

codes to ensure different log-levels are highlighted in different ways

when outputing to the standard output stream (stdout/stderr). These are

defined in the `pennylane.logging.formatter` module, and can be

customized to suit any colors, or messaging structure.

### Building a plugin[¶](#building-a-plugin "Permalink to this headline")

Writing your own PennyLane plugin, to allow an external quantum library to take advantage of the

automatic differentiation ability of PennyLane, is a simple and easy process. In this section,

we will walk through the steps for creating your own PennyLane plugin. In addition, we also

provide two default reference plugins — [`'default.qubit'`](index.html#module-pennylane.devices.default_qubit "pennylane.devices.default_qubit") for basic pure

state qubit simulations, and [`'default.gaussian'`](index.html#module-pennylane.devices.default_gaussian "pennylane.devices.default_gaussian") for basic

continuous-variable simulations.

#### What a plugin provides[¶](#what-a-plugin-provides "Permalink to this headline")

A quick primer on terminology of PennyLane plugins in this section:

* A plugin is an external Python package that provides additional quantum *devices* to PennyLane.

* Each plugin may provide one (or more) devices, that are accessible directly through

PennyLane, as well as any additional private functions or classes.

* Depending on the scope of the plugin, you may wish to provide additional (custom)

quantum operations and observables that the user can import.

Important

In your plugin module, **standard NumPy** (*not* the wrapped Autograd version of NumPy)

should be imported in all places (i.e., `import numpy as np`).

#### Creating your device[¶](#creating-your-device "Permalink to this headline")

The first step in creating your PennyLane plugin is to create your device class.

This is as simple as importing the abstract base class [`pennylane.Device`](index.html#pennylane.Device "pennylane.Device") from PennyLane,

and subclassing it:

```

from pennylane import Device

class MyDevice(Device):

 """MyDevice docstring"""

    name = 'My custom device'

    short\_name = 'example.mydevice'

    pennylane\_requires = '0.1.0'

    version = '0.0.1'

    author = 'Ada Lovelace'

```

Note

Most devices inherit from a subclass of [`pennylane.Device`](index.html#pennylane.Device "pennylane.Device") called [`QubitDevice`](index.html#pennylane.QubitDevice "pennylane.QubitDevice"),

which contains a lot of functionality specific to computations based on qubits. We will

take a deeper look at this important case below.

Warning

The API of PennyLane devices will be updated soon to follow a new interface defined by

the experimental [`pennylane.devices.experimental.Device`](index.html#pennylane.devices.experimental.Device "pennylane.devices.experimental.Device") class. This guide describes

how to create a device with the current [`pennylane.Device`](index.html#pennylane.Device "pennylane.Device") and

[`pennylane.QubitDevice`](index.html#pennylane.QubitDevice "pennylane.QubitDevice") base classes, and will be updated as we switch to the new API.

In the meantime, please reach out to the PennyLane team if you would like help with building

a plugin, either by creating an [issue](https://github.com/PennyLaneAI/pennylane/issues) or

by posting in our [discussion forum](https://discuss.pennylane.ai/).

Here, we have begun defining some important class attributes that allow PennyLane to identify

and use the device. These include:

* [`pennylane.Device.name`](index.html#pennylane.Device.name "pennylane.Device.name"): a string containing the official name of the device

* [`pennylane.Device.short\_name`](index.html#pennylane.Device.short_name "pennylane.Device.short_name"): the string used to identify and load the device by users of PennyLane

* [`pennylane.Device.pennylane\_requires`](index.html#pennylane.Device.pennylane_requires "pennylane.Device.pennylane_requires"): the PennyLane version this device supports.

Note that this class attribute supports pip *requirements.txt* style version ranges,

for example:

	+ `pennylane\_requires = "2"` to support PennyLane version 2.x.x

	+ `pennylane\_requires = ">=0.1.5,<0.6"` to support a range of PennyLane versions

* [`pennylane.Device.version`](index.html#pennylane.Device.version "pennylane.Device.version"): the version number of the device

* [`pennylane.Device.author`](index.html#pennylane.Device.author "pennylane.Device.author"): the author of the device

Defining all these attributes is mandatory.

#### Device capabilities[¶](#device-capabilities "Permalink to this headline")

You must further tell PennyLane about the operations that your device supports,

as well as potential further capabilities, by providing the following class attributes/properties:

* [`pennylane.Device.stopping\_condition`](index.html#pennylane.Device.stopping_condition "pennylane.Device.stopping_condition"): This [`BooleanFn`](index.html#pennylane.BooleanFn "pennylane.BooleanFn") should return `True` for supported

operations and measurement processes, and `False` otherwise. Note that this function is called on

**both** `Operator` and `MeasurementProcess` classes. Though this function must accept both `Operator`

and `MeasurementProcess` classes, it does not affect whether or not a `MeasurementProcess` is supported.

```

@property

def stopping\_condition(self):

    def accepts\_obj(obj):

        return obj.name in {'CNOT', 'PauliX', 'PauliY', 'PauliZ'}

    return qml.BooleanFn(accepts\_obj)

```

If the device does *not* inherit from [`DefaultQubit`](index.html#pennylane.devices.default_qubit.DefaultQubit "pennylane.devices.default_qubit.DefaultQubit"), then supported operations can be determined

by the [`pennylane.Device.operations`](index.html#pennylane.Device.operations "pennylane.Device.operations") property. This property is a list of string names for supported operations.

[`DefaultQubit`](index.html#pennylane.devices.default_qubit.DefaultQubit "pennylane.devices.default_qubit.DefaultQubit") supports any operation with a matrix, even if it’s name isn’t specifically enumerated

in [`pennylane.Device.operations`](index.html#pennylane.Device.operations "pennylane.Device.operations").

```

operations = {"CNOT", "PauliX"}

```

See [Quantum operators](index.html#document-introduction/operations) for a full list of operations

supported by PennyLane.

If your device does not natively support an operation that has the

[`decomposition()`](index.html#pennylane.operation.Operation.decomposition "pennylane.operation.Operation.decomposition") static method defined, PennyLane will

attempt to decompose the operation before calling the device. For example,

the [`Rot`](index.html#pennylane.Rot "pennylane.Rot") [decomposition method](../_modules/pennylane/ops/qubit.html#Rot.decomposition) will

decompose the single-qubit rotation gate to [`RZ`](index.html#pennylane.RZ "pennylane.RZ") and [`RY`](index.html#pennylane.RY "pennylane.RY") gates.

Note

If the convention differs between the built-in PennyLane operation

and the corresponding operation in the targeted framework, ensure that the

conversion between the two conventions takes place automatically

by the plugin device.

* [`pennylane.Device.capabilities()`](index.html#pennylane.Device.capabilities "pennylane.Device.capabilities"): A class method which returns the dictionary of capabilities of a device. A

new device should override this method to retrieve the parent classes’ capabilities dictionary, make a copy

and update and/or add capabilities before returning the copy.

Examples of capabilities are:

	+ `'model'` (*str*): either `'qubit'` or `'cv'`.

	+ `'returns\_state'` (*bool*): `True` if the device returns the quantum state via `dev.state`.

	+ `'supports\_inverse\_operations'` (*bool*): `True` if the device supports

	applying the inverse of operations. Operations which should be inverted

	have the property `operation.inverse == True`.

	+ `'supports\_tensor\_observables'` (*bool*): `True` if the device supports observables composed from tensor

	products such as `PauliZ(wires=0) @ PauliZ(wires=1)`.

	+ `'supports\_tracker'` (*bool*): `True` if it has a device tracker attribute and updates information with

	it.Some capabilities are queried by PennyLane core to make decisions on how to best run computations, others are used

by external apps built on top of the device ecosystem.

To find out which capabilities are (possibly automatically) defined for your device `dev = device('my.device')`,

check the output of `dev.capabilities()`.

#### Adding arguments to your device[¶](#adding-arguments-to-your-device "Permalink to this headline")

Important

PennyLane supports both qubit and continuous-variable (CV) devices. However, from

here onwards, we will demonstrate plugin development focusing on qubit-based devices

inheriting from the [`QubitDevice`](index.html#pennylane.QubitDevice "pennylane.QubitDevice") class.

Defining the `\_\_init\_\_.py` method of a custom device is not necessary; by default,

the [`QubitDevice`](index.html#pennylane.QubitDevice "pennylane.QubitDevice") initialization will be called, where the user can pass the

following arguments:

* `wires` (*int* or *Iterable[Number, str]*): The number of subsystems represented by the device,

or iterable that contains unique labels for the subsystems as numbers (i.e., `[-1, 0, 2]`)

and/or strings (`['auxiliary', 'q1', 'q2']`).

* `shots=1000` (*None*, *int* or *List[int]*): number of circuit

evaluations/random samples used to estimate probabilities, expectation

values, variances of observables in non-analytic mode. If `None`, the device

calculates probability, expectation values, and variances analytically. If an

integer, it specifies the number of samples to estimate these quantities. If a

list of integers is passed, the circuit evaluations are batched over the list

of shots.

To add your own device arguments, or to override any of the above defaults, simply

overwrite the `\_\_init\_\_.py` method. For example, here is a device where the number

of wires is fixed to `24`, that cannot be used in analytic mode, and that can accept a dictionary

of low-level hardware control options:

```

class CustomDevice(QubitDevice):

    name = 'My custom device'

    short\_name = 'example.mydevice'

    pennylane\_requires = '0.1.0'

    version = '0.0.1'

    author = 'Ada Lovelace'

    operations = {"PauliX", "RX", "CNOT"}

    observables = {"PauliZ", "PauliX", "PauliY"}

    def \_\_init\_\_(self, shots=1024, hardware\_options=None):

        super().\_\_init\_\_(wires=24, shots=shots)

        self.hardware\_options = hardware\_options or hardware\_defaults

```

Note that we have also overridden the default shot number.

The user can now pass any of these arguments to the PennyLane device loader:

```

>>> dev = qml.device("example.mydevice", hardware\_options={"t2": 0.1})

>>> dev.hardware\_options

{"t2": 0.1}

```

#### Device execution[¶](#device-execution "Permalink to this headline")

Once all the class attributes are defined, it is necessary to define some required class

methods to allow PennyLane to apply operations and measure observables on your device.

To execute operations on the device, the following methods **must** be defined:

| [`apply`](index.html#pennylane.QubitDevice.apply "pennylane.QubitDevice.apply")(operations, \*\*kwargs) | Apply quantum operations, rotate the circuit into the measurement basis, and compile and execute the quantum circuit. |

If the device is a statevector simulator (it can perform analytic computations when `shots=None`)

then it **must** also overwrite:

| [`analytic\_probability`](index.html#pennylane.QubitDevice.analytic_probability "pennylane.QubitDevice.analytic_probability")([wires]) | Return the (marginal) probability of each computational basis state from the last run of the device. |

The [`QubitDevice`](index.html#pennylane.QubitDevice "pennylane.QubitDevice") class

provides the following convenience methods that may be used by the plugin:

| [`active\_wires`](index.html#pennylane.QubitDevice.active_wires "pennylane.QubitDevice.active_wires")(operators) | Returns the wires acted on by a set of operators. |

| [`marginal\_prob`](index.html#pennylane.QubitDevice.marginal_prob "pennylane.QubitDevice.marginal_prob")(prob[, wires]) | Return the marginal probability of the computational basis states by summing the probabiliites on the non-specified wires. |

In addition, if your qubit device generates its own computational basis samples for measured wires

after execution, you need to overwrite the following method:

| [`generate\_samples`](index.html#pennylane.QubitDevice.generate_samples "pennylane.QubitDevice.generate_samples")() | Returns the computational basis samples generated for all wires. |

[`generate\_samples()`](index.html#pennylane.QubitDevice.generate_samples "pennylane.QubitDevice.generate_samples") should return samples with shape `(dev.shots, dev.num\_wires)`.

Furthermore, PennyLane uses the convention \(|q\_0,q\_1,\dots,q\_{N-1}\rangle\) where

\(q\_0\) is the most significant bit.

And thats it! The device has inherited [`expval()`](index.html#pennylane.QubitDevice.expval "pennylane.QubitDevice.expval"), [`var()`](index.html#pennylane.QubitDevice.var "pennylane.QubitDevice.var"),

and [`sample()`](index.html#pennylane.QubitDevice.sample "pennylane.QubitDevice.sample") methods, that accepts an observable (or tensor product of

observables) and returns the corresponding measurement statistic.

[Advanced execution control (click to expand)](#content1)

Additional flexibility is sometimes required for interfacing with more

complicated frameworks.

When PennyLane needs to evaluate a QNode, it accesses the [`execute()`](index.html#pennylane.QubitDevice.execute "pennylane.QubitDevice.execute") method of

your plugin which, by default, performs the following process:

```

self.check\_validity(circuit.operations, circuit.observables)

# apply all circuit operations

self.apply(circuit.operations, rotations=circuit.diagonalizing\_gates)

# generate computational basis samples

if self.shots is not None or circuit.is\_sampled:

    self.\_samples = self.generate\_samples()

# compute the required statistics

results = self.statistics(circuit)

return self.\_asarray(results)

```

where

* `circuit` is a [`CircuitGraph`](index.html#pennylane.CircuitGraph "pennylane.CircuitGraph") object

* [`circuit.operations`](index.html#pennylane.CircuitGraph.operations "pennylane.CircuitGraph.operations") are the user-provided

operations to be executed

* [`circuit.observables`](index.html#pennylane.CircuitGraph.observables "pennylane.CircuitGraph.observables") are the user-provided

observables to be measured

* `circuit.diagonalizing\_gates` are the

gates that rotate the circuit prior to measurement so that computational basis

measurements are performed in the eigenbasis of the requested observables

* [`QubitDevice.statistics()`](index.html#pennylane.QubitDevice.statistics "pennylane.QubitDevice.statistics") returns the results of [`QubitDevice.expval()`](index.html#pennylane.QubitDevice.expval "pennylane.QubitDevice.expval"),

[`var()`](index.html#pennylane.QubitDevice.var "pennylane.QubitDevice.var"), or [`sample()`](index.html#pennylane.QubitDevice.sample "pennylane.QubitDevice.sample") depending on the type

of observable.

In advanced cases, the [`QubitDevice.execute()`](index.html#pennylane.QubitDevice.execute "pennylane.QubitDevice.execute") method, as well as

[`QubitDevice.statistics()`](index.html#pennylane.QubitDevice.statistics "pennylane.QubitDevice.statistics"), may be overwritten directly.

This provides full flexibility for handling the device execution yourself. However,

this may have unintended side-effects and is not recommended.

#### Wire handling[¶](#wire-handling "Permalink to this headline")

PennyLane uses the [`Wires`](index.html#pennylane.wires.Wires "pennylane.wires.Wires") class for the internal representation of wires. [`Wires`](index.html#pennylane.wires.Wires "pennylane.wires.Wires")

inherits from Python’s `Sequence`, and represents an ordered set of unique wire labels.

Indexing a `Wires` instance will return another `Wires` instance of length one.

The `labels` attribute stores a tuple of the wire labels.

For example:

```

from pennylane.wires import Wires

wires = Wires(['auxiliary', 0, 1])

print(wires[0]) # <Wires = ['auxiliary']>

print(wires.labels) # ('auxiliary', 0, 1)

```

As shown in the section on [Quantum circuits](index.html#document-introduction/circuits), a device can be created with custom wire labels:

```

from pennylane import \*

dev = device('my.device', wires=['q11', 'q12', 'q21', 'q22'])

@qnode(dev)

def circuit():

   Gate1(wires='q22')

   Gate2(wires=['q21','q11'])

   Gate1(wires=['q21'])

   return expval(Obs(wires='q11') @ Obs(wires='q12'))

```

Behind the scenes, when `my.device` gets created it turns `['q11', 'q12', 'q21', 'q22']` into a

[`Wires`](index.html#pennylane.wires.Wires "pennylane.wires.Wires") object and stores it in the device’s `wires` attribute. Likewise, when gates and

observables get created they turn their `wires` argument into a [`Wires`](index.html#pennylane.wires.Wires "pennylane.wires.Wires")

object and store it in their `wires` attribute.

```

print(dev.wires) # <Wires = ['q11', 'q12', 'q21', 'q22']>

op = Gate2(wires=['q21','q11'])

print(op.wires) # <Wires = ['q21', 'q11']>

```

When the device applies operations, it needs to translate

`op.wires` into wire labels that the backend “understands”. This can be done with the

[`pennylane.Device.map\_wires()`](index.html#pennylane.Device.map_wires "pennylane.Device.map_wires") method which maps `Wires` objects to other `Wires` objects,

but changes the labels according to the `wire\_map` attribute of the device which defines the translation.

```

# inside the class defining 'my.device', which inherits from the base Device class

device\_wires = self.map\_wires(op.wires)

print(device\_wires) # <Wires = [2, 0]>

```

By default, the map translates the custom labels `'q11'`, `'q12'`, `'q21'`, `'q22'` to

consecutive integers `0`, `1`, `2`, `3`. If a device uses a different wire labeling,

such as non-consecutive wires `0`, `4`, `7`, `12`, the [`pennylane.Device.define\_wire\_map()`](index.html#pennylane.Device.define_wire_map "pennylane.Device.define_wire_map") method

has to be overwritten accordingly.

The `device\_wires` can then be further processed, for example by extracting the actual labels as a tuple,

list or array, or by getting the number of wires:

```

device\_wires.labels # (2, 0)

device\_wires.tolist() # [2, 0]

device\_wires.toarray() # ndarray([2, 0])

len(device\_wires) # 2

```

The `Wires` class also offers set functionality like identifying the unique or shared wires between several `Wires`

object.

As a convention, devices should do the translation and unpacking as late as possible in the function tree, and

where possible pass the original [`Wires`](index.html#pennylane.wires.Wires "pennylane.wires.Wires") objects around.

#### Device tracker support[¶](#device-tracker-support "Permalink to this headline")

The device tracker stores and records information when tracking mode is turned on. Devices can store data like

the number of executions, number of shots, number of batches, or remote simulator cost for users to interact with

in a customizable way.

Three aspects of the [`Tracker`](index.html#pennylane.Tracker "pennylane.Tracker") class are relevant to plugin designers:

* The boolean `active` attribute that denotes whether or not to update and record

* `update` method which accepts keyword-value pairs and stores the information

* `record` method which users can customize to log, print, or otherwise do something with the stored information

To gain any of the device tracker functionality, a device should initialize with a placeholder

[`Tracker`](index.html#pennylane.Tracker "pennylane.Tracker") instance. Users can overwrite this attribute by initializing a new instance with

the device as an argument.

We recommend placing the following code near the end of the `execute` method:

```

if self.tracker.active:

  self.tracker.update(executions=1, shots=self.\_shots)

  self.tracker.record()

```

And similar code in the `batch\_execute` method:

```

if self.tracker.active:

  self.tracker.update(batches=1, batch\_len=len(circuits))

  self.tracker.record()

```

These functions are called in base [`pennylane.Device`](index.html#pennylane.Device "pennylane.Device") and [`QubitDevice`](index.html#pennylane.QubitDevice "pennylane.QubitDevice") devices. Unless you are

overriding the `execute` and `batch\_execute` methods or want to customize the stored

information, you do not need to add any new code.

While this is the recommended usage, the `update` and `record` methods can be called at any location

within the device. While the above example tracks executions, shots, and batches, the

[`update()`](index.html#pennylane.Tracker.update "pennylane.Tracker.update") method can accept any combination of

keyword-value pairs. For example, a device could also track cost and a job ID via:

```

price\_for\_execution = 0.10

job\_id = "abcde"

self.tracker.update(price=price\_for\_execution, job\_id=job\_id)

```

#### Identifying and installing your device[¶](#installing-plugin "Permalink to this headline")

When performing a hybrid computation using PennyLane, one of the first steps is often to

initialize the quantum device(s). PennyLane identifies the devices via their `short\_name`,

which allows the device to be initialized in the following way:

```

import pennylane as qml

dev1 = qml.device(short\_name, wires=2)

```

where `short\_name` is a string that uniquely identifies the device. The `short\_name`

should have the form `pluginname.devicename`, using periods for delimitation.

PennyLane uses a setuptools `entry\_points` approach to plugin discovery/integration.

In order to make the devices of your plugin accessible to PennyLane, simply provide the

following keyword argument to the `setup()` function in your `setup.py` file:

```

devices\_list = [

        'example.mydevice1 = MyModule.MySubModule:MyDevice1'

        'example.mydevice2 = MyModule.MySubModule:MyDevice2'

    ],

setup(entry\_points={'pennylane.plugins': devices\_list})

```

where

* `devices\_list` is a list of devices you would like to register,

* `example.mydevice1` is the short name of the device, and

* `MyModule.MySubModule` is the path to your Device class, `MyDevice1`.

To ensure your device is working as expected, you can install it in developer mode using

`pip install -e pluginpath`, where `pluginpath` is the location of the plugin. It will

then be accessible via PennyLane.

#### Testing[¶](#testing "Permalink to this headline")

All plugins should come with extensive unit tests, to ensure that each logical unit of the

device has correct execution.

Integration tests to check that the probabilities, expectation values, variance, and samples are

correct for various circuits and observables are provided as part of the PennyLane device

test utility:

```

pl-device-test --device device\_shortname --shots 10000

```

In general, as all supported operations have their gradient formula defined and tested by

PennyLane, testing that your device calculates the correct gradients is not required.

For more details on the PennyLane device test utility, see [`pennylane.devices.tests`](index.html#module-pennylane.devices.tests "pennylane.devices.tests").

#### Supporting custom operators[¶](#supporting-custom-operators "Permalink to this headline")

If you would like to support an operator (such as a gate or observable) that is not currently supported by

PennyLane, you can subclass the [`Operator`](index.html#pennylane.operation.Operator "pennylane.operation.Operator") class. Detailed information can be found in the

section [Adding new operators](index.html#document-development/adding_operators).

Users can then import this operator directly from your plugin, and use it when defining a QNode:

```

import pennylane as qml

from MyModule.MySubModule import CustomGate

@qnode(dev1)

def my\_qfunc(phi):

    qml.Hadamard(wires=0)

    CustomGate(phi, theta, wires=0)

    return qml.expval(qml.PauliZ(0))

```

Warning

If you are providing custom operators not natively supported by PennyLane, it is recommended

that the plugin unit tests provide tests to ensure that PennyLane returns the correct

gradient for the custom operations.

If the custom operator is diagonal in the computational basis, it can be added to the

`diagonal\_in\_z\_basis` attribute in `pennylane.ops.qubit.attributes`. Devices can use this

information to implement faster simulations.

### Adding new operators[¶](#adding-new-operators "Permalink to this headline")

The following steps will help you to create custom operators, and to

potentially add them to PennyLane.

Note that in PennyLane, a circuit ansatz consisting of multiple gates is also an operator — one whose

action is defined by specifying a representation as a combination of other operators.

For historical reasons, you find circuit ansaetze in the `pennylane/template/` folder,

while all other operations are found in `pennylane/ops/`.

The base classes to construct new operators, [`Operator`](index.html#pennylane.operation.Operator "pennylane.operation.Operator") and

corresponding subclasses, are found in `pennylane/operations.py`.

Note

Check [qml.measurements](index.html#document-code/qml_measurements) for documentation on how to create new measurements.

#### Abstraction[¶](#abstraction "Permalink to this headline")

Operators in quantum mechanics are maps that act on vector spaces, and in differentiable quantum computing, these

maps can depend on a set of trainable parameters. The [`Operator`](index.html#pennylane.operation.Operator "pennylane.operation.Operator") class

serves as the main abstraction of such objects, and all operators (such as gates, channels, observables)

inherit from it.

```

>>> from jax import numpy as jnp

>>> op = qml.Rot(jnp.array(0.1), jnp.array(0.2), jnp.array(0.3), wires=["a"])

>>> isinstance(op, qml.operation.Operator)

True

```

The basic components of operators are the following:

1. **The name of the operator** ([`Operator.name`](index.html#pennylane.operation.Operator.name "pennylane.operation.Operator.name")), which may have a canonical, universally known interpretation (such as a “Hadamard” gate),

or could be a name specific to PennyLane.

```

>>> op.name

Rot

```

2. **The subsystems that the operator addresses** ([`Operator.wires`](index.html#pennylane.operation.Operator.wires "pennylane.operation.Operator.wires")), which mathematically speaking defines the subspace that it acts on.

```

>>> op.wires

<Wires = ['a']>

```

3. **Trainable parameters** ([`Operator.parameters`](index.html#pennylane.operation.Operator.parameters "pennylane.operation.Operator.parameters")) that the map depends on, such as a rotation angle,

which can be fed to the operator as tensor-like objects. For example, since we used jax arrays to

specify the three rotation angles of `op`, the parameters are jax `Arrays`.

```

>>> op.parameters

[Array(0.1, dtype=float32, weak\_type=True),

 Array(0.2, dtype=float32, weak\_type=True),

 Array(0.3, dtype=float32, weak\_type=True)]

```

4. **Non-trainable hyperparameters** ([`Operator.hyperparameters`](index.html#pennylane.operation.Operator.hyperparameters "pennylane.operation.Operator.hyperparameters")) that influence the action of the operator.

Not every operator has hyperparameters.

```

>>> op.hyperparameters

{}

```

5. Possible **symbolic or numerical representations** of the operator, which can be used by PennyLane’s

devices to interpret the map. Examples are:

	* Representation as a **product of operators** ([`Operator.decomposition()`](index.html#pennylane.operation.Operator.decomposition "pennylane.operation.Operator.decomposition")):

	

	

	

	```

	>>> op = qml.Rot(0.1, 0.2, 0.3, wires=["a"])

	>>> op.decomposition()

	[RZ(0.1, wires=['a']), RY(0.2, wires=['a']), RZ(0.3, wires=['a'])]

	

	```

	* Representation as a **linear combination of operators** ([`Operator.terms()`](index.html#pennylane.operation.Operator.terms "pennylane.operation.Operator.terms")):

	

	

	

	```

	>>> op = qml.Hamiltonian([1., 2.], [qml.PauliX(0), qml.PauliZ(0)])

	>>> op.terms()

	((1.0, 2.0), [PauliX(wires=[0]), PauliZ(wires=[0])])

	

	```

	* Representation via the **eigenvalue decomposition** specified by eigenvalues (for the diagonal matrix, [`Operator.eigvals()`](index.html#pennylane.operation.Operator.eigvals "pennylane.operation.Operator.eigvals"))

	and diagonalizing gates (for the unitaries [`Operator.diagonalizing\_gates()`](index.html#pennylane.operation.Operator.diagonalizing_gates "pennylane.operation.Operator.diagonalizing_gates")):

	

	

	

	```

	>>> op = qml.PauliX(0)

	>>> op.diagonalizing\_gates()

	[Hadamard(wires=[0])]

	>>> op.eigvals()

	[ 1 -1]

	

	```

	* Representation as a **matrix** ([`Operator.matrix()`](index.html#pennylane.operation.Operator.matrix "pennylane.operation.Operator.matrix")), as specified by a global wire order that tells us where the

	wires are found on a register:

	

	

	

	```

	>>> op = qml.PauliRot(0.2, "X", wires=["b"])

	>>> op.matrix(wire\_order=["a", "b"])

	[[9.95e-01-2.26e-18j 2.72e-17-9.98e-02j, 0+0j, 0+0j]

	 [2.72e-17-9.98e-02j 9.95e-01-2.26e-18j, 0+0j, 0+0j]

	 [0+0j, 0+0j, 9.95e-01-2.26e-18j 2.72e-17-9.98e-02j]

	 [0+0j, 0+0j, 2.72e-17-9.98e-02j 9.95e-01-2.26e-18j]]

	

	```

	* Representation as a **sparse matrix** ([`Operator.sparse\_matrix()`](index.html#pennylane.operation.Operator.sparse_matrix "pennylane.operation.Operator.sparse_matrix")):

	

	

	

	```

	>>> from scipy.sparse.coo import coo\_matrix

	>>> row = np.array([0, 1])

	>>> col = np.array([1, 0])

	>>> data = np.array([1, -1])

	>>> mat = coo\_matrix((data, (row, col)), shape=(4, 4))

	>>> op = qml.SparseHamiltonian(mat, wires=["a"])

	>>> op.sparse\_matrix(wire\_order=["a"])

	(0, 1) 1

	(1, 0) - 1

	

	```

New operators can be created by applying arithmetic functions to operators, such as addition, scalar multiplication,

multiplication, taking the adjoint, or controlling an operator. At the moment, such arithmetic is only implemented for

specific subclasses.

* Operators inheriting from [`Observable`](index.html#pennylane.operation.Observable "pennylane.operation.Observable") support addition and scalar multiplication:

```

>>> op = qml.PauliX(0) + 0.1 \* qml.PauliZ(0)

>>> op.name

Hamiltonian

>>> op

 (0.1) [Z0]

+ (1.0) [X0]

```

* Operators may define a hermitian conjugate:

```

>>> qml.RX(1., wires=0).adjoint()

RX(-1.0, wires=[0])

```

#### Creating custom operators[¶](#creating-custom-operators "Permalink to this headline")

A custom operator can be created by inheriting from [`Operator`](index.html#pennylane.operation.Operator "pennylane.operation.Operator") or one of its subclasses.

The following is an example for a custom gate that possibly flips a qubit and then rotates another qubit.

The custom operator defines a decomposition, which the devices can use (since it is unlikely that a device

knows a native implementation for `FlipAndRotate`). It also defines an adjoint operator.

```

import pennylane as qml

class FlipAndRotate(qml.operation.Operation):

    # Define how many wires the operator acts on in total.

    # In our case this may be one or two, which is why we

    # use the AnyWires Enumeration to indicate a variable number.

    num\_wires = qml.operation.AnyWires

    # This attribute tells PennyLane what differentiation method to use. Here

    # we request parameter-shift (or "analytic") differentiation.

    grad\_method = "A"

    def \_\_init\_\_(self, angle, wire\_rot, wire\_flip=None, do\_flip=False, id=None):

        # checking the inputs --------------

        if do\_flip and wire\_flip is None:

            raise ValueError("Expected a wire to flip; got None.")

        # note: we use the framework-agnostic math library since

        # trainable inputs could be tensors of different types

        shape = qml.math.shape(angle)

        if len(shape) > 1:

            raise ValueError(f"Expected a scalar angle; got angle of shape {shape}.")

        #------------------------------------

        # do\_flip is not trainable but influences the action of the operator,

        # which is why we define it to be a hyperparameter

        self.\_hyperparameters = {

            "do\_flip": do\_flip

        }

        # we extract all wires that the operator acts on,

        # relying on the Wire class arithmetic

        all\_wires = qml.wires.Wires(wire\_rot) + qml.wires.Wires(wire\_flip)

        # The parent class expects all trainable parameters to be fed as positional

        # arguments, and all wires acted on fed as a keyword argument.

        # The id keyword argument allows users to give their instance a custom name.

        super().\_\_init\_\_(angle, wires=all\_wires, id=id)

    @property

    def num\_params(self):

        # if it is known before creation, define the number of parameters to expect here,

        # which makes sure an error is raised if the wrong number was passed

        return 1

    @staticmethod

    def compute\_decomposition(angle, wires, do\_flip):  # pylint: disable=arguments-differ

        # Overwriting this method defines the decomposition of the new gate, as it is

        # called by Operator.decomposition().

        # The general signature of this function is (\*parameters, wires, \*\*hyperparameters).

        op\_list = []

        if do\_flip:

            op\_list.append(qml.PauliX(wires=wires[1]))

        op\_list.append(qml.RX(angle, wires=wires[0]))

        return op\_list

    def adjoint(self):

        # the adjoint operator of this gate simply negates the angle

        return FlipAndRotate(-self.parameters[0], self.wires[0], self.wires[1], do\_flip=self.hyperparameters["do\_flip"])

```

The new gate can now be created as follows:

```

>>> op = FlipAndRotate(0.1, wire\_rot="q3", wire\_flip="q1", do\_flip=True)

>>> op

FlipAndRotate(0.1, wires=['q3', 'q1'])

>>> op.decomposition()

[PauliX(wires=['q1']), RX(0.1, wires=['q3'])]

>>> op.adjoint()

FlipAndRotate(-0.1, wires=['q3', 'q1'])

```

The new gate can be used with PennyLane devices. Device support for an operation can be checked via

`dev.stopping\_condition(op)`. If `True`, then the device supports the operation.

`DefaultQubit` first checks if the operator has a matrix using the [`has\_matrix`](index.html#pennylane.operation.Operator.has_matrix "pennylane.operation.Operator.has_matrix") property.

If the Operator doesn’t have a matrix, the device then checks if the name of the Operator is explicitly specified in

`operations` or `observables`.

Other devices that do not inherit from `DefaultQubit` only check if the name is explicitly specified in the `operations`

property.

* If the device registers support for an operation with the same name,

PennyLane leaves the gate implementation up to the device. The device

might have a hardcoded implementation, *or* it may refer to one of the

numerical representations of the operator (such as [`Operator.matrix()`](index.html#pennylane.operation.Operator.matrix "pennylane.operation.Operator.matrix")).

* If the device does not support an operation, PennyLane will automatically

decompose the gate using [`Operator.decomposition()`](index.html#pennylane.operation.Operator.decomposition "pennylane.operation.Operator.decomposition").

```

from pennylane import numpy as np

dev = qml.device("default.qubit", wires=["q1", "q2", "q3"])

@qml.qnode(dev)

def circuit(angle):

    FlipAndRotate(angle, wire\_rot="q1", wire\_flip="q1")

    return qml.expval(qml.PauliZ("q1"))

```

```

>>> a = np.array(3.14)

>>> circuit(a)

-0.9999987318946099

```

If all gates used in the decomposition have gradient recipes defined,

we can even compute gradients of circuits that use the new gate without any extra effort.

```

>>> qml.grad(circuit)(a)

-0.0015926529164868282

```

Note

The example of `FlipAndRotate` is simple enough that one could write a function

```

def FlipAndRotate(angle, wire\_rot, wire\_flip=None, do\_flip=False):

    if do\_flip:

        qml.PauliX(wires=wire\_flip)

    qml.RX(angle, wires=wire\_rot)

```

and call it in the quantum function *as if it was a gate*.

However, classes allow much more functionality, such as defining the adjoint gate above,

defining the shape expected for the trainable parameter(s), or specifying gradient rules.

#### Defining special properties of an operator[¶](#defining-special-properties-of-an-operator "Permalink to this headline")

Apart from the main [`Operator`](index.html#pennylane.operation.Operator "pennylane.operation.Operator") class, operators with special methods or representations

are implemented as subclasses [`Operation`](index.html#pennylane.operation.Operation "pennylane.operation.Operation"), [`Observable`](index.html#pennylane.operation.Observable "pennylane.operation.Observable"), [`Channel`](index.html#pennylane.operation.Channel "pennylane.operation.Channel"),

[`CVOperation`](index.html#pennylane.operation.CVOperation "pennylane.operation.CVOperation") and [`CVObservable`](index.html#pennylane.operation.CVObservable "pennylane.operation.CVObservable").

However, unlike many other frameworks, PennyLane does not use class

inheritance to define fine-grained properties of operators,

such as whether it is its own self-inverse, if it is diagonal,

or whether it can be decomposed into Pauli rotations. This avoids changing the inheritance structure

every time an application needs to query a new property.

Instead, PennyLane uses “attributes”, which are bookkeeping classes that list operators

which fulfill a specific property.

For example, we can create a new attribute, `pauli\_ops`, like so:

```

>>> from pennylane.ops.qubits.attributes import Attribute

>>> pauli\_ops = Attribute(["PauliX", "PauliY", "PauliZ"])

```

We can check either a string or an Operation for inclusion in this set:

```

>>> qml.PauliX(0) in pauli\_ops

True

>>> "Hadamard" in pauli\_ops

False

```

We can also dynamically add operators to the sets at runtime. This is useful

for adding custom operations to the attributes such as `composable\_rotations`

and `self\_inverses` that are used in compilation transforms. For example,

suppose you have created a new operation `MyGate`, which you know to be its

own inverse. Adding it to the set, like so

```

>>> from pennylane.ops.qubits.attributes import self\_inverses

>>> self\_inverses.add("MyGate")

```

Attributes can also be queried by devices to use special tricks that allow more efficient

implementations. The onus is on the contributors of new operators to add them to the right attributes.

Note

The attributes for qubit gates are currently found in `pennylane/ops/qubit/attributes.py`.

Included attributes are listed in the `Operation`

[documentation](https://pennylane.readthedocs.io/en/latest/code/qml_operation.html#operation-attributes).

#### Adding your new operator to PennyLane[¶](#adding-your-new-operator-to-pennylane "Permalink to this headline")

If you want PennyLane to natively support your new operator, you have to make a Pull Request that adds it

to the appropriate folder in `pennylane/ops/`. The

tests are added to a file of a similar name and location in `tests/ops/`. If your operator defines an

ansatz, add it to the appropriate subfolder in `pennylane/templates/`.

The new operation may have to be imported in the module’s `\_\_init\_\_.py` file in order to be imported correctly.

Make sure that all hyperparameters and errors are tested, and that the parameters can be passed as

tensors from all supported autodifferentiation frameworks.

Don’t forget to also add the new operator to the documentation in the `docs/introduction/operations.rst` file, or to

the template gallery if it is an ansatz. The latter is done by adding a `gallery-item`

to the correct section in `doc/introduction/templates.rst`:

```

.. gallery-item::

  :link: ../code/api/pennylane.templates.<templ\_type>.MyNewTemplate.html

  :description: MyNewTemplate

  :figure: ../\_static/templates/<templ\_type>/my\_new\_template.png

```

Note

This loads the image of the template added to `doc/\_static/templates/test\_<templ\_type>/`. Make sure that

this image has the same dimensions and style as other template icons in the folder.

Here are a few more tips for adding operators:

* *Choose the name carefully.* Good names tell the user what the operator is used for,

or what architecture it implements. Ask yourself if a gate of a similar name could

be added soon in a different context.

* *Write good docstrings.* Explain what your operator does in a clear docstring with ample examples.

You find more about Pennylane standards in the guidelines on [Documentation](index.html#document-development/guide/documentation).

* *Efficient representations.* Try to implement representations as efficiently as possible, since they may

be constructed several times.

* *Input checks.* Checking the inputs of the operation introduces an overhead and clashes with tools like

just-in-time compilation. Find a balance of adding meaningful sanity checks (such as for the shape of tensors),

but keeping them to a minimum.

### Deprecations[¶](#deprecations "Permalink to this headline")

#### Pending deprecations[¶](#pending-deprecations "Permalink to this headline")

* The RandomLayers.compute\_decomposition keyword argument ratio\_imprivitive will be changed to ratio\_imprim to

match the call signature of the operation.

	+ Deprecated in v0.32

	+ Removed in v0.33

* `qml.enable\_return` and `qml.disable\_return` are deprecated. Please avoid calling

`disable\_return`, as the old return system is deprecated along with these switch functions.

	+ Deprecated in v0.32

	+ Will be removed in v0.33

* The `mode` keyword argument in `QNode` is deprecated, as it was only used in the old return

system (which is also deprecated). Please use `grad\_on\_execution` instead.

	+ Deprecated in v0.32

	+ Will be removed in v0.33

* The `observables` argument in `QubitDevice.statistics` is deprecated. Please use `circuit`

instead. Using a list of observables in `QubitDevice.statistics` is deprecated. Please use a

`QuantumTape` instead.

	+ Still accessible in v0.28, v0.29, v0.30

	+ Will be removed in v0.31

* `qml.ExpvalCost` has been deprecated, and usage will now raise a warning.

	+ Deprecated in v0.24

	+ Will be removed in v0.32Instead, it is recommended to simply

pass Hamiltonians to the `qml.expval` function inside QNodes:

```

@qml.qnode(dev)

def ansatz(params):

    some\_qfunc(params)

    return qml.expval(Hamiltonian)

```

* The behaviour of `Operator.\_\_eq\_\_` and `Operator.\_\_hash\_\_` will be updated soon. Their documentation

has been updated to reflect the incoming changes.

The upcoming changes to operator equality will allow users to use operator equality the same way as

with `qml.equal`. With the changes to hashing, unique operators that are equal will have the same

hash. These changes will allow behaviour such as the following:

```

>>> qml.RX(0.1, wires=0) == qml.RX(0.1, wires=0)

True

>>> {qml.PauliZ(0), qml.PauliZ(0)}

{PauliZ(wires=[0])}

```

Meanwhile, the current behaviour is shown below:

```

>>> qml.RX(0.1, wires=0) == qml.RX(0.1, wires=0)

False

>>> {qml.PauliZ(0), qml.PauliZ(0)}

{PauliZ(wires=[0]), PauliZ(wires=[0])}

```

	+ Added in v0.32

	+ Behaviour will change in v0.33

* The public methods of `DefaultQubit` are pending changes to

follow the new device API, as used in `DefaultQubit2`.

We will be switching to the new device interface in a coming release.

In this new interface, simulation implementation details

will be abstracted away from the device class itself and provided by composition, rather than inheritance.

Therefore, some public and private methods from `DefaultQubit` will no longer exist, though its behaviour

in a workflow will remain the same.

If you directly interact with device methods, please consult

[`pennylane.devices.experimental.Device`](index.html#pennylane.devices.experimental.Device "pennylane.devices.experimental.Device") and

[`pennylane.devices.experimental.DefaultQubit2`](index.html#pennylane.devices.experimental.DefaultQubit2 "pennylane.devices.experimental.DefaultQubit2")

for more information on what the new interface will look like and be prepared

to make updates in a coming release. If you have any feedback on these

changes, please create an

[issue](https://github.com/PennyLaneAI/pennylane/issues) or post in our

[discussion forum](https://discuss.pennylane.ai/).

	+ Deprecated in v0.31

* `qml.qchem.jordan\_wigner` is deprecated, and usage will now raise a warning.

Use `qml.jordan\_wigner` instead. List input to define the fermionic operator

is also deprecated; the fermionic operators `qml.FermiA`, `qml.FermiC`,

`qml.FermiWord` and `qml.FermiSentence` should be used instead. See the

`pennylane.fermi` module documentation and the

[Fermionic Operator](https://pennylane.ai/qml/demos/tutorial_fermionic_operators)

tutorial for more details.

* The CV observables `qml.X` and `qml.P` have been deprecated, and usage will now

raise a warning. Please use `qml.QuadX` and `qml.QuadP` instead.

	+ Deprecated in v0.32

	+ Will be removed in v0.33

* The method `tape.unwrap()` and corresponding `UnwrapTape` and `Unwrap` classes are

deprecated, and usage will now raise a warning.

Instead of `tape.unwrap()`, use [`convert\_to\_numpy\_parameters()`](index.html#pennylane.transforms.convert_to_numpy_parameters "pennylane.transforms.convert_to_numpy_parameters"):

```

from pennylane.transforms import convert\_to\_numpy\_parameters

qscript = qml.tape.QuantumTape([qml.RX(torch.tensor(0.1234), 0)],

                                 [qml.expval(qml.Hermitian(torch.eye(2), 0))] )

unwrapped\_qscript = convert\_to\_numpy\_parameters(qscript)

torch\_params = qscript.get\_parameters()

numpy\_params = unwrapped\_qscript.get\_parameters()

```

* The `QuantumScript.set\_parameters` method and the `QuantumScript.data` setter has

been deprecated. Please use `QuantumScript.bind\_new\_parameters` instead.

	+ Deprecated in v0.32

	+ Will be removed in v0.33

* The `tuple` input type in `qubit\_observable` has been deprecated. Please use a fermionic

operator object. The `tuple` return type in `fermionic\_hamiltonian` and

`fermionic\_observable` has been deprecated and these functions will return a fermionic operator

by default.

	+ Deprecated in v0.32

	+ Will be removed in v0.33

* The `sampler\_seed` argument of `qml.gradients.spsa\_grad` has been deprecated, along with a bug

fix of the seed-setting behaviour.

Instead, the `sampler\_rng` argument should be set, either to an integer value, which will be used

to create a PRNG internally, or to a NumPy pseudo-random number generator (PRNG) created via

`np.random.default\_rng(seed)`.

The advantage of passing a PRNG is that one can reuse that PRNG when calling `spsa\_grad`

multiple times, for instance during an optimization procedure.

	+ Deprecated in v0.32

	+ Will be removed in v0.33

#### Completed deprecation cycles[¶](#completed-deprecation-cycles "Permalink to this headline")

* `qml.math.purity`, `qml.math.vn\_entropy`, `qml.math.mutual\_info`, `qml.math.fidelity`,

`qml.math.relative\_entropy`, and `qml.math.max\_entropy` no longer support state vectors as

input. Please call `qml.math.dm\_from\_state\_vector` on the input before passing to any of these functions.

	+ Still accepted in v0.31

	+ Removed in v0.32

* The `do\_queue` keyword argument in `qml.operation.Operator` has been removed. This affects

all child classes, such as `Operation`, `Observable`, `SymbolicOp` and more. Instead of

setting `do\_queue=False`, use the `qml.QueuingManager.stop\_recording()` context.

	+ Deprecated in v0.31

	+ Removed in v0.32

* The `qml.specs` dictionary longer supports direct key access to certain keys. Instead

these quantities can be accessed as fields of the new `Resources` object saved under

`specs\_dict["resources"]`:

	+ `num\_operations` is no longer supported, use `specs\_dict["resources"].num\_gates`

	+ `num\_used\_wires` is no longer supported, use `specs\_dict["resources"].num\_wires`

	+ `gate\_types` is no longer supported, use `specs\_dict["resources"].gate\_types`

	+ `gate\_sizes` is no longer supported, use `specs\_dict["resources"].gate\_sizes`

	+ `depth` is no longer supported, use `specs\_dict["resources"].depth`These keys were still accessible in v0.31 and removed in v0.32.

* `qml.math.reduced\_dm` has been removed. Please use `qml.math.reduce\_dm` or `qml.math.reduce\_statevector` instead.

	+ Still accessible in v0.31

	+ Removed in v0.32

* `QuantumScript`’s `name` keyword argument and property are removed.

This also affects `QuantumTape` and `OperationRecorder`.

	+ Deprecated in v0.31

	+ Removed in v0.32

* The `Operation.base\_name` property is removed. Please use `Operator.name` or `type(obj).\_\_name\_\_` instead.

	+ Still accessible in v0.31

	+ Removed in v0.32

* `LieAlgebraOptimizer` has been renamed. Please use `RiemannianGradientOptimizer` instead.

	+ Deprecated in v0.31

	+ Removed in v0.32

* The `grouping\_type` and `grouping\_method` arguments of `qchem.molecular\_hamiltonian()` are removed.

	+ Deprecated in v0.31

	+ Removed in v0.32Instead, simply construct a new instance of `Hamiltonian` with the grouping specified:

```

H, qubits = molecular\_hamiltonian(symbols, coordinates)

grouped\_h = qml.Hamiltonian(

    H.coeffs,

    H.ops,

    grouping\_type=grouping\_type,

    groupingmethod=grouping\_method,

)

```

* `zyz\_decomposition` and `xyx\_decomposition` are removed, use `one\_qubit\_decomposition` with a rotations

keyword instead.

	+ Deprecated in v0.31

	+ Removed in v0.32

* The `qml.utils.sparse\_hamiltonian` function has been removed. `~.Hamiltonian.sparse\_matrix` should be used instead.

	+ Deprecated in v0.29

	+ Removed in v0.31

* The `collections` module has been removed.

	+ Deprecated in v0.29

	+ Removed in v0.31

* `qml.op\_sum` has been removed. Users should use `qml.sum` instead.

	+ Deprecated in v0.29.

	+ Removed in v0.31.

* The argument `argnum` for gradient transforms using the Jax interface is replaced by `argnums`.

	+ `argnum` is automatically changed to `argnums` for gradient transforms using JAX and a warning is raised in v0.30

	+ `argnums` is the only option for gradient transforms using JAX in v0.31

* `Evolution` now adds a `-1` to the input parameter. Beforehand, the minus sign was not included.

	+ Transition warning added in v0.29.

	+ Updated to current behaviour in v0.30.

* The `seed\_recipes` argument in `qml.classical\_shadow` and `qml.shadow\_expval` has been removed.

An argument `seed` which defaults to `None` can contain an integer with the wanted seed.

	+ Still accessible in v0.28, v0.29

	+ Removed in v0.30

* The `get\_operation` tape method is updated to return the operation index as well, changing its signature.

	+ The new signature is available by changing the arg `return\_op\_index` to `True` in v0.29

	+ The old signature is replaced with the new one in v0.30

* The `grouping` module has been removed. The functionality has been moved and

reorganized in the new `pauli` module under `pauli/utils.py` or `pauli/grouping/`.

	+ Still accessible in v0.27, v0.28, v0.29, v0.30

	+ Removed in v0.31The functions from `grouping/pauli.py`, `grouping/transformations.py` and

`grouping/utils.py` have been moved to `pauli/utils.py`. The remaining functions

have been consolidated in the `pauli/grouping/` directory.

* `qml.VQECost` is removed.

> 

> 

> 	+ Deprecated in 0.13

> 	+ Removed in 0.29

>

* In-place inversion — `op.inv()` and `op.inverse=value` — is deprecated. Please

use `qml.adjoint` or `qml.pow` instead.

	+ Still accessible in v0.27 and v0.28

	+ Removed in v0.29Don’t use:

```

>>> v1 = qml.PauliX(0).inv()

>>> v2 = qml.PauliX(0)

>>> v2.inverse = True

```

Instead, use:

```

>>> qml.adjoint(qml.PauliX(0))

Adjoint(PauliX(wires=[0]))

>>> qml.pow(qml.PauliX(0), -1)

PauliX(wires=[0])\*\*-1

>>> qml.pow(qml.PauliX(0), -1, lazy=False)

PauliX(wires=[0])

>>> qml.PauliX(0) \*\* -1

PauliX(wires=[0])\*\*-1

```

* The `qml.utils.decompose\_hamiltonian()` method is removed. Please

use `qml.pauli\_decompose()`.

	+ Still accessible in v0.27

	+ Removed in v0.28

* `qml.tape.get\_active\_tape` is deprecated. Please use `qml.QueuingManager.active\_context()` instead.

	+ Deprecated in v0.27

	+ Removed in v0.28

* `qml.transforms.qcut.remap\_tape\_wires` is deprecated. Please use `qml.map\_wires` instead.

	+ Deprecated in v0.27

	+ Removed in v0.28

* `QuantumTape.inv()` is deprecated. Please use `QuantumTape.adjoint()` instead. This method

returns a new tape instead of modifying itself in-place.

	+ Deprecated in v0.27

	+ Removed in v0.28

* `qml.tape.stop\_recording` and `QuantumTape.stop\_recording` are moved to `qml.QueuingManager.stop\_recording`

	+ Deprecated in v0.27

	+ Removed in v0.28

* `QueuingContext` is renamed `QueuingManager`.

	+ Deprecated name `QueuingContext` in v0.27

	+ Removed in v0.28

* `QueuingManager.safe\_update\_info` and `AnnotateQueue.safe\_update\_info` are removed.

	+ Deprecated in v0.27

	+ Removed in v0.28

* `ObservableReturnTypes` `Sample`, `Variance`, `Expectation`, `Probability`, `State`, and `MidMeasure`

are moved to `measurements` from `operation`.

	+ Deprecated in v0.23

	+ Removed in v0.27

* The `qml.utils.expand` function is deprecated. `qml.math.expand\_matrix` should be used

instead.

	+ Deprecated in v0.24

	+ Removed in v0.27

* The `qml.Operation.get\_parameter\_shift` method is removed. Use the methods of the `gradients` module

for general parameter-shift rules instead.

	+ Deprecated in v0.22

	+ Removed in v0.28

* `qml.transforms.measurement\_grouping` has been removed. Please use `qml.transforms.hamiltonian\_expand`

instead.

	+ Deprecated in v0.28

	+ Removed in v0.29

* `qml.transforms.make\_tape` was previously deprecated, but there is no longer a plan to remove it.

It no longer raises a warning, and the functionality is unchanged.

	+ Deprecated in v0.28

	+ Un-deprecated in v0.29

### Release notes[¶](#release-notes "Permalink to this headline")

This page contains the release notes for PennyLane.

orphan

#### Release 0.32.0 (current release)[¶](#release-0-32-0-current-release "Permalink to this headline")

### New features since last release

#### Encode matrices using a linear combination of unitaries ⛓️️

* It is now possible to encode an operator `A` into a quantum circuit by decomposing it into

a linear combination of unitaries using PREP

([qml.StatePrep](https://docs.pennylane.ai/en/stable/code/api/pennylane.StatePrep.html)) and

SELECT ([qml.Select](https://docs.pennylane.ai/en/stable/code/api/pennylane.Select.html))

routines.

[(#4431)](https://github.com/PennyLaneAI/pennylane/pull/4431)

[(#4437)](https://github.com/PennyLaneAI/pennylane/pull/4437)

[(#4444)](https://github.com/PennyLaneAI/pennylane/pull/4444)

[(#4450)](https://github.com/PennyLaneAI/pennylane/pull/4450)

[(#4506)](https://github.com/PennyLaneAI/pennylane/pull/4506)

[(#4526)](https://github.com/PennyLaneAI/pennylane/pull/4526)

Consider an operator `A` composed of a linear combination of Pauli terms:

```

>>> A = qml.PauliX(2) + 2 \* qml.PauliY(2) + 3 \* qml.PauliZ(2)

```

A decomposable block-encoding circuit can be created:

```

def block\_encode(A, control\_wires):

    probs = A.coeffs / np.sum(A.coeffs)

    state = np.pad(np.sqrt(probs, dtype=complex), (0, 1))

    unitaries = A.ops

    qml.StatePrep(state, wires=control\_wires)

    qml.Select(unitaries, control=control\_wires)

    qml.adjoint(qml.StatePrep)(state, wires=control\_wires)

```

```

>>> print(qml.draw(block\_encode, show\_matrices=False)(A, control\_wires=[0, 1]))

0: ─╭|Ψ⟩─╭Select─╭|Ψ⟩†─┤

1: ─╰|Ψ⟩─├Select─╰|Ψ⟩†─┤

2: ──────╰Select───────┤

```

This circuit can be used as a building block within a larger QNode to perform algorithms such as

[QSVT](https://docs.pennylane.ai/en/stable/code/api/pennylane.QSVT.html) and [Hamiltonian simulation](https://codebook.xanadu.ai/H.6).

* Decomposing a Hermitian matrix into a linear combination of Pauli words via `qml.pauli\_decompose` is

now faster and differentiable.

[(#4395)](https://github.com/PennyLaneAI/pennylane/pull/4395)

[(#4479)](https://github.com/PennyLaneAI/pennylane/pull/4479)

[(#4493)](https://github.com/PennyLaneAI/pennylane/pull/4493)

```

def find\_coeffs(p):

    mat = np.array([[3, p], [p, 3]])

    A = qml.pauli\_decompose(mat)

    return A.coeffs

```

```

>>> import jax

>>> from jax import numpy as np

>>> jax.jacobian(find\_coeffs)(np.array(2.))

Array([0., 1.], dtype=float32, weak\_type=True)

```

#### Monitor PennyLane's inner workings with logging 📃

* Python-native logging can now be enabled with `qml.logging.enable\_logging()`.

[(#4377)](https://github.com/PennyLaneAI/pennylane/pull/4377)

[(#4383)](https://github.com/PennyLaneAI/pennylane/pull/4383)

Consider the following code that is contained in `my\_code.py`:

```

import pennylane as qml

qml.logging.enable\_logging()  # enables logging

dev = qml.device("default.qubit", wires=2)

@qml.qnode(dev)

def f(x):

    qml.RX(x, wires=0)

    return qml.state()

f(0.5)

```

Executing `my\_code.py` with logging enabled will detail every step in PennyLane’s

pipeline that gets used to run your code.

```

$ python my_code.py

[1967-02-13 15:18:38,591][DEBUG][<PID 8881:MainProcess>] - pennylane.qnode.__init__()::"Creating QNode(func=<function f at 0x7faf2a6fbaf0>, device=<DefaultQubit device (wires=2, shots=None) at 0x7faf2a689b50>, interface=auto, diff_method=best, expansion_strategy=gradient, max_expansion=10, grad_on_execution=best, mode=None, cache=True, cachesize=10000, max_diff=1, gradient_kwargs={}"

...

```

Additional logging configuration settings can be specified by modifying the contents of the logging

configuration file, which can be located by running `qml.logging.config\_path()`. Follow our

[logging docs page](https://docs.pennylane.ai/en/latest/introduction/logging.html) for more

details!

#### More input states for quantum chemistry calculations ⚛️

* Input states obtained from advanced quantum chemistry calculations can be used in a circuit.

[(#4427)](https://github.com/PennyLaneAI/pennylane/pull/4427)

[(#4433)](https://github.com/PennyLaneAI/pennylane/pull/4433)

[(#4461)](https://github.com/PennyLaneAI/pennylane/pull/4461)

[(#4476)](https://github.com/PennyLaneAI/pennylane/pull/4476)

[(#4505)](https://github.com/PennyLaneAI/pennylane/pull/4505)

Quantum chemistry calculations rely on an initial state that is typically selected to be the

trivial Hartree-Fock state. For molecules with a complicated electronic structure, using initial

states obtained from affordable post-Hartree-Fock calculations helps to improve the efficiency of

the quantum simulations. These calculations can be done with external quantum chemistry libraries

such as PySCF.

It is now possible to import a PySCF solver object in PennyLane and extract the corresponding

wave function in the form of a state vector that can be directly used in a circuit. First, perform

your classical quantum chemistry calculations and then use the

[qml.qchem.import\_state](https://docs.pennylane.ai/en/stable/code/api/pennylane.qchem.import_state.html)

function to import the solver object and return a state vector.

```

 >>> from pyscf import gto, scf, ci

 >>> mol = gto.M(atom=[['H', (0, 0, 0)], ['H', (0,0,0.71)]], basis='sto6g')

 >>> myhf = scf.UHF(mol).run()

 >>> myci = ci.UCISD(myhf).run()

 >>> wf\_cisd = qml.qchem.import\_state(myci, tol=1e-1)

 >>> print(wf\_cisd)

 [ 0. +0.j 0. +0.j 0. +0.j 0.1066467 +0.j

 1. +0.j 0. +0.j 0. +0.j 0. +0.j

 2. +0.j 0. +0.j 0. +0.j 0. +0.j

 -0.99429698+0.j 0. +0.j 0. +0.j 0. +0.j]

The state vector can be implemented in a circuit using ``qml.StatePrep``.

```

```

 >>> dev = qml.device('default.qubit', wires=4)

 >>> @qml.qnode(dev)

 ... def circuit():

 ... qml.StatePrep(wf\_cisd, wires=range(4))

 ... return qml.state()

 >>> print(circuit())

 [ 0. +0.j 0. +0.j 0. +0.j 0.1066467 +0.j

 1. +0.j 0. +0.j 0. +0.j 0. +0.j

 2. +0.j 0. +0.j 0. +0.j 0. +0.j

 -0.99429698+0.j 0. +0.j 0. +0.j 0. +0.j]

The currently supported post-Hartree-Fock methods are RCISD, UCISD, RCCSD, and UCCSD which

denote restricted (R) and unrestricted (U) configuration interaction (CI) and coupled cluster (CC)

calculations with single and double (SD) excitations.

```

#### Reuse and reset qubits after mid-circuit measurements ♻️

* PennyLane now allows you to define circuits that reuse a qubit after a mid-circuit

measurement has taken place. Optionally, the wire can also be reset to the \(|0\rangle\)

state.

[(#4402)](https://github.com/PennyLaneAI/pennylane/pull/4402)

[(#4432)](https://github.com/PennyLaneAI/pennylane/pull/4432)

Post-measurement reset can be activated by setting `reset=True` when calling

[qml.measure](https://docs.pennylane.ai/en/stable/code/api/pennylane.measure.html).

In this version of PennyLane, executing circuits with qubit reuse will result in the

[defer\_measurements](https://docs.pennylane.ai/en/latest/code/api/pennylane.defer_measurements.html)

transform being applied. This transform replaces each reused wire with an *additional* qubit.

However, future releases of PennyLane will explore device-level support for qubit reuse without

consuming additional qubits.

Qubit reuse and reset is also fully differentiable:

```

dev = qml.device("default.qubit", wires=4)

@qml.qnode(dev)

def circuit(p):

    qml.RX(p, wires=0)

    m = qml.measure(0, reset=True)

    qml.cond(m, qml.Hadamard)(1)

    qml.RX(p, wires=0)

    m = qml.measure(0)

    qml.cond(m, qml.Hadamard)(1)

    return qml.expval(qml.PauliZ(1))

```

```

>>> jax.grad(circuit)(0.4)

Array(-0.35867804, dtype=float32, weak\_type=True)

```

You can read more about mid-circuit measurements

[in the documentation](https://docs.pennylane.ai/en/latest/introduction/measurements.html#mid-circuit-measurements-and-conditional-operations),

and stay tuned for more mid-circuit measurement features in the next few releases!

### Improvements 🛠

#### A new PennyLane drawing style

* Circuit drawings and plots can now be created following a PennyLane style.

[(#3950)](https://github.com/PennyLaneAI/pennylane/pull/3950)

The `qml.draw\_mpl` function accepts a `style='pennylane'` argument to create PennyLane themed

circuit diagrams:

```

def circuit(x, z):

    qml.QFT(wires=(0,1,2,3))

    qml.Toffoli(wires=(0,1,2))

    qml.CSWAP(wires=(0,2,3))

    qml.RX(x, wires=0)

    qml.CRZ(z, wires=(3,0))

    return qml.expval(qml.PauliZ(0))

qml.draw\_mpl(circuit, style="pennylane")(1, 1)

```

![](https://docs.pennylane.ai/en/stable/_images/pennylane_style.png)

PennyLane-styled plots can also be drawn by passing `"pennylane.drawer.plot"` to Matplotlib’s

`plt.style.use` function:

```

import matplotlib.pyplot as plt

plt.style.use("pennylane.drawer.plot")

for i in range(3):

    plt.plot(np.random.rand(10))

```

If the font

[Quicksand Bold](https://fonts.google.com/specimen/Quicksand) isn’t available,

an available default font is used instead.

#### Making operators immutable and PyTrees

* Any class inheriting from `Operator` is now automatically registered as a pytree with JAX.

This unlocks the ability to jit functions of `Operator`.

[(#4458)](https://github.com/PennyLaneAI/pennylane/pull/4458/)

```

>>> op = qml.adjoint(qml.RX(1.0, wires=0))

>>> jax.jit(qml.matrix)(op)

Array([[0.87758255-0.j , 0. +0.47942555j],

 [0. +0.47942555j, 0.87758255-0.j ]], dtype=complex64, weak\_type=True)

>>> jax.tree\_util.tree\_map(lambda x: x+1, op)

Adjoint(RX(2.0, wires=[0]))

```

* All `Operator` objects now define `Operator.\_flatten` and `Operator.\_unflatten` methods that separate

trainable from untrainable components. These methods will be used in serialization and pytree registration.

Custom operations may need an update to ensure compatibility with new PennyLane features.

[(#4483)](https://github.com/PennyLaneAI/pennylane/pull/4483)

[(#4314)](https://github.com/PennyLaneAI/pennylane/pull/4314)

* The `QuantumScript` class now has a `bind\_new\_parameters` method that allows creation of

new `QuantumScript` objects with the provided parameters.

[(#4345)](https://github.com/PennyLaneAI/pennylane/pull/4345)

* The `qml.gradients` module no longer mutates operators in-place for any gradient transforms.

Instead, operators that need to be mutated are copied with new parameters.

[(#4220)](https://github.com/PennyLaneAI/pennylane/pull/4220)

* PennyLane no longer directly relies on `Operator.\_\_eq\_\_`.

[(#4398)](https://github.com/PennyLaneAI/pennylane/pull/4398)

* `qml.equal` no longer raises errors when operators or measurements of different types are compared.

Instead, it returns `False`.

[(#4315)](https://github.com/PennyLaneAI/pennylane/pull/4315)

#### Transforms

* Transform programs are now integrated with the QNode.

[(#4404)](https://github.com/PennyLaneAI/pennylane/pull/4404)

```

def null\_postprocessing(results: qml.typing.ResultBatch) -> qml.typing.Result:

    return results[0]

@qml.transforms.core.transform

def scale\_shots(tape: qml.tape.QuantumTape, shot\_scaling) -> (Tuple[qml.tape.QuantumTape], Callable):

    new\_shots = tape.shots.total\_shots \* shot\_scaling

    new\_tape = qml.tape.QuantumScript(tape.operations, tape.measurements, shots=new\_shots)

    return (new\_tape, ), null\_postprocessing

dev = qml.devices.experimental.DefaultQubit2()

@partial(scale\_shots, shot\_scaling=2)

@qml.qnode(dev, interface=None)

def circuit():

    return qml.sample(wires=0)

```

```

>>> circuit(shots=1)

array([False, False])

```

* Transform Programs, `qml.transforms.core.TransformProgram`, can now be called on a batch of circuits

and return a new batch of circuits and a single post processing function.

[(#4364)](https://github.com/PennyLaneAI/pennylane/pull/4364)

* `TransformDispatcher` now allows registration of custom QNode transforms.

[(#4466)](https://github.com/PennyLaneAI/pennylane/pull/4466)

* QNode transforms in `qml.qinfo` now support custom wire labels.

[#4331](https://github.com/PennyLaneAI/pennylane/pull/4331)

* `qml.transforms.adjoint\_metric\_tensor` now uses the simulation tools in `qml.devices.qubit` instead of

private methods of `qml.devices.DefaultQubit`.

[(#4456)](https://github.com/PennyLaneAI/pennylane/pull/4456)

* Auxiliary wires and device wires are now treated the same way in `qml.transforms.metric\_tensor`

as in `qml.gradients.hadamard\_grad`. All valid wire input formats for `aux\_wire` are supported.

[(#4328)](https://github.com/PennyLaneAI/pennylane/pull/4328)

#### Next-generation device API

* The experimental device interface has been integrated with the QNode for JAX, JAX-JIT, TensorFlow and PyTorch.

[(#4323)](https://github.com/PennyLaneAI/pennylane/pull/4323)

[(#4352)](https://github.com/PennyLaneAI/pennylane/pull/4352)

[(#4392)](https://github.com/PennyLaneAI/pennylane/pull/4392)

[(#4393)](https://github.com/PennyLaneAI/pennylane/pull/4393)

* The experimental `DefaultQubit2` device now supports computing VJPs and JVPs using the adjoint method.

[(#4374)](https://github.com/PennyLaneAI/pennylane/pull/4374)

* New functions called `adjoint\_jvp` and `adjoint\_vjp` that compute the JVP and VJP of a tape using the adjoint method

have been added to `qml.devices.qubit.adjoint\_jacobian`

[(#4358)](https://github.com/PennyLaneAI/pennylane/pull/4358)

* `DefaultQubit2` now accepts a `max\_workers` argument which controls multiprocessing.

A `ProcessPoolExecutor` executes tapes asynchronously

using a pool of at most `max\_workers` processes. If `max\_workers` is `None`

or not given, only the current process executes tapes. If you experience any

issue, say using JAX, TensorFlow, Torch, try setting `max\_workers` to `None`.

[(#4319)](https://github.com/PennyLaneAI/pennylane/pull/4319)

[(#4425)](https://github.com/PennyLaneAI/pennylane/pull/4425)

* `qml.devices.experimental.Device` now accepts a shots keyword argument and has a `shots`

property. This property is only used to set defaults for a workflow, and does not directly

influence the number of shots used in executions or derivatives.

[(#4388)](https://github.com/PennyLaneAI/pennylane/pull/4388)

* `expand\_fn()` for `DefaultQubit2` has been updated to decompose `StatePrep` operations present in the middle of a circuit.

[(#4444)](https://github.com/PennyLaneAI/pennylane/pull/4444)

* If no seed is specified on initialization with `DefaultQubit2`, the local random number generator will be

seeded from NumPy’s global random number generator.

[(#4394)](https://github.com/PennyLaneAI/pennylane/pull/4394)

#### Improvements to machine learning library interfaces

* `pennylane/interfaces` has been refactored. The `execute\_fn` passed to the machine learning framework boundaries

is now responsible for converting parameters to NumPy. The gradients module can now handle TensorFlow parameters,

but gradient tapes now retain the original `dtype` instead of converting to `float64`. This may cause instability

with finite-difference differentiation and `float32` parameters. The machine learning boundary functions are now uncoupled from their legacy counterparts.

[(#4415)](https://github.com/PennyLaneAI/pennylane/pull/4415)

* `qml.interfaces.set\_shots` now accepts a `Shots` object as well as `int`‘s and tuples of `int`‘s.

[(#4388)](https://github.com/PennyLaneAI/pennylane/pull/4388)

* Readability improvements and stylistic changes have been made to `pennylane/interfaces/jax\_jit\_tuple.py`

[(#4379)](https://github.com/PennyLaneAI/pennylane/pull/4379/)

#### Pulses

* A `HardwareHamiltonian` can now be summed with `int` or `float` objects.

A sequence of `HardwareHamiltonian`s can now be summed via the builtin `sum`.

[(#4343)](https://github.com/PennyLaneAI/pennylane/pull/4343)

* `qml.pulse.transmon\_drive` has been updated in accordance with [1904.06560](https://arxiv.org/abs/1904.06560).

In particular, the functional form has been changed from

\(\Omega(t)(\cos(\omega\_d t + \phi) X - \sin(\omega\_d t + \phi) Y)$ to $\Omega(t) \sin(\omega\_d t + \phi) Y\).

[(#4418)](https://github.com/PennyLaneAI/pennylane/pull/4418/)

[(#4465)](https://github.com/PennyLaneAI/pennylane/pull/4465/)

[(#4478)](https://github.com/PennyLaneAI/pennylane/pull/4478/)

[(#4418)](https://github.com/PennyLaneAI/pennylane/pull/4418/)

#### Other improvements

* The `qchem` module has been upgraded to use the fermionic operators of the `fermi` module.

[#4336](https://github.com/PennyLaneAI/pennylane/pull/4336)

[#4521](https://github.com/PennyLaneAI/pennylane/pull/4521)

* The calculation of `Sum`, `Prod`, `SProd`, `PauliWord`, and `PauliSentence` sparse matrices

are orders of magnitude faster.

[(#4475)](https://github.com/PennyLaneAI/pennylane/pull/4475)

[(#4272)](https://github.com/PennyLaneAI/pennylane/pull/4272)

[(#4411)](https://github.com/PennyLaneAI/pennylane/pull/4411)

* A function called `qml.math.fidelity\_statevector` that computes the fidelity between two state vectors has been added.

[(#4322)](https://github.com/PennyLaneAI/pennylane/pull/4322)

* `qml.ctrl(qml.PauliX)` returns a `CNOT`, `Toffoli`, or `MultiControlledX` operation instead of `Controlled(PauliX)`.

[(#4339)](https://github.com/PennyLaneAI/pennylane/pull/4339)

* When given a callable, `qml.ctrl` now does its custom pre-processing on all queued operators from the callable.

[(#4370)](https://github.com/PennyLaneAI/pennylane/pull/4370)

* The `qchem` functions `primitive\_norm` and `contracted\_norm` have been modified to be compatible with

higher versions of SciPy. The private function `\_fac2` for computing double factorials has also been added.

[#4321](https://github.com/PennyLaneAI/pennylane/pull/4321)

* `tape\_expand` now uses `Operator.decomposition` instead of `Operator.expand` in order to make

more performant choices.

[(#4355)](https://github.com/PennyLaneAI/pennylane/pull/4355)

* CI now runs tests with TensorFlow 2.13.0

[(#4472)](https://github.com/PennyLaneAI/pennylane/pull/4472)

* All tests in CI and pre-commit hooks now enable linting.

[(#4335)](https://github.com/PennyLaneAI/pennylane/pull/4335)

* The default label for a `StatePrepBase` operator is now `|Ψ⟩`.

[(#4340)](https://github.com/PennyLaneAI/pennylane/pull/4340)

* `Device.default\_expand\_fn()` has been updated to decompose `qml.StatePrep` operations present in the middle of a provided circuit.

[(#4437)](https://github.com/PennyLaneAI/pennylane/pull/4437)

* `QNode.construct` has been updated to only apply the `qml.defer\_measurements` transform if the device

does not natively support mid-circuit measurements.

[(#4516)](https://github.com/PennyLaneAI/pennylane/pull/4516)

* The application of the `qml.defer\_measurements` transform has been moved from

`QNode.construct` to `qml.Device.batch\_transform` to allow more fine-grain

control over when `defer\_measurements` should be used.

[(#4432)](https://github.com/PennyLaneAI/pennylane/pull/4432)

* The label for `ParametrizedEvolution` can display parameters with the requested format as set by the

kwarg `decimals`. Array-like parameters are displayed in the same format as matrices and stored in the

cache.

[(#4151)](https://github.com/PennyLaneAI/pennylane/pull/4151)

### Breaking changes 💔

* Applying gradient transforms to broadcasted/batched tapes has been deactivated until it is consistently

supported for QNodes as well.

[(#4480)](https://github.com/PennyLaneAI/pennylane/pull/4480)

* Gradient transforms no longer implicitly cast `float32` parameters to `float64`. Finite difference differentiation

with `float32` parameters may no longer give accurate results.

[(#4415)](https://github.com/PennyLaneAI/pennylane/pull/4415)

* The `do\_queue` keyword argument in `qml.operation.Operator` has been removed. Instead of

setting `do\_queue=False`, use the `qml.QueuingManager.stop\_recording()` context.

[(#4317)](https://github.com/PennyLaneAI/pennylane/pull/4317)

* `Operator.expand` now uses the output of `Operator.decomposition` instead of what it queues.

[(#4355)](https://github.com/PennyLaneAI/pennylane/pull/4355)

* The gradients module no longer needs shot information passed to it explicitly, as the shots are on the tapes.

[(#4448)](https://github.com/PennyLaneAI/pennylane/pull/4448)

* `qml.StatePrep` has been renamed to `qml.StatePrepBase` and `qml.QubitStateVector` has been renamed to `qml.StatePrep`.

`qml.operation.StatePrep` and `qml.QubitStateVector` are still accessible.

[(#4450)](https://github.com/PennyLaneAI/pennylane/pull/4450)

* Support for Python 3.8 has been dropped.

[(#4453)](https://github.com/PennyLaneAI/pennylane/pull/4453)

* `MeasurementValue`‘s signature has been updated to accept a list of `MidMeasureMP`‘s rather than a list of

their IDs.

[(#4446)](https://github.com/PennyLaneAI/pennylane/pull/4446)

* The `grouping\_type` and `grouping\_method` keyword arguments have been removed from `qchem.molecular\_hamiltonian`.

[(#4301)](https://github.com/PennyLaneAI/pennylane/pull/4301)

* `zyz\_decomposition` and `xyx\_decomposition` have been removed. Use `one\_qubit\_decomposition` instead.

[(#4301)](https://github.com/PennyLaneAI/pennylane/pull/4301)

* `LieAlgebraOptimizer` has been removed. Use `RiemannianGradientOptimizer` instead.

[(#4301)](https://github.com/PennyLaneAI/pennylane/pull/4301)

* `Operation.base\_name` has been removed.

[(#4301)](https://github.com/PennyLaneAI/pennylane/pull/4301)

* `QuantumScript.name` has been removed.

[(#4301)](https://github.com/PennyLaneAI/pennylane/pull/4301)

* `qml.math.reduced\_dm` has been removed. Use `qml.math.reduce\_dm` or `qml.math.reduce\_statevector` instead.

[(#4301)](https://github.com/PennyLaneAI/pennylane/pull/4301)

* The `qml.specs` dictionary no longer supports direct key access to certain keys.

[(#4301)](https://github.com/PennyLaneAI/pennylane/pull/4301)

Instead, these quantities can be accessed as fields of the new `Resources` object saved under

`specs\_dict["resources"]`:

	+ `num\_operations` is no longer supported, use `specs\_dict["resources"].num\_gates`

	+ `num\_used\_wires` is no longer supported, use `specs\_dict["resources"].num\_wires`

	+ `gate\_types` is no longer supported, use `specs\_dict["resources"].gate\_types`

	+ `gate\_sizes` is no longer supported, use `specs\_dict["resources"].gate\_sizes`

	+ `depth` is no longer supported, use `specs\_dict["resources"].depth`

* `qml.math.purity`, `qml.math.vn\_entropy`, `qml.math.mutual\_info`, `qml.math.fidelity`,

`qml.math.relative\_entropy`, and `qml.math.max\_entropy` no longer support state vectors as

input.

[(#4322)](https://github.com/PennyLaneAI/pennylane/pull/4322)

* The private `QuantumScript.\_prep` list has been removed, and prep operations now go into the `\_ops` list.

[(#4485)](https://github.com/PennyLaneAI/pennylane/pull/4485)

### Deprecations 👋

* `qml.enable\_return` and `qml.disable\_return` have been deprecated. Please avoid calling

`disable\_return`, as the old return system has been deprecated along with these switch functions.

[(#4316)](https://github.com/PennyLaneAI/pennylane/pull/4316)

* `qml.qchem.jordan\_wigner` has been deprecated. Use `qml.jordan\_wigner` instead.

List input to define the fermionic operator has also been deprecated; the fermionic

operators in the `qml.fermi` module should be used instead.

[(#4332)](https://github.com/PennyLaneAI/pennylane/pull/4332)

* The `qml.RandomLayers.compute\_decomposition` keyword argument `ratio\_imprimitive` will be changed to `ratio\_imprim` to

match the call signature of the operation.

[(#4314)](https://github.com/PennyLaneAI/pennylane/pull/4314)

* The CV observables `qml.X` and `qml.P` have been deprecated. Use `qml.QuadX`

and `qml.QuadP` instead.

[(#4330)](https://github.com/PennyLaneAI/pennylane/pull/4330)

* The method `tape.unwrap()` and corresponding `UnwrapTape` and `Unwrap` classes

have been deprecated. Use `convert\_to\_numpy\_parameters` instead.

[(#4344)](https://github.com/PennyLaneAI/pennylane/pull/4344)

* The `mode` keyword argument in QNode has been deprecated, as it was only used in the

old return system (which has also been deprecated). Please use `grad\_on\_execution` instead.

[(#4316)](https://github.com/PennyLaneAI/pennylane/pull/4316)

* The `QuantumScript.set\_parameters` method and the `QuantumScript.data` setter have

been deprecated. Please use `QuantumScript.bind\_new\_parameters` instead.

[(#4346)](https://github.com/PennyLaneAI/pennylane/pull/4346)

* The `\_\_eq\_\_` and `\_\_hash\_\_` dunder methods of `Operator` and `MeasurementProcess` will now raise

warnings to reflect upcoming changes to operator and measurement process equality and hashing.

[(#4144)](https://github.com/PennyLaneAI/pennylane/pull/4144)

[(#4454)](https://github.com/PennyLaneAI/pennylane/pull/4454)

[(#4489)](https://github.com/PennyLaneAI/pennylane/pull/4489)

[(#4498)](https://github.com/PennyLaneAI/pennylane/pull/4498)

* The `sampler\_seed` argument of `qml.gradients.spsa\_grad` has been deprecated, along with a bug

fix of the seed-setting behaviour.

Instead, the `sampler\_rng` argument should be set, either to an integer value, which will be used

to create a PRNG internally or to a NumPy pseudo-random number generator created via

`np.random.default\_rng(seed)`.

[(4165)](https://github.com/PennyLaneAI/pennylane/pull/4165)

### Documentation 📝

* The `qml.pulse.transmon\_interaction` and `qml.pulse.transmon\_drive` documentation has been updated.

[#4327](https://github.com/PennyLaneAI/pennylane/pull/4327)

* `qml.ApproxTimeEvolution.compute\_decomposition()` now has a code example.

[(#4354)](https://github.com/PennyLaneAI/pennylane/pull/4354)

* The documentation for `qml.devices.experimental.Device` has been improved to clarify

some aspects of its use.

[(#4391)](https://github.com/PennyLaneAI/pennylane/pull/4391)

* Input types and sources for operators in `qml.import\_operator` are specified.

[(#4476)](https://github.com/PennyLaneAI/pennylane/pull/4476)

### Bug fixes 🐛

* `qml.Projector` is pickle-able again.

[(#4452)](https://github.com/PennyLaneAI/pennylane/pull/4452)

* `\_copy\_and\_shift\_params` does not cast or convert integral types, just relying on `+` and `\*`‘s casting rules in this case.

[(#4477)](https://github.com/PennyLaneAI/pennylane/pull/4477)

* Sparse matrix calculations of `SProd`s containing a `Tensor` are now allowed. When using

`Tensor.sparse\_matrix()`, it is recommended to use the `wire\_order` keyword argument over `wires`.

[(#4424)](https://github.com/PennyLaneAI/pennylane/pull/4424)

* `op.adjoint` has been replaced with `qml.adjoint` in `QNSPSAOptimizer`.

[(#4421)](https://github.com/PennyLaneAI/pennylane/pull/4421)

* `jax.ad` (deprecated) has been replaced by `jax.interpreters.ad`.

[(#4403)](https://github.com/PennyLaneAI/pennylane/pull/4403)

* `metric\_tensor` stops accidentally catching errors that stem from

flawed wires assignments in the original circuit, leading to recursion errors.

[(#4328)](https://github.com/PennyLaneAI/pennylane/pull/4328)

* A warning is now raised if control indicators are hidden when calling `qml.draw\_mpl`

[(#4295)](https://github.com/PennyLaneAI/pennylane/pull/4295)

* `qml.qinfo.purity` now produces correct results with custom wire labels.

[(#4331)](https://github.com/PennyLaneAI/pennylane/pull/4331)

* `default.qutrit` now supports all qutrit operations used with `qml.adjoint`.

[(#4348)](https://github.com/PennyLaneAI/pennylane/pull/4348)

* The observable data of `qml.GellMann` now includes its index, allowing correct comparison

between instances of `qml.GellMann`, as well as Hamiltonians and Tensors

containing `qml.GellMann`.

[(#4366)](https://github.com/PennyLaneAI/pennylane/pull/4366)

* `qml.transforms.merge\_amplitude\_embedding` now works correctly when the `AmplitudeEmbedding`s

have a batch dimension.

[(#4353)](https://github.com/PennyLaneAI/pennylane/pull/4353)

* The `jordan\_wigner` function has been modified to work with Hamiltonians built with an active space.

[(#4372)](https://github.com/PennyLaneAI/pennylane/pull/4372)

* When a `style` option is not provided, `qml.draw\_mpl` uses the current style set from

`qml.drawer.use\_style` instead of `black\_white`.

[(#4357)](https://github.com/PennyLaneAI/pennylane/pull/4357)

* `qml.devices.qubit.preprocess.validate\_and\_expand\_adjoint` no longer sets the

trainable parameters of the expanded tape.

[(#4365)](https://github.com/PennyLaneAI/pennylane/pull/4365)

* `qml.default\_expand\_fn` now selectively expands operations or measurements allowing more

operations to be executed in circuits when measuring non-qwc Hamiltonians.

[(#4401)](https://github.com/PennyLaneAI/pennylane/pull/4401)

* `qml.ControlledQubitUnitary` no longer reports `has\_decomposition` as `True` when it does

not really have a decomposition.

[(#4407)](https://github.com/PennyLaneAI/pennylane/pull/4407)

* `qml.transforms.split\_non\_commuting` now correctly works on tapes containing both `expval`

and `var` measurements.

[(#4426)](https://github.com/PennyLaneAI/pennylane/pull/4426)

* Subtracting a `Prod` from another operator now works as expected.

[(#4441)](https://github.com/PennyLaneAI/pennylane/pull/4441)

* The `sampler\_seed` argument of `qml.gradients.spsa\_grad` has been changed to `sampler\_rng`. One can either provide

an integer, which will be used to create a PRNG internally. Previously, this lead to the same direction

being sampled, when `num\_directions` is greater than 1. Alternatively, one can provide a NumPy PRNG,

which allows reproducibly calling `spsa\_grad` without getting the same results every time.

[(4165)](https://github.com/PennyLaneAI/pennylane/pull/4165)

[(4482)](https://github.com/PennyLaneAI/pennylane/pull/4482)

* `qml.math.get\_dtype\_name` now works with autograd array boxes.

[(#4494)](https://github.com/PennyLaneAI/pennylane/pull/4494)

* The backprop gradient of `qml.math.fidelity` is now correct.

[(#4380)](https://github.com/PennyLaneAI/pennylane/pull/4380)

### Contributors ✍️

This release contains contributions from (in alphabetical order):

Utkarsh Azad,

Thomas Bromley,

Isaac De Vlugt,

Amintor Dusko,

Stepan Fomichev,

Lillian M. A. Frederiksen,

Soran Jahangiri,

Edward Jiang,

Korbinian Kottmann,

Ivana Kurečić,

Christina Lee,

Vincent Michaud-Rioux,

Romain Moyard,

Lee James O’Riordan,

Mudit Pandey,

Borja Requena,

Matthew Silverman,

Jay Soni,

David Wierichs,

Frederik Wilde.

orphan

#### Release 0.31.0[¶](#release-0-31-0 "Permalink to this headline")

### New features since last release

#### Seamlessly create and combine fermionic operators 🔬

* Fermionic operators and arithmetic are now available.

[(#4191)](https://github.com/PennyLaneAI/pennylane/pull/4191)

[(#4195)](https://github.com/PennyLaneAI/pennylane/pull/4195)

[(#4200)](https://github.com/PennyLaneAI/pennylane/pull/4200)

[(#4201)](https://github.com/PennyLaneAI/pennylane/pull/4201)

[(#4209)](https://github.com/PennyLaneAI/pennylane/pull/4209)

[(#4229)](https://github.com/PennyLaneAI/pennylane/pull/4229)

[(#4253)](https://github.com/PennyLaneAI/pennylane/pull/4253)

[(#4255)](https://github.com/PennyLaneAI/pennylane/pull/4255)

[(#4262)](https://github.com/PennyLaneAI/pennylane/pull/4262)

[(#4278)](https://github.com/PennyLaneAI/pennylane/pull/4278)

There are a couple of ways to create fermionic operators with this new feature:

	+ `qml.FermiC` and `qml.FermiA`: the

	[fermionic creation](https://docs.pennylane.ai/en/stable/code/api/pennylane.FermiC.html) and

	[annihilation operators](https://docs.pennylane.ai/en/stable/code/api/pennylane.FermiA.html),

	respectively. These operators are

	defined by passing the index of the orbital that the fermionic operator acts on. For instance,

	the operators `a⁺(0)` and `a(3)` are respectively constructed as

	

	

	

	```

	>>> qml.FermiC(0)

	a⁺(0)

	>>> qml.FermiA(3)

	a(3)

	

	```

	

	

	These operators can be composed with (`\*`) and linearly combined with (`+` and `-`) other Fermi operators

	to create arbitrary fermionic Hamiltonians. Multiplying several Fermi operators together creates an operator that we call a Fermi word:

	

	

	

	```

	>>> word = qml.FermiC(0) \* qml.FermiA(0) \* qml.FermiC(3) \* qml.FermiA(3)

	>>> word

	a⁺(0) a(0) a⁺(3) a(3)

	

	```

	

	

	Fermi words can be linearly combined to create a fermionic operator that we call a Fermi sentence:

	

	

	

	```

	>>> sentence = 1.2 \* word - 0.345 \* qml.FermiC(3) \* qml.FermiA(3)

	>>> sentence

	1.2 \* a⁺(0) a(0) a⁺(3) a(3)

	- 0.345 \* a⁺(3) a(3)

	

	```

	+ via [qml.fermi.from\_string](https://docs.pennylane.ai/en/stable/code/api/pennylane.fermi.from_string.html): create a fermionic operator that represents multiple creation and annihilation operators being

	multiplied by each other (a Fermi word).

	

	

	

	```

	>>> qml.fermi.from\_string('0+ 1- 0+ 1-')

	a⁺(0) a(1) a⁺(0) a(1)

	>>> qml.fermi.from\_string('0^ 1 0^ 1')

	a⁺(0) a(1) a⁺(0) a(1)

	

	```

	

	

	Fermi words created with `from\_string` can also be linearly combined to create a Fermi sentence:

	

	

	

	```

	>>> word1 = qml.fermi.from\_string('0+ 0- 3+ 3-')

	>>> word2 = qml.fermi.from\_string('3+ 3-')

	>>> sentence = 1.2 \* word1 + 0.345 \* word2

	>>> sentence

	1.2 \* a⁺(0) a(0) a⁺(3) a(3)

	+ 0.345 \* a⁺(3) a(3)

	

	```Additionally, any fermionic operator, be it a single fermionic creation/annihilation operator, a Fermi word, or a Fermi sentence,

can be mapped to the qubit basis by using [qml.jordan\_wigner](https://docs.pennylane.ai/en/stable/code/api/pennylane.jordan_wigner.html):

```

>>> qml.jordan\_wigner(sentence)

((0.4725+0j)\*(Identity(wires=[0]))) + ((-0.4725+0j)\*(PauliZ(wires=[3]))) + ((-0.3+0j)\*(PauliZ(wires=[0]))) + ((0.3+0j)\*(PauliZ(wires=[0]) @ PauliZ(wires=[3])))

```

Learn how to create fermionic Hamiltonians describing some simple chemical systems by checking

out our [fermionic operators demo](https://pennylane.ai/qml/demos/tutorial_fermionic_operators)!

#### Workflow-level resource estimation 🧮

* PennyLane’s [Tracker](https://docs.pennylane.ai/en/stable/code/api/pennylane.Tracker.html) now

monitors the resource requirements of circuits being executed by the device.

[(#4045)](https://github.com/PennyLaneAI/pennylane/pull/4045)

[(#4110)](https://github.com/PennyLaneAI/pennylane/pull/4110)

Suppose we have a workflow that involves executing circuits with different qubit numbers. We

can obtain the resource requirements as a function of the number of qubits by executing the

workflow with the `Tracker` context:

```

dev = qml.device("default.qubit", wires=4)

@qml.qnode(dev)

def circuit(n\_wires):

    for i in range(n\_wires):

        qml.Hadamard(i)

    return qml.probs(range(n\_wires))

with qml.Tracker(dev) as tracker:

    for i in range(1, 5):

        circuit(i)

```

The resource requirements of individual circuits can then be inspected as follows:

```

>>> resources = tracker.history["resources"]

>>> resources[0]

wires: 1

gates: 1

depth: 1

shots: Shots(total=None)

gate\_types:

{'Hadamard': 1}

gate\_sizes:

{1: 1}

>>> [r.num\_wires for r in resources]

[1, 2, 3, 4]

```

Moreover, it is possible to predict the resource requirements without evaluating circuits

using the `null.qubit` device, which follows the standard execution pipeline but returns numeric

zeros. Consider the following workflow that takes the gradient of a `50`-qubit circuit:

```

n\_wires = 50

dev = qml.device("null.qubit", wires=n\_wires)

weight\_shape = qml.StronglyEntanglingLayers.shape(2, n\_wires)

weights = np.random.random(weight\_shape, requires\_grad=True)

@qml.qnode(dev, diff\_method="parameter-shift")

def circuit(weights):

    qml.StronglyEntanglingLayers(weights, wires=range(n\_wires))

    return qml.expval(qml.PauliZ(0))

with qml.Tracker(dev) as tracker:

    qml.grad(circuit)(weights)

```

The tracker can be inspected to extract resource requirements without requiring a 50-qubit circuit

run:

```

>>> tracker.totals

{'executions': 451, 'batches': 2, 'batch\_len': 451}

>>> tracker.history["resources"][0]

wires: 50

gates: 200

depth: 77

shots: Shots(total=None)

gate\_types:

{'Rot': 100, 'CNOT': 100}

gate\_sizes:

{1: 100, 2: 100}

```

* Custom operations can now be constructed that solely define resource requirements — an explicit

decomposition or matrix representation is not needed.

[(#4033)](https://github.com/PennyLaneAI/pennylane/pull/4033)

PennyLane is now able to estimate the total resource requirements of circuits that include one

or more of these operations, allowing you to estimate requirements for high-level algorithms

composed of abstract subroutines.

These operations can be defined by inheriting from

[ResourcesOperation](https://docs.pennylane.ai/en/stable/code/api/pennylane.resource.ResourcesOperation.html)

and overriding the `resources()` method to return an appropriate

[Resources](https://docs.pennylane.ai/en/stable/code/api/pennylane.resource.Resources.html)

object:

```

class CustomOp(qml.resource.ResourcesOperation):

    def resources(self):

        n = len(self.wires)

        r = qml.resource.Resources(

            num\_wires=n,

            num\_gates=n \*\* 2,

            depth=5,

        )

        return r

```

```

>>> wires = [0, 1, 2]

>>> c = CustomOp(wires)

>>> c.resources()

wires: 3

gates: 9

depth: 5

shots: Shots(total=None)

gate\_types:

{}

gate\_sizes:

{}

```

A quantum circuit that contains `CustomOp` can be created and inspected using

[qml.specs](https://docs.pennylane.ai/en/stable/code/api/pennylane.specs.html):

```

dev = qml.device("default.qubit", wires=wires)

@qml.qnode(dev)

def circ():

    qml.PauliZ(wires=0)

    CustomOp(wires)

    return qml.state()

```

```

>>> specs = qml.specs(circ)()

>>> specs["resources"].depth

6

```

#### Community contributions from UnitaryHack 🤝

* [ParametrizedHamiltonian](https://docs.pennylane.ai/en/stable/code/api/pennylane.pulse.ParametrizedHamiltonian.html)

now has an improved string representation.

[(#4176)](https://github.com/PennyLaneAI/pennylane/pull/4176)

```

>>> def f1(p, t): return p[0] \* jnp.sin(p[1] \* t)

>>> def f2(p, t): return p \* t

>>> coeffs = [2., f1, f2]

>>> observables =  [qml.PauliX(0), qml.PauliY(0), qml.PauliZ(0)]

>>> qml.dot(coeffs, observables)

 (2.0\*(PauliX(wires=[0])))

+ (f1(params\_0, t)\*(PauliY(wires=[0])))

+ (f2(params\_1, t)\*(PauliZ(wires=[0])))

```

* The quantum information module now supports [trace distance](https://en.wikipedia.org/wiki/Trace_distance).

[(#4181)](https://github.com/PennyLaneAI/pennylane/pull/4181)

Two cases are enabled for calculating the trace distance:

	+ A QNode transform via [qml.qinfo.trace\_distance](https://docs.pennylane.ai/en/stable/code/api/pennylane.qinfo.transforms.trace_distance.html):

	

	

	

	```

	dev = qml.device('default.qubit', wires=2)

	

	@qml.qnode(dev)

	def circuit(param):

	    qml.RY(param, wires=0)

	    qml.CNOT(wires=[0, 1])

	    return qml.state()

	

	```

	

	

	

	```

	>>> trace\_distance\_circuit = qml.qinfo.trace\_distance(circuit, circuit, wires0=[0], wires1=[0])

	>>> x, y = np.array(0.4), np.array(0.6)

	>>> trace\_distance\_circuit((x,), (y,))

	0.047862689546603415

	

	```

	+ Flexible post-processing via [qml.math.trace\_distance](https://docs.pennylane.ai/en/stable/code/api/pennylane.math.trace_distance.html):

	

	

	

	```

	>>> rho = np.array([[0.3, 0], [0, 0.7]])

	>>> sigma = np.array([[0.5, 0], [0, 0.5]])

	>>> qml.math.trace\_distance(rho, sigma)

	0.19999999999999998

	

	```

* It is now possible to prepare qutrit basis states with [qml.QutritBasisState](https://docs.pennylane.ai/en/stable/code/api/pennylane.QutritBasisState.html).

[(#4185)](https://github.com/PennyLaneAI/pennylane/pull/4185)

```

wires = range(2)

dev = qml.device("default.qutrit", wires=wires)

@qml.qnode(dev)

def qutrit\_circuit():

    qml.QutritBasisState([1, 1], wires=wires)

    qml.TAdd(wires=wires)

    return qml.probs(wires=1)

```

```

>>> qutrit\_circuit()

array([0., 0., 1.])

```

* A new transform called [one\_qubit\_decomposition](https://docs.pennylane.ai/en/stable/code/api/pennylane.transforms.one_qubit_decomposition.html) has been added to provide a unified interface for decompositions

of a single-qubit unitary matrix into sequences of X, Y, and Z rotations. All

decompositions simplify the rotations angles to be between `0` and `4` pi.

[(#4210)](https://github.com/PennyLaneAI/pennylane/pull/4210)

[(#4246)](https://github.com/PennyLaneAI/pennylane/pull/4246)

```

>>> from pennylane.transforms import one\_qubit\_decomposition

>>> U = np.array([[-0.28829348-0.78829734j,  0.30364367+0.45085995j],

...               [ 0.53396245-0.10177564j,  0.76279558-0.35024096j]])

>>> one\_qubit\_decomposition(U, 0, "ZYZ")

[RZ(tensor(12.32427531, requires\_grad=True), wires=[0]),

 RY(tensor(1.14938178, requires\_grad=True), wires=[0]),

 RZ(tensor(1.73305815, requires\_grad=True), wires=[0])]

>>> one\_qubit\_decomposition(U, 0, "XYX", return\_global\_phase=True)

[RX(tensor(10.84535137, requires\_grad=True), wires=[0]),

 RY(tensor(1.39749741, requires\_grad=True), wires=[0]),

 RX(tensor(0.45246584, requires\_grad=True), wires=[0]),

 (0.38469215914523336-0.9230449299422961j)\*(Identity(wires=[0]))]

```

* The `has\_unitary\_generator` attribute in `qml.ops.qubit.attributes` no longer contains operators

with non-unitary generators.

[(#4183)](https://github.com/PennyLaneAI/pennylane/pull/4183)

* PennyLane Docker builds have been updated to include the latest plugins and interface versions.

[(#4178)](https://github.com/PennyLaneAI/pennylane/pull/4178)

#### Extended support for differentiating pulses ⚛️

* The stochastic parameter-shift gradient method can now be used with hardware-compatible Hamiltonians.

[(#4132)](https://github.com/PennyLaneAI/pennylane/pull/4132)

[(#4215)](https://github.com/PennyLaneAI/pennylane/pull/4215)

This new feature generalizes the stochastic parameter-shift gradient transform for pulses

(`stoch\_pulse\_grad`) to support Hermitian generating terms beyond just Pauli words in pulse Hamiltonians,

which makes it hardware-compatible.

* A new differentiation method called [qml.gradients.pulse\_generator](https://docs.pennylane.ai/en/stable/code/api/pennylane.gradients.pulse_generator.html) is available, which combines classical processing

with the parameter-shift rule for multivariate gates to differentiate pulse programs. Access it in your pulse

programs by setting `diff\_method=qml.gradients.pulse\_generator`.

[(#4160)](https://github.com/PennyLaneAI/pennylane/pull/4160)

* `qml.pulse.ParametrizedEvolution` now uses *batched* compressed sparse row (`BCSR`) format.

This allows for computing Jacobians of the unitary directly even when `dense=False`.

[(#4126)](https://github.com/PennyLaneAI/pennylane/pull/4126)

```

def U(params):

    H = jnp.polyval \* qml.PauliZ(0) # time dependent Hamiltonian

    Um = qml.evolve(H, dense=False)(params, t=10.)

    return qml.matrix(Um)

params = jnp.array([[0.5]], dtype=complex)

jac = jax.jacobian(U, holomorphic=True)(params)

```

#### Broadcasting and other tweaks to Torch and Keras layers 🦾

* The `TorchLayer` and `KerasLayer` integrations with `torch.nn` and `Keras` have been upgraded.

Consider the following `TorchLayer`:

```

n\_qubits = 2

dev = qml.device("default.qubit", wires=n\_qubits)

@qml.qnode(dev)

def qnode(inputs, weights):

    qml.AngleEmbedding(inputs, wires=range(n\_qubits))

    qml.BasicEntanglerLayers(weights, wires=range(n\_qubits))

    return [qml.expval(qml.PauliZ(wires=i)) for i in range(n\_qubits)]

n\_layers = 6

weight\_shapes = {"weights": (n\_layers, n\_qubits)}

qlayer = qml.qnn.TorchLayer(qnode, weight\_shapes)

```

The following features are now available:

	+ Native support for parameter broadcasting.

	[(#4131)](https://github.com/PennyLaneAI/pennylane/pull/4131)

	

	

	

	```

	>>> batch\_size = 10

	>>> inputs = torch.rand((batch\_size, n\_qubits))

	>>> qlayer(inputs)

	>>> dev.num\_executions == 1

	True

	

	```

	+ The ability to draw a `TorchLayer` and `KerasLayer` using `qml.draw()` and

	`qml.draw\_mpl()`.

	[(#4197)](https://github.com/PennyLaneAI/pennylane/pull/4197)

	

	

	

	```

	>>> print(qml.draw(qlayer, show\_matrices=False)(inputs))

	0: ─╭AngleEmbedding(M0)─╭BasicEntanglerLayers(M1)─┤ <Z>

	1: ─╰AngleEmbedding(M0)─╰BasicEntanglerLayers(M1)─┤ <Z>

	

	```

	+ Support for `KerasLayer` model saving and clearer instructions on `TorchLayer` model saving.

	[(#4149)](https://github.com/PennyLaneAI/pennylane/pull/4149)

	[(#4158)](https://github.com/PennyLaneAI/pennylane/pull/4158)

	

	

	

	```

	>>> torch.save(qlayer.state\_dict(), "weights.pt")  # Saving

	>>> qlayer.load\_state\_dict(torch.load("weights.pt"))  # Loading

	>>> qlayer.eval()

	

	```

	

	

	Hybrid models containing `KerasLayer` or `TorchLayer` objects can also be saved and loaded.

### Improvements 🛠

#### A more flexible projector

* `qml.Projector` now accepts a state vector representation, which enables the creation of projectors

in any basis.

[(#4192)](https://github.com/PennyLaneAI/pennylane/pull/4192)

```

dev = qml.device("default.qubit", wires=2)

@qml.qnode(dev)

def circuit(state):

    return qml.expval(qml.Projector(state, wires=[0, 1]))

zero\_state = [0, 0]

plusplus\_state = np.array([1, 1, 1, 1]) / 2

```

```

>>> circuit(zero\_state)

tensor(1., requires\_grad=True)

>>> circuit(plusplus\_state)

tensor(0.25, requires\_grad=True)

```

#### Do more with qutrits

* Three qutrit rotation operators have been added that are analogous to `RX`, `RY`, and `RZ`:

	+ `qml.TRX`: an X rotation

	+ `qml.TRY`: a Y rotation

	+ `qml.TRZ`: a Z rotation[(#2845)](https://github.com/PennyLaneAI/pennylane/pull/2845)

[(#2846)](https://github.com/PennyLaneAI/pennylane/pull/2846)

[(#2847)](https://github.com/PennyLaneAI/pennylane/pull/2847)

* Qutrit devices now support parameter-shift differentiation.

[(#2845)](https://github.com/PennyLaneAI/pennylane/pull/2845)

#### The qchem module

* `qchem.molecular\_hamiltonian()`, `qchem.qubit\_observable()`, `qchem.import\_operator()`, and `qchem.dipole\_moment()` now return an arithmetic operator if `enable\_new\_opmath()` is active.

[(#4138)](https://github.com/PennyLaneAI/pennylane/pull/4138)

[(#4159)](https://github.com/PennyLaneAI/pennylane/pull/4159)

[(#4189)](https://github.com/PennyLaneAI/pennylane/pull/4189)

[(#4204)](https://github.com/PennyLaneAI/pennylane/pull/4204)

* Non-cubic lattice support for all electron resource estimation has been added.

[(3956)](https://github.com/PennyLaneAI/pennylane/pull/3956)

* The `qchem.molecular\_hamiltonian()` function has been upgraded to support custom wires for constructing

differentiable Hamiltonians. The zero imaginary component of the Hamiltonian coefficients have been

removed.

[(#4050)](https://github.com/PennyLaneAI/pennylane/pull/4050)

[(#4094)](https://github.com/PennyLaneAI/pennylane/pull/4094)

* Jordan-Wigner transforms that cache Pauli gate objects have been accelerated.

[(#4046)](https://github.com/PennyLaneAI/pennylane/pull/4046)

* An error is now raised by `qchem.molecular\_hamiltonian` when the `dhf` method is used for an

open-shell system. This duplicates a similar error in `qchem.Molecule` but makes it clear

that the `pyscf` backend can be used for open-shell calculations.

[(#4058)](https://github.com/PennyLaneAI/pennylane/pull/4058)

* Updated various qubit tapering methods to support operator arithmetic.

[(#4252)](https://github.com/PennyLaneAI/pennylane/pull/4252)

#### Next-generation device API

* The new device interface has been integrated with `qml.execute` for autograd, backpropagation, and no differentiation.

[(#3903)](https://github.com/PennyLaneAI/pennylane/pull/3903)

* Support for adjoint differentiation has been added to the `DefaultQubit2` device.

[(#4037)](https://github.com/PennyLaneAI/pennylane/pull/4037)

* A new function called `measure\_with\_samples` that returns a sample-based measurement result given a state has been added.

[(#4083)](https://github.com/PennyLaneAI/pennylane/pull/4083)

[(#4093)](https://github.com/PennyLaneAI/pennylane/pull/4093)

[(#4162)](https://github.com/PennyLaneAI/pennylane/pull/4162)

[(#4254)](https://github.com/PennyLaneAI/pennylane/pull/4254)

* `DefaultQubit2.preprocess` now returns a new `ExecutionConfig` object with decisions for `gradient\_method`,

`use\_device\_gradient`, and `grad\_on\_execution`.

[(#4102)](https://github.com/PennyLaneAI/pennylane/pull/4102)

* Support for sample-based measurements has been added to the `DefaultQubit2` device.

[(#4105)](https://github.com/PennyLaneAI/pennylane/pull/4105)

[(#4114)](https://github.com/PennyLaneAI/pennylane/pull/4114)

[(#4133)](https://github.com/PennyLaneAI/pennylane/pull/4133)

[(#4172)](https://github.com/PennyLaneAI/pennylane/pull/4172)

* The `DefaultQubit2` device now has a `seed` keyword argument.

[(#4120)](https://github.com/PennyLaneAI/pennylane/pull/4120)

* Added a `dense` keyword to `ParametrizedEvolution` that allows forcing dense or sparse matrices.

[(#4079)](https://github.com/PennyLaneAI/pennylane/pull/4079)

[(#4095)](https://github.com/PennyLaneAI/pennylane/pull/4095)

[(#4285)](https://github.com/PennyLaneAI/pennylane/pull/4285)

* Adds the Type variables `pennylane.typing.Result` and `pennylane.typing.ResultBatch` for type hinting the result of

an execution.

[(#4018)](https://github.com/PennyLaneAI/pennylane/pull/4108)

* `qml.devices.ExecutionConfig` no longer has a `shots` property, as it is now on the `QuantumScript`.  

It now has a `use\_device\_gradient` property. `ExecutionConfig.grad\_on\_execution = None` indicates a

request for `"best"`, instead of a string.

[(#4102)](https://github.com/PennyLaneAI/pennylane/pull/4102)

* The new device interface for Jax has been integrated with `qml.execute`.

[(#4137)](https://github.com/PennyLaneAI/pennylane/pull/4137)

* The new device interface is now integrated with `qml.execute` for Tensorflow.

[(#4169)](https://github.com/PennyLaneAI/pennylane/pull/4169)

* The experimental device `DefaultQubit2` now supports `qml.Snapshot`.

[(#4193)](https://github.com/PennyLaneAI/pennylane/pull/4193)

* The experimental device interface is integrated with the `QNode`.

[(#4196)](https://github.com/PennyLaneAI/pennylane/pull/4196)

* The new device interface in integrated with `qml.execute` for Torch.

[(#4257)](https://github.com/PennyLaneAI/pennylane/pull/4257)

#### Handling shots

* `QuantumScript` now has a `shots` property, allowing shots to be tied to executions instead of devices.

[(#4067)](https://github.com/PennyLaneAI/pennylane/pull/4067)

[(#4103)](https://github.com/PennyLaneAI/pennylane/pull/4103)

[(#4106)](https://github.com/PennyLaneAI/pennylane/pull/4106)

[(#4112)](https://github.com/PennyLaneAI/pennylane/pull/4112)

* Several Python built-in functions are now properly defined for instances of the `Shots` class.

	+ `print`: printing `Shots` instances is now human-readable

	+ `str`: converting `Shots` instances to human-readable strings

	+ `==`: equating two different `Shots` instances

	+ `hash`: obtaining the hash values of `Shots` instances[(#4081)](https://github.com/PennyLaneAI/pennylane/pull/4081)

[(#4082)](https://github.com/PennyLaneAI/pennylane/pull/4082)

* `qml.devices.ExecutionConfig` no longer has a `shots` property, as it is now on the `QuantumScript`. It now has a `use\_device\_gradient` property. `ExecutionConfig.grad\_on\_execution = None` indicates a request for `"best"` instead of a string.

[(#4102)](https://github.com/PennyLaneAI/pennylane/pull/4102)

* `QuantumScript.shots` has been integrated with QNodes so that shots are placed on the `QuantumScript`

during `QNode` construction.

[(#4110)](https://github.com/PennyLaneAI/pennylane/pull/4110)

* The `gradients` module has been updated to use the new `Shots` object internally

[(#4152)](https://github.com/PennyLaneAI/pennylane/pull/4152)

#### Operators

* `qml.prod` now accepts a single quantum function input for creating new `Prod` operators.

[(#4011)](https://github.com/PennyLaneAI/pennylane/pull/4011)

* `DiagonalQubitUnitary` now decomposes into `RZ`, `IsingZZ` and `MultiRZ` gates

instead of a `QubitUnitary` operation with a dense matrix.

[(#4035)](https://github.com/PennyLaneAI/pennylane/pull/4035)

* All objects being queued in an `AnnotatedQueue` are now wrapped so that `AnnotatedQueue` is not

dependent on the has of any operators or measurement processes.

[(#4087)](https://github.com/PennyLaneAI/pennylane/pull/4087)

* A `dense` keyword to `ParametrizedEvolution` that allows forcing dense or sparse matrices has been added.

[(#4079)](https://github.com/PennyLaneAI/pennylane/pull/4079)

[(#4095)](https://github.com/PennyLaneAI/pennylane/pull/4095)

* Added a new function `qml.ops.functions.bind\_new\_parameters` that creates a copy of an operator with new parameters without mutating the original operator.

[(#4113)](https://github.com/PennyLaneAI/pennylane/pull/4113)

[(#4256)](https://github.com/PennyLaneAI/pennylane/pull/4256)

* `qml.CY` has been moved from `qml.ops.qubit.non\_parametric\_ops` to `qml.ops.op\_math.controlled\_ops`

and now inherits from `qml.ops.op\_math.ControlledOp`.

[(#4116)](https://github.com/PennyLaneAI/pennylane/pull/4116/)

* `qml.CZ` now inherits from the `ControlledOp` class and supports exponentiation to arbitrary powers with `pow`, which is no longer limited to integers. It also supports `sparse\_matrix` and `decomposition` representations.

[(#4117)](https://github.com/PennyLaneAI/pennylane/pull/4117)

* The construction of the Pauli representation for the `Sum` class is now faster.

[(#4142)](https://github.com/PennyLaneAI/pennylane/pull/4142)

* `qml.drawer.drawable\_layers.drawable\_layers` and `qml.CircuitGraph` have been updated to not rely on `Operator`

equality or hash to work correctly.

[(#4143)](https://github.com/PennyLaneAI/pennylane/pull/4143)

#### Other improvements

* A transform dispatcher and program have been added.

[(#4109)](https://github.com/PennyLaneAI/pennylane/pull/4109)

[(#4187)](https://github.com/PennyLaneAI/pennylane/pull/4187)

* Reduced density matrix functionality has been added via `qml.math.reduce\_dm` and `qml.math.reduce\_statevector`.

Both functions have broadcasting support.

[(#4173)](https://github.com/PennyLaneAI/pennylane/pull/4173)

* The following functions in `qml.qinfo` now support parameter broadcasting:

	+ `reduced\_dm`

	+ `purity`

	+ `vn\_entropy`

	+ `mutual\_info`

	+ `fidelity`

	+ `relative\_entropy`

	+ `trace\_distance`[(#4234)](https://github.com/PennyLaneAI/pennylane/pull/4234)

* The following functions in `qml.math` now support parameter broadcasting:

	+ `purity`

	+ `vn\_entropy`

	+ `mutual\_info`

	+ `fidelity`

	+ `relative\_entropy`

	+ `max\_entropy`

	+ `sqrt\_matrix`[(#4186)](https://github.com/PennyLaneAI/pennylane/pull/4186)

* `pulse.ParametrizedEvolution` now raises an error if the number of input parameters does not match the number

of parametrized coefficients in the `ParametrizedHamiltonian` that generates it. An exception is made for

`HardwareHamiltonian`s which are not checked.

[(#4216)](https://github.com/PennyLaneAI/pennylane/pull/4216)

* The default value for the `show\_matrices` keyword argument in all drawing methods is now `True`.

This allows for quick insights into broadcasted tapes, for example.

[(#3920)](https://github.com/PennyLaneAI/pennylane/pull/3920)

* Type variables for `qml.typing.Result` and `qml.typing.ResultBatch` have been added for type hinting the result of an execution.

[(#4108)](https://github.com/PennyLaneAI/pennylane/pull/4108)

* The Jax-JIT interface now uses symbolic zeros to determine trainable parameters.

[(4075)](https://github.com/PennyLaneAI/pennylane/pull/4075)

* A new function called `pauli.pauli\_word\_prefactor()` that extracts the prefactor for a given Pauli word has been added.

[(#4164)](https://github.com/PennyLaneAI/pennylane/pull/4164)

* Variable-length argument lists of functions and methods in some docstrings is now more clear.

[(#4242)](https://github.com/PennyLaneAI/pennylane/pull/4242)

* `qml.drawer.drawable\_layers.drawable\_layers` and `qml.CircuitGraph` have been updated to not rely on `Operator`

equality or hash to work correctly.

[(#4143)](https://github.com/PennyLaneAI/pennylane/pull/4143)

* Drawing mid-circuit measurements connected by classical control signals to conditional operations is now possible.

[(#4228)](https://github.com/PennyLaneAI/pennylane/pull/4228)

* The autograd interface now submits all required tapes in a single batch on the backward pass.

[(#4245)](https://github.com/PennyLaneAI/pennylane/pull/4245)

### Breaking changes 💔

* The default value for the `show\_matrices` keyword argument in all drawing methods is now `True`.

This allows for quick insights into broadcasted tapes, for example.

[(#3920)](https://github.com/PennyLaneAI/pennylane/pull/3920)

* `DiagonalQubitUnitary` now decomposes into `RZ`, `IsingZZ`, and `MultiRZ` gates rather than a `QubitUnitary`.

[(#4035)](https://github.com/PennyLaneAI/pennylane/pull/4035)

* Jax trainable parameters are now `Tracer` instead of `JVPTracer`. It is not always the right definition for the JIT

interface, but we update them in the custom JVP using symbolic zeros.

[(4075)](https://github.com/PennyLaneAI/pennylane/pull/4075)

* The experimental Device interface `qml.devices.experimental.Device` now requires that the `preprocess` method

also returns an `ExecutionConfig` object. This allows the device to choose what `"best"` means for various

hyperparameters like `gradient\_method` and `grad\_on\_execution`.

[(#4007)](https://github.com/PennyLaneAI/pennylane/pull/4007)

[(#4102)](https://github.com/PennyLaneAI/pennylane/pull/4102)

* Gradient transforms with Jax no longer support `argnum`. Use `argnums` instead.

[(#4076)](https://github.com/PennyLaneAI/pennylane/pull/4076)

* `qml.collections`, `qml.op\_sum`, and `qml.utils.sparse\_hamiltonian` have been removed.

[(#4071)](https://github.com/PennyLaneAI/pennylane/pull/4071)

* The `pennylane.transforms.qcut` module now uses `(op, id(op))` as nodes in directed multigraphs that are used within

the circuit cutting workflow instead of `op`. This change removes the dependency of the module on the hash of operators.

[(#4227)](https://github.com/PennyLaneAI/pennylane/pull/4227)

* `Operator.data` now returns a `tuple` instead of a `list`.

[(#4222)](https://github.com/PennyLaneAI/pennylane/pull/4222)

* The pulse differentiation methods, `pulse\_generator` and `stoch\_pulse\_grad`, now raise an error when they

are applied to a QNode directly. Instead, use differentiation via a JAX entry point (`jax.grad`, `jax.jacobian`, …).

[(#4241)](https://github.com/PennyLaneAI/pennylane/pull/4241)

### Deprecations 👋

* `LieAlgebraOptimizer` has been renamed to `RiemannianGradientOptimizer`.

[(#4153)(<https://github.com/PennyLaneAI/pennylane/pull/4153>)]

* `Operation.base\_name` has been deprecated. Please use `Operation.name` or `type(op).\_\_name\_\_` instead.

* `QuantumScript`‘s `name` keyword argument and property have been deprecated.

This also affects `QuantumTape` and `OperationRecorder`.

[(#4141)](https://github.com/PennyLaneAI/pennylane/pull/4141)

* The `qml.grouping` module has been removed. Its functionality has been reorganized in the `qml.pauli` module.

* The public methods of `DefaultQubit` are pending changes to follow the new device API, as used in

`DefaultQubit2`. Warnings have been added to the docstrings to reflect this.

[(#4145)](https://github.com/PennyLaneAI/pennylane/pull/4145)

* `qml.math.reduced\_dm` has been deprecated. Please use `qml.math.reduce\_dm` or `qml.math.reduce\_statevector` instead.

[(#4173)](https://github.com/PennyLaneAI/pennylane/pull/4173)

* `qml.math.purity`, `qml.math.vn\_entropy`, `qml.math.mutual\_info`, `qml.math.fidelity`,

`qml.math.relative\_entropy`, and `qml.math.max\_entropy` no longer support state vectors as

input. Please call `qml.math.dm\_from\_state\_vector` on the input before passing to any of these functions.

[(#4186)](https://github.com/PennyLaneAI/pennylane/pull/4186)

* The `do\_queue` keyword argument in `qml.operation.Operator` has been deprecated. Instead of

setting `do\_queue=False`, use the `qml.QueuingManager.stop\_recording()` context.

[(#4148)](https://github.com/PennyLaneAI/pennylane/pull/4148)

* `zyz\_decomposition` and `xyx\_decomposition` are now deprecated in favour of `one\_qubit\_decomposition`.

[(#4230)](https://github.com/PennyLaneAI/pennylane/pull/4230)

### Documentation 📝

* The documentation is updated to construct `QuantumTape` upon initialization instead of with queuing.

[(#4243)](https://github.com/PennyLaneAI/pennylane/pull/4243)

* The docstring for `qml.ops.op\_math.Pow.\_\_new\_\_` is now complete and it has been updated along with

`qml.ops.op\_math.Adjoint.\_\_new\_\_`.

[(#4231)](https://github.com/PennyLaneAI/pennylane/pull/4231)

* The docstring for `qml.grad` now states that it should be used with the Autograd interface only.

[(#4202)](https://github.com/PennyLaneAI/pennylane/pull/4202)

* The description of `mult` in the `qchem.Molecule` docstring now correctly states the value

of `mult` that is supported.

[(#4058)](https://github.com/PennyLaneAI/pennylane/pull/4058)

### Bug Fixes 🐛

* Fixed adjoint jacobian results with `grad\_on\_execution=False` in the JAX-JIT interface.

[(4217)](https://github.com/PennyLaneAI/pennylane/pull/4217)

* Fixed the matrix of `SProd` when the coefficient is tensorflow and the target matrix is not `complex128`.

[(#4249)](https://github.com/PennyLaneAI/pennylane/pull/4249)

* Fixed a bug where `stoch\_pulse\_grad` would ignore prefactors of rescaled Pauli words in the

generating terms of a pulse Hamiltonian.

[(4156)](https://github.com/PennyLaneAI/pennylane/pull/4156)

* Fixed a bug where the wire ordering of the `wires` argument to `qml.density\_matrix`

was not taken into account.

[(#4072)](https://github.com/PennyLaneAI/pennylane/pull/4072)

* A patch in `interfaces/autograd.py` that checks for the `strawberryfields.gbs` device has been removed.

That device is pinned to PennyLane <= v0.29.0, so that patch is no longer necessary.

[(#4089)](https://github.com/PennyLaneAI/pennylane/pull/4089)

* `qml.pauli.are\_identical\_pauli\_words` now treats all identities as equal. Identity terms on Hamiltonians with non-standard

wire orders are no longer eliminated.

[(#4161)](https://github.com/PennyLaneAI/pennylane/pull/4161)

* `qml.pauli\_sentence()` is now compatible with empty Hamiltonians `qml.Hamiltonian([], [])`.

[(#4171)](https://github.com/PennyLaneAI/pennylane/pull/4171)

* Fixed a bug with Jax where executing multiple tapes with `gradient\_fn="device"` would fail.

[(#4190)](https://github.com/PennyLaneAI/pennylane/pull/4190)

* A more meaningful error message is raised when broadcasting with adjoint differentiation on `DefaultQubit`.

[(#4203)](https://github.com/PennyLaneAI/pennylane/pull/4203)

* The `has\_unitary\_generator` attribute in `qml.ops.qubit.attributes` no longer contains operators with non-unitary generators.

[(#4183)](https://github.com/PennyLaneAI/pennylane/pull/4183)

* Fixed a bug where `op = qml.qsvt()` was incorrect up to a global phase when using `convention="Wx""` and `qml.matrix(op)`.

[(#4214)](https://github.com/PennyLaneAI/pennylane/pull/4214)

* Fixed a buggy calculation of the angle in `xyx\_decomposition` that causes it to give an incorrect decomposition.

An `if` conditional was intended to prevent divide by zero errors, but the division was by the sine of the argument. So, any multiple of $pi$ should trigger the conditional, but it was only checking if the argument was 0. Example: `qml.Rot(2.3, 2.3, 2.3)`

[(#4210)](https://github.com/PennyLaneAI/pennylane/pull/4210)

* Fixed bug that caused `ShotAdaptiveOptimizer` to truncate dimensions of parameter-distributed shots during optimization.

[(#4240)](https://github.com/PennyLaneAI/pennylane/pull/4240)

* `Sum` observables can now have trainable parameters.

[(#4251)](https://github.com/PennyLaneAI/pennylane/pull/4251)

[(#4275)](https://github.com/PennyLaneAI/pennylane/pull/4275)

### Contributors ✍️

This release contains contributions from (in alphabetical order):

Venkatakrishnan AnushKrishna,

Utkarsh Azad,

Thomas Bromley,

Isaac De Vlugt,

Lillian M. A. Frederiksen,

Emiliano Godinez Ramirez

Nikhil Harle

Soran Jahangiri,

Edward Jiang,

Korbinian Kottmann,

Christina Lee,

Vincent Michaud-Rioux,

Romain Moyard,

Tristan Nemoz,

Mudit Pandey,

Manul Patel,

Borja Requena,

Modjtaba Shokrian-Zini,

Mainak Roy,

Matthew Silverman,

Jay Soni,

Edward Thomas,

David Wierichs,

Frederik Wilde.

orphan

#### Release 0.30.0[¶](#release-0-30-0 "Permalink to this headline")

### New features since last release

#### Pulse programming on hardware ⚛️🔬

* Support for loading time-dependent Hamiltonians that are compatible with quantum hardware has been

added, making it possible to load a Hamiltonian that describes an ensemble of Rydberg atoms or a

collection of transmon qubits.

[(#3749)](https://github.com/PennyLaneAI/pennylane/pull/3749)

[(#3911)](https://github.com/PennyLaneAI/pennylane/pull/3911)

[(#3930)](https://github.com/PennyLaneAI/pennylane/pull/3930)

[(#3936)](https://github.com/PennyLaneAI/pennylane/pull/3936)

[(#3966)](https://github.com/PennyLaneAI/pennylane/pull/3966)

[(#3987)](https://github.com/PennyLaneAI/pennylane/pull/3987)

[(#4021)](https://github.com/PennyLaneAI/pennylane/pull/4021)

[(#4040)](https://github.com/PennyLaneAI/pennylane/pull/4040)

[Rydberg atoms](https://en.wikipedia.org/wiki/Rydberg_atom) are the foundational

unit for neutral atom quantum computing.

A Rydberg-system Hamiltonian can be constructed from a

[drive term](https://docs.pennylane.ai/en/stable/code/api/pennylane.pulse.rydberg_drive.html)

— `qml.pulse.rydberg\_drive` — and an

[interaction term](https://docs.pennylane.ai/en/stable/code/api/pennylane.pulse.rydberg_interaction.html)

— `qml.pulse.rydberg\_interaction`:

```

from jax import numpy as jnp

atom\_coordinates = [[0, 0], [0, 4], [4, 0], [4, 4]]

wires = [0, 1, 2, 3]

amplitude = lambda p, t: p \* jnp.sin(jnp.pi \* t)

phase = jnp.pi / 2

detuning = 3 \* jnp.pi / 4

H\_d = qml.pulse.rydberg\_drive(amplitude, phase, detuning, wires)

H\_i = qml.pulse.rydberg\_interaction(atom\_coordinates, wires)

H = H\_d + H\_i

```

The time-dependent Hamiltonian `H` can be used in a PennyLane pulse-level differentiable circuit:

```

dev = qml.device("default.qubit.jax", wires=wires)

@qml.qnode(dev, interface="jax")

def circuit(params):

    qml.evolve(H)(params, t=[0, 10])

    return qml.expval(qml.PauliZ(0))

```

```

>>> params = jnp.array([2.4])

>>> circuit(params)

Array(0.6316659, dtype=float32)

>>> import jax

>>> jax.grad(circuit)(params)

Array([1.3116529], dtype=float32)

```

The [qml.pulse](https://docs.pennylane.ai/en/stable/code/qml_pulse.html) page contains

additional details. Check out our

[release blog post](https://pennylane.ai/blog/2023/05/pennylane-v030-released/) for a

demonstration of how to perform the execution on actual hardware!

* A pulse-level circuit can now be differentiated using a

[stochastic parameter-shift](https://arxiv.org/abs/2210.15812) method.

[(#3780)](https://github.com/PennyLaneAI/pennylane/pull/3780)

[(#3900)](https://github.com/PennyLaneAI/pennylane/pull/3900)

[(#4000)](https://github.com/PennyLaneAI/pennylane/pull/4000)

[(#4004)](https://github.com/PennyLaneAI/pennylane/pull/4004)

The new

[qml.gradient.stoch\_pulse\_grad](https://docs.pennylane.ai/en/stable/code/api/pennylane.gradients.stoch_pulse_grad.html)

differentiation method unlocks stochastic-parameter-shift differentiation for pulse-level circuits.

The current version of this new method is restricted to Hamiltonians composed of parametrized

[Pauli words](https://docs.pennylane.ai/en/stable/code/api/pennylane.pauli.PauliWord.html), but

future updates to extend to parametrized

[Pauli sentences](https://docs.pennylane.ai/en/stable/code/api/pennylane.pauli.PauliSentence.html)

can allow this method to be compatible with hardware-based systems such as an ensemble of Rydberg

atoms.

This method can be activated by setting `diff\_method` to

[qml.gradient.stoch\_pulse\_grad](https://docs.pennylane.ai/en/stable/code/api/pennylane.gradients.stoch_pulse_grad.html):

```

>>> dev = qml.device("default.qubit.jax", wires=2)

>>> sin = lambda p, t: jax.numpy.sin(p \* t)

>>> ZZ = qml.PauliZ(0) @ qml.PauliZ(1)

>>> H = 0.5 \* qml.PauliX(0) + qml.pulse.constant \* ZZ + sin \* qml.PauliX(1)

>>> @qml.qnode(dev, interface="jax", diff\_method=qml.gradients.stoch\_pulse\_grad)

>>> def ansatz(params):

...     qml.evolve(H)(params, (0.2, 1.))

...     return qml.expval(qml.PauliY(1))

>>> params = [jax.numpy.array(0.4), jax.numpy.array(1.3)]

>>> jax.grad(ansatz)(params)

[Array(0.16921353, dtype=float32, weak\_type=True),

 Array(-0.2537478, dtype=float32, weak\_type=True)]

```

#### Quantum singular value transformation 🐛➡️🦋

* PennyLane now supports the

[quantum singular value transformation](https://arxiv.org/abs/1806.01838) (QSVT), which describes

how a quantum circuit can be constructed to apply a polynomial transformation to the singular

values of an input matrix.

[(#3756)](https://github.com/PennyLaneAI/pennylane/pull/3756)

[(#3757)](https://github.com/PennyLaneAI/pennylane/pull/3757)

[(#3758)](https://github.com/PennyLaneAI/pennylane/pull/3758)

[(#3905)](https://github.com/PennyLaneAI/pennylane/pull/3905)

[(#3909)](https://github.com/PennyLaneAI/pennylane/pull/3909)

[(#3926)](https://github.com/PennyLaneAI/pennylane/pull/3926)

[(#4023)](https://github.com/PennyLaneAI/pennylane/pull/4023)

Consider a matrix `A` along with a vector `angles` that describes the target polynomial

transformation. The `qml.qsvt`

function creates a corresponding circuit:

```

dev = qml.device("default.qubit", wires=2)

A = np.array([[0.1, 0.2], [0.3, 0.4]])

angles = np.array([0.1, 0.2, 0.3])

@qml.qnode(dev)

def example\_circuit(A):

    qml.qsvt(A, angles, wires=[0, 1])

    return qml.expval(qml.PauliZ(wires=0))

```

This circuit is composed of `qml.BlockEncode` and `qml.PCPhase` operations.

```

>>> example\_circuit(A)

tensor(0.97777078, requires\_grad=True)

>>> print(example\_circuit.qtape.expand(depth=1).draw(decimals=2))

0: ─╭∏\_ϕ(0.30)─╭BlockEncode(M0)─╭∏\_ϕ(0.20)─╭BlockEncode(M0)†─╭∏\_ϕ(0.10)─┤ <Z>

1: ─╰∏\_ϕ(0.30)─╰BlockEncode(M0)─╰∏\_ϕ(0.20)─╰BlockEncode(M0)†─╰∏\_ϕ(0.10)─┤

```

The [qml.qsvt](https://docs.pennylane.ai/en/stable/code/api/pennylane.qsvt.html) function

creates a circuit that is targeted at simulators due to the use of matrix-based operations.

For advanced users, you can use the

[operation-based](https://docs.pennylane.ai/en/stable/code/api/pennylane.QSVT.html)

`qml.QSVT` template to perform

the transformation with a custom choice of unitary and projector operations, which may be

hardware compatible if a decomposition is provided.

The QSVT is a complex but powerful transformation capable of

[generalizing important algorithms](https://arxiv.org/abs/2105.02859)

like amplitude amplification. Stay tuned for a demo in the coming few weeks to learn more!

#### Intuitive QNode returns ↩️

* An updated QNode return system has been introduced. PennyLane QNodes now return exactly what you

tell them to! 🎉

[(#3957)](https://github.com/PennyLaneAI/pennylane/pull/3957)

[(#3969)](https://github.com/PennyLaneAI/pennylane/pull/3969)

[(#3946)](https://github.com/PennyLaneAI/pennylane/pull/3946)

[(#3913)](https://github.com/PennyLaneAI/pennylane/pull/3913)

[(#3914)](https://github.com/PennyLaneAI/pennylane/pull/3914)

[(#3934)](https://github.com/PennyLaneAI/pennylane/pull/3934)

This was an experimental feature introduced in version 0.25 of PennyLane that was enabled

via `qml.enable\_return()`. Now, it’s the default return system. Let’s see how it works.

Consider the following circuit:

```

import pennylane as qml

dev = qml.device("default.qubit", wires=1)

@qml.qnode(dev)

def circuit(x):

    qml.RX(x, wires=0)

    return qml.expval(qml.PauliZ(0)), qml.probs(0)

```

In version 0.29 and earlier of PennyLane, `circuit()` would return a single length-3 array:

```

>>> circuit(0.5)

tensor([0.87758256, 0.93879128, 0.06120872], requires\_grad=True)

```

In versions 0.30 and above, `circuit()` returns a length-2 tuple containing the expectation

value and probabilities separately:

```

>>> circuit(0.5)

(tensor(0.87758256, requires\_grad=True),

 tensor([0.93879128, 0.06120872], requires\_grad=True))

```

You can find

[more details about this change](https://docs.pennylane.ai/en/stable/introduction/returns.html),

along with help and troubleshooting tips to solve any issues.

If you still have questions, comments, or concerns, we encourage you to post on the

PennyLane [discussion forum](https://discuss.pennylane.ai).

#### A bunch of performance tweaks 🏃💨

* Single-qubit operations that have multi-qubit control can now be decomposed more efficiently

using fewer CNOT gates.

[(#3851)](https://github.com/PennyLaneAI/pennylane/pull/3851)

Three decompositions from [arXiv:2302.06377](https://arxiv.org/abs/2302.06377) are provided and

compare favourably to the already-available `qml.ops.ctrl\_decomp\_zyz`:

```

wires = [0, 1, 2, 3, 4, 5]

control\_wires = wires[1:]

@qml.qnode(qml.device('default.qubit', wires=6))

def circuit():

    with qml.QueuingManager.stop\_recording():

        # the decomposition does not un-queue the target

        target = qml.RX(np.pi/2, wires=0)

    qml.ops.ctrl\_decomp\_bisect(target, (1, 2, 3, 4, 5))

    return qml.state()

print(qml.draw(circuit, expansion\_strategy="device")())

```

```

0: ──H─╭X──U(M0)─╭X──U(M0)†─╭X──U(M0)─╭X──U(M0)†──H─┤  State

1: ────├●────────│──────────├●────────│─────────────┤  State

2: ────├●────────│──────────├●────────│─────────────┤  State

3: ────╰●────────│──────────╰●────────│─────────────┤  State

4: ──────────────├●───────────────────├●────────────┤  State

5: ──────────────╰●───────────────────╰●────────────┤  State

```

* A new decomposition to `qml.SingleExcitation` has been added that halves the number of

CNOTs required.

[(3976)](https://github.com/PennyLaneAI/pennylane/pull/3976)

```

>>> qml.SingleExcitation.compute\_decomposition(1.23, wires=(0,1))

[Adjoint(T(wires=[0])), Hadamard(wires=[0]), S(wires=[0]),

 Adjoint(T(wires=[1])), Adjoint(S(wires=[1])), Hadamard(wires=[1]),

 CNOT(wires=[1, 0]), RZ(-0.615, wires=[0]), RY(0.615, wires=[1]),

 CNOT(wires=[1, 0]), Adjoint(S(wires=[0])), Hadamard(wires=[0]),

 T(wires=[0]), Hadamard(wires=[1]), S(wires=[1]), T(wires=[1])]

```

* The adjoint differentiation method can now be more efficient, avoiding the decomposition of operations

that can be differentiated directly. Any operation that defines a `generator()` can

be differentiated with the adjoint method.

[(#3874)](https://github.com/PennyLaneAI/pennylane/pull/3874)

For example, in version 0.29 the `qml.CRY` operation would be decomposed when calculating the

adjoint-method gradient. Executing the code below shows that this decomposition no longer takes

place in version 0.30 and `qml.CRY` is differentiated directly:

```

import jax

from jax import numpy as jnp

def compute\_decomposition(self, phi, wires):

    print("A decomposition has been performed!")

    decomp\_ops = [

        qml.RY(phi / 2, wires=wires[1]),

        qml.CNOT(wires=wires),

        qml.RY(-phi / 2, wires=wires[1]),

        qml.CNOT(wires=wires),

    ]

    return decomp\_ops

qml.CRY.compute\_decomposition = compute\_decomposition

dev = qml.device("default.qubit", wires=2)

@qml.qnode(dev, diff\_method="adjoint")

def circuit(phi):

    qml.Hadamard(wires=0)

    qml.CRY(phi, wires=[0, 1])

    return qml.expval(qml.PauliZ(1))

phi = jnp.array(0.5)

jax.grad(circuit)(phi)

```

* Derivatives are computed more efficiently when using `jax.jit` with gradient transforms; the

trainable parameters are now set correctly instead of every parameter having to be set as

trainable.

[(#3697)](https://github.com/PennyLaneAI/pennylane/pull/3697)

In the circuit below, only the derivative with respect to parameter `b` is now calculated:

```

dev = qml.device("default.qubit", wires=2)

@qml.qnode(dev, interface="jax-jit")

def circuit(a, b):

    qml.RX(a, wires=0)

    qml.RY(b, wires=0)

    qml.CNOT(wires=[0, 1])

    return qml.expval(qml.PauliZ(0))

a = jnp.array(0.4)

b = jnp.array(0.5)

jac = jax.jacobian(circuit, argnums=[1])

jac\_jit = jax.jit(jac)

jac\_jit(a, b)

assert len(circuit.tape.trainable\_params) == 1

```

### Improvements 🛠

#### Next-generation device API

In this release and future releases, we will be making changes to our device API with the goal in mind to make

developing plugins much easier for developers and unlock new device capabilities. Users shouldn’t yet feel any of

these changes when using PennyLane, but here is what has changed this release:

* Several functions in `devices/qubit` have been added or improved:

	+ `sample\_state`: returns a series of samples based on a given state vector and a number of shots.

	[(#3720)](https://github.com/PennyLaneAI/pennylane/pull/3720)

	+ `simulate`: supports measuring expectation values of large observables such as `qml.Hamiltonian`, `qml.SparseHamiltonian`, and `qml.Sum`.

	[(#3759)](https://github.com/PennyLaneAI/pennylane/pull/3759)

	+ `apply\_operation`: supports broadcasting.

	[(#3852)](https://github.com/PennyLaneAI/pennylane/pull/3852)

	+ `adjoint\_jacobian`: supports adjoint differentiation in the new qubit state-vector device.

	[(#3790)](https://github.com/PennyLaneAI/pennylane/pull/3790)

* `qml.devices.qubit.preprocess` now allows circuits with non-commuting observables.

[(#3857)](https://github.com/PennyLaneAI/pennylane/pull/3857)

* `qml.devices.qubit.measure` now computes the expectation values of `Hamiltonian` and `Sum`

in a backpropagation-compatible way.

[(#3862)](https://github.com/PennyLaneAI/pennylane/pull/3862/)

#### Pulse programming

* Here are the functions, classes, and more that were added or improved to facilitate simulating ensembles of Rydberg atoms:

[(#3749)](https://github.com/PennyLaneAI/pennylane/pull/3749)

[(#3911)](https://github.com/PennyLaneAI/pennylane/pull/3911)

[(#3930)](https://github.com/PennyLaneAI/pennylane/pull/3930)

[(#3936)](https://github.com/PennyLaneAI/pennylane/pull/3936)

[(#3966)](https://github.com/PennyLaneAI/pennylane/pull/3966)

[(#3987)](https://github.com/PennyLaneAI/pennylane/pull/3987)

[(#3889)](https://github.com/PennyLaneAI/pennylane/pull/3889)

[(#4021)](https://github.com/PennyLaneAI/pennylane/pull/4021)

	+ `HardwareHamiltonian`: an internal class that contains additional information about pulses and settings.

	+ `rydberg\_interaction`: a user-facing function that returns a `HardwareHamiltonian` containing

	the Hamiltonian of the interaction of all the Rydberg atoms.

	+ `transmon\_interaction`: a user-facing function for constructing

	the Hamiltonian that describes the circuit QED interaction Hamiltonian of superconducting transmon systems.

	+ `drive`: a user-facing function function that returns a `ParametrizedHamiltonian` (`HardwareHamiltonian`) containing

	the Hamiltonian of the interaction between a driving electro-magnetic field and a group of qubits.

	+ `rydberg\_drive`: a user-facing function that returns a `ParametrizedHamiltonian` (`HardwareHamiltonian`) containing

	the Hamiltonian of the interaction between a driving laser field and a group of Rydberg atoms.

	+ `max\_distance`: a keyword argument added to `qml.pulse.rydberg\_interaction` to allow for the removal of negligible contributions from atoms beyond `max\_distance` from each other.

* `ParametrizedEvolution` now takes two new Boolean keyword arguments: `return\_intermediate` and

`complementary`. They allow computing intermediate time evolution matrices.

[(#3900)](https://github.com/PennyLaneAI/pennylane/pull/3900)

Activating `return\_intermediate` will return intermediate time evolution steps, for example

for the matrix of the Operation, or of a quantum circuit when used in a QNode.

Activating `complementary` will make these intermediate steps be the *remaining*

time evolution complementary to the output for `complementary=False`.

See the [docstring](https://docs.pennylane.ai/en/stable/code/api/pennylane.pulse.ParametrizedEvolution.html)

for details.

* Hardware-compatible pulse sequence gradients with `qml.gradient.stoch\_pulse\_grad` can now be calculated faster using

the new keyword argument `use\_broadcasting`. Executing a `ParametrizedEvolution` that returns

intermediate evolutions has increased performance using the state vector ODE solver, as well.

[(#4000)](https://github.com/PennyLaneAI/pennylane/pull/4000)

[(#4004)](https://github.com/PennyLaneAI/pennylane/pull/4004)

#### Intuitive QNode returns

* The QNode keyword argument `mode` has been replaced by the boolean `grad\_on\_execution`.

[(#3969)](https://github.com/PennyLaneAI/pennylane/pull/3969)

* The `"default.gaussian"` device and parameter-shift CV both support the new return system, but only for single measurements.

[(#3946)](https://github.com/PennyLaneAI/pennylane/pull/3946)

* Keras and Torch NN modules are now compatible with the new return type system.

[(#3913)](https://github.com/PennyLaneAI/pennylane/pull/3913)

[(#3914)](https://github.com/PennyLaneAI/pennylane/pull/3914)

* `DefaultQutrit` now supports the new return system.

[(#3934)](https://github.com/PennyLaneAI/pennylane/pull/3934)

#### Performance improvements

* The efficiency of `tapering()`, `tapering\_hf()` and `clifford()` have been improved.

[(3942)](https://github.com/PennyLaneAI/pennylane/pull/3942)

* The peak memory requirements of `tapering()` and `tapering\_hf()` have been improved when used for larger observables.

[(3977)](https://github.com/PennyLaneAI/pennylane/pull/3977)

* Pauli arithmetic has been updated to convert to a Hamiltonian more efficiently.

[(#3939)](https://github.com/PennyLaneAI/pennylane/pull/3939)

* `Operator` has a new Boolean attribute `has\_generator`. It returns whether or not the `Operator`

has a `generator` defined. `has\_generator` is used in `qml.operation.has\_gen`, which improves its performance

and extends differentiation support.

[(#3875)](https://github.com/PennyLaneAI/pennylane/pull/3875)

* The performance of `CompositeOp` has been significantly improved now that it overrides

determining whether it is being used with a batch of parameters (see `Operator.\_check\_batching`).

`Hamiltonian` also now overrides this, but it does nothing since it does not support batching.

[(#3915)](https://github.com/PennyLaneAI/pennylane/pull/3915)

* The performance of a `Sum` operator has been significantly improved now that `is\_hermitian` checks

that all coefficients are real if the operator has a pre-computed Pauli representation.

[(#3915)](https://github.com/PennyLaneAI/pennylane/pull/3915)

* The `coefficients` function and the `visualize` submodule of the `qml.fourier` module

now allow assigning different degrees for different parameters of the input function.

[(#3005)](https://github.com/PennyLaneAI/pennylane/pull/3005)

Previously, the arguments `degree` and `filter\_threshold` to `qml.fourier.coefficients` were

expected to be integers. Now, they can be a sequences of integers with one integer per function

parameter (i.e. `len(degree)==n\_inputs`), resulting in a returned array with shape

`(2\*degrees[0]+1,..., 2\*degrees[-1]+1)`.

The functions in `qml.fourier.visualize` accordingly accept such arrays of coefficients.

#### Other improvements

* A `Shots` class has been added to the `measurements` module to hold shot-related data.

[(#3682)](https://github.com/PennyLaneAI/pennylane/pull/3682)

* The custom JVP rules in PennyLane also now support non-scalar and mixed-shape tape parameters as

well as multi-dimensional tape return types, like broadcasted `qml.probs`, for example.

[(#3766)](https://github.com/PennyLaneAI/pennylane/pull/3766)

* The `qchem.jordan\_wigner` function has been extended to support more fermionic operator orders.

[(#3754)](https://github.com/PennyLaneAI/pennylane/pull/3754)

[(#3751)](https://github.com/PennyLaneAI/pennylane/pull/3751)

* The `AdaptiveOptimizer` has been updated to use non-default user-defined QNode arguments.

[(#3765)](https://github.com/PennyLaneAI/pennylane/pull/3765)

* Operators now use `TensorLike` types dunder methods.

[(#3749)](https://github.com/PennyLaneAI/pennylane/pull/3749)

* `qml.QubitStateVector.state\_vector` now supports broadcasting.

[(#3852)](https://github.com/PennyLaneAI/pennylane/pull/3852)

* `qml.SparseHamiltonian` can now be applied to any wires in a circuit rather than being restricted to all wires

in the circuit.

[(#3888)](https://github.com/PennyLaneAI/pennylane/pull/3888)

* Operators can now be divided by scalars with `/` with the addition of the `Operation.\_\_truediv\_\_` dunder

method.

[(#3749)](https://github.com/PennyLaneAI/pennylane/pull/3749)

* Printing an instance of `MutualInfoMP` now displays the distribution of the wires between the two subsystems.

[(#3898)](https://github.com/PennyLaneAI/pennylane/pull/3898)

* `Operator.num\_wires` has been changed from an abstract value to `AnyWires`.

[(#3919)](https://github.com/PennyLaneAI/pennylane/pull/3919)

* `qml.transforms.sum\_expand` is not run in `Device.batch\_transform` if the device supports `Sum` observables.

[(#3915)](https://github.com/PennyLaneAI/pennylane/pull/3915)

* The type of `n\_electrons` in `qml.qchem.Molecule` has been set to `int`.

[(#3885)](https://github.com/PennyLaneAI/pennylane/pull/3885)

* Explicit errors have been added to `QutritDevice` if `classical\_shadow` or `shadow\_expval` is measured.

[(#3934)](https://github.com/PennyLaneAI/pennylane/pull/3934)

* `QubitDevice` now defines the private `\_get\_diagonalizing\_gates(circuit)` method and uses it when executing circuits.

This allows devices that inherit from `QubitDevice` to override and customize their definition of diagonalizing gates.

[(#3938)](https://github.com/PennyLaneAI/pennylane/pull/3938)

* `retworkx` has been renamed to `rustworkx` to accommodate the change in the package name.

[(#3975)](https://github.com/PennyLaneAI/pennylane/pull/3975)

* `Exp`, `Sum`, `Prod`, and `SProd` operator data is now a flat list instead of nested.

[(#3958)](https://github.com/PennyLaneAI/pennylane/pull/3958)

[(#3983)](https://github.com/PennyLaneAI/pennylane/pull/3983)

* `qml.transforms.convert\_to\_numpy\_parameters` has been added to convert a circuit with interface-specific parameters to one

with only numpy parameters. This transform is designed to replace `qml.tape.Unwrap`.

[(#3899)](https://github.com/PennyLaneAI/pennylane/pull/3899)

* `qml.operation.WiresEnum.AllWires` is now -2 instead of 0 to avoid the

ambiguity between `op.num\_wires = 0` and `op.num\_wires = AllWires`.

[(#3978)](https://github.com/PennyLaneAI/pennylane/pull/3978)

* Execution code has been updated to use the new `qml.transforms.convert\_to\_numpy\_parameters` instead of `qml.tape.Unwrap`.

[(#3989)](https://github.com/PennyLaneAI/pennylane/pull/3989)

* A sub-routine of `expand\_tape` has been converted into `qml.tape.tape.rotations\_and\_diagonal\_measurements`,

a helper function that computes rotations and diagonal measurements for a tape with measurements

with overlapping wires.

[(#3912)](https://github.com/PennyLaneAI/pennylane/pull/3912)

* Various operators and templates have been updated to ensure that their decompositions only return lists of operators.

[(#3243)](https://github.com/PennyLaneAI/pennylane/pull/3243)

* The `qml.operation.enable\_new\_opmath` toggle has been introduced to cause dunder methods to return arithmetic

operators instead of a `Hamiltonian` or `Tensor`.

[(#4008)](https://github.com/PennyLaneAI/pennylane/pull/4008)

```

>>> type(qml.PauliX(0) @ qml.PauliZ(1))

<class 'pennylane.operation.Tensor'>

>>> qml.operation.enable\_new\_opmath()

>>> type(qml.PauliX(0) @ qml.PauliZ(1))

<class 'pennylane.ops.op\_math.prod.Prod'>

>>> qml.operation.disable\_new\_opmath()

>>> type(qml.PauliX(0) @ qml.PauliZ(1))

<class 'pennylane.operation.Tensor'>

```

* A new data class called `Resources` has been added to store resources like the number of gates and

circuit depth throughout a quantum circuit.

[(#3981)](https://github.com/PennyLaneAI/pennylane/pull/3981/)

* A new function called `\_count\_resources()` has been added to count the resources required when executing a

`QuantumTape` for a given number of shots.

[(#3996)](https://github.com/PennyLaneAI/pennylane/pull/3996)

* `QuantumScript.specs` has been modified to make use of the new `Resources` class. This also modifies the

output of `qml.specs()`.

[(#4015)](https://github.com/PennyLaneAI/pennylane/pull/4015)

* A new class called `ResourcesOperation` has been added to allow users to define operations with custom resource information.

[(#4026)](https://github.com/PennyLaneAI/pennylane/pull/4026)

For example, users can define a custom operation by inheriting from this new class:

```

>>> class CustomOp(qml.resource.ResourcesOperation):

...     def resources(self):

...         return qml.resource.Resources(num\_wires=1, num\_gates=2,

...                                       gate\_types={"PauliX": 2})

...

>>> CustomOp(wires=1)

CustomOp(wires=[1])

```

Then, we can track and display the resources of the workflow using `qml.specs()`:

```

>>> dev = qml.device("default.qubit", wires=[0,1])

>>> @qml.qnode(dev)

... def circ():

...     qml.PauliZ(wires=0)

...     CustomOp(wires=1)

...     return qml.state()

...

>>> print(qml.specs(circ)()['resources'])

wires: 2

gates: 3

depth: 1

shots: 0

gate\_types:

{'PauliZ': 1, 'PauliX': 2}

```

* `MeasurementProcess.shape` now accepts a `Shots` object as one of its arguments to reduce exposure to unnecessary

execution details.

[(#4012)](https://github.com/PennyLaneAI/pennylane/pull/4012)

### Breaking changes 💔

* The `seed\_recipes` argument has been removed from `qml.classical\_shadow` and `qml.shadow\_expval`.

[(#4020)](https://github.com/PennyLaneAI/pennylane/pull/4020)

* The tape method `get\_operation` has an updated signature.

[(#3998)](https://github.com/PennyLaneAI/pennylane/pull/3998)

* Both JIT interfaces are no longer compatible with JAX `>0.4.3` (we raise an error for those versions).

[(#3877)](https://github.com/PennyLaneAI/pennylane/pull/3877)

* An operation that implements a custom `generator` method, but does not always return a valid generator, also has

to implement a `has\_generator` property that reflects in which scenarios a generator will be returned.

[(#3875)](https://github.com/PennyLaneAI/pennylane/pull/3875)

* Trainable parameters for the Jax interface are the parameters that are `JVPTracer`, defined by setting

`argnums`. Previously, all JAX tracers, including those used for JIT compilation, were interpreted to be trainable.

[(#3697)](https://github.com/PennyLaneAI/pennylane/pull/3697)

* The keyword argument `argnums` is now used for gradient transforms using Jax instead of `argnum`.

`argnum` is automatically converted to `argnums` when using Jax and will no longer be supported in v0.31 of PennyLane.

[(#3697)](https://github.com/PennyLaneAI/pennylane/pull/3697)

[(#3847)](https://github.com/PennyLaneAI/pennylane/pull/3847)

* `qml.OrbitalRotation` and, consequently, `qml.GateFabric` are now more consistent with the interleaved Jordan-Wigner ordering.

Previously, they were consistent with the sequential Jordan-Wigner ordering.

[(#3861)](https://github.com/PennyLaneAI/pennylane/pull/3861)

* Some `MeasurementProcess` classes can now only be instantiated with arguments that they will actually use.

For example, you can no longer create `StateMP(qml.PauliX(0))` or `PurityMP(eigvals=(-1,1), wires=Wires(0))`.

[(#3898)](https://github.com/PennyLaneAI/pennylane/pull/3898)

* `Exp`, `Sum`, `Prod`, and `SProd` operator data is now a flat list, instead of nested.

[(#3958)](https://github.com/PennyLaneAI/pennylane/pull/3958)

[(#3983)](https://github.com/PennyLaneAI/pennylane/pull/3983)

* `qml.tape.tape.expand\_tape` and, consequentially, `QuantumScript.expand` no longer update the input tape

with rotations and diagonal measurements. Note that the newly expanded tape that is returned will still have

the rotations and diagonal measurements.

[(#3912)](https://github.com/PennyLaneAI/pennylane/pull/3912)

* `qml.Evolution` now initializes the coefficient with a factor of `-1j` instead of `1j`.

[(#4024)](https://github.com/PennyLaneAI/pennylane/pull/4024)

### Deprecations 👋

Nothing for this release!

### Documentation 📝

* The documentation of `QubitUnitary` and `DiagonalQubitUnitary` was clarified regarding the

parameters of the operations.

[(#4031)](https://github.com/PennyLaneAI/pennylane/pull/4031)

* A typo has been corrected in the documentation for the introduction to `inspecting\_circuits` and `chemistry`.

[(#3844)](https://github.com/PennyLaneAI/pennylane/pull/3844)

* `Usage Details` and `Theory` sections have been separated in the documentation for `qml.qchem.taper\_operation`.

[(3977)](https://github.com/PennyLaneAI/pennylane/pull/3977)

### Bug fixes 🐛

* `ctrl\_decomp\_bisect` and `ctrl\_decomp\_zyz` are no longer used by default when decomposing

controlled operations due to the presence of a global phase difference in the zyz decomposition of some target operators.

[(#4065)](https://github.com/PennyLaneAI/pennylane/pull/4065)

* Fixed a bug where `qml.math.dot` returned a numpy array instead of an autograd array, breaking autograd derivatives

in certain circumstances.

[(#4019)](https://github.com/PennyLaneAI/pennylane/pull/4019)

* Operators now cast a `tuple` to an `np.ndarray` as well as `list`.

[(#4022)](https://github.com/PennyLaneAI/pennylane/pull/4022)

* Fixed a bug where `qml.ctrl` with parametric gates was incompatible with PyTorch tensors on GPUs.

[(#4002)](https://github.com/PennyLaneAI/pennylane/pull/4002)

* Fixed a bug where the broadcast expand results were stacked along the wrong axis for the new return system.

[(#3984)](https://github.com/PennyLaneAI/pennylane/pull/3984)

* A more informative error message is raised in `qml.jacobian` to explain potential

problems with the new return types specification.

[(#3997)](https://github.com/PennyLaneAI/pennylane/pull/3997)

* Fixed a bug where calling `Evolution.generator` with `coeff` being a complex ArrayBox raised an error.

[(#3796)](https://github.com/PennyLaneAI/pennylane/pull/3796)

* `MeasurementProcess.hash` now uses the hash property of the observable. The property now depends on all

properties that affect the behaviour of the object, such as `VnEntropyMP.log\_base` or the distribution of wires between

the two subsystems in `MutualInfoMP`.

[(#3898)](https://github.com/PennyLaneAI/pennylane/pull/3898)

* The enum `measurements.Purity` has been added so that `PurityMP.return\_type` is defined. `str` and `repr` for `PurityMP` are also now defined.

[(#3898)](https://github.com/PennyLaneAI/pennylane/pull/3898)

* `Sum.hash` and `Prod.hash` have been changed slightly

to work with non-numeric wire labels. `sum\_expand` should now return correct results and not treat some products as the same

operation.

[(#3898)](https://github.com/PennyLaneAI/pennylane/pull/3898)

* Fixed bug where the coefficients where not ordered correctly when summing a `ParametrizedHamiltonian`

with other operators.

[(#3749)](https://github.com/PennyLaneAI/pennylane/pull/3749)

[(#3902)](https://github.com/PennyLaneAI/pennylane/pull/3902)

* The metric tensor transform is now fully compatible with Jax and therefore users can provide multiple parameters.

[(#3847)](https://github.com/PennyLaneAI/pennylane/pull/3847)

* `qml.math.ndim` and `qml.math.shape` are now registered for built-ins and autograd to accomodate Autoray 0.6.1.

[#3864](https://github.com/PennyLaneAI/pennylane/pull/3865)

* Ensured that `qml.data.load` returns datasets in a stable and expected order.

[(#3856)](https://github.com/PennyLaneAI/pennylane/pull/3856)

* The `qml.equal` function now handles comparisons of `ParametrizedEvolution` operators.

[(#3870)](https://github.com/PennyLaneAI/pennylane/pull/3870)

* `qml.devices.qubit.apply\_operation` catches the `tf.errors.UnimplementedError` that occurs when `PauliZ` or `CNOT` gates

are applied to a large (>8 wires) tensorflow state. When that occurs, the logic falls back to the tensordot logic instead.

[(#3884)](https://github.com/PennyLaneAI/pennylane/pull/3884/)

* Fixed parameter broadcasting support with `qml.counts` in most cases and introduced explicit errors otherwise.

[(#3876)](https://github.com/PennyLaneAI/pennylane/pull/3876)

* An error is now raised if a QNode with Jax-jit in use returns `counts` while having trainable parameters

[(#3892)](https://github.com/PennyLaneAI/pennylane/pull/3892)

* A correction has been added to the reference values in `test\_dipole\_of` to account for small changes

(~`2e-8`) in the computed dipole moment values resulting from the new [PySCF 2.2.0](https://github.com/pyscf/pyscf/releases/tag/v2.2.0) release.

[(#3908)](https://github.com/PennyLaneAI/pennylane/pull/3908)

* `SampleMP.shape` is now correct when sampling only occurs on a subset of the device wires.

[(#3921)](https://github.com/PennyLaneAI/pennylane/pull/3921)

* An issue has been fixed in `qchem.Molecule` to allow basis sets other than the hard-coded ones to be

used in the `Molecule` class.

[(#3955)](https://github.com/PennyLaneAI/pennylane/pull/3955)

* Fixed bug where all devices that inherit from `DefaultQubit` claimed to support `ParametrizedEvolution`.

Now, only `DefaultQubitJax` supports the operator, as expected.

[(#3964)](https://github.com/PennyLaneAI/pennylane/pull/3964)

* Ensured that parallel `AnnotatedQueues` do not queue each other’s contents.

[(#3924)](https://github.com/PennyLaneAI/pennylane/pull/3924)

* Added a `map\_wires` method to `PauliWord` and `PauliSentence`, and ensured that operators call

it in their respective `map\_wires` methods if they have a Pauli rep.

[(#3985)](https://github.com/PennyLaneAI/pennylane/pull/3985)

* Fixed a bug when a `Tensor` is multiplied by a `Hamiltonian` or vice versa.

[(#4036)](https://github.com/PennyLaneAI/pennylane/pull/4036)

### Contributors ✍️

This release contains contributions from (in alphabetical order):

Komi Amiko,

Utkarsh Azad,

Thomas Bromley,

Isaac De Vlugt,

Olivia Di Matteo,

Lillian M. A. Frederiksen,

Diego Guala,

Soran Jahangiri,

Korbinian Kottmann,

Christina Lee,

Vincent Michaud-Rioux,

Albert Mitjans Coma,

Romain Moyard,

Lee J. O’Riordan,

Mudit Pandey,

Matthew Silverman,

Jay Soni,

David Wierichs.

orphan

#### Release 0.29.0[¶](#release-0-29-0 "Permalink to this headline")

### New features since last release

#### Pulse programming 🔊

* Support for creating pulse-based circuits that describe evolution under a time-dependent

Hamiltonian has now been added, as well as the ability to execute and differentiate these

pulse-based circuits on simulator.

[(#3586)](https://github.com/PennyLaneAI/pennylane/pull/3586)

[(#3617)](https://github.com/PennyLaneAI/pennylane/pull/3617)

[(#3645)](https://github.com/PennyLaneAI/pennylane/pull/3645)

[(#3652)](https://github.com/PennyLaneAI/pennylane/pull/3652)

[(#3665)](https://github.com/PennyLaneAI/pennylane/pull/3665)

[(#3673)](https://github.com/PennyLaneAI/pennylane/pull/3673)

[(#3706)](https://github.com/PennyLaneAI/pennylane/pull/3706)

[(#3730)](https://github.com/PennyLaneAI/pennylane/pull/3730)

A time-dependent Hamiltonian can be created using `qml.pulse.ParametrizedHamiltonian`, which

holds information representing a linear combination of operators

with parametrized coefficents and can be constructed as follows:

```

from jax import numpy as jnp

f1 = lambda p, t: p \* jnp.sin(t) \* (t - 1)

f2 = lambda p, t: p[0] \* jnp.cos(p[1]\* t \*\* 2)

XX = qml.PauliX(0) @ qml.PauliX(1)

YY = qml.PauliY(0) @ qml.PauliY(1)

ZZ = qml.PauliZ(0) @ qml.PauliZ(1)

H =  2 \* ZZ + f1 \* XX + f2 \* YY

```

```

>>> H

ParametrizedHamiltonian: terms=3

>>> p1 = jnp.array(1.2)

>>> p2 = jnp.array([2.3, 3.4])

>>> H((p1, p2), t=0.5)

(2\*(PauliZ(wires=[0]) @ PauliZ(wires=[1]))) + ((-0.2876553231625218\*(PauliX(wires=[0]) @ PauliX(wires=[1]))) + (1.517961235535459\*(PauliY(wires=[0]) @ PauliY(wires=[1]))))

```

The time-dependent Hamiltonian can be used within a circuit with `qml.evolve`:

```

def pulse\_circuit(params, time):

    qml.evolve(H)(params, time)

    return qml.expval(qml.PauliX(0) @ qml.PauliY(1))

```

Pulse-based circuits can be executed and differentiated on the `default.qubit.jax` simulator using

JAX as an interface:

```

>>> dev = qml.device("default.qubit.jax", wires=2)

>>> qnode = qml.QNode(pulse\_circuit, dev, interface="jax")

>>> params = (p1, p2)

>>> qnode(params, time=0.5)

Array(0.72153819, dtype=float64)

>>> jax.grad(qnode)(params, time=0.5)

(Array(-0.11324919, dtype=float64),

 Array([-0.64399616, 0.06326374], dtype=float64))

```

Check out the [qml.pulse](https://docs.pennylane.ai/en/stable/code/qml_pulse.html) documentation

page for more details!

#### Special unitary operation 🌞

* A new operation `qml.SpecialUnitary` has been added, providing access to an arbitrary

unitary gate via a parametrization in the Pauli basis.

[(#3650)](https://github.com/PennyLaneAI/pennylane/pull/3650)

[(#3651)](https://github.com/PennyLaneAI/pennylane/pull/3651)

[(#3674)](https://github.com/PennyLaneAI/pennylane/pull/3674)

`qml.SpecialUnitary` creates a unitary that exponentiates a linear combination of all possible Pauli words in lexicographical order — except for the identity operator — for `num\_wires` wires, of which there are `4\*\*num\_wires - 1`. As its first argument,

`qml.SpecialUnitary` takes a list of the `4\*\*num\_wires - 1` parameters that are the coefficients of the linear combination.

To see all possible Pauli words for `num\_wires` wires, you can use the `qml.ops.qubit.special\_unitary.pauli\_basis\_strings` function:

```

>>> qml.ops.qubit.special\_unitary.pauli\_basis\_strings(1) # 4\*\*1-1 = 3 Pauli words

['X', 'Y', 'Z']

>>> qml.ops.qubit.special\_unitary.pauli\_basis\_strings(2) # 4\*\*2-1 = 15 Pauli words

['IX', 'IY', 'IZ', 'XI', 'XX', 'XY', 'XZ', 'YI', 'YX', 'YY', 'YZ', 'ZI', 'ZX', 'ZY', 'ZZ']

```

To use `qml.SpecialUnitary`, for example, on a single qubit, we may define

```

>>> thetas = np.array([0.2, 0.1, -0.5])

>>> U = qml.SpecialUnitary(thetas, 0)

>>> qml.matrix(U)

array([[ 0.8537127 -0.47537233j, 0.09507447+0.19014893j],

 [-0.09507447+0.19014893j, 0.8537127 +0.47537233j]])

```

A single non-zero entry in the parameters will create a Pauli rotation:

```

>>> x = 0.412

>>> theta = x \* np.array([1, 0, 0]) # The first entry belongs to the Pauli word "X"

>>> su = qml.SpecialUnitary(theta, wires=0)

>>> rx = qml.RX(-2 \* x, 0) # RX introduces a prefactor -0.5 that has to be compensated

>>> qml.math.allclose(qml.matrix(su), qml.matrix(rx))

True

```

This operation can be differentiated with hardware-compatible methods like parameter shifts

and it supports parameter broadcasting/batching, but not both at the same time. Learn more by

visiting the

[qml.SpecialUnitary](https://docs.pennylane.ai/en/stable/code/api/pennylane.SpecialUnitary.html)

documentation.

#### Always differentiable 📈

* The Hadamard test gradient transform is now available via `qml.gradients.hadamard\_grad`. This transform

is also available as a differentiation method within `QNode`s.

[(#3625)](https://github.com/PennyLaneAI/pennylane/pull/3625)

[(#3736)](https://github.com/PennyLaneAI/pennylane/pull/3736)

`qml.gradients.hadamard\_grad` is a hardware-compatible transform that calculates the

gradient of a quantum circuit using the Hadamard test. Note that the device requires an

auxiliary wire to calculate the gradient.

```

>>> dev = qml.device("default.qubit", wires=2)

>>> @qml.qnode(dev)

... def circuit(params):

...     qml.RX(params[0], wires=0)

...     qml.RY(params[1], wires=0)

...     qml.RX(params[2], wires=0)

...     return qml.expval(qml.PauliZ(0))

>>> params = np.array([0.1, 0.2, 0.3], requires\_grad=True)

>>> qml.gradients.hadamard\_grad(circuit)(params)

(tensor(-0.3875172, requires\_grad=True),

 tensor(-0.18884787, requires\_grad=True),

 tensor(-0.38355704, requires\_grad=True))

```

This transform can be registered directly as the quantum gradient transform to use during

autodifferentiation:

```

>>> dev = qml.device("default.qubit", wires=2)

>>> @qml.qnode(dev, interface="jax", diff\_method="hadamard")

... def circuit(params):

...     qml.RX(params[0], wires=0)

...     qml.RY(params[1], wires=0)

...     qml.RX(params[2], wires=0)

...     return qml.expval(qml.PauliZ(0))

>>> params = jax.numpy.array([0.1, 0.2, 0.3])

>>> jax.jacobian(circuit)(params)

Array([-0.3875172 , -0.18884787, -0.38355705], dtype=float32)

```

* The gradient transform `qml.gradients.spsa\_grad` is now registered as a

differentiation method for QNodes.

[(#3440)](https://github.com/PennyLaneAI/pennylane/pull/3440)

The SPSA gradient transform can now be used implicitly by marking a QNode

as differentiable with SPSA. It can be selected via

```

>>> dev = qml.device("default.qubit", wires=1)

>>> @qml.qnode(dev, interface="jax", diff\_method="spsa", h=0.05, num\_directions=20)

... def circuit(x):

...     qml.RX(x, 0)

...     return qml.expval(qml.PauliZ(0))

>>> jax.jacobian(circuit)(jax.numpy.array(0.5))

Array(-0.4792258, dtype=float32, weak\_type=True)

```

The argument `num\_directions` determines how many directions of simultaneous

perturbation are used and therefore the number of circuit evaluations, up

to a prefactor. See the

[SPSA gradient transform documentation](https://docs.pennylane.ai/en/stable/code/api/pennylane.gradients.spsa_grad.html) for details.

Note: The full SPSA optimization method is already available as `qml.SPSAOptimizer`.

* The default interface is now `auto`. There is no need to specify the interface anymore; it is automatically

determined by checking your QNode parameters.

[(#3677)](https://github.com/PennyLaneAI/pennylane/pull/3677)

[(#3752)](https://github.com/PennyLaneAI/pennylane/pull/3752)

[(#3829)](https://github.com/PennyLaneAI/pennylane/pull/3829)

```

import jax

import jax.numpy as jnp

qml.enable\_return()

a = jnp.array(0.1)

b = jnp.array(0.2)

dev = qml.device("default.qubit", wires=2)

@qml.qnode(dev)

def circuit(a, b):

    qml.RY(a, wires=0)

    qml.RX(b, wires=1)

    qml.CNOT(wires=[0, 1])

    return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliY(1))

```

```

>>> circuit(a, b)

(Array(0.9950042, dtype=float32), Array(-0.19767681, dtype=float32))

>>> jac = jax.jacobian(circuit)(a, b)

>>> jac

(Array(-0.09983341, dtype=float32, weak\_type=True), Array(0.01983384, dtype=float32, weak\_type=True))

```

* The JAX-JIT interface now supports higher-order gradient computation with the new return types system.

[(#3498)](https://github.com/PennyLaneAI/pennylane/pull/3498)

Here is an example of using JAX-JIT to compute the Hessian of a circuit:

```

import pennylane as qml

import jax

from jax import numpy as jnp

jax.config.update("jax\_enable\_x64", True)

qml.enable\_return()

dev = qml.device("default.qubit", wires=2)

@jax.jit

@qml.qnode(dev, interface="jax-jit", diff\_method="parameter-shift", max\_diff=2)

def circuit(a, b):

    qml.RY(a, wires=0)

    qml.RX(b, wires=1)

    return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliZ(1))

a, b = jnp.array(1.0), jnp.array(2.0)

```

```

>>> jax.hessian(circuit, argnums=[0, 1])(a, b)

(((Array(-0.54030231, dtype=float64, weak\_type=True),

 Array(0., dtype=float64, weak\_type=True)),

 (Array(-1.76002563e-17, dtype=float64, weak\_type=True),

 Array(0., dtype=float64, weak\_type=True))),

 ((Array(0., dtype=float64, weak\_type=True),

 Array(-1.00700085e-17, dtype=float64, weak\_type=True)),

 (Array(0., dtype=float64, weak\_type=True),

 Array(0.41614684, dtype=float64, weak\_type=True))))

```

* The `qchem` workflow has been modified to support both Autograd and JAX frameworks.

[(#3458)](https://github.com/PennyLaneAI/pennylane/pull/3458)

[(#3462)](https://github.com/PennyLaneAI/pennylane/pull/3462)

[(#3495)](https://github.com/PennyLaneAI/pennylane/pull/3495)

The JAX interface is automatically used when the differentiable parameters are JAX objects. Here

is an example for computing the Hartree-Fock energy gradients with respect to the atomic

coordinates.

```

import pennylane as qml

from pennylane import numpy as np

import jax

symbols = ["H", "H"]

geometry = np.array([[0.0, 0.0, 0.0], [0.0, 0.0, 1.0]])

mol = qml.qchem.Molecule(symbols, geometry)

args = [jax.numpy.array(mol.coordinates)]

```

```

>>> jax.grad(qml.qchem.hf\_energy(mol))(\*args)

Array([[ 0. , 0. , 0.3650435],

 [ 0. , 0. , -0.3650435]], dtype=float64)

```

* The kernel matrix utility functions in `qml.kernels` are now autodifferentiation-compatible.

In addition, they support batching, for example for quantum kernel execution with shot vectors.

[(#3742)](https://github.com/PennyLaneAI/pennylane/pull/3742)

This allows for the following:

```

dev = qml.device('default.qubit', wires=2, shots=(100, 100))

@qml.qnode(dev)

def circuit(x1, x2):

    qml.templates.AngleEmbedding(x1, wires=dev.wires)

    qml.adjoint(qml.templates.AngleEmbedding)(x2, wires=dev.wires)

    return qml.probs(wires=dev.wires)

kernel = lambda x1, x2: circuit(x1, x2)

```

We can then compute the kernel matrix on a set of 4 (random) feature

vectors `X` but using two sets of 100 shots each via

```

>>> X = np.random.random((4, 2))

>>> qml.kernels.square\_kernel\_matrix(X, kernel)[:, 0]

tensor([[[1. , 0.86, 0.88, 0.92],

 [0.86, 1. , 0.75, 0.97],

 [0.88, 0.75, 1. , 0.91],

 [0.92, 0.97, 0.91, 1. ]],

 [[1. , 0.93, 0.91, 0.92],

 [0.93, 1. , 0.8 , 1. ],

 [0.91, 0.8 , 1. , 0.91],

 [0.92, 1. , 0.91, 1. ]]], requires\_grad=True)

```

Note that we have extracted the first probability vector entry for each 100-shot evaluation.

#### Smartly decompose Hamiltonian evolution 💯

* Hamiltonian evolution using `qml.evolve` or `qml.exp` can now be decomposed into operations.

[(#3691)](https://github.com/PennyLaneAI/pennylane/pull/3691)

[(#3777)](https://github.com/PennyLaneAI/pennylane/pull/3777)

If the time-evolved Hamiltonian is equivalent to another PennyLane operation, then that

operation is returned as the decomposition:

```

>>> exp\_op = qml.evolve(qml.PauliX(0) @ qml.PauliX(1))

>>> exp\_op.decomposition()

[IsingXX((2+0j), wires=[0, 1])]

```

If the Hamiltonian is a Pauli word, then the decomposition is provided as a

`qml.PauliRot` operation:

```

>>> qml.evolve(qml.PauliZ(0) @ qml.PauliX(1)).decomposition()

[PauliRot((2+0j), ZX, wires=[0, 1])]

```

Otherwise, the Hamiltonian is a linear combination of operators and the Suzuki-Trotter

decomposition is used:

```

>>> qml.evolve(qml.sum(qml.PauliX(0), qml.PauliY(0), qml.PauliZ(0)), num\_steps=2).decomposition()

[RX((1+0j), wires=[0]),

 RY((1+0j), wires=[0]),

 RZ((1+0j), wires=[0]),

 RX((1+0j), wires=[0]),

 RY((1+0j), wires=[0]),

 RZ((1+0j), wires=[0])]

```

#### Tools for quantum chemistry and other applications 🛠️

* A new method called `qml.qchem.givens\_decomposition` has been added, which decomposes a unitary into a sequence

of Givens rotation gates with phase shifts and a diagonal phase matrix.

[(#3573)](https://github.com/PennyLaneAI/pennylane/pull/3573)

```

unitary = np.array([[ 0.73678+0.27511j, -0.5095 +0.10704j, -0.06847+0.32515j],

                    [-0.21271+0.34938j, -0.38853+0.36497j,  0.61467-0.41317j],

                    [ 0.41356-0.20765j, -0.00651-0.66689j,  0.32839-0.48293j]])

phase\_mat, ordered\_rotations = qml.qchem.givens\_decomposition(unitary)

```

```

>>> phase\_mat

tensor([-0.20604358+0.9785369j , -0.82993272+0.55786114j,

 0.56230612-0.82692833j], requires\_grad=True)

>>> ordered\_rotations

[(tensor([[-0.65087861-0.63937521j, -0.40933651-0.j ],

 [-0.29201359-0.28685265j, 0.91238348-0.j ]], requires\_grad=True),

 (0, 1)),

(tensor([[ 0.47970366-0.33308926j, -0.8117487 -0.j ],

 [ 0.66677093-0.46298215j, 0.5840069 -0.j ]], requires\_grad=True),

 (1, 2)),

(tensor([[ 0.36147547+0.73779454j, -0.57008306-0.j ],

 [ 0.2508207 +0.51194108j, 0.82158706-0.j ]], requires\_grad=True),

 (0, 1))]

```

* A new template called `qml.BasisRotation` has been added, which performs a basis transformation defined by a set of

fermionic ladder operators.

[(#3573)](https://github.com/PennyLaneAI/pennylane/pull/3573)

```

import pennylane as qml

from pennylane import numpy as np

V = np.array([[ 0.53672126+0.j        , -0.1126064 -2.41479668j],

              [-0.1126064 +2.41479668j,  1.48694623+0.j        ]])

eigen\_vals, eigen\_vecs = np.linalg.eigh(V)

umat = eigen\_vecs.T

wires = range(len(umat))

def circuit():

    qml.adjoint(qml.BasisRotation(wires=wires, unitary\_matrix=umat))

    for idx, eigenval in enumerate(eigen\_vals):

        qml.RZ(eigenval, wires=[idx])

    qml.BasisRotation(wires=wires, unitary\_matrix=umat)

```

```

>>> circ\_unitary = qml.matrix(circuit)()

>>> np.round(circ\_unitary/circ\_unitary[0][0], 3)

tensor([[ 1. -0.j , -0. +0.j , -0. +0.j , -0. +0.j ],

 [-0. +0.j , -0.516-0.596j, -0.302-0.536j, -0. +0.j ],

 [-0. +0.j , 0.35 +0.506j, -0.311-0.724j, -0. +0.j ],

 [-0. +0.j , -0. +0.j , -0. +0.j , -0.438+0.899j]], requires\_grad=True)

```

* A new function called `qml.qchem.load\_basisset` has been added to extract `qml.qchem` basis set data from the Basis Set Exchange

library.

[(#3363)](https://github.com/PennyLaneAI/pennylane/pull/3363)

* A new function called `qml.math.max\_entropy` has been added to compute the maximum entropy of a quantum state.

[(#3594)](https://github.com/PennyLaneAI/pennylane/pull/3594)

* A new template called `qml.TwoLocalSwapNetwork` has been added that implements a canonical 2-complete linear (2-CCL) swap network

described in [arXiv:1905.05118](https://arxiv.org/abs/1905.05118).

[(#3447)](https://github.com/PennyLaneAI/pennylane/pull/3447)

```

dev = qml.device('default.qubit', wires=5)

weights = np.random.random(size=qml.templates.TwoLocalSwapNetwork.shape(len(dev.wires)))

acquaintances = lambda index, wires, param: (qml.CRY(param, wires=index)

                                 if np.abs(wires[0]-wires[1]) else qml.CRZ(param, wires=index))

@qml.qnode(dev)

def swap\_network\_circuit():

    qml.templates.TwoLocalSwapNetwork(dev.wires, acquaintances, weights, fermionic=False)

    return qml.state()

```

```

>>> print(weights)

tensor([0.20308242, 0.91906199, 0.67988804, 0.81290256, 0.08708985,

 0.81860084, 0.34448344, 0.05655892, 0.61781612, 0.51829044], requires\_grad=True)

>>> print(qml.draw(swap\_network\_circuit, expansion\_strategy = 'device')())

0: ─╭●────────╭SWAP─────────────────╭●────────╭SWAP─────────────────╭●────────╭SWAP─┤ State

1: ─╰RY(0.20)─╰SWAP─╭●────────╭SWAP─╰RY(0.09)─╰SWAP─╭●────────╭SWAP─╰RY(0.62)─╰SWAP─┤ State

2: ─╭●────────╭SWAP─╰RY(0.68)─╰SWAP─╭●────────╭SWAP─╰RY(0.34)─╰SWAP─╭●────────╭SWAP─┤ State

3: ─╰RY(0.92)─╰SWAP─╭●────────╭SWAP─╰RY(0.82)─╰SWAP─╭●────────╭SWAP─╰RY(0.52)─╰SWAP─┤ State

4: ─────────────────╰RY(0.81)─╰SWAP─────────────────╰RY(0.06)─╰SWAP─────────────────┤ State

```

### Improvements 🛠

#### Pulse programming

* A new function called `qml.pulse.pwc` has been added as a convenience function for defining a `qml.pulse.ParametrizedHamiltonian`.

This function can be used to create a callable coefficient by setting

the timespan over which the function should be non-zero. The resulting callable

can be passed an array of parameters and a time.

[(#3645)](https://github.com/PennyLaneAI/pennylane/pull/3645)

```

>>> timespan = (2, 4)

>>> f = qml.pulse.pwc(timespan)

>>> f \* qml.PauliX(0)

ParametrizedHamiltonian: terms=1

```

The `params` array will be used as bin values evenly distributed over the timespan,

and the parameter `t` will determine which of the bins is returned.

```

>>> f(params=[1.2, 2.3, 3.4, 4.5], t=3.9)

DeviceArray(4.5, dtype=float32)

>>> f(params=[1.2, 2.3, 3.4, 4.5], t=6)  # zero outside the range (2, 4)

DeviceArray(0., dtype=float32)

```

* A new function called`qml.pulse.pwc\_from\_function` has been added as a decorator for defining a

`qml.pulse.ParametrizedHamiltonian`.

This function can be used to decorate a function and create a piecewise constant

approximation of it.

[(#3645)](https://github.com/PennyLaneAI/pennylane/pull/3645)

```

>>> @qml.pulse.pwc\_from\_function((2, 4), num\_bins=10)

... def f1(p, t):

...     return p \* t

```

The resulting function approximates the same of `p\*\*2 \* t` on the interval `t=(2, 4)`

in 10 bins, and returns zero outside the interval.

```

# t=2 and t=2.1 are within the same bin

>>> f1(3, 2), f1(3, 2.1)

(DeviceArray(6., dtype=float32), DeviceArray(6., dtype=float32))

# next bin

>>> f1(3, 2.2)

DeviceArray(6.6666665, dtype=float32)

# outside the interval t=(2, 4)

>>> f1(3, 5)

DeviceArray(0., dtype=float32)

```

* Add `ParametrizedHamiltonianPytree` class, which is a pytree jax object representing a parametrized

Hamiltonian, where the matrix computation is delayed to improve performance.

[(#3779)](https://github.com/PennyLaneAI/pennylane/pull/3779)

#### Operations and batching

* The function `qml.dot` has been updated to compute the dot product between a vector and a list of operators.

[(#3586)](https://github.com/PennyLaneAI/pennylane/pull/3586)

```

>>> coeffs = np.array([1.1, 2.2])

>>> ops = [qml.PauliX(0), qml.PauliY(0)]

>>> qml.dot(coeffs, ops)

(1.1\*(PauliX(wires=[0]))) + (2.2\*(PauliY(wires=[0])))

>>> qml.dot(coeffs, ops, pauli=True)

1.1 \* X(0) + 2.2 \* Y(0)

```

* `qml.evolve` returns the evolution of an `Operator` or a `ParametrizedHamiltonian`.

[(#3617)](https://github.com/PennyLaneAI/pennylane/pull/3617)

[(#3706)](https://github.com/PennyLaneAI/pennylane/pull/3706)

* `qml.ControlledQubitUnitary` now inherits from `qml.ops.op\_math.ControlledOp`, which defines `decomposition`, `expand`, and `sparse\_matrix` rather than raising an error.

[(#3450)](https://github.com/PennyLaneAI/pennylane/pull/3450)

* Parameter broadcasting support has been added for the `qml.ops.op\_math.Controlled` class if the base operator supports

broadcasting.

[(#3450)](https://github.com/PennyLaneAI/pennylane/pull/3450)

* The `qml.generator` function now checks if the generator is Hermitian, rather than whether it is a subclass of

`Observable`. This allows it to return valid generators from `SymbolicOp` and `CompositeOp` classes.

[(#3485)](https://github.com/PennyLaneAI/pennylane/pull/3485)

* The `qml.equal` function has been extended to compare `Prod` and `Sum` operators.

[(#3516)](https://github.com/PennyLaneAI/pennylane/pull/3516)

* `qml.purity` has been added as a measurement process for purity

[(#3551)](https://github.com/PennyLaneAI/pennylane/pull/3551)

* In-place inversion has been removed for qutrit operations in preparation for the

removal of in-place inversion.

[(#3566)](https://github.com/PennyLaneAI/pennylane/pull/3566)

* The `qml.utils.sparse\_hamiltonian` function has been moved to thee `qml.Hamiltonian.sparse\_matrix` method.

[(#3585)](https://github.com/PennyLaneAI/pennylane/pull/3585)

* The `qml.pauli.PauliSentence.operation()` method has been improved to avoid instantiating an `SProd` operator when

the coefficient is equal to 1.

[(#3595)](https://github.com/PennyLaneAI/pennylane/pull/3595)

* Batching is now allowed in all `SymbolicOp` operators, which include `Exp`, `Pow` and `SProd`.

[(#3597)](https://github.com/PennyLaneAI/pennylane/pull/3597)

* The `Sum` and `Prod` operations now have broadcasted operands.

[(#3611)](https://github.com/PennyLaneAI/pennylane/pull/3611)

* The XYX single-qubit unitary decomposition has been implemented.

[(#3628)](https://github.com/PennyLaneAI/pennylane/pull/3628)

* All dunder methods now return `NotImplemented`, allowing the right dunder method (e.g. `\_\_radd\_\_`)

of the other class to be called.

[(#3631)](https://github.com/PennyLaneAI/pennylane/pull/3631)

* The `qml.GellMann` operators now include their index when displayed.

[(#3641)](https://github.com/PennyLaneAI/pennylane/pull/3641)

* `qml.ops.ctrl\_decomp\_zyz` has been added to compute the decomposition of a controlled single-qubit operation given

a single-qubit operation and the control wires.

[(#3681)](https://github.com/PennyLaneAI/pennylane/pull/3681)

* `qml.pauli.is\_pauli\_word` now supports `Prod` and `SProd` operators, and it returns `False` when a

`Hamiltonian` contains more than one term.

[(#3692)](https://github.com/PennyLaneAI/pennylane/pull/3692)

* `qml.pauli.pauli\_word\_to\_string` now supports `Prod`, `SProd` and `Hamiltonian` operators.

[(#3692)](https://github.com/PennyLaneAI/pennylane/pull/3692)

* `qml.ops.op\_math.Controlled` can now decompose single qubit target operations more effectively using the ZYZ

decomposition.

[(#3726)](https://github.com/PennyLaneAI/pennylane/pull/3726)

	+ The `qml.qchem.Molecule` class raises an error when the molecule has an odd number of electrons or

	when the spin multiplicity is not 1.

	[(#3748)](https://github.com/PennyLaneAI/pennylane/pull/3748)

* `qml.qchem.basis\_rotation` now accounts for spin, allowing it to perform Basis Rotation Groupings

for molecular hamiltonians.

[(#3714)](https://github.com/PennyLaneAI/pennylane/pull/3714)

[(#3774)](https://github.com/PennyLaneAI/pennylane/pull/3774)

* The gradient transforms work for the new return type system with non-trivial classical jacobians.

[(#3776)](https://github.com/PennyLaneAI/pennylane/pull/3776)

* The `default.mixed` device has received a performance improvement for multi-qubit operations.

This also allows to apply channels that act on more than seven qubits, which was not possible before.

[(#3584)](https://github.com/PennyLaneAI/pennylane/pull/3584)

* `qml.dot` now groups coefficients together.

[(#3691)](https://github.com/PennyLaneAI/pennylane/pull/3691)

```

>>> qml.dot(coeffs=[2, 2, 2], ops=[qml.PauliX(0), qml.PauliY(1), qml.PauliZ(2)])

2\*(PauliX(wires=[0]) + PauliY(wires=[1]) + PauliZ(wires=[2]))

```

* `qml.generator` now supports operators with `Sum` and `Prod` generators.

[(#3691)](https://github.com/PennyLaneAI/pennylane/pull/3691)

* The `Sum.\_sort` method now takes into account the name of the operator when sorting.

[(#3691)](https://github.com/PennyLaneAI/pennylane/pull/3691)

* A new tape transform called `qml.transforms.sign\_expand` has been added. It implements the optimal decomposition of a fast-forwardable Hamiltonian that minimizes the variance of its estimator in the Single-Qubit-Measurement from [arXiv:2207.09479](https://arxiv.org/abs/2207.09479).

[(#2852)](https://github.com/PennyLaneAI/pennylane/pull/2852)

#### Differentiability and interfaces

* The `qml.math` module now also contains a submodule for

fast Fourier transforms, `qml.math.fft`.

[(#1440)](https://github.com/PennyLaneAI/pennylane/pull/1440)

The submodule in particular provides differentiable

versions of the following functions, available in all common

interfaces for PennyLane

	+ [fft](https://numpy.org/doc/stable/reference/generated/numpy.fft.fft.html)

	+ [ifft](https://numpy.org/doc/stable/reference/generated/numpy.fft.ifft.html)

	+ [fft2](https://numpy.org/doc/stable/reference/generated/numpy.fft.fft2.html)

	+ [ifft2](https://numpy.org/doc/stable/reference/generated/numpy.fft.ifft2.html)Note that the output of the derivative of these functions

may differ when used with complex-valued inputs, due to different

conventions on complex-valued derivatives.

* Validation has been added on gradient keyword arguments when initializing a QNode — if unexpected keyword arguments are passed,

a `UserWarning` is raised. A list of the current expected gradient function keyword arguments can be accessed via

`qml.gradients.SUPPORTED\_GRADIENT\_KWARGS`.

[(#3526)](https://github.com/PennyLaneAI/pennylane/pull/3526)

* The `numpy` version has been constrained to `<1.24`.

[(#3563)](https://github.com/PennyLaneAI/pennylane/pull/3563)

* Support for two-qubit unitary decomposition with JAX-JIT has been added.

[(#3569)](https://github.com/PennyLaneAI/pennylane/pull/3569)

* `qml.math.size` now supports PyTorch tensors.

[(#3606)](https://github.com/PennyLaneAI/pennylane/pull/3606)

* Most quantum channels are now fully differentiable on all interfaces.

[(#3612)](https://github.com/PennyLaneAI/pennylane/pull/3612)

* `qml.math.matmul` now supports PyTorch and Autograd tensors.

[(#3613)](https://github.com/PennyLaneAI/pennylane/pull/3613)

* Add `qml.math.detach`, which detaches a tensor from its trace. This stops

automatic gradient computations.

[(#3674)](https://github.com/PennyLaneAI/pennylane/pull/3674)

* Add `typing.TensorLike` type.

[(#3675)](https://github.com/PennyLaneAI/pennylane/pull/3675)

* `qml.QuantumMonteCarlo` template is now JAX-JIT compatible when passing `jax.numpy` arrays to the template.

[(#3734)](https://github.com/PennyLaneAI/pennylane/pull/3734)

* `DefaultQubitJax` now supports evolving the state vector when executing `qml.pulse.ParametrizedEvolution`

gates.

[(#3743)](https://github.com/PennyLaneAI/pennylane/pull/3743)

* `SProd.sparse\_matrix` now supports interface-specific variables with a single element as the `scalar`.

[(#3770)](https://github.com/PennyLaneAI/pennylane/pull/3770)

* Added `argnum` argument to `metric\_tensor`. By passing a sequence of indices referring to trainable tape parameters,

the metric tensor is only computed with respect to these parameters. This reduces the number of tapes that have to

be run.

[(#3587)](https://github.com/PennyLaneAI/pennylane/pull/3587)

* The parameter-shift derivative of variances saves a redundant evaluation of the

corresponding unshifted expectation value tape, if possible

[(#3744)](https://github.com/PennyLaneAI/pennylane/pull/3744)

#### Next generation device API

* The `apply\_operation` single-dispatch function is added to `devices/qubit` that applies an operation

to a state and returns a new state.

[(#3637)](https://github.com/PennyLaneAI/pennylane/pull/3637)

* The `preprocess` function is added to `devices/qubit` that validates, expands, and transforms a batch

of `QuantumTape` objects to abstract preprocessing details away from the device.

[(#3708)](https://github.com/PennyLaneAI/pennylane/pull/3708)

* The `create\_initial\_state` function is added to `devices/qubit` that returns an initial state for an execution.

[(#3683)](https://github.com/PennyLaneAI/pennylane/pull/3683)

* The `simulate` function is added to `devices/qubit` that turns a single quantum tape into a measurement result.

The function only supports state based measurements with either no observables or observables with diagonalizing gates.

It supports simultaneous measurement of non-commuting observables.

[(#3700)](https://github.com/PennyLaneAI/pennylane/pull/3700)

* The `ExecutionConfig` data class has been added.

[(#3649)](https://github.com/PennyLaneAI/pennylane/pull/3649)

* The `StatePrep` class has been added as an interface that state-prep operators must implement.

[(#3654)](https://github.com/PennyLaneAI/pennylane/pull/3654)

* `qml.QubitStateVector` now implements the `StatePrep` interface.

[(#3685)](https://github.com/PennyLaneAI/pennylane/pull/3685)

* `qml.BasisState` now implements the `StatePrep` interface.

[(#3693)](https://github.com/PennyLaneAI/pennylane/pull/3693)

* New Abstract Base Class for devices `Device` is added to the `devices.experimental` submodule.

This interface is still in experimental mode and not integrated with the rest of pennylane.

[(#3602)](https://github.com/PennyLaneAI/pennylane/pull/3602)

#### Other improvements

* Writing Hamiltonians to a file using the `qml.data` module has been improved by employing a condensed writing format.

[(#3592)](https://github.com/PennyLaneAI/pennylane/pull/3592)

* Lazy-loading in the `qml.data.Dataset.read()` method is more universally supported.

[(#3605)](https://github.com/PennyLaneAI/pennylane/pull/3605)

* The `qchem.Molecule` class raises an error when the molecule has an odd number of electrons or

when the spin multiplicity is not 1.

[(#3748)](https://github.com/PennyLaneAI/pennylane/pull/3748)

* `qml.draw` and `qml.draw\_mpl` have been updated to draw any quantum function,

which allows for visualizing only part of a complete circuit/QNode.

[(#3760)](https://github.com/PennyLaneAI/pennylane/pull/3760)

* The string representation of a Measurement Process now includes the `\_eigvals`

property if it is set.

[(#3820)](https://github.com/PennyLaneAI/pennylane/pull/3820)

### Breaking changes 💔

* The argument `mode` in execution has been replaced by the boolean `grad\_on\_execution` in the new execution pipeline.

[(#3723)](https://github.com/PennyLaneAI/pennylane/pull/3723)

* `qml.VQECost` has been removed.

[(#3735)](https://github.com/PennyLaneAI/pennylane/pull/3735)

* The default interface is now `auto`.

[(#3677)](https://github.com/PennyLaneAI/pennylane/pull/3677)

[(#3752)](https://github.com/PennyLaneAI/pennylane/pull/3752)

[(#3829)](https://github.com/PennyLaneAI/pennylane/pull/3829)

The interface is determined during the QNode call instead of the

initialization. It means that the `gradient\_fn` and `gradient\_kwargs` are only defined on the QNode at the beginning

of the call. Moreover, without specifying the interface it is not possible to guarantee that the device will not be changed

during the call if you are using backprop (such as `default.qubit` changing to `default.qubit.jax`) whereas before it was happening at

initialization.

* The tape method `get\_operation` can also now return the operation index in the tape, and it can be

activated by setting the `return\_op\_index` to `True`: `get\_operation(idx, return\_op\_index=True)`. It will become

the default in version `0.30`.

[(#3667)](https://github.com/PennyLaneAI/pennylane/pull/3667)

* `Operation.inv()` and the `Operation.inverse` setter have been removed. Please use `qml.adjoint` or `qml.pow` instead.

[(#3618)](https://github.com/PennyLaneAI/pennylane/pull/3618)

For example, instead of

```

>>> qml.PauliX(0).inv()

```

use

```

>>> qml.adjoint(qml.PauliX(0))

```

* The `Operation.inverse` property has been removed completely.

[(#3725)](https://github.com/PennyLaneAI/pennylane/pull/3725)

* The target wires of `qml.ControlledQubitUnitary` are no longer available via `op.hyperparameters["u\_wires"]`.

Instead, they can be accesses via `op.base.wires` or `op.target\_wires`.

[(#3450)](https://github.com/PennyLaneAI/pennylane/pull/3450)

* The tape constructed by a `QNode` is no longer queued to surrounding contexts.

[(#3509)](https://github.com/PennyLaneAI/pennylane/pull/3509)

* Nested operators like `Tensor`, `Hamiltonian`, and `Adjoint` now remove their owned operators

from the queue instead of updating their metadata to have an `"owner"`.

[(#3282)](https://github.com/PennyLaneAI/pennylane/pull/3282)

* `qml.qchem.scf`, `qml.RandomLayers.compute\_decomposition`, and `qml.Wires.select\_random` now use

local random number generators instead of global random number generators. This may lead to slightly

different random numbers and an independence of the results from the global random number generation state.

Please provide a seed to each individual function instead if you want controllable results.

[(#3624)](https://github.com/PennyLaneAI/pennylane/pull/3624)

* `qml.transforms.measurement\_grouping` has been removed. Users should use `qml.transforms.hamiltonian\_expand`

instead.

[(#3701)](https://github.com/PennyLaneAI/pennylane/pull/3701)

* `op.simplify()` for operators which are linear combinations of Pauli words will use a builtin Pauli representation

to more efficiently compute the simplification of the operator.

[(#3481)](https://github.com/PennyLaneAI/pennylane/pull/3481)

* All `Operator`‘s input parameters that are lists are cast into vanilla numpy arrays.

[(#3659)](https://github.com/PennyLaneAI/pennylane/pull/3659)

* `QubitDevice.expval` no longer permutes an observable’s wire order before passing

it to `QubitDevice.probability`. The associated downstream changes for `default.qubit`

have been made, but this may still affect expectations for other devices that inherit

from `QubitDevice` and override `probability` (or any other helper functions that take

a wire order such as `marginal\_prob`, `estimate\_probability` or `analytic\_probability`).

[(#3753)](https://github.com/PennyLaneAI/pennylane/pull/3753)

### Deprecations 👋

* `qml.utils.sparse\_hamiltonian` function has been deprecated, and usage will now raise a warning.

Instead, one should use the `qml.Hamiltonian.sparse\_matrix` method.

[(#3585)](https://github.com/PennyLaneAI/pennylane/pull/3585)

* The `collections` module has been deprecated.

[(#3686)](https://github.com/PennyLaneAI/pennylane/pull/3686)

[(#3687)](https://github.com/PennyLaneAI/pennylane/pull/3687)

* `qml.op\_sum` has been deprecated. Users should use `qml.sum` instead.

[(#3686)](https://github.com/PennyLaneAI/pennylane/pull/3686)

* The use of `Evolution` directly has been deprecated. Users should use `qml.evolve` instead.

This new function changes the sign of the given parameter.

[(#3706)](https://github.com/PennyLaneAI/pennylane/pull/3706)

* Use of `qml.dot` with a `QNodeCollection` has been deprecated.

[(#3586)](https://github.com/PennyLaneAI/pennylane/pull/3586)

### Documentation 📝

* Revise note on GPU support in the [circuit introduction](https://docs.pennylane.ai/en/stable/introduction/circuits.html#defining-a-device).

[(#3836)](https://github.com/PennyLaneAI/pennylane/pull/3836)

* Make warning about vanilla version of NumPy for differentiation more prominent.

[(#3838)](https://github.com/PennyLaneAI/pennylane/pull/3838)

* The documentation for `qml.operation` has been improved.

[(#3664)](https://github.com/PennyLaneAI/pennylane/pull/3664)

* The code example in `qml.SparseHamiltonian` has been updated with the correct wire range.

[(#3643)](https://github.com/PennyLaneAI/pennylane/pull/3643)

* A hyperlink has been added in the text for a URL in the `qml.qchem.mol\_data` docstring.

[(#3644)](https://github.com/PennyLaneAI/pennylane/pull/3644)

* A typo was corrected in the documentation for `qml.math.vn\_entropy`.

[(#3740)](https://github.com/PennyLaneAI/pennylane/pull/3740)

### Bug fixes 🐛

* Fixed a bug where measuring `qml.probs` in the computational basis with non-commuting

measurements returned incorrect results. Now an error is raised.

[(#3811)](https://github.com/PennyLaneAI/pennylane/pull/3811)

* Fixed a bug where measuring `qml.probs` in the computational basis with non-commuting

measurements returned incorrect results. Now an error is raised.

[(#3811)](https://github.com/PennyLaneAI/pennylane/pull/3811)

* Fixed a bug in the drawer where nested controlled operations would output

the label of the operation being controlled, rather than the control values.

[(#3745)](https://github.com/PennyLaneAI/pennylane/pull/3745)

* Fixed a bug in `qml.transforms.metric\_tensor` where prefactors of operation generators were taken

into account multiple times, leading to wrong outputs for non-standard operations.

[(#3579)](https://github.com/PennyLaneAI/pennylane/pull/3579)

* Local random number generators are now used where possible to avoid mutating the global random state.

[(#3624)](https://github.com/PennyLaneAI/pennylane/pull/3624)

* The `networkx` version change being broken has been fixed by selectively skipping a `qcut` TensorFlow-JIT test.

[(#3609)](https://github.com/PennyLaneAI/pennylane/pull/3609)

[(#3619)](https://github.com/PennyLaneAI/pennylane/pull/3619)

* Fixed the wires for the `Y` decomposition in the ZX calculus transform.

[(#3598)](https://github.com/PennyLaneAI/pennylane/pull/3598)

* `qml.pauli.PauliWord` is now pickle-able.

[(#3588)](https://github.com/PennyLaneAI/pennylane/pull/3588)

* Child classes of `QuantumScript` now return their own type when using `SomeChildClass.from\_queue`.

[(#3501)](https://github.com/PennyLaneAI/pennylane/pull/3501)

* A typo has been fixed in the calculation and error messages in `operation.py`

[(#3536)](https://github.com/PennyLaneAI/pennylane/pull/3536)

* `qml.data.Dataset.write()` now ensures that any lazy-loaded values are loaded before they are written to a file.

[(#3605)](https://github.com/PennyLaneAI/pennylane/pull/3605)

* `Tensor.\_batch\_size` is now set to `None` during initialization, copying and `map\_wires`.

[(#3642)](https://github.com/PennyLaneAI/pennylane/pull/3642)

[(#3661)](https://github.com/PennyLaneAI/pennylane/pull/3661)

* `Tensor.has\_matrix` is now set to `True`.

[(#3647)](https://github.com/PennyLaneAI/pennylane/pull/3647)

* Fixed typo in the example of `qml.IsingZZ` gate decomposition.

[(#3676)](https://github.com/PennyLaneAI/pennylane/pull/3676)

* Fixed a bug that made tapes/qnodes using `qml.Snapshot` incompatible with `qml.drawer.tape\_mpl`.

[(#3704)](https://github.com/PennyLaneAI/pennylane/pull/3704)

* `Tensor.\_pauli\_rep` is set to `None` during initialization and `Tensor.data` has been added to its setter.

[(#3722)](https://github.com/PennyLaneAI/pennylane/pull/3722)

* `qml.math.ndim` has been redirected to `jnp.ndim` when using it on a `jax` tensor.

[(#3730)](https://github.com/PennyLaneAI/pennylane/pull/3730)

* Implementations of `marginal\_prob` (and subsequently, `qml.probs`) now return

probabilities with the expected wire order.

[(#3753)](https://github.com/PennyLaneAI/pennylane/pull/3753)

This bug affected most probabilistic measurement processes on devices that

inherit from `QubitDevice` when the measured wires are out of order with

respect to the device wires and 3 or more wires are measured. The assumption

was that marginal probabilities would be computed with the device’s state

and wire order, then re-ordered according to the measurement process wire

order. Instead, the re-ordering went in the inverse direction (that is, from

measurement process wire order to device wire order). This is now fixed. Note

that this only occurred for 3 or more measured wires because this mapping is

identical otherwise. More details and discussion of this bug can be found in

[the original bug report](https://github.com/PennyLaneAI/pennylane/issues/3741).

* Empty iterables can no longer be returned from QNodes.

[(#3769)](https://github.com/PennyLaneAI/pennylane/pull/3769)

* The keyword arguments for `qml.equal` now are used when comparing the observables of a

Measurement Process. The eigvals of measurements are only requested if both observables are `None`,

saving computational effort.

[(#3820)](https://github.com/PennyLaneAI/pennylane/pull/3820)

* Only converts input to `qml.Hermitian` to a numpy array if the input is a list.

[(#3820)](https://github.com/PennyLaneAI/pennylane/pull/3820)

### Contributors ✍

This release contains contributions from (in alphabetical order):

Gian-Luca Anselmetti,

Guillermo Alonso-Linaje,

Juan Miguel Arrazola,

Ikko Ashimine,

Utkarsh Azad,

Miriam Beddig,

Cristian Boghiu,

Thomas Bromley,

Astral Cai,

Isaac De Vlugt,

Olivia Di Matteo,

Lillian M. A. Frederiksen,

Soran Jahangiri,

Korbinian Kottmann,

Christina Lee,

Albert Mitjans Coma,

Romain Moyard,

Mudit Pandey,

Borja Requena,

Matthew Silverman,

Jay Soni,

Antal Száva,

Frederik Wilde,

David Wierichs,

Moritz Willmann.

orphan

#### Release 0.28.0[¶](#release-0-28-0 "Permalink to this headline")

### New features since last release

#### Custom measurement processes 📐

* Custom measurements can now be facilitated with the addition of the `qml.measurements` module.

[(#3286)](https://github.com/PennyLaneAI/pennylane/pull/3286)

[(#3343)](https://github.com/PennyLaneAI/pennylane/pull/3343)

[(#3288)](https://github.com/PennyLaneAI/pennylane/pull/3288)

[(#3312)](https://github.com/PennyLaneAI/pennylane/pull/3312)

[(#3287)](https://github.com/PennyLaneAI/pennylane/pull/3287)

[(#3292)](https://github.com/PennyLaneAI/pennylane/pull/3292)

[(#3287)](https://github.com/PennyLaneAI/pennylane/pull/3287)

[(#3326)](https://github.com/PennyLaneAI/pennylane/pull/3326)

[(#3327)](https://github.com/PennyLaneAI/pennylane/pull/3327)

[(#3388)](https://github.com/PennyLaneAI/pennylane/pull/3388)

[(#3439)](https://github.com/PennyLaneAI/pennylane/pull/3439)

[(#3466)](https://github.com/PennyLaneAI/pennylane/pull/3466)

Within `qml.measurements` are new subclasses that allow for the possibility to create *custom* measurements:

	+ `SampleMeasurement`: represents a sample-based measurement

	+ `StateMeasurement`: represents a state-based measurement

	+ `MeasurementTransform`: represents a measurement process that requires the application of a batch transformCreating a custom measurement involves making a class that inherits from one of the classes above. An example is given below. Here, the measurement computes the number of samples obtained of a given state:

```

from pennylane.measurements import SampleMeasurement

class CountState(SampleMeasurement):

    def \_\_init\_\_(self, state: str):

        self.state = state  # string identifying the state, e.g. "0101"

        wires = list(range(len(state)))

        super().\_\_init\_\_(wires=wires)

    def process\_samples(self, samples, wire\_order, shot\_range, bin\_size):

        counts\_mp = qml.counts(wires=self.\_wires)

        counts = counts\_mp.process\_samples(samples, wire\_order, shot\_range, bin\_size)

        return counts.get(self.state, 0)

    def \_\_copy\_\_(self):

        return CountState(state=self.state)

```

We can now execute the new measurement in a QNode as follows.

```

dev = qml.device("default.qubit", wires=1, shots=10000)

@qml.qnode(dev)

def circuit(x):

    qml.RX(x, wires=0)

    return CountState(state="1")

```

```

>>> circuit(1.23)

tensor(3303., requires\_grad=True)

```

Differentiability is also supported for this new measurement process:

```

>>> x = qml.numpy.array(1.23, requires\_grad=True)

>>> qml.grad(circuit)(x)

4715.000000000001

```

For more information about these new features, see the documentation for ``qml.measurements` <<https://docs.pennylane.ai/en/stable/code/qml_measurements.html>>`\_.

#### ZX Calculus 🧮

* QNodes can now be converted into ZX diagrams via the PyZX framework.

[(#3446)](https://github.com/PennyLaneAI/pennylane/pull/3446)

ZX diagrams are the medium for which we can envision a quantum circuit as a graph in the ZX-calculus language, showing properties of quantum protocols in a visually compact and logically complete fashion.

QNodes decorated with `@qml.transforms.to\_zx` will return a PyZX graph that represents the computation in the ZX-calculus language.

```

dev = qml.device("default.qubit", wires=2)

@qml.transforms.to\_zx

@qml.qnode(device=dev)

def circuit(p):

    qml.RZ(p[0], wires=1),

    qml.RZ(p[1], wires=1),

    qml.RX(p[2], wires=0),

    qml.PauliZ(wires=0),

    qml.RZ(p[3], wires=1),

    qml.PauliX(wires=1),

    qml.CNOT(wires=[0, 1]),

    qml.CNOT(wires=[1, 0]),

    qml.SWAP(wires=[0, 1]),

    return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1))

```

```

>>> params = [5 / 4 \* np.pi, 3 / 4 \* np.pi, 0.1, 0.3]

>>> circuit(params)

Graph(20 vertices, 23 edges)

```

Information about PyZX graphs can be found in the [PyZX Graphs API](https://pyzx.readthedocs.io/en/stable/api.html).

#### QChem databases and basis sets ⚛️

* The symbols and geometry of a compound from the PubChem database can now be accessed via `qchem.mol\_data()`.

[(#3289)](https://github.com/PennyLaneAI/pennylane/pull/3289)

[(#3378)](https://github.com/PennyLaneAI/pennylane/pull/3378)

```

>>> import pennylane as qml

>>> from pennylane.qchem import mol\_data

>>> mol\_data("BeH2")

(['Be', 'H', 'H'],

 tensor([[ 4.79404621, 0.29290755, 0. ],

 [ 3.77945225, -0.29290755, 0. ],

 [ 5.80882913, -0.29290755, 0. ]], requires\_grad=True))

>>> mol\_data(223, "CID")

(['N', 'H', 'H', 'H', 'H'],

 tensor([[ 0. , 0. , 0. ],

 [ 1.82264085, 0.52836742, 0.40402345],

 [ 0.01417295, -1.67429735, -0.98038991],

 [-0.98927163, -0.22714508, 1.65369933],

 [-0.84773114, 1.373075 , -1.07733286]], requires\_grad=True))

```

* Perform quantum chemistry calculations with two new basis sets: `6-311g` and `CC-PVDZ`.

[(#3279)](https://github.com/PennyLaneAI/pennylane/pull/3279)

```

>>> symbols = ["H", "He"]

>>> geometry = np.array([[1.0, 0.0, 0.0], [0.0, 0.0, 0.0]], requires\_grad=False)

>>> charge = 1

>>> basis\_names = ["6-311G", "CC-PVDZ"]

>>> for basis\_name in basis\_names:

...     mol = qml.qchem.Molecule(symbols, geometry, charge=charge, basis\_name=basis\_name)

...     print(qml.qchem.hf\_energy(mol)())

[-2.84429531]

[-2.84061284]

```

#### A bunch of new operators 👀

* The controlled CZ gate and controlled Hadamard gate are now available via `qml.CCZ` and `qml.CH`, respectively.

[(#3408)](https://github.com/PennyLaneAI/pennylane/pull/3408)

```

>>> ccz = qml.CCZ(wires=[0, 1, 2])

>>> qml.matrix(ccz)

[[ 1 0 0 0 0 0 0 0]

 [ 0 1 0 0 0 0 0 0]

 [ 0 0 1 0 0 0 0 0]

 [ 0 0 0 1 0 0 0 0]

 [ 0 0 0 0 1 0 0 0]

 [ 0 0 0 0 0 1 0 0]

 [ 0 0 0 0 0 0 1 0]

 [ 0 0 0 0 0 0 0 -1]]

>>> ch = qml.CH(wires=[0, 1])

>>> qml.matrix(ch)

[[ 1. 0. 0. 0. ]

 [ 0. 1. 0. 0. ]

 [ 0. 0. 0.70710678 0.70710678]

 [ 0. 0. 0.70710678 -0.70710678]]

```

* Three new parametric operators, `qml.CPhaseShift00`, `qml.CPhaseShift01`, and `qml.CPhaseShift10`, are now available. Each of these operators performs a phase shift akin to `qml.ControlledPhaseShift` but on different positions of the state vector.

[(#2715)](https://github.com/PennyLaneAI/pennylane/pull/2715)

```

>>> dev = qml.device("default.qubit", wires=2)

>>> @qml.qnode(dev)

>>> def circuit():

...     qml.PauliX(wires=1)

...     qml.CPhaseShift01(phi=1.23, wires=[0,1])

...     return qml.state()

...

>>> circuit()

tensor([0. +0.j , 0.33423773+0.9424888j,

 1. +0.j , 0. +0.j ], requires\_grad=True)

```

* A new gate operation called `qml.FermionicSWAP` has been added. This implements the exchange of spin orbitals

representing fermionic-modes while maintaining proper anti-symmetrization.

[(#3380)](https://github.com/PennyLaneAI/pennylane/pull/3380)

```

dev = qml.device('default.qubit', wires=2)

@qml.qnode(dev)

def circuit(phi):

    qml.BasisState(np.array([0, 1]), wires=[0, 1])

    qml.FermionicSWAP(phi, wires=[0, 1])

    return qml.state()

```

```

>>> circuit(0.1)

tensor([0. +0.j , 0.99750208+0.04991671j,

 0.00249792-0.04991671j, 0. +0.j ], requires\_grad=True)

```

* Create operators defined from a generator via `qml.ops.op\_math.Evolution`.

[(#3375)](https://github.com/PennyLaneAI/pennylane/pull/3375)

`qml.ops.op\_math.Evolution` defines the exponential of an operator $hat{O}$ of the form $e^{ixhat{O}}$, with a single trainable parameter, $x$. Limiting to a single trainable parameter allows the use of `qml.gradients.param\_shift` to find the gradient with respect to the parameter $x$.

```

dev = qml.device('default.qubit', wires=2)

@qml.qnode(dev, diff\_method=qml.gradients.param\_shift)

def circuit(phi):

    qml.ops.op\_math.Evolution(qml.PauliX(0), -.5 \* phi)

    return qml.expval(qml.PauliZ(0))

```

```

>>> phi = np.array(1.2)

>>> circuit(phi)

tensor(0.36235775, requires\_grad=True)

>>> qml.grad(circuit)(phi)

-0.9320390495504149

```

* The qutrit Hadamard gate, `qml.THadamard`, is now available.

[(#3340)](https://github.com/PennyLaneAI/pennylane/pull/3340)

The operation accepts a `subspace` keyword argument which determines which variant of the qutrit Hadamard to use.

```

>>> th = qml.THadamard(wires=0, subspace=[0, 1])

>>> qml.matrix(th)

array([[ 0.70710678+0.j, 0.70710678+0.j, 0. +0.j],

 [ 0.70710678+0.j, -0.70710678+0.j, 0. +0.j],

 [ 0. +0.j, 0. +0.j, 1. +0.j]])

```

#### New transforms, functions, and more 😯

* Calculating the purity of arbitrary quantum states is now supported.

[(#3290)](https://github.com/PennyLaneAI/pennylane/pull/3290)

The purity can be calculated in an analogous fashion to, say, the Von Neumann entropy:

	+ `qml.math.purity` can be used as an in-line function:

	

	

	

	```

	>>> x = [1, 0, 0, 1] / np.sqrt(2)

	>>> qml.math.purity(x, [0, 1])

	1.0

	>>> qml.math.purity(x, [0])

	0.5

	

	>>> x = [[1 / 2, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 1 / 2]]

	>>> qml.math.purity(x, [0, 1])

	0.5

	

	```

	+ `qml.qinfo.transforms.purity` can transform a QNode returning a state to a

	function that returns the purity:

	

	

	

	```

	dev = qml.device("default.mixed", wires=2)

	

	@qml.qnode(dev)

	def circuit(x):

	    qml.IsingXX(x, wires=[0, 1])

	    return qml.state()

	

	```

	

	

	

	```

	>>> qml.qinfo.transforms.purity(circuit, wires=[0])(np.pi / 2)

	0.5

	>>> qml.qinfo.transforms.purity(circuit, wires=[0, 1])(np.pi / 2)

	1.0

	

	```As with the other methods in `qml.qinfo`, the purity is fully differentiable:

```

>>> param = np.array(np.pi / 4, requires\_grad=True)

>>> qml.grad(qml.qinfo.transforms.purity(circuit, wires=[0]))(param)

-0.5

```

* A new gradient transform, `qml.gradients.spsa\_grad`, that is based on the idea of SPSA is now available.

[(#3366)](https://github.com/PennyLaneAI/pennylane/pull/3366)

This new transform allows users to compute a single estimate of a quantum gradient using simultaneous perturbation of parameters and a stochastic approximation. A QNode that takes, say, an argument `x`, the approximate gradient can be computed as follows.

```

>>> dev = qml.device("default.qubit", wires=2)

>>> x = np.array(0.4, requires\_grad=True)

>>> @qml.qnode(dev)

... def circuit(x):

...     qml.RX(x, 0)

...     qml.RX(x, 1)

...     return qml.expval(qml.PauliZ(0))

>>> grad\_fn = qml.gradients.spsa\_grad(circuit, h=0.1, num\_directions=1)

>>> grad\_fn(x)

array(-0.38876964)

```

The argument `num\_directions` determines how many directions of simultaneous perturbation are used, which is proportional to the number of circuit evaluations. See the [SPSA gradient transform documentation](https://docs.pennylane.ai/en/stable/code/api/pennylane.gradients.spsa_grad.html) for details. Note that the full SPSA optimizer is already available as `qml.SPSAOptimizer`.

* Multiple mid-circuit measurements can now be combined arithmetically to create new conditionals.

[(#3159)](https://github.com/PennyLaneAI/pennylane/pull/3159)

```

dev = qml.device("default.qubit", wires=3)

@qml.qnode(dev)

def circuit():

    qml.Hadamard(wires=0)

    qml.Hadamard(wires=1)

    m0 = qml.measure(wires=0)

    m1 = qml.measure(wires=1)

    combined = 2 \* m1 + m0

    qml.cond(combined == 2, qml.RX)(1.3, wires=2)

    return qml.probs(wires=2)

```

```

>>> circuit()

[0.90843735 0.09156265]

```

* A new method called `pauli\_decompose()` has been added to the `qml.pauli` module, which takes a hermitian matrix, decomposes it in the Pauli basis, and returns it either as a `qml.Hamiltonian` or `qml.PauliSentence` instance.

[(#3384)](https://github.com/PennyLaneAI/pennylane/pull/3384)

* `Operation` or `Hamiltonian` instances can now be generated from a `qml.PauliSentence` or `qml.PauliWord` via the new `operation()` and `hamiltonian()` methods.

[(#3391)](https://github.com/PennyLaneAI/pennylane/pull/3391)

* A `sum\_expand` function has been added for tapes, which splits a tape measuring a `Sum` expectation into mutliple tapes of summand expectations, and provides a function to recombine the results.

[(#3230)](https://github.com/PennyLaneAI/pennylane/pull/3230)

#### (Experimental) More interface support for multi-measurement and gradient output types 🧪

* The autograd and Tensorflow interfaces now support devices with shot vectors when `qml.enable\_return()` has been called.

[(#3374)](https://github.com/PennyLaneAI/pennylane/pull/3374)

[(#3400)](https://github.com/PennyLaneAI/pennylane/pull/3400)

Here is an example using Tensorflow:

```

import tensorflow as tf

qml.enable\_return()

dev = qml.device("default.qubit", wires=2, shots=[1000, 2000, 3000])

@qml.qnode(dev, diff\_method="parameter-shift", interface="tf")

def circuit(a):

    qml.RY(a, wires=0)

    qml.RX(0.2, wires=0)

    qml.CNOT(wires=[0, 1])

    return qml.expval(qml.PauliZ(0)), qml.probs([0, 1])

```

```

>>> a = tf.Variable(0.4)

>>> with tf.GradientTape() as tape:

...     res = circuit(a)

...     res = tf.stack([tf.experimental.numpy.hstack(r) for r in res])

...

>>> res

<tf.Tensor: shape=(3, 5), dtype=float64, numpy=

array([[0.902, 0.951, 0. , 0. , 0.049],

 [0.898, 0.949, 0. , 0. , 0.051],

 [0.892, 0.946, 0. , 0. , 0.054]])>

>>> tape.jacobian(res, a)

<tf.Tensor: shape=(3, 5), dtype=float64, numpy=

array([[-0.345 , -0.1725 , 0. , 0. , 0.1725 ],

 [-0.383 , -0.1915 , 0. , 0. , 0.1915 ],

 [-0.38466667, -0.19233333, 0. , 0. , 0.19233333]])>

```

* The PyTorch interface is now fully supported when `qml.enable\_return()` has been called, allowing the calculation of the Jacobian and the Hessian using custom differentiation methods (e.g., parameter-shift, finite difference, or adjoint).

[(#3416)](https://github.com/PennyLaneAI/pennylane/pull/3414)

```

import torch

qml.enable\_return()

dev = qml.device("default.qubit", wires=2)

@qml.qnode(dev, diff\_method="parameter-shift", interface="torch")

def circuit(a, b):

    qml.RY(a, wires=0)

    qml.RX(b, wires=1)

    qml.CNOT(wires=[0, 1])

    return qml.expval(qml.PauliZ(0)), qml.probs([0, 1])

```

```

>>> a = torch.tensor(0.1, requires\_grad=True)

>>> b = torch.tensor(0.2, requires\_grad=True)

>>> torch.autograd.functional.jacobian(circuit, (a, b))

((tensor(-0.0998), tensor(0.)), (tensor([-0.0494, -0.0005, 0.0005, 0.0494]), tensor([-0.0991, 0.0991, 0.0002, -0.0002])))

```

* The JAX-JIT interface now supports first-order gradient computation when `qml.enable\_return()` has been called.

[(#3235)](https://github.com/PennyLaneAI/pennylane/pull/3235)

[(#3445)](https://github.com/PennyLaneAI/pennylane/pull/3445)

```

import jax

from jax import numpy as jnp

jax.config.update("jax\_enable\_x64", True)

qml.enable\_return()

dev = qml.device("lightning.qubit", wires=2)

@jax.jit

@qml.qnode(dev, interface="jax-jit", diff\_method="parameter-shift")

def circuit(a, b):

    qml.RY(a, wires=0)

    qml.RX(b, wires=0)

    return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliZ(1))

a, b = jnp.array(1.0), jnp.array(2.0)

```

```

>>> jax.jacobian(circuit, argnums=[0, 1])(a, b)

((Array(0.35017549, dtype=float64, weak\_type=True),

Array(-0.4912955, dtype=float64, weak\_type=True)),

(Array(5.55111512e-17, dtype=float64, weak\_type=True),

Array(0., dtype=float64, weak\_type=True)))

```

### Improvements 🛠

* `qml.pauli.is\_pauli\_word` now supports instances of `qml.Hamiltonian`.

[(#3389)](https://github.com/PennyLaneAI/pennylane/pull/3389)

* When `qml.probs`, `qml.counts`, and `qml.sample` are called with no arguments, they measure all

wires. Calling any of the aforementioned measurements with an empty wire list (e.g., `qml.sample(wires=[])`) will raise an error.

[(#3299)](https://github.com/PennyLaneAI/pennylane/pull/3299)

* Made `qml.gradients.finite\_diff` more convenient to use with custom data type observables/devices by reducing the

number of magic methods that need to be defined in the custom data type to support `finite\_diff`.

[(#3426)](https://github.com/PennyLaneAI/pennylane/pull/3426)

* The `qml.ISWAP` gate is now natively supported on `default.mixed`, improving on its efficiency.

[(#3284)](https://github.com/PennyLaneAI/pennylane/pull/3284)

* Added more input validation to `qml.transforms.hamiltonian\_expand` such that Hamiltonian objects with no terms raise an error.

[(#3339)](https://github.com/PennyLaneAI/pennylane/pull/3339)

* Continuous integration checks are now performed for Python 3.11 and Torch v1.13. Python 3.7 is dropped.

[(#3276)](https://github.com/PennyLaneAI/pennylane/pull/3276)

* `qml.Tracker` now also logs results in `tracker.history` when tracking the execution of a circuit.[(#3306)](https://github.com/PennyLaneAI/pennylane/pull/3306)

* The execution time of `Wires.all\_wires` has been improved by avoiding data type changes and making use of `itertools.chain`.

[(#3302)](https://github.com/PennyLaneAI/pennylane/pull/3302)

* Printing an instance of `qml.qchem.Molecule` is now more concise and informational.

[(#3364)](https://github.com/PennyLaneAI/pennylane/pull/3364)

* The error message for `qml.transforms.insert` when it fails to diagonalize non-qubit-wise-commuting observables is now more detailed.

[(#3381)](https://github.com/PennyLaneAI/pennylane/pull/3381)

* Extended the `qml.equal` function to `qml.Hamiltonian` and `Tensor` objects.

[(#3390)](https://github.com/PennyLaneAI/pennylane/pull/3390)

* `QuantumTape.\_process\_queue` has been moved to `qml.queuing.process\_queue` to disentangle its functionality from the `QuantumTape` class.

[(#3401)](https://github.com/PennyLaneAI/pennylane/pull/3401)

* QPE can now accept a target operator instead of a matrix and target wires pair.

[(#3373)](https://github.com/PennyLaneAI/pennylane/pull/3373)

* The `qml.ops.op\_math.Controlled.map\_wires` method now uses `base.map\_wires` internally instead of the private `\_wires` property setter.

[(#3405)](https://github.com/PennyLaneAI/pennylane/pull/3405)

* A new function called `qml.tape.make\_qscript` has been created for converting a quantum function into a quantum script. This replaces `qml.transforms.make\_tape`.

[(#3429)](https://github.com/PennyLaneAI/pennylane/pull/3429)

* Add a `\_pauli\_rep` attribute to operators to integrate the new Pauli arithmetic classes with native PennyLane objects.

[(#3443)](https://github.com/PennyLaneAI/pennylane/pull/3443)

* Extended the functionality of `qml.matrix` to qutrits.

[(#3508)](https://github.com/PennyLaneAI/pennylane/pull/3508)

* The `qcut.py` file in `pennylane/transforms/` has been reorganized into multiple files that are now in `pennylane/transforms/qcut/`.

[(#3413)](https://github.com/PennyLaneAI/pennylane/pull/3413)

* A warning now appears when creating a `Tensor` object with overlapping wires, informing that this can lead to undefined behaviour.

[(#3459)](https://github.com/PennyLaneAI/pennylane/pull/3459)

* Extended the `qml.equal` function to `qml.ops.op\_math.Controlled` and `qml.ops.op\_math.ControlledOp` objects.

[(#3463)](https://github.com/PennyLaneAI/pennylane/pull/3463)

* Nearly every instance of `with QuantumTape()` has been replaced with `QuantumScript` construction.

[(#3454)](https://github.com/PennyLaneAI/pennylane/pull/3454)

* Added `validate\_subspace` static method to `qml.Operator` to check the validity of the subspace of certain

qutrit operations.

[(#3340)](https://github.com/PennyLaneAI/pennylane/pull/3340)

* `qml.equal` now supports operators created via `qml.s\_prod`, `qml.pow`, `qml.exp`, and `qml.adjoint`.

[(#3471)](https://github.com/PennyLaneAI/pennylane/pull/3471)

* Devices can now disregard observable grouping indices in Hamiltonians through the optional `use\_grouping` attribute.

[(#3456)](https://github.com/PennyLaneAI/pennylane/pull/3456)

* Add the optional argument `lazy=True` to functions `qml.s\_prod`, `qml.prod` and `qml.op\_sum` to allow simplification.

[(#3483)](https://github.com/PennyLaneAI/pennylane/pull/3483)

* Updated the `qml.transforms.zyz\_decomposition` function such that it now supports broadcast operators. This means that single-qubit `qml.QubitUnitary` operators, instantiated from a batch of unitaries, can now be decomposed.

[(#3477)](https://github.com/PennyLaneAI/pennylane/pull/3477)

* The performance of executing circuits under the `jax.vmap` transformation has been improved by being able to leverage the batch-execution capabilities of some devices.

[(#3452)](https://github.com/PennyLaneAI/pennylane/pull/3452)

* The tolerance for converting openfermion Hamiltonian complex coefficients to real ones has been modified to prevent conversion errors.

[(#3367)](https://github.com/PennyLaneAI/pennylane/pull/3367)

* `OperationRecorder` now inherits from `AnnotatedQueue` and `QuantumScript` instead of `QuantumTape`.

[(#3496)](https://github.com/PennyLaneAI/pennylane/pull/3496)

* Updated `qml.transforms.split\_non\_commuting` to support the new return types.

[(#3414)](https://github.com/PennyLaneAI/pennylane/pull/3414)

* Updated `qml.transforms.mitigate\_with\_zne` to support the new return types.

[(#3415)](https://github.com/PennyLaneAI/pennylane/pull/3415)

* Updated `qml.transforms.metric\_tensor`, `qml.transforms.adjoint\_metric\_tensor`, `qml.qinfo.classical\_fisher`, and `qml.qinfo.quantum\_fisher` to support the new return types.

[(#3449)](https://github.com/PennyLaneAI/pennylane/pull/3449)

* Updated `qml.transforms.batch\_params` and `qml.transforms.batch\_input` to support the new return types.

[(#3431)](https://github.com/PennyLaneAI/pennylane/pull/3431)

* Updated `qml.transforms.cut\_circuit` and `qml.transforms.cut\_circuit\_mc` to support the new return types.

[(#3346)](https://github.com/PennyLaneAI/pennylane/pull/3346)

* Limit NumPy version to `<1.24`.

[(#3346)](https://github.com/PennyLaneAI/pennylane/pull/3346)

### Breaking changes 💔

* Python 3.7 support is no longer maintained. PennyLane will be maintained for versions 3.8 and up.

[(#3276)](https://github.com/PennyLaneAI/pennylane/pull/3276)

* The `log\_base` attribute has been moved from `MeasurementProcess` to the new `VnEntropyMP` and `MutualInfoMP` classes, which inherit from `MeasurementProcess`.

[(#3326)](https://github.com/PennyLaneAI/pennylane/pull/3326)

* `qml.utils.decompose\_hamiltonian()` has been removed. Please use `qml.pauli.pauli\_decompose()` instead.

[(#3384)](https://github.com/PennyLaneAI/pennylane/pull/3384)

* The `return\_type` attribute of `MeasurementProcess` has been removed where possible. Use `isinstance` checks instead.

[(#3399)](https://github.com/PennyLaneAI/pennylane/pull/3399)

* Instead of having an `OrderedDict` attribute called `\_queue`, `AnnotatedQueue` now inherits from `OrderedDict` and encapsulates the queue. Consequentially, this also applies to the `QuantumTape` class which inherits from `AnnotatedQueue`.

[(#3401)](https://github.com/PennyLaneAI/pennylane/pull/3401)

* The `ShadowMeasurementProcess` class has been renamed to `ClassicalShadowMP`.

[(#3388)](https://github.com/PennyLaneAI/pennylane/pull/3388)

* The `qml.Operation.get\_parameter\_shift` method has been removed. The `gradients` module should be used for general parameter-shift rules instead.

[(#3419)](https://github.com/PennyLaneAI/pennylane/pull/3419)

* The signature of the `QubitDevice.statistics` method has been changed from

```

def statistics(self, observables, shot\_range=None, bin\_size=None, circuit=None):

```

to

```

def statistics(self, circuit: QuantumTape, shot\_range=None, bin\_size=None):

```

[(#3421)](https://github.com/PennyLaneAI/pennylane/pull/3421)

* The `MeasurementProcess` class is now an abstract class and `return\_type` is now a property of the class.

[(#3434)](https://github.com/PennyLaneAI/pennylane/pull/3434)

### Deprecations 👋

Deprecations cycles are tracked at [doc/developement/deprecations.rst](https://docs.pennylane.ai/en/stable/development/deprecations.html).

* The following methods are deprecated:

[(#3281)](https://github.com/PennyLaneAI/pennylane/pull/3281/)

	+ `qml.tape.get\_active\_tape`: Use `qml.QueuingManager.active\_context()` instead

	+ `qml.transforms.qcut.remap\_tape\_wires`: Use `qml.map\_wires` instead

	+ `qml.tape.QuantumTape.inv()`: Use `qml.tape.QuantumTape.adjoint()` instead

	+ `qml.tape.stop\_recording()`: Use `qml.QueuingManager.stop\_recording()` instead

	+ `qml.tape.QuantumTape.stop\_recording()`: Use `qml.QueuingManager.stop\_recording()` instead

	+ `qml.QueuingContext` is now `qml.QueuingManager`

	+ `QueuingManager.safe\_update\_info` and `AnnotatedQueue.safe\_update\_info`: Use `update\_info` instead.

* `qml.transforms.measurement\_grouping` has been deprecated. Use `qml.transforms.hamiltonian\_expand` instead.

[(#3417)](https://github.com/PennyLaneAI/pennylane/pull/3417)

* The `observables` argument in `QubitDevice.statistics` is deprecated. Please use `circuit` instead.

[(#3433)](https://github.com/PennyLaneAI/pennylane/pull/3433)

* The `seed\_recipes` argument in `qml.classical\_shadow` and `qml.shadow\_expval` is deprecated. A new argument `seed` has been added, which defaults to None and can contain an integer with the wanted seed.

[(#3388)](https://github.com/PennyLaneAI/pennylane/pull/3388)

* `qml.transforms.make\_tape` has been deprecated. Please use `qml.tape.make\_qscript` instead.

[(#3478)](https://github.com/PennyLaneAI/pennylane/pull/3478)

### Documentation 📝

* Added documentation on parameter broadcasting regarding both its usage and technical aspects.

[(#3356)](https://github.com/PennyLaneAI/pennylane/pull/3356)

The [quickstart guide on circuits](https://docs.pennylane.ai/en/stable/introduction/circuits.html#parameter-broadcasting-in-qnodes) as well as the the documentation of [QNodes](https://docs.pennylane.ai/en/stable/code/api/pennylane.QNode.html) and [Operators](https://docs.pennylane.ai/en/stable/code/api/pennylane.operation.Operator.html) now contain introductions and details on parameter broadcasting. The QNode documentation mostly contains usage details, the Operator documentation is concerned with implementation details and a guide to support broadcasting in custom operators.

* The return type statements of gradient and Hessian transforms and a series of other functions that are a `batch\_transform` have been corrected.

[(#3476)](https://github.com/PennyLaneAI/pennylane/pull/3476)

* Developer documentation for the queuing module has been added.

[(#3268)](https://github.com/PennyLaneAI/pennylane/pull/3268)

* More mentions of diagonalizing gates for all relevant operations have been corrected.

[(#3409)](https://github.com/PennyLaneAI/pennylane/pull/3409)

The docstrings for `compute\_eigvals` used to say that the diagonalizing gates implemented $U$, the unitary such that $O = U Sigma U^{dagger}$, where $O$ is the original observable and $Sigma$ a diagonal matrix. However, the diagonalizing gates actually implement $U^{dagger}$, since $langle psi | O | psi rangle = langle psi | U Sigma U^{dagger} | psi rangle$, making $U^{dagger} | psi rangle$ the actual state being measured in the $Z$-basis.

* A warning about using `dill` to pickle and unpickle datasets has been added.

[(#3505)](https://github.com/PennyLaneAI/pennylane/pull/3505)

### Bug fixes 🐛

* Fixed a bug that prevented `qml.gradients.param\_shift` from being used for broadcasted tapes.

[(#3528)](https://github.com/PennyLaneAI/pennylane/pull/3528)

* Fixed a bug where `qml.transforms.hamiltonian\_expand` didn’t preserve the type of the input results in its output.

[(#3339)](https://github.com/PennyLaneAI/pennylane/pull/3339)

* Fixed a bug that made `qml.gradients.param\_shift` raise an error when used with unshifted terms only in a custom recipe, and when using any unshifted terms at all under the new return type system.

[(#3177)](https://github.com/PennyLaneAI/pennylane/pull/3177)

* The original tape `\_obs\_sharing\_wires` attribute is updated during its expansion.

[(#3293)](https://github.com/PennyLaneAI/pennylane/pull/3293)

* An issue with `drain=False` in the adaptive optimizer has been fixed. Before the fix, the operator pool needed to be reconstructed inside the optimization pool when `drain=False`. With this fix, this reconstruction is no longer needed.

[(#3361)](https://github.com/PennyLaneAI/pennylane/pull/3361)

* If the device originally has no shots but finite shots are dynamically specified, Hamiltonian expansion now occurs.

[(#3369)](https://github.com/PennyLaneAI/pennylane/pull/3369)

* `qml.matrix(op)` now fails if the operator truly has no matrix (e.g., `qml.Barrier`) to match `op.matrix()`.

[(#3386)](https://github.com/PennyLaneAI/pennylane/pull/3386)

* The `pad\_with` argument in the `qml.AmplitudeEmbedding` template is now compatible with all interfaces.

[(#3392)](https://github.com/PennyLaneAI/pennylane/pull/3392)

* `Operator.pow` now queues its constituents by default.

[(#3373)](https://github.com/PennyLaneAI/pennylane/pull/3373)

* Fixed a bug where a QNode returning `qml.sample` would produce incorrect results when run on a device defined with a shot vector.

[(#3422)](https://github.com/PennyLaneAI/pennylane/pull/3422)

* The `qml.data` module now works as expected on Windows.

[(#3504)](https://github.com/PennyLaneAI/pennylane/pull/3504)

### Contributors ✍️

This release contains contributions from (in alphabetical order):

Guillermo Alonso,

Juan Miguel Arrazola,

Utkarsh Azad,

Samuel Banning,

Thomas Bromley,

Astral Cai,

Albert Mitjans Coma,

Ahmed Darwish,

Isaac De Vlugt,

Olivia Di Matteo,

Amintor Dusko,

Pieter Eendebak,

Lillian M. A. Frederiksen,

Diego Guala,

Katharine Hyatt,

Josh Izaac,

Soran Jahangiri,

Edward Jiang,

Korbinian Kottmann,

Christina Lee,

Romain Moyard,

Lee James O’Riordan,

Mudit Pandey,

Kevin Shen,

Matthew Silverman,

Jay Soni,

Antal Száva,

David Wierichs,

Moritz Willmann, and

Filippo Vicentini.

orphan

#### Release 0.27.0[¶](#release-0-27-0 "Permalink to this headline")

### New features since last release

#### An all-new data module 💾

* The `qml.data` module is now available, allowing users to download, load, and create quantum datasets.

[(#3156)](https://github.com/PennyLaneAI/pennylane/pull/3156)

Datasets are hosted on Xanadu Cloud and can be downloaded by using `qml.data.load()`:

```

>>> H2\_datasets = qml.data.load(

...   data\_name="qchem", molname="H2", basis="STO-3G", bondlength=1.1

... )

>>> H2data = H2\_datasets[0]

>>> H2data

<Dataset = description: qchem/H2/STO-3G/1.1, attributes: ['molecule', 'hamiltonian', ...]>

```

	+ Datasets available to be downloaded can be listed with `qml.data.list\_datasets()`.

	+ To download or load only specific properties of a dataset, we can specify the desired properties in `qml.data.load` with the `attributes` keyword argument:

	

	

	

	```

	>>> H2\_hamiltonian = qml.data.load(

	... data\_name="qchem", molname="H2", basis="STO-3G", bondlength=1.1,

	... attributes=["molecule", "hamiltonian"]

	... )[0]

	>>> H2\_hamiltonian.hamiltonian

	<Hamiltonian: terms=15, wires=[0, 1, 2, 3]>

	

	```

	

	

	The available attributes can be found using `qml.data.list\_attributes()`:

	+ To select data interactively, we can use `qml.data.load\_interactive()`:

	

	

	

	```

	>>> qml.data.load\_interactive()

	Please select a data name:

	 1) qspin

	 2) qchem

	Choice [1-2]: 1

	Please select a sysname:

	 ...

	Please select a periodicity:

	 ...

	Please select a lattice:

	 ...

	Please select a layout:

	 ...

	Please select attributes:

	 ...

	Force download files? (Default is no) [y/N]: N

	Folder to download to? (Default is pwd, will download to /datasets subdirectory):

	

	Please confirm your choices:

	dataset: qspin/Ising/open/rectangular/4x4

	attributes: ['parameters', 'ground\_states']

	force: False

	dest folder: datasets

	Would you like to continue? (Default is yes) [Y/n]:

	<Dataset = description: qspin/Ising/open/rectangular/4x4, attributes: ['parameters', 'ground\_states']>

	

	```

	+ Once a dataset is loaded, its properties can be accessed as follows:

	

	

	

	```

	>>> dev = qml.device("default.qubit",wires=4)

	>>> @qml.qnode(dev)

	... def circuit():

	...     qml.BasisState(H2data.hf\_state, wires = [0, 1, 2, 3])

	...     for op in H2data.vqe\_gates:

	...          qml.apply(op)

	...     return qml.expval(H2data.hamiltonian)

	>>> print(circuit())

	-1.0791430411076344

	

	```It’s also possible to create custom datasets with `qml.data.Dataset`:

```

>>> example\_hamiltonian = qml.Hamiltonian(coeffs=[1,0.5], observables=[qml.PauliZ(wires=0),qml.PauliX(wires=1)])

>>> example\_energies, \_ = np.linalg.eigh(qml.matrix(example\_hamiltonian))

>>> example\_dataset = qml.data.Dataset(

... data\_name = 'Example', hamiltonian=example\_hamiltonian, energies=example\_energies

... )

>>> example\_dataset.data\_name

'Example'

>>> example\_dataset.hamiltonian

 (0.5) [X1]

+ (1) [Z0]

>>> example\_dataset.energies

array([-1.5, -0.5, 0.5, 1.5])

```

Custom datasets can be saved and read with the `qml.data.Dataset.write()` and `qml.data.Dataset.read()` methods, respectively.

```

>>> example\_dataset.write('./path/to/dataset.dat')

>>> read\_dataset = qml.data.Dataset()

>>> read\_dataset.read('./path/to/dataset.dat')

>>> read\_dataset.data\_name

'Example'

>>> read\_dataset.hamiltonian

 (0.5) [X1]

+ (1) [Z0]

>>> read\_dataset.energies

array([-1.5, -0.5, 0.5, 1.5])

```

We will continue to work on adding more datasets and features for `qml.data` in future releases.

#### Adaptive optimization 🏃🏋️🏊

* Optimizing quantum circuits can now be done *adaptively* with

`qml.AdaptiveOptimizer`.

[(#3192)](https://github.com/PennyLaneAI/pennylane/pull/3192)

The `qml.AdaptiveOptimizer` takes an initial circuit and a collection of operators as input and adds a selected gate to the circuit at each optimization step. The process of growing the circuit can be repeated until the circuit gradients converge to zero within a given threshold. The adaptive optimizer can be used to implement algorithms such as ADAPT-VQE as shown in the following example.

Firstly, we define some preliminary variables needed for VQE:

```

symbols = ["H", "H", "H"]

geometry = np.array([[0.01076341, 0.04449877, 0.0],

                    [0.98729513, 1.63059094, 0.0],

                    [1.87262415, -0.00815842, 0.0]], requires\_grad=False)

H, qubits = qml.qchem.molecular\_hamiltonian(symbols, geometry, charge = 1)

```

The collection of gates to grow the circuit is built to contain all single and double excitations:

```

n\_electrons = 2

singles, doubles = qml.qchem.excitations(n\_electrons, qubits)

singles\_excitations = [qml.SingleExcitation(0.0, x) for x in singles]

doubles\_excitations = [qml.DoubleExcitation(0.0, x) for x in doubles]

operator\_pool = doubles\_excitations + singles\_excitations

```

Next, an initial circuit that prepares a Hartree-Fock state and returns the expectation value of the Hamiltonian is defined:

```

hf\_state = qml.qchem.hf\_state(n\_electrons, qubits)

dev = qml.device("default.qubit", wires=qubits)

@qml.qnode(dev)

def circuit():

    qml.BasisState(hf\_state, wires=range(qubits))

    return qml.expval(H)

```

Finally, the optimizer is instantiated and then the circuit is created and optimized adaptively:

```

opt = qml.optimize.AdaptiveOptimizer()

for i in range(len(operator\_pool)):

    circuit, energy, gradient = opt.step\_and\_cost(circuit, operator\_pool, drain\_pool=True)

    print('Energy:', energy)

    print(qml.draw(circuit)())

    print('Largest Gradient:', gradient)

    print()

    if gradient < 1e-3:

        break

```

```

Energy: -1.246549938420637

0: ─╭BasisState(M0)─╭G²(0.20)─┤ ╭<𝓗>

1: ─├BasisState(M0)─├G²(0.20)─┤ ├<𝓗>

2: ─├BasisState(M0)─│─────────┤ ├<𝓗>

3: ─├BasisState(M0)─│─────────┤ ├<𝓗>

4: ─├BasisState(M0)─├G²(0.20)─┤ ├<𝓗>

5: ─╰BasisState(M0)─╰G²(0.20)─┤ ╰<𝓗>

Largest Gradient: 0.14399872776755085

Energy: -1.2613740231529604

0: ─╭BasisState(M0)─╭G²(0.20)─╭G²(0.19)─┤ ╭<𝓗>

1: ─├BasisState(M0)─├G²(0.20)─├G²(0.19)─┤ ├<𝓗>

2: ─├BasisState(M0)─│─────────├G²(0.19)─┤ ├<𝓗>

3: ─├BasisState(M0)─│─────────╰G²(0.19)─┤ ├<𝓗>

4: ─├BasisState(M0)─├G²(0.20)───────────┤ ├<𝓗>

5: ─╰BasisState(M0)─╰G²(0.20)───────────┤ ╰<𝓗>

Largest Gradient: 0.1349349562423238

Energy: -1.2743971719780331

0: ─╭BasisState(M0)─╭G²(0.20)─╭G²(0.19)──────────┤ ╭<𝓗>

1: ─├BasisState(M0)─├G²(0.20)─├G²(0.19)─╭G(0.00)─┤ ├<𝓗>

2: ─├BasisState(M0)─│─────────├G²(0.19)─│────────┤ ├<𝓗>

3: ─├BasisState(M0)─│─────────╰G²(0.19)─╰G(0.00)─┤ ├<𝓗>

4: ─├BasisState(M0)─├G²(0.20)────────────────────┤ ├<𝓗>

5: ─╰BasisState(M0)─╰G²(0.20)────────────────────┤ ╰<𝓗>

Largest Gradient: 0.00040841755397108586

```

For a detailed breakdown of its implementation, check out the [Adaptive circuits for quantum chemistry

demo](https://pennylane.ai/qml/demos/tutorial_adaptive_circuits.html).

#### Automatic interface detection 🧩

* QNodes now accept an `auto` interface argument which automatically detects the machine learning library to use.

[(#3132)](https://github.com/PennyLaneAI/pennylane/pull/3132)

```

from pennylane import numpy as np

import torch

import tensorflow as tf

from jax import numpy as jnp

dev = qml.device("default.qubit", wires=2)

@qml.qnode(dev, interface="auto")

def circuit(weight):

    qml.RX(weight[0], wires=0)

    qml.RY(weight[1], wires=1)

    return qml.expval(qml.PauliZ(0))

interface\_tensors = [[0, 1], np.array([0, 1]), torch.Tensor([0, 1]), tf.Variable([0, 1], dtype=float), jnp.array([0, 1])]

for tensor in interface\_tensors:

    res = circuit(weight=tensor)

    print(f"Result value: {res:.2f}; Result type: {type(res)}")

```

```

Result value: 1.00; Result type: <class 'pennylane.numpy.tensor.tensor'>

Result value: 1.00; Result type: <class 'pennylane.numpy.tensor.tensor'>

Result value: 1.00; Result type: <class 'torch.Tensor'>

Result value: 1.00; Result type: <class 'tensorflow.python.framework.ops.EagerTensor'>

Result value: 1.00; Result type: <class 'jaxlib.xla\_extension.Array'>

```

#### Upgraded JAX-JIT gradient support 🏎

* JAX-JIT support for computing the gradient of QNodes that return a single vector of probabilities or multiple expectation values is now available.

[(#3244)](https://github.com/PennyLaneAI/pennylane/pull/3244)

[(#3261)](https://github.com/PennyLaneAI/pennylane/pull/3261)

```

import jax

from jax import numpy as jnp

from jax.config import config

config.update("jax\_enable\_x64", True)

dev = qml.device("lightning.qubit", wires=2)

@jax.jit

@qml.qnode(dev, diff\_method="parameter-shift", interface="jax")

def circuit(x, y):

    qml.RY(x, wires=0)

    qml.RY(y, wires=1)

    qml.CNOT(wires=[0, 1])

    return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliZ(1))

x = jnp.array(1.0)

y = jnp.array(2.0)

```

```

>>> jax.jacobian(circuit, argnums=[0, 1])(x, y)

(Array([-0.84147098, 0.35017549], dtype=float64, weak\_type=True),

 Array([ 4.47445479e-18, -4.91295496e-01], dtype=float64, weak\_type=True))

```

Note that this change depends on `jax.pure\_callback`, which requires `jax>=0.3.17`.

#### Construct Pauli words and sentences 🔤

* We’ve reorganized and grouped everything in PennyLane responsible for manipulating Pauli operators into a `pauli` module. The `grouping` module has been deprecated as a result, and logic was moved from `pennylane/grouping` to `pennylane/pauli/grouping`.

[(#3179)](https://github.com/PennyLaneAI/pennylane/pull/3179)

* `qml.pauli.PauliWord` and `qml.pauli.PauliSentence` can be used to represent tensor products and linear combinations of Pauli operators, respectively. These provide a more performant method to compute sums and products of Pauli operators.

[(#3195)](https://github.com/PennyLaneAI/pennylane/pull/3195)

	+ `qml.pauli.PauliWord` represents tensor products of Pauli operators. We can efficiently multiply and extract the matrix of these operators using this representation.

	

	

	

	```

	>>> pw1 = qml.pauli.PauliWord({0:"X", 1:"Z"})

	>>> pw2 = qml.pauli.PauliWord({0:"Y", 1:"Z"})

	>>> pw1, pw2

	(X(0) @ Z(1), Y(0) @ Z(1))

	>>> pw1 \* pw2

	(Z(0), 1j)

	>>> pw1.to\_mat(wire\_order=[0,1])

	array([[ 0, 0, 1, 0],

	 [ 0, 0, 0, -1],

	 [ 1, 0, 0, 0],

	 [ 0, -1, 0, 0]])

	

	```

	+ `qml.pauli.PauliSentence` represents linear combinations of Pauli words. We can efficiently add, multiply and extract the matrix of these operators in this representation.

	

	

	

	```

	>>> ps1 = qml.pauli.PauliSentence({pw1: 1.2, pw2: 0.5j})

	>>> ps2 = qml.pauli.PauliSentence({pw1: -1.2})

	>>> ps1

	1.2 \* X(0) @ Z(1)

	+ 0.5j \* Y(0) @ Z(1)

	>>> ps1 + ps2

	0.0 \* X(0) @ Z(1)

	+ 0.5j \* Y(0) @ Z(1)

	>>> ps1 \* ps2

	-1.44 \* I

	+ (-0.6+0j) \* Z(0)

	>>> (ps1 + ps2).to\_mat(wire\_order=[0,1])

	array([[ 0. +0.j, 0. +0.j, 0.5+0.j, 0. +0.j],

	 [ 0. +0.j, 0. +0.j, 0. +0.j, -0.5+0.j],

	 [-0.5+0.j, 0. +0.j, 0. +0.j, 0. +0.j],

	 [ 0. +0.j, 0.5+0.j, 0. +0.j, 0. +0.j]])

	

	```

#### (Experimental) More support for multi-measurement and gradient output types 🧪

* `qml.enable\_return()` now supports QNodes returning multiple measurements,

including shots vectors, and gradient output types.

[(#2886)](https://github.com/PennyLaneAI/pennylane/pull/2886)

[(#3052)](https://github.com/PennyLaneAI/pennylane/pull/3052)

[(#3041)](https://github.com/PennyLaneAI/pennylane/pull/3041)

[(#3090)](https://github.com/PennyLaneAI/pennylane/pull/3090)

[(#3069)](https://github.com/PennyLaneAI/pennylane/pull/3069)

[(#3137)](https://github.com/PennyLaneAI/pennylane/pull/3137)

[(#3127)](https://github.com/PennyLaneAI/pennylane/pull/3127)

[(#3099)](https://github.com/PennyLaneAI/pennylane/pull/3099)

[(#3098)](https://github.com/PennyLaneAI/pennylane/pull/3098)

[(#3095)](https://github.com/PennyLaneAI/pennylane/pull/3095)

[(#3091)](https://github.com/PennyLaneAI/pennylane/pull/3091)

[(#3176)](https://github.com/PennyLaneAI/pennylane/pull/3176)

[(#3170)](https://github.com/PennyLaneAI/pennylane/pull/3170)

[(#3194)](https://github.com/PennyLaneAI/pennylane/pull/3194)

[(#3267)](https://github.com/PennyLaneAI/pennylane/pull/3267)

[(#3234)](https://github.com/PennyLaneAI/pennylane/pull/3234)

[(#3232)](https://github.com/PennyLaneAI/pennylane/pull/3232)

[(#3223)](https://github.com/PennyLaneAI/pennylane/pull/3223)

[(#3222)](https://github.com/PennyLaneAI/pennylane/pull/3222)

[(#3315)](https://github.com/PennyLaneAI/pennylane/pull/3315)

In v0.25, we introduced `qml.enable\_return()`, which separates measurements into their own tensors. The motivation of this change is the deprecation of ragged `ndarray` creation in NumPy.

With this release, we’re continuing to elevate this feature by adding support for:

	+ Execution (`qml.execute`)

	+ Jacobian vector product (JVP) computation

	+ Gradient transforms (`qml.gradients.param\_shift`, `qml.gradients.finite\_diff`, `qml.gradients.hessian\_transform`, `qml.gradients.param\_shift\_hessian`).

	+ Interfaces (Autograd, TensorFlow, and JAX, although without JIT)With this added support, the JAX interface can handle multiple shots (shots vectors), measurements, and gradient output types with `qml.enable\_return()`:

```

import jax

qml.enable\_return()

dev = qml.device("default.qubit", wires=2, shots=(1, 10000))

params = jax.numpy.array([0.1, 0.2])

@qml.qnode(dev, interface="jax", diff\_method="parameter-shift", max\_diff=2)

def circuit(x):

    qml.RX(x[0], wires=[0])

    qml.RY(x[1], wires=[1])

    qml.CNOT(wires=[0, 1])

    return qml.var(qml.PauliZ(0) @ qml.PauliX(1)), qml.probs(wires=[0])

```

```

>>> jax.hessian(circuit)(params)

((Array([[ 0., 0.],

 [ 2., -3.]], dtype=float32),

Array([[[-0.5, 0. ],

 [ 0. , 0. ]],

 [[ 0.5, 0. ],

 [ 0. , 0. ]]], dtype=float32)),

(Array([[ 0.07677898, 0.0563341 ],

 [ 0.07238522, -1.830669 ]], dtype=float32),

Array([[[-4.9707499e-01, 2.9999996e-04],

 [-6.2500127e-04, 1.2500001e-04]],

 [[ 4.9707499e-01, -2.9999996e-04],

 [ 6.2500127e-04, -1.2500001e-04]]], dtype=float32)))

```

For more details, please [refer to the documentation](https://docs.pennylane.ai/en/stable/code/api/pennylane.enable_return.html?highlight=enable_return#pennylane.enable_return).

#### New basis rotation and tapering features in qml.qchem 🤓

* Grouped coefficients, observables, and basis rotation transformation matrices needed to construct a qubit Hamiltonian in the rotated basis of molecular orbitals are now calculable via `qml.qchem.basis\_rotation()`.

([#3011](https://github.com/PennyLaneAI/pennylane/pull/3011))

```

>>> symbols  = ['H', 'H']

>>> geometry = np.array([[0.0, 0.0, 0.0], [1.398397361, 0.0, 0.0]], requires\_grad = False)

>>> mol = qml.qchem.Molecule(symbols, geometry)

>>> core, one, two = qml.qchem.electron\_integrals(mol)()

>>> coeffs, ops, unitaries = qml.qchem.basis\_rotation(one, two, tol\_factor=1.0e-5)

>>> unitaries

[tensor([[-1.00000000e+00, -5.46483514e-13],

 [ 5.46483514e-13, -1.00000000e+00]], requires\_grad=True),

tensor([[-1.00000000e+00, 3.17585063e-14],

 [-3.17585063e-14, -1.00000000e+00]], requires\_grad=True),

tensor([[-0.70710678, -0.70710678],

 [-0.70710678, 0.70710678]], requires\_grad=True),

tensor([[ 2.58789009e-11, 1.00000000e+00],

 [-1.00000000e+00, 2.58789009e-11]], requires\_grad=True)]

```

* Any gate operation can now be tapered according to \(\mathbb{Z}\_2\) symmetries of the Hamiltonian via `qml.qchem.taper\_operation`.

[(#3002)](https://github.com/PennyLaneAI/pennylane/pull/3002)

[(#3121)](https://github.com/PennyLaneAI/pennylane/pull/3121)

```

>>> symbols = ['He', 'H']

>>> geometry =  np.array([[0.0, 0.0, 0.0], [0.0, 0.0, 1.4589]])

>>> mol = qml.qchem.Molecule(symbols, geometry, charge=1)

>>> H, n\_qubits = qml.qchem.molecular\_hamiltonian(symbols, geometry)

>>> generators = qml.qchem.symmetry\_generators(H)

>>> paulixops = qml.qchem.paulix\_ops(generators, n\_qubits)

>>> paulix\_sector = qml.qchem.optimal\_sector(H, generators, mol.n\_electrons)

>>> tap\_op = qml.qchem.taper\_operation(qml.SingleExcitation, generators, paulixops,

...                paulix\_sector, wire\_order=H.wires, op\_wires=[0, 2])

>>> tap\_op(3.14159)

[Exp(1.5707949999999993j PauliY)]

```

Moreover, the obtained tapered operation can be used directly within a QNode.

```

>>> dev = qml.device('default.qubit', wires=[0, 1])

>>> @qml.qnode(dev)

... def circuit(params):

...     tap\_op(params[0])

...     return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1))

>>> drawer = qml.draw(circuit, show\_all\_wires=True)

>>> print(drawer(params=[3.14159]))

0: ──Exp(0.00+1.57j Y)─┤ ╭<Z@Z>

1: ────────────────────┤ ╰<Z@Z>

```

* Functionality has been added to estimate the number of measurements required to compute an expectation value with a target error and estimate the error in computing an expectation value with a given number of measurements.

[(#3000)](https://github.com/PennyLaneAI/pennylane/pull/3000)

#### New functions, operations, and observables 🤩

* Wires of operators or entire QNodes can now be mapped to other wires via `qml.map\_wires()`.

[(#3143)](https://github.com/PennyLaneAI/pennylane/pull/3143)

[(#3145)](https://github.com/PennyLaneAI/pennylane/pull/3145)

The `qml.map\_wires()` function requires a dictionary representing a wire map. Use it with

	+ arbitrary operators:

	

	

	

	```

	>>> op = qml.RX(0.54, wires=0) + qml.PauliX(1) + (qml.PauliZ(2) @ qml.RY(1.23, wires=3))

	>>> op

	(RX(0.54, wires=[0]) + PauliX(wires=[1])) + (PauliZ(wires=[2]) @ RY(1.23, wires=[3]))

	>>> wire\_map = {0: 10, 1: 11, 2: 12, 3: 13}

	>>> qml.map\_wires(op, wire\_map)

	(RX(0.54, wires=[10]) + PauliX(wires=[11])) + (PauliZ(wires=[12]) @ RY(1.23, wires=[13]))

	

	```

	

	

	A `map\_wires` method has also been added to operators, which returns a copy

	of the operator with its wires changed according to the given wire map.

	+ entire QNodes:

	

	

	

	```

	dev = qml.device("default.qubit", wires=["A", "B", "C", "D"])

	wire\_map = {0: "A", 1: "B", 2: "C", 3: "D"}

	

	@qml.qnode(dev)

	def circuit():

	    qml.RX(0.54, wires=0)

	    qml.PauliX(1)

	    qml.PauliZ(2)

	    qml.RY(1.23, wires=3)

	    return qml.probs(wires=0)

	

	```

	

	

	

	```

	>>> mapped\_circuit = qml.map\_wires(circuit, wire\_map)

	>>> mapped\_circuit()

	tensor([0.92885434, 0.07114566], requires\_grad=True)

	>>> print(qml.draw(mapped\_circuit)())

	A: ──RX(0.54)─┤ Probs

	B: ──X────────┤

	C: ──Z────────┤

	D: ──RY(1.23)─┤

	

	```

* The `qml.IntegerComparator` arithmetic operation is now available.

[(#3113)](https://github.com/PennyLaneAI/pennylane/pull/3113)

Given a basis state \(\vert n \rangle\), where \(n\) is a positive integer, and a fixed positive integer \(L\), `qml.IntegerComparator` flips a target qubit if \(n \geq L\). Alternatively, the flipping condition can be \(n < L\) as demonstrated below:

```

dev = qml.device("default.qubit", wires=2)

@qml.qnode(dev)

def circuit():

    qml.BasisState(np.array([0, 1]), wires=range(2))

    qml.broadcast(qml.Hadamard, wires=range(2), pattern='single')

    qml.IntegerComparator(2, geq=False, wires=[0, 1])

    return qml.state()

```

```

>>> circuit()

[-0.5+0.j 0.5+0.j -0.5+0.j 0.5+0.j]

```

* The `qml.GellMann` qutrit observable, the ternary generalization of the Pauli observables, is now available.

[(#3035)](https://github.com/PennyLaneAI/pennylane/pull/3035)

When using `qml.GellMann`, the `index` keyword argument determines which of the 8 Gell-Mann matrices is used.

```

dev = qml.device("default.qutrit", wires=2)

@qml.qnode(dev)

def circuit():

    qml.TClock(wires=0)

    qml.TShift(wires=1)

    qml.TAdd(wires=[0, 1])

    return qml.expval(qml.GellMann(wires=0, index=8) + qml.GellMann(wires=1, index=3))

```

```

>>> circuit()

-0.42264973081037416

```

* Controlled qutrit operations can now be performed with `qml.ControlledQutritUnitary`.

([#2844](https://github.com/PennyLaneAI/pennylane/pull/2844))

The control wires and values that define the operation are defined analogously to the qubit operation.

```

dev = qml.device("default.qutrit", wires=3)

@qml.qnode(dev)

def circuit(U):

    qml.TShift(wires=0)

    qml.TAdd(wires=[0, 1])

    qml.ControlledQutritUnitary(U, control\_wires=[0, 1], control\_values='12', wires=2)

    return qml.state()

```

```

>>> U = np.array([[1, 1, 0], [1, -1, 0], [0, 0, np.sqrt(2)]]) / np.sqrt(2)

>>> circuit(U)

tensor([0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j,

 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j,

 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j,

 0.+0.j, 0.+0.j, 0.+0.j], requires\_grad=True)

```

### Improvements

* PennyLane now supports Python 3.11!

[(#3297)](https://github.com/PennyLaneAI/pennylane/pull/3297)

* `qml.sample` and `qml.counts` work more efficiently and track if computational basis samples are being generated when they are called without specifying an observable.

[(#3207)](https://github.com/PennyLaneAI/pennylane/pull/3207)

* The parameters of a basis set containing a different number of Gaussian functions are now easier to differentiate.

[(#3213)](https://github.com/PennyLaneAI/pennylane/pull/3213)

* Printing a `qml.MultiControlledX` operator now shows the `control\_values` keyword argument.

[(#3113)](https://github.com/PennyLaneAI/pennylane/pull/3113)

* `qml.simplify` and transforms like `qml.matrix`, `batch\_transform`, `hamiltonian\_expand`, and `split\_non\_commuting` now work with

`QuantumScript` as well as `QuantumTape`.

[(#3209)](https://github.com/PennyLaneAI/pennylane/pull/3209)

* A redundant flipping of the initial state in the UCCSD and kUpCCGSD templates has been removed.

[(#3148)](https://github.com/PennyLaneAI/pennylane/pull/3148)

* `qml.adjoint` now supports batching if the base operation supports batching.

[(#3168)](https://github.com/PennyLaneAI/pennylane/pull/3168)

* `qml.OrbitalRotation` is now decomposed into two `qml.SingleExcitation` operations for faster execution and more efficient parameter-shift gradient calculations on devices that natively support `qml.SingleExcitation`.

[(#3171)](https://github.com/PennyLaneAI/pennylane/pull/3171)

* The `Exp` class decomposes into a `PauliRot` class if the coefficient is imaginary and the base operator is a Pauli Word.

[(#3249)](https://github.com/PennyLaneAI/pennylane/pull/3249)

* Added the operator attributes `has\_decomposition` and `has\_adjoint` that indicate

whether a corresponding `decomposition` or `adjoint` method is available.

[(#2986)](https://github.com/PennyLaneAI/pennylane/pull/2986)

* Structural improvements are made to `QueuingManager`, formerly `QueuingContext`, and `AnnotatedQueue`.

[(#2794)](https://github.com/PennyLaneAI/pennylane/pull/2794)

[(#3061)](https://github.com/PennyLaneAI/pennylane/pull/3061)

[(#3085)](https://github.com/PennyLaneAI/pennylane/pull/3085)

	+ `QueuingContext` is renamed to `QueuingManager`.

	+ `QueuingManager` should now be the global communication point for putting queuable objects into the active queue.

	+ `QueuingManager` is no longer an abstract base class.

	+ `AnnotatedQueue` and its children no longer inherit from `QueuingManager`.

	+ `QueuingManager` is no longer a context manager.

	+ Recording queues should start and stop recording via the `QueuingManager.add\_active\_queue` and

	`QueuingContext.remove\_active\_queue` class methods instead of directly manipulating the `\_active\_contexts` property.

	+ `AnnotatedQueue` and its children no longer provide global information about actively recording queues. This information is now only available through `QueuingManager`.

	+ `AnnotatedQueue` and its children no longer have the private `\_append`, `\_remove`, `\_update\_info`, `\_safe\_update\_info`, and `\_get\_info` methods. The public analogues should be used instead.

	+ `QueuingManager.safe\_update\_info` and `AnnotatedQueue.safe\_update\_info` are deprecated. Their functionality is moved to `update\_info`.

* `qml.Identity` now accepts multiple wires.[(#3049)](https://github.com/PennyLaneAI/pennylane/pull/3049)

```

>>> id\_op = qml.Identity([0, 1])

>>> id\_op.matrix()

array([[1., 0., 0., 0.],

 [0., 1., 0., 0.],

 [0., 0., 1., 0.],

 [0., 0., 0., 1.]])

>>> id\_op.sparse\_matrix()

<4x4 sparse matrix of type '<class 'numpy.float64'>'

 with 4 stored elements in Compressed Sparse Row format>

>>> id\_op.eigvals()

array([1., 1., 1., 1.])

```

* Added `unitary\_check` keyword argument to the constructor of the `QubitUnitary` class which

indicates whether the user wants to check for unitarity of the input matrix or not. Its default

value is `false`.

[(#3063)](https://github.com/PennyLaneAI/pennylane/pull/3063)

* Modified the representation of `WireCut` by using `qml.draw\_mpl`.

[(#3067)](https://github.com/PennyLaneAI/pennylane/pull/3067)

* Improved the performance of `qml.math.expand\_matrix` function for dense

and sparse matrices.

[(#3060)](https://github.com/PennyLaneAI/pennylane/pull/3060)

[(#3064)](https://github.com/PennyLaneAI/pennylane/pull/3064)

* Added support for sums and products of operator classes with scalar tensors of any interface

(NumPy, JAX, Tensorflow, PyTorch…).

[(#3149)](https://github.com/PennyLaneAI/pennylane/pull/3149)

```

>>> s\_prod = torch.tensor(4) \* qml.RX(1.23, 0)

>>> s\_prod

4\*(RX(1.23, wires=[0]))

>>> s\_prod.scalar

tensor(4)

```

* Added `overlapping\_ops` property to the `Composite` class to improve the

performance of the `eigvals`, `diagonalizing\_gates` and `Prod.matrix` methods.

[(#3084)](https://github.com/PennyLaneAI/pennylane/pull/3084)

* Added the `map\_wires` method to the operators, which returns a copy of the operator with

its wires changed according to the given wire map.

[(#3143)](https://github.com/PennyLaneAI/pennylane/pull/3143)

```

>>> op = qml.Toffoli([0, 1, 2])

>>> wire\_map = {0: 2, 2: 0}

>>> op.map\_wires(wire\_map=wire\_map)

Toffoli(wires=[2, 1, 0])

```

* Calling `compute\_matrix` and `compute\_sparse\_matrix` of simple non-parametric operations is now faster and more memory-efficient with the addition of caching.

[(#3134)](https://github.com/PennyLaneAI/pennylane/pull/3134)

* Added details to the output of `Exp.label()`.

[(#3126)](https://github.com/PennyLaneAI/pennylane/pull/3126)

* `qml.math.unwrap` no longer creates ragged arrays. Lists remain lists.

[(#3163)](https://github.com/PennyLaneAI/pennylane/pull/3163)

* New `null.qubit` device. The `null.qubit` performs no operations or memory allocations.

[(#2589)](https://github.com/PennyLaneAI/pennylane/pull/2589)

* `default.qubit` favours decomposition and avoids matrix construction for `QFT` and `GroverOperator` at larger qubit numbers.

[(#3193)](https://github.com/PennyLaneAI/pennylane/pull/3193)

* `qml.ControlledQubitUnitary` now has a `control\_values` property.

[(#3206)](https://github.com/PennyLaneAI/pennylane/pull/3206)

* Added a new `qml.tape.QuantumScript` class that contains all the non-queuing behavior of `QuantumTape`. Now, `QuantumTape` inherits from `QuantumScript` as well as `AnnotatedQueue`.

[(#3097)](https://github.com/PennyLaneAI/pennylane/pull/3097)

* Extended the `qml.equal` function to MeasurementProcesses

[(#3189)](https://github.com/PennyLaneAI/pennylane/pull/3189)

* `qml.drawer.draw.draw\_mpl` now accepts a `style` kwarg to select a style for plotting, rather than calling

`qml.drawer.use\_style(style)` before plotting. Setting a style for `draw\_mpl` does not change the global

configuration for matplotlib plotting. If no `style` is passed, the function defaults

to plotting with the `black\_white` style.

[(#3247)](https://github.com/PennyLaneAI/pennylane/pull/3247)

### Breaking changes

* `QuantumTape.\_par\_info` is now a list of dictionaries, instead of a dictionary whose keys are integers starting from zero.

[(#3185)](https://github.com/PennyLaneAI/pennylane/pull/3185)

* `QueuingContext` has been renamed to `QueuingManager`.

[(#3061)](https://github.com/PennyLaneAI/pennylane/pull/3061)

* Deprecation patches for the return types enum’s location and `qml.utils.expand` are removed.

[(#3092)](https://github.com/PennyLaneAI/pennylane/pull/3092)

* `\_multi\_dispatch` functionality has been moved inside the `get\_interface` function. This function

can now be called with one or multiple tensors as arguments.

[(#3136)](https://github.com/PennyLaneAI/pennylane/pull/3136)

```

>>> torch\_scalar = torch.tensor(1)

>>> torch\_tensor = torch.Tensor([2, 3, 4])

>>> numpy\_tensor = np.array([5, 6, 7])

>>> qml.math.get\_interface(torch\_scalar)

'torch'

>>> qml.math.get\_interface(numpy\_tensor)

'numpy'

```

`\_multi\_dispatch` previously had only one argument which contained a list of the tensors to be

dispatched:

```

>>> qml.math.\_multi\_dispatch([torch\_scalar, torch\_tensor, numpy\_tensor])

'torch'

```

To differentiate whether the user wants to get the interface of a single tensor or multiple

tensors, `get\_interface` now accepts a different argument per tensor to be dispatched:

```

>>> qml.math.get\_interface(\*[torch\_scalar, torch\_tensor, numpy\_tensor])

'torch'

>>> qml.math.get\_interface(torch\_scalar, torch\_tensor, numpy\_tensor)

'torch'

```

* `Operator.compute\_terms` is removed. On a specific instance of an operator, `op.terms()` can be used

instead. There is no longer a static method for this.

[(#3215)](https://github.com/PennyLaneAI/pennylane/pull/3215)

### Deprecations

* `QueuingManager.safe\_update\_info` and `AnnotatedQueue.safe\_update\_info` are deprecated. Instead, `update\_info` no longer raises errorsif the object isn’t in the queue.

[(#3085)](https://github.com/PennyLaneAI/pennylane/pull/3085)

* `qml.tape.stop\_recording` and `QuantumTape.stop\_recording` have been moved to `qml.QueuingManager.stop\_recording`. The old functions will still be available until v0.29.

[(#3068)](https://github.com/PennyLaneAI/pennylane/pull/3068)

* `qml.tape.get\_active\_tape` has been deprecated. Use `qml.QueuingManager.active\_context()` instead.

[(#3068)](https://github.com/PennyLaneAI/pennylane/pull/3068)

* `Operator.compute\_terms` has been removed. On a specific instance of an operator, use `op.terms()` instead. There is no longer a static method for this.

[(#3215)](https://github.com/PennyLaneAI/pennylane/pull/3215)

* `qml.tape.QuantumTape.inv()` has been deprecated. Use `qml.tape.QuantumTape.adjoint` instead.

[(#3237)](https://github.com/PennyLaneAI/pennylane/pull/3237)

* `qml.transforms.qcut.remap\_tape\_wires` has been deprecated. Use `qml.map\_wires` instead.

[(#3186)](https://github.com/PennyLaneAI/pennylane/pull/3186)

* The grouping module `qml.grouping` has been deprecated. Use `qml.pauli` or `qml.pauli.grouping` instead. The module will still be available until v0.28.

[(#3262)](https://github.com/PennyLaneAI/pennylane/pull/3262)

### Documentation

* The code block in the usage details of the UCCSD template has been updated.

[(#3140)](https://github.com/PennyLaneAI/pennylane/pull/3140)

* Added a “Deprecations” page to the developer documentation.

[(#3093)](https://github.com/PennyLaneAI/pennylane/pull/3093)

* The example of the `qml.FlipSign` template has been updated.

[(#3219)](https://github.com/PennyLaneAI/pennylane/pull/3219)

### Bug fixes

* `qml.SparseHamiltonian` now validates the size of the input matrix.

[(#3278)](https://github.com/PennyLaneAI/pennylane/pull/3278)

* Users no longer see unintuitive errors when inputing sequences to `qml.Hermitian`.

[(#3181)](https://github.com/PennyLaneAI/pennylane/pull/3181)

* The evaluation of QNodes that return either `vn\_entropy` or `mutual\_info` raises an

informative error message when using devices that define a vector of shots.

[(#3180)](https://github.com/PennyLaneAI/pennylane/pull/3180)

* Fixed a bug that made `qml.AmplitudeEmbedding` incompatible with JITting.

[(#3166)](https://github.com/PennyLaneAI/pennylane/pull/3166)

* Fixed the `qml.transforms.transpile` transform to work correctly for all two-qubit operations.

[(#3104)](https://github.com/PennyLaneAI/pennylane/pull/3104)

* Fixed a bug with the control values of a controlled version of a `ControlledQubitUnitary`.

[(#3119)](https://github.com/PennyLaneAI/pennylane/pull/3119)

* Fixed a bug where `qml.math.fidelity(non\_trainable\_state, trainable\_state)` failed unexpectedly.

[(#3160)](https://github.com/PennyLaneAI/pennylane/pull/3160)

* Fixed a bug where `qml.QueuingManager.stop\_recording` did not clean up if yielded code raises an exception.

[(#3182)](https://github.com/PennyLaneAI/pennylane/pull/3182)

* Returning `qml.sample()` or `qml.counts()` with other measurements of non-commuting observables

now raises a QuantumFunctionError (e.g., `return qml.expval(PauliX(wires=0)), qml.sample()`

now raises an error).

[(#2924)](https://github.com/PennyLaneAI/pennylane/pull/2924)

* Fixed a bug where `op.eigvals()` would return an incorrect result if the operator was a non-hermitian

composite operator.

[(#3204)](https://github.com/PennyLaneAI/pennylane/pull/3204)

* Fixed a bug where `qml.BasisStatePreparation` and `qml.BasisEmbedding` were not jit-compilable with JAX.

[(#3239)](https://github.com/PennyLaneAI/pennylane/pull/3239)

* Fixed a bug where `qml.MottonenStatePreparation` was not jit-compilable with JAX.

[(#3260)](https://github.com/PennyLaneAI/pennylane/pull/3260)

* Fixed a bug where `qml.MottonenStatePreparation` was not jit-compilable with JAX.

[(#3260)](https://github.com/PennyLaneAI/pennylane/pull/3260)

* Fixed a bug where `qml.expval(qml.Hamiltonian())` would not raise an error

if the Hamiltonian involved some wires that are not present on the device.

[(#3266)](https://github.com/PennyLaneAI/pennylane/pull/3266)

* Fixed a bug where `qml.tape.QuantumTape.shape()` did not account for the batch dimension of the tape

[(#3269)](https://github.com/PennyLaneAI/pennylane/pull/3269)

### Contributors

This release contains contributions from (in alphabetical order):

Kamal Mohamed Ali,

Guillermo Alonso-Linaje,

Juan Miguel Arrazola,

Utkarsh Azad,

Thomas Bromley,

Albert Mitjans Coma,

Isaac De Vlugt,

Olivia Di Matteo,

Amintor Dusko,

Lillian M. A. Frederiksen,

Diego Guala,

Josh Izaac,

Soran Jahangiri,

Edward Jiang,

Korbinian Kottmann,

Christina Lee,

Romain Moyard,

Lee J. O’Riordan,

Mudit Pandey,

Matthew Silverman,

Jay Soni,

Antal Száva,

David Wierichs,

orphan

#### Release 0.26.0[¶](#release-0-26-0 "Permalink to this headline")

### New features since last release

#### Classical shadows 👤

* PennyLane now provides built-in support for implementing the classical-shadows measurement protocol.

[(#2820)](https://github.com/PennyLaneAI/pennylane/pull/2820)

[(#2821)](https://github.com/PennyLaneAI/pennylane/pull/2821)

[(#2871)](https://github.com/PennyLaneAI/pennylane/pull/2871)

[(#2968)](https://github.com/PennyLaneAI/pennylane/pull/2968)

[(#2959)](https://github.com/PennyLaneAI/pennylane/pull/2959)

[(#2968)](https://github.com/PennyLaneAI/pennylane/pull/2968)

The classical-shadow measurement protocol is described in detail in the paper

[Predicting Many Properties of a Quantum System from Very Few Measurements](https://arxiv.org/abs/2002.08953).

As part of the support for classical shadows in this release, two new finite-shot and fully-differentiable measurements are available:

	+ QNodes returning the new measurement `qml.classical\_shadow()` will return two entities;

	`bits` (0 or 1 if the 1 or -1 eigenvalue is sampled, respectively) and `recipes`

	(the randomized Pauli measurements that are performed for each qubit, labelled by integer):

	

	

	

	```

	dev = qml.device("default.qubit", wires=2, shots=3)

	

	@qml.qnode(dev)

	def circuit():

	    qml.Hadamard(wires=0)

	    qml.CNOT(wires=[0, 1])

	    return qml.classical\_shadow(wires=[0, 1])

	

	```

	

	

	

	```

	>>> bits, recipes = circuit()

	>>> bits

	tensor([[0, 0],

	 [1, 0],

	 [0, 1]], dtype=uint8, requires\_grad=True)

	>>> recipes

	tensor([[2, 2],

	 [0, 2],

	 [0, 2]], dtype=uint8, requires\_grad=True)

	

	```

	+ QNodes returning `qml.shadow\_expval()` yield the expectation value estimation using classical shadows:

	

	

	

	```

	dev = qml.device("default.qubit", wires=range(2), shots=10000)

	

	@qml.qnode(dev)

	def circuit(x, H):

	    qml.Hadamard(0)

	    qml.CNOT((0,1))

	    qml.RX(x, wires=0)

	    return qml.shadow\_expval(H)

	

	x = np.array(0.5, requires\_grad=True)

	H = qml.Hamiltonian(

	        [1., 1.],

	        [qml.PauliZ(0) @ qml.PauliZ(1), qml.PauliX(0) @ qml.PauliX(1)]

	    )

	

	```

	

	

	

	```

	>>> circuit(x, H)

	tensor(1.8486, requires\_grad=True)

	>>> qml.grad(circuit)(x, H)

	-0.4797000000000001

	

	```Fully-differentiable QNode transforms for both new classical-shadows measurements are also available via

`qml.shadows.shadow\_state` and `qml.shadows.shadow\_expval`, respectively.

For convenient post-processing, we’ve also added the ability to calculate general Renyi entropies

by way of the `ClassicalShadow` class’ `entropy` method, which requires the wires of the subsystem of interest

and the Renyi entropy order:

```

>>> shadow = qml.ClassicalShadow(bits, recipes)

>>> vN\_entropy = shadow.entropy(wires=[0, 1], alpha=1)

```

#### Qutrits: quantum circuits for tertiary degrees of freedom ☘️

* An entirely new framework for quantum computing is now simulatable with the addition of qutrit functionalities.

[(#2699)](https://github.com/PennyLaneAI/pennylane/pull/2699)

[(#2781)](https://github.com/PennyLaneAI/pennylane/pull/2781)

[(#2782)](https://github.com/PennyLaneAI/pennylane/pull/2782)

[(#2783)](https://github.com/PennyLaneAI/pennylane/pull/2783)

[(#2784)](https://github.com/PennyLaneAI/pennylane/pull/2784)

[(#2841)](https://github.com/PennyLaneAI/pennylane/pull/2841)

[(#2843)](https://github.com/PennyLaneAI/pennylane/pull/2843)

[Qutrits](https://en.wikipedia.org/wiki/Qutrit) are like qubits, but instead live in a *three*-dimensional Hilbert space; they are not binary degrees of freedom, they are *tertiary*.

The advent of qutrits allows for all sorts of interesting theoretical, practical, and algorithmic capabilities that have yet to be discovered.

To facilitate qutrit circuits requires a new device: `default.qutrit`.

The `default.qutrit` device is a Python-based simulator, akin to `default.qubit`, and is defined as per usual:

```

>>> dev = qml.device("default.qutrit", wires=1)

```

The following operations are supported on `default.qutrit` devices:

	+ The qutrit shift operator, `qml.TShift`, and the ternary clock operator, `qml.TClock`, as defined in this paper by [Yeh et al. (2022)](https://arxiv.org/abs/2204.00552),

	which are the qutrit analogs of the Pauli X and Pauli Z operations, respectively.

	+ The `qml.TAdd` and `qml.TSWAP` operations which are the qutrit analogs of the CNOT and SWAP operations, respectively.

	+ Custom unitary operations via `qml.QutritUnitary`.

	+ `qml.state` and `qml.probs` measurements.

	+ Measuring user-specified Hermitian matrix observables via `qml.THermitian`.A comprehensive example of these features is given below:

```

dev = qml.device("default.qutrit", wires=1)

U = np.array([

        [1, 1, 1],

        [1, 1, 1],

        [1, 1, 1]

    ]

) / np.sqrt(3)

obs = np.array([

        [1, 1, 0],

        [1, -1, 0],

        [0, 0, np.sqrt(2)]

    ]

) / np.sqrt(2)

@qml.qnode(dev)

def qutrit\_state(U, obs):

    qml.TShift(0)

    qml.TClock(0)

    qml.QutritUnitary(U, wires=0)

    return qml.state()

@qml.qnode(dev)

def qutrit\_expval(U, obs):

    qml.TShift(0)

    qml.TClock(0)

    qml.QutritUnitary(U, wires=0)

    return qml.expval(qml.THermitian(obs, wires=0))

```

```

>>> qutrit\_state(U, obs)

tensor([-0.28867513+0.5j, -0.28867513+0.5j, -0.28867513+0.5j], requires\_grad=True)

>>> qutrit\_expval(U, obs)

tensor(0.80473785, requires\_grad=True)

```

We will continue to add more and more support for qutrits in future releases.

#### Simplifying just got... simpler 😌

* The `qml.simplify()` function has several intuitive improvements with this release.

[(#2978)](https://github.com/PennyLaneAI/pennylane/pull/2978)

[(#2982)](https://github.com/PennyLaneAI/pennylane/pull/2982)

[(#2922)](https://github.com/PennyLaneAI/pennylane/pull/2922)

[(#3012)](https://github.com/PennyLaneAI/pennylane/pull/3012)

`qml.simplify` can now perform the following:

	+ simplify parametrized operations

	+ simplify the adjoint and power of specific operators

	+ group like terms in a sum

	+ resolve products of Pauli operators

	+ combine rotation angles of identical rotation gatesHere is an example of `qml.simplify` in action with parameterized rotation gates.

In this case, the angles of rotation are simplified to be modulo \(4\pi\).

```

>>> op1 = qml.RX(30.0, wires=0)

>>> qml.simplify(op1)

RX(4.867258771281655, wires=[0])

>>> op2 = qml.RX(4 \* np.pi, wires=0)

>>> qml.simplify(op2)

Identity(wires=[0])

```

All of these simplification features can be applied directly to quantum functions, QNodes, and tapes via decorating with `@qml.simplify`, as well:

```

dev = qml.device("default.qubit", wires=2)

@qml.simplify

@qml.qnode(dev)

def circuit():

    qml.adjoint(qml.prod(qml.RX(1, 0) \*\* 1, qml.RY(1, 0), qml.RZ(1, 0)))

    return qml.probs(wires=0)

```

```

>>> circuit()

>>> list(circuit.tape)

[RZ(11.566370614359172, wires=[0]) @ RY(11.566370614359172, wires=[0]) @ RX(11.566370614359172, wires=[0]),

 probs(wires=[0])]

```

#### QNSPSA optimizer 💪

* A new optimizer called `qml.QNSPSAOptimizer` is available that implements the quantum natural simultaneous

perturbation stochastic approximation (QNSPSA) method based on

[Simultaneous Perturbation Stochastic Approximation of the Quantum Fisher Information](https://quantum-journal.org/papers/q-2021-10-20-567/).

[(#2818)](https://github.com/PennyLaneAI/pennylane/pull/2818)

`qml.QNSPSAOptimizer` is a second-order [SPSA algorithm](https://en.wikipedia.org/wiki/Simultaneous_perturbation_stochastic_approximation),

which combines the convergence power of the quantum-aware Quantum Natural Gradient

(QNG) optimization method with the reduced quantum evaluations of SPSA methods.

While the QNSPSA optimizer requires additional circuit executions (10 executions per

step) compared to standard SPSA optimization (3 executions per step), these additional

evaluations are used to provide a stochastic estimation of a second-order

metric tensor, which often helps the optimizer to achieve faster convergence.

Use `qml.QNSPSAOptimizer` like you would any other optimizer:

```

max\_iterations = 50

opt = qml.QNSPSAOptimizer()

for \_ in range(max\_iterations):

    params, cost = opt.step\_and\_cost(cost, params)

```

Check out [our demo](https://pennylane.ai/qml/demos/qnspsa.html) on the QNSPSA optimizer for more information.

#### Operator and parameter broadcasting supplements 📈

* Operator methods for exponentiation and raising to a power have been added.

[(#2799)](https://github.com/PennyLaneAI/pennylane/pull/2799)

[(#3029)](https://github.com/PennyLaneAI/pennylane/pull/3029)

	+ The `qml.exp` function can be used to create observables or generic rotation gates:

	

	

	

	```

	>>> x = 1.234

	>>> t = qml.PauliX(0) @ qml.PauliX(1) + qml.PauliY(0) @ qml.PauliY(1)

	>>> isingxy = qml.exp(t, 0.25j \* x)

	>>> isingxy.matrix()

	array([[1. +0.j , 0. +0.j ,

	 1. +0.j , 0. +0.j ],

	 [0. +0.j , 0.8156179+0.j ,

	 1. +0.57859091j, 0. +0.j ],

	 [0. +0.j , 0. +0.57859091j,

	 0.8156179+0.j , 0. +0.j ],

	 [0. +0.j , 0. +0.j ,

	 1. +0.j , 1. +0.j ]])

	

	```

	+ The `qml.pow` function raises a given operator to a power:

	

	

	

	```

	>>> op = qml.pow(qml.PauliX(0), 2)

	>>> op.matrix()

	array([[1, 0], [0, 1]])

	

	```

* An operator called `qml.PSWAP` is now available.

[(#2667)](https://github.com/PennyLaneAI/pennylane/pull/2667)

The `qml.PSWAP` gate – or phase-SWAP gate – was previously available within the PennyLane-Braket plugin only. Enjoy it natively in PennyLane with v0.26.

* Check whether or not an operator is hermitian or unitary with `qml.is\_hermitian` and `qml.is\_unitary`.

[(#2960)](https://github.com/PennyLaneAI/pennylane/pull/2960)

```

>>> op1 = qml.PauliX(wires=0)

>>> qml.is\_hermitian(op1)

True

>>> op2 = qml.PauliX(0) + qml.RX(np.pi/3, 0)

>>> qml.is\_unitary(op2)

False

```

* Embedding templates now support parameter broadcasting.

[(#2810)](https://github.com/PennyLaneAI/pennylane/pull/2810)

Embedding templates like `AmplitudeEmbedding` or `IQPEmbedding` now support

parameter broadcasting with a leading broadcasting dimension in their variational

parameters. `AmplitudeEmbedding`, for example, would usually use a one-dimensional input

vector of features. With broadcasting, we can now compute

```

>>> features = np.array([

...     [0.5, 0.5, 0., 0., 0.5, 0., 0.5, 0.],

...     [1., 0., 0., 0., 0., 0., 0., 0.],

...     [0.5, 0.5, 0., 0., 0., 0., 0.5, 0.5],

... ])

>>> op = qml.AmplitudeEmbedding(features, wires=[1, 5, 2])

>>> op.batch\_size

3

```

An exception is `BasisEmbedding`, which is not broadcastable.

### Improvements

* The `qml.math.expand\_matrix()` method now allows the sparse matrix representation of an operator to be extended to

a larger hilbert space.

[(#2998)](https://github.com/PennyLaneAI/pennylane/pull/2998)

```

>>> from scipy import sparse

>>> mat = sparse.csr\_matrix([[0, 1], [1, 0]])

>>> qml.math.expand\_matrix(mat, wires=[1], wire\_order=[0,1]).toarray()

array([[0., 1., 0., 0.],

 [1., 0., 0., 0.],

 [0., 0., 0., 1.],

 [0., 0., 1., 0.]])

```

* `qml.ctrl` now uses `Controlled` instead of `ControlledOperation`. The new `Controlled` class

wraps individual `Operator`‘s instead of a tape. It provides improved representations and integration.

[(#2990)](https://github.com/PennyLaneAI/pennylane/pull/2990)

* `qml.matrix` can now compute the matrix of tapes and QNodes that contain multiple

broadcasted operations or non-broadcasted operations after broadcasted ones.

[(#3025)](https://github.com/PennyLaneAI/pennylane/pull/3025)

A common scenario in which this becomes relevant is the decomposition of broadcasted

operations: the decomposition in general will contain one or multiple broadcasted

operations as well as operations with no or fixed parameters that are not broadcasted.

* Lists of operators are now internally sorted by their respective wires while also taking into account their commutativity property.

[(#2995)](https://github.com/PennyLaneAI/pennylane/pull/2995)

* Some methods of the `QuantumTape` class have been simplified and reordered to

improve both readability and performance.

[(#2963)](https://github.com/PennyLaneAI/pennylane/pull/2963)

* The `qml.qchem.molecular\_hamiltonian` function is modified to support observable grouping.

[(#2997)](https://github.com/PennyLaneAI/pennylane/pull/2997)

* `qml.ops.op\_math.Controlled` now has basic decomposition functionality.

[(#2938)](https://github.com/PennyLaneAI/pennylane/pull/2938)

* Automatic circuit cutting has been improved by making better partition imbalance derivations.

Now it is more likely to generate optimal cuts for larger circuits.

[(#2517)](https://github.com/PennyLaneAI/pennylane/pull/2517)

* By default, `qml.counts` only returns the outcomes observed in sampling. Optionally, specifying `qml.counts(all\_outcomes=True)`

will return a dictionary containing all possible outcomes.

[(#2889)](https://github.com/PennyLaneAI/pennylane/pull/2889)

```

>>> dev = qml.device("default.qubit", wires=2, shots=1000)

>>>

>>> @qml.qnode(dev)

>>> def circuit():

...     qml.Hadamard(wires=0)

...     qml.CNOT(wires=[0, 1])

...     return qml.counts(all\_outcomes=True)

>>> result = circuit()

>>> result

{'00': 495, '01': 0, '10': 0, '11': 505}

```

* Internal use of in-place inversion is eliminated in preparation for its deprecation.

[(#2965)](https://github.com/PennyLaneAI/pennylane/pull/2965)

* `Controlled` operators now work with `qml.is\_commuting`.

[(#2994)](https://github.com/PennyLaneAI/pennylane/pull/2994)

* `qml.prod` and `qml.op\_sum` now support the `sparse\_matrix()` method.

[(#3006)](https://github.com/PennyLaneAI/pennylane/pull/3006)

```

>>> xy = qml.prod(qml.PauliX(1), qml.PauliY(1))

>>> op = qml.op\_sum(xy, qml.Identity(0))

>>>

>>> sparse\_mat = op.sparse\_matrix(wire\_order=[0,1])

>>> type(sparse\_mat)

<class 'scipy.sparse.csr.csr\_matrix'>

>>> sparse\_mat.toarray()

[[1.+1.j 0.+0.j 0.+0.j 0.+0.j]

[0.+0.j 1.-1.j 0.+0.j 0.+0.j]

[0.+0.j 0.+0.j 1.+1.j 0.+0.j]

[0.+0.j 0.+0.j 0.+0.j 1.-1.j]]

```

* Provided `sparse\_matrix()` support for single qubit observables.

[(#2964)](https://github.com/PennyLaneAI/pennylane/pull/2964)

* `qml.Barrier` with `only\_visual=True` now simplifies via `op.simplify()` to the identity operator

or a product of identity operators.

[(#3016)](https://github.com/PennyLaneAI/pennylane/pull/3016)

* More accurate and intuitive outputs for printing some operators have been added.

[(#3013)](https://github.com/PennyLaneAI/pennylane/pull/3013)

* Results for the matrix of the sum or product of operators are stored in a more efficient manner.

[(#3022)](https://github.com/PennyLaneAI/pennylane/pull/3022)

* The computation of the (sparse) matrix for the sum or product of operators is now more efficient.

[(#3030)](https://github.com/PennyLaneAI/pennylane/pull/3030)

* When the factors of `qml.prod` don’t share any wires, the matrix and sparse matrix are computed using

a kronecker product for improved efficiency.

[(#3040)](https://github.com/PennyLaneAI/pennylane/pull/3040)

* `qml.grouping.is\_pauli\_word` now returns `False` for operators that don’t inherit from `qml.Observable` instead of raising an error.

[(#3039)](https://github.com/PennyLaneAI/pennylane/pull/3039)

* Added functionality to iterate over operators created from `qml.op\_sum` and `qml.prod`.

[(#3028)](https://github.com/PennyLaneAI/pennylane/pull/3028)

```

>>> op = qml.op\_sum(qml.PauliX(0), qml.PauliY(1), qml.PauliZ(2))

>>> len(op)

3

>>> op[1]

PauliY(wires=[1])

>>> [o.name for o in op]

['PauliX', 'PauliY', 'PauliZ']

```

### Deprecations

* In-place inversion is now deprecated. This includes `op.inv()` and `op.inverse=value`. Please

use `qml.adjoint` or `qml.pow` instead. Support for these methods will remain till v0.28.

[(#2988)](https://github.com/PennyLaneAI/pennylane/pull/2988)

Don’t use:

```

>>> v1 = qml.PauliX(0).inv()

>>> v2 = qml.PauliX(0)

>>> v2.inverse = True

```

Instead use:

```

>>> qml.adjoint(qml.PauliX(0))

Adjoint(PauliX(wires=[0]))

>>> qml.pow(qml.PauliX(0), -1)

PauliX(wires=[0])\*\*-1

>>> qml.pow(qml.PauliX(0), -1, lazy=False)

PauliX(wires=[0])

>>> qml.PauliX(0) \*\* -1

PauliX(wires=[0])\*\*-1

```

`qml.adjoint` takes the conjugate transpose of an operator, while `qml.pow(op, -1)` indicates matrix

inversion. For unitary operators, `adjoint` will be more efficient than `qml.pow(op, -1)`, even

though they represent the same thing.

* The `supports\_reversible\_diff` device capability is unused and has been removed.

[(#2993)](https://github.com/PennyLaneAI/pennylane/pull/2993)

### Breaking changes

* Measuring an operator that might not be hermitian now raises a warning instead of an

error. To definitively determine whether or not an operator is hermitian, use `qml.is\_hermitian`.

[(#2960)](https://github.com/PennyLaneAI/pennylane/pull/2960)

* The `ControlledOperation` class has been removed. This was a developer-only class, so the change should not be evident to

any users. It is replaced by `Controlled`.

[(#2990)](https://github.com/PennyLaneAI/pennylane/pull/2990)

* The default `execute` method for the `QubitDevice` base class now calls `self.statistics`

with an additional keyword argument `circuit`, which represents the quantum tape

being executed.

Any device that overrides `statistics` should edit the signature of the method to include

the new `circuit` keyword argument.

[(#2820)](https://github.com/PennyLaneAI/pennylane/pull/2820)

* The `expand\_matrix()` has been moved from `pennylane.operation` to

`pennylane.math.matrix\_manipulation`

[(#3008)](https://github.com/PennyLaneAI/pennylane/pull/3008)

* `qml.grouping.utils.is\_commuting` has been removed, and its Pauli word logic is now part of `qml.is\_commuting`.

[(#3033)](https://github.com/PennyLaneAI/pennylane/pull/3033)

* `qml.is\_commuting` has been moved from `pennylane.transforms.commutation\_dag` to `pennylane.ops.functions`.

[(#2991)](https://github.com/PennyLaneAI/pennylane/pull/2991)

### Documentation

* Updated the Fourier transform docs to use `circuit\_spectrum` instead of `spectrum`, which has been deprecated.

[(#3018)](https://github.com/PennyLaneAI/pennylane/pull/3018)

* Corrected the docstrings for diagonalizing gates for all relevant operations. The docstrings used

to say that the diagonalizing gates implemented \(U\), the unitary such that \(O = U \Sigma U^{\dagger}\), where \(O\) is

the original observable and \(\Sigma\) a diagonal matrix. However, the diagonalizing gates actually implement

\(U^{\dagger}\), since \(\langle \psi | O | \psi \rangle = \langle \psi | U \Sigma U^{\dagger} | \psi \rangle\),

making \(U^{\dagger} | \psi \rangle\) the actual state being measured in the Z-basis.

[(#2981)](https://github.com/PennyLaneAI/pennylane/pull/2981)

### Bug fixes

* Fixed a bug with `qml.ops.Exp` operators when the coefficient is autograd but the diagonalizing gates

don’t act on all wires.

[(#3057)](https://github.com/PennyLaneAI/pennylane/pull/3057)

* Fixed a bug where the tape transform `single\_qubit\_fusion` computed wrong rotation angles

for specific combinations of rotations.

[(#3024)](https://github.com/PennyLaneAI/pennylane/pull/3024)

* Jax gradients now work with a QNode when the quantum function was transformed by `qml.simplify`.

[(#3017)](https://github.com/PennyLaneAI/pennylane/pull/3017)

* Operators that have `num\_wires = AnyWires` or `num\_wires = AnyWires` now raise an error, with

certain exceptions, when instantiated with `wires=[]`.

[(#2979)](https://github.com/PennyLaneAI/pennylane/pull/2979)

* Fixed a bug where printing `qml.Hamiltonian` with complex coefficients raises `TypeError` in some cases.

[(#3004)](https://github.com/PennyLaneAI/pennylane/pull/3004)

* Added a more descriptive error message when measuring non-commuting observables at the end of a circuit with

`probs`, `samples`, `counts` and `allcounts`.

[(#3065)](https://github.com/PennyLaneAI/pennylane/pull/3065)

### Contributors

This release contains contributions from (in alphabetical order):

Juan Miguel Arrazola, Utkarsh Azad, Tom Bromley, Olivia Di Matteo, Isaac De Vlugt, Yiheng Duan,

Lillian Marie Austin Frederiksen, Josh Izaac, Soran Jahangiri, Edward Jiang, Ankit Khandelwal,

Korbinian Kottmann, Meenu Kumari, Christina Lee, Albert Mitjans Coma, Romain Moyard, Rashid N H M,

Zeyue Niu, Mudit Pandey, Matthew Silverman, Jay Soni, Antal Száva, Cody Wang, David Wierichs.

orphan

#### Release 0.25.1[¶](#release-0-25-1 "Permalink to this headline")

### Bug fixes

* Fixed Torch device discrepencies for certain parametrized operations by

updating `qml.math.array` and `qml.math.eye` to preserve the Torch device

used.

[(#2967)](https://github.com/PennyLaneAI/pennylane/pull/2967)

### Contributors

This release contains contributions from (in alphabetical order):

Romain Moyard, Rashid N H M, Lee James O’Riordan, Antal Száva

orphan

#### Release 0.25.0[¶](#release-0-25-0 "Permalink to this headline")

### New features since last release

#### Estimate computational resource requirements 🧠

* Functionality for estimating molecular simulation computations has been added with `qml.resource`.

[(#2646)](https://github.com/PennyLaneAI/pennylane/pull/2646)

[(#2653)](https://github.com/PennyLaneAI/pennylane/pull/2653)

[(#2665)](https://github.com/PennyLaneAI/pennylane/pull/2665)

[(#2694)](https://github.com/PennyLaneAI/pennylane/pull/2694)

[(#2720)](https://github.com/PennyLaneAI/pennylane/pull/2720)

[(#2723)](https://github.com/PennyLaneAI/pennylane/pull/2723)

[(#2746)](https://github.com/PennyLaneAI/pennylane/pull/2746)

[(#2796)](https://github.com/PennyLaneAI/pennylane/pull/2796)

[(#2797)](https://github.com/PennyLaneAI/pennylane/pull/2797)

[(#2874)](https://github.com/PennyLaneAI/pennylane/pull/2874)

[(#2944)](https://github.com/PennyLaneAI/pennylane/pull/2944)

[(#2644)](https://github.com/PennyLaneAI/pennylane/pull/2644)

The new [resource](https://pennylane.readthedocs.io/en/stable/code/qml_resource.html) module allows you to estimate the number of

non-[Clifford gates](https://en.wikipedia.org/wiki/Clifford_gates) and logical

qubits needed to implement [quantum phase estimation](https://codebook.xanadu.ai/P.1)

algorithms for simulating materials and molecules. This includes support for quantum

algorithms using [first](https://en.wikipedia.org/wiki/First_quantization) and [second](https://en.wikipedia.org/wiki/Second_quantization) quantization with specific bases:

	+ [First quantization](https://en.wikipedia.org/wiki/First_quantization) using a plane-wave basis via the `FirstQuantization` class:

	

	

	

	```

	>>> n = 100000        # number of plane waves

	>>> eta = 156         # number of electrons

	>>> omega = 1145.166  # unit cell volume in atomic units

	>>> algo = FirstQuantization(n, eta, omega)

	>>> print(algo.gates, algo.qubits)

	1.10e+13, 4416

	

	```

	+ [Second quantization](https://en.wikipedia.org/wiki/Second_quantization) with a double-factorized Hamiltonian via the

	`DoubleFactorization` class:

	

	

	

	```

	symbols = ["O", "H", "H"]

	geometry = np.array(

	    [

	        [0.00000000, 0.00000000, 0.28377432],

	        [0.00000000, 1.45278171, -1.00662237],

	        [0.00000000, -1.45278171, -1.00662237],

	    ],

	    requires\_grad=False,

	)

	

	mol = qml.qchem.Molecule(symbols, geometry, basis\_name="sto-3g")

	core, one, two = qml.qchem.electron\_integrals(mol)()

	

	algo = DoubleFactorization(one, two)

	

	```

	

	

	

	```

	>>> print(algo.gates, algo.qubits)

	103969925, 290

	

	```The methods of the `FirstQuantization` and the `DoubleFactorization` classes, such as `qubit\_cost` (number of logical qubits) and `gate\_cost` (number of non-Clifford gates), can be also accessed as static methods:

```

>>> qml.resource.FirstQuantization.qubit\_cost(100000, 156, 169.69608, 0.01)

4377

>>> qml.resource.FirstQuantization.gate\_cost(100000, 156, 169.69608, 0.01)

3676557345574

```

#### Differentiable error mitigation ⚙️

* Differentiable zero-noise-extrapolation (ZNE) error mitigation is now available.

[(#2757)](https://github.com/PennyLaneAI/pennylane/pull/2757)

Elevate any variational quantum algorithm to a *mitigated* algorithm with improved

results on noisy hardware while maintaining differentiability throughout.

In order to do so, use the `qml.transforms.mitigate\_with\_zne` transform on your QNode and provide the PennyLane proprietary

`qml.transforms.fold\_global` folding function and `qml.transforms.poly\_extrapolate` extrapolation function.

Here is an example for a noisy simulation device where we mitigate a QNode and are still

able to compute the gradient:

```

# Describe noise

noise\_gate = qml.DepolarizingChannel

noise\_strength = 0.1

# Load devices

dev\_ideal = qml.device("default.mixed", wires=1)

dev\_noisy = qml.transforms.insert(noise\_gate, noise\_strength)(dev\_ideal)

scale\_factors = [1, 2, 3]

@mitigate\_with\_zne(

  scale\_factors,

  qml.transforms.fold\_global,

  qml.transforms.poly\_extrapolate,

  extrapolate\_kwargs={'order': 2}

)

@qml.qnode(dev\_noisy)

def qnode\_mitigated(theta):

    qml.RY(theta, wires=0)

    return qml.expval(qml.PauliX(0))

```

```

>>> theta = np.array(0.5, requires\_grad=True)

>>> qml.grad(qnode\_mitigated)(theta)

0.5712737447327619

```

#### More native support for parameter broadcasting 📡

* `default.qubit` now natively supports parameter broadcasting, providing

increased performance when executing the same circuit at various parameter positions

compared to manually looping over parameters, or directly using the `qml.transforms.broadcast\_expand` transform.

[(#2627)](https://github.com/PennyLaneAI/pennylane/pull/2627)

```

dev = qml.device("default.qubit", wires=1)

@qml.qnode(dev)

def circuit(x):

    qml.RX(x, wires=0)

    return qml.expval(qml.PauliZ(0))

```

```

>>> circuit(np.array([0.1, 0.3, 0.2]))

tensor([0.99500417, 0.95533649, 0.98006658], requires\_grad=True)

```

Currently, not all templates have been updated to support broadcasting.

* Parameter-shift gradients now allow for parameter broadcasting internally,

which can result in a significant speedup when computing gradients of

circuits with many parameters.

[(#2749)](https://github.com/PennyLaneAI/pennylane/pull/2749)

The gradient transform `qml.gradients.param\_shift` now accepts the keyword argument

`broadcast`. If set to `True`, broadcasting is used to compute the derivative:

```

dev = qml.device("default.qubit", wires=2)

@qml.qnode(dev)

def circuit(x, y):

    qml.RX(x, wires=0)

    qml.RY(y, wires=1)

    return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1))

```

```

>>> x = np.array([np.pi/3, np.pi/2], requires\_grad=True)

>>> y = np.array([np.pi/6, np.pi/5], requires\_grad=True)

>>> qml.gradients.param\_shift(circuit, broadcast=True)(x, y)

(tensor([[-0.7795085, 0. ],

 [ 0. , -0.7795085]], requires\_grad=True),

tensor([[-0.125, 0. ],

 [0. , -0.125]], requires\_grad=True))

```

The following example highlights how to make use of broadcasting

gradients at the QNode level. Internally, broadcasting is used to

compute the parameter-shift rule when required, which may result in

performance improvements.

```

@qml.qnode(dev, diff\_method="parameter-shift", broadcast=True)

def circuit(x, y):

    qml.RX(x, wires=0)

    qml.RY(y, wires=1)

    return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1))

```

```

>>> x = np.array(0.1, requires\_grad=True)

>>> y = np.array(0.4, requires\_grad=True)

>>> qml.grad(circuit)(x, y)

(array(-0.09195267), array(-0.38747287))

```

Here, only 2 circuits are created internally, rather than 4

with `broadcast=False`.

To illustrate the speedup, for a constant-depth circuit with Pauli rotations and controlled Pauli rotations, the

time required to compute `qml.gradients.param\_shift(circuit, broadcast=False)(params)`

(“No broadcasting”) and `qml.gradients.param\_shift(circuit, broadcast=True)(params)`

(“Broadcasting”) as a function of the number of qubits is given

[here](https://pennylane.readthedocs.io/en/stable/_images/param_shift_broadcast_speedup.png).

* Operations for quantum chemistry now support parameter broadcasting.

[(#2726)](https://github.com/PennyLaneAI/pennylane/pull/2726)

```

>>> op = qml.SingleExcitation(np.array([0.3, 1.2, -0.7]), wires=[0, 1])

>>> op.matrix().shape

(3, 4, 4)

```

#### Intuitive operator arithmetic 🧮

* New functionality for representing the sum, product, and scalar-product

of operators is available.

[(#2475)](https://github.com/PennyLaneAI/pennylane/pull/2475)

[(#2625)](https://github.com/PennyLaneAI/pennylane/pull/2625)

[(#2622)](https://github.com/PennyLaneAI/pennylane/pull/2622)

[(#2721)](https://github.com/PennyLaneAI/pennylane/pull/2721)

The following functionalities have been added to facilitate creating new operators

whose matrix, terms, and eigenvalues can be accessed as per usual, while maintaining

differentiability. Operators created from these new features can be used within

QNodes as operations or as observables (where physically applicable).

	+ Summing any number of operators via `qml.op\_sum` results in a “summed” operator:

	

	

	

	```

	>>> ops\_to\_sum = [qml.PauliX(0), qml.PauliY(1), qml.PauliZ(0)]

	>>> summed\_ops = qml.op\_sum(\*ops\_to\_sum)

	>>> summed\_ops

	PauliX(wires=[0]) + PauliY(wires=[1]) + PauliZ(wires=[0])

	>>> qml.matrix(summed\_ops)

	array([[ 1.+0.j, 0.-1.j, 1.+0.j, 0.+0.j],

	 [ 0.+1.j, 1.+0.j, 0.+0.j, 1.+0.j],

	 [ 1.+0.j, 0.+0.j, -1.+0.j, 0.-1.j],

	 [ 0.+0.j, 1.+0.j, 0.+1.j, -1.+0.j]])

	>>> summed\_ops.terms()

	([1.0, 1.0, 1.0], (PauliX(wires=[0]), PauliY(wires=[1]), PauliZ(wires=[0])))

	

	```

	+ Multiplying any number of operators via `qml.prod` results in a “product” operator,

	where the matrix product or tensor product is used correspondingly:

	

	

	

	```

	>>> theta = 1.23

	>>> prod\_op = qml.prod(qml.PauliZ(0), qml.RX(theta, 1))

	>>> prod\_op

	PauliZ(wires=[0]) @ RX(1.23, wires=[1])

	>>> qml.eigvals(prod\_op)

	[-1.39373197 -0.23981492 0.23981492 1.39373197]

	

	```

	+ Taking the product of a coefficient and an operator via `qml.s\_prod` produces a

	“scalar-product” operator:

	

	

	

	```

	>>> sprod\_op = qml.s\_prod(2.0, qml.PauliX(0))

	>>> sprod\_op

	2.0\*(PauliX(wires=[0]))

	>>> sprod\_op.matrix()

	array([[ 0., 2.],

	 [ 2., 0.]])

	>>> sprod\_op.terms()

	([2.0], [PauliX(wires=[0])])

	

	```Each of these new functionalities can be used within QNodes as operators or observables,

where applicable, while also maintaining differentiability. For example:

```

dev = qml.device("default.qubit", wires=2)

@qml.qnode(dev)

def circuit(angles):

    qml.prod(qml.PauliZ(0), qml.RY(angles[0], 1))

    qml.op\_sum(qml.PauliX(1), qml.RY(angles[1], 0))

    return qml.expval(qml.op\_sum(qml.PauliX(0), qml.PauliZ(1)))

```

```

>>> angles = np.array([1.23, 4.56], requires\_grad=True)

>>> circuit(angles)

tensor(0.33423773, requires\_grad=True)

>>> qml.grad(circuit)(angles)

array([-0.9424888, 0. ])

```

* All PennyLane operators can now be added, subtracted, multiplied, scaled, and raised to

powers using `+`, `-`, `@`, `\*`, `\*\*`, respectively.

[(#2849)](https://github.com/PennyLaneAI/pennylane/pull/2849)

[(#2825)](https://github.com/PennyLaneAI/pennylane/pull/2825)

[(#2891)](https://github.com/PennyLaneAI/pennylane/pull/2891)

	+ You can now add scalars to operators, where the interpretation is that the

	scalar is a properly-sized identity matrix;

	

	

	

	```

	>>> sum\_op = 5 + qml.PauliX(0)

	>>> sum\_op.matrix()

	array([[5., 1.],

	 [1., 5.]])

	

	```

	+ The `+` and `-` operators can be used to combine all Pennylane operators:

	

	

	

	```

	>>> sum\_op = qml.RX(phi=1.23, wires=0) + qml.RZ(phi=3.14, wires=0) - qml.RY(phi=0.12, wires=0)

	>>> sum\_op

	RX(1.23, wires=[0]) + RZ(3.14, wires=[0]) + -1\*(RY(0.12, wires=[0]))

	>>> qml.matrix(sum\_op)

	array([[-0.18063077-0.99999968j, 0.05996401-0.57695852j],

	 [-0.05996401-0.57695852j, -0.18063077+0.99999968j]])

	

	```

	

	

	Note that the behavior of `+` and `-` with *observables* is different; it still creates

	a Hamiltonian.

	+ The `\*` and `@` operators can be used to scale and compose all PennyLane operators.

	

	

	

	```

	>>> prod\_op = 2\*qml.RX(1, wires=0) @ qml.RY(2, wires=0)

	>>> prod\_op

	2\*(RX(1, wires=[0])) @ RY(2, wires=[0])

	>>> qml.matrix(prod\_op)

	array([[ 0.94831976-0.80684536j, -1.47692053-0.51806945j],

	 [ 1.47692053-0.51806945j, 0.94831976+0.80684536j]])

	

	```

	+ The `\*\*` operator can be used to raise PennyLane operators to a power.

	

	

	

	```

	>>> exp\_op = qml.RZ(1.0, wires=0) \*\* 2

	>>> exp\_op

	RZ\*\*2(1.0, wires=[0])

	>>> qml.matrix(exp\_op)

	array([[0.54030231-0.84147098j, 0. +0.j ],

	 [0. +0.j , 0.54030231+0.84147098j]])

	

	```

* A new class called `Controlled` is available in `qml.ops.op\_math` to represent

a controlled version of any operator. This will eventually be integrated into

`qml.ctrl` to provide a performance increase and more feature coverage.

[(#2634)](https://github.com/PennyLaneAI/pennylane/pull/2634)

* Arithmetic operations can now be simplified using `qml.simplify`.

[(#2835)](https://github.com/PennyLaneAI/pennylane/pull/2835)

[(#2854)](https://github.com/PennyLaneAI/pennylane/pull/2854)

```

>>> op = qml.adjoint(qml.adjoint(qml.RX(x, wires=0)))

>>> op

Adjoint(Adjoint(RX))(tensor([1.04719755, 1.57079633], requires\_grad=True), wires=[0])

>>> qml.simplify(op)

RX(tensor([1.04719755, 1.57079633], requires\_grad=True), wires=[0])

```

* A new function called `qml.equal` can be used to compare the equality

of parametric operators.

[(#2651)](https://github.com/PennyLaneAI/pennylane/pull/2651)

```

>>> qml.equal(qml.RX(1.23, 0), qml.RX(1.23, 0))

True

>>> qml.equal(qml.RY(4.56, 0), qml.RY(7.89, 0))

False

```

#### Marvelous mixed state features 🙌

* The `default.mixed` device now supports [backpropagation](https://pennylane.readthedocs.io/en/stable/introduction/unsupported_gradients.html#backpropagation) with the `"jax"` interface, which can result in significant speedups.

[(#2754)](https://github.com/PennyLaneAI/pennylane/pull/2754)

[(#2776)](https://github.com/PennyLaneAI/pennylane/pull/2776)

```

dev = qml.device("default.mixed", wires=2)

@qml.qnode(dev, diff\_method="backprop", interface="jax")

def circuit(angles):

    qml.RX(angles[0], wires=0)

    qml.RY(angles[1], wires=1)

    return qml.expval(qml.PauliZ(0) + qml.PauliZ(1))

```

```

>>> angles = np.array([np.pi/6, np.pi/5], requires\_grad=True)

>>> qml.grad(circuit)(angles)

array([-0.8660254 , -0.25881905])

```

Additionally, quantum channels now support Jax and TensorFlow tensors.

This allows quantum channels to be used inside QNodes decorated by `tf.function`,

`jax.jit`, or `jax.vmap`.

* The `default.mixed` device now supports readout error.

[(#2786)](https://github.com/PennyLaneAI/pennylane/pull/2786)

A new keyword argument called `readout\_prob` can be specified when creating a

`default.mixed` device. Any circuits running on a `default.mixed` device with a

finite `readout\_prob` (upper-bounded by 1) will alter the measurements performed

at the end of the circuit similarly to how a `qml.BitFlip` channel would affect

circuit measurements:

```

>>> dev = qml.device("default.mixed", wires=2, readout\_prob=0.1)

>>> @qml.qnode(dev)

... def circuit():

...     return qml.expval(qml.PauliZ(0))

>>> circuit()

array(0.8)

```

#### Relative entropy is now available in qml.qinfo 💥

* The quantum information module now supports computation of [relative entropy](https://en.wikipedia.org/wiki/Quantum_relative_entropy).

[(#2772)](https://github.com/PennyLaneAI/pennylane/pull/2772)

We’ve enabled two cases for calculating the relative entropy:

	+ A QNode transform via `qml.qinfo.relative\_entropy`:

	

	

	

	```

	dev = qml.device('default.qubit', wires=2)

	

	@qml.qnode(dev)

	def circuit(param):

	    qml.RY(param, wires=0)

	    qml.CNOT(wires=[0, 1])

	    return qml.state()

	

	```

	

	

	

	```

	>>> relative\_entropy\_circuit = qml.qinfo.relative\_entropy(circuit, circuit, wires0=[0], wires1=[0])

	>>> x, y = np.array(0.4), np.array(0.6)

	>>> relative\_entropy\_circuit((x,), (y,))

	0.017750012490703237

	

	```

	+ Support in `qml.math` for flexible post-processing:

	

	

	

	```

	>>> rho = np.array([[0.3, 0], [0, 0.7]])

	>>> sigma = np.array([[0.5, 0], [0, 0.5]])

	>>> qml.math.relative\_entropy(rho, sigma)

	tensor(0.08228288, requires\_grad=True)

	

	```

#### New measurements, operators, and more! ✨

* A new measurement called `qml.counts` is available.

[(#2686)](https://github.com/PennyLaneAI/pennylane/pull/2686)

[(#2839)](https://github.com/PennyLaneAI/pennylane/pull/2839)

[(#2876)](https://github.com/PennyLaneAI/pennylane/pull/2876)

QNodes with `shots != None` that return `qml.counts` will yield a dictionary

whose keys are bitstrings representing computational basis states that were measured,

and whose values are the corresponding counts (i.e., how many times that computational

basis state was measured):

```

dev = qml.device("default.qubit", wires=2, shots=1000)

@qml.qnode(dev)

def circuit():

    qml.Hadamard(wires=0)

    qml.CNOT(wires=[0, 1])

    return qml.counts()

```

```

>>> circuit()

{'00': 495, '11': 505}

```

`qml.counts` can also accept observables, where the resulting dictionary is ordered

by the eigenvalues of the observable.

```

dev = qml.device("default.qubit", wires=2, shots=1000)

@qml.qnode(dev)

def circuit():

    qml.Hadamard(wires=0)

    qml.CNOT(wires=[0, 1])

    return qml.counts(qml.PauliZ(0)), qml.counts(qml.PauliZ(1))

```

```

>>> circuit()

({-1: 470, 1: 530}, {-1: 470, 1: 530})

```

* A new experimental return type for QNodes with multiple measurements has been added.

[(#2814)](https://github.com/PennyLaneAI/pennylane/pull/2814)

[(#2815)](https://github.com/PennyLaneAI/pennylane/pull/2815)

[(#2860)](https://github.com/PennyLaneAI/pennylane/pull/2860)

QNodes returning a list or tuple of different measurements return an intuitive

data structure via `qml.enable\_return()`, where the individual measurements are

separated into their own tensors:

```

qml.enable\_return()

dev = qml.device("default.qubit", wires=2)

@qml.qnode(dev)

def circuit(x):

    qml.Hadamard(wires=[0])

    qml.CRX(x, wires=[0, 1])

    return (qml.probs(wires=[0]), qml.vn\_entropy(wires=[0]), qml.probs(wires=0), qml.expval(wires=1))

```

```

>>> circuit(0.5)

(tensor([0.5, 0.5], requires\_grad=True), tensor(0.08014815, requires\_grad=True), tensor([0.5, 0.5], requires\_grad=True), tensor(0.93879128, requires\_grad=True))

```

In addition, QNodes that utilize this new return type support backpropagation.

This new return type can be disabled thereafter via `qml.disable\_return()`.

* An operator called `qml.FlipSign` is now available.

[(#2780)](https://github.com/PennyLaneAI/pennylane/pull/2780)

Mathematically, `qml.FlipSign` functions as follows:

\(\text{FlipSign}(n) \vert m \rangle = (-1)^\delta\_{n,m} \vert m \rangle\), where

\(\vert m \rangle\) is an arbitrary qubit state and $n$ is a qubit configuration:

```

basis\_state = [0, 1]

dev = qml.device("default.qubit", wires=2)

@qml.qnode(dev)

def circuit():

  for wire in list(range(2)):

        qml.Hadamard(wires = wire)

  qml.FlipSign(basis\_state, wires = list(range(2)))

  return qml.state()

```

```

>>> circuit()

tensor([ 0.5+0.j -0.5+0.j 0.5+0.j 0.5+0.j], requires\_grad=True)

```

* The [simultaneous perturbation stochastic approximation (SPSA) optimizer](https://www.jhuapl.edu/SPSA/PDF-SPSA/Spall_An_Overview.PDF)

is available via `qml.SPSAOptimizer`.

[(#2661)](https://github.com/PennyLaneAI/pennylane/pull/2661)

The SPSA optimizer is suitable for cost functions whose evaluation may involve

noise. Use the SPSA optimizer like you would any other optimizer:

```

max\_iterations = 50

opt = qml.SPSAOptimizer(maxiter=max\_iterations)

for \_ in range(max\_iterations):

    params, cost = opt.step\_and\_cost(cost, params)

```

#### More drawing styles 🎨

* New PennyLane-inspired `sketch` and `sketch\_dark` styles are now available for

drawing circuit diagram graphics.

[(#2709)](https://github.com/PennyLaneAI/pennylane/pull/2709)

### Improvements 📈

* `default.qubit` now natively executes any operation that defines a matrix except

for trainable `Pow` operations.

[(#2836)](https://github.com/PennyLaneAI/pennylane/pull/2836)

* Added `expm` to the `qml.math` module for matrix exponentiation.

[(#2890)](https://github.com/PennyLaneAI/pennylane/pull/2890)

* When adjoint differentiation is requested, circuits are now decomposed so

that all trainable operations have a generator.

[(#2836)](https://github.com/PennyLaneAI/pennylane/pull/2836)

* A warning is now emitted for `qml.state`, `qml.density\_matrix`,

`qml.vn\_entropy`, and `qml.mutual\_info` when using a device with

finite shots or a shot list since these measurements are always analytic.

[(#2918)](https://github.com/PennyLaneAI/pennylane/pull/2918)

* The efficiency of the Hartree-Fock workflow has been improved by removing

repetitive steps.

[(#2850)](https://github.com/PennyLaneAI/pennylane/pull/2850)

* The coefficients of the non-differentiable molecular Hamiltonians generated

with openfermion now have `requires\_grad = False` by default.

[(#2865)](https://github.com/PennyLaneAI/pennylane/pull/2865)

* Upgraded performance of the `compute\_matrix` method of broadcastable

parametric operations.

[(#2759)](https://github.com/PennyLaneAI/pennylane/pull/2759)

* Jacobians are now cached with the Autograd interface when using the

parameter-shift rule.

[(#2645)](https://github.com/PennyLaneAI/pennylane/pull/2645)

* The `qml.state` and `qml.density\_matrix` measurements now support custom wire

labels.

[(#2779)](https://github.com/PennyLaneAI/pennylane/pull/2779)

* Add trivial behaviour logic to `qml.operation.expand\_matrix`.

[(#2785)](https://github.com/PennyLaneAI/pennylane/issues/2785)

* Added an `are\_pauli\_words\_qwc` function which checks if certain

Pauli words are pairwise qubit-wise commuting. This new function improves performance

when measuring hamiltonians with many commuting terms.

[(#2789)](https://github.com/PennyLaneAI/pennylane/pull/2798)

* Adjoint differentiation now uses the adjoint symbolic wrapper instead of in-place

inversion.

[(#2855)](https://github.com/PennyLaneAI/pennylane/pull/2855)

### Breaking changes 💔

* The deprecated `qml.hf` module is removed. Users with code that calls `qml.hf`

can simply replace `qml.hf` with `qml.qchem` in most cases, or refer to the

[qchem documentation](https://pennylane.readthedocs.io/en/stable/code/qml_qchem.html)

and [demos](https://pennylane.ai/qml/demos_quantum-chemistry.html) for more

information.

[(#2795)](https://github.com/PennyLaneAI/pennylane/pull/2795)

* `default.qubit` now uses `stopping\_condition` to specify support for anything with a matrix.

To override this behavior in inheriting devices and to support only a specific subset of operations,

developers need to override `stopping\_condition`.

[(#2836)](https://github.com/PennyLaneAI/pennylane/pull/2836)

* Custom devices inheriting from `DefaultQubit` or `QubitDevice` can break due to the introduction

of parameter broadcasting.

[(#2627)](https://github.com/PennyLaneAI/pennylane/pull/2627)

A custom device should only break if all three following statements hold simultaneously:

	1. The custom device inherits from `DefaultQubit`, not `QubitDevice`.

	2. The device implements custom methods in the simulation pipeline that are incompatible

	with broadcasting (for example `expval`, `apply\_operation` or `analytic\_probability`).

	3. The custom device maintains the flag `"supports\_broadcasting": True` in its `capabilities`

	dictionary *or* it overwrites `Device.batch\_transform` without applying `broadcast\_expand`

	(or both).The `capabilities["supports\_broadcasting"]` is set to `True` for

`DefaultQubit`. Typically, the easiest fix will be to change the

`capabilities["supports\_broadcasting"]` flag to `False` for the child device

and/or to include a call to `broadcast\_expand` in

`CustomDevice.batch\_transform`, similar to how `Device.batch\_transform` calls

it.

Separately from the above, custom devices that inherit from `QubitDevice` and implement a

custom `\_gather` method need to allow for the kwarg `axis` to be passed to this `\_gather` method.

* The argument `argnum` of the function `qml.batch\_input` has been redefined: now it indicates the

indices of the batched parameters, which need to be non-trainable, in the quantum tape. Consequently, its default

value (set to 0) has been removed.

[(#2873)](https://github.com/PennyLaneAI/pennylane/pull/2873)

Before this breaking change, one could call `qml.batch\_input` without any arguments when using

batched inputs as the first argument of the quantum circuit.

```

dev = qml.device("default.qubit", wires=2, shots=None)

@qml.batch\_input()  # argnum = 0

@qml.qnode(dev, diff\_method="parameter-shift", interface="tf")

def circuit(inputs, weights):  # argument `inputs` is batched

    qml.RY(weights[0], wires=0)

    qml.AngleEmbedding(inputs, wires=range(2), rotation="Y")

    qml.RY(weights[1], wires=1)

    return qml.expval(qml.PauliZ(1))

```

With this breaking change, users must set a value to `argnum` specifying the index of the

batched inputs with respect to all quantum tape parameters. In this example the quantum tape

parameters are `[ weights[0], inputs, weights[1] ]`, thus `argnum` should be set to 1, specifying

that `inputs` is batched:

```

dev = qml.device("default.qubit", wires=2, shots=None)

@qml.batch\_input(argnum=1)

@qml.qnode(dev, diff\_method="parameter-shift", interface="tf")

def circuit(inputs, weights):

    qml.RY(weights[0], wires=0)

    qml.AngleEmbedding(inputs, wires=range(2), rotation="Y")

    qml.RY(weights[1], wires=1)

    return qml.expval(qml.PauliZ(1))

```

* PennyLane now depends on newer versions (>=2.7) of the `semantic\_version` package,

which provides an updated API that is incompatible which versions of the package

prior to 2.7. If you run into issues relating to this package, please reinstall

PennyLane.

[(#2744)](https://github.com/PennyLaneAI/pennylane/pull/2744)

[(#2767)](https://github.com/PennyLaneAI/pennylane/pull/2767)

### Documentation 📕

* Added a dedicated docstring for the `QubitDevice.sample` method.

[(#2812)](https://github.com/PennyLaneAI/pennylane/pull/2812)

* Optimization examples of using JAXopt and Optax with the JAX interface have

been added.

[(#2769)](https://github.com/PennyLaneAI/pennylane/pull/2769)

* Updated IsingXY gate docstring.

[(#2858)](https://github.com/PennyLaneAI/pennylane/pull/2858)

### Bug fixes 🐞

* Fixes `qml.equal` so that operators with different inverse properties are not equal.

[(#2947)](https://github.com/PennyLaneAI/pennylane/pull/2947)

* Cleans up interactions between operator arithmetic and batching by

testing supported cases and adding errors when batching is not supported.

[(#2900)](https://github.com/PennyLaneAI/pennylane/pull/2900)

* Fixed a bug where the parameter-shift rule wasn’t defined for `qml.kUpCCGSD`.

[(#2913)](https://github.com/PennyLaneAI/pennylane/pull/2913)

* Reworked the Hermiticity check in `qml.Hermitian` by using `qml.math` calls

because calling `.conj()` on an `EagerTensor` from TensorFlow raised an

error.

[(#2895)](https://github.com/PennyLaneAI/pennylane/pull/2895)

* Fixed a bug where the parameter-shift gradient breaks when using both

custom `grad\_recipe`s that contain unshifted terms and recipes that

do not contain any unshifted terms.

[(#2834)](https://github.com/PennyLaneAI/pennylane/pull/2834)

* Fixed mixed CPU-GPU data-locality issues for the Torch interface.

[(#2830)](https://github.com/PennyLaneAI/pennylane/pull/2830)

* Fixed a bug where the parameter-shift Hessian of circuits with untrainable

parameters might be computed with respect to the wrong parameters or

might raise an error.

[(#2822)](https://github.com/PennyLaneAI/pennylane/pull/2822)

* Fixed a bug where the custom implementation of the `states\_to\_binary` device

method was not used.

[(#2809)](https://github.com/PennyLaneAI/pennylane/pull/2809)

* `qml.grouping.group\_observables` now works when individual wire

labels are iterable.

[(#2752)](https://github.com/PennyLaneAI/pennylane/pull/2752)

* The adjoint of an adjoint now has a correct `expand` result.

[(#2766)](https://github.com/PennyLaneAI/pennylane/pull/2766)

* Fixed the ability to return custom objects as the expectation value of a QNode with

the Autograd interface.

[(#2808)](https://github.com/PennyLaneAI/pennylane/pull/2808)

* The WireCut operator now raises an error when instantiating it with an empty list.

[(#2826)](https://github.com/PennyLaneAI/pennylane/pull/2826)

* Hamiltonians with grouped observables are now allowed to be measured on devices

which were transformed using `qml.transform.insert()`.

[(#2857)](https://github.com/PennyLaneAI/pennylane/pull/2857)

* Fixed a bug where `qml.batch\_input` raised an error when using a batched operator that was not

located at the beginning of the circuit. In addition, now `qml.batch\_input` raises an error when

using trainable batched inputs, which avoids an unwanted behaviour with duplicated parameters.

[(#2873)](https://github.com/PennyLaneAI/pennylane/pull/2873)

* Calling `qml.equal` with nested operators now raises a `NotImplementedError`.

[(#2877)](https://github.com/PennyLaneAI/pennylane/pull/2877)

* Fixed a bug where a non-sensible error message was raised when using `qml.counts` with `shots=False`.

[(#2928)](https://github.com/PennyLaneAI/pennylane/pull/2928)

* Fixed a bug where no error was raised and a wrong value was returned when using `qml.counts`

with another non-commuting observable.

[(#2928)](https://github.com/PennyLaneAI/pennylane/pull/2928)

* Operator Arithmetic now allows `Hamiltonian` objects to be used and produces correct matrices.

[(#2957)](https://github.com/PennyLaneAI/pennylane/pull/2957)

### Contributors

This release contains contributions from (in alphabetical order):

Juan Miguel Arrazola, Utkarsh Azad, Samuel Banning, Prajwal Borkar, Isaac De Vlugt, Olivia Di Matteo, Kristiyan Dilov,

David Ittah, Josh Izaac, Soran Jahangiri, Edward Jiang, Ankit Khandelwal, Korbinian Kottmann, Meenu Kumari,

Christina Lee, Sergio Martínez-Losa, Albert Mitjans Coma, Ixchel Meza Chavez, Romain Moyard, Lee James O’Riordan,

Mudit Pandey, Bogdan Reznychenko, Shuli Shu, Jay Soni, Modjtaba Shokrian-Zini, Antal Száva, David Wierichs,

Moritz Willmann

orphan

#### Release 0.24.0[¶](#release-0-24-0 "Permalink to this headline")

### New features since last release

#### All new quantum information quantities 📏

* Functionality for computing quantum information quantities for QNodes has been added.

[(#2554)](https://github.com/PennyLaneAI/pennylane/pull/2554)

[(#2569)](https://github.com/PennyLaneAI/pennylane/pull/2569)

[(#2598)](https://github.com/PennyLaneAI/pennylane/pull/2598)

[(#2617)](https://github.com/PennyLaneAI/pennylane/pull/2617)

[(#2631)](https://github.com/PennyLaneAI/pennylane/pull/2631)

[(#2640)](https://github.com/PennyLaneAI/pennylane/pull/2640)

[(#2663)](https://github.com/PennyLaneAI/pennylane/pull/2663)

[(#2684)](https://github.com/PennyLaneAI/pennylane/pull/2684)

[(#2688)](https://github.com/PennyLaneAI/pennylane/pull/2688)

[(#2695)](https://github.com/PennyLaneAI/pennylane/pull/2695)

[(#2710)](https://github.com/PennyLaneAI/pennylane/pull/2710)

[(#2712)](https://github.com/PennyLaneAI/pennylane/pull/2712)

This includes two new QNode measurements:

	+ The [Von Neumann entropy](https://en.wikipedia.org/wiki/Von_Neumann_entropy) via `qml.vn\_entropy`:

	

	

	

	```

	>>> dev = qml.device("default.qubit", wires=2)

	>>> @qml.qnode(dev)

	... def circuit\_entropy(x):

	...     qml.IsingXX(x, wires=[0,1])

	...     return qml.vn\_entropy(wires=[0], log\_base=2)

	>>> circuit\_entropy(np.pi/2)

	1.0

	

	```

	+ The [mutual information](https://en.wikipedia.org/wiki/Quantum_mutual_information) via `qml.mutual\_info`:

	

	

	

	```

	>>> dev = qml.device("default.qubit", wires=2)

	>>> @qml.qnode(dev)

	... def circuit(x):

	...     qml.IsingXX(x, wires=[0,1])

	...     return qml.mutual\_info(wires0=[0], wires1=[1], log\_base=2)

	>>> circuit(np.pi/2)

	2.0

	

	```New differentiable transforms are also available in the `qml.qinfo` module:

	+ The classical and quantum [Fisher information](https://en.wikipedia.org/wiki/Fisher_information) via `qml.qinfo.classical\_fisher`, `qml.qinfo.quantum\_fisher`, respectively:

	

	

	

	```

	dev = qml.device("default.qubit", wires=3)

	

	@qml.qnode(dev)

	def circ(params):

	    qml.RY(params[0], wires=1)

	    qml.CNOT(wires=(1,0))

	    qml.RY(params[1], wires=1)

	    qml.RZ(params[2], wires=1)

	    return qml.expval(qml.PauliX(0) @ qml.PauliX(1) - 0.5 \* qml.PauliZ(1))

	

	params = np.array([0.5, 1., 0.2], requires\_grad=True)

	cfim = qml.qinfo.classical\_fisher(circ)(params)

	qfim = qml.qinfo.quantum\_fisher(circ)(params)

	

	```

	

	

	These quantities are typically employed in variational optimization schemes to tilt the gradient in a more favourable direction — producing what is known as the [natural gradient](https://pennylane.ai/qml/demos/tutorial_quantum_natural_gradient.html). For example:

	

	

	

	```

	>>> grad = qml.grad(circ)(params)

	>>> cfim @ grad  # natural gradient

	[ 5.94225615e-01 -2.61509542e-02 -1.18674655e-18]

	>>> qfim @ grad  # quantum natural gradient

	[ 0.59422561 -0.02615095 -0.03989212]

	

	```

	+ The fidelity between two arbitrary states via `qml.qinfo.fidelity`:

	

	

	

	```

	dev = qml.device('default.qubit', wires=1)

	

	@qml.qnode(dev)

	def circuit\_rx(x):

	    qml.RX(x[0], wires=0)

	    qml.RZ(x[1], wires=0)

	    return qml.state()

	

	@qml.qnode(dev)

	def circuit\_ry(y):

	    qml.RY(y, wires=0)

	    return qml.state()

	

	```

	

	

	

	```

	>>> x = np.array([0.1, 0.3], requires\_grad=True)

	>>> y = np.array(0.2, requires\_grad=True)

	>>> fid\_func = qml.qinfo.fidelity(circuit\_rx, circuit\_ry, wires0=[0], wires1=[0])

	>>> fid\_func(x, y)

	0.9905158135644924

	>>> df = qml.grad(fid\_func)

	>>> df(x, y)

	(array([-0.04768725, -0.29183666]), array(-0.09489803))

	

	```

	+ [Reduced density matrices](https://en.wikipedia.org/wiki/Quantum_entanglement#Reduced_density_matrices) of arbitrary states via `qml.qinfo.reduced\_dm`:

	

	

	

	```

	dev = qml.device("default.qubit", wires=2)

	@qml.qnode(dev)

	def circuit(x):

	    qml.IsingXX(x, wires=[0,1])

	    return qml.state()

	

	```

	

	

	

	```

	>>> qml.qinfo.reduced\_dm(circuit, wires=[0])(np.pi/2)

	[[0.5+0.j 0.+0.j]

	 [0.+0.j 0.5+0.j]]

	

	```

	+ Similar transforms, `qml.qinfo.vn\_entropy` and `qml.qinfo.mutual\_info` exist

	for transforming QNodes.Currently, all quantum information measurements and transforms are differentiable, but only

support statevector devices, with hardware support to come in a future release (with the

exception of `qml.qinfo.classical\_fisher` and `qml.qinfo.quantum\_fisher`, which are both hardware

compatible).

For more information, check out the new [qinfo module](https://pennylane.readthedocs.io/en/stable/code/qml_qinfo.html) and

[measurements page](https://pennylane.readthedocs.io/en/stable/introduction/measurements.html).

* In addition to the QNode transforms and measurements above, functions for computing and

differentiating quantum information metrics with numerical statevectors and density matrices have

been added to the `qml.math` module. This enables flexible custom post-processing.

Added functions include:

	+ `qml.math.reduced\_dm`

	+ `qml.math.vn\_entropy`

	+ `qml.math.mutual\_info`

	+ `qml.math.fidelity`For example:

```

>>> x = torch.tensor([1.0, 0.0, 0.0, 1.0], requires\_grad=True)

>>> en = qml.math.vn\_entropy(x / np.sqrt(2.), indices=[0])

>>> en

tensor(0.6931, dtype=torch.float64, grad\_fn=<DivBackward0>)

>>> en.backward()

>>> x.grad

tensor([-0.3069, 0.0000, 0.0000, -0.3069])

```

#### Faster mixed-state training with backpropagation 📉

* The `default.mixed` device now supports differentiation via backpropagation with the Autograd,

TensorFlow, and PyTorch (CPU) interfaces, leading to significantly more performant optimization

and training.

[(#2615)](https://github.com/PennyLaneAI/pennylane/pull/2615)

[(#2670)](https://github.com/PennyLaneAI/pennylane/pull/2670)

[(#2680)](https://github.com/PennyLaneAI/pennylane/pull/2680)

As a result, the default differentiation method for the device is now `"backprop"`. To continue

using the old default `"parameter-shift"`, explicitly specify this differentiation method in the

QNode:

```

dev = qml.device("default.mixed", wires=2)

@qml.qnode(dev, interface="autograd", diff\_method="backprop")

def circuit(x):

    qml.RY(x, wires=0)

    qml.CNOT(wires=[0, 1])

    return qml.expval(qml.PauliZ(wires=1))

```

```

>>> x = np.array(0.5, requires\_grad=True)

>>> circuit(x)

array(0.87758256)

>>> qml.grad(circuit)(x)

-0.479425538604203

```

#### Support for quantum parameter broadcasting 📡

* Quantum operators, functions, and tapes now support broadcasting across

parameter dimensions, making it more convenient for developers to execute their PennyLane

programs with multiple sets of parameters.

[(#2575)](https://github.com/PennyLaneAI/pennylane/pull/2575)

[(#2609)](https://github.com/PennyLaneAI/pennylane/pull/2609)

Parameter broadcasting refers to passing tensor parameters with additional leading dimensions

to quantum operators; additional dimensions will flow through the computation,

and produce additional dimensions at the output.

For example, instantiating a rotation gate with a one-dimensional array leads to a broadcasted

`Operation`:

```

>>> x = np.array([0.1, 0.2, 0.3], requires\_grad=True)

>>> op = qml.RX(x, 0)

>>> op.batch\_size

3

```

Its matrix correspondingly is augmented by a leading dimension of size `batch\_size`:

```

>>> np.round(qml.matrix(op), 4)

tensor([[[0.9988+0.j , 0. -0.05j ],

 [0. -0.05j , 0.9988+0.j ]],

 [[0.995 +0.j , 0. -0.0998j],

 [0. -0.0998j, 0.995 +0.j ]],

 [[0.9888+0.j , 0. -0.1494j],

 [0. -0.1494j, 0.9888+0.j ]]], requires\_grad=True)

>>> qml.matrix(op).shape

(3, 2, 2)

```

This can be extended to quantum functions, where we may mix-and-match operations

with batched parameters and those without. However, the `batch\_size` of each batched

`Operator` within the quantum function must be the same:

```

>>> dev = qml.device('default.qubit', wires=1)

>>> @qml.qnode(dev)

... def circuit\_rx(x, z):

...     qml.RX(x, wires=0)

...     qml.RZ(z, wires=0)

...     qml.RY(0.3, wires=0)

...     return qml.probs(wires=0)

>>> circuit\_rx([0.1, 0.2], [0.3, 0.4])

tensor([[0.97092256, 0.02907744],

 [0.95671515, 0.04328485]], requires\_grad=True)

```

Parameter broadcasting is supported on all devices, hardware and simulator. Note that

if not natively supported by the underlying device, parameter broadcasting may result

in additional quantum device evaluations.

* A new transform, `qml.transforms.broadcast\_expand`, has been added,

which automates the process of transforming quantum functions (and tapes) to

multiple quantum evaluations with no parameter broadcasting.

[(#2590)](https://github.com/PennyLaneAI/pennylane/pull/2590)

```

>>> dev = qml.device('default.qubit', wires=1)

>>> @qml.transforms.broadcast\_expand()

>>> @qml.qnode(dev)

... def circuit\_rx(x, z):

...     qml.RX(x, wires=0)

...     qml.RZ(z, wires=0)

...     qml.RY(0.3, wires=0)

...     return qml.probs(wires=0)

>>> print(qml.draw(circuit\_rx)([0.1, 0.2], [0.3, 0.4]))

0: ──RX(0.10)──RZ(0.30)──RY(0.30)─┤ Probs

\

0: ──RX(0.20)──RZ(0.40)──RY(0.30)─┤ Probs

```

Under-the-hood, this transform is used for devices that don’t natively support

parameter broadcasting.

* To specify that a device natively supports broadcasted tapes,

the new flag `Device.capabilities()["supports\_broadcasting"]` should be set to `True`.

* To support parameter broadcasting for new or custom operations, the following

new `Operator` class attributes must be specified:

	+ `Operator.ndim\_params` specifies expected number of dimensions for each parameterOnce set, `Operator.batch\_size` and `QuantumTape.batch\_size` will dynamically compute the

parameter broadcasting axis dimension, if present.

#### Improved JAX JIT support 🏎

* JAX just-in-time (JIT) compilation now supports vector-valued QNodes,

enabling new types of workflows and significant performance boosts.

[(#2034)](https://github.com/PennyLaneAI/pennylane/pull/2034)

Vector-valued QNodes include those with:

	+ `qml.probs`;

	+ `qml.state`;

	+ `qml.sample` or

	+ multiple `qml.expval` / `qml.var` measurements.Consider a QNode that returns basis-state probabilities:

```

dev = qml.device('default.qubit', wires=2)

x = jnp.array(0.543)

y = jnp.array(-0.654)

@jax.jit

@qml.qnode(dev, diff\_method="parameter-shift", interface="jax")

def circuit(x, y):

    qml.RX(x, wires=[0])

    qml.RY(y, wires=[1])

    qml.CNOT(wires=[0, 1])

    return qml.probs(wires=[1])

```

```

>>> circuit(x, y)

Array([0.8397495 , 0.16025047], dtype=float32)

```

Note that computing the jacobian of vector-valued QNode is not supported with JAX

JIT. The output of vector-valued QNodes can, however, be used in

the definition of scalar-valued cost functions whose gradients can be

computed.

For example, one can define a cost function that outputs the first element of

the probability vector:

```

def cost(x, y):

    return circuit(x, y)[0]

```

```

>>> jax.grad(cost, argnums=[0])(x, y)

(Array(-0.2050439, dtype=float32),)

```

#### More drawing styles 🎨

* New `solarized\_light` and `solarized\_dark` styles are available for drawing circuit diagram graphics.

[(#2662)](https://github.com/PennyLaneAI/pennylane/pull/2662)

#### New operations & transforms 🤖

* The `qml.IsingXY` gate is now available (see [1912.04424](https://arxiv.org/abs/1912.04424)).

[(#2649)](https://github.com/PennyLaneAI/pennylane/pull/2649)

* The `qml.ECR` (echoed cross-resonance) operation is now available (see

[2105.01063](https://arxiv.org/pdf/2105.01063.pdf)). This gate is a maximally-entangling gate and

is equivalent to a CNOT gate up to single-qubit pre-rotations.

[(#2613)](https://github.com/PennyLaneAI/pennylane/pull/2613)

* The adjoint transform `adjoint` can now accept either a single instantiated operator or a quantum

function. It returns an entity of the same type / call signature as what it was given:

[(#2222)](https://github.com/PennyLaneAI/pennylane/pull/2222)

[(#2672)](https://github.com/PennyLaneAI/pennylane/pull/2672)

```

>>> qml.adjoint(qml.PauliX(0))

Adjoint(PauliX)(wires=[0])

>>> qml.adjoint(qml.RX)(1.23, wires=0)

Adjoint(RX)(1.23, wires=[0])

```

Now, `adjoint` wraps operators in a symbolic operator class `qml.ops.op\_math.Adjoint`. This class

should not be constructed directly; the `adjoint` constructor should always be used instead. The

class behaves just like any other `Operator`:

```

>>> op = qml.adjoint(qml.S(0))

>>> qml.matrix(op)

array([[1.-0.j, 0.-0.j],

 [0.-0.j, 0.-1.j]])

>>> qml.eigvals(op)

array([1.-0.j, 0.-1.j])

```

* A new symbolic operator class `qml.ops.op\_math.Pow` represents an operator raised to a power.

When `decomposition()` is called, a list of new operators equal to this one raised to the given power is given:

[(#2621)](https://github.com/PennyLaneAI/pennylane/pull/2621)

```

>>> op = qml.ops.op\_math.Pow(qml.PauliX(0), 0.5)

>>> op.decomposition()

[SX(wires=[0])]

>>> qml.matrix(op)

array([[0.5+0.5j, 0.5-0.5j],

 [0.5-0.5j, 0.5+0.5j]])

```

* A new transform `qml.batch\_partial` is available which behaves similarly to `functools.partial`,

but supports batching in the unevaluated parameters.

[(#2585)](https://github.com/PennyLaneAI/pennylane/pull/2585)

This is useful for executing a circuit with a batch dimension in some of its parameters:

```

dev = qml.device("default.qubit", wires=1)

@qml.qnode(dev)

def circuit(x, y):

   qml.RX(x, wires=0)

   qml.RY(y, wires=0)

   return qml.expval(qml.PauliZ(wires=0))

```

```

>>> batched\_partial\_circuit = qml.batch\_partial(circuit, x=np.array(np.pi / 4))

>>> y = np.array([0.2, 0.3, 0.4])

>>> batched\_partial\_circuit(y=y)

tensor([0.69301172, 0.67552491, 0.65128847], requires\_grad=True)

```

* A new transform `qml.split\_non\_commuting` is available, which splits a quantum

function or tape into multiple functions/tapes determined by groups of commuting

observables:

[(#2587)](https://github.com/PennyLaneAI/pennylane/pull/2587)

```

dev = qml.device("default.qubit", wires=1)

@qml.transforms.split\_non\_commuting

@qml.qnode(dev)

def circuit(x):

    qml.RX(x,wires=0)

    return [qml.expval(qml.PauliX(0)), qml.expval(qml.PauliZ(0))]

```

```

>>> print(qml.draw(circuit)(0.5))

0: ──RX(0.50)─┤ <X>

\

0: ──RX(0.50)─┤ <Z>

```

### Improvements

* Expectation values of multiple non-commuting observables from within a single QNode are now

supported:

[(#2587)](https://github.com/PennyLaneAI/pennylane/pull/2587)

```

>>> dev = qml.device('default.qubit', wires=1)

>>> @qml.qnode(dev)

... def circuit\_rx(x, z):

...     qml.RX(x, wires=0)

...     qml.RZ(z, wires=0)

...     return qml.expval(qml.PauliX(0)), qml.expval(qml.PauliY(0))

>>> circuit\_rx(0.1, 0.3)

tensor([ 0.02950279, -0.09537451], requires\_grad=True)

```

* Selecting which parts of parameter-shift Hessians are computed is now possible.

[(#2538)](https://github.com/PennyLaneAI/pennylane/pull/2538)

The `argnum` keyword argument for `qml.gradients.param\_shift\_hessian`

is now allowed to be a two-dimensional Boolean `array\_like`.

Only the indicated entries of the Hessian will then be computed.

A particularly useful example is the computation of the diagonal

of the Hessian:

```

dev = qml.device("default.qubit", wires=1)

@qml.qnode(dev)

def circuit(x):

    qml.RX(x[0], wires=0)

    qml.RY(x[1], wires=0)

    qml.RX(x[2], wires=0)

    return qml.expval(qml.PauliZ(0))

argnum = qml.math.eye(3, dtype=bool)

x = np.array([0.2, -0.9, 1.1], requires\_grad=True)

```

```

>>> qml.gradients.param\_shift\_hessian(circuit, argnum=argnum)(x)

tensor([[-0.09928388, 0. , 0. ],

 [ 0. , -0.27633945, 0. ],

 [ 0. , 0. , -0.09928388]], requires\_grad=True)

```

* Commuting Pauli operators are now measured faster.

[(#2425)](https://github.com/PennyLaneAI/pennylane/pull/2425)

The logic that checks for qubit-wise commuting (QWC) observables has been improved, resulting in

a performance boost that is noticable when many commuting Pauli operators of the same type are

measured.

* It is now possible to add `Observable` objects to the integer `0`, for example

`qml.PauliX(wires=[0]) + 0`.

[(#2603)](https://github.com/PennyLaneAI/pennylane/pull/2603)

* Wires can now be passed as the final argument to an `Operator`, instead of requiring the wires to

be explicitly specified with keyword `wires`. This functionality already existed for

`Observable`s, but now extends to all `Operator`s:

[(#2432)](https://github.com/PennyLaneAI/pennylane/pull/2432)

```

>>> qml.S(0)

S(wires=[0])

>>> qml.CNOT((0,1))

CNOT(wires=[0, 1])

```

* The `qml.taper` function can now be used to consistently taper any additional observables such as

dipole moment, particle number, and spin operators using the symmetries obtained from the

Hamiltonian.

[(#2510)](https://github.com/PennyLaneAI/pennylane/pull/2510)

* Sparse Hamiltonians’ representation has changed from Coordinate (COO) to Compressed Sparse Row

(CSR) format.

[(#2561)](https://github.com/PennyLaneAI/pennylane/pull/2561)

The CSR representation is more performant for arithmetic operations and matrix-vector products.

This change decreases the `expval()` calculation time for `qml.SparseHamiltonian`, specially for

large workflows. In addition, the CSR format consumes less memory for `qml.SparseHamiltonian`

storage.

* IPython now displays the `str` representation of a `Hamiltonian`, rather than the `repr`. This

displays more information about the object.

[(#2648)](https://github.com/PennyLaneAI/pennylane/pull/2648)

* The `qml.qchem` tests have been restructured.

[(#2593)](https://github.com/PennyLaneAI/pennylane/pull/2593)

[(#2545)](https://github.com/PennyLaneAI/pennylane/pull/2545)

	+ OpenFermion-dependent tests are now localized and collected in

	`tests.qchem.of\_tests`. The new module `test\_structure` is created to collect the tests of the

	`qchem.structure` module in one place and remove their dependency to OpenFermion.

	+ Test classes have been created to group the integrals and matrices

	unit tests.

* An `operations\_only` argument is introduced to the `tape.get\_parameters` method.

[(#2543)](https://github.com/PennyLaneAI/pennylane/pull/2543)

* The `gradients` module now uses faster subroutines and uniform formats of gradient rules.

[(#2452)](https://github.com/XanaduAI/pennylane/pull/2452)

* Instead of checking types, objects are now processed in the `QuantumTape` based on a new

`\_queue\_category` property. This is a temporary fix that will disappear in the future.

[(#2408)](https://github.com/PennyLaneAI/pennylane/pull/2408)

* The `QNode` class now contains a new method `best\_method\_str` that returns the best

differentiation method for a provided device and interface, in human-readable format.

[(#2533)](https://github.com/PennyLaneAI/pennylane/pull/2533)

* Using `Operation.inv()` in a queuing environment no longer updates the queue’s metadata, but

merely updates the operation in place.

[(#2596)](https://github.com/PennyLaneAI/pennylane/pull/2596)

* A new method `safe\_update\_info` is added to `qml.QueuingContext`. This method is substituted

for `qml.QueuingContext.update\_info` in a variety of places.

[(#2612)](https://github.com/PennyLaneAI/pennylane/pull/2612)

[(#2675)](https://github.com/PennyLaneAI/pennylane/pull/2675)

* `BasisEmbedding` can accept an int as argument instead of a list of bits.

[(#2601)](https://github.com/PennyLaneAI/pennylane/pull/2601)

For example, `qml.BasisEmbedding(4, wires = range(4))` is now equivalent to

`qml.BasisEmbedding([0,1,0,0], wires = range(4))` (as `4==0b100`).

* Introduced a new `is\_hermitian` property to `Operator`s to determine if an operator can be used in a measurement

process.

[(#2629)](https://github.com/PennyLaneAI/pennylane/pull/2629)

* Added separate `requirements\_dev.txt` for separation of concerns for code development and just

using PennyLane.

[(#2635)](https://github.com/PennyLaneAI/pennylane/pull/2635)

* The performance of building sparse Hamiltonians has been improved by accumulating the sparse

representation of coefficient-operator pairs in a temporary storage and by eliminating

unnecessary `kron` operations on identity matrices.

[(#2630)](https://github.com/PennyLaneAI/pennylane/pull/2630)

* Control values are now displayed distinctly in text and matplotlib drawings of circuits.

[(#2668)](https://github.com/PennyLaneAI/pennylane/pull/2668)

* The `TorchLayer` `init\_method` argument now accepts either a `torch.nn.init` function or a

dictionary which should specify a `torch.nn.init`/`torch.Tensor` for each different weight.

[(#2678)](https://github.com/PennyLaneAI/pennylane/pull/2678)

* The unused keyword argument `do\_queue` for `Operation.adjoint` is now fully removed.

[(#2583)](https://github.com/PennyLaneAI/pennylane/pull/2583)

* Several non-decomposable `Adjoint` operators are added to the device test suite.

[(#2658)](https://github.com/PennyLaneAI/pennylane/pull/2658)

* The developer-facing `pow` method has been added to `Operator` with concrete implementations for

many classes.

[(#2225)](https://github.com/PennyLaneAI/pennylane/pull/2225)

* The `ctrl` transform and `ControlledOperation` have been moved to the new `qml.ops.op\_math`

submodule. The developer-facing `ControlledOperation` class is no longer imported top-level.

[(#2656)](https://github.com/PennyLaneAI/pennylane/pull/2656)

### Deprecations

* `qml.ExpvalCost` has been deprecated, and usage will now raise a warning.

[(#2571)](https://github.com/PennyLaneAI/pennylane/pull/2571)

Instead, it is recommended to simply

pass Hamiltonians to the `qml.expval` function inside QNodes:

```

@qml.qnode(dev)

def ansatz(params):

    some\_qfunc(params)

    return qml.expval(Hamiltonian)

```

### Breaking changes

* When using `qml.TorchLayer`, weights with negative shapes will now raise an error, while weights

with `size = 0` will result in creating empty Tensor objects.

[(#2678)](https://github.com/PennyLaneAI/pennylane/pull/2678)

* PennyLane no longer supports TensorFlow `<=2.3`.

[(#2683)](https://github.com/PennyLaneAI/pennylane/pull/2683)

* The `qml.queuing.Queue` class has been removed.

[(#2599)](https://github.com/PennyLaneAI/pennylane/pull/2599)

* The `qml.utils.expand` function is now removed; `qml.operation.expand\_matrix` should be used

instead.

[(#2654)](https://github.com/PennyLaneAI/pennylane/pull/2654)

* The module `qml.gradients.param\_shift\_hessian` has been renamed to

`qml.gradients.parameter\_shift\_hessian` in order to distinguish it from the identically named

function. Note that the `param\_shift\_hessian` function is unaffected by this change and can be

invoked in the same manner as before via the `qml.gradients` module.

[(#2528)](https://github.com/PennyLaneAI/pennylane/pull/2528)

* The properties `eigval` and `matrix` from the `Operator` class were replaced with the methods

`eigval()` and `matrix(wire\_order=None)`.

[(#2498)](https://github.com/PennyLaneAI/pennylane/pull/2498)

* `Operator.decomposition()` is now an instance method, and no longer accepts parameters.

[(#2498)](https://github.com/PennyLaneAI/pennylane/pull/2498)

* Adds tests, adds no-coverage directives, and removes inaccessible logic to improve code coverage.

[(#2537)](https://github.com/PennyLaneAI/pennylane/pull/2537)

* The base classes `QubitDevice` and `DefaultQubit` now accept data-types for a statevector. This

enables a derived class (device) in a plugin to choose correct data-types:

[(#2448)](https://github.com/PennyLaneAI/pennylane/pull/2448)

```

>>> dev = qml.device("default.qubit", wires=4, r\_dtype=np.float32, c\_dtype=np.complex64)

>>> dev.R\_DTYPE

<class 'numpy.float32'>

>>> dev.C\_DTYPE

<class 'numpy.complex64'>

```

### Bug fixes

* Fixed a bug where returning `qml.density\_matrix` using the PyTorch interface would return a

density matrix with wrong shape.

[(#2643)](https://github.com/PennyLaneAI/pennylane/pull/2643)

* Fixed a bug to make `param\_shift\_hessian` work with QNodes in which gates marked

as trainable do not have any impact on the QNode output.

[(#2584)](https://github.com/PennyLaneAI/pennylane/pull/2584)

* QNodes can now interpret variations on the interface name, like `"tensorflow"`

or `"jax-jit"`, when requesting backpropagation.

[(#2591)](https://github.com/PennyLaneAI/pennylane/pull/2591)

* Fixed a bug for `diff\_method="adjoint"` where incorrect gradients were computed for QNodes with

parametrized observables (e.g., `qml.Hermitian`).

[(#2543)](https://github.com/PennyLaneAI/pennylane/pull/2543)

* Fixed a bug where `QNGOptimizer` did not work with operators whose generator was a Hamiltonian.

[(#2524)](https://github.com/PennyLaneAI/pennylane/pull/2524)

* Fixed a bug with the decomposition of `qml.CommutingEvolution`.

[(#2542)](https://github.com/PennyLaneAI/pennylane/pull/2542)

* Fixed a bug enabling PennyLane to work with the latest version of Autoray.

[(#2549)](https://github.com/PennyLaneAI/pennylane/pull/2549)

* Fixed a bug which caused different behaviour for `Hamiltonian @ Observable` and `Observable @

Hamiltonian`.

[(#2570)](https://github.com/PennyLaneAI/pennylane/pull/2570)

* Fixed a bug in `DiagonalQubitUnitary.\_controlled` where an invalid operation was queued instead

of the controlled version of the diagonal unitary.

[(#2525)](https://github.com/PennyLaneAI/pennylane/pull/2525)

* Updated the gradients fix to only apply to the `strawberryfields.gbs` device, since the original

logic was breaking some devices.

[(#2485)](https://github.com/PennyLaneAI/pennylane/pull/2485)

[(#2595)](https://github.com/PennyLaneAI/pennylane/pull/2595)

* Fixed a bug in `qml.transforms.insert` where operations were not inserted after gates within a

template.

[(#2704)](https://github.com/PennyLaneAI/pennylane/pull/2704)

* `Hamiltonian.wires` is now properly updated after in place operations.

[(#2738)](https://github.com/PennyLaneAI/pennylane/pull/2738)

### Documentation

* The centralized [Xanadu Sphinx Theme](https://github.com/XanaduAI/xanadu-sphinx-theme)

is now used to style the Sphinx documentation.

[(#2450)](https://github.com/PennyLaneAI/pennylane/pull/2450)

* Added a reference to `qml.utils.sparse\_hamiltonian` in `qml.SparseHamiltonian` to clarify

how to construct sparse Hamiltonians in PennyLane.

[(2572)](https://github.com/PennyLaneAI/pennylane/pull/2572)

* Added a new section in the [Gradients and Training](https://pennylane.readthedocs.io/en/stable/introduction/interfaces.html)

page that summarizes the supported device configurations and provides justification.

In addition, [code examples](https://pennylane.readthedocs.io/en/stable/introduction/unsupported.html) were added for some selected configurations.

[(#2540)](https://github.com/PennyLaneAI/pennylane/pull/2540)

* Added a note for the [Depolarization Channel](https://pennylane.readthedocs.io/en/stable/code/api/pennylane.DepolarizingChannel.html)

that specifies how the channel behaves for the different values of depolarization probability `p`.

[(#2669)](https://github.com/PennyLaneAI/pennylane/pull/2669)

* The quickstart documentation has been improved.

[(#2530)](https://github.com/PennyLaneAI/pennylane/pull/2530)

[(#2534)](https://github.com/PennyLaneAI/pennylane/pull/2534)

[(#2564](https://github.com/PennyLaneAI/pennylane/pull/2564)

[(#2565](https://github.com/PennyLaneAI/pennylane/pull/2565)

[(#2566)](https://github.com/PennyLaneAI/pennylane/pull/2566)

[(#2607)](https://github.com/PennyLaneAI/pennylane/pull/2607)

[(#2608)](https://github.com/PennyLaneAI/pennylane/pull/2608)

* The quantum chemistry quickstart documentation has been improved.

[(#2500)](https://github.com/PennyLaneAI/pennylane/pull/2500)

* Testing documentation has been improved.

[(#2536)](https://github.com/PennyLaneAI/pennylane/pull/2536)

* Documentation for the `pre-commit` package has been added.

[(#2567)](https://github.com/PennyLaneAI/pennylane/pull/2567)

* Documentation for draw control wires change has been updated.

[(#2682)](https://github.com/PennyLaneAI/pennylane/pull/2682)

### Contributors

This release contains contributions from (in alphabetical order):

Guillermo Alonso-Linaje, Mikhail Andrenkov, Juan Miguel Arrazola, Ali Asadi, Utkarsh Azad, Samuel Banning,

Avani Bhardwaj, Thomas Bromley, Albert Mitjans Coma, Isaac De Vlugt, Amintor Dusko, Trent Fridey, Christian Gogolin,

Qi Hu, Katharine Hyatt, David Ittah, Josh Izaac, Soran Jahangiri, Edward Jiang, Nathan Killoran, Korbinian Kottmann,

Ankit Khandelwal, Christina Lee, Chae-Yeun Park, Mason Moreland, Romain Moyard, Maria Schuld, Jay Soni, Antal Száva,

tal66, David Wierichs, Roeland Wiersema, WingCode.

orphan

#### Release 0.23.1[¶](#release-0-23-1 "Permalink to this headline")

### Bug fixes

* Fixed a bug enabling PennyLane to work with the latest version of Autoray.

[(#2548)](https://github.com/PennyLaneAI/pennylane/pull/2548)

### Contributors

This release contains contributions from (in alphabetical order):

Josh Izaac

orphan

#### Release 0.23.0[¶](#release-0-23-0 "Permalink to this headline")

### New features since last release

####  More powerful circuit cutting ✂️

* Quantum circuit cutting (running `N`-wire circuits on devices with fewer than

`N` wires) is now supported for QNodes of finite-shots using the new

`@qml.cut\_circuit\_mc` transform.

[(#2313)](https://github.com/PennyLaneAI/pennylane/pull/2313)

[(#2321)](https://github.com/PennyLaneAI/pennylane/pull/2321)

[(#2332)](https://github.com/PennyLaneAI/pennylane/pull/2332)

[(#2358)](https://github.com/PennyLaneAI/pennylane/pull/2358)

[(#2382)](https://github.com/PennyLaneAI/pennylane/pull/2382)

[(#2399)](https://github.com/PennyLaneAI/pennylane/pull/2399)

[(#2407)](https://github.com/PennyLaneAI/pennylane/pull/2407)

[(#2444)](https://github.com/PennyLaneAI/pennylane/pull/2444)

With these new additions, samples from the original circuit can be

simulated using a Monte Carlo method, using fewer qubits at the expense of

more device executions. Additionally, this transform can take an optional

classical processing function as an argument and return an expectation

value.

The following `3`-qubit circuit contains a `WireCut` operation and a `sample`

measurement. When decorated with `@qml.cut\_circuit\_mc`, we can cut the circuit

into two `2`-qubit fragments:

```

dev = qml.device("default.qubit", wires=2, shots=1000)

@qml.cut\_circuit\_mc

@qml.qnode(dev)

def circuit(x):

    qml.RX(0.89, wires=0)

    qml.RY(0.5, wires=1)

    qml.RX(1.3, wires=2)

    qml.CNOT(wires=[0, 1])

    qml.WireCut(wires=1)

    qml.CNOT(wires=[1, 2])

    qml.RX(x, wires=0)

    qml.RY(0.7, wires=1)

    qml.RX(2.3, wires=2)

    return qml.sample(wires=[0, 2])

```

we can then execute the circuit as usual by calling the QNode:

```

>>> x = 0.3

>>> circuit(x)

tensor([[1, 1],

 [0, 1],

 [0, 1],

 ...,

 [0, 1],

 [0, 1],

 [0, 1]], requires\_grad=True)

```

Furthermore, the number of shots can be temporarily altered when calling

the QNode:

```

>>> results = circuit(x, shots=123)

>>> results.shape

(123, 2)

```

The `cut\_circuit\_mc` transform also supports returning sample-based

expectation values of observables using the `classical\_processing\_fn`

argument. Refer to the `UsageDetails` section of the [transform

documentation](https://pennylane.readthedocs.io/en/latest/code/api/pennylane.cut_circuit_mc.html)

for an example.

* The `cut\_circuit` transform now supports automatic graph partitioning by

specifying `auto\_cutter=True` to cut arbitrary tape-converted graphs using

the general purpose graph partitioning framework

[KaHyPar](https://pypi.org/project/kahypar/).

[(#2330)](https://github.com/PennyLaneAI/pennylane/pull/2330)

[(#2428)](https://github.com/PennyLaneAI/pennylane/pull/2428)

Note that `KaHyPar` needs to be installed separately with the `auto\_cutter=True` option.

For integration with the existing low-level manual cut pipeline, refer to

the [documentation of the

function](https://pennylane.readthedocs.io/en/latest/code/api/pennylane.transforms.qcut.find_and_place_cuts.html)

.

```

@qml.cut\_circuit(auto\_cutter=True)

@qml.qnode(dev)

def circuit(x):

 qml.RX(x, wires=0)

 qml.RY(0.9, wires=1)

 qml.RX(0.3, wires=2)

 qml.CZ(wires=[0, 1])

 qml.RY(-0.4, wires=0)

 qml.CZ(wires=[1, 2])

 return qml.expval(qml.grouping.string\_to\_pauli\_word("ZZZ"))

```

```

>>> x = np.array(0.531, requires\_grad=True)

>>> circuit(x)

0.47165198882111165

>>> qml.grad(circuit)(x)

-0.276982865449393

```

#### Grand QChem unification ⚛️ 🏰

* Quantum chemistry functionality — previously split between an external

`pennylane-qchem` package and internal `qml.hf` differentiable Hartree-Fock

solver — is now unified into a single, included, `qml.qchem` module.

[(#2164)](https://github.com/PennyLaneAI/pennylane/pull/2164)

[(#2385)](https://github.com/PennyLaneAI/pennylane/pull/2385)

[(#2352)](https://github.com/PennyLaneAI/pennylane/pull/2352)

[(#2420)](https://github.com/PennyLaneAI/pennylane/pull/2420)

[(#2454)](https://github.com/PennyLaneAI/pennylane/pull/2454)  

[(#2199)](https://github.com/PennyLaneAI/pennylane/pull/2199)

[(#2371)](https://github.com/PennyLaneAI/pennylane/pull/2371)

[(#2272)](https://github.com/PennyLaneAI/pennylane/pull/2272)

[(#2230)](https://github.com/PennyLaneAI/pennylane/pull/2230)

[(#2415)](https://github.com/PennyLaneAI/pennylane/pull/2415)

[(#2426)](https://github.com/PennyLaneAI/pennylane/pull/2426)

[(#2465)](https://github.com/PennyLaneAI/pennylane/pull/2465)

The `qml.qchem` module provides a differentiable Hartree-Fock solver and the functionality to

construct a fully-differentiable molecular Hamiltonian.

For example, one can continue to generate molecular Hamiltonians using  

`qml.qchem.molecular\_hamiltonian`:

```

symbols = ["H", "H"]

geometry = np.array([[0., 0., -0.66140414], [0., 0., 0.66140414]])

hamiltonian, qubits = qml.qchem.molecular\_hamiltonian(symbols, geometry, method="dhf")

```

By default, this will use the differentiable Hartree-Fock solver; however, simply set

`method="pyscf"` to continue to use PySCF for Hartree-Fock calculations.

* Functions are added for building a differentiable dipole moment observable. Functions for

computing multipole moment molecular integrals, needed for building the dipole moment observable,

are also added.

[(#2173)](https://github.com/PennyLaneAI/pennylane/pull/2173)

[(#2166)](https://github.com/PennyLaneAI/pennylane/pull/2166)

The dipole moment observable can be constructed using `qml.qchem.dipole\_moment`:

```

symbols  = ['H', 'H']

geometry = np.array([[0.0, 0.0, 0.0], [0.0, 0.0, 1.0]])

mol = qml.qchem.Molecule(symbols, geometry)

args = [geometry]

D = qml.qchem.dipole\_moment(mol)(\*args)

```

* The efficiency of computing molecular integrals and Hamiltonian is improved. This has been done

by adding optimized functions for building fermionic and qubit observables and optimizing

the functions used for computing the electron repulsion integrals.

[(#2316)](https://github.com/PennyLaneAI/pennylane/pull/2316)

* The `6-31G` basis set is added to the qchem basis set repo. This addition allows performing

differentiable Hartree-Fock calculations with basis sets beyond the minimal `sto-3g` basis set

for atoms with atomic number 1-10.

[(#2372)](https://github.com/PennyLaneAI/pennylane/pull/2372)

The `6-31G` basis set can be used to construct a Hamiltonian as

```

symbols = ["H", "H"]

geometry = np.array([[0.0, 0.0, 0.0], [0.0, 0.0, 1.0]])

H, qubits = qml.qchem.molecular\_hamiltonian(symbols, geometry, basis="6-31g")

```

* External dependencies are replaced with local functions for spin and particle number observables.

[(#2197)](https://github.com/PennyLaneAI/pennylane/pull/2197)

[(#2362)](https://github.com/PennyLaneAI/pennylane/pull/2362)

#### Pattern matching optimization 🔎 💎

* Added an optimization transform that matches pieces of user-provided identity

templates in a circuit and replaces them with an equivalent component.

[(#2032)](https://github.com/PennyLaneAI/pennylane/pull/2032)

For example, consider the following circuit where we want to

replace sequence of two `pennylane.S` gates with a

`pennylane.PauliZ` gate.

```

def circuit():

    qml.S(wires=0)

    qml.PauliZ(wires=0)

    qml.S(wires=1)

    qml.CZ(wires=[0, 1])

    qml.S(wires=1)

    qml.S(wires=2)

    qml.CZ(wires=[1, 2])

    qml.S(wires=2)

    return qml.expval(qml.PauliX(wires=0))

```

We specify use the following pattern that implements the identity:

```

with qml.tape.QuantumTape() as pattern:

    qml.S(wires=0)

    qml.S(wires=0)

    qml.PauliZ(wires=0)

```

To optimize the circuit with this identity pattern, we apply the

`qml.transforms.pattern\_matching` transform.

```

>>> dev = qml.device('default.qubit', wires=5)

>>> qnode = qml.QNode(circuit, dev)

>>> optimized\_qfunc = qml.transforms.pattern\_matching\_optimization(pattern\_tapes=[pattern])(circuit)

>>> optimized\_qnode = qml.QNode(optimized\_qfunc, dev)

>>> print(qml.draw(qnode)())

0: ──S──Z─╭C──────────┤ <X>

1: ──S────╰Z──S─╭C────┤

2: ──S──────────╰Z──S─┤

>>> print(qml.draw(optimized\_qnode)())

0: ──S⁻¹─╭C────┤ <X>

1: ──Z───╰Z─╭C─┤

2: ──Z──────╰Z─┤

```

For more details on using pattern matching optimization you can check the

[corresponding

documentation](https://pennylane.readthedocs.io/en/latest/code/api/pennylane.pattern_matching_optimization.html)

and also the following [paper](https://dl.acm.org/doi/full/10.1145/3498325).

#### Measure the distance between two unitaries📏

* Added the `HilbertSchmidt` and the

`LocalHilbertSchmidt` templates to be used for computing distance measures

between unitaries.

[(#2364)](https://github.com/PennyLaneAI/pennylane/pull/2364)

Given a unitary `U`, `qml.HilberSchmidt` can be used to measure the distance

between unitaries and to define a cost function (`cost\_hst`) used for

learning a unitary `V` that is equivalent to `U` up to a global phase:

```

# Represents unitary U

with qml.tape.QuantumTape(do\_queue=False) as u\_tape:

    qml.Hadamard(wires=0)

# Represents unitary V

def v\_function(params):

    qml.RZ(params[0], wires=1)

@qml.qnode(dev)

def hilbert\_test(v\_params, v\_function, v\_wires, u\_tape):

    qml.HilbertSchmidt(v\_params, v\_function=v\_function, v\_wires=v\_wires, u\_tape=u\_tape)

    return qml.probs(u\_tape.wires + v\_wires)

def cost\_hst(parameters, v\_function, v\_wires, u\_tape):

    return (1 - hilbert\_test(v\_params=parameters, v\_function=v\_function, v\_wires=v\_wires, u\_tape=u\_tape)[0])

```

```

>>> cost\_hst(parameters=[0.1], v\_function=v\_function, v\_wires=[1], u\_tape=u\_tape)

tensor(0.999, requires\_grad=True)

```

For more information refer to the [documentation of

qml.HilbertSchmidt](https://pennylane.readthedocs.io/en/latest/code/api/pennylane.HilbertSchmidt.html).

#### More tensor network support 🕸️

* Adds the `qml.MERA` template for implementing quantum circuits with the shape

of a multi-scale entanglement renormalization ansatz (MERA).

[(#2418)](https://github.com/PennyLaneAI/pennylane/pull/2418)

MERA follows the style of previous tensor network templates and is similar to

[quantum convolutional neural networks](https://arxiv.org/abs/1810.03787).

```

def block(weights, wires):

    qml.CNOT(wires=[wires[0],wires[1]])

    qml.RY(weights[0], wires=wires[0])

    qml.RY(weights[1], wires=wires[1])

n\_wires = 4

n\_block\_wires = 2

n\_params\_block = 2

n\_blocks = qml.MERA.get\_n\_blocks(range(n\_wires),n\_block\_wires)

template\_weights = [[0.1,-0.3]]\*n\_blocks

dev= qml.device('default.qubit',wires=range(n\_wires))

@qml.qnode(dev)

def circuit(template\_weights):

    qml.MERA(range(n\_wires),n\_block\_wires,block, n\_params\_block, template\_weights)

    return qml.expval(qml.PauliZ(wires=1))

```

It may be necessary to reorder the wires to see the MERA architecture clearly:

```

>>> print(qml.draw(circuit,expansion\_strategy='device',wire\_order=[2,0,1,3])(template\_weights))

2: ───────────────╭C──RY(0.10)──╭X──RY(-0.30)───────────────┤

0: ─╭X──RY(-0.30)─│─────────────╰C──RY(0.10)──╭C──RY(0.10)──┤

1: ─╰C──RY(0.10)──│─────────────╭X──RY(-0.30)─╰X──RY(-0.30)─┤ <Z>

3: ───────────────╰X──RY(-0.30)─╰C──RY(0.10)────────────────┤

```

#### New transform for transpilation ⚙️

* Added a swap based transpiler transform.

[(#2118)](https://github.com/PennyLaneAI/pennylane/pull/2118)

The transpile function takes a quantum function and a coupling map as inputs

and compiles the circuit to ensure that it can be executed on corresponding

hardware. The transform can be used as a decorator in the following way:

```

dev = qml.device('default.qubit', wires=4)

@qml.qnode(dev)

@qml.transforms.transpile(coupling\_map=[(0, 1), (1, 2), (2, 3)])

def circuit(param):

    qml.CNOT(wires=[0, 1])

    qml.CNOT(wires=[0, 2])

    qml.CNOT(wires=[0, 3])

    qml.PhaseShift(param, wires=0)

    return qml.probs(wires=[0, 1, 2, 3])

```

```

>>> print(qml.draw(circuit)(0.3))

0: ─╭C───────╭C──────────╭C──Rϕ(0.30)─┤ ╭Probs

1: ─╰X─╭SWAP─╰X────╭SWAP─╰X───────────┤ ├Probs

2: ────╰SWAP─╭SWAP─╰SWAP──────────────┤ ├Probs

3: ──────────╰SWAP────────────────────┤ ╰Probs

```

### Improvements

* `QuantumTape` objects are now iterable, allowing iteration over the

contained operations and measurements.

[(#2342)](https://github.com/PennyLaneAI/pennylane/pull/2342)

```

with qml.tape.QuantumTape() as tape:

    qml.RX(0.432, wires=0)

    qml.RY(0.543, wires=0)

    qml.CNOT(wires=[0, 'a'])

    qml.RX(0.133, wires='a')

    qml.expval(qml.PauliZ(wires=[0]))

```

Given a `QuantumTape` object the underlying quantum circuit can be iterated

over using a `for` loop:

```

>>> for op in tape:

...     print(op)

RX(0.432, wires=[0])

RY(0.543, wires=[0])

CNOT(wires=[0, 'a'])

RX(0.133, wires=['a'])

expval(PauliZ(wires=[0]))

```

Indexing into the circuit is also allowed via `tape[i]`:

```

>>> tape[0]

RX(0.432, wires=[0])

```

A tape object can also be converted to a sequence (e.g., to a `list`) of

operations and measurements:

```

>>> list(tape)

[RX(0.432, wires=[0]),

 RY(0.543, wires=[0]),

 CNOT(wires=[0, 'a']),

 RX(0.133, wires=['a']),

 expval(PauliZ(wires=[0]))]

```

* Added the `QuantumTape.shape` method and `QuantumTape.numeric\_type`

attribute to allow extracting information about the shape and numeric type of

the output returned by a quantum tape after execution.

[(#2044)](https://github.com/PennyLaneAI/pennylane/pull/2044)

```

dev = qml.device("default.qubit", wires=2)

a = np.array([0.1, 0.2, 0.3])

def func(a):

    qml.RY(a[0], wires=0)

    qml.RX(a[1], wires=0)

    qml.RY(a[2], wires=0)

with qml.tape.QuantumTape() as tape:

    func(a)

    qml.state()

```

```

>>> tape.shape(dev)

(1, 4)

>>> tape.numeric\_type

complex

```

* Defined a `MeasurementProcess.shape` method and a

`MeasurementProcess.numeric\_type` attribute to allow extracting information

about the shape and numeric type of results obtained when evaluating QNodes

using the specific measurement process.

[(#2044)](https://github.com/PennyLaneAI/pennylane/pull/2044)

* The parameter-shift Hessian can now be computed for arbitrary

operations that support the general parameter-shift rule for

gradients, using `qml.gradients.param\_shift\_hessian`

[(#2319)](https://github.com/XanaduAI/pennylane/pull/2319)

Multiple ways to obtain the

gradient recipe are supported, in the following order of preference:

	+ A custom `grad\_recipe`. It is iterated to obtain the shift rule for

	the second-order derivatives in the diagonal entries of the Hessian.

	+ Custom `parameter\_frequencies`. The second-order shift rule can

	directly be computed using them.

	+ An operation’s `generator`. Its eigenvalues will be used to obtain

	`parameter\_frequencies`, if they are not given explicitly for an operation.

* The strategy for expanding a circuit can now be specified with the

`qml.specs` transform, for example to calculate the specifications of the

circuit that will actually be executed by the device

(`expansion\_strategy="device"`).

[(#2395)](https://github.com/PennyLaneAI/pennylane/pull/2395)

* The `default.qubit` and `default.mixed` devices now skip over identity

operators instead of performing matrix multiplication

with the identity.

[(#2356)](https://github.com/PennyLaneAI/pennylane/pull/2356)

[(#2365)](https://github.com/PennyLaneAI/pennylane/pull/2365)

* The function `qml.eigvals` is modified to use the efficient `scipy.sparse.linalg.eigsh`

method for obtaining the eigenvalues of a `SparseHamiltonian`. This `scipy` method is called

to compute \(k\) eigenvalues of a sparse \(N \times N\) matrix if `k` is smaller

than \(N-1\). If a larger \(k\) is requested, the dense matrix representation of

the Hamiltonian is constructed and the regular `qml.math.linalg.eigvalsh` is applied.

[(#2333)](https://github.com/PennyLaneAI/pennylane/pull/2333)

* The function `qml.ctrl` was given the optional argument `control\_values=None`.

If overridden, `control\_values` takes an integer or a list of integers corresponding to

the binary value that each control value should take. The same change is reflected in

`ControlledOperation`. Control values of `0` are implemented by `qml.PauliX` applied

before and after the controlled operation

[(#2288)](https://github.com/PennyLaneAI/pennylane/pull/2288)

* Operators now have a `has\_matrix` property denoting whether or not the operator defines a matrix.

[(#2331)](https://github.com/PennyLaneAI/pennylane/pull/2331)

[(#2476)](https://github.com/PennyLaneAI/pennylane/pull/2476)

* Circuit cutting now performs expansion to search for wire cuts in contained operations or tapes.

[(#2340)](https://github.com/PennyLaneAI/pennylane/pull/2340)

* The `qml.draw` and `qml.draw\_mpl` transforms are now located in the `drawer` module. They can still be

accessed via the top-level `qml` namespace.

[(#2396)](https://github.com/PennyLaneAI/pennylane/pull/2396)

* Raise a warning where caching produces identical shot noise on execution results with finite shots.

[(#2478)](https://github.com/PennyLaneAI/pennylane/pull/2478)

### Deprecations

* The `ObservableReturnTypes` `Sample`, `Variance`, `Expectation`, `Probability`, `State`, and `MidMeasure`

have been moved to `measurements` from `operation`.

[(#2329)](https://github.com/PennyLaneAI/pennylane/pull/2329)

[(#2481)](https://github.com/PennyLaneAI/pennylane/pull/2481)

### Breaking changes

* The caching ability of devices has been removed. Using the caching on

the QNode level is the recommended alternative going forward.

[(#2443)](https://github.com/PennyLaneAI/pennylane/pull/2443)

One way for replicating the removed `QubitDevice` caching behaviour is by

creating a `cache` object (e.g., a dictionary) and passing it to the `QNode`:

```

n\_wires = 4

wires = range(n\_wires)

dev = qml.device('default.qubit', wires=n\_wires)

cache = {}

@qml.qnode(dev, diff\_method='parameter-shift', cache=cache)

def expval\_circuit(params):

    qml.templates.BasicEntanglerLayers(params, wires=wires, rotation=qml.RX)

    return qml.expval(qml.PauliZ(0) @ qml.PauliY(1) @ qml.PauliX(2) @ qml.PauliZ(3))

shape = qml.templates.BasicEntanglerLayers.shape(5, n\_wires)

params = np.random.random(shape)

```

```

>>> expval\_circuit(params)

tensor(0.20598436, requires\_grad=True)

>>> dev.num\_executions

1

>>> expval\_circuit(params)

tensor(0.20598436, requires\_grad=True)

>>> dev.num\_executions

1

```

* The `qml.finite\_diff` function has been removed. Please use `qml.gradients.finite\_diff` to compute

the gradient of tapes of QNodes. Otherwise, manual implementation is required.

[(#2464)](https://github.com/PennyLaneAI/pennylane/pull/2464)

* The `get\_unitary\_matrix` transform has been removed, please use

`qml.matrix` instead.

[(#2457)](https://github.com/PennyLaneAI/pennylane/pull/2457)

* The `update\_stepsize` method has been removed from `GradientDescentOptimizer` and its child

optimizers. The `stepsize` property can be interacted with directly instead.

[(#2370)](https://github.com/PennyLaneAI/pennylane/pull/2370)

* Most optimizers no longer flatten and unflatten arguments during computation. Due to this change, user

provided gradient functions *must* return the same shape as `qml.grad`.

[(#2381)](https://github.com/PennyLaneAI/pennylane/pull/2381)

* The old circuit text drawing infrastructure has been removed.

[(#2310)](https://github.com/PennyLaneAI/pennylane/pull/2310)

	+ `RepresentationResolver` was replaced by the `Operator.label` method.

	+ `qml.drawer.CircuitDrawer` was replaced by `qml.drawer.tape\_text`.

	+ `qml.drawer.CHARSETS` was removed because unicode is assumed to be accessible.

	+ `Grid` and `qml.drawer.drawable\_grid` were removed because the custom data class was replaced

	by list of sets of operators or measurements.

	+ `qml.transforms.draw\_old` was replaced by `qml.draw`.

	+ `qml.CircuitGraph.greedy\_layers` was deleted, as it was no longer needed by the circuit drawer and

	did not seem to have uses outside of that situation.

	+ `qml.CircuitGraph.draw` was deleted, as we draw tapes instead.

	+ The tape method `qml.tape.QuantumTape.draw` now simply calls `qml.drawer.tape\_text`.

	+ In the new pathway, the `charset` keyword was deleted, the `max\_length` keyword defaults to `100`, and

	the `decimals` and `show\_matrices` keywords were added.

* The deprecated QNode, available via `qml.qnode\_old.QNode`, has been removed. Please

transition to using the standard `qml.QNode`.

[(#2336)](https://github.com/PennyLaneAI/pennylane/pull/2336)

[(#2337)](https://github.com/PennyLaneAI/pennylane/pull/2337)

[(#2338)](https://github.com/PennyLaneAI/pennylane/pull/2338)

In addition, several other components which powered the deprecated QNode have been removed:

	+ The deprecated, non-batch compatible interfaces, have been removed.

	+ The deprecated tape subclasses `QubitParamShiftTape`, `JacobianTape`, `CVParamShiftTape`, and

	`ReversibleTape` have been removed.

* The deprecated tape execution method `tape.execute(device)` has been removed. Please use

`qml.execute([tape], device)` instead.

[(#2339)](https://github.com/PennyLaneAI/pennylane/pull/2339)

### Bug fixes

* Fixed a bug in the `qml.PauliRot` operation, where computing the generator was

not taking into account the operation wires.

[(#2466)](https://github.com/PennyLaneAI/pennylane/pull/2466)

* Fixed a bug where non-trainable arguments were shifted in the `NesterovMomentumOptimizer`

if a trainable argument was after it in the argument list.

[(#2466)](https://github.com/PennyLaneAI/pennylane/pull/2466)

* Fixed a bug with `@jax.jit` for grad when `diff\_method="adjoint"` and `mode="backward"`.

[(#2460)](https://github.com/PennyLaneAI/pennylane/pull/2460)

* Fixed a bug where `qml.DiagonalQubitUnitary` did not support `@jax.jit`

and `@tf.function`.

[(#2445)](https://github.com/PennyLaneAI/pennylane/pull/2445)

* Fixed a bug in the `qml.PauliRot` operation, where computing the generator was not taking into

account the operation wires.

[(#2442)](https://github.com/PennyLaneAI/pennylane/pull/2442)

* Fixed a bug with the padding capability of `AmplitudeEmbedding` where the

inputs are on the GPU.

[(#2431)](https://github.com/PennyLaneAI/pennylane/pull/2431)

* Fixed a bug by adding a comprehensible error message for calling `qml.probs`

without passing wires or an observable.

[(#2438)](https://github.com/PennyLaneAI/pennylane/pull/2438)

* The behaviour of `qml.about()` was modified to avoid warnings being emitted

due to legacy behaviour of `pip`.

[(#2422)](https://github.com/PennyLaneAI/pennylane/pull/2422)

* Fixed a bug where observables were not considered when determining the use of

the `jax-jit` interface.

[(#2427)](https://github.com/PennyLaneAI/pennylane/pull/2427)

[(#2474)](https://github.com/PennyLaneAI/pennylane/pull/2474)

* Fixed a bug where computing statistics for a relatively few number of shots

(e.g., `shots=10`), an error arose due to indexing into an array using a

`Array`.

[(#2427)](https://github.com/PennyLaneAI/pennylane/pull/2427)

* PennyLane Lightning version in Docker container is pulled from latest wheel-builds.

[(#2416)](https://github.com/PennyLaneAI/pennylane/pull/2416)

* Optimizers only consider a variable trainable if they have `requires\_grad = True`.

[(#2381)](https://github.com/PennyLaneAI/pennylane/pull/2381)

* Fixed a bug with `qml.expval`, `qml.var`, `qml.state` and

`qml.probs` (when `qml.probs` is the only measurement) where the `dtype`

specified on the device did not match the `dtype` of the QNode output.

[(#2367)](https://github.com/PennyLaneAI/pennylane/pull/2367)

* Fixed a bug where the output shapes from batch transforms are inconsistent

with the QNode output shape.

[(#2215)](https://github.com/PennyLaneAI/pennylane/pull/2215)

* Fixed a bug caused by the squeezing in `qml.gradients.param\_shift\_hessian`.

[(#2215)](https://github.com/PennyLaneAI/pennylane/pull/2215)

* Fixed a bug in which the `expval`/`var` of a `Tensor(Observable)` would depend on the order

in which the observable is defined:

[(#2276)](https://github.com/PennyLaneAI/pennylane/pull/2276)

```

>>> @qml.qnode(dev)

... def circ(op):

...   qml.RX(0.12, wires=0)

...   qml.RX(1.34, wires=1)

...   qml.RX(3.67, wires=2)

...   return qml.expval(op)

>>> op1 = qml.Identity(wires=0) @ qml.Identity(wires=1) @ qml.PauliZ(wires=2)

>>> op2 = qml.PauliZ(wires=2) @ qml.Identity(wires=0) @ qml.Identity(wires=1)

>>> print(circ(op1), circ(op2))

-0.8636111153905662 -0.8636111153905662

```

* Fixed a bug where `qml.hf.transform\_hf()` would fail due to missing wires in

the qubit operator that is prepared for tapering the HF state.

[(#2441)](https://github.com/PennyLaneAI/pennylane/pull/2441)

* Fixed a bug with custom device defined jacobians not being returned properly.

[(#2485)](https://github.com/PennyLaneAI/pennylane/pull/2485)

### Documentation

* The sections on adding operator and observable support in the “How to add a

plugin” section of the plugins page have been updated.

[(#2389)](https://github.com/PennyLaneAI/pennylane/pull/2389)

* The missing arXiv reference in the `LieAlgebra` optimizer has been fixed.

[(#2325)](https://github.com/PennyLaneAI/pennylane/pull/2325)

### Contributors

This release contains contributions from (in alphabetical order):

Karim Alaa El-Din, Guillermo Alonso-Linaje, Juan Miguel Arrazola, Ali Asadi,

Utkarsh Azad, Sam Banning, Thomas Bromley, Alain Delgado, Isaac De Vlugt,

Olivia Di Matteo, Amintor Dusko, Anthony Hayes, David Ittah, Josh Izaac, Soran

Jahangiri, Nathan Killoran, Christina Lee, Angus Lowe, Romain Moyard, Zeyue

Niu, Matthew Silverman, Lee James O’Riordan, Maria Schuld, Jay Soni, Antal

Száva, Maurice Weber, David Wierichs.

orphan

#### Release 0.22.2[¶](#release-0-22-2 "Permalink to this headline")

### Bug fixes

* Most compilation transforms, and relevant subroutines, have been updated to

support just-in-time compilation with jax.jit. This fix was intended to be

included in `v0.22.0`, but due to a bug was incomplete.

[(#2397)](https://github.com/PennyLaneAI/pennylane/pull/2397)

### Documentation

* The documentation run has been updated to require `jinja2==3.0.3` due to an

issue that arises with `jinja2` `v3.1.0` and `sphinx` `v3.5.3`.

[(#2378)](https://github.com/PennyLaneAI/pennylane/pull/2378)

### Contributors

This release contains contributions from (in alphabetical order):

Olivia Di Matteo, Christina Lee, Romain Moyard, Antal Száva.

orphan

#### Release 0.22.1[¶](#release-0-22-1 "Permalink to this headline")

### Bug fixes

* Fixes cases with `qml.measure` where unexpected operations were added to the

circuit.

[(#2328)](https://github.com/PennyLaneAI/pennylane/pull/2328)

### Contributors

This release contains contributions from (in alphabetical order):

Guillermo Alonso-Linaje, Antal Száva.

orphan

#### Release 0.22.0[¶](#release-0-22-0 "Permalink to this headline")

### New features since last release

#### Quantum circuit cutting ✂️

* You can now run `N`-wire circuits on devices with fewer than `N` wires, by

strategically placing `WireCut` operations that allow their circuit to be

partitioned into smaller fragments, at a cost of needing to perform a greater

number of device executions. Circuit cutting is enabled by decorating a QNode

with the `@qml.cut\_circuit` transform.

[(#2107)](https://github.com/PennyLaneAI/pennylane/pull/2107)

[(#2124)](https://github.com/PennyLaneAI/pennylane/pull/2124)

[(#2153)](https://github.com/PennyLaneAI/pennylane/pull/2153)

[(#2165)](https://github.com/PennyLaneAI/pennylane/pull/2165)

[(#2158)](https://github.com/PennyLaneAI/pennylane/pull/2158)

[(#2169)](https://github.com/PennyLaneAI/pennylane/pull/2169)

[(#2192)](https://github.com/PennyLaneAI/pennylane/pull/2192)

[(#2216)](https://github.com/PennyLaneAI/pennylane/pull/2216)

[(#2168)](https://github.com/PennyLaneAI/pennylane/pull/2168)

[(#2223)](https://github.com/PennyLaneAI/pennylane/pull/2223)

[(#2231)](https://github.com/PennyLaneAI/pennylane/pull/2231)

[(#2234)](https://github.com/PennyLaneAI/pennylane/pull/2234)

[(#2244)](https://github.com/PennyLaneAI/pennylane/pull/2244)

[(#2251)](https://github.com/PennyLaneAI/pennylane/pull/2251)

[(#2265)](https://github.com/PennyLaneAI/pennylane/pull/2265)

[(#2254)](https://github.com/PennyLaneAI/pennylane/pull/2254)

[(#2260)](https://github.com/PennyLaneAI/pennylane/pull/2260)

[(#2257)](https://github.com/PennyLaneAI/pennylane/pull/2257)

[(#2279)](https://github.com/PennyLaneAI/pennylane/pull/2279)

The example below shows how a three-wire circuit can be run on a two-wire device:

```

dev = qml.device("default.qubit", wires=2)

@qml.cut\_circuit

@qml.qnode(dev)

def circuit(x):

    qml.RX(x, wires=0)

    qml.RY(0.9, wires=1)

    qml.RX(0.3, wires=2)

    qml.CZ(wires=[0, 1])

    qml.RY(-0.4, wires=0)

    qml.WireCut(wires=1)

    qml.CZ(wires=[1, 2])

    return qml.expval(qml.grouping.string\_to\_pauli\_word("ZZZ"))

```

Instead of executing the circuit directly, it will be partitioned into smaller fragments

according to the `WireCut` locations, and each fragment executed multiple times. Combining the

results of the fragment executions will recover the expected output of the original uncut circuit.

```

>>> x = np.array(0.531, requires\_grad=True)

>>> circuit(0.531)

0.47165198882111165

```

Circuit cutting support is also differentiable:

```

>>> qml.grad(circuit)(x)

-0.276982865449393

```

For more details on circuit cutting, check out the

[qml.cut\_circuit](https://pennylane.readthedocs.io/en/latest/code/api/pennylane.cut_circuit.html)

documentation page or [Peng et. al](https://arxiv.org/abs/1904.00102).

#### Conditional operations: quantum teleportation unlocked 🔓🌀

* Support for mid-circuit measurements and conditional operations

has been added, to enable use cases like quantum teleportation, quantum error

correction and quantum error mitigation.

[(#2211)](https://github.com/PennyLaneAI/pennylane/pull/2211)

[(#2236)](https://github.com/PennyLaneAI/pennylane/pull/2236)

[(#2275)](https://github.com/PennyLaneAI/pennylane/pull/2275)

Two new functions have been added to support this capability:

	+ `qml.measure()` places mid-circuit measurements in the middle of a quantum function.

	+ `qml.cond()` allows operations and quantum functions to be conditioned on the result of a

	previous measurement.For example, the code below shows how to teleport a qubit from wire 0 to wire 2:

```

dev = qml.device("default.qubit", wires=3)

input\_state = np.array([1, -1], requires\_grad=False) / np.sqrt(2)

@qml.qnode(dev)

def teleport(state):

    # Prepare input state

    qml.QubitStateVector(state, wires=0)

    # Prepare Bell state

    qml.Hadamard(wires=1)

    qml.CNOT(wires=[1, 2])

    # Apply gates

    qml.CNOT(wires=[0, 1])

    qml.Hadamard(wires=0)

    # Measure first two wires

    m1 = qml.measure(0)

    m2 = qml.measure(1)

    # Condition final wire on results

    qml.cond(m2 == 1, qml.PauliX)(wires=2)

    qml.cond(m1 == 1, qml.PauliZ)(wires=2)

    # Return state on final wire

    return qml.density\_matrix(wires=2)

```

We can double-check that the qubit has been teleported by computing the

overlap between the input state and the resulting state on wire 2:

```

>>> output\_state = teleport(input\_state)

>>> output\_state

tensor([[ 0.5+0.j, -0.5+0.j],

 [-0.5+0.j, 0.5+0.j]], requires\_grad=True)

>>> input\_state.conj() @ output\_state @ input\_state

tensor(1.+0.j, requires\_grad=True)

```

For a full description of new capabilities, refer to the [Mid-circuit

measurements and conditional

operations](https://pennylane.readthedocs.io/en/latest/introduction/measurements.html#mid-circuit-measurements-and-conditional-operations)

section in the documentation.

* Train mid-circuit measurements by deferring them, via the new

`@qml.defer\_measurements` transform.

[(#2211)](https://github.com/PennyLaneAI/pennylane/pull/2211)

[(#2236)](https://github.com/PennyLaneAI/pennylane/pull/2236)

[(#2275)](https://github.com/PennyLaneAI/pennylane/pull/2275)

If a device doesn’t natively support mid-circuit measurements, the `@qml.defer\_measurements`

transform can be applied to the QNode to transform the QNode into one with *terminal* measurements

and *controlled* operations:

```

dev = qml.device("default.qubit", wires=2)

@qml.qnode(dev)

@qml.defer\_measurements

def circuit(x):

    qml.Hadamard(wires=0)

    m = qml.measure(0)

    def op\_if\_true():

        return qml.RX(x\*\*2, wires=1)

    def op\_if\_false():

        return qml.RY(x, wires=1)

    qml.cond(m==1, op\_if\_true, op\_if\_false)()

    return qml.expval(qml.PauliZ(1))

```

```

>>> x = np.array(0.7, requires\_grad=True)

>>> print(qml.draw(circuit, expansion\_strategy="device")(x))

0: ──H─╭C─────────X─╭C─────────X─┤

1: ────╰RX(0.49)────╰RY(0.70)────┤ <Z>

>>> circuit(x)

tensor(0.82358752, requires\_grad=True)

```

Deferring mid-circuit measurements also enables differentiation:

```

>>> qml.grad(circuit)(x)

-0.651546965338656

```

#### Debug with mid-circuit quantum snapshots 📷

* A new operation `qml.Snapshot` has been added to assist in debugging quantum functions.

[(#2233)](https://github.com/PennyLaneAI/pennylane/pull/2233)

[(#2289)](https://github.com/PennyLaneAI/pennylane/pull/2289)

[(#2291)](https://github.com/PennyLaneAI/pennylane/pull/2291)

[(#2315)](https://github.com/PennyLaneAI/pennylane/pull/2315)

`qml.Snapshot` saves the internal state of devices at arbitrary points of execution.

Currently supported devices include:

	+ `default.qubit`: each snapshot saves the quantum state vector

	+ `default.mixed`: each snapshot saves the density matrix

	+ `default.gaussian`: each snapshot saves the covariance matrix and vector of meansDuring normal execution, the snapshots are ignored:

```

dev = qml.device("default.qubit", wires=2)

@qml.qnode(dev, interface=None)

def circuit():

    qml.Snapshot()

    qml.Hadamard(wires=0)

    qml.Snapshot("very\_important\_state")

    qml.CNOT(wires=[0, 1])

    qml.Snapshot()

    return qml.expval(qml.PauliX(0))

```

However, when using the `qml.snapshots`

transform, intermediate device states will be stored and returned alongside the

results.

```

>>> qml.snapshots(circuit)()

{0: array([1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j]),

 'very\_important\_state': array([0.70710678+0.j, 0. +0.j, 0.70710678+0.j, 0. +0.j]),

 2: array([0.70710678+0.j, 0. +0.j, 0. +0.j, 0.70710678+0.j]),

 'execution\_results': array(0.)}

```

#### Batch embedding and state preparation data 📦

* Added the `@qml.batch\_input` transform to enable batching non-trainable gate parameters.

In addition, the `qml.qnn.KerasLayer` class has been updated to natively support

batched training data.

[(#2069)](https://github.com/PennyLaneAI/pennylane/pull/2069)

As with other transforms, `@qml.batch\_input` can be used to decorate QNodes:

```

dev = qml.device("default.qubit", wires=2, shots=None)

@qml.batch\_input(argnum=0)

@qml.qnode(dev, diff\_method="parameter-shift", interface="tf")

def circuit(inputs, weights):

    # add a batch dimension to the embedding data

    qml.AngleEmbedding(inputs, wires=range(2), rotation="Y")

    qml.RY(weights[0], wires=0)

    qml.RY(weights[1], wires=1)

    return qml.expval(qml.PauliZ(1))

```

Batched input parameters can then be passed during QNode evaluation:

```

>>> x = tf.random.uniform((10, 2), 0, 1)

>>> w = tf.random.uniform((2,), 0, 1)

>>> circuit(x, w)

<tf.Tensor: shape=(10,), dtype=float64, numpy=

array([0.46230079, 0.73971315, 0.95666004, 0.5355225 , 0.66180948,

 0.44519553, 0.93874261, 0.9483197 , 0.78737918, 0.90866411])>

```

#### Even more mighty quantum transforms 🐛➡🦋

* New functions and transforms of operators have been added:

	+ `qml.matrix()` for computing the matrix representation of one or more unitary operators.

	[(#2241)](https://github.com/PennyLaneAI/pennylane/pull/2241)

	+ `qml.eigvals()` for computing the eigenvalues of one or more operators.

	[(#2248)](https://github.com/PennyLaneAI/pennylane/pull/2248)

	+ `qml.generator()` for computing the generator of a single-parameter unitary operation.

	[(#2256)](https://github.com/PennyLaneAI/pennylane/pull/2256)All operator transforms can be used on instantiated operators,

```

>>> op = qml.RX(0.54, wires=0)

>>> qml.matrix(op)

[[0.9637709+0.j 0. -0.26673144j]

[0. -0.26673144j 0.9637709+0.j ]]

```

Operator transforms can also be used in a functional form:

```

>>> x = torch.tensor(0.6, requires\_grad=True)

>>> matrix\_fn = qml.matrix(qml.RX)

>>> matrix\_fn(x, wires=[0])

tensor([[0.9553+0.0000j, 0.0000-0.2955j],

 [0.0000-0.2955j, 0.9553+0.0000j]], grad\_fn=<AddBackward0>)

```

In its functional form, it is fully differentiable with respect to gate arguments:

```

>>> loss = torch.real(torch.trace(matrix\_fn(x, wires=0)))

>>> loss.backward()

>>> x.grad

tensor(-0.2955)

```

Some operator transform can also act on multiple operations, by passing

quantum functions or tapes:

```

>>> def circuit(theta):

...     qml.RX(theta, wires=1)

...     qml.PauliZ(wires=0)

>>> qml.matrix(circuit)(np.pi / 4)

array([[ 0.92387953+0.j, 0.+0.j , 0.-0.38268343j, 0.+0.j],

[ 0.+0.j, -0.92387953+0.j, 0.+0.j, 0. +0.38268343j],

[ 0. -0.38268343j, 0.+0.j, 0.92387953+0.j, 0.+0.j],

[ 0.+0.j, 0.+0.38268343j, 0.+0.j, -0.92387953+0.j]])

```

* A new transform has been added to construct the pairwise-commutation directed acyclic graph (DAG)

representation of a quantum circuit.

[(#1712)](https://github.com/PennyLaneAI/pennylane/pull/1712)

In the DAG, each node represents a quantum operation, and edges represent non-commutation

between two operations.

This transform takes into account that not all operations can be moved next to each other by

pairwise commutation:

```

>>> def circuit(x, y, z):

...     qml.RX(x, wires=0)

...     qml.RX(y, wires=0)

...     qml.CNOT(wires=[1, 2])

...     qml.RY(y, wires=1)

...     qml.Hadamard(wires=2)

...     qml.CRZ(z, wires=[2, 0])

...     qml.RY(-y, wires=1)

...     return qml.expval(qml.PauliZ(0))

>>> dag\_fn = qml.commutation\_dag(circuit)

>>> dag = dag\_fn(np.pi / 4, np.pi / 3, np.pi / 2)

```

Nodes in the commutation DAG can be accessed via the `get\_nodes()` method, returning a list of

the form `(ID, CommutationDAGNode)`:

```

>>> nodes = dag.get\_nodes()

>>> nodes

NodeDataView({0: <pennylane.transforms.commutation\_dag.CommutationDAGNode object at 0x7f461c4bb580>, ...}, data='node')

```

Specific nodes in the commutation DAG can be accessed via the `get\_node()` method:

```

>>> second\_node = dag.get\_node(2)

>>> second\_node

<pennylane.transforms.commutation\_dag.CommutationDAGNode object at 0x136f8c4c0>

>>> second\_node.op

CNOT(wires=[1, 2])

>>> second\_node.successors

[3, 4, 5, 6]

>>> second\_node.predecessors

[]

```

### Improvements

* The text-based drawer accessed via `qml.draw()` has been optimized and improved.

[(#2128)](https://github.com/PennyLaneAI/pennylane/pull/2128)

[(#2198)](https://github.com/PennyLaneAI/pennylane/pull/2198)

The new drawer has:

	+ a `decimals` keyword for controlling parameter rounding

	+ a `show\_matrices` keyword for controlling display of matrices

	+ a different algorithm for determining positions

	+ deprecation of the `charset` keyword

	+ additional minor cosmetic changes

```

@qml.qnode(qml.device('lightning.qubit', wires=2))

def circuit(a, w):

    qml.Hadamard(0)

    qml.CRX(a, wires=[0, 1])

    qml.Rot(\*w, wires=[1])

    qml.CRX(-a, wires=[0, 1])

    return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1))

```

```

>>> print(qml.draw(circuit, decimals=2)(a=2.3, w=[1.2, 3.2, 0.7]))

0: ──H─╭C─────────────────────────────╭C─────────┤ ╭<Z@Z>

1: ────╰RX(2.30)──Rot(1.20,3.20,0.70)─╰RX(-2.30)─┤ ╰<Z@Z>

```

* The frequencies of gate parameters are now accessible as an operation

property and can be used for circuit analysis, optimization via the

`RotosolveOptimizer` and differentiation with the parameter-shift rule

(including the general shift rule).

[(#2180)](https://github.com/PennyLaneAI/pennylane/pull/2180)

[(#2182)](https://github.com/PennyLaneAI/pennylane/pull/2182)

[(#2227)](https://github.com/PennyLaneAI/pennylane/pull/2227)

```

>>> op = qml.CRot(0.4, 0.1, 0.3, wires=[0, 1])

>>> op.parameter\_frequencies

[(0.5, 1.0), (0.5, 1.0), (0.5, 1.0)]

```

When using `qml.gradients.param\_shift`, either a custom `grad\_recipe` or the

parameter frequencies are used to obtain the shift rule for the operation, in

that order of preference.

See [Vidal and Theis (2018)](https://arxiv.org/abs/1812.06323) and [Wierichs

et al. (2021)](https://arxiv.org/abs/2107.12390) for theoretical background

information on the general parameter-shift rule.

* No two-term parameter-shift rule is assumed anymore by default.

[(#2227)](https://github.com/PennyLaneAI/pennylane/pull/2227)

Previously, operations marked for analytic differentiation that

did not provide a `generator`, `parameter\_frequencies` or a

custom `grad\_recipe` were assumed to satisfy the two-term shift

rule. This now has to be made explicit for custom operations

by adding any of the above attributes.

* Most compilation transforms, and relevant subroutines, have been updated to

support just-in-time compilation with `jax.jit`.

[(#1894)](https://github.com/PennyLaneAI/pennylane/pull/1894/)

* The `qml.draw\_mpl` transform supports a `expansion\_strategy` keyword argument.

[(#2271)](https://github.com/PennyLaneAI/pennylane/pull/2271/)

* The `qml.gradients` module has been streamlined and special-purpose functions

moved closer to their use cases, while preserving existing behaviour.

[(#2200)](https://github.com/PennyLaneAI/pennylane/pull/2200)

* Added a new `partition\_pauli\_group` function to the `grouping` module for

efficiently measuring the `N`-qubit Pauli group with `3 \*\* N`

qubit-wise commuting terms.

[(#2185)](https://github.com/PennyLaneAI/pennylane/pull/2185)

* The Operator class has undergone a major refactor with the following changes:

	+ **Matrices**: the static method `Operator.compute\_matrices()` defines the matrix representation

	of the operator, and the function `qml.matrix(op)` computes this for a given

	instance.

	[(#1996)](https://github.com/PennyLaneAI/pennylane/pull/1996)

	+ **Eigvals**: the static method `Operator.compute\_eigvals()` defines the matrix representation

	of the operator, and the function `qml.eigvals(op)` computes this for a given

	instance.

	[(#2048)](https://github.com/PennyLaneAI/pennylane/pull/2048)

	+ **Decompositions**: the static method `Operator.compute\_decomposition()` defines the matrix representation

	of the operator, and the method `op.decomposition()` computes this for a given

	instance.

	[(#2024)](https://github.com/PennyLaneAI/pennylane/pull/2024)

	[(#2053)](https://github.com/PennyLaneAI/pennylane/pull/2053)

	+ **Sparse matrices**: the static method `Operator.compute\_sparse\_matrix()` defines the sparse

	matrix representation of the operator, and the method `op.sparse\_matrix()` computes this for a

	given instance.

	[(#2050)](https://github.com/PennyLaneAI/pennylane/pull/2050)

	+ **Linear combinations of operators**: The static method `compute\_terms()`, used for representing

	the linear combination of coefficients and operators representing the operator, has been added.

	The method `op.terms()` computes this for a given instance.

	Currently, only the `Hamiltonian` class overwrites `compute\_terms()` to store

	coefficients and operators. The `Hamiltonian.terms` property hence becomes

	a proper method called by `Hamiltonian.terms()`.

	[(#2036)](https://github.com/PennyLaneAI/pennylane/pull/2036)

	+ **Diagonalization**: The `diagonalizing\_gates()` representation has been moved to the

	highest-level `Operator` class and is therefore available to all subclasses. A condition

	`qml.operation.defines\_diagonalizing\_gates` has been added, which can be used in tape contexts

	without queueing. In addition, a static `compute\_diagonalizing\_gates` method has been added,

	which is called by default in `diagonalizing\_gates()`.

	[(#1985)](https://github.com/PennyLaneAI/pennylane/pull/1985)

	[(#1993)](https://github.com/PennyLaneAI/pennylane/pull/1993)

	+ Error handling has been improved for Operator representations. Custom errors subclassing

	`OperatorPropertyUndefined` are raised if a representation has not been defined. This replaces

	the `NotImplementedError` and allows finer control for developers.

	[(#2064)](https://github.com/PennyLaneAI/pennylane/pull/2064)

	[(#2287)](https://github.com/PennyLaneAI/pennylane/pull/2287/)

	+ A `Operator.hyperparameters` attribute, used for storing operation parameters that are *never*

	trainable, has been added to the operator class.

	[(#2017)](https://github.com/PennyLaneAI/pennylane/pull/2017)

	+ The `string\_for\_inverse` attribute is removed.

	[(#2021)](https://github.com/PennyLaneAI/pennylane/pull/2021)

	+ The `expand()` method was moved from the `Operation` class to the main `Operator` class.

	[(#2053)](https://github.com/PennyLaneAI/pennylane/pull/2053)

	[(#2239)](https://github.com/PennyLaneAI/pennylane/pull/2239)

### Deprecations

* There are several important changes when creating custom operations:

[(#2214)](https://github.com/PennyLaneAI/pennylane/pull/2214)

[(#2227)](https://github.com/PennyLaneAI/pennylane/pull/2227)

[(#2030)](https://github.com/PennyLaneAI/pennylane/pull/2030)

[(#2061)](https://github.com/PennyLaneAI/pennylane/pull/2061)

	+ The `Operator.matrix` method has been deprecated and `Operator.compute\_matrix`

	should be defined instead. Operator matrices should be accessed using `qml.matrix(op)`.

	If you were previously defining the class method `Operator.\_matrix()`, this is a a **breaking

	change** — please update your operation to instead overwrite `Operator.compute\_matrix`.

	+ The `Operator.decomposition` method has been deprecated and `Operator.compute\_decomposition`

	should be defined instead. Operator decompositions should be accessed using `Operator.decomposition()`.

	+ The `Operator.eigvals` method has been deprecated and `Operator.compute\_eigvals`

	should be defined instead. Operator eigenvalues should be accessed using `qml.eigvals(op)`.

	+ The `Operator.generator` property is now a method, and should return an *operator instance*

	representing the generator. Note that unlike the other representations above, this is a

	**breaking change**. Operator generators should be accessed using `qml.generator(op)`.

	+ The `Operation.get\_parameter\_shift` method has been deprecated

	and will be removed in a future release.

	

	

	Instead, the functionalities for general parameter-shift rules in the

	`qml.gradients` module should be used, together with the operation attributes

	`parameter\_frequencies` or `grad\_recipe`.

* Executing tapes using `tape.execute(dev)` is deprecated.

Please use the `qml.execute([tape], dev)` function instead.

[(#2306)](https://github.com/PennyLaneAI/pennylane/pull/2306)

* The subclasses of the quantum tape, including `JacobianTape`, `QubitParamShiftTape`,

`CVParamShiftTape`, and `ReversibleTape` are deprecated. Instead of calling

`JacobianTape.jacobian()` and `JacobianTape.hessian()`,

please use a standard `QuantumTape`, and apply gradient transforms using

the `qml.gradients` module.

[(#2306)](https://github.com/PennyLaneAI/pennylane/pull/2306)

* `qml.transforms.get\_unitary\_matrix()` has been deprecated and will be removed

in a future release. For extracting matrices of operations and quantum functions,

please use `qml.matrix()`.

[(#2248)](https://github.com/PennyLaneAI/pennylane/pull/2248)

* The `qml.finite\_diff()` function has been deprecated and will be removed

in an upcoming release. Instead,

`qml.gradients.finite\_diff()` can be used to compute purely quantum gradients

(that is, gradients of tapes or QNode).

[(#2212)](https://github.com/PennyLaneAI/pennylane/pull/2212)

* The `MultiControlledX` operation now accepts a single `wires` keyword argument for both `control\_wires` and `wires`.

The single `wires` keyword should be all the control wires followed by a single target wire.

[(#2121)](https://github.com/PennyLaneAI/pennylane/pull/2121)

[(#2278)](https://github.com/PennyLaneAI/pennylane/pull/2278)

### Breaking changes

* The representation of an operator as a matrix has been overhauled.

[(#1996)](https://github.com/PennyLaneAI/pennylane/pull/1996)

The “canonical matrix”, which is independent of wires,

is now defined in the static method `compute\_matrix()` instead of `\_matrix`.

By default, this method is assumed to take all parameters and non-trainable

hyperparameters that define the operation.

```

>>> qml.RX.compute\_matrix(0.5)

[[0.96891242+0.j 0. -0.24740396j]

 [0. -0.24740396j 0.96891242+0.j ]]

```

If no canonical matrix is specified for a gate, `compute\_matrix()`

raises a `MatrixUndefinedError`.

* The generator property has been updated to an instance method,

`Operator.generator()`. It now returns an instantiated operation,

representing the generator of the instantiated operator.

[(#2030)](https://github.com/PennyLaneAI/pennylane/pull/2030)

[(#2061)](https://github.com/PennyLaneAI/pennylane/pull/2061)

Various operators have been updated to specify the generator as either

an `Observable`, `Tensor`, `Hamiltonian`, `SparseHamiltonian`, or `Hermitian`

operator.

In addition, `qml.generator(operation)` has been added to aid in retrieving

generator representations of operators.

* The argument `wires` in `heisenberg\_obs`, `heisenberg\_expand` and `heisenberg\_tr`

was renamed to `wire\_order` to be consistent with other matrix representations.

[(#2051)](https://github.com/PennyLaneAI/pennylane/pull/2051)

* The property `kraus\_matrices` has been changed to a method, and `\_kraus\_matrices` renamed to

`compute\_kraus\_matrices`, which is now a static method.

[(#2055)](https://github.com/PennyLaneAI/pennylane/pull/2055)

* The `pennylane.measure` module has been renamed to `pennylane.measurements`.

[(#2236)](https://github.com/PennyLaneAI/pennylane/pull/2236)

### Bug fixes

* The `basis` property of `qml.SWAP` was set to `"X"`, which is incorrect; it is

now set to `None`.

[(#2287)](https://github.com/PennyLaneAI/pennylane/pull/2287/)

* The `qml.RandomLayers` template now decomposes when the weights are a list of lists.

[(#2266)](https://github.com/PennyLaneAI/pennylane/pull/2266/)

* The `qml.QubitUnitary` operation now supports just-in-time compilation using JAX.

[(#2249)](https://github.com/PennyLaneAI/pennylane/pull/2249)

* Fixes a bug in the JAX interface where `Array` objects

were not being converted to NumPy arrays before executing an

external device.

[(#2255)](https://github.com/PennyLaneAI/pennylane/pull/2255)

* The `qml.ctrl` transform now works correctly with gradient transforms

such as the parameter-shift rule.

[(#2238)](https://github.com/PennyLaneAI/pennylane/pull/2238)

* Fixes a bug in which passing required arguments into operations as

keyword arguments would throw an error because the documented call

signature didn’t match the function definition.

[(#1976)](https://github.com/PennyLaneAI/pennylane/pull/1976)

* The operation `OrbitalRotation` previously was wrongfully registered to satisfy

the four-term parameter shift rule. The correct eight-term rule will now be used when

using the parameter-shift rule.

[(#2180)](https://github.com/PennyLaneAI/pennylane/pull/2180)

* Fixes a bug where `qml.gradients.param\_shift\_hessian` would produce an

error whenever all elements of the Hessian are known in advance to be 0.

[(#2299)](https://github.com/PennyLaneAI/pennylane/pull/2299)

### Documentation

* The developer guide on adding templates and the architecture overview were rewritten

to reflect the past and planned changes of the operator refactor.

[(#2066)](https://github.com/PennyLaneAI/pennylane/pull/2066)

* Links to the Strawberry Fields documentation for information on the CV

model.

[(#2259)](https://github.com/PennyLaneAI/pennylane/pull/2259)

* Fixes the documentation example for `qml.QFT`.

[(#2232)](https://github.com/PennyLaneAI/pennylane/pull/2232)

* Fixes the documentation example for using `qml.sample` with `jax.jit`.

[(#2196)](https://github.com/PennyLaneAI/pennylane/pull/2196)

* The `qml.numpy` subpackage is now included in the PennyLane

API documentation.

[(#2179)](https://github.com/PennyLaneAI/pennylane/pull/2179)

* Improves the documentation of `RotosolveOptimizer` regarding the

usage of the passed `substep\_optimizer` and its keyword arguments.

[(#2160)](https://github.com/PennyLaneAI/pennylane/pull/2160)

* Ensures that signatures of `@qml.qfunc\_transform` decorated functions

display correctly in the docs.

[(#2286)](https://github.com/PennyLaneAI/pennylane/pull/2286)

* Docstring examples now display using the updated text-based circuit drawer.

[(#2252)](https://github.com/PennyLaneAI/pennylane/pull/2252)

* Add docstring to `OrbitalRotation.grad\_recipe`.

[(#2193)](https://github.com/PennyLaneAI/pennylane/pull/2193)

### Contributors

This release contains contributions from (in alphabetical order):

Catalina Albornoz, Jack Y. Araz, Juan Miguel Arrazola, Ali Asadi, Utkarsh Azad,

Sam Banning, Thomas Bromley, Olivia Di Matteo, Christian Gogolin, Diego Guala,

Anthony Hayes, David Ittah, Josh Izaac, Soran Jahangiri, Nathan Killoran,

Christina Lee, Angus Lowe, Maria Fernanda Morris, Romain Moyard, Zeyue Niu, Lee

James O’Riordan, Chae-Yeun Park, Maria Schuld, Jay Soni, Antal Száva, David

Wierichs.

orphan

#### Release 0.21.0[¶](#release-0-21-0 "Permalink to this headline")

### New features since last release

#### Reduce qubit requirements of simulating Hamiltonians ⚛️

* Functions for tapering qubits based on molecular symmetries have been added,

following results from [Setia et al](https://arxiv.org/abs/1910.14644).

[(#1966)](https://github.com/PennyLaneAI/pennylane/pull/1966)

[(#1974)](https://github.com/PennyLaneAI/pennylane/pull/1974)

[(#2041)](https://github.com/PennyLaneAI/pennylane/pull/2041)

[(#2042)](https://github.com/PennyLaneAI/pennylane/pull/2042)

With this functionality, a molecular Hamiltonian and the corresponding Hartree-Fock (HF) state can be transformed to a new Hamiltonian and HF state that acts on a reduced number of qubits, respectively.

```

# molecular geometry

symbols = ["He", "H"]

geometry = np.array([[0.0, 0.0, 0.0], [0.0, 0.0, 1.4588684632]])

mol = qml.hf.Molecule(symbols, geometry, charge=1)

# generate the qubit Hamiltonian

H = qml.hf.generate\_hamiltonian(mol)(geometry)

# determine Hamiltonian symmetries

generators, paulix\_ops = qml.hf.generate\_symmetries(H, len(H.wires))

opt\_sector = qml.hf.optimal\_sector(H, generators, mol.n\_electrons)

# taper the Hamiltonian

H\_tapered = qml.hf.transform\_hamiltonian(H, generators, paulix\_ops, opt\_sector)

```

We can compare the number of qubits required by the original Hamiltonian

and the tapered Hamiltonian:

```

>>> len(H.wires)

4

>>> len(H\_tapered.wires)

2

```

For quantum chemistry algorithms, the Hartree-Fock state can also be tapered:

```

n\_elec = mol.n\_electrons

n\_qubits = mol.n\_orbitals \* 2

hf\_tapered = qml.hf.transform\_hf(

    generators, paulix\_ops, opt\_sector, n\_elec, n\_qubits

)

```

```

>>> hf\_tapered

tensor([1, 1], requires\_grad=True)

```

#### New tensor network templates 🪢

* Quantum circuits with the shape

of a matrix product state tensor network can now be easily implemented

using the new `qml.MPS` template, based on the work

[arXiv:1803.11537](https://arxiv.org/abs/1803.11537).

[(#1871)](https://github.com/PennyLaneAI/pennylane/pull/1871)

```

def block(weights, wires):

    qml.CNOT(wires=[wires[0], wires[1]])

    qml.RY(weights[0], wires=wires[0])

    qml.RY(weights[1], wires=wires[1])

n\_wires = 4

n\_block\_wires = 2

n\_params\_block = 2

template\_weights = np.array([[0.1, -0.3], [0.4, 0.2], [-0.15, 0.5]], requires\_grad=True)

dev = qml.device("default.qubit", wires=range(n\_wires))

@qml.qnode(dev)

def circuit(weights):

    qml.MPS(range(n\_wires), n\_block\_wires, block, n\_params\_block, weights)

    return qml.expval(qml.PauliZ(wires=n\_wires - 1))

```

The resulting circuit is:

```

>>> print(qml.draw(circuit, expansion\_strategy="device")(template\_weights))

0: ──╭C──RY(0.1)───────────────────────────────┤

1: ──╰X──RY(-0.3)──╭C──RY(0.4)─────────────────┤

2: ────────────────╰X──RY(0.2)──╭C──RY(-0.15)──┤

3: ─────────────────────────────╰X──RY(0.5)────┤ ⟨Z⟩

```

* Added a template for tree tensor networks, `qml.TTN`.

[(#2043)](https://github.com/PennyLaneAI/pennylane/pull/2043)

```

def block(weights, wires):

    qml.CNOT(wires=[wires[0], wires[1]])

    qml.RY(weights[0], wires=wires[0])

    qml.RY(weights[1], wires=wires[1])

n\_wires = 4

n\_block\_wires = 2

n\_params\_block = 2

n\_blocks = qml.MPS.get\_n\_blocks(range(n\_wires), n\_block\_wires)

template\_weights = [[0.1, -0.3]] \* n\_blocks

dev = qml.device("default.qubit", wires=range(n\_wires))

@qml.qnode(dev)

def circuit(template\_weights):

    qml.TTN(range(n\_wires), n\_block\_wires, block, n\_params\_block, template\_weights)

    return qml.expval(qml.PauliZ(wires=n\_wires - 1))

```

The resulting circuit is:

```

>>> print(qml.draw(circuit, expansion\_strategy="device")(template\_weights))

0: ──╭C──RY(0.1)─────────────────┤

1: ──╰X──RY(-0.3)──╭C──RY(0.1)───┤

2: ──╭C──RY(0.1)───│─────────────┤

3: ──╰X──RY(-0.3)──╰X──RY(-0.3)──┤ ⟨Z⟩

```

#### Generalized RotosolveOptmizer 📉

* The `RotosolveOptimizer` has been generalized to arbitrary frequency spectra

in the cost function. Also note the changes in behaviour listed under *Breaking

changes*.

[(#2081)](https://github.com/PennyLaneAI/pennylane/pull/2081)

Previously, the RotosolveOptimizer only supported variational circuits using

special gates such as single-qubit Pauli rotations. Now, circuits with

arbitrary gates are supported natively without decomposition, as long as the

frequencies of the gate parameters are known. This new generalization extends

the Rotosolve optimization method to a larger class of circuits, and can

reduce the cost of the optimization compared to decomposing all gates to

single-qubit rotations.

Consider the QNode

```

dev = qml.device("default.qubit", wires=2)

@qml.qnode(dev)

def qnode(x, Y):

    qml.RX(2.5 \* x, wires=0)

    qml.CNOT(wires=[0, 1])

    qml.RZ(0.3 \* Y[0], wires=0)

    qml.CRY(1.1 \* Y[1], wires=[1, 0])

    return qml.expval(qml.PauliX(0) @ qml.PauliZ(1))

x = np.array(0.8, requires\_grad=True)

Y = np.array([-0.2, 1.5], requires\_grad=True)

```

Its frequency spectra can be easily obtained via `qml.fourier.qnode\_spectrum`:

```

>>> spectra = qml.fourier.qnode\_spectrum(qnode)(x, Y)

>>> spectra

{'x': {(): [-2.5, 0.0, 2.5]},

 'Y': {(0,): [-0.3, 0.0, 0.3], (1,): [-1.1, -0.55, 0.0, 0.55, 1.1]}}

```

We may then initialize the `RotosolveOptimizer` and minimize the QNode cost function

by providing this information about the frequency spectra. We also compare the cost at

each step to the initial cost.

```

>>> cost\_init = qnode(x, Y)

>>> opt = qml.RotosolveOptimizer()

>>> for \_ in range(2):

...     x, Y = opt.step(qnode, x, Y, spectra=spectra)

...     print(f"New cost: {np.round(qnode(x, Y), 3)}; Initial cost: {np.round(cost\_init, 3)}")

New cost: 0.0; Initial cost: 0.706

New cost: -1.0; Initial cost: 0.706

```

The optimization with `RotosolveOptimizer` is performed in substeps. The minimal cost

of these substeps can be retrieved by setting `full\_output=True`.

```

>>> x = np.array(0.8, requires\_grad=True)

>>> Y = np.array([-0.2, 1.5], requires\_grad=True)

>>> opt = qml.RotosolveOptimizer()

>>> for \_ in range(2):

...     (x, Y), history = opt.step(qnode, x, Y, spectra=spectra, full\_output=True)

...     print(f"New cost: {np.round(qnode(x, Y), 3)} reached via substeps {np.round(history, 3)}")

New cost: 0.0 reached via substeps [-0. 0. 0.]

New cost: -1.0 reached via substeps [-1. -1. -1.]

```

However, note that these intermediate minimal values are evaluations of the

*reconstructions* that Rotosolve creates and uses internally for the optimization,

and not of the original objective function. For noisy cost functions, these intermediate

evaluations may differ significantly from evaluations of the original cost function.

#### Improved JAX support 💻

* The JAX interface now supports evaluating vector-valued QNodes.

[(#2110)](https://github.com/PennyLaneAI/pennylane/pull/2110)

Vector-valued QNodes include those with:

	+ `qml.probs`;

	+ `qml.state`;

	+ `qml.sample` or

	+ multiple `qml.expval` / `qml.var` measurements.Consider a QNode that returns basis-state probabilities:

```

dev = qml.device('default.qubit', wires=2)

x = jnp.array(0.543)

y = jnp.array(-0.654)

@qml.qnode(dev, diff\_method="parameter-shift", interface="jax")

def circuit(x, y):

    qml.RX(x, wires=[0])

    qml.RY(y, wires=[1])

    qml.CNOT(wires=[0, 1])

    return qml.probs(wires=[1])

```

The QNode can be evaluated and its jacobian can be computed:

```

>>> circuit(x, y)

Array([0.8397495 , 0.16025047], dtype=float32)

>>> jax.jacobian(circuit, argnums=[0, 1])(x, y)

(Array([-0.2050439, 0.2050439], dtype=float32, weak\_type=True),

 Array([ 0.26043, -0.26043], dtype=float32, weak\_type=True))

```

Note that `jax.jit` is not yet supported for vector-valued QNodes.

#### Speedier quantum natural gradient ⚡

* A new function for computing the metric tensor on simulators,

`qml.adjoint\_metric\_tensor`, has been added, that uses classically

efficient methods to massively improve performance.

[(#1992)](https://github.com/PennyLaneAI/pennylane/pull/1992)

This method, detailed in [Jones (2020)](https://arxiv.org/abs/2011.02991),

computes the metric tensor using four copies of the state vector and

a number of operations that scales quadratically in the number of trainable

parameters.

Note that as it makes use of state cloning, it is inherently classical

and can only be used with statevector simulators and `shots=None`.

It is particularly useful for larger circuits for which backpropagation requires

inconvenient or even unfeasible amounts of storage, but is slower.

Furthermore, the adjoint method is only available for analytic computation, not

for measurements simulation with `shots!=None`.

```

dev = qml.device("default.qubit", wires=3)

@qml.qnode(dev)

def circuit(x, y):

    qml.Rot(\*x[0], wires=0)

    qml.Rot(\*x[1], wires=1)

    qml.Rot(\*x[2], wires=2)

    qml.CNOT(wires=[0, 1])

    qml.CNOT(wires=[1, 2])

    qml.CNOT(wires=[2, 0])

    qml.RY(y[0], wires=0)

    qml.RY(y[1], wires=1)

    qml.RY(y[0], wires=2)

    return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1)), qml.expval(qml.PauliY(1))

x = np.array([[0.2, 0.4, -0.1], [-2.1, 0.5, -0.2], [0.1, 0.7, -0.6]], requires\_grad=False)

y = np.array([1.3, 0.2], requires\_grad=True)

```

```

>>> qml.adjoint\_metric\_tensor(circuit)(x, y)

tensor([[ 0.25495723, -0.07086695],

 [-0.07086695, 0.24945606]], requires\_grad=True)

```

Computational cost

The adjoint method uses \(2P^2+4P+1\) gates and state cloning operations if the circuit

is composed only of trainable gates, where \(P\) is the number of trainable operations.

If non-trainable gates are included, each of them is applied about \(n^2-n\) times, where

\(n\) is the number of trainable operations that follow after the respective

non-trainable operation in the circuit. This means that non-trainable gates later in the

circuit are executed less often, making the adjoint method a bit cheaper if such gates

appear later.

The adjoint method requires memory for 4 independent state vectors, which corresponds roughly

to storing a state vector of a system with 2 additional qubits.

#### Compute the Hessian on hardware ⬆️

* A new gradient transform `qml.gradients.param\_shift\_hessian` has been added

to directly compute the Hessian (2nd order partial derivative matrix) of

QNodes on hardware.

[(#1884)](https://github.com/PennyLaneAI/pennylane/pull/1884)

The function generates parameter-shifted tapes which allow the Hessian to be

computed analytically on hardware and software devices. Compared to using an

auto-differentiation framework to compute the Hessian via parameter shifts,

this function will use fewer device invocations and can be used to inspect

the parameter-shifted “Hessian tapes” directly. The function remains fully

differentiable on all supported PennyLane interfaces.

Additionally, the parameter-shift Hessian comes with a new batch transform decorator

`@qml.gradients.hessian\_transform`, which can be used to create custom Hessian functions.

The following code demonstrates how to use the parameter-shift Hessian:

```

dev = qml.device("default.qubit", wires=2)

@qml.qnode(dev)

def circuit(x):

    qml.RX(x[0], wires=0)

    qml.RY(x[1], wires=0)

    return qml.expval(qml.PauliZ(0))

x = np.array([0.1, 0.2], requires\_grad=True)

hessian = qml.gradients.param\_shift\_hessian(circuit)(x)

```

```

>>> hessian

tensor([[-0.97517033, 0.01983384],

 [ 0.01983384, -0.97517033]], requires\_grad=True)

```

### Improvements

* The `qml.transforms.insert` transform now supports adding operation after or

before certain specific gates.

[(#1980)](https://github.com/PennyLaneAI/pennylane/pull/1980)

* Added a modified version of the `simplify` function to the `hf` module.

[(#2103)](https://github.com/PennyLaneAI/pennylane/pull/2103)

This function combines redundant terms in a Hamiltonian and eliminates terms

with a coefficient smaller than a cutoff value. The new function makes

construction of molecular Hamiltonians more efficient. For LiH, as an

example, the time to construct the Hamiltonian is reduced roughly by a factor

of 20.

* The QAOA module now accepts both NetworkX and RetworkX graphs as function inputs.

[(#1791)](https://github.com/PennyLaneAI/pennylane/pull/1791)

* The `CircuitGraph`, used to represent circuits via directed acyclic graphs, now

uses RetworkX for its internal representation. This results in significant speedup

for algorithms that rely on a directed acyclic graph representation.

[(#1791)](https://github.com/PennyLaneAI/pennylane/pull/1791)

* For subclasses of `Operator` where the number of parameters

is known before instantiation, the

`num\_params` is reverted back to being a static property. This allows to

programmatically know the number of parameters before an operator is

instantiated without changing the user interface. A test was added to ensure

that different ways of defining `num\_params` work as expected.

[(#2101)](https://github.com/PennyLaneAI/pennylane/pull/2101)

[(#2135)](https://github.com/PennyLaneAI/pennylane/pull/2135)

* A `WireCut` operator has been added for manual wire cut placement

when constructing a QNode.

[(#2093)](https://github.com/PennyLaneAI/pennylane/pull/2093)

* The new function `qml.drawer.tape\_text` produces a string drawing of a tape. This function

differs in implementation and minor stylistic details from the old string circuit drawing

infrastructure.

[(#1885)](https://github.com/PennyLaneAI/pennylane/pull/1885)

* The `RotosolveOptimizer` now raises an error if no trainable arguments are

detected, instead of silently skipping update steps for all arguments.

[(#2109)](https://github.com/PennyLaneAI/pennylane/pull/2109)

* The function `qml.math.safe\_squeeze` is introduced and `gradient\_transform` allows

for QNode argument axes of size `1`.

[(#2080)](https://github.com/PennyLaneAI/pennylane/pull/2080)

`qml.math.safe\_squeeze` wraps `qml.math.squeeze`, with slight modifications:

	+ When provided the `axis` keyword argument, axes that do not have size `1` will be

	ignored, instead of raising an error.

	+ The keyword argument `exclude\_axis` allows to explicitly exclude axes from the

	squeezing.

* The `adjoint` transform now raises and error whenever the object it is applied to

is not callable.

[(#2060)](https://github.com/PennyLaneAI/pennylane/pull/2060)

An example is a list of operations to which one might apply `qml.adjoint`:

```

dev = qml.device("default.qubit", wires=2)

@qml.qnode(dev)

def circuit\_wrong(params):

    # Note the difference: v v

    qml.adjoint(qml.templates.AngleEmbedding(params, wires=dev.wires))

    return qml.state()

@qml.qnode(dev)

def circuit\_correct(params):

    # Note the difference: v v

    qml.adjoint(qml.templates.AngleEmbedding)(params, wires=dev.wires)

    return qml.state()

params = list(range(1, 3))

```

Evaluating `circuit\_wrong(params)` now raises a `ValueError` and if we apply

`qml.adjoint` correctly, we get

```

>>> circuit\_correct(params)

[ 0.47415988+0.j 0. 0.73846026j 0. 0.25903472j

 -0.40342268+0.j ]

```

* A precision argument has been added to the tape’s `to\_openqasm` function

to control the precision of parameters.

[(#2071)](https://github.com/PennyLaneAI/pennylane/pull/2071)

* Interferometer now has a `shape` method.

[(#1946)](https://github.com/PennyLaneAI/pennylane/pull/1946)

* The Barrier and Identity operations now support the `adjoint` method.

[(#2062)](https://github.com/PennyLaneAI/pennylane/pull/2062)

[(#2063)](https://github.com/PennyLaneAI/pennylane/pull/2063)

* `qml.BasisStatePreparation` now supports the `batch\_params` decorator.

[(#2091)](https://github.com/PennyLaneAI/pennylane/pull/2091)

* Added a new `multi\_dispatch` decorator that helps ease the definition of new functions

inside PennyLane. The decorator is used throughout the math module, demonstrating use cases.

[(#2082)](https://github.com/PennyLaneAI/pennylane/pull/2084)

[(#2096)](https://github.com/PennyLaneAI/pennylane/pull/2096)

We can decorate a function, indicating the arguments that are

tensors handled by the interface:

```

>>> @qml.math.multi\_dispatch(argnum=[0, 1])

... def some\_function(tensor1, tensor2, option, like):

...     # the interface string is stored in ``like``.

...     ...

```

Previously, this was done using the private utility function `\_multi\_dispatch`.

```

>>> def some\_function(tensor1, tensor2, option):

...     interface = qml.math.\_multi\_dispatch([tensor1, tensor2])

...     ...

```

* The `IsingZZ` gate was added to the `diagonal\_in\_z\_basis` attribute. For this

an explicit `\_eigvals` method was added.

[(#2113)](https://github.com/PennyLaneAI/pennylane/pull/2113)

* The `IsingXX`, `IsingYY` and `IsingZZ` gates were added to

the `composable\_rotations` attribute.

[(#2113)](https://github.com/PennyLaneAI/pennylane/pull/2113)

### Breaking changes

* QNode arguments will no longer be considered trainable by default when using

the Autograd interface. In order to obtain derivatives with respect to a parameter,

it should be instantiated via PennyLane’s NumPy wrapper using the `requires\_grad=True`

attribute. The previous behaviour was deprecated in version v0.19.0 of PennyLane.

[(#2116)](https://github.com/PennyLaneAI/pennylane/pull/2116)

[(#2125)](https://github.com/PennyLaneAI/pennylane/pull/2125)

[(#2139)](https://github.com/PennyLaneAI/pennylane/pull/2139)

[(#2148)](https://github.com/PennyLaneAI/pennylane/pull/2148)

[(#2156)](https://github.com/PennyLaneAI/pennylane/pull/2156)

```

from pennylane import numpy as np

@qml.qnode(qml.device("default.qubit", wires=2))

def circuit(x):

  ...

x = np.array([0.1, 0.2], requires\_grad=True)

qml.grad(circuit)(x)

```

For the `qml.grad` and `qml.jacobian` functions, trainability can alternatively be

indicated via the `argnum` keyword:

```

import numpy as np

@qml.qnode(qml.device("default.qubit", wires=2))

def circuit(hyperparam, param):

  ...

x = np.array([0.1, 0.2])

qml.grad(circuit, argnum=1)(0.5, x)

```

* `qml.jacobian` now follows a different convention regarding its output shape.

[(#2059)](https://github.com/PennyLaneAI/pennylane/pull/2059)

Previously, `qml.jacobian` would attempt to stack the Jacobian for multiple

QNode arguments, which succeeded whenever the arguments have the same shape.

In this case, the stacked Jacobian would also be transposed, leading to the

output shape `(\*reverse\_QNode\_args\_shape, \*reverse\_output\_shape, num\_QNode\_args)`

If no stacking and transposing occurs, the output shape instead is a `tuple`

where each entry corresponds to one QNode argument and has the shape

`(\*output\_shape, \*QNode\_arg\_shape)`.

This breaking change alters the behaviour in the first case and removes the attempt

to stack and transpose, so that the output always has the shape of the second

type.

Note that the behaviour is unchanged — that is, the Jacobian tuple is unpacked into

a single Jacobian — if `argnum=None` and there is only one QNode argument

with respect to which the differentiation takes place, or if an integer

is provided as `argnum`.

A workaround that allowed `qml.jacobian` to differentiate multiple QNode arguments

will no longer support higher-order derivatives. In such cases, combining multiple

arguments into a single array is recommended.

* `qml.metric\_tensor`, `qml.adjoint\_metric\_tensor` and `qml.transforms.classical\_jacobian`

now follow a different convention regarding their output shape when being used

with the Autograd interface

[(#2059)](https://github.com/PennyLaneAI/pennylane/pull/2059)

See the previous entry for details. This breaking change immediately follows from

the change in `qml.jacobian` whenever `hybrid=True` is used in the above methods.

* The behaviour of `RotosolveOptimizer` has been changed regarding

its keyword arguments.

[(#2081)](https://github.com/PennyLaneAI/pennylane/pull/2081)

The keyword arguments `optimizer` and `optimizer\_kwargs` for the

`RotosolveOptimizer` have been renamed to `substep\_optimizer`

and `substep\_kwargs`, respectively. Furthermore they have been

moved from `step` and `step\_and\_cost` to the initialization `\_\_init\_\_`.

The keyword argument `num\_freqs` has been renamed to `nums\_frequency`

and is expected to take a different shape now:

Previously, it was expected to be an `int` or a list of entries, with

each entry in turn being either an `int` or a `list` of `int` entries.

Now the expected structure is a nested dictionary, matching the

formatting expected by

[qml.fourier.reconstruct](https://pennylane.readthedocs.io/en/stable/code/api/pennylane.fourier.reconstruct.html)

This also matches the expected formatting of the new keyword arguments

`spectra` and `shifts`.

For more details, see the

[RotosolveOptimizer documentation](https://pennylane.readthedocs.io/en/stable/code/api/pennylane.RotosolveOptimizer.html).

### Deprecations

* Deprecates the caching ability provided by `QubitDevice`.

[(#2154)](https://github.com/PennyLaneAI/pennylane/pull/2154)

Going forward, the preferred way is to use the caching abilities of the

QNode:

```

dev = qml.device("default.qubit", wires=2)

cache = {}

@qml.qnode(dev, diff\_method='parameter-shift', cache=cache)

def circuit():

    qml.RY(0.345, wires=0)

    return qml.expval(qml.PauliZ(0))

```

```

>>> for \_ in range(10):

...    circuit()

>>> dev.num\_executions

1

```

### Bug fixes

* Fixes a bug where an incorrect number of executions are recorded by

a QNode using a custom cache with `diff\_method="backprop"`.

[(#2171)](https://github.com/PennyLaneAI/pennylane/pull/2171)

* Fixes a bug where the `default.qubit.jax` device can’t be used with `diff\_method=None` and jitting.

[(#2136)](https://github.com/PennyLaneAI/pennylane/pull/2136)

* Fixes a bug where the Torch interface was not properly unwrapping Torch tensors

to NumPy arrays before executing gradient tapes on devices.

[(#2117)](https://github.com/PennyLaneAI/pennylane/pull/2117)

* Fixes a bug for the TensorFlow interface where the dtype of input tensors was

not cast.

[(#2120)](https://github.com/PennyLaneAI/pennylane/pull/2120)

* Fixes a bug where batch transformed QNodes would fail to apply batch transforms

provided by the underlying device.

[(#2111)](https://github.com/PennyLaneAI/pennylane/pull/2111)

* An error is now raised during QNode creation if backpropagation is requested on a device with

finite shots specified.

[(#2114)](https://github.com/PennyLaneAI/pennylane/pull/2114)

* Pytest now ignores any `DeprecationWarning` raised within autograd’s `numpy\_wrapper` module.

Other assorted minor test warnings are fixed.

[(#2007)](https://github.com/PennyLaneAI/pennylane/pull/2007)

* Fixes a bug where the QNode was not correctly diagonalizing qubit-wise

commuting observables.

[(#2097)](https://github.com/PennyLaneAI/pennylane/pull/2097)

* Fixes a bug in `gradient\_transform` where the hybrid differentiation

of circuits with a single parametrized gate failed and QNode argument

axes of size `1` where removed from the output gradient.

[(#2080)](https://github.com/PennyLaneAI/pennylane/pull/2080)

* The available `diff\_method` options for QNodes has been corrected in both the

error messages and the documentation.

[(#2078)](https://github.com/PennyLaneAI/pennylane/pull/2078)

* Fixes a bug in `DefaultQubit` where the second derivative of QNodes at

positions corresponding to vanishing state vector amplitudes is wrong.

[(#2057)](https://github.com/PennyLaneAI/pennylane/pull/2057)

* Fixes a bug where PennyLane didn’t require v0.20.0 of PennyLane-Lightning,

but raised an error with versions of Lightning earlier than v0.20.0 due to

the new batch execution pipeline.

[(#2033)](https://github.com/PennyLaneAI/pennylane/pull/2033)

* Fixes a bug in `classical\_jacobian` when used with Torch, where the

Jacobian of the preprocessing was also computed for non-trainable

parameters.

[(#2020)](https://github.com/PennyLaneAI/pennylane/pull/2020)

* Fixes a bug in queueing of the `two\_qubit\_decomposition` method that

originally led to circuits with >3 two-qubit unitaries failing when passed

through the `unitary\_to\_rot` optimization transform.

[(#2015)](https://github.com/PennyLaneAI/pennylane/pull/2015)

* Fixes a bug which allows using `jax.jit` to be compatible with circuits

which return `qml.probs` when the `default.qubit.jax` is provided with a custom shot

vector.

[(#2028)](https://github.com/PennyLaneAI/pennylane/pull/2028)

* Updated the `adjoint()` method for non-parametric qubit operations to

solve a bug where repeated `adjoint()` calls don’t return the correct

operator.

[(#2133)](https://github.com/PennyLaneAI/pennylane/pull/2133)

* Fixed a bug in `insert()` which prevented operations that inherited

from multiple classes to be inserted.

[(#2172)](https://github.com/PennyLaneAI/pennylane/pull/2172)

### Documentation

* Fixes an error in the signs of equations in the `DoubleExcitation` page.

[(#2072)](https://github.com/PennyLaneAI/pennylane/pull/2072)

* Extends the interfaces description page to explicitly mention device

compatibility.

[(#2031)](https://github.com/PennyLaneAI/pennylane/pull/2031)

### Contributors

This release contains contributions from (in alphabetical order):

Juan Miguel Arrazola, Ali Asadi, Utkarsh Azad, Sam Banning, Thomas Bromley,

Esther Cruz, Olivia Di Matteo, Christian Gogolin, Diego Guala, Anthony Hayes,

David Ittah, Josh Izaac, Soran Jahangiri, Edward Jiang, Ankit Khandelwal,

Nathan Killoran, Korbinian Kottmann, Christina Lee, Romain Moyard, Lee James

O’Riordan, Maria Schuld, Jay Soni, Antal Száva, David Wierichs, Shaoming Zhang.

orphan

#### Release 0.20.0[¶](#release-0-20-0 "Permalink to this headline")

### New features since last release

#### Shiny new circuit drawer!🎨🖌️

* PennyLane now supports drawing a QNode with matplotlib!

[(#1803)](https://github.com/PennyLaneAI/pennylane/pull/1803)

[(#1811)](https://github.com/PennyLaneAI/pennylane/pull/1811)

[(#1931)](https://github.com/PennyLaneAI/pennylane/pull/1931)

[(#1954)](https://github.com/PennyLaneAI/pennylane/pull/1954)

```

dev = qml.device("default.qubit", wires=4)

@qml.qnode(dev)

def circuit(x, z):

    qml.QFT(wires=(0,1,2,3))

    qml.Toffoli(wires=(0,1,2))

    qml.CSWAP(wires=(0,2,3))

    qml.RX(x, wires=0)

    qml.CRZ(z, wires=(3,0))

    return qml.expval(qml.PauliZ(0))

fig, ax = qml.draw\_mpl(circuit)(1.2345, 1.2345)

fig.show()

```

![](https://pennylane.readthedocs.io/en/latest/_images/main_example.png)

#### New and improved quantum-aware optimizers

* Added `qml.LieAlgebraOptimizer`, a new quantum-aware Lie Algebra optimizer

that allows one to perform gradient descent on the special unitary group.

[(#1911)](https://github.com/PennyLaneAI/pennylane/pull/1911)

```

dev = qml.device("default.qubit", wires=2)

H = -1.0 \* qml.PauliX(0) - qml.PauliZ(1) - qml.PauliY(0) @ qml.PauliX(1)

@qml.qnode(dev)

def circuit():

    qml.RX(0.1, wires=[0])

    qml.RY(0.5, wires=[1])

    qml.CNOT(wires=[0,1])

    qml.RY(0.6, wires=[0])

    return qml.expval(H)

opt = qml.LieAlgebraOptimizer(circuit=circuit, stepsize=0.1)

```

Note that, unlike other optimizers, the `LieAlgebraOptimizer` accepts a QNode

with *no* parameters, and instead grows the circuit by appending operations

during the optimization:

```

>>> circuit()

tensor(-1.3351865, requires\_grad=True)

>>> circuit1, cost = opt.step\_and\_cost()

>>> circuit1()

tensor(-1.99378872, requires\_grad=True)

```

For more details, see the

[LieAlgebraOptimizer documentation](https://pennylane.readthedocs.io/en/stable/code/api/pennylane.LieAlgebraOptimizer.html).

* The `qml.metric\_tensor` transform can now be used to compute the full

tensor, beyond the block diagonal approximation.

[(#1725)](https://github.com/PennyLaneAI/pennylane/pull/1725)

This is performed using Hadamard tests, and requires an additional wire

on the device to execute the circuits produced by the transform,

as compared to the number of wires required by the original circuit.

The transform defaults to computing the full tensor, which can

be controlled by the `approx` keyword argument.

As an example, consider the QNode

```

dev = qml.device("default.qubit", wires=3)

@qml.qnode(dev)

def circuit(weights):

    qml.RX(weights[0], wires=0)

    qml.RY(weights[1], wires=0)

    qml.CNOT(wires=[0, 1])

    qml.RZ(weights[2], wires=1)

    return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1))

weights = np.array([0.2, 1.2, -0.9], requires\_grad=True)

```

Then we can compute the (block) diagonal metric tensor as before, now using the

`approx="block-diag"` keyword:

```

>>> qml.metric\_tensor(circuit, approx="block-diag")(weights)

[[0.25 0. 0. ]

 [0. 0.24013262 0. ]

 [0. 0. 0.21846983]]

```

Instead, we now can also compute the full metric tensor, using

Hadamard tests on the additional wire of the device:

```

>>> qml.metric\_tensor(circuit)(weights)

[[ 0.25 0. -0.23300977]

 [ 0. 0.24013262 0.01763859]

 [-0.23300977 0.01763859 0.21846983]]

```

See the

[metric tensor documentation](https://pennylane.readthedocs.io/en/stable/code/api/pennylane.transforms.metric_tensor.html).

for more information and usage details.

#### Faster performance with optimized quantum workflows

* The QNode has been re-written to support batch execution across the board,

custom gradients, better decomposition strategies, and higher-order derivatives.

[(#1807)](https://github.com/PennyLaneAI/pennylane/pull/1807)

[(#1969)](https://github.com/PennyLaneAI/pennylane/pull/1969)

	+ Internally, if multiple circuits are generated for simultaneous execution, they

	will be packaged into a single job for execution on the device. This can lead to

	significant performance improvement when executing the QNode on remote

	quantum hardware or simulator devices with parallelization capabilities.

	+ Custom gradient transforms can be specified as the differentiation method:

	

	

	

	```

	@qml.gradients.gradient\_transform

	def my\_gradient\_transform(tape):

	    ...

	    return tapes, processing\_fn

	

	@qml.qnode(dev, diff\_method=my\_gradient\_transform)

	def circuit():

	

	```For breaking changes related to the use of the new QNode, refer to the

Breaking Changes section.

Note that the old QNode remains accessible at `@qml.qnode\_old.qnode`, however this will

be removed in the next release.

* Custom decompositions can now be applied to operations at the device level.

[(#1900)](https://github.com/PennyLaneAI/pennylane/pull/1900)

For example, suppose we would like to implement the following QNode:

```

def circuit(weights):

    qml.BasicEntanglerLayers(weights, wires=[0, 1, 2])

    return qml.expval(qml.PauliZ(0))

original\_dev = qml.device("default.qubit", wires=3)

original\_qnode = qml.QNode(circuit, original\_dev)

```

```

>>> weights = np.array([[0.4, 0.5, 0.6]])

>>> print(qml.draw(original\_qnode, expansion\_strategy="device")(weights))

 0: ──RX(0.4)──╭C──────╭X──┤ ⟨Z⟩

 1: ──RX(0.5)──╰X──╭C──│───┤

 2: ──RX(0.6)──────╰X──╰C──┤

```

Now, let’s swap out the decomposition of the `CNOT` gate into `CZ`

and `Hadamard`, and furthermore the decomposition of `Hadamard` into

`RZ` and `RY` rather than the decomposition already available in PennyLane.

We define the two decompositions like so, and pass them to a device:

```

def custom\_cnot(wires):

    return [

        qml.Hadamard(wires=wires[1]),

        qml.CZ(wires=[wires[0], wires[1]]),

        qml.Hadamard(wires=wires[1])

    ]

def custom\_hadamard(wires):

    return [

        qml.RZ(np.pi, wires=wires),

        qml.RY(np.pi / 2, wires=wires)

    ]

# Can pass the operation itself, or a string

custom\_decomps = {qml.CNOT : custom\_cnot, "Hadamard" : custom\_hadamard}

decomp\_dev = qml.device("default.qubit", wires=3, custom\_decomps=custom\_decomps)

decomp\_qnode = qml.QNode(circuit, decomp\_dev)

```

Now when we draw or run a QNode on this device, the gates will be expanded

according to our specifications:

```

>>> print(qml.draw(decomp\_qnode, expansion\_strategy="device")(weights))

 0: ──RX(0.4)──────────────────────╭C──RZ(3.14)──RY(1.57)──────────────────────────╭Z──RZ(3.14)──RY(1.57)──┤ ⟨Z⟩

 1: ──RX(0.5)──RZ(3.14)──RY(1.57)──╰Z──RZ(3.14)──RY(1.57)──╭C──────────────────────│───────────────────────┤

 2: ──RX(0.6)──RZ(3.14)──RY(1.57)──────────────────────────╰Z──RZ(3.14)──RY(1.57)──╰C──────────────────────┤

```

A separate context manager, `set\_decomposition`, has also been implemented to enable

application of custom decompositions on devices that have already been created.

```

>>> with qml.transforms.set\_decomposition(custom\_decomps, original\_dev):

...     print(qml.draw(original\_qnode, expansion\_strategy="device")(weights))

 0: ──RX(0.4)──────────────────────╭C──RZ(3.14)──RY(1.57)──────────────────────────╭Z──RZ(3.14)──RY(1.57)──┤ ⟨Z⟩

 1: ──RX(0.5)──RZ(3.14)──RY(1.57)──╰Z──RZ(3.14)──RY(1.57)──╭C──────────────────────│───────────────────────┤

 2: ──RX(0.6)──RZ(3.14)──RY(1.57)──────────────────────────╰Z──RZ(3.14)──RY(1.57)──╰C──────────────────────┤

```

* Given an operator of the form \(U=e^{iHt}\), where \(H\) has

commuting terms and known eigenvalues,

`qml.gradients.generate\_shift\_rule` computes the generalized parameter shift rules for determining

the gradient of the expectation value \(f(t) = \langle 0|U(t)^\dagger \hat{O} U(t)|0\rangle\) on

hardware.

[(#1788)](https://github.com/PennyLaneAI/pennylane/pull/1788)

[(#1932)](https://github.com/PennyLaneAI/pennylane/pull/1932)

Given

\[H = \sum\_i a\_i h\_i,\]

where the eigenvalues of \(H\) are known and all \(h\_i\) commute, we can compute

the *frequencies* (the unique positive differences of any two eigenvalues) using

`qml.gradients.eigvals\_to\_frequencies`.

`qml.gradients.generate\_shift\_rule` can then be used to compute the parameter

shift rules to compute \(f'(t)\) using `2R` shifted cost function evaluations.

This becomes cheaper than the standard application of the chain rule and

two-term shift rule when `R` is less than the

number of Pauli words in the generator.

For example, consider the case where \(H\) has eigenspectrum `(-1, 0, 1)`:

```

>>> frequencies = qml.gradients.eigvals\_to\_frequencies((-1, 0, 1))

>>> frequencies

(1, 2)

>>> coeffs, shifts = qml.gradients.generate\_shift\_rule(frequencies)

>>> coeffs

array([ 0.85355339, -0.85355339, -0.14644661, 0.14644661])

>>> shifts

array([ 0.78539816, -0.78539816, 2.35619449, -2.35619449])

```

As we can see, `generate\_shift\_rule` returns four coefficients \(c\_i\) and shifts

\(s\_i\) corresponding to a four term parameter shift rule. The gradient can then

be reconstructed via:

\[\frac{\partial}{\partial\phi}f = \sum\_{i} c\_i f(\phi + s\_i),\]

where \(f(\phi) = \langle 0|U(\phi)^\dagger \hat{O} U(\phi)|0\rangle\)

for some observable \(\hat{O}\) and the unitary \(U(\phi)=e^{iH\phi}\).

#### Support for TensorFlow AutoGraph mode with quantum hardware

* It is now possible to use TensorFlow’s [AutoGraph

mode](https://www.tensorflow.org/guide/function) with QNodes on all devices and with arbitrary

differentiation methods. Previously, AutoGraph mode only support `diff\_method="backprop"`. This

will result in significantly more performant model execution, at the cost of a more expensive

initial compilation. [(#1866)](https://github.com/PennyLaneAI/pennylane/pull/1886)

Use AutoGraph to convert your QNodes or cost functions into TensorFlow

graphs by decorating them with `@tf.function`:

```

dev = qml.device("lightning.qubit", wires=2)

@qml.qnode(dev, diff\_method="adjoint", interface="tf", max\_diff=1)

def circuit(x):

    qml.RX(x[0], wires=0)

    qml.RY(x[1], wires=1)

    return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1)), qml.expval(qml.PauliZ(0))

@tf.function

def cost(x):

    return tf.reduce\_sum(circuit(x))

x = tf.Variable([0.5, 0.7], dtype=tf.float64)

with tf.GradientTape() as tape:

    loss = cost(x)

grad = tape.gradient(loss, x)

```

The initial execution may take slightly longer than when executing the circuit in

eager mode; this is because TensorFlow is tracing the function to create the graph.

Subsequent executions will be much more performant.

Note that using AutoGraph with backprop-enabled devices, such as `default.qubit`,

will yield the best performance.

For more details, please see the [TensorFlow AutoGraph

documentation](https://www.tensorflow.org/guide/function).

#### Characterize your quantum models with classical QNode reconstruction

* The `qml.fourier.reconstruct` function is added. It can be used to

reconstruct QNodes outputting expectation values along a specified

parameter dimension, with a minimal number of calls to the

original QNode. The returned

reconstruction is exact and purely classical, and can be evaluated

without any quantum executions.

[(#1864)](https://github.com/PennyLaneAI/pennylane/pull/1864)

The reconstruction technique differs for functions with equidistant frequencies

that are reconstructed using the function value at equidistant sampling points, and

for functions with arbitrary frequencies reconstructed using arbitrary sampling points.

As an example, consider the following QNode:

```

dev = qml.device("default.qubit", wires=2)

@qml.qnode(dev)

def circuit(x, Y, f=1.0):

    qml.RX(f \* x, wires=0)

    qml.RY(Y[0], wires=0)

    qml.RY(Y[1], wires=1)

    qml.CNOT(wires=[0, 1])

    qml.RY(3 \* Y[1], wires=1)

    return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1))

```

It has three variational parameters overall: A scalar input `x`

and an array-valued input `Y` with two entries. Additionally, we can

tune the dependence on `x` with the frequency `f`.

We then can reconstruct the QNode output function with respect to `x` via

```

>>> x = 0.3

>>> Y = np.array([0.1, -0.9])

>>> rec = qml.fourier.reconstruct(circuit, ids="x", nums\_frequency={"x": {0: 1}})(x, Y)

>>> rec

{'x': {0: <function pennylane.fourier.reconstruct.\_reconstruct\_equ.<locals>.\_reconstruction(x)>}}

```

As we can see, we get a nested dictionary in the format of the input `nums\_frequency`

with functions as values. These functions are simple float-to-float callables:

```

>>> univariate = rec["x"][0]

>>> univariate(x)

-0.880208251507

```

For more details on usage, reconstruction cost and differentiability support, please see the

[fourier.reconstruct docstring](https://pennylane.readthedocs.io/en/stable/code/api/pennylane.fourier.reconstruct.html).

#### State-of-the-art operations and templates

* A circuit template for time evolution under a commuting Hamiltonian utilizing generalized

parameter shift rules for cost function gradients is available as `qml.CommutingEvolution`.

[(#1788)](https://github.com/PennyLaneAI/pennylane/pull/1788)

If the template is handed a frequency spectrum during its instantiation, then `generate\_shift\_rule`

is internally called to obtain the general parameter shift rules with respect to

`CommutingEvolution`‘s \(t\) parameter, otherwise the shift rule for a decomposition of

`CommutingEvolution` will be used.

The template can be initialized within QNode as:

```

import pennylane as qml

n\_wires = 2

dev = qml.device('default.qubit', wires=n\_wires)

coeffs = [1, -1]

obs = [qml.PauliX(0) @ qml.PauliY(1), qml.PauliY(0) @ qml.PauliX(1)]

hamiltonian = qml.Hamiltonian(coeffs, obs)

frequencies = (2,4)

@qml.qnode(dev)

def circuit(time):

    qml.PauliX(0)

    qml.CommutingEvolution(hamiltonian, time, frequencies)

    return qml.expval(qml.PauliZ(0))

```

Note that there is no internal validation that 1) the input `qml.Hamiltonian` is fully commuting

and 2) the eigenvalue frequency spectrum is correct, since these checks become

prohibitively expensive for large Hamiltonians.

* The `qml.Barrier()` operator has been added. With it we can separate blocks

in compilation or use it as a visual tool.

[(#1844)](https://github.com/PennyLaneAI/pennylane/pull/1844)

* Added the identity observable to be an operator. Now we can explicitly call the identity

operation on our quantum circuits for both qubit and CV devices.

[(#1829)](https://github.com/PennyLaneAI/pennylane/pull/1829)

* Added the `qml.QubitDensityMatrix` initialization gate for

mixed state simulation.

[(#1850)](https://github.com/PennyLaneAI/pennylane/pull/1850)

* A thermal relaxation channel is added to the Noisy channels. The channel description can be

found on the supplementary information of [Quantum classifier with tailored quantum kernels](https://arxiv.org/abs/1909.02611).

[(#1766)](https://github.com/PennyLaneAI/pennylane/pull/1766)

* Added a new `qml.PauliError` channel that allows the application of an

arbitrary number of Pauli operators on an arbitrary number of wires.

[(#1781)](https://github.com/PennyLaneAI/pennylane/pull/1781)

#### Manipulate QNodes to your ❤️s content with new transforms

* The `merge\_amplitude\_embedding` transformation has been created to

automatically merge all gates of this type into one.

[(#1933)](https://github.com/PennyLaneAI/pennylane/pull/1933)

```

from pennylane.transforms import merge\_amplitude\_embedding

dev = qml.device("default.qubit", wires = 3)

@qml.qnode(dev)

@merge\_amplitude\_embedding

def qfunc():

    qml.AmplitudeEmbedding([0,1,0,0], wires = [0,1])

    qml.AmplitudeEmbedding([0,1], wires = 2)

    return qml.expval(qml.PauliZ(wires = 0))

```

```

>>> print(qml.draw(qnode)())

 0: ──╭AmplitudeEmbedding(M0)──┤ ⟨Z⟩

 1: ──├AmplitudeEmbedding(M0)──┤

 2: ──╰AmplitudeEmbedding(M0)──┤

 M0 =

 [0.+0.j 0.+0.j 0.+0.j 1.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j]

```

* The `undo\_swaps` transformation has been created to automatically remove all

swaps of a circuit.

[(#1960)](https://github.com/PennyLaneAI/pennylane/pull/1960)

```

dev = qml.device('default.qubit', wires=3)

@qml.qnode(dev)

@qml.transforms.undo\_swaps

def qfunc():

    qml.Hadamard(wires=0)

    qml.PauliX(wires=1)

    qml.SWAP(wires=[0,1])

    qml.SWAP(wires=[0,2])

    qml.PauliY(wires=0)

    return qml.expval(qml.PauliZ(0))

```

```

>>> print(qml.draw(qfunc)())

 0: ──Y──┤ ⟨Z⟩

 1: ──H──┤

 2: ──X──┤

```

### Improvements

* Added functions for computing the values of atomic and molecular orbitals at a given position.

[(#1867)](https://github.com/PennyLaneAI/pennylane/pull/1867)

The functions `atomic\_orbital` and `molecular\_orbital` can be used, as shown in the

following codeblock, to evaluate the orbitals. By generating values of the orbitals at different

positions, one can plot the spatial shape of a desired orbital.

```

symbols  = ['H', 'H']

geometry = np.array([[0.0, 0.0, 0.0], [0.0, 0.0, 1.0]], requires\_grad = False)

mol = hf.Molecule(symbols, geometry)

hf.generate\_scf(mol)()

ao = mol.atomic\_orbital(0)

mo = mol.molecular\_orbital(1)

```

```

>>> print(ao(0.0, 0.0, 0.0))

>>> print(mo(0.0, 0.0, 0.0))

0.6282468778183719

0.018251285973461928

```

* Added support for Python 3.10.

[(#1964)](https://github.com/PennyLaneAI/pennylane/pull/1964)

* The execution of QNodes that have

	+ multiple return types;

	+ a return type other than Variance and Expectationnow raises a descriptive error message when using the JAX interface.

[(#2011)](https://github.com/PennyLaneAI/pennylane/pull/2011)

* The PennyLane `qchem` package is now lazily imported; it will only be imported

the first time it is accessed.

[(#1962)](https://github.com/PennyLaneAI/pennylane/pull/1962)

* `qml.math.scatter\_element\_add` now supports adding multiple values at

multiple indices with a single function call, in all interfaces

[(#1864)](https://github.com/PennyLaneAI/pennylane/pull/1864)

For example, we may set five values of a three-dimensional tensor

in the following way:

```

>>> X = tf.zeros((3, 2, 9), dtype=tf.float64)

>>> indices = [(0, 0, 1, 2, 2), (0, 0, 0, 0, 1), (1, 3, 8, 6, 7)]

>>> values = [1 \* i for i in range(1,6)]

>>> qml.math.scatter\_element\_add(X, indices, values)

<tf.Tensor: shape=(3, 2, 9), dtype=float64, numpy=

array([[[0., 1., 0., 2., 0., 0., 0., 0., 0.],

 [0., 0., 0., 0., 0., 0., 0., 0., 0.]],

 [[0., 0., 0., 0., 0., 0., 0., 0., 3.],

 [0., 0., 0., 0., 0., 0., 0., 0., 0.]],

 [[0., 0., 0., 0., 0., 0., 4., 0., 0.],

 [0., 0., 0., 0., 0., 0., 0., 5., 0.]]])>

```

* All instances of `str.format` have been replace with f-strings.

[(#1970)](https://github.com/PennyLaneAI/pennylane/pull/1970)

* Tests do not loop over automatically imported and instantiated operations any more,

which was opaque and created unnecessarily many tests.

[(#1895)](https://github.com/PennyLaneAI/pennylane/pull/1895)

* A `decompose()` method has been added to the `Operator` class such that we can

obtain (and queue) decompositions directly from instances of operations.

[(#1873)](https://github.com/PennyLaneAI/pennylane/pull/1873)

```

>>> op = qml.PhaseShift(0.3, wires=0)

>>> op.decompose()

[RZ(0.3, wires=[0])]

```

* `qml.circuit\_drawer.tape\_mpl` produces a matplotlib figure and axes given a tape.

[(#1787)](https://github.com/PennyLaneAI/pennylane/pull/1787)

* The `AngleEmbedding`, `BasicEntanglerLayers` and `MottonenStatePreparation`

templates now support parameters with batch dimension when using the `@qml.batch\_params` decorator.

[(#1812)](https://github.com/PennyLaneAI/pennylane/pull/1812)

[(#1883)](https://github.com/PennyLaneAI/pennylane/pull/1883)

[(#1893)](https://github.com/PennyLaneAI/pennylane/pull/1893)

* `qml.draw` now supports a `max\_length` argument to help prevent text overflows when printing circuits.

[(#1892)](https://github.com/PennyLaneAI/pennylane/pull/1892)

* `Identity` operation is now part of both the `ops.qubit` and `ops.cv`

modules.

[(#1956)](https://github.com/PennyLaneAI/pennylane/pull/1956)

### Breaking changes

* The QNode has been re-written to support batch execution across the board,

custom gradients, better decomposition strategies, and higher-order derivatives.

[(#1807)](https://github.com/PennyLaneAI/pennylane/pull/1807)

[(#1969)](https://github.com/PennyLaneAI/pennylane/pull/1969)

	+ Arbitrary \(n\)-th order derivatives are supported on hardware using gradient transforms

	such as the parameter-shift rule. To specify that an \(n\)-th order derivative of a QNode

	will be computed, the `max\_diff` argument should be set. By default, this is set to 1

	(first-order derivatives only). Increasing this value allows for higher order derivatives to be

	extracted, at the cost of additional (classical) computational overhead during the backwards

	pass.

	+ When decomposing the circuit, the default decomposition strategy `expansion\_strategy="gradient"`

	will prioritize decompositions that result in the smallest number of parametrized operations

	required to satisfy the differentiation method. While this may lead to a slight increase in

	classical processing, it significantly reduces the number of circuit evaluations needed to

	compute gradients of complicated unitaries.

	

	

	To return to the old behaviour, `expansion\_strategy="device"` can be specified.Note that the old QNode remains accessible at `@qml.qnode\_old.qnode`, however this will

be removed in the next release.

* Certain features deprecated in `v0.19.0` have been removed:

[(#1981)](https://github.com/PennyLaneAI/pennylane/pull/1981)

[(#1963)](https://github.com/PennyLaneAI/pennylane/pull/1963)

	+ The `qml.template` decorator (use a `

	QuantumTape <<https://pennylane.readthedocs.io/en/stable/code/api/pennylane.tape.QuantumTape.html>>`\_

	as a context manager to record operations and its `operations` attribute to

	return them, see the linked page for examples);

	+ The `default.tensor` and `default.tensor.tf` experimental devices;

	+ The `qml.fourier.spectrum` function (use the `qml.fourier.circuit\_spectrum`

	or `qml.fourier.qnode\_spectrum` functions instead);

	+ The `diag\_approx` keyword argument of `qml.metric\_tensor` and

	`qml.QNGOptimizer` (pass `approx='diag'` instead).

* The default behaviour of the `qml.metric\_tensor` transform has been modified.

By default, the full metric tensor is computed, leading to higher cost than the previous

default of computing the block diagonal only. At the same time, the Hadamard tests for

the full metric tensor require an additional wire on the device, so that

```

>>> qml.metric\_tensor(some\_qnode)(weights)

```

will revert back to the block diagonal restriction and raise a warning if the

used device does not have an additional wire.

[(#1725)](https://github.com/PennyLaneAI/pennylane/pull/1725)

* The `circuit\_drawer` module has been renamed `drawer`.

[(#1949)](https://github.com/PennyLaneAI/pennylane/pull/1949)

* The `par\_domain` attribute in the operator class has been removed.

[(#1907)](https://github.com/PennyLaneAI/pennylane/pull/1907)

* The `mutable` keyword argument has been removed from the QNode,

due to underlying bugs that result in incorrect results being

returned from immutable QNodes. This functionality will return

in an upcoming release.

[(#1807)](https://github.com/PennyLaneAI/pennylane/pull/1807)

* The reversible QNode differentiation method has been removed; the adjoint

differentiation method is preferred instead (`diff\_method='adjoint'`).

[(#1807)](https://github.com/PennyLaneAI/pennylane/pull/1807)

* `QuantumTape.trainable\_params` now is a list instead of a set. This

means that `tape.trainable\_params` will return a list unlike before,

but setting the `trainable\_params` with a set works exactly as before.

[(#1904)](https://github.com/PennyLaneAI/pennylane/pull/1904)

* The `num\_params` attribute in the operator class is now dynamic. This makes it easier

to define operator subclasses with a flexible number of parameters.

[(#1898)](https://github.com/PennyLaneAI/pennylane/pull/1898)

[(#1909)](https://github.com/PennyLaneAI/pennylane/pull/1909)

* The static method `decomposition()`, formerly in the `Operation` class, has

been moved to the base `Operator` class.

[(#1873)](https://github.com/PennyLaneAI/pennylane/pull/1873)

* `DiagonalOperation` is not a separate subclass any more.

[(#1889)](https://github.com/PennyLaneAI/pennylane/pull/1889)

Instead, devices can check for the diagonal

property using attributes:

```

from pennylane.ops.qubit.attributes import diagonal\_in\_z\_basis

if op in diagonal\_in\_z\_basis:

    # do something

```

Custom operations can be added to this attribute at runtime via

`diagonal\_in\_z\_basis.add("MyCustomOp")`.

### Bug fixes

* Fixes a bug with `qml.probs` when using `default.qubit.jax`.

[(#1998)](https://github.com/PennyLaneAI/pennylane/pull/1998)

* Fixes a bug where output tensors of a QNode would always be put on the

default GPU with `default.qubit.torch`.

[(#1982)](https://github.com/PennyLaneAI/pennylane/pull/1982)

* Device test suite doesn’t use empty circuits so that it can also

test the IonQ plugin, and it checks if operations are supported in

more places.

[(#1979)](https://github.com/PennyLaneAI/pennylane/pull/1979)

* Fixes a bug where the metric tensor was computed incorrectly when using

gates with `gate.inverse=True`.

[(#1987)](https://github.com/PennyLaneAI/pennylane/pull/1987)

* Corrects the documentation of `qml.transforms.classical\_jacobian`

for the Autograd interface (and improves test coverage).

[(#1978)](https://github.com/PennyLaneAI/pennylane/pull/1978)

* Fixes a bug where differentiating a QNode with `qml.state` using the JAX

interface raised an error.

[(#1906)](https://github.com/PennyLaneAI/pennylane/pull/1906)

* Fixes a bug with the adjoint of `qml.QFT`.

[(#1955)](https://github.com/PennyLaneAI/pennylane/pull/1955)

* Fixes a bug where the `ApproxTimeEvolution` template was not correctly

computing the operation wires from the input Hamiltonian. This did not

affect computation with the `ApproxTimeEvolution` template, but did

cause circuit drawing to fail.

[(#1952)](https://github.com/PennyLaneAI/pennylane/pull/1952)

* Fixes a bug where the classical preprocessing Jacobian

computed by `qml.transforms.classical\_jacobian` with JAX

returned a reduced submatrix of the Jacobian.

[(#1948)](https://github.com/PennyLaneAI/pennylane/pull/1948)

* Fixes a bug where the operations are not accessed in the correct order

in `qml.fourier.qnode\_spectrum`, leading to wrong outputs.

[(#1935)](https://github.com/PennyLaneAI/pennylane/pull/1935)

* Fixes several Pylint errors.

[(#1951)](https://github.com/PennyLaneAI/pennylane/pull/1951)

* Fixes a bug where the device test suite wasn’t testing certain operations.

[(#1943)](https://github.com/PennyLaneAI/pennylane/pull/1943)

* Fixes a bug where batch transforms would mutate a QNodes execution options.

[(#1934)](https://github.com/PennyLaneAI/pennylane/pull/1934)

* `qml.draw` now supports arbitrary templates with matrix parameters.

[(#1917)](https://github.com/PennyLaneAI/pennylane/pull/1917)

* `QuantumTape.trainable\_params` now is a list instead of a set, making

it more stable in very rare edge cases.

[(#1904)](https://github.com/PennyLaneAI/pennylane/pull/1904)

* `ExpvalCost` now returns corrects results shape when `optimize=True` with

shots batch.

[(#1897)](https://github.com/PennyLaneAI/pennylane/pull/1897)

* `qml.circuit\_drawer.MPLDrawer` was slightly modified to work with

matplotlib version 3.5.

[(#1899)](https://github.com/PennyLaneAI/pennylane/pull/1899)

* `qml.CSWAP` and `qml.CRot` now define `control\_wires`, and `qml.SWAP`

returns the default empty wires object.

[(#1830)](https://github.com/PennyLaneAI/pennylane/pull/1830)

* The `requires\_grad` attribute of `qml.numpy.tensor` objects is now

preserved when pickling/unpickling the object.

[(#1856)](https://github.com/PennyLaneAI/pennylane/pull/1856)

* Device tests no longer throw warnings about the `requires\_grad`

attribute of variational parameters.

[(#1913)](https://github.com/PennyLaneAI/pennylane/pull/1913)

* `AdamOptimizer` and `AdagradOptimizer` had small fixes to their

optimization step updates.

[(#1929)](https://github.com/PennyLaneAI/pennylane/pull/1929)

* Fixes a bug where differentiating a QNode with multiple array

arguments via `qml.gradients.param\_shift` throws an error.

[(#1989)](https://github.com/PennyLaneAI/pennylane/pull/1989)

* `AmplitudeEmbedding` template no longer produces a `ComplexWarning`

when the `features` parameter is batched and provided as a 2D array.

[(#1990)](https://github.com/PennyLaneAI/pennylane/pull/1990)

* `qml.circuit\_drawer.CircuitDrawer` no longer produces an error

when attempting to draw tapes inside of circuits (e.g. from

decomposition of an operation or manual placement).

[(#1994)](https://github.com/PennyLaneAI/pennylane/pull/1994)

* Fixes a bug where using SciPy sparse matrices with the new QNode

could lead to a warning being raised about prioritizing the TensorFlow

and PyTorch interfaces.

[(#2001)](https://github.com/PennyLaneAI/pennylane/pull/2001)

* Fixed a bug where the `QueueContext` was not empty when first importing PennyLane.

[(#1957)](https://github.com/PennyLaneAI/pennylane/pull/1957)

* Fixed circuit drawing problem with `Interferometer` and `CVNeuralNet`.

[(#1953)](https://github.com/PennyLaneAI/pennylane/pull/1953)

### Documentation

* Added examples in documentation for some operations.

[(#1902)](https://github.com/PennyLaneAI/pennylane/pull/1902)

* Improves the Developer’s Guide Testing document.

[(#1896)](https://github.com/PennyLaneAI/pennylane/pull/1896)

* Added documentation examples for `AngleEmbedding`, `BasisEmbedding`, `StronglyEntanglingLayers`,

`SqueezingEmbedding`, `DisplacementEmbedding`, `MottonenStatePreparation` and `Interferometer`.

[(#1910)](https://github.com/PennyLaneAI/pennylane/pull/1910)

[(#1908)](https://github.com/PennyLaneAI/pennylane/pull/1908)

[(#1912)](https://github.com/PennyLaneAI/pennylane/pull/1912)

[(#1920)](https://github.com/PennyLaneAI/pennylane/pull/1920)

[(#1936)](https://github.com/PennyLaneAI/pennylane/pull/1936)

[(#1937)](https://github.com/PennyLaneAI/pennylane/pull/1937)

### Contributors

This release contains contributions from (in alphabetical order):

Catalina Albornoz, Guillermo Alonso-Linaje, Juan Miguel Arrazola, Ali Asadi, Utkarsh Azad, Samuel Banning, Benjamin Cordier, Alain Delgado,

Olivia Di Matteo, Anthony Hayes, David Ittah, Josh Izaac, Soran Jahangiri, Jalani Kanem, Ankit Khandelwal, Nathan Killoran, Shumpei

Kobayashi, Robert Lang, Christina Lee, Cedric Lin, Alejandro Montanez, Romain Moyard, Lee James O’Riordan, Chae-Yeun Park, Isidor Schoch,

Maria Schuld, Jay Soni, Antal Száva, Rodrigo Vargas, David Wierichs, Roeland Wiersema, Moritz Willmann.

orphan

#### Release 0.19.1[¶](#release-0-19-1 "Permalink to this headline")

### Bug fixes

* Fixes several bugs when using parametric operations with the

`default.qubit.tensor` device on GPU. The device takes the `torch\_device`

argument once again to allow running non-parametric QNodes on the GPU.

[(#1927)](https://github.com/PennyLaneAI/pennylane/pull/1927)

* Fixes a bug where using JAX’s jit function on certain QNodes that contain

the `qml.QubitStateVector` operation raised an error with earlier JAX

versions (e.g., `jax==0.2.10` and `jaxlib==0.1.64`).

[(#1924)](https://github.com/PennyLaneAI/pennylane/pull/1924)

### Contributors

This release contains contributions from (in alphabetical order):

Josh Izaac, Christina Lee, Romain Moyard, Lee James O’Riordan, Antal Száva.

orphan

#### Release 0.19.0[¶](#release-0-19-0 "Permalink to this headline")

### New features since last release

#### Differentiable Hartree-Fock solver

* A differentiable Hartree-Fock (HF) solver has been added. It can be used to construct molecular

Hamiltonians that can be differentiated with respect to nuclear coordinates and basis-set

parameters. [(#1610)](https://github.com/PennyLaneAI/pennylane/pull/1610)

The HF solver computes the integrals over basis functions, constructs the relevant matrices, and

performs self-consistent-field iterations to obtain a set of optimized molecular orbital

coefficients. These coefficients and the computed integrals over basis functions are used to

construct the one- and two-body electron integrals in the molecular orbital basis which can be

used to generate a differentiable second-quantized Hamiltonian in the fermionic and qubit basis.

The following code shows the construction of the Hamiltonian for the hydrogen molecule where the

geometry of the molecule is differentiable.

```

symbols = ["H", "H"]

geometry = np.array([[0.0000000000, 0.0000000000, -0.6943528941],

                     [0.0000000000, 0.0000000000,  0.6943528941]], requires\_grad=True)

mol = qml.hf.Molecule(symbols, geometry)

args\_mol = [geometry]

hamiltonian = qml.hf.generate\_hamiltonian(mol)(\*args\_mol)

```

```

>>> hamiltonian.coeffs

tensor([-0.09041082+0.j, 0.17220382+0.j, 0.17220382+0.j,

 0.16893367+0.j, 0.04523101+0.j, -0.04523101+0.j,

 -0.04523101+0.j, 0.04523101+0.j, -0.22581352+0.j,

 0.12092003+0.j, -0.22581352+0.j, 0.16615103+0.j,

 0.16615103+0.j, 0.12092003+0.j, 0.17464937+0.j], requires\_grad=True)

```

The generated Hamiltonian can be used in a circuit where the atomic

coordinates and circuit parameters are optimized simultaneously.

```

symbols = ["H", "H"]

geometry = np.array([[0.0000000000, 0.0000000000, 0.0],

                     [0.0000000000, 0.0000000000, 2.0]], requires\_grad=True)

mol = qml.hf.Molecule(symbols, geometry)

dev = qml.device("default.qubit", wires=4)

params = [np.array([0.0], requires\_grad=True)]

def generate\_circuit(mol):

    @qml.qnode(dev)

    def circuit(\*args):

        qml.BasisState(np.array([1, 1, 0, 0]), wires=[0, 1, 2, 3])

        qml.DoubleExcitation(\*args[0][0], wires=[0, 1, 2, 3])

        return qml.expval(qml.hf.generate\_hamiltonian(mol)(\*args[1:]))

    return circuit

for n in range(25):

    mol = qml.hf.Molecule(symbols, geometry)

    args = [params, geometry] # initial values of the differentiable parameters

    g\_params = qml.grad(generate\_circuit(mol), argnum = 0)(\*args)

    params = params - 0.5 \* g\_params[0]

    forces = qml.grad(generate\_circuit(mol), argnum = 1)(\*args)

    geometry = geometry - 0.5 \* forces

    print(f'Step: {n}, Energy: {generate\_circuit(mol)(\*args)}, Maximum Force: {forces.max()}')

```

In addition, the new Hartree-Fock solver can further be used to optimize the

basis set parameters. For details, please refer to the [differentiable

Hartree-Fock solver

documentation](https://pennylane.readthedocs.io/en/latest/code/qml_hf.html#using-the-differentiable-hf-solver).

#### Integration with Mitiq

* Error mitigation using the zero-noise extrapolation method is now available through the

`transforms.mitigate\_with\_zne` transform. This transform can integrate with the

[Mitiq](https://mitiq.readthedocs.io/en/stable/) package for unitary folding and extrapolation

functionality.

[(#1813)](https://github.com/PennyLaneAI/pennylane/pull/1813)

Consider the following noisy device:

```

noise\_strength = 0.05

dev = qml.device("default.mixed", wires=2)

dev = qml.transforms.insert(qml.AmplitudeDamping, noise\_strength)(dev)

```

We can mitigate the effects of this noise for circuits run on this device by using the added

transform:

```

from mitiq.zne.scaling import fold\_global

from mitiq.zne.inference import RichardsonFactory

n\_wires = 2

n\_layers = 2

shapes = qml.SimplifiedTwoDesign.shape(n\_wires, n\_layers)

np.random.seed(0)

w1, w2 = [np.random.random(s) for s in shapes]

@qml.transforms.mitigate\_with\_zne([1, 2, 3], fold\_global, RichardsonFactory.extrapolate)

@qml.beta.qnode(dev)

def circuit(w1, w2):

    qml.SimplifiedTwoDesign(w1, w2, wires=range(2))

    return qml.expval(qml.PauliZ(0))

```

Now, when we execute `circuit`, errors will be automatically mitigated:

```

>>> circuit(w1, w2)

0.19113067083636542

```

#### Powerful new transforms

* The unitary matrix corresponding to a quantum circuit can now be generated using the new

`get\_unitary\_matrix()` transform.

[(#1609)](https://github.com/PennyLaneAI/pennylane/pull/1609)

[(#1786)](https://github.com/PennyLaneAI/pennylane/pull/1786)

This transform is fully differentiable across all supported PennyLane autodiff frameworks.

```

def circuit(theta):

    qml.RX(theta, wires=1)

    qml.PauliZ(wires=0)

    qml.CNOT(wires=[0, 1])

```

```

>>> theta = torch.tensor(0.3, requires\_grad=True)

>>> matrix = qml.transforms.get\_unitary\_matrix(circuit)(theta)

>>> print(matrix)

tensor([[ 0.9888+0.0000j, 0.0000+0.0000j, 0.0000-0.1494j, 0.0000+0.0000j],

 [ 0.0000+0.0000j, 0.0000+0.1494j, 0.0000+0.0000j, -0.9888+0.0000j],

 [ 0.0000-0.1494j, 0.0000+0.0000j, 0.9888+0.0000j, 0.0000+0.0000j],

 [ 0.0000+0.0000j, -0.9888+0.0000j, 0.0000+0.0000j, 0.0000+0.1494j]],

 grad\_fn=<MmBackward>)

>>> loss = torch.real(torch.trace(matrix))

>>> loss.backward()

>>> theta.grad

tensor(-0.1494)

```

* Arbitrary two-qubit unitaries can now be decomposed into elementary gates. This

functionality has been incorporated into the `qml.transforms.unitary\_to\_rot` transform, and is

available separately as `qml.transforms.two\_qubit\_decomposition`.

[(#1552)](https://github.com/PennyLaneAI/pennylane/pull/1552)

As an example, consider the following randomly-generated matrix and circuit that uses it:

```

U = np.array([

    [-0.03053706-0.03662692j,  0.01313778+0.38162226j, 0.4101526 -0.81893687j, -0.03864617+0.10743148j],

    [-0.17171136-0.24851809j,  0.06046239+0.1929145j, -0.04813084-0.01748555j, -0.29544883-0.88202604j],

    [ 0.39634931-0.78959795j, -0.25521689-0.17045233j, -0.1391033 -0.09670952j, -0.25043606+0.18393466j],

    [ 0.29599198-0.19573188j,  0.55605806+0.64025769j, 0.06140516+0.35499559j,  0.02674726+0.1563311j ]

])

dev = qml.device('default.qubit', wires=2)

@qml.qnode(dev)

@qml.transforms.unitary\_to\_rot

def circuit(x, y):

    qml.QubitUnitary(U, wires=[0, 1])

    return qml.expval(qml.PauliZ(wires=0))

```

If we run the circuit, we can see the new decomposition:

```

>>> circuit(0.3, 0.4)

tensor(-0.81295986, requires\_grad=True)

>>> print(qml.draw(circuit)(0.3, 0.4))

0: ──Rot(2.78, 0.242, -2.28)──╭X──RZ(0.176)───╭C─────────────╭X──Rot(-3.87, 0.321, -2.09)──┤ ⟨Z⟩

1: ──Rot(4.64, 2.69, -1.56)───╰C──RY(-0.883)──╰X──RY(-1.47)──╰C──Rot(1.68, 0.337, 0.587)───┤

```

* A new transform, `@qml.batch\_params`, has been added, that makes QNodes

handle a batch dimension in trainable parameters.

[(#1710)](https://github.com/PennyLaneAI/pennylane/pull/1710)

[(#1761)](https://github.com/PennyLaneAI/pennylane/pull/1761)

This transform will create multiple circuits, one per batch dimension.

As a result, it is both simulator and hardware compatible.

```

@qml.batch\_params

@qml.beta.qnode(dev)

def circuit(x, weights):

    qml.RX(x, wires=0)

    qml.RY(0.2, wires=1)

    qml.templates.StronglyEntanglingLayers(weights, wires=[0, 1, 2])

    return qml.expval(qml.Hadamard(0))

```

The `qml.batch\_params` decorator allows us to pass arguments `x` and `weights`

that have a batch dimension. For example,

```

>>> batch\_size = 3

>>> x = np.linspace(0.1, 0.5, batch\_size)

>>> weights = np.random.random((batch\_size, 10, 3, 3))

```

If we evaluate the QNode with these inputs, we will get an output

of shape `(batch\_size,)`:

```

>>> circuit(x, weights)

tensor([0.08569816, 0.12619101, 0.21122004], requires\_grad=True)

```

* The `insert` transform has now been added, providing a way to insert single-qubit operations into

a quantum circuit. The transform can apply to quantum functions, tapes, and devices.

[(#1795)](https://github.com/PennyLaneAI/pennylane/pull/1795)

The following QNode can be transformed to add noise to the circuit:

```

dev = qml.device("default.mixed", wires=2)

@qml.qnode(dev)

@qml.transforms.insert(qml.AmplitudeDamping, 0.2, position="end")

def f(w, x, y, z):

    qml.RX(w, wires=0)

    qml.RY(x, wires=1)

    qml.CNOT(wires=[0, 1])

    qml.RY(y, wires=0)

    qml.RX(z, wires=1)

    return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1))

```

Executions of this circuit will differ from the noise-free value:

```

>>> f(0.9, 0.4, 0.5, 0.6)

tensor(0.754847, requires\_grad=True)

>>> print(qml.draw(f)(0.9, 0.4, 0.5, 0.6))

 0: ──RX(0.9)──╭C──RY(0.5)──AmplitudeDamping(0.2)──╭┤ ⟨Z ⊗ Z⟩

 1: ──RY(0.4)──╰X──RX(0.6)──AmplitudeDamping(0.2)──╰┤ ⟨Z ⊗ Z⟩

```

* Common tape expansion functions are now available in `qml.transforms`,

alongside a new `create\_expand\_fn` function for easily creating expansion functions

from stopping criteria.

[(#1734)](https://github.com/PennyLaneAI/pennylane/pull/1734)

[(#1760)](https://github.com/PennyLaneAI/pennylane/pull/1760)

`create\_expand\_fn` takes the default depth to which the expansion function

should expand a tape, a stopping criterion, an optional device, and a docstring to be set for the

created function.

The stopping criterion must take a queuable object and return a boolean.

For example, to create an expansion function that decomposes all trainable,

multi-parameter operations:

```

>>> stop\_at = ~(qml.operation.has\_multipar & qml.operation.is\_trainable)

>>> expand\_fn = qml.transforms.create\_expand\_fn(depth=5, stop\_at=stop\_at)

```

The created expansion function can be used within a custom transform.

Devices can also be provided, producing expansion functions that decompose

tapes to support the native gate set of the device.

#### Batch execution of circuits

* A new, experimental QNode has been added, that adds support for batch execution of circuits,

custom quantum gradient support, and arbitrary order derivatives. This QNode is available via

`qml.beta.QNode`, and `@qml.beta.qnode`.

[(#1642)](https://github.com/PennyLaneAI/pennylane/pull/1642)

[(#1646)](https://github.com/PennyLaneAI/pennylane/pull/1646)

[(#1651)](https://github.com/PennyLaneAI/pennylane/pull/1651)

[(#1804)](https://github.com/PennyLaneAI/pennylane/pull/1804)

It differs from the standard QNode in several ways:

	+ Custom gradient transforms can be specified as the differentiation method:

	

	

	

	```

	@qml.gradients.gradient\_transform

	def my\_gradient\_transform(tape):

	    ...

	    return tapes, processing\_fn

	

	@qml.beta.qnode(dev, diff\_method=my\_gradient\_transform)

	def circuit():

	

	```

	+ Arbitrary \(n\)-th order derivatives are supported on hardware using

	gradient transforms such as the parameter-shift rule. To specify that an \(n\)-th

	order derivative of a QNode will be computed, the `max\_diff` argument should be set.

	By default, this is set to 1 (first-order derivatives only).

	+ Internally, if multiple circuits are generated for execution simultaneously, they

	will be packaged into a single job for execution on the device. This can lead to

	significant performance improvement when executing the QNode on remote

	quantum hardware.

	+ When decomposing the circuit, the default decomposition strategy will prioritize

	decompositions that result in the smallest number of parametrized operations

	required to satisfy the differentiation method. Additional decompositions required

	to satisfy the native gate set of the quantum device will be performed later, by the

	device at execution time. While this may lead to a slight increase in classical processing,

	it significantly reduces the number of circuit evaluations needed to compute

	gradients of complex unitaries.In an upcoming release, this QNode will replace the existing one. If you come across any bugs

while using this QNode, please let us know via a [bug

report](https://github.com/PennyLaneAI/pennylane/issues/new?assignees=&labels=bug+%3Abug%3A&template=bug_report.yml&title=%5BBUG%5D)

on our GitHub bug tracker.

Currently, this beta QNode does not support the following features:

	+ Non-mutability via the `mutable` keyword argument

	+ The `reversible` QNode differentiation method

	+ The ability to specify a `dtype` when using PyTorch and TensorFlow.It is also not tested with the `qml.qnn` module.

#### New operations and templates

* Added a new operation `OrbitalRotation`, which implements the spin-adapted spatial orbital

rotation gate. [(#1665)](https://github.com/PennyLaneAI/pennylane/pull/1665)

An example circuit that uses `OrbitalRotation` operation is:

```

dev = qml.device('default.qubit', wires=4)

@qml.qnode(dev)

def circuit(phi):

    qml.BasisState(np.array([1, 1, 0, 0]), wires=[0, 1, 2, 3])

    qml.OrbitalRotation(phi, wires=[0, 1, 2, 3])

    return qml.state()

```

If we run this circuit, we will get the following output

```

>>> circuit(0.1)

array([ 0. +0.j, 0. +0.j, 0. +0.j,

 0.00249792+0.j, 0. +0.j, 0. +0.j,

 -0.04991671+0.j, 0. +0.j, 0. +0.j,

 -0.04991671+0.j, 0. +0.j, 0. +0.j,

 0.99750208+0.j, 0. +0.j, 0. +0.j,

 0. +0.j])

```

* Added a new template `GateFabric`, which implements a local, expressive, quantum-number-preserving

ansatz proposed by Anselmetti *et al.* in [arXiv:2104.05692](https://arxiv.org/abs/2104.05695).

[(#1687)](https://github.com/PennyLaneAI/pennylane/pull/1687)

An example of a circuit using `GateFabric` template is:

```

coordinates = np.array([0.0, 0.0, -0.6614, 0.0, 0.0, 0.6614])

H, qubits = qml.qchem.molecular\_hamiltonian(["H", "H"], coordinates)

ref\_state = qml.qchem.hf\_state(electrons=2, orbitals=qubits)

dev = qml.device('default.qubit', wires=qubits)

@qml.qnode(dev)

def ansatz(weights):

    qml.templates.GateFabric(weights, wires=[0,1,2,3],

                                init\_state=ref\_state, include\_pi=True)

    return qml.expval(H)

```

For more details, see the [GateFabric

documentation](https://pennylane.readthedocs.io/en/latest/code/api/pennylane.GateFabric.html).

* Added a new template `kUpCCGSD`, which implements a unitary coupled cluster ansatz with

generalized singles and pair doubles excitation operators, proposed by Joonho Lee *et al.*

in [arXiv:1810.02327](https://arxiv.org/abs/1810.02327).

[(#1743)](https://github.com/PennyLaneAI/pennylane/pull/1743)

An example of a circuit using `kUpCCGSD` template is:

```

coordinates = np.array([0.0, 0.0, -0.6614, 0.0, 0.0, 0.6614])

H, qubits = qml.qchem.molecular\_hamiltonian(["H", "H"], coordinates)

ref\_state = qml.qchem.hf\_state(electrons=2, orbitals=qubits)

dev = qml.device('default.qubit', wires=qubits)

@qml.qnode(dev)

def ansatz(weights):

    qml.templates.kUpCCGSD(weights, wires=[0,1,2,3], k=0, delta\_sz=0,

                                init\_state=ref\_state)

    return qml.expval(H)

```

#### Improved utilities for quantum compilation and characterization

* The new `qml.fourier.qnode\_spectrum` function extends the former

`qml.fourier.spectrum` function

and takes classical processing of QNode arguments into account.

The frequencies are computed per (requested) QNode argument instead

of per gate `id`. The gate `id`s are ignored.

[(#1681)](https://github.com/PennyLaneAI/pennylane/pull/1681)

[(#1720)](https://github.com/PennyLaneAI/pennylane/pull/1720)

Consider the following example, which uses non-trainable inputs `x`, `y` and `z`

as well as trainable parameters `w` as arguments to the QNode.

```

import pennylane as qml

import numpy as np

n\_qubits = 3

dev = qml.device("default.qubit", wires=n\_qubits)

@qml.qnode(dev)

def circuit(x, y, z, w):

    for i in range(n\_qubits):

        qml.RX(0.5\*x[i], wires=i)

        qml.Rot(w[0,i,0], w[0,i,1], w[0,i,2], wires=i)

        qml.RY(2.3\*y[i], wires=i)

        qml.Rot(w[1,i,0], w[1,i,1], w[1,i,2], wires=i)

        qml.RX(z, wires=i)

    return qml.expval(qml.PauliZ(wires=0))

x = np.array([1., 2., 3.])

y = np.array([0.1, 0.3, 0.5])

z = -1.8

w = np.random.random((2, n\_qubits, 3))

```

This circuit looks as follows:

```

>>> print(qml.draw(circuit)(x, y, z, w))

0: ──RX(0.5)──Rot(0.598, 0.949, 0.346)───RY(0.23)──Rot(0.693, 0.0738, 0.246)──RX(-1.8)──┤ ⟨Z⟩

1: ──RX(1)────Rot(0.0711, 0.701, 0.445)──RY(0.69)──Rot(0.32, 0.0482, 0.437)───RX(-1.8)──┤

2: ──RX(1.5)──Rot(0.401, 0.0795, 0.731)──RY(1.15)──Rot(0.756, 0.38, 0.38)─────RX(-1.8)──┤

```

Applying the `qml.fourier.qnode\_spectrum` function to the circuit for the non-trainable

parameters, we obtain:

```

>>> spec = qml.fourier.qnode\_spectrum(circuit, encoding\_args={"x", "y", "z"})(x, y, z, w)

>>> for inp, freqs in spec.items():

...     print(f"{inp}: {freqs}")

"x": {(0,): [-0.5, 0.0, 0.5], (1,): [-0.5, 0.0, 0.5], (2,): [-0.5, 0.0, 0.5]}

"y": {(0,): [-2.3, 0.0, 2.3], (1,): [-2.3, 0.0, 2.3], (2,): [-2.3, 0.0, 2.3]}

"z": {(): [-3.0, -2.0, -1.0, 0.0, 1.0, 2.0, 3.0]}

```

We can see that all three parameters in the QNode arguments `x` and `y`

contribute the spectrum of a Pauli rotation `[-1.0, 0.0, 1.0]`, rescaled with the

prefactor of the respective parameter in the circuit.

The three `RX` rotations using the parameter `z` accumulate, yielding a more

complex frequency spectrum.

For details on how to control for which parameters the spectrum is computed,

a comparison to `qml.fourier.circuit\_spectrum`, and other usage details, please see the

[fourier.qnode\_spectrum docstring](https://pennylane.readthedocs.io/en/latest/code/api/pennylane.fourier.qnode_spectrum.html).

* Two new methods were added to the Device API, allowing PennyLane devices

increased control over circuit decompositions.

[(#1651)](https://github.com/PennyLaneAI/pennylane/pull/1651)

	+ `Device.expand\_fn(tape) -> tape`: expands a tape such that it is supported by the device. By

	default, performs the standard device-specific gate set decomposition done in the default

	QNode. Devices may overwrite this method in order to define their own decomposition logic.

	

	

	Note that the numerical result after applying this method should remain unchanged; PennyLane

	will assume that the expanded tape returns exactly the same value as the original tape when

	executed.

	+ `Device.batch\_transform(tape) -> (tapes, processing\_fn)`: preprocesses the tape in the case

	where the device needs to generate multiple circuits to execute from the input circuit. The

	requirement of a post-processing function makes this distinct to the `expand\_fn` method above.

	

	

	By default, this method applies the transform

	

	

	

	\[\left\langle \sum\_i c\_i h\_i\right\rangle → \sum\_i c\_i \left\langle h\_i \right\rangle\]

	if `expval(H)` is present on devices that do not natively support Hamiltonians with

	non-commuting terms.

* A new class has been added to store operator attributes, such as `self\_inverses`,

and `composable\_rotation`, as a list of operation names.

[(#1763)](https://github.com/PennyLaneAI/pennylane/pull/1763)

A number of such attributes, for the purpose of compilation transforms, can be found

in `ops/qubit/attributes.py`, but the class can also be used to create your own. For

example, we can create a new Attribute, `pauli\_ops`, like so:

```

>>> from pennylane.ops.qubit.attributes import Attribute

>>> pauli\_ops = Attribute(["PauliX", "PauliY", "PauliZ"])

```

We can check either a string or an Operation for inclusion in this set:

```

>>> qml.PauliX(0) in pauli\_ops

True

>>> "Hadamard" in pauli\_ops

False

```

We can also dynamically add operators to the sets at runtime. This is useful

for adding custom operations to the attributes such as `composable\_rotations`

and `self\_inverses` that are used in compilation transforms. For example,

suppose you have created a new Operation, `MyGate`, which you know to be its

own inverse. Adding it to the set, like so

```

>>> from pennylane.ops.qubit.attributes import self\_inverses

>>> self\_inverses.add("MyGate")

```

will enable the gate to be considered by the `cancel\_inverses` compilation

transform if two such gates are adjacent in a circuit.

### Improvements

* The `qml.metric\_tensor` transform has been improved with regards to

both function and performance.

[(#1638)](https://github.com/PennyLaneAI/pennylane/pull/1638)

[(#1721)](https://github.com/PennyLaneAI/pennylane/pull/1721)

	+ If the underlying device supports batch execution of circuits, the quantum circuits required to

	compute the metric tensor elements will be automatically submitted as a batched job. This can

	lead to significant performance improvements for devices with a non-trivial job submission

	overhead.

	+ Previously, the transform would only return the metric tensor with respect to gate arguments,

	and ignore any classical processing inside the QNode, even very trivial classical processing

	such as parameter permutation. The metric tensor now takes into account classical processing,

	and returns the metric tensor with respect to QNode arguments, not simply gate arguments:

	

	

	

	```

	>>> @qml.qnode(dev)

	... def circuit(x):

	...     qml.Hadamard(wires=1)

	...     qml.RX(x[0], wires=0)

	...     qml.CNOT(wires=[0, 1])

	...     qml.RY(x[1] \*\* 2, wires=1)

	...     qml.RY(x[1], wires=0)

	...     return qml.expval(qml.PauliZ(0))

	>>> x = np.array([0.1, 0.2], requires\_grad=True)

	>>> qml.metric\_tensor(circuit)(x)

	array([[0.25 , 0. ],

	 [0. , 0.28750832]])

	

	```

	

	

	To revert to the previous behaviour of returning the metric tensor with respect to gate

	arguments, `qml.metric\_tensor(qnode, hybrid=False)` can be passed.

	

	

	

	```

	>>> qml.metric\_tensor(circuit, hybrid=False)(x)

	array([[0.25 , 0. , 0. ],

	 [0. , 0.25 , 0. ],

	 [0. , 0. , 0.24750832]])

	

	```

	+ The metric tensor transform now works with a larger set of operations. In particular,

	all operations that have a single variational parameter and define a generator are now

	supported. In addition to a reduction in decomposition overhead, the change

	also results in fewer circuit evaluations.

* The expansion rule in the `qml.metric\_tensor` transform has been changed.

[(#1721)](https://github.com/PennyLaneAI/pennylane/pull/1721)

If `hybrid=False`, the changed expansion rule might lead to a changed output.

* The `ApproxTimeEvolution` template can now be used with Hamiltonians that have

trainable coefficients.

[(#1789)](https://github.com/PennyLaneAI/pennylane/pull/1789)

Resulting QNodes can be differentiated with respect to both the time parameter

*and* the Hamiltonian coefficients.

```

dev = qml.device('default.qubit', wires=2)

obs = [qml.PauliX(0) @ qml.PauliY(1), qml.PauliY(0) @ qml.PauliX(1)]

@qml.qnode(dev)

def circuit(coeffs, t):

    H = qml.Hamiltonian(coeffs, obs)

    qml.templates.ApproxTimeEvolution(H, t, 2)

    return qml.expval(qml.PauliZ(0))

```

```

>>> t = np.array(0.54, requires\_grad=True)

>>> coeffs = np.array([-0.6, 2.0], requires\_grad=True)

>>> qml.grad(circuit)(coeffs, t)

(array([-1.07813375, -1.07813375]), array(-2.79516158))

```

All differentiation methods, including backpropagation and the parameter-shift

rule, are supported.

* Quantum function transforms and batch transforms can now be applied to devices.

Once applied to a device, any quantum function executed on the

modified device will be transformed prior to execution.

[(#1809)](https://github.com/PennyLaneAI/pennylane/pull/1809)

[(#1810)](https://github.com/PennyLaneAI/pennylane/pull/1810)

```

dev = qml.device("default.mixed", wires=1)

dev = qml.transforms.merge\_rotations()(dev)

@qml.beta.qnode(dev)

def f(w, x, y, z):

    qml.RX(w, wires=0)

    qml.RX(x, wires=0)

    qml.RX(y, wires=0)

    qml.RX(z, wires=0)

    return qml.expval(qml.PauliZ(0))

```

```

>>> print(f(0.9, 0.4, 0.5, 0.6))

 -0.7373937155412453

>>> print(qml.draw(f, expansion\_strategy="device")(0.9, 0.4, 0.5, 0.6))

 0: ──RX(2.4)──┤ ⟨Z⟩

```

* It is now possible to draw QNodes that have been transformed by a ‘batch transform’; that is,

a transform that maps a single QNode into multiple circuits under the hood. Examples of

batch transforms include `@qml.metric\_tensor` and `@qml.gradients`.

[(#1762)](https://github.com/PennyLaneAI/pennylane/pull/1762)

For example, consider the parameter-shift rule, which generates two circuits per parameter;

one circuit that has the parameter shifted forward, and another that has the parameter shifted

backwards:

```

dev = qml.device("default.qubit", wires=2)

@qml.gradients.param\_shift

@qml.beta.qnode(dev)

def circuit(x):

    qml.RX(x, wires=0)

    qml.CNOT(wires=[0, 1])

    return qml.expval(qml.PauliZ(wires=0))

```

```

>>> print(qml.draw(circuit)(0.6))

 0: ──RX(2.17)──╭C──┤ ⟨Z⟩

 1: ────────────╰X──┤

 0: ──RX(-0.971)──╭C──┤ ⟨Z⟩

 1: ──────────────╰X──┤

```

* Support for differentiable execution of batches of circuits has been

extended to the JAX interface for scalar functions, via the beta

`pennylane.interfaces.batch` module.

[(#1634)](https://github.com/PennyLaneAI/pennylane/pull/1634)

[(#1685)](https://github.com/PennyLaneAI/pennylane/pull/1685)

For example using the `execute` function from the `pennylane.interfaces.batch` module:

```

from pennylane.interfaces.batch import execute

def cost\_fn(x):

    with qml.tape.JacobianTape() as tape1:

        qml.RX(x[0], wires=[0])

        qml.RY(x[1], wires=[1])

        qml.CNOT(wires=[0, 1])

        qml.var(qml.PauliZ(0) @ qml.PauliX(1))

    with qml.tape.JacobianTape() as tape2:

        qml.RX(x[0], wires=0)

        qml.RY(x[0], wires=1)

        qml.CNOT(wires=[0, 1])

        qml.probs(wires=1)

    result = execute(

      [tape1, tape2], dev,

      gradient\_fn=qml.gradients.param\_shift,

      interface="autograd"

    )

    return (result[0] + result[1][0, 0])[0]

res = jax.grad(cost\_fn)(params)

```

* All qubit operations have been re-written to use the `qml.math` framework

for internal classical processing and the generation of their matrix representations.

As a result these representations are now fully differentiable, and the

framework-specific device classes no longer need to maintain framework-specific

versions of these matrices.

[(#1749)](https://github.com/PennyLaneAI/pennylane/pull/1749)

[(#1802)](https://github.com/PennyLaneAI/pennylane/pull/1802)

* The use of `expval(H)`, where `H` is a cost Hamiltonian generated by the `qaoa` module,

has been sped up. This was achieved by making PennyLane decompose a circuit with an `expval(H)`

measurement into subcircuits if the `Hamiltonian.grouping\_indices` attribute is set, and setting

this attribute in the relevant `qaoa` module functions.

[(#1718)](https://github.com/PennyLaneAI/pennylane/pull/1718)

* Operations can now have gradient recipes that depend on the state of the operation.

[(#1674)](https://github.com/PennyLaneAI/pennylane/pull/1674)

For example, this allows for gradient recipes that are parameter dependent:

```

class RX(qml.RX):

    @property

    def grad\_recipe(self):

        # The gradient is given by [f(2x) - f(0)] / (2 sin(x)), by subsituting

        # shift = x into the two term parameter-shift rule.

        x = self.data[0]

        c = 0.5 / np.sin(x)

        return ([[c, 0.0, 2 \* x], [-c, 0.0, 0.0]],)

```

* Shots can now be passed as a runtime argument to transforms that execute circuits in batches,

similarly to QNodes. [(#1707)](https://github.com/PennyLaneAI/pennylane/pull/1707)

An example of such a transform are the gradient transforms in the

`qml.gradients` module. As a result, we can now call gradient transforms

(such as `qml.gradients.param\_shift`) and set the number of shots at runtime.

```

>>> dev = qml.device("default.qubit", wires=1, shots=1000)

>>> @qml.beta.qnode(dev)

... def circuit(x):

...     qml.RX(x, wires=0)

...     return qml.expval(qml.PauliZ(0))

>>> grad\_fn = qml.gradients.param\_shift(circuit)

>>> param = np.array(0.564, requires\_grad=True)

>>> grad\_fn(param, shots=[(1, 10)]).T

array([[-1., -1., -1., -1., -1., 0., -1., 0., -1., 0.]])

>>> param2 = np.array(0.1233, requires\_grad=True)

>>> grad\_fn(param2, shots=None)

array([[-0.12298782]])

```

* Templates are now top level imported and can be used directly e.g. `qml.QFT(wires=0)`.

[(#1779)](https://github.com/PennyLaneAI/pennylane/pull/1779)

* `qml.probs` now accepts an attribute `op` that allows to rotate the computational basis and get

the probabilities in the rotated basis.

[(#1692)](https://github.com/PennyLaneAI/pennylane/pull/1692)

* Refactored the `expand\_fn` functionality in the Device class to avoid any

edge cases leading to failures with plugins.

[(#1838)](https://github.com/PennyLaneAI/pennylane/pull/1838)

* Updated the `qml.QNGOptimizer.step\_and\_cost` method to avoid the use of

deprecated functionality.

[(#1834)](https://github.com/PennyLaneAI/pennylane/pull/1834)

* Added a custom `torch.to\_numpy` implementation to

`pennylane/math/single\_dispatch.py` to ensure compabilitity with

PyTorch 1.10.

[(#1824)](https://github.com/PennyLaneAI/pennylane/pull/1824)

[(#1825)](https://github.com/PennyLaneAI/pennylane/pull/1825)

* The default for an `Operation`‘s `control\_wires` attribute is now an empty `Wires`

object instead of the attribute raising a `NonImplementedError`.

[(#1821)](https://github.com/PennyLaneAI/pennylane/pull/1821)

* `qml.circuit\_drawer.MPLDrawer` will now automatically rotate and resize text to fit inside

the rectangle created by the `box\_gate` method.

[(#1764)](https://github.com/PennyLaneAI/pennylane/pull/1764)

* Operators now have a `label` method to determine how they are drawn. This will

eventually override the `RepresentationResolver` class.

[(#1678)](https://github.com/PennyLaneAI/pennylane/pull/1678)

* The operation `label` method now supports string variables.

[(#1815)](https://github.com/PennyLaneAI/pennylane/pull/1815)

* A new utility class `qml.BooleanFn` is introduced. It wraps a function that takes a single

argument and returns a Boolean.

[(#1734)](https://github.com/PennyLaneAI/pennylane/pull/1734)

After wrapping, `qml.BooleanFn` can be called like the wrapped function, and

multiple instances can be manipulated and combined with the bitwise operators

`&`, `|` and `~`.

* There is a new utility function `qml.math.is\_independent` that checks whether

a callable is independent of its arguments.

[(#1700)](https://github.com/PennyLaneAI/pennylane/pull/1700)

This function is experimental and might behave differently than expected.

Note that the test relies on both numerical and analytical checks, except

when using the PyTorch interface which only performs a numerical check.

It is known that there are edge cases on which this test will yield wrong

results, in particular non-smooth functions may be problematic.

For details, please refer to the

[is\_indpendent docstring](https://pennylane.readthedocs.io/en/latest/code/api/pennylane.math.is_independent.html).

* The `qml.beta.QNode` now supports the `qml.qnn` module.

[(#1748)](https://github.com/PennyLaneAI/pennylane/pull/1748)

* `@qml.beta.QNode` now supports the `qml.specs` transform.

[(#1739)](https://github.com/PennyLaneAI/pennylane/pull/1739)

* `qml.circuit\_drawer.drawable\_layers` and `qml.circuit\_drawer.drawable\_grid` process a list of

operations to layer positions for drawing.

[(#1639)](https://github.com/PennyLaneAI/pennylane/pull/1639)

* `qml.transforms.batch\_transform` now accepts `expand\_fn`s that take additional arguments and

keyword arguments. In fact, `expand\_fn` and `transform\_fn` now **must** have the same signature.

[(#1721)](https://github.com/PennyLaneAI/pennylane/pull/1721)

* The `qml.batch\_transform` decorator is now ignored during Sphinx builds, allowing

the correct signature to display in the built documentation.

[(#1733)](https://github.com/PennyLaneAI/pennylane/pull/1733)

* The tests for qubit operations are split into multiple files.

[(#1661)](https://github.com/PennyLaneAI/pennylane/pull/1661)

* The transform for the Jacobian of the classical preprocessing within a QNode,

`qml.transforms.classical\_jacobian`, now takes a keyword argument `argnum` to specify

the QNode argument indices with respect to which the Jacobian is computed.

[(#1645)](https://github.com/PennyLaneAI/pennylane/pull/1645)

An example for the usage of `argnum` is

```

@qml.qnode(dev)

def circuit(x, y, z):

    qml.RX(qml.math.sin(x), wires=0)

    qml.CNOT(wires=[0, 1])

    qml.RY(y \*\* 2, wires=1)

    qml.RZ(1 / z, wires=1)

    return qml.expval(qml.PauliZ(0))

jac\_fn = qml.transforms.classical\_jacobian(circuit, argnum=[1, 2])

```

The Jacobian can then be computed at specified parameters.

```

>>> x, y, z = np.array([0.1, -2.5, 0.71])

>>> jac\_fn(x, y, z)

(array([-0., -5., -0.]), array([-0. , -0. , -1.98373339]))

```

The returned arrays are the derivatives of the three parametrized gates in the circuit

with respect to `y` and `z` respectively.

There also are explicit tests for `classical\_jacobian` now, which previously was tested

implicitly via its use in the `metric\_tensor` transform.

For more usage details, please see the

[classical Jacobian docstring](https://pennylane.readthedocs.io/en/latest/code/api/pennylane.transforms.classical_jacobian.html).

* A new utility function `qml.math.is\_abstract(tensor)` has been added. This function

returns `True` if the tensor is *abstract*; that is, it has no value or shape.

This can occur if within a function that has been just-in-time compiled.

[(#1845)](https://github.com/PennyLaneAI/pennylane/pull/1845)

* `qml.circuit\_drawer.CircuitDrawer` can accept a string for the `charset` keyword, instead of

a `CharSet` object. [(#1640)](https://github.com/PennyLaneAI/pennylane/pull/1640)

* `qml.math.sort` will now return only the sorted torch tensor and not the corresponding indices,

making sort consistent across interfaces.

[(#1691)](https://github.com/PennyLaneAI/pennylane/pull/1691)

* Specific QNode execution options are now re-used by batch transforms

to execute transformed QNodes.

[(#1708)](https://github.com/PennyLaneAI/pennylane/pull/1708)

* To standardize across all optimizers, `qml.optimize.AdamOptimizer` now also uses `accumulation`

(in form of `collections.namedtuple`) to keep track of running quantities. Before it used three

variables `fm`, `sm` and `t`. [(#1757)](https://github.com/PennyLaneAI/pennylane/pull/1757)

### Breaking changes

* The operator attributes `has\_unitary\_generator`, `is\_composable\_rotation`,

`is\_self\_inverse`, `is\_symmetric\_over\_all\_wires`, and

`is\_symmetric\_over\_control\_wires` have been removed as attributes from the

base class. They have been replaced by the sets that store the names of

operations with similar properties in `ops/qubit/attributes.py`.

[(#1763)](https://github.com/PennyLaneAI/pennylane/pull/1763)

* The `qml.inv` function has been removed, `qml.adjoint` should be used

instead.

[(#1778)](https://github.com/PennyLaneAI/pennylane/pull/1778)

* The input signature of an `expand\_fn` used in a `batch\_transform`

now **must** have the same signature as the provided `transform\_fn`,

and vice versa.

[(#1721)](https://github.com/PennyLaneAI/pennylane/pull/1721)

* The `default.qubit.torch` device automatically determines if computations

should be run on a CPU or a GPU and doesn’t take a `torch\_device` argument

anymore.

[(#1705)](https://github.com/PennyLaneAI/pennylane/pull/1705)

* The utility function `qml.math.requires\_grad` now returns `True` when using Autograd

if and only if the `requires\_grad=True` attribute is set on the NumPy array. Previously,

this function would return `True` for *all* NumPy arrays and Python floats, unless

`requires\_grad=False` was explicitly set.

[(#1638)](https://github.com/PennyLaneAI/pennylane/pull/1638)

* The operation `qml.Interferometer` has been renamed `qml.InterferometerUnitary` in order to

distinguish it from the template `qml.templates.Interferometer`.

[(#1714)](https://github.com/PennyLaneAI/pennylane/pull/1714)

* The `qml.transforms.invisible` decorator has been replaced with `qml.tape.stop\_recording`, which

may act as a context manager as well as a decorator to ensure that contained logic is

non-recordable or non-queueable within a QNode or quantum tape context.

[(#1754)](https://github.com/PennyLaneAI/pennylane/pull/1754)

* Templates `SingleExcitationUnitary` and `DoubleExcitationUnitary` have been renamed

to `FermionicSingleExcitation` and `FermionicDoubleExcitation`, respectively.

[(#1822)](https://github.com/PennyLaneAI/pennylane/pull/1822)

### Deprecations

* Allowing cost functions to be differentiated using `qml.grad` or

`qml.jacobian` without explicitly marking parameters as trainable is being

deprecated, and will be removed in an upcoming release.

Please specify the `requires\_grad` attribute for every argument, or specify

`argnum` when using `qml.grad` or `qml.jacobian`.

[(#1773)](https://github.com/PennyLaneAI/pennylane/pull/1773)

The following raises a warning in v0.19.0 and will raise an error in

an upcoming release:

```

import pennylane as qml

dev = qml.device('default.qubit', wires=1)

@qml.qnode(dev)

def test(x):

    qml.RY(x, wires=[0])

    return qml.expval(qml.PauliZ(0))

par = 0.3

qml.grad(test)(par)

```

Preferred approaches include specifying the `requires\_grad` attribute:

```

import pennylane as qml

from pennylane import numpy as np

dev = qml.device('default.qubit', wires=1)

@qml.qnode(dev)

def test(x):

    qml.RY(x, wires=[0])

    return qml.expval(qml.PauliZ(0))

par = np.array(0.3, requires\_grad=True)

qml.grad(test)(par)

```

Or specifying the `argnum` argument when using `qml.grad` or `qml.jacobian`:

```

import pennylane as qml

dev = qml.device('default.qubit', wires=1)

@qml.qnode(dev)

def test(x):

    qml.RY(x, wires=[0])

    return qml.expval(qml.PauliZ(0))

par = 0.3

qml.grad(test, argnum=0)(par)

```

![](https://pennylane.readthedocs.io/en/latest/_static/requires_grad.png)

* The `default.tensor` device from the beta folder is no longer maintained

and has been deprecated. It will be removed in future releases.

[(#1851)](https://github.com/PennyLaneAI/pennylane/pull/1851)

* The `qml.metric\_tensor` and `qml.QNGOptimizer` keyword argument `diag\_approx`

is deprecated.

Approximations can be controlled with the more fine-grained `approx` keyword

argument, with `approx="block-diag"` (the default) reproducing the old

behaviour.

[(#1721)](https://github.com/PennyLaneAI/pennylane/pull/1721)

[(#1834)](https://github.com/PennyLaneAI/pennylane/pull/1834)

* The `template` decorator is now deprecated with a warning message and will be removed

in release `v0.20.0`. It has been removed from different PennyLane functions.

[(#1794)](https://github.com/PennyLaneAI/pennylane/pull/1794)

[(#1808)](https://github.com/PennyLaneAI/pennylane/pull/1808)

* The `qml.fourier.spectrum` function has been renamed to

`qml.fourier.circuit\_spectrum`, in order to clearly separate the new

`qnode\_spectrum` function from this one. `qml.fourier.spectrum` is now an

alias for `circuit\_spectrum` but is flagged for deprecation and will be

removed soon.

[(#1681)](https://github.com/PennyLaneAI/pennylane/pull/1681)

* The `init` module, which contains functions to generate random parameter

tensors for templates, is flagged for deprecation and will be removed in the

next release cycle. Instead, the templates’ `shape` method can be used to

get the desired shape of the tensor, which can then be generated manually.

[(#1689)](https://github.com/PennyLaneAI/pennylane/pull/1689)

To generate the parameter tensors, the `np.random.normal` and

`np.random.uniform` functions can be used (just like in the `init` module).

Considering the default arguments of these functions as of NumPy v1.21, some

non-default options were used by the `init` module:

	+ All functions generating normally distributed parameters used

	`np.random.normal` by passing `scale=0.1`;

	+ Most functions generating uniformly distributed parameters (except for

	certain CVQNN initializers) used `np.random.uniform` by passing

	`high=2\*math.pi`;

	+ The `cvqnn\_layers\_r\_uniform`, `cvqnn\_layers\_a\_uniform`,

	`cvqnn\_layers\_kappa\_uniform` functions used `np.random.uniform` by passing

	`high=0.1`.

* The `QNode.draw` method has been deprecated, and will be removed in an

upcoming release. Please use the `qml.draw` transform instead.

[(#1746)](https://github.com/PennyLaneAI/pennylane/pull/1746)

* The `QNode.metric\_tensor` method has been deprecated, and will be removed in

an upcoming release. Please use the `qml.metric\_tensor` transform instead.

[(#1638)](https://github.com/PennyLaneAI/pennylane/pull/1638)

* The `pad` parameter of the `qml.AmplitudeEmbedding` template has been removed.

It has instead been renamed to the `pad\_with` parameter.

[(#1805)](https://github.com/PennyLaneAI/pennylane/pull/1805)

### Bug fixes

* Fixes a bug where `qml.math.dot` failed to work with `@tf.function` autograph mode.

[(#1842)](https://github.com/PennyLaneAI/pennylane/pull/1842)

* Fixes a bug where in rare instances the parameters of a tape are returned unsorted

by `Tape.get\_parameters`.

[(#1836)](https://github.com/PennyLaneAI/pennylane/pull/1836)

* Fixes a bug with the arrow width in the `measure` of `qml.circuit\_drawer.MPLDrawer`.

[(#1823)](https://github.com/PennyLaneAI/pennylane/pull/1823)

* The helper functions `qml.math.block\_diag` and `qml.math.scatter\_element\_add`

now are entirely differentiable when using Autograd. Previously only indexed

entries of the block diagonal could be differentiated, while the derivative

w.r.t to the second argument of `qml.math.scatter\_element\_add` dispatched to

NumPy instead of Autograd.

[(#1816)](https://github.com/PennyLaneAI/pennylane/pull/1816)

[(#1818)](https://github.com/PennyLaneAI/pennylane/pull/1818)

* Fixes a bug such that the original shot vector information of a

device is preserved, so that outside the context manager the device

remains unchanged.

[(#1792)](https://github.com/PennyLaneAI/pennylane/pull/1792)

* Modifies `qml.math.take` to be compatible with a breaking change

released in JAX 0.2.24 and ensure that PennyLane supports this JAX

version.

[(#1769)](https://github.com/PennyLaneAI/pennylane/pull/1769)

* Fixes a bug where the GPU cannot be used with `qml.qnn.TorchLayer`.

[(#1705)](https://github.com/PennyLaneAI/pennylane/pull/1705)

* Fix a bug where the devices cache the same result for different observables

return types.

[(#1719)](https://github.com/PennyLaneAI/pennylane/pull/1719)

* Fixed a bug of the default circuit drawer where having more measurements

compared to the number of measurements on any wire raised a `KeyError`.

[(#1702)](https://github.com/PennyLaneAI/pennylane/pull/1702)

* Fix a bug where it was not possible to use `jax.jit` on a `QNode` when using

`QubitStateVector`.

[(#1683)](https://github.com/PennyLaneAI/pennylane/pull/1683)

* The device suite tests can now execute successfully if no shots configuration

variable is given.

[(#1641)](https://github.com/PennyLaneAI/pennylane/pull/1641)

* Fixes a bug where the `qml.gradients.param\_shift` transform would raise an

error while attempting to compute the variance of a QNode with ragged output.

[(#1646)](https://github.com/PennyLaneAI/pennylane/pull/1646)

* Fixes a bug in `default.mixed`, to ensure that returned probabilities are

always non-negative.

[(#1680)](https://github.com/PennyLaneAI/pennylane/pull/1680)

* Fixes a bug where gradient transforms would fail to apply to QNodes

containing classical processing.

[(#1699)](https://github.com/PennyLaneAI/pennylane/pull/1699)

* Fixes a bug where the the parameter-shift method was not correctly using the

fallback gradient function when *all* circuit parameters required the fallback.

[(#1782)](https://github.com/PennyLaneAI/pennylane/pull/1782)

### Documentation

* Adds a link to <https://pennylane.ai/qml/demonstrations.html> in the navbar.

[(#1624)](https://github.com/PennyLaneAI/pennylane/pull/1624)

* Corrects the docstring of `ExpvalCost` by adding `wires` to the signature of

the `ansatz` argument.

[(#1715)](https://github.com/PennyLaneAI/pennylane/pull/1715)

* Updated docstring examples using the `qchem.molecular\_hamiltonian` function.

[(#1724)](https://github.com/PennyLaneAI/pennylane/pull/1724)

* Updates the ‘Gradients and training’ quickstart guide to provide information

on gradient transforms.

[(#1751)](https://github.com/PennyLaneAI/pennylane/pull/1751)

* All instances of `qnode.draw()` have been updated to instead use the

transform `qml.draw(qnode)`.

[(#1750)](https://github.com/PennyLaneAI/pennylane/pull/1750)

* Add the `jax` interface in QNode Documentation.

[(#1755)](https://github.com/PennyLaneAI/pennylane/pull/1755)

* Reorganized all the templates related to quantum chemistry under a common

header `Quantum Chemistry templates`.

[(#1822)](https://github.com/PennyLaneAI/pennylane/pull/1822)

### Contributors

This release contains contributions from (in alphabetical order):

Catalina Albornoz, Juan Miguel Arrazola, Utkarsh Azad, Akash Narayanan B, Sam

Banning, Thomas Bromley, Jack Ceroni, Alain Delgado, Olivia Di Matteo, Andrew

Gardhouse, Anthony Hayes, Theodor Isacsson, David Ittah, Josh Izaac, Soran

Jahangiri, Nathan Killoran, Christina Lee, Guillermo Alonso-Linaje, Romain

Moyard, Lee James O’Riordan, Carrie-Anne Rubidge, Maria Schuld, Rishabh Singh,

Jay Soni, Ingrid Strandberg, Antal Száva, Teresa Tamayo-Mendoza, Rodrigo

Vargas, Cody Wang, David Wierichs, Moritz Willmann.

orphan

#### Release 0.18.0[¶](#release-0-18-0 "Permalink to this headline")

### New features since last release

#### PennyLane now comes packaged with `lightning.qubit`

* The C++-based [lightning.qubit](https://pennylane-lightning.readthedocs.io/en/stable/) device

is now included with installations of PennyLane.

[(#1663)](https://github.com/PennyLaneAI/pennylane/pull/1663)

The `lightning.qubit` device is a fast state-vector simulator equipped with the efficient

[adjoint method](https://arxiv.org/abs/2009.02823) for differentiating quantum circuits,

check out the plugin

[release notes](https://github.com/PennyLaneAI/pennylane-lightning/blob/v0.18.0/.github/CHANGELOG.md#new-features-since-last-release) for more details! The device can be accessed in the following way:

```

import pennylane as qml

wires = 3

layers = 2

dev = qml.device("lightning.qubit", wires=wires)

@qml.qnode(dev, diff\_method="adjoint")

def circuit(weights):

    qml.templates.StronglyEntanglingLayers(weights, wires=range(wires))

    return qml.expval(qml.PauliZ(0))

weights = qml.init.strong\_ent\_layers\_normal(layers, wires, seed=1967)

```

Evaluating circuits and their gradients on the device can be achieved using the standard approach:

```

>>> print(f"Circuit evaluated: {circuit(weights)}")

Circuit evaluated: 0.9801286266677633

>>> print(f"Circuit gradient:\n{qml.grad(circuit)(weights)}")

Circuit gradient:

[[[-9.35301749e-17 -1.63051504e-01 -4.14810501e-04]

 [-7.88816484e-17 -1.50136528e-04 -1.77922957e-04]

 [-5.20670796e-17 -3.92874550e-02 8.14523075e-05]]

 [[-1.14472273e-04 3.85963953e-02 -9.39190132e-18]

 [-5.76791765e-05 -9.78478343e-02 0.00000000e+00]

 [ 0.00000000e+00 0.00000000e+00 0.00000000e+00]]]

```

The adjoint method operates after a forward pass by iteratively applying

inverse gates to scan backwards through the circuit. The method is already

available in PennyLane’s `default.qubit` device, but the version provided by

`lightning.qubit` integrates with the C++ backend and is more performant, as

shown in the plot below:

![](https://raw.githubusercontent.com/PennyLaneAI/pennylane-lightning/master/doc/_static/lightning_adjoint.png)

#### Support for native backpropagation using PyTorch

* The built-in PennyLane simulator `default.qubit` now supports

backpropogation with PyTorch.

[(#1360)](https://github.com/PennyLaneAI/pennylane/pull/1360)

[(#1598)](https://github.com/PennyLaneAI/pennylane/pull/1598)

As a result, `default.qubit` can now use end-to-end classical backpropagation as

a means to compute gradients. End-to-end backpropagation can be faster than

the parameter-shift rule for computing quantum gradients when the number of

parameters to be optimized is large. This is now the default differentiation method when

using `default.qubit` with PyTorch.

Using this method, the created QNode is a ‘white-box’ that is

tightly integrated with your PyTorch computation, including

TorchScript and GPU support.

```

x = torch.tensor(0.43316321, dtype=torch.float64, requires\_grad=True)

y = torch.tensor(0.2162158, dtype=torch.float64, requires\_grad=True)

z = torch.tensor(0.75110998, dtype=torch.float64, requires\_grad=True)

p = torch.tensor([x, y, z], requires\_grad=True)

dev = qml.device("default.qubit", wires=1)

@qml.qnode(dev, interface="torch", diff\_method="backprop")

def circuit(x):

    qml.Rot(x[0], x[1], x[2], wires=0)

    return qml.expval(qml.PauliZ(0))

res = circuit(p)

res.backward()

```

```

>>> res = circuit(p)

>>> res.backward()

>>> print(p.grad)

tensor([-9.1798e-17, -2.1454e-01, -1.0511e-16], dtype=torch.float64)

```

#### Improved quantum optimization methods

* The `RotosolveOptimizer` now can tackle general parametrized circuits, and is no longer

restricted to single-qubit Pauli rotations.

[(#1489)](https://github.com/PennyLaneAI/pennylane/pull/1489)

This includes:

	+ layers of gates controlled by the same parameter,

	+ controlled variants of parametrized gates, and

	+ Hamiltonian time evolution.Note that the eigenvalue spectrum of the gate generator needs to be known to

use `RotosolveOptimizer` for a general gate, and it

is required to produce equidistant frequencies.

For details see [Vidal and Theis, 2018](https://arxiv.org/abs/1812.06323)

and [Wierichs, Izaac, Wang, Lin 2021](https://arxiv.org/abs/2107.12390).

Consider a circuit with a mixture of Pauli rotation gates, controlled Pauli rotations, and

single-parameter layers of Pauli rotations:

```

dev = qml.device('default.qubit', wires=3, shots=None)

@qml.qnode(dev)

def cost\_function(rot\_param, layer\_par, crot\_param):

    for i, par in enumerate(rot\_param):

        qml.RX(par, wires=i)

    for w in dev.wires:

        qml.RX(layer\_par, wires=w)

    for i, par in enumerate(crot\_param):

        qml.CRY(par, wires=[i, (i+1) % 3])

    return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1) @ qml.PauliZ(2))

```

This cost function has one frequency for each of the first `RX` rotation angles,

three frequencies for the layer of `RX` gates that depend on `layer\_par`, and two

frequencies for each of the `CRY` gate parameters. Rotosolve can then be used to minimize

the `cost\_function`:

```

# Initial parameters

init\_param = [

    np.array([0.3, 0.2, 0.67], requires\_grad=True),

    np.array(1.1, requires\_grad=True),

    np.array([-0.2, 0.1, -2.5], requires\_grad=True),

]

# Numbers of frequencies per parameter

num\_freqs = [[1, 1, 1], 3, [2, 2, 2]]

opt = qml.RotosolveOptimizer()

param = init\_param.copy()

```

In addition, the optimization technique for the Rotosolve substeps can be chosen via the

`optimizer` and `optimizer\_kwargs` keyword arguments and the minimized cost of the

intermediate univariate reconstructions can be read out via `full\_output`, including the

cost *after* the full Rotosolve step:

```

for step in range(3):

    param, cost, sub\_cost = opt.step\_and\_cost(

        cost\_function,

        \*param,

        num\_freqs=num\_freqs,

        full\_output=True,

        optimizer="brute",

    )

    print(f"Cost before step: {cost}")

    print(f"Minimization substeps: {np.round(sub\_cost, 6)}")

```

```

Cost before step: 0.042008210392535605

Minimization substeps: [-0.230905 -0.863336 -0.980072 -0.980072 -1. -1. -1. ]

Cost before step: -0.999999999068121

Minimization substeps: [-1. -1. -1. -1. -1. -1. -1.]

Cost before step: -1.0

Minimization substeps: [-1. -1. -1. -1. -1. -1. -1.]

```

For usage details please consider the [docstring of the optimizer](https://pennylane.readthedocs.io/en/stable/code/api/pennylane.RotosolveOptimizer.html?highlight=rotosolveoptimizer#pennylane.RotosolveOptimizer).

#### Faster, trainable, Hamiltonian simulations

* Hamiltonians are now trainable with respect to their coefficients.

[(#1483)](https://github.com/PennyLaneAI/pennylane/pull/1483)

```

from pennylane import numpy as np

dev = qml.device("default.qubit", wires=2)

@qml.qnode(dev)

def circuit(coeffs, param):

    qml.RX(param, wires=0)

    qml.RY(param, wires=0)

    return qml.expval(

        qml.Hamiltonian(coeffs, [qml.PauliX(0), qml.PauliZ(0)], simplify=True)

    )

coeffs = np.array([-0.05, 0.17])

param = np.array(1.7)

grad\_fn = qml.grad(circuit)

```

```

>>> grad\_fn(coeffs, param)

(array([-0.12777055, 0.0166009 ]), array(0.0917819))

```

Furthermore, a gradient recipe for Hamiltonian coefficients has been added. This makes it possible

to compute parameter-shift gradients of these coefficients on devices that natively

support Hamiltonians.

[(#1551)](https://github.com/PennyLaneAI/pennylane/pull/1551)

* Hamiltonians are now natively supported on the `default.qubit` device if `shots=None`.

This makes VQE workflows a lot faster in some cases.

[(#1551)](https://github.com/PennyLaneAI/pennylane/pull/1551)

[(#1596)](https://github.com/PennyLaneAI/pennylane/pull/1596)

![](https://pennylane.readthedocs.io/en/latest/_static/hamiltonian_expval_h_plot.png)

* The Hamiltonian can now store grouping information, which can be accessed by a device to

speed up computations of the expectation value of a Hamiltonian.

[(#1515)](https://github.com/PennyLaneAI/pennylane/pull/1515)

```

obs = [qml.PauliX(0), qml.PauliX(1), qml.PauliZ(0)]

coeffs = np.array([1., 2., 3.])

H = qml.Hamiltonian(coeffs, obs, grouping\_type='qwc')

```

Initialization with a `grouping\_type` other than `None` stores the indices

required to make groups of commuting observables and their coefficients.

```

>>> H.grouping\_indices

[[0, 1], [2]]

```

#### Create multi-circuit quantum transforms and custom gradient rules

* Custom gradient transforms can now be created using the new

`@qml.gradients.gradient\_transform` decorator on a batch-tape transform.

[(#1589)](https://github.com/PennyLaneAI/pennylane/pull/1589)

Quantum gradient transforms are a specific case of `qml.batch\_transform`.

Supported gradient transforms must be of the following form:

```

@qml.gradients.gradient\_transform

def my\_custom\_gradient(tape, argnum=None, \*\*kwargs):

    ...

    return gradient\_tapes, processing\_fn

```

Various built-in quantum gradient transforms are provided within the

`qml.gradients` module, including `qml.gradients.param\_shift`.

Once defined, quantum gradient transforms can be applied directly

to QNodes:

```

>>> @qml.qnode(dev)

... def circuit(x):

...     qml.RX(x, wires=0)

...     qml.CNOT(wires=[0, 1])

...     return qml.expval(qml.PauliZ(0))

>>> circuit(0.3)

tensor(0.95533649, requires\_grad=True)

>>> qml.gradients.param\_shift(circuit)(0.5)

array([[-0.47942554]])

```

Quantum gradient transforms are fully differentiable, allowing higher order derivatives to be

accessed:

```

>>> qml.grad(qml.gradients.param\_shift(circuit))(0.5)

tensor(-0.87758256, requires\_grad=True)

```

Refer to the page of [quantum gradient transforms](https://pennylane.readthedocs.io/en/stable/code/qml_gradients.html)

for more details.

* The ability to define *batch* transforms has been added via the new

`@qml.batch\_transform` decorator.

[(#1493)](https://github.com/PennyLaneAI/pennylane/pull/1493)

A batch transform is a transform that takes a single tape or QNode as input,

and executes multiple tapes or QNodes independently. The results may then be post-processed

before being returned.

For example, consider the following batch transform:

```

@qml.batch\_transform

def my\_transform(tape, a, b):

 """Generates two tapes, one with all RX replaced with RY,

 and the other with all RX replaced with RZ."""

    tape1 = qml.tape.JacobianTape()

    tape2 = qml.tape.JacobianTape()

    # loop through all operations on the input tape

    for op in tape.operations + tape.measurements:

        if op.name == "RX":

            with tape1:

                qml.RY(a \* qml.math.abs(op.parameters[0]), wires=op.wires)

            with tape2:

                qml.RZ(b \* qml.math.abs(op.parameters[0]), wires=op.wires)

        else:

            for t in [tape1, tape2]:

                with t:

                    qml.apply(op)

    def processing\_fn(results):

        return qml.math.sum(qml.math.stack(results))

    return [tape1, tape2], processing\_fn

```

We can transform a QNode directly using decorator syntax:

```

>>> @my\_transform(0.65, 2.5)

... @qml.qnode(dev)

... def circuit(x):

...     qml.Hadamard(wires=0)

...     qml.RX(x, wires=0)

...     return qml.expval(qml.PauliX(0))

>>> print(circuit(-0.5))

1.2629730888100839

```

Batch tape transforms are fully differentiable:

```

>>> gradient = qml.grad(circuit)(-0.5)

>>> print(gradient)

2.5800122591960153

```

Batch transforms can also be applied to existing QNodes,

```

>>> new\_qnode = my\_transform(existing\_qnode, \*transform\_weights)

>>> new\_qnode(weights)

```

or to tapes (in which case, the processed tapes and classical post-processing

functions are returned):

```

>>> tapes, fn = my\_transform(tape, 0.65, 2.5)

>>> from pennylane.interfaces.batch import execute

>>> dev = qml.device("default.qubit", wires=1)

>>> res = execute(tapes, dev, interface="autograd", gradient\_fn=qml.gradients.param\_shift)

1.2629730888100839

```

* Vector-Jacobian product transforms have been added to the `qml.gradients` package.

[(#1494)](https://github.com/PennyLaneAI/pennylane/pull/1494)

The new transforms include:

	+ `qml.gradients.vjp`

	+ `qml.gradients.batch\_vjp`

* Support for differentiable execution of batches of circuits has been

added, via the beta `pennylane.interfaces.batch` module.

[(#1501)](https://github.com/PennyLaneAI/pennylane/pull/1501)

[(#1508)](https://github.com/PennyLaneAI/pennylane/pull/1508)

[(#1542)](https://github.com/PennyLaneAI/pennylane/pull/1542)

[(#1549)](https://github.com/PennyLaneAI/pennylane/pull/1549)

[(#1608)](https://github.com/PennyLaneAI/pennylane/pull/1608)

[(#1618)](https://github.com/PennyLaneAI/pennylane/pull/1618)

[(#1637)](https://github.com/PennyLaneAI/pennylane/pull/1637)

For now, this is a low-level feature, and will be integrated into the QNode in a future release.

For example:

```

from pennylane.interfaces.batch import execute

def cost\_fn(x):

    with qml.tape.JacobianTape() as tape1:

        qml.RX(x[0], wires=[0])

        qml.RY(x[1], wires=[1])

        qml.CNOT(wires=[0, 1])

        qml.var(qml.PauliZ(0) @ qml.PauliX(1))

    with qml.tape.JacobianTape() as tape2:

        qml.RX(x[0], wires=0)

        qml.RY(x[0], wires=1)

        qml.CNOT(wires=[0, 1])

        qml.probs(wires=1)

    result = execute(

        [tape1, tape2], dev,

        gradient\_fn=qml.gradients.param\_shift,

        interface="autograd"

    )

    return result[0] + result[1][0, 0]

res = qml.grad(cost\_fn)(params)

```

### Improvements

* A new operation `qml.SISWAP` has been added, the square-root of the `qml.ISWAP` operation.

[(#1563)](https://github.com/PennyLaneAI/pennylane/pull/1563)

* The `frobenius\_inner\_product` function has been moved to the `qml.math`

module, and is now differentiable using all autodiff frameworks.

[(#1388)](https://github.com/PennyLaneAI/pennylane/pull/1388)

* A warning is raised to inform the user that specifying a list of shots is

only supported for `QubitDevice` based devices.

[(#1659)](https://github.com/PennyLaneAI/pennylane/pull/1659)

* The `qml.circuit\_drawer.MPLDrawer` class provides manual circuit drawing

functionality using Matplotlib. While not yet integrated with automatic circuit

drawing, this class provides customization and control.

[(#1484)](https://github.com/PennyLaneAI/pennylane/pull/1484)

```

from pennylane.circuit\_drawer import MPLDrawer

drawer = MPLDrawer(n\_wires=3, n\_layers=3)

drawer.label([r"$|\Psi\rangle$", r"$|\theta\rangle$", "aux"])

drawer.box\_gate(layer=0, wires=[0, 1, 2], text="Entangling Layers", text\_options={'rotation': 'vertical'})

drawer.box\_gate(layer=1, wires=[0, 1], text="U(θ)")

drawer.CNOT(layer=2, wires=[1, 2])

drawer.measure(layer=3, wires=2)

drawer.fig.suptitle('My Circuit', fontsize='xx-large')

```

![](https://pennylane.readthedocs.io/en/latest/_static/drawer/example_release_notes.png)

* The slowest tests, more than 1.5 seconds, now have the pytest mark `slow`, and can be

selected or deselected during local execution of tests.

[(#1633)](https://github.com/PennyLaneAI/pennylane/pull/1633)

* The device test suite has been expanded to cover more qubit operations and observables.

[(#1510)](https://github.com/PennyLaneAI/pennylane/pull/1510)

* The `MultiControlledX` class now inherits from `Operation` instead of `ControlledQubitUnitary` which makes the `MultiControlledX` gate a non-parameterized gate.

[(#1557)](https://github.com/PennyLaneAI/pennylane/pull/1557)

* The `utils.sparse\_hamiltonian` function can now deal with non-integer

wire labels, and it throws an error for the edge case of observables that are

created from multi-qubit operations.

[(#1550)](https://github.com/PennyLaneAI/pennylane/pull/1550)

* Added the matrix attribute to `qml.templates.subroutines.GroverOperator`

[(#1553)](https://github.com/PennyLaneAI/pennylane/pull/1553)

* The `tape.to\_openqasm()` method now has a `measure\_all` argument that specifies whether the

serialized OpenQASM script includes computational basis measurements on all of the qubits or

just those specified by the tape.

[(#1559)](https://github.com/PennyLaneAI/pennylane/pull/1559)

* An error is now raised when no arguments are passed to an observable, to

inform that wires have not been supplied.

[(#1547)](https://github.com/PennyLaneAI/pennylane/pull/1547)

* The `group\_observables` transform is now differentiable.

[(#1483)](https://github.com/PennyLaneAI/pennylane/pull/1483)

For example:

```

import jax

from jax import numpy as jnp

coeffs = jnp.array([1., 2., 3.])

obs = [PauliX(wires=0), PauliX(wires=1), PauliZ(wires=1)]

def group(coeffs, select=None):

  \_, grouped\_coeffs = qml.grouping.group\_observables(obs, coeffs)

  # in this example, grouped\_coeffs is a list of two jax tensors

  # [Array([1., 2.], dtype=float32), Array([3.], dtype=float32)]

  return grouped\_coeffs[select]

jac\_fn = jax.jacobian(group)

```

```

>>> jac\_fn(coeffs, select=0)

[[1. 0. 0.]

[0. 1. 0.]]

>>> jac\_fn(coeffs, select=1)

[[0., 0., 1.]]

```

* The tape does not verify any more that all Observables have owners in the annotated queue.

[(#1505)](https://github.com/PennyLaneAI/pennylane/pull/1505)

This allows manipulation of Observables inside a tape context. An example is

`expval(Tensor(qml.PauliX(0), qml.Identity(1)).prune())` which makes the expval

an owner of the pruned tensor and its constituent observables, but leaves the

original tensor in the queue without an owner.

* The `qml.ResetError` is now supported for `default.mixed` device.

[(#1541)](https://github.com/PennyLaneAI/pennylane/pull/1541)

* `QNode.diff\_method` will now reflect which method was selected from `diff\_method="best"`.

[(#1568)](https://github.com/PennyLaneAI/pennylane/pull/1568)

* QNodes now support `diff\_method=None`. This works the same as `interface=None`. Such QNodes accept

floats, ints, lists and NumPy arrays and return NumPy output but can not be differentiated.

[(#1585)](https://github.com/PennyLaneAI/pennylane/pull/1585)

* QNodes now include validation to warn users if a supplied keyword argument is

not one of the recognized arguments.

[(#1591)](https://github.com/PennyLaneAI/pennylane/pull/1591)

### Breaking changes

* The `QFT` operation has been moved, and is now accessible via

`pennylane.templates.QFT`.

[(#1548)](https://github.com/PennyLaneAI/pennylane/pull/1548)

* Specifying `shots=None` with `qml.sample` was previously deprecated.

From this release onwards, setting `shots=None` when sampling will

raise an error also for `default.qubit.jax`.

[(#1629)](https://github.com/PennyLaneAI/pennylane/pull/1629)

* An error is raised during QNode creation when a user requests backpropagation on

a device with finite-shots.

[(#1588)](https://github.com/PennyLaneAI/pennylane/pull/1588)

* The class `qml.Interferometer` is deprecated and will be renamed `qml.InterferometerUnitary`

after one release cycle.

[(#1546)](https://github.com/PennyLaneAI/pennylane/pull/1546)

* All optimizers except for Rotosolve and Rotoselect now have a public attribute `stepsize`.

Temporary backward compatibility has been added to support the use of `\_stepsize` for one

release cycle. `update\_stepsize` method is deprecated.

[(#1625)](https://github.com/PennyLaneAI/pennylane/pull/1625)

### Bug fixes

* Fixed a bug with shot vectors and `Device` base class.

[(#1666)](https://github.com/PennyLaneAI/pennylane/pull/1666)

* Fixed a bug where `@jax.jit` would fail on a QNode that used `qml.QubitStateVector`.

[(#1649)](https://github.com/PennyLaneAI/pennylane/pull/1649)

* Fixed a bug related to an edge case of single-qubit `zyz\_decomposition` when

only off-diagonal elements are present.

[(#1643)](https://github.com/PennyLaneAI/pennylane/pull/1643)

* `MottonenStatepreparation` can now be run with a single wire label not in a list.

[(#1620)](https://github.com/PennyLaneAI/pennylane/pull/1620)

* Fixed the circuit representation of CY gates to align with CNOT and CZ gates when calling the circuit drawer.

[(#1504)](https://github.com/PennyLaneAI/pennylane/issues/1504)

* Dask and CVXPY dependent tests are skipped if those packages are not installed.

[(#1617)](https://github.com/PennyLaneAI/pennylane/pull/1617)

* The `qml.layer` template now works with tensorflow variables.

[(#1615)](https://github.com/PennyLaneAI/pennylane/pull/1615)

* Remove `QFT` from possible operations in `default.qubit` and `default.mixed`.

[(#1600)](https://github.com/PennyLaneAI/pennylane/pull/1600)

* Fixed a bug when computing expectations of Hamiltonians using TensorFlow.

[(#1586)](https://github.com/PennyLaneAI/pennylane/pull/1586)

* Fixed a bug when computing the specs of a circuit with a Hamiltonian

observable.

[(#1533)](https://github.com/PennyLaneAI/pennylane/pull/1533)

### Documentation

* The `qml.Identity` operation is placed under the sections Qubit observables and CV observables.

[(#1576)](https://github.com/PennyLaneAI/pennylane/pull/1576)

* Updated the documentation of `qml.grouping`, `qml.kernels` and `qml.qaoa` modules to present

the list of functions first followed by the technical details of the module.

[(#1581)](https://github.com/PennyLaneAI/pennylane/pull/1581)

* Recategorized Qubit operations into new and existing categories so that code for each

operation is easier to locate.

[(#1566)](https://github.com/PennyLaneAI/pennylane/pull/1583)

### Contributors

This release contains contributions from (in alphabetical order):

Vishnu Ajith, Akash Narayanan B, Thomas Bromley, Olivia Di Matteo, Sahaj

Dhamija, Tanya Garg, Anthony Hayes, Theodor Isacsson, Josh Izaac, Prateek Jain,

Ankit Khandelwal, Nathan Killoran, Christina Lee, Ian McLean, Johannes Jakob

Meyer, Romain Moyard, Lee James O’Riordan, Esteban Payares, Pratul Saini, Maria

Schuld, Arshpreet Singh, Jay Soni, Ingrid Strandberg, Antal Száva, Slimane

Thabet, David Wierichs, Vincent Wong.

orphan

#### Release 0.17.0[¶](#release-0-17-0 "Permalink to this headline")

### New features since the last release

#### Circuit optimization

* PennyLane can now perform quantum circuit optimization using the

top-level transform `qml.compile`. The `compile` transform allows you

to chain together sequences of tape and quantum function transforms

into custom circuit optimization pipelines.

[(#1475)](https://github.com/PennyLaneAI/pennylane/pull/1475)

For example, take the following decorated quantum function:

```

dev = qml.device('default.qubit', wires=[0, 1, 2])

@qml.qnode(dev)

@qml.compile()

def qfunc(x, y, z):

    qml.Hadamard(wires=0)

    qml.Hadamard(wires=1)

    qml.Hadamard(wires=2)

    qml.RZ(z, wires=2)

    qml.CNOT(wires=[2, 1])

    qml.RX(z, wires=0)

    qml.CNOT(wires=[1, 0])

    qml.RX(x, wires=0)

    qml.CNOT(wires=[1, 0])

    qml.RZ(-z, wires=2)

    qml.RX(y, wires=2)

    qml.PauliY(wires=2)

    qml.CZ(wires=[1, 2])

    return qml.expval(qml.PauliZ(wires=0))

```

The default behaviour of `qml.compile` is to apply a sequence of three

transforms: `commute\_controlled`, `cancel\_inverses`, and then `merge\_rotations`.

```

>>> print(qml.draw(qfunc)(0.2, 0.3, 0.4))

 0: ──H───RX(0.6)──────────────────┤ ⟨Z⟩

 1: ──H──╭X────────────────────╭C──┤

 2: ──H──╰C────────RX(0.3)──Y──╰Z──┤

```

The `qml.compile` transform is flexible and accepts a custom pipeline

of tape and quantum function transforms (you can even write your own!).

For example, if we wanted to only push single-qubit gates through

controlled gates and cancel adjacent inverses, we could do:

```

from pennylane.transforms import commute\_controlled, cancel\_inverses

pipeline = [commute\_controlled, cancel\_inverses]

@qml.qnode(dev)

@qml.compile(pipeline=pipeline)

def qfunc(x, y, z):

    qml.Hadamard(wires=0)

    qml.Hadamard(wires=1)

    qml.Hadamard(wires=2)

    qml.RZ(z, wires=2)

    qml.CNOT(wires=[2, 1])

    qml.RX(z, wires=0)

    qml.CNOT(wires=[1, 0])

    qml.RX(x, wires=0)

    qml.CNOT(wires=[1, 0])

    qml.RZ(-z, wires=2)

    qml.RX(y, wires=2)

    qml.PauliY(wires=2)

    qml.CZ(wires=[1, 2])

    return qml.expval(qml.PauliZ(wires=0))

```

```

>>> print(qml.draw(qfunc)(0.2, 0.3, 0.4))

 0: ──H───RX(0.4)──RX(0.2)────────────────────────────┤ ⟨Z⟩

 1: ──H──╭X───────────────────────────────────────╭C──┤

 2: ──H──╰C────────RZ(0.4)──RZ(-0.4)──RX(0.3)──Y──╰Z──┤

```

The following compilation transforms have been added and are also available

to use, either independently, or within a `qml.compile` pipeline:

	+ `commute\_controlled`: push commuting single-qubit gates through controlled operations.

	[(#1464)](https://github.com/PennyLaneAI/pennylane/pull/1464)

	+ `cancel\_inverses`: removes adjacent pairs of operations that cancel out.

	[(#1455)](https://github.com/PennyLaneAI/pennylane/pull/1455)

	+ `merge\_rotations`: combines adjacent rotation gates of

	the same type into a single gate, including controlled rotations.

	[(#1455)](https://github.com/PennyLaneAI/pennylane/pull/1455)

	+ `single\_qubit\_fusion`: acts on all sequences of

	single-qubit operations in a quantum function, and converts each

	sequence to a single `Rot` gate.

	[(#1458)](https://github.com/PennyLaneAI/pennylane/pull/1458)For more details on `qml.compile` and the available compilation transforms, see

[the compilation documentation](https://pennylane.readthedocs.io/en/stable/code/qml_transforms.html#transforms-for-circuit-compilation).

#### QNodes are even more powerful

* Computational basis samples directly from the underlying device can

now be returned directly from QNodes via `qml.sample()`.

[(#1441)](https://github.com/PennyLaneAI/pennylane/pull/1441)

```

dev = qml.device("default.qubit", wires=3, shots=5)

@qml.qnode(dev)

def circuit\_1():

    qml.Hadamard(wires=0)

    qml.Hadamard(wires=1)

    return qml.sample()

@qml.qnode(dev)

def circuit\_2():

    qml.Hadamard(wires=0)

    qml.Hadamard(wires=1)

    return qml.sample(wires=[0,2])    # no observable provided and wires specified

```

```

>>> print(circuit\_1())

[[1, 0, 0],

 [1, 1, 0],

 [1, 0, 0],

 [0, 0, 0],

 [0, 1, 0]]

>>> print(circuit\_2())

[[1, 0],

 [1, 0],

 [1, 0],

 [0, 0],

 [0, 0]]

>>> print(qml.draw(circuit\_2)())

 0: ──H──╭┤ Sample[basis]

 1: ──H──│┤

 2: ─────╰┤ Sample[basis]

```

* The new `qml.apply` function can be used to add operations that might have

already been instantiated elsewhere to the QNode and other queuing contexts:

[(#1433)](https://github.com/PennyLaneAI/pennylane/pull/1433)

```

op = qml.RX(0.4, wires=0)

dev = qml.device("default.qubit", wires=2)

@qml.qnode(dev)

def circuit(x):

    qml.RY(x, wires=0)

    qml.apply(op)

    return qml.expval(qml.PauliZ(0))

```

```

>>> print(qml.draw(circuit)(0.6))

0: ──RY(0.6)──RX(0.4)──┤ ⟨Z⟩

```

Previously instantiated measurements can also be applied to QNodes.

#### Device Resource Tracker

* The new Device Tracker capabilities allows for flexible and versatile tracking of executions,

even inside parameter-shift gradients. This functionality will improve the ease of monitoring

large batches and remote jobs.

[(#1355)](https://github.com/PennyLaneAI/pennylane/pull/1355)

```

dev = qml.device('default.qubit', wires=1, shots=100)

@qml.qnode(dev, diff\_method="parameter-shift")

def circuit(x):

    qml.RX(x, wires=0)

    return qml.expval(qml.PauliZ(0))

x = np.array(0.1)

with qml.Tracker(circuit.device) as tracker:

    qml.grad(circuit)(x)

```

```

>>> tracker.totals

{'executions': 3, 'shots': 300, 'batches': 1, 'batch\_len': 2}

>>> tracker.history

{'executions': [1, 1, 1],

 'shots': [100, 100, 100],

 'batches': [1],

 'batch\_len': [2]}

>>> tracker.latest

{'batches': 1, 'batch\_len': 2}

```

Users can also provide a custom function to the `callback` keyword that gets called each time

the information is updated. This functionality allows users to monitor remote jobs or large

parameter-shift batches.

```

>>> def shots\_info(totals, history, latest):

...     print("Total shots: ", totals['shots'])

>>> with qml.Tracker(circuit.device, callback=shots\_info) as tracker:

...     qml.grad(circuit)(0.1)

Total shots: 100

Total shots: 200

Total shots: 300

Total shots: 300

```

#### Containerization support

* Docker support for building PennyLane with support for all interfaces (TensorFlow,

Torch, and Jax), as well as device plugins and QChem, for GPUs and CPUs, has been added.

[(#1391)](https://github.com/PennyLaneAI/pennylane/pull/1391)

The build process using Docker and `make` requires that the repository source

code is cloned or downloaded from GitHub. Visit the the detailed description

for an [extended list of

options](https://pennylane.readthedocs.io/en/stable/development/guide/installation.html#installation).

#### Improved Hamiltonian simulations

* Added a sparse Hamiltonian observable and the functionality to support computing its expectation

value with `default.qubit`. [(#1398)](https://github.com/PennyLaneAI/pennylane/pull/1398)

For example, the following QNode returns the expectation value of a sparse Hamiltonian:

```

dev = qml.device("default.qubit", wires=2)

@qml.qnode(dev, diff\_method="parameter-shift")

def circuit(param, H):

    qml.PauliX(0)

    qml.SingleExcitation(param, wires=[0, 1])

    return qml.expval(qml.SparseHamiltonian(H, [0, 1]))

```

We can execute this QNode, passing in a sparse identity matrix:

```

>>> print(circuit([0.5], scipy.sparse.eye(4).tocoo()))

0.9999999999999999

```

The expectation value of the sparse Hamiltonian is computed directly, which leads to executions

that are faster by orders of magnitude. Note that “parameter-shift” is the only differentiation

method that is currently supported when the observable is a sparse Hamiltonian.

* VQE problems can now be intuitively set up by passing the Hamiltonian

as an observable. [(#1474)](https://github.com/PennyLaneAI/pennylane/pull/1474)

```

dev = qml.device("default.qubit", wires=2)

H = qml.Hamiltonian([1., 2., 3.],  [qml.PauliZ(0), qml.PauliY(0), qml.PauliZ(1)])

w = qml.init.strong\_ent\_layers\_uniform(1, 2, seed=1967)

@qml.qnode(dev)

def circuit(w):

    qml.templates.StronglyEntanglingLayers(w, wires=range(2))

    return qml.expval(H)

```

```

>>> print(circuit(w))

-1.5133943637878295

>>> print(qml.grad(circuit)(w))

[[[-8.32667268e-17 1.39122955e+00 -9.12462052e-02]

[ 1.02348685e-16 -7.77143238e-01 -1.74708049e-01]]]

```

Note that other measurement types like `var(H)` or `sample(H)`, as well

as multiple expectations like `expval(H1), expval(H2)` are not supported.

* Added functionality to compute the sparse matrix representation of a `qml.Hamiltonian` object.

[(#1394)](https://github.com/PennyLaneAI/pennylane/pull/1394)

#### New gradients module

* A new gradients module `qml.gradients` has been added, which provides

differentiable quantum gradient transforms.

[(#1476)](https://github.com/PennyLaneAI/pennylane/pull/1476)

[(#1479)](https://github.com/PennyLaneAI/pennylane/pull/1479)

[(#1486)](https://github.com/PennyLaneAI/pennylane/pull/1486)

Available quantum gradient transforms include:

	+ `qml.gradients.finite\_diff`

	+ `qml.gradients.param\_shift`

	+ `qml.gradients.param\_shift\_cv`For example,

```

>>> params = np.array([0.3,0.4,0.5], requires\_grad=True)

>>> with qml.tape.JacobianTape() as tape:

...     qml.RX(params[0], wires=0)

...     qml.RY(params[1], wires=0)

...     qml.RX(params[2], wires=0)

...     qml.expval(qml.PauliZ(0))

...     qml.var(qml.PauliZ(0))

>>> tape.trainable\_params = {0, 1, 2}

>>> gradient\_tapes, fn = qml.gradients.finite\_diff(tape)

>>> res = dev.batch\_execute(gradient\_tapes)

>>> fn(res)

array([[-0.69688381, -0.32648317, -0.68120105],

 [ 0.8788057 , 0.41171179, 0.85902895]])

```

#### Even more new operations and templates

* Grover Diffusion Operator template added.

[(#1442)](https://github.com/PennyLaneAI/pennylane/pull/1442)

For example, if we have an oracle that marks the “all ones” state with a

negative sign:

```

n\_wires = 3

wires = list(range(n\_wires))

def oracle():

    qml.Hadamard(wires[-1])

    qml.Toffoli(wires=wires)

    qml.Hadamard(wires[-1])

```

We can perform [Grover’s Search Algorithm](https://en.wikipedia.org/wiki/Grover%27s_algorithm):

```

dev = qml.device('default.qubit', wires=wires)

@qml.qnode(dev)

def GroverSearch(num\_iterations=1):

    for wire in wires:

        qml.Hadamard(wire)

    for \_ in range(num\_iterations):

        oracle()

        qml.templates.GroverOperator(wires=wires)

    return qml.probs(wires)

```

We can see this circuit yields the marked state with high probability:

```

>>> GroverSearch(num\_iterations=1)

tensor([0.03125, 0.03125, 0.03125, 0.03125, 0.03125, 0.03125, 0.03125,

 0.78125], requires\_grad=True)

>>> GroverSearch(num\_iterations=2)

tensor([0.0078125, 0.0078125, 0.0078125, 0.0078125, 0.0078125, 0.0078125,

 0.0078125, 0.9453125], requires\_grad=True)

```

* A decomposition has been added to `QubitUnitary` that makes the

single-qubit case fully differentiable in all interfaces. Furthermore,

a quantum function transform, `unitary\_to\_rot()`, has been added to decompose all

single-qubit instances of `QubitUnitary` in a quantum circuit.

[(#1427)](https://github.com/PennyLaneAI/pennylane/pull/1427)

Instances of `QubitUnitary` may now be decomposed directly to `Rot`

operations, or `RZ` operations if the input matrix is diagonal. For

example, let

```

>>> U = np.array([

 [-0.28829348-0.78829734j, 0.30364367+0.45085995j],

 [ 0.53396245-0.10177564j, 0.76279558-0.35024096j]

])

```

Then, we can compute the decomposition as:

```

>>> qml.QubitUnitary.decomposition(U, wires=0)

[Rot(-0.24209530281458358, 1.1493817777199102, 1.733058145303424, wires=[0])]

```

We can also apply the transform directly to a quantum function, and compute the

gradients of parameters used to construct the unitary matrices.

```

def qfunc\_with\_qubit\_unitary(angles):

    z, x = angles[0], angles[1]

    Z\_mat = np.array([[np.exp(-1j \* z / 2), 0.0], [0.0, np.exp(1j \* z / 2)]])

    c = np.cos(x / 2)

    s = np.sin(x / 2) \* 1j

    X\_mat = np.array([[c, -s], [-s, c]])

    qml.Hadamard(wires="a")

    qml.QubitUnitary(Z\_mat, wires="a")

    qml.QubitUnitary(X\_mat, wires="b")

    qml.CNOT(wires=["b", "a"])

    return qml.expval(qml.PauliX(wires="a"))

```

```

>>> dev = qml.device("default.qubit", wires=["a", "b"])

>>> transformed\_qfunc = qml.transforms.unitary\_to\_rot(qfunc\_with\_qubit\_unitary)

>>> transformed\_qnode = qml.QNode(transformed\_qfunc, dev)

>>> input = np.array([0.3, 0.4], requires\_grad=True)

>>> transformed\_qnode(input)

tensor(0.95533649, requires\_grad=True)

>>> qml.grad(transformed\_qnode)(input)

array([-0.29552021, 0. ])

```

* Ising YY gate functionality added.

[(#1358)](https://github.com/PennyLaneAI/pennylane/pull/1358)

### Improvements

* The tape does not verify any more that all Observables have owners in the annotated queue.

[(#1505)](https://github.com/PennyLaneAI/pennylane/pull/1505)

This allows manipulation of Observables inside a tape context. An example is

`expval(Tensor(qml.PauliX(0), qml.Identity(1)).prune())` which makes the expval an owner

of the pruned tensor and its constituent observables, but leaves the original tensor in

the queue without an owner.

* The `step` and `step\_and\_cost` methods of `QNGOptimizer` now accept a custom `grad\_fn`

keyword argument to use for gradient computations.

[(#1487)](https://github.com/PennyLaneAI/pennylane/pull/1487)

* The precision used by `default.qubit.jax` now matches the float precision

indicated by

```

from jax.config import config

config.read('jax\_enable\_x64')

```

where `True` means `float64`/`complex128` and `False` means `float32`/`complex64`.

[(#1485)](https://github.com/PennyLaneAI/pennylane/pull/1485)

* The `./pennylane/ops/qubit.py` file is broken up into a folder of six separate files.

[(#1467)](https://github.com/PennyLaneAI/pennylane/pull/1467)

* Changed to using commas as the separator of wires in the string

representation of `qml.Hamiltonian` objects for multi-qubit terms.

[(#1465)](https://github.com/PennyLaneAI/pennylane/pull/1465)

* Changed to using `np.object\_` instead of `np.object` as per the NumPy

deprecations starting version 1.20.

[(#1466)](https://github.com/PennyLaneAI/pennylane/pull/1466)

* Change the order of the covariance matrix and the vector of means internally

in `default.gaussian`. [(#1331)](https://github.com/PennyLaneAI/pennylane/pull/1331)

* Added the `id` attribute to templates.

[(#1438)](https://github.com/PennyLaneAI/pennylane/pull/1438)

* The `qml.math` module, for framework-agnostic tensor manipulation,

has two new functions available:

[(#1490)](https://github.com/PennyLaneAI/pennylane/pull/1490)

	+ `qml.math.get\_trainable\_indices(sequence\_of\_tensors)`: returns the indices corresponding to

	trainable tensors in the input sequence.

	+ `qml.math.unwrap(sequence\_of\_tensors)`: unwraps a sequence of tensor-like objects to NumPy

	arrays.In addition, the behaviour of `qml.math.requires\_grad` has been improved in order to

correctly determine trainability during Autograd and JAX backwards passes.

* A new tape method, `tape.unwrap()` is added. This method is a context manager; inside the

context, the tape’s parameters are unwrapped to NumPy arrays and floats, and the trainable

parameter indices are set.

[(#1491)](https://github.com/PennyLaneAI/pennylane/pull/1491)

These changes are temporary, and reverted on exiting the context.

```

>>> with tf.GradientTape():

...     with qml.tape.QuantumTape() as tape:

...         qml.RX(tf.Variable(0.1), wires=0)

...         qml.RY(tf.constant(0.2), wires=0)

...         qml.RZ(tf.Variable(0.3), wires=0)

...     with tape.unwrap():

...         print("Trainable params:", tape.trainable\_params)

...         print("Unwrapped params:", tape.get\_parameters())

Trainable params: {0, 2}

Unwrapped params: [0.1, 0.3]

>>> print("Original parameters:", tape.get\_parameters())

Original parameters: [<tf.Variable 'Variable:0' shape=() dtype=float32, numpy=0.1>,

 <tf.Variable 'Variable:0' shape=() dtype=float32, numpy=0.3>]

```

In addition, `qml.tape.Unwrap` is a context manager that unwraps multiple tapes:

```

>>> with qml.tape.Unwrap(tape1, tape2):

```

### Breaking changes

* Removed the deprecated tape methods `get\_resources` and `get\_depth` as they are

superseded by the `specs` tape attribute.

[(#1522)](https://github.com/PennyLaneAI/pennylane/pull/1522)

* Specifying `shots=None` with `qml.sample` was previously deprecated.

From this release onwards, setting `shots=None` when sampling will

raise an error.

[(#1522)](https://github.com/PennyLaneAI/pennylane/pull/1522)

* The existing `pennylane.collections.apply` function is no longer accessible

via `qml.apply`, and needs to be imported directly from the `collections`

package.

[(#1358)](https://github.com/PennyLaneAI/pennylane/pull/1358)

### Bug fixes

* Fixes a bug in `qml.adjoint` and `qml.ctrl`

where the adjoint of operations outside of a `QNode` or a `QuantumTape` could

not be obtained.

[(#1532)](https://github.com/PennyLaneAI/pennylane/pull/1532)

* Fixes a bug in `GradientDescentOptimizer` and `NesterovMomentumOptimizer`

where a cost function with one trainable parameter and non-trainable

parameters raised an error.

[(#1495)](https://github.com/PennyLaneAI/pennylane/pull/1495)

* Fixed an example in the documentation’s

[introduction to numpy gradients](https://pennylane.readthedocs.io/en/stable/introduction/interfaces/numpy.html), where

the wires were a non-differentiable argument to the QNode.

[(#1499)](https://github.com/PennyLaneAI/pennylane/pull/1499)

* Fixed a bug where the adjoint of `qml.QFT` when using the `qml.adjoint` function

was not correctly computed.

[(#1451)](https://github.com/PennyLaneAI/pennylane/pull/1451)

* Fixed the differentiability of the operation`IsingYY` for Autograd, Jax and Tensorflow.

[(#1425)](https://github.com/PennyLaneAI/pennylane/pull/1425)

* Fixed a bug in the `torch` interface that prevented gradients from being

computed on a GPU. [(#1426)](https://github.com/PennyLaneAI/pennylane/pull/1426)

* Quantum function transforms now preserve the format of the measurement

results, so that a single measurement returns a single value rather than

an array with a single element. [(#1434)](https://github.com/PennyLaneAI/pennylane/pull/1434)

* Fixed a bug in the parameter-shift Hessian implementation, which resulted

in the incorrect Hessian being returned for a cost function

that performed post-processing on a vector-valued QNode.

[(#1436)](https://github.com/PennyLaneAI/pennylane/pull/1436)

* Fixed a bug in the initialization of `QubitUnitary` where the size of

the matrix was not checked against the number of wires.

[(#1439)](https://github.com/PennyLaneAI/pennylane/pull/1439)

### Documentation

* Improved Contribution Guide and Pull Requests Guide.

[(#1461)](https://github.com/PennyLaneAI/pennylane/pull/1461)

* Examples have been added to clarify use of the continuous-variable

`FockStateVector` operation in the multi-mode case.

[(#1472)](https://github.com/PennyLaneAI/pennylane/pull/1472)

### Contributors

This release contains contributions from (in alphabetical order):

Juan Miguel Arrazola, Olivia Di Matteo, Anthony Hayes, Theodor Isacsson, Josh

Izaac, Soran Jahangiri, Nathan Killoran, Arshpreet Singh Khangura, Leonhard

Kunczik, Christina Lee, Romain Moyard, Lee James O’Riordan, Ashish Panigrahi,

Nahum Sá, Maria Schuld, Jay Soni, Antal Száva, David Wierichs.

orphan

#### Release 0.16.0[¶](#release-0-16-0 "Permalink to this headline")

#### First class support for quantum kernels

* The new `qml.kernels` module provides basic functionalities for [working with quantum

kernels](https://pennylane.readthedocs.io/en/stable/code/qml_kernels.html) as

well as post-processing methods to mitigate sampling errors and device noise:

[(#1102)](https://github.com/PennyLaneAI/pennylane/pull/1102)

```

num\_wires = 6

wires = range(num\_wires)

dev = qml.device('default.qubit', wires=wires)

@qml.qnode(dev)

def kernel\_circuit(x1, x2):

    qml.templates.AngleEmbedding(x1, wires=wires)

    qml.adjoint(qml.templates.AngleEmbedding)(x2, wires=wires)

    return qml.probs(wires)

kernel = lambda x1, x2: kernel\_circuit(x1, x2)[0]

X\_train = np.random.random((10, 6))

X\_test = np.random.random((5, 6))

# Create symmetric square kernel matrix (for training)

K = qml.kernels.square\_kernel\_matrix(X\_train, kernel)

# Compute kernel between test and training data.

K\_test = qml.kernels.kernel\_matrix(X\_train, X\_test, kernel)

K1 = qml.kernels.mitigate\_depolarizing\_noise(K, num\_wires, method='single')

```

#### Extract the fourier representation of quantum circuits

* PennyLane now has a `fourier` module, which hosts a [growing library

of methods](https://pennylane.readthedocs.io/en/stable/code/qml_fourier.html)

that help with investigating the Fourier representation of functions

implemented by quantum circuits. The Fourier representation can be used

to examine and characterize the expressivity of the quantum circuit.

[(#1160)](https://github.com/PennyLaneAI/pennylane/pull/1160)

[(#1378)](https://github.com/PennyLaneAI/pennylane/pull/1378)

For example, one can plot distributions over Fourier series coefficients like

this one:

![](https://pennylane.readthedocs.io/en/latest/_static/fourier.png)

#### Seamless support for working with the Pauli group

* Added functionality for constructing and manipulating the Pauli group

[(#1181)](https://github.com/PennyLaneAI/pennylane/pull/1181).

The function `qml.grouping.pauli\_group` provides a generator to

easily loop over the group, or construct and store it in its entirety.

For example, we can construct the single-qubit Pauli group like so:

```

>>> from pennylane.grouping import pauli\_group

>>> pauli\_group\_1\_qubit = list(pauli\_group(1))

>>> pauli\_group\_1\_qubit

[Identity(wires=[0]), PauliZ(wires=[0]), PauliX(wires=[0]), PauliY(wires=[0])]

```

We can multiply together its members at the level of Pauli words

using the `pauli\_mult` and `pauli\_multi\_with\_phase` functions.

This can be done on arbitrarily-labeled wires as well, by defining a wire map.

```

>>> from pennylane.grouping import pauli\_group, pauli\_mult

>>> wire\_map = {'a' : 0, 'b' : 1, 'c' : 2}

>>> pg = list(pauli\_group(3, wire\_map=wire\_map))

>>> pg[3]

PauliZ(wires=['b']) @ PauliZ(wires=['c'])

>>> pg[55]

PauliY(wires=['a']) @ PauliY(wires=['b']) @ PauliZ(wires=['c'])

>>> pauli\_mult(pg[3], pg[55], wire\_map=wire\_map)

PauliY(wires=['a']) @ PauliX(wires=['b'])

```

Functions for conversion of Pauli observables to strings (and back),

are included.

```

>>> from pennylane.grouping import pauli\_word\_to\_string, string\_to\_pauli\_word

>>> pauli\_word\_to\_string(pg[55], wire\_map=wire\_map)

'YYZ'

>>> string\_to\_pauli\_word('ZXY', wire\_map=wire\_map)

PauliZ(wires=['a']) @ PauliX(wires=['b']) @ PauliY(wires=['c'])

```

Calculation of the matrix representation for arbitrary Paulis and wire maps is now

also supported.

```

>>> from pennylane.grouping import pauli\_word\_to\_matrix

>>> wire\_map = {'a' : 0, 'b' : 1}

>>> pauli\_word = qml.PauliZ('b')  # corresponds to Pauli 'IZ'

>>> pauli\_word\_to\_matrix(pauli\_word, wire\_map=wire\_map)

array([[ 1., 0., 0., 0.],

 [ 0., -1., 0., -0.],

 [ 0., 0., 1., 0.],

 [ 0., -0., 0., -1.]])

```

#### New transforms

* The `qml.specs` QNode transform creates a function that returns specifications or

details about the QNode, including depth, number of gates, and number of

gradient executions required.

[(#1245)](https://github.com/PennyLaneAI/pennylane/pull/1245)

For example:

```

dev = qml.device('default.qubit', wires=4)

@qml.qnode(dev, diff\_method='parameter-shift')

def circuit(x, y):

    qml.RX(x[0], wires=0)

    qml.Toffoli(wires=(0, 1, 2))

    qml.CRY(x[1], wires=(0, 1))

    qml.Rot(x[2], x[3], y, wires=0)

    return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliX(1))

```

We can now use the `qml.specs` transform to generate a function that returns

details and resource information:

```

>>> x = np.array([0.05, 0.1, 0.2, 0.3], requires\_grad=True)

>>> y = np.array(0.4, requires\_grad=False)

>>> specs\_func = qml.specs(circuit)

>>> specs\_func(x, y)

{'gate\_sizes': defaultdict(int, {1: 2, 3: 1, 2: 1}),

 'gate\_types': defaultdict(int, {'RX': 1, 'Toffoli': 1, 'CRY': 1, 'Rot': 1}),

 'num\_operations': 4,

 'num\_observables': 2,

 'num\_diagonalizing\_gates': 1,

 'num\_used\_wires': 3,

 'depth': 4,

 'num\_trainable\_params': 4,

 'num\_parameter\_shift\_executions': 11,

 'num\_device\_wires': 4,

 'device\_name': 'default.qubit',

 'diff\_method': 'parameter-shift'}

```

The tape methods `get\_resources` and `get\_depth` are superseded by `specs` and will be

deprecated after one release cycle.

* Adds a decorator `@qml.qfunc\_transform` to easily create a transformation

that modifies the behaviour of a quantum function.

[(#1315)](https://github.com/PennyLaneAI/pennylane/pull/1315)

For example, consider the following transform, which scales the parameter of

all `RX` gates by \(x \rightarrow \sin(a) \sqrt{x}\), and the parameters

of all `RY` gates by \(y \rightarrow \cos(a \* b) y\):

```

@qml.qfunc\_transform

def my\_transform(tape, a, b):

    for op in tape.operations + tape.measurements:

        if op.name == "RX":

            x = op.parameters[0]

            qml.RX(qml.math.sin(a) \* qml.math.sqrt(x), wires=op.wires)

        elif op.name == "RY":

            y = op.parameters[0]

            qml.RX(qml.math.cos(a \* b) \* y, wires=op.wires)

        else:

            op.queue()

```

We can now apply this transform to any quantum function:

```

dev = qml.device("default.qubit", wires=2)

def ansatz(x):

    qml.Hadamard(wires=0)

    qml.RX(x[0], wires=0)

    qml.RY(x[1], wires=1)

    qml.CNOT(wires=[0, 1])

@qml.qnode(dev)

def circuit(params, transform\_weights):

    qml.RX(0.1, wires=0)

    # apply the transform to the ansatz

    my\_transform(\*transform\_weights)(ansatz)(params)

    return qml.expval(qml.PauliZ(1))

```

We can print this QNode to show that the qfunc transform is taking place:

```

>>> x = np.array([0.5, 0.3], requires\_grad=True)

>>> transform\_weights = np.array([0.1, 0.6], requires\_grad=True)

>>> print(qml.draw(circuit)(x, transform\_weights))

 0: ──RX(0.1)────H──RX(0.0706)──╭C──┤

 1: ──RX(0.299)─────────────────╰X──┤ ⟨Z⟩

```

Evaluating the QNode, as well as the derivative, with respect to the gate

parameter *and* the transform weights:

```

>>> circuit(x, transform\_weights)

tensor(0.00672829, requires\_grad=True)

>>> qml.grad(circuit)(x, transform\_weights)

(array([ 0.00671711, -0.00207359]), array([6.69695008e-02, 3.73694364e-06]))

```

* Adds a `hamiltonian\_expand` tape transform. This takes a tape ending in

`qml.expval(H)`, where `H` is a Hamiltonian, and maps it to a collection

of tapes which can be executed and passed into a post-processing function yielding

the expectation value.

[(#1142)](https://github.com/PennyLaneAI/pennylane/pull/1142)

Example use:

```

H = qml.PauliZ(0) + 3 \* qml.PauliZ(0) @ qml.PauliX(1)

with qml.tape.QuantumTape() as tape:

    qml.Hadamard(wires=1)

    qml.expval(H)

tapes, fn = qml.transforms.hamiltonian\_expand(tape)

```

We can now evaluate the transformed tapes, and apply the post-processing

function:

```

>>> dev = qml.device("default.qubit", wires=3)

>>> res = dev.batch\_execute(tapes)

>>> fn(res)

3.999999999999999

```

* The `quantum\_monte\_carlo` transform has been added, allowing an input circuit to be transformed

into the full quantum Monte Carlo algorithm.

[(#1316)](https://github.com/PennyLaneAI/pennylane/pull/1316)

Suppose we want to measure the expectation value of the sine squared function according to

a standard normal distribution. We can calculate the expectation value analytically as

`0.432332`, but we can also estimate using the quantum Monte Carlo algorithm. The first step is to

discretize the problem:

```

from scipy.stats import norm

m = 5

M = 2 \*\* m

xmax = np.pi  # bound to region [-pi, pi]

xs = np.linspace(-xmax, xmax, M)

probs = np.array([norm().pdf(x) for x in xs])

probs /= np.sum(probs)

func = lambda i: np.sin(xs[i]) \*\* 2

r\_rotations = np.array([2 \* np.arcsin(np.sqrt(func(i))) for i in range(M)])

```

The `quantum\_monte\_carlo` transform can then be used:

```

from pennylane.templates.state\_preparations.mottonen import (

    \_uniform\_rotation\_dagger as r\_unitary,

)

n = 6

N = 2 \*\* n

a\_wires = range(m)

wires = range(m + 1)

target\_wire = m

estimation\_wires = range(m + 1, n + m + 1)

dev = qml.device("default.qubit", wires=(n + m + 1))

def fn():

    qml.templates.MottonenStatePreparation(np.sqrt(probs), wires=a\_wires)

    r\_unitary(qml.RY, r\_rotations, control\_wires=a\_wires[::-1], target\_wire=target\_wire)

@qml.qnode(dev)

def qmc():

    qml.quantum\_monte\_carlo(fn, wires, target\_wire, estimation\_wires)()

    return qml.probs(estimation\_wires)

phase\_estimated = np.argmax(qmc()[:int(N / 2)]) / N

```

The estimated value can be retrieved using:

```

>>> (1 - np.cos(np.pi \* phase\_estimated)) / 2

0.42663476277231915

```

The resources required to perform the quantum Monte Carlo algorithm can also be inspected using

the `specs` transform.

#### Extended QAOA module

* Functionality to support solving the maximum-weighted cycle problem has been added to the `qaoa`

module.

[(#1207)](https://github.com/PennyLaneAI/pennylane/pull/1207)

[(#1209)](https://github.com/PennyLaneAI/pennylane/pull/1209)

[(#1251)](https://github.com/PennyLaneAI/pennylane/pull/1251)

[(#1213)](https://github.com/PennyLaneAI/pennylane/pull/1213)

[(#1220)](https://github.com/PennyLaneAI/pennylane/pull/1220)

[(#1214)](https://github.com/PennyLaneAI/pennylane/pull/1214)

[(#1283)](https://github.com/PennyLaneAI/pennylane/pull/1283)

[(#1297)](https://github.com/PennyLaneAI/pennylane/pull/1297)

[(#1396)](https://github.com/PennyLaneAI/pennylane/pull/1396)

[(#1403)](https://github.com/PennyLaneAI/pennylane/pull/1403)

The `max\_weight\_cycle` function returns the appropriate cost and mixer Hamiltonians:

```

>>> a = np.random.random((3, 3))

>>> np.fill\_diagonal(a, 0)

>>> g = nx.DiGraph(a)  # create a random directed graph

>>> cost, mixer, mapping = qml.qaoa.max\_weight\_cycle(g)

>>> print(cost)

 (-0.9775906842165344) [Z2]

+ (-0.9027248603361988) [Z3]

+ (-0.8722207409852838) [Z0]

+ (-0.6426184210832898) [Z5]

+ (-0.2832594164291379) [Z1]

+ (-0.0778133996933755) [Z4]

>>> print(mapping)

{0: (0, 1), 1: (0, 2), 2: (1, 0), 3: (1, 2), 4: (2, 0), 5: (2, 1)}

```

Additional functionality can be found in the

[qml.qaoa.cycle](https://pennylane.readthedocs.io/en/latest/code/api/pennylane.qaoa.cycle.html)

module.

#### Extended operations and templates

* Added functionality to compute the sparse matrix representation of a `qml.Hamiltonian` object.

[(#1394)](https://github.com/PennyLaneAI/pennylane/pull/1394)

```

coeffs = [1, -0.45]

obs = [qml.PauliZ(0) @ qml.PauliZ(1), qml.PauliY(0) @ qml.PauliZ(1)]

H = qml.Hamiltonian(coeffs, obs)

H\_sparse = qml.utils.sparse\_hamiltonian(H)

```

The resulting matrix is a sparse matrix in scipy coordinate list (COO) format:

```

>>> H\_sparse

<4x4 sparse matrix of type '<class 'numpy.complex128'>'

 with 8 stored elements in COOrdinate format>

```

The sparse matrix can be converted to an array as:

```

>>> H\_sparse.toarray()

array([[ 1.+0.j , 0.+0.j , 0.+0.45j, 0.+0.j ],

 [ 0.+0.j , -1.+0.j , 0.+0.j , 0.-0.45j],

 [ 0.-0.45j, 0.+0.j , -1.+0.j , 0.+0.j ],

 [ 0.+0.j , 0.+0.45j, 0.+0.j , 1.+0.j ]])

```

* Adds the new template `AllSinglesDoubles` to prepare quantum states of molecules

using the `SingleExcitation` and `DoubleExcitation` operations.

The new template reduces significantly the number of operations

and the depth of the quantum circuit with respect to the traditional UCCSD

unitary.

[(#1383)](https://github.com/PennyLaneAI/pennylane/pull/1383)

For example, consider the case of two particles and four qubits.

First, we define the Hartree-Fock initial state and generate all

possible single and double excitations.

```

import pennylane as qml

from pennylane import numpy as np

electrons = 2

qubits = 4

hf\_state = qml.qchem.hf\_state(electrons, qubits)

singles, doubles = qml.qchem.excitations(electrons, qubits)

```

Now we can use the template `AllSinglesDoubles` to define the

quantum circuit,

```

from pennylane.templates import AllSinglesDoubles

wires = range(qubits)

dev = qml.device('default.qubit', wires=wires)

@qml.qnode(dev)

def circuit(weights, hf\_state, singles, doubles):

    AllSinglesDoubles(weights, wires, hf\_state, singles, doubles)

    return qml.expval(qml.PauliZ(0))

params = np.random.normal(0, np.pi, len(singles) + len(doubles))

```

and execute it:

```

>>> circuit(params, hf\_state, singles=singles, doubles=doubles)

tensor(-0.73772194, requires\_grad=True)

```

* Adds `QubitCarry` and `QubitSum` operations for basic arithmetic.

[(#1169)](https://github.com/PennyLaneAI/pennylane/pull/1169)

The following example adds two 1-bit numbers, returning a 2-bit answer:

```

dev = qml.device('default.qubit', wires = 4)

a = 0

b = 1

@qml.qnode(dev)

def circuit():

    qml.BasisState(np.array([a, b]), wires=[1, 2])

    qml.QubitCarry(wires=[0, 1, 2, 3])

    qml.CNOT(wires=[1, 2])

    qml.QubitSum(wires=[0, 1, 2])

    return qml.probs(wires=[3, 2])

probs = circuit()

bitstrings = tuple(itertools.product([0, 1], repeat = 2))

indx = np.argwhere(probs == 1).flatten()[0]

output = bitstrings[indx]

```

```

>>> print(output)

(0, 1)

```

* Added the `qml.Projector` observable, which is available on all devices

inheriting from the `QubitDevice` class.

[(#1356)](https://github.com/PennyLaneAI/pennylane/pull/1356)

[(#1368)](https://github.com/PennyLaneAI/pennylane/pull/1368)

Using `qml.Projector`, we can define the basis state projectors to use when

computing expectation values. Let us take for example a circuit that prepares

Bell states:

```

dev = qml.device("default.qubit", wires=2)

@qml.qnode(dev)

def circuit(basis\_state):

    qml.Hadamard(wires=[0])

    qml.CNOT(wires=[0, 1])

    return qml.expval(qml.Projector(basis\_state, wires=[0, 1]))

```

We can then specify the `|00>` basis state to construct the `|00><00|`

projector and compute the expectation value:

```

>>> basis\_state = [0, 0]

>>> circuit(basis\_state)

tensor(0.5, requires\_grad=True)

```

As expected, we get similar results when specifying the `|11>` basis state:

```

>>> basis\_state = [1, 1]

>>> circuit(basis\_state)

tensor(0.5, requires\_grad=True)

```

* The following new operations have been added:

	+ The IsingXX gate `qml.IsingXX` [(#1194)](https://github.com/PennyLaneAI/pennylane/pull/1194)

	+ The IsingZZ gate `qml.IsingZZ` [(#1199)](https://github.com/PennyLaneAI/pennylane/pull/1199)

	+ The ISWAP gate `qml.ISWAP` [(#1298)](https://github.com/PennyLaneAI/pennylane/pull/1298)

	+ The reset error noise channel `qml.ResetError` [(#1321)](https://github.com/PennyLaneAI/pennylane/pull/1321)

### Improvements

* The `argnum` keyword argument can now be specified for a QNode to define a

subset of trainable parameters used to estimate the Jacobian.

[(#1371)](https://github.com/PennyLaneAI/pennylane/pull/1371)

For example, consider two trainable parameters and a quantum function:

```

dev = qml.device("default.qubit", wires=2)

x = np.array(0.543, requires\_grad=True)

y = np.array(-0.654, requires\_grad=True)

def circuit(x,y):

    qml.RX(x, wires=[0])

    qml.RY(y, wires=[1])

    qml.CNOT(wires=[0, 1])

    return qml.expval(qml.PauliZ(0) @ qml.PauliX(1))

```

When computing the gradient of the QNode, we can specify the trainable

parameters to consider by passing the `argnum` keyword argument:

```

>>> qnode1 = qml.QNode(circuit, dev, diff\_method="parameter-shift", argnum=[0,1])

>>> print(qml.grad(qnode1)(x,y))

(array(0.31434679), array(0.67949903))

```

Specifying a proper subset of the trainable parameters will estimate the

Jacobian:

```

>>> qnode2 = qml.QNode(circuit, dev, diff\_method="parameter-shift", argnum=[0])

>>> print(qml.grad(qnode2)(x,y))

(array(0.31434679), array(0.))

```

* Allows creating differentiable observables that return custom objects such

that the observable is supported by devices.

[(1291)](https://github.com/PennyLaneAI/pennylane/pull/1291)

As an example, first we define `NewObservable` class:

```

from pennylane.devices import DefaultQubit

class NewObservable(qml.operation.Observable):

 """NewObservable"""

    num\_wires = qml.operation.AnyWires

    num\_params = 0

    par\_domain = None

    def diagonalizing\_gates(self):

 """Diagonalizing gates"""

        return []

```

Once we have this new observable class, we define a `SpecialObject` class

that can be used to encode data in an observable and a new device that supports

our new observable and returns a `SpecialObject` as the expectation value

(the code is shortened for brevity, the extended example can be found as a

test in the previously referenced pull request):

```

class SpecialObject:

    def \_\_init\_\_(self, val):

        self.val = val

    def \_\_mul\_\_(self, other):

        new = SpecialObject(self.val)

        new \*= other

        return new

    ...

class DeviceSupportingNewObservable(DefaultQubit):

    name = "Device supporting NewObservable"

    short\_name = "default.qubit.newobservable"

    observables = DefaultQubit.observables.union({"NewObservable"})

    def expval(self, observable, \*\*kwargs):

        if self.shots is None and isinstance(observable, NewObservable):

            val = super().expval(qml.PauliZ(wires=0), \*\*kwargs)

            return SpecialObject(val)

        return super().expval(observable, \*\*kwargs)

```

At this point, we can create a device that will support the differentiation

of a `NewObservable` object:

```

dev = DeviceSupportingNewObservable(wires=1, shots=None)

@qml.qnode(dev, diff\_method="parameter-shift")

def qnode(x):

    qml.RY(x, wires=0)

    return qml.expval(NewObservable(wires=0))

```

We can then compute the jacobian of this object:

```

>>> result = qml.jacobian(qnode)(0.2)

>>> print(result)

<\_\_main\_\_.SpecialObject object at 0x7fd2c54721f0>

>>> print(result.item().val)

-0.19866933079506116

```

* PennyLane NumPy now includes the

[random module’s](https://numpy.org/doc/stable/reference/random/index.html#module-numpy.random)

`Generator` objects, the recommended way of random number generation. This allows for

random number generation using a local, rather than global seed.

[(#1267)](https://github.com/PennyLaneAI/pennylane/pull/1267)

```

from pennylane import numpy as np

rng = np.random.default\_rng()

random\_mat1 = rng.random((3,2))

random\_mat2 = rng.standard\_normal(3, requires\_grad=False)

```

* The performance of adjoint jacobian differentiation was significantly

improved as the method now reuses the state computed on the forward pass.

This can be turned off to save memory with the Torch and TensorFlow

interfaces by passing `adjoint\_cache=False` during QNode creation.

[(#1341)](https://github.com/PennyLaneAI/pennylane/pull/1341)

* The `Operator` (and by inheritance, the `Operation` and `Observable` class and their children)

now have an `id` attribute, which can mark an operator in a circuit, for example to

identify it on the tape by a tape transform.

[(#1377)](https://github.com/PennyLaneAI/pennylane/pull/1377)

* The `benchmark` module was deleted, since it was outdated and is superseded by

the new separate [benchmark repository](https://github.com/PennyLaneAI/benchmark).

[(#1343)](https://github.com/PennyLaneAI/pennylane/pull/1343)

* Decompositions in terms of elementary gates has been added for:

	+ `qml.CSWAP` [(#1306)](https://github.com/PennyLaneAI/pennylane/issues/1306)

	+ `qml.SWAP` [(#1329)](https://github.com/PennyLaneAI/pennylane/pull/1329)

	+ `qml.SingleExcitation` [(#1303)](https://github.com/PennyLaneAI/pennylane/pull/1303)

	+ `qml.SingleExcitationPlus` and `qml.SingleExcitationMinus` [(#1278)](https://github.com/PennyLaneAI/pennylane/pull/1278)

	+ `qml.DoubleExcitation` [(#1303)](https://github.com/PennyLaneAI/pennylane/pull/1303)

	+ `qml.Toffoli` [(#1320)](https://github.com/PennyLaneAI/pennylane/pull/1320)

	+ `qml.MultiControlledX`. [(#1287)](https://github.com/PennyLaneAI/pennylane/pull/1287)

	When controlling on three or more wires, an ancilla

	register of worker wires is required to support the decomposition.

	

	

	

	```

	ctrl\_wires = [f"c{i}" for i in range(5)]

	work\_wires = [f"w{i}" for i in range(3)]

	target\_wires = ["t0"]

	all\_wires = ctrl\_wires + work\_wires + target\_wires

	

	dev = qml.device("default.qubit", wires=all\_wires)

	

	with qml.tape.QuantumTape() as tape:

	    qml.MultiControlledX(control\_wires=ctrl\_wires, wires=target\_wires, work\_wires=work\_wires)

	

	```

	

	

	

	```

	>>> tape = tape.expand(depth=1)

	>>> print(tape.draw(wire\_order=qml.wires.Wires(all\_wires)))

	

	 c0: ──────────────╭C──────────────────────╭C──────────┤

	 c1: ──────────────├C──────────────────────├C──────────┤

	 c2: ──────────╭C──│───╭C──────────────╭C──│───╭C──────┤

	 c3: ──────╭C──│───│───│───╭C──────╭C──│───│───│───╭C──┤

	 c4: ──╭C──│───│───│───│───│───╭C──│───│───│───│───│───┤

	 w0: ──│───│───├C──╰X──├C──│───│───│───├C──╰X──├C──│───┤

	 w1: ──│───├C──╰X──────╰X──├C──│───├C──╰X──────╰X──├C──┤

	 w2: ──├C──╰X──────────────╰X──├C──╰X──────────────╰X──┤

	 t0: ──╰X──────────────────────╰X──────────────────────┤

	

	```

* Added `qml.CPhase` as an alias for the existing `qml.ControlledPhaseShift` operation.

[(#1319)](https://github.com/PennyLaneAI/pennylane/pull/1319).

* The `Device` class now uses caching when mapping wires.

[(#1270)](https://github.com/PennyLaneAI/pennylane/pull/1270)

* The `Wires` class now uses caching for computing its `hash`.

[(#1270)](https://github.com/PennyLaneAI/pennylane/pull/1270)

* Added custom gate application for Toffoli in `default.qubit`.

[(#1249)](https://github.com/PennyLaneAI/pennylane/pull/1249)

* Added validation for noise channel parameters. Invalid noise parameters now

raise a `ValueError`.

[(#1357)](https://github.com/PennyLaneAI/pennylane/pull/1357)

* The device test suite now provides test cases for checking gates by comparing

expectation values.

[(#1212)](https://github.com/PennyLaneAI/pennylane/pull/1212)

* PennyLane’s test suite is now code-formatted using `black -l 100`.

[(#1222)](https://github.com/PennyLaneAI/pennylane/pull/1222)

* PennyLane’s `qchem` package and tests are now code-formatted using `black -l 100`.

[(#1311)](https://github.com/PennyLaneAI/pennylane/pull/1311)

### Breaking changes

* The `qml.inv()` function is now deprecated with a warning to use the more general `qml.adjoint()`.

[(#1325)](https://github.com/PennyLaneAI/pennylane/pull/1325)

* Removes support for Python 3.6 and adds support for Python 3.9.

[(#1228)](https://github.com/XanaduAI/pennylane/pull/1228)

* The tape methods `get\_resources` and `get\_depth` are superseded by `specs` and will be

deprecated after one release cycle.

[(#1245)](https://github.com/PennyLaneAI/pennylane/pull/1245)

* Using the `qml.sample()` measurement on devices with `shots=None` continue to

raise a warning with this functionality being fully deprecated and raising an

error after one release cycle.

[(#1079)](https://github.com/PennyLaneAI/pennylane/pull/1079)

[(#1196)](https://github.com/PennyLaneAI/pennylane/pull/1196)

### Bug fixes

* QNodes now display readable information when in interactive environments or when printed.

[(#1359)](https://github.com/PennyLaneAI/pennylane/pull/1359).

* Fixes a bug with `qml.math.cast` where the `MottonenStatePreparation` operation expected

a float type instead of double.

[(#1400)](https://github.com/XanaduAI/pennylane/pull/1400)

* Fixes a bug where a copy of `qml.ControlledQubitUnitary` was non-functional as it did not have all the necessary information.

[(#1411)](https://github.com/PennyLaneAI/pennylane/pull/1411)

* Warns when adjoint or reversible differentiation specified or called on a device with finite shots.

[(#1406)](https://github.com/PennyLaneAI/pennylane/pull/1406)

* Fixes the differentiability of the operations `IsingXX` and `IsingZZ` for Autograd, Jax and Tensorflow.

[(#1390)](https://github.com/PennyLaneAI/pennylane/pull/1390)

* Fixes a bug where multiple identical Hamiltonian terms will produce a

different result with `optimize=True` using `ExpvalCost`.

[(#1405)](https://github.com/XanaduAI/pennylane/pull/1405)

* Fixes bug where `shots=None` was not reset when changing shots temporarily in a QNode call

like `circuit(0.1, shots=3)`.

[(#1392)](https://github.com/XanaduAI/pennylane/pull/1392)

* Fixes floating point errors with `diff\_method="finite-diff"` and `order=1` when parameters are `float32`.

[(#1381)](https://github.com/PennyLaneAI/pennylane/pull/1381)

* Fixes a bug where `qml.ctrl` would fail to transform gates that had no

control defined and no decomposition defined.

[(#1376)](https://github.com/PennyLaneAI/pennylane/pull/1376)

* Copying the `JacobianTape` now correctly also copies the `jacobian\_options` attribute. This fixes a bug

allowing the JAX interface to support adjoint differentiation.

[(#1349)](https://github.com/PennyLaneAI/pennylane/pull/1349)

* Fixes drawing QNodes that contain multiple measurements on a single wire.

[(#1353)](https://github.com/PennyLaneAI/pennylane/pull/1353)

* Fixes drawing QNodes with no operations.

[(#1354)](https://github.com/PennyLaneAI/pennylane/pull/1354)

* Fixes incorrect wires in the decomposition of the `ControlledPhaseShift` operation.

[(#1338)](https://github.com/PennyLaneAI/pennylane/pull/1338)

* Fixed tests for the `Permute` operation that used a QNode and hence expanded

tapes twice instead of once due to QNode tape expansion and an explicit tape

expansion call.

[(#1318)](https://github.com/PennyLaneAI/pennylane/pull/1318).

* Prevent Hamiltonians that share wires from being multiplied together.

[(#1273)](https://github.com/PennyLaneAI/pennylane/pull/1273)

* Fixed a bug where the custom range sequences could not be passed

to the `StronglyEntanglingLayers` template.

[(#1332)](https://github.com/PennyLaneAI/pennylane/pull/1332)

* Fixed a bug where `qml.sum()` and `qml.dot()` do not support the JAX interface.

[(#1380)](https://github.com/PennyLaneAI/pennylane/pull/1380)

### Documentation

* Math present in the `QubitParamShiftTape` class docstring now renders correctly.

[(#1402)](https://github.com/PennyLaneAI/pennylane/pull/1402)

* Fix typo in the documentation of `qml.StronglyEntanglingLayers`.

[(#1367)](https://github.com/PennyLaneAI/pennylane/pull/1367)

* Fixed typo in TensorFlow interface documentation

[(#1312)](https://github.com/PennyLaneAI/pennylane/pull/1312)

* Fixed typos in the mathematical expressions in documentation of `qml.DoubleExcitation`.

[(#1278)](https://github.com/PennyLaneAI/pennylane/pull/1278)

* Remove unsupported `None` option from the `qml.QNode` docstrings.

[(#1271)](https://github.com/PennyLaneAI/pennylane/pull/1271)

* Updated the docstring of `qml.PolyXP` to reference the new location of internal

usage.

[(#1262)](https://github.com/PennyLaneAI/pennylane/pull/1262)

* Removes occurrences of the deprecated device argument `analytic` from the documentation.

[(#1261)](https://github.com/PennyLaneAI/pennylane/pull/1261)

* Updated PyTorch and TensorFlow interface introductions.

[(#1333)](https://github.com/PennyLaneAI/pennylane/pull/1333)

* Updates the quantum chemistry quickstart to reflect recent changes to the `qchem` module.

[(#1227)](https://github.com/PennyLaneAI/pennylane/pull/1227)

### Contributors

This release contains contributions from (in alphabetical order):

Marius Aglitoiu, Vishnu Ajith, Juan Miguel Arrazola, Thomas Bromley, Jack Ceroni, Alaric Cheng, Miruna Daian,

Olivia Di Matteo, Tanya Garg, Christian Gogolin, Alain Delgado Gran, Diego Guala, Anthony Hayes, Ryan Hill,

Theodor Isacsson, Josh Izaac, Soran Jahangiri, Pavan Jayasinha, Nathan Killoran, Christina Lee, Ryan Levy,

Alberto Maldonado, Johannes Jakob Meyer, Romain Moyard, Ashish Panigrahi, Nahum Sá, Maria Schuld, Brian Shi,

Antal Száva, David Wierichs, Vincent Wong.

orphan

#### Release 0.15.1[¶](#release-0-15-1 "Permalink to this headline")

### Bug fixes

* Fixes two bugs in the parameter-shift Hessian.

[(#1260)](https://github.com/PennyLaneAI/pennylane/pull/1260)

	+ Fixes a bug where having an unused parameter in the Autograd interface

	would result in an indexing error during backpropagation.

	+ The parameter-shift Hessian only supports the two-term parameter-shift

	rule currently, so raises an error if asked to differentiate

	any unsupported gates (such as the controlled rotation gates).

* A bug which resulted in `qml.adjoint()` and `qml.inv()` failing to work with

templates has been fixed.

[(#1243)](https://github.com/PennyLaneAI/pennylane/pull/1243)

* Deprecation warning instances in PennyLane have been changed to `UserWarning`,

to account for recent changes to how Python warnings are filtered in

[PEP565](https://www.python.org/dev/peps/pep-0565/).

[(#1211)](https://github.com/PennyLaneAI/pennylane/pull/1211)

### Documentation

* Updated the order of the parameters to the `GaussianState` operation to match

the way that the PennyLane-SF plugin uses them.

[(#1255)](https://github.com/PennyLaneAI/pennylane/pull/1255)

### Contributors

This release contains contributions from (in alphabetical order):

Thomas Bromley, Olivia Di Matteo, Diego Guala, Anthony Hayes, Ryan Hill,

Josh Izaac, Christina Lee, Maria Schuld, Antal Száva.

orphan

#### Release 0.15.0[¶](#release-0-15-0 "Permalink to this headline")

### New features since last release

#### Better and more flexible shot control

* Adds a new optimizer `qml.ShotAdaptiveOptimizer`, a gradient-descent optimizer where

the shot rate is adaptively calculated using the variances of the parameter-shift gradient.

[(#1139)](https://github.com/PennyLaneAI/pennylane/pull/1139)

By keeping a running average of the parameter-shift gradient and the *variance* of the

parameter-shift gradient, this optimizer frugally distributes a shot budget across the partial

derivatives of each parameter.

In addition, if computing the expectation value of a Hamiltonian, weighted random sampling can be

used to further distribute the shot budget across the local terms from which the Hamiltonian is

constructed.

This optimizer is based on both the [iCANS1](https://quantum-journal.org/papers/q-2020-05-11-263)

and [Rosalin](https://arxiv.org/abs/2004.06252) shot-adaptive optimizers.

Once constructed, the cost function can be passed directly to the optimizer’s `step` method. The

attribute `opt.total\_shots\_used` can be used to track the number of shots per iteration.

```

>>> coeffs = [2, 4, -1, 5, 2]

>>> obs = [

...   qml.PauliX(1),

...   qml.PauliZ(1),

...   qml.PauliX(0) @ qml.PauliX(1),

...   qml.PauliY(0) @ qml.PauliY(1),

...   qml.PauliZ(0) @ qml.PauliZ(1)

... ]

>>> H = qml.Hamiltonian(coeffs, obs)

>>> dev = qml.device("default.qubit", wires=2, shots=100)

>>> cost = qml.ExpvalCost(qml.templates.StronglyEntanglingLayers, H, dev)

>>> params = qml.init.strong\_ent\_layers\_uniform(n\_layers=2, n\_wires=2)

>>> opt = qml.ShotAdaptiveOptimizer(min\_shots=10)

>>> for i in range(5):

...    params = opt.step(cost, params)

...    print(f"Step {i}: cost = {cost(params):.2f}, shots\_used = {opt.total\_shots\_used}")

Step 0: cost = -5.68, shots\_used = 240

Step 1: cost = -2.98, shots\_used = 336

Step 2: cost = -4.97, shots\_used = 624

Step 3: cost = -5.53, shots\_used = 1054

Step 4: cost = -6.50, shots\_used = 1798

```

* Batches of shots can now be specified as a list, allowing measurement statistics

to be course-grained with a single QNode evaluation.

[(#1103)](https://github.com/PennyLaneAI/pennylane/pull/1103)

```

>>> shots\_list = [5, 10, 1000]

>>> dev = qml.device("default.qubit", wires=2, shots=shots\_list)

```

When QNodes are executed on this device, a single execution of 1015 shots will be submitted.

However, three sets of measurement statistics will be returned; using the first 5 shots,

second set of 10 shots, and final 1000 shots, separately.

For example, executing a circuit with two outputs will lead to a result of shape `(3, 2)`:

```

>>> @qml.qnode(dev)

... def circuit(x):

...     qml.RX(x, wires=0)

...     qml.CNOT(wires=[0, 1])

...     return qml.expval(qml.PauliZ(0) @ qml.PauliX(1)), qml.expval(qml.PauliZ(0))

>>> circuit(0.5)

[[0.33333333 1. ]

 [0.2 1. ]

 [0.012 0.868 ]]

```

This output remains fully differentiable.

* The number of shots can now be specified on a per-call basis when evaluating a QNode.

[(#1075)](https://github.com/PennyLaneAI/pennylane/pull/1075).

For this, the qnode should be called with an additional `shots` keyword argument:

```

>>> dev = qml.device('default.qubit', wires=1, shots=10) # default is 10

>>> @qml.qnode(dev)

... def circuit(a):

...     qml.RX(a, wires=0)

...     return qml.sample(qml.PauliZ(wires=0))

>>> circuit(0.8)

[ 1 1 1 -1 -1 1 1 1 1 1]

>>> circuit(0.8, shots=3)

[ 1 1 1]

>>> circuit(0.8)

[ 1 1 1 -1 -1 1 1 1 1 1]

```

#### New differentiable quantum transforms

A new module is available,

[qml.transforms](https://pennylane.rtfd.io/en/stable/code/qml_transforms.html),

which contains *differentiable quantum transforms*. These are functions that act

on QNodes, quantum functions, devices, and tapes, transforming them while remaining

fully differentiable.

* A new adjoint transform has been added.

[(#1111)](https://github.com/PennyLaneAI/pennylane/pull/1111)

[(#1135)](https://github.com/PennyLaneAI/pennylane/pull/1135)

This new method allows users to apply the adjoint of an arbitrary sequence of operations.

```

def subroutine(wire):

    qml.RX(0.123, wires=wire)

    qml.RY(0.456, wires=wire)

dev = qml.device('default.qubit', wires=1)

@qml.qnode(dev)

def circuit():

    subroutine(0)

    qml.adjoint(subroutine)(0)

    return qml.expval(qml.PauliZ(0))

```

This creates the following circuit:

```

>>> print(qml.draw(circuit)())

0: --RX(0.123)--RY(0.456)--RY(-0.456)--RX(-0.123)--| <Z>

```

Directly applying to a gate also works as expected.

```

qml.adjoint(qml.RX)(0.123, wires=0) # applies RX(-0.123)

```

* A new transform `qml.ctrl` is now available that adds control wires to subroutines.

[(#1157)](https://github.com/PennyLaneAI/pennylane/pull/1157)

```

def my\_ansatz(params):

   qml.RX(params[0], wires=0)

   qml.RZ(params[1], wires=1)

# Create a new operation that applies `my\_ansatz`

# controlled by the "2" wire.

my\_ansatz2 = qml.ctrl(my\_ansatz, control=2)

@qml.qnode(dev)

def circuit(params):

    my\_ansatz2(params)

    return qml.state()

```

This is equivalent to:

```

@qml.qnode(...)

def circuit(params):

    qml.CRX(params[0], wires=[2, 0])

    qml.CRZ(params[1], wires=[2, 1])

    return qml.state()

```

* The `qml.transforms.classical\_jacobian` transform has been added.

[(#1186)](https://github.com/PennyLaneAI/pennylane/pull/1186)

This transform returns a function to extract the Jacobian matrix of the classical part of a

QNode, allowing the classical dependence between the QNode arguments and the quantum gate

arguments to be extracted.

For example, given the following QNode:

```

>>> @qml.qnode(dev)

... def circuit(weights):

...     qml.RX(weights[0], wires=0)

...     qml.RY(weights[0], wires=1)

...     qml.RZ(weights[2] \*\* 2, wires=1)

...     return qml.expval(qml.PauliZ(0))

```

We can use this transform to extract the relationship

\(f: \mathbb{R}^n \rightarrow\mathbb{R}^m\) between the input QNode

arguments \(w\) and the gate arguments \(g\), for

a given value of the QNode arguments:

```

>>> cjac\_fn = qml.transforms.classical\_jacobian(circuit)

>>> weights = np.array([1., 1., 1.], requires\_grad=True)

>>> cjac = cjac\_fn(weights)

>>> print(cjac)

[[1. 0. 0.]

 [1. 0. 0.]

 [0. 0. 2.]]

```

The returned Jacobian has rows corresponding to gate arguments, and columns corresponding to

QNode arguments; that is, \(J\_{ij} = \frac{\partial}{\partial g\_i} f(w\_j)\).

#### More operations and templates

* Added the `SingleExcitation` two-qubit operation, which is useful for quantum

chemistry applications.

[(#1121)](https://github.com/PennyLaneAI/pennylane/pull/1121)

It can be used to perform an SO(2) rotation in the subspace

spanned by the states \(|01\rangle\) and \(|10\rangle\).

For example, the following circuit performs the transformation

\(|10\rangle \rightarrow \cos(\phi/2)|10\rangle - \sin(\phi/2)|01\rangle\):

```

dev = qml.device('default.qubit', wires=2)

@qml.qnode(dev)

def circuit(phi):

    qml.PauliX(wires=0)

    qml.SingleExcitation(phi, wires=[0, 1])

```

The `SingleExcitation` operation supports analytic gradients on hardware

using only four expectation value calculations, following results from

[Kottmann et al.](https://arxiv.org/abs/2011.05938)

* Added the `DoubleExcitation` four-qubit operation, which is useful for quantum

chemistry applications.

[(#1123)](https://github.com/PennyLaneAI/pennylane/pull/1123)

It can be used to perform an SO(2) rotation in the subspace

spanned by the states \(|1100\rangle\) and \(|0011\rangle\).

For example, the following circuit performs the transformation

\(|1100\rangle\rightarrow \cos(\phi/2)|1100\rangle - \sin(\phi/2)|0011\rangle\):

```

dev = qml.device('default.qubit', wires=2)

@qml.qnode(dev)

def circuit(phi):

    qml.PauliX(wires=0)

    qml.PauliX(wires=1)

    qml.DoubleExcitation(phi, wires=[0, 1, 2, 3])

```

The `DoubleExcitation` operation supports analytic gradients on hardware using only

four expectation value calculations, following results from

[Kottmann et al.](https://arxiv.org/abs/2011.05938).

* Added the `QuantumMonteCarlo` template for performing quantum Monte Carlo estimation of an

expectation value on simulator.

[(#1130)](https://github.com/PennyLaneAI/pennylane/pull/1130)

The following example shows how the expectation value of sine squared over a standard normal

distribution can be approximated:

```

from scipy.stats import norm

m = 5

M = 2 \*\* m

n = 10

N = 2 \*\* n

target\_wires = range(m + 1)

estimation\_wires = range(m + 1, n + m + 1)

xmax = np.pi  # bound to region [-pi, pi]

xs = np.linspace(-xmax, xmax, M)

probs = np.array([norm().pdf(x) for x in xs])

probs /= np.sum(probs)

func = lambda i: np.sin(xs[i]) \*\* 2

dev = qml.device("default.qubit", wires=(n + m + 1))

@qml.qnode(dev)

def circuit():

    qml.templates.QuantumMonteCarlo(

        probs,

        func,

        target\_wires=target\_wires,

        estimation\_wires=estimation\_wires,

    )

    return qml.probs(estimation\_wires)

phase\_estimated = np.argmax(circuit()[:int(N / 2)]) / N

expectation\_estimated = (1 - np.cos(np.pi \* phase\_estimated)) / 2

```

* Added the `QuantumPhaseEstimation` template for performing quantum phase estimation for an input

unitary matrix.

[(#1095)](https://github.com/PennyLaneAI/pennylane/pull/1095)

Consider the matrix corresponding to a rotation from an `RX` gate:

```

>>> phase = 5

>>> target\_wires = [0]

>>> unitary = qml.RX(phase, wires=0).matrix

```

The `phase` parameter can be estimated using `QuantumPhaseEstimation`. For example, using five

phase-estimation qubits:

```

n\_estimation\_wires = 5

estimation\_wires = range(1, n\_estimation\_wires + 1)

dev = qml.device("default.qubit", wires=n\_estimation\_wires + 1)

@qml.qnode(dev)

def circuit():

    # Start in the |+> eigenstate of the unitary

    qml.Hadamard(wires=target\_wires)

    QuantumPhaseEstimation(

        unitary,

        target\_wires=target\_wires,

        estimation\_wires=estimation\_wires,

    )

    return qml.probs(estimation\_wires)

phase\_estimated = np.argmax(circuit()) / 2 \*\* n\_estimation\_wires

# Need to rescale phase due to convention of RX gate

phase\_estimated = 4 \* np.pi \* (1 - phase)

```

* Added the `ControlledPhaseShift` gate as well as the `QFT` operation for applying quantum Fourier

transforms.

[(#1064)](https://github.com/PennyLaneAI/pennylane/pull/1064)

```

@qml.qnode(dev)

def circuit\_qft(basis\_state):

    qml.BasisState(basis\_state, wires=range(3))

    qml.templates.QFT(wires=range(3))

    return qml.state()

```

* Added the `ControlledQubitUnitary` operation. This

enables implementation of multi-qubit gates with a variable number of

control qubits. It is also possible to specify a different state for the

control qubits using the `control\_values` argument (also known as a

mixed-polarity multi-controlled operation).

[(#1069)](https://github.com/PennyLaneAI/pennylane/pull/1069)

[(#1104)](https://github.com/PennyLaneAI/pennylane/pull/1104)

For example, we can create a multi-controlled T gate using:

```

T = qml.T.\_matrix()

qml.ControlledQubitUnitary(T, control\_wires=[0, 1, 3], wires=2, control\_values="110")

```

Here, the T gate will be applied to wire `2` if control wires `0` and `1` are in

state `1`, and control wire `3` is in state `0`. If no value is passed to

`control\_values`, the gate will be applied if all control wires are in

the `1` state.

* Added `MultiControlledX` for multi-controlled `NOT` gates.

This is a special case of `ControlledQubitUnitary` that applies a

Pauli X gate conditioned on the state of an arbitrary number of

control qubits.

[(#1104)](https://github.com/PennyLaneAI/pennylane/pull/1104)

#### Support for higher-order derivatives on hardware

* Computing second derivatives and Hessians of QNodes is now supported with

the parameter-shift differentiation method, on all machine learning interfaces.

[(#1130)](https://github.com/PennyLaneAI/pennylane/pull/1130)

[(#1129)](https://github.com/PennyLaneAI/pennylane/pull/1129)

[(#1110)](https://github.com/PennyLaneAI/pennylane/pull/1110)

Hessians are computed using the parameter-shift rule, and can be

evaluated on both hardware and simulator devices.

```

dev = qml.device('default.qubit', wires=1)

@qml.qnode(dev, diff\_method="parameter-shift")

def circuit(p):

    qml.RY(p[0], wires=0)

    qml.RX(p[1], wires=0)

    return qml.expval(qml.PauliZ(0))

x = np.array([1.0, 2.0], requires\_grad=True)

```

```

>>> hessian\_fn = qml.jacobian(qml.grad(circuit))

>>> hessian\_fn(x)

[[0.2248451 0.7651474]

 [0.7651474 0.2248451]]

```

* Added the function `finite\_diff()` to compute finite-difference

approximations to the gradient and the second-order derivatives of

arbitrary callable functions.

[(#1090)](https://github.com/PennyLaneAI/pennylane/pull/1090)

This is useful to compute the derivative of parametrized

`pennylane.Hamiltonian` observables with respect to their parameters.

For example, in quantum chemistry simulations it can be used to evaluate

the derivatives of the electronic Hamiltonian with respect to the nuclear

coordinates:

```

>>> def H(x):

...    return qml.qchem.molecular\_hamiltonian(['H', 'H'], x)[0]

>>> x = np.array([0., 0., -0.66140414, 0., 0., 0.66140414])

>>> grad\_fn = qml.finite\_diff(H, N=1)

>>> grad = grad\_fn(x)

>>> deriv2\_fn = qml.finite\_diff(H, N=2, idx=[0, 1])

>>> deriv2\_fn(x)

```

* The JAX interface now supports all devices, including hardware devices,

via the parameter-shift differentiation method.

[(#1076)](https://github.com/PennyLaneAI/pennylane/pull/1076)

For example, using the JAX interface with Cirq:

```

dev = qml.device('cirq.simulator', wires=1)

@qml.qnode(dev, interface="jax", diff\_method="parameter-shift")

def circuit(x):

    qml.RX(x[1], wires=0)

    qml.Rot(x[0], x[1], x[2], wires=0)

    return qml.expval(qml.PauliZ(0))

weights = jnp.array([0.2, 0.5, 0.1])

print(circuit(weights))

```

Currently, when used with the parameter-shift differentiation method,

only a single returned expectation value or variance is supported.

Multiple expectations/variances, as well as probability and state returns,

are not currently allowed.

### Improvements

```

   dev = qml.device("default.qubit", wires=2)

   inputstate = [np.sqrt(0.2), np.sqrt(0.3), np.sqrt(0.4), np.sqrt(0.1)]

   @qml.qnode(dev)

   def circuit():

       mottonen.MottonenStatePreparation(inputstate,wires=[0, 1])

       return qml.expval(qml.PauliZ(0))

Previously returned:

```

```

 >>> print(qml.draw(circuit)())

 0: ──RY(1.57)──╭C─────────────╭C──╭C──╭C──┤ ⟨Z⟩

 1: ──RY(1.35)──╰X──RY(0.422)──╰X──╰X──╰X──┤

In this release, it now returns:

```

```

>>> print(qml.draw(circuit)())

0: ──RY(1.57)──╭C─────────────╭C──┤ ⟨Z⟩

1: ──RY(1.35)──╰X──RY(0.422)──╰X──┤

```

* The templates are now classes inheriting

from `Operation`, and define the ansatz in their `expand()` method. This

change does not affect the user interface.

[(#1138)](https://github.com/PennyLaneAI/pennylane/pull/1138)

[(#1156)](https://github.com/PennyLaneAI/pennylane/pull/1156)

[(#1163)](https://github.com/PennyLaneAI/pennylane/pull/1163)

[(#1192)](https://github.com/PennyLaneAI/pennylane/pull/1192)

For convenience, some templates have a new method that returns the expected

shape of the trainable parameter tensor, which can be used to create

random tensors.

```

shape = qml.templates.BasicEntanglerLayers.shape(n\_layers=2, n\_wires=4)

weights = np.random.random(shape)

qml.templates.BasicEntanglerLayers(weights, wires=range(4))

```

* `QubitUnitary` now validates to ensure the input matrix is two dimensional.

[(#1128)](https://github.com/PennyLaneAI/pennylane/pull/1128)

* Most layers in Pytorch or Keras accept arbitrary dimension inputs, where each dimension barring

the last (in the case where the actual weight function of the layer operates on one-dimensional

vectors) is broadcast over. This is now also supported by KerasLayer and TorchLayer.

[(#1062)](https://github.com/PennyLaneAI/pennylane/pull/1062).

Example use:

```

dev = qml.device("default.qubit", wires=4)

x = tf.ones((5, 4, 4))

@qml.qnode(dev)

def layer(weights, inputs):

    qml.templates.AngleEmbedding(inputs, wires=range(4))

    qml.templates.StronglyEntanglingLayers(weights, wires=range(4))

    return [qml.expval(qml.PauliZ(i)) for i in range(4)]

qlayer = qml.qnn.KerasLayer(layer, {"weights": (4, 4, 3)}, output\_dim=4)

out = qlayer(x)

```

The output tensor has the following shape:

```

>>> out.shape

(5, 4, 4)

```

* If only one argument to the function `qml.grad` has the `requires\_grad` attribute

set to True, then the returned gradient will be a NumPy array, rather than a

tuple of length 1.

[(#1067)](https://github.com/PennyLaneAI/pennylane/pull/1067)

[(#1081)](https://github.com/PennyLaneAI/pennylane/pull/1081)

* An improvement has been made to how `QubitDevice` generates and post-processess samples,

allowing QNode measurement statistics to work on devices with more than 32 qubits.

[(#1088)](https://github.com/PennyLaneAI/pennylane/pull/1088)

* Due to the addition of `density\_matrix()` as a return type from a QNode, tuples are now supported

by the `output\_dim` parameter in `qnn.KerasLayer`.

[(#1070)](https://github.com/PennyLaneAI/pennylane/pull/1070)

* Two new utility methods are provided for working with quantum tapes.

[(#1175)](https://github.com/PennyLaneAI/pennylane/pull/1175)

	+ `qml.tape.get\_active\_tape()` gets the currently recording tape.

	+ `tape.stop\_recording()` is a context manager that temporarily

	stops the currently recording tape from recording additional

	tapes or quantum operations.For example:

```

>>> with qml.tape.QuantumTape():

...     qml.RX(0, wires=0)

...     current\_tape = qml.tape.get\_active\_tape()

...     with current\_tape.stop\_recording():

...         qml.RY(1.0, wires=1)

...     qml.RZ(2, wires=1)

>>> current\_tape.operations

[RX(0, wires=[0]), RZ(2, wires=[1])]

```

* When printing `qml.Hamiltonian` objects, the terms are sorted by number of wires followed by coefficients.

[(#981)](https://github.com/PennyLaneAI/pennylane/pull/981)

* Adds `qml.math.conj` to the PennyLane math module.

[(#1143)](https://github.com/PennyLaneAI/pennylane/pull/1143)

This new method will do elementwise conjugation to the given tensor-like object,

correctly dispatching to the required tensor-manipulation framework

to preserve differentiability.

```

>>> a = np.array([1.0 + 2.0j])

>>> qml.math.conj(a)

array([1.0 - 2.0j])

```

* The four-term parameter-shift rule, as used by the controlled rotation operations,

has been updated to use coefficients that minimize the variance as per

<https://arxiv.org/abs/2104.05695>.

[(#1206)](https://github.com/PennyLaneAI/pennylane/pull/1206)

* A new transform `qml.transforms.invisible` has been added, to make it easier

to transform QNodes.

[(#1175)](https://github.com/PennyLaneAI/pennylane/pull/1175)

### Breaking changes

* Devices do not have an `analytic` argument or attribute anymore.

Instead, `shots` is the source of truth for whether a simulator

estimates return values from a finite number of shots, or whether

it returns analytic results (`shots=None`).

[(#1079)](https://github.com/PennyLaneAI/pennylane/pull/1079)

[(#1196)](https://github.com/PennyLaneAI/pennylane/pull/1196)

```

dev\_analytic = qml.device('default.qubit', wires=1, shots=None)

dev\_finite\_shots = qml.device('default.qubit', wires=1, shots=1000)

def circuit():

    qml.Hadamard(wires=0)

    return qml.expval(qml.PauliZ(wires=0))

circuit\_analytic = qml.QNode(circuit, dev\_analytic)

circuit\_finite\_shots = qml.QNode(circuit, dev\_finite\_shots)

```

Devices with `shots=None` return deterministic, exact results:

```

>>> circuit\_analytic()

0.0

>>> circuit\_analytic()

0.0

```

Devices with `shots > 0` return stochastic results estimated from

samples in each run:

```

>>> circuit\_finite\_shots()

-0.062

>>> circuit\_finite\_shots()

0.034

```

The `qml.sample()` measurement can only be used on devices on which the number

of shots is set explicitly.

* If creating a QNode from a quantum function with an argument named `shots`,

a `UserWarning` is raised, warning the user that this is a reserved

argument to change the number of shots on a per-call basis.

[(#1075)](https://github.com/PennyLaneAI/pennylane/pull/1075)

* For devices inheriting from `QubitDevice`, the methods `expval`, `var`, `sample`

accept two new keyword arguments — `shot\_range` and `bin\_size`.

[(#1103)](https://github.com/PennyLaneAI/pennylane/pull/1103)

These new arguments allow for the statistics to be performed on only a subset of device samples.

This finer level of control is accessible from the main UI by instantiating a device with a batch

of shots.

For example, consider the following device:

```

>>> dev = qml.device("my\_device", shots=[5, (10, 3), 100])

```

This device will execute QNodes using 135 shots, however

measurement statistics will be **course grained** across these 135

shots:

	+ All measurement statistics will first be computed using the

	first 5 shots — that is, `shots\_range=[0, 5]`, `bin\_size=5`.

	+ Next, the tuple `(10, 3)` indicates 10 shots, repeated 3 times. This will use

	`shot\_range=[5, 35]`, performing the expectation value in bins of size 10

	(`bin\_size=10`).

	+ Finally, we repeat the measurement statistics for the final 100 shots,

	`shot\_range=[35, 135]`, `bin\_size=100`.

* The old PennyLane core has been removed, including the following modules:

[(#1100)](https://github.com/PennyLaneAI/pennylane/pull/1100)

	+ `pennylane.variables`

	+ `pennylane.qnodes`As part of this change, the location of the new core within the Python

module has been moved:

	+ Moves `pennylane.tape.interfaces` → `pennylane.interfaces`

	+ Merges `pennylane.CircuitGraph` and `pennylane.TapeCircuitGraph` → `pennylane.CircuitGraph`

	+ Merges `pennylane.OperationRecorder` and `pennylane.TapeOperationRecorder` →

	+ `pennylane.tape.operation\_recorder`

	+ Merges `pennylane.measure` and `pennylane.tape.measure` → `pennylane.measure`

	+ Merges `pennylane.operation` and `pennylane.tape.operation` → `pennylane.operation`

	+ Merges `pennylane.\_queuing` and `pennylane.tape.queuing` → `pennylane.queuing`This has no affect on import location.

In addition,

	+ All tape-mode functions have been removed (`qml.enable\_tape()`, `qml.tape\_mode\_active()`),

	+ All tape fixtures have been deleted,

	+ Tests specifically for non-tape mode have been deleted.

* The device test suite no longer accepts the `analytic` keyword.

[(#1216)](https://github.com/PennyLaneAI/pennylane/pull/1216)

### Bug fixes

* Fixes a bug where using the circuit drawer with a `ControlledQubitUnitary`

operation raised an error.

[(#1174)](https://github.com/PennyLaneAI/pennylane/pull/1174)

* Fixes a bug and a test where the `QuantumTape.is\_sampled` attribute was not

being updated.

[(#1126)](https://github.com/PennyLaneAI/pennylane/pull/1126)

* Fixes a bug where `BasisEmbedding` would not accept inputs whose bits are all ones

or all zeros.

[(#1114)](https://github.com/PennyLaneAI/pennylane/pull/1114)

* The `ExpvalCost` class raises an error if instantiated

with non-expectation measurement statistics.

[(#1106)](https://github.com/PennyLaneAI/pennylane/pull/1106)

* Fixes a bug where decompositions would reset the differentiation method

of a QNode.

[(#1117)](https://github.com/PennyLaneAI/pennylane/pull/1117)

* Fixes a bug where the second-order CV parameter-shift rule would error

if attempting to compute the gradient of a QNode with more than one

second-order observable.

[(#1197)](https://github.com/PennyLaneAI/pennylane/pull/1197)

* Fixes a bug where repeated Torch interface applications after expansion caused an error.

[(#1223)](https://github.com/PennyLaneAI/pennylane/pull/1223)

* Sampling works correctly with batches of shots specified as a list.

[(#1232)](https://github.com/PennyLaneAI/pennylane/pull/1232)

### Documentation

* Updated the diagram used in the Architectural overview page of the

Development guide such that it doesn’t mention Variables.

[(#1235)](https://github.com/PennyLaneAI/pennylane/pull/1235)

* Typos addressed in templates documentation.

[(#1094)](https://github.com/PennyLaneAI/pennylane/pull/1094)

* Upgraded the documentation to use Sphinx 3.5.3 and the new m2r2 package.

[(#1186)](https://github.com/PennyLaneAI/pennylane/pull/1186)

* Added `flaky` as dependency for running tests in the documentation.

[(#1113)](https://github.com/PennyLaneAI/pennylane/pull/1113)

### Contributors

This release contains contributions from (in alphabetical order):

Shahnawaz Ahmed, Juan Miguel Arrazola, Thomas Bromley, Olivia Di Matteo, Alain Delgado Gran, Kyle

Godbey, Diego Guala, Theodor Isacsson, Josh Izaac, Soran Jahangiri, Nathan Killoran, Christina Lee,

Daniel Polatajko, Chase Roberts, Sankalp Sanand, Pritish Sehzpaul, Maria Schuld, Antal Száva, David Wierichs.

orphan

#### Release 0.14.1[¶](#release-0-14-1 "Permalink to this headline")

### Bug fixes

* Fixes a testing bug where tests that required JAX would fail if JAX was not installed.

The tests will now instead be skipped if JAX can not be imported.

[(#1066)](https://github.com/PennyLaneAI/pennylane/pull/1066)

* Fixes a bug where inverse operations could not be differentiated

using backpropagation on `default.qubit`.

[(#1072)](https://github.com/PennyLaneAI/pennylane/pull/1072)

* The QNode has a new keyword argument, `max\_expansion`, that determines the maximum number of times

the internal circuit should be expanded when executed on a device. In addition, the default number

of max expansions has been increased from 2 to 10, allowing devices that require more than two

operator decompositions to be supported.

[(#1074)](https://github.com/PennyLaneAI/pennylane/pull/1074)

* Fixes a bug where `Hamiltonian` objects created with non-list arguments raised an error for

arithmetic operations. [(#1082)](https://github.com/PennyLaneAI/pennylane/pull/1082)

* Fixes a bug where `Hamiltonian` objects with no coefficients or operations would return a faulty

result when used with `ExpvalCost`. [(#1082)](https://github.com/PennyLaneAI/pennylane/pull/1082)

### Documentation

* Updates mentions of `generate\_hamiltonian` to `molecular\_hamiltonian` in the

docstrings of the `ExpvalCost` and `Hamiltonian` classes.

[(#1077)](https://github.com/PennyLaneAI/pennylane/pull/1077)

### Contributors

This release contains contributions from (in alphabetical order):

Thomas Bromley, Josh Izaac, Antal Száva.

orphan

#### Release 0.14.0[¶](#release-0-14-0 "Permalink to this headline")

### New features since last release

#### Perform quantum machine learning with JAX

* QNodes created with `default.qubit` now support a JAX interface, allowing JAX to be used

to create, differentiate, and optimize hybrid quantum-classical models.

[(#947)](https://github.com/PennyLaneAI/pennylane/pull/947)

This is supported internally via a new `default.qubit.jax` device. This device runs end to end in

JAX, meaning that it supports all of the awesome JAX transformations (`jax.vmap`, `jax.jit`,

`jax.hessian`, etc).

Here is an example of how to use the new JAX interface:

```

dev = qml.device("default.qubit", wires=1)

@qml.qnode(dev, interface="jax", diff\_method="backprop")

def circuit(x):

    qml.RX(x[1], wires=0)

    qml.Rot(x[0], x[1], x[2], wires=0)

    return qml.expval(qml.PauliZ(0))

weights = jnp.array([0.2, 0.5, 0.1])

grad\_fn = jax.grad(circuit)

print(grad\_fn(weights))

```

Currently, only `diff\_method="backprop"` is supported, with plans to support more in the future.

#### New, faster, quantum gradient methods

* A new differentiation method has been added for use with simulators. The `"adjoint"`

method operates after a forward pass by iteratively applying inverse gates to scan backwards

through the circuit.

[(#1032)](https://github.com/PennyLaneAI/pennylane/pull/1032)

This method is similar to the reversible method, but has a lower time

overhead and a similar memory overhead. It follows the approach provided by

[Jones and Gacon](https://arxiv.org/abs/2009.02823). This method is only compatible with certain

statevector-based devices such as `default.qubit`.

Example use:

```

import pennylane as qml

wires = 1

device = qml.device("default.qubit", wires=wires)

@qml.qnode(device, diff\_method="adjoint")

def f(params):

    qml.RX(0.1, wires=0)

    qml.Rot(\*params, wires=0)

    qml.RX(-0.3, wires=0)

    return qml.expval(qml.PauliZ(0))

params = [0.1, 0.2, 0.3]

qml.grad(f)(params)

```

* The default logic for choosing the ‘best’ differentiation method has been altered

to improve performance.

[(#1008)](https://github.com/PennyLaneAI/pennylane/pull/1008)

	+ If the quantum device provides its own gradient, this is now the preferred

	differentiation method.

	+ If the quantum device natively supports classical

	backpropagation, this is now preferred over the parameter-shift rule.

	

	

	This will lead to marked speed improvement during optimization when using

	`default.qubit`, with a sight penalty on the forward-pass evaluation.More details are available below in the ‘Improvements’ section for plugin developers.

* PennyLane now supports analytical quantum gradients for noisy channels, in addition to its

existing support for unitary operations. The noisy channels `BitFlip`, `PhaseFlip`, and

`DepolarizingChannel` all support analytic gradients out of the box.

[(#968)](https://github.com/PennyLaneAI/pennylane/pull/968)

* A method has been added for calculating the Hessian of quantum circuits using the second-order

parameter shift formula.

[(#961)](https://github.com/PennyLaneAI/pennylane/pull/961)

The following example shows the calculation of the Hessian:

```

n\_wires = 5

weights = [2.73943676, 0.16289932, 3.4536312, 2.73521126, 2.6412488]

dev = qml.device("default.qubit", wires=n\_wires)

with qml.tape.QubitParamShiftTape() as tape:

    for i in range(n\_wires):

        qml.RX(weights[i], wires=i)

    qml.CNOT(wires=[0, 1])

    qml.CNOT(wires=[2, 1])

    qml.CNOT(wires=[3, 1])

    qml.CNOT(wires=[4, 3])

    qml.expval(qml.PauliZ(1))

print(tape.hessian(dev))

```

The Hessian is not yet supported via classical machine learning interfaces, but will

be added in a future release.

#### More operations and templates

* Two new error channels, `BitFlip` and `PhaseFlip` have been added.

[(#954)](https://github.com/PennyLaneAI/pennylane/pull/954)

They can be used in the same manner as existing error channels:

```

dev = qml.device("default.mixed", wires=2)

@qml.qnode(dev)

def circuit():

    qml.RX(0.3, wires=0)

    qml.RY(0.5, wires=1)

    qml.BitFlip(0.01, wires=0)

    qml.PhaseFlip(0.01, wires=1)

    return qml.expval(qml.PauliZ(0))

```

* Apply permutations to wires using the `Permute` subroutine.

[(#952)](https://github.com/PennyLaneAI/pennylane/pull/952)

```

import pennylane as qml

dev = qml.device('default.qubit', wires=5)

@qml.qnode(dev)

def apply\_perm():

    # Send contents of wire 4 to wire 0, of wire 2 to wire 1, etc.

    qml.templates.Permute([4, 2, 0, 1, 3], wires=dev.wires)

    return qml.expval(qml.PauliZ(0))

```

#### QNode transformations

* The `qml.metric\_tensor` function transforms a QNode to produce the Fubini-Study

metric tensor with full autodifferentiation support—even on hardware.

[(#1014)](https://github.com/PennyLaneAI/pennylane/pull/1014)

Consider the following QNode:

```

dev = qml.device("default.qubit", wires=3)

@qml.qnode(dev, interface="autograd")

def circuit(weights):

    # layer 1

    qml.RX(weights[0, 0], wires=0)

    qml.RX(weights[0, 1], wires=1)

    qml.CNOT(wires=[0, 1])

    qml.CNOT(wires=[1, 2])

    # layer 2

    qml.RZ(weights[1, 0], wires=0)

    qml.RZ(weights[1, 1], wires=2)

    qml.CNOT(wires=[0, 1])

    qml.CNOT(wires=[1, 2])

    return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1)), qml.expval(qml.PauliY(2))

```

We can use the `metric\_tensor` function to generate a new function, that returns the

metric tensor of this QNode:

```

>>> met\_fn = qml.metric\_tensor(circuit)

>>> weights = np.array([[0.1, 0.2, 0.3], [0.4, 0.5, 0.6]], requires\_grad=True)

>>> met\_fn(weights)

tensor([[0.25 , 0. , 0. , 0. ],

 [0. , 0.25 , 0. , 0. ],

 [0. , 0. , 0.0025, 0.0024],

 [0. , 0. , 0.0024, 0.0123]], requires\_grad=True)

```

The returned metric tensor is also fully differentiable, in all interfaces.

For example, differentiating the `(3, 2)` element:

```

>>> grad\_fn = qml.grad(lambda x: met\_fn(x)[3, 2])

>>> grad\_fn(weights)

array([[ 0.04867729, -0.00049502, 0. ],

 [ 0. , 0. , 0. ]])

```

Differentiation is also supported using Torch, Jax, and TensorFlow.

* Adds the new function `qml.math.cov\_matrix()`. This function accepts a list of commuting

observables, and the probability distribution in the shared observable eigenbasis after the

application of an ansatz. It uses these to construct the covariance matrix in a *framework

independent* manner, such that the output covariance matrix is autodifferentiable.

[(#1012)](https://github.com/PennyLaneAI/pennylane/pull/1012)

For example, consider the following ansatz and observable list:

```

obs\_list = [qml.PauliX(0) @ qml.PauliZ(1), qml.PauliY(2)]

ansatz = qml.templates.StronglyEntanglingLayers

```

We can construct a QNode to output the probability distribution in the shared eigenbasis of the

observables:

```

dev = qml.device("default.qubit", wires=3)

@qml.qnode(dev, interface="autograd")

def circuit(weights):

    ansatz(weights, wires=[0, 1, 2])

    # rotate into the basis of the observables

    for o in obs\_list:

        o.diagonalizing\_gates()

    return qml.probs(wires=[0, 1, 2])

```

We can now compute the covariance matrix:

```

>>> weights = qml.init.strong\_ent\_layers\_normal(n\_layers=2, n\_wires=3)

>>> cov = qml.math.cov\_matrix(circuit(weights), obs\_list)

>>> cov

array([[0.98707611, 0.03665537],

 [0.03665537, 0.99998377]])

```

Autodifferentiation is fully supported using all interfaces:

```

>>> cost\_fn = lambda weights: qml.math.cov\_matrix(circuit(weights), obs\_list)[0, 1]

>>> qml.grad(cost\_fn)(weights)[0]

array([[[ 4.94240914e-17, -2.33786398e-01, -1.54193959e-01],

 [-3.05414996e-17, 8.40072236e-04, 5.57884080e-04],

 [ 3.01859411e-17, 8.60411436e-03, 6.15745204e-04]],

 [[ 6.80309533e-04, -1.23162742e-03, 1.08729813e-03],

 [-1.53863193e-01, -1.38700657e-02, -1.36243323e-01],

 [-1.54665054e-01, -1.89018172e-02, -1.56415558e-01]]])

```

* A new `qml.draw` function is available, allowing QNodes to be easily

drawn without execution by providing example input.

[(#962)](https://github.com/PennyLaneAI/pennylane/pull/962)

```

@qml.qnode(dev)

def circuit(a, w):

    qml.Hadamard(0)

    qml.CRX(a, wires=[0, 1])

    qml.Rot(\*w, wires=[1])

    qml.CRX(-a, wires=[0, 1])

    return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1))

```

The QNode circuit structure may depend on the input arguments;

this is taken into account by passing example QNode arguments

to the `qml.draw()` drawing function:

```

>>> drawer = qml.draw(circuit)

>>> result = drawer(a=2.3, w=[1.2, 3.2, 0.7])

>>> print(result)

0: ──H──╭C────────────────────────────╭C─────────╭┤ ⟨Z ⊗ Z⟩

1: ─────╰RX(2.3)──Rot(1.2, 3.2, 0.7)──╰RX(-2.3)──╰┤ ⟨Z ⊗ Z⟩

```

#### A faster, leaner, and more flexible core

* The new core of PennyLane, rewritten from the ground up and developed over the last few release

cycles, has achieved feature parity and has been made the new default in PennyLane v0.14. The old

core has been marked as deprecated, and will be removed in an upcoming release.

[(#1046)](https://github.com/PennyLaneAI/pennylane/pull/1046)

[(#1040)](https://github.com/PennyLaneAI/pennylane/pull/1040)

[(#1034)](https://github.com/PennyLaneAI/pennylane/pull/1034)

[(#1035)](https://github.com/PennyLaneAI/pennylane/pull/1035)

[(#1027)](https://github.com/PennyLaneAI/pennylane/pull/1027)

[(#1026)](https://github.com/PennyLaneAI/pennylane/pull/1026)

[(#1021)](https://github.com/PennyLaneAI/pennylane/pull/1021)

[(#1054)](https://github.com/PennyLaneAI/pennylane/pull/1054)

[(#1049)](https://github.com/PennyLaneAI/pennylane/pull/1049)

While high-level PennyLane code and tutorials remain unchanged, the new core

provides several advantages and improvements:

	+ **Faster and more optimized**: The new core provides various performance optimizations, reducing

	pre- and post-processing overhead, and reduces the number of quantum evaluations in certain

	cases.

	+ **Support for in-QNode classical processing**: this allows for differentiable classical

	processing within the QNode.

	

	

	

	```

	dev = qml.device("default.qubit", wires=1)

	

	@qml.qnode(dev, interface="tf")

	def circuit(p):

	    qml.RX(tf.sin(p[0])\*\*2 + p[1], wires=0)

	    return qml.expval(qml.PauliZ(0))

	

	```

	

	

	The classical processing functions used within the QNode must match

	the QNode interface. Here, we use TensorFlow:

	

	

	

	```

	>>> params = tf.Variable([0.5, 0.1], dtype=tf.float64)

	>>> with tf.GradientTape() as tape:

	...     res = circuit(params)

	>>> grad = tape.gradient(res, params)

	>>> print(res)

	tf.Tensor(0.9460913127754935, shape=(), dtype=float64)

	>>> print(grad)

	tf.Tensor([-0.27255248 -0.32390003], shape=(2,), dtype=float64)

	

	```

	

	

	As a result of this change, quantum decompositions that require classical processing

	are fully supported and end-to-end differentiable in tape mode.

	+ **No more Variable wrapping**: QNode arguments no longer become `Variable`

	objects within the QNode.

	

	

	

	```

	dev = qml.device("default.qubit", wires=1)

	

	@qml.qnode(dev)

	def circuit(x):

	    print("Parameter value:", x)

	    qml.RX(x, wires=0)

	    return qml.expval(qml.PauliZ(0))

	

	```

	

	

	Internal QNode parameters can be easily inspected, printed, and manipulated:

	

	

	

	```

	>>> circuit(0.5)

	Parameter value: 0.5

	tensor(0.87758256, requires\_grad=True)

	

	```

	+ **Less restrictive QNode signatures**: There is no longer any restriction on the QNode signature; the QNode can be

	defined and called following the same rules as standard Python functions.

	

	

	For example, the following QNode uses positional, named, and variable

	keyword arguments:

	

	

	

	```

	x = torch.tensor(0.1, requires\_grad=True)

	y = torch.tensor([0.2, 0.3], requires\_grad=True)

	z = torch.tensor(0.4, requires\_grad=True)

	

	@qml.qnode(dev, interface="torch")

	def circuit(p1, p2=y, \*\*kwargs):

	    qml.RX(p1, wires=0)

	    qml.RY(p2[0] \* p2[1], wires=0)

	    qml.RX(kwargs["p3"], wires=0)

	    return qml.var(qml.PauliZ(0))

	

	```

	

	

	When we call the QNode, we may pass the arguments by name

	even if defined positionally; any argument not provided will

	use the default value.

	

	

	

	```

	>>> res = circuit(p1=x, p3=z)

	>>> print(res)

	tensor(0.2327, dtype=torch.float64, grad\_fn=<SelectBackward>)

	>>> res.backward()

	>>> print(x.grad, y.grad, z.grad)

	tensor(0.8396) tensor([0.0289, 0.0193]) tensor(0.8387)

	

	```

	

	

	This extends to the `qnn` module, where `KerasLayer` and `TorchLayer` modules

	can be created from QNodes with unrestricted signatures.

	+ **Smarter measurements:** QNodes can now measure wires more than once, as

	long as all observables are commuting:

	

	

	

	```

	@qml.qnode(dev)

	def circuit(x):

	    qml.RX(x, wires=0)

	    return [

	        qml.expval(qml.PauliZ(0)),

	        qml.expval(qml.PauliZ(0) @ qml.PauliZ(1))

	    ]

	

	```

	

	

	Further, the `qml.ExpvalCost()` function allows for optimizing

	measurements to reduce the number of quantum evaluations required.With the new PennyLane core, there are a few small breaking changes, detailed

below in the ‘Breaking Changes’ section.

### Improvements

* The built-in PennyLane optimizers allow more flexible cost functions. The cost function passed to most optimizers

may accept any combination of trainable arguments, non-trainable arguments, and keyword arguments.

[(#959)](https://github.com/PennyLaneAI/pennylane/pull/959)

[(#1053)](https://github.com/PennyLaneAI/pennylane/pull/1053)

The full changes apply to:

	+ `AdagradOptimizer`

	+ `AdamOptimizer`

	+ `GradientDescentOptimizer`

	+ `MomentumOptimizer`

	+ `NesterovMomentumOptimizer`

	+ `RMSPropOptimizer`

	+ `RotosolveOptimizer`The `requires\_grad=False` property must mark any non-trainable constant argument.

The `RotoselectOptimizer` allows passing only keyword arguments.

Example use:

```

def cost(x, y, data, scale=1.0):

    return scale \* (x[0]-data)\*\*2 + scale \* (y-data)\*\*2

x = np.array([1.], requires\_grad=True)

y = np.array([1.0])

data = np.array([2.], requires\_grad=False)

opt = qml.GradientDescentOptimizer()

# the optimizer step and step\_and\_cost methods can

# now update multiple parameters at once

x\_new, y\_new, data = opt.step(cost, x, y, data, scale=0.5)

(x\_new, y\_new, data), value = opt.step\_and\_cost(cost, x, y, data, scale=0.5)

# list and tuple unpacking is also supported

params = (x, y, data)

params = opt.step(cost, \*params)

```

* The circuit drawer has been updated to support the inclusion of unused or inactive

wires, by passing the `show\_all\_wires` argument.

[(#1033)](https://github.com/PennyLaneAI/pennylane/pull/1033)

```

dev = qml.device('default.qubit', wires=[-1, "a", "q2", 0])

@qml.qnode(dev)

def circuit():

    qml.Hadamard(wires=-1)

    qml.CNOT(wires=[-1, "q2"])

    return qml.expval(qml.PauliX(wires="q2"))

```

```

>>> print(qml.draw(circuit, show\_all\_wires=True)())

>>>

 -1: ──H──╭C──┤

 a: ─────│───┤

 q2: ─────╰X──┤ ⟨X⟩

 0: ─────────┤

```

* The logic for choosing the ‘best’ differentiation method has been altered

to improve performance.

[(#1008)](https://github.com/PennyLaneAI/pennylane/pull/1008)

	+ If the device provides its own gradient, this is now the preferred

	differentiation method.

	+ If a device provides additional interface-specific versions that natively support classical

	backpropagation, this is now preferred over the parameter-shift rule.

	

	

	Devices define additional interface-specific devices via their `capabilities()` dictionary. For

	example, `default.qubit` supports supplementary devices for TensorFlow, Autograd, and JAX:

	

	

	

	```

	{

	  "passthru\_devices": {

	      "tf": "default.qubit.tf",

	      "autograd": "default.qubit.autograd",

	      "jax": "default.qubit.jax",

	  },

	}

	

	```As a result of this change, if the QNode `diff\_method` is not explicitly provided,

it is possible that the QNode will run on a *supplementary device* of the device that was

specifically provided:

```

dev = qml.device("default.qubit", wires=2)

qml.QNode(dev) # will default to backprop on default.qubit.autograd

qml.QNode(dev, interface="tf") # will default to backprop on default.qubit.tf

qml.QNode(dev, interface="jax") # will default to backprop on default.qubit.jax

```

* The `default.qubit` device has been updated so that internally it applies operations in a more

functional style, i.e., by accepting an input state and returning an evolved state.

[(#1025)](https://github.com/PennyLaneAI/pennylane/pull/1025)

* A new test series, `pennylane/devices/tests/test\_compare\_default\_qubit.py`, has been added, allowing to test if

a chosen device gives the same result as `default.qubit`.

[(#897)](https://github.com/PennyLaneAI/pennylane/pull/897)

Three tests are added:

	+ `test\_hermitian\_expectation`,

	+ `test\_pauliz\_expectation\_analytic`, and

	+ `test\_random\_circuit`.

* Adds the following agnostic tensor manipulation functions to the `qml.math` module: `abs`,

`angle`, `arcsin`, `concatenate`, `dot`, `squeeze`, `sqrt`, `sum`, `take`, `where`. These functions are

required to fully support end-to-end differentiable Mottonen and Amplitude embedding.

[(#922)](https://github.com/PennyLaneAI/pennylane/pull/922)

[(#1011)](https://github.com/PennyLaneAI/pennylane/pull/1011)

* The `qml.math` module now supports JAX.

[(#985)](https://github.com/XanaduAI/software-docs/pull/274)

* Several improvements have been made to the `Wires` class to reduce overhead and simplify the logic

of how wire labels are interpreted:

[(#1019)](https://github.com/PennyLaneAI/pennylane/pull/1019)

[(#1010)](https://github.com/PennyLaneAI/pennylane/pull/1010)

[(#1005)](https://github.com/PennyLaneAI/pennylane/pull/1005)

[(#983)](https://github.com/PennyLaneAI/pennylane/pull/983)

[(#967)](https://github.com/PennyLaneAI/pennylane/pull/967)

	+ If the input `wires` to a wires class instantiation `Wires(wires)` can be iterated over,

	its elements are interpreted as wire labels. Otherwise, `wires` is interpreted as a single wire label.

	The only exception to this are strings, which are always interpreted as a single

	wire label, so users can address wires with labels such as `"ancilla"`.

	+ Any type can now be a wire label as long as it is hashable. The hash is used to establish

	the uniqueness of two labels.

	+ Indexing wires objects now returns a label, instead of a new `Wires` object. For example:

	

	

	

	```

	>>> w = Wires([0, 1, 2])

	>>> w[1]

	>>> 1

	

	```

	+ The check for uniqueness of wires moved from `Wires` instantiation to

	the `qml.wires.\_process` function in order to reduce overhead from repeated

	creation of `Wires` instances.

	+ Calls to the `Wires` class are substantially reduced, for example by avoiding to call

	Wires on Wires instances on `Operation` instantiation, and by using labels instead of

	`Wires` objects inside the default qubit device.

* Adds the `PauliRot` generator to the `qml.operation` module. This

generator is required to construct the metric tensor.

[(#963)](https://github.com/PennyLaneAI/pennylane/pull/963)

* The templates are modified to make use of the new `qml.math` module, for framework-agnostic

tensor manipulation. This allows the template library to be differentiable

in backpropagation mode (`diff\_method="backprop"`).

[(#873)](https://github.com/PennyLaneAI/pennylane/pull/873)

* The circuit drawer now allows for the wire order to be (optionally) modified:

[(#992)](https://github.com/PennyLaneAI/pennylane/pull/992)

```

>>> dev = qml.device('default.qubit', wires=["a", -1, "q2"])

>>> @qml.qnode(dev)

... def circuit():

...     qml.Hadamard(wires=-1)

...     qml.CNOT(wires=["a", "q2"])

...     qml.RX(0.2, wires="a")

...     return qml.expval(qml.PauliX(wires="q2"))

```

Printing with default wire order of the device:

```

>>> print(circuit.draw())

 a: ─────╭C──RX(0.2)──┤

 -1: ──H──│────────────┤

 q2: ─────╰X───────────┤ ⟨X⟩

```

Changing the wire order:

```

>>> print(circuit.draw(wire\_order=["q2", "a", -1]))

 q2: ──╭X───────────┤ ⟨X⟩

 a: ──╰C──RX(0.2)──┤

 -1: ───H───────────┤

```

### Breaking changes

* QNodes using the new PennyLane core will no longer accept ragged arrays as inputs.

* When using the new PennyLane core and the Autograd interface, non-differentiable data passed

as a QNode argument or a gate must have the `requires\_grad` property set to `False`:

```

@qml.qnode(dev)

def circuit(weights, data):

    basis\_state = np.array([1, 0, 1, 1], requires\_grad=False)

    qml.BasisState(basis\_state, wires=[0, 1, 2, 3])

    qml.templates.AmplitudeEmbedding(data, wires=[0, 1, 2, 3])

    qml.templates.BasicEntanglerLayers(weights, wires=[0, 1, 2, 3])

    return qml.probs(wires=0)

data = np.array(data, requires\_grad=False)

weights = np.array(weights, requires\_grad=True)

circuit(weights, data)

```

### Bug fixes

* Fixes an issue where if the constituent observables of a tensor product do not exist in the queue,

an error is raised. With this fix, they are first queued before annotation occurs.

[(#1038)](https://github.com/PennyLaneAI/pennylane/pull/1038)

* Fixes an issue with tape expansions where information about sampling

(specifically the `is\_sampled` tape attribute) was not preserved.

[(#1027)](https://github.com/PennyLaneAI/pennylane/pull/1027)

* Tape expansion was not properly taking into devices that supported inverse operations,

causing inverse operations to be unnecessarily decomposed. The QNode tape expansion logic, as well

as the `Operation.expand()` method, has been modified to fix this.

[(#956)](https://github.com/PennyLaneAI/pennylane/pull/956)

* Fixes an issue where the Autograd interface was not unwrapping non-differentiable

PennyLane tensors, which can cause issues on some devices.

[(#941)](https://github.com/PennyLaneAI/pennylane/pull/941)

* `qml.vqe.Hamiltonian` prints any observable with any number of strings.

[(#987)](https://github.com/PennyLaneAI/pennylane/pull/987)

* Fixes a bug where parameter-shift differentiation would fail if the QNode

contained a single probability output.

[(#1007)](https://github.com/PennyLaneAI/pennylane/pull/1007)

* Fixes an issue when using trainable parameters that are lists/arrays with `tape.vjp`.

[(#1042)](https://github.com/PennyLaneAI/pennylane/pull/1042)

* The `TensorN` observable is updated to support being copied without any parameters or wires passed.

[(#1047)](https://github.com/PennyLaneAI/pennylane/pull/1047)

* Fixed deprecation warning when importing `Sequence` from `collections` instead of `collections.abc` in `vqe/vqe.py`.

[(#1051)](https://github.com/PennyLaneAI/pennylane/pull/1051)

### Contributors

This release contains contributions from (in alphabetical order):

Juan Miguel Arrazola, Thomas Bromley, Olivia Di Matteo, Theodor Isacsson, Josh Izaac, Christina Lee,

Alejandro Montanez, Steven Oud, Chase Roberts, Sankalp Sanand, Maria Schuld, Antal

Száva, David Wierichs, Jiahao Yao.

orphan

#### Release 0.13.0[¶](#release-0-13-0 "Permalink to this headline")

### New features since last release

#### Automatically optimize the number of measurements

* QNodes in tape mode now support returning observables on the same wire whenever the observables are

qubit-wise commuting Pauli words. Qubit-wise commuting observables can be evaluated with a

*single* device run as they are diagonal in the same basis, via a shared set of single-qubit rotations.

[(#882)](https://github.com/PennyLaneAI/pennylane/pull/882)

The following example shows a single QNode returning the expectation values of

the qubit-wise commuting Pauli words `XX` and `XI`:

```

qml.enable\_tape()

@qml.qnode(dev)

def f(x):

    qml.Hadamard(wires=0)

    qml.Hadamard(wires=1)

    qml.CRot(0.1, 0.2, 0.3, wires=[1, 0])

    qml.RZ(x, wires=1)

    return qml.expval(qml.PauliX(0) @ qml.PauliX(1)), qml.expval(qml.PauliX(0))

```

```

>>> f(0.4)

tensor([0.89431013, 0.9510565 ], requires\_grad=True)

```

* The `ExpvalCost` class (previously `VQECost`) now provides observable optimization using the

`optimize` argument, resulting in potentially fewer device executions.

[(#902)](https://github.com/PennyLaneAI/pennylane/pull/902)

This is achieved by separating the observables composing the Hamiltonian into qubit-wise

commuting groups and evaluating those groups on a single QNode using functionality from the

`qml.grouping` module:

```

qml.enable\_tape()

commuting\_obs = [qml.PauliX(0), qml.PauliX(0) @ qml.PauliZ(1)]

H = qml.vqe.Hamiltonian([1, 1], commuting\_obs)

dev = qml.device("default.qubit", wires=2)

ansatz = qml.templates.StronglyEntanglingLayers

cost\_opt = qml.ExpvalCost(ansatz, H, dev, optimize=True)

cost\_no\_opt = qml.ExpvalCost(ansatz, H, dev, optimize=False)

params = qml.init.strong\_ent\_layers\_uniform(3, 2)

```

Grouping these commuting observables leads to fewer device executions:

```

>>> cost\_opt(params)

>>> ex\_opt = dev.num\_executions

>>> cost\_no\_opt(params)

>>> ex\_no\_opt = dev.num\_executions - ex\_opt

>>> print("Number of executions:", ex\_no\_opt)

Number of executions: 2

>>> print("Number of executions (optimized):", ex\_opt)

Number of executions (optimized): 1

```

#### New quantum gradient features

* Compute the analytic gradient of quantum circuits in parallel on supported devices.

[(#840)](https://github.com/PennyLaneAI/pennylane/pull/840)

This release introduces support for batch execution of circuits, via a new device API method

`Device.batch\_execute()`. Devices that implement this new API support submitting a batch of

circuits for *parallel* evaluation simultaneously, which can significantly reduce the computation time.

Furthermore, if using tape mode and a compatible device, gradient computations will

automatically make use of the new batch API—providing a speedup during optimization.

* Gradient recipes are now much more powerful, allowing for operations to define their gradient

via an arbitrary linear combination of circuit evaluations.

[(#909)](https://github.com/PennyLaneAI/pennylane/pull/909)

[(#915)](https://github.com/PennyLaneAI/pennylane/pull/915)

With this change, gradient recipes can now be of the form

\(\frac{\partial}{\partial\phi\_k}f(\phi\_k) = \sum\_{i} c\_i f(a\_i \phi\_k + s\_i )\),

and are no longer restricted to two-term shifts with identical (but opposite in sign) shift values.

As a result, PennyLane now supports native analytic quantum gradients for the

controlled rotation operations `CRX`, `CRY`, `CRZ`, and `CRot`. This allows for parameter-shift

analytic gradients on hardware, without decomposition.

Note that this is a breaking change for developers; please see the *Breaking Changes* section

for more details.

* The `qnn.KerasLayer` class now supports differentiating the QNode through classical

backpropagation in tape mode.

[(#869)](https://github.com/PennyLaneAI/pennylane/pull/869)

```

qml.enable\_tape()

dev = qml.device("default.qubit.tf", wires=2)

@qml.qnode(dev, interface="tf", diff\_method="backprop")

def f(inputs, weights):

    qml.templates.AngleEmbedding(inputs, wires=range(2))

    qml.templates.StronglyEntanglingLayers(weights, wires=range(2))

    return [qml.expval(qml.PauliZ(i)) for i in range(2)]

weight\_shapes = {"weights": (3, 2, 3)}

qlayer = qml.qnn.KerasLayer(f, weight\_shapes, output\_dim=2)

inputs = tf.constant(np.random.random((4, 2)), dtype=tf.float32)

with tf.GradientTape() as tape:

    out = qlayer(inputs)

tape.jacobian(out, qlayer.trainable\_weights)

```

#### New operations, templates, and measurements

* Adds the `qml.density\_matrix` QNode return with partial trace capabilities.

[(#878)](https://github.com/PennyLaneAI/pennylane/pull/878)

The density matrix over the provided wires is returned, with all other subsystems traced out.

`qml.density\_matrix` currently works for both the `default.qubit` and `default.mixed` devices.

```

qml.enable\_tape()

dev = qml.device("default.qubit", wires=2)

def circuit(x):

    qml.PauliY(wires=0)

    qml.Hadamard(wires=1)

    return qml.density\_matrix(wires=[1])  # wire 0 is traced out

```

* Adds the square-root X gate `SX`. [(#871)](https://github.com/PennyLaneAI/pennylane/pull/871)

```

dev = qml.device("default.qubit", wires=1)

@qml.qnode(dev)

def circuit():

    qml.SX(wires=[0])

    return qml.expval(qml.PauliZ(wires=[0]))

```

* Two new hardware-efficient particle-conserving templates have been implemented

to perform VQE-based quantum chemistry simulations. The new templates apply

several layers of the particle-conserving entanglers proposed in Figs. 2a and 2b

of Barkoutsos *et al*., [arXiv:1805.04340](https://arxiv.org/abs/1805.04340)

[(#875)](https://github.com/PennyLaneAI/pennylane/pull/875)

[(#876)](https://github.com/PennyLaneAI/pennylane/pull/876)

#### Estimate and track resources

* The `QuantumTape` class now contains basic resource estimation functionality. The method

`tape.get\_resources()` returns a dictionary with a list of the constituent operations and the

number of times they appear in the circuit. Similarly, `tape.get\_depth()` computes the circuit depth.

[(#862)](https://github.com/PennyLaneAI/pennylane/pull/862)

```

>>> with qml.tape.QuantumTape() as tape:

...    qml.Hadamard(wires=0)

...    qml.RZ(0.26, wires=1)

...    qml.CNOT(wires=[1, 0])

...    qml.Rot(1.8, -2.7, 0.2, wires=0)

...    qml.Hadamard(wires=1)

...    qml.CNOT(wires=[0, 1])

...    qml.expval(qml.PauliZ(0) @ qml.PauliZ(1))

>>> tape.get\_resources()

{'Hadamard': 2, 'RZ': 1, 'CNOT': 2, 'Rot': 1}

>>> tape.get\_depth()

4

```

* The number of device executions over a QNode’s lifetime can now be returned using `num\_executions`.

[(#853)](https://github.com/PennyLaneAI/pennylane/pull/853)

```

>>> dev = qml.device("default.qubit", wires=2)

>>> @qml.qnode(dev)

... def circuit(x, y):

...    qml.RX(x, wires=[0])

...    qml.RY(y, wires=[1])

...    qml.CNOT(wires=[0, 1])

...    return qml.expval(qml.PauliZ(0) @ qml.PauliX(1))

>>> for \_ in range(10):

...    circuit(0.432, 0.12)

>>> print(dev.num\_executions)

10

```

### Improvements

* Support for tape mode has improved across PennyLane. The following features now work in tape mode:

	+ QNode collections [(#863)](https://github.com/PennyLaneAI/pennylane/pull/863)

	+ `qnn.ExpvalCost` [(#863)](https://github.com/PennyLaneAI/pennylane/pull/863)

	[(#911)](https://github.com/PennyLaneAI/pennylane/pull/911)

	+ `qml.qnn.KerasLayer` [(#869)](https://github.com/PennyLaneAI/pennylane/pull/869)

	+ `qml.qnn.TorchLayer` [(#865)](https://github.com/PennyLaneAI/pennylane/pull/865)

	+ The `qml.qaoa` module [(#905)](https://github.com/PennyLaneAI/pennylane/pull/905)

* A new function, `qml.refresh\_devices()`, has been added, allowing PennyLane to

rescan installed PennyLane plugins and refresh the device list. In addition, the `qml.device`

loader will attempt to refresh devices if the required plugin device cannot be found.

This will result in an improved experience if installing PennyLane and plugins within

a running Python session (for example, on Google Colab), and avoid the need to

restart the kernel/runtime.

[(#907)](https://github.com/PennyLaneAI/pennylane/pull/907)

* When using `grad\_fn = qml.grad(cost)` to compute the gradient of a cost function with the Autograd

interface, the value of the intermediate forward pass is now available via the `grad\_fn.forward`

property

[(#914)](https://github.com/PennyLaneAI/pennylane/pull/914):

```

def cost\_fn(x, y):

    return 2 \* np.sin(x[0]) \* np.exp(-x[1]) + x[0] \*\* 3 + np.cos(y)

params = np.array([0.1, 0.5], requires\_grad=True)

data = np.array(0.65, requires\_grad=False)

grad\_fn = qml.grad(cost\_fn)

grad\_fn(params, data)  # perform backprop and evaluate the gradient

grad\_fn.forward  # the cost function value

```

* Gradient-based optimizers now have a `step\_and\_cost` method that returns

both the next step as well as the objective (cost) function output.

[(#916)](https://github.com/PennyLaneAI/pennylane/pull/916)

```

>>> opt = qml.GradientDescentOptimizer()

>>> params, cost = opt.step\_and\_cost(cost\_fn, params)

```

* PennyLane provides a new experimental module `qml.proc` which provides framework-agnostic processing

functions for array and tensor manipulations.

[(#886)](https://github.com/PennyLaneAI/pennylane/pull/886)

Given the input tensor-like object, the call is

dispatched to the corresponding array manipulation framework, allowing for end-to-end

differentiation to be preserved.

```

>>> x = torch.tensor([1., 2.])

>>> qml.proc.ones\_like(x)

tensor([1, 1])

>>> y = tf.Variable([[0], [5]])

>>> qml.proc.ones\_like(y, dtype=np.complex128)

<tf.Tensor: shape=(2, 1), dtype=complex128, numpy=

array([[1.+0.j],

 [1.+0.j]])>

```

Note that these functions are experimental, and only a subset of common functionality is

supported. Furthermore, the names and behaviour of these functions may differ from similar

functions in common frameworks; please refer to the function docstrings for more details.

* The gradient methods in tape mode now fully separate the quantum and classical processing. Rather

than returning the evaluated gradients directly, they now return a tuple containing the required

quantum and classical processing steps.

[(#840)](https://github.com/PennyLaneAI/pennylane/pull/840)

```

def gradient\_method(idx, param, \*\*options):

    # generate the quantum tapes that must be computed

    # to determine the quantum gradient

    tapes = quantum\_gradient\_tapes(self)

    def processing\_fn(results):

        # perform classical processing on the evaluated tapes

        # returning the evaluated quantum gradient

        return classical\_processing(results)

    return tapes, processing\_fn

```

The `JacobianTape.jacobian()` method has been similarly modified to accumulate all gradient

quantum tapes and classical processing functions, evaluate all quantum tapes simultaneously,

and then apply the post-processing functions to the evaluated tape results.

* The MultiRZ gate now has a defined generator, allowing it to be used in quantum natural gradient

optimization.

[(#912)](https://github.com/PennyLaneAI/pennylane/pull/912)

* The CRot gate now has a `decomposition` method, which breaks the gate down into rotations

and CNOT gates. This allows `CRot` to be used on devices that do not natively support it.

[(#908)](https://github.com/PennyLaneAI/pennylane/pull/908)

* The classical processing in the `MottonenStatePreparation` template has been largely

rewritten to use dense matrices and tensor manipulations wherever possible.

This is in preparation to support differentiation through the template in the future.

[(#864)](https://github.com/PennyLaneAI/pennylane/pull/864)

* Device-based caching has replaced QNode caching. Caching is now accessed by passing a

`cache` argument to the device.

[(#851)](https://github.com/PennyLaneAI/pennylane/pull/851)

The `cache` argument should be an integer specifying the size of the cache. For example, a

cache of size 10 is created using:

```

>>> dev = qml.device("default.qubit", wires=2, cache=10)

```

* The `Operation`, `Tensor`, and `MeasurementProcess` classes now have the `\_\_copy\_\_` special method

defined.

[(#840)](https://github.com/PennyLaneAI/pennylane/pull/840)

This allows us to ensure that, when a shallow copy is performed of an operation, the

mutable list storing the operation parameters is *also* shallow copied. Both the old operation and

the copied operation will continue to share the same parameter data,

```

>>> import copy

>>> op = qml.RX(0.2, wires=0)

>>> op2 = copy.copy(op)

>>> op.data[0] is op2.data[0]

True

```

however the *list container* is not a reference:

```

>>> op.data is op2.data

False

```

This allows the parameters of the copied operation to be modified, without mutating

the parameters of the original operation.

* The `QuantumTape.copy` method has been tweaked so that

[(#840)](https://github.com/PennyLaneAI/pennylane/pull/840):

	+ Optionally, the tape’s operations are shallow copied in addition to the tape by passing the

	`copy\_operations=True` boolean flag. This allows the copied tape’s parameters to be mutated

	without affecting the original tape’s parameters. (Note: the two tapes will share parameter data

	*until* one of the tapes has their parameter list modified.)

	+ Copied tapes can be cast to another `QuantumTape` subclass by passing the `tape\_cls` keyword

	argument.

### Breaking changes

* Updated how parameter-shift gradient recipes are defined for operations, allowing for

gradient recipes that are specified as an arbitrary number of terms.

[(#909)](https://github.com/PennyLaneAI/pennylane/pull/909)

Previously, `Operation.grad\_recipe` was restricted to two-term parameter-shift formulas.

With this change, the gradient recipe now contains elements of the form

\([c\_i, a\_i, s\_i]\), resulting in a gradient recipe of

\(\frac{\partial}{\partial\phi\_k}f(\phi\_k) = \sum\_{i} c\_i f(a\_i \phi\_k + s\_i )\).

As this is a breaking change, all custom operations with defined gradient recipes must be

updated to continue working with PennyLane 0.13. Note though that if `grad\_recipe = None`, the

default gradient recipe remains unchanged, and corresponds to the two terms \([c\_0, a\_0, s\_0]=[1/2, 1, \pi/2]\)

and \([c\_1, a\_1, s\_1]=[-1/2, 1, -\pi/2]\) for every parameter.

* The `VQECost` class has been renamed to `ExpvalCost` to reflect its general applicability

beyond VQE. Use of `VQECost` is still possible but will result in a deprecation warning.

[(#913)](https://github.com/PennyLaneAI/pennylane/pull/913)

### Bug fixes

* The `default.qubit.tf` device is updated to handle TensorFlow objects (e.g.,

`tf.Variable`) as gate parameters correctly when using the `MultiRZ` and

`CRot` operations.

[(#921)](https://github.com/PennyLaneAI/pennylane/pull/921)

* PennyLane tensor objects are now unwrapped in BaseQNode when passed as a

keyword argument to the quantum function.

[(#903)](https://github.com/PennyLaneAI/pennylane/pull/903)

[(#893)](https://github.com/PennyLaneAI/pennylane/pull/893)

* The new tape mode now prevents multiple observables from being evaluated on the same wire

if the observables are not qubit-wise commuting Pauli words.

[(#882)](https://github.com/PennyLaneAI/pennylane/pull/882)

* Fixes a bug in `default.qubit` whereby inverses of common gates were not being applied

via efficient gate-specific methods, instead falling back to matrix-vector multiplication.

The following gates were affected: `PauliX`, `PauliY`, `PauliZ`, `Hadamard`, `SWAP`, `S`,

`T`, `CNOT`, `CZ`.

[(#872)](https://github.com/PennyLaneAI/pennylane/pull/872)

* The `PauliRot` operation now gracefully handles single-qubit Paulis, and all-identity Paulis

[(#860)](https://github.com/PennyLaneAI/pennylane/pull/860).

* Fixes a bug whereby binary Python operators were not properly propagating the `requires\_grad`

attribute to the output tensor.

[(#889)](https://github.com/PennyLaneAI/pennylane/pull/889)

* Fixes a bug which prevents `TorchLayer` from doing `backward` when CUDA is enabled.

[(#899)](https://github.com/PennyLaneAI/pennylane/pull/899)

* Fixes a bug where multi-threaded execution of `QNodeCollection` sometimes fails

because of simultaneous queuing. This is fixed by adding thread locking during queuing.

[(#910)](https://github.com/PennyLaneAI/pennylane/pull/918)

* Fixes a bug in `QuantumTape.set\_parameters()`. The previous implementation assumed

that the `self.trainable\_parms` set would always be iterated over in increasing integer

order. However, this is not guaranteed behaviour, and can lead to the incorrect tape parameters

being set if this is not the case.

[(#923)](https://github.com/PennyLaneAI/pennylane/pull/923)

* Fixes broken error message if a QNode is instantiated with an unknown exception.

[(#930)](https://github.com/PennyLaneAI/pennylane/pull/930)

### Contributors

This release contains contributions from (in alphabetical order):

Juan Miguel Arrazola, Thomas Bromley, Christina Lee, Alain Delgado Gran, Olivia Di Matteo, Anthony

Hayes, Theodor Isacsson, Josh Izaac, Soran Jahangiri, Nathan Killoran, Shumpei Kobayashi, Romain

Moyard, Zeyue Niu, Maria Schuld, Antal Száva.

orphan

#### Release 0.12.0[¶](#release-0-12-0 "Permalink to this headline")

### New features since last release

#### New and improved simulators

* PennyLane now supports a new device, `default.mixed`, designed for

simulating mixed-state quantum computations. This enables native

support for implementing noisy channels in a circuit, which generally

map pure states to mixed states.

[(#794)](https://github.com/PennyLaneAI/pennylane/pull/794)

[(#807)](https://github.com/PennyLaneAI/pennylane/pull/807)

[(#819)](https://github.com/PennyLaneAI/pennylane/pull/819)

The device can be initialized as

```

>>> dev = qml.device("default.mixed", wires=1)

```

This allows the construction of QNodes that include non-unitary operations,

such as noisy channels:

```

>>> @qml.qnode(dev)

... def circuit(params):

...     qml.RX(params[0], wires=0)

...     qml.RY(params[1], wires=0)

...     qml.AmplitudeDamping(0.5, wires=0)

...     return qml.expval(qml.PauliZ(0))

>>> print(circuit([0.54, 0.12]))

0.9257702929524184

>>> print(circuit([0, np.pi]))

0.0

```

#### New tools for optimizing measurements

* The new `grouping` module provides functionality for grouping simultaneously measurable Pauli word

observables.

[(#761)](https://github.com/PennyLaneAI/pennylane/pull/761)

[(#850)](https://github.com/PennyLaneAI/pennylane/pull/850)

[(#852)](https://github.com/PennyLaneAI/pennylane/pull/852)

	+ The `optimize\_measurements` function will take as input a list of Pauli word observables and

	their corresponding coefficients (if any), and will return the partitioned Pauli terms

	diagonalized in the measurement basis and the corresponding diagonalizing circuits.

	

	

	

	```

	from pennylane.grouping import optimize\_measurements

	h, nr\_qubits = qml.qchem.molecular\_hamiltonian("h2", "h2.xyz")

	rotations, grouped\_ops, grouped\_coeffs = optimize\_measurements(h.ops, h.coeffs, grouping="qwc")

	

	```

	

	

	The diagonalizing circuits of `rotations` correspond to the diagonalized Pauli word groupings of

	`grouped\_ops`.

	+ Pauli word partitioning utilities are performed by the `PauliGroupingStrategy`

	class. An input list of Pauli words can be partitioned into mutually commuting,

	qubit-wise-commuting, or anticommuting groupings.

	

	

	For example, partitioning Pauli words into anticommutative groupings by the Recursive Largest

	First (RLF) graph colouring heuristic:

	

	

	

	```

	from pennylane import PauliX, PauliY, PauliZ, Identity

	from pennylane.grouping import group\_observables

	pauli\_words = [

	    Identity('a') @ Identity('b'),

	    Identity('a') @ PauliX('b'),

	    Identity('a') @ PauliY('b'),

	    PauliZ('a') @ PauliX('b'),

	    PauliZ('a') @ PauliY('b'),

	    PauliZ('a') @ PauliZ('b')

	]

	groupings = group\_observables(pauli\_words, grouping\_type='anticommuting', method='rlf')

	

	```

	+ Various utility functions are included for obtaining and manipulating Pauli

	words in the binary symplectic vector space representation.

	

	

	For instance, two Pauli words may be converted to their binary vector representation:

	

	

	

	```

	>>> from pennylane.grouping import pauli\_to\_binary

	>>> from pennylane.wires import Wires

	>>> wire\_map = {Wires('a'): 0, Wires('b'): 1}

	>>> pauli\_vec\_1 = pauli\_to\_binary(qml.PauliX('a') @ qml.PauliY('b'))

	>>> pauli\_vec\_2 = pauli\_to\_binary(qml.PauliZ('a') @ qml.PauliZ('b'))

	>>> pauli\_vec\_1

	[1. 1. 0. 1.]

	>>> pauli\_vec\_2

	[0. 0. 1. 1.]

	

	```

	

	

	Their product up to a phase may be computed by taking the sum of their binary vector

	representations, and returned in the operator representation.

	

	

	

	```

	>>> from pennylane.grouping import binary\_to\_pauli

	>>> binary\_to\_pauli((pauli\_vec\_1 + pauli\_vec\_2) % 2, wire\_map)

	Tensor product ['PauliY', 'PauliX']: 0 params, wires ['a', 'b']

	

	```

	

	

	For more details on the grouping module, see the

	[grouping module documentation](https://pennylane.readthedocs.io/en/stable/code/qml_grouping.html)

#### Returning the quantum state from simulators

* The quantum state of a QNode can now be returned using the `qml.state()` return function.

[(#818)](https://github.com/XanaduAI/pennylane/pull/818)

```

import pennylane as qml

dev = qml.device("default.qubit", wires=3)

qml.enable\_tape()

@qml.qnode(dev)

def qfunc(x, y):

    qml.RZ(x, wires=0)

    qml.CNOT(wires=[0, 1])

    qml.RY(y, wires=1)

    qml.CNOT(wires=[0, 2])

    return qml.state()

>>> qfunc(0.56, 0.1)

array([0.95985437-0.27601028j, 0.        +0.j        ,

       0.04803275-0.01381203j, 0.        +0.j        ,

       0.        +0.j        , 0.        +0.j        ,

       0.        +0.j        , 0.        +0.j        ])

```

Differentiating the state is currently available when using the

classical backpropagation differentiation method (`diff\_method="backprop"`) with a compatible device,

and when using the new tape mode.

#### New operations and channels

* PennyLane now includes standard channels such as the Amplitude-damping,

Phase-damping, and Depolarizing channels, as well as the ability

to make custom qubit channels.

[(#760)](https://github.com/PennyLaneAI/pennylane/pull/760)

[(#766)](https://github.com/PennyLaneAI/pennylane/pull/766)

[(#778)](https://github.com/PennyLaneAI/pennylane/pull/778)

* The controlled-Y operation is now available via `qml.CY`. For devices that do

not natively support the controlled-Y operation, it will be decomposed

into `qml.RY`, `qml.CNOT`, and `qml.S` operations.

[(#806)](https://github.com/PennyLaneAI/pennylane/pull/806)

#### Preview the next-generation PennyLane QNode

* The new PennyLane `tape` module provides a re-formulated QNode class, rewritten from the ground-up,

that uses a new `QuantumTape` object to represent the QNode’s quantum circuit. Tape mode

provides several advantages over the standard PennyLane QNode.

[(#785)](https://github.com/PennyLaneAI/pennylane/pull/785)

[(#792)](https://github.com/PennyLaneAI/pennylane/pull/792)

[(#796)](https://github.com/PennyLaneAI/pennylane/pull/796)

[(#800)](https://github.com/PennyLaneAI/pennylane/pull/800)

[(#803)](https://github.com/PennyLaneAI/pennylane/pull/803)

[(#804)](https://github.com/PennyLaneAI/pennylane/pull/804)

[(#805)](https://github.com/PennyLaneAI/pennylane/pull/805)

[(#808)](https://github.com/PennyLaneAI/pennylane/pull/808)

[(#810)](https://github.com/PennyLaneAI/pennylane/pull/810)

[(#811)](https://github.com/PennyLaneAI/pennylane/pull/811)

[(#815)](https://github.com/PennyLaneAI/pennylane/pull/815)

[(#820)](https://github.com/PennyLaneAI/pennylane/pull/820)

[(#823)](https://github.com/PennyLaneAI/pennylane/pull/823)

[(#824)](https://github.com/PennyLaneAI/pennylane/pull/824)

[(#829)](https://github.com/PennyLaneAI/pennylane/pull/829)

	+ Support for in-QNode classical processing: Tape mode allows for differentiable classical

	processing within the QNode.

	+ No more Variable wrapping: In tape mode, QNode arguments no longer become `Variable`

	objects within the QNode.

	+ Less restrictive QNode signatures: There is no longer any restriction on the QNode signature;

	the QNode can be defined and called following the same rules as standard Python functions.

	+ Unifying all QNodes: The tape-mode QNode merges all QNodes (including the

	`JacobianQNode` and the `PassthruQNode`) into a single unified QNode, with

	identical behaviour regardless of the differentiation type.

	+ Optimizations: Tape mode provides various performance optimizations, reducing pre- and

	post-processing overhead, and reduces the number of quantum evaluations in certain cases.Note that tape mode is **experimental**, and does not currently have feature-parity with the

existing QNode. [Feedback and bug reports](https://github.com/PennyLaneAI/pennylane/issues) are

encouraged and will help improve the new tape mode.

Tape mode can be enabled globally via the `qml.enable\_tape` function, without changing your

PennyLane code:

```

qml.enable\_tape()

dev = qml.device("default.qubit", wires=1)

@qml.qnode(dev, interface="tf")

def circuit(p):

    print("Parameter value:", p)

    qml.RX(tf.sin(p[0])\*\*2 + p[1], wires=0)

    return qml.expval(qml.PauliZ(0))

```

For more details, please see the [tape mode

documentation](https://pennylane.readthedocs.io/en/stable/code/qml_tape.html).

### Improvements

* QNode caching has been introduced, allowing the QNode to keep track of the results of previous

device executions and reuse those results in subsequent calls.

Note that QNode caching is only supported in the new and experimental tape-mode.

[(#817)](https://github.com/PennyLaneAI/pennylane/pull/817)

Caching is available by passing a `caching` argument to the QNode:

```

dev = qml.device("default.qubit", wires=2)

qml.enable\_tape()

@qml.qnode(dev, caching=10)  # cache up to 10 evaluations

def qfunc(x):

    qml.RX(x, wires=0)

    qml.RX(0.3, wires=1)

    qml.CNOT(wires=[0, 1])

    return qml.expval(qml.PauliZ(1))

qfunc(0.1)  # first evaluation executes on the device

qfunc(0.1)  # second evaluation accesses the cached result

```

* Sped up the application of certain gates in `default.qubit` by using array/tensor

manipulation tricks. The following gates are affected: `PauliX`, `PauliY`, `PauliZ`,

`Hadamard`, `SWAP`, `S`, `T`, `CNOT`, `CZ`.

[(#772)](https://github.com/PennyLaneAI/pennylane/pull/772)

* The computation of marginal probabilities has been made more efficient for devices

with a large number of wires, achieving in some cases a 5x speedup.

[(#799)](https://github.com/PennyLaneAI/pennylane/pull/799)

* Adds arithmetic operations (addition, tensor product,

subtraction, and scalar multiplication) between `Hamiltonian`,

`Tensor`, and `Observable` objects, and inline arithmetic

operations between Hamiltonians and other observables.

[(#765)](https://github.com/PennyLaneAI/pennylane/pull/765)

Hamiltonians can now easily be defined as sums of observables:

```

>>> H = 3 \* qml.PauliZ(0) - (qml.PauliX(0) @ qml.PauliX(1)) + qml.Hamiltonian([4], [qml.PauliZ(0)])

>>> print(H)

(7.0) [Z0] + (-1.0) [X0 X1]

```

* Adds `compare()` method to `Observable` and `Hamiltonian` classes, which allows

for comparison between observable quantities.

[(#765)](https://github.com/PennyLaneAI/pennylane/pull/765)

```

>>> H = qml.Hamiltonian([1], [qml.PauliZ(0)])

>>> obs = qml.PauliZ(0) @ qml.Identity(1)

>>> print(H.compare(obs))

True

```

```

>>> H = qml.Hamiltonian([2], [qml.PauliZ(0)])

>>> obs = qml.PauliZ(1) @ qml.Identity(0)

>>> print(H.compare(obs))

False

```

* Adds `simplify()` method to the `Hamiltonian` class.

[(#765)](https://github.com/PennyLaneAI/pennylane/pull/765)

```

>>> H = qml.Hamiltonian([1, 2], [qml.PauliZ(0), qml.PauliZ(0) @ qml.Identity(1)])

>>> H.simplify()

>>> print(H)

(3.0) [Z0]

```

* Added a new bit-flip mixer to the `qml.qaoa` module.

[(#774)](https://github.com/PennyLaneAI/pennylane/pull/774)

* Summation of two `Wires` objects is now supported and will return

a `Wires` object containing the set of all wires defined by the

terms in the summation.

[(#812)](https://github.com/PennyLaneAI/pennylane/pull/812)

### Breaking changes

* The PennyLane NumPy module now returns scalar (zero-dimensional) arrays where

Python scalars were previously returned.

[(#820)](https://github.com/PennyLaneAI/pennylane/pull/820)

[(#833)](https://github.com/PennyLaneAI/pennylane/pull/833)

For example, this affects array element indexing, and summation:

```

>>> x = np.array([1, 2, 3], requires\_grad=False)

>>> x[0]

tensor(1, requires\_grad=False)

>>> np.sum(x)

tensor(6, requires\_grad=True)

```

This may require small updates to user code. A convenience method, `np.tensor.unwrap()`,

has been added to help ease the transition. This converts PennyLane NumPy tensors

to standard NumPy arrays and Python scalars:

```

>>> x = np.array(1.543, requires\_grad=False)

>>> x.unwrap()

1.543

```

Note, however, that information regarding array differentiability will be

lost.

* The device capabilities dictionary has been redesigned, for clarity and robustness. In particular,

the capabilities dictionary is now inherited from the parent class, various keys have more

expressive names, and all keys are now defined in the base device class. For more details, please

[refer to the developer

documentation](https://pennylane.readthedocs.io/en/stable/development/plugins.html#device-capabilities).

[(#781)](https://github.com/PennyLaneAI/pennylane/pull/781/files)

### Bug fixes

* Changed to use lists for storing variable values inside `BaseQNode`

allowing complex matrices to be passed to `QubitUnitary`.

[(#773)](https://github.com/PennyLaneAI/pennylane/pull/773)

* Fixed a bug within `default.qubit`, resulting in greater efficiency

when applying a state vector to all wires on the device.

[(#849)](https://github.com/PennyLaneAI/pennylane/pull/849)

### Documentation

* Equations have been added to the `qml.sample` and `qml.probs` docstrings

to clarify the mathematical foundation of the performed measurements.

[(#843)](https://github.com/PennyLaneAI/pennylane/pull/843)

### Contributors

This release contains contributions from (in alphabetical order):

Aroosa Ijaz, Juan Miguel Arrazola, Thomas Bromley, Jack Ceroni, Alain Delgado Gran, Josh Izaac,

Soran Jahangiri, Nathan Killoran, Robert Lang, Cedric Lin, Olivia Di Matteo, Nicolás Quesada, Maria

Schuld, Antal Száva.

orphan

#### Release 0.11.0[¶](#release-0-11-0 "Permalink to this headline")

### New features since last release

#### New and improved simulators

* Added a new device, `default.qubit.autograd`, a pure-state qubit simulator written using Autograd.

This device supports classical backpropagation (`diff\_method="backprop"`); this can

be faster than the parameter-shift rule for computing quantum gradients

when the number of parameters to be optimized is large.

[(#721)](https://github.com/XanaduAI/pennylane/pull/721)

```

>>> dev = qml.device("default.qubit.autograd", wires=1)

>>> @qml.qnode(dev, diff\_method="backprop")

... def circuit(x):

...     qml.RX(x[1], wires=0)

...     qml.Rot(x[0], x[1], x[2], wires=0)

...     return qml.expval(qml.PauliZ(0))

>>> weights = np.array([0.2, 0.5, 0.1])

>>> grad\_fn = qml.grad(circuit)

>>> print(grad\_fn(weights))

array([-2.25267173e-01, -1.00864546e+00, 6.93889390e-18])

```

See the [device documentation](https://pennylane.readthedocs.io/en/stable/code/api/pennylane.devices.default_qubit_autograd.DefaultQubitAutograd.html) for more details.

* A new experimental C++ state-vector simulator device is now available, `lightning.qubit`. It

uses the C++ Eigen library to perform fast linear algebra calculations for simulating quantum

state-vector evolution.

`lightning.qubit` is currently in beta; it can be installed via `pip`:

```

$ pip install pennylane-lightning

```

Once installed, it can be used as a PennyLane device:

```

>>> dev = qml.device("lightning.qubit", wires=2)

```

For more details, please see the [lightning qubit documentation](https://pennylane-lightning.readthedocs.io).

#### New algorithms and templates

* Added built-in QAOA functionality via the new `qml.qaoa` module.

[(#712)](https://github.com/PennyLaneAI/pennylane/pull/712)

[(#718)](https://github.com/PennyLaneAI/pennylane/pull/718)

[(#741)](https://github.com/PennyLaneAI/pennylane/pull/741)

[(#720)](https://github.com/PennyLaneAI/pennylane/pull/720)

This includes the following features:

	+ New `qml.qaoa.x\_mixer` and `qml.qaoa.xy\_mixer` functions for defining Pauli-X and XY

	mixer Hamiltonians.

	+ MaxCut: The `qml.qaoa.maxcut` function allows easy construction of the cost Hamiltonian

	and recommended mixer Hamiltonian for solving the MaxCut problem for a supplied graph.

	+ Layers: `qml.qaoa.cost\_layer` and `qml.qaoa.mixer\_layer` take cost and mixer

	Hamiltonians, respectively, and apply the corresponding QAOA cost and mixer layers

	to the quantum circuitFor example, using PennyLane to construct and solve a MaxCut problem with QAOA:

```

wires = range(3)

graph = Graph([(0, 1), (1, 2), (2, 0)])

cost\_h, mixer\_h = qaoa.maxcut(graph)

def qaoa\_layer(gamma, alpha):

    qaoa.cost\_layer(gamma, cost\_h)

    qaoa.mixer\_layer(alpha, mixer\_h)

def antatz(params, \*\*kwargs):

    for w in wires:

        qml.Hadamard(wires=w)

    # repeat the QAOA layer two times

    qml.layer(qaoa\_layer, 2, params[0], params[1])

dev = qml.device('default.qubit', wires=len(wires))

cost\_function = qml.VQECost(ansatz, cost\_h, dev)

```

* Added an `ApproxTimeEvolution` template to the PennyLane templates module, which

can be used to implement Trotterized time-evolution under a Hamiltonian.

[(#710)](https://github.com/XanaduAI/pennylane/pull/710)

![](https://pennylane.readthedocs.io/en/latest/_static/templates/subroutines/approx_time_evolution.png)

* Added a `qml.layer` template-constructing function, which takes a unitary, and

repeatedly applies it on a set of wires to a given depth.

[(#723)](https://github.com/PennyLaneAI/pennylane/pull/723)

```

def subroutine():

    qml.Hadamard(wires=[0])

    qml.CNOT(wires=[0, 1])

    qml.PauliX(wires=[1])

dev = qml.device('default.qubit', wires=3)

@qml.qnode(dev)

def circuit():

    qml.layer(subroutine, 3)

    return [qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliZ(1))]

```

This creates the following circuit:

```

>>> circuit()

>>> print(circuit.draw())

0: ──H──╭C──X──H──╭C──X──H──╭C──X──┤ ⟨Z⟩

1: ─────╰X────────╰X────────╰X─────┤ ⟨Z⟩

```

* Added the `qml.utils.decompose\_hamiltonian` function. This function can be used to

decompose a Hamiltonian into a linear combination of Pauli operators.

[(#671)](https://github.com/XanaduAI/pennylane/pull/671)

```

>>> A = np.array(

... [[-2, -2+1j, -2, -2],

... [-2-1j,  0,  0, -1],

... [-2,  0, -2, -1],

... [-2, -1, -1,  0]])

>>> coeffs, obs\_list = decompose\_hamiltonian(A)

```

#### New device features

* It is now possible to specify custom wire labels, such as `['anc1', 'anc2', 0, 1, 3]`, where the labels

can be strings or numbers.

[(#666)](https://github.com/XanaduAI/pennylane/pull/666)

Custom wire labels are defined by passing a list to the `wires` argument when creating the device:

```

>>> dev = qml.device("default.qubit", wires=['anc1', 'anc2', 0, 1, 3])

```

Quantum operations should then be invoked with these custom wire labels:

```

>>> @qml.qnode(dev)

>>> def circuit():

...    qml.Hadamard(wires='anc2')

...    qml.CNOT(wires=['anc1', 3])

...    ...

```

The existing behaviour, in which the number of wires is specified on device initialization,

continues to work as usual. This gives a default behaviour where wires are labelled

by consecutive integers.

```

>>> dev = qml.device("default.qubit", wires=5)

```

* An integrated device test suite has been added, which can be used

to run basic integration tests on core or external devices.

[(#695)](https://github.com/PennyLaneAI/pennylane/pull/695)

[(#724)](https://github.com/PennyLaneAI/pennylane/pull/724)

[(#733)](https://github.com/PennyLaneAI/pennylane/pull/733)

The test can be invoked against a particular device by calling the `pl-device-test`

command line program:

```

$ pl-device-test --device=default.qubit --shots=1234 --analytic=False

```

If the tests are run on external devices, the device and its dependencies must be

installed locally. For more details, please see the

[plugin test documentation](http://pennylane.readthedocs.io/en/latest/code/api/pennylane.devices.tests.html).

### Improvements

* The functions implementing the quantum circuits building the Unitary Coupled-Cluster

(UCCSD) VQE ansatz have been improved, with a more consistent naming convention and

improved docstrings.

[(#748)](https://github.com/PennyLaneAI/pennylane/pull/748)

The changes include:

	+ The terms *1particle-1hole (ph)* and *2particle-2hole (pphh)* excitations

	were replaced with the names *single* and *double* excitations, respectively.

	+ The non-differentiable arguments in the `UCCSD` template were renamed accordingly:

	`ph` → `s\_wires`, `pphh` → `d\_wires`

	+ The term *virtual*, previously used to refer the *unoccupied* orbitals, was discarded.

	+ The Usage Details sections were updated and improved.

* Added support for TensorFlow 2.3 and PyTorch 1.6.

[(#725)](https://github.com/PennyLaneAI/pennylane/pull/725)

* Returning probabilities is now supported from photonic QNodes.

As with qubit QNodes, photonic QNodes returning probabilities are

end-to-end differentiable.

[(#699)](https://github.com/XanaduAI/pennylane/pull/699/)

```

>>> dev = qml.device("strawberryfields.fock", wires=2, cutoff\_dim=5)

>>> @qml.qnode(dev)

... def circuit(a):

...     qml.Displacement(a, 0, wires=0)

...     return qml.probs(wires=0)

>>> print(circuit(0.5))

[7.78800783e-01 1.94700196e-01 2.43375245e-02 2.02812704e-03 1.26757940e-04]

```

### Breaking changes

* The `pennylane.plugins` and `pennylane.beta.plugins` folders have been renamed to

`pennylane.devices` and `pennylane.beta.devices`, to reflect their content better.

[(#726)](https://github.com/XanaduAI/pennylane/pull/726)

### Bug fixes

* The PennyLane interface conversion functions can now convert QNodes with

pre-existing interfaces.

[(#707)](https://github.com/XanaduAI/pennylane/pull/707)

### Documentation

* The interfaces section of the documentation has been renamed to ‘Interfaces and training’,

and updated with the latest variable handling details.

[(#753)](https://github.com/PennyLaneAI/pennylane/pull/753)

### Contributors

This release contains contributions from (in alphabetical order):

Juan Miguel Arrazola, Thomas Bromley, Jack Ceroni, Alain Delgado Gran, Shadab Hussain, Theodor

Isacsson, Josh Izaac, Nathan Killoran, Maria Schuld, Antal Száva, Nicola Vitucci.

orphan

#### Release 0.10.0[¶](#release-0-10-0 "Permalink to this headline")

### New features since last release

#### New and improved simulators

* Added a new device, `default.qubit.tf`, a pure-state qubit simulator written using TensorFlow.

As a result, it supports classical backpropagation as a means to compute the Jacobian. This can

be faster than the parameter-shift rule for computing quantum gradients

when the number of parameters to be optimized is large.

`default.qubit.tf` is designed to be used with end-to-end classical backpropagation

(`diff\_method="backprop"`) with the TensorFlow interface. This is the default method

of differentiation when creating a QNode with this device.

Using this method, the created QNode is a ‘white-box’ that is

tightly integrated with your TensorFlow computation, including

[AutoGraph](https://www.tensorflow.org/guide/function) support:

```

>>> dev = qml.device("default.qubit.tf", wires=1)

>>> @tf.function

... @qml.qnode(dev, interface="tf", diff\_method="backprop")

... def circuit(x):

...     qml.RX(x[1], wires=0)

...     qml.Rot(x[0], x[1], x[2], wires=0)

...     return qml.expval(qml.PauliZ(0))

>>> weights = tf.Variable([0.2, 0.5, 0.1])

>>> with tf.GradientTape() as tape:

...     res = circuit(weights)

>>> print(tape.gradient(res, weights))

tf.Tensor([-2.2526717e-01 -1.0086454e+00 1.3877788e-17], shape=(3,), dtype=float32)

```

See the `default.qubit.tf`

[documentation](https://pennylane.ai/en/stable/code/api/pennylane.beta.plugins.DefaultQubitTF.html)

for more details.

* The [default.tensor plugin](https://github.com/XanaduAI/pennylane/blob/master/pennylane/beta/plugins/default_tensor.py)

has been significantly upgraded. It now allows two different

tensor network representations to be used: `"exact"` and `"mps"`. The former uses a

exact factorized representation of quantum states, while the latter uses a matrix product state

representation.

([#572](https://github.com/XanaduAI/pennylane/pull/572))

([#599](https://github.com/XanaduAI/pennylane/pull/599))

#### New machine learning functionality and integrations

* PennyLane QNodes can now be converted into Torch layers, allowing for creation of quantum and

hybrid models using the `torch.nn` API.

[(#588)](https://github.com/XanaduAI/pennylane/pull/588)

A PennyLane QNode can be converted into a `torch.nn` layer using the `qml.qnn.TorchLayer` class:

```

>>> @qml.qnode(dev)

... def qnode(inputs, weights\_0, weight\_1):

...    # define the circuit

...    # ...

>>> weight\_shapes = {"weights\_0": 3, "weight\_1": 1}

>>> qlayer = qml.qnn.TorchLayer(qnode, weight\_shapes)

```

A hybrid model can then be easily constructed:

```

>>> model = torch.nn.Sequential(qlayer, torch.nn.Linear(2, 2))

```

* Added a new “reversible” differentiation method which can be used in simulators, but not hardware.

The reversible approach is similar to backpropagation, but trades off extra computation for

enhanced memory efficiency. Where backpropagation caches the state tensors at each step during

a simulated evolution, the reversible method only caches the final pre-measurement state.

Compared to the parameter-shift method, the reversible method can be faster or slower,

depending on the density and location of parametrized gates in a circuit

(circuits with higher density of parametrized gates near the end of the circuit will see a benefit).

[(#670)](https://github.com/XanaduAI/pennylane/pull/670)

```

>>> dev = qml.device("default.qubit", wires=2)

... @qml.qnode(dev, diff\_method="reversible")

... def circuit(x):

...     qml.RX(x, wires=0)

...     qml.RX(x, wires=0)

...     qml.CNOT(wires=[0,1])

...     return qml.expval(qml.PauliZ(0))

>>> qml.grad(circuit)(0.5)

(array(-0.47942554),)

```

#### New templates and cost functions

* Added the new templates `UCCSD`, `SingleExcitationUnitary`, and`DoubleExcitationUnitary`,

which together implement the Unitary Coupled-Cluster Singles and Doubles (UCCSD) ansatz

to perform VQE-based quantum chemistry simulations using PennyLane-QChem.

[(#622)](https://github.com/XanaduAI/pennylane/pull/622)

[(#638)](https://github.com/XanaduAI/pennylane/pull/638)

[(#654)](https://github.com/XanaduAI/pennylane/pull/654)

[(#659)](https://github.com/XanaduAI/pennylane/pull/659)

[(#622)](https://github.com/XanaduAI/pennylane/pull/622)

* Added module `pennylane.qnn.cost` with class `SquaredErrorLoss`. The module contains classes

to calculate losses and cost functions on circuits with trainable parameters.

[(#642)](https://github.com/XanaduAI/pennylane/pull/642)

### Improvements

* Improves the wire management by making the `Operator.wires` attribute a `wires` object.

[(#666)](https://github.com/XanaduAI/pennylane/pull/666)

* A significant improvement with respect to how QNodes and interfaces mark quantum function

arguments as differentiable when using Autograd, designed to improve performance and make

QNodes more intuitive.

[(#648)](https://github.com/XanaduAI/pennylane/pull/648)

[(#650)](https://github.com/XanaduAI/pennylane/pull/650)

In particular, the following changes have been made:

	+ A new `ndarray` subclass `pennylane.numpy.tensor`, which extends NumPy arrays with

	the keyword argument and attribute `requires\_grad`. Tensors which have `requires\_grad=False`

	are treated as non-differentiable by the Autograd interface.

	+ A new subpackage `pennylane.numpy`, which wraps `autograd.numpy` such that NumPy functions

	accept the `requires\_grad` keyword argument, and allows Autograd to differentiate

	`pennylane.numpy.tensor` objects.

	+ The `argnum` argument to `qml.grad` is now optional; if not provided, arguments explicitly

	marked as `requires\_grad=False` are excluded for the list of differentiable arguments.

	The ability to pass `argnum` has been retained for backwards compatibility, and

	if present the old behaviour persists.

* The QNode Torch interface now inspects QNode positional arguments.

If any argument does not have the attribute `requires\_grad=True`, it

is automatically excluded from quantum gradient computations.

[(#652)](https://github.com/XanaduAI/pennylane/pull/652)

[(#660)](https://github.com/XanaduAI/pennylane/pull/660)

* The QNode TF interface now inspects QNode positional arguments.

If any argument is not being watched by a `tf.GradientTape()`,

it is automatically excluded from quantum gradient computations.

[(#655)](https://github.com/XanaduAI/pennylane/pull/655)

[(#660)](https://github.com/XanaduAI/pennylane/pull/660)

* QNodes have two new public methods: `QNode.set\_trainable\_args()` and `QNode.get\_trainable\_args()`.

These are designed to be called by interfaces, to specify to the QNode which of its

input arguments are differentiable. Arguments which are non-differentiable will not be converted

to PennyLane Variable objects within the QNode.

[(#660)](https://github.com/XanaduAI/pennylane/pull/660)

* Added `decomposition` method to PauliX, PauliY, PauliZ, S, T, Hadamard, and PhaseShift gates, which

decomposes each of these gates into rotation gates.

[(#668)](https://github.com/XanaduAI/pennylane/pull/668)

* The `CircuitGraph` class now supports serializing contained circuit operations

and measurement basis rotations to an OpenQASM2.0 script via the new

`CircuitGraph.to\_openqasm()` method.

[(#623)](https://github.com/XanaduAI/pennylane/pull/623)

### Breaking changes

* Removes support for Python 3.5.

[(#639)](https://github.com/XanaduAI/pennylane/pull/639)

### Documentation

* Various small typos were fixed.

### Contributors

This release contains contributions from (in alphabetical order):

Thomas Bromley, Jack Ceroni, Alain Delgado Gran, Theodor Isacsson, Josh Izaac,

Nathan Killoran, Maria Schuld, Antal Száva, Nicola Vitucci.

orphan

#### Release 0.9.0[¶](#release-0-9-0 "Permalink to this headline")

### New features since last release

#### New machine learning integrations

* PennyLane QNodes can now be converted into Keras layers, allowing for creation of quantum and

hybrid models using the Keras API.

[(#529)](https://github.com/XanaduAI/pennylane/pull/529)

A PennyLane QNode can be converted into a Keras layer using the `KerasLayer` class:

```

from pennylane.qnn import KerasLayer

@qml.qnode(dev)

def circuit(inputs, weights\_0, weight\_1):

   # define the circuit

   # ...

weight\_shapes = {"weights\_0": 3, "weight\_1": 1}

qlayer = qml.qnn.KerasLayer(circuit, weight\_shapes, output\_dim=2)

```

A hybrid model can then be easily constructed:

```

model = tf.keras.models.Sequential([qlayer, tf.keras.layers.Dense(2)])

```

* Added a new type of QNode, `qml.qnodes.PassthruQNode`. For simulators which are coded in an

external library which supports automatic differentiation, PennyLane will treat a PassthruQNode as

a “white box”, and rely on the external library to directly provide gradients via backpropagation.

This can be more efficient than the using parameter-shift rule for a large number of parameters.

[(#488)](https://github.com/XanaduAI/pennylane/pull/488)

Currently this behaviour is supported by PennyLane’s `default.tensor.tf` device backend,

compatible with the `'tf'` interface using TensorFlow 2:

```

dev = qml.device('default.tensor.tf', wires=2)

@qml.qnode(dev, diff\_method="backprop")

def circuit(params):

    qml.RX(params[0], wires=0)

    qml.RX(params[1], wires=1)

    qml.CNOT(wires=[0, 1])

    return qml.expval(qml.PauliZ(0))

qnode = PassthruQNode(circuit, dev)

params = tf.Variable([0.3, 0.1])

with tf.GradientTape() as tape:

    tape.watch(params)

    res = qnode(params)

grad = tape.gradient(res, params)

```

#### New optimizers

* Added the `qml.RotosolveOptimizer`, a gradient-free optimizer

that minimizes the quantum function by updating each parameter,

one-by-one, via a closed-form expression while keeping other parameters

fixed.

[(#636)](https://github.com/XanaduAI/pennylane/pull/636)

[(#539)](https://github.com/XanaduAI/pennylane/pull/539)

* Added the `qml.RotoselectOptimizer`, which uses Rotosolve to

minimizes a quantum function with respect to both the

rotation operations applied and the rotation parameters.

[(#636)](https://github.com/XanaduAI/pennylane/pull/636)

[(#539)](https://github.com/XanaduAI/pennylane/pull/539)

For example, given a quantum function `f` that accepts parameters `x`

and a list of corresponding rotation operations `generators`,

the Rotoselect optimizer will, at each step, update both the parameter

values and the list of rotation gates to minimize the loss:

```

>>> opt = qml.optimize.RotoselectOptimizer()

>>> x = [0.3, 0.7]

>>> generators = [qml.RX, qml.RY]

>>> for \_ in range(100):

...     x, generators = opt.step(f, x, generators)

```

#### New operations

* Added the `PauliRot` gate, which performs an arbitrary

Pauli rotation on multiple qubits, and the `MultiRZ` gate,

which performs a rotation generated by a tensor product

of Pauli Z operators.

[(#559)](https://github.com/XanaduAI/pennylane/pull/559)

```

dev = qml.device('default.qubit', wires=4)

@qml.qnode(dev)

def circuit(angle):

    qml.PauliRot(angle, "IXYZ", wires=[0, 1, 2, 3])

    return [qml.expval(qml.PauliZ(wire)) for wire in [0, 1, 2, 3]]

```

```

>>> circuit(0.4)

[1. 0.92106099 0.92106099 1. ]

>>> print(circuit.draw())

 0: ──╭RI(0.4)──┤ ⟨Z⟩

 1: ──├RX(0.4)──┤ ⟨Z⟩

 2: ──├RY(0.4)──┤ ⟨Z⟩

 3: ──╰RZ(0.4)──┤ ⟨Z⟩

```

If the `PauliRot` gate is not supported on the target device, it will

be decomposed into `Hadamard`, `RX` and `MultiRZ` gates. Note that

identity gates in the Pauli word result in untouched wires:

```

>>> print(circuit.draw())

 0: ───────────────────────────────────┤ ⟨Z⟩

 1: ──H──────────╭RZ(0.4)──H───────────┤ ⟨Z⟩

 2: ──RX(1.571)──├RZ(0.4)──RX(-1.571)──┤ ⟨Z⟩

 3: ─────────────╰RZ(0.4)──────────────┤ ⟨Z⟩

```

If the `MultiRZ` gate is not supported, it will be decomposed into

`CNOT` and `RZ` gates:

```

>>> print(circuit.draw())

 0: ──────────────────────────────────────────────────┤ ⟨Z⟩

 1: ──H──────────────╭X──RZ(0.4)──╭X──────H───────────┤ ⟨Z⟩

 2: ──RX(1.571)──╭X──╰C───────────╰C──╭X──RX(-1.571)──┤ ⟨Z⟩

 3: ─────────────╰C───────────────────╰C──────────────┤ ⟨Z⟩

```

* PennyLane now provides `DiagonalQubitUnitary` for diagonal gates, that are e.g.,

encountered in IQP circuits. These kinds of gates can be evaluated much faster on

a simulator device.

[(#567)](https://github.com/XanaduAI/pennylane/pull/567)

The gate can be used, for example, to efficiently simulate oracles:

```

dev = qml.device('default.qubit', wires=3)

# Function as a bitstring

f = np.array([1, 0, 0, 1, 1, 0, 1, 0])

@qml.qnode(dev)

def circuit(weights1, weights2):

    qml.templates.StronglyEntanglingLayers(weights1, wires=[0, 1, 2])

    # Implements the function as a phase-kickback oracle

    qml.DiagonalQubitUnitary((-1)\*\*f, wires=[0, 1, 2])

    qml.templates.StronglyEntanglingLayers(weights2, wires=[0, 1, 2])

    return [qml.expval(qml.PauliZ(w)) for w in range(3)]

```

* Added the `TensorN` CVObservable that can represent the tensor product of the

`NumberOperator` on photonic backends.

[(#608)](https://github.com/XanaduAI/pennylane/pull/608)

#### New templates

* Added the `ArbitraryUnitary` and `ArbitraryStatePreparation` templates, which use

`PauliRot` gates to perform an arbitrary unitary and prepare an arbitrary basis

state with the minimal number of parameters.

[(#590)](https://github.com/XanaduAI/pennylane/pull/590)

```

dev = qml.device('default.qubit', wires=3)

@qml.qnode(dev)

def circuit(weights1, weights2):

      qml.templates.ArbitraryStatePreparation(weights1, wires=[0, 1, 2])

      qml.templates.ArbitraryUnitary(weights2, wires=[0, 1, 2])

      return qml.probs(wires=[0, 1, 2])

```

* Added the `IQPEmbedding` template, which encodes inputs into the diagonal gates of an

IQP circuit.

[(#605)](https://github.com/XanaduAI/pennylane/pull/605)

![](https://pennylane.readthedocs.io/en/latest/_images/iqp.png)

* Added the `SimplifiedTwoDesign` template, which implements the circuit

design of [Cerezo et al. (2020)](https://arxiv.org/abs/2001.00550).

[(#556)](https://github.com/XanaduAI/pennylane/pull/556)

![](https://pennylane.readthedocs.io/en/latest/_images/simplified_two_design.png)

* Added the `BasicEntanglerLayers` template, which is a simple layer architecture

of rotations and CNOT nearest-neighbour entanglers.

[(#555)](https://github.com/XanaduAI/pennylane/pull/555)

![](https://pennylane.readthedocs.io/en/latest/_images/basic_entangler.png)

* PennyLane now offers a broadcasting function to easily construct templates:

`qml.broadcast()` takes single quantum operations or other templates and applies

them to wires in a specific pattern.

[(#515)](https://github.com/XanaduAI/pennylane/pull/515)

[(#522)](https://github.com/XanaduAI/pennylane/pull/522)

[(#526)](https://github.com/XanaduAI/pennylane/pull/526)

[(#603)](https://github.com/XanaduAI/pennylane/pull/603)

For example, we can use broadcast to repeat a custom template

across multiple wires:

```

from pennylane.templates import template

@template

def mytemplate(pars, wires):

    qml.Hadamard(wires=wires)

    qml.RY(pars, wires=wires)

dev = qml.device('default.qubit', wires=3)

@qml.qnode(dev)

def circuit(pars):

    qml.broadcast(mytemplate, pattern="single", wires=[0,1,2], parameters=pars)

    return qml.expval(qml.PauliZ(0))

```

```

>>> circuit([1, 1, 0.1])

-0.841470984807896

>>> print(circuit.draw())

 0: ──H──RY(1.0)──┤ ⟨Z⟩

 1: ──H──RY(1.0)──┤

 2: ──H──RY(0.1)──┤

```

For other available patterns, see the

[broadcast function documentation](https://pennylane.readthedocs.io/en/latest/code/api/pennylane.broadcast.html).

### Breaking changes

* The `QAOAEmbedding` now uses the new `MultiRZ` gate as a `ZZ` entangler,

which changes the convention. While

previously, the `ZZ` gate in the embedding was implemented as

```

CNOT(wires=[wires[0], wires[1]])

RZ(2 \* parameter, wires=wires[0])

CNOT(wires=[wires[0], wires[1]])

```

the `MultiRZ` corresponds to

```

CNOT(wires=[wires[1], wires[0]])

RZ(parameter, wires=wires[0])

CNOT(wires=[wires[1], wires[0]])

```

which differs in the factor of `2`, and fixes a bug in the

wires that the `CNOT` was applied to.

[(#609)](https://github.com/XanaduAI/pennylane/pull/609)

* Probability methods are handled by `QubitDevice` and device method

requirements are modified to simplify plugin development.

[(#573)](https://github.com/XanaduAI/pennylane/pull/573)

* The internal variables `All` and `Any` to mark an `Operation` as acting on all or any

wires have been renamed to `AllWires` and `AnyWires`.

[(#614)](https://github.com/XanaduAI/pennylane/pull/614)

### Improvements

* A new `Wires` class was introduced for the internal

bookkeeping of wire indices.

[(#615)](https://github.com/XanaduAI/pennylane/pull/615)

* Improvements to the speed/performance of the `default.qubit` device.

[(#567)](https://github.com/XanaduAI/pennylane/pull/567)

[(#559)](https://github.com/XanaduAI/pennylane/pull/559)

* Added the `"backprop"` and `"device"` differentiation methods to the `qnode`

decorator.

[(#552)](https://github.com/XanaduAI/pennylane/pull/552)

	+ `"backprop"`: Use classical backpropagation. Default on simulator

	devices that are classically end-to-end differentiable.

	The returned QNode can only be used with the same machine learning

	framework (e.g., `default.tensor.tf` simulator with the `tensorflow` interface).

	+ `"device"`: Queries the device directly for the gradient.Using the `"backprop"` differentiation method with the `default.tensor.tf`

device, the created QNode is a ‘white-box’, and is tightly integrated with

the overall TensorFlow computation:

```

>>> dev = qml.device("default.tensor.tf", wires=1)

>>> @qml.qnode(dev, interface="tf", diff\_method="backprop")

>>> def circuit(x):

...     qml.RX(x[1], wires=0)

...     qml.Rot(x[0], x[1], x[2], wires=0)

...     return qml.expval(qml.PauliZ(0))

>>> vars = tf.Variable([0.2, 0.5, 0.1])

>>> with tf.GradientTape() as tape:

...     res = circuit(vars)

>>> tape.gradient(res, vars)

<tf.Tensor: shape=(3,), dtype=float32, numpy=array([-2.2526717e-01, -1.0086454e+00, 1.3877788e-17], dtype=float32)>

```

* The circuit drawer now displays inverted operations, as well as wires

where probabilities are returned from the device:

[(#540)](https://github.com/XanaduAI/pennylane/pull/540)

```

>>> @qml.qnode(dev)

... def circuit(theta):

...     qml.RX(theta, wires=0)

...     qml.CNOT(wires=[0, 1])

...     qml.S(wires=1).inv()

...     return qml.probs(wires=[0, 1])

>>> circuit(0.2)

array([0.99003329, 0. , 0. , 0.00996671])

>>> print(circuit.draw())

0: ──RX(0.2)──╭C───────╭┤ Probs

1: ───────────╰X──S⁻¹──╰┤ Probs

```

* You can now evaluate the metric tensor of a VQE Hamiltonian via the new

`VQECost.metric\_tensor` method. This allows `VQECost` objects to be directly

optimized by the quantum natural gradient optimizer (`qml.QNGOptimizer`).

[(#618)](https://github.com/XanaduAI/pennylane/pull/618)

* The input check functions in `pennylane.templates.utils` are now public

and visible in the API documentation.

[(#566)](https://github.com/XanaduAI/pennylane/pull/566)

* Added keyword arguments for step size and order to the `qnode` decorator, as well as

the `QNode` and `JacobianQNode` classes. This enables the user to set the step size

and order when using finite difference methods. These options are also exposed when

creating QNode collections.

[(#530)](https://github.com/XanaduAI/pennylane/pull/530)

[(#585)](https://github.com/XanaduAI/pennylane/pull/585)

[(#587)](https://github.com/XanaduAI/pennylane/pull/587)

* The decomposition for the `CRY` gate now uses the simpler form `RY @ CNOT @ RY @ CNOT`

[(#547)](https://github.com/XanaduAI/pennylane/pull/547)

* The underlying queuing system was refactored, removing the `qml.\_current\_context`

property that held the currently active `QNode` or `OperationRecorder`. Now, all

objects that expose a queue for operations inherit from `QueuingContext` and

register their queue globally.

[(#548)](https://github.com/XanaduAI/pennylane/pull/548)

* The PennyLane repository has a new benchmarking tool which supports the comparison of different git revisions.

[(#568)](https://github.com/XanaduAI/pennylane/pull/568)

[(#560)](https://github.com/XanaduAI/pennylane/pull/560)

[(#516)](https://github.com/XanaduAI/pennylane/pull/516)

### Documentation

* Updated the development section by creating a landing page with links to sub-pages

containing specific guides.

[(#596)](https://github.com/XanaduAI/pennylane/pull/596)

* Extended the developer’s guide by a section explaining how to add new templates.

[(#564)](https://github.com/XanaduAI/pennylane/pull/564)

### Bug fixes

* `tf.GradientTape().jacobian()` can now be evaluated on QNodes using the TensorFlow interface.

[(#626)](https://github.com/XanaduAI/pennylane/pull/626)

* `RandomLayers()` is now compatible with the qiskit devices.

[(#597)](https://github.com/XanaduAI/pennylane/pull/597)

* `DefaultQubit.probability()` now returns the correct probability when called with

`device.analytic=False`.

[(#563)](https://github.com/XanaduAI/pennylane/pull/563)

* Fixed a bug in the `StronglyEntanglingLayers` template, allowing it to

work correctly when applied to a single wire.

[(544)](https://github.com/XanaduAI/pennylane/pull/544)

* Fixed a bug when inverting operations with decompositions; operations marked as inverted

are now correctly inverted when the fallback decomposition is called.

[(#543)](https://github.com/XanaduAI/pennylane/pull/543)

* The `QNode.print\_applied()` method now correctly displays wires where

`qml.prob()` is being returned.

[#542](https://github.com/XanaduAI/pennylane/pull/542)

### Contributors

This release contains contributions from (in alphabetical order):

Ville Bergholm, Lana Bozanic, Thomas Bromley, Theodor Isacsson, Josh Izaac, Nathan Killoran,

Maggie Li, Johannes Jakob Meyer, Maria Schuld, Sukin Sim, Antal Száva.

orphan

#### Release 0.8.0[¶](#release-0-8-0 "Permalink to this headline")

### New features since last release

* Added a quantum chemistry package, `pennylane.qchem`, which supports

integration with OpenFermion, Psi4, PySCF, and OpenBabel.

[(#453)](https://github.com/XanaduAI/pennylane/pull/453)

Features include:

	+ Generate the qubit Hamiltonians directly starting with the atomic structure of the molecule.

	+ Calculate the mean-field (Hartree-Fock) electronic structure of molecules.

	+ Allow to define an active space based on the number of active electrons and active orbitals.

	+ Perform the fermionic-to-qubit transformation of the electronic Hamiltonian by

	using different functions implemented in OpenFermion.

	+ Convert OpenFermion’s QubitOperator to a Pennylane `Hamiltonian` class.

	+ Perform a Variational Quantum Eigensolver (VQE) computation with this Hamiltonian in PennyLane.Check out the [quantum chemistry quickstart](https://pennylane.readthedocs.io/en/latest/introduction/chemistry.html), as well the quantum chemistry and VQE tutorials.

* PennyLane now has some functions and classes for creating and solving VQE

problems. [(#467)](https://github.com/XanaduAI/pennylane/pull/467)

	+ `qml.Hamiltonian`: a lightweight class for representing qubit Hamiltonians

	+ `qml.VQECost`: a class for quickly constructing a differentiable cost function

	given a circuit ansatz, Hamiltonian, and one or more devices

	

	

	

	```

	>>> H = qml.vqe.Hamiltonian(coeffs, obs)

	>>> cost = qml.VQECost(ansatz, hamiltonian, dev, interface="torch")

	>>> params = torch.rand([4, 3])

	>>> cost(params)

	tensor(0.0245, dtype=torch.float64)

	

	```

* Added a circuit drawing feature that provides a text-based representation

of a QNode instance. It can be invoked via `qnode.draw()`. The user can specify

to display variable names instead of variable values and choose either an ASCII

or Unicode charset.

[(#446)](https://github.com/XanaduAI/pennylane/pull/446)

Consider the following circuit as an example:

```

@qml.qnode(dev)

def qfunc(a, w):

    qml.Hadamard(0)

    qml.CRX(a, wires=[0, 1])

    qml.Rot(w[0], w[1], w[2], wires=[1])

    qml.CRX(-a, wires=[0, 1])

    return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1))

```

We can draw the circuit after it has been executed:

```

>>> result = qfunc(2.3, [1.2, 3.2, 0.7])

>>> print(qfunc.draw())

 0: ──H──╭C────────────────────────────╭C─────────╭┤ ⟨Z ⊗ Z⟩

 1: ─────╰RX(2.3)──Rot(1.2, 3.2, 0.7)──╰RX(-2.3)──╰┤ ⟨Z ⊗ Z⟩

>>> print(qfunc.draw(charset="ascii"))

 0: --H--+C----------------------------+C---------+| <Z @ Z>

 1: -----+RX(2.3)--Rot(1.2, 3.2, 0.7)--+RX(-2.3)--+| <Z @ Z>

>>> print(qfunc.draw(show\_variable\_names=True))

 0: ──H──╭C─────────────────────────────╭C─────────╭┤ ⟨Z ⊗ Z⟩

 1: ─────╰RX(a)──Rot(w[0], w[1], w[2])──╰RX(-1\*a)──╰┤ ⟨Z ⊗ Z⟩

```

* Added `QAOAEmbedding` and its parameter initialization

as a new trainable template.

[(#442)](https://github.com/XanaduAI/pennylane/pull/442)

![](https://pennylane.readthedocs.io/en/latest/_images/qaoa_layers.png)

* Added the `qml.probs()` measurement function, allowing QNodes

to differentiate variational circuit probabilities

on simulators and hardware.

[(#432)](https://github.com/XanaduAI/pennylane/pull/432)

```

@qml.qnode(dev)

def circuit(x):

    qml.Hadamard(wires=0)

    qml.RY(x, wires=0)

    qml.RX(x, wires=1)

    qml.CNOT(wires=[0, 1])

    return qml.probs(wires=[0])

```

Executing this circuit gives the marginal probability of wire 1:

```

>>> circuit(0.2)

[0.40066533 0.59933467]

```

QNodes that return probabilities fully support autodifferentiation.

* Added the convenience load functions `qml.from\_pyquil`, `qml.from\_quil` and

`qml.from\_quil\_file` that convert pyQuil objects and Quil code to PennyLane

templates. This feature requires version 0.8 or above of the PennyLane-Forest

plugin.

[(#459)](https://github.com/XanaduAI/pennylane/pull/459)

* Added a `qml.inv` method that inverts templates and sequences of Operations.

Added a `@qml.template` decorator that makes templates return the queued Operations.

[(#462)](https://github.com/XanaduAI/pennylane/pull/462)

For example, using this function to invert a template inside a QNode:

```

@qml.template

def ansatz(weights, wires):

    for idx, wire in enumerate(wires):

        qml.RX(weights[idx], wires=[wire])

    for idx in range(len(wires) - 1):

        qml.CNOT(wires=[wires[idx], wires[idx + 1]])

dev = qml.device('default.qubit', wires=2)

@qml.qnode(dev)

def circuit(weights):

    qml.inv(ansatz(weights, wires=[0, 1]))

    return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1))

```

* Added the `QNodeCollection` container class, that allows independent

QNodes to be stored and evaluated simultaneously. Experimental support

for asynchronous evaluation of contained QNodes is provided with the

`parallel=True` keyword argument.

[(#466)](https://github.com/XanaduAI/pennylane/pull/466)

* Added a high level `qml.map` function, that maps a quantum

circuit template over a list of observables or devices, returning

a `QNodeCollection`.

[(#466)](https://github.com/XanaduAI/pennylane/pull/466)

For example:

```

>>> def my\_template(params, wires, \*\*kwargs):

>>>    qml.RX(params[0], wires=wires[0])

>>>    qml.RX(params[1], wires=wires[1])

>>>    qml.CNOT(wires=wires)

>>> obs\_list = [qml.PauliX(0) @ qml.PauliZ(1), qml.PauliZ(0) @ qml.PauliX(1)]

>>> dev = qml.device("default.qubit", wires=2)

>>> qnodes = qml.map(my\_template, obs\_list, dev, measure="expval")

>>> qnodes([0.54, 0.12])

array([-0.06154835 0.99280864])

```

* Added high level `qml.sum`, `qml.dot`, `qml.apply` functions

that act on QNode collections.

[(#466)](https://github.com/XanaduAI/pennylane/pull/466)

`qml.apply` allows vectorized functions to act over the entire QNode

collection:

```

>>> qnodes = qml.map(my\_template, obs\_list, dev, measure="expval")

>>> cost = qml.apply(np.sin, qnodes)

>>> cost([0.54, 0.12])

array([-0.0615095 0.83756375])

```

`qml.sum` and `qml.dot` take the sum of a QNode collection, and a

dot product of tensors/arrays/QNode collections, respectively.

### Breaking changes

* Deprecated the old-style `QNode` such that only the new-style `QNode` and its syntax can be used,

moved all related files from the `pennylane/beta` folder to `pennylane`.

[(#440)](https://github.com/XanaduAI/pennylane/pull/440)

### Improvements

* Added the `Tensor.prune()` method and the `Tensor.non\_identity\_obs` property for extracting

non-identity instances from the observables making up a `Tensor` instance.

[(#498)](https://github.com/XanaduAI/pennylane/pull/498)

* Renamed the `expt.tensornet` and `expt.tensornet.tf` devices to `default.tensor` and

`default.tensor.tf`.

[(#495)](https://github.com/XanaduAI/pennylane/pull/495)

* Added a serialization method to the `CircuitGraph` class that is used to create a unique

hash for each quantum circuit graph.

[(#470)](https://github.com/XanaduAI/pennylane/pull/470)

* Added the `Observable.eigvals` method to return the eigenvalues of observables.

[(#449)](https://github.com/XanaduAI/pennylane/pull/449)

* Added the `Observable.diagonalizing\_gates` method to return the gates

that diagonalize an observable in the computational basis.

[(#454)](https://github.com/XanaduAI/pennylane/pull/454)

* Added the `Operator.matrix` method to return the matrix representation

of an operator in the computational basis.

[(#454)](https://github.com/XanaduAI/pennylane/pull/454)

* Added a `QubitDevice` class which implements common functionalities of plugin devices such that

plugin devices can rely on these implementations. The new `QubitDevice` also includes

a new `execute` method, which allows for more convenient plugin design. In addition, `QubitDevice`

also unifies the way samples are generated on qubit-based devices.

[(#452)](https://github.com/XanaduAI/pennylane/pull/452)

[(#473)](https://github.com/XanaduAI/pennylane/pull/473)

* Improved documentation of `AmplitudeEmbedding` and `BasisEmbedding` templates.

[(#441)](https://github.com/XanaduAI/pennylane/pull/441)

[(#439)](https://github.com/XanaduAI/pennylane/pull/439)

* Codeblocks in the documentation now have a ‘copy’ button for easily

copying examples.

[(#437)](https://github.com/XanaduAI/pennylane/pull/437)

### Documentation

* Update the developers plugin guide to use QubitDevice.

[(#483)](https://github.com/XanaduAI/pennylane/pull/483)

### Bug fixes

* Fixed a bug in `CVQNode.\_pd\_analytic`, where non-descendant observables were not

Heisenberg-transformed before evaluating the partial derivatives when using the

order-2 parameter-shift method, resulting in an erroneous Jacobian for some circuits.

[(#433)](https://github.com/XanaduAI/pennylane/pull/433)

### Contributors

This release contains contributions from (in alphabetical order):

Juan Miguel Arrazola, Ville Bergholm, Alain Delgado Gran, Olivia Di Matteo,

Theodor Isacsson, Josh Izaac, Soran Jahangiri, Nathan Killoran, Johannes Jakob Meyer,

Zeyue Niu, Maria Schuld, Antal Száva.

orphan

#### Release 0.7.0[¶](#release-0-7-0 "Permalink to this headline")

### New features since last release

* Custom padding constant in `AmplitudeEmbedding` is supported (see ‘Breaking changes’.)

[(#419)](https://github.com/XanaduAI/pennylane/pull/419)

* `StronglyEntanglingLayer` and `RandomLayer` now work with a single wire.

[(#409)](https://github.com/XanaduAI/pennylane/pull/409)

[(#413)](https://github.com/XanaduAI/pennylane/pull/413)

* Added support for applying the inverse of an `Operation` within a circuit.

[(#377)](https://github.com/XanaduAI/pennylane/pull/377)

* Added an `OperationRecorder()` context manager, that allows templates

and quantum functions to be executed while recording events. The

recorder can be used with and without QNodes as a debugging utility.

[(#388)](https://github.com/XanaduAI/pennylane/pull/388)

* Operations can now specify a decomposition that is used when the desired operation

is not supported on the target device.

[(#396)](https://github.com/XanaduAI/pennylane/pull/396)

* The ability to load circuits from external frameworks as templates

has been added via the new `qml.load()` function. This feature

requires plugin support — this initial release provides support

for Qiskit circuits and QASM files when `pennylane-qiskit` is installed,

via the functions `qml.from\_qiskit` and `qml.from\_qasm`.

[(#418)](https://github.com/XanaduAI/pennylane/pull/418)

* An experimental tensor network device has been added

[(#416)](https://github.com/XanaduAI/pennylane/pull/416)

[(#395)](https://github.com/XanaduAI/pennylane/pull/395)

[(#394)](https://github.com/XanaduAI/pennylane/pull/394)

[(#380)](https://github.com/XanaduAI/pennylane/pull/380)

* An experimental tensor network device which uses TensorFlow for

backpropagation has been added

[(#427)](https://github.com/XanaduAI/pennylane/pull/427)

* Custom padding constant in `AmplitudeEmbedding` is supported (see ‘Breaking changes’.)

[(#419)](https://github.com/XanaduAI/pennylane/pull/419)

### Breaking changes

* The `pad` parameter in `AmplitudeEmbedding()` is now either `None` (no automatic padding), or a

number that is used as the padding constant.

[(#419)](https://github.com/XanaduAI/pennylane/pull/419)

* Initialization functions now return a single array of weights per function. Utilities for multi-weight templates

`Interferometer()` and `CVNeuralNetLayers()` are provided.

[(#412)](https://github.com/XanaduAI/pennylane/pull/412)

* The single layer templates `RandomLayer()`, `CVNeuralNetLayer()` and `StronglyEntanglingLayer()`

have been turned into private functions `\_random\_layer()`, `\_cv\_neural\_net\_layer()` and

`\_strongly\_entangling\_layer()`. Recommended use is now via the corresponding `Layers()` templates.

[(#413)](https://github.com/XanaduAI/pennylane/pull/413)

### Improvements

* Added extensive input checks in templates.

[(#419)](https://github.com/XanaduAI/pennylane/pull/419)

* Templates integration tests are rewritten - now cover keyword/positional argument passing,

interfaces and combinations of templates.

[(#409)](https://github.com/XanaduAI/pennylane/pull/409)

[(#419)](https://github.com/XanaduAI/pennylane/pull/419)

* State vector preparation operations in the `default.qubit` plugin can now be

applied to subsets of wires, and are restricted to being the first operation

in a circuit.

[(#346)](https://github.com/XanaduAI/pennylane/pull/346)

* The `QNode` class is split into a hierarchy of simpler classes.

[(#354)](https://github.com/XanaduAI/pennylane/pull/354)

[(#398)](https://github.com/XanaduAI/pennylane/pull/398)

[(#415)](https://github.com/XanaduAI/pennylane/pull/415)

[(#417)](https://github.com/XanaduAI/pennylane/pull/417)

[(#425)](https://github.com/XanaduAI/pennylane/pull/425)

* Added the gates U1, U2 and U3 parametrizing arbitrary unitaries on 1, 2 and 3

qubits and the Toffoli gate to the set of qubit operations.

[(#396)](https://github.com/XanaduAI/pennylane/pull/396)

* Changes have been made to accomodate the movement of the main function

in `pytest.\_internal` to `pytest.\_internal.main` in pip 19.3.

[(#404)](https://github.com/XanaduAI/pennylane/pull/404)

* Added the templates `BasisStatePreparation` and `MottonenStatePreparation` that use

gates to prepare a basis state and an arbitrary state respectively.

[(#336)](https://github.com/XanaduAI/pennylane/pull/336)

* Added decompositions for `BasisState` and `QubitStateVector` based on state

preparation templates.

[(#414)](https://github.com/XanaduAI/pennylane/pull/414)

* Replaces the pseudo-inverse in the quantum natural gradient optimizer

(which can be numerically unstable) with `np.linalg.solve`.

[(#428)](https://github.com/XanaduAI/pennylane/pull/428)

### Contributors

This release contains contributions from (in alphabetical order):

Ville Bergholm, Josh Izaac, Nathan Killoran, Angus Lowe, Johannes Jakob Meyer,

Oluwatobi Ogunbayo, Maria Schuld, Antal Száva.

orphan

#### Release 0.6.0[¶](#release-0-6-0 "Permalink to this headline")

### New features since last release

* The devices `default.qubit` and `default.gaussian` have a new initialization parameter

`analytic` that indicates if expectation values and variances should be calculated

analytically and not be estimated from data.

[(#317)](https://github.com/XanaduAI/pennylane/pull/317)

* Added C-SWAP gate to the set of qubit operations

[(#330)](https://github.com/XanaduAI/pennylane/pull/330)

* The TensorFlow interface has been renamed from `"tfe"` to `"tf"`, and

now supports TensorFlow 2.0.

[(#337)](https://github.com/XanaduAI/pennylane/pull/337)

* Added the S and T gates to the set of qubit operations.

[(#343)](https://github.com/XanaduAI/pennylane/pull/343)

* Tensor observables are now supported within the `expval`,

`var`, and `sample` functions, by using the `@` operator.

[(#267)](https://github.com/XanaduAI/pennylane/pull/267)

### Breaking changes

* The argument `n` specifying the number of samples in the method `Device.sample` was removed.

Instead, the method will always return `Device.shots` many samples.

[(#317)](https://github.com/XanaduAI/pennylane/pull/317)

### Improvements

* The number of shots / random samples used to estimate expectation values and variances, `Device.shots`,

can now be changed after device creation.

[(#317)](https://github.com/XanaduAI/pennylane/pull/317)

* Unified import shortcuts to be under qml in qnode.py

and test\_operation.py

[(#329)](https://github.com/XanaduAI/pennylane/pull/329)

* The quantum natural gradient now uses `scipy.linalg.pinvh` which is more efficient for symmetric matrices

than the previously used `scipy.linalg.pinv`.

[(#331)](https://github.com/XanaduAI/pennylane/pull/331)

* The deprecated `qml.expval.Observable` syntax has been removed.

[(#267)](https://github.com/XanaduAI/pennylane/pull/267)

* Remainder of the unittest-style tests were ported to pytest.

[(#310)](https://github.com/XanaduAI/pennylane/pull/310)

* The `do\_queue` argument for operations now only takes effect

within QNodes. Outside of QNodes, operations can now be instantiated

without needing to specify `do\_queue`.

[(#359)](https://github.com/XanaduAI/pennylane/pull/359)

### Documentation

* The docs are rewritten and restructured to contain a code introduction section as well as an API section.

[(#314)](https://github.com/XanaduAI/pennylane/pull/275)

* Added Ising model example to the tutorials

[(#319)](https://github.com/XanaduAI/pennylane/pull/319)

* Added tutorial for QAOA on MaxCut problem

[(#328)](https://github.com/XanaduAI/pennylane/pull/328)

* Added QGAN flow chart figure to its tutorial

[(#333)](https://github.com/XanaduAI/pennylane/pull/333)

* Added missing figures for gallery thumbnails of state-preparation

and QGAN tutorials

[(#326)](https://github.com/XanaduAI/pennylane/pull/326)

* Fixed typos in the state preparation tutorial

[(#321)](https://github.com/XanaduAI/pennylane/pull/321)

* Fixed bug in VQE tutorial 3D plots

[(#327)](https://github.com/XanaduAI/pennylane/pull/327)

### Bug fixes

* Fixed typo in measurement type error message in qnode.py

[(#341)](https://github.com/XanaduAI/pennylane/pull/341)

### Contributors

This release contains contributions from (in alphabetical order):

Shahnawaz Ahmed, Ville Bergholm, Aroosa Ijaz, Josh Izaac, Nathan Killoran, Angus Lowe,

Johannes Jakob Meyer, Maria Schuld, Antal Száva, Roeland Wiersema.

orphan

#### Release 0.5.0[¶](#release-0-5-0 "Permalink to this headline")

### New features since last release

* Adds a new optimizer, `qml.QNGOptimizer`, which optimizes QNodes using

quantum natural gradient descent. See <https://arxiv.org/abs/1909.02108>

for more details.

[(#295)](https://github.com/XanaduAI/pennylane/pull/295)

[(#311)](https://github.com/XanaduAI/pennylane/pull/311)

* Adds a new QNode method, `QNode.metric\_tensor()`,

which returns the block-diagonal approximation to the Fubini-Study

metric tensor evaluated on the attached device.

[(#295)](https://github.com/XanaduAI/pennylane/pull/295)

* Sampling support: QNodes can now return a specified number of samples

from a given observable via the top-level `pennylane.sample()` function.

To support this on plugin devices, there is a new `Device.sample` method.

Calculating gradients of QNodes that involve sampling is not possible.

[(#256)](https://github.com/XanaduAI/pennylane/pull/256)

* `default.qubit` has been updated to provide support for sampling.

[(#256)](https://github.com/XanaduAI/pennylane/pull/256)

* Added controlled rotation gates to PennyLane operations and `default.qubit` plugin.

[(#251)](https://github.com/XanaduAI/pennylane/pull/251)

### Breaking changes

* The method `Device.supported` was removed, and replaced with the methods

`Device.supports\_observable` and `Device.supports\_operation`.

Both methods can be called with string arguments (`dev.supports\_observable('PauliX')`) and

class arguments (`dev.supports\_observable(qml.PauliX)`).

[(#276)](https://github.com/XanaduAI/pennylane/pull/276)

* The following CV observables were renamed to comply with the new Operation/Observable

scheme: `MeanPhoton` to `NumberOperator`, `Homodyne` to `QuadOperator` and `NumberState` to `FockStateProjector`.

[(#254)](https://github.com/XanaduAI/pennylane/pull/254)

### Improvements

* The `AmplitudeEmbedding` function now provides options to normalize and

pad features to ensure a valid state vector is prepared.

[(#275)](https://github.com/XanaduAI/pennylane/pull/275)

* Operations can now optionally specify generators, either as existing PennyLane

operations, or by providing a NumPy array.

[(#295)](https://github.com/XanaduAI/pennylane/pull/295)

[(#313)](https://github.com/XanaduAI/pennylane/pull/313)

* Adds a `Device.parameters` property, so that devices can view a dictionary mapping free

parameters to operation parameters. This will allow plugin devices to take advantage

of parametric compilation.

[(#283)](https://github.com/XanaduAI/pennylane/pull/283)

* Introduces two enumerations: `Any` and `All`, representing any number of wires

and all wires in the system respectively. They can be imported from

`pennylane.operation`, and can be used when defining the `Operation.num\_wires`

class attribute of operations.

[(#277)](https://github.com/XanaduAI/pennylane/pull/277)

As part of this change:

	+ `All` is equivalent to the integer 0, for backwards compatibility with the

	existing test suite

	+ `Any` is equivalent to the integer -1 to allow numeric comparison

	operators to continue working

	+ An additional validation is now added to the `Operation` class,

	which will alert the user that an operation with `num\_wires = All`

	is being incorrectly.

* The one-qubit rotations in `pennylane.plugins.default\_qubit` no longer depend on Scipy’s `expm`. Instead

they are calculated with Euler’s formula.

[(#292)](https://github.com/XanaduAI/pennylane/pull/292)

* Creates an `ObservableReturnTypes` enumeration class containing `Sample`,

`Variance` and `Expectation`. These new values can be assigned to the `return\_type`

attribute of an `Observable`.

[(#290)](https://github.com/XanaduAI/pennylane/pull/290)

* Changed the signature of the `RandomLayer` and `RandomLayers` templates to have a fixed seed by default.

[(#258)](https://github.com/XanaduAI/pennylane/pull/258)

* `setup.py` has been cleaned up, removing the non-working shebang,

and removing unused imports.

[(#262)](https://github.com/XanaduAI/pennylane/pull/262)

### Documentation

* A documentation refactor to simplify the tutorials and

include Sphinx-Gallery.

[(#291)](https://github.com/XanaduAI/pennylane/pull/291)

	+ Examples and tutorials previously split across the `examples/`

	and `doc/tutorials/` directories, in a mixture of ReST and Jupyter notebooks,

	have been rewritten as Python scripts with ReST comments in a single location,

	the `examples/` folder.

	+ Sphinx-Gallery is used to automatically build and run the tutorials.

	Rendered output is displayed in the Sphinx documentation.

	+ Links are provided at the top of every tutorial page for downloading the

	tutorial as an executable python script, downloading the tutorial

	as a Jupyter notebook, or viewing the notebook on GitHub.

	+ The tutorials table of contents have been moved to a single quick start page.

* Fixed a typo in `QubitStateVector`.

[(#296)](https://github.com/XanaduAI/pennylane/pull/296)

* Fixed a typo in the `default\_gaussian.gaussian\_state` function.

[(#293)](https://github.com/XanaduAI/pennylane/pull/293)

* Fixed a typo in the gradient recipe within the `RX`, `RY`, `RZ`

operation docstrings.

[(#248)](https://github.com/XanaduAI/pennylane/pull/248)

* Fixed a broken link in the tutorial documentation, as a

result of the `qml.expval.Observable` deprecation.

[(#246)](https://github.com/XanaduAI/pennylane/pull/246)

### Bug fixes

* Fixed a bug where a `PolyXP` observable would fail if applied to subsets

of wires on `default.gaussian`.

[(#277)](https://github.com/XanaduAI/pennylane/pull/277)

### Contributors

This release contains contributions from (in alphabetical order):

Simon Cross, Aroosa Ijaz, Josh Izaac, Nathan Killoran, Johannes Jakob Meyer,

Rohit Midha, Nicolás Quesada, Maria Schuld, Antal Száva, Roeland Wiersema.

orphan

#### Release 0.4.0[¶](#release-0-4-0 "Permalink to this headline")

### New features since last release

* `pennylane.expval()` is now a top-level *function*, and is no longer

a package of classes. For now, the existing `pennylane.expval.Observable`

interface continues to work, but will raise a deprecation warning.

[(#232)](https://github.com/XanaduAI/pennylane/pull/232)

* Variance support: QNodes can now return the variance of observables,

via the top-level `pennylane.var()` function. To support this on

plugin devices, there is a new `Device.var` method.

The following observables support analytic gradients of variances:

	+ All qubit observables (requiring 3 circuit evaluations for involutory

	observables such as `Identity`, `X`, `Y`, `Z`; and 5 circuit evals for

	non-involutary observables, currently only `qml.Hermitian`)

	+ First-order CV observables (requiring 5 circuit evaluations)Second-order CV observables support numerical variance gradients.

* `pennylane.about()` function added, providing details

on current PennyLane version, installed plugins, Python,

platform, and NumPy versions [(#186)](https://github.com/XanaduAI/pennylane/pull/186)

* Removed the logic that allowed `wires` to be passed as a positional

argument in quantum operations. This allows us to raise more useful

error messages for the user if incorrect syntax is used.

[(#188)](https://github.com/XanaduAI/pennylane/pull/188)

* Adds support for multi-qubit expectation values of the `pennylane.Hermitian()`

observable [(#192)](https://github.com/XanaduAI/pennylane/pull/192)

* Adds support for multi-qubit expectation values in `default.qubit`.

[(#202)](https://github.com/XanaduAI/pennylane/pull/202)

* Organize templates into submodules [(#195)](https://github.com/XanaduAI/pennylane/pull/195).

This included the following improvements:

	+ Distinguish embedding templates from layer templates.

	+ New random initialization functions supporting the templates available

	in the new submodule `pennylane.init`.

	+ Added a random circuit template (`RandomLayers()`), in which rotations and 2-qubit gates are randomly

	distributed over the wires

	+ Add various embedding strategies

### Breaking changes

* The `Device` methods `expectations`, `pre\_expval`, and `post\_expval` have been

renamed to `observables`, `pre\_measure`, and `post\_measure` respectively.

[(#232)](https://github.com/XanaduAI/pennylane/pull/232)

### Improvements

* `default.qubit` plugin now uses `np.tensordot` when applying quantum operations

and evaluating expectations, resulting in significant speedup

[(#239)](https://github.com/XanaduAI/pennylane/pull/239),

[(#241)](https://github.com/XanaduAI/pennylane/pull/241)

* PennyLane now allows division of quantum operation parameters by a constant

[(#179)](https://github.com/XanaduAI/pennylane/pull/179)

* Portions of the test suite are in the process of being ported to pytest.

Note: this is still a work in progress.

Ported tests include:

	+ `test\_ops.py`

	+ `test\_about.py`

	+ `test\_classical\_gradients.py`

	+ `test\_observables.py`

	+ `test\_measure.py`

	+ `test\_init.py`

	+ `test\_templates\*.py`

	+ `test\_ops.py`

	+ `test\_variable.py`

	+ `test\_qnode.py` (partial)

### Bug fixes

* Fixed a bug in `Device.supported`, which would incorrectly

mark an operation as supported if it shared a name with an

observable [(#203)](https://github.com/XanaduAI/pennylane/pull/203)

* Fixed a bug in `Operation.wires`, by explicitly casting the

type of each wire to an integer [(#206)](https://github.com/XanaduAI/pennylane/pull/206)

* Removed code in PennyLane which configured the logger,

as this would clash with users’ configurations

[(#208)](https://github.com/XanaduAI/pennylane/pull/208)

* Fixed a bug in `default.qubit`, in which `QubitStateVector` operations

were accidentally being cast to `np.float` instead of `np.complex`.

[(#211)](https://github.com/XanaduAI/pennylane/pull/211)

### Contributors

This release contains contributions from:

Shahnawaz Ahmed, riveSunder, Aroosa Ijaz, Josh Izaac, Nathan Killoran, Maria Schuld.

orphan

#### Release 0.3.1[¶](#release-0-3-1 "Permalink to this headline")

### Bug fixes

* Fixed a bug where the interfaces submodule was not correctly being packaged via setup.py

orphan

#### Release 0.3.0[¶](#release-0-3-0 "Permalink to this headline")

### New features since last release

* PennyLane now includes a new `interfaces` submodule, which enables QNode integration with additional machine learning libraries.

* Adds support for an experimental PyTorch interface for QNodes

* Adds support for an experimental TensorFlow eager execution interface for QNodes

* Adds a PyTorch+GPU+QPU tutorial to the documentation

* Documentation now includes links and tutorials including the new [PennyLane-Forest](https://github.com/rigetti/pennylane-forest) plugin.

### Improvements

* Printing a QNode object, via `print(qnode)` or in an interactive terminal, now displays more useful information regarding the QNode,

including the device it runs on, the number of wires, it’s interface, and the quantum function it uses:

```

>>> print(qnode)

<QNode: device='default.qubit', func=circuit, wires=2, interface=PyTorch>

```

### Contributors

This release contains contributions from:

Josh Izaac and Nathan Killoran.

orphan

#### Release 0.2.0[¶](#release-0-2-0 "Permalink to this headline")

### New features since last release

* Added the `Identity` expectation value for both CV and qubit models [(#135)](https://github.com/XanaduAI/pennylane/pull/135)

* Added the `templates.py` submodule, containing some commonly used QML models to be used as ansatz in QNodes [(#133)](https://github.com/XanaduAI/pennylane/pull/133)

* Added the `qml.Interferometer` CV operation [(#152)](https://github.com/XanaduAI/pennylane/pull/152)

* Wires are now supported as free QNode parameters [(#151)](https://github.com/XanaduAI/pennylane/pull/151)

* Added ability to update stepsizes of the optimizers [(#159)](https://github.com/XanaduAI/pennylane/pull/159)

### Improvements

* Removed use of hardcoded values in the optimizers, made them parameters (see [#131](https://github.com/XanaduAI/pennylane/pull/131) and [#132](https://github.com/XanaduAI/pennylane/pull/132))

* Created the new `PlaceholderExpectation`, to be used when both CV and qubit expval modules contain expectations with the same name

* Provide a way for plugins to view the operation queue *before* applying operations. This allows for on-the-fly modifications of

the queue, allowing hardware-based plugins to support the full range of qubit expectation values. [(#143)](https://github.com/XanaduAI/pennylane/pull/143)

* QNode return values now support *any* form of sequence, such as lists, sets, etc. [(#144)](https://github.com/XanaduAI/pennylane/pull/144)

* CV analytic gradient calculation is now more robust, allowing for operations which may not themselves be differentiated, but have a

well defined `\_heisenberg\_rep` method, and so may succeed operations that are analytically differentiable [(#152)](https://github.com/XanaduAI/pennylane/pull/152)

### Bug fixes

* Fixed a bug where the variational classifier example was not batching when learning parity (see [#128](https://github.com/XanaduAI/pennylane/pull/128) and [#129](https://github.com/XanaduAI/pennylane/pull/129))

* Fixed an inconsistency where some initial state operations were documented as accepting complex parameters - all operations

now accept real values [(#146)](https://github.com/XanaduAI/pennylane/pull/146)

### Contributors

This release contains contributions from:

Christian Gogolin, Josh Izaac, Nathan Killoran, and Maria Schuld.

orphan

#### Release 0.1.0[¶](#release-0-1-0 "Permalink to this headline")

Initial public release.

### Contributors

This release contains contributions from:

Ville Bergholm, Josh Izaac, Maria Schuld, Christian Gogolin, and Nathan Killoran.

### qml[¶](#module-pennylane "Permalink to this headline")

This is the top level module from which all basic functions and classes of

PennyLane can be directly imported.

#### Functions[¶](#functions "Permalink to this headline")

| [`about`](index.html#pennylane.about "pennylane.about")() | Prints the information for pennylane installation. |

| [`active\_return`](index.html#pennylane.active_return "pennylane.active_return")() | Function that checks if the new return types system is activated. |

| [`adjoint`](index.html#pennylane.adjoint "pennylane.adjoint")(fn[, lazy]) | Create the adjoint of an Operator or a function that applies the adjoint of the provided function. |

| [`adjoint\_metric\_tensor`](index.html#pennylane.adjoint_metric_tensor "pennylane.adjoint_metric_tensor")(circuit[, device, hybrid]) | Implements the adjoint method outlined in [Jones](https://arxiv.org/abs/2011.02991) to compute the metric tensor. |

| [`apply`](index.html#pennylane.apply "pennylane.apply")(op[, context]) | Apply an instantiated operator or measurement to a queuing context. |

| [`apply\_controlled\_Q`](index.html#pennylane.apply_controlled_Q "pennylane.apply_controlled_Q")(fn, wires, target\_wire, …) | Provides the circuit to apply a controlled version of the \(\mathcal{Q}\) unitary defined in [this](https://arxiv.org/abs/1805.00109) paper. |

| [`batch\_input`](index.html#pennylane.batch_input "pennylane.batch_input")(tape, argnum) | Transform a QNode to support an initial batch dimension for gate inputs. |

| [`batch\_params`](index.html#pennylane.batch_params "pennylane.batch_params")(tape[, all\_operations]) | Transform a QNode to support an initial batch dimension for operation parameters. |

| [`batch\_partial`](index.html#pennylane.batch_partial "pennylane.batch_partial")(qnode[, all\_operations, …]) | Create a batched partial callable object from the QNode specified. |

| [`broadcast`](index.html#pennylane.broadcast "pennylane.broadcast")(unitary, wires, pattern[, …]) | Applies a unitary multiple times to a specific pattern of wires. |

| [`classical\_shadow`](index.html#pennylane.classical_shadow "pennylane.classical_shadow")(wires[, seed]) | The classical shadow measurement protocol. |

| [`commutation\_dag`](index.html#pennylane.commutation_dag "pennylane.commutation_dag")(circuit) | Construct the pairwise-commutation DAG (directed acyclic graph) representation of a quantum circuit. |

| [`compile`](index.html#pennylane.compile "pennylane.compile")(tape[, pipeline, basis\_set, …]) | Compile a circuit by applying a series of transforms to a quantum function. |

| [`cond`](index.html#pennylane.cond "pennylane.cond")(condition, true\_fn[, false\_fn]) | Condition a quantum operation on the results of mid-circuit qubit measurements. |

| [`counts`](index.html#pennylane.counts "pennylane.counts")([op, wires, all\_outcomes]) | Sample from the supplied observable, with the number of shots determined from the `dev.shots` attribute of the corresponding device, returning the number of counts for each sample. |

| [`ctrl`](index.html#pennylane.ctrl "pennylane.ctrl")(op, control[, control\_values, work\_wires]) | Create a method that applies a controlled version of the provided op. |

| [`cut\_circuit`](index.html#pennylane.cut_circuit "pennylane.cut_circuit")(tape[, auto\_cutter, …]) | Cut up a quantum circuit into smaller circuit fragments. |

| [`cut\_circuit\_mc`](index.html#pennylane.cut_circuit_mc "pennylane.cut_circuit_mc")(tape[, …]) | Cut up a circuit containing sample measurements into smaller fragments using a Monte Carlo method. |

| [`defer\_measurements`](index.html#pennylane.defer_measurements "pennylane.defer_measurements")(tape) | Quantum function transform that substitutes operations conditioned on measurement outcomes to controlled operations. |

| [`density\_matrix`](index.html#pennylane.density_matrix "pennylane.density_matrix")(wires) | Quantum density matrix in the computational basis. |

| [`device`](index.html#pennylane.device "pennylane.device")(name[, wires]) | Load a [`Device`](index.html#pennylane.Device "pennylane.Device") and return the instance. |

| [`disable\_return`](index.html#pennylane.disable_return "pennylane.disable_return")() | Function that turns off the new return type system. |

| [`dot`](index.html#pennylane.dot "pennylane.dot")(coeffs, ops[, pauli]) | Returns the dot product between the `coeffs` vector and the `ops` list of operators. |

| [`draw`](index.html#pennylane.draw "pennylane.draw")(qnode[, wire\_order, show\_all\_wires, …]) | Create a function that draws the given qnode or quantum function. |

| [`draw\_mpl`](index.html#pennylane.draw_mpl "pennylane.draw_mpl")(qnode[, wire\_order, …]) | Draw a qnode with matplotlib |

| [`eigvals`](index.html#pennylane.eigvals "pennylane.eigvals")(op[, k, which]) | The eigenvalues of one or more operations. |

| [`enable\_return`](index.html#pennylane.enable_return "pennylane.enable_return")() | Function that turns on the experimental return type system that prefers the use of sequences over arrays. |

| [`equal`](index.html#pennylane.equal "pennylane.equal")(op1, op2[, check\_interface, …]) | Function for determining operator or measurement equality. |

| [`evolve`](index.html#pennylane.evolve "pennylane.evolve")() | This method is dispatched and its functionality depends on the type of the input `op`. |

| [`execute`](index.html#pennylane.execute "pennylane.execute")(tapes, device[, gradient\_fn, …]) | New function to execute a batch of tapes on a device in an autodifferentiable-compatible manner. |

| [`exp`](index.html#pennylane.exp "pennylane.exp")(op[, coeff, num\_steps, id]) | Take the exponential of an Operator times a coefficient. |

| [`expval`](index.html#pennylane.expval "pennylane.expval")(op) | Expectation value of the supplied observable. |

| [`from\_pyquil`](index.html#pennylane.from_pyquil "pennylane.from_pyquil")(pyquil\_program) | Loads pyQuil Program objects by using the converter in the PennyLane-Forest plugin. |

| [`from\_qasm`](index.html#pennylane.from_qasm "pennylane.from_qasm")(quantum\_circuit) | Loads quantum circuits from a QASM string using the converter in the PennyLane-Qiskit plugin. |

| [`from\_qasm\_file`](index.html#pennylane.from_qasm_file "pennylane.from_qasm_file")(qasm\_filename) | Loads quantum circuits from a QASM file using the converter in the PennyLane-Qiskit plugin. |

| [`from\_qiskit`](index.html#pennylane.from_qiskit "pennylane.from_qiskit")(quantum\_circuit) | Loads Qiskit QuantumCircuit objects by using the converter in the PennyLane-Qiskit plugin. |

| [`from\_quil`](index.html#pennylane.from_quil "pennylane.from_quil")(quil) | Loads quantum circuits from a Quil string using the converter in the PennyLane-Forest plugin. |

| [`from\_quil\_file`](index.html#pennylane.from_quil_file "pennylane.from_quil_file")(quil\_filename) | Loads quantum circuits from a Quil file using the converter in the PennyLane-Forest plugin. |

| [`generator`](index.html#pennylane.generator "pennylane.generator")(op[, format]) | Returns the generator of an operation. |

| [`import\_operator`](index.html#pennylane.import_operator "pennylane.import_operator")(qubit\_observable[, format, …]) | Convert an external operator to a PennyLane operator. |

| [`is\_commuting`](index.html#pennylane.is_commuting "pennylane.is_commuting")(operation1, operation2[, wire\_map]) | Check if two operations are commuting using a lookup table. |

| [`is\_hermitian`](index.html#pennylane.is_hermitian "pennylane.is_hermitian")(op) | Check if the operation is hermitian. |

| [`is\_unitary`](index.html#pennylane.is_unitary "pennylane.is_unitary")(op) | Check if the operation is unitary. |

| [`jacobian`](index.html#pennylane.jacobian "pennylane.jacobian")(func[, argnum]) | Returns the Jacobian as a callable function of vector-valued (functions of) QNodes. |

| [`jordan\_wigner`](index.html#pennylane.jordan_wigner "pennylane.jordan_wigner")(fermi\_operator, \*\*kwargs) | Convert a fermionic operator to a qubit operator using the Jordan-Wigner mapping. |

| [`layer`](index.html#pennylane.layer "pennylane.layer")(template, depth, \*args, \*\*kwargs) | Repeatedly applies a unitary a given number of times. |

| [`load`](index.html#pennylane.load "pennylane.load")(quantum\_circuit\_object, format) | Load external quantum assembly and quantum circuits from supported frameworks into PennyLane templates. |

| [`map\_wires`](index.html#pennylane.map_wires "pennylane.map_wires")(input, wire\_map[, queue, replace]) | Changes the wires of an operator, tape, qnode or quantum function according to the given wire map. |

| [`matrix`](index.html#pennylane.matrix "pennylane.matrix")(op, \*[, wire\_order]) | The matrix representation of an operation or quantum circuit. |

| [`measure`](index.html#pennylane.measure "pennylane.measure")(wires[, reset]) | Perform a mid-circuit measurement in the computational basis on the supplied qubit. |

| [`metric\_tensor`](index.html#pennylane.metric_tensor "pennylane.metric_tensor")(tape[, argnum, approx, …]) | Returns a function that computes the metric tensor of a given QNode or quantum tape. |

| [`mutual\_info`](index.html#pennylane.mutual_info "pennylane.mutual_info")(wires0, wires1[, log\_base]) | Mutual information between the subsystems prior to measurement: |

| [`pattern\_matching`](index.html#pennylane.pattern_matching "pennylane.pattern_matching")(circuit\_dag, pattern\_dag) | Function that applies the pattern matching algorithm and returns the list of maximal matches. |

| [`pattern\_matching\_optimization`](index.html#pennylane.pattern_matching_optimization "pennylane.pattern_matching_optimization")(tape, …[, …]) | Quantum function transform to optimize a circuit given a list of patterns (templates). |

| [`pauli\_decompose`](index.html#pennylane.pauli_decompose "pennylane.pauli_decompose")(H[, hide\_identity, …]) | Decomposes a Hermitian matrix into a linear combination of Pauli operators. |

| [`paulix\_ops`](index.html#pennylane.paulix_ops "pennylane.paulix_ops")(generators, num\_qubits) | Generate the single qubit Pauli-X operators \(\sigma^{x}\_{i}\) for each symmetry \(\tau\_j\), such that it anti-commutes with \(\tau\_j\) and commutes with all others symmetries \(\tau\_{k\neq j}\). |

| [`pow`](index.html#pennylane.pow "pennylane.pow")(base[, z, lazy, id]) | Raise an Operator to a power. |

| [`probs`](index.html#pennylane.probs "pennylane.probs")([wires, op]) | Probability of each computational basis state. |

| [`prod`](index.html#pennylane.prod "pennylane.prod")(\*ops[, id, lazy]) | Construct an operator which represents the generalized product of the operators provided. |

| [`purity`](index.html#pennylane.purity "pennylane.purity")(wires) | The purity of the system prior to measurement. |

| [`qfunc\_transform`](index.html#pennylane.qfunc_transform "pennylane.qfunc_transform")(tape\_transform) | Given a function which defines a tape transform, convert the function into one that applies the tape transform to quantum functions (qfuncs). |

| [`qnode`](index.html#pennylane.qnode "pennylane.qnode")(func, device[, interface, …]) | Represents a quantum node in the hybrid computational graph. |

| [`qsvt`](index.html#pennylane.qsvt "pennylane.qsvt")(A, angles, wires[, convention]) | Implements the [quantum singular value transformation](https://arxiv.org/abs/1806.01838) (QSVT) circuit. |

| [`quantum\_monte\_carlo`](index.html#pennylane.quantum_monte_carlo "pennylane.quantum_monte_carlo")(fn, wires, target\_wire, …) | Provides the circuit to perform the [quantum Monte Carlo estimation](https://arxiv.org/abs/1805.00109) algorithm. |

| [`refresh\_devices`](index.html#pennylane.refresh_devices "pennylane.refresh_devices")() | Scan installed PennyLane plugins to refresh the device list. |

| [`s\_prod`](index.html#pennylane.s_prod "pennylane.s_prod")(scalar, operator[, lazy, id]) | Construct an operator which is the scalar product of the given scalar and operator provided. |

| [`sample`](index.html#pennylane.sample "pennylane.sample")([op, wires]) | Sample from the supplied observable, with the number of shots determined from the `dev.shots` attribute of the corresponding device, returning raw samples. |

| [`shadow\_expval`](index.html#pennylane.shadow_expval "pennylane.shadow_expval")(H[, k, seed]) | Compute expectation values using classical shadows in a differentiable manner. |

| [`simplify`](index.html#pennylane.simplify "pennylane.simplify")(input) | Simplifies an operator, tape, qnode or quantum function by reducing its arithmetic depth or number of rotation parameters. |

| [`snapshots`](index.html#pennylane.snapshots "pennylane.snapshots")(qnode) | Create a function that retrieves snapshot results from a QNode. |

| [`specs`](index.html#pennylane.specs "pennylane.specs")(qnode[, max\_expansion, expansion\_strategy]) | Resource information about a quantum circuit. |

| [`state`](index.html#pennylane.state "pennylane.state")() | Quantum state in the computational basis. |

| [`sum`](index.html#pennylane.sum "pennylane.sum")(\*summands[, id, lazy]) | Construct an operator which is the sum of the given operators. |

| [`symmetry\_generators`](index.html#pennylane.symmetry_generators "pennylane.symmetry_generators")(h) | Compute the generators \(\{\tau\_1, \ldots, \tau\_k\}\) for a Hamiltonian over the binary field \(\mathbb{Z}\_2\). |

| [`taper`](index.html#pennylane.taper "pennylane.taper")(h, generators, paulixops, paulix\_sector) | Transform a Hamiltonian with a Clifford operator and then taper qubits. |

| [`taper\_operation`](index.html#pennylane.taper_operation "pennylane.taper_operation")(operation, generators, …) | Transform a gate operation with a Clifford operator and then taper qubits. |

| [`var`](index.html#pennylane.var "pennylane.var")(op) | Variance of the supplied observable. |

| [`version`](index.html#pennylane.version "pennylane.version")() | Returns the PennyLane version number. |

| [`vn\_entropy`](index.html#pennylane.vn_entropy "pennylane.vn_entropy")(wires[, log\_base]) | Von Neumann entropy of the system prior to measurement. |

#### Classes[¶](#classes "Permalink to this headline")

| [`AdagradOptimizer`](index.html#pennylane.AdagradOptimizer "pennylane.AdagradOptimizer")([stepsize, eps]) | Gradient-descent optimizer with past-gradient-dependent learning rate in each dimension. |

| [`AdamOptimizer`](index.html#pennylane.AdamOptimizer "pennylane.AdamOptimizer")([stepsize, beta1, beta2, eps]) | Gradient-descent optimizer with adaptive learning rate, first and second moment. |

| [`AdaptiveOptimizer`](index.html#pennylane.AdaptiveOptimizer "pennylane.AdaptiveOptimizer")([param\_steps, stepsize]) | Optimizer for building fully trained quantum circuits by adding gates adaptively. |

| [`AllSinglesDoubles`](index.html#pennylane.AllSinglesDoubles "pennylane.AllSinglesDoubles")(weights, wires, hf\_state) | Builds a quantum circuit to prepare correlated states of molecules by applying all [`SingleExcitation`](index.html#pennylane.SingleExcitation "pennylane.SingleExcitation") and [`DoubleExcitation`](index.html#pennylane.DoubleExcitation "pennylane.DoubleExcitation") operations to the initial Hartree-Fock state. |

| [`AmplitudeDamping`](index.html#pennylane.AmplitudeDamping "pennylane.AmplitudeDamping")(gamma, wires[, id]) | Single-qubit amplitude damping error channel. |

| [`AmplitudeEmbedding`](index.html#pennylane.AmplitudeEmbedding "pennylane.AmplitudeEmbedding")(features, wires[, …]) | Encodes \(2^n\) features into the amplitude vector of \(n\) qubits. |

| [`AngleEmbedding`](index.html#pennylane.AngleEmbedding "pennylane.AngleEmbedding")(features, wires[, rotation, id]) | Encodes \(N\) features into the rotation angles of \(n\) qubits, where \(N \leq n\). |

| [`ApproxTimeEvolution`](index.html#pennylane.ApproxTimeEvolution "pennylane.ApproxTimeEvolution")(hamiltonian, time, n[, id]) | Applies the Trotterized time-evolution operator for an arbitrary Hamiltonian, expressed in terms of Pauli gates. |

| [`ArbitraryStatePreparation`](index.html#pennylane.ArbitraryStatePreparation "pennylane.ArbitraryStatePreparation")(weights, wires[, id]) | Implements an arbitrary state preparation on the specified wires. |

| [`ArbitraryUnitary`](index.html#pennylane.ArbitraryUnitary "pennylane.ArbitraryUnitary")(weights, wires[, id]) | Implements an arbitrary unitary on the specified wires. |

| [`Barrier`](index.html#pennylane.Barrier "pennylane.Barrier")(wires) | The Barrier operator, used to separate the compilation process into blocks or as a visual tool. |

| [`BasicEntanglerLayers`](index.html#pennylane.BasicEntanglerLayers "pennylane.BasicEntanglerLayers")(weights[, wires, …]) | Layers consisting of one-parameter single-qubit rotations on each qubit, followed by a closed chain or *ring* of CNOT gates. |

| [`BasisEmbedding`](index.html#pennylane.BasisEmbedding "pennylane.BasisEmbedding")(features, wires[, id]) | Encodes \(n\) binary features into a basis state of \(n\) qubits. |

| [`BasisRotation`](index.html#pennylane.BasisRotation "pennylane.BasisRotation")(wires, unitary\_matrix[, check, id]) | Implement a circuit that provides a unitary that can be used to do an exact single-body basis rotation. |

| [`BasisState`](index.html#pennylane.BasisState "pennylane.BasisState")(n, wires) | Prepares a single computational basis state. |

| [`BasisStatePreparation`](index.html#pennylane.BasisStatePreparation "pennylane.BasisStatePreparation")(basis\_state, wires[, id]) | Prepares a basis state on the given wires using a sequence of Pauli-X gates. |

| [`Beamsplitter`](index.html#pennylane.Beamsplitter "pennylane.Beamsplitter")(theta, phi, wires[, id]) | Beamsplitter interaction. |

| [`BitFlip`](index.html#pennylane.BitFlip "pennylane.BitFlip")(p, wires[, id]) | Single-qubit bit flip (Pauli \(X\)) error channel. |

| [`BlockEncode`](index.html#pennylane.BlockEncode "pennylane.BlockEncode")(A, wires) | Construct a unitary \(U(A)\) such that an arbitrary matrix \(A\) is encoded in the top-left block. |

| [`BooleanFn`](index.html#pennylane.BooleanFn "pennylane.BooleanFn")(fn) | Wrapper for simple callables with boolean output that can be manipulated and combined with bit-wise operators. |

| [`CCZ`](index.html#pennylane.CCZ "pennylane.CCZ")(wires) | CCZ (controlled-controlled-Z) gate. |

| [`CH`](index.html#pennylane.CH "pennylane.CH")(wires) | The controlled-Hadamard operator |

| [`CNOT`](index.html#pennylane.CNOT "pennylane.CNOT")(wires) | The controlled-NOT operator |

| [`CPhase`](index.html#pennylane.CPhase "pennylane.CPhase") | alias of `pennylane.ops.qubit.parametric\_ops\_controlled.ControlledPhaseShift` |

| [`CPhaseShift00`](index.html#pennylane.CPhaseShift00 "pennylane.CPhaseShift00")(phi, wires[, id]) | A qubit controlled phase shift. |

| [`CPhaseShift01`](index.html#pennylane.CPhaseShift01 "pennylane.CPhaseShift01")(phi, wires[, id]) | A qubit controlled phase shift. |

| [`CPhaseShift10`](index.html#pennylane.CPhaseShift10 "pennylane.CPhaseShift10")(phi, wires[, id]) | A qubit controlled phase shift. |

| [`CRX`](index.html#pennylane.CRX "pennylane.CRX")(phi, wires[, id]) | The controlled-RX operator |

| [`CRY`](index.html#pennylane.CRY "pennylane.CRY")(phi, wires[, id]) | The controlled-RY operator |

| [`CRZ`](index.html#pennylane.CRZ "pennylane.CRZ")(phi, wires[, id]) | The controlled-RZ operator |

| [`CRot`](index.html#pennylane.CRot "pennylane.CRot")(phi, theta, omega, wires[, id]) | The controlled-Rot operator |

| [`CSWAP`](index.html#pennylane.CSWAP "pennylane.CSWAP")(wires) | The controlled-swap operator |

| [`CVNeuralNetLayers`](index.html#pennylane.CVNeuralNetLayers "pennylane.CVNeuralNetLayers")(theta\_1, phi\_1, varphi\_1, …) | A sequence of layers of a continuous-variable quantum neural network, as specified in [Killoran et al. (2019)](https://doi.org/10.1103/PhysRevResearch.1.033063). |

| [`CY`](index.html#pennylane.CY "pennylane.CY")(wires) | The controlled-Y operator |

| [`CZ`](index.html#pennylane.CZ "pennylane.CZ")(wires) | The controlled-Z operator |

| [`CatState`](index.html#pennylane.CatState "pennylane.CatState")(a, phi, p, wires[, id]) | Prepares a cat state. |

| [`CircuitGraph`](index.html#pennylane.CircuitGraph "pennylane.CircuitGraph")(ops, obs, wires[, par\_info, …]) | Represents a quantum circuit as a directed acyclic graph. |

| [`ClassicalShadow`](index.html#pennylane.ClassicalShadow "pennylane.ClassicalShadow")(bits, recipes[, wire\_map]) | Class for classical shadow post-processing expectation values, approximate states, and entropies. |

| [`CoherentState`](index.html#pennylane.CoherentState "pennylane.CoherentState")(a, phi, wires[, id]) | Prepares a coherent state. |

| [`CommutingEvolution`](index.html#pennylane.CommutingEvolution "pennylane.CommutingEvolution")(hamiltonian, time[, …]) | Applies the time-evolution operator for a Hamiltonian expressed as a linear combination of mutually commuting Pauli words. |

| [`Configuration`](index.html#pennylane.Configuration "pennylane.Configuration")(name) | Configuration class. |

| [`ControlledAddition`](index.html#pennylane.ControlledAddition "pennylane.ControlledAddition")(s, wires[, id]) | Controlled addition operation. |

| [`ControlledPhase`](index.html#pennylane.ControlledPhase "pennylane.ControlledPhase")(s, wires[, id]) | Controlled phase operation. |

| [`ControlledPhaseShift`](index.html#pennylane.ControlledPhaseShift "pennylane.ControlledPhaseShift")(phi, wires[, id]) | A qubit controlled phase shift. |

| [`ControlledQubitUnitary`](index.html#pennylane.ControlledQubitUnitary "pennylane.ControlledQubitUnitary")(U, control\_wires, …) | Apply an arbitrary fixed unitary to `wires` with control from the `control\_wires`. |

| [`ControlledQutritUnitary`](index.html#pennylane.ControlledQutritUnitary "pennylane.ControlledQutritUnitary")(U, control\_wires, …) | Apply an arbitrary fixed unitary to `wires` with control from the `control\_wires`. |

| [`CrossKerr`](index.html#pennylane.CrossKerr "pennylane.CrossKerr")(kappa, wires[, id]) | Cross-Kerr interaction. |

| [`CubicPhase`](index.html#pennylane.CubicPhase "pennylane.CubicPhase")(gamma, wires[, id]) | Cubic phase shift. |

| [`DepolarizingChannel`](index.html#pennylane.DepolarizingChannel "pennylane.DepolarizingChannel")(p, wires[, id]) | Single-qubit symmetrically depolarizing error channel. |

| [`Device`](index.html#pennylane.Device "pennylane.Device")([wires, shots, analytic]) | Abstract base class for PennyLane devices. |

| [`DeviceError`](index.html#pennylane.DeviceError "pennylane.DeviceError") | Exception raised by a `Device` when it encounters an illegal operation in the quantum circuit. |

| [`DiagonalQubitUnitary`](index.html#pennylane.DiagonalQubitUnitary "pennylane.DiagonalQubitUnitary")(D, wires) | Apply an arbitrary diagonal unitary matrix with a dimension that is a power of two. |

| [`DisplacedSqueezedState`](index.html#pennylane.DisplacedSqueezedState "pennylane.DisplacedSqueezedState")(a, phi\_a, r, phi\_r, wires) | Prepares a displaced squeezed vacuum state. |

| [`Displacement`](index.html#pennylane.Displacement "pennylane.Displacement")(a, phi, wires[, id]) | Phase space displacement. |

| [`DisplacementEmbedding`](index.html#pennylane.DisplacementEmbedding "pennylane.DisplacementEmbedding")(features, wires[, …]) | Encodes \(N\) features into the displacement amplitudes \(r\) or phases \(\phi\) of \(M\) modes, where \(N\leq M\). |

| [`DoubleExcitation`](index.html#pennylane.DoubleExcitation "pennylane.DoubleExcitation")(phi, wires[, id]) | Double excitation rotation. |

| [`DoubleExcitationMinus`](index.html#pennylane.DoubleExcitationMinus "pennylane.DoubleExcitationMinus")(\*params[, wires, id]) | Double excitation rotation with negative phase-shift outside the rotation subspace. |

| [`DoubleExcitationPlus`](index.html#pennylane.DoubleExcitationPlus "pennylane.DoubleExcitationPlus")(phi, wires[, id]) | Double excitation rotation with positive phase-shift outside the rotation subspace. |

| [`ECR`](index.html#pennylane.ECR "pennylane.ECR")(wires) | An echoed RZX(pi/2) gate. |

| [`ExpvalCost`](index.html#pennylane.ExpvalCost "pennylane.ExpvalCost")(ansatz, hamiltonian, device[, …]) | Create a cost function that gives the expectation value of an input Hamiltonian. |

| [`FermiA`](index.html#pennylane.FermiA "pennylane.FermiA")(orbital) | The fermionic annihilation operator \(a\) |

| [`FermiC`](index.html#pennylane.FermiC "pennylane.FermiC")(orbital) | The fermionic creation operator \(a^{\dagger}\) |

| [`FermionicDoubleExcitation`](index.html#pennylane.FermionicDoubleExcitation "pennylane.FermionicDoubleExcitation")(weight[, wires1, …]) | Circuit to exponentiate the tensor product of Pauli matrices representing the double-excitation operator entering the Unitary Coupled-Cluster Singles and Doubles (UCCSD) ansatz. |

| [`FermionicSWAP`](index.html#pennylane.FermionicSWAP "pennylane.FermionicSWAP")(phi, wires[, id]) | Fermionic SWAP rotation. |

| [`FermionicSingleExcitation`](index.html#pennylane.FermionicSingleExcitation "pennylane.FermionicSingleExcitation")(weight[, wires, id]) | Circuit to exponentiate the tensor product of Pauli matrices representing the single-excitation operator entering the Unitary Coupled-Cluster Singles and Doubles (UCCSD) ansatz. |

| [`FlipSign`](index.html#pennylane.FlipSign "pennylane.FlipSign")(n, wires[, id]) | Flips the sign of a given basis state. |

| [`FockDensityMatrix`](index.html#pennylane.FockDensityMatrix "pennylane.FockDensityMatrix")(state, wires[, id]) | Prepare subsystems using the given density matrix in the Fock basis. |

| [`FockState`](index.html#pennylane.FockState "pennylane.FockState")(n, wires[, id]) | Prepares a single Fock state. |

| [`FockStateProjector`](index.html#pennylane.FockStateProjector "pennylane.FockStateProjector")(n, wires[, id]) | The number state observable \(\ket{n}\bra{n}\). |

| [`FockStateVector`](index.html#pennylane.FockStateVector "pennylane.FockStateVector")(state, wires[, id]) | Prepare subsystems using the given ket vector in the Fock basis. |

| [`GateFabric`](index.html#pennylane.GateFabric "pennylane.GateFabric")(weights, wires, init\_state[, …]) | Implements a local, expressive, and quantum-number-preserving ansatz proposed by [Anselmetti et al. (2021)](https://doi.org/10.1088/1367-2630/ac2cb3). |

| [`GaussianState`](index.html#pennylane.GaussianState "pennylane.GaussianState")(V, r, wires[, id]) | Prepare subsystems in a given Gaussian state. |

| [`GellMann`](index.html#pennylane.GellMann "pennylane.GellMann")(wires[, index, id]) | The Gell-Mann observables for qutrits |

| [`GeneralizedAmplitudeDamping`](index.html#pennylane.GeneralizedAmplitudeDamping "pennylane.GeneralizedAmplitudeDamping")(gamma, p, wires) | Single-qubit generalized amplitude damping error channel. |

| [`GradientDescentOptimizer`](index.html#pennylane.GradientDescentOptimizer "pennylane.GradientDescentOptimizer")([stepsize]) | Basic gradient-descent optimizer. |

| [`GroverOperator`](index.html#pennylane.GroverOperator "pennylane.GroverOperator")([wires, work\_wires, id]) | Performs the Grover Diffusion Operator. |

| [`Hadamard`](index.html#pennylane.Hadamard "pennylane.Hadamard")(wires) | The Hadamard operator |

| [`Hamiltonian`](index.html#pennylane.Hamiltonian "pennylane.Hamiltonian")(coeffs, observables[, simplify, …]) | Operator representing a Hamiltonian. |

| [`Hermitian`](index.html#pennylane.Hermitian "pennylane.Hermitian")(A, wires[, id]) | An arbitrary Hermitian observable. |

| [`HilbertSchmidt`](index.html#pennylane.HilbertSchmidt "pennylane.HilbertSchmidt")(\*params, v\_function, v\_wires, …) | Create a Hilbert-Schmidt template that can be used to compute the Hilbert-Schmidt Test (HST). |

| [`IQPEmbedding`](index.html#pennylane.IQPEmbedding "pennylane.IQPEmbedding")(features, wires[, n\_repeats, …]) | Encodes \(n\) features into \(n\) qubits using diagonal gates of an IQP circuit. |

| [`ISWAP`](index.html#pennylane.ISWAP "pennylane.ISWAP")(wires) | The i-swap operator |

| [`Identity`](index.html#pennylane.Identity "pennylane.Identity")(wires) | The identity observable \(\I\). |

| [`IntegerComparator`](index.html#pennylane.IntegerComparator "pennylane.IntegerComparator")(value, geq, wires) | Apply a controlled Pauli X gate using integer comparison as the condition. |

| [`Interferometer`](index.html#pennylane.Interferometer "pennylane.Interferometer")(theta, phi, varphi, wires[, …]) | General linear interferometer, an array of beamsplitters and phase shifters. |

| [`InterferometerUnitary`](index.html#pennylane.InterferometerUnitary "pennylane.InterferometerUnitary")(U, wires[, id]) | A linear interferometer transforming the bosonic operators according to the unitary matrix \(U\). |

| [`IsingXX`](index.html#pennylane.IsingXX "pennylane.IsingXX")(phi, wires[, id]) | Ising XX coupling gate |

| [`IsingXY`](index.html#pennylane.IsingXY "pennylane.IsingXY")(phi, wires[, id]) | Ising (XX + YY) coupling gate |

| [`IsingYY`](index.html#pennylane.IsingYY "pennylane.IsingYY")(phi, wires[, id]) | Ising YY coupling gate |

| [`IsingZZ`](index.html#pennylane.IsingZZ "pennylane.IsingZZ")(phi, wires[, id]) | Ising ZZ coupling gate |

| [`Kerr`](index.html#pennylane.Kerr "pennylane.Kerr")(kappa, wires[, id]) | Kerr interaction. |

| [`LocalHilbertSchmidt`](index.html#pennylane.LocalHilbertSchmidt "pennylane.LocalHilbertSchmidt")(\*params, v\_function, …) | Create a Local Hilbert-Schmidt template that can be used to compute the Local Hilbert-Schmidt Test (LHST). |

| [`MERA`](index.html#pennylane.MERA "pennylane.MERA")(wires, n\_block\_wires, block, n\_params\_block) | The MERA template broadcasts an input circuit across many wires following the architecture of a multi-scale entanglement renormalization ansatz tensor network. |

| [`MPS`](index.html#pennylane.MPS "pennylane.MPS")(wires, n\_block\_wires, block, n\_params\_block) | The MPS template broadcasts an input circuit across many wires following the architecture of a Matrix Product State tensor network. |

| [`MomentumOptimizer`](index.html#pennylane.MomentumOptimizer "pennylane.MomentumOptimizer")([stepsize, momentum]) | Gradient-descent optimizer with momentum. |

| [`MottonenStatePreparation`](index.html#pennylane.MottonenStatePreparation "pennylane.MottonenStatePreparation")(state\_vector, wires) | Prepares an arbitrary state on the given wires using a decomposition into gates developed by [Möttönen et al. (2004)](https://arxiv.org/abs/quant-ph/0407010). |

| [`MultiControlledX`](index.html#pennylane.MultiControlledX "pennylane.MultiControlledX")(control\_wires, wires, …) | Apply a Pauli X gate controlled on an arbitrary computational basis state. |

| [`MultiRZ`](index.html#pennylane.MultiRZ "pennylane.MultiRZ")(theta[, wires, id]) | Arbitrary multi Z rotation. |

| [`NesterovMomentumOptimizer`](index.html#pennylane.NesterovMomentumOptimizer "pennylane.NesterovMomentumOptimizer")([stepsize, momentum]) | Gradient-descent optimizer with Nesterov momentum. |

| [`NumberOperator`](index.html#pennylane.NumberOperator "pennylane.NumberOperator")(wires) | The photon number observable \(\langle \hat{n}\rangle\). |

| [`OrbitalRotation`](index.html#pennylane.OrbitalRotation "pennylane.OrbitalRotation")(phi, wires[, id]) | Spin-adapted spatial orbital rotation. |

| [`P`](index.html#pennylane.P "pennylane.P")(wires) | The momentum quadrature observable \(\hat{p}\). |

| [`PCPhase`](index.html#pennylane.PCPhase "pennylane.PCPhase")(phi, dim, wires) | A projector-controlled phase gate. |

| [`PSWAP`](index.html#pennylane.PSWAP "pennylane.PSWAP")(phi, wires[, id]) | Phase SWAP gate |

| [`ParticleConservingU1`](index.html#pennylane.ParticleConservingU1 "pennylane.ParticleConservingU1")(weights, wires[, …]) | Implements the heuristic VQE ansatz for quantum chemistry simulations using the particle-conserving gate \(U\_{1,\mathrm{ex}}\) proposed by Barkoutsos *et al.* in [arXiv:1805.04340](https://arxiv.org/abs/1805.04340). |

| [`ParticleConservingU2`](index.html#pennylane.ParticleConservingU2 "pennylane.ParticleConservingU2")(weights, wires[, …]) | Implements the heuristic VQE ansatz for Quantum Chemistry simulations using the particle-conserving entangler \(U\_\mathrm{ent}(\vec{\theta}, \vec{\phi})\) proposed in [arXiv:1805.04340](https://arxiv.org/abs/1805.04340).

 |

| [`PauliError`](index.html#pennylane.PauliError "pennylane.PauliError")(operators, p[, wires, id]) | Pauli operator error channel for an arbitrary number of qubits. |

| [`PauliRot`](index.html#pennylane.PauliRot "pennylane.PauliRot")(theta, pauli\_word[, wires, id]) | Arbitrary Pauli word rotation. |

| [`PauliX`](index.html#pennylane.PauliX "pennylane.PauliX")(wires) | The Pauli X operator |

| [`PauliY`](index.html#pennylane.PauliY "pennylane.PauliY")(wires) | The Pauli Y operator |

| [`PauliZ`](index.html#pennylane.PauliZ "pennylane.PauliZ")(wires) | The Pauli Z operator |

| [`Permute`](index.html#pennylane.Permute "pennylane.Permute")(permutation, wires[, id]) | Applies a permutation to a set of wires. |

| [`PhaseDamping`](index.html#pennylane.PhaseDamping "pennylane.PhaseDamping")(gamma, wires[, id]) | Single-qubit phase damping error channel. |

| [`PhaseFlip`](index.html#pennylane.PhaseFlip "pennylane.PhaseFlip")(p, wires[, id]) | Single-qubit bit flip (Pauli \(Z\)) error channel. |

| [`PhaseShift`](index.html#pennylane.PhaseShift "pennylane.PhaseShift")(phi, wires[, id]) | Arbitrary single qubit local phase shift |

| [`PolyXP`](index.html#pennylane.PolyXP "pennylane.PolyXP")(q, wires[, id]) | An arbitrary second-order polynomial observable. |

| [`Projector`](index.html#pennylane.Projector "pennylane.Projector")(state, wires[, id]) | Observable corresponding to the state projector \(P=\ket{\phi}\bra{\phi}\). |

| [`QAOAEmbedding`](index.html#pennylane.QAOAEmbedding "pennylane.QAOAEmbedding")(features, weights, wires[, …]) | Encodes \(N\) features into \(n>N\) qubits, using a layered, trainable quantum circuit that is inspired by the QAOA ansatz. |

| [`QFT`](index.html#pennylane.QFT "pennylane.QFT")(wires) | Apply a quantum Fourier transform (QFT). |

| [`QNGOptimizer`](index.html#pennylane.QNGOptimizer "pennylane.QNGOptimizer")([stepsize, approx, lam]) | Optimizer with adaptive learning rate, via calculation of the diagonal or block-diagonal approximation to the Fubini-Study metric tensor. |

| [`QNSPSAOptimizer`](index.html#pennylane.QNSPSAOptimizer "pennylane.QNSPSAOptimizer")([stepsize, regularization, …]) | Quantum natural SPSA (QNSPSA) optimizer. |

| [`QNode`](index.html#pennylane.QNode "pennylane.QNode")(func, device[, interface, …]) | Represents a quantum node in the hybrid computational graph. |

| [`QSVT`](index.html#pennylane.QSVT "pennylane.QSVT")(UA,projectors) | Implements the [quantum singular value transformation](https://arxiv.org/abs/1806.01838) (QSVT) circuit. |

| [`QuadOperator`](index.html#pennylane.QuadOperator "pennylane.QuadOperator")(phi, wires[, id]) | The generalized quadrature observable \(\x\_\phi = \x cos\phi+\p\sin\phi\). |

| [`QuadP`](index.html#pennylane.QuadP "pennylane.QuadP")(wires) | The momentum quadrature observable \(\hat{p}\). |

| [`QuadX`](index.html#pennylane.QuadX "pennylane.QuadX")(wires) | The position quadrature observable \(\hat{x}\). |

| [`QuadraticPhase`](index.html#pennylane.QuadraticPhase "pennylane.QuadraticPhase")(s, wires[, id]) | Quadratic phase shift. |

| [`QuantumFunctionError`](index.html#pennylane.QuantumFunctionError "pennylane.QuantumFunctionError") | Exception raised when an illegal operation is defined in a quantum function. |

| [`QuantumMonteCarlo`](index.html#pennylane.QuantumMonteCarlo "pennylane.QuantumMonteCarlo")(probs, func, target\_wires, …) | Performs the [quantum Monte Carlo estimation](https://arxiv.org/abs/1805.00109) algorithm. |

| [`QuantumPhaseEstimation`](index.html#pennylane.QuantumPhaseEstimation "pennylane.QuantumPhaseEstimation")(unitary[, …]) | Performs the [quantum phase estimation](https://en.wikipedia.org/wiki/Quantum_phase_estimation_algorithm) circuit. |

| [`QubitCarry`](index.html#pennylane.QubitCarry "pennylane.QubitCarry")(wires) | Apply the `QubitCarry` operation to four input wires. |

| [`QubitChannel`](index.html#pennylane.QubitChannel "pennylane.QubitChannel")(K\_list[, wires, id]) | Apply an arbitrary fixed quantum channel. |

| [`QubitDensityMatrix`](index.html#pennylane.QubitDensityMatrix "pennylane.QubitDensityMatrix")(state, wires) | Prepare subsystems using the given density matrix. |

| [`QubitDevice`](index.html#pennylane.QubitDevice "pennylane.QubitDevice")([wires, shots, r\_dtype, …]) | Abstract base class for PennyLane qubit devices. |

| [`QubitStateVector`](index.html#pennylane.QubitStateVector "pennylane.QubitStateVector")(state, wires[, id]) |  |

| [`QubitSum`](index.html#pennylane.QubitSum "pennylane.QubitSum")(wires) | Apply a `QubitSum` operation on three input wires. |

| [`QubitUnitary`](index.html#pennylane.QubitUnitary "pennylane.QubitUnitary")(U, wires) | Apply an arbitrary unitary matrix with a dimension that is a power of two. |

| [`QueuingManager`](index.html#pennylane.QueuingManager "pennylane.QueuingManager")() | Singleton global entry point for managing active recording contexts. |

| [`QutritBasisState`](index.html#pennylane.QutritBasisState "pennylane.QutritBasisState")(n, wires) | Prepares a single computational basis state for a qutrit system. |

| [`QutritBasisStatePreparation`](index.html#pennylane.QutritBasisStatePreparation "pennylane.QutritBasisStatePreparation")(basis\_state, wires) | Prepares a basis state on the given wires using a sequence of TShift gates. |

| [`QutritDevice`](index.html#pennylane.QutritDevice "pennylane.QutritDevice")([wires, shots, r\_dtype, …]) | Abstract base class for PennyLane qutrit devices. |

| [`QutritUnitary`](index.html#pennylane.QutritUnitary "pennylane.QutritUnitary")(\*params, wires) | Apply an arbitrary, fixed unitary matrix. |

| [`RMSPropOptimizer`](index.html#pennylane.RMSPropOptimizer "pennylane.RMSPropOptimizer")([stepsize, decay, eps]) | Root mean squared propagation optimizer. |

| [`RX`](index.html#pennylane.RX "pennylane.RX")(phi, wires[, id]) | The single qubit X rotation |

| [`RY`](index.html#pennylane.RY "pennylane.RY")(phi, wires[, id]) | The single qubit Y rotation |

| [`RZ`](index.html#pennylane.RZ "pennylane.RZ")(phi, wires[, id]) | The single qubit Z rotation |

| [`RandomLayers`](index.html#pennylane.RandomLayers "pennylane.RandomLayers")(weights, wires[, ratio\_imprim, …]) | Layers of randomly chosen single qubit rotations and 2-qubit entangling gates, acting on randomly chosen qubits. |

| [`ResetError`](index.html#pennylane.ResetError "pennylane.ResetError")(p0, p1, wires[, id]) | Single-qubit Reset error channel. |

| [`RiemannianGradientOptimizer`](index.html#pennylane.RiemannianGradientOptimizer "pennylane.RiemannianGradientOptimizer")(circuit[, …]) | Riemannian gradient optimizer. |

| [`Rot`](index.html#pennylane.Rot "pennylane.Rot")(phi, theta, omega, wires[, id]) | Arbitrary single qubit rotation |

| [`Rotation`](index.html#pennylane.Rotation "pennylane.Rotation")(phi, wires[, id]) | Phase space rotation. |

| [`RotoselectOptimizer`](index.html#pennylane.RotoselectOptimizer "pennylane.RotoselectOptimizer")([possible\_generators]) | Rotoselect gradient-free optimizer. |

| [`RotosolveOptimizer`](index.html#pennylane.RotosolveOptimizer "pennylane.RotosolveOptimizer")([substep\_optimizer, …]) | Rotosolve gradient-free optimizer. |

| [`S`](index.html#pennylane.S "pennylane.S")(wires) | The single-qubit phase gate |

| [`SISWAP`](index.html#pennylane.SISWAP "pennylane.SISWAP")(wires) | The square root of i-swap operator. |

| [`SPSAOptimizer`](index.html#pennylane.SPSAOptimizer "pennylane.SPSAOptimizer")([maxiter, alpha, gamma, c, A, a]) | The Simultaneous Perturbation Stochastic Approximation method (SPSA) is a stochastic approximation algorithm for optimizing cost functions whose evaluation may involve noise. |

| [`SQISW`](index.html#pennylane.SQISW "pennylane.SQISW") | alias of `pennylane.ops.qubit.non\_parametric\_ops.SISWAP` |

| [`SWAP`](index.html#pennylane.SWAP "pennylane.SWAP")(wires) | The swap operator |

| [`SX`](index.html#pennylane.SX "pennylane.SX")(wires) | The single-qubit Square-Root X operator. |

| [`Select`](index.html#pennylane.Select "pennylane.Select")(ops, control[, id]) | Applies specific input operations depending on the state of the designated control qubits. |

| [`ShotAdaptiveOptimizer`](index.html#pennylane.ShotAdaptiveOptimizer "pennylane.ShotAdaptiveOptimizer")(min\_shots[, …]) | Optimizer where the shot rate is adaptively calculated using the variances of the parameter-shift gradient. |

| [`SimplifiedTwoDesign`](index.html#pennylane.SimplifiedTwoDesign "pennylane.SimplifiedTwoDesign")(initial\_layer\_weights, …) | Layers consisting of a simplified 2-design architecture of Pauli-Y rotations and controlled-Z entanglers proposed in [Cerezo et al. (2021)](https://doi.org/10.1038/s41467-021-21728-w). |

| [`SingleExcitation`](index.html#pennylane.SingleExcitation "pennylane.SingleExcitation")(phi, wires[, id]) | Single excitation rotation. |

| [`SingleExcitationMinus`](index.html#pennylane.SingleExcitationMinus "pennylane.SingleExcitationMinus")(phi, wires[, id]) | Single excitation rotation with negative phase-shift outside the rotation subspace. |

| [`SingleExcitationPlus`](index.html#pennylane.SingleExcitationPlus "pennylane.SingleExcitationPlus")(phi, wires[, id]) | Single excitation rotation with positive phase-shift outside the rotation subspace. |

| [`Snapshot`](index.html#pennylane.Snapshot "pennylane.Snapshot")([tag]) | The Snapshot operation saves the internal simulator state at specific execution steps of a quantum function. |

| [`SparseHamiltonian`](index.html#pennylane.SparseHamiltonian "pennylane.SparseHamiltonian")(H[, wires, id]) | A Hamiltonian represented directly as a sparse matrix in Compressed Sparse Row (CSR) format. |

| [`SpecialUnitary`](index.html#pennylane.SpecialUnitary "pennylane.SpecialUnitary")(theta, wires[, id]) | Gate from the group \(SU(N)\) with \(N=2^n\) for \(n\) qubits. |

| [`SqueezedState`](index.html#pennylane.SqueezedState "pennylane.SqueezedState")(r, phi, wires[, id]) | Prepares a squeezed vacuum state. |

| [`Squeezing`](index.html#pennylane.Squeezing "pennylane.Squeezing")(r, phi, wires[, id]) | Phase space squeezing. |

| [`SqueezingEmbedding`](index.html#pennylane.SqueezingEmbedding "pennylane.SqueezingEmbedding")(features, wires[, …]) | Encodes \(N\) features into the squeezing amplitudes \(r \geq 0\) or phases \(\phi \in [0, 2\pi)\) of \(M\) modes, where \(N\leq M\). |

| [`StatePrep`](index.html#pennylane.StatePrep "pennylane.StatePrep")(state, wires) | Prepare subsystems using the given ket vector in the computational basis. |

| [`StronglyEntanglingLayers`](index.html#pennylane.StronglyEntanglingLayers "pennylane.StronglyEntanglingLayers")(weights, wires[, …]) | Layers consisting of single qubit rotations and entanglers, inspired by the circuit-centric classifier design [arXiv:1804.00633](https://arxiv.org/abs/1804.00633). |

| [`T`](index.html#pennylane.T "pennylane.T")(wires) | The single-qubit T gate |

| [`TAdd`](index.html#pennylane.TAdd "pennylane.TAdd")(wires) | The 2-qutrit controlled add gate |

| [`TClock`](index.html#pennylane.TClock "pennylane.TClock")(wires) | Ternary Clock gate |

| [`THadamard`](index.html#pennylane.THadamard "pennylane.THadamard")(wires, subspace) | The ternary Hadamard operator |

| [`THermitian`](index.html#pennylane.THermitian "pennylane.THermitian")(A, wires[, id]) | An arbitrary Hermitian observable for qutrits. |

| [`TRX`](index.html#pennylane.TRX "pennylane.TRX")(phi, wires[, subspace, id]) | The single qutrit X rotation |

| [`TRY`](index.html#pennylane.TRY "pennylane.TRY")(phi, wires[, subspace, id]) | The single qutrit Y rotation |

| [`TRZ`](index.html#pennylane.TRZ "pennylane.TRZ")(phi, wires[, subspace, id]) | The single qutrit Z rotation |

| [`TSWAP`](index.html#pennylane.TSWAP "pennylane.TSWAP")(wires) | The ternary swap operator. |

| [`TShift`](index.html#pennylane.TShift "pennylane.TShift")(wires) | The qutrit shift operator |

| [`TTN`](index.html#pennylane.TTN "pennylane.TTN")(wires, n\_block\_wires, block, n\_params\_block) | The TTN template broadcasts an input circuit across many wires following the architecture of a tree tensor network. |

| [`TensorN`](index.html#pennylane.TensorN "pennylane.TensorN")([wires]) | The tensor product of the [`NumberOperator`](index.html#pennylane.NumberOperator "pennylane.NumberOperator") acting on different wires. |

| [`ThermalRelaxationError`](index.html#pennylane.ThermalRelaxationError "pennylane.ThermalRelaxationError")(pe, t1, t2, tq, wires) | Thermal relaxation error channel. |

| [`ThermalState`](index.html#pennylane.ThermalState "pennylane.ThermalState")(nbar, wires[, id]) | Prepares a thermal state. |

| [`Toffoli`](index.html#pennylane.Toffoli "pennylane.Toffoli")(wires) | Toffoli (controlled-controlled-X) gate. |

| [`Tracker`](index.html#pennylane.Tracker "pennylane.Tracker")([dev, callback, persistent]) | This class stores information about device executions and allows users to interact with that data upon individual executions and batches, even within parameter-shift gradients and optimization steps. |

| [`TwoLocalSwapNetwork`](index.html#pennylane.TwoLocalSwapNetwork "pennylane.TwoLocalSwapNetwork")(wires[, acquaintances, …]) | Apply two-local gate operations using a canonical 2-complete linear (2-CCL) swap network. |

| [`TwoModeSqueezing`](index.html#pennylane.TwoModeSqueezing "pennylane.TwoModeSqueezing")(r, phi, wires[, id]) | Phase space two-mode squeezing. |

| [`U1`](index.html#pennylane.U1 "pennylane.U1")(phi, wires[, id]) | U1 gate. |

| [`U2`](index.html#pennylane.U2 "pennylane.U2")(phi, delta, wires[, id]) | U2 gate. |

| [`U3`](index.html#pennylane.U3 "pennylane.U3")(theta, phi, delta, wires[, id]) | Arbitrary single qubit unitary. |

| [`UCCSD`](index.html#pennylane.UCCSD "pennylane.UCCSD")(weights, wires[, s\_wires, d\_wires, …]) | Implements the Unitary Coupled-Cluster Singles and Doubles (UCCSD) ansatz. |

| [`WireCut`](index.html#pennylane.WireCut "pennylane.WireCut")(wires) | The wire cut operation, used to manually mark locations for wire cuts. |

| [`X`](index.html#pennylane.X "pennylane.X")(wires) | The position quadrature observable \(\hat{x}\). |

| [`batch\_transform`](index.html#pennylane.batch_transform "pennylane.batch_transform")(\*args, \*\*kwargs) | Class for registering a tape transform that takes a tape, and outputs a batch of tapes to be independently executed on a quantum device. |

| [`grad`](index.html#pennylane.grad "pennylane.grad")(fun[, argnum]) | Returns the gradient as a callable function of (functions of) QNodes. |

| [`kUpCCGSD`](index.html#pennylane.kUpCCGSD "pennylane.kUpCCGSD")(weights, wires[, k, delta\_sz, …]) | Implements the k-Unitary Pair Coupled-Cluster Generalized Singles and Doubles (k-UpCCGSD) ansatz. |

| [`op\_transform`](index.html#pennylane.op_transform "pennylane.op_transform")(\*args, \*\*kwargs) | Convert a function that applies to operators into a functional transform. |

| [`single\_tape\_transform`](index.html#pennylane.single_tape_transform "pennylane.single_tape_transform")(transform\_fn) | For registering a tape transform that takes a tape and outputs a single new tape. |

#### Variables[¶](#variables "Permalink to this headline")

### qml.data[¶](#module-pennylane.data "Permalink to this headline")

The data subpackage provides functionality to access, store and manipulate [quantum datasets](https://pennylane.ai/datasets).

Note

For more details on using datasets, please see the

[quantum datasets quickstart guide](index.html#document-introduction/data).

#### Overview[¶](#overview "Permalink to this headline")

Datasets are generally stored and accessed using the [`Dataset`](index.html#pennylane.data.Dataset "pennylane.data.Dataset") class.

Pre-computed datasets are available for download and can be accessed using the [`load()`](index.html#pennylane.data.load "pennylane.data.load") or

[`load\_interactive()`](index.html#pennylane.data.load_interactive "pennylane.data.load_interactive") functions.

Additionally, users can easily create, write to disk, and read custom datasets using functions within the

[`Dataset`](index.html#pennylane.data.Dataset "pennylane.data.Dataset") class.

| [`attribute`](index.html#pennylane.data.attribute "pennylane.data.attribute")(val[, doc]) | Creates a dataset attribute that contains both a value and associated metadata. |

| [`field`](index.html#pennylane.data.field "pennylane.data.field")([attribute\_type, doc, py\_type]) | Used to define fields on a declarative Dataset. |

| [`Dataset`](index.html#pennylane.data.Dataset "pennylane.data.Dataset")([bind, data\_name, identifiers]) | Base class for Datasets. |

| [`DatasetNotWriteableError`](index.html#pennylane.data.DatasetNotWriteableError "pennylane.data.DatasetNotWriteableError")(bind) | Exception raised when attempting to set an attribute on a dataset whose underlying file is not writeable. |

| [`load`](index.html#pennylane.data.load "pennylane.data.load")(data\_name[, attributes, folder\_path, …]) | Downloads the data if it is not already present in the directory and returns it as a list of [`Dataset`](index.html#pennylane.data.Dataset "pennylane.data.Dataset") objects. |

| [`load\_interactive`](index.html#pennylane.data.load_interactive "pennylane.data.load_interactive")() | Download a dataset using an interactive load prompt. |

| [`list\_attributes`](index.html#pennylane.data.list_attributes "pennylane.data.list_attributes")(data\_name) | List the attributes that exist for a specific `data\_name`. |

| [`list\_datasets`](index.html#pennylane.data.list_datasets "pennylane.data.list_datasets")() | Returns a dictionary of the available datasets. |

In addition, various dataset types are provided

| [`AttributeInfo`](index.html#pennylane.data.AttributeInfo "pennylane.data.AttributeInfo")([attrs\_bind]) | Contains metadata that may be assigned to a dataset attribute. |

| [`DatasetAttribute`](index.html#pennylane.data.DatasetAttribute "pennylane.data.DatasetAttribute")([value, info, bind, …]) | The DatasetAttribute class provides an interface for converting Python objects to and from a HDF5 array or Group. |

| [`DatasetArray`](index.html#pennylane.data.DatasetArray "pennylane.data.DatasetArray")([value, info, bind, parent\_and\_key]) | Attribute type for objects that implement the Array protocol, including numpy arrays and pennylane.math.tensor. |

| [`DatasetScalar`](index.html#pennylane.data.DatasetScalar "pennylane.data.DatasetScalar")([value, info, bind, …]) | Attribute type for numbers. |

| [`DatasetString`](index.html#pennylane.data.DatasetString "pennylane.data.DatasetString")([value, info, bind, …]) | Attribute type for strings. |

| [`DatasetList`](index.html#pennylane.data.DatasetList "pennylane.data.DatasetList")([value, info, bind, parent\_and\_key]) | Provides a list-like collection type for Dataset Attributes. |

| [`DatasetDict`](index.html#pennylane.data.DatasetDict "pennylane.data.DatasetDict")([value, info, bind, parent\_and\_key]) | Provides a dict-like collection for Dataset attribute types. |

| [`DatasetOperator`](index.html#pennylane.data.DatasetOperator "pennylane.data.DatasetOperator")([value, info, bind, …]) | `DatasetAttribute` for `pennylane.operation.Operator` classes. |

| [`DatasetNone`](index.html#pennylane.data.DatasetNone "pennylane.data.DatasetNone")([value, info, bind, parent\_and\_key]) | Datasets type for ‘None’ values. |

| [`DatasetMolecule`](index.html#pennylane.data.DatasetMolecule "pennylane.data.DatasetMolecule")([value, info, bind, …]) | Attribute type for `pennylane.qchem.Molecule`. |

| [`DatasetSparseArray`](index.html#pennylane.data.DatasetSparseArray "pennylane.data.DatasetSparseArray")([value, info, bind, …]) | Attribute type for Scipy sparse arrays. |

| [`DatasetJSON`](index.html#pennylane.data.DatasetJSON "pennylane.data.DatasetJSON")([value, info, bind, parent\_and\_key]) | Dataset type for JSON-serializable data. |

| [`DatasetTuple`](index.html#pennylane.data.DatasetTuple "pennylane.data.DatasetTuple")([value, info, bind, parent\_and\_key]) | Type for tuples. |

#### Datasets[¶](#datasets "Permalink to this headline")

The [`Dataset`](index.html#pennylane.data.Dataset "pennylane.data.Dataset") class provides a portable storage format for information describing a physical

system and its evolution. For example, a dataset for an arbitrary quantum system could have

a Hamiltonian, its ground state, and an efficient state-preparation circuit for that state. Datasets

can contain a range of object types, including:

* `numpy.ndarray`

* any numeric type

* [`Molecule`](index.html#pennylane.qchem.Molecule "pennylane.qchem.Molecule")

* most [`Operator`](index.html#pennylane.operation.Operator "pennylane.operation.Operator") types

* `list` of any supported type

* `dict` of any supported type, as long as the keys are strings

For more details on using datasets, please see the

[quantum datasets quickstart guide](index.html#document-introduction/data).

#### Creating a Dataset[¶](#creating-a-dataset "Permalink to this headline")

To create a new dataset in-memory, initialize a new [`Dataset`](index.html#pennylane.data.Dataset "pennylane.data.Dataset") with the desired attributes:

```

>>> hamiltonian = qml.Hamiltonian([1., 1.], [qml.PauliZ(wires=0), qml.PauliZ(wires=1)])

>>> eigvals, eigvecs = np.linalg.eigh(qml.matrix(hamiltonian))

>>> dataset = qml.data.Dataset(

...   hamiltonian = hamiltonian,

...   eigen = {"eigvals": eigvals, "eigvecs": eigvecs}

... )

>>> dataset.hamiltonian

(1.0) [Z0]

+ (1.0) [Z1]

>>> dataset.eigen

{'eigvals': array([-2., 0., 0., 2.]),

'eigvecs': array([[0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j],

 [0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j],

 [0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j],

 [1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j]])}

```

Attributes can also be assigned to the instance after creation:

```

>>> dataset.ground\_state = np.transpose(eigvecs)[np.argmin(eigvals)]

>>> dataset.ground\_state

array([0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j])

```

#### Reading and Writing Datasets[¶](#reading-and-writing-datasets "Permalink to this headline")

Datasets can be saved to disk for later use. Datasets use the HDF5 format for serialization,

which uses the ‘.h5’ file extension.

To save a dataset, use the [`Dataset.write()`](index.html#pennylane.data.Dataset.write "pennylane.data.Dataset.write") method:

```

>>> my\_dataset = Dataset(...)

>>> my\_dataset.write("~/datasets/my\_dataset.h5")

```

To open a dataset from a file, use [`Dataset.open()`](index.html#pennylane.data.Dataset.open "pennylane.data.Dataset.open") class method:

```

>>> my\_dataset = Dataset.open("~/datasets/my\_dataset.h5", mode="r")

```

The `mode` argument follow the standard library convention — `r` for

reading, `w-` and `w` for create and overwrite, and ‘a’ for editing.

`open()` can be used to create a new dataset directly on disk:

```

>>> new\_dataset = Dataset.open("~/datasets/new\_datasets.h5", mode="w")

```

By default, any changes made to an opened dataset will be committed directly to the file, which will fail

if the file is opened read-only. The `"copy"` mode can be used to load the dataset into memory and detach

it from the file:

```

>>> my\_dataset = Dataset.open("~/dataset/my\_dataset/h5", mode="copy")

>>> my\_dataset.new\_attribute = "abc"

```

#### Attribute Metadata[¶](#attribute-metadata "Permalink to this headline")

Dataset attributes can also contain additional metadata, such as docstrings. The [`attribute()`](index.html#pennylane.data.attribute "pennylane.data.attribute")

function can be used to attach metadata on assignment or initialization.

```

>>> hamiltonian = qml.Hamiltonian([1., 1.], [qml.PauliZ(wires=0), qml.PauliZ(wires=1)])

>>> eigvals, eigvecs = np.linalg.eigh(qml.matrix(hamiltonian))

>>> dataset = qml.data.Dataset(hamiltonian = qml.data.attribute(

...     hamiltonian,

...     doc="The hamiltonian of the system"))

>>> dataset.eigen = qml.data.attribute(

...     {"eigvals": eigvals, "eigvecs": eigvecs},

...     doc="Eigenvalues and eigenvectors of the hamiltonain")

```

This metadata can then be accessed using the [`Dataset.attr\_info()`](index.html#pennylane.data.Dataset.attr_info "pennylane.data.Dataset.attr_info") mapping:

```

>>> dataset.attr\_info["eigen"]["doc"]

'Eigenvalues and eigenvectors of the hamiltonain'

```

#### Declarative API[¶](#declarative-api "Permalink to this headline")

When creating datasets to model a physical system, it is common to collect the same data for

a system under different conditions or assumptions. For example, a collection of datasets describing

a quantum oscillator, which contains the first 1000 energy levels for different masses and force constants.

The datasets declarative API allows us to create subclasses

of [`Dataset`](index.html#pennylane.data.Dataset "pennylane.data.Dataset") that define the required attributes, or ‘fields’, and

their associated type and documentation:

```

class QuantumOscillator(qml.data.Dataset, data\_name="quantum\_oscillator", identifiers=["mass", "force\_constant"]):

 """Dataset describing a quantum oscillator."""

    mass: float = qml.data.field(doc = "The mass of the particle")

    force\_constant: float = qml.data.field(doc = "The force constant of the oscillator")

    hamiltonian: qml.Hamiltonian = qml.data.field(doc = "The hamiltonian of the particle")

    energy\_levels: np.ndarray = qml.data.field(doc = "The first 1000 energy levels of the system")

```

The `data\_name` keyword specifies a category or descriptive name for the dataset type, and the `identifiers`

keyword to the class is used to specify fields that function as parameters, i.e they determine the behaviour

of the system.

When a `QuantumOscillator` dataset is created, its attributes will have the documentation from the field

definition:

```

>>> dataset = QuantumOscillator(

...     mass=1,

...     force\_constant=0.5,

...     hamiltonian=qml.PauliX(0),

...     energy\_levels=np.array([0.1, 0.2])

... )

>>> dataset.attr\_info["mass"]["doc"]

'The mass of the particle'

```

### qml.drawer[¶](#qml-drawer "Permalink to this headline")

The `drawer` module contains the code for generating visuals

of circuits.

This module provides the circuit drawing functionality used to display circuits visually.

#### Functions[¶](#functions "Permalink to this headline")

| [`draw`](index.html#pennylane.drawer.draw "pennylane.drawer.draw")(qnode[, wire\_order, show\_all\_wires, …]) | Create a function that draws the given qnode or quantum function. |

| [`draw\_mpl`](index.html#pennylane.drawer.draw_mpl "pennylane.drawer.draw_mpl")(qnode[, wire\_order, …]) | Draw a qnode with matplotlib |

| [`tape\_mpl`](index.html#pennylane.drawer.tape_mpl "pennylane.drawer.tape_mpl")(tape[, wire\_order, show\_all\_wires, …]) | Produces a matplotlib graphic from a tape. |

| [`tape\_text`](index.html#pennylane.drawer.tape_text "pennylane.drawer.tape_text")(tape[, wire\_order, …]) | Text based diagram for a Quantum Tape. |

#### Classes[¶](#classes "Permalink to this headline")

| [`MPLDrawer`](index.html#pennylane.drawer.MPLDrawer "pennylane.drawer.MPLDrawer")(n\_layers, n\_wires[, wire\_options, …]) | Allows easy creation of graphics representing circuits with matplotlib |

##### Styling Matplotlib Circuit Graphics[¶](#styling-matplotlib-circuit-graphics "Permalink to this headline")

The `drawer` module provides two functions for modifying the style of matplotlib

graphics, such as those generated by `qml.draw\_mpl`. The `qml.drawer.use\_style`

function modifies the `plt.rcParams` global styling variable. Any styling can

be reset with `qml.drawer.use\_style('black\_white')`.

| [`available\_styles`](index.html#pennylane.drawer.available_styles "pennylane.drawer.available_styles")() | Get available style specification strings. |

| [`use\_style`](index.html#pennylane.drawer.use_style "pennylane.drawer.use_style")(style) | Set a style setting. |

The following images are generated via the code:

```

@qml.qnode(qml.device('lightning.qubit', wires=(0,1,2,3)))

def circuit(x, z):

    qml.QFT(wires=(0,1,2,3))

    qml.Toffoli(wires=(0,1,2))

    qml.CSWAP(wires=(0,2,3))

    qml.RX(x, wires=0)

    qml.CRZ(z, wires=(3,0))

    return qml.expval(qml.PauliZ(0))

qml.drawer.use\_style(style)

fig, ax = qml.draw\_mpl(circuit)(1.2345, 1.2345)

```

#### Currently Available Styles[¶](#currently-available-styles "Permalink to this headline")

| [bws](_images/black_white_style1.png) | [bwd](_images/black_white_dark_style.png) | [sks](_images/sketch_style2.png) |

|

| [pls](_images/pennylane_style.png) | [skd](_images/sketch_dark_style.png) | [sol](_images/solarized_light_style.png) |

|

| [sod](_images/solarized_dark_style.png) | [def](_images/default_style.png) |  |

|

### qml.fermi[¶](#qml-fermi "Permalink to this headline")

#### Overview[¶](#overview "Permalink to this headline")

This module contains functions and classes for creating and manipulating fermionic operators.

##### Functions[¶](#functions "Permalink to this headline")

| [`from\_string`](index.html#pennylane.fermi.from_string "pennylane.fermi.from_string")(fermi\_string) | Return a fermionic operator object from its string representation. |

| [`jordan\_wigner`](index.html#pennylane.fermi.jordan_wigner "pennylane.fermi.jordan_wigner")(fermi\_operator, \*\*kwargs) | Convert a fermionic operator to a qubit operator using the Jordan-Wigner mapping. |

##### Classes[¶](#classes "Permalink to this headline")

| [`FermiA`](index.html#pennylane.fermi.FermiA "pennylane.fermi.FermiA")(orbital) | The fermionic annihilation operator \(a\) |

| [`FermiC`](index.html#pennylane.fermi.FermiC "pennylane.fermi.FermiC")(orbital) | The fermionic creation operator \(a^{\dagger}\) |

| [`FermiSentence`](index.html#pennylane.fermi.FermiSentence "pennylane.fermi.FermiSentence")(operator) | Immutable dictionary used to represent a Fermi sentence, a linear combination of Fermi words, with the keys as FermiWord instances and the values correspond to coefficients. |

| [`FermiWord`](index.html#pennylane.fermi.FermiWord "pennylane.fermi.FermiWord")(operator) | Immutable dictionary used to represent a Fermi word, a product of fermionic creation and annihilation operators, that can be constructed from a standard dictionary. |

#### FermiC and FermiA[¶](#fermic-and-fermia "Permalink to this headline")

The fermionic creation and annihilation operators are constructed with [`FermiC`](index.html#pennylane.FermiC "pennylane.FermiC")

and [`FermiA`](index.html#pennylane.FermiA "pennylane.FermiA"), respectively. We pass in the index of the orbital that the

operator acts on. For example, the operators \(a^{\dagger}\_0\) and \(a\_3\), acting on the

\(0\text{th}\) and \(3\text{rd}\) orbitals, are constructed as

```

>>> qml.FermiC(0)

a⁺(0)

>>> qml.FermiA(3)

a(3)

```

These operators can be multiplied by each other to create \(n\)-orbital fermionic operators such

as \(a^{\dagger}\_0 a\_0 a^{\dagger}\_3 a\_3\). We call these \(n\)-orbital fermionic operators

Fermi words.

```

>>> qml.FermiC(0) \* qml.FermiA(0) \* qml.FermiC(3) \* qml.FermiA(3)

a⁺(0) a(0) a⁺(3) a(3)

```

The Fermi words can be linearly combined to create fermionic operators that we call Fermi

sentences. For instance, a fermionic Hamiltonian such as

\(H = 1.2 a^{\dagger}\_0 a\_0 + 2.3 a^{\dagger}\_3 a\_3\) can be constructed from Fermi words with

```

>>> h = 1.2 \* qml.FermiC(0) \* qml.FermiA(0) + 2.3 \* qml.FermiC(3) \* qml.FermiA(3)

>>> h

1.2 \* a⁺(0) a(0)

+ 2.3 \* a⁺(3) a(3)

```

#### Mapping to qubit operators[¶](#mapping-to-qubit-operators "Permalink to this headline")

The fermionic operators can be mapped to the qubit basis by using the

[`jordan\_wigner()`](index.html#pennylane.jordan_wigner "pennylane.jordan_wigner") function. This function can be used to map

[`FermiC`](index.html#pennylane.FermiC "pennylane.FermiC") and [`FermiA`](index.html#pennylane.FermiA "pennylane.FermiA") operators as well as Fermi words and

Fermi sentences.

```

>>> qml.jordan\_wigner(qml.FermiA(1))

(0.5\*(PauliZ(wires=[0]) @ PauliX(wires=[1])))

+ (0.5j\*(PauliZ(wires=[0]) @ PauliY(wires=[1])))

```

```

>>> qml.jordan\_wigner(qml.FermiC(1) \* qml.FermiA(1))

((0.5+0j)\*(Identity(wires=[1])))

+ ((-0.5+0j)\*(PauliZ(wires=[1])))

```

```

>>> f = 0.5 \* qml.FermiC(1) \* qml.FermiA(1) + 0.75 \* qml.FermiC(2) \* qml.FermiA(2)

>>> qml.jordan\_wigner(f)

((0.625+0j)\*(Identity(wires=[1])))

+ ((-0.25+0j)\*(PauliZ(wires=[1])))

+ ((-0.375+0j)\*(PauliZ(wires=[2])))

```

#### FermiWord and FermiSentence[¶](#fermiword-and-fermisentence "Permalink to this headline")

Fermi words and Fermi sentences can also be constructed directly with

[`FermiWord`](index.html#pennylane.fermi.FermiWord "pennylane.fermi.FermiWord") and [`FermiSentence`](index.html#pennylane.fermi.FermiSentence "pennylane.fermi.FermiSentence") by passing

dictionaries that define the fermionic operators.

For Fermi words, the dictionary items define the fermionic creation and annihilation operators.

The keys of the dictionary are tuples of two integers. The first integer represents the

position of the creation/annihilation operator in the Fermi word and the second integer represents

the orbital it acts on. The values of the dictionary are one of `'+'` or `'-'` symbols that

denote creation and annihilation operators, respectively. The operator

\(a^{\dagger}\_0 a\_3 a^{\dagger}\_1\) can then be constructed with

```

>>> qml.fermi.FermiWord({(0, 0): '+', (1, 3): '-', (2, 1): '+'})

a⁺(0) a(3) a⁺(1)

```

A Fermi sentence can be constructed directly by passing a dictionary of Fermi words and their

corresponding coefficients to the [`FermiSentence`](index.html#pennylane.fermi.FermiSentence "pennylane.fermi.FermiSentence") class. For instance, the

Fermi sentence \(1.2 a^{\dagger}\_0 a\_0 + 2.3 a^{\dagger}\_3 a\_3\) can be constructed as

```

>>> fw1 = qml.fermi.FermiWord({(0, 0): '+', (1, 0): '-'})

>>> fw2 = qml.fermi.FermiWord({(0, 3): '+', (1, 3): '-'})

>>> qml.fermi.FermiSentence({fw1: 1.2, fw2: 2.3})

1.2 \* a⁺(0) a(0)

+ 2.3 \* a⁺(3) a(3)

```

### qml.fourier[¶](#qml-fourier "Permalink to this headline")

#### Overview[¶](#module-pennylane.fourier "Permalink to this headline")

This module contains functions to analyze the Fourier representation

of quantum circuits.

##### Functions[¶](#functions "Permalink to this headline")

| [`circuit\_spectrum`](index.html#pennylane.fourier.circuit_spectrum "pennylane.fourier.circuit_spectrum")(qnode[, encoding\_gates, …]) | Compute the frequency spectrum of the Fourier representation of simple quantum circuits ignoring classical preprocessing. |

| [`coefficients`](index.html#pennylane.fourier.coefficients "pennylane.fourier.coefficients")(f, n\_inputs, degree[, …]) | Computes the first \(2d+1\) Fourier coefficients of a \(2\pi\) periodic function, where \(d\) is the highest desired frequency (the degree) of the Fourier spectrum. |

| [`get\_spectrum`](index.html#pennylane.fourier.get_spectrum "pennylane.fourier.get_spectrum")(op, decimals) | Extract the frequencies contributed by an input-encoding gate to the overall Fourier representation of a quantum circuit. |

| [`join\_spectra`](index.html#pennylane.fourier.join_spectra "pennylane.fourier.join_spectra")(spec1, spec2) | Join two sets of frequencies that belong to the same input. |

| [`qnode\_spectrum`](index.html#pennylane.fourier.qnode_spectrum "pennylane.fourier.qnode_spectrum")(qnode[, encoding\_args, …]) | Compute the frequency spectrum of the Fourier representation of quantum circuits, including classical preprocessing. |

| [`reconstruct`](index.html#pennylane.fourier.reconstruct "pennylane.fourier.reconstruct")(qnode[, ids, nums\_frequency, …]) | Reconstruct an expectation value QNode along a single parameter direction. |

##### Visualization[¶](#visualization "Permalink to this headline")

Tools to visualize the Fourier representations can be found in the `fourier.visualize`

submodule. This requires the `matplotlib` package to be installed.

| [`bar`](index.html#pennylane.fourier.visualize.bar "pennylane.fourier.visualize.bar")(coeffs, n\_inputs, ax[, colour\_dict, …]) | Plot a set of Fourier coefficients as a bar plot. |

| [`box`](index.html#pennylane.fourier.visualize.box "pennylane.fourier.visualize.box")(coeffs, n\_inputs, ax[, colour\_dict, …]) | Plot a list of sets of Fourier coefficients as a box plot. |

| [`panel`](index.html#pennylane.fourier.visualize.panel "pennylane.fourier.visualize.panel")(coeffs, n\_inputs, ax[, colour]) | Plot a list of sets of coefficients in the complex plane for a 1- or 2-dimensional function. |

| [`radial\_box`](index.html#pennylane.fourier.visualize.radial_box "pennylane.fourier.visualize.radial_box")(coeffs, n\_inputs, ax[, …]) | Plot a list of sets of Fourier coefficients on a radial plot as box plots. |

| [`violin`](index.html#pennylane.fourier.visualize.violin "pennylane.fourier.visualize.violin")(coeffs, n\_inputs, ax[, colour\_dict, …]) | Plots a list of sets of Fourier coefficients as a violin plot. |

#### Fourier representation of quantum circuits[¶](#fourier-representation-of-quantum-circuits "Permalink to this headline")

Consider a quantum circuit that depends on a parameter vector \(x\) with

length \(N\). The circuit involves application of some unitary operations

\(U(x)\), and then measurement of an observable \(\hat{O}\).

Analytically, the expectation value is

\[\langle \hat{O} \rangle = \langle 0 \vert U^\dagger (x) \hat{O} U(x) \vert 0\rangle = \langle

\psi(x) \vert \hat{O} \vert \psi (x)\rangle.\]

This output is simply a function \(f(x) = \langle \psi(x) \vert \hat{O} \vert \psi

(x)\rangle\). Notably, it is a periodic function of the parameters, and

it can thus be expressed as a multidimensional Fourier series:

\[f(x) = \sum \limits\_{n\_1\in \Omega\_1} \dots \sum \limits\_{n\_N \in \Omega\_N}

c\_{n\_1,\dots, n\_N} e^{-i x\_1 n\_1} \dots e^{-i x\_N n\_N},\]

where \(n\_i\) are integer-valued frequencies, \(\Omega\_i\) are the set

of available values for the integer frequencies, and the

\(c\_{n\_1,\ldots,n\_N}\) are Fourier coefficients.

As a simple example, consider `simple\_circuit` below, which is a function of a

single parameter.

```

import pennylane as qml

from pennylane import numpy as np

dev = qml.device('default.qubit', wires=2)

@qml.qnode(dev)

def simple\_circuit(x):

    qml.RX(x[0], wires=0)

    qml.RY(x[0], wires=1)

    qml.CNOT(wires=[1, 0])

    return qml.expval(qml.PauliZ(0))

```

We can mathematically evaluate the expectation value of this function to be

\(\langle Z \rangle = 0.5 + 0.5 \cos(2x)\). Thus, the Fourier coefficients

of this function are \(c\_0 = 0.5\), \(c\_1 = c^\*\_{-1} = 0\), and \(c\_2 = c^\*\_{-2} = 0.25\).

The PennyLane `fourier` module enables calculation of

the values of the Fourier coefficients \(c\_{n\_1,\dots, n\_N}\).

Knowledge of the coefficients, and thereby the spectrum of frequencies

where the coefficients are non-zero, is important

for the study of the expressivity of quantum circuits, as described in [Schuld,

Sweke and Meyer (2020)](https://arxiv.org/abs/2008.08605) and [Vidal and

Theis, 2019](https://arxiv.org/abs/1901.11434) – the more coefficients

available to a quantum model, the larger the class of functions that model can

represent, potentially leading to greater utility for quantum machine learning

applications.

#### Calculating the frequencies supported by a circuit[¶](#calculating-the-frequencies-supported-by-a-circuit "Permalink to this headline")

For certain circuits, information on the frequency spectra \(\Omega\_j\)

can be derived solely from the structure of the gates

that encode the corresponding inputs \(x\_j\) (see for example [Schuld,

Sweke, and Meyer (2020)](https://arxiv.org/abs/2008.08605)). More precisely, if

all input-encoding gates are of the form \(e^{-ix\_j G}\), where \(G\) is

a Hermitian operator that “generates” the operation, we can deduce a maximum set of frequencies

that can theoretically appear in \(\Omega\_j\). Depending on the non-input-encoding

gates in the circuit, some of these theoretically supported frequencies may end up

having vanishing Fourier coefficients, and \(\Omega\_j\) effectively turns out to be smaller.

However, estimates based on the input-encoding strategy can still be useful to understand

the potential expressivity of a type of ansatz.

The theoretically supported frequencies can be computed

using the [`circuit\_spectrum()`](index.html#pennylane.fourier.circuit_spectrum "pennylane.fourier.circuit_spectrum") function. To mark which gates encode

inputs (and, for example, which ones are only used for trainable parameters), we

have to give input-encoding gates an `id`:

```

import pennylane as qml

dev = qml.device('default.qubit', wires=2)

@qml.qnode(dev)

def simple\_circuit\_marked(x):

    qml.RX(x[0], wires=0, id="x")

    qml.RY(x[0], wires=1, id="x")

    qml.CNOT(wires=[1, 0])

    return qml.expval(qml.PauliZ(0))

```

We can then compute the frequencies supported by the input-encoding gates as:

```

>>> from pennylane.fourier import circuit\_spectrum

>>> freqs = circuit\_spectrum(simple\_circuit\_marked)([0.1])

>>> for k, v in freqs.items():

>>>     print(k, ":", v)

x : [-2.0, -1.0, 0.0, 1.0, 2.0]

```

Note

Some encoding-gate types may give rise to non-integer-valued frequencies. In this case,

the [`circuit\_spectrum()`](index.html#pennylane.fourier.circuit_spectrum "pennylane.fourier.circuit_spectrum") function computes the frequency sets \(\Omega\_j\)

of the *Fourier sum* of the form

\[f(x) = \sum \limits\_{\omega\_1\in \Omega\_1} \dots \sum \limits\_{\omega\_N \in \Omega\_N}

c\_{\omega\_1,\dots, \omega\_N} e^{-i x\_1 \omega\_1} \dots e^{-i x\_N \omega\_N},\]

with \(\omega \in \mathbb{R}\). Just like any other function, such a sum can be turned into a

proper Fourier series, but the mapping from non-integer-valued to integer-valued frequencies

is not always trivial.

#### Calculating the Fourier coefficients[¶](#calculating-the-fourier-coefficients "Permalink to this headline")

To get a more accurate picture of the Fourier series representation of a quantum circuit,

we have to compute the Fourier coefficients \(c\_{n\_1,\ldots,n\_N}\). This is done using numerical methods in the

[`coefficients()`](index.html#pennylane.fourier.coefficients "pennylane.fourier.coefficients") function:

```

>>> from pennylane.fourier import coefficients

>>> coeffs = coefficients(simple\_circuit, 1, 2)

>>> print(np.round(coeffs, decimals=4))

[0.5 +0.j 0. -0.j 0.25+0.j 0.25+0.j 0. -0.j]

```

The inputs to the [`coefficients()`](index.html#pennylane.fourier.coefficients "pennylane.fourier.coefficients") function are

* A function, or QNode containing the variational circuit for which to compute the Fourier coefficients,

* the length of the input vector, and

* the maximum frequency for which to calculate the coefficients (also known as

the *degree*).

Internally, the coefficients are computed using NumPy’s [discrete Fourier

transform](https://numpy.org/doc/stable/reference/generated/numpy.fft.fftn.html)

function. The order of the coefficients in the output thus follows the standard

output ordering, i.e., \([c\_0, c\_1, c\_2, c\_{-2}, c\_{-1}]\), and similarly

for multiple dimensions. The normalization convention used here corresponds to

the `norm="forward"` option in the NumPy transforms, i.e., the Fourier

transform over an array of size \(N\) is rescaled by \(1/N\), while the

inverse Fourier transform is left as-is.

For more details and examples of coefficient calculation, please see the

documentation for [`coefficients()`](index.html#pennylane.fourier.coefficients "pennylane.fourier.coefficients").

##### Fourier coefficient visualization[¶](#fourier-coefficient-visualization "Permalink to this headline")

A key application of the Fourier module is to analyze the *expressivity* of

classes of quantum circuit families. The set of frequencies in the Fourier

representation of a quantum circuit can be used to characterize the function

class that a parametrized circuit gives rise to. For example, if an embedding

leads to a Fourier representation with a few low-order frequencies, a quantum

circuit using this embedding can only express rather simple periodic functions.

The Fourier module contains a number of methods to visualize the coefficients of

the Fourier series representation of a single circuit, as well as distributions

over Fourier coefficients for a parametrized circuit family.

Note

Visualization of the Fourier coefficients requires the `matplotlib`

library. As such, visualization functions are contained in the submodule

`pennylane.fourier.visualize`. The visualization functions are structured

to accept `matplotlib` axes as arguments so that additional configuration

(such as adding titles, saving, etc.) can be done outside the functions. Many

of the plots, however, require a specific number of subplots. The examples

below demonstrate how the subplots should be created for each function.

##### Visualizing a single set of coefficients[¶](#visualizing-a-single-set-of-coefficients "Permalink to this headline")

While all the functions available for visualizing multiple sets of Fourier

coefficients can be used for a single set, the primary tool for this purpose is

the [`bar()`](index.html#pennylane.fourier.visualize.bar "pennylane.fourier.visualize.bar") function. Using the coefficients we obtained in the

earlier example,

```

>>> from pennylane.fourier.visualize import \*

>>> import matplotlib.pyplot as plt

```

```

>>> fig, ax = plt.subplots(2, 1, sharex=True, sharey=True) # Set up the axes

>>> bar(coeffs, 1, ax)

```

[![_images/fourier_vis_bar_plot.png](_images/fourier_vis_bar_plot.png)](javascript:void(0);)

  

In the bar plots, real coefficients are shown in the top panel, and complex in

the bottom. The labels along the x-axis represent the coefficient frequencies

(for large plots, it is sometimes convenient to remove these by passing

`show\_freqs=False` to the plotting function).

Below is a more complex example that demonstrates some of the additional

customization options available:

```

from functools import partial

weights = np.array([[0.1, 0.2, 0.3], [0.4, 0.5, 0.6]])

@qml.qnode(dev)

def circuit\_with\_weights(w, x):

    qml.RX(x[0], wires=0)

    qml.RY(x[1], wires=1)

    qml.CNOT(wires=[1, 0])

    qml.Rot(\*w[0], wires=0)

    qml.Rot(\*w[1], wires=1)

    qml.CNOT(wires=[1, 0])

    qml.RX(x[0], wires=0)

    qml.RY(x[1], wires=1)

    qml.CNOT(wires=[1, 0])

    return qml.expval(qml.PauliZ(0))

coeffs = coefficients(partial(circuit\_with\_weights, weights), 2, 2)

# Number of inputs is now 2; pass custom colours as well

fig, ax = plt.subplots(2, 1, sharex=True, sharey=True, figsize=(15, 4))

bar(coeffs, 2, ax, colour\_dict={"real" : "red", "imag" : "blue"})

```

[![_images/fourier_vis_bar_plot_2.png](_images/fourier_vis_bar_plot_2.png)](javascript:void(0);)

##### Visualizing multiple sets of coefficients[¶](#visualizing-multiple-sets-of-coefficients "Permalink to this headline")

Suppose we do not want to visualize the Fourier coefficients for a fixed

`weights` argument in `circuit\_with\_weights`, but the distribution over sets

of Fourier coefficients when the weights are randomly sampled. For each

`weights` sample we get a different set of coefficients:

```

coeffs = []

for \_ in range(100):

    weights = np.random.normal(0, 1, size=(2, 3))

    c = coefficients(partial(circuit\_with\_weights, weights), 2, degree=2)

    coeffs.append(np.round(c, decimals=8))

```

One option to plot the distribution is [`violin()`](index.html#pennylane.fourier.visualize.violin "pennylane.fourier.visualize.violin"):

```

fig, ax = plt.subplots(2, 1, sharey=True, figsize=(15, 4))

violin(coeffs, 2, ax, show\_freqs=True)

```

[![_images/fourier_vis_violin.png](_images/fourier_vis_violin.png)](javascript:void(0);)

  

A similar option is [`box()`](index.html#pennylane.fourier.visualize.box "pennylane.fourier.visualize.box"), which

produces a plot of the same format but using a box plot.

A different view can obtained using the

[`radial\_box()`](index.html#pennylane.fourier.visualize.radial_box "pennylane.fourier.visualize.radial_box") function. This “rolls up”

the coefficients onto a polar grid. Let us use it to visualize the same set of

coefficients as above:

```

# The subplot axes must be \*polar\* for the radial plots

fig, ax = plt.subplots(

    1, 2, sharex=True, sharey=True,

    subplot\_kw=dict(polar=True),

    figsize=(15, 8)

)

radial\_box(coeffs, 2, ax, show\_freqs=True, show\_fliers=False)

```

[![_images/fourier_vis_radial_box.png](_images/fourier_vis_radial_box.png)](javascript:void(0);)

  

The left plot displays the real part, and the right the imaginary

part of the distribution over a parametrized quantum circuit’s

Fourier coefficients. The labels on the “spokes” of the wheels represent the particular

frequencies; we see that this matches the coefficients we found earlier. Note

how the coefficient \(c\_0\) appears in the top middle of each plot; the

negative frequencies extend counterclockwise from that point, and the positive

frequencies increase in the clockwise direction. Such plots allow for a more

compact representation of a large number of frequencies than the linear violin

and box plots discussed above. For a large number of frequencies, however, it is

recommended to disable the frequency labelling by setting `show\_freqs=False`,

and hiding box plot fliers as was done above.

Finally, for the special case of 1- or 2-dimensional functions, we can use the

[`panel()`](index.html#pennylane.fourier.visualize.panel "pennylane.fourier.visualize.panel") function to plot the distributions of the

sampled sets of Fourier coefficients on the complex plane.

```

# Need a grid large enough to hold all coefficients up to frequency 2

fig, ax = plt.subplots(5, 5, figsize=(12, 10), sharex=True, sharey=True)

panel(coeffs, 2, ax)

```

[![_images/fourier_vis_panel.png](_images/fourier_vis_panel.png)](javascript:void(0);)

### qml.gradients[¶](#module-pennylane.gradients "Permalink to this headline")

Quantum gradient transforms are strategies for computing the gradient of a quantum

circuit that work by **transforming** the quantum circuit into one or more gradient circuits.

These gradient circuits, once executed and post-processed, return the gradient

of the original circuit.

Examples of quantum gradient transforms include finite-differences and parameter-shift

rules.

This module provides a selection of device-independent, differentiable quantum

gradient transforms. As such, these quantum gradient transforms can be used to

compute the gradients of quantum circuits on both simulators and hardware.

In addition, it also includes an API for writing your own quantum gradient

transforms.

These quantum gradient transforms can be used in two ways:

* Transforming quantum circuits directly

* Registering a quantum gradient strategy for use when performing autodifferentiation

with a [`QNode`](index.html#pennylane.QNode "pennylane.QNode").

#### Overview[¶](#overview "Permalink to this headline")

##### Gradient transforms[¶](#gradient-transforms "Permalink to this headline")

| [`finite\_diff`](index.html#pennylane.gradients.finite_diff "pennylane.gradients.finite_diff")(tape[, argnum, h, approx\_order, …]) | Transform a QNode to compute the finite-difference gradient of all gate parameters with respect to its inputs. |

| [`param\_shift`](index.html#pennylane.gradients.param_shift "pennylane.gradients.param_shift")(tape[, argnum, shifts, …]) | Transform a QNode to compute the parameter-shift gradient of all gate parameters with respect to its inputs. |

| [`param\_shift\_cv`](index.html#pennylane.gradients.param_shift_cv "pennylane.gradients.param_shift_cv")(tape, dev[, argnum, shifts, …]) | Transform a continuous-variable QNode to compute the parameter-shift gradient of all gate parameters with respect to its inputs. |

| [`param\_shift\_hessian`](index.html#pennylane.gradients.param_shift_hessian "pennylane.gradients.param_shift_hessian")(tape[, argnum, …]) | Transform a QNode to compute the parameter-shift Hessian with respect to its trainable parameters. |

| [`spsa\_grad`](index.html#pennylane.gradients.spsa_grad "pennylane.gradients.spsa_grad")(tape[, argnum, h, approx\_order, …]) | Transform a QNode to compute the SPSA gradient of all gate parameters with respect to its inputs. |

| [`hadamard\_grad`](index.html#pennylane.gradients.hadamard_grad "pennylane.gradients.hadamard_grad")(tape[, argnum, aux\_wire, …]) | Transform a QNode to compute the Hadamard test gradient of all gates with respect to their inputs. |

| [`stoch\_pulse\_grad`](index.html#pennylane.gradients.stoch_pulse_grad "pennylane.gradients.stoch_pulse_grad")(tape[, argnum, …]) | Compute the gradient of a quantum circuit composed of pulse sequences by applying the stochastic parameter shift rule. |

| [`pulse\_generator`](index.html#pennylane.gradients.pulse_generator "pennylane.gradients.pulse_generator")(tape[, argnum, atol]) | Transform a QNode to compute the pulse generator parameter-shift gradient of pulses in a pulse program with respect to their inputs. |

##### Custom gradients[¶](#custom-gradients "Permalink to this headline")

| [`gradient\_transform`](index.html#pennylane.gradients.gradient_transform "pennylane.gradients.gradient_transform")(\*args, \*\*kwargs) | Decorator for defining quantum gradient transforms. |

| [`hessian\_transform`](index.html#pennylane.gradients.hessian_transform "pennylane.gradients.hessian_transform")(\*args, \*\*kwargs) | Decorator for defining quantum Hessian transforms. |

##### Utility functions[¶](#utility-functions "Permalink to this headline")

| [`finite\_diff\_coeffs`](index.html#pennylane.gradients.finite_diff_coeffs "pennylane.gradients.finite_diff_coeffs")(n, approx\_order, strategy) | Generate the finite difference shift values and corresponding term coefficients for a given derivative order, approximation accuracy, and strategy. |

| [`generate\_shifted\_tapes`](index.html#pennylane.gradients.generate_shifted_tapes "pennylane.gradients.generate_shifted_tapes")(tape, index, shifts) | Generate a list of tapes or a single broadcasted tape, where one marked trainable parameter has been shifted by the provided shift values. |

| [`generate\_multishifted\_tapes`](index.html#pennylane.gradients.generate_multishifted_tapes "pennylane.gradients.generate_multishifted_tapes")(tape, indices, …) | Generate a list of tapes where multiple marked trainable parameters have been shifted by the provided shift values. |

| [`generate\_shift\_rule`](index.html#pennylane.gradients.generate_shift_rule "pennylane.gradients.generate_shift_rule")(frequencies[, shifts, order]) | Computes the parameter shift rule for a unitary based on its generator’s eigenvalue frequency spectrum. |

| [`generate\_multi\_shift\_rule`](index.html#pennylane.gradients.generate_multi_shift_rule "pennylane.gradients.generate_multi_shift_rule")(frequencies[, …]) | Computes the parameter shift rule with respect to two parametrized unitaries, given their generator’s eigenvalue frequency spectrum. |

| [`eigvals\_to\_frequencies`](index.html#pennylane.gradients.eigvals_to_frequencies "pennylane.gradients.eigvals_to_frequencies")(eigvals) | Convert an eigenvalue spectrum to frequency values, defined as the the set of positive, unique differences of the eigenvalues in the spectrum. |

| [`compute\_vjp`](index.html#pennylane.gradients.compute_vjp "pennylane.gradients.compute_vjp")(dy, jac[, num]) | Convenience function to compute the vector-Jacobian product for a given vector of gradient outputs and a Jacobian. |

| [`compute\_vjp\_single`](index.html#pennylane.gradients.compute_vjp_single "pennylane.gradients.compute_vjp_single")(dy, jac[, num]) | Convenience function to compute the vector-Jacobian product for a given vector of gradient outputs and a Jacobian for a single measurement tape. |

| [`compute\_vjp\_multi`](index.html#pennylane.gradients.compute_vjp_multi "pennylane.gradients.compute_vjp_multi")(dy, jac[, num]) | Convenience function to compute the vector-Jacobian product for a given vector of gradient outputs and a Jacobian for a tape with multiple measurements. |

| [`batch\_vjp`](index.html#pennylane.gradients.batch_vjp "pennylane.gradients.batch_vjp")(tapes, dys, gradient\_fn[, …]) | Generate the gradient tapes and processing function required to compute the vector-Jacobian products of a batch of tapes. |

| [`vjp`](index.html#pennylane.gradients.vjp "pennylane.gradients.vjp")(tape, dy, gradient\_fn[, gradient\_kwargs]) | Generate the gradient tapes and processing function required to compute the vector-Jacobian products of a tape. |

| [`compute\_jvp\_single`](index.html#pennylane.gradients.compute_jvp_single "pennylane.gradients.compute_jvp_single")(tangent, jac) | Convenience function to compute the Jacobian vector product for a given tangent vector and a Jacobian for a single measurement tape. |

| [`compute\_jvp\_multi`](index.html#pennylane.gradients.compute_jvp_multi "pennylane.gradients.compute_jvp_multi")(tangent, jac) | Convenience function to compute the Jacobian-vector product for a given vector of gradient outputs and a Jacobian for a tape with multiple measurements. |

| [`batch\_jvp`](index.html#pennylane.gradients.batch_jvp "pennylane.gradients.batch_jvp")(tapes, tangents, gradient\_fn[, …]) | Generate the gradient tapes and processing function required to compute the Jacobian vector products of a batch of tapes. |

| [`jvp`](index.html#pennylane.gradients.jvp "pennylane.gradients.jvp")(tape, tangent, gradient\_fn[, …]) | Generate the gradient tapes and processing function required to compute the Jacobian vector product of a tape. |

#### Registering autodifferentiation gradients[¶](#registering-autodifferentiation-gradients "Permalink to this headline")

All PennyLane QNodes are automatically differentiable, and can be included

seamlessly within an autodiff pipeline. When creating a [`QNode`](index.html#pennylane.QNode "pennylane.QNode"), the

strategy for determining the optimal differentiation strategy is *automated*,

and takes into account the circuit, device, autodiff framework, and metadata

(such as whether a finite number of shots are used).

```

dev = qml.device("default.qubit", wires=2, shots=1000)

@qml.qnode(dev, interface="tf")

def circuit(weights):

    ...

```

In particular:

* When using a simulator device with exact measurement statistics, backpropagation

is preferred due to performance and memory improvements.

* When using a hardware device, or a simulator with a finite number of shots,

a quantum gradient transform—such as the parameter-shift rule—is preferred.

If you would like to specify a particular quantum gradient transform to use

when differentiating your quantum circuit, this can be passed when

creating the QNode:

```

@qml.qnode(dev, diff\_method=qml.gradients.param\_shift)

def circuit(weights):

    ...

```

When using your preferred autodiff framework to compute the gradient of your

hybrid quantum-classical cost function, the specified gradient transform

for each QNode will be used.

Note

A single cost function may include multiple QNodes, each with their

own quantum gradient transform registered.

#### Transforming QNodes[¶](#transforming-qnodes "Permalink to this headline")

Alternatively, quantum gradient transforms can be applied manually to QNodes.

```

dev = qml.device("default.qubit", wires=2)

@qml.qnode(dev)

def circuit(weights):

    qml.RX(weights[0], wires=0)

    qml.RY(weights[1], wires=1)

    qml.CNOT(wires=[0, 1])

    qml.RX(weights[2], wires=1)

    return qml.probs(wires=1)

```

```

>>> weights = np.array([0.1, 0.2, 0.3], requires\_grad=True)

>>> circuit(weights)

tensor([0.9658079, 0.0341921], requires\_grad=True)

>>> qml.gradients.param\_shift(circuit)(weights)

tensor([[-0.04673668, -0.09442394, -0.14409127],

 [ 0.04673668, 0.09442394, 0.14409127]], requires\_grad=True)

```

Comparing this to autodifferentiation:

```

>>> qml.jacobian(circuit)(weights)

array([[-0.04673668, -0.09442394, -0.14409127],

 [ 0.04673668, 0.09442394, 0.14409127]])

```

Quantum gradient transforms can also be applied as decorators to QNodes,

if *only* gradient information is needed. Evaluating the QNode will then

automatically return the gradient:

```

dev = qml.device("default.qubit", wires=2)

@qml.gradients.param\_shift

@qml.qnode(dev)

def decorated\_circuit(weights):

    qml.RX(weights[0], wires=0)

    qml.RY(weights[1], wires=1)

    qml.CNOT(wires=[0, 1])

    qml.RX(weights[2], wires=1)

    return qml.probs(wires=1)

```

```

>>> decorated\_circuit(weights)

(tensor([-0.04673668, 0.04673668], requires\_grad=True),

 tensor([-0.09442394, 0.09442394], requires\_grad=True),

 tensor([-0.14409127, 0.14409127], requires\_grad=True))

```

Note

If your circuit contains any operations not supported by the gradient

transform, the transform will attempt to automatically decompose the

circuit into only operations that support gradients.

Note

If you wish to only return the purely **quantum** component of the

gradient—that is, the gradient of the output with respect to

**gate** arguments, not QNode arguments—pass `hybrid=False`

when applying the transform:

```

>>> qml.gradients.param\_shift(circuit, hybrid=False)(weights)

```

#### Differentiating gradient transforms and higher-order derivatives[¶](#differentiating-gradient-transforms-and-higher-order-derivatives "Permalink to this headline")

Gradient transforms are themselves differentiable, allowing higher-order

gradients to be computed:

```

dev = qml.device("default.qubit", wires=2)

@qml.qnode(dev)

def circuit(weights):

    qml.RX(weights[0], wires=0)

    qml.RY(weights[1], wires=1)

    qml.CNOT(wires=[0, 1])

    qml.RX(weights[2], wires=1)

    return qml.expval(qml.PauliZ(1))

```

```

>>> weights = np.array([0.1, 0.2, 0.3], requires\_grad=True)

>>> circuit(weights)

tensor(0.9316158, requires\_grad=True)

>>> qml.gradients.param\_shift(circuit)(weights)  # gradient

(tensor(-0.09347337, requires\_grad=True),

 tensor(-0.18884787, requires\_grad=True),

 tensor(-0.28818254, requires\_grad=True))

>>> def stacked\_output(weights):

...     return qml.numpy.stack(qml.gradients.param\_shift(circuit)(weights))

>>> qml.jacobian(stacked\_output)(weights)  # hessian

array([[-0.9316158 , 0.01894799, 0.0289147 ],

 [ 0.01894799, -0.9316158 , 0.05841749],

 [ 0.0289147 , 0.05841749, -0.9316158 ]])

```

Another way to compute higher-order derivatives is by passing the `max\_diff` and

`diff\_method` arguments to the QNode and by successive differentiation:

```

@qml.qnode(dev, diff\_method="parameter-shift", max\_diff=2)

def circuit(weights):

    qml.RX(weights[0], wires=0)

    qml.RY(weights[1], wires=1)

    qml.CNOT(wires=[0, 1])

    qml.RX(weights[2], wires=1)

    return qml.expval(qml.PauliZ(1))

```

```

>>> weights = np.array([0.1, 0.2, 0.3], requires\_grad=True)

>>> qml.jacobian(qml.jacobian(circuit))(weights)  # hessian

array([[-0.9316158 , 0.01894799, 0.0289147 ],

 [ 0.01894799, -0.9316158 , 0.05841749],

 [ 0.0289147 , 0.05841749, -0.9316158 ]])

```

Note that the `max\_diff` argument only applies to gradient transforms and that its default value is `1`; failing to

set its value correctly may yield incorrect results for higher-order derivatives. Also, passing

`diff\_method="parameter-shift"` is equivalent to passing `diff\_method=qml.gradients.param\_shift`.

#### Transforming tapes[¶](#transforming-tapes "Permalink to this headline")

Gradient transforms can be applied to low-level [`QuantumTape`](index.html#pennylane.tape.QuantumTape "pennylane.tape.QuantumTape") objects,

a datastructure representing variational quantum algorithms:

```

weights = np.array([0.1, 0.2, 0.3], requires\_grad=True)

ops = [

    qml.RX(weights[0], wires=0),

    qml.RY(weights[1], wires=1),

    qml.CNOT(wires=[0, 1]),

    qml.RX(weights[2], wires=1)]

measurements = [qml.expval(qml.PauliZ(1))]

tape = qml.tape.QuantumTape(ops, measurements)

```

Unlike when transforming a QNode, transforming a tape directly

will perform no implicit quantum device evaluation. Instead, it returns

the processed tapes, and a post-processing function, which together

define the gradient:

```

>>> gradient\_tapes, fn = qml.gradients.param\_shift(tape)

>>> gradient\_tapes

[<QuantumTape: wires=[0, 1], params=3>,

 <QuantumTape: wires=[0, 1], params=3>,

 <QuantumTape: wires=[0, 1], params=3>,

 <QuantumTape: wires=[0, 1], params=3>,

 <QuantumTape: wires=[0, 1], params=3>,

 <QuantumTape: wires=[0, 1], params=3>]

```

This can be useful if the underlying circuits representing the gradient

computation need to be analyzed.

The output tapes can then be evaluated and post-processed to retrieve

the gradient:

```

>>> dev = qml.device("default.qubit", wires=2)

>>> fn(qml.execute(gradient\_tapes, dev, None))

(array(-0.09347337), array(-0.18884787), array(-0.28818254))

```

Note that the post-processing function `fn` returned by the

gradient transform is applied to the flat list of results returned

from executing the gradient tapes.

#### Custom gradient transforms[¶](#custom-gradient-transforms "Permalink to this headline")

Using the [`gradient\_transform`](index.html#pennylane.gradients.gradient_transform "pennylane.gradients.gradient_transform") decorator, custom gradient transforms

can be created:

```

@gradient\_transform

def my\_custom\_gradient(tape, \*\*kwargs):

    ...

    return gradient\_tapes, processing\_fn

```

Once created, a custom gradient transform can be applied directly

to QNodes, or registered as the quantum gradient transform to use

during autodifferentiation.

For more details, please see the [`gradient\_transform`](index.html#pennylane.gradients.gradient_transform "pennylane.gradients.gradient_transform")

documentation.

### qml.kernels[¶](#qml-kernels "Permalink to this headline")

#### Overview[¶](#overview "Permalink to this headline")

This subpackage defines functions that relate to quantum kernel methods.

On one hand this includes functions to call a quantum kernel systematically

on training and test datasets to obtain the *kernel matrix*.

On the other hand it provides postprocessing methods for those kernel

matrices which can be used to mitigate device noise and sampling errors.

##### Functions[¶](#functions "Permalink to this headline")

| [`closest\_psd\_matrix`](index.html#pennylane.kernels.closest_psd_matrix "pennylane.kernels.closest_psd_matrix")(K[, fix\_diagonal, solver]) | Return the closest positive semi-definite matrix to the given kernel matrix. |

| [`displace\_matrix`](index.html#pennylane.kernels.displace_matrix "pennylane.kernels.displace_matrix")(K) | Remove negative eigenvalues from the given kernel matrix by adding a multiple of the identity matrix. |

| [`flip\_matrix`](index.html#pennylane.kernels.flip_matrix "pennylane.kernels.flip_matrix")(K) | Remove negative eigenvalues from the given kernel matrix by taking the absolute value. |

| [`kernel\_matrix`](index.html#pennylane.kernels.kernel_matrix "pennylane.kernels.kernel_matrix")(X1, X2, kernel) | Computes the matrix of pairwise kernel values for two given datasets. |

| [`mitigate\_depolarizing\_noise`](index.html#pennylane.kernels.mitigate_depolarizing_noise "pennylane.kernels.mitigate_depolarizing_noise")(K, num\_wires, method) | Estimate depolarizing noise rate(s) using on the diagonal entries of a kernel matrix and mitigate the noise, assuming a global depolarizing noise model. |

| [`polarity`](index.html#pennylane.kernels.polarity "pennylane.kernels.polarity")(X, Y, kernel[, …]) | Polarity of a given kernel function. |

| [`square\_kernel\_matrix`](index.html#pennylane.kernels.square_kernel_matrix "pennylane.kernels.square_kernel_matrix")(X, kernel[, …]) | Computes the square matrix of pairwise kernel values for a given dataset. |

| [`target\_alignment`](index.html#pennylane.kernels.target_alignment "pennylane.kernels.target_alignment")(X, Y, kernel[, …]) | Target alignment of a given kernel function. |

| [`threshold\_matrix`](index.html#pennylane.kernels.threshold_matrix "pennylane.kernels.threshold_matrix")(K) | Remove negative eigenvalues from the given kernel matrix. |

#### Description[¶](#description "Permalink to this headline")

Given a kernel

\[k: \mathbb{R}^d \times \mathbb{R}^d \to \mathbb{R}, \quad

(x\_1, x\_2)\mapsto k(x\_1, x\_2)\]

the kernel matrix of \(k\) on a training dataset

\(\{(x\_1, y\_1),\cdots (x\_n, y\_n)\}\) with \(x\_i\in\mathbb{R}^d\)

and \(y\_i\in\{-1, 1\}\) is defined as

\[K\_{ij} = k(x\_i, x\_j).\]

For valid kernels, this is a real symmetric positive semi-definite matrix.

We also define the *ideal kernel matrix* for the training dataset which

perfectly predicts whether two points have identical labels or not:

\[K^\ast\_{ij} = y\_i y\_j\]

We can measure the similarity between \(K\) and \(K^\ast\),

through the *kernel polarity* which can be expressed as the Frobenius inner

product between the two matrices:

\[\operatorname{P}(k) = \langle K^\ast, K \rangle\_F = \sum\_{i,j=1}^n y\_i y\_j k(x\_i, x\_j)\]

Additionally, there is the *kernel-target alignment*, which is the normalized

counterpart to the kernel polarity:

\[\begin{split} \operatorname{TA}(k) &= \frac{P(k)}{\lVert K^\ast \rVert\_F\;\lVert K \rVert\_F}\\

 \lVert K\rVert\_F &= \sqrt{\sum\_{i,j=1}^n k(x\_i, x\_j)^2}\\

\lVert K^\ast\rVert\_F &= \sqrt{\sum\_{i,j=1}^n (y\_iy\_j)^2}\end{split}\]

For datasets with different numbers of training points per class the labels are rescaled

by the number of datapoints in the respective class to avoid that kernel polarity and

kernel-target alignment are dominated by the properties of the kernel for just a single class.

Given a callable kernel function, all these quantities can readily be computed

using the methods in this module.

### qml.logging[¶](#module-pennylane.logging "Permalink to this headline")

This module enables support for log-level messaging throughout PennyLane, following the native Python logging framework interface. Please see the [PennyLane logging development guidelines](index.html#document-development/guide/logging), and the official Python documentation for details on usage <https://docs.python.org/3/library/logging.html>

#### Functions[¶](#functions "Permalink to this headline")

| [`config\_path`](index.html#pennylane.logging.config_path "pennylane.logging.config_path")() | This method returns the full absolute path to the the `log\_config.toml` configuration file. |

| [`enable\_logging`](index.html#pennylane.logging.enable_logging "pennylane.logging.enable_logging")() | This method allows to selectively enable logging throughout PennyLane, following the configuration options defined in the `log\_config.toml` file. |

#### Classes[¶](#classes "Permalink to this headline")

| [`DebugOnlyFilter`](index.html#pennylane.logging.DebugOnlyFilter "pennylane.logging.DebugOnlyFilter")([name]) | Filters logs that are less verbose than the DEBUG level (CRITICAL, ERROR, WARN & INFO). |

| [`DefaultFormatter`](index.html#pennylane.logging.DefaultFormatter "pennylane.logging.DefaultFormatter")([fmt, datefmt, style, validate]) | This formatter has the default rules used for formatting PennyLane log messages. |

| [`LocalProcessFilter`](index.html#pennylane.logging.LocalProcessFilter "pennylane.logging.LocalProcessFilter")() | Filters logs not originating from the current executing Python process ID. |

| [`SimpleFormatter`](index.html#pennylane.logging.SimpleFormatter "pennylane.logging.SimpleFormatter")([fmt, datefmt, style, validate]) | This formatter has a simplified layout and rules used for formatting PennyLane log messages. |

### qml.math[¶](#module-pennylane.math "Permalink to this headline")

This package contains unified functions for framework-agnostic tensor and array

manipulation. Given the input tensor-like object, the call is dispatched

to the corresponding array manipulation framework, allowing for end-to-end

differentiation to be preserved.

Warning

These functions are experimental, and only a subset of common functionality is supported.

Furthermore, the names and behaviour of these functions may differ from similar

functions in common frameworks; please refer to the function docstrings for more details.

The following frameworks are currently supported:

* NumPy

* Autograd

* TensorFlow

* PyTorch

* JAX

#### Functions[¶](#functions "Permalink to this headline")

| [`add`](index.html#pennylane.math.add "pennylane.math.add")(\*args[, like]) | Add arguments element-wise. |

| [`allclose`](index.html#pennylane.math.allclose "pennylane.math.allclose")(a, b[, rtol, atol]) | Returns True if two arrays are element-wise equal within a tolerance. |

| [`allequal`](index.html#pennylane.math.allequal "pennylane.math.allequal")(tensor1, tensor2, \*\*kwargs) | Returns True if two tensors are element-wise equal along a given axis. |

| [`array`](index.html#pennylane.math.array "pennylane.math.array")(\*args[, like]) | Creates an array or tensor object of the target framework. |

| [`block\_diag`](index.html#pennylane.math.block_diag "pennylane.math.block_diag")(values[, like]) | Combine a sequence of 2D tensors to form a block diagonal tensor. |

| [`cast`](index.html#pennylane.math.cast "pennylane.math.cast")(tensor, dtype) | Casts the given tensor to a new type. |

| [`cast\_like`](index.html#pennylane.math.cast_like "pennylane.math.cast_like")(tensor1, tensor2) | Casts a tensor to the same dtype as another. |

| [`concatenate`](index.html#pennylane.math.concatenate "pennylane.math.concatenate")(values[, axis, like]) | Concatenate a sequence of tensors along the specified axis. |

| [`convert\_like`](index.html#pennylane.math.convert_like "pennylane.math.convert_like")(tensor1, tensor2) | Convert a tensor to the same type as another. |

| [`cov\_matrix`](index.html#pennylane.math.cov_matrix "pennylane.math.cov_matrix")(prob, obs[, wires, diag\_approx]) | Calculate the covariance matrix of a list of commuting observables, given the joint probability distribution of the system in the shared eigenbasis. |

| [`detach`](index.html#pennylane.math.detach "pennylane.math.detach")(tensor[, like]) | Detach a tensor from its trace and return just its numerical values. |

| [`diag`](index.html#pennylane.math.diag "pennylane.math.diag")(values[, k, like]) | Construct a diagonal tensor from a list of scalars. |

| [`dm\_from\_state\_vector`](index.html#pennylane.math.dm_from_state_vector "pennylane.math.dm_from_state_vector")(state[, check\_state, …]) | Convenience function to compute a (full) density matrix from a state vector. |

| [`dot`](index.html#pennylane.math.dot "pennylane.math.dot")(tensor1, tensor2[, like]) | Returns the matrix or dot product of two tensors. |

| [`einsum`](index.html#pennylane.math.einsum "pennylane.math.einsum")(indices, \*operands[, like, optimize]) | Evaluates the Einstein summation convention on the operands. |

| [`expand\_matrix`](index.html#pennylane.math.expand_matrix "pennylane.math.expand_matrix")(mat, wires[, wire\_order, …]) | Re-express a matrix acting on a subspace defined by a set of wire labels according to a global wire order. |

| [`eye`](index.html#pennylane.math.eye "pennylane.math.eye")(\*args[, like]) | Creates an identity array or tensor object of the target framework. |

| [`fidelity`](index.html#pennylane.math.fidelity "pennylane.math.fidelity")(state0, state1[, check\_state, c\_dtype]) | Compute the fidelity for two states (given as density matrices) acting on quantum systems with the same size. |

| [`fidelity\_statevector`](index.html#pennylane.math.fidelity_statevector "pennylane.math.fidelity_statevector")(state0, state1[, …]) | Compute the fidelity for two states (given as state vectors) acting on quantum systems with the same size. |

| [`frobenius\_inner\_product`](index.html#pennylane.math.frobenius_inner_product "pennylane.math.frobenius_inner_product")(A, B[, normalize, like]) | Frobenius inner product between two matrices. |

| [`get\_dtype\_name`](index.html#pennylane.math.get_dtype_name "pennylane.math.get_dtype_name")(x) | An interface independent way of getting the name of the datatype. |

| [`get\_interface`](index.html#pennylane.math.get_interface "pennylane.math.get_interface")(\*values) | Determines the correct framework to dispatch to given a tensor-like object or a sequence of tensor-like objects. |

| [`get\_trainable\_indices`](index.html#pennylane.math.get_trainable_indices "pennylane.math.get_trainable_indices")(values[, like]) | Returns a set containing the trainable indices of a sequence of values. |

| [`in\_backprop`](index.html#pennylane.math.in_backprop "pennylane.math.in_backprop")(tensor[, interface]) | Returns True if the tensor is considered to be in a backpropagation environment, it works for Autograd, Tensorflow and Jax. |

| [`is\_abstract`](index.html#pennylane.math.is_abstract "pennylane.math.is_abstract")(tensor[, like]) | Returns True if the tensor is considered abstract. |

| [`is\_independent`](index.html#pennylane.math.is_independent "pennylane.math.is_independent")(func, interface, args[, …]) | Test whether a function is independent of its input arguments, both numerically and analytically. |

| [`iscomplex`](index.html#pennylane.math.iscomplex "pennylane.math.iscomplex")(tensor[, like]) | Return True if the tensor has a non-zero complex component. |

| [`marginal\_prob`](index.html#pennylane.math.marginal_prob "pennylane.math.marginal_prob")(prob, axis) | Compute the marginal probability given a joint probability distribution expressed as a tensor. |

| [`max\_entropy`](index.html#pennylane.math.max_entropy "pennylane.math.max_entropy")(state, indices[, base, …]) | Compute the maximum entropy of a density matrix on a given subsystem. |

| [`multi\_dispatch`](index.html#pennylane.math.multi_dispatch "pennylane.math.multi_dispatch")([argnum, tensor\_list]) | Decorater to dispatch arguments handled by the interface. |

| [`mutual\_info`](index.html#pennylane.math.mutual_info "pennylane.math.mutual_info")(state, indices0, indices1[, …]) | Compute the mutual information between two subsystems given a state: |

| [`ones\_like`](index.html#pennylane.math.ones_like "pennylane.math.ones_like")(tensor[, dtype]) | Returns a tensor of all ones with the same shape and dtype as the input tensor. |

| [`purity`](index.html#pennylane.math.purity "pennylane.math.purity")(state, indices[, check\_state, c\_dtype]) | Computes the purity of a density matrix. |

| [`reduce\_dm`](index.html#pennylane.math.reduce_dm "pennylane.math.reduce_dm")(density\_matrix, indices[, …]) | Compute the density matrix from a state represented with a density matrix. |

| [`reduce\_statevector`](index.html#pennylane.math.reduce_statevector "pennylane.math.reduce_statevector")(state, indices[, …]) | Compute the density matrix from a state vector. |

| [`relative\_entropy`](index.html#pennylane.math.relative_entropy "pennylane.math.relative_entropy")(state0, state1[, base, …]) | Compute the quantum relative entropy of one state with respect to another. |

| [`requires\_grad`](index.html#pennylane.math.requires_grad "pennylane.math.requires_grad")(tensor[, interface]) | Returns True if the tensor is considered trainable. |

| [`sqrt\_matrix`](index.html#pennylane.math.sqrt_matrix "pennylane.math.sqrt_matrix")(density\_matrix) | Compute the square root matrix of a density matrix where \(\rho = \sqrt{\rho} \times \sqrt{\rho}\) |

| [`scatter\_element\_add`](index.html#pennylane.math.scatter_element_add "pennylane.math.scatter_element_add")(tensor, index, value[, like]) | In-place addition of a multidimensional value over various indices of a tensor. |

| [`stack`](index.html#pennylane.math.stack "pennylane.math.stack")(values[, axis, like]) | Stack a sequence of tensors along the specified axis. |

| [`tensordot`](index.html#pennylane.math.tensordot "pennylane.math.tensordot")(tensor1, tensor2[, axes, like]) | Returns the tensor product of two tensors. |

| [`trace\_distance`](index.html#pennylane.math.trace_distance "pennylane.math.trace_distance")(state0, state1[, …]) | Compute the trace distance between two quantum states. |

| [`unwrap`](index.html#pennylane.math.unwrap "pennylane.math.unwrap")(values[, max\_depth]) | Unwrap a sequence of objects to NumPy arrays. |

| [`vn\_entropy`](index.html#pennylane.math.vn_entropy "pennylane.math.vn_entropy")(state, indices[, base, …]) | Compute the Von Neumann entropy from a density matrix on a given subsystem. |

| [`where`](index.html#pennylane.math.where "pennylane.math.where")(condition[, x, y]) | Returns elements chosen from x or y depending on a boolean tensor condition, or the indices of entries satisfying the condition. |

### qml.numpy[¶](#module-pennylane.numpy "Permalink to this headline")

#### Overview[¶](#overview "Permalink to this headline")

The PennyLane NumPy subpackage provides a differentiable wrapper around NumPy, that enables

backpropagation through standard NumPy code.

This version of NumPy **must** be used when using PennyLane with the [Autograd interface](index.html#document-introduction/interfaces/numpy):

```

>>> from pennylane import numpy as np

```

Note

If using other interfaces, such as [TensorFlow](index.html#document-introduction/interfaces/tf) [PyTorch](index.html#document-introduction/interfaces/torch), or [JAX](index.html#document-introduction/interfaces/jax), then the

PennyLane-provided NumPy should not be used; instead, simply use the standard NumPy import.

This package is a wrapper around `autograd.numpy`; for details on all available functions,

please refer to the [Autograd

docs](https://github.com/HIPS/autograd/blob/master/docs/tutorial.md).

PennyLane additionally extends Autograd with the following classes,

errors, and functions:

| [`wrap\_arrays`](index.html#pennylane.numpy.wrap_arrays "pennylane.numpy.wrap_arrays") | Loop through an object’s symbol table, wrapping each function with [`tensor\_wrapper()`](index.html#pennylane.numpy.tensor_wrapper "pennylane.numpy.tensor_wrapper"). |

| [`extract\_tensors`](index.html#pennylane.numpy.extract_tensors "pennylane.numpy.extract_tensors") | Iterate through an iterable, and extract any PennyLane tensors that appear. |

| [`tensor\_wrapper`](index.html#pennylane.numpy.tensor_wrapper "pennylane.numpy.tensor_wrapper") | Decorator that wraps callable objects and classes so that they both accept a `requires\_grad` keyword argument, as well as returning a PennyLane [`tensor`](index.html#pennylane.numpy.tensor "pennylane.numpy.tensor"). |

| [`tensor`](index.html#pennylane.numpy.tensor "pennylane.numpy.tensor") | Constructs a PennyLane tensor for use with Autograd QNodes. |

| [`NonDifferentiableError`](index.html#pennylane.numpy.NonDifferentiableError "pennylane.numpy.NonDifferentiableError") | Exception raised if attempting to differentiate non-trainable [`tensor`](index.html#pennylane.numpy.tensor "pennylane.numpy.tensor") using Autograd. |

#### Caveats[¶](#caveats "Permalink to this headline")

This package is a wrapper around `autograd.numpy`, and therefore comes with several caveats

inherited from Autograd:

**Do not use:**

* Assignment to arrays, such as `A[0, 0] = x`.

* Implicit casting of lists to arrays, for example `A = np.sum([x, y])`.

Make sure to explicitly cast to a NumPy array first, i.e.,

`A = np.sum(np.array([x, y]))` instead.

* `A.dot(B)` notation. Use `np.dot(A, B)` or `A @ B` instead.

* In-place operations such as `a += b`. Use `a = a + b` instead.

* Some `isinstance` checks, like `isinstance(x, np.ndarray)` or `isinstance(x, tuple)`,

without first doing `from autograd.builtins import isinstance, tuple`.

For more details, please consult the [Autograd

docs](https://github.com/HIPS/autograd/blob/master/docs/tutorial.md).

### qml.ops.op\_math[¶](#module-pennylane.ops.op_math "Permalink to this headline")

This module contains classes and functions for Operator arithmetic.

#### Constructor Functions[¶](#constructor-functions "Permalink to this headline")

| [`adjoint`](index.html#pennylane.adjoint "pennylane.adjoint")(fn[, lazy]) | Create the adjoint of an Operator or a function that applies the adjoint of the provided function. |

| [`ctrl`](index.html#pennylane.ctrl "pennylane.ctrl")(op, control[, control\_values, work\_wires]) | Create a method that applies a controlled version of the provided op. |

| [`exp`](index.html#pennylane.exp "pennylane.exp")(op[, coeff, num\_steps, id]) | Take the exponential of an Operator times a coefficient. |

| [`sum`](index.html#pennylane.sum "pennylane.sum")(\*summands[, id, lazy]) | Construct an operator which is the sum of the given operators. |

| [`pow`](index.html#pennylane.pow "pennylane.pow")(base[, z, lazy, id]) | Raise an Operator to a power. |

| [`prod`](index.html#pennylane.prod "pennylane.prod")(\*ops[, id, lazy]) | Construct an operator which represents the generalized product of the operators provided. |

| [`s\_prod`](index.html#pennylane.s_prod "pennylane.s_prod")(scalar, operator[, lazy, id]) | Construct an operator which is the scalar product of the given scalar and operator provided. |

#### Symbolic Classes[¶](#symbolic-classes "Permalink to this headline")

| [`Adjoint`](index.html#pennylane.ops.op_math.Adjoint "pennylane.ops.op_math.Adjoint")([base, id]) | The Adjoint of an operator. |

| [`CompositeOp`](index.html#pennylane.ops.op_math.CompositeOp "pennylane.ops.op_math.CompositeOp")(\*operands[, id]) | A base class for operators that are composed of other operators. |

| [`Controlled`](index.html#pennylane.ops.op_math.Controlled "pennylane.ops.op_math.Controlled")(base, control\_wires[, …]) | Symbolic operator denoting a controlled operator. |

| [`ControlledOp`](index.html#pennylane.ops.op_math.ControlledOp "pennylane.ops.op_math.ControlledOp")(base, control\_wires[, …]) | Operation-specific methods and properties for the [`Controlled`](index.html#pennylane.ops.op_math.Controlled "pennylane.ops.op_math.Controlled") class. |

| [`Evolution`](index.html#pennylane.ops.op_math.Evolution "pennylane.ops.op_math.Evolution")(generator[, param, num\_steps, id]) | Create an exponential operator that defines a generator, of the form \(e^{-ix\hat{G}}\) |

| [`Exp`](index.html#pennylane.ops.op_math.Exp "pennylane.ops.op_math.Exp")(base[, coeff, num\_steps, id]) | A symbolic operator representing the exponential of a operator. |

| [`Pow`](index.html#pennylane.ops.op_math.Pow "pennylane.ops.op_math.Pow")([base, z, id]) | Symbolic operator denoting an operator raised to a power. |

| [`Prod`](index.html#pennylane.ops.op_math.Prod "pennylane.ops.op_math.Prod")(\*operands[, id]) | Symbolic operator representing the product of operators. |

| [`Sum`](index.html#pennylane.ops.op_math.Sum "pennylane.ops.op_math.Sum")(\*operands[, id]) | Symbolic operator representing the sum of operators. |

| [`SProd`](index.html#pennylane.ops.op_math.SProd "pennylane.ops.op_math.SProd")(scalar, base[, id]) | Arithmetic operator representing the scalar product of an operator with the given scalar. |

| [`SymbolicOp`](index.html#pennylane.ops.op_math.SymbolicOp "pennylane.ops.op_math.SymbolicOp")(base[, id]) | Developer-facing base class for single-operator symbolic operators. |

| [`ScalarSymbolicOp`](index.html#pennylane.ops.op_math.ScalarSymbolicOp "pennylane.ops.op_math.ScalarSymbolicOp")(base, scalar[, id]) | Developer-facing base class for single-operator symbolic operators that contain a scalar coefficient. |

#### Controlled Operator Classes[¶](#controlled-operator-classes "Permalink to this headline")

| [`ControlledQubitUnitary`](index.html#pennylane.ControlledQubitUnitary "pennylane.ControlledQubitUnitary")(U, control\_wires, …) | Apply an arbitrary fixed unitary to `wires` with control from the `control\_wires`. |

| [`CY`](index.html#pennylane.CY "pennylane.CY")(wires) | The controlled-Y operator |

| [`CZ`](index.html#pennylane.CZ "pennylane.CZ")(wires) | The controlled-Z operator |

#### Decompositions[¶](#decompositions "Permalink to this headline")

| [`ctrl\_decomp\_zyz`](index.html#pennylane.ops.op_math.ctrl_decomp_zyz "pennylane.ops.op_math.ctrl_decomp_zyz")(target\_operation, control\_wires) | Decompose the controlled version of a target single-qubit operation |

| [`ctrl\_decomp\_bisect`](index.html#pennylane.ops.op_math.ctrl_decomp_bisect "pennylane.ops.op_math.ctrl_decomp_bisect")(target\_operation, …) | Decompose the controlled version of a target single-qubit operation |

### qml.pauli[¶](#qml-pauli "Permalink to this headline")

#### Overview[¶](#overview "Permalink to this headline")

This module defines functions and classes for generating and manipulating

elements of the Pauli group. It also contains a subpackage `pauli/grouping`

for Pauli-word partitioning functionality used in measurement optimization.

##### Functions[¶](#functions "Permalink to this headline")

| [`are\_identical\_pauli\_words`](index.html#pennylane.pauli.are_identical_pauli_words "pennylane.pauli.are_identical_pauli_words")(pauli\_1, pauli\_2) | Performs a check if two Pauli words have the same `wires` and `name` attributes. |

| [`are\_pauli\_words\_qwc`](index.html#pennylane.pauli.are_pauli_words_qwc "pennylane.pauli.are_pauli_words_qwc")(lst\_pauli\_words) | Given a list of observables assumed to be valid Pauli words, determine if they are pairwise qubit-wise commuting. |

| [`binary\_to\_pauli`](index.html#pennylane.pauli.binary_to_pauli "pennylane.pauli.binary_to_pauli")(binary\_vector[, wire\_map]) | Converts a binary vector of even dimension to an Observable instance. |

| [`diagonalize\_pauli\_word`](index.html#pennylane.pauli.diagonalize_pauli_word "pennylane.pauli.diagonalize_pauli_word")(pauli\_word) | Transforms the Pauli word to diagonal form in the computational basis. |

| [`diagonalize\_qwc\_groupings`](index.html#pennylane.pauli.diagonalize_qwc_groupings "pennylane.pauli.diagonalize_qwc_groupings")(qwc\_groupings) | Diagonalizes a list of qubit-wise commutative groupings of Pauli strings. |

| [`diagonalize\_qwc\_pauli\_words`](index.html#pennylane.pauli.diagonalize_qwc_pauli_words "pennylane.pauli.diagonalize_qwc_pauli_words")(qwc\_grouping) | Diagonalizes a list of mutually qubit-wise commutative Pauli words. |

| [`group\_observables`](index.html#pennylane.pauli.group_observables "pennylane.pauli.group_observables")(observables[, …]) | Partitions a list of observables (Pauli operations and tensor products thereof) into groupings according to a binary relation (qubit-wise commuting, fully-commuting, or anticommuting). |

| [`is\_pauli\_word`](index.html#pennylane.pauli.is_pauli_word "pennylane.pauli.is_pauli_word")(observable) | Checks if an observable instance consists only of Pauli and Identity Operators. |

| [`is\_qwc`](index.html#pennylane.pauli.is_qwc "pennylane.pauli.is_qwc")(pauli\_vec\_1, pauli\_vec\_2) | Checks if two Pauli words in the binary vector representation are qubit-wise commutative. |

| [`observables\_to\_binary\_matrix`](index.html#pennylane.pauli.observables_to_binary_matrix "pennylane.pauli.observables_to_binary_matrix")(observables[, …]) | Converts a list of Pauli words to the binary vector representation and yields a row matrix of the binary vectors. |

| [`optimize\_measurements`](index.html#pennylane.pauli.optimize_measurements "pennylane.pauli.optimize_measurements")(observables[, …]) | Partitions then diagonalizes a list of Pauli words, facilitating simultaneous measurement of all observables within a partition. |

| [`partition\_pauli\_group`](index.html#pennylane.pauli.partition_pauli_group "pennylane.pauli.partition_pauli_group")(n\_qubits) | Partitions the \(n\)-qubit Pauli group into qubit-wise commuting terms. |

| [`pauli\_decompose`](index.html#pennylane.pauli.pauli_decompose "pennylane.pauli.pauli_decompose")(H[, hide\_identity, …]) | Decomposes a Hermitian matrix into a linear combination of Pauli operators. |

| [`pauli\_group`](index.html#pennylane.pauli.pauli_group "pennylane.pauli.pauli_group")(n\_qubits[, wire\_map]) | Generate the \(n\)-qubit Pauli group. |

| [`pauli\_mult`](index.html#pennylane.pauli.pauli_mult "pennylane.pauli.pauli_mult")(pauli\_1, pauli\_2[, wire\_map]) | Multiply two Pauli words together and return the product as a Pauli word. |

| [`pauli\_mult\_with\_phase`](index.html#pennylane.pauli.pauli_mult_with_phase "pennylane.pauli.pauli_mult_with_phase")(pauli\_1, pauli\_2[, …]) | Multiply two Pauli words together, and return both their product as a Pauli word and the global phase. |

| [`pauli\_sentence`](index.html#pennylane.pauli.pauli_sentence "pennylane.pauli.pauli_sentence")(op) | Return the PauliSentence representation of an arithmetic operator or Hamiltonian. |

| [`pauli\_to\_binary`](index.html#pennylane.pauli.pauli_to_binary "pennylane.pauli.pauli_to_binary")(pauli\_word[, n\_qubits, …]) | Converts a Pauli word to the binary vector representation. |

| [`pauli\_word\_prefactor`](index.html#pennylane.pauli.pauli_word_prefactor "pennylane.pauli.pauli_word_prefactor")(observable) | If the operator provided is a valid Pauli word (i.e a single term which may be a tensor product of pauli operators), then this function extracts the prefactor. |

| [`pauli\_word\_to\_matrix`](index.html#pennylane.pauli.pauli_word_to_matrix "pennylane.pauli.pauli_word_to_matrix")(pauli\_word[, wire\_map]) | Convert a Pauli word from a tensor to its matrix representation. |

| [`pauli\_word\_to\_string`](index.html#pennylane.pauli.pauli_word_to_string "pennylane.pauli.pauli_word_to_string")(pauli\_word[, wire\_map]) | Convert a Pauli word to a string. |

| [`qwc\_complement\_adj\_matrix`](index.html#pennylane.pauli.qwc_complement_adj_matrix "pennylane.pauli.qwc_complement_adj_matrix")(binary\_observables) | Obtains the adjacency matrix for the complementary graph of the qubit-wise commutativity graph for a given set of observables in the binary representation. |

| [`qwc\_rotation`](index.html#pennylane.pauli.qwc_rotation "pennylane.pauli.qwc_rotation")(pauli\_operators) | Performs circuit implementation of diagonalizing unitary for a Pauli word. |

| [`simplify`](index.html#pennylane.pauli.simplify "pennylane.pauli.simplify")(h[, cutoff]) | Add together identical terms in the Hamiltonian. |

| [`string\_to\_pauli\_word`](index.html#pennylane.pauli.string_to_pauli_word "pennylane.pauli.string_to_pauli_word")(pauli\_string[, wire\_map]) | Convert a string in terms of `'I'`, `'X'`, `'Y'`, and `'Z'` into a Pauli word for the given wire map. |

##### Classes[¶](#classes "Permalink to this headline")

| [`PauliGroupingStrategy`](index.html#pennylane.pauli.PauliGroupingStrategy "pennylane.pauli.PauliGroupingStrategy")(observables[, …]) | Class for partitioning a list of Pauli words according to some binary symmetric relation. |

| [`PauliSentence`](index.html#pennylane.pauli.PauliSentence "pennylane.pauli.PauliSentence") | Dictionary representing a linear combination of Pauli words, with the keys as PauliWord instances and the values correspond to coefficients. |

| [`PauliWord`](index.html#pennylane.pauli.PauliWord "pennylane.pauli.PauliWord")(mapping) | Immutable dictionary used to represent a Pauli Word, associating wires with their respective operators. |

#### PauliWord and PauliSentence[¶](#pauliword-and-paulisentence "Permalink to this headline")

The single-qubit Pauli group consists of the four single-qubit Pauli operations

[`Identity`](index.html#pennylane.Identity "pennylane.Identity"), [`PauliX`](index.html#pennylane.PauliX "pennylane.PauliX"),

[`PauliY`](index.html#pennylane.PauliY "pennylane.PauliY") , and [`PauliZ`](index.html#pennylane.PauliZ "pennylane.PauliZ"). The \(n\)-qubit

Pauli group is constructed by taking all possible \(N\)-fold tensor products

of these elements. Elements of the \(n\)-qubit Pauli group are known as

Pauli words, and have the form \(P\_J = \otimes\_{i=1}^{n}\sigma\_i^{(J)}\),

where \(\sigma\_i^{(J)}\) is one of the Pauli operators

([`PauliX`](index.html#pennylane.PauliX "pennylane.PauliX"), [`PauliY`](index.html#pennylane.PauliY "pennylane.PauliY"),

[`PauliZ`](index.html#pennylane.PauliZ "pennylane.PauliZ")) or identity ([`Identity`](index.html#pennylane.Identity "pennylane.Identity")) acting on

the \(i^{th}\) qubit. The full \(n\)-qubit Pauli group has size

\(4^n\) (neglecting the four possible global phases that may arise from

multiplication of its elements).

[`PauliWord`](index.html#pennylane.pauli.PauliWord "pennylane.pauli.PauliWord") is a lightweight class which uses a dictionary

approach to represent Pauli words. A [`PauliWord`](index.html#pennylane.pauli.PauliWord "pennylane.pauli.PauliWord") can be

instantiated by passing a dictionary of wires and their associated Pauli operators.

```

>>> from pennylane.pauli import PauliWord

>>> pw1 = qml.pauli.PauliWord({0:"X", 1:"Z"})  # X@Z

>>> pw2 = qml.pauli.PauliWord({0:"Y", 1:"Z"})  # Y@Z

>>> pw1, pw2

(X(0) @ Z(1), Y(0) @ Z(1))

```

The purpose of this class is to efficiently compute products of Pauli words and

obtain the matrix representation.

```

>>> pw1 \* pw2

(Z(0), 1j)

>>> pw1.to\_mat(wire\_order=[0, 1])

array([[ 0, 0, 1, 0],

 [ 0, 0, 0, -1],

 [ 1, 0, 0, 0],

 [ 0, -1, 0, 0]])

```

The [`PauliSentence`](index.html#pennylane.pauli.PauliSentence "pennylane.pauli.PauliSentence") class represents linear combinations of

Pauli words. Using a similar dictionary based approach we can efficiently add, multiply

and extract the matrix of operators in this representation.

```

>>> ps1 = qml.pauli.PauliSentence({pw1: 1.2, pw2: 0.5j})

>>> ps2 = qml.pauli.PauliSentence({pw1: -1.2})

>>> ps1

1.2 \* X(0) @ Z(1)

+ 0.5j \* Y(0) @ Z(1)

>>> ps1 + ps2

0.0 \* X(0) @ Z(1)

+ 0.5j \* Y(0) @ Z(1)

>>> ps1 \* ps2

-1.44 \* I

+ (-0.6+0j) \* Z(0)

>>> (ps1 + ps2).to\_mat(wire\_order=[0, 1])

array([[ 0. +0.j, 0. +0.j, 0.5+0.j, 0. +0.j],

 [ 0. +0.j, 0. +0.j, 0. +0.j, -0.5+0.j],

 [-0.5+0.j, 0. +0.j, 0. +0.j, 0. +0.j],

 [ 0. +0.j, 0.5+0.j, 0. +0.j, 0. +0.j]])

```

#### Graph colouring[¶](#module-pennylane.pauli.grouping.graph_colouring "Permalink to this headline")

A module for heuristic algorithms for colouring Pauli graphs.

A Pauli graph is a graph where vertices represent Pauli words and edges denote

if a specified symmetric binary relation (e.g., commutation) is satisfied for the

corresponding Pauli words. The graph-colouring problem is to assign a colour to

each vertex such that no vertices of the same colour are connected, using the

fewest number of colours (lowest “chromatic number”) as possible.

##### Functions[¶](#id1 "Permalink to this headline")

| [`largest\_first`](index.html#pennylane.pauli.grouping.graph_colouring.largest_first "pennylane.pauli.grouping.graph_colouring.largest_first")(binary\_observables, adj) | Performs graph-colouring using the Largest Degree First heuristic. |

| [`recursive\_largest\_first`](index.html#pennylane.pauli.grouping.graph_colouring.recursive_largest_first "pennylane.pauli.grouping.graph_colouring.recursive_largest_first")(binary\_observables, adj) | Performs graph-colouring using the Recursive Largest Degree First heuristic. |

#### Grouping observables[¶](#grouping-observables "Permalink to this headline")

Pauli words can be used for expressing a qubit [`Hamiltonian`](index.html#pennylane.Hamiltonian "pennylane.Hamiltonian").

A qubit Hamiltonian has the form \(H\_{q} = \sum\_{J} C\_J P\_J\) where

\(C\_{J}\) are numerical coefficients, and \(P\_J\) are Pauli words.

A list of Pauli words can be partitioned according to certain grouping

strategies. As an example, the [`group\_observables()`](index.html#pennylane.pauli.group_observables "pennylane.pauli.group_observables") function partitions

a list of observables (Pauli operations and tensor products thereof) into

groupings according to a binary relation (e.g., qubit-wise commuting):

```

>>> observables = [qml.PauliY(0), qml.PauliX(0) @ qml.PauliX(1), qml.PauliZ(1)]

>>> obs\_groupings = group\_observables(observables)

>>> obs\_groupings

[[PauliX(wires=[0]) @ PauliX(wires=[1])],

 [PauliY(wires=[0]), PauliZ(wires=[1])]]

```

The \(C\_{J}\) coefficients for each \(P\_J\) Pauli word making up a

Hamiltonian can also be specified along with further options, such as the

Pauli-word grouping method (e.g., *qubit-wise commuting*) and the underlying

graph-colouring algorithm (e.g., *recursive largest first*) used for creating

the groups of observables:

```

>>> obs = [qml.PauliY(0), qml.PauliX(0) @ qml.PauliX(1), qml.PauliZ(1)]

>>> coeffs = [1.43, 4.21, 0.97]

>>> obs\_groupings, coeffs\_groupings = group\_observables(obs, coeffs, 'qwc', 'rlf')

>>> obs\_groupings

[[PauliX(wires=[0]) @ PauliX(wires=[1])],

 [PauliY(wires=[0]), PauliZ(wires=[1])]]

>>> coeffs\_groupings

[[4.21], [1.43, 0.97]]

```

### qml.pulse[¶](#module-pennylane.pulse "Permalink to this headline")

Pulse programming is used in a variety of quantum systems for low-level control of quantum operations. A

time-dependent electromagnetic field tuned to the characteristic energies is applied,

leading to a time-dependent Hamiltonian interaction \(H(t)\). Driving the system with such an

electromagnetic field for a fixed time window is a **pulse program**. This pulse program can be tuned to

implement the higher level gates used for quantum computation.

The [`pulse`](#module-pennylane.pulse "pennylane.pulse") module provides functions and classes used to simulate pulse-level control of quantum

systems.

It contains a [`ParametrizedHamiltonian`](index.html#pennylane.pulse.ParametrizedHamiltonian "pennylane.pulse.ParametrizedHamiltonian") and [`ParametrizedEvolution`](index.html#pennylane.pulse.ParametrizedEvolution "pennylane.pulse.ParametrizedEvolution") class for

describing time-dependent Hamiltonian interactions. The [`pulse`](#module-pennylane.pulse "pennylane.pulse") module also includes several convenience

functions for defining pulses.

The [`pulse`](#module-pennylane.pulse "pennylane.pulse") module is written for `jax` and will not work with other machine learning frameworks

typically encountered in PennyLane. It requires separate installation, see

[jax.readthedocs.io](https://jax.readthedocs.io/en/latest/).

For a demonstration of the basic pulse functionality in PennyLane and running a ctrl-VQE example, see our demo on

[differentiable pulse programming](https://pennylane.ai/qml/demos/tutorial_pulse_programming101.html).

#### Overview[¶](#overview "Permalink to this headline")

##### Time evolution classes[¶](#time-evolution-classes "Permalink to this headline")

| [`ParametrizedHamiltonian`](index.html#pennylane.pulse.ParametrizedHamiltonian "pennylane.pulse.ParametrizedHamiltonian")(coeffs, observables) | Callable object holding the information representing a parametrized Hamiltonian. |

| [`ParametrizedEvolution`](index.html#pennylane.pulse.ParametrizedEvolution "pennylane.pulse.ParametrizedEvolution")(H[, params, t, …]) | Parametrized evolution gate, created by passing a [`ParametrizedHamiltonian`](index.html#pennylane.pulse.ParametrizedHamiltonian "pennylane.pulse.ParametrizedHamiltonian") to the [`evolve()`](index.html#pennylane.evolve "pennylane.evolve") function |

##### Convenience Functions[¶](#convenience-functions "Permalink to this headline")

| [`constant`](index.html#pennylane.pulse.constant "pennylane.pulse.constant")(scalar, time) | Returns the given `scalar`, for use in defining a [`ParametrizedHamiltonian`](index.html#pennylane.pulse.ParametrizedHamiltonian "pennylane.pulse.ParametrizedHamiltonian") with a trainable coefficient. |

| [`pwc`](index.html#pennylane.pulse.pwc "pennylane.pulse.pwc")(timespan) | Takes a time span and returns a callable for creating a function that is piece-wise constant in time. |

| [`pwc\_from\_function`](index.html#pennylane.pulse.pwc_from_function "pennylane.pulse.pwc_from_function")(timespan, num\_bins) | Decorates a smooth function, creating a piece-wise constant function that approximates it. |

| [`rect`](index.html#pennylane.pulse.rect "pennylane.pulse.rect")(x[, windows]) | Takes a scalar or a scalar-valued function, x, and applies a rectangular window to it, such that the returned function is x inside the window and 0 outside it. |

##### Hardware Compatible Hamiltonians[¶](#hardware-compatible-hamiltonians "Permalink to this headline")

| [`rydberg\_interaction`](index.html#pennylane.pulse.rydberg_interaction "pennylane.pulse.rydberg_interaction")(register[, wires, …]) | Returns a [`ParametrizedHamiltonian`](index.html#pennylane.pulse.ParametrizedHamiltonian "pennylane.pulse.ParametrizedHamiltonian") representing the interaction of an ensemble of Rydberg atoms due to the Rydberg blockade |

| [`rydberg\_drive`](index.html#pennylane.pulse.rydberg_drive "pennylane.pulse.rydberg_drive")(amplitude, phase, detuning, wires) | Returns a [`ParametrizedHamiltonian`](index.html#pennylane.pulse.ParametrizedHamiltonian "pennylane.pulse.ParametrizedHamiltonian") representing the action of a driving laser field |

| [`transmon\_interaction`](index.html#pennylane.pulse.transmon_interaction "pennylane.pulse.transmon_interaction")(qubit\_freq, …[, …]) | Returns a [`ParametrizedHamiltonian`](index.html#pennylane.pulse.ParametrizedHamiltonian "pennylane.pulse.ParametrizedHamiltonian") representing the circuit QED Hamiltonian of a superconducting transmon system. |

| [`transmon\_drive`](index.html#pennylane.pulse.transmon_drive "pennylane.pulse.transmon_drive")(amplitude, phase, freq, wires) | Returns a [`ParametrizedHamiltonian`](index.html#pennylane.pulse.ParametrizedHamiltonian "pennylane.pulse.ParametrizedHamiltonian") representing the drive term of a transmon qubit. |

#### Creating a parametrized Hamiltonian[¶](#creating-a-parametrized-hamiltonian "Permalink to this headline")

The [`pulse`](#module-pennylane.pulse "pennylane.pulse") module provides a framework to create a time-dependent Hamiltonian of the form

\[H(\{v\_j\}, t) = H\_\text{drift} + \sum\_j f\_j(v\_j, t) H\_j\]

with constant operators \(H\_j\) and scalar functions \(f\_j(v\_j, t)\) that may depend on

parameters \(p\) and time \(t\).

Defining a [`ParametrizedHamiltonian`](index.html#pennylane.pulse.ParametrizedHamiltonian "pennylane.pulse.ParametrizedHamiltonian") requires coefficients and operators, where some of the coefficients

are callables. The callables defining the parameterized coefficients must have the call signature `(p, t)`, where `p` can be a `float`,

`list` or `jnp.array`. These functions should be defined using `jax.numpy` rather than `numpy` where relevant.

```

import pennylane as qml

from jax import numpy as jnp

# defining the coefficients fj(p, t) for the two parametrized terms

f1 = lambda p, t: p \* jnp.sin(t) \* (t - 1)

f2 = lambda p, t: p[0] \* jnp.cos(p[1]\* t \*\* 2)

# defining the operations for the three terms in the Hamiltonian

XX = qml.PauliX(0) @ qml.PauliX(1)

YY = qml.PauliY(0) @ qml.PauliY(1)

ZZ = qml.PauliZ(0) @ qml.PauliZ(1)

```

There are two ways to construct a [`ParametrizedHamiltonian`](index.html#pennylane.pulse.ParametrizedHamiltonian "pennylane.pulse.ParametrizedHamiltonian") from the coefficients

and operators:

```

# Option 1

H1 =  2 \* XX + f1 \* YY + f2 \* ZZ

# Option 2

coeffs = [2, f1, f2]

ops = [XX, YY, ZZ]

H2 =  qml.dot(coeffs, ops)

```

Warning

When initializing a [`ParametrizedHamiltonian`](index.html#pennylane.pulse.ParametrizedHamiltonian "pennylane.pulse.ParametrizedHamiltonian") via a list of parametrized coefficients, it

is possible to create a list of multiple coefficients of the same form iteratively using lambda

functions, i.e.

`coeffs = [lambda p, t: p \* t for \_ in range(3)]`.

Be careful when defining coefficients using lambda functions within a list comprehension. Avoid

doing `coeffs = [lambda p, t: p \* t\*\*i for i in range(3)]`, which will only use the final index `i=2`

in the `lambda` and will thus behave as `coeffs = [(lambda p, t: p \* t\*\*2)] \* 3`.

Instead, use `coeffs = [lambda p, t, power=i: p \* t\*\*power for i in range(3)]`

The [`ParametrizedHamiltonian`](index.html#pennylane.pulse.ParametrizedHamiltonian "pennylane.pulse.ParametrizedHamiltonian") is a callable, and can return an [`Operator`](index.html#pennylane.operation.Operator "pennylane.operation.Operator") if passed a set of

parameters and a time at which to evaluate the coefficients \(f\_j\).

```

>>> H1

 (2\*(PauliX(wires=[0]) @ PauliX(wires=[1])))

+ (<lambda>(params\_0, t)\*(PauliY(wires=[0]) @ PauliY(wires=[1])))

+ (<lambda>(params\_1, t)\*(PauliZ(wires=[0]) @ PauliZ(wires=[1])))

```

```

>>> params = [1.2, [2.3, 3.4]]  # f1 takes a single parameter, f2 takes 2

>>> H1(params, t=0.5)

(2\*(PauliX(wires=[0]) @ PauliX(wires=[1]))) + ((-0.2876553535461426\*(PauliY(wires=[0]) @ PauliY(wires=[1]))) + (1.5179612636566162\*(PauliZ(wires=[0]) @ PauliZ(wires=[1]))))

```

When passing parameters, ensure that the order of the coefficient functions and the order of

the parameters match.

When initializing a [`ParametrizedHamiltonian`](index.html#pennylane.pulse.ParametrizedHamiltonian "pennylane.pulse.ParametrizedHamiltonian"), terms defined with fixed coefficients have to come

before parametrized terms to prevent discrepancy in the wire order.

Note

The [`ParametrizedHamiltonian`](index.html#pennylane.pulse.ParametrizedHamiltonian "pennylane.pulse.ParametrizedHamiltonian") must be Hermitian at all times. This is not explicitly

checked; ensuring a correctly defined Hamiltonian is the responsibility of the user.

#### ParametrizedEvolution[¶](#parametrizedevolution "Permalink to this headline")

During a pulse program spanning time \((t\_0, t\_1)\), the state evolves according to the time-dependent Schrodinger equation

\[\frac{\partial}{\partial t} |\psi\rangle = -i H(t) |\psi\rangle\]

realizing a unitary evolution \(U(t\_0, t\_1)\) of the input state, i.e.

\[|\psi(t\_1)\rangle = U(t\_0, t\_1) |\psi(t\_0)\rangle\]

A [`ParametrizedEvolution`](index.html#pennylane.pulse.ParametrizedEvolution "pennylane.pulse.ParametrizedEvolution") is this solution \(U(t\_0, t\_1)\) to the time-dependent

Schrödinger equation for a [`ParametrizedHamiltonian`](index.html#pennylane.pulse.ParametrizedHamiltonian "pennylane.pulse.ParametrizedHamiltonian").

The [`ParametrizedEvolution`](index.html#pennylane.pulse.ParametrizedEvolution "pennylane.pulse.ParametrizedEvolution") class uses a numerical ordinary differential equation

solver (see [jax.experimental.ode](https://github.com/google/jax/blob/main/jax/experimental/ode.py)). It

can be created using the [`evolve()`](index.html#pennylane.evolve "pennylane.evolve") function:

```

from jax import numpy as jnp

f1 = lambda p, t: p \* jnp.sin(t) \* (t - 1)

H = 2 \* qml.PauliX(0) + f1 \* qml.PauliY(1)

ev = qml.evolve(H)

```

```

>>> ev

ParametrizedEvolution(wires=[0, 1])

```

The initial [`ParametrizedEvolution`](index.html#pennylane.pulse.ParametrizedEvolution "pennylane.pulse.ParametrizedEvolution") does not have parameters defined, and so will

not have a matrix defined. To obtain an [`Operator`](index.html#pennylane.operation.Operator "pennylane.operation.Operator") with a matrix, we have to pass

parameters and a time interval:

```

>>> ev([1.2], t=[0, 4]).matrix()

Array([[-0.14115842+0.j , 0.03528605+0.j ,

 0. -0.95982337j, 0. +0.23993255j],

 [-0.03528605+0.j , -0.14115842+0.j ,

 0. -0.23993255j, 0. -0.95982337j],

 [ 0. -0.95982337j, 0. +0.23993255j,

 -0.14115842+0.j , 0.03528605+0.j ],

 [ 0. -0.23993255j, 0. -0.95982337j,

 -0.03528605+0.j , -0.14115842+0.j ]], dtype=complex64)

```

The parameters can be updated by calling the [`ParametrizedEvolution`](index.html#pennylane.pulse.ParametrizedEvolution "pennylane.pulse.ParametrizedEvolution") again with different inputs.

Additional options with regards to how the matrix is calculated can be passed to the [`ParametrizedEvolution`](index.html#pennylane.pulse.ParametrizedEvolution "pennylane.pulse.ParametrizedEvolution")

along with the parameters, as keyword arguments:

```

>>> qml.evolve(H)(params=[1.2], t=[0, 4], atol=1e-6, mxstep=1)

ParametrizedEvolution(Array(1.2, dtype=float32, weak\_type=True), wires=[0, 1])

```

The available keyword arguments can be found in in [`ParametrizedEvolution`](index.html#pennylane.pulse.ParametrizedEvolution "pennylane.pulse.ParametrizedEvolution"). If not specified, they

will default to predetermined values.

##### Using qml.evolve in a QNode[¶](#using-qml-evolve-in-a-qnode "Permalink to this headline")

The [`ParametrizedEvolution`](index.html#pennylane.pulse.ParametrizedEvolution "pennylane.pulse.ParametrizedEvolution") can be implemented in a QNode. We will evolve the

following [`ParametrizedHamiltonian`](index.html#pennylane.pulse.ParametrizedHamiltonian "pennylane.pulse.ParametrizedHamiltonian"):

```

from jax import numpy as jnp

f1 = lambda p, t: jnp.sin(p \* t)

H = f1 \* qml.PauliY(0)

```

Now we can execute the evolution of this Hamiltonian in a QNode and compute its gradient:

```

import jax

dev = qml.device("default.qubit.jax", wires=1)

@jax.jit

@qml.qnode(dev, interface="jax")

def circuit(params):

    qml.evolve(H)(params, t=[0, 10])

    return qml.expval(qml.PauliZ(0))

```

```

>>> params = [1.2]

>>> circuit(params)

Array(0.96632576, dtype=float32)

```

```

>>> jax.grad(circuit)(params)

[Array(2.3569832, dtype=float32)]

```

We can use the decorator `jax.jit` to compile this execution just-in-time. This means the first execution

will typically take a little longer with the benefit that all following executions will be significantly faster.

JIT-compiling is optional, and one can remove the decorator when only single executions are of interest. See the

`jax` docs on jitting for more information.

Warning

To find the simultaneous evolution of the two operators, it is important that they are included

in the same [`evolve()`](index.html#pennylane.evolve "pennylane.evolve"). For two non-commuting [`ParametrizedHamiltonian`](index.html#pennylane.pulse.ParametrizedHamiltonian "pennylane.pulse.ParametrizedHamiltonian")’s, applying

`qml.evolve(H1)(params, t=[0, 10])` followed by `qml.evolve(H2)(params, t=[0, 10])` will **not**

apply the two pulses simultaneously, despite the overlapping time window. Instead, they will be evolved

over the same timespan, but without taking into account how the evolution of `H1` affects `H2`.

See Usage Details of [`ParametrizedEvolution`](index.html#pennylane.pulse.ParametrizedEvolution "pennylane.pulse.ParametrizedEvolution") for a detailed example.

### qml.qinfo[¶](#qml-qinfo "Permalink to this headline")

#### Overview[¶](#overview "Permalink to this headline")

This module provides a collection of methods to return quantum information quantities from [`QNode`](index.html#pennylane.QNode "pennylane.QNode")

returning [`state()`](index.html#pennylane.state "pennylane.state").

#### Transforms[¶](#module-pennylane.qinfo.transforms "Permalink to this headline")

QNode transforms for the quantum information quantities.

##### Functions[¶](#functions "Permalink to this headline")

| [`classical\_fisher`](index.html#pennylane.qinfo.transforms.classical_fisher "pennylane.qinfo.transforms.classical_fisher")(qnode[, argnums]) | Returns a function that computes the classical fisher information matrix (CFIM) of a given [`QNode`](index.html#pennylane.QNode "pennylane.QNode") or quantum tape. |

| [`fidelity`](index.html#pennylane.qinfo.transforms.fidelity "pennylane.qinfo.transforms.fidelity")(qnode0, qnode1, wires0, wires1) | Compute the fidelity for two [`QNode`](index.html#pennylane.QNode "pennylane.QNode") returning a [`state()`](index.html#pennylane.state "pennylane.state") (a state can be a state vector or a density matrix, depending on the device) acting on quantum systems with the same size. |

| [`mutual\_info`](index.html#pennylane.qinfo.transforms.mutual_info "pennylane.qinfo.transforms.mutual_info")(qnode, wires0, wires1[, base]) | Compute the mutual information from a [`QNode`](index.html#pennylane.QNode "pennylane.QNode") returning a [`state()`](index.html#pennylane.state "pennylane.state"): |

| [`purity`](index.html#pennylane.qinfo.transforms.purity "pennylane.qinfo.transforms.purity")(qnode, wires) | Compute the purity of a [`QNode`](index.html#pennylane.QNode "pennylane.QNode") returning [`state()`](index.html#pennylane.state "pennylane.state"). |

| [`quantum\_fisher`](index.html#pennylane.qinfo.transforms.quantum_fisher "pennylane.qinfo.transforms.quantum_fisher")(qnode, \*args, \*\*kwargs) | Returns a function that computes the quantum fisher information matrix (QFIM) of a given [`QNode`](index.html#pennylane.QNode "pennylane.QNode"). |

| [`reduced\_dm`](index.html#pennylane.qinfo.transforms.reduced_dm "pennylane.qinfo.transforms.reduced_dm")(qnode, wires) | Compute the reduced density matrix from a [`QNode`](index.html#pennylane.QNode "pennylane.QNode") returning [`state()`](index.html#pennylane.state "pennylane.state"). |

| [`relative\_entropy`](index.html#pennylane.qinfo.transforms.relative_entropy "pennylane.qinfo.transforms.relative_entropy")(qnode0, qnode1, wires0, wires1) | Compute the relative entropy for two [`QNode`](index.html#pennylane.QNode "pennylane.QNode") returning a [`state()`](index.html#pennylane.state "pennylane.state") (a state can be a state vector or a density matrix, depending on the device) acting on quantum systems with the same size. |

| [`trace\_distance`](index.html#pennylane.qinfo.transforms.trace_distance "pennylane.qinfo.transforms.trace_distance")(qnode0, qnode1, wires0, wires1) | Compute the trace distance for two [`QNode`](index.html#pennylane.QNode "pennylane.QNode") returning a [`state()`](index.html#pennylane.state "pennylane.state") (a state can be a state vector or a density matrix, depending on the device) acting on quantum systems with the same size. |

| [`vn\_entropy`](index.html#pennylane.qinfo.transforms.vn_entropy "pennylane.qinfo.transforms.vn_entropy")(qnode, wires[, base]) | Compute the Von Neumann entropy from a [`QNode`](index.html#pennylane.QNode "pennylane.QNode") returning a [`state()`](index.html#pennylane.state "pennylane.state"). |

### qml.resource[¶](#module-pennylane.resource "Permalink to this headline")

The `resource` module provides classes and functionality to estimate the quantum resources

(number of qubits, circuit depth, etc.) required to implement advanced quantum algorithms.

#### Expectation Value Functions[¶](#expectation-value-functions "Permalink to this headline")

| [`estimate\_error`](index.html#pennylane.resource.estimate_error "pennylane.resource.estimate_error")(coeffs[, variances, shots]) | Estimate the error in computing an expectation value with a given number of measurements. |

| [`estimate\_shots`](index.html#pennylane.resource.estimate_shots "pennylane.resource.estimate_shots")(coeffs[, variances, error]) | Estimate the number of measurements required to compute an expectation value with a target error. |

#### Quantum Phase Estimation Resources[¶](#quantum-phase-estimation-resources "Permalink to this headline")

| [`FirstQuantization`](index.html#pennylane.resource.FirstQuantization "pennylane.resource.FirstQuantization")(n, eta[, omega, error, …]) | Estimate the number of non-Clifford gates and logical qubits for a quantum phase estimation algorithm in first quantization using a plane-wave basis. |

| [`DoubleFactorization`](index.html#pennylane.resource.DoubleFactorization "pennylane.resource.DoubleFactorization")(one\_electron, two\_electron) | Estimate the number of non-Clifford gates and logical qubits for a quantum phase estimation algorithm in second quantization with a double-factorized Hamiltonian. |

#### Resource Classes[¶](#resource-classes "Permalink to this headline")

| [`Resources`](index.html#pennylane.resource.Resources "pennylane.resource.Resources")([num\_wires, num\_gates, …]) | Contains attributes which store key resources such as number of gates, number of wires, shots, depth and gate types. |

| [`ResourcesOperation`](index.html#pennylane.resource.ResourcesOperation "pennylane.resource.ResourcesOperation")(\*params[, wires, id]) | Base class that represents quantum gates or channels applied to quantum states and stores the resource requirements of the quantum gate. |

#### Tracking Resources for Custom Operations[¶](#tracking-resources-for-custom-operations "Permalink to this headline")

We can use the `null.qubit` device with the `qml.Tracker` to track the resources

used in a quantum circuit with custom operations without execution.

```

class MyCustomAlgorithm(ResourcesOperation):

    num\_wires = 2

    def resources(self):

        return Resources(

            num\_wires=self.num\_wires,

            num\_gates=5,

            gate\_types={"Hadamard": 2, "CNOT": 1, "PauliZ": 2},

            gate\_sizes={1: 4, 2: 1},

            depth=3,

        )

dev = qml.device("null.qubit", wires=[0, 1, 2], shots=100)

@qml.qnode(dev)

def circuit(theta):

    qml.RZ(theta, wires=0)

    qml.CNOT(wires=[0,1])

    MyCustomAlgorithm(wires=[1, 2])

    return qml.expval(qml.PauliZ(wires=1))

x = np.array(1.23, requires\_grad=True)

with qml.Tracker(dev) as tracker:

    circuit(x)

```

We can examine the resources by accessing the `resources` key:

```

>>> resources\_lst = tracker.history['resources']

>>> print(resources\_lst[0])

wires: 3

gates: 7

depth: 5

shots: Shots(None)

gate\_types:

{"RZ": 1, "CNOT": 2, "Hadamard": 2, "PauliZ": 2}

gate\_sizes:

{1: 5, 2: 2}

```

### qml.shadows[¶](#qml-shadows "Permalink to this headline")

#### Overview[¶](#module-pennylane.shadows "Permalink to this headline")

##### Measurements[¶](#measurements "Permalink to this headline")

| [`classical\_shadow`](index.html#pennylane.classical_shadow "pennylane.classical_shadow")(wires[, seed]) | The classical shadow measurement protocol. |

| [`shadow\_expval`](index.html#pennylane.shadow_expval "pennylane.shadow_expval")(H[, k, seed]) | Compute expectation values using classical shadows in a differentiable manner. |

##### Shadow class for classical post-processing[¶](#shadow-class-for-classical-post-processing "Permalink to this headline")

| [`ClassicalShadow`](index.html#pennylane.ClassicalShadow "pennylane.ClassicalShadow")(bits, recipes[, wire\_map]) | Class for classical shadow post-processing expectation values, approximate states, and entropies. |

##### QNode transforms[¶](#qnode-transforms "Permalink to this headline")

| [`shadow\_expval`](index.html#pennylane.shadows.shadow_expval "pennylane.shadows.shadow_expval")(H[, k]) | Transform a QNode returning a classical shadow into one that returns the approximate expectation values in a differentiable manner. |

| [`shadow\_state`](index.html#pennylane.shadows.shadow_state "pennylane.shadows.shadow_state")(wires[, diffable]) | Transform a QNode returning a classical shadow into one that returns the reconstructed state in a differentiable manner. |

##### Classical Shadows formalism[¶](#classical-shadows-formalism "Permalink to this headline")

Note

As per [arXiv:2103.07510](https://arxiv.org/abs/2103.07510), when computing multiple expectation values it is advisable to directly estimate the desired observables by simultaneously measuring

qubit-wise-commuting terms. One way of doing this in PennyLane is via [`Hamiltonian`](index.html#pennylane.Hamiltonian "pennylane.Hamiltonian") and setting `grouping\_type="qwc"`. For more details on this topic, see the PennyLane demo

on [estimating expectation values with classical shadows](https://pennylane.ai/qml/demos/tutorial_diffable_shadows.html).

A [`ClassicalShadow`](index.html#pennylane.ClassicalShadow "pennylane.ClassicalShadow") is a classical description of a quantum state that is capable of reproducing expectation values of local Pauli observables, see [arXiv:2002.08953](https://arxiv.org/abs/2002.08953).

The idea is to capture \(T\) local snapshots (given by the `shots` set in the device) of the state by performing measurements in random Pauli bases at each qubit.

The measurement outcomes, denoted `bits`, as well as the choices of measurement bases, `recipes`, are recorded in two `(T, len(wires))` integer tensors, respectively.

From the \(t\)-th measurement, we can reconstruct the `local\_snapshots` (see [`ClassicalShadow`](index.html#pennylane.ClassicalShadow "pennylane.ClassicalShadow") methods)

\[\rho^{(t)} = \bigotimes\_{i=1}^{n} 3 U^\dagger\_i |b\_i \rangle \langle b\_i | U\_i - \mathbb{I},\]

where \(U\_i\) is the rotation corresponding to the measurement (e.g. \(U\_i=H\) for measurement in \(X\)) of qubit \(i\) at snapshot \(t\) and

\(|b\_i\rangle = (1 - b\_i, b\_i)\)

the corresponding computational basis state given the output bit \(b\_i\).

From these local snapshots, one can compute expectation values of local Pauli strings, where locality refers to the number of non-Identity operators.

The accuracy of the procedure is determined by the number of measurements \(T\) (`shots`).

To target an error \(\epsilon\), one needs of order \(T = \mathcal{O}\left( \log(M) 4^\ell/\epsilon^2 \right)\) measurements to determine \(M\) different,

\(\ell\)-local observables.

One can in principle also reconstruct the global state \(\sum\_t \rho^{(t)}/T\), though it is not advisable nor practical for larger systems due to its exponential scaling.

##### Basic usage[¶](#basic-usage "Permalink to this headline")

The easiest way of computing expectation values with classical shadows in PennyLane is to return [`shadow\_expval()`](index.html#pennylane.shadow_expval "pennylane.shadow_expval") directly from the qnode.

```

H = qml.Hamiltonian([1., 1.], [qml.PauliZ(0) @ qml.PauliZ(1), qml.PauliX(0) @ qml.PauliX(1)])

dev = qml.device("default.qubit", wires=range(2), shots=10000)

@qml.qnode(dev)

def qnode(x):

    qml.Hadamard(0)

    qml.CNOT((0,1))

    qml.RX(x, wires=0)

    return qml.shadow\_expval(H)

x = np.array(0.5, requires\_grad=True)

```

The big advantage of this way of computing expectation values is that it is differentiable.

```

>>> qnode(x)

tensor(1.827, requires\_grad=True)

>>> qml.grad(qnode)(x)

-0.44999999999999984

```

There are more options for post-processing classical shadows in [`ClassicalShadow`](index.html#pennylane.ClassicalShadow "pennylane.ClassicalShadow").

### qml.transforms[¶](#module-pennylane.transforms "Permalink to this headline")

This subpackage contains QNode, quantum function, device, and tape transforms.

#### Transforms[¶](#transforms "Permalink to this headline")

##### Transforms that act on QNodes[¶](#transforms-that-act-on-qnodes "Permalink to this headline")

These transforms accept QNodes, and return new transformed functions

that compute the desired quantity.

| [`classical\_jacobian`](index.html#pennylane.transforms.classical_jacobian "pennylane.transforms.classical_jacobian")(qnode[, argnum, …]) | Returns a function to extract the Jacobian matrix of the classical part of a QNode. |

| [`batch\_params`](index.html#pennylane.batch_params "pennylane.batch_params")(tape[, all\_operations]) | Transform a QNode to support an initial batch dimension for operation parameters. |

| [`batch\_input`](index.html#pennylane.batch_input "pennylane.batch_input")(tape, argnum) | Transform a QNode to support an initial batch dimension for gate inputs. |

| [`batch\_partial`](index.html#pennylane.batch_partial "pennylane.batch_partial")(qnode[, all\_operations, …]) | Create a batched partial callable object from the QNode specified. |

| [`metric\_tensor`](index.html#pennylane.metric_tensor "pennylane.metric_tensor")(tape[, argnum, approx, …]) | Returns a function that computes the metric tensor of a given QNode or quantum tape. |

| [`adjoint\_metric\_tensor`](index.html#pennylane.adjoint_metric_tensor "pennylane.adjoint_metric_tensor")(circuit[, device, hybrid]) | Implements the adjoint method outlined in [Jones](https://arxiv.org/abs/2011.02991) to compute the metric tensor. |

| [`specs`](index.html#pennylane.specs "pennylane.specs")(qnode[, max\_expansion, expansion\_strategy]) | Resource information about a quantum circuit. |

| [`split\_non\_commuting`](index.html#pennylane.transforms.split_non_commuting "pennylane.transforms.split_non_commuting")(tape) | Splits a qnode measuring non-commuting observables into groups of commuting observables. |

##### Transforms that act on quantum functions[¶](#transforms-that-act-on-quantum-functions "Permalink to this headline")

These transforms accept quantum functions (Python functions

containing quantum operations) that are used to construct QNodes.

| [`cond`](index.html#pennylane.transforms.cond "pennylane.transforms.cond")(condition, true\_fn[, false\_fn]) | Condition a quantum operation on the results of mid-circuit qubit measurements. |

| [`defer\_measurements`](index.html#pennylane.defer_measurements "pennylane.defer_measurements")(tape) | Quantum function transform that substitutes operations conditioned on measurement outcomes to controlled operations. |

| [`apply\_controlled\_Q`](index.html#pennylane.apply_controlled_Q "pennylane.apply_controlled_Q")(fn, wires, target\_wire, …) | Provides the circuit to apply a controlled version of the \(\mathcal{Q}\) unitary defined in [this](https://arxiv.org/abs/1805.00109) paper. |

| [`quantum\_monte\_carlo`](index.html#pennylane.quantum_monte_carlo "pennylane.quantum_monte_carlo")(fn, wires, target\_wire, …) | Provides the circuit to perform the [quantum Monte Carlo estimation](https://arxiv.org/abs/1805.00109) algorithm. |

| [`insert`](index.html#pennylane.transforms.insert "pennylane.transforms.insert")(circuit, op, op\_args[, position, before]) | Insert an operation into specified points in an input circuit. |

##### Transforms for circuit compilation[¶](#transforms-for-circuit-compilation "Permalink to this headline")

This set of transforms accept quantum functions, and perform basic circuit compilation tasks.

| [`compile`](index.html#pennylane.compile "pennylane.compile")(tape[, pipeline, basis\_set, …]) | Compile a circuit by applying a series of transforms to a quantum function. |

| [`cancel\_inverses`](index.html#pennylane.transforms.cancel_inverses "pennylane.transforms.cancel_inverses")(tape) | Quantum function transform to remove any operations that are applied next to their (self-)inverses or adjoint. |

| [`commute\_controlled`](index.html#pennylane.transforms.commute_controlled "pennylane.transforms.commute_controlled")(tape[, direction]) | Quantum function transform to move commuting gates past control and target qubits of controlled operations. |

| [`merge\_rotations`](index.html#pennylane.transforms.merge_rotations "pennylane.transforms.merge_rotations")(tape[, atol, include\_gates]) | Quantum function transform to combine rotation gates of the same type that act sequentially. |

| [`single\_qubit\_fusion`](index.html#pennylane.transforms.single_qubit_fusion "pennylane.transforms.single_qubit_fusion")(tape[, atol, exclude\_gates]) | Quantum function transform to fuse together groups of single-qubit operations into a general single-qubit unitary operation ([`Rot`](index.html#pennylane.Rot "pennylane.Rot")). |

| [`unitary\_to\_rot`](index.html#pennylane.transforms.unitary_to_rot "pennylane.transforms.unitary_to_rot")(tape) | Quantum function transform to decomposes all instances of single-qubit and select instances of two-qubit [`QubitUnitary`](index.html#pennylane.QubitUnitary "pennylane.QubitUnitary") operations to parametrized single-qubit operations. |

| [`merge\_amplitude\_embedding`](index.html#pennylane.transforms.merge_amplitude_embedding "pennylane.transforms.merge_amplitude_embedding")(tape) | Quantum function transform to combine amplitude embedding templates that act on different qubits. |

| [`remove\_barrier`](index.html#pennylane.transforms.remove_barrier "pennylane.transforms.remove_barrier")(tape) | Quantum function transform to remove Barrier gates. |

| [`undo\_swaps`](index.html#pennylane.transforms.undo_swaps "pennylane.transforms.undo_swaps")(tape) | Quantum function transform to remove SWAP gates by running from right to left through the circuit changing the position of the qubits accordingly. |

| [`pattern\_matching\_optimization`](index.html#pennylane.transforms.pattern_matching_optimization "pennylane.transforms.pattern_matching_optimization")(tape, …[, …]) | Quantum function transform to optimize a circuit given a list of patterns (templates). |

| [`transpile`](index.html#pennylane.transforms.transpile "pennylane.transforms.transpile")(tape, coupling\_map) | Transpile a circuit according to a desired coupling map |

There are also utility functions and decompositions available that assist with

both transforms, and decompositions within the larger PennyLane codebase.

| [`one\_qubit\_decomposition`](index.html#pennylane.transforms.one_qubit_decomposition "pennylane.transforms.one_qubit_decomposition")(U, wire[, …]) | Decompose a one-qubit unitary \(U\) in terms of elementary operations. |

| [`two\_qubit\_decomposition`](index.html#pennylane.transforms.two_qubit_decomposition "pennylane.transforms.two_qubit_decomposition")(U, wires) | Decompose a two-qubit unitary \(U\) in terms of elementary operations. |

| [`set\_decomposition`](index.html#pennylane.transforms.set_decomposition "pennylane.transforms.set_decomposition")(custom\_decomps, dev[, …]) | Context manager for setting custom decompositions. |

| [`pattern\_matching`](index.html#pennylane.transforms.pattern_matching "pennylane.transforms.pattern_matching")(circuit\_dag, pattern\_dag) | Function that applies the pattern matching algorithm and returns the list of maximal matches. |

| [`to\_zx`](index.html#pennylane.transforms.to_zx "pennylane.transforms.to_zx")(tape[, expand\_measurement]) | This transform converts a PennyLane quantum tape to a ZX-Graph in the [PyZX framework](https://pyzx.readthedocs.io/en/latest/). |

| [`from\_zx`](index.html#pennylane.transforms.from_zx "pennylane.transforms.from_zx")(graph[, decompose\_phases]) | Converts a graph from [PyZX](https://pyzx.readthedocs.io/en/latest/) to a PennyLane tape, if the graph is diagram-like. |

There are also utility functions that take a circuit and return a DAG.

| [`commutation\_dag`](index.html#pennylane.transforms.commutation_dag "pennylane.transforms.commutation_dag")(circuit) | Construct the pairwise-commutation DAG (directed acyclic graph) representation of a quantum circuit. |

| [`CommutationDAG`](index.html#pennylane.transforms.CommutationDAG "pennylane.transforms.CommutationDAG")(tape) | Class to represent a quantum circuit as a directed acyclic graph (DAG). |

| [`CommutationDAGNode`](index.html#pennylane.transforms.CommutationDAGNode "pennylane.transforms.CommutationDAGNode")([op, wires, …]) | Class to store information about a quantum operation in a node of the commutation DAG. |

##### Transform for circuit cutting[¶](#transform-for-circuit-cutting "Permalink to this headline")

The [`cut\_circuit()`](index.html#pennylane.cut_circuit "pennylane.cut_circuit") transform accepts a QNode and returns a new function that cuts the original circuit,

allowing larger circuits to be split into smaller circuits that are compatible with devices that

have a restricted number of qubits.

| [`cut\_circuit`](index.html#pennylane.cut_circuit "pennylane.cut_circuit")(tape[, auto\_cutter, …]) | Cut up a quantum circuit into smaller circuit fragments. |

The [`cut\_circuit\_mc()`](index.html#pennylane.cut_circuit_mc "pennylane.cut_circuit_mc") transform is designed to be used for cutting circuits which contain [`sample()`](index.html#pennylane.sample "pennylane.sample")

measurements and is implemented using a Monte Carlo method. Similarly to the [`cut\_circuit()`](index.html#pennylane.cut_circuit "pennylane.cut_circuit")

transform, this transform accepts a QNode and returns a new function that cuts the original circuit.

This transform can also accept an optional classical processing function to calculate an

expectation value.

| [`cut\_circuit\_mc`](index.html#pennylane.cut_circuit_mc "pennylane.cut_circuit_mc")(tape[, …]) | Cut up a circuit containing sample measurements into smaller fragments using a Monte Carlo method. |

There are also low-level functions that can be used to build up the circuit cutting functionalities:

| [`tape\_to\_graph`](index.html#pennylane.transforms.qcut.tape_to_graph "pennylane.transforms.qcut.tape_to_graph")(tape) | Converts a quantum tape to a directed multigraph. |

| [`replace\_wire\_cut\_nodes`](index.html#pennylane.transforms.qcut.replace_wire_cut_nodes "pennylane.transforms.qcut.replace_wire_cut_nodes")(graph) | Replace each [`WireCut`](index.html#pennylane.WireCut "pennylane.WireCut") node in the graph with a `MeasureNode` and `PrepareNode`. |

| [`fragment\_graph`](index.html#pennylane.transforms.qcut.fragment_graph "pennylane.transforms.qcut.fragment_graph")(graph) | Fragments a graph into a collection of subgraphs as well as returning the communication ([quotient](https://en.wikipedia.org/wiki/Quotient_graph)) graph. |

| [`graph\_to\_tape`](index.html#pennylane.transforms.qcut.graph_to_tape "pennylane.transforms.qcut.graph_to_tape")(graph) | Converts a directed multigraph to the corresponding [`QuantumTape`](index.html#pennylane.tape.QuantumTape "pennylane.tape.QuantumTape"). |

| [`expand\_fragment\_tape`](index.html#pennylane.transforms.qcut.expand_fragment_tape "pennylane.transforms.qcut.expand_fragment_tape")(tape) | Expands a fragment tape into a sequence of tapes for each configuration of the contained `MeasureNode` and `PrepareNode` operations. |

| [`expand\_fragment\_tapes\_mc`](index.html#pennylane.transforms.qcut.expand_fragment_tapes_mc "pennylane.transforms.qcut.expand_fragment_tapes_mc")(tapes, …) | Expands fragment tapes into a sequence of random configurations of the contained pairs of `MeasureNode` and `PrepareNode` operations. |

| [`qcut\_processing\_fn`](index.html#pennylane.transforms.qcut.qcut_processing_fn "pennylane.transforms.qcut.qcut_processing_fn")(results, …[, …]) | Processing function for the [`cut\_circuit()`](index.html#pennylane.cut_circuit "pennylane.cut_circuit") transform. |

| [`qcut\_processing\_fn\_sample`](index.html#pennylane.transforms.qcut.qcut_processing_fn_sample "pennylane.transforms.qcut.qcut_processing_fn_sample")(results, …) | Function to postprocess samples for the [`cut\_circuit\_mc()`](index.html#pennylane.cut_circuit_mc "pennylane.cut_circuit_mc") transform. |

| [`qcut\_processing\_fn\_mc`](index.html#pennylane.transforms.qcut.qcut_processing_fn_mc "pennylane.transforms.qcut.qcut_processing_fn_mc")(results, …) | Function to postprocess samples for the [`cut\_circuit\_mc()`](index.html#pennylane.cut_circuit_mc "pennylane.cut_circuit_mc") transform. |

| [`CutStrategy`](index.html#pennylane.transforms.qcut.CutStrategy "pennylane.transforms.qcut.CutStrategy")([devices, max\_free\_wires, …]) | A circuit-cutting distribution policy for executing (large) circuits on available (comparably smaller) devices. |

| [`kahypar\_cut`](index.html#pennylane.transforms.qcut.kahypar_cut "pennylane.transforms.qcut.kahypar_cut")(graph, num\_fragments[, …]) | Calls [KaHyPar](https://kahypar.org/) to partition a graph. |

| [`place\_wire\_cuts`](index.html#pennylane.transforms.qcut.place_wire_cuts "pennylane.transforms.qcut.place_wire_cuts")(graph, cut\_edges) | Inserts a [`WireCut`](index.html#pennylane.WireCut "pennylane.WireCut") node for each provided cut edge into a circuit graph. |

| [`find\_and\_place\_cuts`](index.html#pennylane.transforms.qcut.find_and_place_cuts "pennylane.transforms.qcut.find_and_place_cuts")(graph[, cut\_method, …]) | Automatically finds and places optimal [`WireCut`](index.html#pennylane.WireCut "pennylane.WireCut") nodes into a given tape-converted graph using a customizable graph partitioning function. |

##### Transforms that act on tapes[¶](#transforms-that-act-on-tapes "Permalink to this headline")

These transforms accept quantum tapes, and return one or

more tapes as well as a classical processing function.

| [`broadcast\_expand`](index.html#pennylane.transforms.broadcast_expand "pennylane.transforms.broadcast_expand")(tape) | Expand a broadcasted tape into multiple tapes and a function that stacks and squeezes the results. |

| [`hamiltonian\_expand`](index.html#pennylane.transforms.hamiltonian_expand "pennylane.transforms.hamiltonian_expand")(tape[, group]) | Splits a tape measuring a Hamiltonian expectation into mutliple tapes of Pauli expectations, and provides a function to recombine the results. |

| [`sign\_expand`](index.html#pennylane.transforms.sign_expand "pennylane.transforms.sign_expand")(tape[, circuit, J, delta, controls]) | Splits a tape measuring a (fast-forwardable) Hamiltonian expectation into mutliple tapes of the Xi or sgn decomposition, and provides a function to recombine the results. |

| [`sum\_expand`](index.html#pennylane.transforms.sum_expand "pennylane.transforms.sum_expand")(tape[, group]) | Splits a quantum tape measuring a Sum expectation into multiple tapes of summand expectations, and provides a function to recombine the results. |

This transform accepts a single tape and returns a single tape:

| [`convert\_to\_numpy\_parameters`](index.html#pennylane.transforms.convert_to_numpy_parameters "pennylane.transforms.convert_to_numpy_parameters")(circuit) | Transforms a circuit to one with purely numpy parameters. |

#### Decorators and utility functions[¶](#decorators-and-utility-functions "Permalink to this headline")

The following decorators and convenience functions are provided

to help build custom QNode, quantum function, and tape transforms:

| [`single\_tape\_transform`](index.html#pennylane.single_tape_transform "pennylane.single_tape_transform")(transform\_fn) | For registering a tape transform that takes a tape and outputs a single new tape. |

| [`batch\_transform`](index.html#pennylane.batch_transform "pennylane.batch_transform")(\*args, \*\*kwargs) | Class for registering a tape transform that takes a tape, and outputs a batch of tapes to be independently executed on a quantum device. |

| [`qfunc\_transform`](index.html#pennylane.qfunc_transform "pennylane.qfunc_transform")(tape\_transform) | Given a function which defines a tape transform, convert the function into one that applies the tape transform to quantum functions (qfuncs). |

| [`op\_transform`](index.html#pennylane.op_transform "pennylane.op_transform")(\*args, \*\*kwargs) | Convert a function that applies to operators into a functional transform. |

| [`make\_tape`](index.html#pennylane.transforms.make_tape "pennylane.transforms.make_tape")(fn) | Returns a function that generates the tape from a quantum function without any operation queuing taking place. |

| [`map\_batch\_transform`](index.html#pennylane.transforms.map_batch_transform "pennylane.transforms.map_batch_transform")(transform, tapes) | Map a batch transform over multiple tapes. |

| [`create\_expand\_fn`](index.html#pennylane.transforms.create_expand_fn "pennylane.transforms.create_expand_fn")(depth[, stop\_at, device, …]) | Create a function for expanding a tape to a given depth, and with a specific stopping criterion. |

| [`create\_decomp\_expand\_fn`](index.html#pennylane.transforms.create_decomp_expand_fn "pennylane.transforms.create_decomp_expand_fn")(custom\_decomps, dev) | Creates a custom expansion function for a device that applies a set of specified custom decompositions. |

| [`expand\_invalid\_trainable`](index.html#pennylane.transforms.expand_invalid_trainable "pennylane.transforms.expand_invalid_trainable")(tape[, depth]) | Expand out a tape so that it supports differentiation of requested operations. |

| [`expand\_invalid\_trainable\_hadamard\_gradient`](index.html#pennylane.transforms.expand_invalid_trainable_hadamard_gradient "pennylane.transforms.expand_invalid_trainable_hadamard_gradient")(tape) | Expand out a tape so that it supports differentiation of requested operations with the Hadamard test gradient. |

| [`expand\_multipar`](index.html#pennylane.transforms.expand_multipar "pennylane.transforms.expand_multipar")(tape[, depth]) | Expand out a tape so that all its parametrized operations have a single parameter. |

| [`expand\_trainable\_multipar`](index.html#pennylane.transforms.expand_trainable_multipar "pennylane.transforms.expand_trainable_multipar")(tape[, depth]) | Expand out a tape so that all its trainable operations have a single parameter. |

| [`expand\_nonunitary\_gen`](index.html#pennylane.transforms.expand_nonunitary_gen "pennylane.transforms.expand_nonunitary_gen")(tape[, depth]) | Expand out a tape so that all its parametrized operations have a unitary generator. |

#### Transforms for error mitigation[¶](#transforms-for-error-mitigation "Permalink to this headline")

| [`mitigate\_with\_zne`](index.html#pennylane.transforms.mitigate_with_zne "pennylane.transforms.mitigate_with_zne")(circuit, scale\_factors, …) | Mitigate an input circuit using zero-noise extrapolation. |

| [`fold\_global`](index.html#pennylane.transforms.fold_global "pennylane.transforms.fold_global")(circuit, scale\_factor) | Differentiable circuit folding of the global unitary `circuit`. |

| [`poly\_extrapolate`](index.html#pennylane.transforms.poly_extrapolate "pennylane.transforms.poly_extrapolate")(x, y, order) | Extrapolator to \(f(0)\) for polynomial fit. |

| [`richardson\_extrapolate`](index.html#pennylane.transforms.richardson_extrapolate "pennylane.transforms.richardson_extrapolate")(x, y) | Polynomial fit where the degree of the polynomial is fixed to being equal to the length of `x`. |

#### Transforms core[¶](#transforms-core "Permalink to this headline")

| [`transform`](index.html#pennylane.transforms.core.transform "pennylane.transforms.core.transform")(quantum\_transform[, …]) | The transform function is to be used to validate and dispatch a quantum transform on PennyLane objects (tape, qfunc and Qnode). |

| [`transform\_dispatcher`](index.html#module-pennylane.transforms.core.transform_dispatcher "pennylane.transforms.core.transform_dispatcher") | This module contains the transform function, the transform dispatcher and the transform container. |

### qml.qaoa[¶](#qml-qaoa "Permalink to this headline")

#### Overview[¶](#overview "Permalink to this headline")

This module provides a collection of methods that help in the construction of

QAOA workflows.

#### Mixer Hamiltonians[¶](#module-pennylane.qaoa.mixers "Permalink to this headline")

Methods for constructing QAOA mixer Hamiltonians.

##### Functions[¶](#functions "Permalink to this headline")

| [`bit\_flip\_mixer`](index.html#pennylane.qaoa.mixers.bit_flip_mixer "pennylane.qaoa.mixers.bit_flip_mixer")(graph, b) | Creates a bit-flip mixer Hamiltonian. |

| [`x\_mixer`](index.html#pennylane.qaoa.mixers.x_mixer "pennylane.qaoa.mixers.x_mixer")(wires) | Creates a basic Pauli-X mixer Hamiltonian. |

| [`xy\_mixer`](index.html#pennylane.qaoa.mixers.xy_mixer "pennylane.qaoa.mixers.xy_mixer")(graph) | Creates a generalized SWAP/XY mixer Hamiltonian. |

#### Cost Hamiltonians[¶](#module-pennylane.qaoa.cost "Permalink to this headline")

Methods for generating QAOA cost Hamiltonians corresponding to

different optimization problems.

##### Functions[¶](#id1 "Permalink to this headline")

| [`bit\_driver`](index.html#pennylane.qaoa.cost.bit_driver "pennylane.qaoa.cost.bit_driver")(wires, b) | Returns the bit-driver cost Hamiltonian. |

| [`edge\_driver`](index.html#pennylane.qaoa.cost.edge_driver "pennylane.qaoa.cost.edge_driver")(graph, reward) | Returns the edge-driver cost Hamiltonian. |

| [`max\_clique`](index.html#pennylane.qaoa.cost.max_clique "pennylane.qaoa.cost.max_clique")(graph[, constrained]) | Returns the QAOA cost Hamiltonian and the recommended mixer corresponding to the Maximum Clique problem, for a given graph. |

| [`max\_independent\_set`](index.html#pennylane.qaoa.cost.max_independent_set "pennylane.qaoa.cost.max_independent_set")(graph[, constrained]) | For a given graph, returns the QAOA cost Hamiltonian and the recommended mixer corresponding to the Maximum Independent Set problem. |

| [`max\_weight\_cycle`](index.html#pennylane.qaoa.cost.max_weight_cycle "pennylane.qaoa.cost.max_weight_cycle")(graph[, constrained]) | Returns the QAOA cost Hamiltonian and the recommended mixer corresponding to the maximum-weighted cycle problem, for a given graph. |

| [`maxcut`](index.html#pennylane.qaoa.cost.maxcut "pennylane.qaoa.cost.maxcut")(graph) | Returns the QAOA cost Hamiltonian and the recommended mixer corresponding to the MaxCut problem, for a given graph. |

| [`min\_vertex\_cover`](index.html#pennylane.qaoa.cost.min_vertex_cover "pennylane.qaoa.cost.min_vertex_cover")(graph[, constrained]) | Returns the QAOA cost Hamiltonian and the recommended mixer corresponding to the Minimum Vertex Cover problem, for a given graph. |

#### QAOA Layers[¶](#module-pennylane.qaoa.layers "Permalink to this headline")

Methods that define cost and mixer layers for use in QAOA workflows.

##### Functions[¶](#id2 "Permalink to this headline")

| [`cost\_layer`](index.html#pennylane.qaoa.layers.cost_layer "pennylane.qaoa.layers.cost_layer")(gamma, hamiltonian) | Applies the QAOA cost layer corresponding to a cost Hamiltonian. |

| [`mixer\_layer`](index.html#pennylane.qaoa.layers.mixer_layer "pennylane.qaoa.layers.mixer_layer")(alpha, hamiltonian) | Applies the QAOA mixer layer corresponding to a mixer Hamiltonian. |

#### Cycle Optimization[¶](#cycle-optimization "Permalink to this headline")

The [`cycle`](index.html#module-pennylane.qaoa.cycle "pennylane.qaoa.cycle") module is available for additional functionality related to the maximum-weighted

cycle problem.

| [`cycle`](index.html#module-pennylane.qaoa.cycle "pennylane.qaoa.cycle") | Functionality for finding the maximum weighted cycle of directed graphs. |

#### Solving the MaxCut problem using QAOA[¶](#solving-the-maxcut-problem-using-qaoa "Permalink to this headline")

We can demonstrate the PennyLane QAOA functionality with a basic application of QAOA:

solving the [MaxCut](https://en.wikipedia.org/wiki/Maximum_cut) problem.

We begin by defining the set of wires on which QAOA is executed, as well as the graph

on which we will perform MaxCut. The node labels of the graph are the index of the wire to which they

correspond:

```

import pennylane as qml

from pennylane import qaoa

from networkx import Graph

# Defines the wires and the graph on which MaxCut is being performed

wires = range(3)

graph = Graph([(0, 1), (1, 2), (2, 0)])

```

We now obtain the QAOA cost and mixer Hamiltonians for MaxCut on the graph that we defined:

```

# Defines the QAOA cost and mixer Hamiltonians

cost\_h, mixer\_h = qaoa.maxcut(graph)

```

These cost and mixer Hamiltonians are then used to define layers of the variational QAOA ansatz,

which we implement as the following function:

```

# Defines a layer of the QAOA ansatz from the cost and mixer Hamiltonians

def qaoa\_layer(gamma, alpha):

    qaoa.cost\_layer(gamma, cost\_h)

    qaoa.mixer\_layer(alpha, mixer\_h)

```

Finally, the full QAOA circuit is built. We begin by initializing the wires in an even superposition over

computational basis states, and then repeatedly apply QAOA layers with the

`qml.layer` method. In this case we repeat the circuit twice:

```

# Repeatedly applies layers of the QAOA ansatz

def circuit(params, \*\*kwargs):

    for w in wires:

        qml.Hadamard(wires=w)

    qml.layer(qaoa\_layer, 2, params[0], params[1])

```

With the circuit defined, we call the device on which QAOA will be executed, as well as the `qml.ExpvalCost`, which

creates the QAOA cost function: the expected value of the cost Hamiltonian with respect to the parametrized output

of the QAOA circuit.

```

# Defines the device and the QAOA cost function

dev = qml.device('default.qubit', wires=len(wires))

cost\_function = qml.ExpvalCost(circuit, cost\_h, dev)

```

```

>>> print(cost\_function([[1, 1], [1, 1]]))

-1.8260274380964299

```

The QAOA cost function can then be optimized in the usual way, by calling one of the built-in PennyLane optimizers

and updating the variational parameters until the expected value of the cost Hamiltonian is minimized.

### qml.qchem[¶](#qml-qchem "Permalink to this headline")

#### Overview[¶](#overview "Permalink to this headline")

The quantum chemistry module provides the functionality to perform Hartree-Fock calculations

and construct observables such as molecular Hamiltonians as well as dipole moment, spin and particle

number observables.

This subpackage provides the functionality to perform quantum chemistry calculations.

##### Functions[¶](#functions "Permalink to this headline")

| [`active\_space`](index.html#pennylane.qchem.active_space "pennylane.qchem.active_space")(electrons, orbitals[, mult, …]) | Build the active space for a given number of active electrons and active orbitals. |

| [`atom\_basis\_data`](index.html#pennylane.qchem.atom_basis_data "pennylane.qchem.atom_basis_data")(name, atom[, load\_data]) | Generate default basis set parameters for an atom. |

| [`attraction\_integral`](index.html#pennylane.qchem.attraction_integral "pennylane.qchem.attraction_integral")(r, basis\_a, basis\_b[, …]) | Return a function that computes the nuclear attraction integral for two contracted Gaussian functions. |

| [`attraction\_matrix`](index.html#pennylane.qchem.attraction_matrix "pennylane.qchem.attraction_matrix")(basis\_functions, charges, r) | Return a function that computes the electron-nuclear attraction matrix for a given set of basis functions. |

| [`basis\_rotation`](index.html#pennylane.qchem.basis_rotation "pennylane.qchem.basis_rotation")(one\_electron, two\_electron[, …]) | Return the grouped coefficients and observables of a molecular Hamiltonian and the basis rotation unitaries obtained with the basis rotation grouping method. |

| [`clifford`](index.html#pennylane.qchem.clifford "pennylane.qchem.clifford")(generators, paulixops) | Compute a Clifford operator from a set of generators and Pauli-X operators. |

| [`contracted\_norm`](index.html#pennylane.qchem.contracted_norm "pennylane.qchem.contracted_norm")(l, alpha, a) | Compute the normalization constant for a contracted Gaussian function. |

| [`core\_matrix`](index.html#pennylane.qchem.core_matrix "pennylane.qchem.core_matrix")(basis\_functions, charges, r) | Return a function that computes the core matrix for a given set of basis functions. |

| [`decompose`](index.html#pennylane.qchem.decompose "pennylane.qchem.decompose")(hf\_file[, mapping, core, active]) | Decomposes the molecular Hamiltonian into a linear combination of Pauli operators using OpenFermion tools. |

| [`diff\_hamiltonian`](index.html#pennylane.qchem.diff_hamiltonian "pennylane.qchem.diff_hamiltonian")(mol[, cutoff, core, active, fs]) | Return a function that computes the qubit Hamiltonian. |

| [`dipole\_integrals`](index.html#pennylane.qchem.dipole_integrals "pennylane.qchem.dipole_integrals")(mol[, core, active]) | Return a function that computes the dipole moment integrals over the molecular orbitals. |

| [`dipole\_moment`](index.html#pennylane.qchem.dipole_moment "pennylane.qchem.dipole_moment")(mol[, cutoff, core, active]) | Return a function that computes the qubit dipole moment observable. |

| [`dipole\_of`](index.html#pennylane.qchem.dipole_of "pennylane.qchem.dipole_of")(symbols, coordinates[, name, …]) | Computes the electric dipole moment operator in the Pauli basis. |

| [`electron\_integrals`](index.html#pennylane.qchem.electron_integrals "pennylane.qchem.electron_integrals")(mol[, core, active]) | Return a function that computes the one- and two-electron integrals in the molecular orbital basis. |

| [`electron\_repulsion`](index.html#pennylane.qchem.electron_repulsion "pennylane.qchem.electron_repulsion")(la, lb, lc, ld, ra, rb, …) | Compute the electron-electron repulsion integral between four primitive Gaussian functions. |

| [`excitations`](index.html#pennylane.qchem.excitations "pennylane.qchem.excitations")(electrons, orbitals[, delta\_sz]) | Generate single and double excitations from a Hartree-Fock reference state. |

| [`excitations\_to\_wires`](index.html#pennylane.qchem.excitations_to_wires "pennylane.qchem.excitations_to_wires")(singles, doubles[, wires]) | Map the indices representing the single and double excitations generated with the function [`excitations()`](index.html#pennylane.qchem.excitations "pennylane.qchem.excitations") to the wires that the Unitary Coupled-Cluster (UCCSD) template will act on. |

| [`expansion`](index.html#pennylane.qchem.expansion "pennylane.qchem.expansion")(la, lb, ra, rb, alpha, beta, t) | Compute Hermite Gaussian expansion coefficients recursively for two Gaussian functions. |

| [`factorize`](index.html#pennylane.qchem.factorize "pennylane.qchem.factorize")(two\_electron[, tol\_factor, tol\_eigval]) | Return the double-factorized form of a two-electron integral tensor in spatial basis. |

| [`fermionic\_dipole`](index.html#pennylane.qchem.fermionic_dipole "pennylane.qchem.fermionic_dipole")(mol[, cutoff, core, active]) | Return a function that builds the fermionic dipole moment observable. |

| [`fermionic\_hamiltonian`](index.html#pennylane.qchem.fermionic_hamiltonian "pennylane.qchem.fermionic_hamiltonian")(mol[, cutoff, core, …]) | Return a function that computes the fermionic Hamiltonian. |

| [`fermionic\_observable`](index.html#pennylane.qchem.fermionic_observable "pennylane.qchem.fermionic_observable")(constant[, one, two, …]) | Create a fermionic observable from molecular orbital integrals. |

| [`gaussian\_kinetic`](index.html#pennylane.qchem.gaussian_kinetic "pennylane.qchem.gaussian_kinetic")(la, lb, ra, rb, alpha, beta) | Compute the kinetic integral for two primitive Gaussian functions. |

| [`gaussian\_moment`](index.html#pennylane.qchem.gaussian_moment "pennylane.qchem.gaussian_moment")(li, lj, ri, rj, alpha, beta, …) | Compute the one-dimensional multipole moment integral for two primitive Gaussian functions. |

| [`gaussian\_overlap`](index.html#pennylane.qchem.gaussian_overlap "pennylane.qchem.gaussian_overlap")(la, lb, ra, rb, alpha, beta) | Compute overlap integral for two primitive Gaussian functions. |

| [`givens\_decomposition`](index.html#pennylane.qchem.givens_decomposition "pennylane.qchem.givens_decomposition")(unitary) | Decompose a unitary into a sequence of Givens rotation gates with phase shifts and a diagonal phase matrix. |

| [`hermite\_moment`](index.html#pennylane.qchem.hermite_moment "pennylane.qchem.hermite_moment")(alpha, beta, t, order, r) | Compute the Hermite moment integral recursively. |

| [`hf\_energy`](index.html#pennylane.qchem.hf_energy "pennylane.qchem.hf_energy")(mol) | Return a function that computes the Hartree-Fock energy. |

| [`hf\_state`](index.html#pennylane.qchem.hf_state "pennylane.qchem.hf_state")(electrons, orbitals) | Generate the occupation-number vector representing the Hartree-Fock state. |

| [`import\_state`](index.html#pennylane.qchem.import_state "pennylane.qchem.import_state")(solver[, tol]) | Convert an external wavefunction to a state vector. |

| [`jordan\_wigner`](index.html#pennylane.qchem.jordan_wigner "pennylane.qchem.jordan_wigner")(op[, notation]) | Convert a fermionic operator to a qubit operator using the Jordan-Wigner mapping. |

| [`kinetic\_integral`](index.html#pennylane.qchem.kinetic_integral "pennylane.qchem.kinetic_integral")(basis\_a, basis\_b[, normalize]) | Return a function that computes the kinetic integral for two contracted Gaussian functions. |

| [`kinetic\_matrix`](index.html#pennylane.qchem.kinetic_matrix "pennylane.qchem.kinetic_matrix")(basis\_functions) | Return a function that computes the kinetic matrix for a given set of basis functions. |

| [`load\_basisset`](index.html#pennylane.qchem.load_basisset "pennylane.qchem.load_basisset")(basis, element) | Extracts basis set data from the Basis Set Exchange library. |

| [`meanfield`](index.html#pennylane.qchem.meanfield "pennylane.qchem.meanfield")(symbols, coordinates[, name, …]) | Generates a file from which the mean field electronic structure of the molecule can be retrieved. |

| [`mol\_basis\_data`](index.html#pennylane.qchem.mol_basis_data "pennylane.qchem.mol_basis_data")(name, symbols[, load\_data]) | Generates default basis set parameters for a molecule. |

| [`mol\_data`](index.html#pennylane.qchem.mol_data "pennylane.qchem.mol_data")(identifier[, identifier\_type]) | Obtain symbols and geometry of a compound from the PubChem Database. |

| [`mol\_density\_matrix`](index.html#pennylane.qchem.mol_density_matrix "pennylane.qchem.mol_density_matrix")(n\_electron, c) | Compute the molecular density matrix. |

| [`molecular\_hamiltonian`](index.html#pennylane.qchem.molecular_hamiltonian "pennylane.qchem.molecular_hamiltonian")(symbols, coordinates) | Generate the qubit Hamiltonian of a molecule. |

| [`moment\_integral`](index.html#pennylane.qchem.moment_integral "pennylane.qchem.moment_integral")(basis\_a, basis\_b, order, idx) | Return a function that computes the multipole moment integral for two contracted Gaussians. |

| [`moment\_matrix`](index.html#pennylane.qchem.moment_matrix "pennylane.qchem.moment_matrix")(basis\_functions, order, idx) | Return a function that computes the multipole moment matrix for a set of basis functions. |

| [`nuclear\_attraction`](index.html#pennylane.qchem.nuclear_attraction "pennylane.qchem.nuclear_attraction")(la, lb, ra, rb, alpha, …) | Compute nuclear attraction integral between primitive Gaussian functions. |

| [`nuclear\_energy`](index.html#pennylane.qchem.nuclear_energy "pennylane.qchem.nuclear_energy")(charges, r) | Return a function that computes the nuclear-repulsion energy. |

| [`observable`](index.html#pennylane.qchem.observable "pennylane.qchem.observable")(fermion\_ops[, init\_term, …]) | Builds the fermionic many-body observable whose expectation value can be measured in PennyLane. |

| [`one\_particle`](index.html#pennylane.qchem.one_particle "pennylane.qchem.one_particle")(matrix\_elements[, core, …]) | Generates the [FermionOperator](https://github.com/quantumlib/OpenFermion/blob/master/docs/tutorials/intro_to_openfermion.ipynb) representing a given one-particle operator required to build many-body qubit observables. |

| [`optimal\_sector`](index.html#pennylane.qchem.optimal_sector "pennylane.qchem.optimal_sector")(qubit\_op, generators, …) | Get the optimal sector which contains the ground state. |

| [`overlap\_integral`](index.html#pennylane.qchem.overlap_integral "pennylane.qchem.overlap_integral")(basis\_a, basis\_b[, normalize]) | Return a function that computes the overlap integral for two contracted Gaussian functions. |

| [`overlap\_matrix`](index.html#pennylane.qchem.overlap_matrix "pennylane.qchem.overlap_matrix")(basis\_functions) | Return a function that computes the overlap matrix for a given set of basis functions. |

| [`particle\_number`](index.html#pennylane.qchem.particle_number "pennylane.qchem.particle_number")(orbitals) | Compute the particle number observable \(\hat{N}=\sum\_\alpha \hat{n}\_\alpha\) in the Pauli basis. |

| [`primitive\_norm`](index.html#pennylane.qchem.primitive_norm "pennylane.qchem.primitive_norm")(l, alpha) | Compute the normalization constant for a primitive Gaussian function. |

| [`qubit\_observable`](index.html#pennylane.qchem.qubit_observable "pennylane.qchem.qubit_observable")(o\_ferm[, cutoff]) | Convert a fermionic observable to a PennyLane qubit observable. |

| [`read\_structure`](index.html#pennylane.qchem.read_structure "pennylane.qchem.read_structure")(filepath[, outpath]) | Read the structure of the polyatomic system from a file and returns a list with the symbols of the atoms in the molecule and a 1D array with their positions \([x\_1, y\_1, z\_1, x\_2, y\_2, z\_2, \dots]\) in atomic units (Bohr radius = 1). |

| [`repulsion\_integral`](index.html#pennylane.qchem.repulsion_integral "pennylane.qchem.repulsion_integral")(basis\_a, basis\_b, …[, …]) | Return a function that computes the electron-electron repulsion integral for four contracted Gaussian functions. |

| [`repulsion\_tensor`](index.html#pennylane.qchem.repulsion_tensor "pennylane.qchem.repulsion_tensor")(basis\_functions) | Return a function that computes the electron repulsion tensor for a given set of basis functions. |

| [`scf`](index.html#pennylane.qchem.scf "pennylane.qchem.scf")(mol[, n\_steps, tol]) | Return a function that performs the self-consistent-field calculations. |

| [`spin2`](index.html#pennylane.qchem.spin2 "pennylane.qchem.spin2")(electrons, orbitals) | Compute the total spin observable \(\hat{S}^2\). |

| [`spinz`](index.html#pennylane.qchem.spinz "pennylane.qchem.spinz")(orbitals) | Computes the total spin projection observable \(\hat{S}\_z\). |

| [`taper\_hf`](index.html#pennylane.qchem.taper_hf "pennylane.qchem.taper_hf")(generators, paulixops, …) | Transform a Hartree-Fock state with a Clifford operator and then taper qubits. |

| [`taper\_operation`](index.html#pennylane.qchem.taper_operation "pennylane.qchem.taper_operation")(operation, generators, …) | Transform a gate operation with a Clifford operator and then taper qubits. |

| [`two\_particle`](index.html#pennylane.qchem.two_particle "pennylane.qchem.two_particle")(matrix\_elements[, core, …]) | Generates the [FermionOperator](https://github.com/quantumlib/OpenFermion/blob/master/docs/tutorials/intro_to_openfermion.ipynb) representing a given two-particle operator required to build many-body qubit observables.

 |

##### Classes[¶](#classes "Permalink to this headline")

| [`BasisFunction`](index.html#pennylane.qchem.BasisFunction "pennylane.qchem.BasisFunction")(l, alpha, coeff, r) | Create a basis function object. |

| [`Molecule`](index.html#pennylane.qchem.Molecule "pennylane.qchem.Molecule")(symbols, coordinates[, charge, …]) | Create a molecule object that stores molecular information and default basis set parameters. |

#### Differentiable Hartree-Fock[¶](#differentiable-hartree-fock "Permalink to this headline")

The differentiable Hartree-Fock (HF) solver allows performing differentiable HF calculations and

computing exact gradients with respect to

molecular geometry, basis set, and circuit parameters simultaneously using the techniques of

automatic differentiation available in [Autograd](https://github.com/HIPS/autograd). This makes

the solver more versatile and robust compared to non-differentiable tools that mainly rely

on numerical approaches for computing gradients, which can lead to inaccuracies and instability.

Additionally, optimizing the basis set parameters allows reaching lower ground-state energies

without increasing the size of the basis set. Overall, the solver allows users to execute end-to-end

differentiable algorithms for quantum chemistry.

The differentiable HF solver computes the integrals over basis functions, constructs the relevant

matrices, and performs self-consistent-field iterations to obtain a set of optimized molecular

orbital coefficients. These coefficients and the computed integrals over basis functions are used to

construct the one- and two-body electron integrals in the molecular orbital basis, which can be

used to generate differentiable second-quantized Hamiltonians and dipole moments in the fermionic

and qubit basis.

The following code shows the construction of the Hamiltonian for the hydrogen molecule where the

geometry of the molecule and the basis set parameters are all differentiable.

```

import pennylane as qml

from pennylane import numpy as np

symbols = ["H", "H"]

# This initial geometry is suboptimal and will be optimized by the algorithm

geometry = np.array([[0.0, 0.0, 0.0], [0.0, 0.0, 2.0]], requires\_grad=True)

# The exponents and contraction coefficients of the Gaussian basis functions

alpha = np.array([[3.42525091, 0.62391373, 0.1688554],

                  [3.42525091, 0.62391373, 0.1688554]], requires\_grad = True)

coeff = np.array([[0.15432897, 0.53532814, 0.44463454],

                  [0.15432897, 0.53532814, 0.44463454]], requires\_grad = True)

```

We then construct the Hamiltonian.

```

args = [geometry, alpha, coeff] # initial values of the differentiable parameters

hamiltonian, qubits = qml.qchem.molecular\_hamiltonian(symbols, geometry, alpha=alpha, coeff=coeff, args=args)

```

```

>>> print(hamiltonian)

 (-0.35968235922631075) [I0]

+ (-0.11496335836166222) [Z2]

+ (-0.11496335836166222) [Z3]

+ (0.13082414303722753) [Z1]

+ (0.13082414303722759) [Z0]

+ (0.1031689825163302) [Z0 Z2]

+ (0.1031689825163302) [Z1 Z3]

+ (0.15329959994281844) [Z0 Z3]

+ (0.15329959994281844) [Z1 Z2]

+ (0.15405495855815063) [Z0 Z1]

+ (0.1609686663987323) [Z2 Z3]

+ (-0.05013061742648825) [Y0 Y1 X2 X3]

+ (-0.05013061742648825) [X0 X1 Y2 Y3]

+ (0.05013061742648825) [Y0 X1 X2 Y3]

+ (0.05013061742648825) [X0 Y1 Y2 X3]

```

The generated Hamiltonian can be used in a circuit where the molecular geometry, the basis set

parameters, and the circuit parameters are optimized simultaneously. Further information about

molecular geometry optimization with PennyLane is provided in this

[paper](https://arxiv.org/abs/2106.13840) and this

[demo](https://pennylane.ai/qml/demos/tutorial_mol_geo_opt.html).

```

dev = qml.device("default.qubit", wires=4)

hf\_state = np.array([1, 1, 0, 0])

params = [np.array([0.0], requires\_grad=True)] # initial values of the circuit parameters

def generate\_circuit(mol):

    @qml.qnode(dev)

    def circuit(\*args):

        qml.BasisState(hf\_state, wires=[0, 1, 2, 3])

        qml.DoubleExcitation(\*args[0][0], wires=[0, 1, 2, 3])

        return qml.expval(qml.qchem.molecular\_hamiltonian(mol.symbols, mol.coordinates, alpha=mol.alpha, coeff=mol.coeff, args=args[1:])[0])

    return circuit

```

Now that the circuit is defined, we can create a geometry and parameter optimization loop. For

convenience, we create a molecule object that stores the molecular parameters.

```

for n in range(21):

    mol = qml.qchem.Molecule(symbols, geometry, alpha=alpha, coeff=coeff)

    args = [params, geometry, alpha, coeff] # initial values of the differentiable parameters

    # compute gradients with respect to the circuit parameters and update the parameters

    g\_params = qml.grad(generate\_circuit(mol), argnum = 0)(\*args)

    params = params - 0.25 \* g\_params[0]

    # compute gradients with respect to the nuclear coordinates and update geometry

    g\_coor = qml.grad(generate\_circuit(mol), argnum = 1)(\*args)

    geometry = geometry - 0.5 \* g\_coor

    # compute gradients with respect to the Gaussian exponents and update the exponents

    g\_alpha = qml.grad(generate\_circuit(mol), argnum = 2)(\*args)

    alpha = alpha - 0.25 \* g\_alpha

    # compute gradients with respect to the Gaussian contraction coefficients and update them

    g\_coeff = qml.grad(generate\_circuit(mol), argnum = 3)(\*args)

    coeff = coeff - 0.25 \* g\_coeff

    if n%5 == 0:

        print(f'Step: {n}, Energy: {generate\_circuit(mol)(\*args)}, Maximum Absolute Force: {abs(g\_coor).max()}')

```

Running this optimization, we get the following output in atomic units:

```

Step: 0, Energy: -1.0491709019856188, Maximum Absolute Force: 0.1580194718925249

Step: 5, Energy: -1.1349862621177522, Maximum Absolute Force: 0.037660768852544046

Step: 10, Energy: -1.1399960666483346, Maximum Absolute Force: 0.005175323916673413

Step: 15, Energy: -1.140321384816611, Maximum Absolute Force: 0.0004138319900744425

Step: 20, Energy: -1.1403680839339787, Maximum Absolute Force: 8.223248376348913e-06

```

Note that the computed energy is lower than the Full-CI energy, -1.1373060483 Ha, obtained without

optimizing the basis set parameters.

The components of the HF solver can also be differentiated individually. For instance, the overlap

integral can be differentiated with respect to the basis set parameters as follows

```

symbols = ["H", "H"]

geometry = np.array([[0.0, 0.0, 0.0], [0.0, 0.0, 2.0]], requires\_grad=False)

alpha = np.array([[3.42525091, 0.62391373, 0.1688554],

                [3.42525091, 0.62391373, 0.1688554]], requires\_grad = True)

coeff = np.array([[0.15432897, 0.53532814, 0.44463454],

                [0.15432897, 0.53532814, 0.44463454]], requires\_grad = True)

mol = qml.qchem.Molecule(symbols, geometry, alpha=alpha, coeff=coeff)

args = [alpha, coeff]

a = mol.basis\_set[0]

b = mol.basis\_set[1]

g\_alpha = qml.grad(qml.qchem.overlap\_integral(a, b), argnum = 0)(\*args)

g\_coeff = qml.grad(qml.qchem.overlap\_integral(a, b), argnum = 1)(\*args)

```

```

>>> print(g\_alpha)

[[ 0.00169332 -0.14826928 -0.37296693]

 [ 0.00169332 -0.14826928 -0.37296693]]

```

#### OpenFermion-PySCF backend[¶](#openfermion-pyscf-backend "Permalink to this headline")

The [`molecular\_hamiltonian()`](index.html#pennylane.qchem.molecular_hamiltonian "pennylane.qchem.molecular_hamiltonian") function can be also used to construct the molecular Hamiltonian

with a non-differentiable backend that uses the

[OpenFermion-PySCF](https://github.com/quantumlib/OpenFermion-PySCF) plugin interfaced with the

electronic structure package [PySCF](https://github.com/sunqm/pyscf). The non-differentiable

backend can be selected by setting `method='pyscf'` in [`molecular\_hamiltonian()`](index.html#pennylane.qchem.molecular_hamiltonian "pennylane.qchem.molecular_hamiltonian"):

```

import pennylane as qml

from pennylane import numpy as np

symbols = ["H", "H"]

geometry = np.array([[0.0, 0.0, 0.0], [0.0, 0.0, 2.0]])

hamiltonian, qubits = qml.qchem.molecular\_hamiltonian(

    symbols,

    geometry,

    charge=0,

    mult=1,

    basis='sto-3g',

    method='pyscf'

)

```

The non-differentiable backend requires the `OpenFermion-PySCF` plugin to be installed by the user

with

```

pip install openfermionpyscf

```

### qml.qnn[¶](#module-pennylane.qnn "Permalink to this headline")

This module contains functionality for converting PennyLane QNodes into layers that are compatible

with Keras and PyTorch.

Note

Check out our [Keras](https://pennylane.ai/qml/demos/tutorial_qnn_module_tf.html "(in PennyLane)") and

[Torch](https://pennylane.ai/qml/demos/tutorial_qnn_module_torch.html "(in PennyLane)") tutorials for further details.

Classes

| [`KerasLayer`](index.html#pennylane.qnn.KerasLayer "pennylane.qnn.KerasLayer") | Converts a [`QNode`](index.html#pennylane.QNode "pennylane.QNode") to a Keras [Layer](https://www.tensorflow.org/api_docs/python/tf/keras/layers/Layer). |

| [`TorchLayer`](index.html#pennylane.qnn.TorchLayer "pennylane.qnn.TorchLayer") | Converts a [`QNode`](index.html#pennylane.QNode "pennylane.QNode") to a Torch layer. |

### qml.devices[¶](#qml-devices "Permalink to this headline")

Warning

Unless you are a PennyLane or plugin developer, you likely do not need

to use these classes directly.

See the [main plugins page](https://pennylane.ai/plugins.html) for more

details on available plugins.

Modules

This subpackage provides default devices for PennyLane, which do not need external plugins to be installed.

The default devices provide basic built-in qubit

and CV circuit simulators that can be used with PennyLane without the need for additional

dependencies. They may also be used in the PennyLane test suite in order

to verify and test quantum gradient computations.

| [`default\_qubit`](index.html#module-pennylane.devices.default_qubit "pennylane.devices.default_qubit") | The default.qubit device is PennyLane’s standard qubit-based device. |

| [`default\_qubit\_jax`](index.html#module-pennylane.devices.default_qubit_jax "pennylane.devices.default_qubit_jax") | This module contains a jax implementation of the [`DefaultQubit`](index.html#pennylane.devices.default_qubit.DefaultQubit "pennylane.devices.default_qubit.DefaultQubit") reference plugin. |

| [`default\_qubit\_torch`](index.html#module-pennylane.devices.default_qubit_torch "pennylane.devices.default_qubit_torch") | This module contains a PyTorch implementation of the [`DefaultQubit`](index.html#pennylane.devices.default_qubit.DefaultQubit "pennylane.devices.default_qubit.DefaultQubit") reference plugin. |

| [`default\_qubit\_tf`](index.html#module-pennylane.devices.default_qubit_tf "pennylane.devices.default_qubit_tf") | This module contains a TensorFlow implementation of the [`DefaultQubit`](index.html#pennylane.devices.default_qubit.DefaultQubit "pennylane.devices.default_qubit.DefaultQubit") reference plugin. |

| [`default\_qubit\_autograd`](index.html#module-pennylane.devices.default_qubit_autograd "pennylane.devices.default_qubit_autograd") | This module contains an autograd implementation of the [`DefaultQubit`](index.html#pennylane.devices.default_qubit.DefaultQubit "pennylane.devices.default_qubit.DefaultQubit") reference plugin. |

| [`default\_gaussian`](index.html#module-pennylane.devices.default_gaussian "pennylane.devices.default_gaussian") | The `default.gaussian` device is a simulator for Gaussian continuous-variable quantum computations, and can be used as a template for writing PennyLane devices for new CV backends. |

| [`default\_mixed`](index.html#module-pennylane.devices.default_mixed "pennylane.devices.default_mixed") | The default.mixed device is PennyLane’s standard qubit simulator for mixed-state computations. |

| [`default\_qutrit`](index.html#module-pennylane.devices.default_qutrit "pennylane.devices.default_qutrit") | The default.qutrit device is PennyLane’s standard qutrit-based device. |

| [`tests`](index.html#module-pennylane.devices.tests "pennylane.devices.tests") | This subpackage provides integration tests for the devices with PennyLane’s core functionalities. |

#### Next generation devices[¶](#next-generation-devices "Permalink to this headline")

[`pennylane.devices.experimental.Device`](index.html#pennylane.devices.experimental.Device "pennylane.devices.experimental.Device") in an experimental interface for the next generation of devices that

will eventually replace [`pennylane.Device`](index.html#pennylane.Device "pennylane.Device") and [`pennylane.QubitDevice`](index.html#pennylane.QubitDevice "pennylane.QubitDevice").

While the current interface [`pennylane.Device`](index.html#pennylane.Device "pennylane.Device") is imported top level, the new [`pennylane.devices.experimental.Device`](index.html#pennylane.devices.experimental.Device "pennylane.devices.experimental.Device") is

accessible from the `pennylane.devices.experimental` submodule.

| [`ExecutionConfig`](index.html#pennylane.devices.experimental.ExecutionConfig "pennylane.devices.experimental.ExecutionConfig")([grad\_on\_execution, …]) | A class to configure the execution of a quantum circuit on a device. |

| [`Device`](index.html#pennylane.devices.experimental.Device "pennylane.devices.experimental.Device")([shots]) | A device driver that can control one or more backends. |

| [`DefaultQubit2`](index.html#pennylane.devices.experimental.DefaultQubit2 "pennylane.devices.experimental.DefaultQubit2")([shots, seed, max\_workers]) | A PennyLane device written in Python and capable of backpropagation derivatives. |

### qml.interfaces[¶](#qml-interfaces "Permalink to this headline")

Warning

Unless you are a PennyLane or plugin developer, you likely do not need

to use these functions directly.

See the [main interfaces page](index.html#document-introduction/interfaces) for more

details on available interfaces.

Modules

This subpackage defines functions for interfacing devices’ execution

capabilities with different machine learning libraries.

#### Execution functions and utilities[¶](#execution-functions-and-utilities "Permalink to this headline")

| [`execute`](index.html#pennylane.execute "pennylane.execute")(tapes, device[, gradient\_fn, …]) | New function to execute a batch of tapes on a device in an autodifferentiable-compatible manner. |

| [`cache\_execute`](index.html#pennylane.interfaces.cache_execute "pennylane.interfaces.cache_execute")(fn, cache[, pass\_kwargs, …]) | Decorator that adds caching to a function that executes multiple tapes on a device. |

| [`set\_shots`](index.html#pennylane.interfaces.set_shots "pennylane.interfaces.set_shots")(device, shots) | Context manager to temporarily change the shots of a device. |

#### Supported interfaces[¶](#supported-interfaces "Permalink to this headline")

| [`autograd`](index.html#module-pennylane.interfaces.autograd "pennylane.interfaces.autograd") | This module contains functions for adding the Autograd interface to a PennyLane Device class. |

| [`jax`](index.html#module-pennylane.interfaces.jax "pennylane.interfaces.jax") | This module contains functions for adding the JAX interface to a PennyLane Device class. |

| [`jax\_jit`](index.html#module-pennylane.interfaces.jax_jit "pennylane.interfaces.jax_jit") | This module contains functions for adding the JAX interface to a PennyLane Device class. |

| [`tensorflow`](index.html#module-pennylane.interfaces.tensorflow "pennylane.interfaces.tensorflow") | This module contains functions for adding the TensorFlow interface to a PennyLane Device class. |

| [`tensorflow\_autograph`](index.html#module-pennylane.interfaces.tensorflow_autograph "pennylane.interfaces.tensorflow_autograph") | This module contains functions for adding the TensorFlow Autograph interface to a PennyLane Device class. |

| [`torch`](index.html#module-pennylane.interfaces.torch "pennylane.interfaces.torch") | This module contains functions for adding the PyTorch interface to a PennyLane Device class. |

### qml.measurements[¶](#qml-measurements "Permalink to this headline")

Warning

Unless you are a PennyLane or plugin developer, you likely do not need

to use these classes directly.

See the [main measurements page](index.html#document-introduction/measurements) for

details on available measurements.

This module contains all the measurements supported by PennyLane.

#### Description[¶](#description "Permalink to this headline")

##### Measurements[¶](#measurements "Permalink to this headline")

The [`MeasurementProcess`](index.html#pennylane.measurements.MeasurementProcess "pennylane.measurements.MeasurementProcess") class serves as a base class for measurements, and is inherited

from by the [`SampleMeasurement`](index.html#pennylane.measurements.SampleMeasurement "pennylane.measurements.SampleMeasurement"), [`StateMeasurement`](index.html#pennylane.measurements.StateMeasurement "pennylane.measurements.StateMeasurement") and [`MeasurementTransform`](index.html#pennylane.measurements.MeasurementTransform "pennylane.measurements.MeasurementTransform")

classes. These classes are subclassed to implement measurements in PennyLane.

* Each [`SampleMeasurement`](index.html#pennylane.measurements.SampleMeasurement "pennylane.measurements.SampleMeasurement") subclass represents a sample-based measurement, which contains a

[`SampleMeasurement.process\_samples()`](index.html#pennylane.measurements.SampleMeasurement.process_samples "pennylane.measurements.SampleMeasurement.process_samples") method that processes the sequence of samples generated

by the device. This method should always have the same arguments:

	+ samples (Sequence[complex]): computational basis samples generated for all wires

	+ wire\_order (Wires): wires determining the subspace that `samples` acts on

	+ shot\_range (tuple[int]): 2-tuple of integers specifying the range of samples to use. If not

	specified, all samples are used.

	+ bin\_size (int): Divides the shot range into bins of size `bin\_size`, and returns the

	measurement statistic separately over each bin. If not provided, the entire shot range is treated

	as a single bin.See [`CountsMP`](index.html#pennylane.measurements.CountsMP "pennylane.measurements.CountsMP") for an example.

* Each [`StateMeasurement`](index.html#pennylane.measurements.StateMeasurement "pennylane.measurements.StateMeasurement") subclass represents a state-based measurement, which contains a

[`StateMeasurement.process\_state()`](index.html#pennylane.measurements.StateMeasurement.process_state "pennylane.measurements.StateMeasurement.process_state") method that processes the quantum state generated by the

device. This method should always have the same arguments:

	+ state (Sequence[complex]): quantum state

	+ wire\_order (Wires): wires determining the subspace that `state` acts on; a matrix of dimension

	\(2^n\) acts on a subspace of \(n\) wiresSee [`StateMP`](index.html#pennylane.measurements.StateMP "pennylane.measurements.StateMP") for an example.

* Each [`MeasurementTransform`](index.html#pennylane.measurements.MeasurementTransform "pennylane.measurements.MeasurementTransform") subclass represents a measurement process that requires

the application of a batch transform, which contains a [`MeasurementTransform.process()`](index.html#pennylane.measurements.MeasurementTransform.process "pennylane.measurements.MeasurementTransform.process") method

that converts the given quantum tape into a batch of quantum tapes and executes them using the

device. This method should always have the same arguments:

	+ tape (QuantumTape): quantum tape to transform

	+ device (Device): device used to transform the quantum tapeThe main difference between a [`MeasurementTransform`](index.html#pennylane.measurements.MeasurementTransform "pennylane.measurements.MeasurementTransform") and a

[`batch\_transform()`](index.html#pennylane.batch_transform "pennylane.batch_transform") is that a batch transform is tracked by the gradient transform,

while a [`MeasurementTransform`](index.html#pennylane.measurements.MeasurementTransform "pennylane.measurements.MeasurementTransform") process isn’t.

See [`ClassicalShadowMP`](index.html#pennylane.measurements.ClassicalShadowMP "pennylane.measurements.ClassicalShadowMP") for an example.

Note

A measurement process can inherit from both [`SampleMeasurement`](index.html#pennylane.measurements.SampleMeasurement "pennylane.measurements.SampleMeasurement") and

[`StateMeasurement`](index.html#pennylane.measurements.StateMeasurement "pennylane.measurements.StateMeasurement") classes, defining the needed logic to process either samples or the

quantum state. See [`VarianceMP`](index.html#pennylane.measurements.VarianceMP "pennylane.measurements.VarianceMP") for an example.

###### Differentiation[¶](#differentiation "Permalink to this headline")

In general, a [`MeasurementProcess`](index.html#pennylane.measurements.MeasurementProcess "pennylane.measurements.MeasurementProcess") is differentiable with respect to a parameter if the domain of

that parameter is continuous. When using the analytic method of differentiation the output of the

measurement process must be a real scalar value for it to be differentiable.

#### Creating custom measurements[¶](#creating-custom-measurements "Permalink to this headline")

A custom measurement process can be created by inheriting from any of the classes mentioned above.

The following is an example for a sample-based measurement that computes the number of samples

obtained of a given state:

```

import pennylane as qml

from pennylane.measurements import SampleMeasurement

class CountState(SampleMeasurement):

    def \_\_init\_\_(self, state: str):

        self.state = state  # string identifying the state e.g. "0101"

        wires = list(range(len(state)))

        super().\_\_init\_\_(wires=wires)

    def process\_samples(self, samples, wire\_order, shot\_range, bin\_size):

        counts\_mp = qml.counts(wires=self.\_wires)

        counts = counts\_mp.process\_samples(samples, wire\_order, shot\_range, bin\_size)

        return counts.get(self.state, 0)

    def \_\_copy\_\_(self):

        return CountState(state=self.state)

```

Note

The `\_\_copy\_\_` method needs to be overriden when new arguments are added into the `\_\_init\_\_`

method.

The measurement process in this example uses the [`counts()`](index.html#pennylane.counts "pennylane.counts") function, which is a

measurement process which returns a dictionary containing the number of times each quantum

state has been sampled.

We can now execute the new measurement in a [`QNode`](index.html#pennylane.QNode "pennylane.QNode"). Let’s use a simple circuit

so that we can verify our results mathematically.

```

dev = qml.device("default.qubit", wires=1, shots=10000)

@qml.qnode(dev)

def circuit(x):

    qml.RX(x, wires=0)

    return CountState(state="1")

```

The quantum state before the measurement will be:

\[\begin{split}\psi = R\_x(\theta) \begin{bmatrix} 1 \\ 0 \end{bmatrix} = \begin{bmatrix}

 \cos(\theta/2) & -i\sin(\theta/2) \\

 -i\sin(\theta/2) & \cos(\theta/2)

\end{bmatrix} \begin{bmatrix} 1 \\ 0 \end{bmatrix} = \begin{bmatrix}

 \cos(\theta/2) \\ -i\sin(\theta/2)

\end{bmatrix}\end{split}\]

When \(\theta = 1.23\), the probability of obtaining the state

\(\begin{bmatrix} 1 \\ 0 \end{bmatrix}\) is \(\sin^2(\theta/2) = 0.333\). Using 10000 shots

we should obtain the excited state 3333 times approximately.

```

>>> circuit(1.23)

tensor(3303., requires\_grad=True)

```

Given that the measurement process returns a real scalar value, we can differentiate it

using the analytic method.

We know from the previous analysis that the analytic result of the measurement process is

\(r(\theta) = \text{nshots} \cdot \sin^2(\theta/2)\).

The gradient of the measurement process is

\(\frac{\partial r}{\partial \theta} = \text{nshots} \sin(\theta/2) \cos(\theta/2)\).

When \(\theta = 1.23\), \(\frac{\partial r}{\partial \theta} = 4712.444\)

```

>>> x = qml.numpy.array(1.23, requires\_grad=True)

>>> qml.grad(circuit)(x)

4715.000000000001

```

Note

In PennyLane we use functions to define measurements (e.g. [`counts()`](index.html#pennylane.measurements.counts "pennylane.measurements.counts")). These

functions will return an instance of the corresponding measurement process

(e.g. [`CountsMP`](index.html#pennylane.measurements.CountsMP "pennylane.measurements.CountsMP")). This decision is just for design purposes.

#### Adding your new measurement to PennyLane[¶](#adding-your-new-measurement-to-pennylane "Permalink to this headline")

If you want to add this new measurement to PennyLane such that other users can benefit from it, you have to make a Pull Request

creating a file with the name of your measurement (e.g. `state.py`) and add it in

`pennylane/measurements/`. This file should contain:

* The measurement class with the appropriate `process` method defined.

* A function with the same name as the created file that will be used to instantiate the

measurement class.

The tests are added to a file of a similar name and location in `tests/measurements/`.

The class and the function need to be imported in `pennylane/measurements/\_\_init\_\_.py`. The

function needs to be imported in `pennylane/\_\_init\_\_.py`.

Here are a few more tips for adding measurements:

* *Choose the name carefully.* Good names tell the user what the measurement is used for,

or what architecture it implements. Ask yourself if a measurement of a similar name could

be added soon in a different context.

* *Write good docstrings.* Explain what your measurement does in a clear docstring with ample examples.

You can find more about Pennylane standards in the guidelines on [Documentation](index.html#document-development/guide/documentation).

#### Functions[¶](#functions "Permalink to this headline")

| [`classical\_shadow`](index.html#pennylane.measurements.classical_shadow "pennylane.measurements.classical_shadow")(wires[, seed]) | The classical shadow measurement protocol. |

| [`counts`](index.html#pennylane.measurements.counts "pennylane.measurements.counts")([op, wires, all\_outcomes]) | Sample from the supplied observable, with the number of shots determined from the `dev.shots` attribute of the corresponding device, returning the number of counts for each sample. |

| [`density\_matrix`](index.html#pennylane.measurements.density_matrix "pennylane.measurements.density_matrix")(wires) | Quantum density matrix in the computational basis. |

| [`expval`](index.html#pennylane.measurements.expval "pennylane.measurements.expval")(op) | Expectation value of the supplied observable. |

| [`measure`](index.html#pennylane.measurements.measure "pennylane.measurements.measure")(wires[, reset]) | Perform a mid-circuit measurement in the computational basis on the supplied qubit. |

| [`mutual\_info`](index.html#pennylane.measurements.mutual_info "pennylane.measurements.mutual_info")(wires0, wires1[, log\_base]) | Mutual information between the subsystems prior to measurement: |

| [`probs`](index.html#pennylane.measurements.probs "pennylane.measurements.probs")([wires, op]) | Probability of each computational basis state. |

| [`purity`](index.html#pennylane.measurements.purity "pennylane.measurements.purity")(wires) | The purity of the system prior to measurement. |

| [`sample`](index.html#pennylane.measurements.sample "pennylane.measurements.sample")([op, wires]) | Sample from the supplied observable, with the number of shots determined from the `dev.shots` attribute of the corresponding device, returning raw samples. |

| [`shadow\_expval`](index.html#pennylane.measurements.shadow_expval "pennylane.measurements.shadow_expval")(H[, k, seed]) | Compute expectation values using classical shadows in a differentiable manner. |

| [`state`](index.html#pennylane.measurements.state "pennylane.measurements.state")() | Quantum state in the computational basis. |

| [`var`](index.html#pennylane.measurements.var "pennylane.measurements.var")(op) | Variance of the supplied observable. |

| [`vn\_entropy`](index.html#pennylane.measurements.vn_entropy "pennylane.measurements.vn_entropy")(wires[, log\_base]) | Von Neumann entropy of the system prior to measurement. |

#### Classes[¶](#classes "Permalink to this headline")

| [`ClassicalShadowMP`](index.html#pennylane.measurements.ClassicalShadowMP "pennylane.measurements.ClassicalShadowMP")([wires, seed, id]) | Represents a classical shadow measurement process occurring at the end of a quantum variational circuit. |

| [`CountsMP`](index.html#pennylane.measurements.CountsMP "pennylane.measurements.CountsMP")([obs, wires, eigvals, id, all\_outcomes]) | Measurement process that samples from the supplied observable and returns the number of counts for each sample. |

| [`ExpectationMP`](index.html#pennylane.measurements.ExpectationMP "pennylane.measurements.ExpectationMP")([obs, wires, eigvals, id]) | Measurement process that computes the expectation value of the supplied observable. |

| [`MeasurementProcess`](index.html#pennylane.measurements.MeasurementProcess "pennylane.measurements.MeasurementProcess")([obs, wires, eigvals, id]) | Represents a measurement process occurring at the end of a quantum variational circuit. |

| [`MeasurementTransform`](index.html#pennylane.measurements.MeasurementTransform "pennylane.measurements.MeasurementTransform")([obs, wires, eigvals, id]) | Measurement process that applies a transform into the given quantum tape. |

| [`MeasurementValue`](index.html#pennylane.measurements.MeasurementValue "pennylane.measurements.MeasurementValue")(measurements, processing\_fn) | A class representing unknown measurement outcomes in the qubit model. |

| [`MidMeasureMP`](index.html#pennylane.measurements.MidMeasureMP "pennylane.measurements.MidMeasureMP")([wires, reset, id]) | Mid-circuit measurement. |

| [`MutualInfoMP`](index.html#pennylane.measurements.MutualInfoMP "pennylane.measurements.MutualInfoMP")([wires, id, log\_base]) | Measurement process that computes the mutual information between the provided wires. |

| [`ProbabilityMP`](index.html#pennylane.measurements.ProbabilityMP "pennylane.measurements.ProbabilityMP")([obs, wires, eigvals, id]) | Measurement process that computes the probability of each computational basis state. |

| [`PurityMP`](index.html#pennylane.measurements.PurityMP "pennylane.measurements.PurityMP")(wires[, id]) | Measurement process that computes the purity of the system prior to measurement. |

| [`SampleMP`](index.html#pennylane.measurements.SampleMP "pennylane.measurements.SampleMP")([obs, wires, eigvals, id]) | Measurement process that returns the samples of a given observable. |

| [`SampleMeasurement`](index.html#pennylane.measurements.SampleMeasurement "pennylane.measurements.SampleMeasurement")([obs, wires, eigvals, id]) | Sample-based measurement process. |

| [`ShadowExpvalMP`](index.html#pennylane.measurements.ShadowExpvalMP "pennylane.measurements.ShadowExpvalMP")(H[, seed, k, id]) | Measures the expectation value of an operator using the classical shadow measurement process. |

| [`ShotCopies`](index.html#pennylane.measurements.ShotCopies "pennylane.measurements.ShotCopies")(shots, copies) | A namedtuple that represents a shot quantity being repeated some number of times. |

| [`Shots`](index.html#pennylane.measurements.Shots "pennylane.measurements.Shots")([shots]) | A data class that stores shot information. |

| [`StateMP`](index.html#pennylane.measurements.StateMP "pennylane.measurements.StateMP")([wires, id]) | Measurement process that returns the quantum state in the computational basis. |

| [`StateMeasurement`](index.html#pennylane.measurements.StateMeasurement "pennylane.measurements.StateMeasurement")([obs, wires, eigvals, id]) | State-based measurement process. |

| [`VarianceMP`](index.html#pennylane.measurements.VarianceMP "pennylane.measurements.VarianceMP")([obs, wires, eigvals, id]) | Measurement process that computes the variance of the supplied observable. |

| [`VnEntropyMP`](index.html#pennylane.measurements.VnEntropyMP "pennylane.measurements.VnEntropyMP")([wires, id, log\_base]) | Measurement process that computes the Von Neumann entropy of the system prior to measurement. |

#### Variables[¶](#variables "Permalink to this headline")

| [`AllCounts`](index.html#pennylane.measurements.AllCounts "pennylane.measurements.AllCounts") | Enumeration class to represent the return types of an observable. |

| [`Counts`](index.html#pennylane.measurements.Counts "pennylane.measurements.Counts") | Enumeration class to represent the return types of an observable. |

| [`Expectation`](index.html#pennylane.measurements.Expectation "pennylane.measurements.Expectation") | Enumeration class to represent the return types of an observable. |

| [`MidMeasure`](index.html#pennylane.measurements.MidMeasure "pennylane.measurements.MidMeasure") | Enumeration class to represent the return types of an observable. |

| [`MutualInfo`](index.html#pennylane.measurements.MutualInfo "pennylane.measurements.MutualInfo") | Enumeration class to represent the return types of an observable. |

| [`Probability`](index.html#pennylane.measurements.Probability "pennylane.measurements.Probability") | Enumeration class to represent the return types of an observable. |

| [`Purity`](index.html#pennylane.measurements.Purity "pennylane.measurements.Purity") | Enumeration class to represent the return types of an observable. |

| [`Sample`](index.html#pennylane.measurements.Sample "pennylane.measurements.Sample") | Enumeration class to represent the return types of an observable. |

| [`Shadow`](index.html#pennylane.measurements.Shadow "pennylane.measurements.Shadow") | Enumeration class to represent the return types of an observable. |

| [`ShadowExpval`](index.html#pennylane.measurements.ShadowExpval "pennylane.measurements.ShadowExpval") | Enumeration class to represent the return types of an observable. |

| [`State`](index.html#pennylane.measurements.State "pennylane.measurements.State") | Enumeration class to represent the return types of an observable. |

| [`Variance`](index.html#pennylane.measurements.Variance "pennylane.measurements.Variance") | Enumeration class to represent the return types of an observable. |

| [`VnEntropy`](index.html#pennylane.measurements.VnEntropy "pennylane.measurements.VnEntropy") | Enumeration class to represent the return types of an observable. |

#### Class Inheritance Diagram[¶](#class-inheritance-diagram "Permalink to this headline")

![Inheritance diagram of pennylane.measurements.classical_shadow.ClassicalShadowMP, pennylane.measurements.counts.CountsMP, pennylane.measurements.expval.ExpectationMP, pennylane.measurements.measurements.MeasurementProcess, pennylane.measurements.measurements.MeasurementTransform, pennylane.measurements.mid_measure.MeasurementValue, pennylane.measurements.mid_measure.MidMeasureMP, pennylane.measurements.mutual_info.MutualInfoMP, pennylane.measurements.probs.ProbabilityMP, pennylane.measurements.purity.PurityMP, pennylane.measurements.sample.SampleMP, pennylane.measurements.measurements.SampleMeasurement, pennylane.measurements.classical_shadow.ShadowExpvalMP, pennylane.measurements.shots.ShotCopies, pennylane.measurements.shots.Shots, pennylane.measurements.state.StateMP, pennylane.measurements.measurements.StateMeasurement, pennylane.measurements.var.VarianceMP, pennylane.measurements.vn_entropy.VnEntropyMP](_images/inheritance-1740af88564e985ea52692e1f3f64f3fc597acfd.png)

### qml.operation[¶](#module-pennylane.operation "Permalink to this headline")

This module contains the abstract base classes for defining PennyLane

operations and observables.

Warning

Unless you are a PennyLane or plugin developer, you likely do not need

to use these classes directly.

See the [main operations page](index.html#document-introduction/operations) for

details on available operations and observables.

#### Description[¶](#description "Permalink to this headline")

##### Qubit Operations[¶](#qubit-operations "Permalink to this headline")

The [`Operator`](index.html#pennylane.operation.Operator "pennylane.operation.Operator") class serves as a base class for operators,

and is inherited by both the [`Observable`](index.html#pennylane.operation.Observable "pennylane.operation.Observable") class and the

[`Operation`](index.html#pennylane.operation.Operation "pennylane.operation.Operation") class. These classes are subclassed to implement quantum operations

and measure observables in PennyLane.

* Each [`Operator`](index.html#pennylane.operation.Operator "pennylane.operation.Operator") subclass represents a general type of

map between physical states. Each instance of these subclasses

represents either

	+ an application of the operator or

	+ an instruction to measure and return the respective result.Operators act on a sequence of wires (subsystems) using given parameter values.

* Each [`Operation`](index.html#pennylane.operation.Operation "pennylane.operation.Operation") subclass represents a type of quantum operation,

for example a unitary quantum gate. Each instance of these subclasses

represents an application of the operation with given parameter values to

a given sequence of wires (subsystems).

* Each [`Observable`](index.html#pennylane.operation.Observable "pennylane.operation.Observable") subclass represents a type of physical observable.

Each instance of these subclasses represents an instruction to measure and

return the respective result for the given parameter values on a

sequence of wires (subsystems).

###### Differentiation[¶](#differentiation "Permalink to this headline")

In general, an [`Operation`](index.html#pennylane.operation.Operation "pennylane.operation.Operation") is differentiable (at least using the finite-difference

method) with respect to a parameter iff

* the domain of that parameter is continuous.

For an [`Operation`](index.html#pennylane.operation.Operation "pennylane.operation.Operation") to be differentiable with respect to a parameter using the

analytic method of differentiation, it must satisfy an additional constraint:

* the parameter domain must be real.

Note

These conditions are *not* sufficient for analytic differentiation. For example,

CV gates must also define a matrix representing their Heisenberg linear

transformation on the quadrature operators.

##### CV Operation base classes[¶](#cv-operation-base-classes "Permalink to this headline")

Due to additional requirements, continuous-variable (CV) operations must subclass the

[`CVOperation`](index.html#pennylane.operation.CVOperation "pennylane.operation.CVOperation") or [`CVObservable`](index.html#pennylane.operation.CVObservable "pennylane.operation.CVObservable") classes instead of [`Operation`](index.html#pennylane.operation.Operation "pennylane.operation.Operation")

and [`Observable`](index.html#pennylane.operation.Observable "pennylane.operation.Observable").

###### Differentiation[¶](#id1 "Permalink to this headline")

To enable gradient computation using the analytic method for Gaussian CV operations, in addition, you need to

provide the static class method `\_heisenberg\_rep()` that returns the Heisenberg representation of

the operation given its list of parameters, namely:

* For Gaussian CV Operations this method should return the matrix of the linear transformation carried out by the

operation on the vector of quadrature operators \(\mathbf{r}\) for the given parameter

values.

* For Gaussian CV Observables this method should return a real vector (first-order observables)

or symmetric matrix (second-order observables) of coefficients of the quadrature

operators \(\x\) and \(\p\).

PennyLane uses the convention \(\mathbf{r} = (\I, \x, \p)\) for single-mode operations and observables

and \(\mathbf{r} = (\I, \x\_0, \p\_0, \x\_1, \p\_1, \ldots)\) for multi-mode operations and observables.

Note

Non-Gaussian CV operations and observables are currently only supported via

the finite-difference method of gradient computation.

#### Contents[¶](#contents "Permalink to this headline")

##### Operator Types[¶](#operator-types "Permalink to this headline")

| [`Operator`](index.html#pennylane.operation.Operator "pennylane.operation.Operator")(\*params[, wires, id]) | Base class representing quantum operators. |

| [`Operation`](index.html#pennylane.operation.Operation "pennylane.operation.Operation")(\*params[, wires, id]) | Base class representing quantum gates or channels applied to quantum states. |

| [`Observable`](index.html#pennylane.operation.Observable "pennylane.operation.Observable")(\*params[, wires, id]) | Base class representing observables. |

| [`CV`](index.html#pennylane.operation.CV "pennylane.operation.CV")() | A mixin base class denoting a continuous-variable operation. |

| [`CVObservable`](index.html#pennylane.operation.CVObservable "pennylane.operation.CVObservable")(\*params[, wires, id]) | Base class representing continuous-variable observables. |

| [`CVOperation`](index.html#pennylane.operation.CVOperation "pennylane.operation.CVOperation")(\*params[, wires, id]) | Base class representing continuous-variable quantum gates. |

| [`Channel`](index.html#pennylane.operation.Channel "pennylane.operation.Channel")(\*params[, wires, id]) | Base class for quantum channels. |

| [`Tensor`](index.html#pennylane.operation.Tensor "pennylane.operation.Tensor")(\*args) | Container class representing tensor products of observables. |

| [`StatePrepBase`](index.html#pennylane.operation.StatePrepBase "pennylane.operation.StatePrepBase")(\*params[, wires, id]) | An interface for state-prep operations. |

![Inheritance diagram of Operator, Operation, Observable, Channel, CV, CVObservable, CVOperation, Tensor, StatePrepBase](_images/inheritance-2f1105aa3e762c1831e2f3a46ca6940a0db65cd0.png)

##### Errors[¶](#errors "Permalink to this headline")

When an [`Operator`](index.html#pennylane.operation.Operator "pennylane.operation.Operator") method is undefined, it raises a error type that depends

on the method that is undefined.

| [`OperatorPropertyUndefined`](index.html#pennylane.operation.OperatorPropertyUndefined "pennylane.operation.OperatorPropertyUndefined") | Generic exception to be used for undefined Operator properties or methods. |

| [`AdjointUndefinedError`](index.html#pennylane.operation.AdjointUndefinedError "pennylane.operation.AdjointUndefinedError") | Raised when an Operator’s adjoint version is undefined. |

| [`DecompositionUndefinedError`](index.html#pennylane.operation.DecompositionUndefinedError "pennylane.operation.DecompositionUndefinedError") | Raised when an Operator’s representation as a decomposition is undefined. |

| [`DiagGatesUndefinedError`](index.html#pennylane.operation.DiagGatesUndefinedError "pennylane.operation.DiagGatesUndefinedError") | Raised when an Operator’s diagonalizing gates are undefined. |

| [`EigvalsUndefinedError`](index.html#pennylane.operation.EigvalsUndefinedError "pennylane.operation.EigvalsUndefinedError") | Raised when an Operator’s eigenvalues are undefined. |

| [`GeneratorUndefinedError`](index.html#pennylane.operation.GeneratorUndefinedError "pennylane.operation.GeneratorUndefinedError") | Exception used to indicate that an operator does not have a generator |

| [`MatrixUndefinedError`](index.html#pennylane.operation.MatrixUndefinedError "pennylane.operation.MatrixUndefinedError") | Raised when an Operator’s matrix representation is undefined. |

| [`ParameterFrequenciesUndefinedError`](index.html#pennylane.operation.ParameterFrequenciesUndefinedError "pennylane.operation.ParameterFrequenciesUndefinedError") | Exception used to indicate that an operator does not have parameter\_frequencies |

| [`PowUndefinedError`](index.html#pennylane.operation.PowUndefinedError "pennylane.operation.PowUndefinedError") | Raised when an Operator’s power is undefined. |

| [`SparseMatrixUndefinedError`](index.html#pennylane.operation.SparseMatrixUndefinedError "pennylane.operation.SparseMatrixUndefinedError") | Raised when an Operator’s sparse matrix representation is undefined. |

| [`TermsUndefinedError`](index.html#pennylane.operation.TermsUndefinedError "pennylane.operation.TermsUndefinedError") | Raised when an Operator’s representation as a linear combination is undefined. |

##### Boolean Functions[¶](#boolean-functions "Permalink to this headline")

[`BooleanFn`](index.html#pennylane.BooleanFn "pennylane.BooleanFn")’s are functions of a single object that return `True` or `False`.

The `operation` module provides the following:

| [`defines\_diagonalizing\_gates`](index.html#pennylane.operation.defines_diagonalizing_gates "pennylane.operation.defines_diagonalizing_gates") | Returns `True` if an operator defines the diagonalizing gates. |

| [`gen\_is\_multi\_term\_hamiltonian`](index.html#pennylane.operation.gen_is_multi_term_hamiltonian "pennylane.operation.gen_is_multi_term_hamiltonian") | Returns `True` if an operator has a generator defined and it is a Hamiltonian with more than one term. |

| [`has\_gen`](index.html#pennylane.operation.has_gen "pennylane.operation.has_gen") | Returns `True` if an operator has a generator defined. |

| [`has\_grad\_method`](index.html#pennylane.operation.has_grad_method "pennylane.operation.has_grad_method") | Returns `True` if an operator has a grad\_method defined. |

| [`has\_multipar`](index.html#pennylane.operation.has_multipar "pennylane.operation.has_multipar") | Returns `True` if an operator has more than one parameter according to `num\_params`. |

| [`has\_nopar`](index.html#pennylane.operation.has_nopar "pennylane.operation.has_nopar") | Returns `True` if an operator has no parameters according to `num\_params`. |

| [`has\_unitary\_gen`](index.html#pennylane.operation.has_unitary_gen "pennylane.operation.has_unitary_gen") | Returns `True` if an operator has a unitary\_generator according to the `has\_unitary\_generator` flag. |

| [`is\_measurement`](index.html#pennylane.operation.is_measurement "pennylane.operation.is_measurement") | Returns `True` if an operator is a `MeasurementProcess` instance. |

| [`is\_trainable`](index.html#pennylane.operation.is_trainable "pennylane.operation.is_trainable") | Returns `True` if any of the parameters of an operator is trainable according to `qml.math.requires\_grad`. |

| [`not\_tape`](index.html#pennylane.operation.not_tape "pennylane.operation.not_tape") | Returns `True` if the object is not a quantum tape |

##### Enabling New Arithmetic Operators[¶](#enabling-new-arithmetic-operators "Permalink to this headline")

PennyLane is in the process of replacing [`Hamiltonian`](index.html#pennylane.Hamiltonian "pennylane.Hamiltonian") and [`Tensor`](index.html#pennylane.operation.Tensor "pennylane.operation.Tensor")

with newer, more general arithmetic operators. These consist of [`Prod`](index.html#pennylane.ops.op_math.Prod "pennylane.ops.op_math.Prod"),

[`Sum`](index.html#pennylane.ops.op_math.Sum "pennylane.ops.op_math.Sum") and [`SProd`](index.html#pennylane.ops.op_math.SProd "pennylane.ops.op_math.SProd"). By default, using dunder

methods (eg. `+`, `-`, `@`, `\*`) to combine operators with scalars or other operators will

create [`Hamiltonian`](index.html#pennylane.Hamiltonian "pennylane.Hamiltonian")’s and [`Tensor`](index.html#pennylane.operation.Tensor "pennylane.operation.Tensor")’s. If you would like to switch dunders to

return newer arithmetic operators, the `operation` module provides the following helper functions:

| [`enable\_new\_opmath`](index.html#pennylane.operation.enable_new_opmath "pennylane.operation.enable_new_opmath")() | Change dunder methods to return arithmetic operators instead of Hamiltonians and Tensors |

| [`disable\_new\_opmath`](index.html#pennylane.operation.disable_new_opmath "pennylane.operation.disable_new_opmath")() | Change dunder methods to return Hamiltonians and Tensors instead of arithmetic operators |

| [`active\_new\_opmath`](index.html#pennylane.operation.active_new_opmath "pennylane.operation.active_new_opmath")() | Function that checks if the new arithmetic operator dunders are active |

##### Other[¶](#other "Permalink to this headline")

| [`operation\_derivative`](index.html#pennylane.operation.operation_derivative "pennylane.operation.operation_derivative")(operation) | Calculate the derivative of an operation. |

| [`WiresEnum`](index.html#pennylane.operation.WiresEnum "pennylane.operation.WiresEnum")(value) | Integer enumeration class to represent the number of wires an operation acts on |

| [`AllWires`](index.html#pennylane.operation.AllWires "pennylane.operation.AllWires") | An enumeration which represents all wires in the subsystem. |

| [`AnyWires`](index.html#pennylane.operation.AnyWires "pennylane.operation.AnyWires") | An enumeration which represents any wires in the subsystem. |

##### Operation attributes[¶](#operation-attributes "Permalink to this headline")

PennyLane contains a mechanism for storing lists of operations with similar

attributes and behaviour (for example, those that are their own inverses).

The attributes below are already included, and are used primarily for the

purpose of compilation transforms. New attributes can be added by instantiating

new [`Attribute`](index.html#pennylane.ops.qubit.attributes.Attribute "pennylane.ops.qubit.attributes.Attribute") objects. Please note that

these objects are located in `pennylane.ops.qubit.attributes`, not `pennylane.operation`.

| [`Attribute`](index.html#pennylane.ops.qubit.attributes.Attribute "pennylane.ops.qubit.attributes.Attribute") | Class to represent a set of operators with a certain attribute. |

| [`composable\_rotations`](index.html#pennylane.ops.qubit.attributes.composable_rotations "pennylane.ops.qubit.attributes.composable_rotations") | Operations for which composing multiple copies of the operation results in an addition (or alternative accumulation) of parameters. |

| [`diagonal\_in\_z\_basis`](index.html#pennylane.ops.qubit.attributes.diagonal_in_z_basis "pennylane.ops.qubit.attributes.diagonal_in_z_basis") | Operations that are diagonal in the computational basis. |

| [`has\_unitary\_generator`](index.html#pennylane.ops.qubit.attributes.has_unitary_generator "pennylane.ops.qubit.attributes.has_unitary_generator") | Operations that are generated by a unitary operator. |

| [`self\_inverses`](index.html#pennylane.ops.qubit.attributes.self_inverses "pennylane.ops.qubit.attributes.self_inverses") | Operations that are their own inverses. |

| [`supports\_broadcasting`](index.html#pennylane.ops.qubit.attributes.supports_broadcasting "pennylane.ops.qubit.attributes.supports_broadcasting") | Operations that support parameter broadcasting. |

| [`symmetric\_over\_all\_wires`](index.html#pennylane.ops.qubit.attributes.symmetric_over_all_wires "pennylane.ops.qubit.attributes.symmetric_over_all_wires") | Operations that are the same if you exchange the order of wires. |

| [`symmetric\_over\_control\_wires`](index.html#pennylane.ops.qubit.attributes.symmetric_over_control_wires "pennylane.ops.qubit.attributes.symmetric_over_control_wires") | Controlled operations that are the same if you exchange the order of all but the last (target) wire. |

### qml.queuing[¶](#qml-queuing "Permalink to this headline")

#### Overview[¶](#overview "Permalink to this headline")

Warning

Unless you are a PennyLane developer, you likely do not need

to use these classes directly.

This module contains the classes for placing objects into queues.

##### Description[¶](#description "Permalink to this headline")

Users provide *quantum functions* which PennyLane needs to convert into a circuit representation capable

of being executed by a device. A quantum function is any callable that:

* accepts classical inputs

* constructs any number of quantum [`Operator`](index.html#pennylane.operation.Operator "pennylane.operation.Operator") objects

* returns one or more [`MeasurementProcess`](index.html#pennylane.measurements.MeasurementProcess "pennylane.measurements.MeasurementProcess") objects.

For example:

```

def qfunc(x, scale\_value=1):

    qml.RX(x \* scale\_value, wires=0)

    if (1 != 2):

        qml.S(0)

    return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliX(1))

```

To convert from a quantum function to a representation of a circuit, we use queuing.

A *queuable object* is anything that can be placed into a queue. These will be [`Operator`](index.html#pennylane.operation.Operator "pennylane.operation.Operator"),

[`MeasurementProcess`](index.html#pennylane.measurements.MeasurementProcess "pennylane.measurements.MeasurementProcess"), and [`QuantumTape`](index.html#pennylane.tape.QuantumTape "pennylane.tape.QuantumTape") objects. [`Operator`](index.html#pennylane.operation.Operator "pennylane.operation.Operator") and

[`MeasurementProcess`](index.html#pennylane.measurements.MeasurementProcess "pennylane.measurements.MeasurementProcess") objects achieve queuing via a [`queue()`](index.html#pennylane.operation.Operator.queue "pennylane.operation.Operator.queue") method called upon construction.

Note that even though [`QuantumTape`](index.html#pennylane.tape.QuantumTape "pennylane.tape.QuantumTape") is a queuable object, it does not have a `queue` method.

When an object is queued, it sends itself to the [`QueuingManager`](index.html#pennylane.queuing.QueuingManager "pennylane.queuing.QueuingManager"). The [`QueuingManager`](index.html#pennylane.queuing.QueuingManager "pennylane.queuing.QueuingManager")

is a global singleton class that facilitates placing objects in the queue. All of [`QueuingManager`](index.html#pennylane.queuing.QueuingManager "pennylane.queuing.QueuingManager")’s methods

and properties are class methods and properties, so all instances will access the same information.

The [`active\_context()`](index.html#pennylane.queuing.QueuingManager.active_context "pennylane.queuing.QueuingManager.active_context") is the queue where any new objects are placed.

The [`QueuingManager`](index.html#pennylane.queuing.QueuingManager "pennylane.queuing.QueuingManager") is said to be *recording* if an active context exists.

Active contexts are [`AnnotatedQueue`](index.html#pennylane.queuing.AnnotatedQueue "pennylane.queuing.AnnotatedQueue") instances. They are *context managers* where recording occurs

within a `with` block.

Let’s take a look at an example. If we query the [`QueuingManager`](index.html#pennylane.queuing.QueuingManager "pennylane.queuing.QueuingManager") outside of an

[`AnnotatedQueue`](index.html#pennylane.queuing.AnnotatedQueue "pennylane.queuing.AnnotatedQueue")’s context, we can see that nothing is recording and no active context exists.

```

>>> print("Are we recording? ", qml.QueuingManager.recording())

Are we recording? False

>>> print("What's the active context? ", qml.QueuingManager.active\_context())

What's the active context? None

```

Inside of a context, we can see the active recording context:

```

>>> with qml.queuing.AnnotatedQueue() as q:

...     print("Are we recording? ", qml.QueuingManager.recording())

...     print("Is q the active queue? ", q is qml.QueuingManager.active\_context())

Are we recording? True

Is q the active queue? True

```

If we have nested [`AnnotatedQueue`](index.html#pennylane.queuing.AnnotatedQueue "pennylane.queuing.AnnotatedQueue") contexts, only the innermost one will be recording.

Once the currently active queue exits, any outer queue will resume recording.

```

>>> with qml.queuing.AnnotatedQueue() as q1:

...     print("Is q1 recording? ", q1 is qml.QueuingManager.active\_context())

...     with qml.queuing.AnnotatedQueue() as q2:

...         print("Is q1 recording? ", q1 is qml.QueuingManager.active\_context())

...     print("Is q1 recording? ", q1 is qml.QueuingManager.active\_context())

Is q1 recording? True

Is q1 recording? False

Is q1 recording? True

```

If we construct an operator inside the recording context, we can see it is added to the queue:

```

>>> with qml.queuing.AnnotatedQueue() as q:

...     op = qml.PauliX(0)

>>> q.queue

[PauliX(wires=[0])]

```

If an operator is constructed outside of the context, we can manually add it to the queue by

calling the [`queue()`](index.html#pennylane.operation.Operator.queue "pennylane.operation.Operator.queue") method. The [`queue()`](index.html#pennylane.operation.Operator.queue "pennylane.operation.Operator.queue") method is automatically

called upon initialization, but it can also be manually called at a later time.

```

>>> op = qml.PauliX(0)

>>> with qml.queuing.AnnotatedQueue() as q:

...     op.queue()

>>> q.queue

[PauliX(wires=[0])]

```

An object can only exist up to *once* in the queue, so calling queue multiple times will

not do anything.

```

>>> op = qml.PauliX(0)

>>> with qml.queuing.AnnotatedQueue() as q:

...     op.queue()

...     op.queue()

>>> q.queue

[PauliX(wires=[0])]

```

The [`apply()`](index.html#pennylane.queuing.apply "pennylane.queuing.apply") method allows a single object to be queued multiple times in a circuit.

The function queues a copy of the original object if it already in the queue.

```

>>> op = qml.PauliX(0)

>>> with qml.queuing.AnnotatedQueue() as q:

...     qml.apply(op)

...     qml.apply(op)

>>> q.queue

[PauliX(wires=[0]), PauliX(wires=[0])]

>>> q.queue[0] is q.queue[1]

False

```

In the case of operators composed of other operators, like with [`SymbolicOp`](index.html#pennylane.ops.op_math.SymbolicOp "pennylane.ops.op_math.SymbolicOp") and

[`CompositeOp`](index.html#pennylane.ops.op_math.CompositeOp "pennylane.ops.op_math.CompositeOp"), the new nested operation removes its constituents from the queue.

Only the operators that will end up in the circuit will remain.

```

>>> with qml.queuing.AnnotatedQueue() as q:

...     base = qml.PauliX(0)

...     print(q.queue)

...     pow\_op = base \*\* 1.5

...     print(q.queue)

[PauliX(wires=[0])]

[PauliX(wires=[0])\*\*1.5]

```

Once the queue is constructed, the [`process\_queue()`](index.html#pennylane.queuing.process_queue "pennylane.queuing.process_queue") function converts it into the operations

and measurements in the final circuit. This step eliminates any object that has an owner.

```

>>> with qml.queuing.AnnotatedQueue() as q:

...     qml.StatePrep(np.array([1.0, 0]), wires=0)

...     base = qml.PauliX(0)

...     pow\_op = base \*\* 1.5

...     qml.expval(qml.PauliZ(0) @ qml.PauliX(1))

>>> ops, measurements, prep = qml.queuing.process\_queue(q)

>>> ops

[StatePrep(tensor([1., 0.], requires\_grad=True), wires=[0]), PauliX(wires=[0])\*\*1.5]

>>> measurements

[expval(PauliZ(wires=[0]) @ PauliX(wires=[1]))]

>>> prep

[]

```

These lists can be used to construct a [`QuantumScript`](index.html#pennylane.tape.QuantumScript "pennylane.tape.QuantumScript"):

```

>>> qml.tape.QuantumScript(ops, measurements, prep)

<QuantumScript: wires=[0, 1], params=1>

```

In order to construct new operators within a recording, but without queuing them

use the [`stop\_recording()`](index.html#pennylane.queuing.QueuingManager.stop_recording "pennylane.queuing.QueuingManager.stop_recording") context upon construction:

```

>>> with qml.queuing.AnnotatedQueue() as q:

...     with qml.QueuingManager.stop\_recording():

...         qml.PauliY(1)

>>> q.queue

[]

```

##### Functions[¶](#functions "Permalink to this headline")

| [`apply`](index.html#pennylane.queuing.apply "pennylane.queuing.apply")(op[, context]) | Apply an instantiated operator or measurement to a queuing context. |

| [`process\_queue`](index.html#pennylane.queuing.process_queue "pennylane.queuing.process_queue")(queue) | Process the annotated queue, creating a list of quantum operations and measurement processes. |

##### Classes[¶](#classes "Permalink to this headline")

| [`AnnotatedQueue`](index.html#pennylane.queuing.AnnotatedQueue "pennylane.queuing.AnnotatedQueue") | Lightweight class that maintains a basic queue of operations, in addition to metadata annotations. |

| [`QueuingError`](index.html#pennylane.queuing.QueuingError "pennylane.queuing.QueuingError") | Exception that is raised when there is a queuing error |

| [`QueuingManager`](index.html#pennylane.queuing.QueuingManager "pennylane.queuing.QueuingManager")() | Singleton global entry point for managing active recording contexts. |

| [`WrappedObj`](index.html#pennylane.queuing.WrappedObj "pennylane.queuing.WrappedObj")(obj) | Wraps an object to make its hash dependent on its identity |

##### Variables[¶](#variables "Permalink to this headline")

| [`Optional`](index.html#pennylane.queuing.Optional "pennylane.queuing.Optional") | Optional type. |

### qml.tape[¶](#qml-tape "Permalink to this headline")

Quantum tapes are a datastructure that can represent quantum circuits and measurement statistics in PennyLane. They are queuing contexts that can record and process quantum operations and measurements.

In addition to being created internally by QNodes, quantum tapes can also be created,

nested, expanded (via [`expand()`](index.html#pennylane.tape.QuantumTape.expand "pennylane.tape.QuantumTape.expand")), and executed manually.

Finally, quantum tapes are fully compatible with autodifferentiating via NumPy/Autograd,

TensorFlow, and PyTorch.

Warning

Unless you are a PennyLane or plugin developer, you likely do not need

to use these classes directly.

See the [quantum circuits](index.html#document-introduction/circuits) page for more

details on creating QNodes, as well as the [`qnode()`](index.html#pennylane.qnode "pennylane.qnode") decorator

and [`QNode()`](index.html#pennylane.QNode "pennylane.QNode") constructor.

#### pennylane.tape Package[¶](#pennylane-tape-package "Permalink to this headline")

##### Functions[¶](#functions "Permalink to this headline")

| [`expand\_tape\_state\_prep`](index.html#pennylane.tape.expand_tape_state_prep "pennylane.tape.expand_tape_state_prep")(tape[, skip\_first]) | Expand all instances of StatePrepBase operations in the tape. |

| [`make\_qscript`](index.html#pennylane.tape.make_qscript "pennylane.tape.make_qscript")(fn[, shots]) | Returns a function that generates a qscript from a quantum function without any operation queuing taking place. |

##### Classes[¶](#classes "Permalink to this headline")

| [`OperationRecorder`](index.html#pennylane.tape.OperationRecorder "pennylane.tape.OperationRecorder")([ops, measurements, prep, …]) | A template and quantum function inspector, allowing easy introspection of operators that have been applied without requiring a QNode. |

| [`QuantumScript`](index.html#pennylane.tape.QuantumScript "pennylane.tape.QuantumScript")([ops, measurements, prep, …]) | The operations and measurements that represent instructions for execution on a quantum device. |

| [`QuantumTape`](index.html#pennylane.tape.QuantumTape "pennylane.tape.QuantumTape")([ops, measurements, prep, …]) | A quantum tape recorder, that records and stores variational quantum programs. |

| [`TapeError`](index.html#pennylane.tape.TapeError "pennylane.tape.TapeError") | An error raised with a quantum tape. |

| [`Unwrap`](index.html#pennylane.tape.Unwrap "pennylane.tape.Unwrap")(\*tapes[, params]) | A context manager that unwraps multiple tapes with tensor-like parameters to NumPy arrays. |

| [`UnwrapTape`](index.html#pennylane.tape.UnwrapTape "pennylane.tape.UnwrapTape")(tape[, params]) | A context manager that unwraps a single tape with tensor-like parameters to NumPy arrays. |

##### Class Inheritance Diagram[¶](#class-inheritance-diagram "Permalink to this headline")

![Inheritance diagram of pennylane.tape.operation_recorder.OperationRecorder, pennylane.tape.qscript.QuantumScript, pennylane.tape.tape.QuantumTape, pennylane.tape.tape.TapeError, pennylane.tape.unwrap.Unwrap, pennylane.tape.unwrap.UnwrapTape](_images/inheritance-61d1ea2178c3903e1956ea4521e8846f293e04e9.png)

### qml.utils[¶](#qml-utils "Permalink to this headline")

Warning

Unless you are a PennyLane or plugin developer, you likely do not need

to use these utility functions.

This module contains utilities and auxiliary functions which are shared

across the PennyLane submodules.

#### Functions[¶](#functions "Permalink to this headline")

| [`expand\_vector`](index.html#pennylane.utils.expand_vector "pennylane.utils.expand_vector")(vector, original\_wires, …) | Expand a vector to more wires. |

| [`pauli\_eigs`](index.html#pennylane.utils.pauli_eigs "pennylane.utils.pauli_eigs")(n) | Eigenvalues for \(A^{\otimes n}\), where \(A\) is Pauli operator, or shares its eigenvalues. |

| [`unflatten`](index.html#pennylane.utils.unflatten "pennylane.utils.unflatten")(flat, model) | Wrapper for `\_unflatten()`. |

### qml.wires[¶](#qml-wires "Permalink to this headline")

Warning

Unless you are a PennyLane or plugin developer, you likely do not need

to use the `Wires` class.

This module contains the [`Wires`](index.html#pennylane.wires.Wires "pennylane.wires.Wires") class, which takes care of wire bookkeeping.

#### Classes[¶](#classes "Permalink to this headline")

| [`WireError`](index.html#pennylane.wires.WireError "pennylane.wires.WireError") | Exception raised by a `Wire` object when it is unable to process wires. |

| [`Wires`](index.html#pennylane.wires.Wires "pennylane.wires.Wires")(wires[, \_override]) | A bookkeeping class for wires, which are ordered collections of unique objects. |

index

 

 Download Python script

 

 Download Notebook

 

 View on GitHub

### Contents

Using PennyLane

* [What is PennyLane?](index.html#document-introduction/pennylane)

* [Quantum circuits](index.html#document-introduction/circuits)

* [Gradients and training](index.html#document-introduction/interfaces)

* [Quantum operators](index.html#document-introduction/operations)

* [Measurements](index.html#document-introduction/measurements)

* [Templates](index.html#document-introduction/templates)

* [Inspecting circuits](index.html#document-introduction/inspecting_circuits)

* [Compiling circuits](index.html#document-introduction/compiling_circuits)

* [Quantum Chemistry](index.html#document-introduction/chemistry)

* [Quantum Datasets](index.html#document-introduction/data)

* [QNode returns](index.html#document-introduction/returns)

* [Logging](index.html#document-introduction/logging)

Development

* [Development guide](index.html#document-development/guide)

* [Building a plugin](index.html#document-development/plugins)

* [Adding new operators](index.html#document-development/adding_operators)

* [Deprecations](index.html#document-development/deprecations)

* [Release notes](index.html#document-development/release_notes)

API

* [qml](index.html#document-code/qml)

* [qml.data](index.html#document-code/qml_data)

* [qml.drawer](index.html#document-code/qml_drawer)

* [qml.fermi](index.html#document-code/qml_fermi)

* [qml.fourier](index.html#document-code/qml_fourier)

* [qml.gradients](index.html#document-code/qml_gradients)

* [qml.kernels](index.html#document-code/qml_kernels)

* [qml.logging](index.html#document-code/qml_logging)

* [qml.math](index.html#document-code/qml_math)

* [qml.numpy](index.html#document-code/qml_numpy)

* [qml.ops.op\_math](index.html#document-code/qml_ops_op_math)

* [qml.pauli](index.html#document-code/qml_pauli)

* [qml.pulse](index.html#document-code/qml_pulse)

* [qml.qinfo](index.html#document-code/qml_qinfo)

* [qml.resource](index.html#document-code/qml_resource)

* [qml.shadows](index.html#document-code/qml_shadows)

* [qml.transforms](index.html#document-code/qml_transforms)

* [qml.qaoa](index.html#document-code/qml_qaoa)

* [qml.qchem](index.html#document-code/qml_qchem)

* [qml.qnn](index.html#document-code/qml_qnn)

Internals

* [qml.devices](index.html#document-code/qml_devices)

* [qml.interfaces](index.html#document-code/qml_interfaces)

* [qml.measurements](index.html#document-code/qml_measurements)

* [qml.operation](index.html#document-code/qml_operation)

* [qml.queuing](index.html#document-code/qml_queuing)

* [qml.tape](index.html#document-code/qml_tape)

* [qml.utils](index.html#document-code/qml_utils)

* [qml.wires](index.html#document-code/qml_wires)

### Downloads

index

 

 Download Python script

 

 Download Notebook

 

 View on GitHub

###  Related

### Navigation

* [PennyLane 0.32.0 documentation](#) »

* PennyLane 0.32.0 documentation

---

