Przejdź do głównej treści

Dokładna i zaszumiona symulacja z prymitywami Qiskit Aer

Wersje pakietów

Kod na tej stronie został opracowany przy użyciu poniższych wymagań. Zalecamy korzystanie z tych lub nowszych wersji.

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

Dokładna symulacja z prymitywami Qiskit pokazuje, jak używać referencyjnych prymitywów dołączonych do Qiskit do wykonywania dokładnej symulacji Circuit kwantowych. Istniejące procesory kwantowe są podatne na błędy, zwane szumem, więc wyniki dokładnej symulacji niekoniecznie odzwierciedlają wyniki uzyskiwane podczas uruchamiania Circuit na prawdziwym sprzęcie. Podczas gdy referencyjne prymitywy w Qiskit nie obsługują modelowania szumu, Qiskit Aer zawiera implementacje prymitywów obsługujące modelowanie szumu. Qiskit Aer to wysokowydajny symulator Circuit kwantowych, którego możesz używać zamiast referencyjnych prymitywów dla lepszej wydajności i większej liczby funkcji. Jest częścią ekosystemu Qiskit. W tym artykule demonstrujemy użycie prymitywów Qiskit Aer do dokładnej i zaszumionej symulacji.

Uwagi
  • Wymagana jest wersja qiskit-aer v0.14 lub nowsza.
  • Choć prymitywy Qiskit Aer implementują interfejsy prymitywów, nie udostępniają tych samych opcji co prymitywy Qiskit Runtime. Na przykład poziom odporności nie jest dostępny w prymitywach Qiskit Aer.
  • Szczegóły dotyczące opcji metod symulacji obsługiwanych przez Aer znajdziesz w dokumentacji AerSimulator.

Aby zbadać dokładną i zaszumioną symulację, utwórzmy przykładowy Circuit na ośmiu Qubitach:

# Added by doQumentation — required packages for this notebook
!pip install -q qiskit qiskit-aer
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 Circuit zawiera parametry reprezentujące kąty obrotu dla Gate RyR_y i RzR_z. Przy symulowaniu tego Circuit musimy podać konkretne wartości dla tych parametrów. W następnej komórce określamy pewne wartości tych parametrów i używamy prymitywu Estimator z Qiskit Aer do obliczenia dokładnej wartości oczekiwanej obserwowalnej ZZZZZ \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 zainicjujemy model szumu uwzględniający błąd depolaryzacyjny o wartości 2% dla każdej Gate CX. W praktyce błędy wynikające z Gate dwuQubitowych, którymi są tutaj Gate CX, są dominującym źródłem błędów przy uruchamianiu Circuit. Informacje na temat konstruowania modeli szumu w Qiskit Aer znajdziesz w artykule Budowanie modeli szumu.

W następnej komórce konstruujemy Estimator uwzględniający ten model szumu i używamy go do obliczenia wartości oczekiwanej obserwowalnej.

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.7247404214143528

Jak widać, wartość oczekiwana w obecności szumu znacznie odbiega od poprawnej wartości. W praktyce można stosować różne techniki mitygacji błędów, aby przeciwdziałać efektom szumu, jednak dyskusja na ich temat wykracza poza zakres tego artykułu.

Aby uzyskać bardzo przybliżone pojęcie o tym, jak szum wpływa na wynik końcowy, rozważmy nasz model szumu, który dodaje błąd depolaryzacyjny o wartości 2% do każdej Gate CX. Błąd depolaryzacyjny z prawdopodobieństwem pp jest zdefiniowany jako kanał kwantowy EE o następującym działaniu na macierzy gęstości ρ\rho:

E(ρ)=(1p)ρ+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 stanem całkowicie mieszanym, a z prawdopodobieństwem 1p1 - p stan jest zachowywany. Po mm zastosowaniach kanału depolaryzacyjnego prawdopodobieństwo zachowania stanu wyniosłoby (1p)m(1 - p)^m. Dlatego spodziewamy się, że prawdopodobieństwo zachowania poprawnego stanu na końcu symulacji maleje wykładniczo wraz z liczbą Gate CX w naszym Circuit.

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

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

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

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

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()
{'00100000': 1,
'00000000': 65,
'10101000': 1,
'10000000': 5,
'00001000': 1,
'00000110': 2,
'11110010': 1,
'00000011': 3,
'01010000': 3,
'11000000': 3,
'01111000': 1,
'01000000': 2,
'00000010': 1,
'01100000': 1,
'00011000': 1,
'00111100': 1,
'00010100': 1,
'00001111': 1,
'00110000': 1,
'01100101': 1,
'00000100': 1,
'10100000': 1,
'00000001': 1,
'11010000': 1}

Następne kroki

Rekomendacje