PennyLane
  • Why PennyLane
  • Getting Started
  • Documentation
  • Ecosystem
Install
Install
  1. Blog/
  2. Releases/
  3. PennyLane v0.28 released

December 20, 2022

PennyLane v0.28 released

Isaac De Vlugt

Isaac De Vlugt

PennyLane v0.28 โ€” the release so good, not even ChatGPT can fathom it ๐Ÿค–! Check out all of the awesome new functionality below.

# This code block gets replaced with the table of contents. # Documentation: https://www.gatsbyjs.com/plugins/gatsby-remark-table-of-contents/

Custom measurement processes ๐Ÿ“

Spread your wings and get creative with the ability to create custom measurements using the new qml.measurements module!

PL-3D-Measuring-Tool

Previously, PennyLane only came with built-in measurements that you can return from QNodes: qml.expval, qml.probs, etc., to name a few. Over time, we have added more, but now you can define your own measurement process function to use in QNodes.

Within qml.measurements are new subclasses that allow for the possibility to create measurements:

  • StateMeasurement: represents a state-based measurement
  • SampleMeasurement: represents a sample-based measurement

Creating a custom measurement involves making a class that inherits from one of the classes above. Here is an example that inherits from SampleMeasurement, where the new measurement, CountState, computes the number of obtained samples for 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)

The method process_samples must be defined in order to instruct how CountState processes the samples. Within it, a call to the familiar qml.counts measurement is made, its process_samples method is called to obtain measurement counts, and only counts for the specified state are returned.

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 conserved for this new measurement process:

>>> x = qml.numpy.array(1.23, requires_grad=True) >>> qml.grad(circuit)(x) 4715.000000000001
  • MeasurementTransform: represents a measurement process that requires the application of a batch transform

For more information about these new features, see the documentation for qml.measurements.

ZX-calculus ๐Ÿงฎ

The magic of ZX-calculus is now at your fingertips! Envision quantum protocols like a boss. ๐Ÿ˜ค

Circuit-Transformation

ZX-calculus is a graphical formalism designed to provide an intuitive way to look at quantum protocols as linear maps between qubits, which are called ZX-diagrams. A great example of how intuitive a ZX-diagram can be is the one representing a SWAP gate โ€” consisting of three CNOT gates โ€” as seen above.

With the help of the PyZX framework, QNodes decorated with @qml.transforms.to_zx will return a PyZX graph that represents the computation at hand in the language of ZX-calculus.

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.

PubChem database access and new basis sets โš›

PubChem database access

PennyLane, meet PubChem. PubChem, meet PennyLane. ๐Ÿค

PL-PubChem

The symbols and geometry of compounds from the PubChem database can now be accessed via qchem.mol_data().

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

New basis sets

On the basis of basis sets, PennyLane basically has it covered. ๐Ÿ™Œ

Enjoy the ability to use the 6-311g and CC-PVDZ basis sets in your qml.qchem code!

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

New transforms, operators, and more ๐Ÿ˜ฏ

Enjoy this roux of the finest functionalities in town! ๐Ÿง‘โ€๐Ÿณ๐Ÿฒ

Purity

Calculating the purity of arbitrary quantum states is now supported. Purity can now be calculated in an analogous fashion to, say, the Von Neumann entropy.

  • qml.math.purity can be used as an in-line function
  • qml.qinfo.transforms.purity can transform a QNode returning a state to a function that returns the purity
>>> theta = np.array(np.pi/3, requires_grad=True) >>> x = np.array([np.cos(theta), 0, 0, np.sin(theta)]) >>> qml.math.purity(x, [0, 1]) 1.0 >>> qml.math.purity(np.outer(x, np.conj(x)), [0]) 0.625 >>> dev = qml.device("default.mixed", wires=2) >>> @qml.qnode(dev) ... def circuit(theta): ... qml.QubitStateVector(np.array([np.cos(theta), 0, 0, np.sin(theta)]), wires=[0, 1]) ... return qml.state() ... >>> qml.qinfo.transforms.purity(circuit, wires=[0])(theta) 0.625 >>> qml.qinfo.transforms.purity(circuit, wires=[0, 1])(theta) 1.0

As with the other methods in qml.qinfo, purity is fully differentiable:

>>> qml.grad(qml.qinfo.transforms.purity(circuit, wires=[0]))(theta) (0.8660254037844384+0j)

Combine mid-circuit measurements

  • Multiple mid-circuit measurements can now be combined arithmetically to create new conditionals.
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]

New operators

Parameteric operators

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.

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

Create operators from a generator

Create operators defined from a generator via qml.ops.op_math.Evolution. qml.ops.op_math.Evolution defines the exponential of an operator \hat{O}, of the form e^{ix\hat{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

Qutrit Hadamard

The qutrit Hadamard gate, qml.THadamard, is now available. This 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]])

Improvements ๐Ÿ› 

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

  • PennyLane now supports Python 3.11 and Torch v1.13. Support for Python 3.7 has been dropped.
  • qml.pauli.is_pauli_word now supports instances of qml.Hamiltonian.
  • 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.
  • The qml.ISWAP gate is now natively supported on default.mixed, improving on its efficiency.
  • qml.equal now supports operators created via qml.s_prod, qml.pow, qml.exp, and qml.adjoint.
  • Start-up times for lightning.gpu have been improved.

Deprecations and breaking changes ๐Ÿ’”

As new things are added, outdated features are removed. To keep track of things in the deprecation pipeline, weโ€™ve created a deprecation page.

Hereโ€™s what has changed in this release:

  • Python 3.7 support is no longer maintained. PennyLane will be maintained for versions 3.8 and up.
  • qml.utils.decompose_hamiltonian() has been removed. Please use qml.pauli.pauli_decompose() instead.

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:

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, Tarik El-Khateeb, 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.

About the author

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 ๐Ÿค 

Last modified: August 06, 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