Migrate to primitives for users of third-party providers with backend.run
The backend.run
interface was the primary access point to quantum hardware and simulators offered by third-party providers that integrate with Qiskit. The evolution of user access patterns for QPUs led to the Qiskit primitives (Sampler
and Estimator
) superseding this interface. However, not all third-party providers have transitioned to the primitives framework, and backend.run
remains in Qiskit for backward compatibility.
This guide is for you if you have written or want to write code using Sampler
and Estimator
primitives but need to interact with a provider that still relies on backend.run
. If you are a
provider developer looking to implement and expose your own Sampler
and
Estimator
primitives, see the Migrate provider interfaces from backend.run to primitives guide instead.
For providers that don't expose native primitives, the Qiskit SDK offers wrappers for backend.run
that you can
use out-of the box: the BackendSamplerV2
. and
BackendEstimatorV2
classes.
If you are already familiar with the SamplerV2
and EstimatorV2
interfaces, the transition to
BackendSamplerV2
. and
BackendEstimatorV2
is seamless, as
these classes follow the same usage patterns. The inputs to the primitives should follow
the primitive unified bloc (PUB) syntax, and the output formats should follow the
PrimitiveResult
interface. See the Primitive inputs and outputs for details.
The two main differences with the implementations of SamplerV2
and EstimatorV2
are:
-
The
backend
input passed during the "backend primitive" instantiation. This input argument allows internal provider access throughbackend
and should not be confused with themode
input argument ofSamplerV2
andEstimatorV2
. -
Which
options
can be set. Options should be provided as adict
instead of anOptions
instance.
BackendSamplerV2
includesdefault_shots
,seed_simulator
andrun_options
.BackendEstimatorV2
includesdefault_precision
,abelian_grouping
,seed_simulator
, andrun_options
.- The
run_options
field defines the options to pass through to the.
method of the wrapped backend instance.
Because these wrappers are independent of qiskit_ibm_runtime
, they do not offer access to execution
modes (Session
and Batch
), local testing modes, or any other qiskit_ibm_runtime
-specific feature. These are up to the
third-party provider to implement and expose, ideally through a native primitive.
If the third-party backend requires a more fine-grained option handling
strategy that is not covered by the out-of-the-box wrapper, you can extend the
BackendSamplerV2
. and
BackendEstimatorV2
interfaces through subclassing to fit the specific
interface needs.
The following is an example usage of the BackendSamplerV2
class with a fictional third-party provider backend that only implements backend
:
from qiskit import QuantumCircuit, generate_preset_pass_manager
from qiskit.primitives import BackendSamplerV2
from qiskit_fictional_provider import BackendRunProvider
# get backend and pass onto BackendSamplerV2
backend = BackendRunProvider("").get_backend("fictional_backend")
sampler = BackendSamplerV2(backend, options={"default_shots": 1000})
# from this point on, use sampler as any SamplerV2
qc = QuantumCircuit(2)
qc.cx(0, 1)
qc.measure_all()
# assuming that third-party backend is compatible with our transpilation pipeline
# (whether this step is required or not depends on the provider)
pm = generate_preset_pass_manager(backend=backend)
tqc = pm.run(qc)
# run using pub syntax
result = sampler.run([qc]).result()