Sprzęt
Masao Tokunari i Tamiya Onodera (14 czerwca 2024)
Ten kurs oparty jest na kursie prowadzonym na żywo na Uniwersytecie Tokijskim.
Wykład do tej lekcji w formacie PDF został podzielony na dwie części. Pobierz część 1 i pobierz część 2. Pamiętaj, że niektóre fragmenty kodu mogą być przestarzałe, ponieważ są to statyczne obrazy.
1. Introduction
Ta lekcja omawia nowoczesny sprzęt do obliczeń kwantowych.
Zaczniemy od sprawdzenia wersji pakietów i zaimportowania potrzebnych bibliotek.
# Added by doQumentation — required packages for this notebook
!pip install -q qiskit qiskit-ibm-runtime
import statistics
from qiskit_ibm_runtime import QiskitRuntimeService
2. Backend and Target
Qiskit udostępnia API do pobierania informacji — zarówno statycznych, jak i dynamicznych — o urządzeniu kwantowym. Do komunikacji z urządzeniem używamy instancji Backend, która zawiera instancję Target — abstrakcyjny model maszyny podsumowujący istotne cechy, takie jak architektura zestawu instrukcji (ISA) oraz powiązane właściwości i ograniczenia. Skorzystajmy z tych instancji Backend, aby uzyskać część informacji widocznych na stronie Compute resources w IBM Quantum® Platform. Na początek tworzymy instancję Backend dla interesującego nas urządzenia. Poniżej wybieramy "ibm_kyoto", "ibm_kawasaki" lub najmniej obciążoną maszynę Eagle. Twój dostęp do QPU może się różnić — zaktualizuj nazwę Backend odpowiednio.
service = QiskitRuntimeService()
# backend = service.backend("ibm_kawasaki") # an Eagle, if you have access to ibm_kawasaki
backend = service.least_busy(
operational=True, simulator=False, min_num_qubits=127
) # Eagle
backend.name
'ibm_strasbourg'
Zaczynamy od podstawowych (statycznych) informacji o urządzeniu.
print(
f"""
{backend.name}, {backend.num_qubits} qubits
processor type = {backend.processor_type}
basis gates = {backend.basis_gates}
"""
)
ibm_strasbourg, 127 qubits
processor type = {'family': 'Eagle', 'revision': 3}
basis gates = ['ecr', 'id', 'rz', 'sx', 'x']
2.1 Exercise
Spróbuj uzyskać podstawowe informacje o urządzeniu Heron o nazwie "ibm_strasbourg". Zrób to samodzielnie, ale poniżej dodano kod, dzięki któremu możesz się sprawdzić.
a_heron = service.backend("ibm_strasbourg") # a Heron
# your code here
print(
f"""
{backend.name}, {a_heron.num_qubits} qubits
processor type = {a_heron.processor_type}
basis gates = {a_heron.basis_gates}
"""
)
ibm_strasbourg, 133 qubits
processor type = {'family': 'Heron', 'revision': '1'}
basis gates = ['cz', 'id', 'rz', 'sx', 'x']
2.2 Coupling map
Teraz narysujemy coupling map urządzenia. Jak widać, węzły to Qubity opatrzone numerami. Krawędzie wskazują pary, do których możesz bezpośrednio zastosować dwukubitową bramkę splątującą. Topologia ta nosi nazwę "siatki ciężkiego heksa" (heavy-hex lattice).
# This function requires that Graphviz is installed. If you need to install Graphviz you can refer to:
# https://graphviz.org/download/#executable-packages for instructions.
try:
fig = backend.coupling_map.draw()
except RuntimeError as ex:
print(ex)
fig

3. Właściwości qubitów
Urządzenie Eagle ma 127 qubitów. Pobierzmy właściwości kilku z nich.
for qn in range(backend.num_qubits):
if qn >= 5:
break
print(f"{qn}: {backend.qubit_properties(qn)}")
0: QubitProperties(t1=0.000183686508736532, t2=0.00023613944465408068, frequency=4832100227.116953)
1: QubitProperties(t1=0.00048794378526038294, t2=9.007098375327869e-05, frequency=4736264354.075363)
2: QubitProperties(t1=0.00021247781834456527, t2=7.81037910324034e-05, frequency=4859349851.150393)
3: QubitProperties(t1=0.0002936462084765663, t2=0.00011400214529510604, frequency=4679749549.503852)
4: QubitProperties(t1=0.00044229440258559125, t2=0.0003181648356339447, frequency=4845872064.050596)
Obliczmy medianę czasów T1 qubitów. Porównaj wynik z tym pokazanym dla urządzenia na IBM Quantum Platform.
t1s = [backend.qubit_properties(qq).t1 for qq in range(backend.num_qubits)]
f"Median T1: {(statistics.median(t1s)*10**6):.2f} \u03bcs"
'Median T1: 285.43 μs'
3.1 Ćwiczenie
Oblicz medianę czasów T2 qubitów. Spróbuj zrobić to samodzielnie, ale poniżej dodano kod, dzięki któremu możesz się sprawdzić.
# Your code here
t2s = [backend.qubit_properties(qq).t2 for qq in range(backend.num_qubits)]
f"Median T2: {(statistics.median(t2s)*10**6):.2f} \u03bcs"
'Median T2: 173.10 μs'
3.2 Błędy Gate i readout
Przejdźmy teraz do błędów Gate. Na początek przyjrzyjmy się strukturze danych instancji target. Jest to słownik, którego kluczami są nazwy operacji.
target = backend.target
target.keys()
dict_keys(['measure', 'id', 'sx', 'delay', 'x', 'for_loop', 'rz', 'if_else', 'ecr', 'reset', 'switch_case'])
Jego wartości to również słowniki. Przyjrzyjmy się kilku elementom wartości (słownika) dla operacji 'sx'.
for i, qq in enumerate(target["sx"]):
if i >= 5:
break
print(i, qq, target["sx"][qq])
0 (0,) InstructionProperties(duration=6e-08, error=0.0007401311759115297)
1 (1,) InstructionProperties(duration=6e-08, error=0.0003163759907528654)
2 (2,) InstructionProperties(duration=6e-08, error=0.0003183859004638003)
3 (3,) InstructionProperties(duration=6e-08, error=0.00042235914178831863)
4 (4,) InstructionProperties(duration=6e-08, error=0.011163151923589715)
Zróbmy to samo dla operacji 'ecr' i 'measure'.
for i, edge in enumerate(target["ecr"]):
if i >= 5:
break
print(i, edge, target["ecr"][edge])
0 (0, 14) InstructionProperties(duration=6.6e-07, error=0.01486295709788732)
1 (1, 0) InstructionProperties(duration=6.6e-07, error=0.015201590794522601)
2 (2, 1) InstructionProperties(duration=6.6e-07, error=0.00697838102630724)
3 (2, 3) InstructionProperties(duration=6.6e-07, error=0.008075067943986797)
4 (3, 4) InstructionProperties(duration=6.6e-07, error=0.0630164507876913)
for i, qq in enumerate(target["measure"]):
if i >= 5:
break
print(i, qq, target["measure"][qq])
0 (0,) InstructionProperties(duration=1.6e-06, error=0.0078125)
1 (1,) InstructionProperties(duration=1.6e-06, error=0.155029296875)
2 (2,) InstructionProperties(duration=1.6e-06, error=0.057373046875)
3 (3,) InstructionProperties(duration=1.6e-06, error=0.02880859375)
4 (4,) InstructionProperties(duration=1.6e-06, error=0.01318359375)
Jak widać, błędy readout są zazwyczaj większe niż błędy operacji dwu-qubitowych, które z kolei są zazwyczaj większe niż błędy operacji jedno-qubitowych.
Po zapoznaniu się ze strukturami danych jesteśmy gotowi obliczyć mediany błędów dla Gate 'sx' i 'ecr'. Ponownie porównaj wyniki z tymi pokazanymi dla urządzenia na IBM Quantum Platform.
sx_errors = [inst_prop.error for inst_prop in target["sx"].values()]
f"Median SX error: {(statistics.median(sx_errors)):.3e}"
'Median SX error: 2.277e-04'
ecr_errors = [inst_prop.error for inst_prop in target["ecr"].values()]
f"Median ECR error: {(statistics.median(ecr_errors)):.3e}"
'Median ECR error: 6.895e-03'
4. Dodatek
Popularną funkcją Qiskit jest możliwość wizualizacji. Obejmuje ona wizualizatory Circuit, stanu i rozkładu oraz wizualizator target. Pierwsze dwa były już używane w poprzednich notebookach Jupyter. Skorzystajmy z niektórych możliwości wizualizatora target.
from qiskit.visualization import plot_gate_map
plot_gate_map(backend, font_size=14)

from qiskit.visualization import plot_error_map
plot_error_map(backend)

# Check Qiskit version
import qiskit
qiskit.__version__
'2.0.2'