Benchmarkează circuite dinamice cu perechi Bell tăiate
Estimare utilizare: 22 de secunde pe un procesor Heron r2 (NOTĂ: Aceasta este doar o estimare. Timpul tău de rulare poate varia.)
Context
Hardware-ul cuantic este de obicei limitat la interacțiuni locale, dar mulți algoritmi necesită împletirea unor Qubiți aflați la distanță sau chiar a Qubiților de pe procesoare separate. Circuitele dinamice — adică circuitele cu măsurători la mijlocul circuitului și feedforward — oferă o metodă de a depăși aceste limitări prin utilizarea comunicării clasice în timp real, pentru a implementa efectiv operații cuantice non-locale. În această abordare, rezultatele măsurătorilor dintr-o parte a circuitului (sau de pe un QPU) pot declanșa condiționat porți pe altul, permițându-ne să teleportăm împletirea pe distanțe mari. Aceasta stă la baza schemelor de operații locale și comunicare clasică (LOCC), unde consumăm stări resursă împletite (perechi Bell) și comunicăm clasic rezultatele măsurătorilor pentru a conecta Qubiți aflați la distanță.
O utilizare promițătoare a LOCC este realizarea porților CNOT virtuale pe distanță lungă prin teleportare, așa cum este prezentat în tutorialul de împletire pe distanță lungă. În loc de un CNOT direct pe distanță lungă (pe care conectivitatea hardware-ului s-ar putea să nu o permită), creăm perechi Bell și realizăm o implementare a porții bazată pe teleportare. Totuși, fidelitatea unor astfel de operații depinde de caracteristicile hardware-ului. Decoerența Qubitului în timpul întârzierii necesare (în timp ce se așteaptă rezultatele măsurătorilor) și latența comunicării clasice pot degrada starea împletită. De asemenea, erorile la măsurătorile la mijlocul circuitului sunt mai greu de corectat decât erorile la măsurătorile finale, deoarece se propagă în restul circuitului prin porțile condiționale.
În experimentul de referință, autorii introduc un benchmark de fidelitate a perechii Bell pentru a identifica care părți ale unui dispozitiv sunt cel mai potrivite pentru împletirea bazată pe LOCC. Ideea este de a rula un mic circuit dinamic pe fiecare grup de patru Qubiți conectați din procesor. Acest circuit de patru Qubiți creează mai întâi o pereche Bell pe doi Qubiți din mijloc, apoi îi folosește ca resursă pentru a împleti cei doi Qubiți de la margine, utilizând LOCC. Concret, Qubiții 1 și 2 sunt pregătiți într-o pereche Bell netăiată local (utilizând un Hadamard și CNOT), iar apoi o rutină de teleportare consumă acea pereche Bell pentru a împleti Qubiții 0 și 3. Qubiții 1 și 2 sunt măsurați în timpul execuției circuitului, iar pe baza acelor rezultate, se aplică corecții Pauli (un X pe Qubitul 3 și Z pe Qubitul 0). Qubiții 0 și 3 sunt lăsați astfel într-o stare Bell la finalul circuitului.
Pentru a cuantifica calitatea acestei perechi finale împletite, măsurăm stabilizatorii săi: mai precis, paritatea în baza () și în baza (). Pentru o pereche Bell perfectă, ambele așteptări sunt egale cu +1. În practică, zgomotul hardware-ului va reduce aceste valori. Prin urmare, repetăm circuitul de două ori pentru fiecare pereche de Qubiți: un circuit măsoară Qubiții 0 și 3 în baza , iar altul îi măsoară în baza . Din rezultate, obținem o estimare a și pentru acea pereche de Qubiți. Folosim eroarea medie pătratică (MSE) a acestor stabilizatori față de valoarea ideală (1) ca o metrică simplă a fidelității de împletire. Un MSE mai mic înseamnă că cei doi Qubiți au atins o stare Bell mai apropiată de ideal (fidelitate mai mare), în timp ce un MSE mai mare indică mai multe erori. Prin scanarea acestui experiment pe dispozitiv, putem benchmarka capacitatea de măsurare și feedforward a diferitelor grupuri de Qubiți și identifica cele mai bune perechi de Qubiți pentru operațiile LOCC.
Acest tutorial demonstrează experimentul pe un dispozitiv IBM Quantum® pentru a ilustra cum pot fi utilizate circuitele dinamice pentru a genera și evalua împletirea între Qubiți aflați la distanță. Vom cartografia toate lanțurile liniare de patru Qubiți de pe dispozitiv, vom rula circuitul de teleportare pe fiecare și vom vizualiza distribuția valorilor MSE. Această procedură end-to-end arată cum se poate folosi Qiskit Runtime și funcțiile circuitelor dinamice pentru a informa alegerile conștiente de hardware la tăierea circuitelor sau distribuirea algoritmilor cuantici pe un sistem modular.
Cerințe
Înainte de a începe acest tutorial, asigură-te că ai instalat următoarele:
- Qiskit SDK v2.0 sau versiune ulterioară, cu suport de vizualizare
- Qiskit Runtime v0.40 sau versiune ulterioară (
pip install qiskit-ibm-runtime)
Configurare
# Added by doQumentation — required packages for this notebook
!pip install -q matplotlib numpy qiskit qiskit-ibm-runtime
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
), f"The length of the chain must be a multiple of 4, 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:, {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()
Pasul 1: Maparea intrărilor clasice la o problemă cuantică
Primul pas este să creezi un set de circuite cuantice pentru a evalua toate legăturile candidate de perechi Bell, adaptate topologiei dispozitivului. Căutăm programatic în harta de cuplare a dispozitivului toate lanțurile de patru Qubiți conectați liniar. Fiecare astfel de lanț (etichetat prin indicii Qubiților ) servește drept caz de test pentru circuitul de schimb de entanglement. Identificând toate căile de lungime 4 posibile, asigurăm acoperirea maximă pentru posibilele grupări de Qubiți care ar putea implementa protocolul.
service = QiskitRuntimeService()
backend = service.least_busy(operational=True)
Generăm aceste lanțuri folosind o funcție auxiliară care efectuează o căutare greedy pe graful dispozitivului. Ea returnează „dungi" de patru lanțuri de câte patru Qubiți, grupate în grupuri de 16 Qubiți (circuitele dinamice limitează momentan dimensiunea registrului de măsurare la 16 Qubiți). Gruparea ne permite să rulăm mai multe experimente de câte patru Qubiți în paralel pe porțiuni distincte ale cipului și să utilizăm eficient întregul dispozitiv. Fiecare dungă de 16 Qubiți conține patru lanțuri disjuncte, ceea ce înseamnă că niciun Qubit nu este reutilizat în cadrul acelui grup. De exemplu, o dungă ar putea consta din lanțurile , , și toate împachetate împreună. Orice Qubit care nu a fost inclus într-o dungă este returnat în variabila leftover.
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, leftovers
initial_layouts, leftover = stripes16_from_backend(backend)
Apoi, construim circuitul pentru fiecare dungă de 16 Qubiți. Rutina face următoarele pentru fiecare lanț:
- Pregătirea unei perechi Bell de mijloc: Aplică un Hadamard pe Qubitul 1 și un CNOT de la Qubitul 1 la Qubitul 2. Aceasta entanglează Qubiții 1 și 2 (creând o stare Bell ).
- Entanglarea Qubiților de margine: Aplică un CNOT de la Qubitul 0 la Qubitul 1, și un CNOT de la Qubitul 2 la Qubitul 3. Aceasta leagă perechile inițial separate, astfel încât Qubiții 0 și 3 să devină entanglați după pașii următori. Se aplică și un Hadamard pe Qubitul 2 (acesta, combinat cu CNOT-urile anterioare, formează parte dintr-o măsurătoare Bell pe Qubiții 1 și 2). În acest punct, Qubiții 0 și 3 nu sunt încă entanglați, dar Qubiții 1 și 2 sunt entanglați cu ei într-o stare de patru Qubiți mai largă.
- Măsurători în mijlocul circuitului și feedforward: Qubiții 1 și 2 (Qubiții de mijloc) sunt măsurați în baza computațională, producând doi biți clasici. Pe baza acelor rezultate ale măsurătorilor, aplicăm operații condiționale: dacă măsurătoarea Qubitului 1 (numim acest bit ) este 1, aplicăm o poartă pe Qubitul 3; dacă măsurătoarea Qubitului 2 () este 1, aplicăm o poartă pe Qubitul 0. Aceste porți condiționale (realizate folosind constructul Qiskit
if_test/if_else) implementează corecțiile standard de teleportare. Ele „anulează" flip-urile Pauli aleatorii care apar din cauza proiectării Qubiților 1 și 2, asigurând că Qubiții 0 și 3 ajung într-o stare Bell cunoscută, indiferent de rezultatele măsurătorilor. După acest pas, Qubiții 0 și 3 ar trebui să fie idealmente entanglați în starea Bell . - Măsurarea stabilizatorilor perechii Bell: Împărțim apoi în două versiuni ale circuitului. În prima versiune, măsurăm stabilizatorul pe Qubiții 0 și 3. În a doua versiune, măsurăm stabilizatorul pe acești Qubiți.
Pentru fiecare aranjament inițial de patru Qubiți, funcția de mai sus returnează două circuite (unul pentru măsurarea stabilizatorului , unul pentru ). La sfârșitul acestui pas, avem o listă de circuite care acoperă fiecare lanț de patru Qubiți de pe dispozitiv. Aceste circuite includ măsurători în mijlocul circuitului și operații condiționale (if/else), care sunt instrucțiunile cheie ale circuitului dinamic.
circuits = create_bell_stab(initial_layouts)
circuits[-1].draw("mpl", fold=-1)

Pasul 2: Optimizarea problemei pentru execuția pe hardware cuantic
Înainte de a executa circuitele noastre pe hardware real, trebuie să le transpilăm pentru a corespunde constrângerilor fizice ale dispozitivului. Transpilarea va mapa circuitul abstract pe Qubiții fizici și setul de porți al dispozitivului ales. Deoarece am ales deja Qubiții fizici specifici pentru fiecare lanț (furnizând un initial_layout generatorului de circuite), folosim optimization_level=0 al transpilerului cu acel aranjament fix. Astfel îi spunem lui Qiskit să nu reasigneze Qubiți sau să efectueze optimizări grele care ar putea altera structura circuitului. Dorim să păstrăm secvența de operații (în special porțile condiționale) exact așa cum a fost specificată.
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)

Pasul 3: Execuția folosind primitivele Qiskit
Putem acum rula experimentul pe dispozitivul cuantic. Folosim Qiskit Runtime și primitiva sa Sampler pentru a executa eficient lotul de circuite.
sampler = Sampler(mode=backend)
sampler.options.environment.job_tags = ["cut-bell-pair-test"]
job = sampler.run(isa_circuits)
Pasul 4: Post-procesare și returnarea rezultatului în formatul clasic dorit
Ultimul pas este să calculăm metrica erorii medii pătratice (MSE) pentru fiecare grup de Qubiți testat și să rezumăm rezultatele. Pentru fiecare lanț, avem acum și măsurate. Dacă Qubiții 0 și 3 ar fi perfect entanglați într-o stare Bell , ne-am aștepta ca ambele să fie +1. Cuantificăm deviația folosind MSE:
Această valoare este 0 pentru o pereche Bell perfectă și crește pe măsură ce starea entanglată devine mai zgomotoasă (cu rezultate aleatorii care dau o valoare de așteptare în jurul valorii 0, MSE s-ar apropia de 1). Codul calculează acest MSE pentru fiecare grup de patru Qubiți.
Rezultatele dezvăluie o gamă largă de calitate a entanglementului pe întreg dispozitivul. Aceasta confirmă descoperirea din articol că poate exista o variație de peste un ordin de mărime în fidelitatea stării Bell, în funcție de ce Qubiți fizici sunt folosiți. Din punct de vedere practic, aceasta înseamnă că anumite regiuni sau legături din cip sunt mult mai bune pentru operațiunile de măsurare în mijlocul circuitului și feedforward decât altele. Factori precum eroarea de citire a Qubitului, durata de viață a Qubitului și crosstalk-ul contribuie probabil la aceste diferențe. De exemplu, dacă un lanț include un Qubit de citire deosebit de zgomotos, măsurătoarea din mijlocul circuitului poate fi nesigură, ducând la o fidelitate slabă pentru acea pereche entanglată (MSE ridicat).
layouts_mse = get_mse(job.result(), initial_layouts)
layout [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
qubits: [0, 1, 2, 3], mse:, 0.0312
qubits: [4, 5, 6, 7], mse:, 0.0491
qubits: [8, 9, 10, 11], mse:, 0.0711
qubits: [12, 13, 14, 15], mse:, 0.0436
layout [16, 23, 22, 21, 17, 27, 26, 25, 18, 31, 30, 29, 19, 35, 34, 33]
qubits: [16, 23, 22, 21], mse:, 0.0197
qubits: [17, 27, 26, 25], mse:, 0.113
qubits: [18, 31, 30, 29], mse:, 0.0287
qubits: [19, 35, 34, 33], mse:, 0.0433
layout [36, 41, 42, 43, 37, 45, 46, 47, 38, 49, 50, 51, 39, 53, 54, 55]
qubits: [36, 41, 42, 43], mse:, 0.1645
qubits: [37, 45, 46, 47], mse:, 0.0409
qubits: [38, 49, 50, 51], mse:, 0.0519
qubits: [39, 53, 54, 55], mse:, 0.0829
layout [56, 63, 62, 61, 57, 67, 66, 65, 58, 71, 70, 69, 59, 75, 74, 73]
qubits: [56, 63, 62, 61], mse:, 0.8663
qubits: [57, 67, 66, 65], mse:, 0.0375
qubits: [58, 71, 70, 69], mse:, 0.0664
qubits: [59, 75, 74, 73], mse:, 0.0291
layout [76, 81, 82, 83, 77, 85, 86, 87, 78, 89, 90, 91, 79, 93, 94, 95]
qubits: [76, 81, 82, 83], mse:, 0.0598
qubits: [77, 85, 86, 87], mse:, 0.313
qubits: [78, 89, 90, 91], mse:, 0.0679
qubits: [79, 93, 94, 95], mse:, 0.0505
layout [96, 103, 102, 101, 97, 107, 106, 105, 98, 111, 110, 109, 99, 115, 114, 113]
qubits: [96, 103, 102, 101], mse:, 0.0302
qubits: [97, 107, 106, 105], mse:, 0.0384
qubits: [98, 111, 110, 109], mse:, 0.0375
qubits: [99, 115, 114, 113], mse:, 0.1051
layout [116, 121, 122, 123, 117, 125, 126, 127, 118, 129, 130, 131, 119, 133, 134, 135]
qubits: [116, 121, 122, 123], mse:, 0.1624
qubits: [117, 125, 126, 127], mse:, 0.7246
qubits: [118, 129, 130, 131], mse:, 0.5919
qubits: [119, 133, 134, 135], mse:, 0.5277
layout [136, 143, 142, 141, 137, 147, 146, 145, 138, 151, 150, 149, 139, 155, 154, 153]
qubits: [136, 143, 142, 141], mse:, 0.0383
qubits: [137, 147, 146, 145], mse:, 1.0187
qubits: [138, 151, 150, 149], mse:, 0.1531
qubits: [139, 155, 154, 153], mse:, 0.0471
În final, vizualizăm performanța globală prin reprezentarea funcției de distribuție cumulativă (CDF) a valorilor MSE pentru toate lanțurile. Graficul CDF arată pragul MSE pe axa x și fracțiunea perechilor de Qubiți cu MSE cel mult egal cu acel prag pe axa y. Această curbă pornește de la zero și se apropie de unu pe măsură ce pragul crește pentru a cuprinde toate punctele de date. O creștere abruptă lângă un MSE scăzut ar indica că multe perechi au fidelitate ridicată; o creștere lentă înseamnă că multe perechi au erori mai mari. Adnotăm CDF-ul cu identitățile celor mai bune perechi. În grafic, fiecare punct din CDF corespunde MSE-ului unui lanț de patru Qubiți, și etichetăm punctul cu perechea de indici de Qubiți care au fost entanglați în acel experiment. Aceasta facilitează identificarea perechilor de Qubiți fizici cu cele mai bune performanțe (punctele din extrema stângă a CDF-ului).
plot_mse_ecdfs(layouts_mse, combine_layouts=True)