PennyLane v0.12.0 Released

Hi everyone! We are pleased to announce the release of PennyLane version 0.12. :confetti_ball: :stars:

This release comes with a new mixed-state simulator and quantum noisy channels, a new module for minimizing the number of measurement settings for hardware, the ability to access the state vector from circuits, and a preview to the next-generation QNode.

New and improved simulators :notes: :slot_machine:

A new mixed-state simulator called default.mixed has been added to the set of default devices in PennyLane. This device is ideal for simulating and optimizing circuits that include noise and quantum channels.

Code example

The device can be initialized as

dev = qml.device("default.mixed", wires=1)

def circuit(params):
    qml.RX(params[0], wires=0)
    qml.RY(params[1], wires=0)
    qml.AmplitudeDamping(0.5, wires=0)
    return qml.expval(qml.PauliZ(0))

print(circuit([0.54, 0.12]))


print(circuit([0, np.pi]))


New tools for optimizing measurements :package: :bar_chart:

The new grouping module provides functionality for grouping simultaneously measurable Pauli word observables.

Code example

As an example, you can use the new optimize_measurements function to reduce the number of measurements needed on quantum hardware during optimization:

from pennylane.grouping import optimize_measurements

h, nr_qubits = qml.qchem.molecular_hamiltonian("h2", "")
rotations, grouped_ops, grouped_coeffs = optimize_measurements(h.ops, h.coeffs, grouping="qwc")

This depends on a lower level function called group_observables which partitions a list of observables (Pauli operations and tensor products thereof) into groupings according to a binary relation:

from pennylane.grouping import group_observables

observables = [qml.PauliY(0), qml.PauliX(0) @ qml.PauliX(1), qml.PauliZ(1)]
obs_groupings = group_observables(observables)

[[Tensor(PauliX(wires=[0]), PauliX(wires=[1]))], [PauliY(wires=[0]), PauliZ(wires=[1])]]

Returning the quantum state from simulators :microscope:

The quantum state of a QNode can now be returned using the qml.state() return function. Differentiating the state is currently available when using the classical backpropagation differentiation method (diff_method="backprop") with a compatible device, and when using the new tape mode (qml.enable_tape).

Code example
import pennylane as qml

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

def qfunc(x, y):
    qml.RZ(x, wires=0)
    qml.RY(y, wires=0)
    qml.CNOT(wires=[0, 1])
    return qml.state()

qfunc(0.56, 0.1)

tensor([0.95985437-0.27601028j, 0.        +0.j        ,
        0.        +0.j        , 0.04803275-0.01381203j], requires_grad=True)

Additional features :gear: :gift:

Other new features include the addition of quantum channels (Amplitude-damping, Phase-damping, Depolarizing, and custom qubit channels) that can be used with default.mixed, the tape module which includes a new re-formulated QNode class (experimental). A couple of major advantages of tape mode include that it provides a way of working with less restrictive QNode signatures and it supports in-QNode classical processing.

The full release notes are available at

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

@AroosaIjaz, @jmarrazola, @Tom_Bromley, Jack Ceroni, @Alain_Delgado_Gran, @josh, @sjahangiri, @nathan, Robert Lang, Cedric Lin, @glassnotes, @Nicolas_Quesada, @Maria_Schuld, Antal Szรกva