After more than 70 commits by 20 contributors, we’re excited to announce PennyLane v0.15, with many new and exciting features. These include new hardware device integration, more flexible shot control, brand new operations, and new methods for working with more powerful quantum circuits.

## More flexibility with shot control 📉

Flexible control over the number of QPU executions helps improve convergence and reduce costs. It is now possible to:

Specify shots on a per-call basis

>>> 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]

Run multiple experiments in one job by partitioning shots

>>> shots_list = [5, 10, 1000] >>> dev = qml.device("default.qubit", wires=2, shots=shots_list) >>> @qml.qnode(dev) ... def circuit(a, b): ... qml.RX(a, wires=0) ... qml.RY(b, wires=1) ... return qml.expval(qml.PauliZ(wires=0)) >>> circuit(0.8, 1.1) tensor([0.6 , 0.6 , 0.704], requires_grad=True)

Furthermore, if you want to conserve your shots, but you’re not sure how best to allocate them, you
can use our new `ShotAdaptiveOptimizer`. Based on the iCANS
and Rosalin schemes, the shot rate is
adaptively calculated using the variances of the parameter-shift gradient.

## Support for higher order gradients 🌐

PennyLane now supports second-order derivatives and Hessians, because sometimes a gradient is just not enough to train those harder models. Second-order derivatives can be computed using both the hardware-compatible parameter-shift rule and backpropagation, supporting all quantum hardware and classical machine learning libraries.

```
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)
```

The circuit defined above can now be used to calculate the Hessian as follows:

```
>>> hessian_fn = qml.jacobian(qml.grad(circuit))
>>> hessian_fn(x)
[[0.2248451 0.7651474]
[0.7651474 0.2248451]]
```

## Differentiable circuit transforms 🤖

Our menagerie of differentiable circuit transforms keeps expanding. You can now do the following in PennyLane, while retaining full differentiability of your code:

Invert gates—and arbitrary sequences of operations—with the new adjoint method

# applies RX(-0.123) to wire 0 qml.adjoint(qml.RX)(0.123, wires=0)

Add control wires to existing gates and parametrized templates

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()

Evaluate “in-circuit” classical jacobians, i.e., extract the classical dependence between the QNode arguments and the quantum gate arguments.

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 the

`classical_jacobian`transform to extract the relationship 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)\).

Check out the documentation for a full list of differentiable quantum transforms.

## New application-focused operations 🧩

We’re also constantly adding more operations and circuit templates related to specific applications. Among others, you can now try out our new operations for:

- Quantum chemistry, with the new two-qubit
`SingleExcitation`and four-qubit`DoubleExcitation`operations. - Quantum Monte Carlo simulations, including a
`QuantumMonteCarlo`template for performing quantum Monte Carlo estimation of an expectation value on a simulator. - A
`QuantumPhaseEstimation`template for performing quantum phase estimation for an input unitary matrix.

Additional new operations in PennyLane v0.15 include `ControlledPhaseShift`, `QFT`, `ControlledQubitUnitary`,
and `MultiControlledX`.

## New IonQ plugin ⚛️

We’re excited to announce support for another amazing hardware platform. You can now run your PennyLane models directly on quantum computing devices provided by IonQ— including both trapped ion hardware and simulators—via the new PennyLane-IonQ plugin:

```
import pennylane as qml
dev1 = qml.device('ionq.simulator', wires=2, shots=1000)
dev2 = qml.device('ionq.qpu', wires=2, shots=1000)
```

For more details, check out the blog post or plugin documentation.

## Improvements

Alongside the aforementioned new features, this release includes a slew of general improvements and bug fixes. Notable improvements include:

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))

Computing the Jacobian of QNodes now results in a smaller number of device evaluations.

The

`MottonenStatePreparation`template has improved performance on states with only real amplitudes by reducing the number of redundant CNOT gates at the end of a circuit.`KerasLayer`and`TorchLayer`now accept arbitrary dimensional inputs with support for broadcasting.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.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.

## Breaking changes and deprecations

There are a few major changes coming with this release, that will bring along a few deprecations and breaking changes. These are meant to streamline PennyLane’s usability, providing a clearer and more powerful package.

Devices do not have an

`analytic`argument 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`).dev_analytic = qml.device('default.qubit', wires=1, shots=None) dev_finite_shots = qml.device('default.qubit', wires=1, shots=1000)

Calling QNodes returning

`qml.sample()`now raises a`DeprecationWarning`if the number of shots is not explicitly set in the device, setting`shots=1000`as a transitory solution.Additionally, creating QNodes from quantum functions having a

`shots`argument will raise a`DeprecationWarning`, warning the user that this is a reserved argument to change the number of shots on a per-call basis.This release comes with some major changes to the PennyLane core. What was previously known as tape-mode has become the new default mode, replacing the old core. This change improves how PennyLane functions internally without any major alterations to the front-end. Noticable changes include the removal of

`qml.enable_tape()`and`qml.tape_mode_active()`, as well as the modules`pennylane.variables`and`pennylane.qnodes`.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.

These highlights are just scratching the surface; check out the full release notes for all the details.

Finally, thank you to all our contributors for this release:

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.