PennyLane
  • Why PennyLane
  • Getting Started
  • Documentation
  • Ecosystem
Install
Install
  1. Blog/
  2. Releases/
  3. PennyLane v0.35 and Catalyst v0.5 released

March 05, 2024

PennyLane v0.35 and Catalyst v0.5 released

Isaac De Vlugt

Isaac De Vlugt

Thomas Bromley

Thomas Bromley

Josh Izaac

Josh Izaac

Life still goes on after QHack! We've got a load of new features lined up for you with PennyLane v0.35 and Catalyst v0.5. ๐Ÿ™Œ Let us know how hyped you are for this release by filling out the latest surveyโ€”your feedback will help shape the future of PennyLane ๐Ÿ”ฎ

Contents

  • Qiskit 1.0 integration ๐Ÿ”Œ
  • CUDA Quantum integration ๐Ÿ”ง
  • Native mid-circuit measurements on default.qubit ๐Ÿ’ก
  • A new Clifford device ๐Ÿฆพ
  • New Catalyst features: vectorize with vmap, more QJIT functionality, mid-circuit measurement improvements and more! ๐Ÿƒ
  • Improvements ๐Ÿ› ๏ธ
  • Deprecations and breaking changes ๐Ÿ’”
  • Contributors โœ๏ธ

Qiskit 1.0 integration ๐Ÿ”Œ

Quantum programming is a big, wonderful place, but all roads lead to PennyLane ๐Ÿ˜Ž

This version of PennyLane makes it easier to import workflows from Qiskit. The qml.from_qiskit function converts a Qiskit QuantumCircuit into a PennyLane quantum function. Although qml.from_qiskit already exists in PennyLane, we have made a number of improvements to make importing from Qiskit easier. And yes โ€” qml.from_qiskit functionality is compatible with both Qiskit 1.0 and earlier versions!

Make sure you install PennyLane's Qiskit plugin to access these features:

  • You can now append PennyLane measurements onto the quantum function returned by qml.from_qiskit. Consider this simple Qiskit circuit:

    import pennylane as qml from qiskit import QuantumCircuit qc = QuantumCircuit(2) qc.rx(0.785, 0) qc.ry(1.57, 1)

    We can convert it into a PennyLane QNode in just a few lines, with PennyLane measurements easily included:

    >>> dev = qml.device("default.qubit") >>> measurements = qml.expval(qml.Z(0) @ qml.Z(1)) >>> qfunc = qml.from_qiskit(qc, measurements=measurements) >>> qnode = qml.QNode(qfunc, dev) >>> qnode() tensor(0.00056331, requires_grad=True)
  • Quantum circuits that already contain Qiskit-side measurements can be faithfully converted with qml.from_qiskit.

  • It is now more intuitive to handle and differentiate parametrized Qiskit circuits.

  • In addition to full circuits, it is now also possible to convert operators from Qiskit to PennyLane with a new function called qml.from_qiskit_op.

    A Qiskit SparsePauliOp can be converted to a PennyLane operator using qml.from_qiskit_op:

    >>> from qiskit.quantum_info import SparsePauliOp >>> qiskit_op = SparsePauliOp(["II", "XY"]) >>> qiskit_op SparsePauliOp(['II', 'XY'], coeffs=[1.+0.j, 1.+0.j]) >>> pl_op = qml.from_qiskit_op(qiskit_op) >>> pl_op I(0) + X(1) @ Y(0)

    Combined with qml.from_qiskit, it becomes easy to quickly calculate quantities like expectation values by converting the whole workflow to PennyLane:

    qc = QuantumCircuit(2) # Create circuit qc.rx(0.785, 0) qc.ry(1.57, 1) measurements = qml.expval(pl_op) # Create QNode qfunc = qml.from_qiskit(qc, measurements) qnode = qml.QNode(qfunc, dev)
    >>> qnode() # Evaluate! tensor(0.29317504, requires_grad=True)

To read more about our updated Qiskit conversion capabilities, check out the quick start guide for importing workflows into PennyLane.

CUDA Quantum integration ๐Ÿ”ง

When using PennyLane's @qml.qjit decorator for just-in-time compilation, simply specify @qml.qjit(compiler="cuda_quantum") to utilize CUDA Quantum to compile your PennyLane workflow, and execute it on CUDA Quantum supported backends!

dev = qml.device("softwareq.qpp", wires=2) @qml.qjit(compiler="cuda_quantum") @qml.qnode(dev) def circuit(x): qml.RX(x[0], wires=0) qml.RY(x[1], wires=1) qml.CNOT(wires=[0, 1]) return qml.expval(qml.PauliY(0))
>>> circuit(jnp.array([0.5, 1.4])) -0.47244976756708373

The following devices are available when compiling with CUDA Quantum:

  • softwareq.qpp: a modern C++ state vector simulator
  • nvidia.custatevec: The NVIDIA CuStateVec GPU simulator (with multi-GPU support)
  • nvidia.cutensornet: The NVIDIA CuTensorNet GPU simulator (with support for matrix product states)

Note that CUDA Quantum compilation currently does not have feature parity with Catalyst compilation; in particular, AutoGraph, control flow, differentiation, and various measurement statistics (such as probabilities and variance) are not yet supported.

For more details, please see the Compiling workflows documentation.

Native mid-circuit measurements on default.qubit ๐Ÿ’ก

These features aren't halfmid-baked ๐Ÿž

Dynamic circuits in PennyLane

One of PennyLane's major focuses for 2024 is to improve support for dynamic circuits, where mid-circuit measurements can determine downstream circuit structure. Building on our existing mid-circuit measurement capabilities, you'll see a continuous stream of improvements over the next few releases. In this release, we decided to focus on the basicsโ€”making sure that mid-circuit measurements (MCMs) can be executed efficiently.

MCMs can now be made more scalable and efficient in finite-shots mode with default.qubit by simulating them in a way similar to what happens on quantum hardware. Previously, MCMs would be automatically replaced with an additional qubit using the @qml.defer_measurements transform, and circuits with a lot of MCMs (like the one below) would have used thousands of qubits to simulate.

With finite shots on default.qubit, each shot and each time an MCM is encountered, the device now evaluates the probability of projecting onto \vert 0 \rangle or \vert 1 \rangle and makes a random choice to collapse the circuit state. This approach works well when there are a lot of MCMs and the number of shots is not too high.

import pennylane as qml dev = qml.device("default.qubit", shots=10) @qml.qnode(dev) def f(): for i in range(1967): qml.Hadamard(0) qml.measure(0) return qml.sample(qml.PauliX(0))
>>> f() tensor([-1, -1, -1, 1, 1, -1, 1, -1, 1, -1], requires_grad=True)

A new Clifford device ๐Ÿฆพ

Feel good about being left to your own devices ๐Ÿ˜Œ

A new default.clifford device enables efficient simulation of large-scale Clifford circuits defined in PennyLane through the use of Stim as a backend.

Given a circuit with only Clifford gates, one can use this device to obtain the usual range of PennyLane measurements as well as the state represented in the Tableau form of Aaronson & Gottesman (2004):

import pennylane as qml dev = qml.device("default.clifford", tableau=True) @qml.qnode(dev) def circuit(): qml.CNOT(wires=[0, 1]) qml.PauliX(wires=[1]) qml.ISWAP(wires=[0, 1]) qml.Hadamard(wires=[0]) return qml.state()
>>> circuit() array([[0, 1, 1, 0, 0], [1, 0, 1, 1, 1], [0, 0, 0, 1, 0], [1, 0, 0, 1, 1]])

The default.clifford device also supports the PauliError, DepolarizingChannel, BitFlip and PhaseFlip noise channels when operating in finite-shot mode.

New Catalyst features: vectorize with vmap, more QJIT functionality, mid-circuit measurement improvements and more! ๐Ÿƒ

Vectorization support with vmap

When working with tensor/array frameworks in Python, it can be important to ensure that code is written to minimize the usage of Python for loops (which can be slow and inefficient), and instead push as much of the computation through to the array manipulation library, by taking advantage of extra batch dimensions.

To help, Catalyst now provides a QJIT-compatible catalyst.vmap() function, which makes it even easier to modify functions to map over inputs with additional batch dimensions.

For example, consider the following QNode:

dev = qml.device("lightning.qubit", wires=1) @qml.qnode(dev) def circuit(x, y): qml.RX(jnp.pi * x[0] + y, wires=0) qml.RY(x[1] ** 2, wires=0) qml.RX(x[1] * x[2], wires=0) return qml.expval(qml.PauliZ(0))
>>> circuit(jnp.array([0.1, 0.2, 0.3]), jnp.pi) Array(-0.93005586, dtype=float64)

We can use catalyst.vmap to introduce additional batch dimensions to our input arguments, without needing to use a Python for loop:

>>> from catalyst import vmap >>> x = jnp.array([[0.1, 0.2, 0.3], ... [0.4, 0.5, 0.6], ... [0.7, 0.8, 0.9]]) >>> y = jnp.array([jnp.pi, jnp.pi / 2, jnp.pi / 4]) >>> qjit(vmap(cost))(x, y) array([-0.93005586, -0.97165424, -0.6987465 ])

catalyst.vmap() has been implemented to match the same behaviour of jax.vmap, so it should be a drop-in replacement in most cases. Under the hood, it is automatically inserting Catalyst-compatible for loops, which will be compiled and executed outside of Python for increased performance.

Post-selection and qubit reset

Mid-circuit measurements now support post-selection and qubit reset when used with the Lightning simulators.

To specify post-selection, simply pass the postselect argument to the catalyst.measure function:

dev = qml.device("lightning.qubit", wires=1) @qjit @qml.qnode(dev) def f(): qml.Hadamard(0) m = catalyst.measure(0, postselect=1) return qml.expval(qml.PauliZ(0))

Likewise, to reset a wire after mid-circuit measurement, simply specify reset=True.

Just-in-time compilation of static (compile-time constant) arguments

The @qml.qjit decorator now takes a new argument static_argnums, which specifies that certain positional arguments of the decorated function should be treated as compile-time static arguments.

This allows any hashable Python object to be passed to the function during compilation; the function will only be recompiled if the value of the static arguments change. Otherwise, reusing previous static argument values will result in no recompilation.

For more details, see specifying compile-time constants.

Improvements ๐Ÿ› ๏ธ

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

  • Over the past few releases, we've strived to make working with PennyLane operators as easy as with pen and paper and to improve operator arithmetic efficiency. The updated operator arithmetic functionality is still being finalized, but can be activated using qml.operation.enable_new_opmath(). You can check out all of the changes in the full release notes. The new behaviour will become the default in the next release, so we recommend getting familiar with the new system!

  • Lightning GPU now supports CUDA version 12, allowing you to get the latest and greatest out of your NVIDIA GPUs.

  • Vector-Jacobian products (VJPs) can result in faster computations when the output of your quantum node has a low dimension. They can be enabled by setting device_vjp=True when loading a QNode. In the next release of PennyLane, VJPs are planned to be used by default, when available. You can check out the experimental support offered in PennyLane v0.35 by heading to the improvements section of the release notes.

  • Catalyst now supports Python 3.12 and JAX 0.4.23, and the dependence on TensorFlow for use of AutoGraph functionality has been removed.

  • Improvements have been made to the @qml.qjit decorator, reducing the need to recompile the function if previously called with known argument types and static values.

  • Gradient functions used within a @qjit compiled function (such as qml.grad, qml.jacobian, qml.vjp, and qml.jvp) are now much more flexible, and support being applied to functions that use (nested) container types as inputs and outputs. This includes lists and dictionaries, as well as any data structure implementing the PyTree protocol.

  • Capturing quantum circuits for just-in-time compilation with @qml.qjit with many gates is now quadratically faster.

Deprecations and breaking changes ๐Ÿ’”

As new things are added, outdated features are removed. To keep track of things in the deprecation pipeline, check out the deprecations page.

Here's a summary of what has changed in this release:

  • Passing additional arguments to a transform that decorates a QNode must now be done through the use of functools.partial.

  • qml.ExpvalCost has been removed. Users should use qml.expval() moving forward.

  • Calling qml.matrix without providing a wire_order on objects where the wire order could be ambiguous now raises a warning. In the future, the wire_order argument will be required in these cases.

  • Gradient functions when used with @qjit now match the JAX convention for the returned axes of gradients, Jacobians, VJPs, and JVPs. As a result, the returned tensor shape from various gradient functions may differ compared to previous versions of PennyLane and Catalyst.


These highlights are just scratching the surface โ€” check out the full release notes for PennyLane and Catalyst for more details.

Contributors โœ๏ธ

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

Abhishek Abhishek, Mikhail Andrenkov, Ali Asadi, Utkarsh Azad, Trenten Babcock, Gabriel Bottrill, Thomas Bromley, Astral Cai, Skylar Chan, Isaac De Vlugt, Diksha Dhawan, Tarik El-Khateeb, Lillian Frederiksen, Pietropaolo Frisoni, Eugenio Gigante, Diego Guala, David Ittah, Soran Jahangiri, Jacky Jiang, Tzung-Han Juang, Korbinian Kottmann, Ivana Kureฤiฤ‡, Christina Lee, Xiaoran Li, Vincent Michaud-Rioux, Romain Moyard, Pablo Antonio Moreno Casares, Erick Ochoa Lopez, Lee J. O'Riordan, Mudit Pandey, Alex Preciado, Matthew Silverman, Jay Soni, Raul Torres, Haochen Paul Wang.

About the authors

Isaac De Vlugt
Isaac De Vlugt

Isaac De Vlugt

My job is to help manage the PennyLane and Catalyst feature roadmap... and spam lots of emojis in the chat ๐Ÿค 

Thomas Bromley
Thomas Bromley

Thomas Bromley

Josh Izaac
Josh Izaac

Josh Izaac

Josh is a theoretical physicist, software tinkerer, and occasional baker. At Xanadu, he contributes to the development and growth of Xanaduโ€™s open-source quantum software products.

Last modified:ย August 14, 2024

Related Blog Posts

PennyLane

PennyLane is an open-source software framework for quantum machine learning, quantum chemistry, and quantum computing, with the ability to run on all hardware. Built with โค๏ธ by Xanadu.

Stay updated with our newsletter

For researchers

  • Research
  • Features
  • Demos
  • Compilation
  • Datasets
  • Performance
  • Learn
  • Videos
  • Documentation
  • Teach

For learners

  • Learn
  • Codebook
  • Teach
  • Videos
  • Challenges
  • Demos
  • Compilation
  • Glossary

For developers

  • Features
  • Documentation
  • API
  • GitHub
  • Datasets
  • Demos
  • Compilation
  • Performance
  • Devices
  • Catalyst

ยฉ Copyright 2025 | Xanadu | All rights reserved

TensorFlow, the TensorFlow logo and any related marks are trademarks of Google Inc.

Privacy Policy|Terms of Service|Cookie Policy|Code of Conduct