Przejdź do głównej treści

SQD i SKQD

W tym rozdziale przyjrzymy się, jak komputery kwantowe i klasyczne współpracują ze sobą, aby rozwiązać jedno z najważniejszych wyzwań nauki: dokładne szacowanie energii cząsteczek i materiałów.

Iskandar Sitdikov opisuje podejście algorytmiczne w poniższym filmie.

Hamiltonian

Kluczem do tego problemu jest operator matematyczny — Hamiltonian, który reprezentuje całkowitą energię układu. Na potrzeby obliczeń możemy myśleć o tym Hamiltonianie jak o dużej macierzy. Szukanych przez nas rozwiązań — konkretnie ground state układu — należy szukać wśród najniższych wartości własnych tej macierzy. Problem polega jednak na tym, że w praktycznych zastosowaniach macierz Hamiltonianu jest bardzo duża. Rośnie wykładniczo wraz z rozmiarem układu, szybko stając się zbyt wielka (2n2^n, gdzie nn to liczba qubitów), aby nawet najpotężniejsze superkomputery mogły ją zapisać lub rozwiązać bezpośrednio.

H=(H0,0H0,1H0,N1H1,0H1,1H1,N1HN1,0HN1,1HN1,N1)(N=2n)H = \begin{pmatrix} H_{0,0} & H_{0,1} & \cdots & H_{0,N-1} \\ H_{1,0} & H_{1,1} & \cdots & H_{1,N-1} \\ \vdots & \vdots & \ddots & \vdots \\ H_{N-1,0} & H_{N-1,1} & \cdots & H_{N-1,N-1} \end{pmatrix} \quad (N=2^n)

Aby to obejść, stosujemy potężną strategię zwaną metodą podprzestrzeni. Zamiast atakować całą macierz, inteligentnie wybieramy mały, istotny wycinek — „podprzestrzeń" — o której sądzimy, że zawiera najważniejsze informacje dotyczące szukanego rozwiązania niskoenergetycznego.

(Hi,j)Full HamiltonianProjectH~Projected Hamiltonian=(b1Hb1b1HbLbLHb1bLHbL)Diagonalize(E000EL1)Eigenvalues\underset{\text{Full Hamiltonian}}{\begin{pmatrix} \ddots & \vdots \\ \cdots & H_{i,j} & \cdots \\ & \vdots & \ddots \end{pmatrix}} \quad \xrightarrow{\text{Project}} \quad \underset{\text{Projected Hamiltonian}}{\tilde{H}} = \begin{pmatrix} \langle b_1 | H | b_1 \rangle & \cdots & \langle b_1 | H | b_L \rangle \\ \vdots & \ddots & \vdots \\ \langle b_L | H | b_1 \rangle & \cdots & \langle b_L | H | b_L \rangle \end{pmatrix} \quad \xrightarrow{\text{Diagonalize}} \quad \underset{\text{Eigenvalues}}{\begin{pmatrix} E_0 & & 0 \\ & \ddots & \\ 0 & & E_{L-1} \end{pmatrix}}

Po zdefiniowaniu tej małej podprzestrzeni za pomocą zbioru stanów bazowych {bi}\{|b_i\rangle\} pełny Hamiltonian jest na nią rzutowany, tworząc nową, mniejszą macierz H~\tilde{H}. Każdy element tej macierzy jest obliczany na podstawie stanów bazowych podprzestrzeni i oryginalnego Hamiltonianu jako biHbj\langle b_i | H | b_j \rangle. Ta mała macierz może następnie zostać łatwo zdiagonalizowana na komputerze klasycznym, a wynikające z tego wartości własne są naszymi szacowanymi energiami.

Jak można się domyślić, sukces całego tego podejścia w dużej mierze zależy od wyboru „dobrej" podprzestrzeni. Jeśli nasza podprzestrzeń nie reprezentuje dokładnie prawdziwego ground state, ostateczna odpowiedź będzie błędna. Tu właśnie z pomocą przychodzą komputery kwantowe: pozwalają nam przygotowywać i próbkować złożone stany kwantowe zaprojektowane do identyfikowania tych ważnych podprzestrzeni. W przypadku naprawdę ogromnych problemów — jak złożone struktury chemiczne czy miejsca wiązania — nawet rzutowana macierz może być trudna do zdiagonalizowania. Dlatego takie problemy idealnie nadają się do wykorzystania mocnych stron zarówno kwantowych, jak i klasycznych zasobów obliczeniowych.

W kolejnych sekcjach przyjrzymy się dwóm zaawansowanym algorytmom, SQD i SKQD, które wykorzystują mechanikę kwantową do znajdowania i konstruowania tych podprzestrzeni. Dla dogłębniejszego zapoznania się z tematem istnieje pełny kurs na IBM Quantum Learning poświęcony tym zagadnieniom. Na potrzeby tego kursu utrzymamy wyjaśnienia na wysokim poziomie ogólności.

Sample-based Quantum Diagonalization

Sample-based Quantum Diagonalization (SQD) to potężny algorytm wariacyjny implementujący metodę podprzestrzeni w sposób kwantowy. Unika kosztownych i skomplikowanych procedur, takich jak testy Hadamarda, wykorzystując komputer kwantowy do przygotowania stanu próbnego i próbkowania bitciągów, które definiują podprzestrzeń do klasycznej diagonalizacji.

A schematic of the workflow specific to sample-based quantum diagonalization. The steps include a variational quantum circuit, using measurements to project the Hamiltonian into a subspace, then using a classical optimizer to update variational parameters in the circuit and repeating.

Algorytm SQD można podzielić na następujące kroki:

Krok 1: Przygotowanie stanu ansatz

Niech H=j=1QαjPjH = \sum_{j=1}^Q \alpha_j P_j będzie Hamiltonianem na nn qubitach. Choć prawdziwy ground state może być oparty na wszystkich 2n2^n stanach bazowych, SQD jest najbardziej efektywny w przypadkach, gdy ground state można dobrze aproksymować przez rzadką podprzestrzeń (wielomianowy zbiór bitciągów).

Aby zbudować tę podprzestrzeń, zaczynamy od stanu wejściowego ϕ0|\phi_0\rangle, takiego jak stan Hartree-Focka (HF) w chemii. Następnie stosujemy sparametryzowany obwód kwantowy U(θ)U(\theta), znany jako ansatz.

A diagram showing the overlap of the computational basis states making up the ansatz and those making up the true ground state. Specifically, the image shows that the two regions will have some overlap, but might not perfectly match.

Ten diagram ilustruje cel dobrego ansatzu. Ansatz przygotowuje stan kwantowy, którego nośnik (zbiór stanów bazowych, z których się składa) powinien idealnie mieć duże pokrycie z nośnikiem prawdziwego ground state. Ten obwód pozwala nam szybko rzutować ansatz na stany bazowe przestrzeni obliczeniowej, które zostaną następnie użyte w klasycznej diagonalizacji. Innymi słowy: nie musimy zgadywać ansatzu będącego ground state; wystarczy, że zawiera te same stany bazowe. Klasyczna diagonalizacja rzutowanego Hamiltonianu da nam superpozycję stanów bazowych najlepiej aproksymującą ground state.

Krok 2: Próbkowanie podprzestrzeni

Poprzez próbkowanie z obwodu przygotowanego przez ansatz otrzymujemy kolekcję bitciągów {bj}j=1L\{b_j\}_{j=1}^L. Te bitciągi definiują bazę wybranej przez nas podprzestrzeni. Czas działania kwantowego w tym kroku zależy od głębokości obwodu i liczby pobranych próbek.

Krok 3: Rzutowanie i klasyczna diagonalizacja

Używając spróbkowanych bitciągów, rzutujemy Hamiltonian na podprzestrzeń przez nie rozpiętą. Dla każdej pary bitciągów (j,k)(j, k) klasycznie obliczamy element macierzy H~jk=bjHbk\tilde{H}_{jk} = \langle b_j | H | b_k \rangle. Ponieważ operatory Pauliego są rzadkie, ten krok jest klasycznie efektywny dla fizycznych Hamiltonianów. Wynikowa mała macierz H~\tilde{H} jest następnie diagonalizowana na procesorze klasycznym w celu oszacowania ground state i jego energii.

Krok 4: Optymalizacja ansatzu (opcjonalnie)

Proces można uczynić iteracyjnym. Traktując oszacowaną energię ground state jako funkcję kosztu, możemy optymalizować parametry obwodu (θ\theta) metodami takimi jak gradient descent, aby ulepszać ansatz, a co za tym idzie — aproksymację energii w kolejnej iteracji.

Key advantages of SQD

SQD oferuje kilka potężnych cech, które czynią go czołowym kandydatem do demonstrowania przewagi kwantowej:

  • Duża odporność na szum: Załóżmy, że prawdziwy ground state jest oparty tylko na dwóch bitciągach. Jeśli zostaną one w ogóle spróbkowane — nawet jeśli ich pokrycie z naszym ansatzem jest małe — diagonalizacja przypisze im odpowiednie wagi i skutecznie zignoruje wszystkie inne zbędne, zaszumione bitciągi, które mogły zostać spróbkowane. Ta wbudowana filtracja sprawia, że SQD jest szczególnie odporny na szumy.
  • Klasyczna weryfikowalność: W odróżnieniu od QPE czy VQA, SQD daje klasyczną aproksymację ground state. Oznacza to, że każdy, kto ma dostęp do listy bitciągów i ich wag, może samodzielnie przeliczyć i zweryfikować oszacowanie energii bezpośrednio na komputerze klasycznym.

SQD zostało już użyte do oszacowania energii dysocjacji ground state cząsteczki N2_2 oraz właściwości elektronowych klastrów [2Fe-2S] i [4Fe-4S] [2], z obwodami o rozmiarze do 77 qubitów i 10 570 bramek.

Check your understanding

Prawda czy fałsz: SQD można zastosować do układów chemicznych.

Odpowiedź:

Prawda

Check your understanding

Oznacz zbiór wszystkich stanów bazowych przestrzeni obliczeniowej tworzących twój ansatz jako AA. Oznacz zbiór wszystkich stanów bazowych przestrzeni obliczeniowej tworzących prawdziwy ground state twojego układu jako GG. Który z poniższych przypadków odpowiada „dobremu" ansatzowi? Zaznacz wszystkie poprawne odpowiedzi.

(a) AGA \subset G \\ (b) AGA \subseteq G\\ (c) GAG \subset A\\ (d) GAG \subseteq A\\

Odpowiedź:

(c) i (d)

SKQD (Sample-based Krylov Quantum Diagonalization)

Sample-based Krylov Quantum Diagonalization (SKQD) to kolejny potężny kwantowy algorytm oparty na próbkowaniu, który bazuje na zasadach SQD. Choć jego cel jest ten sam — znalezienie dobrej podprzestrzeni do diagonalizacji — SKQD stosuje bardziej ustrukturyzowaną metodę generowania bitciągów, szczególnie w przypadku problemów takich jak sieciowe Hamiltoniany.

Podstawowa idea SKQD polega na tym, że zamiast optymalizować sparametryzowany obwód w celu znalezienia dobrego ansatzu, można w dowiedziony sposób zbiegać do stanu podstawowego poprzez próbkowanie ze zbioru stanów wygenerowanych przez naturalną ewolucję czasową samego układu — podprzestrzeń Krylov. Algorytm SKQD można rozbić na następujące kroki:

Krok 1: Zbuduj podprzestrzeń Krylov za pomocą ewolucji czasowej

Proces zaczyna się od stanu początkowego ϕ0.|\phi_0\rangle. Co ważne, nie jest potrzebne, by ten stan początkowy miał „dobre" pokrycie ze stanem podstawowym. Wystarczy, że jest „wielomianowo duży", czyli opisany wielomianem rozmiaru układu. Sam algorytm będzie następnie przybliżał stan coraz bliżej stanu podstawowego układu. SKQD stosuje operator ewolucji czasowej, eiHte^{-iHt}, dla różnych długości czasu. W ten sposób powstaje zbiór dd różnych stanów kwantowych, zdefiniowanych jako:

ϕj=eiδtjHϕ0,for j=0,1,,d1|\phi_j\rangle = e^{-i \,\delta t j H}|\phi_0\rangle, \quad \text{for } j = 0, 1, \dots, d-1 \quad \text{}

Ten zbiór stanów po ewolucji czasowej tworzy bazę Krylov. Ten krok jest szczególnie skuteczny w przypadku sieciowych Hamiltonianów, w których liczba wyrazów Hamiltonianu nie jest duża. W przypadku problemów chemicznych ewolucja czasowa może prowadzić do bardzo głębokich obwodów, dlatego w takich przypadkach zaleca się stosowanie SQD.

Krok 2: Próbkuj ze stanów bazy Krylov

Następnie ze wszystkich dd różnych stanów (ϕ0,ϕ1,,ϕd1|\phi_0\rangle, |\phi_1\rangle, \dots, |\phi_{d-1}\rangle) przygotowanych w poprzednim kroku zbierane są próbki bitciągów. Wszystkie te bitciągi są następnie łączone, tworząc bazę podprzestrzeni.

Krok 3: Rzutuj i diagonalizuj klasycznie

Ten krok jest identyczny jak w SQD. Zebrane bitciągi są używane do rzutowania pełnego Hamiltonianu na rozpiętą przez nie podprzestrzeń. Wynikająca z tego mała macierz, H~\tilde{H}, jest następnie diagonalizowana na klasycznym komputerze w celu wyznaczenia energii stanu podstawowego.

Key advantages and guarantees of SKQD

Ustrukturyzowane podejście SKQD zapewnia wyjątkowe korzyści:

  • Dowiedziona zbieżność: kluczową zaletą SKQD jest teoretyczna gwarancja zbieżności w określonych, dobrze zdefiniowanych warunkach. Jeśli prawdziwy stan podstawowy jest rzadki (może być dobrze aproksymowany przez wielomianową liczbę bitciągów), a przerwa energetyczna do pierwszego wzbudzonego stanu nie jest zbyt mała, dowiedziono, że metoda działa efektywnie. W tych warunkach SKQD gwarantuje znalezienie kluczowych bitciągów składających się na stan podstawowy i może aproksymować energię stanu podstawowego z dużą dokładnością. Wymaga to jedynie wielomianowej liczby eksperymentów kwantowych i ujęć. Gwarancja ta stawia podejście oparte na próbkowaniu na solidnych teoretycznych podstawach, podobnie do uznanych metod takich jak kwantowe szacowanie faz.

  • Wspólne zalety z SQD: podobnie jak SQD, SKQD posiada również właściwość odporności na szumy. Innymi słowy, dopóki w zbiorze próbkowanych bitciągów znajdują się wszystkie dobre bitciągi, diagonalizacja przypisuje niemal zerową wagę nieprawidłowym bitciągom, co sprawia, że procedura jest odporna na szumy. Ponadto, ponieważ rozwiązanie jest wytwarzane przez klasyczny HPC, energia rozwiązania jest klasycznie weryfikowalna.

W eksperymentach SKQD był stosowany z nawet 70 kubitami i tysiącami bramek do badania stanu podstawowego złożonych modeli Andersona z 4 zanieczyszczeniami, osiągając doskonałą zgodność z najnowocześniejszymi klasycznymi metodami, takimi jak DMRG.[1]

Check your understanding

Która część algorytmu SKQD sprawia, że nadaje się on lepiej do problemów fizycznych, takich jak sieciowe układy spinowe, niż do problemów chemicznych? Dlaczego?

Odpowiedź:

Ewolucja czasowa wymaga obwodów Trottera, które są bardzo głębokie dla Hamiltonianów skomplikowanych i nierdkich. Oddziaływania sieciowe spinów są opisywane przez macierze spinowe, odpowiadające macierzom Pauli. Hamiltoniany układów sieciowych spinów mają więc tendencję do bardziej zwartego wyrażania się w macierzach Pauli, szczególnie te z oddziaływaniami najbliższych sąsiadów.

SQD i SKQD jako obliczenia heterogeniczne

Aby zebrać wszystko razem, możemy przedstawić algorytmy oparte na próbkowaniu jako kombinację różnych modeli programowania na zestawie heterogenicznych zasobów. Na przykład, możemy przedstawić nasz algorytm jako przepływ pracy składający się z zadań.

Schemat przepływu pracy specyficznego dla diagonalizacji kwantowej opartej na próbkowaniu. Kroki obejmują wariacyjny obwód kwantowy, wykorzystanie pomiarów do zrzutowania Hamiltonianu na podprzestrzeń, a następnie użycie klasycznego optymalizatora do aktualizacji parametrów wariacyjnych w obwodzie i powtórzenie procesu.

Ten rysunek ilustruje podstawowy czteroetapowy przepływ pracy. Na początku będziemy mieli zadanie przygotowania obwodu kwantowego, który pokrywa się z naszym stanem docelowym, a następnie zadanie transpilacji, które do wykonania wymaga jedynie zasobów klasycznych. Następnie znajduje się zadanie wykorzystujące prymitywy do wykonania naszego obwodu kwantowego, które wymaga zasobów kwantowych. Wreszcie, mamy zadanie post-processingu, które samo w sobie może być równoległym algorytmem diagonalizacji uruchomionym na wielu węzłach.

Dodatkowo, możemy chcieć uruchomić jeden z tych algorytmów wiele razy, zmieniając nasz ansatz, lub możemy chcieć uruchomić je całkowicie równolegle z różnymi populacjami.

Schemat obciążenia SQD podzielonego pomiędzy kilka zasobów. Pokazuje kilka procesów działających sekwencyjnie, wykorzystujących wyniki jednej iteracji do zasilenia następnej, ale także wykonujących wiele takich procesów równolegle.

Jak pokazano powyżej, możesz uruchamiać wiele przepływów pracy jednocześnie, wykonując następujące czynności:

  • Zmienianie parametrów lub struktury ansatzu w celu znalezienia najbardziej efektywnego.
  • Rozpoczynanie od różnych stanów początkowych lub konfiguracji ("populacji"), aby uniknąć minimów lokalnych i zapewnić bardziej solidny wynik.

To wielowarstwowe podejście, łączące heterogeniczność opartą na zadaniach z równoległością na poziomie przepływu pracy, jest kluczem do odblokowania pełnego potencjału tych algorytmów.

Praktyka programowania

Przećwiczmy algorytm SKQD, demonstrując heterogeniczny przepływ pracy opisany wcześniej. Proces jest podzielony na cztery odrębne etapy, każdy z własnym skryptem Pythona i odpowiadającym mu skryptem powłoki do zlecania zadań.

Mapowanie (mapping.py i mapping.sh)

Pierwszym krokiem w naszym przepływie pracy jest zdefiniowanie problemu fizycznego i zmapowanie go na zestaw obwodów kwantowych.

Plik mapping.py definiuje parametry dla konkretnego problemu fizycznego — w tym przypadku modelu domieszkowego Andersona z siedmioma miejscami kąpieli (n_bath = 7). Konstruuje on całki jednociałowe (h1e) i dwuciałowe (h2e), które reprezentują Hamiltonian układu.


...

n_bath = 7 # number of bath sites

...

# One body matrix elements in the "position" basis
h1e = -t * np.diag(np.ones(n_bath), k=1) - t * np.diag(np.ones(n_bath), k=-1)
h1e[impurity_index, impurity_index + 1] = -V
h1e[impurity_index + 1, impurity_index] = -V
h1e[impurity_index, impurity_index] = eps

# Two body matrix elements in the "position" basis
h2e = np.zeros((n_bath + 1, n_bath + 1, n_bath + 1, n_bath + 1))
h2e[impurity_index, impurity_index, impurity_index, impurity_index] = U

...

# The one-body time evolution
free_fermion_evolution = ffsim.qiskit.OrbitalRotationJW(n_modes, Utar)

# The two-body time evolution
def append_diagonal_evolution(dt, U, impurity_qubit, num_orb, q_circuit):
"""Append two-body time evolution to a quantum circuit."""
if U != 0:
q_circuit.append(
CPhaseGate(-dt / 2 * U),
[impurity_qubit, impurity_qubit + num_orb],
)

Następnie generuje on obwody kwantowe wymagane przez algorytm SKQD. Zaczyna od utworzenia stanu początkowego (initial_state), a następnie stosuje operatory ewolucji w czasie dla różnej liczby kroków (d = 8), aby wygenerować różne stany bazowe Kryłowa, ϕj=(eiHt)jϕ0|\phi_j\rangle = (e^{-iHt})^j |\phi_0\rangle.


# The reference state
def initial_state(q_circuit, norb, nocc):
"""Prepare an initial state."""
for i in range(nocc):
q_circuit.append(XGate(), [i])
q_circuit.append(XGate(), [norb + i])
rot = XXPlusYYGate(np.pi / 2, -np.pi / 2)

for i in range(3):
for j in range(nocc - i - 1, nocc + i, 2):
q_circuit.append(rot, [j, j + 1])
q_circuit.append(rot, [norb + j, norb + j + 1])
q_circuit.append(rot, [j + 1, j + 2])
q_circuit.append(rot, [norb + j + 1, norb + j + 2])

...

# Generate the initial state
qubits = QuantumRegister(2 * n_modes, name="q")
init_state = QuantumCircuit(qubits)
initial_state(init_state, n_modes, n_modes // 2)

...

d = 8 # Number of Krylov basis states
circuits = []
for i in range(d):
circ = init_state.copy()
circuits.append(circ)
for _ in range(i):
append_diagonal_evolution(dt, U, impurity_index, n_modes, circ)
circ.append(free_fermion_evolution, qubits)
append_diagonal_evolution(dt, U, impurity_index, n_modes, circ)
circ.measure_all()

print(circuits[0].draw(scale=0.4, fold=-1))

Skrypt zapisuje listę 8 wygenerowanych obwodów (każdy z dołączonymi pomiarami) do pliku o nazwie circuits.qpy.

Plik mapping.sh to skrypt wsadowy Slurm używany do zlecania zadania mapping.py. Ponieważ jest to obliczenie klasyczne, żąda on zasobów ze standardowej partycji CPU (--partition=normal).

#!/bin/bash
#
#SBATCH --job-name=sqd-mapping
#SBATCH --output=sqd-mapping.out
#SBATCH --nodes=1
#SBATCH --ntasks-per-node=1
#SBATCH --cpus-per-task=1
#SBATCH --partition=normal

srun python /data/ch4/sqd/mapping.py

Optymalizacja (optimization.py i optimization.sh)

Gdy mamy już nasze obwody, muszą one zostać zoptymalizowane i skompilowane, aby efektywnie działały na docelowym sprzęcie kwantowym.

W pliku optimization.py ten skrypt najpierw ładuje plik circuits.qpy utworzony na etapie mapowania i pobiera informacje o zasobach kwantowych za pomocą QRMI(), menedżera zasobów kwantowych. Następnie używa funkcji generate_preset_pass_manager z Qiskit z wysokim poziomem optymalizacji (optimization_level=3), aby przekonwertować abstrakcyjne, logiczne obwody na obwody zgodne z architekturą zestawu instrukcji (ISA circuits). Proces ten przepisuje obwody przy użyciu natywnych bramek sprzętu i optymalizuje je, aby zmniejszyć głębokość i zminimalizować błędy.


...
qrmi = QRMI()
resources = qrmi.resources()
quantum_resource = resources[0]
target = quantum_resource.target

pass_manager = generate_preset_pass_manager(
optimization_level=3,
target=target
)
isa_circuits = pass_manager.run(circuits)

Przetranspilowane, gotowe do uruchomienia na sprzęcie obwody są zapisywane do nowego pliku isa_circuits.qpy.

Podobnie jak skrypt mapowania, to zadanie Slurm również działa na klasycznej partycji CPU (--partition=normal), ponieważ transpilacja jest zadaniem klasycznym.

#!/bin/bash
#
#SBATCH --job-name=sqd-mapping
#SBATCH --output=sqd-mapping.out
#SBATCH --nodes=1
#SBATCH --ntasks-per-node=1
#SBATCH --cpus-per-task=1
#SBATCH --partition=normal

srun python /data/ch4/sqd/mapping.py

Wykonanie (execution.py i execution.sh)

To jedyny etap, na którym używany jest komputer kwantowy. Tutaj wykonujemy zoptymalizowane obwody i zbieramy próbki pomiarów.

Plik execution.py ładuje zoptymalizowany plik isa_circuits.qpy, a następnie inicjalizuje prymityw SamplerV2, który jest połączony z zasobem kwantowym. Następnie wywołuje sampler.run(), aby wykonać obwody na QPU dla określonej liczby strzałów (shots=500).


...

qrmi = QRMI()
resources = qrmi.resources()
quantum_resource = resources[0]

# Sample from the circuits
noisy_sampler = Sampler(quantum_resource)
job = noisy_sampler.run(isa_circuits, shots=500)

Na koniec wykonania zmierzone wyniki (ciągi bitów) ze wszystkich obwodów są zbierane i łączone, a ich liczności są zapisywane do pliku counts.json.

Skrypt Slurm execution.sh różni się od pozostałych na tym etapie. Wymaga uruchomienia na partycji kwantowej (--partition=quantum) i konkretnie żąda jednego QPU (--gres=qpu:1).

#!/bin/bash
#
#SBATCH --job-name=sqd-execution
#SBATCH --output=sqd-execution.out
#SBATCH --nodes=1
#SBATCH --ntasks-per-node=1
#SBATCH --cpus-per-task=1
#SBATCH --partition=quantum
#SBATCH --gres=qpu:1

srun python /data/ch4/sqd/execution.py

Przetwarzanie końcowe (postprocessing.py i postprocessing.sh)

W ostatnim kroku wracamy do komputera klasycznego, aby przeanalizować dane z eksperymentu kwantowego i obliczyć końcowy wynik: energię stanu podstawowego naszego docelowego układu.

Program postprocessing.py najpierw odczytuje plik counts.json zawierający wyniki pomiarów. Następnie rekonstruuje Hamiltonian modelu Andersona (używając tych samych parametrów co w mapping.py). Potem przekazuje zmierzone bitstringi oraz definicję Hamiltonianu do funkcji diagonalize_fermionic_hamiltonian. Funkcja ta realizuje główną logikę SKQD: wykorzystuje bitstringi do skonstruowania zrzutowanego Hamiltonianu H~\tilde{H} i diagonalizuje go, aby znaleźć energię stanu podstawowego.


...

def callback(results: list[SCIResult]):
result_history.append(results)
iteration = len(result_history)
print(f"Iteration {iteration}")
for i, result in enumerate(results):
print(f"\tSubsample {i}")
print(f"\t\tEnergy: {result.energy}")
print(f"\t\tSubspace dimension: {np.prod(result.sci_state.amplitudes.shape)}")

rng = np.random.default_rng(24)
result = diagonalize_fermionic_hamiltonian(
h1e,
h2e,
bit_array,
samples_per_batch=300,
norb=n_modes,
nelec=nelec,
num_batches=3,
max_iterations=10,
symmetrize_spin=True,
callback=callback,
seed=rng,
)

Na koniec program wypisuje obliczoną energię SKQD i porównuje ją ze znaną energią dokładną dla tego problemu, pokazując końcowy błąd bezwzględny obliczeń.

Końcowy skrypt zadania uruchamia się na partycji klasycznej (--partition=normal), ponieważ cała analiza jest klasyczna. W przypadku dużych podprzestrzeni ten krok może wymagać większych klasycznych zasobów HPC.

#!/bin/bash
#
#SBATCH --job-name=sqd-postprocessing
#SBATCH --output=sqd-postprocessing.out
#SBATCH --nodes=1
#SBATCH --ntasks-per-node=1
#SBATCH --cpus-per-task=1
#SBATCH --partition=normal

srun python /data/ch4/sqd/postprocessing.py

Podsumowanie

I to wszystko! Omówiliśmy kilka koncepcji i przykładów, które mogą pomóc Ci rozpocząć zarządzanie złożonymi programami hybrydowymi. Oczywiście to dopiero początek tego, co można zrobić dzięki połączeniu kwantowych i klasycznych zasobów HPC.

Aby poznać więcej przypadków użycia i algorytmów, przeglądaj naszą dokumentację oraz samouczki na platformie IBM Quantum Platform, a także koniecznie odwiedź zasoby udostępnione w następnej lekcji, aby uzyskać więcej informacji o algorytmach i oprogramowaniu zarówno dla naukowców obliczeniowych, jak i administratorów centrów danych.

Bibliografia

[1] Quantum-Centric Algorithm for Sample-Based Krylov Diagonalization. https://arxiv.org/abs/2501.09702