Aller au contenu principal

Sampler avec l'API REST

Les étapes décrites dans cette rubrique expliquent comment exécuter et configurer des workloads 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 démontrer l'API REST de Qiskit Runtime. Cependant, ce workflow peut être exécuté en utilisant 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.

1. Initialiser le compte

Comme Qiskit Runtime Sampler est un service géré, tu dois d'abord initialiser ton compte. Tu peux ensuite sélectionner l'appareil sur lequel tu veux exécuter tes calculs.

Trouve des détails sur la façon d'initialiser ton compte, d'afficher les backends disponibles et de travailler avec des tokens dans Configurer l'utilisation d'IBM Quantum Platform avec l'API REST.

2. Créer un circuit QASM

Tu as besoin d'au moins un circuit comme 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 donnés ci-dessous supposent que le qasm_string a été transcompilé en une nouvelle chaîne resulting_qasm.

3. Exécuter le circuit quantique à l'aide de l'API Sampler V2

remarque

Les jobs ci-dessous utilisent les primitives Qiskit Runtime V2. SamplerV2 prend un ou plusieurs blocs unifiés primitifs (PUBs) comme entrée. Chaque PUB est un tuple qui contient un circuit et les données diffusées à ce circuit, qui peuvent être plusieurs paramètres, et renvoie un résultat par PUB.

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": {
# primitive unified blocs (PUBs) containing one circuit each:
"pubs": [[resulting_qasm],[resulting_qasm,None,500]]
}}

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 obtenir 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')

Output

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

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

Output

['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 de Qiskit Runtime

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

Les techniques d'atténuation d'erreurs intégrées aux primitives sont des options de résilience avancées. Pour spécifier ces options, 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. Cependant, tu peux activer ou désactiver des méthodes individuelles d'atténuation / suppression d'erreurs.

Les exemples suivants démontrent les options par défaut pour le découplage dynamique et la torsion. Trouve plus d'options et de détails supplémentaires dans la rubrique Techniques d'atténuation et de suppression d'erreurs.

Découplage dynamique

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": {
# primitive unified blocs (PUBs) containing one circuit each:
"pubs": [[resulting_qasm]],
"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}")

Torsion

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": {
# primitive unified blocs (PUBs) containing one circuit each:
"pubs": [[resulting_qasm]],
"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}")

Circuits paramétrés

1. Initialiser le compte

Comme Qiskit Runtime est un service géré, tu dois d'abord initialiser ton compte. Tu peux ensuite sélectionner l'appareil sur lequel tu veux exécuter tes calculs.

Trouve des détails sur la façon d'initialiser ton compte, d'afficher les backends disponibles et d'invalider des tokens dans cette rubrique.

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')
# In case we want to pass a dictionary:
parameter_values = {'theta': 1.57, 'phi': 3.14}

3. Créer un circuit quantique et ajouter des gates 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 à l'aide de l'API Sampler V2

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
# # primitive unified blocs (PUBs) containing one circuit each:
#"pubs": [[qasm_str,[1,2],500]],

# primitive unified blocs (PUBs) containing one circuit each:
"pubs": [[qasm_str,parameter_values,500]],
}}

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 obtenir 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')

Output

{'status': 'Completed'}

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

Output

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

Étapes suivantes

Recommandations
  • Il existe plusieurs façons d'exécuter des workloads, selon tes besoins : mode job, mode session et mode batch. Apprends à travailler avec le mode session et le mode batch dans la rubrique sur les modes d'exécution. Note que les utilisateurs du plan Open ne peuvent pas soumettre de jobs de session.
  • Apprends à initialiser ton compte avec l'API REST.
  • Entraîne-toi avec les primitives en suivant la leçon sur les fonctions de coût dans IBM Quantum Learning.
  • Apprends à transcompiler localement dans la section Transcompilation.