Skip to main content
IBM Quantum Platform

QkObs

typedef struct QkObs QkObs

Une 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

QkObs=icinAi(n)\text{\texttt{QkObs}} = \sum_i c_i \bigotimes_n A^{(n)}_i

pour les nombres complexes cic_i et les opérateurs à qubit unique agissant sur le qubit nn à partir d'un alphabet restreint Ai(n)A^{(n)}_i. La somme sur ii 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 Ai(n)A^{(n)}_i sont tirés. Il s'agit explicitement de

Opérateur
QkBitTerm
Valeur numérique
II (identité)Non stocké.Non stocké.
XX (Pauli X)QkBitTerm_X0b0010 (2)
YY (Pauli Y)QkBitTerm_Y0b0011 (3)
ZZ (Pauli Z)QkBitTerm_Z0b0001 (1)
++\lvert+\rangle\langle+\rvert (projecteur sur un état propre positif de X)QkBitTerm_Plus0b1010 (10)
\lvert-\rangle\langle-\rvert (projecteur sur l'état propre négatif de X)QkBitTerm_Minus0b0110 (6)
rr\lvert r\rangle\langle r\rvert (projecteur sur un état propre positif de Y)QkBitTerm_Right0b1011 (11)
ll\lvert l\rangle\langle l\rvert (projecteur sur l'état propre négatif de Y)QkBitTerm_Left0b0111 (7)
00\lvert0\rangle\langle0\rvert (projecteur sur un état propre positif de Z)QkBitTerm_Zero0b1001 (9)
11\lvert1\rangle\langle1\rvert (projecteur sur l'état propre négatif de Z)QkBitTerm_One0b0101 (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 00n{\lvert0\rangle\langle0\rvert}^{\otimes n} peut être mesuré efficacement sur le matériel avec de simples mesures ZZ, mais ne peut être représenté en termes de Paulis que sous la forme (I+Z)n/2n{(I + Z)}^{\otimes n}/2^n, ce qui nécessite des termes stockés 2n2^n. 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 nqubitsZ(n)\sum_{n\in \text{qubits}} Z^{(n)}; 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_coeffsttLe multiplicateur scalaire complexe pour chaque terme.
qk_obs_bit_termsssChacun des termes non-identiques du qubit unique pour tous les opérateurs, dans l'ordre. Elles correspondent à la non-identité Ai(n)A^{(n)}_i dans la description de la somme, où les entrées sont stockées dans l'ordre croissant de ii en premier, et dans l'ordre croissant de nn à l'intérieur de chaque terme.
qk_obs_indicesssLe qubit correspondant ( nn ) à 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_boundariest+1t+1Les indices qui divisent les termes binaires et les indices en termes complets. Pour le terme numéro ii, 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 tt est le nombre de termes de la somme et peut être interrogé à l'aide de qk_obs_num_terms. Le paramètre ss 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 Z2Z0X3Y1Z_2 Z_0 - X_3 Y_1, 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 (voir qk_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.

Remarque

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

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...
}
Avertissement

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_zeroConstruire un observable vide sur un nombre donné de qubits.
qk_obs_identityConstruire l'observable d'identité sur un nombre donné de qubits.
qk_obs_newConstruire 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_add et qk_obs_add_inplace
  • multiplier par un nombre complexe avec qk_obs_multiply et qk_obs_multiply_inplace
  • composer (multiplier) deux observables via qk_obs_compose et qk_obs_compose_map
  • calculer left + scalar * right pour deux grandeurs observables et un scalaire complexe avec qk_obs_scaled_add et qk_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 :

  • coeffs est un pointeur sur un tableau QkComplex64 de longueur num_terms
  • bit_terms est un pointeur sur un tableau d'éléments QkBitTerm valides de longueur num_bits
  • indices est un pointeur sur un tableau uint32_t de longueur num_bits, qui est trié par terme dans l'ordre strictement croissant, et dont chaque élément est plus petit que num_qubits
  • boundaries est un pointeur sur un tableau size_t de longueur num_terms + 1, qui est trié par ordre croissant, le premier élément est 0 et le dernier est plus petit que num_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é :

  • obs est un pointeur valide et non nul vers un fichier QkObs
  • cterm est un pointeur valide et non nul vers un fichier QkObsTerm

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é

  • obs est un pointeur valide et non nul vers un fichier QkObs
  • out est un pointeur valide et non nul vers un fichier QkObsTerm

Paramètres

  • obs - Un pointeur sur l'observable.
  • index - L'index du terme à obtenir.
  • out - Un pointeur sur QkObsTerm utilisé 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==1

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

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==100

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

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 terms

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

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é

  • obs est un pointeur valide et non nul vers un fichier QkObs
  • coeff est un pointeur valide et non nul vers un fichier QkComplex64

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é

  • obs est un pointeur valide et non nul vers un fichier QkObs
  • coeff est un pointeur valide et non nul vers un fichier QkComplex64

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é

  • first et second doivent être des pointeurs valides et non nuls vers QkObs\ s
  • qargs doit pointer vers un tableau de uint32_t, lisible pour les éléments de qk_obs_num_qubits(second) (c'est-à-dire le nombre de qubits dans second)

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 de second.

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 type uint32_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_Success en cas de succès
  • QkExitCode_DuplicteIndexError si des indices de qubits en double ont été trouvés
  • QkExitCode_MismatchedQubits si num_qubits est plus petit que le nombre de qubits dans l'observable
  • QkExitCode_IndexError pour toute autre erreur d'index, telle que des valeurs non valides dans layout.

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 QkObs pour 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_str ou qk_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.

Cette page a-t-elle été utile ?
Signaler un bogue, une coquille ou proposer du contenu sur GitHub.