QfFermionOperator
QfFermionOperator
struct QfFermionOperator
Un operatore fermionico senza spin.
Si tratta di una struttura dati trasparente rispetto all'API C, i cui meccanismi interni sono implementati interamente in Rust. Il resto di questa pagina descrive la struttura e le relative funzioni per l'utilizzo di questa struttura.
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 anticommutative: [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 struttura 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:
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 le rispettive funzioni:
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 qf_ferm_op_simplify().
Costruzioni
È possibile costruire un nuovo operatore direttamente specificando gli array corrispondenti descritti sopra. In alternativa, un campo vuoto può QfFermionOperator essere inizializzato con e qf_ferm_op_zero() i termini possono essere aggiunti in modo iterativo tramite qf_ferm_op_add_term().
qf_ferm_op_new() | Crea un nuovo operatore a partire dagli array forniti. |
qf_ferm_op_zero() | Costruisce l'operatore di identità additiva. |
qf_ferm_op_one() | Crea l'operatore di identità moltiplicativo. |
qf_ferm_op_add_term() | Aggiunge un termine a un file esistente QfFermionOperator. |
A QfFermionOperator può essere liberato con qf_ferm_op_free().
Aritmetica
Le seguenti funzioni consentono di eseguire operazioni aritmetiche:
qf_ferm_op_add() | Somma due operatori. |
qf_ferm_op_mul() | Moltiplica un operatore per uno scalare. |
qf_ferm_op_compose() | Combina due operatori tra loro. |
qf_ferm_op_adjoint() | Restituisce l'operatore coniugato ermitiano. |
Manipolazione
Le seguenti funzioni forniscono la logica di manipolazione degli operatori:
qf_ferm_op_ichop() | Elimina i termini con coefficienti di piccola entità. |
qf_ferm_op_simplify() | Restituisce un operatore equivalente ma semplificato. |
qf_ferm_op_normal_ordered() | Restituisce un operatore equivalente con termini ordinati normalmente. |
qf_ferm_op_relabel_modes() | Rinomina le modalità di un operatore. |
Proprietà
Sono disponibili le seguenti funzioni per verificare determinate proprietà di un operatore.
qf_ferm_op_is_hermitian() | Restituisce se un operatore è ermitiano. |
qf_ferm_op_max_rank() | Restituisce il rango massimo dei termini presenti in questo operatore. |
qf_ferm_op_conserves_particle_number() | Restituisce se un operatore conserva il numero di particelle. |
[ 1 ]
Membri
qf_ferm_op_new
QfFermionOperator *qf_ferm_op_new(uint64_t num_terms, uint64_t num_actions, const QkComplex64 *coeffs, const bool *actions, const uint32_t *modes, const uint32_t *boundaries)
Crea un nuovo operatore.
Qualsiasi argomento di tipo puntatore può essere NULL se e solo se la lunghezza corrispondente è zero.
Esempio
1uint64_t num_terms = 3;
2uint64_t num_actions = 4;
3bool actions[4] = {true, false, true, false};
4uint32_t modes[4] = {0, 1, 2, 3};
5QkComplex64 coeffs[3] = {{1.0, 0.0}, {-1.0, 0.0}, {0.0, -1.0}};
6uint32_t boundaries[4] = {0, 0, 2, 4};
7QfFermionOperator *op = qf_ferm_op_new(num_terms, num_actions, coeffs,
8 actions, modes, boundaries);Parametri
- num_terms – Il numero di termini presenti nell'operatore.
- num_actions – Il numero di azioni sommato su tutti i termini.
- coeffs – Un puntatore a un array di coefficienti dei termini. La lunghezza di questo array dovrebbe essere
num_terms. - azioni – Un puntatore a un array di azioni relative a tutti i termini. La lunghezza di questo array dovrebbe essere
num_actions. - modalità – Un puntatore a un array contenente le modalità di azione per tutti i termini. La lunghezza di questo array dovrebbe essere
num_actions. - confini – Un puntatore a un array contenente i confini tra i termini. La lunghezza di questo array dovrebbe essere
num_terms + 1.
qf_ferm_op_free
void qf_ferm_op_free(QfFermionOperator *op)
Rilascia un operatore esistente.
Esempio
1QfFermionOperator *op = qf_ferm_op_one();
2qf_ferm_op_free(op);Parametri
- op – Un puntatore all’operatore fermionico da liberare.
qf_ferm_op_get_coeffs
void qf_ferm_op_get_coeffs(const QfFermionOperator *op, QkComplex64 **coeffs_out, uint64_t *coeffs_len)
Fornisce accesso in sola lettura ai coefficienti dell'operatore.
La spiegazione della struttura interna dei dati è disponibile qui.
Esempio
1uint64_t num_terms = 2;
2uint64_t num_actions = 0;
3QkComplex64 coeffs[2] = {{1.0, 0.0}, {0.0, -1.0}};
4uint32_t boundaries[3] = {0, 0, 0};
5QfFermionOperator *op =
6 qf_ferm_op_new(num_terms, num_actions, coeffs, NULL, NULL, boundaries);
7
8QkComplex64 *coeffs_out;
9uint64_t *coeffs_len;
10
11qf_ferm_op_get_coeffs(op, &coeffs_out, &coeffs_len);
12
13assert(coeffs_len == 2);Questa funzione restituisce una copia dei dati interni.
Parametri
- op – Un puntatore all’operatore fermionico di cui si desidera accedere ai coefficienti.
- coeffs_out – Un puntatore all'array di valori complessi in cui scrivere i coefficienti.
- coeffs_len – Un puntatore all’intero in cui scrivere la lunghezza dell’array di output.
qf_ferm_op_get_actions
void qf_ferm_op_get_actions(const QfFermionOperator *op, bool **actions_out, uint64_t *actions_len)
Fornisce un accesso in sola lettura alle azioni dell'operatore.
La spiegazione della struttura interna dei dati è disponibile qui.
Esempio
1uint64_t num_terms = 2;
2uint64_t num_actions = 2;
3bool actions[2] = {true, false};
4uint32_t modes[2] = {0, 1};
5QkComplex64 coeffs[2] = {{1.0, 0.0}, {0.0, -1.0}};
6uint32_t boundaries[3] = {0, 0, 2};
7QfFermionOperator *op =
8 qf_ferm_op_new(num_terms, num_actions, coeffs, actions, modes, boundaries);
9
10QkComplex64 *actions_out;
11uint64_t *actions_len;
12
13qf_ferm_op_get_actions(op, &actions_out, &actions_len);
14
15assert(actions_len == 2);Questa funzione restituisce una copia dei dati interni.
Parametri
- op – Un puntatore all’operatore fermionico le cui azioni si desidera accedere.
- actions_out – Un puntatore all'array di valori booleani in cui scrivere le azioni.
- actions_len – Un puntatore all'intero in cui scrivere la lunghezza dell'array di output.
qf_ferm_op_get_modes
void qf_ferm_op_get_modes(const QfFermionOperator *op, uint32_t **modes_out, uint64_t *modes_len)
Fornisce accesso in sola lettura agli indici delle modalità su cui l’operatore ha agito.
La spiegazione della struttura interna dei dati è disponibile qui.
Esempio
1uint64_t num_terms = 2;
2uint64_t num_actions = 2;
3bool actions[2] = {true, false};
4uint32_t modes[2] = {0, 1};
5QkComplex64 coeffs[2] = {{1.0, 0.0}, {0.0, -1.0}};
6uint32_t boundaries[3] = {0, 0, 2};
7QfFermionOperator *op =
8 qf_ferm_op_new(num_terms, num_actions, coeffs, actions, modes, boundaries);
9
10QkComplex64 *modes_out;
11uint64_t *modes_len;
12
13qf_ferm_op_get_modes(op, &modes_out, &modes_len);
14
15assert(modes_len == 2);Questa funzione restituisce una copia dei dati interni.
Parametri
- op – Un puntatore all’operatore fermionico di cui si desidera accedere alle modalità.
- modes_out – Un puntatore all’array di valori booleani in cui scrivere le modalità.
- modes_len – Un puntatore all’intero in cui scrivere la lunghezza dell’array di output.
qf_ferm_op_get_boundaries
void qf_ferm_op_get_boundaries(const QfFermionOperator *op, size_t **boundaries_out, uint64_t *boundaries_len)
Fornisce un accesso in sola lettura agli indici che indicano i confini tra i termini dell’operatore.
La spiegazione della struttura interna dei dati è disponibile qui.
Esempio
1uint64_t num_terms = 2;
2uint64_t num_actions = 2;
3bool actions[2] = {true, false};
4uint32_t modes[2] = {0, 1};
5QkComplex64 coeffs[2] = {{1.0, 0.0}, {0.0, -1.0}};
6uint32_t boundaries[3] = {0, 0, 2};
7QfFermionOperator *op =
8 qf_ferm_op_new(num_terms, num_actions, coeffs, actions, modes, boundaries);
9
10QkComplex64 *boundaries_out;
11uint64_t *boundaries_len;
12
13qf_ferm_op_get_boundaries(op, &boundaries_out, &boundaries_len);
14
15assert(boundaries_len == 3);Questa funzione restituisce una copia dei dati interni.
Parametri
- op – Un puntatore all’operatore fermionico ai cui confini si desidera accedere.
- boundaries_out – Un puntatore all'array di valori booleani in cui scrivere i limiti.
- boundaries_len – Un puntatore all’intero in cui scrivere la lunghezza dell’array di output.
qf_ferm_op_zero
QfFermionOperator *qf_ferm_op_zero(void)
Costruisce l'operatore di identità additiva.
L'aggiunta di un operatore costruito con questo metodo a un altro operatore non ha alcun effetto.
Esempio
1QfFermionOperator *zero = qf_ferm_op_zero();
2
3QfFermionOperator *op_plus_zero = qf_ferm_op_add(op, zero);
4
5assert(qf_ferm_op_equal(op, op_plus_zero));Risultati
Un puntatore all’operatore creato.
qf_ferm_op_one
QfFermionOperator *qf_ferm_op_one(void)
Crea l'operatore di identità moltiplicativo.
La composizione dell'operatore ottenuto con questo metodo con un altro operatore non ha alcun effetto.
Esempio
1QfFermionOperator *one = qf_ferm_op_one();
2
3QfFermionOperator *op_times_one = qf_ferm_op_compose(op, one);
4
5assert(qf_ferm_op_equal(op, op_times_one));Risultati
Un puntatore all’operatore creato.
qf_ferm_op_has_groups
bool qf_ferm_op_has_groups(const QfFermionOperator *op)
Verifica se questo operatore tiene traccia degli indici di gruppo.
Spiegazione dei termini relativi agli operatori di gruppo: utilizzare la struttura degli operatori.
Esempio
1QfFCIDump *fcidump = qf_fcidump_from_file("molecule.fcidump");
2QfFermionOperator *op = qf_ferm_op_from_fcidump(fcidump);
3
4bool has_groups = qf_ferm_op_has_groups(op);
5
6assert(!has_groups);Parametri
- op – Un puntatore all’operatore fermionico da verificare.
Risultati
Se l'operatore specificato possiede un attributo groups .
qf_ferm_op_num_groups
uint32_t qf_ferm_op_num_groups(const QfFermionOperator *op)
Recupera il numero di gruppi associati a un operatore.
Spiegazione dei termini relativi agli operatori di gruppo: utilizzare la struttura degli operatori.
Esempio
1QfFCIDump *fcidump = qf_fcidump_from_file("molecule.fcidump");
2QfFermionOperator *op = qf_ferm_op_from_fcidump(fcidump);
3
4uint32_t num_groups = qf_ferm_op_num_groups(op);Il numero di gruppi viene calcolato in modo differito come l'indice del gruppo più grande presente più 1.
Parametri
- op – Un puntatore all’operatore fermionico di cui si desidera ottenere il numero di gruppi.
Risultati
Il numero di indici di gruppo derivante dall'attributo groups dell'operatore.
qf_ferm_op_group_weights
void qf_ferm_op_group_weights(const QfFermionOperator *op, double *weights_out)
Calcola la media del modulo assoluto del coefficiente per ciascun gruppo.
La i-esima voce è la somma di abs(coeff) sui termini del gruppo i, divisa per il numero di termini di quel gruppo. Si tratta del peso di campionamento di una formula di prodotto randomizzata (ad esempio qDRIFT ) che estrae interi gruppi anziché singoli termini, e viene calcolato in un unico passaggio sull’operatore anziché riducendo e qf_ferm_op_get_coeffs() ( qf_ferm_op_get_groups() un valore per ciascun termine non raggruppato ) dal lato del chiamante.
Spiegazione dei termini relativi agli operatori di gruppo: utilizzare la struttura degli operatori.
Esempio
1uint64_t num_terms = 4;
2uint64_t num_actions = 8;
3bool actions[8] = {true, false, true, false, true, false, true, false};
4uint32_t modes[8] = {0, 1, 2, 3, 1, 0, 3, 2};
5QkComplex64 coeffs[4] = {{1.0, 0.0}, {2.0, 0.0}, {-1.0, 0.0}, {-2.0, 0.0}};
6uint32_t boundaries[5] = {0, 2, 4, 6, 8};
7QfFermionOperator *op =
8 qf_ferm_op_new(num_terms, num_actions, coeffs, actions, modes, boundaries);
9
10uint32_t groups_in[4] = {0, 1, 0, 1};
11qf_ferm_op_set_groups(op, groups_in, num_terms);
12
13double weights[2];
14qf_ferm_op_group_weights(op, weights);
15
16assert(weights[0] == 1.0);
17assert(weights[1] == 2.0);Un indice di gruppo a cui nessun termine è associato ha peso 0.0, il che lo esclude dal campione.
Parametri
- op – Un puntatore all’operatore fermionico di cui si devono calcolare i pesi di gruppo.
- weights_out – Un puntatore all'array di valori di tipo double in cui scrivere i pesi. Deve essere dimensionato in base a :c:func
qf_ferm_op_num_groups:.
qf_ferm_op_get_groups
void qf_ferm_op_get_groups(const QfFermionOperator *op, uint32_t **groups_out, uint64_t *groups_len)
Recupera gli indici di gruppo per tutti i termini dell'operatore.
Spiegazione dei termini relativi agli operatori di gruppo: utilizzare la struttura degli operatori.
Esempio
1QfFermionOperator *op = ...;
2uint32_t *groups_out;
3uint32_t groups_len;
4
5qf_ferm_op_get_groups(op, &groups_out, &groups_len);Parametri
- op – Un puntatore all'operatore fermionico di cui si desidera ottenere gli indici di gruppo.
- groups_out – Un puntatore all'array di interi in cui scrivere gli indici dei gruppi.
- groups_len – Un puntatore all’intero in cui scrivere la lunghezza dell’array di output.
qf_ferm_op_set_groups
void qf_ferm_op_set_groups(QfFermionOperator *op, const uint32_t *groups_in, uint64_t groups_len)
Imposta l'attributo groups dell'operatore specificato.
Spiegazione dei termini relativi agli operatori di gruppo: utilizzare la struttura degli operatori.
Esempio
1QfFermionOperator *op = ...;
2
3uint32_t num_terms = 4;
4uint32_t groups_in[4] = {0, 1, 0, 1};
5qf_ferm_op_set_groups(op, groups_in, num_terms);Parametri
- op – Un puntatore all'operatore fermionico di cui si desidera scrivere l'attributo
groups. - groups_in – Un puntatore all'array di interi
groupsin cui scrivere nell'operatore. - groups_len – Il numero di elementi presenti nell'array
groups_in.
qf_ferm_op_del_groups
void qf_ferm_op_del_groups(QfFermionOperator *op)
Elimina l'attributo groups dall'operatore specificato.
Spiegazione dei termini relativi agli operatori di gruppo: utilizzare la struttura degli operatori.
Esempio
1QfFermionOperator *op = ...;
2
3qf_ferm_op_del_groups(op);Parametri
- op – Un puntatore all’operatore fermionico di cui si desidera eliminare l’attributo
groups.
qf_ferm_op_split_out_groups
void qf_ferm_op_split_out_groups(const QfFermionOperator *op, const uint32_t *group_indices, uint64_t num_indices, QfFermionOperator **group_ops_out)
Suddivide questo operatore in un elenco di nuovi operatori in base al suo attributo groups .
Un indice duplicato in group_indices viene scritto una volta per ogni occorrenza in group_ops_out. Richiedere solo un numero limitato di gruppi rispetto a un totale molto più ampio è notevolmente più economico rispetto a richiederli tutti, poiché i termini appartenenti a un gruppo non richiesto vengono saltati anziché essere aggiunti in qualsiasi punto.
Spiegazione dei termini relativi agli operatori di gruppo: utilizzare la struttura degli operatori.
Esempio
1uint64_t num_terms = 4;
2uint64_t num_actions = 8;
3bool actions[8] = {true, false, true, false, true, false, true, false};
4uint32_t modes[8] = {0, 1, 2, 3, 1, 0, 3, 2};
5QkComplex64 coeffs[4] = {{1.0, 0.0}, {1.0, 0.0}, {1.0, 0.0}, {1.0, 0.0}};
6uint32_t boundaries[5] = {0, 2, 4, 6, 8};
7QfFermionOperator *op =
8 qf_ferm_op_new(num_terms, num_actions, coeffs, actions, modes, boundaries);
9
10uint32_t groups_in[4] = {0, 1, 0, 1};
11qf_ferm_op_set_groups(op, groups_in, num_terms);
12
13// build every group, in index order
14QfFermionOperator *group_ops[2];
15qf_ferm_op_split_out_groups(op, NULL, 0, group_ops);
16
17// build only group 1
18uint32_t group_indices[1] = {1};
19QfFermionOperator *group_op[1];
20qf_ferm_op_split_out_groups(op, group_indices, 1, group_op);Parametri
- op – Un puntatore all'operatore fermionico
groupsda estrarre. - group_indices – Un puntatore all'array degli indici dei gruppi per i quali costruire gli operatori, nell'ordine di output desiderato. È possibile che
NULL, in tal caso, ogni gruppo venga costruito in ordine di indice (il che equivale a passare ogni indice da0a :c:func:qf_ferm_op_num_groups- 1). - num_indices – Il numero di indici presenti nell'array
group_indices. Viene ignorato se ègroup_indicesNULL. - group_ops_out – Un puntatore all'array di :c:struct:
QfFermionOperatorin cui scrivere gli operatori per ciascun gruppo richiesto. Deve essere dimensionato in base anum_indicesquandogroup_indicesè diverso daNULL, oppure in base a :c:func:qf_ferm_op_num_groupsquando èNULL.
qf_ferm_op_add_term
void qf_ferm_op_add_term(QfFermionOperator *op, uint64_t num_actions, const bool *actions, const uint32_t *modes, const QkComplex64 *coeff)
Aggiunge un termine a un operatore esistente.
Qualsiasi argomento di tipo puntatore può essere NULL se e solo se la lunghezza corrispondente è zero.
Questa funzione reimposta l'attributo groups dell'operatore su NULL.
Esempio
1QfFermionOperator *one = qf_ferm_op_one();
2
3QfFermionOperator *op = qf_ferm_op_zero();
4bool actions[0] = {};
5uint32_t modes[0] = {};
6QkComplex64 coeff = {1.0, 0.0};
7
8qf_ferm_op_add_term(op, 0, actions, modes, &coeff);
9
10assert(qf_ferm_op_equal(op, one));Parametri
- op – Un puntatore all'operatore fermionico da modificare.
- num_actions – La lunghezza dell'array delle azioni.
- azioni – Un puntatore a un array di azioni. La lunghezza di questo array dovrebbe essere
num_actions. - modalità – Un puntatore a un array di modalità di azione. La lunghezza di questo array dovrebbe essere
num_actions. - coeff – Un puntatore al coefficiente complesso.
qf_ferm_op_add
QfFermionOperator *qf_ferm_op_add(const QfFermionOperator *left, const QfFermionOperator *right)
Somma due operatori.
Esempio
1QfFermionOperator *one = qf_ferm_op_one();
2QfFermionOperator *zero = qf_ferm_op_zero();
3
4QfFermionOperator *result = qf_ferm_op_add(one, zero);
5
6assert(qf_ferm_op_equal(result, one));Parametri
- sinistra – Un puntatore all'operatore di sinistra.
- right – Un puntatore all'operatore "a destra".
Risultati
Un puntatore all'operatore risultante.
qf_ferm_op_mul
QfFermionOperator *qf_ferm_op_mul(const QfFermionOperator *op, const QkComplex64 *scalar)
Moltiplica un operatore per uno scalare.
Esempio
1QfFermionOperator *one = qf_ferm_op_one();
2QkComplex64 coeff = {2.0, 0.0};
3QfFermionOperator *result = qf_ferm_op_mul(one, &coeff);
4
5QfFermionOperator *expected = qf_ferm_op_zero();
6bool actions[0] = {};
7uint32_t modes[0] = {};
8qf_ferm_op_add_term(expected, 0, actions, modes, &coeff);
9
10assert(qf_ferm_op_equal(result, expected));Parametri
- op – Un puntatore all'operatore.
- scalare – Un puntatore allo scalare.
Risultati
Un puntatore all'operatore risultante.
qf_ferm_op_compose
QfFermionOperator *qf_ferm_op_compose(const QfFermionOperator *left, const QfFermionOperator *right)
Combina due operatori tra loro.
Esempio
1QfFermionOperator *one = qf_ferm_op_one();
2QfFermionOperator *zero = qf_ferm_op_zero();
3
4QfFermionOperator *result = qf_ferm_op_compose(one, zero);
5
6assert(qf_ferm_op_equal(result, zero));Parametri
- sinistra – Un puntatore all'operatore di sinistra.
- right – Un puntatore all'operatore "a destra".
Risultati
Un puntatore all'operatore risultante.
qf_ferm_op_adjoint
QfFermionOperator *qf_ferm_op_adjoint(const QfFermionOperator *op)
Restituisce il coniugato ermitiano (o aggiunto) di un 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
Esempio
1QfFermionOperator *op = qf_ferm_op_zero();
2bool actions[0] = {};
3uint32_t modes[0] = {};
4QkComplex64 coeff = {0.0, 1.0};
5qf_ferm_op_add_term(op, 0, actions, modes, &coeff);
6
7QfFermionOperator *adjoint = qf_ferm_op_adjoint(op);
8
9QfFermionOperator *expected = qf_ferm_op_zero();
10QkComplex64 coeff_adj = {0.0, -1.0};
11qf_ferm_op_add_term(expected, 0, actions, modes, &coeff_adj);
12
13assert(qf_ferm_op_equal(adjoint, expected));Parametri
- op – Un puntatore all'operatore.
Risultati
Un puntatore all’operatore creato.
qf_ferm_op_ichop
void qf_ferm_op_ichop(QfFermionOperator *op, double atol)
Rimuove i termini il cui coefficiente è inferiore alla soglia specificata.
Questa funzione tronca i coefficienti in modo avido! Se l'operatore su cui si agisce dovesse contenere coefficienti distinti per termini duplicati, valuta invece qf_ferm_op_simplify() di chiamare!
Esempio
1QfFermionOperator *op = qf_ferm_op_zero();
2bool actions[0] = {};
3uint32_t modes[0] = {};
4QkComplex64 coeff = {1e-8};
5qf_ferm_op_add_term(op, 0, actions, modes, &coeff);
6
7qf_ferm_op_ichop(op, 1e-6);
8
9QfFermionOperator *expected = qf_ferm_op_zero();
10
11assert(qf_ferm_op_equal(op, expected));Parametri
- op – Un puntatore all'operatore.
- atol – La tolleranza assoluta per il troncamento dei coefficienti.
qf_ferm_op_simplify
QfFermionOperator *qf_ferm_op_simplify(const QfFermionOperator *op, double atol)
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 qf_ferm_op_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 qf_ferm_op_ichop() sia possibile troncare termini la cui somma porta a un coefficiente di grandezza totale che non dovrebbe essere troncato:
1uint64_t num_terms = 100000;
2uint64_t num_actions = 0;
3bool actions[0] = {};
4uint32_t modes[0] = {};
5QkComplex64 coeffs[100000];
6uint32_t boundaries[100001];
7for (int i = 0; i < 100000; i++) {
8 coeffs[i].re = 1e-5;
9 coeffs[i].im = 0.0;
10 boundaries[i] = 0;
11}
12boundaries[100000] = 0;
13QfFermionOperator *op = qf_ferm_op_new(num_terms, num_actions, coeffs,
14 actions, modes, boundaries);
15
16QfFermionOperator *canon = qf_ferm_op_simplify(op, 1e-4);
17
18QfFermionOperator *one = qf_ferm_op_one();
19bool canon_is_equal = qf_ferm_op_equiv(canon, one, 1e-6);
20
21qf_ferm_op_ichop(op, 1e-4);
22
23QfFermionOperator *zero = qf_ferm_op_zero();
24bool ichop_is_equal = qf_ferm_op_equiv(op, zero, 1e-6);Parametri
- op – Un puntatore all’operatore fermionico da semplificare.
- atol – La tolleranza assoluta per il troncamento dei coefficienti.
Risultati
Un operatore equivalente ma semplificato.
qf_ferm_op_normal_ordered
QfFermionOperator *qf_ferm_op_normal_ordered(const QfFermionOperator *op, const bool *sandwich)
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 lessicograficamente. Il fatto che l'ordine sia crescente o decrescente dipende dal valore dell'argomento sandwich :
NULL: 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 lessicografico 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)
Esempio
1QfFermionOperator *op = qf_ferm_op_zero();
2bool actions[4] = {false, true, false, true};
3uint32_t modes[4] = {1, 1, 0, 0};
4QkComplex64 coeff = {1.0, 0.0};
5qf_ferm_op_add_term(op, 4, actions, modes, &coeff);
6
7QfFermionOperator *normal_ordered = qf_ferm_op_normal_ordered(op, NULL);
8
9uint64_t num_terms = 4;
10uint64_t num_actions = 8;
11bool actions_exp[8] = {true, false, true, false, true, true, false, false};
12uint32_t modes_exp[8] = {0, 0, 1, 1, 1, 0, 1, 0};
13QkComplex64 coeffs_exp[4] = {
14 {1.0, 0.0}, {-1.0, 0.0}, {-1.0, 0.0}, {-1.0, 0.0}};
15uint32_t boundaries_exp[5] = {0, 0, 2, 4, 8};
16QfFermionOperator *expected =
17 qf_ferm_op_new(num_terms, num_actions, coeffs_exp, actions_exp,
18 modes_exp, boundaries_exp);
19
20assert(qf_ferm_op_equal(normal_ordered, expected));Quando si riorganizza un termine, occorre tenere conto delle relazioni di anticommutazione, , il che implica che il numero dei termini potrebbe variare.
Parametri
- op – Un puntatore all'operatore.
- sandwich – Un puntatore a un valore booleano. Questo puntatore può essere
NULL.
Risultati
Un puntatore all’operatore creato.
qf_ferm_op_is_hermitian
bool qf_ferm_op_is_hermitian(const QfFermionOperator *op, double atol)
Verifica se un operatore è ermitiano.
Esempio
1QfFermionOperator *op = qf_ferm_op_zero();
2bool actions1[2] = {true, false};
3uint32_t modes1[2] = {0, 1};
4QkComplex64 coeff1 = {0.0, 1.00001};
5qf_ferm_op_add_term(op, 2, actions1, modes1, &coeff1);
6bool actions2[2] = {true, false};
7uint32_t modes2[2] = {1, 0};
8QkComplex64 coeff2 = {0.0, -1};
9qf_ferm_op_add_term(op, 2, actions2, modes2, &coeff1);
10
11assert(qf_ferm_op_is_hermitian(op, 1e-4));
12assert(!qf_ferm_op_is_hermitian(op, 1e-8));Questo controllo viene implementato utilizzando qf_ferm_op_equiv() la differenza qf_ferm_op_normal_ordered() tra e op i suoi e qf_ferm_op_adjoint() qf_ferm_op_zero().
Parametri
- op – Un puntatore all’operatore fermionico da verificare.
- atol – La tolleranza assoluta entro la quale i coefficienti sono considerati uguali.
Risultati
Se l'operatore fornito è ermitiano.
qf_ferm_op_max_rank
uint32_t qf_ferm_op_max_rank(const QfFermionOperator *op)
Verifica il grado massimo di un operatore.
Esempio
1QfFermionOperator *op = qf_ferm_op_zero();
2bool actions[4] = {true, false, true, false};
3uint32_t modes[4] = {0, 1, 2, 3};
4QkComplex64 coeff = {1.0, 0.0};
5qf_ferm_op_add_term(op, 4, actions, modes, &coeff);
6
7assert(qf_ferm_op_max_rank(op), 4);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.
Parametri
- op – Un puntatore all’operatore fermionico da verificare.
Risultati
Il grado massimo dell'operatore.
qf_ferm_op_conserves_particle_number
bool qf_ferm_op_conserves_particle_number(const QfFermionOperator *op)
Verifica se un operatore conserva il numero di particelle.
Esempio
1QfFermionOperator *op = qf_ferm_op_zero();
2bool actions1[2] = {true, false};
3uint32_t modes1[2] = {0, 1};
4QkComplex64 coeff1 = {0.0, 1.00001};
5qf_ferm_op_add_term(op, 2, actions1, modes1, &coeff1);
6bool actions2[2] = {true, false};
7uint32_t modes2[2] = {1, 0};
8QkComplex64 coeff2 = {0.0, -1};
9qf_ferm_op_add_term(op, 2, actions2, modes2, &coeff2);
10
11assert(qf_ferm_op_is_hermitian(op, 1e-4));
12assert(!qf_ferm_op_is_hermitian(op, 1e-8));Parametri
- op – Un puntatore all’operatore fermionico da verificare.
Risultati
Se l'operatore fornito conserva il numero di particelle.
qf_ferm_op_equal
bool qf_ferm_op_equal(const QfFermionOperator *left, const QfFermionOperator *right)
Confronta due operatori per verificare se sono uguali.
Esempio
1QfFermionOperator *one = qf_ferm_op_one();
2QfFermionOperator *zero = qf_ferm_op_zero();
3
4assert(qf_ferm_op_equal(one, one));
5assert(!qf_ferm_op_equal(one, zero));Parametri
- sinistra – Un puntatore all'operatore di sinistra.
- right – Un puntatore all'operatore "a destra".
Risultati
Se i due operatori sono uguali.
qf_ferm_op_equiv
bool qf_ferm_op_equiv(const QfFermionOperator *left, const QfFermionOperator *right, double atol)
Confronta due operatori per verificare se sono equivalenti.
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.
Esempio
1QfFermionOperator *zero = qf_ferm_op_zero();
2
3QfFermionOperator *op = qf_ferm_op_zero();
4bool actions[0] = {};
5uint32_t modes[0] = {};
6QkComplex64 coeff = {1e-7, 0.0};
7qf_ferm_op_add_term(op, 0, actions, modes, &coeff);
8
9assert(qf_ferm_op_equiv(op, zero, 1e-6));
10assert(!qf_ferm_op_equiv(op, zero, 1e-8));Parametri
- sinistra – Un puntatore all'operatore di sinistra.
- right – Un puntatore all'operatore "a destra".
- atol – La tolleranza assoluta per l'equivalenza dei coefficienti.
Risultati
Se i due operatori sono equivalenti.
qf_ferm_op_len
size_t qf_ferm_op_len(const QfFermionOperator *op)
Restituisce la lunghezza (ovvero il numero di termini) dell'operatore specificato.
Esempio
1QfFermionOperator *op = qf_ferm_op_zero();
2bool actions[4] = {true, false, true, false};
3uint32_t modes[4] = {0, 1, 2, 3};
4QkComplex64 coeff = {1.0, 0.0};
5qf_ferm_op_add_term(op, 4, actions, modes, &coeff);
6
7assert(qf_ferm_op_len(op) == 1);Parametri
- op – Un puntatore all’operatore fermionico.
Risultati
La lunghezza (o il numero di termini) dell'operatore.
qf_ferm_op_relabel_modes
QfExitCode qf_ferm_op_relabel_modes(QfFermionOperator *op, uint64_t num_modes, const uint32_t *permutation)
Rinomina gli indici dell'operatore specificato.
Esempio
1QfFermionOperator *op = qf_ferm_op_zero();
2bool actions[4] = {true, false, true, false};
3uint32_t indices[4] = {0, 1, 2, 3};
4QkComplex64 coeff = {1.0, 0.0};
5qf_ferm_op_add_term(op, 4, actions, indices, &coeff);
6
7uint32_t permutation[4] = {3, 2, 1, 0};
8
9QfExitCode exit = qf_ferm_op_relabel_modes(op, 4, permutation);
10
11assert(exit == QfExitCode_Success);Parametri
- op – Un puntatore all’operatore fermionico.
- num_modes – Il numero di indici di modalità presenti nell'elenco delle permutazioni fornito.
- permutazione – L'elenco delle permutazioni degli indici.
Risultati
Un codice di uscita.
QfExitCode_Successin caso di successoQfExitCode_DuplicateIndexErrorse nella permutazione sono stati rilevati indici duplicatiQfExitCode_IndexErrorper eventuali altri errori relativi agli indici, come ad esempio indici non validi.