Перейти до основного вмісту

Бенчмаркінг динамічних схем із розрізаними парами Белла

Приблизна оцінка використання: 22 секунди на процесорі Heron r2 (ПРИМІТКА: Це лише оцінка. Ваш час виконання може відрізнятися.)

Результати навчання

Після проходження цього посібника користувачі повинні розуміти:

  • Як будувати динамічні схеми з вимірюваннями в середині схеми та класичним зворотним зв'язком для телепортації заплутаності між віддаленими кубітами;
  • Як обчислювати та інтерпретувати метрику похибки для кількісної оцінки точності пари Белла на пристрої;
  • Як визначати, які пари кубітів найкраще підходять для операцій на основі LOCC, використовуючи результати бенчмаркінгу.

Передумови

Ми рекомендуємо, щоб користувачі були знайомі з такими темами перед проходженням цього посібника:

Передісторія

Квантове обладнання зазвичай обмежене локальними взаємодіями, але багато алгоритмів потребують заплутування віддалених кубітів або навіть кубітів на окремих процесорах. Динамічні схеми — тобто схеми з вимірюванням у середині схеми та зворотним зв'язком — надають спосіб подолати ці обмеження, використовуючи класичний зв'язок у реальному часі для ефективної реалізації нелокальних квантових операцій. У цьому підході результати вимірювань з однієї частини схеми (або одного QPU) можуть умовно запускати вентилі на іншій, дозволяючи нам телепортувати заплутаність на великі відстані. Це формує основу схем локальних операцій та класичного зв'язку (LOCC), де ми використовуємо заплутані ресурсні стани (пари Белла) та класично передаємо результати вимірювань для зв'язування віддалених кубітів.

Одне з перспективних застосувань LOCC — реалізація віртуальних далекодіючих вентилів CNOT шляхом телепортації, як показано в посібнику з далекодіючого заплутування. Замість прямого далекодіючого CNOT (який може не підтримуватися зв'язністю обладнання) ми створюємо пари Белла та виконуємо реалізацію вентиля на основі телепортації. Однак точність таких операцій залежить від характеристик обладнання. Декогеренція кубітів під час необхідної затримки (очікування результатів вимірювань) та затримка класичного зв'язку можуть погіршити заплутаний стан. Крім того, помилки при вимірюваннях у середині схеми важче виправити, ніж помилки при фінальних вимірюваннях, оскільки вони поширюються на решту схеми через умовні вентилі.

У базовому експерименті автори вводять бенчмарк точності пар Белла для визначення, які частини пристрою найкраще підходять для заплутування на основі LOCC. Ідея полягає у виконанні невеликої динамічної схеми на кожній групі з чотирьох зв'язаних кубітів процесора. Ця чотирикубітна схема спочатку створює пару Белла на двох середніх кубітах, а потім використовує їх як ресурс для заплутування двох крайніх кубітів за допомогою LOCC. Конкретно, кубіти 1 і 2 підготовлюються локально в нерозрізану пару Белла (пару Белла, створену безпосередньо за допомогою вентилів Адамара та CNOT, без телепортації), а потім процедура телепортації використовує цю пару Белла для заплутування кубітів 0 і 3. Кубіти 1 і 2 вимірюються під час виконання схеми, і на основі цих результатів застосовуються корекції Паулі (вентиль X на кубіті 3 та Z на кубіті 0). Після цього кубіти 0 і 3 залишаються в стані Белла наприкінці схеми.

Для кількісної оцінки якості цієї фінальної заплутаної пари ми вимірюємо її стабілізатори: зокрема, парність у базисі ZZ (Z0Z3Z_0Z_3) та в базисі XX (X0X3X_0X_3). Для ідеальної пари Белла обидва ці математичні очікування дорівнюють +1. На практиці апаратний шум зменшить ці значення. Тому ми повторюємо схему двічі для кожної пари кубітів: одна схема вимірює кубіти 0 і 3 у базисі ZZ, а інша — у базисі XX. З результатів ми отримуємо оцінку Z0Z3\langle Z_0Z_3\rangle та X0X3\langle X_0X_3\rangle для цієї пари кубітів. Ми використовуємо середньоквадратичну помилку (MSE) цих стабілізаторів відносно ідеального значення (1) як просту метрику точності заплутування. Менше значення MSE означає, що два кубіти досягли стану Белла, ближчого до ідеального (вища точність), тоді як більше значення MSE вказує на більшу помилку. Скануючи цей експеримент по всьому пристрою, ми можемо оцінити можливості вимірювання та зворотного зв'язку різних груп кубітів та визначити найкращі пари кубітів для операцій LOCC.

Цей посібник демонструє експеримент на пристрої IBM Quantum® для ілюстрації того, як динамічні схеми можуть використовуватися для генерації та оцінки заплутаності між віддаленими кубітами. Ми визначимо всі чотирикубітні лінійні ланцюги на пристрої, запустимо схему телепортації на кожному з них, а потім візуалізуємо розподіл значень MSE. Ця наскрізна процедура показує, як використовувати Qiskit Runtime та функції динамічних схем для прийняття апаратно-усвідомлених рішень щодо розрізання схем або розподілу квантових алгоритмів у модульній системі.

Вимоги

Перед початком цього посібника переконайтеся, що у вас встановлено наступне:

  • Qiskit SDK v2.0 або новішої версії з підтримкою візуалізації
  • Qiskit Runtime v0.40 або новішої версії (pip install qiskit-ibm-runtime)
  • Qiskit Aer v0.17 або новішої версії (pip install qiskit-aer)

Налаштування

# Added by doQumentation — required packages for this notebook
!pip install -q matplotlib numpy qiskit qiskit-aer 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()

Приклад на невеликому симуляторі

Перед запуском на реальному QPU ми перевіряємо, що схема створює пару Белла, тестуючи її на безшумному симуляторі з чотирикубітним ланцюгом [0, 1, 2, 3]. Ми використовуємо Qiskit Runtime Sampler з AerSimulator як режим бекенду для виконання схем.

Крок 1: Відображення класичних вхідних даних на квантову задачу

Перший крок — створити набір квантових схем для бенчмаркінгу всіх кандидатних зв'язків пар Белла, адаптованих до топології пристрою. Ми починаємо з побудови таких схем для чотирикубітного ланцюга [0, 1, 2, 3].

Процедура create_bell_stab() виконує таке для кожного ланцюга:

  • Підготовка середньої пари Белла: Застосовуємо вентиль Адамара на кубіті 1 та CNOT від кубіта 1 до кубіта 2. Це заплутує кубіти 1 і 2 (створюючи стан Белла Φ+=(00+11)/2|\Phi^+\rangle = (|00\rangle + |11\rangle)/\sqrt{2}).
  • Заплутування крайніх кубітів: Застосовуємо CNOT від кубіта 0 до кубіта 1, та CNOT від кубіта 2 до кубіта 3. Це зв'язує початково окремі пари, щоб кубіти 0 і 3 стали заплутаними після наступних кроків. Також застосовується вентиль Адамара на кубіті 2 (це, у поєднанні з попередніми CNOT, формує частину вимірювання Белла на кубітах 1 і 2). На цьому етапі кубіти 0 і 3 ще не заплутані, але кубіти 1 і 2 заплутані з ними у більшому чотирикубітному стані.
  • Вимірювання в середині схеми та зворотний зв'язок: Кубіти 1 і 2 (середні кубіти) вимірюються в обчислювальному базисі, даючи два класичні біти. На основі результатів цих вимірювань ми застосовуємо умовні операції: якщо результат вимірювання кубіта 1 (назвемо цей біт m12m_{12}) дорівнює 1, ми застосовуємо вентиль XX на кубіті 3; якщо результат вимірювання кубіта 2 (m21m_{21}) дорівнює 1, ми застосовуємо вентиль ZZ на кубіті 0. Ці умовні вентилі (реалізовані за допомогою конструкції Qiskit if_test/if_else) реалізують стандартні корекції телепортації. Вони «скасовують» випадкові перекиди Паулі, що виникають через проєкцію кубітів 1 і 2, забезпечуючи, що кубіти 0 і 3 опиняються у відомому стані Белла незалежно від результатів вимірювань. Після цього кроку кубіти 0 і 3 в ідеалі мають бути заплутані у стані Белла Φ+|\Phi^+\rangle.
  • Вимірювання стабілізаторів пари Белла: Потім ми розділяємо на дві версії схеми. У першій версії ми вимірюємо стабілізатор ZZZZ на кубітах 0 і 3. У другій версії ми вимірюємо стабілізатор XXXX на цих кубітах.

Для кожного чотирикубітного початкового розміщення наведена вище функція повертає дві схеми (одну для вимірювання стабілізатора ZZZZ, іншу для XXXX). Ці схеми включають вимірювання в середині схеми та умовні (if/else) операції, які є ключовими інструкціями динамічної схеми.

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)

Результат виконання попередньої комірки коду

Крок 2: Оптимізація задачі для виконання на квантовому обладнанні

Перед виконанням наших схем нам потрібно транспілювати їх до операцій вентилів, що підтримуються на вказаному бекенді. Транспіляція відобразить абстрактну схему на фізичні кубіти та набір вентилів обраного бекенду. Оскільки ми вже обрали конкретні фізичні кубіти для кожного ланцюга (надавши initial_layout генератору схем), ми використовуємо optimization_level=0 транспілятора з фіксованим розміщенням. Це вказує Qiskit не перепризначати кубіти та не виконувати жодних складних оптимізацій, які могли б змінити структуру схеми. Ми хочемо зберегти послідовність операцій (особливо умовних вентилів) саме такою, як було задано.

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)

Крок 3: Виконання за допомогою примітивів Qiskit

Тепер ми можемо запустити експеримент на безшумному бекенді симулятора.

# 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)
layout [0, 1, 2, 3]
qubits: [0, 1, 2, 3], mse:, 0.0

Крок 4: Постобробка та повернення результату в бажаному класичному форматі

Останній крок — обчислити метрику середньоквадратичної похибки (MSE) для кожної протестованої групи кубітів та узагальнити результати. Для кожного ланцюга ми тепер маємо виміряні Z0Z3\langle Z_0Z_3\rangle та X0X3\langle X_0X_3\rangle. Якби кубіти 0 та 3 були ідеально заплутані у стані Белла Φ+|\Phi^+\rangle, ми очікували б, що обидва ці значення дорівнюватимуть +1. Ми кількісно оцінюємо відхилення за допомогою MSE:

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

Це значення дорівнює 0 для ідеальної пари Белла та зростає в міру того, як заплутаний стан стає більш зашумленим (при випадкових результатах, що дають математичне сподівання близько 0, MSE наближатиметься до 1). Код обчислює цю MSE для кожної чотирикубітної групи. Без шуму ми бачимо MSE = 0 у цьому прикладі на невеликому симуляторі, як і очікувалося.

Приклад на великому реальному обладнанні

Тут ми об'єднуємо всі ці деталі в єдиний робочий процес у більшому масштабі, який потім запускається на реальному квантовому обладнанні.

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

Ми програмно здійснюємо пошук по карті зв'язності пристрою для всіх лінійно з'єднаних ланцюгів із чотирьох кубітів. Кожен такий ланцюг (позначений індексами кубітів [q0q1q2q3][q0-q1-q2-q3]) слугує тестовим випадком для схеми обміну заплутаністю. Визначивши всі можливі шляхи довжиною 4, ми забезпечуємо максимальне покриття можливих груп кубітів, які могли б реалізувати протокол.

Ми генеруємо ці ланцюги за допомогою допоміжної функції, яка виконує жадібний пошук на графі пристрою. Вона повертає «смуги» з чотирьох чотирикубітних ланцюгів, об'єднаних у 16-кубітні групи. Об'єднання дозволяє нам запускати кілька чотирикубітних експериментів паралельно на різних частинах чипа та ефективно використовувати весь пристрій. Кожна 16-кубітна смуга містить чотири непересічні ланцюги, що означає, що жоден кубіт не використовується повторно в цій групі. Наприклад, одна смуга може складатися з ланцюгів [0123][0-1-2-3], [4567][4-5-6-7], [891011][8-9-10-11] та [12131415][12-13-14-15], упакованих разом. Будь-який кубіт, який не увійшов до смуги, повертається у змінній 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)

Далі ми конструюємо схему для кожної 16-кубітної смуги за допомогою функції create_bell_stab(). Наприкінці цього кроку ми маємо список схем, що покривають кожен чотирикубітний ланцюг на пристрої. Потім ми транспілюємо та запускаємо схеми на реальному бекенді і постобробляємо результати.

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

Результати виявляють широкий діапазон якості заплутування по всьому пристрою. Це підтверджує висновок статті про те, що варіація точності стану Белла може перевищувати порядок величини залежно від того, які фізичні кубіти використовуються. На практиці це означає, що певні ділянки або зв'язки на чипі значно краще справляються з операціями вимірювання всередині схеми та зворотного зв'язку, ніж інші. Такі фактори, як похибка зчитування кубітів, час життя кубітів та перехресні завади, ймовірно, спричиняють ці відмінності. Наприклад, якщо один ланцюг містить особливо зашумлений кубіт зчитування, вимірювання всередині схеми може бути ненадійним, що призведе до низької точності для цієї заплутаної пари (високе MSE). Нарешті, ми візуалізуємо загальну продуктивність, побудувавши графік кумулятивної функції розподілу (CDF) значень MSE для всіх ланцюгів. Графік CDF показує поріг MSE на осі x та частку пар кубітів, що мають не більше цього MSE, на осі y. Ця крива починається з нуля та наближається до одиниці в міру того, як поріг зростає, охоплюючи всі точки даних. Крутий підйом поблизу низького MSE свідчив би про те, що багато пар мають високу точність; повільний підйом означає, що багато пар мають більші похибки. Ми анотуємо CDF ідентифікаторами найкращих пар. На графіку кожна точка CDF відповідає MSE одного чотирикубітного ланцюга, і ми позначаємо точку парою індексів кубітів [q0,q3][q0, q3], які були заплутані в цьому експерименті. Це дозволяє легко визначити, які фізичні пари кубітів є найкращими (крайні ліві точки на CDF).

plot_mse_ecdfs(layouts_mse, combine_layouts=True)

Вивід попередньої комірки коду

Наступні кроки

Рекомендації

Якщо ця робота вас зацікавила, можливо, вас зацікавлять наступні матеріали:

Посилання

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