Aller au contenu principal

Primitives avec l'API REST

Les étapes décrites dans cette page expliquent comment exécuter et configurer des charges de travail primitives avec l'API REST, et montrent comment les invoquer dans n'importe quel programme de ton choix.

remarque

Cette documentation utilise le module Python requests pour illustrer l'API REST Qiskit Runtime. Ce workflow peut toutefois être exécuté avec n'importe quel langage ou framework prenant en charge les API REST. Consulte la documentation de référence de l'API pour plus de détails.

Primitive Estimator avec l'API REST

1. Initialiser le compte

Comme Qiskit Runtime Estimator est un service géré, tu dois d'abord initialiser ton compte. Tu pourras ensuite sélectionner le dispositif à utiliser pour calculer la valeur d'espérance.

Retrouve les détails sur l'initialisation de ton compte, la consultation des backends disponibles et l'invalidation des tokens dans cette page.

2. Créer un circuit QASM

Il te faut au moins un circuit en entrée de la primitive Estimator.

Définis un circuit quantique QASM. Par exemple :

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];
'''

Les extraits de code suivants supposent que qasm_string a été transpilée en une nouvelle chaîne resulting_qasm.

3. Exécuter le circuit quantique avec l'API Estimator V2

remarque

Les jobs suivants utilisent les primitives Qiskit Runtime V2. SamplerV2 et EstimatorV2 acceptent un ou plusieurs blocs unifiés primitifs (PUBs) en entrée. Chaque PUB est un tuple contenant un circuit et les données diffusées à ce circuit, ce qui peut inclure plusieurs observables et paramètres. Chaque PUB retourne un résultat.

import requests

url = 'https://quantum.cloud.ibm.com/api/v1/jobs'
auth_id = "Bearer <YOUR_BEARER_TOKEN>"
crn = "<SERVICE-CRN>"
backend = "<BACKEND_NAME>"

headers = {
'Content-Type': 'application/json',
'Authorization':auth_id,
'Service-CRN': crn
}

job_input = {
'program_id': 'estimator',
"backend": backend,
"params": {
"pubs": [ #primitive unified blocs (PUBs) containing one circuit each.
[resulting_qasm, # QASM circuit
{"IIZII": 1, "XIZZZ": 2.3}, # Observable
None # parameter values
]]
}}

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. Vérifier le statut du job et récupérer les résultats

Ensuite, passe le job_id à l'API :

response_status_singlejob= requests.get(url+'/'+job_id, headers=headers)
response_status_singlejob.json().get('state')

Sortie

>>> Job ID: 58223448-5100-4dec-a47a-942fb30edcad
>>> Job Status: JobStatus.RUNNING

Récupérer les résultats du job :

response_result= requests.get(url+'/'+job_id+'/results', headers=headers)

res_dict=response_result.json()

estimator_result=res_dict['results']
print(estimator_result)

Sortie

[{'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. Travailler avec les options Runtime

Les techniques d'atténuation des erreurs permettent aux utilisateurs de réduire les erreurs de circuit en modélisant le bruit du dispositif au moment de l'exécution. Cela entraîne généralement un surcoût de pré-traitement quantique lié à l'entraînement du modèle, ainsi qu'un surcoût de post-traitement classique pour atténuer les erreurs dans les résultats bruts à l'aide du modèle généré.

Les techniques d'atténuation des erreurs intégrées aux primitives sont des options de résilience avancées. Pour les spécifier, utilise l'option resilience_level lors de la soumission de ton job.

Les exemples suivants illustrent les options par défaut pour le découplage dynamique, le twirling et TREX + ZNE. Retrouve plus d'options et de détails dans la page Techniques d'atténuation et de suppression des erreurs.

import requests

url = 'https://quantum.cloud.ibm.com/api/v1/jobs'
auth_id = "Bearer <YOUR_BEARER_TOKEN>"
crn = "<SERVICE-CRN>"
backend = "BACKEND_NAME"

headers = {
'Content-Type': 'application/json',
'Authorization':auth_id,
'Service-CRN': crn
}
job_input = {
'program_id': 'estimator',
"backend": backend,
"params": {
"pubs": [ #primitive unified blocs (PUBs) containing one circuit each
[resulting_qasm, # QASM circuit
{"IIZII": 1, "XIZZZ": 2.3}, # Observable
None # parameter values
]]
"options": {
"resilience": {
"measure_mitigation": True,
"zne_mitigation": True,
"zne": {
"extrapolator":["exponential", "linear"],
"noise_factors":[1, 3, 5],
},
},
},
}
}

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}")

Primitive Sampler avec l'API REST

1. Initialiser le compte

Comme Qiskit Runtime Sampler est un service géré, tu dois d'abord initialiser ton compte. Tu pourras ensuite sélectionner le dispositif sur lequel tu veux effectuer tes calculs.

Retrouve les détails sur l'initialisation de ton compte, la consultation des backends disponibles et l'invalidation des tokens dans cette page.

2. Créer un circuit QASM

Il te faut au moins un circuit en entrée de la primitive Sampler.

Définis un circuit quantique QASM :

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];
'''

Les extraits de code ci-dessous supposent que qasm_string a été transpilée en une nouvelle chaîne resulting_qasm.

3. Exécuter le circuit quantique avec l'API Sampler V2

remarque

Les jobs ci-dessous utilisent les primitives Qiskit Runtime V2. SamplerV2 et EstimatorV2 acceptent un ou plusieurs blocs unifiés primitifs (PUBs) en entrée. Chaque PUB est un tuple contenant un circuit et les données diffusées à ce circuit, ce qui peut inclure plusieurs observables et paramètres. Chaque PUB retourne un résultat.

import requests

url = 'https://quantum.cloud.ibm.com/api/v1/jobs'
auth_id = "Bearer <YOUR_BEARER_TOKEN>"
crn = "<SERVICE-CRN>"
backend = "<BACKEND_NAME>"

headers = {
'Content-Type': 'application/json',
'Authorization':auth_id,
'Service-CRN': crn
}
job_input = {
'program_id': 'sampler',
"backend": backend,
"params": {
"pubs": [[resulting_qasm],[resulting_qasm,None,500]] # primitive unified blocs (PUBs) containing one circuit each.
}}

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. Vérifier le statut du job et récupérer les résultats

Ensuite, passe le job_id à l'API :

response_status_singlejob= requests.get(url+'/'+job_id, headers=headers)
response_status_singlejob.json().get('state')

Sortie

>>> Job ID: 58223448-5100-4dec-a47a-942fb30edced
>>> Job Status: JobStatus.RUNNING

Récupérer les résultats du job :

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])

Sortie

['0x3', '0x0', '0x2', '0x1', '0x0', '0x3', '0x0', '0x3', '0x1', '0x2', '0x2', '0x0', '0x2', '0x0', '0x3', '0x3', '0x2', '0x0', '0x1', '0x0']

5. Travailler avec les options Runtime

Les techniques d'atténuation des erreurs permettent aux utilisateurs de réduire les erreurs de circuit en modélisant le bruit du dispositif au moment de l'exécution. Cela entraîne généralement un surcoût de pré-traitement quantique lié à l'entraînement du modèle, ainsi qu'un surcoût de post-traitement classique pour atténuer les erreurs dans les résultats bruts à l'aide du modèle généré.

Les techniques d'atténuation des erreurs intégrées aux primitives sont des options de résilience avancées. Pour les spécifier, utilise l'option resilience_level lors de la soumission de ton job. Sampler V2 ne prend pas en charge la spécification de niveaux de résilience. Tu peux cependant activer ou désactiver individuellement les méthodes d'atténuation et de suppression des erreurs.

Les exemples suivants illustrent les options par défaut pour le découplage dynamique et le twirling. Retrouve plus d'options et de détails dans la page Techniques d'atténuation et de suppression des erreurs.

import requests

url = 'https://quantum.cloud.ibm.com/api/v1/jobs'
auth_id = "Bearer <YOUR_BEARER_TOKEN>"
crn = "<SERVICE-CRN>"
backend = "<BACKEND_NAME>"

headers = {
'Content-Type': 'application/json',
'Authorization':auth_id,
'Service-CRN': crn
}
job_input = {
'program_id': 'sampler',
"backend": backend,
"params": {
"pubs": [[resulting_qasm]], # primitive unified blocs (PUBs) containing one circuit each.
"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}")

Primitive Sampler avec l'API REST et circuits paramétrés

1. Initialiser le compte

Comme Qiskit Runtime est un service géré, tu dois d'abord initialiser ton compte. Tu pourras ensuite sélectionner le dispositif sur lequel tu veux effectuer tes calculs.

Retrouve les détails sur l'initialisation de ton compte, la consultation des backends disponibles et l'invalidation des tokens dans cette page.

2. Définir les paramètres

import requests
import qiskit_ibm_runtime
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit.transpiler import generate_preset_pass_manager
from qiskit.qasm3 import dumps
from qiskit import QuantumCircuit
from qiskit.circuit import Parameter
from qiskit import transpile

service = QiskitRuntimeService(channel='ibm_quantum')
backend = service.backend("<SPECIFY BACKEND>")

pm = generate_preset_pass_manager(backend=backend, optimization_level=1)

theta = Parameter('theta')
phi = Parameter('phi')
parameter_values = {'theta': 1.57, 'phi': 3.14} # In case we want to pass a dictionary

3. Créer un circuit quantique et ajouter des portes paramétrées

qc = QuantumCircuit(2)

# Add parameterized gates
qc.rx(theta, 0)
qc.ry(phi, 1)
qc.cx(0, 1)
qc.measure_all()

# Draw the original circuit
qc.draw('mpl')

# Get an ISA circuit
isa_circuit = pm.run(qc)

4. Générer le code QASM 3

qasm_str = dumps(isa_circuit)
print("Generated QASM 3 code:")
print(qasm_str)

5. Exécuter le circuit quantique avec l'API Sampler V2

remarque

Les jobs suivants utilisent les primitives Qiskit Runtime V2. SamplerV2 et EstimatorV2 acceptent un ou plusieurs blocs unifiés primitifs (PUBs) en entrée. Chaque PUB est un tuple contenant un circuit et les données diffusées à ce circuit, ce qui peut inclure plusieurs observables et paramètres. Chaque PUB retourne un résultat.

import requests

url = 'https://quantum.cloud.ibm.com/api/v1/jobs'
auth_id = "Bearer <YOUR_BEARER_TOKEN>"
crn = "<SERVICE-CRN>"
backend = "<BACKEND_NAME>"

headers = {
'Content-Type': 'application/json',
'Authorization':auth_id,
'Service-CRN': crn
}

job_input = {
'program_id': 'sampler',
"backend": backend,
"params": {
# Choose one option: direct parameter transfer or through a dictionary
#"pubs": [[qasm_str,[1,2],500]], # primitive unified blocs (PUBs) containing one circuit each.
"pubs": [[qasm_str,parameter_values,500]], # primitive unified blocs (PUBs) containing one circuit each.
}}

response = requests.post(url, headers=headers, json=job_input)

if response.status_code == 200:
job_id = response.json().get('id')
print(f"Job created: {response.text}")
else:
print(f"Error: {response.status_code}")
print(response.text)

6. Vérifier le statut du job et récupérer les résultats

Ensuite, passe le job_id à l'API :

response_status_singlejob = requests.get(f"{url}/{job_id}", headers=headers)
response_status_singlejob.json().get('state')

Sortie

{'status': 'Completed'}

Récupérer les résultats du job :

response_result = requests.get(f"{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])

Sortie

['0x1', '0x2', '0x1', '0x2', '0x1', '0x2', '0x0', '0x2', '0x1', '0x1', '0x2', '0x2', '0x1', '0x1', '0x1', '0x1', '0x1', '0x1', '0x1', '0x1']

Prochaines étapes

Recommandations