Przejdź do głównej treści
Ten projekt jest w wersji beta. Znalazłeś błąd? Otwórz zgłoszenie na GitHub. Masz pytanie lub pomysł? Zapytaj w Discussions — chętnie poznamy Twoją opinię!
Jak oceniasz jakość tłumaczenia tej strony?

Dokładna i zaszumiona symulacja z prymitywami Qiskit Aer

Wersje pakietów

Kod na tej stronie przygotowano z użyciem poniższych wersji pakietów. Zalecamy korzystanie z tych lub nowszych wersji.

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

Dokładna symulacja z prymitywami Qiskit SDK pokazuje, jak używać prymitywów referencyjnych dołączonych do Qiskit do przeprowadzania dokładnej symulacji obwodów kwantowych. Obecnie istniejące procesory kwantowe są obarczone błędami, czyli szumem, więc wyniki dokładnej symulacji niekoniecznie odzwierciedlają wyniki, jakich można by oczekiwać podczas uruchamiania obwodów na rzeczywistym sprzęcie. Podczas gdy prymitywy referencyjne w Qiskit nie obsługują modelowania szumu, Qiskit Aer zawiera implementacje prymitywów, które obsługują modelowanie szumu. Qiskit Aer to wysokowydajny symulator obwodów kwantowych, którego można używać zamiast prymitywów referencyjnych, aby uzyskać lepszą wydajność i więcej funkcji. Jest częścią Qiskit Ecosystem. W tym artykule pokazujemy użycie prymitywów Qiskit Aer do dokładnej i zaszumionej symulacji.

Uwagi
  • Wymagana jest wersja qiskit-aer 0.14 lub nowsza.
  • Chociaż prymitywy Qiskit Aer implementują interfejsy prymitywów, nie oferują tych samych opcji co prymitywy IBM Quantum. Na przykład poziom odporności (resilience level) nie jest dostępny w prymitywach Qiskit Aer.
  • Zobacz dokumentację AerSimulator po szczegóły dotyczące opcji metod symulacji obsługiwanych przez Aer.

Aby zbadać symulację dokładną i zaszumioną, utwórz przykładowy obwód na ośmiu qubitach:

# Added by doQumentation — installs the packages this notebook needs if they are missing
import importlib.util

_needed = {"qiskit": "qiskit", "qiskit_aer": "qiskit-aer"}
_missing = [pip for module, pip in _needed.items()
if importlib.util.find_spec(module) is None]
# One at a time, so a package that fails to install does not block the others
for _pip in _missing:
%pip install -q {_pip}
if not _missing:
print("\u2713 All required packages are installed")
from qiskit.circuit.library import efficient_su2

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

Output of the previous code cell

Ten obwód zawiera parametry reprezentujące kąty obrotu dla bramek RyR_y i RzR_z. Podczas symulacji tego obwodu musimy określić jawne wartości dla tych parametrów. W następnej komórce określamy pewne wartości dla tych parametrów i używamy prymitywu Estimator z Qiskit Aer, aby obliczyć dokładną wartość oczekiwaną obserwabli ZZ⋯ZZZ \cdots Z.

from qiskit.quantum_info import SparsePauliOp
from qiskit.transpiler import generate_preset_pass_manager
from qiskit_aer import AerSimulator
from qiskit_aer.primitives import EstimatorV2 as Estimator

observable = SparsePauliOp("Z" * n_qubits)
params = [0.1] * circuit.num_parameters

exact_estimator = Estimator()
# The circuit needs to be transpiled to the AerSimulator target
pass_manager = generate_preset_pass_manager(3, AerSimulator())
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.8870140234256602

Teraz zainicjujmy model szumu, który zawiera błąd depolaryzacji na poziomie 2% na każdej bramce CX. W praktyce błąd wynikający z bramek dwuqubitowych, którymi są tutaj bramki CX, jest dominującym źródłem błędu podczas wykonywania obwodu. Zobacz Budowanie modeli szumu, aby uzyskać przegląd konstruowania modeli szumu w Qiskit Aer.

W następnej komórce konstruujemy Estimator, który uwzględnia ten model szumu, i używamy go do obliczenia wartości oczekiwanej obserwabli.

from qiskit_aer.noise import NoiseModel, depolarizing_error

noise_model = NoiseModel()
cx_depolarizing_prob = 0.02
noise_model.add_all_qubit_quantum_error(
depolarizing_error(cx_depolarizing_prob, 2), ["cx"]
)

noisy_estimator = Estimator(
options=dict(backend_options=dict(noise_model=noise_model))
)
job = noisy_estimator.run([pub])
result = job.result()
pub_result = result[0]
noisy_value = float(pub_result.data.evs)
noisy_value
0.7247404214143529

Jak widać, wartość oczekiwana w obecności szumu jest dość odległa od poprawnej wartości. W praktyce można zastosować różne techniki łagodzenia błędów, aby przeciwdziałać skutkom szumu, jednak omówienie tych technik wykracza poza zakres tego artykułu.

Aby uzyskać bardzo przybliżone wyobrażenie o tym, jak szum wpływa na wynik końcowy, rozważmy nasz model szumu, który dodaje błąd depolaryzacji na poziomie 2% do każdej bramki CX. Błąd depolaryzacji z prawdopodobieństwem pp jest zdefiniowany jako kanał kwantowy EE, który działa na macierz gęstości ρ\rho w następujący sposób:

E(ρ)=(1−p)ρ+pI2nE(\rho) = (1 - p) \rho + p\frac{I}{2^n}

gdzie nn to liczba qubitów, w tym przypadku 2. Oznacza to, że z prawdopodobieństwem pp stan jest zastępowany całkowicie zmieszanym stanem, a stan jest zachowywany z prawdopodobieństwem 1−p1 - p. Po mm zastosowaniach kanału depolaryzującego prawdopodobieństwo zachowania stanu wyniosłoby (1−p)m(1 - p)^m. Dlatego spodziewamy się, że prawdopodobieństwo zachowania poprawnego stanu na końcu symulacji będzie maleć wykładniczo wraz z liczbą bramek CX w naszym obwodzie.

Policzmy liczbę bramek CX w naszym obwodzie i obliczmy (1−p)m(1 - p)^m. Wywołujemy count_ops, aby uzyskać słownik mapujący nazwy bramek na ich liczbę, i pobieramy wpis dla bramki CX.

cx_count = circuit.count_ops()["cx"]
(1 - cx_depolarizing_prob) ** cx_count
0.6542558123199923

Ta wartość, 65%, daje przybliżone oszacowanie prawdopodobieństwa, że nasz stan końcowy jest poprawny. Jest to konserwatywne oszacowanie, ponieważ nie uwzględnia ono stanu początkowego symulacji.

Poniższa komórka kodu pokazuje, jak użyć prymitywu Sampler z Qiskit Aer do próbkowania z zaszumionego obwodu. Przed uruchomieniem obwodu z prymitywem Sampler musimy dodać do niego pomiary.

from qiskit_aer.primitives import SamplerV2 as Sampler

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

noisy_sampler = Sampler(
options=dict(backend_options=dict(noise_model=noise_model))
)
# The circuit needs to be transpiled to the AerSimulator target
pass_manager = generate_preset_pass_manager(3, AerSimulator())
isa_circuit = pass_manager.run(measured_circuit)
pub = (isa_circuit, params, 100)
job = noisy_sampler.run([pub])
result = job.result()
pub_result = result[0]
pub_result.data.meas.get_counts()
{'00000000': 69,
'00100000': 2,
'00000110': 1,
'11000000': 2,
'00010100': 1,
'01100000': 2,
'01010000': 3,
'00101000': 1,
'10100000': 2,
'01100101': 1,
'00001010': 1,
'10000000': 2,
'00000010': 3,
'01000000': 4,
'11100000': 1,
'10000101': 1,
'00110000': 1,
'00001100': 1,
'00011000': 2}

Następne kroki​

Zalecenia