Rappresentazioni degli operatori di mappa
I mappatori sono routine che trasformano gli operatori da una rappresentazione a un’altra, preservandone l’equivalenza matematica. Utilizzali per lavorare in modo flessibile con diverse algebre di operatori e per preparare gli operatori all'esecuzione dei circuiti quantistici.
Implementare mappatori personalizzati
Il modulo "mappers" semplifica l'implementazione di mappature personalizzate. I mappatori operano trasformando le azioni fondamentali (creazione, annichilimento, Majorana e così via) che compongono un operatore, per poi combinare tali azioni trasformate secondo le regole della rappresentazione di destinazione.
A titolo di esempio concreto, si consideri una trasformazione di Jordan-Wigner che mappa un MajoranaOperator su un operatore su qubit utilizzando map_majorana_action_generators():
>>> 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)>// 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.I passaggi fondamentali per implementare qualsiasi mapper personalizzato sono:
- Definizione della trasformazione delle azioni : specificare in che modo ciascuna azione (indicizzata in base alla modalità) viene mappata sulla rappresentazione di destinazione. Nell'esempio sopra riportato, le azioni di Majorana si corrispondono alle stringhe di Pauli secondo le regole di Jordan-Wigner.
- Utilizzare una delle funzioni di mappatura fornite : il
mappersmodulo mette a disposizione funzioni di utilità per gestire l'iterazione sui termini dell'operatore e le successive applicazioni della mappa di azioni personalizzata alle rappresentazioni dell'operatore fornite daloperatorsmodulo. Ad esempio,map_majorana_action_generators()funziona con gli operatori di Majorana. - Ottenere il risultato : la funzione di mappatura restituisce un operatore nella rappresentazione di destinazione, con la trasformazione applicata in modo coerente a tutti i termini.
Questo approccio semplifica la creazione di prototipi di mappature personalizzate senza richiedere una conoscenza approfondita delle strutture interne degli operatori. La trasformazione viene applicata automaticamente a ogni termine dell'operatore, preservando l'equivalenza matematica.
È anche possibile iterare manualmente i termini di un operatore, anziché utilizzare una delle funzioni iteratrici fornite. Per ulteriori dettagli, consultare la sezione dedicata all’iterazione dei termini nella guida agli operatori.
Implementazioni di librerie
Il modulo qiskit_fermions.mappers.library offre implementazioni efficienti e accuratamente testate delle mappature più comuni. Questi seguono lo stesso schema di base dei mapper personalizzati, ma sono ottimizzati per l’uso in produzione e sono disponibili sia nell’API Python che nell’API C.
L'esempio riportato di seguito applica un mapper della libreria allo stesso elemento della MajoranaOperator sezione dei mapper personalizzati, dimostrando che i risultati sono equivalenti:
>>> 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#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);La sequenza in due passaggi sopra riportata illustra la composizione di due mappatori di librerie. In pratica, si assegnerebbe invece un MajoranaOperator in un unico passaggio, con majorana_jordan_wigner() (qf_maj_op_jordan_wigner() nell'API C), e lo stesso vale per gli altri tipi di operatori – edge_vertex_jordan_wigner() e ( transfer_vertex_jordan_wigner()qf_edge_op_jordan_wigner() , qf_transfer_op_jordan_wigner()). Passare attraverso un ingrossa FermionOperator inoltre il risultato intermedio: ogni generatore di queste algebre si mappa su una singola stringa di Pauli, mentre ogni azione fermionica si mappa su una somma a due termini, quindi un termine costruito da diversi generatori si espande solo per poi essere nuovamente ridotto. Tale risparmio aumenta con la lunghezza dei termini; infatti, per i termini a generatore singolo di un hamiltoniano a salto, i due percorsi hanno un costo pressoché identico.
Nell'API " Python ", alcuni di questi mappatori di librerie sono accessibili anche tramite mappatori di comodità indipendenti dal tipo. fermion_operator() e majorana_operator() si trovano davanti a e majorana_to_fermion() fermion_to_majorana() (tra gli altri), delegando internamente all'implementazione della libreria appropriata in base al tipo di oggetto che viene loro fornito, anziché richiedere all'utente di scegliere personalmente la funzione corretta. Lo stesso vale per jordan_wigner(), che invia il codice a una delle quattro implementazioni dirette che corrisponde all’operatore che gli viene fornito. Vedi qiskit_fermions.protocols per capire come questo dispaccio viene implementato internamente.