Prymitywy z REST API
Kroki opisane w tym temacie pokazują, jak uruchamiać i konfigurować obciążenia prymitywów za pomocą REST API, oraz demonstrują, jak wywoływać je w dowolnym programie według własnego wyboru.
Ta dokumentacja wykorzystuje moduł Python requests do zademonstrowania Qiskit Runtime REST API. Jednak ten przepływ pracy można wykonać przy użyciu dowolnego języka lub frameworka obsługującego REST API. Szczegółowe informacje znajdziesz w dokumentacji referencyjnej API.
Estimator primitive z REST API
1. Zainicjuj konto
Ponieważ Qiskit Runtime Estimator jest usługą zarządzaną, najpierw musisz zainicjować swoje konto. Następnie możesz wybrać urządzenie, którego chcesz użyć do obliczenia wartości oczekiwanej.
Szczegóły dotyczące inicjowania konta, przeglądania dostępnych Backend-ów i unieważniania tokenów znajdziesz w tym temacie.
2. Utwórz Circuit QASM
Potrzebujesz co najmniej jednego Circuit jako danych wejściowych dla prymitywu Estimator.
Zdefiniuj Circuit kwantowy QASM. Na przykład:
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];
'''
Poniższe fragmenty kodu zakładają, że qasm_string został poddany transpilacji do nowego ciągu znaków resulting_qasm.
3. Uruchom Circuit kwantowy za pomocą Estimator V2 API
Poniższe zadania używają Qiskit Runtime V2 primitives. Zarówno SamplerV2, jak i EstimatorV2 przyjmują jeden lub więcej primitive unified bloców (PUB) jako dane wejściowe. Każdy PUB to krotka zawierająca jeden Circuit oraz dane rozgłaszane do tego Circuit, co może obejmować wiele obserwowalnych i parametrów. Każdy PUB zwraca wynik.
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. Sprawdź status zadania i pobierz wyniki
Następnie przekaż job_id do 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
Pobierz wyniki zadania:
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. Pracuj z opcjami Runtime
Techniki łagodzenia błędów pozwalają użytkownikom minimalizować błędy Circuit poprzez modelowanie szumów urządzenia w czasie wykonywania. Zazwyczaj wiąże się to z kwantowym narzutem przetwarzania wstępnego związanym z trenowaniem modelu oraz klasycznym narzutem przetwarzania końcowego służącym do łagodzenia błędów w surowych wynikach przy użyciu wygenerowanego modelu.
Techniki łagodzenia błędów wbudowane w prymitywy to zaawansowane opcje odporności. Aby określić te opcje, użyj opcji resilience_level podczas przesyłania zadania.
Poniższe przykłady demonstrują domyślne opcje dla dynamicznego odsprzęgania, twirling-u i TREX + ZNE. Więcej opcji i szczegółów znajdziesz w temacie Techniki łagodzenia i tłumienia błędów.
- 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}")
Prymityw Sampler z REST API
1. Zainicjalizuj konto
Ponieważ Qiskit Runtime Sampler jest usługą zarządzaną, najpierw musisz zainicjalizować swoje konto. Następnie możesz wybrać urządzenie, na którym chcesz wykonywać obliczenia.
Szczegóły dotyczące inicjalizacji konta, przeglądania dostępnych Backend-ów oraz unieważniania tokenów znajdziesz w tym temacie.
2. Utwórz Circuit QASM
Potrzebujesz co najmniej jednego Circuit jako wejścia do prymitywu Sampler.
Zdefiniuj kwantowy Circuit 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];
'''
Poniższe fragmenty kodu zakładają, że qasm_string został przetranspilowany do nowego ciągu znaków resulting_qasm.
3. Uruchom kwantowy Circuit za pomocą API Sampler V2
Poniższe zadania korzystają z prymitywów Qiskit Runtime V2. Zarówno SamplerV2, jak i EstimatorV2 przyjmują jeden lub więcej prymitywnych bloków zunifikowanych (PUB) jako wejście. Każdy PUB to krotka zawierająca jeden Circuit oraz dane rozgłaszane do tego Circuit, którymi może być wiele obserwabli i parametrów. Każdy PUB zwraca wynik.
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. Sprawdź status zadania i pobierz wyniki
Następnie przekaż job_id do API:
response_status_singlejob= requests.get(url+'/'+job_id, headers=headers)
response_status_singlejob.json().get('state')
Wynik
>>> Job ID: 58223448-5100-4dec-a47a-942fb30edced
>>> Job Status: JobStatus.RUNNING
Pobierz wyniki zadania:
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])
Wynik
['0x3', '0x0', '0x2', '0x1', '0x0', '0x3', '0x0', '0x3', '0x1', '0x2', '0x2', '0x0', '0x2', '0x0', '0x3', '0x3', '0x2', '0x0', '0x1', '0x0']
5. Praca z opcjami Runtime
Techniki mitygacji błędów pozwalają użytkownikom ograniczać błędy Circuit przez modelowanie szumów urządzenia w czasie wykonania. Zazwyczaj wiąże się to z narzutem przetwarzania wstępnego związanym z trenowaniem modelu oraz narzutem przetwarzania klasycznego służącym do mitygacji błędów w surowych wynikach przy użyciu wygenerowanego modelu.
Techniki mitygacji błędów wbudowane w prymitywy to zaawansowane opcje odporności. Aby je określić, użyj opcji resilience_level podczas przesyłania zadania.
Sampler V2 nie obsługuje określania poziomów odporności. Możesz jednak włączać lub wyłączać poszczególne metody mitygacji / tłumienia błędów.
Poniższe przykłady przedstawiają domyślne opcje dynamicznego odsprzęgania i twirling-u. Więcej opcji i szczegółów znajdziesz w temacie Techniki mitygacji i tłumienia błędów.
- 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}")
Primitive Sampler z REST API i parametryzowanymi Circuit
1. Zainicjuj konto
Ponieważ Qiskit Runtime jest usługą zarządzaną, najpierw musisz zainicjować swoje konto. Następnie możesz wybrać urządzenie, na którym chcesz wykonywać obliczenia.
Szczegółowe informacje na temat inicjowania konta, przeglądania dostępnych Backend oraz unieważniania tokenów znajdziesz w tym temacie.
2. Zdefiniuj parametry
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. Utwórz Circuit kwantowy i dodaj sparametryzowane Gate
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. Wygeneruj kod QASM 3
qasm_str = dumps(isa_circuit)
print("Generated QASM 3 code:")
print(qasm_str)
5. Uruchom Circuit kwantowy za pomoc ą API Sampler V2
Poniższe zadania korzystają z prymitywów Qiskit Runtime V2. Zarówno SamplerV2, jak i EstimatorV2 przyjmują jeden lub więcej primitive unified blocs (PUB) jako dane wejściowe. Każdy PUB to krotka zawierająca jeden Circuit oraz dane rozgłaszane do tego Circuit, które mogą obejmować wiele obserwabli i parametrów. Każdy PUB zwraca wynik.
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. Sprawdź status zadania i pobierz wyniki
Następnie przekaż job_id do API:
response_status_singlejob = requests.get(f"{url}/{job_id}", headers=headers)
response_status_singlejob.json().get('state')
Wynik
{'status': 'Completed'}
Pobierz wyniki zadania:
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])
Wynik
['0x1', '0x2', '0x1', '0x2', '0x1', '0x2', '0x0', '0x2', '0x1', '0x1', '0x2', '0x2', '0x1', '0x1', '0x1', '0x1', '0x1', '0x1', '0x1', '0x1']
Następne kroki
- Istnieje kilka sposobów uruchamiania zadań, w zależności od potrzeb: tryb zadania, tryb Session i tryb wsadowy. Dowiedz się, jak pracować z trybem Session i trybem wsadowym w temacie dotyczącym trybów wykonywania. Pamiętaj, że użytkownicy planu Open nie mogą przesyłać zadań w trybie Session.
- Dowiedz się, jak zainicjować konto za pomocą REST API.
- Przeczytaj Migrate to V2 primitives.
- Ćwicz z prymitywami, realizując lekcję dotyczącą funkcji kosztu w IBM Quantum Learning.
- Dowiedz się, jak Transpilować lokalnie, korzystając z sekcji Transpile.
- Migruj do prymitywów Qiskit Runtime V2.