Przejdź do głównej treści

Używanie postelekcji w obciążeniach roboczych

Wersje pakietów

Kod na tej stronie został opracowany przy użyciu następujących wymagań. Zalecamy używanie tych lub nowszych wersji.

qiskit[all]~=2.5.2
qiskit-ibm-runtime~=0.47.0
qiskit-addon-utils~=0.4.0

Podczas optymalizacji strategii łagodzenia błędów w obciążeniu roboczym często przydatne jest odfiltrowywanie pomiarów, o których wiadomo, że zostały zainfekowane przez niemarkowskie (skorelowane) procesy szumowe. Jedną z takich metod jest dołączanie do obwodu kroku przetwarzania końcowego, który mierzy aktywne i sąsiadujące kubity "obserwatora", stosuje powolną rotację do każdego kubitu, a następnie mierzy je ponownie. W przypadkach, gdy dwa pomiary nie potwierdzają odwróconego kubitu zgodnie z oczekiwaniami, pomiar jest odrzucany poprzez zastosowanie maski do wyników.

Pakiet Qiskit addon utilities dostarcza zestaw przejść transpilatora i funkcję postelekcji do zastosowania maski. Ta strona zawiera wskazówki dotyczące włączania postelekcji do obciążeń roboczych kwantowych, używając czterokubitowego stanu GHZ jako przykładu.

Tworzenie obciążenia roboczego​

Zacznij od przygotowania obwodu do wykonania i transpilacji względem backendu obsługującego bramki ułamkowe.

# Added by doQumentation — required packages for this notebook
!pip install -q qiskit qiskit-addon-utils qiskit-ibm-runtime
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit.circuit import QuantumCircuit
from qiskit.transpiler import generate_preset_pass_manager

circuit = QuantumCircuit(4)
circuit.h(0)
circuit.cx(0, 1)
circuit.cx(1, 2)
circuit.cx(2, 3)
circuit.measure_all()

service = QiskitRuntimeService()
backend = service.least_busy(use_fractional_gates=True)
pm = generate_preset_pass_manager(optimization_level=3, backend=backend)

transpiled_circuit = pm.run(circuit)
transpiled_circuit.draw("mpl")

Wyjście poprzedniej komórki kodu

Dodawanie przejść transpilatora postelekcji​

Następnie utwórz menedżer przejść predefiniowanych zawierający przejścia AddPostSelectionMeasures i AddSpectatorMeasures z pakietu qiskit-addon-utils. Spowoduje to dołączenie do obwodu sekwencji małokątowych rotacji RX (efektywnie tworząc długą bramkę X) wraz z drugim zestawem pomiarów.

from qiskit.transpiler import PassManager
from qiskit_addon_utils.noise_management.post_selection import PostSelector
from qiskit_addon_utils.noise_management.post_selection.transpiler.passes import (
AddPostSelectionMeasures,
AddSpectatorMeasures,
)

post_selection_pm = PassManager(
[
AddSpectatorMeasures(backend.coupling_map, add_barrier=True),
AddPostSelectionMeasures(x_pulse_type="rx"),
]
)

template_circuit_ps = post_selection_pm.run(transpiled_circuit)
template_circuit_ps.draw("mpl", fold=-1, idle_wires=False)

Wyjście poprzedniej komórki kodu

Wykonanie programu kwantowego​

Następnie przygotuj obiekt QuantumProgram zawierający obwód do wykonania.

from qiskit_ibm_runtime import QuantumProgram, Executor

shots = 4000

program = QuantumProgram(shots=shots)
program.append_circuit_item(template_circuit_ps)

# Initialize the Executor job and run
executor = Executor(backend)
executor_job = executor.run(program)
print(f"Job ID: {executor_job.job_id()}")
Job ID: dab7lmhl216s739p6q1g

Teraz możesz zinterpretować wyniki. Wynik executora to słownik z kilkoma kluczami.

executor_result = executor_job.result()[0]
executor_result.keys()
KeysView(QuantumProgramItemResult({'meas': array([[ True, True, True, True],
[ True, True, True, True],
[False, False, False, False],
...,
[ True, True, True, True],
[ True, True, True, True],
[False, False, False, False]], shape=(4000, 4)), 'spec': array([[False, False, False],
[False, False, False],
[False, False, False],
...,
[False, False, False],
[False, False, False],
[False, False, False]], shape=(4000, 3)), 'meas_ps': array([[False, False, False, False],
[False, False, False, False],
[ True, True, True, True],
...,
[False, False, False, False],
[False, False, False, False],
[False, True, True, True]], shape=(4000, 4)), 'spec_ps': array([[ True, True, True],
[ True, True, True],
[ True, True, True],
...,
[ True, True, True],
[ True, True, True],
[ True, True, True]], shape=(4000, 3))}, metadata=ItemMetadata()))

Te klucze odpowiadają aktywnym kubitom i kubitom obserwatora przed instrukcjami rx (meas i spec) oraz po instrukcjach rx (meas_ps i spec_ps). Każdy z nich jest tablicą tablic opartą na liczbie pomiarów i kubitów. W tym przypadku kształt to (1000, 4).

Tworzenie maski postelekcji​

Na podstawie tych pomiarów możesz utworzyć maskę, używając klasy PostSelector z qiskit-addon-utils. Maska ta jest tablicą logiczną, gdzie każdy pomiar jest oznaczony jako True lub False na podstawie jednej z dwóch strategii postelekcji. Pierwsza strategia, node, używa informacji o kubitach do decydowania, czy pomiar powinien zostać odrzucony — a druga, edge, używa informacji o łączności z najbliższymi sąsiadami do podjęcia tej decyzji.

post_selector = PostSelector.from_circuit(
circuit=template_circuit_ps, coupling_map=backend.coupling_map
)

mask_node = post_selector.compute_mask(executor_result, strategy="node")
mask_edge = post_selector.compute_mask(executor_result, strategy="edge")

Zarówno strategia węzłowa, jak i krawędziowa często odrzucają różne pomiary. Możesz wybrać dowolną z nich. Ten notatnik stosuje iloczyn bitowy AND, który jest strategią zachowawczą, zachowującą pomiar tylko wtedy, gdy jest zaakceptowany przez obie strategie — węzłową i krawędziową.

mask = mask_node & mask_edge
print(f"The combined mask: {mask}")
count_retained = 0

for m in mask:
count_retained += m

print(
f"Percentage of the shots retained is after post selection "
f"{100 * count_retained / shots}"
)
The combined mask: [ True True True ... True True False]
Percentage of the shots retained is after post selection 83.3

Porównaj rozkład prawdopodobieństwa z postelekcją i bez niej. Poniższy fragment kodu oblicza rozkład prawdopodobieństwa przed i po postelekcji, a także odległość między zmierzonymi a idealnymi rozkładami.

counts = {}
counts_ps = {}

for idx, measurement in enumerate(executor_result["meas"]):
bitstring = ""
for bit in measurement:
bitstring += str(int(bit))

if bitstring in counts:
counts[bitstring] += 1
else:
counts[bitstring] = 1

# Compute count data for postselected shots based on the mask
if mask[idx]:
bitstring = ""
for bit in measurement:
bitstring += str(int(bit))

if bitstring in counts_ps:
counts_ps[bitstring] += 1
else:
counts_ps[bitstring] = 1

for key, val in counts.items():
counts[key] = val / shots

for key, val in counts_ps.items():
counts_ps[key] = float(val / count_retained)

Aby zademonstrować, jak postelekcja zmieniła wyniki, oblicz odległość między idealnym rozkładem prawdopodobieństwa a zmierzonymi.

import itertools
from qiskit.visualization import plot_histogram

bitstrings = ["".join(i) for i in itertools.product("01", repeat=4)]
counts_ideal = {}
for bitstring in bitstrings:
counts_ideal[bitstring] = 0.0
counts_ideal["1111"] = 0.5
counts_ideal["0000"] = 0.5

prob_distance = 0.0
prob_distance_ps = 0.0

for bitstring in counts_ideal.keys():
dist = 0.0
dist_ps = 0.0
if bitstring in counts:
dist = abs(counts[bitstring] - counts_ideal[bitstring])
if bitstring in counts_ps:
dist_ps = abs(counts_ps[bitstring] - counts_ideal[bitstring])
prob_distance += dist
prob_distance_ps += dist_ps

print(
f"Distance from ideal distribution before postselection: "
f"{1-prob_distance*0.5}"
)
print(
f"Distance from ideal distribution before after-selection: "
f"{1-prob_distance_ps*0.5}"
)

plot_histogram([counts, counts_ps], legend=["Normal", "Post selected"])
Distance from ideal distribution before postselection: 0.9385
Distance from ideal distribution before after-selection: 0.9315726290516206

Wyjście poprzedniej komórki kodu

Chociaż postelekcja może znacznie poprawić jakość wyników poprzez odfiltrowywanie pomiarów wyników, na które wpłynął szum niemarkowski, nie jest ona kompletnym rozwiązaniem łagodzenia błędów sama w sobie. Postelekcja zmniejsza wpływ pewnych błędów przez odrzucanie nieprawidłowych wyników pomiarów, ale wiąże się to z kosztem zwiększonego narzutu pobierania próbek i nie eliminuje wszystkich mechanizmów błędów obecnych w sprzęcie kwantowym bliskiego horyzontu. W rezultacie prawdopodobnie niewystarczające jest poleganie wyłącznie na postelekcji w przypadku bardziej złożonych lub głębszych obwodów. Zamiast tego postelekcja jest najbardziej skuteczna, gdy jest używana jako część szerszej strategii łagodzenia błędów — uzupełniając techniki takie jak łagodzenie błędów pomiarowych, kompilacja obwodów uwzględniająca szum lub probabilistyczna anulacja błędów — aby poprawić niezawodność obciążeń roboczych kwantowych przy zachowaniu równowagi między dokładnością a kosztem zasobów.

Następne kroki​

Zalecenia