qiskit-documentation/docs/migration-guides/qiskit-runtime-use-case.mdx

273 lines
8.0 KiB
Plaintext

---
title: Common use cases
description: Common use cases when migrating from backend.run to Qiskit Runtime primitives
---
# 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.](qiskit-runtime-examples)
## Basic circuits
The only changes when running basic circuits are how you run the job and retrieve results.
<Tabs>
<TabItem value="Updated" label="Runtime primitives">
```python
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]
```
</TabItem>
<TabItem value="Legacy" label="backend.run">
``` python
from qiskit_ibm_provider import IBMProvider
# Define provider and backend
provider = IBMProvider()
backend = provider.get_backend("ibmq_qasm_simulator")
job = backend.run(isa_circuit)
result = job.result()
```
</TabItem>
</Tabs>
<span id="migrate-options"></span>
## 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](qiskit-runtime-options) and [Advanced Qiskit Runtime options.](/guides/runtime-options-overview)
<Tabs>
<TabItem value="Updated" label="Runtime primitives">
```python
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
```
</TabItem>
<TabItem value="Legacy" label="backend.run">
```python
from qiskit_ibm_provider import IBMProvider
provider = IBMProvider()
backend = provider.get_backend("backend_name")
backend.run(isa_circuit, shots=1024)
```
</TabItem>
</Tabs>
## Dynamic circuits
To migrate programs that run dynamic circuits, change the run call.
<Tabs>
<TabItem value="primitives" label="Sampler">
```python
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()}")
```
</TabItem>
<TabItem value="backend" label="backend.run">
```python
job = backend.run(dynamic_circ, dynamic=True)
job.job_id()
hardware_counts = job.result().get_counts()
hardware_counts
```
</TabItem>
</Tabs>
For more information about dynamic circuits, see the [Classical feedforward and control flow](/guides/classical-feedforward-and-control-flow) topic, or try the [Repeat until success](https://learning.quantum.ibm.com/tutorial/repeat-until-success) tutorial.
<span id="parm-circ"></span>
## 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:
``` python
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:
``` python
import numpy as np
theta_values = [np.pi/2, np.pi/2, np.pi/2]
```
<Tabs>
<TabItem value="updated" label="Runtime primitives">
Only circuits that adhere to the Instruction Set Architecture (ISA) of a specific backend are accepted, so we must transform the circuits.
```python
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.](/guides/primitive-input-output)
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]).
<Admonition type="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`.
</Admonition>
``` python
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()}")
```
</TabItem>
<TabItem value="legacy" label="backend.run">
The parameter values had to be bound to their respective
circuit parameters prior to calling `backend.run()`.
``` python
from qiskit import Aer
bound_circuit = qc.bind_parameters(theta_values)
bound_circuit.draw()
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_circuit = pm.run(bound_circuit)
backend = Aer.get_backend('aer_simulator')
job = backend.run(isa_circuit)
counts = job.result().get_counts()
print(counts)
```
</TabItem>
</Tabs>
## Get the averaged IQ data (meas_level=1)
<Tabs>
<TabItem value="updated" label="Runtime primitives">
```python
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}")
```
</TabItem>
<TabItem value="legacy" label="backend.run">
```python
from qiskit import QuantumCircuit
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
circuit = QuantumCircuit(2, 2)
circuit.h(0)
circuit.cx(0, 1)
circuit.measure_all()
# Define provider and simulator backend
from qiskit_ibm_provider import IBMProvider
provider = IBMProvider()
backend = provider.get_backend("ibmq_qasm_simulator")
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_circuit = pm.run(circuit)
result = backend.run(isa_circuit, shots=10, meas_level=1, meas_return="avg").result()
>>> print("result: ", result)
```
</TabItem>
</Tabs>
## 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.](https://qiskit.github.io/qiskit-serverless/migration/migration_from_qiskit_runtime_programs.html)