Primitive cu REST API
Pașii din acest topic descriu cum să rulezi și să configurezi sarcini primitive cu REST API și demonstrează cum să le invoci în orice program la alegerea ta.
Această documentație folosește modulul Python requests pentru a demonstra Qiskit Runtime REST API. Cu toate acestea, acest flux de lucru poate fi executat folosind orice limbaj sau framework care suportă lucrul cu REST API. Consultă documentația de referință a API pentru detalii.
Primitiva Estimator cu REST API
1. Inițializează contul
Deoarece Qiskit Runtime Estimator este un serviciu gestionat, mai întâi trebuie să îți inițializezi contul. Poți apoi selecta dispozitivul pe care vrei să îl folosești pentru a calcula valoarea de așteptare.
Găsești detalii despre cum să îți inițializezi contul, să vizualizezi Backend-urile disponibile și să invalidezi token-urile în acest topic.
2. Creează un Circuit QASM
Ai nevoie de cel puțin un Circuit ca intrare pentru primitiva Estimator.
Definește un Circuit cuantic QASM. De exemplu:
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];
'''
Fragmentele de cod următoare presupun că qasm_string a fost transpilat într-un nou șir resulting_qasm.
3. Rulează Circuit-ul cuantic folosind Estimator V2 API
Joburile următoare folosesc primitivele Qiskit Runtime V2. Atât SamplerV2, cât și EstimatorV2 primesc unul sau mai multe primitive unified blocs (PUBs) ca intrare. Fiecare PUB este un tuplu care conține un Circuit și datele difuzate către acel Circuit, care pot fi mai multe observabile și parametri. Fiecare PUB returnează un rezultat.
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. Verifică starea jobului și obține rezultatele
Apoi, transmite job_id către API:
response_status_singlejob= requests.get(url+'/'+job_id, headers=headers)
response_status_singlejob.json().get('state')
Output
>>> Job ID: 58223448-5100-4dec-a47a-942fb30edcad
>>> Job Status: JobStatus.RUNNING
Obține rezultatele jobului:
response_result= requests.get(url+'/'+job_id+'/results', headers=headers)
res_dict=response_result.json()
estimator_result=res_dict['results']
print(estimator_result)
Output
[{'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. Lucrează cu opțiunile Runtime
Tehnicile de atenuare a erorilor le permit utilizatorilor să atenueze erorile de Circuit prin modelarea zgomotului dispozitivului la momentul execuției. Aceasta duce de obicei la costuri suplimentare de pre-procesare cuantică legate de antrenarea modelului și la costuri suplimentare de post-procesare clasică pentru atenuarea erorilor din rezultatele brute, folosind modelul generat.
Tehnicile de atenuare a erorilor integrate în primitive sunt opțiuni avansate de reziliență. Pentru a specifica aceste opțiuni, folosește opțiunea resilience_level atunci când trimiți jobul.
Exemplele de mai jos demonstrează opțiunile implicite pentru decuplarea dinamică, twirling și TREX + ZNE. Găsești mai multe opțiuni și detalii suplimentare în subiectul Tehnici de atenuare și suprimare a erorilor.
- 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. Inițializează contul
Deoarece Qiskit Runtime Sampler este un serviciu gestionat, trebuie mai întâi să îți inițializezi contul. Poți apoi să selectezi dispozitivul pe care vrei să rulezi calculele.
Găsești detalii despre cum să îți inițializezi contul, să vizualizezi Backend-urile disponibile și să invalidezi tokenuri în acest topic.
2. Creează un Circuit QASM
Ai nevoie de cel puțin un Circuit ca intrare pentru primitiva Sampler.
Definește un Circuit cuantic 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];
'''
Fragmentele de cod de mai jos presupun că qasm_string a fost transpilat într-un nou șir resulting_qasm.
3. Rulează Circuit-ul cuantic folosind Sampler V2 API
Job-urile de mai jos folosesc primitivele Qiskit Runtime V2. Atât SamplerV2, cât și EstimatorV2 primesc ca intrare unul sau mai multe primitive unified blocs (PUBs). Fiecare PUB este un tuplu care conține un Circuit și datele transmise acelui Circuit, care pot fi mai multe observabile și parametri. Fiecare PUB returnează un rezultat.
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. Verifică statusul job-ului și obține rezultatele
Apoi, transmite job_id către 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
Obține rezultatele job-ului:
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. Lucrează cu opțiunile Runtime
Tehnicile de atenuare a erorilor le permit utilizatorilor să atenueze erorile din Circuit prin modelarea zgomotului dispozitivului la momentul execuției. Acest lucru duce de obicei la un overhead de pre-procesare cuantică legat de antrenarea modelului, și la un overhead de post-procesare clasică pentru a atenua erorile din rezultatele brute folosind modelul generat.
Tehnicile de atenuare a erorilor integrate în primitive sunt opțiuni avansate de reziliență. Pentru a specifica aceste opțiuni, folosește opțiunea resilience_level atunci când trimiți job-ul.
Sampler V2 nu suportă specificarea nivelurilor de reziliență. Totuși, poți activa sau dezactiva metode individuale de atenuare / suprimare a erorilor.
Exemplele de mai jos demonstrează opțiunile implicite pentru decuplarea dinamică și twirling. Găsești mai multe opțiuni și detalii suplimentare în topicul Tehnici de atenuare și suprimare a erorilor.
- 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 cu REST API și circuite parametrizate
1. Inițializează contul
Deoarece Qiskit Runtime este un serviciu gestionat, trebuie mai întâi să îți inițializezi contul. Poți apoi selecta dispozitivul pe care vrei să îți rulezi calculele.
Găsești detalii despre cum să îți inițializezi contul, să vizualizezi Backend-urile disponibile și să invalidezi token-urile în acest topic.
2. Definește parametrii
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. Creează un Circuit cuantic și adaugă Gate-uri parametrizate
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. Generează cod QASM 3
qasm_str = dumps(isa_circuit)
print("Generated QASM 3 code:")
print(qasm_str)
5. Rulează Circuit-ul cuantic folosind Sampler V2 API
Joburile de mai jos folosesc Qiskit Runtime V2 primitives. Atât SamplerV2, cât și EstimatorV2 primesc unul sau mai multe primitive unified blocs (PUBs) ca intrare. Fiecare PUB este un tuplu care conține un Circuit și datele difuzate către acel Circuit, care pot fi mai multe observabile și parametri. Fiecare PUB returnează un rezultat.
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. Verifică starea jobului și obține rezultatele
În continuare, transmite job_id către API:
response_status_singlejob = requests.get(f"{url}/{job_id}", headers=headers)
response_status_singlejob.json().get('state')
Output
{'status': 'Completed'}
Obține rezultatele jobului:
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']
Pași următori
- Există mai multe modalități de a rula workload-uri, în funcție de nevoile tale: job mode, session mode și batch mode. Află cum să lucrezi cu session mode și batch mode în topicul despre moduri de execuție. Reține că utilizatorii planului Open nu pot trimite joburi de tip Session.
- Află cum să îți inițializezi contul cu REST API.
- Citește Migrează la primitive V2.
- Exersează cu primitive lucrând prin lecția despre funcții de cost din IBM Quantum Learning.
- Află cum să transpilezi local în secțiunea Transpiler.
- Migrează la Qiskit Runtime V2 primitives.