Circuits dynamiques de référence avec paires de cloches coupées
Estimation de l'utilisation : 22 secondes sur un processeur r2 Heron (REMARQUE : il s'agit uniquement d'une estimation. Votre durée d'exécution peut varier.)
Résultats d'apprentissage
À l'issue de ce tutoriel, les utilisateurs devraient être en mesure de :
- Comment construire des circuits dynamiques avec des mesures en cours de circuit et un système classique de transmission directe pour téléporter l'intrication entre des qubits distants;
- Comment calculer et interpréter la mesure d'erreur permettant de quantifier la fidélité de la paire de Bell sur un appareil;
- Comment déterminer, à partir des résultats des tests de performance, quelles paires de qubits sont les mieux adaptées aux opérations basées sur le LOCC.
Prérequis
Nous recommandons aux utilisateurs de se familiariser avec les sujets suivants avant de suivre ce tutoriel :
- Les concepts fondamentaux de l'informatique quantique, notamment les états de Bell, l'intrication et les portes quantiques;
- Connaissance des circuits dynamiques ( mesures en cours de fonctionnement et régulation classique à action directe);
- Connaissances de base sur Qiskit SDK et IBM Quantum® Compute Service, ainsi qu’un accès à un compte IBM Quantum.
Arrière-plan
Le matériel quantique est généralement limité aux interactions locales, mais de nombreux algorithmes nécessitent l'intrication de qubits distants, voire de qubits situés sur des processeurs distincts. Les circuits dynamiques, c'est-à-dire les circuits avec mesure à mi-circuit et feedforward, permettent de surmonter ces limites en utilisant la communication classique en temps réel pour mettre en œuvre efficacement des opérations quantiques non locales. Dans cette approche, les résultats de mesure provenant d'une partie d'un circuit (ou d'un QPU) peuvent déclencher de manière conditionnelle des portes logiques sur une autre partie, ce qui nous permet de téléporter l'intrication sur de longues distances. Cela constitue la base des schémas LOCC (Local Operations and Classical Communication), dans lesquels nous consommons des états de ressources intriqués (paires de Bell) et communiquons les résultats des mesures de manière classique afin de relier des qubits distants.
Une utilisation prometteuse du LOCC consiste à réaliser des portes CNOT virtuelles à longue portée par téléportation, comme le montre le tutoriel sur l'intrication à longue portée. Au lieu d'un CNOT direct à longue portée (que la connectivité matérielle pourrait ne pas permettre), nous créons des paires de Bell et mettons en œuvre une porte basée sur la téléportation. Cependant, la fidélité de ces opérations dépend des caractéristiques matérielles. La décohérence des qubits pendant le délai nécessaire (en attendant les résultats des mesures) et la latence de la communication classique peuvent dégrader l'état intriqué. De plus, les erreurs sur les mesures à mi-circuit sont plus difficiles à corriger que les erreurs sur les mesures finales, car elles se propagent au reste du circuit par le biais des portes conditionnelles.
Dans l 'expérience de référence, les auteurs proposent un critère de fidélité pour les paires de Bell afin de déterminer quelles parties d'un dispositif se prêtent le mieux à l'intrication basée sur la technique LOCC. L'idée est d'exécuter un petit circuit dynamique sur chaque groupe de quatre qubits connectés au sein du processeur. Ce circuit à quatre qubits commence par créer une paire de Bell sur les deux qubits centraux, puis utilise celle-ci comme ressource pour intriquer les deux qubits périphériques à l'aide de la technique LOCC. Concrètement, les qubits 1 et 2 sont préparés localement sous la forme d'une paire de Bell non coupée (une paire de Bell créée directement à l'aide d'une matrice de Hadamard et d'une porte CNOT, sans téléportation), puis une routine de téléportation utilise cette paire de Bell pour entrelacer les qubits 0 et 3. Les qubits 1 et 2 sont mesurés pendant l'exécution du circuit, et en fonction de ces résultats, des corrections de Pauli (un X sur le qubit 3 et un Z sur le qubit 0) sont appliquées. Les qubits 0 et 3 se retrouvent alors dans un état de Bell à la fin du circuit.
Pour quantifier la qualité de cette paire intriquée finale, nous mesurons ses stabilisateurs : plus précisément, la parité dans la base ( ) et dans la base ( ). Pour une paire de Bell parfaite, ces deux attentes sont égales à +1. En pratique, le bruit matériel réduira ces valeurs. Nous répétons donc le circuit deux fois pour chaque paire de qubits : un circuit mesure les qubits 0 et 3 dans la base, et un autre les mesure dans la base. À partir des résultats, nous obtenons une estimation de et pour cette paire de qubits. Nous utilisons l'erreur quadratique moyenne (MSE) de ces stabilisateurs par rapport à la valeur idéale (1) comme mesure simple de la fidélité de l'intrication. Une MSE plus faible signifie que les deux qubits ont atteint un état de Bell plus proche de l'idéal (fidélité plus élevée), tandis qu'une MSE plus élevée indique davantage d'erreurs. En analysant cette expérience sur l'ensemble du dispositif, nous pouvons évaluer les capacités de mesure et de feedforward de différents groupes de qubits et identifier les meilleures paires de qubits pour les opérations LOCC.
Ce tutoriel présente une expérience réalisée sur un dispositif « IBM Quantum® » afin d'illustrer comment des circuits dynamiques peuvent être utilisés pour générer et évaluer l'intrication entre des qubits distants. Nous allons cartographier toutes les chaînes linéaires à quatre qubits présentes sur le dispositif, exécuter le circuit de téléportation sur chacune d'entre elles, puis visualiser la distribution des valeurs MSE. Cette procédure complète explique comment tirer parti du service de calcul « IBM Quantum » et des fonctionnalités de circuits dynamiques afin d'orienter les choix liés au matériel pour la conception de circuits ou la répartition d'algorithmes quantiques au sein d'un système modulaire.
Exigences
Avant de commencer ce tutoriel, assurez-vous que les éléments suivants sont installés :
- Qiskit SDK v2.0 ou plus tard, avec prise en charge de la visualisation
- v0.40Qiskit Runtime ou plus tard (
pip install qiskit-ibm-runtime) - Qiskit Aer v0.17 ou version ultérieure (
pip install qiskit-aer)
Configuration
from qiskit import QuantumCircuit
from qiskit_ibm_runtime import QiskitRuntimeService, SamplerV2 as Sampler
from qiskit.transpiler import generate_preset_pass_manager
import numpy as np
import matplotlib.pyplot as plt
def create_bell_stab(initial_layouts):
"""
Create a circuit for a 1D chain of qubits (number
of qubits must be a multiple of 4), where a middle
Bell pair is consumed to create a Bell at the edge.
Takes as input a list of lists, where each element
of the list is a 1D chain of physical qubits that is
used as the initial_layout for the transpiled circuit.
Returns a list of length-2 tuples, each tuple
contains a circuit to measure the ZZ stabilizer and
a circuit to measure the XX stabilizer of the edge
Bell state.
"""
bell_circuits = []
for (
initial_layout
) in initial_layouts: # Iterate over chains of physical qubits
assert (
len(initial_layout) % 4 == 0
), "The length of the chain must be a multiple of 4, "
f"len(inital_layout)={len(initial_layout)}"
num_pairs = len(initial_layout) // 4
bell_parallel = QuantumCircuit(4 * num_pairs, 4 * num_pairs)
for pair_idx in range(num_pairs):
(q0, q1, q2, q3) = (
pair_idx * 4,
pair_idx * 4 + 1,
pair_idx * 4 + 2,
pair_idx * 4 + 3,
)
(c0, c1) = pair_idx * 4, pair_idx * 4 + 3 # edge qubits
(ca0, ca1) = pair_idx * 4 + 1, pair_idx * 4 + 2 # middle qubits
bell_parallel.h(q0)
bell_parallel.h(q1)
bell_parallel.cx(q1, q2)
bell_parallel.cx(q0, q1)
bell_parallel.cx(q2, q3)
bell_parallel.h(q2)
# add barrier BEFORE measurements and add id in conditional
bell_parallel.barrier()
for pair_idx in range(num_pairs):
(q0, q1, q2, q3) = (
pair_idx * 4,
pair_idx * 4 + 1,
pair_idx * 4 + 2,
pair_idx * 4 + 3,
)
(ca0, ca1) = pair_idx * 4 + 1, pair_idx * 4 + 2 # middle qubits
bell_parallel.measure(q1, ca0)
bell_parallel.measure(q2, ca1)
# bell_parallel.barrier() #remove barrier after measurement
for pair_idx in range(num_pairs):
(q0, q1, q2, q3) = (
pair_idx * 4,
pair_idx * 4 + 1,
pair_idx * 4 + 2,
pair_idx * 4 + 3,
)
(ca0, ca1) = pair_idx * 4 + 1, pair_idx * 4 + 2 # middle qubits
with bell_parallel.if_test((ca0, 1)):
bell_parallel.x(q3)
with bell_parallel.if_test((ca1, 1)):
bell_parallel.z(q0)
bell_parallel.id(q0) # add id here for correct alignment
bell_zz = bell_parallel.copy()
bell_zz.barrier()
bell_xx = bell_parallel.copy()
bell_xx.barrier()
for pair_idx in range(num_pairs):
(q0, q1, q2, q3) = (
pair_idx * 4,
pair_idx * 4 + 1,
pair_idx * 4 + 2,
pair_idx * 4 + 3,
)
bell_xx.h(q0)
bell_xx.h(q3)
bell_xx.barrier()
for pair_idx in range(num_pairs):
(q0, q1, q2, q3) = (
pair_idx * 4,
pair_idx * 4 + 1,
pair_idx * 4 + 2,
pair_idx * 4 + 3,
)
(c0, c1) = pair_idx * 4, pair_idx * 4 + 3 # edge qubits
bell_zz.measure(q0, c0)
bell_zz.measure(q3, c1)
bell_xx.measure(q0, c0)
bell_xx.measure(q3, c1)
bell_circuits.append(bell_zz)
bell_circuits.append(bell_xx)
return bell_circuits
def get_mse(result, initial_layouts):
"""
given a result object and the initial layouts,
returns a dict of layouts and their mse
"""
layout_mse = {}
for layout_idx, initial_layout in enumerate(initial_layouts):
layout_mse[tuple(initial_layout)] = {}
num_pairs = len(initial_layout) // 4
counts_zz = result[2 * layout_idx].data.c.get_counts()
total_shots = sum(counts_zz.values())
# Get ZZ expectation value
exp_zz_list = []
for pair_idx in range(num_pairs):
exp_zz = 0
for bitstr, shots in counts_zz.items():
bitstr = bitstr[::-1] # reverse order to big endian
b1, b0 = (
bitstr[pair_idx * 4],
bitstr[pair_idx * 4 + 3],
) # parse bitstring to get edge measurements for each 4-q chain
z_val0 = 1 if b0 == "0" else -1
z_val1 = 1 if b1 == "0" else -1
exp_zz += z_val0 * z_val1 * shots
exp_zz /= total_shots
exp_zz_list.append(exp_zz)
counts_xx = result[2 * layout_idx + 1].data.c.get_counts()
total_shots = sum(counts_xx.values())
# Get XX expectation value
exp_xx_list = []
for pair_idx in range(num_pairs):
exp_xx = 0
for bitstr, shots in counts_xx.items():
bitstr = bitstr[::-1] # reverse order to big endian
b1, b0 = (
bitstr[pair_idx * 4],
bitstr[pair_idx * 4 + 3],
) # parse bitstring to get edge measurements for each 4-q chain
x_val0 = 1 if b0 == "0" else -1
x_val1 = 1 if b1 == "0" else -1
exp_xx += x_val0 * x_val1 * shots
exp_xx /= total_shots
exp_xx_list.append(exp_xx)
mse_list = [
((exp_zz - 1) ** 2 + (exp_xx - 1) ** 2) / 2
for exp_zz, exp_xx in zip(exp_zz_list, exp_xx_list)
]
print(f"layout {initial_layout}")
for idx in range(num_pairs):
layout_mse[tuple(initial_layout)][
tuple(initial_layout[4 * idx : 4 * idx + 4])
] = mse_list[idx]
print(
f"qubits: {initial_layout[4*idx:4*idx+4]}, mse:, "
f"{round(mse_list[idx],4)}"
)
# print(f'exp_zz: {round(exp_zz_list[idx],4)},
# exp_xx: {round(exp_xx_list[idx],4)}')
print(" ")
return layout_mse
def plot_mse_ecdfs(layouts_mse, combine_layouts=False):
"""
Plot CDF of MSE data for multiple layouts.
Optionally combine all data in a single CDF
"""
if not combine_layouts:
for initial_layout, layouts in layouts_mse.items():
sorted_layouts = dict(
sorted(layouts.items(), key=lambda item: item[1])
) # sort layouts by mse
# get layouts and mses
layout_list = list(sorted_layouts.keys())
mse_list = np.asarray(list(sorted_layouts.values()))
# convert to numpy
x = np.array(mse_list)
y = np.arange(1, len(x) + 1) / len(x)
# Prepend (x[0], 0) to start CDF at zero
x = np.insert(x, 0, x[0])
y = np.insert(y, 0, 0)
# Create the plot
plt.plot(
x,
y,
marker="x",
linestyle="-",
label=f"qubits: {initial_layout}",
)
# add qubits labels for the edge pairs
for xi, yi, q in zip(x[1:], y[1:], layout_list):
plt.annotate(
[q[0], q[3]],
(xi, yi),
textcoords="offset points",
xytext=(5, -10),
ha="left",
fontsize=8,
)
elif combine_layouts:
all_layouts = {}
all_initial_layout = []
for (
initial_layout,
layouts,
) in layouts_mse.items(): # puts together all layout information
all_layouts.update(layouts)
all_initial_layout += initial_layout
sorted_layouts = dict(
sorted(all_layouts.items(), key=lambda item: item[1])
) # sort layouts by mse
# get layouts and mses
layout_list = list(sorted_layouts.keys())
mse_list = np.asarray(list(sorted_layouts.values()))
# convert to numpy
x = np.array(mse_list)
y = np.arange(1, len(x) + 1) / len(x)
# Prepend (x[0], 0) to start CDF at zero
x = np.insert(x, 0, x[0])
y = np.insert(y, 0, 0)
# Create the plot
plt.plot(
x,
y,
marker="x",
linestyle="-",
label=f"qubits: {sorted(list(set(all_initial_layout)))}",
)
# add qubit labels for the edge pairs
for xi, yi, q in zip(x[1:], y[1:], layout_list):
plt.annotate(
[q[0], q[3]],
(xi, yi),
textcoords="offset points",
xytext=(5, -10),
ha="left",
fontsize=8,
)
plt.xscale("log")
plt.xlabel("Mean squared error of ⟨ZZ⟩ and ⟨XX⟩")
plt.ylabel("Cumulative distribution function")
plt.title("CDF for different initial layouts")
plt.grid(alpha=0.3)
plt.show()Exemple de simulateur à petite échelle
Avant de lancer l'exécution sur le véritable QPU, nous vérifions que le circuit produit bien une paire de Bell en le testant sur un simulateur sans bruit avec une chaîne de quatre qubits [0, 1, 2, 3]. Nous utilisons l' IBM Quantum Sampler avec comme AerSimulator mode de backend pour exécuter les circuits.
Étape 1 : Mettre en correspondance les entrées classiques avec un problème quantique
La première étape consiste à créer un ensemble de circuits quantiques afin d'évaluer toutes les liaisons de paires de Bell candidates, adaptées à la topologie du dispositif. [0, 1, 2, 3]Nous commençons par construire de tels circuits à partir d'une chaîne de quatre qubits.
La create_bell_stab() routine effectue les opérations suivantes pour chaque chaîne :
- Préparez une paire de Bell intermédiaire : appliquez un Hadamard sur le qubit 1 et un CNOT du qubit 1 au qubit 2. Cela entremêle les qubits 1 et 2 (créant un état de Bell).
- Entrelacer les qubits périphériques : appliquer un CNOT du qubit 0 au qubit 1, et un CNOT du qubit 2 au qubit 3. Cela relie les paires initialement séparées afin que les qubits 0 et 3 deviennent intriqués après les étapes suivantes. Un Hadamard sur le qubit 2 est également appliqué (celui-ci, combiné aux CNOT précédents, fait partie d'une mesure de Bell sur les qubits 1 et 2). À ce stade, les qubits 0 et 3 ne sont pas encore intriqués, mais les qubits 1 et 2 sont intriqués avec eux dans un état plus large à quatre qubits.
- Mesures à mi-circuit et feedforward : les qubits 1 et 2 (les qubits du milieu) sont mesurés dans la base de calcul, ce qui donne deux bits classiques. Sur la base des résultats de ces mesures, nous appliquons des opérations conditionnelles : si la mesure du qubit 1 (appelons-la bit ) est 1, nous appliquons une porte sur le qubit 3; si la mesure du qubit 2 ( ) est 1, nous appliquons une porte sur le qubit 0. Ces portes conditionnelles (réalisées à l'aide de Qiskit
if_test/if_elseconstruct) mettent en œuvre les corrections de téléportation standard. Ils « annulent » les inversions aléatoires de Pauli qui se produisent en raison de la projection des qubits 1 et 2, garantissant ainsi que les qubits 0 et 3 se retrouvent dans un état de Bell connu, quels que soient les résultats des mesures. Après cette étape, les qubits 0 et 3 devraient idéalement être intriqués dans l'état de Bell . - Mesurer les stabilisateurs de la paire de cloches : Nous avons ensuite divisé le circuit en deux versions. Dans la première version, nous mesurons le stabilisateur sur les qubits 0 et 3. Dans la deuxième version, nous mesurons le stabilisateur sur ces qubits.
Pour chaque configuration initiale à quatre qubits, la fonction ci-dessus renvoie deux circuits (un pour la mesure de stabilisation de l' , et un pour celle de l' ). Ces circuits comprennent des mesures en cours d'exécution et des opérations conditionnelles (if/else), qui constituent les instructions clés du circuit dynamique.
from qiskit_aer import AerSimulator
# 4-qubit chain for simulation
sim_layout = [[0, 1, 2, 3]]
aer_backend = AerSimulator()
sim_circuits = create_bell_stab(sim_layout)
sim_circuits[1].draw("mpl", fold=-1, idle_wires=False)Output:
Étape 2 : Optimiser le problème pour l'exécution sur du matériel quantique
Avant d'exécuter nos circuits, nous devons les transcompiler en opérations de porte prises en charge par le backend spécifié. La transpilation permettra de mapper le circuit abstrait sur les qubits physiques et l'ensemble de portes du backend sélectionné. Comme nous avons déjà sélectionné des qubits physiques spécifiques pour chaque chaîne (en fournissant un initial_layout au générateur de circuits), nous utilisons le transpileur optimization_level=0 avec cette configuration fixe. Cela indique à Qiskit de ne pas réaffecter les qubits ni d'effectuer d'optimisations lourdes susceptibles de modifier la structure du circuit. Nous souhaitons conserver l'ordre des opérations (en particulier les portes conditionnelles) exactement tel qu'il a été spécifié.
pm_sim = generate_preset_pass_manager(
optimization_level=0, backend=aer_backend, initial_layout=sim_layout[0]
)
isa_sim_circuits = pm_sim.run(sim_circuits)
isa_sim_circuits[1].draw("mpl", fold=-1, idle_wires=False)Étape 3 : Exécutez à l'aide d' Qiskit primitives
Nous pouvons désormais lancer l'expérience sur le backend du simulateur sans bruit.
# Run on noiseless simulator
sampler_sim = Sampler(mode=aer_backend)
sim_job = sampler_sim.run(isa_sim_circuits)
sim_mse = get_mse(sim_job.result(), sim_layout)Output:
layout [0, 1, 2, 3]
qubits: [0, 1, 2, 3], mse:, 0.0
Étape 4 : Post-traitement et renvoi du résultat dans le format classique souhaité
La dernière étape consiste à calculer la métrique d'erreur quadratique moyenne (MSE) pour chaque groupe de qubits testé et à résumer les résultats. Pour chaque chaîne, nous avons désormais les valeurs mesurées et . Si les qubits 0 et 3 étaient parfaitement intriqués dans un état de Bell, nous nous attendrions à ce que ces deux valeurs soient égales à +1. Nous quantifions l'écart à l'aide de l'erreur quadratique moyenne (MSE) :
Cette valeur est égale à 0 pour une paire de Bell parfaite, et augmente à mesure que l'état intriqué devient plus bruité (avec des résultats aléatoires dont l'espérance est proche de 0, l'erreur quadratique moyenne tendrait vers 1). Le code calcule cette erreur quadratique moyenne (MSE) pour chaque groupe de quatre qubits. En l'absence de bruit, on constate, comme prévu, que MSE = 0 dans cet exemple de simulateur à petite échelle.
Exemple de matériel à grande échelle
Nous rassemblons ici tous ces éléments au sein d'un processus unique à plus grande échelle, qui est ensuite exécuté sur du matériel quantique réel.
service = QiskitRuntimeService()
backend = service.least_busy(operational=True)Nous parcourons par programmation la carte de couplage du dispositif à la recherche de toutes les chaînes de quatre qubits reliées de manière linéaire. Chacune de ces chaînes (identifiées par les indices de qubits ) sert de cas test pour le circuit d'échange d'intrication. En identifiant tous les chemins d' length-4 s possibles, nous garantissons une couverture maximale pour tous les groupements de qubits susceptibles de mettre en œuvre le protocole.
Nous générons ces chaînes à l'aide d'une fonction d'aide qui effectue une recherche gloutonne sur le graphe de l'appareil. Il renvoie des « bandes » de quatre chaînes de quatre qubits regroupées en groupes de 16 qubits. Le regroupement nous permet de mener plusieurs expériences à quatre qubits en parallèle sur différentes parties de la puce et d'exploiter efficacement l'ensemble du dispositif. Chaque bande de 16 qubits contient quatre chaînes disjointes, ce qui signifie qu'aucun qubit n'est réutilisé au sein de ce groupe. Par exemple, une bande peut être constituée des chaînes , , et , regroupées en un seul ensemble. Tout qubit qui n'a pas été inclus dans une bande est renvoyé dans la leftover variable.
from itertools import chain
from collections import defaultdict
def stripes16_from_backend(backend):
"""
Creates stripes of 16 qubits, four non-overlapping
four-qubit chains, that cover as much of the coupling
map as possible. Returns any unused qubits as leftovers.
"""
# get the undirected adjacency list
edges = backend.coupling_map.get_edges()
graph = defaultdict(set)
for u, v in edges:
graph[u].add(v)
graph[v].add(u)
qubits = sorted(graph) # all qubit indices that appear
# greedy search for 4-long linear chains (blocks) ────────────
used = set() # qubits already placed in a block
blocks = [] # each block is a four-qubit list
for q in qubits: # deterministic order for reproducibility
if q in used:
continue # already consumed by earlier block
# depth-first "straight" walk of length 3 without revisiting nodes
def extend(path):
if len(path) == 4:
return path
tip = path[-1]
for nbr in sorted(graph[tip]): # deterministic
if nbr not in path and nbr not in used:
maybe = extend(path + [nbr])
if maybe:
return maybe
return None
block = extend([q])
if block: # found a 4-node path
blocks.append(block)
used.update(block)
# bundle four four-qubit blocks into one 16-qubit
# stripe (max number of measurement compatible with if-else)
stripes = [
list(chain.from_iterable(blocks[i : i + 4]))
for i in range(0, len(blocks) // 4 * 4, 4) # full groups of four
]
leftovers = set(qubits) - set(chain.from_iterable(stripes))
return stripes, leftoversinitial_layouts, leftover = stripes16_from_backend(backend)Nous construisons ensuite le circuit pour chaque bande de 16 qubits à l'aide de la fonction create_bell_stab(). À l'issue de cette étape, nous disposons d'une liste de circuits couvrant toutes les chaînes de quatre qubits du dispositif. Nous compilons ensuite les circuits et les exécutons sur le backend réel, puis nous traitons les résultats.
# -------------------------Step 1-------------------------
circuits = create_bell_stab(initial_layouts)
# -------------------------Step 2-------------------------
isa_circuits = []
for ind, init_layout in enumerate(initial_layouts):
pm = generate_preset_pass_manager(
optimization_level=0, backend=backend, initial_layout=init_layout
)
isa_circ = pm.run(circuits[ind * 2 : ind * 2 + 2])
isa_circuits.extend(isa_circ)
isa_circuits[1].draw("mpl", fold=-1, idle_wires=False)
# -------------------------Step 3-------------------------
sampler = Sampler(mode=backend)
sampler.options.environment.job_tags = ["TUT_BDC"]
job = sampler.run(isa_circuits)
# -------------------------Step 4-------------------------
layouts_mse = get_mse(job.result(), initial_layouts)Output:
layout [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
qubits: [0, 1, 2, 3], mse:, 0.6302
qubits: [4, 5, 6, 7], mse:, 0.0949
qubits: [8, 9, 10, 11], mse:, 0.1729
qubits: [12, 13, 14, 15], mse:, 0.0473
layout [16, 23, 22, 21, 17, 27, 26, 25, 18, 31, 30, 29, 19, 35, 34, 33]
qubits: [16, 23, 22, 21], mse:, 0.0533
qubits: [17, 27, 26, 25], mse:, 0.2966
qubits: [18, 31, 30, 29], mse:, 0.0447
qubits: [19, 35, 34, 33], mse:, 0.0392
layout [36, 41, 42, 43, 37, 45, 46, 47, 38, 49, 50, 51, 39, 53, 54, 55]
qubits: [36, 41, 42, 43], mse:, 0.1577
qubits: [37, 45, 46, 47], mse:, 0.0705
qubits: [38, 49, 50, 51], mse:, 0.2914
qubits: [39, 53, 54, 55], mse:, 0.1711
layout [56, 63, 62, 61, 57, 67, 66, 65, 58, 71, 70, 69, 59, 75, 74, 73]
qubits: [56, 63, 62, 61], mse:, 0.1236
qubits: [57, 67, 66, 65], mse:, 0.9969
qubits: [58, 71, 70, 69], mse:, 0.0631
qubits: [59, 75, 74, 73], mse:, 0.0301
layout [76, 81, 82, 83, 77, 85, 86, 87, 78, 89, 90, 91, 79, 93, 94, 95]
qubits: [76, 81, 82, 83], mse:, 0.2787
qubits: [77, 85, 86, 87], mse:, 0.0497
qubits: [78, 89, 90, 91], mse:, 0.1271
qubits: [79, 93, 94, 95], mse:, 0.0468
layout [96, 103, 102, 101, 97, 107, 106, 105, 98, 111, 110, 109, 99, 115, 114, 113]
qubits: [96, 103, 102, 101], mse:, 0.8657
qubits: [97, 107, 106, 105], mse:, 0.0399
qubits: [98, 111, 110, 109], mse:, 0.0667
qubits: [99, 115, 114, 113], mse:, 0.2444
layout [116, 121, 122, 123, 117, 125, 126, 127, 118, 129, 130, 131, 119, 133, 134, 135]
qubits: [116, 121, 122, 123], mse:, 0.0429
qubits: [117, 125, 126, 127], mse:, 0.0487
qubits: [118, 129, 130, 131], mse:, 0.0823
qubits: [119, 133, 134, 135], mse:, 0.0583
layout [136, 143, 142, 141, 137, 147, 146, 145, 138, 151, 150, 149, 139, 155, 154, 153]
qubits: [136, 143, 142, 141], mse:, 0.0209
qubits: [137, 147, 146, 145], mse:, 0.0384
qubits: [138, 151, 150, 149], mse:, 0.4941
qubits: [139, 155, 154, 153], mse:, 0.1062
Les résultats révèlent une grande variabilité dans la qualité de l'intrication à travers le dispositif. Cela confirme les conclusions de l'article selon lesquelles la fidélité de l'état de Bell peut varier d'un ordre de grandeur selon les qubits physiques utilisés. Concrètement, cela signifie que certaines régions ou certains liens de la puce sont beaucoup plus performants que d'autres pour effectuer des mesures à mi-circuit et des opérations de feedforward. Des facteurs tels que les erreurs de lecture des qubits, leur durée de vie et la diaphonie contribuent probablement à ces différences. Par exemple, si une chaîne comprend un qubit de lecture particulièrement bruyant, la mesure à mi-circuit pourrait être peu fiable, ce qui entraînerait une mauvaise fidélité pour cette paire intriquée (MSE élevé).
Enfin, nous visualisons la performance globale en traçant la fonction de distribution cumulative (CDF) des valeurs MSE pour toutes les chaînes. Le graphique CDF montre le seuil MSE sur l'axe des x et la fraction de paires de qubits qui ont au plus ce MSE sur l'axe des y. Cette courbe commence à zéro et tend vers un à mesure que le seuil augmente pour englober tous les points de données. Une forte augmentation près d'une faible MSE indiquerait que de nombreuses paires sont très fidèles; une augmentation lente signifie que de nombreuses paires présentent des erreurs plus importantes. Nous annotons le CDF avec les identités des meilleures paires. Dans le graphique, chaque point de la CDF correspond à l'erreur quadratique moyenne (MSE) d'une chaîne de quatre qubits, et nous étiquetons le point avec la paire d'indices de qubits qui ont été intriqués dans cette expérience. Cela permet de repérer facilement les paires de qubits physiques les plus performantes (les points situés à l'extrême gauche de la CDF).
plot_mse_ecdfs(layouts_mse, combine_layouts=True)Output:
Etapes suivantes
Si ce travail vous a paru intéressant, les ressources suivantes pourraient vous intéresser :
- Découvrez comment mettre en œuvre l'intrication à longue distance à l'aide de circuits dynamiques
- Découvrez comment simuler l 'hamiltonien d'Ising « kicked » à l'aide de circuits dynamiques