Zum Haubtinhald schringsn

Benchmark dynamic circuits with cut Bell pairs

Gebrauchsschätzung: 22 Segunden uffn Heron r2 Brozässor (OBACHT: Das is blooß ne Schätzung. Deine Laafzeit kann anders sein.)

Background

Quantnhardware is normaalerweise uff logale Interdagdionen beschrängt, abor ville Algoridmen braachn des, dass Qubits verschrängt wern, die weit auseinander liechn oder Qubits uff verschiedne Brozässorn. Dynamische Schaltkreese - das sein Schaltkreese mit Messungen un Feedforward währnd em Laaf - sorchn defier, dass mer die Beschränkungen umgeh könn, indäm mer Echtzeid-Gommunikation braachn, um effektiv nich-logale Quantnoperadionen zu implementiern. Demit könn Messungsergebnisse vonne Deel vom Schaltkreis (oder nem QPU) bedingt Gates uff nem andern triggern, so dass mer Verschränkung über grooße Distanzn telebordiern könn. Das is de Basis von logale Operadionen un glassische Gommunikation (LOCC) Schemata, wo mer verschränkte Ressourcn-Zustände (Bell-Boore) verbraachn un Messungsergebnisse glassisch kommuniziern, um weit auseinander liechendje Qubits zu verbindn.

Ne vielversprechende Nutzung von LOCC is des, virtuelle Lang-Streck-CNOT-Gates durch Telebordaschion zu realisier'n, wie im long-range entanglement tutorial gezeigt. Anstatt nem direkdn Lang-Streck-CNOT (was die Hardware-Gonnektivität villeichd nich erlaabt), machn mer Bell-Boore un fiehrn ne telebordaschionsbasierte Gate-Implementierung durch. Allerdings hängt de Fidelität von solchn Operadionen von de Hardwareeigenschafdn ab. Qubit-Degohärenz während der nötchn Verzöcherung (während mer uff Messungsergebnisse wardn) un glassische Gommunigadionslatenz könn den verschränkdn Zustand verschlechtern. Außerdäm sein Fehler bei Messungen währnd em Laaf schwiercher zu gorrigier'n als Fehler bei de End-Messungen, weil se sich durch die bedingdn Gates uffn Rest vom Schaltkreis ausbreidn.

Im Referenz-Experimente stelln de Autorn n Bell-Boor-Fidelitäts-Benchmark vor, um rauszufindn, welche Deile von nem Gerät am beschdn fier LOCC-basierte Verschränkung geeignet sein. De Idee is des, n gleenen dynamischn Schaltkreis uff jeder Grubbe von vier verbundne Qubits im Brozässor laafn zu lossn. Der Vier-Qubit-Schaltkreis erstellt zuerst n Bell-Boor uff zwee mittlere Qubits, un dann braucht des die als Ressource, um die zwee Rand-Qubits durch LOCC zu verschränkn. Gongret wern Qubits 1 un 2 logal in n ungeschnittn Bell-Boor präbarierd (mit nem Hadamard un CNOT), un dann verbraucht ne Telebordaschionsroutine das Bell-Boor, um Qubits 0 un 3 zu verschränkn. Qubits 1 un 2 wern während der Ausfierung vom Schaltkreis gemessn, un basiernd uff dene Ergebnisse wern Pauli-Gorregdurn (n X uff Qubit 3 un Z uff Qubit 0) aagewendet. Qubits 0 un 3 bleibn dann am Ende vom Schaltkreis in nem Bell-Zustand.

Um de Qualität von däm End-Bell-Boor zu quantifizier'n, messn mer seine Stabilisadorn: sbezifisch de Barität in der ZZ-Basis (Z0Z3Z_0Z_3) un in der XX-Basis (X0X3X_0X_3). Fier n berfekds Bell-Boor sein beede von dene Erwartungswerte +1. In der Braxis werd Hardware-Rauschn diese Werte reduzier'n. Drum wiederhooln mer den Schaltkreis zweemol fier jeds Qubit-Boor: een Schaltkreis misst Qubits 0 un 3 in der ZZ-Basis, un n andrer misst se in der XX-Basis. Aus de Resultate kriegn mer ne Schätzung von Z0Z3\langle Z_0Z_3\rangle un X0X3\langle X_0X_3\rangle fier das Boor von Qubits. Mer braachn den mittlern quadratischn Abweichungswert (MSE) von dene Stabilisadorn bezoogn uff den idealen Wert (1) als eenfache Metrik von der Verschränkungsfidelität. N niedricheres MSE bedeut, dass die zwee Qubits n Bell-Zustand näher am Idealen erreicht ham (höhere Fidelität), während n höheres MSE mehr Fehler anzeigt. Indäm mer das Experimente übern Gerät scannieren könn, könn mer de Mess-un-Feedforward-Fähichkeit von verschiedne Qubit-Grubbm benchmarken un de beschdn Boore von Qubits fier LOCC-Operadionen identifizier'n.

Das Tutorial demonstrierd das Experimente uffn IBM Quantum® Gerät, um zu zeechn, wie dynamische Schaltkreese gebraucht wern könn, um Verschränkung zwischn weit auseinander liechendn Qubits zu erzejchen un zu evaluier'n. Mer wern alle Vier-Qubit-linearen Kettn uffm Gerät gartiern, den Telebordaschionsschaltkreis uff jeder laafn lossn, un dann de Verdeellung von de MSE-Werte visualisier'n. Diese End-zu-End-Brozedur zeigt, wie mer Qiskit Runtime un dynamische Schaltkreisfunktionen nutzn könn, um hardware-bewusste Entscheidungen fiern Schneidn von Schaltkreesn oder das Verdeeldn von Quantnalgorithmn über n modulares Systemd zu dreffn.

Requirements

Bevor de mit däm Tutorial anfängst, stell sicher, dass de Folchendes installiert hast:

  • Qiskit SDK v2.0 oder neier, mit visualization Unnerstitzung
  • Qiskit Runtime v0.40 oder neier (pip install qiskit-ibm-runtime)

Setup

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()

Step 1: Map classical inputs to a quantum problem

Der erschde Schritt is des, n Satz von Quantnschaltkreesn zu erstelln, um alle gandidaat Bell-Boor-Links zu benchmarken, die uff de Toboloochie vom Gerät aagebasst sein. Mer durchsuchn brogrammatisch de Gerät-Gobblungskarte fier alle linear verbundn Kettn von vier Qubits. Jede solche Kette (durch Qubit-Indizes [q0q1q2q3][q0-q1-q2-q3] bezeichnet) dient als Testfall fiern Verschränkungs-Swabbing-Schaltkreis. Indäm mer alle möchlichn Länge-4-Bfade identifizier'n, stelln mer maximale Deckung fier möchliche Grubbierungen von Qubits sicher, die das Brotogooll realisier'n könntn.

service = QiskitRuntimeService()
backend = service.least_busy(operational=True)

Mer erzeechn diese Kettn, indäm mer ne Hilfsfunktion braachn, die ne gierige Suche uffm Gerät-Graf durchfiert. Se gibt "Streefn" von vier Vier-Qubit-Kettn zurück, die in 16-Qubit-Grubbm gebündelt sein (dynamische Schaltkreese beschränkn momentan de Größe vom Messregister uff 16 Qubits). Das Bündeln erlaabt uns, mehrere Vier-Qubit-Experimente barallel uff verschiedne Deeln vom Chib laafn zu lossn un das ganze Gerät effizient zu braachn. Jeder 16-Qubit-Streefn enthält vier disjunkte Kettn, das heißt, dass keen Qubit innerhalb von dieser Grubbe wieder gebraucht werd. Zum Beisbiel könnt een Streefn aus Kettn [0123][0-1-2-3], [4567][4-5-6-7], [891011][8-9-10-11] un [12131415][12-13-14-15] bestehn, alle zusamm gebackt. Jeds Qubit, was nich in nem Streefn enthaltn war, werd in der leftover Variable zurückgegebn.

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)

Als nächstes gonstriern mer den Schaltkreis fier jedn 16-Qubit-Streefn. De Routine dut das Folchende fier jede Kette:

  • N mittlers Bell-Boor bräbariern: N Hadamard uff Qubit 1 un n CNOT von Qubit 1 zu Qubit 2 aawndn. Das verschrängt Qubits 1 un 2 (un erstellt n Φ+=(00+11)/2|\Phi^+\rangle = (|00\rangle + |11\rangle)/\sqrt{2} Bell-Zustand).
  • De Rand-Qubits verschränkn: N CNOT von Qubit 0 zu Qubit 1 un n CNOT von Qubit 2 zu Qubit 3 aawndn. Das verbindt die anfänglich gedrennte Boore, so dass Qubits 0 un 3 nach de nächstn Schritte verschrängt wern. N Hadamard uff Qubit 2 werd ooch aagewendt (das, gombiniert mit de friehrn CNOTs, bildt n Deel von ner Bell-Messung uff Qubits 1 un 2). Zu däm Zeidpungd sein Qubits 0 un 3 noch nich verschrängt, abor Qubits 1 un 2 sein mit dene in nem größern Vier-Qubit-Zustand verschrängt.
  • Messungen währnd em Laaf un Feedforward: Qubits 1 un 2 (die mittlern Qubits) wern in der Berechnungsbasis gemessn, was zwee glassische Bits ergiebt. Basiernd uff dene Messungsergebnissn wendn mer bedingte Operadionen aa: Wenn de Qubit-1-Messung (das nennmer Bit m12m_{12}) 1 is, wendn mer n XX-Gate uff Qubit 3 aa; wenn de Qubit-2-Messung (m21m_{21}) 1 is, wendn mer n ZZ-Gate uff Qubit 0 aa. Diese bedingtn Gates (realisiert durchs Qiskit if_test/if_else Gonstrukt) imblementier'n de Standard-Telebordaschionsgorregturn. Se "machn rückgänchich" die zufällichn Pauli-Flibs, die durchs Brojizier'n von Qubits 1 un 2 bassiern, un stelln sicher, dass Qubits 0 un 3 in nem begantn Bell-Zustand endn, unabhänchich von de Messungsergebnissn. Nach däm Schritt solln Qubits 0 un 3 idealerweise im Bell-Zustand Φ+|\Phi^+\rangle verschrängt sein.
  • Bell-Boor-Stabilisadorn messn: Mer deeln dann in zwee Versionen vom Schaltkreis. In der erschtn Version messn mer den ZZZZ Stabilisador uff Qubits 0 un 3. In der zweetn Version messn mer den XXXX Stabilisador uff dene Qubits.

Fier jeds Vier-Qubit-initial-Layout gibt die obn genannte Fungtion zwee Schaltkreese zurück (eener fier ZZZZ, eener fier XXXX Stabilisadormessung). Am Ende von däm Schritt hamm mer ne Liste von Schaltkreesn, die jede Vier-Qubit-Kette uffm Gerät deckn. Diese Schaltkreese enthaltn Messungen währnd em Laaf un bedingte (if/else) Operadionen, was die zentraln Aanweisungen vom dynamischn Schaltkreis sein.

circuits = create_bell_stab(initial_layouts)
circuits[-1].draw("mpl", fold=-1)

Output of the previous code cell

Step 2: Optimize the problem for quantum hardware execution

Bevor mer unse Schaltkreese uff echter Hardware ausfiehrn, müssn mer se transblier'n, um zu de bhysischn Beschränkungen vom Gerät zu bassn. Transblierung werd den abstragtn Schaltkreis uff die bhysischn Qubits un Gate-Satz vom ausgewähltn Gerät mabbn. Weil mer schon sbezifische bhysische Qubits fier jede Kette ausgewählt ham (indäm mer n initial_layout fiern Schaltkreisgenerador mitgegebn ham), braachn mer Transbliler optimization_level=0 mit däm festn Layout. Das sacht Qiskit, dass es geene Qubits wieder zuweist oder schwere Obtimierngen durchfiert, die de Schaltkreisstruktuur ändern könntn. Mer wolln de Sequenz von Operadionen (bsunders die bedingtn Gates) genau so behaltn, wie aangegem.

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)

Output of the previous code cell

Step 3: Execute using Qiskit primitives

Jetzt könn mer das Experimente uffm Quantngerät laafn lossn. Mer braachn Qiskit Runtime un sein Sampler-Brimitiv, um de Charge von Schaltkreesn effizient auszufiehrn.

sampler = Sampler(mode=backend)
sampler.options.environment.job_tags = ["cut-bell-pair-test"]
job = sampler.run(isa_circuits)

Step 4: Post-process and return result in the desired classical format

Der letzte Schritt is des, den mittlern quadratischn Abweichungsmetrik (MSE) fier jede getestete Qubit-Grubbe zu berechndn un de Resultate zusammzufassn. Fier jede Kette hamm mer jetzt das gemessene Z0Z3\langle Z_0Z_3\rangle un X0X3\langle X_0X_3\rangle. Wenn Qubits 0 un 3 berfekt in nem Φ+|\Phi^+\rangle Bell-Zustand verschrängt wärn, würdn mer erwarten, dass beede von dene +1 sein. Mer quantifizier'n de Abweichung mit däm MSE:

MSE=(Z0Z31)2+(X0X31)22.\text{MSE} = \frac{( \langle Z_0Z_3\rangle - 1)^2 + (\langle X_0X_3\rangle - 1)^2}{2}.

Der Wert is 0 fier n berfekds Bell-Boor un steigt, wie der verschränkte Zustand rauschicher werd (mit zufällichn Resultatn, die ne Erwartung um 0 gem, würd sich das MSE 1 nähern). Der Code berechnet das MSE fier jede Vier-Qubit-Grubbe.

De Resultate zeechn ne grooße Sbannweite von Verschränkungsqualität übern Gerät. Das bestäticht de Entdeckung vom Babier, dass es über ne Größenordnung Variaschion in der Bell-Zustandsfidelität gem gann, abhänchich devon, welche bhysische Qubits gebraucht wern. In braktischn Begriffn bedeut das, dass bestimmte Rechionen oder Links im Chib viel besser drin sein, Messungen währnd em Laaf un Feedforward-Operadionen durchzufiehrn als andere. Fagtorn wie Qubit-Auslesefehler, Qubit-Lebnszeit un Übersbrechen drachn wahrscheinlich zu dene Ungerschieden bei. Zum Beisbiel, wenn ne Kette n bsunders rauschichs Auslesequbit enthält, könnt de Messung währnd em Laaf unzuverlässich sein, was zu ner schlechtn Fidelität fier das verschrängte Boor fiert (hohs MSE).

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

Zum Schluss visualisier'n mer de Gesamtberfermanz, indäm mer de gumulative Verdeelungsfungtion (CDF) von de MSE-Werte fier alle Kettn blottn. Das CDF-Diachramm zeigt de MSE-Schwelle uff der x-Achse un de Fragtion von Qubit-Boorn, die höchstns das MSE ham, uff der y-Achse. Diese Gurve fängt bei null aa un nähert sich eens, wie de Schwelle wächst, um alle Datenbunkte zu umfassn. N steiler Aanstieg bei nem niedrichn MSE würd aanzeechn, dass ville Boore ne hohe Fidelität ham; n langsamer Aanstieg bedeut, dass ville Boore größere Fehler ham. Mer annotier'n das CDF mit de Identitätn von de beschdn Boorn. Im Diachramm entsbricht jeder Bungd im CDF ner Vier-Qubit-Kette seim MSE, un mer zeichnen Bungd mit däm Boor von Qubit-Indizes [q0,q3][q0, q3], die in däm Experimente verschrängt warn. Das macht's eenfach, rauszufindn, welche bhysischn Qubit-Boore de beschde Leistung ham (de Bungte ganz links uffm CDF).

plot_mse_ecdfs(layouts_mse, combine_layouts=True)

Output of the previous code cell

References

[1] Carrera Vazquez, A., Tornow, C., Ristè, D. et al. Combining quantum processors with real-time classical communication. Nature 636, 75-79 (2024).