Circuiti dinamici di riferimento con coppie Bell tagliate
Stima di utilizzo: 22 secondi su un processore r2 Heron (NOTA: si tratta solo di una stima). Il tempo di esecuzione può variare.)
Risultati di apprendimento
Dopo aver seguito questo tutorial, gli utenti dovrebbero aver compreso:
- Come realizzare circuiti dinamici con misurazioni a metà percorso e feedforward classico per teletrasportare l'entanglement tra qubit distanti;
- Come calcolare e interpretare la metrica di errore per quantificare la fedeltà della coppia di Bell su un dispositivo;
- Come individuare, sulla base dei risultati dei test di benchmark, quali coppie di qubit sono più adatte alle operazioni basate sul LOCC.
Prerequisiti
Consigliamo agli utenti di acquisire familiarità con i seguenti argomenti prima di seguire questo tutorial:
- Concetti fondamentali dell'informatica quantistica, tra cui gli stati di Bell, l'entanglement e i gate quantistici;
- Conoscenza dei circuiti dinamici ( misure a metà circuito e feedforward classico);
- Conoscenze di base di Qiskit SDK e del servizio IBM Quantum® Compute Service, nonché accesso a un account IBM Quantum.
Sfondo
L'hardware quantistico è tipicamente limitato alle interazioni locali, ma molti algoritmi richiedono l'entanglement di qubit distanti o addirittura di qubit su processori separati. I circuiti dinamici, ovvero circuiti con misurazione a metà circuito e feedforward, consentono di superare tali limitazioni utilizzando la comunicazione classica in tempo reale per implementare in modo efficace operazioni quantistiche non locali. In questo approccio, i risultati delle misurazioni effettuate su una parte di un circuito (o su una QPU) possono attivare in modo condizionale i gate su un'altra parte, consentendoci di teletrasportare l'entanglement su lunghe distanze. Questo costituisce la base dei sistemi LOCC (Local Operations and Classical Communication), in cui utilizziamo stati di risorse intrecciate (coppie di Bell) e comunichiamo i risultati delle misurazioni in modo classico per collegare qubit distanti.
Un utilizzo promettente del LOCC è quello di realizzare porte CNOT virtuali a lungo raggio tramite teletrasporto, come mostrato nel tutorial sull'entanglement a lungo raggio. Invece di un CNOT diretto a lungo raggio (che la connettività hardware potrebbe non consentire), creiamo coppie di Bell ed eseguiamo un'implementazione del gate basata sul teletrasporto. Tuttavia, la fedeltà di tali operazioni dipende dalle caratteristiche dell'hardware. La decoerenza dei qubit durante il ritardo necessario (in attesa dei risultati delle misurazioni) e la latenza della comunicazione classica possono degradare lo stato di entanglement. Inoltre, gli errori nelle misurazioni intermedie del circuito sono più difficili da correggere rispetto agli errori nelle misurazioni finali, poiché si propagano al resto del circuito attraverso i gate condizionali.
Nell'esperimento di riferimento, gli autori introducono un parametro di riferimento della fedeltà della coppia di Bell per individuare quali parti di un dispositivo siano più adatte all'entanglement basato sulla tecnologia LOCC. L'idea è quella di far funzionare un piccolo circuito dinamico su ogni gruppo di quattro qubit collegati nel processore. Questo circuito a quattro qubit crea innanzitutto una coppia di Bell sui due qubit centrali, quindi li utilizza come risorsa per intrecciare i due qubit periferici tramite LOCC. In pratica, i qubit 1 e 2 vengono preparati localmente in una coppia di Bell non tagliata (una coppia di Bell creata direttamente con un Hadamard e un CNOT, senza teletrasporto), dopodiché una procedura di teletrasporto utilizza quella coppia di Bell per intrecciare i qubit 0 e 3. I qubit 1 e 2 vengono misurati durante l'esecuzione del circuito e, in base a tali risultati, vengono applicate le correzioni di Pauli (una X sul qubit 3 e una Z sul qubit 0). I qubit 0 e 3 rimangono quindi in uno stato di Bell alla fine del circuito.
Per quantificare la qualità di questa coppia intrecciata finale, misuriamo i suoi stabilizzatori: in particolare, la parità nella base ( ) e nella base ( ). Per una coppia di Bell perfetta, entrambe queste aspettative sono pari a +1. In pratica, il rumore dell'hardware ridurrà questi valori. Ripetiamo quindi il circuito due volte per ogni coppia di qubit: un circuito misura i qubit 0 e 3 nella base, mentre un altro li misura nella base. Dai risultati otteniamo una stima di e per quella coppia di qubit. Utilizziamo l'errore quadratico medio (MSE) di questi stabilizzatori rispetto al valore ideale (1) come semplice metrica della fedeltà dell'entanglement. Un MSE più basso significa che i due qubit hanno raggiunto uno stato di Bell più vicino all'ideale (maggiore fedeltà), mentre un MSE più alto indica un errore maggiore. Eseguendo la scansione di questo esperimento sul dispositivo, possiamo valutare le capacità di misurazione e feedforward di diversi gruppi di qubit e identificare le migliori coppie di qubit per le operazioni LOCC.
Questo tutorial illustra l'esperimento condotto su un dispositivo IBM Quantum® per mostrare come i circuiti dinamici possano essere utilizzati per generare e valutare l'entanglement tra qubit distanti. Mapperemo tutte le catene lineari a quattro qubit presenti sul dispositivo, eseguiremo il circuito di teletrasporto su ciascuna di esse e infine visualizzeremo la distribuzione dei valori di MSE. Questa procedura completa illustra come sfruttare le funzionalità del servizio di calcolo quantistico " IBM Quantum " e dei circuiti dinamici per orientare le scelte relative all'hardware, al fine di ridurre i circuiti o distribuire algoritmi quantistici all'interno di un sistema modulare.
Requisiti
Prima di iniziare questo tutorial, assicurati di avere installato quanto segue:
- Qiskit SDK v2.0 o versioni successive, con supporto alla visualizzazione
- v0.40Qiskit Runtime o successivamente (
pip install qiskit-ibm-runtime) - Qiskit Aer v0.17 o versioni successive (
pip install qiskit-aer)
Configura
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()Esempio di simulatore su piccola scala
Prima di eseguire il codice sulla QPU reale, verifichiamo che il circuito produca una coppia di Bell testandolo su un simulatore privo di rumore con una catena di quattro qubit [0, 1, 2, 3]. Utilizziamo l' IBM Quantum Sampler con come AerSimulator modalità di backend per l'esecuzione dei circuiti.
Fase 1: mappare gli input classici su un problema quantistico
Il primo passo consiste nel creare una serie di circuiti quantistici per valutare tutte le possibili connessioni di coppie di Bell, adattate alla topologia del dispositivo. [0, 1, 2, 3]Iniziamo realizzando tali circuiti con una catena di quattro qubit.
La create_bell_stab() routine esegue le seguenti operazioni per ogni catena:
- Prepara una coppia Bell centrale: applica un Hadamard sul qubit 1 e un CNOT dal qubit 1 al qubit 2. Questo intreccia i qubit 1 e 2 (creando uno stato di Bell).
- Intreccia i qubit periferici: applica un CNOT dal qubit 0 al qubit 1 e un CNOT dal qubit 2 al qubit 3. Questo collega le coppie inizialmente separate in modo che i qubit 0 e 3 diventino intrecciati dopo i passaggi successivi. Viene applicato anche un Hadamard sul qubit 2 (questo, combinato con i precedenti CNOT, costituisce parte di una misurazione di Bell sui qubit 1 e 2). A questo punto, i qubit 0 e 3 non sono ancora intrecciati, ma i qubit 1 e 2 sono intrecciati con essi in uno stato più ampio a quattro qubit.
- Misurazioni a metà circuito e feedforward: i qubit 1 e 2 (i qubit centrali) vengono misurati nella base computazionale, producendo due bit classici. Sulla base dei risultati di tali misurazioni, applichiamo operazioni condizionali: se la misurazione del qubit 1 (chiamiamola bit ) è 1, applichiamo un gate sul qubit 3; se la misurazione del qubit 2 ( ) è 1, applichiamo un gate sul qubit 0. Questi gate condizionali (realizzati utilizzando il Qiskit
if_test/if_elseconstruct) implementano le correzioni standard del teletrasporto. Essi "annullano" i ribaltamenti casuali di Pauli che si verificano a causa della proiezione dei qubit 1 e 2, assicurando che i qubit 0 e 3 finiscano in uno stato di Bell noto, indipendentemente dai risultati della misurazione. Dopo questo passaggio, i qubit 0 e 3 dovrebbero idealmente essere intrecciati nello stato di Bell . - Misurare gli stabilizzatori della coppia di campane: Abbiamo quindi suddiviso il circuito in due versioni. Nella prima versione, misuriamo lo stabilizzatore sui qubit 0 e 3. Nella seconda versione, misuriamo lo stabilizzatore su questi qubit.
Per ogni configurazione iniziale a quattro qubit, la funzione sopra riportata restituisce due circuiti (uno per la misurazion e e uno per la misurazione stabilizzatrice ). Questi circuiti includono misurazioni a metà circuito e operazioni condizionali (if/else), che costituiscono le istruzioni fondamentali del circuito dinamico.
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:
Fase 2: Ottimizzare il problema per l'esecuzione su hardware quantistico
Prima di eseguire i nostri circuiti, dobbiamo traspilarli in operazioni a livello di porta supportate dal backend specificato. La transpilazione mapperà il circuito astratto sui qubit fisici e sull'insieme di porte del backend selezionato. Poiché abbiamo già scelto qubit fisici specifici per ciascuna catena (specificando un initial_layout nel generatore di circuiti), utilizziamo il transpiler optimization_level=0 con quella configurazione fissa. Questo indica a Qiskit di non riassegnare i qubit né di eseguire ottimizzazioni complesse che potrebbero alterare la struttura del circuito. Vogliamo mantenere la sequenza delle operazioni (in particolare i gate condizionali) esattamente come specificato.
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)Passaggio 3: eseguire utilizzando Qiskit primitives
Ora possiamo eseguire l'esperimento sul backend del simulatore senza rumore.
# 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
Fase 4: Post-elaborazione e restituzione del risultato nel formato classico desiderato
Il passo finale consiste nel calcolare la metrica dell'errore quadratico medio (MSE) per ciascun gruppo di qubit testato e riassumere i risultati. Per ogni catena, ora abbiamo i valori misurati e . Se i qubit 0 e 3 fossero perfettamente intrecciati in uno stato di Bell, ci aspetteremmo che entrambi fossero +1. Quantifichiamo la deviazione utilizzando l'MSE:
Questo valore è pari a 0 per una coppia di Bell perfetta e aumenta man mano che lo stato intrecciato diventa più rumoroso (con risultati casuali che danno un valore atteso intorno a 0, l'errore quadratico medio si avvicinerebbe a 1). Il codice calcola questo MSE per ciascun gruppo di quattro qubit. In assenza di rumore, in questo esempio di simulatore su piccola scala osserviamo che MSE = 0, come previsto.
Esempio di hardware su larga scala
A questo punto riuniamo tutti questi dettagli in un unico flusso di lavoro su scala più ampia, che viene poi eseguito su hardware quantistico reale.
service = QiskitRuntimeService()
backend = service.least_busy(operational=True)Effettuiamo una ricerca automatica nella mappa di accoppiamento del dispositivo per individuare tutte le catene di quattro qubit collegate linearmente. Ciascuna di queste catene (contrassegnata dagli indici dei qubit ) funge da caso di prova per il circuito di scambio di entanglement. Identificando tutti i possibili percorsi di length-4, garantiamo la massima copertura per i possibili raggruppamenti di qubit in grado di attuare il protocollo.
Generiamo queste catene utilizzando una funzione di supporto che esegue una ricerca avida sul grafico dei dispositivi. Restituisce "strisce" di quattro catene da quattro qubit raggruppate in gruppi da 16 qubit. Il bundling ci permette di eseguire più esperimenti a quattro qubit in parallelo su parti distinte del chip e di sfruttare in modo efficiente l'intero dispositivo. Ogni striscia da 16 qubit contiene quattro catene disgiunte, il che significa che nessun qubit viene riutilizzato all'interno di quel gruppo. Ad esempio, una striscia potrebbe essere costituita dalle catene , , e , tutte raggruppate insieme. Qualsiasi qubit che non sia stato incluso in una striscia viene restituito nella leftover variabile.
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)Successivamente, costruiamo il circuito per ciascuna striscia da 16 qubit utilizzando la funzione create_bell_stab(). Al termine di questa fase, disponiamo di un elenco di circuiti che coprono tutte le catene a quattro qubit presenti sul dispositivo. Successivamente, trasponiamo ed eseguiamo i circuiti sul backend reale, quindi elaboriamo i risultati.
# -------------------------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
I risultati rivelano un'ampia gamma di qualità di entanglement in tutto il dispositivo. Ciò conferma la conclusione dell'articolo secondo cui può esserci una variazione di oltre un ordine di grandezza nella fedeltà dello stato di Bell a seconda dei qubit fisici utilizzati. In termini pratici, ciò significa che alcune regioni o collegamenti del chip sono molto più efficaci di altri nell'eseguire misurazioni a metà circuito e operazioni di feedforward. Fattori quali errori di lettura dei qubit, durata dei qubit e crosstalk contribuiscono probabilmente a queste differenze. Ad esempio, se una catena include un qubit di lettura particolarmente rumoroso, la misurazione a metà circuito potrebbe essere inaffidabile, portando a una scarsa fedeltà per quella coppia intrecciata (MSE elevato).
Infine, visualizziamo le prestazioni complessive tracciando la funzione di distribuzione cumulativa (CDF) dei valori MSE per tutte le catene. Il grafico CDF mostra la soglia MSE sull'asse x e la frazione di coppie di qubit che hanno al massimo quell'MSE sull'asse y. Questa curva parte da zero e si avvicina a uno man mano che la soglia cresce fino a comprendere tutti i punti dati. Un aumento ripido vicino a un MSE basso indicherebbe che molte coppie sono ad alta fedeltà; un aumento lento significa che molte coppie presentano errori più grandi. Annotiamo il CDF con le identità delle coppie migliori. Nel grafico, ogni punto nella CDF corrisponde all'MSE di una catena di quattro qubit e contrassegniamo il punto con la coppia di indici di qubit che erano intrecciati in quell'esperimento. Questo rende facile individuare quali coppie di qubit fisici sono quelle con le prestazioni migliori (i punti all'estrema sinistra della CDF).
plot_mse_ecdfs(layouts_mse, combine_layouts=True)Output:
Passi successivi
Se questo lavoro ti è sembrato interessante, potrebbero interessarti anche i seguenti materiali:
- Scopri come implementare l'entanglement a lunga distanza con circuiti dinamici
- Scopri come simulare l 'Hamiltoniano di Ising con kickback utilizzando circuiti dinamici