Using PennyLane and Strawberry Fields to run programs on Xanadu hardware

Jack Ceroni (Xanadu Resident)

One of the advantages of PennyLane is that it can be run on many different simulators and real quantum devices from a variety of external providers through our Plugins, as well as Xanadu’s own devices! In this how-to, we will show you how to create a simple program in PennyLane (using the PennyLane-SF plugin), and execute it on Xanadu’s hardware!

First things first: in order to query the Xanadu remote hardware, you must have a personal access token. You can request one of these tokens by filling out this form on the main Xanadu website. For the rest of the tutorial, we will refer to the access token simply as MY_TOKEN.

We begin by importing the necessary libraries and configuring our Xanadu cloud platform account. We can do this with the store_account() method, which saves our personal login credentials to a configuration file:

import strawberryfields as sf
import pennylane as qml

sf.store_account("MY_TOKEN")

Next, we can test to make sure we are connected to the Xanadu cloud using the ping() method:

>>> sf.ping()
You have successfully authenticated to the platform!

This indicates that everything is working properly! Now, we are able to specify a device on which we can run our quantum program.

Simulating Circuits on Xanadu’s Cloud Simulator

Xanadu’s quantum cloud isn’t only made up of real quantum devices: it also consists of high-performance classical simulators (which we refer to as “simulons”). As a warm-up, we will simulate a quantum circuit using Xanadu’s cloud simulator!

We will be using the simulon_gaussian device, which is a simulator that runs on the gaussian Strawberry Fields backend. We first define our device instance, using our access token:

dev = qml.device(
    'strawberryfields.remote', backend="simulon_gaussian", sf_token="MY_TOKEN", wires=3
)

Since the simulon_gaussian device runs on the gaussian backend, it follows that any circuit we run on this simulator must consist entirely of Gaussian operations. Recall that any unitary operation can be written in the form:

$$U = \exp (-i t H).$$

Gaussian unitaries are those such that \(H\) is at most quadratic in the operators \(\hat{x}\) and \(\hat{p}\) (for more information on the theory, see this page). Common examples of photonic Gaussian operations are displacements, quadratic phase gates, and beamsplitters, which are precisely the operations we use in our circuit:

@qml.qnode(dev)
def circuit(theta, phi):
    qml.Displacement(1, 0, wires=0)
    qml.Displacement(1, 0, wires=1)
    qml.QuadraticPhase(1, wires=2)
    qml.Beamsplitter(theta, phi, wires=[0, 1])
    qml.Beamsplitter(theta, phi, wires=[1, 2])
    return qml.expval(qml.X(wires=0))

Notice that the circuit ends with a measurement of the expectation value of the position quadrature observable. These kinds of measurements are supported on the Gaussian simulator! Finally, we execute the circuit on the device:

>>> circuit(0.5, 0.5)
0.91369414

That was simple enough! As you probably noticed, simulating a circuit in the cloud is very similar to how we would go about simulating a quantum program locally 💻.

Executing a Program on a Xanadu X8 Device

Now that we have simulated a circuit using the Xanadu cloud, we are ready to perform a real quantum experiment ‍🔬. We will use one of Xanadu’s X8 devices to execute a simple quantum circuit, taking \(10\) samples from the device. The X8 devices perform a process known as Gaussian boson sampling (GBS), which involves executing a very specific set of Gaussian operations on a series of photonic modes, and sampling from the resulting probability distribution by taking measurements in the Fock basis.

As we did with the simulator, we first must specify our device instance, noting that our backend is one of the X8 devices, and that we require \(10\) circuit executions. In addition, we must give our personal access token:

dev = qml.device('strawberryfields.remote', backend="X8", shots=10, sf_token="MY_TOKEN")

It is important to remember that the X8 devices have the following fixed circuit structure:

As is indicated above, only certain types of operations can be implemented on the X8 device, in a certain order. More specifically:

  • The X8 chip begins with a series of squeezers and beamsplitters, which can create two-mode squeezed states. The only allowed squeezer parameters are \(r = 1.0\) and \(r = 0.0\).
  • Next, each collection of 4 modes can be acted upon by an arbitrary \(SU(4)\) unitary operation, which is implemented using interferometers.
  • Finally, the modes are measured using photon-number-resolving (PNR) detectors, which count the number of detected photons after an execution of the device.

It is crucial that we only attempt to execute a QNode that contains operations supported by the X8 device.

We therefore define a simple circuit which first performs two-mode squeezing between two pairs of modes (0 and 4, and 1 and 5), with \(r = 1.0\) for each squeezer. Next, we add two beamsplitters with parameters \(\theta\) and \(\phi\), which are in fact \(SU(4)\) transformations. Finally, we measure the expectation value of a tensor product of number operators, \(\langle \hat{n}_0 \otimes \hat{n}_5 \rangle\), which can be calculated using PNR detectors:

@qml.qnode(dev)
def circuit(theta, phi):
    qml.TwoModeSqueezing(1.0, 0.0, wires=[0, 4])
    qml.TwoModeSqueezing(1.0, 0.0, wires=[1, 5])
    qml.Beamsplitter(theta, phi, wires=[0, 1])
    qml.Beamsplitter(theta, phi, wires=[4, 5])
    return qml.expval(qml.TensorN(wires=[0, 5]))

We can then run the circuit for the pair of beamsplitter parameters \(\theta = 0.5\) and \(\phi = 0.5\):

>>> circuit(0.5, 0.5)
2.0349449940160445

Success 🎉! We have just executed a quantum program on Xanadu’s X8 device! For more information on running GBS-based algorithms on Xanadu’s hardware, check out this tutorial over on the Strawberry Fields website.