Skip to main contentIBM Quantum Documentation

End-to-end examples

Follow these examples to design a Qiskit Runtime algorithm.


Use Estimator to design an algorithm

Use the Estimator primitive to design an algorithm that calculates expectation values.

Backend.run() model: In this model, you accessed real QPUs (quantum processing units) and remote simulators by using the qiskit-ibmq-provider or the qiskit-ibm-provider module. To run local simulations, you could import a specific simulator from qiskit-aer. All of them followed the backend.run() interface. The following examples assume you have defined isa_circuits, circuits that follow the instruction set architecture (ISA) of the backend after undergoing transpilation.

from qiskit_ibm_provider import IBMProvider
 
# Select provider
provider = IBMProvider()
 
# Get backend
backend = provider.get_backend("ibmq_qasm_simulator") # cloud simulator
 
# Run
result = backend.run(isa_circuits)

Primitives model: Access real QPUs through the qiskit-ibm-runtime primitives (Sampler and Estimator). Use Local testing mode to run local simulations on Qiskit Runtime fake backends or Aer simulators. The following examples assume you have defined circuits isa_circuits and observables isa_observables.

from qiskit_ibm_runtime import EstimatorV2 as Estimator, QiskitRuntimeService
 
# Define the service.  This allows you to access IBM QPUs.
service = QiskitRuntimeService()
 
# Get a backend
backend = service.least_busy(operational=True, simulator=False)
 
# Define Estimator
estimator = Estimator(backend)
 
# Run an expectation value calculation
job = estimator.run([(isa_circuits, isa_observables)])
result = job.result()

End-to-end example

If your code previously calculated expectation values using backend.run(), you likely used the qiskit.opflow module to handle operators and state functions. To support this scenario, the following migration example shows how to replace the backend.run() plus qiskit.opflow workflow with an Estimator-based workflow.

1. Problem definition

We want to compute the expectation value of a quantum state (circuit) with respect to a certain operator. This example uses the H2 molecule and an arbitrary circuit as the quantum state:

from qiskit import QuantumCircuit
from qiskit.quantum_info import SparsePauliOp
 
# Step 1: Define operator
op = SparsePauliOp.from_list(
    [
        ("II", -1.052373245772859),
        ("IZ", 0.39793742484318045),
        ("ZI", -0.39793742484318045),
        ("ZZ", -0.01128010425623538),
        ("XX", 0.18093119978423156),
    ]
)
 
# Step 2: Define quantum state
circuit = QuantumCircuit(2)
circuit.x(0)
circuit.x(1)
 
# Define a local backend
from qiskit_ibm_runtime.fake_provider import FakeManilaV2
backend = FakeManilaV2()
 
# Or define a real backend
# from qiskit_ibm_runtime import QiskitRuntimeService
# service = QiskitRuntimeService()
# backend = service.least_busy(operational=True, simulator=False)
 
# Circuits and parameters must obey the Instruction Set Architecture (ISA) of a particular backend.
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
 
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_circuit = pm.run(circuit)
 
isa_observable = op.apply_layout(isa_circuit.layout)

2. Calculate expectation values

Estimator simplifies the user-side syntax compared to the legacy approaches, making it a more

convenient tool for algorithm design.

from qiskit_ibm_runtime import EstimatorV2 as Estimator
 
estimator = Estimator(backend, options={"default_shots": int(1e4)})
job = estimator.run([(isa_circuit, isa_observable)])
 
 
 
# Get results for the first (and only) PUB
pub_result = job.result()[0]
 
print(f">>> Expectation value: {pub_result.data.evs}")

Output

>>> Expectation value: [-0.8879899326312926]

Use Sampler to design an algorithm

The Sampler primitive is used to design an algorithm that samples circuits and extracts probability distributions.

Both Sampler and backend.run() take in circuits as inputs. The main difference is the format of the output: backend.run() outputs counts, while Sampler returns per-shot measurements (but has convenience methods to also return counts).

Backend.run() model: In this model, you used the qiskit-ibmq-provider or the qiskit-ibm-provider module to access real QPUs and remote simulators. To run local simulations, you could import a specific simulator from qiskit-aer. All of them followed the backend.run() interface.

from qiskit_ibm_provider import IBMProvider
 
 
# Select provider
provider = IBMProvider()
 
 
# Get backend
backend = provider.get_backend("ibmq_qasm_simulator") # Use the cloud simulator
 
# Run
result = backend.run(isa_circuits)

Primitives model: Access real QPUs through the qiskit-ibm-runtime Sampler and Estimator primitives. Use local testing mode to run local simulations by using Qiskit Runtime fake backends or Aer simulators.

from qiskit_ibm_runtime import SamplerV2 as Sampler, QiskitRuntimeService
 
# Define the service.  This allows you to access IBM QPUs.
service = QiskitRuntimeService()
 
# Get a backend
backend = service.least_busy(operational=True, simulator=False)
 
# Define Sampler
sampler = Sampler(mode=backend)
 
# Run calculation
job = sampler.run([isa_circuit])
 
result = job.result()

End-to-end example

The following example shows an end-to-end example of sampling a circuit by using backend.run() and Sampler.

1. Problem definition

We want to find the probability distribution associated with a quantum state:

Important

When using the Sampler primitive, the circuit must contain measurements.

from qiskit_ibm_runtime import SamplerV2 as Sampler
 
# Define a local backend
from qiskit_ibm_runtime.fake_provider import FakeManilaV2
backend = FakeManilaV2()
 
# Define a real backend
# from qiskit_ibm_runtime import QiskitRuntimeService
# service = QiskitRuntimeService()
# backend = service.least_busy(operational=True, simulator=False)
 
from qiskit import QuantumCircuit
 
circuit = QuantumCircuit(4)
circuit.h(range(2))
circuit.cx(0,1)
circuit.measure_all() # measurement!
 
# Circuits must obey the ISA of the backend.
# Convert to ISA circuits
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
 
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_circuit = pm.run(circuit)
 

2. Get counts from the result

sampler = Sampler(mode=backend)
 
job = sampler.run([isa_circuit])
 
result = job.result()
# Get results for the first (and only) PUB
pub_result = result[0]
 
# Get counts from the classical register "meas".
print(f" >> Meas output register counts: {pub_result.data.meas.get_counts()}")
 
>> Meas output register counts: {'0001': 210, '0010': 305, '0000': 282, '0011': 201, '0101': 2, '1010': 6, '0110': 5, '0100': 6, '1000': 3, '0111': 1, '1001': 2, '1011': 1}

Next steps

The Runtime primitives offer a series of features and tuning options, some of which do not have a legacy alternative to migrate from, but can help improve your performance and results. For more information, refer to the following:

Was this page helpful?
Report a bug or request content on GitHub.