Skip to main contentIBM Quantum Documentation Preview
This is a preview build of IBM Quantum™ documentation. Refer to docs.quantum.ibm.com for the official documentation.

Common use cases

This topic describes how to migrate programs with the most commonly used types of circuits. For a full example, see End-to-end examples.


Basic circuits

The only changes when running basic circuits are how you run the job and retrieve results.

from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2 as Sampler
 
# Define the service.  This allows you to access IBM QPUs (quantum processing units).
service = QiskitRuntimeService()
 
# Get a backend
backend = service.least_busy(operational=True, simulator=False)
 
job = sampler.run([isa_circuit])
result = job.result()
# Get results for the first (and only) PUB
pub_result = result[0]
 

Specifying options

All options that were available with backend.run are available in the Qiskit Runtime primitives, but they are specified differently. For more information, see Migrate options and Advanced Qiskit Runtime options.

from qiskit_ibm_runtime import SamplerV2 as Sampler
 
sampler = Sampler(backend)
 
# You can use auto-complete to see and complete the options.
sampler.options.default_shots = 1024

Dynamic circuits

To migrate programs that run dynamic circuits, change the run call.

from qiskit_ibm_runtime import SamplerV2 as Sampler
 
sampler = Sampler(backend)
job = sampler.run([dynamic_circ])
 
pub_result = job.result()[0]
print(f">>> Hardware counts: {pub_result.data.meas.get_counts()}")

For more information about dynamic circuits, see the Classical feedforward and control flow topic, or try the Repeat until success tutorial.


Parameterized circuits

Parametrized circuits are a commonly used tool for quantum algorithm design. Because backend.run() did not accept parametrized circuits, the parameter binding step had to be integrated in the algorithm workflow. The primitives can perform the parameter binding step internally, which results in a simplification of the algorithm-side logic.

The following example summarizes the new workflow for managing parametrized circuits.

Example

Define a parametrized circuit:

from qiskit.circuit import QuantumCircuit, ParameterVector
 
n = 3
thetas = ParameterVector('θ',n)
 
qc = QuantumCircuit(n, 1)
qc.h(0)
 
for i in range(n-1):
    qc.cx(i, i+1)
 
for i,t in enumerate(thetas):
    qc.rz(t, i)
 
for i in reversed(range(n-1)):
    qc.cx(i, i+1)
 
qc.h(0)
qc.measure(0, 0)
 
qc.draw()

Assign the following parameter values to the circuit:

import numpy as np
theta_values = [np.pi/2, np.pi/2, np.pi/2]

Only circuits that adhere to the Instruction Set Architecture (ISA) of a specific backend are accepted, so we must transform the circuits.

from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
 
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)
 
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_circuit = pm.run(qc)

The primitives take in parametrized circuits directly, together with the parameter values, and the parameter assignment operation can be performed more efficiently on the server side. The input is in the form of primitive unified blocs (PUBs), where each PUB is a tuple that contains a circuit and the data broadcasted to it. For further details, see Primitive inputs and outputs.

If you have multiple sets of parameter values you want to bind to the same circuit, you can specify them in a single PUB, in the format of (circuit, [parameter_value_set1, parameter_value_set2]).

Note

You need the classical register name to get the results. By default, it is named meas when you use measure_all(). However, the classical register name for this example is c. You can find the classical register name by running <circuit_name>.cregs. For example, qc.cregs.

from qiskit_ibm_runtime import SamplerV2 as Sampler
 
sampler = Sampler(backend)
job = sampler.run([(isa_circuit, theta_values)])
result = job.result()
# Get results for the first (and only) PUB
pub_result = result[0]
# Get counts from the classical register "c".
print(f" >> Counts for the c output register: {pub_result.data.c.get_counts()}")

Get the averaged IQ data (meas_level=1)

from qiskit.circuit import QuantumCircuit
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2 as Sampler
 
circuit = QuantumCircuit(2, 2)
circuit.h(0)
circuit.cx(0, 1)
circuit.measure_all()
 
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_circuit = pm.run(circuit)
 
sampler = Sampler(backend)
# Get the averaged IQ data.
# This is equivalent to meas_level=1, meas_return="avg" in backend.run
sampler.options.execution.meas_type = "avg_kerneled"
job = sampler.run([isa_circuit], shots=10)
pub_result = job.result()[0]
print(f">>> Averaged IQ data: {pub_result.data.meas}")

Upload, view, or delete custom prototype programs

This function has been replaced with Quantum Serverless patterns. For instructions to migrate, see Converting from Qiskit Runtime Programs.