Aller au contenu principal

Matériel

remarque

Masao Tokunari and Tamiya Onodera (14 June 2024)

This course is based on a live course delivered at the University of Tokyo.

This lesson's lecture pdf was split into two parts. Download part 1 and download part 2. Note that some code snippets might become deprecated since these are static images.

1. Introduction

Cette leçon explore le matériel moderne de calcul quantique.

Nous commencerons par vérifier certaines versions et importer quelques paquets pertinents.

# 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 et Target

Qiskit fournit une API pour obtenir des informations, à la fois statiques et dynamiques, sur un dispositif quantique. Nous utilisons une instance backend pour interfacer avec un dispositif, qui inclut une instance Target, un modèle de machine abstrait résumant les caractéristiques pertinentes telles que son architecture de jeu d'instructions (ISA) et toutes les propriétés ou contraintes qui lui sont associées. Utilisons ces instances backend pour obtenir certaines des informations que tu vois sur la page Ressources de calcul sur IBM Quantum® Platform. D'abord, créons une instance backend pour un dispositif d'intérêt. Dans ce qui suit, nous choisissons « ibm_kyoto », « ibm_kawasaki » ou la machine Eagle la moins chargée. Ton accès aux QPU peut différer ; mets à jour le nom du backend en conséquence.

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'

Commençons par quelques informations de base (statiques) sur le dispositif.

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 Exercice

Essaie d'obtenir les informations de base sur un dispositif Heron, « ibm_strasbourg ». Essaie par toi-même, mais du code a été ajouté ci-dessous pour que tu puisses te vérifier.

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 Carte de couplage

Nous allons maintenant dessiner la carte de couplage du dispositif. Comme tu peux le voir, les nœuds sont des qubits numérotés. Les arêtes indiquent les paires sur lesquelles tu peux directement appliquer la porte d'intrication à 2 qubits. La topologie est appelée un « réseau hexagonal lourd ».

# 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. Propriétés des qubits

Le dispositif Eagle a 127 qubits. Obtenons les propriétés de certains d'entre eux.

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)

Calculons la médiane des temps T1 des qubits. Compare le résultat avec celui affiché pour le dispositif sur 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 Exercice

Calcule la médiane des temps T2 des qubits. Essaie par toi-même, mais du code a été ajouté ci-dessous pour que tu puisses te vérifier.

# 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 Erreurs de portes et de lecture

Nous nous tournons maintenant vers les erreurs de portes. Pour commencer, nous étudions la structure de données de l'instance Target. Il s'agit d'un dictionnaire dont les clés sont des noms d'opérations.

target = backend.target
target.keys()
dict_keys(['measure', 'id', 'sx', 'delay', 'x', 'for_loop', 'rz', 'if_else', 'ecr', 'reset', 'switch_case'])

Ses valeurs sont également des dictionnaires. Examinons certains des éléments de la valeur (dictionnaire) pour l'opération « 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)

Faisons de même pour les opérations « ecr » et « 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)

Comme tu peux le constater, les erreurs de lecture ont tendance à être plus importantes que celles de l'opération à 2 qubits, qui à leur tour ont tendance à être plus importantes que l'opération à 1 qubit.

Ayant compris les structures de données, nous sommes prêts à calculer les erreurs médianes pour les portes « sx » et « ecr ». Compare de nouveau les résultats avec ceux affichés pour le dispositif sur 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. Annexe

Une fonctionnalité populaire de Qiskit est sa capacité de visualisation. Elle comprend des visualiseurs de circuits, de visualiseurs d'états et de distributions, et un visualiseur de Target. Tu as déjà utilisé les deux premiers dans les notebooks jupyter précédents. Utilisons quelques fonctionnalités du visualiseur de Target.

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'