Skip to main content
IBM Quantum Platform

SparseObservable

class qiskit.quantum_info.SparseObservable(data, /, num_qubits=None)

GitHub

Basi: object

Un'osservabile su basi di Pauli che memorizza i suoi dati in un formato qubit-sparse.


Matematica

Questa osservabile rappresenta una somma di stringhe degli operatori di Pauli e dei proiettori di autovalori di Pauli, con ogni termine ponderato per un numero complesso. Cioè, l'osservabile completo è

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

per i numeri complessi cic_i e gli operatori single-qubit che agiscono sui qubit nn da un alfabeto ristretto Ai(n)A^{(n)}_i. La somma su ii è la somma dei singoli termini e il prodotto tensoriale produce le stringhe di operatori.

L'alfabeto degli operatori a singolo bit consentiti da cui è tratto Ai(n)A^{(n)}_i è costituito dagli operatori di Pauli e dagli operatori di proiezione degli autostati di Pauli. Esplicitamente, questi sono:

Etichetta
Operatore
Valore numerico
BitTerm attributo
"I"II (identità)Non conservato.Non conservato.
"X"XX (Pauli X)0b0010 (2)X
"Y"YY (Pauli Y)0b0011 (3)Y
"Z"ZZ (Pauli Z)0b0001 (1)Z
"+"++\lvert+\rangle\langle+\rvert (proiettore all'autostato positivo di X)0b1010 (10)PLUS
"-"\lvert-\rangle\langle-\rvert (proiettore all'autostato negativo di X)0b0110 (6)MINUS
"r"rr\lvert r\rangle\langle r\rvert (proiettore all'autostato positivo di Y)0b1011 (11)RIGHT
"l"ll\lvert l\rangle\langle l\rvert (proiettore all'autostato negativo di Y)0b0111 (7)LEFT
"0"00\lvert0\rangle\langle0\rvert (proiettore verso un autostato positivo di Z)0b1001 (9)ZERO
"1"11\lvert1\rangle\langle1\rvert (proiettore all'autostato negativo di Z)0b0101 (5)ONE

L'alfabeto consentito forma una base sovra-completa dello spazio degli operatori. Ciò significa che non esiste un'unica sommatoria per rappresentare una determinata osservabile. In confronto, SparsePauliOp utilizza una base precisa dello spazio degli operatori, per cui (dopo aver combinato i termini della stessa stringa di Pauli, rimosso gli zeri e ordinato i termini secondo un ordine canonico ) esiste una sola rappresentazione di qualsiasi operatore.

SparseObservable utilizza la sua particolare base sovracompleta con l'obiettivo di rendere l'"efficienza della misurazione" equivalente all'"efficienza della rappresentazione". Ad esempio, l'osservabile 00n{\lvert0\rangle\langle0\rvert}^{\otimes n} può essere misurata in modo efficiente sull'hardware con semplici misure ZZ, ma può essere rappresentata solo da SparsePauliOp come (I+Z)n/2n{(I + Z)}^{\otimes n}/2^n, che richiede termini memorizzati 2n2^n. SparseObservable richiede un solo termine per memorizzarlo.

L'aspetto negativo di questa soluzione è che non è pratico prendere una matrice arbitraria o SparsePauliOp e trovare la migliore SparseObservable rappresentazione. In genere si vuole costruire un elemento SparseObservable direttamente, piuttosto che cercare di decomporlo.


Rappresentazione

La rappresentazione interna di un SparseObservable memorizza solo gli operatori dei qubit non identici. Questo rende molto più efficiente la rappresentazione di osservabili come nqubitsZ(n)\sum_{n\in \text{qubits}} Z^{(n)}; SparseObservable richiede una quantità di memoria lineare rispetto al numero totale di qubit, mentre SparsePauliOp scala quadraticamente.

I termini vengono memorizzati compressi, in modo simile al formato compresso delle matrici rade. In questa analogia, i termini della somma sono le "righe" e i termini dei qubit sono le "colonne", dove una voce assente rappresenta l'identità piuttosto che uno zero. Più esplicitamente, la rappresentazione è costituita da quattro array contigui:

Attributo
Lunghezza
Descrizione
coeffsttIl moltiplicatore scalare complesso per ogni termine.
bit_termsssOgnuno dei termini non identici a singolo qubit per tutti gli operatori, nell'ordine. Questi corrispondono alla non identità Ai(n)A^{(n)}_i nella descrizione della somma, dove le voci sono memorizzate in ordine crescente ii prima, e in ordine crescente nn all'interno di ogni termine.
indicesssIl qubit corrispondente ( nn ) per ciascuno degli operatori in bit_terms. SparseObservable richiede che questo elenco sia ordinato per termini e gli algoritmi possono fare affidamento sul mantenimento di questo invariante.
boundariest+1t+1Gli indici che suddividono bit_terms e indices in termini completi. Per il termine numero ii, il suo coefficiente complesso è coeffs[i], e i suoi operatori single-qubit non identici e i loro qubit corrispondenti sono la fetta boundaries[i] : boundaries[i+1] in bit_terms e indices rispettivamente. boundaries ha sempre uno 0 esplicito come primo elemento.

Il parametro di lunghezza tt è il numero di termini della somma e il parametro ss è il numero totale di termini single-qubit non identici.

Come esempi illustrativi:

  • nel caso di un operatore zero, boundaries è di lunghezza 1 (un singolo 0) e tutti gli altri vettori sono vuoti.
  • nel caso di un operatore identità completamente semplificato, boundaries è [0, 0], coeffs ha una sola voce e bit_terms e indices sono vuoti.
  • per l'operatore Z2Z0X3Y1Z_2 Z_0 - X_3 Y_1, boundaries è [0, 2, 4], coeffs è [1.0, -1.0], bit_terms è [BitTerm.Z, BitTerm.Z, BitTerm.Y, BitTerm.X] e indices è [0, 2, 1, 3]. L'operatore potrebbe agire su più di quattro qubit, a seconda dei num_qubits parametro. I bit_terms sono valori interi, i cui numeri magici sono accessibili tramite la classe di attributi BitTerm dell'attributo. Si noti che i termini e gli indici a bit singolo sono ordinati in modo termale. Questo è un requisito del corso.

Questi casi non sono speciali, sono pienamente coerenti con le regole e non dovrebbero richiedere una gestione speciale.

L'elemento scalare dell'array bit_terms viene memorizzato come byte numerico. I valori numerici sono relativi alla rappresentazione di Pauli simplectica che SparsePauliOp utilizza e sono accessibili con un accesso con nome tramite un'enumerazione:

BitTerm

class BitTerm

GitHub

Un IntEnum che fornisce un accesso con nome ai valori numerici utilizzati per rappresentare ciascuno dei termini dell'alfabeto single-qubit enumerati in Alfabeto dei termini single-qubit utilizzati in SparseObservable.

Questa classe è collegata a SparseObservable. Accedere come SparseObservable.BitTerm. Se la digitazione è eccessiva e si ha a che fare solo con gli oggetti :class:¬SparseObservable` e il nome BitTerm non è ambiguo, si potrebbe abbreviare come:

>>> ops = SparseObservable.BitTerm
>>> assert ops.X is SparseObservable.BitTerm.X

È possibile accedere a tutti i valori dell'enumerazione sia con il loro nome completo in tutte le lettere maiuscole, sia con la loro etichetta di una sola lettera. Le etichette di una sola lettera non sono generalmente identificatori validi per Python, quindi è necessario utilizzare la notazione di indicizzazione per accedervi:

>>> assert SparseObservable.BitTerm.ZERO is SparseObservable.BitTerm["0"]

La struttura numerica di questi è che sono tutti valori a quattro bit di cui i due bit più bassi sono la rappresentazione simplettica (senza fase) dell'operatore di Pauli relativo all'oggetto, dove il bit più basso denota un contributo di ZZ e il secondo più basso un contributo di XX, mentre i due bit superiori sono 00 per un operatore di Pauli, 01 per il proiettore di autovalori negativi e 10 per il proiettore di autovalori positivi.

Valori

X

Valore predefinito: 2

L'operatore di Pauli XX. Utilizza l'etichetta a lettera singola "X".

Plus

Valore predefinito: 10

Il proiettore all'autostato positivo dell'operatore XX : ++\lvert+\rangle\langle+\rvert. Utilizza l'etichetta a lettera singola "+".

meno

Valore predefinito: 6

Il proiettore all'autostato negativo dell'operatore XX : \lvert-\rangle\langle-\rvert. Utilizza l'etichetta a lettera singola "-".

Y

Valore predefinito: 3

L'operatore di Pauli YY. Utilizza l'etichetta a lettera singola "Y".

DESTRO

Valore predefinito: 11

Il proiettore all'autostato positivo dell'operatore YY : rr\lvert r\rangle\langle r\rvert. Utilizza l'etichetta a lettera singola "r".

SINISTRA

Valore predefinito: 7

Il proiettore all'autostato negativo dell'operatore YY : ll\lvert l\rangle\langle l\rvert. Utilizza l'etichetta a lettera singola "l".

Z

Valore predefinito: 1

L'operatore di Pauli ZZ. Utilizza l'etichetta a lettera singola "Z".

ZERO

Valore predefinito: 9

Il proiettore all'autostato positivo dell'operatore ZZ : 00\lvert0\rangle\langle0\rvert. Utilizza l'etichetta a lettera singola "0".

ONE

Valore predefinito: 5

Il proiettore all'autostato negativo dell'operatore ZZ : 11\lvert1\rangle\langle1\rvert. Utilizza l'etichetta a lettera singola "1".

Attributi

label

L'etichetta a stringa di un solo carattere usata per rappresentare questo termine nell'alfabeto SparseObservable alfabeto.

Ogni attributo di tipo array si comporta come una sequenza Python. È possibile indicizzarli e tagliarli con una semantica list-con la semantica standard. Affettare un attributo restituisce un Numpy ndarray contenente una copia dei dati rilevanti con il dtype naturale del campo; questo permette di fare facilmente matematica sui risultati, come operazioni bitwise su bit_terms. È possibile assegnare agli indici o alle fette di ciascun attributo, ma è necessario rispettare le regole di coerenza dei dati. Ad esempio:

>>> obs = SparseObservable.from_list([("XZY", 1.5j), ("+1r", -0.5)])
>>> assert isinstance(obs.coeffs[:], np.ndarray)
>>> # Reduce all single-qubit terms to the relevant Pauli operator, if they are a projector.
>>> obs.bit_terms[:] = obs.bit_terms[:] & 0b00_11
>>> assert obs == SparseObservable.from_list([("XZY", 1.5j), ("XZY", -0.5)])
Nota

La riduzione di cui sopra alle basi di Pauli può essere ottenuta anche con pauli_bases().

Ordinamento canonico

Per ogni osservabile matematico, esistono diversi modi di rappresentarlo con SparseObservable. Ad esempio, lo stesso insieme di termini a bit singolo e i loro indici corrispondenti possono comparire più volte nell'osservabile. Dal punto di vista matematico, ciò equivale ad avere un solo termine con tutti i coefficienti sommati. Analogamente, i termini della somma in a SparseObservable possono essere in qualsiasi ordine pur rappresentando la stessa osservabile, poiché l'addizione è commutativa (anche se l'addizione in virgola mobile non è associativa), SparseObservable non garantisce l'ordine della somma).

Queste due categorie di degenerazione della rappresentazione possono indurre == l'operatore a ritenere che due osservabili non siano uguali, nonostante rappresentino lo stesso oggetto. In questi casi, può essere utile definire una forma canonica che consenta di confrontare strutturalmente le grandezze osservabili.

È possibile inserire un elemento SparseObservable in forma canonica utilizzando il metodo simplify() metodo. L'ordine preciso dei termini nell'ordinamento canonico non è specificato e può cambiare da una versione all'altra di Qiskit. All'interno della stessa versione di Qiskit, tuttavia, è possibile confrontare due osservabili dal punto di vista strutturale, confrontando le loro forme semplificate.

Nota

Se si desidera tenere conto della tolleranza in virgola mobile nel confronto, è più sicuro utilizzare una ricetta come:

def equivalent(left, right, tol):
    return (left - right).simplify(tol) == SparseObservable.zero(left.num_qubits)
Nota

La forma canonica prodotta da simplify() da sola non è in grado di rilevare universalmente tutte le osservabili equivalenti a causa dell'alfabeto di basi troppo completo. Per ottenere un'espressione univoca, si può innanzitutto rappresentare l'osservabile usando solo i termini di Pauli chiamando as_paulis(), seguito da simplify(). Si noti che l'espansione del proiettore (ad es. + in I e X) non è computazionalmente fattibile in scala.

Indicizzazione

SparseObservable si comporta come una sequenza Python (la forma standard, non quella espansa collections.abc.Sequence). L'osservabile può essere indicizzato da numeri interi e iterato per ottenere i singoli termini.

Ogni termine appare come un'istanza di una classe autonoma. I singoli termini sono copiati dall'osservabile di base; le mutazioni ad essi apportate non influiscono sull'osservabile.

Termine

class Term(num_qubits, coeff, bit_terms, indices)

GitHub

Basi: object

Un singolo termine di un'opera completa SparseObservable.

In genere vengono creati indicizzando o iterando in un file SparseObservable.

bit_labels

bit_labels()

Restituisce le etichette dei bit del termine come stringa.

Le etichette dei bit corrisponderanno all'ordine di SparseTerm.indices, in modo che l'i-esimo carattere della stringa sia applicato all'indice del qubit in term.indices[i].

Risultati

I termini di bit non identici come stringa concatenata.

bit_terms

Visualizzazione in sola lettura dei singoli termini a singolo qubit.

Gli unici valori validi nell'array sono quelli con un corrispondente valore BitTerm.

coeff

Il coefficiente del termine.

copy

copy()

Ottenere una copia di questo termine.

indices

Visualizzazione in sola lettura degli indici di ogni termine non identitario a singolo qubit.

Gli indici saranno sempre in ordine sparso.

num_qubits

Il numero di qubit su cui è definito il termine.

pauli_base

pauli_base()

Ottenere un Pauli che rappresenta la base di misura necessaria per questo termine.

Ad esempio, il proiettore 0l+ restituirà un Pauli ZYX. Il risultato Pauli è denso, nel senso che vengono memorizzate identità esplicite. Un'identità nell'uscita di Pauli non richiede una misura concreta.

Restituisce: Pauli: l'operatore di Pauli che rappresenta il necessario

base di misurazione.

Vedi anche

SparseObservable.pauli_bases()

Un metodo simile per un'intera osservabile in una sola volta.

to_observable

to_observable()

Convertire questo termine in un termine completo SparseObservable.


Costruzioni

SparseObservable definisce diversi costruttori. Il costruttore predefinito tenterà di delegare a uno dei costruttori più specifici, in base al tipo di input. Si possono sempre usare i costruttori specifici per avere un maggiore controllo sulla costruzione.

Metodo
Riepilogo
from_label()Convertire un'etichetta stringa densa in un termine singolo SparseObservable.
from_list()Somma un elenco di tuple di etichette di stringhe dense e i coefficienti associati in un osservabile.
from_sparse_list()Somma un elenco di tuple di etichette di stringhe sparse, i qubit a cui si applicano e i loro coefficienti in un osservabile.
from_pauli()Trasformare un singolo Pauli in un termine singolo SparseObservable.
from_sparse_pauli_op()Sollevare un SparsePauliOp in un SparseObservable.
from_terms()Somma esplicita di singole Term istanze.
from_raw_parts()Costruire l'osservabile dagli array di dati grezzi.

__new__

__new__(data, /, num_qubits=None)

Il costruttore predefinito di SparseObservable.

Delega a uno dei metodi espliciti del costruttore di conversione, in base al tipo dell'argomento data . Se viene fornito num_qubits e il costruttore implicito nel tipo di data non accetta un numero, il numero intero fornito deve corrispondere all'input.

Parametri

  • data - Il tipo di dati dell'ingresso. Questo può essere un altro SparseObservable, nel qual caso l'input viene copiato, un Pauli o SparsePauliOp, nel qual caso from_pauli() o from_sparse_pauli_op() vengono richiamati a seconda dei casi, oppure può essere un elenco in un formato valido per i due metodi from_list() o from_sparse_list().
  • num_qubits (int|None) – Numero opzionale di qubit per l'operatore. Per la maggior parte degli input di dati, questo può essere dedotto e non è necessario passarlo. È necessario solo per gli elenchi vuoti o per il formato sparse-list. Se viene dato inutilmente, deve corrispondere ai dati immessi.

Oltre ai costruttori basati sulla conversione, esistono anche metodi di aiuto che costruiscono forme speciali di osservabili.

Metodo
Riepilogo
zero()L'operatore zero su un dato numero di qubit.
identity()L'operatore di identità su un dato numero di qubit.

Conversioni

Un file esistente SparseObservable può essere convertito in altri quantum_info formati o in formati generici. SparseObservableSi tenga presente che altri oggetti potrebbero non essere in grado di rappresentare la stessa grandezza osservabile con la stessa efficienza, e potrebbero richiedere una quantità di memoria esponenzialmente maggiore.

Metodo
Riepilogo
as_paulis()Creare un nuovo SparseObservableche si espande solo in termini di operatori di Pauli.
to_sparse_list()Esprimere l'osservabile in un formato di lista rada con elementi (bit_terms, indices, coeff).

Inoltre, SparsePauliOp.from_sparse_observable() è disponibile per la conversione da questa classe a SparsePauliOp. Si noti che questo metodo soffre degli stessi problemi di utilizzo esponenziale della memoria di as_paulis().


Manipolazione matematica

SparseObservable supporta l'insieme standard di operatori matematici Python, proprio come gli altri quantum_info operatori.

In aritmetica di base, è possibile:

  • aggiungere due osservabili usando +
  • sottrarre due osservabili utilizzando -
  • moltiplicare o dividere per un int, float o complex utilizzando * e /
  • negare tutti i coefficienti di un'osservabile con unary -

Ciascuno degli operatori aritmetici binari di base ha un metodo in-place specializzato corrispondente, che muta il lato sinistro in-place. L'uso di questi operatori è in genere più efficiente degli operatori infix, soprattutto per costruire un osservabile in un ciclo.

Il prodotto tensoriale è calcolato con tensor() (per l'ordinamento standard di giustapposizione delle etichette di Pauli) oppure expand() (per l'ordinamento inverso). L'operatore ^ è sovraccaricato per essere equivalente a tensor().

Nota

Quando si utilizzano gli operatori binari ^ (tensor()) e & (compose()), si tenga presente che le regole di precedenza degli operatori di Python possono far sì che l'ordine di valutazione sia diverso da quello previsto. In particolare, l'operatore + si lega più strettamente di ^ o &, così come * si lega più strettamente di +.

Quando si utilizzano gli operatori nelle espressioni miste, è preferibile utilizzare le parentesi per raggruppare gli operandi dei prodotti tensoriali.

A SparseObservable ha un valore ben definito adjoint(). Le nozioni di coniugazione complessa scalare (conjugate()) e trasposizione a valori reali (transpose()) sono definite in modo analogo alla rappresentazione matriciale di altri operatori di Pauli in Qiskit.

Note sull'efficienza

Internamente, SparseObservable è mutabile in-place, anche utilizzando vettori crescenti sovra-allocati per estendere il numero di termini. Ciò significa che il costo dell'aggiunta a un'osservabile utilizzando += viene ammortizzato in modo lineare rispetto al numero totale di termini aggiunti, invece della complessità quadratica che richiederebbe + binario.

Le aggiunte e le sottrazioni sono implementate da un'operazione di impilamento dei termini; non c'è una "semplificazione" automatica (somma di termini simili), perché la maggior parte delle aggiunte per costruire un osservabile generano solo un piccolo numero di duplicazioni e il rilevamento dei termini simili ha costi aggiuntivi. Se questo non si adatta ai casi d'uso, si può chiamare periodicamente simplify()o discutere con noi di altre API per migliorare la costruzione degli osservabili.


Attributi

bit_terms

Un elenco piatto di termini a singolo qubit. Si tratta più naturalmente di un elenco di elenchi, ma viene memorizzato in modo piatto per motivi di utilizzo della memoria e di localizzazione, con i sottoelenchi indicati dai confini.

boundaries

Indici che dividono bit_terms e indices in sottoelenchi per ogni singolo termine della somma. boundaries[0] : boundaries[1] è l'intervallo di indici in bit_terms e indices che corrispondono al primo termine della somma. Tutti gli indici di qubit non specificati sono implicitamente l'identità. Questo è un elemento più lungo di coeffs, dato che boundaries[0] è sempre uno zero esplicito (per semplicità algoritmica).

coeffs

I coefficienti di ciascun termine astratto nella somma. Questo ha tanti elementi quanti sono i termini della somma.

indices

Un elenco piatto degli indici dei qubit su cui agiscono le voci corrispondenti in bit_terms agiscono su di essi. Questo elenco deve essere sempre ordinato per termini, dove un termine è un sottoelenco indicato da boundaries.

Avvertenza

Se si scrive in questo attributo dallo spazio Python, è necessario assicurarsi di scrivere solo indici ordinati per termine.

num_qubits

Il numero di qubit su cui agisce l'operatore.

Questo non è deducibile da altre forme o valori, poiché le identità non sono memorizzate esplicitamente.

num_terms

Il numero di termini della somma che l'operatore sta tracciando.


Metodi

adjoint

adjoint()

Calcolare l'adjoint di questa osservabile.

Questo è ben definito in senso matematico astratto. Tutti i termini dell'alfabeto a singolo qubit sono auto-aggiunti, quindi il risultato di questa operazione è lo stesso osservabile, con la differenza che i suoi coefficienti sono tutti i loro coniugati complessi.

Esempi

>>> left = SparseObservable.from_list([("XY+-", 1j)])
>>> right = SparseObservable.from_list([("XY+-", -1j)])
>>> assert left.adjoint() == right

apply_layout

apply_layout(layout, num_qubits=None)

Applicare un layout di transpiler a questo SparseObservable.

In genere si definisce l'osservabile in termini di qubit virtuali dei circuiti da utilizzare per preparare gli stati. Dopo la transpilazione, i qubit virtuali vengono mappati su particolari qubit fisici di un dispositivo, che può essere più ampio del vostro circuito. Questa mappatura può anche cambiare nel corso del circuito. Questo metodo trasforma l'osservabile di ingresso sui qubit virtuali in un'osservabile adatta ad essere applicata immediatamente dopo il circuito fisico completamente transpilato.

Parametri

  • layout (TranspileLayout |list[int] | None) – Il layout da applicare. Nella maggior parte dei casi, questa funzione dovrebbe ricevere il QuantumCircuit.layout campo proveniente da un circuito che è stato transpilato per l'hardware. Inoltre, è possibile passare un elenco di indici dei nuovi qubit. NoneSe specificato in modo esplicito, non viene applicata alcuna rimappatura (ma è comunque possibile utilizzare num_qubits per espandere l'osservabile).
  • num_qubits (int | None) – Il numero di qubit a cui espandere l'osservabile. Se non viene fornito, l'output sarà largo quanto il dato TranspileLayouto della stessa larghezza dell'input se layout è fornito in un'altra forma.

Risultati

Un nuovo SparseObservable con l'applicazione del layout fornito.

as_paulis

as_paulis()

Esprimere l'osservabile solo in termini di Pauli, scrivendo ogni proiettore come somma di termini di Pauli.

Si noti che non è garantito l'ordine dei termini di Pauli risultanti. Utilizzare SparseObservable.simplify() per ottenere una rappresentazione canonica.

Avvertenza

Si noti che questo utilizzerà almeno 2n2^n termini se sono presenti nn proiettori a singolo qubit, il che può portare a un numero esponenziale di termini.

Risultati

La stessa osservabile, ma espressa solo in termini di Pauli.

Esempi

Riscrivere un'osservabile in termini di proiettori in operatori di Pauli:

>>> obs = SparseObservable("+")
>>> obs.as_paulis()
<SparseObservable with 2 terms on 1 qubit: (0.5+0j)() + (0.5+0j)(X_0)>
>>> direct = SparseObservable.from_list([("I", 0.5), ("Z", 0.5)])
>>> assert direct.simplify() == obs.as_paulis().simplify()

Per piccoli operatori, questo può essere usato con simplify() come forma canonica unica:

>>> left = SparseObservable.from_list([("+", 0.5), ("-", 0.5)])
>>> right = SparseObservable.from_list([("r", 0.5), ("l", 0.5)])
>>> assert left.as_paulis().simplify() == right.as_paulis().simplify()
Vedi anche

SparsePauliOp.from_sparse_observable()

Un costruttore di SparsePauliOp che può convertire un oggetto SparseObservable nella SparsePauliOp rappresentazione densa di Pauli.

clear

clear()

Cancella tutti i termini da questo operatore, rendendolo di nuovo uguale all'operatore zero.

Ciò non modifica la capacità delle allocazioni interne, pertanto le successive operazioni di aggiunta o sottrazione potrebbero non richiedere una riallocazione.

Esempi

>>> obs = SparseObservable.from_list([("IX+-rl", 2.0), ("01YZII", -1j)])
>>> obs.clear()
>>> assert obs == SparseObservable.zero(obs.py_num_qubits())

commutes

commutes(other, tol=1e-12)

Verifica se l'osservabile commuta con un altro.

Parametri

  • other (SparseObservable) – L'altro osservabile con cui verificare la commutazione.
  • tol (float) – Se i coefficienti nel prodotto di sé e dell'altro sono inferiori alla tolleranza (in grandezza), i termini vengono ignorati.

Risultati

True se i termini sono commutativi, fino alla tolleranza, False altrimenti.

Aumenti

TypeError – Se non other potesse essere costretto a SparseObservable.

compose

compose(other, /, qargs=None, *, front=False)

Comporre un altro SparseObservable su questo.

In termini di algebre di operatori, la composizione corrisponde alla moltiplicazione a sinistra: c = a.compose(b) corrisponde a $C = B A$. In altre parole, a.compose(b) restituisce un operatore che "esegue a e poi esegue b sul risultato". L'argomento front=True rende invece questa moltiplicazione giusta.

self e other devono avere la stessa dimensione, a meno che non venga dato qargs , nel qual caso other può essere più piccolo di self, purché il numero di qubit in other e la lunghezza di qargs corrispondano. qargs non può mai contenere duplicati o indici di qubit che non esistono in self.

Attenzione: questa funzione può causare un'esplosione esponenziale dell'utilizzo della memoria dell'osservabile, poiché l'alfabeto di SparseObservable non è chiuso sotto composizione; la composizione di due termini a singolo bit può essere una somma, che moltiplica il numero totale di termini. Questo utilizzo di memoria non è ´necessariamente´ inerente all'osservabile risultante, ma trovare una rifattorizzazione efficiente della somma è generalmente altrettanto difficile dal punto di vista computazionale. È meglio utilizzare la conoscenza del dominio delle osservabili per ridurre al minimo il numero di termini esistenti, piuttosto che cercare di semplificarli a posteriori.

Parametri

  • altro - l'osservabile utilizzato per la moltiplicazione a sinistra self.

  • qargs -

    se dato, i qubit in self da associare ai qubit in other. Detto altrimenti: se questo è dato, è simile a un'implementazione più efficiente di:

    self.compose(other.apply_layout(qargs, self.num_qubits))

    poiché non viene creato un osservabile temporaneo per memorizzare la forma di layout applicato di other.

  • front - se True, allora moltiplica a destra per other invece di moltiplicare a sinistra (default False). Il sito qargs è ancora applicato a other. Questo è molto utile quando qargs è impostato, o other potrebbe essere un oggetto che deve essere forzato a SparseObservable.

conjugate

conjugate()

Calcolare la coniugazione complessa di questa osservabile.

Questa operazione è definita in termini di convenzioni matriciali standard di Qiskit, in quanto la forma della matrice è considerata nella base computazionale $Z$. I termini dell'alfabeto legati a ´X´ e ´Z´ non sono influenzati dalla coniugazione complessa, ma i termini legati a ´Y´ modificano i loro termini dell'alfabeto. Precisamente:

  • YY si coniuga con Y-Y
  • rr\lvert r\rangle\langle r\rvert coniugati a ll\lvert l\rangle\langle l\rvert
  • ll\lvert l\rangle\langle l\rvert coniugati a rr\lvert r\rangle\langle r\rvert

Inoltre, tutti i coefficienti sono coniugati.

Esempi

>>> obs = SparseObservable([("III", 1j), ("Yrl", 0.5)])
>>> assert obs.conjugate() == SparseObservable([("III", -1j), ("Ylr", -0.5)])

copy

copy()

Ottenere una copia di questo osservabile.

Esempi

>>> obs = SparseObservable.from_list([("IXZ+lr01", 2.5), ("ZXI-rl10", 0.5j)])
>>> assert obs == obs.copy()
>>> assert obs is not obs.copy()

evolve

evolve(other, /, qargs=None)

Evolvi questa osservabile mediante un termine di Pauli.

Un'evoluzione dell' OO e osservabile mediante un' PP e di Pauli corrisponde a POPP^\dagger O P.

A differenza di un'implementazione letterale tramite due composizioni complete, questo metodo esegue la coniugazione direttamente a livello di singolo qubit utilizzando una tabella di consultazione fissa. In questo modo si evita di materializzare qualsiasi grandezza intermedia SparseObservable e si calcola l'osservabile risultante in un unico passaggio sui termini. self e other deve avere lo stesso numero di qubit, a meno che qargs non sia specificato, nel qual caso other può essere inferiore a self, a condizione che il numero di qubit in other e la lunghezza di qargs corrispondano. qargs specifica quali qubit di self vengono fatti evolvere da other.

Attualmente, questo metodo supporta l'evoluzione solo tramite un operatore a termine singolo, il che significa che other deve essere un operatore di Pauli rappresentato da Pauli.

Parametri

  • altro – l'operatore di Pauli utilizzato per coniugare self.
  • qargs – se specificato, i qubit in self da sottoporre all'evoluzione tramite other. La lunghezza deve corrispondere al numero di qubit in other.

Risultati

Una nuova versione evoluta SparseObservable con coniugazioni applicate.

Aumenti

  • TypeError – se non other è di tipo Pauli.
  • ValueError – se self e other hanno un numero diverso di qubit (e non qargs è specificato).
  • ValueError – se qargs la lunghezza non corrisponde other al numero di qubit.
  • ValueError – se qargs contiene duplicati o indici fuori intervallo.
  • ValueError – se other contiene più di un termine.

expand

expand(other, /)

Prodotto tensoriale di ordine inverso.

Questo è equivalente a other.tensor(self), tranne che per il fatto che other verrà prima trasformato in SparseObservable se non lo è già (richiamando il costruttore predefinito).

Parametri

altro - l'osservabile da mettere sul lato sinistro del prodotto tensoriale.

Esempi

Questo è equivalente a tensor() con l'ordine degli argomenti invertito:

>>> left = SparseObservable.from_label("XYZ")
>>> right = SparseObservable.from_label("+-IIrl")
>>> assert left.tensor(right) == right.expand(left)
Vedi anche

tensor()

La stessa funzione con l'ordine degli argomenti invertito. tensor() è l'ordinamento degli argomenti più standard e corrisponde alle altre convenzioni di Qiskit.

from_label

static from_label(label, /)

Costruire un osservabile a termine singolo da un'etichetta di stringa densa.

L'operatore risultante avrà un coefficiente pari a 1. L'etichetta deve essere una sequenza dell'alfabeto 'IXYZ+-rl01'. L'etichetta viene interpretata in modo analogo a una stringa di bit. In altre parole, la lettera più a destra è associata al qubit 0 e così via. Questa è la stessa etichetta per Pauli e SparsePauliOp.

Parametri

label (str) – l'etichetta densa.

Esempi

>>> SparseObservable.from_label("IIII+ZI")
<SparseObservable with 1 term on 7 qubits: (1+0j)(+_2 Z_1)>
>>> label = "IYXZI"
>>> pauli = Pauli(label)
>>> assert SparseObservable.from_label(label) == SparseObservable.from_pauli(pauli)
Vedi anche

from_list()

Una generalizzazione di questo metodo che costruisce un operatore di somma a partire da più etichette e dai loro coefficienti corrispondenti.

from_list

static from_list(iter, /, *, num_qubits=None)

Costruire un osservabile da un elenco di etichette e coefficienti densi.

È analogo a SparsePauliOp.from_list()con la differenza che utilizza l'alfabeto esteso di SparseObservable. In questa forma densa, è necessario fornire esplicitamente tutte le identità in ogni etichetta.

L'etichetta deve essere una sequenza dell'alfabeto 'IXYZ+-rl01'. L'etichetta viene interpretata in modo analogo a una stringa di bit. In altre parole, la lettera più a destra è associata al qubit 0 e così via. Questa è la stessa etichetta per Pauli e SparsePauliOp.

Parametri

  • iter (list[tuple[str, complex]]) – Coppie di etichette e coefficienti associati da sommare. Le etichette vengono interpretate come in from_label().
  • num_qubits (int | None) – Non è necessario specificarlo se si è sicuri che iter non è una sequenza vuota, poiché può essere dedotta dalle lunghezze delle etichette. Se iter può essere vuoto, è necessario specificare questo argomento per disambiguare il numero di qubit dell'osservabile. Se viene dato e iter non è vuoto, il valore deve corrispondere alle lunghezze delle etichette.

Esempi

Costruire un osservabile da un elenco di etichette della stessa lunghezza:

>>> SparseObservable.from_list([
...     ("III++", 1.0),
...     ("II--I", 1.0j),
...     ("I++II", -0.5),
...     ("--III", -0.25j),
... ])
<SparseObservable with 4 terms on 5 qubits:
    (1+0j)(+_1 +_0) + (0+1j)(-_2 -_1) + (-0.5+0j)(+_3 +_2) + (-0-0.25j)(-_4 -_3)>

Utilizzare num_qubits per disambiguare gli input potenzialmente vuoti:

>>> SparseObservable.from_list([], num_qubits=10)
<SparseObservable with 0 terms on 10 qubits: 0.0>

Questo metodo è equivalente alle chiamate a from_sparse_list() con il campo esplicito qubit-arguments impostato su numeri interi decrescenti:

>>> labels = ["XY+Z", "rl01", "-lXZ"]
>>> coeffs = [1.5j, 2.0, -0.5]
>>> from_list = SparseObservable.from_list(list(zip(labels, coeffs)))
>>> from_sparse_list = SparseObservable.from_sparse_list([
...     (label, (3, 2, 1, 0), coeff)
...     for label, coeff in zip(labels, coeffs)
... ])
>>> assert from_list == from_sparse_list
Vedi anche

from_label()

Un costruttore simile, ma che accetta solo una singola etichetta e ha sempre il suo coefficiente impostato su 1.0.

from_sparse_list()

Costruire l'osservabile a partire da una lista di etichette senza identità esplicite, ma con i qubit a cui si applica ogni termine a singolo qubit elencati esplicitamente.

from_pauli

static from_pauli(pauli, /)

Costruire un SparseObservable da una singola Pauli istanza.

L'osservabile di uscita avrà un unico termine, con un coefficiente unitario dipendente dalla fase.

Parametri

pauli (Pauli) – il singolo Pauli da convertire.

Esempi

>>> label = "IYXZI"
>>> pauli = Pauli(label)
>>> SparseObservable.from_pauli(pauli)
<SparseObservable with 1 term on 5 qubits: (1+0j)(Y_3 X_2 Z_1)>
>>> assert SparseObservable.from_label(label) == SparseObservable.from_pauli(pauli)

from_raw_parts

static from_raw_parts(num_qubits, coeffs, bit_terms, indices, boundaries, check=True)

Costruire una classe SparseObservable da array Numpy grezzi che corrispondono alla rappresentazione dei dati richiesta, descritta nella documentazione a livello di classe.

I dati di ogni array vengono copiati in allocazioni fresche e crescenti dello spazio Rust.

Parametri

  • num_qubit - numero di qubit nell'osservabile.

  • coeff - coefficienti complessi di ciascun termine dell'osservabile. Dovrebbe essere una matrice Numpy con il tipo dtype complex128.

  • bit_terms - elenco appiattito dei termini single-qubit che comprende tutti i termini completi. Dovrebbe essere un array Numpy con dtype uint8 (che è compatibile con BitTerm).

  • indici - elenco appiattito ordinato per termini dei qubit a cui corrisponde ogni termine a singolo qubit. Dovrebbe essere una matrice Numpy con il tipo dtype uint32.

  • confini - gli indici che suddividono bit_terms e indices in termini. Dovrebbe essere un array Numpy con il tipo dtype uintp.

  • controllo -

    se True (l'impostazione predefinita), convalida che i dati soddisfino tutte le garanzie di coerenza. Se False, non viene effettuato alcun controllo.

    Avvertenza

    Se check=False, i bit_terms devono assolutamente essere tutti valori validi di SparseObservable.BitTerm. In caso contrario, potrebbe verificarsi un comportamento non definito nello spazio di Rust, invalidando completamente l'esecuzione del programma.

Esempi

Costruire una somma di ZZ su ogni singolo qubit:

>>> num_qubits = 100
>>> terms = np.full((num_qubits,), SparseObservable.BitTerm.Z, dtype=np.uint8)
>>> indices = np.arange(num_qubits, dtype=np.uint32)
>>> coeffs = np.ones((num_qubits,), dtype=complex)
>>> boundaries = np.arange(num_qubits + 1, dtype=np.uintp)
>>> SparseObservable.from_raw_parts(num_qubits, coeffs, terms, indices, boundaries)
<SparseObservable with 100 terms on 100 qubits: (1+0j)(Z_0) + ... + (1+0j)(Z_99)>

from_sparse_list

static from_sparse_list(iter, /, num_qubits)

Costruire un osservabile da un elenco di etichette, i qubit a cui si applica ogni elemento e il coefficiente dell'intero termine.

È analogo a SparsePauliOp.from_sparse_list()con la differenza che utilizza l'alfabeto esteso di SparseObservable.

I campi "label" e "indices" delle triple sono associati tra loro mediante lo zippaggio. Per esempio, ciò significa che una chiamata a from_list() può essere convertita nella forma utilizzata da questo metodo impostando il campo "indici" di ogni tripla a (num_qubits-1, ..., 1, 0).

Parametri

  • iter (list[tuple[str, Sequence[int], complex]]) – triple di etichette, i qubit a cui si applica ogni termine a singolo qubit e il coefficiente dell'intero termine.
  • num_qubits (int) – il numero di qubit nell'operatore.

Esempi

Costruire un operatore semplice:

>>> SparseObservable.from_sparse_list(
...     [("ZX", (1, 4), 1.0), ("YY", (0, 3), 2j)],
...     num_qubits=5,
... )
<SparseObservable with 2 terms on 5 qubits: (1+0j)(X_4 Z_1) + (0+2j)(Y_3 Y_0)>

Costruire l'osservabile identità (anche se, in realtà, basta usare identity()):

>>> SparseObservable.from_sparse_list([("", (), 1.0)], num_qubits=100)
<SparseObservable with 1 term on 100 qubits: (1+0j)()>

Questo metodo può replicare il comportamento di from_list()se il campo qubit-arguments della tripla è impostato su numeri interi decrescenti:

>>> labels = ["XY+Z", "rl01", "-lXZ"]
>>> coeffs = [1.5j, 2.0, -0.5]
>>> from_list = SparseObservable.from_list(list(zip(labels, coeffs)))
>>> from_sparse_list = SparseObservable.from_sparse_list([
...     (label, (3, 2, 1, 0), coeff)
...     for label, coeff in zip(labels, coeffs)
... ])
>>> assert from_list == from_sparse_list
Vedi anche

to_sparse_list()

L'inverso di questo metodo.

from_sparse_pauli_op

static from_sparse_pauli_op(op, /)

Costruire un SparseObservable da un'istanza SparsePauliOp istanza.

Si tratta di una traduzione in gran parte diretta del modello SparsePauliOpin particolare, non c'è alcuna somma al volo di termini simili, né alcun tentativo di rifattorizzare le somme di termini di Pauli in operatori di proiezione equivalenti.

Parametri

op (SparsePauliOp) – l'operatore da convertire.

Esempi

>>> spo = SparsePauliOp.from_list([("III", 1.0), ("IIZ", 0.5), ("IZI", 0.5)])
>>> SparseObservable.from_sparse_pauli_op(spo)
<SparseObservable with 3 terms on 3 qubits: (1+0j)() + (0.5+0j)(Z_0) + (0.5+0j)(Z_1)>

from_terms

static from_terms(obj, /, num_qubits=None)

Costruire un SparseObservable con i singoli termini.

Tutti i termini devono avere lo stesso numero di qubit. Se fornito, l'argomento num_qubits deve corrispondere ai termini.

Non viene effettuata alcuna semplificazione nell'ambito della creazione dell'osservabile.

Parametri

  • obj (Iterable[Term]) – Iterabile di termini individuali da cui costruire l'osservabile.
  • num_qubits (int | None) – Il numero di qubit su cui deve agire l'osservabile. Di solito viene dedotto dall'input, ma può essere dato esplicitamente per gestire il caso di un iterabile vuoto.

Risultati

L'osservabile corrispondente.

identity

static identity(num_qubits)

Ottiene l'operatore di identità sul numero di qubit dato.

Esempi

Ottenere l'operatore di identità per 100 qubit:

>>> SparseObservable.identity(100)
<SparseObservable with 1 term on 100 qubits: (1+0j)()>

pauli_bases

pauli_bases()

Ottenere un PauliList che rappresenta la base di misura necessaria per ogni termine (in ordine) di questa osservabile.

Ad esempio, il proiettore 0l+ restituirà un Pauli ZXY. Il risultato Pauli è denso, nel senso che vengono memorizzate identità esplicite. Un'identità nell'uscita di Pauli non richiede una misura concreta.

Questo restituirà una voce nell'elenco Pauli per ogni termine della somma.

Risultati

l'elenco degli operatori di Pauli che rappresentano le basi di misura necessarie.

Tipo di restituzione

PauliList

simplify

simplify(tol=1e-08)

Somma tutti i termini simili in questo operatore, eliminandoli se il coefficiente complesso risultante ha un valore assoluto entro la tolleranza di zero.

Come effetto collaterale, questo ordina l'operatore in ordine canonico.

Nota

Quando si utilizza questa operazione per confronti di uguaglianza, occorre tenere presente che l'arrotondamento dei valori in virgola mobile e la non associatività dell'addizione in virgola mobile possono far sì che coefficienti diversi da zero dei termini sommati risultino disuguali al confronto. Per confrontare due grandezze osservabili entro un certo margine di tolleranza, il metodo più sicuro consiste nel verificare se la differenza canonizzata delle due grandezze è pari a zero.

Parametri

tol (float) – dopo aver sommato i termini simili, i coefficienti il cui valore assoluto è inferiore alla tolleranza assoluta indicata saranno eliminati dall'uscita.

Esempi

Utilizzando simplify() per confrontare due operatori che rappresentano lo stesso osservabile, ma che si confronterebbero in modo diseguale a causa dei test strutturali predefiniti:

>>> base = SparseObservable.from_sparse_list([
...     ("XZ", (2, 1), 1e-10),  # value too small
...     ("+-", (3, 1), 2j),
...     ("+-", (3, 1), 2j),     # can be combined with the above
...     ("01", (3, 1), 0.5),    # out of order compared to `expected`
... ], num_qubits=5)
>>> expected = SparseObservable.from_list([("I0I1I", 0.5), ("I+I-I", 4j)])
>>> assert base != expected  # non-canonical comparison
>>> assert base.simplify() == expected.simplify()

Si noti che nell'esempio precedente i coefficienti sono scelti in modo tale che tutti i calcoli in virgola mobile siano esatti e non vi siano problemi di arrotondamento o associatività intermedia. Se non è possibile garantire che ciò avvenga, la forma più sicura è la seguente:

>>> left = SparseObservable.from_list([("XYZ", 1.0/3.0)] * 3)   # sums to 1.0
>>> right = SparseObservable.from_list([("XYZ", 1.0/7.0)] * 7)  # doesn't sum to 1.0
>>> assert left.simplify() != right.simplify()
>>> assert (left - right).simplify() == SparseObservable.zero(left.num_qubits)

tensor

tensor(other, /)

Prodotto tensoriale di due osservabili.

L'ordinamento dei bit è definito in modo tale che gli indici dei qubit dell'argomento rimangano gli stessi, mentre gli indici di self vengano spostati del numero di qubit presenti in other. Si tratta della stessa convenzione utilizzata dal resto degli operatori di Qiskit quantum_info .

Questa funzione viene utilizzata per l'operatore infix ^ . Se si usa questo operatore, bisogna tenere presente che le regole di precedenza degli operatori di Python ' possono far sì che l'ordine di valutazione sia diverso da quello previsto. In particolare, l'operatore + si lega più strettamente di ^, così come * si lega più strettamente di +. Usare le parentesi per fissare l'ordine di valutazione, se necessario.

L'argomento verrà lanciato in SparseObservable utilizzando il suo costruttore predefinito, se non è già nella forma corretta.

Parametri

altro - l'osservabile da mettere sul lato destro del prodotto tensoriale.

Esempi

L'ordinamento dei bit è tale che il prodotto tensoriale di due osservabili ricavati da una singola etichetta "assomiglia" a un osservabile ricavato dalla concatenazione delle due stringhe:

>>> left = SparseObservable.from_label("XYZ")
>>> right = SparseObservable.from_label("+-IIrl")
>>> assert left.tensor(right) == SparseObservable.from_label("XYZ+-IIrl")

Si può anche usare l'operatore infix ^ per i prodotti tensoriali, che in modo analogo casterà il lato destro dell'operazione, se non è già un elemento SparseObservable:

>>> assert SparseObservable("rl") ^ Pauli("XYZ") == SparseObservable("rlXYZ")
Vedi anche

expand()

La stessa funzione, ma con l'ordine degli argomenti invertito. Questo può essere utile se si desidera utilizzare il comportamento di fusione per l'argomento, ma si vuole che il parametro esistente SparseObservable sia sul lato destro dell'ordinamento del tensore.

to_sparse_list

to_sparse_list()

Esprimere l'osservabile in termini di formato di elenco sparso.

Questa può essere vista come una contro-operazione di SparseObservable.from_sparse_list()ma non è garantito che l'ordine dei termini sia lo stesso dopo un viaggio di andata e ritorno verso un elenco rado.

Esempi

>>> obs = SparseObservable.from_list([("IIXIZ", 2j), ("IIZIX", 2j)])
>>> reconstructed = SparseObservable.from_sparse_list(obs.to_sparse_list(), obs.num_qubits)
Vedi anche

from_sparse_list()

Il costruttore che può interpretare questi elenchi.

transpose

transpose()

Calcolare la trasposizione matriciale di questa osservabile.

Questa operazione è definita in termini di convenzioni matriciali standard di Qiskit, in quanto la forma della matrice è considerata nella base computazionale $Z$. I termini dell'alfabeto legati a ´X´ e ´Z´ non sono influenzati dalla trasposizione, ma i termini legati a ´Y´ modificano i loro termini dell'alfabeto. Precisamente:

  • YY si traspone in Y-Y
  • rr\lvert r\rangle\langle r\rvert si traspone in ll\lvert l\rangle\langle l\rvert
  • ll\lvert l\rangle\langle l\rvert si traspone in rr\lvert r\rangle\langle r\rvert

Esempi

>>> obs = SparseObservable([("III", 1j), ("Yrl", 0.5)])
>>> assert obs.transpose() == SparseObservable([("III", 1j), ("Ylr", -0.5)])

zero

static zero(num_qubits)

Ottiene l'operatore zero sul numero di qubit indicato.

L'operatore zero è l'operatore il cui valore di aspettativa è zero per tutti gli stati quantistici. Non ha termini. È l'elemento di identità per l'addizione di due SparseObservable qualsiasi cosa venga aggiunta all'operatore zero è uguale a se stesso.

Se si desidera che il proiettore si trovi nello stato di tutti gli zeri, utilizzare:

>>> num_qubits = 10
>>> all_zeros = SparseObservable.from_label("0" * num_qubits)

Esempi

Ottenere l'operatore zero per 100 qubit:

>>> SparseObservable.zero(100)
<SparseObservable with 0 terms on 100 qubits: 0.0>
Questa pagina è stata utile?
Segnala un bug, un errore di battitura o richiedi contenuti su GitHub.