PennyLane v0.19 released

PennyLane team

The latest release of PennyLane is now out and available for everyone to use. It comes with many new additions, including a fully differentiable Hartree-Fock solver, error mitigation with Mitiq, powerful new transforms, improved support for batch execution, and much more.

Fully differentiable quantum chemistry workflows ⚛️

Part of what makes PennyLane so powerful is its focus on differentiable workflows, allowing every aspect of your hybrid quantum-classical code to be optimized.

With this new release, we extend this philosophy to quantum chemistry, with the introduction of a fully differentiable Hartree-Fock solver. Construct molecular Hamiltonians and perform variational quantum algorithms that can be differentiated and optimized with respect to molecular geometry, basis set, and circuit parameters simultaneously.

Train the molecule alongside your variational algorithm, or simply explore how optimizing the basis set parameters allows you to reach lower ground-state energies without increasing the size of the basis set.

For more details and examples, please refer to the differentiable Hartree-Fock solver documentation. You can also learn more about molecular geometry optimization with PennyLane from our latest paper and demonstration.

Error mitigation with Mitiq 📣

With near quantum, comes great noise.

The rapid availability of near-term quantum hardware provides an amazing playground for testing and prototyping hybrid quantum-classical algorithms. However, these near-term devices aren’t perfect — noise tends to creep in, affecting the ability of our algorithms to work as expected.

With this release, PennyLane now integrates with Mitiq, a software toolkit from the Unitary Fund for mitigating errors on quantum hardware. Transform your QNodes (and devices!) using the zero-noise extrapolation method now available through the qml.transforms.mitigate_with_zne transform:

from mitiq.zne.scaling import fold_global
from mitiq.zne.inference import RichardsonFactory

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

For more details, check out the mitigate_with_zne documentation.

Powerful new transforms 🤖

Our library of quantum transforms keeps growing. Manipulate, inspect, and transform QNodes to your heart’s content. All transforms provided by PennyLane are fully differentiable, and can even be trained themselves.

Add a batch dimension to QNodes with @qml.batch_params

Transform a QNode to support an initial batch dimension for operation parameters:

@qml.batch_params
@qml.beta.qnode(dev)
def circuit(weights):
    qml.StronglyEntanglingLayers(weights, wires=[0, 1, 2])
    return qml.expval(qml.Hadamard(0))

By applying the @qml.batch_params decorator to the QNode, we can now include a batch dimension for all QNode arguments when executing the QNode. The evaluated QNode will have an output of shape (batch_size,):

>>> batch_size = 3
>>> weights = np.random.random((batch_size, 10, 3, 3))
>>> circuit(x, weights)
tensor([-0.30773348 0.23135516 0.13086565], requires_grad=True)

Extract numeric representations of circuits with qml.transforms.get_unitary_matrix

And even differentiate the returned matrix with respect to QNode arguments!

def circuit(theta):
    qml.RX(theta, wires=1)
    qml.PauliZ(wires=0)
    qml.CNOT(wires=[0, 1])

def cost(theta):
    matrix = get_unitary_matrix(circuit)(theta)
    return np.real(np.trace(matrix))
>>> theta = np.array(0.3, requires_grad=True)
>>> cost(theta)
1.9775421558720845
>>> qml.grad(cost)(theta)
-0.14943813247359922

Visualize batch transformed QNodes

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.

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──┤

Differentiable 2-qubit unitary decomposition

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.

Insert gates and channels automatically into a quantum circuit

The qml.transforms.insert transform has now been added, providing a way to insert single-qubit operations into a quantum circuit, at various automatic positions. The transform can apply to quantum functions, tapes, and devices. If applied to a device, any QNode executed on that device will automatically have the specified operations inserted!

Test drive our new QNode 🚗

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.

It differs from the standard QNode in several ways:

Everything is batched

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.

Arbitrary \(n\)-th order derivatives on hardware

Compute arbitrary higher-order derivatives using any support gradient transform — even on hardware. All gates and templates are supported. Note that to specify that an \(n\)-th order derivative of a QNode needs to be computed, the max_diff argument should be set. By default, this is set to 1 (first-order derivatives only).

Better decomposition strategies

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.

Custom gradient transforms can be specified as the differentiation method

Take any of our provided gradient transforms in qml.gradients and bind it to a QNode for backpropagation. Or even define your own custom gradient transform!

@qml.gradients.gradient_transform
def my_gradient_transform(tape):
    ...
    return tapes, processing_fn

@qml.beta.qnode(dev, diff_method=my_gradient_transform)
def circuit():

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 on our GitHub bug tracker.

New operations and templates

Alongside the great new features above, we also have a ton of new operations and templates to share. These include:

  • A new operation qml.OrbitalRotation, which implements the spin-adapted spatial orbital rotation gate.
  • A new template qml.GateFabric, which implements a local, expressive, quantum-number-preserving ansatz proposed by Anselmetti et al. in arXiv:2104.05692
  • A new template qml.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

Improvements

In addition to the new features listed above, the release contains a wide array of improvements and optimizations:

  • The qml.metric_tensor transform supports batching. Quantum circuits required to compute the metric tensor elements will be automatically submitted as a batched job. This can lead to significant performance improvements.

  • The qml.metric_tensor transform now supports a larger set of operations, including all operations that have a single variational parameter and define a generator. In addition to a reduction in decomposition overhead, the change also results in fewer circuit evaluations.

  • Operator properties and attributes are now collected in the pennylane.ops.qubit.attributes module — including properties useful for compilation, such as self_inverses. These attributes can be extended dynamically, and are used by various PennyLane compilation transforms.

  • The new qml.fourier.qnode_spectrum function allows the Fourier spectrum of QNodes to be computed with respect to QNode arguments, allowing for detailed characterization of variational algorithms.

  • 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.

  • The ApproxTimeEvolution template can now be used with Hamiltonians that have trainable coefficients.

  • Templates are now top level imported and can be used directly; for example, qml.StronglyEntanglingWires(weights, wires).

  • Two new methods were added to the Device API, device.expand_fn and device.batch_transform, allowing PennyLane devices increased control over circuit decompositions.

Breaking changes

As new things are added, outdated features are removed. Here’s what will be disappearing in this release:

  • The qml.inv function has been removed, qml.adjoint should be used instead.

  • The operation qml.Interferometer has been renamed qml.InterferometerUnitary in order to distinguish it from the template qml.templates.Interferometer.

  • Templates SingleExcitationUnitary and DoubleExcitationUnitary have been renamed to FermionicSingleExcitation and FermionicDoubleExcitation, respectively.

  • 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 pennylane.ops.qubit.attributes.

Deprecations

There are also a couple of important deprecations in the pipeline:

  • 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.

  • 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.

  • The QNode.draw and QNode.metric_tensor methods has been deprecated, and will be removed in an upcoming release. Please use the qml.draw and qml.metric_tensor transforms instead.

  • The pad parameter of the qml.AmplitudeEmbedding template has been removed. It has instead been renamed to the pad_with parameter.

  • The default.tensor device from the beta folder has not been maintained in years and is deprecated. It will be removed in future releases.

  • 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.

  • 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.

These highlights are just scratching the surface — check out the full release notes for more details.

Contributors

As always, this release would not have been possible without the hard work of our development team and contributors:

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.