Zum Hauptinhalt springen

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.

hinweis

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

hinweis

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.

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

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

hinweis

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.

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

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

hinweis

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

Empfehlungen