Primitives mit REST API
Die Schritte in diesem Abschnitt beschreiben, wie du Primitive-Workloads mit der REST API ausführst und konfigurierst, und zeigen, wie du sie in einem beliebigen Programm deiner Wahl aufrufst.
Diese Dokumentation verwendet das Python-Modul requests, um die Qiskit Runtime REST API zu demonstrieren. Dieser Workflow kann jedoch mit jeder Sprache oder jedem Framework ausgeführt werden, das die Arbeit mit REST APIs unterstützt. Weitere Details findest du in der API-Referenzdokumentation.
Estimator-Primitive mit REST API
1. Konto initialisieren
Da der Qiskit Runtime Estimator ein verwalteter Dienst ist, musst du zunächst dein Konto initialisieren. Danach kannst du das Gerät auswählen, das du zur Berechnung des Erwartungswerts verwenden möchtest.
Details zur Kontoinitialisierung, zum Anzeigen verfügbarer Backends und zum Ungültigmachen von Tokens findest du in diesem Abschnitt.
2. QASM-Circuit erstellen
Du benötigst mindestens einen Circuit als Eingabe für das Estimator-Primitive.
Definiere einen QASM-Quantum-Circuit. Zum Beispiel:
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];
'''
Die folgenden Code-Snippets gehen davon aus, dass qasm_string in einen neuen String resulting_qasm transpiliert wurde.
3. Quantum-Circuit mit der Estimator V2 API ausführen
Die folgenden Jobs verwenden Qiskit Runtime V2 Primitives. Sowohl SamplerV2 als auch EstimatorV2 nehmen einen oder mehrere Primitive Unified Blocs (PUBs) als Eingabe entgegen. Jeder PUB ist ein Tupel, das einen Circuit und die an diesen Circuit übertragenen Daten enthält, bei denen es sich um mehrere Observablen und Parameter handeln kann. Jeder PUB gibt ein Ergebnis zurück.
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. Job-Status prüfen und Ergebnisse abrufen
Übergib als Nächstes die job_id an die API:
response_status_singlejob= requests.get(url+'/'+job_id, headers=headers)
response_status_singlejob.json().get('state')
Ausgabe
>>> Job ID: 58223448-5100-4dec-a47a-942fb30edcad
>>> Job Status: JobStatus.RUNNING
Job-Ergebnisse abrufen:
response_result= requests.get(url+'/'+job_id+'/results', headers=headers)
res_dict=response_result.json()
estimator_result=res_dict['results']
print(estimator_result)
Ausgabe
[{'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. Mit Runtime-Optionen arbeiten
Fehlerminderungstechniken ermöglichen es Nutzern, Circuit-Fehler zu reduzieren, indem das Geräterauschen zum Zeitpunkt der Ausführung modelliert wird. Dies führt typischerweise zu quantenspezifischem Vorverarbeitungs-Overhead beim Modelltraining und klassischem Nachverarbeitungs-Overhead, um Fehler in den Rohergebnissen mithilfe des generierten Modells zu mindern.
Die in Primitives integrierten Fehlerminderungstechniken sind erweiterte Resilience-Optionen. Um diese Optionen anzugeben, verwende die Option resilience_level beim Einreichen deines Jobs.
Die folgenden Beispiele zeigen die Standardoptionen für Dynamical Decoupling, Twirling und TREX + ZNE. Weitere Optionen und Details findest du im Abschnitt Fehlerminderungs- und Unterdrückungstechniken.
- TREX + ZNE
- Dynamical Decoupling
- Twirling
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}")
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": {
"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}")
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": {
"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}")
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.
2. Create a QASM circuit
You need at least one circuit as the input to the Sampler primitive.
Define a QASM quantum circuit:
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];
'''
Die folgenden Code-Snippets gehen davon aus, dass qasm_string in einen neuen String resulting_qasm transpiliert wurde.
3. Quantum-Circuit mit der Sampler V2 API ausführen
Die folgenden Jobs verwenden Qiskit Runtime V2 Primitives. Sowohl SamplerV2 als auch EstimatorV2 nehmen einen oder mehrere Primitive Unified Blocs (PUBs) als Eingabe entgegen. Jeder PUB ist ein Tupel, das einen Circuit und die an diesen Circuit übertragenen Daten enthält, bei denen es sich um mehrere Observablen und Parameter handeln kann. Jeder PUB gibt ein Ergebnis zurück.
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. Job-Status prüfen und Ergebnisse abrufen
Übergib als Nächstes die job_id an die API:
response_status_singlejob= requests.get(url+'/'+job_id, headers=headers)
response_status_singlejob.json().get('state')
Ausgabe
>>> Job ID: 58223448-5100-4dec-a47a-942fb30edced
>>> Job Status: JobStatus.RUNNING
Job-Ergebnisse abrufen:
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])
Ausgabe
['0x3', '0x0', '0x2', '0x1', '0x0', '0x3', '0x0', '0x3', '0x1', '0x2', '0x2', '0x0', '0x2', '0x0', '0x3', '0x3', '0x2', '0x0', '0x1', '0x0']
5. Mit Runtime-Optionen arbeiten
Fehlerminderungstechniken ermöglichen es Nutzern, Circuit-Fehler zu reduzieren, indem das Geräterauschen zum Zeitpunkt der Ausführung modelliert wird. Dies führt typischerweise zu quantenspezifischem Vorverarbeitungs-Overhead beim Modelltraining und klassischem Nachverarbeitungs-Overhead, um Fehler in den Rohergebnissen mithilfe des generierten Modells zu mindern.
Die in Primitives integrierten Fehlerminderungstechniken sind erweiterte Resilience-Optionen. Um diese Optionen anzugeben, verwende die Option resilience_level beim Einreichen deines Jobs.
Sampler V2 unterstützt keine Angabe von Resilience-Levels. Du kannst jedoch einzelne Fehlerminderungs- und Unterdrückungsmethoden aktivieren oder deaktivieren.
Die folgenden Beispiele zeigen die Standardoptionen für Dynamical Decoupling und Twirling. Weitere Optionen und Details findest du im Abschnitt Fehlerminderungs- und Unterdrückungstechniken.
- Dynamical Decoupling
- Twirling
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}")
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": {
"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}")
Sampler-Primitive mit REST API und parametrisierten Circuits
1. Konto initialisieren
Da Qiskit Runtime ein verwalteter Dienst ist, musst du zunächst dein Konto initialisieren. Danach kannst du das Gerät auswählen, auf dem du deine Berechnungen ausführen möchtest.
Details zur Kontoinitialisierung, zum Anzeigen verfügbarer Backends und zum Ungültigmachen von Tokens findest du in diesem Abschnitt.
2. Parameter definieren
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. Quantum-Circuit erstellen und parametrisierte Gates hinzufügen
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. QASM 3-Code generieren
qasm_str = dumps(isa_circuit)
print("Generated QASM 3 code:")
print(qasm_str)
5. Quantum-Circuit mit der Sampler V2 API ausführen
Die folgenden Jobs verwenden Qiskit Runtime V2 Primitives. Sowohl SamplerV2 als auch EstimatorV2 nehmen einen oder mehrere Primitive Unified Blocs (PUBs) als Eingabe entgegen. Jeder PUB ist ein Tupel, das einen Circuit und die an diesen Circuit übertragenen Daten enthält, bei denen es sich um mehrere Observablen und Parameter handeln kann. Jeder PUB gibt ein Ergebnis zurück.
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. Job-Status prüfen und Ergebnisse abrufen
Übergib als Nächstes die job_id an die API:
response_status_singlejob = requests.get(f"{url}/{job_id}", headers=headers)
response_status_singlejob.json().get('state')
Ausgabe
{'status': 'Completed'}
Job-Ergebnisse abrufen:
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])
Ausgabe
['0x1', '0x2', '0x1', '0x2', '0x1', '0x2', '0x0', '0x2', '0x1', '0x1', '0x2', '0x2', '0x1', '0x1', '0x1', '0x1', '0x1', '0x1', '0x1', '0x1']
Nächste Schritte
- Es gibt mehrere Möglichkeiten, Workloads auszuführen, je nach deinen Anforderungen: Job-Modus, Session-Modus und Batch-Modus. Wie du mit dem Session-Modus und dem Batch-Modus arbeitest, erfährst du im Abschnitt zu Ausführungsmodi. Beachte, dass Nutzer des Open Plan keine Session-Jobs einreichen können.
- Erfahre, wie du dein Konto initialisierst mit REST API.
- Lies Migration zu V2 Primitives.
- Übe mit Primitives anhand der Lektion zu Kostenfunktionen im IBM Quantum Learning.
- Erfahre, wie du lokal transpilierst, im Abschnitt Transpile.
- Migriere zu den Qiskit Runtime V2 Primitives.