273 lines
8.0 KiB
Plaintext
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)
|