QkObs
typedef struct QkObs QkObsUne observable sur les bases de Pauli qui stocke ses données dans un format de qubits clairsemés.
Mathematics
Cette observable représente une somme sur les chaînes des opérateurs de Pauli et des projecteurs d'états propres de Pauli, chaque terme étant pondéré par un nombre complexe. En d'autres termes, l'observable complet est
pour les nombres complexes et les opérateurs à qubit unique agissant sur le qubit à partir d'un alphabet restreint . La somme sur est la somme des termes individuels, et le produit tensoriel produit les chaînes d'opérateurs. Les opérateurs de Pauli et les opérateurs de projection de l'état propre de Pauli constituent l'alphabet des opérateurs de qubits uniques autorisés dont les sont tirés. Il s'agit explicitement de
Opérateur | QkBitTerm | Valeur numérique |
|---|---|---|
| (identité) | Non stocké. | Non stocké. |
| (Pauli X) | QkBitTerm_X | 0b0010 (2) |
| (Pauli Y) | QkBitTerm_Y | 0b0011 (3) |
| (Pauli Z) | QkBitTerm_Z | 0b0001 (1) |
| (projecteur sur un état propre positif de X) | QkBitTerm_Plus | 0b1010 (10) |
| (projecteur sur l'état propre négatif de X) | QkBitTerm_Minus | 0b0110 (6) |
| (projecteur sur un état propre positif de Y) | QkBitTerm_Right | 0b1011 (11) |
| (projecteur sur l'état propre négatif de Y) | QkBitTerm_Left | 0b0111 (7) |
| (projecteur sur un état propre positif de Z) | QkBitTerm_Zero | 0b1001 (9) |
| (projecteur sur l'état propre négatif de Z) | QkBitTerm_One | 0b0101 (5) |
En raison de l'autorisation des Paulis et de leurs projecteurs, l'alphabet autorisé forme une base surcomplète de l'espace des opérateurs. Cela signifie qu'il n'existe pas de somme unique pour représenter un observable donné. Par conséquent, la comparaison nécessite des précautions supplémentaires et l'utilisation de qk_obs_canonicalize pour deux observables mathématiquement équivalents peut ne pas aboutir à la même représentation.
QkObs utilise sa base surcomplète particulière dans le but de rendre "l'efficacité de la mesure" équivalente à "l'efficacité de la représentation". Par exemple, l'observable peut être mesuré efficacement sur le matériel avec de simples mesures , mais ne peut être représenté en termes de Paulis que sous la forme , ce qui nécessite des termes stockés . QkObs ne nécessite qu'un seul terme pour le stocker. L'inconvénient est qu'il n'est pas pratique de prendre une matrice arbitraire et de trouver la meilleure représentation QkObs . En règle générale, il est préférable de construire directement un site QkObs , plutôt que d'essayer de le décomposer.
Représentation
La représentation interne d'un site QkObs ne stocke que les opérateurs des qubits non identitaires. Il est donc nettement plus efficace de représenter des observables tels que ; QkObs nécessite une quantité de mémoire linéaire par rapport au nombre total de qubits. Les termes sont stockés de manière comprimée, dans un esprit similaire au format compressé des rangées éparses des matrices éparses. Dans cette analogie, les termes de la somme sont les "lignes", et les termes du qubit sont les "colonnes", où une entrée absente représente l'identité plutôt qu'un zéro. Plus explicitement, la représentation est constituée de quatre tableaux contigus :
Attribut accessible par | Longueur | Description |
|---|---|---|
qk_obs_coeffs | Le multiplicateur scalaire complexe pour chaque terme. | |
qk_obs_bit_terms | Chacun des termes non-identiques du qubit unique pour tous les opérateurs, dans l'ordre. Elles correspondent à la non-identité dans la description de la somme, où les entrées sont stockées dans l'ordre croissant de en premier, et dans l'ordre croissant de à l'intérieur de chaque terme. | |
qk_obs_indices | Le qubit correspondant ( ) à chacun des termes binaires. QkObs exige que cette liste soit triée par terme, et les algorithmes peuvent compter sur le respect de cet invariant. | |
qk_obs_boundaries | Les indices qui divisent les termes binaires et les indices en termes complets. Pour le terme numéro , son coefficient complexe est stocké à l'index i, et ses opérateurs qubits uniques non identiques et leurs qubits correspondants se trouvent dans l'intervalle [boundaries[i], boundaries[i+1]) dans les termes et les index de bits, respectivement. Les limites ont toujours un 0 explicite comme premier élément. |
Le paramètre de longueur est le nombre de termes de la somme et peut être interrogé à l'aide de qk_obs_num_terms. Le paramètre est le nombre total de termes de qubits uniques non identiques et peut être interrogé à l'aide de qk_obs_len.
A titre d'exemple :
- dans le cas d'un opérateur zéro, les frontières sont de longueur 1 (un seul 0) et tous les autres vecteurs sont vides.
- dans le cas d'un opérateur identité entièrement simplifié, les limites sont
{0, 0}, les coefficients ont une seule entrée et les termes binaires et les indices sont vides. - pour l'opérateur , les limites sont
{0, 2, 4}, les coefficients sont{1.0, -1.0}, les termes binaires sont{QkBitTerm_Z, QkBitTerm_Z, QkBitTerm_Y, QkBitTerm_X}et les indices sont{0, 2, 1, 3}. L'opérateur peut agir sur plus de quatre qubits, en fonction du nombre de qubits (voirqk_obs_num_qubits). Notez que les termes et indices à un seul bit sont triés dans l'ordre des termes.
Ces cas ne sont pas particuliers, ils sont parfaitement conformes aux règles et ne devraient pas nécessiter de traitement particulier.
Ordre canonique
Pour toute observable mathématique donnée, il existe plusieurs façons de la représenter à l'aide de QkObs. Par exemple, le même ensemble de termes d'un seul bit et leurs indices correspondants peuvent apparaître plusieurs fois dans l'observable. Mathématiquement, cela équivaut à n'avoir qu'un seul terme dont tous les coefficients sont additionnés. De même, les termes de la somme dans un site QkObs peuvent être dans n'importe quel ordre tout en représentant le même observable, puisque l'addition est commutative (bien que l'addition en virgule flottante ne soit pas associative, QkObs ne donne aucune garantie quant à l'ordre de la somme).
Ces deux catégories de dégénérescence de représentation peuvent amener l'opérateur d'égalité, qk_obs_equal, à affirmer que deux observables ne sont pas égales, bien qu'elles représentent le même objet. Dans ce cas, il peut être pratique de définir une forme canonique, qui permet de comparer les observables de manière structurelle. Vous pouvez mettre un QkObs sous forme canonique en utilisant la fonction qk_obs_canonicalize . L'ordre précis des termes dans l'ordre canonique n'est pas spécifié et peut changer d'une version à l'autre de Qiskit. Dans la même version de Qiskit, cependant, vous pouvez comparer deux observables structurellement en comparant leurs formes simplifiées.
Si vous souhaitez tenir compte de la tolérance de la virgule flottante dans la comparaison, il est plus sûr d'utiliser une recette telle que :
bool equivalent(QkObs *left, QkObs *right, double tol) {
// compare a canonicalized version of left - right to the zero observable
QkObs *neg_right = qk_obs_multiply(right, &(QkComplex64){-1, 0});
QkObs *diff = qk_obs_add(left, neg_right);
QkObs *canonical = qk_obs_canonicalize(diff, tol);
QkObs *zero = qk_obs_zero(qk_obs_num_qubits(left));
bool equiv = qk_obs_equal(diff, zero);
// free all temporary variables
qk_obs_free(neg_right);
qk_obs_free(diff);
qk_obs_free(canonical);
qk_obs_free(zero);
return equiv;
}La forme canonique produite par qk_obs_canonicalize ne permet pas à elle seule de détecter universellement toutes les observables équivalentes en raison de l'alphabet de base trop complet.
Indexation
Les termes observables individuels de la somme dans QkObs sont accessibles via qk_obs_term et renvoient des objets de type QkObsTerm. Ces termes contiennent ensuite des champs contenant le coefficient du terme, ses termes binaires, ses indices et le nombre de qubits sur lesquels il est défini. Avec l'information sur le nombre de termes, vous pouvez itérer sur tous les termes observables comme suit
size_t num_terms = qk_obs_num_terms(obs); // obs is QkObs*
for (size_t i = 0; i < num_terms; i++) {
QkObsTerm term; // allocate term on stack
int exit = qk_obs_term(obs, i, &term); // get the term (exit > 0 upon index errors)
// do something with the term...
}L'alimentation d'un site QkObsTerm par le biais de qk_obs_term fera référence aux données du site original QkObs. La modification des termes binaires ou des indices modifie l'observable et peut le laisser dans un état incohérent.
Construction
QkObs peut être construit en initialisant un observable vide (avec qk_obs_zero) et en ajoutant itérativement des termes (avec qk_obs_add_term). Une observable peut également être construite à partir de données "brutes" (avec qk_obs_new) si toutes les données internes sont spécifiées. Il faut donc veiller à ce que les données soient cohérentes et aboutissent à un observable valide.
Fonction | Récapitulatif |
|---|---|
qk_obs_zero | Construire un observable vide sur un nombre donné de qubits. |
qk_obs_identity | Construire l'observable d'identité sur un nombre donné de qubits. |
qk_obs_new | Construire un observable à partir des tableaux de données brutes. |
Manipulation mathématique
QkObs prend en charge les opérations arithmétiques fondamentales entre les observables ou avec les scalaires. Solutions à envisager :
- ajouter deux observables à l'aide de
qk_obs_addetqk_obs_add_inplace - multiplier par un nombre complexe avec
qk_obs_multiplyetqk_obs_multiply_inplace - composer (multiplier) deux observables via
qk_obs_composeetqk_obs_compose_map - calculer
left + scalar * rightpour deux grandeurs observables et un scalaire complexe avecqk_obs_scaled_addetqk_obs_scaled_add_inplace
Fonctions
qk_obs_zero
QkObs *qk_obs_zero(uint32_t num_qubits)
Construire l'observable zéro (sans aucun terme).
Exemple
QkObs *zero = qk_obs_zero(100);Paramètres
- num_qubits - Le nombre de qubits sur lesquels l'observable est définie.
Retours
Un pointeur sur l'observable créé.
qk_obs_identity
QkObs *qk_obs_identity(uint32_t num_qubits)
Construire l'observable d'identité.
Exemple
QkObs *identity = qk_obs_identity(100);Paramètres
- num_qubits - Le nombre de qubits sur lesquels l'observable est définie.
Retours
Un pointeur sur l'observable créé.
qk_obs_new
QkObs *qk_obs_new(uint32_t num_qubits, uint64_t num_terms, uint64_t num_bits, QkComplex64 *coeffs, QkBitTerm *bit_terms, uint32_t *indices, size_t *boundaries)
Construire un nouvel observable à partir de données brutes.
Un argument de type pointeur peut être NULL nul si et seulement si sa longueur correspondante est nulle.
Exemple
// define the raw data for the 100-qubit observable |01><01|_{0, 1} - |+-><+-|_{98, 99}
uint32_t num_qubits = 100;
uint64_t num_terms = 2; // we have 2 terms: |01><01|, -1 * |+-><+-|
uint64_t num_bits = 4; // we have 4 non-identity bits: 0, 1, +, -
QkComplex64 coeffs[] = {{1, 0}, {-1, 0}};
QkBitTerm bits[4] = {QkBitTerm_Zero, QkBitTerm_One, QkBitTerm_Plus, QkBitTerm_Minus};
uint32_t indices[4] = {0, 1, 98, 99}; // <-- e.g. {1, 0, 99, 98} would be invalid
size_t boundaries[3] = {0, 2, 4};
QkObs *obs = qk_obs_new(
num_qubits, num_terms, num_bits, coeffs, bits, indices, boundaries
);
qk_obs_free(obs);Sécurité
Le comportement est indéfini si l'une des conditions suivantes n'est pas respectée :
coeffsest un pointeur sur un tableauQkComplex64de longueurnum_termsbit_termsest un pointeur sur un tableau d'élémentsQkBitTermvalides de longueurnum_bitsindicesest un pointeur sur un tableauuint32_tde longueurnum_bits, qui est trié par terme dans l'ordre strictement croissant, et dont chaque élément est plus petit quenum_qubitsboundariesest un pointeur sur un tableausize_tde longueurnum_terms + 1, qui est trié par ordre croissant, le premier élément est 0 et le dernier est plus petit quenum_terms
Paramètres
- num_qubits - Le nombre de qubits sur lesquels l'observable est définie.
- num_terms - Le nombre de termes.
- num_bits - Le nombre total de termes binaires non identitaires.
- coeffs - Un pointeur sur le premier élément du tableau des coefficients, de longueur
num_terms. - bit_terms - Un pointeur sur le premier élément du tableau des termes de bits, qui a une longueur de
num_bits. - indices - Un pointeur sur le premier élément du tableau d'indices, de longueur
num_bits. Notez que, pour chaque terme, ils doivent être triés de manière incrémentielle. - boundaries - Un pointeur sur le premier élément du tableau boundaries, de longueur
num_terms + 1.
Retours
Si les données d'entrée sont cohérentes et la construction réussie, le résultat est un pointeur sur l'observable. Sinon, un pointeur nul est renvoyé.
qk_obs_free
void qk_obs_free(QkObs *obs)
Libérer l'observable.
Exemple
QkObs *obs = qk_obs_zero(100);
qk_obs_free(obs);Sécurité
Le comportement est indéfini si obs n'est ni null ni un pointeur valide vers QkObs.
Paramètres
- obs - Un pointeur sur l'observable à libérer.
qk_obs_add_term
QkExitCode qk_obs_add_term(QkObs *obs, const QkObsTerm *cterm)
Ajouter un terme à l'observable.
Exemple
uint32_t num_qubits = 100;
QkObs *obs = qk_obs_zero(num_qubits);
QkComplex64 coeff = {1, 0};
QkBitTerm bit_terms[3] = {QkBitTerm_X, QkBitTerm_Y, QkBitTerm_Z};
uint32_t indices[3] = {0, 1, 2};
QkObsTerm term = {coeff, 3, bit_terms, indices, num_qubits};
QkExitCode exit_code = qk_obs_add_term(obs, &term);Sécurité
Le comportement est indéfini si l'un des éléments suivants n'est pas respecté :
obsest un pointeur valide et non nul vers un fichierQkObsctermest un pointeur valide et non nul vers un fichierQkObsTerm
Paramètres
- obs - Un pointeur sur l'observable.
- cterm - Un pointeur sur le terme à ajouter.
Retours
Un code de sortie. Il s'agit de >0 si le terme est incohérent ou si l'ajout du terme échoue.
qk_obs_term
QkExitCode qk_obs_term(QkObs *obs, uint64_t index, QkObsTerm *out)
Obtenir un terme observable par référence.
Un site QkObsTerm contient des pointeurs vers les indices et les termes binaires du terme, qui peuvent être utilisés pour modifier les données internes de l'observable. Cela peut laisser l'observable dans un état incohérent et doit être évité, sauf si l'on fait preuve d'une grande prudence. Il est généralement plus sûr de construire un nouvel observable plutôt que de tenter des modifications sur place.
Exemple
QkObs *obs = qk_obs_identity(100);
QkObsTerm term;
QkExitCode exit_code = qk_obs_term(obs, 0, &term);
// out-of-bounds indices return an error code
// QkExitCode error = qk_obs_term(obs, 12, &term);Sécurité
Le comportement est indéfini si l'un des éléments suivants n'est pas respecté
obsest un pointeur valide et non nul vers un fichierQkObsoutest un pointeur valide et non nul vers un fichierQkObsTerm
Paramètres
- obs - Un pointeur sur l'observable.
- index - L'index du terme à obtenir.
- out - Un pointeur sur
QkObsTermutilisé pour renvoyer le terme observable.
Retours
Un code de sortie.
qk_obs_num_terms
size_t qk_obs_num_terms(const QkObs *obs)
Obtenir le nombre de termes dans l'observable.
Exemple
QkObs *obs = qk_obs_identity(100);
size_t num_terms = qk_obs_num_terms(obs); // num_terms==1Sécurité
Le comportement est indéfini obs n'est pas un pointeur valide et non nul vers QkObs.
Paramètres
- obs - Un pointeur sur l'observable.
Retours
Le nombre de termes dans l'observable.
qk_obs_num_qubits
uint32_t qk_obs_num_qubits(const QkObs *obs)
Obtenir le nombre de qubits sur lesquels l'observable est définie.
Exemple
QkObs *obs = qk_obs_identity(100);
uint32_t num_qubits = qk_obs_num_qubits(obs); // num_qubits==100Sécurité
Le comportement est indéfini obs n'est pas un pointeur valide et non nul vers QkObs.
Paramètres
- obs - Un pointeur sur l'observable.
Retours
Le nombre de qubits sur lesquels l'observable est définie.
qk_obs_len
size_t qk_obs_len(const QkObs *obs)
Obtenir le nombre de termes/indices binaires dans l'observable.
Exemple
QkObs *obs = qk_obs_identity(100);
size_t len = qk_obs_len(obs); // len==0, as there are no non-trivial bit termsSécurité
Le comportement est indéfini obs n'est pas un pointeur valide et non nul vers QkObs.
Paramètres
- obs - Un pointeur sur l'observable.
Retours
Le nombre de termes dans l'observable.
qk_obs_coeffs
QkComplex64 *qk_obs_coeffs(QkObs *obs)
Obtenir un pointeur sur les coefficients.
Elle permet de lire et de modifier les coefficients de l'observable. Le pointeur résultant est valide en lecture pour qk_obs_num_terms(obs) éléments de QkComplex64.
Exemple
QkObs *obs = qk_obs_identity(100);
size_t num_terms = qk_obs_num_terms(obs);
QkComplex64 *coeffs = qk_obs_coeffs(obs);
for (size_t i = 0; i < num_terms; i++) {
printf("%f + i%f\n", coeffs[i].re, coeffs[i].im);
}Sécurité
Le comportement est indéfini obs n'est pas un pointeur valide et non nul vers QkObs.
Paramètres
- obs - Un pointeur sur l'observable.
Retours
Un pointeur sur les coefficients.
qk_obs_indices
uint32_t *qk_obs_indices(QkObs *obs)
Obtenir un pointeur sur les indices.
Elle peut être utilisée pour lire et modifier les indices de l'observable. Le pointeur résultant est valide en lecture pour qk_obs_len(obs) éléments de taille uint32_t.
Exemple
uint32_t num_qubits = 100;
QkObs *obs = qk_obs_zero(num_qubits);
QkComplex64 coeff = {1, 0};
QkBitTerm bit_terms[3] = {QkBitTerm_X, QkBitTerm_Y, QkBitTerm_Z};
uint32_t term_indices[3] = {0, 1, 2};
QkObsTerm term = {coeff, 3, bit_terms, term_indices, num_qubits};
qk_obs_add_term(obs, &term);
size_t len = qk_obs_len(obs);
uint32_t *indices = qk_obs_indices(obs);
for (size_t i = 0; i < len; i++) {
printf("index %i: %i\n", i, indices[i]);
}
qk_obs_free(obs);Sécurité
Le comportement est indéfini obs n'est pas un pointeur valide et non nul vers QkObs.
Paramètres
- obs - Un pointeur sur l'observable.
Retours
Un pointeur sur les indices.
qk_obs_boundaries
size_t *qk_obs_boundaries(QkObs *obs)
Obtenir un pointeur sur les limites du terme.
Elle peut être utilisée pour lire et modifier les limites des termes de l'observable. Le pointeur résultant est valide en lecture pour qk_obs_num_terms(obs) + 1 éléments de taille size_t.
Exemple
uint32_t num_qubits = 100;
QkObs *obs = qk_obs_zero(num_qubits);
QkComplex64 coeff = {1, 0};
QkBitTerm bit_terms[3] = {QkBitTerm_X, QkBitTerm_Y, QkBitTerm_Z};
uint32_t indices[3] = {0, 1, 2};
QkObsTerm term = {coeff, 3, bit_terms, indices, num_qubits};
qk_obs_add_term(obs, &term);
size_t num_terms = qk_obs_num_terms(obs);
size_t *boundaries = qk_obs_boundaries(obs);
for (size_t i = 0; i < num_terms + 1; i++) {
printf("boundary %i: %i\n", i, boundaries[i]);
}Sécurité
Le comportement est indéfini obs n'est pas un pointeur valide et non nul vers QkObs.
Paramètres
- obs - Un pointeur sur l'observable.
Retours
Un pointeur sur les limites.
qk_obs_bit_terms
QkBitTerm *qk_obs_bit_terms(QkObs *obs)
Obtenir un pointeur sur les termes de bits.
Elle peut être utilisée pour lire et modifier les termes binaires de l'observable. Le pointeur résultant est valide en lecture pour qk_obs_len(obs) éléments de taille uint8_t.
Exemple
uint32_t num_qubits = 100;
QkObs *obs = qk_obs_zero(num_qubits);
QkComplex64 coeff = {1, 0};
QkBitTerm bit_terms[3] = {QkBitTerm_X, QkBitTerm_Y, QkBitTerm_Z};
uint32_t indices[3] = {0, 1, 2};
QkObsTerm term = {coeff, 3, bit_terms, indices, num_qubits};
qk_obs_add_term(obs, &term);
size_t len = qk_obs_len(obs);
QkBitTerm *bits = qk_obs_bit_terms(obs);
for (size_t i = 0; i < len; i++) {
printf("bit term %i: %i\n", i, bits[i]);
}
qk_obs_free(obs);Sécurité
Le comportement est indéfini obs si le pointeur n'est pas valide QkObs ou n'est pas nul, ou si des valeurs non valides sont écrites dans le pointeur QkBitTerm résultant.
Paramètres
- obs - Un pointeur sur l'observable.
Retours
Un pointeur sur les termes du bit.
qk_obs_multiply
QkObs *qk_obs_multiply(const QkObs *obs, const QkComplex64 *coeff)
Multiplier l'observable par un coefficient complexe.
Exemple
QkObs *obs = qk_obs_identity(100);
QkComplex64 coeff = {2, 0};
QkObs *result = qk_obs_multiply(obs, &coeff);Sécurité
Le comportement est indéfini si l'un des éléments suivants n'est pas respecté
obsest un pointeur valide et non nul vers un fichierQkObscoeffest un pointeur valide et non nul vers un fichierQkComplex64
Paramètres
- obs - Un pointeur sur l'observable.
- coeff - Le coefficient avec lequel multiplier l'observable.
Retours
Un pointeur vers le résultat obs * coeff.
qk_obs_multiply_inplace
void qk_obs_multiply_inplace(QkObs *obs, const QkComplex64 *coeff)
Multiplier la grandeur observable sur place par un coefficient complexe.
Exemple
QkObs *obs = qk_obs_identity(100);
QkComplex64 coeff = {2, 0};
qk_obs_multiply_inplace(obs, &coeff);Sécurité
Le comportement est indéfini si l'un des éléments suivants n'est pas respecté
obsest un pointeur valide et non nul vers un fichierQkObscoeffest un pointeur valide et non nul vers un fichierQkComplex64
Paramètres
- obs - Un pointeur sur l'observable.
- coeff - Le coefficient avec lequel multiplier l'observable.
qk_obs_add
QkObs *qk_obs_add(const QkObs *left, const QkObs *right)
Ajouter deux observables.
Exemple
QkObs *left = qk_obs_identity(100);
QkObs *right = qk_obs_zero(100);
QkObs *result = qk_obs_add(left, right);Sécurité
Le comportement est indéfini si left ou right ne sont pas des pointeurs valides et non nuls vers QkObs.
Paramètres
- left - Un pointeur sur l'observable de gauche.
- right - Un pointeur sur l'observable de droite.
Retours
Un pointeur sur le résultat left + right.
qk_obs_add_inplace
void qk_obs_add_inplace(QkObs *left, const QkObs *right)
Ajouter un observable à un observable existant.
Exemple
QkObs *left = qk_obs_identity(100);
QkObs *right = qk_obs_zero(100);
qk_obs_add_inplace(left, right);Sécurité
Le comportement est indéfini si left ou right ne sont pas des pointeurs valides et non nuls vers QkObs.
Paramètres
- left - Un pointeur sur l'observable de gauche.
- right - Un pointeur sur l'observable de droite.
qk_obs_scaled_add
QkObs *qk_obs_scaled_add(const QkObs *left, const QkObs *right, const QkComplex64 *factor)
Ajoutez deux observables tout en modifiant les coefficients de celle de droite.
Exemple
QkObs *left = qk_obs_zero(100);
QkObs *right = qk_obs_identity(100);
QkComplex64 factor = {2, 0};
QkObs *result = qk_obs_scaled_add(left, right, &factor);Sécurité
Le comportement est indéfini si left ou right ne sont pas des pointeurs valides et non nuls vers QkObs.
Paramètres
- left - Un pointeur sur l'observable de gauche.
- right - Un pointeur sur l'observable de droite.
- facteur – Facteur par lequel il faut multiplier les coefficients.
Retours
Un pointeur géré vers le résultat left + factor * right.
qk_obs_scaled_add_inplace
void qk_obs_scaled_add_inplace(QkObs *left, const QkObs *right, const QkComplex64 *factor)
Ajouter un observable mis à l'échelle à un observable existant.
Exemple
QkObs *left = qk_obs_zero(100);
QkObs *right = qk_obs_identity(100);
QkComplex64 factor = {2, 0};
qk_obs_scaled_add_inplace(left, right, &factor);Sécurité
Le comportement est indéfini si left ou right ne sont pas des pointeurs valides et non nuls vers QkObs.
Paramètres
- left - Un pointeur sur l'observable de gauche.
- right - Un pointeur sur l'observable de droite.
- facteur – Facteur par lequel il faut multiplier les coefficients.
qk_obs_compose
QkObs *qk_obs_compose(const QkObs *first, const QkObs *second)
Composer (multiplier) deux observables.
Exemple
QkObs *first = qk_obs_zero(100);
QkObs *second = qk_obs_identity(100);
QkObs *result = qk_obs_compose(first, second);Sécurité
Le comportement est indéfini si first ou second ne sont pas des pointeurs valides et non nuls vers QkObs.
Paramètres
- premier - Un observable.
- second - L'autre observable.
Retours
first.compose(second) qui équivaut à l'observable result = second @ first, en termes de multiplication matricielle @.
qk_obs_compose_map
QkObs *qk_obs_compose_map(const QkObs *first, const QkObs *second, const uint32_t *qargs)
Composer (multiplier) deux observables en fonction d'un ordre de qubit personnalisé.
Cela permet notamment de composer deux observables de taille différente.
Exemple
QkObs *first = qk_obs_zero(100);
QkObs *second = qk_obs_identity(100);
QkObs *result = qk_obs_compose(first, second);Sécurité
Pour appeler cette fonction en toute sécurité
firstetseconddoivent être des pointeurs valides et non nuls versQkObs\ sqargsdoit pointer vers un tableau deuint32_t, lisible pour les éléments deqk_obs_num_qubits(second)(c'est-à-dire le nombre de qubits danssecond)
Paramètres
- premier - Un observable.
- second - L'autre observable. Le nombre de qubits doit correspondre à la longueur de
qargs. - qargs - Les arguments qubit ont spécifié les indices de
firstà associer à ceux desecond.
Retours
first.compose(second) qui équivaut à l'observable result = second @ first, en termes de multiplication matricielle @.
qk_obs_apply_layout
QkExitCode qk_obs_apply_layout(QkObs *obs, const uint32_t *layout, uint32_t num_qubits)
Appliquer une nouvelle disposition des qubits à l'observable.
La disposition est définie par un tableau layout de nouveaux indices, spécifiant que le qubit à l'indice actuel i est réétiqueté à l'indice layout[i]. Le nombre de qubits sur lesquels l'observable agit peut être étendu en définissant une adresse num_qubits plus grande que celle de l'observable actuel.
Exemple
Cette interface permet d'étiqueter et d'étendre les indices des qubits :
QkObs *obs = qk_obs_zero(4);
// add a term to the observable
QkBitTerm bit_terms[3] = {QkBitTerm_X, QkBitTerm_Y, QkBitTerm_Z};
uint32_t qubits[3] = {1, 2, 3};
complex double coeff = 1;
QkObsTerm term = {coeff, 3, bit_terms, qubits, 4};
qk_obs_add_term(obs, &term);
uint32_t layout[3] = {0, 10, 9}; // qubit mapping is: 0->0, 1->10, 2->9
uint32_t num_output_qubits = 11;
QkExitCode exit = qk_obs_apply_layout(obs, layout, num_output_qubits);Dans un flux de travail de compilateur, cette fonction peut être utilisée de manière pratique pour appliquer une QkTranspileLayout* obtenue à partir d'une passe de transpilateur, appelée transpile_layout dans l'exemple suivant :
// get the number of output qubits
uint32_t num_output_qubits = qk_transpile_layout_num_output_qubits(transpile_layout);
// get the layout including the ancillas (hence the ``false`` in the function call)
uint32_t *layout = malloc(sizeof(uint32_t) * num_output_qubits);
qk_transpile_layout_final_layout(transpile_layout, false, layout);
// apply the layout
QkExitCode exit = qk_obs_apply_layout(obs, layout, num_output_qubits);
// free the layout array
free(layout);Sécurité
Le comportement est indéfini si obs n'est pas un pointeur valide et non nul vers QkObs ou si layout n'est pas un pointeur valide et non nul vers une séquence de qk_obs_num_qubits(obs) éléments consécutifs de uint32_t.
Paramètres
- obs - Un pointeur sur l'observable, cet observable sera modifié en place en cas de succès. Vérifier le code de sortie pour s'assurer que la mise en page a été correctement appliquée.
- layout - Un pointeur sur le layout. Le pointeur doit pointer sur un tableau de
qk_obs_num_qubits(obs)éléments de typeuint32_t. Chaque élément doit avoir des valeurs dans[0, num_qubits). - num_qubits - Le nombre de qubits de sortie.
Retours
Un code de sortie.
QkExitCode_Successen cas de succèsQkExitCode_DuplicteIndexErrorsi des indices de qubits en double ont été trouvésQkExitCode_MismatchedQubitssinum_qubitsest plus petit que le nombre de qubits dans l'observableQkExitCode_IndexErrorpour toute autre erreur d'index, telle que des valeurs non valides danslayout.
qk_obs_canonicalize
QkObs *qk_obs_canonicalize(const QkObs *obs, double tol)
Calculer la représentation canonique de l'observable.
Exemple
QkObs *iden = qk_obs_identity(100);
QkObs *two = qk_obs_add(iden, iden);
double tol = 1e-6;
QkObs *canonical = qk_obs_canonicalize(two, tol);Sécurité
Le comportement est indéfini obs n'est pas un pointeur valide et non nul vers QkObs.
Paramètres
- obs - Un pointeur sur l'observable.
- tol - Tolérance en dessous de laquelle les coefficients sont considérés comme nuls.
Retours
La représentation canonique de l'observable.
qk_obs_copy
QkObs *qk_obs_copy(const QkObs *obs)
Copier l'observable.
Exemple
QkObs *original = qk_obs_identity(100);
QkObs *copied = qk_obs_copy(original);Sécurité
Le comportement est indéfini obs n'est pas un pointeur valide et non nul vers QkObs.
Paramètres
- obs - Un pointeur sur l'observable.
Retours
Un pointeur sur une copie de l'observable.
qk_obs_equal
bool qk_obs_equal(const QkObs *obs, const QkObs *other)
Comparer deux observables pour vérifier leur égalité.
Notez qu'il ne s'agit pas d'une comparaison d'égalité mathématique, mais d'égalité de données. Cela signifie que deux observables peuvent représenter la même chose mais ne pas être comparés comme étant égaux.
Exemple
QkObs *observable = qk_obs_identity(100);
QkObs *other = qk_obs_identity(100);
bool are_equal = qk_obs_equal(observable, other);Sécurité
Le comportement est indéfini si obs ou other ne sont pas des pointeurs valides et non nuls vers QkObs.
Paramètres
- obs - Un pointeur sur un observable.
- other - Un pointeur vers un autre observable.
Retours
true si les observables sont égaux, false dans le cas contraire.
qk_obs_str
char *qk_obs_str(const QkObs *obs)
Retourne une représentation sous forme de chaîne de caractères d'un QkObs.
Exemple
QkObs *obs = qk_obs_identity(100);
char *string = qk_obs_str(obs);
qk_str_free(string);
qk_obs_free(obs);Sécurité
Le comportement est indéfini obs n'est pas un pointeur valide et non nul vers QkObs.
La chaîne ne doit pas être libérée à l'aide de la fonction C free normale, vous devez utiliser qk_str_free pour libérer la mémoire consommée par la chaîne. Ne pas appeler qk_str_free entraînera une fuite de mémoire.
Ne pas modifier la longueur de la chaîne après son retour (en écrivant un octet nul quelque part dans la chaîne ou en supprimant le dernier octet), bien que les valeurs puissent être modifiées.
Paramètres
- obs - Un pointeur sur
QkObspour obtenir la chaîne de caractères.
Retours
Un pointeur sur un tableau de caractères à terminaison nulle de la représentation de la chaîne de caractères pour obs
qk_str_free
void qk_str_free(char *string)
Libère une représentation sous forme de chaîne de caractères.
Sécurité
Le comportement est indéfini si str n'est pas un pointeur renvoyé par qk_obs_str ou qk_obsterm_str.
Paramètres
- string - Un pointeur sur la représentation de la chaîne renvoyée par
qk_obs_strouqk_obsterm_str.
qk_obs_to_python
PyObject *qk_obs_to_python(QkObs *obs)
Transférez la propriété d'un QkObs objet à Python.
Il n'est pas sûr d'utiliser le QkObs pointeur après avoir appelé cette fonction. En particulier, vous ne devez pas essayer de le nettoyer ou de le dégager. L'appelant doit être le propriétaire de l'objet QkObs, et non pas détenir une référence empruntée (par exemple, un objet QkObs * récupéré à partir de qk_obs_borrow_from_python n'est pas considéré comme étant de sa propriété).
Sécurité
L'appelant doit être connecté à un interprète d' Python. Le comportement est indéfini si obs n'est pas un pointeur valide et non nul vers un objet initialisé et appartenant à l'utilisateur QkObs.
Paramètres
- obs – L'objet concerné.
Retours
Une référence de type « owned- Python » à l'objet.
qk_obs_borrow_from_python
QkObs *qk_obs_borrow_from_python(PyObject *ob)
Récupérer un QkObs pointeur à partir d'un objet Python.
Cette opération emprunte une référence à un objet de type Python et en extrait le QkObs pointeur, à condition que celui-ci soit du type approprié. Le pointeur renvoyé est emprunté au ob pointeur. Si le type PyObject n'est pas correct, la valeur de retour est NULL et l'état d'exception de l'interpréteur Python est activé.
Vous devez être connecté à un interpréteur Python pour pouvoir appeler cette fonction.
Vous pouvez également utiliser qk_obs_convert_from_python, qui est logiquement identique à cette fonction, mais qui peut être directement utilisé comme fonction de « conversion » pour la PyArg_Parse* famille de fonctions de conversion de l' Python.
Sécurité
L'appelant doit être connecté à un interprète d' Python. Le comportement est indéfini si ob n'est pas un pointeur valide et non nul vers un objet de type Python.
Paramètres
- ob – Un objet de type « Python » emprunté.
Retours
Un pointeur vers l'objet natif, ou NULL si l'objet de l' Python ation n'est pas du bon type.
qk_obs_convert_from_python
int qk_obs_convert_from_python(PyObject *object, void *address)
Récupérer un QkObs pointeur à partir d'un objet Python.
Cette fonction emprunte une référence à Python et en extrait le QkObs pointeur vers address, si celui-ci est du type approprié. Le pointeur renvoyé est emprunté au object pointeur. Si PyObject n'est pas du type correct, la valeur de retour est 1, l'état d'exception de l'interpréteur Python est activé et address reste inchangé.
Vous devez être connecté à un interpréteur Python pour pouvoir appeler cette fonction.
Vous pouvez également utiliser qk_obs_borrow_from_python, qui est logiquement identique à ceci, mais qui présente une syntaxe plus naturelle pour une utilisation directe.
Sécurité
L'appelant doit être connecté à un interprète d' Python. Le comportement est indéfini si object n'est pas un pointeur valide et non nul vers un objet Python, ou si address n'est pas un pointeur vers des données modifiables du type approprié.
Paramètres
- objet – Un objet emprunté de type « Python ».
- adresse – Emplacement où enregistrer les données de sortie.
Retours
1 en cas de réussite, 0 en cas d'échec.