FermionOperator
class FermionOperator(coeffs, actions, modes, boundaries)
Basi: object
Un operatore fermionico senza spin.
Definizione
Questo operatore è definito da una combinazione lineare di prodotti di operatori di creazione e annichilimento fermionici che agiscono su modi fermionici privi di spin. In altre parole, i singoli termini soddisfano le seguenti relazioni di anticommutatività: [1]
dove e non distinguono la specie di spin delle modalità fermioniche a cui fanno riferimento.
Ne consegue che la definizione dell'intero operatore è la seguente:
dove e è il coefficiente (complesso) che costituisce la combinazione lineare dei prodotti. L'indice può assumere qualsiasi valore compreso tra 0 e il numero di modi fermionici su cui agisce l'operatore meno 1.
Implementazione
Questa classe memorizza i termini e i coefficienti in più vettori sparsi, analogamente al formato "compressed sparse row" comunemente utilizzato per le matrici sparse. Più precisamente, un singolo operatore contiene 4 array:
Rubrica 1 | Rubrica 2 |
|---|---|
coeffs | Un vettore di coefficienti complessi costituito da due numeri in virgola mobile a 64 bit. |
actions | Un vettore di valori booleani che memorizza la natura delle operazioni di seconda quantizzazione. |
modes | Un vettore di interi a 32 bit che memorizza gli indici delle modalità fermioniche su cui è stata eseguita l'operazione. |
boundaries | Un vettore di numeri interi che indica i confini in e actions modes. |
Le voci in actions indicano operatori di creazione (annichilimento) da parte di ( True``False ). Le modalità fermioniche indicizzate da modes sono considerate prive di spin.
È possibile accedere a copie in sola lettura di questi array interni tramite i rispettivi metodi: get_coeffs(), get_actions(), get_modes(), e get_boundaries().
Questa struttura dati consente di creare e manipolare gli operatori in modo molto efficiente. Tuttavia, ciò implica che in qualsiasi momento un operatore possa contenere termini duplicati. Questi devono essere risolti manualmente utilizzando simplify().
Costruzioni
È possibile creare un operatore direttamente fornendo gli array descritti sopra:
>>> from qiskit_fermions.operators import FermionOperator
>>> coeffs = [1.0, 2.0, -3.0, 4.0j, -0.5j]
>>> actions = [True, False, False, True, True, True, False, False]
>>> modes = [0, 0, 0, 1, 0, 1, 2, 3]
>>> boundaries = [0, 0, 1, 2, 4, 8]
>>> op = FermionOperator(coeffs, actions, modes, boundaries)
>>> print(format(op))
1.000000e0 +0.000000e0j * ()
-3.000000e0 +0.000000e0j * (-0)
0.000000e0 +4.000000e0j * (-0 +1)
2.000000e0 +0.000000e0j * (+0)
-0.000000e0-5.000000e-1j * (+0 +1 -2 -3)
Per comodità, è possibile creare un operatore a partire da un dizionario di tipo “ Python ” in questo modo:
>>> from qiskit_fermions.operators import cre, ann
>>> op = FermionOperator.from_dict(
... {
... (): 1.0,
... (cre(0),): 2.0,
... (ann(0),): -3.0,
... (ann(0), cre(1)): 4.0j,
... (cre(0), cre(1), ann(2), ann(3)): -0.5j,
... }
... )
>>> print(format(op))
1.000000e0 +0.000000e0j * ()
-3.000000e0 +0.000000e0j * (-0)
0.000000e0 +4.000000e0j * (-0 +1)
2.000000e0 +0.000000e0j * (+0)
-0.000000e0-5.000000e-1j * (+0 +1 -2 -3)
In questo esempio, abbiamo utilizzato cre() e ann() per definire gli operatori di creazione e di annichilimento nelle modalità specificate.
Inoltre, sono disponibili i seguenti metodi di costruzione e di aiuto rapido:
Rubrica 1 | Rubrica 2 |
|---|---|
zero() | Costruisce l'operatore di identità additiva. |
one() | Crea l'operatore di identità moltiplicativa. |
from_terms(termini) | Crea un nuovo operatore a partire da un iteratore di termini (vedi anche iter_terms()). |
from_terms_with_groups(termini) | Crea un nuovo operatore a partire da un iteratore di termini con gruppi (vedi anche iter_terms_with_groups()). |
Formattazione
Negli esempi precedenti, gli operatori creati sono stati visualizzati utilizzando l'output di format(), il che permette di ottenere una rappresentazione dell'operatore leggibile dall'utente.
>>> print(format(op))
1.000000e0 +0.000000e0j * ()
-3.000000e0 +0.000000e0j * (-0)
0.000000e0 +4.000000e0j * (-0 +1)
2.000000e0 +0.000000e0j * (+0)
-0.000000e0-5.000000e-1j * (+0 +1 -2 -3)
L'ordine di stampa di format(op) viene ordinato in modo esplicito prima della stampa. Pertanto, non riflette l’ordine dei termini all’interno dell’operatore.
È possibile ottenere una forma alternativa dalla funzione repr() , che fornisce una rappresentazione interpretabile nel Python. In altre parole, questo output può essere facilmente copiato e incollato in una shell Python :
>>> print(repr(op))
FermionOperator.from_dict({...})
Infine, per gli operatori di grandi dimensioni, entrambi questi output potrebbero risultare molto lunghi e indesiderabili. A questo punto, dalla funzione str() è possibile ottenere un modulo molto semplice con informazioni minime:
>>> print(str(op))
<FermionOperator with 5 terms>
Iterazione
Poiché la struttura dati sottostante è implementata in Rust e presenta un layout non banale, non è possibile iterarla direttamente:
>>> list(iter(op))
Traceback (most recent call last):
...
TypeError: 'qiskit_fermions.operators.fermion_operator.FermionOperator' object is not iterable
Questa classe fornisce invece degli iteratori personalizzati per soddisfare tale scopo:
>>> list(sorted(op.iter_terms()))
[([], (1+0j)), ([(False, 0)], (-3+0j)), ([(False, 0), (True, 1)], 4j), ([(True, 0)], (2+0j)), ([(True, 0), (True, 1), (False, 2), (False, 3)], (-0-0.5j))]
Per ulteriori dettagli relativi all'implementazione.
La tabella seguente elenca tutti gli iteratori disponibili:
Rubrica 1 | Rubrica 2 |
|---|---|
iter_terms() | Un iteratore sui termini dell'operatore. |
iter_terms_with_groups() | Un iteratore sui termini dell'operatore con il relativo indice di gruppo. |
Aritmetica
Sono supportate le seguenti operazioni aritmetiche:
Addizione/Sottrazione
>>> op = FermionOperator.one()
>>> (op + op).simplify()
FermionOperator.from_dict({(): 2+0j})
>>> (op - op).simplify()
FermionOperator.from_dict({})
>>> op += op
>>> op.simplify()
FermionOperator.from_dict({(): 2+0j})
>>> op -= op
>>> op.simplify()
FermionOperator.from_dict({})
Moltiplicazione e divisione scalari
>>> op = FermionOperator.one()
>>> (2 * op).simplify()
FermionOperator.from_dict({(): 2+0j})
>>> (op / 2).simplify()
FermionOperator.from_dict({(): 0.5+0j})
>>> op *= 2
>>> op.simplify()
FermionOperator.from_dict({(): 2+0j})
>>> op /= 2
>>> op.simplify()
FermionOperator.from_dict({(): 1+0j})
Composizione dell'operatore
La composizione degli operatori corrisponde alla moltiplicazione a sinistra: c = a & b corrisponde a . In altre parole, la composizione di due operatori restituisce un operatore risultante che esegue “prima a e poi ”. b
>>> op1 = FermionOperator.from_dict({(): 2.0, (cre(0),): 3.0})
>>> op2 = FermionOperator.from_dict({(): 1.5, (ann(1),): 4.0})
>>> comp = (op1 & op2).simplify()
>>> print(format(comp))
3.000000e0 +0.000000e0j * ()
8.000000e0 +0.000000e0j * (-1)
1.200000e1 +0.000000e0j * (-1 +0)
4.500000e0 +0.000000e0j * (+0)
>>> op2 &= op1
>>> print(format(op2.simplify()))
3.000000e0 +0.000000e0j * ()
8.000000e0 +0.000000e0j * (-1)
4.500000e0 +0.000000e0j * (+0)
1.200000e1 +0.000000e0j * (+0 -1)
>>> squared = (op1 ** 2).simplify()
>>> print(format(squared))
4.000000e0 +0.000000e0j * ()
1.200000e1 +0.000000e0j * (+0)
9.000000e0 +0.000000e0j * (+0 +0)
Per comodità, la moltiplicazione a destra viene implementata tramite c = a @ b (il che porta a ).
>>> (op1 @ op2).equiv(op2 & op1)
True
Altre operazioni
Oltre ai metodi magici corrispondenti alle operazioni aritmetiche descritte in precedenza, sono disponibili i seguenti metodi:
Rubrica 1 | Rubrica 2 |
|---|---|
adjoint() | Restituisce il coniugato ermitiano (o aggiunto) di questo operatore. |
ichop( [atol] ) | Rimuove i termini il cui coefficiente è inferiore alla soglia specificata. |
simplify( [atol] ) | Restituisce un operatore equivalente ma semplificato. |
normal_ordered( [panino] ) | Restituisce un operatore equivalente con termini ordinati normalmente. |
relabel_modes(permutazione) | Restituisce un nuovo operatore con le modalità rinominate. |
Proprietà
Infine, esistono vari metodi per verificare determinate proprietà di un operatore:
Rubrica 1 | Rubrica 2 |
|---|---|
is_hermitian( [atol] ) | Restituisce se questo operatore è ermitiano. |
max_rank() | Restituisce il rango massimo dei termini presenti in questo operatore. |
conserves_particle_number() | Indica se questo operatore conserva il numero di particelle. |
[ 1 ]
Attributi
groups
Un vettore facoltativo di indici di gruppo per ciascun termine.
Per ulteriori informazioni, consultare il modulo grouping .
Metodi
adjoint
adjoint()
Restituisce il coniugato ermitiano (o aggiunto) di questo operatore.
Ciò influisce sui termini e sui coefficienti come segue:
- le azioni in ogni termine invertono il loro ordine e alternano creazione e annichilimento
- i coefficienti sono complessi coniugati
>>> from qiskit_fermions.operators import FermionOperator
>>> op = FermionOperator.from_dict({(): -1.0j, ((True, 0), (False, 1)): 1.0})
>>> adj = op.adjoint()
>>> print(format(adj))
-0.000000e0 +1.000000e0j * ()
1.000000e0 -0.000000e0j * (+1 -0)
conserves_particle_number
conserves_particle_number()
Indica se questo operatore conserva il numero di particelle.
>>> from qiskit_fermions.operators import FermionOperator
>>> op = FermionOperator.from_dict({((True, 0), (False, 1)): 1})
>>> op.conserves_particle_number()
True
>>> op = FermionOperator.from_dict({((True, 0),): 1})
>>> op.conserves_particle_number()
False
Risultati
Se questo operatore conservi il numero di particelle.
conserves_sector
conserves_sector(block_sizes)
Indica se ogni termine mantiene il numero di particelle all'interno di ciascun blocco modale.
block_sizes suddivide l'intervallo delle modalità in blocchi consecutivi e non sovrapposti: il blocco b comprende le modalità [start_b, start_b + block_sizes[b]) dove start_b è la somma delle dimensioni dei blocchi precedenti. Un termine conserva il settore se e solo se, in ogni blocco, il numero dei suoi operatori di creazione è uguale al numero dei suoi operatori di annichilimento. Un termine che agisce su una modalità al di fuori del blocco finale non conserva il settore.
Un "empty" tratta block_sizes tutte le modalità come un unico blocco, rendendo questa operazione equivalente a conserves_particle_number(). Un singolo blocco [norb] verifica la conservazione per un settore FCI senza spin, mentre due blocchi uguali [norb, norb] verificano che le modalità alfa [0, norb) e le modalità beta [norb, 2 * norb) siano ciascuna conservate – ovvero la conservazione sia del numero di particelle che della componente z dello spin.
>>> from qiskit_fermions.operators import FermionOperator
>>> op = FermionOperator.from_dict({((True, 0), (False, 2)): 1})
>>> op.conserves_sector([4]) # one spinless block of 4 orbitals
True
>>> op.conserves_sector([2, 2]) # moves a particle from the alpha block to the beta block
False
Parametri
block_sizes – le dimensioni dei blocchi in modalità consecutiva che devono essere mantenute.
Risultati
Se ogni termine conserva il numero di particelle all'interno di ciascun blocco modale.
equiv
equiv(other, atol=1e-08)
Verifica se questo operatore è equivalente a un altro operatore.
In questo contesto, per “equivalenza” si intende un’uguaglianza approssimativa entro i limiti della tolleranza assoluta specificata. Per essere più precisi, questo metodo restituisce True, quando tutti i valori assoluti dei coefficienti nella differenza other - self sono inferiori alla soglia specificata atol.
Questo è il confronto matematico che quasi sempre si desidera. Si differenzia dall’operatore == , che verifica l’uguaglianza esatta dei termini memorizzati (i loro coefficienti, azioni, modalità e confini interni dei termini) senza tolleranza né semplificazioni. Due operatori matematicamente uguali possono quindi risultare diversi nel confronto == se sono memorizzati in modo diverso – ad esempio, un non semplificato a + a rispetto a 2 * a, oppure termini disposti in un ordine diverso. Utilizzare equiv per confrontare gli operatori entro i limiti della tolleranza numerica.
>>> from qiskit_fermions.operators import FermionOperator
>>> op = FermionOperator.from_dict({(): 1e-7})
>>> zero = FermionOperator.zero()
>>> op.equiv(zero)
False
>>> op.equiv(zero, 1e-6)
True
>>> op.equiv(zero, 1e-9)
False
Parametri
- altro – l’altro operatore con cui effettuare il confronto.
- atol – la tolleranza assoluta per il confronto. Il valore predefinito è
1e-8.
from_1body_tril_spin
classmethod from_1body_tril_spin(one_body_a, one_body_b, norb)
Costruisce un operatore a partire da integrali triangolari a un corpo relativi a specie di spin distinte.
L'operatore risultante è definito da
dove ( ) sono i coefficienti integrali memorizzati in one_body_a (one_body_b, rispettivamente), e sono gli indici ricavati dall'indice triangolare che indicizza gli array, e è il numero di orbitali, norb.
L'operatore risultante agisce su modi fermionici privi di spin con ordinamento a blocchi di spin: i modi sono gli orbitali di spin , mentre i modi sono gli orbitali di spin (pertanto, l'orbitale della specie di spin corrisponde al modo ).
>>> import numpy as np
>>> from qiskit_fermions.operators import FermionOperator
>>> one_body_a = np.array([1.0, 2.0, 3.0])
>>> one_body_b = np.array([-1.0, -2.0, -3.0])
>>> op = FermionOperator.from_1body_tril_spin(one_body_a, one_body_b, norb=2)
>>> print(format(op))
1.000000e0 +0.000000e0j * (+0 -0)
2.000000e0 +0.000000e0j * (+0 -1)
2.000000e0 +0.000000e0j * (+1 -0)
3.000000e0 +0.000000e0j * (+1 -1)
-1.000000e0 +0.000000e0j * (+2 -2)
-2.000000e0 +0.000000e0j * (+2 -3)
-2.000000e0 +0.000000e0j * (+3 -2)
-3.000000e0 +0.000000e0j * (+3 -3)
Parametri
- one_body_a – un array unidimensionale di lunghezza che memorizza i coefficienti dell’integrale elettronico a un corpo delle specie con spin , sotto forma di matrice triangolare appiattita.
- one_body_b – un array unidimensionale di lunghezza che memorizza i coefficienti dell’integrale elettronico a un corpo delle specie con spin , sotto forma di matrice triangolare appiattita.
- norb – il numero di orbitali, .
Risultati
La componente a un corpo dell'Hamiltoniano della struttura elettronica, come definito sopra.
from_1body_tril_spin_sym
classmethod from_1body_tril_spin_sym(one_body_a, norb)
Costruisce un operatore a partire da integrali triangolari a un corpo simmetrici rispetto allo spin.
L'operatore risultante è definito da
dove sono i coefficienti integrali memorizzati in one_body_a, e sono gli indici ricavati dall'indice triangolare che indicizza l'array, e è il numero di orbitali, norb.
L'operatore risultante agisce su modi fermionici privi di spin con ordinamento a blocchi di spin: i modi sono gli orbitali di spin , mentre i modi sono gli orbitali di spin (pertanto, l'orbitale della specie di spin corrisponde al modo ).
>>> import numpy as np
>>> from qiskit_fermions.operators import FermionOperator
>>> one_body_a = np.array([1.0, 2.0, 3.0])
>>> op = FermionOperator.from_1body_tril_spin_sym(one_body_a, norb=2)
>>> print(format(op))
1.000000e0 +0.000000e0j * (+0 -0)
2.000000e0 +0.000000e0j * (+0 -1)
2.000000e0 +0.000000e0j * (+1 -0)
3.000000e0 +0.000000e0j * (+1 -1)
1.000000e0 +0.000000e0j * (+2 -2)
2.000000e0 +0.000000e0j * (+2 -3)
2.000000e0 +0.000000e0j * (+3 -2)
3.000000e0 +0.000000e0j * (+3 -3)
Parametri
- one_body_a – un array unidimensionale di lunghezza che memorizza i coefficienti dell’integrale elettronico a un corpo delle specie con spin , sotto forma di matrice triangolare appiattita.
- norb – il numero di orbitali, .
Risultati
La componente a un corpo dell'Hamiltoniano della struttura elettronica, come definito sopra.
from_2body_tril_spin
classmethod from_2body_tril_spin(two_body_aa, two_body_ab, two_body_bb, norb)
Costruisce un operatore a partire da integrali triangolari a due corpi relativi a specie di spin distinte.
L'operatore risultante è definito da
dove ( , ) sono i coefficienti integrali memorizzati rispettivamente in ( two_body_aa``two_body_ab , two_body_bb,), è l'indice corrente dell'array, ( ) genera le permutazioni univoche del 4-indice (vedi sotto), e è il numero di orbitali, norb.
I coefficienti a due corpi sono definiti secondo la notazione dei chimici, , ovvero le due coppie di indici e indicano ciascuna una densità di carica. Il fattore è il prefattore convenzionale a due corpi.
L'operatore risultante agisce su modi fermionici privi di spin con ordinamento a blocchi di spin: i modi sono gli orbitali di spin , mentre i modi sono gli orbitali di spin (pertanto, l'orbitale della specie di spin corrisponde al modo ).
two_body_aa e two_body_bb sono matrici simmetriche di tipo S8-fold. Ciò significa che si tratta dei dati triangolari inferiori appiattiti delle matrici di forma (npair, npair), dove npair = (norb * (norb + 1) // 2. Questi, a loro volta, sono i dati del triangolo inferiore delle matrici a 4 dimensioni di forma (norb, norb, norb, norb). Pertanto, l'espressione sopra riportata espande l'indice appiattito in tutte le permutazioni dell'indice che indicizzano questi array a 4 dimensioni.
Tuttavia, two_body_ab è simmetrico solo rispetto a S4-fold. Pertanto, contiene tutti i dati della matrice (npair, npair) (ma ancora in forma appiattita). Il metodo esegue la corrispondente espansione degli indici. (Nella definizione precedente, abbiamo riutilizzato l'indice come abuso di notazione.)
>>> import numpy as np
>>> from qiskit_fermions.operators import FermionOperator
>>> two_body_aa = np.arange(1, 7, dtype=float)
>>> two_body_ab = np.arange(11, 20, dtype=float)
>>> two_body_bb = np.arange(-1, -7, -1, dtype=float)
>>> op = FermionOperator.from_2body_tril_spin(two_body_aa, two_body_ab, two_body_bb, norb=2)
>>> len(op)
64
Parametri
- two_body_aa – un array unidimensionale contenente i coefficienti integrali elettronici simmetrici a due corpi dell’ S8-fold, relativi alle specie con spin , sotto forma di array appiattito.
- two_body_ab – un array unidimensionale contenente i coefficienti integrali elettronici simmetrici a due corpi dell' S4-fold, relativi alle specie con spin , sotto forma di array appiattito.
- two_body_bb – un array unidimensionale contenente i coefficienti integrali elettronici simmetrici a due corpi dell’ S8-fold, relativi alle specie con spin , sotto forma di array appiattito.
- norb – il numero di orbitali, .
Risultati
La componente a due corpi dell’Hamiltoniano della struttura elettronica, come definito sopra.
from_2body_tril_spin_sym
classmethod from_2body_tril_spin_sym(two_body_aa, norb)
Costruisce un operatore a partire da integrali triangolari a due corpi simmetrici rispetto allo spin.
L'operatore risultante è definito da
dove sono i coefficienti integrali memorizzati in two_body_aa, è l'indice corrente dell'array, genera le permutazioni univoche dell'indice a 4 elementi (vedi sotto), e è il numero di orbitali, norb.
I coefficienti a due corpi sono definiti secondo la notazione dei chimici, , ovvero le due coppie di indici e indicano ciascuna una densità di carica. Il fattore è il prefattore convenzionale a due corpi.
L'operatore risultante agisce su modi fermionici privi di spin con ordinamento a blocchi di spin: i modi sono gli orbitali di spin , mentre i modi sono gli orbitali di spin (pertanto, l'orbitale della specie di spin corrisponde al modo ).
two_body_aa è una matrice simmetrica di tipo S8-fold. Ciò significa che si tratta dei dati della parte inferiore triangolare appiattita di una matrice di forma (npair, npair), dove npair = (norb * (norb + 1) // 2. Questi, a loro volta, costituiscono i dati del triangolo inferiore della matrice a 4 dimensioni di forma (norb, norb, norb, norb). Pertanto, l' e sopra riportata espande l'indice appiattito in tutte le permutazioni dell'indice che indicizzano questo array a 4 dimensioni.
>>> import numpy as np
>>> from qiskit_fermions.operators import FermionOperator
>>> two_body_aa = np.arange(1, 7, dtype=float)
>>> op = FermionOperator.from_2body_tril_spin_sym(two_body_aa, norb=2)
>>> len(op)
64
Parametri
- two_body_aa – un array unidimensionale contenente i coefficienti integrali elettronici simmetrici a due corpi dell’ S8-fold, relativi alle specie con spin , sotto forma di array appiattito.
- norb – il numero di orbitali, .
Risultati
La componente a due corpi dell’Hamiltoniano della struttura elettronica, come definito sopra.
from_dict
classmethod from_dict(data)
Crea un nuovo operatore a partire da un dizionario.
>>> from qiskit_fermions.operators import FermionOperator
>>> op = FermionOperator.from_dict(
... {
... (): 1.0-1.0j,
... ((True, 0), (False, 1)): 2.0,
... }
... )
>>> print(format(op))
1.000000e0 -1.000000e0j * ()
2.000000e0 +0.000000e0j * (+0 -1)
Parametri
dati – un dizionario che associa tuple di termini a coefficienti complessi. Ogni chiave è una tupla composta da coppie (bool, int) . È possibile utilizzare e cre() ann() per semplificarne la costruzione.
Risultati
Un nuovo operatore.
from_fcidump
classmethod from_fcidump(fcidump)
Crea un FermionOperator partendo da una struttura dati FCIDump .
Supponendo di avere un file FCIDump denominato molecule.fcidump, è possibile costruire l'operatore a seconda quantizzazione nel modo seguente:
from qiskit_fermions.operators import FermionOperator
from qiskit_fermions.operators.library import FCIDump
fcidump = FCIDump.from_file("molecule.fcidump")
operator = FermionOperator.from_fcidump(fcidump)Parametri
fcidump – la struttura dati FCIDump.
Risultati
L'operatore costruito. Quando FCIDump fornisce un'energia costante (ad esempio, quella della repulsione nucleare), questa viene inclusa come termine identitario ().
from_terms
classmethod from_terms(terms)
Crea un nuovo operatore a partire da un iteratore di termini (vedi anche iter_terms()).
>>> from qiskit_fermions.operators import FermionOperator
>>> op = FermionOperator.from_dict({(): 2.0, ((True, 0),): 1.0, ((False, 1),): -1.0j})
>>> op.equiv(FermionOperator.from_terms(op.iter_terms()))
True
Parametri
termini – un iteratore di termini generato da iter_terms().
Risultati
Un nuovo operatore.
from_terms_with_groups
classmethod from_terms_with_groups(terms)
Crea un nuovo operatore a partire da un iteratore di termini con gruppi (vedi anche iter_terms_with_groups()).
>>> from qiskit_fermions.operators import FermionOperator
>>> op = FermionOperator(
... [2.0, 1.0, -1.0],
... [True, False, True, False],
... [0, 1, 1, 0],
... [0, 0, 2, 4],
... )
>>> op.groups = [0, 1, 1]
>>> reconstructed = FermionOperator.from_terms_with_groups(op.iter_terms_with_groups())
>>> op.equiv(reconstructed) and op.groups == reconstructed.groups
True
Parametri
termini – un iteratore di termini generato da iter_terms_with_groups().
Risultati
Un nuovo operatore.
get_actions
get_actions()
Restituisce un elenco in sola lettura delle azioni dell'operatore.
Questo metodo restituisce una copia dei dati interni.
La spiegazione della struttura interna dei dati è disponibile qui.
>>> from qiskit_fermions.operators import FermionOperator
>>> op = FermionOperator.one()
>>> op += FermionOperator.from_dict({((True, 0), (False, 1)): 1.0})
>>> op.get_actions()
[True, False]
Risultati
Un elenco delle azioni dell'operatore.
get_boundaries
get_boundaries()
Restituisce un elenco in sola lettura degli indici che indicano i confini tra i termini dell'operatore.
Questo metodo restituisce una copia dei dati interni.
La spiegazione della struttura interna dei dati è disponibile qui.
>>> from qiskit_fermions.operators import FermionOperator
>>> op = FermionOperator.one()
>>> op += FermionOperator.from_dict({((True, 0), (False, 1)): 1.0})
>>> op.get_boundaries()
[0, 0, 2]
Risultati
Un elenco dei limiti previsti dai termini e dalle condizioni dell'operatore.
get_coeffs
get_coeffs()
Restituisce un elenco in sola lettura dei coefficienti dell'operatore.
Questo metodo restituisce una copia dei dati interni.
La spiegazione della struttura interna dei dati è disponibile qui.
>>> from qiskit_fermions.operators import FermionOperator
>>> op = FermionOperator.one()
>>> op += -1j * FermionOperator.one()
>>> op.get_coeffs()
[(1+0j), -1j]
Risultati
Un elenco dei coefficienti dell'operatore.
get_modes
get_modes()
Restituisce un elenco in sola lettura degli indici delle modalità su cui l'operatore ha agito.
Questo metodo restituisce una copia dei dati interni.
La spiegazione della struttura interna dei dati è disponibile qui.
>>> from qiskit_fermions.operators import FermionOperator
>>> op = FermionOperator.one()
>>> op += FermionOperator.from_dict({((True, 0), (False, 1)): 1.0})
>>> op.get_modes()
[0, 1]
Risultati
Un elenco delle modalità dell'operatore.
get_support
get_support()
Restituisce l'insieme degli indici di modalità su cui agisce questo operatore.
>>> from qiskit_fermions.operators import FermionOperator
>>> op = FermionOperator.from_dict(
... {
... ((True, 0), (False, 4)): 1,
... ((True, 1), (True, 3), (False, 4), (False, 7)): 1,
... }
... )
>>> assert op.get_support() == {0, 1, 3, 4, 7}
Risultati
L'insieme degli indici di modalità su cui agisce questo operatore.
has_groups
has_groups()
Indica se questo operatore tiene traccia degli indici di gruppo.
Ciò equivale a (ma è più economico di) controllare op.groups is not None, poiché non copia gli indici dei gruppi dall'operatore per esaminarli.
Questo restituisce un valore anche True quando groups è una lista vuota, ovvero lo stato di un operatore raggruppato che non contiene termini.
>>> from qiskit_fermions.operators import FermionOperator
>>> op = FermionOperator(
... [1.0, 2.0, -1.0, -2.0],
... [True, False, True, False, True, False, True, False],
... [0, 1, 2, 3, 1, 0, 3, 2],
... [0, 2, 4, 6, 8],
... )
>>> op.has_groups()
False
>>> op.groups = [0, 1, 0, 1]
>>> op.has_groups()
True
Risultati
Se groups è impostato su questo operatore.
ichop
ichop(atol=1e-08)
Rimuove i termini il cui coefficiente è inferiore alla soglia specificata.
Questo metodo modifica l'operatore direttamente e restituisce None.
Questo metodo tronca i coefficienti in modo avido! Se l'operatore su cui si agisce può contenere coefficienti distinti per termini duplicati, valuta invece simplify() di chiamare!
>>> from qiskit_fermions.operators import FermionOperator
>>> op = FermionOperator.from_dict({(): 1e-4, ((True, 0),): 1e-6, ((False, 0),): 1e-10})
>>> print(format(op))
1.000000e-4 +0.000000e0j * ()
1.000000e-10 +0.000000e0j * (-0)
1.000000e-6 +0.000000e0j * (+0)
>>> op.ichop()
>>> print(format(op))
1.000000e-4 +0.000000e0j * ()
1.000000e-6 +0.000000e0j * (+0)
>>> op.ichop(1e-5)
>>> print(format(op))
1.000000e-4 +0.000000e0j * ()
Parametri
atol – la tolleranza assoluta per il valore di soglia. Il valore predefinito è 1e-8.
is_hermitian
is_hermitian(atol=1e-08)
Restituisce se questo operatore è ermitiano.
Questo controllo viene implementato utilizzando equiv() la differenza normal_ordered() tra e self i suoi e adjoint() zero().
>>> from qiskit_fermions.operators import FermionOperator
>>> op = FermionOperator.from_dict({
... ((True, 0), (False, 1)): 1.00001j,
... ((True, 1), (False, 0)): -1j,
... })
>>> op.is_hermitian()
False
>>> op.is_hermitian(1e-4)
True
Parametri
atol – Il livello di precisione numerica entro il quale i coefficienti sono considerati uguali. Il valore predefinito è 1e-8.
Risultati
Se questo operatore sia ermitiano.
iter_terms
iter_terms()
Un iteratore sui termini dell'operatore.
La modifica degli elementi dell'iterazione non influisce sui dati sottostanti dell'operatore.
>>> from qiskit_fermions.operators import FermionOperator
>>> op = FermionOperator.from_dict({(): 2.0, ((True, 0),): 1.0, ((False, 1),): -1.0j})
>>> list(sorted(op.iter_terms()))
[([], (2+0j)), ([(False, 1)], (-0-1j)), ([(True, 0)], (1+0j))]
iter_terms_with_groups
iter_terms_with_groups()
Un iteratore sui termini dell'operatore con il relativo indice di gruppo.
La modifica degli elementi dell'iterazione non influisce sui dati sottostanti dell'operatore.
>>> from qiskit_fermions.operators import FermionOperator
>>> op = FermionOperator(
... [2.0, 1.0, -1.0],
... [True, False, True, False],
... [0, 1, 1, 0],
... [0, 0, 2, 4],
... )
>>> op.groups = [0, 1, 1]
>>> list(sorted(op.iter_terms_with_groups()))
[([], (2+0j), 0), ([(True, 0), (False, 1)], (1+0j), 1), ([(True, 1), (False, 0)], (-1+0j), 1)]
max_rank
max_rank()
Restituisce il rango massimo dei termini presenti in questo operatore.
La lunghezza del termine più lungo può dipendere dalla forma dell’operatore, il che significa che (ad esempio) la semplificazione dell’operatore o l’ordinamento normale possono determinare un rango massimo diverso.
>>> from qiskit_fermions.operators import FermionOperator
>>> op = FermionOperator.from_dict({
... ((True, 0), (False, 1), (True, 2), (False, 3)): 1,
... })
>>> op.max_rank()
4
Risultati
Il grado massimo di questo operatore.
normal_ordered
normal_ordered(sandwich=None)
Restituisce un operatore equivalente con termini ordinati normalmente.
L'ordine normale di un termine operatore è definito in modo tale che tutte le azioni di creazione compaiano prima di tutte le azioni di annichilimento. All’interno di ciascun gruppo, le modalità su cui agisce l’azione sono ordinate in ordine lessicografico. Il fatto che l'ordine sia crescente o decrescente dipende dal valore dell'argomento sandwich :
None(impostazione predefinita): entrambi i gruppi sono ordinati in ordine lessicografico decrescente (ad es.+1 +0 -1 -0)True: gli indici più grandi compaiono verso il centro, ovvero le azioni di creazione sono in ordine lessicografico crescente mentre quelle di annichilimento sono in ordine decrescente (ad es.+0 +1 -1 -0)False: gli indici più piccoli compaiono verso il centro, ovvero le azioni di creazione sono in ordine lessicografico decrescente mentre quelle di annichilimento sono in ordine crescente (ad es.+1 +0 -0 -1)
Quando si riorganizza un termine, occorre tenere conto delle relazioni di anticommutazione, , il che implica che il numero dei termini possa variare.
>>> from qiskit_fermions.operators import FermionOperator
>>> op = FermionOperator.from_dict({((False, 1), (True, 1), (False, 0), (True, 0)): 1})
>>> print(format(op.normal_ordered().simplify()))
1.000000e0 +0.000000e0j * ()
-1.000000e0 +0.000000e0j * (+0 -0)
-1.000000e0 +0.000000e0j * (+1 -1)
-1.000000e0 +0.000000e0j * (+1 +0 -1 -0)
>>> print(format(op.normal_ordered(sandwich=True).simplify()))
1.000000e0 +0.000000e0j * ()
-1.000000e0 +0.000000e0j * (+0 -0)
1.000000e0 +0.000000e0j * (+0 +1 -1 -0)
-1.000000e0 +0.000000e0j * (+1 -1)
>>> print(format(op.normal_ordered(sandwich=False).simplify()))
1.000000e0 +0.000000e0j * ()
-1.000000e0 +0.000000e0j * (+0 -0)
-1.000000e0 +0.000000e0j * (+1 -1)
1.000000e0 +0.000000e0j * (+1 +0 -0 -1)
Risultati
Un operatore equivalente ma con ordine normale.
num_groups
num_groups()
Restituisce il numero di gruppi.
Se è groups None, questa funzione restituisce anche None. In caso contrario, restituirà il numero di gruppi, definito come l'indice del gruppo più grande presente più 1 (che potrà quindi essere utilizzato come indice per il gruppo successivo).
>>> from qiskit_fermions.operators import FermionOperator
>>> op = FermionOperator(
... [1.0, 2.0, -1.0, -2.0],
... [True, False, True, False, True, False, True, False],
... [0, 1, 2, 3, 1, 0, 3, 2],
... [0, 2, 4, 6, 8],
... )
>>> op.groups = [0, 1, 0, 1]
>>> op.num_groups()
2
Risultati
L'indice di gruppo più importante è in groups rialzo di 1.
one
classmethod one()
Crea l'operatore di identità moltiplicativa.
La composizione dell'operatore ottenuto con questo metodo con un altro operatore non produce alcun effetto.
>>> from qiskit_fermions.operators import FermionOperator
>>> op = FermionOperator.from_dict({(): 2.0})
>>> one = FermionOperator.one()
>>> op & one == op
True
relabel_modes
relabel_modes(permutation)
Restituisce un nuovo operatore con le modalità rinominate.
>>> from qiskit_fermions.operators import FermionOperator
>>> op = FermionOperator.from_dict({
... ((True, 0), (False, 1)): 1,
... ((True, 0), (False, 1), (True, 2), (False, 3)): 1,
... })
>>> permutation = [5, 6, 4, 3]
>>> relabeled = op.relabel_modes(permutation)
>>> print(format(relabeled))
1.000000e0 +0.000000e0j * (+5 -6)
1.000000e0 +0.000000e0j * (+5 -6 +4 -3)
Parametri
permutazione – l'elenco delle permutazioni degli indici. La modalità viene i rinominata in permutation[i], pertanto l'elenco non deve contenere voci duplicate e deve essere sufficientemente lungo da indicizzare ogni modalità su cui agisce l'operatore (la sua lunghezza deve superare l'indice di modalità più elevato dell'operatore).
Risultati
Un nuovo operatore con le modalità rinominate.
Aumenti
ValueError – se contiene permutation voci duplicate o è troppo breve per ridenominare una modalità su cui agisce l'operatore.
simplify
simplify(atol=1e-08)
Restituisce un operatore equivalente ma semplificato.
Il processo di semplificazione somma innanzitutto tutti i coefficienti appartenenti a termini uguali e poi mantiene solo quelli il cui coefficiente totale supera la tolleranza specificata (proprio come ichop()).
Quando un operatore è stato manipolato aritmeticamente o costruito in modo tale da non garantire l'unicità dei termini, è opportuno richiamare questo metodo prima di applicare qualsiasi metodo che filtri i coefficienti numericamente piccoli, al fine di evitare la perdita di informazioni. Si veda l'esempio riportato di seguito, che illustra come ichop() sia possibile troncare termini la cui somma porta a un coefficiente di grandezza totale che non dovrebbe essere troncato:
>>> from qiskit_fermions.operators import FermionOperator
>>> coeffs = [1e-5] * int(1e5)
>>> boundaries = [0] + [0] * int(1e5)
>>> op = FermionOperator(coeffs, [], [], boundaries)
>>> canon = op.simplify(1e-4)
>>> assert canon.equiv(op.one(), 1e-6)
>>> op.ichop(1e-4)
>>> assert op.equiv(op.zero(), 1e-6)
Parametri
atol – la tolleranza assoluta per il valore di soglia. Il valore predefinito è 1e-8.
Risultati
Un operatore equivalente ma semplificato.
split_out_groups
split_out_groups(group_indices=None)
Suddivide questo operatore in un elenco facoltativo di nuovi operatori in base a groups.
Se è groups None, questa funzione restituisce anche None. Altrimenti, se group_indices è None (impostazione predefinita), restituisce una lista contenente un nuovo operatore per ogni indice di gruppo in groups, in ordine di indice. Se group_indices è specificato, vengono generati solo gli indici richiesti, nell'ordine indicato: ciò evita il costo legato alla creazione di operatori per gruppi che non vengono mai utilizzati, il che è particolarmente vantaggioso quando è necessario ricorrere solo a un numero limitato di gruppi rispetto a un totale molto più ampio, ad esempio quando si effettua un sottocampionamento dei gruppi per una formula di prodotto randomizzata. Un indice duplicato in group_indices viene restituito una volta per ogni occorrenza.
>>> from qiskit_fermions.operators import FermionOperator
>>> op = FermionOperator(
... [1.0, 2.0, -1.0, -2.0],
... [True, False, True, False, True, False, True, False],
... [0, 1, 2, 3, 1, 0, 3, 2],
... [0, 2, 4, 6, 8],
... )
>>> print(op.split_out_groups())
None
>>> op.groups = [0, 1, 0, 1]
>>> groups = op.split_out_groups()
>>> for g in groups:
... print(list(sorted(g.iter_terms())))
[([(True, 0), (False, 1)], (1+0j)), ([(True, 1), (False, 0)], (-1+0j))]
[([(True, 2), (False, 3)], (2+0j)), ([(True, 3), (False, 2)], (-2+0j))]
>>> groups = op.split_out_groups(group_indices=[1])
>>> for g in groups:
... print(list(sorted(g.iter_terms())))
[([(True, 2), (False, 3)], (2+0j)), ([(True, 3), (False, 2)], (-2+0j))]
Parametri
group_indices – gli indici di gruppo per i quali creare gli operatori, nell'ordine di output desiderato. Se non specificato, vengono creati tutti i gruppi, in ordine di indice.
Risultati
Un vettore facoltativo contenente un nuovo operatore per ciascun indice di gruppo richiesto.
zero
classmethod zero()
Costruisce l'operatore di identità additiva.
L'aggiunta di un operatore costruito con questo metodo a un altro operatore non ha alcun effetto.
>>> from qiskit_fermions.operators import FermionOperator
>>> op = FermionOperator.from_dict({(): 2.0})
>>> zero = FermionOperator.zero()
>>> op + zero == op
True
Metodi del protocollo
_anti_commutator_
static _anti_commutator_(op_a, op_b)
_commutator_
static _commutator_(op_a, op_b)
_double_commutator_
static _double_commutator_(op_a, op_b, op_c, sign)
_linear_operator_
_linear_operator_(norb, nelec)
Restituisce un oggetto SciPy per LinearOperator questo operatore nel settore FCI (norb, nelec) .
Ciò viene implementato ffsim.SupportsLinearOperator convertendo il dato in un e ffsim.FermionOperator passandolo a ffsim.linear_operator(): la simulazione è di competenza di ffsim, mentre questo pacchetto gestisce il circuito indipendente dal mappatore anziché un secondo backend di simulazione.
ffsim rifiuta un operatore che non conservi sia il numero di particelle sia la componente z dello spin, poiché un operatore di questo tipo non ha alcun effetto su un settore fisso e ignora silenziosamente un termine che agisce su un orbitale al di fuori di esso [0, norb).
Parametri
- norb (int) – il numero di orbitali spaziali.
- nelec (int |tuple[int, int]) – il numero di elettroni – un numero intero per un settore senza spin, oppure una coppia
(n_alpha, n_beta)per un settore con spin. - self (FermionOperator)
Risultati
A applicando scipy.sparse.linalg.LinearOperator questo operatore al settore richiesto.
Tipo di restituzione
_majorana_operator_
_majorana_operator_()
Converte questo operatore in un MajoranaOperator.
Questo implementa il protocollo SupportsMajoranaOperator delegando a fermion_to_majorana().
_trace_
_trace_(norb, nelec)
Restituisce la traccia di questo operatore sul settore FCI (norb, nelec) .
Ciò implementa tramite ffsim.SupportsTrace ffsim.trace(), rispecchiando _linear_operator_.
Parametri
- norb (int) – il numero di orbitali spaziali.
- nelec (int |tuple[int, int]) – il numero di elettroni – un numero intero per un settore senza spin, oppure una coppia
(n_alpha, n_beta)per un settore con spin. - self (FermionOperator)
Risultati
La traccia di questo operatore sul settore richiesto.
Tipo di restituzione