491 lines
18 KiB
Plaintext
491 lines
18 KiB
Plaintext
---
|
|
title: Primitives with REST API
|
|
description: How to use the Sampler and Estimator primitives with Qiskit Runtime REST API.
|
|
---
|
|
|
|
{/* cspell:ignore IIZII, XIZZZ, accum */}
|
|
|
|
# Primitives with REST API
|
|
|
|
The steps in this topic describe how to run and configure primitive workloads with REST API, and demonstrate how to invoke them in any program of your choice.
|
|
|
|
<Admonition type="note">
|
|
This documentation utilizes the Python `requests` module to demonstrate the Qiskit Runtime REST API. However, this workflow can be executed using any language or framework that supports working with REST APIs. Refer to the [API reference documentation](/api/runtime/tags/jobs) for details.
|
|
</Admonition>
|
|
|
|
<span id="start-estimator"></span>
|
|
## Estimator primitive with REST API
|
|
|
|
### 1. Initialize the account
|
|
|
|
Because Qiskit Runtime Estimator is a managed service, you first need to initialize your account. You can then select the device you want to use to calculate the expectation value.
|
|
|
|
Find details on how to initialize your account, view available backends, and invalidate tokens in this [topic](./setup-channel#set-up-to-use-ibm-quantum-platform-with-rest-api).
|
|
|
|
### 2. Create a QASM circuit
|
|
|
|
You need at least one circuit as the input to the Estimator primitive.
|
|
|
|
Define a QASM quantum circuit. For example:
|
|
|
|
```python
|
|
qasm_string='''
|
|
OPENQASM 3;
|
|
include "stdgates.inc";
|
|
qreg q[2];
|
|
creg c[2];
|
|
x q[0];
|
|
cx q[0], q[1];
|
|
c[0] = measure q[0];
|
|
c[1] = measure q[1];
|
|
'''
|
|
```
|
|
|
|
The following code snippets assume that the `qasm_string` has been transpiled to a new string `resulting_qasm`. Find detailed instructions on how to use the Qiskit transpiler service API in this [topic](./transpile-rest-api).
|
|
|
|
### 3. Run the quantum circuit using the Estimator V2 API
|
|
|
|
|
|
<Admonition type="note">
|
|
The following jobs use [Qiskit Runtime V2 primitives](/migration-guides/v2-primitives). Both `SamplerV2` and `EstimatorV2` take one or more primitive unified blocs (PUBs) as the input. Each PUB is a tuple that contains one circuit and the data broadcasted to that circuit, which can be multiple observables and parameters. Each PUB returns a result.
|
|
</Admonition>
|
|
|
|
|
|
```python
|
|
import requests
|
|
|
|
url = 'https://api.quantum-computing.ibm.com/runtime/jobs'
|
|
headers = {
|
|
'Content-Type': 'application/json',
|
|
'x-access-token':auth_id,
|
|
'x-qx-client-application': 'qiskit-version-2/0.39.2/'+'your_application' # specifying the application you might be running from. For an actual Integration project, this option is invaluable to know where jobs are coming from. At this time the "qiskit-version-2/0.39.2/" string is a necessary prefix.
|
|
}
|
|
job_input = {
|
|
'program_id': 'estimator',
|
|
"backend": backend,
|
|
"hub": "hub1",
|
|
"group": "group1",
|
|
"project": "project1",
|
|
"start_session": "False", # set to False if you just need to run a single job.
|
|
"params": {
|
|
"pubs": [ #primitive unified blocs (PUBs) containing one circuit each. c.f. https://docs.quantum.ibm.com/migration-guides/v2-primitives
|
|
[resulting_qasm, # QASM circuit
|
|
{"IIZII": 1, "XIZZZ": 2.3}, # Observable
|
|
None # parameter values
|
|
]],
|
|
"version": 2 # this defines the version of the Qiskit Runtime Primitive to use, c.f. https://docs.quantum.ibm.com/migration-guides/v2-primitives
|
|
}}
|
|
|
|
response = requests.post(url, headers=headers, json=job_input)
|
|
|
|
if response.status_code == 200:
|
|
job_id = response.json().get('id')
|
|
print("Job created:",response.text)
|
|
else:
|
|
print(f"Error: {response.status_code}")
|
|
```
|
|
|
|
|
|
### 4. Check job status and get results
|
|
|
|
Next, pass the `job_id` to the API:
|
|
|
|
```python
|
|
response_status_singlejob= requests.get(url+'/'+job_id, headers=headers)
|
|
response_status_singlejob.json().get('state')
|
|
```
|
|
Output
|
|
|
|
```text
|
|
>>> Job ID: 58223448-5100-4dec-a47a-942fb30edcad
|
|
>>> Job Status: JobStatus.RUNNING
|
|
```
|
|
|
|
Get job results:
|
|
```python
|
|
response_result= requests.get(url+'/'+job_id+'/results', headers=headers)
|
|
|
|
res_dict=response_result.json()
|
|
|
|
estimator_result=res_dict['results']
|
|
print(estimator_result)
|
|
```
|
|
Output
|
|
```text
|
|
[{'data': {'evs': 0.7428980350102542, 'stds': 0.029884014518789213, 'ensemble_standard_error': 0.03261147170624149}, 'metadata': {'shots': 10016, 'target_precision': 0.01, 'circuit_metadata': {}, 'resilience': {}, 'num_randomizations': 32}}]
|
|
```
|
|
|
|
### 5. Work with Runtime options
|
|
|
|
Error mitigation techniques allow users to mitigate circuit errors by modeling the device noise at the time of execution. This typically results in quantum pre-processing overhead related to model training, and classical post-processing overhead to mitigate errors in the raw results by using the generated model.
|
|
|
|
The error mitigation techniques built in to primitives are advanced resilience options. To specify these options, use the `resilience_level` option when submitting your job.
|
|
|
|
The following examples demonstrate the default options for dynamical decoupling, twirling, and TREX + ZNE. Find more options and further details in the [Error mitigation and suppression techniques](./error-mitigation-and-suppression-techniques) topic.
|
|
|
|
<Tabs>
|
|
|
|
<TabItem value="TREX + ZNE" label="TREX + ZNE">
|
|
|
|
```python
|
|
import requests
|
|
|
|
url = 'https://api.quantum-computing.ibm.com/runtime/jobs'
|
|
headers = {
|
|
'Content-Type': 'application/json',
|
|
'x-access-token':auth_id,
|
|
'x-qx-client-application': 'qiskit-version-2/0.39.2/'+'your_application' # specifying the application you might be running from. For an actual Integration project, this option is invaluable to know where jobs are coming from. At this time the "qiskit-version-2/0.39.2/" string is a necessary prefix.
|
|
}
|
|
job_input = {
|
|
'program_id': 'estimator',
|
|
"backend": backend,
|
|
"hub": "hub1",
|
|
"group": "group1",
|
|
"project": "project1",
|
|
"start_session": "False", # set to False if you just need to run a single job.
|
|
"params": {
|
|
"pubs": [ #primitive unified blocs (PUBs) containing one circuit each. c.f. https://docs.quantum.ibm.com/migration-guides/v2-primitives
|
|
[resulting_qasm, # QASM circuit
|
|
{"IIZII": 1, "XIZZZ": 2.3}, # Observable
|
|
None # parameter values
|
|
]],
|
|
"version": 2, # this defines the version of the Qiskit Runtime Primitive to use, c.f. https://docs.quantum.ibm.com/migration-guides/v2-primitives
|
|
"options": {
|
|
"resilience": {
|
|
"measure_mitigation": True,
|
|
"zne_mitigation": True,
|
|
"zne": {
|
|
"extrapolator":["exponential", "linear"],
|
|
"noise_factors":[1, 3, 5],
|
|
},
|
|
#"pec_mitigation": False,
|
|
#"pec": None,
|
|
#"layer_noise_learning":None,
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
response = requests.post(url, headers=headers, json=job_input)
|
|
|
|
if response.status_code == 200:
|
|
job_id = response.json().get('id')
|
|
print("Job created:",response.text)
|
|
else:
|
|
print(f"Error: {response.status_code}")
|
|
```
|
|
|
|
</TabItem>
|
|
|
|
<TabItem value="Dynamical Decoupling" label="Dynamical Decoupling">
|
|
|
|
```python
|
|
import requests
|
|
|
|
url = 'https://api.quantum-computing.ibm.com/runtime/jobs'
|
|
headers = {
|
|
'Content-Type': 'application/json',
|
|
'x-access-token':auth_id,
|
|
'x-qx-client-application': 'qiskit-version-2/0.39.2/'+'your_application' # specifying the application you might be running from. For an actual Integration project, this option is invaluable to know where jobs are coming from. At this time the "qiskit-version-2/0.39.2/" string is a necessary prefix.
|
|
}
|
|
job_input = {
|
|
'program_id': 'estimator',
|
|
"backend": backend,
|
|
"hub": "hub1",
|
|
"group": "group1",
|
|
"project": "project1",
|
|
"start_session": "False", # set to False if you just need to run a single job.
|
|
"params": {
|
|
"pubs": [ #primitive unified blocs (PUBs) containing one circuit each. c.f. https://docs.quantum.ibm.com/migration-guides/v2-primitives
|
|
[resulting_qasm, # QASM circuit
|
|
{"IIZII": 1, "XIZZZ": 2.3}, # Observable
|
|
None # parameter values
|
|
]],
|
|
"version": 2, # this defines the version of the Qiskit Runtime Primitive to use, c.f. https://docs.quantum.ibm.com/migration-guides/v2-primitives
|
|
"options": {
|
|
"dynamical_decoupling": {
|
|
"enable": True,
|
|
"sequence_type": 'XpXm',
|
|
"extra_slack_distribution": 'middle',
|
|
"scheduling_method": 'alap',
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
response = requests.post(url, headers=headers, json=job_input)
|
|
|
|
if response.status_code == 200:
|
|
job_id = response.json().get('id')
|
|
print("Job created:",response.text)
|
|
else:
|
|
print(f"Error: {response.status_code}")
|
|
```
|
|
|
|
</TabItem>
|
|
|
|
<TabItem value="Twirling" label="Twirling">
|
|
|
|
```python
|
|
import requests
|
|
|
|
url = 'https://api.quantum-computing.ibm.com/runtime/jobs'
|
|
headers = {
|
|
'Content-Type': 'application/json',
|
|
'x-access-token':auth_id,
|
|
'x-qx-client-application': 'qiskit-version-2/0.39.2/'+'your_application' # specifying the application you might be running from. For an actual Integration project, this option is invaluable to know where jobs are coming from. At this time the "qiskit-version-2/0.39.2/" string is a necessary prefix.
|
|
}
|
|
job_input = {
|
|
'program_id': 'estimator',
|
|
"backend": backend,
|
|
"hub": "hub1",
|
|
"group": "group1",
|
|
"project": "project1",
|
|
"start_session": "False", # set to False if you just need to run a single job.
|
|
"params": {
|
|
"pubs": [ #primitive unified blocs (PUBs) containing one circuit each. c.f. https://docs.quantum.ibm.com/migration-guides/v2-primitives
|
|
[resulting_qasm, # QASM circuit
|
|
{"IIZII": 1, "XIZZZ": 2.3}, # Observable
|
|
None # parameter values
|
|
]],
|
|
"version": 2, # this defines the version of the Qiskit Runtime Primitive to use, c.f. https://docs.quantum.ibm.com/migration-guides/v2-primitives
|
|
"options": {
|
|
"twirling": {
|
|
"enable_gates": True,
|
|
"enable_measure": True,
|
|
"num_randomizations": "auto",
|
|
"shots_per_randomization": "auto",
|
|
"strategy": "active-accum",
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
response = requests.post(url, headers=headers, json=job_input)
|
|
|
|
if response.status_code == 200:
|
|
job_id = response.json().get('id')
|
|
print("Job created:",response.text)
|
|
else:
|
|
print(f"Error: {response.status_code}")
|
|
```
|
|
|
|
|
|
</TabItem>
|
|
</Tabs>
|
|
|
|
|
|
<span id="start-sampler"></span>
|
|
## Sampler primitive with REST API
|
|
|
|
### 1. Initialize the account
|
|
|
|
Because Qiskit Runtime Sampler is a managed service, you first need to initialize your account. You can then select the device you want to use to run your calculations on.
|
|
|
|
Find details on how to initialize your account, view available backends, and invalidate tokens in this [topic](./setup-channel#set-up-to-use-ibm-quantum-platform-with-rest-api).
|
|
|
|
|
|
### 2. Create a QASM circuit
|
|
|
|
You need at least one circuit as the input to the Sampler primitive.
|
|
|
|
|
|
Define a QASM quantum circuit:
|
|
|
|
```python
|
|
qasm_string='''
|
|
OPENQASM 3;
|
|
include "stdgates.inc";
|
|
qreg q[2];
|
|
creg c[2];
|
|
x q[0];
|
|
cx q[0], q[1];
|
|
c[0] = measure q[0];
|
|
c[1] = measure q[1];
|
|
'''
|
|
```
|
|
|
|
|
|
The code snippets given below assume that the `qasm_string` has been transpiled to a new string `resulting_qasm`. Find detailed instructions on how to use the Qiskit transpiler service API in this [topic](./transpile-rest-api).
|
|
|
|
|
|
### 3. Run the quantum circuit using Sampler V2 API
|
|
|
|
|
|
<Admonition type="note">
|
|
The jobs below use [Qiskit Runtime V2 primitives](/migration-guides/v2-primitives). Both `SamplerV2` and `EstimatorV2` take one or more primitive unified blocs (PUBs) as the input. Each PUB is a tuple that contains one circuit and the data broadcasted to that circuit, which can be multiple observables and parameters. Each PUB returns a result.
|
|
</Admonition>
|
|
|
|
|
|
```python
|
|
import requests
|
|
|
|
url = 'https://api.quantum-computing.ibm.com/runtime/jobs'
|
|
headers = {
|
|
'Content-Type': 'application/json',
|
|
'x-access-token':auth_id,
|
|
'x-qx-client-application': 'qiskit-version-2/0.39.2/'+'your_application' # specifying the application you might be running from. For an actual Integration project, this option is invaluable to know where jobs are coming from. At this time the "qiskit-version-2/0.39.2/" string is a necessary prefix.
|
|
}
|
|
job_input = {
|
|
'program_id': 'sampler',
|
|
"backend": backend,
|
|
"hub": "hub1",
|
|
"group": "group1",
|
|
"project": "project1",
|
|
"start_session": "False", # set to False if you just need to run a single job.
|
|
"params": {
|
|
"pubs": [[resulting_qasm],[resulting_qasm,None,500]], # primitive unified blocs (PUBs) containing one circuit each. c.f. https://docs.quantum.ibm.com/migration-guides/v2-primitives
|
|
"version": 2 # this defines the version of the Qiskit Runtime Primitive to use, c.f. https://docs.quantum.ibm.com/migration-guides/v2-primitives
|
|
}}
|
|
|
|
response = requests.post(url, headers=headers, json=job_input)
|
|
|
|
if response.status_code == 200:
|
|
job_id = response.json().get('id')
|
|
print("Job created:",response.text)
|
|
else:
|
|
print(f"Error: {response.status_code}")
|
|
```
|
|
|
|
|
|
### 4. Check job status and get results
|
|
|
|
Next, pass the `job_id` to the API:
|
|
|
|
```python
|
|
response_status_singlejob= requests.get(url+'/'+job_id, headers=headers)
|
|
response_status_singlejob.json().get('state')
|
|
```
|
|
Output
|
|
|
|
```text
|
|
>>> Job ID: 58223448-5100-4dec-a47a-942fb30edced
|
|
>>> Job Status: JobStatus.RUNNING
|
|
```
|
|
|
|
Get job results:
|
|
```python
|
|
response_result= requests.get(url+'/'+job_id+'/results', headers=headers)
|
|
|
|
res_dict=response_result.json()
|
|
|
|
# Get results for the first PUB
|
|
counts=res_dict['results'][0]['data']['c']['samples']
|
|
|
|
print(counts[:20])
|
|
```
|
|
Output
|
|
```text
|
|
['0x3', '0x0', '0x2', '0x1', '0x0', '0x3', '0x0', '0x3', '0x1', '0x2', '0x2', '0x0', '0x2', '0x0', '0x3', '0x3', '0x2', '0x0', '0x1', '0x0']
|
|
```
|
|
|
|
### 5. Work with Runtime options
|
|
|
|
Error mitigation techniques allow users to mitigate circuit errors by modeling the device noise at the time of execution. This typically results in quantum pre-processing overhead related to model training, and classical post-processing overhead to mitigate errors in the raw results by using the generated model.
|
|
|
|
The error mitigation techniques built in to primitives are advanced resilience options. To specify these options, use the `resilience_level` option when submitting your job.
|
|
Sampler V2 does not support specifying resilience levels. However, you can turn on or off individual error mitigation / suppression methods.
|
|
|
|
The following examples demonstrate the default options for dynamical decoupling and twirling. Find more options and further details in the [Error mitigation and suppression techniques](./error-mitigation-and-suppression-techniques) topic.
|
|
|
|
<Tabs>
|
|
|
|
<TabItem value="Dynamical Decoupling" label="Dynamical Decoupling">
|
|
|
|
```python
|
|
import requests
|
|
|
|
url = 'https://api.quantum-computing.ibm.com/runtime/jobs'
|
|
headers = {
|
|
'Content-Type': 'application/json',
|
|
'x-access-token':auth_id,
|
|
'x-qx-client-application': 'qiskit-version-2/0.39.2/'+'your_application' # specifying the application you might be running from. For an actual Integration project, this option is invaluable to know where jobs are coming from. At this time the "qiskit-version-2/0.39.2/" string is a necessary prefix.
|
|
}
|
|
job_input = {
|
|
'program_id': 'sampler',
|
|
"backend": backend,
|
|
"hub": "hub1",
|
|
"group": "group1",
|
|
"project": "project1",
|
|
"start_session": "False", # set to False if you just need to run a single job.
|
|
"params": {
|
|
"pubs": [[resulting_qasm]], # primitive unified blocs (PUBs) containing one circuit each. c.f. https://docs.quantum.ibm.com/migration-guides/v2-primitives
|
|
"version": 2, # this defines the version of the Qiskit Runtime Primitive to use, c.f. https://docs.quantum.ibm.com/migration-guides/v2-primitives
|
|
"options": {
|
|
"dynamical_decoupling": {
|
|
"enable": True,
|
|
"sequence_type": 'XpXm',
|
|
"extra_slack_distribution": 'middle',
|
|
"scheduling_method": 'alap',
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
response = requests.post(url, headers=headers, json=job_input)
|
|
|
|
if response.status_code == 200:
|
|
job_id = response.json().get('id')
|
|
print("Job created:",response.text)
|
|
else:
|
|
print(f"Error: {response.status_code}")
|
|
```
|
|
|
|
</TabItem>
|
|
|
|
<TabItem value="Twirling" label="Twirling">
|
|
|
|
```python
|
|
import requests
|
|
|
|
url = 'https://api.quantum-computing.ibm.com/runtime/jobs'
|
|
headers = {
|
|
'Content-Type': 'application/json',
|
|
'x-access-token':auth_id,
|
|
'x-qx-client-application': 'qiskit-version-2/0.39.2/'+'your_application' # specifying the application you might be running from. For an actual Integration project, this option is invaluable to know where jobs are coming from. At this time the "qiskit-version-2/0.39.2/" string is a necessary prefix.
|
|
}
|
|
job_input = {
|
|
'program_id': 'sampler',
|
|
"backend": backend,
|
|
"hub": "hub1",
|
|
"group": "group1",
|
|
"project": "project1",
|
|
"start_session": "False", # set to False if you just need to run a single job.
|
|
"params": {
|
|
"pubs": [[resulting_qasm]], # primitive unified blocs (PUBs) containing one circuit each. c.f. https://docs.quantum.ibm.com/migration-guides/v2-primitives
|
|
"version": 2, # this defines the version of the Qiskit Runtime Primitive to use, c.f. https://docs.quantum.ibm.com/migration-guides/v2-primitives
|
|
"options": {
|
|
"twirling": {
|
|
"enable_gates": True,
|
|
"enable_measure": True,
|
|
"num_randomizations": "auto",
|
|
"shots_per_randomization": "auto",
|
|
"strategy": "active-accum",
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
response = requests.post(url, headers=headers, json=job_input)
|
|
|
|
if response.status_code == 200:
|
|
job_id = response.json().get('id')
|
|
print("Job created:",response.text)
|
|
else:
|
|
print(f"Error: {response.status_code}")
|
|
```
|
|
|
|
|
|
</TabItem>
|
|
</Tabs>
|
|
|
|
## Next steps
|
|
|
|
<Admonition type="tip" title="Recommendations">
|
|
- There are several ways to run workloads, depending on your needs: job mode, session mode and batch mode. Learn how to work with session mode and batch mode in the [execution modes topic](./execution-modes-rest-api).
|
|
- Learn how to [initialize your account](./setup-channel#set-up-to-use-ibm-quantum-platform-with-rest-api) with REST API.
|
|
- Learn how to [transpile circuits using REST API](./transpile-rest-api).
|
|
- Read [Migrate to V2 primitives](/migration-guides/v2-primitives).
|
|
- Practice with primitives by working through the [Cost function lesson](https://learning.quantum.ibm.com/course/variational-algorithm-design/cost-functions#primitives) in IBM Quantum Learning.
|
|
- Learn how to transpile locally in the [Transpile](./transpile) section.
|
|
</Admonition> |