Hardware
Masao Tokunari und Tamiya Onodera (14. Juni 2024)
Dieser Kurs basiert auf einem Live-Kurs an der Universität Tokio.
Das Vorlesungs-PDF dieser Lektion wurde in zwei Teile aufgeteilt. Teil 1 herunterladen und Teil 2 herunterladen. Beachte, dass manche Codeausschnitte veraltet sein können, da es sich um statische Bilder handelt.
1. Einführung
Diese Lektion erkundet moderne Quantencomputing-Hardware.
Wir beginnen damit, einige Versionen zu überprüfen und relevante Pakete zu importieren.
# 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 und Target
Qiskit bietet eine API, um sowohl statische als auch dynamische Informationen über ein Quantengerät abzurufen. Wir verwenden eine Backend-Instanz als Schnittstelle zu einem Gerät. Diese enthält eine Target-Instanz – ein abstraktes Maschinenmodell, das die wesentlichen Eigenschaften zusammenfasst, wie etwa die Instruction Set Architecture (ISA) sowie zugehörige Eigenschaften und Einschränkungen. Nutzen wir diese Backend-Instanzen, um einige der Informationen abzurufen, die du auf der Seite Compute resources der IBM Quantum® Platform siehst. Zunächst erstellen wir eine Backend-Instanz für ein Gerät unserer Wahl. Im folgenden Beispiel verwenden wir „ibm_kyoto", „ibm_kawasaki" oder die am wenigsten ausgelastete Eagle-Maschine. Dein Zugang zu QPUs kann abweichen – passe den Backend-Namen entsprechend an.
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'
Beginnen wir mit einigen grundlegenden (statischen) Informationen über das Gerät.
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 Übung
Versuche, die grundlegenden Informationen über ein Heron-Gerät, „ibm_strasbourg", abzurufen. Probiere es zunächst selbst – weiter unten findest du einen Lösungscode zum Vergleichen.
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
Wir zeichnen jetzt die Coupling Map des Geräts. Wie du sehen kannst, stellen die Knoten nummerierte Qubits dar. Kanten zeigen an, welche Paare direkt mit dem 2-Qubit-Verschränkungs-Gate verbunden werden können. Die Topologie wird als „Heavy-Hex-Gitter" bezeichnet.
# 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. Qubit-Eigenschaften
Das Eagle-Gerät verfügt über 127 Qubits. Schauen wir uns die Eigenschaften einiger davon an.
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)
Berechnen wir den Median der T1-Zeiten der Qubits. Vergleiche das Ergebnis mit dem, was für das Gerät auf der IBM Quantum Platform angezeigt wird.
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 Übung
Berechne den Median der T2-Zeiten der Qubits. Probiere es zunächst selbst – weiter unten findest du einen Lösungscode zum Vergleichen.
# 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 Gate- und Auslesefehler
Wir widmen uns nun den Gate-Fehlern. Zunächst untersuchen wir die Datenstruktur der Target-Instanz. Sie ist ein Dictionary, dessen Schlüssel Operationsnamen sind.
target = backend.target
target.keys()
dict_keys(['measure', 'id', 'sx', 'delay', 'x', 'for_loop', 'rz', 'if_else', 'ecr', 'reset', 'switch_case'])
Die Werte sind ebenfalls Dictionaries. Schauen wir uns einige Einträge des Wert-Dictionarys für die Operation 'sx' an.
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)
Machen wir dasselbe für die Operationen 'ecr' und '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)
Wie zu sehen ist, sind die Auslesefehler in der Regel größer als die Fehler bei 2-Qubit-Operationen, die wiederum größer sind als die Fehler bei 1-Qubit-Operationen.
Nachdem wir die Datenstrukturen verstanden haben, können wir die mittleren Fehler für die Gates 'sx' und 'ecr' berechnen. Vergleiche die Ergebnisse erneut mit den Angaben zum Gerät auf der 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. Anhang
Ein besonders beliebtes Feature von Qiskit ist seine Visualisierungsfähigkeit. Sie umfasst Circuit-Visualisierer, Zustands- und Verteilungsvisualisierer sowie einen Target-Visualisierer. Die ersten beiden hast du bereits in den vorherigen Jupyter-Notebooks verwendet. Schauen wir uns nun einige Funktionen des Target-Visualisierers an.
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'