Skip to main content
IBM Quantum Platform

Représentations des opérateurs de correspondance

Les « mappeurs » sont des routines qui transforment des opérateurs d'une représentation à une autre tout en préservant l'équivalence mathématique. Utilisez-les pour travailler de manière flexible avec différentes algèbres d'opérateurs et pour préparer les opérateurs en vue de l'exécution de circuits quantiques.


Implémenter des mappeurs personnalisés

Le module « mappers » permet de mettre en œuvre très facilement des mappages personnalisés. Les « mappeurs » fonctionnent en transformant les actions fondamentales (création, annihilation, Majorana, etc.) qui composent un opérateur, puis en combinant ces actions transformées selon les règles de la représentation cible.

À titre d'exemple concret, considérons une transformation de Jordan-Wigner qui associe un MajoranaOperator à un opérateur de qubit à l'aide de map_majorana_action_generators():

[x] PYTHON

>>> from qiskit.quantum_info import SparseObservable
>>> from qiskit_fermions.mappers import map_majorana_action_generators
>>> from qiskit_fermions.operators import MajoranaOperator
>>>
>>> # Create a Majorana operator
>>> maj_op = MajoranaOperator.from_dict({(0, 1): 1.0, (2,): 0.5})
>>>
>>> # Define how each Majorana action maps to Pauli strings
>>> num_qubits = 2
>>> def map_action(mode: int) -> SparseObservable:
...     idx = mode // 2
...     qubits = list(range(idx + 1))
...     pauli = "Y" if mode % 2 else "X"
...     return SparseObservable.from_sparse_list(
...         [("Z" * idx + pauli, qubits, 1.0)],
...         num_qubits=num_qubits,
...     )
>>>
>>> # Apply the mapping to transform the operator
>>> custom_observable = map_majorana_action_generators(
...     maj_op,
...     map_action,
...     identity=lambda: SparseObservable.identity(num_qubits),
...     compose=SparseObservable.compose,
... )
>>> print(custom_observable.simplify())
<SparseObservable with 2 terms on 2 qubits: (0+1j)(Z_0) + (0.5+0j)(X_1 Z_0)>

[] C

// The C API provides direct mapping functions for common transformations.
// Custom mapper prototyping as shown in Python is primarily a Python feature.
// For custom mappings in C, you will need to perform the iteration and
// conversion logic entirely by yourself.

Les étapes clés pour mettre en œuvre un mappeur personnalisé sont les suivantes :

  1. Définir la transformation d'action : préciser comment chaque action (indexée par mode) est mise en correspondance avec la représentation cible. Dans l'exemple ci-dessus, les actions de Majorana se transforment en cordes de Pauli selon les règles de Jordan-Wigner.
  2. Utilisez l'une des fonctions de mappage fournies : le mappers module propose des fonctions utilitaires permettant de parcourir les termes de l'opérateur et d'appliquer ensuite la carte d'action personnalisée aux représentations de l'opérateur fournies par le module operators . Par exemple, cela s'applique map_majorana_action_generators() aux opérateurs de Majorana.
  3. Obtenir le résultat : la fonction de mise en correspondance renvoie un opérateur dans la représentation cible, la transformation étant appliquée de manière cohérente à tous les termes.

Cette conception permet de créer facilement des prototypes de mappages personnalisés sans avoir besoin d'une connaissance approfondie des structures internes des opérateurs. La transformation est appliquée automatiquement à chaque terme de l'opérateur, tout en préservant l'équivalence mathématique.

Conseil

Vous pouvez également parcourir manuellement les termes d'un opérateur plutôt que d'utiliser l'une des fonctions d'itération fournies. Pour plus de détails, consultez la section consacrée à l'itération des termes dans le guide des opérateurs.


Implémentations de bibliothèques

Ce module qiskit_fermions.mappers.library propose des implémentations efficaces et rigoureusement testées des correspondances courantes. Ces derniers suivent le même modèle de base que les mappeurs personnalisés, mais sont optimisés pour une utilisation en production et sont disponibles à la fois dans l'API « Python » et dans l'API C.

L'exemple ci-dessous applique un mappeur de bibliothèque au même élément MajoranaOperator que celui de la section « Mappeurs personnalisés », ce qui montre que les résultats sont équivalents :

[x] PYTHON

>>> from qiskit_fermions.mappers.library import majorana_to_fermion, jordan_wigner
>>>
>>> # Convert MajoranaOperator to FermionOperator using library mapper
>>> ferm_op = majorana_to_fermion(maj_op)
>>>
>>> # Apply Jordan-Wigner mapper to get qubit operator
>>> sparse_observable = jordan_wigner(ferm_op, num_qubits=2)
>>> difference = sparse_observable - custom_observable
>>> print(difference.simplify() == SparseObservable.zero(num_qubits))
True

[] C

#include <qiskit_fermions.h>

// Create a MajoranaOperator with the same terms as maj_op above
uint64_t num_terms = 2;
uint64_t num_modes = 3;
uint32_t modes[3] = {0, 1, 2};
QkComplex64 coeffs[2] = {{1.0, 0.0}, {0.5, 0.0}};
uint32_t boundaries[3] = {0, 2, 3};
QfMajoranaOperator *maj_op = qf_maj_op_new(num_terms, num_modes, coeffs, modes, boundaries);

// Convert MajoranaOperator to FermionOperator using library mapper
QfFermionOperator *ferm_op = qf_majorana_to_fermion(maj_op);

// Apply Jordan-Wigner mapper to get qubit operator
QkObs *qubit_op;
QfExitCode exit = qf_ferm_op_jordan_wigner(ferm_op, 2, &qubit_op);
assert(exit == QfExitCode_Success);

// Clean up
qf_ferm_op_free(ferm_op);
qf_maj_op_free(maj_op);
qk_obs_free(qubit_op);
Remarque

Les deux étapes ci-dessus sont décrites afin d'illustrer la composition de deux mappeurs de bibliothèques. En pratique, on préférera plutôt effectuer la transformation en MajoranaOperator une seule étape, à l’aide de majorana_jordan_wigner() (qf_maj_op_jordan_wigner() dans l’API C), et de la même manière pour les autres types d’opérateurs – edge_vertex_jordan_wigner() et ( transfer_vertex_jordan_wigner()qf_edge_op_jordan_wigner() , qf_transfer_op_jordan_wigner()). Passer par un entraîne également FermionOperator un gonflement du résultat intermédiaire : chaque générateur de ces algèbres se transforme en une seule chaîne de Pauli, tandis que chaque action fermionique se transforme en une somme à deux termes; ainsi, un terme construit à partir de plusieurs générateurs s’étend pour être ensuite regroupé à nouveau. Cette économie augmente avec la longueur des termes; en effet, pour les termes à générateur unique d'un hamiltonien sautillant, les deux méthodes ont un coût à peu près équivalent.

Dans l'API « Python », certains de ces mappeurs de bibliothèques sont également accessibles via des mappeurs pratiques indépendants du type. fermion_operator() et majorana_operator() s'appuient sur et majorana_to_fermion() ( fermion_to_majorana() entre autres), en déléguant en interne à l'implémentation de bibliothèque appropriée en fonction du type d'objet qui leur est transmis, plutôt que de vous obliger à choisir vous-même la bonne fonction. Il en va de même pour jordan_wigner(), qui renvoie celle des quatre implémentations directes qui correspond à l'opérateur qui lui est fourni. Consultez cette page qiskit_fermions.protocols pour savoir comment cette répartition est mise en œuvre en interne.

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