Skip to main content
IBM Quantum Platform

SparseObservable

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

GitHub

Bases: object

Un observable sobre bases Pauli que almacena sus datos en un formato de qubit disperso.


mathematics

Este observable representa una suma sobre cadenas de operadores de Pauli y proyectores de estados propios de Pauli, con cada término ponderado por algún número complejo. Es decir, el observable completo es

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

para números complejos cic_i y operadores single-qubit que actúan sobre qubit nn a partir de un alfabeto restringido Ai(n)A^{(n)}_i. La suma sobre ii es la suma de los términos individuales, y el producto tensorial produce las cadenas de operadores.

El alfabeto de operadores de un solo qubit permitido del que se extraen los Ai(n)A^{(n)}_i son los operadores de Pauli y los operadores de proyección de Pauli-eigen-estado. Explícitamente, estos son:

Etiqueta
Operador
Valor numérico
BitTerm atributo
"I"II (identidad)No guardado.No guardado.
"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 (proyector a estado propio positivo de X)0b1010 (10)PLUS
"-"\lvert-\rangle\langle-\rvert (proyector a estado propio negativo de X)0b0110 (6)MINUS
"r"rr\lvert r\rangle\langle r\rvert (proyector a estado propio positivo de Y)0b1011 (11)RIGHT
"l"ll\lvert l\rangle\langle l\rvert (proyector a estado propio negativo de Y)0b0111 (7)LEFT
"0"00\lvert0\rangle\langle0\rvert (proyector a estado propio positivo de Z)0b1001 (9)ZERO
"1"11\lvert1\rangle\langle1\rvert (proyector a estado propio negativo de Z)0b0101 (5)ONE

El alfabeto permitido forma una base sobrecompleta del espacio de operadores. Esto significa que no existe una suma única para representar un observable dado. En comparación, SparsePauliOp utiliza una base precisa del espacio de operadores, por lo que (tras combinar términos de la misma cadena de Pauli, eliminar ceros y ordenar los términos según algún orden canónico ) sólo hay una representación de cualquier operador.

SparseObservable utiliza su particular base sobrecompleta con el objetivo de hacer equivalente la "eficacia de la medición" a la "eficacia de la representación". Por ejemplo, el observable 00n{\lvert0\rangle\langle0\rvert}^{\otimes n} puede medirse eficientemente en el hardware con simples mediciones de ZZ, pero sólo puede ser representado por SparsePauliOp como (I+Z)n/2n{(I + Z)}^{\otimes n}/2^n, lo que requiere términos almacenados en 2n2^n. SparseObservable requiere un único término para almacenarlo.

El inconveniente de esto es que resulta poco práctico tomar una matriz arbitraria o SparsePauliOp y encontrar la mejor SparseObservable representación. Por lo general, querrá construir un SparseObservable directamente, en lugar de intentar descomponerlo en uno.


Representación

La representación interna de a SparseObservable almacena sólo los operadores qubit no identitarios. Esto hace que sea significativamente más eficiente representar observables como nqubitsZ(n)\sum_{n\in \text{qubits}} Z^{(n)}; SparseObservable requiere una cantidad de memoria lineal en el número total de qubits, mientras que SparsePauliOp se escala cuadráticamente.

Los términos se almacenan comprimidos, de forma similar al formato de filas dispersas comprimido de las matrices dispersas. En esta analogía, los términos de la suma son las "filas", y los términos del qubit son las "columnas", donde una entrada ausente representa la identidad en lugar de un cero. Más explícitamente, la representación se compone de cuatro matrices contiguas:

Atributo
Longitud
Descripción
coeffsttEl multiplicador escalar complejo para cada término.
bit_termsssCada uno de los términos single-qubit no idénticos para todos los operadores, en orden. Corresponden a la no-identidad Ai(n)A^{(n)}_i en la descripción de la suma, donde las entradas se almacenan en orden creciente ii primero, y en orden creciente nn dentro de cada término.
indicesssEl qubit correspondiente ( nn ) para cada uno de los operadores en bit_terms. SparseObservable requiere que esta lista esté ordenada por términos, y los algoritmos pueden confiar en que esta invariante se mantenga.
boundariest+1t+1Los índices que dividen bit_terms y indices en términos completos. Para el término número ii, su coeficiente complejo es coeffs[i], y sus operadores single-qubit no-identidad y sus qubits correspondientes son el corte boundaries[i] : boundaries[i+1] en bit_terms y indices respectivamente. boundaries siempre tiene un 0 explícito como primer elemento.

El parámetro de longitud tt es el número de términos en la suma, y el parámetro ss es el número total de términos single-qubit no idénticos.

Como ejemplos ilustrativos:

  • en el caso de un operador cero, boundaries es de longitud 1 (un único 0) y todos los demás vectores están vacíos.
  • en el caso de un operador de identidad totalmente simplificado, boundaries es [0, 0], coeffs tiene una única entrada, y bit_terms y indices están vacíos.
  • para el operador Z2Z0X3Y1Z_2 Z_0 - X_3 Y_1, boundaries es [0, 2, 4], coeffs es [1.0, -1.0], bit_terms es [BitTerm.Z, BitTerm.Z, BitTerm.Y, BitTerm.X] y indices es [0, 2, 1, 3]. El operador puede actuar sobre más de cuatro qubits, dependiendo del num_qubits parámetro. Los bit_terms son valores enteros, a cuyos números mágicos se puede acceder mediante la clase de atributo BitTerm clase de atributo. Obsérvese que los términos e índices de un bit se ordenan por términos. Este es un requisito de la clase.

Estos casos no son especiales, son totalmente coherentes con las normas y no deberían necesitar un tratamiento especial.

El elemento escalar de la matriz bit_terms se almacena como un byte numérico. Los valores numéricos están relacionados con la representación Pauli simpléctica que SparsePauliOp utiliza, y son accesibles con acceso nominativo mediante una enumeración:

BitTerm

class BitTerm

GitHub

Un IntEnum que proporciona acceso con nombre a los valores numéricos utilizados para representar cada uno de los términos del alfabeto de un solo qubit enumerados en Alfabeto de términos de un solo qubit utilizados en SparseObservable.

Esta clase se adjunta a SparseObservable. Acceder como SparseObservable.BitTerm. Si esto es teclear demasiado, y sólo está tratando con objetos :class:¬SparseObservable` y el nombre BitTerm no es ambiguo, puede acortarlo como:

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

Puede acceder a todos los valores de la enumeración por su nombre completo en mayúsculas o por su etiqueta de una sola letra. Las etiquetas de una sola letra no suelen ser identificadores válidos de Python, por lo que debe utilizar la notación de indexación para acceder a ellas:

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

La estructura numérica de éstos es que son todos valores de cuatro bits de los cuales los dos bits inferiores son la representación simpléctica (sin fase) del operador de Pauli relacionado con el objeto, donde el bit inferior denota una contribución por ZZ y el segundo inferior una contribución por XX, mientras que los dos bits superiores son 00 para un operador de Pauli, 01 para el proyector de estado propio negativo, y 10 para el proyector de estado propio positivo.

Valores

X

Valor predeterminado: 2

El operador Pauli XX. Utiliza la etiqueta de una sola letra "X".

PLUS

Valor predeterminado: 10

El proyector al estado propio positivo del operador XX : ++\lvert+\rangle\langle+\rvert. Utiliza la etiqueta de una sola letra "+".

MINUS

Valor predeterminado: 6

El proyector al estado propio negativo del operador XX : \lvert-\rangle\langle-\rvert. Utiliza la etiqueta de una sola letra "-".

Y

Valor predeterminado: 3

El operador Pauli YY. Utiliza la etiqueta de una sola letra "Y".

DERECHA

Valor predeterminado: 11

El proyector al estado propio positivo del operador YY : rr\lvert r\rangle\langle r\rvert. Utiliza la etiqueta de una sola letra "r".

IZQUIERDA

Valor predeterminado: 7

El proyector al estado propio negativo del operador YY : ll\lvert l\rangle\langle l\rvert. Utiliza la etiqueta de una sola letra "l".

Z

Valor predeterminado: 1

El operador Pauli ZZ. Utiliza la etiqueta de una sola letra "Z".

CERO

Valor predeterminado: 9

El proyector al estado propio positivo del operador ZZ : 00\lvert0\rangle\langle0\rvert. Utiliza la etiqueta de una sola letra "0".

UNO

Valor predeterminado: 5

El proyector al estado propio negativo del operador ZZ : 11\lvert1\rangle\langle1\rvert. Utiliza la etiqueta de una sola letra "1".

Atributos

label

La etiqueta de cadena de un solo carácter utilizada para representar este término en el SparseObservable alfabeto.

Cada uno de los atributos tipo array se comporta como una secuencia Python. Puede indexarlos y cortarlos con la semántica list-estándar. El corte de un atributo devuelve un Numpy ndarray que contiene una copia de los datos relevantes con la dirección natural dtype del campo; esto le permite realizar fácilmente operaciones matemáticas con los resultados, como operaciones bit a bit con bit_terms. Puede asignar a índices o rebanadas de cada uno de los atributos, pero tenga en cuenta que al hacerlo debe respetar las normas de coherencia de datos. Por ejemplo:

>>> 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 reducción anterior a las bases de Pauli también se puede conseguir con pauli_bases().

Orden canónico

Para cualquier observable matemático dado, hay varias formas de representarlo con SparseObservable. Por ejemplo, el mismo conjunto de términos de un solo bit y sus índices correspondientes pueden aparecer varias veces en el observable. Matemáticamente, esto equivale a tener un único término con todos los coeficientes sumados. Del mismo modo, los términos de la suma en a SparseObservable pueden estar en cualquier orden mientras representan el mismo observable, ya que la suma es conmutativa (aunque la suma en coma flotante no es asociativa, SparseObservable no garantiza el orden de la suma).

Estas dos categorías de degeneración de la representación pueden hacer que el == operador afirme que dos observables no son iguales, a pesar de que representan el mismo objeto. En estos casos, puede resultar conveniente definir una forma canónica que permita comparar los observables desde el punto de vista estructural.

Puede poner un SparseObservable en forma canónica utilizando el método simplify() método. El orden preciso de los términos en el orden canónico no está especificado, y puede cambiar entre versiones de Qiskit. Sin embargo, dentro de la misma versión de Qiskit, puedes comparar dos observables estructuralmente comparando sus formas simplificadas.

Nota

Si desea tener en cuenta la tolerancia de coma flotante en la comparación, lo más seguro es utilizar una receta como:

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

La forma canónica producida por simplify() por sí sola no detectará universalmente todos los observables que son equivalentes debido al alfabeto de bases sobrecompletas. Para obtener una expresión única, primero puede representar el observable utilizando sólo términos de Pauli llamando a as_paulis()seguido de simplify(). Tenga en cuenta que la expansión del proyector (p. ej. + en I y X) no es computacionalmente factible a escala.

Indexación

SparseObservable se comporta como una secuencia Python (la forma estándar, no la expandida collections.abc.Sequence). El observable puede indexarse por enteros e iterarse para obtener términos individuales.

Cada término aparece como una instancia de una clase autónoma. Los términos individuales se copian del observable base; las mutaciones en ellos no afectarán al observable.

Plazo

class Term(num_qubits, coeff, bit_terms, indices)

GitHub

Bases: object

Un solo término de un SparseObservable.

Normalmente se crean indexando o iterando a través de un archivo SparseObservable.

bit_labels

bit_labels()

Devuelve las etiquetas de bits del término como cadena.

Las etiquetas de los bits coincidirán con el orden de SparseTerm.indices, de forma que el carácter i-ésimo de la cadena se aplique al índice del qubit en term.indices[i].

Devuelve

Los términos de bits de no identidad como cadena concatenada.

bit_terms

Vista de sólo lectura de los términos single-qubit individuales.

Los únicos valores válidos en la matriz son los que tienen un valor BitTerm.

coeff

El coeficiente del término.

copy

copy()

Obtenga una copia de este término.

indices

Vista de sólo lectura de los índices de cada término single-qubit no identitario.

Los índices estarán siempre ordenados.

num_qubits

El número de qubits en los que se define el término.

pauli_base

pauli_base()

Obtener un Pauli objeto que representa la base de medida necesaria para este término.

Por ejemplo, el proyector 0l+ devolverá un Pauli ZYX. El resultado Pauli es denso, en el sentido de que se almacenan identidades explícitas. Una identidad en la salida de Pauli no requiere una medida concreta.

Devuelve: Pauli: el operador de Pauli que representa lo necesario

base de medición.

Consulte también

SparseObservable.pauli_bases()

Un método similar para todo un observable a la vez.

to_observable

to_observable()

Convertir este término en un SparseObservable.


Construcción

SparseObservable define varios constructores. El constructor por defecto intentará delegar en uno de los constructores más específicos, basándose en el tipo de la entrada. Siempre puedes utilizar los constructores específicos para tener más control sobre la construcción.

Método
Resumen
from_label()Convertir una etiqueta de cadena densa en un único término SparseObservable.
from_list()Suma una lista de tuplas de etiquetas de cadenas densas y los coeficientes asociados en un observable.
from_sparse_list()Suma una lista de tuplas de etiquetas de cadenas dispersas, los qubits a los que se aplican y sus coeficientes en un observable.
from_pauli()Convierte un Pauli en un único término SparseObservable.
from_sparse_pauli_op()Elevar un SparsePauliOp a SparseObservable.
from_terms()Suma explícita de Term instancias.
from_raw_parts()Construir el observable a partir de las matrices de datos brutos.

__new__

__new__(data, /, num_qubits=None)

El constructor por defecto de SparseObservable.

Esto delega en uno de los métodos constructores de conversión explícitos, basándose en el tipo del argumento data . Si se suministra num_qubits y el constructor implicado por el tipo de data no acepta un número, el entero dado debe coincidir con la entrada.

Parámetros

  • data - Tipo de datos de la entrada. Puede ser otro SparseObservableen cuyo caso se copia la entrada, un Pauli o SparsePauliOpen cuyo caso from_pauli() o from_sparse_pauli_op() según corresponda, o puede ser una lista en un formato válido para from_list() o from_sparse_list().
  • num_qubits (int|None) – Número opcional de qubits para el operador. Para la mayoría de las entradas de datos, esto se puede deducir y no es necesario pasarlo. Sólo es necesario para las listas vacías o el formato sparse-list. Si se da innecesariamente, debe coincidir con los datos introducidos.

Además de los constructores basados en conversiones, también existen métodos de ayuda que construyen formas especiales de observables.

Método
Resumen
zero()El operador cero en un número determinado de qubits.
identity()El operador de identidad en un número determinado de qubits.

Conversiones

Una SparseObservable puede convertirse en otros quantum_info operadores o formatos genéricos. Tenga en cuenta que otros objetos pueden no ser capaces de representar el mismo observable tan eficientemente como SparseObservableincluyendo la posibilidad de necesitar exponencialmente más memoria.

Método
Resumen
as_paulis()Crear un nuevo SparseObservableexpandiéndose sólo en términos de operadores de Pauli.
to_sparse_list()Exprese el observable en formato de lista dispersa con elementos (bit_terms, indices, coeff).

Además, SparsePauliOp.from_sparse_observable() está disponible para la conversión de esta clase a SparsePauliOp. Tenga en cuenta que este método sufre los mismos problemas de uso exponencial de memoria que el método as_paulis().


Manipulación matemática

SparseObservable admite el conjunto estándar de operadores matemáticos Python, al igual que otros quantum_info operadores.

En aritmética básica, puedes:

  • añadir dos observables utilizando +
  • restar dos observables mediante -
  • multiplicar o dividir por un int, float o complex utilizando * y /
  • negar todos los coeficientes de un observable unario -

Cada uno de los operadores aritméticos binarios básicos tiene su correspondiente método in-place especializado, que muta el lado izquierdo in-place. Su uso suele ser más eficiente que el de los operadores infijos, especialmente para construir un observable en un bucle.

El producto tensorial se calcula con tensor() (para el orden estándar, de yuxtaposición de etiquetas de Pauli) o expand() (para el orden inverso). El operador ^ se sobrecarga para que sea equivalente a tensor().

Nota

Al utilizar los operadores binarios ^ (tensor()) y & (compose()), tenga en cuenta que las reglas de precedencia de operadores de Python pueden hacer que el orden de evaluación sea diferente al esperado. En concreto, el operador + se une más estrechamente que ^ o &, al igual que * se une más estrechamente que +.

Cuando se utilizan los operadores en expresiones mixtas, lo más seguro es utilizar paréntesis para agrupar los operandos de los productos tensoriales.

A SparseObservable tiene un adjoint(). Las nociones de conjugación compleja escalar (conjugate()) y transposición de valor real (transpose()) se definen de forma análoga a la representación matricial de otros operadores de Pauli en Qiskit.

Notas sobre eficiencia

Internamente, SparseObservable es mutable in-place, incluyendo el uso de vectores crecibles sobre-asignados para extender el número de términos. Esto significa que el coste de añadir a un observable utilizando += se amortiza linealmente en el número total de términos añadidos, en lugar de la complejidad cuadrática que requeriría el binario + .

Las sumas y restas se ejecutan mediante una operación de apilamiento de términos; no hay "simplificación" automática (suma de términos similares), porque la mayoría de las sumas para construir un observable generan sólo un pequeño número de duplicaciones, y la detección de términos similares tiene costes adicionales. Si esto no se ajusta a sus casos de uso, puede llamar periódicamente a simplify()o discutir otras APIs con nosotros para una mejor construcción de observables.


Atributos

bit_terms

Una lista plana de términos single-qubit. Esto es más naturalmente una lista de listas, pero se almacena plana por razones de uso de memoria y localización, con las sublistas denotadas por límites.

boundaries

Índices que particionan bit_terms y indices en sublistas para cada término individual de la suma. boundaries[0] : boundaries[1] es el rango de índices en bit_terms y indices que corresponden al primer término de la suma. Todos los índices de qubit no especificados son implícitamente la identidad. Es un elemento más largo que coeffsya que boundaries[0] es siempre un cero explícito (para facilitar el algoritmo).

coeffs

Los coeficientes de cada término abstracto en en la suma. Tiene tantos elementos como términos tiene la suma.

indices

Una lista plana de los índices de qubits sobre los que actúan las entradas correspondientes en bit_terms actúan. Esta lista debe estar siempre ordenada por términos, donde un término es una sublista denotada por boundaries.

Aviso

Si escribe en este atributo desde el espacio Python, debe asegurarse de que sólo escribe en índices ordenados por términos.

num_qubits

Número de qubits sobre los que actúa el operador.

Esto no puede deducirse de ninguna otra forma o valor, ya que las identidades no se almacenan explícitamente.

num_terms

El número de términos en la suma que este operador está rastreando.


Métodos

adjoint

adjoint()

Calcular el adjunto de este observable.

Esto está bien definido en el sentido matemático abstracto. Todos los términos del alfabeto single-qubit son autoadjuntos, por lo que el resultado de esta operación es el mismo observable, excepto que sus coeficientes son todos sus conjugados complejos.

Ejemplos

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

apply_layout

apply_layout(layout, num_qubits=None)

Aplique un diseño de transpilador a esto SparseObservable.

Normalmente habrás definido tu observable en términos de los qubits virtuales de los circuitos que utilizarás para preparar estados. Tras la transpilación, los qubits virtuales se asignan a qubits físicos concretos en un dispositivo, que puede ser más amplio que tu circuito. Esa asignación también puede cambiar a lo largo del circuito. Este método transforma el observable de entrada en qubits virtuales en un observable adecuado para aplicar inmediatamente después del circuito físico totalmente transpilado.

Parámetros

  • layout (TranspileLayout |list[int] | None) – La disposición a aplicar. La mayoría de los usos de esta función deben pasar el QuantumCircuit.layout campo de un circuito transpilado para hardware. Además, puede pasar una lista de nuevos índices de qubits. Si se da explícitamente None, no se aplica ninguna reasignación (pero puede seguir utilizando num_qubits para ampliar el observable).
  • num_qubits (int | None) – El número de qubits al que expandir el observable. Si no se proporciona, la salida será tan ancha como la entrada TranspileLayouto la misma anchura que la entrada si layout se proporciona de otra forma.

Devuelve

Un nuevo SparseObservable con el diseño proporcionado aplicado.

as_paulis

as_paulis()

Expresar el observable sólo en términos de Pauli, escribiendo cada proyector como suma de términos de Pauli.

Nótese que no se garantiza el orden de los términos de Pauli resultantes. Utilice SparseObservable.simplify() además para obtener una representación canónica.

Aviso

Tenga en cuenta que esto utilizará al menos 2n2^n términos si hay nn proyectores single-qubit presentes, lo que puede conducir a un número exponencial de términos.

Devuelve

El mismo observable, pero expresado sólo en términos de Pauli.

Ejemplos

Reescribir un observable en términos de proyectores en operadores de 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()

Para operadores pequeños, esto se puede utilizar con simplify() como forma canónica única:

>>> 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()
Consulte también

SparsePauliOp.from_sparse_observable()

Un constructor de SparsePauliOp que puede convertir un SparseObservable en la SparsePauliOp representación densa de Pauli.

clear

clear()

Borra todos los términos de este operador, haciéndolo de nuevo igual al operador cero.

Esto no modifica la capacidad de las asignaciones internas, por lo que es posible que las operaciones posteriores de suma o resta no requieran una reasignación.

Ejemplos

>>> 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)

Comprueba si el observable conmuta con otro.

Parámetros

  • other (SparseObservable) – El otro observable con el que comprobar la conmutación.
  • tol (float) – Si los coeficientes en el producto de uno mismo y otro están por debajo de la tolerancia (en magnitud), los términos se ignoran.

Devuelve

True si los términos conmutan, hasta la tolerancia, False de lo contrario.

Aumentos

TypeError – Si no other pudiera ser coaccionado para SparseObservable.

compose

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

Componga otro SparseObservable sobre éste.

En términos de álgebras de operadores, la composición corresponde a la multiplicación por la izquierda: c = a.compose(b) corresponde a $C = B A$. En otras palabras, a.compose(b) devuelve un operador que "realiza a, y luego realiza b sobre el resultado". En cambio, el argumento front=True lo convierte en una multiplicación por la derecha.

self y other deben tener el mismo tamaño, a menos que se indique qargs , en cuyo caso other puede ser menor que self, siempre que el número de qubits de other y la longitud de qargs coincidan. qargs nunca puede contener duplicados o índices de qubits que no existan en self.

Tenga en cuenta que esta función puede provocar una explosión exponencial del uso de memoria del observable, ya que el alfabeto de SparseObservable no es cerrado bajo composición; la composición de dos términos de un solo bit puede ser una suma, que multiplica el número total de términos. Este uso de memoria no es necesariamente inherente al observable resultante, pero encontrar una refactorización eficiente de la suma suele ser igualmente difícil desde el punto de vista computacional. Es mejor utilizar el conocimiento del dominio de tus observables para minimizar el número de términos que existen, en lugar de intentar simplificarlos a posteriori.

Parámetros

  • other - el observable utilizado para multiplicar por la izquierda self.

  • qargs -

    si se indica, los qubits de self que deben asociarse a los qubits de other. Dicho de otro modo: si esto se da, es similar a una implementación más eficiente de:

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

    ya que no se crea ningún observable temporal para almacenar la forma de disposición aplicada de other.

  • front - si True, entonces se multiplica a la derecha por other en lugar de a la izquierda (por defecto False). Los qargs se siguen aplicando a other. Esto es muy útil cuando qargs está establecido, o other puede ser un objeto que debe ser coaccionado a SparseObservable.

conjugate

conjugate()

Calcular la conjugación compleja de este observable.

Esta operación se define en términos de las convenciones estándar de la matriz de Qiskit, en que la forma de la matriz se toma para estar en la base computacional $Z$. Los términos del alfabeto relacionados con $X$- y $Z$ no se ven afectados por la conjugación compleja, pero los términos relacionados con $Y$ modifican sus términos del alfabeto. Precisamente:

  • YY se conjuga con Y-Y
  • rr\lvert r\rangle\langle r\rvert conjugados con ll\lvert l\rangle\langle l\rvert
  • ll\lvert l\rangle\langle l\rvert conjugados con rr\lvert r\rangle\langle r\rvert

Además, todos los coeficientes están conjugados.

Ejemplos

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

copy

copy()

Obtener una copia de este observable.

Ejemplos

>>> 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)

Desarrolla este observable mediante un término de Pauli.

Una evolución de la observable OO mediante un PP de Pauli corresponde a POPP^\dagger O P.

A diferencia de una implementación literal mediante dos composiciones completas, este método realiza la conjugación directamente a nivel de un solo qubit utilizando una tabla de consulta fija. De este modo se evita materializar cualquier término intermedio SparseObservable y se calcula la observable evolucionada en una sola pasada por los términos. self y other debe tener el mismo número de qubits, a menos que qargs se especifique, en cuyo caso other puede ser menor que self, siempre que el número de qubits en other y la longitud de qargs coincidan. qargs especifica qué qubits de self son evolucionados por other.

Actualmente, este método solo admite la evolución mediante un operador de un solo término, lo que significa que other debe ser un operador de Pauli representado por Pauli.

Parámetros

  • otro : el operador de Pauli, que se utiliza para conjugar self.
  • qargs : si se proporciona, los qubits de self que se van a evolucionar mediante other. La longitud debe coincidir con el número de qubits en other.

Devuelve

Una nueva versión mejorada SparseObservable con conjugaciones aplicadas.

Aumentos

  • TypeError – si no other es de tipo Pauli.
  • ValueError – si self y other tienen un número diferente de qubits (y no qargs se especifica).
  • ValueError – si qargs la longitud no coincide con other el número de qubits.
  • ValueError – si qargs contiene duplicados o índices fuera de rango.
  • ValueError – si other contiene más de un término.

expand

expand(other, /)

Producto tensorial de orden inverso.

Esto es equivalente a other.tensor(self), excepto que other será primero convertido a SparseObservable si no lo es ya (llamando al constructor por defecto).

Parámetros

otro - el observable a poner en el lado izquierdo del producto tensorial.

Ejemplos

Esto equivale a tensor() con el orden de los argumentos invertido:

>>> left = SparseObservable.from_label("XYZ")
>>> right = SparseObservable.from_label("+-IIrl")
>>> assert left.tensor(right) == right.expand(left)
Consulte también

tensor()

La misma función con el orden de los argumentos invertido. tensor() es la ordenación de argumentos más estándar, y coincide con otras convenciones de Qiskit.

from_label

static from_label(label, /)

Construir un observable de un solo término a partir de una etiqueta de cadena densa.

El operador resultante tendrá un coeficiente de 1. La etiqueta debe ser una secuencia del alfabeto 'IXYZ+-rl01'. La etiqueta se interpreta de forma análoga a una cadena de bits. En otras palabras, la letra más a la derecha está asociada al qubit 0, y así sucesivamente. Esto es lo mismo que las etiquetas para Pauli y SparsePauliOp.

Parámetros

label (str) – la etiqueta densa.

Ejemplos

>>> 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)
Consulte también

from_list()

Una generalización de este método que construye un operador de suma a partir de múltiples etiquetas y sus coeficientes correspondientes.

from_list

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

Construir un observable a partir de una lista de etiquetas densas y coeficientes.

Es análogo a SparsePauliOp.from_list()salvo que utiliza el alfabeto ampliado de SparseObservable. En este formulario denso, debe suministrar todas las identidades explícitamente en cada etiqueta.

La etiqueta debe ser una secuencia del alfabeto 'IXYZ+-rl01'. La etiqueta se interpreta de forma análoga a una cadena de bits. En otras palabras, la letra más a la derecha está asociada al qubit 0, y así sucesivamente. Esto es lo mismo que las etiquetas para Pauli y SparsePauliOp.

Parámetros

  • iter (list[tuple[str, complex]]) – Pares de etiquetas y sus coeficientes asociados para sumar. Las etiquetas se interpretan del mismo modo que en from_label().
  • num_qubits (int | None) – No es necesario especificarlo si está seguro de que iter no es una secuencia vacía, ya que puede deducirse de las longitudes de las etiquetas. Si iter puede estar vacío, debe especificar este argumento para desambiguar para cuántos qubits es el observable. Si se indica y iter no está vacío, el valor debe coincidir con la longitud de las etiquetas.

Ejemplos

Construir un observable a partir de una lista de etiquetas de la misma longitud:

>>> 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)>

Utilice num_qubits para desambiguar entradas potencialmente vacías:

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

Este método es equivalente a las llamadas a from_sparse_list() con el campo explícito qubit-arguments establecido en enteros decrecientes:

>>> 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
Consulte también

from_label()

Un constructor similar, pero sólo toma una etiqueta y siempre tiene su coeficiente fijado en 1.0.

from_sparse_list()

Construir el observable a partir de una lista de etiquetas sin identidades explícitas, pero con los qubits a los que se aplica cada término single-qubit enumerados explícitamente.

from_pauli

static from_pauli(pauli, /)

Construir un SparseObservable a partir de una única Pauli instancia.

El observable de salida tendrá un único término, con un coeficiente unitario dependiente de la fase.

Parámetros

pauli (Pauli) – el único Pauli para convertir.

Ejemplos

>>> 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)

Construye un SparseObservable a partir de matrices Numpy sin procesar que coincidan con la representación de datos requerida descrita en la documentación de nivel de clase.

Los datos de cada matriz se copian en asignaciones de espacio Rust nuevas y ampliables.

Parámetros

  • num_qubits - número de qubits en el observable.

  • coeffs - coeficientes complejos de cada término del observable. Debería ser un array Numpy con dtype complex128.

  • bit_terms - lista aplanada de los términos single-qubit que comprende todos los términos completos. Debe ser un array Numpy con dtype uint8 (que es compatible con BitTerm).

  • índices - lista ordenada por términos de los qubits a los que corresponde cada término de un qubit. Debería ser un array Numpy con dtype uint32.

  • límites : los índices que dividen bit_terms y indices en términos. Debería ser un array Numpy con dtype uintp.

  • comprobar -

    si True (por defecto), valida que los datos satisfacen todas las garantías de coherencia. Si False, no se realiza ninguna comprobación.

    Aviso

    Si check=False, los bit_terms deben ser absolutamente todos valores válidos de SparseObservable.BitTerm. Si no lo son, puede producirse un comportamiento indefinido en el espacio Rust, invalidando por completo la ejecución del programa.

Ejemplos

Construye una suma de ZZ en cada qubit individual:

>>> 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)

Construye un observable a partir de una lista de etiquetas, los qubits a los que se aplica cada elemento y el coeficiente del término completo.

Es análogo a SparsePauliOp.from_sparse_list()salvo que utiliza el alfabeto ampliado de SparseObservable.

Los campos "labels" e "indices" de las triplas se asocian comprimiéndolos. Por ejemplo, esto significa que una llamada a from_list() puede convertirse a la forma utilizada por este método estableciendo el campo "índices" de cada triple en (num_qubits-1, ..., 1, 0).

Parámetros

  • iter (list[tuple[str, Sequence[int], complex]]) – triples de etiquetas, los qubits a los que se aplica cada término single-qubit y el coeficiente del término completo.
  • num_qubits (int) – el número de qubits del operador.

Ejemplos

Construye un operador simple:

>>> 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)>

Construir el observable de identidad (aunque en realidad, basta con utilizar identity()):

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

Este método puede reproducir el comportamiento de from_list()si el campo qubit-arguments de la tripleta se establece en enteros decrecientes:

>>> 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
Consulte también

to_sparse_list()

El reverso de este método.

from_sparse_pauli_op

static from_sparse_pauli_op(op, /)

Construir un SparseObservable a partir de una SparsePauliOp instancia.

Esta será una traducción en gran medida directa del SparsePauliOpen particular, no hay ninguna suma sobre la marcha de términos similares, ni ningún intento de refactorizar sumas de términos de Pauli en operadores de proyección equivalentes.

Parámetros

op (SparsePauliOp) – el operador a convertir.

Ejemplos

>>> 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)

Construya un SparseObservable a partir de términos individuales.

Todos los términos deben tener el mismo número de qubits. Si se proporciona, el argumento num_qubits debe coincidir con los términos.

No se realiza ninguna simplificación como parte de la creación observable.

Parámetros

  • obj (Iterable[Term]) – Iterable de términos individuales a partir de los cuales se construye el observable.
  • num_qubits (int | None) – El número de qubits sobre los que debe actuar el observable. Normalmente se deduce de la entrada, pero puede indicarse explícitamente para manejar el caso de un iterable vacío.

Devuelve

El observable correspondiente.

identity

static identity(num_qubits)

Obtiene el operador de identidad sobre el número dado de qubits.

Ejemplos

Obtén el operador de identidad para 100 qubits:

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

pauli_bases

pauli_bases()

Obtener un PauliList que representa la base de medida necesaria para cada término (en orden) en este observable.

Por ejemplo, el proyector 0l+ devolverá un Pauli ZXY. El resultado Pauli es denso, en el sentido de que se almacenan identidades explícitas. Una identidad en la salida de Pauli no requiere una medida concreta.

Esto devolverá una entrada en la lista Pauli para cada término de la suma.

Devuelve

la lista de operadores de Pauli que representa las bases de medida necesarias.

Tipo de retorno

PauliList

simplify

simplify(tol=1e-08)

Suma todos los términos semejantes en este operador, eliminándolos si el coeficiente complejo resultante tiene un valor absoluto dentro de la tolerancia de cero.

Como efecto secundario, esto ordena el operador en orden canónico.

Nota

Al utilizar esto para comparaciones de igualdad, hay que tener en cuenta que el redondeo de los números de coma flotante y la no asociatividad de la suma de números de coma flotante pueden hacer que los coeficientes distintos de cero de los términos sumados se consideren desiguales. Para comparar dos observables dentro de un margen de tolerancia, lo más seguro es comparar la diferencia canonicizada de ambas con cero.

Parámetros

tol (float) – después de sumar términos similares, se suprimirán de la salida los coeficientes cuyo valor absoluto sea inferior a la tolerancia absoluta dada.

Ejemplos

Utilizando simplify() para comparar dos operadores que representan el mismo observable, pero que se compararían de forma desigual debido a las pruebas estructurales por defecto:

>>> 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()

Tenga en cuenta que en el ejemplo anterior, los coeficientes se eligen de tal manera que todos los cálculos de punto flotante son exactos, y no hay redondeo intermedio o problemas de asociatividad. Si no se puede garantizar que sea así, la forma más segura es:

>>> 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, /)

Producto tensorial de dos observables.

La ordenación de bits se define de tal manera que los índices de qubits del argumento seguirán siendo los mismos, y los índices de self se desplazarán por el número de qubits en other. Esta es la misma convención utilizada por el resto de los operadores de Qiskit quantum_info de Qiskit.

Esta función se utiliza para el operador infijo ^ . Si utiliza este operador, tenga en cuenta que las reglas de precedencia de operadores de Python pueden hacer que el orden de evaluación sea diferente al esperado. En concreto, el operador + se une más estrechamente que ^, al igual que * se une más estrechamente que +. Utilice paréntesis para fijar el orden de evaluación, si es necesario.

El argumento se convertirá en SparseObservable utilizando su constructor por defecto, si no está ya en la forma correcta.

Parámetros

otro - el observable que hay que poner en el lado derecho del producto tensorial.

Ejemplos

El orden de bits es tal que el producto tensorial de dos observables hechos a partir de una sola etiqueta "se parece" a un observable hecho concatenando las dos cadenas:

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

También se puede utilizar el operador infijo ^ para productos tensoriales, que de forma similar lanzará el lado derecho de la operación si no es ya un SparseObservable:

>>> assert SparseObservable("rl") ^ Pauli("XYZ") == SparseObservable("rlXYZ")
Consulte también

expand()

La misma función, pero con el orden de los argumentos invertido. Esto puede ser útil si te gusta usar el comportamiento de fundición para el argumento, pero quieres que tu SparseObservable esté en el lado derecho de la ordenación tensorial.

to_sparse_list

to_sparse_list()

Expresar el observable en términos de un formato de lista dispersa.

Esto puede verse como una contraoperación de SparseObservable.from_sparse_list()sin embargo, no se garantiza que el orden de los términos sea el mismo después de un viaje de ida y vuelta a una lista dispersa.

Ejemplos

>>> obs = SparseObservable.from_list([("IIXIZ", 2j), ("IIZIX", 2j)])
>>> reconstructed = SparseObservable.from_sparse_list(obs.to_sparse_list(), obs.num_qubits)
Consulte también

from_sparse_list()

El constructor que puede interpretar estas listas.

transpose

transpose()

Calcular la transposición matricial de este observable.

Esta operación se define en términos de las convenciones estándar de la matriz de Qiskit, en que la forma de la matriz se toma para estar en la base computacional $Z$. Los términos del alfabeto relacionados con $X$- y $Z$ no se ven afectados por la transposición, pero los términos relacionados con $Y$ modifican sus términos del alfabeto. Precisamente:

  • YY se transpone a Y-Y
  • rr\lvert r\rangle\langle r\rvert se transpone a ll\lvert l\rangle\langle l\rvert
  • ll\lvert l\rangle\langle l\rvert se transpone a rr\lvert r\rangle\langle r\rvert

Ejemplos

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

zero

static zero(num_qubits)

Obtiene el operador cero sobre el número dado de qubits.

El operador cero es el operador cuyo valor de expectativa es cero para todos los estados cuánticos. No tiene condiciones. Es el elemento de identidad para la suma de dos SparseObservable instancias; cualquier cosa añadida al operador cero es igual a sí misma.

Si desea que el proyector en el estado de todos los ceros, utilice:

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

Ejemplos

Obtén el operador cero para 100 qubits:

>>> SparseObservable.zero(100)
<SparseObservable with 0 terms on 100 qubits: 0.0>
¿Le ha resultado útil esta página?
Informe de un error, de una errata o solicite contenido en GitHub.