Skip to main content
IBM Quantum Platform

QfFermionOperator

QfFermionOperator

struct QfFermionOperator

Un opérateur fermionique sans spin.

Remarque

Il s'agit d'une structure de données opaque pour l'API C, dont le fonctionnement interne est entièrement implémenté en Rust. La suite de cette page décrit la conception et les fonctions associées permettant d'utiliser cette structure.



Définition

Cet opérateur est défini par une combinaison linéaire de produits d'opérateurs de création et d'annihilation de fermions agissant sur des modes fermioniques sans spin. Autrement dit, les termes individuels satisfont aux relations d'anti-commutation suivantes : [1]

{ai†,aj†}={ai,aj}=0,  and  {ai,aj†}=δij ,\left\{a^\dagger_i, a^\dagger_j\right\} = \left\{a_i, a_j\right\} = 0,~~\text{and}~~ \left\{a_i, a^\dagger_j\right\} = \delta_{ij} \, ,

où ii et jj ne font pas la distinction entre les espèces de spin des modes fermioniques qu’ils indexent.

La définition de l'opérateur dans son ensemble est donc la suivante :

QfFermionOperator=∑ici⨂jAj^ ,\text{\texttt{QfFermionOperator}} = \sum_i c_i \bigotimes_j \hat{A_j} \, ,

où Aj^∈{aj,aj†}\hat{A_j} \in \{ a_j, a^\dagger_j \} et cic_i est le coefficient (complexe) constituant la combinaison linéaire des produits. L'indice jj peut prendre n'importe quelle valeur comprise entre 0 et le nombre de modes fermioniques sur lesquels agit l'opérateur, moins 1.



Implémentation

Cette structure stocke les termes et les coefficients dans plusieurs vecteurs creux, à l'instar du format « compressed sparse row » couramment utilisé pour les matrices creuses. Plus précisément, un opérateur contient 4 tableaux :

Chronique « 1 »
Chronique « 2 »
coeffsUn vecteur de coefficients complexes composé de deux nombres à virgule flottante de 64 bits.
actionsUn vecteur de valeurs booléennes contenant la nature des opérations de seconde quantification.
modesUn vecteur d'entiers de 32 bits contenant les indices des modes fermioniques sur lesquels l'opération a été effectuée.
boundariesUn vecteur d'entiers indiquant les limites dans actions et modes.

Les entrées dans actions désignent les opérateurs de création (annihilation) par True (False). Les modes fermioniques indexés par modes sont considérés comme dépourvus de spin.

Remarque

Vous pouvez accéder à des copies en lecture seule de ces tableaux internes via leurs fonctions respectives :

Cette structure de données permet de créer et de manipuler des opérateurs de manière très efficace. Cela implique toutefois qu'un opérateur puisse contenir à tout moment des termes en double. Ces problèmes doivent être résolus manuellement à l'aide de qf_ferm_op_simplify().

Construction

Il est possible de créer un nouvel opérateur directement en spécifiant les tableaux correspondants décrits ci-dessus. Sinon, un vide QfFermionOperator peut être initialisé avec qf_ferm_op_zero() et des termes peuvent être ajoutés de manière itérative via qf_ferm_op_add_term().

Chronique « 1 »
Chronique « 2 »
qf_ferm_op_new()Crée un nouvel opérateur à partir des tableaux fournis.
qf_ferm_op_zero()Construit l'opérateur d'identité additive.
qf_ferm_op_one()Construit l'opérateur d'identité multiplicative.
qf_ferm_op_add_term()Ajoute un terme à un fichier existant QfFermionOperator.
Remarque

On QfFermionOperator peut libérer A à l'aide de qf_ferm_op_free().

Arithmétique

Les fonctions suivantes permettent d'effectuer des opérations arithmétiques :

Chronique « 1 »
Chronique « 2 »
qf_ferm_op_add()Additionne deux opérandes.
qf_ferm_op_mul()Multiplie un opérateur par un scalaire.
qf_ferm_op_compose()Combine deux opérateurs entre eux.
qf_ferm_op_adjoint()Renvoie l'opérateur conjugué hermitien.

manipulation

Les fonctions suivantes fournissent la logique de manipulation des opérateurs :

Chronique « 1 »
Chronique « 2 »
qf_ferm_op_ichop()Supprime les termes dont les coefficients ont une faible valeur absolue.
qf_ferm_op_simplify()Renvoie un opérateur équivalent mais simplifié.
qf_ferm_op_normal_ordered()Renvoie un opérateur équivalent dont les termes sont classés selon l'ordre habituel.
qf_ferm_op_relabel_modes()Renomme les modes d'un opérateur.

Propriétés

Les fonctions suivantes permettent de vérifier certaines propriétés d'un opérateur.

Chronique « 1 »
Chronique « 2 »
qf_ferm_op_is_hermitian()Indique si un opérateur est hermitien.
qf_ferm_op_max_rank()Renvoie le rang maximal des termes de cet opérateur.
qf_ferm_op_conserves_particle_number()Indique si un opérateur préserve le nombre de particules.

[ 1 ]

https://en.wikipedia.org/wiki/Second _quantification#Opérateurs_de_création_et_d'annihilation_des_fermions


Membres

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)

Crée un nouvel opérateur.

Un argument de type pointeur peut être NULL si et seulement si sa longueur correspondante est égale à zéro.

Exemple

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);

Paramètres

  • num_terms – Le nombre de termes dans l'opérateur.
  • num_actions – Nombre total d'actions, toutes catégories confondues.
  • coeffs – Un pointeur vers un tableau de coefficients de termes. La longueur de ce tableau devrait être de num_terms.
  • actions – Un pointeur vers un tableau d'actions sur l'ensemble des termes. La longueur de ce tableau devrait être de num_actions.
  • modes – Un pointeur vers un tableau contenant les modes d'action pour tous les termes. La longueur de ce tableau devrait être de num_actions.
  • limites – Un pointeur vers un tableau contenant les limites entre les termes. La longueur de ce tableau devrait être de num_terms + 1.

qf_ferm_op_free

void qf_ferm_op_free(QfFermionOperator *op)

Libère un opérateur existant.

Exemple

1QfFermionOperator *op = qf_ferm_op_one();
2qf_ferm_op_free(op);

Paramètres

  • op – Un pointeur vers l'opérateur fermionique à libérer.

qf_ferm_op_get_coeffs

void qf_ferm_op_get_coeffs(const QfFermionOperator *op, QkComplex64 **coeffs_out, uint64_t *coeffs_len)

Permet d'accéder en lecture seule aux coefficients de l'opérateur.

Voir aussi

Vous trouverez ici une explication de la structure interne des données.

Exemple

 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);
Remarque

Cette fonction renvoie une copie des données internes.

Paramètres

  • op – Un pointeur vers l'opérateur fermionique dont on souhaite accéder aux coefficients.
  • coeffs_out – Un pointeur vers le tableau de valeurs complexes dans lequel les coefficients doivent être écrits.
  • coeffs_len – Un pointeur vers l'entier dans lequel écrire la longueur du tableau de sortie.

qf_ferm_op_get_actions

void qf_ferm_op_get_actions(const QfFermionOperator *op, bool **actions_out, uint64_t *actions_len)

Permet un accès en lecture seule aux actions de l'opérateur.

Voir aussi

Vous trouverez ici une explication de la structure interne des données.

Exemple

 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);
Remarque

Cette fonction renvoie une copie des données internes.

Paramètres

  • op – Un pointeur vers l'opérateur fermionique dont on souhaite accéder aux actions.
  • actions_out – Un pointeur vers le tableau de valeurs booléennes dans lequel les actions doivent être écrites.
  • actions_len – Un pointeur vers l'entier dans lequel écrire la longueur du tableau de sortie.

qf_ferm_op_get_modes

void qf_ferm_op_get_modes(const QfFermionOperator *op, uint32_t **modes_out, uint64_t *modes_len)

Fournit un accès en lecture seule aux indices de mode sur lesquels l'opérateur agit.

Voir aussi

Vous trouverez ici une explication de la structure interne des données.

Exemple

 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);
Remarque

Cette fonction renvoie une copie des données internes.

Paramètres

  • op – Un pointeur vers l'opérateur fermionique dont on souhaite accéder aux modes.
  • modes_out – Un pointeur vers le tableau de valeurs booléennes dans lequel écrire les modes.
  • modes_len – Un pointeur vers l'entier dans lequel doit être écrite la longueur du tableau de sortie.

qf_ferm_op_get_boundaries

void qf_ferm_op_get_boundaries(const QfFermionOperator *op, size_t **boundaries_out, uint64_t *boundaries_len)

Permet un accès en lecture seule aux index indiquant les limites entre les termes d'opérateur.

Voir aussi

Vous trouverez ici une explication de la structure interne des données.

Exemple

 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);
Remarque

Cette fonction renvoie une copie des données internes.

Paramètres

  • op – Un pointeur vers l'opérateur fermionique dont il faut accéder aux limites.
  • boundaries_out – Un pointeur vers le tableau de valeurs booléennes dans lequel les limites doivent être écrites.
  • boundaries_len – Un pointeur vers l'entier dans lequel doit être écrite la longueur du tableau de sortie.

qf_ferm_op_num_support

uint32_t qf_ferm_op_num_support(const QfFermionOperator *op)

Récupère la taille du support d'un opérateur.

Utilisez cette fonction pour dimensionner le tampon de sortie de qf_ferm_op_get_support(), qui ne fournit pas d'information sur sa propre longueur.

Exemple

1bool actions[3] = {true, false, true};
2uint32_t modes[3] = {2, 0, 2};
3QkComplex64 coeffs[2] = {{1.0, 0.0}, {1.0, 0.0}};
4uint32_t boundaries[3] = {0, 2, 3};
5QfFermionOperator *op = qf_ferm_op_new(2, 3, coeffs, actions, modes, boundaries);
6
7uint32_t num_support = qf_ferm_op_num_support(op);
8
9assert(num_support == 2);

Paramètres

  • op – Un pointeur vers l’opérateur fermionique dont on souhaite connaître la taille du support.

Retours

Le nombre d'indices de mode distincts sur lesquels agit l'opérateur.

qf_ferm_op_get_support

void qf_ferm_op_get_support(const QfFermionOperator *op, uint32_t *support_out)

Récupère le support d'un opérateur, c'est-à-dire les indices de mode sur lesquels agit l'opérateur.

Les indices sont classés par ordre croissant, et chaque indice n'apparaît qu'une seule fois, quel que soit le nombre de termes qui lui sont associés.

Exemple

 1bool actions[3] = {true, false, true};
 2uint32_t modes[3] = {2, 0, 2};
 3QkComplex64 coeffs[2] = {{1.0, 0.0}, {1.0, 0.0}};
 4uint32_t boundaries[3] = {0, 2, 3};
 5QfFermionOperator *op = qf_ferm_op_new(2, 3, coeffs, actions, modes, boundaries);
 6
 7uint32_t num_support = qf_ferm_op_num_support(op);
 8uint32_t *support_out = malloc(num_support * sizeof(uint32_t));
 9
10qf_ferm_op_get_support(op, support_out);
11
12assert(support_out[0] == 0);
13assert(support_out[1] == 2);
14
15free(support_out);
Remarque

Contrairement aux autres accesseurs, celui-ci ne renvoie pas de pointeur vers l'opérateur : le support est calculé à la demande plutôt que d'être pré-stocké; c'est donc l'appelant qui fournit le tampon de sortie. qf_ferm_op_num_support() Commencez par vérifier la longueur requise de la requête.

Paramètres

  • op – Un pointeur vers l'opérateur fermionique dont on souhaite obtenir le support.
  • support_out – Un pointeur vers le tableau d'entiers dans lequel écrire le support. Sa taille doit être d'au moins :c:func:qf_ferm_op_num_support éléments.

qf_ferm_op_zero

QfFermionOperator *qf_ferm_op_zero(void)

Construit l'opérateur d'identité additive.

L'ajout de l'opérateur ainsi créé à un autre opérateur n'a aucun effet.

Exemple

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));

Retours

Un pointeur vers l'opérateur créé.

qf_ferm_op_one

QfFermionOperator *qf_ferm_op_one(void)

Construit l'opérateur d'identité multiplicative.

La composition de l'opérateur ainsi construit avec un autre opérateur n'a aucun effet.

Exemple

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));

Retours

Un pointeur vers l'opérateur créé.

qf_ferm_op_has_groups

bool qf_ferm_op_has_groups(const QfFermionOperator *op)

Vérifie si cet opérateur prend en compte les indices de groupe.

Voir aussi

Explication des termes relatifs aux opérateurs de groupe : utilisez la structure des opérateurs.

Exemple

1QfFCIDump *fcidump = NULL;
2qf_fcidump_from_file("molecule.fcidump", &fcidump);
3QfFermionOperator *op = qf_ferm_op_from_fcidump(fcidump);
4
5bool has_groups = qf_ferm_op_has_groups(op);
6
7assert(!has_groups);

Paramètres

  • op – Un pointeur vers l'opérateur fermionique à vérifier.

Retours

Vérifier si l'opérateur fourni possède un attribut groups .

qf_ferm_op_num_groups

uint32_t qf_ferm_op_num_groups(const QfFermionOperator *op)

Récupère le nombre de groupes d'un opérateur.

Voir aussi

Explication des termes relatifs aux opérateurs de groupe : utilisez la structure des opérateurs.

Exemple

1QfFCIDump *fcidump = NULL;
2qf_fcidump_from_file("molecule.fcidump", &fcidump);
3QfFermionOperator *op = qf_ferm_op_from_fcidump(fcidump);
4
5uint32_t num_groups = qf_ferm_op_num_groups(op);
Remarque

Le nombre de groupes est évalué de manière paresseuse : il correspond à l'indice du plus grand groupe rencontré, majoré de 1.

Paramètres

  • op – Un pointeur vers l'opérateur fermionique dont il faut obtenir le nombre de groupes.

Retours

Le nombre d'indices de groupe issus de l'attribut groups de l'opérateur.

qf_ferm_op_get_groups

void qf_ferm_op_get_groups(const QfFermionOperator *op, uint32_t **groups_out, uint64_t *groups_len)

Récupère les indices de groupe pour tous les termes de l'opérateur.

Voir aussi

Explication des termes relatifs aux opérateurs de groupe : utilisez la structure des opérateurs.

Exemple

1QfFermionOperator *op = ...;
2uint32_t *groups_out;
3uint32_t groups_len;
4
5qf_ferm_op_get_groups(op, &groups_out, &groups_len);

Paramètres

  • op – Un pointeur vers l'opérateur fermionique dont on souhaite obtenir les indices de groupe.
  • groups_out – Un pointeur vers le tableau d'entiers dans lequel écrire les indices des groupes.
  • groups_len – Un pointeur vers l'entier dans lequel écrire la longueur du tableau de sortie.

qf_ferm_op_set_groups

QfExitCode qf_ferm_op_set_groups(QfFermionOperator *op, const uint32_t *groups_in, uint64_t groups_len)

Définit l'attribut groups de l'opérateur fourni.

La longueur est validée ici car aucun élément en aval ne la vérifie à nouveau : un nombre insuffisant d'index entraînerait la suppression silencieuse des termes finaux lorsque ceux-ci sont itérés avec leurs groupes, tandis qu'un nombre trop élevé ferait apparaître des groupes de rapport qf_ferm_op_num_groups() ne comportant aucun terme.

Voir aussi

Explication des termes relatifs aux opérateurs de groupe : utilisez la structure des opérateurs.

Exemple

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);

Paramètres

  • op – Un pointeur vers l'opérateur fermionique dont l'attribut groups doit être écrit.
  • groups_in – Un pointeur vers le tableau d'entiers groups dans lequel l'opérateur doit écrire.
  • groups_len – Le nombre d'éléments du tableau groups_in .

Retours

Un code de sortie.

  • QfExitCode_Success en cas de réussite
  • QfExitCode_ValueError si groups_len diffère du nombre de termes de l'opérateur

qf_ferm_op_del_groups

void qf_ferm_op_del_groups(QfFermionOperator *op)

Supprime l'attribut groups de l'opérateur indiqué.

Voir aussi

Explication des termes relatifs aux opérateurs de groupe : utilisez la structure des opérateurs.

Exemple

1QfFermionOperator *op = ...;
2
3qf_ferm_op_del_groups(op);

Paramètres

  • op – Un pointeur vers l'opérateur fermionique dont l'attribut groups doit être supprimé.

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)

Divise cet opérateur en une liste de nouveaux opérateurs en fonction de son attribut groups .

Un index en double dans group_indices est écrit une fois par occurrence dans group_ops_out. Demander uniquement un petit nombre de groupes parmi un ensemble beaucoup plus vaste revient nettement moins cher que de tous les demander, car les termes appartenant à un groupe qui n'est pas demandé sont ignorés plutôt que d'être ajoutés n'importe où.

Voir aussi

Explication des termes relatifs aux opérateurs de groupe : utilisez la structure des opérateurs.

Exemple

 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);

Paramètres

  • op – Un pointeur vers l'opérateur fermionique dont on groups souhaite extraire la composante.
  • group_indices – Un pointeur vers le tableau des indices de groupe pour lesquels il faut créer des opérateurs, dans l'ordre de sortie souhaité. C'est possible NULL; dans ce cas, chaque groupe est construit selon l'ordre des indices (ce qui revient à passer chaque indice de 0 à :c:func:qf_ferm_op_num_groups - 1).
  • num_indices – Le nombre d'indices dans le tableau group_indices . Ignoré si est group_indices NULL.
  • group_ops_out – Un pointeur vers le tableau de :c:struct:QfFermionOperator dans lequel doivent être écrits les opérateurs pour chaque groupe demandé. Doit être dimensionné à num_indices lorsque est group_indices différent de NULL, ou à :c:func:qf_ferm_op_num_groups lorsqu'il est égal à 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)

Ajoute un terme à un opérateur existant.

Un argument de type pointeur peut être NULL si et seulement si sa longueur correspondante est égale à zéro.

Attention

Cette fonction réinitialise l'attribut groups de l'opérateur à NULL.

Exemple

 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));

Paramètres

  • op – Un pointeur vers l'opérateur fermionique à modifier.
  • num_actions – La longueur du tableau « actions ».
  • actions – Un pointeur vers un tableau d'actions. La longueur de ce tableau devrait être de num_actions.
  • modes – Un pointeur vers un tableau de modes d'action. La longueur de ce tableau devrait être de num_actions.
  • coeff – Un pointeur vers le coefficient complexe.

qf_ferm_op_add

QfFermionOperator *qf_ferm_op_add(const QfFermionOperator *left, const QfFermionOperator *right)

Additionne deux opérandes.

Exemple

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));

Paramètres

  • gauche – Un pointeur vers l'opérateur gauche.
  • à droite – Un pointeur vers l'opérateur « à droite ».

Retours

Un pointeur vers l'opérateur obtenu.

qf_ferm_op_scaled_add

QfFermionOperator *qf_ferm_op_scaled_add(const QfFermionOperator *left, const QfFermionOperator *right, const QkComplex64 *factor)

Additionne deux opérateurs, en mettant à l'échelle les coefficients de celui de droite.

Cela permet d'intégrer la mise à l'échelle dans l'opération d'ajout, ce qui évite de créer une copie entièrement mise à l'échelle de simplement right pour l'ajouter à la fin. Le fait de passer un facteur de entraîne -1 donc une soustraction; c'est pourquoi aucune fonction de soustraction distincte n'est fournie.

Exemple

1QfFermionOperator *one = qf_ferm_op_one();
2QfFermionOperator *other = qf_ferm_op_one();
3
4// Subtracting via a factor of -1 leaves the two terms cancelling each other out.
5QkComplex64 factor = {-1.0, 0.0};
6QfFermionOperator *result = qf_ferm_op_scaled_add(one, other, &factor);
7
8QfFermionOperator *simplified = qf_ferm_op_simplify(result, 1e-10);
9assert(qf_ferm_op_len(simplified) == 0);
Remarque

En effet qf_ferm_op_add(), cela ajoute les termes de right sans les combiner avec ceux de left, de sorte que le résultat ne comporte aucun indice de groupe. Appelez-nous par la suite qf_ferm_op_simplify() pour convenir de conditions équitables.

Paramètres

  • gauche – Un pointeur vers l'opérateur gauche.
  • à droite – Un pointeur vers l'opérateur « à droite ».
  • facteur – Un pointeur vers le facteur permettant de mettre à l'échelle les coefficients de l'opérateur de droite.

Retours

Un pointeur vers l'opérateur obtenu, left + factor * right.

qf_ferm_op_add_inplace

void qf_ferm_op_add_inplace(QfFermionOperator *left, const QfFermionOperator *right)

Ajoute un opérateur à un autre, sur place.

L'équivalent « sur place » de qf_ferm_op_add(), qui évite de copier left dans une variable de résultat nouvellement allouée.

Attention

Cette fonction réinitialise l'attribut groups de l'opérateur à NULL.

Exemple

1QfFermionOperator *left = qf_ferm_op_one();
2QfFermionOperator *right = qf_ferm_op_one();
3
4qf_ferm_op_add_inplace(left, right);
5
6assert(qf_ferm_op_len(left) == 2);

Paramètres

  • à gauche – Un pointeur vers l'opérateur dans lequel effectuer l'ajout.
  • right – Un pointeur vers l'opérateur à ajouter.

qf_ferm_op_scaled_add_inplace

void qf_ferm_op_scaled_add_inplace(QfFermionOperator *left, const QfFermionOperator *right, const QkComplex64 *factor)

Ajoute un opérateur à un autre sur place, en redimensionnant les coefficients de celui de droite.

L'équivalent « in-place » de qf_ferm_op_scaled_add(), qui effectue le calcul left + factor * right sans allouer de résultat. Comme là-bas, un facteur de est soustrait -1 .

Attention

Cette fonction réinitialise l'attribut groups de l'opérateur à NULL.

Exemple

1QfFermionOperator *left = qf_ferm_op_one();
2QfFermionOperator *right = qf_ferm_op_one();
3
4// Subtract, leaving two terms that cancel each other out.
5QkComplex64 factor = {-1.0, 0.0};
6qf_ferm_op_scaled_add_inplace(left, right, &factor);
7
8QfFermionOperator *simplified = qf_ferm_op_simplify(left, 1e-10);
9assert(qf_ferm_op_len(simplified) == 0);

Paramètres

  • à gauche – Un pointeur vers l'opérateur dans lequel effectuer l'ajout.
  • right – Un pointeur vers l'opérateur à ajouter.
  • facteur – Un pointeur vers le facteur permettant de mettre à l'échelle les coefficients de l'opérateur de droite.

qf_ferm_op_mul_inplace

void qf_ferm_op_mul_inplace(QfFermionOperator *op, const QkComplex64 *scalar)

Multiplie un opérateur par un scalaire, sur place.

L'équivalent « sur place » de qf_ferm_op_mul(), ce qui évite de copier l'opérateur dans une variable de résultat nouvellement allouée.

Exemple

1QfFermionOperator *op = qf_ferm_op_one();
2QkComplex64 scalar = {2.0, 0.0};
3
4qf_ferm_op_mul_inplace(op, &scalar);
Remarque

Contrairement aux deux ajouts « sur place » mentionnés ci-dessus, cette méthode préserve l’attribut groups : la mise à l’échelle des coefficients ne modifie pas le nombre de termes, et donc l’invariance « un indice par terme ».

Paramètres

  • op – Un pointeur vers l'opérateur de mise à l'échelle.
  • scalaire – Un pointeur vers le scalaire.

qf_ferm_op_mul

QfFermionOperator *qf_ferm_op_mul(const QfFermionOperator *op, const QkComplex64 *scalar)

Multiplie un opérateur par un scalaire.

Exemple

 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));

Paramètres

  • op – Un pointeur vers l'opérateur.
  • scalaire – Un pointeur vers le scalaire.

Retours

Un pointeur vers l'opérateur obtenu.

qf_ferm_op_compose

QfFermionOperator *qf_ferm_op_compose(const QfFermionOperator *left, const QfFermionOperator *right)

Combine deux opérateurs entre eux.

Exemple

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));
Remarque

L'opération entre deux opérateurs ne prend en compte aucun groupe, même lorsque les deux opérandes en contiennent.

Paramètres

  • gauche – Un pointeur vers l'opérateur gauche.
  • à droite – Un pointeur vers l'opérateur « à droite ».

Retours

Un pointeur vers left.compose(right), qui équivaut à l'opérateur result = right @ left en termes de multiplication matricielle @. En d'autres termes, right est appliqué en premier. Pour obtenir left @ right, inversez l'ordre des arguments.

qf_ferm_op_adjoint

QfFermionOperator *qf_ferm_op_adjoint(const QfFermionOperator *op)

Renvoie le conjugué hermitien (ou adjoint) d'un opérateur.

Cela a les conséquences suivantes sur les termes et les coefficients :

  • les actions de chaque terme inversent leur ordre et alternent entre création et annihilation
  • les coefficients sont les conjugués complexes

Exemple

 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));

Paramètres

  • op – Un pointeur vers l'opérateur.

Retours

Un pointeur vers l'opérateur créé.

qf_ferm_op_ichop

void qf_ferm_op_ichop(QfFermionOperator *op, double atol)

Supprime les termes dont la valeur absolue du coefficient est inférieure au seuil indiqué.

Attention

Cette fonction tronque les coefficients de manière « gourmande »! Si l'opérateur sur lequel porte l'action est susceptible de contenir des coefficients distincts pour des termes identiques, pensez à utiliser qf_ferm_op_simplify() à la place!

Exemple

 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));

Paramètres

  • op – Un pointeur vers l'opérateur.
  • atol – Tolérance absolue pour la troncature des coefficients.

qf_ferm_op_simplify

QfFermionOperator *qf_ferm_op_simplify(const QfFermionOperator *op, double atol)

Renvoie un opérateur équivalent mais simplifié.

Le processus de simplification commence par additionner tous les coefficients appartenant à des termes identiques, puis ne conserve que ceux dont le coefficient total dépasse la tolérance spécifiée (exactement comme qf_ferm_op_ichop()).

Lorsqu'un opérateur a fait l'objet d'une manipulation arithmétique ou a été construit d'une manière qui ne garantit pas l'unicité des termes, il convient d'appeler cette méthode avant d'appliquer toute méthode filtrant les coefficients numériquement faibles, afin d'éviter toute perte d'information. Consultez l'exemple ci-dessous, qui montre comment peut qf_ferm_op_ichop() tronquer des termes dont la somme donne une valeur absolue de coefficient qui ne devrait pas être tronquée :

 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);

Paramètres

  • op – Un pointeur vers l'opérateur fermionique à simplifier.
  • atol – Tolérance absolue pour la troncature des coefficients.

Retours

Un opérateur équivalent mais simplifié.

qf_ferm_op_normal_ordered

QfFermionOperator *qf_ferm_op_normal_ordered(const QfFermionOperator *op, const bool *sandwich)

Renvoie un opérateur équivalent dont les termes sont classés selon l'ordre habituel.

L'ordre normal d'un terme d'opérateur est défini de telle sorte que toutes les actions de création apparaissent avant toutes les actions d'annihilation. Au sein de chaque groupe, les modes sur lesquels porte l'action sont classés par ordre lexicographique. Le fait que leur ordre soit croissant ou décroissant dépend de la valeur de l'argument sandwich :

  • NULL: les deux groupes sont classés par ordre lexicographique décroissant (par exemple +_1 +_0 -_1 -_0)
  • True: les indices les plus grands apparaissent vers le milieu, c'est-à-dire que les actions de création sont classées par ordre lexicographique croissant, tandis que celles d'annihilation sont classées par ordre décroissant (par exemple +_0 +_1 -_1 -_0)
  • False: les indices les plus petits apparaissent vers le milieu, c'est-à-dire que les actions de création sont classées par ordre lexicographique décroissant, tandis que celles d'annihilation sont classées par ordre croissant (par exemple +_1 +_0 -_0 -_1)

Exemple

 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));
Remarque

Lorsqu'on réorganise un terme, il faut tenir compte des relations d'anti-commutation, aiaj†=δij−aj†aia_i a^\dagger_j = \delta_{ij} - a^\dagger_j a^i, ce qui implique que le nombre de termes peut varier.

Paramètres

  • op – Un pointeur vers l'opérateur.
  • sandwich – Un pointeur vers une valeur booléenne. Ce pointeur peut être NULL.

Retours

Un pointeur vers l'opérateur créé.

qf_ferm_op_is_hermitian

bool qf_ferm_op_is_hermitian(const QfFermionOperator *op, double atol)

Vérifie si un opérateur est hermitien.

Exemple

 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));
Remarque

Cette vérification est effectuée à partir qf_ferm_op_equiv() de la différence qf_ferm_op_normal_ordered() entre op et ses et qf_ferm_op_adjoint() qf_ferm_op_zero().

Paramètres

  • op – Un pointeur vers l'opérateur fermionique à vérifier.
  • atol – Tolérance absolue jusqu'à laquelle les coefficients sont considérés comme égaux.

Retours

Si l'opérateur donné est hermitien.

qf_ferm_op_max_rank

uint32_t qf_ferm_op_max_rank(const QfFermionOperator *op)

Vérifie le rang maximal d'un opérateur.

Exemple

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);
Remarque

La longueur du terme le plus long peut dépendre de la forme de l’opérateur, ce qui signifie que (par exemple) la simplification de l’opérateur ou le rang normal peuvent conduire à un rang maximal différent.

Paramètres

  • op – Un pointeur vers l'opérateur fermionique à vérifier.

Retours

Le rang maximal de l'opérateur.

qf_ferm_op_conserves_particle_number

bool qf_ferm_op_conserves_particle_number(const QfFermionOperator *op)

Vérifie si un opérateur préserve le nombre de particules.

Il s'agit du cas particulier de qf_ferm_op_conserves_sector() qui traite tous les modes comme un seul bloc. Utilisez cette fonction pour imposer des contraintes supplémentaires de conservation au sein des blocs de mode, par exemple pour vérifier la conservation de la composante z du spin ainsi que celle du nombre de particules.

Exemple

 1// A hopping term conserves the particle number, ...
 2QfFermionOperator *op = qf_ferm_op_zero();
 3bool actions[2] = {true, false};
 4uint32_t modes[2] = {0, 2};
 5QkComplex64 coeff = {1.0, 0.0};
 6qf_ferm_op_add_term(op, 2, actions, modes, &coeff);
 7
 8assert(qf_ferm_op_conserves_particle_number(op));
 9
10// ... whereas a bare creation operator does not.
11QfFermionOperator *cre = qf_ferm_op_zero();
12bool cre_actions[1] = {true};
13uint32_t cre_modes[1] = {0};
14qf_ferm_op_add_term(cre, 1, cre_actions, cre_modes, &coeff);
15
16assert(!qf_ferm_op_conserves_particle_number(cre));

Paramètres

  • op – Un pointeur vers l'opérateur fermionique à vérifier.

Retours

L'opérateur fourni préserve-t-il le nombre de particules?

qf_ferm_op_conserves_sector

bool qf_ferm_op_conserves_sector(const QfFermionOperator *op, const uint32_t *block_sizes, uint64_t num_blocks)

Vérifie si un opérateur conserve le nombre de particules au sein de chaque bloc de mode.

La partition divise block_sizes la plage de modes en blocs consécutifs qui ne se chevauchent pas : le bloc b couvre les modes [start_b, start_b + block_sizes[b]) où start_b est la somme des tailles de tous les blocs précédents. Un terme préserve le secteur si et seulement si, dans chaque bloc, le nombre de ses opérateurs de création est égal au nombre de ses opérateurs d'annihilation. Un terme agissant sur un mode situé au-delà du dernier bloc ne préserve jamais le secteur, car il n'existe aucun bloc dont il pourrait équilibrer le compteur.

Pour une configuration spin-orbitale d'orbitales spatiales norb , [norb] vérifie le nombre de particules d'un système sans spin, tandis que [norb, norb] exige [norb, 2 * norb) que le bloc alpha [0, norb) et le bloc bêta soient conservés séparément, c'est-à-dire une conservation stricte à la fois du nombre de particules et de la composante z du spin.

Exemple

 1// This term hops an electron from the beta block into the alpha block.
 2QfFermionOperator *op = qf_ferm_op_zero();
 3bool actions[2] = {true, false};
 4uint32_t modes[2] = {0, 2};
 5QkComplex64 coeff = {1.0, 0.0};
 6qf_ferm_op_add_term(op, 2, actions, modes, &coeff);
 7
 8// The total particle number is conserved, ...
 9uint32_t one_block[1] = {4};
10assert(qf_ferm_op_conserves_sector(op, one_block, 1));
11assert(qf_ferm_op_conserves_sector(op, NULL, 0));
12
13// ... but the two spin sectors are not conserved individually.
14uint32_t spin_blocks[2] = {2, 2};
15assert(!qf_ferm_op_conserves_sector(op, spin_blocks, 2));
Remarque

Le passage ( NULL avec num_blocks réglé sur 0) traite tous les modes comme un bloc illimité, ce qui revient à qf_ferm_op_conserves_particle_number().

Paramètres

  • op – Un pointeur vers l'opérateur fermionique à vérifier.
  • block_sizes – Un pointeur vers le tableau des tailles de blocs qui divisent la plage de modes. Il serait peut-être possible NULL de traiter tous les modes comme un seul bloc.
  • num_blocks – Le nombre d'éléments du block_sizes tableau.

Retours

L'opérateur fourni préserve-t-il le nombre de particules au sein de chaque bloc?

qf_ferm_op_equal

bool qf_ferm_op_equal(const QfFermionOperator *left, const QfFermionOperator *right)

Comparer deux opérateurs pour vérifier s'ils sont égaux.

Exemple

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));

Paramètres

  • gauche – Un pointeur vers l'opérateur gauche.
  • à droite – Un pointeur vers l'opérateur « à droite ».

Retours

Si les deux opérateurs sont égaux.

qf_ferm_op_equiv

bool qf_ferm_op_equiv(const QfFermionOperator *left, const QfFermionOperator *right, double atol)

Comparer deux opérateurs pour vérifier s'ils sont équivalents.

Dans ce contexte, l'équivalence désigne une égalité approximative, dans les limites de la tolérance absolue spécifiée. Plus précisément, cette méthode renvoie True, lorsque toutes les valeurs absolues des coefficients de la différence other - self sont inférieures au seuil spécifié atol.

Exemple

 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));

Paramètres

  • gauche – Un pointeur vers l'opérateur gauche.
  • à droite – Un pointeur vers l'opérateur « à droite ».
  • atol – Tolérance absolue pour l'équivalence des coefficients.

Retours

Si les deux opérateurs sont équivalents.

qf_ferm_op_len

size_t qf_ferm_op_len(const QfFermionOperator *op)

Renvoie la longueur (ou le nombre de termes) de l'opérateur fourni.

Exemple

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);

Paramètres

  • op – Un pointeur vers l'opérateur fermionique.

Retours

La longueur (ou le nombre de termes) de l'opérateur.

qf_ferm_op_relabel_modes

QfExitCode qf_ferm_op_relabel_modes(QfFermionOperator *op, uint64_t num_modes, const uint32_t *permutation)

Renomme les indices de l’opérateur fourni.

Exemple

 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);

Paramètres

  • op – Un pointeur vers l'opérateur fermionique.
  • num_modes – Nombre d'indices de mode dans la liste de permutations fournie.
  • permutation – La liste des permutations d'index.

Retours

Un code de sortie.

  • QfExitCode_Success en cas de réussite
  • QfExitCode_DuplicateIndexError si des indices en double ont été détectés dans la permutation
  • QfExitCode_IndexError pour toute autre erreur liée aux index, telle que des index non valides.
Cette page a-t-elle été utile ?
Signaler un bogue, une coquille ou proposer du contenu sur GitHub.