Zum Hauptinhalt springen

Hardware

hinweis

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

Output of the previous code cell

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)

Output of the previous code cell

from qiskit.visualization import plot_error_map

plot_error_map(backend)

Output of the previous code cell

# Check Qiskit version
import qiskit

qiskit.__version__
'2.0.2'