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

January 09, 2024

PennyLane v0.34 and Catalyst v0.4 released

Isaac De Vlugt

Isaac De Vlugt

Thomas Bromley

Thomas Bromley

Josh Izaac

Josh Izaac

New Year, new features πŸ₯³! Ring in 2024 with the latest and greatest functionality in PennyLane v0.34 and Catalyst v0.4 πŸ””

Contents

  • Catalyst integration with PennyLane, and much more! βš—οΈ
  • Statistics and drawings for mid-circuit measurements 🎨
  • Decompose circuits into the Clifford+T gateset 🧩
  • Use an iterative approach for quantum phase estimation πŸ”„
  • New Catalyst features: asynchronous execution, dynamic arrays, transforms, and error-mitigation πŸƒ
  • Transforms πŸ€–
  • Improvements πŸ› οΈ
  • Deprecations and breaking changes πŸ’”
  • Contributors ✍️

Catalyst integration with PennyLane, and much more! βš—οΈ

Catalyst enables just-in-time (JIT) compilation of PennyLane programs, allowing you to compile the entire quantum-classical workflow.

Now, Catalyst can be accessed more easily from PennyLane using the qml.qjit decorator:

import pennylane as qml dev = qml.device("lightning.qubit", wires=2) @qml.qjit @qml.qnode(dev) def circuit(theta): qml.Hadamard(wires=0) qml.RX(theta, wires=1) qml.CNOT(wires=[0,1]) return qml.expval(qml.PauliZ(wires=1))

With qml.qjit, both quantum and classical processing is JIT compiled β€” down to a machine binary on first-function execution. Subsequent calls to the compiled function will execute the previously-compiled binary, resulting in significant performance improvements.

To access these features, make sure that you pip install pennylane-catalyst. Check out more new Catalyst features below!

Statistics and drawings for mid-circuit measurements 🎨

We’re not middling around with mid-circuit measurements 🧠!

In the last couple of releases, we've made a concerted effort to making our mid-circuit measurement ecosystem more versatile and easier to interact with. We're continuing on that path in v0.34 with a couple of great new features:

  • Mid-circuit measurements including qubit reuse and reset, postselection, conditioning, and collecting statistics is now supported with the text-based qml.draw() and the graphical qml.draw_mpl() methods.

    def circuit(): m0 = qml.measure(0, reset=True) m1 = qml.measure(1, postselect=1) qml.cond(m0 - m1 == 0, qml.S)(0) m2 = qml.measure(1) qml.cond(m0 + m1 == 2, qml.T)(0) qml.cond(m2, qml.PauliX)(1)

    The text-based drawer outputs:

    >>> print(qml.draw(circuit)()) 0: ───↗│ β”‚0βŸ©β”€β”€β”€β”€β”€β”€β”€β”€S───────T───── 1: β”€β”€β”€β•‘β”€β”€β”€β”€β”€β”€β”€β”€β”€β†—β‚β”œβ”€β”€β•‘β”€β”€β”€β†—β”œβ”€β”€β•‘β”€β”€X── β•šβ•β•β•β•β•β•β•β•β•β•‘β•β•β•β•β•¬β•β•β•β•‘β•β•β•β•£ β•‘ β•šβ•β•β•β•β•©β•β•β•β•‘β•β•β•β• β•‘ β•šβ•β•β•β•β•β•β•

    The graphical drawer outputs:

    >>> print(qml.draw_mpl(circuit)())
  • Mid-circuit measurement results can now be composed using basic arithmetic operations and then statistics can be calculated by putting the result within a PennyLane measurement like qml.expval(). For example:

    dev = qml.device("default.qubit") @qml.qnode(dev) def circuit(phi, theta): qml.RX(phi, wires=0) m0 = qml.measure(wires=0) qml.RY(theta, wires=1) m1 = qml.measure(wires=1) return qml.expval(~m0 + m1) print(circuit(1.23, 4.56))
    1.2430187928114291

    Another option, for ease-of-use when using qml.sample(), qml.probs(), or qml.counts(), is to provide a simple list of mid-circuit measurement results:

    @qml.qnode(dev) def circuit(phi, theta): qml.RX(phi, wires=0) m0 = qml.measure(wires=0) qml.RY(theta, wires=1) m1 = qml.measure(wires=1) return qml.sample(op=[m0, m1]) print(circuit(1.23, 4.56, shots=5))
    [[0 1] [0 1] [0 0] [1 0] [0 1]]

    Composite mid-circuit measurement statistics are supported on default.qubit and default.mixed. To learn more about which measurements and arithmetic operators are supported, refer to the measurements page and the documentation for qml.measure.

Decompose circuits into the Clifford+T gateset 🧩

We made sure to have this as a New Year's resolution decomposition πŸ˜‰

Clifford+T in PennyLane

Circuits can now be decomposed into the Clifford+T gateset with the new qml.clifford_t_decomposition() transform. Behind the scenes, this decomposition is enacted via the Solovay-Kitaev algorithm, which approximately decomposes a quantum circuit into the Clifford+T gateset. To account for errors in the approximation, a desired total circuit decomposition error, epsilon, must be specified when using qml.clifford_t_decomposition:

dev = qml.device("default.qubit") @qml.qnode(dev) def circuit(): qml.RX(1.1, 0) return qml.state() circuit = qml.clifford_t_decomposition(circuit, epsilon=0.1)
>>> circuit() [ 0.86033365-0.03792839j -0.01571045-0.50807542j] >>> print(qml.draw(circuit)()) 0: ──T†──H──T†──H──T──H──T──H──T──H──T──H──T†──H──T†──T†──H──T†──H──T──H──T──H──T──H──T──H──T†──H──T†──H──T──H──GlobalPhase(0.39)── State

The resource requirements of this circuit can also be evaluated:

with qml.Tracker(dev) as tracker: circuit() resources_lst = tracker.history['resources'] print(resources_lst[0])
wires: 1 gates: 34 depth: 34 shots: Shots(total=None) gate_types: {'Adjoint(T)': 8, 'Hadamard': 16, 'T': 9, 'GlobalPhase': 1} gate_sizes: {1: 33, 0: 1}

Use an iterative approach for quantum phase estimation πŸ”„

More versatility for one of quantum's prized algorithms πŸ’ͺ

Last release, we added a couple of great features β€” ControlledSequence and CosineWindow β€” for modularizing QPE. In this release, we've added iterative quantum phase estimation (IQPE) with qml.iterative_qpe. The subroutine can be used similarly to mid-circuit measurements:

dev = qml.device("default.qubit", shots=5) @qml.qnode(dev) def circuit(): qml.PauliX(wires=[0]) measurements = qml.iterative_qpe(qml.RZ(2., wires=[0]), ancilla=[1], iters=3) return qml.sample(op=measurements)
>>> print(circuit()) [[0 0 1] [0 0 1] [0 0 1] [0 0 1] [0 0 1]]

The i-th element in the list refers to the 5 samples generated by the i-th measurement of the algorithm.

New Catalyst features: asynchronous execution, dynamic arrays, transforms, and error-mitigation πŸƒ

With this release, we've added a bunch of new and exciting features to Catalyst, such as asynchronous execution of multiple QNodes, new compilation routines, and support for arrays with dynamic shapes.

Asynchronous execution of QNodes

Just-in-time compiled functions now support asynchronuous execution of QNodes. Simply specify async_qnodes=True when using the @qml.qjit decorator to enable the async execution of QNodes. Currently, asynchronous execution is only supported by lightning.qubit and lightning.kokkos.

Asynchronous execution will be most beneficial for just-in-time compiled functions that contain β€” or generate β€” multiple QNodes.

For example,

from jax import numpy as jnp dev = qml.device("lightning.qubit", wires=2) @qml.qnode(device=dev) def circuit(params): qml.RX(params[0], wires=0) qml.RY(params[1], wires=1) qml.CNOT(wires=[0, 1]) return qml.expval(qml.PauliZ(wires=0)) @qml.qjit(async_qnodes=True) def multiple_qnodes(params): x = jnp.sin(params) y = jnp.cos(params) z = jnp.array([circuit(x), circuit(y)]) # will be executed in parallel return circuit(z)
>>> func(jnp.array([1.0, 2.0])) 1.0

Here, the first two circuit executions will occur in parallel across multiple threads, as their execution can occur independently.

Support for PennyLane transforms

Preliminary support for PennyLane transforms has been added. These transformations will be applied in Python, prior to compilation occurring:

@qml.qjit @qml.transforms.split_non_commuting @qml.qnode(dev) def circuit(x): qml.RX(x,wires=0) return [qml.expval(qml.PauliY(0)), qml.expval(qml.PauliZ(0))]
>>> circuit(0.4) [array(-0.51413599), array(0.85770868)]

Dynamically-shaped arrays

The @qml.qjit decorator can now be used to compile functions that accepts or contain tensors whose dimensions are not known at compile time; runtime execution with different shapes is supported without recompilation.

In addition, standard tensor initialisation functions jax.numpy.ones, jnp.zeros, and jnp.empty now accept dynamic variables (where the value is only known at runtime).

For more details, see the qjit documentation.

Built-in error mitigation

Error mitigation using the zero-noise extrapolation method is now available through the catalyst.mitigate_with_zne transform. This transform can be applied to any qjit-compiled QNode, allowing for error mitigation on quantum programs with dynamic circuit structure.

Transforms πŸ€–

You name it, PennyLane can transform it πŸ€–

Over the last couple of releases, we've been rolling out changes to our transforms API to make it more intuitive and versatile. We're never done making changes and improvements, but now is a good time to summarize and highlight these new features to you!

First, let's see how to make a transform following the new style:

@qml.transform def my_quantum_transform(tape): no_rx = filter(lambda op: op.name != "RX", tape.operations) no_ry = filter(lambda op: op.name != "RY", tape.operations) tape1 = qml.tape.QuantumTape(no_rx, tape.measurements) tape2 = qml.tape.QuantumTape(no_ry, tape.measurements) def post_processing_fn(results): return qml.math.sum(results) return [tape1, tape2], post_processing_fn

We decorate our function with @qml.transform and ensure that it returns a sequence of QuantumTape objects and a postprocessing function. See the qml.transform docs for more details.

We can now show off one of our main featuresβ€”it is now possible to arbitrarily compose transforms together. Let's see it in action:

dev = qml.device("default.qubit") @my_quantum_transform @qml.transforms.hamiltonian_expand @qml.qnode(dev) def circuit(x): qml.RX(x, 0) qml.RY(x, 0) return qml.expval(qml.PauliX(0) + qml.PauliZ(0)) circuit(0.5)

In the above, we have combined our custom transform with hamiltonian_expand.

For more information, check out our bolstered transforms documentation page!

Improvements πŸ› οΈ

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

  • The Approximate Quantum Fourier Transform (AQFT) is now available with qml.AQFT, as well as eleven other community contributions πŸš€.

  • qml.AmplitudeEmbedding now supports batching when used with TensorFlow.

  • Autograd, PyTorch, and JAX can now use vector-Jacobian products (VJPs) provided by the device from the new device API. If a device provides a VJP, this can be selected by providing device_vjp=True to a QNode or qml.execute.

    >>> dev = qml.device('default.qubit') >>> @qml.qnode(dev, diff_method="adjoint", device_vjp=True) >>> def circuit(x): ... qml.RX(x, wires=0) ... return qml.expval(qml.PauliZ(0)) >>> with dev.tracker: ... g = qml.grad(circuit)(qml.numpy.array(0.1)) >>> dev.tracker.totals {'batches': 1, 'simulations': 1, 'executions': 1, 'vjp_batches': 1, 'vjps': 1} >>> g -0.09983341664682815
  • ClassicalShadow.entropy now uses the algorithm outlined in 1106.5458 to project the approximate density matrix (with potentially negative eigenvalues) onto the closest valid density matrix.

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:

  • single_tape_transform, batch_transform, qfunc_transform, and op_transform are deprecated. Use the new qml.transform function instead.

  • The functions qml.transforms.one_qubit_decomposition, qml.transforms.two_qubit_decomposition, and qml.transforms.sk_decomposition were moved to qml.ops.one_qubit_decomposition, qml.ops.two_qubit_decomposition, and qml.ops.sk_decomposition, respectively.

  • The function qml.transforms.classical_jacobian has been moved to the gradients module and is now accessible as qml.gradients.classical_jacobian.

  • The transforms submodule qml.transforms.qcut is now its own module: qml.qcut.

  • The "pennylane" MPL-drawer style now draws straight lines instead of sketch-style lines.


These highlights are just scratching the surface β€” check out the full release notes for more details, and let us know how you're liking the new release in the PennyLane v0.34 survey.

Contributors ✍️

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

Guillermo Alonso, Ali Asadi, Utkarsh Azad, Gabriel Bottrill, Thomas Bromley, Astral Cai, Minh Chau, Isaac De Vlugt, Amintor Dusko, Pieter Eendebak, Tarik El-Khateeb, Lillian Frederiksen, Pietropaolo Frisoni, Ivana KurečiΔ‡, David Ittah, Josh Izaac, Juan Giraldo, Emiliano Godinez Ramirez, Ankit Khandelwal, Korbinian Kottmann, Christina Lee, Erick Ochoa Lopez, Vincent Michaud-Rioux, Sergei Mironov, Anurav Modak, Romain Moyard, Lee James O'Riordan, Mudit Pandey, Shuli Shu, Matthew Silverman, Jay Soni, David Wierichs, Justin Woodring.

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