PennyLane v0.8.0 Released

Hi everyone, we’re pleased to announce PennyLane version 0.8.0 :confetti_ball: :fireworks: :partying_face:

This is a major release, that contains some great new features and improvements. These include:

A new quantum chemistry package, pennylane.qchem

Features include:

  • Generate the qubit Hamiltonians directly starting with the atomic structure of the molecule.

  • Calculate the mean-field (Hartree-Fock) electronic structure of molecules.

  • Perform the fermionic-to-qubit transformation of the electronic Hamiltonian by using different functions implemented in OpenFermion.

  • Perform a Variational Quantum Eigensolver (VQE) computation with this Hamiltonian in PennyLane.

    >>> H = qml.vqe.Hamiltonian(coeffs, obs)
    >>> cost = qml.VQECost(ansatz, hamiltonian, dev, interface="torch")
    >>> params = torch.rand([4, 3])
    >>> cost(params)
    tensor(0.0245, dtype=torch.float64)
    

Check out the quantum chemistry quickstart, as well the quantum chemistry and VQE tutorials.

A new variational circuit drawer

Consider the following circuit as an example:

@qml.qnode(dev)
def qfunc(a, w):
    qml.Hadamard(0)
    qml.CRX(a, wires=[0, 1])
    qml.Rot(w[0], w[1], w[2], wires=[1])
    qml.CRX(-a, wires=[0, 1])

    return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1))

We can draw the circuit after it has been executed:

>>> result = qfunc(2.3, [1.2, 3.2, 0.7])
>>> print(qfunc.draw())
 0: ──H──╭C───────────────────╭C──────╭─ ⟨Z βŠ— Z⟩
 1: ─────╰RX(2.3)──Rot(1.2, 3.2, 0.7)──╰RX(-2.3)──╰─ ⟨Z βŠ— Z⟩
>>> print(qfunc.draw(show_variable_names=True))
 0: ──H──╭C────────────────────╭C───────╭─ ⟨Z βŠ— Z⟩
 1: ─────╰RX(a)──Rot(w[0], w[1], w[2])──╰RX(-1*a)──╰─ ⟨Z βŠ— Z⟩

Output and train on circuit probabilities

The new qml.probs() measurement allows you to output and train
on circuit probabilities, on both simulators and hardware.

@qml.qnode(dev)
def circuit(x):
    qml.Hadamard(wires=0)
    qml.RY(x, wires=0)
    qml.RX(x, wires=1)
    qml.CNOT(wires=[0, 1])
    return qml.probs(wires=[0])

Executing this circuit gives the marginal probability of wire 1:

>>> circuit(0.2)
[0.40066533 0.59933467]

QNodes that return probabilities fully support autodifferentiation.

Create QNode collections and execute on multiple QPUs in parallel

The new QNodeCollection container class allows independent QNodes to be stored and evaluated simultaneously. Experimental support for asynchronous evaluation of contained QNodes is provided with the parallel=True keyword argument.

QNode collections can be easily created using qml.map() to map quantum circuit templates over a list of observables or devices.

For example:

>>> def my_template(params, wires, **kwargs):
>>>    qml.RX(params[0], wires=wires[0])
>>>    qml.RX(params[1], wires=wires[1])
>>>    qml.CNOT(wires=wires)

>>> obs_list = [qml.PauliX(0) @ qml.PauliZ(1), qml.PauliZ(0) @ qml.PauliX(1)]
>>> dev = qml.device("default.qubit", wires=2)
>>> qnodes = qml.map(my_template, obs_list, dev, measure="expval")
>>> qnodes([0.54, 0.12])
array([-0.06154835  0.99280864])

Other new high level functions such as qml.sum and qml.dot take the sum of a QNode collection, and a dot product of tensors/arrays/QNode collections, respectively.

qml.apply allows vectorized functions to act over the entire QNode
collection:

>>> qnodes = qml.map(my_template, obs_list, dev, measure="expval")
>>> cost = qml.apply(np.sin, qnodes)
>>> cost([0.54, 0.12])
array([-0.0615095  0.83756375])

Easily invert templates

The new qml.inv function inverts templates and sequences of Operations. Note that this requires the new @qml.template decorator to be used to register templates with PennyLane.

For example, using this function to invert a template inside a QNode:

@qml.template
def ansatz(weights, wires):
    for idx, wire in enumerate(wires):
        qml.RX(weights[idx], wires=[wire])

    for idx in range(len(wires) - 1):
        qml.CNOT(wires=[wires[idx], wires[idx + 1]])

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

@qml.qnode(dev)
def circuit(weights):
    qml.inv(ansatz(weights, wires=[0, 1]))
    return qml.expval(qml.PauliZ(0) @ qml.PauliZ(1))

Import quantum program from pyQuil, and make them differentiable

The loading functions qml.from_pyquil, qml.from_quil and qml.from_quil_file convert pyQuil objects and Quil code to PennyLane templates. Note that this feature requires version 0.8 or above of the PennyLane-Forest plugin.


See the full release notes for more details on the latest PennyLane release.

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

@jmarrazola, Ville Bergholm, @Alain_Delgado_Gran, Olivia Di Matteo, Theodor Isacsson, Soran Jahangiri, @nathan, @johannesjmeyer, Zeyue Niu, @Maria_Schuld, @antalszava.