Przejdź do głównej treści

Wydajna symulacja Circuit stabilizatorowych z prymitywami Qiskit Aer

Wersje pakietów

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

qiskit[all]~=2.3.0
qiskit-aer~=0.17

Ta strona pokazuje, jak używać prymitywów Qiskit Aer do wydajnej symulacji Circuit stabilizatorowych, w tym tych podlegających szumowi Pauliego.

Circuit stabilizatorowe, znane również jako Circuit Clifforda, to ważna, ograniczona klasa Circuit kwantowych, które można wydajnie symulować klasycznie. Istnieje kilka równoważnych sposobów definiowania Circuit stabilizatorowych. Jedna definicja mówi, że Circuit stabilizatorowy to Circuit kwantowy składający się wyłącznie z następujących Gate:

Zauważ, że używając Hadamarda i S, możemy skonstruować dowolną bramkę rotacji Pauliego (RxR_x, RyR_y i RzR_z) z kątem zawartym w zbiorze {0,π2,π,3π2}\{0, \frac{\pi}{2}, \pi, \frac{3\pi}{2}\} (z dokładnością do globalnej fazy), więc możemy uwzględnić te Gate również w definicji.

Circuit stabilizatorowe są ważne w badaniu korekcji błędów kwantowych. Ich klasyczna symulowalność sprawia również, że są przydatne do weryfikacji wyników komputerów kwantowych. Załóżmy na przykład, że chcesz wykonać Circuit kwantowy używający 100 Qubit na komputerze kwantowym. Skąd wiesz, że komputer kwantowy działa poprawnie? Circuit kwantowy na 100 Qubit wykracza poza możliwości klasycznej symulacji metodą brute-force. Modyfikując Circuit tak, aby stał się Circuit stabilizatorowym, możesz uruchamiać Circuit na komputerze kwantowym, które mają podobną strukturę do pożądanego Circuit, ale które możesz symulować na komputerze klasycznym. Sprawdzając wynik komputera kwantowego na Circuit stabilizatorowych, możesz zyskać pewność, że działa on poprawnie również na Circuit niestabilizatorowych. Zobacz Evidence for the utility of quantum computing before fault tolerance jako przykład tego pomysłu w praktyce.

Artykuł Dokładna i zaszumiona symulacja z prymitywami Qiskit Aer pokazuje, jak używać Qiskit Aer do przeprowadzania dokładnych i zaszumionych symulacji ogólnych Circuit kwantowych. Rozważ przykładowy Circuit użyty w tamtym artykule – 8-Qubitowy Circuit zbudowany przy użyciu efficient_su2:

# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-aer
from qiskit.circuit.library import efficient_su2

n_qubits = 8
circuit = efficient_su2(n_qubits)
circuit.draw("mpl")

Wynik poprzedniego bloku kodu

Używając Qiskit Aer, mogliśmy z łatwością zasymulować ten Circuit. Załóżmy jednak, że ustawimy liczbę Qubit na 500:

n_qubits = 500
circuit = efficient_su2(n_qubits)
# don't try to draw the circuit because it's too large

Ponieważ koszt symulacji Circuit kwantowych skaluje się wykładniczo z liczbą Qubit, tak duży Circuit generalnie przekraczałby możliwości nawet wysoko wydajnego symulatora jak Qiskit Aer. Klasyczna symulacja ogólnych Circuit kwantowych staje się niewykonalna, gdy liczba Qubit przekracza mniej więcej 50–100. Zauważ jednak, że Circuit efficient_su2 jest parametryzowany kątami na Gate RyR_y i RzR_z. Jeśli wszystkie te kąty zawierają się w zbiorze {0,π2,π,3π2}\{0, \frac{\pi}{2}, \pi, \frac{3\pi}{2}\}, Circuit jest Circuit stabilizatorowym i może być wydajnie symulowany!

W poniższym bloku uruchamiamy Circuit z prymitywem Sampler wspartym symulatorem Circuit stabilizatorowych, używając parametrów wybranych losowo tak, że Circuit jest zagwarantowany jako stabilizatorowy.

import numpy as np
from qiskit.transpiler import generate_preset_pass_manager
from qiskit_aer import AerSimulator
from qiskit_aer.primitives import SamplerV2 as Sampler

measured_circuit = circuit.copy()
measured_circuit.measure_all()

rng = np.random.default_rng(1234)
params = rng.choice(
[0, np.pi / 2, np.pi, 3 * np.pi / 2],
size=circuit.num_parameters,
)

# Initialize a Sampler backed by the stabilizer circuit simulator
exact_sampler = Sampler(
options=dict(backend_options=dict(method="stabilizer"))
)
# The circuit needs to be transpiled to the AerSimulator target
pass_manager = generate_preset_pass_manager(
1, AerSimulator(method="stabilizer")
)
isa_circuit = pass_manager.run(measured_circuit)
pub = (isa_circuit, params)
job = exact_sampler.run([pub])
result = job.result()
pub_result = result[0]
counts = pub_result.data.meas.get_counts()

Symulator Circuit stabilizatorowych obsługuje również symulację zaszumioną, ale tylko dla ograniczonej klasy modeli szumu. W szczególności każdy szum kwantowy musi być scharakteryzowany przez kanał błędu Pauliego. Błąd depolaryzujący wchodzi w tę kategorię, więc może być również symulowany. Klasyczne kanały szumu, takie jak błąd odczytu, mogą być również symulowane.

Poniższy blok kodu uruchamia tę samą symulację co poprzednio, ale tym razem z modelem szumu dodającym błąd depolaryzujący o wartości 2% do każdej Gate CX, a także błąd odczytu, który odwraca każdy mierzony bit z prawdopodobieństwem 5%.

from qiskit_aer.noise import NoiseModel, depolarizing_error, ReadoutError

noise_model = NoiseModel()
cx_depolarizing_prob = 0.02
bit_flip_prob = 0.05
noise_model.add_all_qubit_quantum_error(
depolarizing_error(cx_depolarizing_prob, 2), ["cx"]
)
noise_model.add_all_qubit_readout_error(
ReadoutError(
[
[1 - bit_flip_prob, bit_flip_prob],
[bit_flip_prob, 1 - bit_flip_prob],
]
)
)

noisy_sampler = Sampler(
options=dict(
backend_options=dict(method="stabilizer", noise_model=noise_model)
)
)
job = noisy_sampler.run([pub])
result = job.result()
pub_result = result[0]
counts = pub_result.data.meas.get_counts()

Teraz użyjmy prymitywu Estimator wspartego symulatorem stabilizatorowym, aby obliczyć wartość oczekiwaną obserwabli ZZZZZ \cdots Z. Ze względu na specjalną strukturę Circuit stabilizatorowych wynik najprawdopodobniej wyniesie 0.

from qiskit.quantum_info import SparsePauliOp
from qiskit_aer.primitives import EstimatorV2 as Estimator

observable = SparsePauliOp("Z" * n_qubits)

exact_estimator = Estimator(
options=dict(backend_options=dict(method="stabilizer")),
)
isa_circuit = pass_manager.run(circuit)
pub = (isa_circuit, observable, params)
job = exact_estimator.run([pub])
result = job.result()
pub_result = result[0]
exact_value = float(pub_result.data.evs)
exact_value
0.0

Następne kroki

Rekomendacje