Circuitos dinâmicos de referência com pares Bell cortados
Estimativa de uso: 22 segundos em um processador r2 Heron (NOTA: Esta é apenas uma estimativa. O tempo de execução pode variar.)
Resultados do aprendizado
Após concluir este tutorial, os usuários deverão compreender:
- Como construir circuitos dinâmicos com medições no meio do circuito e alimentação direta clássica para teletransportar o entrelaçamento entre qubits distantes;
- Como calcular e interpretar a métrica de erro para quantificar a fidelidade do par de Bell em um dispositivo;
- Como identificar quais pares de qubits são mais adequados para operações baseadas em LOCC utilizando os resultados dos testes de desempenho.
Pré-requisitos
Recomendamos que os usuários estejam familiarizados com os seguintes tópicos antes de seguir com este tutorial:
- Conceitos básicos de computação quântica, incluindo estados de Bell, entrelaçamento e portas quânticas;
- Conhecimento de circuitos dinâmicos ( medições no meio do circuito e alimentação direta clássica);
- Conhecimentos básicos sobre Qiskit SDK e Qiskit Runtime, além de acesso a uma conta no IBM Quantum®.
Segundo plano
O hardware quântico é normalmente limitado a interações locais, mas muitos algoritmos exigem o entrelaçamento de qubits distantes ou mesmo qubits em processadores separados. Os circuitos dinâmicos — ou seja, circuitos com medição no meio do circuito e feedforward — oferecem uma maneira de superar essas limitações usando comunicação clássica em tempo real para implementar efetivamente operações quânticas não locais. Nessa abordagem, os resultados das medições de uma parte de um circuito (ou de uma QPU) podem acionar condicionalmente portas em outra parte, permitindo-nos teletransportar o entrelaçamento por longas distâncias. Isso forma a base dos esquemas de operações locais e comunicação clássica (LOCC), nos quais consumimos estados de recursos entrelaçados (pares de Bell) e comunicamos os resultados das medições de forma clássica para conectar qubits distantes.
Um uso promissor do LOCC é a realização de portas CNOT virtuais de longo alcance por teletransporte, conforme mostrado no tutorial sobre entrelaçamento de longo alcance. Em vez de um CNOT direto de longo alcance (que a conectividade do hardware pode não permitir), criamos pares de Bell e realizamos uma implementação de porta baseada em teletransporte. No entanto, a fidelidade dessas operações depende das características do hardware. A decoerência do qubit durante o atraso necessário (enquanto se aguarda os resultados da medição) e a latência da comunicação clássica podem degradar o estado entrelaçado. Além disso, os erros nas medições intermediárias do circuito são mais difíceis de corrigir do que os erros nas medições finais, pois se propagam para o resto do circuito através das portas condicionais.
Na experiência de referência, os autores introduzem um parâmetro de referência de fidelidade do par de Bell para identificar quais partes de um dispositivo são mais adequadas para o entrelaçamento baseado em LOCC. A ideia é executar um pequeno circuito dinâmico em cada grupo de quatro qubits conectados no processador. Este circuito de quatro qubits cria primeiro um par de Bell nos dois qubits centrais e, em seguida, utiliza-os como recurso para entrelaçar os dois qubits laterais por meio do LOCC. Concretamente, os qubits 1 e 2 são preparados localmente em um par de Bell não cortado (um par de Bell criado diretamente com um Hadamard e um CNOT, sem teletransporte) e, em seguida, uma rotina de teletransporte utiliza esse par de Bell para entrelaçar os qubits 0 e 3. Os qubits 1 e 2 são medidos durante a execução do circuito e, com base nesses resultados, são aplicadas correções de Pauli (um X no qubit 3 e um Z no qubit 0). Os qubits 0 e 3 ficam, então, em um estado de Bell no final do circuito.
Para quantificar a qualidade desse par entrelaçado final, medimos seus estabilizadores: especificamente, a paridade na base ( ) e na base ( ). Para um par Bell perfeito, ambas as expectativas são iguais a +1. Na prática, o ruído do hardware reduzirá esses valores. Portanto, repetimos o circuito duas vezes para cada par de qubits: um circuito mede os qubits 0 e 3 na base e outro os mede na base. A partir dos resultados, obtemos uma estimativa de e para esse par de qubits. Utilizamos o erro quadrático médio (MSE) desses estabilizadores em relação ao valor ideal (1) como uma métrica simples da fidelidade do entrelaçamento. Um MSE mais baixo significa que os dois qubits alcançaram um estado de Bell mais próximo do ideal (maior fidelidade), enquanto um MSE mais alto indica mais erros. Ao analisar essa experiência em todo o dispositivo, podemos comparar a capacidade de medição e feedforward de diferentes grupos de qubits e identificar os melhores pares de qubits para operações LOCC.
Este tutorial demonstra a experiência em um IBM Quantum® dispositivo para ilustrar como circuitos dinâmicos podem ser usados para gerar e avaliar o entrelaçamento entre qubits distantes. Iremos mapear todas as cadeias lineares de quatro qubits no dispositivo, executar o circuito de teletransporte em cada uma delas e, em seguida, visualizar a distribuição dos valores MSE. Este procedimento completo mostra como aproveitar Qiskit Runtime os recursos de circuitos dinâmicos para informar escolhas conscientes de hardware para cortar circuitos ou distribuir algoritmos quânticos em um sistema modular.
Requisitos
Antes de iniciar este tutorial, certifique-se de que você tem o seguinte instalado:
- Qiskit SDK v2.0 ou posterior, com suporte para visualização
- v0.40Qiskit Runtime ou mais tarde (
pip install qiskit-ibm-runtime) - Qiskit Aer v0.17 ou versão posterior (
pip install qiskit-aer)
Instalação
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()Exemplo de simulador em pequena escala
[0, 1, 2, 3]Antes de executar o código na QPU real, verificamos se o circuito produz um par de Bell, testando-o em um simulador sem ruído com uma cadeia de quatro qubits. Utilizamos o Qiskit RuntimeSampler com AerSimulator como modo de backend para executar os circuitos.
Passo 1: Mapear entradas clássicas para um problema quântico
O primeiro passo é criar um conjunto de circuitos quânticos para avaliar todas as ligações de pares de Bell candidatas, adaptadas à topologia do dispositivo. [0, 1, 2, 3]Começamos construindo esses circuitos com uma cadeia de quatro qubits.
A create_bell_stab() rotina realiza o seguinte para cada cadeia:
- Prepare um par Bell médio: aplique um Hadamard no qubit 1 e um CNOT do qubit 1 para o qubit 2. Isso entrelaça os qubits 1 e 2 (criando um estado de Bell).
- Entrelace os qubits de borda: aplique um CNOT do qubit 0 ao qubit 1 e um CNOT do qubit 2 ao qubit 3. Isso liga os pares inicialmente separados, de modo que os qubits 0 e 3 ficarão entrelaçados após as próximas etapas. Um Hadamard no qubit 2 também é aplicado (isso, combinado com os CNOTs anteriores, faz parte de uma medição Bell nos qubits 1 e 2). Neste ponto, os qubits 0 e 3 ainda não estão entrelaçados, mas os qubits 1 e 2 estão entrelaçados com eles em um estado maior de quatro qubits.
- Medições no meio do circuito e feedforward: os qubits 1 e 2 (os qubits do meio) são medidos na base computacional, produzindo dois bits clássicos. Com base nos resultados dessas medições, aplicamos operações condicionais: se a medição do qubit 1 (chamemos esse bit de ) for 1, aplicamos um portão no qubit 3; se a medição do qubit 2 ( ) for 1, aplicamos um portão no qubit 0. Essas portas condicionais (realizadas usando o Qiskit
if_test/if_elseconstruct) implementam as correções padrão de teletransporte. Eles “desfazem” as inversões aleatórias de Pauli que ocorrem devido à projeção dos qubits 1 e 2, garantindo que os qubits 0 e 3 terminem em um estado Bell conhecido, independentemente dos resultados da medição. Após esta etapa, os qubits 0 e 3 devem, idealmente, estar entrelaçados no estado de Bell. - Medir os estabilizadores do par de sinos: Em seguida, dividimos o circuito em duas versões. Na primeira versão, medimos o estabilizador nos qubits 0 e 3. Na segunda versão, medimos o estabilizador nesses qubits.
Para cada configuração inicial de quatro qubits, a função acima retorna dois circuitos (um para a medição do estabilizad e outro para a medição do estabilizador ). Esses circuitos incluem medições no meio do circuito e operações condicionais (if/else), que são as instruções fundamentais do circuito dinâmico.
from qiskit_aer import AerSimulator
# 4-qubit chain for simulation
sim_layout = [[0, 1, 2, 3]]
aer_backend = AerSimulator()
sim_circuits = create_bell_stab(sim_layout)
sim_circuits[1].draw("mpl", fold=-1, idle_wires=False)Output:
Etapa 2: Otimizar o problema para execução em hardware quântico
Antes de executar nossos circuitos, precisamos compilá-los para operações de porta compatíveis com o backend especificado. A transpilação irá mapear o circuito abstrato para os qubits físicos e o conjunto de portas do backend escolhido. Como já escolhemos qubits físicos específicos para cada cadeia (fornecendo um initial_layout ao gerador de circuitos), usamos o transpiler optimization_level=0 com esse layout fixo. Isso indica ao Qiskit para não reatribuir qubits nem realizar otimizações complexas que possam alterar a estrutura do circuito. Queremos manter a sequência de operações (especialmente as portas condicionais) exatamente como especificado.
pm_sim = generate_preset_pass_manager(
optimization_level=0, backend=aer_backend, initial_layout=sim_layout[0]
)
isa_sim_circuits = pm_sim.run(sim_circuits)
isa_sim_circuits[1].draw("mpl", fold=-1, idle_wires=False)Passo 3: Execute usando Qiskit primitives
Agora podemos executar o experimento no backend do simulador sem ruído.
# 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
Etapa 4: Pós-processamento e retorno do resultado no formato clássico desejado
A etapa final consiste em calcular a métrica do erro quadrático médio (MSE) para cada grupo de qubits testado e resumir os resultados. Para cada cadeia, agora temos os valores medidos e . Se os qubits 0 e 3 estivessem perfeitamente entrelaçados em um estado de Bell, esperaríamos que ambos fossem +1. Quantificamos o desvio usando o MSE:
Esse valor é 0 para um par de Bell perfeito e aumenta à medida que o estado entrelaçado se torna mais ruidoso (com resultados aleatórios que geram uma expectativa em torno de 0, o MSE se aproximaria de 1). O código calcula esse MSE para cada grupo de quatro qubits. Sem ruído, observamos que MSE = 0 neste exemplo de simulador em pequena escala, como esperado.
Exemplo de hardware em grande escala
Aqui, reunimos todos esses detalhes em um único fluxo de trabalho em maior escala, que é então executado em hardware quântico real.
service = QiskitRuntimeService()
backend = service.least_busy(operational=True)Pesquisamos programaticamente no mapa de acoplamento do dispositivo todas as cadeias de quatro qubits conectadas linearmente. Cada uma dessas cadeias (identificadas pelos índices de qubits ) serve como um caso de teste para o circuito de troca de entrelaçamento. Ao identificar todos os caminhos possíveis de " length-4 ", garantimos a cobertura máxima para os possíveis agrupamentos de qubits que poderiam implementar o protocolo.
Geramos essas cadeias utilizando uma função auxiliar que realiza uma pesquisa gananciosa no gráfico do dispositivo. Ele retorna "faixas" de quatro cadeias de quatro qubits agrupadas em conjuntos de 16 qubits. O agrupamento nos permite realizar várias experiências com quatro qubits em paralelo em partes distintas do chip e utilizar todo o dispositivo de forma eficiente. Cada faixa de 16 qubits contém quatro cadeias independentes, o que significa que nenhum qubit é reutilizado dentro desse grupo. Por exemplo, uma faixa pode consistir nas cadeias , , e , todas agrupadas. Qualquer qubit que não tenha sido incluído em uma faixa é retornado na leftover variável.
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)Em seguida, construímos o circuito para cada faixa de 16 qubits utilizando a função create_bell_stab(). Ao final desta etapa, temos uma lista de circuitos que abrange todas as cadeias de quatro qubits do dispositivo. Em seguida, compilamos e executamos os circuitos no backend real e processamos os resultados posteriormente.
# -------------------------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
Os resultados revelam uma ampla variação na qualidade do entrelaçamento em todo o dispositivo. Isso confirma a conclusão do artigo de que pode haver uma variação de mais de uma ordem de magnitude na fidelidade do estado de Bell, dependendo de quais qubits físicos são usados. Em termos práticos, isso significa que certas regiões ou ligações no chip são muito melhores em realizar medições no meio do circuito e operações de feedforward do que outras. Fatores como erro de leitura do qubit, tempo de vida do qubit e interferência provavelmente contribuem para essas diferenças. Por exemplo, se uma cadeia incluir um qubit de leitura particularmente ruidoso, a medição no meio do circuito poderá não ser fiável, levando a uma baixa fidelidade para esse par entrelaçado (MSE elevado).
Por fim, visualizamos o desempenho geral traçando a função de distribuição cumulativa (CDF) dos valores MSE para todas as cadeias. O gráfico CDF mostra o limiar MSE no eixo x e a fração de pares de qubits que têm, no máximo, esse MSE no eixo y. Essa curva começa em zero e se aproxima de um à medida que o limite cresce para abranger todos os pontos de dados. Um aumento acentuado próximo a um MSE baixo indicaria que muitos pares são de alta fidelidade; um aumento lento significa que muitos pares têm erros maiores. Anotamos o CDF com as identidades dos melhores pares. No gráfico, cada ponto na CDF corresponde ao MSE de uma cadeia de quatro qubits, e rotulamos o ponto com o par de índices de qubits que estavam entrelaçados nessa experiência. Isso facilita identificar quais pares de qubits físicos têm o melhor desempenho (os pontos mais à esquerda na CDF).
plot_mse_ecdfs(layouts_mse, combine_layouts=True)Output:
Próximas etapas
Se você achou este trabalho interessante, talvez se interesse pelos seguintes materiais:
- Aprenda a implementar o entrelaçamento de longo alcance com circuitos dinâmicos
- Aprenda a simular o hamiltoniano de Ising com efeito de kick usando circuitos dinâmicos