PennyLane v0.16 is now live! This release is chock full of new goodies with over 50 PRs from 26 contributors and two new modules.
Extract the Fourier representation of quantum circuits
The new fourier
module provides a host of methods for extracting the Fourier representation of functions implemented by quantum circuits. With these newly provided tools, you can examine (and visualize!) the expressivity of your quantum circuit 📈
For more information, check out the Fourier module documentation.
First-class support for quantum kernels
The new kernels
module provides easy access to quantum kernels for all your machine learning needs.
Similar to classical kernel methods, which compute distance metrics between embedded data in feature space, quantum kernels take advantage of the high-dimensional Hilbert space of quantum computers, utilizing measurements to compute distances between encoded quantum datasets.
Use functions from the kernels
module to evaluate quantum kernel functions on provided datasets:
n_wires=6 n_points = 5 dev = qml.device('default.qubit', wires=n_wires) @qml.qnode(dev) def kernel_circuit(x1, x2): qml.templates.AngleEmbedding(x1, wires=range(n_wires)) qml.adjoint(qml.templates.AngleEmbedding)(x2, wires=range(n_wires)) return qml.probs(range(n_wires)) kernel = lambda x1, x2: kernel_circuit(x1, x2)[0] rng = np.random.default_rng(seed=1234) X = rng.random((n_points, n_wires)) K = qml.kernels.square_kernel_matrix(X, kernel)
In addition, the kernels
module provides functionality for mitigating error associated with the evaluated kernel matrix.
For more information on quantum kernels, you can visit the module documentation or read Xanadu Researcher Maria Schuld’s paper on the topic.
New transforms
Do more with your QNodes! Quantum transforms allow you to manipulate your QNodes, turn them into something new, or just look at them in a different light. Transforms preserve differentiability, allowing even the transform to be optimized and trained.
- Specifications: Need to know the size of your circuit before you run it? How many executions will the gradient take? Is the circuit too deep for a QPU? Look no further than the
specs
transform.
dev = qml.device('default.qubit', wires=4) @qml.qnode(dev, diff_method='parameter-shift') def circuit(x, y): qml.RX(x[0], wires=0) qml.Toffoli(wires=(0, 1, 2)) qml.CRY(x[1], wires=(0, 1)) qml.Rot(x[2], x[3], y, wires=0) return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliX(1)) x = np.array([0.05, 0.1, 0.2, 0.3], requires_grad=True) y = np.array(0.4, requires_grad=False) specs_func = qml.specs(circuit) info = specs_func(x, y) >>> info {'gate_sizes': defaultdict(int, {1: 2, 3: 1, 2: 1}), 'gate_types': defaultdict(int, {'RX': 1, 'Toffoli': 1, 'CRY': 1, 'Rot': 1}), 'num_operations': 4, 'num_observables': 2, 'num_diagonalizing_gates': 1, 'num_used_wires': 3, 'depth': 4, 'num_trainable_params': 4, 'num_parameter_shift_executions': 11, 'num_device_wires': 4, 'device_name': 'default.qubit', 'diff_method': 'parameter-shift'}
- Custom transform decorator: Write your own transforms! The new decorators make it easy to manipulate quantum circuits in any way you see fit.
For example, you can scale every X rotation:
@qml.qfunc_transform def my_transform(tape, a): for op in tape.operations + tape.measurements: if op.name == "RX": x = op.parameters[0] qml.RX(a * x, wires=op.wires) else: op.queue()
And then apply it in a circuit:
dev = qml.device("default.qubit", wires=2) params = np.array([1.0, 1.0]) def ansatz(x): qml.Hadamard(wires=0) qml.RX(x[0], wires=0) qml.RY(x[1], wires=1) qml.CNOT(wires=[0, 1]) @qml.qnode(dev) def ansatz_plain(params): ansatz(params) return qml.expval(qml.PauliZ(1)) @qml.qnode(dev) def ansatz_transformed(params, scale): my_transform(scale)(ansatz)(params) return qml.expval(qml.PauliZ(1))
If we draw both circuits, we can see that the parameters of the transformed version have been modified:
>>> print(qml.draw(ansatz_plain)(params)) 0: ──RX(1)──╭C──┤ ⟨Z⟩ 1: ──RY(1)──╰X──┤ >>> print(qml.draw(ansatz_transformed)(params, 2.0)) 0: ──RX(2)──╭C──┤ ⟨Z⟩ 1: ──RY(1)──╰X──┤
Transforms are fully differentiable, allowing you to take gradients with respect to transform parameters:
>>> qml.grad(ansatz_transformed)(params, 2.0) (array([-1.81859485e+00, -2.77555756e-17]), array(-0.90929743))
- Quantum Monte Carlo: The Monte Carlo estimation algorithm 🎲 calculates the expectation value over some input distribution. The quantum version can potentially calculate that value faster than classical sampling. PennyLane already has a
qml.templates.QuantumMonteCarlo
template, and the new transform allows for easier benchmarking and specifications tabulation.
New operations
PennyLane’s library of operations and templates continues to grow, with several new operations available with this release:
Check out the operations guide and templates gallery for a full list of available operations and templates.
Improvements
In addition to the new features listed above, the release contains a wide array of improvements and optimizations:
- Compute quantum gradients with respect to a subset of stochastically chosen parameters.
- The adjoint differentiation method is up to 15% faster because of eliminated redundant evaluations.
- Tag your operators with an
id
attribute, useful for all sorts of transformations and manipulations. - PennyLane now provides support for Python 3.9.
Breaking changes and deprecations
As new things are added, old things can be pruned away. Here’s what will be disappearing in the future:
- With this release, support for Python 3.6 has been removed.
- The transform
qml.inv()
is deprecated in favor of the more flexibleqml.adjoint()
. - The tape methods
tape.get_resources()
andtape.get_depth()
are deprecated in favor of the new attributetape.specs
.
These highlights are just scratching the surface — check out the full release notes for more details.
unitaryHACK
In this release cycle, we participated in unitaryHACK, a quantum open source hackathon sponsored by the Unitary Fund. We merged 12 PRs from a number of community contributors (with some still in the pipeline for the next release!):
- Marius Aglitoiu
- Miruna Daian
- Brian Shi
- Nahum Sá
- Tanya Garg
- Vishnu Ajith
- Ryan Hill
- Alberto Maldonado
- Vincent Wong
- Ashish Panigrahi
Congrats to the Unitary Fund for a successful event, and thanks to our many new contributors! 🙏
Contributors
As always, this release would not have been possible without the hard work of our development team and contributors:
Marius Aglitoiu, Vishnu Ajith, Juan Miguel Arrazola, Thomas Bromley, Jack Ceroni, Alaric Cheng, Miruna Daian, Olivia Di Matteo, Tanya Garg, Christian Gogolin, Alain Delgado Gran, Diego Guala, Anthony Hayes, Ryan Hill, Theodor Isacsson, Josh Izaac, Soran Jahangiri, Pavan Jayasinha, Nathan Killoran, Christina Lee, Ryan Levy, Alberto Maldonado, Johannes Jakob Meyer, Romain Moyard, Ashish Panigrahi, Nahum Sá, Maria Schuld, Brian Shi, Antal Száva, David Wierichs, Vincent Wong.
About the author
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.