SQD și SKQD
În acest capitol, vom explora modul în care calculatoarele cuantice și clasice colaborează pentru a rezolva una dintre cele mai importante provocări din știință: estimarea precisă a energiei moleculelor și materialelor.
Iskandar Sitdikov descrie abordarea algoritmică în videoclipul următor.
Hamiltonian
Cheia acestei probleme este un operator matematic — Hamiltonianul, care reprezintă energia totală a unui sistem. În scopuri computaționale, putem privi acest Hamiltonian ca pe o matrice mare. Soluțiile pe care le căutăm — în special starea fundamentală a sistemului — sunt valorile proprii cele mai mici ale acestei matrice. Provocarea, însă, este că pentru probleme practice, această matrice Hamiltoniană este foarte mare. Ea crește exponențial cu dimensiunea sistemului, devenind rapid prea mare ( unde este numărul de qubiți) chiar și pentru cele mai puternice supercalculatoare, care nu o pot stoca sau rezolva direct.
Pentru a depăși această dificultate, folosim o strategie puternică cunoscută sub numele de metoda subspațiului. În loc să abordăm întreaga matrice, selectăm în mod inteligent o felie mică și relevantă — un „subspațiu" — despre care credem că conține cele mai importante informații privind soluția de joasă energie pe care o căutăm.
Odată ce acest subspațiu mic este definit printr-un set de stări de bază , Hamiltonianul complet este proiectat pe acesta pentru a crea noua matrice mai mică . Fiecare element al acestei matrice este calculat din stările de bază ale subspațiului și Hamiltonianul original, conform . Această matrice mică poate fi apoi diagonalizată cu ușurință pe un calculator clasic, iar valorile proprii rezultate reprezintă energiile estimate.
Așa cum ai putea bănui, succesul acestei abordări depinde în mare măsură de alegerea unui subspațiu „bun". Dacă subspațiul nostru nu reprezintă cu acuratețe starea fundamentală reală, răspunsul final va fi incorect. Aici intervin calculatoarele cuantice: ele ne permit să pregătim și să eșantionăm stări cuantice complexe, concepute pentru a identifica aceste subspații importante. Pentru probleme cu adevărat masive, cum ar fi structuri chimice complexe sau situri de legătură, chiar și matricea proiectată poate fi dificil de diagonalizat. Prin urmare, astfel de probleme sunt perfect potrivite pentru a valorifica punctele forte atât ale resurselor de calcul cuantic, cât și ale celor clasice.
În secțiunile următoare, vom explora doi algoritmi avansați, SQD și SKQD, care utilizează mecanica cuantică pentru a găsi și construi aceste subspații. Pentru o aprofundare mai detaliată, există un curs complet pe IBM Quantum Learning dedicat acestor subiecte. În scopul acestui curs, vom păstra explicația la un nivel înalt.
Diagonalizare Cuantică Bazată pe Eșantionare
Diagonalizarea Cuantică Bazată pe Eșantionare (SQD) este un algoritm variațional puternic care implementează metoda subspațiului într-un mod cuantic. Evită proceduri costisitoare și complexe, cum ar fi testele Hadamard, utilizând un calculator cuantic pentru a pregăti o stare de probă și a eșantiona șiruri de biți, care definesc subspațiul pentru diagonalizarea clasică.
Algoritmul SQD poate fi descompus în următorii pași:
Pasul 1: Pregătirea stării ansatz
Fie Hamiltonianul pe qubiți. Deși starea fundamentală reală poate fi susținută de toți cei vectori de bază, SQD este cel mai eficient în cazurile în care starea fundamentală poate fi bine aproximată printr-un subspațiu rar (un set de dimensiune polinomială de șiruri de biți).
Pentru a construi acest subspațiu, pornim de la o stare de intrare , cum ar fi starea Hartree-Fock (HF) în chimie. Apoi aplicăm un circuit cuantic parametrizat, , cunoscut sub numele de ansatz.
Această diagramă ilustrează scopul unui ansatz bun. ansatz-ul pregătește o stare cuantică al cărei suport (setul de stări de bază din care este compusă) ar trebui să aibă în mod ideal o suprapunere mare cu suportul stării fundamentale reale. Acest circuit ne permite să proiectăm rapid ansatz-ul pe stări de bază computaționale, care vor fi utilizate ulterior în diagonalizarea clasică. Cu alte cuvinte: nu trebuie să ghicim un ansatz care să fie starea fundamentală; avem nevoie doar ca acesta să conțină aceleași stări de bază. Apoi diagonalizarea clasică a Hamiltonianului proiectat ne va oferi superpoziția de stări de bază care aproximează cel mai bine starea fundamentală.
Pasul 2: Eșantionarea subspațiului
Prin eșantionarea din circuitul pregătit de ansatz, obținem o colecție de șiruri de biți, . Aceste șiruri de biți definesc baza subspațiului ales. Timpul de execuție cuantică pentru acest pas este determinat de adâncimea circuitului și de numărul de eșantioane preluate.
Pasul 3: Proiectarea și diagonalizarea clasică
Folosind șirurile de biți eșantionate, proiectăm Hamiltonianul în subspațiul pe care îl acoperă. Pentru fiecare pereche de șiruri de biți , calculăm clasic elementul de matrice . Deoarece operatorii Pauli sunt rari, acest pas este eficient din punct de vedere clasic pentru Hamiltonieni fizici. Matricea mică rezultată este apoi diagonalizată pe un procesor clasic pentru a estima starea fundamentală și energia sa.
Pasul 4: Optimizarea ansatz-ului (opțional)
Procesul poate fi transformat în unul iterativ. Tratând energia estimată a stării fundamentale ca funcție de cost, putem optimiza parametrii circuitului () folosind metode precum coborârea gradientului, pentru a îmbunătăți ansatz-ul și, implicit, aproximarea energiei în iterația următoare.
Avantajele cheie ale SQD
SQD oferă mai multe caracteristici puternice care îl fac un candidat de frunte pentru demonstrarea avantajului cuantic:
- Robustețe puternică la zgomot: Să presupunem că starea fundamentală reală este susținută de doar două șiruri de biți. Dacă acestea sunt eșantionate, chiar dacă suprapunerea lor cu ansatz-ul nostru este mică, diagonalizarea le va atribui ponderile corespunzătoare și va ignora efectiv toate celelalte șiruri de biți parazite și zgomotoase care ar fi putut fi, de asemenea, eșantionate. Această filtrare intrinsecă face SQD deosebit de tolerant la zgomot.
- Verificabilitate clasică: Spre deosebire de QPE sau VQAs, SQD produce o aproximare clasică a stării fundamentale. Aceasta înseamnă că oricine are acces la lista de șiruri de biți și ponderile lor poate recalcula și verifica direct estimarea energiei pe un calculator clasic.
SQD a fost deja utilizat pentru a estima energia de disociere a stării fundamentale a N și proprietățile electronice ale clusterilor [2Fe-2S] și [4Fe-4S] [2], cu circuite de până la 77 de qubiți și 10.570 de Gate-uri.
Verifică-ți înțelegerea
Adevărat sau Fals: SQD poate fi aplicat sistemelor chimice.
Răspuns:
Adevărat
Verifică-ți înțelegerea
Numește setul tuturor stărilor de bază computaționale ce alcătuiesc ansatz-ul tău. Numește setul tuturor stărilor de bază computaționale ce alcătuiesc starea fundamentală reală a sistemului tău. Care dintre următoarele corespunde unui ansatz „bun"? Selectează toate variantele aplicabile.
(a)
(b)
(c)
(d)
Răspuns:
(c) și (d)
SKQD (Diagonalizare Cuantică Krylov Bazată pe Eșantionare)
Diagonalizarea Cuantică Krylov Bazată pe Eșantionare (SKQD) este un alt algoritm cuantic puternic bazat pe eșantionare, care se construiește pe principiile SQD. Deși scopul său este același — găsirea unui subspațiu bun pentru diagonalizare — SKQD folosește o metodă mai structurată pentru generarea șirurilor de biți, în special pentru probleme precum Hamiltonieni de rețea.
Ideea centrală a SKQD este că, în loc să optimizeze un circuit parametrizat pentru a găsi un ansatz bun, se poate converge în mod demonstrabil la starea fundamentală prin eșantionarea dintr-un set de stări generate de propria evoluție temporală naturală a sistemului — subspațiul Krylov. Algoritmul SKQD poate fi descompus în următorii pași:
Pasul 1: Construirea subspațiului Krylov prin evoluție temporală
Procesul începe cu o stare inițială Important, nu avem nevoie ca această stare inițială să aibă o suprapunere „bună" cu starea fundamentală. Ea trebuie doar să fie „polinomial mare", adică descrisă de un polinom în dimensiunea sistemului. Algoritmul în sine va conduce apoi starea tot mai aproape de starea fundamentală a sistemului. SKQD aplică operatorul de evoluție temporală, , pentru durate diferite de timp. Aceasta creează un set de stări cuantice diferite, definite ca:
Această colecție de stări evoluate temporal formează o bază Krylov. Acest pas este deosebit de eficient pentru Hamiltonieni de rețea unde numărul de termeni din Hamiltonian nu este mare. Pentru probleme de chimie, această evoluție temporală poate duce la circuite foarte adânci, motiv pentru care SQD este adesea recomandat în acele cazuri.
Pasul 2: Eșantionarea din stările bazei Krylov
Apoi, eșantioane de șiruri de biți sunt colectate din fiecare dintre cele stări diferite () pregătite în pasul anterior. Toate aceste șiruri de biți sunt apoi reunite pentru a forma baza subspațiului.
Pasul 3: Proiectarea și diagonalizarea clasică
Acest pas este identic cu cel din SQD. Șirurile de biți colectate sunt folosite pentru a proiecta Hamiltonianul complet în subspațiul pe care îl acoperă. Matricea mică rezultată, , este apoi diagonalizată pe un calculator clasic pentru a găsi energia stării fundamentale.
Avantajele cheie și garanțiile SKQD
Abordarea structurată a SKQD oferă beneficii unice:
-
Convergență demonstrabilă: Avantajul cheie al SKQD este garanția sa teoretică de convergență în condiții specifice, bine definite. Dacă starea fundamentală reală este rară (poate fi bine aproximată printr-un număr polinomial de șiruri de biți) și decalajul de energie față de prima stare excitată nu este prea mic, s-a demonstrat că metoda funcționează eficient. În aceste condiții, SKQD garantează că va găsi șirurile de biți cruciale care alcătuiesc starea fundamentală și poate aproxima energia stării fundamentale cu înaltă precizie. Aceasta necesită doar un număr polinomial de experimente cuantice și shots. Această garanție plasează abordarea bazată pe eșantionare pe o bază teoretică riguroasă, similară cu metode consacrate precum estimarea fazei cuantice.
-
Beneficii comune cu SQD: Similar cu SQD, SKQD prezintă de asemenea proprietatea de robustețe la zgomot. Cu alte cuvinte, atâta timp cât setul de șiruri de biți eșantionate conține toate șirurile de biți bune, diagonalizarea atribuie o pondere aproape zero șirurilor de biți incorecte, făcând procedura robustă la zgomot. Mai mult, deoarece soluția este produsă de un HPC clasic, energia soluției este verificabilă clasic.
În experimente, SKQD a fost utilizat cu până la 70 de qubiți și mii de Gate-uri pentru a studia starea fundamentală a unor modele Anderson complexe cu 4 impurități, obținând o concordanță excelentă cu metode clasice de ultimă generație, precum DMRG.[1]
Verifică-ți înțelegerea
Ce parte din algoritmul SKQD îl face mai potrivit pentru probleme fizice, cum ar fi rețelele de spin, decât pentru probleme chimice? De ce?
Răspuns:
Evoluția temporală necesită circuite Trotter, care sunt foarte adânci pentru Hamiltonieni complicați și nerari. Interacțiunile în rețelele de spin sunt guvernate de matrici de spin, echivalente cu matricile Pauli. Prin urmare, Hamiltonenii pentru rețelele de spin tind să fie mai compact exprimabili în matrici Pauli, în special cei cu interacțiuni între vecini apropiați.
SQD și SKQD ca resurse de calcul eterogen
Pentru a pune totul cap la cap, putem reprezenta algoritmii bazați pe eșantionare ca o combinație de diferite modele de programare pe un set de resurse eterogene. De exemplu, putem reprezenta algoritmul nostru ca un flux de sarcini.
Această figură ilustrează fluxul de lucru fundamental în patru etape. Mai întâi, vom avea o sarcină pentru pregătirea circuitului cuantic care se suprapune cu starea noastră țintă, urmată de o sarcină pentru transpilare, care necesită doar resurse clasice pentru a fi executată. Urmează o sarcină care folosește primitivele pentru a executa circuitul nostru cuantic, necesitând resurse cuantice. În final, avem o sarcină de post-procesare, care poate fi ea însăși un algoritm de diagonalizare paralelă rulând pe mai multe noduri.
În plus, am putea dori să rulăm unul dintre acești algoritmi de mai multe ori în timp ce variăm ansatz-ul, sau am putea dori să îi rulăm complet în paralel cu populații diferite.
Așa cum este descris mai sus, ai putea rula mai multe fluxuri de lucru simultan, făcând următoarele:
- Variind parametrii sau structura ansatz-ului pentru a-l găsi pe cel mai eficient.
- Pornind cu stări sau configurații inițiale diferite („populații") pentru a evita minimele locale și a asigura un rezultat mai robust.
Această abordare pe mai multe niveluri, care combină eterogenitatea bazată pe sarcini cu paralelismul la nivelul fluxului de lucru, este cheia pentru a debloca întregul potențial al acestor algoritmi.
Practică de programare
Să exersăm algoritmul SKQD, demonstrând fluxul de lucru eterogen descris anterior. Procesul este împărțit în patru etape distincte, fiecare cu propriul script Python și un script shell corespunzător pentru trimiterea jobului.
Mapare (mapping.py și mapping.sh)
Primul pas în fluxul nostru de lucru este definirea problemei fizice și maparea ei la un set de circuite cuantice.
mapping.py definește parametrii pentru o problemă fizică specifică — în acest caz, un model de impuritate Anderson cu șapte situri de baie (n_bath = 7). Construiește integralele de un corp (h1e) și de două corpuri (h2e) care reprezintă Hamiltonianul sistemului.
...
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],
)
Scriptul generează apoi circuitele cuantice necesare algoritmului SKQD. Începe prin crearea unei stări inițiale (initial_state) și apoi aplică operatori de evoluție temporală pentru un număr variabil de pași (d = 8) pentru a genera diferitele stări ale bazei Krylov, .
# 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))
Scriptul salvează lista celor 8 circuite generate (fiecare cu măsurători adăugate) într-un fișier numit circuits.qpy.
mapping.sh este un script batch Slurm folosit pentru a trimite jobul mapping.py. Deoarece aceasta este o computație clasică, solicită resurse dintr-o partiție standard 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
Optimizare (optimization.py și optimization.sh)
Odată ce avem circuitele, acestea trebuie optimizate și compilate pentru a rula eficient pe hardware-ul cuantic țintă.
În optimization.py, scriptul încarcă mai întâi fișierul circuits.qpy creat în etapa de mapare și aduce informații despre resursele cuantice prin QRMI(), un manager de resurse cuantice. Apoi folosește generate_preset_pass_manager din Qiskit cu un nivel ridicat de optimizare (optimization_level=3) pentru a converti circuitele abstracte și logice în circuite ISA (Instruction Set Architecture). Acest proces rescrie circuitele folosind Gate-urile native ale hardware-ului și le optimizează pentru a reduce adâncimea și a minimiza erorile.
...
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)
Circuitele transpilate, gata pentru hardware, sunt salvate într-un nou fișier, isa_circuits.qpy.
Similar cu scriptul de mapare, acest job Slurm rulează de asemenea pe o partiție clasică CPU (--partition=normal), deoarece transpilarea este o sarcină clasică.
#!/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
Execuție (execution.py și execution.sh)
Aceasta este singura etapă în care este folosit un calculator cuantic. Aici executăm circuitele optimizate și colectăm eșantioanele de măsurare.
execution.py încarcă fișierul optimizat isa_circuits.qpy, apoi inițializează o primitivă SamplerV2 conectată la o resursă cuantică. Apoi apelează sampler.run() pentru a executa circuitele pe QPU pentru un număr specificat de shots (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)
La sfârșitul execuției, rezultatele măsurate (șirurile de biți) din toate circuitele sunt colectate și combinate, iar numărul lor de apariții este salvat într-un fișier counts.json.
Scriptul Slurm execution.sh este diferit de celelalte în această etapă. Solicită să fie rulat pe partiția cuantică (--partition=quantum) și solicită în mod specific un 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
Post-procesare (postprocessing.py și postprocessing.sh)
În ultimul pas, revenim la un calculator clasic pentru a analiza datele din experimentul cuantic și a calcula rezultatul final: energia stării fundamentale a sistemului nostru țintă.
Programul postprocessing.py citește mai întâi fișierul counts.json care conține rezultatele măsur ătorilor. Apoi reconstruiește Hamiltonianul modelului Anderson (folosind aceiași parametri ca în mapping.py). Trece apoi șirurile de biți măsurate și definiția Hamiltonianului funcției diagonalize_fermionic_hamiltonian. Această funcție execută logica de bază a SKQD: folosește șirurile de biți pentru a construi Hamiltonianul proiectat și îl diagonalizează pentru a găsi energia stării fundamentale.
...
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,
)
În final, aceasta afișează energia SKQD calculată și o compară cu energia exactă cunoscută pentru această problemă, arătând eroarea absolută finală a calculului.
Scriptul final de job rulează pe o partiție clasică (--partition=normal), deoarece toată analiza este clasică. Pentru subspații mari, acest pas ar putea necesita mai multe resurse HPC clasice.
#!/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
Rezumat
Și asta e tot! Am parcurs acum mai multe concepte și exemple care te pot ajuta să începi gestionarea unor programe hibride complexe. Desigur, acesta este doar începutul a tot ceea ce poți face cu combinația de resurse cuantice și HPC clasice.
Pentru a explora mai multe cazuri de utilizare și algoritmi, răsfoiește documentația și tutorialele noastre de pe IBM Quantum Platform și asigură-te că vizitezi resursele prezentate în lecția următoare pentru mai multe informații despre algoritmi și software atât pentru oamenii de știință computaționali, cât și pentru administratorii centrelor de date.
Referințe
[1] Quantum-Centric Algorithm for Sample-Based Krylov Diagonalization. https://arxiv.org/abs/2501.09702