Przejdź do głównej treści

Twój pierwszy eksperyment kwantowy

Wprowadzenie

W poniższym filmie Olivia Lanes przeprowadza cię przez materiał z tej lekcji. Możesz też otworzyć film na YouTube dotyczący tej lekcji w osobnym oknie.

Do tej pory uruchomiłeś swój pierwszy Circuit kwantowy i poznałeś podstawy obliczeń kwantowych: jak reprezentuje się stany kwantowe, jak Gate'y działają na te stany oraz jak kwantowe właściwości — superpozycja i splątanie — są w to zaangażowane. Czas teraz zastosować to wszystko w praktyce i rozwiązać swój pierwszy problem na komputerze kwantowym.

Szerszy krajobraz problemów nadających się do rozwiązania kwantowego omówimy w późniejszej lekcji. Na razie skupimy się na problemie z dziedziny symulacji natury: użyciu komputera kwantowego jako czystszego i bardziej kontrolowalnego substytutu naturalnego układu kwantowego. W rzeczywistości było to pierwsze zastosowanie, jakie Richard Feynman przewidział dla komputerów kwantowych w latach 80. Jak słynnie ujął: „Natura nie jest klasyczna, do diabła, a jeśli chcesz symulować naturę, lepiej zrób to kwantowo-mechanicznie..."

W tej lekcji będziemy postępować zgodnie z tą zasadą, symulując oddziaływanie między dwoma spinami, które możesz wyobrazić sobie jako małe magnesy. W zależności od znaku ich oddziaływania mogą preferować wyrównanie i wskazywanie w tym samym kierunku albo przeciwne wyrównanie i wskazywanie w przeciwnych kierunkach. Skupimy się na tym ostatnim przypadku, ponieważ często prowadzi do ciekawszego — i trudniejszego — zachowania. Gdy zrozumiemy ten mały układ dwuqubitowy, pokażemy, jak te same idee się skalują, pozwalając komputerom kwantowym wykorzystać wykładnicze skalowanie przy symulacji dużych układów spinowych.

Dwa oddziałujące magnesy

W tym problemie użyjemy dwóch Qubitów, po jednym na każdy spin w naszym modelu. Każdy spin może wskazywać w górę (stan Qubitu 0|0\rangle), w dół (stan Qubitu 1|1\rangle) lub być w superpozycji obu stanów.

Jeśli spiny mają oddziaływanie antyferromagnetyczne, oznacza to, że chcą się ustawić przeciwnie: gdy jeden jest skierowany w górę, drugi woli być skierowany w dół i odwrotnie.

Załóżmy teraz, że w naszym układzie istnieje również pole magnetyczne skierowane od lewej do prawej. Ponieważ pole to wskazuje prostopadle do zwykłego kierunku góra-dół spinów, nazywane jest polem poprzecznym. Pole to może przewracać spiny, co sprawia, że konfiguracja o najniższej energii jest pewną superpozycją ułożeń spinów góra-dół, a nie jakimkolwiek pojedynczym określonym wzorcem spinowym.

Wszystkie te efekty możemy opisać przy użyciu obiektu matematycznego zwanego Hamiltonianem. Hamiltonian mówi nam o energii układu dla danego ułożenia spinów:

H=JZ1Z0+hx(X1+X0)H = J Z_1 Z_0 + h_x (X_1 + X_0)

gdzie JJ to współczynnik kontrolujący siłę oddziaływania między spinami, a hxh_x to współczynnik siły zewnętrznego pola magnetycznego. Z1Z0Z_1 Z_0 nagradza lub karze spiny w zależności od tego, czy są wyrównane, czy przeciwnie wyrównane, natomiast X0X_0 i X1X_1 reprezentują efekt przewracania spinów przez pole magnetyczne.

W fizyce układy dążą do osiągnięcia stanu o najniższej możliwej energii, zwanego stanem podstawowym. Znalezienie tego stanu o najniższej energii jest powszechnym problemem, ale wymaga technik optymalizacji wykraczających poza zakres tej lekcji.

Zamiast tego zadamy prostsze pytanie: Jeśli przygotujemy spiny w określonym stanie, jaka jest energia tego stanu?

Aby odpowiedzieć na to pytanie:

  1. Przygotujemy spiny w wybranym przez nas stanie
  2. Zmierzymy energię tego stanu za pomocą powyższego Hamiltonianu

Jest to dokładnie rodzaj obliczeń, który pojawia się wewnątrz większych algorytmów kwantowych, takich jak algorytmy wariacyjne, które możesz zgłębiać w późniejszych kursach.

Implementacja w Qiskit

Zanim przejdziemy do pisania kodu, potrzebujemy trochę kontekstu. Gdy uruchamiamy Circuit kwantowy, zawsze kończymy pomiarem Qubitów. Istnieją jednak dwa różne rodzaje pytań, jakie możemy chcieć zadać dotyczące wyniku tego pomiaru: Czasem po prostu chcemy wiedzieć, jaki jest stan Qubitu. Innym razem chcemy wiedzieć, jaka jest wartość fizycznej wielkości, np. energii, dla danego stanu kwantowego.

W Qiskit te dwa rodzaje pytań obsługiwane są przez dwa różne narzędzia, zwane prymitywami.

Sampler odpowiada na pierwszy rodzaj pytania. Uruchamia Circuit wiele razy i mówi nam, jak często mierzymy każdy możliwy wynik, na przykład 00, 01, 10 lub 11. Wynikiem jest histogram pokazujący prawdopodobieństwo każdego wyniku pomiaru.

Estimator odpowiada na drugi rodzaj pytania. Zamiast dawać histogram, łączy wiele pomiarów w tle, aby obliczyć pojedynczą liczbę, np. energię stanu zgodnie z podanym przez nas Hamiltonianem.

Aby pomóc ci zrozumieć, kiedy i dlaczego używamy każdego z tych narzędzi, przeprowadzimy cię przez dwa kompletne przepływy pracy (zwane „wzorcami Qiskit") zastosowane do tego samego układu dwuqubitowego.

Przepływ pracy wzorców Qiskit

Przepływ pracy wzorców Qiskit to ogólny framework używany do rozwiązywania problemów kwantowych za pomocą Qiskit. Dzieli zadanie obliczeniowe na cztery kroki:

  1. Odwzorowanie problemu na model, który można reprezentować przez Circuit kwantowe
  2. Optymalizacja Circuit do uruchomienia na konkretnym Backend'zie
  3. Wykonanie zoptymalizowanego Circuit na wybranym Backend'zie
  4. Przetwarzanie końcowe surowych danych pomiarowych

Eksperyment 1: Użyj Sampler do pomiaru stanu

Odwzorowanie

Ogólnie rzecz biorąc, krok odwzorowania to moment, w którym ustalamy, jak przedstawić rzeczywisty problem w kategoriach Qubitów, operatorów i pomiarów. W wielu zastosowaniach jest to najtrudniejsza i najbardziej złożona część przepływu pracy — nawet proste pytania, takie jak „co reprezentuje każdy Qubit?", nie zawsze mają jednoznaczne odpowiedzi.

W tym eksperymencie odwzorowanie jest jednak celowo proste. Każdy fizyczny stopień swobody jest bezpośrednio odwzorowany na jeden Qubit. Dzięki tej korespondencji jeden do jednego krok odwzorowania sprowadza się do wybrania stanu kwantowego, który chcemy przygotować, i napisania Circuit, który go przygotowuje i mierzy.

Tutaj przygotujemy splątany stan Bella, podobny do tego, który stworzyliśmy w pierwszej lekcji tego kursu:

Ψ=12(1001)\vert\Psi\rangle = \frac{1}{\sqrt{2}}(\vert 10\rangle - \vert 01\rangle)
# Added by doQumentation — required packages for this notebook
!pip install -q qiskit qiskit-ibm-runtime
# Import Qiskit primitives
from qiskit import QuantumCircuit

# Make state
qc = QuantumCircuit(2)
qc.h(0)
qc.cx(0, 1)
qc.x(1)
qc.z(0)

# Measure state
qc.measure_all()

# Draw circuit
qc.draw("mpl")

Output of the previous code cell

Optymalizacja

Zanim uruchomimy nasz Circuit na komputerze kwantowym (lub symulatorze, jeśli wyczerpałeś bezpłatny czas na prawdziwych komputerach kwantowych w tym miesiącu), musimy go przygotować do wykonania. Ten krok nazywa się optymalizacją. (Uwaga: użycie słowa „optymalizacja" może być mylące. W obliczeniach kwantowych problemy optymalizacyjne odnoszą się do konkretnej klasy problemów. Tutaj używamy optymalizacji do opisania wymaganego kroku przygotowawczego, przez który przechodzi każdy Circuit kwantowy przed efektywnym uruchomieniem na sprzęcie.)

Podczas optymalizacji:

  1. Wybieramy Backend — prawdziwy komputer kwantowy lub symulator.
  2. Przypisujemy Qubity naszego Circuit do fizycznych Qubitów na urządzeniu.
  3. Przepisujemy Circuit, używając wyłącznie Gate'ów, które komputer kwantowy jest w stanie wykonać.
  4. Opcjonalnie implementujemy techniki mitygacji i tłumienia błędów, aby zmniejszyć wpływ szumów.

W Qiskit zajmuje się tym automatycznie Transpiler. Gdy wybierzesz Backend, Transpiler wykonuje całą pracę, aby Twój Circuit był gotowy do wykonania — nie musisz ręcznie dostosowywać Gate'ów ani przypisań Qubitów. Transpiler oferuje również różne poziomy optymalizacji, które mogą pomóc w redukcji błędów. Optymalizacja odbywa się w etapach zwanych „przebiegami" (passes). Ta optymalizacja jest obsługiwana przez pass_manager w poniższym kodzie. Aby dowiedzieć się więcej o błędach i mitygacji błędów, zapoznaj się z kursem Olivii Lanes Quantum Computing in Practice.

# Load the Qiskit Runtime service
from qiskit_ibm_runtime import QiskitRuntimeService

## Load the Qiskit Runtime service
# QiskitRuntimeService.save_account(
# channel="ibm_quantum_platform",
# token="YOUR_TOKEN_HERE",
# overwrite=True,
# set_as_default=True,
# )
# service = QiskitRuntimeService(channel="ibm_quantum_platform")

# Or load saved credentials
service = QiskitRuntimeService()

# Use the least busy backend, or uncomment the loading of a specific backend like "ibm_brisbane".
backend = service.least_busy(operational=True, simulator=False, min_num_qubits=127)
# backend = service.backend("ibm_brisbane")
print(backend.name)
ibm_fez
# Transpile the circuit and optimize for running on the quantum computer selected
# Step 2: Transpile
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager

target = backend.target
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc)

qc_isa.draw("mpl")

Output of the previous code cell

Wykonanie

Teraz jesteśmy gotowi do wykonania! Załadujemy Sampler, a następnie wyślemy zadanie do Backend'u.

# Load the Runtime primitive and session
from qiskit_ibm_runtime import SamplerV2 as Sampler

sampler = Sampler(mode=backend)

Jeśli używasz symulatora, możesz odkomentować i uruchomić tę komórkę:

## Load the backend sampler
# from qiskit.primitives import BackendSamplerV2

## Load the Aer simulator and generate a noise model based on the currently-selected backend.
# from qiskit_aer import AerSimulator
# from qiskit_aer.noise import NoiseModel

# noise_model = NoiseModel.from_backend(backend)

## Define a simulator using Aer, and use it in Sampler.
# backend_sim = AerSimulator(noise_model=noise_model)
# sampler_sim = BackendSamplerV2(backend=backend_sim)

## Alternatively, load a fake backend with generic properties and define a simulator.
## backend_gen = GenericBackendV2(num_qubits=18)
## sampler_gen = BackendSamplerV2(backend=backend_gen)
job = sampler.run([qc_isa], shots=100)
# job = sampler_sim.run([qc_isa]) # uncomment if you want to run on a simulator
res = job.result()
counts = res[0].data.meas.get_counts()

Przetwarzanie końcowe

from qiskit.visualization import plot_histogram

print("counts = ", counts)
plot_histogram(counts)
counts =  {'10': 49, '01': 50, '11': 1}

Output of the previous code cell

Widzimy, że większość zliczeń przypada na 01 lub 10, co oznacza, że gdy jeden Qubit był mierzony jako 0, drugi wynosił 1 i odwrotnie. Jest to zgodne ze stanem Bella Ψ\vert \Psi^- \rangle, który przygotowaliśmy.

Eksperyment 2: Użyj Estimator do pomiaru energii

Teraz, gdy zobaczyliśmy, jak próbkować stan kwantowy, użyjmy Estimatora do obliczenia energii naszego stanu Bella Ψ=12(0110)\vert \Psi^- \rangle = \frac{1}{\sqrt{2}}(\vert 01 \rangle - \vert 10 \rangle).

Odwzorowanie

Dla przypomnienia: energia układu jest zdeterminowana przez oddziaływanie między spinami (JJ) i zewnętrzne pole magnetyczne (hxh_x), co jest ujęte przez Hamiltonian:

H=JZ1Z0+hx(X1+X0)H = J Z_1 Z_0 + h_x (X_1 + X_0)

Każdy człon Hamiltonianu mówi nam, jak określona kombinacja spinów przyczynia się do energii. W Qiskit możemy reprezentować te człony jako operatory Pauliego, które są po prostu etykietami prostych działań na Qubitach:

  • Z1Z0Z_1 Z_0 działa przez ZZ na obu Qubitach.
  • X0X_0 działa przez XX na Qubicie 0.
  • X1X_1 działa przez XX na Qubicie 1.

SparsePauliOp w Qiskit to sposób na przechowywanie listy tych operatorów Pauliego wraz z ich numerycznymi współczynnikami. Te operatory Pauliego są obserwablami, które chcemy, aby komputer kwantowy zmierzył — wielkościami, które mówią nam o układzie. Używając Estimator, możemy obliczyć średnią wartość każdej obserwabli dla naszego stanu i połączyć je zgodnie ze współczynnikami w Hamiltonianie, aby uzyskać całkowitą energię.

# Import Qiskit primitives
from qiskit.quantum_info import SparsePauliOp

# Parameters
J = 1.0 # antiferromagnetic coupling (J<0)
hx = -0.5 # transverse field strength

# 1. Define the Hamiltonian H = J Z1 Z2 + hx (X1 + X2)
obs = SparsePauliOp.from_list([("ZZ", J), ("XI", hx), ("IX", hx)])

# Make state
qc = QuantumCircuit(2)
qc.h(0)
qc.cx(0, 1)
qc.x(1)
qc.z(0)
<qiskit.circuit.instructionset.InstructionSet at 0x1387ed630>

Zwróć uwagę, że pominęliśmy linię qc.measure_all() w naszym kodzie. Dzieje się tak, ponieważ w przypadku Estimator nie musimy określać, gdzie mierzyć w Circuit. Powiemy mu jedynie, które obserwable chcemy oszacować, a Qiskit zajmie się pomiarami w tle.

Optymalizacja

Krok optymalizacji przebiega jak poprzednio, z tym że dodatkowo upewniamy się, że nasze obserwable są również zapisane w sposób zrozumiały dla komputera kwantowego.

# Transpile the circuit and optimize for running on the quantum computer selected
# Step 2: Transpile
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager

target = backend.target
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc)
obs_isa = obs.apply_layout(layout=qc_isa.layout)

qc_isa.draw("mpl")

Output of the previous code cell

Wykonanie

W kroku wykonania załadujemy Estimator, a następnie wyślemy Circuit wraz z listą obserwabli do oszacowania do komputera kwantowego.

# Load the Runtime primitive and session
from qiskit_ibm_runtime import EstimatorV2 as Estimator

estimator = Estimator(mode=backend)
# Load the backend sampler

# noise_model = NoiseModel.from_backend(backend)

# Use Aer simulator in Estimator
# estimator_sim = BackendEstimatorV2(backend=backend_sim)

# Alternatively, load a fake backend with generic properties and define a simulator.
# backend_gen = GenericBackendV2(num_qubits=18)
# estimator_gen = BackendEstimatorV2(backend=backend_gen)
pubs = [(qc_isa, obs_isa)]
job = estimator.run([[qc_isa, obs_isa]])
res = job.result()

# Uncomment lines below to run the job on the Aer simulator with noise model from real backend
# job = estimator_sim.run([[qc_isa,obs_isa]])
# res=job.result()

Przetwarzanie końcowe

Na koniec, w kroku przetwarzania końcowego, po prostu drukujemy energię obliczoną przez Estimator w tle.

print(res[0].data.evs)
-0.9934112021453058

To jest energia naszego stanu!

Podsumowanie

W tej lekcji nauczyliśmy się, jak przygotować prosty dwuqubitowy stan kwantowy reprezentujący dwa oddziałujące spiny. Zobaczyliśmy, jak używać Sampler do obserwowania rozkładu wyników pomiarów i jak używać Estimator do obliczenia energii stanu zgodnie z Hamiltonianem. Po drodze zobaczyliśmy, jak Hamiltonian koduje oddziaływania między spinami i efekty zewnętrznego pola, oraz jak różne stany mogą mieć różne energie.

Rozszerzenie na wiele spinów

Do tej pory patrzyliśmy tylko na dwa spiny, co jest wystarczająco proste do przeanalizowania ręcznie. W rzeczywistych układach fizycznych, takich jak magnes lub inne złożone materiały, często istnieje wiele oddziałujących spinów. Gdy liczba spinów rośnie, Hamiltonian staje się bardziej złożony, a znalezienie stanu o najniższej energii jest znacznie trudniejsze. Tu właśnie mogą pomóc komputery kwantowe: przygotowując różne stany i szacując ich energie, możemy badać konfiguracje niskoen­ergetyczne efektywniej niż komputery klasyczne dla dużych układów.

Naturalnym rozszerzeniem tego eksperymentu byłoby zwiększenie liczby Qubitów reprezentujących więcej spinów i dostosowanie sposobu przygotowania spinów, aby spróbować znaleźć stan o najniższej energii. To podejście jest istotą metod wariacyjnych, o których możesz się dowiedzieć w kursie Variational Quantum Algorithms.

Istnieją też inne kwantowe podejścia do badania energii stanu podstawowego, wykraczające poza techniki wariacyjne. Metody te nie są tu omówione, ale zostają przedstawione w kursie Quantum Diagonalization Algorithms, jeśli chcesz dowiedzieć się więcej.

Cel nauki

Wróć do początku Eksperymentu 2 i spróbuj ponownie z innym stanem superpozycji. Czy uda ci się znaleźć stan o jeszcze niższej energii niż ten, którego użyliśmy?

This translation based on the English version of 7 maj 2026