QPUs vs. QVMs
The process of developing quantum software often begins with testing against a QVM. Eventually, you'll come to a point where you're ready to run your programs against a real QPU.
This guide will focus specifically on the differences between QPUs and QVMs when targeting them via the Forest SDK.
Your pyQuil code will more than likely include a call to
get_qc()
. For instance, if you're targeting a 2-qubit QVM, the call might look something like:qc = get_qc("2q-qvm")
From a pyQuil perspective, changing from a QVM to a QPU (and vice versa) is usually as simple as changing the string within the
get_qc()
function call. For example, to target the Aspen-9
QPU, you can change the line above to:qc = get_qc("Aspen-9")
In both cases above, the
qc
object will be an instance of a pyQuil QuantumComputer
. A QuantumComputer
is comprised of:- A quantum abstract machine, accessed via
qc.qam
(classQAM
) - An abstract compiler, accessed via
qc.compiler
(classAbstractCompiler
)
If your code accesses either
qc.qam
or qc.compiler
, it's important to understand that the QAM
and AbstractCompiler
implementations differ between QPU and QVM use cases.For instance, if your code targets a QVM,
qc.qam
will be a QVM
instance, and qc.compiler
will be a QVMCompiler
instance. However, if your code targets a QPU, qc.qam
will be a QPU
instance, and qc.compiler
will be a QPUCompiler
instance.While these subcomponents follow common interfaces, namely
QAM
and AbstractCompiler
, there may be some methods or properties that are accessible on the QPU-based instances but not on the QVM-based instances, and vice versa.You can make your code robust by performing type checks on
qc.qam
and/or qc.compiler
. For example:pyQuil v3
from pyquil import get_qc
from pyquil.api import QPUCompiler
qc = get_qc("Aspen-9") # or "2q-qvm"
if isinstance(qc.compiler, QPUCompiler):
# Working with a QPU - refresh calibrations
qc.compiler.get_calibration_program(force_refresh=True)
Without the type check on line 6, your code might run well when targeting a QPU but raise an error when changing to a QVM (because
get_calibration_program()
is not available on QVMCompiler
). With the type check in place, your code will run seamlessly between both cases.While QVMs typically run in your current environment and therefore don't have special access requirements, QPUs are remote resources hosted by QCS. As such, a QPU will only be accessible to you during a reservation window. You must also have network access to the QPU, which is most easily obtained by using your provisioned JupyterLab IDE.
When moving from a QVM to a QPU, it's important to consider qubit topology. Qubit topology describes which qubits can be used together in quantum operations. For a QVM, this is a fully-connected graph — meaning any qubit can be used with any other qubit. This is not necessarily the case for a QPU, in which only certain qubits can be used together.

On a QPU, qubits and qubit pairs also have differing fidelities for certain operations. You can view this information by clicking
Device Calibration
under a QPU when making a reservation, as shown above.Assume your quantum program includes an operation on qubits 0 and 1. On a QVM, your program may run well, but what about on a particular QPU? What if these qubits are not connected in the desired QPU's topology? Or perhaps they are connected but have poor fidelity for the operation in question. To run your program on the desired QPU, you can take advantage of compiler rewiring.
Rewiring is a step that the Quil compiler will perform to select optimal qubits for you. The qubits selected will be based on a QPU's topology and calibration information. Rewiring will happen by default, if needed, but rewiring behavior can also be explicitly overridden using a compiler directive.
To learn more about rewiring, including how to override default behavior, see the pyQuil documentation on rewiring.
If you'd like to simulate the topology and fidelities of a real QPU, you can create a QVM based on a QPU using the
as_qvm
parameter of get_qc()
:qc = get_qc("Aspen-9", as_qvm=True)
Note: This does not simulate the noise model of the QPU — only the qubit topology and operator fidelities.
Active reset — enacted by using the Quil
RESET
instruction at the beginning of a program — forces all qubits to their ground states. This is useful when running sequential programs against a QPU, as it reduces the time needed for qubits to return to their ground states between programs.Active reset has no effect when running programs against a QVM, as a QVM will start with its qubits in their ground states regardless of active reset.
It may seem theoretically trivial to use active reset when targeting a QPU. However, its use can have side effects in practice, as active reset has its own associated fidelity (as seen in the figure under QPU Topology & Fidelities) — it's important to be aware of this when moving from a QVM to a QPU.
Last modified 1yr ago