Sari la conținutul principal
Acest proiect este în versiune beta. Ai găsit o eroare? Deschide un issue pe GitHub. Ai o întrebare sau o idee? Întreabă în Discussions — ne-ar plăcea să aflăm părerea ta!
Cum este calitatea traducerii pe această pagină?

Cum se raportează acest pachet la ffsim

Important

Conceptele din acest ghid sunt disponibile doar în API-ul Python.

ffsim și acest pachet își împart munca, în loc să se suprapună, de-a lungul unei singure linii:

ffsim se ocupă deqiskit-fermions se ocupă de
Operatorii ansatz de nivel înalt (UCJOpSpinBalanced, UCCSDOpRestrictedReal și variantele lor), construiți din amplitudini coupled-cluster sau dintr-un vector de parametriCircuitul fermionic (FermionicCircuit) în care devin acei operatori și transpilarea lui într-un circuit pe qubiți, sub orice codificare fermion-qubit
Simulare rapidă într-un spațiu compact cu număr fix de particuleCadrul de mapare și structurile de date ale operatorilor din care este construit circuitul

Consecința practică funcționează în ambele sensuri. Matematica ansatz-ului se află în ffsim, așa că UCJ și UCC primesc direct un operator ffsim ca intrare. Invers, porțile Qiskit proprii ale ffsim sunt specifice transformării Jordan-Wigner, așa că ceea ce îți oferă aducerea unuia dintre operatorii săi ansatz aici este coborârea lui printr-o codificare diferită.

Simularea este locul unde se întâlnesc cei doi, iar acest ghid explică cum. ffsim este backend-ul de simulare al acestui pachet, accesat prin propriile protocoale, nu printr-un wrapper: ghidul SKQD apelează ffsim.apply_unitary(), ffsim.linear_operator() și ffsim.sample_state_vector() direct pe obiecte FermionicCircuit și pe obiecte FermionOperator, fără niciun pas de conversie.

Conectarea la interfața de simulare a ffsim​

ffsim este un simulator de înaltă performanță pentru circuite cuantice fermionice, care exploatează conservarea numărului de particule și a spinului Z pentru a reprezenta vectorii de stare mai compact decât un vector de stare generic pe qubiți de dimensiune 2n2^n. Definește protocoale pe care orice obiect le poate implementa pentru a participa la mecanismul său de simulare (vezi qiskit_fermions.protocols pentru protocoalele proprii ale acestui pachet, care urmează același design):

Acest pachet implementează acea interfață: fiecare poartă fermionică din qiskit_fermions.circuit.library oferă _apply_unitary_, iar FermionOperator oferă _linear_operator_ și _trace_. Aceasta face operatorii și circuitele acestui pachet compatibile cu ffsim, astfel încât instrumentele sale funcționează nativ pe ele, fără niciun pas de conversie. ffsim.apply_unitary() poate simula un FermionicCircuit de la un capăt la altul, ffsim.linear_operator() poate diagonaliza un FermionOperator, iar utilitarele de eșantionare precum ffsim.sample_state_vector() (folosit în ghidul SKQD pentru a transforma un vector de stare simulat în numărători de măsurare) funcționează fără modificări.

Ceea ce returnează _linear_operator_ este un LinearOperator SciPy obișnuit, deci scipy.sparse.linalg.eigsh() și funcțiile similare funcționează și pe el.

>>> import ffsim
>>> import numpy as np
>>>
>>> from qiskit_fermions.circuit import FermionicCircuit
>>> from qiskit_fermions.circuit.library import Evolution
>>> from qiskit_fermions.operators import FermionOperator, ann, cre
>>>
>>> norb, nelec = 2, (1, 1)
>>> hamiltonian = FermionOperator.from_terms([
... ([cre(0), ann(1)], 0.5),
... ([cre(1), ann(0)], 0.5),
... ])
>>>
>>> circuit = FermionicCircuit(2 * norb)
>>> circuit.append(Evolution(2 * norb, hamiltonian, time=1.0), circuit.modes)
>>>
>>> reference = ffsim.hartree_fock_state(norb, nelec)
>>> state = ffsim.apply_unitary(reference, circuit, norb=norb, nelec=nelec) # native ffsim call

Cuplarea prin protocoalele ffsim este ceea ce aduce acest lucru: ecosistemul său de utilitare de simulare și eșantionare, dezvoltat activ, se aplică neschimbat circuitelor și operatorilor acestui pachet, iar utilizatorii care lucrează deja cu ffsim pot amesteca porțile și operatorii acestui pachet fără să învețe un alt API de simulare.

ffsim este o dependență opțională​

ffsim este declarat ca extra opțional (pip install "qiskit-fermions[ffsim]", sau tranzitiv prin [all]), protejat la runtime de HAS_FFSIM (așa cum s-a arătat mai sus). Instalarea lui deblochează simularea: ffsim.SupportsLinearOperator și ffsim.SupportsTrace sunt implementate prin conversia FermionOperator-ului acestui pachet într-un ffsim.FermionOperator, deci fără ffsim ele ridică MissingOptionalLibraryError. Tot ce nu simulează (construirea operatorilor, maparea lor și transpilarea circuitelor rezultate) nu are nevoie de nimic din toate acestea.

Simularea fermionică se desfășoară într-un sector cu număr fix de particule​

Atât _apply_unitary_, cât și _linear_operator_ primesc un argument nelec și reprezintă vectorul de stare peste baza de determinanți cu număr fix de particule pentru acel sector (norb, nelec), oglindind configurarea spațiului FCI din ffsim (și, tranzitiv, din PySCF), în loc de spațiul complet de dimensiune 2num_modes2^{\text{num\_modes}} pe care l-ar folosi un simulator generic de qubiți. Acesta este un spațiu mult mai mic (dimensiunea lui este un produs de coeficienți binomiali, nu o putere a lui doi), dar vine cu o restricție strictă. Doar operatorii și porțile care păstrează numărul de particule (și, în cazul cu spin, numărul de particule al fiecărei specii de spin individual) pot fi reprezentate în el. Un operator a cărui acțiune ar muta amplitudine către un alt număr de particule nu are unde să o pună.

ffsim rezolvă aceasta respingând de-a dreptul un astfel de operator: conversia unuia într-un operator liniar ridică o ValueError care numește ce lege de conservare eșuează. Aceasta este opțiunea implicită corectă, deoarece aplicarea lui exp⁡(−itH)\exp(-i t H) pentru un Hamiltonian HH cu un termen care nu conservă numărul de particule ar transforma altfel o aplicație care ar fi unitară într-una neunitară, fără sens fizic.

  • Evolution scoate la suprafață acea respingere din operatorul pe care îl evoluează.

  • OrbitalRotation verifică dacă matricea sa de rotație (încorporată) este bloc-diagonală pe împărțirea alfa/beta în cazul cu spin și generează o eroare ValueError dacă aceasta amestecă sectoarele de spin.

>>> from qiskit_fermions.circuit.library import Evolution
>>>
>>> non_conserving = FermionOperator.from_terms([([cre(0), cre(1)], 1.0)]) # creates 2 particles
>>> gate = Evolution(2 * norb, non_conserving, time=1.0)
>>>
>>> try:
... gate._apply_unitary_(reference, norb, nelec, copy=True)
... except ValueError as exc:
... print("rejected:", exc)
rejected: The given FermionOperator could not be converted to a LinearOperator because it does not conserve particle number and the z component of spin. Conserves particle number: False Conserves spin z: False

Prin urmare, simularea care nu conservă numărul de particule este imposibilă în spațiul fermionic, prin construcția reprezentării cu sector fix, iar acesta este prețul spațiului FCI compact care face simularea fermionică tratabilă încă de la început. Dacă algoritmul tău are nevoie de operatori care încalcă numărul de particule (de exemplu, un canal de eroare nativ pentru qubiți sau un operator construit pentru un Hamiltonian mapat care nu conservă numărul de particule termen cu termen), transpilează mai întâi la qubiți și simulează în schimb QuantumCircuit rezultat cu un simulator la nivel de qubit. Orice rută de transpilare funcționează pentru aceasta; ghidurile despre circuite fermionice și transpilare oferă mai multe detalii, dar generate_preset_jw_pass_manager() este o alegere implicită rezonabilă.

Convenția block-spin pentru sistemele cu spin​

nelec are tipul int | tuple[int, int], iar tipul său, nu un indicator separat, este cel care selectează unul dintre aranjamentele de moduri acceptate:

  • Un int selectează interpretarea fără spin. Cele norb moduri sunt tratate direct ca orbitali fără spin, iar nelec este numărul total de particule.

  • O pereche (n_alpha, n_beta) selectează interpretarea cu spin a celor 2 * norb moduri sub o convenție block-spin fixă. Modurile 0 .. norb sunt orbitalii alfa (spin sus), iar modurile norb .. 2 * norb sunt orbitalii beta (spin jos). Fiecare specie de spin este conservată independent; un termen doar alfa poate muta un electron între moduri alfa, dar niciodată într-un mod beta, și invers.

Această distribuire are loc în fiecare punct de intrare al protocolului ffsim din acest pachet (constructorii de porți, implementările _apply_unitary_placed_ și compilarea sectoarelor a nucleului nativ Rust) și este convenția folosită în ghidurile LUCJ și SKQD (de exemplu, InitializeModes.from_hartree_fock() plasează ocupările alfa în modurile 0 .. n_alpha și ocupările beta în modurile norb .. norb + n_beta). Merită comparată cu modulul qiskit_fermions.operators și cu FermionicCircuit în general, care folosesc indici de mod generici, fără semantică de spin inerentă (vezi ghidul circuitelor fermionice). Semnificația block-spin este impusă doar atunci când un nelec cu spin este furnizat unui apel de simulare, nu este încorporată în reprezentarea operatorului sau a circuitului în sine.

>>> from qiskit_fermions.circuit.library import InitializeModes
>>>
>>> norb, nelec = 3, (2, 1)
>>> init = InitializeModes.from_hartree_fock(norb, nelec)
>>> print([bool(occ) for occ in init.occupation]) # alpha modes 0,1; beta mode 3 (= norb + 0)
[True, True, False, True, False, False]

Pașii următori​