Circuitos dinámicos de referencia con pares Bell cortados
Estimación de uso: 22 segundos en un procesador r2 Heron (NOTA: Esto es solo una estimación). El tiempo de ejecución puede variar.
Resultados del aprendizaje
Una vez completado este tutorial, los usuarios deberían comprender:
- Cómo construir circuitos dinámicos con mediciones intermedias y alimentación directa clásica para teletransportar el entrelazamiento entre qubits distantes;
- Cómo calcular e interpretar la métrica de error para cuantificar la fidelidad del par de Bell en un dispositivo;
- Cómo determinar qué pares de qubits son los más adecuados para operaciones basadas en LOCC a partir de los resultados de las pruebas comparativas.
Requisitos previos
Recomendamos a los usuarios que se familiaricen con los siguientes temas antes de seguir este tutorial:
- Conceptos básicos de la computación cuántica, incluidos los estados de Bell, el entrelazamiento y las puertas cuánticas;
- Conocimiento de los circuitos dinámicos ( mediciones en el punto medio del circuito y control clásico por anticipación);
- Conocimientos básicos de Qiskit SDK y Qiskit Runtime, así como acceso a una cuenta de IBM Quantum®.
En segundo plano
El hardware cuántico suele limitarse a interacciones locales, pero muchos algoritmos requieren entrelazar qubits distantes o incluso qubits en procesadores separados. Los circuitos dinámicos, es decir, los circuitos con medición en medio del circuito y alimentación directa, proporcionan una forma de superar estas limitaciones mediante el uso de la comunicación clásica en tiempo real para implementar de manera eficaz operaciones cuánticas no locales. En este enfoque, los resultados de las mediciones de una parte de un circuito (o una QPU) pueden activar condicionalmente puertas en otra, lo que nos permite teletransportar el entrelazamiento a largas distancias. Esto constituye la base de los esquemas de operaciones locales y comunicación clásica (LOCC), en los que consumimos estados de recursos entrelazados (pares de Bell) y comunicamos los resultados de las mediciones de forma clásica para conectar qubits distantes.
Un uso prometedor de LOCC es la realización de puertas CNOT virtuales de largo alcance mediante teletransportación, como se muestra en el tutorial sobre entrelazamiento de largo alcance. En lugar de un CNOT directo de largo alcance (que la conectividad del hardware podría no permitir), creamos pares de Bell y realizamos una implementación de puerta basada en teletransportación. Sin embargo, la fidelidad de estas operaciones depende de las características del hardware. La decoherencia de los qubits durante el retraso necesario (mientras se esperan los resultados de la medición) y la latencia de la comunicación clásica pueden degradar el estado entrelazado. Además, los errores en las mediciones intermedias del circuito son más difíciles de corregir que los errores en las mediciones finales, ya que se propagan al resto del circuito a través de las puertas condicionales.
En el experimento de referencia, los autores introducen un criterio de referencia de fidelidad del par de Bell para identificar qué partes de un dispositivo son las más adecuadas para el entrelazamiento basado en LOCC. La idea consiste en ejecutar un pequeño circuito dinámico en cada grupo de cuatro qubits conectados del procesador. Este circuito de cuatro qubits crea primero un par de Bell en los dos qubits centrales y, a continuación, utiliza este par como recurso para entrelazar los dos qubits de los extremos mediante LOCC. En concreto, los qubits 1 y 2 se preparan localmente en un par de Bell sin cortar (un par de Bell creado directamente mediante un Hadamard y un CNOT, sin teletransporte), y a continuación una rutina de teletransporte consume ese par de Bell para entrelazar los qubits 0 y 3. Los qubits 1 y 2 se miden durante la ejecución del circuito y, en función de los resultados obtenidos, se aplican correcciones de Pauli (una X en el qubit 3 y una Z en el qubit 0). Los qubits 0 y 3 quedan entonces en un estado de Bell al final del circuito.
Para cuantificar la calidad de este par entrelazado final, medimos sus estabilizadores: concretamente, la paridad en la base ( ) y en la base ( ). Para un par Bell perfecto, ambas expectativas son iguales a +1. En la práctica, el ruido del hardware reducirá estos valores. Por lo tanto, repetimos el circuito dos veces para cada par de qubits: un circuito mide los qubits 0 y 3 en la base, y otro los mide en la base. A partir de los resultados, obtenemos una estimación de y para ese par de qubits. Utilizamos el error cuadrático medio (MSE) de estos estabilizadores con respecto al valor ideal (1) como una métrica simple de la fidelidad del entrelazamiento. Un MSE más bajo significa que los dos qubits alcanzaron un estado de Bell más cercano al ideal (mayor fidelidad), mientras que un MSE más alto indica más errores. Al escanear este experimento en todo el dispositivo, podemos comparar la capacidad de medición y alimentación directa de diferentes grupos de qubits e identificar los mejores pares de qubits para operaciones LOCC.
Este tutorial muestra el experimento en un IBM Quantum® dispositivo para ilustrar cómo se pueden utilizar los circuitos dinámicos para generar y evaluar el entrelazamiento entre qubits distantes. Trazaremos todas las cadenas lineales de cuatro qubits en el dispositivo, ejecutaremos el circuito de teletransportación en cada una de ellas y, a continuación, visualizaremos la distribución de los valores MSE. Este procedimiento integral muestra cómo aprovechar Qiskit Runtime y las características de los circuitos dinámicos para tomar decisiones informadas sobre el hardware a la hora de cortar circuitos o distribuir algoritmos cuánticos en un sistema modular.
Requisitos
Antes de comenzar este tutorial, asegúrate de tener instalado lo siguiente:
- Qiskit SDK v2.0 o posterior, con soporte de visualización
- v0.40Qiskit Runtime o posterior (
pip install qiskit-ibm-runtime) - Qiskit Aer v0.17 o posterior (
pip install qiskit-aer)
Configuración
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()Ejemplo de simulador a pequeña escala
[0, 1, 2, 3]Antes de ejecutarlo en la QPU real, verificamos que el circuito genera un par de Bell probándolo en un simulador sin ruido con una cadena de cuatro qubits. Utilizamos el Qiskit RuntimeSampler con AerSimulator como modo de backend para ejecutar los circuitos.
Paso 1: Asignar entradas clásicas a un problema cuántico
El primer paso consiste en crear un conjunto de circuitos cuánticos para evaluar todos los enlaces de pares de Bell candidatos, adaptados a la topología del dispositivo. [0, 1, 2, 3]Comenzamos construyendo circuitos de este tipo con una cadena de cuatro qubits.
La create_bell_stab() rutina realiza lo siguiente para cada cadena:
- Prepare un par Bell medio: aplique un Hadamard al qubit 1 y un CNOT del qubit 1 al qubit 2. Esto entrelaza los qubits 1 y 2 (creando un estado de Bell).
- Entrelazar los qubits del borde: aplicar un CNOT del qubit 0 al qubit 1 y un CNOT del qubit 2 al qubit 3. Esto enlaza los pares inicialmente separados, de modo que los qubits 0 y 3 quedarán entrelazados tras los siguientes pasos. También se aplica un Hadamard al qubit 2 (esto, combinado con los CNOT anteriores, forma parte de una medición de Bell en los qubits 1 y 2). En este punto, los qubits 0 y 3 aún no están entrelazados, pero los qubits 1 y 2 están entrelazados con ellos en un estado más amplio de cuatro qubits.
- Mediciones a mitad del circuito y alimentación directa: los qubits 1 y 2 (los qubits centrales) se miden en la base computacional, lo que da como resultado dos bits clásicos. Basándonos en los resultados de esas mediciones, aplicamos operaciones condicionales: si la medición del qubit 1 (llamemos a este bit ) es 1, aplicamos una puerta al qubit 3; si la medición del qubit 2 ( ) es 1, aplicamos una puerta al qubit 0. Estas puertas condicionales (realizadas mediante el uso de Qiskit
if_test/if_elseconstruct) implementan las correcciones estándar de teletransporte. «Deshacen» los cambios aleatorios de Pauli que se producen debido a la proyección de los qubits 1 y 2, asegurando que los qubits 0 y 3 terminen en un estado Bell conocido, independientemente de los resultados de la medición. Después de este paso, lo ideal sería que los qubits 0 y 3 estuvieran entrelazados en el estado de Bell . - Medir los estabilizadores del par de campanas: A continuación, dividimos el circuito en dos versiones. En la primera versión, medimos el estabilizador en los qubits 0 y 3. En la segunda versión, medimos el estabilizador en estos qubits.
Para cada configuración inicial de cuatro qubits, la función anterior devuelve dos circuitos (uno para la medición del estabilizador « » y otro para la medición del estabilizador « »). Estos circuitos incluyen mediciones a mitad del circuito y operaciones condicionales (if/else), que constituyen las instrucciones clave del circuito dinámico.
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:
Paso 2: Optimizar el problema para la ejecución en hardware cuántico
Antes de ejecutar nuestros circuitos, debemos transpilarlos a operaciones de puerta compatibles con el backend especificado. La transpilación asignará el circuito abstracto a los qubits físicos y al conjunto de puertas del backend seleccionado. Dado que ya hemos seleccionado qubits físicos específicos para cada cadena (al proporcionar un initial_layout al generador de circuitos), utilizamos el transpilador optimization_level=0 con esa disposición fija. Esto indica a Qiskit que no reasigne los qubits ni realice optimizaciones complejas que puedan alterar la estructura del circuito. Queremos mantener la secuencia de operaciones (especialmente las puertas condicionales) exactamente tal y como se ha especificado.
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)Paso 3: Ejecutar utilizando Qiskit primitives
Ahora podemos ejecutar el experimento en el backend del simulador sin ruido.
# 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
Paso 4: Posprocesar y devolver el resultado en el formato clásico deseado
El último paso consiste en calcular la métrica del error cuadrático medio (MSE) para cada grupo de qubits probado y resumir los resultados. Para cada cadena, ahora tenemos los valores medidos y . Si los qubits 0 y 3 estuvieran perfectamente entrelazados en un estado de Bell, esperaríamos que ambos fueran +1. Cuantificamos la desviación utilizando el MSE:
Este valor es 0 para un par de Bell perfecto, y aumenta a medida que el estado entrelazado se vuelve más ruidoso (con resultados aleatorios que dan una esperanza en torno a 0, el MSE se acercaría a 1). El código calcula este error cuadrático medio (MSE) para cada grupo de cuatro qubits. Sin ruido, observamos que MSE = 0 en este ejemplo de simulador a pequeña escala, tal y como se esperaba.
Ejemplo de hardware a gran escala
Aquí reunimos ahora todos estos detalles en un único flujo de trabajo a mayor escala, que luego se ejecuta en hardware cuántico real.
service = QiskitRuntimeService()
backend = service.least_busy(operational=True)Buscamos mediante programación en el mapa de acoplamientos del dispositivo todas las cadenas de cuatro qubits conectadas linealmente. Cada una de estas cadenas (identificadas por los índices de qubits ) sirve como caso de prueba para el circuito de intercambio de entrelazamiento. Al identificar todas las rutas posibles de « length-4 », garantizamos la máxima cobertura para las posibles agrupaciones de qubits que podrían llevar a cabo el protocolo.
Generamos estas cadenas utilizando una función auxiliar que realiza una búsqueda glotona en el grafo de dispositivos. Devuelve «franjas» de cuatro cadenas de cuatro qubits agrupadas en conjuntos de 16 qubits. La agrupación nos permite realizar varios experimentos de cuatro qubits en paralelo en distintas partes del chip y aprovechar de forma eficiente todo el dispositivo. Cada banda de 16 qubits contiene cuatro cadenas disjuntas, lo que significa que ningún qubit se reutiliza dentro de ese grupo. Por ejemplo, una franja podría estar formada por las cadenas , , y , todas agrupadas. Cualquier qubit que no se haya incluido en una banda se devuelve en 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)A continuación, construimos el circuito para cada banda de 16 qubits utilizando la función create_bell_stab(). Al finalizar este paso, disponemos de una lista de circuitos que abarca todas las cadenas de cuatro qubits del dispositivo. A continuación, compilamos y ejecutamos los circuitos en el backend real y procesamos los resultados.
# -------------------------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
Los resultados revelan una amplia gama de calidad de entrelazamiento en todo el dispositivo. Esto confirma la conclusión del artículo de que puede haber una variación de más de un orden de magnitud en la fidelidad del estado de Bell dependiendo de los qubits físicos que se utilicen. En términos prácticos, esto significa que ciertas regiones o enlaces del chip son mucho más eficaces que otros a la hora de realizar mediciones a mitad del circuito y operaciones de alimentación directa. Factores como el error de lectura de qubits, la vida útil de los qubits y la diafonía probablemente contribuyen a estas diferencias. Por ejemplo, si una cadena incluye un qubit de lectura particularmente ruidoso, la medición a mitad del circuito podría ser poco fiable, lo que daría lugar a una fidelidad deficiente para ese par entrelazado (alto MSE).
Por último, visualizamos el rendimiento general trazando la función de distribución acumulativa (CDF) de los valores MSE para todas las cadenas. El gráfico CDF muestra el umbral MSE en el eje x y la fracción de pares de qubits que tienen como máximo ese MSE en el eje y. Esta curva comienza en cero y se aproxima a uno a medida que el umbral crece hasta abarcar todos los puntos de datos. Un aumento pronunciado cerca de un MSE bajo indicaría que muchos pares son de alta fidelidad; un aumento lento significa que muchos pares tienen errores mayores. Anotamos el CDF con las identidades de los mejores pares. En el gráfico, cada punto de la CDF corresponde al MSE de una cadena de cuatro qubits, y etiquetamos el punto con el par de índices de qubits que se entrelazaron en ese experimento. Esto facilita la identificación de los pares de qubits físicos con mejor rendimiento (los puntos situados en el extremo izquierdo de la CDF).
plot_mse_ecdfs(layouts_mse, combine_layouts=True)Output:
Próximos pasos
Si te ha parecido interesante este trabajo, quizá te interesen los siguientes materiales:
- Descubre cómo implementar el entrelazamiento a larga distancia con circuitos dinámicos
- Aprende a simular el hamiltoniano de Ising «kicked» con circuitos dinámicos