PennyLane v0.11.0 Released

Hi everyone! Today we’re very glad to announce the release of PennyLane version 0.11.0. :tada: :sparkles:

This release comes with two brand new devices, a new QAOA module, as well as an exciting overhaul of the wires system, among other things.

New and improved simulators :zap:

There are two brand new devices added to the set of default devices in PennyLane:

  • default.qubit.autograd, a pure-state qubit simulator written using Autograd, supporting fast gradient calculations using automatic differentiation.

  • lightning.qubit, a new experimental C++ state-vector simulator device. It uses the C++ Eigen library to perform fast linear algebra calculations for simulating quantum state-vector evolution.

lightning.qubit is currently in beta; it can be installed via pip:

$ pip install pennylane-lightning

For more details, please see the lightning qubit documentation.

New algorithms and templates :brain: :jigsaw:

There’s a new Quantum Approximate Optimization Algorithm (QAOA) module providing many new and exciting features for solving optimization problems on quantum devices.

As an example, you can use it to construct and solve a MaxCut problem with QAOA!

Code example
wires = range(3)
graph = Graph([(0, 1), (1, 2), (2, 0)])
cost_h, mixer_h = qaoa.maxcut(graph)

def qaoa_layer(gamma, alpha):
    qaoa.cost_layer(gamma, cost_h)
    qaoa.mixer_layer(alpha, mixer_h)

def antatz(params, **kwargs):

    for w in wires:

    # repeat the QAOA layer two times
    qml.layer(qaoa_layer, 2, params[0], params[1])

dev = qml.device('default.qubit', wires=len(wires))
cost_function = qml.VQECost(ansatz, cost_h, dev)

There is also a new ApproxTimeEvolution template added to the PennyLane templates module, which can be used to implement Trotterized time-evolution under a Hamiltonian, as well as a qml.layer template-constructing function, which takes a unitary, and repeatedly applies it on a set of wires to a given depth.

Code example
def subroutine():
    qml.CNOT(wires=[0, 1])

dev = qml.device('default.qubit', wires=3)

def circuit():
    qml.layer(subroutine, 3)
    return [qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliZ(1))]

which creates the following circuit:

>>> circuit()
>>> print(circuit.draw())
0: ──H──╭C──X──H──╭C──X──H──╭C──X─── ⟨Z⟩
1: ─────╰X────────╰X────────╰X────── ⟨Z⟩

Wires overhaul :electric_plug:

The wires system has been overhauled to become more powerful and user friendly. You can now specify custom wire labels, such as ['anc1', 'anc2', 0, 1, 3], where the labels can be strings or numbers, instead of simply using consecutive numbers, as was the case before.

Code example

Custom wire labels are defined by passing a list to the wires argument when creating the device:

>>> dev = qml.device("default.qubit", wires=['anc1', 'anc2', 0, 1, 3])

Quantum operations should then be invoked with these custom wire labels:

>>> @qml.qnode(dev)
>>> def circuit():
…         qml.Hadamard(wires='anc2')
…         qml.CNOT(wires=['anc1', 3])
…         ...

The existing behaviour, in which the number of wires is specified on device initialization, continues to work as usual. This gives a default behaviour where wires are labelled by consecutive integers.

>>> dev = qml.device("default.qubit", wires=5)

Additional features :hammer_and_wrench:

Other new features include a qml.utils.decompose_hamiltonian function that can be used to decompose a Hamiltonian into a linear combination of Pauli operators, an integrated device test suite, which can be used to run basic integration tests on core or external devices, and support for returning probabilities from photonic QNodes.

The full release notes are available at

As always, this release would not have been possible without all the help from our contributors:

@jmarrazola, @Tom_Bromley, Jack Ceroni, @Alain_Delgado_Gran, Shadab Hussain, @theodor, @josh, @nathan, @Maria_Schuld, @antalszava, @nvitucci