In che modo questo pacchetto è correlato a ffsim
I concetti illustrati in questa guida sono disponibili esclusivamente nell'API " Python ".
ffsim e questo pacchetto si dividono il lavoro anziché sovrapporsi, seguendo un unico filone:
ffsim possiede | qiskit-fermions possiede |
|---|---|
Gli operatori di ansatz di alto livello (UCJOpSpinBalanced, e UCCSDOpRestrictedReal i loro omologhi), costruiti a partire da ampiezze del metodo coupled-cluster o da un vettore di parametri | Il circuito fermionico (FermionicCircuit) in cui si trasformano tali operatori e la sua trasposizione in un circuito a qubit mediante qualsiasi codifica da fermioni a qubit |
| Simulazione veloce in uno spazio compatto a numero fisso di particelle | Il framework di mappatura e le strutture dati degli operatori che costituiscono il circuito |
La conseguenza pratica vale in entrambi i sensi. La matematica di Ansatz è implementata in ffsim, quindi e UCJ UCC accettano direttamente un operatore ffsim come input. Al contrario, i gate Qiskit propri di ffsim sono specifici per la trasformazione di Jordan-Wigner, quindi il vantaggio di utilizzarli in questo contesto consiste proprio nel poter semplificare uno dei suoi operatori di ansatz tramite una codifica diversa.
È proprio nella simulazione che le due cose si incontrano, e questa guida spiega come. ffsim è il backend di simulazione di questo pacchetto, accessibile tramite i propri protocolli anziché tramite un wrapper: la guida SKQD chiama ffsim.apply_unitary(), ffsim.linear_operator(), e direttamente ffsim.sample_state_vector() sugli FermionicCircuitoggetti e sugli FermionOperatoroggetti, senza alcuna fase di conversione.
Collegamento all'interfaccia di simulazione di ffsim
ffsim è un simulatore ad alte prestazioni per circuiti quantistici fermionici che sfrutta la conservazione del numero di particelle e dello spin Z per rappresentare i vettori di stato in modo più compatto rispetto a un generico vettore di stato a -dimensioni per i qubit. Definisce i protocolli che qualsiasi oggetto può implementare per partecipare al suo meccanismo di simulazione (si veda qiskit_fermions.protocols per i protocolli propri di questo pacchetto, che seguono lo stesso schema):
ffsim.SupportsApplyUnitary, mediante il metodo_apply_unitary_(vec, norb, nelec, copy), applicando l'operatore come unitario a un vettore di stato con numero fisso di particelleffsim.SupportsLinearOperator, tramite il metodo_linear_operator_(norb, nelec), restituendo una vistascipy.sparse.linalg.LinearOperatordell'oggetto in quello stesso settoreffsim.SupportsTrace, tramite il metodo_trace_(norb, nelec), restituendo la traccia dell'oggetto su quel settore.
Questo pacchetto implementa tale interfaccia: ogni gate fermionico in qiskit_fermions.circuit.library fornisce _apply_unitary_, mentre FermionOperator fornisce e _linear_operator_ _trace_. È proprio questo che rende gli operatori e i circuiti di questo pacchetto compatibili con ffsim, per cui i suoi strumenti funzionano su di essi in modo nativo, senza alcuna fase di conversione. ffsim.apply_unitary() è in grado di simulare un FermionicCircuit end-to-end, ffsim.linear_operator() può diagonalizzare un FermionOperator, e le utilità di campionamento come ffsim.sample_state_vector() (utilizzate nella guida SKQD per trasformare un vettore di stato simulato in conteggi di misura) funzionano senza modifiche.
Il risultato _linear_operator_ è un normale oggetto di tipo SciPy LinearOperator, quindi anche scipy.sparse.linalg.eigsh() and friends funzionano su di esso.
>>> 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È proprio l’integrazione tramite i protocolli di ffsim a rendere possibile tutto questo: il suo ecosistema di utilità di simulazione e campionamento, in continua evoluzione, si applica senza modifiche ai circuiti e agli operatori di questo pacchetto, e gli utenti che già utilizzano ffsim possono integrare i gate e gli operatori di questo pacchetto senza dover apprendere un’altra API di simulazione.
ffsim è una dipendenza facoltativa
ffsim è dichiarato come extra opzionale (pip install "qiskit-fermions[ffsim]", o transitivamente da [all]), protetto in fase di esecuzione da HAS_FFSIM (come illustrato sopra). L'installazione sblocca la simulazione: e ffsim.SupportsLinearOperator ffsim.SupportsTrace vengono implementati convertendo il di questo pacchetto in FermionOperator un ffsim.FermionOperator, quindi senza ffsim generano un MissingOptionalLibraryError. Tutto ciò che non riguarda la simulazione (la creazione di operatori, la loro mappatura e la transpilazione dei circuiti risultanti) non ne ha bisogno.
ffsim dipende in modo transitivo da PySCF, che non supporta Windows; pertanto, su Windows il comando “extra” non produce alcun risultato (un’operazione silenziosa senza effetto tramite un sys_platform marcatore) anziché generare un errore di installazione. Gli utenti Windows che desiderano eseguire la simulazione possono farlo, per il momento, tramite il Sottosistema Windows per l' Linux.
La simulazione fermionica si svolge in un settore con un numero fisso di particelle
Sia _apply_unitary_ che _linear_operator_ accettano un nelec argomento e rappresentano il vettore di stato sulla base determinante a numero fisso di particelle per quel (norb, nelec) settore, rispecchiando la configurazione dello spazio FCI di ffsim (e, per traslazione, di PySCF’s ), anziché lo spazio completo a dimensioni che un simulatore di qubit generico utilizzerebbe. Si tratta di uno spazio molto più piccolo (la sua dimensione è il prodotto dei coefficienti binomiali anziché una potenza di due), ma presenta una restrizione rigida. In esso possono essere rappresentati solo gli operatori e i gate che conservano il numero di particelle (e, nel caso in cui lo spin sia non nullo, il numero di particelle di ciascuna specie di spin singolarmente). Un operatore la cui azione comporterebbe lo spostamento dell'ampiezza su un numero diverso di particelle non avrebbe dove collocarla.
ffsim risolve il problema rifiutando categoricamente un operatore di questo tipo: la conversione di un operatore in un operatore lineare genera un errore che indica ValueError quale legge di conservazione non viene rispettata. Questa è l'impostazione predefinita corretta, poiché l'applicazione dell' e a un hamiltoniano contenente un termine che non conserva le particelle trasformerebbe altrimenti una mappa potenzialmente unitaria in una mappa non unitaria e fisicamente priva di significato.
Evolutionsuperfici che, a seguito del rifiuto da parte dell’operatore, si evolvono.OrbitalRotationverifica che la sua matrice di rotazione (incorporata) sia diagonale a blocchi rispetto alla suddivisione alfa/beta nel caso con spin, e genera un'eccezioneValueErrorse mescola i settori di 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: FalseLa simulazione che non preserva le particelle è quindi impossibile nello spazio fermionico, per come è costruita la rappresentazione a settore fisso, e questo è il prezzo da pagare per lo spazio FCI compatto che rende la simulazione fermionica fattibile in primo luogo. Se il tuo algoritmo richiede operatori che violano il numero di particelle (ad esempio, un canale di errore nativo per i qubit o un operatore costruito per un hamiltoniano mappato che non conserva il numero di particelle termine per termine), effettua prima la transpilazione in qubit e simula il risultato QuantumCircuit utilizzando invece un simulatore a livello di qubit. In questo caso va bene qualsiasi percorso di transpilazione; il circuito fermionico e le guide alla transpilazione forniscono maggiori dettagli, ma generate_preset_jw_pass_manager() è una scelta predefinita ragionevole.
La convenzione "block-spin" per i sistemi con spin
nelec viene specificato il tipo int | tuple[int, int], ed è proprio il tipo, e non un flag separato, a determinare quale delle configurazioni di modalità supportate venga selezionata:
- Un int indica l'interpretazione senza spin. Le modalità
norbsono considerate direttamente come orbitali privi di spin, enelecè il numero totale di particelle. - Una coppia
(n_alpha, n_beta)seleziona l’interpretazione “spinful” delle modalità2 * norbsecondo una convenzione fissa di “block-spin”. Le modalità0 .. norbcorrispondono agli orbitali alfa (spin verso l'alto) e le modalitànorb .. 2 * norbcorrispondono agli orbitali beta (spin verso il basso). Ogni specie di spin è conservata in modo indipendente; un termine esclusivamente alfa può spostare un elettrone tra i modi alfa, ma mai in un modo beta, e viceversa.
Questa trasmissione avviene in ogni punto di ingresso del protocollo ffsim presente in questo pacchetto (costruttori di gate, _apply_unitary_placed_ implementazioni e compilazione dei settori del kernel nativo di Rust) ed è la convenzione utilizzata in tutte le guide LUCJ e SKQD (ad esempio, InitializeModes.from_hartree_fock() inserisce le occupazioni alfa nelle modalità 0 .. n_alpha e le occupazioni beta nelle modalità norb .. norb + n_beta). È opportuno mettere a confronto questo approccio con il modulo qiskit_fermions.operators e, più in FermionicCircuit generale, con quelli che utilizzano indici di modo generici privi di semantica intrinseca dello spin (si veda la guida ai circuiti fermionici ). Il significato di "block-spin" viene imposto solo quando nelec viene fornito uno "spinful" a una chiamata di simulazione, e non è integrato nella rappresentazione dell'operatore o del circuito stesso.
>>> 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]Passi successivi
-
Consulta la guida SKQD per vedere come
ffsim.apply_unitary()e vengono utilizzatiffsim.sample_state_vector()insieme per campionare circuiti realizzati con i gate di questo pacchetto e per valutare il valore atteso dell’Hamiltoniano tramiteffsim.linear_operator()(a sua volta basato sullo stesso metodo del protocollo_linear_operator_qui descritto). -
Consulta la guida LUCJ per scoprire l'altra metà della storia: come far passare un operatore ffsim ansatz attraverso la pipeline di transpilazione di questo pacchetto e arrivare a una mappa di accoppiamento con il dispositivo.
-
Leggi la guida ai circuiti fermionici per l'indicizzazione generica delle modalità, indipendente dallo spin, utilizzata al di fuori delle chiamate di simulazione.
-
Leggi la guida alla transpilazione per sapere come uscire dallo spazio fermionico
e simulare sui qubit, cosa necessaria per gli operatori che non conservano le particelle.
-
Consulta il
qiskit_fermions.protocolscatalogo completo dei protocolli definiti da questo pacchetto, compresi i protocolli di conversione (SupportsFermionOperator,SupportsMajoranaOperator) che non sono correlati a ffsim. -
Leggi le guide redatte da ffsim relative ai flussi di lavoro di sua competenza, in particolare quelle dedicate alla creazione di un ansatz UCJ e alla sua ottimizzazione variazionale. I vettori di parametri che tali guide guidano sono ciò che
UCJeUCCaccettano, tramite gli operatori che costruiscono.