PennyLane-Rigetti Plugin¶
- Release
0.35.0-dev
The PennyLane Rigetti plugin allows different Rigetti devices to work with PennyLane — the wavefunction simulator, the Quantum Virtual Machine (QVM), and Quantum Processing Units (QPUs).
pyQuil is a Python library for quantum programming using the quantum instruction language (Quil) — resulting quantum programs can be executed using the Rigetti Forest SDK and Rigetti Quantum Cloud Services (QCS).
PennyLane is a cross-platform Python library for quantum machine learning, automatic differentiation, and optimization of hybrid quantum-classical computations.
Once Pennylane-Rigetti is installed, the provided Rigetti devices can be accessed straight away in PennyLane, without the need to import any additional packages.
Devices¶
Currently, PennyLane-Rigetti provides these Rigetti devices for PennyLane:
Tutorials¶
Check out these demos to see the PennyLane-Rigetti plugin in action:
You can also try it out using any of the qubit based demos from the PennyLane documentation, for example the tutorial on
qubit rotation.
Simply replace 'default.qubit'
with a 'rigetti.XXX'
device if you have an API key for
hardware access.
dev = qml.device('rigetti.XXX', wires=XXX)
Installation¶
PennyLane-Rigetti, as well as all required Python packages mentioned above, can be installed via pip
:
$ python -m pip install pennylane-rigetti
Make sure you are using the Python 3 version of pip.
Alternatively, you can install PennyLane-Rigetti from the source code by navigating to the top-level directory and running
$ python setup.py install
Dependencies¶
PennyLane-Rigetti requires the following libraries be installed:
Python >=3.9
as well as the following Python packages:
If you currently do not have Python 3 installed, we recommend Anaconda for Python 3, a distributed version of Python packaged for scientific computation.
Additionally, if you would like to compile the quantum instruction language (Quil) and run it locally using a quantum virtual machine (QVM) server, you will need to download and install the Forest software development kit (SDK):
Alternatively, you may sign up for Rigetti’s Quantum Cloud Services (QCS) which will allow you to compile your quantum code and run on real QPUs. Note that this requires a valid QCS account and the QCS CLI:
Tests¶
To test that the PennyLane-Rigetti plugin is working correctly you can run
$ make test
in the source folder.
Documentation¶
To build the HTML documentation, go to the top-level directory and run:
$ make docs
The documentation can then be found in the doc/_build/html/
directory.
Support¶
Source Code: https://github.com/PennyLaneAI/pennylane-rigetti
Issue Tracker: https://github.com/PennyLaneAI/pennylane-rigetti/issues
PennyLane Forum: https://discuss.pennylane.ai
If you are having issues, please let us know by posting the issue on our Github issue tracker, or by asking a question in the forum.
The Numpy-Wavefunction device¶
The rigetti.numpy_wavefunction
device provides an interface between PennyLane
and the pyQuil NumpyWavefunctionSimulator
.
As the NumPy wavefunction simulator allows access and manipulation of the underlying
quantum state vector, rigetti.numpy_wavefunction
is able to support the full
suite of PennyLane and Quil quantum operations and observables.
Note
Since the NumPy wavefunction simulator is written entirely in NumPy, no external Quil compiler is required.
Note
By default, rigetti.numpy_wavefunction
is initialized with analytic=True
, indicating
that the exact analytic expectation value is to be returned.
If the number of trials or shots provided to the rigetti.numpy_wavefunction
is
instead non-zero, a spectral decomposition is performed and a Bernoulli distribution
is constructed and sampled. This allows the rigetti.numpy_wavefunction
device to
‘approximate’ the effect of sampling the expectation value.
Usage¶
You can instantiate the device in PennyLane as follows:
import pennylane as qml
dev_numpy = qml.device('rigetti.numpy_wavefunction', wires=2)
This device can then be used just like other devices for the definition and evaluation of QNodes within PennyLane.
A simple quantum function that returns the expectation value and variance of a measurement and depends on three classical input parameters would look like:
@qml.qnode(dev_numpy)
def circuit(x, y, z):
qml.RZ(z, wires=[0])
qml.RY(y, wires=[0])
qml.RX(x, wires=[0])
qml.CNOT(wires=[0, 1])
return qml.expval(qml.PauliZ(0)), var(qml.PauliZ(1))
You can then execute the circuit like any other function to get the quantum mechanical expectation value and variance:
>>> circuit(0.2, 0.1, 0.3)
array([0.97517033, 0.04904283])
Supported operations¶
All Rigetti devices support all PennyLane operations and observables, with the exception of the PennyLane StatePrepBase
state preparation operations.
The Wavefunction device¶
The rigetti.wavefunction
device provides an interface between PennyLane and
the Forest SDK wavefunction simulator. Because
the wavefunction simulator allows access and manipulation of the underlying quantum state vector,
rigetti.wavefunction
is able to support the full suite of PennyLane and Quil quantum operations and observables.
In addition, it is generally faster than running equivalent simulations on the QVM, as the final state can be inspected and the expectation value calculated analytically, rather than by sampling measurements.
Note
By default, rigetti.wavefunction
is initialized with shots=0
, indicating
that the exact analytic expectation value is to be returned.
If the number of trials or shots provided to the rigetti.wavefunction
is
instead non-zero, a spectral decomposition is performed and a Bernoulli distribution
is constructed and sampled. This allows the rigetti.wavefunction
device to
‘approximate’ the effect of sampling the expectation value.
Usage¶
You can instantiate the device in PennyLane as follows:
import pennylane as qml
dev_wfun = qml.device('rigetti.wavefunction', wires=2)
This device can then be used just like other devices for the definition and evaluation of QNodes within PennyLane.
A simple quantum function that returns the expectation value and variance of a measurement and depends on three classical input parameters would look like:
@qml.qnode(dev_wfun)
def circuit(x, y, z):
qml.RZ(z, wires=[0])
qml.RY(y, wires=[0])
qml.RX(x, wires=[0])
qml.CNOT(wires=[0, 1])
return qml.expval(qml.PauliZ(0)), var(qml.PauliZ(1))
You can then execute the circuit like any other function to get the quantum mechanical expectation value and variance:
>>> circuit(0.2, 0.1, 0.3)
array([0.97517033, 0.04904283])
Supported operations¶
All devices support all PennyLane operations and observables, with the exception of the PennyLane StatePrepBase
state preparation operations.
QVM and quilc server configuration¶
Note
If using the downloadable Rigetti SDK with the default server configurations
for the QVM and the Quil compiler (i.e., you launch them with the commands
qvm -S
and quilc -R
), then no special configuration is needed.
If using a non-default port or host for either of the servers, see the
pyQuil configuration documentation
for details on how to override the default values.
The QVM device¶
The rigetti.qvm
device provides an interface between PennyLane and the Forest
SDK quantum virtual machine or the pyQuil built-in
pyQVM. The QVM is used to simulate various quantum abstract machines, ranging from simulations of
physical QPUs to completely connected lattices.
Usage¶
When initializing the rigetti.qvm
device, the following required keyword argument must also be passed:
device
(str or networkx.Graph)The name or topology of the quantum computer to initialize.
Nq-qvm
: for a fully connected/unrestricted N-qubit QVM.9q-square-qvm
: a \(9\times 9\) lattice.Nq-pyqvm
or9q-square-pyqvm
, for the same as the above but run via the built-in pyQuil pyQVM device.Any other supported Rigetti device architecture, for example a QPU lattice such as
'Aspen-8'
.Graph topology (as a
networkx.Graph
object) representing the device architecture.
Note that, unlike rigetti.wavefunction
, you do not pass the number of wires - this is inferred
automatically from the requested quantum computer topology.
>>> import pennylane as qml
>>> dev = qml.device('rigetti.qvm', device='Aspen-8')
>>> dev.num_wires
16
In addition, you may also request a QVM with noise models to better simulate a physical
QPU; this is done by passing the keyword argument noisy=True
:
>>> dev = qml.device('rigetti.qvm', device='Aspen-8', noisy=True)
Note that only the default noise models provided by pyQuil are currently supported.
To specify the pyQVM, simply append pyqvm
to the end of the device name instead of qvm
:
>>> dev = qml.device('rigetti.qvm', device='4q-pyqvm')
The device can then be used just like other devices for the definition and evaluation of QNodes within PennyLane.
A simple quantum function that returns the expectation value and variance of a measurement and depends on three classical input parameters would look like:
@qml.qnode(dev)
def circuit(x, y, z):
qml.RZ(z, wires=[0])
qml.RY(y, wires=[0])
qml.RX(x, wires=[0])
qml.CNOT(wires=[0, 1])
return qml.expval(qml.PauliZ(0)), var(qml.PauliZ(1))
You can then execute the circuit like any other function to get the quantum mechanical expectation value and variance:
>>> circuit(0.2, 0.1, 0.3)
array([0.97517033, 0.04904283])
Measurements and expectations¶
Since the QVM returns a number of trial measurements of the quantum circuit, the larger the number of
‘trials’ or ‘shots’, the closer PennyLane is able to approximate the expectation value,
and as a result the gradient. By default, shots=1024
, but this can be increased or decreased as required.
For example, see how increasing the shot count increases the expectation value and corresponding gradient accuracy:
def circuit(x):
qml.RX(x, wires=[0])
return qml.expval(qml.PauliZ(0))
dev_exact = qml.device('rigetti.wavefunction', wires=1)
dev_s1024 = qml.device('rigetti.qvm', device='1q-qvm')
dev_s100000 = qml.device('rigetti.qvm', device='1q-qvm', shots=100000)
circuit_exact = qml.QNode(circuit, dev_exact)
circuit_s1024 = qml.QNode(circuit, dev_s1024)
circuit_s100000 = qml.QNode(circuit, dev_s100000)
Printing out the results of the three device expectation values:
>>> circuit_exact(0.8)
0.6967067093471655
>>> circuit_s1024(0.8)
0.689453125
>>> circuit_s100000(0.8)
0.6977
Supported operations¶
All devices support all PennyLane operations and observables, with the exception of the PennyLane StatePrepBase
state preparation operations.
Supported observables¶
The QVM device supports qml.PauliZ
observables values ‘natively’, while also supporting qml.Identity
, qml.PauliY
, qml.Hadamard
, and qml.Hermitian
by performing implicit change of basis operations.
Native observables¶
The QVM currently supports only one measurement, returning 1
if the qubit is measured to be in the state \(|1\rangle\), and 0
if the qubit is measured to be in the state \(|0\rangle\). This is equivalent to measuring in the Pauli-Z basis, with state \(|1\rangle\) corresponding to Pauli-Z eigenvalue \(\lambda=-1\), and likewise state \(|0\rangle\) corresponding to eigenvalue \(\lambda=1\). As a result, we can simply perform a rescaling of the measurement results to get the Pauli-Z expectation value of the \(i\) th wire:
where \(N\) is the total number of shots, and \(m_j\) is the \(j\) th measurement of wire \(i\).
Change of measurement basis¶
For the remaining observables, it is easy to perform a quantum change of basis operation before measurement such that the correct expectation value is performed. For example, say we have a unitary Hermitian observable \(\hat{A}\). Since, by definition, it must have eigenvalues \(\pm 1\), there will always exist a unitary matrix \(U\) such that it satisfies the following similarity transform:
Since \(U\) is unitary, it can be applied to the specified qubit before measurement in the Pauli-Z basis. Below is a table of the various change of basis operations performed implicitly by PennyLane.
Observable |
Change of basis gate \(U\) |
---|---|
|
\(H\) |
|
\(H S^{-1}=HSZ\) |
|
\(R_y(-\pi/4)\) |
To see how this affects the resultant Quil program, you may use the program
property
to print out the Quil program after evaluation on the device.
dev = qml.device('rigetti.qvm', device='2q-qvm')
@qml.qnode(dev)
def circuit(x):
qml.RX(x, wires=[0])
return expval(qml.PauliY(0))
>>> circuit(0.54)
-0.525390625
>>> print(dev.program)
PRAGMA INITIAL_REWIRING "PARTIAL"
RX(0.54000000000000004) 0
Z 0
S 0
H 0
DECLARE ro BIT[1]
MEASURE 0 ro[0]
Note
program
will return the last evaluated quantum program performed on the device.
If viewing program
after evaluating a quantum gradient or performing an optimization,
this may not match the user-defined QNode, as PennyLane automatically modifies the QNode to take into account
the parameter shift rule, product rule, and chain rule.
Arbitrary Hermitian observables¶
Arbitrary Hermitian observables, qml.Hermitian
, are also supported by the QVM. However, since they are not necessarily unitary (and thus have eigenvalues \(\lambda_i\neq \pm 1\)), we cannot use the similarity transform approach above.
Instead, we can calculate the eigenvectors \(\mathbf{v}_i\) of \(\hat{A}\), and construct our unitary change of basis operation as follows:
After measuring the qubit state, we can determine the probability \(P_0\) of measuring state \(|0\rangle\) and the probability \(P_1\) of measuring state \(|1\rangle\), and, using the eigenvalues of \(\hat{A}\), recover the expectation value \(\langle\hat{A}\rangle\):
This process is done automatically behind the scenes in the QVM device when qml.expval(qml.Hermitian)
is returned.
QVM and quilc server configuration¶
Note
If using the downloadable Rigetti SDK with the default server configurations
for the QVM and the Quil compiler (i.e., you launch them with the commands
qvm -S
and quilc -R
), then no special configuration is needed.
If using a non-default port or host for either of the servers, see the
pyQuil configuration documentation
for details on how to override the default values.
The QPU device¶
The intention of the rigetti.qpu
device is to construct a device that will allow for execution on an actual QPU.
Constructing and using this device is very similar in design and implementation as the rigetti.qvm
device, with
slight differences at initialization, such as not supporting the keyword argument noisy
.
In addition, rigetti.qpu
also accepts the optional active_reset
keyword argument:
active_reset
(bool)Whether to actively reset qubits instead of waiting for for qubits to decay to the ground state naturally. Default is
False
. Setting this toTrue
results in a significantly faster expectation value evaluation when the number of shots is larger than ~1000.
Usage¶
A QPU device can be created via:
>>> import pennylane as qml
>>> dev_qpu = qml.device('rigetti.qpu', device='Aspen-M-2', shots=1000)
The QPU can then be used like this:
import pennylane as qml
from pennylane import numpy as np
@qml.qnode(dev_qpu)
def func(x, y):
qml.BasisState(np.array([1, 1]), wires=0)
qml.RY(x, wires=0)
qml.RX(y, wires=1)
qml.PSWAP(0.432, wires=[0, 1])
qml.CNOT(wires=[0, 1])
return expval(qml.PauliZ(1))
We can then integrate the quantum hardware and PennyLane’s automatic differentiation to determine analytic gradients:
>>> func(0.4, 0.1)
0.92578125
>>> df = qml.grad(func, argnum=0)
>>> df(0.4, 0.1)
-0.4130859375
Supported operations¶
All devices support all PennyLane operations and observables, with the exception of the PennyLane StatePrepBase
state preparation operations.
quilc server configuration¶
Note
If using the downloadable Forest SDK with the default server configurations
for the Quil compiler (i.e., quilc -R
), then no special configuration is needed.
If using a non-default port or host for the server, see the
pyQuil configuration documentation
for details on how to override the default values.
pennylane-rigetti¶
This section contains the API documentation for the PennyLane-Rigetti plugin.
Warning
Unless you are a PennyLane plugin developer, you likely do not need to use these classes and functions directly.
See the overview page for more details using the available Rigetti devices with PennyLane.
Plugin overview¶
Functions¶
|
Load a pyquil.Program instance as a PennyLane template. |
|
Load a quil string as a PennyLane template. |
|
Load a quil file as a PennyLane template. |
Classes¶
|
CHPASE(phi, q, wires) Controlled-phase gate. |
|
NumpyWavefunction simulator device for PennyLane. |
|
Rigetti QPU device for PennyLane. |
|
Rigetti QVM device for PennyLane. |
|
Wavefunction simulator device for PennyLane. |
Class Inheritance Diagram¶
